Merge branch 'master' into sixel

This commit is contained in:
Nicholas Marriott 2020-01-12 20:03:41 +00:00
commit 40ad01073d
15 changed files with 701 additions and 94 deletions

8
cfg.c
View File

@ -184,9 +184,9 @@ load_cfg(const char *path, struct client *c, struct cmdq_item *item, int flags,
new_item0 = cmdq_get_command(pr->cmdlist, NULL, NULL, 0);
if (item != NULL)
cmdq_insert_after(item, new_item0);
new_item0 = cmdq_insert_after(item, new_item0);
else
cmdq_append(NULL, new_item0);
new_item0 = cmdq_append(NULL, new_item0);
cmd_list_free(pr->cmdlist);
if (new_item != NULL)
@ -230,9 +230,9 @@ load_cfg_from_buffer(const void *buf, size_t len, const char *path,
new_item0 = cmdq_get_command(pr->cmdlist, NULL, NULL, 0);
if (item != NULL)
cmdq_insert_after(item, new_item0);
new_item0 = cmdq_insert_after(item, new_item0);
else
cmdq_append(NULL, new_item0);
new_item0 = cmdq_append(NULL, new_item0);
cmd_list_free(pr->cmdlist);
if (new_item != NULL)

View File

@ -52,7 +52,7 @@ const struct cmd_entry cmd_move_pane_entry = {
.args = { "bdhvp:l:s:t:", 0, 0 },
.usage = "[-bdhv] [-p percentage|-l size] " CMD_SRCDST_PANE_USAGE,
.source = { 's', CMD_FIND_PANE, 0 },
.source = { 's', CMD_FIND_PANE, CMD_FIND_DEFAULT_MARKED },
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,

View File

@ -53,12 +53,16 @@ cmdq_get(struct client *c)
}
/* Append an item. */
void
struct cmdq_item *
cmdq_append(struct client *c, struct cmdq_item *item)
{
struct cmdq_list *queue = cmdq_get(c);
struct cmdq_item *next;
TAILQ_FOREACH(next, queue, entry) {
log_debug("%s %s: queue %s (%u)", __func__, cmdq_name(c),
next->name, next->group);
}
do {
next = item->next;
item->next = NULL;
@ -73,16 +77,21 @@ cmdq_append(struct client *c, struct cmdq_item *item)
item = next;
} while (item != NULL);
return (TAILQ_LAST(queue, cmdq_list));
}
/* Insert an item. */
void
struct cmdq_item *
cmdq_insert_after(struct cmdq_item *after, struct cmdq_item *item)
{
struct client *c = after->client;
struct cmdq_list *queue = after->queue;
struct cmdq_item *next;
TAILQ_FOREACH(next, queue, entry) {
log_debug("%s %s: queue %s (%u)", __func__, cmdq_name(c),
next->name, next->group);
}
do {
next = item->next;
item->next = after->next;
@ -100,6 +109,7 @@ cmdq_insert_after(struct cmdq_item *after, struct cmdq_item *item)
after = item;
item = next;
} while (item != NULL);
return (after);
}
/* Insert a hook. */
@ -143,11 +153,10 @@ cmdq_insert_hook(struct session *s, struct cmdq_item *item,
new_item = cmdq_get_command(cmdlist, fs, NULL, CMDQ_NOHOOKS);
cmdq_format(new_item, "hook", "%s", name);
if (item != NULL) {
cmdq_insert_after(item, new_item);
item = new_item;
} else
cmdq_append(NULL, new_item);
if (item != NULL)
item = cmdq_insert_after(item, new_item);
else
item = cmdq_append(NULL, new_item);
a = options_array_next(a);
}
@ -542,7 +551,10 @@ cmdq_error(struct cmdq_item *item, const char *fmt, ...)
msg = utf8_sanitize(tmp);
free(tmp);
}
file_error(c, "%s\n", msg);
if (c->flags & CLIENT_CONTROL)
file_print(c, "%s\n", msg);
else
file_error(c, "%s\n", msg);
c->retval = 1;
} else {
*msg = toupper((u_char) *msg);

View File

@ -113,6 +113,7 @@ cmd_source_file_done(struct client *c, const char *path, int error,
static void
cmd_source_file_add(struct cmd_source_file_data *cdata, const char *path)
{
log_debug("%s: %s", __func__, path);
cdata->files = xreallocarray(cdata->files, cdata->nfiles + 1,
sizeof *cdata->files);
cdata->files[cdata->nfiles++] = xstrdup(path);
@ -123,7 +124,6 @@ cmd_source_file_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct cmd_source_file_data *cdata;
int flags = 0;
struct client *c = item->client;
enum cmd_retval retval = CMD_RETURN_NORMAL;
char *pattern, *cwd;
@ -159,7 +159,7 @@ cmd_source_file_exec(struct cmd *self, struct cmdq_item *item)
if ((result = glob(pattern, 0, NULL, &g)) != 0) {
if (result != GLOB_NOMATCH ||
(~flags & CMD_PARSE_QUIET)) {
(~cdata->flags & CMD_PARSE_QUIET)) {
if (result == GLOB_NOMATCH)
error = strerror(ENOENT);
else if (result == GLOB_NOSPACE)

2
cmd.c
View File

@ -660,7 +660,7 @@ char *
cmd_template_replace(const char *template, const char *s, int idx)
{
char ch, *buf;
const char *ptr, *cp, quote[] = "\"\\$;";
const char *ptr, *cp, quote[] = "\"\\$;~";
int replaced, quoted;
size_t len;

View File

@ -849,8 +849,10 @@ format_trim_left(const char *expanded, u_int limit)
out += ud.size;
}
width += ud.width;
} else
} else {
cp -= ud.have;
cp++;
}
} else if (*cp > 0x1f && *cp < 0x7f) {
if (width + 1 <= limit)
*out++ = *cp;
@ -896,8 +898,10 @@ format_trim_right(const char *expanded, u_int limit)
out += ud.size;
}
width += ud.width;
} else
} else {
cp -= ud.have;
cp++;
}
} else if (*cp > 0x1f && *cp < 0x7f) {
if (width >= skip)
*out++ = *cp;

220
format.c
View File

@ -456,6 +456,35 @@ format_cb_pid(__unused struct format_tree *ft, struct format_entry *fe)
xasprintf(&fe->value, "%ld", (long)getpid());
}
/* Callback for session_attached_list. */
static void
format_cb_session_attached_list(struct format_tree *ft, struct format_entry *fe)
{
struct session *s = ft->s;
struct client *loop;
struct evbuffer *buffer;
int size;
if (s == NULL)
return;
buffer = evbuffer_new();
if (buffer == NULL)
fatalx("out of memory");
TAILQ_FOREACH(loop, &clients, entry) {
if (loop->session == s) {
if (EVBUFFER_LENGTH(buffer) > 0)
evbuffer_add(buffer, ",", 1);
evbuffer_add_printf(buffer, "%s", loop->name);
}
}
if ((size = EVBUFFER_LENGTH(buffer)) != 0)
xasprintf(&fe->value, "%.*s", size, EVBUFFER_DATA(buffer));
evbuffer_free(buffer);
}
/* Callback for session_alerts. */
static void
format_cb_session_alerts(struct format_tree *ft, struct format_entry *fe)
@ -528,6 +557,128 @@ format_cb_window_stack_index(struct format_tree *ft, struct format_entry *fe)
fe->value = xstrdup("0");
}
/* Callback for window_linked_sessions_list. */
static void
format_cb_window_linked_sessions_list(struct format_tree *ft,
struct format_entry *fe)
{
struct window *w = ft->wl->window;
struct winlink *wl;
struct evbuffer *buffer;
int size;
buffer = evbuffer_new();
if (buffer == NULL)
fatalx("out of memory");
TAILQ_FOREACH(wl, &w->winlinks, wentry) {
if (EVBUFFER_LENGTH(buffer) > 0)
evbuffer_add(buffer, ",", 1);
evbuffer_add_printf(buffer, "%s", wl->session->name);
}
if ((size = EVBUFFER_LENGTH(buffer)) != 0)
xasprintf(&fe->value, "%.*s", size, EVBUFFER_DATA(buffer));
evbuffer_free(buffer);
}
/* Callback for window_active_sessions. */
static void
format_cb_window_active_sessions(struct format_tree *ft,
struct format_entry *fe)
{
struct window *w = ft->wl->window;
struct winlink *wl;
u_int n = 0;
TAILQ_FOREACH(wl, &w->winlinks, wentry) {
if (wl->session->curw == wl)
n++;
}
xasprintf(&fe->value, "%u", n);
}
/* Callback for window_active_sessions_list. */
static void
format_cb_window_active_sessions_list(struct format_tree *ft,
struct format_entry *fe)
{
struct window *w = ft->wl->window;
struct winlink *wl;
struct evbuffer *buffer;
int size;
buffer = evbuffer_new();
if (buffer == NULL)
fatalx("out of memory");
TAILQ_FOREACH(wl, &w->winlinks, wentry) {
if (wl->session->curw == wl) {
if (EVBUFFER_LENGTH(buffer) > 0)
evbuffer_add(buffer, ",", 1);
evbuffer_add_printf(buffer, "%s", wl->session->name);
}
}
if ((size = EVBUFFER_LENGTH(buffer)) != 0)
xasprintf(&fe->value, "%.*s", size, EVBUFFER_DATA(buffer));
evbuffer_free(buffer);
}
/* Callback for window_active_clients. */
static void
format_cb_window_active_clients(struct format_tree *ft, struct format_entry *fe)
{
struct window *w = ft->wl->window;
struct client *loop;
struct session *client_session;
u_int n = 0;
TAILQ_FOREACH(loop, &clients, entry) {
client_session = loop->session;
if (client_session == NULL)
continue;
if (w == client_session->curw->window)
n++;
}
xasprintf(&fe->value, "%u", n);
}
/* Callback for window_active_clients_list. */
static void
format_cb_window_active_clients_list(struct format_tree *ft,
struct format_entry *fe)
{
struct window *w = ft->wl->window;
struct client *loop;
struct session *client_session;
struct evbuffer *buffer;
int size;
buffer = evbuffer_new();
if (buffer == NULL)
fatalx("out of memory");
TAILQ_FOREACH(loop, &clients, entry) {
client_session = loop->session;
if (client_session == NULL)
continue;
if (w == client_session->curw->window) {
if (EVBUFFER_LENGTH(buffer) > 0)
evbuffer_add(buffer, ",", 1);
evbuffer_add_printf(buffer, "%s", loop->name);
}
}
if ((size = EVBUFFER_LENGTH(buffer)) != 0)
xasprintf(&fe->value, "%.*s", size, EVBUFFER_DATA(buffer));
evbuffer_free(buffer);
}
/* Callback for window_layout. */
static void
format_cb_window_layout(struct format_tree *ft, struct format_entry *fe)
@ -677,11 +828,52 @@ format_cb_session_group_list(struct format_tree *ft, struct format_entry *fe)
buffer = evbuffer_new();
if (buffer == NULL)
fatalx("out of memory");
TAILQ_FOREACH(loop, &sg->sessions, gentry) {
if (EVBUFFER_LENGTH(buffer) > 0)
evbuffer_add(buffer, ",", 1);
evbuffer_add_printf(buffer, "%s", loop->name);
}
if ((size = EVBUFFER_LENGTH(buffer)) != 0)
xasprintf(&fe->value, "%.*s", size, EVBUFFER_DATA(buffer));
evbuffer_free(buffer);
}
/* Callback for session_group_attached_list. */
static void
format_cb_session_group_attached_list(struct format_tree *ft,
struct format_entry *fe)
{
struct session *s = ft->s, *client_session, *session_loop;
struct session_group *sg;
struct client *loop;
struct evbuffer *buffer;
int size;
if (s == NULL)
return;
sg = session_group_contains(s);
if (sg == NULL)
return;
buffer = evbuffer_new();
if (buffer == NULL)
fatalx("out of memory");
TAILQ_FOREACH(loop, &clients, entry) {
client_session = loop->session;
if (client_session == NULL)
continue;
TAILQ_FOREACH(session_loop, &sg->sessions, gentry) {
if (session_loop == client_session){
if (EVBUFFER_LENGTH(buffer) > 0)
evbuffer_add(buffer, ",", 1);
evbuffer_add_printf(buffer, "%s", loop->name);
}
}
}
if ((size = EVBUFFER_LENGTH(buffer)) != 0)
xasprintf(&fe->value, "%.*s", size, EVBUFFER_DATA(buffer));
evbuffer_free(buffer);
@ -974,12 +1166,12 @@ format_each(struct format_tree *ft, void (*cb)(const char *, const char *,
void *), void *arg)
{
struct format_entry *fe;
static char s[64];
char s[64];
RB_FOREACH(fe, format_entry_tree, &ft->tree) {
if (fe->t != 0) {
xsnprintf(s, sizeof s, "%lld", (long long)fe->t);
cb(fe->key, fe->value, s);
cb(fe->key, s, arg);
} else {
if (fe->value == NULL && fe->cb != NULL) {
fe->cb(ft, fe);
@ -1022,8 +1214,7 @@ format_add(struct format_tree *ft, const char *key, const char *fmt, ...)
static void
format_add_tv(struct format_tree *ft, const char *key, struct timeval *tv)
{
struct format_entry *fe;
struct format_entry *fe_now;
struct format_entry *fe, *fe_now;
fe = xmalloc(sizeof *fe);
fe->key = xstrdup(key);
@ -2141,8 +2332,14 @@ format_defaults_session(struct format_tree *ft, struct session *s)
format_add(ft, "session_group", "%s", sg->name);
format_add(ft, "session_group_size", "%u",
session_group_count (sg));
format_add(ft, "session_group_attached", "%u",
session_group_attached_count (sg));
format_add(ft, "session_group_many_attached", "%u",
session_group_attached_count (sg) > 1);
format_add_cb(ft, "session_group_list",
format_cb_session_group_list);
format_add_cb(ft, "session_group_attached_list",
format_cb_session_group_attached_list);
}
format_add_tv(ft, "session_created", &s->creation_time);
@ -2151,6 +2348,8 @@ format_defaults_session(struct format_tree *ft, struct session *s)
format_add(ft, "session_attached", "%u", s->attached);
format_add(ft, "session_many_attached", "%d", s->attached > 1);
format_add_cb(ft, "session_attached_list",
format_cb_session_attached_list);
format_add_cb(ft, "session_alerts", format_cb_session_alerts);
format_add_cb(ft, "session_stack", format_cb_session_stack);
@ -2265,6 +2464,14 @@ format_defaults_winlink(struct format_tree *ft, struct winlink *wl)
format_add_cb(ft, "window_stack_index", format_cb_window_stack_index);
format_add(ft, "window_flags", "%s", window_printable_flags(wl));
format_add(ft, "window_active", "%d", wl == s->curw);
format_add_cb(ft, "window_active_sessions",
format_cb_window_active_sessions);
format_add_cb(ft, "window_active_sessions_list",
format_cb_window_active_sessions_list);
format_add_cb(ft, "window_active_clients",
format_cb_window_active_clients);
format_add_cb(ft, "window_active_clients_list",
format_cb_window_active_clients_list);
format_add(ft, "window_start_flag", "%d",
!!(wl == RB_MIN(winlinks, &s->windows)));
@ -2285,6 +2492,11 @@ format_defaults_winlink(struct format_tree *ft, struct winlink *wl)
format_add(ft, "window_last_flag", "%d",
!!(wl == TAILQ_FIRST(&s->lastw)));
format_add(ft, "window_linked", "%d", session_is_linked(s, wl->window));
format_add_cb(ft, "window_linked_sessions_list",
format_cb_window_linked_sessions_list);
format_add(ft, "window_linked_sessions", "%u",
wl->window->references);
}
/* Set default format keys for a window pane. */

View File

@ -85,6 +85,14 @@ key_bindings_cmp(struct key_binding *bd1, struct key_binding *bd2)
return (0);
}
static void
key_bindings_free(struct key_table *table, struct key_binding *bd)
{
RB_REMOVE(key_bindings, &table->key_bindings, bd);
cmd_list_free(bd->cmdlist);
free(bd);
}
struct key_table *
key_bindings_get_table(const char *name, int create)
{
@ -126,11 +134,8 @@ key_bindings_unref_table(struct key_table *table)
if (--table->references != 0)
return;
RB_FOREACH_SAFE(bd, key_bindings, &table->key_bindings, bd1) {
RB_REMOVE(key_bindings, &table->key_bindings, bd);
cmd_list_free(bd->cmdlist);
free(bd);
}
RB_FOREACH_SAFE(bd, key_bindings, &table->key_bindings, bd1)
key_bindings_free(table, bd);
free((void *)table->name);
free(table);
@ -162,17 +167,13 @@ key_bindings_add(const char *name, key_code key, int repeat,
struct cmd_list *cmdlist)
{
struct key_table *table;
struct key_binding bd_find, *bd;
struct key_binding *bd;
table = key_bindings_get_table(name, 1);
bd_find.key = (key & ~KEYC_XTERM);
bd = RB_FIND(key_bindings, &table->key_bindings, &bd_find);
if (bd != NULL) {
RB_REMOVE(key_bindings, &table->key_bindings, bd);
cmd_list_free(bd->cmdlist);
free(bd);
}
bd = key_bindings_get(table, key & ~KEYC_XTERM);
if (bd != NULL)
key_bindings_free(table, bd);
bd = xcalloc(1, sizeof *bd);
bd->key = key;
@ -187,20 +188,16 @@ void
key_bindings_remove(const char *name, key_code key)
{
struct key_table *table;
struct key_binding bd_find, *bd;
struct key_binding *bd;
table = key_bindings_get_table(name, 0);
if (table == NULL)
return;
bd_find.key = (key & ~KEYC_XTERM);
bd = RB_FIND(key_bindings, &table->key_bindings, &bd_find);
bd = key_bindings_get(table, key & ~KEYC_XTERM);
if (bd == NULL)
return;
RB_REMOVE(key_bindings, &table->key_bindings, bd);
cmd_list_free(bd->cmdlist);
free(bd);
key_bindings_free(table, bd);
if (RB_EMPTY(&table->key_bindings)) {
RB_REMOVE(key_tables, &key_tables, table);
@ -520,8 +517,8 @@ key_bindings_dispatch(struct key_binding *bd, struct cmdq_item *item,
new_item->shared->flags |= CMDQ_SHARED_REPEAT;
}
if (item != NULL)
cmdq_insert_after(item, new_item);
new_item = cmdq_insert_after(item, new_item);
else
cmdq_append(c, new_item);
new_item = cmdq_append(c, new_item);
return (new_item);
}

View File

@ -89,9 +89,7 @@ notify_insert_hook(struct cmdq_item *item, struct notify_entry *ne)
new_item = cmdq_get_command(cmdlist, &fs, NULL, CMDQ_NOHOOKS);
cmdq_format(new_item, "hook", "%s", ne->name);
notify_hook_formats(new_item, s, w, ne->pane);
cmdq_insert_after(item, new_item);
item = new_item;
item = cmdq_insert_after(item, new_item);
a = options_array_next(a);
}

View File

@ -568,7 +568,20 @@ session_group_count(struct session_group *sg)
n = 0;
TAILQ_FOREACH(s, &sg->sessions, gentry)
n++;
n++;
return (n);
}
/* Count number of clients attached to sessions in session group. */
u_int
session_group_attached_count(struct session_group *sg)
{
struct session *s;
u_int n;
n = 0;
TAILQ_FOREACH(s, &sg->sessions, gentry)
n += s->attached;
return (n);
}

View File

@ -78,6 +78,8 @@ spawn_log(const char *from, struct spawn_context *sc)
struct winlink *
spawn_window(struct spawn_context *sc, char **cause)
{
struct cmdq_item *item = sc->item;
struct client *c = item->client;
struct session *s = sc->s;
struct window *w;
struct window_pane *wp;
@ -180,7 +182,8 @@ spawn_window(struct spawn_context *sc, char **cause)
/* Set the name of the new window. */
if (~sc->flags & SPAWN_RESPAWN) {
if (sc->name != NULL) {
w->name = xstrdup(sc->name);
w->name = format_single(item, sc->name, c, s, NULL,
NULL);
options_set_number(w->options, "automatic-rename", 0);
} else
w->name = xstrdup(default_window_name(w));

51
tmux.1
View File

@ -938,7 +938,9 @@ If
is specified, any other clients attached to the session are detached.
If
.Fl x
is given, send SIGHUP to the parent process of the client as well as
is given, send
.Dv SIGHUP
to the parent process of the client as well as
detaching the client, typically causing it to exit.
.Fl r
signifies the client is read-only (only keys bound to the
@ -989,7 +991,9 @@ option kills all but the client given with
.Fl t .
If
.Fl P
is given, send SIGHUP to the parent process of the client, typically causing it
is given, send
.Dv SIGHUP
to the parent process of the client, typically causing it
to exit.
With
.Fl E ,
@ -4316,10 +4320,14 @@ The following variables are available, where appropriate:
.It Li "session_activity" Ta "" Ta "Time of session last activity"
.It Li "session_alerts" Ta "" Ta "List of window indexes with alerts"
.It Li "session_attached" Ta "" Ta "Number of clients session is attached to"
.It Li "session_attached_list" Ta "" Ta "List of clients session is attached to"
.It Li "session_created" Ta "" Ta "Time session created"
.It Li "session_format" Ta "" Ta "1 if format is for a session"
.It Li "session_group" Ta "" Ta "Name of session group"
.It Li "session_group_attached" Ta "" Ta "Number of clients sessions in group are attached to"
.It Li "session_group_attached_list" Ta "" Ta "List of clients sessions in group are attached to"
.It Li "session_group_list" Ta "" Ta "List of sessions in group"
.It Li "session_group_many_attached" Ta "" Ta "1 if multiple clients attached to sessions in group"
.It Li "session_group_size" Ta "" Ta "Size of session group"
.It Li "session_grouped" Ta "" Ta "1 if session in a group"
.It Li "session_id" Ta "" Ta "Unique session ID"
@ -4332,6 +4340,10 @@ The following variables are available, where appropriate:
.It Li "start_time" Ta "" Ta "Server start time"
.It Li "version" Ta "" Ta "Server version"
.It Li "window_active" Ta "" Ta "1 if window active"
.It Li "window_active_clients" Ta "" Ta "Number of clients viewing this window"
.It Li "window_active_clients_list" Ta "" Ta "List of clients viewing this window"
.It Li "window_active_sessions" Ta "" Ta "Number of sessions on which this window is active"
.It Li "window_active_sessions_list" Ta "" Ta "List of sessions on which this window is active"
.It Li "window_activity" Ta "" Ta "Time of window last activity"
.It Li "window_activity_flag" Ta "" Ta "1 if window has activity"
.It Li "window_bell_flag" Ta "" Ta "1 if window has bell"
@ -4347,6 +4359,8 @@ The following variables are available, where appropriate:
.It Li "window_last_flag" Ta "" Ta "1 if window is the last used"
.It Li "window_layout" Ta "" Ta "Window layout description, ignoring zoomed window panes"
.It Li "window_linked" Ta "" Ta "1 if window is linked across sessions"
.It Li "window_linked_sessions" Ta "" Ta "Number of sessions this window is linked to"
.It Li "window_linked_sessions_list" Ta "" Ta "List of sessions this window is linked to"
.It Li "window_marked_flag" Ta "" Ta "1 if window contains the marked pane"
.It Li "window_name" Ta "#W" Ta "Name of window"
.It Li "window_offset_x" Ta "" Ta "X offset into window if larger than client"
@ -4367,7 +4381,7 @@ interface, for example
.Ic status-style
for the status line.
In addition, embedded styles may be specified in format options, such as
.Ic status-left-format ,
.Ic status-left ,
by enclosing them in
.Ql #[
and
@ -5145,6 +5159,37 @@ channel are made to wait until the channel is unlocked with
.Ic wait-for
.Fl U .
.El
.Sh EXIT MESSAGES
When a
.Nm
client detaches, it prints a message.
This may be one of:
.Bl -tag -width Ds
.It [detached (from session ...)]
The client was detached normally.
.It [detached and SIGHUP]
The client was detached and its parent sent the
.Dv SIGHUP
signal (for example with
.Ic detach-client
.Fl P ) .
.It [lost tty]
The client's
.Xr tty 4
or
.Xr pty 4
was unexpectedly destroyed.
.It [terminated]
The client was killed with
.Dv SIGTERM .
.It [exited]
The server exited when it had no sessions.
.It [server exited]
The server exited when it received
.Dv SIGTERM .
.It [server exited unexpectedly]
The server crashed or otherwise exited without telling the client the reason.
.El
.Sh TERMINFO EXTENSIONS
.Nm
understands some unofficial extensions to

8
tmux.h
View File

@ -1620,7 +1620,8 @@ struct client {
#define CLIENT_NOSIZEFLAGS \
(CLIENT_DEAD| \
CLIENT_SUSPENDED| \
CLIENT_DETACHING)
CLIENT_DETACHING| \
CLIENT_READONLY)
int flags;
struct key_table *keytable;
@ -2157,8 +2158,8 @@ struct cmdq_item *cmdq_get_command(struct cmd_list *, struct cmd_find_state *,
#define cmdq_get_callback(cb, data) cmdq_get_callback1(#cb, cb, data)
struct cmdq_item *cmdq_get_callback1(const char *, cmdq_cb, void *);
struct cmdq_item *cmdq_get_error(const char *);
void cmdq_insert_after(struct cmdq_item *, struct cmdq_item *);
void cmdq_append(struct client *, struct cmdq_item *);
struct cmdq_item *cmdq_insert_after(struct cmdq_item *, struct cmdq_item *);
struct cmdq_item *cmdq_append(struct client *, struct cmdq_item *);
void cmdq_insert_hook(struct session *, struct cmdq_item *,
struct cmd_find_state *, const char *, ...);
void cmdq_continue(struct cmdq_item *);
@ -2714,6 +2715,7 @@ void session_group_add(struct session_group *, struct session *);
void session_group_synchronize_to(struct session *);
void session_group_synchronize_from(struct session *);
u_int session_group_count(struct session_group *);
u_int session_group_attached_count(struct session_group *);
void session_renumber_windows(struct session *);
/* utf8.c */

View File

@ -19,6 +19,7 @@
#include <sys/types.h>
#include <ctype.h>
#include <regex.h>
#include <stdlib.h>
#include <string.h>
@ -57,18 +58,29 @@ static int window_copy_search_lr(struct grid *, struct grid *, u_int *,
u_int, u_int, u_int, int);
static int window_copy_search_rl(struct grid *, struct grid *, u_int *,
u_int, u_int, u_int, int);
static int window_copy_search_lr_regex(struct grid *, struct grid *,
u_int *, u_int *, u_int, u_int, u_int, int);
static int window_copy_search_rl_regex(struct grid *, struct grid *,
u_int *, u_int *, u_int, u_int, u_int, int);
static int window_copy_last_regex(struct grid *gd, u_int py, u_int first,
u_int last, u_int len, u_int *ppx, u_int *psx,
const char *buf, const regex_t *preg, int eflags);
static char *window_copy_stringify(struct grid *, u_int, u_int, u_int,
char *, u_int *);
static void window_copy_cstrtocellpos(struct grid *, u_int, u_int *, u_int *,
const char *str);
static int window_copy_search_marks(struct window_mode_entry *,
struct screen *);
struct screen *, int);
static void window_copy_clear_marks(struct window_mode_entry *);
static void window_copy_move_left(struct screen *, u_int *, u_int *, int);
static void window_copy_move_right(struct screen *, u_int *, u_int *, int);
static int window_copy_is_lowercase(const char *);
static int window_copy_search_jump(struct window_mode_entry *,
struct grid *, struct grid *, u_int, u_int, u_int, int, int,
int);
static int window_copy_search(struct window_mode_entry *, int);
static int window_copy_search_up(struct window_mode_entry *);
static int window_copy_search_down(struct window_mode_entry *);
int, int);
static int window_copy_search(struct window_mode_entry *, int, int);
static int window_copy_search_up(struct window_mode_entry *, int);
static int window_copy_search_down(struct window_mode_entry *, int);
static void window_copy_goto_line(struct window_mode_entry *, const char *);
static void window_copy_update_cursor(struct window_mode_entry *, u_int,
u_int);
@ -622,7 +634,7 @@ window_copy_resize(struct window_mode_entry *wme, u_int sx, u_int sy)
screen_write_stop(&ctx);
if (search)
window_copy_search_marks(wme, NULL);
window_copy_search_marks(wme, NULL, 1);
data->searchx = data->cx;
data->searchy = data->cy;
data->searcho = data->oy;
@ -1458,10 +1470,10 @@ window_copy_cmd_search_again(struct window_copy_cmd_state *cs)
if (data->searchtype == WINDOW_COPY_SEARCHUP) {
for (; np != 0; np--)
window_copy_search_up(wme);
window_copy_search_up(wme, 1);
} else if (data->searchtype == WINDOW_COPY_SEARCHDOWN) {
for (; np != 0; np--)
window_copy_search_down(wme);
window_copy_search_down(wme, 1);
}
return (WINDOW_COPY_CMD_NOTHING);
}
@ -1475,10 +1487,10 @@ window_copy_cmd_search_reverse(struct window_copy_cmd_state *cs)
if (data->searchtype == WINDOW_COPY_SEARCHUP) {
for (; np != 0; np--)
window_copy_search_down(wme);
window_copy_search_down(wme, 1);
} else if (data->searchtype == WINDOW_COPY_SEARCHDOWN) {
for (; np != 0; np--)
window_copy_search_up(wme);
window_copy_search_up(wme, 1);
}
return (WINDOW_COPY_CMD_NOTHING);
}
@ -1696,7 +1708,7 @@ window_copy_cmd_search_backward(struct window_copy_cmd_state *cs)
if (data->searchstr != NULL) {
data->searchtype = WINDOW_COPY_SEARCHUP;
for (; np != 0; np--)
window_copy_search_up(wme);
window_copy_search_up(wme, 1);
}
return (WINDOW_COPY_CMD_NOTHING);
}
@ -1731,7 +1743,7 @@ window_copy_cmd_search_forward(struct window_copy_cmd_state *cs)
if (data->searchstr != NULL) {
data->searchtype = WINDOW_COPY_SEARCHDOWN;
for (; np != 0; np--)
window_copy_search_down(wme);
window_copy_search_down(wme, 1);
}
return (WINDOW_COPY_CMD_NOTHING);
}
@ -1767,7 +1779,7 @@ window_copy_cmd_search_backward_incremental(struct window_copy_cmd_state *cs)
data->searchtype = WINDOW_COPY_SEARCHUP;
free(data->searchstr);
data->searchstr = xstrdup(argument);
if (!window_copy_search_up(wme)) {
if (!window_copy_search_up(wme, 0)) {
window_copy_clear_marks(wme);
return (WINDOW_COPY_CMD_REDRAW);
}
@ -1776,7 +1788,7 @@ window_copy_cmd_search_backward_incremental(struct window_copy_cmd_state *cs)
data->searchtype = WINDOW_COPY_SEARCHDOWN;
free(data->searchstr);
data->searchstr = xstrdup(argument);
if (!window_copy_search_down(wme)) {
if (!window_copy_search_down(wme, 0)) {
window_copy_clear_marks(wme);
return (WINDOW_COPY_CMD_REDRAW);
}
@ -1816,7 +1828,7 @@ window_copy_cmd_search_forward_incremental(struct window_copy_cmd_state *cs)
data->searchtype = WINDOW_COPY_SEARCHDOWN;
free(data->searchstr);
data->searchstr = xstrdup(argument);
if (!window_copy_search_down(wme)) {
if (!window_copy_search_down(wme, 0)) {
window_copy_clear_marks(wme);
return (WINDOW_COPY_CMD_REDRAW);
}
@ -1825,7 +1837,7 @@ window_copy_cmd_search_forward_incremental(struct window_copy_cmd_state *cs)
data->searchtype = WINDOW_COPY_SEARCHUP;
free(data->searchstr);
data->searchstr = xstrdup(argument);
if (!window_copy_search_up(wme)) {
if (!window_copy_search_up(wme, 0)) {
window_copy_clear_marks(wme);
return (WINDOW_COPY_CMD_REDRAW);
}
@ -2152,6 +2164,297 @@ window_copy_search_rl(struct grid *gd,
return (0);
}
static int
window_copy_search_lr_regex(struct grid *gd, struct grid *sgd,
u_int *ppx, u_int *psx, u_int py, u_int first, u_int last, int cis)
{
int cflags = REG_EXTENDED, eflags = 0;
u_int endline, foundx, foundy, len, pywrap, size = 1;
u_int ssize = 1;
char *buf, *sbuf;
regex_t reg;
regmatch_t regmatch;
struct grid_line *gl;
/*
* This can happen during search if the last match was the last
* character on a line.
*/
if (first >= last)
return (0);
sbuf = xmalloc(ssize);
sbuf[0] = '\0';
sbuf = window_copy_stringify(sgd, 0, 0, sgd->sx, sbuf, &ssize);
if (sbuf == NULL)
return (0);
/* Set flags for regex search. */
if (cis)
cflags |= REG_ICASE;
if (regcomp(&reg, sbuf, cflags) != 0) {
free(sbuf);
return (0);
}
if (first != 0)
eflags |= REG_NOTBOL;
/* Need to look at the entire string. */
buf = xmalloc(size);
buf[0] = '\0';
buf = window_copy_stringify(gd, py, first, gd->sx, buf, &size);
len = gd->sx - first;
endline = gd->hsize + gd->sy - 1;
pywrap = py;
while (buf != NULL && pywrap <= endline) {
gl = grid_get_line(gd, pywrap);
if (~gl->flags & GRID_LINE_WRAPPED)
break;
pywrap++;
buf = window_copy_stringify(gd, pywrap, 0, gd->sx, buf, &size);
len += gd->sx;
}
if (regexec(&reg, buf, 1, &regmatch, eflags) == 0) {
foundx = first;
foundy = py;
window_copy_cstrtocellpos(gd, len, &foundx, &foundy,
buf + regmatch.rm_so);
if (foundy == py && foundx < last) {
*ppx = foundx;
len -= foundx - first;
window_copy_cstrtocellpos(gd, len, &foundx, &foundy,
buf + regmatch.rm_eo);
*psx = foundx;
while (foundy > py) {
*psx += gd->sx;
foundy--;
}
*psx -= *ppx;
regfree(&reg);
free(sbuf);
free(buf);
return (1);
}
}
regfree(&reg);
free(sbuf);
free(buf);
*ppx = 0;
*psx = 0;
return (0);
}
static int
window_copy_search_rl_regex(struct grid *gd, struct grid *sgd,
u_int *ppx, u_int *psx, u_int py, u_int first, u_int last, int cis)
{
int cflags = REG_EXTENDED, eflags = 0;
u_int endline, len, pywrap, size = 1, ssize = 1;
char *buf, *sbuf;
regex_t reg;
struct grid_line *gl;
sbuf = xmalloc(ssize);
sbuf[0] = '\0';
sbuf = window_copy_stringify(sgd, 0, 0, sgd->sx, sbuf, &ssize);
if (sbuf == NULL)
return (0);
/* Set flags for regex search. */
if (cis)
cflags |= REG_ICASE;
if (regcomp(&reg, sbuf, cflags) != 0) {
free(sbuf);
return (0);
}
if (first != 0)
eflags |= REG_NOTBOL;
/* Need to look at the entire string. */
buf = xmalloc(size);
buf[0] = '\0';
buf = window_copy_stringify(gd, py, first, gd->sx, buf, &size);
len = gd->sx - first;
endline = gd->hsize + gd->sy - 1;
pywrap = py;
while (buf != NULL && (pywrap <= endline)) {
gl = grid_get_line(gd, pywrap);
if (~gl->flags & GRID_LINE_WRAPPED)
break;
pywrap++;
buf = window_copy_stringify(gd, pywrap, 0, gd->sx, buf, &size);
len += gd->sx;
}
if (window_copy_last_regex(gd, py, first, last, len, ppx, psx, buf,
&reg, eflags))
{
regfree(&reg);
free(sbuf);
free(buf);
return (1);
}
regfree(&reg);
free(sbuf);
free(buf);
*ppx = 0;
*psx = 0;
return (0);
}
/* Find last match in given range. */
static int
window_copy_last_regex(struct grid *gd, u_int py, u_int first, u_int last,
u_int len, u_int *ppx, u_int *psx, const char *buf, const regex_t *preg,
int eflags)
{
u_int foundx, foundy, oldx, px = 0, savepx, savesx = 0;
regmatch_t regmatch;
foundx = first;
foundy = py;
oldx = first;
while (regexec(preg, buf + px, 1, &regmatch, eflags) == 0) {
window_copy_cstrtocellpos(gd, len, &foundx, &foundy,
buf + px + regmatch.rm_so);
if (foundy > py || foundx >= last)
break;
len -= foundx - oldx;
savepx = foundx;
window_copy_cstrtocellpos(gd, len, &foundx, &foundy,
buf + px + regmatch.rm_eo);
if (foundy > py || foundx >= last) {
*ppx = savepx;
*psx = foundx;
while (foundy > py) {
*psx += gd->sx;
foundy--;
}
*psx -= *ppx;
return (1);
} else {
savesx = foundx - savepx;
len -= savesx;
oldx = foundx;
}
px += regmatch.rm_eo;
}
if (savesx > 0) {
*ppx = savepx;
*psx = savesx;
return (1);
} else {
*ppx = 0;
*psx = 0;
return (0);
}
}
/* Stringify line and append to input buffer. Caller frees. */
static char *
window_copy_stringify(struct grid *gd, u_int py, u_int first, u_int last,
char *buf, u_int *size)
{
u_int ax, bx, newsize;
struct grid_cell gc;
bx = *size - 1;
newsize = *size;
for (ax = first; ax < last; ax++) {
grid_get_cell(gd, ax, py, &gc);
newsize += gc.data.size;
buf = xrealloc(buf, newsize);
memcpy(buf + bx, gc.data.data, gc.data.size);
bx += gc.data.size;
}
buf[newsize - 1] = '\0';
*size = newsize;
return (buf);
}
/* Map start of C string containing UTF-8 data to grid cell position. */
static void
window_copy_cstrtocellpos(struct grid *gd, u_int ncells, u_int *ppx, u_int *ppy,
const char *str)
{
u_int cell, ccell, px, pywrap;
int match;
const char *cstr;
char *celldata, **cells;
struct grid_cell gc;
/* Set up staggered array of cell contents. This speeds up search. */
cells = xreallocarray(NULL, ncells, sizeof cells[0]);
/* Populate the array of cell data. */
cell = 0;
px = *ppx;
pywrap = *ppy;
while (cell < ncells) {
grid_get_cell(gd, px, pywrap, &gc);
celldata = xmalloc(gc.data.size + 1);
memcpy(celldata, gc.data.data, gc.data.size);
celldata[gc.data.size] = '\0';
cells[cell] = celldata;
cell++;
px = (px + 1) % gd->sx;
if (px == 0)
pywrap++;
}
/* Locate starting cell. */
cell = 0;
while (cell < ncells) {
ccell = cell;
cstr = str;
match = 1;
while (ccell < ncells) {
/* Anchor found to the end. */
if (*cstr == '\0') {
match = 0;
break;
}
celldata = cells[ccell];
while (*celldata != '\0' && *cstr != '\0') {
if (*celldata++ != *cstr++) {
match = 0;
break;
}
}
if (!match)
break;
ccell++;
}
if (match)
break;
cell++;
}
/* If not found this will be one past the end. */
px = *ppx + cell;
pywrap = *ppy;
while (px >= gd->sx) {
px -= gd->sx;
pywrap++;
}
*ppx = px;
*ppy = pywrap;
/* Free cell data. */
for (cell = 0; cell < ncells; cell++)
free(cells[cell]);
free(cells);
}
static void
window_copy_move_left(struct screen *s, u_int *fx, u_int *fy, int wrapflag)
{
@ -2206,24 +2509,31 @@ window_copy_is_lowercase(const char *ptr)
static int
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 direction, int regex)
{
u_int i, px;
int found;
u_int i, px, sx;
int found = 0;
found = 0;
if (direction) {
for (i = fy; i <= endline; i++) {
found = window_copy_search_lr(gd, sgd, &px, i, fx,
gd->sx, cis);
if (regex)
found = window_copy_search_lr_regex(gd, sgd,
&px, &sx, i, fx, gd->sx, cis);
else
found = window_copy_search_lr(gd, sgd,
&px, i, fx, gd->sx, cis);
if (found)
break;
fx = 0;
}
} else {
for (i = fy + 1; endline < i; i--) {
found = window_copy_search_rl(gd, sgd, &px, i - 1, 0,
fx + 1, cis);
if (regex)
found = window_copy_search_rl_regex(gd, sgd,
&px, &sx, i - 1, 0, fx + 1, cis);
else
found = window_copy_search_rl(gd, sgd,
&px, i - 1, 0, fx + 1, cis);
if (found) {
i--;
break;
@ -2240,7 +2550,7 @@ window_copy_search_jump(struct window_mode_entry *wme, struct grid *gd,
return (window_copy_search_jump(wme, gd, sgd,
direction ? 0 : gd->sx - 1,
direction ? 0 : gd->hsize + gd->sy - 1, fy, cis, 0,
direction));
direction, regex));
}
return (0);
}
@ -2250,7 +2560,7 @@ window_copy_search_jump(struct window_mode_entry *wme, struct grid *gd,
* down.
*/
static int
window_copy_search(struct window_mode_entry *wme, int direction)
window_copy_search(struct window_mode_entry *wme, int direction, int regex)
{
struct window_pane *wp = wme->wp;
struct window_copy_mode_data *data = wme->data;
@ -2281,10 +2591,11 @@ window_copy_search(struct window_mode_entry *wme, int direction)
window_copy_move_left(s, &fx, &fy, wrapflag);
endline = 0;
}
found = window_copy_search_jump(wme, gd, ss.grid, fx, fy, endline, cis,
wrapflag, direction);
if (window_copy_search_marks(wme, &ss))
found = window_copy_search_jump(wme, gd, ss.grid, fx, fy, endline, cis,
wrapflag, direction, regex);
if (window_copy_search_marks(wme, &ss, regex))
window_copy_redraw_screen(wme);
screen_free(&ss);
@ -2292,7 +2603,8 @@ window_copy_search(struct window_mode_entry *wme, int direction)
}
static int
window_copy_search_marks(struct window_mode_entry *wme, struct screen *ssp)
window_copy_search_marks(struct window_mode_entry *wme, struct screen *ssp,
int regex)
{
struct window_copy_mode_data *data = wme->data;
struct screen *s = data->backing, ss;
@ -2320,10 +2632,19 @@ window_copy_search_marks(struct window_mode_entry *wme, struct screen *ssp)
for (py = 0; py < gd->hsize + gd->sy; py++) {
px = 0;
for (;;) {
found = window_copy_search_lr(gd, ssp->grid, &px, py,
px, gd->sx, cis);
if (!found)
break;
if (regex) {
found = window_copy_search_lr_regex(gd,
ssp->grid, &px, &width, py, px,
gd->sx, cis);
if (!found)
break;
}
else {
found = window_copy_search_lr(gd, ssp->grid,
&px, py, px, gd->sx, cis);
if (!found)
break;
}
nfound++;
if (px == data->cx && py == gd->hsize + data->cy - data->oy)
@ -2357,15 +2678,15 @@ window_copy_clear_marks(struct window_mode_entry *wme)
}
static int
window_copy_search_up(struct window_mode_entry *wme)
window_copy_search_up(struct window_mode_entry *wme, int regex)
{
return (window_copy_search(wme, 0));
return (window_copy_search(wme, 0, regex));
}
static int
window_copy_search_down(struct window_mode_entry *wme)
window_copy_search_down(struct window_mode_entry *wme, int regex)
{
return (window_copy_search(wme, 1));
return (window_copy_search(wme, 1, regex));
}
static void

View File

@ -33,7 +33,7 @@ static void window_tree_key(struct window_mode_entry *,
struct client *, struct session *,
struct winlink *, key_code, struct mouse_event *);
#define WINDOW_TREE_DEFAULT_COMMAND "switch-client -t '%%'"
#define WINDOW_TREE_DEFAULT_COMMAND "switch-client -Zt '%%'"
#define WINDOW_TREE_DEFAULT_FORMAT \
"#{?pane_format," \