Merge branch 'obsd-master'

This commit is contained in:
Thomas Adam 2019-03-18 15:07:51 +00:00
commit acb2413852
20 changed files with 692 additions and 454 deletions

View File

@ -39,8 +39,8 @@ const struct cmd_entry cmd_display_message_entry = {
.name = "display-message", .name = "display-message",
.alias = "display", .alias = "display",
.args = { "c:pt:F:", 0, 1 }, .args = { "c:pt:F:v", 0, 1 },
.usage = "[-p] [-c target-client] [-F format] " .usage = "[-pv] [-c target-client] [-F format] "
CMD_TARGET_PANE_USAGE " [message]", CMD_TARGET_PANE_USAGE " [message]",
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
@ -60,6 +60,7 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
const char *template; const char *template;
char *msg; char *msg;
struct format_tree *ft; struct format_tree *ft;
int flags;
if (args_has(args, 'F') && args->argc != 0) { if (args_has(args, 'F') && args->argc != 0) {
cmdq_error(item, "only one of -F or argument must be given"); cmdq_error(item, "only one of -F or argument must be given");
@ -83,10 +84,14 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
target_c = c; target_c = c;
else else
target_c = cmd_find_best_client(s); target_c = cmd_find_best_client(s);
ft = format_create(item->client, item, FORMAT_NONE, 0); if (args_has(self->args, 'v'))
flags = FORMAT_VERBOSE;
else
flags = 0;
ft = format_create(item->client, item, FORMAT_NONE, flags);
format_defaults(ft, target_c, s, wl, wp); format_defaults(ft, target_c, s, wl, wp);
msg = format_expand_time(ft, template, 0); msg = format_expand_time(ft, template);
if (args_has(self->args, 'p')) if (args_has(self->args, 'p'))
cmdq_print(item, "%s", msg); cmdq_print(item, "%s", msg);
else if (c != NULL) else if (c != NULL)

View File

@ -1263,17 +1263,17 @@ found:
no_session: no_session:
if (~flags & CMD_FIND_QUIET) if (~flags & CMD_FIND_QUIET)
cmdq_error(item, "can't find session %s", session); cmdq_error(item, "can't find session: %s", session);
goto error; goto error;
no_window: no_window:
if (~flags & CMD_FIND_QUIET) if (~flags & CMD_FIND_QUIET)
cmdq_error(item, "can't find window %s", window); cmdq_error(item, "can't find window: %s", window);
goto error; goto error;
no_pane: no_pane:
if (~flags & CMD_FIND_QUIET) if (~flags & CMD_FIND_QUIET)
cmdq_error(item, "can't find pane %s", pane); cmdq_error(item, "can't find pane: %s", pane);
goto error; goto error;
} }
@ -1343,7 +1343,7 @@ cmd_find_client(struct cmdq_item *item, const char *target, int quiet)
/* If no client found, report an error. */ /* If no client found, report an error. */
if (c == NULL && !quiet) if (c == NULL && !quiet)
cmdq_error(item, "can't find client %s", copy); cmdq_error(item, "can't find client: %s", copy);
free(copy); free(copy);
log_debug("%s: target %s, return %p", __func__, target, c); log_debug("%s: target %s, return %p", __func__, target, c);

View File

@ -109,7 +109,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
/* Expand the command. */ /* Expand the command. */
ft = format_create(item->client, item, FORMAT_NONE, 0); ft = format_create(item->client, item, FORMAT_NONE, 0);
format_defaults(ft, c, s, wl, wp); format_defaults(ft, c, s, wl, wp);
cmd = format_expand_time(ft, args->argv[0], 0); cmd = format_expand_time(ft, args->argv[0]);
format_free(ft); format_free(ft);
/* Fork the child. */ /* Fork the child. */

View File

@ -163,11 +163,9 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
parent = options_get(oo, name); parent = options_get(oo, name);
/* Check that array options and indexes match up. */ /* Check that array options and indexes match up. */
if (idx != -1) { if (idx != -1 && (*name == '@' || !options_isarray(parent))) {
if (*name == '@' || options_array_size(parent, NULL) == -1) { cmdq_error(item, "not an array: %s", argument);
cmdq_error(item, "not an array: %s", argument); goto fail;
goto fail;
}
} }
/* With -o, check this option is not already set. */ /* With -o, check this option is not already set. */
@ -209,7 +207,7 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
goto fail; goto fail;
} }
options_set_string(oo, name, append, "%s", value); options_set_string(oo, name, append, "%s", value);
} else if (idx == -1 && options_array_size(parent, NULL) == -1) { } else if (idx == -1 && !options_isarray(parent)) {
error = cmd_set_option_set(self, item, oo, parent, value); error = cmd_set_option_set(self, item, oo, parent, value);
if (error != 0) if (error != 0)
goto fail; goto fail;
@ -264,7 +262,7 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
layout_fix_panes(w); layout_fix_panes(w);
} }
RB_FOREACH(s, sessions, &sessions) RB_FOREACH(s, sessions, &sessions)
status_update_saved(s); status_update_cache(s);
/* /*
* Update sizes and redraw. May not always be necessary but do it * Update sizes and redraw. May not always be necessary but do it

View File

@ -88,20 +88,20 @@ static void
cmd_show_options_print(struct cmd *self, struct cmdq_item *item, cmd_show_options_print(struct cmd *self, struct cmdq_item *item,
struct options_entry *o, int idx) struct options_entry *o, int idx)
{ {
const char *name; struct options_array_item *a;
const char *value; const char *name, *value;
char *tmp, *escaped; char *tmp, *escaped;
u_int size, i;
if (idx != -1) { if (idx != -1) {
xasprintf(&tmp, "%s[%d]", options_name(o), idx); xasprintf(&tmp, "%s[%d]", options_name(o), idx);
name = tmp; name = tmp;
} else { } else {
if (options_array_size(o, &size) != -1) { if (options_isarray(o)) {
for (i = 0; i < size; i++) { a = options_array_first(o);
if (options_array_get(o, i) == NULL) while (a != NULL) {
continue; idx = options_array_item_index(a);
cmd_show_options_print(self, item, o, i); cmd_show_options_print(self, item, o, idx);
a = options_array_next(a);
} }
return; return;
} }
@ -164,9 +164,10 @@ static enum cmd_retval
cmd_show_options_all(struct cmd *self, struct cmdq_item *item, cmd_show_options_all(struct cmd *self, struct cmdq_item *item,
struct options *oo) struct options *oo)
{ {
struct options_entry *o; struct options_entry *o;
const struct options_table_entry *oe; const struct options_table_entry *oe;
u_int size, idx; struct options_array_item *a;
u_int idx;
o = options_first(oo); o = options_first(oo);
while (o != NULL) { while (o != NULL) {
@ -175,13 +176,14 @@ cmd_show_options_all(struct cmd *self, struct cmdq_item *item,
o = options_next(o); o = options_next(o);
continue; continue;
} }
if (options_array_size(o, &size) == -1) if (!options_isarray(o))
cmd_show_options_print(self, item, o, -1); cmd_show_options_print(self, item, o, -1);
else { else {
for (idx = 0; idx < size; idx++) { a = options_array_first(o);
if (options_array_get(o, idx) == NULL) while (a != NULL) {
continue; idx = options_array_item_index(a);
cmd_show_options_print(self, item, o, idx); cmd_show_options_print(self, item, o, idx);
a = options_array_next(a);
} }
} }
o = options_next(o); o = options_next(o);

38
cmd.c
View File

@ -318,31 +318,31 @@ cmd_stringify_argv(int argc, char **argv)
static int static int
cmd_try_alias(int *argc, char ***argv) cmd_try_alias(int *argc, char ***argv)
{ {
struct options_entry *o; struct options_entry *o;
int old_argc = *argc, new_argc; struct options_array_item *a;
char **old_argv = *argv, **new_argv; int old_argc = *argc, new_argc, i;
u_int size, idx; char **old_argv = *argv, **new_argv;
int i; size_t wanted;
size_t wanted; const char *s, *cp = NULL;
const char *s, *cp = NULL;
o = options_get_only(global_options, "command-alias"); o = options_get_only(global_options, "command-alias");
if (o == NULL || options_array_size(o, &size) == -1 || size == 0) if (o == NULL)
return (-1); return (-1);
wanted = strlen(old_argv[0]); wanted = strlen(old_argv[0]);
for (idx = 0; idx < size; idx++) {
s = options_array_get(o, idx);
if (s == NULL)
continue;
cp = strchr(s, '='); a = options_array_first(o);
if (cp == NULL || (size_t)(cp - s) != wanted) while (a != NULL) {
continue; s = options_array_item_value(a);
if (strncmp(old_argv[0], s, wanted) == 0) if (s != NULL) {
break; cp = strchr(s, '=');
if (cp != NULL &&
(size_t)(cp - s) == wanted &&
strncmp(old_argv[0], s, wanted) == 0)
break;
}
a = options_array_next(a);
} }
if (idx == size) if (a == NULL)
return (-1); return (-1);
if (cmd_string_split(cp + 1, &new_argc, &new_argv) != 0) if (cmd_string_split(cp + 1, &new_argc, &new_argv) != 0)

View File

@ -174,22 +174,26 @@ environ_unset(struct environ *env, const char *name)
void void
environ_update(struct options *oo, struct environ *src, struct environ *dst) environ_update(struct options *oo, struct environ *src, struct environ *dst)
{ {
struct environ_entry *envent; struct environ_entry *envent;
struct options_entry *o; struct options_entry *o;
u_int size, idx; struct options_array_item *a;
const char *value; const char *value;
o = options_get(oo, "update-environment"); o = options_get(oo, "update-environment");
if (o == NULL || options_array_size(o, &size) == -1) if (o == NULL)
return; return;
for (idx = 0; idx < size; idx++) { a = options_array_first(o);
value = options_array_get(o, idx); while (a != NULL) {
if (value == NULL) value = options_array_item_value(a);
if (value == NULL) {
a = options_array_next(a);
continue; continue;
}
if ((envent = environ_find(src, value)) == NULL) if ((envent = environ_find(src, value)) == NULL)
environ_clear(dst, value); environ_clear(dst, value);
else else
environ_set(dst, envent->name, "%s", envent->value); environ_set(dst, envent->name, "%s", envent->value);
a = options_array_next(a);
} }
} }

238
format.c
View File

@ -100,6 +100,9 @@ format_job_cmp(struct format_job *fj1, struct format_job *fj2)
#define FORMAT_WINDOWS 0x100 #define FORMAT_WINDOWS 0x100
#define FORMAT_PANES 0x200 #define FORMAT_PANES 0x200
/* Limit on recursion. */
#define FORMAT_LOOP_LIMIT 10
/* Entry in format tree. */ /* Entry in format tree. */
struct format_entry { struct format_entry {
char *key; char *key;
@ -121,13 +124,15 @@ struct format_tree {
struct client *client; struct client *client;
u_int tag; u_int tag;
int flags; int flags;
time_t time;
u_int loop;
RB_HEAD(format_entry_tree, format_entry) tree; RB_HEAD(format_entry_tree, format_entry) tree;
}; };
static int format_entry_cmp(struct format_entry *, struct format_entry *); static int format_entry_cmp(struct format_entry *, struct format_entry *);
RB_GENERATE_STATIC(format_entry_tree, format_entry, entry, format_entry_cmp); RB_GENERATE_STATIC(format_entry_tree, format_entry, entry, format_entry_cmp);
/* Format modifiers. */ /* Format modifier. */
struct format_modifier { struct format_modifier {
char modifier[3]; char modifier[3];
u_int size; u_int size;
@ -203,6 +208,36 @@ static const char *format_lower[] = {
NULL /* z */ NULL /* z */
}; };
/* Is logging enabled? */
static inline int
format_logging(struct format_tree *ft)
{
return (log_get_level() != 0 || (ft->flags & FORMAT_VERBOSE));
}
/* Log a message if verbose. */
static void printflike(3, 4)
format_log1(struct format_tree *ft, const char *from, const char *fmt, ...)
{
va_list ap;
char *s;
static const char spaces[] = " ";
if (!format_logging(ft))
return;
va_start(ap, fmt);
vasprintf(&s, fmt, ap);
va_end(ap);
log_debug("%s: %s", from, s);
if (ft->item != NULL && (ft->flags & FORMAT_VERBOSE))
cmdq_print(ft->item, "#%.*s%s", ft->loop, spaces, s);
free(s);
}
#define format_log(ft, fmt, ...) format_log1(ft, __func__, fmt, ##__VA_ARGS__)
/* Format job update callback. */ /* Format job update callback. */
static void static void
format_job_update(struct job *job) format_job_update(struct job *job)
@ -311,7 +346,9 @@ format_job_get(struct format_tree *ft, const char *cmd)
force = (ft->flags & FORMAT_FORCE); force = (ft->flags & FORMAT_FORCE);
t = time(NULL); t = time(NULL);
if (fj->job == NULL && (force || fj->last != t)) { if (force && fj->job != NULL)
job_free(fj->job);
if (force || (fj->job == NULL && fj->last != t)) {
fj->job = job_run(expanded, NULL, fj->job = job_run(expanded, NULL,
server_client_get_cwd(ft->client, NULL), format_job_update, server_client_get_cwd(ft->client, NULL), format_job_update,
format_job_complete, NULL, fj, JOB_NOWAIT); format_job_complete, NULL, fj, JOB_NOWAIT);
@ -697,6 +734,7 @@ format_create(struct client *c, struct cmdq_item *item, int tag, int flags)
ft->tag = tag; ft->tag = tag;
ft->flags = flags; ft->flags = flags;
ft->time = time(NULL);
format_add(ft, "version", "%s", VERSION); format_add(ft, "version", "%s", VERSION);
format_add_cb(ft, "host", format_cb_host); format_add_cb(ft, "host", format_cb_host);
@ -1154,7 +1192,9 @@ format_substitute(const char *source, const char *from, const char *to)
static char * static char *
format_loop_sessions(struct format_tree *ft, const char *fmt) format_loop_sessions(struct format_tree *ft, const char *fmt)
{ {
struct client *c = ft->client;
struct cmdq_item *item = ft->item; struct cmdq_item *item = ft->item;
struct format_tree *nft;
char *expanded, *value; char *expanded, *value;
size_t valuelen; size_t valuelen;
struct session *s; struct session *s;
@ -1163,7 +1203,12 @@ format_loop_sessions(struct format_tree *ft, const char *fmt)
valuelen = 1; valuelen = 1;
RB_FOREACH(s, sessions, &sessions) { RB_FOREACH(s, sessions, &sessions) {
expanded = format_single(item, fmt, ft->c, ft->s, NULL, NULL); format_log(ft, "session loop: $%u", s->id);
nft = format_create(c, item, FORMAT_NONE, ft->flags);
nft->loop = ft->loop;
format_defaults(nft, ft->c, s, NULL, NULL);
expanded = format_expand(nft, fmt);
format_free(nft);
valuelen += strlen(expanded); valuelen += strlen(expanded);
value = xrealloc(value, valuelen); value = xrealloc(value, valuelen);
@ -1179,13 +1224,18 @@ format_loop_sessions(struct format_tree *ft, const char *fmt)
static char * static char *
format_loop_windows(struct format_tree *ft, const char *fmt) format_loop_windows(struct format_tree *ft, const char *fmt)
{ {
struct client *c = ft->client;
struct cmdq_item *item = ft->item; struct cmdq_item *item = ft->item;
struct format_tree *nft;
char *all, *active, *use, *expanded, *value; char *all, *active, *use, *expanded, *value;
size_t valuelen; size_t valuelen;
struct winlink *wl; struct winlink *wl;
struct window *w;
if (ft->s == NULL) if (ft->s == NULL) {
format_log(ft, "window loop but no session");
return (NULL); return (NULL);
}
if (format_choose(ft, fmt, &all, &active, 0) != 0) { if (format_choose(ft, fmt, &all, &active, 0) != 0) {
all = xstrdup(fmt); all = xstrdup(fmt);
@ -1196,11 +1246,17 @@ format_loop_windows(struct format_tree *ft, const char *fmt)
valuelen = 1; valuelen = 1;
RB_FOREACH(wl, winlinks, &ft->s->windows) { RB_FOREACH(wl, winlinks, &ft->s->windows) {
w = wl->window;
format_log(ft, "window loop: %u @%u", wl->idx, w->id);
if (active != NULL && wl == ft->s->curw) if (active != NULL && wl == ft->s->curw)
use = active; use = active;
else else
use = all; use = all;
expanded = format_single(item, use, ft->c, ft->s, wl, NULL); nft = format_create(c, item, FORMAT_WINDOW|w->id, ft->flags);
nft->loop = ft->loop;
format_defaults(nft, ft->c, ft->s, wl, NULL);
expanded = format_expand(nft, use);
format_free(nft);
valuelen += strlen(expanded); valuelen += strlen(expanded);
value = xrealloc(value, valuelen); value = xrealloc(value, valuelen);
@ -1219,13 +1275,17 @@ format_loop_windows(struct format_tree *ft, const char *fmt)
static char * static char *
format_loop_panes(struct format_tree *ft, const char *fmt) format_loop_panes(struct format_tree *ft, const char *fmt)
{ {
struct client *c = ft->client;
struct cmdq_item *item = ft->item; struct cmdq_item *item = ft->item;
struct format_tree *nft;
char *all, *active, *use, *expanded, *value; char *all, *active, *use, *expanded, *value;
size_t valuelen; size_t valuelen;
struct window_pane *wp; struct window_pane *wp;
if (ft->w == NULL) if (ft->w == NULL) {
format_log(ft, "pane loop but no window");
return (NULL); return (NULL);
}
if (format_choose(ft, fmt, &all, &active, 0) != 0) { if (format_choose(ft, fmt, &all, &active, 0) != 0) {
all = xstrdup(fmt); all = xstrdup(fmt);
@ -1236,11 +1296,16 @@ format_loop_panes(struct format_tree *ft, const char *fmt)
valuelen = 1; valuelen = 1;
TAILQ_FOREACH(wp, &ft->w->panes, entry) { TAILQ_FOREACH(wp, &ft->w->panes, entry) {
format_log(ft, "pane loop: %%%u", wp->id);
if (active != NULL && wp == ft->w->active) if (active != NULL && wp == ft->w->active)
use = active; use = active;
else else
use = all; use = all;
expanded = format_single(item, use, ft->c, ft->s, ft->wl, wp); nft = format_create(c, item, FORMAT_PANE|wp->id, ft->flags);
nft->loop = ft->loop;
format_defaults(nft, ft->c, ft->s, ft->wl, wp);
expanded = format_expand(nft, use);
format_free(nft);
valuelen += strlen(expanded); valuelen += strlen(expanded);
value = xrealloc(value, valuelen); value = xrealloc(value, valuelen);
@ -1264,25 +1329,27 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
const char *errptr, *copy, *cp; const char *errptr, *copy, *cp;
char *copy0, *condition, *found, *new; char *copy0, *condition, *found, *new;
char *value, *left, *right; char *value, *left, *right;
char tmp[64];
size_t valuelen; size_t valuelen;
int modifiers = 0, limit = 0; int modifiers = 0, limit = 0;
struct format_modifier *list, *fm, *cmp = NULL, *search = NULL; struct format_modifier *list, *fm, *cmp = NULL, *search = NULL;
struct format_modifier *sub = NULL; struct format_modifier *sub = NULL;
u_int i, count; u_int i, count;
int j;
/* Make a copy of the key. */ /* Make a copy of the key. */
copy = copy0 = xstrndup(key, keylen); copy = copy0 = xstrndup(key, keylen);
log_debug("%s: format = '%s'", __func__, copy);
/* Process modifier list. */ /* Process modifier list. */
list = format_build_modifiers(ft, &copy, &count); list = format_build_modifiers(ft, &copy, &count);
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
xsnprintf(tmp, sizeof tmp, "%s: modifier %u", __func__, i);
log_debug("%s = %s", tmp, list[i].modifier);
cmd_log_argv(list[i].argc, list[i].argv, tmp);
fm = &list[i]; fm = &list[i];
if (format_logging(ft)) {
format_log(ft, "modifier %u is %s", i, fm->modifier);
for (j = 0; j < fm->argc; j++) {
format_log(ft, "modifier %u argument %d: %s", i,
j, fm->argv[j]);
}
}
if (fm->size == 1) { if (fm->size == 1) {
switch (fm->modifier[0]) { switch (fm->modifier[0]) {
case 'm': case 'm':
@ -1365,14 +1432,22 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
goto fail; goto fail;
} else if (search != NULL) { } else if (search != NULL) {
/* Search in pane. */ /* Search in pane. */
if (wp == NULL) if (wp == NULL) {
format_log(ft, "search '%s' but no pane", copy);
value = xstrdup("0"); value = xstrdup("0");
else } else {
format_log(ft, "search '%s' pane %%%u", copy, wp->id);
xasprintf(&value, "%u", window_pane_search(wp, copy)); xasprintf(&value, "%u", window_pane_search(wp, copy));
}
} else if (cmp != NULL) { } else if (cmp != NULL) {
/* Comparison of left and right. */ /* Comparison of left and right. */
if (format_choose(ft, copy, &left, &right, 1) != 0) if (format_choose(ft, copy, &left, &right, 1) != 0) {
format_log(ft, "compare %s syntax error: %s",
cmp->modifier, copy);
goto fail; goto fail;
}
format_log(ft, "compare %s left is: %s", cmp->modifier, left);
format_log(ft, "compare %s right is: %s", cmp->modifier, right);
if (strcmp(cmp->modifier, "||") == 0) { if (strcmp(cmp->modifier, "||") == 0) {
if (format_true(left) || format_true(right)) if (format_true(left) || format_true(right))
@ -1407,9 +1482,12 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
} else if (*copy == '?') { } else if (*copy == '?') {
/* Conditional: check first and choose second or third. */ /* Conditional: check first and choose second or third. */
cp = format_skip(copy + 1, ","); cp = format_skip(copy + 1, ",");
if (cp == NULL) if (cp == NULL) {
format_log(ft, "condition syntax error: %s", copy + 1);
goto fail; goto fail;
}
condition = xstrndup(copy + 1, cp - (copy + 1)); condition = xstrndup(copy + 1, cp - (copy + 1));
format_log(ft, "condition is: %s", condition);
found = format_find(ft, condition, modifiers); found = format_find(ft, condition, modifiers);
if (found == NULL) { if (found == NULL) {
@ -1422,27 +1500,42 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
if (strcmp(found, condition) == 0) { if (strcmp(found, condition) == 0) {
free(found); free(found);
found = xstrdup(""); found = xstrdup("");
format_log(ft, "condition '%s' found: %s",
condition, found);
} else {
format_log(ft,
"condition '%s' not found; assuming false",
condition);
} }
} } else
free(condition); format_log(ft, "condition '%s' found", condition);
if (format_choose(ft, cp + 1, &left, &right, 0) != 0) { if (format_choose(ft, cp + 1, &left, &right, 0) != 0) {
format_log(ft, "condition '%s' syntax error: %s",
condition, cp + 1);
free(found); free(found);
goto fail; goto fail;
} }
if (format_true(found)) if (format_true(found)) {
format_log(ft, "condition '%s' is true", condition);
value = format_expand(ft, left); value = format_expand(ft, left);
else } else {
format_log(ft, "condition '%s' is false", condition);
value = format_expand(ft, right); value = format_expand(ft, right);
}
free(right); free(right);
free(left); free(left);
free(condition);
free(found); free(found);
} else { } else {
/* Neither: look up directly. */ /* Neither: look up directly. */
value = format_find(ft, copy, modifiers); value = format_find(ft, copy, modifiers);
if (value == NULL) if (value == NULL) {
format_log(ft, "format '%s' not found", copy);
value = xstrdup(""); value = xstrdup("");
} else
format_log(ft, "format '%s' found: %s", copy, value);
} }
done: done:
@ -1453,7 +1546,7 @@ done:
value = new; value = new;
} }
else if (modifiers & FORMAT_EXPANDTIME) { else if (modifiers & FORMAT_EXPANDTIME) {
new = format_expand_time(ft, value, 0); new = format_expand_time(ft, value);
free(value); free(value);
value = new; value = new;
} }
@ -1461,6 +1554,8 @@ done:
/* Perform substitution if any. */ /* Perform substitution if any. */
if (sub != NULL) { if (sub != NULL) {
new = format_substitute(value, sub->argv[0], sub->argv[1]); new = format_substitute(value, sub->argv[0], sub->argv[1]);
format_log(ft, "substituted '%s' to '%s: %s", sub->argv[0],
sub->argv[1], new);
free(value); free(value);
value = new; value = new;
} }
@ -1468,16 +1563,17 @@ done:
/* Truncate the value if needed. */ /* Truncate the value if needed. */
if (limit > 0) { if (limit > 0) {
new = utf8_trimcstr(value, limit); new = utf8_trimcstr(value, limit);
format_log(ft, "applied length limit %d: %s", limit, new);
free(value); free(value);
value = new; value = new;
} else if (limit < 0) { } else if (limit < 0) {
new = utf8_rtrimcstr(value, -limit); new = utf8_rtrimcstr(value, -limit);
format_log(ft, "applied length limit %d: %s", limit, new);
free(value); free(value);
value = new; value = new;
} }
/* Expand the buffer and copy in the value. */ /* Expand the buffer and copy in the value. */
log_debug("%s: '%s' -> '%s'", __func__, copy0, value);
valuelen = strlen(value); valuelen = strlen(value);
while (*len - *off < valuelen + 1) { while (*len - *off < valuelen + 1) {
*buf = xreallocarray(*buf, 2, *len); *buf = xreallocarray(*buf, 2, *len);
@ -1486,48 +1582,50 @@ done:
memcpy(*buf + *off, value, valuelen); memcpy(*buf + *off, value, valuelen);
*off += valuelen; *off += valuelen;
format_log(ft, "replaced '%s' with '%s'", copy0, value);
free(value); free(value);
format_free_modifiers(list, count); format_free_modifiers(list, count);
free(copy0); free(copy0);
return (0); return (0);
fail: fail:
format_log(ft, "failed %s", copy0);
format_free_modifiers(list, count); format_free_modifiers(list, count);
free(copy0); free(copy0);
return (-1); return (-1);
} }
/* Expand keys in a template, passing through strftime first. */ /* Expand keys in a template. */
char * static char *
format_expand_time(struct format_tree *ft, const char *fmt, time_t t) format_expand1(struct format_tree *ft, const char *fmt, int time)
{ {
char *buf, *out, *name;
const char *ptr, *s;
size_t off, len, n, outlen;
int ch, brackets;
struct tm *tm; struct tm *tm;
char s[2048]; char expanded[8192];
if (fmt == NULL || *fmt == '\0') if (fmt == NULL || *fmt == '\0')
return (xstrdup("")); return (xstrdup(""));
if (t == 0) if (ft->loop == FORMAT_LOOP_LIMIT)
t = time(NULL);
tm = localtime(&t);
if (strftime(s, sizeof s, fmt, tm) == 0)
return (xstrdup("")); return (xstrdup(""));
ft->loop++;
return (format_expand(ft, s)); format_log(ft, "expanding format: %s", fmt);
}
/* Expand keys in a template. */ if (time) {
char * tm = localtime(&ft->time);
format_expand(struct format_tree *ft, const char *fmt) if (strftime(expanded, sizeof expanded, fmt, tm) == 0) {
{ format_log(ft, "format is too long");
char *buf, *out, *name; return (xstrdup(""));
const char *ptr, *s, *saved = fmt; }
size_t off, len, n, outlen; if (format_logging(ft) && strcmp(expanded, fmt) != 0)
int ch, brackets; format_log(ft, "after time expanded: %s", expanded);
fmt = expanded;
if (fmt == NULL) }
return (xstrdup(""));
len = 64; len = 64;
buf = xmalloc(len); buf = xmalloc(len);
@ -1544,7 +1642,7 @@ format_expand(struct format_tree *ft, const char *fmt)
} }
fmt++; fmt++;
ch = (u_char) *fmt++; ch = (u_char)*fmt++;
switch (ch) { switch (ch) {
case '(': case '(':
brackets = 1; brackets = 1;
@ -1558,15 +1656,19 @@ format_expand(struct format_tree *ft, const char *fmt)
break; break;
n = ptr - fmt; n = ptr - fmt;
if (ft->flags & FORMAT_NOJOBS) name = xstrndup(fmt, n);
out = xstrdup(""); format_log(ft, "found #(): %s", name);
else {
name = xstrndup(fmt, n);
out = format_job_get(ft, name);
free(name);
}
outlen = strlen(out);
if (ft->flags & FORMAT_NOJOBS) {
out = xstrdup("");
format_log(ft, "#() is disabled");
} else {
out = format_job_get(ft, name);
format_log(ft, "#() result: %s", out);
}
free(name);
outlen = strlen(out);
while (len - off < outlen + 1) { while (len - off < outlen + 1) {
buf = xreallocarray(buf, 2, len); buf = xreallocarray(buf, 2, len);
len *= 2; len *= 2;
@ -1584,6 +1686,7 @@ format_expand(struct format_tree *ft, const char *fmt)
break; break;
n = ptr - fmt; n = ptr - fmt;
format_log(ft, "found #{}: %.*s", (int)n, fmt);
if (format_replace(ft, fmt, n, &buf, &len, &off) != 0) if (format_replace(ft, fmt, n, &buf, &len, &off) != 0)
break; break;
fmt += n + 1; fmt += n + 1;
@ -1591,6 +1694,7 @@ format_expand(struct format_tree *ft, const char *fmt)
case '}': case '}':
case '#': case '#':
case ',': case ',':
format_log(ft, "found #%c", ch);
while (len - off < 2) { while (len - off < 2) {
buf = xreallocarray(buf, 2, len); buf = xreallocarray(buf, 2, len);
len *= 2; len *= 2;
@ -1613,6 +1717,7 @@ format_expand(struct format_tree *ft, const char *fmt)
continue; continue;
} }
n = strlen(s); n = strlen(s);
format_log(ft, "found #%c: %s", ch, s);
if (format_replace(ft, s, n, &buf, &len, &off) != 0) if (format_replace(ft, s, n, &buf, &len, &off) != 0)
break; break;
continue; continue;
@ -1622,10 +1727,26 @@ format_expand(struct format_tree *ft, const char *fmt)
} }
buf[off] = '\0'; buf[off] = '\0';
log_debug("%s: '%s' -> '%s'", __func__, saved, buf); format_log(ft, "result is: %s", buf);
ft->loop--;
return (buf); return (buf);
} }
/* Expand keys in a template, passing through strftime first. */
char *
format_expand_time(struct format_tree *ft, const char *fmt)
{
return (format_expand1(ft, fmt, 1));
}
/* Expand keys in a template. */
char *
format_expand(struct format_tree *ft, const char *fmt)
{
return (format_expand1(ft, fmt, 0));
}
/* Expand a single string. */ /* Expand a single string. */
char * char *
format_single(struct cmdq_item *item, const char *fmt, struct client *c, format_single(struct cmdq_item *item, const char *fmt, struct client *c,
@ -1813,6 +1934,11 @@ format_defaults_winlink(struct format_tree *ft, struct winlink *wl)
format_add(ft, "window_flags", "%s", window_printable_flags(wl)); format_add(ft, "window_flags", "%s", window_printable_flags(wl));
format_add(ft, "window_active", "%d", wl == s->curw); format_add(ft, "window_active", "%d", wl == s->curw);
format_add(ft, "window_start_flag", "%d",
!!(wl == RB_MIN(winlinks, &s->windows)));
format_add(ft, "window_end_flag", "%d",
!!(wl == RB_MAX(winlinks, &s->windows)));
format_add(ft, "window_bell_flag", "%d", format_add(ft, "window_bell_flag", "%d",
!!(wl->flags & WINLINK_BELL)); !!(wl->flags & WINLINK_BELL));
format_add(ft, "window_activity_flag", "%d", format_add(ft, "window_activity_flag", "%d",

175
options.c
View File

@ -30,6 +30,23 @@
* a red-black tree. * a red-black tree.
*/ */
struct options_array_item {
u_int index;
char *value;
RB_ENTRY(options_array_item) entry;
};
RB_HEAD(options_array, options_array_item);
static int
options_array_cmp(struct options_array_item *a1, struct options_array_item *a2)
{
if (a1->index < a2->index)
return (-1);
if (a1->index > a2->index)
return (1);
return (0);
}
RB_GENERATE_STATIC(options_array, options_array_item, entry, options_array_cmp);
struct options_entry { struct options_entry {
struct options *owner; struct options *owner;
@ -40,10 +57,7 @@ struct options_entry {
char *string; char *string;
long long number; long long number;
struct style style; struct style style;
struct { struct options_array array;
const char **array;
u_int arraysize;
};
}; };
RB_ENTRY(options_entry) entry; RB_ENTRY(options_entry) entry;
@ -56,8 +70,6 @@ struct options {
static struct options_entry *options_add(struct options *, const char *); static struct options_entry *options_add(struct options *, const char *);
#define OPTIONS_ARRAY_LIMIT 1000
#define OPTIONS_IS_STRING(o) \ #define OPTIONS_IS_STRING(o) \
((o)->tableentry == NULL || \ ((o)->tableentry == NULL || \
(o)->tableentry->type == OPTIONS_TABLE_STRING) (o)->tableentry->type == OPTIONS_TABLE_STRING)
@ -163,18 +175,26 @@ options_empty(struct options *oo, const struct options_table_entry *oe)
o = options_add(oo, oe->name); o = options_add(oo, oe->name);
o->tableentry = oe; o->tableentry = oe;
if (oe->type == OPTIONS_TABLE_ARRAY)
RB_INIT(&o->array);
return (o); return (o);
} }
struct options_entry * struct options_entry *
options_default(struct options *oo, const struct options_table_entry *oe) options_default(struct options *oo, const struct options_table_entry *oe)
{ {
struct options_entry *o; struct options_entry *o;
u_int i;
o = options_empty(oo, oe); o = options_empty(oo, oe);
if (oe->type == OPTIONS_TABLE_ARRAY) if (oe->type == OPTIONS_TABLE_ARRAY) {
options_array_assign(o, oe->default_str); if (oe->default_arr != NULL) {
else if (oe->type == OPTIONS_TABLE_STRING) for (i = 0; oe->default_arr[i] != NULL; i++)
options_array_set(o, i, oe->default_arr[i], 0);
} else
options_array_assign(o, oe->default_str);
} else if (oe->type == OPTIONS_TABLE_STRING)
o->string = xstrdup(oe->default_str); o->string = xstrdup(oe->default_str);
else if (oe->type == OPTIONS_TABLE_STYLE) { else if (oe->type == OPTIONS_TABLE_STYLE) {
style_set(&o->style, &grid_default_cell); style_set(&o->style, &grid_default_cell);
@ -205,15 +225,11 @@ void
options_remove(struct options_entry *o) options_remove(struct options_entry *o)
{ {
struct options *oo = o->owner; struct options *oo = o->owner;
u_int i;
if (OPTIONS_IS_STRING(o)) if (OPTIONS_IS_STRING(o))
free((void *)o->string); free(o->string);
else if (OPTIONS_IS_ARRAY(o)) { else if (OPTIONS_IS_ARRAY(o))
for (i = 0; i < o->arraysize; i++) options_array_clear(o);
free((void *)o->array[i]);
free(o->array);
}
RB_REMOVE(options_tree, &oo->tree, o); RB_REMOVE(options_tree, &oo->tree, o);
free(o); free(o);
@ -231,62 +247,79 @@ options_table_entry(struct options_entry *o)
return (o->tableentry); return (o->tableentry);
} }
static struct options_array_item *
options_array_item(struct options_entry *o, u_int idx)
{
struct options_array_item a;
a.index = idx;
return (RB_FIND(options_array, &o->array, &a));
}
static void
options_array_free(struct options_entry *o, struct options_array_item *a)
{
free(a->value);
RB_REMOVE(options_array, &o->array, a);
free(a);
}
void void
options_array_clear(struct options_entry *o) options_array_clear(struct options_entry *o)
{ {
if (OPTIONS_IS_ARRAY(o)) struct options_array_item *a, *a1;
o->arraysize = 0;
if (!OPTIONS_IS_ARRAY(o))
return;
RB_FOREACH_SAFE(a, options_array, &o->array, a1)
options_array_free(o, a);
} }
const char * const char *
options_array_get(struct options_entry *o, u_int idx) options_array_get(struct options_entry *o, u_int idx)
{ {
struct options_array_item *a;
if (!OPTIONS_IS_ARRAY(o)) if (!OPTIONS_IS_ARRAY(o))
return (NULL); return (NULL);
if (idx >= o->arraysize) a = options_array_item(o, idx);
if (a == NULL)
return (NULL); return (NULL);
return (o->array[idx]); return (a->value);
} }
int int
options_array_set(struct options_entry *o, u_int idx, const char *value, options_array_set(struct options_entry *o, u_int idx, const char *value,
int append) int append)
{ {
char *new; struct options_array_item *a;
u_int i; char *new;
if (!OPTIONS_IS_ARRAY(o)) if (!OPTIONS_IS_ARRAY(o))
return (-1); return (-1);
if (idx >= OPTIONS_ARRAY_LIMIT) a = options_array_item(o, idx);
return (-1); if (value == NULL) {
if (idx >= o->arraysize) { if (a != NULL)
o->array = xreallocarray(o->array, idx + 1, sizeof *o->array); options_array_free(o, a);
for (i = o->arraysize; i < idx + 1; i++) return (0);
o->array[i] = NULL;
o->arraysize = idx + 1;
} }
new = NULL; if (a == NULL) {
if (value != NULL) { a = xcalloc(1, sizeof *a);
if (o->array[idx] != NULL && append) a->index = idx;
xasprintf(&new, "%s%s", o->array[idx], value); a->value = xstrdup(value);
RB_INSERT(options_array, &o->array, a);
} else {
free(a->value);
if (a != NULL && append)
xasprintf(&new, "%s%s", a->value, value);
else else
new = xstrdup(value); new = xstrdup(value);
a->value = new;
} }
free((void *)o->array[idx]);
o->array[idx] = new;
return (0);
}
int
options_array_size(struct options_entry *o, u_int *size)
{
if (!OPTIONS_IS_ARRAY(o))
return (-1);
if (size != NULL)
*size = o->arraysize;
return (0); return (0);
} }
@ -305,37 +338,69 @@ options_array_assign(struct options_entry *o, const char *s)
while ((next = strsep(&string, separator)) != NULL) { while ((next = strsep(&string, separator)) != NULL) {
if (*next == '\0') if (*next == '\0')
continue; continue;
for (i = 0; i < OPTIONS_ARRAY_LIMIT; i++) { for (i = 0; i < UINT_MAX; i++) {
if (i >= o->arraysize || o->array[i] == NULL) if (options_array_item(o, i) == NULL)
break; break;
} }
if (i == OPTIONS_ARRAY_LIMIT) if (i == UINT_MAX)
break; break;
options_array_set(o, i, next, 0); options_array_set(o, i, next, 0);
} }
free(copy); free(copy);
} }
struct options_array_item *
options_array_first(struct options_entry *o)
{
if (!OPTIONS_IS_ARRAY(o))
return (NULL);
return (RB_MIN(options_array, &o->array));
}
struct options_array_item *
options_array_next(struct options_array_item *a)
{
return (RB_NEXT(options_array, &o->array, a));
}
u_int
options_array_item_index(struct options_array_item *a)
{
return (a->index);
}
const char *
options_array_item_value(struct options_array_item *a)
{
return (a->value);
}
int
options_isarray(struct options_entry *o)
{
return (OPTIONS_IS_ARRAY(o));
}
int int
options_isstring(struct options_entry *o) options_isstring(struct options_entry *o)
{ {
if (o->tableentry == NULL)
return (1);
return (OPTIONS_IS_STRING(o) || OPTIONS_IS_ARRAY(o)); return (OPTIONS_IS_STRING(o) || OPTIONS_IS_ARRAY(o));
} }
const char * const char *
options_tostring(struct options_entry *o, int idx, int numeric) options_tostring(struct options_entry *o, int idx, int numeric)
{ {
static char s[1024]; static char s[1024];
const char *tmp; const char *tmp;
struct options_array_item *a;
if (OPTIONS_IS_ARRAY(o)) { if (OPTIONS_IS_ARRAY(o)) {
if (idx == -1) if (idx == -1)
return (NULL); return (NULL);
if ((u_int)idx >= o->arraysize || o->array[idx] == NULL) a = options_array_item(o, idx);
if (a == NULL)
return (""); return ("");
return (o->array[idx]); return (a->value);
} }
if (OPTIONS_IS_STYLE(o)) if (OPTIONS_IS_STYLE(o))
return (style_tostring(&o->style)); return (style_tostring(&o->style));

View File

@ -162,7 +162,7 @@ recalculate_sizes(void)
*/ */
RB_FOREACH(s, sessions, &sessions) { RB_FOREACH(s, sessions, &sessions) {
s->attached = 0; s->attached = 0;
status_update_saved(s); status_update_cache(s);
} }
/* /*

View File

@ -569,7 +569,7 @@ screen_redraw_draw_status(struct screen_redraw_ctx *ctx)
struct client *c = ctx->c; struct client *c = ctx->c;
struct window *w = c->session->curw->window; struct window *w = c->session->curw->window;
struct tty *tty = &c->tty; struct tty *tty = &c->tty;
struct screen *s = &c->status.status; struct screen *s = c->status.active;
u_int i, y; u_int i, y;
log_debug("%s: %s @%u", __func__, c->name, w->id); log_debug("%s: %s @%u", __func__, c->name, w->id);

View File

@ -202,7 +202,7 @@ server_client_create(int fd)
c->tty.sx = 80; c->tty.sx = 80;
c->tty.sy = 24; c->tty.sy = 24;
screen_init(&c->status.status, c->tty.sx, 1, 0); status_init(c);
c->message_string = NULL; c->message_string = NULL;
TAILQ_INIT(&c->message_log); TAILQ_INIT(&c->message_log);
@ -279,13 +279,7 @@ server_client_lost(struct client *c)
if (c->stderr_data != c->stdout_data) if (c->stderr_data != c->stdout_data)
evbuffer_free(c->stderr_data); evbuffer_free(c->stderr_data);
if (event_initialized(&c->status.timer)) status_free(c);
evtimer_del(&c->status.timer);
screen_free(&c->status.status);
if (c->status.old_status != NULL) {
screen_free(c->status.old_status);
free(c->status.old_status);
}
free(c->title); free(c->title);
free((void *)c->cwd); free((void *)c->cwd);
@ -1547,7 +1541,7 @@ server_client_set_title(struct client *c)
ft = format_create(c, NULL, FORMAT_NONE, 0); ft = format_create(c, NULL, FORMAT_NONE, 0);
format_defaults(ft, c, NULL, NULL, NULL); format_defaults(ft, c, NULL, NULL, NULL);
title = format_expand_time(ft, template, 0); title = format_expand_time(ft, template);
if (c->title == NULL || strcmp(title, c->title) != 0) { if (c->title == NULL || strcmp(title, c->title) != 0) {
free(c->title); free(c->title);
c->title = xstrdup(title); c->title = xstrdup(title);

View File

@ -135,7 +135,7 @@ session_create(const char *prefix, const char *name, int argc, char **argv,
s->options = oo; s->options = oo;
s->hooks = hooks_create(global_hooks); s->hooks = hooks_create(global_hooks);
status_update_saved(s); status_update_cache(s);
s->tio = NULL; s->tio = NULL;
if (tio != NULL) { if (tio != NULL) {

237
status.c
View File

@ -29,14 +29,14 @@
#include "tmux.h" #include "tmux.h"
static char *status_redraw_get_left(struct client *, time_t, static char *status_redraw_get_left(struct client *, struct grid_cell *,
struct grid_cell *, size_t *); size_t *);
static char *status_redraw_get_right(struct client *, time_t, static char *status_redraw_get_right(struct client *, struct grid_cell *,
struct grid_cell *, size_t *); size_t *);
static char *status_print(struct client *, struct winlink *, time_t, static char *status_print(struct client *, struct winlink *,
struct grid_cell *); struct grid_cell *);
static char *status_replace(struct client *, struct winlink *, const char *, static char *status_replace(struct client *, struct winlink *,
time_t); const char *);
static void status_message_callback(int, short, void *); static void status_message_callback(int, short, void *);
static void status_timer_callback(int, short, void *); static void status_timer_callback(int, short, void *);
@ -194,7 +194,7 @@ status_timer_start_all(void)
/* Update status cache. */ /* Update status cache. */
void void
status_update_saved(struct session *s) status_update_cache(struct session *s)
{ {
if (!options_get_number(s->options, "status")) if (!options_get_number(s->options, "status"))
s->statusat = -1; s->statusat = -1;
@ -232,8 +232,7 @@ status_line_size(struct client *c)
/* Retrieve options for left string. */ /* Retrieve options for left string. */
static char * static char *
status_redraw_get_left(struct client *c, time_t t, struct grid_cell *gc, status_redraw_get_left(struct client *c, struct grid_cell *gc, size_t *size)
size_t *size)
{ {
struct session *s = c->session; struct session *s = c->session;
const char *template; const char *template;
@ -243,7 +242,7 @@ status_redraw_get_left(struct client *c, time_t t, struct grid_cell *gc,
style_apply_update(gc, s->options, "status-left-style"); style_apply_update(gc, s->options, "status-left-style");
template = options_get_string(s->options, "status-left"); template = options_get_string(s->options, "status-left");
left = status_replace(c, NULL, template, t); left = status_replace(c, NULL, template);
*size = options_get_number(s->options, "status-left-length"); *size = options_get_number(s->options, "status-left-length");
leftlen = screen_write_cstrlen("%s", left); leftlen = screen_write_cstrlen("%s", left);
@ -254,8 +253,7 @@ status_redraw_get_left(struct client *c, time_t t, struct grid_cell *gc,
/* Retrieve options for right string. */ /* Retrieve options for right string. */
static char * static char *
status_redraw_get_right(struct client *c, time_t t, struct grid_cell *gc, status_redraw_get_right(struct client *c, struct grid_cell *gc, size_t *size)
size_t *size)
{ {
struct session *s = c->session; struct session *s = c->session;
const char *template; const char *template;
@ -265,7 +263,7 @@ status_redraw_get_right(struct client *c, time_t t, struct grid_cell *gc,
style_apply_update(gc, s->options, "status-right-style"); style_apply_update(gc, s->options, "status-right-style");
template = options_get_string(s->options, "status-right"); template = options_get_string(s->options, "status-right");
right = status_replace(c, NULL, template, t); right = status_replace(c, NULL, template);
*size = options_get_number(s->options, "status-right-length"); *size = options_get_number(s->options, "status-right-length");
rightlen = screen_write_cstrlen("%s", right); rightlen = screen_write_cstrlen("%s", right);
@ -298,17 +296,69 @@ status_get_window_at(struct client *c, u_int x)
return (NULL); return (NULL);
} }
/* Draw status for client on the last lines of given context. */ /* Save old status line. */
static void
status_push_screen(struct client *c)
{
struct status_line *sl = &c->status;
if (sl->active == &sl->screen) {
sl->active = xmalloc(sizeof *sl->active);
screen_init(sl->active, c->tty.sx, status_line_size(c), 0);
}
sl->references++;
}
/* Restore old status line. */
static void
status_pop_screen(struct client *c)
{
struct status_line *sl = &c->status;
if (--sl->references == 0) {
screen_free(sl->active);
free(sl->active);
sl->active = &sl->screen;
}
}
/* Initialize status line. */
void
status_init(struct client *c)
{
struct status_line *sl = &c->status;
screen_init(&sl->screen, c->tty.sx, 1, 0);
sl->active = &sl->screen;
}
/* Free status line. */
void
status_free(struct client *c)
{
struct status_line *sl = &c->status;
if (event_initialized(&sl->timer))
evtimer_del(&sl->timer);
if (sl->active != &sl->screen) {
screen_free(sl->active);
free(sl->active);
}
screen_free(&sl->screen);
}
/* Draw status line for client. */
int int
status_redraw(struct client *c) status_redraw(struct client *c)
{ {
struct status_line *sl = &c->status;
struct screen_write_ctx ctx; struct screen_write_ctx ctx;
struct session *s = c->session; struct session *s = c->session;
struct winlink *wl; struct winlink *wl;
struct screen old_status, window_list; struct screen old_screen, window_list;
struct grid_cell stdgc, lgc, rgc, gc; struct grid_cell stdgc, lgc, rgc, gc;
struct options *oo; struct options *oo;
time_t t;
char *left, *right; char *left, *right;
const char *sep; const char *sep;
u_int offset, needed, lines; u_int offset, needed, lines;
@ -316,12 +366,9 @@ status_redraw(struct client *c)
size_t llen, rlen, seplen; size_t llen, rlen, seplen;
int larrow, rarrow; int larrow, rarrow;
/* Delete the saved status line, if any. */ /* Shouldn't get here if not the active screen. */
if (c->status.old_status != NULL) { if (sl->active != &sl->screen)
screen_free(c->status.old_status); fatalx("not the active screen");
free(c->status.old_status);
c->status.old_status = NULL;
}
/* No status line? */ /* No status line? */
lines = status_line_size(c); lines = status_line_size(c);
@ -330,16 +377,13 @@ status_redraw(struct client *c)
left = right = NULL; left = right = NULL;
larrow = rarrow = 0; larrow = rarrow = 0;
/* Store current time. */
t = time(NULL);
/* Set up default colour. */ /* Set up default colour. */
style_apply(&stdgc, s->options, "status-style"); style_apply(&stdgc, s->options, "status-style");
/* Create the target screen. */ /* Create the target screen. */
memcpy(&old_status, &c->status.status, sizeof old_status); memcpy(&old_screen, sl->active, sizeof old_screen);
screen_init(&c->status.status, c->tty.sx, lines, 0); screen_init(sl->active, c->tty.sx, lines, 0);
screen_write_start(&ctx, NULL, &c->status.status); screen_write_start(&ctx, NULL, sl->active);
for (offset = 0; offset < lines * c->tty.sx; offset++) for (offset = 0; offset < lines * c->tty.sx; offset++)
screen_write_putc(&ctx, &stdgc, ' '); screen_write_putc(&ctx, &stdgc, ' ');
screen_write_stop(&ctx); screen_write_stop(&ctx);
@ -350,9 +394,9 @@ status_redraw(struct client *c)
/* Work out left and right strings. */ /* Work out left and right strings. */
memcpy(&lgc, &stdgc, sizeof lgc); memcpy(&lgc, &stdgc, sizeof lgc);
left = status_redraw_get_left(c, t, &lgc, &llen); left = status_redraw_get_left(c, &lgc, &llen);
memcpy(&rgc, &stdgc, sizeof rgc); memcpy(&rgc, &stdgc, sizeof rgc);
right = status_redraw_get_right(c, t, &rgc, &rlen); right = status_redraw_get_right(c, &rgc, &rlen);
/* /*
* Figure out how much space we have for the window list. If there * Figure out how much space we have for the window list. If there
@ -372,7 +416,7 @@ status_redraw(struct client *c)
RB_FOREACH(wl, winlinks, &s->windows) { RB_FOREACH(wl, winlinks, &s->windows) {
free(wl->status_text); free(wl->status_text);
memcpy(&wl->status_cell, &stdgc, sizeof wl->status_cell); memcpy(&wl->status_cell, &stdgc, sizeof wl->status_cell);
wl->status_text = status_print(c, wl, t, &wl->status_cell); wl->status_text = status_print(c, wl, &wl->status_cell);
wl->status_width = screen_write_cstrlen("%s", wl->status_text); wl->status_width = screen_write_cstrlen("%s", wl->status_text);
if (wl == s->curw) if (wl == s->curw)
@ -462,7 +506,7 @@ status_redraw(struct client *c)
draw: draw:
/* Begin drawing. */ /* Begin drawing. */
screen_write_start(&ctx, NULL, &c->status.status); screen_write_start(&ctx, NULL, sl->active);
/* Draw the left string and arrow. */ /* Draw the left string and arrow. */
screen_write_cursormove(&ctx, 0, 0, 0); screen_write_cursormove(&ctx, 0, 0, 0);
@ -506,14 +550,14 @@ draw:
wloffset++; wloffset++;
/* Copy the window list. */ /* Copy the window list. */
c->status.window_list_offset = -wloffset + wlstart; sl->window_list_offset = -wloffset + wlstart;
screen_write_cursormove(&ctx, wloffset, 0, 0); screen_write_cursormove(&ctx, wloffset, 0, 0);
screen_write_fast_copy(&ctx, &window_list, wlstart, 0, wlwidth, 1); screen_write_fast_copy(&ctx, &window_list, wlstart, 0, wlwidth, 1);
screen_free(&window_list); screen_free(&window_list);
/* Save left and right size. */ /* Save left and right size. */
c->status.left_size = llen; sl->left_size = llen;
c->status.right_size = rlen; sl->right_size = rlen;
screen_write_stop(&ctx); screen_write_stop(&ctx);
@ -521,17 +565,17 @@ out:
free(left); free(left);
free(right); free(right);
if (grid_compare(c->status.status.grid, old_status.grid) == 0) { if (grid_compare(sl->active->grid, old_screen.grid) == 0) {
screen_free(&old_status); screen_free(&old_screen);
return (0); return (0);
} }
screen_free(&old_status); screen_free(&old_screen);
return (1); return (1);
} }
/* Replace special sequences in fmt. */ /* Replace special sequences in fmt. */
static char * static char *
status_replace(struct client *c, struct winlink *wl, const char *fmt, time_t t) status_replace(struct client *c, struct winlink *wl, const char *fmt)
{ {
struct format_tree *ft; struct format_tree *ft;
char *expanded; char *expanded;
@ -550,7 +594,7 @@ status_replace(struct client *c, struct winlink *wl, const char *fmt, time_t t)
ft = format_create(c, NULL, tag, FORMAT_STATUS); ft = format_create(c, NULL, tag, FORMAT_STATUS);
format_defaults(ft, c, NULL, wl, NULL); format_defaults(ft, c, NULL, wl, NULL);
expanded = format_expand_time(ft, fmt, t); expanded = format_expand_time(ft, fmt);
format_free(ft); format_free(ft);
return (expanded); return (expanded);
@ -558,8 +602,7 @@ status_replace(struct client *c, struct winlink *wl, const char *fmt, time_t t)
/* Return winlink status line entry and adjust gc as necessary. */ /* Return winlink status line entry and adjust gc as necessary. */
static char * static char *
status_print(struct client *c, struct winlink *wl, time_t t, status_print(struct client *c, struct winlink *wl, struct grid_cell *gc)
struct grid_cell *gc)
{ {
struct options *oo = wl->window->options; struct options *oo = wl->window->options;
struct session *s = c->session; struct session *s = c->session;
@ -580,7 +623,7 @@ status_print(struct client *c, struct winlink *wl, time_t t,
else if (wl->flags & (WINLINK_ACTIVITY|WINLINK_SILENCE)) else if (wl->flags & (WINLINK_ACTIVITY|WINLINK_SILENCE))
style_apply_update(gc, oo, "window-status-activity-style"); style_apply_update(gc, oo, "window-status-activity-style");
text = status_replace(c, wl, fmt, t); text = status_replace(c, wl, fmt);
return (text); return (text);
} }
@ -593,13 +636,7 @@ status_message_set(struct client *c, const char *fmt, ...)
int delay; int delay;
status_message_clear(c); status_message_clear(c);
status_push_screen(c);
if (c->status.old_status == NULL) {
c->status.old_status = xmalloc(sizeof *c->status.old_status);
memcpy(c->status.old_status, &c->status.status,
sizeof *c->status.old_status);
screen_init(&c->status.status, c->tty.sx, 1, 0);
}
va_start(ap, fmt); va_start(ap, fmt);
xvasprintf(&c->message_string, fmt, ap); xvasprintf(&c->message_string, fmt, ap);
@ -636,7 +673,7 @@ status_message_clear(struct client *c)
c->tty.flags &= ~(TTY_NOCURSOR|TTY_FREEZE); c->tty.flags &= ~(TTY_NOCURSOR|TTY_FREEZE);
c->flags |= CLIENT_ALLREDRAWFLAGS; /* was frozen and may have changed */ c->flags |= CLIENT_ALLREDRAWFLAGS; /* was frozen and may have changed */
screen_reinit(&c->status.status); status_pop_screen(c);
} }
/* Clear status line message after timer expires. */ /* Clear status line message after timer expires. */
@ -652,23 +689,22 @@ status_message_callback(__unused int fd, __unused short event, void *data)
int int
status_message_redraw(struct client *c) status_message_redraw(struct client *c)
{ {
struct screen_write_ctx ctx; struct status_line *sl = &c->status;
struct session *s = c->session; struct screen_write_ctx ctx;
struct screen old_status; struct session *s = c->session;
size_t len; struct screen old_screen;
struct grid_cell gc; size_t len;
u_int lines, offset; u_int lines, offset;
struct grid_cell gc;
if (c->tty.sx == 0 || c->tty.sy == 0) if (c->tty.sx == 0 || c->tty.sy == 0)
return (0); return (0);
memcpy(&old_status, &c->status.status, sizeof old_status); memcpy(&old_screen, sl->active, sizeof old_screen);
lines = status_line_size(c); lines = status_line_size(c);
if (lines <= 1) { if (lines <= 1)
lines = 1; lines = 1;
screen_init(&c->status.status, c->tty.sx, 1, 0); screen_init(sl->active, c->tty.sx, lines, 0);
} else
screen_init(&c->status.status, c->tty.sx, lines, 0);
len = screen_write_strlen("%s", c->message_string); len = screen_write_strlen("%s", c->message_string);
if (len > c->tty.sx) if (len > c->tty.sx)
@ -676,7 +712,7 @@ status_message_redraw(struct client *c)
style_apply(&gc, s->options, "message-style"); style_apply(&gc, s->options, "message-style");
screen_write_start(&ctx, NULL, &c->status.status); screen_write_start(&ctx, NULL, sl->active);
screen_write_cursormove(&ctx, 0, 0, 0); screen_write_cursormove(&ctx, 0, 0, 0);
for (offset = 0; offset < lines * c->tty.sx; offset++) for (offset = 0; offset < lines * c->tty.sx; offset++)
screen_write_putc(&ctx, &gc, ' '); screen_write_putc(&ctx, &gc, ' ');
@ -684,11 +720,11 @@ status_message_redraw(struct client *c)
screen_write_nputs(&ctx, len, &gc, "%s", c->message_string); screen_write_nputs(&ctx, len, &gc, "%s", c->message_string);
screen_write_stop(&ctx); screen_write_stop(&ctx);
if (grid_compare(c->status.status.grid, old_status.grid) == 0) { if (grid_compare(sl->active->grid, old_screen.grid) == 0) {
screen_free(&old_status); screen_free(&old_screen);
return (0); return (0);
} }
screen_free(&old_status); screen_free(&old_screen);
return (1); return (1);
} }
@ -698,31 +734,23 @@ status_prompt_set(struct client *c, const char *msg, const char *input,
prompt_input_cb inputcb, prompt_free_cb freecb, void *data, int flags) prompt_input_cb inputcb, prompt_free_cb freecb, void *data, int flags)
{ {
struct format_tree *ft; struct format_tree *ft;
time_t t;
char *tmp, *cp; char *tmp, *cp;
ft = format_create(c, NULL, FORMAT_NONE, 0); ft = format_create(c, NULL, FORMAT_NONE, 0);
format_defaults(ft, c, NULL, NULL, NULL); format_defaults(ft, c, NULL, NULL, NULL);
t = time(NULL);
if (input == NULL) if (input == NULL)
input = ""; input = "";
if (flags & PROMPT_NOFORMAT) if (flags & PROMPT_NOFORMAT)
tmp = xstrdup(input); tmp = xstrdup(input);
else else
tmp = format_expand_time(ft, input, t); tmp = format_expand_time(ft, input);
status_message_clear(c); status_message_clear(c);
status_prompt_clear(c); status_prompt_clear(c);
status_push_screen(c);
if (c->status.old_status == NULL) { c->prompt_string = format_expand_time(ft, msg);
c->status.old_status = xmalloc(sizeof *c->status.old_status);
memcpy(c->status.old_status, &c->status.status,
sizeof *c->status.old_status);
screen_init(&c->status.status, c->tty.sx, 1, 0);
}
c->prompt_string = format_expand_time(ft, msg, t);
c->prompt_buffer = utf8_fromcstr(tmp); c->prompt_buffer = utf8_fromcstr(tmp);
c->prompt_index = utf8_strlen(c->prompt_buffer); c->prompt_index = utf8_strlen(c->prompt_buffer);
@ -772,7 +800,7 @@ status_prompt_clear(struct client *c)
c->tty.flags &= ~(TTY_NOCURSOR|TTY_FREEZE); c->tty.flags &= ~(TTY_NOCURSOR|TTY_FREEZE);
c->flags |= CLIENT_ALLREDRAWFLAGS; /* was frozen and may have changed */ c->flags |= CLIENT_ALLREDRAWFLAGS; /* was frozen and may have changed */
screen_reinit(&c->status.status); status_pop_screen(c);
} }
/* Update status line prompt with a new prompt string. */ /* Update status line prompt with a new prompt string. */
@ -780,17 +808,15 @@ void
status_prompt_update(struct client *c, const char *msg, const char *input) status_prompt_update(struct client *c, const char *msg, const char *input)
{ {
struct format_tree *ft; struct format_tree *ft;
time_t t;
char *tmp; char *tmp;
ft = format_create(c, NULL, FORMAT_NONE, 0); ft = format_create(c, NULL, FORMAT_NONE, 0);
format_defaults(ft, c, NULL, NULL, NULL); format_defaults(ft, c, NULL, NULL, NULL);
t = time(NULL); tmp = format_expand_time(ft, input);
tmp = format_expand_time(ft, input, t);
free(c->prompt_string); free(c->prompt_string);
c->prompt_string = format_expand_time(ft, msg, t); c->prompt_string = format_expand_time(ft, msg);
free(c->prompt_buffer); free(c->prompt_buffer);
c->prompt_buffer = utf8_fromcstr(tmp); c->prompt_buffer = utf8_fromcstr(tmp);
@ -808,23 +834,22 @@ status_prompt_update(struct client *c, const char *msg, const char *input)
int int
status_prompt_redraw(struct client *c) status_prompt_redraw(struct client *c)
{ {
struct status_line *sl = &c->status;
struct screen_write_ctx ctx; struct screen_write_ctx ctx;
struct session *s = c->session; struct session *s = c->session;
struct screen old_status; struct screen old_screen;
u_int i, offset, left, start, pcursor, pwidth, width; u_int i, lines, offset, left, start, width;
u_int lines; u_int pcursor, pwidth;
struct grid_cell gc, cursorgc; struct grid_cell gc, cursorgc;
if (c->tty.sx == 0 || c->tty.sy == 0) if (c->tty.sx == 0 || c->tty.sy == 0)
return (0); return (0);
memcpy(&old_status, &c->status.status, sizeof old_status); memcpy(&old_screen, sl->active, sizeof old_screen);
lines = status_line_size(c); lines = status_line_size(c);
if (lines <= 1) { if (lines <= 1)
lines = 1; lines = 1;
screen_init(&c->status.status, c->tty.sx, 1, 0); screen_init(sl->active, c->tty.sx, lines, 0);
} else
screen_init(&c->status.status, c->tty.sx, lines, 0);
if (c->prompt_mode == PROMPT_COMMAND) if (c->prompt_mode == PROMPT_COMMAND)
style_apply(&gc, s->options, "message-command-style"); style_apply(&gc, s->options, "message-command-style");
@ -838,7 +863,7 @@ status_prompt_redraw(struct client *c)
if (start > c->tty.sx) if (start > c->tty.sx)
start = c->tty.sx; start = c->tty.sx;
screen_write_start(&ctx, NULL, &c->status.status); screen_write_start(&ctx, NULL, sl->active);
screen_write_cursormove(&ctx, 0, 0, 0); screen_write_cursormove(&ctx, 0, 0, 0);
for (offset = 0; offset < lines * c->tty.sx; offset++) for (offset = 0; offset < lines * c->tty.sx; offset++)
screen_write_putc(&ctx, &gc, ' '); screen_write_putc(&ctx, &gc, ' ');
@ -884,18 +909,17 @@ status_prompt_redraw(struct client *c)
screen_write_cell(&ctx, &cursorgc); screen_write_cell(&ctx, &cursorgc);
} }
} }
if (c->status.status.cx < screen_size_x(&c->status.status) && if (sl->active->cx < screen_size_x(sl->active) && c->prompt_index >= i)
c->prompt_index >= i)
screen_write_putc(&ctx, &cursorgc, ' '); screen_write_putc(&ctx, &cursorgc, ' ');
finished: finished:
screen_write_stop(&ctx); screen_write_stop(&ctx);
if (grid_compare(c->status.status.grid, old_status.grid) == 0) { if (grid_compare(sl->active->grid, old_screen.grid) == 0) {
screen_free(&old_status); screen_free(&old_screen);
return (0); return (0);
} }
screen_free(&old_status); screen_free(&old_screen);
return (1); return (1);
} }
@ -1486,9 +1510,10 @@ status_prompt_complete_list(u_int *size, const char *s)
const char **layout, *value, *cp; const char **layout, *value, *cp;
const struct cmd_entry **cmdent; const struct cmd_entry **cmdent;
const struct options_table_entry *oe; const struct options_table_entry *oe;
u_int items, idx; u_int idx;
size_t slen = strlen(s), valuelen; size_t slen = strlen(s), valuelen;
struct options_entry *o; struct options_entry *o;
struct options_array_item *a;
const char *layouts[] = { const char *layouts[] = {
"even-horizontal", "even-vertical", "main-horizontal", "even-horizontal", "even-vertical", "main-horizontal",
"main-vertical", "tiled", NULL "main-vertical", "tiled", NULL
@ -1514,16 +1539,22 @@ status_prompt_complete_list(u_int *size, const char *s)
} }
} }
o = options_get_only(global_options, "command-alias"); o = options_get_only(global_options, "command-alias");
if (o != NULL && options_array_size(o, &items) != -1) { if (o != NULL) {
for (idx = 0; idx < items; idx++) { a = options_array_first(o);
value = options_array_get(o, idx); while (a != NULL) {
value = options_array_item_value(a);;
if (value == NULL || (cp = strchr(value, '=')) == NULL) if (value == NULL || (cp = strchr(value, '=')) == NULL)
continue; goto next;
valuelen = cp - value; valuelen = cp - value;
if (slen > valuelen || strncmp(value, s, slen) != 0) if (slen > valuelen || strncmp(value, s, slen) != 0)
continue; goto next;
list = xreallocarray(list, (*size) + 1, sizeof *list); list = xreallocarray(list, (*size) + 1, sizeof *list);
list[(*size)++] = xstrndup(value, valuelen); list[(*size)++] = xstrndup(value, valuelen);
next:
a = options_array_next(a);
} }
} }
for (idx = 0; idx < (*size); idx++) for (idx = 0; idx < (*size); idx++)

65
style.c
View File

@ -39,24 +39,24 @@ static struct style style_default = {
int int
style_parse(struct style *sy, const struct grid_cell *base, const char *in) style_parse(struct style *sy, const struct grid_cell *base, const char *in)
{ {
struct style saved; struct style saved;
const char delimiters[] = " ,"; const char delimiters[] = " ,";
char tmp[32]; char tmp[32];
int value, fg, bg, attr, flags; int value;
size_t end; size_t end;
if (*in == '\0') if (*in == '\0')
return (0); return (0);
if (strchr(delimiters, in[strlen(in) - 1]) != NULL)
return (-1);
style_copy(&saved, sy); style_copy(&saved, sy);
fg = sy->gc.fg;
bg = sy->gc.bg;
attr = sy->gc.attr;
flags = sy->gc.flags;
do { do {
while (*in != '\0' && strchr(delimiters, *in) != NULL) {
in++;
end--;
}
if (*in == '\0')
break;
end = strcspn(in, delimiters); end = strcspn(in, delimiters);
if (end > (sizeof tmp) - 1) if (end > (sizeof tmp) - 1)
goto error; goto error;
@ -64,45 +64,40 @@ style_parse(struct style *sy, const struct grid_cell *base, const char *in)
tmp[end] = '\0'; tmp[end] = '\0';
if (strcasecmp(tmp, "default") == 0) { if (strcasecmp(tmp, "default") == 0) {
fg = base->fg; sy->gc.fg = base->fg;
bg = base->bg; sy->gc.bg = base->bg;
attr = base->attr; sy->gc.attr = base->attr;
flags = base->flags; sy->gc.flags = base->flags;
} 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;
if (*in == 'f' || *in == 'F') { if (*in == 'f' || *in == 'F') {
if (value != 8) if (value != 8)
fg = value; sy->gc.fg = value;
else else
fg = base->fg; sy->gc.fg = base->fg;
} else if (*in == 'b' || *in == 'B') { } else if (*in == 'b' || *in == 'B') {
if (value != 8) if (value != 8)
bg = value; sy->gc.bg = value;
else else
bg = base->bg; sy->gc.bg = base->bg;
} else } else
goto error; goto error;
} else if (strcasecmp(tmp, "none") == 0) } else if (strcasecmp(tmp, "none") == 0)
attr = 0; sy->gc.attr = 0;
else if (end > 2 && strncasecmp(tmp, "no", 2) == 0) { else if (end > 2 && strncasecmp(tmp, "no", 2) == 0) {
if ((value = attributes_fromstring(tmp + 2)) == -1) if ((value = attributes_fromstring(tmp + 2)) == -1)
goto error; goto error;
attr &= ~value; sy->gc.attr &= ~value;
} else { } else {
if ((value = attributes_fromstring(tmp)) == -1) if ((value = attributes_fromstring(tmp)) == -1)
goto error; goto error;
attr |= value; sy->gc.attr |= value;
} }
in += end + strspn(in + end, delimiters); in += end + strspn(in + end, delimiters);
} while (*in != '\0'); } while (*in != '\0');
sy->gc.fg = fg;
sy->gc.bg = bg;
sy->gc.attr = attr;
sy->gc.flags = flags;
return (0); return (0);
error: error:
@ -122,18 +117,18 @@ style_tostring(struct style *sy)
*s = '\0'; *s = '\0';
if (gc->fg != 8) { if (gc->fg != 8) {
off += xsnprintf(s + off, sizeof s - off, "%sfg=%s", off += xsnprintf(s + off, sizeof s - off, "%sfg=%s", comma,
comma, colour_tostring(gc->fg)); colour_tostring(gc->fg));
comma = ","; comma = ",";
} }
if (gc->bg != 8) { if (gc->bg != 8) {
off += xsnprintf(s + off, sizeof s - off, "%sbg=%s", off += xsnprintf(s + off, sizeof s - off, "%sbg=%s", comma,
comma, colour_tostring(gc->bg)); colour_tostring(gc->bg));
comma = ","; comma = ",";
} }
if (gc->attr != 0 && gc->attr != GRID_ATTR_CHARSET) { if (gc->attr != 0 && gc->attr != GRID_ATTR_CHARSET) {
xsnprintf(s + off, sizeof s - off, "%s%s", xsnprintf(s + off, sizeof s - off, "%s%s", comma,
comma, attributes_tostring(gc->attr)); attributes_tostring(gc->attr));
comma = ","; comma = ",";
} }
@ -174,7 +169,7 @@ style_apply_update(struct grid_cell *gc, struct options *oo, const char *name)
void void
style_set(struct style *sy, const struct grid_cell *gc) style_set(struct style *sy, const struct grid_cell *gc)
{ {
memset(sy, 0, sizeof *sy); memcpy(sy, &style_default, sizeof *sy);
memcpy(&sy->gc, gc, sizeof sy->gc); memcpy(&sy->gc, gc, sizeof sy->gc);
} }

235
tmux.1
View File

@ -2837,82 +2837,19 @@ The default is to run
with with
.Fl np . .Fl np .
.It Ic message-command-style Ar style .It Ic message-command-style Ar style
Set status line message command style, where Set status line message command style.
.Ar style For how to specify
is a comma-separated list of characteristics to be specified. .Ar style ,
.Pp see the
The style format is shared by many options and may be: .Sx STYLES
.Ql bg=colour section.
to set the background colour,
.Ql fg=colour
to set the foreground colour, and a list of attributes as specified below.
.Pp
The colour is one of:
.Ic black ,
.Ic red ,
.Ic green ,
.Ic yellow ,
.Ic blue ,
.Ic magenta ,
.Ic cyan ,
.Ic white ,
aixterm bright variants (if supported:
.Ic brightred ,
.Ic brightgreen ,
and so on),
.Ic colour0
to
.Ic colour255
from the 256-colour set,
.Ic default
for the default colour (inherited from another option in the case of some options, for example
.Ic window-status-style
inherits from
.Ic status-style ) ,
.Ic terminal
for the terminal default colour, or a hexadecimal RGB string such as
.Ql #ffffff .
.Pp
The attributes is either
.Ic none
or a comma-delimited list of one or more of:
.Ic bright
(or
.Ic bold ) ,
.Ic dim ,
.Ic underscore ,
.Ic blink ,
.Ic reverse ,
.Ic hidden ,
.Ic italics ,
.Ic strikethrough ,
.Ic double-underscore
.Ic curly-underscore
.Ic dotted-underscore
or
.Ic dashed-underscore
to turn an attribute on, or an attribute prefixed with
.Ql no
to turn one off.
.Pp
Examples are:
.Bd -literal -offset indent
fg=yellow,bold,underscore,blink
bg=black,fg=default,noreverse
.Ed
.Pp
With the
.Fl a
flag to the
.Ic set-option
command the new style is added otherwise the existing style is replaced.
.It Ic message-style Ar style .It Ic message-style Ar style
Set status line message style. Set status line message style.
For how to specify For how to specify
.Ar style , .Ar style ,
see the see the
.Ic message-command-style .Sx STYLES
option. section.
.It Xo Ic mouse .It Xo Ic mouse
.Op Ic on | off .Op Ic on | off
.Xc .Xc
@ -3019,17 +2956,12 @@ Display
(by default the session name) to the left of the status line. (by default the session name) to the left of the status line.
.Ar string .Ar string
will be passed through will be passed through
.Xr strftime 3 .Xr strftime 3 .
and formats (see Also see the
.Sx FORMATS ) .Sx FORMATS
will be expanded. and
It may also contain the special character sequence #[] to change the colour .Sx STYLES
or attributes, for example sections.
.Ql #[fg=red,bright]
to set a bright red foreground.
See the
.Ic message-command-style
option for a description of colours and attributes.
.Pp .Pp
For details on how the names and titles can be set see the For details on how the names and titles can be set see the
.Sx "NAMES AND TITLES" .Sx "NAMES AND TITLES"
@ -3053,8 +2985,8 @@ Set the style of the left part of the status line.
For how to specify For how to specify
.Ar style , .Ar style ,
see the see the
.Ic message-command-style .Sx STYLES
option. section.
.It Xo Ic status-position .It Xo Ic status-position
.Op Ic top | bottom .Op Ic top | bottom
.Xc .Xc
@ -3081,15 +3013,15 @@ Set the style of the right part of the status line.
For how to specify For how to specify
.Ar style , .Ar style ,
see the see the
.Ic message-command-style .Sx STYLES
option. section.
.It Ic status-style Ar style .It Ic status-style Ar style
Set status line style. Set status line style.
For how to specify For how to specify
.Ar style , .Ar style ,
see the see the
.Ic message-command-style .Sx STYLES
option. section.
.It Ic update-environment[] Ar variable .It Ic update-environment[] Ar variable
Set list of environment variables to be copied into the session environment Set list of environment variables to be copied into the session environment
when a new session is created or an existing session is attached. when a new session is created or an existing session is attached.
@ -3266,8 +3198,8 @@ Set window modes style.
For how to specify For how to specify
.Ar style , .Ar style ,
see the see the
.Ic message-command-style .Sx STYLES
option. section.
.Pp .Pp
.It Xo Ic monitor-activity .It Xo Ic monitor-activity
.Op Ic on | off .Op Ic on | off
@ -3315,8 +3247,8 @@ Set the pane border style for the currently active pane.
For how to specify For how to specify
.Ar style , .Ar style ,
see the see the
.Ic message-command-style .Sx STYLES
option. section.
Attributes are ignored. Attributes are ignored.
.Pp .Pp
.It Ic pane-base-index Ar index .It Ic pane-base-index Ar index
@ -3337,8 +3269,8 @@ Set the pane border style for panes aside from the active pane.
For how to specify For how to specify
.Ar style , .Ar style ,
see the see the
.Ic message-command-style .Sx STYLES
option. section.
Attributes are ignored. Attributes are ignored.
.Pp .Pp
.It Xo Ic remain-on-exit .It Xo Ic remain-on-exit
@ -3361,24 +3293,24 @@ Set the style for the window's active pane.
For how to specify For how to specify
.Ar style , .Ar style ,
see the see the
.Ic message-command-style .Sx STYLES
option. section.
.Pp .Pp
.It Ic window-status-activity-style Ar style .It Ic window-status-activity-style Ar style
Set status line style for windows with an activity alert. Set status line style for windows with an activity alert.
For how to specify For how to specify
.Ar style , .Ar style ,
see the see the
.Ic message-command-style .Sx STYLES
option. section.
.Pp .Pp
.It Ic window-status-bell-style Ar style .It Ic window-status-bell-style Ar style
Set status line style for windows with a bell alert. Set status line style for windows with a bell alert.
For how to specify For how to specify
.Ar style , .Ar style ,
see the see the
.Ic message-command-style .Sx STYLES
option. section.
.Pp .Pp
.It Ic window-status-current-format Ar string .It Ic window-status-current-format Ar string
Like Like
@ -3390,24 +3322,24 @@ Set status line style for the currently active window.
For how to specify For how to specify
.Ar style , .Ar style ,
see the see the
.Ic message-command-style .Sx STYLES
option. section.
.Pp .Pp
.It Ic window-status-format Ar string .It Ic window-status-format Ar string
Set the format in which the window is displayed in the status line window list. Set the format in which the window is displayed in the status line window list.
See the See the
.Ar status-left .Sx FORMATS
option for details of special character sequences available. and
The default is .Sx STYLES
.Ql #I:#W#F . sections.
.Pp .Pp
.It Ic window-status-last-style Ar style .It Ic window-status-last-style Ar style
Set status line style for the last active window. Set status line style for the last active window.
For how to specify For how to specify
.Ar style , .Ar style ,
see the see the
.Ic message-command-style .Sx STYLES
option. section.
.Pp .Pp
.It Ic window-status-separator Ar string .It Ic window-status-separator Ar string
Sets the separator drawn between windows in the status line. Sets the separator drawn between windows in the status line.
@ -3418,8 +3350,8 @@ Set status line style for a single window.
For how to specify For how to specify
.Ar style , .Ar style ,
see the see the
.Ic message-command-style .Sx STYLES
option. section.
.Pp .Pp
.It Xo Ic Ic window-size .It Xo Ic Ic window-size
.Ar largest | Ar smallest | Ar manual .Ar largest | Ar smallest | Ar manual
@ -3448,8 +3380,8 @@ Set the default window style.
For how to specify For how to specify
.Ar style , .Ar style ,
see the see the
.Ic message-command-style .Sx STYLES
option. section.
.Pp .Pp
.It Xo Ic wrap-search .It Xo Ic wrap-search
.Op Ic on | off .Op Ic on | off
@ -3978,6 +3910,7 @@ The following variables are available, where appropriate:
.It Li "window_active" Ta "" Ta "1 if window active" .It Li "window_active" Ta "" Ta "1 if window active"
.It Li "window_bell_flag" Ta "" Ta "1 if window has bell" .It Li "window_bell_flag" Ta "" Ta "1 if window has bell"
.It Li "window_bigger" Ta "" Ta "1 if window is larger than client" .It Li "window_bigger" Ta "" Ta "1 if window is larger than client"
.It Li "window_end_flag" Ta "" Ta "1 if window has the highest index"
.It Li "window_flags" Ta "#F" Ta "Window flags" .It Li "window_flags" Ta "#F" Ta "Window flags"
.It Li "window_format" Ta "" Ta "1 if format is for a window (not assuming the current)" .It Li "window_format" Ta "" Ta "1 if format is for a window (not assuming the current)"
.It Li "window_height" Ta "" Ta "Height of window" .It Li "window_height" Ta "" Ta "Height of window"
@ -3992,11 +3925,83 @@ The following variables are available, where appropriate:
.It Li "window_panes" Ta "" Ta "Number of panes in window" .It Li "window_panes" Ta "" Ta "Number of panes in window"
.It Li "window_silence_flag" Ta "" Ta "1 if window has silence alert" .It Li "window_silence_flag" Ta "" Ta "1 if window has silence alert"
.It Li "window_stack_index" Ta "" Ta "Index in session most recent stack" .It Li "window_stack_index" Ta "" Ta "Index in session most recent stack"
.It Li "window_start_flag" Ta "" Ta "1 if window has the lowest index"
.It Li "window_visible_layout" Ta "" Ta "Window layout description, respecting zoomed window panes" .It Li "window_visible_layout" Ta "" Ta "Window layout description, respecting zoomed window panes"
.It Li "window_width" Ta "" Ta "Width of window" .It Li "window_width" Ta "" Ta "Width of window"
.It Li "window_zoomed_flag" Ta "" Ta "1 if window is zoomed" .It Li "window_zoomed_flag" Ta "" Ta "1 if window is zoomed"
.It Li "wrap_flag" Ta "" Ta "Pane wrap flag" .It Li "wrap_flag" Ta "" Ta "Pane wrap flag"
.El .El
.Sh STYLES
.Nm
offers various options to specify the colour and attributes of aspects of the
interface, for example
.Ic status-style
for the status line.
In addition, embedded styles may be specified in format options, such as
.Ic status-left-format ,
by enclosing them in
.Ql #[
and
.Ql ] .
.Pp
A style may be the single term
.Ql default
to specify the default style (which may inherit from another option) or a space
separated list of the following:
.Bl -tag -width Ds
.It Ic fg=colour
Set the foreground colour.
The colour is one of:
.Ic black ,
.Ic red ,
.Ic green ,
.Ic yellow ,
.Ic blue ,
.Ic magenta ,
.Ic cyan ,
.Ic white ;
if supported the bright variants
.Ic brightred ,
.Ic brightgreen ,
.Ic brightyellow ;
.Ic colour0
to
.Ic colour255
from the 256-colour set;
.Ic default
for the default colour;
.Ic terminal
for the terminal default colour; or a hexadecimal RGB string such as
.Ql #ffffff .
.It Ic bg=colour
Set the background colour.
.It Ic none
Set no attributes (turn off any active attributes).
.It Xo Ic bright (or
.Ic bold )
.Ic dim ,
.Ic underscore ,
.Ic blink ,
.Ic reverse ,
.Ic hidden ,
.Ic italics ,
.Ic strikethrough ,
.Ic double-underscore ,
.Ic curly-underscore ,
.Ic dotted-underscore ,
.Ic dashed-underscore
.Xc
Set an attribute.
Any of the attributes may be prefixed with
.Ql no
to unset.
.El
.Pp
Examples are:
.Bd -literal -offset indent
fg=yellow,bold,underscore,blink
bg=black,fg=default,noreverse
.Ed
.Sh NAMES AND TITLES .Sh NAMES AND TITLES
.Nm .Nm
distinguishes between names and titles. distinguishes between names and titles.
@ -4277,7 +4282,7 @@ option.
This command works only from inside This command works only from inside
.Nm . .Nm .
.It Xo Ic display-message .It Xo Ic display-message
.Op Fl p .Op Fl pv
.Op Fl c Ar target-client .Op Fl c Ar target-client
.Op Fl t Ar target-pane .Op Fl t Ar target-pane
.Op Ar message .Op Ar message
@ -4299,6 +4304,10 @@ if
.Fl t .Fl t
is given, otherwise the active pane for the session attached to is given, otherwise the active pane for the session attached to
.Ar target-client . .Ar target-client .
.Pp
With
.Fl v ,
verbose logging is printed as the format is parsed.
.El .El
.Sh BUFFERS .Sh BUFFERS
.Nm .Nm

22
tmux.h
View File

@ -52,6 +52,7 @@ struct mode_tree_data;
struct mouse_event; struct mouse_event;
struct options; struct options;
struct options_entry; struct options_entry;
struct options_array_item;
struct session; struct session;
struct tmuxpeer; struct tmuxpeer;
struct tmuxproc; struct tmuxproc;
@ -1316,8 +1317,9 @@ struct cmd_entry {
struct status_line { struct status_line {
struct event timer; struct event timer;
struct screen status; struct screen screen;
struct screen *old_status; struct screen *active;
int references;
int window_list_offset; int window_list_offset;
@ -1436,8 +1438,6 @@ struct client {
struct session *session; struct session *session;
struct session *last_session; struct session *last_session;
int wlmouse;
int references; int references;
void *pan_window; void *pan_window;
@ -1501,6 +1501,7 @@ struct options_table_entry {
const char *default_str; const char *default_str;
long long default_num; long long default_num;
const char **default_arr;
const char *separator; const char *separator;
const char *style; const char *style;
@ -1577,6 +1578,7 @@ char *paste_make_sample(struct paste_buffer *);
#define FORMAT_STATUS 0x1 #define FORMAT_STATUS 0x1
#define FORMAT_FORCE 0x2 #define FORMAT_FORCE 0x2
#define FORMAT_NOJOBS 0x4 #define FORMAT_NOJOBS 0x4
#define FORMAT_VERBOSE 0x8
#define FORMAT_NONE 0 #define FORMAT_NONE 0
#define FORMAT_PANE 0x80000000U #define FORMAT_PANE 0x80000000U
#define FORMAT_WINDOW 0x40000000U #define FORMAT_WINDOW 0x40000000U
@ -1587,7 +1589,7 @@ struct format_tree *format_create(struct client *, struct cmdq_item *, int,
void format_free(struct format_tree *); void format_free(struct format_tree *);
void printflike(3, 4) format_add(struct format_tree *, const char *, void printflike(3, 4) format_add(struct format_tree *, const char *,
const char *, ...); const char *, ...);
char *format_expand_time(struct format_tree *, const char *, time_t); char *format_expand_time(struct format_tree *, const char *);
char *format_expand(struct format_tree *, const char *); char *format_expand(struct format_tree *, const char *);
char *format_single(struct cmdq_item *, const char *, char *format_single(struct cmdq_item *, const char *,
struct client *, struct session *, struct winlink *, struct client *, struct session *, struct winlink *,
@ -1643,8 +1645,12 @@ void options_array_clear(struct options_entry *);
const char *options_array_get(struct options_entry *, u_int); const char *options_array_get(struct options_entry *, u_int);
int options_array_set(struct options_entry *, u_int, const char *, int options_array_set(struct options_entry *, u_int, const char *,
int); int);
int options_array_size(struct options_entry *, u_int *);
void options_array_assign(struct options_entry *, const char *); void options_array_assign(struct options_entry *, const char *);
struct options_array_item *options_array_first(struct options_entry *);
struct options_array_item *options_array_next(struct options_array_item *);
u_int options_array_item_index(struct options_array_item *);
const char *options_array_item_value(struct options_array_item *);
int options_isarray(struct options_entry *);
int options_isstring(struct options_entry *); int options_isstring(struct options_entry *);
const char *options_tostring(struct options_entry *, int, int); const char *options_tostring(struct options_entry *, int, int);
char *options_parse(const char *, int *); char *options_parse(const char *, int *);
@ -1969,10 +1975,12 @@ void server_unzoom_window(struct window *);
/* status.c */ /* status.c */
void status_timer_start(struct client *); void status_timer_start(struct client *);
void status_timer_start_all(void); void status_timer_start_all(void);
void status_update_saved(struct session *); void status_update_cache(struct session *);
int status_at_line(struct client *); int status_at_line(struct client *);
u_int status_line_size(struct client *); u_int status_line_size(struct client *);
struct window *status_get_window_at(struct client *, u_int); struct window *status_get_window_at(struct client *, u_int);
void status_init(struct client *);
void status_free(struct client *);
int status_redraw(struct client *); int status_redraw(struct client *);
void printflike(2, 3) status_message_set(struct client *, const char *, ...); void printflike(2, 3) status_message_set(struct client *, const char *, ...);
void status_message_clear(struct client *); void status_message_clear(struct client *);

View File

@ -398,9 +398,10 @@ tty_keys_build(struct tty *tty)
{ {
const struct tty_default_key_raw *tdkr; const struct tty_default_key_raw *tdkr;
const struct tty_default_key_code *tdkc; const struct tty_default_key_code *tdkc;
u_int i, size; u_int i;
const char *s, *value; const char *s, *value;
struct options_entry *o; struct options_entry *o;
struct options_array_item *a;
if (tty->key_tree != NULL) if (tty->key_tree != NULL)
tty_keys_free(tty); tty_keys_free(tty);
@ -423,11 +424,13 @@ tty_keys_build(struct tty *tty)
} }
o = options_get(global_options, "user-keys"); o = options_get(global_options, "user-keys");
if (o != NULL && options_array_size(o, &size) != -1) { if (o != NULL) {
for (i = 0; i < size; i++) { a = options_array_first(o);
value = options_array_get(o, i); while (a != NULL) {
value = options_array_item_value(a);
if (value != NULL) if (value != NULL)
tty_keys_add(tty, value, KEYC_USER + i); tty_keys_add(tty, value, KEYC_USER + i);
a = options_array_next(a);
} }
} }
} }

View File

@ -419,7 +419,8 @@ tty_term_find(char *name, int fd, char **cause)
const struct tty_term_code_entry *ent; const struct tty_term_code_entry *ent;
struct tty_code *code; struct tty_code *code;
struct options_entry *o; struct options_entry *o;
u_int size, i; struct options_array_item *a;
u_int i;
int n, error; int n, error;
const char *s, *acs; const char *s, *acs;
@ -494,12 +495,12 @@ tty_term_find(char *name, int fd, char **cause)
/* Apply terminal overrides. */ /* Apply terminal overrides. */
o = options_get_only(global_options, "terminal-overrides"); o = options_get_only(global_options, "terminal-overrides");
if (options_array_size(o, &size) != -1) { a = options_array_first(o);
for (i = 0; i < size; i++) { while (a != NULL) {
s = options_array_get(o, i); s = options_array_item_value(a);
if (s != NULL) if (s != NULL)
tty_term_override(term, s); tty_term_override(term, s);
} a = options_array_next(a);
} }
/* Delete curses data. */ /* Delete curses data. */

View File

@ -229,10 +229,7 @@ window_client_draw(__unused void *modedata, void *itemdata,
screen_write_hline(ctx, sx, 0, 0); screen_write_hline(ctx, sx, 0, 0);
screen_write_cursormove(ctx, cx, cy + sy - 1, 0); screen_write_cursormove(ctx, cx, cy + sy - 1, 0);
if (c->status.old_status != NULL) screen_write_fast_copy(ctx, &c->status.screen, 0, 0, sx, 1);
screen_write_fast_copy(ctx, c->status.old_status, 0, 0, sx, 1);
else
screen_write_fast_copy(ctx, &c->status.status, 0, 0, sx, 1);
} }
static struct screen * static struct screen *