par_term/copy_mode/
types.rs1use std::collections::HashMap;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum VisualMode {
8 None,
10 Char,
12 Line,
14 Block,
16}
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20pub enum PendingOperator {
21 Yank,
23}
24
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27pub enum SearchDirection {
28 Forward,
29 Backward,
30}
31
32#[derive(Debug, Clone, Copy)]
34pub struct Mark {
35 pub col: usize,
36 pub absolute_line: usize,
37}
38
39pub struct CopyModeState {
47 pub active: bool,
49 pub cursor_col: usize,
51 pub cursor_absolute_line: usize,
53 pub visual_mode: VisualMode,
55 pub selection_anchor: Option<(usize, usize)>,
57 pub count: Option<usize>,
59 pub pending_operator: Option<PendingOperator>,
61 pub marks: HashMap<char, Mark>,
63 pub cols: usize,
65 pub rows: usize,
67 pub scrollback_len: usize,
69 pub search_query: String,
71 pub search_direction: SearchDirection,
73 pub is_searching: bool,
75 pub(crate) pending_g: bool,
77 pub(crate) pending_mark_set: bool,
79 pub(crate) pending_mark_goto: bool,
81}
82
83impl Default for CopyModeState {
84 fn default() -> Self {
85 Self::new()
86 }
87}
88
89impl CopyModeState {
90 pub fn new() -> Self {
92 Self {
93 active: false,
94 cursor_col: 0,
95 cursor_absolute_line: 0,
96 visual_mode: VisualMode::None,
97 selection_anchor: None,
98 count: None,
99 pending_operator: None,
100 marks: HashMap::new(),
101 cols: 80,
102 rows: 24,
103 scrollback_len: 0,
104 search_query: String::new(),
105 search_direction: SearchDirection::Forward,
106 is_searching: false,
107 pending_g: false,
108 pending_mark_set: false,
109 pending_mark_goto: false,
110 }
111 }
112
113 pub fn enter(
115 &mut self,
116 cursor_col: usize,
117 cursor_row: usize,
118 cols: usize,
119 rows: usize,
120 scrollback_len: usize,
121 ) {
122 self.active = true;
123 self.cols = cols;
124 self.rows = rows;
125 self.scrollback_len = scrollback_len;
126 self.cursor_absolute_line = scrollback_len + cursor_row;
128 self.cursor_col = cursor_col.min(cols.saturating_sub(1));
129 self.visual_mode = VisualMode::None;
130 self.selection_anchor = None;
131 self.count = None;
132 self.pending_operator = None;
133 self.search_query.clear();
134 self.is_searching = false;
135 self.pending_g = false;
136 self.pending_mark_set = false;
137 self.pending_mark_goto = false;
138 }
139
140 pub fn exit(&mut self) {
142 self.active = false;
143 self.visual_mode = VisualMode::None;
144 self.selection_anchor = None;
145 self.count = None;
146 self.pending_operator = None;
147 self.is_searching = false;
148 self.pending_g = false;
149 self.pending_mark_set = false;
150 self.pending_mark_goto = false;
151 }
152
153 pub(super) fn total_lines(&self) -> usize {
155 self.scrollback_len + self.rows
156 }
157
158 pub(super) fn max_line(&self) -> usize {
160 self.total_lines().saturating_sub(1)
161 }
162
163 pub fn push_count_digit(&mut self, digit: u8) {
165 let current = self.count.unwrap_or(0);
166 self.count = Some(current * 10 + digit as usize);
167 }
168
169 pub fn effective_count(&mut self) -> usize {
171 let c = self.count.unwrap_or(1);
172 self.count = None;
173 c
174 }
175
176 pub fn update_dimensions(&mut self, cols: usize, rows: usize, scrollback_len: usize) {
178 self.cols = cols;
179 self.rows = rows;
180 self.scrollback_len = scrollback_len;
181 self.cursor_col = self.cursor_col.min(cols.saturating_sub(1));
183 self.cursor_absolute_line = self.cursor_absolute_line.min(self.max_line());
184 }
185}