on master help sign in
Fixing Multiple Panics (#121)
c17dcb8Kirawi
helix-core/src/movement.rs+4−1
@@ -45,7 +45,10 @@ pub fn move_vertically(
45
45
46 let new_line = match dir {
46 let new_line = match dir {
47 Direction::Backward => row.saturating_sub(count),
47 Direction::Backward => row.saturating_sub(count),
48− Direction::Forward => std::cmp::min(row.saturating_add(count), text.len_lines() - 2),
48+ Direction::Forward => std::cmp::min(
49+ row.saturating_add(count),
50+ text.len_lines().saturating_sub(2),
51+ ),
49 };
52 };
50
53
51 // convert to 0-indexed, subtract another 1 because len_chars() counts \n
54 // convert to 0-indexed, subtract another 1 because len_chars() counts \n
helix-core/src/selection.rs+1−1
@@ -383,7 +383,7 @@ pub fn split_on_matches(
383 // TODO: retain range direction
383 // TODO: retain range direction
384
384
385 let end = text.byte_to_char(start_byte + mat.start());
385 let end = text.byte_to_char(start_byte + mat.start());
386− result.push(Range::new(start, end - 1));
386+ result.push(Range::new(start, end.saturating_sub(1)));
387 start = text.byte_to_char(start_byte + mat.end());
387 start = text.byte_to_char(start_byte + mat.end());
388 }
388 }
389
389
helix-core/src/transaction.rs+19−1
@@ -90,7 +90,8 @@ impl ChangeSet {
90 return;
90 return;
91 }
91 }
92
92
93+ // Avoiding std::str::len() to account for UTF-8 characters.
93− self.len_after += fragment.len();
94+ self.len_after += fragment.chars().count();
94
95
95 let new_last = match self.changes.as_mut_slice() {
96 let new_last = match self.changes.as_mut_slice() {
96 [.., Insert(prev)] | [.., Insert(prev), Delete(_)] => {
97 [.., Insert(prev)] | [.., Insert(prev), Delete(_)] => {
@@ -754,4 +755,21 @@ mod test {
754 use Operation::*;
755 use Operation::*;
755 assert_eq!(changes.changes, &[Insert("a".into())]);
756 assert_eq!(changes.changes, &[Insert("a".into())]);
756 }
757 }
758+
759+ #[test]
760+ fn combine_with_utf8() {
761+ const TEST_CASE: &'static str = "Hello, これはヒレクスエディターです!";
762+
763+ let empty = Rope::from("");
764+ let mut a = ChangeSet::new(&empty);
765+
766+ let mut b = ChangeSet::new(&empty);
767+ b.insert(TEST_CASE.into());
768+
769+ let changes = a.compose(b);
770+
771+ use Operation::*;
772+ assert_eq!(changes.changes, &[Insert(TEST_CASE.into())]);
773+ assert_eq!(changes.len_after, TEST_CASE.chars().count());
774+ }
757}
775}
helix-term/src/commands.rs+4−2
@@ -669,7 +669,7 @@ fn _search(doc: &mut Document, view: &mut View, contents: &str, regex: &Regex, e
669 return;
669 return;
670 }
670 }
671
671
672− let head = end - 1;
672+ let head = end;
673
673
674 let selection = if extend {
674 let selection = if extend {
675 selection.clone().push(Range::new(start, head))
675 selection.clone().push(Range::new(start, head))
@@ -749,7 +749,9 @@ pub fn select_line(cx: &mut Context) {
749
749
750 let line = text.char_to_line(pos.head);
750 let line = text.char_to_line(pos.head);
751 let start = text.line_to_char(line);
751 let start = text.line_to_char(line);
752+ let end = text
753+ .line_to_char(std::cmp::min(doc.text().len_lines(), line + count))
752− let end = text.line_to_char(line + count).saturating_sub(1);
754+ .saturating_sub(1);
753
755
754 doc.set_selection(view.id, Selection::single(start, end));
756 doc.set_selection(view.id, Selection::single(start, end));
755}
757}
helix-term/src/ui/editor.rs+1−1
@@ -341,7 +341,7 @@ impl EditorView {
341 let info: Style = theme.get("info");
341 let info: Style = theme.get("info");
342 let hint: Style = theme.get("hint");
342 let hint: Style = theme.get("hint");
343
343
344− for (i, line) in (view.first_line..last_line).enumerate() {
344+ for (i, line) in (view.first_line..=last_line).enumerate() {
345 use helix_core::diagnostic::Severity;
345 use helix_core::diagnostic::Severity;
346 if let Some(diagnostic) = doc.diagnostics.iter().find(|d| d.line == line) {
346 if let Some(diagnostic) = doc.diagnostics.iter().find(|d| d.line == line) {
347 surface.set_stringn(
347 surface.set_stringn(
helix-term/src/ui/prompt.rs+1−1
@@ -114,7 +114,7 @@ impl Prompt {
114 let selected_color = theme.get("ui.menu.selected");
114 let selected_color = theme.get("ui.menu.selected");
115 // completion
115 // completion
116
116
117− let max_col = area.width / BASE_WIDTH;
117+ let max_col = std::cmp::max(1, area.width / BASE_WIDTH);
118 let height = ((self.completion.len() as u16 + max_col - 1) / max_col);
118 let height = ((self.completion.len() as u16 + max_col - 1) / max_col);
119 let completion_area = Rect::new(
119 let completion_area = Rect::new(
120 area.x,
120 area.x,
helix-view/src/view.rs+1−1
@@ -106,7 +106,7 @@ impl View {
106 /// Calculates the last visible line on screen
106 /// Calculates the last visible line on screen
107 #[inline]
107 #[inline]
108 pub fn last_line(&self, doc: &Document) -> usize {
108 pub fn last_line(&self, doc: &Document) -> usize {
109− let height = self.area.height.saturating_sub(1); // - 1 for statusline
109+ let height = self.area.height.saturating_sub(2); // - 2 for statusline
110 std::cmp::min(
110 std::cmp::min(
111 self.first_line + height as usize,
111 self.first_line + height as usize,
112 doc.text().len_lines() - 1,
112 doc.text().len_lines() - 1,