summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arguments.c6
-rw-r--r--client.c14
-rw-r--r--cmd-command-prompt.c1
-rw-r--r--cmd-confirm-before.c9
-rw-r--r--cmd-queue.c21
-rw-r--r--cmd-run-shell.c18
-rw-r--r--cmd.c2
-rw-r--r--compat/systemd.c11
-rw-r--r--job.c31
-rw-r--r--layout-custom.c2
-rw-r--r--mode-tree.c60
-rw-r--r--options-table.c1
-rw-r--r--regress/copy-mode-test-emacs.sh10
-rw-r--r--regress/copy-mode-test-vi.sh8
-rw-r--r--server.c2
-rw-r--r--status.c40
-rw-r--r--tmux.122
-rw-r--r--tmux.c18
-rw-r--r--tmux.h9
-rw-r--r--tty.c5
-rw-r--r--utf8.c2
-rw-r--r--window-copy.c17
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. */
diff --git a/client.c b/client.c
index 9cd5ad85..4bec9f1d 100644
--- a/client.c
+++ b/client.c
@@ -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)
diff --git a/cmd.c b/cmd.c
index 32c00b4e..92fd15b6 100644
--- a/cmd.c
+++ b/cmd.c
@@ -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.
*/
diff --git a/job.c b/job.c
index d2d9adbf..cab91d2c 100644
--- a/job.c
+++ b/job.c
@@ -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
diff --git a/server.c b/server.c
index 6fef468b..96a638cb 100644
--- a/server.c
+++ b/server.c
@@ -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);
diff --git a/status.c b/status.c
index a11cc8b8..4afac626 100644
--- a/status.c
+++ b/status.c
@@ -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)
diff --git a/tmux.1 b/tmux.1
index b73efdd6..b31b1a2f 100644
--- a/tmux.1
+++ b/tmux.1
@@ -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"
diff --git a/tmux.c b/tmux.c
index a01ed423..a9619baf 100644
--- a/tmux.c
+++ b/tmux.c
@@ -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)
{
diff --git a/tmux.h b/tmux.h
index a052b799..965b7443 100644
--- a/tmux.h
+++ b/tmux.h
@@ -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 *);
diff --git a/tty.c b/tty.c
index 359dc137..f6d5618e 100644
--- a/tty.c
+++ b/tty.c
@@ -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;
diff --git a/utf8.c b/utf8.c
index 5053e459..1b3acd53 100644
--- a/utf8.c
+++ b/utf8.c
@@ -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, &reg);
@@ -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, &reg);
@@ -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);