8000 Add mode 2031 support (automatic dark/light mode) by jonathanslenders · Pull Request #4353 · tmux/tmux · GitHub
[go: up one dir, main page]

Skip to content

Conversation

@jonathanslenders
Copy link
@jonathanslenders jonathanslenders commented Jan 27, 2025

See: #4269

This PR implements:

  • Enable mode 2031 when the terminal is Vt100-like to subscribe to theme updates from the terminal.
  • Handle mode 2031 for applications running within tmux.
  • Adds a client_theme variable for usage in the formatting.
  • This adds two hooks: client-dark-theme and client-light-theme that allows a tmux config to respond to theme changes and update colors.

Usage instructions

For anyone coming across this PR:

  1. Use a terminal emulator that also supports mode 2031 like Ghostty or Kitty. Ghostty can automatically follow the system theme, when configured like that. E.g., in ~/.config/ghostty/config, do:
theme = "light:rose-pine-dawn,dark:rose-pine"
  1. In the tmux config, bind shell scripts to the client-{dark,light}-theme events. In these shell scripts, you can then perform tmux commands that toggle the style of the status bar and tmux panes.
set-hook -g client-dark-theme 'run-shell ~/bin/tmux-dark-theme.sh'
set-hook -g client-light-theme 'run-shell ~/bin/tmux-light-theme.sh'

For debugging, you can display the theme in the status bar:

set -g status-right " %H:%M %d-%b-%y [#{client_theme}]"
  1. For neovim, use a recent neovim version that supports mode 2031. This will automatically toggle the bg setting between light and dark following tmux and ghostty. Then use a color scheme like rose-pine that follows the bg setting.

Testing the protocol

Query whether mode 2031 is supported (should return <csi>?2031;2$y):

echo -e '\e[?2031$p'

Within a tmux pane, the following should report the current theme (<CSI>?997;1n for light a <CSI>?997;2n for dark):

echo -e "\e[?996n"

To subscribe for theme updates:

echo -e "\e[?2031h"

To unsubscribe:

echo -e "\e[?2031l"

When tmux is styled with a background color of its own, this should automatically be taken into account and reported whenever this changes. Do echo -e "\e[?2031h" and then type the following in the tmux prompt:

set window-style 'fg=#000000,bg=#ffffff'

Co-Author: Nicholas Marriott <nicholas.marriott@gmail.com>
@nicm
Copy link
Member
nicm commented Jan 30, 2025

Good stuff, thanks - let me know when you have the last bits finished.

@jonathanslenders
Copy link
Author
jonathanslenders commented Feb 25, 2025

@nicm : The last bit is finished now. That's the second commit in this PR. Hope this is good to be merged. ;)

edit: for clarity, moving the final piece that is now addressed below in this comment, out of the PR description:

I'm don't think screen_redraw_draw_pane is the best place to call window_pane_send_theme_update since 1) PANE_STYLECHANGED does not always mean redraw, so it seems like it might miss updates and 2) it is a long way from where PANE_STYLECHANGED is actually cleared... I'm not sure what the best thing to do here is, there are a couple of options I can think of:

  • Add a PANE_THEMECHANGED flag and use it instead for the theme change- it can be set in the same places as PANE_STYLECHANGED and cleared once window_pane_send_theme_update is called. It could be checked in server_client_loop instead of in the redraw code so it happens regardless of the redraw flags.
  • Add a window_pane_style_changed function that sets the flag and calls window_pane_send_theme_update immediately - would this send the updates too often though?

@disrupted
Copy link

I am not familiar with C lang so please disregard this if it's something obvious.

When I compiled from this branch I had to update tmux.h

diff --git a/tmux.h b/tmux.h
index 3d1ee2dc..30001fbd 100644
--- a/tmux.h
+++ b/tmux.h
@@ -2944,6 +2944,7 @@ void	 input_reply_clipboard(struct bufferevent *, const char *, size_t,
 void	 input_set_buffer_size(size_t);
 int 	 input_get_bg_client(struct window_pane *);
 int 	 input_get_bg_control_client(struct window_pane *);
+int 	 window_get_bg_client(struct window_pane *);
 
 /* input-key.c */
 void	 input_key_build(void);
@@ -3260,7 +3261,10 @@ void		 window_set_fill_character(struct window *);
 void		 window_pane_default_cursor(struct window_pane *);
 int		 window_pane_mode(struct window_pane *);
 int		 window_pane_show_scrollbar(struct window_pane *, int);
+int		 window_pane_get_fg(struct window_pane *);
 int		 window_pane_get_bg(struct window_pane *);
+int		 window_pane_get_fg_control_client(struct window_pane *);
+int		 window_pane_get_bg_control_client(struct window_pane *);
 enum client_theme window_pane_get_theme(struct window_pane *);
 void		 window_pane_send_theme_update(struct window_pane *);

afterwards it compiled successfully. (macOS 15.3.1)

./autogen.sh
./configure --enable-utf8proc && make

@jonathanslenders
Copy link
Author

@disrupted : I pushed a commit that includes these missing headers. Looks like in my case, on Linux, these were only warnings. Can you try again?

@disrupted
Copy link

thanks! It does work now

@disrupted
Copy link
disrupted commented Feb 27, 2025

I've been using this branch for a while already together with Neovim nightly. What I noticed is that when I toggle the system appearance (light/dark) all nvim instances of the current tmux session toggle the background/colorscheme correctly. But when I switch to another tmux session, those nvim instances keep their previous appearance.

@jonathanslenders
Copy link
Author

@disrupted : Thanks for testing! Now, with the latest commit, all terminal apps should immediately receive a theme update when toggling sessions (if they are subscribed for theme updates). Can you try again?

@disrupted
Copy link

can confirm, it works great now! Thanks a lot for working on this