Unnamed repository; edit this file 'description' to name the repository.
Trim all trailing whitespace on insert_newline
Michael Davis 2024-12-05
parent 4c8175c · commit 1e6fe00
-rw-r--r--helix-term/src/commands.rs40
-rw-r--r--helix-term/tests/test/commands.rs1
-rw-r--r--helix-term/tests/test/commands/insert.rs53
-rw-r--r--helix-term/tests/test/languages/yaml.rs2
4 files changed, 78 insertions, 18 deletions
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<ret>",
+ indoc! {"\
+ hello
+ #[|
+ ]#world
+ "}
+ .replace('·', " "),
+ ))
+ .await?;
+
+ // Whitespace that would become trailing is trimmed too.
+ test((
+ indoc! {"\
+ hello········#[|w]#orld
+ "}
+ .replace('·', " "),
+ "i<ret>",
+ indoc! {"\
+ hello
+ #[|w]#orld
+ "}
+ .replace('·', " "),
+ ))
+ .await?;
+
+ // Only whitespace before the cursor is trimmed.
+ test((
+ indoc! {"\
+ hello········#[|·]#····world
+ "}
+ .replace('·', " "),
+ "i<ret>",
+ 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<ret>",
indoc! {"\
- foo:
+ foo:
#[|b]#ar
"},
),