From ab42788071c16050649f03d435bacc290b8810c5 Mon Sep 17 00:00:00 2001 From: Dmitry Batrak <Dmitry.Batrak@jetbrains.com> Date: Fri, 11 Jul 2014 13:57:39 +0400 Subject: [PATCH] IDEA-125021 Improve multi-caret copy-paste logic --- .../editorActions/CopyHandler.java | 7 +- .../editorActions/TextBlockTransferable.java | 2 +- .../TextBlockTransferableData.java | 2 +- .../editor/CaretStateTransferableData.java | 56 +++++ .../editor/ClipboardTextPerCaretSplitter.java | 18 +- .../openapi/editor/CopyPasteSupport.java | 212 ++++++++++++++++++ .../editor/EditorModificationUtil.java | 155 +------------ .../editor/impl/SelectionModelImpl.java | 11 +- .../openapi/editor/EditorMultiCaretTest.java | 32 +++ 9 files changed, 333 insertions(+), 162 deletions(-) rename platform/{lang-impl => platform-api}/src/com/intellij/codeInsight/editorActions/TextBlockTransferable.java (98%) rename platform/{lang-impl => platform-api}/src/com/intellij/codeInsight/editorActions/TextBlockTransferableData.java (95%) create mode 100644 platform/platform-api/src/com/intellij/openapi/editor/CaretStateTransferableData.java create mode 100644 platform/platform-api/src/com/intellij/openapi/editor/CopyPasteSupport.java diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CopyHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CopyHandler.java index a68a1fdeee5a..2a46c08fc2dd 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CopyHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CopyHandler.java @@ -37,8 +37,6 @@ import java.util.ArrayList; import java.util.List; public class CopyHandler extends EditorActionHandler { - private static final Logger LOG = Logger.getInstance(CopyHandler.class); - private final EditorActionHandler myOriginalAction; public CopyHandler(final EditorActionHandler originalHandler) { @@ -93,7 +91,10 @@ public class CopyHandler extends EditorActionHandler { transferableDatas.addAll(processor.collectTransferableData(file, editor, startOffsets, endOffsets)); } - String rawText = TextBlockTransferable.convertLineSeparators(selectionModel.getSelectedText(true), "\n", transferableDatas); + String text = editor.getCaretModel().supportsMultipleCarets() + ? CopyPasteSupport.getSelectedTextForClipboard(editor, transferableDatas) + : selectionModel.getSelectedText(); + String rawText = TextBlockTransferable.convertLineSeparators(text, "\n", transferableDatas); String escapedText = null; for (CopyPastePreProcessor processor : Extensions.getExtensions(CopyPastePreProcessor.EP_NAME)) { escapedText = processor.preprocessOnCopy(file, startOffsets, endOffsets, rawText); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/TextBlockTransferable.java b/platform/platform-api/src/com/intellij/codeInsight/editorActions/TextBlockTransferable.java similarity index 98% rename from platform/lang-impl/src/com/intellij/codeInsight/editorActions/TextBlockTransferable.java rename to platform/platform-api/src/com/intellij/codeInsight/editorActions/TextBlockTransferable.java index 075f7618eddd..7d972816769c 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/TextBlockTransferable.java +++ b/platform/platform-api/src/com/intellij/codeInsight/editorActions/TextBlockTransferable.java @@ -30,7 +30,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; -class TextBlockTransferable implements Transferable { +public class TextBlockTransferable implements Transferable { private final Collection<TextBlockTransferableData> myExtraData; private final RawText myRawText; private final String myText; diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/TextBlockTransferableData.java b/platform/platform-api/src/com/intellij/codeInsight/editorActions/TextBlockTransferableData.java similarity index 95% rename from platform/lang-impl/src/com/intellij/codeInsight/editorActions/TextBlockTransferableData.java rename to platform/platform-api/src/com/intellij/codeInsight/editorActions/TextBlockTransferableData.java index c15a50e3019a..bdaf6f2ea546 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/TextBlockTransferableData.java +++ b/platform/platform-api/src/com/intellij/codeInsight/editorActions/TextBlockTransferableData.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * 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. diff --git a/platform/platform-api/src/com/intellij/openapi/editor/CaretStateTransferableData.java b/platform/platform-api/src/com/intellij/openapi/editor/CaretStateTransferableData.java new file mode 100644 index 000000000000..f0d2085cbb6b --- /dev/null +++ b/platform/platform-api/src/com/intellij/openapi/editor/CaretStateTransferableData.java @@ -0,0 +1,56 @@ +/* + * 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.openapi.editor; + +import com.intellij.codeInsight.editorActions.TextBlockTransferableData; + +import java.awt.datatransfer.DataFlavor; + +public class CaretStateTransferableData implements TextBlockTransferableData { + public static final DataFlavor FLAVOR = new DataFlavor(CaretStateTransferableData.class, "Caret state"); + + public final int[] startOffsets; + public final int[] endOffsets; + + public CaretStateTransferableData(int[] startOffsets, int[] endOffsets) { + this.startOffsets = startOffsets; + this.endOffsets = endOffsets; + } + + @Override + public DataFlavor getFlavor() { + return FLAVOR; + } + + @Override + public int getOffsetCount() { + return startOffsets.length + endOffsets.length; + } + + @Override + public int getOffsets(int[] offsets, int index) { + System.arraycopy(startOffsets, 0, offsets, index, startOffsets.length); + System.arraycopy(endOffsets, 0, offsets, index + startOffsets.length, endOffsets.length); + return index + getOffsetCount(); + } + + @Override + public int setOffsets(int[] offsets, int index) { + System.arraycopy(offsets, index, startOffsets, 0, startOffsets.length); + System.arraycopy(offsets, index + startOffsets.length, endOffsets, 0, endOffsets.length); + return index + getOffsetCount(); + } +} diff --git a/platform/platform-api/src/com/intellij/openapi/editor/ClipboardTextPerCaretSplitter.java b/platform/platform-api/src/com/intellij/openapi/editor/ClipboardTextPerCaretSplitter.java index afc58b818bce..a3e62412f4a4 100644 --- a/platform/platform-api/src/com/intellij/openapi/editor/ClipboardTextPerCaretSplitter.java +++ b/platform/platform-api/src/com/intellij/openapi/editor/ClipboardTextPerCaretSplitter.java @@ -15,12 +15,16 @@ */ package com.intellij.openapi.editor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + import java.util.ArrayList; import java.util.Collections; import java.util.List; public class ClipboardTextPerCaretSplitter { - public List<String> split(String input, int caretCount) { + @NotNull + public List<String> split(@NotNull String input, @Nullable CaretStateTransferableData caretData, int caretCount) { if (caretCount <= 0) { throw new IllegalArgumentException("Caret count must be positive"); } @@ -28,9 +32,17 @@ public class ClipboardTextPerCaretSplitter { return Collections.singletonList(input); } List<String> result = new ArrayList<String>(caretCount); - String[] lines = input.split("\n", -1); + int sourceCaretCount = caretData == null ? -1 : caretData.startOffsets.length; + String[] lines = sourceCaretCount == 1 || sourceCaretCount == caretCount ? null : input.split("\n", -1); for (int i = 0; i < caretCount; i++) { - if (lines.length == 0) { + if (sourceCaretCount == 1) { + result.add(input); + } + else if (sourceCaretCount == caretCount) { + //noinspection ConstantConditions + result.add(new String(input.substring(caretData.startOffsets[i], caretData.endOffsets[i]))); + } + else if (lines.length == 0) { result.add(""); } else if (lines.length == 1) { diff --git a/platform/platform-api/src/com/intellij/openapi/editor/CopyPasteSupport.java b/platform/platform-api/src/com/intellij/openapi/editor/CopyPasteSupport.java new file mode 100644 index 000000000000..7095080aa13d --- /dev/null +++ b/platform/platform-api/src/com/intellij/openapi/editor/CopyPasteSupport.java @@ -0,0 +1,212 @@ +/* + * 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.openapi.editor; + +import com.intellij.codeInsight.editorActions.TextBlockTransferable; +import com.intellij.codeInsight.editorActions.TextBlockTransferableData; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.ide.CopyPasteManager; +import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.text.LineTokenizer; +import com.intellij.util.Producer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.StringSelection; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +public class CopyPasteSupport { + private static final Logger LOG = Logger.getInstance(CopyPasteSupport.class); + + private CopyPasteSupport() { } + + public static void copySelectionToClipboard(@NotNull Editor editor) { + ApplicationManager.getApplication().assertIsDispatchThread(); + List<TextBlockTransferableData> extraData = new ArrayList<TextBlockTransferableData>(); + String s = editor.getCaretModel().supportsMultipleCarets() ? getSelectedTextForClipboard(editor, extraData) + : editor.getSelectionModel().getSelectedText(); + if (s == null) return; + + s = TextBlockTransferable.convertLineSeparators(s, "\n", extraData); + Transferable contents = editor.getCaretModel().supportsMultipleCarets() ? new TextBlockTransferable(s, extraData, null) : new StringSelection(s); + CopyPasteManager.getInstance().setContents(contents); + } + + public static String getSelectedTextForClipboard(@NotNull Editor editor, @NotNull Collection<TextBlockTransferableData> extraDataCollector) { + final StringBuilder buf = new StringBuilder(); + String separator = ""; + List<Caret> carets = editor.getCaretModel().getAllCarets(); + int[] startOffsets = new int[carets.size()]; + int[] endOffsets = new int[carets.size()]; + for (int i = 0; i < carets.size(); i++) { + buf.append(separator); + String caretSelectedText = carets.get(i).getSelectedText(); + startOffsets[i] = buf.length(); + if (caretSelectedText != null) { + buf.append(caretSelectedText); + } + endOffsets[i] = buf.length(); + separator = "\n"; + } + extraDataCollector.add(new CaretStateTransferableData(startOffsets, endOffsets)); + return buf.toString(); + } + + + public static TextRange pasteFromClipboard(Editor editor) { + return pasteTransferable(editor, (Producer<Transferable>)null); + } + + public static TextRange pasteTransferable(Editor editor, final Transferable content) { + return pasteTransferable(editor, new Producer<Transferable>() { + @Nullable + @Override + public Transferable produce() { + return content; + } + }); + } + + @Nullable + public static TextRange pasteTransferable(final Editor editor, @Nullable Producer<Transferable> producer) { + Transferable content = getTransferable(producer); + if (content == null) return null; + String text = getStringContent(content); + if (text == null) return null; + + if (editor.getCaretModel().supportsMultipleCarets()) { + int caretCount = editor.getCaretModel().getCaretCount(); + if (caretCount == 1 && editor.isColumnMode()) { + int pastedLineCount = LineTokenizer.calcLineCount(text, true); + EditorModificationUtil.deleteSelectedText(editor); + Caret caret = editor.getCaretModel().getPrimaryCaret(); + for (int i = 0; i < pastedLineCount - 1; i++) { + caret = caret.clone(false); + if (caret == null) { + break; + } + } + caretCount = editor.getCaretModel().getCaretCount(); + } + CaretStateTransferableData caretData = null; + try { + caretData = content.isDataFlavorSupported(CaretStateTransferableData.FLAVOR) + ? (CaretStateTransferableData)content.getTransferData(CaretStateTransferableData.FLAVOR) : null; + } + catch (Exception e) { + LOG.error(e); + } + final Iterator<String> segments = new ClipboardTextPerCaretSplitter().split(text, caretData, caretCount).iterator(); + editor.getCaretModel().runForEachCaret(new CaretAction() { + @Override + public void perform(Caret caret) { + EditorModificationUtil.insertStringAtCaret(editor, segments.next(), false, true); + } + }); + return null; + } + else { + int caretOffset = editor.getCaretModel().getOffset(); + EditorModificationUtil.insertStringAtCaret(editor, text, false, true); + return new TextRange(caretOffset, caretOffset + text.length()); + } + } + + public static void pasteTransferableAsBlock(Editor editor, @Nullable Producer<Transferable> producer) { + Transferable content = getTransferable(producer); + if (content == null) return; + String text = getStringContent(content); + if (text == null) return; + + int caretLine = editor.getCaretModel().getLogicalPosition().line; + int originalCaretLine = caretLine; + int selectedLinesCount = 0; + + final SelectionModel selectionModel = editor.getSelectionModel(); + if (selectionModel.hasBlockSelection()) { + final LogicalPosition start = selectionModel.getBlockStart(); + final LogicalPosition end = selectionModel.getBlockEnd(); + assert start != null; + assert end != null; + LogicalPosition caret = new LogicalPosition(Math.min(start.line, end.line), Math.min(start.column, end.column)); + selectedLinesCount = Math.abs(end.line - start.line); + caretLine = caret.line; + + EditorModificationUtil.deleteSelectedText(editor); + editor.getCaretModel().moveToLogicalPosition(caret); + } + + LogicalPosition caretToRestore = editor.getCaretModel().getLogicalPosition(); + + String[] lines = LineTokenizer.tokenize(text.toCharArray(), false); + if (lines.length > 1 || selectedLinesCount == 0) { + int longestLineLength = 0; + for (int i = 0; i < lines.length; i++) { + String line = lines[i]; + longestLineLength = Math.max(longestLineLength, line.length()); + editor.getCaretModel().moveToLogicalPosition(new LogicalPosition(caretLine + i, caretToRestore.column)); + EditorModificationUtil.insertStringAtCaret(editor, line, false, true); + } + caretToRestore = new LogicalPosition(originalCaretLine, caretToRestore.column + longestLineLength); + } + else { + for (int i = 0; i <= selectedLinesCount; i++) { + editor.getCaretModel().moveToLogicalPosition(new LogicalPosition(caretLine + i, caretToRestore.column)); + EditorModificationUtil.insertStringAtCaret(editor, text, false, true); + } + caretToRestore = new LogicalPosition(originalCaretLine, caretToRestore.column + text.length()); + } + + editor.getCaretModel().moveToLogicalPosition(caretToRestore); + EditorModificationUtil.zeroWidthBlockSelectionAtCaretColumn(editor, caretLine, caretLine + selectedLinesCount); + } + + @Nullable + private static String getStringContent(@NotNull Transferable content) { + RawText raw = RawText.fromTransferable(content); + if (raw != null) return raw.rawText; + + try { + return (String)content.getTransferData(DataFlavor.stringFlavor); + } + catch (UnsupportedFlavorException ignore) { } + catch (IOException ignore) { } + + return null; + } + + private static Transferable getTransferable(Producer<Transferable> producer) { + Transferable content = null; + if (producer != null) { + content = producer.produce(); + } + else { + CopyPasteManager manager = CopyPasteManager.getInstance(); + if (manager.areDataFlavorsAvailable(DataFlavor.stringFlavor)) { + content = manager.getContents(); + } + } + return content; + } +} diff --git a/platform/platform-api/src/com/intellij/openapi/editor/EditorModificationUtil.java b/platform/platform-api/src/com/intellij/openapi/editor/EditorModificationUtil.java index 3fddbc344585..ee5527967440 100644 --- a/platform/platform-api/src/com/intellij/openapi/editor/EditorModificationUtil.java +++ b/platform/platform-api/src/com/intellij/openapi/editor/EditorModificationUtil.java @@ -19,20 +19,14 @@ import com.intellij.codeStyle.CodeStyleFacade; import com.intellij.openapi.editor.actionSystem.EditorActionManager; import com.intellij.openapi.editor.event.DocumentEvent; import com.intellij.openapi.editor.event.MockDocumentEvent; -import com.intellij.openapi.ide.CopyPasteManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.TextRange; -import com.intellij.openapi.util.text.LineTokenizer; import com.intellij.psi.PsiDocumentManager; import com.intellij.util.Producer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; -import java.awt.datatransfer.UnsupportedFlavorException; -import java.io.IOException; -import java.util.Iterator; import java.util.List; public class EditorModificationUtil { @@ -99,7 +93,7 @@ public class EditorModificationUtil { zeroWidthBlockSelectionAtCaretColumn(editor, startLine, endLine); } - private static void zeroWidthBlockSelectionAtCaretColumn(final Editor editor, final int startLine, final int endLine) { + public static void zeroWidthBlockSelectionAtCaretColumn(final Editor editor, final int startLine, final int endLine) { int caretColumn = editor.getCaretModel().getLogicalPosition().column; editor.getSelectionModel().setBlockSelection(new LogicalPosition(startLine, caretColumn), new LogicalPosition(endLine, caretColumn)); } @@ -181,112 +175,21 @@ public class EditorModificationUtil { return offset; } + /** + * @deprecated Use {@link com.intellij.openapi.editor.CopyPasteSupport#pasteTransferable(Editor, com.intellij.util.Producer)} instead. + * (to remove in IDEA 15) + */ @Nullable public static TextRange pasteTransferable(final Editor editor, @Nullable Producer<Transferable> producer) { - String text = getStringContent(producer); - if (text == null) return null; - - if (editor.getCaretModel().supportsMultipleCarets()) { - int caretCount = editor.getCaretModel().getCaretCount(); - if (caretCount == 1 && editor.isColumnMode()) { - int pastedLineCount = LineTokenizer.calcLineCount(text, true); - deleteSelectedText(editor); - Caret caret = editor.getCaretModel().getPrimaryCaret(); - for (int i = 0; i < pastedLineCount - 1; i++) { - caret = caret.clone(false); - if (caret == null) { - break; - } - } - caretCount = editor.getCaretModel().getCaretCount(); - } - final Iterator<String> segments = new ClipboardTextPerCaretSplitter().split(text, caretCount).iterator(); - editor.getCaretModel().runForEachCaret(new CaretAction() { - @Override - public void perform(Caret caret) { - insertStringAtCaret(editor, segments.next(), false, true); - } - }); - return null; - } - else { - int caretOffset = editor.getCaretModel().getOffset(); - insertStringAtCaret(editor, text, false, true); - return new TextRange(caretOffset, caretOffset + text.length()); - } + return CopyPasteSupport.pasteTransferable(editor, producer); } + /** + * @deprecated Use {@link com.intellij.openapi.editor.CopyPasteSupport#pasteTransferableAsBlock(Editor, com.intellij.util.Producer)} instead. + * (to remove in IDEA 15) + */ public static void pasteTransferableAsBlock(Editor editor, @Nullable Producer<Transferable> producer) { - String text = getStringContent(producer); - if (text == null) return; - - int caretLine = editor.getCaretModel().getLogicalPosition().line; - int originalCaretLine = caretLine; - int selectedLinesCount = 0; - - final SelectionModel selectionModel = editor.getSelectionModel(); - if (selectionModel.hasBlockSelection()) { - final LogicalPosition start = selectionModel.getBlockStart(); - final LogicalPosition end = selectionModel.getBlockEnd(); - assert start != null; - assert end != null; - LogicalPosition caret = new LogicalPosition(Math.min(start.line, end.line), Math.min(start.column, end.column)); - selectedLinesCount = Math.abs(end.line - start.line); - caretLine = caret.line; - - deleteSelectedText(editor); - editor.getCaretModel().moveToLogicalPosition(caret); - } - - LogicalPosition caretToRestore = editor.getCaretModel().getLogicalPosition(); - - String[] lines = LineTokenizer.tokenize(text.toCharArray(), false); - if (lines.length > 1 || selectedLinesCount == 0) { - int longestLineLength = 0; - for (int i = 0; i < lines.length; i++) { - String line = lines[i]; - longestLineLength = Math.max(longestLineLength, line.length()); - editor.getCaretModel().moveToLogicalPosition(new LogicalPosition(caretLine + i, caretToRestore.column)); - insertStringAtCaret(editor, line, false, true); - } - caretToRestore = new LogicalPosition(originalCaretLine, caretToRestore.column + longestLineLength); - } - else { - for (int i = 0; i <= selectedLinesCount; i++) { - editor.getCaretModel().moveToLogicalPosition(new LogicalPosition(caretLine + i, caretToRestore.column)); - insertStringAtCaret(editor, text, false, true); - } - caretToRestore = new LogicalPosition(originalCaretLine, caretToRestore.column + text.length()); - } - - editor.getCaretModel().moveToLogicalPosition(caretToRestore); - zeroWidthBlockSelectionAtCaretColumn(editor, caretLine, caretLine + selectedLinesCount); - } - - @Nullable - private static String getStringContent(@Nullable Producer<Transferable> producer) { - Transferable content = null; - if (producer != null) { - content = producer.produce(); - } - else { - CopyPasteManager manager = CopyPasteManager.getInstance(); - if (manager.areDataFlavorsAvailable(DataFlavor.stringFlavor)) { - content = manager.getContents(); - } - } - if (content == null) return null; - - RawText raw = RawText.fromTransferable(content); - if (raw != null) return raw.rawText; - - try { - return (String)content.getTransferData(DataFlavor.stringFlavor); - } - catch (UnsupportedFlavorException ignore) { } - catch (IOException ignore) { } - - return null; + CopyPasteSupport.pasteTransferableAsBlock(editor, producer); } /** @@ -494,40 +397,4 @@ public class EditorModificationUtil { CaretModel caretModel = editor.getCaretModel(); caretModel.moveToOffset(caretModel.getOffset() + caretShift); } - - /** @deprecated use {@link #pasteTransferable(Editor, Producer)} (to remove in IDEA 14) */ - @SuppressWarnings("UnusedDeclaration") - public static TextRange pasteFromClipboard(Editor editor) { - return pasteTransferable(editor, null); - } - - /** @deprecated use {@link #pasteTransferable(Editor, Producer)} (to remove in IDEA 14) */ - @SuppressWarnings("SpellCheckingInspection,UnusedDeclaration") - public static TextRange pasteFromTransferrable(final Transferable content, Editor editor) { - return pasteTransferable(editor, new Producer<Transferable>() { - @Nullable - @Override - public Transferable produce() { - return content; - } - }); - } - - @SuppressWarnings("UnusedDeclaration") - /** @deprecated use {@link #pasteTransferableAsBlock(Editor, Producer)} (to remove in IDEA 14) */ - public static void pasteFromClipboardAsBlock(Editor editor) { - pasteTransferableAsBlock(editor, (Producer<Transferable>)null); - } - - @SuppressWarnings("UnusedDeclaration") - /** @deprecated use {@link #pasteTransferableAsBlock(Editor, Producer)} (to remove in IDEA 14) */ - public static void pasteTransferableAsBlock(Editor editor, @Nullable final Transferable content) { - pasteTransferableAsBlock(editor, new Producer<Transferable>() { - @Nullable - @Override - public Transferable produce() { - return content; - } - }); - } } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/SelectionModelImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/SelectionModelImpl.java index 263ea77c286f..2f5a81153579 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/SelectionModelImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/SelectionModelImpl.java @@ -36,16 +36,13 @@ import com.intellij.openapi.editor.ex.DocumentEx; import com.intellij.openapi.editor.ex.PrioritizedDocumentListener; import com.intellij.openapi.editor.ex.util.EditorUtil; import com.intellij.openapi.editor.markup.TextAttributes; -import com.intellij.openapi.ide.CopyPasteManager; import com.intellij.openapi.util.Pair; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.containers.ContainerUtil; import gnu.trove.TIntArrayList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.awt.datatransfer.StringSelection; import java.util.Collection; import java.util.Iterator; import java.util.LinkedList; @@ -570,13 +567,7 @@ public class SelectionModelImpl implements SelectionModel, PrioritizedDocumentLi @Override public void copySelectionToClipboard() { - validateContext(true); - String s = getSelectedText(true); - if (s == null) return; - - s = StringUtil.convertLineSeparators(s); - StringSelection contents = new StringSelection(s); - CopyPasteManager.getInstance().setContents(contents); + CopyPasteSupport.copySelectionToClipboard(myEditor); } @Override diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/EditorMultiCaretTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/EditorMultiCaretTest.java index 26be81d2f341..fdaf7c6ed5b0 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/editor/EditorMultiCaretTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/EditorMultiCaretTest.java @@ -245,6 +245,38 @@ public class EditorMultiCaretTest extends AbstractEditorTest { "seven<caret>"); } + public void testCopyMultilineFromOneCaretPasteIntoTwo() throws Exception { + init("<selection>one\n" + + "two<caret></selection>\n" + + "three\n" + + "four", + TestFileType.TEXT); + executeAction("EditorCopy"); + executeAction("EditorTextStart"); + executeAction("EditorCloneCaretBelow"); + executeAction("EditorPaste"); + checkResultByText("one\n" + + "two<caret>one\n" + + "one\n" + + "two<caret>two\n" + + "three\n" + + "four"); + } + + public void testCopyPasteDoesNothingWithUnevenSelection() throws Exception { + init("<selection>one\n" + + "two<caret></selection>\n" + + "<selection>three<caret></selection>\n" + + "four", + TestFileType.TEXT); + executeAction("EditorCopy"); + executeAction("EditorPaste"); + checkResultByText("one\n" + + "two<caret>\n" + + "three<caret>\n" + + "four"); + } + public void testEscapeAfterDragDown() throws Exception { init("line1\n" + "line2", -- GitLab