1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-06-08 18:26:01 +02:00

Bug 363406: extensible semantic highlighting

- introduced extension point to allow plugins to add new semantic
highlighters
- see bug for more details

Change-Id: Ic019e8a3c483fcfc42344fe4ef2139cc933c0301
Reviewed-on: https://git.eclipse.org/r/10074
Reviewed-by: Doug Schaefer <dschaefer@qnx.com>
IP-Clean: Doug Schaefer <dschaefer@qnx.com>
Tested-by: Doug Schaefer <dschaefer@qnx.com>
This commit is contained in:
Andrew Eidsness 2013-01-31 11:41:44 -05:00 committed by Doug Schaefer
parent d960fff7dd
commit 2bc9035f8c
9 changed files with 714 additions and 56 deletions

View file

@ -644,4 +644,6 @@ RefreshExclusionContributorExtensionPoint = Refresh Exclusion Contributor
newProjectWizard.name = C/C++ Project (prototype) newProjectWizard.name = C/C++ Project (prototype)
projectTypePages = Project Type Pages projectTypePages = Project Type Pages
semanticHighlightingExtensionPoint = Semantic Highlighting Extension Point
UserSettingEntries.name = CDT User Setting Entries UserSettingEntries.name = CDT User Setting Entries

View file

@ -29,6 +29,7 @@
<extension-point id="LanguageSettingsProviderAssociation" name="%LanguageSettingsProviderAssociationExtensionPoint" schema="schema/LanguageSettingsProviderAssociation.exsd"/> <extension-point id="LanguageSettingsProviderAssociation" name="%LanguageSettingsProviderAssociationExtensionPoint" schema="schema/LanguageSettingsProviderAssociation.exsd"/>
<extension-point id="RefreshExclusionContributor" name="%RefreshExclusionContributorExtensionPoint" schema="schema/RefreshExclusionContributor.exsd"/> <extension-point id="RefreshExclusionContributor" name="%RefreshExclusionContributorExtensionPoint" schema="schema/RefreshExclusionContributor.exsd"/>
<extension-point id="projectTypePages" name="%projectTypePages" schema="schema/projectTypePages.exsd"/> <extension-point id="projectTypePages" name="%projectTypePages" schema="schema/projectTypePages.exsd"/>
<extension-point id="semanticHighlighting" name="%semanticHighlightingExtensionPoint" schema="schema/semanticHighlighting.exsd"/>
<extension <extension
point="org.eclipse.core.runtime.adapters"> point="org.eclipse.core.runtime.adapters">

View file

@ -0,0 +1,245 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Schema file written by PDE -->
<schema targetNamespace="org.eclipse.cdt.ui" xmlns="http://www.w3.org/2001/XMLSchema">
<annotation>
<appInfo>
<meta.schema plugin="org.eclipse.cdt.ui" id="semanticHighligher" name="Semantic Highlighting"/>
</appInfo>
<documentation>
This extension point allows extensions to contribute to the semantic highlighting.
&lt;p&gt;
Extensions specify the priority of the highlighting, which determines the order in which the highlighting is invoked.
&lt;/p&gt;
&lt;p&gt;
This extension point supports the &lt;code&gt;enablement&lt;/code&gt; tag. Properties to test on are:
&lt;dl&gt;
&lt;li&gt;projectNatures: type Collection; all project natures of the current project&lt;/li&gt;
&lt;li&gt;languageId: type String; the result if ILanguage.getId on the token&apos;s ITranslationUnit&lt;/li&gt;
&lt;/dl&gt;
&lt;/p&gt;
&lt;p&gt;
Contributed highlightings will be visible in the Code tree of the &apos;C/C++ - Editor - Syntax Colouring&apos; preference page.
&lt;/p&gt;
</documentation>
</annotation>
<include schemaLocation="schema://org.eclipse.core.expressions/schema/expressionLanguage.exsd"/>
<element name="extension">
<annotation>
<appInfo>
<meta.element />
</appInfo>
</annotation>
<complexType>
<sequence>
<element ref="semanticHighlighting" minOccurs="1" maxOccurs="unbounded"/>
</sequence>
<attribute name="point" type="string" use="required">
<annotation>
<documentation>
a fully qualified identifier of the target extension point
</documentation>
</annotation>
</attribute>
<attribute name="id" type="string">
<annotation>
<documentation>
an optional identifier of the extension instance
</documentation>
</annotation>
</attribute>
<attribute name="name" type="string">
<annotation>
<documentation>
an optional name of the extension instance
</documentation>
<appInfo>
<meta.attribute translatable="true"/>
</appInfo>
</annotation>
</attribute>
</complexType>
</element>
<element name="semanticHighlighting">
<complexType>
<sequence>
<element ref="enablement" minOccurs="0" maxOccurs="1"/>
</sequence>
<attribute name="id" type="string" use="required">
<annotation>
<documentation>
a unique identifier for the Quick Fix processor
</documentation>
</annotation>
</attribute>
<attribute name="name" type="string">
<annotation>
<documentation>
a localized name of the Quick Fix processor
</documentation>
<appInfo>
<meta.attribute translatable="true"/>
</appInfo>
</annotation>
</attribute>
<attribute name="class" type="string" use="required">
<annotation>
<documentation>
The name of the class that implements this Semantic Highlighting. The
class must be public and implement
&lt;samp&gt;org.eclipse.cdt.ui.text.ISemanticHighlighter&lt;/samp&gt;
with a public 0-argument constructor.
</documentation>
<appInfo>
<meta.attribute kind="java" basedOn=":org.eclipse.cdt.ui.text.ISemanticHighlighting"/>
</appInfo>
</annotation>
</attribute>
<attribute name="priority" type="string" use="required">
<annotation>
<documentation>
The priority determines the order in which highlightings are given the opportunity to highlight a token. Lower values are more important.
The priorities of the built-in highlightings are available in org.eclipse.cdt.internal.ui.editor.SemanticHighlightings.loadBuiltInSemanticHighlightings.
</documentation>
</annotation>
</attribute>
<attribute name="preferenceKey" type="string" use="required">
<annotation>
<documentation>
A key to uniquely identify the highlighting&apos;s settings in the preference store.
</documentation>
</annotation>
</attribute>
<attribute name="displayName" type="string" use="required">
<annotation>
<documentation>
The name that is displayed for the highlighter in the Preferences window.
</documentation>
<appInfo>
<meta.attribute translatable="true"/>
</appInfo>
</annotation>
</attribute>
<attribute name="defaultTextColor" type="string">
<annotation>
<documentation>
The default text color of the contributed highlighting. The value must be the integer RGB values (0-255) separated by commas. E.g., &quot;127,0,85&quot;. Defaults to &quot;0,0,0&quot; (black).
</documentation>
</annotation>
</attribute>
<attribute name="defaultBold" type="boolean">
<annotation>
<documentation>
false by default
</documentation>
</annotation>
</attribute>
<attribute name="defaultItalic" type="boolean">
<annotation>
<documentation>
false by default
</documentation>
</annotation>
</attribute>
<attribute name="defaultStrikethrough" type="boolean">
<annotation>
<documentation>
false by default
</documentation>
</annotation>
</attribute>
<attribute name="defaultUnderline" type="boolean">
<annotation>
<documentation>
false by default
</documentation>
</annotation>
</attribute>
<attribute name="defaultEnabled" type="boolean">
<annotation>
<documentation>
false by default
</documentation>
</annotation>
</attribute>
</complexType>
</element>
<annotation>
<appInfo>
<meta.section type="since"/>
</appInfo>
<documentation>
8.2
</documentation>
</annotation>
<annotation>
<appInfo>
<meta.section type="examples"/>
</appInfo>
<documentation>
The following is an example of a Semantic Highligher contribution:
&lt;p&gt;
&lt;pre&gt;
&lt;extension
point=&quot;org.eclipse.cdt.ui.semanticHighlighting&quot;
name=&quot;%extensionName&quot;
id=&quot;com.example.ui.semanticHighlightings&quot;&gt;
&lt;semanticHighlighting
id=&quot;com.example.ui.keywordHighlighting&quot;
priority=&quot;5&quot;
class=&quot;com.example.internal.ui.ExampleHighlighting&quot;
preferenceKey=&quot;example-keywords&quot;
displayName=&quot;%exampleHighlighting.displayName&quot;
defaultTextColor=&quot;127,0,85&quot;
defaultBold=&quot;true&quot;
defaultEnabled=&quot;true&quot;&gt;
&lt;enablement&gt;
&lt;with variable=&quot;projectNatures&quot;&gt;
&lt;iterate operator=&quot;or&quot;&gt;
&lt;equals value=&quot;org.eclipse.cdt.core.ccnature&quot;/&gt;
&lt;/iterate&gt;
&lt;/with&gt;
&lt;with variable=&quot;languageId&quot;&gt;
&lt;or&gt;
&lt;equals value=&quot;org.eclipse.cdt.core.g++&quot;/&gt;
&lt;equals value=&quot;org.eclipse.cdt.core.gcc&quot;/&gt;
&lt;/or&gt;
&lt;/with&gt;
&lt;/enablement&gt;
&lt;/semanticHighlighting&gt;
&lt;/extension&gt;
&lt;/pre&gt;
&lt;/p&gt;
</documentation>
</annotation>
<annotation>
<appInfo>
<meta.section type="apiInfo"/>
</appInfo>
<documentation>
The contributed class must implement &lt;code&gt;org.eclipse.cdt.ui.text.ISemanticHighlighter&lt;/code&gt;
</documentation>
</annotation>
<annotation>
<appInfo>
<meta.section type="copyright"/>
</appInfo>
<documentation>
Copyright (c) 2013 QNX Software Systems 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
</documentation>
</annotation>
</schema>

View file

@ -0,0 +1,272 @@
/*
* Copyright (c) 2013 QNX Software Systems 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
*/
package org.eclipse.cdt.internal.ui.editor;
import java.util.Arrays;
import org.eclipse.core.expressions.EvaluationContext;
import org.eclipse.core.expressions.EvaluationResult;
import org.eclipse.core.expressions.Expression;
import org.eclipse.core.expressions.ExpressionConverter;
import org.eclipse.core.expressions.ExpressionTagNames;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.jface.resource.DataFormatException;
import org.eclipse.jface.resource.StringConverter;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.core.model.ILanguage;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.ui.CUIPlugin;
import org.eclipse.cdt.ui.text.ISemanticHighlighter;
import org.eclipse.cdt.ui.text.ISemanticToken;
public class ContributedSemanticHighlighting extends SemanticHighlighting {
/**
* The configuration element needs to be cached until the class is instantiated. Instantiation is deferred
* to avoid loading the contributing plugin when the highlighter is not actually needed.
*/
private IConfigurationElement configurationElement;
private Boolean fStatus = null;
private ISemanticHighlighter semanticHighlighter;
private final Expression enablementExpression;
private final int priority;
private final String id;
private final String preferenceKey;
private final String displayName;
private final RGB defaultTextColor;
private final boolean defaultBold;
private final boolean defaultItalic;
private final boolean defaultStrikethrough;
private final boolean defaultUnderline;
private final boolean defaultEnabled;
private static final String Attr_Class = "class"; //$NON-NLS-1$
private static final String Attr_Priority = "priority"; //$NON-NLS-1$
private static final String Attr_PrefKey = "preferenceKey"; //$NON-NLS-1$
private static final String Attr_DisplayName = "displayName"; //$NON-NLS-1$
private static final String Attr_DefaultTextColor = "defaultTextColor"; //$NON-NLS-1$
private static final String Attr_DefaultBold = "defaultBold"; //$NON-NLS-1$
private static final String Attr_DefaultItalic = "defaultItalic"; //$NON-NLS-1$
private static final String Attr_DefaultStrikethrough = "defaultStrikethrough"; //$NON-NLS-1$
private static final String Attr_DefaultUnderline = "defaultUnderline"; //$NON-NLS-1$
private static final String Attr_DefaultEnabled = "defaultEnabled"; //$NON-NLS-1$
private static final String Var_projectNature = "projectNatures"; //$NON-NLS-1$
private static final String Var_languageId = "languageId"; //$NON-NLS-1$
private static final int Default_Priority = 1000;
public ContributedSemanticHighlighting(IConfigurationElement element) {
configurationElement = element;
// required
id = element.getDeclaringExtension().getNamespaceIdentifier() + '.'
+ element.getDeclaringExtension().getSimpleIdentifier();
int pri = Default_Priority;
String priStr = element.getAttribute(Attr_Priority);
if (priStr != null)
try {
pri = Integer.parseInt(priStr);
} catch (NumberFormatException e) {
CUIPlugin.log("Error in priority attribute of " + id + " was " + priStr, e); //$NON-NLS-1$ //$NON-NLS-2$
}
priority = pri;
Expression expr = null;
IConfigurationElement[] children = element.getChildren(ExpressionTagNames.ENABLEMENT);
switch (children.length) {
case 0:
fStatus = Boolean.TRUE;
break;
case 1:
try {
ExpressionConverter parser = ExpressionConverter.getDefault();
expr = parser.perform(children[0]);
} catch (CoreException e) {
CUIPlugin.log("Error in enablement expression of " + id, e); //$NON-NLS-1$
}
break;
default:
CUIPlugin.logError("Too many enablement expressions for " + id); //$NON-NLS-1$
fStatus = Boolean.FALSE;
break;
}
enablementExpression = expr;
preferenceKey = element.getAttribute(Attr_PrefKey);
displayName = element.getAttribute(Attr_DisplayName);
// optional
defaultTextColor = getRGBAttribute(element, id, Attr_DefaultTextColor);
defaultBold = Boolean.parseBoolean(element.getAttribute(Attr_DefaultBold));
defaultItalic = Boolean.parseBoolean(element.getAttribute(Attr_DefaultItalic));
defaultStrikethrough = Boolean.parseBoolean(element.getAttribute(Attr_DefaultStrikethrough));
defaultUnderline = Boolean.parseBoolean(element.getAttribute(Attr_DefaultUnderline));
defaultEnabled = Boolean.parseBoolean(element.getAttribute(Attr_DefaultEnabled));
}
public String getId() {
return id;
}
public int getPriority() {
return priority;
}
private static RGB getRGBAttribute(IConfigurationElement element, String extensionId, String key) {
String val = element.getAttribute(key);
if (val != null)
try {
return StringConverter.asRGB(val);
} catch (DataFormatException e) {
CUIPlugin
.log("Error in " + Attr_DefaultTextColor + " attribute of " + extensionId + ' ' + val + " is not a RGB value", e); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
// black by default
return new RGB(0, 0, 0);
}
private ISemanticHighlighter createSemanticHighlighter() {
// only one try at creating the class
if (configurationElement == null)
return null;
IConfigurationElement element = configurationElement;
configurationElement = null;
try {
return (ISemanticHighlighter) element.createExecutableExtension(Attr_Class);
} catch (CoreException e) {
CUIPlugin.log("Error in class attribute of " + id, e); //$NON-NLS-1$
}
return null;
}
@Override
public String getPreferenceKey() {
return preferenceKey;
}
@Override
public RGB getDefaultDefaultTextColor() {
return defaultTextColor;
}
@Override
public boolean isBoldByDefault() {
return defaultBold;
}
@Override
public boolean isItalicByDefault() {
return defaultItalic;
}
@Override
public boolean isStrikethroughByDefault() {
return defaultStrikethrough;
}
@Override
public boolean isUnderlineByDefault() {
return defaultUnderline;
}
@Override
public boolean isEnabledByDefault() {
return defaultEnabled;
}
@Override
public String getDisplayName() {
return displayName;
}
@Override
public boolean requiresImplicitNames() {
return false;
}
private boolean matches(ITranslationUnit tu) {
// if the enablement expression is missing or structurally invalid, then return immediately
if (fStatus != null)
return fStatus.booleanValue();
if (enablementExpression != null)
try {
EvaluationContext evalContext = new EvaluationContext(null, tu);
ICProject cProject = tu.getCProject();
String[] natures = cProject.getProject().getDescription().getNatureIds();
evalContext.addVariable(Var_projectNature, Arrays.asList(natures));
ILanguage language = tu.getLanguage();
if( language != null )
evalContext.addVariable(Var_languageId, language.getId());
return enablementExpression.evaluate(evalContext) == EvaluationResult.TRUE;
} catch (CoreException e) {
CUIPlugin.log("Error while evaluating enablement expression for " + id, e); //$NON-NLS-1$
}
fStatus = Boolean.FALSE;
return false;
}
/**
* Return the contributed ISemanticHighlighter if the receiver should be applied to the specified TU and
* null otherwise.
*/
private ISemanticHighlighter getSemanticHighlighter(ITranslationUnit tu) {
if (!matches(tu))
return null;
if (semanticHighlighter == null)
synchronized (this) {
if (semanticHighlighter == null) {
semanticHighlighter = createSemanticHighlighter();
}
}
return semanticHighlighter;
}
@Override
public boolean consumes(ISemanticToken token) {
if (token == null)
return false;
IASTTranslationUnit astTU = token.getRoot();
if (astTU == null)
return false;
ITranslationUnit tu = astTU.getOriginatingTranslationUnit();
if (tu == null)
return false;
ISemanticHighlighter highlighter = getSemanticHighlighter(tu);
if (highlighter == null)
return false;
return highlighter.consumes(token);
}
}

View file

@ -17,6 +17,7 @@ import org.eclipse.swt.graphics.RGB;
import org.eclipse.ui.PlatformUI; import org.eclipse.ui.PlatformUI;
import org.eclipse.cdt.ui.CUIPlugin; import org.eclipse.cdt.ui.CUIPlugin;
import org.eclipse.cdt.ui.text.ISemanticToken;
/** /**
* Semantic highlighting. * Semantic highlighting.
@ -100,7 +101,7 @@ public abstract class SemanticHighlighting {
* @param token the semantic token for a {@link org.eclipse.cdt.core.dom.ast.IASTName} * @param token the semantic token for a {@link org.eclipse.cdt.core.dom.ast.IASTName}
* @return <code>true</code> iff the semantic highlighting consumes the semantic token * @return <code>true</code> iff the semantic highlighting consumes the semantic token
*/ */
public abstract boolean consumes(SemanticToken token); public abstract boolean consumes(ISemanticToken token);
private String getThemeColorKey() { private String getThemeColorKey() {
return CUIPlugin.PLUGIN_ID + "." + getPreferenceKey() + "Highlighting"; //$NON-NLS-1$//$NON-NLS-2$ return CUIPlugin.PLUGIN_ID + "." + getPreferenceKey() + "Highlighting"; //$NON-NLS-1$//$NON-NLS-2$

View file

@ -11,7 +11,11 @@
*******************************************************************************/ *******************************************************************************/
package org.eclipse.cdt.internal.ui.editor; package org.eclipse.cdt.internal.ui.editor;
import java.util.Map;
import java.util.TreeMap;
import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferenceConverter; import org.eclipse.jface.preference.PreferenceConverter;
@ -56,6 +60,7 @@ import org.eclipse.cdt.core.index.IIndexFile;
import org.eclipse.cdt.core.index.IIndexName; import org.eclipse.cdt.core.index.IIndexName;
import org.eclipse.cdt.ui.CUIPlugin; import org.eclipse.cdt.ui.CUIPlugin;
import org.eclipse.cdt.ui.PreferenceConstants; import org.eclipse.cdt.ui.PreferenceConstants;
import org.eclipse.cdt.ui.text.ISemanticToken;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding;
import org.eclipse.cdt.internal.core.dom.parser.cpp.OverloadableOperator; import org.eclipse.cdt.internal.core.dom.parser.cpp.OverloadableOperator;
@ -228,7 +233,7 @@ public class SemanticHighlightings {
} }
@Override @Override
public boolean consumes(SemanticToken token) { public boolean consumes(ISemanticToken token) {
IASTNode node= token.getNode(); IASTNode node= token.getNode();
if (node instanceof IASTName) { if (node instanceof IASTName) {
IASTName name= (IASTName) node; IASTName name= (IASTName) node;
@ -279,7 +284,7 @@ public class SemanticHighlightings {
} }
@Override @Override
public boolean consumes(SemanticToken token) { public boolean consumes(ISemanticToken token) {
IASTNode node= token.getNode(); IASTNode node= token.getNode();
if (node instanceof IASTName) { if (node instanceof IASTName) {
IASTName name= (IASTName) node; IASTName name= (IASTName) node;
@ -330,7 +335,7 @@ public class SemanticHighlightings {
} }
@Override @Override
public boolean consumes(SemanticToken token) { public boolean consumes(ISemanticToken token) {
IASTNode node= token.getNode(); IASTNode node= token.getNode();
if (node instanceof IASTImplicitName) if (node instanceof IASTImplicitName)
return false; return false;
@ -407,7 +412,7 @@ public class SemanticHighlightings {
} }
@Override @Override
public boolean consumes(SemanticToken token) { public boolean consumes(ISemanticToken token) {
IASTNode node= token.getNode(); IASTNode node= token.getNode();
if (node instanceof IASTName) { if (node instanceof IASTName) {
IASTName name= (IASTName) node; IASTName name= (IASTName) node;
@ -461,7 +466,7 @@ public class SemanticHighlightings {
} }
@Override @Override
public boolean consumes(SemanticToken token) { public boolean consumes(ISemanticToken token) {
IASTNode node= token.getNode(); IASTNode node= token.getNode();
if (node instanceof IASTImplicitName) if (node instanceof IASTImplicitName)
return false; return false;
@ -514,7 +519,7 @@ public class SemanticHighlightings {
} }
@Override @Override
public boolean consumes(SemanticToken token) { public boolean consumes(ISemanticToken token) {
IASTNode node= token.getNode(); IASTNode node= token.getNode();
if (node instanceof IASTImplicitName) if (node instanceof IASTImplicitName)
return false; return false;
@ -585,7 +590,7 @@ public class SemanticHighlightings {
} }
@Override @Override
public boolean consumes(SemanticToken token) { public boolean consumes(ISemanticToken token) {
IASTNode node= token.getNode(); IASTNode node= token.getNode();
if (node instanceof IASTImplicitName) if (node instanceof IASTImplicitName)
return false; return false;
@ -638,7 +643,7 @@ public class SemanticHighlightings {
} }
@Override @Override
public boolean consumes(SemanticToken token) { public boolean consumes(ISemanticToken token) {
IASTNode node= token.getNode(); IASTNode node= token.getNode();
if (node instanceof IASTName) { if (node instanceof IASTName) {
IASTName name= (IASTName) node; IASTName name= (IASTName) node;
@ -698,7 +703,7 @@ public class SemanticHighlightings {
} }
@Override @Override
public boolean consumes(SemanticToken token) { public boolean consumes(ISemanticToken token) {
IASTNode node= token.getNode(); IASTNode node= token.getNode();
if (node instanceof IASTName) { if (node instanceof IASTName) {
IASTName name= (IASTName) node; IASTName name= (IASTName) node;
@ -774,7 +779,7 @@ public class SemanticHighlightings {
} }
@Override @Override
public boolean consumes(SemanticToken token) { public boolean consumes(ISemanticToken token) {
IASTNode node= token.getNode(); IASTNode node= token.getNode();
if (node instanceof IASTName) { if (node instanceof IASTName) {
IASTName name= (IASTName) node; IASTName name= (IASTName) node;
@ -836,7 +841,7 @@ public class SemanticHighlightings {
} }
@Override @Override
public boolean consumes(SemanticToken token) { public boolean consumes(ISemanticToken token) {
IBinding binding= token.getBinding(); IBinding binding= token.getBinding();
if (binding instanceof IParameter) { if (binding instanceof IParameter) {
return true; return true;
@ -880,7 +885,7 @@ public class SemanticHighlightings {
} }
@Override @Override
public boolean consumes(SemanticToken token) { public boolean consumes(ISemanticToken token) {
IASTNode node= token.getNode(); IASTNode node= token.getNode();
if (node instanceof IASTName) { if (node instanceof IASTName) {
IBinding binding= token.getBinding(); IBinding binding= token.getBinding();
@ -927,7 +932,7 @@ public class SemanticHighlightings {
} }
@Override @Override
public boolean consumes(SemanticToken token) { public boolean consumes(ISemanticToken token) {
IASTNode node= token.getNode(); IASTNode node= token.getNode();
if (node instanceof ICPPASTQualifiedName || node instanceof ICPPASTTemplateId) { if (node instanceof ICPPASTQualifiedName || node instanceof ICPPASTTemplateId) {
return false; return false;
@ -977,7 +982,7 @@ public class SemanticHighlightings {
} }
@Override @Override
public boolean consumes(SemanticToken token) { public boolean consumes(ISemanticToken token) {
IASTNode node= token.getNode(); IASTNode node= token.getNode();
if (node instanceof IASTName) { if (node instanceof IASTName) {
IBinding binding= token.getBinding(); IBinding binding= token.getBinding();
@ -1024,7 +1029,7 @@ public class SemanticHighlightings {
} }
@Override @Override
public boolean consumes(SemanticToken token) { public boolean consumes(ISemanticToken token) {
IBinding binding= token.getBinding(); IBinding binding= token.getBinding();
if (binding instanceof IMacroBinding) { if (binding instanceof IMacroBinding) {
IASTName name= (IASTName)token.getNode(); IASTName name= (IASTName)token.getNode();
@ -1071,7 +1076,7 @@ public class SemanticHighlightings {
} }
@Override @Override
public boolean consumes(SemanticToken token) { public boolean consumes(ISemanticToken token) {
IBinding binding= token.getBinding(); IBinding binding= token.getBinding();
if (binding instanceof IMacroBinding) { if (binding instanceof IMacroBinding) {
IASTName name= (IASTName)token.getNode(); IASTName name= (IASTName)token.getNode();
@ -1118,7 +1123,7 @@ public class SemanticHighlightings {
} }
@Override @Override
public boolean consumes(SemanticToken token) { public boolean consumes(ISemanticToken token) {
IASTNode node= token.getNode(); IASTNode node= token.getNode();
if (node instanceof IASTName) { if (node instanceof IASTName) {
IASTName name= (IASTName) node; IASTName name= (IASTName) node;
@ -1169,7 +1174,7 @@ public class SemanticHighlightings {
} }
@Override @Override
public boolean consumes(SemanticToken token) { public boolean consumes(ISemanticToken token) {
IBinding binding= token.getBinding(); IBinding binding= token.getBinding();
if (binding instanceof ICPPNamespace) { if (binding instanceof ICPPNamespace) {
return true; return true;
@ -1213,7 +1218,7 @@ public class SemanticHighlightings {
} }
@Override @Override
public boolean consumes(SemanticToken token) { public boolean consumes(ISemanticToken token) {
IBinding binding= token.getBinding(); IBinding binding= token.getBinding();
if (binding instanceof ILabel) { if (binding instanceof ILabel) {
return true; return true;
@ -1257,7 +1262,7 @@ public class SemanticHighlightings {
} }
@Override @Override
public boolean consumes(SemanticToken token) { public boolean consumes(ISemanticToken token) {
IASTNode node= token.getNode(); IASTNode node= token.getNode();
if (node instanceof IASTName) { if (node instanceof IASTName) {
IASTName name= (IASTName) node; IASTName name= (IASTName) node;
@ -1313,7 +1318,7 @@ public class SemanticHighlightings {
} }
@Override @Override
public boolean consumes(SemanticToken token) { public boolean consumes(ISemanticToken token) {
IASTNode node= token.getNode(); IASTNode node= token.getNode();
if (node.getTranslationUnit().isBasedOnIncompleteIndex()) { if (node.getTranslationUnit().isBasedOnIncompleteIndex()) {
// Do not highlight problems is the AST is unreliable. // Do not highlight problems is the AST is unreliable.
@ -1370,7 +1375,7 @@ public class SemanticHighlightings {
} }
@Override @Override
public boolean consumes(SemanticToken token) { public boolean consumes(ISemanticToken token) {
IASTNode node= token.getNode(); IASTNode node= token.getNode();
if (node instanceof IASTName) { if (node instanceof IASTName) {
IASTName name= (IASTName) node; IASTName name= (IASTName) node;
@ -1459,7 +1464,7 @@ public class SemanticHighlightings {
} }
@Override @Override
public boolean consumes(SemanticToken token) { public boolean consumes(ISemanticToken token) {
IASTNode node = token.getNode(); IASTNode node = token.getNode();
// So far we only have implicit names for overloaded operators and destructors, // So far we only have implicit names for overloaded operators and destructors,
// so this works. // so this works.
@ -1545,36 +1550,106 @@ public class SemanticHighlightings {
return PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_PREFIX + semanticHighlighting.getPreferenceKey() + PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_ENABLED_SUFFIX; return PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_PREFIX + semanticHighlighting.getPreferenceKey() + PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_ENABLED_SUFFIX;
} }
private static class Key implements Comparable<Key> {
public final int priority;
public final String id;
public Key(int priority) {
this(priority, null);
}
public Key(int priority, String id) {
this.priority = priority;
this.id = id;
}
@Override
public int compareTo(Key o) {
if (priority < o.priority)
return -1;
if (o.priority < priority)
return 1;
if (id == null)
return o.id == null ? 0 : -1;
return o.id == null ? 1 : id.compareTo(o.id);
}
@Override
public String toString() {
StringBuilder str = new StringBuilder();
str.append(priority);
if (id != null) {
str.append(' ');
str.append(id);
}
return str.toString();
}
}
private static void loadBuiltInSemanticHighlightings(Map<Key, SemanticHighlighting> highlightings) {
highlightings.put(new Key(10), new MacroReferenceHighlighting()); // before all others!
highlightings.put(new Key(20), new ProblemHighlighting());
highlightings.put(new Key(30), new ExternalSDKHighlighting());
highlightings.put(new Key(40), new ClassHighlighting());
highlightings.put(new Key(50), new StaticFieldHighlighting());
highlightings.put(new Key(60), new FieldHighlighting()); // after all other fields
highlightings.put(new Key(70), new MethodDeclarationHighlighting());
highlightings.put(new Key(80), new StaticMethodInvocationHighlighting());
highlightings.put(new Key(90), new ParameterVariableHighlighting()); // before local variables
highlightings.put(new Key(100), new LocalVariableDeclarationHighlighting());
highlightings.put(new Key(110), new LocalVariableHighlighting());
highlightings.put(new Key(120), new GlobalVariableHighlighting());
highlightings.put(new Key(130), new TemplateParameterHighlighting()); // before template arguments!
highlightings.put(new Key(140), new OverloadedOperatorHighlighting()); // before both method and function
highlightings.put(new Key(150), new MethodHighlighting()); // before types to get ctors
highlightings.put(new Key(160), new EnumHighlighting());
highlightings.put(new Key(170), new MacroDefinitionHighlighting());
highlightings.put(new Key(180), new FunctionDeclarationHighlighting());
highlightings.put(new Key(190), new FunctionHighlighting());
highlightings.put(new Key(200), new TypedefHighlighting());
highlightings.put(new Key(210), new NamespaceHighlighting());
highlightings.put(new Key(220), new LabelHighlighting());
highlightings.put(new Key(230), new EnumeratorHighlighting());
}
private static final String ExtensionPoint = "semanticHighlighting"; //$NON-NLS-1$
private static SemanticHighlighting[] loadSemanticHighlightings() {
Map<Key, SemanticHighlighting> highlightings = new TreeMap<SemanticHighlightings.Key, SemanticHighlighting>();
// load the built-in highlightings
loadBuiltInSemanticHighlightings(highlightings);
// load the extensions
IConfigurationElement[] elements = Platform.getExtensionRegistry().getConfigurationElementsFor(
CUIPlugin.getPluginId(), ExtensionPoint);
for (IConfigurationElement element : elements) {
ContributedSemanticHighlighting contributedHighlighting = new ContributedSemanticHighlighting(
element);
Key key = new Key(contributedHighlighting.getPriority(), contributedHighlighting.getId());
highlightings.put(key, contributedHighlighting);
}
return highlightings.values().toArray(new SemanticHighlighting[highlightings.size()]);
}
private static final Object SemanticHighlightingsLock = new Object();
/** /**
* @return The semantic highlightings, the order defines the precedence of matches, the first match wins. * @return The semantic highlightings, the order defines the precedence of matches, the first match wins.
*/ */
public static SemanticHighlighting[] getSemanticHighlightings() { public static SemanticHighlighting[] getSemanticHighlightings() {
if (fgSemanticHighlightings == null) if (fgSemanticHighlightings == null)
fgSemanticHighlightings= new SemanticHighlighting[] { synchronized (SemanticHighlightingsLock) {
new MacroReferenceHighlighting(), // before all others! if (fgSemanticHighlightings == null)
new ProblemHighlighting(), fgSemanticHighlightings = loadSemanticHighlightings();
new ExternalSDKHighlighting(), }
new ClassHighlighting(),
new StaticFieldHighlighting(),
new FieldHighlighting(), // after all other fields
new MethodDeclarationHighlighting(),
new StaticMethodInvocationHighlighting(),
new ParameterVariableHighlighting(), // before local variables
new LocalVariableDeclarationHighlighting(),
new LocalVariableHighlighting(),
new GlobalVariableHighlighting(),
new TemplateParameterHighlighting(), // before template arguments!
new OverloadedOperatorHighlighting(), // before both method and function
new MethodHighlighting(), // before types to get ctors
new EnumHighlighting(),
new MacroDefinitionHighlighting(),
new FunctionDeclarationHighlighting(),
new FunctionHighlighting(),
new TypedefHighlighting(),
new NamespaceHighlighting(),
new LabelHighlighting(),
new EnumeratorHighlighting(),
};
return fgSemanticHighlightings; return fgSemanticHighlightings;
} }

View file

@ -15,6 +15,7 @@ import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.ui.text.ISemanticToken;
/** /**
* Semantic token. * Semantic token.
@ -22,7 +23,7 @@ import org.eclipse.cdt.core.dom.ast.IBinding;
* *
* @since 4.0 * @since 4.0
*/ */
public final class SemanticToken { public final class SemanticToken implements ISemanticToken {
/** AST node */ /** AST node */
private IASTNode fNode; private IASTNode fNode;
@ -38,6 +39,7 @@ public final class SemanticToken {
/** /**
* @return Returns the binding, can be <code>null</code>. * @return Returns the binding, can be <code>null</code>.
*/ */
@Override
public IBinding getBinding() { public IBinding getBinding() {
if (!fIsBindingResolved) { if (!fIsBindingResolved) {
fIsBindingResolved= true; fIsBindingResolved= true;
@ -51,6 +53,7 @@ public final class SemanticToken {
/** /**
* @return the AST node * @return the AST node
*/ */
@Override
public IASTNode getNode() { public IASTNode getNode() {
return fNode; return fNode;
} }
@ -58,6 +61,7 @@ public final class SemanticToken {
/** /**
* @return the AST root * @return the AST root
*/ */
@Override
public IASTTranslationUnit getRoot() { public IASTTranslationUnit getRoot() {
if (!fIsRootResolved) { if (!fIsRootResolved) {
fIsRootResolved= true; fIsRootResolved= true;

View file

@ -0,0 +1,31 @@
/*
* Copyright (c) 2013 QNX Software Systems 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
*/
package org.eclipse.cdt.ui.text;
/**
* Interface that must be implemented by contributors to the org.eclipse.cdt.ui.semanticHighlighting extension
* point.
*
* @since 5.5
*/
public interface ISemanticHighlighter {
/**
* Returns <code>true</code> iff the semantic highlighting consumes the semantic token.
* <p>
* NOTE: Implementors are not allowed to keep a reference on the token or on any object retrieved from the
* token.
* </p>
*
* @param token
* the semantic token for a {@link org.eclipse.cdt.core.dom.ast.IASTName}
* @return <code>true</code> iff the semantic highlighting consumes the semantic token
*/
public boolean consumes(ISemanticToken token);
}

View file

@ -0,0 +1,27 @@
package org.eclipse.cdt.ui.text;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IBinding;
/**
* An interface for accessing details of the token that is being highlighted.
*
* @since 5.5
*/
public interface ISemanticToken {
/**
* @return Returns the binding, can be <code>null</code>.
*/
public IBinding getBinding();
/**
* @return the AST node
*/
public IASTNode getNode();
/**
* @return the AST root
*/
public IASTTranslationUnit getRoot();
}