blob: 2794c5c1ef44737d6eb87162211810381887128a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2003 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.ui.text.java;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jface.preference.IPreferenceStore;
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.jface.text.rules.WordRule;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.ui.text.IColorManager;
import org.eclipse.jdt.ui.text.IJavaColorConstants;
import org.eclipse.jdt.internal.ui.text.AbstractJavaScanner;
import org.eclipse.jdt.internal.ui.text.JavaWhitespaceDetector;
import org.eclipse.jdt.internal.ui.text.JavaWordDetector;
/**
* A Java code scanner.
*/
public final class JavaCodeScanner extends AbstractJavaScanner {
private static final boolean COLOR_RETURN_AS_METHOD_NAME= Boolean.getBoolean("org.eclipse.jdt.internal.ui.text.java.colorReturnAsMethodName"); //$NON-NLS-1$
/**
* Rule to detect java operators.
*
* @since 3.0
*/
protected class OperatorRule implements IRule {
/** Java operators */
private final char[] JAVA_OPERATORS= { ';', '(', ')', '{', '}', '.', '=', '/', '\\', '+', '-', '*', '[', ']', '<', '>', ':', '?', '!', ',', '|', '&', '^', '%', '~'};
/** Token to return for this rule */
private final IToken fToken;
/**
* Creates a new operator rule.
*
* @param token Token to use for this rule
*/
public OperatorRule(IToken token) {
fToken= token;
}
/**
* Is this character an operator character?
*
* @param character Character to determine whether it is an operator character
* @return <code>true</code> iff the character is an operator, <code>false</code> otherwise.
*/
public boolean isOperator(char character) {
for (int index= 0; index < JAVA_OPERATORS.length; index++) {
if (JAVA_OPERATORS[index] == character)
return true;
}
return false;
}
/*
* @see org.eclipse.jface.text.rules.IRule#evaluate(org.eclipse.jface.text.rules.ICharacterScanner)
*/
public IToken evaluate(ICharacterScanner scanner) {
int character= scanner.read();
if (isOperator((char) character)) {
do {
character= scanner.read();
} while (isOperator((char) character));
scanner.unread();
return fToken;
} else {
scanner.unread();
return Token.UNDEFINED;
}
}
}
/**
* Word rule to detect java method names.
*
* @since 3.0
*/
protected class MethodNameRule implements IRule {
/** Token to return for this rule */
private final IToken fToken;
/** Detector to determine the method names */
private final IWordDetector fDetector;
/**
* Creates a new method name rule.
*
* @param detector Detector to detect the method names
* @param token Token to use for this rule
*/
public MethodNameRule(IWordDetector detector, IToken token) {
fDetector= detector;
fToken= token;
}
/*
* @see org.eclipse.jface.text.rules.IRule#evaluate(org.eclipse.jface.text.rules.ICharacterScanner)
*/
public IToken evaluate(ICharacterScanner scanner) {
int count= 1;
IToken token= Token.UNDEFINED;
int character= scanner.read();
final StringBuffer buffer= new StringBuffer(32); // Average word length?
// Scan for valid word start
if (fDetector.isWordStart((char) character)) {
do {
buffer.append((char) character);
character= scanner.read();
++count;
} while (fDetector.isWordPart((char) character));
boolean isKeyword= false;
final String word= buffer.toString();
// Treat "return" as method name
if (COLOR_RETURN_AS_METHOD_NAME && "return".equals(word)) //$NON-NLS-1$
return fToken;
// Check for keywords
for (int index= 0; index < JavaCodeScanner.fgKeywords.length; index++) {
if (JavaCodeScanner.fgKeywords[index].equals(word)) {
isKeyword= true;
break;
}
}
if (!isKeyword) {
// Ignore trailing whitespaces
while (Character.isWhitespace((char) character)) {
character= scanner.read();
++count;
}
// Check for matching parenthesis
if (character == '(') {
scanner.unread();
return fToken;
}
}
}
// Unwind scanner in case of detection failure
for (int index= 0; index < count; index++)
scanner.unread();
return token;
}
}
private static class VersionedWordRule extends WordRule {
private final IToken fDefaultToken;
private final String fVersion;
private final boolean fEnable;
private String fCurrentVersion;
public VersionedWordRule(IWordDetector detector, IToken defaultToken, String version, boolean enable, String currentVersion) {
super(detector);
fDefaultToken= defaultToken;
fVersion= version;
fEnable= enable;
fCurrentVersion= currentVersion;
}
public void setCurrentVersion(String version) {
fCurrentVersion= version;
}
/*
* @see IRule#evaluate
*/
public IToken evaluate(ICharacterScanner scanner) {
IToken token= super.evaluate(scanner);
if (fEnable) {
if (fCurrentVersion.equals(fVersion) || token.isUndefined())
return token;
return fDefaultToken;
} else {
if (fCurrentVersion.equals(fVersion))
return Token.UNDEFINED;
return token;
}
}
}
private static final String SOURCE_VERSION= JavaCore.COMPILER_SOURCE;
private static String[] fgKeywords= {
"abstract", //$NON-NLS-1$
"break", //$NON-NLS-1$
"case", "catch", "class", "const", "continue", //$NON-NLS-5$ //$NON-NLS-4$ //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$
"default", "do", //$NON-NLS-2$ //$NON-NLS-1$
"else", "extends", //$NON-NLS-2$ //$NON-NLS-1$
"final", "finally", "for", //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$
"goto", //$NON-NLS-1$
"if", "implements", "import", "instanceof", "interface", //$NON-NLS-5$ //$NON-NLS-4$ //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$
"native", "new", //$NON-NLS-2$ //$NON-NLS-1$
"package", "private", "protected", "public", //$NON-NLS-4$ //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$
"return", //$NON-NLS-1$
"static", "super", "switch", "synchronized", //$NON-NLS-4$ //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$
"this", "throw", "throws", "transient", "try", //$NON-NLS-5$ //$NON-NLS-4$ //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$
"volatile", //$NON-NLS-1$
"while" //$NON-NLS-1$
};
private static String[] fgNewKeywords= { "assert" }; //$NON-NLS-1$
private static String[] fgTypes= { "void", "boolean", "char", "byte", "short", "strictfp", "int", "long", "float", "double" }; //$NON-NLS-1$ //$NON-NLS-5$ //$NON-NLS-7$ //$NON-NLS-6$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-2$
private static String[] fgConstants= { "false", "null", "true" }; //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-1$
private static String[] fgTokenProperties= {
IJavaColorConstants.JAVA_KEYWORD,
IJavaColorConstants.JAVA_STRING,
IJavaColorConstants.JAVA_DEFAULT,
IJavaColorConstants.JAVA_METHOD_NAME,
IJavaColorConstants.JAVA_OPERATOR
};
private VersionedWordRule fVersionedWordRule;
/**
* Creates a Java code scanner
*/
public JavaCodeScanner(IColorManager manager, IPreferenceStore store) {
super(manager, store);
initialize();
}
/*
* @see AbstractJavaScanner#getTokenProperties()
*/
protected String[] getTokenProperties() {
return fgTokenProperties;
}
/*
* @see AbstractJavaScanner#createRules()
*/
protected List createRules() {
List rules= new ArrayList();
// Add rule for character constants.
Token token= getToken(IJavaColorConstants.JAVA_STRING);
rules.add(new SingleLineRule("'", "'", token, '\\')); //$NON-NLS-2$ //$NON-NLS-1$
// Add generic whitespace rule.
rules.add(new WhitespaceRule(new JavaWhitespaceDetector()));
// Add word rule for new keywords, 4077
Object version= null;
try {
version= JavaCore.getOptions().get(SOURCE_VERSION);
} catch (NullPointerException x) {
// plugin not initialized - happens in test code
}
if (version instanceof String) {
token= getToken(IJavaColorConstants.JAVA_DEFAULT);
fVersionedWordRule= new VersionedWordRule(new JavaWordDetector(), token, "1.4", true, (String) version); //$NON-NLS-1$
token= getToken(IJavaColorConstants.JAVA_KEYWORD);
for (int i=0; i<fgNewKeywords.length; i++)
fVersionedWordRule.addWord(fgNewKeywords[i], token);
rules.add(fVersionedWordRule);
}
// Add rule for operators and brackets
token= getToken(IJavaColorConstants.JAVA_OPERATOR);
rules.add(new OperatorRule(token));
// Add word rule for method names.
token= getToken(IJavaColorConstants.JAVA_METHOD_NAME);
rules.add(new MethodNameRule(new JavaWordDetector(), token));
// Add word rule for keywords, types, and constants.
token= getToken(IJavaColorConstants.JAVA_DEFAULT);
WordRule wordRule= new WordRule(new JavaWordDetector(), token);
token= getToken(IJavaColorConstants.JAVA_KEYWORD);
for (int i=0; i<fgKeywords.length; i++)
wordRule.addWord(fgKeywords[i], token);
for (int i=0; i<fgTypes.length; i++)
wordRule.addWord(fgTypes[i], token);
for (int i=0; i<fgConstants.length; i++)
wordRule.addWord(fgConstants[i], token);
rules.add(wordRule);
setDefaultReturnToken(getToken(IJavaColorConstants.JAVA_DEFAULT));
return rules;
}
/*
* @see RuleBasedScanner#setRules(IRule[])
*/
public void setRules(IRule[] rules) {
int i;
for (i= 0; i < rules.length; i++)
if (rules[i].equals(fVersionedWordRule))
break;
// not found - invalidate fVersionedWordRule
if (i == rules.length)
fVersionedWordRule= null;
super.setRules(rules);
}
/*
* @see AbstractJavaScanner#affectsBehavior(PropertyChangeEvent)
*/
public boolean affectsBehavior(PropertyChangeEvent event) {
return event.getProperty().equals(SOURCE_VERSION) || super.affectsBehavior(event);
}
/*
* @see AbstractJavaScanner#adaptToPreferenceChange(PropertyChangeEvent)
*/
public void adaptToPreferenceChange(PropertyChangeEvent event) {
if (event.getProperty().equals(SOURCE_VERSION)) {
Object value= event.getNewValue();
if (value instanceof String) {
String s= (String) value;
if (fVersionedWordRule != null)
fVersionedWordRule.setCurrentVersion(s);
}
} else if (super.affectsBehavior(event)) {
super.adaptToPreferenceChange(event);
}
}
}