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();
}
}