1use parking_lot::ReentrantMutex;
4use std::cell::RefCell;
5use std::collections::HashMap;
6use std::collections::VecDeque;
7use std::sync::Mutex;
8
9#[derive(Debug)]
11pub struct ZleState {
12 pub buffer: String,
14 pub cursor: usize,
16 pub mark: usize,
18 pub numeric_arg: Option<i32>,
20 pub insert_mode: bool,
22 pub last_find_char: Option<char>,
24 pub find_forward: bool,
26 undo_history: Vec<(String, usize)>,
28 pub undo_stack: Vec<(String, usize)>,
30 kill_ring: VecDeque<String>,
32 kill_ring_max: usize,
34 pub vi_cmd_mode: bool,
36 pub keymap: KeymapName,
38 last_yank_pos: Option<(usize, usize)>,
40 pub region_active: bool,
42}
43
44impl Default for ZleState {
45 fn default() -> Self {
46 Self::new()
47 }
48}
49
50impl ZleState {
51 pub fn new() -> Self {
52 ZleState {
53 buffer: String::new(),
54 cursor: 0,
55 mark: 0,
56 numeric_arg: None,
57 insert_mode: true,
58 last_find_char: None,
59 find_forward: true,
60 undo_history: Vec::new(),
61 undo_stack: Vec::new(),
62 kill_ring: VecDeque::new(),
63 kill_ring_max: 8,
64 vi_cmd_mode: false,
65 keymap: KeymapName::Emacs,
66 last_yank_pos: None,
67 region_active: false,
68 }
69 }
70
71 pub fn save_undo(&mut self) {
73 self.undo_history.push((self.buffer.clone(), self.cursor));
74 if self.undo_history.len() > 100 {
75 self.undo_history.remove(0);
76 }
77 }
78
79 pub fn undo(&mut self) -> bool {
81 if let Some((buffer, cursor)) = self.undo_history.pop() {
82 self.undo_stack.push((self.buffer.clone(), self.cursor));
83 self.buffer = buffer;
84 self.cursor = cursor;
85 true
86 } else {
87 false
88 }
89 }
90
91 pub fn redo(&mut self) -> bool {
93 if let Some((buffer, cursor)) = self.undo_stack.pop() {
94 self.undo_history.push((self.buffer.clone(), self.cursor));
95 self.buffer = buffer;
96 self.cursor = cursor;
97 true
98 } else {
99 false
100 }
101 }
102
103 pub fn kill_add(&mut self, text: &str) {
105 self.kill_ring.push_front(text.to_string());
106 if self.kill_ring.len() > self.kill_ring_max {
107 self.kill_ring.pop_back();
108 }
109 }
110
111 pub fn yank(&mut self) -> Option<String> {
113 if let Some(text) = self.kill_ring.front().cloned() {
114 let start = self.cursor;
115 let chars: Vec<char> = self.buffer.chars().collect();
117 let mut new_buffer = String::new();
118 for (i, c) in chars.iter().enumerate() {
119 if i == self.cursor {
120 new_buffer.push_str(&text);
121 }
122 new_buffer.push(*c);
123 }
124 if self.cursor >= chars.len() {
125 new_buffer.push_str(&text);
126 }
127 self.buffer = new_buffer;
128 self.cursor += text.chars().count();
129 self.last_yank_pos = Some((start, self.cursor));
130 Some(text)
131 } else {
132 None
133 }
134 }
135
136 pub fn yank_pop(&mut self) -> Option<String> {
138 if let Some((start, end)) = self.last_yank_pos {
139 let chars: Vec<char> = self.buffer.chars().collect();
141 let mut new_buffer = String::new();
142 for (i, c) in chars.iter().enumerate() {
143 if i < start || i >= end {
144 new_buffer.push(*c);
145 }
146 }
147 self.buffer = new_buffer;
148 self.cursor = start;
149
150 if let Some(front) = self.kill_ring.pop_front() {
152 self.kill_ring.push_back(front);
153 }
154
155 self.yank()
157 } else {
158 None
159 }
160 }
161
162 pub fn kill_yank(&self) -> Option<&str> {
164 self.kill_ring.front().map(|s| s.as_str())
165 }
166
167 pub fn kill_rotate(&mut self) {
169 if let Some(front) = self.kill_ring.pop_front() {
170 self.kill_ring.push_back(front);
171 }
172 }
173}
174
175pub struct ZleManager {
177 pub keymaps: HashMap<KeymapName, Keymap>,
179 user_widgets: HashMap<String, String>,
181}
182
183impl Default for ZleManager {
184 fn default() -> Self {
185 Self::new()
186 }
187}
188
189impl ZleManager {
190 pub fn new() -> Self {
191 let mut mgr = ZleManager {
192 keymaps: HashMap::new(),
193 user_widgets: HashMap::new(),
194 };
195
196 mgr.keymaps
197 .insert(KeymapName::Main, Keymap::emacs_default());
198 mgr.keymaps
199 .insert(KeymapName::Emacs, Keymap::emacs_default());
200 mgr.keymaps
201 .insert(KeymapName::ViInsert, Keymap::viins_default());
202 mgr.keymaps
203 .insert(KeymapName::ViCommand, Keymap::vicmd_default());
204 mgr.keymaps.insert(KeymapName::Isearch, Keymap::new());
205 mgr.keymaps.insert(KeymapName::Command, Keymap::new());
206 mgr.keymaps.insert(KeymapName::MenuSelect, Keymap::new());
207
208 mgr
209 }
210
211 pub fn define_widget(&mut self, name: &str, func: &str) {
213 self.user_widgets.insert(name.to_string(), func.to_string());
214 }
215
216 pub fn get_widget<'a>(&'a self, name: &'a str) -> Option<&'a str> {
218 if let Some(func) = self.user_widgets.get(name) {
220 return Some(func);
221 }
222 if BUILTIN_WIDGETS.contains(&name) {
224 return Some(name);
225 }
226 None
227 }
228
229 pub fn bind_key(&mut self, keymap: KeymapName, key: &str, widget: &str) {
231 if let Some(km) = self.keymaps.get_mut(&keymap) {
232 km.bind(key, widget);
233 }
234 }
235
236 pub fn unbind_key(&mut self, keymap: KeymapName, key: &str) {
238 if let Some(km) = self.keymaps.get_mut(&keymap) {
239 km.unbind(key);
240 }
241 }
242
243 pub fn execute_widget(
245 &mut self,
246 name: &str,
247 _key: Option<char>,
248 ) -> super::widgets::WidgetResult {
249 if self.get_widget(name).is_some() {
250 super::widgets::WidgetResult::Ok
251 } else {
252 super::widgets::WidgetResult::Error(format!("Unknown widget: {}", name))
253 }
254 }
255
256 pub fn list_widgets(&self) -> Vec<&str> {
258 let mut widgets: Vec<&str> = BUILTIN_WIDGETS.to_vec();
259
260 for name in self.user_widgets.keys() {
261 widgets.push(name.as_str());
262 }
263
264 widgets
265 }
266}
267
268const BUILTIN_WIDGETS: &[&str] = &[
270 "accept-line",
271 "accept-and-hold",
272 "backward-char",
273 "backward-delete-char",
274 "backward-kill-line",
275 "backward-kill-word",
276 "backward-word",
277 "beep",
278 "beginning-of-history",
279 "beginning-of-line",
280 "capitalize-word",
281 "clear-screen",
282 "complete-word",
283 "copy-region-as-kill",
284 "delete-char",
285 "delete-char-or-list",
286 "down-case-word",
287 "down-history",
288 "down-line-or-history",
289 "down-line-or-search",
290 "end-of-history",
291 "end-of-line",
292 "exchange-point-and-mark",
293 "execute-named-cmd",
294 "expand-or-complete",
295 "forward-char",
296 "forward-word",
297 "history-incremental-search-backward",
298 "history-incremental-search-forward",
299 "kill-buffer",
300 "kill-line",
301 "kill-region",
302 "kill-whole-line",
303 "kill-word",
304 "overwrite-mode",
305 "quoted-insert",
306 "redisplay",
307 "redo",
308 "self-insert",
309 "send-break",
310 "set-mark-command",
311 "transpose-chars",
312 "transpose-words",
313 "undo",
314 "up-case-word",
315 "up-history",
316 "up-line-or-history",
317 "up-line-or-search",
318 "vi-add-eol",
319 "vi-add-next",
320 "vi-backward-blank-word",
321 "vi-backward-char",
322 "vi-backward-delete-char",
323 "vi-backward-word",
324 "vi-change",
325 "vi-change-eol",
326 "vi-change-whole-line",
327 "vi-cmd-mode",
328 "vi-delete",
329 "vi-delete-char",
330 "vi-end-of-line",
331 "vi-find-next-char",
332 "vi-find-next-char-skip",
333 "vi-find-prev-char",
334 "vi-find-prev-char-skip",
335 "vi-first-non-blank",
336 "vi-forward-blank-word",
337 "vi-forward-char",
338 "vi-forward-word",
339 "vi-forward-word-end",
340 "vi-insert",
341 "vi-insert-bol",
342 "vi-join",
343 "vi-kill-eol",
344 "vi-open-line-above",
345 "vi-open-line-below",
346 "vi-put-after",
347 "vi-put-before",
348 "vi-repeat-change",
349 "vi-repeat-find",
350 "vi-repeat-search",
351 "vi-replace",
352 "vi-replace-chars",
353 "vi-rev-repeat-find",
354 "vi-rev-repeat-search",
355 "vi-substitute",
356 "vi-yank",
357 "vi-yank-whole-line",
358 "which-command",
359 "yank",
360 "yank-pop",
361];
362
363thread_local! {
364 static ZLE_MANAGER: RefCell<ZleManager> = RefCell::new(ZleManager::new());
365}
366
367pub struct ZleGuard<'a>(std::cell::RefMut<'a, ZleManager>);
369
370impl<'a> std::ops::Deref for ZleGuard<'a> {
371 type Target = ZleManager;
372 fn deref(&self) -> &Self::Target {
373 &self.0
374 }
375}
376
377impl<'a> std::ops::DerefMut for ZleGuard<'a> {
378 fn deref_mut(&mut self) -> &mut Self::Target {
379 &mut self.0
380 }
381}
382
383pub fn zle() -> ZleGuard<'static> {
385 ZLE_MANAGER.with(|m| {
386 ZleGuard(unsafe { std::mem::transmute(m.borrow_mut()) })
388 })
389}
390
391#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
393pub enum KeymapName {
394 Emacs,
395 ViInsert,
396 ViCommand,
397 Main, Isearch, Command, MenuSelect, }
402
403impl KeymapName {
404 pub fn from_str(s: &str) -> Option<Self> {
405 match s {
406 "emacs" => Some(Self::Emacs),
407 "viins" => Some(Self::ViInsert),
408 "vicmd" => Some(Self::ViCommand),
409 "main" => Some(Self::Main),
410 "isearch" => Some(Self::Isearch),
411 "command" => Some(Self::Command),
412 "menuselect" => Some(Self::MenuSelect),
413 _ => None,
414 }
415 }
416
417 pub fn as_str(&self) -> &'static str {
418 match self {
419 Self::Emacs => "emacs",
420 Self::ViInsert => "viins",
421 Self::ViCommand => "vicmd",
422 Self::Main => "main",
423 Self::Isearch => "isearch",
424 Self::Command => "command",
425 Self::MenuSelect => "menuselect",
426 }
427 }
428}
429
430#[derive(Debug, Clone)]
432pub struct Keymap {
433 bindings: HashMap<String, String>,
434}
435
436impl Default for Keymap {
437 fn default() -> Self {
438 Self::new()
439 }
440}
441
442impl Keymap {
443 pub fn new() -> Self {
444 Self {
445 bindings: HashMap::new(),
446 }
447 }
448
449 pub fn emacs_default() -> Self {
451 let mut km = Self::new();
452
453 km.bind("^F", "forward-char");
455 km.bind("^B", "backward-char");
456 km.bind("^A", "beginning-of-line");
457 km.bind("^E", "end-of-line");
458 km.bind("\\ef", "forward-word"); km.bind("\\eb", "backward-word"); km.bind("^D", "delete-char");
463 km.bind("^H", "backward-delete-char");
464 km.bind("^?", "backward-delete-char"); km.bind("^K", "kill-line");
466 km.bind("^U", "backward-kill-line");
467 km.bind("\\ed", "kill-word"); km.bind("\\e^?", "backward-kill-word"); km.bind("^W", "backward-kill-word");
470 km.bind("^Y", "yank");
471 km.bind("\\ey", "yank-pop"); km.bind("^_", "undo");
475 km.bind("^X^U", "undo");
476 km.bind("\\e_", "redo"); km.bind("^P", "up-line-or-history");
480 km.bind("^N", "down-line-or-history");
481 km.bind("\\e<", "beginning-of-history");
482 km.bind("\\e>", "end-of-history");
483 km.bind("^R", "history-incremental-search-backward");
484 km.bind("^S", "history-incremental-search-forward");
485
486 km.bind("^I", "expand-or-complete"); km.bind("\\e\\e", "complete-word");
489
490 km.bind("^J", "accept-line"); km.bind("^M", "accept-line"); km.bind("^G", "send-break");
494 km.bind("^C", "send-break");
495 km.bind("^L", "clear-screen");
496
497 km.bind("^T", "transpose-chars");
499 km.bind("\\et", "transpose-words");
500
501 km.bind("\\ec", "capitalize-word");
503 km.bind("\\el", "down-case-word");
504 km.bind("\\eu", "up-case-word");
505
506 km.bind("^@", "set-mark-command"); km.bind("^X^X", "exchange-point-and-mark");
509 km.bind("\\ew", "copy-region-as-kill");
510
511 km
512 }
513
514 pub fn viins_default() -> Self {
516 let mut km = Self::new();
517
518 km.bind("^[", "vi-cmd-mode"); km.bind("^H", "backward-delete-char");
523 km.bind("^?", "backward-delete-char");
524 km.bind("^W", "backward-kill-word");
525 km.bind("^U", "backward-kill-line");
526
527 km.bind("^J", "accept-line");
529 km.bind("^M", "accept-line");
530
531 km.bind("^I", "expand-or-complete");
533
534 km.bind("^P", "up-line-or-history");
536 km.bind("^N", "down-line-or-history");
537
538 km
539 }
540
541 pub fn vicmd_default() -> Self {
543 let mut km = Self::new();
544
545 km.bind("i", "vi-insert");
547 km.bind("a", "vi-add-next");
548 km.bind("I", "vi-insert-bol");
549 km.bind("A", "vi-add-eol");
550
551 km.bind("h", "backward-char");
553 km.bind("l", "forward-char");
554 km.bind("w", "forward-word");
555 km.bind("b", "backward-word");
556 km.bind("0", "beginning-of-line");
557 km.bind("^", "beginning-of-line");
558 km.bind("$", "end-of-line");
559
560 km.bind("x", "delete-char");
562 km.bind("X", "backward-delete-char");
563 km.bind("dd", "kill-whole-line");
564 km.bind("dw", "kill-word");
565 km.bind("db", "backward-kill-word");
566 km.bind("d$", "kill-line");
567 km.bind("d0", "backward-kill-line");
568
569 km.bind("y", "vi-yank");
571 km.bind("p", "vi-put-after");
572 km.bind("P", "vi-put-before");
573
574 km.bind("k", "up-line-or-history");
576 km.bind("j", "down-line-or-history");
577 km.bind("/", "history-incremental-search-backward");
578 km.bind("?", "history-incremental-search-forward");
579 km.bind("n", "vi-repeat-search");
580 km.bind("N", "vi-rev-repeat-search");
581
582 km.bind("u", "undo");
584 km.bind("^R", "redo");
585
586 km.bind("^J", "accept-line");
588 km.bind("^M", "accept-line");
589
590 km
591 }
592
593 pub fn bind(&mut self, keys: &str, widget: &str) {
595 let normalized = Self::normalize_keys(keys);
596 self.bindings.insert(normalized, widget.to_string());
597 }
598
599 pub fn unbind(&mut self, keys: &str) {
601 let normalized = Self::normalize_keys(keys);
602 self.bindings.remove(&normalized);
603 }
604
605 pub fn lookup(&self, keys: &str) -> Option<&str> {
607 let normalized = Self::normalize_keys(keys);
608 self.bindings.get(&normalized).map(|s| s.as_str())
609 }
610
611 pub fn has_prefix(&self, keys: &str) -> bool {
613 let normalized = Self::normalize_keys(keys);
614 self.bindings
615 .keys()
616 .any(|k| k.starts_with(&normalized) && k != &normalized)
617 }
618
619 pub fn list_bindings(&self) -> impl Iterator<Item = (&str, &str)> {
621 self.bindings.iter().map(|(k, v)| (k.as_str(), v.as_str()))
622 }
623
624 fn normalize_keys(keys: &str) -> String {
631 let mut result = String::new();
632 let mut chars = keys.chars().peekable();
633
634 while let Some(c) = chars.next() {
635 match c {
636 '^' => {
637 if let Some(&next) = chars.peek() {
639 chars.next();
640 let ctrl_char = if next == '?' {
641 '\x7f' } else if next == '@' {
643 '\x00' } else if next == '[' {
645 '\x1b' } else {
647 ((next.to_ascii_uppercase() as u8) & 0x1f) as char
649 };
650 result.push(ctrl_char);
651 } else {
652 result.push(c);
653 }
654 }
655 '\\' => {
656 if let Some(&next) = chars.peek() {
658 match next {
659 'e' | 'E' => {
660 chars.next();
661 result.push('\x1b'); }
663 'C' => {
664 chars.next();
665 if chars.peek() == Some(&'-') {
666 chars.next();
667 if let Some(&ctrl_char) = chars.peek() {
668 chars.next();
669 let ctrl =
670 ((ctrl_char.to_ascii_uppercase() as u8) & 0x1f) as char;
671 result.push(ctrl);
672 }
673 }
674 }
675 'M' => {
676 chars.next();
677 if chars.peek() == Some(&'-') {
678 chars.next();
679 result.push('\x1b'); if let Some(&meta_char) = chars.peek() {
681 chars.next();
682 result.push(meta_char);
683 }
684 }
685 }
686 'n' => {
687 chars.next();
688 result.push('\n');
689 }
690 't' => {
691 chars.next();
692 result.push('\t');
693 }
694 'r' => {
695 chars.next();
696 result.push('\r');
697 }
698 '\\' => {
699 chars.next();
700 result.push('\\');
701 }
702 _ => {
703 result.push(c);
704 }
705 }
706 } else {
707 result.push(c);
708 }
709 }
710 _ => result.push(c),
711 }
712 }
713
714 result
715 }
716}
717
718#[cfg(test)]
719mod tests {
720 use super::*;
721
722 #[test]
723 fn test_normalize_keys() {
724 assert_eq!(Keymap::normalize_keys("^A"), "\x01");
725 assert_eq!(Keymap::normalize_keys("^?"), "\x7f");
726 assert_eq!(Keymap::normalize_keys("\\ef"), "\x1bf");
727 assert_eq!(Keymap::normalize_keys("\\C-a"), "\x01");
728 assert_eq!(Keymap::normalize_keys("\\M-x"), "\x1bx");
729 }
730
731 #[test]
732 fn test_keymap_bind_lookup() {
733 let mut km = Keymap::new();
734 km.bind("^A", "beginning-of-line");
735
736 assert_eq!(km.lookup("^A"), Some("beginning-of-line"));
737 assert_eq!(km.lookup("\x01"), Some("beginning-of-line"));
738 }
739
740 #[test]
741 fn test_has_prefix() {
742 let mut km = Keymap::new();
743 km.bind("^X^U", "undo");
744
745 assert!(km.has_prefix("^X"));
746 assert!(!km.has_prefix("^X^U"));
747 assert!(!km.has_prefix("^A"));
748 }
749}