mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
smart indent on paste for Python (PY-208)
This commit is contained in:
+6
-1
@@ -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<Refer
|
||||
return null;
|
||||
}
|
||||
|
||||
public void processTransferableData(final Project project, final Editor editor, final RangeMarker bounds, final ReferenceTransferableData value) {
|
||||
public void processTransferableData(final Project project,
|
||||
final Editor editor,
|
||||
final RangeMarker bounds,
|
||||
int caretColumn,
|
||||
Ref<Boolean> indented, final ReferenceTransferableData value) {
|
||||
if (DumbService.getInstance(project).isDumb()) {
|
||||
return;
|
||||
}
|
||||
|
||||
+7
-1
@@ -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<Folding
|
||||
return null;
|
||||
}
|
||||
|
||||
public void processTransferableData(final Project project, final Editor editor, final RangeMarker bounds, final FoldingTransferableData value) {
|
||||
public void processTransferableData(final Project project,
|
||||
final Editor editor,
|
||||
final RangeMarker bounds,
|
||||
int caretColumn,
|
||||
Ref<Boolean> indented,
|
||||
final FoldingTransferableData value) {
|
||||
final CodeFoldingManagerImpl foldingManager = (CodeFoldingManagerImpl)CodeFoldingManager.getInstance(project);
|
||||
foldingManager.updateFoldRegions(editor, true);
|
||||
|
||||
|
||||
+7
-1
@@ -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<T extends TextBlockTransferableData> {
|
||||
@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<Boolean> indented,
|
||||
final T value);
|
||||
}
|
||||
|
||||
+65
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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<Boolean> indented = new Ref<Boolean>(Boolean.FALSE);
|
||||
for(Map.Entry<CopyPastePostProcessor, TextBlockTransferableData> 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:
|
||||
|
||||
+127
@@ -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<IndentTransferableData> {
|
||||
@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<end; i++) {
|
||||
if (chars.charAt(i) == ' ') {
|
||||
result++;
|
||||
}
|
||||
else if (chars.charAt(i) == '\t') {
|
||||
result = ((result / tabSize) + 1) * tabSize;
|
||||
}
|
||||
else {
|
||||
nonEmpty = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return nonEmpty ? result : -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IndentTransferableData extractTransferableData(Transferable content) {
|
||||
IndentTransferableData indentData = null;
|
||||
try {
|
||||
final DataFlavor flavor = IndentTransferableData.getDataFlavorStatic();
|
||||
if (flavor != null) {
|
||||
indentData = (IndentTransferableData)content.getTransferData(flavor);
|
||||
}
|
||||
}
|
||||
catch (UnsupportedFlavorException e) {
|
||||
// do nothing
|
||||
}
|
||||
catch (IOException e) {
|
||||
// do nothing
|
||||
}
|
||||
return indentData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processTransferableData(final Project project,
|
||||
final Editor editor,
|
||||
final RangeMarker bounds,
|
||||
final int caretColumn,
|
||||
final Ref<Boolean> 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user