Help with status line styling

342 views
Skip to first unread message

Haodong Du

unread,
Feb 20, 2021, 1:42:38 PM2/20/21
to tmux-users
Hello tmux users,

I'm setting up my tmux status line. I want to achieve something like the figure below with powerline triangles. But there are gaps between two window tabs and also with the status left. I want to get rid of gaps completely. So I set all the divider to none. But I still need to set fg and bg properly. Namely, make the triangle bg match the bg of the next tab. In order to do that, I need to know whether the next tab is active or not and whether it's the last tab.
```
#{?window_end_flag,#[fg=colour239#,bg=colour237],#{?#{==:#(tmux lsw -f '#{?window_active,1,}' -F '#I'),#{e|+|:#I,1}},#[fg=colour239#,bg=colour214],#[fg=colour239#,bg=colour239]}}"
```
This is what I came up with. I want to compare the index of active window and this window index plus 1. But this does not seem to work. It always uses the color setting for the false condition.

687474703a2f2f692e696d6775722e636f6d2f694f6a637a2e706e67.png
Full config for status line if you want to give it a try:
```
set-window-option -g window-status-current-format "\
#{?window_start_flag,#[fg=colour195#,bg=colour214],#[fg=colour214#,bg=colour214]}\
#[fg=colour239, bg=colour214] #I* \
#[fg=colour239, bg=colour214, bold] #W \
#{?window_end_flag,#[fg=colour214#,bg=colour237],#[fg=colour214#,bg=colour239]}"

set-window-option -g window-status-format "\
#{?window_start_flag,#[fg=colour195#,bg=colour239],#[fg=colour239#,bg=colour239]}\
#[fg=colour223,bg=colour239] #I \
#[fg=colour223, bg=colour239] #W \
#{?window_end_flag,#[fg=colour239#,bg=colour237],#{?#{==:#(tmux lsw -f '#{?window_active,1,}' -F '#I'),#{e|+|:#I,1}},#[fg=colour239#,bg=colour214],#[fg=colour239#,bg=colour239]}}"
```
Regards,
Haodong Du

Nicholas Marriott

unread,
Feb 20, 2021, 2:28:46 PM2/20/21
to Haodong Du, tmux-users
I can't try it til next week but if it was me I'd add an active-window-index format in format_defaults_session in format.c and use that instead of the #().

Then you could also debug the format using display -pv.


--
You received this message because you are subscribed to the Google Groups "tmux-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to tmux-users+...@googlegroups.com.
To view this discussion on the web, visit https://groups.google.com/d/msgid/tmux-users/3d8a56b9-f36b-4a24-bd52-29a5efdd166an%40googlegroups.com.

Haodong Du

unread,
Feb 25, 2021, 2:18:52 PM2/25/21
to Nicholas Marriott, tmux-...@googlegroups.com
Hi Nicholas,
Could you take a look at this issue? It would be nice to do it without digging into the code.

For the format.c, is this what I need? Sorry, I didn't really read the code. so could be wrong.
format_cb_window_active_idx(struct format_tree *ft)
{
if (ft->wl != NULL) {
return (xstrdup(ft->wl->session->curw->idx))
}
return (NULL);
}


Best regards,
Haodong Du

On Sat, Feb 20, 2021 at 3:26 PM, Nicholas Marriott <nicholas...@gmail.com> wrote:
#() will not work with display -p because it stops before the command finishes (it does not wait). In the status line it should work, I don't know why It doesn't. It would be easy to add an additional format variable though and it would be generally useful.


On Sat, 20 Feb 2021, 20:20 Haodong Du, <duhd...@gmail.com> wrote:
Thank you Nocholas!
I haven't digged into customizing tmux code myself, but would try later.
Regarding the #(). I find it's not executing, and found this post that might be related: https://stackoverflow.com/questions/30264679/tmux-titles-string-not-executing-shell-command I'm running HEAD-742e670 (built yesterday) on macos 11.2.1

```bash
$ tmux display -pv -F "#{==:#(tmux lsw -f '#{?window_active,1,}' -F '#I'),#I}"
# expanding format: #{==:#(tmux lsw -f '#{?window_active,1,}' -F '#I'),#I}
# found #{}: ==:#(tmux lsw -f '#{?window_active,1,}' -F '#I'),#I
# modifier 0 is ==
# expanding format: #(tmux lsw -f '#{?window_active,1,}' -F '#I')
# found #(): tmux lsw -f '#{?window_active,1,}' -F '#I'
# expanding format: tmux lsw -f '#{?window_active,1,}' -F '#I'
# found #{}: ?window_active,1,
# condition is: window_active
# condition 'window_active' found
# condition 'window_active' is true
# expanding format: 1
# result is: 1
# replaced '?window_active,1,' with '1'
# found #I: window_index
# format 'window_index' found: 4
# replaced 'window_index' with '4'
# result is: tmux lsw -f '1' -F '4'
# expanding format: <'tmux lsw -f '#{?window_active,1,}' -F '#I'' not ready>
# found #{}: ?window_active,1,
# condition is: window_active
# condition 'window_active' found
# condition 'window_active' is true
# expanding format: 1
# result is: 1
# replaced '?window_active,1,' with '1'
# found #I: window_index
# format 'window_index' found: 4
# replaced 'window_index' with '4'
# result is: <'tmux lsw -f '1' -F '4'' not ready>
# #() result: <'tmux lsw -f '1' -F '4'' not ready>
# result is: <'tmux lsw -f '1' -F '4'' not ready>
# expanding format: #I
# found #I: window_index
# format 'window_index' found: 4
# replaced 'window_index' with '4'
# result is: 4
# compare == left is: <'tmux lsw -f '1' -F '4'' not ready>
# compare == right is: 4
# replaced '==:#(tmux lsw -f '#{?window_active,1,}' -F '#I'),#I' with '0'
# result is: 0
```
within #(), I don't need replacing. So I tried escaping with #. This exited with error. Then I wrapped with echo ``. Looks better now. Still not working.

```bash
$ tmux display -pv -F "#{==:#(echo `tmux lsw -f '#{?window_active,1,}' -F '#I'`),2}"
# expanding format: #{==:#(echo 4),2}
# found #{}: ==:#(echo 4),2
# modifier 0 is ==
# expanding format: #(echo 4)
# found #(): echo 4
# expanding format: echo 4
# result is: echo 4
# expanding format: <'echo 4' not ready>
# result is: <'echo 4' not ready>
# #() result: <'echo 4' not ready>
# result is: <'echo 4' not ready>
# expanding format: 2
# result is: 2
# compare == left is: <'echo 4' not ready>
# compare == right is: 2
# replaced '==:#(echo 4),2' with '0'
# result is: 0
```

Best regards,
Haodong Du

Nicholas Marriott

unread,
Feb 25, 2021, 2:42:33 PM2/25/21
to Haodong Du, tmux-...@googlegroups.com
Sorry, I forgot - you can try this (attached) against master. Apply with
"patch <x.diff".

Then you can check if a window is after the active one with, for
example:

#{==:#{e/-:#{window_index},1},#{active_window_index}}

Or before it:

#{==:#{e/+:#{window_index},1},#{active_window_index}}

This will only work if you have renumber-windows turned on (so there are
no gaps in the indexes), but I assume you do or your original idea
wouldn't work either.

I'll take a look see if your #() way will work in a bit.
> '#I'),#{e|+|:#I,1}},#[fg=colour239#,bg=colour214],#[fg=colour239#,bg=colour239]}}i*DEG"
> ```
> This is what I came up with. I want to compare the index of active
> window and this window index plus 1. But this does not seem to
> work. It always uses the color setting for the false condition.
> 687474703a2f2f692e696d6775722e636f6d2f694f6a637a2e706e67.png
> Full config for status line if you want to give it a try:
> ```
> set-window-option -g window-status-current-format "\
> #{?window_start_flag,#[fg=colour195#,bg=colour214],#[fg=colour214#,bg=colour214]}i*DEG\
> #[fg=colour239, bg=colour214] #I* i*+-\
> #[fg=colour239, bg=colour214, bold] #W \
> #{?window_end_flag,#[fg=colour214#,bg=colour237],#[fg=colour214#,bg=colour239]}i*DEG"
> set-window-option -g window-status-format "\
> #{?window_start_flag,#[fg=colour195#,bg=colour239],#[fg=colour239#,bg=colour239]}i*DEG\
> #[fg=colour223,bg=colour239] #I i*+-\
> #[fg=colour223, bg=colour239] #W \
> #{?window_end_flag,#[fg=colour239#,bg=colour237],#{?#{==:#(tmux
> lsw -f '#{?window_active,1,}' -F
> '#I'),#{e|+|:#I,1}},#[fg=colour239#,bg=colour214],#[fg=colour239#,bg=colour239]}}i*DEG"
> ```
x.diff

Nicholas Marriott

unread,
Feb 25, 2021, 2:50:52 PM2/25/21
to Haodong Du, tmux-...@googlegroups.com
#{} inside #() inside #{} won't work because the parser does not know to
handle #() so the } for the #{} inside the #() terminates the first #{}.

If you do not use #{} inside your #() it does run, but then you can't
get format variable values for the right window.

I don't think there is a way to do this easily.
> Index: format.c
> ===================================================================
> RCS file: /cvs/src/usr.bin/tmux/format.c,v
> retrieving revision 1.277
> diff -u -p -r1.277 format.c
> --- format.c 24 Feb 2021 09:22:15 -0000 1.277
> +++ format.c 25 Feb 2021 19:40:53 -0000
> @@ -2099,6 +2099,28 @@ format_cb_version(__unused struct format
> return (xstrdup(getversion()));
> }
>
> +/* Callback for active_window_index. */
> +static void *
> +format_cb_active_window_index(struct format_tree *ft)
> +{
> + if (ft->s != NULL)
> + return (format_printf("%u", ft->s->curw->idx));
> + return (NULL);
> +}
> +
> +/* Callback for last_window_index. */
> +static void *
> +format_cb_last_window_index(struct format_tree *ft)
> +{
> + struct winlink *wl;
> +
> + if (ft->s != NULL) {
> + wl = RB_MAX(winlinks, &ft->s->windows);
> + return (format_printf("%u", wl->idx));
> + }
> + return (NULL);
> +}
> +
> /* Callback for window_active. */
> static void *
> format_cb_window_active(struct format_tree *ft)
> @@ -2496,6 +2518,9 @@ struct format_table_entry {
> * Only variables which are added by the caller go into the tree.
> */
> static const struct format_table_entry format_table[] = {
> + { "active_window_index", FORMAT_TABLE_STRING,
> + format_cb_active_window_index
> + },
> { "alternate_on", FORMAT_TABLE_STRING,
> format_cb_alternate_on
> },
> @@ -2630,6 +2655,9 @@ static const struct format_table_entry f
> },
> { "keypad_flag", FORMAT_TABLE_STRING,
> format_cb_keypad_flag
> + },
> + { "last_window_index", FORMAT_TABLE_STRING,
> + format_cb_last_window_index
> },
> { "mouse_all_flag", FORMAT_TABLE_STRING,
> format_cb_mouse_all_flag
> Index: tmux.1
> ===================================================================
> RCS file: /cvs/src/usr.bin/tmux/tmux.1,v
> retrieving revision 1.823
> diff -u -p -r1.823 tmux.1
> --- tmux.1 22 Feb 2021 08:18:13 -0000 1.823
> +++ tmux.1 25 Feb 2021 19:40:54 -0000
> @@ -4756,6 +4756,7 @@ will be replaced by
> The following variables are available, where appropriate:
> .Bl -column "XXXXXXXXXXXXXXXXXXX" "XXXXX"
> .It Sy "Variable name" Ta Sy "Alias" Ta Sy "Replaced with"
> +.It Li "active_window_index" Ta "" Ta "Index of active window in session"
> .It Li "alternate_on" Ta "" Ta "1 if pane is in alternate screen"
> .It Li "alternate_saved_x" Ta "" Ta "Saved cursor X in alternate screen"
> .It Li "alternate_saved_y" Ta "" Ta "Saved cursor Y in alternate screen"
> @@ -4763,7 +4764,6 @@ The following variables are available, w
> .It Li "buffer_name" Ta "" Ta "Name of buffer"
> .It Li "buffer_sample" Ta "" Ta "Sample of start of buffer"
> .It Li "buffer_size" Ta "" Ta "Size of the specified buffer in bytes"
> -.It Li "config_files" Ta "" Ta "List of configuration files loaded"
> .It Li "client_activity" Ta "" Ta "Time client last had activity"
> .It Li "client_cell_height" Ta "" Ta "Height of each client cell in pixels"
> .It Li "client_cell_width" Ta "" Ta "Width of each client cell in pixels"
> @@ -4790,6 +4790,7 @@ The following variables are available, w
> .It Li "command_list_alias" Ta "" Ta "Command alias if listing commands"
> .It Li "command_list_name" Ta "" Ta "Command name if listing commands"
> .It Li "command_list_usage" Ta "" Ta "Command usage if listing commands"
> +.It Li "config_files" Ta "" Ta "List of configuration files loaded"
> .It Li "copy_cursor_line" Ta "" Ta "Line the cursor is on in copy mode"
> .It Li "copy_cursor_word" Ta "" Ta "Word under cursor in copy mode"
> .It Li "copy_cursor_x" Ta "" Ta "Cursor X position in copy mode"
> @@ -4812,6 +4813,7 @@ The following variables are available, w
> .It Li "insert_flag" Ta "" Ta "Pane insert flag"
> .It Li "keypad_cursor_flag" Ta "" Ta "Pane keypad cursor flag"
> .It Li "keypad_flag" Ta "" Ta "Pane keypad flag"
> +.It Li "last_window_index" Ta "" Ta "Index of last window in session"
> .It Li "line" Ta "" Ta "Line number in the list"
> .It Li "mouse_all_flag" Ta "" Ta "Pane mouse all flag"
> .It Li "mouse_any_flag" Ta "" Ta "Pane mouse any flag"
> @@ -4867,8 +4869,8 @@ The following variables are available, w
> .It Li "scroll_position" Ta "" Ta "Scroll position in copy mode"
> .It Li "scroll_region_lower" Ta "" Ta "Bottom of scroll region in pane"
> .It Li "scroll_region_upper" Ta "" Ta "Top of scroll region in pane"
> -.It Li "search_present" Ta "" Ta "1 if search started in copy mode"
> .It Li "search_match" Ta "" Ta "Search match if any"
> +.It Li "search_present" Ta "" Ta "1 if search started in copy mode"
> .It Li "selection_active" Ta "" Ta "1 if selection started and changes with the cursor in copy mode"
> .It Li "selection_end_x" Ta "" Ta "X position of the end of the selection"
> .It Li "selection_end_y" Ta "" Ta "Y position of the end of the selection"

Haodong Du

unread,
Feb 25, 2021, 3:19:25 PM2/25/21
to Nicholas Marriott, tmux-...@googlegroups.com
Thank you! I confirm this patch works. Although unlikely, any chance you would merge this into tmux?

The #{} inside #() actually should be directly passed for execution without translating. Wrapping it in `` seems to do the trick.
``
tmux display -pv -F "#{==:#(echo `tmux lsw -f '#{?window_active,1,}' -F '#I'`),2}"
.........
# compare == left is: <'echo 4' not ready>
# compare == right is: 2
``
It does not work as expected. Something like this might work?

Best regards,
Haodong Du

Nicholas Marriott

unread,
Feb 25, 2021, 3:22:24 PM2/25/21
to Haodong Du, tmux-users
Yes I will apply it tomorrow.

Nicholas Marriott

unread,
Feb 25, 2021, 3:23:18 PM2/25/21
to Haodong Du, tmux-users
No the problem is the } inside the #().

Making it #} might work actually because the shell would ignore the #.

Haodong Du

unread,
Feb 25, 2021, 3:31:27 PM2/25/21
to Nicholas Marriott, tmux-users
Thank you! In case some others might be interested, this is my final setting for status bar.

``
# Set status bar
set -g status-bg colour237
set -g status-fg colour223
set -g window-status-separator ''

set-option -g status-left "\
#[fg=colour241, bg=colour195]#{?client_prefix,#[bg=colour167],} ❐ #{session_name} \
#[fg=colour241, bg=colour195]#{?window_zoomed_flag, 🔍,}"

set-option -g status-right "\
#[fg=colour214, bg=colour237]\
#[fg=colour233, bg=colour214] %b %d %H:%M "

set-window-option -g window-status-current-format "\
#{?window_start_flag,#{?client_prefix,#[fg=colour167#,bg=colour214],#[fg=colour195#,bg=colour214]},#[fg=colour214#,bg=colour214]}\
#[fg=colour239, bg=colour214] #I* \
#[fg=colour239, bg=colour214, bold] #W \
#{?window_end_flag,#[fg=colour214#,bg=colour237],#[fg=colour214#,bg=colour239]}"

set-window-option -g window-status-format "\
#{?window_start_flag,#{?client_prefix,#[fg=colour167#,bg=colour239],#[fg=colour195#,bg=colour239]},#[fg=colour239#,bg=colour239]}\
#[fg=colour223,bg=colour239] #I \
#[fg=colour223, bg=colour239] #W \
#{?window_end_flag,#[fg=colour239#,bg=colour237],#{?#{==:#{active_window_index},#{e|+|:#I,1}},#[fg=colour239#,bg=colour214],#[fg=colour245#,bg=colour239]}}"
``


Best regards,
Haodong Du
Reply all
Reply to author
Forward
0 new messages