From 63582c154c760652093846e3d009fcf9c93ece95 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 25 Oct 2024 07:57:49 +0000 Subject: [PATCH 01/10] Add a helper function for cell data comparison, from Alexander Arch. --- grid-reader.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/grid-reader.c b/grid-reader.c index c14e3d33..f5050f7e 100644 --- a/grid-reader.c +++ b/grid-reader.c @@ -338,6 +338,18 @@ grid_reader_cursor_previous_word(struct grid_reader *gr, const char *separators, gr->cy = oldy; } +/* Compare grid cell to UTF-8 data. Return 1 if equal, 0 if not. */ +static int +grid_reader_cell_equals_data(const struct grid_cell *gc, + const struct utf8_data *ud) +{ + if (gc->flags & GRID_FLAG_PADDING) + return (0); + if (gc->data.size != ud->size) + return (0); + return (memcmp(gc->data.data, ud->data, gc->data.size) == 0); +} + /* Jump forward to character. */ int grid_reader_cursor_jump(struct grid_reader *gr, const struct utf8_data *jc) @@ -352,9 +364,7 @@ grid_reader_cursor_jump(struct grid_reader *gr, const struct utf8_data *jc) 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) { + if (grid_reader_cell_equals_data(&gc, jc)) { gr->cx = px; gr->cy = py; return (1); @@ -382,9 +392,7 @@ grid_reader_cursor_jump_back(struct grid_reader *gr, const struct utf8_data *jc) 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) { + if (grid_reader_cell_equals_data(&gc, jc)) { gr->cx = px - 1; gr->cy = py - 1; return (1); From fdbc6cdea543695bb10622d1a483507639f52ad9 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 25 Oct 2024 15:00:18 +0000 Subject: [PATCH 02/10] Flag tabs if possible in the grid cell so they can be preserved on copying and capture-pane. From Alexander Arch in GitHub issue 4201. --- grid-reader.c | 2 ++ grid.c | 42 +++++++++++++++++++++++++++++++++--------- input.c | 27 ++++++++++++++++++++++++--- screen-write.c | 2 ++ tmux.h | 2 ++ window-copy.c | 25 +++++++++++++++++++++---- 6 files changed, 84 insertions(+), 16 deletions(-) diff --git a/grid-reader.c b/grid-reader.c index f5050f7e..6cd60c50 100644 --- a/grid-reader.c +++ b/grid-reader.c @@ -345,6 +345,8 @@ grid_reader_cell_equals_data(const struct grid_cell *gc, { if (gc->flags & GRID_FLAG_PADDING) return (0); + if (gc->flags & GRID_FLAG_TAB && ud->size == 1 && *ud->data == '\t') + return (1); if (gc->data.size != ud->size) return (0); return (memcmp(gc->data.data, ud->data, gc->data.size) == 0); diff --git a/grid.c b/grid.c index 78629419..a87a2376 100644 --- a/grid.c +++ b/grid.c @@ -92,6 +92,8 @@ grid_need_extended_cell(const struct grid_cell_entry *gce, return (1); if (gc->link != 0) return (1); + if (gc->flags & GRID_FLAG_TAB) + return (1); return (0); } @@ -124,7 +126,10 @@ grid_extended_cell(struct grid_line *gl, struct grid_cell_entry *gce, fatalx("offset too big"); gl->flags |= GRID_LINE_EXTENDED; - utf8_from_data(&gc->data, &uc); + if (gc->flags & GRID_FLAG_TAB) + uc = gc->data.width; + else + utf8_from_data(&gc->data, &uc); gee = &gl->extddata[gce->offset]; gee->data = uc; @@ -252,6 +257,16 @@ grid_cells_equal(const struct grid_cell *gc1, const struct grid_cell *gc2) return (memcmp(gc1->data.data, gc2->data.data, gc1->data.size) == 0); } +/* Set grid cell to a tab. */ +void +grid_set_tab(struct grid_cell *gc, u_int width) +{ + memset(&gc->data, 0, sizeof gc->data); + gc->flags |= GRID_FLAG_TAB; + gc->data.width = gc->data.size = gc->data.have = width; + memset(&gc->data, ' ', gc->data.size); +} + /* Free one line. */ static void grid_free_line(struct grid *gd, u_int py) @@ -515,7 +530,11 @@ grid_get_cell1(struct grid_line *gl, u_int px, struct grid_cell *gc) gc->bg = gee->bg; gc->us = gee->us; gc->link = gee->link; - utf8_to_data(gee->data, &gc->data); + + if (gc->flags & GRID_FLAG_TAB) + grid_set_tab(gc, gee->data); + else + utf8_to_data(gee->data, &gc->data); } return; } @@ -1077,13 +1096,18 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx, } else codelen = 0; - data = gc.data.data; - size = gc.data.size; - if ((flags & GRID_STRING_ESCAPE_SEQUENCES) && - size == 1 && - *data == '\\') { - data = "\\\\"; - size = 2; + if (gc.flags & GRID_FLAG_TAB) { + data = "\t"; + size = 1; + } else { + data = gc.data.data; + size = gc.data.size; + if ((flags & GRID_STRING_ESCAPE_SEQUENCES) && + size == 1 && + *data == '\\') { + data = "\\\\"; + size = 2; + } } while (len < off + size + codelen + 1) { diff --git a/input.c b/input.c index b13e078f..c89abc5f 100644 --- a/input.c +++ b/input.c @@ -1213,6 +1213,10 @@ input_c0_dispatch(struct input_ctx *ictx) struct screen_write_ctx *sctx = &ictx->ctx; struct window_pane *wp = ictx->wp; struct screen *s = sctx->s; + struct grid_cell gc, first_gc; + u_int cx = s->cx, line = s->cy + s->grid->hsize; + u_int width; + int has_content = 0; ictx->utf8started = 0; /* can't be valid UTF-8 */ @@ -1234,11 +1238,28 @@ input_c0_dispatch(struct input_ctx *ictx) break; /* Find the next tab point, or use the last column if none. */ + grid_get_cell(s->grid, s->cx, line, &first_gc); do { - s->cx++; - if (bit_test(s->tabs, s->cx)) + if (!has_content) { + grid_get_cell(s->grid, cx, line, &gc); + if (gc.data.size != 1 || + *gc.data.data != ' ' || + !grid_cells_look_equal(&gc, &first_gc)) + has_content = 1; + } + cx++; + if (bit_test(s->tabs, cx)) break; - } while (s->cx < screen_size_x(s) - 1); + } while (cx < screen_size_x(s) - 1); + + width = cx - s->cx; + if (has_content || width > sizeof gc.data.data) + s->cx = cx; + else { + grid_get_cell(s->grid, s->cx, line, &gc); + grid_set_tab(&gc, width); + screen_write_collect_add(sctx, &gc); + } break; case '\012': /* LF */ case '\013': /* VT */ diff --git a/screen-write.c b/screen-write.c index 793ad556..46b7378e 100644 --- a/screen-write.c +++ b/screen-write.c @@ -1814,6 +1814,8 @@ screen_write_collect_add(struct screen_write_ctx *ctx, collect = 1; if (gc->data.width != 1 || gc->data.size != 1 || *gc->data.data >= 0x7f) collect = 0; + else if (gc->flags & GRID_FLAG_TAB) + collect = 0; else if (gc->attr & GRID_ATTR_CHARSET) collect = 0; else if (~s->mode & MODE_WRAP) diff --git a/tmux.h b/tmux.h index 0e8d600e..940c8d2d 100644 --- a/tmux.h +++ b/tmux.h @@ -709,6 +709,7 @@ struct colour_palette { #define GRID_FLAG_SELECTED 0x10 #define GRID_FLAG_NOPALETTE 0x20 #define GRID_FLAG_CLEARED 0x40 +#define GRID_FLAG_TAB 0x80 /* Grid line flags. */ #define GRID_LINE_WRAPPED 0x1 @@ -2861,6 +2862,7 @@ int attributes_fromstring(const char *); /* grid.c */ extern const struct grid_cell grid_default_cell; void grid_empty_line(struct grid *, u_int, u_int); +void grid_set_tab(struct grid_cell *, u_int); int grid_cells_equal(const struct grid_cell *, const struct grid_cell *); int grid_cells_look_equal(const struct grid_cell *, const struct grid_cell *); diff --git a/window-copy.c b/window-copy.c index b271d5bb..5e1a327c 100644 --- a/window-copy.c +++ b/window-copy.c @@ -3301,6 +3301,11 @@ window_copy_cellstring(const struct grid_line *gl, u_int px, size_t *size, *allocated = 0; return (&gce->data.data); } + if (gce->flags & GRID_FLAG_TAB) { + *size = 1; + *allocated = 0; + return ("\t"); + } utf8_to_data(gl->extddata[gce->offset].data, &ud); if (ud.size == 0) { @@ -4083,9 +4088,15 @@ window_copy_match_at_cursor(struct window_copy_mode_data *data) px = at - (py * sx); grid_get_cell(gd, px, gd->hsize + py - data->oy, &gc); - buf = xrealloc(buf, len + gc.data.size + 1); - memcpy(buf + len, gc.data.data, gc.data.size); - len += gc.data.size; + if (gc.flags & GRID_FLAG_TAB) { + buf = xrealloc(buf, len + 2); + buf[len] = '\t'; + len++; + } else { + buf = xrealloc(buf, len + gc.data.size + 1); + memcpy(buf + len, gc.data.data, gc.data.size); + len += gc.data.size; + } } if (len != 0) buf[len] = '\0'; @@ -4812,7 +4823,13 @@ window_copy_copy_line(struct window_mode_entry *wme, char **buf, size_t *off, grid_get_cell(gd, i, sy, &gc); if (gc.flags & GRID_FLAG_PADDING) continue; - utf8_copy(&ud, &gc.data); + if (gc.flags & GRID_FLAG_TAB) { + memset(ud.data, 0, sizeof ud.data); + *ud.data = '\t'; + ud.have = ud.size = 1; + ud.width = gc.data.width; + } else + utf8_copy(&ud, &gc.data); if (ud.size == 1 && (gc.attr & GRID_ATTR_CHARSET)) { s = tty_acs_get(NULL, ud.data[0]); if (s != NULL && strlen(s) <= sizeof ud.data) { From eaec0a48f4f07060f4bdfdd19fe8cd3fe5818fe7 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 25 Oct 2024 15:13:10 +0000 Subject: [PATCH 03/10] Do not stop stop at first padding in format_grid_line and handle tabs. --- format.c | 7 +++++-- window-copy.c | 9 +++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/format.c b/format.c index 28a57b24..415640f0 100644 --- a/format.c +++ b/format.c @@ -5273,10 +5273,13 @@ format_grid_line(struct grid *gd, u_int y) for (x = 0; x < grid_line_length(gd, y); x++) { grid_get_cell(gd, x, y, &gc); if (gc.flags & GRID_FLAG_PADDING) - break; + continue; ud = xreallocarray(ud, size + 2, sizeof *ud); - memcpy(&ud[size++], &gc.data, sizeof *ud); + if (gc.flags & GRID_FLAG_TAB) + utf8_set(&ud[size++], '\t'); + else + memcpy(&ud[size++], &gc.data, sizeof *ud); } if (size != 0) { ud[size].size = 0; diff --git a/window-copy.c b/window-copy.c index 5e1a327c..4e8f947b 100644 --- a/window-copy.c +++ b/window-copy.c @@ -4823,12 +4823,9 @@ window_copy_copy_line(struct window_mode_entry *wme, char **buf, size_t *off, grid_get_cell(gd, i, sy, &gc); if (gc.flags & GRID_FLAG_PADDING) continue; - if (gc.flags & GRID_FLAG_TAB) { - memset(ud.data, 0, sizeof ud.data); - *ud.data = '\t'; - ud.have = ud.size = 1; - ud.width = gc.data.width; - } else + if (gc.flags & GRID_FLAG_TAB) + utf8_set(&ud, '\t'); + else utf8_copy(&ud, &gc.data); if (ud.size == 1 && (gc.attr & GRID_ATTR_CHARSET)) { s = tty_acs_get(NULL, ud.data[0]); From 487b0ee124363f838bfd5dcc1dcccd4db22f414a Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 25 Oct 2024 15:19:15 +0000 Subject: [PATCH 04/10] Do not attempt to search for zero length strings, from Alexander Arch in GitHub issue 4209. --- window-copy.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/window-copy.c b/window-copy.c index 4e8f947b..7a2734ac 100644 --- a/window-copy.c +++ b/window-copy.c @@ -3701,7 +3701,7 @@ window_copy_search(struct window_mode_entry *wme, int direction, int regex) struct screen_write_ctx ctx; struct grid *gd = s->grid; const char *str = data->searchstr; - u_int at, endline, fx, fy, start; + u_int at, endline, fx, fy, start, ssx; int cis, found, keys, visible_only; int wrapflag; @@ -3728,7 +3728,9 @@ window_copy_search(struct window_mode_entry *wme, int direction, int regex) fx = data->cx; fy = screen_hsize(data->backing) - data->oy + data->cy; - screen_init(&ss, screen_write_strlen("%s", str), 1, 0); + if ((ssx = screen_write_strlen("%s", str)) == 0) + return (0); + screen_init(&ss, ssx, 1, 0); screen_write_start(&ctx, &ss); screen_write_nputs(&ctx, -1, &grid_default_cell, "%s", str); screen_write_stop(&ctx); From 71a503e40c48bf36c66f9723faa0c9aa0a828363 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 25 Oct 2024 15:32:51 +0000 Subject: [PATCH 05/10] Allow control characters to be entered at the command prompt prefixed with with C-v, from Alexander Arch in GitHub issue 4206. --- status.c | 39 ++++++++++++++++++++++++++++++++++----- tmux.h | 1 + 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/status.c b/status.c index 2f64845d..f39c2584 100644 --- a/status.c +++ b/status.c @@ -740,6 +740,8 @@ status_prompt_redraw(struct client *c) u_int pcursor, pwidth, promptline; struct grid_cell gc; struct format_tree *ft; + u_char ch; + struct utf8_data *ud; if (c->tty.sx == 0 || c->tty.sy == 0) return (0); @@ -801,17 +803,25 @@ status_prompt_redraw(struct client *c) width = 0; for (i = 0; c->prompt_buffer[i].size != 0; i++) { + ud = &c->prompt_buffer[i]; if (width < offset) { - width += c->prompt_buffer[i].width; + width += ud->width; continue; } if (width >= offset + pwidth) break; - width += c->prompt_buffer[i].width; + width += ud->width; if (width > offset + pwidth) break; - utf8_copy(&gc.data, &c->prompt_buffer[i]); + ch = *ud->data; + if (ud->size == 1 && (ch <= 0x1f || ch == 0x7f)) { + gc.data.data[0] = '^'; + gc.data.data[1] = (ch == 0x7f) ? '?' : ch|0x40; + gc.data.size = gc.data.have = 2; + gc.data.width = 2; + } else + utf8_copy(&gc.data, ud); screen_write_cell(&ctx, &gc); } @@ -864,6 +874,7 @@ status_prompt_translate_key(struct client *c, key_code key, key_code *new_key) case 'p'|KEYC_CTRL: case 't'|KEYC_CTRL: case 'u'|KEYC_CTRL: + case 'v'|KEYC_CTRL: case 'w'|KEYC_CTRL: case 'y'|KEYC_CTRL: case '\n': @@ -1262,6 +1273,19 @@ status_prompt_key(struct client *c, key_code key) } key &= ~KEYC_MASK_FLAGS; + if (c->prompt_flags & (PROMPT_SINGLE|PROMPT_QUOTENEXT)) { + c->prompt_flags &= ~PROMPT_QUOTENEXT; + if ((key & KEYC_MASK_KEY) == KEYC_BSPACE) + key = 0x7f; + else if ((key & KEYC_MASK_KEY) > 0x7f) { + if (!KEYC_IS_UNICODE(key)) + return (0); + key &= KEYC_MASK_KEY; + } else + key &= (key & KEYC_CTRL) ? 0x1f : KEYC_MASK_KEY; + goto append_key; + } + keys = options_get_number(c->session->options, "status-keys"); if (keys == MODEKEY_VI) { switch (status_prompt_translate_key(c, key, &key)) { @@ -1484,6 +1508,9 @@ process_key: } else prefix = '+'; goto changed; + case 'v'|KEYC_CTRL: + c->prompt_flags |= PROMPT_QUOTENEXT; + break; default: goto append_key; } @@ -1492,9 +1519,11 @@ process_key: return (0); append_key: - if (key <= 0x7f) + if (key <= 0x7f) { utf8_set(&tmp, key); - else if (KEYC_IS_UNICODE(key)) + if (key <= 0x1f || key == 0x7f) + tmp.width = 2; + } else if (KEYC_IS_UNICODE(key)) utf8_to_data(key, &tmp); else return (0); diff --git a/tmux.h b/tmux.h index 940c8d2d..014dcdf2 100644 --- a/tmux.h +++ b/tmux.h @@ -1938,6 +1938,7 @@ struct client { #define PROMPT_NOFORMAT 0x8 #define PROMPT_KEY 0x10 #define PROMPT_ACCEPT 0x20 +#define PROMPT_QUOTENEXT 0x40 int prompt_flags; enum prompt_type prompt_type; int prompt_cursor; From 40c01c2d370e637e2ed4dfd247fdecdb84b4ac81 Mon Sep 17 00:00:00 2001 From: nicm Date: Fri, 25 Oct 2024 19:36:38 +0000 Subject: [PATCH 06/10] Allow tabs even on terminals without UTF-8, reported by jmc. --- tty.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tty.c b/tty.c index f1fd47bc..f4676170 100644 --- a/tty.c +++ b/tty.c @@ -1361,6 +1361,8 @@ tty_check_codeset(struct tty *tty, const struct grid_cell *gc) /* Characters less than 0x7f are always fine, no matter what. */ if (gc->data.size == 1 && *gc->data.data < 0x7f) return (gc); + if (gc->flags & GRID_FLAG_TAB) + return (gc); /* UTF-8 terminal and a UTF-8 character - fine. */ if (tty->client->flags & CLIENT_UTF8) From 125a7b91776a02d3ba391bbcdaf571cbbe2a33f2 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 28 Oct 2024 08:11:59 +0000 Subject: [PATCH 07/10] Fix issues in the command prompt: set PROMPT_QUOTENEXT after quoting than before, meaning that accidentally scrolling the mouse wheel doesn't break quoting; and move the cursor correctly over wide characters. From Alexander Arch in GitHub issue 4212. --- status.c | 81 +++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 59 insertions(+), 22 deletions(-) diff --git a/status.c b/status.c index f39c2584..32833f8c 100644 --- a/status.c +++ b/status.c @@ -728,6 +728,55 @@ status_prompt_update(struct client *c, const char *msg, const char *input) format_free(ft); } +/* Redraw character. Return 1 if can continue redrawing, 0 otherwise. */ +static int +status_prompt_redraw_character(struct screen_write_ctx *ctx, u_int offset, + u_int pwidth, u_int *width, struct grid_cell *gc, + const struct utf8_data *ud) +{ + u_char ch; + + if (*width < offset) { + *width += ud->width; + return (1); + } + if (*width >= offset + pwidth) + return (0); + *width += ud->width; + if (*width > offset + pwidth) + return (0); + + ch = *ud->data; + if (ud->size == 1 && (ch <= 0x1f || ch == 0x7f)) { + gc->data.data[0] = '^'; + gc->data.data[1] = (ch == 0x7f) ? '?' : ch|0x40; + gc->data.size = gc->data.have = 2; + gc->data.width = 2; + } else + utf8_copy(&gc->data, ud); + screen_write_cell(ctx, gc); + return (1); +} + +/* + * Redraw quote indicator '^' if necessary. Return 1 if can continue redrawing, + * 0 otherwise. + */ +static int +status_prompt_redraw_quote(const struct client *c, u_int pcursor, + struct screen_write_ctx *ctx, u_int offset, u_int pwidth, u_int *width, + struct grid_cell *gc) +{ + struct utf8_data ud; + + if (c->prompt_flags & PROMPT_QUOTENEXT && ctx->s->cx == pcursor + 1) { + utf8_set(&ud, '^'); + return (status_prompt_redraw_character(ctx, offset, pwidth, + width, gc, &ud)); + } + return (1); +} + /* Draw client prompt on status line of present else on last line. */ int status_prompt_redraw(struct client *c) @@ -740,8 +789,6 @@ status_prompt_redraw(struct client *c) u_int pcursor, pwidth, promptline; struct grid_cell gc; struct format_tree *ft; - u_char ch; - struct utf8_data *ud; if (c->tty.sx == 0 || c->tty.sy == 0) return (0); @@ -788,6 +835,8 @@ status_prompt_redraw(struct client *c) pcursor = utf8_strwidth(c->prompt_buffer, c->prompt_index); pwidth = utf8_strwidth(c->prompt_buffer, -1); + if (c->prompt_flags & PROMPT_QUOTENEXT) + pwidth++; if (pcursor >= left) { /* * The cursor would be outside the screen so start drawing @@ -799,31 +848,19 @@ status_prompt_redraw(struct client *c) offset = 0; if (pwidth > left) pwidth = left; - c->prompt_cursor = start + c->prompt_index - offset; + c->prompt_cursor = start + pcursor - offset; width = 0; for (i = 0; c->prompt_buffer[i].size != 0; i++) { - ud = &c->prompt_buffer[i]; - if (width < offset) { - width += ud->width; - continue; - } - if (width >= offset + pwidth) + if (!status_prompt_redraw_quote(c, pcursor, &ctx, offset, + pwidth, &width, &gc)) break; - width += ud->width; - if (width > offset + pwidth) + if (!status_prompt_redraw_character(&ctx, offset, pwidth, + &width, &gc, &c->prompt_buffer[i])) break; - - ch = *ud->data; - if (ud->size == 1 && (ch <= 0x1f || ch == 0x7f)) { - gc.data.data[0] = '^'; - gc.data.data[1] = (ch == 0x7f) ? '?' : ch|0x40; - gc.data.size = gc.data.have = 2; - gc.data.width = 2; - } else - utf8_copy(&gc.data, ud); - screen_write_cell(&ctx, &gc); } + status_prompt_redraw_quote(c, pcursor, &ctx, offset, pwidth, &width, + &gc); finished: screen_write_stop(&ctx); @@ -1274,7 +1311,6 @@ status_prompt_key(struct client *c, key_code key) key &= ~KEYC_MASK_FLAGS; if (c->prompt_flags & (PROMPT_SINGLE|PROMPT_QUOTENEXT)) { - c->prompt_flags &= ~PROMPT_QUOTENEXT; if ((key & KEYC_MASK_KEY) == KEYC_BSPACE) key = 0x7f; else if ((key & KEYC_MASK_KEY) > 0x7f) { @@ -1283,6 +1319,7 @@ status_prompt_key(struct client *c, key_code key) key &= KEYC_MASK_KEY; } else key &= (key & KEYC_CTRL) ? 0x1f : KEYC_MASK_KEY; + c->prompt_flags &= ~PROMPT_QUOTENEXT; goto append_key; } From 62e15e905bda23de4aafca6c3f9bc08ebe2326a1 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 28 Oct 2024 08:16:06 +0000 Subject: [PATCH 08/10] Treat tabs as a word separator, from Alexander Arch in GitHub issue 4201. --- format.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/format.c b/format.c index 415640f0..6ca5ad07 100644 --- a/format.c +++ b/format.c @@ -5188,6 +5188,16 @@ format_defaults_paste_buffer(struct format_tree *ft, struct paste_buffer *pb) ft->pb = pb; } +static int +format_is_word_separator(const char *ws, const struct grid_cell *gc) +{ + if (utf8_cstrhas(ws, &gc->data)) + return (1); + if (gc->flags & GRID_FLAG_TAB) + return (1); + return gc->data.size == 1 && *gc->data.data == ' '; +} + /* Return word at given coordinates. Caller frees. */ char * format_grid_word(struct grid *gd, u_int x, u_int y) @@ -5207,8 +5217,7 @@ format_grid_word(struct grid *gd, u_int x, u_int y) grid_get_cell(gd, x, y, &gc); if (gc.flags & GRID_FLAG_PADDING) break; - if (utf8_cstrhas(ws, &gc.data) || - (gc.data.size == 1 && *gc.data.data == ' ')) { + if (format_is_word_separator(ws, &gc)) { found = 1; break; } @@ -5245,8 +5254,7 @@ format_grid_word(struct grid *gd, u_int x, u_int y) grid_get_cell(gd, x, y, &gc); if (gc.flags & GRID_FLAG_PADDING) break; - if (utf8_cstrhas(ws, &gc.data) || - (gc.data.size == 1 && *gc.data.data == ' ')) + if (format_is_word_separator(ws, &gc)) break; ud = xreallocarray(ud, size + 2, sizeof *ud); From c8bd42de160902a3efebf021b660fd230ca08ca2 Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 28 Oct 2024 08:16:51 +0000 Subject: [PATCH 09/10] Match tab cells when searching, from Alexander Arch in GitHub issue 4201. --- window-copy.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/window-copy.c b/window-copy.c index 7a2734ac..8542092e 100644 --- a/window-copy.c +++ b/window-copy.c @@ -3082,6 +3082,9 @@ window_copy_search_compare(struct grid *gd, u_int px, u_int py, grid_get_cell(sgd, spx, 0, &sgc); sud = &sgc.data; + if (*sud->data == '\t' && sud->size == 1 && gc.flags & GRID_FLAG_TAB) + return (1); + if (ud->size != sud->size || ud->width != sud->width) return (0); From 46f384665965dd279754915772d3d86245b48784 Mon Sep 17 00:00:00 2001 From: Nicholas Marriott Date: Thu, 31 Oct 2024 12:57:40 +0000 Subject: [PATCH 10/10] Add -Wno-macro-redefined for macOS. --- Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.am b/Makefile.am index 6c7d2d3f..ff0de9f8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -30,7 +30,7 @@ AM_CFLAGS += -Wundef -Wbad-function-cast -Winline -Wcast-align AM_CFLAGS += -Wdeclaration-after-statement -Wno-pointer-sign -Wno-attributes AM_CFLAGS += -Wno-unused-result -Wno-format-y2k if IS_DARWIN -AM_CFLAGS += -Wno-deprecated-declarations -Wno-cast-align +AM_CFLAGS += -Wno-deprecated-declarations -Wno-cast-align -Wno-macro-redefined endif AM_CPPFLAGS += -DDEBUG endif