From 98459537fa4cabd6545685bb2bde122df285a483 Mon Sep 17 00:00:00 2001 From: BoykoAlex Date: Thu, 23 Oct 2025 14:46:41 -0700 Subject: [PATCH 1/2] Theme support for stereotype icons Signed-off-by: BoykoAlex --- .../META-INF/MANIFEST.MF | 3 +- .../boot/ls/BootLanguageServerPlugin.java | 57 ++++++++++++++++++- 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/eclipse-language-servers/org.springframework.tooling.boot.ls/META-INF/MANIFEST.MF b/eclipse-language-servers/org.springframework.tooling.boot.ls/META-INF/MANIFEST.MF index 0bee5f6fe4..eacc5c208c 100644 --- a/eclipse-language-servers/org.springframework.tooling.boot.ls/META-INF/MANIFEST.MF +++ b/eclipse-language-servers/org.springframework.tooling.boot.ls/META-INF/MANIFEST.MF @@ -36,7 +36,8 @@ Require-Bundle: org.eclipse.jdt.launching;bundle-version="3.9.0", org.springsource.ide.eclipse.commons.core;bundle-version="4.17.0", org.springframework.tooling.jdt.ls.commons;bundle-version="4.17.0", org.eclipse.jface.notifications, - org.eclipse.core.net + org.eclipse.core.net, + org.eclipse.e4.ui.css.swt.theme Import-Package: com.google.common.base, com.google.common.collect, com.google.gson, diff --git a/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/BootLanguageServerPlugin.java b/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/BootLanguageServerPlugin.java index 9936c069ef..80173069b6 100644 --- a/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/BootLanguageServerPlugin.java +++ b/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/BootLanguageServerPlugin.java @@ -11,18 +11,30 @@ package org.springframework.tooling.boot.ls; import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; +import java.util.Optional; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.core.runtime.preferences.InstanceScope; -import org.eclipse.jdt.internal.ui.JavaPluginImages; +import org.eclipse.e4.ui.css.swt.theme.IThemeEngine; import org.eclipse.jface.bindings.Binding; +import org.eclipse.jface.preference.JFacePreferences; +import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.resource.ImageRegistry; import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.RGB; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.keys.IBindingService; import org.eclipse.ui.plugin.AbstractUIPlugin; @@ -121,7 +133,6 @@ public void run() { } } - @SuppressWarnings("restriction") @Override protected void initializeImageRegistry(ImageRegistry reg) { super.initializeImageRegistry(reg); @@ -135,9 +146,49 @@ protected void initializeImageRegistry(ImageRegistry reg) { if (p.getFileExtension().equals("svg")) { String fileName = p.lastSegment(); String name = fileName.substring(0, fileName.length() - 4); - reg.put(STEREOTYPE_IMG_PREFIX + name, JavaPluginImages.createImageDescriptor(getBundle(), p, false)); + + try { + URI uri = new URI("platform", null, "/plugin/" + PLUGIN_ID + "/" + p, null); + reg.put(STEREOTYPE_IMG_PREFIX + name, createStereotypeImageDescriptor(uri.toURL(), p)); + } catch (URISyntaxException | MalformedURLException e) { + getLog().log(Status.error("Failed to create image descriptor for " + p, e)); + } + } + } + } + + @SuppressWarnings("restriction") + private Optional getActiveThemeId() { + return Optional.ofNullable(PlatformUI.getWorkbench().getService(IThemeEngine.class)) + .flatMap(themeEngine -> Optional.ofNullable(themeEngine.getActiveTheme())) + .map(theme -> theme.getId()); + } + + private ImageDescriptor createStereotypeImageDescriptor(URL url, IPath p) { + RGB rgb = PlatformUI.getWorkbench().getThemeManager().getCurrentTheme().getColorRegistry().getRGB(JFacePreferences.INFORMATION_FOREGROUND_COLOR); + if (rgb != null) { + final String fileName = p.lastSegment(); + Optional optThemeId = getActiveThemeId(); + if (optThemeId.isPresent()) { + try { + java.nio.file.Path tempDir = Paths.get(System.getProperty("java.io.tmpdir"), PLUGIN_ID, optThemeId.get()); + if (!Files.exists(tempDir)) { + Files.createDirectories(tempDir); + } + java.nio.file.Path tempSvgPath = tempDir.resolve(fileName); + if (!Files.exists(tempSvgPath)) { + String svg = new String(url.openStream().readAllBytes(), StandardCharsets.UTF_8) + .replace("currentColor", "rgb(%d,%d,%d)".formatted(rgb.red, rgb.green, rgb.blue)); + Files.createFile(tempSvgPath); + Files.write(tempSvgPath, svg.getBytes(StandardCharsets.UTF_8)); + } + return ImageDescriptor.createFromURL(tempSvgPath.toUri().toURL()); + } catch (IOException e) { + getLog().error("Failed to create theme compatible SVG icon " + p, e); + } } } + return ImageDescriptor.createFromURL(url); } public BootLsState getLsState() { From f84d122cbd2d412bf2389ede2f0ff1e9ae941779 Mon Sep 17 00:00:00 2001 From: BoykoAlex Date: Thu, 23 Oct 2025 17:54:57 -0700 Subject: [PATCH 2/2] Cleanup Signed-off-by: BoykoAlex --- .../META-INF/MANIFEST.MF | 3 +- .../boot/ls/BootLanguageServerPlugin.java | 44 +++++++------------ 2 files changed, 18 insertions(+), 29 deletions(-) diff --git a/eclipse-language-servers/org.springframework.tooling.boot.ls/META-INF/MANIFEST.MF b/eclipse-language-servers/org.springframework.tooling.boot.ls/META-INF/MANIFEST.MF index eacc5c208c..0bee5f6fe4 100644 --- a/eclipse-language-servers/org.springframework.tooling.boot.ls/META-INF/MANIFEST.MF +++ b/eclipse-language-servers/org.springframework.tooling.boot.ls/META-INF/MANIFEST.MF @@ -36,8 +36,7 @@ Require-Bundle: org.eclipse.jdt.launching;bundle-version="3.9.0", org.springsource.ide.eclipse.commons.core;bundle-version="4.17.0", org.springframework.tooling.jdt.ls.commons;bundle-version="4.17.0", org.eclipse.jface.notifications, - org.eclipse.core.net, - org.eclipse.e4.ui.css.swt.theme + org.eclipse.core.net Import-Package: com.google.common.base, com.google.common.collect, com.google.gson, diff --git a/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/BootLanguageServerPlugin.java b/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/BootLanguageServerPlugin.java index 80173069b6..0635b7ca5b 100644 --- a/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/BootLanguageServerPlugin.java +++ b/eclipse-language-servers/org.springframework.tooling.boot.ls/src/org/springframework/tooling/boot/ls/BootLanguageServerPlugin.java @@ -21,14 +21,12 @@ import java.util.ArrayList; import java.util.Enumeration; import java.util.List; -import java.util.Optional; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.core.runtime.preferences.InstanceScope; -import org.eclipse.e4.ui.css.swt.theme.IThemeEngine; import org.eclipse.jface.bindings.Binding; import org.eclipse.jface.preference.JFacePreferences; import org.eclipse.jface.resource.ImageDescriptor; @@ -157,35 +155,27 @@ protected void initializeImageRegistry(ImageRegistry reg) { } } - @SuppressWarnings("restriction") - private Optional getActiveThemeId() { - return Optional.ofNullable(PlatformUI.getWorkbench().getService(IThemeEngine.class)) - .flatMap(themeEngine -> Optional.ofNullable(themeEngine.getActiveTheme())) - .map(theme -> theme.getId()); - } - private ImageDescriptor createStereotypeImageDescriptor(URL url, IPath p) { - RGB rgb = PlatformUI.getWorkbench().getThemeManager().getCurrentTheme().getColorRegistry().getRGB(JFacePreferences.INFORMATION_FOREGROUND_COLOR); + RGB rgb = PlatformUI.getWorkbench().getThemeManager().getCurrentTheme().getColorRegistry() + .getRGB(JFacePreferences.INFORMATION_FOREGROUND_COLOR); if (rgb != null) { final String fileName = p.lastSegment(); - Optional optThemeId = getActiveThemeId(); - if (optThemeId.isPresent()) { - try { - java.nio.file.Path tempDir = Paths.get(System.getProperty("java.io.tmpdir"), PLUGIN_ID, optThemeId.get()); - if (!Files.exists(tempDir)) { - Files.createDirectories(tempDir); - } - java.nio.file.Path tempSvgPath = tempDir.resolve(fileName); - if (!Files.exists(tempSvgPath)) { - String svg = new String(url.openStream().readAllBytes(), StandardCharsets.UTF_8) - .replace("currentColor", "rgb(%d,%d,%d)".formatted(rgb.red, rgb.green, rgb.blue)); - Files.createFile(tempSvgPath); - Files.write(tempSvgPath, svg.getBytes(StandardCharsets.UTF_8)); - } - return ImageDescriptor.createFromURL(tempSvgPath.toUri().toURL()); - } catch (IOException e) { - getLog().error("Failed to create theme compatible SVG icon " + p, e); + try { + String rgbStr = "%02x-%02x-%02x".formatted(rgb.red, rgb.green, rgb.blue); + java.nio.file.Path tempDir = Paths.get(System.getProperty("java.io.tmpdir"), PLUGIN_ID, rgbStr); + if (!Files.exists(tempDir)) { + Files.createDirectories(tempDir); + } + java.nio.file.Path tempSvgPath = tempDir.resolve(fileName); + if (!Files.exists(tempSvgPath)) { + String svg = new String(url.openStream().readAllBytes(), StandardCharsets.UTF_8) + .replace("currentColor", "rgb(%d,%d,%d)".formatted(rgb.red, rgb.green, rgb.blue)); + Files.createFile(tempSvgPath); + Files.write(tempSvgPath, svg.getBytes(StandardCharsets.UTF_8)); } + return ImageDescriptor.createFromURL(tempSvgPath.toUri().toURL()); + } catch (IOException e) { + getLog().error("Failed to create theme compatible SVG icon " + p, e); } } return ImageDescriptor.createFromURL(url);