diff --git a/core/org.eclipse.cdt.ui/plugin.properties b/core/org.eclipse.cdt.ui/plugin.properties index 82a725516ba..18028baf180 100644 --- a/core/org.eclipse.cdt.ui/plugin.properties +++ b/core/org.eclipse.cdt.ui/plugin.properties @@ -644,4 +644,6 @@ RefreshExclusionContributorExtensionPoint = Refresh Exclusion Contributor newProjectWizard.name = C/C++ Project (prototype) projectTypePages = Project Type Pages +semanticHighlightingExtensionPoint = Semantic Highlighting Extension Point + UserSettingEntries.name = CDT User Setting Entries diff --git a/core/org.eclipse.cdt.ui/plugin.xml b/core/org.eclipse.cdt.ui/plugin.xml index e86fecfc6d4..f5655de04b1 100644 --- a/core/org.eclipse.cdt.ui/plugin.xml +++ b/core/org.eclipse.cdt.ui/plugin.xml @@ -29,6 +29,7 @@ + diff --git a/core/org.eclipse.cdt.ui/schema/semanticHighlighting.exsd b/core/org.eclipse.cdt.ui/schema/semanticHighlighting.exsd new file mode 100644 index 00000000000..f5960fd03c8 --- /dev/null +++ b/core/org.eclipse.cdt.ui/schema/semanticHighlighting.exsd @@ -0,0 +1,245 @@ + + + + + + + + + This extension point allows extensions to contribute to the semantic highlighting. +<p> +Extensions specify the priority of the highlighting, which determines the order in which the highlighting is invoked. +</p> +<p> +This extension point supports the <code>enablement</code> tag. Properties to test on are: +<dl> +<li>projectNatures: type Collection; all project natures of the current project</li> +<li>languageId: type String; the result if ILanguage.getId on the token's ITranslationUnit</li> +</dl> +</p> +<p> +Contributed highlightings will be visible in the Code tree of the 'C/C++ - Editor - Syntax Colouring' preference page. +</p> + + + + + + + + + + + + + + + + + + + a fully qualified identifier of the target extension point + + + + + + + an optional identifier of the extension instance + + + + + + + an optional name of the extension instance + + + + + + + + + + + + + + + + + + a unique identifier for the Quick Fix processor + + + + + + + a localized name of the Quick Fix processor + + + + + + + + + + The name of the class that implements this Semantic Highlighting. The +class must be public and implement +<samp>org.eclipse.cdt.ui.text.ISemanticHighlighter</samp> +with a public 0-argument constructor. + + + + + + + + + + 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. + + + + + + + A key to uniquely identify the highlighting's settings in the preference store. + + + + + + + The name that is displayed for the highlighter in the Preferences window. + + + + + + + + + + The default text color of the contributed highlighting. The value must be the integer RGB values (0-255) separated by commas. E.g., "127,0,85". Defaults to "0,0,0" (black). + + + + + + + false by default + + + + + + + false by default + + + + + + + false by default + + + + + + + false by default + + + + + + + false by default + + + + + + + + + + + + 8.2 + + + + + + + + + The following is an example of a Semantic Highligher contribution: + +<p> +<pre> +<extension + point="org.eclipse.cdt.ui.semanticHighlighting" + name="%extensionName" + id="com.example.ui.semanticHighlightings"> + <semanticHighlighting + id="com.example.ui.keywordHighlighting" + priority="5" + class="com.example.internal.ui.ExampleHighlighting" + preferenceKey="example-keywords" + displayName="%exampleHighlighting.displayName" + defaultTextColor="127,0,85" + defaultBold="true" + defaultEnabled="true"> + <enablement> + <with variable="projectNatures"> + <iterate operator="or"> + <equals value="org.eclipse.cdt.core.ccnature"/> + </iterate> + </with> + <with variable="languageId"> + <or> + <equals value="org.eclipse.cdt.core.g++"/> + <equals value="org.eclipse.cdt.core.gcc"/> + </or> + </with> + </enablement> + </semanticHighlighting> +</extension> +</pre> +</p> + + + + + + + + + The contributed class must implement <code>org.eclipse.cdt.ui.text.ISemanticHighlighter</code> + + + + + + + + + + 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 + + + + diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/ContributedSemanticHighlighting.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/ContributedSemanticHighlighting.java new file mode 100644 index 00000000000..ada16913806 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/ContributedSemanticHighlighting.java @@ -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); + } +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/SemanticHighlighting.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/SemanticHighlighting.java index a58b7463bc6..b6d72dc3562 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/SemanticHighlighting.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/SemanticHighlighting.java @@ -17,11 +17,12 @@ import org.eclipse.swt.graphics.RGB; import org.eclipse.ui.PlatformUI; import org.eclipse.cdt.ui.CUIPlugin; +import org.eclipse.cdt.ui.text.ISemanticToken; /** * Semantic highlighting. * Cloned from JDT. - * + * * @since 4.0 */ public abstract class SemanticHighlighting { @@ -81,9 +82,9 @@ public abstract class SemanticHighlighting { * @return the display name */ public abstract String getDisplayName(); - + /** - * Indicates that the highlighting needs to visit implicit names + * Indicates that the highlighting needs to visit implicit names * (e.g. overloaded operators) */ public boolean requiresImplicitNames() { @@ -100,7 +101,7 @@ public abstract class SemanticHighlighting { * @param token the semantic token for a {@link org.eclipse.cdt.core.dom.ast.IASTName} * @return true iff the semantic highlighting consumes the semantic token */ - public abstract boolean consumes(SemanticToken token); + public abstract boolean consumes(ISemanticToken token); private String getThemeColorKey() { return CUIPlugin.PLUGIN_ID + "." + getPreferenceKey() + "Highlighting"; //$NON-NLS-1$//$NON-NLS-2$ diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/SemanticHighlightings.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/SemanticHighlightings.java index e3df7aedf1e..5e6da1c7d65 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/SemanticHighlightings.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/SemanticHighlightings.java @@ -11,7 +11,11 @@ *******************************************************************************/ 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.IConfigurationElement; import org.eclipse.core.runtime.Platform; import org.eclipse.jface.preference.IPreferenceStore; 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.ui.CUIPlugin; 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.OverloadableOperator; @@ -228,7 +233,7 @@ public class SemanticHighlightings { } @Override - public boolean consumes(SemanticToken token) { + public boolean consumes(ISemanticToken token) { IASTNode node= token.getNode(); if (node instanceof IASTName) { IASTName name= (IASTName) node; @@ -279,7 +284,7 @@ public class SemanticHighlightings { } @Override - public boolean consumes(SemanticToken token) { + public boolean consumes(ISemanticToken token) { IASTNode node= token.getNode(); if (node instanceof IASTName) { IASTName name= (IASTName) node; @@ -330,7 +335,7 @@ public class SemanticHighlightings { } @Override - public boolean consumes(SemanticToken token) { + public boolean consumes(ISemanticToken token) { IASTNode node= token.getNode(); if (node instanceof IASTImplicitName) return false; @@ -407,7 +412,7 @@ public class SemanticHighlightings { } @Override - public boolean consumes(SemanticToken token) { + public boolean consumes(ISemanticToken token) { IASTNode node= token.getNode(); if (node instanceof IASTName) { IASTName name= (IASTName) node; @@ -461,7 +466,7 @@ public class SemanticHighlightings { } @Override - public boolean consumes(SemanticToken token) { + public boolean consumes(ISemanticToken token) { IASTNode node= token.getNode(); if (node instanceof IASTImplicitName) return false; @@ -514,7 +519,7 @@ public class SemanticHighlightings { } @Override - public boolean consumes(SemanticToken token) { + public boolean consumes(ISemanticToken token) { IASTNode node= token.getNode(); if (node instanceof IASTImplicitName) return false; @@ -585,7 +590,7 @@ public class SemanticHighlightings { } @Override - public boolean consumes(SemanticToken token) { + public boolean consumes(ISemanticToken token) { IASTNode node= token.getNode(); if (node instanceof IASTImplicitName) return false; @@ -638,7 +643,7 @@ public class SemanticHighlightings { } @Override - public boolean consumes(SemanticToken token) { + public boolean consumes(ISemanticToken token) { IASTNode node= token.getNode(); if (node instanceof IASTName) { IASTName name= (IASTName) node; @@ -698,7 +703,7 @@ public class SemanticHighlightings { } @Override - public boolean consumes(SemanticToken token) { + public boolean consumes(ISemanticToken token) { IASTNode node= token.getNode(); if (node instanceof IASTName) { IASTName name= (IASTName) node; @@ -774,7 +779,7 @@ public class SemanticHighlightings { } @Override - public boolean consumes(SemanticToken token) { + public boolean consumes(ISemanticToken token) { IASTNode node= token.getNode(); if (node instanceof IASTName) { IASTName name= (IASTName) node; @@ -836,7 +841,7 @@ public class SemanticHighlightings { } @Override - public boolean consumes(SemanticToken token) { + public boolean consumes(ISemanticToken token) { IBinding binding= token.getBinding(); if (binding instanceof IParameter) { return true; @@ -880,7 +885,7 @@ public class SemanticHighlightings { } @Override - public boolean consumes(SemanticToken token) { + public boolean consumes(ISemanticToken token) { IASTNode node= token.getNode(); if (node instanceof IASTName) { IBinding binding= token.getBinding(); @@ -927,7 +932,7 @@ public class SemanticHighlightings { } @Override - public boolean consumes(SemanticToken token) { + public boolean consumes(ISemanticToken token) { IASTNode node= token.getNode(); if (node instanceof ICPPASTQualifiedName || node instanceof ICPPASTTemplateId) { return false; @@ -977,7 +982,7 @@ public class SemanticHighlightings { } @Override - public boolean consumes(SemanticToken token) { + public boolean consumes(ISemanticToken token) { IASTNode node= token.getNode(); if (node instanceof IASTName) { IBinding binding= token.getBinding(); @@ -1024,7 +1029,7 @@ public class SemanticHighlightings { } @Override - public boolean consumes(SemanticToken token) { + public boolean consumes(ISemanticToken token) { IBinding binding= token.getBinding(); if (binding instanceof IMacroBinding) { IASTName name= (IASTName)token.getNode(); @@ -1071,7 +1076,7 @@ public class SemanticHighlightings { } @Override - public boolean consumes(SemanticToken token) { + public boolean consumes(ISemanticToken token) { IBinding binding= token.getBinding(); if (binding instanceof IMacroBinding) { IASTName name= (IASTName)token.getNode(); @@ -1118,7 +1123,7 @@ public class SemanticHighlightings { } @Override - public boolean consumes(SemanticToken token) { + public boolean consumes(ISemanticToken token) { IASTNode node= token.getNode(); if (node instanceof IASTName) { IASTName name= (IASTName) node; @@ -1169,7 +1174,7 @@ public class SemanticHighlightings { } @Override - public boolean consumes(SemanticToken token) { + public boolean consumes(ISemanticToken token) { IBinding binding= token.getBinding(); if (binding instanceof ICPPNamespace) { return true; @@ -1213,7 +1218,7 @@ public class SemanticHighlightings { } @Override - public boolean consumes(SemanticToken token) { + public boolean consumes(ISemanticToken token) { IBinding binding= token.getBinding(); if (binding instanceof ILabel) { return true; @@ -1257,7 +1262,7 @@ public class SemanticHighlightings { } @Override - public boolean consumes(SemanticToken token) { + public boolean consumes(ISemanticToken token) { IASTNode node= token.getNode(); if (node instanceof IASTName) { IASTName name= (IASTName) node; @@ -1313,7 +1318,7 @@ public class SemanticHighlightings { } @Override - public boolean consumes(SemanticToken token) { + public boolean consumes(ISemanticToken token) { IASTNode node= token.getNode(); if (node.getTranslationUnit().isBasedOnIncompleteIndex()) { // Do not highlight problems is the AST is unreliable. @@ -1370,7 +1375,7 @@ public class SemanticHighlightings { } @Override - public boolean consumes(SemanticToken token) { + public boolean consumes(ISemanticToken token) { IASTNode node= token.getNode(); if (node instanceof IASTName) { IASTName name= (IASTName) node; @@ -1459,7 +1464,7 @@ public class SemanticHighlightings { } @Override - public boolean consumes(SemanticToken token) { + public boolean consumes(ISemanticToken token) { IASTNode node = token.getNode(); // So far we only have implicit names for overloaded operators and destructors, // so this works. @@ -1545,36 +1550,106 @@ public class SemanticHighlightings { return PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_PREFIX + semanticHighlighting.getPreferenceKey() + PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_ENABLED_SUFFIX; } + private static class Key implements Comparable { + 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 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 highlightings = new TreeMap(); + + // 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. */ public static SemanticHighlighting[] getSemanticHighlightings() { if (fgSemanticHighlightings == null) - fgSemanticHighlightings= new SemanticHighlighting[] { - new MacroReferenceHighlighting(), // before all others! - new ProblemHighlighting(), - 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(), - }; + synchronized (SemanticHighlightingsLock) { + if (fgSemanticHighlightings == null) + fgSemanticHighlightings = loadSemanticHighlightings(); + } return fgSemanticHighlightings; } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/SemanticToken.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/SemanticToken.java index 6b34458aae0..03b8e5136de 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/SemanticToken.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/editor/SemanticToken.java @@ -15,14 +15,15 @@ import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.IBinding; +import org.eclipse.cdt.ui.text.ISemanticToken; /** * Semantic token. * Cloned from JDT. - * + * * @since 4.0 */ -public final class SemanticToken { +public final class SemanticToken implements ISemanticToken { /** AST node */ private IASTNode fNode; @@ -38,26 +39,29 @@ public final class SemanticToken { /** * @return Returns the binding, can be null. */ + @Override public IBinding getBinding() { if (!fIsBindingResolved) { fIsBindingResolved= true; if (fNode instanceof IASTName) fBinding= ((IASTName) fNode).resolveBinding(); } - + return fBinding; } /** * @return the AST node */ + @Override public IASTNode getNode() { return fNode; } - + /** * @return the AST root */ + @Override public IASTTranslationUnit getRoot() { if (!fIsRootResolved) { fIsRootResolved= true; diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/text/ISemanticHighlighter.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/text/ISemanticHighlighter.java new file mode 100644 index 00000000000..65640501405 --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/text/ISemanticHighlighter.java @@ -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 true iff the semantic highlighting consumes the semantic token. + *

+ * NOTE: Implementors are not allowed to keep a reference on the token or on any object retrieved from the + * token. + *

+ * + * @param token + * the semantic token for a {@link org.eclipse.cdt.core.dom.ast.IASTName} + * @return true iff the semantic highlighting consumes the semantic token + */ + public boolean consumes(ISemanticToken token); +} diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/text/ISemanticToken.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/text/ISemanticToken.java new file mode 100644 index 00000000000..c9f3d65020c --- /dev/null +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/text/ISemanticToken.java @@ -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 null. + */ + public IBinding getBinding(); + + /** + * @return the AST node + */ + public IASTNode getNode(); + + /** + * @return the AST root + */ + public IASTTranslationUnit getRoot(); +}