diff --git a/cmd-parse.y b/cmd-parse.y index 4cd8a420..215943b1 100644 --- a/cmd-parse.y +++ b/cmd-parse.y @@ -758,7 +758,7 @@ static int cmd_parse_expand_alias(struct cmd_parse_command *cmd, struct cmd_parse_input *pi, struct cmd_parse_result *pr) { - struct cmd_parse_argument *arg, *arg1, *first; + struct cmd_parse_argument *first; struct cmd_parse_commands *cmds; struct cmd_parse_command *last; char *alias, *name, *cause; @@ -798,10 +798,7 @@ cmd_parse_expand_alias(struct cmd_parse_command *cmd, TAILQ_REMOVE(&cmd->arguments, first, entry); cmd_parse_free_argument(first); - TAILQ_FOREACH_SAFE(arg, &cmd->arguments, entry, arg1) { - TAILQ_REMOVE(&cmd->arguments, arg, entry); - TAILQ_INSERT_TAIL(&last->arguments, arg, entry); - } + TAILQ_CONCAT(&last->arguments, &cmd->arguments, entry); cmd_parse_log_commands(cmds, __func__); pi->flags |= CMD_PARSE_NOALIAS; diff --git a/key-bindings.c b/key-bindings.c index a5e1f9c8..22e5cf59 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -480,9 +480,9 @@ key_bindings_init(void) "bind -n M-MouseDown3Pane { display-menu -t= -xM -yM -T '#[align=centre]#{pane_index} (#{pane_id})' " DEFAULT_PANE_MENU " }", /* Mouse on scrollbar. */ - "bind -n MouseDown1ScrollbarUp { copy-mode -u }", - "bind -n MouseDown1ScrollbarDown { copy-mode -d }", - "bind -n MouseDrag1ScrollbarSlider { copy-mode -S }", + "bind -n MouseDown1ScrollbarUp { if -Ft= '#{pane_in_mode}' { send -X page-up } {copy-mode -u } }", + "bind -n MouseDown1ScrollbarDown { if -Ft= '#{pane_in_mode}' { send -X page-down } {copy-mode -d } }", + "bind -n MouseDrag1ScrollbarSlider { if -Ft= '#{pane_in_mode}' { send -X scroll-to-mouse } { copy-mode -S } }", /* Copy mode (emacs) keys. */ "bind -Tcopy-mode C-Space { send -X begin-selection }", diff --git a/screen-redraw.c b/screen-redraw.c index 1c1b8503..fd58c480 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -197,9 +197,11 @@ screen_redraw_pane_border(struct screen_redraw_ctx *ctx, struct window_pane *wp, } else { /* sb_pos == PANE_SCROLLBARS_RIGHT */ if ((wp->xoff == 0 || px >= wp->xoff) && (px <= ex || (sb_w != 0 && px < ex + sb_w))) { - if (wp->yoff != 0 && py == wp->yoff - 1) + if (pane_status != PANE_STATUS_BOTTOM && + wp->yoff != 0 && + py == wp->yoff - 1) return (SCREEN_REDRAW_BORDER_TOP); - if (py == ey) + if (pane_status != PANE_STATUS_TOP && py == ey) return (SCREEN_REDRAW_BORDER_BOTTOM); } } @@ -380,7 +382,6 @@ screen_redraw_check_cell(struct screen_redraw_ctx *ctx, u_int px, u_int py, /* Check if CELL_SCROLLBAR */ if (window_pane_show_scrollbar(wp, pane_scrollbars)) { - if (pane_status == PANE_STATUS_TOP) line = wp->yoff - 1; else diff --git a/spawn.c b/spawn.c index 90cda757..964d0334 100644 --- a/spawn.c +++ b/spawn.c @@ -211,7 +211,9 @@ spawn_pane(struct spawn_context *sc, char **cause) struct environ *child; struct environ_entry *ee; char **argv, *cp, **argvp, *argv0, *cwd, *new_cwd; - const char *cmd, *tmp; + char path[PATH_MAX]; + const char *cmd, *tmp, *home = find_home(); + const char *actual_cwd = NULL; int argc; u_int idx; struct termios now; @@ -366,6 +368,16 @@ spawn_pane(struct spawn_context *sc, char **cause) goto complete; } + /* Store current working directory and change to new one. */ + if (getcwd(path, sizeof path) != NULL) { + if (chdir(new_wp->cwd) == 0) + actual_cwd = new_wp->cwd; + else if (home != NULL && chdir(home) == 0) + actual_cwd = home; + else if (chdir("/") == 0) + actual_cwd = "/"; + } + /* Fork the new process. */ new_wp->pid = fdforkpty(ptm_fd, &new_wp->fd, new_wp->tty, NULL, &ws); if (new_wp->pid == -1) { @@ -381,8 +393,15 @@ spawn_pane(struct spawn_context *sc, char **cause) return (NULL); } - /* In the parent process, everything is done now. */ + /* + * In the parent process, everything is done now. Change the working + * directory back. + */ if (new_wp->pid != 0) { + if (actual_cwd != NULL && + chdir(path) != 0 && + (home == NULL || chdir(home) != 0)) + chdir("/"); goto complete; } @@ -397,17 +416,10 @@ spawn_pane(struct spawn_context *sc, char **cause) } #endif /* - * Child process. Change to the working directory or home if that - * fails. + * Child process. Set PWD to the working directory. */ - if (chdir(new_wp->cwd) == 0) - environ_set(child, "PWD", 0, "%s", new_wp->cwd); - else if ((tmp = find_home()) != NULL && chdir(tmp) == 0) - environ_set(child, "PWD", 0, "%s", tmp); - else if (chdir("/") == 0) - environ_set(child, "PWD", 0, "/"); - else - fatal("chdir failed"); + if (actual_cwd != NULL) + environ_set(child, "PWD", 0, "%s", actual_cwd); /* * Update terminal escape characters from the session if available and diff --git a/tmux.1 b/tmux.1 index 404909bd..29948db2 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2213,6 +2213,13 @@ but also exit copy mode if the cursor reaches the bottom. Scroll so that the current line becomes the middle one while keeping the cursor on that line. .It Xo +.Ic scroll-to-mouse +.Xc +Scroll pane in copy-mode when bound to a mouse drag event. +.Fl e +causes copy mode to exit when at the bottom. +.Pp +.It Xo .Ic scroll-top .Xc Scroll down until the current line is at the top while keeping the cursor on @@ -2449,12 +2456,10 @@ cancels copy mode and any other modes. .Fl M begins a mouse drag (only valid if bound to a mouse key binding, see .Sx MOUSE SUPPORT ) . +.Pp .Fl S -scrolls when bound to a mouse drag event; for example, -.Ic copy-mode -Se -is bound to -.Ar MouseDrag1ScrollbarSlider -by default. +enters copy-mode and scrolls when bound to a mouse drag event; See +.Ic scroll-to-mouse . .Pp .Fl s copies from diff --git a/tty-keys.c b/tty-keys.c index 7474621c..c59e6a68 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -909,9 +909,15 @@ first_key: * used. termios should have a better idea. */ bspace = tty->tio.c_cc[VERASE]; - if (bspace != _POSIX_VDISABLE && key == bspace) { - log_debug("%s: key %#llx is backspace", c->name, key); - key = KEYC_BSPACE; + if (bspace != _POSIX_VDISABLE) { + if (key == bspace) { + log_debug("%s: key %#llx is BSpace", c->name, key); + key = KEYC_BSPACE; + } + if (key == (bspace|KEYC_META)) { + log_debug("%s: key %#llx is M-BSpace", c->name, key); + key = KEYC_BSPACE|KEYC_META; + } } /* @@ -1304,7 +1310,7 @@ tty_keys_clipboard(struct tty *tty, const char *buf, size_t len, size_t *size) struct client *c = tty->client; size_t end, terminator = 0, needed; char *copy, *out; - int outlen; + int outlen; struct input_request_clipboard_data cd; *size = 0; diff --git a/window-copy.c b/window-copy.c index 2d528496..f8700555 100644 --- a/window-copy.c +++ b/window-copy.c @@ -1479,6 +1479,20 @@ window_copy_cmd_scroll_middle(struct window_copy_cmd_state *cs) return (window_copy_cmd_scroll_to(cs, mid_value)); } +/* Scroll the pane to the mouse in the scrollbar. */ +static enum window_copy_cmd_action +window_copy_cmd_scroll_to_mouse(struct window_copy_cmd_state *cs) +{ + struct window_mode_entry *wme = cs->wme; + struct window_pane *wp = wme->wp; + struct client *c = cs->c; + struct mouse_event *m = cs->m; + int scroll_exit = args_has(cs->wargs, 'e'); + + window_copy_scroll(wp, c->tty.mouse_slider_mpos, m->y, scroll_exit); + return (WINDOW_COPY_CMD_NOTHING); +} + /* Scroll line containing the cursor to the top. */ static enum window_copy_cmd_action window_copy_cmd_scroll_top(struct window_copy_cmd_state *cs) @@ -3044,6 +3058,11 @@ static const struct { .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS, .f = window_copy_cmd_scroll_middle }, + { .command = "scroll-to-mouse", + .args = { "e", 0, 0, NULL }, + .clear = WINDOW_COPY_CMD_CLEAR_EMACS_ONLY, + .f = window_copy_cmd_scroll_to_mouse + }, { .command = "scroll-top", .args = { "", 0, 0, NULL }, .clear = WINDOW_COPY_CMD_CLEAR_ALWAYS,