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 if let Ok(s) = std::str::from_utf8(&bytes) {
479 if let Some(c) = s.chars().next() {
480 self.lastchar_wide = c as ZleInt;
481 self.lastchar_wide_valid = true;
482 return Some(c);
483 }
484 }
485
486 self.lastchar_wide_valid = false;
487 None
488 }
489
490 pub fn redrawhook(&mut self) {
492 }
495
496 pub fn zlecore(&mut self) {
498 self.done = false;
499
500 while !self.done {
501 if !self.prefixflag {
503 self.zmod = Modifier::default();
504 }
505 self.prefixflag = false;
506
507 let c = match self.getfullchar(false) {
509 Some(c) => c,
510 None => {
511 self.done = true;
512 continue;
513 }
514 };
515
516 let key = c;
518
519 if let Some(thingy) = self.keymaps.lookup_key(key) {
520 self.lbindk = self.bindk.take();
521 self.bindk = Some(thingy.clone());
522
523 if let Some(widget) = &thingy.widget {
525 self.execute_widget(widget);
526 }
527 } else {
528 self.do_self_insert(key);
530 }
531
532 if self.resetneeded {
534 self.zrefresh();
535 self.resetneeded = false;
536 }
537 }
538 }
539
540 fn execute_widget(&mut self, widget: &Widget) {
542 self.lastcmd = widget.flags;
543
544 match &widget.func {
545 super::widget::WidgetFunc::Internal(f) => {
546 f(self);
547 }
548 super::widget::WidgetFunc::User(name) => {
549 let _ = name;
552 }
553 }
554 }
555
556 fn do_self_insert(&mut self, c: char) {
558 if self.insmode {
559 self.zleline.insert(self.zlecs, c);
561 self.zlecs += 1;
562 self.zlell += 1;
563 } else {
564 if self.zlecs < self.zlell {
566 self.zleline[self.zlecs] = c;
567 } else {
568 self.zleline.push(c);
569 self.zlell += 1;
570 }
571 self.zlecs += 1;
572 }
573 self.resetneeded = true;
574 }
575
576 pub fn zleread(
578 &mut self,
579 lprompt: &str,
580 rprompt: &str,
581 flags: ZleReadFlags,
582 context: ZleContext,
583 ) -> io::Result<String> {
584 self.lprompt = lprompt.to_string();
585 self.rprompt = rprompt.to_string();
586 self.zlereadflags = flags;
587 self.zlecontext = context;
588
589 self.zleline.clear();
591 self.zlecs = 0;
592 self.zlell = 0;
593 self.mark = 0;
594 self.done = false;
595
596 self.zsetterm()?;
598
599 print!("{}", lprompt);
601 io::stdout().flush()?;
602
603 self.zlecore();
605
606 Ok(self.zleline.iter().collect())
608 }
609
610 pub fn initmodifier(&mut self) {
612 self.zmod = Modifier {
613 flags: ModifierFlags::empty(),
614 mult: 1,
615 tmult: 0,
616 vibuf: -1,
617 base: 10,
618 };
619 }
620
621 pub fn handleprefixes(&mut self) {
623 if self.zmod.flags.contains(ModifierFlags::TMULT) {
624 self.zmod.flags.remove(ModifierFlags::TMULT);
625 self.zmod.flags.insert(ModifierFlags::MULT);
626 self.zmod.mult = self.zmod.tmult;
627 }
628 }
629
630 pub fn trashzle(&mut self) {
632 print!("\r\x1b[K");
633 io::stdout().flush().ok();
634 }
635
636 pub fn resetprompt(&mut self) {
638 self.resetneeded = true;
639 }
640
641 pub fn reexpandprompt(&mut self) {
643 self.resetneeded = true;
645 }
646
647 pub fn recursive_edit(&mut self) -> i32 {
649 self.zle_recursive += 1;
650
651 let old_done = self.done;
652 self.done = false;
653
654 self.zlecore();
655
656 self.done = old_done;
657 self.zle_recursive -= 1;
658
659 0
660 }
661
662 pub fn finish_line(&mut self) {
664 self.done = true;
665 }
666
667 pub fn abort_line(&mut self) {
669 self.zleline.clear();
670 self.zlecs = 0;
671 self.zlell = 0;
672 self.done = true;
673 }
674}
675
676impl Zle {
677 pub fn save_keymap(&mut self) -> SavedKeymap {
680 SavedKeymap {
681 name: self.keymaps.current_name.clone(),
682 local: self.keymaps.local.clone(),
683 }
684 }
685
686 pub fn restore_keymap(&mut self, saved: SavedKeymap) {
689 self.keymaps.select(&saved.name);
690 self.keymaps.local = saved.local;
691 }
692
693 pub fn describe_key_briefly(&mut self) {
696 if let Some(c) = self.getfullchar(false) {
697 if let Some(thingy) = self.keymaps.lookup_key(c) {
698 self.display_msg(&format!("{} is bound to {}", c, thingy.name));
699 } else {
700 self.display_msg(&format!("{} is not bound", c));
701 }
702 }
703 }
704
705 pub fn whereis(&self, widget_name: &str) -> Vec<String> {
708 let mut bindings = Vec::new();
709
710 for (name, km) in &self.keymaps.keymaps {
711 for (i, opt) in km.first.iter().enumerate() {
713 if let Some(t) = opt {
714 if t.name == widget_name {
715 bindings.push(format!("{}:{}", name, super::utils::print_bind(&[i as u8])));
716 }
717 }
718 }
719
720 for (seq, kb) in &km.multi {
722 if let Some(ref t) = kb.bind {
723 if t.name == widget_name {
724 bindings.push(format!("{}:{}", name, super::utils::print_bind(seq)));
725 }
726 }
727 }
728 }
729
730 bindings
731 }
732
733 pub fn exec_immortal(&mut self, name: &str) -> bool {
736 if let Some(widget) = get_builtin_widget(name) {
737 self.execute_widget(&widget);
738 true
739 } else {
740 false
741 }
742 }
743
744 pub fn exec_zle_func(&mut self, name: &str, _args: &[String]) -> i32 {
747 if let Some(widget) = get_builtin_widget(name) {
748 self.execute_widget(&widget);
749 0
750 } else {
751 1
753 }
754 }
755
756 pub fn break_read(&mut self) {
759 self.done = true;
760 }
761
762 pub fn before_trap(&mut self) {
765 }
767
768 pub fn after_trap(&mut self) {
771 self.resetneeded = true;
773 }
774
775 pub fn zle_reset_prompt(&mut self) {
778 self.resetneeded = true;
779 }
780
781 fn display_msg(&self, msg: &str) {
783 eprintln!("{}", msg);
784 }
785
786 pub fn prompt(&self) -> &str {
788 &self.lprompt
789 }
790
791 pub fn set_prompt(&mut self, prompt: &str) {
793 self.lprompt = prompt.to_string();
794 self.resetneeded = true;
795 }
796
797 pub fn get_mult(&self) -> i32 {
799 if self.zmod.flags.contains(ModifierFlags::MULT) {
800 self.zmod.mult
801 } else {
802 1
803 }
804 }
805
806 pub fn toggle_neg_arg(&mut self) {
808 self.zmod.flags.toggle(ModifierFlags::NEG);
809 }
810
811 pub fn is_neg(&self) -> bool {
813 self.zmod.flags.contains(ModifierFlags::NEG)
814 }
815
816 pub fn is_vicmd(&self) -> bool {
818 self.keymaps.is_vi_cmd()
819 }
820
821 pub fn is_viins(&self) -> bool {
823 self.keymaps.is_vi_insert()
824 }
825
826 pub fn is_emacs(&self) -> bool {
828 self.keymaps.is_emacs()
829 }
830
831 pub fn was_yank(&self) -> bool {
833 self.lastcmd.contains(WidgetFlags::YANK)
834 }
835}
836
837#[derive(Debug, Clone)]
839pub struct SavedKeymap {
840 pub name: String,
841 pub local: Option<std::sync::Arc<Keymap>>,
842}
843
844fn get_builtin_widget(name: &str) -> Option<Widget> {
846 Some(Widget::builtin(name))
847}
848
849pub fn bin_vared(zle: &mut Zle, varname: &str, opts: VaredOpts) -> io::Result<String> {
852 let initial = std::env::var(varname).unwrap_or_default();
854
855 zle.zleline = initial.chars().collect();
857 zle.zlell = zle.zleline.len();
858 zle.zlecs = if opts.cursor_at_end { zle.zlell } else { 0 };
859
860 let prompt = opts.prompt.as_deref().unwrap_or("");
862 let rprompt = opts.rprompt.as_deref().unwrap_or("");
863
864 let result = zle.zleread(
865 prompt,
866 rprompt,
867 ZleReadFlags {
868 vared: true,
869 ..Default::default()
870 },
871 ZleContext::Vared,
872 )?;
873
874 Ok(result)
875}
876
877#[derive(Debug, Default)]
879pub struct VaredOpts {
880 pub prompt: Option<String>,
881 pub rprompt: Option<String>,
882 pub cursor_at_end: bool,
883 pub history: bool,
884}
885
886pub fn zle_main_entry(op: ZleOperation, data: ZleData) -> i32 {
889 match op {
890 ZleOperation::Read => {
891 0
893 }
894 ZleOperation::Refresh => {
895 0
897 }
898 ZleOperation::Invalidate => {
899 0
901 }
902 ZleOperation::Reset => {
903 0
905 }
906 _ => 1,
907 }
908}
909
910#[derive(Debug, Clone, Copy)]
912pub enum ZleOperation {
913 Read,
914 Refresh,
915 Invalidate,
916 Reset,
917 SetKeymap,
918}
919
920#[derive(Debug, Default)]
922pub struct ZleData {
923 pub prompt: Option<String>,
924 pub keymap: Option<String>,
925}
926
927mod termios {
929 pub use libc::{ECHO, ICANON, TCSANOW, VMIN, VTIME};
930 use std::io;
931 use std::os::unix::io::RawFd;
932
933 #[derive(Clone)]
934 pub struct Termios {
935 inner: libc::termios,
936 }
937
938 impl Termios {
939 pub fn from_fd(fd: RawFd) -> io::Result<Self> {
940 let mut termios = std::mem::MaybeUninit::uninit();
941 let ret = unsafe { libc::tcgetattr(fd, termios.as_mut_ptr()) };
942 if ret != 0 {
943 return Err(io::Error::last_os_error());
944 }
945 Ok(Termios {
946 inner: unsafe { termios.assume_init() },
947 })
948 }
949 }
950
951 impl std::ops::Deref for Termios {
952 type Target = libc::termios;
953 fn deref(&self) -> &Self::Target {
954 &self.inner
955 }
956 }
957
958 impl std::ops::DerefMut for Termios {
959 fn deref_mut(&mut self) -> &mut Self::Target {
960 &mut self.inner
961 }
962 }
963
964 pub fn tcsetattr(fd: RawFd, action: i32, termios: &Termios) -> io::Result<()> {
965 let ret = unsafe { libc::tcsetattr(fd, action, &termios.inner) };
966 if ret != 0 {
967 return Err(io::Error::last_os_error());
968 }
969 Ok(())
970 }
971}