IDEA-18764 Emacs-Mode: Ctrl-y only pastes the last line killed and not the entire kill buffer

1. The action removes line feed if [caret offset; line end) interval doesn't contain non-white space symbols;
2. Refactoring: common functionality is moved to utility class;
3, Test are added;
This commit is contained in:
Denis Zhdanov
2011-04-18 16:10:46 +04:00
parent c5fd9dccdb
commit 206fd11d4d
5 changed files with 147 additions and 24 deletions
@@ -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);
}
}
}
@@ -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) {
@@ -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 <caret>comment string\n" +
"}",
"class Test {\n" +
" // This is a <caret>\n" +
"}"
);
}
public void testEmptyLineEnd() throws IOException {
doTest(
"class Test {\n" +
" <caret> \n" +
" // some comment\n" +
"}",
"class Test {\n" +
" <caret> // some comment\n" +
"}"
);
}
public void testAtLineEnd() throws IOException {
doTest(
"class Test {\n" +
" // This is a comment string1<caret>\n" +
" // This is a comment string2\n" +
"}",
"class Test {\n" +
" // This is a comment string1<caret> // This is a comment string2\n" +
"}"
);
}
public void testAtDocumentEnd() throws IOException {
String text =
"class Test{\n" +
"}<caret>";
doTest(text, text);
}
public void testEmptyLastLineEnd() throws IOException {
doTest(
"class Test {\n" +
"}<caret> ",
"class Test {\n" +
"}<caret>"
);
}
private void doTest(@NotNull String before, @NotNull String after) throws IOException {
configureFromFileText(getTestName(false) + ".java", before);
cutToLineEnd();
checkResultByText(after);
}
}
@@ -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());
}
@@ -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 <code>true</code> if target region of the given text contains white space symbols only; <code>false</code> 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;
}
}