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) {