git.lucas.co / cce-ui
GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git

src/widget/editor.rs (7.2K)

  1 #[derive(Debug, Clone, Default)]
  2 pub struct TextEditorState {
  3     pub buffer: String,
  4     pub cursor_idx: usize,
  5     pub select_anchor: Option<usize>,
  6     pub all_selected: bool,
  7 }
  8 
  9 impl TextEditorState {
 10     pub fn new(text: String) -> Self {
 11         let len = text.chars().count();
 12         Self {
 13             buffer: text,
 14             cursor_idx: len,
 15             select_anchor: None,
 16             all_selected: false,
 17         }
 18     }
 19 
 20     pub fn select_all(&mut self) {
 21         let len = self.buffer.chars().count();
 22         self.select_anchor = Some(0);
 23         self.cursor_idx = len;
 24         self.all_selected = len > 0;
 25     }
 26 
 27     pub fn clear_selection(&mut self) {
 28         self.select_anchor = None;
 29         self.all_selected = false;
 30     }
 31 
 32     pub fn clamp_bounds(&mut self) {
 33         let len = self.buffer.chars().count();
 34         self.cursor_idx = self.cursor_idx.min(len);
 35         if let Some(anchor) = self.select_anchor {
 36             self.select_anchor = Some(anchor.min(len));
 37         }
 38     }
 39 
 40     pub fn selected_range(&self) -> Option<(usize, usize)> {
 41         let len = self.buffer.chars().count();
 42         let anchor = self.select_anchor?.min(len);
 43         let cursor = self.cursor_idx.min(len);
 44         if anchor == cursor {
 45             None
 46         } else {
 47             Some((anchor.min(cursor), anchor.max(cursor)))
 48         }
 49     }
 50 
 51     pub fn selected_text(&self) -> Option<String> {
 52         let (start, end) = self.selected_range()?;
 53         let chars: Vec<char> = self.buffer.chars().collect();
 54         Some(chars[start..end].iter().collect())
 55     }
 56 
 57     pub fn insert_text(&mut self, text: &str) {
 58         self.clamp_bounds();
 59         if self.all_selected {
 60             self.buffer.clear();
 61             self.cursor_idx = 0;
 62             self.clear_selection();
 63         }
 64 
 65         let start = self.select_anchor.unwrap_or(self.cursor_idx).min(self.cursor_idx);
 66         let end = self.select_anchor.unwrap_or(self.cursor_idx).max(self.cursor_idx);
 67         let chars: Vec<char> = self.buffer.chars().collect();
 68         let mut new_buf = String::new();
 69         for i in 0..start {
 70             new_buf.push(chars[i]);
 71         }
 72         let inserted_count = text.chars().count();
 73         new_buf.push_str(text);
 74         for i in end..chars.len() {
 75             new_buf.push(chars[i]);
 76         }
 77         self.buffer = new_buf;
 78         self.cursor_idx = start + inserted_count;
 79         self.clear_selection();
 80     }
 81 
 82     pub fn delete_backwards(&mut self) -> bool {
 83         self.clamp_bounds();
 84         if self.all_selected {
 85             self.buffer.clear();
 86             self.cursor_idx = 0;
 87             self.clear_selection();
 88             return true;
 89         }
 90         let start = self.select_anchor.unwrap_or(self.cursor_idx).min(self.cursor_idx);
 91         let end = self.select_anchor.unwrap_or(self.cursor_idx).max(self.cursor_idx);
 92         if start != end {
 93             let chars: Vec<char> = self.buffer.chars().collect();
 94             let mut new_buf = String::new();
 95             for i in 0..start {
 96                 new_buf.push(chars[i]);
 97             }
 98             for i in end..chars.len() {
 99                 new_buf.push(chars[i]);
100             }
101             self.buffer = new_buf;
102             self.cursor_idx = start;
103             self.clear_selection();
104             return true;
105         }
106         if self.cursor_idx > 0 {
107             let mut chars: Vec<char> = self.buffer.chars().collect();
108             chars.remove(self.cursor_idx - 1);
109             self.buffer = chars.into_iter().collect();
110             self.cursor_idx -= 1;
111             self.clear_selection();
112             return true;
113         }
114         false
115     }
116 
117     pub fn delete_forwards(&mut self) -> bool {
118         self.clamp_bounds();
119         if self.all_selected {
120             self.buffer.clear();
121             self.cursor_idx = 0;
122             self.clear_selection();
123             return true;
124         }
125         let start = self.select_anchor.unwrap_or(self.cursor_idx).min(self.cursor_idx);
126         let end = self.select_anchor.unwrap_or(self.cursor_idx).max(self.cursor_idx);
127         if start != end {
128             let chars: Vec<char> = self.buffer.chars().collect();
129             let mut new_buf = String::new();
130             for i in 0..start {
131                 new_buf.push(chars[i]);
132             }
133             for i in end..chars.len() {
134                 new_buf.push(chars[i]);
135             }
136             self.buffer = new_buf;
137             self.cursor_idx = start;
138             self.clear_selection();
139             return true;
140         }
141         let char_count = self.buffer.chars().count();
142         if self.cursor_idx < char_count {
143             let mut chars: Vec<char> = self.buffer.chars().collect();
144             chars.remove(self.cursor_idx);
145             self.buffer = chars.into_iter().collect();
146             self.clear_selection();
147             return true;
148         }
149         false
150     }
151 
152     pub fn move_cursor_left(&mut self, select: bool) -> bool {
153         self.clamp_bounds();
154         if select {
155             if self.select_anchor.is_none() {
156                 self.select_anchor = Some(self.cursor_idx);
157             }
158             if self.cursor_idx > 0 {
159                 self.cursor_idx -= 1;
160                 true
161             } else {
162                 false
163             }
164         } else {
165             if let Some(anchor) = self.select_anchor {
166                 self.cursor_idx = anchor.min(self.cursor_idx);
167                 self.clear_selection();
168                 true
169             } else if self.cursor_idx > 0 {
170                 self.cursor_idx -= 1;
171                 true
172             } else {
173                 false
174             }
175         }
176     }
177 
178     pub fn move_cursor_right(&mut self, select: bool) -> bool {
179         self.clamp_bounds();
180         let char_count = self.buffer.chars().count();
181         if select {
182             if self.select_anchor.is_none() {
183                 self.select_anchor = Some(self.cursor_idx);
184             }
185             if self.cursor_idx < char_count {
186                 self.cursor_idx += 1;
187                 true
188             } else {
189                 false
190             }
191         } else {
192             if let Some(anchor) = self.select_anchor {
193                 self.cursor_idx = anchor.max(self.cursor_idx);
194                 self.clear_selection();
195                 true
196             } else if self.cursor_idx < char_count {
197                 self.cursor_idx += 1;
198                 true
199             } else {
200                 false
201             }
202         }
203     }
204 
205     pub fn move_cursor_to_start(&mut self, select: bool) -> bool {
206         self.clamp_bounds();
207         if select {
208             if self.select_anchor.is_none() {
209                 self.select_anchor = Some(self.cursor_idx);
210             }
211         } else {
212             self.clear_selection();
213         }
214         let changed = self.cursor_idx != 0;
215         self.cursor_idx = 0;
216         changed
217     }
218 
219     pub fn move_cursor_to_end(&mut self, select: bool) -> bool {
220         self.clamp_bounds();
221         let char_count = self.buffer.chars().count();
222         if select {
223             if self.select_anchor.is_none() {
224                 self.select_anchor = Some(self.cursor_idx);
225             }
226         } else {
227             self.clear_selection();
228         }
229         let changed = self.cursor_idx != char_count;
230         self.cursor_idx = char_count;
231         changed
232     }
233 }