logic for indenting after pasting does not based on copying now

PY-6884, PY-6965, PY-6966, PY-6907
This commit is contained in:
Ekaterina Tuzova
2012-07-16 19:18:20 +04:00
parent 726e76f7e9
commit e460d0ffd3
6 changed files with 55 additions and 84 deletions
@@ -96,7 +96,7 @@ public abstract class CopyPasteReferenceProcessor<TRef extends PsiElement> imple
public void processTransferableData(final Project project,
final Editor editor,
final RangeMarker bounds,
int caretColumn,
int caretOffset,
Ref<Boolean> indented, final ReferenceTransferableData value) {
if (DumbService.getInstance(project).isDumb()) {
return;
@@ -83,7 +83,7 @@ public class CopyPasteFoldingProcessor implements CopyPastePostProcessor<Folding
public void processTransferableData(final Project project,
final Editor editor,
final RangeMarker bounds,
int caretColumn,
int caretOffset,
Ref<Boolean> indented,
final FoldingTransferableData value) {
final CodeFoldingManagerImpl foldingManager = (CodeFoldingManagerImpl)CodeFoldingManager.getInstance(project);
@@ -1,27 +1,26 @@
package com.intellij.codeInsight.editorActions;
import com.intellij.codeInsight.CodeInsightSettings;
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.editor.impl.DocumentImpl;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.CharFilter;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiDocumentManager;
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;
import java.util.List;
/**
* @author yole
@@ -35,26 +34,7 @@ public class CopyPasteIndentProcessor implements CopyPastePostProcessor<IndentTr
if (!acceptFileType(file.getFileType())) {
return null;
}
if (startOffsets.length != 1) {
return null;
}
Document document = editor.getDocument();
int selStartLine = document.getLineNumber(startOffsets[0]);
// 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 tabSize = CodeStyleFacade.getInstance(file.getProject()).getTabSize(file.getFileType());
int start = document.getLineStartOffset(selStartLine);
int end = document.getLineEndOffset(selStartLine);
int minIndent = getIndent(document.getCharsSequence(), start, end, tabSize);
int firstNonSpaceChar = CharArrayUtil.shiftForward(document.getCharsSequence(), startOffsets[0], " \t");
int firstLineLeadingSpaces = (firstNonSpaceChar <= document.getLineEndOffset(selStartLine)) ? firstNonSpaceChar - startOffsets[0] : 0;
return new IndentTransferableData(minIndent, 0, firstLineLeadingSpaces);
return new IndentTransferableData(editor.getCaretModel().getOffset());
}
private static boolean acceptFileType(FileType fileType) {
@@ -66,24 +46,6 @@ public class CopyPasteIndentProcessor implements CopyPastePostProcessor<IndentTr
return false;
}
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;
@@ -109,12 +71,14 @@ public class CopyPasteIndentProcessor implements CopyPastePostProcessor<IndentTr
public void processTransferableData(final Project project,
final Editor editor,
final RangeMarker bounds,
final int caretColumn,
final int caretOffset,
final Ref<Boolean> indented,
final IndentTransferableData value) {
if (!CodeInsightSettings.getInstance().INDENT_TO_CARET_ON_PASTE) {
return;
}
if (value.getOffset() == editor.getCaretModel().getOffset()) return;
final Document document = editor.getDocument();
final PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(document);
if (psiFile == null || !acceptFileType(psiFile.getFileType())) {
@@ -129,33 +93,45 @@ public class CopyPasteIndentProcessor implements CopyPastePostProcessor<IndentTr
int startLine = document.getLineNumber(bounds.getStartOffset());
int endLine = document.getLineNumber(bounds.getEndOffset());
//calculate from indent
int fromIndent = StringUtil.findFirst(pastedText, CharFilter.NOT_WHITESPACE_FILTER);
if (fromIndent < 0) fromIndent = 0;
//calculate to indent
String initialText = document.getText(TextRange.create(0, bounds.getStartOffset())) +
document.getText(TextRange.create(bounds.getEndOffset(), document.getTextLength()));
final DocumentImpl initialDocument = new DocumentImpl(initialText);
final int lineNumber = initialDocument.getLineNumber(caretOffset);
final int offset = getLineStartSafeOffset(initialDocument, lineNumber);
final int caretColumn = caretOffset - offset;
String toString = initialDocument.getText(TextRange.create(offset, initialDocument.getLineEndOffset(lineNumber)));
int toIndent = StringUtil.findFirst(toString, new CharFilter() {
@Override
public boolean accept(char ch) {
return ch != ' ';
}
});
if (toIndent < 0 || toString.startsWith("\n")) {
if (StringUtil.isEmptyOrSpaces(toString) && toString.length() > 0) {
toIndent = toString.length();
}
else {
toIndent = caretColumn;
}
}
// actual difference in indentation level
int indent = toIndent - fromIndent;
// don't indent single-line text
if (!StringUtil.startsWithWhitespace(pastedText) && !StringUtil.endsWithLineBreak(pastedText) &&
!(StringUtil.splitByLines(pastedText).length > 1))
return;
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 (pastedText.endsWith("\n")) endLine -= 1;
final int caretOffset = editor.getCaretModel().getOffset();
int realCaretColumn = caretOffset - document.getLineStartOffset(document.getLineNumber(caretOffset));
//insert on top level, doesn't need indent
if (realCaretColumn == 0 && !pastedText.startsWith(" "))
return;
if (textBeforeFirstLine.trim().length() == 0) {
EditorActionUtil.indentLine(project, editor, startLine, -value.getFirstLineLeadingSpaces());
}
final List<String> strings = StringUtil.split(pastedText, "\n");
if (realCaretColumn >= value.getIndent() && !strings.isEmpty() &&
StringUtil.isEmptyOrSpaces(strings.get(strings.size()-1))) endLine -=1;
for (int i = startLine+1; i <= endLine; i++) {
int indent = realCaretColumn - value.getIndent();
for (int i = startLine; i <= endLine; i++) {
EditorActionUtil.indentLine(project, editor, i, indent);
}
indented.set(Boolean.TRUE);
@@ -163,4 +139,10 @@ public class CopyPasteIndentProcessor implements CopyPastePostProcessor<IndentTr
});
//System.out.println("--- after indent ---\n" + document.getText());
}
public static int getLineStartSafeOffset(final Document document, int line) {
if (line == document.getLineCount()) return document.getTextLength();
return document.getLineStartOffset(line);
}
}
@@ -41,7 +41,7 @@ public interface CopyPastePostProcessor<T extends TextBlockTransferableData> {
void processTransferableData(final Project project,
final Editor editor,
final RangeMarker bounds,
int caretColumn,
int caretOffset,
Ref<Boolean> indented,
final T value);
}
@@ -11,26 +11,15 @@ import java.io.Serializable;
public class IndentTransferableData implements TextBlockTransferableData, Serializable {
private static @NonNls DataFlavor ourFlavor;
private final int myIndent;
private final int myMaxIndent;
private final int myFirstLineLeadingSpaces;
private final int myOffset;
public IndentTransferableData(int indent, int maxIndent, int firstLineLeadingSpaces) {
myIndent = indent;
myMaxIndent = maxIndent;
myFirstLineLeadingSpaces = firstLineLeadingSpaces;
public IndentTransferableData(int offset) {
myOffset = offset;
}
public int getIndent() {
return myIndent;
}
public int getMaxIndent() {
return myMaxIndent;
}
public int getFirstLineLeadingSpaces() {
return myFirstLineLeadingSpaces;
public int getOffset() {
return myOffset;
}
public DataFlavor getFlavor() {
@@ -66,6 +55,6 @@ public class IndentTransferableData implements TextBlockTransferableData, Serial
}
protected IndentTransferableData clone() {
return new IndentTransferableData(myIndent, myMaxIndent, myFirstLineLeadingSpaces);
return new IndentTransferableData(myOffset);
}
}
@@ -227,7 +227,7 @@ public class PasteHandler extends EditorActionHandler implements EditorTextInser
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, col, indented, e.getValue());
e.getKey().processTransferableData(project, editor, bounds, offset, indented, e.getValue());
}
boolean pastedTextContainsWhiteSpacesOnly =