package org.python.pydev.core.partition; import java.util.ArrayList; import java.util.List; import org.eclipse.jface.text.rules.ICharacterScanner; import org.eclipse.jface.text.rules.IPredicateRule; import org.eclipse.jface.text.rules.IToken; import org.eclipse.jface.text.rules.Token; import org.python.pydev.shared_core.partitioner.IChangeTokenRule; import org.python.pydev.shared_core.partitioner.IMarkScanner; import org.python.pydev.shared_core.string.FastStringBuffer; public class MultiLineRuleWithMultipleStarts implements IPredicateRule, IChangeTokenRule { protected IToken fToken; protected final List<char[]> fStartSequences; protected final char[] fEndSequence; protected final char fEscapeCharacter; @Override public void setToken(IToken token) { this.fToken = token; } public MultiLineRuleWithMultipleStarts(String[] startSequences, String end, IToken token, char escapeCharacter) { ArrayList<char[]> lst = new ArrayList<>(startSequences.length); for (String start : startSequences) { lst.add(start.toCharArray()); } this.fStartSequences = lst; this.fEndSequence = end.toCharArray(); this.fToken = token; this.fEscapeCharacter = escapeCharacter; } @Override public IToken evaluate(ICharacterScanner scanner) { return evaluate(scanner, false); } @Override public IToken getSuccessToken() { return fToken; } @Override public IToken evaluate(ICharacterScanner scanner, boolean resume) { if (resume) { return Token.UNDEFINED; } IMarkScanner markScanner = (IMarkScanner) scanner; int mark = markScanner.getMark(); int c; int size = fStartSequences.size(); for (int j = 0; j < size; j++) { boolean found = true; char[] startSequence = fStartSequences.get(j); for (int i = 0; i < startSequence.length; i++) { c = scanner.read(); if (c != startSequence[i]) { //Backup to where we started found = false; markScanner.setMark(mark); break; } } if (found) { break; } else { //Didn't find... go to next (unless we checked all: in this case return that //we didn't match the start). if (j == size - 1) { return Token.UNDEFINED; } } } //Ok, found start sequence, now, find the end sequence. while (true) { c = scanner.read(); if (c == ICharacterScanner.EOF) { return fToken; //Always match open partitions that are unclosed on a multi line rule. } if (c == fEscapeCharacter) { //skip the next char if skip char is matched c = scanner.read(); if (c == ICharacterScanner.EOF) { return fToken; //Always match open partitions that are unclosed on a multi line rule. } continue; } mark = markScanner.getMark(); boolean matched = true; for (int i = 0;; i++) { if (c != fEndSequence[i]) { markScanner.setMark(mark); matched = false; break; } if (i + 1 < fEndSequence.length) { c = scanner.read(); } else { break; } } if (matched) { return fToken; } } } @Override public String toString() { FastStringBuffer buf = new FastStringBuffer("MultiLineRuleWithMultipleStarts(", fEndSequence.length + 40); buf.append("start: "); for (char[] chars : this.fStartSequences) { buf.append(chars).append(",\n"); } buf.append("end: ") .append(fEndSequence) .append(")"); return buf.toString(); } }