diff --git a/reqtui/src/text_object/text_object.rs b/reqtui/src/text_object/text_object.rs index 0c5b993..83e3d36 100644 --- a/reqtui/src/text_object/text_object.rs +++ b/reqtui/src/text_object/text_object.rs @@ -1,4 +1,4 @@ -use std::ops::Add; +use std::ops::{Add, Sub}; use crate::text_object::cursor::Cursor; use ropey::Rope; @@ -90,6 +90,85 @@ impl TextObject { line_len } + pub fn erase_until_eol(&mut self, cursor: &Cursor) { + let line = self.content.line_to_char(cursor.row()); + let next_line = self.content.line_to_char(cursor.row().add(1)); + let col_offset = line + cursor.col(); + self.content + .try_remove(col_offset.saturating_sub(1)..next_line.saturating_sub(1)) + .ok(); + } + + pub fn find_char_after_whitespace(&self, cursor: &Cursor) -> (usize, usize) { + let line = self.content.line_to_char(cursor.row()); + let col_offset = line + cursor.col(); + let mut walked = 0; + let mut found = false; + + for char in self.content.chars_at(col_offset) { + match (char, found) { + (c, false) if c.is_whitespace() => { + found = true; + walked = walked.add(1); + } + (c, true) if !c.is_whitespace() => break, + _ => walked = walked.add(1), + } + } + let curr_idx = col_offset.add(walked); + let curr_row = self.content.char_to_line(col_offset.add(walked)); + let curr_row_start = self.content.line_to_char(curr_row); + let curr_col = curr_idx.sub(curr_row_start); + (curr_col, curr_row) + } + + pub fn find_char_before_whitespace(&self, cursor: &Cursor) -> (usize, usize) { + let line = self.content.line_to_char(cursor.row()); + let col_offset = line + cursor.col(); + let mut found = false; + let mut index = col_offset.saturating_sub(1); + + for _ in (0..col_offset.saturating_sub(1)).rev() { + let char = self.content.char(index); + match (char, found) { + (c, false) if c.is_whitespace() => found = true, + (c, true) if !c.is_whitespace() => break, + _ => {} + } + index = index.saturating_sub(1); + } + + 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) + } + + pub fn find_char_after_separator(&self, cursor: &Cursor) -> (usize, usize) { + let line = self.content.line_to_char(cursor.row()); + let col_offset = line + cursor.col(); + let mut walked = 0; + let mut found = false; + + for char in self.content.chars_at(col_offset) { + match (char, found) { + (c, false) if !c.is_alphanumeric() => { + found = true; + walked = walked.add(1); + } + (c, true) if c.is_alphanumeric() => break, + _ => walked = walked.add(1), + } + } + + let curr_idx = col_offset.add(walked); + let curr_row = self.content.char_to_line(col_offset.add(walked)); + let curr_row_start = self.content.line_to_char(curr_row); + let curr_col = curr_idx.sub(curr_row_start); + (curr_col, curr_row) + } + pub fn len_lines(&self) -> usize { self.content.len_lines() } @@ -100,3 +179,7 @@ impl std::fmt::Display for TextObject { f.write_str(&self.content.to_string()) } } + +fn is_separator(c: char) -> bool { + c.is_whitespace() || matches!(c, '.' | '/' | '\'' | '"') +} diff --git a/tui/src/components/api_explorer/req_editor.rs b/tui/src/components/api_explorer/req_editor.rs index e6d613c..df381ec 100644 --- a/tui/src/components/api_explorer/req_editor.rs +++ b/tui/src/components/api_explorer/req_editor.rs @@ -389,6 +389,28 @@ impl Eventful for ReqEditor<'_> { let len_lines = self.body.len_lines(); self.cursor.move_to_row(len_lines.saturating_sub(1)); } + (EditorMode::Normal, KeyCode::Char('D'), KeyModifiers::SHIFT) => { + self.body.erase_until_eol(&self.cursor); + } + (EditorMode::Normal, KeyCode::Char('B'), KeyModifiers::SHIFT) => { + let (col, row) = self.body.find_char_before_whitespace(&self.cursor); + self.cursor.move_to_row(row); + self.cursor.move_to_col(col); + } + (EditorMode::Normal, KeyCode::Char('w'), KeyModifiers::NONE) => { + let (col, row) = self.body.find_char_after_separator(&self.cursor); + self.cursor.move_to_row(row); + self.cursor.move_to_col(col); + let current_line_len = self.body.line_len(self.cursor.row()); + self.cursor.maybe_snap_to_col(current_line_len); + } + (EditorMode::Normal, KeyCode::Char('W'), KeyModifiers::SHIFT) => { + let (col, row) = self.body.find_char_after_whitespace(&self.cursor); + self.cursor.move_to_row(row); + self.cursor.move_to_col(col); + let current_line_len = self.body.line_len(self.cursor.row()); + self.cursor.maybe_snap_to_col(current_line_len); + } (EditorMode::Normal, KeyCode::Char('i'), KeyModifiers::NONE) => { self.editor_mode = EditorMode::Insert; }