diff --git a/org.eclipse.lsp4e.debug/META-INF/MANIFEST.MF b/org.eclipse.lsp4e.debug/META-INF/MANIFEST.MF index a6b57c107..ac0147c2f 100644 --- a/org.eclipse.lsp4e.debug/META-INF/MANIFEST.MF +++ b/org.eclipse.lsp4e.debug/META-INF/MANIFEST.MF @@ -3,16 +3,16 @@ Bundle-ManifestVersion: 2 Bundle-Name: Debug Adapter client for Eclipse IDE (Incubation) Bundle-SymbolicName: org.eclipse.lsp4e.debug;singleton:=true Bundle-Vendor: Eclipse LSP4E -Bundle-Version: 0.16.1.qualifier +Bundle-Version: 0.16.2.qualifier Bundle-Activator: org.eclipse.lsp4e.debug.DSPPlugin Require-Bundle: org.eclipse.ui, org.eclipse.core.runtime, org.eclipse.debug.core, org.eclipse.debug.ui, org.eclipse.jface, - org.eclipse.lsp4j.jsonrpc;bundle-version="[0.24.0,0.25.0)", - org.eclipse.lsp4j.jsonrpc.debug;bundle-version="[0.24.0,0.25.0)", - org.eclipse.lsp4j.debug;bundle-version="[0.24.0,0.25.0)", + org.eclipse.lsp4j.jsonrpc;bundle-version="[1.0.0,2.0.0)", + org.eclipse.lsp4j.jsonrpc.debug;bundle-version="[1.0.0,2.0.0)", + org.eclipse.lsp4j.debug;bundle-version="[1.0.0,2.0.0)", org.eclipse.ui.editors, org.eclipse.core.filesystem, org.eclipse.ui.ide;bundle-version="[3.16.0,4.0.0)", diff --git a/org.eclipse.lsp4e.test/META-INF/MANIFEST.MF b/org.eclipse.lsp4e.test/META-INF/MANIFEST.MF index 6369d95b0..4bdbc8c30 100644 --- a/org.eclipse.lsp4e.test/META-INF/MANIFEST.MF +++ b/org.eclipse.lsp4e.test/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Tests for language server bundle (Incubation) Bundle-SymbolicName: org.eclipse.lsp4e.test;singleton:=true -Bundle-Version: 0.16.4.qualifier +Bundle-Version: 0.16.5.qualifier Fragment-Host: org.eclipse.lsp4e Bundle-Vendor: Eclipse LSP4E Bundle-RequiredExecutionEnvironment: JavaSE-21 diff --git a/org.eclipse.lsp4e.test/pom.xml b/org.eclipse.lsp4e.test/pom.xml index c87cf3093..50051a8b9 100644 --- a/org.eclipse.lsp4e.test/pom.xml +++ b/org.eclipse.lsp4e.test/pom.xml @@ -8,7 +8,7 @@ org.eclipse.lsp4e.test eclipse-test-plugin - 0.16.4-SNAPSHOT + 0.16.5-SNAPSHOT diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/diagnostics/DiagnosticsTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/diagnostics/DiagnosticsTest.java index f6674f003..40dcaddac 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/diagnostics/DiagnosticsTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/diagnostics/DiagnosticsTest.java @@ -13,12 +13,10 @@ *******************************************************************************/ package org.eclipse.lsp4e.test.diagnostics; -import static org.eclipse.lsp4e.test.utils.TestUtils.waitForAndAssertCondition; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.eclipse.lsp4e.test.utils.TestUtils.*; +import static org.hamcrest.CoreMatchers.*; +import static org.hamcrest.MatcherAssert.*; +import static org.junit.jupiter.api.Assertions.*; import java.io.File; import java.io.FileOutputStream; @@ -106,7 +104,7 @@ public void testDiagnostics() throws CoreException { assertEquals(markerCharStart, MarkerUtilities.getCharStart(marker.get())); assertEquals(markerCharEnd, MarkerUtilities.getCharEnd(marker.get())); assertEquals(markerLineIndex + 1, MarkerUtilities.getLineNumber(marker.get())); - assertEquals(diagnostic.getMessage() + " [" + diagnostic.getCode().get() + "]", + assertEquals(diagnostic.getMessage().getLeft() + " [" + diagnostic.getCode().get() + "]", MarkerUtilities.getMessage(marker.get())); } @@ -232,7 +230,7 @@ public void testDiagnosticsRangeAfterDocument() throws CoreException { Diagnostic diagnostic = diagnostics.get(i); IMarker marker = markers[i]; - assertEquals(diagnostic.getMessage() + " [" + diagnostic.getCode().get() + "]", + assertEquals(diagnostic.getMessage().getLeft() + " [" + diagnostic.getCode().get() + "]", MarkerUtilities.getMessage(marker)); assertEquals(content.length(), MarkerUtilities.getCharStart(marker)); assertEquals(content.length(), MarkerUtilities.getCharEnd(marker)); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/edit/LSPEclipseUtilsTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/edit/LSPEclipseUtilsTest.java index 51c70f724..7304ff251 100644 --- a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/edit/LSPEclipseUtilsTest.java +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/edit/LSPEclipseUtilsTest.java @@ -13,12 +13,8 @@ *******************************************************************************/ package org.eclipse.lsp4e.test.edit; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assumptions.*; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -138,8 +134,9 @@ public void testWorkspaceEdit_CreateAndPopulateFile() throws Exception { String uri = file.getLocation().toFile().toURI().toString(); edits.add(Either.forRight(new CreateFile(uri))); edits.add(Either.forLeft( - new TextDocumentEdit(new VersionedTextDocumentIdentifier(uri, null), List.of( - new TextEdit(new Range(new Position(0, 0), new Position(0, 0)), "abcHere\nabcHere2"))))); + new TextDocumentEdit(new VersionedTextDocumentIdentifier(uri, null), + List.of(Either.forLeft( + new TextEdit(new Range(new Position(0, 0), new Position(0, 0)), "abcHere\nabcHere2")))))); final var workspaceEdit = new WorkspaceEdit(edits); // they should be applied from bottom to top LSPEclipseUtils.applyWorkspaceEdit(workspaceEdit); @@ -358,8 +355,8 @@ public void testResourceOperations() throws Exception { assertTrue(targetFile.exists()); LSPEclipseUtils.applyWorkspaceEdit(new WorkspaceEdit(List.of(Either.forLeft( new TextDocumentEdit(new VersionedTextDocumentIdentifier(targetFile.getLocationURI().toString(), 1), - List.of( - new TextEdit(new Range(new Position(0, 0), new Position(0, 0)), "hello"))))))); + List.of(Either.forLeft( + new TextEdit(new Range(new Position(0, 0), new Position(0, 0)), "hello")))))))); assertEquals("hello", readContent(targetFile)); IFile otherFile = project.getFile("another/folder/file.lol"); LSPEclipseUtils.applyWorkspaceEdit(new WorkspaceEdit(List.of(Either.forRight( @@ -388,7 +385,7 @@ public void editExternalFile() throws Exception { te.setNewText("abc\ndef"); final var docEdit = new TextDocumentEdit( new VersionedTextDocumentIdentifier(file.toURI().toString(), null), - List.of(te)); + List.of(Either.forLeft(te))); final var we = new WorkspaceEdit(List.of(Either.forLeft(docEdit))); LSPEclipseUtils.applyWorkspaceEdit(we); assertTrue(file.isFile()); @@ -428,7 +425,7 @@ public void testTextEditDoesntAutomaticallySaveOpenResourceFiles() throws Except te.setNewText("abc\ndef"); final var docEdit = new TextDocumentEdit( new VersionedTextDocumentIdentifier(LSPEclipseUtils.toUri(targetFile).toString(), null), - List.of(te)); + List.of(Either.forLeft(te))); final var we = new WorkspaceEdit(List.of(Either.forLeft(docEdit))); LSPEclipseUtils.applyWorkspaceEdit(we); assertEquals("abc\ndef", ((StyledText) ((AbstractTextEditor) editor).getAdapter(Control.class)).getText()); @@ -444,7 +441,7 @@ public void testTextEditDoesntAutomaticallySaveOpenExternalFiles() throws Except te.setNewText("abc\ndef"); final var docEdit = new TextDocumentEdit( new VersionedTextDocumentIdentifier(file.toURI().toString(), null), - List.of(te)); + List.of(Either.forLeft(te))); final var we = new WorkspaceEdit(List.of(Either.forLeft(docEdit))); LSPEclipseUtils.applyWorkspaceEdit(we); assertEquals("abc\ndef", ((StyledText) ((AbstractTextEditor) editor).getAdapter(Control.class)).getText()); diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/symbols/SymbolsUtilTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/symbols/SymbolsUtilTest.java new file mode 100644 index 000000000..e954c4f38 --- /dev/null +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/symbols/SymbolsUtilTest.java @@ -0,0 +1,88 @@ +/******************************************************************************* + * Copyright (c) 2024 Advantest GmbH 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: + * Dietrich Travkin (Solunar GmbH) - initial implementation + *******************************************************************************/ +package org.eclipse.lsp4e.test.symbols; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.Arrays; +import java.util.List; + +import org.eclipse.lsp4e.operations.symbols.SymbolsUtil; +import org.eclipse.lsp4j.DocumentSymbol; +import org.eclipse.lsp4j.SymbolInformation; +import org.eclipse.lsp4j.SymbolTag; +import org.eclipse.lsp4j.WorkspaceSymbol; +import org.junit.jupiter.api.Test; + +public class SymbolsUtilTest { + + private static final List symbolTagsWithDeprecated = Arrays.asList( + SymbolTag.Package, SymbolTag.Deprecated, SymbolTag.ReadOnly); + private static final List symbolTagsWithoutDeprecated = Arrays.asList( + SymbolTag.Public, SymbolTag.Declaration, SymbolTag.Static); + + @Test + public void testDeprecatedCheckForSymbolInformation() { + var symbolInformation = new SymbolInformation(); + + assertFalse(SymbolsUtil.isDeprecated(symbolInformation)); + + symbolInformation.setDeprecated(true); + + assertTrue(SymbolsUtil.isDeprecated(symbolInformation)); + + symbolInformation = new SymbolInformation(); + symbolInformation.setTags(symbolTagsWithDeprecated); + + assertTrue(SymbolsUtil.isDeprecated(symbolInformation)); + + symbolInformation.setTags(symbolTagsWithoutDeprecated); + + assertFalse(SymbolsUtil.isDeprecated(symbolInformation)); + } + + @Test + public void testDeprecatedCheckForWorkspaceSymbol() { + var workspaceSymbol = new WorkspaceSymbol(); + + assertFalse(SymbolsUtil.isDeprecated(workspaceSymbol)); + + workspaceSymbol.setTags(symbolTagsWithDeprecated); + + assertTrue(SymbolsUtil.isDeprecated(workspaceSymbol)); + + workspaceSymbol.setTags(symbolTagsWithoutDeprecated); + + assertFalse(SymbolsUtil.isDeprecated(workspaceSymbol)); + } + + @Test + public void testDeprecatedCheckForDocumentSymbol() { + var documentSymbol = new DocumentSymbol(); + + assertFalse(SymbolsUtil.isDeprecated(documentSymbol)); + + documentSymbol.setDeprecated(true); + + assertTrue(SymbolsUtil.isDeprecated(documentSymbol)); + + documentSymbol = new DocumentSymbol(); + documentSymbol.setTags(symbolTagsWithDeprecated); + + assertTrue(SymbolsUtil.isDeprecated(documentSymbol)); + + documentSymbol.setTags(symbolTagsWithoutDeprecated); + + assertFalse(SymbolsUtil.isDeprecated(documentSymbol)); + } + +} diff --git a/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/utils/LSPImagesTest.java b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/utils/LSPImagesTest.java new file mode 100644 index 000000000..23d806786 --- /dev/null +++ b/org.eclipse.lsp4e.test/src/org/eclipse/lsp4e/test/utils/LSPImagesTest.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2024 Advantest GmbH 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: + * Dietrich Travkin (Solunar GmbH) - initial implementation + *******************************************************************************/ +package org.eclipse.lsp4e.test.utils; + +import static org.junit.jupiter.api.Assertions.*; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.lsp4e.ui.LSPImages; +import org.eclipse.lsp4j.CompletionItem; +import org.eclipse.lsp4j.CompletionItemKind; +import org.eclipse.lsp4j.SymbolKind; +import org.eclipse.lsp4j.SymbolTag; +import org.eclipse.swt.graphics.Image; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; +import org.junit.jupiter.params.provider.EnumSource.Mode; + +public class LSPImagesTest { + + @ParameterizedTest + @EnumSource(SymbolKind.class) + public void testAllImagesForSymbolKindAvailable(SymbolKind kind) { + Image img = LSPImages.imageFromSymbolKind(kind); + + assertNotNull(img); + } + + @ParameterizedTest + @EnumSource(SymbolTag.class) + public void testAllOverlayImagesForSymbolTagAvailable(SymbolTag tag) { + ImageDescriptor descriptor = LSPImages.imageDescriptorOverlayFromSymbolTag(tag); + Image img = LSPImages.imageOverlayFromSymbolTag(tag); + + assertNotNull(descriptor); + assertNotNull(img); + } + + @ParameterizedTest + @EnumSource(value=CompletionItemKind.class, mode=Mode.EXCLUDE, names= { "Color", "Event", "Operator" }) + public void testAllImagesForCompletionItemKindAvailable(CompletionItemKind kind) { + CompletionItem item = new CompletionItem(); + item.setKind(kind); + + Image img = LSPImages.imageFromCompletionItem(item); + + assertNotNull(img); + } + +} diff --git a/org.eclipse.lsp4e/META-INF/MANIFEST.MF b/org.eclipse.lsp4e/META-INF/MANIFEST.MF index 40bfd4fef..8974d720c 100644 --- a/org.eclipse.lsp4e/META-INF/MANIFEST.MF +++ b/org.eclipse.lsp4e/META-INF/MANIFEST.MF @@ -28,8 +28,8 @@ Require-Bundle: org.eclipse.core.runtime;bundle-version="3.12.0", org.eclipse.tm4e.ui;resolution:=optional, org.eclipse.ui.editors, org.eclipse.ui.navigator;bundle-version="3.6.100", - org.eclipse.lsp4j;bundle-version="[0.24.0,0.25.0)", - org.eclipse.lsp4j.jsonrpc;bundle-version="[0.24.0,0.25.0)", + org.eclipse.lsp4j;bundle-version="[1.0.0,2.0.0)", + org.eclipse.lsp4j.jsonrpc;bundle-version="[1.0.0,2.0.0)", org.eclipse.ui.console, org.eclipse.ltk.core.refactoring, org.eclipse.core.expressions;bundle-version="3.5.0", diff --git a/org.eclipse.lsp4e/icons/full/obj16/constructor.png b/org.eclipse.lsp4e/icons/full/obj16/constructor.png index ab97bb71e..71e558555 100644 Binary files a/org.eclipse.lsp4e/icons/full/obj16/constructor.png and b/org.eclipse.lsp4e/icons/full/obj16/constructor.png differ diff --git a/org.eclipse.lsp4e/icons/full/obj16/constructor.svg b/org.eclipse.lsp4e/icons/full/obj16/constructor.svg index c1fdb7378..4a229c816 100644 --- a/org.eclipse.lsp4e/icons/full/obj16/constructor.svg +++ b/org.eclipse.lsp4e/icons/full/obj16/constructor.svg @@ -2,23 +2,23 @@ + inkscape:export-ydpi="96" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + inkscape:window-y="58" + inkscape:window-maximized="0" + inkscape:showpageshadow="0" + inkscape:pagecheckerboard="0" + inkscape:deskcolor="#505050"> + snapvisiblegridlinesonly="true" + originx="0" + originy="0" + spacingy="1" + spacingx="1" + units="px" /> @@ -467,19 +475,46 @@ id="tspan4209" x="4.8992257" y="938.64496" - style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:6.14256096px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#ffffff;fill-opacity:1">M - + style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:6.14256px;line-height:1.25;font-family:sans-serif;-inkscape-font-specification:'sans-serif Bold';fill:#ffffff;fill-opacity:1">M + + + id="path4163-4-0" + d="m 15.347633,1041.4132 v 0.5002 c 0,0 -0.532599,1.0498 -1.506129,1.0498 h -1.188536 c -0.515959,0 -1.124963,-0.7698 -1.124963,-0.9276 l -0.148438,-0.6884 v -0.8854" + style="fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.01003;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + + + + + diff --git a/org.eclipse.lsp4e/icons/full/obj16/constructor@2x.png b/org.eclipse.lsp4e/icons/full/obj16/constructor@2x.png index 92aab92e7..bcae997b3 100644 Binary files a/org.eclipse.lsp4e/icons/full/obj16/constructor@2x.png and b/org.eclipse.lsp4e/icons/full/obj16/constructor@2x.png differ diff --git a/org.eclipse.lsp4e/icons/full/ovr16/abstract_co.svg b/org.eclipse.lsp4e/icons/full/ovr16/abstract_co.svg new file mode 100644 index 000000000..416c9365f --- /dev/null +++ b/org.eclipse.lsp4e/icons/full/ovr16/abstract_co.svg @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/org.eclipse.lsp4e/icons/full/ovr16/constr_ovr.svg b/org.eclipse.lsp4e/icons/full/ovr16/constr_ovr.svg new file mode 100644 index 000000000..8c4fab343 --- /dev/null +++ b/org.eclipse.lsp4e/icons/full/ovr16/constr_ovr.svg @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/org.eclipse.lsp4e/icons/full/ovr16/declaration_co.svg b/org.eclipse.lsp4e/icons/full/ovr16/declaration_co.svg new file mode 100644 index 000000000..95c493013 --- /dev/null +++ b/org.eclipse.lsp4e/icons/full/ovr16/declaration_co.svg @@ -0,0 +1,1052 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/org.eclipse.lsp4e/icons/full/ovr16/definition_co.svg b/org.eclipse.lsp4e/icons/full/ovr16/definition_co.svg new file mode 100644 index 000000000..b106c342e --- /dev/null +++ b/org.eclipse.lsp4e/icons/full/ovr16/definition_co.svg @@ -0,0 +1,1052 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/org.eclipse.lsp4e/icons/full/ovr16/deprecated.svg b/org.eclipse.lsp4e/icons/full/ovr16/deprecated.svg new file mode 100644 index 000000000..76431fe24 --- /dev/null +++ b/org.eclipse.lsp4e/icons/full/ovr16/deprecated.svg @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/org.eclipse.lsp4e/icons/full/ovr16/file_visable_co.svg b/org.eclipse.lsp4e/icons/full/ovr16/file_visable_co.svg new file mode 100644 index 000000000..1f56b59cc --- /dev/null +++ b/org.eclipse.lsp4e/icons/full/ovr16/file_visable_co.svg @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/org.eclipse.lsp4e/icons/full/ovr16/final_co.svg b/org.eclipse.lsp4e/icons/full/ovr16/final_co.svg new file mode 100644 index 000000000..61c5103a6 --- /dev/null +++ b/org.eclipse.lsp4e/icons/full/ovr16/final_co.svg @@ -0,0 +1,159 @@ + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/org.eclipse.lsp4e/icons/full/ovr16/implement_co.svg b/org.eclipse.lsp4e/icons/full/ovr16/implement_co.svg new file mode 100644 index 000000000..d1325bddf --- /dev/null +++ b/org.eclipse.lsp4e/icons/full/ovr16/implement_co.svg @@ -0,0 +1,828 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/org.eclipse.lsp4e/icons/full/ovr16/internal_co.svg b/org.eclipse.lsp4e/icons/full/ovr16/internal_co.svg new file mode 100644 index 000000000..c6812a413 --- /dev/null +++ b/org.eclipse.lsp4e/icons/full/ovr16/internal_co.svg @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/org.eclipse.lsp4e/icons/full/ovr16/non_null_co.svg b/org.eclipse.lsp4e/icons/full/ovr16/non_null_co.svg new file mode 100644 index 000000000..fec5a6692 --- /dev/null +++ b/org.eclipse.lsp4e/icons/full/ovr16/non_null_co.svg @@ -0,0 +1,159 @@ + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/org.eclipse.lsp4e/icons/full/ovr16/nullable_co.svg b/org.eclipse.lsp4e/icons/full/ovr16/nullable_co.svg new file mode 100644 index 000000000..92bdf7366 --- /dev/null +++ b/org.eclipse.lsp4e/icons/full/ovr16/nullable_co.svg @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/org.eclipse.lsp4e/icons/full/ovr16/override_co.svg b/org.eclipse.lsp4e/icons/full/ovr16/override_co.svg new file mode 100644 index 000000000..ca6269a86 --- /dev/null +++ b/org.eclipse.lsp4e/icons/full/ovr16/override_co.svg @@ -0,0 +1,828 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/org.eclipse.lsp4e/icons/full/ovr16/package_co.svg b/org.eclipse.lsp4e/icons/full/ovr16/package_co.svg new file mode 100644 index 000000000..dee689a3b --- /dev/null +++ b/org.eclipse.lsp4e/icons/full/ovr16/package_co.svg @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/org.eclipse.lsp4e/icons/full/ovr16/private_co.svg b/org.eclipse.lsp4e/icons/full/ovr16/private_co.svg new file mode 100644 index 000000000..12ff1c672 --- /dev/null +++ b/org.eclipse.lsp4e/icons/full/ovr16/private_co.svg @@ -0,0 +1,4448 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/org.eclipse.lsp4e/icons/full/ovr16/protected_co.svg b/org.eclipse.lsp4e/icons/full/ovr16/protected_co.svg new file mode 100644 index 000000000..61e694bf6 --- /dev/null +++ b/org.eclipse.lsp4e/icons/full/ovr16/protected_co.svg @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/org.eclipse.lsp4e/icons/full/ovr16/public_co.svg b/org.eclipse.lsp4e/icons/full/ovr16/public_co.svg new file mode 100644 index 000000000..c72adc590 --- /dev/null +++ b/org.eclipse.lsp4e/icons/full/ovr16/public_co.svg @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/org.eclipse.lsp4e/icons/full/ovr16/read_only_co.svg b/org.eclipse.lsp4e/icons/full/ovr16/read_only_co.svg new file mode 100644 index 000000000..2aaecc516 --- /dev/null +++ b/org.eclipse.lsp4e/icons/full/ovr16/read_only_co.svg @@ -0,0 +1,263 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/org.eclipse.lsp4e/icons/full/ovr16/sealed_co.svg b/org.eclipse.lsp4e/icons/full/ovr16/sealed_co.svg new file mode 100644 index 000000000..b235e7d44 --- /dev/null +++ b/org.eclipse.lsp4e/icons/full/ovr16/sealed_co.svg @@ -0,0 +1,78 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/org.eclipse.lsp4e/icons/full/ovr16/static_co.svg b/org.eclipse.lsp4e/icons/full/ovr16/static_co.svg new file mode 100644 index 000000000..a94d9c822 --- /dev/null +++ b/org.eclipse.lsp4e/icons/full/ovr16/static_co.svg @@ -0,0 +1,78 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/org.eclipse.lsp4e/icons/full/ovr16/synch_co.svg b/org.eclipse.lsp4e/icons/full/ovr16/synch_co.svg new file mode 100644 index 000000000..abea286be --- /dev/null +++ b/org.eclipse.lsp4e/icons/full/ovr16/synch_co.svg @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/org.eclipse.lsp4e/icons/full/ovr16/transient_co.svg b/org.eclipse.lsp4e/icons/full/ovr16/transient_co.svg new file mode 100644 index 000000000..5f98881e1 --- /dev/null +++ b/org.eclipse.lsp4e/icons/full/ovr16/transient_co.svg @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + diff --git a/org.eclipse.lsp4e/icons/full/ovr16/virtual_co.svg b/org.eclipse.lsp4e/icons/full/ovr16/virtual_co.svg new file mode 100644 index 000000000..eb3e4d528 --- /dev/null +++ b/org.eclipse.lsp4e/icons/full/ovr16/virtual_co.svg @@ -0,0 +1,86 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/org.eclipse.lsp4e/icons/full/ovr16/volatile_co.svg b/org.eclipse.lsp4e/icons/full/ovr16/volatile_co.svg new file mode 100644 index 000000000..979eda22c --- /dev/null +++ b/org.eclipse.lsp4e/icons/full/ovr16/volatile_co.svg @@ -0,0 +1,76 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/IMarkerAttributeComputer.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/IMarkerAttributeComputer.java index 90c4ea3dc..805fc07bf 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/IMarkerAttributeComputer.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/IMarkerAttributeComputer.java @@ -16,6 +16,7 @@ import org.eclipse.core.resources.IResource; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.text.IDocument; +import org.eclipse.lsp4e.internal.NullSafetyHelper; import org.eclipse.lsp4j.Diagnostic; import org.eclipse.lsp4j.jsonrpc.messages.Either; @@ -48,8 +49,9 @@ void addMarkerAttributesForDiagnostic(Diagnostic diagnostic, @Nullable IDocument */ default String computeMarkerMessage(Diagnostic diagnostic) { final Either code = diagnostic.getCode(); + String messageText = NullSafetyHelper.defaultIfNull(diagnostic.getMessage().getLeft(), ""); //$NON-NLS-1$ return code == null // - ? diagnostic.getMessage() - : diagnostic.getMessage() + " [" + code.get() + "]"; //$NON-NLS-1$//$NON-NLS-2$ + ? messageText + : messageText + " [" + code.get() + "]"; //$NON-NLS-1$//$NON-NLS-2$ } } diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/LSPEclipseUtils.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/LSPEclipseUtils.java index 7270449ba..6f41a4c29 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/LSPEclipseUtils.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/LSPEclipseUtils.java @@ -21,7 +21,7 @@ *******************************************************************************/ package org.eclipse.lsp4e; -import static org.eclipse.lsp4e.internal.NullSafetyHelper.castNonNull; +import static org.eclipse.lsp4e.internal.NullSafetyHelper.*; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -121,6 +121,7 @@ import org.eclipse.lsp4j.RenameFile; import org.eclipse.lsp4j.ResourceOperation; import org.eclipse.lsp4j.SignatureHelpParams; +import org.eclipse.lsp4j.SnippetTextEdit; import org.eclipse.lsp4j.TextDocumentEdit; import org.eclipse.lsp4j.TextDocumentIdentifier; import org.eclipse.lsp4j.TextDocumentPositionParams; @@ -1078,7 +1079,8 @@ private static boolean applyWorkspaceEditIfSingleOpenFile(WorkspaceEdit wsEdit) .map(TextDocumentIdentifier::getUri) .map(LSPEclipseUtils::toUri) .forEach(documentUris::add); - firstDocumentEdits.addAll(wsEdit.getDocumentChanges().get(0).getLeft().getEdits()); + firstDocumentEdits.addAll(toTextEditList( + wsEdit.getDocumentChanges().get(0).getLeft().getEdits())); } } if (documentUris.size() != 1 || firstDocumentEdits.isEmpty()) { @@ -1140,7 +1142,7 @@ private static CompositeChange toCompositeChange(WorkspaceEdit wsEdit, String na TextDocumentEdit edit = action.getLeft(); VersionedTextDocumentIdentifier id = edit.getTextDocument(); URI uri = URI.create(id.getUri()); - List textEdits = edit.getEdits(); + List textEdits = toTextEditList(edit.getEdits()); change.add(toChanges(uri, textEdits)); collectChangedURI(uri, textEdits, collector); } else if (action.isRight()) { @@ -1238,6 +1240,13 @@ private static CompositeChange toCompositeChange(WorkspaceEdit wsEdit, String na return change; } + private static final List toTextEditList(List> textEdits) { + return textEdits.stream() + .filter(e -> e.isLeft()) + .map(e -> e.getLeft()) + .toList(); + } + private static final Range DEFAULT_RANGE = new Range(new Position(0, 0), new Position(0, 0)); /** diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/LanguageServerPlugin.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/LanguageServerPlugin.java index 0e95f700c..fe59b9bcb 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/LanguageServerPlugin.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/LanguageServerPlugin.java @@ -64,8 +64,13 @@ public void start(BundleContext context) throws Exception { @Override public void stop(BundleContext context) throws Exception { plugin = null; - LanguageServiceAccessor.shutdownAllDispatchers(); - super.stop(context); + try { + LanguageServiceAccessor.shutdownAllDispatchers(); + LSPImages.dispose(); + } + finally { + super.stop(context); + } } /** diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/callhierarchy/CallHierarchyLabelProvider.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/callhierarchy/CallHierarchyLabelProvider.java index cc874037c..ba671714c 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/callhierarchy/CallHierarchyLabelProvider.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/callhierarchy/CallHierarchyLabelProvider.java @@ -29,7 +29,7 @@ public class CallHierarchyLabelProvider extends LabelProvider implements IStyled public @Nullable Image getImage(final @Nullable Object element) { if (element instanceof CallHierarchyViewTreeNode treeNode) { CallHierarchyItem callContainer = treeNode.getCallContainer(); - Image res = LSPImages.imageFromSymbolKind(callContainer.getKind()); + Image res = LSPImages.getImageFor(callContainer.getKind(), callContainer.getTags()); if (res != null) { return res; } diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/internal/SupportedFeatures.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/internal/SupportedFeatures.java index f674b4eed..f8c3615c8 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/internal/SupportedFeatures.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/internal/SupportedFeatures.java @@ -57,6 +57,8 @@ import org.eclipse.lsp4j.SymbolCapabilities; import org.eclipse.lsp4j.SymbolKind; import org.eclipse.lsp4j.SymbolKindCapabilities; +import org.eclipse.lsp4j.SymbolTag; +import org.eclipse.lsp4j.SymbolTagSupportCapabilities; import org.eclipse.lsp4j.SynchronizationCapabilities; import org.eclipse.lsp4j.TextDocumentClientCapabilities; import org.eclipse.lsp4j.TypeDefinitionCapabilities; @@ -120,6 +122,7 @@ public static TextDocumentClientCapabilities getTextDocumentClientCapabilities() final var documentSymbol = new DocumentSymbolCapabilities(); documentSymbol.setHierarchicalDocumentSymbolSupport(true); documentSymbol.setSymbolKind(new SymbolKindCapabilities(List.of(SymbolKind.values()))); + documentSymbol.setTagSupport(new SymbolTagSupportCapabilities(List.of(SymbolTag.values()))); textDocumentClientCapabilities.setDocumentSymbol(documentSymbol); final var foldingRangeCapabilities = new FoldingRangeCapabilities(); foldingRangeCapabilities.setLineFoldingOnly(true); @@ -153,7 +156,9 @@ public static WorkspaceClientCapabilities getWorkspaceClientCapabilities() { workspaceClientCapabilities.setApplyEdit(true); workspaceClientCapabilities.setConfiguration(true); workspaceClientCapabilities.setExecuteCommand(new ExecuteCommandCapabilities(true)); - workspaceClientCapabilities.setSymbol(new SymbolCapabilities(true)); + SymbolCapabilities symbolCapabilities = new SymbolCapabilities(true); + symbolCapabilities.setTagSupport(new SymbolTagSupportCapabilities(List.of(SymbolTag.values()))); + workspaceClientCapabilities.setSymbol(symbolCapabilities); workspaceClientCapabilities.setWorkspaceFolders(true); final var editCapabilities = new WorkspaceEditCapabilities(); diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/symbols/SymbolsUtil.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/symbols/SymbolsUtil.java new file mode 100644 index 000000000..884645904 --- /dev/null +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/symbols/SymbolsUtil.java @@ -0,0 +1,188 @@ +/******************************************************************************* + * Copyright (c) 2024 Advantest GmbH 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: + * Dietrich Travkin (Solunar GmbH) - initial implementation + *******************************************************************************/ +package org.eclipse.lsp4e.operations.symbols; + +import java.util.Collections; +import java.util.List; + +import org.eclipse.lsp4e.outline.SymbolsModel.DocumentSymbolWithURI; +import org.eclipse.lsp4j.DocumentSymbol; +import org.eclipse.lsp4j.SymbolInformation; +import org.eclipse.lsp4j.SymbolKind; +import org.eclipse.lsp4j.SymbolTag; +import org.eclipse.lsp4j.WorkspaceSymbol; + +public class SymbolsUtil { + + public static SymbolKind getKind(SymbolInformation symbolInformation) { + return symbolInformation.getKind(); + } + + public static SymbolKind getKind(WorkspaceSymbol workspaceSymbol) { + return workspaceSymbol.getKind(); + } + + public static SymbolKind getKind(DocumentSymbol documentSymbol) { + return documentSymbol.getKind(); + } + + public static SymbolKind getKind(DocumentSymbolWithURI documentSymbolWithUri) { + return getKind(documentSymbolWithUri.symbol); + } + + public static List getSymbolTags(SymbolInformation symbolInformation) { + if (symbolInformation.getTags() != null) { + return symbolInformation.getTags(); + } + + return Collections.emptyList(); + } + + public static List getSymbolTags(WorkspaceSymbol workspaceSymbol) { + if (workspaceSymbol.getTags() != null) { + return workspaceSymbol.getTags(); + } + + return Collections.emptyList(); + } + + public static List getSymbolTags(DocumentSymbol documentSymbol) { + if (documentSymbol.getTags() != null) { + return documentSymbol.getTags(); + } + + return Collections.emptyList(); + } + + public static List getSymbolTags(DocumentSymbolWithURI documentSymbolWithUri) { + return getSymbolTags(documentSymbolWithUri.symbol); + } + + public static boolean hasSymbolTag(List tagList, SymbolTag tag) { + return tagList.contains(tag); + } + + public static boolean hasSymbolTag(SymbolInformation symbolInformation, SymbolTag tag) { + return getSymbolTags(symbolInformation).contains(tag); + } + + public static boolean hasSymbolTag(WorkspaceSymbol workspaceSymbol, SymbolTag tag) { + return getSymbolTags(workspaceSymbol).contains(tag); + } + + public static boolean hasSymbolTag(DocumentSymbol documentSymbol, SymbolTag tag) { + return getSymbolTags(documentSymbol).contains(tag); + } + + public static boolean hasSymbolTag(DocumentSymbolWithURI documentSymbolWithUri, SymbolTag tag) { + return getSymbolTags(documentSymbolWithUri).contains(tag); + } + + public static boolean isDeprecated(SymbolInformation symbolInformation) { + boolean deprecated = isDeprecated(getSymbolTags(symbolInformation)); + return deprecated || (symbolInformation.getDeprecated() == null ? false: symbolInformation.getDeprecated()); + } + + public static boolean isDeprecated(WorkspaceSymbol workspaceSymbol) { + return isDeprecated(getSymbolTags(workspaceSymbol)); + } + + public static boolean isDeprecated(DocumentSymbol documentSymbol) { + boolean deprecated = isDeprecated(getSymbolTags(documentSymbol)); + return deprecated || (documentSymbol.getDeprecated() == null ? false: documentSymbol.getDeprecated()); + } + + public static boolean isDeprecated(DocumentSymbolWithURI documentSymbolWithUri) { + return isDeprecated(documentSymbolWithUri.symbol); + } + + public static boolean isDeprecated(List tags) { + return SymbolsUtil.hasSymbolTag(tags, SymbolTag.Deprecated); + } + + public static boolean isPrivate(List tags) { + return SymbolsUtil.hasSymbolTag(tags, SymbolTag.Private); + } + + public static boolean isPackage(List tags) { + return SymbolsUtil.hasSymbolTag(tags, SymbolTag.Package); + } + + public static boolean isProtected(List tags) { + return SymbolsUtil.hasSymbolTag(tags, SymbolTag.Protected); + } + + public static boolean isPublic(List tags) { + return SymbolsUtil.hasSymbolTag(tags, SymbolTag.Public); + } + + public static boolean isInternal(List tags) { + return SymbolsUtil.hasSymbolTag(tags, SymbolTag.Internal); + } + + public static boolean isFileVisible(List tags) { + return SymbolsUtil.hasSymbolTag(tags, SymbolTag.File); + } + + public static boolean isStatic(List tags) { + return SymbolsUtil.hasSymbolTag(tags, SymbolTag.Static); + } + + public static boolean isAbstract(List tags) { + return SymbolsUtil.hasSymbolTag(tags, SymbolTag.Abstract); + } + + public static boolean isFinal(List tags) { + return SymbolsUtil.hasSymbolTag(tags, SymbolTag.Final); + } + + public static boolean isSealed(List tags) { + return SymbolsUtil.hasSymbolTag(tags, SymbolTag.Sealed); + } + + public static boolean isTransient(List tags) { + return SymbolsUtil.hasSymbolTag(tags, SymbolTag.Transient); + } + + public static boolean isVolatile(List tags) { + return SymbolsUtil.hasSymbolTag(tags, SymbolTag.Volatile); + } + + public static boolean isSynchronized(List tags) { + return SymbolsUtil.hasSymbolTag(tags, SymbolTag.Synchronized); + } + + public static boolean isVirtual(List tags) { + return SymbolsUtil.hasSymbolTag(tags, SymbolTag.Virtual); + } + + public static boolean isNullable(List tags) { + return SymbolsUtil.hasSymbolTag(tags, SymbolTag.Nullable); + } + + public static boolean isNonNull(List tags) { + return SymbolsUtil.hasSymbolTag(tags, SymbolTag.NonNull); + } + + public static boolean isDeclaration(List tags) { + return SymbolsUtil.hasSymbolTag(tags, SymbolTag.Declaration); + } + + public static boolean isDefinition(List tags) { + return SymbolsUtil.hasSymbolTag(tags, SymbolTag.Definition); + } + + public static boolean isReadOnly(List tags) { + return SymbolsUtil.hasSymbolTag(tags, SymbolTag.ReadOnly); + } + +} diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/typeHierarchy/TypeHierarchyItemLabelProvider.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/typeHierarchy/TypeHierarchyItemLabelProvider.java index 1cea86359..c4f4841cd 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/typeHierarchy/TypeHierarchyItemLabelProvider.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/typeHierarchy/TypeHierarchyItemLabelProvider.java @@ -29,7 +29,7 @@ public String getText(Object element) { @Override public @Nullable Image getImage(@Nullable Object element) { if (element instanceof TypeHierarchyItem item) { - return LSPImages.imageFromSymbolKind(item.getKind()); + return LSPImages.getImageFor(item.getKind(), item.getTags()); } return element == null ? null : super.getImage(element); } diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/outline/SymbolsLabelProvider.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/outline/SymbolsLabelProvider.java index 69720ffbc..b53341f7e 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/outline/SymbolsLabelProvider.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/outline/SymbolsLabelProvider.java @@ -11,16 +11,15 @@ *******************************************************************************/ package org.eclipse.lsp4e.outline; -import static org.eclipse.lsp4e.LSPEclipseUtils.findResourceFor; -import static org.eclipse.lsp4e.internal.NullSafetyHelper.castNullable; +import static org.eclipse.lsp4e.LSPEclipseUtils.*; import java.net.URI; import java.util.Arrays; +import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Objects; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IResource; @@ -35,9 +34,7 @@ import org.eclipse.jface.resource.JFaceResources; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; -import org.eclipse.jface.viewers.DecorationOverlayIcon; import org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider.IStyledLabelProvider; -import org.eclipse.jface.viewers.IDecoration; import org.eclipse.jface.viewers.ILabelProviderListener; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.LabelProviderChangedEvent; @@ -45,6 +42,7 @@ import org.eclipse.lsp4e.LSPEclipseUtils; import org.eclipse.lsp4e.LanguageServerPlugin; import org.eclipse.lsp4e.internal.StyleUtil; +import org.eclipse.lsp4e.operations.symbols.SymbolsUtil; import org.eclipse.lsp4e.outline.SymbolsModel.DocumentSymbolWithURI; import org.eclipse.lsp4e.ui.LSPImages; import org.eclipse.lsp4e.ui.Messages; @@ -87,11 +85,7 @@ public class SymbolsLabelProvider extends LabelProvider LanguageServerPlugin.logError(ex); } }; - /* - * key: initial object image - * value: array of images decorated with marker for severity (index + 1) - */ - private final Map overlays = new HashMap<>(); + private final Map resourceCache = new HashMap<>(); private final boolean showLocation; @@ -114,14 +108,16 @@ public SymbolsLabelProvider(boolean showLocation, boolean showKind) { public void dispose() { ResourcesPlugin.getWorkspace().removeResourceChangeListener(listener); InstanceScope.INSTANCE.getNode(LanguageServerPlugin.PLUGIN_ID).removePreferenceChangeListener(this); - overlays.values().stream().flatMap(Arrays::stream).filter(Objects::nonNull).forEach(Image::dispose); - overlays.clear(); super.dispose(); } @Override public @Nullable Image getImage(@Nullable Object element) { - if (element == null) { + // If needed, we could use more overlays like in org.eclipse.jdt.ui.JavaElementImageDescriptor, + // but this would demand more space in various views. + // See guidelines, Section "Icon Overlays": https://www.eclipse.org/articles/Article-UI-Guidelines/Contents.html + + if (element == null){ return null; } if (element instanceof PendingUpdateAdapter) { @@ -133,26 +129,48 @@ public void dispose() { if (element instanceof Either either) { element = either.get(); } + SymbolKind symbolKind = null; + List symbolTags = Collections.emptyList(); + boolean deprecated = false; + if (element instanceof SymbolInformation info) { + symbolKind = SymbolsUtil.getKind(info); + symbolTags = SymbolsUtil.getSymbolTags(info); + deprecated = SymbolsUtil.isDeprecated(info); + } else if (element instanceof WorkspaceSymbol symbol) { + symbolKind = SymbolsUtil.getKind(symbol); + symbolTags = SymbolsUtil.getSymbolTags(symbol); + deprecated = SymbolsUtil.isDeprecated(symbol); + } else if (element instanceof DocumentSymbol symbol) { + symbolKind = SymbolsUtil.getKind(symbol); + symbolTags = SymbolsUtil.getSymbolTags(symbol); + deprecated = SymbolsUtil.isDeprecated(symbol); + } else if (element instanceof DocumentSymbolWithURI symbolWithURI) { + symbolKind = SymbolsUtil.getKind(symbolWithURI); + symbolTags = SymbolsUtil.getSymbolTags(symbolWithURI); + deprecated = SymbolsUtil.isDeprecated(symbolWithURI); + } + + if (element != null && symbolKind != null) { + return LSPImages.getImageFor(symbolKind, symbolTags, deprecated, getMaxSeverity(element)); + } + + return null; + } - Image image = null; + private int getMaxSeverity(Object element) { IResource file = null; if (element instanceof SymbolInformation info) { - image = LSPImages.imageFromSymbolKind(info.getKind()); file = resourceCache.computeIfAbsent(info.getLocation().getUri(), uri -> findResourceFor((String) uri)); } else if (element instanceof WorkspaceSymbol symbol) { - image = LSPImages.imageFromSymbolKind(symbol.getKind()); file = resourceCache.computeIfAbsent(getUri(symbol), uri -> findResourceFor((String) uri)); - } else if (element instanceof DocumentSymbol symbol) { - image = LSPImages.imageFromSymbolKind(symbol.getKind()); } else if (element instanceof DocumentSymbolWithURI symbolWithURI) { - image = LSPImages.imageFromSymbolKind(symbolWithURI.symbol.getKind()); file = resourceCache.computeIfAbsent(symbolWithURI.uri, uri -> findResourceFor((URI) uri)); } /* * Implementation node: for problem decoration, maybe consider using a ILabelDecorator/IDelayedLabelDecorator? */ - if (file != null && image != null) { + if (file != null) { Range range = null; if (element instanceof SymbolInformation symbol) { range = symbol.getLocation().getRange(); @@ -163,6 +181,7 @@ public void dispose() { } else if (element instanceof DocumentSymbolWithURI symbolWithURI) { range = symbolWithURI.symbol.getRange(); } + if (range != null) { try { // use existing documents only to calculate the severity @@ -171,17 +190,14 @@ public void dispose() { IDocument doc = LSPEclipseUtils.getExistingDocument(file); if (doc != null) { - int maxSeverity = getMaxSeverity(file, doc, range); - if (maxSeverity > IMarker.SEVERITY_INFO) { - return getOverlay(image, maxSeverity); - } + return getMaxSeverity(file, doc, range); } } catch (CoreException | BadLocationException e) { LanguageServerPlugin.logError(e); } } } - return image; + return -1; } protected int getMaxSeverity(IResource resource, IDocument doc, Range range) @@ -228,24 +244,6 @@ private void refreshMarkersByLine(IResource resource) throws CoreException { severities.put(resource, rangeMap); } - private Image getOverlay(Image res, int maxSeverity) { - if (maxSeverity != 1 && maxSeverity != 2) { - throw new IllegalArgumentException("Severity " + maxSeverity + " not supported."); //$NON-NLS-1$ //$NON-NLS-2$ - } - Image[] currentOverlays = this.overlays.computeIfAbsent(res, key -> new Image [2]); - if (castNullable(currentOverlays[maxSeverity - 1]) == null) { - String overlayId = null; - if (maxSeverity == IMarker.SEVERITY_ERROR) { - overlayId = ISharedImages.IMG_DEC_FIELD_ERROR; - } else if (maxSeverity == IMarker.SEVERITY_WARNING) { - overlayId = ISharedImages.IMG_DEC_FIELD_WARNING; - } - currentOverlays[maxSeverity - 1] = new DecorationOverlayIcon(res, - LSPImages.getSharedImageDescriptor(overlayId), IDecoration.BOTTOM_LEFT).createImage(); - } - return currentOverlays[maxSeverity - 1]; - } - @Override public String getText(Object element) { return getStyledText(element).getString(); @@ -279,7 +277,7 @@ public StyledString getStyledText(@Nullable Object element) { if (element instanceof SymbolInformation symbolInformation) { name = symbolInformation.getName(); kind = symbolInformation.getKind(); - deprecated = isDeprecated(symbolInformation.getTags()) || symbolInformation.getDeprecated() != null && symbolInformation.getDeprecated(); + deprecated = SymbolsUtil.isDeprecated(symbolInformation); try { location = URI.create(symbolInformation.getLocation().getUri()); } catch (IllegalArgumentException e) { @@ -289,7 +287,7 @@ public StyledString getStyledText(@Nullable Object element) { name = workspaceSymbol.getName(); kind = workspaceSymbol.getKind(); String rawUri = getUri(workspaceSymbol); - deprecated = isDeprecated(workspaceSymbol.getTags()); + deprecated = SymbolsUtil.isDeprecated(workspaceSymbol); try { location = URI.create(rawUri); } catch (IllegalArgumentException e) { @@ -299,13 +297,13 @@ public StyledString getStyledText(@Nullable Object element) { name = documentSymbol.getName(); kind = documentSymbol.getKind(); detail = documentSymbol.getDetail(); - deprecated = isDeprecated(documentSymbol.getTags()) || documentSymbol.getDeprecated() != null && documentSymbol.getDeprecated(); + deprecated = SymbolsUtil.isDeprecated(documentSymbol); } else if (element instanceof DocumentSymbolWithURI symbolWithURI) { name = symbolWithURI.symbol.getName(); kind = symbolWithURI.symbol.getKind(); detail = symbolWithURI.symbol.getDetail(); location = symbolWithURI.uri; - deprecated = isDeprecated(symbolWithURI.symbol.getTags()) || symbolWithURI.symbol.getDeprecated() != null && symbolWithURI.symbol.getDeprecated(); + deprecated = SymbolsUtil.isDeprecated(symbolWithURI); } if (name != null) { if (deprecated) { @@ -332,13 +330,6 @@ public StyledString getStyledText(@Nullable Object element) { return res; } - private boolean isDeprecated(@Nullable List tags) { - if(tags != null){ - return tags.contains(SymbolTag.Deprecated); - } - return false; - } - @Override public void restoreState(final IMemento aMemento) { } diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/ui/LSPImages.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/ui/LSPImages.java index 88bb6bfcf..b066e3b92 100644 --- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/ui/LSPImages.java +++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/ui/LSPImages.java @@ -8,23 +8,35 @@ * * Contributors: * Michał Niewrzał (Rogue Wave Software Inc.) - initial implementation + * Dietrich Travkin (Solunar GmbH) - add overlay images computation, dispose cached images *******************************************************************************/ package org.eclipse.lsp4e.ui; import java.net.URL; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.eclipse.core.resources.IMarker; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; import org.eclipse.jdt.annotation.Nullable; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.resource.ImageRegistry; +import org.eclipse.jface.viewers.DecorationOverlayIcon; import org.eclipse.lsp4e.LSPEclipseUtils; import org.eclipse.lsp4e.LanguageServerPlugin; +import org.eclipse.lsp4e.operations.symbols.SymbolsUtil; import org.eclipse.lsp4j.CompletionItem; import org.eclipse.lsp4j.SymbolKind; +import org.eclipse.lsp4j.SymbolTag; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; @@ -40,10 +52,24 @@ private LSPImages() { } private static @Nullable ImageRegistry imageRegistry; + private static final Map colorToImageCache = new HashMap<>(); + + /** + * Cache for symbol images with various overlays and / or an underlay. + * + * First key: the element's kind (e.g. class or method); + * Second key: hash value calculated for a set of overlay image descriptors, + * see {@link #getImageWithOverlays(SymbolKind, ImageDescriptor[])}; + * Value: the base image with overlays and an optional underlay combined in one image. + */ + private static final Map> overlayImagesCache = new HashMap<>(); + private static final String ICONS_PATH = "$nl$/icons/full/"; //$NON-NLS-1$ private static final String OBJECT = ICONS_PATH + "obj16/"; // basic colors - size 16x16 //$NON-NLS-1$ private static final String ACTION = ICONS_PATH + "elcl16/"; // basic colors - size 16x16 //$NON-NLS-1$ + private static final String OVERLAY = ICONS_PATH + "ovr16/"; // basic colors - size 7x8 and 14x16 //$NON-NLS-1$ + private static final Image EMPTY_IMAGE = new Image(UI.getDisplay(), 16, 16); public static final String IMG_MODULE = "IMG_MODULE"; //$NON-NLS-1$ @@ -80,6 +106,31 @@ private LSPImages() { public static final String IMG_SUPERTYPE = "IMG_SUPERTYPE"; //$NON-NLS-1$ public static final String IMG_SUBTYPE = "IMG_SUBTYPE"; //$NON-NLS-1$ + public static final String IMG_OVR_CONSTRUCTOR = "IMG_OVR_CONSTRUCTOR"; //$NON-NLS-1$ + public static final String IMG_OVR_DEPRECATED = "IMG_OVR_DEPRECATED"; //$NON-NLS-1$ + public static final String IMG_OVR_PRIVATE = "IMG_OVR_PRIVATE"; //$NON-NLS-1$ + public static final String IMG_OVR_PACKAGE = "IMG_OVR_PACKAGE"; //$NON-NLS-1$ + public static final String IMG_OVR_PROTECTED = "IMG_OVR_PROTECTED"; //$NON-NLS-1$ + public static final String IMG_OVR_PUBLIC = "IMG_OVR_PUBLIC"; //$NON-NLS-1$ + public static final String IMG_OVR_INTERNAL = "IMG_OVR_INTERNAL"; //$NON-NLS-1$ + public static final String IMG_OVR_FILE_VIS = "IMG_OVR_FILE_VIS"; //$NON-NLS-1$ + public static final String IMG_OVR_ABSTRACT = "IMG_OVR_ABSTRACT"; //$NON-NLS-1$ + public static final String IMG_OVR_VIRTUAL = "IMG_OVR_VIRTUAL"; //$NON-NLS-1$ + public static final String IMG_OVR_FINAL = "IMG_OVR_FINAL"; //$NON-NLS-1$ + public static final String IMG_OVR_SEALED = "IMG_OVR_SEALED"; //$NON-NLS-1$ + public static final String IMG_OVR_STATIC = "IMG_OVR_STATIC"; //$NON-NLS-1$ + public static final String IMG_OVR_SYNC = "IMG_OVR_SYNC"; //$NON-NLS-1$ + public static final String IMG_OVR_TRANSIENT = "IMG_OVR_TRANSIENT"; //$NON-NLS-1$ + public static final String IMG_OVR_VOLATILE = "IMG_OVR_VOLATILE"; //$NON-NLS-1$ + public static final String IMG_OVR_NULLABLE = "IMG_OVR_NULLABLE"; //$NON-NLS-1$ + public static final String IMG_OVR_NON_NULL = "IMG_OVR_NON_NULL"; //$NON-NLS-1$ + public static final String IMG_OVR_DECLARATION = "IMG_OVR_DECLARATION"; //$NON-NLS-1$ + public static final String IMG_OVR_DEFINITION = "IMG_OVR_DEFINITION"; //$NON-NLS-1$ + public static final String IMG_OVR_READ_ONLY = "IMG_OVR_READ_ONLY"; //$NON-NLS-1$ + public static final String IMG_OVR_IMPLEMENT = "IMG_OVR_IMPLEMENT"; //$NON-NLS-1$ + public static final String IMG_OVR_OVERRIDE = "IMG_OVR_OVERRIDE"; //$NON-NLS-1$ + + public static void initalize(ImageRegistry registry) { imageRegistry = registry; @@ -116,6 +167,30 @@ public static void initalize(ImageRegistry registry) { declareRegistryImage(IMG_SUPERTYPE, ACTION + "super_co.png"); //$NON-NLS-1$ declareRegistryImage(IMG_SUBTYPE, ACTION + "sub_co.png"); //$NON-NLS-1$ declareRegistryImage(IMG_TERMINATE_CO, OBJECT + "terminate_co.png"); //$NON-NLS-1$ + + declareRegistryImage(IMG_OVR_CONSTRUCTOR, OVERLAY + "constr_ovr.svg"); //$NON-NLS-1$ + declareRegistryImage(IMG_OVR_DEPRECATED, OVERLAY + "deprecated.svg"); //$NON-NLS-1$ + declareRegistryImage(IMG_OVR_PRIVATE, OVERLAY + "private_co.svg"); //$NON-NLS-1$ + declareRegistryImage(IMG_OVR_PACKAGE, OVERLAY + "package_co.svg"); //$NON-NLS-1$ + declareRegistryImage(IMG_OVR_PROTECTED, OVERLAY + "protected_co.svg"); //$NON-NLS-1$ + declareRegistryImage(IMG_OVR_PUBLIC, OVERLAY + "public_co.svg"); //$NON-NLS-1$ + declareRegistryImage(IMG_OVR_INTERNAL, OVERLAY + "internal_co.svg"); //$NON-NLS-1$ + declareRegistryImage(IMG_OVR_FILE_VIS, OVERLAY + "file_visable_co.svg"); //$NON-NLS-1$ + declareRegistryImage(IMG_OVR_ABSTRACT, OVERLAY + "abstract_co.svg"); //$NON-NLS-1$ + declareRegistryImage(IMG_OVR_VIRTUAL, OVERLAY + "virtual_co.svg"); //$NON-NLS-1$ + declareRegistryImage(IMG_OVR_FINAL, OVERLAY + "final_co.svg"); //$NON-NLS-1$ + declareRegistryImage(IMG_OVR_SEALED, OVERLAY + "sealed_co.svg"); //$NON-NLS-1$ + declareRegistryImage(IMG_OVR_STATIC, OVERLAY + "static_co.svg"); //$NON-NLS-1$ + declareRegistryImage(IMG_OVR_SYNC, OVERLAY + "synch_co.svg"); //$NON-NLS-1$ + declareRegistryImage(IMG_OVR_TRANSIENT, OVERLAY + "transient_co.svg"); //$NON-NLS-1$ + declareRegistryImage(IMG_OVR_VOLATILE, OVERLAY + "volatile_co.svg"); //$NON-NLS-1$ + declareRegistryImage(IMG_OVR_NULLABLE, OVERLAY + "nullable_co.svg"); //$NON-NLS-1$ + declareRegistryImage(IMG_OVR_NON_NULL, OVERLAY + "non_null_co.svg"); //$NON-NLS-1$ + declareRegistryImage(IMG_OVR_DECLARATION, OVERLAY + "declaration_co.svg"); //$NON-NLS-1$ + declareRegistryImage(IMG_OVR_DEFINITION, OVERLAY + "definition_co.svg"); //$NON-NLS-1$ + declareRegistryImage(IMG_OVR_READ_ONLY, OVERLAY + "read_only_co.svg"); //$NON-NLS-1$ + declareRegistryImage(IMG_OVR_IMPLEMENT, OVERLAY + "implement_co.svg"); //$NON-NLS-1$ + declareRegistryImage(IMG_OVR_OVERRIDE, OVERLAY + "override_co.svg"); //$NON-NLS-1$ } private static void declareRegistryImage(String key, String path) { @@ -235,6 +310,56 @@ public static ImageRegistry getImageRegistry() { }; } + public static @Nullable Image imageOverlayFromSymbolTag(SymbolTag symbolTag) { + return switch (symbolTag) { + case Deprecated -> getImage(IMG_OVR_DEPRECATED); + case Private -> getImage(IMG_OVR_PRIVATE); + case Package -> getImage(IMG_OVR_PACKAGE); + case Protected -> getImage(IMG_OVR_PROTECTED); + case Public -> getImage(IMG_OVR_PUBLIC); + case Internal -> getImage(IMG_OVR_INTERNAL); + case File -> getImage(IMG_OVR_FILE_VIS); + case Static -> getImage(IMG_OVR_STATIC); + case Abstract -> getImage(IMG_OVR_ABSTRACT); + case Final -> getImage(IMG_OVR_FINAL); + case Sealed -> getImage(IMG_OVR_SEALED); + case Transient -> getImage(IMG_OVR_TRANSIENT); + case Volatile -> getImage(IMG_OVR_VOLATILE); + case Synchronized -> getImage(IMG_OVR_SYNC); + case Virtual -> getImage(IMG_OVR_VIRTUAL); + case Nullable -> getImage(IMG_OVR_NULLABLE); + case NonNull -> getImage(IMG_OVR_NON_NULL); + case Declaration -> getImage(IMG_OVR_DECLARATION); + case Definition -> getImage(IMG_OVR_DEFINITION); + case ReadOnly -> getImage(IMG_OVR_READ_ONLY); + }; + } + + public static @Nullable ImageDescriptor imageDescriptorOverlayFromSymbolTag(SymbolTag symbolTag) { + return switch (symbolTag) { + case Deprecated -> getImageDescriptor(IMG_OVR_DEPRECATED); + case Private -> getImageDescriptor(IMG_OVR_PRIVATE); + case Package -> getImageDescriptor(IMG_OVR_PACKAGE); + case Protected -> getImageDescriptor(IMG_OVR_PROTECTED); + case Public -> getImageDescriptor(IMG_OVR_PUBLIC); + case Internal -> getImageDescriptor(IMG_OVR_INTERNAL); + case File -> getImageDescriptor(IMG_OVR_FILE_VIS); + case Static -> getImageDescriptor(IMG_OVR_STATIC); + case Abstract -> getImageDescriptor(IMG_OVR_ABSTRACT); + case Final -> getImageDescriptor(IMG_OVR_FINAL); + case Sealed -> getImageDescriptor(IMG_OVR_SEALED); + case Transient -> getImageDescriptor(IMG_OVR_TRANSIENT); + case Volatile -> getImageDescriptor(IMG_OVR_VOLATILE); + case Synchronized -> getImageDescriptor(IMG_OVR_SYNC); + case Virtual -> getImageDescriptor(IMG_OVR_VIRTUAL); + case Nullable -> getImageDescriptor(IMG_OVR_NULLABLE); + case NonNull -> getImageDescriptor(IMG_OVR_NON_NULL); + case Declaration -> getImageDescriptor(IMG_OVR_DECLARATION); + case Definition -> getImageDescriptor(IMG_OVR_DEFINITION); + case ReadOnly -> getImageDescriptor(IMG_OVR_READ_ONLY); + }; + } + private static @Nullable Image getImageForColor(CompletionItem completionItem) { String hexValue = null; @@ -269,4 +394,183 @@ public static ImageRegistry getImageRegistry() { return image; }); } + + private static final List VISIBILITY_PRECEDENCE = Arrays.asList(new SymbolTag[] { + SymbolTag.Public, SymbolTag.Protected, SymbolTag.Package, SymbolTag.Private, + SymbolTag.Internal, SymbolTag.File }); + + // precedence for remaining symbol tags (without visibility tags and deprecation tag) + private static final List ADDITIONAL_TAGS_PRECEDENCE = Arrays.asList(new SymbolTag[] { + SymbolTag.Static, SymbolTag.Abstract, SymbolTag.Virtual, SymbolTag.Final, SymbolTag.Sealed, + SymbolTag.Synchronized, SymbolTag.Transient, SymbolTag.Volatile, + SymbolTag.Nullable, SymbolTag.NonNull, SymbolTag.ReadOnly, + SymbolTag.Declaration, SymbolTag.Definition }); + + private static class VisibilitySymbolTagComparator implements Comparator { + @Override + public int compare(SymbolTag tag1, SymbolTag tag2) { + return VISIBILITY_PRECEDENCE.indexOf(tag1) - VISIBILITY_PRECEDENCE.indexOf(tag2); + } + } + + private static class AdditionalSymbolTagComparator implements Comparator { + @Override + public int compare(SymbolTag tag1, SymbolTag tag2) { + return ADDITIONAL_TAGS_PRECEDENCE.indexOf(tag1) - ADDITIONAL_TAGS_PRECEDENCE.indexOf(tag2); + } + } + + private static List getVisibilitySymbolTagsSorted(List symbolTags) { + return symbolTags.stream() + .filter(tag -> VISIBILITY_PRECEDENCE.contains(tag)) + .sorted(new VisibilitySymbolTagComparator()) + .collect(Collectors.toList()); + } + + private static List getAdditionalSymbolTagsSorted(List symbolTags) { + return symbolTags.stream() + .filter(tag -> ADDITIONAL_TAGS_PRECEDENCE.contains(tag)) + .sorted(new AdditionalSymbolTagComparator()) + .collect(Collectors.toList()); + } + + private static @Nullable ImageDescriptor getOverlayForVisibility(List symbolTags) { + List visibilityTags = getVisibilitySymbolTagsSorted(symbolTags); + + if (visibilityTags.isEmpty()) { + return null; + } + + SymbolTag highestPrioVisibilityTag = visibilityTags.get(0); + return LSPImages.imageDescriptorOverlayFromSymbolTag(highestPrioVisibilityTag); + } + + private static @Nullable ImageDescriptor getOverlayForMarkerSeverity(int severity) { + if (severity != IMarker.SEVERITY_WARNING && severity != IMarker.SEVERITY_ERROR) { + return null; + } + + String overlayId = null; + if (severity == IMarker.SEVERITY_ERROR) { + overlayId = ISharedImages.IMG_DEC_FIELD_ERROR; + } else if (severity == IMarker.SEVERITY_WARNING) { + overlayId = ISharedImages.IMG_DEC_FIELD_WARNING; + } + + if (overlayId != null) { + return LSPImages.getSharedImageDescriptor(overlayId); + } + return null; + } + + private static @Nullable ImageDescriptor getUnderlayForDeprecation(boolean deprecated) { + if (!deprecated) { + return null; + } + return LSPImages.imageDescriptorOverlayFromSymbolTag(SymbolTag.Deprecated); + } + + private static @Nullable Image getImageWithOverlays(SymbolKind symbolKind, ImageDescriptor @Nullable[] overlays) { + Image baseImage = LSPImages.imageFromSymbolKind(symbolKind); + + if (baseImage == null) { + return null; + } + + @SuppressWarnings("null") + long numOverlays = Arrays.stream(overlays) + // Despite the IDE's warning, this null check were not necessary, this check is needed, + // since the array entries could be null. + .filter(e -> e != null).count(); + if (numOverlays == 0) { + return baseImage; + } + + int hashCode = Arrays.hashCode(overlays); + + Map overlayImagesForSymbolKind = overlayImagesCache.computeIfAbsent(symbolKind, + kind -> new HashMap<>()); + + return overlayImagesForSymbolKind.computeIfAbsent(hashCode, + hash -> new DecorationOverlayIcon(baseImage, overlays).createImage()); + } + + /** + * Returns an image for the given arguments. + * + * @param symbolKind the kind of symbol + * @param symbolTags the symbol tags + * @return a new or cached image for the given symbol kind with overlay icons computed for the given arguments. + * + * @see #getImageFor(SymbolKind, List, boolean, int) + */ + public static @Nullable Image getImageFor(@Nullable SymbolKind symbolKind, @Nullable List symbolTags) { + return getImageFor(symbolKind, symbolTags, false, -1); + } + + /** + * Returns an image for the given arguments. + * Uses caching for all combinations of a symbol kind and a set of overlays. + * Deprecation is shown if the deprecated parameter is true + * or {@link SymbolTag#Deprecated} is in the set of symbol tags. + * + * @param symbolKind the kind of symbol + * @param symbolTags the symbol tags + * @param deprecated whether to add a deprecation overlay icon even if there is no {@link SymbolTag#Deprecated} in the tags. + * @param severity one of -1, {@link IMarker#SEVERITY_WARNING}, and {@link IMarker#SEVERITY_ERROR}. -1 indicates no overlay icon. + * @return a new or cached image for the given symbol kind with overlay icons computed for the given arguments. + */ + public static @Nullable Image getImageFor(@Nullable SymbolKind symbolKind, @Nullable List symbolTags, + boolean deprecated, int severity) { + + if (symbolKind == null) { + return EMPTY_IMAGE; + } + + if (symbolTags == null) { + symbolTags = Collections.emptyList(); + } + + ImageDescriptor severityImageDescriptor = getOverlayForMarkerSeverity(severity); + ImageDescriptor visibilityImageDescriptor = getOverlayForVisibility(symbolTags); + ImageDescriptor deprecatedImageDescriptor = getUnderlayForDeprecation(deprecated || SymbolsUtil.isDeprecated(symbolTags)); + + List additionalTags = getAdditionalSymbolTagsSorted(symbolTags); + ImageDescriptor topRightOverlayDescriptor = null; + ImageDescriptor bottomRightOverlayDescriptor = null; + + if (!additionalTags.isEmpty()) { + topRightOverlayDescriptor = LSPImages.imageDescriptorOverlayFromSymbolTag(additionalTags.get(0)); + + if (SymbolKind.Constructor.equals(symbolKind)) { + // constructor base image has a built-in overlay in the top right corner, use bottom right instead + bottomRightOverlayDescriptor = topRightOverlayDescriptor; + topRightOverlayDescriptor = null; + } else if (additionalTags.size() > 1) { + bottomRightOverlayDescriptor = LSPImages.imageDescriptorOverlayFromSymbolTag(additionalTags.get(1)); + } + } + + // array index: 0 = top left, 1 = top right, 2 = bottom left, 3 = bottom right, 4 = underlay + // see IDecoration.TOP_LEFT ... IDecoration.BOTTOM_RIGHT, IDecoration.UNDERLAY + ImageDescriptor @Nullable[] overlays = { + visibilityImageDescriptor, topRightOverlayDescriptor, + severityImageDescriptor, bottomRightOverlayDescriptor, + deprecatedImageDescriptor}; + + return getImageWithOverlays(symbolKind, overlays); + } + + public static final void dispose() { + Stream.concat( + colorToImageCache.values().stream(), + overlayImagesCache.values().stream() + .flatMap(map -> map.values().stream())) + .filter(Objects::nonNull) + .forEach(Image::dispose); + overlayImagesCache.values().stream() + .forEach(Map::clear); + overlayImagesCache.clear(); + colorToImageCache.clear(); + } } diff --git a/target-platforms/target-platform-latest/target-platform-latest.target b/target-platforms/target-platform-latest/target-platform-latest.target index 50626e37e..945b99d33 100644 --- a/target-platforms/target-platform-latest/target-platform-latest.target +++ b/target-platforms/target-platform-latest/target-platform-latest.target @@ -8,7 +8,7 @@ - +