Skip to content

Commit 099cbb5

Browse files
authored
fix: keep Tab-as-spaces indentation on blank lines (LangCfg) (#951)
1 parent fb75cf5 commit 099cbb5

File tree

2 files changed

+75
-0
lines changed

2 files changed

+75
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/**
2+
* Copyright (c) 2025 Vegard IT GmbH and others.
3+
*
4+
* This program and the accompanying materials are made
5+
* available under the terms of the Eclipse Public License 2.0
6+
* which is available at https://www.eclipse.org/legal/epl-2.0/
7+
*
8+
* SPDX-License-Identifier: EPL-2.0
9+
*
10+
* Contributors:
11+
* - Sebastian Thomschke (Vegard IT) - initial implementation
12+
*/
13+
package org.eclipse.tm4e.languageconfiguration.tests;
14+
15+
import static org.assertj.core.api.Assertions.assertThat;
16+
17+
import java.io.ByteArrayInputStream;
18+
19+
import org.eclipse.core.resources.IFile;
20+
import org.eclipse.core.resources.IProject;
21+
import org.eclipse.core.resources.ResourcesPlugin;
22+
import org.eclipse.swt.custom.StyledText;
23+
import org.eclipse.swt.widgets.Control;
24+
import org.eclipse.tm4e.ui.internal.utils.UI;
25+
import org.eclipse.ui.ide.IDE;
26+
import org.eclipse.ui.texteditor.ITextEditor;
27+
import org.junit.jupiter.api.AfterEach;
28+
import org.junit.jupiter.api.Test;
29+
30+
/**
31+
* Verifies that inserting whitespace (e.g., Tab-as-spaces) on a blank line is not stripped
32+
* when indentation rules are active (issue #949).
33+
*/
34+
public class TestWhitespaceInsert {
35+
36+
@AfterEach
37+
public void tearDown() throws Exception {
38+
UI.getActivePage().closeAllEditors(false);
39+
for (final IProject p : ResourcesPlugin.getWorkspace().getRoot().getProjects()) {
40+
p.delete(true, null);
41+
}
42+
}
43+
44+
@Test
45+
public void testWhitespaceInsertOnBlankLine() throws Exception {
46+
final IProject p = ResourcesPlugin.getWorkspace().getRoot().getProject(getClass().getName() + System.currentTimeMillis());
47+
p.create(null);
48+
p.open(null);
49+
final IFile file = p.getFile("whatever.lc-test");
50+
file.create(new ByteArrayInputStream(new byte[0]), true, null);
51+
final var editor = (ITextEditor) IDE.openEditor(UI.getActivePage(), file);
52+
final var text = (StyledText) editor.getAdapter(Control.class);
53+
54+
// Insert 4 spaces on an empty line: should remain as inserted (not stripped)
55+
text.setText("");
56+
text.setSelection(0);
57+
text.insert(" ");
58+
assertThat(text.getText()).isEqualTo(" ");
59+
60+
// Insert 4 more spaces at end of a whitespace-only line: should append (not stripped)
61+
text.setSelection(text.getCharCount());
62+
text.insert(" ");
63+
assertThat(text.getText()).isEqualTo(" ");
64+
}
65+
}

org.eclipse.tm4e.languageconfiguration/src/main/java/org/eclipse/tm4e/languageconfiguration/internal/LanguageConfigurationAutoEditStrategy.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,16 @@ && isFollowedBy(doc, command.offset, charPair.close))) {
142142
final var isTargetLineBlank = TextUtils.isBlankLine(doc, lineIndex);
143143

144144
if (isPastedTextMultiLine || isTargetLineBlank) {
145+
146+
// Do not auto-reindent single-line whitespace-only inserts (e.g., Tab as spaces on a blank line)
147+
// See: https://github.com/eclipse-tm4e/tm4e/issues/949
148+
final boolean isWhitespaceOnlySingleLineInsert = !isPastedTextMultiLine
149+
&& command.text.chars().allMatch(Character::isWhitespace);
150+
if (isWhitespaceOnlySingleLineInsert) {
151+
// Keep user-inserted spaces as-is; skip indentation adjustment
152+
continue;
153+
}
154+
145155
final var newIndent = registry.getGoodIndentForLine(doc, lineIndex, contentType, IIndentConverter.of(cursorCfg));
146156
if (newIndent != null) {
147157
final var lineStartOffset = doc.getLineOffset(lineIndex);

0 commit comments

Comments
 (0)