use std::sync::Arc;
use {parking_lot::RwLock, reovim_kernel::api::v1::Service};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct BracketPair {
pub open: char,
pub close: char,
}
impl BracketPair {
#[must_use]
pub const fn new(open: char, close: char) -> Self {
Self { open, close }
}
#[must_use]
pub const fn is_symmetric(&self) -> bool {
self.open as u32 == self.close as u32
}
}
#[derive(Debug, Clone)]
pub struct BracketConfig {
language_id: Arc<str>,
rainbow_pairs: Vec<BracketPair>,
autopair_pairs: Vec<BracketPair>,
highlight_pairs: Vec<BracketPair>,
}
impl BracketConfig {
#[must_use]
pub fn new(language_id: impl Into<Arc<str>>) -> Self {
Self {
language_id: language_id.into(),
rainbow_pairs: Vec::new(),
autopair_pairs: Vec::new(),
highlight_pairs: Vec::new(),
}
}
#[must_use]
pub fn with_rainbow(mut self, pairs: impl IntoIterator<Item = (char, char)>) -> Self {
self.rainbow_pairs = pairs
.into_iter()
.map(|(o, c)| BracketPair::new(o, c))
.collect();
self
}
#[must_use]
pub fn with_autopair(mut self, pairs: impl IntoIterator<Item = (char, char)>) -> Self {
self.autopair_pairs = pairs
.into_iter()
.map(|(o, c)| BracketPair::new(o, c))
.collect();
self
}
#[must_use]
pub fn with_highlight(mut self, pairs: impl IntoIterator<Item = (char, char)>) -> Self {
self.highlight_pairs = pairs
.into_iter()
.map(|(o, c)| BracketPair::new(o, c))
.collect();
self
}
#[must_use]
pub fn language_id(&self) -> &str {
&self.language_id
}
#[must_use]
pub fn rainbow_pairs(&self) -> &[BracketPair] {
&self.rainbow_pairs
}
#[must_use]
pub fn autopair_pairs(&self) -> &[BracketPair] {
&self.autopair_pairs
}
#[must_use]
pub fn highlight_pairs(&self) -> &[BracketPair] {
&self.highlight_pairs
}
}
#[must_use]
pub fn default_bracket_config() -> BracketConfig {
BracketConfig::new("*")
.with_rainbow([('(', ')'), ('[', ']'), ('{', '}')])
.with_autopair([('(', ')'), ('[', ']'), ('{', '}'), ('"', '"'), ('\'', '\'')])
.with_highlight([('(', ')'), ('[', ']'), ('{', '}')])
}
#[derive(Default)]
pub struct BracketConfigStore {
entries: RwLock<Vec<BracketConfig>>,
}
impl BracketConfigStore {
#[must_use]
pub fn new() -> Self {
Self::default()
}
pub fn add(&self, config: BracketConfig) {
self.entries.write().push(config);
}
#[must_use]
pub fn find(&self, language_id: &str) -> Option<BracketConfig> {
self.entries
.read()
.iter()
.find(|c| &*c.language_id == language_id)
.cloned()
}
#[must_use]
pub fn find_or_default(&self, language_id: &str) -> BracketConfig {
self.find(language_id)
.unwrap_or_else(default_bracket_config)
}
pub fn take_all(&self) -> Vec<BracketConfig> {
std::mem::take(&mut *self.entries.write())
}
#[must_use]
pub fn len(&self) -> usize {
self.entries.read().len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.entries.read().is_empty()
}
}
impl Service for BracketConfigStore {}
impl std::fmt::Debug for BracketConfigStore {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("BracketConfigStore")
.field("count", &self.len())
.finish()
}
}
#[cfg(test)]
#[path = "bracket_tests.rs"]
mod tests;