Open fabiospampinato opened 7 years ago
I'd rather avoid API that gives out the actual color, but hope that all can be done with color references. That way extensions don't need to worry about listening to theme changes. Yes, sounds like a useful idea but is not an easy addition as token colors are based on text mate theme rules and the text mate scope hierarchy. If there are more requests, we can certainly look at it. Until then I recommend you to use one of the regular workbench colors, or - added to 1.16 - define a new color in your extension.
@aeschli while I still think an API for this would be valuable (or at the least an API that tells you if the current theme is light or dark), another alternative that might work in certain scenarios would be to expose the set of theme colors as css variables. This would allow the scenario here: https://github.com/Microsoft/vscode/issues/34411#issue-257879258
In theory I could use an SVG image, with colors pulled from the css variables, allowing me to get theme adaptable icons into the hovers.
Thoughts?
FYI, this is similar to this request https://github.com/Microsoft/vscode/issues/41785, but not just for the webview, for the editor itself.
@eamodio Great idea. If using css variables in SVG images works then we should definitely do this. Let's track this in a separate issue!
This issue has come up again. In GitLens, I would like to expose 2 colors (hot and cold versions) for the heatmap that GitLens generates, but I am unable to use theme colors, because I need access to the real color values to generate the full palette of colors required.
A lot of extensions would benefit from this. Bracket colorizer, jumpy, gitlens and a zillion others. Would be good to implement this.
@piggyslasher Please explain how/where these extension could profit from this.
There is already a story that extensions can declare a new color (by id) and use it in decorations. Users can redefine these colors in themes.
My use case: I'm making an extension that decorates some tokens, and I'd like them to have the same color that comments have in my theme, the problem is that the regex I use to find those tokens depends on some configurable value, so I cannot pre-compute it in advance and just put it in a .tmLanguage file
@aeschli that's my use case. Sure, I'm already exporting these colors via the settings and users can override them already. But I can't just pick the colors for them automatically depending on what theme they are currently using. Also if someone uses one of those extensions for rotating themes I can't just expect them to update their settings every time.
@aeschli A use case in my scenario is I use the extension called "Bracket pair colorizer" with adds colors to matching brackets, like so: Now, in order for the extension to render the brackets to match my theme, I have to hard code the colors into my settings:
Without this, I would end up with something that looks like this out of the box:
Notice the color of the brackets. They're from the extension's default preferences because the developer can't access the colors. I hope I'm on the right track.
@piggyslasher Did you see that you can define new colors in the extension's package.json?
"contributes": {
"colors": [{
"id": "bracketPairColorizer.bracket1",
"description": "Color for the outermost bracket",
"defaults": {
"dark": "#112233",
"light": "#ddeeff",
"highContrast": "foreground"
}
}]
}
Users can then customize the color in the workspace.colorCustomization
setting and even themes can add a default color.
Color default values can be defined for light, dark and high contrast theme and can either be a reference to an existing color or a color hex value.
Hi, I am working on a PR for , a VSCode extension for LaTeX editing. In the PR, I make a latex preview in hover available rendering math equations in SVG format with MathJax and embedding the dataurl of generated SVG into a markdown text as an image source.
When rendering math equations, I have to tell MathJax which color to use for each rendering. Otherwise rendered equations are invisible on a certain theme. To work around the lack of color API in VSCode, I have to render equations in a WebView process, not in an extension process because we can know colors form css variables in the WebView process, as suggested by @eamodio. So when LaTeX-Workshop users close a WebView pane, my PR does not work. For LaTeX-Workshop users, opening a WebView pane as a pdf viewer is a usual thing. So the lack of color api seems to be a minor thing.
However, the same can be said for other documents having TeX-like equations. Docstring in python, for example. Let's think about API documents with math equations written in docstring. Python libraries should have tons of such API documents. If we want to render equations in them with MathJax, and to display them with API documents in hover, the same problem happens. And, for python programmers while coding, opening a WebView pane is an unusual thing.
Please notice that, for this purpose, extensions don't have to listen to theme changes. Equations are dynamically rendered each time. MathJax is enough fast to do that.
Regards,
On a light theme.
On a dark theme.
@aeschli Unfortunately that doesn't allow the colours to be used outside of the vscode API. π
@aeschli can you provide a reference for this? I feel like it might solve the @vviikk issue (which I'm also having) but I'm not sure I understand your suggestion.
Basically you're suggesting to use these? https://code.visualstudio.com/api/references/theme-color
Yes, ideally you use one of the existing colors, or define a new color id (see https://github.com/Microsoft/vscode/issues/32813#issuecomment-414227205) to allow users to theme your color as well. I know that there are still many gaps with this story, Colors in hover, computed colors...
If I understand correctly.
User defines a css color as editor.foreground
I need to do a lookup to workbench.colorCustomizations
to retrieve the css value
However if I do vscode.workspace.getConfiguration("workbench.colorCustomizations", undefined);
I get only the user defined settings. Is there I way I can get the flattened settings including all the theme colors. (e.g. if user did not specify a custom editor.foreground
)
No, you can not look up a color, that's the API that's missing.
But you can reference a color by using new ThemeColor('editor.foreground')
in certain APIs (status bar, decorators)
Aah that's the missing link. Awesome π I think it works now
I found a way to abuse the WebView to find out whether the theme is Dark or Light. It's a huge hack, but I need to know whether to use light/dark icons and there's no API, so...
It returns a promise with an enum of the theme:
detectTheme(context.subscriptions).then((theme) => {
if (theme === Theme.Dark) {
console.log("Using Dark theme!");
} else if (theme === Theme.Light) {
console.log("Using Light theme!");
} else if (theme === Theme.HighContrast) {
console.log("Using High Contrast theme!");
} else {
console.log("Failed to parse theme");
}
});
It'll automatically resolve with Unknown after a second, in case something has gone wrong. theme_detector.ts
looks like this:
import * as vs from "vscode";
export enum Theme {
Unknown,
Dark,
Light,
HighContrast,
}
export function detectTheme(disposables?: vs.Disposable[]): Promise<Theme> {
return new Promise((resolve) => {
let panel = createPanel();
const messageHandler = (bodyCssClass?: string) => {
if (panel) {
panel.dispose();
panel = undefined;
}
resolve(bodyCssClass ? parseClass(bodyCssClass) : Theme.Unknown);
};
// After a second, just resolve as unknown.
setTimeout(() => messageHandler(), 1000);
panel.webview.onDidReceiveMessage(
messageHandler,
undefined,
disposables,
);
panel.webview.html = themeDetectorScript;
});
}
const themeDetectorScript = `<html><body><script>
(function() {
const vscode = acquireVsCodeApi();
vscode.postMessage(document.body.className);
})();
</script></body></html>`;
function createPanel() {
return vs.window.createWebviewPanel(
"theme-detector",
"",
{
preserveFocus: true,
viewColumn: vs.ViewColumn.Beside,
},
{
enableScripts: true,
localResourceRoots: [],
},
);
}
function parseClass(bodyCssClass: string): Theme {
if (bodyCssClass && bodyCssClass.indexOf("vscode-dark") !== -1) {
return Theme.Dark;
} else if (bodyCssClass && bodyCssClass.indexOf("vscode-light") !== -1) {
return Theme.Light;
} else if (bodyCssClass && bodyCssClass.indexOf("vscode-high-contrast") !== -1) {
return Theme.HighContrast;
} else {
return Theme.Unknown;
}
}
I don't take any responsibility if you decide to use this, it could be fragile, but since I wrote it I thought I'd share it. I only need the theme, but you should be able to tweak the support extracting colours.
Note: It doesn't do any detection of the theme changing, so you may not want to hold onto the result for too long. Though there is also a visible flicker of the window and it could take up to a second to fail, so you might also not want to call it too much.
Can we initialize a ThemeColor based on a "scope" value? For example, if our extension wants to add text decorations based on the theme's setting for the "comment" scope, is it possible?
For the C++ extension, we essentially want to color the code based on our own language service's information instead of TextMate grammars which are not capable of classifying user-defined types correctly.
Can we initialize a ThemeColor based on a "scope" value?
@bobbrow That's currently not possible
I'm plus oneing @bobbrow's comment. We need the same thing for the Python Extension. We host the monaco editor in our 'Python Interactive' window and we have no way to get the colors for different scopes. Currently we have a hack of trying to find the current theme's json on disk.
The PDF previewer in LaTeX Workshop could benefit from knowing if the current theme is dark or light in order to decide whether to invert or not the background and foreground colors. In general, I believe the light/dark state is an important piece of information to expose.
I +1000 this one. My use case is that in Clojure there are three types of comments:
;
.(comment)
function, returning nil
whatever you pass it.#_
resulting in that the reader skips the whole form following it.These are often used differently, with ; comment
being the way to just comment something, (comment)
to keep test code in the file, and #_
to disable chunks of code.
To support this use I'm rendering the (comment foo)
and #_
stuff as dimmed, with intact syntax highlighting. But some users want those to be rendered the same as line based comments. Which I can't do, since I can't find the theme color value of comments.
Note that I can't solve this with tmLanguage
grammar, because dimming can't be done that way.
Here's another annoyance with not knowing if the theme is light or dark... Terminal ansi colours...
I had some code that used Grey and White in stack traces so that users own code frames was more visible (white) than framework code (grey). I tested it with both light and dark themes and found that the White ansi color codes produce a dark color in the themes (great!).
Well, until a user with a third party theme found that I was showing white text on a light background π
I figured I could raise this as a bug against their theme, however I failed to find any guidance on how themes should handle these, though I did found that in the VS Code code, ansiWhite is inverted for light/dark theme but ansiBlack
is not which leaves me more confused.
Came here via @DanTup - I'm trying to write a VS Extension to sync your color theme to Windows Terminal, but this bug blocks it. This information is available internally (via "Generate Color Theme from Current Settings"), but I have no sane access to it
@anaisbetts Iβve done this before. Itβs not exactly sane but it worked for me at the time.
const getTokenColorsForTheme = (themeName: string): TokenColors => {
const tokenColors = new Map();
let currentThemePath;
for (const extension of extensions.all) {
const themes = extension.packageJSON.contributes && extension.packageJSON.contributes.themes;
const currentTheme = themes && themes.find((theme) => theme.id === themeName);
if (currentTheme) {
currentThemePath = path.join(extension.extensionPath, currentTheme.path);
break;
}
}
const themePaths = [];
if (currentThemePath) { themePaths.push(currentThemePath); }
while (themePaths.length > 0) {
const themePath = themePaths.pop();
const theme = require(themePath);
if (theme) {
if (theme.include) {
themePaths.push(path.join(path.dirname(themePath), theme.include));
}
if (theme.tokenColors) {
theme.tokenColors.forEach((rule) => {
if (typeof rule.scope === "string" && !tokenColors.has(rule.scope)) {
tokenColors.set(rule.scope, rule.settings);
} else if (rule.scope instanceof Array) {
rule.scope.forEach((scope) => {
if (!tokenColors.has(rule.scope)) {
tokenColors.set(scope, rule.settings);
}
});
}
});
}
}
}
return tokenColors;
}
where
type TokenColors = Map<string, TokenColorSettings>
interface TokenColorSettings {
background?: string
fontStyle?: string
foreground?: string
}
Usage:
const themeName: string | undefined = workspace.getConfiguration("workbench").get("colorTheme");
const tokenColors = getTokenColorsForTheme(themeName);
@paulyoung Thanks for the solution! pretty hacky but it worked for me
This is a proposal for accessing the current workbench colors
/**
* Represents a color theme kind.
*/
export enum ColorThemeKind {
Light = 1,
Dark = 2,
HighContrast = 3
}
/**
* Represents a color theme.
*/
export interface ColorTheme {
/**
* The kind of this color theme: light, dark or high contrast.
*/
readonly kind: ColorThemeKind;
/**
* The id of the color theme. This corresponds to the value used in the `workbench.colorTheme` setting.
*/
readonly id: string;
/**
* Get the color value for a color identifier.
*
* @param colorIdentifier A color identifier as defined in https://code.visualstudio.com/docs/getstarted/theme-color-reference
* or contributed by an extension.
* @return The color as defined by the theme or in the color defaults. If the color identifier is
* unknown, `undefined` is returned.
*/
getColor(colorIdentifier: ThemeColor): Color | undefined;
}
export namespace window {
/**
* The currently active color theme as configured in the settings. The active
* theme can be changed via the `workbench.colorTheme` setting.
*/
export let activeColorTheme: ColorTheme;
/**
* An [event](#Event) which fires when the active theme changes.
*/
export const onDidChangeActiveColorTheme: Event<ColorTheme>;
}
I'm not sure why that API is needed? All of those colors are available in the root CSS for a webview?
What we really want is the token colors, not the CSS colors.
Token colors are coming too. I've just added the first implementation for https://github.com/microsoft/vscode/issues/77133 and once that has settled I'll propose something like
function getTokenStyle(type: string, modifiers: string[]): TokenStyle;
interface TokenStyle {
foreground: Color:
bold: boolean:
italics: boolean:
underline: boolean;
}
Would onDidChangeActiveColorTheme() fire when colors are changed by settings that override theme colors? (i.e. editor.tokenColorCustomizations).
@Colengms Yes
@APerricone for Webviews you can use the vscode css vars in your css. Like I do here: https://github.com/BetterThanTomorrow/calva/tree/master/assets/styles
@PEZ sorry, i saw the documentation 5 minutes after the comment, so I removed the comment... Thank you anyway.
Any ETA of this moving from proposed state to stable?
The APIs to get the theme kind (light / dark / hc) is now made public API. This should help with selecting the corresponding images in hovers.
Only kind? Not the getting color value from id as in https://github.com/microsoft/vscode/issues/32813#issuecomment-558242506?
Im creating an extension and I added an Icon to my webview panel but I currently can't change its color depending on the Color Theme. Couldn't you allow me to use an SVG with a fill color using a VSCode CSS property? or do the same as it happens to the "editor/title" button.
For the SVG suggestion I could do this (I tested and it does not work):
<path fill="var(--vscode-class)"></path>
For the editor menu I can switch the icons using the Manifest, like show below. But the icon for the Panel I could not. it would be great if the panel had two properties too somewhere or use at least the same icons from command.
Here you can see that the Panel Icon and Editor Icon have different colors
While here they both have the same colors.
"contributes": {
"commands": [
{
"command": "YOUR_COMMAND",
"title": "COMMAND TITLE",
"icon": {
"light": "/.images/icon2.png",
"dark": "/.images/icon2.png"
}
}
],
"menus": {
"editor/title": [
{
"command": "YOUR_COMMAND",
"alt": "markdown.showPreviewToSide",
"group": "navigation"
}
]
}
}
I'm not knowledgeable about webviews, but from reading https://github.com/microsoft/vscode/pull/54912 also web view icons support light and dark variants. If that's not good enough, can you file a new issue against web views?
I'm not knowledgeable about webviews, but from reading #54912 also web view icons support light and dark variants. If that's not good enough, can you file a new issue against web views?
But the doc does not say how to do it.
@mjbvz Can you help @AllanOricil ?
@AllanOricil WebviewPanel.iconPath
takes a dark
and light
icon variant: https://github.com/microsoft/vscode/blob/fa55787dbc15086031e596b7da434644878a2add/src/vs/vscode.d.ts#L6873
@AllanOricil
WebviewPanel.iconPath
takes adark
andlight
icon variant:
Thanks @aeschli and @mjbvz !!!! I was using this Doc https://code.visualstudio.com/api/references/vscode-api
For one particular use case -- I would love to use this in an extension I'm working to provide completions for webview colors, so that I could show the user's current color in the completion items.
I still want it to make more of the GitLens blame annotations themeable -- since gutterIconPath
isn't themeable today, so I need to generate svgs with specific colors. But if I could read a theme color, then I could use that value to re-generate the SVGs
I found another use case. Imagine i have an extension that locally serves a page, so the user can work in a separate window. Now imagine I changed theme inside Vscode, how can I notify the local server the theme has been changed, so I can also apply the new theme on the page? I cant. There should be an event we can hook somewhere to get the new theme that was applied.
My personal use case would be setting my rooms Philips Hue lights coloring according to my current vsc themes colors when I open vscode :) That would be neat, altough achievable by hardcoding if the theme is not changed too often.
I want to generate svg diagrams representing inline regular expressions, and want to use the theme colors for elements of the generated illustration.
@duncanbeevers In this case you can in the same way I did in https://github.com/APerricone/vscode-regexper-unofficial. Simply use the css variables https://code.visualstudio.com/api/extension-guides/webview#theming-webview-content
I think we should add support for accessing theme's colors programmatically.
For instance let's take as an example the popular OneDark Pro theme, I'd like to access colors defined under tokenColors.
My use case: I'm making an extension that decorates some tokens, and I'd like them to have the same color that comments have in my theme, the problem is that the regex I use to find those tokens depends on some configurable value, so I cannot pre-compute it in advance and just put it in a
.tmLanguage
file.It's already possible to somehow access colors defined under the colors key, via something like
new vscode.ThemeColor ( 'activityBar.background' )
, adding support for this sounds like a useful generalization to me.What do you think?