Skip to main content

hac_core/text_object/
cursor.rs

1use std::ops::Add;
2
3#[derive(Debug, Default, Clone, PartialEq)]
4pub struct Cursor {
5    row: usize,
6    col: usize,
7    snapback_col: usize,
8    // offsets are used for commands that visually should move the cursor but shouldn't influence in
9    // the actual cursor position on the content
10    col_offset: usize,
11    row_offset: usize,
12}
13
14impl Cursor {
15    pub fn move_left(&mut self, amount: usize) {
16        self.col = self.col.saturating_sub(amount);
17        self.snapback_col = self.col;
18    }
19
20    pub fn move_down(&mut self, amount: usize) {
21        self.row = self.row.add(amount);
22    }
23
24    pub fn move_up(&mut self, amount: usize) {
25        self.row = self.row.saturating_sub(amount);
26    }
27
28    pub fn move_right(&mut self, amount: usize) {
29        self.col = self.col.add(amount);
30        self.snapback_col = self.col;
31    }
32
33    pub fn move_to_newline_start(&mut self) {
34        self.col = 0;
35        self.snapback_col = 0;
36        self.row = self.row.add(1);
37    }
38
39    pub fn move_to_line_start(&mut self) {
40        self.col = 0;
41        self.snapback_col = 0;
42    }
43
44    pub fn move_to_line_end(&mut self, line_len: usize) {
45        self.col = line_len.saturating_sub(1);
46        self.snapback_col = self.col;
47    }
48
49    pub fn move_to_col(&mut self, col: usize) {
50        self.col = col;
51        self.snapback_col = col;
52    }
53
54    pub fn move_to_row(&mut self, row: usize) {
55        self.row = row;
56    }
57
58    pub fn row(&self) -> usize {
59        self.row
60    }
61
62    pub fn col(&self) -> usize {
63        self.col
64    }
65
66    pub fn row_with_offset(&self) -> usize {
67        self.row + self.row_offset
68    }
69
70    pub fn col_with_offset(&self) -> usize {
71        self.col + self.col_offset
72    }
73
74    pub fn set_col_offset(&mut self, offset: usize) {
75        self.col_offset = offset;
76    }
77
78    pub fn set_row_offset(&mut self, offset: usize) {
79        self.row_offset = offset;
80    }
81
82    pub fn readable_position(&self) -> (usize, usize) {
83        (self.col.add(1), self.row.add(1))
84    }
85
86    // when moving horizontally, expand_col and col will always have the same value.
87    //
88    // when moving into a smaller line (line_len < cursor.col) we make so the col is
89    // equal to the length of that line;
90    //
91    // when moving into a bigger line (line_len > cursor.col) we make the col snap back
92    // to the min col between line_len and the current expand_col position.
93    pub fn maybe_snap_to_col(&mut self, line_len: usize) {
94        match line_len.saturating_sub(1).cmp(&self.col) {
95            std::cmp::Ordering::Less => {
96                if self.snapback_col.eq(&self.col) {
97                    self.snapback_col = self.col;
98                }
99                self.col = line_len.saturating_sub(1);
100            }
101            std::cmp::Ordering::Greater => {
102                self.col = self.snapback_col.min(line_len.saturating_sub(1))
103            }
104            // if both expand_col and col are the same we dont have to do nothing
105            std::cmp::Ordering::Equal => {}
106        }
107    }
108}