diff --git a/cmd-copy-mode.c b/cmd-copy-mode.c index b35d0af1..9c0015bf 100644 --- a/cmd-copy-mode.c +++ b/cmd-copy-mode.c @@ -30,8 +30,8 @@ const struct cmd_entry cmd_copy_mode_entry = { .name = "copy-mode", .alias = NULL, - .args = { "Met:u", 0, 0 }, - .usage = "[-Mu] " CMD_TARGET_PANE_USAGE, + .args = { "eHMt:u", 0, 0 }, + .usage = "[-eHMu] " CMD_TARGET_PANE_USAGE, .target = { 't', CMD_FIND_PANE, 0 }, diff --git a/cmd-run-shell.c b/cmd-run-shell.c index 2f45f492..5f207bbb 100644 --- a/cmd-run-shell.c +++ b/cmd-run-shell.c @@ -31,6 +31,7 @@ static enum cmd_retval cmd_run_shell_exec(struct cmd *, struct cmdq_item *); +static void cmd_run_shell_timer(int, short, void *); static void cmd_run_shell_callback(struct job *); static void cmd_run_shell_free(void *); static void cmd_run_shell_print(struct job *, const char *); @@ -39,8 +40,8 @@ const struct cmd_entry cmd_run_shell_entry = { .name = "run-shell", .alias = "run", - .args = { "bt:", 1, 1 }, - .usage = "[-b] " CMD_TARGET_PANE_USAGE " shell-command", + .args = { "bd:t:", 0, 1 }, + .usage = "[-b] [-d delay] " CMD_TARGET_PANE_USAGE " [shell-command]", .target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL }, @@ -50,8 +51,11 @@ const struct cmd_entry cmd_run_shell_entry = { struct cmd_run_shell_data { char *cmd; + char *cwd; struct cmdq_item *item; + struct session *s; int wp_id; + struct event timer; }; static void @@ -91,9 +95,14 @@ cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item) struct session *s = item->target.s; struct winlink *wl = item->target.wl; struct window_pane *wp = item->target.wp; + const char *delay; + double d; + struct timeval tv; + char *end; cdata = xcalloc(1, sizeof *cdata); - cdata->cmd = format_single(item, args->argv[0], c, s, wl, wp); + if (args->argc != 0) + cdata->cmd = format_single(item, args->argv[0], c, s, wl, wp); if (args_has(args, 't') && wp != NULL) cdata->wp_id = wp->id; @@ -103,18 +112,48 @@ cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item) if (!args_has(args, 'b')) cdata->item = item; - if (job_run(cdata->cmd, s, server_client_get_cwd(item->client, s), NULL, - cmd_run_shell_callback, cmd_run_shell_free, cdata, 0) == NULL) { - cmdq_error(item, "failed to run command: %s", cdata->cmd); - free(cdata); - return (CMD_RETURN_ERROR); - } + cdata->cwd = xstrdup(server_client_get_cwd(item->client, s)); + cdata->s = s; + session_add_ref(s, __func__); + + evtimer_set(&cdata->timer, cmd_run_shell_timer, cdata); + + if ((delay = args_get(args, 'd')) != NULL) { + d = strtod(delay, &end); + if (*end != '\0') { + cmdq_error(item, "invalid delay time: %s", delay); + cmd_run_shell_free(cdata); + return (CMD_RETURN_ERROR); + } + timerclear(&tv); + tv.tv_sec = (time_t)d; + tv.tv_usec = (d - (double)tv.tv_sec) * 1000000U; + evtimer_add(&cdata->timer, &tv); + } else + cmd_run_shell_timer(-1, 0, cdata); if (args_has(args, 'b')) return (CMD_RETURN_NORMAL); return (CMD_RETURN_WAIT); } +static void +cmd_run_shell_timer(__unused int fd, __unused short events, void* arg) +{ + struct cmd_run_shell_data *cdata = arg; + + if (cdata->cmd != NULL) { + if (job_run(cdata->cmd, cdata->s, cdata->cwd, NULL, + cmd_run_shell_callback, cmd_run_shell_free, cdata, + 0) == NULL) + cmd_run_shell_free(cdata); + } else { + if (cdata->item != NULL) + cmdq_continue(cdata->item); + cmd_run_shell_free(cdata); + } +} + static void cmd_run_shell_callback(struct job *job) { @@ -163,6 +202,9 @@ cmd_run_shell_free(void *data) { struct cmd_run_shell_data *cdata = data; + evtimer_del(&cdata->timer); + session_remove_ref(cdata->s, __func__); + free(cdata->cwd); free(cdata->cmd); free(cdata); } diff --git a/server-client.c b/server-client.c index fe72317a..b3f3ad3d 100644 --- a/server-client.c +++ b/server-client.c @@ -417,7 +417,6 @@ server_client_check_mouse(struct client *c, struct key_event *event) struct winlink *wl; struct window_pane *wp; u_int x, y, b, sx, sy, px, py; - int flag; key_code key; struct timeval tv; struct style_range *sr; @@ -441,7 +440,11 @@ server_client_check_mouse(struct client *c, struct key_event *event) m->x, m->y, m->lx, m->ly, c->tty.mouse_drag_flag); /* What type of event is this? */ - if ((m->sgr_type != ' ' && + if (event->key == KEYC_DOUBLECLICK) { + type = DOUBLE; + x = m->x, y = m->y, b = m->b; + log_debug("double-click at %u,%u", x, y); + } else if ((m->sgr_type != ' ' && MOUSE_DRAG(m->sgr_b) && MOUSE_BUTTONS(m->sgr_b) == 3) || (m->sgr_type == ' ' && @@ -475,10 +478,8 @@ server_client_check_mouse(struct client *c, struct key_event *event) evtimer_del(&c->click_timer); c->flags &= ~CLIENT_DOUBLECLICK; if (m->b == c->click_button) { - type = DOUBLE; - x = m->x, y = m->y, b = m->b; - log_debug("double-click at %u,%u", x, y); - flag = CLIENT_TRIPLECLICK; + type = NOTYPE; + c->flags |= CLIENT_TRIPLECLICK; goto add_timer; } } else if (c->flags & CLIENT_TRIPLECLICK) { @@ -495,11 +496,11 @@ server_client_check_mouse(struct client *c, struct key_event *event) type = DOWN; x = m->x, y = m->y, b = m->b; log_debug("down at %u,%u", x, y); - flag = CLIENT_DOUBLECLICK; + c->flags |= CLIENT_DOUBLECLICK; add_timer: if (KEYC_CLICK_TIMEOUT != 0) { - c->flags |= flag; + memcpy(&c->click_event, m, sizeof c->click_event); c->click_button = m->b; tv.tv_sec = KEYC_CLICK_TIMEOUT / 1000; @@ -1045,7 +1046,7 @@ server_client_key_callback(struct cmdq_item *item, void *data) /* Check for mouse keys. */ m->valid = 0; - if (key == KEYC_MOUSE) { + if (key == KEYC_MOUSE || key == KEYC_DOUBLECLICK) { if (c->flags & CLIENT_READONLY) goto out; key = server_client_check_mouse(c, event); @@ -1547,8 +1548,22 @@ server_client_repeat_timer(__unused int fd, __unused short events, void *data) static void server_client_click_timer(__unused int fd, __unused short events, void *data) { - struct client *c = data; + struct client *c = data; + struct key_event *event; + log_debug("click timer expired"); + + if (c->flags & CLIENT_TRIPLECLICK) { + /* + * Waiting for a third click that hasn't happened, so this must + * have been a double click. + */ + event = xmalloc(sizeof *event); + event->key = KEYC_DOUBLECLICK; + memcpy(&event->m, &c->click_event, sizeof event->m); + if (!server_client_handle_key(c, event)) + free(event); + } c->flags &= ~(CLIENT_DOUBLECLICK|CLIENT_TRIPLECLICK); } diff --git a/tmux.1 b/tmux.1 index 8f8ab1bd..a6317714 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1565,7 +1565,7 @@ The synopsis for the command is: .Bl -tag -width Ds .It Xo Ic copy-mode -.Op Fl Meu +.Op Fl eHMu .Op Fl t Ar target-pane .Xc Enter copy mode. @@ -1575,6 +1575,9 @@ option scrolls one page up. .Fl M begins a mouse drag (only valid if bound to a mouse key binding, see .Sx MOUSE SUPPORT ) . +.Fl H +hides the position indicator in the top right. +.Pp .Fl e specifies that scrolling to the bottom of the history (to the visible screen) should exit copy mode. @@ -5200,8 +5203,9 @@ Lock each client individually by running the command specified by the option. .It Xo Ic run-shell .Op Fl b +.Op Fl d Ar delay .Op Fl t Ar target-pane -.Ar shell-command +.Ar [shell-command] .Xc .D1 (alias: Ic run ) Execute @@ -5214,8 +5218,12 @@ section. With .Fl b , the command is run in the background. -After it finishes, any output to stdout is displayed in copy mode (in the pane -specified by +.Fl d +waits for +.Ar delay +seconds before starting the command. +After the command finishes, any output to stdout is displayed in view mode (in +the pane specified by .Fl t or the current pane if omitted). If the command doesn't return success, the exit status is also displayed. diff --git a/tmux.h b/tmux.h index d278ac17..c1de98e0 100644 --- a/tmux.h +++ b/tmux.h @@ -168,6 +168,7 @@ enum { /* Mouse keys. */ KEYC_MOUSE, /* unclassified mouse event */ KEYC_DRAGGING, /* dragging in progress */ + KEYC_DOUBLECLICK, /* double click complete */ KEYC_MOUSE_KEY(MOUSEMOVE), KEYC_MOUSE_KEY(MOUSEDOWN1), KEYC_MOUSE_KEY(MOUSEDOWN2), @@ -1549,6 +1550,7 @@ struct client { struct event click_timer; u_int click_button; + struct mouse_event click_event; struct status_line status; diff --git a/window-copy.c b/window-copy.c index 3e6b3e68..1aa1734f 100644 --- a/window-copy.c +++ b/window-copy.c @@ -230,6 +230,7 @@ struct window_copy_mode_data { } lineflag; /* line selection mode */ int rectflag; /* in rectangle copy mode? */ int scroll_exit; /* exit on scroll to end? */ + int hide_position; /* hide position marker */ enum { SEL_CHAR, /* select one char at a time */ @@ -345,6 +346,7 @@ window_copy_init(struct window_mode_entry *wme, data->cy = data->backing->cy; data->scroll_exit = args_has(args, 'e'); + data->hide_position = args_has(args, 'H'); data->screen.cx = data->cx; data->screen.cy = data->cy; @@ -2774,7 +2776,7 @@ window_copy_write_line(struct window_mode_entry *wme, style_apply(&gc, oo, "mode-style"); gc.flags |= GRID_FLAG_NOPALETTE; - if (py == 0 && s->rupper < s->rlower) { + if (py == 0 && s->rupper < s->rlower && !data->hide_position) { if (data->searchmark == NULL) { size = xsnprintf(hdr, sizeof hdr, "[%u/%u]", data->oy, screen_hsize(data->backing));