📄 pyautoindentstrategy.java
字号:
/*
* Created on Dec 10, 2003
* Author: atotic
* License: Common Public License 1.0
*/
package org.python.pydev.editor.autoedit;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.DocumentCommand;
import org.eclipse.jface.text.IAutoEditStrategy;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.python.copiedfromeclipsesrc.PythonPairMatcher;
import org.python.pydev.core.Tuple;
import org.python.pydev.core.Tuple3;
import org.python.pydev.core.docutils.DocUtils;
import org.python.pydev.core.docutils.ImportsSelection;
import org.python.pydev.core.docutils.ParsingUtils;
import org.python.pydev.core.docutils.PySelection;
import org.python.pydev.core.docutils.StringUtils;
import org.python.pydev.editor.actions.PyAction;
/**
* Class which implements the following behaviors:
* - indenting: after 'class' or 'def'
* - replacement: when typing colons or parentheses
*
* This class uses the org.python.pydev.core.docutils.DocUtils class extensively
* for some document-related operations.
*/
public class PyAutoIndentStrategy implements IAutoEditStrategy{
private IIndentPrefs prefs;
public PyAutoIndentStrategy(){
}
public void setIndentPrefs(IIndentPrefs prefs) {
this.prefs = prefs;
}
public IIndentPrefs getIndentPrefs() {
if (this.prefs == null) {
this.prefs = new DefaultIndentPrefs(); //create a new one (because each pyedit may force the tabs differently).
}
return this.prefs;
}
/**
* Set indentation automatically after newline.
*/
private Tuple<String,Boolean> autoIndentNewline(IDocument document, int length, String text, int offset)
throws BadLocationException {
if (offset > 0) {
PySelection selection = new PySelection(document, offset);
String lineWithoutComments = selection.getLineContentsToCursor(true, true);
Tuple<Integer, Boolean> tup = determineSmartIndent(offset, selection, prefs);
int smartIndent = tup.o1;
boolean isInsidePar = tup.o2;
if(lineWithoutComments.length() > 0){
//ok, now let's see the auto-indent
int curr = lineWithoutComments.length() -1;
char lastChar = lineWithoutComments.charAt(curr);
//we dont want whitespaces
while (curr > 0 && Character.isWhitespace(lastChar)) {
curr--;
lastChar = lineWithoutComments.charAt(curr);
}
//we have to check if smartIndent is -1 because otherwise we are inside some bracket
if(smartIndent == -1 && DocUtils.isClosingPeer(lastChar)){
//ok, not inside brackets
PythonPairMatcher matcher = new PythonPairMatcher(DocUtils.BRACKETS);
int bracketOffset = selection.getLineOffset()+curr;
IRegion region = matcher.match(document, bracketOffset+1);
if(region != null){
if(!PySelection.endsInSameLine(document, region)){
//we might not have a match if there is an error in the program...
//e.g. a single ')' without its counterpart.
int openingBracketLine = document.getLineOfOffset(region.getOffset());
String openingBracketLineStr = PySelection.getLine(document, openingBracketLine);
int first = PySelection.getFirstCharPosition(openingBracketLineStr);
String initial = getCharsBeforeNewLine(text);
text = initial + openingBracketLineStr.substring(0, first);
return new Tuple<String, Boolean>(text, isInsidePar);
}
}
} else if (smartIndent == -1 && lastChar == ':') {
//we have to check if smartIndent is -1 because otherwise we are in a dict
//ok, not inside brackets
text = indentBasedOnStartingScope(text, selection, false);
return new Tuple<String, Boolean>(text, isInsidePar);
}
}
String trimmedLine = lineWithoutComments.trim();
if(smartIndent >= 0 && (DocUtils.hasOpeningBracket(trimmedLine) || DocUtils.hasClosingBracket(trimmedLine))){
return new Tuple<String, Boolean>(makeSmartIndent(text, smartIndent), isInsidePar);
}
//let's check for dedents...
if(PySelection.startsWithDedentToken(trimmedLine)){
return new Tuple<String, Boolean>(dedent(text),isInsidePar);
}
boolean indentBasedOnStartingScope = false;
try {
if (PySelection.containsOnlyWhitespaces(selection.getLineContentsFromCursor())){
indentBasedOnStartingScope = true;
}
} catch (BadLocationException e) {
//(end of the file)
indentBasedOnStartingScope = true;
}
if(indentBasedOnStartingScope && selection.getLineContentsToCursor().trim().length() == 0){
return new Tuple<String, Boolean>(indentBasedOnStartingScope(text, selection, true), isInsidePar);
}
}
return new Tuple<String, Boolean>(text, false);
}
/**
* @return the text for the indent
*/
private String indentBasedOnStartingScope(String text, PySelection selection, boolean checkForLowestBeforeNewScope) {
Tuple3<String,String, String> previousIfLine = selection.getPreviousLineThatStartsScope();
if(previousIfLine != null){
String initial = getCharsBeforeNewLine(text);
if(previousIfLine.o2 == null){ //no dedent was found
String indent = PySelection.getIndentationFromLine(previousIfLine.o1);
if(checkForLowestBeforeNewScope && previousIfLine.o3 != null){
indent = PySelection.getIndentationFromLine(previousIfLine.o3);
text = initial + indent;
}else{
text = initial + indent + prefs.getIndentationString();
}
}else{ //some dedent was found
String indent = PySelection.getIndentationFromLine(previousIfLine.o2);
String indentationString = prefs.getIndentationString();
final int i = indent.length() - indentationString.length();
if (i > 0 && indent.length() > i){
text = (initial+indent).substring(0, i+1);
}else{
text = initial; // this can happen if we found a dedent that is 1 level deep
}
}
}
return text;
}
/**
* Returns the first offset greater than <code>offset</code> and smaller than
* <code>end</code> whose character is not a space or tab character. If no such
* offset is found, <code>end</code> is returned.
*
* @param document the document to search in
* @param offset the offset at which searching start
* @param end the offset at which searching stops
* @return the offset in the specified range whose character is not a space or tab
* @exception BadLocationException if position is an invalid range in the given document
*/
private int findEndOfWhiteSpace(IDocument document, int offset, int end) throws BadLocationException {
while (offset < end) {
char c= document.getChar(offset);
if (c != ' ' && c != '\t') {
return offset;
}
offset++;
}
return end;
}
private void autoIndentSameAsPrevious(IDocument d, DocumentCommand c) {
String txt = autoIndentSameAsPrevious(d, c.offset, c.text, true);
if(txt != null){
c.text = txt;
}
}
/**
* Copies the indentation of the previous line.
*
* @param d the document to work on
* @param text the string that should added to the start of the returned string
* @param considerEmptyLines whether we should consider empty lines in this function
* @param c the command to deal with
*
* @return a string with text+ the indentation found in the previous line (or previous non-empty line).
*/
private String autoIndentSameAsPrevious(IDocument d, int offset, String text, boolean considerEmptyLines) {
if (offset == -1 || d.getLength() == 0)
return null;
try {
// find start of line
IRegion info= d.getLineInformationOfOffset(offset);
String line = d.get(info.getOffset(), info.getLength());
if(!considerEmptyLines){
int currLine = d.getLineOfOffset(offset);
while(PySelection.containsOnlyWhitespaces(line)){
currLine--;
if(currLine <= 0){
break;
}
info= d.getLineInformation(currLine);
line = d.get(info.getOffset(), info.getLength());
}
}
int start= info.getOffset();
// find white spaces
int end= findEndOfWhiteSpace(d, start, offset);
StringBuffer buf= new StringBuffer(text);
if (end > start) {
// append to input
buf.append(d.get(start, end - start));
}
return buf.toString();
} catch (BadLocationException excp) {
// stop work
return null;
}
}
/**
* @param document
* @param length
* @param text
* @return
*/
private boolean isNewLineText(IDocument document, int length, String text) {
return length == 0 && text != null && AbstractIndentPrefs.endsWithNewline(document, text) && text.length() < 3;
}
private String dedent(String text) {
String indentationString = prefs.getIndentationString();
int indentationLength = indentationString.length();
int len = text.length();
if(len >= indentationLength){
text = text.substring(0, len - indentationLength);
}
return text;
}
private Tuple<String, Integer> removeFirstIndent(String text) {
String indentationString = prefs.getIndentationString();
if(text.startsWith(indentationString)){
return new Tuple<String, Integer>(text.substring(indentationString.length()), indentationString.length());
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -