floem_editor_core/
util.rs1use core::str::FromStr;
2use std::collections::HashMap;
3
4pub fn matching_pair_direction(c: char) -> Option<bool> {
6 Some(match c {
7 '{' => true,
8 '}' => false,
9 '(' => true,
10 ')' => false,
11 '[' => true,
12 ']' => false,
13 _ => return None,
14 })
15}
16
17pub fn matching_char(c: char) -> Option<char> {
18 Some(match c {
19 '{' => '}',
20 '}' => '{',
21 '(' => ')',
22 ')' => '(',
23 '[' => ']',
24 ']' => '[',
25 _ => return None,
26 })
27}
28
29pub fn matching_bracket_general<R: ToStaticTextType>(char: char) -> Option<R>
31where
32 &'static str: ToStaticTextType<R>,
33{
34 let pair = match char {
35 '{' => "}",
36 '}' => "{",
37 '(' => ")",
38 ')' => "(",
39 '[' => "]",
40 ']' => "[",
41 _ => return None,
42 };
43 Some(pair.to_static())
44}
45
46pub trait ToStaticTextType<R: 'static = Self>: 'static {
47 fn to_static(self) -> R;
48}
49
50impl ToStaticTextType for &'static str {
51 #[inline]
52 fn to_static(self) -> &'static str {
53 self
54 }
55}
56
57impl ToStaticTextType<char> for &'static str {
58 #[inline]
59 fn to_static(self) -> char {
60 char::from_str(self).unwrap()
61 }
62}
63
64impl ToStaticTextType<String> for &'static str {
65 #[inline]
66 fn to_static(self) -> String {
67 self.to_string()
68 }
69}
70
71impl ToStaticTextType for char {
72 #[inline]
73 fn to_static(self) -> char {
74 self
75 }
76}
77
78impl ToStaticTextType for String {
79 #[inline]
80 fn to_static(self) -> String {
81 self
82 }
83}
84
85pub fn has_unmatched_pair(line: &str) -> bool {
86 let mut count = HashMap::new();
87 let mut pair_first = HashMap::new();
88 for c in line.chars().rev() {
89 if let Some(left) = matching_pair_direction(c) {
90 let key = if left { c } else { matching_char(c).unwrap() };
91 let pair_count = *count.get(&key).unwrap_or(&0i32);
92 pair_first.entry(key).or_insert(left);
93 if left {
94 count.insert(key, pair_count - 1);
95 } else {
96 count.insert(key, pair_count + 1);
97 }
98 }
99 }
100 for (_, pair_count) in count.iter() {
101 if *pair_count < 0 {
102 return true;
103 }
104 }
105 for (_, left) in pair_first.iter() {
106 if *left {
107 return true;
108 }
109 }
110 false
111}
112
113pub fn str_is_pair_left(c: &str) -> bool {
114 if c.chars().count() == 1 {
115 let c = c.chars().next().unwrap();
116 if matching_pair_direction(c).unwrap_or(false) {
117 return true;
118 }
119 }
120 false
121}
122
123pub fn str_matching_pair(c: &str) -> Option<char> {
124 if c.chars().count() == 1 {
125 let c = c.chars().next().unwrap();
126 return matching_char(c);
127 }
128 None
129}