Unnamed repository; edit this file 'description' to name the repository.
fix: alignment when indenting with spaces (#13498) (#13824)
Adjust the number of spaces inserted, so that indentation is aligned on columns.
Sylvain Terrien 4 months ago
parent 329188d · commit bc1cd7d
-rw-r--r--helix-term/src/commands.rs32
-rw-r--r--helix-term/tests/test/commands/insert.rs56
-rw-r--r--helix-term/tests/test/commands/movement.rs2
3 files changed, 82 insertions, 8 deletions
diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs
index 7abb5463..6a4b737e 100644
--- a/helix-term/src/commands.rs
+++ b/helix-term/src/commands.rs
@@ -4268,14 +4268,23 @@ pub mod insert {
fn insert_tab_impl(cx: &mut Context, count: usize) {
let (view, doc) = current!(cx.editor);
- // TODO: round out to nearest indentation level (for example a line with 3 spaces should
- // indent by one to reach 4 spaces).
- let indent = Tendril::from(doc.indent_style.as_str().repeat(count));
- let transaction = Transaction::insert(
+ let transaction = Transaction::change(
doc.text(),
- &doc.selection(view.id).clone().cursors(doc.text().slice(..)),
- indent,
+ doc.selection(view.id).ranges().iter().map(|range| {
+ let cursor = range.cursor(doc.text().slice(..));
+ let indent = if let IndentStyle::Spaces(indent_width) = doc.indent_style {
+ let line = range.cursor_line(doc.text().slice(..));
+ let line_start = doc.text().line_to_char(line);
+ let offset = (cursor - line_start) % indent_width as usize;
+
+ Tendril::from(doc.indent_style.as_str().repeat(count)).split_off(offset)
+ } else {
+ Tendril::from(doc.indent_style.as_str().repeat(count))
+ };
+
+ (cursor, cursor, Some(indent))
+ }),
);
doc.apply(&transaction, view.id);
}
@@ -5006,7 +5015,16 @@ fn indent(cx: &mut Context) {
return None;
}
let pos = doc.text().line_to_char(line);
- Some((pos, pos, Some(indent.clone())))
+
+ let indent = if let IndentStyle::Spaces(indent_width) = doc.indent_style {
+ let line = doc.text().line(line);
+ let offset = line.first_non_whitespace_char().unwrap_or(0) % indent_width as usize;
+ indent.clone().split_off(offset)
+ } else {
+ indent.clone()
+ };
+
+ Some((pos, pos, Some(indent)))
}),
);
doc.apply(&transaction, view.id);
diff --git a/helix-term/tests/test/commands/insert.rs b/helix-term/tests/test/commands/insert.rs
index 9499868e..7f00826b 100644
--- a/helix-term/tests/test/commands/insert.rs
+++ b/helix-term/tests/test/commands/insert.rs
@@ -583,3 +583,59 @@ async fn test_jump_undo_redo() -> anyhow::Result<()> {
.await?;
Ok(())
}
+
+#[tokio::test(flavor = "multi_thread")]
+async fn test_indent_with_spaces() -> anyhow::Result<()> {
+ let tests = vec![
+ // at start of line
+ (
+ indoc! {"\
+ SELECT *
+ #[|FROM table]#
+ #(|WHERE condition)#
+ "},
+ "i<tab>",
+ indoc! {"\
+ SELECT *
+ #[|FROM table]#
+ #(|WHERE condition)#
+ "},
+ ),
+ // in the middle of line
+ (
+ indoc! {"\
+ SELECT #[*|]#
+ FROM #(table|)#
+ WHERE #(condition|)#
+ "},
+ "i<S-tab>",
+ indoc! {"\
+ SELECT #[|*]#
+ FROM #(|table)#
+ WHERE #(|condition)#
+ "},
+ ),
+ // indentation in normal mode
+ (
+ indoc! {"\
+ -- comment
+ #[|SELECT *
+ FROM table
+ WHERE condition]#
+ "},
+ "<gt>",
+ indoc! {"\
+ -- comment
+ #[|SELECT *
+ FROM table
+ WHERE condition]#
+ "},
+ ),
+ ];
+
+ for test in tests {
+ test_with_config(AppBuilder::new().with_file("foo.rs", None), test).await?;
+ }
+
+ Ok(())
+}
diff --git a/helix-term/tests/test/commands/movement.rs b/helix-term/tests/test/commands/movement.rs
index 5868fa49..c7e71ae9 100644
--- a/helix-term/tests/test/commands/movement.rs
+++ b/helix-term/tests/test/commands/movement.rs
@@ -437,7 +437,7 @@ async fn test_smart_tab_move_parent_node_end() -> anyhow::Result<()> {
let result = if true {
#[|\"yes\"\n]#
} else {
- \"no #(|\"\n)#
+ \"no #(|\"\n)#
}
}
"},