Skip to main content

zsh/zle/
params.rs

1//! ZLE parameters
2//!
3//! Direct port from zsh/Src/Zle/zle_params.c
4//!
5//! Special parameters that expose ZLE state to shell scripts
6
7use super::main::Zle;
8
9/// ZLE parameter names
10pub mod names {
11    pub const BUFFER: &str = "BUFFER";
12    pub const CURSOR: &str = "CURSOR";
13    pub const LBUFFER: &str = "LBUFFER";
14    pub const RBUFFER: &str = "RBUFFER";
15    pub const PREBUFFER: &str = "PREBUFFER";
16    pub const WIDGET: &str = "WIDGET";
17    pub const LASTWIDGET: &str = "LASTWIDGET";
18    pub const KEYMAP: &str = "KEYMAP";
19    pub const KEYS: &str = "KEYS";
20    pub const NUMERIC: &str = "NUMERIC";
21    pub const HISTNO: &str = "HISTNO";
22    pub const BUFFERLINES: &str = "BUFFERLINES";
23    pub const PENDING: &str = "PENDING";
24    pub const CUTBUFFER: &str = "CUTBUFFER";
25    pub const KILLRING: &str = "killring";
26    pub const MARK: &str = "MARK";
27    pub const REGION_ACTIVE: &str = "REGION_ACTIVE";
28    pub const ZLE_STATE: &str = "ZLE_STATE";
29}
30
31impl Zle {
32    /// Get BUFFER parameter
33    pub fn get_buffer(&self) -> String {
34        self.zleline.iter().collect()
35    }
36
37    /// Set BUFFER parameter
38    pub fn set_buffer(&mut self, s: &str) {
39        self.zleline = s.chars().collect();
40        self.zlell = self.zleline.len();
41        self.zlecs = self.zlecs.min(self.zlell);
42        self.resetneeded = true;
43    }
44
45    /// Get CURSOR parameter
46    pub fn get_cursor(&self) -> usize {
47        self.zlecs
48    }
49
50    /// Set CURSOR parameter
51    pub fn set_cursor(&mut self, pos: usize) {
52        self.zlecs = pos.min(self.zlell);
53        self.resetneeded = true;
54    }
55
56    /// Get LBUFFER (text before cursor)
57    pub fn get_lbuffer(&self) -> String {
58        self.zleline[..self.zlecs].iter().collect()
59    }
60
61    /// Set LBUFFER
62    pub fn set_lbuffer(&mut self, s: &str) {
63        let rbuf: String = self.zleline[self.zlecs..].iter().collect();
64        self.zleline = s.chars().chain(rbuf.chars()).collect();
65        self.zlell = self.zleline.len();
66        self.zlecs = s.chars().count();
67        self.resetneeded = true;
68    }
69
70    /// Get RBUFFER (text after cursor)
71    pub fn get_rbuffer(&self) -> String {
72        self.zleline[self.zlecs..].iter().collect()
73    }
74
75    /// Set RBUFFER
76    pub fn set_rbuffer(&mut self, s: &str) {
77        let lbuf: String = self.zleline[..self.zlecs].iter().collect();
78        self.zleline = lbuf.chars().chain(s.chars()).collect();
79        self.zlell = self.zleline.len();
80        self.resetneeded = true;
81    }
82
83    /// Get CUTBUFFER (kill ring top)
84    pub fn get_cutbuffer(&self) -> String {
85        self.killring
86            .front()
87            .map(|v| v.iter().collect())
88            .unwrap_or_default()
89    }
90
91    /// Set CUTBUFFER
92    pub fn set_cutbuffer(&mut self, s: &str) {
93        let chars: Vec<char> = s.chars().collect();
94        if self.killring.is_empty() {
95            self.killring.push_front(chars);
96        } else {
97            self.killring[0] = chars;
98        }
99    }
100
101    /// Get MARK parameter
102    pub fn get_mark(&self) -> usize {
103        self.mark
104    }
105
106    /// Set MARK parameter
107    pub fn set_mark(&mut self, pos: usize) {
108        self.mark = pos.min(self.zlell);
109    }
110
111    /// Get BUFFERLINES (number of lines)
112    pub fn get_bufferlines(&self) -> usize {
113        self.zleline.iter().filter(|&&c| c == '\n').count() + 1
114    }
115
116    /// Get PENDING (number of bytes waiting)
117    pub fn get_pending(&self) -> usize {
118        // unget_buf is private, return 0 for now
119        0
120    }
121
122    /// Get current keymap name
123    pub fn get_keymap(&self) -> &str {
124        &self.keymaps.current_name
125    }
126
127    /// Get NUMERIC (numeric argument if set)
128    pub fn get_numeric(&self) -> Option<i32> {
129        if self.zmod.flags.contains(super::main::ModifierFlags::MULT) {
130            Some(self.zmod.mult)
131        } else {
132            None
133        }
134    }
135
136    /// Check if in insert mode
137    pub fn is_insert_mode(&self) -> bool {
138        self.insmode
139    }
140
141    /// Check if region is active
142    pub fn is_region_active(&self) -> bool {
143        // Region is "active" if mark != cursor (simplified)
144        self.mark != self.zlecs
145    }
146
147    /// Get ZLE_STATE string
148    pub fn get_zle_state(&self) -> String {
149        let mut state = String::new();
150
151        if self.insmode {
152            state.push_str("insert");
153        } else {
154            state.push_str("overwrite");
155        }
156
157        // Add keymap info
158        state.push(':');
159        state.push_str(&self.keymaps.current_name);
160
161        state
162    }
163}