diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/actions/CutLineEndAction.java b/platform/platform-impl/src/com/intellij/openapi/editor/actions/CutLineEndAction.java index a0c1d135b6b1..1908f897b244 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/actions/CutLineEndAction.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/actions/CutLineEndAction.java @@ -24,14 +24,13 @@ */ package com.intellij.openapi.editor.actions; -import com.intellij.openapi.ide.KillRingTransferable; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.actionSystem.EditorAction; import com.intellij.openapi.editor.actionSystem.EditorWriteActionHandler; -import com.intellij.openapi.ide.CopyPasteManager; -import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.text.CharArrayUtil; +import org.jetbrains.annotations.NotNull; public class CutLineEndAction extends EditorAction { public CutLineEndAction() { @@ -47,37 +46,35 @@ public class CutLineEndAction extends EditorAction { public void executeWriteAction(Editor editor, DataContext dataContext) { final Document doc = editor.getDocument(); - if (doc.getLineCount() == 0) return; int caretOffset = editor.getCaretModel().getOffset(); + if (caretOffset >= doc.getTextLength()) { + return; + } final int lineNumber = doc.getLineNumber(caretOffset); int lineEndOffset = doc.getLineEndOffset(lineNumber); + int start; + int end; if (caretOffset >= lineEndOffset) { - if (myCopyToClipboard) { - copyToClipboard(doc, lineEndOffset, lineEndOffset + 1); - } - doc.deleteString(lineEndOffset, lineEndOffset + 1); - return; - } - - if (myCopyToClipboard) { - copyToClipboard(doc, caretOffset, lineEndOffset); - } - - final int lineStartOffset = doc.getLineStartOffset(lineNumber); - if (StringUtil.isEmptyOrSpaces(doc.getCharsSequence().subSequence(lineStartOffset, lineEndOffset).toString())) { - DeleteLineAction.deleteLineAtCaret(editor); + start = lineEndOffset; + end = lineEndOffset + 1; } else { - doc.deleteString(caretOffset, lineEndOffset); + start = caretOffset; + end = lineEndOffset; + if (lineEndOffset < doc.getTextLength() && CharArrayUtil.isEmptyOrSpaces(doc.getCharsSequence(), caretOffset, lineEndOffset)) { + end++; + } } + + delete(doc, start, end); } - private static void copyToClipboard(final Document doc, int startOffset, int endOffset) { - String s = doc.getCharsSequence().subSequence(startOffset, endOffset).toString(); - - s = StringUtil.convertLineSeparators(s); - CopyPasteManager.getInstance().setContents(new KillRingTransferable(s, doc, startOffset, startOffset, true)); + private void delete(@NotNull Document document, int start, int end) { + if (myCopyToClipboard) { + EditorActionUtil.copyToKillRing(document, start, end, true); + } + document.deleteString(start, end); } } } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/actions/EditorActionUtil.java b/platform/platform-impl/src/com/intellij/openapi/editor/actions/EditorActionUtil.java index a3f1a005670d..e263f23ec3ae 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/actions/EditorActionUtil.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/actions/EditorActionUtil.java @@ -34,10 +34,13 @@ import com.intellij.openapi.editor.event.EditorMouseEvent; import com.intellij.openapi.editor.event.EditorMouseEventArea; import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.editor.ex.util.EditorUtil; +import com.intellij.openapi.ide.CopyPasteManager; +import com.intellij.openapi.ide.KillRingTransferable; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.EditorPopupHandler; +import org.jetbrains.annotations.NotNull; import java.awt.*; import java.awt.event.MouseEvent; @@ -645,6 +648,21 @@ public class EditorActionUtil { setupSelection(editor, isWithSelection, selectionStart, blockSelectionStart); } + /** + * Copies target region from the given offset to the kill ring, i.e. combines it with the previously + * copied/cut adjacent text if necessary and puts to the clipboard. + * + * @param document target document + * @param startOffset start offset of the target region within the given document + * @param endOffset end offset of the target region within the given document + * @param cut flag that identifies if target text region will be cut from the given document + */ + public static void copyToKillRing(@NotNull final Document document, int startOffset, int endOffset, boolean cut) { + String s = document.getCharsSequence().subSequence(startOffset, endOffset).toString(); + s = StringUtil.convertLineSeparators(s); + CopyPasteManager.getInstance().setContents(new KillRingTransferable(s, document, startOffset, endOffset, cut)); + } + public static EditorPopupHandler createEditorPopupHandler(final String groupId) { return new EditorPopupHandler() { public void invokePopup(final EditorMouseEvent event) { diff --git a/platform/platform-impl/testSrc/com/intellij/openapi/editor/actions/CutLineEndActionsTest.java b/platform/platform-impl/testSrc/com/intellij/openapi/editor/actions/CutLineEndActionsTest.java new file mode 100644 index 000000000000..45d232865576 --- /dev/null +++ b/platform/platform-impl/testSrc/com/intellij/openapi/editor/actions/CutLineEndActionsTest.java @@ -0,0 +1,85 @@ +/* + * Copyright 2000-2011 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.openapi.editor.actions; + +import com.intellij.testFramework.LightPlatformCodeInsightTestCase; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; + +/** + * @author Denis Zhdanov + * @since 4/18/11 2:47 PM + */ +public class CutLineEndActionsTest extends LightPlatformCodeInsightTestCase { + + public void testNonEmptyLineEnd() throws IOException { + doTest( + "class Test {\n" + + " // This is a comment string\n" + + "}", + "class Test {\n" + + " // This is a \n" + + "}" + ); + } + + public void testEmptyLineEnd() throws IOException { + doTest( + "class Test {\n" + + " \n" + + " // some comment\n" + + "}", + "class Test {\n" + + " // some comment\n" + + "}" + ); + } + + public void testAtLineEnd() throws IOException { + doTest( + "class Test {\n" + + " // This is a comment string1\n" + + " // This is a comment string2\n" + + "}", + "class Test {\n" + + " // This is a comment string1 // This is a comment string2\n" + + "}" + ); + } + + public void testAtDocumentEnd() throws IOException { + String text = + "class Test{\n" + + "}"; + doTest(text, text); + } + + public void testEmptyLastLineEnd() throws IOException { + doTest( + "class Test {\n" + + "} ", + "class Test {\n" + + "}" + ); + } + + private void doTest(@NotNull String before, @NotNull String after) throws IOException { + configureFromFileText(getTestName(false) + ".java", before); + cutToLineEnd(); + checkResultByText(after); + } +} diff --git a/platform/testFramework/src/com/intellij/testFramework/LightPlatformCodeInsightTestCase.java b/platform/testFramework/src/com/intellij/testFramework/LightPlatformCodeInsightTestCase.java index 5ce206cad3d7..c490d4662e68 100644 --- a/platform/testFramework/src/com/intellij/testFramework/LightPlatformCodeInsightTestCase.java +++ b/platform/testFramework/src/com/intellij/testFramework/LightPlatformCodeInsightTestCase.java @@ -500,6 +500,10 @@ public abstract class LightPlatformCodeInsightTestCase extends LightPlatformTest doAction("EditorNextWordWithSelection"); } + protected static void cutToLineEnd() { + doAction("EditorCutLineEnd"); + } + protected static void lineComment() { new CommentByLineCommentHandler().invoke(getProject(), getEditor(), getFile()); } diff --git a/platform/util/src/com/intellij/util/text/CharArrayUtil.java b/platform/util/src/com/intellij/util/text/CharArrayUtil.java index 79bc1c4c5e92..08780b12f831 100644 --- a/platform/util/src/com/intellij/util/text/CharArrayUtil.java +++ b/platform/util/src/com/intellij/util/text/CharArrayUtil.java @@ -16,6 +16,7 @@ package com.intellij.util.text; import com.intellij.openapi.util.TextRange; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.ByteArrayOutputStream; @@ -523,4 +524,22 @@ public class CharArrayUtil { } return false; } + + /** + * Allows to answer if target region of the given text contains only white space symbols (tabulations, white spaces and line feeds). + * + * @param text text to check + * @param start start offset within the given text to check (inclusive) + * @param end end offset within the given text to check (exclusive) + * @return true if target region of the given text contains white space symbols only; false otherwise + */ + public static boolean isEmptyOrSpaces(@NotNull CharSequence text, int start, int end) { + for (int i = start; i < end; i++) { + char c = text.charAt(i); + if (c != ' ' && c != '\t' && c != '\n') { + return false; + } + } + return true; + } }