Merge branch 'sixel-passthrough' into sixel

pull/3363/head
Nicholas Marriott 2020-01-30 09:11:01 +00:00
commit 3a741aacd1
26 changed files with 621 additions and 280 deletions

27
CHANGES
View File

@ -1,5 +1,32 @@
CHANGES FROM 3.0 to X.X CHANGES FROM 3.0 to X.X
* Add support for adding a note to a key binding (with bind-key -N) and use
this to add descriptions to the default key bindings. A new -N flag to
list-keys shows key bindings with notes. Change the default ? binding to use
this to show a readable summary of keys. Also extend command-prompt to return
the name of the key pressed and add a default binding (/) to show the note
for the next key pressed.
* Add support for the iTerm2 DSR 1337 sequence to get the terminal version.
* Treat plausible but invalid keys (like C-BSpace) as literal like any other
unrecognised string passed to send-keys
* Detect iTerm2 and enable use of DECSLRM (much faster with horizontally split
windows).
* Add -Z to default switch-client command in tree mode.
* Add ~ to quoted characters for %%%.
* Document client exit messages in the manual page.
* Do not let read-only clients limit the size, unless all clients are
read-only.
* Add a number of new formats to inspect what sessions and clients a window is
present or active in.
* Change file reading and writing to go through the client if necessary. This * Change file reading and writing to go through the client if necessary. This
fixes commands like "tmux loadb /dev/fd/X". Also modify source-file to fixes commands like "tmux loadb /dev/fd/X". Also modify source-file to
support "-" for standard input, like load-buffer and save-buffer. support "-" for standard input, like load-buffer and save-buffer.

View File

@ -11,8 +11,9 @@ EXTRA_DIST = \
dist_EXTRA_tmux_SOURCES = compat/*.[ch] dist_EXTRA_tmux_SOURCES = compat/*.[ch]
# Preprocessor flags. # Preprocessor flags.
AM_CPPFLAGS += @XOPEN_DEFINES@ AM_CPPFLAGS += @XOPEN_DEFINES@ \
AM_CPPFLAGS += -DTMUX_CONF="\"$(sysconfdir)/tmux.conf:~/.tmux.conf:~/.config/tmux/tmux.conf\"" -DTMUX_VERSION="\"@VERSION@\"" \
-DTMUX_CONF="\"$(sysconfdir)/tmux.conf:~/.tmux.conf:~/.config/tmux/tmux.conf\""
# Additional object files. # Additional object files.
LDADD = $(LIBOBJS) LDADD = $(LIBOBJS)

View File

@ -865,6 +865,12 @@ client_dispatch_wait(struct imsg *imsg)
case MSG_WRITE_CLOSE: case MSG_WRITE_CLOSE:
client_write_close(data, datalen); client_write_close(data, datalen);
break; break;
case MSG_OLDSTDERR:
case MSG_OLDSTDIN:
case MSG_OLDSTDOUT:
fprintf(stderr, "server version is too old for client\n");
proc_exit(client_proc);
break;
} }
} }

View File

@ -33,8 +33,8 @@ const struct cmd_entry cmd_bind_key_entry = {
.name = "bind-key", .name = "bind-key",
.alias = "bind", .alias = "bind",
.args = { "cnrT:", 2, -1 }, .args = { "cnrN:T:", 2, -1 },
.usage = "[-cnr] [-T key-table] key " .usage = "[-cnr] [-T key-table] [-N note] key "
"command [arguments]", "command [arguments]",
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
@ -46,10 +46,10 @@ cmd_bind_key_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = self->args; struct args *args = self->args;
key_code key; key_code key;
const char *tablename; const char *tablename, *note;
struct cmd_parse_result *pr; struct cmd_parse_result *pr;
char **argv = args->argv; char **argv = args->argv;
int argc = args->argc; int argc = args->argc, repeat;
key = key_string_lookup_string(argv[0]); key = key_string_lookup_string(argv[0]);
if (key == KEYC_NONE || key == KEYC_UNKNOWN) { if (key == KEYC_NONE || key == KEYC_UNKNOWN) {
@ -63,6 +63,7 @@ cmd_bind_key_exec(struct cmd *self, struct cmdq_item *item)
tablename = "root"; tablename = "root";
else else
tablename = "prefix"; tablename = "prefix";
repeat = args_has(args, 'r');
if (argc == 2) if (argc == 2)
pr = cmd_parse_from_string(argv[1], NULL); pr = cmd_parse_from_string(argv[1], NULL);
@ -79,6 +80,7 @@ cmd_bind_key_exec(struct cmd *self, struct cmdq_item *item)
case CMD_PARSE_SUCCESS: case CMD_PARSE_SUCCESS:
break; break;
} }
key_bindings_add(tablename, key, args_has(args, 'r'), pr->cmdlist); note = args_get(args, 'N');
key_bindings_add(tablename, key, note, repeat, pr->cmdlist);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@ -40,8 +40,8 @@ const struct cmd_entry cmd_command_prompt_entry = {
.name = "command-prompt", .name = "command-prompt",
.alias = NULL, .alias = NULL,
.args = { "1iI:Np:t:", 0, 1 }, .args = { "1kiI:Np:t:", 0, 1 },
.usage = "[-1Ni] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE " " .usage = "[-1kiN] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE " "
"[template]", "[template]",
.flags = 0, .flags = 0,
@ -122,6 +122,8 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
cdata->flags |= PROMPT_NUMERIC; cdata->flags |= PROMPT_NUMERIC;
else if (args_has(args, 'i')) else if (args_has(args, 'i'))
cdata->flags |= PROMPT_INCREMENTAL; cdata->flags |= PROMPT_INCREMENTAL;
else if (args_has(args, 'k'))
cdata->flags |= PROMPT_KEY;
status_prompt_set(c, prompt, input, cmd_command_prompt_callback, status_prompt_set(c, prompt, input, cmd_command_prompt_callback,
cmd_command_prompt_free, cdata, cdata->flags); cmd_command_prompt_free, cdata, cdata->flags);
free(prompt); free(prompt);

View File

@ -36,8 +36,8 @@ const struct cmd_entry cmd_list_keys_entry = {
.name = "list-keys", .name = "list-keys",
.alias = "lsk", .alias = "lsk",
.args = { "T:", 0, 0 }, .args = { "1NP:T:", 0, 1 },
.usage = "[-T key-table]", .usage = "[-1N] [-P prefix-string] [-T key-table] [key]",
.flags = CMD_STARTSERVER|CMD_AFTERHOOK, .flags = CMD_STARTSERVER|CMD_AFTERHOOK,
.exec = cmd_list_keys_exec .exec = cmd_list_keys_exec
@ -54,6 +54,88 @@ const struct cmd_entry cmd_list_commands_entry = {
.exec = cmd_list_keys_exec .exec = cmd_list_keys_exec
}; };
static u_int
cmd_list_keys_get_width(const char *tablename, key_code only)
{
struct key_table *table;
struct key_binding *bd;
u_int width, keywidth = 0;
table = key_bindings_get_table(tablename, 0);
if (table == NULL)
return (0);
bd = key_bindings_first(table);
while (bd != NULL) {
if ((only != KEYC_UNKNOWN && bd->key != only) ||
KEYC_IS_MOUSE(bd->key) ||
bd->note == NULL) {
bd = key_bindings_next(table, bd);
continue;
}
width = utf8_cstrwidth(key_string_lookup_key(bd->key));
if (width > keywidth)
keywidth = width;
bd = key_bindings_next(table, bd);
}
return (keywidth);
}
static int
cmd_list_keys_print_notes(struct cmdq_item *item, struct args *args,
const char *tablename, u_int keywidth, key_code only, const char *prefix)
{
struct client *c = cmd_find_client(item, NULL, 1);
struct key_table *table;
struct key_binding *bd;
const char *key;
char *tmp;
int found = 0;
table = key_bindings_get_table(tablename, 0);
if (table == NULL)
return (0);
bd = key_bindings_first(table);
while (bd != NULL) {
if ((only != KEYC_UNKNOWN && bd->key != only) ||
KEYC_IS_MOUSE(bd->key) ||
bd->note == NULL) {
bd = key_bindings_next(table, bd);
continue;
}
found = 1;
key = key_string_lookup_key(bd->key);
tmp = utf8_padcstr(key, keywidth + 1);
if (args_has(args, '1') && c != NULL)
status_message_set(c, "%s%s%s", prefix, tmp, bd->note);
else
cmdq_print(item, "%s%s%s", prefix, tmp, bd->note);
free(tmp);
if (args_has(args, '1'))
break;
bd = key_bindings_next(table, bd);
}
return (found);
}
static char *
cmd_list_keys_get_prefix(struct args *args, key_code *prefix)
{
char *s;
*prefix = options_get_number(global_s_options, "prefix");
if (!args_has(args, 'P')) {
if (*prefix != KEYC_NONE)
xasprintf(&s, "%s ", key_string_lookup_key(*prefix));
else
s = xstrdup("");
} else
s = xstrdup(args_get(args, 'P'));
return (s);
}
static enum cmd_retval static enum cmd_retval
cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item) cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
{ {
@ -61,19 +143,63 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
struct key_table *table; struct key_table *table;
struct key_binding *bd; struct key_binding *bd;
const char *tablename, *r; const char *tablename, *r;
char *key, *cp, *tmp; char *key, *cp, *tmp, *start, *empty;
int repeat, width, tablewidth, keywidth; key_code prefix, only = KEYC_UNKNOWN;
int repeat, width, tablewidth, keywidth, found = 0;
size_t tmpsize, tmpused, cplen; size_t tmpsize, tmpused, cplen;
if (self->entry == &cmd_list_commands_entry) if (self->entry == &cmd_list_commands_entry)
return (cmd_list_keys_commands(self, item)); return (cmd_list_keys_commands(self, item));
if (args->argc != 0) {
only = key_string_lookup_string(args->argv[0]);
if (only == KEYC_UNKNOWN) {
cmdq_error(item, "invalid key: %s", args->argv[0]);
return (CMD_RETURN_ERROR);
}
}
tablename = args_get(args, 'T'); tablename = args_get(args, 'T');
if (tablename != NULL && key_bindings_get_table(tablename, 0) == NULL) { if (tablename != NULL && key_bindings_get_table(tablename, 0) == NULL) {
cmdq_error(item, "table %s doesn't exist", tablename); cmdq_error(item, "table %s doesn't exist", tablename);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (args_has(args, 'N')) {
if (tablename == NULL) {
start = cmd_list_keys_get_prefix(args, &prefix);
keywidth = cmd_list_keys_get_width("root", only);
if (prefix != KEYC_NONE) {
width = cmd_list_keys_get_width("prefix", only);
if (width == 0)
prefix = KEYC_NONE;
else if (width > keywidth)
keywidth = width;
}
empty = utf8_padcstr("", utf8_cstrwidth(start));
found = cmd_list_keys_print_notes(item, args, "root",
keywidth, only, empty);
if (prefix != KEYC_NONE) {
if (cmd_list_keys_print_notes(item, args,
"prefix", keywidth, only, start))
found = 1;
}
free(empty);
} else {
if (args_has(args, 'P'))
start = xstrdup(args_get(args, 'P'));
else
start = xstrdup("");
keywidth = cmd_list_keys_get_width(tablename, only);
found = cmd_list_keys_print_notes(item, args, tablename,
keywidth, only, start);
}
free(start);
goto out;
}
repeat = 0; repeat = 0;
tablewidth = keywidth = 0; tablewidth = keywidth = 0;
table = key_bindings_first_table (); table = key_bindings_first_table ();
@ -84,6 +210,10 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
} }
bd = key_bindings_first(table); bd = key_bindings_first(table);
while (bd != NULL) { while (bd != NULL) {
if (only != KEYC_UNKNOWN && bd->key != only) {
bd = key_bindings_next(table, bd);
continue;
}
key = args_escape(key_string_lookup_key(bd->key)); key = args_escape(key_string_lookup_key(bd->key));
if (bd->flags & KEY_BINDING_REPEAT) if (bd->flags & KEY_BINDING_REPEAT)
@ -113,6 +243,11 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
} }
bd = key_bindings_first(table); bd = key_bindings_first(table);
while (bd != NULL) { while (bd != NULL) {
if (only != KEYC_UNKNOWN && bd->key != only) {
bd = key_bindings_next(table, bd);
continue;
}
found = 1;
key = args_escape(key_string_lookup_key(bd->key)); key = args_escape(key_string_lookup_key(bd->key));
if (!repeat) if (!repeat)
@ -162,6 +297,11 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
free(tmp); free(tmp);
out:
if (only != KEYC_UNKNOWN && !found) {
cmdq_error(item, "unknown key: %s", args->argv[0]);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@ -133,7 +133,12 @@ statements : statement '\n'
free($2); free($2);
} }
statement : condition statement : /* empty */
{
$$ = xmalloc (sizeof *$$);
TAILQ_INIT($$);
}
| condition
{ {
struct cmd_parse_state *ps = &parse_state; struct cmd_parse_state *ps = &parse_state;
@ -144,11 +149,6 @@ statement : condition
cmd_parse_free_commands($1); cmd_parse_free_commands($1);
} }
} }
| assignment
{
$$ = xmalloc (sizeof *$$);
TAILQ_INIT($$);
}
| commands | commands
{ {
struct cmd_parse_state *ps = &parse_state; struct cmd_parse_state *ps = &parse_state;
@ -194,8 +194,10 @@ expanded : format
free($1); free($1);
} }
assignment : /* empty */ optional_assignment : /* empty */
| EQUALS | assignment
assignment : EQUALS
{ {
struct cmd_parse_state *ps = &parse_state; struct cmd_parse_state *ps = &parse_state;
int flags = ps->input->flags; int flags = ps->input->flags;
@ -339,7 +341,8 @@ commands : command
struct cmd_parse_state *ps = &parse_state; struct cmd_parse_state *ps = &parse_state;
$$ = cmd_parse_new_commands(); $$ = cmd_parse_new_commands();
if (ps->scope == NULL || ps->scope->flag) if ($1->name != NULL &&
(ps->scope == NULL || ps->scope->flag))
TAILQ_INSERT_TAIL($$, $1, entry); TAILQ_INSERT_TAIL($$, $1, entry);
else else
cmd_parse_free_command($1); cmd_parse_free_command($1);
@ -358,7 +361,8 @@ commands : command
{ {
struct cmd_parse_state *ps = &parse_state; struct cmd_parse_state *ps = &parse_state;
if (ps->scope == NULL || ps->scope->flag) { if ($3->name != NULL &&
(ps->scope == NULL || ps->scope->flag)) {
$$ = $1; $$ = $1;
TAILQ_INSERT_TAIL($$, $3, entry); TAILQ_INSERT_TAIL($$, $3, entry);
} else { } else {
@ -372,7 +376,15 @@ commands : command
$$ = $1; $$ = $1;
} }
command : assignment TOKEN command : assignment
{
struct cmd_parse_state *ps = &parse_state;
$$ = xcalloc(1, sizeof *$$);
$$->name = NULL;
$$->line = ps->input->line;
}
| optional_assignment TOKEN
{ {
struct cmd_parse_state *ps = &parse_state; struct cmd_parse_state *ps = &parse_state;
@ -381,7 +393,7 @@ command : assignment TOKEN
$$->line = ps->input->line; $$->line = ps->input->line;
} }
| assignment TOKEN arguments | optional_assignment TOKEN arguments
{ {
struct cmd_parse_state *ps = &parse_state; struct cmd_parse_state *ps = &parse_state;

View File

@ -60,6 +60,9 @@ static struct cmdq_item *
cmd_send_keys_inject_key(struct client *c, struct cmd_find_state *fs, cmd_send_keys_inject_key(struct client *c, struct cmd_find_state *fs,
struct cmdq_item *item, key_code key) struct cmdq_item *item, key_code key)
{ {
struct session *s = fs->s;
struct winlink *wl = fs->wl;
struct window_pane *wp = fs->wp;
struct window_mode_entry *wme; struct window_mode_entry *wme;
struct key_table *table; struct key_table *table;
struct key_binding *bd; struct key_binding *bd;
@ -68,7 +71,8 @@ cmd_send_keys_inject_key(struct client *c, struct cmd_find_state *fs,
if (wme == NULL || wme->mode->key_table == NULL) { if (wme == NULL || wme->mode->key_table == NULL) {
if (options_get_number(fs->wp->window->options, "xterm-keys")) if (options_get_number(fs->wp->window->options, "xterm-keys"))
key |= KEYC_XTERM; key |= KEYC_XTERM;
window_pane_key(fs->wp, item->client, fs->s, fs->wl, key, NULL); if (window_pane_key(wp, item->client, s, wl, key, NULL) != 0)
return (NULL);
return (item); return (item);
} }
table = key_bindings_get_table(wme->mode->key_table(wme), 1); table = key_bindings_get_table(wme->mode->key_table(wme), 1);
@ -87,6 +91,7 @@ cmd_send_keys_inject_string(struct client *c, struct cmd_find_state *fs,
struct cmdq_item *item, struct args *args, int i) struct cmdq_item *item, struct args *args, int i)
{ {
const char *s = args->argv[i]; const char *s = args->argv[i];
struct cmdq_item *new_item;
struct utf8_data *ud, *uc; struct utf8_data *ud, *uc;
wchar_t wc; wchar_t wc;
key_code key; key_code key;
@ -104,8 +109,11 @@ cmd_send_keys_inject_string(struct client *c, struct cmd_find_state *fs,
literal = args_has(args, 'l'); literal = args_has(args, 'l');
if (!literal) { if (!literal) {
key = key_string_lookup_string(s); key = key_string_lookup_string(s);
if (key != KEYC_NONE && key != KEYC_UNKNOWN) if (key != KEYC_NONE && key != KEYC_UNKNOWN) {
return (cmd_send_keys_inject_key(c, fs, item, key)); new_item = cmd_send_keys_inject_key(c, fs, item, key);
if (new_item != NULL)
return (new_item);
}
literal = 1; literal = 1;
} }
if (literal) { if (literal) {

View File

@ -171,8 +171,12 @@ void warnx(const char *, ...);
#endif #endif
#ifndef FNM_CASEFOLD #ifndef FNM_CASEFOLD
#ifdef FNM_IGNORECASE
#define FNM_CASEFOLD FNM_IGNORECASE
#else
#define FNM_CASEFOLD 0 #define FNM_CASEFOLD 0
#endif #endif
#endif
#ifndef INFTIM #ifndef INFTIM
#define INFTIM -1 #define INFTIM -1

View File

@ -1121,7 +1121,7 @@ format_create(struct client *c, struct cmdq_item *item, int tag, int flags)
ft->flags = flags; ft->flags = flags;
ft->time = time(NULL); ft->time = time(NULL);
format_add(ft, "version", "%s", VERSION); format_add(ft, "version", "%s", getversion());
format_add_cb(ft, "host", format_cb_host); format_add_cb(ft, "host", format_cb_host);
format_add_cb(ft, "host_short", format_cb_host_short); format_add_cb(ft, "host_short", format_cb_host_short);
format_add_cb(ft, "pid", format_cb_pid); format_add_cb(ft, "pid", format_cb_pid);
@ -2362,7 +2362,6 @@ format_defaults_client(struct format_tree *ft, struct client *c)
struct session *s; struct session *s;
const char *name; const char *name;
struct tty *tty = &c->tty; struct tty *tty = &c->tty;
const char *types[] = TTY_TYPES;
if (ft->s == NULL) if (ft->s == NULL)
ft->s = c->session; ft->s = c->session;
@ -2380,8 +2379,6 @@ format_defaults_client(struct format_tree *ft, struct client *c)
if (tty->term_name != NULL) if (tty->term_name != NULL)
format_add(ft, "client_termname", "%s", tty->term_name); format_add(ft, "client_termname", "%s", tty->term_name);
if (tty->term_name != NULL)
format_add(ft, "client_termtype", "%s", types[tty->term_type]);
format_add_tv(ft, "client_created", &c->creation_time); format_add_tv(ft, "client_created", &c->creation_time);
format_add_tv(ft, "client_activity", &c->activity_time); format_add_tv(ft, "client_activity", &c->activity_time);

View File

@ -149,7 +149,7 @@ input_split2(u_int c, u_char *dst)
} }
/* Translate a key code into an output key sequence. */ /* Translate a key code into an output key sequence. */
void int
input_key(struct window_pane *wp, key_code key, struct mouse_event *m) input_key(struct window_pane *wp, key_code key, struct mouse_event *m)
{ {
const struct input_key_ent *ike; const struct input_key_ent *ike;
@ -166,14 +166,14 @@ input_key(struct window_pane *wp, key_code key, struct mouse_event *m)
if (KEYC_IS_MOUSE(key)) { if (KEYC_IS_MOUSE(key)) {
if (m != NULL && m->wp != -1 && (u_int)m->wp == wp->id) if (m != NULL && m->wp != -1 && (u_int)m->wp == wp->id)
input_key_mouse(wp, m); input_key_mouse(wp, m);
return; return (0);
} }
/* Literal keys go as themselves (can't be more than eight bits). */ /* Literal keys go as themselves (can't be more than eight bits). */
if (key & KEYC_LITERAL) { if (key & KEYC_LITERAL) {
ud.data[0] = (u_char)key; ud.data[0] = (u_char)key;
bufferevent_write(wp->event, &ud.data[0], 1); bufferevent_write(wp->event, &ud.data[0], 1);
return; return (0);
} }
/* Is this backspace? */ /* Is this backspace? */
@ -194,15 +194,15 @@ input_key(struct window_pane *wp, key_code key, struct mouse_event *m)
bufferevent_write(wp->event, "\033", 1); bufferevent_write(wp->event, "\033", 1);
ud.data[0] = justkey; ud.data[0] = justkey;
bufferevent_write(wp->event, &ud.data[0], 1); bufferevent_write(wp->event, &ud.data[0], 1);
return; return (0);
} }
if (justkey > 0x7f && justkey < KEYC_BASE) { if (justkey > 0x7f && justkey < KEYC_BASE) {
if (utf8_split(justkey, &ud) != UTF8_DONE) if (utf8_split(justkey, &ud) != UTF8_DONE)
return; return (-1);
if (key & KEYC_ESCAPE) if (key & KEYC_ESCAPE)
bufferevent_write(wp->event, "\033", 1); bufferevent_write(wp->event, "\033", 1);
bufferevent_write(wp->event, ud.data, ud.size); bufferevent_write(wp->event, ud.data, ud.size);
return; return (0);
} }
/* /*
@ -213,7 +213,7 @@ input_key(struct window_pane *wp, key_code key, struct mouse_event *m)
if ((out = xterm_keys_lookup(key)) != NULL) { if ((out = xterm_keys_lookup(key)) != NULL) {
bufferevent_write(wp->event, out, strlen(out)); bufferevent_write(wp->event, out, strlen(out));
free(out); free(out);
return; return (0);
} }
} }
key &= ~KEYC_XTERM; key &= ~KEYC_XTERM;
@ -236,7 +236,7 @@ input_key(struct window_pane *wp, key_code key, struct mouse_event *m)
} }
if (i == nitems(input_keys)) { if (i == nitems(input_keys)) {
log_debug("key 0x%llx missing", key); log_debug("key 0x%llx missing", key);
return; return (-1);
} }
dlen = strlen(ike->data); dlen = strlen(ike->data);
log_debug("found key 0x%llx: \"%s\"", key, ike->data); log_debug("found key 0x%llx: \"%s\"", key, ike->data);
@ -245,6 +245,7 @@ input_key(struct window_pane *wp, key_code key, struct mouse_event *m)
if (key & KEYC_ESCAPE) if (key & KEYC_ESCAPE)
bufferevent_write(wp->event, "\033", 1); bufferevent_write(wp->event, "\033", 1);
bufferevent_write(wp->event, ike->data, dlen); bufferevent_write(wp->event, ike->data, dlen);
return (0);
} }
/* Translate mouse and output. */ /* Translate mouse and output. */

12
input.c
View File

@ -20,6 +20,7 @@
#include <netinet/in.h> #include <netinet/in.h>
#include <ctype.h>
#include <resolv.h> #include <resolv.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -772,6 +773,7 @@ input_save_state(struct input_ctx *ictx)
ictx->old_mode = s->mode; ictx->old_mode = s->mode;
} }
/* Restore screen state. */
static void static void
input_restore_state(struct input_ctx *ictx) input_restore_state(struct input_ctx *ictx)
{ {
@ -1301,6 +1303,7 @@ input_csi_dispatch(struct input_ctx *ictx)
struct input_table_entry *entry; struct input_table_entry *entry;
int i, n, m; int i, n, m;
u_int cx, bg = ictx->cell.cell.bg; u_int cx, bg = ictx->cell.cell.bg;
char *copy, *cp;
if (ictx->flags & INPUT_DISCARD) if (ictx->flags & INPUT_DISCARD)
return (0); return (0);
@ -1432,6 +1435,13 @@ input_csi_dispatch(struct input_ctx *ictx)
case 6: case 6:
input_reply(ictx, "\033[%u;%uR", s->cy + 1, s->cx + 1); input_reply(ictx, "\033[%u;%uR", s->cy + 1, s->cx + 1);
break; break;
case 1337: /* Terminal version, from iTerm2. */
copy = xstrdup(getversion());
for (cp = copy; *cp != '\0'; cp++)
*cp = toupper((u_char)*cp);
input_reply(ictx, "\033[TMUX %sn", copy);
free(copy);
break;
default: default:
log_debug("%s: unknown '%c'", __func__, ictx->ch); log_debug("%s: unknown '%c'", __func__, ictx->ch);
break; break;
@ -2151,8 +2161,6 @@ static int
input_dcs_dispatch(struct input_ctx *ictx) input_dcs_dispatch(struct input_ctx *ictx)
{ {
struct screen_write_ctx *sctx = &ictx->ctx; struct screen_write_ctx *sctx = &ictx->ctx;
struct window_pane *wp = ictx->wp;
struct window *w = wp->window;
u_char *buf = ictx->input_buf; u_char *buf = ictx->input_buf;
size_t len = ictx->input_len; size_t len = ictx->input_len;
const char prefix[] = "tmux;"; const char prefix[] = "tmux;";

View File

@ -90,6 +90,7 @@ key_bindings_free(struct key_table *table, struct key_binding *bd)
{ {
RB_REMOVE(key_bindings, &table->key_bindings, bd); RB_REMOVE(key_bindings, &table->key_bindings, bd);
cmd_list_free(bd->cmdlist); cmd_list_free(bd->cmdlist);
free((void *)bd->note);
free(bd); free(bd);
} }
@ -163,7 +164,7 @@ key_bindings_next(__unused struct key_table *table, struct key_binding *bd)
} }
void void
key_bindings_add(const char *name, key_code key, int repeat, key_bindings_add(const char *name, key_code key, const char *note, int repeat,
struct cmd_list *cmdlist) struct cmd_list *cmdlist)
{ {
struct key_table *table; struct key_table *table;
@ -177,6 +178,8 @@ key_bindings_add(const char *name, key_code key, int repeat,
bd = xcalloc(1, sizeof *bd); bd = xcalloc(1, sizeof *bd);
bd->key = key; bd->key = key;
if (note != NULL)
bd->note = xstrdup(note);
RB_INSERT(key_bindings, &table->key_bindings, bd); RB_INSERT(key_bindings, &table->key_bindings, bd);
if (repeat) if (repeat)
@ -226,87 +229,88 @@ void
key_bindings_init(void) key_bindings_init(void)
{ {
static const char *defaults[] = { static const char *defaults[] = {
"bind C-b send-prefix", "bind -N 'Send the prefix key' C-b send-prefix",
"bind C-o rotate-window", "bind -N 'Rotate through the panes' C-o rotate-window",
"bind C-z suspend-client", "bind -N 'Suspend the current client' C-z suspend-client",
"bind Space next-layout", "bind -N 'Select next layout' Space next-layout",
"bind ! break-pane", "bind -N 'Break pane to a new window' ! break-pane",
"bind '\"' split-window", "bind -N 'Split window vertically' '\"' split-window",
"bind '#' list-buffers", "bind -N 'List all paste buffers' '#' list-buffers",
"bind '$' command-prompt -I'#S' \"rename-session -- '%%'\"", "bind -N 'Rename current session' '$' command-prompt -I'#S' \"rename-session -- '%%'\"",
"bind % split-window -h", "bind -N 'Split window horizontally' % split-window -h",
"bind & confirm-before -p\"kill-window #W? (y/n)\" kill-window", "bind -N 'Kill current window' & confirm-before -p\"kill-window #W? (y/n)\" kill-window",
"bind \"'\" command-prompt -pindex \"select-window -t ':%%'\"", "bind -N 'Prompt for window index to select' \"'\" command-prompt -pindex \"select-window -t ':%%'\"",
"bind ( switch-client -p", "bind -N 'Switch to previous client' ( switch-client -p",
"bind ) switch-client -n", "bind -N 'Switch to next client' ) switch-client -n",
"bind , command-prompt -I'#W' \"rename-window -- '%%'\"", "bind -N 'Rename current window' , command-prompt -I'#W' \"rename-window -- '%%'\"",
"bind - delete-buffer", "bind -N 'Delete the most recent paste buffer' - delete-buffer",
"bind . command-prompt \"move-window -t '%%'\"", "bind -N 'Move the current window' . command-prompt \"move-window -t '%%'\"",
"bind 0 select-window -t:=0", "bind -N 'Describe key binding' '/' command-prompt -kpkey 'list-keys -1N \"%%%\"'",
"bind 1 select-window -t:=1", "bind -N 'Select window 0' 0 select-window -t:=0",
"bind 2 select-window -t:=2", "bind -N 'Select window 1' 1 select-window -t:=1",
"bind 3 select-window -t:=3", "bind -N 'Select window 2' 2 select-window -t:=2",
"bind 4 select-window -t:=4", "bind -N 'Select window 3' 3 select-window -t:=3",
"bind 5 select-window -t:=5", "bind -N 'Select window 4' 4 select-window -t:=4",
"bind 6 select-window -t:=6", "bind -N 'Select window 5' 5 select-window -t:=5",
"bind 7 select-window -t:=7", "bind -N 'Select window 6' 6 select-window -t:=6",
"bind 8 select-window -t:=8", "bind -N 'Select window 7' 7 select-window -t:=7",
"bind 9 select-window -t:=9", "bind -N 'Select window 8' 8 select-window -t:=8",
"bind : command-prompt", "bind -N 'Select window 9' 9 select-window -t:=9",
"bind \\; last-pane", "bind -N 'Prompt for a command' : command-prompt",
"bind = choose-buffer -Z", "bind -N 'Move to the previously active pane' \\; last-pane",
"bind ? list-keys", "bind -N 'Choose a paste buffer from a list' = choose-buffer -Z",
"bind D choose-client -Z", "bind -N 'List key bindings' ? list-keys -N",
"bind E select-layout -E", "bind -N 'Choose a client from a list' D choose-client -Z",
"bind L switch-client -l", "bind -N 'Spread panes out evenly' E select-layout -E",
"bind M select-pane -M", "bind -N 'Switch to the last client' L switch-client -l",
"bind [ copy-mode", "bind -N 'Clear the marked pane' M select-pane -M",
"bind ] paste-buffer", "bind -N 'Enter copy mode' [ copy-mode",
"bind c new-window", "bind -N 'Paste the most recent paste buffer' ] paste-buffer",
"bind d detach-client", "bind -N 'Create a new window' c new-window",
"bind f command-prompt \"find-window -Z -- '%%'\"", "bind -N 'Detach the current client' d detach-client",
"bind i display-message", "bind -N 'Search for a pane' f command-prompt \"find-window -Z -- '%%'\"",
"bind l last-window", "bind -N 'Display window information' i display-message",
"bind m select-pane -m", "bind -N 'Select the previously current window' l last-window",
"bind n next-window", "bind -N 'Toggle the marked pane' m select-pane -m",
"bind o select-pane -t:.+", "bind -N 'Select the next window' n next-window",
"bind p previous-window", "bind -N 'Select the next pane' o select-pane -t:.+",
"bind q display-panes", "bind -N 'Select the previous pane' p previous-window",
"bind r refresh-client", "bind -N 'Display pane numbers' q display-panes",
"bind s choose-tree -Zs", "bind -N 'Redraw the current client' r refresh-client",
"bind t clock-mode", "bind -N 'Choose a session from a list' s choose-tree -Zs",
"bind w choose-tree -Zw", "bind -N 'Show a clock' t clock-mode",
"bind x confirm-before -p\"kill-pane #P? (y/n)\" kill-pane", "bind -N 'Choose a window from a list' w choose-tree -Zw",
"bind z resize-pane -Z", "bind -N 'Kill the active pane' x confirm-before -p\"kill-pane #P? (y/n)\" kill-pane",
"bind '{' swap-pane -U", "bind -N 'Zoom the active pane' z resize-pane -Z",
"bind '}' swap-pane -D", "bind -N 'Swap the active pane with the pane above' '{' swap-pane -U",
"bind '~' show-messages", "bind -N 'Swap the active pane with the pane below' '}' swap-pane -D",
"bind PPage copy-mode -u", "bind -N 'Show messages' '~' show-messages",
"bind -r Up select-pane -U", "bind -N 'Enter copy mode and scroll up' PPage copy-mode -u",
"bind -r Down select-pane -D", "bind -N 'Select the pane above the active pane' -r Up select-pane -U",
"bind -r Left select-pane -L", "bind -N 'Select the pane below the active pane' -r Down select-pane -D",
"bind -r Right select-pane -R", "bind -N 'Select the pane to the left of the active pane' -r Left select-pane -L",
"bind M-1 select-layout even-horizontal", "bind -N 'Select the pane to the right of the active pane' -r Right select-pane -R",
"bind M-2 select-layout even-vertical", "bind -N 'Set the even-horizontal layout' M-1 select-layout even-horizontal",
"bind M-3 select-layout main-horizontal", "bind -N 'Set the even-vertical layout' M-2 select-layout even-vertical",
"bind M-4 select-layout main-vertical", "bind -N 'Set the main-horizontal layout' M-3 select-layout main-horizontal",
"bind M-5 select-layout tiled", "bind -N 'Set the main-vertical layout' M-4 select-layout main-vertical",
"bind M-n next-window -a", "bind -N 'Select the tiled layout' M-5 select-layout tiled",
"bind M-o rotate-window -D", "bind -N 'Select the next window with an alert' M-n next-window -a",
"bind M-p previous-window -a", "bind -N 'Rotate through the panes in reverse' M-o rotate-window -D",
"bind -r S-Up refresh-client -U 10", "bind -N 'Select the previous window with an alert' M-p previous-window -a",
"bind -r S-Down refresh-client -D 10", "bind -N 'Move the visible part of the window up' -r S-Up refresh-client -U 10",
"bind -r S-Left refresh-client -L 10", "bind -N 'Move the visible part of the window down' -r S-Down refresh-client -D 10",
"bind -r S-Right refresh-client -R 10", "bind -N 'Move the visible part of the window left' -r S-Left refresh-client -L 10",
"bind -r DC refresh-client -c", "bind -N 'Move the visible part of the window right' -r S-Right refresh-client -R 10",
"bind -r M-Up resize-pane -U 5", "bind -N 'Reset so the visible part of the window follows the cursor' -r DC refresh-client -c",
"bind -r M-Down resize-pane -D 5", "bind -N 'Resize the pane up by 5' -r M-Up resize-pane -U 5",
"bind -r M-Left resize-pane -L 5", "bind -N 'Resize the pane down by 5' -r M-Down resize-pane -D 5",
"bind -r M-Right resize-pane -R 5", "bind -N 'Resize the pane left by 5' -r M-Left resize-pane -L 5",
"bind -r C-Up resize-pane -U", "bind -N 'Resize the pane right by 5' -r M-Right resize-pane -R 5",
"bind -r C-Down resize-pane -D", "bind -N 'Resize the pane up' -r C-Up resize-pane -U",
"bind -r C-Left resize-pane -L", "bind -N 'Resize the pane down' -r C-Down resize-pane -D",
"bind -r C-Right resize-pane -R", "bind -N 'Resize the pane left' -r C-Left resize-pane -L",
"bind -N 'Resize the pane right' -r C-Right resize-pane -R",
"bind -n MouseDown1Pane select-pane -t=\\; send-keys -M", "bind -n MouseDown1Pane select-pane -t=\\; send-keys -M",
"bind -n MouseDrag1Border resize-pane -M", "bind -n MouseDrag1Border resize-pane -M",

2
proc.c
View File

@ -181,7 +181,7 @@ proc_start(const char *name)
memset(&u, 0, sizeof u); memset(&u, 0, sizeof u);
log_debug("%s started (%ld): version %s, socket %s, protocol %d", name, log_debug("%s started (%ld): version %s, socket %s, protocol %d", name,
(long)getpid(), VERSION, socket_path, PROTOCOL_VERSION); (long)getpid(), getversion(), socket_path, PROTOCOL_VERSION);
log_debug("on %s %s %s; libevent %s (%s)", u.sysname, u.release, log_debug("on %s %s %s; libevent %s (%s)", u.sysname, u.release,
u.version, event_get_version(), event_get_method()); u.version, event_get_version(), event_get_method());

View File

@ -66,10 +66,26 @@ resize_window(struct window *w, u_int sx, u_int sy, int xpixel, int ypixel)
static int static int
ignore_client_size(struct client *c) ignore_client_size(struct client *c)
{ {
struct client *loop;
if (c->session == NULL) if (c->session == NULL)
return (1); return (1);
if (c->flags & CLIENT_NOSIZEFLAGS) if (c->flags & CLIENT_NOSIZEFLAGS)
return (1); return (1);
if (c->flags & CLIENT_READONLY) {
/*
* Ignore readonly clients if there are any attached clients
* that aren't readonly.
*/
TAILQ_FOREACH (loop, &clients, entry) {
if (loop->session == NULL)
continue;
if (loop->flags & CLIENT_NOSIZEFLAGS)
continue;
if (~loop->flags & CLIENT_READONLY)
return (1);
}
}
if ((c->flags & CLIENT_CONTROL) && (~c->flags & CLIENT_SIZECHANGED)) if ((c->flags & CLIENT_CONTROL) && (~c->flags & CLIENT_SIZECHANGED))
return (1); return (1);
return (0); return (0);
@ -363,14 +379,15 @@ recalculate_sizes(void)
* client. * client.
*/ */
TAILQ_FOREACH(c, &clients, entry) { TAILQ_FOREACH(c, &clients, entry) {
s = c->session;
if (s != NULL && !(c->flags & CLIENT_UNATTACHEDFLAGS))
s->attached++;
if (ignore_client_size(c)) if (ignore_client_size(c))
continue; continue;
s = c->session;
if (c->tty.sy <= s->statuslines || (c->flags & CLIENT_CONTROL)) if (c->tty.sy <= s->statuslines || (c->flags & CLIENT_CONTROL))
c->flags |= CLIENT_STATUSOFF; c->flags |= CLIENT_STATUSOFF;
else else
c->flags &= ~CLIENT_STATUSOFF; c->flags &= ~CLIENT_STATUSOFF;
s->attached++;
} }
/* Walk each window and adjust the size. */ /* Walk each window and adjust the size. */

View File

@ -1032,7 +1032,7 @@ server_client_key_callback(struct cmdq_item *item, void *data)
key_code key0; key_code key0;
/* Check the client is good to accept input. */ /* Check the client is good to accept input. */
if (s == NULL || (c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0) if (s == NULL || (c->flags & CLIENT_UNATTACHEDFLAGS))
goto out; goto out;
wl = s->curw; wl = s->curw;
@ -1219,7 +1219,7 @@ server_client_handle_key(struct client *c, struct key_event *event)
struct cmdq_item *item; struct cmdq_item *item;
/* Check the client is good to accept input. */ /* Check the client is good to accept input. */
if (s == NULL || (c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0) if (s == NULL || (c->flags & CLIENT_UNATTACHEDFLAGS))
return (0); return (0);
/* /*

35
spawn.c
View File

@ -223,6 +223,17 @@ spawn_pane(struct spawn_context *sc, char **cause)
spawn_log(__func__, sc); spawn_log(__func__, sc);
/*
* Work out the current working directory. If respawning, use
* the pane's stored one unless specified.
*/
if (sc->cwd != NULL)
cwd = format_single(item, sc->cwd, c, s, NULL, NULL);
else if (~sc->flags & SPAWN_RESPAWN)
cwd = xstrdup(server_client_get_cwd(c, s));
else
cwd = NULL;
/* /*
* If we are respawning then get rid of the old process. Otherwise * If we are respawning then get rid of the old process. Otherwise
* either create a new cell or assign to the one we are given. * either create a new cell or assign to the one we are given.
@ -233,6 +244,7 @@ spawn_pane(struct spawn_context *sc, char **cause)
window_pane_index(sc->wp0, &idx); window_pane_index(sc->wp0, &idx);
xasprintf(cause, "pane %s:%d.%u still active", xasprintf(cause, "pane %s:%d.%u still active",
s->name, sc->wl->idx, idx); s->name, sc->wl->idx, idx);
free(cwd);
return (NULL); return (NULL);
} }
if (sc->wp0->fd != -1) { if (sc->wp0->fd != -1) {
@ -253,8 +265,8 @@ spawn_pane(struct spawn_context *sc, char **cause)
} }
/* /*
* Now we have a pane with nothing running in it ready for the new * Now we have a pane with nothing running in it ready for the new process.
* process. Work out the command and arguments. * Work out the command and arguments and store the working directory.
*/ */
if (sc->argc == 0 && (~sc->flags & SPAWN_RESPAWN)) { if (sc->argc == 0 && (~sc->flags & SPAWN_RESPAWN)) {
cmd = options_get_string(s->options, "default-command"); cmd = options_get_string(s->options, "default-command");
@ -269,6 +281,10 @@ spawn_pane(struct spawn_context *sc, char **cause)
argc = sc->argc; argc = sc->argc;
argv = sc->argv; argv = sc->argv;
} }
if (cwd != NULL) {
free(new_wp->cwd);
new_wp->cwd = cwd;
}
/* /*
* Replace the stored arguments if there are new ones. If not, the * Replace the stored arguments if there are new ones. If not, the
@ -280,21 +296,6 @@ spawn_pane(struct spawn_context *sc, char **cause)
new_wp->argv = cmd_copy_argv(argc, argv); new_wp->argv = cmd_copy_argv(argc, argv);
} }
/*
* Work out the current working directory. If respawning, use
* the pane's stored one unless specified.
*/
if (sc->cwd != NULL)
cwd = format_single(item, sc->cwd, c, s, NULL, NULL);
else if (~sc->flags & SPAWN_RESPAWN)
cwd = xstrdup(server_client_get_cwd(c, s));
else
cwd = NULL;
if (cwd != NULL) {
free(new_wp->cwd);
new_wp->cwd = cwd;
}
/* Create an environment for this pane. */ /* Create an environment for this pane. */
child = environ_for_session(s, 0); child = environ_for_session(s, 0);
if (sc->environ != NULL) if (sc->environ != NULL)

View File

@ -915,11 +915,17 @@ status_prompt_key(struct client *c, key_code key)
{ {
struct options *oo = c->session->options; struct options *oo = c->session->options;
char *s, *cp, word[64], prefix = '='; char *s, *cp, word[64], prefix = '=';
const char *histstr, *ws = NULL; const char *histstr, *ws = NULL, *keystring;
size_t size, n, off, idx, used; size_t size, n, off, idx, used;
struct utf8_data tmp, *first, *last, *ud; struct utf8_data tmp, *first, *last, *ud;
int keys; int keys;
if (c->prompt_flags & PROMPT_KEY) {
keystring = key_string_lookup_key(key);
c->prompt_inputcb(c, c->prompt_data, keystring, 1);
status_prompt_clear(c);
return (0);
}
size = utf8_strlen(c->prompt_buffer); size = utf8_strlen(c->prompt_buffer);
if (c->prompt_flags & PROMPT_NUMERIC) { if (c->prompt_flags & PROMPT_NUMERIC) {

68
tmux.1
View File

@ -214,7 +214,6 @@ was given) and off.
Report the Report the
.Nm .Nm
version. version.
.Pp
.It Ar command Op Ar flags .It Ar command Op Ar flags
This specifies one of a set of commands used to control This specifies one of a set of commands used to control
.Nm , .Nm ,
@ -1292,6 +1291,17 @@ shows the parsed commands and line numbers if possible.
Start the Start the
.Nm .Nm
server, if not already running, without creating any sessions. server, if not already running, without creating any sessions.
.Pp
Note that as by default the
.Nm
server will exit with no sessions, this is only useful if a session is created in
.Pa ~/.tmux.conf ,
.Ic exit-empty
is turned off, or another command is run as part of the same command sequence.
For example:
.Bd -literal -offset indent
$ tmux start \\; show -g
.Ed
.It Xo Ic suspend-client .It Xo Ic suspend-client
.Op Fl t Ar target-client .Op Fl t Ar target-client
.Xc .Xc
@ -1340,7 +1350,8 @@ is used,
option will not be applied. option will not be applied.
.Pp .Pp
.Fl T .Fl T
sets the client's key table; the next key from the client will be interpreted from sets the client's key table; the next key from the client will be interpreted
from
.Ar key-table . .Ar key-table .
This may be used to configure multiple prefix keys, or to bind commands to This may be used to configure multiple prefix keys, or to bind commands to
sequences of keys. sequences of keys.
@ -2538,10 +2549,11 @@ This is similar to
except the source and destination windows are swapped. except the source and destination windows are swapped.
It is an error if no window exists at It is an error if no window exists at
.Ar src-window . .Ar src-window .
If
.Fl d
is given, the new window does not become the current window.
.Pp .Pp
Like If
.Ic swap-pane ,
if
.Fl s .Fl s
is omitted and a marked pane is present (see is omitted and a marked pane is present (see
.Ic select-pane .Ic select-pane
@ -2617,6 +2629,7 @@ Commands related to key bindings are as follows:
.Bl -tag -width Ds .Bl -tag -width Ds
.It Xo Ic bind-key .It Xo Ic bind-key
.Op Fl nr .Op Fl nr
.Op Fl N Ar note
.Op Fl T Ar key-table .Op Fl T Ar key-table
.Ar key Ar command Op Ar arguments .Ar key Ar command Op Ar arguments
.Xc .Xc
@ -2664,22 +2677,46 @@ The
flag indicates this key may repeat, see the flag indicates this key may repeat, see the
.Ic repeat-time .Ic repeat-time
option. option.
.Fl N
attaches a note to the key (shown with
.Ic list-keys
.Fl N ) .
.Pp .Pp
To view the default bindings and possible commands, see the To view the default bindings and possible commands, see the
.Ic list-keys .Ic list-keys
command. command.
.It Xo Ic list-keys .It Xo Ic list-keys
.Op Fl T Ar key-table .Op Fl 1N
.Op Fl P Ar prefix-string Fl T Ar key-table
.Op key
.Xc .Xc
.D1 (alias: Ic lsk ) .D1 (alias: Ic lsk )
List all key bindings. List all key bindings.
Without By default this shows all keys or any bindings for
.Fl T .Ar key
all key tables are printed. in the syntax of the
.Ic bind-key
command.
.Fl N
instead show keys and attached notes, i
.Ar key-table
if given or in the
.Em root
and
.Em prefix
key tables by default.
.Fl P
specifies a prefix to print before each key.
With With
.Fl 1
only the first matching key and note is shown.
.Pp
Without
.Fl N ,
.Fl T .Fl T
only prints only keys in
.Ar key-table . .Ar key-table ,
otherwise all key tables are printed.
.It Xo Ic send-keys .It Xo Ic send-keys
.Op Fl FHlMRX .Op Fl FHlMRX
.Op Fl N Ar repeat-count .Op Fl N Ar repeat-count
@ -4232,7 +4269,6 @@ The following variables are available, where appropriate:
.It Li "client_readonly" Ta "" Ta "1 if client is readonly" .It Li "client_readonly" Ta "" Ta "1 if client is readonly"
.It Li "client_session" Ta "" Ta "Name of the client's session" .It Li "client_session" Ta "" Ta "Name of the client's session"
.It Li "client_termname" Ta "" Ta "Terminal name of client" .It Li "client_termname" Ta "" Ta "Terminal name of client"
.It Li "client_termtype" Ta "" Ta "Terminal type of client"
.It Li "client_tty" Ta "" Ta "Pseudo terminal of client" .It Li "client_tty" Ta "" Ta "Pseudo terminal of client"
.It Li "client_utf8" Ta "" Ta "1 if client supports UTF-8" .It Li "client_utf8" Ta "" Ta "1 if client supports UTF-8"
.It Li "client_width" Ta "" Ta "Width of client" .It Li "client_width" Ta "" Ta "Width of client"
@ -4700,7 +4736,7 @@ session option.
Commands related to the status line are as follows: Commands related to the status line are as follows:
.Bl -tag -width Ds .Bl -tag -width Ds
.It Xo Ic command-prompt .It Xo Ic command-prompt
.Op Fl 1Ni .Op Fl 1ikN
.Op Fl I Ar inputs .Op Fl I Ar inputs
.Op Fl p Ar prompts .Op Fl p Ar prompts
.Op Fl t Ar target-client .Op Fl t Ar target-client
@ -4750,6 +4786,10 @@ but any quotation marks are escaped.
.Fl 1 .Fl 1
makes the prompt only accept one key press, in this case the resulting input makes the prompt only accept one key press, in this case the resulting input
is a single character. is a single character.
.Fl k
is like
.Fl 1
but the key press is translated to a key name.
.Fl N .Fl N
makes the prompt only accept numeric key presses. makes the prompt only accept numeric key presses.
.Fl i .Fl i
@ -4913,7 +4953,7 @@ When the
option is reached, the oldest automatically named buffer is deleted. option is reached, the oldest automatically named buffer is deleted.
Explicitly named buffers are not subject to Explicitly named buffers are not subject to
.Ic buffer-limit .Ic buffer-limit
and may be deleted with and may be deleted with the
.Ic delete-buffer .Ic delete-buffer
command. command.
.Pp .Pp

15
tmux.c
View File

@ -18,6 +18,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/utsname.h>
#include <errno.h> #include <errno.h>
#include <event.h> #include <event.h>
@ -209,6 +210,12 @@ find_home(void)
return (home); return (home);
} }
const char *
getversion(void)
{
return TMUX_VERSION;
}
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
@ -235,7 +242,7 @@ main(int argc, char **argv)
flags = 0; flags = 0;
label = path = NULL; label = path = NULL;
while ((opt = getopt(argc, argv, "2c:Cdf:lL:qS:uUVv")) != -1) { while ((opt = getopt(argc, argv, "2c:Cdf:lL:qS:uUvV")) != -1) {
switch (opt) { switch (opt) {
case '2': case '2':
flags |= CLIENT_256COLOURS; flags |= CLIENT_256COLOURS;
@ -249,12 +256,12 @@ main(int argc, char **argv)
else else
flags |= CLIENT_CONTROL; flags |= CLIENT_CONTROL;
break; break;
case 'V':
printf("%s %s\n", getprogname(), VERSION);
exit(0);
case 'f': case 'f':
set_cfg_file(optarg); set_cfg_file(optarg);
break; break;
case 'V':
printf("%s %s\n", getprogname(), getversion());
exit(0);
case 'l': case 'l':
flags |= CLIENT_LOGIN; flags |= CLIENT_LOGIN;
break; break;

51
tmux.h
View File

@ -1187,8 +1187,11 @@ struct tty_term {
struct tty_code *codes; struct tty_code *codes;
#define TERM_256COLOURS 0x1 #define TERM_256COLOURS 0x1
#define TERM_EARLYWRAP 0x2 #define TERM_NOXENL 0x2
#define TERM_SIXEL 0x4 #define TERM_DECSLRM 0x4
#define TERM_DECFRA 0x8
#define TERM_RGBCOLOURS 0x10
#define TERM_SIXEL 0x20
int flags; int flags;
LIST_ENTRY(tty_term) entry; LIST_ENTRY(tty_term) entry;
@ -1197,6 +1200,7 @@ LIST_HEAD(tty_terms, tty_term);
struct tty { struct tty {
struct client *client; struct client *client;
struct event start_timer;
u_int sx; u_int sx;
u_int sy; u_int sy;
@ -1245,22 +1249,14 @@ struct tty {
#define TTY_OPENED 0x20 #define TTY_OPENED 0x20
#define TTY_FOCUS 0x40 #define TTY_FOCUS 0x40
#define TTY_BLOCK 0x80 #define TTY_BLOCK 0x80
#define TTY_NOBLOCK 0x100 #define TTY_HAVEDA 0x100
#define TTY_HAVEDSR 0x200
#define TTY_NOBLOCK 0x400
int flags; int flags;
struct tty_term *term; struct tty_term *term;
char *term_name; char *term_name;
int term_flags; int term_flags;
enum {
TTY_VT100,
TTY_VT101,
TTY_VT102,
TTY_VT220,
TTY_VT320,
TTY_VT420,
TTY_VT520,
TTY_UNKNOWN
} term_type;
u_int mouse_last_x; u_int mouse_last_x;
u_int mouse_last_y; u_int mouse_last_y;
@ -1274,15 +1270,6 @@ struct tty {
struct event key_timer; struct event key_timer;
struct tty_key *key_tree; struct tty_key *key_tree;
}; };
#define TTY_TYPES \
{ "VT100", \
"VT101", \
"VT102", \
"VT220", \
"VT320", \
"VT420", \
"VT520", \
"Unknown" }
/* TTY command context. */ /* TTY command context. */
struct tty_ctx { struct tty_ctx {
@ -1293,6 +1280,7 @@ struct tty_ctx {
u_int num; u_int num;
void *ptr; void *ptr;
int more;
/* /*
* Cursor and region position before the screen was updated - this is * Cursor and region position before the screen was updated - this is
@ -1617,11 +1605,14 @@ struct client {
CLIENT_REDRAWSTATUSALWAYS| \ CLIENT_REDRAWSTATUSALWAYS| \
CLIENT_REDRAWBORDERS| \ CLIENT_REDRAWBORDERS| \
CLIENT_REDRAWOVERLAY) CLIENT_REDRAWOVERLAY)
#define CLIENT_UNATTACHEDFLAGS \
(CLIENT_DEAD| \
CLIENT_SUSPENDED| \
CLIENT_DETACHING)
#define CLIENT_NOSIZEFLAGS \ #define CLIENT_NOSIZEFLAGS \
(CLIENT_DEAD| \ (CLIENT_DEAD| \
CLIENT_SUSPENDED| \ CLIENT_SUSPENDED| \
CLIENT_DETACHING| \ CLIENT_DETACHING)
CLIENT_READONLY)
int flags; int flags;
struct key_table *keytable; struct key_table *keytable;
@ -1644,6 +1635,7 @@ struct client {
#define PROMPT_NUMERIC 0x2 #define PROMPT_NUMERIC 0x2
#define PROMPT_INCREMENTAL 0x4 #define PROMPT_INCREMENTAL 0x4
#define PROMPT_NOFORMAT 0x8 #define PROMPT_NOFORMAT 0x8
#define PROMPT_KEY 0x10
int prompt_flags; int prompt_flags;
struct session *session; struct session *session;
@ -1671,6 +1663,7 @@ TAILQ_HEAD(clients, client);
struct key_binding { struct key_binding {
key_code key; key_code key;
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
const char *note;
int flags; int flags;
#define KEY_BINDING_REPEAT 0x1 #define KEY_BINDING_REPEAT 0x1
@ -1798,6 +1791,7 @@ int areshell(const char *);
void setblocking(int, int); void setblocking(int, int);
const char *find_cwd(void); const char *find_cwd(void);
const char *find_home(void); const char *find_home(void);
const char *getversion(void);
/* proc.c */ /* proc.c */
struct imsg; struct imsg;
@ -2014,7 +2008,7 @@ void tty_draw_images(struct tty *, struct window_pane *, struct screen *);
int tty_open(struct tty *, char **); int tty_open(struct tty *, char **);
void tty_close(struct tty *); void tty_close(struct tty *);
void tty_free(struct tty *); void tty_free(struct tty *);
void tty_set_type(struct tty *, int, int); void tty_set_flags(struct tty *, int);
void tty_write(void (*)(struct tty *, const struct tty_ctx *), void tty_write(void (*)(struct tty *, const struct tty_ctx *),
struct tty_ctx *); struct tty_ctx *);
void tty_cmd_alignmenttest(struct tty *, const struct tty_ctx *); void tty_cmd_alignmenttest(struct tty *, const struct tty_ctx *);
@ -2184,7 +2178,8 @@ void key_bindings_unref_table(struct key_table *);
struct key_binding *key_bindings_get(struct key_table *, key_code); struct key_binding *key_bindings_get(struct key_table *, key_code);
struct key_binding *key_bindings_first(struct key_table *); struct key_binding *key_bindings_first(struct key_table *);
struct key_binding *key_bindings_next(struct key_table *, struct key_binding *); struct key_binding *key_bindings_next(struct key_table *, struct key_binding *);
void key_bindings_add(const char *, key_code, int, struct cmd_list *); void key_bindings_add(const char *, key_code, const char *, int,
struct cmd_list *);
void key_bindings_remove(const char *, key_code); void key_bindings_remove(const char *, key_code);
void key_bindings_remove_table(const char *); void key_bindings_remove_table(const char *);
void key_bindings_init(void); void key_bindings_init(void);
@ -2315,7 +2310,7 @@ void input_parse(struct window_pane *);
void input_parse_buffer(struct window_pane *, u_char *, size_t); void input_parse_buffer(struct window_pane *, u_char *, size_t);
/* input-key.c */ /* input-key.c */
void input_key(struct window_pane *, key_code, struct mouse_event *); int input_key(struct window_pane *, key_code, struct mouse_event *);
/* xterm-keys.c */ /* xterm-keys.c */
char *xterm_keys_lookup(key_code); char *xterm_keys_lookup(key_code);
@ -2540,7 +2535,7 @@ int window_pane_set_mode(struct window_pane *,
struct args *); struct args *);
void window_pane_reset_mode(struct window_pane *); void window_pane_reset_mode(struct window_pane *);
void window_pane_reset_mode_all(struct window_pane *); void window_pane_reset_mode_all(struct window_pane *);
void window_pane_key(struct window_pane *, struct client *, int window_pane_key(struct window_pane *, struct client *,
struct session *, struct winlink *, key_code, struct session *, struct winlink *, key_code,
struct mouse_event *); struct mouse_event *);
int window_pane_visible(struct window_pane *); int window_pane_visible(struct window_pane *);

View File

@ -52,6 +52,8 @@ static int tty_keys_clipboard(struct tty *, const char *, size_t,
size_t *); size_t *);
static int tty_keys_device_attributes(struct tty *, const char *, size_t, static int tty_keys_device_attributes(struct tty *, const char *, size_t,
size_t *); size_t *);
static int tty_keys_device_status_report(struct tty *, const char *,
size_t, size_t *);
/* Default raw keys. */ /* Default raw keys. */
struct tty_default_key_raw { struct tty_default_key_raw {
@ -607,6 +609,17 @@ tty_keys_next(struct tty *tty)
goto partial_key; goto partial_key;
} }
/* Is this a device status report response? */
switch (tty_keys_device_status_report(tty, buf, len, &size)) {
case 0: /* yes */
key = KEYC_UNKNOWN;
goto complete_key;
case -1: /* no, or not valid */
break;
case 1: /* partial */
goto partial_key;
}
/* Is this a mouse key press? */ /* Is this a mouse key press? */
switch (tty_keys_mouse(tty, buf, len, &size, &m)) { switch (tty_keys_mouse(tty, buf, len, &size, &m)) {
case 0: /* yes */ case 0: /* yes */
@ -1004,10 +1017,11 @@ tty_keys_device_attributes(struct tty *tty, const char *buf, size_t len,
struct client *c = tty->client; struct client *c = tty->client;
u_int i, n = 0; u_int i, n = 0;
char tmp[64], *endptr, p[32] = { 0 }, *cp, *next; char tmp[64], *endptr, p[32] = { 0 }, *cp, *next;
static const char *types[] = TTY_TYPES; int flags = 0;
int type, flags = 0;
*size = 0; *size = 0;
if (tty->flags & TTY_HAVEDA)
return (-1);
/* First three bytes are always \033[?. */ /* First three bytes are always \033[?. */
if (buf[0] != '\033') if (buf[0] != '\033')
@ -1038,44 +1052,80 @@ tty_keys_device_attributes(struct tty *tty, const char *buf, size_t len,
cp = tmp; cp = tmp;
while ((next = strsep(&cp, ";")) != NULL) { while ((next = strsep(&cp, ";")) != NULL) {
p[n] = strtoul(next, &endptr, 10); p[n] = strtoul(next, &endptr, 10);
if (*endptr != '\0' && *endptr != ';') if (*endptr != '\0')
p[n] = 0; p[n] = 0;
n++; n++;
} }
/* Store terminal type. */ /* Set terminal flags. */
type = TTY_UNKNOWN;
switch (p[0]) { switch (p[0]) {
case 1: case 64: /* VT420 */
if (p[1] == 2) flags |= (TERM_DECFRA|TERM_DECSLRM);
type = TTY_VT100;
else if (p[1] == 0)
type = TTY_VT101;
break;
case 6:
type = TTY_VT102;
break;
case 62:
type = TTY_VT220;
break;
case 63:
type = TTY_VT320;
break;
case 64:
type = TTY_VT420;
break;
case 65:
type = TTY_VT520;
break; break;
} }
for (i = 2; i < n; i++) { for (i = 1; i < n; i++) {
log_debug("%s: DA feature: %d", c->name, p[i]); log_debug("%s: DA feature: %d", c->name, p[i]);
if (p[i] == 4) if (p[i] == 4)
flags |= TERM_SIXEL; flags |= TERM_SIXEL;
} }
tty_set_type(tty, type, flags);
log_debug("%s: received DA %.*s (%s)", c->name, (int)*size, buf, tty_set_flags(tty, flags);
types[type]); tty->flags |= TTY_HAVEDA;
return (0);
}
/*
* Handle device status report input. Returns 0 for success, -1 for failure, 1
* for partial.
*/
static int
tty_keys_device_status_report(struct tty *tty, const char *buf, size_t len,
size_t *size)
{
struct client *c = tty->client;
u_int i;
char tmp[64];
int flags = 0;
*size = 0;
if (tty->flags & TTY_HAVEDSR)
return (-1);
/* First three bytes are always \033[. */
if (buf[0] != '\033')
return (-1);
if (len == 1)
return (1);
if (buf[1] != '[')
return (-1);
if (len == 2)
return (1);
if (buf[2] != 'I' && buf[2] != 'T')
return (-1);
if (len == 3)
return (1);
/* Copy the rest up to a 'n'. */
for (i = 0; i < (sizeof tmp) - 1 && buf[2 + i] != 'n'; i++) {
if (2 + i == len)
return (1);
tmp[i] = buf[2 + i];
}
if (i == (sizeof tmp) - 1)
return (-1);
tmp[i] = '\0';
*size = 3 + i;
/* Set terminal flags. */
if (strncmp(tmp, "ITERM2 ", 7) == 0)
flags |= (TERM_DECSLRM|TERM_256COLOURS|TERM_RGBCOLOURS);
if (strncmp(tmp, "TMUX ", 5) == 0)
flags |= (TERM_256COLOURS|TERM_RGBCOLOURS);
log_debug("%s: received DSR %.*s", c->name, (int)*size, buf);
tty_set_flags(tty, flags);
tty->flags |= TTY_HAVEDSR;
return (0); return (0);
} }

View File

@ -529,11 +529,16 @@ tty_term_find(char *name, int fd, char **cause)
goto error; goto error;
} }
/* Figure out if we have 256 colours (or more). */ /* Set flag if terminal has 256 colours. */
if (tty_term_number(term, TTYC_COLORS) >= 256 || if (tty_term_number(term, TTYC_COLORS) >= 256)
tty_term_has(term, TTYC_RGB))
term->flags |= TERM_256COLOURS; term->flags |= TERM_256COLOURS;
/* Set flag if terminal has RGB colours. */
if ((tty_term_flag(term, TTYC_TC) || tty_term_has(term, TTYC_RGB)) ||
(tty_term_has(term, TTYC_SETRGBF) &&
tty_term_has(term, TTYC_SETRGBB)))
term->flags |= TERM_RGBCOLOURS;
/* /*
* Terminals without xenl (eat newline glitch) wrap at at $COLUMNS - 1 * Terminals without xenl (eat newline glitch) wrap at at $COLUMNS - 1
* rather than $COLUMNS (the cursor can never be beyond $COLUMNS - 1). * rather than $COLUMNS (the cursor can never be beyond $COLUMNS - 1).
@ -545,7 +550,7 @@ tty_term_find(char *name, int fd, char **cause)
* do the best possible. * do the best possible.
*/ */
if (!tty_term_flag(term, TTYC_XENL)) if (!tty_term_flag(term, TTYC_XENL))
term->flags |= TERM_EARLYWRAP; term->flags |= TERM_NOXENL;
/* Generate ACS table. If none is present, use nearest ASCII. */ /* Generate ACS table. If none is present, use nearest ASCII. */
memset(term->acs, 0, sizeof term->acs); memset(term->acs, 0, sizeof term->acs);
@ -568,22 +573,7 @@ tty_term_find(char *name, int fd, char **cause)
code->type = TTYCODE_STRING; code->type = TTYCODE_STRING;
} }
/* /* Log the capabilities. */
* On terminals with RGB colour (Tc or RGB), fill in setrgbf and
* setrgbb if they are missing.
*/
if ((tty_term_flag(term, TTYC_TC) || tty_term_flag(term, TTYC_RGB)) &&
!tty_term_has(term, TTYC_SETRGBF) &&
!tty_term_has(term, TTYC_SETRGBB)) {
code = &term->codes[TTYC_SETRGBF];
code->value.string = xstrdup("\033[38;2;%p1%d;%p2%d;%p3%dm");
code->type = TTYCODE_STRING;
code = &term->codes[TTYC_SETRGBB];
code->value.string = xstrdup("\033[48;2;%p1%d;%p2%d;%p3%dm");
code->type = TTYCODE_STRING;
}
/* Log it. */
for (i = 0; i < tty_term_ncodes(); i++) for (i = 0; i < tty_term_ncodes(); i++)
log_debug("%s%s", name, tty_term_describe(term, i)); log_debug("%s%s", name, tty_term_describe(term, i));

67
tty.c
View File

@ -74,7 +74,7 @@ static void tty_default_attributes(struct tty *, struct window_pane *,
u_int); u_int);
#define tty_use_margin(tty) \ #define tty_use_margin(tty) \
((tty)->term_type == TTY_VT420) ((tty->term->flags|tty->term_flags) & TERM_DECSLRM)
#define tty_pane_full_width(tty, ctx) \ #define tty_pane_full_width(tty, ctx) \
((ctx)->xoff == 0 && screen_size_x((ctx)->wp->screen) >= (tty)->sx) ((ctx)->xoff == 0 && screen_size_x((ctx)->wp->screen) >= (tty)->sx)
@ -115,9 +115,7 @@ tty_init(struct tty *tty, struct client *c, int fd, char *term)
tty->ccolour = xstrdup(""); tty->ccolour = xstrdup("");
tty->flags = 0; tty->flags = 0;
tty->term_flags = 0; tty->term_flags = 0;
tty->term_type = TTY_UNKNOWN;
return (0); return (0);
} }
@ -292,11 +290,22 @@ tty_open(struct tty *tty, char **cause)
return (0); return (0);
} }
static void
tty_start_timer_callback(__unused int fd, __unused short events, void *data)
{
struct tty *tty = data;
struct client *c = tty->client;
log_debug("%s: start timer fired", c->name);
tty->flags |= (TTY_HAVEDA|TTY_HAVEDSR);
}
void void
tty_start_tty(struct tty *tty) tty_start_tty(struct tty *tty)
{ {
struct client *c = tty->client; struct client *c = tty->client;
struct termios tio; struct termios tio;
struct timeval tv = { .tv_sec = 1 };
if (tty->fd != -1 && tcgetattr(tty->fd, &tty->tio) == 0) { if (tty->fd != -1 && tcgetattr(tty->fd, &tty->tio) == 0) {
setblocking(tty->fd, 0); setblocking(tty->fd, 0);
@ -334,8 +343,15 @@ tty_start_tty(struct tty *tty)
tty->flags |= TTY_FOCUS; tty->flags |= TTY_FOCUS;
tty_puts(tty, "\033[?1004h"); tty_puts(tty, "\033[?1004h");
} }
if (~tty->flags & TTY_HAVEDA)
tty_puts(tty, "\033[c"); tty_puts(tty, "\033[c");
} if (~tty->flags & TTY_HAVEDSR)
tty_puts(tty, "\033[1337n");
} else
tty->flags |= (TTY_HAVEDA|TTY_HAVEDSR);
evtimer_set(&tty->start_timer, tty_start_timer_callback, tty);
evtimer_add(&tty->start_timer, &tv);
tty->flags |= TTY_STARTED; tty->flags |= TTY_STARTED;
tty_invalidate(tty); tty_invalidate(tty);
@ -357,6 +373,8 @@ tty_stop_tty(struct tty *tty)
return; return;
tty->flags &= ~TTY_STARTED; tty->flags &= ~TTY_STARTED;
evtimer_del(&tty->start_timer);
event_del(&tty->timer); event_del(&tty->timer);
tty->flags &= ~TTY_BLOCK; tty->flags &= ~TTY_BLOCK;
@ -443,9 +461,8 @@ tty_free(struct tty *tty)
} }
void void
tty_set_type(struct tty *tty, int type, int flags) tty_set_flags(struct tty *tty, int flags)
{ {
tty->term_type = type;
tty->term_flags |= flags; tty->term_flags |= flags;
if (tty_use_margin(tty)) if (tty_use_margin(tty))
@ -549,7 +566,7 @@ tty_putc(struct tty *tty, u_char ch)
{ {
const char *acs; const char *acs;
if ((tty->term->flags & TERM_EARLYWRAP) && if ((tty->term->flags & TERM_NOXENL) &&
ch >= 0x20 && ch != 0x7f && ch >= 0x20 && ch != 0x7f &&
tty->cy == tty->sy - 1 && tty->cy == tty->sy - 1 &&
tty->cx + 1 >= tty->sx) tty->cx + 1 >= tty->sx)
@ -575,7 +592,7 @@ tty_putc(struct tty *tty, u_char ch)
* where we think it should be after a line wrap - this * where we think it should be after a line wrap - this
* means it works on sensible terminals as well. * means it works on sensible terminals as well.
*/ */
if (tty->term->flags & TERM_EARLYWRAP) if (tty->term->flags & TERM_NOXENL)
tty_putcode2(tty, TTYC_CUP, tty->cy, tty->cx); tty_putcode2(tty, TTYC_CUP, tty->cy, tty->cx);
} else } else
tty->cx++; tty->cx++;
@ -585,7 +602,7 @@ tty_putc(struct tty *tty, u_char ch)
void void
tty_putn(struct tty *tty, const void *buf, size_t len, u_int width) tty_putn(struct tty *tty, const void *buf, size_t len, u_int width)
{ {
if ((tty->term->flags & TERM_EARLYWRAP) && if ((tty->term->flags & TERM_NOXENL) &&
tty->cy == tty->sy - 1 && tty->cy == tty->sy - 1 &&
tty->cx + len >= tty->sx) tty->cx + len >= tty->sx)
len = tty->sx - tty->cx - 1; len = tty->sx - tty->cx - 1;
@ -1135,7 +1152,8 @@ tty_clear_area(struct tty *tty, struct window_pane *wp, u_int py, u_int ny,
* background colour isn't default (because it doesn't work * background colour isn't default (because it doesn't work
* after SGR 0). * after SGR 0).
*/ */
if (tty->term_type == TTY_VT420 && !COLOUR_DEFAULT(bg)) { if (((tty->term->flags|tty->term_flags) & TERM_DECFRA) &&
!COLOUR_DEFAULT(bg)) {
xsnprintf(tmp, sizeof tmp, "\033[32;%u;%u;%u;%u$x", xsnprintf(tmp, sizeof tmp, "\033[32;%u;%u;%u;%u$x",
py + 1, px + 1, py + ny, px + nx); py + 1, px + 1, py + ny, px + nx);
tty_puts(tty, tmp); tty_puts(tty, tmp);
@ -1862,7 +1880,7 @@ tty_cmd_cells(struct tty *tty, const struct tty_ctx *ctx)
ctx->xoff + ctx->ocx + ctx->num > ctx->ox + ctx->sx)) { ctx->xoff + ctx->ocx + ctx->num > ctx->ox + ctx->sx)) {
if (!ctx->wrapped || if (!ctx->wrapped ||
!tty_pane_full_width(tty, ctx) || !tty_pane_full_width(tty, ctx) ||
(tty->term->flags & TERM_EARLYWRAP) || (tty->term->flags & TERM_NOXENL) ||
ctx->xoff + ctx->ocx != 0 || ctx->xoff + ctx->ocx != 0 ||
ctx->yoff + ctx->ocy != tty->cy + 1 || ctx->yoff + ctx->ocy != tty->cy + 1 ||
tty->cx < tty->sx || tty->cx < tty->sx ||
@ -1957,7 +1975,7 @@ tty_cell(struct tty *tty, const struct grid_cell *gc, struct window_pane *wp)
const struct grid_cell *gcp; const struct grid_cell *gcp;
/* Skip last character if terminal is stupid. */ /* Skip last character if terminal is stupid. */
if ((tty->term->flags & TERM_EARLYWRAP) && if ((tty->term->flags & TERM_NOXENL) &&
tty->cy == tty->sy - 1 && tty->cy == tty->sy - 1 &&
tty->cx == tty->sx - 1) tty->cx == tty->sx - 1)
return; return;
@ -2116,7 +2134,7 @@ tty_cursor_pane_unless_wrap(struct tty *tty, const struct tty_ctx *ctx,
{ {
if (!ctx->wrapped || if (!ctx->wrapped ||
!tty_pane_full_width(tty, ctx) || !tty_pane_full_width(tty, ctx) ||
(tty->term->flags & TERM_EARLYWRAP) || (tty->term->flags & TERM_NOXENL) ||
ctx->xoff + cx != 0 || ctx->xoff + cx != 0 ||
ctx->yoff + cy != tty->cy + 1 || ctx->yoff + cy != tty->cy + 1 ||
tty->cx < tty->sx || tty->cx < tty->sx ||
@ -2453,11 +2471,10 @@ tty_check_fg(struct tty *tty, struct window_pane *wp, struct grid_cell *gc)
/* Is this a 24-bit colour? */ /* Is this a 24-bit colour? */
if (gc->fg & COLOUR_FLAG_RGB) { if (gc->fg & COLOUR_FLAG_RGB) {
/* Not a 24-bit terminal? Translate to 256-colour palette. */ /* Not a 24-bit terminal? Translate to 256-colour palette. */
if (!tty_term_has(tty->term, TTYC_SETRGBF)) { if ((tty->term->flags|tty->term_flags) & TERM_RGBCOLOURS)
return;
colour_split_rgb(gc->fg, &r, &g, &b); colour_split_rgb(gc->fg, &r, &g, &b);
gc->fg = colour_find_rgb(r, g, b); gc->fg = colour_find_rgb(r, g, b);
} else
return;
} }
/* How many colours does this terminal have? */ /* How many colours does this terminal have? */
@ -2503,11 +2520,10 @@ tty_check_bg(struct tty *tty, struct window_pane *wp, struct grid_cell *gc)
/* Is this a 24-bit colour? */ /* Is this a 24-bit colour? */
if (gc->bg & COLOUR_FLAG_RGB) { if (gc->bg & COLOUR_FLAG_RGB) {
/* Not a 24-bit terminal? Translate to 256-colour palette. */ /* Not a 24-bit terminal? Translate to 256-colour palette. */
if (!tty_term_has(tty->term, TTYC_SETRGBB)) { if ((tty->term->flags|tty->term_flags) & TERM_RGBCOLOURS)
return;
colour_split_rgb(gc->bg, &r, &g, &b); colour_split_rgb(gc->bg, &r, &g, &b);
gc->bg = colour_find_rgb(r, g, b); gc->bg = colour_find_rgb(r, g, b);
} else
return;
} }
/* How many colours does this terminal have? */ /* How many colours does this terminal have? */
@ -2684,15 +2700,14 @@ tty_try_colour(struct tty *tty, int colour, const char *type)
} }
if (colour & COLOUR_FLAG_RGB) { if (colour & COLOUR_FLAG_RGB) {
colour_split_rgb(colour & 0xffffff, &r, &g, &b);
if (*type == '3') { if (*type == '3') {
if (!tty_term_has(tty->term, TTYC_SETRGBF)) if (!tty_term_has(tty->term, TTYC_SETRGBF))
return (-1); goto fallback_rgb;
colour_split_rgb(colour & 0xffffff, &r, &g, &b);
tty_putcode3(tty, TTYC_SETRGBF, r, g, b); tty_putcode3(tty, TTYC_SETRGBF, r, g, b);
} else { } else {
if (!tty_term_has(tty->term, TTYC_SETRGBB)) if (!tty_term_has(tty->term, TTYC_SETRGBB))
return (-1); goto fallback_rgb;
colour_split_rgb(colour & 0xffffff, &r, &g, &b);
tty_putcode3(tty, TTYC_SETRGBB, r, g, b); tty_putcode3(tty, TTYC_SETRGBB, r, g, b);
} }
return (0); return (0);
@ -2705,6 +2720,12 @@ fallback_256:
log_debug("%s: 256 colour fallback: %s", tty->client->name, s); log_debug("%s: 256 colour fallback: %s", tty->client->name, s);
tty_puts(tty, s); tty_puts(tty, s);
return (0); return (0);
fallback_rgb:
xsnprintf(s, sizeof s, "\033[%s;2;%d;%d;%dm", type, r, g, b);
log_debug("%s: RGB colour fallback: %s", tty->client->name, s);
tty_puts(tty, s);
return (0);
} }
static void static void

View File

@ -210,7 +210,7 @@ window_client_draw(__unused void *modedata, void *itemdata,
struct window_pane *wp; struct window_pane *wp;
u_int cx = s->cx, cy = s->cy, lines, at; u_int cx = s->cx, cy = s->cy, lines, at;
if (c->session == NULL || (c->flags & (CLIENT_DEAD|CLIENT_DETACHING))) if (c->session == NULL || (c->flags & CLIENT_UNATTACHEDFLAGS))
return; return;
wp = c->session->curw->window->active; wp = c->session->curw->window->active;

View File

@ -1239,7 +1239,7 @@ window_pane_reset_mode_all(struct window_pane *wp)
window_pane_reset_mode(wp); window_pane_reset_mode(wp);
} }
void int
window_pane_key(struct window_pane *wp, struct client *c, struct session *s, window_pane_key(struct window_pane *wp, struct client *c, struct session *s,
struct winlink *wl, key_code key, struct mouse_event *m) struct winlink *wl, key_code key, struct mouse_event *m)
{ {
@ -1247,23 +1247,24 @@ window_pane_key(struct window_pane *wp, struct client *c, struct session *s,
struct window_pane *wp2; struct window_pane *wp2;
if (KEYC_IS_MOUSE(key) && m == NULL) if (KEYC_IS_MOUSE(key) && m == NULL)
return; return (-1);
wme = TAILQ_FIRST(&wp->modes); wme = TAILQ_FIRST(&wp->modes);
if (wme != NULL) { if (wme != NULL) {
wp->modelast = time(NULL); wp->modelast = time(NULL);
if (wme->mode->key != NULL) if (wme->mode->key != NULL)
wme->mode->key(wme, c, s, wl, (key & ~KEYC_XTERM), m); wme->mode->key(wme, c, s, wl, (key & ~KEYC_XTERM), m);
return; return (0);
} }
if (wp->fd == -1 || wp->flags & PANE_INPUTOFF) if (wp->fd == -1 || wp->flags & PANE_INPUTOFF)
return; return (0);
input_key(wp, key, m); if (input_key(wp, key, m) != 0)
return (-1);
if (KEYC_IS_MOUSE(key)) if (KEYC_IS_MOUSE(key))
return; return (0);
if (options_get_number(wp->window->options, "synchronize-panes")) { if (options_get_number(wp->window->options, "synchronize-panes")) {
TAILQ_FOREACH(wp2, &wp->window->panes, entry) { TAILQ_FOREACH(wp2, &wp->window->panes, entry) {
if (wp2 != wp && if (wp2 != wp &&
@ -1274,6 +1275,7 @@ window_pane_key(struct window_pane *wp, struct client *c, struct session *s,
input_key(wp2, key, NULL); input_key(wp2, key, NULL);
} }
} }
return (0);
} }
int int