From 7310ea029c1ab49d65cdfbdb86265a4225f3403d Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 22 Feb 2021 07:09:06 +0000 Subject: [PATCH] There are many format variables now so allocating all the default ones each time a tree is created is too expensive. Instead, convert them all into callbacks and put them in a static table so they only allocate on demand. The tree remains for the moment for extra (non-default) variables added by for example copy mode or popups. Also reduce expensive calls to localtime_r/strftime. GitHub issue 2253. --- usr.bin/tmux/format.c | 2553 +++++++++++++++++++++++++++++------- usr.bin/tmux/tmux.h | 5 +- usr.bin/tmux/window-copy.c | 8 +- usr.bin/tmux/window.c | 13 +- 4 files changed, 2075 insertions(+), 504 deletions(-) diff --git a/usr.bin/tmux/format.c b/usr.bin/tmux/format.c index cda2f2354a4..d15c0cc513d 100644 --- a/usr.bin/tmux/format.c +++ b/usr.bin/tmux/format.c @@ -1,4 +1,4 @@ -/* $OpenBSD: format.c,v 1.274 2021/02/15 09:39:37 nicm Exp $ */ +/* $OpenBSD: format.c,v 1.275 2021/02/22 07:09:06 nicm Exp $ */ /* * Copyright (c) 2011 Nicholas Marriott @@ -119,13 +119,23 @@ struct format_entry { RB_ENTRY(format_entry) entry; }; -/* Format entry tree. */ +/* Format type. */ +enum format_type { + FORMAT_TYPE_UNKNOWN, + FORMAT_TYPE_SESSION, + FORMAT_TYPE_WINDOW, + FORMAT_TYPE_PANE +}; + struct format_tree { + enum format_type type; + struct client *c; struct session *s; struct winlink *wl; struct window *w; struct window_pane *wp; + struct paste_buffer *pb; struct cmdq_item *item; struct client *client; @@ -144,6 +154,7 @@ struct format_expand_state { struct format_tree *ft; u_int loop; time_t time; + struct tm tm; int flags; }; @@ -263,6 +274,7 @@ format_copy_state(struct format_expand_state *to, to->ft = from->ft; to->loop = from->loop; to->time = from->time; + memcpy(&to->tm, &from->tm, sizeof to->tm); to->flags = from->flags|flags; } @@ -451,8 +463,21 @@ format_job_timer(__unused int fd, __unused short events, __unused void *arg) evtimer_add(&format_job_event, &tv); } +/* Wrapper for asprintf. */ +static char * printflike(1, 2) +format_printf(const char *fmt, ...) +{ + va_list ap; + char *s; + + va_start(ap, fmt); + xvasprintf(&s, fmt, ap); + va_end(ap); + return (s); +} + /* Callback for host. */ -static char * +static void * format_cb_host(__unused struct format_tree *ft) { char host[HOST_NAME_MAX + 1]; @@ -463,7 +488,7 @@ format_cb_host(__unused struct format_tree *ft) } /* Callback for host_short. */ -static char * +static void * format_cb_host_short(__unused struct format_tree *ft) { char host[HOST_NAME_MAX + 1], *cp; @@ -476,7 +501,7 @@ format_cb_host_short(__unused struct format_tree *ft) } /* Callback for pid. */ -static char * +static void * format_cb_pid(__unused struct format_tree *ft) { char *value; @@ -486,7 +511,7 @@ format_cb_pid(__unused struct format_tree *ft) } /* Callback for session_attached_list. */ -static char * +static void * format_cb_session_attached_list(struct format_tree *ft) { struct session *s = ft->s; @@ -517,7 +542,7 @@ format_cb_session_attached_list(struct format_tree *ft) } /* Callback for session_alerts. */ -static char * +static void * format_cb_session_alerts(struct format_tree *ft) { struct session *s = ft->s; @@ -547,7 +572,7 @@ format_cb_session_alerts(struct format_tree *ft) } /* Callback for session_stack. */ -static char * +static void * format_cb_session_stack(struct format_tree *ft) { struct session *s = ft->s; @@ -569,14 +594,18 @@ format_cb_session_stack(struct format_tree *ft) } /* Callback for window_stack_index. */ -static char * +static void * format_cb_window_stack_index(struct format_tree *ft) { - struct session *s = ft->wl->session; + struct session *s; struct winlink *wl; u_int idx; char *value = NULL; + if (ft->wl == NULL) + return (NULL); + s = ft->wl->session; + idx = 0; TAILQ_FOREACH(wl, &s->lastw, sentry) { idx++; @@ -590,15 +619,19 @@ format_cb_window_stack_index(struct format_tree *ft) } /* Callback for window_linked_sessions_list. */ -static char * +static void * format_cb_window_linked_sessions_list(struct format_tree *ft) { - struct window *w = ft->wl->window; + struct window *w; struct winlink *wl; struct evbuffer *buffer; int size; char *value = NULL; + if (ft->wl == NULL) + return (NULL); + w = ft->wl->window; + buffer = evbuffer_new(); if (buffer == NULL) fatalx("out of memory"); @@ -616,14 +649,18 @@ format_cb_window_linked_sessions_list(struct format_tree *ft) } /* Callback for window_active_sessions. */ -static char * +static void * format_cb_window_active_sessions(struct format_tree *ft) { - struct window *w = ft->wl->window; + struct window *w; struct winlink *wl; u_int n = 0; char *value; + if (ft->wl == NULL) + return (NULL); + w = ft->wl->window; + TAILQ_FOREACH(wl, &w->winlinks, wentry) { if (wl->session->curw == wl) n++; @@ -634,15 +671,19 @@ format_cb_window_active_sessions(struct format_tree *ft) } /* Callback for window_active_sessions_list. */ -static char * +static void * format_cb_window_active_sessions_list(struct format_tree *ft) { - struct window *w = ft->wl->window; + struct window *w; struct winlink *wl; struct evbuffer *buffer; int size; char *value = NULL; + if (ft->wl == NULL) + return (NULL); + w = ft->wl->window; + buffer = evbuffer_new(); if (buffer == NULL) fatalx("out of memory"); @@ -662,15 +703,19 @@ format_cb_window_active_sessions_list(struct format_tree *ft) } /* Callback for window_active_clients. */ -static char * +static void * format_cb_window_active_clients(struct format_tree *ft) { - struct window *w = ft->wl->window; + struct window *w; struct client *loop; struct session *client_session; u_int n = 0; char *value; + if (ft->wl == NULL) + return (NULL); + w = ft->wl->window; + TAILQ_FOREACH(loop, &clients, entry) { client_session = loop->session; if (client_session == NULL) @@ -685,16 +730,20 @@ format_cb_window_active_clients(struct format_tree *ft) } /* Callback for window_active_clients_list. */ -static char * +static void * format_cb_window_active_clients_list(struct format_tree *ft) { - struct window *w = ft->wl->window; + struct window *w; struct client *loop; struct session *client_session; struct evbuffer *buffer; int size; char *value = NULL; + if (ft->wl == NULL) + return (NULL); + w = ft->wl->window; + buffer = evbuffer_new(); if (buffer == NULL) fatalx("out of memory"); @@ -718,7 +767,7 @@ format_cb_window_active_clients_list(struct format_tree *ft) } /* Callback for window_layout. */ -static char * +static void * format_cb_window_layout(struct format_tree *ft) { struct window *w = ft->w; @@ -732,7 +781,7 @@ format_cb_window_layout(struct format_tree *ft) } /* Callback for window_visible_layout. */ -static char * +static void * format_cb_window_visible_layout(struct format_tree *ft) { struct window *w = ft->w; @@ -744,7 +793,7 @@ format_cb_window_visible_layout(struct format_tree *ft) } /* Callback for pane_start_command. */ -static char * +static void * format_cb_start_command(struct format_tree *ft) { struct window_pane *wp = ft->wp; @@ -756,7 +805,7 @@ format_cb_start_command(struct format_tree *ft) } /* Callback for pane_current_command. */ -static char * +static void * format_cb_current_command(struct format_tree *ft) { struct window_pane *wp = ft->wp; @@ -780,7 +829,7 @@ format_cb_current_command(struct format_tree *ft) } /* Callback for pane_current_path. */ -static char * +static void * format_cb_current_path(struct format_tree *ft) { struct window_pane *wp = ft->wp; @@ -796,7 +845,7 @@ format_cb_current_path(struct format_tree *ft) } /* Callback for history_bytes. */ -static char * +static void * format_cb_history_bytes(struct format_tree *ft) { struct window_pane *wp = ft->wp; @@ -822,7 +871,7 @@ format_cb_history_bytes(struct format_tree *ft) } /* Callback for history_all_bytes. */ -static char * +static void * format_cb_history_all_bytes(struct format_tree *ft) { struct window_pane *wp = ft->wp; @@ -849,7 +898,7 @@ format_cb_history_all_bytes(struct format_tree *ft) } /* Callback for pane_tabs. */ -static char * +static void * format_cb_pane_tabs(struct format_tree *ft) { struct window_pane *wp = ft->wp; @@ -879,7 +928,7 @@ format_cb_pane_tabs(struct format_tree *ft) } /* Callback for pane_fg. */ -static char * +static void * format_cb_pane_fg(struct format_tree *ft) { struct window_pane *wp = ft->wp; @@ -890,7 +939,7 @@ format_cb_pane_fg(struct format_tree *ft) } /* Callback for pane_bg. */ -static char * +static void * format_cb_pane_bg(struct format_tree *ft) { struct window_pane *wp = ft->wp; @@ -901,7 +950,7 @@ format_cb_pane_bg(struct format_tree *ft) } /* Callback for session_group_list. */ -static char * +static void * format_cb_session_group_list(struct format_tree *ft) { struct session *s = ft->s; @@ -934,7 +983,7 @@ format_cb_session_group_list(struct format_tree *ft) } /* Callback for session_group_attached_list. */ -static char * +static void * format_cb_session_group_attached_list(struct format_tree *ft) { struct session *s = ft->s, *client_session, *session_loop; @@ -974,7 +1023,7 @@ format_cb_session_group_attached_list(struct format_tree *ft) } /* Callback for pane_in_mode. */ -static char * +static void * format_cb_pane_in_mode(struct format_tree *ft) { struct window_pane *wp = ft->wp; @@ -986,13 +1035,13 @@ format_cb_pane_in_mode(struct format_tree *ft) return (NULL); TAILQ_FOREACH(wme, &wp->modes, entry) - n++; + n++; xasprintf(&value, "%u", n); return (value); } /* Callback for pane_at_top. */ -static char * +static void * format_cb_pane_at_top(struct format_tree *ft) { struct window_pane *wp = ft->wp; @@ -1014,7 +1063,7 @@ format_cb_pane_at_top(struct format_tree *ft) } /* Callback for pane_at_bottom. */ -static char * +static void * format_cb_pane_at_bottom(struct format_tree *ft) { struct window_pane *wp = ft->wp; @@ -1036,7 +1085,7 @@ format_cb_pane_at_bottom(struct format_tree *ft) } /* Callback for cursor_character. */ -static char * +static void * format_cb_cursor_character(struct format_tree *ft) { struct window_pane *wp = ft->wp; @@ -1052,153 +1101,1861 @@ format_cb_cursor_character(struct format_tree *ft) return (value); } -/* Return word at given coordinates. Caller frees. */ -char * -format_grid_word(struct grid *gd, u_int x, u_int y) +/* Callback for mouse_word. */ +static void * +format_cb_mouse_word(struct format_tree *ft) { - const struct grid_line *gl; - struct grid_cell gc; - const char *ws; - struct utf8_data *ud = NULL; - u_int end; - size_t size = 0; - int found = 0; - char *s = NULL; + struct window_pane *wp; + struct grid *gd; + u_int x, y; + char *s; - ws = options_get_string(global_s_options, "word-separators"); + if (!ft->m.valid) + return (NULL); + wp = cmd_mouse_pane(&ft->m, NULL, NULL); + if (wp == NULL) + return (NULL); + if (cmd_mouse_at(wp, &ft->m, &x, &y, 0) != 0) + return (NULL); - for (;;) { - grid_get_cell(gd, x, y, &gc); - if (gc.flags & GRID_FLAG_PADDING) - break; - if (utf8_cstrhas(ws, &gc.data)) { - found = 1; - break; - } + if (!TAILQ_EMPTY(&wp->modes)) { + if (TAILQ_FIRST(&wp->modes)->mode == &window_copy_mode || + TAILQ_FIRST(&wp->modes)->mode == &window_view_mode) + return (s = window_copy_get_word(wp, x, y)); + return (NULL); + } + gd = wp->base.grid; + return (format_grid_word(gd, x, gd->hsize + y)); +} - if (x == 0) { - if (y == 0) - break; - gl = grid_peek_line(gd, y - 1); - if (~gl->flags & GRID_LINE_WRAPPED) - break; - y--; - x = grid_line_length(gd, y); - if (x == 0) - break; - } - x--; +/* Callback for mouse_line. */ +static void * +format_cb_mouse_line(struct format_tree *ft) +{ + struct window_pane *wp; + struct grid *gd; + u_int x, y; + + if (!ft->m.valid) + return (NULL); + wp = cmd_mouse_pane(&ft->m, NULL, NULL); + if (wp == NULL) + return (NULL); + if (cmd_mouse_at(wp, &ft->m, &x, &y, 0) != 0) + return (NULL); + + if (!TAILQ_EMPTY(&wp->modes)) { + if (TAILQ_FIRST(&wp->modes)->mode == &window_copy_mode || + TAILQ_FIRST(&wp->modes)->mode == &window_view_mode) + return (window_copy_get_line(wp, y)); + return (NULL); } - for (;;) { - if (found) { - end = grid_line_length(gd, y); - if (end == 0 || x == end - 1) { - if (y == gd->hsize + gd->sy - 1) - break; - gl = grid_peek_line(gd, y); - if (~gl->flags & GRID_LINE_WRAPPED) - break; - y++; - x = 0; - } else - x++; - } - found = 1; + gd = wp->base.grid; + return (format_grid_line(gd, gd->hsize + y)); +} - grid_get_cell(gd, x, y, &gc); - if (gc.flags & GRID_FLAG_PADDING) - break; - if (utf8_cstrhas(ws, &gc.data)) - break; +/* Callback for alternate_on. */ +static void * +format_cb_alternate_on(struct format_tree *ft) +{ + if (ft->wp != NULL) { + if (ft->wp->base.saved_grid != NULL) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} - ud = xreallocarray(ud, size + 2, sizeof *ud); - memcpy(&ud[size++], &gc.data, sizeof *ud); +/* Callback for alternate_saved_x. */ +static void * +format_cb_alternate_saved_x(struct format_tree *ft) +{ + if (ft->wp != NULL) + return (format_printf("%u", ft->wp->base.saved_cx)); + return (NULL); +} + +/* Callback for alternate_saved_y. */ +static void * +format_cb_alternate_saved_y(struct format_tree *ft) +{ + if (ft->wp != NULL) + return (format_printf("%u", ft->wp->base.saved_cy)); + return (NULL); +} + +/* Callback for buffer_name. */ +static void * +format_cb_buffer_name(struct format_tree *ft) +{ + if (ft->pb != NULL) + return (xstrdup(paste_buffer_name(ft->pb))); + return (NULL); +} + +/* Callback for buffer_sample. */ +static void * +format_cb_buffer_sample(struct format_tree *ft) +{ + if (ft->pb != NULL) + return (paste_make_sample(ft->pb)); + return (NULL); +} + +/* Callback for buffer_size. */ +static void * +format_cb_buffer_size(struct format_tree *ft) +{ + size_t size; + + if (ft->pb != NULL) { + paste_buffer_data(ft->pb, &size); + return (format_printf("%zu", size)); } - if (size != 0) { - ud[size].size = 0; - s = utf8_tocstr(ud); - free(ud); + return (NULL); +} + +/* Callback for client_cell_height. */ +static void * +format_cb_client_cell_height(struct format_tree *ft) +{ + if (ft->c != NULL && (ft->c->tty.flags & TTY_STARTED)) + return (format_printf("%u", ft->c->tty.ypixel)); + return (NULL); +} + +/* Callback for client_cell_width. */ +static void * +format_cb_client_cell_width(struct format_tree *ft) +{ + if (ft->c != NULL && (ft->c->tty.flags & TTY_STARTED)) + return (format_printf("%u", ft->c->tty.xpixel)); + return (NULL); +} + +/* Callback for client_control_mode. */ +static void * +format_cb_client_control_mode(struct format_tree *ft) +{ + if (ft->c != NULL) { + if (ft->c->flags & CLIENT_CONTROL) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for client_discarded. */ +static void * +format_cb_client_discarded(struct format_tree *ft) +{ + if (ft->c != NULL) + return (format_printf("%zu", ft->c->discarded)); + return (NULL); +} + +/* Callback for client_flags. */ +static void * +format_cb_client_flags(struct format_tree *ft) +{ + if (ft->c != NULL) + return (xstrdup(server_client_get_flags(ft->c))); + return (NULL); +} + +/* Callback for client_height. */ +static void * +format_cb_client_height(struct format_tree *ft) +{ + if (ft->c != NULL && (ft->c->tty.flags & TTY_STARTED)) + return (format_printf("%u", ft->c->tty.sy)); + return (NULL); +} + +/* Callback for client_key_table. */ +static void * +format_cb_client_key_table(struct format_tree *ft) +{ + if (ft->c != NULL) + return (xstrdup(ft->c->keytable->name)); + return (NULL); +} + +/* Callback for client_last_session. */ +static void * +format_cb_client_last_session(struct format_tree *ft) +{ + if (ft->c != NULL && + ft->c->last_session != NULL && + session_alive(ft->c->last_session)) + return (xstrdup(ft->c->last_session->name)); + return (NULL); +} + +/* Callback for client_name. */ +static void * +format_cb_client_name(struct format_tree *ft) +{ + if (ft->c != NULL) + return (xstrdup(ft->c->name)); + return (NULL); +} + +/* Callback for client_pid. */ +static void * +format_cb_client_pid(struct format_tree *ft) +{ + if (ft->c != NULL) + return (format_printf("%ld", (long)ft->c->pid)); + return (NULL); +} + +/* Callback for client_prefix. */ +static void * +format_cb_client_prefix(struct format_tree *ft) +{ + const char *name; + + if (ft->c != NULL) { + name = server_client_get_key_table(ft->c); + if (strcmp(ft->c->keytable->name, name) == 0) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for client_readonly. */ +static void * +format_cb_client_readonly(struct format_tree *ft) +{ + if (ft->c != NULL) { + if (ft->c->flags & CLIENT_READONLY) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for client_session. */ +static void * +format_cb_client_session(struct format_tree *ft) +{ + if (ft->c != NULL && ft->c->session != NULL) + return (xstrdup(ft->c->session->name)); + return (NULL); +} + +/* Callback for client_termfeatures. */ +static void * +format_cb_client_termfeatures(struct format_tree *ft) +{ + if (ft->c != NULL) + return (xstrdup(tty_get_features(ft->c->term_features))); + return (NULL); +} + +/* Callback for client_termname. */ +static void * +format_cb_client_termname(struct format_tree *ft) +{ + if (ft->c != NULL) + return (xstrdup(ft->c->term_name)); + return (NULL); +} + +/* Callback for client_termtype. */ +static void * +format_cb_client_termtype(struct format_tree *ft) +{ + if (ft->c != NULL) + return (xstrdup(ft->c->term_type)); + return (NULL); +} + +/* Callback for client_tty. */ +static void * +format_cb_client_tty(struct format_tree *ft) +{ + if (ft->c != NULL) + return (xstrdup(ft->c->ttyname)); + return (NULL); +} + +/* Callback for client_utf8. */ +static void * +format_cb_client_utf8(struct format_tree *ft) +{ + if (ft->c != NULL) { + if (ft->c->flags & CLIENT_UTF8) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for client_width. */ +static void * +format_cb_client_width(struct format_tree *ft) +{ + if (ft->c != NULL) + return (format_printf("%u", ft->c->tty.sx)); + return (NULL); +} + +/* Callback for client_written. */ +static void * +format_cb_client_written(struct format_tree *ft) +{ + if (ft->c != NULL) + return (format_printf("%zu", ft->c->written)); + return (NULL); +} + +/* Callback for cursor_flag. */ +static void * +format_cb_cursor_flag(struct format_tree *ft) +{ + if (ft->wp != NULL) { + if (ft->wp->base.mode & MODE_CURSOR) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for cursor_x. */ +static void * +format_cb_cursor_x(struct format_tree *ft) +{ + if (ft->wp != NULL) + return (format_printf("%u", ft->wp->base.cx)); + return (NULL); +} + +/* Callback for cursor_y. */ +static void * +format_cb_cursor_y(struct format_tree *ft) +{ + if (ft->wp != NULL) + return (format_printf("%u", ft->wp->base.cy)); + return (NULL); +} + +/* Callback for history_limit. */ +static void * +format_cb_history_limit(struct format_tree *ft) +{ + if (ft->wp != NULL) + return (format_printf("%u", ft->wp->base.grid->hlimit)); + return (NULL); +} + +/* Callback for history_size. */ +static void * +format_cb_history_size(struct format_tree *ft) +{ + if (ft->wp != NULL) + return (format_printf("%u", ft->wp->base.grid->hsize)); + return (NULL); +} + +/* Callback for insert_flag. */ +static void * +format_cb_insert_flag(struct format_tree *ft) +{ + if (ft->wp != NULL) { + if (ft->wp->base.mode & MODE_INSERT) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for keypad_cursor_flag. */ +static void * +format_cb_keypad_cursor_flag(struct format_tree *ft) +{ + if (ft->wp != NULL) { + if (ft->wp->base.mode & MODE_KCURSOR) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for keypad_flag. */ +static void * +format_cb_keypad_flag(struct format_tree *ft) +{ + if (ft->wp != NULL) { + if (ft->wp->base.mode & MODE_KKEYPAD) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for mouse_all_flag. */ +static void * +format_cb_mouse_all_flag(struct format_tree *ft) +{ + if (ft->wp != NULL) { + if (ft->wp->base.mode & MODE_MOUSE_ALL) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for mouse_any_flag. */ +static void * +format_cb_mouse_any_flag(struct format_tree *ft) +{ + if (ft->wp != NULL) { + if (ft->wp->base.mode & ALL_MOUSE_MODES) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for mouse_button_flag. */ +static void * +format_cb_mouse_button_flag(struct format_tree *ft) +{ + if (ft->wp != NULL) { + if (ft->wp->base.mode & MODE_MOUSE_BUTTON) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for mouse_pane. */ +static void * +format_cb_mouse_pane(struct format_tree *ft) +{ + struct window_pane *wp; + + if (ft->m.valid) { + wp = cmd_mouse_pane(&ft->m, NULL, NULL); + if (wp != NULL) + return (format_printf("%%%u", wp->id)); + return (NULL); + } + return (NULL); +} + +/* Callback for mouse_sgr_flag. */ +static void * +format_cb_mouse_sgr_flag(struct format_tree *ft) +{ + if (ft->wp != NULL) { + if (ft->wp->base.mode & MODE_MOUSE_SGR) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for mouse_standard_flag. */ +static void * +format_cb_mouse_standard_flag(struct format_tree *ft) +{ + if (ft->wp != NULL) { + if (ft->wp->base.mode & MODE_MOUSE_STANDARD) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for mouse_utf8_flag. */ +static void * +format_cb_mouse_utf8_flag(struct format_tree *ft) +{ + if (ft->wp != NULL) { + if (ft->wp->base.mode & MODE_MOUSE_UTF8) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for mouse_x. */ +static void * +format_cb_mouse_x(struct format_tree *ft) +{ + struct window_pane *wp; + u_int x, y; + + if (ft->m.valid) { + wp = cmd_mouse_pane(&ft->m, NULL, NULL); + if (wp != NULL && cmd_mouse_at(wp, &ft->m, &x, &y, 0) == 0) + return (format_printf("%u", x)); + return (NULL); + } + return (NULL); +} + +/* Callback for mouse_y. */ +static void * +format_cb_mouse_y(struct format_tree *ft) +{ + struct window_pane *wp; + u_int x, y; + + if (ft->m.valid) { + wp = cmd_mouse_pane(&ft->m, NULL, NULL); + if (wp != NULL && cmd_mouse_at(wp, &ft->m, &x, &y, 0) == 0) + return (format_printf("%u", y)); + return (NULL); + } + return (NULL); +} + +/* Callback for origin_flag. */ +static void * +format_cb_origin_flag(struct format_tree *ft) +{ + if (ft->wp != NULL) { + if (ft->wp->base.mode & MODE_ORIGIN) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for pane_active. */ +static void * +format_cb_pane_active(struct format_tree *ft) +{ + if (ft->wp != NULL) { + if (ft->wp == ft->wp->window->active) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for pane_at_left. */ +static void * +format_cb_pane_at_left(struct format_tree *ft) +{ + if (ft->wp != NULL) { + if (ft->wp->xoff == 0) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for pane_at_right. */ +static void * +format_cb_pane_at_right(struct format_tree *ft) +{ + if (ft->wp != NULL) { + if (ft->wp->xoff + ft->wp->sx == ft->wp->window->sx) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for pane_bottom. */ +static void * +format_cb_pane_bottom(struct format_tree *ft) +{ + if (ft->wp != NULL) + return (format_printf("%u", ft->wp->yoff + ft->wp->sy - 1)); + return (NULL); +} + +/* Callback for pane_dead. */ +static void * +format_cb_pane_dead(struct format_tree *ft) +{ + if (ft->wp != NULL) { + if (ft->wp->fd == -1) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for pane_dead_status. */ +static void * +format_cb_pane_dead_status(struct format_tree *ft) +{ + struct window_pane *wp = ft->wp; + + if (wp != NULL) { + if ((wp->flags & PANE_STATUSREADY) && WIFEXITED(wp->status)) + return (format_printf("%d", WEXITSTATUS(wp->status))); + return (NULL); + } + return (NULL); +} + +/* Callback for pane_format. */ +static void * +format_cb_pane_format(struct format_tree *ft) +{ + if (ft->type == FORMAT_TYPE_PANE) + return (xstrdup("1")); + return (xstrdup("0")); +} + +/* Callback for pane_height. */ +static void * +format_cb_pane_height(struct format_tree *ft) +{ + if (ft->wp != NULL) + return (format_printf("%u", ft->wp->sy)); + return (NULL); +} + +/* Callback for pane_id. */ +static void * +format_cb_pane_id(struct format_tree *ft) +{ + if (ft->wp != NULL) + return (format_printf("%%%u", ft->wp->id)); + return (NULL); +} + +/* Callback for pane_index. */ +static void * +format_cb_pane_index(struct format_tree *ft) +{ + u_int idx; + + if (ft->wp != NULL && window_pane_index(ft->wp, &idx) == 0) + return (format_printf("%u", idx)); + return (NULL); +} + +/* Callback for pane_input_off. */ +static void * +format_cb_pane_input_off(struct format_tree *ft) +{ + if (ft->wp != NULL) { + if (ft->wp->flags & PANE_INPUTOFF) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for pane_last. */ +static void * +format_cb_pane_last(struct format_tree *ft) +{ + if (ft->wp != NULL) { + if (ft->wp == ft->wp->window->last) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for pane_left. */ +static void * +format_cb_pane_left(struct format_tree *ft) +{ + if (ft->wp != NULL) + return (format_printf("%u", ft->wp->xoff)); + return (NULL); +} + +/* Callback for pane_marked. */ +static void * +format_cb_pane_marked(struct format_tree *ft) +{ + if (ft->wp != NULL) { + if (server_check_marked() && marked_pane.wp == ft->wp) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for pane_marked_set. */ +static void * +format_cb_pane_marked_set(struct format_tree *ft) +{ + if (ft->wp != NULL) { + if (server_check_marked()) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for pane_mode. */ +static void * +format_cb_pane_mode(struct format_tree *ft) +{ + struct window_mode_entry *wme; + + if (ft->wp != NULL) { + wme = TAILQ_FIRST(&ft->wp->modes); + if (wme != NULL) + return (xstrdup(wme->mode->name)); + return (NULL); + } + return (NULL); +} + +/* Callback for pane_path. */ +static void * +format_cb_pane_path(struct format_tree *ft) +{ + if (ft->wp != NULL) { + if (ft->wp->base.path == NULL) + return (xstrdup("")); + return (xstrdup(ft->wp->base.path)); + } + return (NULL); +} + +/* Callback for pane_pid. */ +static void * +format_cb_pane_pid(struct format_tree *ft) +{ + if (ft->wp != NULL) + return (format_printf("%ld", (long)ft->wp->pid)); + return (NULL); +} + +/* Callback for pane_pipe. */ +static void * +format_cb_pane_pipe(struct format_tree *ft) +{ + if (ft->wp != NULL) { + if (ft->wp->pipe_fd != -1) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for pane_right. */ +static void * +format_cb_pane_right(struct format_tree *ft) +{ + if (ft->wp != NULL) + return (format_printf("%u", ft->wp->xoff + ft->wp->sx - 1)); + return (NULL); +} + +/* Callback for pane_search_string. */ +static void * +format_cb_pane_search_string(struct format_tree *ft) +{ + if (ft->wp != NULL) { + if (ft->wp->searchstr == NULL) + return (xstrdup("")); + return (xstrdup(ft->wp->searchstr)); + } + return (NULL); +} + +/* Callback for pane_synchronized. */ +static void * +format_cb_pane_synchronized(struct format_tree *ft) +{ + if (ft->wp != NULL) { + if (options_get_number(ft->wp->options, "synchronize-panes")) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for pane_title. */ +static void * +format_cb_pane_title(struct format_tree *ft) +{ + if (ft->wp != NULL) + return (xstrdup(ft->wp->base.title)); + return (NULL); +} + +/* Callback for pane_top. */ +static void * +format_cb_pane_top(struct format_tree *ft) +{ + if (ft->wp != NULL) + return (format_printf("%u", ft->wp->yoff)); + return (NULL); +} + +/* Callback for pane_tty. */ +static void * +format_cb_pane_tty(struct format_tree *ft) +{ + if (ft->wp != NULL) + return (xstrdup(ft->wp->tty)); + return (NULL); +} + +/* Callback for pane_width. */ +static void * +format_cb_pane_width(struct format_tree *ft) +{ + if (ft->wp != NULL) + return (format_printf("%u", ft->wp->sx)); + return (NULL); +} + +/* Callback for scroll_region_lower. */ +static void * +format_cb_scroll_region_lower(struct format_tree *ft) +{ + if (ft->wp != NULL) + return (format_printf("%u", ft->wp->base.rlower)); + return (NULL); +} + +/* Callback for scroll_region_upper. */ +static void * +format_cb_scroll_region_upper(struct format_tree *ft) +{ + if (ft->wp != NULL) + return (format_printf("%u", ft->wp->base.rupper)); + return (NULL); +} + +/* Callback for session_attached. */ +static void * +format_cb_session_attached(struct format_tree *ft) +{ + if (ft->s != NULL) + return (format_printf("%u", ft->s->attached)); + return (NULL); +} + +/* Callback for session_format. */ +static void * +format_cb_session_format(struct format_tree *ft) +{ + if (ft->type == FORMAT_TYPE_SESSION) + return (xstrdup("1")); + return (xstrdup("0")); +} + +/* Callback for session_group. */ +static void * +format_cb_session_group(struct format_tree *ft) +{ + struct session_group *sg; + + if (ft->s != NULL && (sg = session_group_contains(ft->s)) != NULL) + return (xstrdup(sg->name)); + return (NULL); +} + +/* Callback for session_group_attached. */ +static void * +format_cb_session_group_attached(struct format_tree *ft) +{ + struct session_group *sg; + + if (ft->s != NULL && (sg = session_group_contains(ft->s)) != NULL) + return (format_printf("%u", session_group_attached_count (sg))); + return (NULL); +} + +/* Callback for session_group_many_attached. */ +static void * +format_cb_session_group_many_attached(struct format_tree *ft) +{ + struct session_group *sg; + + if (ft->s != NULL && (sg = session_group_contains(ft->s)) != NULL) { + if (session_group_attached_count (sg) > 1) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for session_group_size. */ +static void * +format_cb_session_group_size(struct format_tree *ft) +{ + struct session_group *sg; + + if (ft->s != NULL && (sg = session_group_contains(ft->s)) != NULL) + return (format_printf("%u", session_group_count (sg))); + return (NULL); +} + +/* Callback for session_grouped. */ +static void * +format_cb_session_grouped(struct format_tree *ft) +{ + if (ft->s != NULL) { + if (session_group_contains(ft->s) != NULL) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for session_id. */ +static void * +format_cb_session_id(struct format_tree *ft) +{ + if (ft->s != NULL) + return (format_printf("$%u", ft->s->id)); + return (NULL); +} + +/* Callback for session_many_attached. */ +static void * +format_cb_session_many_attached(struct format_tree *ft) +{ + if (ft->s != NULL) { + if (ft->s->attached > 1) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for session_marked. */ +static void * +format_cb_session_marked(struct format_tree *ft) +{ + if (ft->s != NULL) { + if (server_check_marked() && marked_pane.s == ft->s) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for session_name. */ +static void * +format_cb_session_name(struct format_tree *ft) +{ + if (ft->s != NULL) + return (xstrdup(ft->s->name)); + return (NULL); +} + +/* Callback for session_path. */ +static void * +format_cb_session_path(struct format_tree *ft) +{ + if (ft->s != NULL) + return (xstrdup(ft->s->cwd)); + return (NULL); +} + +/* Callback for session_windows. */ +static void * +format_cb_session_windows(struct format_tree *ft) +{ + if (ft->s != NULL) + return (format_printf ("%u", winlink_count(&ft->s->windows))); + return (NULL); +} + +/* Callback for socket_path. */ +static void * +format_cb_socket_path(__unused struct format_tree *ft) +{ + return (xstrdup(socket_path)); +} + +/* Callback for version. */ +static void * +format_cb_version(__unused struct format_tree *ft) +{ + return (xstrdup(getversion())); +} + +/* Callback for window_active. */ +static void * +format_cb_window_active(struct format_tree *ft) +{ + if (ft->wl != NULL) { + if (ft->wl == ft->wl->session->curw) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for window_activity_flag. */ +static void * +format_cb_window_activity_flag(struct format_tree *ft) +{ + if (ft->wl != NULL) { + if (ft->wl->flags & WINLINK_ACTIVITY) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for window_bell_flag. */ +static void * +format_cb_window_bell_flag(struct format_tree *ft) +{ + if (ft->wl != NULL) { + if (ft->wl->flags & WINLINK_BELL) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for window_bigger. */ +static void * +format_cb_window_bigger(struct format_tree *ft) +{ + u_int ox, oy, sx, sy; + + if (ft->c != NULL) { + if (tty_window_offset(&ft->c->tty, &ox, &oy, &sx, &sy)) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for window_cell_height. */ +static void * +format_cb_window_cell_height(struct format_tree *ft) +{ + if (ft->w != NULL) + return (format_printf("%u", ft->w->ypixel)); + return (NULL); +} + +/* Callback for window_cell_width. */ +static void * +format_cb_window_cell_width(struct format_tree *ft) +{ + if (ft->w != NULL) + return (format_printf("%u", ft->w->xpixel)); + return (NULL); +} + +/* Callback for window_end_flag. */ +static void * +format_cb_window_end_flag(struct format_tree *ft) +{ + if (ft->wl != NULL) { + if (ft->wl == RB_MAX(winlinks, &ft->wl->session->windows)) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for window_flags. */ +static void * +format_cb_window_flags(struct format_tree *ft) +{ + if (ft->wl != NULL) + return (xstrdup(window_printable_flags(ft->wl, 1))); + return (NULL); +} + +/* Callback for window_format. */ +static void * +format_cb_window_format(struct format_tree *ft) +{ + if (ft->type == FORMAT_TYPE_WINDOW) + return (xstrdup("1")); + return (xstrdup("0")); +} + +/* Callback for window_height. */ +static void * +format_cb_window_height(struct format_tree *ft) +{ + if (ft->w != NULL) + return (format_printf("%u", ft->w->sy)); + return (NULL); +} + +/* Callback for window_id. */ +static void * +format_cb_window_id(struct format_tree *ft) +{ + if (ft->w != NULL) + return (format_printf("@%u", ft->w->id)); + return (NULL); +} + +/* Callback for window_index. */ +static void * +format_cb_window_index(struct format_tree *ft) +{ + if (ft->wl != NULL) + return (format_printf("%d", ft->wl->idx)); + return (NULL); +} + +/* Callback for window_last_flag. */ +static void * +format_cb_window_last_flag(struct format_tree *ft) +{ + if (ft->wl != NULL) { + if (ft->wl == TAILQ_FIRST(&ft->wl->session->lastw)) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for window_linked. */ +static void * +format_cb_window_linked(struct format_tree *ft) +{ + if (ft->wl != NULL) { + if (session_is_linked(ft->wl->session, ft->wl->window)) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for window_linked_sessions. */ +static void * +format_cb_window_linked_sessions(struct format_tree *ft) +{ + if (ft->wl != NULL) + return (format_printf("%u", ft->wl->window->references)); + return (NULL); +} + +/* Callback for window_marked_flag. */ +static void * +format_cb_window_marked_flag(struct format_tree *ft) +{ + if (ft->wl != NULL) { + if (server_check_marked() && marked_pane.wl == ft->wl) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for window_name. */ +static void * +format_cb_window_name(struct format_tree *ft) +{ + if (ft->w != NULL) + return (format_printf("%s", ft->w->name)); + return (NULL); +} + +/* Callback for window_offset_x. */ +static void * +format_cb_window_offset_x(struct format_tree *ft) +{ + u_int ox, oy, sx, sy; + + if (ft->c != NULL) { + if (tty_window_offset(&ft->c->tty, &ox, &oy, &sx, &sy)) + return (format_printf("%u", ox)); + return (NULL); + } + return (NULL); +} + +/* Callback for window_offset_y. */ +static void * +format_cb_window_offset_y(struct format_tree *ft) +{ + u_int ox, oy, sx, sy; + + if (ft->c != NULL) { + if (tty_window_offset(&ft->c->tty, &ox, &oy, &sx, &sy)) + return (format_printf("%u", oy)); + return (NULL); + } + return (NULL); +} + +/* Callback for window_panes. */ +static void * +format_cb_window_panes(struct format_tree *ft) +{ + if (ft->w != NULL) + return (format_printf("%u", window_count_panes(ft->w))); + return (NULL); +} + +/* Callback for window_raw_flags. */ +static void * +format_cb_window_raw_flags(struct format_tree *ft) +{ + if (ft->wl != NULL) + return (xstrdup(window_printable_flags(ft->wl, 0))); + return (NULL); +} + +/* Callback for window_silence_flag. */ +static void * +format_cb_window_silence_flag(struct format_tree *ft) +{ + if (ft->wl != NULL) { + if (ft->wl->flags & WINLINK_SILENCE) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for window_start_flag. */ +static void * +format_cb_window_start_flag(struct format_tree *ft) +{ + if (ft->wl != NULL) { + if (ft->wl == RB_MIN(winlinks, &ft->wl->session->windows)) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for window_width. */ +static void * +format_cb_window_width(struct format_tree *ft) +{ + if (ft->w != NULL) + return (format_printf("%u", ft->w->sx)); + return (NULL); +} + +/* Callback for window_zoomed_flag. */ +static void * +format_cb_window_zoomed_flag(struct format_tree *ft) +{ + if (ft->w != NULL) { + if (ft->w->flags & WINDOW_ZOOMED) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for wrap_flag. */ +static void * +format_cb_wrap_flag(struct format_tree *ft) +{ + if (ft->wp != NULL) { + if (ft->wp->base.mode & MODE_WRAP) + return (xstrdup("1")); + return (xstrdup("0")); + } + return (NULL); +} + +/* Callback for buffer_created. */ +static void * +format_cb_buffer_created(struct format_tree *ft) +{ + static struct timeval tv; + + if (ft->pb != NULL) { + timerclear(&tv); + tv.tv_sec = paste_buffer_created(ft->pb); + return (&tv); } - return (s); + return (NULL); } -/* Callback for mouse_word. */ -static char * -format_cb_mouse_word(struct format_tree *ft) +/* Callback for client_activity. */ +static void * +format_cb_client_activity(struct format_tree *ft) { - struct window_pane *wp; - struct grid *gd; - u_int x, y; - char *s; + if (ft->c != NULL) + return (&ft->c->activity_time); + return (NULL); +} - if (!ft->m.valid) - return (NULL); - wp = cmd_mouse_pane(&ft->m, NULL, NULL); - if (wp == NULL) - return (NULL); - if (cmd_mouse_at(wp, &ft->m, &x, &y, 0) != 0) - return (NULL); +/* Callback for client_created. */ +static void * +format_cb_client_created(struct format_tree *ft) +{ + if (ft->c != NULL) + return (&ft->c->creation_time); + return (NULL); +} - if (!TAILQ_EMPTY(&wp->modes)) { - if (TAILQ_FIRST(&wp->modes)->mode == &window_copy_mode || - TAILQ_FIRST(&wp->modes)->mode == &window_view_mode) - return (s = window_copy_get_word(wp, x, y)); - return (NULL); - } - gd = wp->base.grid; - return (format_grid_word(gd, x, gd->hsize + y)); +/* Callback for session_activity. */ +static void * +format_cb_session_activity(struct format_tree *ft) +{ + if (ft->s != NULL) + return (&ft->s->activity_time); + return (NULL); } -/* Return line at given coordinates. Caller frees. */ -char * -format_grid_line(struct grid *gd, u_int y) +/* Callback for session_created. */ +static void * +format_cb_session_created(struct format_tree *ft) { - struct grid_cell gc; - struct utf8_data *ud = NULL; - u_int x; - size_t size = 0; - char *s = NULL; + if (ft->s != NULL) + return (&ft->s->creation_time); + return (NULL); +} - for (x = 0; x < grid_line_length(gd, y); x++) { - grid_get_cell(gd, x, y, &gc); - if (gc.flags & GRID_FLAG_PADDING) - break; +/* Callback for session_last_attached. */ +static void * +format_cb_session_last_attached(struct format_tree *ft) +{ + if (ft->s != NULL) + return (&ft->s->last_attached_time); + return (NULL); +} - ud = xreallocarray(ud, size + 2, sizeof *ud); - memcpy(&ud[size++], &gc.data, sizeof *ud); - } - if (size != 0) { - ud[size].size = 0; - s = utf8_tocstr(ud); - free(ud); - } - return (s); +/* Callback for start_time. */ +static void * +format_cb_start_time(__unused struct format_tree *ft) +{ + return (&start_time); } -/* Callback for mouse_line. */ -static char * -format_cb_mouse_line(struct format_tree *ft) +/* Callback for window_activity. */ +static void * +format_cb_window_activity(struct format_tree *ft) { - struct window_pane *wp; - struct grid *gd; - u_int x, y; + if (ft->w != NULL) + return (&ft->w->activity_time); + return (NULL); +} - if (!ft->m.valid) - return (NULL); - wp = cmd_mouse_pane(&ft->m, NULL, NULL); - if (wp == NULL) - return (NULL); - if (cmd_mouse_at(wp, &ft->m, &x, &y, 0) != 0) - return (NULL); +/* Callback for buffer_mode_format, */ +static void * +format_cb_buffer_mode_format(__unused struct format_tree *ft) +{ + return (xstrdup(window_buffer_mode.default_format)); +} - if (!TAILQ_EMPTY(&wp->modes)) { - if (TAILQ_FIRST(&wp->modes)->mode == &window_copy_mode || - TAILQ_FIRST(&wp->modes)->mode == &window_view_mode) - return (window_copy_get_line(wp, y)); - return (NULL); +/* Callback for client_mode_format, */ +static void * +format_cb_client_mode_format(__unused struct format_tree *ft) +{ + return (xstrdup(window_client_mode.default_format)); +} + +/* Callback for tree_mode_format, */ +static void * +format_cb_tree_mode_format(__unused struct format_tree *ft) +{ + return (xstrdup(window_tree_mode.default_format)); +} + +/* Format table type. */ +enum format_table_type { + FORMAT_TABLE_STRING, + FORMAT_TABLE_TIME +}; + +/* Format table entry. */ +struct format_table_entry { + const char *key; + enum format_table_type type; + format_cb cb; +}; + +/* + * Format table. Default format variables (that are almost always in the tree + * and where the value is expanded by a callback in this file) are listed here. + * Only variables which are added by the caller go into the tree. + */ +static const struct format_table_entry format_table[] = { + { "alternate_on", FORMAT_TABLE_STRING, + format_cb_alternate_on + }, + { "alternate_saved_x", FORMAT_TABLE_STRING, + format_cb_alternate_saved_x + }, + { "alternate_saved_y", FORMAT_TABLE_STRING, + format_cb_alternate_saved_y + }, + { "buffer_created", FORMAT_TABLE_TIME, + format_cb_buffer_created + }, + { "buffer_mode_format", FORMAT_TABLE_STRING, + format_cb_buffer_mode_format + }, + { "buffer_name", FORMAT_TABLE_STRING, + format_cb_buffer_name + }, + { "buffer_sample", FORMAT_TABLE_STRING, + format_cb_buffer_sample + }, + { "buffer_size", FORMAT_TABLE_STRING, + format_cb_buffer_size + }, + { "client_activity", FORMAT_TABLE_TIME, + format_cb_client_activity + }, + { "client_cell_height", FORMAT_TABLE_STRING, + format_cb_client_cell_height + }, + { "client_cell_width", FORMAT_TABLE_STRING, + format_cb_client_cell_width + }, + { "client_control_mode", FORMAT_TABLE_STRING, + format_cb_client_control_mode + }, + { "client_created", FORMAT_TABLE_TIME, + format_cb_client_created + }, + { "client_discarded", FORMAT_TABLE_STRING, + format_cb_client_discarded + }, + { "client_flags", FORMAT_TABLE_STRING, + format_cb_client_flags + }, + { "client_height", FORMAT_TABLE_STRING, + format_cb_client_height + }, + { "client_key_table", FORMAT_TABLE_STRING, + format_cb_client_key_table + }, + { "client_last_session", FORMAT_TABLE_STRING, + format_cb_client_last_session + }, + { "client_mode_format", FORMAT_TABLE_STRING, + format_cb_client_mode_format + }, + { "client_name", FORMAT_TABLE_STRING, + format_cb_client_name + }, + { "client_pid", FORMAT_TABLE_STRING, + format_cb_client_pid + }, + { "client_prefix", FORMAT_TABLE_STRING, + format_cb_client_prefix + }, + { "client_readonly", FORMAT_TABLE_STRING, + format_cb_client_readonly + }, + { "client_session", FORMAT_TABLE_STRING, + format_cb_client_session + }, + { "client_termfeatures", FORMAT_TABLE_STRING, + format_cb_client_termfeatures + }, + { "client_termname", FORMAT_TABLE_STRING, + format_cb_client_termname + }, + { "client_termtype", FORMAT_TABLE_STRING, + format_cb_client_termtype + }, + { "client_tty", FORMAT_TABLE_STRING, + format_cb_client_tty + }, + { "client_utf8", FORMAT_TABLE_STRING, + format_cb_client_utf8 + }, + { "client_width", FORMAT_TABLE_STRING, + format_cb_client_width + }, + { "client_written", FORMAT_TABLE_STRING, + format_cb_client_written + }, + { "cursor_character", FORMAT_TABLE_STRING, + format_cb_cursor_character + }, + { "cursor_flag", FORMAT_TABLE_STRING, + format_cb_cursor_flag + }, + { "cursor_x", FORMAT_TABLE_STRING, + format_cb_cursor_x + }, + { "cursor_y", FORMAT_TABLE_STRING, + format_cb_cursor_y + }, + { "history_all_bytes", FORMAT_TABLE_STRING, + format_cb_history_all_bytes + }, + { "history_bytes", FORMAT_TABLE_STRING, + format_cb_history_bytes + }, + { "history_limit", FORMAT_TABLE_STRING, + format_cb_history_limit + }, + { "history_size", FORMAT_TABLE_STRING, + format_cb_history_size + }, + { "host", FORMAT_TABLE_STRING, + format_cb_host + }, + { "host_short", FORMAT_TABLE_STRING, + format_cb_host_short + }, + { "insert_flag", FORMAT_TABLE_STRING, + format_cb_insert_flag + }, + { "keypad_cursor_flag", FORMAT_TABLE_STRING, + format_cb_keypad_cursor_flag + }, + { "keypad_flag", FORMAT_TABLE_STRING, + format_cb_keypad_flag + }, + { "mouse_all_flag", FORMAT_TABLE_STRING, + format_cb_mouse_all_flag + }, + { "mouse_any_flag", FORMAT_TABLE_STRING, + format_cb_mouse_any_flag + }, + { "mouse_button_flag", FORMAT_TABLE_STRING, + format_cb_mouse_button_flag + }, + { "mouse_line", FORMAT_TABLE_STRING, + format_cb_mouse_line + }, + { "mouse_pane", FORMAT_TABLE_STRING, + format_cb_mouse_pane + }, + { "mouse_sgr_flag", FORMAT_TABLE_STRING, + format_cb_mouse_sgr_flag + }, + { "mouse_standard_flag", FORMAT_TABLE_STRING, + format_cb_mouse_standard_flag + }, + { "mouse_utf8_flag", FORMAT_TABLE_STRING, + format_cb_mouse_utf8_flag + }, + { "mouse_word", FORMAT_TABLE_STRING, + format_cb_mouse_word + }, + { "mouse_x", FORMAT_TABLE_STRING, + format_cb_mouse_x + }, + { "mouse_y", FORMAT_TABLE_STRING, + format_cb_mouse_y + }, + { "origin_flag", FORMAT_TABLE_STRING, + format_cb_origin_flag + }, + { "pane_active", FORMAT_TABLE_STRING, + format_cb_pane_active + }, + { "pane_at_bottom", FORMAT_TABLE_STRING, + format_cb_pane_at_bottom + }, + { "pane_at_left", FORMAT_TABLE_STRING, + format_cb_pane_at_left + }, + { "pane_at_right", FORMAT_TABLE_STRING, + format_cb_pane_at_right + }, + { "pane_at_top", FORMAT_TABLE_STRING, + format_cb_pane_at_top + }, + { "pane_bg", FORMAT_TABLE_STRING, + format_cb_pane_bg + }, + { "pane_bottom", FORMAT_TABLE_STRING, + format_cb_pane_bottom + }, + { "pane_current_command", FORMAT_TABLE_STRING, + format_cb_current_command + }, + { "pane_current_path", FORMAT_TABLE_STRING, + format_cb_current_path + }, + { "pane_dead", FORMAT_TABLE_STRING, + format_cb_pane_dead + }, + { "pane_dead_status", FORMAT_TABLE_STRING, + format_cb_pane_dead_status + }, + { "pane_fg", FORMAT_TABLE_STRING, + format_cb_pane_fg + }, + { "pane_format", FORMAT_TABLE_STRING, + format_cb_pane_format + }, + { "pane_height", FORMAT_TABLE_STRING, + format_cb_pane_height + }, + { "pane_id", FORMAT_TABLE_STRING, + format_cb_pane_id + }, + { "pane_in_mode", FORMAT_TABLE_STRING, + format_cb_pane_in_mode + }, + { "pane_index", FORMAT_TABLE_STRING, + format_cb_pane_index + }, + { "pane_input_off", FORMAT_TABLE_STRING, + format_cb_pane_input_off + }, + { "pane_last", FORMAT_TABLE_STRING, + format_cb_pane_last + }, + { "pane_left", FORMAT_TABLE_STRING, + format_cb_pane_left + }, + { "pane_marked", FORMAT_TABLE_STRING, + format_cb_pane_marked + }, + { "pane_marked_set", FORMAT_TABLE_STRING, + format_cb_pane_marked_set + }, + { "pane_mode", FORMAT_TABLE_STRING, + format_cb_pane_mode + }, + { "pane_path", FORMAT_TABLE_STRING, + format_cb_pane_path + }, + { "pane_pid", FORMAT_TABLE_STRING, + format_cb_pane_pid + }, + { "pane_pipe", FORMAT_TABLE_STRING, + format_cb_pane_pipe + }, + { "pane_right", FORMAT_TABLE_STRING, + format_cb_pane_right + }, + { "pane_search_string", FORMAT_TABLE_STRING, + format_cb_pane_search_string + }, + { "pane_start_command", FORMAT_TABLE_STRING, + format_cb_start_command + }, + { "pane_synchronized", FORMAT_TABLE_STRING, + format_cb_pane_synchronized + }, + { "pane_tabs", FORMAT_TABLE_STRING, + format_cb_pane_tabs + }, + { "pane_title", FORMAT_TABLE_STRING, + format_cb_pane_title + }, + { "pane_top", FORMAT_TABLE_STRING, + format_cb_pane_top + }, + { "pane_tty", FORMAT_TABLE_STRING, + format_cb_pane_tty + }, + { "pane_width", FORMAT_TABLE_STRING, + format_cb_pane_width + }, + { "pid", FORMAT_TABLE_STRING, + format_cb_pid + }, + { "scroll_region_lower", FORMAT_TABLE_STRING, + format_cb_scroll_region_lower + }, + { "scroll_region_upper", FORMAT_TABLE_STRING, + format_cb_scroll_region_upper + }, + { "session_activity", FORMAT_TABLE_TIME, + format_cb_session_activity + }, + { "session_alerts", FORMAT_TABLE_STRING, + format_cb_session_alerts + }, + { "session_attached", FORMAT_TABLE_STRING, + format_cb_session_attached + }, + { "session_attached_list", FORMAT_TABLE_STRING, + format_cb_session_attached_list + }, + { "session_created", FORMAT_TABLE_TIME, + format_cb_session_created + }, + { "session_format", FORMAT_TABLE_STRING, + format_cb_session_format + }, + { "session_group", FORMAT_TABLE_STRING, + format_cb_session_group + }, + { "session_group_attached", FORMAT_TABLE_STRING, + format_cb_session_group_attached + }, + { "session_group_attached_list", FORMAT_TABLE_STRING, + format_cb_session_group_attached_list + }, + { "session_group_list", FORMAT_TABLE_STRING, + format_cb_session_group_list + }, + { "session_group_many_attached", FORMAT_TABLE_STRING, + format_cb_session_group_many_attached + }, + { "session_group_size", FORMAT_TABLE_STRING, + format_cb_session_group_size + }, + { "session_grouped", FORMAT_TABLE_STRING, + format_cb_session_grouped + }, + { "session_id", FORMAT_TABLE_STRING, + format_cb_session_id + }, + { "session_last_attached", FORMAT_TABLE_TIME, + format_cb_session_last_attached + }, + { "session_many_attached", FORMAT_TABLE_STRING, + format_cb_session_many_attached + }, + { "session_marked", FORMAT_TABLE_STRING, + format_cb_session_marked, + }, + { "session_name", FORMAT_TABLE_STRING, + format_cb_session_name + }, + { "session_path", FORMAT_TABLE_STRING, + format_cb_session_path + }, + { "session_stack", FORMAT_TABLE_STRING, + format_cb_session_stack + }, + { "session_windows", FORMAT_TABLE_STRING, + format_cb_session_windows + }, + { "socket_path", FORMAT_TABLE_STRING, + format_cb_socket_path + }, + { "start_time", FORMAT_TABLE_TIME, + format_cb_start_time + }, + { "tree_mode_format", FORMAT_TABLE_STRING, + format_cb_tree_mode_format + }, + { "version", FORMAT_TABLE_STRING, + format_cb_version + }, + { "window_active", FORMAT_TABLE_STRING, + format_cb_window_active + }, + { "window_active_clients", FORMAT_TABLE_STRING, + format_cb_window_active_clients + }, + { "window_active_clients_list", FORMAT_TABLE_STRING, + format_cb_window_active_clients_list + }, + { "window_active_sessions", FORMAT_TABLE_STRING, + format_cb_window_active_sessions + }, + { "window_active_sessions_list", FORMAT_TABLE_STRING, + format_cb_window_active_sessions_list + }, + { "window_activity", FORMAT_TABLE_TIME, + format_cb_window_activity + }, + { "window_activity_flag", FORMAT_TABLE_STRING, + format_cb_window_activity_flag + }, + { "window_bell_flag", FORMAT_TABLE_STRING, + format_cb_window_bell_flag + }, + { "window_bigger", FORMAT_TABLE_STRING, + format_cb_window_bigger + }, + { "window_cell_height", FORMAT_TABLE_STRING, + format_cb_window_cell_height + }, + { "window_cell_width", FORMAT_TABLE_STRING, + format_cb_window_cell_width + }, + { "window_end_flag", FORMAT_TABLE_STRING, + format_cb_window_end_flag + }, + { "window_flags", FORMAT_TABLE_STRING, + format_cb_window_flags + }, + { "window_format", FORMAT_TABLE_STRING, + format_cb_window_format + }, + { "window_height", FORMAT_TABLE_STRING, + format_cb_window_height + }, + { "window_id", FORMAT_TABLE_STRING, + format_cb_window_id + }, + { "window_index", FORMAT_TABLE_STRING, + format_cb_window_index + }, + { "window_last_flag", FORMAT_TABLE_STRING, + format_cb_window_last_flag + }, + { "window_layout", FORMAT_TABLE_STRING, + format_cb_window_layout + }, + { "window_linked", FORMAT_TABLE_STRING, + format_cb_window_linked + }, + { "window_linked_sessions", FORMAT_TABLE_STRING, + format_cb_window_linked_sessions + }, + { "window_linked_sessions_list", FORMAT_TABLE_STRING, + format_cb_window_linked_sessions_list + }, + { "window_marked_flag", FORMAT_TABLE_STRING, + format_cb_window_marked_flag + }, + { "window_name", FORMAT_TABLE_STRING, + format_cb_window_name + }, + { "window_offset_x", FORMAT_TABLE_STRING, + format_cb_window_offset_x + }, + { "window_offset_y", FORMAT_TABLE_STRING, + format_cb_window_offset_y + }, + { "window_panes", FORMAT_TABLE_STRING, + format_cb_window_panes + }, + { "window_raw_flags", FORMAT_TABLE_STRING, + format_cb_window_raw_flags + }, + { "window_silence_flag", FORMAT_TABLE_STRING, + format_cb_window_silence_flag + }, + { "window_stack_index", FORMAT_TABLE_STRING, + format_cb_window_stack_index + }, + { "window_start_flag", FORMAT_TABLE_STRING, + format_cb_window_start_flag + }, + { "window_visible_layout", FORMAT_TABLE_STRING, + format_cb_window_visible_layout + }, + { "window_width", FORMAT_TABLE_STRING, + format_cb_window_width + }, + { "window_zoomed_flag", FORMAT_TABLE_STRING, + format_cb_window_zoomed_flag + }, + { "wrap_flag", FORMAT_TABLE_STRING, + format_cb_wrap_flag } - gd = wp->base.grid; - return (format_grid_line(gd, gd->hsize + y)); +}; + +/* Compare format table entries. */ +static int +format_table_compare(const void *key0, const void *entry0) +{ + const char *key = key0; + const struct format_table_entry *entry = entry0; + + return (strcmp(key, entry->key)); +} + +/* Get a format callback. */ +static struct format_table_entry * +format_table_get(const char *key) +{ + return (bsearch(key, format_table, nitems(format_table), + sizeof *format_table, format_table_compare)); } /* Merge one format tree into another. */ @@ -1226,20 +2983,8 @@ format_create_add_item(struct format_tree *ft, struct cmdq_item *item) { struct key_event *event = cmdq_get_event(item); struct mouse_event *m = &event->m; - struct window_pane *wp; - u_int x, y; cmdq_merge_formats(item, ft); - - if (m->valid && ((wp = cmd_mouse_pane(m, NULL, NULL)) != NULL)) { - format_add(ft, "mouse_pane", "%%%u", wp->id); - if (cmd_mouse_at(wp, m, &x, &y, 0) == 0) { - format_add(ft, "mouse_x", "%u", x); - format_add(ft, "mouse_y", "%u", y); - format_add_cb(ft, "mouse_word", format_cb_mouse_word); - format_add_cb(ft, "mouse_line", format_cb_mouse_line); - } - } memcpy(&ft->m, m, sizeof ft->m); } @@ -1247,9 +2992,7 @@ format_create_add_item(struct format_tree *ft, struct cmdq_item *item) struct format_tree * format_create(struct client *c, struct cmdq_item *item, int tag, int flags) { - struct format_tree *ft; - const struct window_mode **wm; - char tmp[64]; + struct format_tree *ft; if (!event_initialized(&format_job_event)) { evtimer_set(&format_job_event, format_job_timer, NULL); @@ -1268,21 +3011,6 @@ format_create(struct client *c, struct cmdq_item *item, int tag, int flags) ft->tag = tag; ft->flags = flags; - format_add(ft, "version", "%s", getversion()); - format_add_cb(ft, "host", format_cb_host); - format_add_cb(ft, "host_short", format_cb_host_short); - format_add_cb(ft, "pid", format_cb_pid); - format_add(ft, "socket_path", "%s", socket_path); - format_add_tv(ft, "start_time", &start_time); - - for (wm = all_window_modes; *wm != NULL; wm++) { - if ((*wm)->default_format != NULL) { - xsnprintf(tmp, sizeof tmp, "%s_format", (*wm)->name); - tmp[strcspn(tmp, "-")] = '_'; - format_add(ft, tmp, "%s", (*wm)->default_format); - } - } - if (item != NULL) format_create_add_item(ft, item); @@ -1312,9 +3040,28 @@ void format_each(struct format_tree *ft, void (*cb)(const char *, const char *, void *), void *arg) { - struct format_entry *fe; - char s[64]; + const struct format_table_entry *fte; + struct format_entry *fe; + u_int i; + char s[64]; + void *value; + struct timeval *tv; + + for (i = 0; i < nitems(format_table); i++) { + fte = &format_table[i]; + value = fte->cb(ft); + if (value == NULL) + continue; + if (fte->type == FORMAT_TABLE_TIME) { + tv = value; + xsnprintf(s, sizeof s, "%lld", (long long)tv->tv_sec); + cb(fte->key, s, arg); + } else { + cb(fte->key, value, arg); + free(value); + } + } RB_FOREACH(fe, format_entry_tree, &ft->tree) { if (fe->time != 0) { xsnprintf(s, sizeof s, "%lld", (long long)fe->time); @@ -1484,14 +3231,16 @@ static char * format_find(struct format_tree *ft, const char *key, int modifiers, const char *time_format) { - struct format_entry *fe, fe_find; - struct environ_entry *envent; - struct options_entry *o; - int idx; - char *found = NULL, *saved, s[512]; - const char *errstr; - time_t t = 0; - struct tm tm; + struct format_table_entry *fte; + void *value; + struct format_entry *fe, fe_find; + struct environ_entry *envent; + struct options_entry *o; + int idx; + char *found = NULL, *saved, s[512]; + const char *errstr; + time_t t = 0; + struct tm tm; o = options_parse_get(global_options, key, &idx, 0); if (o == NULL && ft->wp != NULL) @@ -1509,6 +3258,15 @@ format_find(struct format_tree *ft, const char *key, int modifiers, goto found; } + fte = format_table_get(key); + if (fte != NULL) { + value = fte->cb(ft); + if (fte->type == FORMAT_TABLE_TIME) + t = ((struct timeval *)value)->tv_sec; + else + found = value; + goto found; + } fe_find.key = (char *)key; fe = RB_FIND(format_entry_tree, &ft->tree, &fe_find); if (fe != NULL) { @@ -2619,7 +4377,6 @@ format_expand1(struct format_expand_state *es, const char *fmt) const char *ptr, *s; size_t off, len, n, outlen; int ch, brackets; - struct tm *tm; char expanded[8192]; if (fmt == NULL || *fmt == '\0') @@ -2631,11 +4388,12 @@ format_expand1(struct format_expand_state *es, const char *fmt) format_log(es, "expanding format: %s", fmt); - if (es->flags & FORMAT_EXPAND_TIME) { - if (es->time == 0) + if ((es->flags & FORMAT_EXPAND_TIME) && strchr(fmt, '%') != NULL) { + if (es->time == 0) { es->time = time(NULL); - tm = localtime(&es->time); - if (strftime(expanded, sizeof expanded, fmt, tm) == 0) { + localtime_r(&es->time, &es->tm); + } + if (strftime(expanded, sizeof expanded, fmt, &es->tm) == 0) { format_log(es, "format is too long"); return (xstrdup("")); } @@ -2887,9 +4645,14 @@ format_defaults(struct format_tree *ft, struct client *c, struct session *s, if (c != NULL && s != NULL && c->session != s) log_debug("%s: session does not match", __func__); - format_add(ft, "session_format", "%d", s != NULL); - format_add(ft, "window_format", "%d", wl != NULL); - format_add(ft, "pane_format", "%d", wp != NULL); + if (s != NULL) + ft->type = FORMAT_TYPE_SESSION; + else if (wl != NULL) + ft->type = FORMAT_TYPE_WINDOW; + else if (wp != NULL) + ft->type = FORMAT_TYPE_PANE; + else + ft->type = FORMAT_TYPE_UNKNOWN; if (s == NULL && c != NULL) s = c->session; @@ -2916,106 +4679,16 @@ format_defaults(struct format_tree *ft, struct client *c, struct session *s, static void format_defaults_session(struct format_tree *ft, struct session *s) { - struct session_group *sg; - ft->s = s; - - format_add(ft, "session_name", "%s", s->name); - format_add(ft, "session_path", "%s", s->cwd); - format_add(ft, "session_windows", "%u", winlink_count(&s->windows)); - format_add(ft, "session_id", "$%u", s->id); - - sg = session_group_contains(s); - format_add(ft, "session_grouped", "%d", sg != NULL); - if (sg != NULL) { - format_add(ft, "session_group", "%s", sg->name); - format_add(ft, "session_group_size", "%u", - session_group_count (sg)); - format_add(ft, "session_group_attached", "%u", - session_group_attached_count (sg)); - format_add(ft, "session_group_many_attached", "%u", - session_group_attached_count (sg) > 1); - format_add_cb(ft, "session_group_list", - format_cb_session_group_list); - format_add_cb(ft, "session_group_attached_list", - format_cb_session_group_attached_list); - } - - format_add_tv(ft, "session_created", &s->creation_time); - format_add_tv(ft, "session_last_attached", &s->last_attached_time); - format_add_tv(ft, "session_activity", &s->activity_time); - - format_add(ft, "session_attached", "%u", s->attached); - format_add(ft, "session_many_attached", "%d", s->attached > 1); - format_add_cb(ft, "session_attached_list", - format_cb_session_attached_list); - - format_add_cb(ft, "session_alerts", format_cb_session_alerts); - format_add_cb(ft, "session_stack", format_cb_session_stack); - - if (server_check_marked() && marked_pane.s == s) - format_add(ft, "session_marked", "1"); - else - format_add(ft, "session_marked", "0"); } /* Set default format keys for a client. */ static void format_defaults_client(struct format_tree *ft, struct client *c) { - struct session *s; - const char *name; - struct tty *tty = &c->tty; - if (ft->s == NULL) ft->s = c->session; ft->c = c; - - format_add(ft, "client_name", "%s", c->name); - format_add(ft, "client_pid", "%ld", (long) c->pid); - format_add(ft, "client_height", "%u", tty->sy); - format_add(ft, "client_width", "%u", tty->sx); - format_add(ft, "client_cell_width", "%u", tty->xpixel); - format_add(ft, "client_cell_height", "%u", tty->ypixel); - format_add(ft, "client_tty", "%s", c->ttyname); - format_add(ft, "client_control_mode", "%d", - !!(c->flags & CLIENT_CONTROL)); - - format_add(ft, "client_termname", "%s", c->term_name); - format_add(ft, "client_termfeatures", "%s", - tty_get_features(c->term_features)); - if (c->term_type != NULL) - format_add(ft, "client_termtype", "%s", c->term_type); - - format_add_tv(ft, "client_created", &c->creation_time); - format_add_tv(ft, "client_activity", &c->activity_time); - - format_add(ft, "client_written", "%zu", c->written); - format_add(ft, "client_discarded", "%zu", c->discarded); - - name = server_client_get_key_table(c); - if (strcmp(c->keytable->name, name) == 0) - format_add(ft, "client_prefix", "%d", 0); - else - format_add(ft, "client_prefix", "%d", 1); - format_add(ft, "client_key_table", "%s", c->keytable->name); - - if (c->flags & CLIENT_UTF8) - format_add(ft, "client_utf8", "%d", 1); - else - format_add(ft, "client_utf8", "%d", 0); - if (c->flags & CLIENT_READONLY) - format_add(ft, "client_readonly", "%d", 1); - else - format_add(ft, "client_readonly", "%d", 0); - format_add(ft, "client_flags", "%s", server_client_get_flags(c)); - - s = c->session; - if (s != NULL) - format_add(ft, "client_session", "%s", s->name); - s = c->last_session; - if (s != NULL && session_alive(s)) - format_add(ft, "client_last_session", "%s", s->name); } /* Set default format keys for a window. */ @@ -3023,221 +4696,131 @@ void format_defaults_window(struct format_tree *ft, struct window *w) { ft->w = w; - - format_add_tv(ft, "window_activity", &w->activity_time); - format_add(ft, "window_id", "@%u", w->id); - format_add(ft, "window_name", "%s", w->name); - format_add(ft, "window_width", "%u", w->sx); - format_add(ft, "window_height", "%u", w->sy); - format_add(ft, "window_cell_width", "%u", w->xpixel); - format_add(ft, "window_cell_height", "%u", w->ypixel); - format_add_cb(ft, "window_layout", format_cb_window_layout); - format_add_cb(ft, "window_visible_layout", - format_cb_window_visible_layout); - format_add(ft, "window_panes", "%u", window_count_panes(w)); - format_add(ft, "window_zoomed_flag", "%d", - !!(w->flags & WINDOW_ZOOMED)); } /* Set default format keys for a winlink. */ static void format_defaults_winlink(struct format_tree *ft, struct winlink *wl) { - struct client *c = ft->c; - struct session *s = wl->session; - struct window *w = wl->window; - int flag; - u_int ox, oy, sx, sy; - if (ft->w == NULL) - format_defaults_window(ft, w); + format_defaults_window(ft, wl->window); ft->wl = wl; - - if (c != NULL) { - flag = tty_window_offset(&c->tty, &ox, &oy, &sx, &sy); - format_add(ft, "window_bigger", "%d", flag); - if (flag) { - format_add(ft, "window_offset_x", "%u", ox); - format_add(ft, "window_offset_y", "%u", oy); - } - } - - format_add(ft, "window_index", "%d", wl->idx); - format_add_cb(ft, "window_stack_index", format_cb_window_stack_index); - format_add(ft, "window_flags", "%s", window_printable_flags(wl, 1)); - format_add(ft, "window_raw_flags", "%s", window_printable_flags(wl, 0)); - format_add(ft, "window_active", "%d", wl == s->curw); - format_add_cb(ft, "window_active_sessions", - format_cb_window_active_sessions); - format_add_cb(ft, "window_active_sessions_list", - format_cb_window_active_sessions_list); - format_add_cb(ft, "window_active_clients", - format_cb_window_active_clients); - format_add_cb(ft, "window_active_clients_list", - format_cb_window_active_clients_list); - - 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))); - - if (server_check_marked() && marked_pane.wl == wl) - format_add(ft, "window_marked_flag", "1"); - else - format_add(ft, "window_marked_flag", "0"); - - format_add(ft, "window_bell_flag", "%d", - !!(wl->flags & WINLINK_BELL)); - format_add(ft, "window_activity_flag", "%d", - !!(wl->flags & WINLINK_ACTIVITY)); - format_add(ft, "window_silence_flag", "%d", - !!(wl->flags & WINLINK_SILENCE)); - format_add(ft, "window_last_flag", "%d", - !!(wl == TAILQ_FIRST(&s->lastw))); - format_add(ft, "window_linked", "%d", session_is_linked(s, wl->window)); - - format_add_cb(ft, "window_linked_sessions_list", - format_cb_window_linked_sessions_list); - format_add(ft, "window_linked_sessions", "%u", - wl->window->references); } /* Set default format keys for a window pane. */ void format_defaults_pane(struct format_tree *ft, struct window_pane *wp) { - struct window *w = wp->window; - struct grid *gd = wp->base.grid; - int status = wp->status; - u_int idx; struct window_mode_entry *wme; if (ft->w == NULL) - format_defaults_window(ft, w); + format_defaults_window(ft, wp->window); ft->wp = wp; - format_add(ft, "history_size", "%u", gd->hsize); - format_add(ft, "history_limit", "%u", gd->hlimit); - format_add_cb(ft, "history_bytes", format_cb_history_bytes); - format_add_cb(ft, "history_all_bytes", format_cb_history_all_bytes); - - if (window_pane_index(wp, &idx) != 0) - fatalx("index not found"); - format_add(ft, "pane_index", "%u", idx); - - format_add(ft, "pane_width", "%u", wp->sx); - format_add(ft, "pane_height", "%u", wp->sy); - format_add(ft, "pane_title", "%s", wp->base.title); - if (wp->base.path != NULL) - format_add(ft, "pane_path", "%s", wp->base.path); - format_add(ft, "pane_id", "%%%u", wp->id); - format_add(ft, "pane_active", "%d", wp == w->active); - format_add(ft, "pane_input_off", "%d", !!(wp->flags & PANE_INPUTOFF)); - format_add(ft, "pane_pipe", "%d", wp->pipe_fd != -1); - - if ((wp->flags & PANE_STATUSREADY) && WIFEXITED(status)) - format_add(ft, "pane_dead_status", "%d", WEXITSTATUS(status)); - if (~wp->flags & PANE_EMPTY) - format_add(ft, "pane_dead", "%d", wp->fd == -1); - else - format_add(ft, "pane_dead", "0"); - format_add(ft, "pane_last", "%d", wp == w->last); - - if (server_check_marked() && marked_pane.wp == wp) - format_add(ft, "pane_marked", "1"); - else - format_add(ft, "pane_marked", "0"); - format_add(ft, "pane_marked_set", "%d", server_check_marked()); - - format_add(ft, "pane_left", "%u", wp->xoff); - format_add(ft, "pane_top", "%u", wp->yoff); - format_add(ft, "pane_right", "%u", wp->xoff + wp->sx - 1); - format_add(ft, "pane_bottom", "%u", wp->yoff + wp->sy - 1); - format_add(ft, "pane_at_left", "%d", wp->xoff == 0); - format_add_cb(ft, "pane_at_top", format_cb_pane_at_top); - format_add(ft, "pane_at_right", "%d", wp->xoff + wp->sx == w->sx); - format_add_cb(ft, "pane_at_bottom", format_cb_pane_at_bottom); - wme = TAILQ_FIRST(&wp->modes); - if (wme != NULL) { - format_add(ft, "pane_mode", "%s", wme->mode->name); - if (wme->mode->formats != NULL) - wme->mode->formats(wme, ft); - } - format_add_cb(ft, "pane_in_mode", format_cb_pane_in_mode); - - format_add(ft, "pane_synchronized", "%d", - !!options_get_number(wp->options, "synchronize-panes")); - if (wp->searchstr != NULL) - format_add(ft, "pane_search_string", "%s", wp->searchstr); - - format_add(ft, "pane_tty", "%s", wp->tty); - format_add(ft, "pane_pid", "%ld", (long) wp->pid); - format_add_cb(ft, "pane_start_command", format_cb_start_command); - format_add_cb(ft, "pane_current_command", format_cb_current_command); - format_add_cb(ft, "pane_current_path", format_cb_current_path); - - format_add(ft, "cursor_x", "%u", wp->base.cx); - format_add(ft, "cursor_y", "%u", wp->base.cy); - format_add_cb(ft, "cursor_character", format_cb_cursor_character); - - format_add(ft, "scroll_region_upper", "%u", wp->base.rupper); - format_add(ft, "scroll_region_lower", "%u", wp->base.rlower); - - format_add(ft, "alternate_on", "%d", wp->base.saved_grid != NULL); - if (wp->base.saved_cx != UINT_MAX) - format_add(ft, "alternate_saved_x", "%u", wp->base.saved_cx); - if (wp->base.saved_cy != UINT_MAX) - format_add(ft, "alternate_saved_y", "%u", wp->base.saved_cy); - - format_add(ft, "cursor_flag", "%d", - !!(wp->base.mode & MODE_CURSOR)); - format_add(ft, "insert_flag", "%d", - !!(wp->base.mode & MODE_INSERT)); - format_add(ft, "keypad_cursor_flag", "%d", - !!(wp->base.mode & MODE_KCURSOR)); - format_add(ft, "keypad_flag", "%d", - !!(wp->base.mode & MODE_KKEYPAD)); - format_add(ft, "wrap_flag", "%d", - !!(wp->base.mode & MODE_WRAP)); - format_add(ft, "origin_flag", "%d", - !!(wp->base.mode & MODE_ORIGIN)); - - format_add(ft, "mouse_any_flag", "%d", - !!(wp->base.mode & ALL_MOUSE_MODES)); - format_add(ft, "mouse_standard_flag", "%d", - !!(wp->base.mode & MODE_MOUSE_STANDARD)); - format_add(ft, "mouse_button_flag", "%d", - !!(wp->base.mode & MODE_MOUSE_BUTTON)); - format_add(ft, "mouse_all_flag", "%d", - !!(wp->base.mode & MODE_MOUSE_ALL)); - format_add(ft, "mouse_utf8_flag", "%d", - !!(wp->base.mode & MODE_MOUSE_UTF8)); - format_add(ft, "mouse_sgr_flag", "%d", - !!(wp->base.mode & MODE_MOUSE_SGR)); - - format_add_cb(ft, "pane_tabs", format_cb_pane_tabs); - format_add_cb(ft, "pane_fg", format_cb_pane_fg); - format_add_cb(ft, "pane_bg", format_cb_pane_bg); + if (wme != NULL && wme->mode->formats != NULL) + wme->mode->formats(wme, ft); } /* Set default format keys for paste buffer. */ void format_defaults_paste_buffer(struct format_tree *ft, struct paste_buffer *pb) { - struct timeval tv; - size_t size; - char *s; + ft->pb = pb; +} + +/* Return word at given coordinates. Caller frees. */ +char * +format_grid_word(struct grid *gd, u_int x, u_int y) +{ + const struct grid_line *gl; + struct grid_cell gc; + const char *ws; + struct utf8_data *ud = NULL; + u_int end; + size_t size = 0; + int found = 0; + char *s = NULL; - timerclear(&tv); - tv.tv_sec = paste_buffer_created(pb); - paste_buffer_data(pb, &size); + ws = options_get_string(global_s_options, "word-separators"); - format_add(ft, "buffer_size", "%zu", size); - format_add(ft, "buffer_name", "%s", paste_buffer_name(pb)); - format_add_tv(ft, "buffer_created", &tv); + for (;;) { + grid_get_cell(gd, x, y, &gc); + if (gc.flags & GRID_FLAG_PADDING) + break; + if (utf8_cstrhas(ws, &gc.data)) { + found = 1; + break; + } - s = paste_make_sample(pb); - format_add(ft, "buffer_sample", "%s", s); - free(s); + if (x == 0) { + if (y == 0) + break; + gl = grid_peek_line(gd, y - 1); + if (~gl->flags & GRID_LINE_WRAPPED) + break; + y--; + x = grid_line_length(gd, y); + if (x == 0) + break; + } + x--; + } + for (;;) { + if (found) { + end = grid_line_length(gd, y); + if (end == 0 || x == end - 1) { + if (y == gd->hsize + gd->sy - 1) + break; + gl = grid_peek_line(gd, y); + if (~gl->flags & GRID_LINE_WRAPPED) + break; + y++; + x = 0; + } else + x++; + } + found = 1; + + grid_get_cell(gd, x, y, &gc); + if (gc.flags & GRID_FLAG_PADDING) + break; + if (utf8_cstrhas(ws, &gc.data)) + break; + + ud = xreallocarray(ud, size + 2, sizeof *ud); + memcpy(&ud[size++], &gc.data, sizeof *ud); + } + if (size != 0) { + ud[size].size = 0; + s = utf8_tocstr(ud); + free(ud); + } + return (s); +} + +/* Return line at given coordinates. Caller frees. */ +char * +format_grid_line(struct grid *gd, u_int y) +{ + struct grid_cell gc; + struct utf8_data *ud = NULL; + u_int x; + size_t size = 0; + char *s = NULL; + + for (x = 0; x < grid_line_length(gd, y); x++) { + grid_get_cell(gd, x, y, &gc); + if (gc.flags & GRID_FLAG_PADDING) + break; + + ud = xreallocarray(ud, size + 2, sizeof *ud); + memcpy(&ud[size++], &gc.data, sizeof *ud); + } + if (size != 0) { + ud[size].size = 0; + s = utf8_tocstr(ud); + free(ud); + } + return (s); } diff --git a/usr.bin/tmux/tmux.h b/usr.bin/tmux/tmux.h index 92aee93fdd7..48bb0b75dc8 100644 --- a/usr.bin/tmux/tmux.h +++ b/usr.bin/tmux/tmux.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tmux.h,v 1.1093 2021/02/22 06:53:04 nicm Exp $ */ +/* $OpenBSD: tmux.h,v 1.1094 2021/02/22 07:09:06 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -1944,7 +1944,7 @@ char *paste_make_sample(struct paste_buffer *); #define FORMAT_WINDOW 0x40000000U struct format_tree; struct format_modifier; -typedef char *(*format_cb)(struct format_tree *); +typedef void *(*format_cb)(struct format_tree *); const char *format_skip(const char *, const char *); int format_true(const char *); struct format_tree *format_create(struct client *, struct cmdq_item *, int, @@ -2713,7 +2713,6 @@ void screen_alternate_off(struct screen *, struct grid_cell *, int); /* window.c */ extern struct windows windows; extern struct window_pane_tree all_window_panes; -extern const struct window_mode *all_window_modes[]; int window_cmp(struct window *, struct window *); RB_PROTOTYPE(windows, window, entry, window_cmp); int winlink_cmp(struct winlink *, struct winlink *); diff --git a/usr.bin/tmux/window-copy.c b/usr.bin/tmux/window-copy.c index a6cb274fab1..fbe66f96fb0 100644 --- a/usr.bin/tmux/window-copy.c +++ b/usr.bin/tmux/window-copy.c @@ -1,4 +1,4 @@ -/* $OpenBSD: window-copy.c,v 1.315 2021/02/22 06:53:04 nicm Exp $ */ +/* $OpenBSD: window-copy.c,v 1.316 2021/02/22 07:09:06 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -710,7 +710,7 @@ window_copy_get_line(struct window_pane *wp, u_int y) return (format_grid_line(gd, gd->hsize + y)); } -static char * +static void * window_copy_cursor_word_cb(struct format_tree *ft) { struct window_pane *wp = format_get_pane(ft); @@ -720,7 +720,7 @@ window_copy_cursor_word_cb(struct format_tree *ft) return (window_copy_get_word(wp, data->cx, data->cy)); } -static char * +static void * window_copy_cursor_line_cb(struct format_tree *ft) { struct window_pane *wp = format_get_pane(ft); @@ -730,7 +730,7 @@ window_copy_cursor_line_cb(struct format_tree *ft) return (window_copy_get_line(wp, data->cy)); } -static char * +static void * window_copy_search_match_cb(struct format_tree *ft) { struct window_pane *wp = format_get_pane(ft); diff --git a/usr.bin/tmux/window.c b/usr.bin/tmux/window.c index 3082d1b7c1d..0633425979c 100644 --- a/usr.bin/tmux/window.c +++ b/usr.bin/tmux/window.c @@ -1,4 +1,4 @@ -/* $OpenBSD: window.c,v 1.268 2021/01/20 07:16:54 nicm Exp $ */ +/* $OpenBSD: window.c,v 1.269 2021/02/22 07:09:06 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -63,17 +63,6 @@ static u_int next_window_pane_id; static u_int next_window_id; static u_int next_active_point; -/* List of window modes. */ -const struct window_mode *all_window_modes[] = { - &window_buffer_mode, - &window_client_mode, - &window_clock_mode, - &window_copy_mode, - &window_tree_mode, - &window_view_mode, - NULL -}; - struct window_pane_input_data { struct cmdq_item *item; u_int wp; -- 2.20.1