excel_cli/app/
navigation.rs1use crate::app::AppState;
2use crate::utils::find_non_empty_cell;
3use crate::utils::Direction;
4
5impl AppState<'_> {
6 pub fn move_cursor(&mut self, delta_row: isize, delta_col: isize) {
7 let new_row = (self.selected_cell.0 as isize + delta_row).max(1) as usize;
9 let new_col = (self.selected_cell.1 as isize + delta_col).max(1) as usize;
10
11 self.selected_cell = (new_row, new_col);
13
14 self.handle_scrolling();
16 }
17
18 pub fn handle_scrolling(&mut self) {
19 if self.selected_cell.0 < self.start_row {
20 self.start_row = self.selected_cell.0;
21 } else if self.selected_cell.0 >= self.start_row + self.visible_rows {
22 self.start_row = self.selected_cell.0 - self.visible_rows + 1;
23 }
24
25 self.handle_column_scrolling();
26 }
27
28 pub fn jump_to_first_row(&mut self) {
29 let current_col = self.selected_cell.1;
30 self.selected_cell = (1, current_col);
31 self.handle_scrolling();
32 self.add_notification("Jumped to first row".to_string());
33 }
34
35 pub fn jump_to_last_row(&mut self) {
36 let sheet = self.workbook.get_current_sheet();
37 let current_col = self.selected_cell.1;
38
39 let max_row = sheet.max_rows;
40
41 self.selected_cell = (max_row, current_col);
42 self.handle_scrolling();
43 self.add_notification("Jumped to last row".to_string());
44 }
45
46 pub fn jump_to_first_column(&mut self) {
47 let current_row = self.selected_cell.0;
48 self.selected_cell = (current_row, 1);
49 self.handle_scrolling();
50 self.add_notification("Jumped to first column".to_string());
51 }
52
53 pub fn jump_to_first_non_empty_column(&mut self) {
54 let sheet = self.workbook.get_current_sheet();
55 let current_row = self.selected_cell.0;
56
57 let mut first_non_empty_col = 1; if current_row < sheet.data.len() {
60 for col in 1..=sheet.max_cols {
61 if col < sheet.data[current_row].len()
62 && !sheet.data[current_row][col].value.is_empty()
63 {
64 first_non_empty_col = col;
65 break;
66 }
67 }
68 }
69
70 self.selected_cell = (current_row, first_non_empty_col);
71 self.handle_scrolling();
72 self.add_notification("Jumped to first non-empty column".to_string());
73 }
74
75 pub fn jump_to_last_column(&mut self) {
76 let sheet = self.workbook.get_current_sheet();
77 let current_row = self.selected_cell.0;
78
79 let max_col = sheet.max_cols;
80
81 self.selected_cell = (current_row, max_col);
82 self.handle_scrolling();
83 self.add_notification("Jumped to last column".to_string());
84 }
85
86 fn jump_to_non_empty_cell(&mut self, direction: Direction) {
87 let sheet = self.workbook.get_current_sheet();
88 let max_bounds = (sheet.max_rows, sheet.max_cols);
89 let current_pos = self.selected_cell;
90
91 if let Some(new_pos) = find_non_empty_cell(sheet, current_pos, direction, max_bounds) {
92 self.selected_cell = new_pos;
93 self.handle_scrolling();
94
95 let dir_name = match direction {
96 Direction::Left => "left",
97 Direction::Right => "right",
98 Direction::Up => "up",
99 Direction::Down => "down",
100 };
101
102 let sheet = self.workbook.get_current_sheet();
104
105 let (row, col) = self.selected_cell;
106 let is_cell_empty = row >= sheet.data.len()
107 || col >= sheet.data[row].len()
108 || sheet.data[row][col].value.is_empty();
109
110 let message = if is_cell_empty {
111 format!("Jumped to first non-empty cell ({dir_name})")
112 } else {
113 format!("Jumped to last non-empty cell ({dir_name})")
114 };
115
116 self.add_notification(message);
117 }
118 }
119
120 pub fn jump_to_prev_non_empty_cell_left(&mut self) {
121 self.jump_to_non_empty_cell(Direction::Left);
122 }
123
124 pub fn jump_to_prev_non_empty_cell_right(&mut self) {
125 self.jump_to_non_empty_cell(Direction::Right);
126 }
127
128 pub fn jump_to_prev_non_empty_cell_up(&mut self) {
129 self.jump_to_non_empty_cell(Direction::Up);
130 }
131
132 pub fn jump_to_prev_non_empty_cell_down(&mut self) {
133 self.jump_to_non_empty_cell(Direction::Down);
134 }
135
136 fn handle_column_scrolling(&mut self) {
137 self.ensure_column_visible(self.selected_cell.1);
138 }
139
140 pub fn ensure_column_visible(&mut self, column: usize) {
141 if column < self.start_col {
143 self.start_col = column;
144 return;
145 }
146
147 let last_visible_col = self.start_col + self.visible_cols - 1;
148
149 if column > last_visible_col {
151 self.start_col = (column - self.visible_cols + 1).max(1);
152 return;
153 }
154
155 let sheet = self.workbook.get_current_sheet();
157 let max_col = sheet.max_cols;
158
159 if column < max_col && column == last_visible_col && self.visible_cols > 1 {
161 self.start_col = (column - (self.visible_cols - 2)).max(1);
164 }
165 }
166}