Compare commits

..

12 Commits

Author SHA1 Message Date
Thomas Adam
e7c829fc67 Merge branch 'obsd-master' 2023-09-01 20:01:10 +01:00
nicm
579829eef2 Only compare the actual size of the UTF-8 character, not all of it. 2023-09-01 18:43:54 +00:00
Nicholas Marriott
3aa20f6e75 Use %05X not %08X. 2023-09-01 19:37:27 +01:00
nicm
f78279bb2e Add missing -T to getopt string. 2023-09-01 16:40:38 +00:00
Thomas Adam
a99d7c6314 makefile: fixup bad merge 2023-09-01 17:13:55 +01:00
Thomas Adam
cf1ed67fcc Merge branch 'obsd-master' 2023-09-01 17:09:41 +01:00
Thomas Adam
1aec420465 Merge branch 'obsd-master' 2023-09-01 17:06:27 +01:00
nicm
16e4b39359 Clear combine flag when a non-UTF-8 set of characters is encountered. 2023-09-01 16:01:54 +00:00
nicm
9456258ccc Rewrite combined character handling to be more consistent and to support
newer Unicode combined characters (which we have to "know" are combined
since they are not width zero). GitHub issue 3600.
2023-09-01 14:29:11 +00:00
nicm
c41d59f232 Expand name before looking for window with -S, GitHub issue 3670. 2023-09-01 14:24:46 +00:00
Nicholas Marriott
d682ef88e6 Bump width and height to 10000. 2023-09-01 14:54:27 +01:00
nicm
c1e6e54e6e Add detach-on-destroy previous and next, mostly from Alexis Hildebrandt. 2023-09-01 13:48:54 +00:00
14 changed files with 1255 additions and 78 deletions

View File

@ -1,5 +1,3 @@
# Makefile.am
# Obvious program stuff.
bin_PROGRAMS = tmux
CLEANFILES = tmux.1.mdoc tmux.1.man cmd-parse.c
@ -191,6 +189,7 @@ dist_tmux_SOURCES = \
tty-keys.c \
tty-term.c \
tty.c \
utf8-combined.c \
utf8.c \
window-buffer.c \
window-client.c \

View File

@ -39,7 +39,7 @@ const struct cmd_entry cmd_capture_pane_entry = {
.name = "capture-pane",
.alias = "capturep",
.args = { "ab:CeE:JNpPqS:t:", 0, 0, NULL },
.args = { "ab:CeE:JNpPqS:Tt:", 0, 0, NULL },
.usage = "[-aCeJNpPqT] " CMD_BUFFER_USAGE " [-E end-line] "
"[-S start-line] " CMD_TARGET_PANE_USAGE,

View File

@ -60,7 +60,7 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
struct session *s = target->s;
struct winlink *wl = target->wl, *new_wl = NULL;
int idx = target->idx, before;
char *cause = NULL, *cp;
char *cause = NULL, *cp, *expanded;
const char *template, *name;
struct cmd_find_state fs;
struct args_value *av;
@ -71,16 +71,19 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
*/
name = args_get(args, 'n');
if (args_has(args, 'S') && name != NULL && target->idx == -1) {
expanded = format_single(item, name, c, s, NULL, NULL);
RB_FOREACH(wl, winlinks, &s->windows) {
if (strcmp(wl->window->name, name) != 0)
if (strcmp(wl->window->name, expanded) != 0)
continue;
if (new_wl == NULL) {
new_wl = wl;
continue;
}
cmdq_error(item, "multiple windows named %s", name);
free(expanded);
return (CMD_RETURN_ERROR);
}
free(expanded);
if (new_wl != NULL) {
if (args_has(args, 'd'))
return (CMD_RETURN_NORMAL);

View File

@ -24,8 +24,8 @@
#include "tmux.h"
#define SIXEL_COLOUR_REGISTERS 1024
#define SIXEL_WIDTH_LIMIT 2016
#define SIXEL_HEIGHT_LIMIT 2016
#define SIXEL_WIDTH_LIMIT 10000
#define SIXEL_HEIGHT_LIMIT 10000
struct sixel_line {
u_int x;

View File

@ -85,7 +85,7 @@ static const char *options_table_remain_on_exit_list[] = {
"off", "on", "failed", NULL
};
static const char *options_table_detach_on_destroy_list[] = {
"off", "on", "no-detached", NULL
"off", "on", "no-detached", "previous", "next", NULL
};
static const char *options_table_extended_keys_list[] = {
"off", "on", "always", NULL

View File

@ -1887,6 +1887,8 @@ screen_write_collect_add(struct screen_write_ctx *ctx,
u_int sx = screen_size_x(s);
int collect;
ctx->flags &= ~SCREEN_WRITE_COMBINE;
/*
* Don't need to check that the attributes and whatnot are still the
* same - input_parse will end the collection when anything that isn't
@ -1935,46 +1937,37 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
{
struct screen *s = ctx->s;
struct grid *gd = s->grid;
const struct utf8_data *ud = &gc->data;
const struct utf8_data zwj = { "\342\200\215", 0, 3, 0 };
struct grid_cell copy;
const struct utf8_data *ud = &gc->data, *previous = NULL, *combine;
struct grid_line *gl;
struct grid_cell_entry *gce;
struct grid_cell tmp_gc, now_gc;
struct tty_ctx ttyctx;
u_int sx = screen_size_x(s), sy = screen_size_y(s);
u_int width = gc->data.width, xx, last, cx, cy;
u_int width = ud->width, xx, last, cx, cy;
int selected, skip = 1;
/* Ignore padding cells. */
if (gc->flags & GRID_FLAG_PADDING)
return;
/*
* If this is a zero width joiner, set the flag so the next character
* will be treated as zero width and appended. Note that we assume a
* ZWJ will not change the width - the width of the first character is
* used.
*/
if (ud->size == 3 && memcmp(ud->data, "\342\200\215", 3) == 0) {
log_debug("zero width joiner at %u,%u", s->cx, s->cy);
ctx->flags |= SCREEN_WRITE_ZWJ;
/* Check if this cell needs to be combined with the previous cell. */
if (ctx->flags & SCREEN_WRITE_COMBINE)
previous = &ctx->previous;
switch (utf8_try_combined(ud, previous, &combine, &width)) {
case UTF8_DISCARD_NOW:
log_debug("%s: UTF8_DISCARD_NOW (width %u)", __func__, width);
ctx->flags &= ~SCREEN_WRITE_COMBINE;
return;
}
/*
* If the width is zero, combine onto the previous character. We always
* combine with the cell to the left of the cursor position. In theory,
* the application could have moved the cursor somewhere else, but if
* they are silly enough to do that, who cares?
*/
if (ctx->flags & SCREEN_WRITE_ZWJ) {
case UTF8_WRITE_NOW:
log_debug("%s: UTF8_WRITE_NOW (width %u)", __func__, width);
ctx->flags &= ~SCREEN_WRITE_COMBINE;
break;
case UTF8_COMBINE_NOW:
log_debug("%s: UTF8_COMBINE_NOW (width %u)", __func__, width);
screen_write_collect_flush(ctx, 0, __func__);
screen_write_combine(ctx, &zwj, &xx, &cx);
}
if (width == 0 || (ctx->flags & SCREEN_WRITE_ZWJ)) {
ctx->flags &= ~SCREEN_WRITE_ZWJ;
screen_write_collect_flush(ctx, 0, __func__);
if ((gc = screen_write_combine(ctx, ud, &xx, &cx)) != NULL) {
gc = screen_write_combine(ctx, combine, &xx, &cx);
if (gc != NULL) {
cy = s->cy;
screen_write_set_cursor(ctx, xx, s->cy);
screen_write_initctx(ctx, &ttyctx, 0);
@ -1982,8 +1975,27 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc)
tty_write(tty_cmd_cell, &ttyctx);
s->cx = cx; s->cy = cy;
}
ctx->flags &= ~SCREEN_WRITE_COMBINE;
return;
case UTF8_WRITE_MAYBE_COMBINE:
log_debug("%s: UTF8_WRITE_MAYBE_COMBINE (width %u)", __func__,
width);
utf8_copy(&ctx->previous, ud);
ctx->flags |= SCREEN_WRITE_COMBINE;
break;
case UTF8_DISCARD_MAYBE_COMBINE:
log_debug("%s: UTF8_DISCARD_MAYBE_COMBINE (width %u)", __func__,
width);
utf8_copy(&ctx->previous, ud);
ctx->flags |= SCREEN_WRITE_COMBINE;
return;
}
if (width != ud->width) {
memcpy(&copy, gc, sizeof copy);
copy.data.width = width;
gc = ©
}
ud = NULL;
/* Flush any existing scrolling. */
screen_write_collect_flush(ctx, 1, __func__);

View File

@ -27,7 +27,6 @@
#include "tmux.h"
static struct session *server_next_session(struct session *);
static void server_destroy_session_group(struct session *);
void
@ -207,7 +206,7 @@ server_kill_window(struct window *w, int renumber)
if (session_detach(s, wl)) {
server_destroy_session_group(s);
break;
} else
}
server_redraw_session_group(s);
}
@ -385,9 +384,10 @@ server_destroy_session_group(struct session *s)
struct session_group *sg;
struct session *s1;
if ((sg = session_group_contains(s)) == NULL)
if ((sg = session_group_contains(s)) == NULL) {
server_destroy_session(s);
else {
session_destroy(s, 1, __func__);
} else {
TAILQ_FOREACH_SAFE(s, &sg->sessions, gentry, s1) {
server_destroy_session(s);
session_destroy(s, 1, __func__);
@ -396,52 +396,55 @@ server_destroy_session_group(struct session *s)
}
static struct session *
server_next_session(struct session *s)
server_find_session(struct session *s,
int (*f)(struct session *, struct session *))
{
struct session *s_loop, *s_out = NULL;
RB_FOREACH(s_loop, sessions, &sessions) {
if (s_loop == s)
continue;
if (s_out == NULL ||
timercmp(&s_loop->activity_time, &s_out->activity_time, <))
if (s_loop != s && (s_out == NULL || f(s_loop, s_out)))
s_out = s_loop;
}
return (s_out);
}
static struct session *
server_next_detached_session(struct session *s)
static int
server_newer_session(struct session *s_loop, struct session *s_out)
{
struct session *s_loop, *s_out = NULL;
RB_FOREACH(s_loop, sessions, &sessions) {
if (s_loop == s || s_loop->attached)
continue;
if (s_out == NULL ||
timercmp(&s_loop->activity_time, &s_out->activity_time, <))
s_out = s_loop;
return (timercmp(&s_loop->activity_time, &s_out->activity_time, <));
}
return (s_out);
static int
server_newer_detached_session(struct session *s_loop, struct session *s_out)
{
if (s_loop->attached)
return (0);
return (server_newer_session(s_loop, s_out));
}
void
server_destroy_session(struct session *s)
{
struct client *c;
struct session *s_new;
struct session *s_new = NULL;
int detach_on_destroy;
detach_on_destroy = options_get_number(s->options, "detach-on-destroy");
if (detach_on_destroy == 0)
s_new = server_next_session(s);
s_new = server_find_session(s, server_newer_session);
else if (detach_on_destroy == 2)
s_new = server_next_detached_session(s);
else
s_new = server_find_session(s, server_newer_detached_session);
else if (detach_on_destroy == 3)
s_new = session_previous_session(s);
else if (detach_on_destroy == 4)
s_new = session_next_session(s);
if (s_new == s)
s_new = NULL;
TAILQ_FOREACH(c, &clients, entry) {
if (c->session != s)
continue;
c->session = NULL;
c->last_session = NULL;
server_client_set_session(c, s_new);
if (s_new == NULL)
c->flags |= CLIENT_EXIT;

View File

@ -207,6 +207,7 @@ server_start(struct tmuxproc *client, int flags, struct event_base *base,
fatal("pledge failed");
input_key_build();
utf8_build_combined();
RB_INIT(&windows);
RB_INIT(&all_window_panes);
TAILQ_INIT(&clients);

View File

@ -365,10 +365,8 @@ session_detach(struct session *s, struct winlink *wl)
session_group_synchronize_from(s);
if (RB_EMPTY(&s->windows)) {
session_destroy(s, 1, __func__);
if (RB_EMPTY(&s->windows))
return (1);
}
return (0);
}

15
tmux.1
View File

@ -4042,16 +4042,25 @@ The default is 80x24.
If enabled and the session is no longer attached to any clients, it is
destroyed.
.It Xo Ic detach-on-destroy
.Op Ic off | on | no-detached
.Op Ic off | on | no-detached | previous | next
.Xc
If on (the default), the client is detached when the session it is attached to
If
.Ic on
(the default), the client is detached when the session it is attached to
is destroyed.
If off, the client is switched to the most recently active of the remaining
If
.Ic off ,
the client is switched to the most recently active of the remaining
sessions.
If
.Ic no-detached ,
the client is detached only if there are no detached sessions; if detached
sessions exist, the client is switched to the most recently active.
If
.Ic previous
or
.Ic next ,
the client is switched to the previous or next session in alphabetical order.
.It Ic display-panes-active-colour Ar colour
Set the colour used by the
.Ic display-panes

21
tmux.h
View File

@ -627,6 +627,15 @@ enum utf8_state {
UTF8_ERROR
};
/* UTF-8 combine state. */
enum utf8_combine_state {
UTF8_DISCARD_NOW, /* discard immediately */
UTF8_WRITE_NOW, /* do not combine, write immediately */
UTF8_COMBINE_NOW, /* combine immediately */
UTF8_WRITE_MAYBE_COMBINE, /* write but try to combine the next */
UTF8_DISCARD_MAYBE_COMBINE /* discard but try to combine the next */
};
/* Colour flags. */
#define COLOUR_FLAG_256 0x01000000
#define COLOUR_FLAG_RGB 0x02000000
@ -921,7 +930,7 @@ struct screen_write_ctx {
int flags;
#define SCREEN_WRITE_SYNC 0x1
#define SCREEN_WRITE_ZWJ 0x2
#define SCREEN_WRITE_COMBINE 0x2
screen_write_init_ctx_cb init_ctx_cb;
void *arg;
@ -929,6 +938,7 @@ struct screen_write_ctx {
struct screen_write_citem *item;
u_int scrolled;
u_int bg;
struct utf8_data previous;
};
/* Box border lines option. */
@ -3338,6 +3348,15 @@ int utf8_cstrhas(const char *, const struct utf8_data *);
char *osdep_get_name(int, char *);
char *osdep_get_cwd(int);
struct event_base *osdep_event_init(void);
/* utf8-combined.c */
void utf8_build_combined(void);
int utf8_try_combined(const struct utf8_data *,
const struct utf8_data *, const struct utf8_data **,
u_int *width);
/* procname.c */
char *get_proc_name(int, char *);
char *get_proc_cwd(int);
/* log.c */
void log_add_level(void);

1135
utf8-combined.c Normal file

File diff suppressed because it is too large Load Diff

6
utf8.c
View File

@ -229,13 +229,13 @@ utf8_width(struct utf8_data *ud, int *width)
case 0:
return (UTF8_ERROR);
}
log_debug("UTF-8 %.*s is %08X", (int)ud->size, ud->data, (u_int)wc);
log_debug("UTF-8 %.*s is %05X", (int)ud->size, ud->data, (u_int)wc);
#ifdef HAVE_UTF8PROC
*width = utf8proc_wcwidth(wc);
log_debug("utf8proc_wcwidth(%08X) returned %d", (u_int)wc, *width);
log_debug("utf8proc_wcwidth(%05X) returned %d", (u_int)wc, *width);
#else
*width = wcwidth(wc);
log_debug("wcwidth(%08X) returned %d", (u_int)wc, *width);
log_debug("wcwidth(%05X) returned %d", (u_int)wc, *width);
if (*width < 0) {
/*
* C1 control characters are nonprintable, so they are always

View File

@ -3763,8 +3763,7 @@ window_copy_search(struct window_mode_entry *wme, int direction, int regex)
}
}
endline = gd->hsize + gd->sy - 1;
}
else {
} else {
window_copy_move_left(s, &fx, &fy, wrapflag);
endline = 0;
}
@ -3806,8 +3805,7 @@ window_copy_search(struct window_mode_entry *wme, int direction, int regex)
data->cy = fy - screen_hsize(data->backing) +
data-> oy;
}
}
else {
} else {
/*
* When searching backward, position the cursor at the
* beginning of the mark.