diff --git a/lsp4e-cpp/org.eclipse.lsp4e.cpp.language/src/org/eclipse/lsp4e/cpp/language/PresentationReconcilerCPP.java b/lsp4e-cpp/org.eclipse.lsp4e.cpp.language/src/org/eclipse/lsp4e/cpp/language/PresentationReconcilerCPP.java index 520e531d359..1b16aeb9350 100644 --- a/lsp4e-cpp/org.eclipse.lsp4e.cpp.language/src/org/eclipse/lsp4e/cpp/language/PresentationReconcilerCPP.java +++ b/lsp4e-cpp/org.eclipse.lsp4e.cpp.language/src/org/eclipse/lsp4e/cpp/language/PresentationReconcilerCPP.java @@ -17,6 +17,12 @@ package org.eclipse.lsp4e.cpp.language; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + import org.eclipse.cdt.core.dom.ast.gnu.cpp.GPPLanguage; import org.eclipse.cdt.core.model.ICLanguageKeywords; import org.eclipse.cdt.core.model.ILanguage; @@ -24,12 +30,12 @@ import org.eclipse.cdt.internal.ui.text.CCodeScanner; import org.eclipse.cdt.internal.ui.text.CCommentScanner; import org.eclipse.cdt.internal.ui.text.CPreprocessorScanner; import org.eclipse.cdt.internal.ui.text.CPresentationReconciler; -import org.eclipse.cdt.internal.ui.text.FastCPartitioner; import org.eclipse.cdt.internal.ui.text.PartitionDamager; import org.eclipse.cdt.internal.ui.text.SingleTokenCScanner; import org.eclipse.cdt.internal.ui.text.TokenStore; import org.eclipse.cdt.ui.CUIPlugin; import org.eclipse.cdt.ui.ILanguageUI; +import org.eclipse.cdt.ui.PreferenceConstants; import org.eclipse.cdt.ui.text.AbstractCScanner; import org.eclipse.cdt.ui.text.ICColorConstants; import org.eclipse.cdt.ui.text.ICPartitions; @@ -38,6 +44,9 @@ import org.eclipse.cdt.ui.text.ITokenStore; import org.eclipse.cdt.ui.text.ITokenStoreFactory; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.preference.PreferenceConverter; +import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextInputListener; @@ -45,7 +54,14 @@ import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.TextPresentation; import org.eclipse.jface.text.rules.DefaultDamagerRepairer; import org.eclipse.jface.text.rules.RuleBasedScanner; +import org.eclipse.lsp4e.cpp.language.cquery.CquerySemanticHighlights; +import org.eclipse.lsp4e.cpp.language.cquery.HighlightSymbol; +import org.eclipse.lsp4j.Range; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.StyleRange; import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.widgets.Display; /** * Hack-ish reconciler to get some colors in the generic editor using the C/C++ @@ -61,6 +77,9 @@ public class PresentationReconcilerCPP extends CPresentationReconciler { private CqueryLineBackgroundListener fLineBackgroundListener = new CqueryLineBackgroundListener(); private ITextViewer textViewer; private TextInputListenerCPP textInputListener; + + public static Set presentationReconcilers = ConcurrentHashMap.newKeySet(); + protected ITokenStoreFactory getTokenStoreFactory() { return new ITokenStoreFactory() { @Override @@ -154,8 +173,81 @@ public class PresentationReconcilerCPP extends CPresentationReconciler { @Override protected TextPresentation createPresentation(IRegion damage, IDocument document) { - TextPresentation createPresentation = super.createPresentation(damage, document); - return createPresentation; + TextPresentation presentation = super.createPresentation(damage, document); + + IDocument doc = textViewer.getDocument(); + URI uri = Server2ClientProtocolExtension.getUri(doc); + + if (uri == null) { + return presentation; + } + + List semanticHighlights = CquerySemanticHighlights.uriToSemanticHighlightsMapping.get(uri); + + if(semanticHighlights == null) { + return presentation; + } + + IPreferenceStore store = CUIPlugin.getDefault().getPreferenceStore(); + List styleRanges = new ArrayList<>(); + + for (HighlightSymbol highlight : semanticHighlights) { + + String highlightingName = HighlightSymbol.getHighlightingName(highlight.getKind(), highlight.getParentKind(), highlight.getStorage()); + String colorKey = PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_PREFIX + + highlightingName + PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_COLOR_SUFFIX; + + boolean isBold = store.getBoolean(PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_PREFIX + + highlightingName + PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_BOLD_SUFFIX); + boolean isItalic = store.getBoolean(PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_PREFIX + + highlightingName + PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_ITALIC_SUFFIX); + boolean isUnderline = store.getBoolean(PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_PREFIX + + highlightingName + PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_UNDERLINE_SUFFIX); + boolean isStrikethrough = store.getBoolean(PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_PREFIX + + highlightingName + PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_STRIKETHROUGH_SUFFIX); + + Color color = new Color(Display.getCurrent(), + PreferenceConverter.getColor(CUIPlugin.getDefault().getPreferenceStore(), colorKey)); + + int damageStartOffset = damage.getOffset(); + int damageEndOffset = damageStartOffset + damage.getLength(); + + List ranges = highlight.getRanges(); + for (Range range : ranges) { + + int offset = 0, length = 0; + try { + offset = doc.getLineOffset(range.getStart().getLine()) + range.getStart().getCharacter(); + length = doc.getLineOffset(range.getEnd().getLine()) + range.getEnd().getCharacter() - offset; + } catch (BadLocationException e) { + Activator.log(e); + } + if ((offset + length) >= damageStartOffset && offset < damageEndOffset) { + + StyleRange styleRange = new StyleRange(offset, length, color, null); + + if (isBold) { + styleRange.fontStyle = SWT.BOLD; + } + if (isItalic) { + styleRange.fontStyle |= SWT.ITALIC; + } + if (isUnderline) { + styleRange.underline = true; + } + if (isStrikethrough) { + styleRange.strikeout = true; + } + + styleRanges.add(styleRange); + } + } + } + + StyleRange[] styleRangesArray = new StyleRange[styleRanges.size()]; + styleRangesArray = styleRanges.toArray(styleRangesArray); + presentation.replaceStyleRanges(styleRangesArray); + return presentation; } /** @@ -218,7 +310,7 @@ public class PresentationReconcilerCPP extends CPresentationReconciler { return fPreprocessorScanner; } - class TextInputListenerCPP implements ITextInputListener { + public class TextInputListenerCPP implements ITextInputListener { @Override public void inputDocumentChanged(IDocument oldInput, IDocument newInput) { @@ -236,6 +328,10 @@ public class PresentationReconcilerCPP extends CPresentationReconciler { } } + public ITextViewer getTextViewer() { + return textViewer; + } + @Override public void install(ITextViewer viewer) { super.install(viewer); @@ -248,6 +344,7 @@ public class PresentationReconcilerCPP extends CPresentationReconciler { } StyledText textWidget = textViewer.getTextWidget(); textWidget.addLineBackgroundListener(fLineBackgroundListener); + presentationReconcilers.add(this); } @Override @@ -255,5 +352,6 @@ public class PresentationReconcilerCPP extends CPresentationReconciler { super.uninstall(); textViewer.getTextWidget().removeLineBackgroundListener(fLineBackgroundListener); textViewer.removeTextInputListener(textInputListener); + presentationReconcilers.remove(this); } } diff --git a/lsp4e-cpp/org.eclipse.lsp4e.cpp.language/src/org/eclipse/lsp4e/cpp/language/Server2ClientProtocolExtension.java b/lsp4e-cpp/org.eclipse.lsp4e.cpp.language/src/org/eclipse/lsp4e/cpp/language/Server2ClientProtocolExtension.java index 41dc5d5b80b..c2e913c25f2 100644 --- a/lsp4e-cpp/org.eclipse.lsp4e.cpp.language/src/org/eclipse/lsp4e/cpp/language/Server2ClientProtocolExtension.java +++ b/lsp4e-cpp/org.eclipse.lsp4e.cpp.language/src/org/eclipse/lsp4e/cpp/language/Server2ClientProtocolExtension.java @@ -9,10 +9,16 @@ package org.eclipse.lsp4e.cpp.language; import java.net.URI; +import java.util.ArrayList; import java.util.List; +import org.eclipse.core.resources.IFile; import org.eclipse.jface.action.StatusLineContributionItem; import org.eclipse.jface.action.StatusLineManager; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.Region; +import org.eclipse.jface.text.TextPresentation; +import org.eclipse.lsp4e.LSPEclipseUtils; import org.eclipse.lsp4e.LanguageClientImpl; import org.eclipse.lsp4e.cpp.language.cquery.CqueryInactiveRegions; import org.eclipse.lsp4e.cpp.language.cquery.CquerySemanticHighlights; @@ -25,7 +31,6 @@ import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.internal.WorkbenchWindow; - @SuppressWarnings("restriction") public class Server2ClientProtocolExtension extends LanguageClientImpl { @@ -60,8 +65,46 @@ public class Server2ClientProtocolExtension extends LanguageClientImpl { CqueryLineBackgroundListener.fileInactiveRegionsMap.put(uri, inactiveRegions); } + public static URI getUri(IDocument document) { + URI uri = null; + IFile file = LSPEclipseUtils.getFile(document); + if (file != null) { + uri = LSPEclipseUtils.toUri(file); + } + return uri; + } + @JsonNotification("$cquery/publishSemanticHighlighting") public final void semanticHighlights(CquerySemanticHighlights highlights) { - // TODO: Implement + URI uriReceived = highlights.getUri(); + CquerySemanticHighlights.uriToSemanticHighlightsMapping.put(uriReceived, highlights.getSymbols()); + List matchingReconcilers = new ArrayList<>(); + + for (PresentationReconcilerCPP eachReconciler: PresentationReconcilerCPP.presentationReconcilers) { + IDocument currentReconcilerDoc = eachReconciler.getTextViewer().getDocument(); + URI currentReconcilerUri = getUri(currentReconcilerDoc); + + if(currentReconcilerUri == null) { + continue; + } + + if (uriReceived.equals(currentReconcilerUri)) { + matchingReconcilers.add(eachReconciler); + } + } + + Display.getDefault().asyncExec(new Runnable() { + @Override + public void run() { + for (PresentationReconcilerCPP p: matchingReconcilers) { + IDocument currentReconcilerDoc = p.getTextViewer().getDocument(); + if (currentReconcilerDoc == null) { + continue; + } + TextPresentation textPresentation = p.createPresentation(new Region(0, currentReconcilerDoc.getLength()), currentReconcilerDoc); + p.getTextViewer().changeTextPresentation(textPresentation, false); + } + } + }); } } diff --git a/lsp4e-cpp/org.eclipse.lsp4e.cpp.language/src/org/eclipse/lsp4e/cpp/language/cquery/CquerySemanticHighlights.java b/lsp4e-cpp/org.eclipse.lsp4e.cpp.language/src/org/eclipse/lsp4e/cpp/language/cquery/CquerySemanticHighlights.java index 2917e9551cd..5b504a4a7cc 100644 --- a/lsp4e-cpp/org.eclipse.lsp4e.cpp.language/src/org/eclipse/lsp4e/cpp/language/cquery/CquerySemanticHighlights.java +++ b/lsp4e-cpp/org.eclipse.lsp4e.cpp.language/src/org/eclipse/lsp4e/cpp/language/cquery/CquerySemanticHighlights.java @@ -10,10 +10,13 @@ package org.eclipse.lsp4e.cpp.language.cquery; import java.net.URI; import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; public class CquerySemanticHighlights { private URI uri; private List symbols; + public static ConcurrentMap> uriToSemanticHighlightsMapping = new ConcurrentHashMap<>(16, 0.75f, 1); public URI getUri() { return uri; diff --git a/lsp4e-cpp/org.eclipse.lsp4e.cpp.language/src/org/eclipse/lsp4e/cpp/language/cquery/HighlightSymbol.java b/lsp4e-cpp/org.eclipse.lsp4e.cpp.language/src/org/eclipse/lsp4e/cpp/language/cquery/HighlightSymbol.java index b17b6a5346a..2eaeabcb60b 100644 --- a/lsp4e-cpp/org.eclipse.lsp4e.cpp.language/src/org/eclipse/lsp4e/cpp/language/cquery/HighlightSymbol.java +++ b/lsp4e-cpp/org.eclipse.lsp4e.cpp.language/src/org/eclipse/lsp4e/cpp/language/cquery/HighlightSymbol.java @@ -8,16 +8,61 @@ package org.eclipse.lsp4e.cpp.language.cquery; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import org.eclipse.cdt.internal.ui.editor.SemanticHighlightings; import org.eclipse.lsp4j.Range; +import org.eclipse.lsp4j.SymbolKind; +@SuppressWarnings("restriction") public class HighlightSymbol { private int stableId; private ExtendedSymbolKindType parentKind; private ExtendedSymbolKindType kind; private StorageClass storage; private List ranges; + public static Map semanticHighlightSymbolsMap = new HashMap<>(); + + static { + semanticHighlightSymbolsMap.put(SymbolKind.Namespace.getValue(), SemanticHighlightings.NAMESPACE); + semanticHighlightSymbolsMap.put(SymbolKind.Class.getValue(), SemanticHighlightings.CLASS); + semanticHighlightSymbolsMap.put(SymbolKind.Method.getValue(), SemanticHighlightings.METHOD); + semanticHighlightSymbolsMap.put(SymbolKind.Constructor.getValue(), SemanticHighlightings.METHOD); + semanticHighlightSymbolsMap.put(SymbolKind.Enum.getValue(), SemanticHighlightings.ENUM); + semanticHighlightSymbolsMap.put(SymbolKind.Function.getValue(), SemanticHighlightings.FUNCTION); + semanticHighlightSymbolsMap.put(SymbolKind.EnumMember.getValue(), SemanticHighlightings.ENUMERATOR); + semanticHighlightSymbolsMap.put(SymbolKind.Struct.getValue(), SemanticHighlightings.CLASS); + semanticHighlightSymbolsMap.put(SymbolKind.TypeParameter.getValue(), SemanticHighlightings.TEMPLATE_PARAMETER); + semanticHighlightSymbolsMap.put(CquerySymbolKind.TypeAlias.getValue(), SemanticHighlightings.TYPEDEF); + semanticHighlightSymbolsMap.put(CquerySymbolKind.Parameter.getValue(), SemanticHighlightings.PARAMETER_VARIABLE); + semanticHighlightSymbolsMap.put(CquerySymbolKind.StaticMethod.getValue(), SemanticHighlightings.STATIC_METHOD_INVOCATION); + semanticHighlightSymbolsMap.put(CquerySymbolKind.Macro.getValue(), SemanticHighlightings.MACRO_DEFINITION); + } + + public static String getHighlightingName(ExtendedSymbolKindType kind, ExtendedSymbolKindType parentKind, StorageClass storage) { + String highlightingName = semanticHighlightSymbolsMap.get(kind.getValue()); + if (highlightingName == null) { + if (kind.getValue() == SymbolKind.Variable.getValue()) { + if (parentKind.getValue() == SymbolKind.Function.getValue() + || parentKind.getValue() == SymbolKind.Method.getValue() + || parentKind.getValue() == SymbolKind.Constructor.getValue()) { + + highlightingName = SemanticHighlightings.LOCAL_VARIABLE; + } else { + highlightingName = SemanticHighlightings.GLOBAL_VARIABLE; + } + } else if (kind.getValue() == SymbolKind.Field.getValue()) { + if (storage == StorageClass.Static) { + highlightingName = SemanticHighlightings.STATIC_FIELD; + } else { + highlightingName = SemanticHighlightings.FIELD; + } + } + } + return highlightingName; + } public HighlightSymbol(int stableId, ExtendedSymbolKindType parentKind, ExtendedSymbolKindType kind, StorageClass storage, List ranges) {