From 5dc6f5d2e2662f35afeeac64dbadfc0ab721021b Mon Sep 17 00:00:00 2001 From: joeljohansson99 Date: Mon, 23 Mar 2026 11:49:49 +0100 Subject: [PATCH 1/4] Fix incorrect multiline autoindent --- ...LanguageConfigurationAutoEditStrategy.java | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/LanguageConfigurationAutoEditStrategy.java b/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/LanguageConfigurationAutoEditStrategy.java index 1cf4ca5fb..2efc861b3 100644 --- a/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/LanguageConfigurationAutoEditStrategy.java +++ b/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/LanguageConfigurationAutoEditStrategy.java @@ -163,17 +163,30 @@ && isFollowedBy(doc, command.offset, charPair.close))) { final var newIndent = registry.getGoodIndentForLine(doc, lineIndex, contentType, IIndentConverter.of(cursorCfg)); if (newIndent != null) { + final var normalizedIndent = cursorCfg.normalizeIndentation(newIndent); final var lineStartOffset = doc.getLineOffset(lineIndex); - - // check if the content was pasted into a line while the cursor was not at the beginning of the line - // but inside or at the end of an existing line indentation final var offsetInLine = command.offset - lineStartOffset; - if (offsetInLine > 0 && doc.get(lineStartOffset, offsetInLine).isBlank()) { - command.offset = lineStartOffset; - command.length += offsetInLine; + final int firstNewline = command.text.indexOf('\n'); + + if (firstNewline >= 0) { + final var firstLine = command.text.substring(0, firstNewline + 1); + final var reindentedRest = TextUtils.replaceIndent( + command.text.substring(firstNewline + 1), cursorCfg.indentSize, normalizedIndent, false); + + if (offsetInLine > 0 && !doc.get(lineStartOffset, offsetInLine).isBlank()) { + command.text = firstLine + reindentedRest; + } else { + if (offsetInLine > 0) { + command.offset = lineStartOffset; + command.length += offsetInLine; + } + command.text = normalizedIndent + firstLine.stripLeading() + reindentedRest; + } + } else { + command.text = TextUtils + .replaceIndent(command.text, cursorCfg.indentSize, normalizedIndent, false) + .toString(); } - command.text = TextUtils.replaceIndent(command.text, cursorCfg.indentSize, - cursorCfg.normalizeIndentation(newIndent), false).toString(); command.shiftsCaret = true; } } From c06444dcad5c0f6f693c908539e0247f65027d77 Mon Sep 17 00:00:00 2001 From: karljohansson Date: Thu, 26 Mar 2026 08:37:43 +0100 Subject: [PATCH 2/4] Add inline comments --- .../internal/LanguageConfigurationAutoEditStrategy.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/LanguageConfigurationAutoEditStrategy.java b/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/LanguageConfigurationAutoEditStrategy.java index 2efc861b3..b8112ad1c 100644 --- a/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/LanguageConfigurationAutoEditStrategy.java +++ b/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/LanguageConfigurationAutoEditStrategy.java @@ -170,12 +170,17 @@ && isFollowedBy(doc, command.offset, charPair.close))) { if (firstNewline >= 0) { final var firstLine = command.text.substring(0, firstNewline + 1); + // Re-indent lines after the first line final var reindentedRest = TextUtils.replaceIndent( command.text.substring(firstNewline + 1), cursorCfg.indentSize, normalizedIndent, false); if (offsetInLine > 0 && !doc.get(lineStartOffset, offsetInLine).isBlank()) { + // Content was pasted midline after non-whitespace + // First pasted line continues existing content, don't replace indentation command.text = firstLine + reindentedRest; } else { + // Content was pasted at the start of the line, or preceded only by whitespace + // Replace any existing leading whitespace with the correct indent if (offsetInLine > 0) { command.offset = lineStartOffset; command.length += offsetInLine; @@ -183,6 +188,7 @@ && isFollowedBy(doc, command.offset, charPair.close))) { command.text = normalizedIndent + firstLine.stripLeading() + reindentedRest; } } else { + // Single-line paste: straightforward indent replacement command.text = TextUtils .replaceIndent(command.text, cursorCfg.indentSize, normalizedIndent, false) .toString(); From ca9fa380ed53c3140287fded7338d66178d47258 Mon Sep 17 00:00:00 2001 From: karljohansson Date: Thu, 26 Mar 2026 08:40:54 +0100 Subject: [PATCH 3/4] Change method of removing leading whitespaces String.stripLeading() includes newlines --- .../internal/LanguageConfigurationAutoEditStrategy.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/LanguageConfigurationAutoEditStrategy.java b/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/LanguageConfigurationAutoEditStrategy.java index b8112ad1c..6aaa795b5 100644 --- a/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/LanguageConfigurationAutoEditStrategy.java +++ b/org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/LanguageConfigurationAutoEditStrategy.java @@ -185,7 +185,7 @@ && isFollowedBy(doc, command.offset, charPair.close))) { command.offset = lineStartOffset; command.length += offsetInLine; } - command.text = normalizedIndent + firstLine.stripLeading() + reindentedRest; + command.text = normalizedIndent + firstLine.replaceFirst("^[ \\t]+", "") + reindentedRest; } } else { // Single-line paste: straightforward indent replacement From 899e6023cf25177811fd8109f02eae361907b5bc Mon Sep 17 00:00:00 2001 From: karljohansson Date: Thu, 26 Mar 2026 13:50:19 +0100 Subject: [PATCH 4/4] Add tests --- .../tests/TestIndentationRules.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/org.eclipse.tm4e.languageconfiguration.tests/src/main/java/org/eclipse/tm4e/languageconfiguration/tests/TestIndentationRules.java b/org.eclipse.tm4e.languageconfiguration.tests/src/main/java/org/eclipse/tm4e/languageconfiguration/tests/TestIndentationRules.java index 115450dc0..e119d9142 100644 --- a/org.eclipse.tm4e.languageconfiguration.tests/src/main/java/org/eclipse/tm4e/languageconfiguration/tests/TestIndentationRules.java +++ b/org.eclipse.tm4e.languageconfiguration.tests/src/main/java/org/eclipse/tm4e/languageconfiguration/tests/TestIndentationRules.java @@ -58,6 +58,18 @@ public void testIndentAdjustmentOnPaste() throws Exception { text.insert("function bar() {\n}"); assertThat(text.getText()).isEqualTo("public class Foo {\n\tfunction bar() {\n\t}\n}"); + // insert a code snippet with unindented first line and expect the snippet to be correctly indented + text.setText("public class Foo {\n\n}"); + text.setSelection(19); + text.insert("function bar() {\n\t\t\n\t}"); + assertThat(text.getText()).isEqualTo("public class Foo {\n\tfunction bar() {\n\t\t\n\t}\n}"); + + // insert an else code snippet with unindented first line after the if code snippet and expect the snippet to be correctly indented + text.setText("public class Foo {\n\tfunction foo() {\n\t\tif (cond) {\n\t\t} \n\t}\n}"); + text.setSelection(55); + text.insert("else {\n\t\t}"); + assertThat(text.getText()).isEqualTo("public class Foo {\n\tfunction foo() {\n\t\tif (cond) {\n\t\t} else {\n\t\t}\n\t}\n}"); + // insert single line text and ensure the text is only indented in blank lines text.setText("public class Foo {\n\n}"); text.setSelection(19);