tui_lipan/widgets/text_area/
vim_config.rs1use std::sync::Arc;
2
3use crate::core::event::{KeyCode, KeyEvent, KeyMods};
4use crate::input::KeyBindings;
5use crate::style::{Style, StyleSlot};
6
7#[non_exhaustive]
9#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
10pub enum TextAreaVimMode {
11 Insert,
13 #[default]
15 Normal,
16 Visual,
21 VisualLine,
26}
27
28#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
35pub struct TextAreaVimKeymap {
36 bindings: Vec<TextAreaVimKeyBinding>,
37}
38
39#[derive(Clone, Debug, PartialEq, Eq, Hash)]
41pub struct TextAreaVimKeyBinding {
42 pub bindings: KeyBindings,
46 pub command: char,
48}
49
50impl TextAreaVimKeymap {
51 pub fn new() -> Self {
53 Self::default()
54 }
55
56 pub fn bind(mut self, bindings: KeyBindings, command: char) -> Self {
59 self.bindings
60 .push(TextAreaVimKeyBinding { bindings, command });
61 self
62 }
63
64 pub(crate) fn translate_key(&self, key: KeyEvent) -> KeyEvent {
65 let Some(binding) = self.bindings.iter().find(|binding| {
66 binding
67 .bindings
68 .iter()
69 .any(|candidate| !candidate.is_chord() && candidate.matches_sequence(&[key]))
70 }) else {
71 return key;
72 };
73
74 KeyEvent {
75 code: KeyCode::Char(binding.command),
76 mods: KeyMods::default(),
77 }
78 }
79}
80
81#[non_exhaustive]
83#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
84pub enum TextAreaVimCurrentLineHighlight {
85 #[default]
87 Off,
88 Content,
91 Full,
93}
94
95#[derive(Clone, Debug, PartialEq, Eq, Hash)]
102pub struct TextAreaVimConfig {
103 pub search_bar_style: StyleSlot,
107 pub search_bar_prefix_style: StyleSlot,
110 pub search_bar_count_style: StyleSlot,
113 pub search_match_style: StyleSlot,
116 pub current_search_match_style: StyleSlot,
121 pub current_line_highlight: TextAreaVimCurrentLineHighlight,
123 pub current_line_style: StyleSlot,
126 pub current_line_number_style: StyleSlot,
129}
130
131impl Default for TextAreaVimConfig {
132 fn default() -> Self {
133 Self {
134 search_bar_style: StyleSlot::Extend(Style::new().reverse()),
135 search_bar_prefix_style: StyleSlot::Inherit,
136 search_bar_count_style: StyleSlot::Inherit,
137 search_match_style: StyleSlot::Replace(Style::new().underline().bold()),
138 current_search_match_style: StyleSlot::Inherit,
139 current_line_highlight: TextAreaVimCurrentLineHighlight::Off,
140 current_line_style: StyleSlot::Inherit,
141 current_line_number_style: StyleSlot::Inherit,
142 }
143 }
144}
145
146impl TextAreaVimConfig {
147 pub fn new() -> Self {
150 Self::default()
151 }
152
153 pub fn search_bar_style(mut self, style: Style) -> Self {
155 self.search_bar_style = StyleSlot::Replace(style);
156 self
157 }
158
159 pub fn extend_search_bar_style(mut self, style: Style) -> Self {
161 self.search_bar_style = StyleSlot::Extend(style);
162 self
163 }
164
165 pub fn search_bar_style_slot(mut self, slot: StyleSlot) -> Self {
167 self.search_bar_style = slot;
168 self
169 }
170
171 pub fn search_bar_prefix_style(mut self, style: Style) -> Self {
173 self.search_bar_prefix_style = StyleSlot::Replace(style);
174 self
175 }
176
177 pub fn extend_search_bar_prefix_style(mut self, style: Style) -> Self {
179 self.search_bar_prefix_style = StyleSlot::Extend(style);
180 self
181 }
182
183 pub fn search_bar_prefix_style_slot(mut self, slot: StyleSlot) -> Self {
185 self.search_bar_prefix_style = slot;
186 self
187 }
188
189 pub fn search_bar_count_style(mut self, style: Style) -> Self {
191 self.search_bar_count_style = StyleSlot::Replace(style);
192 self
193 }
194
195 pub fn extend_search_bar_count_style(mut self, style: Style) -> Self {
197 self.search_bar_count_style = StyleSlot::Extend(style);
198 self
199 }
200
201 pub fn search_bar_count_style_slot(mut self, slot: StyleSlot) -> Self {
203 self.search_bar_count_style = slot;
204 self
205 }
206
207 pub fn search_match_style(mut self, style: Style) -> Self {
209 self.search_match_style = StyleSlot::Replace(style);
210 self
211 }
212
213 pub fn extend_search_match_style(mut self, style: Style) -> Self {
215 self.search_match_style = StyleSlot::Extend(style);
216 self
217 }
218
219 pub fn search_match_style_slot(mut self, slot: StyleSlot) -> Self {
221 self.search_match_style = slot;
222 self
223 }
224
225 pub fn current_search_match_style(mut self, style: Style) -> Self {
227 self.current_search_match_style = StyleSlot::Replace(style);
228 self
229 }
230
231 pub fn extend_current_search_match_style(mut self, style: Style) -> Self {
233 self.current_search_match_style = StyleSlot::Extend(style);
234 self
235 }
236
237 pub fn current_search_match_style_slot(mut self, slot: StyleSlot) -> Self {
239 self.current_search_match_style = slot;
240 self
241 }
242
243 pub fn current_line_highlight(mut self, mode: TextAreaVimCurrentLineHighlight) -> Self {
245 self.current_line_highlight = mode;
246 self
247 }
248
249 pub fn highlight_current_line(mut self, enabled: bool) -> Self {
251 self.current_line_highlight = if enabled {
252 TextAreaVimCurrentLineHighlight::Full
253 } else {
254 TextAreaVimCurrentLineHighlight::Off
255 };
256 self
257 }
258
259 pub fn current_line_style(mut self, style: Style) -> Self {
261 self.current_line_style = StyleSlot::Replace(style);
262 self
263 }
264
265 pub fn extend_current_line_style(mut self, style: Style) -> Self {
267 self.current_line_style = StyleSlot::Extend(style);
268 self
269 }
270
271 pub fn current_line_style_slot(mut self, slot: StyleSlot) -> Self {
273 self.current_line_style = slot;
274 self
275 }
276
277 pub fn current_line_number_style(mut self, style: Style) -> Self {
279 self.current_line_number_style = StyleSlot::Replace(style);
280 self
281 }
282
283 pub fn extend_current_line_number_style(mut self, style: Style) -> Self {
285 self.current_line_number_style = StyleSlot::Extend(style);
286 self
287 }
288
289 pub fn current_line_number_style_slot(mut self, slot: StyleSlot) -> Self {
291 self.current_line_number_style = slot;
292 self
293 }
294}
295
296#[derive(Clone, Debug, PartialEq, Eq, Hash)]
297pub(crate) struct TextAreaVimSearchFeedback {
298 pub query: Arc<str>,
299 pub cursor: usize,
300 pub forward: bool,
301 pub pending: bool,
302 pub target_range: Option<(usize, usize)>,
303 pub current_match_index: Option<usize>,
304 pub match_count: usize,
305}