1use std::collections::VecDeque;
18use std::io::{self, Read, Write};
19use std::os::unix::io::{AsRawFd, RawFd};
20use std::time::{Duration, Instant};
21
22use super::keymap::{Keymap, KeymapManager};
23use super::thingy::Thingy;
24use super::widget::{Widget, WidgetFlags};
25
26pub type ZleChar = char;
28
29pub type ZleString = Vec<ZleChar>;
31
32pub type ZleInt = i32;
34
35pub const ZLEEOF: ZleInt = -1;
37
38#[derive(Debug, Clone, Copy, Default)]
40pub struct ZleReadFlags {
41 pub no_history: bool,
43 pub completion: bool,
45 pub vared: bool,
47}
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
51pub enum ZleContext {
52 #[default]
53 Line,
54 Cont,
55 Select,
56 Vared,
57}
58
59#[derive(Debug, Clone, Default)]
61pub struct Modifier {
62 pub flags: ModifierFlags,
63 pub mult: i32,
65 pub tmult: i32,
67 pub vibuf: i32,
69 pub base: i32,
71}
72
73bitflags::bitflags! {
74 #[derive(Debug, Clone, Copy, Default)]
75 pub struct ModifierFlags: u32 {
76 const MULT = 1 << 0;
78 const TMULT = 1 << 1;
80 const VIBUF = 1 << 2;
82 const VIAPP = 1 << 3;
84 const NEG = 1 << 4;
86 const NULL = 1 << 5;
88 const CHAR = 1 << 6;
90 const LINE = 1 << 7;
92 const PRI = 1 << 8;
94 const CLIP = 1 << 9;
96 }
97}
98
99#[derive(Debug, Clone)]
101pub struct Change {
102 pub flags: ChangeFlags,
104 pub hist: i32,
106 pub off: usize,
108 pub del: ZleString,
110 pub ins: ZleString,
112 pub old_cs: usize,
114 pub new_cs: usize,
116 pub changeno: u64,
118}
119
120bitflags::bitflags! {
121 #[derive(Debug, Clone, Copy, Default)]
122 pub struct ChangeFlags: u32 {
123 const NEXT = 1 << 0;
125 const PREV = 1 << 1;
127 }
128}
129
130#[derive(Debug, Clone)]
132pub struct WatchFd {
133 pub fd: RawFd,
134 pub func: String,
135}
136
137#[derive(Debug, Clone, Copy, PartialEq, Eq)]
139pub enum TimeoutType {
140 None,
141 Key,
142 Func,
143 Max,
144}
145
146#[derive(Debug, Clone)]
148pub struct Timeout {
149 pub tp: TimeoutType,
150 pub exp100ths: u64,
152}
153
154pub const ZMAXTIMEOUT: u64 = 1 << 21;
156
157pub struct Zle {
159 pub zleline: ZleString,
161 pub zlecs: usize,
163 pub zlell: usize,
165 pub mark: usize,
167 pub insmode: bool,
169 pub done: bool,
171 pub lastchar: ZleInt,
173 pub lastchar_wide: ZleInt,
175 pub lastchar_wide_valid: bool,
177 pub lbindk: Option<Thingy>,
179 pub bindk: Option<Thingy>,
181 pub lastcmd: WidgetFlags,
183 pub zmod: Modifier,
185 pub prefixflag: bool,
187 pub zle_recursive: i32,
189 pub zlereadflags: ZleReadFlags,
191 pub zlecontext: ZleContext,
193 pub statusline: Option<String>,
195 pub stackhist: i32,
197 pub stackcs: usize,
199 pub vistartchange: u64,
201 pub undo_stack: Vec<Change>,
203 pub changeno: u64,
205 unget_buf: VecDeque<u8>,
207 eofchar: u8,
209 eofsent: bool,
211 pub keytimeout: u64,
213 baud: u32,
215 pub watch_fds: Vec<WatchFd>,
217 pub keymaps: KeymapManager,
219 pub compwidget: Option<Widget>,
221 pub incompctlfunc: bool,
223 pub hascompmod: bool,
225 ttyfd: RawFd,
227 lprompt: String,
229 rprompt: String,
231 pre_zle_status: i32,
233 pub resetneeded: bool,
235 pub vibuf: [ZleString; 36],
237 pub killring: VecDeque<ZleString>,
239 pub killringmax: usize,
241 pub yanklast: bool,
243 pub neg_arg: bool,
245 pub mult: i32,
247}
248
249impl Default for Zle {
250 fn default() -> Self {
251 Self::new()
252 }
253}
254
255impl Zle {
256 pub fn new() -> Self {
257 Zle {
258 zleline: Vec::new(),
259 zlecs: 0,
260 zlell: 0,
261 mark: 0,
262 insmode: true,
263 done: false,
264 lastchar: 0,
265 lastchar_wide: 0,
266 lastchar_wide_valid: false,
267 lbindk: None,
268 bindk: None,
269 lastcmd: WidgetFlags::empty(),
270 zmod: Modifier::default(),
271 prefixflag: false,
272 zle_recursive: 0,
273 zlereadflags: ZleReadFlags::default(),
274 zlecontext: ZleContext::default(),
275 statusline: None,
276 stackhist: 0,
277 stackcs: 0,
278 vistartchange: 0,
279 undo_stack: Vec::new(),
280 changeno: 0,
281 unget_buf: VecDeque::new(),
282 eofchar: 4, eofsent: false,
284 keytimeout: 40, baud: 38400,
286 watch_fds: Vec::new(),
287 keymaps: KeymapManager::new(),
288 compwidget: None,
289 incompctlfunc: false,
290 hascompmod: false,
291 ttyfd: 0, lprompt: String::new(),
293 rprompt: String::new(),
294 pre_zle_status: 0,
295 resetneeded: false,
296 vibuf: std::array::from_fn(|_| Vec::new()),
297 killring: VecDeque::new(),
298 killringmax: 8,
299 yanklast: false,
300 neg_arg: false,
301 mult: 1,
302 }
303 }
304
305 pub fn zsetterm(&mut self) -> io::Result<()> {
307 use std::os::unix::io::FromRawFd;
308
309 let mut termios = termios::Termios::from_fd(self.ttyfd)?;
311
312 termios.c_lflag &= !(termios::ICANON | termios::ECHO);
316 termios.c_cc[termios::VMIN] = 1;
317 termios.c_cc[termios::VTIME] = 0;
318
319 termios::tcsetattr(self.ttyfd, termios::TCSANOW, &termios)?;
321
322 Ok(())
323 }
324
325 pub fn ungetbyte(&mut self, ch: u8) {
327 self.unget_buf.push_front(ch);
328 }
329
330 pub fn ungetbytes(&mut self, s: &[u8]) {
332 for &b in s.iter().rev() {
333 self.unget_buf.push_front(b);
334 }
335 }
336
337 fn calc_timeout(&self, do_keytmout: bool) -> Timeout {
339 if do_keytmout && self.keytimeout > 0 {
340 let exp = if self.keytimeout > ZMAXTIMEOUT * 100 {
341 ZMAXTIMEOUT * 100
342 } else {
343 self.keytimeout
344 };
345 Timeout {
346 tp: TimeoutType::Key,
347 exp100ths: exp,
348 }
349 } else {
350 Timeout {
351 tp: TimeoutType::None,
352 exp100ths: 0,
353 }
354 }
355 }
356
357 pub fn raw_getbyte(&mut self, do_keytmout: bool) -> Option<u8> {
359 if let Some(b) = self.unget_buf.pop_front() {
361 return Some(b);
362 }
363
364 let timeout = self.calc_timeout(do_keytmout);
365
366 let timeout_duration = if timeout.tp != TimeoutType::None {
367 Some(Duration::from_millis(timeout.exp100ths * 10))
368 } else {
369 None
370 };
371
372 let mut buf = [0u8; 1];
374
375 if let Some(dur) = timeout_duration {
376 let start = Instant::now();
378 loop {
379 if start.elapsed() >= dur {
380 return None; }
382
383 match self.try_read_byte(&mut buf) {
385 Ok(true) => return Some(buf[0]),
386 Ok(false) => {
387 std::thread::sleep(Duration::from_millis(10));
389 }
390 Err(_) => return None,
391 }
392 }
393 } else {
394 match io::stdin().read(&mut buf) {
396 Ok(1) => Some(buf[0]),
397 _ => None,
398 }
399 }
400 }
401
402 fn try_read_byte(&self, buf: &mut [u8]) -> io::Result<bool> {
404 use std::os::unix::io::AsRawFd;
405
406 let mut fds = [libc::pollfd {
407 fd: io::stdin().as_raw_fd(),
408 events: libc::POLLIN,
409 revents: 0,
410 }];
411
412 let ret = unsafe { libc::poll(fds.as_mut_ptr(), 1, 0) };
413
414 if ret > 0 && (fds[0].revents & libc::POLLIN) != 0 {
415 match io::stdin().read(buf) {
416 Ok(1) => Ok(true),
417 Ok(_) => Ok(false),
418 Err(e) => Err(e),
419 }
420 } else {
421 Ok(false)
422 }
423 }
424
425 pub fn getbyte(&mut self, do_keytmout: bool) -> Option<u8> {
427 let b = self.raw_getbyte(do_keytmout)?;
428
429 let b = if b == b'\n' {
432 b'\r'
433 } else if b == b'\r' {
434 b'\n'
435 } else {
436 b
437 };
438
439 self.lastchar = b as ZleInt;
440 Some(b)
441 }
442
443 pub fn getfullchar(&mut self, do_keytmout: bool) -> Option<char> {
445 let b = self.getbyte(do_keytmout)?;
446
447 if b < 0x80 {
449 let c = b as char;
450 self.lastchar_wide = c as ZleInt;
451 self.lastchar_wide_valid = true;
452 return Some(c);
453 }
454
455 let mut bytes = vec![b];
457 let expected_len = if b < 0xE0 {
458 2
459 } else if b < 0xF0 {
460 3
461 } else {
462 4
463 };
464
465 while bytes.len() < expected_len {
466 if let Some(next) = self.getbyte(true) {
467 if (next & 0xC0) != 0x80 {
468 self.ungetbyte(next);
470 break;
471 }
472 bytes.push(next);
473 } else {
474 break;
475 }
476 }
477
478 match std::str::from_utf8(&bytes) {
479 Ok(s) => {
480 if let Some(c) = s.chars().next() {
481 self.lastchar_wide = c as ZleInt;
482 self.lastchar_wide_valid = true;
483 return Some(c);
484 }
485 }
486 Err(_) => {}
487 }
488
489 self.lastchar_wide_valid = false;
490 None
491 }
492
493 pub fn redrawhook(&mut self) {
495 }
498
499 pub fn zlecore(&mut self) {
501 self.done = false;
502
503 while !self.done {
504 if !self.prefixflag {
506 self.zmod = Modifier::default();
507 }
508 self.prefixflag = false;
509
510 let c = match self.getfullchar(false) {
512 Some(c) => c,
513 None => {
514 self.done = true;
515 continue;
516 }
517 };
518
519 let key = c;
521
522 if let Some(thingy) = self.keymaps.lookup_key(key) {
523 self.lbindk = self.bindk.take();
524 self.bindk = Some(thingy.clone());
525
526 if let Some(widget) = &thingy.widget {
528 self.execute_widget(widget);
529 }
530 } else {
531 self.do_self_insert(key);
533 }
534
535 if self.resetneeded {
537 self.zrefresh();
538 self.resetneeded = false;
539 }
540 }
541 }
542
543 fn execute_widget(&mut self, widget: &Widget) {
545 self.lastcmd = widget.flags;
546
547 match &widget.func {
548 super::widget::WidgetFunc::Internal(f) => {
549 f(self);
550 }
551 super::widget::WidgetFunc::User(name) => {
552 let _ = name;
555 }
556 }
557 }
558
559 fn do_self_insert(&mut self, c: char) {
561 if self.insmode {
562 self.zleline.insert(self.zlecs, c);
564 self.zlecs += 1;
565 self.zlell += 1;
566 } else {
567 if self.zlecs < self.zlell {
569 self.zleline[self.zlecs] = c;
570 } else {
571 self.zleline.push(c);
572 self.zlell += 1;
573 }
574 self.zlecs += 1;
575 }
576 self.resetneeded = true;
577 }
578
579 pub fn zleread(
581 &mut self,
582 lprompt: &str,
583 rprompt: &str,
584 flags: ZleReadFlags,
585 context: ZleContext,
586 ) -> io::Result<String> {
587 self.lprompt = lprompt.to_string();
588 self.rprompt = rprompt.to_string();
589 self.zlereadflags = flags;
590 self.zlecontext = context;
591
592 self.zleline.clear();
594 self.zlecs = 0;
595 self.zlell = 0;
596 self.mark = 0;
597 self.done = false;
598
599 self.zsetterm()?;
601
602 print!("{}", lprompt);
604 io::stdout().flush()?;
605
606 self.zlecore();
608
609 Ok(self.zleline.iter().collect())
611 }
612
613 pub fn initmodifier(&mut self) {
615 self.zmod = Modifier {
616 flags: ModifierFlags::empty(),
617 mult: 1,
618 tmult: 0,
619 vibuf: -1,
620 base: 10,
621 };
622 }
623
624 pub fn handleprefixes(&mut self) {
626 if self.zmod.flags.contains(ModifierFlags::TMULT) {
627 self.zmod.flags.remove(ModifierFlags::TMULT);
628 self.zmod.flags.insert(ModifierFlags::MULT);
629 self.zmod.mult = self.zmod.tmult;
630 }
631 }
632
633 pub fn trashzle(&mut self) {
635 print!("\r\x1b[K");
636 io::stdout().flush().ok();
637 }
638
639 pub fn resetprompt(&mut self) {
641 self.resetneeded = true;
642 }
643
644 pub fn reexpandprompt(&mut self) {
646 self.resetneeded = true;
648 }
649
650 pub fn recursive_edit(&mut self) -> i32 {
652 self.zle_recursive += 1;
653
654 let old_done = self.done;
655 self.done = false;
656
657 self.zlecore();
658
659 self.done = old_done;
660 self.zle_recursive -= 1;
661
662 0
663 }
664
665 pub fn finish_line(&mut self) {
667 self.done = true;
668 }
669
670 pub fn abort_line(&mut self) {
672 self.zleline.clear();
673 self.zlecs = 0;
674 self.zlell = 0;
675 self.done = true;
676 }
677}
678
679impl Zle {
680 pub fn save_keymap(&mut self) -> SavedKeymap {
683 SavedKeymap {
684 name: self.keymaps.current_name.clone(),
685 local: self.keymaps.local.clone(),
686 }
687 }
688
689 pub fn restore_keymap(&mut self, saved: SavedKeymap) {
692 self.keymaps.select(&saved.name);
693 self.keymaps.local = saved.local;
694 }
695
696 pub fn describe_key_briefly(&mut self) {
699 if let Some(c) = self.getfullchar(false) {
700 if let Some(thingy) = self.keymaps.lookup_key(c) {
701 self.display_msg(&format!("{} is bound to {}", c, thingy.name));
702 } else {
703 self.display_msg(&format!("{} is not bound", c));
704 }
705 }
706 }
707
708 pub fn whereis(&self, widget_name: &str) -> Vec<String> {
711 let mut bindings = Vec::new();
712
713 for (name, km) in &self.keymaps.keymaps {
714 for (i, opt) in km.first.iter().enumerate() {
716 if let Some(t) = opt {
717 if t.name == widget_name {
718 bindings.push(format!("{}:{}", name, super::utils::print_bind(&[i as u8])));
719 }
720 }
721 }
722
723 for (seq, kb) in &km.multi {
725 if let Some(ref t) = kb.bind {
726 if t.name == widget_name {
727 bindings.push(format!("{}:{}", name, super::utils::print_bind(seq)));
728 }
729 }
730 }
731 }
732
733 bindings
734 }
735
736 pub fn exec_immortal(&mut self, name: &str) -> bool {
739 if let Some(widget) = get_builtin_widget(name) {
740 self.execute_widget(&widget);
741 true
742 } else {
743 false
744 }
745 }
746
747 pub fn exec_zle_func(&mut self, name: &str, _args: &[String]) -> i32 {
750 if let Some(widget) = get_builtin_widget(name) {
751 self.execute_widget(&widget);
752 0
753 } else {
754 1
756 }
757 }
758
759 pub fn break_read(&mut self) {
762 self.done = true;
763 }
764
765 pub fn before_trap(&mut self) {
768 }
770
771 pub fn after_trap(&mut self) {
774 self.resetneeded = true;
776 }
777
778 pub fn zle_reset_prompt(&mut self) {
781 self.resetneeded = true;
782 }
783
784 fn display_msg(&self, msg: &str) {
786 eprintln!("{}", msg);
787 }
788
789 pub fn prompt(&self) -> &str {
791 &self.lprompt
792 }
793
794 pub fn set_prompt(&mut self, prompt: &str) {
796 self.lprompt = prompt.to_string();
797 self.resetneeded = true;
798 }
799
800 pub fn get_mult(&self) -> i32 {
802 if self.zmod.flags.contains(ModifierFlags::MULT) {
803 self.zmod.mult
804 } else {
805 1
806 }
807 }
808
809 pub fn toggle_neg_arg(&mut self) {
811 self.zmod.flags.toggle(ModifierFlags::NEG);
812 }
813
814 pub fn is_neg(&self) -> bool {
816 self.zmod.flags.contains(ModifierFlags::NEG)
817 }
818
819 pub fn is_vicmd(&self) -> bool {
821 self.keymaps.is_vi_cmd()
822 }
823
824 pub fn is_viins(&self) -> bool {
826 self.keymaps.is_vi_insert()
827 }
828
829 pub fn is_emacs(&self) -> bool {
831 self.keymaps.is_emacs()
832 }
833
834 pub fn was_yank(&self) -> bool {
836 self.lastcmd.contains(WidgetFlags::YANK)
837 }
838}
839
840#[derive(Debug, Clone)]
842pub struct SavedKeymap {
843 pub name: String,
844 pub local: Option<std::sync::Arc<Keymap>>,
845}
846
847fn get_builtin_widget(name: &str) -> Option<Widget> {
849 Some(Widget::builtin(name))
850}
851
852pub fn bin_vared(zle: &mut Zle, varname: &str, opts: VaredOpts) -> io::Result<String> {
855 let initial = std::env::var(varname).unwrap_or_default();
857
858 zle.zleline = initial.chars().collect();
860 zle.zlell = zle.zleline.len();
861 zle.zlecs = if opts.cursor_at_end { zle.zlell } else { 0 };
862
863 let prompt = opts.prompt.as_deref().unwrap_or("");
865 let rprompt = opts.rprompt.as_deref().unwrap_or("");
866
867 let result = zle.zleread(
868 prompt,
869 rprompt,
870 ZleReadFlags {
871 vared: true,
872 ..Default::default()
873 },
874 ZleContext::Vared,
875 )?;
876
877 Ok(result)
878}
879
880#[derive(Debug, Default)]
882pub struct VaredOpts {
883 pub prompt: Option<String>,
884 pub rprompt: Option<String>,
885 pub cursor_at_end: bool,
886 pub history: bool,
887}
888
889pub fn zle_main_entry(op: ZleOperation, data: ZleData) -> i32 {
892 match op {
893 ZleOperation::Read => {
894 0
896 }
897 ZleOperation::Refresh => {
898 0
900 }
901 ZleOperation::Invalidate => {
902 0
904 }
905 ZleOperation::Reset => {
906 0
908 }
909 _ => 1,
910 }
911}
912
913#[derive(Debug, Clone, Copy)]
915pub enum ZleOperation {
916 Read,
917 Refresh,
918 Invalidate,
919 Reset,
920 SetKeymap,
921}
922
923#[derive(Debug, Default)]
925pub struct ZleData {
926 pub prompt: Option<String>,
927 pub keymap: Option<String>,
928}
929
930mod termios {
932 pub use libc::{ECHO, ICANON, TCSANOW, VMIN, VTIME};
933 use std::io;
934 use std::os::unix::io::RawFd;
935
936 #[derive(Clone)]
937 pub struct Termios {
938 inner: libc::termios,
939 }
940
941 impl Termios {
942 pub fn from_fd(fd: RawFd) -> io::Result<Self> {
943 let mut termios = std::mem::MaybeUninit::uninit();
944 let ret = unsafe { libc::tcgetattr(fd, termios.as_mut_ptr()) };
945 if ret != 0 {
946 return Err(io::Error::last_os_error());
947 }
948 Ok(Termios {
949 inner: unsafe { termios.assume_init() },
950 })
951 }
952 }
953
954 impl std::ops::Deref for Termios {
955 type Target = libc::termios;
956 fn deref(&self) -> &Self::Target {
957 &self.inner
958 }
959 }
960
961 impl std::ops::DerefMut for Termios {
962 fn deref_mut(&mut self) -> &mut Self::Target {
963 &mut self.inner
964 }
965 }
966
967 pub fn tcsetattr(fd: RawFd, action: i32, termios: &Termios) -> io::Result<()> {
968 let ret = unsafe { libc::tcsetattr(fd, action, &termios.inner) };
969 if ret != 0 {
970 return Err(io::Error::last_os_error());
971 }
972 Ok(())
973 }
974}