| /******************************************************************************* |
| * 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.contentassist; |
| |
| import java.util.ArrayList; |
| import java.util.EmptyStackException; |
| import java.util.Iterator; |
| import java.util.Stack; |
| |
| import org.eclipse.bpel.model.Link; |
| import org.eclipse.bpel.model.Variable; |
| import org.eclipse.bpel.model.util.BPELUtils; |
| import org.eclipse.bpel.ui.BPELUIPlugin; |
| import org.eclipse.bpel.ui.IBPELUIConstants; |
| import org.eclipse.bpel.ui.details.providers.LinkContentProvider; |
| import org.eclipse.bpel.ui.expressions.IEditorConstants; |
| import org.eclipse.bpel.ui.util.BPELUtil; |
| import org.eclipse.bpel.ui.util.XSDUtils; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.jface.text.BadLocationException; |
| import org.eclipse.jface.text.IDocument; |
| import org.eclipse.jface.text.ITextViewer; |
| import org.eclipse.jface.text.contentassist.CompletionProposal; |
| import org.eclipse.jface.text.contentassist.ContentAssistEvent; |
| import org.eclipse.jface.text.contentassist.ICompletionListener; |
| import org.eclipse.jface.text.contentassist.ICompletionProposal; |
| import org.eclipse.jface.text.contentassist.IContentAssistProcessor; |
| import org.eclipse.jface.text.contentassist.IContentAssistant; |
| import org.eclipse.jface.text.contentassist.IContentAssistantExtension2; |
| import org.eclipse.jface.text.contentassist.IContextInformation; |
| import org.eclipse.jface.text.contentassist.IContextInformationValidator; |
| import org.eclipse.swt.graphics.Image; |
| import org.eclipse.wst.wsdl.Message; |
| import org.eclipse.wst.wsdl.Part; |
| import org.eclipse.xsd.XSDAttributeDeclaration; |
| import org.eclipse.xsd.XSDComplexTypeDefinition; |
| import org.eclipse.xsd.XSDElementDeclaration; |
| import org.eclipse.xsd.XSDSimpleTypeDefinition; |
| import org.eclipse.xsd.XSDTypeDefinition; |
| |
| |
| /** |
| * @author Edward Gee (edward.gee@oracle.com) |
| * @author Michal Chmielewski (michal.chmielewski@oracle.com) |
| * |
| */ |
| |
| public class ExpressionContentAssistProcessor |
| implements IContentAssistProcessor, ICompletionListener { |
| |
| static String EMPTY_STRING = ""; //$NON-NLS-1$ |
| |
| static ICompletionProposal[] EMPTY_COMPLETION_PROPOSALS = {} ; |
| |
| // members of class ExpressionContentAssistProcessor |
| private Object theModel = null; |
| private int theToggle = 3; |
| private String theLastBeginsWith = EMPTY_STRING; |
| private String theExpressionContext = EMPTY_STRING; |
| private IContentAssistantExtension2 theContentAssistant; |
| |
| /** |
| * The function templates content assist processor. |
| */ |
| |
| FunctionTemplatesContentAssistProcessor fFunctionTemplates = new FunctionTemplatesContentAssistProcessor(); |
| XPathTemplateCompletionProcessor fXpathTemplates = new XPathTemplateCompletionProcessor(); |
| |
| // public constants |
| static final String MINUS = "-"; //$NON-NLS-1$ |
| static final String PLUS = "+"; //$NON-NLS-1$ |
| static final String MULTIPLY = "*"; //$NON-NLS-1$ |
| static final String DIVIDE = "/"; //$NON-NLS-1$ |
| static final String OPEN_PAREN = "("; //$NON-NLS-1$ |
| static final String CLOSE_PAREN = ")"; //$NON-NLS-1$ |
| static final String OPEN_BRACKET = "["; //$NON-NLS-1$ |
| static final String CLOSE_BRACKET = "]"; //$NON-NLS-1$ |
| static final String COMMA = ","; //$NON-NLS-1$ |
| static final String DOLLAR = "$"; //$NON-NLS-1$ |
| static final String EQUAL = "="; //$NON-NLS-1$ |
| static final String NOT_EQUAL = "!="; //$NON-NLS-1$ |
| static final String LESS_THAN = "<"; //$NON-NLS-1$ |
| static final String LESS_THAN_EQUAL = "<="; //$NON-NLS-1$ |
| static final String GREATER_THAN = ">"; //$NON-NLS-1$ |
| static final String GREATER_THAN_EQUAL = ">="; //$NON-NLS-1$ |
| static final String MOD = "mod"; //$NON-NLS-1$ |
| static final String DIV = "div"; //$NON-NLS-1$ |
| static final String AND = "and"; //$NON-NLS-1$ |
| static final String OR = "or"; //$NON-NLS-1$ |
| static final String COLON = ":"; //$NON-NLS-1$ |
| static final String AT = "@"; //$NON-NLS-1$ |
| |
| // helper class for defining proposal types |
| class ProposalType { |
| private int theType; |
| private String theBeginsWith; |
| |
| // bitwise flags for different types |
| static final int PROPTYPE_VARIABLE = 1; |
| static final int PROPTYPE_FUNCTION = 2; |
| static final int PROPTYPE_OPERATOR = 4; |
| |
| ProposalType(int type, String beginsWith) { |
| theType = type; |
| theBeginsWith = beginsWith; |
| } |
| |
| boolean isVariable() { return ((theType & PROPTYPE_VARIABLE) == PROPTYPE_VARIABLE); } |
| boolean isFunction() { return ((theType & PROPTYPE_FUNCTION) == PROPTYPE_FUNCTION); } |
| boolean isOperator() { return ((theType & PROPTYPE_OPERATOR) == PROPTYPE_OPERATOR); } |
| boolean isVariableAndFunction() { return ((theType & (PROPTYPE_VARIABLE | PROPTYPE_FUNCTION)) == (PROPTYPE_VARIABLE | PROPTYPE_FUNCTION)); } |
| } |
| |
| // helper class for defining expression types within xpath expression... used by XPathStack |
| class ExpressionType { |
| private int theType; |
| private String theGrammar; |
| |
| static final int EXPRTYPE_VARIABLE = 1; |
| static final int EXPRTYPE_FUNCTION = 2; |
| static final int EXPRTYPE_LITERAL = 3; |
| static final int EXPRTYPE_NUMBER = 4; |
| static final int EXPRTYPE_UNARY_OPERATOR = 5; |
| static final int EXPRTYPE_NUMERIC_OPERATOR = 6; |
| static final int EXPRTYPE_BOOLEAN_OPERATOR = 7; |
| static final int EXPRTYPE_NEW_EXPRESSION = 8; |
| static final int EXPRTYPE_FUNCTION_ARGUMENTS = 9; |
| static final int EXPRTYPE_FUNCTION_ARGUMENT_SEPARATOR = 10; |
| |
| static final int CLASS_NUMERIC = 100; |
| static final int CLASS_BOOLEAN = 101; |
| static final int CLASS_EXPRESSION = 102; |
| |
| |
| ExpressionType(int type, String grammar) { |
| theType = type; |
| theGrammar = grammar; |
| } |
| } |
| |
| // simple call stack used for parsing XPath expressions |
| protected class XPathStack { |
| |
| Stack<ExpressionType> theCallStack; |
| int theStatus; |
| IDocument theDocument; |
| int theOffset; |
| int theIndex; |
| int theTopOfStackExprType = -1; |
| |
| XPathStack(ITextViewer viewer, int offset) { |
| theCallStack = new Stack<ExpressionType>(); |
| theStatus = 0; // flag for stack's integrity |
| theDocument = viewer.getDocument(); |
| theOffset = offset; |
| theIndex = 0; |
| } |
| |
| //parse numeric expression |
| private boolean parseNumberExpression() throws BadLocationException { |
| char currChar; |
| boolean proceed = false; |
| while (theIndex < theOffset) { |
| currChar = theDocument.getChar(theIndex); |
| |
| // variable |
| if (currChar == '$') { |
| if ((theTopOfStackExprType == ExpressionType.EXPRTYPE_UNARY_OPERATOR) || |
| //(theTopOfStackExprType == ExpressionType.EXPRTYPE_BOOLEAN_OPERATOR) || |
| (theTopOfStackExprType == ExpressionType.EXPRTYPE_NUMERIC_OPERATOR)) |
| return parseVariable(); |
| |
| if (!parseVariable()) |
| return false; |
| } |
| // literal |
| else if ((currChar == '\'') || (currChar == '"')) { |
| if ((theTopOfStackExprType == ExpressionType.EXPRTYPE_UNARY_OPERATOR) || |
| //(theTopOfStackExprType == ExpressionType.EXPRTYPE_BOOLEAN_OPERATOR) || |
| (theTopOfStackExprType == ExpressionType.EXPRTYPE_NUMERIC_OPERATOR)) |
| return parseLiteral(); |
| |
| if (!parseLiteral()) |
| return false; |
| } |
| else if (Character.isDigit(currChar) || (currChar == '.')) { |
| if ((theTopOfStackExprType == ExpressionType.EXPRTYPE_UNARY_OPERATOR) || |
| //(theTopOfStackExprType == ExpressionType.EXPRTYPE_BOOLEAN_OPERATOR) || |
| (theTopOfStackExprType == ExpressionType.EXPRTYPE_NUMERIC_OPERATOR)) |
| return parseNumber(); |
| |
| if (!parseNumber()) |
| return false; |
| } |
| else if (isReservedOperatorCharacter(currChar)) { |
| if ((theTopOfStackExprType == ExpressionType.EXPRTYPE_BOOLEAN_OPERATOR) || |
| (theTopOfStackExprType == ExpressionType.EXPRTYPE_NUMERIC_OPERATOR) || |
| (theTopOfStackExprType == ExpressionType.EXPRTYPE_UNARY_OPERATOR) || |
| (theTopOfStackExprType == -1)) { |
| // check to see if it's a unary operator |
| if (currChar == '-') { |
| theCallStack.push(new ExpressionType(ExpressionType.EXPRTYPE_UNARY_OPERATOR, MINUS)); |
| theTopOfStackExprType = ExpressionType.EXPRTYPE_UNARY_OPERATOR; |
| theIndex++; |
| if (parseNumberExpression()) { |
| // pop the operand |
| theCallStack.pop(); |
| // pop the unary operator |
| theCallStack.pop(); |
| // push "numeric" value |
| theCallStack.push(new ExpressionType(ExpressionType.CLASS_NUMERIC, EMPTY_STRING)); |
| theTopOfStackExprType = ExpressionType.CLASS_NUMERIC; |
| } |
| } |
| else { |
| theStatus = -1; |
| return false; |
| } |
| } |
| else { |
| String tempOper = Character.toString(currChar); |
| if ((theIndex+1) < theOffset) { |
| if (isReservedOperatorCharacter(theDocument.getChar(theIndex+1))) { |
| theIndex++; |
| tempOper = tempOper + Character.toString(theDocument.getChar(theIndex)); |
| } |
| int tempType = 0; |
| if ((tempOper.compareTo(PLUS) == 0) || (tempOper.compareTo(MINUS) == 0) || |
| (tempOper.compareTo(MULTIPLY) == 0) || (tempOper.compareTo(DIVIDE) == 0)) |
| tempType = ExpressionType.EXPRTYPE_NUMERIC_OPERATOR; |
| else |
| tempType = ExpressionType.EXPRTYPE_BOOLEAN_OPERATOR; |
| |
| theCallStack.push(new ExpressionType(tempType, tempOper)); |
| theTopOfStackExprType = tempType; |
| theIndex++; |
| if (tempType == ExpressionType.EXPRTYPE_BOOLEAN_OPERATOR) { |
| return parseBooleanExpression(); |
| } |
| if (parseNumberExpression()) { |
| // pop the operand |
| theCallStack.pop(); |
| // pop the operator |
| theCallStack.pop(); |
| // pop the first operand; |
| theCallStack.pop(); |
| // push "numeric value" |
| theCallStack.push(new ExpressionType(ExpressionType.CLASS_NUMERIC, EMPTY_STRING)); |
| theTopOfStackExprType = ExpressionType.CLASS_NUMERIC; |
| } |
| else { |
| return false; |
| } |
| } |
| else {// return |
| int tempType = 0; |
| if ((tempOper.compareTo(PLUS) == 0) || (tempOper.compareTo(MINUS) == 0) || |
| (tempOper.compareTo(MULTIPLY) == 0) || (tempOper.compareTo(DIVIDE) == 0)) |
| tempType = ExpressionType.EXPRTYPE_NUMERIC_OPERATOR; |
| else |
| tempType = ExpressionType.EXPRTYPE_BOOLEAN_OPERATOR; |
| |
| theCallStack.push(new ExpressionType(tempType, tempOper)); |
| theTopOfStackExprType = tempType; |
| return false; |
| |
| } |
| } |
| } |
| else if (Character.isWhitespace(currChar)) { |
| // just ignore |
| } |
| else if (currChar == '(') { |
| theCallStack.push(new ExpressionType(ExpressionType.EXPRTYPE_NEW_EXPRESSION, Character.toString(currChar))); |
| theTopOfStackExprType = ExpressionType.EXPRTYPE_NEW_EXPRESSION; |
| theIndex++; |
| if (parseBooleanExpression()) { |
| // peek and set top of stack id |
| ExpressionType tempExpr = theCallStack.peek(); |
| int type = tempExpr.theType; |
| theCallStack.push(new ExpressionType(ExpressionType.CLASS_EXPRESSION, EMPTY_STRING)); |
| theTopOfStackExprType = ExpressionType.CLASS_EXPRESSION; |
| if ((type == ExpressionType.EXPRTYPE_UNARY_OPERATOR) || |
| (theTopOfStackExprType == ExpressionType.EXPRTYPE_BOOLEAN_OPERATOR) || |
| (theTopOfStackExprType == ExpressionType.EXPRTYPE_NUMERIC_OPERATOR)) |
| return true; |
| } |
| else |
| return false; |
| } |
| else if (isClosingExpressionCharacter(currChar)) { |
| try { |
| ExpressionType tempExpr = theCallStack.pop(); |
| while (!((tempExpr.theType == ExpressionType.EXPRTYPE_NEW_EXPRESSION) || |
| (tempExpr.theType == ExpressionType.EXPRTYPE_FUNCTION_ARGUMENTS))) { |
| tempExpr = theCallStack.pop(); |
| } |
| if (tempExpr != null) { |
| if (tempExpr.theType == ExpressionType.EXPRTYPE_NEW_EXPRESSION) { |
| switch (currChar) { |
| case ')': |
| if (tempExpr.theGrammar.compareTo(OPEN_PAREN) == 0) { |
| return true; |
| } |
| theStatus = -1; |
| return false; |
| |
| case ']': |
| if (tempExpr.theGrammar.compareTo(OPEN_BRACKET) == 0) { |
| return true; |
| } |
| theStatus = -1; |
| return false; |
| default: |
| theStatus = -1; |
| return false; |
| } |
| } |
| else if (tempExpr.theType == ExpressionType.EXPRTYPE_FUNCTION_ARGUMENTS) { |
| if (currChar == ')') { |
| return true; |
| } |
| theStatus = -1; |
| return false; |
| } |
| theStatus = -1; |
| return false; |
| } |
| } |
| catch (EmptyStackException e) { |
| theStatus = -1; |
| return false; |
| } |
| theStatus = -1; |
| return false; |
| } |
| else if (currChar == ',') { |
| // could be a function argument |
| return true; |
| } |
| else { |
| int type = theTopOfStackExprType; |
| proceed = parseWord(); |
| if (proceed) { |
| if ((theTopOfStackExprType == ExpressionType.EXPRTYPE_NUMERIC_OPERATOR) || |
| (theTopOfStackExprType == ExpressionType.EXPRTYPE_BOOLEAN_OPERATOR)) { |
| if ((type == ExpressionType.EXPRTYPE_NUMERIC_OPERATOR) || |
| (type == ExpressionType.EXPRTYPE_BOOLEAN_OPERATOR) || |
| (type == ExpressionType.EXPRTYPE_UNARY_OPERATOR) || |
| (type == -1)) { |
| theStatus = -1; |
| return false; |
| } |
| |
| theIndex++; |
| if (theTopOfStackExprType == ExpressionType.EXPRTYPE_BOOLEAN_OPERATOR) { |
| return parseBooleanExpression(); |
| } |
| if (parseNumberExpression()) { |
| // pop the operand |
| theCallStack.pop(); |
| // pop the operator |
| theCallStack.pop(); |
| // pop the first operand; |
| theCallStack.pop(); |
| // push "numeric value" |
| theCallStack.push(new ExpressionType(ExpressionType.CLASS_NUMERIC, EMPTY_STRING)); |
| theTopOfStackExprType = ExpressionType.CLASS_NUMERIC; |
| } else { |
| return false; |
| } |
| } |
| else { |
| if ((type == ExpressionType.EXPRTYPE_UNARY_OPERATOR) || |
| (theTopOfStackExprType == ExpressionType.EXPRTYPE_BOOLEAN_OPERATOR) || |
| (theTopOfStackExprType == ExpressionType.EXPRTYPE_NUMERIC_OPERATOR)) |
| return true; |
| } |
| } |
| else |
| return false; |
| |
| } |
| theIndex++; |
| } |
| return false; |
| } |
| |
| // parse boolean expressions |
| boolean parseBooleanExpression() throws BadLocationException { |
| |
| boolean proceed = parseNumberExpression(); |
| while (proceed) { |
| ExpressionType tempExpr = theCallStack.peek(); |
| if (tempExpr.theType == ExpressionType.EXPRTYPE_BOOLEAN_OPERATOR) |
| proceed = parseNumberExpression(); |
| else |
| return proceed; |
| } |
| return proceed; |
| } |
| |
| // parse word found in numeric expression |
| private boolean parseWord() throws BadLocationException { |
| String word = EMPTY_STRING; |
| char nextChar; |
| while (theIndex < theOffset) { |
| nextChar = theDocument.getChar(theIndex); |
| if (nextChar == '(') { |
| if (word.length() > 0) { |
| theCallStack.push(new ExpressionType(ExpressionType.EXPRTYPE_FUNCTION, word)); |
| theTopOfStackExprType = ExpressionType.EXPRTYPE_FUNCTION; |
| boolean proceed = parseFunction(); |
| if (proceed) { |
| // pop the function name |
| theCallStack.pop(); |
| // push the expression |
| theCallStack.push(new ExpressionType(ExpressionType.CLASS_EXPRESSION, EMPTY_STRING)); |
| theTopOfStackExprType = ExpressionType.CLASS_EXPRESSION; |
| return true; |
| } |
| return false; |
| } |
| } |
| if (Character.isWhitespace(nextChar)) { |
| if (word.length() > 0) { |
| if ((word.compareToIgnoreCase(MOD) == 0) || |
| (word.compareToIgnoreCase(DIV) == 0)) { |
| theCallStack.push(new ExpressionType(ExpressionType.EXPRTYPE_NUMERIC_OPERATOR, word)); |
| theTopOfStackExprType = ExpressionType.EXPRTYPE_NUMERIC_OPERATOR; |
| return true; |
| } |
| if ((word.compareToIgnoreCase(AND) == 0) || |
| (word.compareToIgnoreCase(OR) == 0)) { |
| theCallStack.push(new ExpressionType(ExpressionType.EXPRTYPE_BOOLEAN_OPERATOR, word)); |
| theTopOfStackExprType = ExpressionType.EXPRTYPE_BOOLEAN_OPERATOR; |
| return true; |
| } |
| |
| //maybe it's a function name... next character should be whitespace or ( |
| int tempIndex = theIndex; |
| while (tempIndex < theOffset) { |
| if (!Character.isWhitespace(theDocument.getChar(tempIndex))) { |
| if (theDocument.getChar(tempIndex) == '(') { |
| break; |
| } |
| theStatus = -1; |
| return false; |
| } |
| tempIndex++; |
| } |
| } |
| } |
| word = word + nextChar; |
| theIndex++; |
| } |
| if (theIndex >= theOffset) { |
| theCallStack.push(new ExpressionType(ExpressionType.EXPRTYPE_FUNCTION, word)); |
| theStatus = 1; |
| return false; |
| } |
| |
| return false; |
| } |
| |
| // parse function |
| private boolean parseFunction() throws BadLocationException { |
| char nextChar; |
| while (theIndex < theOffset) { |
| nextChar = theDocument.getChar(theIndex); |
| if (nextChar == '(') |
| theCallStack.push(new ExpressionType(ExpressionType.EXPRTYPE_FUNCTION_ARGUMENTS, OPEN_PAREN)); |
| else if (nextChar == ')') { |
| try { |
| ExpressionType tempExpr = theCallStack.peek(); |
| |
| if (tempExpr != null) { |
| if (tempExpr.theType == ExpressionType.EXPRTYPE_FUNCTION) |
| return true; |
| else if (tempExpr.theType == ExpressionType.EXPRTYPE_FUNCTION_ARGUMENTS) { |
| theCallStack.pop(); |
| return true; |
| } |
| else { |
| theStatus = -1; |
| return false; |
| } |
| } |
| } |
| catch (EmptyStackException e) { |
| theStatus = -1; |
| return false; |
| } |
| theStatus = -1; |
| return false; |
| } |
| else if (nextChar == ',') { |
| theIndex++; |
| theCallStack.push(new ExpressionType(ExpressionType.EXPRTYPE_FUNCTION_ARGUMENT_SEPARATOR, COMMA)); |
| boolean proceed = parseBooleanExpression(); |
| if (!proceed) |
| return false; |
| |
| continue; |
| } |
| else if (Character.isWhitespace(nextChar)) { |
| //ignore |
| } |
| else { |
| boolean proceed = parseBooleanExpression(); |
| if (!proceed) |
| return false; |
| |
| continue; |
| } |
| |
| theIndex++; |
| } |
| return false; |
| } |
| |
| // parse literal values |
| private boolean parseLiteral() throws BadLocationException { |
| String literal = EMPTY_STRING; |
| char nextChar = theDocument.getChar(theIndex); |
| // delimiter could be single or double quote |
| char delimiter = nextChar; |
| literal = literal + nextChar; |
| theIndex++; |
| while (theIndex < theOffset) { |
| nextChar = theDocument.getChar(theIndex); |
| if (nextChar != delimiter) { |
| literal = literal + nextChar; |
| } |
| else { |
| literal = literal + nextChar; |
| theCallStack.push(new ExpressionType(ExpressionType.EXPRTYPE_LITERAL, literal)); |
| theTopOfStackExprType = ExpressionType.EXPRTYPE_LITERAL; |
| return true; |
| } |
| theIndex++; |
| } |
| |
| if (theIndex >= theOffset) { |
| theCallStack.push(new ExpressionType(ExpressionType.EXPRTYPE_LITERAL, literal)); |
| theStatus = 1; |
| return false; |
| } |
| return false; |
| } |
| |
| // parse number values |
| private boolean parseNumber() throws BadLocationException { |
| String number = EMPTY_STRING; |
| char nextChar; |
| while (theIndex < theOffset) { |
| nextChar = theDocument.getChar(theIndex); |
| if ((Character.isDigit(nextChar) || (nextChar == '.'))) { |
| number = number + nextChar; |
| } |
| else { |
| theCallStack.push(new ExpressionType(ExpressionType.EXPRTYPE_NUMBER, number)); |
| theTopOfStackExprType = ExpressionType.EXPRTYPE_NUMBER; |
| theIndex--; |
| return true; |
| } |
| theIndex++; |
| } |
| |
| if (theIndex >= theOffset) { |
| theCallStack.push(new ExpressionType(ExpressionType.EXPRTYPE_NUMBER, number)); |
| return false; |
| } |
| return false; |
| } |
| |
| // parse variable |
| private boolean parseVariable() throws BadLocationException { |
| theIndex++; // move past $ token |
| String variable = DOLLAR; |
| char nextChar; |
| while (theIndex < theOffset) { |
| nextChar = theDocument.getChar(theIndex); |
| if (isLocationPathCharacter(nextChar)) { |
| variable = variable + nextChar; |
| } |
| else if (nextChar == '[') { |
| theCallStack.push(new ExpressionType(ExpressionType.EXPRTYPE_VARIABLE, variable)); |
| theCallStack.push(new ExpressionType(ExpressionType.EXPRTYPE_NEW_EXPRESSION, OPEN_BRACKET)); |
| theIndex++; |
| boolean proceed = parseBooleanExpression(); |
| if (proceed) { |
| nextChar = theDocument.getChar(theIndex); |
| if (nextChar == ']') { |
| try { |
| ExpressionType tempExpr = theCallStack.pop(); |
| while (tempExpr.theType != ExpressionType.EXPRTYPE_NEW_EXPRESSION) { |
| // continue popping until we find a new expression type |
| tempExpr = theCallStack.pop(); |
| } |
| if (tempExpr != null) { |
| if (tempExpr.theGrammar.compareTo(CLOSE_BRACKET) == 0) { |
| return true; |
| } |
| } |
| } |
| catch (EmptyStackException e) { |
| theStatus = -1; |
| return false; |
| } |
| } |
| else { |
| // in error ... maybe throw something here |
| theStatus = -1; |
| return false; |
| } |
| } |
| else { |
| return proceed; |
| } |
| } |
| else { |
| theCallStack.push(new ExpressionType(ExpressionType.EXPRTYPE_VARIABLE, variable)); |
| theTopOfStackExprType = ExpressionType.EXPRTYPE_VARIABLE; |
| theIndex--; |
| return true; |
| } |
| theIndex++; |
| } |
| |
| if (theIndex >= theOffset) { |
| theCallStack.push(new ExpressionType(ExpressionType.EXPRTYPE_VARIABLE, variable)); |
| theStatus = 1; |
| return false; |
| //return new ProposalType(ProposalType.PROPTYPE_VARIABLE, variable); |
| } |
| |
| // shouldn't get here |
| theStatus = -1; |
| return false; |
| } |
| |
| /** |
| * Parse XPath expression |
| * @return true of parsed OK |
| */ |
| |
| public boolean parse() { |
| try { |
| parseBooleanExpression(); |
| return (theStatus != -1); |
| } |
| catch (BadLocationException e) { |
| System.out.println(e.toString()); |
| } |
| return false; |
| } |
| |
| /** |
| * Retrieve suggestion after parsing |
| * @return the suggestion. |
| */ |
| public ExpressionType getSuggestion() { |
| try { |
| return theCallStack.peek(); |
| } |
| catch (EmptyStackException e) { |
| return null; |
| } |
| } |
| |
| } |
| |
| |
| /** |
| * @see org.eclipse.jface.text.contentassist.ICompletionListener#assistSessionStarted(org.eclipse.jface.text.contentassist.ContentAssistEvent) |
| */ |
| public void assistSessionStarted(ContentAssistEvent event) { |
| |
| IContentAssistant assistant= event.assistant; |
| if (assistant instanceof IContentAssistantExtension2) { |
| theContentAssistant= (IContentAssistantExtension2)assistant; |
| } |
| } |
| |
| /** |
| * @see org.eclipse.jface.text.contentassist.ICompletionListener#assistSessionEnded(org.eclipse.jface.text.contentassist.ContentAssistEvent) |
| */ |
| public void assistSessionEnded(ContentAssistEvent event) { |
| theContentAssistant= null; |
| theToggle = 3; |
| theLastBeginsWith = EMPTY_STRING; |
| } |
| |
| /** |
| * @see org.eclipse.jface.text.contentassist.ICompletionListener#selectionChanged(org.eclipse.jface.text.contentassist.ICompletionProposal, boolean) |
| */ |
| public void selectionChanged(ICompletionProposal proposal, boolean smartToggle) { |
| // do nothing |
| } |
| |
| |
| /** |
| * @param model |
| */ |
| public void setModelObject(Object model) { |
| theModel = model; |
| fFunctionTemplates.setModel(model); |
| } |
| |
| /** |
| * @param expressionContext |
| */ |
| public void setExpressionContext(String expressionContext) { |
| theExpressionContext = expressionContext; |
| } |
| |
| |
| /** |
| * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#computeCompletionProposals(org.eclipse.jface.text.ITextViewer, int) |
| */ |
| public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset) { |
| return generateProposals(viewer, offset); |
| } |
| |
| |
| /** |
| * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#computeContextInformation(org.eclipse.jface.text.ITextViewer, int) |
| */ |
| public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset) { |
| return null; |
| } |
| |
| /** |
| * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#getCompletionProposalAutoActivationCharacters() |
| */ |
| public char[] getCompletionProposalAutoActivationCharacters() { |
| // for variables |
| return new char[] { '$', '/', '@', '.' }; |
| } |
| |
| /** |
| * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#getContextInformationAutoActivationCharacters() |
| */ |
| public char[] getContextInformationAutoActivationCharacters() { |
| // do nothing for now |
| return null; |
| } |
| |
| /** |
| * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#getContextInformationValidator() |
| */ |
| public IContextInformationValidator getContextInformationValidator() { |
| // do nothing for now |
| return null; |
| } |
| |
| /** |
| * @see org.eclipse.jface.text.contentassist.IContentAssistProcessor#getErrorMessage() |
| */ |
| public String getErrorMessage() { |
| // do nothing for now |
| return Messages.getString("ExpressionContentAssistProcessor.32"); //$NON-NLS-1$ |
| } |
| |
| /* |
| * Second iteration of determining proposal type. Attempts to parse the xpath |
| * expression until offset is reached or it can not ascertain what the expression |
| * means. If parsing fails, tries to identify the word located right before |
| * the offset and provide proposal types based on that information. |
| */ |
| private ProposalType determineProposalType2(ITextViewer viewer, int offset) { |
| XPathStack callStack = new XPathStack(viewer, offset); |
| if (callStack.parse()) { |
| |
| ExpressionType expr = callStack.getSuggestion(); |
| |
| if (expr != null) { |
| switch (expr.theType) { |
| case ExpressionType.EXPRTYPE_VARIABLE: |
| if (callStack.theStatus == 1) { |
| return new ProposalType(ProposalType.PROPTYPE_VARIABLE, expr.theGrammar); |
| } |
| return new ProposalType(ProposalType.PROPTYPE_OPERATOR, EMPTY_STRING); |
| |
| case ExpressionType.EXPRTYPE_FUNCTION: |
| if (callStack.theStatus == 1) { |
| return new ProposalType(ProposalType.PROPTYPE_FUNCTION, expr.theGrammar); |
| } |
| return new ProposalType(ProposalType.PROPTYPE_OPERATOR, EMPTY_STRING); |
| |
| case ExpressionType.EXPRTYPE_BOOLEAN_OPERATOR: |
| case ExpressionType.EXPRTYPE_NUMERIC_OPERATOR: |
| case ExpressionType.EXPRTYPE_UNARY_OPERATOR: |
| case ExpressionType.EXPRTYPE_FUNCTION_ARGUMENTS: |
| case ExpressionType.EXPRTYPE_FUNCTION_ARGUMENT_SEPARATOR: |
| case ExpressionType.EXPRTYPE_NEW_EXPRESSION: |
| return new ProposalType(ProposalType.PROPTYPE_FUNCTION | ProposalType.PROPTYPE_VARIABLE, EMPTY_STRING); |
| case ExpressionType.CLASS_BOOLEAN: |
| case ExpressionType.CLASS_NUMERIC: |
| case ExpressionType.CLASS_EXPRESSION: |
| case ExpressionType.EXPRTYPE_NUMBER: |
| return new ProposalType(ProposalType.PROPTYPE_OPERATOR, EMPTY_STRING); |
| case ExpressionType.EXPRTYPE_LITERAL: |
| if (callStack.theStatus == 1) { |
| return (new ProposalType(0, EMPTY_STRING)); |
| } |
| return new ProposalType(ProposalType.PROPTYPE_OPERATOR, EMPTY_STRING); |
| |
| default: |
| return (new ProposalType(0, EMPTY_STRING)); |
| } |
| } |
| // try suggesting everything |
| return new ProposalType(ProposalType.PROPTYPE_FUNCTION | ProposalType.PROPTYPE_VARIABLE, EMPTY_STRING); |
| } |
| |
| // try last ditch effort |
| String tempContext = startOfVariable(viewer, offset); |
| if (tempContext != null) { |
| return new ProposalType(ProposalType.PROPTYPE_VARIABLE, tempContext); |
| } |
| tempContext = startOfFunction(viewer, offset); |
| if (tempContext != null) { |
| return new ProposalType(ProposalType.PROPTYPE_FUNCTION, tempContext); |
| } |
| return new ProposalType(ProposalType.PROPTYPE_FUNCTION | ProposalType.PROPTYPE_VARIABLE, EMPTY_STRING); |
| } |
| |
| /* |
| * Try best guess to generate proposals based on provided context information |
| */ |
| private ICompletionProposal[] generateProposals(ITextViewer viewer, int offset) { |
| ProposalType propType = determineProposalType2(viewer, offset); |
| // only toggle if the begins with hasn't changed |
| boolean toggle = false; |
| if (theLastBeginsWith.compareTo(propType.theBeginsWith) == 0) |
| toggle = true; |
| else |
| theLastBeginsWith = propType.theBeginsWith; |
| |
| String funcStart = EMPTY_STRING; |
| String varlinkStart = EMPTY_STRING; |
| |
| if (propType.isVariableAndFunction()) { |
| theToggle = (theToggle+1) % 4; |
| funcStart = propType.theBeginsWith; |
| varlinkStart = propType.theBeginsWith; |
| } |
| else if (propType.isVariable()) { |
| if (toggle) |
| theToggle = (theToggle+1) % 4; |
| else |
| theToggle = 0; |
| funcStart = EMPTY_STRING; |
| varlinkStart = propType.theBeginsWith; |
| } |
| else if (propType.isFunction()) { |
| if (toggle) |
| theToggle = (theToggle+1) % 4; |
| else |
| theToggle = 1; |
| funcStart = propType.theBeginsWith; |
| varlinkStart = EMPTY_STRING; |
| } |
| else if (propType.isOperator()) { |
| if (toggle) |
| theToggle = (theToggle+1) % 4; |
| else |
| theToggle = 2; |
| funcStart = EMPTY_STRING; |
| varlinkStart = EMPTY_STRING; |
| } |
| |
| switch (theToggle) { |
| case 0: |
| theContentAssistant.setStatusMessage(Messages.getString("ExpressionContentAssistProcessor.44")); //$NON-NLS-1$ |
| if (theExpressionContext.compareTo(IEditorConstants.ET_JOIN) == 0) { |
| return generateLinkProposals(varlinkStart, offset); |
| } |
| return generateVariableProposals(varlinkStart, offset); |
| case 1: |
| theContentAssistant.setStatusMessage(Messages.getString("ExpressionContentAssistProcessor.45")); //$NON-NLS-1$ |
| return generateFunctionProposals(viewer, funcStart, offset); |
| case 2: |
| theContentAssistant.setStatusMessage(Messages.getString("ExpressionContentAssistProcessor.46")); //$NON-NLS-1$ |
| return generateOperatorProposals(EMPTY_STRING, offset); |
| |
| case 3: |
| if (theExpressionContext.compareTo(IEditorConstants.ET_JOIN) == 0) |
| theContentAssistant.setStatusMessage(Messages.getString("ExpressionContentAssistProcessor.48")); //$NON-NLS-1$ |
| else |
| theContentAssistant.setStatusMessage(Messages.getString("ExpressionContentAssistProcessor.49")); //$NON-NLS-1$ |
| //return generateTemplateProposals(tempStart, offset); |
| return (fXpathTemplates.computeCompletionProposals(viewer, offset)); |
| } |
| |
| return null; |
| } |
| |
| /** |
| * From model, determine list of functions the user may want to choose from. |
| */ |
| ICompletionProposal[] generateFunctionProposals(ITextViewer viewer, String context, int offset) { |
| return fFunctionTemplates.computeCompletionProposals(viewer, offset); |
| } |
| |
| /* |
| * Static proposal list of supported operators. Could refine the list |
| * to group by numeric or boolean operators. |
| */ |
| static final String[] OPERATOR_LIST = {AND, OR, EQUAL, NOT_EQUAL, LESS_THAN, GREATER_THAN, |
| LESS_THAN_EQUAL, GREATER_THAN_EQUAL, PLUS, MINUS, MULTIPLY, DIV, MOD}; |
| |
| ICompletionProposal[] generateOperatorProposals(String context, int offset) { |
| |
| Image img = BPELUIPlugin.INSTANCE.getImage(IBPELUIConstants.ICON_OPERATION_16); |
| |
| ICompletionProposal[] proposals = new ICompletionProposal[OPERATOR_LIST.length]; |
| for (int i=0; i<OPERATOR_LIST.length; i++) { |
| proposals[i] = new CompletionProposal(OPERATOR_LIST[i], offset, 0, OPERATOR_LIST[i].length(), img, OPERATOR_LIST[i], null, null); |
| } |
| return proposals; |
| } |
| |
| |
| ICompletionProposal[] generateLinkProposals(String context, int offset) { |
| |
| ArrayList<ICompletionProposal> results = new ArrayList<ICompletionProposal>(); |
| |
| Image linkImg = BPELUIPlugin.INSTANCE.getImage(IBPELUIConstants.ICON_LINK_16); |
| |
| for( Object next : new LinkContentProvider( LinkContentProvider.INCOMING ).getElements(theModel) ) { |
| Link link = (Link) next; |
| |
| String replName = DOLLAR + link.getName(); |
| if (replName.startsWith(context)) { |
| results.add(new CompletionProposal(replName, |
| offset - context.length(), context.length(), |
| replName.length(), linkImg, link.getName() , |
| null, null)); |
| } |
| } |
| |
| if (results.size() < 1) { |
| return new ICompletionProposal[] { |
| new CompletionProposal(EMPTY_STRING, offset, 0, |
| 0, null, Messages.getString("ExpressionContentAssistProcessor.31"), //$NON-NLS-1$ |
| null, null) }; |
| } |
| return results.toArray(EMPTY_COMPLETION_PROPOSALS); |
| } |
| |
| // Bugzilla 320654 |
| String getNamespacePrefix(EObject context, String namespace) |
| { |
| String prefix = BPELUtils.getNamespacePrefix(context, namespace); |
| while ( prefix==null ) |
| { |
| prefix = BPELUtil.lookupOrCreateNamespacePrefix(context, namespace, null, null); |
| if ( prefix == null ) |
| throw new IllegalArgumentException("namespace prefix is null"); |
| } |
| return prefix; |
| } |
| |
| /** |
| * From model, determine list of variables the user may want to choose from. |
| */ |
| ICompletionProposal[] generateVariableProposals(String context, int offset) { |
| boolean seekChildren = false; |
| |
| String context2; |
| if ((context.length() > 0) && (context.charAt(0) == '$')) |
| context2 = context.substring(1); |
| else |
| context2 = context; |
| |
| int slash = context2.indexOf('/'); |
| int dot = context2.indexOf('.'); |
| int at = context2.indexOf('@'); |
| |
| if ((slash > -1) || (dot > -1) || (at > -1)) |
| seekChildren = true; |
| |
| Variable[] variables = BPELUtil.getVisibleVariables((EObject)theModel); |
| ArrayList<ICompletionProposal> results = new ArrayList<ICompletionProposal>(); |
| CompletionProposal prop = null; |
| String name; |
| Variable currVar = null; |
| XSDTypeDefinition currXsdType = null; |
| Message currMsg = null; |
| XSDElementDeclaration currXsdElem = null; |
| |
| Image varImg = BPELUIPlugin.INSTANCE.getImage(IBPELUIConstants.ICON_VARIABLE_16); |
| Image partImg = BPELUIPlugin.INSTANCE.getImage(IBPELUIConstants.ICON_PART_16); |
| Image elementImg = BPELUIPlugin.INSTANCE.getImage(IBPELUIConstants.ICON_XSD_ELEMENT_DECLARATION_16); |
| Image attrImg = BPELUIPlugin.INSTANCE.getImage(IBPELUIConstants.ICON_XSD_ATTRIBUTE_DECLARATION_16); |
| try |
| { |
| if (seekChildren) { |
| // walk down path |
| int index = 0; |
| int level = 0; |
| int token = -1; |
| char t = 0; |
| String levelName; |
| |
| while (index < context2.length()) { |
| t = context2.charAt(index); |
| if ((t == '.') || (t == '/')) { |
| levelName = context2.substring(token+1, index); |
| /* |
| // check for namespace |
| int ns = levelName.indexOf(':'); |
| if (ns > -1) { |
| levelNSPrefix = levelName.substring(0, ns); |
| levelName = levelName.substring(ns+1); |
| } |
| else |
| levelNSPrefix = null; |
| */ |
| |
| // find variable |
| if (level == 0) { |
| for (int i=0; i<variables.length; i++) { |
| if (levelName.compareTo(variables[i].getName()) == 0) { |
| currVar = variables[i]; |
| currXsdType = currVar.getType(); |
| currMsg = currVar.getMessageType(); |
| currXsdElem = currVar.getXSDElement(); |
| |
| level++; |
| break; |
| } |
| } |
| if (currVar == null) |
| break; |
| } |
| // traverse down |
| else { |
| boolean childFound = false; |
| if (context2.charAt(token) == '.') { |
| if (currMsg != null) { |
| if (currMsg.getParts() != null) { |
| for(Object next : currMsg.getParts().values()) { |
| Part item = (Part) next ; |
| if (levelName.compareTo(item.getName()) == 0) { |
| currXsdType = item.getTypeDefinition(); |
| currMsg = item.getEMessage(); |
| currXsdElem = item.getElementDeclaration(); |
| childFound = true; |
| break; |
| } |
| } |
| } |
| } |
| if (!childFound) |
| break; |
| } |
| // search for child objects |
| else if (context2.charAt(token) == '/') { |
| if (currXsdType == null) { |
| if (currXsdElem != null) { |
| currXsdType = currXsdElem.getTypeDefinition(); |
| } |
| } |
| if (currXsdType instanceof XSDComplexTypeDefinition) { |
| XSDComplexTypeDefinition xsdcomplex = (XSDComplexTypeDefinition)currXsdType; |
| |
| for(Object next : XSDUtils.getChildElements(xsdcomplex)) { |
| XSDElementDeclaration elem = ((XSDElementDeclaration)next).getResolvedElementDeclaration(); |
| String elemName = elem.getName(); |
| if (elem.getTargetNamespace() != null) { |
| String elemNSPrefix = getNamespacePrefix(currVar, elem.getTargetNamespace()); |
| if (elemNSPrefix != null) { |
| elemName = elemNSPrefix + COLON + elemName; |
| } |
| } |
| |
| if (levelName.compareTo(elemName) == 0) { |
| currXsdType = elem.getTypeDefinition(); |
| currXsdElem = null; |
| currMsg = null; |
| //currXsdElem = elem.getResolvedElementDeclaration(); |
| childFound = true; |
| break; |
| } |
| } |
| } |
| else if (currXsdType instanceof XSDSimpleTypeDefinition) { |
| XSDSimpleTypeDefinition xsdsimple = (XSDSimpleTypeDefinition)currXsdType; |
| //currXsdType = xsdsimple.getBaseType(); |
| //XSDSimpleTypeDefinition tempsimple = xsdsimple.getBaseTypeDefinition(); |
| //org.eclipse.xsd.XSDParticle temppart = xsdsimple.getComplexType(); |
| //XSDSimpleTypeDefinition tempsimple2 = xsdsimple.getItemTypeDefinition(); |
| String tempname = xsdsimple.getName(); |
| if (levelName.compareTo(tempname) == 0) { |
| childFound = true; |
| } |
| } |
| if (!childFound) |
| break; |
| } |
| } |
| token = index; |
| } |
| else if (t == '@') |
| token = index; |
| |
| index++; |
| } |
| // determine if last character is a special character if above is successful |
| if (index == context2.length()) { |
| // looking for parts, attributes or elements? |
| String beginsWith; |
| if ((index-1) == token) |
| beginsWith = EMPTY_STRING; |
| else |
| beginsWith = context2.substring(token+1); |
| |
| if ((context2.charAt(token) == '/') || (context2.charAt(token) == '@')) { |
| if (currXsdType == null) { |
| if (currXsdElem != null) { |
| currXsdType = currXsdElem.getTypeDefinition(); |
| } |
| } |
| if (currXsdType instanceof XSDComplexTypeDefinition) { |
| XSDComplexTypeDefinition xsdcomplex = (XSDComplexTypeDefinition)currXsdType; |
| @SuppressWarnings("rawtypes") |
| Iterator eaIter; |
| if (context2.charAt(token) == '/') |
| eaIter = XSDUtils.getXSDElementsAndAttributes(xsdcomplex).iterator(); |
| else |
| eaIter = XSDUtils.getChildAttributes(xsdcomplex).iterator(); |
| Image img = null; |
| String tempReplName = null; |
| String tempDispName = null; |
| String namespace = null; |
| String nsprefix = null; |
| while (eaIter.hasNext()) { |
| Object tempEA = eaIter.next(); |
| |
| if (tempEA instanceof XSDAttributeDeclaration) { |
| XSDAttributeDeclaration attr = (XSDAttributeDeclaration)tempEA; |
| tempReplName = AT + attr.getName(); |
| tempDispName = attr.getName(); |
| namespace = attr.getTargetNamespace(); |
| if ((namespace != null) && (namespace.length() > 0)) { |
| nsprefix = getNamespacePrefix(currVar, namespace); |
| tempReplName = AT + nsprefix + COLON + attr.getName(); |
| tempDispName = nsprefix + COLON + tempDispName; |
| } |
| img = attrImg; |
| } |
| else if (tempEA instanceof XSDElementDeclaration) { |
| XSDElementDeclaration elem = ((XSDElementDeclaration)tempEA).getResolvedElementDeclaration(); |
| tempReplName = elem.getName(); |
| tempDispName = tempReplName; |
| namespace = elem.getTargetNamespace(); |
| if ((namespace != null) && (namespace.length() > 0)) { |
| nsprefix = getNamespacePrefix(currVar, namespace); |
| tempReplName = nsprefix + COLON + tempDispName; |
| tempDispName = tempReplName; |
| } |
| img = elementImg; |
| } |
| if (tempReplName != null) { |
| if ((beginsWith.length() == 0) || (tempDispName != null && tempDispName.startsWith(beginsWith))) { |
| int replOffset = offset-beginsWith.length(); |
| int replLen = beginsWith.length(); |
| if (context2.charAt(token) == '@') { |
| replOffset--; |
| replLen++; |
| } |
| |
| prop = new CompletionProposal(tempReplName, replOffset, replLen, |
| tempReplName.length(), img, tempDispName + " " , //$NON-NLS-1$ |
| null, null); |
| results.add(prop); |
| } |
| } |
| tempReplName = null; |
| tempDispName = null; |
| } |
| } |
| else if (currXsdType instanceof XSDSimpleTypeDefinition) { |
| XSDSimpleTypeDefinition simple = (XSDSimpleTypeDefinition)currXsdType; |
| // do nothing? |
| } |
| } |
| // search for parts |
| else if (context2.charAt(token) == '.') { |
| if (currMsg != null) { |
| if (currMsg.getParts() != null) { |
| for(Object next : currMsg.getParts().values() ) { |
| Part item = (Part) next; |
| if ((beginsWith.length() == 0) || (item.getName().startsWith(beginsWith))) { |
| prop = new CompletionProposal(item.getName(), offset-beginsWith.length(), beginsWith.length(), |
| item.getName().length(), partImg, item.getName() + " " , //$NON-NLS-1$ |
| null, null); |
| results.add(prop); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| //variables |
| else { |
| for (Variable v : variables) { |
| name = v.getName(); |
| if (name.startsWith(context2)) { |
| prop = new CompletionProposal(DOLLAR + name, offset-context.length(), context.length(), |
| name.length()+1, varImg, name + " " , //$NON-NLS-1$ |
| null, null); |
| results.add(prop); |
| } |
| } |
| } |
| } |
| catch(IllegalArgumentException ex) |
| { |
| results.toArray(EMPTY_COMPLETION_PROPOSALS); |
| } |
| |
| if (results.size() < 1) { |
| return new ICompletionProposal [] { |
| new CompletionProposal(EMPTY_STRING, offset, 0, |
| 0, null, Messages.getString("ExpressionContentAssistProcessor.31"), //$NON-NLS-1$ |
| null, null) }; |
| } |
| |
| return results.toArray(EMPTY_COMPLETION_PROPOSALS); |
| } |
| |
| // simple form of determining if variable is located at offset |
| String startOfVariable(ITextViewer viewer, int offset) { |
| int startPosition = offset-1; |
| char currChar; |
| String context = EMPTY_STRING; |
| IDocument document = viewer.getDocument(); |
| |
| try { |
| while (startPosition >= 0) { |
| currChar = document.getChar(startPosition); |
| |
| if (currChar == '$') |
| return context; |
| |
| if (!(Character.isLetterOrDigit(currChar) || currChar == '/' |
| || currChar == '.' || currChar == '@' || currChar == '_')) |
| return null; |
| |
| context = currChar + context; |
| startPosition--; |
| } |
| } |
| catch (Exception e) { |
| System.out.println(e.toString()); |
| } |
| return null; |
| } |
| |
| // simple form of determing if function is located at offset |
| String startOfFunction(ITextViewer viewer, int offset) { |
| int startPosition = offset-1; |
| char currChar; |
| String context = EMPTY_STRING; |
| IDocument document = viewer.getDocument(); |
| |
| try { |
| while (startPosition >= 0) { |
| if (Character.isWhitespace(currChar = document.getChar(startPosition)) || |
| isReservedOperatorCharacter(currChar) || |
| (currChar == '(') || (currChar == '[')) { |
| if (context.length() > 0) { |
| return context; |
| } |
| return null; |
| } |
| context = currChar + context; |
| startPosition--; |
| } |
| } |
| catch (Exception e) { |
| System.out.println(e.toString()); |
| } |
| return context; |
| } |
| |
| private boolean isLocationPathCharacter(char c) { |
| final String LOCATION_CHARS = "./:@-"; //$NON-NLS-1$ |
| if ((LOCATION_CHARS.indexOf(c) > -1) || (Character.isLetterOrDigit(c) || c == '_')) |
| return true; |
| return false; |
| } |
| |
| final static String RESERVED_OPERATOR_CHARS = "+-*/"; //$NON-NLS-1$ |
| |
| private boolean isReservedOperatorCharacter(char c) { |
| return RESERVED_OPERATOR_CHARS.indexOf(c) > -1; |
| } |
| |
| final static String RESERVED_CLOSING_EXPR_CHARS = ")]"; //$NON-NLS-1$ |
| |
| private boolean isClosingExpressionCharacter(char c) { |
| return (RESERVED_CLOSING_EXPR_CHARS.indexOf(c) > -1); |
| } |
| } |