diff --git a/cmd-find.c b/cmd-find.c index c5d9e0f3..747d204a 100644 --- a/cmd-find.c +++ b/cmd-find.c @@ -924,6 +924,7 @@ cmd_find_target(struct cmd_find_state *fs, struct cmdq_item *item, const char *target, enum cmd_find_type type, int flags) { struct mouse_event *m; + struct client *c; struct cmd_find_state current; char *colon, *period, *copy = NULL, tmp[256]; const char *session, *window, *pane, *s; @@ -995,6 +996,20 @@ cmd_find_target(struct cmd_find_state *fs, struct cmdq_item *item, if (target == NULL || *target == '\0') goto current; + if (strcmp(target, "@") == 0 || + strcmp(target, "{active}") == 0 || + strcmp(target, "{current}") == 0) { + c = cmdq_get_client(item); + if (c == NULL) { + cmdq_error(item, "no current client"); + goto error; + } + fs->wl = c->session->curw; + fs->wp = c->session->curw->window->active; + fs->w = c->session->curw->window; + goto found; + } + /* Mouse target is a plain = or {mouse}. */ if (strcmp(target, "=") == 0 || strcmp(target, "{mouse}") == 0) { m = &cmdq_get_event(item)->m; diff --git a/cmd-list-keys.c b/cmd-list-keys.c index ddfc0e0c..f25b0636 100644 --- a/cmd-list-keys.c +++ b/cmd-list-keys.c @@ -109,7 +109,8 @@ cmd_list_keys_print_notes(struct cmdq_item *item, struct args *args, key = key_string_lookup_key(bd->key, 0); if (bd->note == NULL || *bd->note == '\0') - note = cmd_list_print(bd->cmdlist, 1); + note = cmd_list_print(bd->cmdlist, + CMD_LIST_PRINT_ESCAPED|CMD_LIST_PRINT_NO_GROUPS); else note = xstrdup(bd->note); tmp = utf8_padcstr(key, keywidth + 1); @@ -288,7 +289,8 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item) tmpused = strlcat(tmp, " ", tmpsize); free(cp); - cp = cmd_list_print(bd->cmdlist, 1); + cp = cmd_list_print(bd->cmdlist, + CMD_LIST_PRINT_ESCAPED|CMD_LIST_PRINT_NO_GROUPS); cplen = strlen(cp); while (tmpused + cplen + 1 >= tmpsize) { tmpsize *= 2; diff --git a/cmd.c b/cmd.c index dfb9ca55..74f4a18d 100644 --- a/cmd.c +++ b/cmd.c @@ -682,11 +682,16 @@ cmd_list_copy(const struct cmd_list *cmdlist, int argc, char **argv) /* Get a command list as a string. */ char * -cmd_list_print(const struct cmd_list *cmdlist, int escaped) +cmd_list_print(const struct cmd_list *cmdlist, int flags) { struct cmd *cmd, *next; char *buf, *this; size_t len; + const char *separator; + int escaped = flags & CMD_LIST_PRINT_ESCAPED; + int no_groups = flags & CMD_LIST_PRINT_NO_GROUPS; + const char *single_separator = escaped ? " \\; " : " ; "; + const char *double_separator = escaped ? " \\;\\; " : " ;; "; len = 1; buf = xcalloc(1, len); @@ -701,17 +706,11 @@ cmd_list_print(const struct cmd_list *cmdlist, int escaped) next = TAILQ_NEXT(cmd, qentry); if (next != NULL) { - if (cmd->group != next->group) { - if (escaped) - strlcat(buf, " \\;\\; ", len); - else - strlcat(buf, " ;; ", len); - } else { - if (escaped) - strlcat(buf, " \\; ", len); - else - strlcat(buf, " ; ", len); - } + if (!no_groups && cmd->group != next->group) + separator = double_separator; + else + separator = single_separator; + strlcat(buf, separator, len); } free(this); diff --git a/compat/imsg-buffer.c b/compat/imsg-buffer.c index 3e314bab..e516b4ab 100644 --- a/compat/imsg-buffer.c +++ b/compat/imsg-buffer.c @@ -1,4 +1,4 @@ -/* $OpenBSD: imsg-buffer.c,v 1.35 2025/06/04 09:06:56 claudio Exp $ */ +/* $OpenBSD: imsg-buffer.c,v 1.36 2025/08/25 08:29:49 claudio Exp $ */ /* * Copyright (c) 2023 Claudio Jeker @@ -699,8 +699,6 @@ msgbuf_queuelen(struct msgbuf *msgbuf) void msgbuf_clear(struct msgbuf *msgbuf) { - struct ibuf *buf; - /* write side */ ibufq_flush(&msgbuf->bufs); diff --git a/format.c b/format.c index fa7e940d..9d60c3f7 100644 --- a/format.c +++ b/format.c @@ -4464,7 +4464,9 @@ format_loop_sessions(struct format_expand_state *es, const char *fmt) for (i = 0; i < n; i++) { s = l[i]; format_log(es, "session loop: $%u", s->id); - if (active != NULL && s->id == ft->c->session->id) + if (active != NULL && + ft->c != NULL && + s->id == ft->c->session->id) use = active; else use = all; diff --git a/grid.c b/grid.c index 63eea68d..7ad6770b 100644 --- a/grid.c +++ b/grid.c @@ -361,9 +361,13 @@ grid_compare(struct grid *ga, struct grid *gb) static void grid_trim_history(struct grid *gd, u_int ny) { + u_int remaining; + grid_free_lines(gd, 0, ny); + remaining = gd->hsize + gd->sy - ny; memmove(&gd->linedata[0], &gd->linedata[ny], - (gd->hsize + gd->sy - ny) * (sizeof *gd->linedata)); + remaining * (sizeof *gd->linedata)); + memset(&gd->linedata[remaining], 0, ny * (sizeof *gd->linedata)); } /* diff --git a/input-keys.c b/input-keys.c index 2f5cfafc..eb5dae88 100644 --- a/input-keys.c +++ b/input-keys.c @@ -313,12 +313,6 @@ static struct input_key_entry input_key_defaults[] = { { .key = KEYC_DC|KEYC_BUILD_MODIFIERS, .data = "\033[3;_~" }, - { .key = KEYC_REPORT_DARK_THEME, - .data = "\033[?997;1n" - }, - { .key = KEYC_REPORT_LIGHT_THEME, - .data = "\033[?997;2n" - }, }; static const key_code input_key_modifiers[] = { 0, diff --git a/input.c b/input.c index 98961f03..0dbc0b2f 100644 --- a/input.c +++ b/input.c @@ -63,7 +63,7 @@ struct input_request { struct input_ctx *ictx; enum input_request_type type; - time_t t; + uint64_t t; enum input_end_type end; int idx; @@ -72,7 +72,7 @@ struct input_request { TAILQ_ENTRY(input_request) entry; TAILQ_ENTRY(input_request) centry; }; -#define INPUT_REQUEST_TIMEOUT 2 +#define INPUT_REQUEST_TIMEOUT 500 /* Input parser cell. */ struct input_cell { @@ -1902,6 +1902,8 @@ input_csi_dispatch_rm_private(struct input_ctx *ictx) break; case 2031: screen_write_mode_clear(sctx, MODE_THEME_UPDATES); + if (ictx->wp != NULL) + ictx->wp->flags &= ~PANE_THEMECHANGED; break; case 2026: /* synchronized output */ screen_write_stop_sync(ictx->wp); @@ -2005,6 +2007,10 @@ input_csi_dispatch_sm_private(struct input_ctx *ictx) break; case 2031: screen_write_mode_set(sctx, MODE_THEME_UPDATES); + if (ictx->wp != NULL) { + ictx->wp->last_theme = window_pane_get_theme(ictx->wp); + ictx->wp->flags &= ~PANE_THEMECHANGED; + } break; case 2026: /* synchronized output */ screen_write_start_sync(ictx->wp); @@ -3237,7 +3243,7 @@ input_request_timer_callback(__unused int fd, __unused short events, void *arg) { struct input_ctx *ictx = arg; struct input_request *ir, *ir1; - time_t t = time(NULL); + uint64_t t = get_timer(); TAILQ_FOREACH_SAFE(ir, &ictx->requests, entry, ir1) { if (ir->t >= t - INPUT_REQUEST_TIMEOUT) @@ -3254,7 +3260,7 @@ input_request_timer_callback(__unused int fd, __unused short events, void *arg) static void input_start_request_timer(struct input_ctx *ictx) { - struct timeval tv = { .tv_sec = 0, .tv_usec = 500000 }; + struct timeval tv = { .tv_sec = 0, .tv_usec = 100000 }; event_del(&ictx->request_timer); event_add(&ictx->request_timer, &tv); @@ -3269,7 +3275,7 @@ input_make_request(struct input_ctx *ictx, enum input_request_type type) ir = xcalloc (1, sizeof *ir); ir->type = type; ir->ictx = ictx; - ir->t = time(NULL); + ir->t = get_timer(); if (++ictx->request_count == 1) input_start_request_timer(ictx); @@ -3390,7 +3396,11 @@ input_request_reply(struct client *c, enum input_request_type type, void *data) input_free_request(ir); continue; } - if (type == INPUT_REQUEST_PALETTE && pd->idx == ir->idx) { + if (type == INPUT_REQUEST_PALETTE) { + if (pd->idx != ir->idx) { + input_free_request(ir); + continue; + } found = ir; break; } @@ -3432,14 +3442,24 @@ input_cancel_requests(struct client *c) static void input_report_current_theme(struct input_ctx *ictx) { - switch (window_pane_get_theme(ictx->wp)) { + struct window_pane *wp = ictx->wp; + + if (wp != NULL) { + wp->last_theme = window_pane_get_theme(wp); + wp->flags &= ~PANE_THEMECHANGED; + + switch (wp->last_theme) { case THEME_DARK: + log_debug("%s: %%%u dark theme", __func__, wp->id); input_reply(ictx, 0, "\033[?997;1n"); break; case THEME_LIGHT: + log_debug("%s: %%%u light theme", __func__, wp->id); input_reply(ictx, 0, "\033[?997;2n"); break; case THEME_UNKNOWN: + log_debug("%s: %%%u unknown theme", __func__, wp->id); break; + } } } diff --git a/key-bindings.c b/key-bindings.c index 12c73347..de17c326 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -444,6 +444,7 @@ key_bindings_init(void) /* Mouse button 1 down on pane. */ "bind -n MouseDown1Pane { select-pane -t=; send -M }", + "bind -n C-MouseDown1Pane { swap-pane -s@ }", /* Mouse button 1 drag on pane. */ "bind -n MouseDrag1Pane { if -F '#{||:#{pane_in_mode},#{mouse_any_flag}}' { send -M } { copy-mode -M } }", @@ -468,6 +469,7 @@ key_bindings_init(void) /* Mouse button 1 down on status line. */ "bind -n MouseDown1Status { switch-client -t= }", + "bind -n C-MouseDown1Status { swap-window -t@ }", /* Mouse wheel down on status line. */ "bind -n WheelDownStatus { next-window }", diff --git a/key-string.c b/key-string.c index a171b0cb..8b9b5604 100644 --- a/key-string.c +++ b/key-string.c @@ -382,6 +382,14 @@ key_string_lookup_key(key_code key, int with_flags) s = "PasteEnd"; goto append; } + if (key == KEYC_REPORT_DARK_THEME) { + s = "ReportDarkTheme"; + goto append; + } + if (key == KEYC_REPORT_LIGHT_THEME) { + s = "ReportLightTheme"; + goto append; + } if (key == KEYC_MOUSE) { s = "Mouse"; goto append; diff --git a/options-table.c b/options-table.c index eac01c09..d9918193 100644 --- a/options-table.c +++ b/options-table.c @@ -664,6 +664,13 @@ const struct options_table_entry options_table[] = { .text = "Time for which status line messages should appear." }, + { .name = "focus-follows-mouse", + .type = OPTIONS_TABLE_FLAG, + .scope = OPTIONS_TABLE_SESSION, + .default_num = 0, + .text = "Whether moving the mouse into a pane selects it." + }, + { .name = "history-limit", .type = OPTIONS_TABLE_NUMBER, .scope = OPTIONS_TABLE_SESSION, @@ -970,6 +977,15 @@ const struct options_table_entry options_table[] = { .text = "Style of the cursor when in the command prompt." }, + { .name = "prompt-command-cursor-style", + .type = OPTIONS_TABLE_CHOICE, + .scope = OPTIONS_TABLE_SESSION, + .choices = options_table_cursor_style_list, + .default_num = 0, + .text = "Style of the cursor in the command prompt when in command " + "mode, if 'status-keys' is set to 'vi'." + }, + { .name = "session-status-current-style", .type = OPTIONS_TABLE_STRING, .scope = OPTIONS_TABLE_WINDOW, diff --git a/options.c b/options.c index f39fbf2a..bfbec5c7 100644 --- a/options.c +++ b/options.c @@ -749,7 +749,7 @@ options_get_number(struct options *oo, const char *name) return (o->value.number); } -const struct cmd_list * +struct cmd_list * options_get_command(struct options *oo, const char *name) { struct options_entry *o; diff --git a/screen-write.c b/screen-write.c index 6d626613..9762f6dd 100644 --- a/screen-write.c +++ b/screen-write.c @@ -61,9 +61,9 @@ screen_write_get_citem(void) ci = TAILQ_FIRST(&screen_write_citem_freelist); if (ci != NULL) { - TAILQ_REMOVE(&screen_write_citem_freelist, ci, entry); - memset(ci, 0, sizeof *ci); - return (ci); + TAILQ_REMOVE(&screen_write_citem_freelist, ci, entry); + memset(ci, 0, sizeof *ci); + return (ci); } return (xcalloc(1, sizeof *ci)); } @@ -71,7 +71,7 @@ screen_write_get_citem(void) static void screen_write_free_citem(struct screen_write_citem *ci) { - TAILQ_INSERT_TAIL(&screen_write_citem_freelist, ci, entry); + TAILQ_INSERT_TAIL(&screen_write_citem_freelist, ci, entry); } static void @@ -1833,8 +1833,16 @@ screen_write_collect_flush(struct screen_write_ctx *ctx, int scroll_only, struct visible_ranges *vr; struct window_pane *wp = ctx->wp; - if (s->mode & MODE_SYNC) + if (s->mode & MODE_SYNC) { + for (y = 0; y < screen_size_y(s); y++) { + cl = &ctx->s->write_list[y]; + TAILQ_FOREACH_SAFE(ci, &cl->items, entry, tmp) { + TAILQ_REMOVE(&cl->items, ci, entry); + screen_write_free_citem(ci); + } + } return; + } if (ctx->scrolled != 0) { log_debug("%s: scrolled %u (region %u-%u)", __func__, @@ -1945,7 +1953,7 @@ void screen_write_collect_end(struct screen_write_ctx *ctx) { struct screen *s = ctx->s; - struct screen_write_citem *ci = ctx->item, *before; + struct screen_write_citem *ci = ctx->item, *nci, *before; struct screen_write_cline *cl = &s->write_list[s->cy]; struct grid_cell gc; u_int xx; @@ -1974,6 +1982,8 @@ screen_write_collect_end(struct screen_write_ctx *ctx) break; grid_view_set_cell(s->grid, xx, s->cy, &grid_default_cell); + log_debug("%s: padding erased (before) at %u", + __func__, xx); } if (xx != s->cx) { if (xx == 0) @@ -1981,8 +1991,19 @@ screen_write_collect_end(struct screen_write_ctx *ctx) if (gc.data.width > 1) { grid_view_set_cell(s->grid, xx, s->cy, &grid_default_cell); + log_debug("%s: padding erased (before) at %u", + __func__, xx); } } + if (xx != s->cx) { + nci = ctx->item; + nci->type = CLEAR; + nci->x = xx; + nci->bg = 8; + nci->used = s->cx - xx; + TAILQ_INSERT_BEFORE(ci, nci, entry); + ctx->item = screen_write_get_citem(); + } } #ifdef ENABLE_SIXEL @@ -1999,6 +2020,16 @@ screen_write_collect_end(struct screen_write_ctx *ctx) if (~gc.flags & GRID_FLAG_PADDING) break; grid_view_set_cell(s->grid, xx, s->cy, &grid_default_cell); + log_debug("%s: padding erased (after) at %u", __func__, xx); + } + if (xx != s->cx) { + nci = ctx->item; + nci->type = CLEAR; + nci->x = s->cx; + nci->bg = 8; + nci->used = xx - s->cx; + TAILQ_INSERT_AFTER(&cl->items, ci, nci, entry); + ctx->item = screen_write_get_citem(); } } @@ -2069,7 +2100,7 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) struct tty_ctx ttyctx; u_int sx = screen_size_x(s), sy = screen_size_y(s); u_int width = ud->width, xx, not_wrap; - int selected, skip = 1; + int selected, skip = 1, redraw = 0; /* Ignore padding cells. */ if (gc->flags & GRID_FLAG_PADDING) @@ -2111,8 +2142,10 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) gl = grid_get_line(s->grid, s->grid->hsize + s->cy); if (gl->flags & GRID_LINE_EXTENDED) { grid_view_get_cell(gd, s->cx, s->cy, &now_gc); - if (screen_write_overwrite(ctx, &now_gc, width)) + if (screen_write_overwrite(ctx, &now_gc, width)) { + redraw = 1; skip = 0; + } } /* @@ -2189,6 +2222,7 @@ screen_write_cell(struct screen_write_ctx *ctx, const struct grid_cell *gc) ttyctx.cell = &tmp_gc; } else ttyctx.cell = gc; + ttyctx.num = redraw ? 2 : 0; tty_write(tty_cmd_cell, &ttyctx); } } @@ -2483,8 +2517,10 @@ screen_write_alternateon(struct screen_write_ctx *ctx, struct grid_cell *gc, screen_write_collect_flush(ctx, 0, __func__); screen_alternate_on(ctx->s, gc, cursor); - if (wp != NULL) + if (wp != NULL) { layout_fix_panes(wp->window, NULL); + server_redraw_window_borders(wp->window); + } screen_write_initctx(ctx, &ttyctx, 1); if (ttyctx.redraw_cb != NULL) @@ -2505,8 +2541,10 @@ screen_write_alternateoff(struct screen_write_ctx *ctx, struct grid_cell *gc, screen_write_collect_flush(ctx, 0, __func__); screen_alternate_off(ctx->s, gc, cursor); - if (wp != NULL) + if (wp != NULL) { layout_fix_panes(wp->window, NULL); + server_redraw_window_borders(wp->window); + } screen_write_initctx(ctx, &ttyctx, 1); if (ttyctx.redraw_cb != NULL) diff --git a/screen.c b/screen.c index d82784c5..7f4f9383 100644 --- a/screen.c +++ b/screen.c @@ -765,6 +765,8 @@ screen_mode_to_string(int mode) strlcat(tmp, "KEYS_EXTENDED,", sizeof tmp); if (mode & MODE_KEYS_EXTENDED_2) strlcat(tmp, "KEYS_EXTENDED_2,", sizeof tmp); + if (mode & MODE_THEME_UPDATES) + strlcat(tmp, "THEME_UPDATES,", sizeof tmp); tmp[strlen(tmp) - 1] = '\0'; return (tmp); } diff --git a/server-client.c b/server-client.c index 0bdff34c..872515fc 100644 --- a/server-client.c +++ b/server-client.c @@ -1092,8 +1092,16 @@ have_event: case NOTYPE: break; case MOVE: - if (where == PANE) + if (where == PANE) { key = KEYC_MOUSEMOVE_PANE; + if (wp != NULL && + wp != w->active && + options_get_number(s->options, "focus-follows-mouse")) { + window_set_active_pane(w, wp, 1); + server_redraw_window_borders(w); + server_status_window(w); + } + } if (where == STATUS) key = KEYC_MOUSEMOVE_STATUS; if (where == STATUS_LEFT) @@ -3012,7 +3020,8 @@ server_client_reset_state(struct client *c) /* * Set mouse mode if requested. To support dragging, always use button - * mode. + * mode. For focus-follows-mouse, we need all-motion mode to receive + * movement events. */ if (options_get_number(oo, "mouse")) { if (c->overlay_draw == NULL) { @@ -3022,7 +3031,9 @@ server_client_reset_state(struct client *c) mode |= MODE_MOUSE_ALL; } } - if (~mode & MODE_MOUSE_ALL) + if (options_get_number(oo, "focus-follows-mouse")) + mode |= MODE_MOUSE_ALL; + else if (~mode & MODE_MOUSE_ALL) mode |= MODE_MOUSE_BUTTON; } @@ -3475,6 +3486,24 @@ server_client_read_only(struct cmdq_item *item, __unused void *data) return (CMD_RETURN_ERROR); } +/* Callback for default command. */ +static enum cmd_retval +server_client_default_command(struct cmdq_item *item, __unused void *data) +{ + struct client *c = cmdq_get_client(item); + struct cmd_list *cmdlist; + struct cmdq_item *new_item; + + cmdlist = options_get_command(global_options, "default-client-command"); + if ((c->flags & CLIENT_READONLY) && + !cmd_list_all_have(cmdlist, CMD_READONLY)) + new_item = cmdq_get_callback(server_client_read_only, NULL); + else + new_item = cmdq_get_command(cmdlist, NULL); + cmdq_insert_after(item, new_item); + return (CMD_RETURN_NORMAL); +} + /* Callback when command is done. */ static enum cmd_retval server_client_command_done(struct cmdq_item *item, __unused void *data) @@ -3503,7 +3532,6 @@ server_client_dispatch_command(struct client *c, struct imsg *imsg) struct cmd_parse_result *pr; struct args_value *values; struct cmdq_item *new_item; - struct cmd_list *cmdlist; if (c->flags & CLIENT_EXIT) return (0); @@ -3524,8 +3552,8 @@ server_client_dispatch_command(struct client *c, struct imsg *imsg) argc = data.argc; if (argc == 0) { - cmdlist = cmd_list_copy(options_get_command(global_options, - "default-client-command"), 0, NULL); + new_item = cmdq_get_callback(server_client_default_command, + NULL); } else { values = args_from_vector(argc, argv); pr = cmd_parse_from_arguments(values, argc, NULL); @@ -3539,18 +3567,17 @@ server_client_dispatch_command(struct client *c, struct imsg *imsg) args_free_values(values, argc); free(values); cmd_free_argv(argc, argv); - cmdlist = pr->cmdlist; + if ((c->flags & CLIENT_READONLY) && + !cmd_list_all_have(pr->cmdlist, CMD_READONLY)) { + new_item = cmdq_get_callback(server_client_read_only, + NULL); + } else + new_item = cmdq_get_command(pr->cmdlist, NULL); + cmd_list_free(pr->cmdlist); } - - if ((c->flags & CLIENT_READONLY) && - !cmd_list_all_have(cmdlist, CMD_READONLY)) - new_item = cmdq_get_callback(server_client_read_only, NULL); - else - new_item = cmdq_get_command(cmdlist, NULL); cmdq_append(c, new_item); cmdq_append(c, cmdq_get_callback(server_client_command_done, NULL)); - cmd_list_free(cmdlist); return (0); error: diff --git a/status.c b/status.c index 0551b547..79ce9cad 100644 --- a/status.c +++ b/status.c @@ -804,7 +804,10 @@ status_prompt_redraw(struct client *c) n = options_get_number(s->options, "prompt-cursor-colour"); sl->active->default_ccolour = n; - n = options_get_number(s->options, "prompt-cursor-style"); + if (c->prompt_mode == PROMPT_COMMAND) + n = options_get_number(s->options, "prompt-command-cursor-style"); + else + n = options_get_number(s->options, "prompt-cursor-style"); screen_set_cursor_style(n, &sl->active->default_cstyle, &sl->active->default_mode); @@ -936,6 +939,8 @@ status_prompt_translate_key(struct client *c, key_code key, key_code *new_key) return (1); case '\033': /* Escape */ c->prompt_mode = PROMPT_COMMAND; + if (c->prompt_index != 0) + c->prompt_index--; c->flags |= CLIENT_REDRAWSTATUS; return (0); } @@ -961,10 +966,11 @@ status_prompt_translate_key(struct client *c, key_code key, key_code *new_key) *new_key = 'u'|KEYC_CTRL; return (1); case 'i': - case '\033': /* Escape */ c->prompt_mode = PROMPT_ENTRY; c->flags |= CLIENT_REDRAWSTATUS; return (0); + case '\033': /* Escape */ + return (0); } switch (key) { diff --git a/tmux.1 b/tmux.1 index ca846d7d..b8acaa38 100644 --- a/tmux.1 +++ b/tmux.1 @@ -841,6 +841,7 @@ Each has a single-character alternative form. .It Li "{last}" Ta "!" Ta "The last (previously current) window" .It Li "{next}" Ta "+" Ta "The next window by number" .It Li "{previous}" Ta "-" Ta "The previous window by number" +.It Li "{current}" Ta "@" Ta "The current window" .El .Pp .Ar target-pane @@ -873,6 +874,7 @@ The following special tokens are available for the pane index: .It Li "{down-of}" Ta "" Ta "The pane below the active pane" .It Li "{left-of}" Ta "" Ta "The pane to the left of the active pane" .It Li "{right-of}" Ta "" Ta "The pane to the right of the active pane" +.It Li "{active}" Ta "@" Ta "The active pane" .El .Pp The tokens @@ -4242,6 +4244,12 @@ passed through to applications running in .Nm . Attached clients should be detached and attached again after changing this option. +.It Xo Ic focus-follows-mouse +.Op Ic on | off +.Xc +When enabled and +.Ic mouse +is on, moving the mouse into a pane selects it. .It Xo Ic get-clipboard .Op Ic both | request | buffer | off .Xc @@ -4696,6 +4704,12 @@ Set the style of the cursor in the command prompt. See the .Ic cursor-style options for available styles. +.It Ic prompt-command-cursor-style Ar style +Set the style of the cursor in the command prompt when vi keys are enabled and +the prompt is in command mode. +See the +.Ic cursor-style +options for available styles. .It Xo Ic renumber-windows .Op Ic on | off .Xc @@ -6232,6 +6246,7 @@ The following variables are available, where appropriate: .It Li "selection_active" Ta "" Ta "1 if selection started and changes with the cursor in copy mode" .It Li "selection_end_x" Ta "" Ta "X position of the end of the selection" .It Li "selection_end_y" Ta "" Ta "Y position of the end of the selection" +.It Li "selection_mode" Ta "" Ta "Selection mode" .It Li "selection_present" Ta "" Ta "1 if selection started in copy mode" .It Li "selection_start_x" Ta "" Ta "X position of the start of the selection" .It Li "selection_start_y" Ta "" Ta "Y position of the start of the selection" diff --git a/tmux.h b/tmux.h index 477b7279..336b7b22 100644 --- a/tmux.h +++ b/tmux.h @@ -1167,6 +1167,16 @@ struct window_pane_resize { }; TAILQ_HEAD(window_pane_resizes, window_pane_resize); +/* + * Client theme, this is worked out from the background colour if not reported + * by terminal. + */ +enum client_theme { + THEME_UNKNOWN, + THEME_LIGHT, + THEME_DARK +}; + /* Child window structure. */ struct window_pane { u_int id; @@ -1233,6 +1243,7 @@ struct window_pane { struct grid_cell cached_gc; struct grid_cell cached_active_gc; struct colour_palette palette; + enum client_theme last_theme; int pipe_fd; struct bufferevent *pipe_event; @@ -1918,16 +1929,6 @@ struct overlay_ranges { u_int nx[OVERLAY_MAX_RANGES]; }; -/* - * Client theme, this is worked out from the background colour if not reported - * by terminal. - */ -enum client_theme { - THEME_UNKNOWN, - THEME_LIGHT, - THEME_DARK -}; - /* Client connection. */ typedef int (*prompt_input_cb)(struct client *, void *, const char *, int); typedef void (*prompt_free_cb)(void *); @@ -2453,7 +2454,7 @@ struct options_entry *options_match_get(struct options *, const char *, int *, int, int *); const char *options_get_string(struct options *, const char *); long long options_get_number(struct options *, const char *); -const struct cmd_list *options_get_command(struct options *, const char *); +struct cmd_list *options_get_command(struct options *, const char *); struct options_entry * printflike(4, 5) options_set_string(struct options *, const char *, int, const char *, ...); struct options_entry *options_set_number(struct options *, const char *, @@ -2750,6 +2751,8 @@ void cmd_list_append(struct cmd_list *, struct cmd *); void cmd_list_append_all(struct cmd_list *, struct cmd_list *); void cmd_list_move(struct cmd_list *, struct cmd_list *); void cmd_list_free(struct cmd_list *); +#define CMD_LIST_PRINT_ESCAPED 0x1 +#define CMD_LIST_PRINT_NO_GROUPS 0x2 char *cmd_list_print(const struct cmd_list *, int); struct cmd *cmd_list_first(struct cmd_list *); struct cmd *cmd_list_next(struct cmd *); diff --git a/tty-keys.c b/tty-keys.c index c59e6a68..33de5cbb 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -956,7 +956,8 @@ partial_key: if (delay == 0) delay = 1; if ((tty->flags & (TTY_WAITFG|TTY_WAITBG) || - (tty->flags & TTY_ALL_REQUEST_FLAGS) != TTY_ALL_REQUEST_FLAGS)) { + (tty->flags & TTY_ALL_REQUEST_FLAGS) != TTY_ALL_REQUEST_FLAGS) || + !TAILQ_EMPTY(&c->input_requests)) { log_debug("%s: increasing delay for active query", c->name); if (delay < 500) delay = 500; @@ -1750,7 +1751,9 @@ tty_keys_palette(struct tty *tty, const char *buf, size_t len, size_t *size) /* Copy the rest up to \033\ or \007. */ start = (endptr - buf) + 1; - for (i = start; i < len && i - start < sizeof tmp; i++) { + for (i = start; i - start < sizeof tmp; i++) { + if (i == len) + return (1); if (buf[i - 1] == '\033' && buf[i] == '\\') break; if (buf[i] == '\007') diff --git a/tty.c b/tty.c index 5c4a8a9a..89f0f7fb 100644 --- a/tty.c +++ b/tty.c @@ -2288,6 +2288,13 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx) vr = screen_redraw_get_visible_ranges(wp, px, py, gcp->data.width); + + if (ctx->num == 2) { + /* xxxx need to check visible range */ + tty_draw_line(tty, s, 0, s->cy, screen_size_x(s), + ctx->xoff - ctx->wox, py, &ctx->defaults, ctx->palette); + return; + } /* Handle partially obstructed wide characters. */ if (gcp->data.width > 1) { @@ -2297,7 +2304,7 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx) for (i = 0; i < OVERLAY_MAX_RANGES; i++) vis += r.nx[i]; if (vis < gcp->data.width || - vis2 < gcp->data.width) { /* xxxx check visible range */ + vis2 < gcp->data.width) { /* xxxx need to check visible range */ tty_draw_line(tty, s, s->cx, s->cy, gcp->data.width, px, py, &ctx->defaults, ctx->palette); return; diff --git a/window-copy.c b/window-copy.c index 957fc5d6..81d84091 100644 --- a/window-copy.c +++ b/window-copy.c @@ -956,6 +956,18 @@ window_copy_formats(struct window_mode_entry *wme, struct format_tree *ft) format_add(ft, "selection_present", "0"); } + switch (data->selflag) { + case SEL_CHAR: + format_add(ft, "selection_mode", "char"); + break; + case SEL_WORD: + format_add(ft, "selection_mode", "word"); + break; + case SEL_LINE: + format_add(ft, "selection_mode", "line"); + break; + } + format_add(ft, "search_present", "%d", data->searchmark != NULL); format_add(ft, "search_timed_out", "%d", data->timeout); if (data->searchcount != -1) { diff --git a/window.c b/window.c index bb930082..b43d3cce 100644 --- a/window.c +++ b/window.c @@ -1036,7 +1036,7 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit) wp = xcalloc(1, sizeof *wp); wp->window = w; wp->options = options_create(w->options); - wp->flags = (PANE_STYLECHANGED|PANE_THEMECHANGED); + wp->flags = PANE_STYLECHANGED; wp->id = next_window_pane_id++; RB_INSERT(window_pane_tree, &all_window_panes, wp); @@ -2051,6 +2051,8 @@ window_pane_get_theme(struct window_pane *wp) void window_pane_send_theme_update(struct window_pane *wp) { + enum client_theme theme; + if (wp == NULL || window_pane_exited(wp)) return; if (~wp->flags & PANE_THEMECHANGED) @@ -2058,16 +2060,23 @@ window_pane_send_theme_update(struct window_pane *wp) if (~wp->screen->mode & MODE_THEME_UPDATES) return; - switch (window_pane_get_theme(wp)) { + theme = window_pane_get_theme(wp); + if (theme == wp->last_theme) + return; + wp->last_theme = theme; + wp->flags &= ~PANE_THEMECHANGED; + + switch (theme) { case THEME_LIGHT: - input_key_pane(wp, KEYC_REPORT_LIGHT_THEME, NULL); + log_debug("%s: %%%u light theme", __func__, wp->id); + bufferevent_write(wp->event, "\033[?997;2n", 9); break; case THEME_DARK: - input_key_pane(wp, KEYC_REPORT_DARK_THEME, NULL); + log_debug("%s: %%%u dark theme", __func__, wp->id); + bufferevent_write(wp->event, "\033[?997;1n", 9); break; case THEME_UNKNOWN: + log_debug("%s: %%%u unknown theme", __func__, wp->id); break; } - - wp->flags &= ~PANE_THEMECHANGED; }