Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Theme-controlled color scheme switch #4066

Closed
alkaitagi opened this issue Dec 27, 2019 · 32 comments · Fixed by #14064
Closed

Theme-controlled color scheme switch #4066

alkaitagi opened this issue Dec 27, 2019 · 32 comments · Fixed by #14064
Labels
Area-Settings Issues related to settings and customizability, for console or terminal Area-User Interface Issues pertaining to the user interface of the Console or Terminal Help Wanted We encourage anyone to jump in on these. Issue-Feature Complex enough to require an in depth planning process and actual budgeted, scheduled work. Product-Terminal The new Windows Terminal. Resolution-Fix-Committed Fix is checked in, but it might be 3-4 weeks until a release.
Milestone

Comments

@alkaitagi
Copy link

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"
@alkaitagi alkaitagi added the Issue-Feature Complex enough to require an in depth planning process and actual budgeted, scheduled work. label Dec 27, 2019
@ghost ghost added Needs-Triage It's a new issue that the core contributor team needs to triage at the next triage meeting Needs-Tag-Fix Doesn't match tag requirements labels Dec 27, 2019
@mkitzan
Copy link
Contributor

mkitzan commented Dec 27, 2019

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.

@DHowett-MSFT DHowett-MSFT added this to the Terminal Backlog milestone Jan 6, 2020
@DHowett-MSFT DHowett-MSFT added Area-Settings Issues related to settings and customizability, for console or terminal Area-User Interface Issues pertaining to the user interface of the Console or Terminal Product-Terminal The new Windows Terminal. and removed Needs-Triage It's a new issue that the core contributor team needs to triage at the next triage meeting labels Jan 6, 2020
@ghost ghost removed the Needs-Tag-Fix Doesn't match tag requirements label Jan 6, 2020
@saitonakamura
Copy link

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 (microsoft/vscode#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

@vriesk
Copy link

vriesk commented May 25, 2021

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.

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.

@henry-js
Copy link

henry-js commented Jun 1, 2021

Any progress on this?

@zadjii-msft
Copy link
Member

Nope. We'll make sure to update this thread when there is. In the meantime, might I recommend the Subscribe button?
image
That way you'll be notified of any updates to this thread, without needlessly pinging everyone on this thread ☺️

@dharmaturtle
Copy link

dharmaturtle commented Dec 11, 2021

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.

@fluffynuts
Copy link

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!

@biutas
Copy link

biutas commented Feb 4, 2022

@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

@zadjii-msft zadjii-msft added the Help Wanted We encourage anyone to jump in on these. label Apr 12, 2022
@Ririshi
Copy link

Ririshi commented Apr 20, 2022

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.

@AndrewSmithDev
Copy link

AndrewSmithDev commented May 14, 2022

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]

@Gravifer
Copy link

Gravifer commented May 20, 2022

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.

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.

@zadjii-msft
Copy link
Member

zadjii-msft commented Aug 25, 2022

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:

@bennettnicholas
Copy link
Contributor

@zadjii-msft I will start work on this feature (Sep 19th) for MSFT hackathon. ☺️ https://hackbox.microsoft.com/project/5766

@bennettnicholas
Copy link
Contributor

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. #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"
},

@bennettnicholas
Copy link
Contributor

bennettnicholas commented Sep 23, 2022

Ill be traveling (Sep 23 2022) and will pick up work and considerations / conversations (Sep 24 2022)

  • Update: Got covid, will resume when better

@ghost ghost added the In-PR This issue has a related PR label Oct 3, 2022
@zadjii-msft
Copy link
Member

zadjii-msft commented Nov 11, 2022

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 applicationTheme to system.
    • The default theme for the Terminal on 1.16 sets applicationTheme to dark, 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 applicationTheme set to system:
        MicrosoftTeams-image (15)

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.

@boop5
Copy link

boop5 commented Nov 11, 2022

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.

@fabianlupa
Copy link

fabianlupa commented Nov 11, 2022

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.

@jerivas
Copy link

jerivas commented Nov 11, 2022

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.

@zadjii-msft
Copy link
Member

real quick clarity:

image

The difference between Theme and Scheme is very important here, lets try to not mix them up

@reynoldsbd
Copy link
Member

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"

@zadjii-msft
Copy link
Member

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?

@jerivas
Copy link

jerivas commented Nov 11, 2022

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

@reynoldsbd
Copy link
Member

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

@zadjii-msft
Copy link
Member

zadjii-msft commented Nov 11, 2022

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.

@khuongduybui
Copy link

@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
Copy link
Member

@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.

@ghost ghost closed this as completed in #14064 Dec 6, 2022
ghost pushed a commit that referenced this issue Dec 6, 2022
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? -->
## Summary of the Pull Request
This pull request solved the problem of users not being able to set color schemes specifically for dark or light mode. Now the code has been updated to accept a dark and light color scheme in the json. The old setting is still compatible. Keep in mind if you update your color scheme through the settings UI, it will set both dark and light to the color scheme selected. This is because the settings UI update for selecting both Dark and Light color schemes is not supported yet.

This also solves the problem of the UI not using the system OS theme. Now you can select system theme and your color scheme will be selected based on if the system theme is dark or light.


<!-- Other than the issue solved, is this relevant to any other issues/existing PRs? --> 
## References
#4066 

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
* [x] Closes #4066 
* [x] Closes #14050
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA. 
* [x] Tests added/passed I believe so, added one test to ColorSchemeTests.cpp and I believe it passed. Also had to modify TerminalSettingsTests.cpp to accept the new ApplyAppearanceSettings function template
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [x] Schema updated.
* [x] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #4066 and also teams messages with @carlos-zamora 

<!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments
-Removed ColorSchemeName from MTSMSettings.h in order to process the setting for both string and object.
-Added DarkColorSchemeName and LightColorSchemeName properties to the AppearanceConfig to replace ColorSchemeName.
-Hacked a few processes to play nice with all 3 properties listed above as in some cases around the UI, we need to still use the ColorSchemeName. Once we change the UI I believe we can go back to just Dark and LightColorSchemeName
-Added and Updated Test to align to the new code.

Acceptable Json values,

"colorScheme": 
                {
                    "dark": "Campbell",
                    "light": "Campbell"
                }
or

"colorScheme": "Campbell"

<!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
Individual testing along with the test case added.
@ghost ghost added Resolution-Fix-Committed Fix is checked in, but it might be 3-4 weeks until a release. and removed In-PR This issue has a related PR labels Dec 6, 2022
@ghost
Copy link

ghost commented Jan 24, 2023

🎉This issue was addressed in #14064, which has now been successfully released as Windows Terminal Preview v1.17.1023.:tada:

Handy links:

@progressio
Copy link

For those who don't understand how to use new functionality:

  1. edit "Terminal" settings manually(1.19.10573.0 GUI has no such option yet) in settings.json(how to find/open it)
  2. at the "profiles"-> "defaults" section set desired schema for each theme:
"profiles": 
{
     "defaults": 
     {
          "colorScheme":
          {
               "light": "One Half Light",
               "dark": "Campbell"
          }
     },

@Tritlo
Copy link

Tritlo commented Aug 28, 2024

This is great! But it would be better if the option was present in the UI

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Settings Issues related to settings and customizability, for console or terminal Area-User Interface Issues pertaining to the user interface of the Console or Terminal Help Wanted We encourage anyone to jump in on these. Issue-Feature Complex enough to require an in depth planning process and actual budgeted, scheduled work. Product-Terminal The new Windows Terminal. Resolution-Fix-Committed Fix is checked in, but it might be 3-4 weeks until a release.
Projects
Status: Done
Development

Successfully merging a pull request may close this issue.