From f0ed98335c2230176c5694c574cac0c86c8ff91a Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Mon, 23 Jun 2014 16:21:11 +0400 Subject: [PATCH] make smart backspace work when virtual space is enabled in editor --- .../IndentingBackspaceHandler.java | 26 +++- .../caretAheadOfText2-after.java | 2 +- .../caretAheadOfText3-after.java | 2 +- .../caretAheadOfText4-after.java | 2 +- .../indentingBackspace/emptyLines-after.java | 3 + .../editor/indentingBackspace/emptyLines.java | 4 + ...ntingBackspaceHandlerVirtualSpaceTest.java | 118 ++++++++++++++++++ 7 files changed, 148 insertions(+), 9 deletions(-) create mode 100644 platform/lang-impl/testData/editor/indentingBackspace/emptyLines-after.java create mode 100644 platform/lang-impl/testData/editor/indentingBackspace/emptyLines.java create mode 100644 platform/lang-impl/testSources/com/intellij/codeInsight/editorActions/IndentingBackspaceHandlerVirtualSpaceTest.java diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/IndentingBackspaceHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/IndentingBackspaceHandler.java index f10c13a7740f..a4f34c49a6bb 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/IndentingBackspaceHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/IndentingBackspaceHandler.java @@ -23,6 +23,7 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.LogicalPosition; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; import com.intellij.psi.codeStyle.LanguageCodeStyleSettingsProvider; @@ -35,13 +36,16 @@ import org.jetbrains.annotations.NotNull; public class IndentingBackspaceHandler extends BackspaceHandlerDelegate { private static final Logger LOG = Logger.getInstance(IndentingBackspaceHandler.class); + private boolean caretWasAtLineStart; + @Override public void beforeCharDeleted(char c, PsiFile file, Editor editor) { + caretWasAtLineStart = editor.getCaretModel().getLogicalPosition().column == 0; } @Override public boolean charDeleted(char c, PsiFile file, Editor editor) { - if (!CodeInsightSettings.getInstance().INDENTING_BACKSPACE || " \n\t".indexOf(c) == -1) { + if (!CodeInsightSettings.getInstance().INDENTING_BACKSPACE || !StringUtil.isWhiteSpace(c)) { return false; } LanguageCodeStyleSettingsProvider codeStyleSettingsProvider = LanguageCodeStyleSettingsProvider.forLanguage(file.getLanguage()); @@ -51,12 +55,13 @@ public class IndentingBackspaceHandler extends BackspaceHandlerDelegate { Document document = editor.getDocument(); - int offset = CharArrayUtil.shiftForward(document.getCharsSequence(), editor.getCaretModel().getOffset(), " \t"); + int caretOffset = editor.getCaretModel().getOffset(); + int offset = CharArrayUtil.shiftForward(document.getCharsSequence(), caretOffset, " \t"); int beforeWhitespaceOffset = CharArrayUtil.shiftBackward(document.getCharsSequence(), offset - 1, " \t") + 1; - LogicalPosition logicalPosition = editor.offsetToLogicalPosition(offset); + LogicalPosition logicalPosition = caretOffset < offset ? editor.offsetToLogicalPosition(offset) : editor.getCaretModel().getLogicalPosition(); int lineStartOffset = document.getLineStartOffset(logicalPosition.line); if (lineStartOffset < beforeWhitespaceOffset) { - if (c == '\n' && beforeWhitespaceOffset < offset) { + if (caretWasAtLineStart && beforeWhitespaceOffset < offset) { document.deleteString(beforeWhitespaceOffset, offset); return true; } @@ -75,11 +80,18 @@ public class IndentingBackspaceHandler extends BackspaceHandlerDelegate { int targetColumn = getWidth(indent, tabSize); if (logicalPosition.column == targetColumn) { - return false; + if (caretOffset < offset) { + editor.getCaretModel().moveToLogicalPosition(logicalPosition); + return true; + } + else { + return false; + } } - if (c == '\n' || logicalPosition.column > targetColumn) { + if (caretWasAtLineStart || logicalPosition.column > targetColumn) { smartReplace(document, lineStartOffset, offset, indent); + editor.getCaretModel().moveToLogicalPosition(new LogicalPosition(logicalPosition.line, targetColumn)); return true; } @@ -93,9 +105,11 @@ public class IndentingBackspaceHandler extends BackspaceHandlerDelegate { if (prevLineStartOffset < targetOffset) { document.deleteString(targetOffset, offset); + editor.getCaretModel().moveToOffset(targetOffset); } else { smartReplace(document, prevLineStartOffset, offset, indent); + editor.getCaretModel().moveToLogicalPosition(new LogicalPosition(logicalPosition.line - 1, targetColumn)); } return true; } diff --git a/platform/lang-impl/testData/editor/indentingBackspace/caretAheadOfText2-after.java b/platform/lang-impl/testData/editor/indentingBackspace/caretAheadOfText2-after.java index e8c58612a4db..7180cd368c25 100644 --- a/platform/lang-impl/testData/editor/indentingBackspace/caretAheadOfText2-after.java +++ b/platform/lang-impl/testData/editor/indentingBackspace/caretAheadOfText2-after.java @@ -1,3 +1,3 @@ class Foo { - int field; + int field; } \ No newline at end of file diff --git a/platform/lang-impl/testData/editor/indentingBackspace/caretAheadOfText3-after.java b/platform/lang-impl/testData/editor/indentingBackspace/caretAheadOfText3-after.java index 6aa58a6ac8b1..7180cd368c25 100644 --- a/platform/lang-impl/testData/editor/indentingBackspace/caretAheadOfText3-after.java +++ b/platform/lang-impl/testData/editor/indentingBackspace/caretAheadOfText3-after.java @@ -1,3 +1,3 @@ class Foo { - int field; + int field; } \ No newline at end of file diff --git a/platform/lang-impl/testData/editor/indentingBackspace/caretAheadOfText4-after.java b/platform/lang-impl/testData/editor/indentingBackspace/caretAheadOfText4-after.java index b77c65948e6f..7180cd368c25 100644 --- a/platform/lang-impl/testData/editor/indentingBackspace/caretAheadOfText4-after.java +++ b/platform/lang-impl/testData/editor/indentingBackspace/caretAheadOfText4-after.java @@ -1,3 +1,3 @@ class Foo { - int field; + int field; } \ No newline at end of file diff --git a/platform/lang-impl/testData/editor/indentingBackspace/emptyLines-after.java b/platform/lang-impl/testData/editor/indentingBackspace/emptyLines-after.java new file mode 100644 index 000000000000..ba5cbf5dcd98 --- /dev/null +++ b/platform/lang-impl/testData/editor/indentingBackspace/emptyLines-after.java @@ -0,0 +1,3 @@ +class Foo { + +} \ No newline at end of file diff --git a/platform/lang-impl/testData/editor/indentingBackspace/emptyLines.java b/platform/lang-impl/testData/editor/indentingBackspace/emptyLines.java new file mode 100644 index 000000000000..04ecf9dceadb --- /dev/null +++ b/platform/lang-impl/testData/editor/indentingBackspace/emptyLines.java @@ -0,0 +1,4 @@ +class Foo { + + +} \ No newline at end of file diff --git a/platform/lang-impl/testSources/com/intellij/codeInsight/editorActions/IndentingBackspaceHandlerVirtualSpaceTest.java b/platform/lang-impl/testSources/com/intellij/codeInsight/editorActions/IndentingBackspaceHandlerVirtualSpaceTest.java new file mode 100644 index 000000000000..78cf05abe4cb --- /dev/null +++ b/platform/lang-impl/testSources/com/intellij/codeInsight/editorActions/IndentingBackspaceHandlerVirtualSpaceTest.java @@ -0,0 +1,118 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.codeInsight.editorActions; + +import com.intellij.openapi.editor.LogicalPosition; +import com.intellij.testFramework.LightPlatformCodeInsightTestCase; + +import java.io.IOException; + +public class IndentingBackspaceHandlerVirtualSpaceTest extends LightPlatformCodeInsightTestCase { + public void testAfterLargeIndent() throws IOException { + doTest("class Foo {\n" + + " \n" + + "}", + new LogicalPosition(1, 10), + "class Foo {\n" + + " \n" + + "}", + new LogicalPosition(1, 4)); + } + + public void testAfterProperIndent() throws IOException { + doTest("class Foo {\n" + + " \n" + + "}", + new LogicalPosition(1, 10), + "class Foo {\n" + + " \n" + + "}", + new LogicalPosition(1, 4)); + } + + public void testAfterSmallIndent() throws IOException { + doTest("class Foo {\n" + + " \n" + + "}", + new LogicalPosition(1, 10), + "class Foo {\n" + + " \n" + + "}", + new LogicalPosition(1, 4)); + } + + public void testAfterEmptyIndent() throws IOException { + doTest("class Foo {\n" + + "\n" + + "}", + new LogicalPosition(1, 10), + "class Foo {\n" + + " \n" + + "}", + new LogicalPosition(1, 4)); + } + + public void testAtIndent() throws IOException { + doTest("class Foo {\n" + + " \n" + + "}", + new LogicalPosition(1, 4), + "class Foo {\n" + + "}", + new LogicalPosition(0, 11)); + } + + public void testAtIndentOnEmptyLine() throws IOException { + doTest("class Foo {\n" + + "\n" + + "}", + new LogicalPosition(1, 4), + "class Foo {\n" + + "}", + new LogicalPosition(0, 11)); + } + + public void testBeforeIndent() throws IOException { + doTest("class Foo {\n" + + " \n" + + "}", + new LogicalPosition(1, 3), + "class Foo {\n" + + "}", + new LogicalPosition(0, 11)); + } + + public void testDeleteLine() throws IOException { + doTest("class Foo {\n" + + "\n" + + "\n" + + "}", + new LogicalPosition(2, 0), + "class Foo {\n" + + " \n" + + "}", + new LogicalPosition(1, 4)); + } + + private void doTest(String textBefore, LogicalPosition caretBefore, String textAfter, LogicalPosition caretAfter) throws IOException { + configureFromFileText(getTestName(false) + ".java", textBefore); + myEditor.getSettings().setVirtualSpace(true); + myEditor.getCaretModel().moveToLogicalPosition(caretBefore); + backspace(); + checkResultByText(textAfter); + assertEquals(caretAfter, myEditor.getCaretModel().getLogicalPosition()); + } +}