/******************************************************************************* * Copyright (c) 2006, 2012 Oracle Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Oracle Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.bpel.ui.editors.xpath; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import org.eclipse.bpel.ui.editors.xpath.rules.AxisRule; import org.eclipse.bpel.ui.editors.xpath.rules.FloatRule; import org.eclipse.bpel.ui.editors.xpath.rules.FunctionRule; import org.eclipse.bpel.ui.editors.xpath.rules.ITokenContext; import org.eclipse.bpel.ui.editors.xpath.rules.SingleCharRule; import org.eclipse.bpel.ui.editors.xpath.rules.SingleOperatorRule; import org.eclipse.bpel.ui.editors.xpath.rules.StringRule; import org.eclipse.bpel.ui.editors.xpath.rules.WordRule; import org.eclipse.bpel.ui.preferences.PreferenceConstants; import org.eclipse.jface.text.TextAttribute; import org.eclipse.jface.text.rules.BufferedRuleBasedScanner; import org.eclipse.jface.text.rules.ICharacterScanner; import org.eclipse.jface.text.rules.IRule; import org.eclipse.jface.text.rules.IToken; import org.eclipse.jface.text.rules.IWordDetector; import org.eclipse.jface.text.rules.SingleLineRule; import org.eclipse.jface.text.rules.Token; import org.eclipse.jface.text.rules.WhitespaceRule; import org.eclipse.swt.SWT; /** * @author Michal Chmielewski (michal.chmielewski@oracle.com) * @date Oct 25, 2006 */ public class XPathSourceScanner extends BufferedRuleBasedScanner { IWordDetector fNCNameDetector = new XPathWordDetector.NCNameWordDetector (); IWordDetector fWordDetector = new XPathWordDetector(); IWordDetector fVariableNameDetector = new XPathWordDetector.VariableDetector(); IWordDetector fQNameDetector = new XPathWordDetector.QNameDetector (); LinkedList<IToken> tokenWindow = new LinkedList<IToken>(); /** * The scanner for the XPath source editor, which provides * syntax coloring based on the default damager and repairer. * * @param manager */ @SuppressWarnings("nls") public XPathSourceScanner( ColorManager manager ) { IToken defToken = new Token ( new TextAttribute ( manager.getColor( PreferenceConstants.DEFAULT ) ) ); final IToken operatorToken = new Token ( new TextAttribute ( manager.getColor( PreferenceConstants.OPERAND ), null, SWT.BOLD ) ); IToken number = new Token ( new TextAttribute ( manager.getColor( PreferenceConstants.NUMBER ), null, SWT.BOLD ) ); IToken string = new Token ( new TextAttribute ( manager.getColor( PreferenceConstants.STRING ) ) ) ; IToken brackets = new Token ( new TextAttribute ( manager.getColor( PreferenceConstants.BRACKET ), null, SWT.BOLD ) ); IToken axis = new Token ( new TextAttribute ( manager.getColor( PreferenceConstants.AXIS ), null, SWT.ITALIC ) ); IToken pathSep = new Token ( new TextAttribute ( manager.getColor( PreferenceConstants.PATH_SEPARATOR ), null, SWT.BOLD ) ); IToken functionsDefault = new Token ( new TextAttribute ( manager.getColor( PreferenceConstants.FUNCTIONS_XPATH ), null, SWT.ITALIC ) ); IToken functions = new Token ( new TextAttribute ( manager.getColor( PreferenceConstants.FUNCTIONS_XPATH ), null, SWT.BOLD) ) ; final IToken variableToken = new Token ( new TextAttribute( manager.getColor( PreferenceConstants.VARIABLES ), null, SWT.BOLD )); IToken partToken = new Token ( new TextAttribute( manager.getColor( PreferenceConstants.VARIABLE_PART ), null, SWT.BOLD )); // The list of rules for this scanner. List<IRule> rules = new ArrayList<IRule>(24); // Add rule for double quotes string rules.add( new SingleLineRule("\"", "\"", string , '\\') ); //$NON-NLS-1$ //$NON-NLS-2$ // Add a rule for single quotes string rules.add( new SingleLineRule("'", "'", string , '\\') ); //$NON-NLS-1$ //$NON-NLS-2$ // Add function calls ... // Add generic whitespace rule. rules.add( new WhitespaceRule(new XPathWhitespaceDetector()) ); // numbers rules.add ( new FloatRule ( number )) ; WordRule wordRule; // variable rule wordRule = new WordRule ( fVariableNameDetector ); wordRule.addWord ( WordRule.ANY , variableToken ); rules.add (wordRule); // Variable part rule wordRule = new WordRule ( new XPathWordDetector.MessagePartDetector() ); wordRule.addWord ( WordRule.ANY , partToken ); wordRule.setTokenContextCheck( new TokenContext () { @Override public boolean checkSeenTokens(XPathSourceScanner scanner) { return (scanner.lastToken(0) == variableToken); } }); rules.add (wordRule); // Some operators. rules.add ( new SingleOperatorRule ( operatorToken, "+-*=|/<>" ) ); // Operators of sorts ... rules.add ( new StringRule ( operatorToken, "!=") ); rules.add ( new StringRule ( operatorToken, ">=") ); rules.add ( new StringRule ( operatorToken, "<=") ); rules.add ( new StringRule ( operatorToken, ">=") ); rules.add ( new SingleCharRule ( brackets, "[]().@," ) ); rules.add ( new StringRule ( operatorToken, "//") ); rules.add ( new StringRule ( pathSep, "::") ); // rule for operators ... wordRule = new WordRule( new XPathWordDetector () ); wordRule.addWord ("mod",operatorToken); wordRule.addWord ("div",operatorToken); wordRule.addWord ("and",operatorToken); wordRule.addWord ("or",operatorToken); wordRule.setTokenContextCheck( new TokenContext() { @Override public boolean checkSeenTokens(XPathSourceScanner scanner) { int idx = (scanner.lastToken(0) == Token.WHITESPACE ? 1 : 0); return scanner.lastToken(idx) != operatorToken; } }); rules.add( wordRule ); AxisRule axisRule = new AxisRule ( fNCNameDetector ); axisRule.addWords(AXIS, axis); rules.add(axisRule); // The basic XPath functions FunctionRule functionRule = new FunctionRule ( fQNameDetector ); functionRule.addWords(XPATH_FUNCTIONS,functionsDefault); rules.add(functionRule); // All other functions functionRule = new FunctionRule ( fQNameDetector ); functionRule.addWord( WordRule.ANY,functions); rules.add(functionRule); wordRule = new WordRule( fWordDetector ); wordRule.addWord ( WordRule.ANY, defToken ); rules.add( wordRule ); setDefaultReturnToken( defToken ) ; setRules ( rules.toArray(new IRule[]{} )); } /** * * @see org.eclipse.jface.text.rules.RuleBasedScanner#nextToken() */ @Override public IToken nextToken() { IToken next = super.nextToken(); tokenWindow.addFirst(next); if (tokenWindow.size() > 4) { tokenWindow.removeLast(); } return next; } /** * Returns the last token with the index of offset. Index 0 means the last token seen, * 1 means the one before the last token seen. * * @param offset * @return the token requested or undefined. */ public IToken lastToken ( int offset ) { try { return tokenWindow.get(offset); } catch (Throwable t) { return Token.UNDEFINED; } } static private final String[] XPATH_FUNCTIONS = { "last","position","count","id","local-name","namespace-uri","name", "string","concat","starts-with","contains","substring-before","substring-after", "substring","string-length","normalize-space","translate", "boolean","not","true","false","lang", "number","sum","floor","ceiling","round" }; static private final String[] AXIS = { "ancestor", "ancestor-or-self", "attribute", "child", "descendant", "descendant-or-self", "following", "following-sibling", "namespace", "parent", "preceding", "preceding-sibling", "self" }; /** * The TokenContext class allows us to see what tokens we have seen * so far. In some syntax coloring constructs we need to have a memory * (albeit a simple one) of where we have been. * * @author Michal Chmielewski (michal.chmielewski@oracle.com) * @date Nov 27, 2006 */ abstract class TokenContext implements ITokenContext { /** (non-Javadoc) * @see org.eclipse.bpel.ui.editors.xpath.rules.ITokenContext#check(org.eclipse.jface.text.rules.ICharacterScanner) */ public boolean check (ICharacterScanner scanner) { if (scanner instanceof XPathSourceScanner) { return checkSeenTokens ( (XPathSourceScanner) scanner); } return false; } /** * * @param scanner * @return true if the right tokens have been seen so far, false * otherwise. * */ public abstract boolean checkSeenTokens ( XPathSourceScanner scanner ) ; } }