diff options
-rw-r--r-- | arguments.c | 6 | ||||
-rw-r--r-- | client.c | 14 | ||||
-rw-r--r-- | cmd-command-prompt.c | 1 | ||||
-rw-r--r-- | cmd-confirm-before.c | 9 | ||||
-rw-r--r-- | cmd-queue.c | 21 | ||||
-rw-r--r-- | cmd-run-shell.c | 18 | ||||
-rw-r--r-- | cmd.c | 2 | ||||
-rw-r--r-- | compat/systemd.c | 11 | ||||
-rw-r--r-- | job.c | 31 | ||||
-rw-r--r-- | layout-custom.c | 2 | ||||
-rw-r--r-- | mode-tree.c | 60 | ||||
-rw-r--r-- | options-table.c | 1 | ||||
-rw-r--r-- | regress/copy-mode-test-emacs.sh | 10 | ||||
-rw-r--r-- | regress/copy-mode-test-vi.sh | 8 | ||||
-rw-r--r-- | server.c | 2 | ||||
-rw-r--r-- | status.c | 40 | ||||
-rw-r--r-- | tmux.1 | 22 | ||||
-rw-r--r-- | tmux.c | 18 | ||||
-rw-r--r-- | tmux.h | 9 | ||||
-rw-r--r-- | tty.c | 5 | ||||
-rw-r--r-- | utf8.c | 2 | ||||
-rw-r--r-- | window-copy.c | 17 |
22 files changed, 211 insertions, 98 deletions
diff --git a/arguments.c b/arguments.c index 669375e2..f96f0471 100644 --- a/arguments.c +++ b/arguments.c @@ -164,10 +164,14 @@ args_parse_flag_argument(struct args_value *values, u_int count, char **cause, argument = &values[*i]; if (argument->type != ARGS_STRING) { xasprintf(cause, "-%c argument must be a string", flag); + args_free_value(new); + free(new); return (-1); } } if (argument == NULL) { + args_free_value(new); + free(new); if (optional_argument) { log_debug("%s: -%c (optional)", __func__, flag); args_set(args, flag, NULL, ARGS_ENTRY_OPTIONAL_VALUE); @@ -662,6 +666,8 @@ args_set(struct args *args, u_char flag, struct args_value *value, int flags) entry->count++; if (value != NULL && value->type != ARGS_NONE) TAILQ_INSERT_TAIL(&entry->values, value, entry); + else + free(value); } /* Get argument value. Will be NULL if it isn't present. */ @@ -497,20 +497,10 @@ client_send_identify(const char *ttynam, const char *termname, char **caps, static __dead void client_exec(const char *shell, const char *shellcmd) { - const char *name, *ptr; - char *argv0; + char *argv0; log_debug("shell %s, command %s", shell, shellcmd); - - ptr = strrchr(shell, '/'); - if (ptr != NULL && *(ptr + 1) != '\0') - name = ptr + 1; - else - name = shell; - if (client_flags & CLIENT_LOGIN) - xasprintf(&argv0, "-%s", name); - else - xasprintf(&argv0, "%s", name); + argv0 = shell_argv0(shell, !!(client_flags & CLIENT_LOGIN)); setenv("SHELL", shell, 1); proc_clear_signals(client_proc, 1); diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c index 6010d0fd..60f7ca37 100644 --- a/cmd-command-prompt.c +++ b/cmd-command-prompt.c @@ -143,6 +143,7 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item) cdata->prompt_type = status_prompt_type(type); if (cdata->prompt_type == PROMPT_TYPE_INVALID) { cmdq_error(item, "unknown type: %s", type); + cmd_command_prompt_free(cdata); return (CMD_RETURN_ERROR); } } else diff --git a/cmd-confirm-before.c b/cmd-confirm-before.c index 485e6e65..fb42d431 100644 --- a/cmd-confirm-before.c +++ b/cmd-confirm-before.c @@ -76,8 +76,10 @@ cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item) cdata = xcalloc(1, sizeof *cdata); cdata->cmdlist = args_make_commands_now(self, item, 0, 1); - if (cdata->cmdlist == NULL) + if (cdata->cmdlist == NULL) { + free(cdata); return (CMD_RETURN_ERROR); + } if (wait) cdata->item = item; @@ -90,6 +92,7 @@ cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item) cdata->confirm_key = confirm_key[0]; else { cmdq_error(item, "invalid confirm key"); + free(cdata); return (CMD_RETURN_ERROR); } } @@ -100,8 +103,8 @@ cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item) xasprintf(&new_prompt, "%s ", prompt); else { cmd = cmd_get_entry(cmd_list_first(cdata->cmdlist))->name; - xasprintf(&new_prompt, "Confirm '%s'? (%c/n) ", - cmd, cdata->confirm_key); + xasprintf(&new_prompt, "Confirm '%s'? (%c/n) ", cmd, + cdata->confirm_key); } status_prompt_set(tc, target, new_prompt, NULL, diff --git a/cmd-queue.c b/cmd-queue.c index e188afcd..85554a4e 100644 --- a/cmd-queue.c +++ b/cmd-queue.c @@ -664,9 +664,18 @@ cmdq_fire_command(struct cmdq_item *item) out: item->client = saved; - if (retval == CMD_RETURN_ERROR) + if (retval == CMD_RETURN_ERROR) { + fsp = NULL; + if (cmd_find_valid_state(&item->target)) + fsp = &item->target; + else if (cmd_find_valid_state(&item->state->current)) + fsp = &item->state->current; + else if (cmd_find_from_client(&fs, item->client, 0) == 0) + fsp = &fs; + cmdq_insert_hook(fsp != NULL ? fsp->s : NULL, item, fsp, + "command-error"); cmdq_guard(item, "error", flags); - else + } else cmdq_guard(item, "end", flags); return (retval); } @@ -805,10 +814,10 @@ cmdq_running(struct client *c) struct cmdq_list *queue = cmdq_get(c); if (queue->item == NULL) - return (NULL); - if (queue->item->flags & CMDQ_WAITING) - return (NULL); - return (queue->item); + return (NULL); + if (queue->item->flags & CMDQ_WAITING) + return (NULL); + return (queue->item); } /* Print a guard line. */ diff --git a/cmd-run-shell.c b/cmd-run-shell.c index ddb5b1b4..9e224c4e 100644 --- a/cmd-run-shell.c +++ b/cmd-run-shell.c @@ -85,12 +85,18 @@ cmd_run_shell_print(struct job *job, const char *msg) if (cdata->wp_id != -1) wp = window_pane_find_by_id(cdata->wp_id); - if (wp == NULL && cdata->item != NULL && cdata->client != NULL) - wp = server_client_get_pane(cdata->client); - if (wp == NULL && cmd_find_from_nothing(&fs, 0) == 0) - wp = fs.wp; - if (wp == NULL) - return; + if (wp == NULL) { + if (cdata->item != NULL) { + cmdq_print(cdata->item, "%s", msg); + return; + } + if (cdata->item != NULL && cdata->client != NULL) + wp = server_client_get_pane(cdata->client); + if (wp == NULL && cmd_find_from_nothing(&fs, 0) == 0) + wp = fs.wp; + if (wp == NULL) + return; + } wme = TAILQ_FIRST(&wp->modes); if (wme == NULL || wme->mode != &window_view_mode) @@ -47,7 +47,6 @@ extern const struct cmd_entry cmd_display_menu_entry; extern const struct cmd_entry cmd_display_message_entry; extern const struct cmd_entry cmd_display_popup_entry; extern const struct cmd_entry cmd_display_panes_entry; -extern const struct cmd_entry cmd_down_pane_entry; extern const struct cmd_entry cmd_find_window_entry; extern const struct cmd_entry cmd_has_session_entry; extern const struct cmd_entry cmd_if_shell_entry; @@ -117,7 +116,6 @@ extern const struct cmd_entry cmd_swap_window_entry; extern const struct cmd_entry cmd_switch_client_entry; extern const struct cmd_entry cmd_unbind_key_entry; extern const struct cmd_entry cmd_unlink_window_entry; -extern const struct cmd_entry cmd_up_pane_entry; extern const struct cmd_entry cmd_wait_for_entry; const struct cmd_entry *cmd_table[] = { diff --git a/compat/systemd.c b/compat/systemd.c index 063474e3..bde372cc 100644 --- a/compat/systemd.c +++ b/compat/systemd.c @@ -145,6 +145,17 @@ systemd_move_pid_to_new_cgroup(pid_t pid, char **cause) } /* + * Make sure that the session shells are terminated with SIGHUP since + * bash and friends tend to ignore SIGTERM. + */ + r = sd_bus_message_append(m, "(sv)", "SendSIGHUP", "b", 1); + if (r < 0) { + xasprintf(cause, "failed to append to properties: %s", + strerror(-r)); + goto finish; + } + + /* * Inherit the slice from the parent process, or default to * "app-tmux.slice" if that fails. */ @@ -77,19 +77,28 @@ job_run(const char *cmd, int argc, char **argv, struct environ *e, struct sessio struct environ *env; pid_t pid; int nullfd, out[2], master; - const char *home; + const char *home, *shell; sigset_t set, oldset; struct winsize ws; - char **argvp, tty[TTY_NAME_MAX]; + char **argvp, tty[TTY_NAME_MAX], *argv0; /* - * Do not set TERM during .tmux.conf, it is nice to be able to use - * if-shell to decide on default-terminal based on outside TERM. + * Do not set TERM during .tmux.conf (second argument here), it is nice + * to be able to use if-shell to decide on default-terminal based on + * outside TERM. */ env = environ_for_session(s, !cfg_finished); if (e != NULL) environ_copy(e, env); + if (s != NULL) + shell = options_get_string(s->options, "default-shell"); + else + shell = options_get_string(global_s_options, "default-shell"); + if (!checkshell(shell)) + shell = _PATH_BSHELL; + argv0 = shell_argv0(shell, 0); + sigfillset(&set); sigprocmask(SIG_BLOCK, &set, &oldset); @@ -105,10 +114,11 @@ job_run(const char *cmd, int argc, char **argv, struct environ *e, struct sessio } if (cmd == NULL) { cmd_log_argv(argc, argv, "%s:", __func__); - log_debug("%s: cwd=%s", __func__, cwd == NULL ? "" : cwd); + log_debug("%s: cwd=%s, shell=%s", __func__, + cwd == NULL ? "" : cwd, shell); } else { - log_debug("%s: cmd=%s, cwd=%s", __func__, cmd, - cwd == NULL ? "" : cwd); + log_debug("%s: cmd=%s, cwd=%s, shell=%s", __func__, cmd, + cwd == NULL ? "" : cwd, shell); } switch (pid) { @@ -150,7 +160,8 @@ job_run(const char *cmd, int argc, char **argv, struct environ *e, struct sessio closefrom(STDERR_FILENO + 1); if (cmd != NULL) { - execl(_PATH_BSHELL, "sh", "-c", cmd, (char *) NULL); + setenv("SHELL", shell, 1); + execl(shell, argv0, "-c", cmd, (char *)NULL); fatal("execl failed"); } else { argvp = cmd_copy_argv(argc, argv); @@ -161,6 +172,7 @@ job_run(const char *cmd, int argc, char **argv, struct environ *e, struct sessio sigprocmask(SIG_SETMASK, &oldset, NULL); environ_free(env); + free(argv0); job = xmalloc(sizeof *job); job->state = JOB_RUNNING; @@ -194,12 +206,13 @@ job_run(const char *cmd, int argc, char **argv, struct environ *e, struct sessio fatalx("out of memory"); bufferevent_enable(job->event, EV_READ|EV_WRITE); - log_debug("run job %p: %s, pid %ld", job, job->cmd, (long) job->pid); + log_debug("run job %p: %s, pid %ld", job, job->cmd, (long)job->pid); return (job); fail: sigprocmask(SIG_SETMASK, &oldset, NULL); environ_free(env); + free(argv0); return (NULL); } diff --git a/layout-custom.c b/layout-custom.c index d7be5b18..2bfb6d89 100644 --- a/layout-custom.c +++ b/layout-custom.c @@ -230,7 +230,7 @@ layout_parse(struct window *w, const char *layout, char **cause) /* Check the new layout. */ if (!layout_check(lc)) { *cause = xstrdup("size mismatch after applying layout"); - return (-1); + goto fail; } /* Resize to the layout size. */ diff --git a/mode-tree.c b/mode-tree.c index cebd4f05..5a4e3bbc 100644 --- a/mode-tree.c +++ b/mode-tree.c @@ -25,6 +25,11 @@ #include "tmux.h" +enum mode_tree_search_dir { + MODE_TREE_SEARCH_FORWARD, + MODE_TREE_SEARCH_BACKWARD +}; + struct mode_tree_item; TAILQ_HEAD(mode_tree_list, mode_tree_item); @@ -68,6 +73,7 @@ struct mode_tree_data { char *search; char *filter; int no_matches; + enum mode_tree_search_dir search_dir; }; struct mode_tree_item { @@ -786,7 +792,49 @@ done: } static struct mode_tree_item * -mode_tree_search_for(struct mode_tree_data *mtd) +mode_tree_search_backward(struct mode_tree_data *mtd) +{ + struct mode_tree_item *mti, *last, *prev; + + if (mtd->search == NULL) + return (NULL); + + mti = last = mtd->line_list[mtd->current].item; + for (;;) { + if ((prev = TAILQ_PREV(mti, mode_tree_list, entry)) != NULL) { + /* Point to the last child in the previous subtree. */ + while (!TAILQ_EMPTY(&prev->children)) + prev = TAILQ_LAST(&prev->children, mode_tree_list); + mti = prev; + } else { + /* If prev is NULL, jump to the parent. */ + mti = mti->parent; + } + + if (mti == NULL) { + /* Point to the last child in the last root subtree. */ + prev = TAILQ_LAST(&mtd->children, mode_tree_list); + while (!TAILQ_EMPTY(&prev->children)) + prev = TAILQ_LAST(&prev->children, mode_tree_list); + mti = prev; + } + if (mti == last) + break; + + if (mtd->searchcb == NULL) { + if (strstr(mti->name, mtd->search) != NULL) + return (mti); + continue; + } + if (mtd->searchcb(mtd->modedata, mti->itemdata, mtd->search)) + return (mti); + } + return (NULL); +} + + +static struct mode_tree_item * +mode_tree_search_forward(struct mode_tree_data *mtd) { struct mode_tree_item *mti, *last, *next; @@ -832,7 +880,10 @@ mode_tree_search_set(struct mode_tree_data *mtd) struct mode_tree_item *mti, *loop; uint64_t tag; - mti = mode_tree_search_for(mtd); + if (mtd->search_dir == MODE_TREE_SEARCH_FORWARD) + mti = mode_tree_search_forward(mtd); + else + mti = mode_tree_search_backward(mtd); if (mti == NULL) return; tag = mti->tag; @@ -1165,6 +1216,11 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key, PROMPT_NOFORMAT, PROMPT_TYPE_SEARCH); break; case 'n': + mtd->search_dir = MODE_TREE_SEARCH_FORWARD; + mode_tree_search_set(mtd); + break; + case 'N': + mtd->search_dir = MODE_TREE_SEARCH_BACKWARD; mode_tree_search_set(mtd); break; case 'f': diff --git a/options-table.c b/options-table.c index 782ce17e..3a9845eb 100644 --- a/options-table.c +++ b/options-table.c @@ -1325,6 +1325,7 @@ const struct options_table_entry options_table[] = { OPTIONS_TABLE_HOOK("client-focus-out", ""), OPTIONS_TABLE_HOOK("client-resized", ""), OPTIONS_TABLE_HOOK("client-session-changed", ""), + OPTIONS_TABLE_HOOK("command-error", ""), OPTIONS_TABLE_PANE_HOOK("pane-died", ""), OPTIONS_TABLE_PANE_HOOK("pane-exited", ""), OPTIONS_TABLE_PANE_HOOK("pane-focus-in", ""), diff --git a/regress/copy-mode-test-emacs.sh b/regress/copy-mode-test-emacs.sh index 63293963..cee0078d 100644 --- a/regress/copy-mode-test-emacs.sh +++ b/regress/copy-mode-test-emacs.sh @@ -42,14 +42,14 @@ $TMUX send-keys -X begin-selection $TMUX send-keys -X next-word-end $TMUX send-keys -X next-word-end $TMUX send-keys -X copy-selection -[ "$($TMUX show-buffer)" = "$(echo -e "words\n Indented")" ] || exit 1 +[ "$($TMUX show-buffer)" = "$(printf "words\n Indented")" ] || exit 1 # Test that `next-word` wraps around un-indented line breaks. $TMUX send-keys -X next-word $TMUX send-keys -X begin-selection $TMUX send-keys -X next-word $TMUX send-keys -X copy-selection -[ "$($TMUX show-buffer)" = "$(echo -e "line\n")" ] || exit 1 +[ "$($TMUX show-buffer)" = "$(printf "line\n")" ] || exit 1 # Test that `next-word-end` treats periods as letters. $TMUX send-keys -X next-word @@ -63,14 +63,14 @@ $TMUX send-keys -X previous-word $TMUX send-keys -X begin-selection $TMUX send-keys -X next-word $TMUX send-keys -X copy-selection -[ "$($TMUX show-buffer)" = "$(echo -e "line...\n")" ] || exit 1 +[ "$($TMUX show-buffer)" = "$(printf "line...\n")" ] || exit 1 # Test that `previous-space` and `next-space` treat periods as letters. $TMUX send-keys -X previous-space $TMUX send-keys -X begin-selection $TMUX send-keys -X next-space $TMUX send-keys -X copy-selection -[ "$($TMUX show-buffer)" = "$(echo -e "line...\n")" ] || exit 1 +[ "$($TMUX show-buffer)" = "$(printf "line...\n")" ] || exit 1 # Test that `next-word` and `next-word-end` treat other symbols as letters. $TMUX send-keys -X begin-selection @@ -87,7 +87,7 @@ $TMUX send-keys -X previous-word $TMUX send-keys -X begin-selection $TMUX send-keys -X next-word $TMUX send-keys -X copy-selection -[ "$($TMUX show-buffer)" = "$(echo -e "\$ym_bols[]{}\n ")" ] || exit 1 +[ "$($TMUX show-buffer)" = "$(printf "\$ym_bols[]{}\n ")" ] || exit 1 # Test that `next-word-end` treats digits as letters $TMUX send-keys -X next-word-end diff --git a/regress/copy-mode-test-vi.sh b/regress/copy-mode-test-vi.sh index 0eca3fa6..8146e456 100644 --- a/regress/copy-mode-test-vi.sh +++ b/regress/copy-mode-test-vi.sh @@ -41,14 +41,14 @@ $TMUX send-keys -X begin-selection $TMUX send-keys -X next-word-end $TMUX send-keys -X next-word-end $TMUX send-keys -X copy-selection -[ "$($TMUX show-buffer)" = "$(echo -e "words\n Indented")" ] || exit 1 +[ "$($TMUX show-buffer)" = "$(printf "words\n Indented")" ] || exit 1 # Test that `next-word` wraps around un-indented line breaks. $TMUX send-keys -X next-word $TMUX send-keys -X begin-selection $TMUX send-keys -X next-word $TMUX send-keys -X copy-selection -[ "$($TMUX show-buffer)" = "$(echo -e "line\nA")" ] || exit 1 +[ "$($TMUX show-buffer)" = "$(printf "line\nA")" ] || exit 1 # Test that `next-word-end` does not treat periods as letters. $TMUX send-keys -X next-word @@ -69,7 +69,7 @@ $TMUX send-keys -X previous-space $TMUX send-keys -X begin-selection $TMUX send-keys -X next-space $TMUX send-keys -X copy-selection -[ "$($TMUX show-buffer)" = "$(echo -e "line...\n.")" ] || exit 1 +[ "$($TMUX show-buffer)" = "$(printf "line...\n.")" ] || exit 1 # Test that `next-word` and `next-word-end` do not treat other symbols as letters. $TMUX send-keys -X begin-selection @@ -85,7 +85,7 @@ $TMUX send-keys -X next-space $TMUX send-keys -X begin-selection $TMUX send-keys -X next-space $TMUX send-keys -X copy-selection -[ "$($TMUX show-buffer)" = "$(echo -e "\$ym_bols[]{}\n ?")" ] || exit 1 +[ "$($TMUX show-buffer)" = "$(printf "\$ym_bols[]{}\n ?")" ] || exit 1 # Test that `next-word-end` treats digits as letters $TMUX send-keys -X next-word-end @@ -264,7 +264,7 @@ server_loop(void) struct client *c; u_int items; - current_time = time (NULL); + current_time = time(NULL); do { items = cmdq_next(NULL); @@ -994,8 +994,7 @@ status_prompt_paste(struct client *c) if ((pb = paste_get_top(NULL)) == NULL) return (0); bufdata = paste_buffer_data(pb, &bufsize); - ud = xreallocarray(NULL, bufsize + 1, sizeof *ud); - udp = ud; + ud = udp = xreallocarray(NULL, bufsize + 1, sizeof *ud); for (i = 0; i != bufsize; /* nothing */) { more = utf8_open(udp, bufdata[i]); if (more == UTF8_MORE) { @@ -1016,25 +1015,24 @@ status_prompt_paste(struct client *c) udp->size = 0; n = udp - ud; } - if (n == 0) - return (0); - - c->prompt_buffer = xreallocarray(c->prompt_buffer, size + n + 1, - sizeof *c->prompt_buffer); - if (c->prompt_index == size) { - memcpy(c->prompt_buffer + c->prompt_index, ud, - n * sizeof *c->prompt_buffer); - c->prompt_index += n; - c->prompt_buffer[c->prompt_index].size = 0; - } else { - memmove(c->prompt_buffer + c->prompt_index + n, - c->prompt_buffer + c->prompt_index, - (size + 1 - c->prompt_index) * sizeof *c->prompt_buffer); - memcpy(c->prompt_buffer + c->prompt_index, ud, - n * sizeof *c->prompt_buffer); - c->prompt_index += n; + if (n != 0) { + c->prompt_buffer = xreallocarray(c->prompt_buffer, size + n + 1, + sizeof *c->prompt_buffer); + if (c->prompt_index == size) { + memcpy(c->prompt_buffer + c->prompt_index, ud, + n * sizeof *c->prompt_buffer); + c->prompt_index += n; + c->prompt_buffer[c->prompt_index].size = 0; + } else { + memmove(c->prompt_buffer + c->prompt_index + n, + c->prompt_buffer + c->prompt_index, + (size + 1 - c->prompt_index) * + sizeof *c->prompt_buffer); + memcpy(c->prompt_buffer + c->prompt_index, ud, + n * sizeof *c->prompt_buffer); + c->prompt_index += n; + } } - if (ud != c->prompt_saved) free(ud); return (1); @@ -1839,6 +1837,7 @@ status_prompt_complete_window_menu(struct client *c, struct session *s, } if (size == 0) { menu_free(menu); + free(spm); return (NULL); } if (size == 1) { @@ -1849,6 +1848,7 @@ status_prompt_complete_window_menu(struct client *c, struct session *s, } else tmp = list[0]; free(list); + free(spm); return (tmp); } if (height > size) @@ -2297,7 +2297,8 @@ The following keys may be used in client mode: .It Li "Up" Ta "Select previous client" .It Li "Down" Ta "Select next client" .It Li "C-s" Ta "Search by name" -.It Li "n" Ta "Repeat last search" +.It Li "n" Ta "Repeat last search forwards" +.It Li "N" Ta "Repeat last search backwards" .It Li "t" Ta "Toggle if client is tagged" .It Li "T" Ta "Tag no clients" .It Li "C-t" Ta "Tag all clients" @@ -2384,7 +2385,8 @@ The following keys may be used in tree mode: .It Li "C-s" Ta "Search by name" .It Li "m" Ta "Set the marked pane" .It Li "M" Ta "Clear the marked pane" -.It Li "n" Ta "Repeat last search" +.It Li "n" Ta "Repeat last search forwards" +.It Li "N" Ta "Repeat last search backwards" .It Li "t" Ta "Toggle if item is tagged" .It Li "T" Ta "Tag no items" .It Li "C-t" Ta "Tag all items" @@ -2462,7 +2464,8 @@ The following keys may be used in customize mode: .It Li "u" Ta "Unset an option (set to default value if global) or unbind a key" .It Li "U" Ta "Unset tagged options and unbind tagged keys" .It Li "C-s" Ta "Search by name" -.It Li "n" Ta "Repeat last search" +.It Li "n" Ta "Repeat last search forwards" +.It Li "N" Ta "Repeat last search backwards" .It Li "t" Ta "Toggle if item is tagged" .It Li "T" Ta "Tag no items" .It Li "C-t" Ta "Tag all items" @@ -4883,6 +4886,14 @@ layout after every set-hook -g after-split-window "selectl even-vertical" .Ed .Pp +If a command fails, the +.Ql command-error +hook will be fired. +For example, this could be used to write to a log file: +.Bd -literal -offset indent +set-hook -g command-error "run-shell \\"echo 'a tmux command failed' >>/tmp/log\\"" +.Ed +.Pp All the notifications listed in the .Sx CONTROL MODE section are hooks (without any arguments), except @@ -4915,6 +4926,8 @@ Run when focus exits a client Run when a client is resized. .It client-session-changed Run when a client's attached session is changed. +.It command-error +Run when a command fails. .It pane-died Run when the program running in a pane exits, but .Ic remain-on-exit @@ -6459,7 +6472,8 @@ The following keys may be used in buffer mode: .It Li "Up" Ta "Select previous buffer" .It Li "Down" Ta "Select next buffer" .It Li "C-s" Ta "Search by name or content" -.It Li "n" Ta "Repeat last search" +.It Li "n" Ta "Repeat last search forwards" +.It Li "N" Ta "Repeat last search backwards" .It Li "t" Ta "Toggle if buffer is tagged" .It Li "T" Ta "Tag no buffers" .It Li "C-t" Ta "Tag all buffers" @@ -235,6 +235,24 @@ fail: return (NULL); } +char * +shell_argv0(const char *shell, int is_login) +{ + const char *slash, *name; + char *argv0; + + slash = strrchr(shell, '/'); + if (slash != NULL && slash[1] != '\0') + name = slash + 1; + else + name = shell; + if (is_login) + xasprintf(&argv0, "-%s", name); + else + xasprintf(&argv0, "%s", name); + return (argv0); +} + void setblocking(int fd, int state) { @@ -2096,6 +2096,7 @@ extern int ptm_fd; extern const char *shell_command; int checkshell(const char *); void setblocking(int, int); +char *shell_argv0(const char *, int); uint64_t get_timer(void); const char *sig2name(int); const char *find_cwd(void); @@ -2390,7 +2391,6 @@ void tty_cmd_clearstartofscreen(struct tty *, const struct tty_ctx *); void tty_cmd_deletecharacter(struct tty *, const struct tty_ctx *); void tty_cmd_clearcharacter(struct tty *, const struct tty_ctx *); void tty_cmd_deleteline(struct tty *, const struct tty_ctx *); -void tty_cmd_erasecharacter(struct tty *, const struct tty_ctx *); void tty_cmd_insertcharacter(struct tty *, const struct tty_ctx *); void tty_cmd_insertline(struct tty *, const struct tty_ctx *); void tty_cmd_linefeed(struct tty *, const struct tty_ctx *); @@ -2567,7 +2567,6 @@ enum cmd_retval cmd_attach_session(struct cmdq_item *, const char *, int, int, int, const char *, int, const char *); /* cmd-parse.c */ -void cmd_parse_empty(struct cmd_parse_input *); struct cmd_parse_result *cmd_parse_from_file(FILE *, struct cmd_parse_input *); struct cmd_parse_result *cmd_parse_from_string(const char *, struct cmd_parse_input *); @@ -2728,8 +2727,6 @@ void server_client_suspend(struct client *); void server_client_detach(struct client *, enum msgtype); void server_client_exec(struct client *, const char *); void server_client_loop(void); -void server_client_push_stdout(struct client *); -void server_client_push_stderr(struct client *); const char *server_client_get_cwd(struct client *, struct session *); void server_client_set_flags(struct client *, const char *); const char *server_client_get_flags(struct client *); @@ -3259,8 +3256,6 @@ void control_add_sub(struct client *, const char *, enum control_sub_type, void control_remove_sub(struct client *, const char *); /* control-notify.c */ -void control_notify_input(struct client *, struct window_pane *, - const u_char *, size_t); void control_notify_pane_mode_changed(int); void control_notify_window_layout_changed(struct window *); void control_notify_window_pane_changed(struct window *); @@ -3294,8 +3289,6 @@ char *session_check_name(const char *); void session_update_activity(struct session *, struct timeval *); struct session *session_next_session(struct session *); struct session *session_previous_session(struct session *); -struct winlink *session_new(struct session *, const char *, int, char **, - const char *, const char *, int, char **); struct winlink *session_attach(struct session *, struct window *, int, char **); int session_detach(struct session *, struct winlink *); @@ -28,6 +28,7 @@ #include <stdlib.h> #include <string.h> #include <termios.h> +#include <time.h> #include <unistd.h> #include "tmux.h" @@ -379,13 +380,13 @@ tty_send_requests(struct tty *tty) tty_puts(tty, "\033]11;?\033\\"); } else tty->flags |= TTY_ALL_REQUEST_FLAGS; - tty->last_requests = time (NULL); + tty->last_requests = time(NULL); } void tty_repeat_requests(struct tty *tty) { - time_t t = time (NULL); + time_t t = time(NULL); if (~tty->flags & TTY_STARTED) return; @@ -525,7 +525,7 @@ utf8_strvis(char *dst, const char *src, size_t len, int flag) /* Not a complete, valid UTF-8 character. */ src -= ud.have; } - if (src[0] == '$' && src < end - 1) { + if ((flag & VIS_DQ) && src[0] == '$' && src < end - 1) { if (isalpha((u_char)src[1]) || src[1] == '_' || src[1] == '{') diff --git a/window-copy.c b/window-copy.c index 27d9782a..de124812 100644 --- a/window-copy.c +++ b/window-copy.c @@ -3614,11 +3614,10 @@ window_copy_search_jump(struct window_mode_entry *wme, struct grid *gd, struct grid *sgd, u_int fx, u_int fy, u_int endline, int cis, int wrap, int direction, int regex) { - u_int i, px, sx, ssize = 1; - int found = 0, cflags = REG_EXTENDED; - char *sbuf; - regex_t reg; - struct grid_line *gl; + u_int i, px, sx, ssize = 1; + int found = 0, cflags = REG_EXTENDED; + char *sbuf; + regex_t reg; if (regex) { sbuf = xmalloc(ssize); @@ -3635,9 +3634,6 @@ window_copy_search_jump(struct window_mode_entry *wme, struct grid *gd, if (direction) { for (i = fy; i <= endline; i++) { - gl = grid_get_line(gd, i); - if (i != endline && gl->flags & GRID_LINE_WRAPPED) - continue; if (regex) { found = window_copy_search_lr_regex(gd, &px, &sx, i, fx, gd->sx, ®); @@ -3651,9 +3647,6 @@ window_copy_search_jump(struct window_mode_entry *wme, struct grid *gd, } } else { for (i = fy + 1; endline < i; i--) { - gl = grid_get_line(gd, i - 1); - if (i != endline && gl->flags & GRID_LINE_WRAPPED) - continue; if (regex) { found = window_copy_search_rl_regex(gd, &px, &sx, i - 1, 0, fx + 1, ®); @@ -4694,7 +4687,7 @@ window_copy_get_selection(struct window_mode_entry *wme, size_t *len) if (keys == MODEKEY_EMACS || lastex <= ey_last) { if (~grid_get_line(data->backing->grid, ey)->flags & GRID_LINE_WRAPPED || lastex != ey_last) - off -= 1; + off -= 1; } *len = off; return (buf); |