From b82a9e867efd164dba148a4d0d7d161e1cfa51fc Mon Sep 17 00:00:00 2001 From: wiru Date: Sat, 11 May 2024 04:39:39 -0300 Subject: [PATCH] feat: page up/page down and delete forward/backward --- reqtui/src/text_object/text_object.rs | 74 +++++++++++++++++++ tui/src/components/api_explorer/req_editor.rs | 35 ++++++++- 2 files changed, 105 insertions(+), 4 deletions(-) diff --git a/reqtui/src/text_object/text_object.rs b/reqtui/src/text_object/text_object.rs index fab8afe..0916436 100644 --- a/reqtui/src/text_object/text_object.rs +++ b/reqtui/src/text_object/text_object.rs @@ -221,6 +221,80 @@ impl TextObject { let end = self.content.line_to_char(line.add(1)); self.content.try_remove(start..end).ok(); } + + /// deletes a word forward in one of two ways: + /// + /// - if the current character is alphanumeric, then this delete up to the first non + /// alphanumeric character + /// - if the current character is non alphanumeric, then delete up to the first alphanumeric + /// character + pub fn delete_word(&mut self, cursor: &Cursor) { + let start_idx = self.content.line_to_char(cursor.row()).add(cursor.col()); + let mut end_idx = start_idx.saturating_sub(1); + + if let Some(initial_char) = self.content.get_char(start_idx) { + for char in self.content.chars_at(start_idx) { + match (initial_char.is_alphanumeric(), char.is_alphanumeric()) { + (false, _) if self.line_break.to_string().contains(char) => break, + (false, true) => { + end_idx = end_idx.add(1); + break; + } + (true, false) => { + end_idx = end_idx.add(1); + break; + } + _ => end_idx = end_idx.add(1), + } + } + + self.content.try_remove(start_idx..end_idx).ok(); + } + } + + /// deletes a word backwards in one of two ways: + /// + /// - if the current character is alphanumeric, then this delete up to the first non + /// alphanumeric character + /// - if the current character is non alphanumeric, then delete up to the first alphanumeric + /// character + /// + /// will always return how many columns to advance the cursor + pub fn delete_word_backwards(&mut self, cursor: &Cursor) -> usize { + let start_idx = self.content.line_to_char(cursor.row()).add(cursor.col()); + let mut end_idx = start_idx.saturating_sub(1); + + if let Some(initial_char) = self.content.get_char(start_idx) { + for _ in (0..start_idx.saturating_sub(1)).rev() { + let char = self.content.char(end_idx); + match (initial_char.is_alphanumeric(), char.is_alphanumeric()) { + (false, _) if self.line_break.to_string().contains(char) => break, + (false, true) => break, + (true, false) => break, + _ => end_idx = end_idx.saturating_sub(1), + } + } + }; + + end_idx.sub(start_idx) + + // for char in self.content.chars_at(start_idx) { + // match (initial_char.is_alphanumeric(), char.is_alphanumeric()) { + // (false, _) if self.line_break.to_string().contains(char) => break, + // (false, true) => break, + // (true, false) => break, + // _ => end_idx = end_idx.add(1), + // } + // + // self.content.try_remove(start_idx..end_idx).ok(); + // + // + // let curr_row = self.content.char_to_line(index); + // let curr_row_start = self.content.line_to_char(curr_row); + // let curr_col = index - curr_row_start; + // + // (curr_col, curr_row) + } } impl std::fmt::Display for TextObject { diff --git a/tui/src/components/api_explorer/req_editor.rs b/tui/src/components/api_explorer/req_editor.rs index 53b3d25..8ab1e69 100644 --- a/tui/src/components/api_explorer/req_editor.rs +++ b/tui/src/components/api_explorer/req_editor.rs @@ -310,14 +310,14 @@ impl<'re> ReqEditor<'re> { Action::DeleteLine => self.delete_current_line(), Action::DeleteCurrAndBelow => self.delete_curr_line_and_below(), Action::DeleteCurrAndAbove => self.delete_curr_line_and_above(), + Action::DeleteWord => self.delete_word(), + Action::DeleteBack => self.delete_word_backwards(), + Action::PageDown => self.page_down(), + Action::PageUp => self.page_up(), Action::Undo => todo!(), Action::FindNext => todo!(), Action::FindPrevious => todo!(), Action::PreviousWord => todo!(), - Action::PageDown => todo!(), - Action::PageUp => todo!(), - Action::DeleteWord => todo!(), - Action::DeleteBack => todo!(), Action::InsertLineBelow => todo!(), Action::InsertLineAbove => todo!(), Action::PasteBelow => todo!(), @@ -353,6 +353,33 @@ impl<'re> ReqEditor<'re> { .then(|| self.col_scroll = self.col_scroll.saturating_sub(1)); } + fn page_up(&mut self) { + let half_height = self.layout.content_pane.height.saturating_sub(2).div(2); + self.cursor.move_up(half_height.into()); + self.maybe_scroll_view(); + let line_len = self.body.line_len(self.cursor.row()); + self.cursor.maybe_snap_to_col(line_len); + } + + fn page_down(&mut self) { + let half_height = self.layout.content_pane.height.saturating_sub(2).div(2); + let len_lines = self.body.len_lines().saturating_sub(1); + let increment = usize::min(len_lines, self.cursor.row().add(half_height as usize)); + self.cursor.move_to_row(increment); + self.maybe_scroll_view(); + let line_len = self.body.line_len(self.cursor.row()); + self.cursor.maybe_snap_to_col(line_len); + } + + fn delete_word(&mut self) { + self.body.delete_word(&self.cursor); + } + + fn delete_word_backwards(&mut self) { + let walked = self.body.delete_word_backwards(&self.cursor); + self.cursor.move_left(walked); + } + fn insert_char(&mut self, c: char) { self.body.insert_char(c, &self.cursor); self.cursor.move_right(1);