From ef221abe83862cfdfcce358bbecc14080824abdb Mon Sep 17 00:00:00 2001 From: Mike Trinkala Date: Sun, 12 Feb 2023 11:13:22 -0800 Subject: [PATCH] Prevent a panic when uncommenting a line with only a comment token (#5933) Open a new document `test.rs` and type the following: `di//` The margin calculation pushes the range out of bounds for the comment marker when there are no characters (newline) after it. thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Char range out of bounds: char range 0..3, Rope/RopeSlice char length 2', ropey-1.6.0/src/rope.rs:546:37 The debug build catches the error in the transaction: thread 'main' panicked at 'attempt to subtract with overflow', helix-core/src/transaction.rs:503:26 --- helix-core/src/comment.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/helix-core/src/comment.rs b/helix-core/src/comment.rs index 6241f7fd5..9c7e50f33 100644 --- a/helix-core/src/comment.rs +++ b/helix-core/src/comment.rs @@ -45,7 +45,7 @@ fn find_line_comment( // determine margin of 0 or 1 for uncommenting; if any comment token is not followed by a space, // a margin of 0 is used for all lines. - if matches!(line_slice.get_char(pos + token_len), Some(c) if c != ' ') { + if !matches!(line_slice.get_char(pos + token_len), Some(c) if c == ' ') { margin = 0; } @@ -108,8 +108,8 @@ mod test { let text = doc.slice(..); let res = find_line_comment("//", text, 0..3); - // (commented = true, to_change = [line 0, line 2], min = col 2, margin = 1) - assert_eq!(res, (false, vec![0, 2], 2, 1)); + // (commented = true, to_change = [line 0, line 2], min = col 2, margin = 0) + assert_eq!(res, (false, vec![0, 2], 2, 0)); // comment let transaction = toggle_line_comments(&doc, &selection, None); @@ -136,6 +136,17 @@ mod test { assert_eq!(doc, " 1\n\n 2\n 3"); assert!(selection.len() == 1); // to ignore the selection unused warning + // 0 margin comments, with no space + doc = Rope::from("//"); + // reset the selection. + selection = Selection::single(0, doc.len_chars() - 1); + + let transaction = toggle_line_comments(&doc, &selection, None); + transaction.apply(&mut doc); + selection = selection.map(transaction.changes()); + assert_eq!(doc, ""); + assert!(selection.len() == 1); // to ignore the selection unused warning + // TODO: account for uncommenting with uneven comment indentation } }