From 1e6fe0000141d61077208156c9b38ab4a1f0ab06 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Mon, 7 Oct 2024 11:20:33 -0400 Subject: [PATCH] Trim all trailing whitespace on insert_newline --- helix-term/src/commands.rs | 40 ++++++++++-------- helix-term/tests/test/commands.rs | 1 + helix-term/tests/test/commands/insert.rs | 53 ++++++++++++++++++++++++ helix-term/tests/test/languages/yaml.rs | 2 +- 4 files changed, 78 insertions(+), 18 deletions(-) create mode 100644 helix-term/tests/test/commands/insert.rs diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 4633299e..d0814836 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -3961,10 +3961,7 @@ pub mod insert { let curr = contents.get_char(pos).unwrap_or(' '); let current_line = text.char_to_line(pos); - let line_is_only_whitespace = text - .line(current_line) - .chars() - .all(|char| char.is_ascii_whitespace()); + let line_start = text.line_to_char(current_line); let mut new_text = String::new(); @@ -3973,15 +3970,10 @@ pub mod insert { .and_then(|config| config.comment_tokens.as_ref()) .and_then(|tokens| comment::get_comment_token(text, tokens, current_line)); - // If the current line is all whitespace, insert a line ending at the beginning of - // the current line. This makes the current line empty and the new line contain the - // indentation of the old line. - let (from, to, local_offs) = if line_is_only_whitespace { - let line_start = text.line_to_char(current_line); - new_text.push_str(doc.line_ending.as_str()); - - (line_start, line_start, new_text.chars().count()) - } else { + let (from, to, local_offs) = if let Some(idx) = + text.slice(line_start..pos).last_non_whitespace_char() + { + let first_trailing_whitespace_char = (line_start + idx + 1).min(pos); let line = text.line(current_line); let indent = match line.first_non_whitespace_char() { @@ -4034,20 +4026,34 @@ pub mod insert { new_text.chars().count() }; - (pos, pos, local_offs) + ( + first_trailing_whitespace_char, + pos, + // Note that `first_trailing_whitespace_char` is at least `pos` so the + // unsigned subtraction (`pos - first_trailing_whitespace_char`) cannot + // underflow. + local_offs as isize - (pos - first_trailing_whitespace_char) as isize, + ) + } else { + // If the current line is all whitespace, insert a line ending at the beginning of + // the current line. This makes the current line empty and the new line contain the + // indentation of the old line. + new_text.push_str(doc.line_ending.as_str()); + + (line_start, line_start, new_text.chars().count() as isize) }; let new_range = if range.cursor(text) > range.anchor { // when appending, extend the range by local_offs Range::new( range.anchor + global_offs, - range.head + local_offs + global_offs, + (range.head as isize + local_offs) as usize + global_offs, ) } else { // when inserting, slide the range by local_offs Range::new( - range.anchor + local_offs + global_offs, - range.head + local_offs + global_offs, + (range.anchor as isize + local_offs) as usize + global_offs, + (range.head as isize + local_offs) as usize + global_offs, ) }; diff --git a/helix-term/tests/test/commands.rs b/helix-term/tests/test/commands.rs index f71ae308..32badaa4 100644 --- a/helix-term/tests/test/commands.rs +++ b/helix-term/tests/test/commands.rs @@ -2,6 +2,7 @@ use helix_term::application::Application; use super::*; +mod insert; mod movement; mod write; diff --git a/helix-term/tests/test/commands/insert.rs b/helix-term/tests/test/commands/insert.rs new file mode 100644 index 00000000..5450cc4c --- /dev/null +++ b/helix-term/tests/test/commands/insert.rs @@ -0,0 +1,53 @@ +use super::*; + +#[tokio::test(flavor = "multi_thread")] +async fn insert_newline_trim_trailing_whitespace() -> anyhow::Result<()> { + // Trailing whitespace is trimmed. + test(( + indoc! {"\ + hello·······#[| + ]#world + "} + .replace('·', " "), + "i", + indoc! {"\ + hello + #[| + ]#world + "} + .replace('·', " "), + )) + .await?; + + // Whitespace that would become trailing is trimmed too. + test(( + indoc! {"\ + hello········#[|w]#orld + "} + .replace('·', " "), + "i", + indoc! {"\ + hello + #[|w]#orld + "} + .replace('·', " "), + )) + .await?; + + // Only whitespace before the cursor is trimmed. + test(( + indoc! {"\ + hello········#[|·]#····world + "} + .replace('·', " "), + "i", + indoc! {"\ + hello + #[|·]#····world + "} + .replace('·', " "), + )) + .await?; + + Ok(()) +} diff --git a/helix-term/tests/test/languages/yaml.rs b/helix-term/tests/test/languages/yaml.rs index 10e1861d..1d959640 100644 --- a/helix-term/tests/test/languages/yaml.rs +++ b/helix-term/tests/test/languages/yaml.rs @@ -795,7 +795,7 @@ async fn auto_indent() -> anyhow::Result<()> { "##}, "i", indoc! {"\ - foo: + foo: #[|b]#ar "}, ),