diff --git a/docs/adopter-guide.md b/docs/adopter-guide.md index 420ea6c38..a267374e0 100644 --- a/docs/adopter-guide.md +++ b/docs/adopter-guide.md @@ -134,17 +134,22 @@ TM4E also defines commands for toggling line comments and adding or removing blo ## Contributing Themes -TM4E ships with built-in Light and Dark themes that are linked to the Eclipse appearance themes, but plugins can contribute additional CSS-based themes through the `org.eclipse.tm4e.ui.themes` extension point. +TM4E ships with built-in Light and Dark themes that are linked to the Eclipse appearance themes, but plugins can contribute additional themes through the `org.eclipse.tm4e.ui.themes` extension point. ```xml - ``` +The `path` attribute can point to: + +- a CSS theme file (`*.css`), or +- a TextMate theme file (for example `*.tmTheme`, `*.plist`, `*.json`, `*.yaml`, `*.yml`). + Themes can be flagged as more suitable for light or dark appearances and can be associated with specific grammar scopes so that, for example, a dedicated theme applies whenever a particular language is active. You declare one or more `` elements and then add `themeAssociation` elements that link themes to one or more scopes and optional dark/light variants. The exact attributes and options are described in the `themes` extension point schema. diff --git a/org.eclipse.tm4e.ui.tests/build.properties b/org.eclipse.tm4e.ui.tests/build.properties index 3fd0f106d..a97d1aeeb 100644 --- a/org.eclipse.tm4e.ui.tests/build.properties +++ b/org.eclipse.tm4e.ui.tests/build.properties @@ -6,3 +6,6 @@ bin.includes = META-INF/,\ grammars/,\ plugin.xml,\ about.html + +# JDT Null Analysis for Eclipse +additional.bundles = org.eclipse.jdt.annotation,assertj-core diff --git a/org.eclipse.tm4e.ui.tests/src/main/java/org/eclipse/tm4e/ui/tests/internal/themes/CSSThemeTokenProviderTest.java b/org.eclipse.tm4e.ui.tests/src/main/java/org/eclipse/tm4e/ui/tests/internal/themes/CSSThemeTokenProviderTest.java new file mode 100644 index 000000000..52945b0f5 --- /dev/null +++ b/org.eclipse.tm4e.ui.tests/src/main/java/org/eclipse/tm4e/ui/tests/internal/themes/CSSThemeTokenProviderTest.java @@ -0,0 +1,76 @@ +/** + * Copyright (c) 2025 Vegard IT 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: + * Sebastian Thomschke (Vegard IT GmbH) - initial implementation + */ +package org.eclipse.tm4e.ui.tests.internal.themes; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.nio.file.Files; +import java.nio.file.Path; + +import org.eclipse.jface.text.TextAttribute; +import org.eclipse.swt.SWT; +import org.eclipse.tm4e.core.theme.RGB; +import org.eclipse.tm4e.ui.themes.ColorManager; +import org.eclipse.tm4e.ui.themes.css.CSSTokenProvider; +import org.junit.jupiter.api.Test; + +class CSSThemeTokenProviderTest { + + private final ColorManager colors = ColorManager.getInstance(); + + private TextAttribute getTextAttribute(final CSSTokenProvider provider, final String tokenType) { + final var tokenData = provider.getToken(tokenType).getData(); + assertThat(tokenData).isInstanceOf(TextAttribute.class); + return (TextAttribute) tokenData; + } + + @Test + void testBuiltInDarkCssTheme() throws Exception { + try (var in = Files.newInputStream(Path.of("../org.eclipse.tm4e.ui/themes/Dark.css"))) { + final var provider = new CSSTokenProvider(in); + + assertThat(provider.getEditorForeground()).isEqualTo(colors.getColor(new RGB(212, 212, 212))); + assertThat(provider.getEditorBackground()).isEqualTo(colors.getColor(new RGB(30, 30, 30))); + assertThat(provider.getEditorCurrentLineHighlight()).isEqualTo(colors.getColor(new RGB(40, 40, 40))); + + assertThat(getTextAttribute(provider, "entity.other.attribute-name").getForeground()) + .isEqualTo(colors.getColor(new RGB(156, 220, 254))); + + assertThat(getTextAttribute(provider, "storage.type.java").getForeground()) + .isEqualTo(colors.getColor(new RGB(78, 201, 176))); + + assertThat(provider.getToken("this.selector.does.not.exist").getData()).isNull(); + } + } + + @Test + void testBuiltInMonokaiCssTheme() throws Exception { + try (var in = Files.newInputStream(Path.of("../org.eclipse.tm4e.ui/themes/Monokai.css"))) { + final var provider = new CSSTokenProvider(in); + + assertThat(provider.getEditorForeground()).isEqualTo(colors.getColor(new RGB(248, 248, 242))); + assertThat(provider.getEditorBackground()).isEqualTo(colors.getColor(new RGB(39, 40, 34))); + + assertThat(getTextAttribute(provider, "keyword").getForeground()) + .isEqualTo(colors.getColor(new RGB(249, 38, 114))); + + final var storageTypeAttrs = getTextAttribute(provider, "storage.type"); + assertThat(storageTypeAttrs.getForeground()).isEqualTo(colors.getColor(new RGB(102, 217, 239))); + assertThat(storageTypeAttrs.getStyle() & SWT.ITALIC).isEqualTo(SWT.ITALIC); + + final var inheritedClassAttrs = getTextAttribute(provider, "entity.other.inherited-class.java"); + assertThat(inheritedClassAttrs.getForeground()).isEqualTo(colors.getColor(new RGB(166, 226, 46))); + assertThat(inheritedClassAttrs.getStyle() & SWT.ITALIC).isEqualTo(SWT.ITALIC); + assertThat(inheritedClassAttrs.getStyle() & TextAttribute.UNDERLINE).isEqualTo(TextAttribute.UNDERLINE); + } + } +} diff --git a/org.eclipse.tm4e.ui.tests/src/main/java/org/eclipse/tm4e/ui/tests/internal/themes/TMTokenProviderTest.java b/org.eclipse.tm4e.ui.tests/src/main/java/org/eclipse/tm4e/ui/tests/internal/themes/TMTokenProviderTest.java index d63392b69..325a2679b 100644 --- a/org.eclipse.tm4e.ui.tests/src/main/java/org/eclipse/tm4e/ui/tests/internal/themes/TMTokenProviderTest.java +++ b/org.eclipse.tm4e.ui.tests/src/main/java/org/eclipse/tm4e/ui/tests/internal/themes/TMTokenProviderTest.java @@ -16,9 +16,11 @@ import java.io.ByteArrayInputStream; import java.nio.file.Files; import java.nio.file.Path; +import java.util.List; import org.eclipse.jface.text.TextAttribute; import org.eclipse.swt.SWT; +import org.eclipse.tm4e.core.model.TMToken; import org.eclipse.tm4e.core.registry.IThemeSource.ContentType; import org.eclipse.tm4e.core.theme.RGB; import org.eclipse.tm4e.ui.internal.themes.TMThemeTokenProvider; @@ -157,4 +159,43 @@ void testVSCodeJsonTheme() throws Exception { assertThat(attrs.getForeground()).isEqualTo(colors.getColor(RGB.fromHex("#00FF00"))); } } + + @Test + void testTMThemeMatchesAgainstScopesStack() throws Exception { + try (var in = new ByteArrayInputStream(""" + { + "name": "Scopes test", + "tokenColors": [ + { + "settings": { + "foreground": "#000000" + } + }, + { + "scope": "entity.other", + "settings": { + "foreground": "#D197D9" + } + } + ] + } + """.getBytes())) { + final var theme = new TMThemeTokenProvider(ContentType.JSON, in); + + final var token = new TMToken( + 0, + "meta.java.other.definition.class.entity.inherited.classes.inherited-class", + List.of( + "source.java@org.eclipse.tm4e.language_pack", + "meta.class.java", + "meta.definition.class.inherited.classes.java", + "entity.other.inherited-class.java"), + null); + + final var data = theme.getToken(token).getData(); + assertThat(data).isInstanceOf(TextAttribute.class); + final var attrs = (TextAttribute) data; + assertThat(attrs.getForeground()).isEqualTo(colors.getColor(RGB.fromHex("#D197D9"))); + } + } } diff --git a/org.eclipse.tm4e.ui.tests/src/main/java/org/eclipse/tm4e/ui/tests/support/StyleRangesCollector.java b/org.eclipse.tm4e.ui.tests/src/main/java/org/eclipse/tm4e/ui/tests/support/StyleRangesCollector.java index 6c47b7828..7d1286fda 100644 --- a/org.eclipse.tm4e.ui.tests/src/main/java/org/eclipse/tm4e/ui/tests/support/StyleRangesCollector.java +++ b/org.eclipse.tm4e.ui.tests/src/main/java/org/eclipse/tm4e/ui/tests/support/StyleRangesCollector.java @@ -45,7 +45,12 @@ public void onUninstalled() { public void onColorized(final TextPresentation presentation, final Throwable error) { add(presentation); if (waitForToLineNumber != null) { - final int offset = presentation.getExtent().getOffset() + presentation.getExtent().getLength(); + final int endOffsetExclusive = presentation.getExtent().getOffset() + presentation.getExtent().getLength(); + // The extent end offset is exclusive. If it points to the start of the next line, + // document.getLineOfOffset(endOffsetExclusive) would already return that next line + // even though the presentation does not actually cover it. + // We therefore check the line number of the last included character. + final int offset = presentation.getExtent().getLength() > 0 ? endOffsetExclusive - 1 : endOffsetExclusive; try { if (waitForToLineNumber != document.getLineOfOffset(offset)) { return; diff --git a/org.eclipse.tm4e.ui.tests/src/main/java/org/eclipse/tm4e/ui/tests/themes/CSSThemeColorizationTest.java b/org.eclipse.tm4e.ui.tests/src/main/java/org/eclipse/tm4e/ui/tests/themes/CSSThemeColorizationTest.java new file mode 100644 index 000000000..6e385c19f --- /dev/null +++ b/org.eclipse.tm4e.ui.tests/src/main/java/org/eclipse/tm4e/ui/tests/themes/CSSThemeColorizationTest.java @@ -0,0 +1,103 @@ +/** + * Copyright (c) 2025 Vegard IT 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: + * Sebastian Thomschke (Vegard IT GmbH) - initial implementation + */ +package org.eclipse.tm4e.ui.tests.themes; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.nio.file.Files; +import java.nio.file.Path; + +import org.eclipse.tm4e.core.grammar.IGrammar; +import org.eclipse.tm4e.core.registry.IGrammarSource; +import org.eclipse.tm4e.core.registry.Registry; +import org.eclipse.tm4e.ui.tests.support.TMEditor; +import org.eclipse.tm4e.ui.tests.support.TestUtils; +import org.eclipse.tm4e.ui.themes.css.CSSTokenProvider; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class CSSThemeColorizationTest { + + private static final String SAMPLE_TEXT = "let a = '';\nlet b = 10;\nlet c = true;"; + + private IGrammar grammar; + private TMEditor editor; + + @BeforeEach + void setup() throws Exception { + TestUtils.assertNoTM4EThreadsRunning(); + grammar = new Registry().addGrammar(IGrammarSource.fromResource(getClass(), "/grammars/TypeScript.tmLanguage.json")); + } + + @AfterEach + void tearDown() throws Exception { + if (editor != null) { + editor.dispose(); + editor = null; + } + TestUtils.assertNoTM4EThreadsRunning(); + } + + private static void assertStyleRange( + final String styleRanges, + final int offset, + final int length, + final String expectedFontStyle, + final String expectedForegroundColor) { + assertThat(styleRanges).contains( + "StyleRange {" + offset + ", " + length + ", fontStyle=" + expectedFontStyle + ", foreground=Color {" + + expectedForegroundColor + ", 255}}"); + } + + @Test + void darkCssThemeColorsAreApplied() throws Exception { + try (var in = Files.newInputStream(Path.of("../org.eclipse.tm4e.ui/themes/Dark.css"))) { + final var theme = new CSSTokenProvider(in); + editor = new TMEditor(grammar, theme, SAMPLE_TEXT); + + final var commands = editor.execute(); + assertThat(commands).hasSize(1); + final String ranges = commands.get(0).getStyleRanges(); + + // let -> storage (matches .storage / .storage.type) + assertStyleRange(ranges, 0, 3, "normal", "86, 156, 214"); + // '' -> string + assertStyleRange(ranges, 8, 2, "normal", "206, 145, 120"); + // 10 -> constant.numeric + assertStyleRange(ranges, 20, 2, "normal", "181, 206, 168"); + // true -> constant.language + assertStyleRange(ranges, 32, 4, "normal", "86, 156, 214"); + } + } + + @Test + void monokaiCssThemeColorsAreApplied() throws Exception { + try (var in = Files.newInputStream(Path.of("../org.eclipse.tm4e.ui/themes/Monokai.css"))) { + final var theme = new CSSTokenProvider(in); + editor = new TMEditor(grammar, theme, SAMPLE_TEXT); + + final var commands = editor.execute(); + assertThat(commands).hasSize(1); + final String ranges = commands.get(0).getStyleRanges(); + + // let -> storage.type + assertStyleRange(ranges, 0, 3, "italic", "102, 217, 239"); + // '' -> string + assertStyleRange(ranges, 8, 2, "normal", "230, 219, 116"); + // 10 -> constant.numeric + assertStyleRange(ranges, 20, 2, "normal", "174, 129, 255"); + // true -> constant.language + assertStyleRange(ranges, 32, 4, "normal", "174, 129, 255"); + } + } +} diff --git a/org.eclipse.tm4e.ui/src/main/java/org/eclipse/tm4e/ui/internal/themes/TMThemeTokenProvider.java b/org.eclipse.tm4e.ui/src/main/java/org/eclipse/tm4e/ui/internal/themes/TMThemeTokenProvider.java index 75c88d8c5..f1642aa61 100644 --- a/org.eclipse.tm4e.ui/src/main/java/org/eclipse/tm4e/ui/internal/themes/TMThemeTokenProvider.java +++ b/org.eclipse.tm4e.ui/src/main/java/org/eclipse/tm4e/ui/internal/themes/TMThemeTokenProvider.java @@ -14,8 +14,11 @@ import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.jface.text.rules.IToken; import org.eclipse.swt.graphics.Color; import org.eclipse.tm4e.core.internal.grammar.ScopeStack; import org.eclipse.tm4e.core.internal.theme.FontStyle; @@ -23,6 +26,8 @@ import org.eclipse.tm4e.core.internal.theme.StyleAttributes; import org.eclipse.tm4e.core.internal.theme.Theme; import org.eclipse.tm4e.core.internal.theme.raw.RawThemeReader; +import org.eclipse.tm4e.core.internal.utils.ScopeNames; +import org.eclipse.tm4e.core.model.TMToken; import org.eclipse.tm4e.core.registry.IThemeSource; import org.eclipse.tm4e.core.theme.IStyle; import org.eclipse.tm4e.core.theme.RGB; @@ -35,6 +40,7 @@ public class TMThemeTokenProvider extends AbstractTokenProvider { private final Theme theme; private final List colors; + private final ConcurrentMap tokenCacheByScopeStack = new ConcurrentHashMap<>(); public TMThemeTokenProvider(final IThemeSource.ContentType contentType, final InputStream in) throws Exception { final var rawTheme = RawThemeReader @@ -43,6 +49,41 @@ public TMThemeTokenProvider(final IThemeSource.ContentType contentType, final In colors = theme.getColorMap(); } + @Override + public IToken getToken(final TMToken token) { + if (token.scopes.isEmpty()) + return DEFAULT_TOKEN; + + final String[] scopeNames = new String[token.scopes.size()]; + final var keyBuilder = new StringBuilder(token.scopes.size() * 24); + for (int i = 0, size = token.scopes.size(); i < size; i++) { + final var scope = ScopeNames.withoutContributor(token.scopes.get(i)); + scopeNames[i] = scope; + if (i > 0) { + keyBuilder.append('\n'); + } + keyBuilder.append(scope); + } + final var cacheKey = keyBuilder.toString(); + final var cachedToken = tokenCacheByScopeStack.get(cacheKey); + if (cachedToken != null) + return cachedToken; + + final IToken computedToken = getTokenUncached(scopeNames); + final var existingToken = tokenCacheByScopeStack.putIfAbsent(cacheKey, computedToken); + return existingToken == null ? computedToken : existingToken; + } + + private IToken getTokenUncached(final String[] scopeNames) { + final var scopePath = ScopeStack.from(scopeNames); + final var styleAttrs = theme.match(scopePath); + if (styleAttrs == null || styleAttrs.equals(StyleAttributes.NO_STYLE)) + return DEFAULT_TOKEN; + + final var style = toStyle(styleAttrs); + return style == null ? DEFAULT_TOKEN : getJFaceTextToken(style); + } + @Override protected @Nullable IStyle getBestStyle(String textMateTokenType) { StyleAttributes styleAttrs = null; @@ -57,27 +98,31 @@ public TMThemeTokenProvider(final IThemeSource.ContentType contentType, final In // this is a workaround because org.eclipse.tm4e.core.model.TMTokenizationSupport.decodeTextMateToken(DecodeMap, List) // simply concatenates scopes into one and here we don't know how to separate them, e.g. "meta.package.java" + "keyword.other" = "meta.package.java.keyword.other" // this results in style definitions for "keyword.other" are not returned by Theme#match() which only matches like "^keyword\.other.*" - // -> time to upgrade to IGrammar.tokenizeLine2? + // Prefer calling getToken(TMToken), which matches against the real TextMate scopes stack. textMateTokenType = textMateTokenType.substring(dotIdx + 1); } } - if (styleAttrs != null) { - final var style = new Style(); - if (styleAttrs.foregroundId > 0) - style.setColor(RGB.fromHex(colors.get(styleAttrs.foregroundId))); - if (styleAttrs.backgroundId > 0) - style.setBackgroundColor(RGB.fromHex(colors.get(styleAttrs.backgroundId))); - - if (styleAttrs.fontStyle > 0) { - style.setBold(FontStyle.isBold(styleAttrs.fontStyle)); - style.setItalic(FontStyle.isItalic(styleAttrs.fontStyle)); - style.setUnderline(FontStyle.isUnderline(styleAttrs.fontStyle)); - style.setStrikeThrough(FontStyle.isStrikethrough(styleAttrs.fontStyle)); - } - return style; + return toStyle(styleAttrs); + } + + private @Nullable IStyle toStyle(final @Nullable StyleAttributes styleAttrs) { + if (styleAttrs == null) + return null; + + final var style = new Style(); + if (styleAttrs.foregroundId > 0) + style.setColor(RGB.fromHex(colors.get(styleAttrs.foregroundId))); + if (styleAttrs.backgroundId > 0) + style.setBackgroundColor(RGB.fromHex(colors.get(styleAttrs.backgroundId))); + + if (styleAttrs.fontStyle > 0) { + style.setBold(FontStyle.isBold(styleAttrs.fontStyle)); + style.setItalic(FontStyle.isItalic(styleAttrs.fontStyle)); + style.setUnderline(FontStyle.isUnderline(styleAttrs.fontStyle)); + style.setStrikeThrough(FontStyle.isStrikethrough(styleAttrs.fontStyle)); } - return null; + return style; } protected @Nullable Color getEditorColor(final String... names) { diff --git a/org.eclipse.tm4e.ui/src/main/java/org/eclipse/tm4e/ui/internal/themes/Theme.java b/org.eclipse.tm4e.ui/src/main/java/org/eclipse/tm4e/ui/internal/themes/Theme.java index 153798d57..d9a5517fa 100644 --- a/org.eclipse.tm4e.ui/src/main/java/org/eclipse/tm4e/ui/internal/themes/Theme.java +++ b/org.eclipse.tm4e.ui/src/main/java/org/eclipse/tm4e/ui/internal/themes/Theme.java @@ -21,6 +21,7 @@ import org.eclipse.jface.text.rules.IToken; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.graphics.Color; +import org.eclipse.tm4e.core.model.TMToken; import org.eclipse.tm4e.core.internal.utils.StringUtils; import org.eclipse.tm4e.core.registry.IThemeSource.ContentType; import org.eclipse.tm4e.registry.TMResource; @@ -98,6 +99,12 @@ public IToken getToken(final String textMateTokenType) { return provider == null ? ITokenProvider.DEFAULT_TOKEN : provider.getToken(textMateTokenType); } + @Override + public IToken getToken(final TMToken token) { + final ITokenProvider provider = getTokenProvider(); + return provider == null ? ITokenProvider.DEFAULT_TOKEN : provider.getToken(token); + } + private @Nullable Color getPriorityColor(final @Nullable Color themeColor, final String prefStoreKey) { // if the theme is light but Eclipse is in dark mode (or vice versa) we cannot use the pref settings and always use the theme colors return UI.isDarkEclipseTheme() == isDark() diff --git a/org.eclipse.tm4e.ui/src/main/java/org/eclipse/tm4e/ui/text/Colorizer.java b/org.eclipse.tm4e.ui/src/main/java/org/eclipse/tm4e/ui/text/Colorizer.java index c83bcf262..1bab4c889 100644 --- a/org.eclipse.tm4e.ui/src/main/java/org/eclipse/tm4e/ui/text/Colorizer.java +++ b/org.eclipse.tm4e.ui/src/main/java/org/eclipse/tm4e/ui/text/Colorizer.java @@ -136,7 +136,7 @@ void colorize(final IRegion damageRegion, final ITMDocumentModel tmModel) throws tokenStartIndex = damageRegion.getOffset() - startLineOffset; } else { tokenStartIndex = damageRegion.getOffset() - startLineOffset; - final IToken token = theme == null ? ITokenProvider.DEFAULT_TOKEN : theme.getToken(currentToken.type); + final IToken token = theme == null ? ITokenProvider.DEFAULT_TOKEN : theme.getToken(currentToken); lastAttribute = getTokenTextAttribute(token); length += getTokenLength(tokenStartIndex, nextToken, lineLength); firstToken = false; @@ -151,7 +151,7 @@ else if (isTokenAfterRegion(currentToken, startLineOffset, damageRegion)) { break; } - final IToken token = theme == null ? ITokenProvider.DEFAULT_TOKEN : theme.getToken(currentToken.type); + final IToken token = theme == null ? ITokenProvider.DEFAULT_TOKEN : theme.getToken(currentToken); final TextAttribute attribute = getTokenTextAttribute(token); if (lastAttribute.equals(attribute)) { length += getTokenLength(tokenStartIndex, nextToken, lineLength); diff --git a/org.eclipse.tm4e.ui/src/main/java/org/eclipse/tm4e/ui/themes/ITokenProvider.java b/org.eclipse.tm4e.ui/src/main/java/org/eclipse/tm4e/ui/themes/ITokenProvider.java index 94f84714a..522d3c329 100644 --- a/org.eclipse.tm4e.ui/src/main/java/org/eclipse/tm4e/ui/themes/ITokenProvider.java +++ b/org.eclipse.tm4e.ui/src/main/java/org/eclipse/tm4e/ui/themes/ITokenProvider.java @@ -15,6 +15,7 @@ import org.eclipse.jface.text.rules.IToken; import org.eclipse.jface.text.rules.Token; import org.eclipse.swt.graphics.Color; +import org.eclipse.tm4e.core.model.TMToken; /** * Provider to retrieve Eclipse JFace Text {@link IToken}s for TextMate token types. @@ -28,6 +29,14 @@ public interface ITokenProvider { */ IToken getToken(String tmTokenType); + /** + * Allows token providers to compute styles using the token's full TextMate scopes stack. + * + * @return the Eclipse JFace Text {@link IToken} for the given TexMate token or {@link #DEFAULT_TOKEN} if {@link TMToken#scopes} is + * empty. + */ + IToken getToken(final TMToken token); + @Nullable Color getEditorBackground(); diff --git a/org.eclipse.tm4e.ui/src/main/java/org/eclipse/tm4e/ui/themes/css/CSSTokenProvider.java b/org.eclipse.tm4e.ui/src/main/java/org/eclipse/tm4e/ui/themes/css/CSSTokenProvider.java index ecc89e3ab..98d39f46f 100644 --- a/org.eclipse.tm4e.ui/src/main/java/org/eclipse/tm4e/ui/themes/css/CSSTokenProvider.java +++ b/org.eclipse.tm4e.ui/src/main/java/org/eclipse/tm4e/ui/themes/css/CSSTokenProvider.java @@ -17,8 +17,10 @@ import java.util.List; import org.eclipse.jdt.annotation.Nullable; +import org.eclipse.jface.text.rules.IToken; import org.eclipse.swt.graphics.Color; import org.eclipse.tm4e.core.internal.utils.StringUtils; +import org.eclipse.tm4e.core.model.TMToken; import org.eclipse.tm4e.core.theme.IStyle; import org.eclipse.tm4e.core.theme.css.CSSParser; import org.eclipse.tm4e.ui.TMUIPlugin; @@ -93,4 +95,9 @@ public CSSTokenProvider(final InputStream in) { public @Nullable Color getEditorCurrentLineHighlight() { return getColor(false, "editor", "lineHighlight"); } + + @Override + public IToken getToken(final TMToken token) { + return getToken(token.type); + } } diff --git a/target-platforms/staging.target b/target-platforms/staging.target index 1be65107d..e014d9d59 100644 --- a/target-platforms/staging.target +++ b/target-platforms/staging.target @@ -10,7 +10,7 @@ - + @@ -38,17 +38,18 @@ - - - - - - - - - - - + + + + + + + + + + + +