Merge branch 'master' into scrollbars

This commit is contained in:
Nicholas Marriott 2024-10-31 12:58:09 +00:00
commit 3c6c7f3422
10 changed files with 202 additions and 44 deletions

View File

@ -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 += -Wdeclaration-after-statement -Wno-pointer-sign -Wno-attributes
AM_CFLAGS += -Wno-unused-result -Wno-format-y2k AM_CFLAGS += -Wno-unused-result -Wno-format-y2k
if IS_DARWIN if IS_DARWIN
AM_CFLAGS += -Wno-deprecated-declarations -Wno-cast-align AM_CFLAGS += -Wno-deprecated-declarations -Wno-cast-align -Wno-macro-redefined
endif endif
AM_CPPFLAGS += -DDEBUG AM_CPPFLAGS += -DDEBUG
endif endif

View File

@ -5192,6 +5192,16 @@ format_defaults_paste_buffer(struct format_tree *ft, struct paste_buffer *pb)
ft->pb = 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. */ /* Return word at given coordinates. Caller frees. */
char * char *
format_grid_word(struct grid *gd, u_int x, u_int y) format_grid_word(struct grid *gd, u_int x, u_int y)
@ -5211,8 +5221,7 @@ format_grid_word(struct grid *gd, u_int x, u_int y)
grid_get_cell(gd, x, y, &gc); grid_get_cell(gd, x, y, &gc);
if (gc.flags & GRID_FLAG_PADDING) if (gc.flags & GRID_FLAG_PADDING)
break; break;
if (utf8_cstrhas(ws, &gc.data) || if (format_is_word_separator(ws, &gc)) {
(gc.data.size == 1 && *gc.data.data == ' ')) {
found = 1; found = 1;
break; break;
} }
@ -5249,8 +5258,7 @@ format_grid_word(struct grid *gd, u_int x, u_int y)
grid_get_cell(gd, x, y, &gc); grid_get_cell(gd, x, y, &gc);
if (gc.flags & GRID_FLAG_PADDING) if (gc.flags & GRID_FLAG_PADDING)
break; break;
if (utf8_cstrhas(ws, &gc.data) || if (format_is_word_separator(ws, &gc))
(gc.data.size == 1 && *gc.data.data == ' '))
break; break;
ud = xreallocarray(ud, size + 2, sizeof *ud); ud = xreallocarray(ud, size + 2, sizeof *ud);
@ -5277,10 +5285,13 @@ format_grid_line(struct grid *gd, u_int y)
for (x = 0; x < grid_line_length(gd, y); x++) { for (x = 0; x < grid_line_length(gd, y); x++) {
grid_get_cell(gd, x, y, &gc); grid_get_cell(gd, x, y, &gc);
if (gc.flags & GRID_FLAG_PADDING) if (gc.flags & GRID_FLAG_PADDING)
break; continue;
ud = xreallocarray(ud, size + 2, sizeof *ud); 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) { if (size != 0) {
ud[size].size = 0; ud[size].size = 0;

View File

@ -338,6 +338,20 @@ grid_reader_cursor_previous_word(struct grid_reader *gr, const char *separators,
gr->cy = oldy; 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->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);
}
/* Jump forward to character. */ /* Jump forward to character. */
int int
grid_reader_cursor_jump(struct grid_reader *gr, const struct utf8_data *jc) grid_reader_cursor_jump(struct grid_reader *gr, const struct utf8_data *jc)
@ -352,9 +366,7 @@ grid_reader_cursor_jump(struct grid_reader *gr, const struct utf8_data *jc)
xx = grid_line_length(gr->gd, py); xx = grid_line_length(gr->gd, py);
while (px < xx) { while (px < xx) {
grid_get_cell(gr->gd, px, py, &gc); grid_get_cell(gr->gd, px, py, &gc);
if (!(gc.flags & GRID_FLAG_PADDING) && if (grid_reader_cell_equals_data(&gc, jc)) {
gc.data.size == jc->size &&
memcmp(gc.data.data, jc->data, gc.data.size) == 0) {
gr->cx = px; gr->cx = px;
gr->cy = py; gr->cy = py;
return (1); return (1);
@ -382,9 +394,7 @@ grid_reader_cursor_jump_back(struct grid_reader *gr, const struct utf8_data *jc)
for (py = gr->cy + 1; py > 0; py--) { for (py = gr->cy + 1; py > 0; py--) {
for (px = xx; px > 0; px--) { for (px = xx; px > 0; px--) {
grid_get_cell(gr->gd, px - 1, py - 1, &gc); grid_get_cell(gr->gd, px - 1, py - 1, &gc);
if (!(gc.flags & GRID_FLAG_PADDING) && if (grid_reader_cell_equals_data(&gc, jc)) {
gc.data.size == jc->size &&
memcmp(gc.data.data, jc->data, gc.data.size) == 0) {
gr->cx = px - 1; gr->cx = px - 1;
gr->cy = py - 1; gr->cy = py - 1;
return (1); return (1);

42
grid.c
View File

@ -92,6 +92,8 @@ grid_need_extended_cell(const struct grid_cell_entry *gce,
return (1); return (1);
if (gc->link != 0) if (gc->link != 0)
return (1); return (1);
if (gc->flags & GRID_FLAG_TAB)
return (1);
return (0); return (0);
} }
@ -124,7 +126,10 @@ grid_extended_cell(struct grid_line *gl, struct grid_cell_entry *gce,
fatalx("offset too big"); fatalx("offset too big");
gl->flags |= GRID_LINE_EXTENDED; 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 = &gl->extddata[gce->offset];
gee->data = uc; 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); 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. */ /* Free one line. */
static void static void
grid_free_line(struct grid *gd, u_int py) 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->bg = gee->bg;
gc->us = gee->us; gc->us = gee->us;
gc->link = gee->link; 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; return;
} }
@ -1077,13 +1096,18 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx,
} else } else
codelen = 0; codelen = 0;
data = gc.data.data; if (gc.flags & GRID_FLAG_TAB) {
size = gc.data.size; data = "\t";
if ((flags & GRID_STRING_ESCAPE_SEQUENCES) && size = 1;
size == 1 && } else {
*data == '\\') { data = gc.data.data;
data = "\\\\"; size = gc.data.size;
size = 2; if ((flags & GRID_STRING_ESCAPE_SEQUENCES) &&
size == 1 &&
*data == '\\') {
data = "\\\\";
size = 2;
}
} }
while (len < off + size + codelen + 1) { while (len < off + size + codelen + 1) {

27
input.c
View File

@ -1213,6 +1213,10 @@ input_c0_dispatch(struct input_ctx *ictx)
struct screen_write_ctx *sctx = &ictx->ctx; struct screen_write_ctx *sctx = &ictx->ctx;
struct window_pane *wp = ictx->wp; struct window_pane *wp = ictx->wp;
struct screen *s = sctx->s; 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 */ ictx->utf8started = 0; /* can't be valid UTF-8 */
@ -1234,11 +1238,28 @@ input_c0_dispatch(struct input_ctx *ictx)
break; break;
/* Find the next tab point, or use the last column if none. */ /* Find the next tab point, or use the last column if none. */
grid_get_cell(s->grid, s->cx, line, &first_gc);
do { do {
s->cx++; if (!has_content) {
if (bit_test(s->tabs, s->cx)) 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; 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; break;
case '\012': /* LF */ case '\012': /* LF */
case '\013': /* VT */ case '\013': /* VT */

View File

@ -1914,6 +1914,8 @@ screen_write_collect_add(struct screen_write_ctx *ctx,
collect = 1; collect = 1;
if (gc->data.width != 1 || gc->data.size != 1 || *gc->data.data >= 0x7f) if (gc->data.width != 1 || gc->data.size != 1 || *gc->data.data >= 0x7f)
collect = 0; collect = 0;
else if (gc->flags & GRID_FLAG_TAB)
collect = 0;
else if (gc->attr & GRID_ATTR_CHARSET) else if (gc->attr & GRID_ATTR_CHARSET)
collect = 0; collect = 0;
else if (~s->mode & MODE_WRAP) else if (~s->mode & MODE_WRAP)

View File

@ -728,6 +728,55 @@ status_prompt_update(struct client *c, const char *msg, const char *input)
format_free(ft); 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. */ /* Draw client prompt on status line of present else on last line. */
int int
status_prompt_redraw(struct client *c) status_prompt_redraw(struct client *c)
@ -786,6 +835,8 @@ status_prompt_redraw(struct client *c)
pcursor = utf8_strwidth(c->prompt_buffer, c->prompt_index); pcursor = utf8_strwidth(c->prompt_buffer, c->prompt_index);
pwidth = utf8_strwidth(c->prompt_buffer, -1); pwidth = utf8_strwidth(c->prompt_buffer, -1);
if (c->prompt_flags & PROMPT_QUOTENEXT)
pwidth++;
if (pcursor >= left) { if (pcursor >= left) {
/* /*
* The cursor would be outside the screen so start drawing * The cursor would be outside the screen so start drawing
@ -797,23 +848,19 @@ status_prompt_redraw(struct client *c)
offset = 0; offset = 0;
if (pwidth > left) if (pwidth > left)
pwidth = left; pwidth = left;
c->prompt_cursor = start + c->prompt_index - offset; c->prompt_cursor = start + pcursor - offset;
width = 0; width = 0;
for (i = 0; c->prompt_buffer[i].size != 0; i++) { for (i = 0; c->prompt_buffer[i].size != 0; i++) {
if (width < offset) { if (!status_prompt_redraw_quote(c, pcursor, &ctx, offset,
width += c->prompt_buffer[i].width; pwidth, &width, &gc))
continue;
}
if (width >= offset + pwidth)
break; break;
width += c->prompt_buffer[i].width; if (!status_prompt_redraw_character(&ctx, offset, pwidth,
if (width > offset + pwidth) &width, &gc, &c->prompt_buffer[i]))
break; break;
utf8_copy(&gc.data, &c->prompt_buffer[i]);
screen_write_cell(&ctx, &gc);
} }
status_prompt_redraw_quote(c, pcursor, &ctx, offset, pwidth, &width,
&gc);
finished: finished:
screen_write_stop(&ctx); screen_write_stop(&ctx);
@ -864,6 +911,7 @@ status_prompt_translate_key(struct client *c, key_code key, key_code *new_key)
case 'p'|KEYC_CTRL: case 'p'|KEYC_CTRL:
case 't'|KEYC_CTRL: case 't'|KEYC_CTRL:
case 'u'|KEYC_CTRL: case 'u'|KEYC_CTRL:
case 'v'|KEYC_CTRL:
case 'w'|KEYC_CTRL: case 'w'|KEYC_CTRL:
case 'y'|KEYC_CTRL: case 'y'|KEYC_CTRL:
case '\n': case '\n':
@ -1262,6 +1310,19 @@ status_prompt_key(struct client *c, key_code key)
} }
key &= ~KEYC_MASK_FLAGS; key &= ~KEYC_MASK_FLAGS;
if (c->prompt_flags & (PROMPT_SINGLE|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;
c->prompt_flags &= ~PROMPT_QUOTENEXT;
goto append_key;
}
keys = options_get_number(c->session->options, "status-keys"); keys = options_get_number(c->session->options, "status-keys");
if (keys == MODEKEY_VI) { if (keys == MODEKEY_VI) {
switch (status_prompt_translate_key(c, key, &key)) { switch (status_prompt_translate_key(c, key, &key)) {
@ -1484,6 +1545,9 @@ process_key:
} else } else
prefix = '+'; prefix = '+';
goto changed; goto changed;
case 'v'|KEYC_CTRL:
c->prompt_flags |= PROMPT_QUOTENEXT;
break;
default: default:
goto append_key; goto append_key;
} }
@ -1492,9 +1556,11 @@ process_key:
return (0); return (0);
append_key: append_key:
if (key <= 0x7f) if (key <= 0x7f) {
utf8_set(&tmp, key); 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); utf8_to_data(key, &tmp);
else else
return (0); return (0);

3
tmux.h
View File

@ -718,6 +718,7 @@ struct colour_palette {
#define GRID_FLAG_SELECTED 0x10 #define GRID_FLAG_SELECTED 0x10
#define GRID_FLAG_NOPALETTE 0x20 #define GRID_FLAG_NOPALETTE 0x20
#define GRID_FLAG_CLEARED 0x40 #define GRID_FLAG_CLEARED 0x40
#define GRID_FLAG_TAB 0x80
/* Grid line flags. */ /* Grid line flags. */
#define GRID_LINE_WRAPPED 0x1 #define GRID_LINE_WRAPPED 0x1
@ -1989,6 +1990,7 @@ struct client {
#define PROMPT_NOFORMAT 0x8 #define PROMPT_NOFORMAT 0x8
#define PROMPT_KEY 0x10 #define PROMPT_KEY 0x10
#define PROMPT_ACCEPT 0x20 #define PROMPT_ACCEPT 0x20
#define PROMPT_QUOTENEXT 0x40
int prompt_flags; int prompt_flags;
enum prompt_type prompt_type; enum prompt_type prompt_type;
int prompt_cursor; int prompt_cursor;
@ -2923,6 +2925,7 @@ int attributes_fromstring(const char *);
/* grid.c */ /* grid.c */
extern const struct grid_cell grid_default_cell; extern const struct grid_cell grid_default_cell;
void grid_empty_line(struct grid *, u_int, u_int); 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_equal(const struct grid_cell *, const struct grid_cell *);
int grid_cells_look_equal(const struct grid_cell *, int grid_cells_look_equal(const struct grid_cell *,
const struct grid_cell *); const struct grid_cell *);

2
tty.c
View File

@ -1366,6 +1366,8 @@ tty_check_codeset(struct tty *tty, const struct grid_cell *gc)
/* Characters less than 0x7f are always fine, no matter what. */ /* Characters less than 0x7f are always fine, no matter what. */
if (gc->data.size == 1 && *gc->data.data < 0x7f) if (gc->data.size == 1 && *gc->data.data < 0x7f)
return (gc); return (gc);
if (gc->flags & GRID_FLAG_TAB)
return (gc);
/* UTF-8 terminal and a UTF-8 character - fine. */ /* UTF-8 terminal and a UTF-8 character - fine. */
if (tty->client->flags & CLIENT_UTF8) if (tty->client->flags & CLIENT_UTF8)

View File

@ -3082,6 +3082,9 @@ window_copy_search_compare(struct grid *gd, u_int px, u_int py,
grid_get_cell(sgd, spx, 0, &sgc); grid_get_cell(sgd, spx, 0, &sgc);
sud = &sgc.data; 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) if (ud->size != sud->size || ud->width != sud->width)
return (0); return (0);
@ -3301,6 +3304,11 @@ window_copy_cellstring(const struct grid_line *gl, u_int px, size_t *size,
*allocated = 0; *allocated = 0;
return (&gce->data.data); 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); utf8_to_data(gl->extddata[gce->offset].data, &ud);
if (ud.size == 0) { if (ud.size == 0) {
@ -3696,7 +3704,7 @@ window_copy_search(struct window_mode_entry *wme, int direction, int regex)
struct screen_write_ctx ctx; struct screen_write_ctx ctx;
struct grid *gd = s->grid; struct grid *gd = s->grid;
const char *str = data->searchstr; 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 cis, found, keys, visible_only;
int wrapflag; int wrapflag;
@ -3723,7 +3731,9 @@ window_copy_search(struct window_mode_entry *wme, int direction, int regex)
fx = data->cx; fx = data->cx;
fy = screen_hsize(data->backing) - data->oy + data->cy; 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_start(&ctx, &ss);
screen_write_nputs(&ctx, -1, &grid_default_cell, "%s", str); screen_write_nputs(&ctx, -1, &grid_default_cell, "%s", str);
screen_write_stop(&ctx); screen_write_stop(&ctx);
@ -4083,9 +4093,15 @@ window_copy_match_at_cursor(struct window_copy_mode_data *data)
px = at - (py * sx); px = at - (py * sx);
grid_get_cell(gd, px, gd->hsize + py - data->oy, &gc); grid_get_cell(gd, px, gd->hsize + py - data->oy, &gc);
buf = xrealloc(buf, len + gc.data.size + 1); if (gc.flags & GRID_FLAG_TAB) {
memcpy(buf + len, gc.data.data, gc.data.size); buf = xrealloc(buf, len + 2);
len += gc.data.size; 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) if (len != 0)
buf[len] = '\0'; buf[len] = '\0';
@ -4814,7 +4830,10 @@ window_copy_copy_line(struct window_mode_entry *wme, char **buf, size_t *off,
grid_get_cell(gd, i, sy, &gc); grid_get_cell(gd, i, sy, &gc);
if (gc.flags & GRID_FLAG_PADDING) if (gc.flags & GRID_FLAG_PADDING)
continue; continue;
utf8_copy(&ud, &gc.data); 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)) { if (ud.size == 1 && (gc.attr & GRID_ATTR_CHARSET)) {
s = tty_acs_get(NULL, ud.data[0]); s = tty_acs_get(NULL, ud.data[0]);
if (s != NULL && strlen(s) <= sizeof ud.data) { if (s != NULL && strlen(s) <= sizeof ud.data) {