diff --git a/helix-core/src/selection.rs b/helix-core/src/selection.rs index 14c542951..a3ea2ed42 100644 --- a/helix-core/src/selection.rs +++ b/helix-core/src/selection.rs @@ -329,11 +329,18 @@ pub struct Selection { impl Selection { // eq + #[inline] #[must_use] pub fn primary(&self) -> Range { self.ranges[self.primary_index] } + #[inline] + #[must_use] + pub fn primary_mut(&mut self) -> &mut Range { + &mut self.ranges[self.primary_index] + } + /// Ensure selection containing only the primary selection. pub fn into_single(self) -> Self { if self.ranges.len() == 1 { diff --git a/helix-term/src/ui/editor.rs b/helix-term/src/ui/editor.rs index 7a2a07ed1..a2b169ed4 100644 --- a/helix-term/src/ui/editor.rs +++ b/helix-term/src/ui/editor.rs @@ -815,25 +815,21 @@ impl Component for EditorView { let editor = &mut cx.editor; let result = editor.tree.views().find_map(|(view, _focus)| { - view.pos_at_screen_coords( - &editor.documents[view.doc], - row as usize, - column as usize, - ) - .map(|pos| (pos, view.id)) + view.pos_at_screen_coords(&editor.documents[view.doc], row, column) + .map(|pos| (pos, view.id)) }); - if let Some((pos, id)) = result { - let doc = &mut editor.documents[editor.tree.get(id).doc]; + if let Some((pos, view_id)) = result { + let doc = &mut editor.documents[editor.tree.get(view_id).doc]; if modifiers == crossterm::event::KeyModifiers::ALT { - let selection = doc.selection(id).clone(); - doc.set_selection(id, selection.push(Range::point(pos))); + let selection = doc.selection(view_id).clone(); + doc.set_selection(view_id, selection.push(Range::point(pos))); } else { - doc.set_selection(id, Selection::point(pos)); + doc.set_selection(view_id, Selection::point(pos)); } - editor.tree.focus = id; + editor.tree.focus = view_id; return EventResult::Consumed(None); } @@ -849,22 +845,15 @@ impl Component for EditorView { }) => { let (view, doc) = current!(cx.editor); - let pos = view.pos_at_screen_coords(doc, row as usize, column as usize); - - if pos == None { - return EventResult::Ignored; - } - - let selection = doc.selection(view.id).clone(); - let primary_anchor = selection.primary().anchor; - let new_selection = selection.transform(|range| -> Range { - if range.anchor == primary_anchor { - return Range::new(primary_anchor, pos.unwrap()); - } - range - }); + let pos = match view.pos_at_screen_coords(doc, row, column) { + Some(pos) => pos, + None => return EventResult::Ignored, + }; - doc.set_selection(view.id, new_selection); + let mut selection = doc.selection(view.id).clone(); + let primary = selection.primary_mut(); + *primary = Range::new(primary.anchor, pos); + doc.set_selection(view.id, selection); EventResult::Consumed(None) } Event::Mouse(_) => EventResult::Ignored, diff --git a/helix-view/src/view.rs b/helix-view/src/view.rs index d61fbe4ae..1b350172a 100644 --- a/helix-view/src/view.rs +++ b/helix-view/src/view.rs @@ -166,38 +166,26 @@ impl View { Some(Position::new(row, col)) } - /// Verifies whether a screen position is inside the view - /// Returns true when position is inside the view - pub fn verify_screen_coords(&self, row: usize, column: usize) -> bool { - // 2 for status - if row < self.area.y as usize || row > self.area.y as usize + self.area.height as usize - 2 - { - return false; - } - - // TODO: not ideal - const OFFSET: usize = 7; // 1 diagnostic + 5 linenr + 1 gutter - - if column < self.area.x as usize + OFFSET - || column > self.area.x as usize + self.area.width as usize - { - return false; - } - true - } - pub fn text_pos_at_screen_coords( &self, text: &RopeSlice, - row: usize, - column: usize, + row: u16, + column: u16, tab_width: usize, ) -> Option { - if !self.verify_screen_coords(row, column) { + // TODO: not ideal + const OFFSET: u16 = 7; // 1 diagnostic + 5 linenr + 1 gutter + + // 2 for status + if row < self.area.top() || row > self.area.bottom().saturating_sub(2) { return None; } - let line_number = row - self.area.y as usize + self.first_line; + if column < self.area.left() + OFFSET || column > self.area.right() { + return None; + } + + let line_number = (row - self.area.y) as usize + self.first_line; if line_number > text.len_lines() - 1 { return Some(text.len_chars()); @@ -207,10 +195,7 @@ impl View { let current_line = text.line(line_number); - // TODO: not ideal - const OFFSET: usize = 7; // 1 diagnostic + 5 linenr + 1 gutter - - let target = column - OFFSET - self.area.x as usize + self.first_col; + let target = (column - OFFSET - self.area.x) as usize + self.first_col; let mut selected = 0; for grapheme in RopeGraphemes::new(current_line) { @@ -231,7 +216,7 @@ impl View { /// Translates a screen position to position in the text document. /// Returns a usize typed position in bounds of the text if found in this view, None if out of view. - pub fn pos_at_screen_coords(&self, doc: &Document, row: usize, column: usize) -> Option { + pub fn pos_at_screen_coords(&self, doc: &Document, row: u16, column: u16) -> Option { self.text_pos_at_screen_coords(&doc.text().slice(..), row, column, doc.tab_width()) } // pub fn traverse(&self, text: RopeSlice, start: usize, end: usize, fun: F)