-
Notifications
You must be signed in to change notification settings - Fork 1.8k
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
Automatic switching between light and dark theme (CSI 2031) #15227
Comments
You could probably do this in a hook by calling term query something like this on a supported terminal. term query "\e[?996n" --prefix "\e[?997;" --terminator "n" | decode Then depending on whether the response is 1 or 2 load a dark or light theme from the nu_scripts repo. |
What are the two strings: |
They're from the linked urls above. It explains how it works. |
@fdncred thanks, that looks promising, although I hit an issue, here is my nushell hook together with some debug prints:
When I run nushell with the hook, the hook itself works as expected, correctly detects system theme and changes
Is this correct behavior? |
To be clear, I've never done what you're trying to do. So, this is a bit of trial and error. I'm not sure it'll work at all, but it might. You should probably be activating themes like this https://github.com/nushell/nu_scripts/tree/main/themes#set-terminal-colors or https://github.com/nushell/nu_scripts/tree/main/themes#load-a-color_config Also, I'd try changing your switch_theme custom command to something more like this. const theme_name = if $system_theme == $dark_theme { } else { } Then either |
Understand, I appreciate your help as my nushell knowledge is very limited. I reworked the code to use the standard theme activation (load the modules with
But it suffers from the same problem - modifications made to the |
I think assigning the theme in $env.config.color_config probably won't work unless your @NotTheDr01ds do you have any advice here? |
Using the
|
I think that is expected, CSI 2031/996 is quite new and supported only in couple modern terminals (ghostty, kitty, contour, maybe some others). I'll have time to test the |
Yup, that's right. The terminal has to support those ansi escape sequences, otherwise it will wait until you hit ctrl+c. |
Edit: I actually got it to work using a So I've fallen down the same rabbit hole a few days ago My strategy was a bit different since This is what I've got so far # Shamelessly stolen/ported from https://github.com/bash/terminal-colorsaurus/tree/main/crates/terminal-colorsaurus and https://github.com/bash/terminal-colorsaurus/tree/main/crates/xterm-color
module color {
def parse_channel_scaled []: string -> float {
let input = $in
let scale = 2 ** (($input | str length) * 4)
($input | into int --radix 16) / $scale
}
def gamma [v: float]: nothing -> float {
if $v <= 0 {
0
} else if $v <= 0.04045 {
$v / 12.92
} else {
(($v + 0.055) / 1.055) ** 2.4
}
}
def luminance []: record<r: float, g: float, b: float> -> float {
let c = $in
0.2126 * (gamma $c.r) + 0.7152 * (gamma $c.g) + 0.0722 * (gamma $c.b)
}
def luminance_to_perceived_lightness []: float -> float {
let luminance = $in
if $luminance <= 216. / 24389. {
$luminance * (24389. / 27.)
} else {
($luminance ** (1 / 3)) * 116. - 16.
}
}
def perceived_lightness []: record<r: float, g: float, b: float> -> float {
($in | luminance | luminance_to_perceived_lightness) / 100
}
def query_color [which: string]: nothing -> record<r: string, g: string, b: string> {
let osc = if $which == "bg" { "11" } else { "10" }
term query $'(ansi osc)($osc);?(ansi st)' --prefix $'(ansi osc)($osc);' --terminator (ansi st)
| decode
| parse 'rgb:{r}/{g}/{b}'
| get 0
}
def parse_xterm_rgb_color []: record<r: string, g: string, b: string> -> record<r: float, g: float, b: float> {
$in
| update r {parse_channel_scaled}
| update g {parse_channel_scaled}
| update b {parse_channel_scaled}
}
def get_bg_color []: nothing -> record<r: float, g: float, b: float> {
query_color "bg" | parse_xterm_rgb_color
}
def get_fg_color []: nothing -> record<r: float, g: float, b: float> {
query_color "fg" | parse_xterm_rgb_color
}
export def get_theme []: nothing -> string {
let fg = get_fg_color | perceived_lightness
let bg = get_bg_color | perceived_lightness
if $bg < $fg {
"dark"
} else if $bg > $fg or $bg > 0.5 {
"light"
} else {
"dark"
}
}
}
# Dark theme
use ~/code/nu_scripts/themes/nu-themes/catppuccin-mocha.nu
# Light theme
use ~/code/nu_scripts/themes/nu-themes/catppuccin-latte.nu
def --env _theme_pre_prompt [] {
use color get_theme
let current_theme = $env | get -i theme | default ""
let theme = get_theme
if $current_theme != $theme {
# Theme has changed
$env.theme = $theme
match $theme {
"dark" => {
catppuccin-mocha set color_config
$env.LS_COLORS = (vivid generate catppuccin-mocha)
}
"light" => {
catppuccin-latte set color_config
$env.LS_COLORS = (vivid generate catppuccin-latte)
}
}
}
}
$env.config = ($env | default {} config).config
$env.config = ($env.config | default {} hooks)
$env.config = (
$env.config | upsert hooks (
$env.config.hooks
| upsert pre_prompt ($env.config.hooks | get -i pre_prompt | default [] | append _theme_pre_prompt)
)
) |
Some random thoughts:
Of course, hybrid solutions are possible (e.g. try using As for the configuration, I'm not sure what it would look like... maybe supporting Even if switching the theme is handled natively, I think it would still be useful to have a |
I also managed to get it working with @abusch I agree with your analysis. I would add that another downside to
My code for automatic theme switching with CSI 996: use ($nu.default-config-dir | path join "rose-pine-moon.nu")
use ($nu.default-config-dir | path join "rose-pine-dawn.nu")
def --env switch_theme [] {
const dark_theme = 1
const light_theme = 2
let system_theme = term query "\e[?996n" --prefix "\e[?997;" --terminator "n" | decode | into int
if $system_theme == $dark_theme {
rose-pine-moon set color_config
} else if $system_theme == $light_theme {
rose-pine-dawn set color_config
} else {
let error_msg = "Unknown system theme returned from terminal: " + ($system_theme | into string)
error make {msg: $error_msg }
}
}
$env.config.hooks.pre_execution = ([ switch_theme ]) |
Related problem
Currently, nushell does not have support for switching between dark and light theme - there is always only one color theme configured in
$env.config.color_config
.Several terminals (Ghostty, Contour, Kitty) have implemented support for CSI 2031 https://github.com/contour-terminal/contour/blob/f3c3334aa5c861348c5bbe8ffe572c872eef2e08/docs/vt-extensions/color-palette-update-notifications.md which allows terminal applications to receive updates regarding the current system theme, and then automatically switch between light/dark theme.
It would be nice if nushell had support for this.
Describe the solution you'd like
$env.config.color_config
to support light and dark theme, e.g.:Describe alternatives you've considered
No response
Additional context and details
No response
The text was updated successfully, but these errors were encountered: