diff --git a/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/internal/cquery/ui/PublishSemanticHighlighting.java b/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/internal/cquery/ui/PublishSemanticHighlighting.java new file mode 100644 index 00000000000..f5f217d181d --- /dev/null +++ b/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/internal/cquery/ui/PublishSemanticHighlighting.java @@ -0,0 +1,154 @@ +/******************************************************************************* + * Copyright (c) 2018, 2020 Manish Khurana, Nathan Ridge and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * https://www.eclipse.org/legal/epl-2.0/. + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.cdt.internal.cquery.ui; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.function.Consumer; + +import org.eclipse.cdt.cquery.CquerySemanticHighlights; +import org.eclipse.cdt.cquery.HighlightSymbol; +import org.eclipse.cdt.internal.ui.editor.SemanticHighlightingManager.HighlightedPosition; +import org.eclipse.cdt.internal.ui.editor.SemanticHighlightingManager.HighlightingStyle; +import org.eclipse.cdt.lsp.core.Activator; +import org.eclipse.cdt.lsp.core.PresentationReconcilerCPP; +import org.eclipse.cdt.lsp.internal.text.ResolveDocumentUri; +import org.eclipse.cdt.ui.CUIPlugin; +import org.eclipse.cdt.ui.PreferenceConstants; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.preference.PreferenceConverter; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.BadPositionCategoryException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.Region; +import org.eclipse.jface.text.TextAttribute; +import org.eclipse.jface.text.TextPresentation; +import org.eclipse.lsp4j.Range; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.widgets.Display; + +//FIXME: needs more work +public class PublishSemanticHighlighting implements Consumer { + + private final ResolveDocumentUri uri; + + public PublishSemanticHighlighting() { + this.uri = new ResolveDocumentUri(); + } + + @Override + public void accept(CquerySemanticHighlights highlights) { + URI uriReceived = highlights.getUri(); + // List of PresentationReconcilerCPP objects attached with same C++ source file. + //FIXME: AF: extract the retrieval of this list to a separate method + List matchingReconcilers = new ArrayList<>(); + + for (PresentationReconcilerCPP eachReconciler : PresentationReconcilerCPP.presentationReconcilers) { + IDocument currentReconcilerDoc = eachReconciler.getTextViewer().getDocument(); + Optional currentReconcilerUri = uri.apply(currentReconcilerDoc); + if (currentReconcilerUri.isEmpty()) { + continue; + } + + if (uriReceived.equals(currentReconcilerUri.get())) { + matchingReconcilers.add(eachReconciler); + } + } + + if (matchingReconcilers.size() == 0) { + return; + } + + // Using only first object of matchingReconcilers because all reconciler objects share same document object. + IDocument doc = matchingReconcilers.get(0).getTextViewer().getDocument(); + IPreferenceStore store = CUIPlugin.getDefault().getPreferenceStore(); + + // Removing semantic highlighting position category and old positions from document. + try { + doc.removePositionCategory(PresentationReconcilerCPP.SEMANTIC_HIGHLIGHTING_POSITION_CATEGORY); + } catch (BadPositionCategoryException e) { + Activator.log(e); + } + // Again add Semantic Highlighting Position Category to the document. + doc.addPositionCategory(PresentationReconcilerCPP.SEMANTIC_HIGHLIGHTING_POSITION_CATEGORY); + + for (HighlightSymbol highlight : highlights.getSymbols()) { + + String highlightingName = HighlightingNames.getHighlightingName(highlight.getKind(), + highlight.getParentKind(), highlight.getStorage(), highlight.getRole()); + String colorKey = PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_PREFIX + highlightingName + + PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_COLOR_SUFFIX; + + boolean isEnabled = store.getBoolean(PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_PREFIX + + highlightingName + PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_ENABLED_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); + + // TODO: Use IColorManager to cache Color objects so that only one object per color is created. + Color color = new Color(Display.getCurrent(), + PreferenceConverter.getColor(CUIPlugin.getDefault().getPreferenceStore(), colorKey)); + + 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); + } + + int textStyle = SWT.NORMAL; + + if (isBold) { + textStyle = SWT.BOLD; + } + if (isItalic) { + textStyle |= SWT.ITALIC; + } + if (isUnderline) { + textStyle |= TextAttribute.UNDERLINE; + } + if (isStrikethrough) { + textStyle |= TextAttribute.STRIKETHROUGH; + } + + TextAttribute textAttribute = new TextAttribute(color, null, textStyle); + HighlightingStyle highlightingStyle = new HighlightingStyle(textAttribute, isEnabled); + HighlightedPosition highlightedPosition = new HighlightedPosition(offset, length, highlightingStyle, + matchingReconcilers.get(0).getSemanticHighlightingPositionUpdater()); + try { + doc.addPosition(PresentationReconcilerCPP.SEMANTIC_HIGHLIGHTING_POSITION_CATEGORY, + highlightedPosition); + } catch (BadLocationException | BadPositionCategoryException e) { + Activator.log(e); + } + } + } + + Display.getDefault().asyncExec(() -> { + for (PresentationReconcilerCPP eachReconciler : matchingReconcilers) { + TextPresentation presentation = eachReconciler.createPresentation(new Region(0, doc.getLength()), doc); + eachReconciler.getTextViewer().changeTextPresentation(presentation, false); + } + }); + } + +} diff --git a/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/core/PresentationReconcilerCPP.java b/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/core/PresentationReconcilerCPP.java index edf0e63b741..6ea5b48e0b4 100644 --- a/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/core/PresentationReconcilerCPP.java +++ b/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/core/PresentationReconcilerCPP.java @@ -181,7 +181,7 @@ public class PresentationReconcilerCPP extends CPresentationReconciler { } @Override - protected TextPresentation createPresentation(IRegion damage, IDocument document) { + public TextPresentation createPresentation(IRegion damage, IDocument document) { TextPresentation presentation = super.createPresentation(damage, document); IDocument doc = textViewer.getDocument(); diff --git a/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/core/Server2ClientProtocolExtension.java b/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/core/Server2ClientProtocolExtension.java index 6391cde5983..60b025d7e01 100644 --- a/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/core/Server2ClientProtocolExtension.java +++ b/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/core/Server2ClientProtocolExtension.java @@ -1,64 +1,38 @@ /******************************************************************************* - * Copyright (c) 2018-2019 Manish Khurana, Nathan Ridge and others. + * Copyright (c) 2018, 2020 Manish Khurana, Nathan Ridge and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License 2.0 which is available at * https://www.eclipse.org/legal/epl-2.0/. * * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Manish Khurana - initial API and implementation - * Nathan Ridge - initial API and implementation - * Alexander Fedorov - Bug 558516 *******************************************************************************/ package org.eclipse.cdt.lsp.core; -import java.net.URI; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - import org.eclipse.cdt.cquery.CqueryInactiveRegions; import org.eclipse.cdt.cquery.CquerySemanticHighlights; -import org.eclipse.cdt.cquery.HighlightSymbol; import org.eclipse.cdt.cquery.IndexingProgressStats; import org.eclipse.cdt.internal.cquery.CqueryMessages; -import org.eclipse.cdt.internal.cquery.ui.HighlightingNames; -import org.eclipse.cdt.internal.ui.editor.SemanticHighlightingManager.HighlightedPosition; -import org.eclipse.cdt.internal.ui.editor.SemanticHighlightingManager.HighlightingStyle; +import org.eclipse.cdt.internal.cquery.ui.PublishSemanticHighlighting; import org.eclipse.cdt.lsp.internal.core.ShowStatus; -import org.eclipse.cdt.lsp.internal.text.ResolveDocumentUri; +import org.eclipse.cdt.lsp.internal.text.SetInactiveRegions; import org.eclipse.cdt.lsp.internal.ui.StatusLineMessage; -import org.eclipse.cdt.ui.CUIPlugin; -import org.eclipse.cdt.ui.PreferenceConstants; -import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.jface.preference.PreferenceConverter; -import org.eclipse.jface.text.BadLocationException; -import org.eclipse.jface.text.BadPositionCategoryException; -import org.eclipse.jface.text.IDocument; -import org.eclipse.jface.text.Position; -import org.eclipse.jface.text.Region; -import org.eclipse.jface.text.TextAttribute; -import org.eclipse.jface.text.TextPresentation; import org.eclipse.lsp4e.LanguageClientImpl; -import org.eclipse.lsp4j.Range; import org.eclipse.lsp4j.jsonrpc.services.JsonNotification; -import org.eclipse.swt.SWT; -import org.eclipse.swt.graphics.Color; -import org.eclipse.swt.widgets.Display; //FIXME: AF: currently this extension is cquery-specific and it should be contributed from cquery-specific part @SuppressWarnings("restriction") public class Server2ClientProtocolExtension extends LanguageClientImpl { - private final ResolveDocumentUri uri; private final ShowStatus progress; + private final SetInactiveRegions inactive; + private final PublishSemanticHighlighting highlighting; public Server2ClientProtocolExtension() { - this.uri = new ResolveDocumentUri(); this.progress = new ShowStatus(() -> CqueryMessages.CqueryLanguageServer_label, new StatusLineMessage()); + this.inactive = new SetInactiveRegions(); + this.highlighting = new PublishSemanticHighlighting(); } @JsonNotification("$cquery/progress") @@ -68,161 +42,12 @@ public class Server2ClientProtocolExtension extends LanguageClientImpl { @JsonNotification("$cquery/setInactiveRegions") public final void setInactiveRegions(CqueryInactiveRegions regions) { - URI uriReceived = regions.getUri(); - List inactiveRegions = regions.getInactiveRegions(); - //FIXME: AF: extract the retrieval of this document to a separate method - IDocument doc = null; - // To get the document for the received URI. - for (PresentationReconcilerCPP eachReconciler : PresentationReconcilerCPP.presentationReconcilers) { - IDocument currentReconcilerDoc = eachReconciler.getTextViewer().getDocument(); - Optional currentReconcilerUri = uri.apply(currentReconcilerDoc); - - if (currentReconcilerUri.isEmpty()) { - continue; - } - - if (uriReceived.equals(currentReconcilerUri.get())) { - doc = currentReconcilerDoc; - break; - } - } - - if (doc == null) { - return; - } - - // Removing inactive code highlighting position category and old positions from document. - try { - doc.removePositionCategory(PresentationReconcilerCPP.INACTIVE_CODE_HIGHLIGHTING_POSITION_CATEGORY); - } catch (BadPositionCategoryException e) { - Activator.log(e); - } - // Again add Inactive Code Position Category to the document. - doc.addPositionCategory(PresentationReconcilerCPP.INACTIVE_CODE_HIGHLIGHTING_POSITION_CATEGORY); - - for (Range region : inactiveRegions) { - int offset = 0, length = 0; - try { - offset = doc.getLineOffset(region.getStart().getLine()); - length = doc.getLineOffset(region.getEnd().getLine()) - offset; - } catch (BadLocationException e) { - Activator.log(e); - } - - Position inactivePosition = new Position(offset, length); - try { - doc.addPosition(PresentationReconcilerCPP.INACTIVE_CODE_HIGHLIGHTING_POSITION_CATEGORY, - inactivePosition); - } catch (BadLocationException | BadPositionCategoryException e) { - Activator.log(e); - } - } + inactive.accept(regions::getUri, regions::getInactiveRegions); } @JsonNotification("$cquery/publishSemanticHighlighting") public final void semanticHighlights(CquerySemanticHighlights highlights) { - URI uriReceived = highlights.getUri(); - - // List of PresentationReconcilerCPP objects attached with same C++ source file. - //FIXME: AF: extract the retrieval of this list to a separate method - List matchingReconcilers = new ArrayList<>(); - - for (PresentationReconcilerCPP eachReconciler : PresentationReconcilerCPP.presentationReconcilers) { - IDocument currentReconcilerDoc = eachReconciler.getTextViewer().getDocument(); - Optional currentReconcilerUri = uri.apply(currentReconcilerDoc); - if (currentReconcilerUri.isEmpty()) { - continue; - } - - if (uriReceived.equals(currentReconcilerUri.get())) { - matchingReconcilers.add(eachReconciler); - } - } - - if (matchingReconcilers.size() == 0) { - return; - } - - // Using only first object of matchingReconcilers because all reconciler objects share same document object. - IDocument doc = matchingReconcilers.get(0).getTextViewer().getDocument(); - IPreferenceStore store = CUIPlugin.getDefault().getPreferenceStore(); - - // Removing semantic highlighting position category and old positions from document. - try { - doc.removePositionCategory(PresentationReconcilerCPP.SEMANTIC_HIGHLIGHTING_POSITION_CATEGORY); - } catch (BadPositionCategoryException e) { - Activator.log(e); - } - // Again add Semantic Highlighting Position Category to the document. - doc.addPositionCategory(PresentationReconcilerCPP.SEMANTIC_HIGHLIGHTING_POSITION_CATEGORY); - - for (HighlightSymbol highlight : highlights.getSymbols()) { - - String highlightingName = HighlightingNames.getHighlightingName(highlight.getKind(), - highlight.getParentKind(), highlight.getStorage(), highlight.getRole()); - String colorKey = PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_PREFIX + highlightingName - + PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_COLOR_SUFFIX; - - boolean isEnabled = store.getBoolean(PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_PREFIX - + highlightingName + PreferenceConstants.EDITOR_SEMANTIC_HIGHLIGHTING_ENABLED_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); - - // TODO: Use IColorManager to cache Color objects so that only one object per color is created. - Color color = new Color(Display.getCurrent(), - PreferenceConverter.getColor(CUIPlugin.getDefault().getPreferenceStore(), colorKey)); - - 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); - } - - int textStyle = SWT.NORMAL; - - if (isBold) { - textStyle = SWT.BOLD; - } - if (isItalic) { - textStyle |= SWT.ITALIC; - } - if (isUnderline) { - textStyle |= TextAttribute.UNDERLINE; - } - if (isStrikethrough) { - textStyle |= TextAttribute.STRIKETHROUGH; - } - - TextAttribute textAttribute = new TextAttribute(color, null, textStyle); - HighlightingStyle highlightingStyle = new HighlightingStyle(textAttribute, isEnabled); - HighlightedPosition highlightedPosition = new HighlightedPosition(offset, length, highlightingStyle, - matchingReconcilers.get(0).getSemanticHighlightingPositionUpdater()); - try { - doc.addPosition(PresentationReconcilerCPP.SEMANTIC_HIGHLIGHTING_POSITION_CATEGORY, - highlightedPosition); - } catch (BadLocationException | BadPositionCategoryException e) { - Activator.log(e); - } - } - } - - Display.getDefault().asyncExec(() -> { - for (PresentationReconcilerCPP eachReconciler : matchingReconcilers) { - TextPresentation presentation = eachReconciler.createPresentation(new Region(0, doc.getLength()), doc); - eachReconciler.getTextViewer().changeTextPresentation(presentation, false); - } - }); + highlighting.accept(highlights); } } diff --git a/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/internal/text/SetInactiveRegions.java b/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/internal/text/SetInactiveRegions.java new file mode 100644 index 00000000000..f9dcbc80cf2 --- /dev/null +++ b/lsp/org.eclipse.cdt.lsp.core/src/org/eclipse/cdt/lsp/internal/text/SetInactiveRegions.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2018, 2020 Manish Khurana, Nathan Ridge and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * https://www.eclipse.org/legal/epl-2.0/. + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.cdt.lsp.internal.text; + +import java.net.URI; +import java.util.Collection; +import java.util.Optional; +import java.util.function.BiConsumer; +import java.util.function.Supplier; + +import org.eclipse.cdt.lsp.core.Activator; +import org.eclipse.cdt.lsp.core.PresentationReconcilerCPP; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.BadPositionCategoryException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.Position; +import org.eclipse.lsp4j.Range; + +//FIXME: needs more work +public final class SetInactiveRegions implements BiConsumer, Supplier>> { + + private final ResolveDocumentUri resolve; + + public SetInactiveRegions() { + this.resolve = new ResolveDocumentUri(); + } + + @Override + public void accept(Supplier uri, Supplier> ranges) { + URI uriReceived = uri.get(); + Collection inactiveRegions = ranges.get(); + //FIXME: AF: extract the retrieval of this document to a separate method + IDocument doc = null; + // To get the document for the received URI. + for (PresentationReconcilerCPP eachReconciler : PresentationReconcilerCPP.presentationReconcilers) { + IDocument currentReconcilerDoc = eachReconciler.getTextViewer().getDocument(); + Optional currentReconcilerUri = resolve.apply(currentReconcilerDoc); + if (currentReconcilerUri.isEmpty()) { + continue; + } + if (uriReceived.equals(currentReconcilerUri.get())) { + doc = currentReconcilerDoc; + break; + } + } + if (doc == null) { + return; + } + // Removing inactive code highlighting position category and old positions from document. + try { + doc.removePositionCategory(PresentationReconcilerCPP.INACTIVE_CODE_HIGHLIGHTING_POSITION_CATEGORY); + } catch (BadPositionCategoryException e) { + Activator.log(e); + } + // Again add Inactive Code Position Category to the document. + doc.addPositionCategory(PresentationReconcilerCPP.INACTIVE_CODE_HIGHLIGHTING_POSITION_CATEGORY); + + for (Range region : inactiveRegions) { + int offset = 0, length = 0; + try { + offset = doc.getLineOffset(region.getStart().getLine()); + length = doc.getLineOffset(region.getEnd().getLine()) - offset; + } catch (BadLocationException e) { + Activator.log(e); + } + + Position inactivePosition = new Position(offset, length); + try { + doc.addPosition(PresentationReconcilerCPP.INACTIVE_CODE_HIGHLIGHTING_POSITION_CATEGORY, + inactivePosition); + } catch (BadLocationException | BadPositionCategoryException e) { + Activator.log(e); + } + } + } + +}