/** * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved. * Licensed under the terms of the Eclipse Public License (EPL). * Please see the license.txt included with this distribution for details. * Any modifications to this file must keep this entire header intact. */ /* * Author: atotic * Created: July 10, 2003 */ package org.python.pydev.core.docutils; import java.util.ArrayList; import java.util.List; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IDocumentExtension3; import org.eclipse.jface.text.IDocumentPartitioner; import org.eclipse.jface.text.rules.EndOfLineRule; import org.eclipse.jface.text.rules.FastPartitioner; import org.eclipse.jface.text.rules.IPredicateRule; import org.eclipse.jface.text.rules.IToken; import org.eclipse.jface.text.rules.MultiLineRule; import org.eclipse.jface.text.rules.PatternRule; import org.eclipse.jface.text.rules.RuleBasedPartitionScanner; import org.eclipse.jface.text.rules.SingleLineRule; import org.eclipse.jface.text.rules.Token; import org.python.pydev.core.IPythonPartitions; import org.python.pydev.core.log.Log; /** * Rule-based partition scanner * * Simple, fast parsing of the document into partitions.<p> * This is like a rough 1st pass at parsing. We only parse * out for comments, single-line strings, and multiline strings<p> * The results are parsed again inside {@link org.python.pydev.editor.PyEditConfiguration#getPresentationReconciler} * and colored there.<p> * * "An IPartitionTokenScanner can also start in the middle of a partition, * if it knows the type of the partition." */ public class PyPartitionScanner extends RuleBasedPartitionScanner implements IPythonPartitions { public PyPartitionScanner() { super(); List<IPredicateRule> rules = new ArrayList<IPredicateRule>(); addMultilineStringRule(rules); addSinglelineStringRule(rules); addReprRule(rules); addCommentRule(rules); setPredicateRules(rules.toArray(new IPredicateRule[0])); } private void addReprRule(List<IPredicateRule> rules) { rules.add(new SingleLineRule("`", "`", new Token(IPythonPartitions.PY_BACKQUOTES))); } private void addSinglelineStringRule(List<IPredicateRule> rules) { // IToken singleLineString = new Token(PY_SINGLELINE_STRING); // rules.add(new SingleLineRule("\"", "\"", singleLineString, '\\')); // rules.add(new SingleLineRule("'", "'", singleLineString, '\\')); -- changed to the construct below because we need to continue on escape IToken singleLineString1 = new Token(IPythonPartitions.PY_SINGLELINE_STRING1); IToken singleLineString2 = new Token(IPythonPartitions.PY_SINGLELINE_STRING2); // deal with "" and '' strings boolean breaksOnEOL = true; boolean breaksOnEOF = false; boolean escapeContinuesLine = true; rules.add(new PatternRule("'", "'", singleLineString1, '\\', breaksOnEOL, breaksOnEOF, escapeContinuesLine)); rules.add(new PatternRule("\"", "\"", singleLineString2, '\\', breaksOnEOL, breaksOnEOF, escapeContinuesLine)); } private void addMultilineStringRule(List<IPredicateRule> rules) { IToken multiLineString1 = new Token(IPythonPartitions.PY_MULTILINE_STRING1); IToken multiLineString2 = new Token(IPythonPartitions.PY_MULTILINE_STRING2); // deal with ''' and """ strings boolean breaksOnEOF = true; //If we don't add breaksOnEOF = true it won't properly recognize the rule while typing //in the following case: ///'''<new line> //text //''' <-- it's already lost at this point and the 'text' will not be in a multiline string partition. rules.add(new MultiLineRule("'''", "'''", multiLineString1, '\\', breaksOnEOF)); rules.add(new MultiLineRule("\"\"\"", "\"\"\"", multiLineString2, '\\', breaksOnEOF)); //there is a bug in this construct: When parsing a simple document such as: // //"""ttt""" //print 'a' // //if lines are feed after 'ttt', it ends up considering the whole document as a multiline string. //the bug is reported at: http://sourceforge.net/tracker/index.php?func=detail&aid=1402165&group_id=85796&atid=577329 // //some regards on the bug: //- it does not happen if the multiline has ''' instead of """ //- also, if we first add the """ rule and after the ''' rule, the bug happens with ''' and not """ //- if the user later changes the first line of that multiline or a line above it, it ends up parsing correctly again //- if we let just one of the constructs, no problem happens // //I also tried creating a new token for it, but it had problems too (not the same ones, but had other problems). } private void addCommentRule(List<IPredicateRule> rules) { IToken comment = new Token(IPythonPartitions.PY_COMMENT); rules.add(new EndOfLineRule("#", comment)); } /** * @return all types recognized by this scanner (used by doc partitioner) */ static public String[] getTypes() { return IPythonPartitions.types; } /** * Checks if the partitioner is correctly set in the document. * @return the partitioner that is set in the document */ public static IDocumentPartitioner checkPartitionScanner(IDocument document) { if (document == null) { return null; } IDocumentExtension3 docExtension = (IDocumentExtension3) document; IDocumentPartitioner partitioner = docExtension.getDocumentPartitioner(IPythonPartitions.PYTHON_PARTITION_TYPE); if (partitioner == null) { addPartitionScanner(document); //get it again for the next check partitioner = docExtension.getDocumentPartitioner(IPythonPartitions.PYTHON_PARTITION_TYPE); } if (!(partitioner instanceof PyPartitioner)) { Log.log("Partitioner should be subclass of PyPartitioner. It is " + partitioner.getClass()); } return partitioner; } /** * @see http://help.eclipse.org/help31/index.jsp?topic=/org.eclipse.platform.doc.isv/guide/editors_documents.htm * @see http://jroller.com/page/bobfoster - Saturday July 16, 2005 * @param document the document where we want to add the partitioner * @return the added document partitioner (or null) */ public static IDocumentPartitioner addPartitionScanner(IDocument document) { if (document != null) { IDocumentExtension3 docExtension = (IDocumentExtension3) document; IDocumentPartitioner curr = docExtension.getDocumentPartitioner(IPythonPartitions.PYTHON_PARTITION_TYPE); if (curr == null) { //set the new one FastPartitioner partitioner = createPyPartitioner(); partitioner.connect(document); docExtension.setDocumentPartitioner(IPythonPartitions.PYTHON_PARTITION_TYPE, partitioner); return partitioner; } else { return curr; } } return null; } public static PyPartitioner createPyPartitioner() { return new PyPartitioner(new PyPartitionScanner(), getTypes()); } }