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 115450dc..e119d914 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); 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 1cf4ca5f..6aaa795b 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,36 @@ && 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); + // 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; + } + command.text = normalizedIndent + firstLine.replaceFirst("^[ \\t]+", "") + reindentedRest; + } + } else { + // Single-line paste: straightforward indent replacement + 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; } }