From 8986c8dfcd0083e5c767b8a247c119a25e1f8093 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 22 Feb 2021 06:53:04 +0000 Subject: Move jump commands to grid reader, make them UTF-8 aware, and tidy up, from Anindya Mukherjee. --- grid-reader.c | 62 +++++++++++ status.c | 12 +- tmux.h | 4 + window-copy.c | 344 +++++++++++++++++++++++----------------------------------- 4 files changed, 206 insertions(+), 216 deletions(-) diff --git a/grid-reader.c b/grid-reader.c index a1af3aaa..c011ea1d 100644 --- a/grid-reader.c +++ b/grid-reader.c @@ -17,6 +17,7 @@ */ #include "tmux.h" +#include /* Initialise virtual cursor. */ void @@ -301,3 +302,64 @@ grid_reader_cursor_previous_word(struct grid_reader *gr, const char *separators, gr->cx = oldx; gr->cy = oldy; } + +/* Jump forward to character. */ +int +grid_reader_cursor_jump(struct grid_reader *gr, const struct utf8_data *jc) +{ + struct grid_cell gc; + u_int px, py, xx, yy; + + px = gr->cx; + yy = gr->gd->hsize + gr->gd->sy - 1; + + for (py = gr->cy; py <= yy; py++) { + xx = grid_line_length(gr->gd, py); + while (px < xx) { + grid_get_cell(gr->gd, px, py, &gc); + if (!(gc.flags & GRID_FLAG_PADDING) && + gc.data.size == jc->size && + memcmp(gc.data.data, jc->data, gc.data.size) == 0) { + gr->cx = px; + gr->cy = py; + return 1; + } + px++; + } + + if (py == yy || + !(grid_get_line(gr->gd, py)->flags & GRID_LINE_WRAPPED)) + return 0; + px = 0; + } + return 0; +} + +/* Jump back to character. */ +int +grid_reader_cursor_jump_back(struct grid_reader *gr, const struct utf8_data *jc) +{ + struct grid_cell gc; + u_int px, py, xx; + + xx = gr->cx + 1; + + for (py = gr->cy + 1; py > 0; py--) { + for (px = xx; px > 0; px--) { + grid_get_cell(gr->gd, px - 1, py - 1, &gc); + if (!(gc.flags & GRID_FLAG_PADDING) && + gc.data.size == jc->size && + memcmp(gc.data.data, jc->data, gc.data.size) == 0) { + gr->cx = px - 1; + gr->cy = py - 1; + return 1; + } + } + + if (py == 1 || + !(grid_get_line(gr->gd, py - 2)->flags & GRID_LINE_WRAPPED)) + return 0; + xx = grid_line_length(gr->gd, py - 2); + } + return 0; +} diff --git a/status.c b/status.c index 82107c58..154d9452 100644 --- a/status.c +++ b/status.c @@ -1319,12 +1319,14 @@ append_key: } if (c->prompt_flags & PROMPT_SINGLE) { - s = utf8_tocstr(c->prompt_buffer); - if (strlen(s) != 1) - status_prompt_clear(c); - else if (c->prompt_inputcb(c, c->prompt_data, s, 1) == 0) + if (utf8_strlen(c->prompt_buffer) != 1) status_prompt_clear(c); - free(s); + else { + s = utf8_tocstr(c->prompt_buffer); + if (c->prompt_inputcb(c, c->prompt_data, s, 1) == 0) + status_prompt_clear(c); + free(s); + } } changed: diff --git a/tmux.h b/tmux.h index 88c6d30e..4339f6a7 100644 --- a/tmux.h +++ b/tmux.h @@ -2589,6 +2589,10 @@ void grid_reader_cursor_next_word(struct grid_reader *, const char *); void grid_reader_cursor_next_word_end(struct grid_reader *, const char *); void grid_reader_cursor_previous_word(struct grid_reader *, const char *, int); +int grid_reader_cursor_jump(struct grid_reader *, + const struct utf8_data *); +int grid_reader_cursor_jump_back(struct grid_reader *, + const struct utf8_data *); /* grid-view.c */ void grid_view_get_cell(struct grid *, u_int, u_int, struct grid_cell *); diff --git a/window-copy.c b/window-copy.c index c6b25413..af8d2937 100644 --- a/window-copy.c +++ b/window-copy.c @@ -135,6 +135,10 @@ static void window_copy_move_mouse(struct mouse_event *); static void window_copy_drag_update(struct client *, struct mouse_event *); static void window_copy_drag_release(struct client *, struct mouse_event *); static void window_copy_jump_to_mark(struct window_mode_entry *); +static void window_copy_acquire_cursor_up(struct window_mode_entry *, + u_int, u_int, u_int, u_int, u_int); +static void window_copy_acquire_cursor_down(struct window_mode_entry *, + u_int, u_int, u_int, u_int, u_int, u_int, int); const struct window_mode window_copy_mode = { .name = "copy-mode", @@ -284,8 +288,8 @@ struct window_copy_mode_data { #define WINDOW_COPY_SEARCH_TIMEOUT 10000 #define WINDOW_COPY_SEARCH_ALL_TIMEOUT 200 - int jumptype; - char jumpchar; + int jumptype; + struct utf8_data *jumpchar; struct event dragtimer; #define WINDOW_COPY_DRAG_REPEAT_TIME 50000 @@ -401,7 +405,7 @@ window_copy_common_init(struct window_mode_entry *wme) data->searchall = 1; data->jumptype = WINDOW_COPY_OFF; - data->jumpchar = '\0'; + data->jumpchar = NULL; screen_init(&data->screen, screen_size_x(base), screen_size_y(base), 0); data->modekeys = options_get_number(wp->window->options, "mode-keys"); @@ -482,6 +486,7 @@ window_copy_free(struct window_mode_entry *wme) free(data->searchmark); free(data->searchstr); + free(data->jumpchar); screen_free(data->backing); free(data->backing); @@ -1935,7 +1940,8 @@ window_copy_cmd_jump_backward(struct window_copy_cmd_state *cs) if (*argument != '\0') { data->jumptype = WINDOW_COPY_JUMPBACKWARD; - data->jumpchar = *argument; + free(data->jumpchar); + data->jumpchar = utf8_fromcstr(argument); for (; np != 0; np--) window_copy_cursor_jump_back(wme); } @@ -1952,7 +1958,8 @@ window_copy_cmd_jump_forward(struct window_copy_cmd_state *cs) if (*argument != '\0') { data->jumptype = WINDOW_COPY_JUMPFORWARD; - data->jumpchar = *argument; + free(data->jumpchar); + data->jumpchar = utf8_fromcstr(argument); for (; np != 0; np--) window_copy_cursor_jump(wme); } @@ -1969,7 +1976,8 @@ window_copy_cmd_jump_to_backward(struct window_copy_cmd_state *cs) if (*argument != '\0') { data->jumptype = WINDOW_COPY_JUMPTOBACKWARD; - data->jumpchar = *argument; + free(data->jumpchar); + data->jumpchar = utf8_fromcstr(argument); for (; np != 0; np--) window_copy_cursor_jump_to_back(wme); } @@ -1986,7 +1994,8 @@ window_copy_cmd_jump_to_forward(struct window_copy_cmd_state *cs) if (*argument != '\0') { data->jumptype = WINDOW_COPY_JUMPTOFORWARD; - data->jumpchar = *argument; + free(data->jumpchar); + data->jumpchar = utf8_fromcstr(argument); for (; np != 0; np--) window_copy_cursor_jump_to(wme); } @@ -4074,7 +4083,7 @@ window_copy_cursor_start_of_line(struct window_mode_entry *wme) struct window_copy_mode_data *data = wme->data; struct screen *back_s = data->backing; struct grid_reader gr; - u_int px, py, cy, oldy, yy, ny, nd, hsize; + u_int px, py, oldy, hsize; px = data->cx; hsize = screen_hsize(back_s); @@ -4084,25 +4093,7 @@ window_copy_cursor_start_of_line(struct window_mode_entry *wme) grid_reader_start(&gr, back_s->grid, px, py); grid_reader_cursor_start_of_line(&gr, 1); grid_reader_get_cursor(&gr, &px, &py); - - /* Scroll up if we went off the visible screen. */ - yy = hsize - data->oy; - if (py < yy) { - ny = yy - py; - cy = 0; - nd = 1; - } else { - ny = 0; - cy = py - yy; - nd = oldy - cy + 1; - } - while (ny > 0) { - window_copy_cursor_up(wme, 1); - ny--; - } - window_copy_update_cursor(wme, px, cy); - if (window_copy_update_selection(wme, 1, 0)) - window_copy_redraw_lines(wme, data->cy, nd); + window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px, py); } static void @@ -4134,7 +4125,7 @@ window_copy_cursor_end_of_line(struct window_mode_entry *wme) struct window_copy_mode_data *data = wme->data; struct screen *back_s = data->backing; struct grid_reader gr; - u_int px, py, cy, oldy, yy, ny, nd, hsize; + u_int px, py, oldy, hsize; px = data->cx; hsize = screen_hsize(back_s); @@ -4147,28 +4138,8 @@ window_copy_cursor_end_of_line(struct window_mode_entry *wme) else grid_reader_cursor_end_of_line(&gr, 1, 0); grid_reader_get_cursor(&gr, &px, &py); - - /* Scroll down if we went off the visible screen. */ - cy = py - hsize + data->oy; - yy = screen_size_y(back_s) - 1; - if (cy > yy) { - ny = cy - yy; - oldy = yy; - nd = 1; - } else { - ny = 0; - nd = cy - oldy + 1; - } - while (ny > 0) { - window_copy_cursor_down(wme, 1); - ny--; - } - if (cy > yy) - window_copy_update_cursor(wme, px, yy); - else - window_copy_update_cursor(wme, px, cy); - if (window_copy_update_selection(wme, 1, 0)) - window_copy_redraw_lines(wme, oldy, nd); + window_copy_acquire_cursor_down(wme, hsize, screen_size_y(back_s), + data->oy, oldy, px, py, 0); } static void @@ -4228,32 +4199,17 @@ window_copy_cursor_left(struct window_mode_entry *wme) struct window_copy_mode_data *data = wme->data; struct screen *back_s = data->backing; struct grid_reader gr; - u_int px, py, cy, yy, ny, hsize; + u_int px, py, oldy, hsize; px = data->cx; hsize = screen_hsize(back_s); py = hsize + data->cy - data->oy; + oldy = data->cy; grid_reader_start(&gr, back_s->grid, px, py); grid_reader_cursor_left(&gr); grid_reader_get_cursor(&gr, &px, &py); - - /* Scroll up if we went off the visible screen. */ - yy = hsize - data->oy; - if (py < yy) { - ny = yy - py; - cy = 0; - } else { - ny = 0; - cy = py - yy; - } - while (ny > 0) { - window_copy_cursor_up(wme, 1); - ny--; - } - window_copy_update_cursor(wme, px, cy); - if (window_copy_update_selection(wme, 1, 0)) - window_copy_redraw_lines(wme, data->cy, 1); + window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px, py); } static void @@ -4262,33 +4218,18 @@ window_copy_cursor_right(struct window_mode_entry *wme, int all) struct window_copy_mode_data *data = wme->data; struct screen *back_s = data->backing; struct grid_reader gr; - u_int px, py, cy, yy, ny, hsize; + u_int px, py, oldy, hsize; px = data->cx; hsize = screen_hsize(back_s); py = hsize + data->cy - data->oy; + oldy = data->cy; grid_reader_start(&gr, back_s->grid, px, py); grid_reader_cursor_right(&gr, 1, all); grid_reader_get_cursor(&gr, &px, &py); - - /* Scroll down if we went off the visible screen. */ - cy = py - hsize + data->oy; - yy = screen_size_y(back_s) - 1; - if (cy > yy) - ny = cy - yy; - else - ny = 0; - while (ny > 0) { - window_copy_cursor_down(wme, 1); - ny--; - } - if (cy > yy) - window_copy_update_cursor(wme, px, yy); - else - window_copy_update_cursor(wme, px, cy); - if (window_copy_update_selection(wme, 1, 0)) - window_copy_redraw_lines(wme, data->cy, 1); + window_copy_acquire_cursor_down(wme, hsize, screen_size_y(back_s), + data->oy, oldy, px, py, 0); } static void @@ -4422,23 +4363,19 @@ window_copy_cursor_jump(struct window_mode_entry *wme) { struct window_copy_mode_data *data = wme->data; struct screen *back_s = data->backing; - struct grid_cell gc; - u_int px, py, xx; + struct grid_reader gr; + u_int px, py, oldy, hsize; px = data->cx + 1; - py = screen_hsize(back_s) + data->cy - data->oy; - xx = window_copy_find_length(wme, py); + hsize = screen_hsize(back_s); + py = hsize + data->cy - data->oy; + oldy = data->cy; - while (px < xx) { - grid_get_cell(back_s->grid, px, py, &gc); - if (!(gc.flags & GRID_FLAG_PADDING) && - gc.data.size == 1 && *gc.data.data == data->jumpchar) { - window_copy_update_cursor(wme, px, data->cy); - if (window_copy_update_selection(wme, 1, 0)) - window_copy_redraw_lines(wme, data->cy, 1); - return; - } - px++; + grid_reader_start(&gr, back_s->grid, px, py); + if (grid_reader_cursor_jump(&gr, data->jumpchar)) { + grid_reader_get_cursor(&gr, &px, &py); + window_copy_acquire_cursor_down(wme, hsize, + screen_size_y(back_s), data->oy, oldy, px, py, 0); } } @@ -4447,27 +4384,22 @@ window_copy_cursor_jump_back(struct window_mode_entry *wme) { struct window_copy_mode_data *data = wme->data; struct screen *back_s = data->backing; - struct grid_cell gc; - u_int px, py; + struct grid_reader gr; + u_int px, py, oldy, hsize; px = data->cx; - py = screen_hsize(back_s) + data->cy - data->oy; + hsize = screen_hsize(back_s); + py = hsize + data->cy - data->oy; + oldy = data->cy; if (px > 0) px--; - for (;;) { - grid_get_cell(back_s->grid, px, py, &gc); - if (!(gc.flags & GRID_FLAG_PADDING) && - gc.data.size == 1 && *gc.data.data == data->jumpchar) { - window_copy_update_cursor(wme, px, data->cy); - if (window_copy_update_selection(wme, 1, 0)) - window_copy_redraw_lines(wme, data->cy, 1); - return; - } - if (px == 0) - break; - px--; + grid_reader_start(&gr, back_s->grid, px, py); + if (grid_reader_cursor_jump_back(&gr, data->jumpchar)) { + grid_reader_get_cursor(&gr, &px, &py); + window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px, + py); } } @@ -4476,23 +4408,20 @@ window_copy_cursor_jump_to(struct window_mode_entry *wme) { struct window_copy_mode_data *data = wme->data; struct screen *back_s = data->backing; - struct grid_cell gc; - u_int px, py, xx; + struct grid_reader gr; + u_int px, py, oldy, hsize; px = data->cx + 2; - py = screen_hsize(back_s) + data->cy - data->oy; - xx = window_copy_find_length(wme, py); + hsize = screen_hsize(back_s); + py = hsize + data->cy - data->oy; + oldy = data->cy; - while (px < xx) { - grid_get_cell(back_s->grid, px, py, &gc); - if (!(gc.flags & GRID_FLAG_PADDING) && - gc.data.size == 1 && *gc.data.data == data->jumpchar) { - window_copy_update_cursor(wme, px - 1, data->cy); - if (window_copy_update_selection(wme, 1, 0)) - window_copy_redraw_lines(wme, data->cy, 1); - return; - } - px++; + grid_reader_start(&gr, back_s->grid, px, py); + if (grid_reader_cursor_jump(&gr, data->jumpchar)) { + grid_reader_cursor_left(&gr); + grid_reader_get_cursor(&gr, &px, &py); + window_copy_acquire_cursor_down(wme, hsize, + screen_size_y(back_s), data->oy, oldy, px, py, 0); } } @@ -4501,11 +4430,13 @@ window_copy_cursor_jump_to_back(struct window_mode_entry *wme) { struct window_copy_mode_data *data = wme->data; struct screen *back_s = data->backing; - struct grid_cell gc; - u_int px, py; + struct grid_reader gr; + u_int px, py, oldy, hsize; px = data->cx; - py = screen_hsize(back_s) + data->cy - data->oy; + hsize = screen_hsize(back_s); + py = hsize + data->cy - data->oy; + oldy = data->cy; if (px > 0) px--; @@ -4513,18 +4444,12 @@ window_copy_cursor_jump_to_back(struct window_mode_entry *wme) if (px > 0) px--; - for (;;) { - grid_get_cell(back_s->grid, px, py, &gc); - if (!(gc.flags & GRID_FLAG_PADDING) && - gc.data.size == 1 && *gc.data.data == data->jumpchar) { - window_copy_update_cursor(wme, px + 1, data->cy); - if (window_copy_update_selection(wme, 1, 0)) - window_copy_redraw_lines(wme, data->cy, 1); - return; - } - if (px == 0) - break; - px--; + grid_reader_start(&gr, back_s->grid, px, py); + if (grid_reader_cursor_jump_back(&gr, data->jumpchar)) { + grid_reader_cursor_right(&gr, 1, 0); + grid_reader_get_cursor(&gr, &px, &py); + window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px, + py); } } @@ -4535,7 +4460,7 @@ window_copy_cursor_next_word(struct window_mode_entry *wme, struct window_copy_mode_data *data = wme->data; struct screen *back_s = data->backing; struct grid_reader gr; - u_int px, py, cy, oldy, yy, ny, nd, hsize; + u_int px, py, oldy, hsize; px = data->cx; hsize = screen_hsize(back_s); @@ -4545,28 +4470,8 @@ window_copy_cursor_next_word(struct window_mode_entry *wme, grid_reader_start(&gr, back_s->grid, px, py); grid_reader_cursor_next_word(&gr, separators); grid_reader_get_cursor(&gr, &px, &py); - - /* Scroll down if we went off the visible screen. */ - cy = py - hsize + data->oy; - yy = screen_size_y(back_s) - 1; - if (cy > yy) { - ny = cy - yy; - oldy = yy; - nd = 1; - } else { - ny = 0; - nd = cy - oldy + 1; - } - while (ny > 0) { - window_copy_cursor_down(wme, 1); - ny--; - } - if (cy > yy) - window_copy_update_cursor(wme, px, yy); - else - window_copy_update_cursor(wme, px, cy); - if (window_copy_update_selection(wme, 1, 0)) - window_copy_redraw_lines(wme, oldy, nd); + window_copy_acquire_cursor_down(wme, hsize, screen_size_y(back_s), + data->oy, oldy, px, py, 0); } static void @@ -4627,7 +4532,7 @@ window_copy_cursor_next_word_end(struct window_mode_entry *wme, struct options *oo = wp->window->options; struct screen *back_s = data->backing; struct grid_reader gr; - u_int px, py, cy, oldy, yy, ny, nd, hsize; + u_int px, py, oldy, hsize; int keys; px = data->cx; @@ -4643,28 +4548,8 @@ window_copy_cursor_next_word_end(struct window_mode_entry *wme, if (keys == MODEKEY_VI) grid_reader_cursor_left(&gr); grid_reader_get_cursor(&gr, &px, &py); - - /* Scroll down if we went off the visible screen. */ - cy = py - hsize + data->oy; - yy = screen_size_y(back_s) - 1; - if (cy > yy) { - ny = cy - yy; - oldy = yy; - nd = 1; - } else { - ny = 0; - nd = cy - oldy + 1; - } - while (ny > 0) { - window_copy_cursor_down(wme, 1); - ny--; - } - if (cy > yy) - window_copy_update_cursor(wme, px, yy); - else - window_copy_update_cursor(wme, px, cy); - if (window_copy_update_selection(wme, 1, no_reset)) - window_copy_redraw_lines(wme, oldy, nd); + window_copy_acquire_cursor_down(wme, hsize, screen_size_y(back_s), + data->oy, oldy, px, py, no_reset); } /* Compute the previous place where a word begins. */ @@ -4721,7 +4606,7 @@ window_copy_cursor_previous_word(struct window_mode_entry *wme, struct window_copy_mode_data *data = wme->data; struct screen *back_s = data->backing; struct grid_reader gr; - u_int px, py, cy, oldy, yy, ny, nd, hsize; + u_int px, py, oldy, hsize; px = data->cx; hsize = screen_hsize(back_s); @@ -4731,25 +4616,7 @@ window_copy_cursor_previous_word(struct window_mode_entry *wme, grid_reader_start(&gr, back_s->grid, px, py); grid_reader_cursor_previous_word(&gr, separators, already); grid_reader_get_cursor(&gr, &px, &py); - - /* Scroll up if we went off the visible screen. */ - yy = hsize - data->oy; - if (py < yy) { - ny = yy - py; - cy = 0; - nd = 1; - } else { - ny = 0; - cy = py - yy; - nd = oldy - cy + 1; - } - while (ny > 0) { - window_copy_cursor_up(wme, 1); - ny--; - } - window_copy_update_cursor(wme, px, cy); - if (window_copy_update_selection(wme, 1, 0)) - window_copy_redraw_lines(wme, data->cy, nd); + window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px, py); } static void @@ -5000,3 +4867,58 @@ window_copy_jump_to_mark(struct window_mode_entry *wme) window_copy_update_selection(wme, 0, 0); window_copy_redraw_screen(wme); } + +/* Scroll up if the cursor went off the visible screen. */ +static void +window_copy_acquire_cursor_up(struct window_mode_entry *wme, u_int hsize, + u_int oy, u_int oldy, u_int px, u_int py) +{ + u_int cy, yy, ny, nd; + + yy = hsize - oy; + if (py < yy) { + ny = yy - py; + cy = 0; + nd = 1; + } else { + ny = 0; + cy = py - yy; + nd = oldy - cy + 1; + } + while (ny > 0) { + window_copy_cursor_up(wme, 1); + ny--; + } + window_copy_update_cursor(wme, px, cy); + if (window_copy_update_selection(wme, 1, 0)) + window_copy_redraw_lines(wme, cy, nd); +} + +/* Scroll down if the cursor went off the visible screen. */ +static void +window_copy_acquire_cursor_down(struct window_mode_entry *wme, u_int hsize, + u_int sy, u_int oy, u_int oldy, u_int px, u_int py, int no_reset) +{ + u_int cy, yy, ny, nd; + + cy = py - hsize + oy; + yy = sy - 1; + if (cy > yy) { + ny = cy - yy; + oldy = yy; + nd = 1; + } else { + ny = 0; + nd = cy - oldy + 1; + } + while (ny > 0) { + window_copy_cursor_down(wme, 1); + ny--; + } + if (cy > yy) + window_copy_update_cursor(wme, px, yy); + else + window_copy_update_cursor(wme, px, cy); + if (window_copy_update_selection(wme, 1, no_reset)) + window_copy_redraw_lines(wme, oldy, nd); +} -- cgit v1.2.3 From e858270006a9041b9016ed9e6cc12d622ac8fe31 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 22 Feb 2021 07:09:06 +0000 Subject: 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. --- format.c | 2551 ++++++++++++++++++++++++++++++++++++++++++++++----------- tmux.h | 3 +- window-copy.c | 6 +- window.c | 11 - 4 files changed, 2071 insertions(+), 500 deletions(-) diff --git a/format.c b/format.c index 47e0bb29..014f1385 100644 --- a/format.c +++ b/format.c @@ -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,