diff --git a/java/java-impl/src/com/intellij/codeInsight/editorActions/CopyPasteReferenceProcessor.java b/java/java-impl/src/com/intellij/codeInsight/editorActions/CopyPasteReferenceProcessor.java index 749eea7d42f7..353543c8d00e 100644 --- a/java/java-impl/src/com/intellij/codeInsight/editorActions/CopyPasteReferenceProcessor.java +++ b/java/java-impl/src/com/intellij/codeInsight/editorActions/CopyPasteReferenceProcessor.java @@ -20,6 +20,7 @@ import com.intellij.codeInsight.daemon.impl.CollectHighlightsUtil; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.RangeMarker; +import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.DumbService; @@ -108,7 +109,11 @@ public class CopyPasteReferenceProcessor implements CopyPastePostProcessor indented, final ReferenceTransferableData value) { if (DumbService.getInstance(project).isDumb()) { return; } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CopyPasteFoldingProcessor.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CopyPasteFoldingProcessor.java index 9828191fb0d6..515cea6ca78a 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CopyPasteFoldingProcessor.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CopyPasteFoldingProcessor.java @@ -22,6 +22,7 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.FoldRegion; import com.intellij.openapi.editor.RangeMarker; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Ref; import com.intellij.psi.PsiFile; import org.jetbrains.annotations.Nullable; @@ -79,7 +80,12 @@ public class CopyPasteFoldingProcessor implements CopyPastePostProcessor indented, + final FoldingTransferableData value) { final CodeFoldingManagerImpl foldingManager = (CodeFoldingManagerImpl)CodeFoldingManager.getInstance(project); foldingManager.updateFoldRegions(editor, true); diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CopyPastePostProcessor.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CopyPastePostProcessor.java index e974f0720b70..1fd38e46c8b5 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CopyPastePostProcessor.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/CopyPastePostProcessor.java @@ -20,6 +20,7 @@ import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.RangeMarker; import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Ref; import com.intellij.psi.PsiFile; import org.jetbrains.annotations.Nullable; @@ -37,5 +38,10 @@ public interface CopyPastePostProcessor { @Nullable T extractTransferableData(final Transferable content); - void processTransferableData(final Project project, final Editor editor, final RangeMarker bounds, final T value); + void processTransferableData(final Project project, + final Editor editor, + final RangeMarker bounds, + int caretColumn, + Ref indented, + final T value); } diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/IndentTransferableData.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/IndentTransferableData.java new file mode 100644 index 000000000000..1702bc02b636 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/IndentTransferableData.java @@ -0,0 +1,65 @@ +package com.intellij.codeInsight.editorActions; + +import org.jetbrains.annotations.NonNls; + +import java.awt.datatransfer.DataFlavor; +import java.io.Serializable; + +/** + * @author yole + */ +public class IndentTransferableData implements TextBlockTransferableData, Serializable { + private static @NonNls DataFlavor ourFlavor; + + private final int myIndent; + private final int myFirstLineLeadingSpaces; + + public IndentTransferableData(int indent, int firstLineLeadingSpaces) { + myIndent = indent; + myFirstLineLeadingSpaces = firstLineLeadingSpaces; + } + + public int getIndent() { + return myIndent; + } + + public int getFirstLineLeadingSpaces() { + return myFirstLineLeadingSpaces; + } + + public DataFlavor getFlavor() { + return getDataFlavorStatic(); + } + + public static DataFlavor getDataFlavorStatic() { + if (ourFlavor != null) { + return ourFlavor; + } + try { + ourFlavor = new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType + ";class=" + IndentTransferableData.class.getName(), "Python indent transferable data"); + } + catch (NoClassDefFoundError e) { + return null; + } + catch (IllegalArgumentException e) { + return null; + } + return ourFlavor; + } + + public int getOffsetCount() { + return 0; + } + + public int getOffsets(int[] offsets, int index) { + return index; + } + + public int setOffsets(int[] offsets, int index) { + return index; + } + + protected IndentTransferableData clone() { + return new IndentTransferableData(myIndent, myFirstLineLeadingSpaces); + } +} diff --git a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/PasteHandler.java b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/PasteHandler.java index 51e376ed2334..dd1d59780db0 100644 --- a/platform/lang-impl/src/com/intellij/codeInsight/editorActions/PasteHandler.java +++ b/platform/lang-impl/src/com/intellij/codeInsight/editorActions/PasteHandler.java @@ -33,6 +33,7 @@ import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.ide.CopyPasteManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; @@ -174,9 +175,10 @@ public class PasteHandler extends EditorActionHandler { editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); editor.getSelectionModel().removeSelection(); + final Ref indented = new Ref(Boolean.FALSE); for(Map.Entry e: extraData.entrySet()) { //noinspection unchecked - e.getKey().processTransferableData(project, editor, bounds, e.getValue()); + e.getKey().processTransferableData(project, editor, bounds, col, indented, e.getValue()); } final int indentOptions1 = indentOptions; @@ -185,11 +187,15 @@ public class PasteHandler extends EditorActionHandler { public void run() { switch (indentOptions1) { case CodeInsightSettings.INDENT_BLOCK: - indentBlock(project, editor, bounds.getStartOffset(), bounds.getEndOffset(), col); + if (!indented.get()) { + indentBlock(project, editor, bounds.getStartOffset(), bounds.getEndOffset(), col); + } break; case CodeInsightSettings.INDENT_EACH_LINE: - indentEachLine(project, editor, bounds.getStartOffset(), bounds.getEndOffset()); + if (!indented.get()) { + indentEachLine(project, editor, bounds.getStartOffset(), bounds.getEndOffset()); + } break; case CodeInsightSettings.REFORMAT_BLOCK: diff --git a/platform/lang-impl/src/com/jetbrains/python/codeInsight/CopyPasteIndentProcessor.java b/platform/lang-impl/src/com/jetbrains/python/codeInsight/CopyPasteIndentProcessor.java new file mode 100644 index 000000000000..7ec455b25c3f --- /dev/null +++ b/platform/lang-impl/src/com/jetbrains/python/codeInsight/CopyPasteIndentProcessor.java @@ -0,0 +1,127 @@ +package com.jetbrains.python.codeInsight; + +import com.intellij.codeInsight.editorActions.CopyPastePostProcessor; +import com.intellij.codeInsight.editorActions.IndentTransferableData; +import com.intellij.codeStyle.CodeStyleFacade; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.RangeMarker; +import com.intellij.openapi.editor.actions.EditorActionUtil; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Ref; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.PsiFile; +import com.intellij.util.text.CharArrayUtil; + +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.io.IOException; + +/** + * @author yole + */ +public class CopyPasteIndentProcessor implements CopyPastePostProcessor { + @Override + public IndentTransferableData collectTransferableData(PsiFile file, + Editor editor, + int[] startOffsets, + int[] endOffsets) { + if (startOffsets.length != 1) { + return null; + } + Document document = editor.getDocument(); + int selStartLine = document.getLineNumber(startOffsets [0]); + int selEndLine = document.getLineNumber(endOffsets [0]); + if (selStartLine == selEndLine) { + return null; + } + // check that selection starts at or before the first non-whitespace character on a line + for (int offset = startOffsets[0] - 1; offset >= document.getLineStartOffset(selStartLine); offset--) { + if (!Character.isWhitespace(document.getCharsSequence().charAt(offset))) { + return null; + } + } + int minIndent = Integer.MAX_VALUE; + int tabSize = CodeStyleFacade.getInstance(file.getProject()).getTabSize(file.getFileType()); + for (int line = selStartLine; line <= selEndLine; line++) { + int start = document.getLineStartOffset(line); + int end = document.getLineEndOffset(line); + int indent = getIndent(document.getCharsSequence(), start, end, tabSize); + if (indent >= 0) { + minIndent = Math.min(minIndent, indent); + } + } + int firstNonSpaceChar = CharArrayUtil.shiftForward(document.getCharsSequence(), startOffsets [0], " \t"); + int firstLineLeadingSpaces = (firstNonSpaceChar <= document.getLineEndOffset(selStartLine)) ? firstNonSpaceChar - startOffsets[0] : 0; + return new IndentTransferableData(minIndent, firstLineLeadingSpaces); + } + + private static int getIndent(CharSequence chars, int start, int end, int tabSize) { + int result = 0; + boolean nonEmpty = false; + for(int i=start; i indented, + final IndentTransferableData value) { + if (value.getIndent() > 0) { + final Document document = editor.getDocument(); + //System.out.println("--- before indent ---\n" + document.getText()); + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + int startLine = document.getLineNumber(bounds.getStartOffset()); + int endLine = document.getLineNumber(bounds.getEndOffset()); + int startLineStart = document.getLineStartOffset(startLine); + // don't indent first line if there's any text before it + final String textBeforeFirstLine = document.getText(new TextRange(startLineStart, bounds.getStartOffset())); + if (textBeforeFirstLine.trim().length() == 0) { + EditorActionUtil.indentLine(project, editor, startLine, -value.getFirstLineLeadingSpaces()); + } + for (int i = startLine+1; i <= endLine; i++) { + EditorActionUtil.indentLine(project, editor, i, caretColumn - value.getIndent()); + } + indented.set(Boolean.TRUE); + } + }); + //System.out.println("--- after indent ---\n" + document.getText()); + } + } +}