From 702a9615178bc9f06b07ef5eb6a8768d403a4431 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Fri, 4 Apr 2025 11:28:15 -0400 Subject: [PATCH] Fix `try_restore_indent` on non-LF documents On Windows for example the behavior of this function typically diverges from the usual behavior on Unix. Instead of checking that the inserted string starts with `'\n'` (untrue for for CRLF line endings) we need to check that the first grapheme cluster in the string is a line ending. (All line endings are single grapheme clusters.) --- helix-term/tests/test/commands/insert.rs | 22 ++++++++++++++++++++++ helix-view/src/editor.rs | 10 +++++++--- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/helix-term/tests/test/commands/insert.rs b/helix-term/tests/test/commands/insert.rs index a3da5fb22..d83dda84b 100644 --- a/helix-term/tests/test/commands/insert.rs +++ b/helix-term/tests/test/commands/insert.rs @@ -512,3 +512,25 @@ async fn test_open_above_with_comments() -> anyhow::Result<()> { Ok(()) } + +#[tokio::test(flavor = "multi_thread")] +async fn try_restore_indent() -> anyhow::Result<()> { + // Assert that `helix_view::editor::try_restore_indent` handles line endings correctly + // endings. + test(( + indoc! {"\ + if true #[|{]# + } + "}, + // `try_restore_indent` should remove the indentation when adding a blank line. + ":lang rusto", + indoc! {"\ + if true { + #[ + |]#} + "}, + )) + .await?; + + Ok(()) +} diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 9aa073fcf..0ecddd879 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -2262,16 +2262,20 @@ impl Editor { fn try_restore_indent(doc: &mut Document, view: &mut View) { use helix_core::{ - chars::char_is_whitespace, line_ending::line_end_char_index, Operation, Transaction, + chars::char_is_whitespace, + line_ending::{line_end_char_index, str_is_line_ending}, + unicode::segmentation::UnicodeSegmentation, + Operation, Transaction, }; fn inserted_a_new_blank_line(changes: &[Operation], pos: usize, line_end_pos: usize) -> bool { if let [Operation::Retain(move_pos), Operation::Insert(ref inserted_str), Operation::Retain(_)] = changes { + let mut graphemes = inserted_str.graphemes(true); move_pos + inserted_str.len() == pos - && inserted_str.starts_with('\n') - && inserted_str.chars().skip(1).all(char_is_whitespace) + && graphemes.next().is_some_and(str_is_line_ending) + && graphemes.all(|g| g.chars().all(char_is_whitespace)) && pos == line_end_pos // ensure no characters exists after current position } else { false