From 1c6b5581f01371a00dc7f6f6e1720ad8af61ec7a Mon Sep 17 00:00:00 2001 From: Nathan Vegdahl Date: Tue, 20 Jul 2021 11:58:56 -0700 Subject: [PATCH] Fix various bugs related to goto-end-of-line command. This also fixes a bug with `Selection::normalize()`, that could result in an out-of-bounds primary index. --- helix-core/src/selection.rs | 6 +++--- helix-term/src/commands.rs | 29 +++++++++++++++++++++++------ 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/helix-core/src/selection.rs b/helix-core/src/selection.rs index f1625f996..c08f504d3 100644 --- a/helix-core/src/selection.rs +++ b/helix-core/src/selection.rs @@ -357,14 +357,14 @@ impl Selection { let mut prev_i = 0; for i in 1..self.ranges.len() { if self.ranges[prev_i].overlaps(&self.ranges[i]) { - if i == self.primary_index { - self.primary_index = prev_i; - } self.ranges[prev_i] = self.ranges[prev_i].merge(self.ranges[i]); } else { prev_i += 1; self.ranges[prev_i] = self.ranges[i]; } + if i == self.primary_index { + self.primary_index = prev_i; + } } self.ranges.truncate(prev_i + 1); diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 61c5096d0..a155e19eb 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -396,11 +396,19 @@ fn goto_line_end(cx: &mut Context) { view.id, doc.selection(view.id).clone().transform(|range| { let text = doc.text().slice(..); - let line = text.char_to_line(range.head); - let pos = line_end_char_index(&text, line); - let pos = graphemes::nth_prev_grapheme_boundary(text, pos, 1); - let pos = range.head.max(pos).max(text.line_to_char(line)); + let head = if range.anchor < range.head { + graphemes::prev_grapheme_boundary(text, range.head) + } else { + range.head + }; + let line = text.char_to_line(head); + + let mut pos = line_end_char_index(&text, line); + if doc.mode != Mode::Select { + pos = graphemes::prev_grapheme_boundary(text, pos); + } + pos = head.max(pos).max(text.line_to_char(line)); range.put(text, pos, doc.mode == Mode::Select) }), @@ -414,9 +422,18 @@ fn goto_line_end_newline(cx: &mut Context) { view.id, doc.selection(view.id).clone().transform(|range| { let text = doc.text().slice(..); - let line = text.char_to_line(range.head); - let pos = line_end_char_index(&text, line); + let head = if range.anchor < range.head { + graphemes::prev_grapheme_boundary(text, range.head) + } else { + range.head + }; + let line = text.char_to_line(head); + + let mut pos = text.line_to_char((line + 1).min(text.len_lines())); + if doc.mode != Mode::Select { + pos = graphemes::prev_grapheme_boundary(text, pos); + } range.put(text, pos, doc.mode == Mode::Select) }), );