package tk.eclipse.plugin.csseditor.editors;
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;
/**
* An implementation of IPredicateRule for CSS properties and values.
* <p>
* For exmaple:
* </p>
* <pre>
* <span style="color:red;">background:</span> <span style="color:blue;">black;</span>
* </pre>
* This rule returns following tokens.
* <ul>
* <li><span style="color:red;">A part ends with ':'</span> - returns a property token</li>
* <li><span style="color:blue;">A part ends with ';'</span> - returns a value token</li>
* </ul>
*
* @author Naoki Takezoe
*/
public class CSSRule implements IPredicateRule {
private IToken propToken;
private IToken valueToken;
/**
* Constructor.
*
* @param propToken a property token
* @param valueToken a value token
*/
public CSSRule(IToken propToken, IToken valueToken){
this.propToken = propToken;
this.valueToken = valueToken;
}
private boolean sequenceDetected(ICharacterScanner scanner, char[] sequence, boolean eofAllowed) {
for (int i= 1; i < sequence.length; i++) {
int c= scanner.read();
if (c == ICharacterScanner.EOF && eofAllowed) {
return true;
} else if (c != sequence[i]) {
// Non-matching character detected, rewind the scanner back to the start.
// Do not unread the first character.
scanner.unread();
for (int j= i-1; j > 0; j--)
scanner.unread();
return false;
}
}
return true;
}
private IToken getToken(ICharacterScanner scanner) {
int c;
char[][] delimiters= scanner.getLegalLineDelimiters();
while ((c= scanner.read()) != ICharacterScanner.EOF) {
if (c == ':') {
return propToken;
} else if (c == ';') {
return valueToken;
} else {
// Check for end of line since it can be used to terminate the pattern.
for (int i= 0; i < delimiters.length; i++) {
if (c == delimiters[i][0] && sequenceDetected(scanner, delimiters[i], true)) {
return null;
}
}
}
}
scanner.unread();
return null;
}
public IToken evaluate(ICharacterScanner scanner, boolean resume) {
return doEvaluate(scanner, resume);
}
private IToken doEvaluate(ICharacterScanner scanner, boolean resume) {
if (resume) {
IToken token = getToken(scanner);
if (token!=null) return token;
} else {
int c = scanner.read();
if (c != ' ' && c != '\t' && c!='\r' && c!='\n'){
IToken token = getToken(scanner);
if (token!=null) return token;
}
}
scanner.unread();
return Token.UNDEFINED;
}
public IToken getSuccessToken() {
return null;
}
public IToken evaluate(ICharacterScanner scanner) {
return evaluate(scanner, false);
}
}