Merge branch 'master' into screen_redraw

This commit is contained in:
Nicholas Marriott
2026-06-19 19:48:50 +01:00
24 changed files with 445 additions and 238 deletions

View File

@@ -168,6 +168,7 @@ cmd_refresh_report(struct tty *tty, const char *value)
{ {
struct window_pane *wp; struct window_pane *wp;
u_int pane; u_int pane;
int fg, bg;
size_t size = 0; size_t size = 0;
char *copy, *split; char *copy, *split;
@@ -184,8 +185,14 @@ cmd_refresh_report(struct tty *tty, const char *value)
if (wp == NULL) if (wp == NULL)
goto out; goto out;
tty_keys_colours(tty, split, strlen(split), &size, &wp->control_fg, fg = wp->control_fg;
&wp->control_bg); 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: out:
free(copy); free(copy);

View File

@@ -120,6 +120,28 @@ colour_force_rgb(int c)
return (-1); 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. */ /* Convert colour to a string. */
const char * const char *
colour_tostring(int c) colour_tostring(int c)

View File

@@ -224,6 +224,14 @@ control_notify_session_window_changed(struct session *s)
{ {
struct client *c; 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) { TAILQ_FOREACH(c, &clients, entry) {
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c)) if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
continue; continue;

180
format.c
View File

@@ -128,6 +128,9 @@ format_job_cmp(struct format_job *fj1, struct format_job *fj2)
/* Limit on time taken (milliseconds). */ /* Limit on time taken (milliseconds). */
#define FORMAT_TIME_LIMIT 100 #define FORMAT_TIME_LIMIT 100
/* How often to check the time in long loops. */
#define FORMAT_TIME_LOOP_CHECK 10000
/* Format expand flags. */ /* Format expand flags. */
#define FORMAT_EXPAND_TIME 0x1 #define FORMAT_EXPAND_TIME 0x1
#define FORMAT_EXPAND_NOJOBS 0x2 #define FORMAT_EXPAND_NOJOBS 0x2
@@ -573,7 +576,7 @@ format_cb_session_attached_list(struct format_tree *ft)
} }
if ((size = EVBUFFER_LENGTH(buffer)) != 0) if ((size = EVBUFFER_LENGTH(buffer)) != 0)
xasprintf(&value, "%.*s", size, EVBUFFER_DATA(buffer)); value = xmemdup(EVBUFFER_DATA(buffer), size);
evbuffer_free(buffer); evbuffer_free(buffer);
return (value); return (value);
} }
@@ -712,7 +715,7 @@ format_cb_window_linked_sessions_list(struct format_tree *ft)
} }
if ((size = EVBUFFER_LENGTH(buffer)) != 0) if ((size = EVBUFFER_LENGTH(buffer)) != 0)
xasprintf(&value, "%.*s", size, EVBUFFER_DATA(buffer)); value = xmemdup(EVBUFFER_DATA(buffer), size);
evbuffer_free(buffer); evbuffer_free(buffer);
return (value); return (value);
} }
@@ -766,7 +769,7 @@ format_cb_window_active_sessions_list(struct format_tree *ft)
} }
if ((size = EVBUFFER_LENGTH(buffer)) != 0) if ((size = EVBUFFER_LENGTH(buffer)) != 0)
xasprintf(&value, "%.*s", size, EVBUFFER_DATA(buffer)); value = xmemdup(EVBUFFER_DATA(buffer), size);
evbuffer_free(buffer); evbuffer_free(buffer);
return (value); return (value);
} }
@@ -830,7 +833,7 @@ format_cb_window_active_clients_list(struct format_tree *ft)
} }
if ((size = EVBUFFER_LENGTH(buffer)) != 0) if ((size = EVBUFFER_LENGTH(buffer)) != 0)
xasprintf(&value, "%.*s", size, EVBUFFER_DATA(buffer)); value = xmemdup(EVBUFFER_DATA(buffer), size);
evbuffer_free(buffer); evbuffer_free(buffer);
return (value); return (value);
} }
@@ -1005,7 +1008,7 @@ format_cb_pane_tabs(struct format_tree *ft)
evbuffer_add_printf(buffer, "%u", i); evbuffer_add_printf(buffer, "%u", i);
} }
if ((size = EVBUFFER_LENGTH(buffer)) != 0) if ((size = EVBUFFER_LENGTH(buffer)) != 0)
xasprintf(&value, "%.*s", size, EVBUFFER_DATA(buffer)); value = xmemdup(EVBUFFER_DATA(buffer), size);
evbuffer_free(buffer); evbuffer_free(buffer);
return (value); return (value);
} }
@@ -1020,7 +1023,7 @@ format_cb_pane_fg(struct format_tree *ft)
if (wp == NULL) if (wp == NULL)
return (NULL); return (NULL);
tty_default_colours(&gc, wp); tty_default_colours(&gc, wp, NULL);
return (xstrdup(colour_tostring(gc.fg))); return (xstrdup(colour_tostring(gc.fg)));
} }
@@ -1057,7 +1060,7 @@ format_cb_pane_bg(struct format_tree *ft)
if (wp == NULL) if (wp == NULL)
return (NULL); return (NULL);
tty_default_colours(&gc, wp); tty_default_colours(&gc, wp, NULL);
return (xstrdup(colour_tostring(gc.bg))); 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) if ((size = EVBUFFER_LENGTH(buffer)) != 0)
xasprintf(&value, "%.*s", size, EVBUFFER_DATA(buffer)); value = xmemdup(EVBUFFER_DATA(buffer), size);
evbuffer_free(buffer); evbuffer_free(buffer);
return (value); return (value);
} }
@@ -1129,7 +1132,7 @@ format_cb_session_group_attached_list(struct format_tree *ft)
} }
if ((size = EVBUFFER_LENGTH(buffer)) != 0) if ((size = EVBUFFER_LENGTH(buffer)) != 0)
xasprintf(&value, "%.*s", size, EVBUFFER_DATA(buffer)); value = xmemdup(EVBUFFER_DATA(buffer), size);
evbuffer_free(buffer); evbuffer_free(buffer);
return (value); return (value);
} }
@@ -1853,15 +1856,6 @@ format_cb_keypad_flag(struct format_tree *ft)
return (NULL); 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. */ /* Callback for mouse_all_flag. */
static void * static void *
format_cb_mouse_all_flag(struct format_tree *ft) 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, { "last_window_index", FORMAT_TABLE_STRING,
format_cb_last_window_index format_cb_last_window_index
}, },
{ "loop_last_flag", FORMAT_TABLE_STRING,
format_cb_loop_last_flag
},
{ "mouse_all_flag", FORMAT_TABLE_STRING, { "mouse_all_flag", FORMAT_TABLE_STRING,
format_cb_mouse_all_flag format_cb_mouse_all_flag
}, },
@@ -4237,10 +4228,14 @@ found:
/* Check if format has not taken too long. */ /* Check if format has not taken too long. */
static int 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) if (t - es->start_time < FORMAT_TIME_LIMIT)
return (1); return (1);
t -= es->start_time; t -= es->start_time;
@@ -4251,21 +4246,24 @@ format_check_time(struct format_expand_state *es)
/* Unescape escaped characters. */ /* Unescape escaped characters. */
static char * 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; const char *end = s + n;
int brackets = 0; char *out, *cp;
int brackets = 0;
u_int check = 0;
cp = out = xmalloc(strlen(s) + 1); cp = out = xmalloc(n + 1);
for (; *s != '\0'; s++) { for (; s != end; s++) {
if (!format_check_time(es)){ if (!format_check_time(es, &check)) {
free(out); free(out);
return (xstrdup("")); return (xstrdup(""));
} }
if (*s == '#' && s[1] == '{') if (*s == '#' && s + 1 != end && s[1] == '{')
brackets++; brackets++;
if (brackets == 0 && if (brackets == 0 &&
*s == '#' && *s == '#' &&
s + 1 != end &&
strchr(",#{}:", s[1]) != NULL) { strchr(",#{}:", s[1]) != NULL) {
*cp++ = *++s; *cp++ = *++s;
continue; continue;
@@ -4284,10 +4282,11 @@ format_strip(struct format_expand_state *es, const char *s)
{ {
char *out, *cp; char *out, *cp;
int brackets = 0; int brackets = 0;
u_int check = 0;
cp = out = xmalloc(strlen(s) + 1); cp = out = xmalloc(strlen(s) + 1);
for (; *s != '\0'; s++) { for (; *s != '\0'; s++) {
if (!format_check_time(es)){ if (!format_check_time(es, &check)) {
free(out); free(out);
return (xstrdup("")); return (xstrdup(""));
} }
@@ -4311,9 +4310,10 @@ static const char *
format_skip1(struct format_expand_state *es, const char *s, const char *end) format_skip1(struct format_expand_state *es, const char *s, const char *end)
{ {
int brackets = 0; int brackets = 0;
u_int check = 0;
for (; *s != '\0'; s++) { for (; *s != '\0'; s++) {
if (es != NULL && !format_check_time(es)) if (es != NULL && !format_check_time(es, &check))
return (NULL); return (NULL);
if (*s == '#' && s[1] == '{') if (*s == '#' && s[1] == '{')
brackets++; brackets++;
@@ -4484,7 +4484,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
break; break;
argv = xcalloc(1, sizeof *argv); 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); argv[0] = format_expand1(es, value);
free(value); free(value);
argc = 1; argc = 1;
@@ -4508,7 +4508,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
cp++; cp++;
argv = xreallocarray(argv, argc + 1, sizeof *argv); 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); argv[argc++] = format_expand1(es, value);
free(value); free(value);
@@ -4671,17 +4671,19 @@ format_loop_sessions(struct format_expand_state *es, const char *fmt)
struct format_tree *nft; struct format_tree *nft;
struct format_expand_state next; struct format_expand_state next;
char *all, *active, *use, *expanded, *value; char *all, *active, *use, *expanded, *value;
size_t valuelen; struct evbuffer *buffer;
size_t size;
struct session *s, **l; struct session *s, **l;
int i, n, last = 0; int i, n;
if (format_choose(es, fmt, &all, &active, 0) != 0) { if (format_choose(es, fmt, &all, &active, 0) != 0) {
all = xstrdup(fmt); all = xstrdup(fmt);
active = NULL; active = NULL;
} }
value = xcalloc(1, 1); buffer = evbuffer_new();
valuelen = 1; if (buffer == NULL)
fatalx("out of memory");
l = sort_get_sessions(&n, sc); l = sort_get_sessions(&n, sc);
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
@@ -4693,25 +4695,27 @@ format_loop_sessions(struct format_expand_state *es, const char *fmt)
use = active; use = active;
else else
use = all; use = all;
if (i == n - 1) nft = format_create(c, item, FORMAT_NONE, ft->flags);
last = FORMAT_LAST; format_add(nft, "loop_index", "%d", i);
nft = format_create(c, item, FORMAT_NONE, ft->flags|last); format_add(nft, "loop_last_flag", "%d", i == n - 1);
format_defaults(nft, ft->c, s, NULL, NULL); format_defaults(nft, ft->c, s, NULL, NULL);
format_copy_state(&next, es, 0); format_copy_state(&next, es, 0);
next.ft = nft; next.ft = nft;
expanded = format_expand1(&next, use); expanded = format_expand1(&next, use);
format_free(next.ft); format_free(next.ft);
valuelen += strlen(expanded); evbuffer_add(buffer, expanded, strlen(expanded));
value = xrealloc(value, valuelen);
strlcat(value, expanded, valuelen);
free(expanded); free(expanded);
} }
free(active); free(active);
free(all); free(all);
if ((size = EVBUFFER_LENGTH(buffer)) != 0)
value = xmemdup(EVBUFFER_DATA(buffer), size);
else
value = xstrdup("");
evbuffer_free(buffer);
return (value); return (value);
} }
@@ -4781,10 +4785,11 @@ format_loop_windows(struct format_expand_state *es, const char *fmt)
struct format_tree *nft; struct format_tree *nft;
struct format_expand_state next; struct format_expand_state next;
char *all, *active, *use, *expanded, *value; char *all, *active, *use, *expanded, *value;
size_t valuelen; struct evbuffer *buffer;
size_t size;
struct winlink *wl, **l; struct winlink *wl, **l;
struct window *w; struct window *w;
int i, n, last = 0; int i, n;
if (ft->s == NULL) { if (ft->s == NULL) {
format_log(es, "window loop but no session"); 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; active = NULL;
} }
value = xcalloc(1, 1); buffer = evbuffer_new();
valuelen = 1; if (buffer == NULL)
fatalx("out of memory");
l = sort_get_winlinks_session(ft->s, &n, sc); l = sort_get_winlinks_session(ft->s, &n, sc);
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
@@ -4808,10 +4814,10 @@ format_loop_windows(struct format_expand_state *es, const char *fmt)
use = active; use = active;
else else
use = all; use = all;
if (i == n - 1)
last = FORMAT_LAST;
nft = format_create(c, item, FORMAT_WINDOW|w->id, 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); format_defaults(nft, ft->c, ft->s, wl, NULL);
/* Add neighbor window data to the format tree. */ /* 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); expanded = format_expand1(&next, use);
format_free(nft); format_free(nft);
valuelen += strlen(expanded); evbuffer_add(buffer, expanded, strlen(expanded));
value = xrealloc(value, valuelen);
strlcat(value, expanded, valuelen);
free(expanded); free(expanded);
} }
free(active); free(active);
free(all); free(all);
if ((size = EVBUFFER_LENGTH(buffer)) != 0)
value = xmemdup(EVBUFFER_DATA(buffer), size);
else
value = xstrdup("");
evbuffer_free(buffer);
return (value); return (value);
} }
@@ -4853,9 +4861,10 @@ format_loop_panes(struct format_expand_state *es, const char *fmt)
struct format_tree *nft; struct format_tree *nft;
struct format_expand_state next; struct format_expand_state next;
char *all, *active, *use, *expanded, *value; char *all, *active, *use, *expanded, *value;
size_t valuelen; struct evbuffer *buffer;
size_t size;
struct window_pane *wp, **l; struct window_pane *wp, **l;
int i, n, last = 0; int i, n;
if (ft->w == NULL) { if (ft->w == NULL) {
format_log(es, "pane loop but no window"); 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; active = NULL;
} }
value = xcalloc(1, 1); buffer = evbuffer_new();
valuelen = 1; if (buffer == NULL)
fatalx("out of memory");
l = sort_get_panes_window(ft->w, &n, sc); l = sort_get_panes_window(ft->w, &n, sc);
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
@@ -4878,26 +4888,28 @@ format_loop_panes(struct format_expand_state *es, const char *fmt)
use = active; use = active;
else else
use = all; use = all;
if (i == n - 1)
last = FORMAT_LAST;
nft = format_create(c, item, FORMAT_PANE|wp->id, 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_defaults(nft, ft->c, ft->s, ft->wl, wp);
format_copy_state(&next, es, 0); format_copy_state(&next, es, 0);
next.ft = nft; next.ft = nft;
expanded = format_expand1(&next, use); expanded = format_expand1(&next, use);
format_free(nft); format_free(nft);
valuelen += strlen(expanded); evbuffer_add(buffer, expanded, strlen(expanded));
value = xrealloc(value, valuelen);
strlcat(value, expanded, valuelen);
free(expanded); free(expanded);
} }
free(active); free(active);
free(all); free(all);
if ((size = EVBUFFER_LENGTH(buffer)) != 0)
value = xmemdup(EVBUFFER_DATA(buffer), size);
else
value = xstrdup("");
evbuffer_free(buffer);
return (value); return (value);
} }
@@ -4912,32 +4924,36 @@ format_loop_clients(struct format_expand_state *es, const char *fmt)
struct format_tree *nft; struct format_tree *nft;
struct format_expand_state next; struct format_expand_state next;
char *expanded, *value; char *expanded, *value;
size_t valuelen; struct evbuffer *buffer;
int i, n, last = 0; size_t size;
int i, n;
value = xcalloc(1, 1); buffer = evbuffer_new();
valuelen = 1; if (buffer == NULL)
fatalx("out of memory");
l = sort_get_clients(&n, sc); l = sort_get_clients(&n, sc);
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
c = l[i]; c = l[i];
format_log(es, "client loop: %s", c->name); format_log(es, "client loop: %s", c->name);
if (i == n - 1) nft = format_create(c, item, 0, ft->flags);
last = FORMAT_LAST; format_add(nft, "loop_index", "%d", i);
nft = format_create(c, item, 0, ft->flags|last); format_add(nft, "loop_last_flag", "%d", i == n - 1);
format_defaults(nft, c, ft->s, ft->wl, ft->wp); format_defaults(nft, c, ft->s, ft->wl, ft->wp);
format_copy_state(&next, es, 0); format_copy_state(&next, es, 0);
next.ft = nft; next.ft = nft;
expanded = format_expand1(&next, fmt); expanded = format_expand1(&next, fmt);
format_free(nft); format_free(nft);
valuelen += strlen(expanded); evbuffer_add(buffer, expanded, strlen(expanded));
value = xrealloc(value, valuelen);
strlcat(value, expanded, valuelen);
free(expanded); free(expanded);
} }
if ((size = EVBUFFER_LENGTH(buffer)) != 0)
value = xmemdup(EVBUFFER_DATA(buffer), size);
else
value = xstrdup("");
evbuffer_free(buffer);
return (value); 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 *list, *cmp = NULL, *search = NULL;
struct format_modifier **sub = NULL, *mexp = NULL, *fm; struct format_modifier **sub = NULL, *mexp = NULL, *fm;
struct format_modifier *bool_op_n = NULL; 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 format_expand_state next;
struct environ_entry *envent; 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? */ /* Is this a literal string? */
if (modifiers & FORMAT_LITERAL) { if (modifiers & FORMAT_LITERAL) {
format_log(es, "literal string is '%s'", copy); format_log(es, "literal string is '%s'", copy);
value = format_unescape(es, copy); value = format_unescape(es, copy, strlen(copy));
goto done; goto done;
} }
@@ -5436,7 +5452,7 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
else { else {
value = xstrdup(""); value = xstrdup("");
for (i = 0; i < nrep; i++) { for (i = 0; i < nrep; i++) {
if (!format_check_time(es)) { if (!format_check_time(es, &check)) {
free(right); free(right);
free(left); free(left);
free(value); free(value);
@@ -5716,7 +5732,7 @@ format_expand1(struct format_expand_state *es, const char *fmt)
int ch, brackets; int ch, brackets;
char expanded[8192]; char expanded[8192];
if (fmt == NULL || *fmt == '\0' || !format_check_time(es)) if (fmt == NULL || *fmt == '\0' || !format_check_time(es, NULL))
return (xstrdup("")); return (xstrdup(""));
if (es->loop == FORMAT_LOOP_LIMIT) { if (es->loop == FORMAT_LOOP_LIMIT) {

View File

@@ -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; new->set_ra = si->set_ra;
/* subtract offset */ /* subtract offset */
new->ra_x = new->ra_x > pox ? new->ra_x - pox : 0; new->ra_x = si->ra_x > pox ? si->ra_x - pox : 0;
new->ra_y = new->ra_y > poy ? new->ra_y - poy : 0; new->ra_y = si->ra_y > poy ? si->ra_y - poy : 0;
/* clamp to size */ /* clamp to size */
new->ra_x = si->ra_x < psx ? si->ra_x : psx; new->ra_x = new->ra_x < psx ? new->ra_x : psx;
new->ra_y = si->ra_y < psy ? si->ra_y : psy; new->ra_y = new->ra_y < psy ? new->ra_y : psy;
/* resize */ /* resize */
new->ra_x = new->ra_x * xpixel / si->xpixel; new->ra_x = new->ra_x * xpixel / si->xpixel;
new->ra_y = new->ra_y * ypixel / si->ypixel; new->ra_y = new->ra_y * ypixel / si->ypixel;

View File

@@ -3055,7 +3055,7 @@ input_osc_10(struct input_ctx *ictx, const char *p)
return; return;
c = window_pane_get_fg_control_client(wp); c = window_pane_get_fg_control_client(wp);
if (c == -1) { if (c == -1) {
tty_default_colours(&defaults, wp); tty_default_colours(&defaults, wp, NULL);
if (COLOUR_DEFAULT(defaults.fg)) if (COLOUR_DEFAULT(defaults.fg))
c = window_pane_get_fg(wp); c = window_pane_get_fg(wp);
else else

View File

@@ -25,11 +25,10 @@
#include "tmux.h" #include "tmux.h"
#define DEFAULT_SESSION_MENU \ #define DEFAULT_SESSION_MENU \
" 'Next' 'n' {switch-client -n}" \ " #{S/t:#{?#{&&:#{<:#{loop_index},6},#{!:#{session_active}}},'Switch To #[underscore]#{session_name}' '' {switch-client -t=#{session_id}#} ,}}" \
" 'Previous' 'p' {switch-client -p}" \
" ''" \ " ''" \
" 'Renumber' 'N' {move-window -r}" \ " '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}" \ " 'Detach' 'd' {detach-client}" \
" ''" \ " ''" \
" 'New Session' 's' {new-session}" \ " 'New Session' 's' {new-session}" \
@@ -486,8 +485,8 @@ key_bindings_init(void)
"bind -n WheelUpStatus { previous-window }", "bind -n WheelUpStatus { previous-window }",
/* Mouse button 3 down on status left. */ /* 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 MouseDown3StatusLeft { run -C \"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 M-MouseDown3StatusLeft { run -C \"display-menu -t= -xM -yW -T '#[align=centre]#{session_name}' " DEFAULT_SESSION_MENU "\" }",
/* Mouse button 3 down on status line. */ /* 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 "}", "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 M-Down { send -X halfpage-down }",
"bind -Tcopy-mode C-Up { send -X scroll-up }", "bind -Tcopy-mode C-Up { send -X scroll-up }",
"bind -Tcopy-mode C-Down { send -X scroll-down }", "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. */ /* Copy mode (vi) keys. */
"bind -Tcopy-mode-vi '#' { send -FX search-backward -- '#{copy_cursor_word}' }", "bind -Tcopy-mode-vi '#' { send -FX search-backward -- '#{copy_cursor_word}' }",

View File

@@ -84,6 +84,7 @@ struct mode_tree_data {
int no_matches; int no_matches;
enum mode_tree_search_dir search_dir; enum mode_tree_search_dir search_dir;
int search_icase; int search_icase;
int help;
}; };
struct mode_tree_item { 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_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[] = { static const struct menu_item mode_tree_menu_items[] = {
{ "Scroll Left", '<', NULL }, { "Scroll Left", '<', NULL },
@@ -135,31 +138,31 @@ static const struct menu_item mode_tree_menu_items[] = {
}; };
static const char* mode_tree_help_start[] = { static const char* mode_tree_help_start[] = {
"\r\033[1m Up, k \033[0m\016x\017 \033[0mMove cursor up\n", "#[bold] Up, k #[default]#[acs]x#[default] Move cursor up",
"\r\033[1m Down, j \033[0m\016x\017 \033[0mMove cursor down\n", "#[bold] Down, j #[default]#[acs]x#[default] Move cursor down",
"\r\033[1m g \033[0m\016x\017 \033[0mGo to top\n", "#[bold] g #[default]#[acs]x#[default] Go to top",
"\r\033[1m G \033[0m\016x\017 \033[0mGo to bottom\n", "#[bold] G #[default]#[acs]x#[default] Go to bottom",
"\r\033[1m PPage, C-b \033[0m\016x\017 \033[0mPage up\n", "#[bold] PPage, C-b #[default]#[acs]x#[default] Page up",
"\r\033[1m NPage, C-f \033[0m\016x\017 \033[0mPage down\n", "#[bold] NPage, C-f #[default]#[acs]x#[default] Page down",
"\r\033[1m Left, h \033[0m\016x\017 \033[0mCollapse %1\n", "#[bold] Left, h #[default]#[acs]x#[default] Collapse %1",
"\r\033[1m Right, l \033[0m\016x\017 \033[0mExpand %1\n", "#[bold] Right, l #[default]#[acs]x#[default] Expand %1",
"\r\033[1m M-- \033[0m\016x\017 \033[0mCollapse all %1s\n", "#[bold] M-- #[default]#[acs]x#[default] Collapse all %1s",
"\r\033[1m M-+ \033[0m\016x\017 \033[0mExpand all %1s\n", "#[bold] M-+ #[default]#[acs]x#[default] Expand all %1s",
"\r\033[1m t \033[0m\016x\017 \033[0mToggle %1 tag\n", "#[bold] t #[default]#[acs]x#[default] Toggle %1 tag",
"\r\033[1m T \033[0m\016x\017 \033[0mUntag all %1s\n", "#[bold] T #[default]#[acs]x#[default] Untag all %1s",
"\r\033[1m C-t \033[0m\016x\017 \033[0mTag all %1s\n", "#[bold] C-t #[default]#[acs]x#[default] Tag all %1s",
"\r\033[1m C-s \033[0m\016x\017 \033[0mSearch forward\n", "#[bold] C-s #[default]#[acs]x#[default] Search forward",
"\r\033[1m C-r \033[0m\016x\017 \033[0mSearch backward\n", "#[bold] C-r #[default]#[acs]x#[default] Search backward",
"\r\033[1m n \033[0m\016x\017 \033[0mRepeat search forward\n", "#[bold] n #[default]#[acs]x#[default] Repeat search forward",
"\r\033[1m N \033[0m\016x\017 \033[0mRepeat search backward\n", "#[bold] N #[default]#[acs]x#[default] Repeat search backward",
"\r\033[1m f \033[0m\016x\017 \033[0mFilter %1s\n", "#[bold] f #[default]#[acs]x#[default] Filter %1s",
"\r\033[1m O \033[0m\016x\017 \033[0mChange sort order\n", "#[bold] O #[default]#[acs]x#[default] Change sort order",
"\r\033[1m r \033[0m\016x\017 \033[0mReverse sort order\n", "#[bold] r #[default]#[acs]x#[default] Reverse sort order",
"\r\033[1m v \033[0m\016x\017 \033[0mToggle preview\n", "#[bold] v #[default]#[acs]x#[default] Toggle preview",
NULL NULL
}; };
static const char* mode_tree_help_end[] = { 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 NULL
}; };
#define MODE_TREE_HELP_DEFAULT_WIDTH 39 #define MODE_TREE_HELP_DEFAULT_WIDTH 39
@@ -928,6 +931,8 @@ mode_tree_draw(struct mode_tree_data *mtd)
} }
done: done:
if (mtd->help)
mode_tree_draw_help(mtd, &ctx);
screen_write_cursormove(&ctx, 0, mtd->current - mtd->offset, 0); screen_write_cursormove(&ctx, 0, mtd->current - mtd->offset, 0);
screen_write_stop(&ctx); 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 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; char *expanded;
u_int px, py, w, h = 0;
const char **line, **lines = NULL, *item = "item"; expanded = cmd_template_replace(line, item, 1);
char *new_line; 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) if (mtd->helpcb == NULL)
w = MODE_TREE_HELP_DEFAULT_WIDTH; 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++) for (line = mode_tree_help_end; *line != NULL; line++)
h++; 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; return;
px = (c->tty.sx - w) / 2; x = (sx - box_w) / 2;
py = (c->tty.sy - h) / 2; y = (sy - box_h) / 2;
if (popup_display(POPUP_CLOSEANYKEY|POPUP_NOJOB, BOX_LINES_DEFAULT, memcpy(&gc, &grid_default_cell, sizeof gc);
NULL, px, py, w, h, NULL, NULL, 0, NULL, NULL, NULL, c, s, NULL, screen_write_cursormove(ctx, x, y, 0);
NULL, NULL, NULL) != 0) screen_write_box(ctx, box_w, box_h, BOX_LINES_DEFAULT, &gc, NULL);
return;
popup_write(c, "\033[H\033[?25l\033[?7l\033)0", 17); y++;
for (line = mode_tree_help_start; *line != NULL; line++) { x++;
new_line = cmd_template_replace(*line, item, 1); for (line = mode_tree_help_start; *line != NULL; line++, y++)
popup_write(c, new_line, strlen(new_line)); mode_tree_draw_help_line(ctx, &gc, *line, item, x, y, w);
free(new_line); for (line = lines; line != NULL && *line != NULL; line++, y++)
} mode_tree_draw_help_line(ctx, &gc, *line, item, x, y, w);
for (line = lines; line != NULL && *line != NULL; line++) { for (line = mode_tree_help_end; *line != NULL; line++, y++)
new_line = cmd_template_replace(*line, item, 1); mode_tree_draw_help_line(ctx, &gc, *line, item, x, y, w);
popup_write(c, new_line, strlen(new_line)); }
free(new_line);
} static void
for (line = mode_tree_help_end; *line != NULL; line++) { mode_tree_display_help(struct mode_tree_data *mtd)
new_line = cmd_template_replace(*line, item, 1); {
popup_write(c, new_line, strlen(new_line)); mtd->help = 1;
free(new_line); mode_tree_draw(mtd);
}
popup_write(c, "\033[H", 3);
} }
int int
@@ -1239,6 +1259,13 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
return (1); 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 (KEYC_IS_MOUSE(*key) && m != NULL) {
if (cmd_mouse_at(mtd->wp, m, &x, &y, 0) != 0) { if (cmd_mouse_at(mtd->wp, m, &x, &y, 0) != 0) {
*key = KEYC_NONE; *key = KEYC_NONE;
@@ -1304,7 +1331,7 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
return (1); return (1);
case KEYC_F1: case KEYC_F1:
case 'h'|KEYC_CTRL: case 'h'|KEYC_CTRL:
mode_tree_display_help(mtd, c); mode_tree_display_help(mtd);
break; break;
case KEYC_UP: case KEYC_UP:
case 'k': case 'k':

View File

@@ -327,6 +327,7 @@ popup_draw_cb(struct client *c, void *data)
defaults.bg = pd->palette.bg; defaults.bg = pd->palette.bg;
style_ctx.defaults = &defaults; style_ctx.defaults = &defaults;
style_ctx.palette = &pd->palette; style_ctx.palette = &pd->palette;
style_ctx.dim = 0;
style_ctx.hyperlinks = s.hyperlinks; style_ctx.hyperlinks = s.hyperlinks;
if (pd->md != NULL) { if (pd->md != NULL) {

20
regress/command-alias.sh Normal file
View File

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

View File

@@ -67,6 +67,7 @@ $TMUX set @true 1 || exit 1
$TMUX set @false 0 || exit 1 $TMUX set @false 0 || exit 1
$TMUX set @warm Summer || exit 1 $TMUX set @warm Summer || exit 1
$TMUX set @cold Winter || exit 1 $TMUX set @cold Winter || exit 1
$TMUX set @v 'foo:bar' || exit 1
# Plain string without substitutions et al # Plain string without substitutions et al
test_format "abc xyz" "abc xyz" test_format "abc xyz" "abc xyz"
@@ -74,6 +75,8 @@ test_format "abc xyz" "abc xyz"
# Test basic escapes for "#", "{", "#{" "}", "#}", "," # Test basic escapes for "#", "{", "#{" "}", "#}", ","
test_format "##" "#" test_format "##" "#"
test_format "#," "," test_format "#," ","
test_format "#{s/#:/_/:@v}" "foo_bar"
test_format "#{s/o/#:/:@v}" "f:::bar"
test_format "{" "{" test_format "{" "{"
test_format "##{" "#{" test_format "##{" "#{"
test_format "#}" "}" test_format "#}" "}"

View File

@@ -252,7 +252,8 @@ screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx,
} else { } else {
ttyctx->redraw_cb = screen_write_redraw_cb; ttyctx->redraw_cb = screen_write_redraw_cb;
if (ctx->wp != NULL) { 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->style_ctx.palette = &ctx->wp->palette;
ttyctx->set_client_cb = screen_write_set_client_cb; ttyctx->set_client_cb = screen_write_set_client_cb;
ttyctx->arg = ctx->wp; ttyctx->arg = ctx->wp;

16
style.c
View File

@@ -32,6 +32,7 @@
static struct style style_default = { static struct style style_default = {
{ { { ' ' }, 0, 1, 1 }, 0, 0, 8, 8, 0, 0 }, { { { ' ' }, 0, 1, 1 }, 0, 0, 8, 8, 0, 0 },
0, 0,
0,
8, 8,
STYLE_ALIGN_DEFAULT, 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) if ((value = colour_fromstring(tmp + 5)) == -1)
goto error; goto error;
sy->fill = value; 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) { } else if (end > 3 && strncasecmp(tmp + 1, "g=", 2) == 0) {
if ((value = colour_fromstring(tmp + 3)) == -1) if ((value = colour_fromstring(tmp + 3)) == -1)
goto error; goto error;
@@ -346,6 +354,11 @@ style_tostring(struct style *sy)
colour_tostring(sy->fill)); colour_tostring(sy->fill));
comma = ","; comma = ",";
} }
if (sy->dim != 0) {
off += xsnprintf(s + off, sizeof s - off, "%sdim=%d%%", comma,
sy->dim);
comma = ",";
}
if (gc->fg != 8) { if (gc->fg != 8) {
off += xsnprintf(s + off, sizeof s - off, "%sfg=%s", comma, off += xsnprintf(s + off, sizeof s - off, "%sfg=%s", comma,
colour_tostring(gc->fg)); colour_tostring(gc->fg));
@@ -386,7 +399,7 @@ style_tostring(struct style *sy)
} }
/* Apply a style on top of the given style. */ /* Apply a style on top of the given style. */
void struct style *
style_add(struct grid_cell *gc, struct options *oo, const char *name, style_add(struct grid_cell *gc, struct options *oo, const char *name,
struct format_tree *ft) struct format_tree *ft)
{ {
@@ -409,6 +422,7 @@ style_add(struct grid_cell *gc, struct options *oo, const char *name,
if (ft0 != NULL) if (ft0 != NULL)
format_free(ft0); format_free(ft0);
return (sy);
} }
/* Apply a style on top of the default style. */ /* Apply a style on top of the default style. */

4
tmux.1
View File

@@ -6776,6 +6776,7 @@ The following variables are available, where appropriate:
.It Li "keypad_flag" Ta "" Ta "Pane keypad 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 "last_window_index" Ta "" Ta "Index of last window in session"
.It Li "line" Ta "" Ta "Line number in the list" .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 "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_all_flag" Ta "" Ta "Pane mouse all flag"
.It Li "mouse_any_flag" Ta "" Ta "Pane mouse any 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. Align text to the left, centre or right of the available space if appropriate.
.It Ic fill=colour .It Ic fill=colour
Fill the available space with a background colour if appropriate. 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 .It Ic width=N
Set the width of the styled area. Set the width of the styled area.
.Ar N .Ar N

9
tmux.h
View File

@@ -960,6 +960,7 @@ enum style_default_type {
struct style { struct style {
struct grid_cell gc; struct grid_cell gc;
int ignore; int ignore;
int dim;
int fill; int fill;
enum style_align align; enum style_align align;
@@ -1307,6 +1308,8 @@ struct window_pane {
struct grid_cell cached_gc; struct grid_cell cached_gc;
struct grid_cell cached_active_gc; struct grid_cell cached_active_gc;
u_int cached_dim;
u_int cached_active_dim;
struct colour_palette palette; struct colour_palette palette;
enum client_theme last_theme; enum client_theme last_theme;
struct style_line_entry border_status_line; struct style_line_entry border_status_line;
@@ -1648,6 +1651,7 @@ LIST_HEAD(tty_terms, tty_term);
struct tty_style_ctx { struct tty_style_ctx {
const struct grid_cell *defaults; const struct grid_cell *defaults;
struct colour_palette *palette; struct colour_palette *palette;
u_int dim;
struct hyperlinks *hyperlinks; 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 *); void tty_draw_images(struct client *, struct window_pane *, struct screen *);
#endif #endif
void tty_cmd_syncstart(struct tty *, const struct tty_ctx *); 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 */ /* tty-term.c */
extern struct tty_terms tty_terms; 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); int colour_join_rgb(u_char, u_char, u_char);
void colour_split_rgb(int, u_char *, u_char *, u_char *); void colour_split_rgb(int, u_char *, u_char *, u_char *);
int colour_force_rgb(int); int colour_force_rgb(int);
int colour_dim(int, u_int);
const char *colour_tostring(int); const char *colour_tostring(int);
enum client_theme colour_totheme(int); enum client_theme colour_totheme(int);
int colour_fromstring(const char *); 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 *, int style_parse(struct style *,const struct grid_cell *,
const char *); const char *);
const char *style_tostring(struct style *); 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 *); const char *, struct format_tree *);
void style_apply(struct grid_cell *, struct options *, void style_apply(struct grid_cell *, struct options *,
const char *, struct format_tree *); const char *, struct format_tree *);

View File

@@ -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) if (px != 0 || !wrapped)
tty_cursor(tty, px, py); tty_cursor(tty, px, py);
if (nx == 1) 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); 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. */ /* Draw a line from screen to tty. */
void void
tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx, 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; size_t len;
enum tty_draw_line_state current_state, next_state; enum tty_draw_line_state current_state, next_state;
struct tty_style_ctx default_style_ctx = { 0 }; struct tty_style_ctx default_style_ctx = { 0 };
const struct grid_cell *defaults;
if (style_ctx == NULL) { if (style_ctx == NULL) {
default_style_ctx.defaults = &grid_default_cell; default_style_ctx.defaults = &grid_default_cell;
default_style_ctx.hyperlinks = s->hyperlinks; default_style_ctx.hyperlinks = s->hyperlinks;
style_ctx = &default_style_ctx; 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 * 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 else
ex = screen_size_x(s); ex = screen_size_x(s);
log_debug("%s: drawing %u-%u,%u (end %u) at %u,%u; defaults: fg=%d, " 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, "bg=%d", __func__, px, px + nx, py, ex, atx, aty, defaults->fg,
style_ctx->defaults->fg, style_ctx->defaults->bg); defaults->bg);
/* Turn off cursor while redrawing and reset region and margins. */ /* Turn off cursor while redrawing and reset region and margins. */
flags = (tty->flags & TTY_NOCURSOR); 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. */ /* Start with the default cell as the last cell. */
memcpy(&last, &grid_default_cell, sizeof last); memcpy(&last, &grid_default_cell, sizeof last);
last.bg = style_ctx->defaults->bg; last.bg = defaults->bg;
tty_default_attributes(tty, 8, style_ctx); 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; break;
} }
if (i == 0) if (i == 0)
bg = style_ctx->defaults->bg; bg = defaults->bg;
else { else {
bg = gc.bg; bg = gc.bg;
if (gc.flags & GRID_FLAG_SELECTED) { 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); tty_attributes(tty, &last, style_ctx);
log_debug("%s: clearing %u padding cells", __func__, cx); 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) if (cx == ex)
goto out; goto out;
atx += cx; 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) if (i > nx)
fatalx("position %u > width %u", 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) { if (px >= ex || i >= ex - px) {
/* Outside the area being drawn. */ /* Outside the area being drawn. */
empty = 1;
} else if (gcp->data.width > nx - i) {
/* Wide character that has been truncated. */
empty = nx - i; empty = nx - i;
} else if (gcp->flags & GRID_FLAG_PADDING) { gcp = &grid_default_cell;
/* Orphan padding cell. */ } else {
empty = 1; /* Get the current cell. */
} else if (gcp->bg == last.bg && gcp->attr == 0 && grid_view_get_cell(gd, px + i, py, &gc);
gcp->link == 0) {
/* /* Work out empty cells. */
* No attributes - empty if cleared, tab or empty = tty_draw_line_get_empty(&gc, &last,
* space. nx - i);
*/ if (empty != 0)
if (gcp->flags & GRID_FLAG_CLEARED) gcp = &gc;
empty = 1; else {
else if (gcp->flags & GRID_FLAG_TAB) /* Update for codeset if needed. */
empty = gcp->data.width; gcp = tty_check_codeset(tty, &gc);
else if (gcp->data.size == 1 &&
*gcp->data.data == ' ') /* And for selection. */
empty = 1; 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. */ /* 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) { if (current_state == TTY_DRAW_LINE_EMPTY) {
tty_attributes(tty, &last, style_ctx); tty_attributes(tty, &last, style_ctx);
tty_draw_line_clear(tty, atx + last_i, aty, tty_draw_line_clear(tty, atx + last_i, aty,
i - last_i, style_ctx->defaults, last.bg, i - last_i, defaults, last.bg, wrapped);
wrapped);
wrapped = 0; wrapped = 0;
} else if (next_state != TTY_DRAW_LINE_SAME && } else if (next_state != TTY_DRAW_LINE_SAME &&
len != 0) { len != 0) {

65
tty.c
View File

@@ -85,7 +85,7 @@ static void tty_write_one(void (*)(struct tty *, const struct tty_ctx *),
#define TTY_REQUEST_LIMIT 30 #define TTY_REQUEST_LIMIT 30
static struct tty_style_ctx tty_default_style_ctx = { static struct tty_style_ctx tty_default_style_ctx = {
&grid_default_cell, NULL, NULL &grid_default_cell, NULL, 0, NULL
}; };
void void
@@ -2591,16 +2591,39 @@ tty_hyperlink(struct tty *tty, const struct grid_cell *gc,
tty_putcode_ss(tty, TTYC_HLS, id, uri); 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 void
tty_attributes(struct tty *tty, const struct grid_cell *gc, tty_attributes(struct tty *tty, const struct grid_cell *gc,
const struct tty_style_ctx *style_ctx) const struct tty_style_ctx *style_ctx)
{ {
struct grid_cell *tc = &tty->cell, gc2; struct grid_cell *tc = &tty->cell, gc2;
struct colour_palette *palette;
int changed; int changed;
/* Use default style if not given. */ /* Use default style if not given. */
if (style_ctx == NULL) if (style_ctx == NULL)
style_ctx = &tty_default_style_ctx; style_ctx = &tty_default_style_ctx;
palette = style_ctx->palette;
/* Copy cell and update default colours. */ /* Copy cell and update default colours. */
memcpy(&gc2, gc, sizeof gc2); 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; gc2.fg = style_ctx->defaults->fg;
if (gc2.bg == 8) if (gc2.bg == 8)
gc2.bg = style_ctx->defaults->bg; 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. */ /* 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. */ /* Fix up the colours if necessary. */
tty_check_fg(tty, style_ctx->palette, &gc2); tty_check_fg(tty, palette, &gc2);
tty_check_bg(tty, style_ctx->palette, &gc2); tty_check_bg(tty, palette, &gc2);
tty_check_us(tty, style_ctx->palette, &gc2); tty_check_us(tty, palette, &gc2);
/* /*
* If any bits are being cleared or the underline colour is now default, * 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 options *oo = wp->options;
struct format_tree *ft; struct format_tree *ft;
struct style *sy;
log_debug("%%%u: style changed", wp->id); log_debug("%%%u: style changed", wp->id);
wp->flags &= ~PANE_STYLECHANGED; wp->flags &= ~PANE_STYLECHANGED;
@@ -3057,16 +3099,18 @@ tty_style_changed(struct window_pane *wp)
format_defaults(ft, NULL, NULL, NULL, wp); format_defaults(ft, NULL, NULL, NULL, wp);
tty_window_default_style(&wp->cached_active_gc, 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); 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); format_free(ft);
} }
void 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) if (wp->flags & PANE_STYLECHANGED)
tty_style_changed (wp); 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; gc->bg = wp->cached_active_gc.bg;
else else
gc->bg = wp->cached_gc.bg; 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 void

View File

@@ -330,13 +330,13 @@ window_buffer_sort(struct sort_criteria *sort_crit)
} }
static const char* window_buffer_help_lines[] = { static const char* window_buffer_help_lines[] = {
"\r\033[1m Enter \033[0m\016x\017 \033[0mPaste selected %1\n", "#[bold] Enter #[default]#[acs]x#[default] Paste selected %1",
"\r\033[1m p \033[0m\016x\017 \033[0mPaste selected %1\n", "#[bold] p #[default]#[acs]x#[default] Paste selected %1",
"\r\033[1m P \033[0m\016x\017 \033[0mPaste tagged %1s\n", "#[bold] P #[default]#[acs]x#[default] Paste tagged %1s",
"\r\033[1m d \033[0m\016x\017 \033[0mDelete selected %1\n", "#[bold] d #[default]#[acs]x#[default] Delete selected %1",
"\r\033[1m D \033[0m\016x\017 \033[0mDelete tagged %1s\n", "#[bold] D #[default]#[acs]x#[default] Delete tagged %1s",
"\r\033[1m e \033[0m\016x\017 \033[0mOpen %1 in editor\n", "#[bold] e #[default]#[acs]x#[default] Open %1 in editor",
"\r\033[1m f \033[0m\016x\017 \033[0mEnter a filter\n", "#[bold] f #[default]#[acs]x#[default] Enter a filter",
NULL NULL
}; };

View File

@@ -369,15 +369,15 @@ window_client_sort(struct sort_criteria *sort_crit)
} }
static const char* window_client_help_lines[] = { static const char* window_client_help_lines[] = {
"\r\033[1m i \033[0m\016x\017 \033[0mToggle info view\n", "#[bold] i #[default]#[acs]x#[default] Toggle info view",
"\r\033[1m Enter \033[0m\016x\017 \033[0mChoose selected %1\n", "#[bold] Enter #[default]#[acs]x#[default] Choose selected %1",
"\r\033[1m d \033[0m\016x\017 \033[0mDetach selected %1\n", "#[bold] d #[default]#[acs]x#[default] Detach selected %1",
"\r\033[1m D \033[0m\016x\017 \033[0mDetach tagged %1s\n", "#[bold] D #[default]#[acs]x#[default] Detach tagged %1s",
"\r\033[1m x \033[0m\016x\017 \033[0mDetach selected %1\n", "#[bold] x #[default]#[acs]x#[default] Detach selected %1",
"\r\033[1m X \033[0m\016x\017 \033[0mDetach tagged %1s\n", "#[bold] X #[default]#[acs]x#[default] Detach tagged %1s",
"\r\033[1m z \033[0m\016x\017 \033[0mSuspend selected %1\n", "#[bold] z #[default]#[acs]x#[default] Suspend selected %1",
"\r\033[1m Z \033[0m\016x\017 \033[0mSuspend tagged %1s\n", "#[bold] Z #[default]#[acs]x#[default] Suspend tagged %1s",
"\r\033[1m f \033[0m\016x\017 \033[0mEnter a filter\n", "#[bold] f #[default]#[acs]x#[default] Enter a filter",
NULL NULL
}; };

View File

@@ -869,15 +869,15 @@ window_customize_height(__unused void *modedata, __unused u_int height)
} }
static const char* window_customize_help_lines[] = { static const char* window_customize_help_lines[] = {
"\r\033[1m Enter, s \033[0m\016x\017 \033[0mSet %1 value\n", "#[bold] Enter, s #[default]#[acs]x#[default] Set %1 value",
"\r\033[1m S \033[0m\016x\017 \033[0mSet global %1 value\n", "#[bold] S #[default]#[acs]x#[default] Set global %1 value",
"\r\033[1m w \033[0m\016x\017 \033[0mSet window %1 value\n", "#[bold] w #[default]#[acs]x#[default] Set window %1 value",
"\r\033[1m d \033[0m\016x\017 \033[0mSet to default value\n", "#[bold] d #[default]#[acs]x#[default] Set to default value",
"\r\033[1m D \033[0m\016x\017 \033[0mSet tagged %1s to default value\n", "#[bold] D #[default]#[acs]x#[default] Set tagged %1s to default value",
"\r\033[1m u \033[0m\016x\017 \033[0mUnset an %1\n", "#[bold] u #[default]#[acs]x#[default] Unset an %1",
"\r\033[1m U \033[0m\016x\017 \033[0mUnset tagged %1s\n", "#[bold] U #[default]#[acs]x#[default] Unset tagged %1s",
"\r\033[1m f \033[0m\016x\017 \033[0mEnter a filter\n", "#[bold] f #[default]#[acs]x#[default] Enter a filter",
"\r\033[1m v \033[0m\016x\017 \033[0mToggle information\n", "#[bold] v #[default]#[acs]x#[default] Toggle information",
NULL NULL
}; };

View File

@@ -889,18 +889,18 @@ window_tree_sort(struct sort_criteria *sort_crit)
} }
static const char* window_tree_help_lines[] = { static const char* window_tree_help_lines[] = {
"\r\033[1m Enter \033[0m\016x\017 \033[0mChoose selected item\n", "#[bold] Enter #[default]#[acs]x#[default] Choose selected item",
"\r\033[1m S-Up \033[0m\016x\017 \033[0mSwap current and previous window\n", "#[bold] S-Up #[default]#[acs]x#[default] Swap current and previous window",
"\r\033[1m S-Down \033[0m\016x\017 \033[0mSwap current and next window\n", "#[bold] S-Down #[default]#[acs]x#[default] Swap current and next window",
"\r\033[1m x \033[0m\016x\017 \033[0mKill selected item\n", "#[bold] x #[default]#[acs]x#[default] Kill selected item",
"\r\033[1m X \033[0m\016x\017 \033[0mKill tagged items\n", "#[bold] X #[default]#[acs]x#[default] Kill tagged items",
"\r\033[1m < \033[0m\016x\017 \033[0mScroll previews left\n", "#[bold] < #[default]#[acs]x#[default] Scroll previews left",
"\r\033[1m > \033[0m\016x\017 \033[0mScroll previews right\n", "#[bold] > #[default]#[acs]x#[default] Scroll previews right",
"\r\033[1m m \033[0m\016x\017 \033[0mSet the marked pane\n", "#[bold] m #[default]#[acs]x#[default] Set the marked pane",
"\r\033[1m M \033[0m\016x\017 \033[0mClear the marked pane\n", "#[bold] M #[default]#[acs]x#[default] Clear the marked pane",
"\r\033[1m : \033[0m\016x\017 \033[0mRun a command for each tagged item\n", "#[bold] : #[default]#[acs]x#[default] Run a command for each tagged item",
"\r\033[1m f \033[0m\016x\017 \033[0mEnter a format\n", "#[bold] f #[default]#[acs]x#[default] Enter a format",
"\r\033[1m H \033[0m\016x\017 \033[0mJump to the starting pane\n", "#[bold] H #[default]#[acs]x#[default] Jump to the starting pane",
NULL NULL
}; };

View File

@@ -599,6 +599,8 @@ window_redraw_active_switch(struct window *w, struct window_pane *wp)
gc2 = &wp->cached_active_gc; gc2 = &wp->cached_active_gc;
if (!grid_cells_look_equal(gc1, gc2)) if (!grid_cells_look_equal(gc1, gc2))
wp->flags |= PANE_REDRAW; wp->flags |= PANE_REDRAW;
else if (wp->cached_dim != wp->cached_active_dim)
wp->flags |= PANE_REDRAW;
else { else {
c1 = window_pane_get_palette(wp, gc1->fg); c1 = window_pane_get_palette(wp, gc1->fg);
c2 = window_pane_get_palette(wp, gc2->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); c = window_pane_get_bg_control_client(wp);
if (c == -1) { if (c == -1) {
tty_default_colours(&defaults, wp); tty_default_colours(&defaults, wp, NULL);
if (COLOUR_DEFAULT(defaults.bg)) if (COLOUR_DEFAULT(defaults.bg))
c = window_get_bg_client(wp); c = window_get_bg_client(wp);
else else

View File

@@ -105,6 +105,18 @@ xstrndup(const char *str, size_t maxlen)
return cp; 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 int
xasprintf(char **ret, const char *fmt, ...) xasprintf(char **ret, const char *fmt, ...)
{ {

View File

@@ -30,6 +30,7 @@ void *xreallocarray(void *, size_t, size_t);
void *xrecallocarray(void *, size_t, size_t, size_t); void *xrecallocarray(void *, size_t, size_t, size_t);
char *xstrdup(const char *); char *xstrdup(const char *);
char *xstrndup(const char *, size_t); char *xstrndup(const char *, size_t);
char *xmemdup(const void *, size_t);
int xasprintf(char **, const char *, ...) int xasprintf(char **, const char *, ...)
__attribute__((__format__ (printf, 2, 3))) __attribute__((__format__ (printf, 2, 3)))
__attribute__((__nonnull__ (2))); __attribute__((__nonnull__ (2)));