diff --git a/cmd-refresh-client.c b/cmd-refresh-client.c index cb30749e..13fcbb1d 100644 --- a/cmd-refresh-client.c +++ b/cmd-refresh-client.c @@ -168,6 +168,7 @@ cmd_refresh_report(struct tty *tty, const char *value) { struct window_pane *wp; u_int pane; + int fg, bg; size_t size = 0; char *copy, *split; @@ -184,8 +185,14 @@ cmd_refresh_report(struct tty *tty, const char *value) if (wp == NULL) goto out; - tty_keys_colours(tty, split, strlen(split), &size, &wp->control_fg, - &wp->control_bg); + fg = wp->control_fg; + bg = wp->control_bg; + if (tty_keys_colours(tty, split, strlen(split), &size, &fg, &bg) == 0) { + if (bg != wp->control_bg) + wp->flags |= PANE_THEMECHANGED; + wp->control_fg = fg; + wp->control_bg = bg; + } out: free(copy); diff --git a/colour.c b/colour.c index 88198e96..1cad01f9 100644 --- a/colour.c +++ b/colour.c @@ -120,6 +120,28 @@ colour_force_rgb(int c) return (-1); } +/* Dim colour by a percentage. */ +int +colour_dim(int c, u_int dim) +{ + u_char r, g, b; + + if (dim == 0 || COLOUR_DEFAULT(c)) + return (c); + if (dim >= 100) + return (colour_join_rgb(0, 0, 0)); + + c = colour_force_rgb(c); + if (c == -1) + return (-1); + colour_split_rgb(c, &r, &g, &b); + + r = (r * (100 - dim)) / 100; + g = (g * (100 - dim)) / 100; + b = (b * (100 - dim)) / 100; + return (colour_join_rgb(r, g, b)); +} + /* Convert colour to a string. */ const char * colour_tostring(int c) diff --git a/control-notify.c b/control-notify.c index 151f959d..021f9884 100644 --- a/control-notify.c +++ b/control-notify.c @@ -224,6 +224,14 @@ control_notify_session_window_changed(struct session *s) { struct client *c; + /* + * A deferred session-window-changed notification can fire after the + * session has been destroyed (which sets curw to NULL) but is kept + * alive by the notification's reference. Skip the notification. + */ + if (s->curw == NULL) + return; + TAILQ_FOREACH(c, &clients, entry) { if (!CONTROL_SHOULD_NOTIFY_CLIENT(c)) continue; diff --git a/format.c b/format.c index d977f154..fd5aebcc 100644 --- a/format.c +++ b/format.c @@ -128,6 +128,9 @@ format_job_cmp(struct format_job *fj1, struct format_job *fj2) /* Limit on time taken (milliseconds). */ #define FORMAT_TIME_LIMIT 100 +/* How often to check the time in long loops. */ +#define FORMAT_TIME_LOOP_CHECK 10000 + /* Format expand flags. */ #define FORMAT_EXPAND_TIME 0x1 #define FORMAT_EXPAND_NOJOBS 0x2 @@ -573,7 +576,7 @@ format_cb_session_attached_list(struct format_tree *ft) } if ((size = EVBUFFER_LENGTH(buffer)) != 0) - xasprintf(&value, "%.*s", size, EVBUFFER_DATA(buffer)); + value = xmemdup(EVBUFFER_DATA(buffer), size); evbuffer_free(buffer); return (value); } @@ -712,7 +715,7 @@ format_cb_window_linked_sessions_list(struct format_tree *ft) } if ((size = EVBUFFER_LENGTH(buffer)) != 0) - xasprintf(&value, "%.*s", size, EVBUFFER_DATA(buffer)); + value = xmemdup(EVBUFFER_DATA(buffer), size); evbuffer_free(buffer); return (value); } @@ -766,7 +769,7 @@ format_cb_window_active_sessions_list(struct format_tree *ft) } if ((size = EVBUFFER_LENGTH(buffer)) != 0) - xasprintf(&value, "%.*s", size, EVBUFFER_DATA(buffer)); + value = xmemdup(EVBUFFER_DATA(buffer), size); evbuffer_free(buffer); return (value); } @@ -830,7 +833,7 @@ format_cb_window_active_clients_list(struct format_tree *ft) } if ((size = EVBUFFER_LENGTH(buffer)) != 0) - xasprintf(&value, "%.*s", size, EVBUFFER_DATA(buffer)); + value = xmemdup(EVBUFFER_DATA(buffer), size); evbuffer_free(buffer); return (value); } @@ -1005,7 +1008,7 @@ format_cb_pane_tabs(struct format_tree *ft) evbuffer_add_printf(buffer, "%u", i); } if ((size = EVBUFFER_LENGTH(buffer)) != 0) - xasprintf(&value, "%.*s", size, EVBUFFER_DATA(buffer)); + value = xmemdup(EVBUFFER_DATA(buffer), size); evbuffer_free(buffer); return (value); } @@ -1020,7 +1023,7 @@ format_cb_pane_fg(struct format_tree *ft) if (wp == NULL) return (NULL); - tty_default_colours(&gc, wp); + tty_default_colours(&gc, wp, NULL); return (xstrdup(colour_tostring(gc.fg))); } @@ -1057,7 +1060,7 @@ format_cb_pane_bg(struct format_tree *ft) if (wp == NULL) return (NULL); - tty_default_colours(&gc, wp); + tty_default_colours(&gc, wp, NULL); return (xstrdup(colour_tostring(gc.bg))); } @@ -1089,7 +1092,7 @@ format_cb_session_group_list(struct format_tree *ft) } if ((size = EVBUFFER_LENGTH(buffer)) != 0) - xasprintf(&value, "%.*s", size, EVBUFFER_DATA(buffer)); + value = xmemdup(EVBUFFER_DATA(buffer), size); evbuffer_free(buffer); return (value); } @@ -1129,7 +1132,7 @@ format_cb_session_group_attached_list(struct format_tree *ft) } if ((size = EVBUFFER_LENGTH(buffer)) != 0) - xasprintf(&value, "%.*s", size, EVBUFFER_DATA(buffer)); + value = xmemdup(EVBUFFER_DATA(buffer), size); evbuffer_free(buffer); return (value); } @@ -1853,15 +1856,6 @@ format_cb_keypad_flag(struct format_tree *ft) return (NULL); } -/* Callback for loop_last_flag. */ -static void * -format_cb_loop_last_flag(struct format_tree *ft) -{ - if (ft->flags & FORMAT_LAST) - return (xstrdup("1")); - return (xstrdup("0")); -} - /* Callback for mouse_all_flag. */ static void * format_cb_mouse_all_flag(struct format_tree *ft) @@ -3346,9 +3340,6 @@ static const struct format_table_entry format_table[] = { { "last_window_index", FORMAT_TABLE_STRING, format_cb_last_window_index }, - { "loop_last_flag", FORMAT_TABLE_STRING, - format_cb_loop_last_flag - }, { "mouse_all_flag", FORMAT_TABLE_STRING, format_cb_mouse_all_flag }, @@ -4237,10 +4228,14 @@ found: /* Check if format has not taken too long. */ static int -format_check_time(struct format_expand_state *es) +format_check_time(struct format_expand_state *es, u_int *check) { - uint64_t t = get_timer(); + uint64_t t; + if (check != NULL && ++*check % FORMAT_TIME_LOOP_CHECK != 0) + return (1); + + t = get_timer(); if (t - es->start_time < FORMAT_TIME_LIMIT) return (1); t -= es->start_time; @@ -4251,21 +4246,24 @@ format_check_time(struct format_expand_state *es) /* Unescape escaped characters. */ static char * -format_unescape(struct format_expand_state *es, const char *s) +format_unescape(struct format_expand_state *es, const char *s, size_t n) { - char *out, *cp; - int brackets = 0; + const char *end = s + n; + char *out, *cp; + int brackets = 0; + u_int check = 0; - cp = out = xmalloc(strlen(s) + 1); - for (; *s != '\0'; s++) { - if (!format_check_time(es)){ + cp = out = xmalloc(n + 1); + for (; s != end; s++) { + if (!format_check_time(es, &check)) { free(out); return (xstrdup("")); } - if (*s == '#' && s[1] == '{') + if (*s == '#' && s + 1 != end && s[1] == '{') brackets++; if (brackets == 0 && *s == '#' && + s + 1 != end && strchr(",#{}:", s[1]) != NULL) { *cp++ = *++s; continue; @@ -4284,10 +4282,11 @@ format_strip(struct format_expand_state *es, const char *s) { char *out, *cp; int brackets = 0; + u_int check = 0; cp = out = xmalloc(strlen(s) + 1); for (; *s != '\0'; s++) { - if (!format_check_time(es)){ + if (!format_check_time(es, &check)) { free(out); return (xstrdup("")); } @@ -4311,9 +4310,10 @@ static const char * format_skip1(struct format_expand_state *es, const char *s, const char *end) { int brackets = 0; + u_int check = 0; for (; *s != '\0'; s++) { - if (es != NULL && !format_check_time(es)) + if (es != NULL && !format_check_time(es, &check)) return (NULL); if (*s == '#' && s[1] == '{') brackets++; @@ -4484,7 +4484,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s, break; argv = xcalloc(1, sizeof *argv); - value = xstrndup(cp + 1, end - (cp + 1)); + value = format_unescape(es, cp + 1, end - (cp + 1)); argv[0] = format_expand1(es, value); free(value); argc = 1; @@ -4508,7 +4508,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s, cp++; argv = xreallocarray(argv, argc + 1, sizeof *argv); - value = xstrndup(cp, end - cp); + value = format_unescape(es, cp, end - cp); argv[argc++] = format_expand1(es, value); free(value); @@ -4671,17 +4671,19 @@ format_loop_sessions(struct format_expand_state *es, const char *fmt) struct format_tree *nft; struct format_expand_state next; char *all, *active, *use, *expanded, *value; - size_t valuelen; + struct evbuffer *buffer; + size_t size; struct session *s, **l; - int i, n, last = 0; + int i, n; if (format_choose(es, fmt, &all, &active, 0) != 0) { all = xstrdup(fmt); active = NULL; } - value = xcalloc(1, 1); - valuelen = 1; + buffer = evbuffer_new(); + if (buffer == NULL) + fatalx("out of memory"); l = sort_get_sessions(&n, sc); for (i = 0; i < n; i++) { @@ -4693,25 +4695,27 @@ format_loop_sessions(struct format_expand_state *es, const char *fmt) use = active; else use = all; - if (i == n - 1) - last = FORMAT_LAST; - nft = format_create(c, item, FORMAT_NONE, ft->flags|last); + nft = format_create(c, item, FORMAT_NONE, ft->flags); + format_add(nft, "loop_index", "%d", i); + format_add(nft, "loop_last_flag", "%d", i == n - 1); format_defaults(nft, ft->c, s, NULL, NULL); format_copy_state(&next, es, 0); next.ft = nft; expanded = format_expand1(&next, use); format_free(next.ft); - valuelen += strlen(expanded); - value = xrealloc(value, valuelen); - - strlcat(value, expanded, valuelen); + evbuffer_add(buffer, expanded, strlen(expanded)); free(expanded); } free(active); free(all); + if ((size = EVBUFFER_LENGTH(buffer)) != 0) + value = xmemdup(EVBUFFER_DATA(buffer), size); + else + value = xstrdup(""); + evbuffer_free(buffer); return (value); } @@ -4781,10 +4785,11 @@ format_loop_windows(struct format_expand_state *es, const char *fmt) struct format_tree *nft; struct format_expand_state next; char *all, *active, *use, *expanded, *value; - size_t valuelen; + struct evbuffer *buffer; + size_t size; struct winlink *wl, **l; struct window *w; - int i, n, last = 0; + int i, n; if (ft->s == NULL) { format_log(es, "window loop but no session"); @@ -4796,8 +4801,9 @@ format_loop_windows(struct format_expand_state *es, const char *fmt) active = NULL; } - value = xcalloc(1, 1); - valuelen = 1; + buffer = evbuffer_new(); + if (buffer == NULL) + fatalx("out of memory"); l = sort_get_winlinks_session(ft->s, &n, sc); for (i = 0; i < n; i++) { @@ -4808,10 +4814,10 @@ format_loop_windows(struct format_expand_state *es, const char *fmt) use = active; else use = all; - if (i == n - 1) - last = FORMAT_LAST; nft = format_create(c, item, FORMAT_WINDOW|w->id, - ft->flags|last); + ft->flags); + format_add(nft, "loop_index", "%d", i); + format_add(nft, "loop_last_flag", "%d", i == n - 1); format_defaults(nft, ft->c, ft->s, wl, NULL); /* Add neighbor window data to the format tree. */ @@ -4829,16 +4835,18 @@ format_loop_windows(struct format_expand_state *es, const char *fmt) expanded = format_expand1(&next, use); format_free(nft); - valuelen += strlen(expanded); - value = xrealloc(value, valuelen); - - strlcat(value, expanded, valuelen); + evbuffer_add(buffer, expanded, strlen(expanded)); free(expanded); } free(active); free(all); + if ((size = EVBUFFER_LENGTH(buffer)) != 0) + value = xmemdup(EVBUFFER_DATA(buffer), size); + else + value = xstrdup(""); + evbuffer_free(buffer); return (value); } @@ -4853,9 +4861,10 @@ format_loop_panes(struct format_expand_state *es, const char *fmt) struct format_tree *nft; struct format_expand_state next; char *all, *active, *use, *expanded, *value; - size_t valuelen; + struct evbuffer *buffer; + size_t size; struct window_pane *wp, **l; - int i, n, last = 0; + int i, n; if (ft->w == NULL) { format_log(es, "pane loop but no window"); @@ -4867,8 +4876,9 @@ format_loop_panes(struct format_expand_state *es, const char *fmt) active = NULL; } - value = xcalloc(1, 1); - valuelen = 1; + buffer = evbuffer_new(); + if (buffer == NULL) + fatalx("out of memory"); l = sort_get_panes_window(ft->w, &n, sc); for (i = 0; i < n; i++) { @@ -4878,26 +4888,28 @@ format_loop_panes(struct format_expand_state *es, const char *fmt) use = active; else use = all; - if (i == n - 1) - last = FORMAT_LAST; nft = format_create(c, item, FORMAT_PANE|wp->id, - ft->flags|last); + ft->flags); + format_add(nft, "loop_index", "%d", i); + format_add(nft, "loop_last_flag", "%d", i == n - 1); format_defaults(nft, ft->c, ft->s, ft->wl, wp); format_copy_state(&next, es, 0); next.ft = nft; expanded = format_expand1(&next, use); format_free(nft); - valuelen += strlen(expanded); - value = xrealloc(value, valuelen); - - strlcat(value, expanded, valuelen); + evbuffer_add(buffer, expanded, strlen(expanded)); free(expanded); } free(active); free(all); + if ((size = EVBUFFER_LENGTH(buffer)) != 0) + value = xmemdup(EVBUFFER_DATA(buffer), size); + else + value = xstrdup(""); + evbuffer_free(buffer); return (value); } @@ -4912,32 +4924,36 @@ format_loop_clients(struct format_expand_state *es, const char *fmt) struct format_tree *nft; struct format_expand_state next; char *expanded, *value; - size_t valuelen; - int i, n, last = 0; + struct evbuffer *buffer; + size_t size; + int i, n; - value = xcalloc(1, 1); - valuelen = 1; + buffer = evbuffer_new(); + if (buffer == NULL) + fatalx("out of memory"); l = sort_get_clients(&n, sc); for (i = 0; i < n; i++) { c = l[i]; format_log(es, "client loop: %s", c->name); - if (i == n - 1) - last = FORMAT_LAST; - nft = format_create(c, item, 0, ft->flags|last); + nft = format_create(c, item, 0, ft->flags); + format_add(nft, "loop_index", "%d", i); + format_add(nft, "loop_last_flag", "%d", i == n - 1); format_defaults(nft, c, ft->s, ft->wl, ft->wp); format_copy_state(&next, es, 0); next.ft = nft; expanded = format_expand1(&next, fmt); format_free(nft); - valuelen += strlen(expanded); - value = xrealloc(value, valuelen); - - strlcat(value, expanded, valuelen); + evbuffer_add(buffer, expanded, strlen(expanded)); free(expanded); } + if ((size = EVBUFFER_LENGTH(buffer)) != 0) + value = xmemdup(EVBUFFER_DATA(buffer), size); + else + value = xstrdup(""); + evbuffer_free(buffer); return (value); } @@ -5103,7 +5119,7 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen, struct format_modifier *list, *cmp = NULL, *search = NULL; struct format_modifier **sub = NULL, *mexp = NULL, *fm; struct format_modifier *bool_op_n = NULL; - u_int i, count, nsub = 0, nrep; + u_int i, count, nsub = 0, nrep, check = 0; struct format_expand_state next; struct environ_entry *envent; @@ -5360,7 +5376,7 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen, /* Is this a literal string? */ if (modifiers & FORMAT_LITERAL) { format_log(es, "literal string is '%s'", copy); - value = format_unescape(es, copy); + value = format_unescape(es, copy, strlen(copy)); goto done; } @@ -5436,7 +5452,7 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen, else { value = xstrdup(""); for (i = 0; i < nrep; i++) { - if (!format_check_time(es)) { + if (!format_check_time(es, &check)) { free(right); free(left); free(value); @@ -5716,7 +5732,7 @@ format_expand1(struct format_expand_state *es, const char *fmt) int ch, brackets; char expanded[8192]; - if (fmt == NULL || *fmt == '\0' || !format_check_time(es)) + if (fmt == NULL || *fmt == '\0' || !format_check_time(es, NULL)) return (xstrdup("")); if (es->loop == FORMAT_LOOP_LIMIT) { diff --git a/image-sixel.c b/image-sixel.c index cc946cfe..2e6f247d 100644 --- a/image-sixel.c +++ b/image-sixel.c @@ -450,11 +450,11 @@ sixel_scale(struct sixel_image *si, u_int xpixel, u_int ypixel, u_int ox, new->set_ra = si->set_ra; /* subtract offset */ - new->ra_x = new->ra_x > pox ? new->ra_x - pox : 0; - new->ra_y = new->ra_y > poy ? new->ra_y - poy : 0; + new->ra_x = si->ra_x > pox ? si->ra_x - pox : 0; + new->ra_y = si->ra_y > poy ? si->ra_y - poy : 0; /* clamp to size */ - new->ra_x = si->ra_x < psx ? si->ra_x : psx; - new->ra_y = si->ra_y < psy ? si->ra_y : psy; + new->ra_x = new->ra_x < psx ? new->ra_x : psx; + new->ra_y = new->ra_y < psy ? new->ra_y : psy; /* resize */ new->ra_x = new->ra_x * xpixel / si->xpixel; new->ra_y = new->ra_y * ypixel / si->ypixel; diff --git a/input.c b/input.c index aa7b0c0c..cd664360 100644 --- a/input.c +++ b/input.c @@ -3055,7 +3055,7 @@ input_osc_10(struct input_ctx *ictx, const char *p) return; c = window_pane_get_fg_control_client(wp); if (c == -1) { - tty_default_colours(&defaults, wp); + tty_default_colours(&defaults, wp, NULL); if (COLOUR_DEFAULT(defaults.fg)) c = window_pane_get_fg(wp); else diff --git a/key-bindings.c b/key-bindings.c index 2e5cc193..5a2c3d96 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -25,11 +25,10 @@ #include "tmux.h" #define DEFAULT_SESSION_MENU \ - " 'Next' 'n' {switch-client -n}" \ - " 'Previous' 'p' {switch-client -p}" \ + " #{S/t:#{?#{&&:#{<:#{loop_index},6},#{!:#{session_active}}},'Switch To #[underscore]#{session_name}' '' {switch-client -t=#{session_id}#} ,}}" \ " ''" \ " 'Renumber' 'N' {move-window -r}" \ - " 'Rename' 'r' {command-prompt -I \"#S\" {rename-session -- '%%'}}" \ + " 'Rename' 'r' {command-prompt -I '#S' {rename-session -- '%%'}}" \ " 'Detach' 'd' {detach-client}" \ " ''" \ " 'New Session' 's' {new-session}" \ @@ -486,8 +485,8 @@ key_bindings_init(void) "bind -n WheelUpStatus { previous-window }", /* Mouse button 3 down on status left. */ - "bind -n MouseDown3StatusLeft { display-menu -t= -xM -yW -T '#[align=centre]#{session_name}' " DEFAULT_SESSION_MENU " }", - "bind -n M-MouseDown3StatusLeft { display-menu -t= -xM -yW -T '#[align=centre]#{session_name}' " DEFAULT_SESSION_MENU " }", + "bind -n MouseDown3StatusLeft { run -C \"display-menu -t= -xM -yW -T '#[align=centre]#{session_name}' " DEFAULT_SESSION_MENU "\" }", + "bind -n M-MouseDown3StatusLeft { run -C \"display-menu -t= -xM -yW -T '#[align=centre]#{session_name}' " DEFAULT_SESSION_MENU "\" }", /* Mouse button 3 down on status line. */ "bind -n MouseDown3Status { display-menu -t= -xW -yW -T '#[align=centre]#{window_index}:#{window_name}' " DEFAULT_WINDOW_MENU "}", @@ -578,6 +577,8 @@ key_bindings_init(void) "bind -Tcopy-mode M-Down { send -X halfpage-down }", "bind -Tcopy-mode C-Up { send -X scroll-up }", "bind -Tcopy-mode C-Down { send -X scroll-down }", + "bind -Tcopy-mode M-C-Up { send -X previous-prompt }", + "bind -Tcopy-mode M-C-Down { send -X next-prompt }", /* Copy mode (vi) keys. */ "bind -Tcopy-mode-vi '#' { send -FX search-backward -- '#{copy_cursor_word}' }", diff --git a/mode-tree.c b/mode-tree.c index cecf7df8..ff31edb4 100644 --- a/mode-tree.c +++ b/mode-tree.c @@ -84,6 +84,7 @@ struct mode_tree_data { int no_matches; enum mode_tree_search_dir search_dir; int search_icase; + int help; }; struct mode_tree_item { @@ -124,6 +125,8 @@ struct mode_tree_menu { }; static void mode_tree_free_items(struct mode_tree_list *); +static void mode_tree_draw_help(struct mode_tree_data *, + struct screen_write_ctx *); static const struct menu_item mode_tree_menu_items[] = { { "Scroll Left", '<', NULL }, @@ -135,31 +138,31 @@ static const struct menu_item mode_tree_menu_items[] = { }; static const char* mode_tree_help_start[] = { - "\r\033[1m Up, k \033[0m\016x\017 \033[0mMove cursor up\n", - "\r\033[1m Down, j \033[0m\016x\017 \033[0mMove cursor down\n", - "\r\033[1m g \033[0m\016x\017 \033[0mGo to top\n", - "\r\033[1m G \033[0m\016x\017 \033[0mGo to bottom\n", - "\r\033[1m PPage, C-b \033[0m\016x\017 \033[0mPage up\n", - "\r\033[1m NPage, C-f \033[0m\016x\017 \033[0mPage down\n", - "\r\033[1m Left, h \033[0m\016x\017 \033[0mCollapse %1\n", - "\r\033[1m Right, l \033[0m\016x\017 \033[0mExpand %1\n", - "\r\033[1m M-- \033[0m\016x\017 \033[0mCollapse all %1s\n", - "\r\033[1m M-+ \033[0m\016x\017 \033[0mExpand all %1s\n", - "\r\033[1m t \033[0m\016x\017 \033[0mToggle %1 tag\n", - "\r\033[1m T \033[0m\016x\017 \033[0mUntag all %1s\n", - "\r\033[1m C-t \033[0m\016x\017 \033[0mTag all %1s\n", - "\r\033[1m C-s \033[0m\016x\017 \033[0mSearch forward\n", - "\r\033[1m C-r \033[0m\016x\017 \033[0mSearch backward\n", - "\r\033[1m n \033[0m\016x\017 \033[0mRepeat search forward\n", - "\r\033[1m N \033[0m\016x\017 \033[0mRepeat search backward\n", - "\r\033[1m f \033[0m\016x\017 \033[0mFilter %1s\n", - "\r\033[1m O \033[0m\016x\017 \033[0mChange sort order\n", - "\r\033[1m r \033[0m\016x\017 \033[0mReverse sort order\n", - "\r\033[1m v \033[0m\016x\017 \033[0mToggle preview\n", + "#[bold] Up, k #[default]#[acs]x#[default] Move cursor up", + "#[bold] Down, j #[default]#[acs]x#[default] Move cursor down", + "#[bold] g #[default]#[acs]x#[default] Go to top", + "#[bold] G #[default]#[acs]x#[default] Go to bottom", + "#[bold] PPage, C-b #[default]#[acs]x#[default] Page up", + "#[bold] NPage, C-f #[default]#[acs]x#[default] Page down", + "#[bold] Left, h #[default]#[acs]x#[default] Collapse %1", + "#[bold] Right, l #[default]#[acs]x#[default] Expand %1", + "#[bold] M-- #[default]#[acs]x#[default] Collapse all %1s", + "#[bold] M-+ #[default]#[acs]x#[default] Expand all %1s", + "#[bold] t #[default]#[acs]x#[default] Toggle %1 tag", + "#[bold] T #[default]#[acs]x#[default] Untag all %1s", + "#[bold] C-t #[default]#[acs]x#[default] Tag all %1s", + "#[bold] C-s #[default]#[acs]x#[default] Search forward", + "#[bold] C-r #[default]#[acs]x#[default] Search backward", + "#[bold] n #[default]#[acs]x#[default] Repeat search forward", + "#[bold] N #[default]#[acs]x#[default] Repeat search backward", + "#[bold] f #[default]#[acs]x#[default] Filter %1s", + "#[bold] O #[default]#[acs]x#[default] Change sort order", + "#[bold] r #[default]#[acs]x#[default] Reverse sort order", + "#[bold] v #[default]#[acs]x#[default] Toggle preview", NULL }; static const char* mode_tree_help_end[] = { - "\r\033[1m q, Escape \033[0m\016x\017 \033[0mExit mode\033[H", + "#[bold] q, Escape #[default]#[acs]x#[default] Exit mode", NULL }; #define MODE_TREE_HELP_DEFAULT_WIDTH 39 @@ -928,6 +931,8 @@ mode_tree_draw(struct mode_tree_data *mtd) } done: + if (mtd->help) + mode_tree_draw_help(mtd, &ctx); screen_write_cursormove(&ctx, 0, mtd->current - mtd->offset, 0); screen_write_stop(&ctx); } @@ -1175,12 +1180,28 @@ mode_tree_display_menu(struct mode_tree_data *mtd, struct client *c, u_int x, } static void -mode_tree_display_help(__unused struct mode_tree_data *mtd, struct client *c) +mode_tree_draw_help_line(struct screen_write_ctx *ctx, + const struct grid_cell *gc, const char *line, const char *item, u_int x, + u_int y, u_int w) { - struct session *s = c->session; - u_int px, py, w, h = 0; - const char **line, **lines = NULL, *item = "item"; - char *new_line; + char *expanded; + + expanded = cmd_template_replace(line, item, 1); + screen_write_cursormove(ctx, x, y, 0); + screen_write_clearcharacter(ctx, w, gc->bg); + screen_write_cursormove(ctx, x, y, 0); + format_draw(ctx, gc, w, expanded, NULL, 0); + free(expanded); +} + +static void +mode_tree_draw_help(struct mode_tree_data *mtd, struct screen_write_ctx *ctx) +{ + struct screen *s = &mtd->screen; + struct grid_cell gc; + const char **line, **lines = NULL, *item = "item"; + u_int sx = screen_size_x(s), sy = screen_size_y(s); + u_int x, y, w, h = 0, box_w, box_h; if (mtd->helpcb == NULL) w = MODE_TREE_HELP_DEFAULT_WIDTH; @@ -1196,33 +1217,32 @@ mode_tree_display_help(__unused struct mode_tree_data *mtd, struct client *c) for (line = mode_tree_help_end; *line != NULL; line++) h++; - if (c->tty.sx < w || c->tty.sy < h) + box_w = w + 2; + box_h = h + 2; + if (sx < box_w || sy < box_h) return; - px = (c->tty.sx - w) / 2; - py = (c->tty.sy - h) / 2; + x = (sx - box_w) / 2; + y = (sy - box_h) / 2; - if (popup_display(POPUP_CLOSEANYKEY|POPUP_NOJOB, BOX_LINES_DEFAULT, - NULL, px, py, w, h, NULL, NULL, 0, NULL, NULL, NULL, c, s, NULL, - NULL, NULL, NULL) != 0) - return; + memcpy(&gc, &grid_default_cell, sizeof gc); + screen_write_cursormove(ctx, x, y, 0); + screen_write_box(ctx, box_w, box_h, BOX_LINES_DEFAULT, &gc, NULL); - popup_write(c, "\033[H\033[?25l\033[?7l\033)0", 17); - for (line = mode_tree_help_start; *line != NULL; line++) { - new_line = cmd_template_replace(*line, item, 1); - popup_write(c, new_line, strlen(new_line)); - free(new_line); - } - for (line = lines; line != NULL && *line != NULL; line++) { - new_line = cmd_template_replace(*line, item, 1); - popup_write(c, new_line, strlen(new_line)); - free(new_line); - } - for (line = mode_tree_help_end; *line != NULL; line++) { - new_line = cmd_template_replace(*line, item, 1); - popup_write(c, new_line, strlen(new_line)); - free(new_line); - } - popup_write(c, "\033[H", 3); + y++; + x++; + for (line = mode_tree_help_start; *line != NULL; line++, y++) + mode_tree_draw_help_line(ctx, &gc, *line, item, x, y, w); + for (line = lines; line != NULL && *line != NULL; line++, y++) + mode_tree_draw_help_line(ctx, &gc, *line, item, x, y, w); + for (line = mode_tree_help_end; *line != NULL; line++, y++) + mode_tree_draw_help_line(ctx, &gc, *line, item, x, y, w); +} + +static void +mode_tree_display_help(struct mode_tree_data *mtd) +{ + mtd->help = 1; + mode_tree_draw(mtd); } int @@ -1239,6 +1259,13 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key, return (1); } + if (mtd->help) { + mtd->help = 0; + mode_tree_draw(mtd); + *key = KEYC_NONE; + return (0); + } + if (KEYC_IS_MOUSE(*key) && m != NULL) { if (cmd_mouse_at(mtd->wp, m, &x, &y, 0) != 0) { *key = KEYC_NONE; @@ -1304,7 +1331,7 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key, return (1); case KEYC_F1: case 'h'|KEYC_CTRL: - mode_tree_display_help(mtd, c); + mode_tree_display_help(mtd); break; case KEYC_UP: case 'k': diff --git a/popup.c b/popup.c index dc7f2fce..74dc2b3a 100644 --- a/popup.c +++ b/popup.c @@ -327,6 +327,7 @@ popup_draw_cb(struct client *c, void *data) defaults.bg = pd->palette.bg; style_ctx.defaults = &defaults; style_ctx.palette = &pd->palette; + style_ctx.dim = 0; style_ctx.hyperlinks = s.hyperlinks; if (pd->md != NULL) { diff --git a/regress/command-alias.sh b/regress/command-alias.sh new file mode 100644 index 00000000..632e959a --- /dev/null +++ b/regress/command-alias.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +# command-alias expansion + +PATH=/bin:/usr/bin +TERM=screen + +[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux) +TMUX="$TEST_TMUX -Ltest -f/dev/null" +$TMUX kill-server 2>/dev/null + +$TMUX new-session -d -sfoo || exit 1 +$TMUX split-window -d -tfoo:0.0 || exit 1 +$TMUX set -s command-alias[100] zoom='resize-pane -Z' || exit 1 +$TMUX zoom -tfoo:0.0 || exit 1 +[ "$($TMUX display-message -p -tfoo:0.0 '#{window_zoomed_flag}')" = 1 ] || exit 1 + +$TMUX kill-server 2>/dev/null + +exit 0 diff --git a/regress/format-strings.sh b/regress/format-strings.sh index 8d192ed2..bae66ab0 100644 --- a/regress/format-strings.sh +++ b/regress/format-strings.sh @@ -67,6 +67,7 @@ $TMUX set @true 1 || exit 1 $TMUX set @false 0 || exit 1 $TMUX set @warm Summer || exit 1 $TMUX set @cold Winter || exit 1 +$TMUX set @v 'foo:bar' || exit 1 # Plain string without substitutions et al test_format "abc xyz" "abc xyz" @@ -74,6 +75,8 @@ test_format "abc xyz" "abc xyz" # Test basic escapes for "#", "{", "#{" "}", "#}", "," test_format "##" "#" test_format "#," "," +test_format "#{s/#:/_/:@v}" "foo_bar" +test_format "#{s/o/#:/:@v}" "f:::bar" test_format "{" "{" test_format "##{" "#{" test_format "#}" "}" diff --git a/screen-write.c b/screen-write.c index 0bacdd0a..4d8d5ac8 100644 --- a/screen-write.c +++ b/screen-write.c @@ -252,7 +252,8 @@ screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx, } else { ttyctx->redraw_cb = screen_write_redraw_cb; if (ctx->wp != NULL) { - tty_default_colours(&ttyctx->defaults, ctx->wp); + tty_default_colours(&ttyctx->defaults, ctx->wp, + &ttyctx->style_ctx.dim); ttyctx->style_ctx.palette = &ctx->wp->palette; ttyctx->set_client_cb = screen_write_set_client_cb; ttyctx->arg = ctx->wp; diff --git a/style.c b/style.c index 586e9f93..b79d3291 100644 --- a/style.c +++ b/style.c @@ -32,6 +32,7 @@ static struct style style_default = { { { { ' ' }, 0, 1, 1 }, 0, 0, 8, 8, 0, 0 }, 0, + 0, 8, STYLE_ALIGN_DEFAULT, @@ -201,6 +202,13 @@ style_parse(struct style *sy, const struct grid_cell *base, const char *in) if ((value = colour_fromstring(tmp + 5)) == -1) goto error; sy->fill = value; + } else if (end > 4 && strncasecmp(tmp, "dim=", 4) == 0) { + if (tmp[end - 1] == '%') + tmp[end - 1] = '\0'; + n = strtonum(tmp + 4, 0, 100, &errstr); + if (errstr != NULL) + goto error; + sy->dim = n; } else if (end > 3 && strncasecmp(tmp + 1, "g=", 2) == 0) { if ((value = colour_fromstring(tmp + 3)) == -1) goto error; @@ -346,6 +354,11 @@ style_tostring(struct style *sy) colour_tostring(sy->fill)); comma = ","; } + if (sy->dim != 0) { + off += xsnprintf(s + off, sizeof s - off, "%sdim=%d%%", comma, + sy->dim); + comma = ","; + } if (gc->fg != 8) { off += xsnprintf(s + off, sizeof s - off, "%sfg=%s", comma, colour_tostring(gc->fg)); @@ -386,7 +399,7 @@ style_tostring(struct style *sy) } /* Apply a style on top of the given style. */ -void +struct style * style_add(struct grid_cell *gc, struct options *oo, const char *name, struct format_tree *ft) { @@ -409,6 +422,7 @@ style_add(struct grid_cell *gc, struct options *oo, const char *name, if (ft0 != NULL) format_free(ft0); + return (sy); } /* Apply a style on top of the default style. */ diff --git a/tmux.1 b/tmux.1 index e7bf3713..84ac0dbe 100644 --- a/tmux.1 +++ b/tmux.1 @@ -6776,6 +6776,7 @@ The following variables are available, where appropriate: .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 "loop_index" Ta "" Ta "Index of item in the W:, P:, S:, or L: loop" .It Li "loop_last_flag" Ta "" Ta "1 if last window, pane, session, client in the W:, P:, S:, or L: loop" .It Li "mouse_all_flag" Ta "" Ta "Pane mouse all flag" .It Li "mouse_any_flag" Ta "" Ta "Pane mouse any flag" @@ -7013,6 +7014,9 @@ is the terminal alternate character set. Align text to the left, centre or right of the available space if appropriate. .It Ic fill=colour Fill the available space with a background colour if appropriate. +.It Ic dim=percentage +Dim foreground and background colours by +.Ar percentage . .It Ic width=N Set the width of the styled area. .Ar N diff --git a/tmux.h b/tmux.h index 4a1d6dd9..cb429f06 100644 --- a/tmux.h +++ b/tmux.h @@ -960,6 +960,7 @@ enum style_default_type { struct style { struct grid_cell gc; int ignore; + int dim; int fill; enum style_align align; @@ -1307,6 +1308,8 @@ struct window_pane { struct grid_cell cached_gc; struct grid_cell cached_active_gc; + u_int cached_dim; + u_int cached_active_dim; struct colour_palette palette; enum client_theme last_theme; struct style_line_entry border_status_line; @@ -1648,6 +1651,7 @@ LIST_HEAD(tty_terms, tty_term); struct tty_style_ctx { const struct grid_cell *defaults; struct colour_palette *palette; + u_int dim; struct hyperlinks *hyperlinks; }; @@ -2751,7 +2755,7 @@ void tty_cmd_sixelimage(struct tty *, const struct tty_ctx *); void tty_draw_images(struct client *, struct window_pane *, struct screen *); #endif void tty_cmd_syncstart(struct tty *, const struct tty_ctx *); -void tty_default_colours(struct grid_cell *, struct window_pane *); +void tty_default_colours(struct grid_cell *, struct window_pane *, u_int *); /* tty-term.c */ extern struct tty_terms tty_terms; @@ -3188,6 +3192,7 @@ int colour_find_rgb(u_char, u_char, u_char); int colour_join_rgb(u_char, u_char, u_char); void colour_split_rgb(int, u_char *, u_char *, u_char *); int colour_force_rgb(int); +int colour_dim(int, u_int); const char *colour_tostring(int); enum client_theme colour_totheme(int); int colour_fromstring(const char *); @@ -3856,7 +3861,7 @@ int popup_modify(struct client *, const char *, const char *, int style_parse(struct style *,const struct grid_cell *, const char *); const char *style_tostring(struct style *); -void style_add(struct grid_cell *, struct options *, +struct style *style_add(struct grid_cell *, struct options *, const char *, struct format_tree *); void style_apply(struct grid_cell *, struct options *, const char *, struct format_tree *); diff --git a/tty-draw.c b/tty-draw.c index ec96409d..825d81e4 100644 --- a/tty-draw.c +++ b/tty-draw.c @@ -78,7 +78,7 @@ tty_draw_line_clear(struct tty *tty, u_int px, u_int py, u_int nx, } } - /* Couldn't use an escape sequence, use spaces. */ + /* Couldn't use an escape sequence, use spaces. */ if (px != 0 || !wrapped) tty_cursor(tty, px, py); if (nx == 1) @@ -89,6 +89,30 @@ tty_draw_line_clear(struct tty *tty, u_int px, u_int py, u_int nx, tty_repeat_space(tty, nx); } +/* Is this cell empty? */ +static u_int +tty_draw_line_get_empty(const struct grid_cell *gc, + const struct grid_cell *last, u_int nx) +{ + u_int empty = 0; + + if (gc->data.width > nx) + empty = nx; + else if (gc->flags & GRID_FLAG_PADDING) + empty = 1; + else if (gc->flags & GRID_FLAG_SELECTED) + empty = 0; + else if (gc->bg == last->bg && gc->attr == 0 && gc->link == 0) { + if (gc->flags & GRID_FLAG_CLEARED) + empty = 1; + else if (gc->flags & GRID_FLAG_TAB) + empty = gc->data.width; + else if (gc->data.size == 1 && *gc->data.data == ' ') + empty = 1; + } + return (empty); +} + /* Draw a line from screen to tty. */ void tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx, @@ -105,13 +129,14 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx, size_t len; enum tty_draw_line_state current_state, next_state; struct tty_style_ctx default_style_ctx = { 0 }; - + const struct grid_cell *defaults; if (style_ctx == NULL) { default_style_ctx.defaults = &grid_default_cell; default_style_ctx.hyperlinks = s->hyperlinks; style_ctx = &default_style_ctx; } + defaults = style_ctx->defaults; /* * py is the line in the screen to draw. px is the start x and nx is @@ -138,8 +163,8 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx, else ex = screen_size_x(s); log_debug("%s: drawing %u-%u,%u (end %u) at %u,%u; defaults: fg=%d, " - "bg=%d", __func__, px, px + nx, py, ex, atx, aty, - style_ctx->defaults->fg, style_ctx->defaults->bg); + "bg=%d", __func__, px, px + nx, py, ex, atx, aty, defaults->fg, + defaults->bg); /* Turn off cursor while redrawing and reset region and margins. */ flags = (tty->flags & TTY_NOCURSOR); @@ -150,7 +175,7 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx, /* Start with the default cell as the last cell. */ memcpy(&last, &grid_default_cell, sizeof last); - last.bg = style_ctx->defaults->bg; + last.bg = defaults->bg; tty_default_attributes(tty, 8, style_ctx); /* @@ -172,7 +197,7 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx, break; } if (i == 0) - bg = style_ctx->defaults->bg; + bg = defaults->bg; else { bg = gc.bg; if (gc.flags & GRID_FLAG_SELECTED) { @@ -183,7 +208,7 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx, } tty_attributes(tty, &last, style_ctx); log_debug("%s: clearing %u padding cells", __func__, cx); - tty_draw_line_clear(tty, atx, aty, cx, style_ctx->defaults, bg, 0); + tty_draw_line_clear(tty, atx, aty, cx, defaults, bg, 0); if (cx == ex) goto out; atx += cx; @@ -218,43 +243,31 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx, if (i > nx) fatalx("position %u > width %u", i, nx); - /* Get the current cell. */ - grid_view_get_cell(gd, px + i, py, &gc); - - /* Update for codeset if needed. */ - gcp = tty_check_codeset(tty, &gc); - - /* And for selection. */ - if (gcp->flags & GRID_FLAG_SELECTED) { - memcpy(&ngc, gcp, sizeof ngc); - if (screen_select_cell(s, &ngc, gcp)) - gcp = &ngc; - } - - /* Work out the the empty width. */ - empty = 0; if (px >= ex || i >= ex - px) { /* Outside the area being drawn. */ - empty = 1; - } else if (gcp->data.width > nx - i) { - /* Wide character that has been truncated. */ empty = nx - i; - } else if (gcp->flags & GRID_FLAG_PADDING) { - /* Orphan padding cell. */ - empty = 1; - } else if (gcp->bg == last.bg && gcp->attr == 0 && - gcp->link == 0) { - /* - * No attributes - empty if cleared, tab or - * space. - */ - if (gcp->flags & GRID_FLAG_CLEARED) - empty = 1; - else if (gcp->flags & GRID_FLAG_TAB) - empty = gcp->data.width; - else if (gcp->data.size == 1 && - *gcp->data.data == ' ') - empty = 1; + gcp = &grid_default_cell; + } else { + /* Get the current cell. */ + grid_view_get_cell(gd, px + i, py, &gc); + + /* Work out empty cells. */ + empty = tty_draw_line_get_empty(&gc, &last, + nx - i); + if (empty != 0) + gcp = &gc; + else { + /* Update for codeset if needed. */ + gcp = tty_check_codeset(tty, &gc); + + /* And for selection. */ + if (gcp->flags & GRID_FLAG_SELECTED) { + memcpy(&ngc, gcp, sizeof ngc); + if (screen_select_cell(s, &ngc, + gcp)) + gcp = &ngc; + } + } } /* Work out the next state. */ @@ -284,8 +297,7 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx, if (current_state == TTY_DRAW_LINE_EMPTY) { tty_attributes(tty, &last, style_ctx); tty_draw_line_clear(tty, atx + last_i, aty, - i - last_i, style_ctx->defaults, last.bg, - wrapped); + i - last_i, defaults, last.bg, wrapped); wrapped = 0; } else if (next_state != TTY_DRAW_LINE_SAME && len != 0) { diff --git a/tty.c b/tty.c index f17e5d57..ed3028c4 100644 --- a/tty.c +++ b/tty.c @@ -85,7 +85,7 @@ static void tty_write_one(void (*)(struct tty *, const struct tty_ctx *), #define TTY_REQUEST_LIMIT 30 static struct tty_style_ctx tty_default_style_ctx = { - &grid_default_cell, NULL, NULL + &grid_default_cell, NULL, 0, NULL }; void @@ -2591,16 +2591,39 @@ tty_hyperlink(struct tty *tty, const struct grid_cell *gc, tty_putcode_ss(tty, TTYC_HLS, id, uri); } +static int +tty_dim_default_colour(struct tty *tty, int c, int foreground) +{ + enum client_theme theme; + + if (!COLOUR_DEFAULT(c)) + return (c); + + if (foreground && tty->fg != -1) + return (tty->fg); + if (!foreground && tty->bg != -1) + return (tty->bg); + + theme = tty->client->theme; + if (theme == THEME_DARK) + return (foreground ? 7 : 0); + if (theme == THEME_LIGHT) + return (foreground ? 0 : 7); + return (c); +} + void tty_attributes(struct tty *tty, const struct grid_cell *gc, const struct tty_style_ctx *style_ctx) { struct grid_cell *tc = &tty->cell, gc2; + struct colour_palette *palette; int changed; /* Use default style if not given. */ if (style_ctx == NULL) style_ctx = &tty_default_style_ctx; + palette = style_ctx->palette; /* Copy cell and update default colours. */ memcpy(&gc2, gc, sizeof gc2); @@ -2609,6 +2632,24 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc, gc2.fg = style_ctx->defaults->fg; if (gc2.bg == 8) gc2.bg = style_ctx->defaults->bg; + if (palette != NULL) { + changed = colour_palette_get(palette, gc2.fg); + if (changed != -1) + gc2.fg = changed; + changed = colour_palette_get(palette, gc2.bg); + if (changed != -1) + gc2.bg = changed; + } + } + if (style_ctx->dim != 0) { + gc2.fg = tty_dim_default_colour(tty, gc2.fg, 1); + gc2.bg = tty_dim_default_colour(tty, gc2.bg, 0); + changed = colour_dim(gc2.fg, style_ctx->dim); + if (changed != -1) + gc2.fg = changed; + changed = colour_dim(gc2.bg, style_ctx->dim); + if (changed != -1) + gc2.bg = changed; } /* Ignore cell if it is the same as the last one. */ @@ -2635,9 +2676,9 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc, } /* Fix up the colours if necessary. */ - tty_check_fg(tty, style_ctx->palette, &gc2); - tty_check_bg(tty, style_ctx->palette, &gc2); - tty_check_us(tty, style_ctx->palette, &gc2); + tty_check_fg(tty, palette, &gc2); + tty_check_bg(tty, palette, &gc2); + tty_check_us(tty, palette, &gc2); /* * If any bits are being cleared or the underline colour is now default, @@ -3049,6 +3090,7 @@ tty_style_changed(struct window_pane *wp) { struct options *oo = wp->options; struct format_tree *ft; + struct style *sy; log_debug("%%%u: style changed", wp->id); wp->flags &= ~PANE_STYLECHANGED; @@ -3057,16 +3099,18 @@ tty_style_changed(struct window_pane *wp) format_defaults(ft, NULL, NULL, NULL, wp); tty_window_default_style(&wp->cached_active_gc, wp); - style_add(&wp->cached_active_gc, oo, "window-active-style", ft); + sy = style_add(&wp->cached_active_gc, oo, "window-active-style", ft); + wp->cached_active_dim = sy->dim; tty_window_default_style(&wp->cached_gc, wp); - style_add(&wp->cached_gc, oo, "window-style", ft); + sy = style_add(&wp->cached_gc, oo, "window-style", ft); + wp->cached_dim = sy->dim; format_free(ft); } void -tty_default_colours(struct grid_cell *gc, struct window_pane *wp) +tty_default_colours(struct grid_cell *gc, struct window_pane *wp, u_int *dim) { if (wp->flags & PANE_STYLECHANGED) tty_style_changed (wp); @@ -3080,6 +3124,13 @@ tty_default_colours(struct grid_cell *gc, struct window_pane *wp) gc->bg = wp->cached_active_gc.bg; else gc->bg = wp->cached_gc.bg; + + if (dim != NULL) { + if (wp == wp->window->active) + *dim = wp->cached_active_dim; + else + *dim = wp->cached_dim; + } } void diff --git a/window-buffer.c b/window-buffer.c index ac604a34..5287d2cd 100644 --- a/window-buffer.c +++ b/window-buffer.c @@ -330,13 +330,13 @@ window_buffer_sort(struct sort_criteria *sort_crit) } static const char* window_buffer_help_lines[] = { - "\r\033[1m Enter \033[0m\016x\017 \033[0mPaste selected %1\n", - "\r\033[1m p \033[0m\016x\017 \033[0mPaste selected %1\n", - "\r\033[1m P \033[0m\016x\017 \033[0mPaste tagged %1s\n", - "\r\033[1m d \033[0m\016x\017 \033[0mDelete selected %1\n", - "\r\033[1m D \033[0m\016x\017 \033[0mDelete tagged %1s\n", - "\r\033[1m e \033[0m\016x\017 \033[0mOpen %1 in editor\n", - "\r\033[1m f \033[0m\016x\017 \033[0mEnter a filter\n", + "#[bold] Enter #[default]#[acs]x#[default] Paste selected %1", + "#[bold] p #[default]#[acs]x#[default] Paste selected %1", + "#[bold] P #[default]#[acs]x#[default] Paste tagged %1s", + "#[bold] d #[default]#[acs]x#[default] Delete selected %1", + "#[bold] D #[default]#[acs]x#[default] Delete tagged %1s", + "#[bold] e #[default]#[acs]x#[default] Open %1 in editor", + "#[bold] f #[default]#[acs]x#[default] Enter a filter", NULL }; diff --git a/window-client.c b/window-client.c index 57c9d619..bf7bbf17 100644 --- a/window-client.c +++ b/window-client.c @@ -369,15 +369,15 @@ window_client_sort(struct sort_criteria *sort_crit) } static const char* window_client_help_lines[] = { - "\r\033[1m i \033[0m\016x\017 \033[0mToggle info view\n", - "\r\033[1m Enter \033[0m\016x\017 \033[0mChoose selected %1\n", - "\r\033[1m d \033[0m\016x\017 \033[0mDetach selected %1\n", - "\r\033[1m D \033[0m\016x\017 \033[0mDetach tagged %1s\n", - "\r\033[1m x \033[0m\016x\017 \033[0mDetach selected %1\n", - "\r\033[1m X \033[0m\016x\017 \033[0mDetach tagged %1s\n", - "\r\033[1m z \033[0m\016x\017 \033[0mSuspend selected %1\n", - "\r\033[1m Z \033[0m\016x\017 \033[0mSuspend tagged %1s\n", - "\r\033[1m f \033[0m\016x\017 \033[0mEnter a filter\n", + "#[bold] i #[default]#[acs]x#[default] Toggle info view", + "#[bold] Enter #[default]#[acs]x#[default] Choose selected %1", + "#[bold] d #[default]#[acs]x#[default] Detach selected %1", + "#[bold] D #[default]#[acs]x#[default] Detach tagged %1s", + "#[bold] x #[default]#[acs]x#[default] Detach selected %1", + "#[bold] X #[default]#[acs]x#[default] Detach tagged %1s", + "#[bold] z #[default]#[acs]x#[default] Suspend selected %1", + "#[bold] Z #[default]#[acs]x#[default] Suspend tagged %1s", + "#[bold] f #[default]#[acs]x#[default] Enter a filter", NULL }; diff --git a/window-customize.c b/window-customize.c index 3f78eca9..71ca206f 100644 --- a/window-customize.c +++ b/window-customize.c @@ -869,15 +869,15 @@ window_customize_height(__unused void *modedata, __unused u_int height) } static const char* window_customize_help_lines[] = { - "\r\033[1m Enter, s \033[0m\016x\017 \033[0mSet %1 value\n", - "\r\033[1m S \033[0m\016x\017 \033[0mSet global %1 value\n", - "\r\033[1m w \033[0m\016x\017 \033[0mSet window %1 value\n", - "\r\033[1m d \033[0m\016x\017 \033[0mSet to default value\n", - "\r\033[1m D \033[0m\016x\017 \033[0mSet tagged %1s to default value\n", - "\r\033[1m u \033[0m\016x\017 \033[0mUnset an %1\n", - "\r\033[1m U \033[0m\016x\017 \033[0mUnset tagged %1s\n", - "\r\033[1m f \033[0m\016x\017 \033[0mEnter a filter\n", - "\r\033[1m v \033[0m\016x\017 \033[0mToggle information\n", + "#[bold] Enter, s #[default]#[acs]x#[default] Set %1 value", + "#[bold] S #[default]#[acs]x#[default] Set global %1 value", + "#[bold] w #[default]#[acs]x#[default] Set window %1 value", + "#[bold] d #[default]#[acs]x#[default] Set to default value", + "#[bold] D #[default]#[acs]x#[default] Set tagged %1s to default value", + "#[bold] u #[default]#[acs]x#[default] Unset an %1", + "#[bold] U #[default]#[acs]x#[default] Unset tagged %1s", + "#[bold] f #[default]#[acs]x#[default] Enter a filter", + "#[bold] v #[default]#[acs]x#[default] Toggle information", NULL }; diff --git a/window-tree.c b/window-tree.c index 42fb05c4..b27d6685 100644 --- a/window-tree.c +++ b/window-tree.c @@ -889,18 +889,18 @@ window_tree_sort(struct sort_criteria *sort_crit) } static const char* window_tree_help_lines[] = { - "\r\033[1m Enter \033[0m\016x\017 \033[0mChoose selected item\n", - "\r\033[1m S-Up \033[0m\016x\017 \033[0mSwap current and previous window\n", - "\r\033[1m S-Down \033[0m\016x\017 \033[0mSwap current and next window\n", - "\r\033[1m x \033[0m\016x\017 \033[0mKill selected item\n", - "\r\033[1m X \033[0m\016x\017 \033[0mKill tagged items\n", - "\r\033[1m < \033[0m\016x\017 \033[0mScroll previews left\n", - "\r\033[1m > \033[0m\016x\017 \033[0mScroll previews right\n", - "\r\033[1m m \033[0m\016x\017 \033[0mSet the marked pane\n", - "\r\033[1m M \033[0m\016x\017 \033[0mClear the marked pane\n", - "\r\033[1m : \033[0m\016x\017 \033[0mRun a command for each tagged item\n", - "\r\033[1m f \033[0m\016x\017 \033[0mEnter a format\n", - "\r\033[1m H \033[0m\016x\017 \033[0mJump to the starting pane\n", + "#[bold] Enter #[default]#[acs]x#[default] Choose selected item", + "#[bold] S-Up #[default]#[acs]x#[default] Swap current and previous window", + "#[bold] S-Down #[default]#[acs]x#[default] Swap current and next window", + "#[bold] x #[default]#[acs]x#[default] Kill selected item", + "#[bold] X #[default]#[acs]x#[default] Kill tagged items", + "#[bold] < #[default]#[acs]x#[default] Scroll previews left", + "#[bold] > #[default]#[acs]x#[default] Scroll previews right", + "#[bold] m #[default]#[acs]x#[default] Set the marked pane", + "#[bold] M #[default]#[acs]x#[default] Clear the marked pane", + "#[bold] : #[default]#[acs]x#[default] Run a command for each tagged item", + "#[bold] f #[default]#[acs]x#[default] Enter a format", + "#[bold] H #[default]#[acs]x#[default] Jump to the starting pane", NULL }; diff --git a/window.c b/window.c index d96d1b9e..29dafb14 100644 --- a/window.c +++ b/window.c @@ -599,6 +599,8 @@ window_redraw_active_switch(struct window *w, struct window_pane *wp) gc2 = &wp->cached_active_gc; if (!grid_cells_look_equal(gc1, gc2)) wp->flags |= PANE_REDRAW; + else if (wp->cached_dim != wp->cached_active_dim) + wp->flags |= PANE_REDRAW; else { c1 = window_pane_get_palette(wp, gc1->fg); c2 = window_pane_get_palette(wp, gc2->fg); @@ -1979,7 +1981,7 @@ window_pane_get_bg(struct window_pane *wp) c = window_pane_get_bg_control_client(wp); if (c == -1) { - tty_default_colours(&defaults, wp); + tty_default_colours(&defaults, wp, NULL); if (COLOUR_DEFAULT(defaults.bg)) c = window_get_bg_client(wp); else diff --git a/xmalloc.c b/xmalloc.c index d11d8dc7..14e805ed 100644 --- a/xmalloc.c +++ b/xmalloc.c @@ -105,6 +105,18 @@ xstrndup(const char *str, size_t maxlen) return cp; } +char * +xmemdup(const void *ptr, size_t len) +{ + char *cp; + + cp = xmalloc(len + 1); + if (len != 0) + memcpy(cp, ptr, len); + cp[len] = '\0'; + return cp; +} + int xasprintf(char **ret, const char *fmt, ...) { diff --git a/xmalloc.h b/xmalloc.h index 26009dd8..a87f053b 100644 --- a/xmalloc.h +++ b/xmalloc.h @@ -30,6 +30,7 @@ void *xreallocarray(void *, size_t, size_t); void *xrecallocarray(void *, size_t, size_t, size_t); char *xstrdup(const char *); char *xstrndup(const char *, size_t); +char *xmemdup(const void *, size_t); int xasprintf(char **, const char *, ...) __attribute__((__format__ (printf, 2, 3))) __attribute__((__nonnull__ (2)));