package org.easyb.ui.editor;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
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;
public class BehaviourWordRule implements IPredicateRule{
private final IToken token;
private final Pattern regexPattern;
private StringBuffer buffer = new StringBuffer();
private char firstChar;
public BehaviourWordRule(IToken token,String...words){
this.token = token;
this.regexPattern = Pattern.compile(buildRegex(words));
this.firstChar = getFirstCharFromWords(words);
}
@Override
public IToken evaluate(ICharacterScanner scanner, boolean resume) {
return evaluate(scanner);
}
@Override
public IToken getSuccessToken() {
return token;
}
@Override
public IToken evaluate(ICharacterScanner scanner) {
int readNum = scanner.read();
char c = (char)readNum;
if(c!=firstChar){
scanner.unread();
return Token.UNDEFINED;
}
buffer.setLength(0);
buffer.append(c);
boolean stringStart = false;
do{
if(!stringStart && isStringIdentifier(c)){
//Could be a groovy GString formatted as """blah blah """
//So iterate over them if necessary
c=iterateBeginningForDoubleQuotes(scanner,c);
stringStart = true;
}else{
readNum = scanner.read();
c = (char)readNum;
buffer.append(c);
}
//Must of located an end string so try and match
//against the regex
if(stringStart && isStringIdentifier(c)){
iterateEndForDoubleQuotes(scanner,c);//Get the full string including trailing " for GStrings
Matcher matcher = regexPattern.matcher(buffer.toString());
if(matcher.find()){
return token;
}else{
break;
}
}
}while(readNum != ICharacterScanner.EOF);
unread(scanner);
return Token.UNDEFINED;
}
/**
* Used to iterate over the " in the scanner as groovy can
* have """ for multi-line GString.
* If its looking for the starting "
* then need to check for an empty string like "" or """""" in which case
* just return a " indicatign the end of the scanning.
* @param scanner
* @param checkForEmpty
* @return
*/
private char iterateBeginningForDoubleQuotes(ICharacterScanner scanner,char lastChar){
if(lastChar!='"'){
lastChar = (char)scanner.read();
buffer.append(lastChar);
return lastChar;
}
int countQuotes = 1;//The last char is a " so start at 1
while(lastChar=='"'){
lastChar = (char)scanner.read();
buffer.append(lastChar);
if(lastChar=='"'){
++countQuotes;
}
}
if((countQuotes==2 || countQuotes==6)){
return '"';//Signifies the end of the scanning
}
return lastChar;
}
private char iterateEndForDoubleQuotes(ICharacterScanner scanner,char lastChar){
if(lastChar!='"'){
return lastChar;
}
while(lastChar=='"'){
lastChar = (char)scanner.read();
if(lastChar=='"'){
buffer.append(lastChar);
}else{
scanner.unread();
}
}
return lastChar;
}
protected void unread(ICharacterScanner scanner){
for (int i= buffer.length() - 1; i >= 0; i--){
scanner.unread();
}
}
protected boolean isStringIdentifier(char c){
return c=='"'||c=='\''||c=='/';
}
protected String buildRegex(String[] words){
StringBuilder builder = new StringBuilder();
builder.append("^\\s*");
for(String word:words){
builder.append(word).append("\\s*");
}
//builder.append("\\s*[\"|'|\\/|].*[\"|'|\\/|]");
builder.append("[\"|'|\\/].*[\"|'|\\/]");
/*TODO do not match when "" as invalid,regex below is nearly there
* ^\s*scenario\s*((?!"{2}).)("{3}|"{1}|'|\/)[^"].*((?!"{2}).)("{3}|"{1}|'|\/)$"*/
//builder.append("\\s*((?!\"{2}).)(\"{3}|\"{1}|'|\\/)[^\"].*((?!\"{2}).)(\"{3}|\"{1}|'|\\/)$");
//builder.append("\\s*(\"{3}|\"{1}|'|\\/).*(\"{3}|\"{1}|'|\\/)$");
return builder.toString();
}
protected char getFirstCharFromWords(String[] words){
if(words.length==0){
return 0;
}
return words[0].charAt(0);
}
}