use std::collections::HashMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VisualMode {
None,
Char,
Line,
Block,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PendingOperator {
Yank,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SearchDirection {
Forward,
Backward,
}
#[derive(Debug, Clone, Copy)]
pub struct Mark {
pub col: usize,
pub absolute_line: usize,
}
pub struct CopyModeState {
pub active: bool,
pub cursor_col: usize,
pub cursor_absolute_line: usize,
pub visual_mode: VisualMode,
pub selection_anchor: Option<(usize, usize)>,
pub count: Option<usize>,
pub pending_operator: Option<PendingOperator>,
pub marks: HashMap<char, Mark>,
pub cols: usize,
pub rows: usize,
pub scrollback_len: usize,
pub search_query: String,
pub search_direction: SearchDirection,
pub is_searching: bool,
pub(crate) pending_g: bool,
pub(crate) pending_mark_set: bool,
pub(crate) pending_mark_goto: bool,
}
impl Default for CopyModeState {
fn default() -> Self {
Self::new()
}
}
impl CopyModeState {
pub fn new() -> Self {
Self {
active: false,
cursor_col: 0,
cursor_absolute_line: 0,
visual_mode: VisualMode::None,
selection_anchor: None,
count: None,
pending_operator: None,
marks: HashMap::new(),
cols: 80,
rows: 24,
scrollback_len: 0,
search_query: String::new(),
search_direction: SearchDirection::Forward,
is_searching: false,
pending_g: false,
pending_mark_set: false,
pending_mark_goto: false,
}
}
pub fn enter(
&mut self,
cursor_col: usize,
cursor_row: usize,
cols: usize,
rows: usize,
scrollback_len: usize,
) {
self.active = true;
self.cols = cols;
self.rows = rows;
self.scrollback_len = scrollback_len;
self.cursor_absolute_line = scrollback_len + cursor_row;
self.cursor_col = cursor_col.min(cols.saturating_sub(1));
self.visual_mode = VisualMode::None;
self.selection_anchor = None;
self.count = None;
self.pending_operator = None;
self.search_query.clear();
self.is_searching = false;
self.pending_g = false;
self.pending_mark_set = false;
self.pending_mark_goto = false;
}
pub fn exit(&mut self) {
self.active = false;
self.visual_mode = VisualMode::None;
self.selection_anchor = None;
self.count = None;
self.pending_operator = None;
self.is_searching = false;
self.pending_g = false;
self.pending_mark_set = false;
self.pending_mark_goto = false;
}
pub(super) fn total_lines(&self) -> usize {
self.scrollback_len + self.rows
}
pub(super) fn max_line(&self) -> usize {
self.total_lines().saturating_sub(1)
}
pub fn push_count_digit(&mut self, digit: u8) {
let current = self.count.unwrap_or(0);
self.count = Some(current * 10 + digit as usize);
}
pub fn effective_count(&mut self) -> usize {
let c = self.count.unwrap_or(1);
self.count = None;
c
}
pub fn update_dimensions(&mut self, cols: usize, rows: usize, scrollback_len: usize) {
self.cols = cols;
self.rows = rows;
self.scrollback_len = scrollback_len;
self.cursor_col = self.cursor_col.min(cols.saturating_sub(1));
self.cursor_absolute_line = self.cursor_absolute_line.min(self.max_line());
}
}