mirror of
https://github.com/tmux/tmux.git
synced 2024-12-13 18:38:48 +00:00
Merge branch 'master' into 3.2-rc
This commit is contained in:
commit
ba9962b568
11
.github/README.md
vendored
11
.github/README.md
vendored
@ -19,6 +19,12 @@ suitable yacc (yacc or bison) are needed.
|
||||
|
||||
## Installation
|
||||
|
||||
### Binary packages
|
||||
|
||||
Some platforms provide binary packages for tmux, although these are sometimes
|
||||
out of date. Examples are listed on
|
||||
[this page](https://github.com/tmux/tmux/wiki/Installing).
|
||||
|
||||
### From release tarball
|
||||
|
||||
To build and install tmux from a release tarball, use:
|
||||
@ -31,6 +37,9 @@ sudo make install
|
||||
tmux can use the utempter library to update utmp(5), if it is installed - run
|
||||
configure with `--enable-utempter` to enable this.
|
||||
|
||||
For more detailed instructions on building and installing tmux, see
|
||||
[this page](https://github.com/tmux/tmux/wiki/Installing).
|
||||
|
||||
### From version control
|
||||
|
||||
To get and build the latest from version control - note that this requires
|
||||
@ -72,7 +81,7 @@ And a bash(1) completion file at:
|
||||
|
||||
https://github.com/imomaliev/tmux-bash-completion
|
||||
|
||||
For debugging, run tmux with `-v` or `-vv` to generate server and client log
|
||||
For debugging, run tmux with `-v` or `-vv` to generate server and client log
|
||||
files in the current directory.
|
||||
|
||||
## Support
|
||||
|
36
CHANGES
36
CHANGES
@ -1,4 +1,33 @@
|
||||
CHANGES FROM 3.1b TO 3.2
|
||||
CHANGES FROM 3.2 TO 3.3
|
||||
|
||||
* Fire focus events even when the pane is in a mode.
|
||||
|
||||
* Add -O flag to display-menu to not automatically close when all mouse buttons
|
||||
are released.
|
||||
|
||||
* Allow fnmatch(3) wildcards in update-environment.
|
||||
|
||||
* Disable nested job expansion so that the result of #() is not expanded again.
|
||||
|
||||
* Use the setal capability as well as (tmux's) Setulc.
|
||||
|
||||
* Add -q flag to unbind-key to hide errors.
|
||||
|
||||
* Allow -N without a command to change or add a note to an existing key.
|
||||
|
||||
* Add a -w flag to set- and load-buffer to send to clipboard using OSC 52.
|
||||
|
||||
* Add -F to set-environment and source-file.
|
||||
|
||||
* Allow colour to be spelt as color in various places.
|
||||
|
||||
* Add n: modifier to get length of a format.
|
||||
|
||||
* Respond to OSC colour requests if a colour is available.
|
||||
|
||||
* Add a -d option to display-message to set delay.
|
||||
|
||||
CHANGES FROM 3.1c TO 3.2
|
||||
|
||||
* Add a way for control mode clients to subscribe to a format and be notified
|
||||
of changes rather than having to poll.
|
||||
@ -265,6 +294,11 @@ CHANGES FROM 3.1b TO 3.2
|
||||
|
||||
* Add number operators for formats (+, -, *, / and m),
|
||||
|
||||
CHANGED FROM 3.1b TO 3.1c
|
||||
|
||||
* Do not write after the end of the array and overwrite the stack when
|
||||
colon-separated SGR sequences contain empty arguments.
|
||||
|
||||
CHANGES FROM 3.1a TO 3.1b
|
||||
|
||||
* Fix build on systems without sys/queue.h.
|
||||
|
10
alerts.c
10
alerts.c
@ -200,7 +200,7 @@ alerts_check_bell(struct window *w)
|
||||
* not check WINLINK_BELL).
|
||||
*/
|
||||
s = wl->session;
|
||||
if (s->curw != wl) {
|
||||
if (s->curw != wl || s->attached == 0) {
|
||||
wl->flags |= WINLINK_BELL;
|
||||
server_status_session(s);
|
||||
}
|
||||
@ -236,7 +236,7 @@ alerts_check_activity(struct window *w)
|
||||
if (wl->flags & WINLINK_ACTIVITY)
|
||||
continue;
|
||||
s = wl->session;
|
||||
if (s->curw != wl) {
|
||||
if (s->curw != wl || s->attached == 0) {
|
||||
wl->flags |= WINLINK_ACTIVITY;
|
||||
server_status_session(s);
|
||||
}
|
||||
@ -272,7 +272,7 @@ alerts_check_silence(struct window *w)
|
||||
if (wl->flags & WINLINK_SILENCE)
|
||||
continue;
|
||||
s = wl->session;
|
||||
if (s->curw != wl) {
|
||||
if (s->curw != wl || s->attached == 0) {
|
||||
wl->flags |= WINLINK_SILENCE;
|
||||
server_status_session(s);
|
||||
}
|
||||
@ -316,9 +316,9 @@ alerts_set_message(struct winlink *wl, const char *type, const char *option)
|
||||
if (visual == VISUAL_OFF)
|
||||
continue;
|
||||
if (c->session->curw == wl)
|
||||
status_message_set(c, 1, "%s in current window", type);
|
||||
status_message_set(c, -1, 1, "%s in current window", type);
|
||||
else {
|
||||
status_message_set(c, 1, "%s in window %d", type,
|
||||
status_message_set(c, -1, 1, "%s in window %d", type,
|
||||
wl->idx);
|
||||
}
|
||||
}
|
||||
|
27
client.c
27
client.c
@ -36,6 +36,7 @@
|
||||
static struct tmuxproc *client_proc;
|
||||
static struct tmuxpeer *client_peer;
|
||||
static uint64_t client_flags;
|
||||
static int client_suspended;
|
||||
static enum {
|
||||
CLIENT_EXIT_NONE,
|
||||
CLIENT_EXIT_DETACHED,
|
||||
@ -59,7 +60,8 @@ static struct client_files client_files = RB_INITIALIZER(&client_files);
|
||||
|
||||
static __dead void client_exec(const char *,const char *);
|
||||
static int client_get_lock(char *);
|
||||
static int client_connect(struct event_base *, const char *, int);
|
||||
static int client_connect(struct event_base *, const char *,
|
||||
uint64_t);
|
||||
static void client_send_identify(const char *, const char *, int);
|
||||
static void client_signal(int);
|
||||
static void client_dispatch(struct imsg *, void *);
|
||||
@ -100,7 +102,7 @@ client_get_lock(char *lockfile)
|
||||
|
||||
/* Connect client to server. */
|
||||
static int
|
||||
client_connect(struct event_base *base, const char *path, int flags)
|
||||
client_connect(struct event_base *base, const char *path, uint64_t flags)
|
||||
{
|
||||
struct sockaddr_un sa;
|
||||
size_t size;
|
||||
@ -220,7 +222,7 @@ static void
|
||||
client_exit(void)
|
||||
{
|
||||
struct client_file *cf;
|
||||
size_t left;
|
||||
size_t left;
|
||||
int waiting = 0;
|
||||
|
||||
RB_FOREACH (cf, client_files, &client_files) {
|
||||
@ -238,7 +240,8 @@ client_exit(void)
|
||||
|
||||
/* Client main loop. */
|
||||
int
|
||||
client_main(struct event_base *base, int argc, char **argv, int flags, int feat)
|
||||
client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
|
||||
int feat)
|
||||
{
|
||||
struct cmd_parse_result *pr;
|
||||
struct msg_command *data;
|
||||
@ -284,7 +287,7 @@ client_main(struct event_base *base, int argc, char **argv, int flags, int feat)
|
||||
|
||||
/* Save the flags. */
|
||||
client_flags = flags;
|
||||
log_debug("flags are %#llx", client_flags);
|
||||
log_debug("flags are %#llx", (unsigned long long)client_flags);
|
||||
|
||||
/* Initialize the client socket and start the server. */
|
||||
fd = client_connect(base, socket_path, client_flags);
|
||||
@ -442,6 +445,8 @@ client_send_identify(const char *ttynam, const char *cwd, int feat)
|
||||
pid_t pid;
|
||||
|
||||
proc_send(client_peer, MSG_IDENTIFY_FLAGS, -1, &flags, sizeof flags);
|
||||
proc_send(client_peer, MSG_IDENTIFY_LONGFLAGS, -1, &client_flags,
|
||||
sizeof client_flags);
|
||||
|
||||
if ((s = getenv("TERM")) == NULL)
|
||||
s = "";
|
||||
@ -761,6 +766,7 @@ client_signal(int sig)
|
||||
struct sigaction sigact;
|
||||
int status;
|
||||
|
||||
log_debug("%s: %s", __func__, strsignal(sig));
|
||||
if (sig == SIGCHLD)
|
||||
waitpid(WAIT_ANY, &status, WNOHANG);
|
||||
else if (!client_attached) {
|
||||
@ -774,7 +780,8 @@ client_signal(int sig)
|
||||
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
|
||||
break;
|
||||
case SIGTERM:
|
||||
client_exitreason = CLIENT_EXIT_TERMINATED;
|
||||
if (!client_suspended)
|
||||
client_exitreason = CLIENT_EXIT_TERMINATED;
|
||||
client_exitval = 1;
|
||||
proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
|
||||
break;
|
||||
@ -789,6 +796,7 @@ client_signal(int sig)
|
||||
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
proc_send(client_peer, MSG_WAKEUP, -1, NULL, 0);
|
||||
client_suspended = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -891,7 +899,8 @@ client_dispatch_wait(struct imsg *imsg)
|
||||
fatalx("bad MSG_FLAGS string");
|
||||
|
||||
memcpy(&client_flags, data, sizeof client_flags);
|
||||
log_debug("new flags are %#llx", client_flags);
|
||||
log_debug("new flags are %#llx",
|
||||
(unsigned long long)client_flags);
|
||||
break;
|
||||
case MSG_SHELL:
|
||||
if (datalen == 0 || data[datalen - 1] != '\0')
|
||||
@ -944,7 +953,8 @@ client_dispatch_attached(struct imsg *imsg)
|
||||
fatalx("bad MSG_FLAGS string");
|
||||
|
||||
memcpy(&client_flags, data, sizeof client_flags);
|
||||
log_debug("new flags are %#llx", client_flags);
|
||||
log_debug("new flags are %#llx",
|
||||
(unsigned long long)client_flags);
|
||||
break;
|
||||
case MSG_DETACH:
|
||||
case MSG_DETACHKILL:
|
||||
@ -999,6 +1009,7 @@ client_dispatch_attached(struct imsg *imsg)
|
||||
sigact.sa_handler = SIG_DFL;
|
||||
if (sigaction(SIGTSTP, &sigact, NULL) != 0)
|
||||
fatal("sigaction failed");
|
||||
client_suspended = 1;
|
||||
kill(getpid(), SIGTSTP);
|
||||
break;
|
||||
case MSG_LOCK:
|
||||
|
@ -59,7 +59,7 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
|
||||
struct session *s;
|
||||
struct winlink *wl;
|
||||
struct window_pane *wp;
|
||||
char *cause;
|
||||
char *cwd, *cause;
|
||||
enum msgtype msgtype;
|
||||
|
||||
if (RB_EMPTY(&sessions)) {
|
||||
@ -99,8 +99,9 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
|
||||
}
|
||||
|
||||
if (cflag != NULL) {
|
||||
cwd = format_single(item, cflag, c, s, wl, wp);
|
||||
free((void *)s->cwd);
|
||||
s->cwd = format_single(item, cflag, c, s, wl, wp);
|
||||
s->cwd = cwd;
|
||||
}
|
||||
if (fflag)
|
||||
server_client_set_flags(c, fflag);
|
||||
|
@ -33,9 +33,9 @@ const struct cmd_entry cmd_bind_key_entry = {
|
||||
.name = "bind-key",
|
||||
.alias = "bind",
|
||||
|
||||
.args = { "nrN:T:", 2, -1 },
|
||||
.args = { "nrN:T:", 1, -1 },
|
||||
.usage = "[-nr] [-T key-table] [-N note] key "
|
||||
"command [arguments]",
|
||||
"[command [arguments]]",
|
||||
|
||||
.flags = CMD_AFTERHOOK,
|
||||
.exec = cmd_bind_key_exec
|
||||
@ -46,7 +46,7 @@ cmd_bind_key_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = cmd_get_args(self);
|
||||
key_code key;
|
||||
const char *tablename, *note;
|
||||
const char *tablename, *note = args_get(args, 'N');
|
||||
struct cmd_parse_result *pr;
|
||||
char **argv = args->argv;
|
||||
int argc = args->argc, repeat;
|
||||
@ -65,22 +65,24 @@ cmd_bind_key_exec(struct cmd *self, struct cmdq_item *item)
|
||||
tablename = "prefix";
|
||||
repeat = args_has(args, 'r');
|
||||
|
||||
if (argc == 2)
|
||||
pr = cmd_parse_from_string(argv[1], NULL);
|
||||
else
|
||||
pr = cmd_parse_from_arguments(argc - 1, argv + 1, NULL);
|
||||
switch (pr->status) {
|
||||
case CMD_PARSE_EMPTY:
|
||||
cmdq_error(item, "empty command");
|
||||
return (CMD_RETURN_ERROR);
|
||||
case CMD_PARSE_ERROR:
|
||||
cmdq_error(item, "%s", pr->error);
|
||||
free(pr->error);
|
||||
return (CMD_RETURN_ERROR);
|
||||
case CMD_PARSE_SUCCESS:
|
||||
break;
|
||||
}
|
||||
note = args_get(args, 'N');
|
||||
key_bindings_add(tablename, key, note, repeat, pr->cmdlist);
|
||||
if (argc != 1) {
|
||||
if (argc == 2)
|
||||
pr = cmd_parse_from_string(argv[1], NULL);
|
||||
else
|
||||
pr = cmd_parse_from_arguments(argc - 1, argv + 1, NULL);
|
||||
switch (pr->status) {
|
||||
case CMD_PARSE_EMPTY:
|
||||
cmdq_error(item, "empty command");
|
||||
return (CMD_RETURN_ERROR);
|
||||
case CMD_PARSE_ERROR:
|
||||
cmdq_error(item, "%s", pr->error);
|
||||
free(pr->error);
|
||||
return (CMD_RETURN_ERROR);
|
||||
case CMD_PARSE_SUCCESS:
|
||||
break;
|
||||
}
|
||||
key_bindings_add(tablename, key, note, repeat, pr->cmdlist);
|
||||
} else
|
||||
key_bindings_add(tablename, key, note, repeat, NULL);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
@ -36,8 +36,8 @@ const struct cmd_entry cmd_display_menu_entry = {
|
||||
.name = "display-menu",
|
||||
.alias = "menu",
|
||||
|
||||
.args = { "c:t:T:x:y:", 1, -1 },
|
||||
.usage = "[-c target-client] " CMD_TARGET_PANE_USAGE " [-T title] "
|
||||
.args = { "c:t:OT:x:y:", 1, -1 },
|
||||
.usage = "[-O] [-c target-client] " CMD_TARGET_PANE_USAGE " [-T title] "
|
||||
"[-x position] [-y position] name key command ...",
|
||||
|
||||
.target = { 't', CMD_FIND_PANE, 0 },
|
||||
@ -229,6 +229,8 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
|
||||
cmd_display_menu_get_position(tc, item, args, &px, &py, menu->width + 4,
|
||||
menu->count + 2);
|
||||
|
||||
if (args_has(args, 'O'))
|
||||
flags |= MENU_STAYOPEN;
|
||||
if (!event->m.valid)
|
||||
flags |= MENU_NOMOUSE;
|
||||
if (menu_display(menu, flags, item, px, py, tc, target, NULL,
|
||||
|
@ -39,8 +39,8 @@ const struct cmd_entry cmd_display_message_entry = {
|
||||
.name = "display-message",
|
||||
.alias = "display",
|
||||
|
||||
.args = { "ac:Ipt:F:v", 0, 1 },
|
||||
.usage = "[-aIpv] [-c target-client] [-F format] "
|
||||
.args = { "acd:Ipt:F:v", 0, 1 },
|
||||
.usage = "[-aIpv] [-c target-client] [-d delay] [-F format] "
|
||||
CMD_TARGET_PANE_USAGE " [message]",
|
||||
|
||||
.target = { 't', CMD_FIND_PANE, 0 },
|
||||
@ -68,6 +68,7 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct window_pane *wp = target->wp;
|
||||
const char *template;
|
||||
char *msg, *cause;
|
||||
int delay = -1;
|
||||
struct format_tree *ft;
|
||||
int flags;
|
||||
|
||||
@ -85,6 +86,15 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
if (args_has(args, 'd')) {
|
||||
delay = args_strtonum(args, 'd', 0, UINT_MAX, &cause);
|
||||
if (cause != NULL) {
|
||||
cmdq_error(item, "delay %s", cause);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
template = args_get(args, 'F');
|
||||
if (args->argc != 0)
|
||||
template = args->argv[0];
|
||||
@ -117,7 +127,7 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (args_has(args, 'p'))
|
||||
cmdq_print(item, "%s", msg);
|
||||
else if (tc != NULL)
|
||||
status_message_set(tc, 0, "%s", msg);
|
||||
status_message_set(tc, delay, 0, "%s", msg);
|
||||
free(msg);
|
||||
|
||||
format_free(ft);
|
||||
|
@ -55,11 +55,11 @@ cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
|
||||
struct session *s = c->session;
|
||||
struct options *oo = s->options;
|
||||
struct window *w = wp->window;
|
||||
struct grid_cell gc;
|
||||
u_int idx, px, py, i, j, xoff, yoff, sx, sy;
|
||||
struct grid_cell fgc, bgc;
|
||||
u_int pane, idx, px, py, i, j, xoff, yoff, sx, sy;
|
||||
int colour, active_colour;
|
||||
char buf[16], *ptr;
|
||||
size_t len;
|
||||
char buf[16], lbuf[16], rbuf[16], *ptr;
|
||||
size_t len, llen, rlen;
|
||||
|
||||
if (wp->xoff + wp->sx <= ctx->ox ||
|
||||
wp->xoff >= ctx->ox + ctx->sx ||
|
||||
@ -109,29 +109,50 @@ cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
|
||||
px = sx / 2;
|
||||
py = sy / 2;
|
||||
|
||||
if (window_pane_index(wp, &idx) != 0)
|
||||
if (window_pane_index(wp, &pane) != 0)
|
||||
fatalx("index not found");
|
||||
len = xsnprintf(buf, sizeof buf, "%u", idx);
|
||||
len = xsnprintf(buf, sizeof buf, "%u", pane);
|
||||
|
||||
if (sx < len)
|
||||
return;
|
||||
colour = options_get_number(oo, "display-panes-colour");
|
||||
active_colour = options_get_number(oo, "display-panes-active-colour");
|
||||
|
||||
memcpy(&fgc, &grid_default_cell, sizeof fgc);
|
||||
memcpy(&bgc, &grid_default_cell, sizeof bgc);
|
||||
if (w->active == wp) {
|
||||
fgc.fg = active_colour;
|
||||
bgc.bg = active_colour;
|
||||
} else {
|
||||
fgc.fg = colour;
|
||||
bgc.bg = colour;
|
||||
}
|
||||
|
||||
rlen = xsnprintf(rbuf, sizeof rbuf, "%ux%u", wp->sx, wp->sy);
|
||||
if (pane > 9 && pane < 35)
|
||||
llen = xsnprintf(lbuf, sizeof lbuf, "%c", 'a' + (pane - 10));
|
||||
else
|
||||
llen = 0;
|
||||
|
||||
if (sx < len * 6 || sy < 5) {
|
||||
tty_cursor(tty, xoff + px - len / 2, yoff + py);
|
||||
goto draw_text;
|
||||
tty_attributes(tty, &fgc, &grid_default_cell, NULL);
|
||||
if (sx >= len + llen + 1) {
|
||||
len += llen + 1;
|
||||
tty_cursor(tty, xoff + px - len / 2, yoff + py);
|
||||
tty_putn(tty, buf, len, len);
|
||||
tty_putn(tty, " ", 1, 1);
|
||||
tty_putn(tty, lbuf, llen, llen);
|
||||
} else {
|
||||
tty_cursor(tty, xoff + px - len / 2, yoff + py);
|
||||
tty_putn(tty, buf, len, len);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
px -= len * 3;
|
||||
py -= 2;
|
||||
|
||||
memcpy(&gc, &grid_default_cell, sizeof gc);
|
||||
if (w->active == wp)
|
||||
gc.bg = active_colour;
|
||||
else
|
||||
gc.bg = colour;
|
||||
tty_attributes(tty, &gc, &grid_default_cell, NULL);
|
||||
tty_attributes(tty, &bgc, &grid_default_cell, NULL);
|
||||
for (ptr = buf; *ptr != '\0'; ptr++) {
|
||||
if (*ptr < '0' || *ptr > '9')
|
||||
continue;
|
||||
@ -147,20 +168,20 @@ cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
|
||||
px += 6;
|
||||
}
|
||||
|
||||
len = xsnprintf(buf, sizeof buf, "%ux%u", wp->sx, wp->sy);
|
||||
if (sx < len || sy < 6)
|
||||
return;
|
||||
tty_cursor(tty, xoff + sx - len, yoff);
|
||||
|
||||
draw_text:
|
||||
memcpy(&gc, &grid_default_cell, sizeof gc);
|
||||
if (w->active == wp)
|
||||
gc.fg = active_colour;
|
||||
else
|
||||
gc.fg = colour;
|
||||
tty_attributes(tty, &gc, &grid_default_cell, NULL);
|
||||
tty_puts(tty, buf);
|
||||
if (sy <= 6)
|
||||
goto out;
|
||||
tty_attributes(tty, &fgc, &grid_default_cell, NULL);
|
||||
if (rlen != 0 && sx >= rlen) {
|
||||
tty_cursor(tty, xoff + sx - rlen, yoff);
|
||||
tty_putn(tty, rbuf, rlen, rlen);
|
||||
}
|
||||
if (llen != 0) {
|
||||
tty_cursor(tty, xoff + sx / 2 + len * 3 - llen - 1,
|
||||
yoff + py + 5);
|
||||
tty_putn(tty, lbuf, llen, llen);
|
||||
}
|
||||
|
||||
out:
|
||||
tty_cursor(tty, 0, 0);
|
||||
}
|
||||
|
||||
@ -197,11 +218,21 @@ cmd_display_panes_key(struct client *c, struct key_event *event)
|
||||
struct window *w = c->session->curw->window;
|
||||
struct window_pane *wp;
|
||||
enum cmd_parse_status status;
|
||||
u_int index;
|
||||
key_code key;
|
||||
|
||||
if (event->key < '0' || event->key > '9')
|
||||
if (event->key >= '0' && event->key <= '9')
|
||||
index = event->key - '0';
|
||||
else if ((event->key & KEYC_MASK_MODIFIERS) == 0) {
|
||||
key = (event->key & KEYC_MASK_KEY);
|
||||
if (key >= 'a' && key <= 'z')
|
||||
index = 10 + (key - 'a');
|
||||
else
|
||||
return (-1);
|
||||
} else
|
||||
return (-1);
|
||||
|
||||
wp = window_pane_at_index(w, event->key - '0');
|
||||
wp = window_pane_at_index(w, index);
|
||||
if (wp == NULL)
|
||||
return (1);
|
||||
window_unzoom(w);
|
||||
|
@ -114,7 +114,7 @@ cmd_list_keys_print_notes(struct cmdq_item *item, struct args *args,
|
||||
note = xstrdup(bd->note);
|
||||
tmp = utf8_padcstr(key, keywidth + 1);
|
||||
if (args_has(args, '1') && tc != NULL)
|
||||
status_message_set(tc, 1, "%s%s%s", prefix, tmp, note);
|
||||
status_message_set(tc, -1, 1, "%s%s%s", prefix, tmp, note);
|
||||
else
|
||||
cmdq_print(item, "%s%s%s", prefix, tmp, note);
|
||||
free(tmp);
|
||||
|
@ -37,14 +37,15 @@ const struct cmd_entry cmd_load_buffer_entry = {
|
||||
.name = "load-buffer",
|
||||
.alias = "loadb",
|
||||
|
||||
.args = { "b:", 1, 1 },
|
||||
.usage = CMD_BUFFER_USAGE " path",
|
||||
.args = { "b:t:w", 1, 1 },
|
||||
.usage = CMD_BUFFER_USAGE " " CMD_TARGET_CLIENT_USAGE " path",
|
||||
|
||||
.flags = CMD_AFTERHOOK,
|
||||
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG|CMD_CLIENT_CANFAIL,
|
||||
.exec = cmd_load_buffer_exec
|
||||
};
|
||||
|
||||
struct cmd_load_buffer_data {
|
||||
struct client *client;
|
||||
struct cmdq_item *item;
|
||||
char *name;
|
||||
};
|
||||
@ -54,6 +55,7 @@ cmd_load_buffer_done(__unused struct client *c, const char *path, int error,
|
||||
int closed, struct evbuffer *buffer, void *data)
|
||||
{
|
||||
struct cmd_load_buffer_data *cdata = data;
|
||||
struct client *tc = cdata->client;
|
||||
struct cmdq_item *item = cdata->item;
|
||||
void *bdata = EVBUFFER_DATA(buffer);
|
||||
size_t bsize = EVBUFFER_LENGTH(buffer);
|
||||
@ -72,7 +74,12 @@ cmd_load_buffer_done(__unused struct client *c, const char *path, int error,
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(cause);
|
||||
free(copy);
|
||||
}
|
||||
} else if (tc != NULL &&
|
||||
tc->session != NULL &&
|
||||
(~tc->flags & CLIENT_DEAD))
|
||||
tty_set_selection(&tc->tty, copy, bsize);
|
||||
if (tc != NULL)
|
||||
server_client_unref(tc);
|
||||
}
|
||||
cmdq_continue(item);
|
||||
|
||||
@ -84,16 +91,19 @@ static enum cmd_retval
|
||||
cmd_load_buffer_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct client *tc = cmdq_get_target_client(item);
|
||||
struct cmd_load_buffer_data *cdata;
|
||||
const char *bufname = args_get(args, 'b');
|
||||
char *path;
|
||||
|
||||
cdata = xmalloc(sizeof *cdata);
|
||||
cdata = xcalloc(1, sizeof *cdata);
|
||||
cdata->item = item;
|
||||
if (bufname != NULL)
|
||||
cdata->name = xstrdup(bufname);
|
||||
else
|
||||
cdata->name = NULL;
|
||||
if (args_has(args, 'w') && tc != NULL) {
|
||||
cdata->client = tc;
|
||||
cdata->client->references++;
|
||||
}
|
||||
|
||||
path = format_single_from_target(item, args->argv[0]);
|
||||
file_read(cmdq_get_client(item), path, cmd_load_buffer_done, cdata);
|
||||
|
@ -858,7 +858,7 @@ cmdq_error(struct cmdq_item *item, const char *fmt, ...)
|
||||
c->retval = 1;
|
||||
} else {
|
||||
*msg = toupper((u_char) *msg);
|
||||
status_message_set(c, 1, "%s", msg);
|
||||
status_message_set(c, -1, 1, "%s", msg);
|
||||
}
|
||||
|
||||
free(msg);
|
||||
|
@ -198,6 +198,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (args_has(args, 'T')) {
|
||||
title = format_single_from_target(item, args_get(args, 'T'));
|
||||
if (screen_set_title(&wp->base, title)) {
|
||||
notify_pane("pane-title-changed", wp);
|
||||
server_redraw_window_borders(wp->window);
|
||||
server_status_window(wp->window);
|
||||
}
|
||||
|
@ -33,10 +33,11 @@ const struct cmd_entry cmd_set_buffer_entry = {
|
||||
.name = "set-buffer",
|
||||
.alias = "setb",
|
||||
|
||||
.args = { "ab:n:", 0, 1 },
|
||||
.usage = "[-a] " CMD_BUFFER_USAGE " [-n new-buffer-name] data",
|
||||
.args = { "ab:t:n:w", 0, 1 },
|
||||
.usage = "[-aw] " CMD_BUFFER_USAGE " [-n new-buffer-name] "
|
||||
CMD_TARGET_CLIENT_USAGE " data",
|
||||
|
||||
.flags = CMD_AFTERHOOK,
|
||||
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG|CMD_CLIENT_CANFAIL,
|
||||
.exec = cmd_set_buffer_exec
|
||||
};
|
||||
|
||||
@ -55,6 +56,7 @@ static enum cmd_retval
|
||||
cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct client *tc = cmdq_get_target_client(item);
|
||||
struct paste_buffer *pb;
|
||||
char *bufdata, *cause;
|
||||
const char *bufname, *olddata;
|
||||
@ -118,6 +120,8 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
if (args_has(args, 'w') && tc != NULL)
|
||||
tty_set_selection(&tc->tty, bufdata, bufsize);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
@ -34,8 +34,8 @@ const struct cmd_entry cmd_set_environment_entry = {
|
||||
.name = "set-environment",
|
||||
.alias = "setenv",
|
||||
|
||||
.args = { "hgrt:u", 1, 2 },
|
||||
.usage = "[-hgru] " CMD_TARGET_SESSION_USAGE " name [value]",
|
||||
.args = { "Fhgrt:u", 1, 2 },
|
||||
.usage = "[-Fhgru] " CMD_TARGET_SESSION_USAGE " name [value]",
|
||||
|
||||
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
|
||||
|
||||
@ -50,6 +50,8 @@ cmd_set_environment_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
struct environ *env;
|
||||
const char *name, *value, *tflag;
|
||||
char *expand = NULL;
|
||||
enum cmd_retval retval = CMD_RETURN_NORMAL;
|
||||
|
||||
name = args->argv[0];
|
||||
if (*name == '\0') {
|
||||
@ -63,6 +65,8 @@ cmd_set_environment_exec(struct cmd *self, struct cmdq_item *item)
|
||||
|
||||
if (args->argc < 2)
|
||||
value = NULL;
|
||||
else if (args_has(args, 'F'))
|
||||
value = expand = format_single_from_target(item, args->argv[1]);
|
||||
else
|
||||
value = args->argv[1];
|
||||
|
||||
@ -75,7 +79,8 @@ cmd_set_environment_exec(struct cmd *self, struct cmdq_item *item)
|
||||
cmdq_error(item, "no such session: %s", tflag);
|
||||
else
|
||||
cmdq_error(item, "no current session");
|
||||
return (CMD_RETURN_ERROR);
|
||||
retval = CMD_RETURN_ERROR;
|
||||
goto out;
|
||||
}
|
||||
env = target->s->environ;
|
||||
}
|
||||
@ -83,25 +88,31 @@ cmd_set_environment_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (args_has(args, 'u')) {
|
||||
if (value != NULL) {
|
||||
cmdq_error(item, "can't specify a value with -u");
|
||||
return (CMD_RETURN_ERROR);
|
||||
retval = CMD_RETURN_ERROR;
|
||||
goto out;
|
||||
}
|
||||
environ_unset(env, name);
|
||||
} else if (args_has(args, 'r')) {
|
||||
if (value != NULL) {
|
||||
cmdq_error(item, "can't specify a value with -r");
|
||||
return (CMD_RETURN_ERROR);
|
||||
retval = CMD_RETURN_ERROR;
|
||||
goto out;
|
||||
}
|
||||
environ_clear(env, name);
|
||||
} else {
|
||||
if (value == NULL) {
|
||||
cmdq_error(item, "no value specified");
|
||||
return (CMD_RETURN_ERROR);
|
||||
retval = CMD_RETURN_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (args_has(args, 'h'))
|
||||
environ_set(env, name, ENVIRON_HIDDEN, "%s", value);
|
||||
else
|
||||
environ_set(env, name, 0, "%s", value);
|
||||
}
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
out:
|
||||
free(expand);
|
||||
return (retval);
|
||||
}
|
||||
|
@ -35,8 +35,8 @@ const struct cmd_entry cmd_source_file_entry = {
|
||||
.name = "source-file",
|
||||
.alias = "source",
|
||||
|
||||
.args = { "nqv", 1, -1 },
|
||||
.usage = "[-nqv] path ...",
|
||||
.args = { "Fnqv", 1, -1 },
|
||||
.usage = "[-Fnqv] path ...",
|
||||
|
||||
.flags = 0,
|
||||
.exec = cmd_source_file_exec
|
||||
@ -126,7 +126,7 @@ cmd_source_file_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct cmd_source_file_data *cdata;
|
||||
struct client *c = cmdq_get_client(item);
|
||||
enum cmd_retval retval = CMD_RETURN_NORMAL;
|
||||
char *pattern, *cwd;
|
||||
char *pattern, *cwd, *expand = NULL;
|
||||
const char *path, *error;
|
||||
glob_t g;
|
||||
int i, result;
|
||||
@ -145,7 +145,12 @@ cmd_source_file_exec(struct cmd *self, struct cmdq_item *item)
|
||||
utf8_stravis(&cwd, server_client_get_cwd(c, NULL), VIS_GLOB);
|
||||
|
||||
for (i = 0; i < args->argc; i++) {
|
||||
path = args->argv[i];
|
||||
if (args_has(args, 'F')) {
|
||||
free(expand);
|
||||
expand = format_single_from_target(item, args->argv[i]);
|
||||
path = expand;
|
||||
} else
|
||||
path = args->argv[i];
|
||||
if (strcmp(path, "-") == 0) {
|
||||
cmd_source_file_add(cdata, "-");
|
||||
continue;
|
||||
@ -172,6 +177,7 @@ cmd_source_file_exec(struct cmd *self, struct cmdq_item *item)
|
||||
free(pattern);
|
||||
continue;
|
||||
}
|
||||
free(expand);
|
||||
free(pattern);
|
||||
|
||||
for (j = 0; j < g.gl_pathc; j++)
|
||||
|
@ -32,8 +32,8 @@ const struct cmd_entry cmd_unbind_key_entry = {
|
||||
.name = "unbind-key",
|
||||
.alias = "unbind",
|
||||
|
||||
.args = { "anT:", 0, 1 },
|
||||
.usage = "[-an] [-T key-table] key",
|
||||
.args = { "anqT:", 0, 1 },
|
||||
.usage = "[-anq] [-T key-table] key",
|
||||
|
||||
.flags = CMD_AFTERHOOK,
|
||||
.exec = cmd_unbind_key_exec
|
||||
@ -45,44 +45,54 @@ cmd_unbind_key_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct args *args = cmd_get_args(self);
|
||||
key_code key;
|
||||
const char *tablename;
|
||||
int quiet = args_has(args, 'q');
|
||||
|
||||
if (!args_has(args, 'a')) {
|
||||
if (args->argc != 1) {
|
||||
cmdq_error(item, "missing key");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
key = key_string_lookup_string(args->argv[0]);
|
||||
if (key == KEYC_NONE || key == KEYC_UNKNOWN) {
|
||||
cmdq_error(item, "unknown key: %s", args->argv[0]);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
} else {
|
||||
if (args_has(args, 'a')) {
|
||||
if (args->argc != 0) {
|
||||
cmdq_error(item, "key given with -a");
|
||||
if (!quiet)
|
||||
cmdq_error(item, "key given with -a");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
key = KEYC_UNKNOWN;
|
||||
}
|
||||
|
||||
if (key == KEYC_UNKNOWN) {
|
||||
tablename = args_get(args, 'T');
|
||||
if (tablename == NULL) {
|
||||
key_bindings_remove_table("root");
|
||||
key_bindings_remove_table("prefix");
|
||||
return (CMD_RETURN_NORMAL);
|
||||
if (args_has(args, 'n'))
|
||||
tablename = "root";
|
||||
else
|
||||
tablename = "prefix";
|
||||
}
|
||||
if (key_bindings_get_table(tablename, 0) == NULL) {
|
||||
cmdq_error(item, "table %s doesn't exist", tablename);
|
||||
if (!quiet) {
|
||||
cmdq_error(item, "table %s doesn't exist" ,
|
||||
tablename);
|
||||
}
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
key_bindings_remove_table(tablename);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
if (args->argc != 1) {
|
||||
if (!quiet)
|
||||
cmdq_error(item, "missing key");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
key = key_string_lookup_string(args->argv[0]);
|
||||
if (key == KEYC_NONE || key == KEYC_UNKNOWN) {
|
||||
if (!quiet)
|
||||
cmdq_error(item, "unknown key: %s", args->argv[0]);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
if (args_has(args, 'T')) {
|
||||
tablename = args_get(args, 'T');
|
||||
if (key_bindings_get_table(tablename, 0) == NULL) {
|
||||
cmdq_error(item, "table %s doesn't exist", tablename);
|
||||
if (!quiet) {
|
||||
cmdq_error(item, "table %s doesn't exist" ,
|
||||
tablename);
|
||||
}
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
} else if (args_has(args, 'n'))
|
||||
|
6
colour.c
6
colour.c
@ -189,6 +189,12 @@ colour_fromstring(const char *s)
|
||||
return (-1);
|
||||
return (n | COLOUR_FLAG_256);
|
||||
}
|
||||
if (strncasecmp(s, "color", (sizeof "color") - 1) == 0) {
|
||||
n = strtonum(s + (sizeof "color") - 1, 0, 255, &errstr);
|
||||
if (errstr != NULL)
|
||||
return (-1);
|
||||
return (n | COLOUR_FLAG_256);
|
||||
}
|
||||
|
||||
if (strcasecmp(s, "default") == 0)
|
||||
return (8);
|
||||
|
8
compat.h
8
compat.h
@ -27,6 +27,10 @@
|
||||
#include <termios.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#ifdef HAVE_MALLOC_TRIM
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UTF8PROC
|
||||
#include <utf8proc.h>
|
||||
#endif
|
||||
@ -35,6 +39,10 @@
|
||||
#define __attribute__(a)
|
||||
#endif
|
||||
|
||||
#ifdef BROKEN___DEAD
|
||||
#undef __dead
|
||||
#endif
|
||||
|
||||
#ifndef __unused
|
||||
#define __unused __attribute__ ((__unused__))
|
||||
#endif
|
||||
|
29
compat/getdtablesize.c
Normal file
29
compat/getdtablesize.c
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
#ifdef HAVE_SYSCONF
|
||||
int
|
||||
getdtablesize(void)
|
||||
{
|
||||
return (sysconf(_SC_OPEN_MAX));
|
||||
}
|
||||
#endif
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: imsg-buffer.c,v 1.11 2017/12/14 09:27:44 kettenis Exp $ */
|
||||
/* $OpenBSD: imsg-buffer.c,v 1.12 2019/01/20 02:50:03 bcook Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
|
||||
@ -70,7 +70,7 @@ ibuf_dynamic(size_t len, size_t max)
|
||||
static int
|
||||
ibuf_realloc(struct ibuf *buf, size_t len)
|
||||
{
|
||||
u_char *b;
|
||||
unsigned char *b;
|
||||
|
||||
/* on static buffers max is eq size and so the following fails */
|
||||
if (buf->wpos + len > buf->max) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: imsg.h,v 1.4 2017/03/24 09:34:12 nicm Exp $ */
|
||||
/* $OpenBSD: imsg.h,v 1.5 2019/01/20 02:50:03 bcook Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org>
|
||||
@ -21,13 +21,15 @@
|
||||
#ifndef _IMSG_H_
|
||||
#define _IMSG_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define IBUF_READ_SIZE 65535
|
||||
#define IMSG_HEADER_SIZE sizeof(struct imsg_hdr)
|
||||
#define MAX_IMSGSIZE 16384
|
||||
|
||||
struct ibuf {
|
||||
TAILQ_ENTRY(ibuf) entry;
|
||||
u_char *buf;
|
||||
unsigned char *buf;
|
||||
size_t size;
|
||||
size_t max;
|
||||
size_t wpos;
|
||||
@ -42,8 +44,8 @@ struct msgbuf {
|
||||
};
|
||||
|
||||
struct ibuf_read {
|
||||
u_char buf[IBUF_READ_SIZE];
|
||||
u_char *rptr;
|
||||
unsigned char buf[IBUF_READ_SIZE];
|
||||
unsigned char *rptr;
|
||||
size_t wpos;
|
||||
};
|
||||
|
||||
|
34
configure.ac
34
configure.ac
@ -1,6 +1,6 @@
|
||||
# configure.ac
|
||||
|
||||
AC_INIT([tmux], 3.2-rc2)
|
||||
AC_INIT([tmux], next-3.3)
|
||||
AC_PREREQ([2.60])
|
||||
|
||||
AC_CONFIG_AUX_DIR(etc)
|
||||
@ -113,6 +113,7 @@ AC_REPLACE_FUNCS([ \
|
||||
fgetln \
|
||||
freezero \
|
||||
getdtablecount \
|
||||
getdtablesize \
|
||||
getline \
|
||||
getprogname \
|
||||
memmem \
|
||||
@ -328,6 +329,31 @@ AC_SEARCH_LIBS(inet_ntoa, nsl)
|
||||
AC_SEARCH_LIBS(socket, socket)
|
||||
AC_CHECK_LIB(xnet, socket)
|
||||
|
||||
# Check if using glibc and have malloc_trim(3). The glibc free(3) is pretty bad
|
||||
# about returning memory to the kernel unless the application tells it when to
|
||||
# with malloc_trim(3).
|
||||
AC_MSG_CHECKING(if free doesn't work very well)
|
||||
AC_LINK_IFELSE([AC_LANG_SOURCE(
|
||||
[
|
||||
#include <stdlib.h>
|
||||
#ifdef __GLIBC__
|
||||
#include <malloc.h>
|
||||
int main(void) {
|
||||
malloc_trim (0);
|
||||
exit(0);
|
||||
}
|
||||
#else
|
||||
no
|
||||
#endif
|
||||
])],
|
||||
found_malloc_trim=yes,
|
||||
found_malloc_trim=no
|
||||
)
|
||||
AC_MSG_RESULT($found_malloc_trim)
|
||||
if test "x$found_malloc_trim" = xyes; then
|
||||
AC_DEFINE(HAVE_MALLOC_TRIM)
|
||||
fi
|
||||
|
||||
# Check for CMSG_DATA. On some platforms like HP-UX this requires UNIX 95
|
||||
# (_XOPEN_SOURCE and _XOPEN_SOURCE_EXTENDED) (see xopen_networking(7)). On
|
||||
# others, UNIX 03 (_XOPEN_SOURCE 600, see standards(7) on Solaris).
|
||||
@ -570,6 +596,12 @@ case "$host_os" in
|
||||
AC_MSG_RESULT(darwin)
|
||||
PLATFORM=darwin
|
||||
#
|
||||
# OS X uses __dead2 instead of __dead, like FreeBSD. But it
|
||||
# defines __dead away so it needs to be removed before we can
|
||||
# replace it.
|
||||
#
|
||||
AC_DEFINE(BROKEN___DEAD)
|
||||
#
|
||||
# OS X CMSG_FIRSTHDR is broken, so redefine it with a working
|
||||
# one. daemon works but has some stupid side effects, so use
|
||||
# our internal version which has a workaround.
|
||||
|
@ -688,8 +688,8 @@ control_write_pending(struct client *c, struct control_pane *cp, size_t limit)
|
||||
else
|
||||
age = 0;
|
||||
log_debug("%s: %s: output block %zu (age %llu) for %%%u "
|
||||
"(used %zu/%zu)", __func__, c->name, cb->size, age,
|
||||
cp->pane, used, limit);
|
||||
"(used %zu/%zu)", __func__, c->name, cb->size,
|
||||
(unsigned long long)age, cp->pane, used, limit);
|
||||
|
||||
size = cb->size;
|
||||
if (size > limit - used)
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <fnmatch.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
@ -191,7 +192,11 @@ environ_update(struct options *oo, struct environ *src, struct environ *dst)
|
||||
a = options_array_first(o);
|
||||
while (a != NULL) {
|
||||
ov = options_array_item_value(a);
|
||||
if ((envent = environ_find(src, ov->string)) == NULL)
|
||||
RB_FOREACH(envent, environ, src) {
|
||||
if (fnmatch(ov->string, envent->name, 0) == 0)
|
||||
break;
|
||||
}
|
||||
if (envent == NULL)
|
||||
environ_clear(dst, ov->string);
|
||||
else
|
||||
environ_set(dst, envent->name, 0, "%s", envent->value);
|
||||
|
469
format.c
469
format.c
@ -38,15 +38,18 @@
|
||||
* string.
|
||||
*/
|
||||
|
||||
static char *format_job_get(struct format_tree *, const char *);
|
||||
static void format_job_timer(int, short, void *);
|
||||
struct format_expand_state;
|
||||
|
||||
static int format_replace(struct format_tree *, const char *, size_t,
|
||||
char **, size_t *, size_t *);
|
||||
static char *format_job_get(struct format_expand_state *, const char *);
|
||||
static void format_job_timer(int, short, void *);
|
||||
static char *format_expand1(struct format_expand_state *, const char *);
|
||||
static int format_replace(struct format_expand_state *, const char *,
|
||||
size_t, char **, size_t *, size_t *);
|
||||
static void format_defaults_session(struct format_tree *,
|
||||
struct session *);
|
||||
static void format_defaults_client(struct format_tree *, struct client *);
|
||||
static void format_defaults_winlink(struct format_tree *, struct winlink *);
|
||||
static void format_defaults_winlink(struct format_tree *,
|
||||
struct winlink *);
|
||||
|
||||
/* Entry in format job tree. */
|
||||
struct format_job {
|
||||
@ -94,15 +97,20 @@ format_job_cmp(struct format_job *fj1, struct format_job *fj2)
|
||||
#define FORMAT_WINDOWS 0x100
|
||||
#define FORMAT_PANES 0x200
|
||||
#define FORMAT_PRETTY 0x400
|
||||
#define FORMAT_LENGTH 0x800
|
||||
|
||||
/* Limit on recursion. */
|
||||
#define FORMAT_LOOP_LIMIT 10
|
||||
|
||||
/* Format expand flags. */
|
||||
#define FORMAT_EXPAND_TIME 0x1
|
||||
#define FORMAT_EXPAND_NOJOBS 0x2
|
||||
|
||||
/* Entry in format tree. */
|
||||
struct format_entry {
|
||||
char *key;
|
||||
char *value;
|
||||
time_t t;
|
||||
time_t time;
|
||||
format_cb cb;
|
||||
RB_ENTRY(format_entry) entry;
|
||||
};
|
||||
@ -119,8 +127,6 @@ struct format_tree {
|
||||
struct client *client;
|
||||
int flags;
|
||||
u_int tag;
|
||||
time_t time;
|
||||
u_int loop;
|
||||
|
||||
struct mouse_event m;
|
||||
|
||||
@ -129,6 +135,14 @@ struct format_tree {
|
||||
static int format_entry_cmp(struct format_entry *, struct format_entry *);
|
||||
RB_GENERATE_STATIC(format_entry_tree, format_entry, entry, format_entry_cmp);
|
||||
|
||||
/* Format expand state. */
|
||||
struct format_expand_state {
|
||||
struct format_tree *ft;
|
||||
u_int loop;
|
||||
time_t time;
|
||||
int flags;
|
||||
};
|
||||
|
||||
/* Format modifier. */
|
||||
struct format_modifier {
|
||||
char modifier[3];
|
||||
@ -214,8 +228,10 @@ format_logging(struct format_tree *ft)
|
||||
|
||||
/* Log a message if verbose. */
|
||||
static void printflike(3, 4)
|
||||
format_log1(struct format_tree *ft, const char *from, const char *fmt, ...)
|
||||
format_log1(struct format_expand_state *es, const char *from, const char *fmt,
|
||||
...)
|
||||
{
|
||||
struct format_tree *ft = es->ft;
|
||||
va_list ap;
|
||||
char *s;
|
||||
static const char spaces[] = " ";
|
||||
@ -229,11 +245,22 @@ format_log1(struct format_tree *ft, const char *from, const char *fmt, ...)
|
||||
|
||||
log_debug("%s: %s", from, s);
|
||||
if (ft->item != NULL && (ft->flags & FORMAT_VERBOSE))
|
||||
cmdq_print(ft->item, "#%.*s%s", ft->loop, spaces, s);
|
||||
cmdq_print(ft->item, "#%.*s%s", es->loop, spaces, s);
|
||||
|
||||
free(s);
|
||||
}
|
||||
#define format_log(ft, fmt, ...) format_log1(ft, __func__, fmt, ##__VA_ARGS__)
|
||||
#define format_log(es, fmt, ...) format_log1(es, __func__, fmt, ##__VA_ARGS__)
|
||||
|
||||
/* Copy expand state. */
|
||||
static void
|
||||
format_copy_state(struct format_expand_state *to,
|
||||
struct format_expand_state *from, int flags)
|
||||
{
|
||||
to->ft = from->ft;
|
||||
to->loop = from->loop;
|
||||
to->time = from->time;
|
||||
to->flags = from->flags|flags;
|
||||
}
|
||||
|
||||
/* Format job update callback. */
|
||||
static void
|
||||
@ -303,13 +330,15 @@ format_job_complete(struct job *job)
|
||||
|
||||
/* Find a job. */
|
||||
static char *
|
||||
format_job_get(struct format_tree *ft, const char *cmd)
|
||||
format_job_get(struct format_expand_state *es, const char *cmd)
|
||||
{
|
||||
struct format_job_tree *jobs;
|
||||
struct format_job fj0, *fj;
|
||||
time_t t;
|
||||
char *expanded;
|
||||
int force;
|
||||
struct format_tree *ft = es->ft;
|
||||
struct format_job_tree *jobs;
|
||||
struct format_job fj0, *fj;
|
||||
time_t t;
|
||||
char *expanded;
|
||||
int force;
|
||||
struct format_expand_state next;
|
||||
|
||||
if (ft->client == NULL)
|
||||
jobs = &format_jobs;
|
||||
@ -334,7 +363,7 @@ format_job_get(struct format_tree *ft, const char *cmd)
|
||||
RB_INSERT(format_job_tree, jobs, fj);
|
||||
}
|
||||
|
||||
expanded = format_expand(ft, cmd);
|
||||
expanded = format_expand1(es, cmd);
|
||||
if (fj->expanded == NULL || strcmp(expanded, fj->expanded) != 0) {
|
||||
free((void *)fj->expanded);
|
||||
fj->expanded = xstrdup(expanded);
|
||||
@ -356,12 +385,12 @@ format_job_get(struct format_tree *ft, const char *cmd)
|
||||
fj->last = t;
|
||||
fj->updated = 0;
|
||||
}
|
||||
free(expanded);
|
||||
|
||||
if (ft->flags & FORMAT_STATUS)
|
||||
fj->status = 1;
|
||||
|
||||
free(expanded);
|
||||
return (format_expand(ft, fj->out));
|
||||
format_copy_state(&next, es, FORMAT_EXPAND_NOJOBS);
|
||||
return (format_expand1(&next, fj->out));
|
||||
}
|
||||
|
||||
/* Remove old jobs. */
|
||||
@ -1210,7 +1239,6 @@ format_create(struct client *c, struct cmdq_item *item, int tag, int flags)
|
||||
|
||||
ft->tag = tag;
|
||||
ft->flags = flags;
|
||||
ft->time = time(NULL);
|
||||
|
||||
format_add(ft, "version", "%s", getversion());
|
||||
format_add_cb(ft, "host", format_cb_host);
|
||||
@ -1260,8 +1288,8 @@ format_each(struct format_tree *ft, void (*cb)(const char *, const char *,
|
||||
char s[64];
|
||||
|
||||
RB_FOREACH(fe, format_entry_tree, &ft->tree) {
|
||||
if (fe->t != 0) {
|
||||
xsnprintf(s, sizeof s, "%lld", (long long)fe->t);
|
||||
if (fe->time != 0) {
|
||||
xsnprintf(s, sizeof s, "%lld", (long long)fe->time);
|
||||
cb(fe->key, s, arg);
|
||||
} else {
|
||||
if (fe->value == NULL && fe->cb != NULL) {
|
||||
@ -1294,7 +1322,7 @@ format_add(struct format_tree *ft, const char *key, const char *fmt, ...)
|
||||
}
|
||||
|
||||
fe->cb = NULL;
|
||||
fe->t = 0;
|
||||
fe->time = 0;
|
||||
|
||||
va_start(ap, fmt);
|
||||
xvasprintf(&fe->value, fmt, ap);
|
||||
@ -1319,7 +1347,7 @@ format_add_tv(struct format_tree *ft, const char *key, struct timeval *tv)
|
||||
}
|
||||
|
||||
fe->cb = NULL;
|
||||
fe->t = tv->tv_sec;
|
||||
fe->time = tv->tv_sec;
|
||||
|
||||
fe->value = NULL;
|
||||
}
|
||||
@ -1343,7 +1371,7 @@ format_add_cb(struct format_tree *ft, const char *key, format_cb cb)
|
||||
}
|
||||
|
||||
fe->cb = cb;
|
||||
fe->t = 0;
|
||||
fe->time = 0;
|
||||
|
||||
fe->value = NULL;
|
||||
}
|
||||
@ -1439,8 +1467,8 @@ format_find(struct format_tree *ft, const char *key, int modifiers,
|
||||
fe_find.key = (char *)key;
|
||||
fe = RB_FIND(format_entry_tree, &ft->tree, &fe_find);
|
||||
if (fe != NULL) {
|
||||
if (fe->t != 0) {
|
||||
t = fe->t;
|
||||
if (fe->time != 0) {
|
||||
t = fe->time;
|
||||
goto found;
|
||||
}
|
||||
if (fe->value == NULL && fe->cb != NULL) {
|
||||
@ -1562,8 +1590,8 @@ format_skip(const char *s, const char *end)
|
||||
|
||||
/* Return left and right alternatives separated by commas. */
|
||||
static int
|
||||
format_choose(struct format_tree *ft, const char *s, char **left, char **right,
|
||||
int expand)
|
||||
format_choose(struct format_expand_state *es, const char *s, char **left,
|
||||
char **right, int expand)
|
||||
{
|
||||
const char *cp;
|
||||
char *left0, *right0;
|
||||
@ -1575,9 +1603,9 @@ format_choose(struct format_tree *ft, const char *s, char **left, char **right,
|
||||
right0 = xstrdup(cp + 1);
|
||||
|
||||
if (expand) {
|
||||
*left = format_expand(ft, left0);
|
||||
*left = format_expand1(es, left0);
|
||||
free(left0);
|
||||
*right = format_expand(ft, right0);
|
||||
*right = format_expand1(es, right0);
|
||||
free(right0);
|
||||
} else {
|
||||
*left = left0;
|
||||
@ -1633,7 +1661,8 @@ format_free_modifiers(struct format_modifier *list, u_int count)
|
||||
|
||||
/* Build modifier list. */
|
||||
static struct format_modifier *
|
||||
format_build_modifiers(struct format_tree *ft, const char **s, u_int *count)
|
||||
format_build_modifiers(struct format_expand_state *es, const char **s,
|
||||
u_int *count)
|
||||
{
|
||||
const char *cp = *s, *end;
|
||||
struct format_modifier *list = NULL;
|
||||
@ -1642,7 +1671,7 @@ format_build_modifiers(struct format_tree *ft, const char **s, u_int *count)
|
||||
|
||||
/*
|
||||
* Modifiers are a ; separated list of the forms:
|
||||
* l,m,C,b,d,t,q,E,T,S,W,P,<,>
|
||||
* l,m,C,b,d,n,t,q,E,T,S,W,P,<,>
|
||||
* =a
|
||||
* =/a
|
||||
* =/a/
|
||||
@ -1659,7 +1688,7 @@ format_build_modifiers(struct format_tree *ft, const char **s, u_int *count)
|
||||
cp++;
|
||||
|
||||
/* Check single character modifiers with no arguments. */
|
||||
if (strchr("lbdqETSWP<>", cp[0]) != NULL &&
|
||||
if (strchr("lbdnqETSWP<>", cp[0]) != NULL &&
|
||||
format_is_end(cp[1])) {
|
||||
format_add_modifier(&list, count, cp, 1, NULL, 0);
|
||||
cp++;
|
||||
@ -1701,7 +1730,7 @@ format_build_modifiers(struct format_tree *ft, const char **s, u_int *count)
|
||||
|
||||
argv = xcalloc(1, sizeof *argv);
|
||||
value = xstrndup(cp + 1, end - (cp + 1));
|
||||
argv[0] = format_expand(ft, value);
|
||||
argv[0] = format_expand1(es, value);
|
||||
free(value);
|
||||
argc = 1;
|
||||
|
||||
@ -1725,7 +1754,7 @@ format_build_modifiers(struct format_tree *ft, const char **s, u_int *count)
|
||||
|
||||
argv = xreallocarray (argv, argc + 1, sizeof *argv);
|
||||
value = xstrndup(cp, end - cp);
|
||||
argv[argc++] = format_expand(ft, value);
|
||||
argv[argc++] = format_expand1(es, value);
|
||||
free(value);
|
||||
|
||||
cp = end;
|
||||
@ -1806,25 +1835,28 @@ format_search(struct format_modifier *fm, struct window_pane *wp, const char *s)
|
||||
|
||||
/* Loop over sessions. */
|
||||
static char *
|
||||
format_loop_sessions(struct format_tree *ft, const char *fmt)
|
||||
format_loop_sessions(struct format_expand_state *es, const char *fmt)
|
||||
{
|
||||
struct client *c = ft->client;
|
||||
struct cmdq_item *item = ft->item;
|
||||
struct format_tree *nft;
|
||||
char *expanded, *value;
|
||||
size_t valuelen;
|
||||
struct session *s;
|
||||
struct format_tree *ft = es->ft;
|
||||
struct client *c = ft->client;
|
||||
struct cmdq_item *item = ft->item;
|
||||
struct format_tree *nft;
|
||||
struct format_expand_state next;
|
||||
char *expanded, *value;
|
||||
size_t valuelen;
|
||||
struct session *s;
|
||||
|
||||
value = xcalloc(1, 1);
|
||||
valuelen = 1;
|
||||
|
||||
RB_FOREACH(s, sessions, &sessions) {
|
||||
format_log(ft, "session loop: $%u", s->id);
|
||||
format_log(es, "session loop: $%u", s->id);
|
||||
nft = format_create(c, item, FORMAT_NONE, ft->flags);
|
||||
nft->loop = ft->loop;
|
||||
format_defaults(nft, ft->c, s, NULL, NULL);
|
||||
expanded = format_expand(nft, fmt);
|
||||
format_free(nft);
|
||||
format_defaults(next.ft, ft->c, s, NULL, NULL);
|
||||
format_copy_state(&next, es, 0);
|
||||
next.ft = nft;
|
||||
expanded = format_expand1(&next, fmt);
|
||||
format_free(next.ft);
|
||||
|
||||
valuelen += strlen(expanded);
|
||||
value = xrealloc(value, valuelen);
|
||||
@ -1838,22 +1870,24 @@ format_loop_sessions(struct format_tree *ft, const char *fmt)
|
||||
|
||||
/* Loop over windows. */
|
||||
static char *
|
||||
format_loop_windows(struct format_tree *ft, const char *fmt)
|
||||
format_loop_windows(struct format_expand_state *es, const char *fmt)
|
||||
{
|
||||
struct client *c = ft->client;
|
||||
struct cmdq_item *item = ft->item;
|
||||
struct format_tree *nft;
|
||||
char *all, *active, *use, *expanded, *value;
|
||||
size_t valuelen;
|
||||
struct winlink *wl;
|
||||
struct window *w;
|
||||
struct format_tree *ft = es->ft;
|
||||
struct client *c = ft->client;
|
||||
struct cmdq_item *item = ft->item;
|
||||
struct format_tree *nft;
|
||||
struct format_expand_state next;
|
||||
char *all, *active, *use, *expanded, *value;
|
||||
size_t valuelen;
|
||||
struct winlink *wl;
|
||||
struct window *w;
|
||||
|
||||
if (ft->s == NULL) {
|
||||
format_log(ft, "window loop but no session");
|
||||
format_log(es, "window loop but no session");
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (format_choose(ft, fmt, &all, &active, 0) != 0) {
|
||||
if (format_choose(es, fmt, &all, &active, 0) != 0) {
|
||||
all = xstrdup(fmt);
|
||||
active = NULL;
|
||||
}
|
||||
@ -1863,15 +1897,16 @@ format_loop_windows(struct format_tree *ft, const char *fmt)
|
||||
|
||||
RB_FOREACH(wl, winlinks, &ft->s->windows) {
|
||||
w = wl->window;
|
||||
format_log(ft, "window loop: %u @%u", wl->idx, w->id);
|
||||
format_log(es, "window loop: %u @%u", wl->idx, w->id);
|
||||
if (active != NULL && wl == ft->s->curw)
|
||||
use = active;
|
||||
else
|
||||
use = all;
|
||||
nft = format_create(c, item, FORMAT_WINDOW|w->id, ft->flags);
|
||||
nft->loop = ft->loop;
|
||||
format_defaults(nft, ft->c, ft->s, wl, NULL);
|
||||
expanded = format_expand(nft, use);
|
||||
format_copy_state(&next, es, 0);
|
||||
next.ft = nft;
|
||||
expanded = format_expand1(&next, use);
|
||||
format_free(nft);
|
||||
|
||||
valuelen += strlen(expanded);
|
||||
@ -1889,21 +1924,23 @@ format_loop_windows(struct format_tree *ft, const char *fmt)
|
||||
|
||||
/* Loop over panes. */
|
||||
static char *
|
||||
format_loop_panes(struct format_tree *ft, const char *fmt)
|
||||
format_loop_panes(struct format_expand_state *es, const char *fmt)
|
||||
{
|
||||
struct client *c = ft->client;
|
||||
struct cmdq_item *item = ft->item;
|
||||
struct format_tree *nft;
|
||||
char *all, *active, *use, *expanded, *value;
|
||||
size_t valuelen;
|
||||
struct window_pane *wp;
|
||||
struct format_tree *ft = es->ft;
|
||||
struct client *c = ft->client;
|
||||
struct cmdq_item *item = ft->item;
|
||||
struct format_tree *nft;
|
||||
struct format_expand_state next;
|
||||
char *all, *active, *use, *expanded, *value;
|
||||
size_t valuelen;
|
||||
struct window_pane *wp;
|
||||
|
||||
if (ft->w == NULL) {
|
||||
format_log(ft, "pane loop but no window");
|
||||
format_log(es, "pane loop but no window");
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (format_choose(ft, fmt, &all, &active, 0) != 0) {
|
||||
if (format_choose(es, fmt, &all, &active, 0) != 0) {
|
||||
all = xstrdup(fmt);
|
||||
active = NULL;
|
||||
}
|
||||
@ -1912,15 +1949,16 @@ format_loop_panes(struct format_tree *ft, const char *fmt)
|
||||
valuelen = 1;
|
||||
|
||||
TAILQ_FOREACH(wp, &ft->w->panes, entry) {
|
||||
format_log(ft, "pane loop: %%%u", wp->id);
|
||||
format_log(es, "pane loop: %%%u", wp->id);
|
||||
if (active != NULL && wp == ft->w->active)
|
||||
use = active;
|
||||
else
|
||||
use = all;
|
||||
nft = format_create(c, item, FORMAT_PANE|wp->id, ft->flags);
|
||||
nft->loop = ft->loop;
|
||||
format_defaults(nft, ft->c, ft->s, ft->wl, wp);
|
||||
expanded = format_expand(nft, use);
|
||||
format_copy_state(&next, es, 0);
|
||||
next.ft = nft;
|
||||
expanded = format_expand1(&next, use);
|
||||
format_free(nft);
|
||||
|
||||
valuelen += strlen(expanded);
|
||||
@ -1937,16 +1975,26 @@ format_loop_panes(struct format_tree *ft, const char *fmt)
|
||||
}
|
||||
|
||||
static char *
|
||||
format_replace_expression(struct format_modifier *mexp, struct format_tree *ft,
|
||||
const char *copy)
|
||||
format_replace_expression(struct format_modifier *mexp,
|
||||
struct format_expand_state *es, const char *copy)
|
||||
{
|
||||
int argc = mexp->argc;
|
||||
const char *errstr;
|
||||
char *endch, *value, *left = NULL, *right = NULL;
|
||||
int use_fp = 0;
|
||||
u_int prec = 0;
|
||||
double mleft, mright, result;
|
||||
enum { ADD, SUBTRACT, MULTIPLY, DIVIDE, MODULUS } operator;
|
||||
int argc = mexp->argc;
|
||||
const char *errstr;
|
||||
char *endch, *value, *left = NULL, *right = NULL;
|
||||
int use_fp = 0;
|
||||
u_int prec = 0;
|
||||
double mleft, mright, result;
|
||||
enum { ADD,
|
||||
SUBTRACT,
|
||||
MULTIPLY,
|
||||
DIVIDE,
|
||||
MODULUS,
|
||||
EQUAL,
|
||||
NOT_EQUAL,
|
||||
GREATER_THAN,
|
||||
GREATER_THAN_EQUAL,
|
||||
LESS_THAN,
|
||||
LESS_THAN_EQUAL } operator;
|
||||
|
||||
if (strcmp(mexp->argv[0], "+") == 0)
|
||||
operator = ADD;
|
||||
@ -1959,8 +2007,20 @@ format_replace_expression(struct format_modifier *mexp, struct format_tree *ft,
|
||||
else if (strcmp(mexp->argv[0], "%") == 0 ||
|
||||
strcmp(mexp->argv[0], "m") == 0)
|
||||
operator = MODULUS;
|
||||
else if (strcmp(mexp->argv[0], "==") == 0)
|
||||
operator = EQUAL;
|
||||
else if (strcmp(mexp->argv[0], "!=") == 0)
|
||||
operator = NOT_EQUAL;
|
||||
else if (strcmp(mexp->argv[0], ">") == 0)
|
||||
operator = GREATER_THAN;
|
||||
else if (strcmp(mexp->argv[0], "<") == 0)
|
||||
operator = LESS_THAN;
|
||||
else if (strcmp(mexp->argv[0], ">=") == 0)
|
||||
operator = GREATER_THAN_EQUAL;
|
||||
else if (strcmp(mexp->argv[0], "<=") == 0)
|
||||
operator = LESS_THAN_EQUAL;
|
||||
else {
|
||||
format_log(ft, "expression has no valid operator: '%s'",
|
||||
format_log(es, "expression has no valid operator: '%s'",
|
||||
mexp->argv[0]);
|
||||
goto fail;
|
||||
}
|
||||
@ -1975,26 +2035,26 @@ format_replace_expression(struct format_modifier *mexp, struct format_tree *ft,
|
||||
if (argc >= 3) {
|
||||
prec = strtonum(mexp->argv[2], INT_MIN, INT_MAX, &errstr);
|
||||
if (errstr != NULL) {
|
||||
format_log (ft, "expression precision %s: %s", errstr,
|
||||
format_log(es, "expression precision %s: %s", errstr,
|
||||
mexp->argv[2]);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (format_choose(ft, copy, &left, &right, 1) != 0) {
|
||||
format_log(ft, "expression syntax error");
|
||||
if (format_choose(es, copy, &left, &right, 1) != 0) {
|
||||
format_log(es, "expression syntax error");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
mleft = strtod(left, &endch);
|
||||
if (*endch != '\0') {
|
||||
format_log(ft, "expression left side is invalid: %s", left);
|
||||
format_log(es, "expression left side is invalid: %s", left);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
mright = strtod(right, &endch);
|
||||
if (*endch != '\0') {
|
||||
format_log(ft, "expression right side is invalid: %s", right);
|
||||
format_log(es, "expression right side is invalid: %s", right);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@ -2002,8 +2062,8 @@ format_replace_expression(struct format_modifier *mexp, struct format_tree *ft,
|
||||
mleft = (long long)mleft;
|
||||
mright = (long long)mright;
|
||||
}
|
||||
format_log(ft, "expression left side is: %.*f", prec, mleft);
|
||||
format_log(ft, "expression right side is: %.*f", prec, mright);
|
||||
format_log(es, "expression left side is: %.*f", prec, mleft);
|
||||
format_log(es, "expression right side is: %.*f", prec, mright);
|
||||
|
||||
switch (operator) {
|
||||
case ADD:
|
||||
@ -2021,12 +2081,30 @@ format_replace_expression(struct format_modifier *mexp, struct format_tree *ft,
|
||||
case MODULUS:
|
||||
result = fmod(mleft, mright);
|
||||
break;
|
||||
case EQUAL:
|
||||
result = fabs(mleft - mright) < 1e-9;
|
||||
break;
|
||||
case NOT_EQUAL:
|
||||
result = fabs(mleft - mright) > 1e-9;
|
||||
break;
|
||||
case GREATER_THAN:
|
||||
result = (mleft > mright);
|
||||
break;
|
||||
case GREATER_THAN_EQUAL:
|
||||
result = (mleft >= mright);
|
||||
break;
|
||||
case LESS_THAN:
|
||||
result = (mleft < mright);
|
||||
break;
|
||||
case LESS_THAN_EQUAL:
|
||||
result = (mleft > mright);
|
||||
break;
|
||||
}
|
||||
if (use_fp)
|
||||
xasprintf(&value, "%.*f", prec, result);
|
||||
else
|
||||
xasprintf(&value, "%.*f", prec, (double)(long long)result);
|
||||
format_log(ft, "expression result is %s", value);
|
||||
format_log(es, "expression result is %s", value);
|
||||
|
||||
free(right);
|
||||
free(left);
|
||||
@ -2040,31 +2118,34 @@ fail:
|
||||
|
||||
/* Replace a key. */
|
||||
static int
|
||||
format_replace(struct format_tree *ft, const char *key, size_t keylen,
|
||||
format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
||||
char **buf, size_t *len, size_t *off)
|
||||
{
|
||||
struct window_pane *wp = ft->wp;
|
||||
const char *errptr, *copy, *cp, *marker = NULL;
|
||||
const char *time_format = NULL;
|
||||
char *copy0, *condition, *found, *new;
|
||||
char *value, *left, *right;
|
||||
size_t valuelen;
|
||||
int modifiers = 0, limit = 0, width = 0, j;
|
||||
struct format_modifier *list, *fm, *cmp = NULL, *search = NULL;
|
||||
struct format_modifier **sub = NULL, *mexp = NULL;
|
||||
u_int i, count, nsub = 0;
|
||||
struct format_tree *ft = es->ft;
|
||||
struct window_pane *wp = ft->wp;
|
||||
const char *errptr, *copy, *cp, *marker = NULL;
|
||||
const char *time_format = NULL;
|
||||
char *copy0, *condition, *found, *new;
|
||||
char *value, *left, *right;
|
||||
size_t valuelen;
|
||||
int modifiers = 0, limit = 0, width = 0;
|
||||
int j;
|
||||
struct format_modifier *list, *cmp = NULL, *search = NULL;
|
||||
struct format_modifier **sub = NULL, *mexp = NULL, *fm;
|
||||
u_int i, count, nsub = 0;
|
||||
struct format_expand_state next;
|
||||
|
||||
/* Make a copy of the key. */
|
||||
copy = copy0 = xstrndup(key, keylen);
|
||||
|
||||
/* Process modifier list. */
|
||||
list = format_build_modifiers(ft, ©, &count);
|
||||
list = format_build_modifiers(es, ©, &count);
|
||||
for (i = 0; i < count; i++) {
|
||||
fm = &list[i];
|
||||
if (format_logging(ft)) {
|
||||
format_log(ft, "modifier %u is %s", i, fm->modifier);
|
||||
format_log(es, "modifier %u is %s", i, fm->modifier);
|
||||
for (j = 0; j < fm->argc; j++) {
|
||||
format_log(ft, "modifier %u argument %d: %s", i,
|
||||
format_log(es, "modifier %u argument %d: %s", i,
|
||||
j, fm->argv[j]);
|
||||
}
|
||||
}
|
||||
@ -2117,6 +2198,9 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
|
||||
case 'd':
|
||||
modifiers |= FORMAT_DIRNAME;
|
||||
break;
|
||||
case 'n':
|
||||
modifiers |= FORMAT_LENGTH;
|
||||
break;
|
||||
case 't':
|
||||
modifiers |= FORMAT_TIMESTRING;
|
||||
if (fm->argc < 1)
|
||||
@ -2165,37 +2249,37 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
|
||||
|
||||
/* Is this a loop, comparison or condition? */
|
||||
if (modifiers & FORMAT_SESSIONS) {
|
||||
value = format_loop_sessions(ft, copy);
|
||||
value = format_loop_sessions(es, copy);
|
||||
if (value == NULL)
|
||||
goto fail;
|
||||
} else if (modifiers & FORMAT_WINDOWS) {
|
||||
value = format_loop_windows(ft, copy);
|
||||
value = format_loop_windows(es, copy);
|
||||
if (value == NULL)
|
||||
goto fail;
|
||||
} else if (modifiers & FORMAT_PANES) {
|
||||
value = format_loop_panes(ft, copy);
|
||||
value = format_loop_panes(es, copy);
|
||||
if (value == NULL)
|
||||
goto fail;
|
||||
} else if (search != NULL) {
|
||||
/* Search in pane. */
|
||||
new = format_expand(ft, copy);
|
||||
new = format_expand1(es, copy);
|
||||
if (wp == NULL) {
|
||||
format_log(ft, "search '%s' but no pane", new);
|
||||
format_log(es, "search '%s' but no pane", new);
|
||||
value = xstrdup("0");
|
||||
} else {
|
||||
format_log(ft, "search '%s' pane %%%u", new, wp->id);
|
||||
format_log(es, "search '%s' pane %%%u", new, wp->id);
|
||||
value = format_search(fm, wp, new);
|
||||
}
|
||||
free(new);
|
||||
} else if (cmp != NULL) {
|
||||
/* Comparison of left and right. */
|
||||
if (format_choose(ft, copy, &left, &right, 1) != 0) {
|
||||
format_log(ft, "compare %s syntax error: %s",
|
||||
if (format_choose(es, copy, &left, &right, 1) != 0) {
|
||||
format_log(es, "compare %s syntax error: %s",
|
||||
cmp->modifier, copy);
|
||||
goto fail;
|
||||
}
|
||||
format_log(ft, "compare %s left is: %s", cmp->modifier, left);
|
||||
format_log(ft, "compare %s right is: %s", cmp->modifier, right);
|
||||
format_log(es, "compare %s left is: %s", cmp->modifier, left);
|
||||
format_log(es, "compare %s right is: %s", cmp->modifier, right);
|
||||
|
||||
if (strcmp(cmp->modifier, "||") == 0) {
|
||||
if (format_true(left) || format_true(right))
|
||||
@ -2246,11 +2330,11 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
|
||||
/* Conditional: check first and choose second or third. */
|
||||
cp = format_skip(copy + 1, ",");
|
||||
if (cp == NULL) {
|
||||
format_log(ft, "condition syntax error: %s", copy + 1);
|
||||
format_log(es, "condition syntax error: %s", copy + 1);
|
||||
goto fail;
|
||||
}
|
||||
condition = xstrndup(copy + 1, cp - (copy + 1));
|
||||
format_log(ft, "condition is: %s", condition);
|
||||
format_log(es, "condition is: %s", condition);
|
||||
|
||||
found = format_find(ft, condition, modifiers, time_format);
|
||||
if (found == NULL) {
|
||||
@ -2259,32 +2343,32 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
|
||||
* the expansion doesn't have any effect, then assume
|
||||
* false.
|
||||
*/
|
||||
found = format_expand(ft, condition);
|
||||
found = format_expand1(es, condition);
|
||||
if (strcmp(found, condition) == 0) {
|
||||
free(found);
|
||||
found = xstrdup("");
|
||||
format_log(ft, "condition '%s' found: %s",
|
||||
format_log(es, "condition '%s' found: %s",
|
||||
condition, found);
|
||||
} else {
|
||||
format_log(ft,
|
||||
format_log(es,
|
||||
"condition '%s' not found; assuming false",
|
||||
condition);
|
||||
}
|
||||
} else
|
||||
format_log(ft, "condition '%s' found", condition);
|
||||
format_log(es, "condition '%s' found", condition);
|
||||
|
||||
if (format_choose(ft, cp + 1, &left, &right, 0) != 0) {
|
||||
format_log(ft, "condition '%s' syntax error: %s",
|
||||
if (format_choose(es, cp + 1, &left, &right, 0) != 0) {
|
||||
format_log(es, "condition '%s' syntax error: %s",
|
||||
condition, cp + 1);
|
||||
free(found);
|
||||
goto fail;
|
||||
}
|
||||
if (format_true(found)) {
|
||||
format_log(ft, "condition '%s' is true", condition);
|
||||
value = format_expand(ft, left);
|
||||
format_log(es, "condition '%s' is true", condition);
|
||||
value = format_expand1(es, left);
|
||||
} else {
|
||||
format_log(ft, "condition '%s' is false", condition);
|
||||
value = format_expand(ft, right);
|
||||
format_log(es, "condition '%s' is false", condition);
|
||||
value = format_expand1(es, right);
|
||||
}
|
||||
free(right);
|
||||
free(left);
|
||||
@ -2292,38 +2376,44 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
|
||||
free(condition);
|
||||
free(found);
|
||||
} else if (mexp != NULL) {
|
||||
value = format_replace_expression(mexp, ft, copy);
|
||||
value = format_replace_expression(mexp, es, copy);
|
||||
if (value == NULL)
|
||||
value = xstrdup("");
|
||||
} else {
|
||||
/* Neither: look up directly. */
|
||||
value = format_find(ft, copy, modifiers, time_format);
|
||||
if (value == NULL) {
|
||||
format_log(ft, "format '%s' not found", copy);
|
||||
value = xstrdup("");
|
||||
} else
|
||||
format_log(ft, "format '%s' found: %s", copy, value);
|
||||
if (strstr(copy, "#{") != 0) {
|
||||
format_log(es, "expanding inner format '%s'", copy);
|
||||
value = format_expand1(es, copy);
|
||||
} else {
|
||||
value = format_find(ft, copy, modifiers, time_format);
|
||||
if (value == NULL) {
|
||||
format_log(es, "format '%s' not found", copy);
|
||||
value = xstrdup("");
|
||||
} else {
|
||||
format_log(es, "format '%s' found: %s", copy,
|
||||
value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
/* Expand again if required. */
|
||||
if (modifiers & FORMAT_EXPAND) {
|
||||
new = format_expand(ft, value);
|
||||
new = format_expand1(es, value);
|
||||
free(value);
|
||||
value = new;
|
||||
}
|
||||
else if (modifiers & FORMAT_EXPANDTIME) {
|
||||
new = format_expand_time(ft, value);
|
||||
} else if (modifiers & FORMAT_EXPANDTIME) {
|
||||
format_copy_state(&next, es, FORMAT_EXPAND_TIME);
|
||||
new = format_expand1(&next, value);
|
||||
free(value);
|
||||
value = new;
|
||||
}
|
||||
|
||||
/* Perform substitution if any. */
|
||||
for (i = 0; i < nsub; i++) {
|
||||
left = format_expand(ft, sub[i]->argv[0]);
|
||||
right = format_expand(ft, sub[i]->argv[1]);
|
||||
left = format_expand1(es, sub[i]->argv[0]);
|
||||
right = format_expand1(es, sub[i]->argv[1]);
|
||||
new = format_sub(sub[i], value, left, right);
|
||||
format_log(ft, "substitute '%s' to '%s': %s", left, right, new);
|
||||
format_log(es, "substitute '%s' to '%s': %s", left, right, new);
|
||||
free(value);
|
||||
value = new;
|
||||
free(right);
|
||||
@ -2340,7 +2430,7 @@ done:
|
||||
free(value);
|
||||
value = new;
|
||||
}
|
||||
format_log(ft, "applied length limit %d: %s", limit, value);
|
||||
format_log(es, "applied length limit %d: %s", limit, value);
|
||||
} else if (limit < 0) {
|
||||
new = format_trim_right(value, -limit);
|
||||
if (marker != NULL && strcmp(new, value) != 0) {
|
||||
@ -2350,7 +2440,7 @@ done:
|
||||
free(value);
|
||||
value = new;
|
||||
}
|
||||
format_log(ft, "applied length limit %d: %s", limit, value);
|
||||
format_log(es, "applied length limit %d: %s", limit, value);
|
||||
}
|
||||
|
||||
/* Pad the value if needed. */
|
||||
@ -2358,12 +2448,20 @@ done:
|
||||
new = utf8_padcstr(value, width);
|
||||
free(value);
|
||||
value = new;
|
||||
format_log(ft, "applied padding width %d: %s", width, value);
|
||||
format_log(es, "applied padding width %d: %s", width, value);
|
||||
} else if (width < 0) {
|
||||
new = utf8_rpadcstr(value, -width);
|
||||
free(value);
|
||||
value = new;
|
||||
format_log(ft, "applied padding width %d: %s", width, value);
|
||||
format_log(es, "applied padding width %d: %s", width, value);
|
||||
}
|
||||
|
||||
/* Replace with the length if needed. */
|
||||
if (modifiers & FORMAT_LENGTH) {
|
||||
xasprintf(&new, "%zu", strlen(value));
|
||||
free(value);
|
||||
value = new;
|
||||
format_log(es, "replacing with length: %s", new);
|
||||
}
|
||||
|
||||
/* Expand the buffer and copy in the value. */
|
||||
@ -2375,7 +2473,7 @@ done:
|
||||
memcpy(*buf + *off, value, valuelen);
|
||||
*off += valuelen;
|
||||
|
||||
format_log(ft, "replaced '%s' with '%s'", copy0, value);
|
||||
format_log(es, "replaced '%s' with '%s'", copy0, value);
|
||||
free(value);
|
||||
|
||||
free(sub);
|
||||
@ -2384,7 +2482,7 @@ done:
|
||||
return (0);
|
||||
|
||||
fail:
|
||||
format_log(ft, "failed %s", copy0);
|
||||
format_log(es, "failed %s", copy0);
|
||||
|
||||
free(sub);
|
||||
format_free_modifiers(list, count);
|
||||
@ -2394,32 +2492,35 @@ fail:
|
||||
|
||||
/* Expand keys in a template. */
|
||||
static char *
|
||||
format_expand1(struct format_tree *ft, const char *fmt, int time)
|
||||
format_expand1(struct format_expand_state *es, const char *fmt)
|
||||
{
|
||||
char *buf, *out, *name;
|
||||
const char *ptr, *s;
|
||||
size_t off, len, n, outlen;
|
||||
int ch, brackets;
|
||||
struct tm *tm;
|
||||
char expanded[8192];
|
||||
struct format_tree *ft = es->ft;
|
||||
char *buf, *out, *name;
|
||||
const char *ptr, *s;
|
||||
size_t off, len, n, outlen;
|
||||
int ch, brackets;
|
||||
struct tm *tm;
|
||||
char expanded[8192];
|
||||
|
||||
if (fmt == NULL || *fmt == '\0')
|
||||
return (xstrdup(""));
|
||||
|
||||
if (ft->loop == FORMAT_LOOP_LIMIT)
|
||||
if (es->loop == FORMAT_LOOP_LIMIT)
|
||||
return (xstrdup(""));
|
||||
ft->loop++;
|
||||
es->loop++;
|
||||
|
||||
format_log(ft, "expanding format: %s", fmt);
|
||||
format_log(es, "expanding format: %s", fmt);
|
||||
|
||||
if (time) {
|
||||
tm = localtime(&ft->time);
|
||||
if (es->flags & FORMAT_EXPAND_TIME) {
|
||||
if (es->time == 0)
|
||||
es->time = time(NULL);
|
||||
tm = localtime(&es->time);
|
||||
if (strftime(expanded, sizeof expanded, fmt, tm) == 0) {
|
||||
format_log(ft, "format is too long");
|
||||
format_log(es, "format is too long");
|
||||
return (xstrdup(""));
|
||||
}
|
||||
if (format_logging(ft) && strcmp(expanded, fmt) != 0)
|
||||
format_log(ft, "after time expanded: %s", expanded);
|
||||
format_log(es, "after time expanded: %s", expanded);
|
||||
fmt = expanded;
|
||||
}
|
||||
|
||||
@ -2453,14 +2554,15 @@ format_expand1(struct format_tree *ft, const char *fmt, int time)
|
||||
n = ptr - fmt;
|
||||
|
||||
name = xstrndup(fmt, n);
|
||||
format_log(ft, "found #(): %s", name);
|
||||
format_log(es, "found #(): %s", name);
|
||||
|
||||
if (ft->flags & FORMAT_NOJOBS) {
|
||||
if ((ft->flags & FORMAT_NOJOBS) ||
|
||||
(es->flags & FORMAT_EXPAND_NOJOBS)) {
|
||||
out = xstrdup("");
|
||||
format_log(ft, "#() is disabled");
|
||||
format_log(es, "#() is disabled");
|
||||
} else {
|
||||
out = format_job_get(ft, name);
|
||||
format_log(ft, "#() result: %s", out);
|
||||
out = format_job_get(es, name);
|
||||
format_log(es, "#() result: %s", out);
|
||||
}
|
||||
free(name);
|
||||
|
||||
@ -2482,15 +2584,15 @@ format_expand1(struct format_tree *ft, const char *fmt, int time)
|
||||
break;
|
||||
n = ptr - fmt;
|
||||
|
||||
format_log(ft, "found #{}: %.*s", (int)n, fmt);
|
||||
if (format_replace(ft, fmt, n, &buf, &len, &off) != 0)
|
||||
format_log(es, "found #{}: %.*s", (int)n, fmt);
|
||||
if (format_replace(es, fmt, n, &buf, &len, &off) != 0)
|
||||
break;
|
||||
fmt += n + 1;
|
||||
continue;
|
||||
case '}':
|
||||
case '#':
|
||||
case ',':
|
||||
format_log(ft, "found #%c", ch);
|
||||
format_log(es, "found #%c", ch);
|
||||
while (len - off < 2) {
|
||||
buf = xreallocarray(buf, 2, len);
|
||||
len *= 2;
|
||||
@ -2513,8 +2615,8 @@ format_expand1(struct format_tree *ft, const char *fmt, int time)
|
||||
continue;
|
||||
}
|
||||
n = strlen(s);
|
||||
format_log(ft, "found #%c: %s", ch, s);
|
||||
if (format_replace(ft, s, n, &buf, &len, &off) != 0)
|
||||
format_log(es, "found #%c: %s", ch, s);
|
||||
if (format_replace(es, s, n, &buf, &len, &off) != 0)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
@ -2523,8 +2625,8 @@ format_expand1(struct format_tree *ft, const char *fmt, int time)
|
||||
}
|
||||
buf[off] = '\0';
|
||||
|
||||
format_log(ft, "result is: %s", buf);
|
||||
ft->loop--;
|
||||
format_log(es, "result is: %s", buf);
|
||||
es->loop--;
|
||||
|
||||
return (buf);
|
||||
}
|
||||
@ -2533,14 +2635,24 @@ format_expand1(struct format_tree *ft, const char *fmt, int time)
|
||||
char *
|
||||
format_expand_time(struct format_tree *ft, const char *fmt)
|
||||
{
|
||||
return (format_expand1(ft, fmt, 1));
|
||||
struct format_expand_state es;
|
||||
|
||||
memset(&es, 0, sizeof es);
|
||||
es.ft = ft;
|
||||
es.flags = FORMAT_EXPAND_TIME;
|
||||
return (format_expand1(&es, fmt));
|
||||
}
|
||||
|
||||
/* Expand keys in a template. */
|
||||
char *
|
||||
format_expand(struct format_tree *ft, const char *fmt)
|
||||
{
|
||||
return (format_expand1(ft, fmt, 0));
|
||||
struct format_expand_state es;
|
||||
|
||||
memset(&es, 0, sizeof es);
|
||||
es.ft = ft;
|
||||
es.flags = 0;
|
||||
return (format_expand1(&es, fmt));
|
||||
}
|
||||
|
||||
/* Expand a single string. */
|
||||
@ -2889,6 +3001,7 @@ format_defaults_pane(struct format_tree *ft, struct window_pane *wp)
|
||||
format_add(ft, "pane_dead", "%d", wp->fd == -1);
|
||||
else
|
||||
format_add(ft, "pane_dead", "0");
|
||||
format_add(ft, "pane_last", "%d", wp == w->last);
|
||||
|
||||
if (server_check_marked() && marked_pane.wp == wp)
|
||||
format_add(ft, "pane_marked", "1");
|
||||
|
24
grid.c
24
grid.c
@ -265,6 +265,9 @@ grid_free_lines(struct grid *gd, u_int py, u_int ny)
|
||||
|
||||
for (yy = py; yy < py + ny; yy++)
|
||||
grid_free_line(gd, yy);
|
||||
#ifdef HAVE_MALLOC_TRIM
|
||||
malloc_trim(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Create a new grid. */
|
||||
@ -463,7 +466,7 @@ grid_expand_line(struct grid *gd, u_int py, u_int sx, u_int bg)
|
||||
sx = gd->sx / 4;
|
||||
else if (sx < gd->sx / 2)
|
||||
sx = gd->sx / 2;
|
||||
else
|
||||
else if (gd->sx > sx)
|
||||
sx = gd->sx;
|
||||
|
||||
gl->celldata = xreallocarray(gl->celldata, sx, sizeof *gl->celldata);
|
||||
@ -1277,7 +1280,7 @@ grid_reflow(struct grid *gd, u_int sx)
|
||||
struct grid *target;
|
||||
struct grid_line *gl;
|
||||
struct grid_cell gc;
|
||||
u_int yy, width, i, at, first;
|
||||
u_int yy, width, i, at;
|
||||
|
||||
/*
|
||||
* Create a destination grid. This is just used as a container for the
|
||||
@ -1294,13 +1297,12 @@ grid_reflow(struct grid *gd, u_int sx)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Work out the width of this line. first is the width of the
|
||||
* first character, at is the point at which the available
|
||||
* width is hit, and width is the full line width.
|
||||
* Work out the width of this line. at is the point at which
|
||||
* the available width is hit, and width is the full line
|
||||
* width.
|
||||
*/
|
||||
first = at = width = 0;
|
||||
at = width = 0;
|
||||
if (~gl->flags & GRID_LINE_EXTENDED) {
|
||||
first = 1;
|
||||
width = gl->cellused;
|
||||
if (width > sx)
|
||||
at = sx;
|
||||
@ -1309,8 +1311,6 @@ grid_reflow(struct grid *gd, u_int sx)
|
||||
} else {
|
||||
for (i = 0; i < gl->cellused; i++) {
|
||||
grid_get_cell1(gl, i, &gc);
|
||||
if (i == 0)
|
||||
first = gc.data.width;
|
||||
if (at == 0 && width + gc.data.width > sx)
|
||||
at = i;
|
||||
width += gc.data.width;
|
||||
@ -1318,10 +1318,10 @@ grid_reflow(struct grid *gd, u_int sx)
|
||||
}
|
||||
|
||||
/*
|
||||
* If the line is exactly right or the first character is wider
|
||||
* than the target width, just move it across unchanged.
|
||||
* If the line is exactly right, just move it across
|
||||
* unchanged.
|
||||
*/
|
||||
if (width == sx || first > sx) {
|
||||
if (width == sx) {
|
||||
grid_reflow_move(target, gl);
|
||||
continue;
|
||||
}
|
||||
|
@ -555,6 +555,8 @@ input_key(struct screen *s, struct bufferevent *bev, key_code key)
|
||||
case KEYC_SHIFT|KEYC_META|KEYC_CTRL:
|
||||
modifier = '8';
|
||||
break;
|
||||
default:
|
||||
fatalx("invalid key modifiers: %llx", key);
|
||||
}
|
||||
xsnprintf(tmp, sizeof tmp, "\033[%llu;%cu", outkey, modifier);
|
||||
bufferevent_write(bev, tmp, strlen(tmp));
|
||||
|
51
input.c
51
input.c
@ -65,7 +65,7 @@ struct input_param {
|
||||
INPUT_MISSING,
|
||||
INPUT_NUMBER,
|
||||
INPUT_STRING
|
||||
} type;
|
||||
} type;
|
||||
union {
|
||||
int num;
|
||||
char *str;
|
||||
@ -81,7 +81,7 @@ struct input_ctx {
|
||||
struct input_cell cell;
|
||||
|
||||
struct input_cell old_cell;
|
||||
u_int old_cx;
|
||||
u_int old_cx;
|
||||
u_int old_cy;
|
||||
int old_mode;
|
||||
|
||||
@ -121,7 +121,7 @@ struct input_ctx {
|
||||
* All input received since we were last in the ground state. Sent to
|
||||
* control clients on connection.
|
||||
*/
|
||||
struct evbuffer *since_ground;
|
||||
struct evbuffer *since_ground;
|
||||
};
|
||||
|
||||
/* Helper functions. */
|
||||
@ -1545,6 +1545,10 @@ input_csi_dispatch(struct input_ctx *ictx)
|
||||
if (n == -1)
|
||||
break;
|
||||
|
||||
m = screen_size_x(s) - s->cx;
|
||||
if (n > m)
|
||||
n = m;
|
||||
|
||||
if (ictx->last == -1)
|
||||
break;
|
||||
ictx->ch = ictx->last;
|
||||
@ -1867,6 +1871,7 @@ input_csi_dispatch_winops(struct input_ctx *ictx)
|
||||
case 2:
|
||||
screen_pop_title(sctx->s);
|
||||
if (wp != NULL) {
|
||||
notify_pane("pane-title-changed", wp);
|
||||
server_redraw_window_borders(wp->window);
|
||||
server_status_window(wp->window);
|
||||
}
|
||||
@ -2266,6 +2271,7 @@ input_exit_osc(struct input_ctx *ictx)
|
||||
case 0:
|
||||
case 2:
|
||||
if (screen_set_title(sctx->s, p) && wp != NULL) {
|
||||
notify_pane("pane-title-changed", wp);
|
||||
server_redraw_window_borders(wp->window);
|
||||
server_status_window(wp->window);
|
||||
}
|
||||
@ -2331,6 +2337,7 @@ input_exit_apc(struct input_ctx *ictx)
|
||||
log_debug("%s: \"%s\"", __func__, ictx->input_buf);
|
||||
|
||||
if (screen_set_title(sctx->s, ictx->input_buf) && wp != NULL) {
|
||||
notify_pane("pane-title-changed", wp);
|
||||
server_redraw_window_borders(wp->window);
|
||||
server_status_window(wp->window);
|
||||
}
|
||||
@ -2461,13 +2468,31 @@ input_osc_parse_colour(const char *p, u_int *r, u_int *g, u_int *b)
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Reply to a colour request. */
|
||||
static void
|
||||
input_osc_colour_reply(struct input_ctx *ictx, u_int n, int c)
|
||||
{
|
||||
u_char r, g, b;
|
||||
const char *end;
|
||||
|
||||
if (c == 8 || (~c & COLOUR_FLAG_RGB))
|
||||
return;
|
||||
colour_split_rgb(c, &r, &g, &b);
|
||||
|
||||
if (ictx->input_end == INPUT_END_BEL)
|
||||
end = "\007";
|
||||
else
|
||||
end = "\033\\";
|
||||
input_reply(ictx, "\033]%u;rgb:%02hhx/%02hhx/%02hhx%s", n, r, g, b, end);
|
||||
}
|
||||
|
||||
/* Handle the OSC 4 sequence for setting (multiple) palette entries. */
|
||||
static void
|
||||
input_osc_4(struct input_ctx *ictx, const char *p)
|
||||
{
|
||||
struct window_pane *wp = ictx->wp;
|
||||
char *copy, *s, *next = NULL;
|
||||
long idx;
|
||||
long idx;
|
||||
u_int r, g, b;
|
||||
|
||||
if (wp == NULL)
|
||||
@ -2499,17 +2524,22 @@ bad:
|
||||
free(copy);
|
||||
}
|
||||
|
||||
/* Handle the OSC 10 sequence for setting foreground colour. */
|
||||
/* Handle the OSC 10 sequence for setting and querying foreground colour. */
|
||||
static void
|
||||
input_osc_10(struct input_ctx *ictx, const char *p)
|
||||
{
|
||||
struct window_pane *wp = ictx->wp;
|
||||
struct grid_cell defaults;
|
||||
u_int r, g, b;
|
||||
|
||||
if (wp == NULL)
|
||||
return;
|
||||
if (strcmp(p, "?") == 0)
|
||||
|
||||
if (strcmp(p, "?") == 0) {
|
||||
tty_default_colours(&defaults, wp);
|
||||
input_osc_colour_reply(ictx, 10, defaults.fg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!input_osc_parse_colour(p, &r, &g, &b))
|
||||
goto bad;
|
||||
@ -2522,17 +2552,22 @@ bad:
|
||||
log_debug("bad OSC 10: %s", p);
|
||||
}
|
||||
|
||||
/* Handle the OSC 11 sequence for setting background colour. */
|
||||
/* Handle the OSC 11 sequence for setting and querying background colour. */
|
||||
static void
|
||||
input_osc_11(struct input_ctx *ictx, const char *p)
|
||||
{
|
||||
struct window_pane *wp = ictx->wp;
|
||||
struct grid_cell defaults;
|
||||
u_int r, g, b;
|
||||
|
||||
if (wp == NULL)
|
||||
return;
|
||||
if (strcmp(p, "?") == 0)
|
||||
|
||||
if (strcmp(p, "?") == 0) {
|
||||
tty_default_colours(&defaults, wp);
|
||||
input_osc_colour_reply(ictx, 11, defaults.bg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!input_osc_parse_colour(p, &r, &g, &b))
|
||||
goto bad;
|
||||
|
@ -191,6 +191,16 @@ key_bindings_add(const char *name, key_code key, const char *note, int repeat,
|
||||
table = key_bindings_get_table(name, 1);
|
||||
|
||||
bd = key_bindings_get(table, key & ~KEYC_MASK_FLAGS);
|
||||
if (cmdlist == NULL) {
|
||||
if (bd != NULL) {
|
||||
free((void *)bd->note);
|
||||
if (note != NULL)
|
||||
bd->note = xstrdup(note);
|
||||
else
|
||||
bd->note = NULL;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (bd != NULL) {
|
||||
RB_REMOVE(key_bindings, &table->key_bindings, bd);
|
||||
key_bindings_free(bd);
|
||||
|
25
menu.c
25
menu.c
@ -203,16 +203,28 @@ menu_key_cb(struct client *c, struct key_event *event)
|
||||
m->x > md->px + 4 + menu->width ||
|
||||
m->y < md->py + 1 ||
|
||||
m->y > md->py + 1 + count - 1) {
|
||||
if (MOUSE_RELEASE(m->b))
|
||||
return (1);
|
||||
if (~md->flags & MENU_STAYOPEN) {
|
||||
if (MOUSE_RELEASE(m->b))
|
||||
return (1);
|
||||
} else {
|
||||
if (!MOUSE_RELEASE(m->b) &&
|
||||
MOUSE_WHEEL(m->b) == 0 &&
|
||||
!MOUSE_DRAG(m->b))
|
||||
return (1);
|
||||
}
|
||||
if (md->choice != -1) {
|
||||
md->choice = -1;
|
||||
c->flags |= CLIENT_REDRAWOVERLAY;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
if (MOUSE_RELEASE(m->b))
|
||||
goto chosen;
|
||||
if (~md->flags & MENU_STAYOPEN) {
|
||||
if (MOUSE_RELEASE(m->b))
|
||||
goto chosen;
|
||||
} else {
|
||||
if (MOUSE_WHEEL(m->b) == 0 && !MOUSE_DRAG(m->b))
|
||||
goto chosen;
|
||||
}
|
||||
md->choice = m->y - (md->py + 1);
|
||||
if (md->choice != old)
|
||||
c->flags |= CLIENT_REDRAWOVERLAY;
|
||||
@ -303,8 +315,11 @@ chosen:
|
||||
if (md->choice == -1)
|
||||
return (1);
|
||||
item = &menu->items[md->choice];
|
||||
if (item->name == NULL || *item->name == '-')
|
||||
if (item->name == NULL || *item->name == '-') {
|
||||
if (md->flags & MENU_STAYOPEN)
|
||||
return (0);
|
||||
return (1);
|
||||
}
|
||||
if (md->cb != NULL) {
|
||||
md->cb(md->menu, md->choice, item->key, md->data);
|
||||
md->cb = NULL;
|
||||
|
@ -1176,7 +1176,7 @@ mode_tree_run_command(struct client *c, struct cmd_find_state *fs,
|
||||
if (status == CMD_PARSE_ERROR) {
|
||||
if (c != NULL) {
|
||||
*error = toupper((u_char)*error);
|
||||
status_message_set(c, 1, "%s", error);
|
||||
status_message_set(c, -1, 1, "%s", error);
|
||||
}
|
||||
free(error);
|
||||
}
|
||||
|
@ -170,6 +170,14 @@ static const char *options_table_status_format_default[] = {
|
||||
.separator = "" \
|
||||
}
|
||||
|
||||
/* Map of name conversions. */
|
||||
const struct options_name_map options_other_names[] = {
|
||||
{ "display-panes-color", "display-panes-colour" },
|
||||
{ "display-panes-active-color", "display-panes-active-colour" },
|
||||
{ "clock-mode-color", "clock-mode-colour" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
/* Top-level options. */
|
||||
const struct options_table_entry options_table[] = {
|
||||
/* Server options. */
|
||||
@ -1120,6 +1128,7 @@ const struct options_table_entry options_table[] = {
|
||||
OPTIONS_TABLE_PANE_HOOK("pane-focus-out", ""),
|
||||
OPTIONS_TABLE_PANE_HOOK("pane-mode-changed", ""),
|
||||
OPTIONS_TABLE_PANE_HOOK("pane-set-clipboard", ""),
|
||||
OPTIONS_TABLE_PANE_HOOK("pane-title-changed", ""),
|
||||
OPTIONS_TABLE_HOOK("session-closed", ""),
|
||||
OPTIONS_TABLE_HOOK("session-created", ""),
|
||||
OPTIONS_TABLE_HOOK("session-renamed", ""),
|
||||
|
42
options.c
42
options.c
@ -95,6 +95,18 @@ options_cmp(struct options_entry *lhs, struct options_entry *rhs)
|
||||
return (strcmp(lhs->name, rhs->name));
|
||||
}
|
||||
|
||||
static const char *
|
||||
options_map_name(const char *name)
|
||||
{
|
||||
const struct options_name_map *map;
|
||||
|
||||
for (map = options_other_names; map->from != NULL; map++) {
|
||||
if (strcmp(map->from, name) == 0)
|
||||
return (map->to);
|
||||
}
|
||||
return (name);
|
||||
}
|
||||
|
||||
static const struct options_table_entry *
|
||||
options_parent_table_entry(struct options *oo, const char *s)
|
||||
{
|
||||
@ -204,10 +216,14 @@ options_next(struct options_entry *o)
|
||||
struct options_entry *
|
||||
options_get_only(struct options *oo, const char *name)
|
||||
{
|
||||
struct options_entry o;
|
||||
struct options_entry o = { .name = name }, *found;
|
||||
|
||||
o.name = name;
|
||||
return (RB_FIND(options_tree, &oo->tree, &o));
|
||||
found = RB_FIND(options_tree, &oo->tree, &o);
|
||||
if (found == NULL) {
|
||||
o.name = options_map_name(name);
|
||||
return (RB_FIND(options_tree, &oo->tree, &o));
|
||||
}
|
||||
return (found);
|
||||
}
|
||||
|
||||
struct options_entry *
|
||||
@ -608,19 +624,21 @@ char *
|
||||
options_match(const char *s, int *idx, int *ambiguous)
|
||||
{
|
||||
const struct options_table_entry *oe, *found;
|
||||
char *name;
|
||||
char *parsed;
|
||||
const char *name;
|
||||
size_t namelen;
|
||||
|
||||
name = options_parse(s, idx);
|
||||
if (name == NULL)
|
||||
parsed = options_parse(s, idx);
|
||||
if (parsed == NULL)
|
||||
return (NULL);
|
||||
namelen = strlen(name);
|
||||
|
||||
if (*name == '@') {
|
||||
if (*parsed == '@') {
|
||||
*ambiguous = 0;
|
||||
return (name);
|
||||
return (parsed);
|
||||
}
|
||||
|
||||
name = options_map_name(parsed);
|
||||
namelen = strlen(name);
|
||||
|
||||
found = NULL;
|
||||
for (oe = options_table; oe->name != NULL; oe++) {
|
||||
if (strcmp(oe->name, name) == 0) {
|
||||
@ -630,13 +648,13 @@ options_match(const char *s, int *idx, int *ambiguous)
|
||||
if (strncmp(oe->name, name, namelen) == 0) {
|
||||
if (found != NULL) {
|
||||
*ambiguous = 1;
|
||||
free(name);
|
||||
free(parsed);
|
||||
return (NULL);
|
||||
}
|
||||
found = oe;
|
||||
}
|
||||
}
|
||||
free(name);
|
||||
free(parsed);
|
||||
if (found == NULL) {
|
||||
*ambiguous = 0;
|
||||
return (NULL);
|
||||
|
2
popup.c
2
popup.c
@ -261,7 +261,7 @@ popup_handle_drag(struct client *c, struct popup_data *pd,
|
||||
pd->sx = m->x - pd->px;
|
||||
pd->sy = m->y - pd->py;
|
||||
|
||||
screen_resize(&pd->s, pd->sx, pd->sy, 0);
|
||||
screen_resize(&pd->s, pd->sx - 2, pd->sy - 2, 0);
|
||||
if (pd->ictx == NULL)
|
||||
popup_write_screen(c, pd);
|
||||
else if (pd->job != NULL)
|
||||
|
1
proc.c
1
proc.c
@ -239,6 +239,7 @@ proc_set_signals(struct tmuxproc *tp, void (*signalcb)(int))
|
||||
sigaction(SIGTSTP, &sa, NULL);
|
||||
sigaction(SIGTTIN, &sa, NULL);
|
||||
sigaction(SIGTTOU, &sa, NULL);
|
||||
sigaction(SIGQUIT, &sa, NULL);
|
||||
|
||||
signal_set(&tp->ev_sigint, SIGINT, proc_signal_cb, tp);
|
||||
signal_add(&tp->ev_sigint, NULL);
|
||||
|
93
regress/style-trim.sh
Normal file
93
regress/style-trim.sh
Normal file
@ -0,0 +1,93 @@
|
||||
#!/bin/sh
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
TMUX2="$TEST_TMUX -Ltest2"
|
||||
$TMUX2 kill-server 2>/dev/null
|
||||
|
||||
$TMUX2 -f/dev/null new -d "$TMUX -f/dev/null new"
|
||||
sleep 2
|
||||
$TMUX set -g status-style fg=default,bg=default
|
||||
|
||||
check() {
|
||||
v=$($TMUX display -p "$1")
|
||||
$TMUX set -g status-format[0] "$1"
|
||||
sleep 1
|
||||
r=$($TMUX2 capturep -Cep|tail -1|sed 's|\\033\[||g')
|
||||
|
||||
#printf "$1 = [$v = $2] [$r = $3]"
|
||||
if [ "$v" = "$2" -a "$r" = "$3" ]; then
|
||||
: #printf " good\n"
|
||||
else
|
||||
#printf " \033[31mbad\033[0m\n"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# drawn as #0
|
||||
$TMUX setenv -g V '#0'
|
||||
check '#{V} #{w:V}' '#0 2' '#0 2'
|
||||
check '#{=3:V}' '#0' '#0'
|
||||
check '#{=-3:V}' '#0' '#0'
|
||||
|
||||
# drawn as #0
|
||||
$TMUX setenv -g V '###[bg=yellow]0'
|
||||
check '#{V} #{w:V}' '###[bg=yellow]0 2' '#43m0 249m'
|
||||
check '#{=3:V}' '###[bg=yellow]0' '#43m049m'
|
||||
check '#{=-3:V}' '###[bg=yellow]0' '#43m049m'
|
||||
|
||||
# drawn as #0123456
|
||||
$TMUX setenv -g V '#0123456'
|
||||
check '#{V} #{w:V}' '#0123456 8' '#0123456 8'
|
||||
check '#{=3:V}' '#01' '#01'
|
||||
check '#{=-3:V}' '456' '456'
|
||||
|
||||
# drawn as ##0123456
|
||||
$TMUX setenv -g V '##0123456'
|
||||
check '#{V} #{w:V}' '##0123456 9' '##0123456 9'
|
||||
check '#{=3:V}' '##0' '##0'
|
||||
check '#{=-3:V}' '456' '456'
|
||||
|
||||
# drawn as ###0123456
|
||||
$TMUX setenv -g V '###0123456'
|
||||
check '#{V} #{w:V}' '###0123456 10' '###0123456 10'
|
||||
check '#{=3:V}' '###' '###'
|
||||
check '#{=-3:V}' '456' '456'
|
||||
|
||||
# drawn as 0123456
|
||||
$TMUX setenv -g V '#[bg=yellow]0123456'
|
||||
check '#{V} #{w:V}' '#[bg=yellow]0123456 7' '43m0123456 749m'
|
||||
check '#{=3:V}' '#[bg=yellow]012' '43m01249m'
|
||||
check '#{=-3:V}' '#[bg=yellow]456' '43m45649m'
|
||||
|
||||
# drawn as #[bg=yellow]0123456
|
||||
$TMUX setenv -g V '##[bg=yellow]0123456'
|
||||
check '#{V} #{w:V}' '##[bg=yellow]0123456 19' '#[bg=yellow]0123456 19'
|
||||
check '#{=3:V}' '##[b' '#[b'
|
||||
check '#{=-3:V}' '456' '456'
|
||||
|
||||
# drawn as #0123456
|
||||
$TMUX setenv -g V '###[bg=yellow]0123456'
|
||||
check '#{V} #{w:V}' '###[bg=yellow]0123456 8' '#43m0123456 849m'
|
||||
check '#{=3:V}' '###[bg=yellow]01' '#43m0149m'
|
||||
check '#{=-3:V}' '#[bg=yellow]456' '43m45649m'
|
||||
|
||||
# drawn as ##[bg=yellow]0123456
|
||||
$TMUX setenv -g V '####[bg=yellow]0123456'
|
||||
check '#{V} #{w:V}' '####[bg=yellow]0123456 20' '##[bg=yellow]0123456 20'
|
||||
check '#{=3:V}' '####[' '##['
|
||||
check '#{=-3:V}' '456' '456'
|
||||
|
||||
# drawn as ###0123456
|
||||
$TMUX setenv -g V '#####[bg=yellow]0123456'
|
||||
check '#{V} #{w:V}' '#####[bg=yellow]0123456 9' '##43m0123456 949m'
|
||||
check '#{=3:V}' '#####[bg=yellow]0' '##43m049m'
|
||||
check '#{=-3:V}' '#[bg=yellow]456' '43m45649m'
|
||||
|
||||
$TMUX kill-server 2>/dev/null
|
||||
$TMUX2 kill-server 2>/dev/null
|
||||
exit 0
|
375
resize.c
375
resize.c
@ -92,130 +92,156 @@ ignore_client_size(struct client *c)
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
default_window_size(struct client *c, struct session *s, struct window *w,
|
||||
u_int *sx, u_int *sy, u_int *xpixel, u_int *ypixel, int type)
|
||||
static u_int
|
||||
clients_with_window(struct window *w)
|
||||
{
|
||||
struct client *loop;
|
||||
u_int cx, cy, n;
|
||||
const char *value;
|
||||
u_int n = 0;
|
||||
|
||||
if (type == -1)
|
||||
type = options_get_number(global_w_options, "window-size");
|
||||
switch (type) {
|
||||
case WINDOW_SIZE_LARGEST:
|
||||
TAILQ_FOREACH(loop, &clients, entry) {
|
||||
if (ignore_client_size(loop) || !session_has(loop->session, w))
|
||||
continue;
|
||||
if (++n > 1)
|
||||
break;
|
||||
}
|
||||
return (n);
|
||||
}
|
||||
|
||||
static int
|
||||
clients_calculate_size(int type, int current, struct session *s,
|
||||
struct window *w, int (*skip_client)(struct client *, int, int,
|
||||
struct session *, struct window *), u_int *sx, u_int *sy, u_int *xpixel,
|
||||
u_int *ypixel)
|
||||
{
|
||||
struct client *loop;
|
||||
u_int cx, cy, n = 0;
|
||||
|
||||
/* Manual windows do not have their size changed based on a client. */
|
||||
if (type == WINDOW_SIZE_MANUAL)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* Start comparing with 0 for largest and UINT_MAX for smallest or
|
||||
* latest.
|
||||
*/
|
||||
if (type == WINDOW_SIZE_LARGEST)
|
||||
*sx = *sy = 0;
|
||||
*xpixel = *ypixel = 0;
|
||||
TAILQ_FOREACH(loop, &clients, entry) {
|
||||
if (ignore_client_size(loop))
|
||||
continue;
|
||||
if (w != NULL && !session_has(loop->session, w))
|
||||
continue;
|
||||
if (w == NULL && loop->session != s)
|
||||
continue;
|
||||
else
|
||||
*sx = *sy = UINT_MAX;
|
||||
*xpixel = *ypixel = 0;
|
||||
|
||||
cx = loop->tty.sx;
|
||||
cy = loop->tty.sy - status_line_size(loop);
|
||||
/*
|
||||
* For latest, count the number of clients with this window. We only
|
||||
* care if there is more than one.
|
||||
*/
|
||||
if (type == WINDOW_SIZE_LATEST)
|
||||
n = clients_with_window(w);
|
||||
|
||||
/* Loop over the clients and work out the size. */
|
||||
TAILQ_FOREACH(loop, &clients, entry) {
|
||||
if (ignore_client_size(loop))
|
||||
continue;
|
||||
if (skip_client(loop, type, current, s, w))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* If there are multiple clients attached, only accept the
|
||||
* latest client; otherwise let the only client be chosen as
|
||||
* for smallest.
|
||||
*/
|
||||
if (type == WINDOW_SIZE_LATEST && n > 1 && loop != w->latest)
|
||||
continue;
|
||||
|
||||
/* Work out this client's size. */
|
||||
cx = loop->tty.sx;
|
||||
cy = loop->tty.sy - status_line_size(loop);
|
||||
|
||||
/*
|
||||
* If it is larger or smaller than the best so far, update the
|
||||
* new size.
|
||||
*/
|
||||
if (type == WINDOW_SIZE_LARGEST) {
|
||||
if (cx > *sx)
|
||||
*sx = cx;
|
||||
if (cy > *sy)
|
||||
*sy = cy;
|
||||
|
||||
if (loop->tty.xpixel > *xpixel &&
|
||||
loop->tty.ypixel > *ypixel) {
|
||||
*xpixel = loop->tty.xpixel;
|
||||
*ypixel = loop->tty.ypixel;
|
||||
}
|
||||
}
|
||||
if (*sx == 0 || *sy == 0)
|
||||
goto manual;
|
||||
break;
|
||||
case WINDOW_SIZE_SMALLEST:
|
||||
*sx = *sy = UINT_MAX;
|
||||
*xpixel = *ypixel = 0;
|
||||
TAILQ_FOREACH(loop, &clients, entry) {
|
||||
if (ignore_client_size(loop))
|
||||
continue;
|
||||
if (w != NULL && !session_has(loop->session, w))
|
||||
continue;
|
||||
if (w == NULL && loop->session != s)
|
||||
continue;
|
||||
|
||||
cx = loop->tty.sx;
|
||||
cy = loop->tty.sy - status_line_size(loop);
|
||||
|
||||
} else {
|
||||
if (cx < *sx)
|
||||
*sx = cx;
|
||||
if (cy < *sy)
|
||||
*sy = cy;
|
||||
|
||||
if (loop->tty.xpixel > *xpixel &&
|
||||
loop->tty.ypixel > *ypixel) {
|
||||
*xpixel = loop->tty.xpixel;
|
||||
*ypixel = loop->tty.ypixel;
|
||||
}
|
||||
}
|
||||
if (*sx == UINT_MAX || *sy == UINT_MAX)
|
||||
goto manual;
|
||||
break;
|
||||
case WINDOW_SIZE_LATEST:
|
||||
if (loop->tty.xpixel > *xpixel && loop->tty.ypixel > *ypixel) {
|
||||
*xpixel = loop->tty.xpixel;
|
||||
*ypixel = loop->tty.ypixel;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return whether a suitable size was found. */
|
||||
if (type == WINDOW_SIZE_LARGEST)
|
||||
return (*sx != 0 && *sy != 0);
|
||||
return (*sx != UINT_MAX && *sy != UINT_MAX);
|
||||
}
|
||||
|
||||
static int
|
||||
default_window_size_skip_client (struct client *loop, int type,
|
||||
__unused int current, struct session *s, struct window *w)
|
||||
{
|
||||
/*
|
||||
* Latest checks separately, so do not check here. Otherwise only
|
||||
* include clients where the session contains the window or where the
|
||||
* session is the given session.
|
||||
*/
|
||||
if (type == WINDOW_SIZE_LATEST)
|
||||
return (0);
|
||||
if (w != NULL && !session_has(loop->session, w))
|
||||
return (1);
|
||||
if (w == NULL && loop->session != s)
|
||||
return (1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
default_window_size(struct client *c, struct session *s, struct window *w,
|
||||
u_int *sx, u_int *sy, u_int *xpixel, u_int *ypixel, int type)
|
||||
{
|
||||
const char *value;
|
||||
|
||||
/* Get type if not provided. */
|
||||
if (type == -1)
|
||||
type = options_get_number(global_w_options, "window-size");
|
||||
|
||||
/*
|
||||
* Latest clients can use the given client if suitable. If there is no
|
||||
* client and no window, use the default size as for manual type.
|
||||
*/
|
||||
if (type == WINDOW_SIZE_LATEST) {
|
||||
if (c != NULL && !ignore_client_size(c)) {
|
||||
*sx = c->tty.sx;
|
||||
*sy = c->tty.sy - status_line_size(c);
|
||||
*xpixel = c->tty.xpixel;
|
||||
*ypixel = c->tty.ypixel;
|
||||
} else {
|
||||
if (w == NULL)
|
||||
goto manual;
|
||||
n = 0;
|
||||
TAILQ_FOREACH(loop, &clients, entry) {
|
||||
if (!ignore_client_size(loop) &&
|
||||
session_has(loop->session, w)) {
|
||||
if (++n > 1)
|
||||
break;
|
||||
}
|
||||
}
|
||||
*sx = *sy = UINT_MAX;
|
||||
*xpixel = *ypixel = 0;
|
||||
TAILQ_FOREACH(loop, &clients, entry) {
|
||||
if (ignore_client_size(loop))
|
||||
continue;
|
||||
if (n > 1 && loop != w->latest)
|
||||
continue;
|
||||
s = loop->session;
|
||||
|
||||
cx = loop->tty.sx;
|
||||
cy = loop->tty.sy - status_line_size(loop);
|
||||
|
||||
if (cx < *sx)
|
||||
*sx = cx;
|
||||
if (cy < *sy)
|
||||
*sy = cy;
|
||||
|
||||
if (loop->tty.xpixel > *xpixel &&
|
||||
loop->tty.ypixel > *ypixel) {
|
||||
*xpixel = loop->tty.xpixel;
|
||||
*ypixel = loop->tty.ypixel;
|
||||
}
|
||||
}
|
||||
if (*sx == UINT_MAX || *sy == UINT_MAX)
|
||||
goto manual;
|
||||
*ypixel = c->tty.ypixel;
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case WINDOW_SIZE_MANUAL:
|
||||
goto manual;
|
||||
if (w == NULL)
|
||||
type = WINDOW_SIZE_MANUAL;
|
||||
}
|
||||
goto done;
|
||||
|
||||
manual:
|
||||
value = options_get_string(s->options, "default-size");
|
||||
if (sscanf(value, "%ux%u", sx, sy) != 2) {
|
||||
*sx = 80;
|
||||
*sy = 24;
|
||||
/*
|
||||
* Look for a client to base the size on. If none exists (or the type
|
||||
* is manual), use the default-size option.
|
||||
*/
|
||||
if (!clients_calculate_size(type, 0, s, w,
|
||||
default_window_size_skip_client, sx, sy, xpixel, ypixel)) {
|
||||
value = options_get_string(s->options, "default-size");
|
||||
if (sscanf(value, "%ux%u", sx, sy) != 2) {
|
||||
*sx = 80;
|
||||
*sy = 24;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
/* Make sure the limits are enforced. */
|
||||
if (*sx < WINDOW_MINIMUM)
|
||||
*sx = WINDOW_MINIMUM;
|
||||
if (*sx > WINDOW_MAXIMUM)
|
||||
@ -226,127 +252,50 @@ done:
|
||||
*sy = WINDOW_MAXIMUM;
|
||||
}
|
||||
|
||||
static int
|
||||
recalculate_size_skip_client(struct client *loop, __unused int type,
|
||||
int current, __unused struct session *s, struct window *w)
|
||||
{
|
||||
/*
|
||||
* If the current flag is set, then skip any client where this window
|
||||
* is not the current window - this is used for aggressive-resize.
|
||||
* Otherwise skip any session that doesn't contain the window.
|
||||
*/
|
||||
if (current)
|
||||
return (loop->session->curw->window != w);
|
||||
return (session_has(loop->session, w) == 0);
|
||||
}
|
||||
|
||||
void
|
||||
recalculate_size(struct window *w, int now)
|
||||
{
|
||||
struct session *s;
|
||||
struct client *c;
|
||||
u_int sx, sy, cx, cy, xpixel = 0, ypixel = 0, n;
|
||||
int type, current, has, changed;
|
||||
u_int sx, sy, xpixel = 0, ypixel = 0;
|
||||
int type, current, changed;
|
||||
|
||||
/*
|
||||
* Do not attempt to resize windows which have no pane, they must be on
|
||||
* the way to destruction.
|
||||
*/
|
||||
if (w->active == NULL)
|
||||
return;
|
||||
log_debug("%s: @%u is %u,%u", __func__, w->id, w->sx, w->sy);
|
||||
|
||||
/*
|
||||
* Type is manual, smallest, largest, latest. Current is the
|
||||
* aggressive-resize option (do not resize based on clients where the
|
||||
* window is not the current window).
|
||||
*/
|
||||
type = options_get_number(w->options, "window-size");
|
||||
current = options_get_number(w->options, "aggressive-resize");
|
||||
|
||||
changed = 1;
|
||||
switch (type) {
|
||||
case WINDOW_SIZE_LARGEST:
|
||||
sx = sy = 0;
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (ignore_client_size(c))
|
||||
continue;
|
||||
s = c->session;
|
||||
/* Look for a suitable client and get the new size. */
|
||||
changed = clients_calculate_size(type, current, NULL, w,
|
||||
recalculate_size_skip_client, &sx, &sy, &xpixel, &ypixel);
|
||||
|
||||
if (current)
|
||||
has = (s->curw->window == w);
|
||||
else
|
||||
has = session_has(s, w);
|
||||
if (!has)
|
||||
continue;
|
||||
|
||||
cx = c->tty.sx;
|
||||
cy = c->tty.sy - status_line_size(c);
|
||||
|
||||
if (cx > sx)
|
||||
sx = cx;
|
||||
if (cy > sy)
|
||||
sy = cy;
|
||||
|
||||
if (c->tty.xpixel > xpixel && c->tty.ypixel > ypixel) {
|
||||
xpixel = c->tty.xpixel;
|
||||
ypixel = c->tty.ypixel;
|
||||
}
|
||||
}
|
||||
if (sx == 0 || sy == 0)
|
||||
changed = 0;
|
||||
break;
|
||||
case WINDOW_SIZE_SMALLEST:
|
||||
sx = sy = UINT_MAX;
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (ignore_client_size(c))
|
||||
continue;
|
||||
s = c->session;
|
||||
|
||||
if (current)
|
||||
has = (s->curw->window == w);
|
||||
else
|
||||
has = session_has(s, w);
|
||||
if (!has)
|
||||
continue;
|
||||
|
||||
cx = c->tty.sx;
|
||||
cy = c->tty.sy - status_line_size(c);
|
||||
|
||||
if (cx < sx)
|
||||
sx = cx;
|
||||
if (cy < sy)
|
||||
sy = cy;
|
||||
|
||||
if (c->tty.xpixel > xpixel && c->tty.ypixel > ypixel) {
|
||||
xpixel = c->tty.xpixel;
|
||||
ypixel = c->tty.ypixel;
|
||||
}
|
||||
}
|
||||
if (sx == UINT_MAX || sy == UINT_MAX)
|
||||
changed = 0;
|
||||
break;
|
||||
case WINDOW_SIZE_LATEST:
|
||||
n = 0;
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (!ignore_client_size(c) &&
|
||||
session_has(c->session, w)) {
|
||||
if (++n > 1)
|
||||
break;
|
||||
}
|
||||
}
|
||||
sx = sy = UINT_MAX;
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (ignore_client_size(c))
|
||||
continue;
|
||||
if (n > 1 && c != w->latest)
|
||||
continue;
|
||||
s = c->session;
|
||||
|
||||
if (current)
|
||||
has = (s->curw->window == w);
|
||||
else
|
||||
has = session_has(s, w);
|
||||
if (!has)
|
||||
continue;
|
||||
|
||||
cx = c->tty.sx;
|
||||
cy = c->tty.sy - status_line_size(c);
|
||||
|
||||
if (cx < sx)
|
||||
sx = cx;
|
||||
if (cy < sy)
|
||||
sy = cy;
|
||||
|
||||
if (c->tty.xpixel > xpixel && c->tty.ypixel > ypixel) {
|
||||
xpixel = c->tty.xpixel;
|
||||
ypixel = c->tty.ypixel;
|
||||
}
|
||||
}
|
||||
if (sx == UINT_MAX || sy == UINT_MAX)
|
||||
changed = 0;
|
||||
break;
|
||||
case WINDOW_SIZE_MANUAL:
|
||||
changed = 0;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Make sure the size has actually changed. If the window has already
|
||||
* got a resize scheduled, then use the new size; otherwise the old.
|
||||
*/
|
||||
if (w->flags & WINDOW_RESIZE) {
|
||||
if (!now && changed && w->new_sx == sx && w->new_sy == sy)
|
||||
changed = 0;
|
||||
@ -355,10 +304,20 @@ recalculate_size(struct window *w, int now)
|
||||
changed = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the size hasn't changed, update the window offset but not the
|
||||
* size.
|
||||
*/
|
||||
if (!changed) {
|
||||
tty_update_window_offset(w);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the now flag is set or if the window is sized manually, change
|
||||
* the size immediately. Otherwise set the flag and it will be done
|
||||
* later.
|
||||
*/
|
||||
log_debug("%s: @%u new size %u,%u", __func__, w->id, sx, sy);
|
||||
if (now || type == WINDOW_SIZE_MANUAL)
|
||||
resize_window(w, sx, sy, xpixel, ypixel);
|
||||
|
2
screen.c
2
screen.c
@ -78,6 +78,7 @@ screen_init(struct screen *s, u_int sx, u_int sy, u_int hlimit)
|
||||
|
||||
s->title = xstrdup("");
|
||||
s->titles = NULL;
|
||||
s->path = NULL;
|
||||
|
||||
s->cstyle = 0;
|
||||
s->ccolour = xstrdup("");
|
||||
@ -120,6 +121,7 @@ screen_free(struct screen *s)
|
||||
{
|
||||
free(s->sel);
|
||||
free(s->tabs);
|
||||
free(s->path);
|
||||
free(s->title);
|
||||
free(s->ccolour);
|
||||
|
||||
|
@ -1588,10 +1588,6 @@ server_client_check_pane_focus(struct window_pane *wp)
|
||||
if (wp->window->active != wp)
|
||||
goto not_focused;
|
||||
|
||||
/* If we're in a mode, we're not focused. */
|
||||
if (wp->screen != &wp->base)
|
||||
goto not_focused;
|
||||
|
||||
/*
|
||||
* If our window is the current window in any focused clients with an
|
||||
* attached session, we're focused.
|
||||
@ -1660,8 +1656,6 @@ server_client_reset_state(struct client *c)
|
||||
s = wp->screen;
|
||||
if (s != NULL)
|
||||
mode = s->mode;
|
||||
if (c->prompt_string != NULL || c->message_string != NULL)
|
||||
mode &= ~MODE_CURSOR;
|
||||
log_debug("%s: client %s mode %x", __func__, c->name, mode);
|
||||
|
||||
/* Reset region and margin. */
|
||||
@ -1693,8 +1687,8 @@ server_client_reset_state(struct client *c)
|
||||
* mode.
|
||||
*/
|
||||
if (options_get_number(oo, "mouse")) {
|
||||
mode &= ~ALL_MOUSE_MODES;
|
||||
if (c->overlay_draw == NULL) {
|
||||
mode &= ~ALL_MOUSE_MODES;
|
||||
TAILQ_FOREACH(loop, &w->panes, entry) {
|
||||
if (loop->screen->mode & MODE_MOUSE_ALL)
|
||||
mode |= MODE_MOUSE_ALL;
|
||||
@ -1985,6 +1979,7 @@ server_client_dispatch(struct imsg *imsg, void *arg)
|
||||
switch (imsg->hdr.type) {
|
||||
case MSG_IDENTIFY_FEATURES:
|
||||
case MSG_IDENTIFY_FLAGS:
|
||||
case MSG_IDENTIFY_LONGFLAGS:
|
||||
case MSG_IDENTIFY_TERM:
|
||||
case MSG_IDENTIFY_TTYNAME:
|
||||
case MSG_IDENTIFY_CWD:
|
||||
@ -2028,7 +2023,7 @@ server_client_dispatch(struct imsg *imsg, void *arg)
|
||||
break;
|
||||
c->flags &= ~CLIENT_SUSPENDED;
|
||||
|
||||
if (c->fd == -1) /* exited in the meantime */
|
||||
if (c->fd == -1 || c->session == NULL) /* exited already */
|
||||
break;
|
||||
s = c->session;
|
||||
|
||||
@ -2143,6 +2138,7 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg)
|
||||
const char *data, *home;
|
||||
size_t datalen;
|
||||
int flags, feat;
|
||||
uint64_t longflags;
|
||||
char *name;
|
||||
|
||||
if (c->flags & CLIENT_IDENTIFIED)
|
||||
@ -2167,6 +2163,14 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg)
|
||||
c->flags |= flags;
|
||||
log_debug("client %p IDENTIFY_FLAGS %#x", c, flags);
|
||||
break;
|
||||
case MSG_IDENTIFY_LONGFLAGS:
|
||||
if (datalen != sizeof longflags)
|
||||
fatalx("bad MSG_IDENTIFY_LONGFLAGS size");
|
||||
memcpy(&longflags, data, sizeof longflags);
|
||||
c->flags |= longflags;
|
||||
log_debug("client %p IDENTIFY_LONGFLAGS %#llx", c,
|
||||
(unsigned long long)longflags);
|
||||
break;
|
||||
case MSG_IDENTIFY_TERM:
|
||||
if (datalen == 0 || data[datalen - 1] != '\0')
|
||||
fatalx("bad MSG_IDENTIFY_TERM string");
|
||||
|
@ -342,6 +342,7 @@ server_destroy_pane(struct window_pane *wp, int notify)
|
||||
|
||||
time(&t);
|
||||
ctime_r(&t, tim);
|
||||
tim[strcspn(tim, "\n")] = '\0';
|
||||
|
||||
if (WIFEXITED(wp->status)) {
|
||||
screen_write_nputs(&ctx, -1, &gc,
|
||||
|
8
server.c
8
server.c
@ -157,7 +157,7 @@ server_start(struct tmuxproc *client, int flags, struct event_base *base,
|
||||
{
|
||||
int pair[2];
|
||||
sigset_t set, oldset;
|
||||
struct client *c;
|
||||
struct client *c = NULL;
|
||||
char *cause = NULL;
|
||||
|
||||
sigfillset(&set);
|
||||
@ -223,9 +223,11 @@ server_start(struct tmuxproc *client, int flags, struct event_base *base,
|
||||
}
|
||||
|
||||
if (cause != NULL) {
|
||||
cmdq_append(c, cmdq_get_error(cause));
|
||||
if (c != NULL) {
|
||||
cmdq_append(c, cmdq_get_error(cause));
|
||||
c->flags |= CLIENT_EXIT;
|
||||
}
|
||||
free(cause);
|
||||
c->flags |= CLIENT_EXIT;
|
||||
}
|
||||
|
||||
server_add_accept(0);
|
||||
|
12
status.c
12
status.c
@ -423,11 +423,11 @@ status_redraw(struct client *c)
|
||||
|
||||
/* Set a status line message. */
|
||||
void
|
||||
status_message_set(struct client *c, int ignore_styles, const char *fmt, ...)
|
||||
status_message_set(struct client *c, int delay, int ignore_styles,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
struct timeval tv;
|
||||
va_list ap;
|
||||
int delay;
|
||||
|
||||
status_message_clear(c);
|
||||
status_push_screen(c);
|
||||
@ -439,7 +439,12 @@ status_message_set(struct client *c, int ignore_styles, const char *fmt, ...)
|
||||
|
||||
server_add_message("%s message: %s", c->name, c->message_string);
|
||||
|
||||
delay = options_get_number(c->session->options, "display-time");
|
||||
/*
|
||||
* With delay -1, the display-time option is used; zero means wait for
|
||||
* key press; more than zero is the actual delay time in milliseconds.
|
||||
*/
|
||||
if (delay == -1)
|
||||
delay = options_get_number(c->session->options, "display-time");
|
||||
if (delay > 0) {
|
||||
tv.tv_sec = delay / 1000;
|
||||
tv.tv_usec = (delay % 1000) * 1000L;
|
||||
@ -447,6 +452,7 @@ status_message_set(struct client *c, int ignore_styles, const char *fmt, ...)
|
||||
if (event_initialized(&c->message_timer))
|
||||
evtimer_del(&c->message_timer);
|
||||
evtimer_set(&c->message_timer, status_message_callback, c);
|
||||
|
||||
evtimer_add(&c->message_timer, &tv);
|
||||
}
|
||||
|
||||
|
89
tmux.1
89
tmux.1
@ -1003,7 +1003,7 @@ wait for an empty line input before exiting in control mode
|
||||
.El
|
||||
.Pp
|
||||
A leading
|
||||
.Ql !
|
||||
.Ql \&!
|
||||
turns a flag off if the client is already attached.
|
||||
.Fl r
|
||||
is an alias for
|
||||
@ -1407,7 +1407,7 @@ and
|
||||
.Fl T
|
||||
show debugging information about jobs and terminals.
|
||||
.It Xo Ic source-file
|
||||
.Op Fl nqv
|
||||
.Op Fl Fnqv
|
||||
.Ar path
|
||||
.Ar ...
|
||||
.Xc
|
||||
@ -1418,6 +1418,11 @@ Execute commands from one or more files specified by
|
||||
.Xr glob 7
|
||||
patterns).
|
||||
If
|
||||
.Fl F
|
||||
is present, then
|
||||
.Ar path
|
||||
is expanded as a format.
|
||||
If
|
||||
.Fl q
|
||||
is given, no error will be returned if
|
||||
.Ar path
|
||||
@ -1853,7 +1858,7 @@ The
|
||||
.Fl P
|
||||
option prints information about the new window after it has been created.
|
||||
By default, it uses the format
|
||||
.Ql #{session_name}:#{window_index}
|
||||
.Ql #{session_name}:#{window_index}.#{pane_index}
|
||||
but a different format may be specified with
|
||||
.Fl F .
|
||||
.It Xo Ic capture-pane
|
||||
@ -3034,7 +3039,7 @@ Send the prefix key, or with
|
||||
.Fl 2
|
||||
the secondary prefix key, to a window as if it was pressed.
|
||||
.It Xo Ic unbind-key
|
||||
.Op Fl an
|
||||
.Op Fl anq
|
||||
.Op Fl T Ar key-table
|
||||
.Ar key
|
||||
.Xc
|
||||
@ -3049,6 +3054,9 @@ are the same as for
|
||||
If
|
||||
.Fl a
|
||||
is present, all key bindings are removed.
|
||||
The
|
||||
.Fl q
|
||||
option prevents errors being returned.
|
||||
.El
|
||||
.Sh OPTIONS
|
||||
The appearance and behaviour of
|
||||
@ -3159,6 +3167,9 @@ flag unsets an option, so a session inherits the option from the global
|
||||
options (or with
|
||||
.Fl g ,
|
||||
restores a global option to the default).
|
||||
.Ar value
|
||||
depends on the option and may be a number, a string, or a flag (on, off, or
|
||||
omitted to toggle).
|
||||
.Pp
|
||||
The
|
||||
.Fl o
|
||||
@ -3230,9 +3241,6 @@ includes hooks (omitted by default).
|
||||
.Fl A
|
||||
includes options inherited from a parent set of options, such options are
|
||||
marked with an asterisk.
|
||||
.Ar value
|
||||
depends on the option and may be a number, a string, or a flag (on, off, or
|
||||
omitted to toggle).
|
||||
.El
|
||||
.Pp
|
||||
Available server options are:
|
||||
@ -4536,7 +4544,7 @@ multiplication
|
||||
.Ql * ,
|
||||
division
|
||||
.Ql / ,
|
||||
and modulus
|
||||
modulus
|
||||
.Ql m
|
||||
or
|
||||
.Ql %
|
||||
@ -4545,7 +4553,15 @@ or
|
||||
must be escaped as
|
||||
.Ql %%
|
||||
in formats which are also expanded by
|
||||
.Xr strftime 3 ) .
|
||||
.Xr strftime 3 )
|
||||
and numeric comparison operators
|
||||
.Ql == ,
|
||||
.Ql != ,
|
||||
.Ql < ,
|
||||
.Ql <= ,
|
||||
.Ql >
|
||||
and
|
||||
.Ql >= .
|
||||
For example,
|
||||
.Ql #{e|*|f|4:5.5,3}
|
||||
multiplies 5.5 by 3 for a result with four decimal places and
|
||||
@ -4574,6 +4590,9 @@ pads the string to a given width, for example
|
||||
.Ql #{p10:pane_title}
|
||||
will result in a width of at least 10 characters.
|
||||
A positive width pads on the left, a negative on the right.
|
||||
.Ql n
|
||||
expands to the length of the variable, for example
|
||||
.Ql #{n:window_name} .
|
||||
.Pp
|
||||
Prefixing a time variable with
|
||||
.Ql t:\&
|
||||
@ -4770,6 +4789,7 @@ The following variables are available, where appropriate:
|
||||
.It Li "pane_in_mode" Ta "" Ta "1 if pane is in a mode"
|
||||
.It Li "pane_index" Ta "#P" Ta "Index of pane"
|
||||
.It Li "pane_input_off" Ta "" Ta "1 if input to pane is disabled"
|
||||
.It Li "pane_last" Ta "" Ta "1 if last pane"
|
||||
.It Li "pane_left" Ta "" Ta "Left of pane"
|
||||
.It Li "pane_marked" Ta "" Ta "1 if this is the marked pane"
|
||||
.It Li "pane_marked_set" Ta "" Ta "1 if a marked pane is set"
|
||||
@ -5098,7 +5118,7 @@ section).
|
||||
Commands to alter and view the environment are:
|
||||
.Bl -tag -width Ds
|
||||
.It Xo Ic set-environment
|
||||
.Op Fl hgru
|
||||
.Op Fl Fhgru
|
||||
.Op Fl t Ar target-session
|
||||
.Ar name Op Ar value
|
||||
.Xc
|
||||
@ -5109,6 +5129,11 @@ If
|
||||
is used, the change is made in the global environment; otherwise, it is applied
|
||||
to the session environment for
|
||||
.Ar target-session .
|
||||
If
|
||||
.Fl F
|
||||
is present, then
|
||||
.Ar value
|
||||
is expanded as a format.
|
||||
The
|
||||
.Fl u
|
||||
flag unsets a variable.
|
||||
@ -5314,6 +5339,7 @@ option.
|
||||
This command works only from inside
|
||||
.Nm .
|
||||
.It Xo Ic display-menu
|
||||
.Op Fl O
|
||||
.Op Fl c Ar target-client
|
||||
.Op Fl t Ar target-pane
|
||||
.Op Fl T Ar title
|
||||
@ -5365,8 +5391,14 @@ Both may be a row or column number, or one of the following special values:
|
||||
Each menu consists of items followed by a key shortcut shown in brackets.
|
||||
If the menu is too large to fit on the terminal, it is not displayed.
|
||||
Pressing the key shortcut chooses the corresponding item.
|
||||
If the mouse is enabled and the menu is opened from a mouse key binding, releasing
|
||||
the mouse button with an item selected will choose that item.
|
||||
If the mouse is enabled and the menu is opened from a mouse key binding,
|
||||
releasing the mouse button with an item selected chooses that item and
|
||||
releasing the mouse button without an item selected closes the menu.
|
||||
.Fl O
|
||||
changes this behaviour so that the menu does not close when the mouse button is
|
||||
released without an item selected the menu is not closed and a mouse button
|
||||
must be clicked to choose an item.
|
||||
.Pp
|
||||
The following keys are also available:
|
||||
.Bl -column "Key" "Function" -offset indent
|
||||
.It Sy "Key" Ta Sy "Function"
|
||||
@ -5378,6 +5410,7 @@ The following keys are also available:
|
||||
.It Xo Ic display-message
|
||||
.Op Fl aIpv
|
||||
.Op Fl c Ar target-client
|
||||
.Op Fl d Ar delay
|
||||
.Op Fl t Ar target-pane
|
||||
.Op Ar message
|
||||
.Xc
|
||||
@ -5387,7 +5420,14 @@ If
|
||||
.Fl p
|
||||
is given, the output is printed to stdout, otherwise it is displayed in the
|
||||
.Ar target-client
|
||||
status line.
|
||||
status line for up to
|
||||
.Ar delay
|
||||
milliseconds.
|
||||
If
|
||||
.Ar delay
|
||||
is not given, the
|
||||
.Ic message-time
|
||||
option is used; a delay of zero waits for a key press.
|
||||
The format of
|
||||
.Ar message
|
||||
is described in the
|
||||
@ -5629,12 +5669,21 @@ See the
|
||||
.Sx FORMATS
|
||||
section.
|
||||
.It Xo Ic load-buffer
|
||||
.Op Fl w
|
||||
.Op Fl b Ar buffer-name
|
||||
.Op Fl t Ar target-client
|
||||
.Ar path
|
||||
.Xc
|
||||
.D1 (alias: Ic loadb )
|
||||
Load the contents of the specified paste buffer from
|
||||
.Ar path .
|
||||
If
|
||||
.Fl w
|
||||
is given, the buffer is also sent to the clipboard for
|
||||
.Ar target-client
|
||||
using the
|
||||
.Xr xterm 1
|
||||
escape sequence, if possible.
|
||||
.It Xo Ic paste-buffer
|
||||
.Op Fl dpr
|
||||
.Op Fl b Ar buffer-name
|
||||
@ -5671,14 +5720,22 @@ The
|
||||
.Fl a
|
||||
option appends to rather than overwriting the file.
|
||||
.It Xo Ic set-buffer
|
||||
.Op Fl a
|
||||
.Op Fl aw
|
||||
.Op Fl b Ar buffer-name
|
||||
.Op Fl t Ar target-client
|
||||
.Op Fl n Ar new-buffer-name
|
||||
.Ar data
|
||||
.Xc
|
||||
.D1 (alias: Ic setb )
|
||||
Set the contents of the specified buffer to
|
||||
.Ar data .
|
||||
If
|
||||
.Fl w
|
||||
is given, the buffer is also sent to the clipboard for
|
||||
.Ar target-client
|
||||
using the
|
||||
.Xr xterm 1
|
||||
escape sequence, if possible.
|
||||
The
|
||||
.Fl a
|
||||
option appends to rather than overwriting the buffer.
|
||||
@ -5855,8 +5912,8 @@ Set a styled underscore.
|
||||
The single parameter is one of: 0 for no underscore, 1 for normal
|
||||
underscore, 2 for double underscore, 3 for curly underscore, 4 for dotted
|
||||
underscore and 5 for dashed underscore.
|
||||
.It Em \&Setulc
|
||||
Set the underscore colour.
|
||||
.It Em \&Setulc , \&ol
|
||||
Set the underscore colour or reset to the default.
|
||||
The argument is (red * 65536) + (green * 256) + blue where each is between 0
|
||||
and 255.
|
||||
.It Em \&Ss , Se
|
||||
|
4
tmux.c
4
tmux.c
@ -322,8 +322,8 @@ main(int argc, char **argv)
|
||||
char *path = NULL, *label = NULL;
|
||||
char *cause, **var;
|
||||
const char *s, *shell, *cwd;
|
||||
int opt, flags = 0, keys;
|
||||
int feat = 0;
|
||||
int opt, keys, feat = 0;
|
||||
uint64_t flags = 0;
|
||||
const struct options_table_entry *oe;
|
||||
|
||||
if (setlocale(LC_CTYPE, "en_US.UTF-8") == NULL &&
|
||||
|
19
tmux.h
19
tmux.h
@ -450,6 +450,7 @@ enum tty_code_code {
|
||||
TTYC_KUP6,
|
||||
TTYC_KUP7,
|
||||
TTYC_MS,
|
||||
TTYC_OL,
|
||||
TTYC_OP,
|
||||
TTYC_REV,
|
||||
TTYC_RGB,
|
||||
@ -461,6 +462,7 @@ enum tty_code_code {
|
||||
TTYC_SE,
|
||||
TTYC_SETAB,
|
||||
TTYC_SETAF,
|
||||
TTYC_SETAL,
|
||||
TTYC_SETRGBB,
|
||||
TTYC_SETRGBF,
|
||||
TTYC_SETULC,
|
||||
@ -498,6 +500,7 @@ enum msgtype {
|
||||
MSG_IDENTIFY_CWD,
|
||||
MSG_IDENTIFY_FEATURES,
|
||||
MSG_IDENTIFY_STDOUT,
|
||||
MSG_IDENTIFY_LONGFLAGS,
|
||||
|
||||
MSG_COMMAND = 200,
|
||||
MSG_DETACH,
|
||||
@ -1790,6 +1793,7 @@ enum options_table_type {
|
||||
|
||||
struct options_table_entry {
|
||||
const char *name;
|
||||
const char *alternative_name;
|
||||
enum options_table_type type;
|
||||
int scope;
|
||||
int flags;
|
||||
@ -1809,6 +1813,11 @@ struct options_table_entry {
|
||||
const char *unit;
|
||||
};
|
||||
|
||||
struct options_name_map {
|
||||
const char *from;
|
||||
const char *to;
|
||||
};
|
||||
|
||||
/* Common command usages. */
|
||||
#define CMD_TARGET_PANE_USAGE "[-t target-pane]"
|
||||
#define CMD_TARGET_WINDOW_USAGE "[-t target-window]"
|
||||
@ -2041,7 +2050,8 @@ int options_remove_or_default(struct options_entry *, int,
|
||||
char **);
|
||||
|
||||
/* options-table.c */
|
||||
extern const struct options_table_entry options_table[];
|
||||
extern const struct options_table_entry options_table[];
|
||||
extern const struct options_name_map options_other_names[];
|
||||
|
||||
/* job.c */
|
||||
typedef void (*job_update_cb) (struct job *);
|
||||
@ -2121,6 +2131,7 @@ int tty_open(struct tty *, char **);
|
||||
void tty_close(struct tty *);
|
||||
void tty_free(struct tty *);
|
||||
void tty_update_features(struct tty *);
|
||||
void tty_set_selection(struct tty *, const char *, size_t);
|
||||
void tty_write(void (*)(struct tty *, const struct tty_ctx *),
|
||||
struct tty_ctx *);
|
||||
void tty_cmd_alignmenttest(struct tty *, const struct tty_ctx *);
|
||||
@ -2325,7 +2336,7 @@ void printflike(2, 3) cmdq_error(struct cmdq_item *, const char *, ...);
|
||||
void cmd_wait_for_flush(void);
|
||||
|
||||
/* client.c */
|
||||
int client_main(struct event_base *, int, char **, int, int);
|
||||
int client_main(struct event_base *, int, char **, uint64_t, int);
|
||||
|
||||
/* key-bindings.c */
|
||||
struct key_table *key_bindings_get_table(const char *, int);
|
||||
@ -2452,8 +2463,7 @@ struct style_range *status_get_range(struct client *, u_int, u_int);
|
||||
void status_init(struct client *);
|
||||
void status_free(struct client *);
|
||||
int status_redraw(struct client *);
|
||||
void printflike(3, 4) status_message_set(struct client *, int, const char *,
|
||||
...);
|
||||
void status_message_set(struct client *, int, int, const char *, ...);
|
||||
void status_message_clear(struct client *);
|
||||
int status_message_redraw(struct client *);
|
||||
void status_prompt_set(struct client *, struct cmd_find_state *,
|
||||
@ -2971,6 +2981,7 @@ __dead void printflike(1, 2) fatalx(const char *, ...);
|
||||
/* menu.c */
|
||||
#define MENU_NOMOUSE 0x1
|
||||
#define MENU_TAB 0x2
|
||||
#define MENU_STAYOPEN 0x4
|
||||
struct menu *menu_create(const char *);
|
||||
void menu_add_items(struct menu *, const struct menu_item *,
|
||||
struct cmdq_item *, struct client *,
|
||||
|
@ -112,6 +112,7 @@ static const struct tty_feature tty_feature_overline = {
|
||||
static const char *tty_feature_usstyle_capabilities[] = {
|
||||
"Smulx=\\E[4::%p1%dm",
|
||||
"Setulc=\\E[58::2::%p1%{65536}%/%d::%p1%{256}%/%{255}%&%d::%p1%{255}%&%d%;m",
|
||||
"ol=\\E[59m",
|
||||
NULL
|
||||
};
|
||||
static const struct tty_feature tty_feature_usstyle = {
|
||||
@ -336,7 +337,7 @@ tty_default_features(int *feat, const char *name, u_int version)
|
||||
"256,RGB,bpaste,clipboard,strikethrough,title"
|
||||
{ .name = "mintty",
|
||||
.features = TTY_FEATURES_BASE_MODERN_XTERM
|
||||
",ccolour,cstyle,extkeys,margins,overline"
|
||||
",ccolour,cstyle,extkeys,margins,overline,usstyle"
|
||||
},
|
||||
{ .name = "tmux",
|
||||
.features = TTY_FEATURES_BASE_MODERN_XTERM
|
||||
|
@ -248,6 +248,7 @@ static const struct tty_term_code_entry tty_term_codes[] = {
|
||||
[TTYC_KUP6] = { TTYCODE_STRING, "kUP6" },
|
||||
[TTYC_KUP7] = { TTYCODE_STRING, "kUP7" },
|
||||
[TTYC_MS] = { TTYCODE_STRING, "Ms" },
|
||||
[TTYC_OL] = { TTYCODE_STRING, "ol" },
|
||||
[TTYC_OP] = { TTYCODE_STRING, "op" },
|
||||
[TTYC_REV] = { TTYCODE_STRING, "rev" },
|
||||
[TTYC_RGB] = { TTYCODE_FLAG, "RGB" },
|
||||
@ -258,6 +259,7 @@ static const struct tty_term_code_entry tty_term_codes[] = {
|
||||
[TTYC_RMKX] = { TTYCODE_STRING, "rmkx" },
|
||||
[TTYC_SETAB] = { TTYCODE_STRING, "setab" },
|
||||
[TTYC_SETAF] = { TTYCODE_STRING, "setaf" },
|
||||
[TTYC_SETAL] = { TTYCODE_STRING, "setal" },
|
||||
[TTYC_SETRGBB] = { TTYCODE_STRING, "setrgbb" },
|
||||
[TTYC_SETRGBF] = { TTYCODE_STRING, "setrgbf" },
|
||||
[TTYC_SETULC] = { TTYCODE_STRING, "Setulc" },
|
||||
@ -305,6 +307,8 @@ tty_term_strip(const char *s)
|
||||
ptr++;
|
||||
if (*ptr == '>')
|
||||
ptr++;
|
||||
if (*ptr == '\0')
|
||||
break;
|
||||
}
|
||||
|
||||
buf[len++] = *ptr;
|
||||
|
54
tty.c
54
tty.c
@ -1896,19 +1896,27 @@ tty_cmd_cells(struct tty *tty, const struct tty_ctx *ctx)
|
||||
void
|
||||
tty_cmd_setselection(struct tty *tty, const struct tty_ctx *ctx)
|
||||
{
|
||||
char *buf;
|
||||
size_t off;
|
||||
tty_set_selection(tty, ctx->ptr, ctx->num);
|
||||
}
|
||||
|
||||
void
|
||||
tty_set_selection(struct tty *tty, const char *buf, size_t len)
|
||||
{
|
||||
char *encoded;
|
||||
size_t size;
|
||||
|
||||
if (~tty->flags & TTY_STARTED)
|
||||
return;
|
||||
if (!tty_term_has(tty->term, TTYC_MS))
|
||||
return;
|
||||
|
||||
off = 4 * ((ctx->num + 2) / 3) + 1; /* storage for base64 */
|
||||
buf = xmalloc(off);
|
||||
size = 4 * ((len + 2) / 3) + 1; /* storage for base64 */
|
||||
encoded = xmalloc(size);
|
||||
|
||||
b64_ntop(ctx->ptr, ctx->num, buf, off);
|
||||
tty_putcode_ptr2(tty, TTYC_MS, "", buf);
|
||||
b64_ntop(buf, len, encoded, size);
|
||||
tty_putcode_ptr2(tty, TTYC_MS, "", encoded);
|
||||
|
||||
free(buf);
|
||||
free(encoded);
|
||||
}
|
||||
|
||||
void
|
||||
@ -2535,7 +2543,7 @@ tty_colours_fg(struct tty *tty, const struct grid_cell *gc)
|
||||
/* Is this a 24-bit or 256-colour colour? */
|
||||
if (gc->fg & COLOUR_FLAG_RGB || gc->fg & COLOUR_FLAG_256) {
|
||||
if (tty_try_colour(tty, gc->fg, "38") == 0)
|
||||
goto save_fg;
|
||||
goto save;
|
||||
/* Should not get here, already converted in tty_check_fg. */
|
||||
return;
|
||||
}
|
||||
@ -2547,13 +2555,13 @@ tty_colours_fg(struct tty *tty, const struct grid_cell *gc)
|
||||
tty_puts(tty, s);
|
||||
} else
|
||||
tty_putcode1(tty, TTYC_SETAF, gc->fg - 90 + 8);
|
||||
goto save_fg;
|
||||
goto save;
|
||||
}
|
||||
|
||||
/* Otherwise set the foreground colour. */
|
||||
tty_putcode1(tty, TTYC_SETAF, gc->fg);
|
||||
|
||||
save_fg:
|
||||
save:
|
||||
/* Save the new values in the terminal current cell. */
|
||||
tc->fg = gc->fg;
|
||||
}
|
||||
@ -2567,7 +2575,7 @@ tty_colours_bg(struct tty *tty, const struct grid_cell *gc)
|
||||
/* Is this a 24-bit or 256-colour colour? */
|
||||
if (gc->bg & COLOUR_FLAG_RGB || gc->bg & COLOUR_FLAG_256) {
|
||||
if (tty_try_colour(tty, gc->bg, "48") == 0)
|
||||
goto save_bg;
|
||||
goto save;
|
||||
/* Should not get here, already converted in tty_check_bg. */
|
||||
return;
|
||||
}
|
||||
@ -2579,13 +2587,13 @@ tty_colours_bg(struct tty *tty, const struct grid_cell *gc)
|
||||
tty_puts(tty, s);
|
||||
} else
|
||||
tty_putcode1(tty, TTYC_SETAB, gc->bg - 90 + 8);
|
||||
goto save_bg;
|
||||
goto save;
|
||||
}
|
||||
|
||||
/* Otherwise set the background colour. */
|
||||
tty_putcode1(tty, TTYC_SETAB, gc->bg);
|
||||
|
||||
save_bg:
|
||||
save:
|
||||
/* Save the new values in the terminal current cell. */
|
||||
tc->bg = gc->bg;
|
||||
}
|
||||
@ -2597,20 +2605,34 @@ tty_colours_us(struct tty *tty, const struct grid_cell *gc)
|
||||
u_int c;
|
||||
u_char r, g, b;
|
||||
|
||||
/* Clear underline colour. */
|
||||
if (gc->us == 0) {
|
||||
tty_putcode(tty, TTYC_OL);
|
||||
goto save;
|
||||
}
|
||||
|
||||
/* Must be an RGB colour - this should never happen. */
|
||||
if (~gc->us & COLOUR_FLAG_RGB)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Setulc follows the ncurses(3) one argument "direct colour"
|
||||
* Setulc and setal follows the ncurses(3) one argument "direct colour"
|
||||
* capability format. Calculate the colour value.
|
||||
*/
|
||||
colour_split_rgb(gc->us, &r, &g, &b);
|
||||
c = (65536 * r) + (256 * g) + b;
|
||||
|
||||
/* Write the colour. */
|
||||
tty_putcode1(tty, TTYC_SETULC, c);
|
||||
/*
|
||||
* Write the colour. Only use setal if the RGB flag is set because the
|
||||
* non-RGB version may be wrong.
|
||||
*/
|
||||
if (tty_term_has(tty->term, TTYC_SETULC))
|
||||
tty_putcode1(tty, TTYC_SETULC, c);
|
||||
else if (tty_term_has(tty->term, TTYC_SETAL) &&
|
||||
tty_term_has(tty->term, TTYC_RGB))
|
||||
tty_putcode1(tty, TTYC_SETAL, c);
|
||||
|
||||
save:
|
||||
/* Save the new values in the terminal current cell. */
|
||||
tc->us = gc->us;
|
||||
}
|
||||
|
156
window-copy.c
156
window-copy.c
@ -72,14 +72,13 @@ static int window_copy_search_marks(struct window_mode_entry *,
|
||||
struct screen *, int, 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, 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);
|
||||
int, int, u_int *);
|
||||
static int window_copy_search(struct window_mode_entry *, int, int, int);
|
||||
static int window_copy_search_up(struct window_mode_entry *, int, int);
|
||||
static int window_copy_search_down(struct window_mode_entry *, int, 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);
|
||||
@ -110,7 +109,7 @@ static void window_copy_cursor_back_to_indentation(
|
||||
static void window_copy_cursor_end_of_line(struct window_mode_entry *);
|
||||
static void window_copy_other_end(struct window_mode_entry *);
|
||||
static void window_copy_cursor_left(struct window_mode_entry *);
|
||||
static void window_copy_cursor_right(struct window_mode_entry *);
|
||||
static void window_copy_cursor_right(struct window_mode_entry *, int);
|
||||
static void window_copy_cursor_up(struct window_mode_entry *, int);
|
||||
static void window_copy_cursor_down(struct window_mode_entry *, int);
|
||||
static void window_copy_cursor_jump(struct window_mode_entry *);
|
||||
@ -1094,7 +1093,7 @@ window_copy_cmd_cursor_right(struct window_copy_cmd_state *cs)
|
||||
u_int np = wme->prefix;
|
||||
|
||||
for (; np != 0; np--)
|
||||
window_copy_cursor_right(wme);
|
||||
window_copy_cursor_right(wme, 0);
|
||||
return (WINDOW_COPY_CMD_NOTHING);
|
||||
}
|
||||
|
||||
@ -1685,10 +1684,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, data->searchregex);
|
||||
window_copy_search_up(wme, data->searchregex, 1);
|
||||
} else if (data->searchtype == WINDOW_COPY_SEARCHDOWN) {
|
||||
for (; np != 0; np--)
|
||||
window_copy_search_down(wme, data->searchregex);
|
||||
window_copy_search_down(wme, data->searchregex, 1);
|
||||
}
|
||||
return (WINDOW_COPY_CMD_NOTHING);
|
||||
}
|
||||
@ -1702,10 +1701,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, data->searchregex);
|
||||
window_copy_search_down(wme, data->searchregex, 1);
|
||||
} else if (data->searchtype == WINDOW_COPY_SEARCHDOWN) {
|
||||
for (; np != 0; np--)
|
||||
window_copy_search_up(wme, data->searchregex);
|
||||
window_copy_search_up(wme, data->searchregex, 1);
|
||||
}
|
||||
return (WINDOW_COPY_CMD_NOTHING);
|
||||
}
|
||||
@ -1953,7 +1952,7 @@ window_copy_cmd_search_backward(struct window_copy_cmd_state *cs)
|
||||
data->searchregex = 1;
|
||||
data->timeout = 0;
|
||||
for (; np != 0; np--)
|
||||
window_copy_search_up(wme, 1);
|
||||
window_copy_search_up(wme, 1, 0);
|
||||
}
|
||||
return (WINDOW_COPY_CMD_NOTHING);
|
||||
}
|
||||
@ -1973,7 +1972,7 @@ window_copy_cmd_search_backward_text(struct window_copy_cmd_state *cs)
|
||||
data->searchregex = 0;
|
||||
data->timeout = 0;
|
||||
for (; np != 0; np--)
|
||||
window_copy_search_up(wme, 0);
|
||||
window_copy_search_up(wme, 0, 0);
|
||||
}
|
||||
return (WINDOW_COPY_CMD_NOTHING);
|
||||
}
|
||||
@ -1993,7 +1992,7 @@ window_copy_cmd_search_forward(struct window_copy_cmd_state *cs)
|
||||
data->searchregex = 1;
|
||||
data->timeout = 0;
|
||||
for (; np != 0; np--)
|
||||
window_copy_search_down(wme, 1);
|
||||
window_copy_search_down(wme, 1, 0);
|
||||
}
|
||||
return (WINDOW_COPY_CMD_NOTHING);
|
||||
}
|
||||
@ -2013,7 +2012,7 @@ window_copy_cmd_search_forward_text(struct window_copy_cmd_state *cs)
|
||||
data->searchregex = 0;
|
||||
data->timeout = 0;
|
||||
for (; np != 0; np--)
|
||||
window_copy_search_down(wme, 0);
|
||||
window_copy_search_down(wme, 0, 0);
|
||||
}
|
||||
return (WINDOW_COPY_CMD_NOTHING);
|
||||
}
|
||||
@ -2052,7 +2051,7 @@ window_copy_cmd_search_backward_incremental(struct window_copy_cmd_state *cs)
|
||||
data->searchregex = 0;
|
||||
free(data->searchstr);
|
||||
data->searchstr = xstrdup(argument);
|
||||
if (!window_copy_search_up(wme, 0)) {
|
||||
if (!window_copy_search_up(wme, 0, 1)) {
|
||||
window_copy_clear_marks(wme);
|
||||
return (WINDOW_COPY_CMD_REDRAW);
|
||||
}
|
||||
@ -2062,7 +2061,7 @@ window_copy_cmd_search_backward_incremental(struct window_copy_cmd_state *cs)
|
||||
data->searchregex = 0;
|
||||
free(data->searchstr);
|
||||
data->searchstr = xstrdup(argument);
|
||||
if (!window_copy_search_down(wme, 0)) {
|
||||
if (!window_copy_search_down(wme, 0, 0)) {
|
||||
window_copy_clear_marks(wme);
|
||||
return (WINDOW_COPY_CMD_REDRAW);
|
||||
}
|
||||
@ -2105,7 +2104,7 @@ window_copy_cmd_search_forward_incremental(struct window_copy_cmd_state *cs)
|
||||
data->searchregex = 0;
|
||||
free(data->searchstr);
|
||||
data->searchstr = xstrdup(argument);
|
||||
if (!window_copy_search_down(wme, 0)) {
|
||||
if (!window_copy_search_down(wme, 0, 1)) {
|
||||
window_copy_clear_marks(wme);
|
||||
return (WINDOW_COPY_CMD_REDRAW);
|
||||
}
|
||||
@ -2115,7 +2114,7 @@ window_copy_cmd_search_forward_incremental(struct window_copy_cmd_state *cs)
|
||||
data->searchregex = 0;
|
||||
free(data->searchstr);
|
||||
data->searchstr = xstrdup(argument);
|
||||
if (!window_copy_search_up(wme, 0)) {
|
||||
if (!window_copy_search_up(wme, 0, 1)) {
|
||||
window_copy_clear_marks(wme);
|
||||
return (WINDOW_COPY_CMD_REDRAW);
|
||||
}
|
||||
@ -2406,8 +2405,8 @@ window_copy_search_compare(struct grid *gd, u_int px, u_int py,
|
||||
}
|
||||
|
||||
static int
|
||||
window_copy_search_lr(struct grid *gd,
|
||||
struct grid *sgd, u_int *ppx, u_int py, u_int first, u_int last, int cis)
|
||||
window_copy_search_lr(struct grid *gd, struct grid *sgd, u_int *ppx, u_int py,
|
||||
u_int first, u_int last, int cis)
|
||||
{
|
||||
u_int ax, bx, px, pywrap, endline;
|
||||
int matched;
|
||||
@ -2817,23 +2816,6 @@ window_copy_move_left(struct screen *s, u_int *fx, u_int *fy, int wrapflag)
|
||||
*fx = *fx - 1;
|
||||
}
|
||||
|
||||
static void
|
||||
window_copy_move_right(struct screen *s, u_int *fx, u_int *fy, int wrapflag)
|
||||
{
|
||||
if (*fx == screen_size_x(s) - 1) { /* right */
|
||||
if (*fy == screen_hsize(s) + screen_size_y(s) - 1) { /* bottom */
|
||||
if (wrapflag) {
|
||||
*fx = 0;
|
||||
*fy = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
*fx = 0;
|
||||
*fy = *fy + 1;
|
||||
} else
|
||||
*fx = *fx + 1;
|
||||
}
|
||||
|
||||
static int
|
||||
window_copy_is_lowercase(const char *ptr)
|
||||
{
|
||||
@ -2854,7 +2836,7 @@ 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 regex)
|
||||
int direction, int regex, u_int *foundlen)
|
||||
{
|
||||
u_int i, px, sx, ssize = 1;
|
||||
int found = 0, cflags = REG_EXTENDED;
|
||||
@ -2871,6 +2853,7 @@ window_copy_search_jump(struct window_mode_entry *wme, struct grid *gd,
|
||||
free(sbuf);
|
||||
return (0);
|
||||
}
|
||||
free(sbuf);
|
||||
}
|
||||
|
||||
if (direction) {
|
||||
@ -2878,15 +2861,20 @@ window_copy_search_jump(struct window_mode_entry *wme, struct grid *gd,
|
||||
if (regex) {
|
||||
found = window_copy_search_lr_regex(gd,
|
||||
&px, &sx, i, fx, gd->sx, ®);
|
||||
if (found)
|
||||
*foundlen = sx;
|
||||
} else {
|
||||
found = window_copy_search_lr(gd, sgd,
|
||||
&px, i, fx, gd->sx, cis);
|
||||
if (found)
|
||||
*foundlen = sgd->sx;
|
||||
}
|
||||
if (found)
|
||||
break;
|
||||
fx = 0;
|
||||
}
|
||||
} else {
|
||||
*foundlen = 0;
|
||||
for (i = fy + 1; endline < i; i--) {
|
||||
if (regex) {
|
||||
found = window_copy_search_rl_regex(gd,
|
||||
@ -2902,10 +2890,8 @@ window_copy_search_jump(struct window_mode_entry *wme, struct grid *gd,
|
||||
fx = gd->sx - 1;
|
||||
}
|
||||
}
|
||||
if (regex) {
|
||||
free(sbuf);
|
||||
if (regex)
|
||||
regfree(®);
|
||||
}
|
||||
|
||||
if (found) {
|
||||
window_copy_scroll_to(wme, px, i, 1);
|
||||
@ -2915,7 +2901,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, regex));
|
||||
direction, regex, foundlen));
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
@ -2925,7 +2911,8 @@ 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, int regex)
|
||||
window_copy_search(struct window_mode_entry *wme, int direction, int regex,
|
||||
int again)
|
||||
{
|
||||
struct window_pane *wp = wme->wp;
|
||||
struct window_copy_mode_data *data = wme->data;
|
||||
@ -2933,7 +2920,7 @@ window_copy_search(struct window_mode_entry *wme, int direction, int regex)
|
||||
struct screen_write_ctx ctx;
|
||||
struct grid *gd = s->grid;
|
||||
const char *str = data->searchstr;
|
||||
u_int fx, fy, endline;
|
||||
u_int fx, fy, endline, i, foundlen;
|
||||
int wrapflag, cis, found, visible_only;
|
||||
|
||||
if (regex && str[strcspn(str, "^$*+()?[].\\")] == '\0')
|
||||
@ -2961,18 +2948,23 @@ window_copy_search(struct window_mode_entry *wme, int direction, int regex)
|
||||
wrapflag = options_get_number(wp->window->options, "wrap-search");
|
||||
cis = window_copy_is_lowercase(str);
|
||||
|
||||
if (direction) {
|
||||
window_copy_move_right(s, &fx, &fy, wrapflag);
|
||||
if (direction)
|
||||
endline = gd->hsize + gd->sy - 1;
|
||||
} else {
|
||||
window_copy_move_left(s, &fx, &fy, wrapflag);
|
||||
else {
|
||||
if (again)
|
||||
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, regex);
|
||||
if (found)
|
||||
wrapflag, direction, regex, &foundlen);
|
||||
if (found) {
|
||||
window_copy_search_marks(wme, &ss, regex, visible_only);
|
||||
if (foundlen != 0) {
|
||||
for (i = 0; i < foundlen; i++)
|
||||
window_copy_cursor_right(wme, 1);
|
||||
}
|
||||
}
|
||||
window_copy_redraw_screen(wme);
|
||||
|
||||
screen_free(&ss);
|
||||
@ -2995,8 +2987,8 @@ window_copy_visible_lines(struct window_copy_mode_data *data, u_int *start,
|
||||
}
|
||||
|
||||
static int
|
||||
window_copy_search_mark_at(struct window_copy_mode_data *data, u_int px, u_int py,
|
||||
u_int *at)
|
||||
window_copy_search_mark_at(struct window_copy_mode_data *data, u_int px,
|
||||
u_int py, u_int *at)
|
||||
{
|
||||
struct screen *s = data->backing;
|
||||
struct grid *gd = s->grid;
|
||||
@ -3049,6 +3041,7 @@ window_copy_search_marks(struct window_mode_entry *wme, struct screen *ssp,
|
||||
free(sbuf);
|
||||
return (0);
|
||||
}
|
||||
free(sbuf);
|
||||
}
|
||||
tstart = get_timer();
|
||||
|
||||
@ -3096,7 +3089,7 @@ again:
|
||||
data->searchgen++;
|
||||
}
|
||||
|
||||
px++;
|
||||
px += width;
|
||||
}
|
||||
|
||||
t = get_timer();
|
||||
@ -3146,10 +3139,8 @@ again:
|
||||
out:
|
||||
if (ssp == &ss)
|
||||
screen_free(&ss);
|
||||
if (regex) {
|
||||
free(sbuf);
|
||||
if (regex)
|
||||
regfree(®);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
@ -3163,15 +3154,15 @@ window_copy_clear_marks(struct window_mode_entry *wme)
|
||||
}
|
||||
|
||||
static int
|
||||
window_copy_search_up(struct window_mode_entry *wme, int regex)
|
||||
window_copy_search_up(struct window_mode_entry *wme, int regex, int again)
|
||||
{
|
||||
return (window_copy_search(wme, 0, regex));
|
||||
return (window_copy_search(wme, 0, regex, again));
|
||||
}
|
||||
|
||||
static int
|
||||
window_copy_search_down(struct window_mode_entry *wme, int regex)
|
||||
window_copy_search_down(struct window_mode_entry *wme, int regex, int again)
|
||||
{
|
||||
return (window_copy_search(wme, 1, regex));
|
||||
return (window_copy_search(wme, 1, regex, again));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -3256,7 +3247,7 @@ window_copy_update_style(struct window_mode_entry *wme, u_int fx, u_int fy,
|
||||
{
|
||||
struct window_copy_mode_data *data = wme->data;
|
||||
u_int mark, start, end, cy, cursor, current;
|
||||
int inv = 0;
|
||||
int inv = 0, found = 0;
|
||||
|
||||
if (data->showmark && fy == data->my) {
|
||||
gc->attr = mkgc->attr;
|
||||
@ -3282,20 +3273,28 @@ window_copy_update_style(struct window_mode_entry *wme, u_int fx, u_int fy,
|
||||
return;
|
||||
|
||||
cy = screen_hsize(data->backing) - data->oy + data->cy;
|
||||
if (window_copy_search_mark_at(data, data->cx, cy, &cursor) == 0 &&
|
||||
data->searchmark[cursor] == mark) {
|
||||
window_copy_match_start_end(data, cursor, &start, &end);
|
||||
if (current >= start && current <= end) {
|
||||
gc->attr = cgc->attr;
|
||||
if (inv) {
|
||||
gc->fg = cgc->bg;
|
||||
gc->bg = cgc->fg;
|
||||
if (window_copy_search_mark_at(data, data->cx, cy, &cursor) == 0) {
|
||||
if (data->searchmark[cursor] == mark)
|
||||
found = 1;
|
||||
else if (cursor != 0) {
|
||||
cursor--;
|
||||
if (data->searchmark[cursor] == mark)
|
||||
found = 1;
|
||||
}
|
||||
if (found) {
|
||||
window_copy_match_start_end(data, cursor, &start, &end);
|
||||
if (current >= start && current <= end) {
|
||||
gc->attr = cgc->attr;
|
||||
if (inv) {
|
||||
gc->fg = cgc->bg;
|
||||
gc->bg = cgc->fg;
|
||||
}
|
||||
else {
|
||||
gc->fg = cgc->fg;
|
||||
gc->bg = cgc->bg;
|
||||
}
|
||||
return;
|
||||
}
|
||||
else {
|
||||
gc->fg = cgc->fg;
|
||||
gc->bg = cgc->bg;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3370,7 +3369,8 @@ window_copy_write_line(struct window_mode_entry *wme,
|
||||
} else if (data->searchthis == -1) {
|
||||
size = xsnprintf(hdr, sizeof hdr,
|
||||
"(%d%s results) [%u/%u]", data->searchcount,
|
||||
data->searchmore ? "+" : "", data->oy, hsize);
|
||||
data->searchmore ? "+" : "", data->oy,
|
||||
hsize);
|
||||
} else {
|
||||
size = xsnprintf(hdr, sizeof hdr,
|
||||
"(%d/%d results) [%u/%u]", data->searchthis,
|
||||
@ -4142,7 +4142,7 @@ window_copy_cursor_left(struct window_mode_entry *wme)
|
||||
}
|
||||
|
||||
static void
|
||||
window_copy_cursor_right(struct window_mode_entry *wme)
|
||||
window_copy_cursor_right(struct window_mode_entry *wme, int all)
|
||||
{
|
||||
struct window_copy_mode_data *data = wme->data;
|
||||
u_int px, py, yy, cx, cy;
|
||||
@ -4150,7 +4150,7 @@ window_copy_cursor_right(struct window_mode_entry *wme)
|
||||
|
||||
py = screen_hsize(data->backing) + data->cy - data->oy;
|
||||
yy = screen_hsize(data->backing) + screen_size_y(data->backing) - 1;
|
||||
if (data->screen.sel != NULL && data->rectflag)
|
||||
if (all || (data->screen.sel != NULL && data->rectflag))
|
||||
px = screen_size_x(&data->screen);
|
||||
else
|
||||
px = window_copy_find_length(wme, py);
|
||||
|
@ -380,7 +380,7 @@ window_customize_build_options(struct window_customize_modedata *data,
|
||||
struct format_tree *ft, const char *filter, struct cmd_find_state *fs)
|
||||
{
|
||||
struct mode_tree_item *top;
|
||||
struct options_entry *o, *loop;
|
||||
struct options_entry *o = NULL, *loop;
|
||||
const char **list = NULL, *name;
|
||||
u_int size = 0, i;
|
||||
enum window_customize_scope scope;
|
||||
@ -1003,7 +1003,7 @@ window_customize_set_option_callback(struct client *c, void *itemdata,
|
||||
|
||||
fail:
|
||||
*cause = toupper((u_char)*cause);
|
||||
status_message_set(c, 1, "%s", cause);
|
||||
status_message_set(c, -1, 1, "%s", cause);
|
||||
free(cause);
|
||||
return (0);
|
||||
}
|
||||
@ -1018,7 +1018,7 @@ window_customize_set_option(struct client *c,
|
||||
struct options *oo;
|
||||
struct window_customize_itemdata *new_item;
|
||||
int flag, idx = item->idx;
|
||||
enum window_customize_scope scope;
|
||||
enum window_customize_scope scope = WINDOW_CUSTOMIZE_NONE;
|
||||
u_int choice;
|
||||
const char *name = item->name, *space = "";
|
||||
char *prompt, *value, *text;
|
||||
@ -1031,7 +1031,7 @@ window_customize_set_option(struct client *c,
|
||||
return;
|
||||
|
||||
oe = options_table_entry(o);
|
||||
if (~oe->scope & OPTIONS_TABLE_PANE)
|
||||
if (oe != NULL && ~oe->scope & OPTIONS_TABLE_PANE)
|
||||
pane = 0;
|
||||
if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_ARRAY)) {
|
||||
scope = item->scope;
|
||||
@ -1209,7 +1209,7 @@ window_customize_set_command_callback(struct client *c, void *itemdata,
|
||||
|
||||
fail:
|
||||
*error = toupper((u_char)*error);
|
||||
status_message_set(c, 1, "%s", error);
|
||||
status_message_set(c, -1, 1, "%s", error);
|
||||
free(error);
|
||||
return (0);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user