⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pyautoindentstrategy.java

📁 Python Development Environment (Python IDE plugin for Eclipse). Features editor, code completion, re
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
/*
 * 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 + -