From 8dedccaa205a91a0dd57012150567403c2ac827d Mon Sep 17 00:00:00 2001 From: nicm Date: Tue, 31 Mar 2020 16:53:23 +0000 Subject: Add non-regex search variants to avoid the performance cost for people with large histories or long lines. --- tmux.1 | 24 ++++++++++- tmux.h | 2 + window-copy.c | 135 +++++++++++++++++++++++++++++++++++++++------------------- 3 files changed, 116 insertions(+), 45 deletions(-) diff --git a/tmux.1 b/tmux.1 index dc78abdc..03950c60 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1503,9 +1503,11 @@ The following commands are supported in copy mode: .It Li "scroll-up" Ta "C-y" Ta "C-Up" .It Li "search-again" Ta "n" Ta "n" .It Li "search-backward " Ta "?" Ta "" -.It Li "search-forward " Ta "/" Ta "" .It Li "search-backward-incremental " Ta "" Ta "C-r" +.It Li "search-backward-text " Ta "" Ta "" +.It Li "search-forward " Ta "/" Ta "" .It Li "search-forward-incremental " Ta "" Ta "C-s" +.It Li "search-forward-text " Ta "" Ta "" .It Li "search-reverse" Ta "N" Ta "N" .It Li "select-line" Ta "V" Ta "" .It Li "select-word" Ta "" Ta "" @@ -1514,6 +1516,26 @@ The following commands are supported in copy mode: .It Li "top-line" Ta "H" Ta "M-R" .El .Pp +The search commands come in several varieties: +.Ql search-forward +and +.Ql search-backward +search for a regular expression; +the +.Ql -text +variants search for a plain text string rather than a regular expression; +.Ql -incremental +perform an incremental search and expect to be used with the +.Fl i +flag to the +.Ic command-prompt +command. +.Ql search-again +repeats the last search and +.Ql search-reverse +does the same but reverses the direction (forward becomes backward and backward +becomes forward). +.Pp Copy commands may take an optional buffer prefix argument which is used to generate the buffer name (the default is .Ql buffer diff --git a/tmux.h b/tmux.h index 222f7d43..3720beee 100644 --- a/tmux.h +++ b/tmux.h @@ -927,7 +927,9 @@ struct window_pane { TAILQ_HEAD (, window_mode_entry) modes; struct event modetimer; time_t modelast; + char *searchstr; + int searchregex; TAILQ_ENTRY(window_pane) entry; RB_ENTRY(window_pane) tree_entry; diff --git a/window-copy.c b/window-copy.c index 8e3f63d1..bb38e60e 100644 --- a/window-copy.c +++ b/window-copy.c @@ -254,6 +254,7 @@ struct window_copy_mode_data { u_int lastsx; /* size of last line w/ content */ int searchtype; + int searchregex; char *searchstr; bitstr_t *searchmark; u_int searchcount; @@ -307,9 +308,11 @@ window_copy_common_init(struct window_mode_entry *wme) if (wp->searchstr != NULL) { data->searchtype = WINDOW_COPY_SEARCHUP; + data->searchregex = wp->searchregex; data->searchstr = xstrdup(wp->searchstr); } else { data->searchtype = WINDOW_COPY_OFF; + data->searchregex = 0; data->searchstr = NULL; } data->searchmark = NULL; @@ -675,6 +678,35 @@ window_copy_key_table(struct window_mode_entry *wme) return ("copy-mode"); } +static int +window_copy_expand_search_string(struct window_copy_cmd_state *cs) +{ + struct window_mode_entry *wme = cs->wme; + struct window_copy_mode_data *data = wme->data; + const char *argument; + char *expanded; + + if (cs->args->argc == 2) { + argument = cs->args->argv[1]; + if (*argument != '\0') { + if (args_has(cs->args, 'F')) { + expanded = format_single(NULL, argument, NULL, + NULL, NULL, wme->wp); + if (*expanded == '\0') { + free(expanded); + return (0); + } + free(data->searchstr); + data->searchstr = expanded; + } else { + free(data->searchstr); + data->searchstr = xstrdup(argument); + } + } + } + return (1); +} + static enum window_copy_cmd_action window_copy_cmd_append_selection(struct window_copy_cmd_state *cs) { @@ -1496,10 +1528,10 @@ window_copy_cmd_search_again(struct window_copy_cmd_state *cs) if (data->searchtype == WINDOW_COPY_SEARCHUP) { for (; np != 0; np--) - window_copy_search_up(wme, 1); + window_copy_search_up(wme, data->searchregex); } else if (data->searchtype == WINDOW_COPY_SEARCHDOWN) { for (; np != 0; np--) - window_copy_search_down(wme, 1); + window_copy_search_down(wme, data->searchregex); } return (WINDOW_COPY_CMD_NOTHING); } @@ -1513,10 +1545,10 @@ window_copy_cmd_search_reverse(struct window_copy_cmd_state *cs) if (data->searchtype == WINDOW_COPY_SEARCHUP) { for (; np != 0; np--) - window_copy_search_down(wme, 1); + window_copy_search_down(wme, data->searchregex); } else if (data->searchtype == WINDOW_COPY_SEARCHDOWN) { for (; np != 0; np--) - window_copy_search_up(wme, 1); + window_copy_search_up(wme, data->searchregex); } return (WINDOW_COPY_CMD_NOTHING); } @@ -1736,29 +1768,13 @@ window_copy_cmd_search_backward(struct window_copy_cmd_state *cs) struct window_mode_entry *wme = cs->wme; struct window_copy_mode_data *data = wme->data; u_int np = wme->prefix; - const char *argument; - char *expanded; - if (cs->args->argc == 2) { - argument = cs->args->argv[1]; - if (*argument != '\0') { - if (args_has(cs->args, 'F')) { - expanded = format_single(NULL, argument, NULL, - NULL, NULL, wme->wp); - if (*expanded == '\0') { - free(expanded); - return (WINDOW_COPY_CMD_NOTHING); - } - free(data->searchstr); - data->searchstr = expanded; - } else { - free(data->searchstr); - data->searchstr = xstrdup(argument); - } - } - } + if (!window_copy_expand_search_string(cs)) + return (WINDOW_COPY_CMD_NOTHING); + if (data->searchstr != NULL) { data->searchtype = WINDOW_COPY_SEARCHUP; + data->searchregex = 1; for (; np != 0; np--) window_copy_search_up(wme, 1); } @@ -1766,40 +1782,62 @@ window_copy_cmd_search_backward(struct window_copy_cmd_state *cs) } static enum window_copy_cmd_action -window_copy_cmd_search_forward(struct window_copy_cmd_state *cs) +window_copy_cmd_search_backward_text(struct window_copy_cmd_state *cs) { struct window_mode_entry *wme = cs->wme; struct window_copy_mode_data *data = wme->data; u_int np = wme->prefix; - const char *argument; - char *expanded; - if (cs->args->argc == 2) { - argument = cs->args->argv[1]; - if (*argument != '\0') { - if (args_has(cs->args, 'F')) { - expanded = format_single(NULL, argument, NULL, - NULL, NULL, wme->wp); - if (*expanded == '\0') { - free(expanded); - return (WINDOW_COPY_CMD_NOTHING); - } - free(data->searchstr); - data->searchstr = expanded; - } else { - free(data->searchstr); - data->searchstr = xstrdup(argument); - } - } + if (!window_copy_expand_search_string(cs)) + return (WINDOW_COPY_CMD_NOTHING); + + if (data->searchstr != NULL) { + data->searchtype = WINDOW_COPY_SEARCHUP; + data->searchregex = 0; + for (; np != 0; np--) + window_copy_search_up(wme, 0); } + return (WINDOW_COPY_CMD_NOTHING); +} + +static enum window_copy_cmd_action +window_copy_cmd_search_forward(struct window_copy_cmd_state *cs) +{ + struct window_mode_entry *wme = cs->wme; + struct window_copy_mode_data *data = wme->data; + u_int np = wme->prefix; + + if (!window_copy_expand_search_string(cs)) + return (WINDOW_COPY_CMD_NOTHING); + if (data->searchstr != NULL) { data->searchtype = WINDOW_COPY_SEARCHDOWN; + data->searchregex = 1; for (; np != 0; np--) window_copy_search_down(wme, 1); } return (WINDOW_COPY_CMD_NOTHING); } +static enum window_copy_cmd_action +window_copy_cmd_search_forward_text(struct window_copy_cmd_state *cs) +{ + struct window_mode_entry *wme = cs->wme; + struct window_copy_mode_data *data = wme->data; + u_int np = wme->prefix; + + if (!window_copy_expand_search_string(cs)) + return (WINDOW_COPY_CMD_NOTHING); + + if (data->searchstr != NULL) { + data->searchtype = WINDOW_COPY_SEARCHDOWN; + data->searchregex = 0; + for (; np != 0; np--) + window_copy_search_down(wme, 0); + } + return (WINDOW_COPY_CMD_NOTHING); +} + static enum window_copy_cmd_action window_copy_cmd_search_backward_incremental(struct window_copy_cmd_state *cs) { @@ -1829,6 +1867,7 @@ window_copy_cmd_search_backward_incremental(struct window_copy_cmd_state *cs) case '=': case '-': data->searchtype = WINDOW_COPY_SEARCHUP; + data->searchregex = 0; free(data->searchstr); data->searchstr = xstrdup(argument); if (!window_copy_search_up(wme, 0)) { @@ -1838,6 +1877,7 @@ window_copy_cmd_search_backward_incremental(struct window_copy_cmd_state *cs) break; case '+': data->searchtype = WINDOW_COPY_SEARCHDOWN; + data->searchregex = 0; free(data->searchstr); data->searchstr = xstrdup(argument); if (!window_copy_search_down(wme, 0)) { @@ -1878,6 +1918,7 @@ window_copy_cmd_search_forward_incremental(struct window_copy_cmd_state *cs) case '=': case '+': data->searchtype = WINDOW_COPY_SEARCHDOWN; + data->searchregex = 0; free(data->searchstr); data->searchstr = xstrdup(argument); if (!window_copy_search_down(wme, 0)) { @@ -1887,6 +1928,7 @@ window_copy_cmd_search_forward_incremental(struct window_copy_cmd_state *cs) break; case '-': data->searchtype = WINDOW_COPY_SEARCHUP; + data->searchregex = 0; free(data->searchstr); data->searchstr = xstrdup(argument); if (!window_copy_search_up(wme, 0)) { @@ -2012,10 +2054,14 @@ static const struct { window_copy_cmd_search_again }, { "search-backward", 0, 1, 0, window_copy_cmd_search_backward }, + { "search-backward-text", 0, 1, 0, + window_copy_cmd_search_backward_text }, { "search-backward-incremental", 1, 1, 0, window_copy_cmd_search_backward_incremental }, { "search-forward", 0, 1, 0, window_copy_cmd_search_forward }, + { "search-forward-text", 0, 1, 0, + window_copy_cmd_search_forward_text }, { "search-forward-incremental", 1, 1, 0, window_copy_cmd_search_forward_incremental }, { "search-reverse", 0, 0, 0, @@ -2624,6 +2670,7 @@ window_copy_search(struct window_mode_entry *wme, int direction, int regex) free(wp->searchstr); wp->searchstr = xstrdup(data->searchstr); + wp->searchregex = regex; fx = data->cx; fy = screen_hsize(data->backing) - data->oy + data->cy; -- cgit From 0dbf4145788cda92b983037e3a7dcdd9a8997e23 Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 1 Apr 2020 07:35:10 +0000 Subject: Performance improvements for regex searching, most notably: - Use the grid data directly instead of copying it. - Special case the most typical one byte character cells and use memcmp for multiple bytes instead of a handrolled loop. - Hoist regcomp out of the loop into the calling functions. GitHub issue 2143. Also a man page from from jmc@. --- window-copy.c | 242 +++++++++++++++++++++++++++++++++------------------------- 1 file changed, 140 insertions(+), 102 deletions(-) diff --git a/window-copy.c b/window-copy.c index bb38e60e..b2b61dc7 100644 --- a/window-copy.c +++ b/window-copy.c @@ -58,10 +58,6 @@ static int window_copy_search_lr(struct grid *, struct grid *, u_int *, u_int, u_int, u_int, int); static int window_copy_search_rl(struct grid *, struct grid *, u_int *, u_int, u_int, u_int, int); -static int window_copy_search_lr_regex(struct grid *, struct grid *, - u_int *, u_int *, u_int, u_int, u_int, int); -static int window_copy_search_rl_regex(struct grid *, struct grid *, - u_int *, u_int *, u_int, u_int, u_int, int); static int window_copy_last_regex(struct grid *gd, u_int py, u_int first, u_int last, u_int len, u_int *ppx, u_int *psx, const char *buf, const regex_t *preg, int eflags); @@ -2263,14 +2259,12 @@ window_copy_search_rl(struct grid *gd, } static int -window_copy_search_lr_regex(struct grid *gd, struct grid *sgd, - u_int *ppx, u_int *psx, u_int py, u_int first, u_int last, int cis) +window_copy_search_lr_regex(struct grid *gd, u_int *ppx, u_int *psx, u_int py, + u_int first, u_int last, regex_t *reg) { - int cflags = REG_EXTENDED, eflags = 0; + int eflags = 0; u_int endline, foundx, foundy, len, pywrap, size = 1; - u_int ssize = 1; - char *buf, *sbuf; - regex_t reg; + char *buf; regmatch_t regmatch; struct grid_line *gl; @@ -2281,19 +2275,7 @@ window_copy_search_lr_regex(struct grid *gd, struct grid *sgd, if (first >= last) return (0); - sbuf = xmalloc(ssize); - sbuf[0] = '\0'; - sbuf = window_copy_stringify(sgd, 0, 0, sgd->sx, sbuf, &ssize); - if (sbuf == NULL) - return (0); - /* Set flags for regex search. */ - if (cis) - cflags |= REG_ICASE; - if (regcomp(®, sbuf, cflags) != 0) { - free(sbuf); - return (0); - } if (first != 0) eflags |= REG_NOTBOL; @@ -2313,7 +2295,7 @@ window_copy_search_lr_regex(struct grid *gd, struct grid *sgd, len += gd->sx; } - if (regexec(®, buf, 1, ®match, eflags) == 0) { + if (regexec(reg, buf, 1, ®match, eflags) == 0) { foundx = first; foundy = py; window_copy_cstrtocellpos(gd, len, &foundx, &foundy, @@ -2329,15 +2311,11 @@ window_copy_search_lr_regex(struct grid *gd, struct grid *sgd, foundy--; } *psx -= *ppx; - regfree(®); - free(sbuf); free(buf); return (1); } } - regfree(®); - free(sbuf); free(buf); *ppx = 0; *psx = 0; @@ -2345,28 +2323,15 @@ window_copy_search_lr_regex(struct grid *gd, struct grid *sgd, } static int -window_copy_search_rl_regex(struct grid *gd, struct grid *sgd, - u_int *ppx, u_int *psx, u_int py, u_int first, u_int last, int cis) +window_copy_search_rl_regex(struct grid *gd, u_int *ppx, u_int *psx, u_int py, + u_int first, u_int last, regex_t *reg) { - int cflags = REG_EXTENDED, eflags = 0; - u_int endline, len, pywrap, size = 1, ssize = 1; - char *buf, *sbuf; - regex_t reg; + int eflags = 0; + u_int endline, len, pywrap, size = 1; + char *buf; struct grid_line *gl; - sbuf = xmalloc(ssize); - sbuf[0] = '\0'; - sbuf = window_copy_stringify(sgd, 0, 0, sgd->sx, sbuf, &ssize); - if (sbuf == NULL) - return (0); - /* Set flags for regex search. */ - if (cis) - cflags |= REG_ICASE; - if (regcomp(®, sbuf, cflags) != 0) { - free(sbuf); - return (0); - } if (first != 0) eflags |= REG_NOTBOL; @@ -2387,22 +2352,38 @@ window_copy_search_rl_regex(struct grid *gd, struct grid *sgd, } if (window_copy_last_regex(gd, py, first, last, len, ppx, psx, buf, - ®, eflags)) + reg, eflags)) { - regfree(®); - free(sbuf); free(buf); return (1); } - regfree(®); - free(sbuf); free(buf); *ppx = 0; *psx = 0; return (0); } +static const char * +window_copy_cellstring(const struct grid_line *gl, u_int px, size_t *size) +{ + struct grid_cell_entry *gce; + + if (px >= gl->cellsize) { + *size = 1; + return (" "); + } + + gce = &gl->celldata[px]; + if (~gce->flags & GRID_FLAG_EXTENDED) { + *size = 1; + return (&gce->data.data); + } + + *size = gl->extddata[gce->offset].data.size; + return (gl->extddata[gce->offset].data.data); +} + /* Find last match in given range. */ static int window_copy_last_regex(struct grid *gd, u_int py, u_int first, u_int last, @@ -2457,20 +2438,33 @@ static char * window_copy_stringify(struct grid *gd, u_int py, u_int first, u_int last, char *buf, u_int *size) { - u_int ax, bx, newsize; - struct grid_cell gc; + u_int ax, bx, newsize = *size; + const struct grid_line *gl; + const char *d; + size_t bufsize = 1024, dlen; + while (bufsize < newsize) + bufsize *= 2; + buf = xrealloc(buf, bufsize); + + gl = grid_peek_line(gd, py); bx = *size - 1; - newsize = *size; for (ax = first; ax < last; ax++) { - grid_get_cell(gd, ax, py, &gc); - newsize += gc.data.size; - buf = xrealloc(buf, newsize); - memcpy(buf + bx, gc.data.data, gc.data.size); - bx += gc.data.size; + d = window_copy_cellstring(gl, ax, &dlen); + newsize += dlen; + while (bufsize < newsize) { + bufsize *= 2; + buf = xrealloc(buf, bufsize); + } + if (dlen == 1) + buf[bx++] = *d; + else { + memcpy(buf + bx, d, dlen); + bx += dlen; + } } - buf[newsize - 1] = '\0'; + *size = newsize; return (buf); } @@ -2480,57 +2474,64 @@ static void window_copy_cstrtocellpos(struct grid *gd, u_int ncells, u_int *ppx, u_int *ppy, const char *str) { - u_int cell, ccell, px, pywrap; - int match; - const char *cstr; - char *celldata, **cells; - struct grid_cell gc; - - /* Set up staggered array of cell contents. This speeds up search. */ - cells = xreallocarray(NULL, ncells, sizeof cells[0]); + u_int cell, ccell, px, pywrap, pos, len; + int match; + const struct grid_line *gl; + const char *d; + size_t dlen; + struct { + const char *d; + size_t dlen; + } *cells; /* Populate the array of cell data. */ + cells = xreallocarray(NULL, ncells, sizeof cells[0]); cell = 0; px = *ppx; pywrap = *ppy; + gl = grid_peek_line(gd, pywrap); while (cell < ncells) { - grid_get_cell(gd, px, pywrap, &gc); - celldata = xmalloc(gc.data.size + 1); - memcpy(celldata, gc.data.data, gc.data.size); - celldata[gc.data.size] = '\0'; - cells[cell] = celldata; + cells[cell].d = window_copy_cellstring(gl, px, + &cells[cell].dlen); cell++; px = (px + 1) % gd->sx; - if (px == 0) + if (px == 0) { pywrap++; + gl = grid_peek_line(gd, pywrap); + } } /* Locate starting cell. */ cell = 0; + len = strlen(str); while (cell < ncells) { ccell = cell; - cstr = str; + pos = 0; match = 1; while (ccell < ncells) { - /* Anchor found to the end. */ - if (*cstr == '\0') { + if (str[pos] == '\0') { match = 0; break; } - - celldata = cells[ccell]; - while (*celldata != '\0' && *cstr != '\0') { - if (*celldata++ != *cstr++) { + d = cells[ccell].d; + dlen = cells[ccell].dlen; + if (dlen == 1) { + if (str[pos] != *d) { match = 0; break; } + pos++; + } else { + if (dlen > len - pos) + dlen = len - pos; + if (memcmp(str + pos, d, dlen) != 0) { + match = 0; + break; + } + pos += dlen; } - - if (!match) - break; ccell++; } - if (match) break; cell++; @@ -2548,8 +2549,6 @@ window_copy_cstrtocellpos(struct grid *gd, u_int ncells, u_int *ppx, u_int *ppy, *ppy = pywrap; /* Free cell data. */ - for (cell = 0; cell < ncells; cell++) - free(cells[cell]); free(cells); } @@ -2609,29 +2608,45 @@ window_copy_search_jump(struct window_mode_entry *wme, struct grid *gd, struct grid *sgd, u_int fx, u_int fy, u_int endline, int cis, int wrap, int direction, int regex) { - u_int i, px, sx; - int found = 0; + u_int i, px, sx, ssize = 1; + int found = 0, cflags = REG_EXTENDED; + char *sbuf; + regex_t reg; + + if (regex) { + sbuf = xmalloc(ssize); + sbuf[0] = '\0'; + sbuf = window_copy_stringify(sgd, 0, 0, sgd->sx, sbuf, &ssize); + if (cis) + cflags |= REG_ICASE; + if (regcomp(®, sbuf, cflags) != 0) { + free(sbuf); + return (0); + } + } if (direction) { for (i = fy; i <= endline; i++) { - if (regex) - found = window_copy_search_lr_regex(gd, sgd, - &px, &sx, i, fx, gd->sx, cis); - else + if (regex) { + found = window_copy_search_lr_regex(gd, + &px, &sx, i, fx, gd->sx, ®); + } else { found = window_copy_search_lr(gd, sgd, &px, i, fx, gd->sx, cis); + } if (found) break; fx = 0; } } else { for (i = fy + 1; endline < i; i--) { - if (regex) - found = window_copy_search_rl_regex(gd, sgd, - &px, &sx, i - 1, 0, fx + 1, cis); - else + if (regex) { + found = window_copy_search_rl_regex(gd, + &px, &sx, i - 1, 0, fx + 1, ®); + } else { found = window_copy_search_rl(gd, sgd, &px, i - 1, 0, fx + 1, cis); + } if (found) { i--; break; @@ -2639,6 +2654,10 @@ window_copy_search_jump(struct window_mode_entry *wme, struct grid *gd, fx = gd->sx - 1; } } + if (regex) { + free(sbuf); + regfree(®); + } if (found) { window_copy_scroll_to(wme, px, i); @@ -2710,7 +2729,11 @@ window_copy_search_marks(struct window_mode_entry *wme, struct screen *ssp, struct screen_write_ctx ctx; struct grid *gd = s->grid; int found, cis, which = -1; + int cflags = REG_EXTENDED; u_int px, py, b, nfound = 0, width; + u_int ssize = 1; + char *sbuf; + regex_t reg; if (ssp == NULL) { width = screen_write_strlen("%s", data->searchstr); @@ -2728,25 +2751,36 @@ window_copy_search_marks(struct window_mode_entry *wme, struct screen *ssp, free(data->searchmark); data->searchmark = bit_alloc((gd->hsize + gd->sy) * gd->sx); + if (regex) { + sbuf = xmalloc(ssize); + sbuf[0] = '\0'; + sbuf = window_copy_stringify(ssp->grid, 0, 0, ssp->grid->sx, + sbuf, &ssize); + if (cis) + cflags |= REG_ICASE; + if (regcomp(®, sbuf, cflags) != 0) { + free(sbuf); + return (0); + } + } for (py = 0; py < gd->hsize + gd->sy; py++) { px = 0; for (;;) { if (regex) { found = window_copy_search_lr_regex(gd, - ssp->grid, &px, &width, py, px, - gd->sx, cis); + &px, &width, py, px, gd->sx, ®); if (!found) break; - } - else { + } else { found = window_copy_search_lr(gd, ssp->grid, - &px, py, px, gd->sx, cis); + &px, py, px, gd->sx, cis); if (!found) break; } nfound++; - if (px == data->cx && py == gd->hsize + data->cy - data->oy) + if (px == data->cx && + py == gd->hsize + data->cy - data->oy) which = nfound; b = (py * gd->sx) + px; @@ -2755,6 +2789,10 @@ window_copy_search_marks(struct window_mode_entry *wme, struct screen *ssp, px++; } } + if (regex) { + free(sbuf); + regfree(®); + } if (which != -1) data->searchthis = 1 + nfound - which; -- cgit From 3476eccf48001865ee43f98454d76895158063dc Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 1 Apr 2020 07:52:07 +0000 Subject: Use a comparison to check for wrap and avoid an expensive modulus. --- window-copy.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/window-copy.c b/window-copy.c index b2b61dc7..c00017b7 100644 --- a/window-copy.c +++ b/window-copy.c @@ -2494,8 +2494,9 @@ window_copy_cstrtocellpos(struct grid *gd, u_int ncells, u_int *ppx, u_int *ppy, cells[cell].d = window_copy_cellstring(gl, px, &cells[cell].dlen); cell++; - px = (px + 1) % gd->sx; - if (px == 0) { + px++; + if (px == gd->sx) { + px = 0; pywrap++; gl = grid_peek_line(gd, pywrap); } -- cgit From a5922546ac1e596fc37dc883cff12a9026f68d27 Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 1 Apr 2020 08:07:05 +0000 Subject: Do not go down the regex search path (which is expensive because we need to convert the grid data into a string for regexec and reverse it to find the grid position) if the search string does not contain any regex special characters. --- window-copy.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/window-copy.c b/window-copy.c index c00017b7..8cf499ca 100644 --- a/window-copy.c +++ b/window-copy.c @@ -2685,23 +2685,27 @@ window_copy_search(struct window_mode_entry *wme, int direction, int regex) struct screen *s = data->backing, ss; struct screen_write_ctx ctx; struct grid *gd = s->grid; + const char *str = data->searchstr; u_int fx, fy, endline; int wrapflag, cis, found; + if (regex && str[strcspn(str, "^$*+()?[].\\")] == '\0') + regex = 0; + free(wp->searchstr); - wp->searchstr = xstrdup(data->searchstr); + wp->searchstr = xstrdup(str); wp->searchregex = regex; fx = data->cx; fy = screen_hsize(data->backing) - data->oy + data->cy; - screen_init(&ss, screen_write_strlen("%s", data->searchstr), 1, 0); + screen_init(&ss, screen_write_strlen("%s", str), 1, 0); screen_write_start(&ctx, NULL, &ss); - screen_write_nputs(&ctx, -1, &grid_default_cell, "%s", data->searchstr); + screen_write_nputs(&ctx, -1, &grid_default_cell, "%s", str); screen_write_stop(&ctx); wrapflag = options_get_number(wp->window->options, "wrap-search"); - cis = window_copy_is_lowercase(data->searchstr); + cis = window_copy_is_lowercase(str); if (direction) { window_copy_move_right(s, &fx, &fy, wrapflag); -- cgit From 9f378a163ff9457eb5b0398ea66263a32e58bba2 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Wed, 1 Apr 2020 10:09:49 +0100 Subject: 3.1-rc4. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 78fbc8c9..9675660c 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ # configure.ac -AC_INIT([tmux], 3.1-rc3) +AC_INIT([tmux], 3.1-rc4) AC_PREREQ([2.60]) AC_CONFIG_AUX_DIR(etc) -- cgit