diff --git a/Makefile.am b/Makefile.am index 982a88d8..696ccb2b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -77,7 +77,6 @@ dist_tmux_SOURCES = \ cmd-command-prompt.c \ cmd-confirm-before.c \ cmd-copy-mode.c \ - cmd-delete-buffer.c \ cmd-detach-client.c \ cmd-display-message.c \ cmd-display-panes.c \ diff --git a/cmd-copy-mode.c b/cmd-copy-mode.c index d729ada6..e04b561b 100644 --- a/cmd-copy-mode.c +++ b/cmd-copy-mode.c @@ -28,8 +28,8 @@ enum cmd_retval cmd_copy_mode_exec(struct cmd *, struct cmd_q *); const struct cmd_entry cmd_copy_mode_entry = { "copy-mode", NULL, - "Mt:u", 0, 0, - "[-Mu] " CMD_TARGET_PANE_USAGE, + "Met:u", 0, 0, + "[-Meu] " CMD_TARGET_PANE_USAGE, 0, cmd_copy_mode_exec }; @@ -66,7 +66,7 @@ cmd_copy_mode_exec(struct cmd *self, struct cmd_q *cmdq) if (wp->mode != &window_copy_mode) { if (window_pane_set_mode(wp, &window_copy_mode) != 0) return (CMD_RETURN_NORMAL); - window_copy_init_from_pane(wp); + window_copy_init_from_pane(wp, args_has(self->args, 'e')); } if (args_has(args, 'M')) { if (wp->mode != NULL && wp->mode != &window_copy_mode) diff --git a/cmd-delete-buffer.c b/cmd-delete-buffer.c deleted file mode 100644 index 42268b78..00000000 --- a/cmd-delete-buffer.c +++ /dev/null @@ -1,57 +0,0 @@ -/* $OpenBSD$ */ - -/* - * Copyright (c) 2007 Nicholas Marriott - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER - * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include - -#include - -#include "tmux.h" - -/* - * Delete a paste buffer. - */ - -enum cmd_retval cmd_delete_buffer_exec(struct cmd *, struct cmd_q *); - -const struct cmd_entry cmd_delete_buffer_entry = { - "delete-buffer", "deleteb", - "b:", 0, 0, - CMD_BUFFER_USAGE, - 0, - cmd_delete_buffer_exec -}; - -enum cmd_retval -cmd_delete_buffer_exec(struct cmd *self, struct cmd_q *cmdq) -{ - struct args *args = self->args; - const char *bufname; - - if (!args_has(args, 'b')) { - paste_free_top(); - return (CMD_RETURN_NORMAL); - } - bufname = args_get(args, 'b'); - - if (paste_free_name(bufname) != 0) { - cmdq_error(cmdq, "no buffer %s", bufname); - return (CMD_RETURN_ERROR); - } - - return (CMD_RETURN_NORMAL); -} diff --git a/cmd-paste-buffer.c b/cmd-paste-buffer.c index 5027a4f8..1c83ee7b 100644 --- a/cmd-paste-buffer.c +++ b/cmd-paste-buffer.c @@ -101,12 +101,8 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmd_q *cmdq) bufferevent_write(wp->event, "\033[201~", 6); } - if (args_has(args, 'd')) { - if (bufname == NULL) - paste_free_top(); - else - paste_free_name(bufname); - } + if (pb != NULL && args_has(args, 'd')) + paste_free(pb); return (CMD_RETURN_NORMAL); } diff --git a/cmd-refresh-client.c b/cmd-refresh-client.c index b6d5d624..5a45ec25 100644 --- a/cmd-refresh-client.c +++ b/cmd-refresh-client.c @@ -65,10 +65,13 @@ cmd_refresh_client_exec(struct cmd *self, struct cmd_q *cmdq) } if (tty_set_size(&c->tty, w, h)) recalculate_sizes(); - } else if (args_has(args, 'S')) + } else if (args_has(args, 'S')) { + c->flags |= CLIENT_STATUSFORCE; server_status_client(c); - else + } else { + c->flags |= CLIENT_STATUSFORCE; server_redraw_client(c); + } return (CMD_RETURN_NORMAL); } diff --git a/cmd-set-buffer.c b/cmd-set-buffer.c index 4fa7ca11..01afa774 100644 --- a/cmd-set-buffer.c +++ b/cmd-set-buffer.c @@ -24,7 +24,7 @@ #include "tmux.h" /* - * Add, set, or append to a paste buffer. + * Add, set, append to or delete a paste buffer. */ enum cmd_retval cmd_set_buffer_exec(struct cmd *, struct cmd_q *); @@ -37,6 +37,14 @@ const struct cmd_entry cmd_set_buffer_entry = { cmd_set_buffer_exec }; +const struct cmd_entry cmd_delete_buffer_entry = { + "delete-buffer", "deleteb", + "b:", 0, 0, + CMD_BUFFER_USAGE, + 0, + cmd_set_buffer_exec +}; + enum cmd_retval cmd_set_buffer_exec(struct cmd *self, struct cmd_q *cmdq) { @@ -46,31 +54,31 @@ cmd_set_buffer_exec(struct cmd *self, struct cmd_q *cmdq) const char *bufname, *olddata; size_t bufsize, newsize; - bufname = NULL; + bufname = args_get(args, 'b'); + if (bufname == NULL) + pb = paste_get_top(&bufname); + else + pb = paste_get_name(bufname); - if (args_has(args, 'n')) { - if (args->argc > 0) { - cmdq_error(cmdq, "don't provide data with n flag"); + if (self->entry == &cmd_delete_buffer_entry) { + if (pb == NULL) { + cmdq_error(cmdq, "no buffer"); return (CMD_RETURN_ERROR); } + paste_free(pb); + return (CMD_RETURN_NORMAL); + } - if (args_has(args, 'b')) - bufname = args_get(args, 'b'); - - if (bufname == NULL) { - pb = paste_get_top(&bufname); - if (pb == NULL) { - cmdq_error(cmdq, "no buffer"); - return (CMD_RETURN_ERROR); - } + if (args_has(args, 'n')) { + if (pb == NULL) { + cmdq_error(cmdq, "no buffer"); + return (CMD_RETURN_ERROR); } - if (paste_rename(bufname, args_get(args, 'n'), &cause) != 0) { cmdq_error(cmdq, "%s", cause); free(cause); return (CMD_RETURN_ERROR); } - return (CMD_RETURN_NORMAL); } @@ -78,19 +86,11 @@ cmd_set_buffer_exec(struct cmd *self, struct cmd_q *cmdq) cmdq_error(cmdq, "no data specified"); return (CMD_RETURN_ERROR); } - pb = NULL; - - bufsize = 0; - bufdata = NULL; - if ((newsize = strlen(args->argv[0])) == 0) return (CMD_RETURN_NORMAL); - if (args_has(args, 'b')) { - bufname = args_get(args, 'b'); - pb = paste_get_name(bufname); - } else if (args_has(args, 'a')) - pb = paste_get_top(&bufname); + bufsize = 0; + bufdata = NULL; if (args_has(args, 'a') && pb != NULL) { olddata = paste_buffer_data(pb, &bufsize); diff --git a/cmd-wait-for.c b/cmd-wait-for.c index 0dce438b..e38ea8f1 100644 --- a/cmd-wait-for.c +++ b/cmd-wait-for.c @@ -97,7 +97,6 @@ cmd_wait_for_add(const char *name) void cmd_wait_for_remove(struct wait_channel *wc) { - if (wc->locked) return; if (!TAILQ_EMPTY(&wc->waiters) || !wc->woken) @@ -241,7 +240,8 @@ cmd_wait_for_flush(void) if (!cmdq_free(wq)) cmdq_continue(wq); } - while ((wq = TAILQ_FIRST(&wc->lockers)) != NULL) { + wc->woken = 1; + TAILQ_FOREACH_SAFE(wq, &wc->lockers, waitentry, wq1) { TAILQ_REMOVE(&wc->lockers, wq, waitentry); if (!cmdq_free(wq)) cmdq_continue(wq); diff --git a/format.c b/format.c index 69d93baf..acfcb531 100644 --- a/format.c +++ b/format.c @@ -106,7 +106,7 @@ struct format_tree { struct session *s; struct window_pane *wp; - int status; + int flags; RB_HEAD(format_entry_tree, format_entry) tree; }; @@ -218,27 +218,31 @@ const char * format_job_get(struct format_tree *ft, const char *cmd) { struct format_job fj0, *fj; + time_t t; fj0.cmd = cmd; if ((fj = RB_FIND(format_job_tree, &format_jobs, &fj0)) == NULL) { fj = xcalloc(1, sizeof *fj); fj->cmd = xstrdup(cmd); - fj->status = ft->status; xasprintf(&fj->out, "<'%s' not ready>", fj->cmd); RB_INSERT(format_job_tree, &format_jobs, fj); } - if (fj->job == NULL && fj->last != time(NULL)) { + t = time(NULL); + if (fj->job == NULL && ((ft->flags & FORMAT_FORCE) || fj->last != t)) { fj->job = job_run(fj->cmd, NULL, -1, format_job_callback, NULL, fj); if (fj->job == NULL) { free(fj->out); xasprintf(&fj->out, "<'%s' didn't start>", fj->cmd); } + fj->last = t; } - fj->last = time(NULL); + + if (ft->flags & FORMAT_STATUS) + fj->status = 1; return (fj->out); } @@ -455,12 +459,12 @@ format_cb_pane_tabs(struct format_tree *ft, struct format_entry *fe) struct format_tree * format_create(void) { - return (format_create_status(0)); + return (format_create_flags(0)); } /* Create a new tree for the status line. */ struct format_tree * -format_create_status(int status) +format_create_flags(int flags) { struct format_tree *ft; @@ -471,7 +475,7 @@ format_create_status(int status) ft = xcalloc(1, sizeof *ft); RB_INIT(&ft->tree); - ft->status = status; + ft->flags = flags; format_add_cb(ft, "host", format_cb_host); format_add_cb(ft, "host_short", format_cb_host_short); diff --git a/paste.c b/paste.c index 11357731..d4f8e99e 100644 --- a/paste.c +++ b/paste.c @@ -110,18 +110,6 @@ paste_get_top(const char **name) return (pb); } -/* Free the most recent buffer. */ -int -paste_free_top(void) -{ - struct paste_buffer *pb; - - pb = paste_get_top(NULL); - if (pb == NULL) - return (-1); - return (paste_free_name(pb->name)); -} - /* Get a paste buffer by name. */ struct paste_buffer * paste_get_name(const char *name) @@ -135,20 +123,10 @@ paste_get_name(const char *name) return (RB_FIND(paste_name_tree, &paste_by_name, &pbfind)); } -/* Free a paste buffer by name. */ -int -paste_free_name(const char *name) +/* Free a paste buffer. */ +void +paste_free(struct paste_buffer *pb) { - struct paste_buffer *pb, pbfind; - - if (name == NULL || *name == '\0') - return (-1); - - pbfind.name = (char *)name; - pb = RB_FIND(paste_name_tree, &paste_by_name, &pbfind); - if (pb == NULL) - return (-1); - RB_REMOVE(paste_name_tree, &paste_by_name, pb); RB_REMOVE(paste_time_tree, &paste_by_time, pb); if (pb->automatic) @@ -157,7 +135,6 @@ paste_free_name(const char *name) free(pb->data); free(pb->name); free(pb); - return (0); } /* @@ -178,7 +155,7 @@ paste_add(char *data, size_t size) if (paste_num_automatic < limit) break; if (pb->automatic) - paste_free_name(pb->name); + paste_free(pb); } pb = xmalloc(sizeof *pb); @@ -256,7 +233,7 @@ paste_rename(const char *oldname, const char *newname, char **cause) int paste_set(char *data, size_t size, const char *name, char **cause) { - struct paste_buffer *pb; + struct paste_buffer *pb, *old; if (cause != NULL) *cause = NULL; @@ -287,8 +264,8 @@ paste_set(char *data, size_t size, const char *name, char **cause) pb->automatic = 0; pb->order = paste_next_order++; - if (paste_get_name(name) != NULL) - paste_free_name(name); + if ((old = paste_get_name(name)) != NULL) + paste_free(old); RB_INSERT(paste_name_tree, &paste_by_name, pb); RB_INSERT(paste_time_tree, &paste_by_time, pb); diff --git a/server-client.c b/server-client.c index c63c11d1..bc006e6a 100644 --- a/server-client.c +++ b/server-client.c @@ -946,7 +946,8 @@ server_client_check_redraw(struct client *c) tty->flags = (tty->flags & ~(TTY_FREEZE|TTY_NOCURSOR)) | flags; tty_update_mode(tty, tty->mode, NULL); - c->flags &= ~(CLIENT_REDRAW|CLIENT_STATUS|CLIENT_BORDERS); + c->flags &= ~(CLIENT_REDRAW|CLIENT_BORDERS|CLIENT_STATUS| + CLIENT_STATUSFORCE); } /* Set client title. */ diff --git a/status.c b/status.c index 29cb686c..7a1d2818 100644 --- a/status.c +++ b/status.c @@ -503,7 +503,10 @@ status_replace(struct client *c, struct winlink *wl, const char *fmt, time_t t) if (fmt == NULL) return (xstrdup("")); - ft = format_create_status(1); + if (c->flags & CLIENT_STATUSFORCE) + ft = format_create_flags(FORMAT_STATUS|FORMAT_FORCE); + else + ft = format_create_flags(FORMAT_STATUS); format_defaults(ft, c, NULL, wl, NULL); expanded = format_expand_time(ft, fmt, t); diff --git a/tmux.1 b/tmux.1 index 2e4edb2f..43c20103 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1137,7 +1137,7 @@ The synopsis for the command is: .Bl -tag -width Ds .It Xo Ic copy-mode -.Op Fl Mu +.Op Fl Meu .Op Fl t Ar target-pane .Xc Enter copy mode. @@ -1147,6 +1147,16 @@ 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 e +specifies that scrolling to the bottom of the history (to the visible screen) +should exit copy mode. +While in copy mode, pressing a key other than those used for scrolling will +disable this behaviour. +This is intended to allow fast scrolling through a pane's history, for +example with: +.Bd -literal -offset indent +bind PageUp copy-mode -eu +.Ed .El .Pp Each window displayed by diff --git a/tmux.h b/tmux.h index 61027b98..6606451f 100644 --- a/tmux.h +++ b/tmux.h @@ -1221,6 +1221,7 @@ struct client { #define CLIENT_UTF8 0x10000 #define CLIENT_256COLOURS 0x20000 #define CLIENT_IDENTIFIED 0x40000 +#define CLIENT_STATUSFORCE 0x80000 int flags; struct key_table *keytable; @@ -1436,17 +1437,18 @@ const char *paste_buffer_data(struct paste_buffer *, size_t *); struct paste_buffer *paste_walk(struct paste_buffer *); struct paste_buffer *paste_get_top(const char **); struct paste_buffer *paste_get_name(const char *); -int paste_free_top(void); -int paste_free_name(const char *); +void paste_free(struct paste_buffer *); void paste_add(char *, size_t); int paste_rename(const char *, const char *, char **); int paste_set(char *, size_t, const char *, char **); char *paste_make_sample(struct paste_buffer *, int); /* format.c */ +#define FORMAT_STATUS 0x1 +#define FORMAT_FORCE 0x2 struct format_tree; struct format_tree *format_create(void); -struct format_tree *format_create_status(int); +struct format_tree *format_create_flags(int); void format_free(struct format_tree *); void printflike(3, 4) format_add(struct format_tree *, const char *, const char *, ...); @@ -2070,7 +2072,7 @@ extern const char window_clock_table[14][5][5]; /* window-copy.c */ extern const struct window_mode window_copy_mode; -void window_copy_init_from_pane(struct window_pane *); +void window_copy_init_from_pane(struct window_pane *, u_int); void window_copy_init_for_output(struct window_pane *); void printflike(2, 3) window_copy_add(struct window_pane *, const char *, ...); void window_copy_vadd(struct window_pane *, const char *, va_list); diff --git a/window-copy.c b/window-copy.c index 460dd10b..d18c0424 100644 --- a/window-copy.c +++ b/window-copy.c @@ -135,7 +135,8 @@ struct window_copy_mode_data { u_int selx; u_int sely; - u_int rectflag; /* are we in rectangle copy mode? */ + int rectflag; /* in rectangle copy mode? */ + int scroll_exit; /* exit on scroll to end? */ u_int cx; u_int cy; @@ -175,6 +176,7 @@ window_copy_init(struct window_pane *wp) data->backing_written = 0; data->rectflag = 0; + data->scroll_exit = 0; data->inputtype = WINDOW_COPY_OFF; data->inputprompt = NULL; @@ -206,7 +208,7 @@ window_copy_init(struct window_pane *wp) } void -window_copy_init_from_pane(struct window_pane *wp) +window_copy_init_from_pane(struct window_pane *wp, u_int scroll_exit) { struct window_copy_mode_data *data = wp->modedata; struct screen *s = &data->screen; @@ -219,6 +221,7 @@ window_copy_init_from_pane(struct window_pane *wp) data->backing = &wp->base; data->cx = data->backing->cx; data->cy = data->backing->cy; + data->scroll_exit = scroll_exit; s->cx = data->cx; s->cy = data->cy; @@ -419,6 +422,13 @@ window_copy_key(struct window_pane *wp, struct client *c, struct session *sess, } cmd = mode_key_lookup(&data->mdata, key, &arg); + if (cmd != MODEKEYCOPY_PREVIOUSPAGE && + cmd != MODEKEYCOPY_NEXTPAGE && + cmd != MODEKEYCOPY_SCROLLUP && + cmd != MODEKEYCOPY_SCROLLDOWN && + cmd != MODEKEYCOPY_HALFPAGEUP && + cmd != MODEKEYCOPY_HALFPAGEDOWN) + data->scroll_exit = 0; switch (cmd) { case MODEKEYCOPY_APPENDSELECTION: if (sess != NULL) { @@ -461,6 +471,10 @@ window_copy_key(struct window_pane *wp, struct client *c, struct session *sess, case MODEKEYCOPY_SCROLLDOWN: for (; np != 0; np--) window_copy_cursor_down(wp, 1); + if (data->scroll_exit && data->oy == 0) { + window_pane_reset_mode(wp); + return; + } break; case MODEKEYCOPY_PREVIOUSPAGE: for (; np != 0; np--) @@ -476,6 +490,10 @@ window_copy_key(struct window_pane *wp, struct client *c, struct session *sess, else data->oy -= n; } + if (data->scroll_exit && data->oy == 0) { + window_pane_reset_mode(wp); + return; + } window_copy_update_selection(wp, 1); window_copy_redraw_screen(wp); break; @@ -498,6 +516,10 @@ window_copy_key(struct window_pane *wp, struct client *c, struct session *sess, else data->oy -= n; } + if (data->scroll_exit && data->oy == 0) { + window_pane_reset_mode(wp); + return; + } window_copy_update_selection(wp, 1); window_copy_redraw_screen(wp); break;