From 596ea62dc33cf9aa4713bb18a094234f86aaff92 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 8 Nov 2024 08:51:36 +0000 Subject: [PATCH 1/2] Some fixes for searching for tabs, from Alexander Arch. --- grid.c | 10 ++++++--- screen-write.c | 16 ++++++++++--- window-copy.c | 61 +++++++++++++++++++++++++++++++++++++------------- 3 files changed, 65 insertions(+), 22 deletions(-) diff --git a/grid.c b/grid.c index 447c2712..53002a67 100644 --- a/grid.c +++ b/grid.c @@ -235,9 +235,13 @@ grid_check_y(struct grid *gd, const char *from, u_int py) int grid_cells_look_equal(const struct grid_cell *gc1, const struct grid_cell *gc2) { + int flags1 = gc1->flags, flags2 = gc2->flags;; + if (gc1->fg != gc2->fg || gc1->bg != gc2->bg) return (0); - if (gc1->attr != gc2->attr || gc1->flags != gc2->flags) + if (gc1->attr != gc2->attr) + return (0); + if ((flags1 & ~GRID_FLAG_CLEARED) != (flags2 & ~GRID_FLAG_CLEARED)) return (0); if (gc1->link != gc2->link) return (0); @@ -261,10 +265,10 @@ grid_cells_equal(const struct grid_cell *gc1, const struct grid_cell *gc2) void grid_set_tab(struct grid_cell *gc, u_int width) { - memset(&gc->data, 0, sizeof gc->data); + memset(gc->data.data, 0, sizeof gc->data.data); gc->flags |= GRID_FLAG_TAB; gc->data.width = gc->data.size = gc->data.have = width; - memset(&gc->data, ' ', gc->data.size); + memset(gc->data.data, ' ', gc->data.size); } /* Free one line. */ diff --git a/screen-write.c b/screen-write.c index c29cc51b..f79c46f8 100644 --- a/screen-write.c +++ b/screen-write.c @@ -377,7 +377,7 @@ screen_write_strlen(const char *fmt, ...) if (more == UTF8_DONE) size += ud.width; } else { - if (*ptr > 0x1f && *ptr < 0x7f) + if (*ptr == '\t' || (*ptr > 0x1f && *ptr < 0x7f)) size++; ptr++; } @@ -547,7 +547,7 @@ screen_write_vnputs(struct screen_write_ctx *ctx, ssize_t maxlen, else if (*ptr == '\n') { screen_write_linefeed(ctx, 0, 8); screen_write_carriagereturn(ctx); - } else if (*ptr > 0x1f && *ptr < 0x7f) { + } else if (*ptr == '\t' || (*ptr > 0x1f && *ptr < 0x7f)) { size++; screen_write_putc(ctx, &gc, *ptr); } @@ -2143,7 +2143,17 @@ screen_write_overwrite(struct screen_write_ctx *ctx, struct grid_cell *gc, break; log_debug("%s: overwrite at %u,%u", __func__, xx, s->cy); - grid_view_set_cell(gd, xx, s->cy, &grid_default_cell); + if (gc->flags & GRID_FLAG_TAB) { + memcpy(&tmp_gc, gc, sizeof tmp_gc); + memset(tmp_gc.data.data, 0, + sizeof tmp_gc.data.data); + *tmp_gc.data.data = ' '; + tmp_gc.data.width = tmp_gc.data.size = + tmp_gc.data.have = 1; + grid_view_set_cell(gd, xx, s->cy, &tmp_gc); + } else + grid_view_set_cell(gd, xx, s->cy, + &grid_default_cell); done = 1; } } diff --git a/window-copy.c b/window-copy.c index e9d8eff0..7e21b0f5 100644 --- a/window-copy.c +++ b/window-copy.c @@ -3098,14 +3098,16 @@ static int window_copy_search_lr(struct grid *gd, struct grid *sgd, u_int *ppx, u_int py, u_int first, u_int last, int cis) { - u_int ax, bx, px, pywrap, endline; + u_int ax, bx, px, pywrap, endline, padding; int matched; struct grid_line *gl; + struct grid_cell gc; endline = gd->hsize + gd->sy - 1; for (ax = first; ax < last; ax++) { + padding = 0; for (bx = 0; bx < sgd->sx; bx++) { - px = ax + bx; + px = ax + bx + padding; pywrap = py; /* Wrap line. */ while (px >= gd->sx && pywrap < endline) { @@ -3116,8 +3118,13 @@ window_copy_search_lr(struct grid *gd, struct grid *sgd, u_int *ppx, u_int py, pywrap++; } /* We have run off the end of the grid. */ - if (px >= gd->sx) + if (px - padding >= gd->sx) break; + + grid_get_cell(gd, px, pywrap, &gc); + if (gc.flags & GRID_FLAG_TAB) + padding += gc.data.width - 1; + matched = window_copy_search_compare(gd, px, pywrap, sgd, bx, cis); if (!matched) @@ -3135,14 +3142,16 @@ static int window_copy_search_rl(struct grid *gd, struct grid *sgd, u_int *ppx, u_int py, u_int first, u_int last, int cis) { - u_int ax, bx, px, pywrap, endline; + u_int ax, bx, px, pywrap, endline, padding; int matched; struct grid_line *gl; + struct grid_cell gc; endline = gd->hsize + gd->sy - 1; for (ax = last; ax > first; ax--) { + padding = 0; for (bx = 0; bx < sgd->sx; bx++) { - px = ax - 1 + bx; + px = ax - 1 + bx + padding; pywrap = py; /* Wrap line. */ while (px >= gd->sx && pywrap < endline) { @@ -3153,8 +3162,13 @@ window_copy_search_rl(struct grid *gd, pywrap++; } /* We have run off the end of the grid. */ - if (px >= gd->sx) + if (px - padding >= gd->sx) break; + + grid_get_cell(gd, px, pywrap, &gc); + if (gc.flags & GRID_FLAG_TAB) + padding += gc.data.width - 1; + matched = window_copy_search_compare(gd, px, pywrap, sgd, bx, cis); if (!matched) @@ -3875,10 +3889,12 @@ window_copy_search_marks(struct window_mode_entry *wme, struct screen *ssp, struct screen *s = data->backing, ss; struct screen_write_ctx ctx; struct grid *gd = s->grid; + struct grid_cell gc; int found, cis, stopped = 0; int cflags = REG_EXTENDED; - u_int px, py, i, b, nfound = 0, width; - u_int ssize = 1, start, end; + u_int px, py, i, b, nfound = 0, width, tw; + u_int ssize = 1, start, end, sx = gd->sx; + u_int sy = gd->sy; char *sbuf; regex_t reg; uint64_t stop = 0, tstart, t; @@ -3915,13 +3931,13 @@ window_copy_search_marks(struct window_mode_entry *wme, struct screen *ssp, window_copy_visible_lines(data, &start, &end); else { start = 0; - end = gd->hsize + gd->sy; + end = gd->hsize + sy; stop = get_timer() + WINDOW_COPY_SEARCH_ALL_TIMEOUT; } again: free(data->searchmark); - data->searchmark = xcalloc(gd->sx, gd->sy); + data->searchmark = xcalloc(sx, sy); data->searchgen = 1; for (py = start; py < end; py++) { @@ -3929,21 +3945,34 @@ again: for (;;) { if (regex) { found = window_copy_search_lr_regex(gd, - &px, &width, py, px, gd->sx, ®); + &px, &width, py, px, sx, ®); + grid_get_cell(gd, px + width - 1, py, &gc); + if (gc.data.width > 2) + width += gc.data.width - 1; if (!found) break; } else { found = window_copy_search_lr(gd, ssp->grid, - &px, py, px, gd->sx, cis); + &px, py, px, sx, cis); if (!found) break; } nfound++; + tw = width; if (window_copy_search_mark_at(data, px, py, &b) == 0) { - if (b + width > gd->sx * gd->sy) - width = (gd->sx * gd->sy) - b; - for (i = b; i < b + width; i++) { + if (b + width > sx * sy) + width = (sx * sy) - b; + tw = width; + for (i = b; i < b + tw; i++) { + if (!regex) { + grid_get_cell(gd, px + (i - b), + py, &gc); + if (gc.flags & GRID_FLAG_TAB) + tw += gc.data.width - 1; + if (b + tw > sx * sy) + tw = (sx * sy) - b; + } if (data->searchmark[i] != 0) continue; data->searchmark[i] = data->searchgen; @@ -3953,7 +3982,7 @@ again: else data->searchgen++; } - px += width; + px += tw; } t = get_timer(); From c26d71d3e9425fd5a5f3075888b5425fe6219462 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 11 Nov 2024 08:41:05 +0000 Subject: [PATCH 2/2] Add an option to control the input buffer size, from Ken Lau. --- input.c | 14 ++++++++++++-- options-table.c | 9 +++++++++ options.c | 2 ++ tmux.1 | 3 +++ tmux.h | 2 ++ 5 files changed, 28 insertions(+), 2 deletions(-) diff --git a/input.c b/input.c index c89abc5f..b6eef671 100644 --- a/input.c +++ b/input.c @@ -93,7 +93,6 @@ struct input_ctx { size_t param_len; #define INPUT_BUF_START 32 -#define INPUT_BUF_LIMIT 1048576 u_char *input_buf; size_t input_len; size_t input_space; @@ -729,6 +728,9 @@ static const struct input_transition input_state_consume_st_table[] = { { -1, -1, NULL, NULL } }; +/* Maximum of bytes allowed to read in a single input. */ +static size_t input_buffer_size = INPUT_BUF_DEFAULT_SIZE; + /* Input table compare. */ static int input_table_compare(const void *key, const void *value) @@ -1193,7 +1195,7 @@ input_input(struct input_ctx *ictx) available = ictx->input_space; while (ictx->input_len + 1 >= available) { available *= 2; - if (available > INPUT_BUF_LIMIT) { + if (available > input_buffer_size) { ictx->flags |= INPUT_DISCARD; return (0); } @@ -3017,3 +3019,11 @@ input_reply_clipboard(struct bufferevent *bev, const char *buf, size_t len, bufferevent_write(bev, end, strlen(end)); free(out); } + +/* Set input buffer size. */ +void +input_set_buffer_size(size_t buffer_size) +{ + log_debug("%s: %lu -> %lu", __func__, input_buffer_size, buffer_size); + input_buffer_size = buffer_size; +} diff --git a/options-table.c b/options-table.c index 0711bceb..b327c1b4 100644 --- a/options-table.c +++ b/options-table.c @@ -348,6 +348,15 @@ const struct options_table_entry options_table[] = { "Empty does not write a history file." }, + { .name = "input-buffer-size", + .type = OPTIONS_TABLE_NUMBER, + .scope = OPTIONS_TABLE_SERVER, + .minimum = INPUT_BUF_DEFAULT_SIZE, + .maximum = UINT_MAX, + .default_num = INPUT_BUF_DEFAULT_SIZE, + .text = "Number of byte accpted in a single input before dropping." + }, + { .name = "menu-style", .type = OPTIONS_TABLE_STRING, .scope = OPTIONS_TABLE_WINDOW, diff --git a/options.c b/options.c index 854d4f45..74d34d88 100644 --- a/options.c +++ b/options.c @@ -1177,6 +1177,8 @@ options_push_changes(const char *name) RB_FOREACH(w, windows, &windows) layout_fix_panes(w, NULL); } + if (strcmp(name, "input-buffer-size") == 0) + input_set_buffer_size(options_get_number(global_options, name)); RB_FOREACH(s, sessions, &sessions) status_update_cache(s); diff --git a/tmux.1 b/tmux.1 index 3bdc2fba..3db4d647 100644 --- a/tmux.1 +++ b/tmux.1 @@ -4139,6 +4139,9 @@ option. If not empty, a file to which .Nm will write command prompt history on exit and load it from on start. +.It Ic input-buffer-size Ar bytes +Maximum of bytes allowed to read in escape and control sequences. +Once reached, the sequence will be discarded. .It Ic message-limit Ar number Set the number of error or information messages to save in the message log for each client. diff --git a/tmux.h b/tmux.h index ee1c2523..3d830d6a 100644 --- a/tmux.h +++ b/tmux.h @@ -2840,6 +2840,7 @@ void recalculate_sizes(void); void recalculate_sizes_now(int); /* input.c */ +#define INPUT_BUF_DEFAULT_SIZE 1048576 struct input_ctx *input_init(struct window_pane *, struct bufferevent *, struct colour_palette *); void input_free(struct input_ctx *); @@ -2851,6 +2852,7 @@ void input_parse_screen(struct input_ctx *, struct screen *, screen_write_init_ctx_cb, void *, u_char *, size_t); void input_reply_clipboard(struct bufferevent *, const char *, size_t, const char *); +void input_set_buffer_size(size_t); /* input-key.c */ void input_key_build(void);