terminal
terminal copied to clipboard
Theme-controlled color scheme switch
Description of the new feature/enhancement
It would be nice to be able to specify two schemes per profile; one for light mode and one for dark. I imagine that would be especially useful with "requestedTheme": "system".
Proposed technical implementation details (optional)
Could be implemented in the form of:
"colorScheme": {
"light": "BlulocoLight",
"dark": "BlulocoDark"
}
or:
"colorSchemeLight": "BlulocoLight",
"colorSchemeDark": "BlulocoDark"
I like the idea. It might make sense to instead of colorSchemeLight and colorSchemeDark preserve the existing colorScheme attribute and add an alternateScheme attribute which could be switchable to. Otherwise, an additional attribute would be required to specify which theme mode to startup with.
Alternatively, this feature could be implemented by making the color schemes themselves have dual palettes: one for light and one for dark. So you could assign to a profile a scheme, like Campbell, and have a hotkey to switch between light and dark palette.
I like the object idea since it doesn't use any other new name and instead uses current one. I'll elaborate on this bit
In vscode it was implemented as a 2 additional keys: preferredDarkColorTheme and preferredLightColorTheme. colorScheme key remain unchanged and the way it works, when vscode switches to appropriate theme, it changes the value of colorScheme in user settings (therefore updating the application visuals). This mechanism probably has something to do with the fact that vscode can't update settings in runtime without updating the file (https://github.com/microsoft/vscode/issues/43226), but I digress. I'm using a dotfiles repo on multiple workstations and automatic system theme switching (based on time of the day). And I'm constantly stumbling across situations when settings.json was updated remotely (by some meaningful stuff) and locally (colorScheme) which makes me do stash then pull again, then stash pop. It's also breaks automatic pull on dotfiles repo.
Of course it doesn't concern terminal since it doesn't update its settings in runtime when profiles.json is updated, but I still find it neat having string literal or object as config).
Having additional keys also increases ambiguity of (what will be selected?)
"colorSchemeLight": "BlulocoLight",
"colorSchemeDark": "BlulocoDark",
"colorScheme": "Campbell"
Adding alternateColorScheme is ambiguous in a sense that it's not clear what is dark and what is light, so I don't think it should be pursued
Alternatively, this feature could be implemented by making the color
schemesthemselves have dual palettes: one for light and one for dark. So you could assign to aprofileascheme, like Campbell, and have a hotkey to switch between light and dark palette.
Unless someone builds a custom tuned color schema, this doesn't sound right to me. People's perception of light vs dark best colors might differ substantially (mine do), so IMHO making it a specific choice in the schema object makes sense.
I'm unsure of how Windows Terminal config schema backward compatibility is treated, but my suggestions would then be:
If it's OK to change the schema for an existing key:
"colorScheme": { "light": "Foo Light", "dark": "Foo Dark" }
And if it's not really OK to change the key type, then I'd introduce a new keyword (colorSchemes?) and deprecate the old one, maybe migrating the user configs on the fly with a new build version.
Any progress on this?
Nope. We'll make sure to update this thread when there is. In the meantime, might I recommend the Subscribe button?
That way you'll be notified of any updates to this thread, without needlessly pinging everyone on this thread ☺️
Workaround:
I have an AutoHotKey script that I run at sun-up and sun-down that changes the themes for programs that don't change automatically like GitKraken and KeyWeb. Windows Terminal thankfully automatically changes if you change its settings file, so this Powershell script does what I want:
$from = $args[0]
$to = $args[1]
$settingsPath = $env:LocalAppData + "\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\settings.json";
# https://stackoverflow.com/a/30893960
$content = [System.IO.File]::ReadAllText($settingsPath).Replace(
"`"colorScheme`": `"" + $from + "`",",
"`"colorScheme`": `"" + $to + "`",");
[System.IO.File]::WriteAllText($settingsPath, $content);
It's blunt and fragile - you could probably improve it by using JQ or actually parsing the JSON. But I'm lazy and this simple string replace works. I recommend you backup your settings.json before trying out this script. I didn't use AHK's string replace because that language gives me conniptions. I'm not sure my $settingsPath works for anyone else - find yours by hitting ctrl+shift+comma in WT.
I have the following function in AHK to make running Powershell scripts easier:
; https://www.autohotkey.com/boards/viewtopic.php?p=224271#p224271
PowerShell(Script, WorkingDir := "", Options := "", Params := "-ExecutionPolicy Bypass") {
Run % "PowerShell.exe " . Params . " -Command &{" . Script . "}", % WorkingDir == "" ? A_ScriptDir : WorkingDir, % Options
}
Finally, with the following, I can hit ctrl+alt+win+PageDown to go to dark mode, and PageUp for light mode.
^#!PgDn::
PowerShell("./wt-theme-switch.ps1 'One Half Light' 'Campbell'")
Return
^#!PgUp::
PowerShell("./wt-theme-switch.ps1 'Campbell' 'One Half Light'")
Return
This assumes the PowerShell script is called ./wt-theme-switch.ps1 and it lives in the same directory as your AHK script. I use two separate keys because sometimes one of my other programs fails to switch themes and I need to run it a second time, so my hotkeys need to be idempotent. You may want to make the PowerShell script more intelligent and toggle to the other theme, based on the current contents, and save yourself a hotkey.
I need to ~steal~ borrow this to add to my systray app which does the flippity on dark/light on command (for when I decide that I should work outside for a while to provide this meat suit with vitamin d). Good Jeorb!
@dharmaturtle, awesome! Just created a Windows schedule based on your powershell, so the theme auto update a 7AM and 7PM
https://gist.github.com/biutas/2a6132170f81319a282c7135abb3dce9
Added a specification file for this feature request.
#12613
This is now the only app I use that doesn't match theme up with Windows light/dark mode (VS Code recently added it). So I'm slightly eager to hear when this feature is shipped 👍
For those who are using Auto Dark Mode: you can use its newly added script execution feature to automatically execute a script like the suggested above. I am successfully using it to automatically switch the colour scheme when my Windows 11 Dark Mode is toggled. It's still rather hacky, but better than the AHK method suggested, in my opinion.
I had trouble getting the powershell script to work with Auto Dark Mode, so I wrote a new (slightly more powerful) script in node. For anyone interested here is the script:
const { readFileSync, writeFileSync } = require("fs");
const { join } = require("path");
// color scheme configurations
// The dark scheme will be swapped with the light scheme and vice versa
const colorSchemes = [
{ dark: "Campbell", light: "Campbell Powershell" },
{ dark: "One Half Dark", light: "One Half Light" },
{ dark: "Solarized Dark", light: "Solarized Light" },
{ dark: "Tango Dark", light: "Tango Light" },
];
// parse argument to determine which mode to switch to
const modeArg = process.argv[2];
if (modeArg !== "-dark" && modeArg !== "-light") {
console.error(`Invalid Argument. Argument must be '-dark' or '-light'. Received '${modeArg}'`);
process.exit(-1);
}
const isDarkMode = modeArg === "-dark";
// read Windows Terminal config
const pathToWinTermConfig = join(
process.env.LocalAppData,
"/Packages/Microsoft.WindowsTerminal_8wekyb3d8bbwe/LocalState/settings.json"
);
const configFileContents = readFileSync(pathToWinTermConfig).toString("utf-8");
const config = JSON.parse(configFileContents);
// update Windows Terminal config
config.profiles.list.forEach((profile) => {
const color = colorSchemes.find((c) => profile.colorScheme === c[isDarkMode ? "light" : "dark"]);
if (color) profile.colorScheme = color[isDarkMode ? "dark" : "light"];
});
// write Windows Terminal config changes to file system
writeFileSync(pathToWinTermConfig, JSON.stringify(config, null, 2));
Below is the Auto Dark Mode script config. The Auto Dark Mode script file should be located in C:\Users\<username>\AppData\Roaming\AutoDarkMode.
Note: I saved the node script in the root of my C drive and named it toggle-win-term-color.js
Enabled: true
Component:
TimeoutMillis: 10000
Scripts:
- Name: WindowsTerminal
Command: node
ArgsLight: [C:\toggle-win-term-color.js, -light]
ArgsDark: [C:\toggle-win-term-color.js, -dark]
AllowedSources: [Any]
Since powershell can parse JSON I binge made a slightly more polished implementation of the ADM route.
Running
powershell -nologo -noprofile -executionpolicy bypass -command "(iwr `"https://gist.githubusercontent.com/Gravifer/6511126e6c174c3ab7c647be43735dcc/raw/windowsTerminal_themeToggler.ps1`").content | out-file themeToggler.tmp.ps1; .\themeToggler.tmp.ps1; remove-item themeToggler.tmp.ps1"
anywhere will have the script initialized (which can be put into ADM's scripts.yaml). Modify themetoggler.config.json in the same folder where settings.json is to pair the Light-Dark theme colorSchemes manually. A simple fix for PowerShell's grammar highlighting palette is provided in the gist; samples of themetoggler.config.json and scripts.yaml of Auto Dark Mode are supplied there as well.
- Ideas are taken from @dharmaturtle @biutas @Ririshi @AndrewSmithDev
Update: Now using Powershell 5.1 is OK.
For those who are using Auto Dark Mode: you can use its newly added script execution feature to automatically execute a script like the suggested above. I am successfully using it to automatically switch the colour scheme when my Windows 11 Dark Mode is toggled. It's still rather hacky, but better than the AHK method suggested, in my opinion.
Just to help clarify: a spec was accepted in #12613. We probably won't have time to get to this one soon, but I don't think it'd be a terribly difficult change to make. I'd be happy to give pointers if anyone's interested in contributing the code ☺️
implementation roadmap:
- Spec link
- You'll probably need to remove
colorSchemefrom MTSM_APPEARANCE_SETTINGS and instead parse manually- A single string value -> set both
DarkColorSchemeNameandLightColorSchemeName - An object -> parse each separately
- A single string value -> set both
- Modify TerminalSettings::_ApplyAppearanceSettings to only apply the UI-theme-appropriate scheme
@zadjii-msft I will start work on this feature (Sep 19th) for MSFT hackathon. ☺️ https://hackbox.microsoft.com/project/5766
Hey All, attached is a draft PR of the work done now and the code cleaned up a bit. Right now there is two big bugs that are holding me back from doing the PR. https://github.com/microsoft/terminal/pull/14064
First is there is no current way to trigger a settings refresh when OS Theme switches. Any advice on how to trigger an event when the OS Theme switches would be useful. WM_THEMECHANGED does not seem to be working in the message handler.
Second, the profile appearance control preview does not update to the "selected" choice for color scheme. I am still trying to debug this a bit, but any suggestions are accepted. I think this is because the preview pulls directly from the profile.defaultappearance, but we never offically save the defaultappearance "ColorSchemeName" because the user hasnt pressed save yet. So some future research will be needed to discover how to force this up.
There is future work needed with the GUI, but will not be apart of this PR as @carlos-zamora mentioned this would need some design considerations from the team.
For now, you can pull the branch and set the dark and light color schemes under the profile though and play around with it. Can accept either single string or object.
example: "colorScheme" : "One Half Dark" or "colorScheme": { "dark": "One Half Dark", "light": "One Half Light" },
Ill be traveling (Sep 23 2022) and will pick up work and considerations / conversations (Sep 24 2022)
- Update: Got covid, will resume when better
Hey everybody. We've got a bit of a quandry here, that #14064 helped draw attention to.
Do folks want the scheme to sync to the Terminal's theme, or the OS's theme? These each come with pro's and cons.
For clarity, the Terminal theme is the window's applicationTheme, which controls the appearance of almost all controls in the app - the command palette, the tabs, the menus, etc. In 1.16, there are also Theme objects for more customization, but ultimately we're interested in the window.applicationTheme property (which is just theme before 1.16).
The Scheme is the colors of the box of text itself. Importantly, this controls the main background of the window.
- OS theme:
- If the user is automatically changing the OS theme based off time of day, the Terminal can automatically pick up on that
- If the user is changing the terminal theme frequently, between light and dark themes, the scheme of the terminal won't reflect this. The user would need to change schemes to match.
- Terminal theme:
- If the user wants the scheme to match the OS theme, they need to set
applicationThemetosystem. - The default theme for the Terminal on 1.16 sets
applicationThemetodark, so users would necessarily need to also change the terminal theme if they want to use this feature.- It's a little wacky to get a dark titlebar, with OS theme set to light, and
applicationThemeset to system:
- It's a little wacky to get a dark titlebar, with OS theme set to light, and
- If the user wants the scheme to match the OS theme, they need to set
We're kinda at an impasse here, and want to know what folks think. I suspect most people who are looking for this feature want the scheme to match the OS theme, always, regardless of terminal theme. But I don't want to make assumptions! Maybe folks are using a tool to swap the Terminal theme based on time of day instead!
There's also a mind to have the Terminal's theme match the OS theme with a similar syntax (draft spec), but I don't think that actually helps any of our problems here.
If the user is automatically changing the OS theme based off time of day, the Terminal can automatically pick up on that
This is all I care about. I'm not a friend of dark mode at day at all. And vice versa. It hurts my eyes.
If the user is automatically changing the OS theme based off time of day, the Terminal can automatically pick up on that
This is all I care about. I'm not a friend of dark mode at day at all. And vice versa. It hurts my eyes.
Same thing, I use a script to change the OS theme and some applications that don't have an option to follow it.
Just one addition: I would also like the option to change the scheme based on the OS theme but I am not sure if that should be the default or if there's enough info to have matching dark and light schemes without user input. I think someone above mentioned VSCode having an explicit setting for picking a dark and a light scheme that should be used in this case.
To me the most complete solution would look like this:
- Application theme lets me choose light, dark, or system. This controls the "chrome" of the app (title bar, tabs, command palette)
- Scheme lets me choose two schemes: one for dark theme and one for light theme. Then, however I change the application theme (directly in Terminal settings, or by changing my system theme) I get a scheme that works for me. I can even set both schemes to be the same if I don't want them to change depending on app theme.
real quick clarity:

The difference between Theme and Scheme is very important here, lets try to not mix them up
This would be my ideal behavior:
- OS switches to dark mode (either due to time of day, or user has explicitly switched system theme)
- Terminal theme (i.e. title bar, controls, menus, etc) switches to match
- Terminal scheme switches to some custom scheme which I have explicitly designated as my "dark mode scheme", e.g. `
- OS switches to light mode
- Terminal theme switches to light
- Terminal scheme switches to my custom "light mode scheme"
Wow overwhelming initial feedback seems like folks want theme AND scheme to match the OS theme. That kinda sounds like an endorsement for "the scheme matches the Terminal's theme", and anyone who wants this feature manually changes their Terminal theme to system (which will mean the Terminal's UI and the color scheme will both reflect the OS theme).
Right?
will mean the Terminal's UI and the color scheme will both reflect the OS theme
@zadjii-msft well, yes and no. We want to be able to manually specify a scheme for each theme. That could mean a light scheme with a dark theme, or the more usual dark on dark and light on light. Being able to set a scheme per theme is the important bit IMO
Rough proposal: two new config properties: colorSchemeLight and colorSchemeDark. To preserve previous behavior, if the original colorScheme is explicitly set, then it is always used, regardless of the current theme. But if colorScheme is not set, and both colorSchemeLight/Dark are set, then we activate the "auto switching" behavior
Er, yes. I was too short there. More verbosely:
The user can set both a colorScheme.light and a colorScheme.dark. When evaluating the settings, the Terminal will pick one of those two, depending on which applicationTheme the Terminal is currently using. Users who want this feature to match the OS theme, should set their theme to system, and the Terminal will automatically switch those schemes based on the OS theme.
If the user's only got a colorScheme set, then that acts as the same value for both colorScheme.light and a colorScheme.dark.
FWIW, this is how #14064 is currently implemented, but there was some confusion because the spec wasn't exactly clear as to which theme (terminal or OS) the scheme should be following.
@zadjii-msft I like the interpretation you just posted. It's the most straightforward / expected default behavior. However, are you sure you are linking to the correct PR?
@zadjii-msft I like the interpretation you just posted. It's the most straightforward / expected default behavior. However, are you sure you are linking to the correct PR?
SURE DIDN'T. Fatfingered that one. The correct PR is #14064.
:tada:This issue was addressed in #14064, which has now been successfully released as Windows Terminal Preview v1.17.1023.:tada:
Handy links: