mirror of
https://github.com/tmux/tmux.git
synced 2026-03-11 19:15:45 +00:00
Compare commits
119 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
88c831af6e | ||
|
|
e254aeb9f9 | ||
|
|
1d4c54717c | ||
|
|
30b816f101 | ||
|
|
9803aee98e | ||
|
|
a34a72d2d9 | ||
|
|
4d80980e50 | ||
|
|
85152ef35c | ||
|
|
ebce251183 | ||
|
|
a3c1b730c9 | ||
|
|
a7b0b30bdd | ||
|
|
d4c2a935f2 | ||
|
|
cc967ffeb9 | ||
|
|
4bea559037 | ||
|
|
674de910ca | ||
|
|
5434a2759a | ||
|
|
b7551c9193 | ||
|
|
d4312281da | ||
|
|
d9eb34b28d | ||
|
|
b79189958f | ||
|
|
ad5c4e719b | ||
|
|
db7570daab | ||
|
|
60069fe8fe | ||
|
|
d817f88fec | ||
|
|
90b331ea46 | ||
|
|
e2d59a6c17 | ||
|
|
2ca1849350 | ||
|
|
e210abf335 | ||
|
|
f9b4095188 | ||
|
|
d1f0138653 | ||
|
|
9e7ec2e971 | ||
|
|
3a9a24a7c0 | ||
|
|
c1b9948525 | ||
|
|
76862acf3e | ||
|
|
f308663ad4 | ||
|
|
876f46abb9 | ||
|
|
620a87db25 | ||
|
|
08014af243 | ||
|
|
774bffb3c6 | ||
|
|
9c920214e6 | ||
|
|
5cc3d50289 | ||
|
|
9ec457575d | ||
|
|
398af28d2a | ||
|
|
8798079ab0 | ||
|
|
c26ec766cb | ||
|
|
c3794d4303 | ||
|
|
4fbb296438 | ||
|
|
21128fea1e | ||
|
|
693c106a1d | ||
|
|
046d8b096f | ||
|
|
0cbab892d5 | ||
|
|
b44f78fe9f | ||
|
|
3f5ec24b5a | ||
|
|
d8d9c2af98 | ||
|
|
cf317412d9 | ||
|
|
5213d9674b | ||
|
|
0e45ca1718 | ||
|
|
c1eeac86fe | ||
|
|
03ee7f7edf | ||
|
|
a8ca1340ad | ||
|
|
7d169a3679 | ||
|
|
98e500f598 | ||
|
|
1c1797e4f2 | ||
|
|
653d1e2fc8 | ||
|
|
9b48c77493 | ||
|
|
96146a8c6f | ||
|
|
7d53e2c946 | ||
|
|
213deb5c66 | ||
|
|
69c1521895 | ||
|
|
17e6dc4405 | ||
|
|
a7341715c1 | ||
|
|
521bf41d12 | ||
|
|
f0c3e9babe | ||
|
|
edd59d9e0f | ||
|
|
326c5bf1b4 | ||
|
|
550906cb09 | ||
|
|
175d82c95b | ||
|
|
3740f8f846 | ||
|
|
adfa5050d5 | ||
|
|
f62dcc1ea1 | ||
|
|
d6dc4c30f4 | ||
|
|
d635d79042 | ||
|
|
b8ce435a54 | ||
|
|
6e0c097d9f | ||
|
|
d9807eeba1 | ||
|
|
cb752f9938 | ||
|
|
2e98603db9 | ||
|
|
39628e8280 | ||
|
|
40af1a854c | ||
|
|
fb5b958837 | ||
|
|
99f78340af | ||
|
|
4a01da19df | ||
|
|
d390a90bf0 | ||
|
|
c41a93d130 | ||
|
|
0a4fd0f7a4 | ||
|
|
a54e670301 | ||
|
|
2651c0d69c | ||
|
|
87a2a13f68 | ||
|
|
5775074f73 | ||
|
|
abb4af7a14 | ||
|
|
b9bbe1d81c | ||
|
|
cd62411d78 | ||
|
|
e39c5a9e14 | ||
|
|
b2fe881307 | ||
|
|
b6659dc563 | ||
|
|
3ce1b91b1b | ||
|
|
2589d117b0 | ||
|
|
8aec4c93eb | ||
|
|
9960a06a67 | ||
|
|
0ecb11fe4f | ||
|
|
7d604ab717 | ||
|
|
ee5e97926d | ||
|
|
e9ebdac3dd | ||
|
|
5339b8ce3a | ||
|
|
20134fa9f4 | ||
|
|
1f01dd8c0a | ||
|
|
25eb48aea3 | ||
|
|
e5cee89727 | ||
|
|
d86c6b2fff |
50
CHANGES
50
CHANGES
@@ -1,3 +1,53 @@
|
||||
CHANGES FROM 1.5 TO 1.6, 23 January 2012
|
||||
|
||||
* Extend the mode-mouse option to add a third choice which means the mouse
|
||||
does not enter copy mode.
|
||||
* Add a -r flag to switch-client to toggle the client read-only flag.
|
||||
* Add pane-base-index option.
|
||||
* Support \ for line continuation in the configuration file.
|
||||
* Framework for more powerful formatting of command output and use it for
|
||||
list-{panes,windows,sessions}. This allows more descriptive replacements
|
||||
(such as #{session_name}) and conditionals.
|
||||
* Mark dead panes with some text saying they are dead.
|
||||
* Reject $SHELL if it is not a full path.
|
||||
* Add -S option to refresh-client to redraw status line.
|
||||
* Add an else clause for if-shell.
|
||||
* Try to resolve relative paths for loadb and saveb (first, using client
|
||||
working directory, if any, then default-path or session working directory).
|
||||
* Support for \e[3J to clear the history and send the corresponding
|
||||
terminfo code (E3) before locking.
|
||||
* When in copy mode, make repeat count indicate buffer to replace, if used.
|
||||
* Add screen*:XT to terminal-overrides for tmux-in-tmux.
|
||||
* Status-line message attributes added.
|
||||
* Move word-separators to be a session rather than window option.
|
||||
* Change the way the working directory for new processes is discovered. If
|
||||
default-path isn't empty, it is used. Otherwise, if a new window is created
|
||||
from the command-line, the working directory of the client is used. If not,
|
||||
platform specific code is used to retrieve the current working directory
|
||||
of the process in the active pane. If that fails, the directory where the
|
||||
session was created is used, instead.
|
||||
* Do not change the current pane if both mouse-select-{pane,window} are
|
||||
enabled.
|
||||
* Add \033[s and \033[u to save and restore cursor position.
|
||||
* Allow $HOME to be used as default-path.
|
||||
* Add CNL and CPL escape sequences.
|
||||
* Calculate last position correctly for UTF-8 wide characters.
|
||||
* Add an option allow-rename to disable the window rename escape sequence.
|
||||
* Attributes for each type of status-line alert (ie bell, content and
|
||||
activity) added. Therefore, remove the superfluous options
|
||||
window-status-alert-{attr,bg,fg}.
|
||||
* Add a -R flag to send-keys to reset the terminal.
|
||||
* Add strings to allow the aixterm bright colours to be used when
|
||||
configuring colours.
|
||||
* Drop the ability to have a list of keys in the prefix in favour of two
|
||||
separate options, prefix and prefix2.
|
||||
* Flag -2 added to send-prefix to send the secondary prefix key.
|
||||
* Show pane size in top right of display panes mode.
|
||||
* Some memory leaks plugged.
|
||||
* More command-prompt editing improvements.
|
||||
* Various manpage improvements.
|
||||
* More Vi mode improvements.
|
||||
|
||||
CHANGES FROM 1.4 TO 1.5, 09 July 2011
|
||||
|
||||
* Support xterm mouse modes 1002 and 1003.
|
||||
|
||||
@@ -43,11 +43,6 @@ CPPFLAGS += -I. -I- -I/usr/local/include
|
||||
endif
|
||||
endif
|
||||
|
||||
# Set flags for static.
|
||||
if IS_STATIC
|
||||
LDFLAGS += -static
|
||||
endif
|
||||
|
||||
# Set flags for Solaris.
|
||||
if IS_SUNOS
|
||||
CPPFLAGS += -D_XPG4_2 -D__EXTENSIONS__ -D_POSIX_PTHREAD_SEMANTICS
|
||||
@@ -141,6 +136,7 @@ dist_tmux_SOURCES = \
|
||||
cmd.c \
|
||||
colour.c \
|
||||
environ.c \
|
||||
format.c \
|
||||
grid-utf8.c \
|
||||
grid-view.c \
|
||||
grid.c \
|
||||
@@ -226,6 +222,9 @@ endif
|
||||
if NO_STRTONUM
|
||||
nodist_tmux_SOURCES += compat/strtonum.c
|
||||
endif
|
||||
if NO_B64_NTOP
|
||||
nodist_tmux_SOURCES += compat/b64_ntop.c
|
||||
endif
|
||||
|
||||
# Update SF web site.
|
||||
upload-index.html: update-index.html
|
||||
|
||||
17
NOTES
17
NOTES
@@ -9,10 +9,27 @@ run on Solaris and AIX (although they haven't been tested in a while). It is
|
||||
usable, although there remain a number of missing features and some remaining
|
||||
bugs are expected.
|
||||
|
||||
If upgrading from 1.5, PLEASE NOTE:
|
||||
- The word-separators window option is now a session option.
|
||||
- The options used to change the window attributes when an alert occurs were
|
||||
removed. Each kind of alert has its own individual set of options.
|
||||
- The ability to have a list of prefix keys was dropped in favour of two
|
||||
separate options, prefix and prefix2.
|
||||
|
||||
Since the 1.2 release that tmux depends on libevent. Download it from:
|
||||
|
||||
http://www.monkey.org/~provos/libevent/
|
||||
|
||||
To build tmux from a release tarball, do:
|
||||
|
||||
$ ./configure && make
|
||||
$ sudo make install
|
||||
|
||||
To build from a version control checkout, the configure script must be
|
||||
generated by running:
|
||||
|
||||
$ sh autogen.sh
|
||||
|
||||
tmux consists of a server part and multiple clients. The server is created when
|
||||
required and runs continuously unless killed by the user. Clients access the
|
||||
server through a socket in /tmp. Multiple sessions may be created on a single
|
||||
|
||||
24
TODO
24
TODO
@@ -6,7 +6,6 @@
|
||||
- flags to centre screen in window
|
||||
- activity/bell should be per-window not per-link? what if it is cur win in
|
||||
session not being watched?
|
||||
- next prev word etc in command prompt
|
||||
- use a better termcap internally instead of screen, perhaps xterm
|
||||
- should be able to move to a hidden pane and it would be moved into view. pane
|
||||
number in status line/top-right would be cool for this
|
||||
@@ -67,7 +66,6 @@
|
||||
sequence until its shell exits, to allow them to be used from the config file
|
||||
- better session sharing: create-socket command to create socket somewhere (-r
|
||||
flag for readonly)
|
||||
- allow buffer to be specified when copying in copy mode
|
||||
- multiline status line (no?)
|
||||
- flag for absolute pane size to resize-pane
|
||||
- sanity check input to socket
|
||||
@@ -100,7 +98,6 @@
|
||||
and a buffer) info() when changing to same window
|
||||
- way to add dest for break-pane; maybe some easier way to unbreak-pane
|
||||
- case insensitive searching
|
||||
- pane-index option like base-index
|
||||
- option to move status line to top
|
||||
- configurable borders and empty space filler for when panes < window?
|
||||
- mouse-select-pane will screw up with !MODE_MOUSE_STANDARD (it sets the
|
||||
@@ -113,13 +110,8 @@
|
||||
in commands without quotes
|
||||
- a command to choose from a generic list, so you can do eg
|
||||
choose-list -l Abc,Moo,Blah "run-shell 'sh /my/choose/script %%'"
|
||||
- else part for if-shell
|
||||
- add general internal format for lists (key=value) and a way to output them in
|
||||
different representations, use for list-windows, etc etc. see message id
|
||||
20110221205346.GA1580@yelena.nicm.ath.cx
|
||||
- numeric prefix in copy mode should be paste buffer for C-w
|
||||
- named buffers and allow gaps in the stack
|
||||
- npage/ppage/dc/ic should have aliases for more typical names
|
||||
- get rid of separate UTF-8 cell stuff: add 1 byte to cell and store BMP as
|
||||
uint16_t+3 bits of flags. anything <=0xffff is Unicode, higher are used to
|
||||
build tree of combined characters/non-BMP (LRU dropped when full)
|
||||
@@ -128,13 +120,25 @@
|
||||
- monitor-activity is broken in several ways with multiple clients
|
||||
- monitor-activity should be more powerful (eg set a region)
|
||||
- maybe a way to put pane names instead of window names in status line
|
||||
- Support for borderless panes
|
||||
- support for borderless panes
|
||||
- run-shell/if-shell should support status_replace stuff
|
||||
- wait-pane command or another way to make it synchronous/wait for command to
|
||||
finish
|
||||
- way to get command window was started with (part of format stuff?)
|
||||
- last-pane across sessions
|
||||
- attach should take a pane and select it as well as attaching
|
||||
- should default-path be a window option?
|
||||
- option to put status line at top (why?)
|
||||
- panes should have names like windows
|
||||
- command-prompt doesn't work if made read-only. why?
|
||||
- option to quote format eg #{session_name:quoted}
|
||||
- formats need to be used for much much more stuff!
|
||||
- formats need conditions for >0 (for #P)
|
||||
- flags to find-window to select what is searched (title, name, content, history)
|
||||
- fetch full command line on !Linux, and add option to strip prefixes
|
||||
such as "sh " "/bin/sh " etc etc
|
||||
- synchronize-windows option
|
||||
- possibly support rxvt-unicode extended mouse input (1015)
|
||||
- append to buffer in copy mode
|
||||
* We need a tmux terminfo entry to document the extensions we are using in
|
||||
upstream terminfo. Must NOT change (only add or remove) anything from
|
||||
TERM=screen so we can fallback!
|
||||
|
||||
35
cfg.c
35
cfg.c
@@ -92,22 +92,37 @@ load_cfg(const char *path, struct cmd_ctx *ctxin, struct causelist *causes)
|
||||
retval = 0;
|
||||
while ((buf = fgetln(f, &len))) {
|
||||
if (buf[len - 1] == '\n')
|
||||
buf[len - 1] = '\0';
|
||||
len--;
|
||||
|
||||
if (line != NULL)
|
||||
line = xrealloc(line, 1, strlen(line) + len + 1);
|
||||
else {
|
||||
line = xrealloc(line, 1, len + 1);
|
||||
memcpy(line, buf, len);
|
||||
line[len] = '\0';
|
||||
buf = line;
|
||||
line = xmalloc(len + 1);
|
||||
*line = '\0';
|
||||
}
|
||||
|
||||
/* Append buffer to line. strncat will terminate. */
|
||||
strncat(line, buf, len);
|
||||
n++;
|
||||
|
||||
/* Continuation: get next line? */
|
||||
len = strlen(line);
|
||||
if (len > 0 && line[len - 1] == '\\') {
|
||||
line[len - 1] = '\0';
|
||||
continue;
|
||||
}
|
||||
buf = line;
|
||||
line = NULL;
|
||||
|
||||
if (cmd_string_parse(buf, &cmdlist, &cause) != 0) {
|
||||
xfree(buf);
|
||||
if (cause == NULL)
|
||||
continue;
|
||||
cfg_add_cause(causes, "%s: %u: %s", path, n, cause);
|
||||
xfree(cause);
|
||||
continue;
|
||||
}
|
||||
} else
|
||||
xfree(buf);
|
||||
if (cmdlist == NULL)
|
||||
continue;
|
||||
cfg_cause = NULL;
|
||||
@@ -131,12 +146,16 @@ load_cfg(const char *path, struct cmd_ctx *ctxin, struct causelist *causes)
|
||||
retval = 1;
|
||||
cmd_list_free(cmdlist);
|
||||
if (cfg_cause != NULL) {
|
||||
cfg_add_cause(causes, "%s: %d: %s", path, n, cfg_cause);
|
||||
cfg_add_cause(
|
||||
causes, "%s: %d: %s", path, n, cfg_cause);
|
||||
xfree(cfg_cause);
|
||||
}
|
||||
}
|
||||
if (line != NULL)
|
||||
if (line != NULL) {
|
||||
cfg_add_cause(causes,
|
||||
"%s: %d: line continuation at end of file", path, n);
|
||||
xfree(line);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
return (retval);
|
||||
|
||||
@@ -76,6 +76,7 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
ctx->curclient->session = s;
|
||||
session_update_activity(s);
|
||||
server_redraw_client(ctx->curclient);
|
||||
s->curw->flags &= ~WINLINK_ALERTFLAGS;
|
||||
} else {
|
||||
if (!(ctx->cmdclient->flags & CLIENT_TERMINAL)) {
|
||||
ctx->error(ctx, "not a terminal");
|
||||
@@ -104,6 +105,7 @@ cmd_attach_session_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
environ_update(update, &ctx->cmdclient->environ, &s->environ);
|
||||
|
||||
server_redraw_client(ctx->cmdclient);
|
||||
s->curw->flags &= ~WINLINK_ALERTFLAGS;
|
||||
}
|
||||
recalculate_sizes();
|
||||
server_update_socket();
|
||||
|
||||
@@ -107,7 +107,7 @@ cmd_bind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key)
|
||||
|
||||
mtmp.key = key;
|
||||
mtmp.mode = !!args_has(args, 'c');
|
||||
if ((mbind = SPLAY_FIND(mode_key_tree, mtab->tree, &mtmp)) != NULL) {
|
||||
if ((mbind = RB_FIND(mode_key_tree, mtab->tree, &mtmp)) != NULL) {
|
||||
mbind->cmd = cmd;
|
||||
return (0);
|
||||
}
|
||||
@@ -115,6 +115,6 @@ cmd_bind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key)
|
||||
mbind->key = mtmp.key;
|
||||
mbind->mode = mtmp.mode;
|
||||
mbind->cmd = cmd;
|
||||
SPLAY_INSERT(mode_key_tree, mtab->tree, mbind);
|
||||
RB_INSERT(mode_key_tree, mtab->tree, mbind);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
buf = NULL;
|
||||
len = 0;
|
||||
|
||||
n = args_strtonum(args, 'S', SHRT_MIN, SHRT_MAX, &cause);
|
||||
n = args_strtonum(args, 'S', INT_MIN, SHRT_MAX, &cause);
|
||||
if (cause != NULL) {
|
||||
top = gd->hsize;
|
||||
xfree(cause);
|
||||
@@ -70,7 +70,7 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
if (top > gd->hsize + gd->sy - 1)
|
||||
top = gd->hsize + gd->sy - 1;
|
||||
|
||||
n = args_strtonum(args, 'E', SHRT_MIN, SHRT_MAX, &cause);
|
||||
n = args_strtonum(args, 'E', INT_MIN, SHRT_MAX, &cause);
|
||||
if (cause != NULL) {
|
||||
bottom = gd->hsize + gd->sy - 1;
|
||||
xfree(cause);
|
||||
@@ -109,6 +109,7 @@ cmd_capture_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
|
||||
if (cause != NULL) {
|
||||
ctx->error(ctx, "buffer %s", cause);
|
||||
xfree(buf);
|
||||
xfree(cause);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
@@ -76,9 +76,11 @@ cmd_choose_client_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
idx++;
|
||||
|
||||
window_choose_add(wl->window->active, i,
|
||||
"%s: %s [%ux%u %s]%s", c->tty.path,
|
||||
"%s: %s [%ux%u %s]%s%s", c->tty.path,
|
||||
c->session->name, c->tty.sx, c->tty.sy,
|
||||
c->tty.termname, c->tty.flags & TTY_UTF8 ? " (utf8)" : "");
|
||||
c->tty.termname,
|
||||
c->tty.flags & TTY_UTF8 ? " (utf8)" : "",
|
||||
c->flags & CLIENT_READONLY ? " (ro)" : "");
|
||||
}
|
||||
|
||||
cdata = xmalloc(sizeof *cdata);
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include "tmux.h"
|
||||
|
||||
/*
|
||||
* Executes a tmux command if a shell command returns true.
|
||||
* Executes a tmux command if a shell command returns true or false.
|
||||
*/
|
||||
|
||||
int cmd_if_shell_exec(struct cmd *, struct cmd_ctx *);
|
||||
@@ -35,8 +35,8 @@ void cmd_if_shell_free(void *);
|
||||
|
||||
const struct cmd_entry cmd_if_shell_entry = {
|
||||
"if-shell", "if",
|
||||
"", 2, 2,
|
||||
"shell-command command",
|
||||
"", 2, 3,
|
||||
"shell-command command [command]",
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
@@ -44,7 +44,8 @@ const struct cmd_entry cmd_if_shell_entry = {
|
||||
};
|
||||
|
||||
struct cmd_if_shell_data {
|
||||
char *cmd;
|
||||
char *cmd_if;
|
||||
char *cmd_else;
|
||||
struct cmd_ctx ctx;
|
||||
};
|
||||
|
||||
@@ -56,7 +57,11 @@ cmd_if_shell_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
const char *shellcmd = args->argv[0];
|
||||
|
||||
cdata = xmalloc(sizeof *cdata);
|
||||
cdata->cmd = xstrdup(args->argv[1]);
|
||||
cdata->cmd_if = xstrdup(args->argv[1]);
|
||||
if (args->argc == 3)
|
||||
cdata->cmd_else = xstrdup(args->argv[2]);
|
||||
else
|
||||
cdata->cmd_else = NULL;
|
||||
memcpy(&cdata->ctx, ctx, sizeof cdata->ctx);
|
||||
|
||||
if (ctx->cmdclient != NULL)
|
||||
@@ -75,12 +80,15 @@ cmd_if_shell_callback(struct job *job)
|
||||
struct cmd_if_shell_data *cdata = job->data;
|
||||
struct cmd_ctx *ctx = &cdata->ctx;
|
||||
struct cmd_list *cmdlist;
|
||||
char *cause;
|
||||
char *cause, *cmd;
|
||||
|
||||
if (!WIFEXITED(job->status) || WEXITSTATUS(job->status) != 0)
|
||||
return;
|
||||
|
||||
if (cmd_string_parse(cdata->cmd, &cmdlist, &cause) != 0) {
|
||||
if (!WIFEXITED(job->status) || WEXITSTATUS(job->status) != 0) {
|
||||
cmd = cdata->cmd_else;
|
||||
if (cmd == NULL)
|
||||
return;
|
||||
} else
|
||||
cmd = cdata->cmd_if;
|
||||
if (cmd_string_parse(cmd, &cmdlist, &cause) != 0) {
|
||||
if (cause != NULL) {
|
||||
ctx->error(ctx, "%s", cause);
|
||||
xfree(cause);
|
||||
@@ -107,6 +115,8 @@ cmd_if_shell_free(void *data)
|
||||
if (ctx->curclient != NULL)
|
||||
ctx->curclient->references--;
|
||||
|
||||
xfree(cdata->cmd);
|
||||
if (cdata->cmd_else != NULL)
|
||||
xfree(cdata->cmd_else);
|
||||
xfree(cdata->cmd_if);
|
||||
xfree(cdata);
|
||||
}
|
||||
|
||||
@@ -31,9 +31,9 @@ int cmd_list_clients_exec(struct cmd *, struct cmd_ctx *);
|
||||
|
||||
const struct cmd_entry cmd_list_clients_entry = {
|
||||
"list-clients", "lsc",
|
||||
"t:", 0, 0,
|
||||
CMD_TARGET_SESSION_USAGE,
|
||||
0,
|
||||
"F:t:", 0, 0,
|
||||
"[-F format] " CMD_TARGET_SESSION_USAGE,
|
||||
CMD_READONLY,
|
||||
NULL,
|
||||
NULL,
|
||||
cmd_list_clients_exec
|
||||
@@ -43,11 +43,13 @@ const struct cmd_entry cmd_list_clients_entry = {
|
||||
int
|
||||
cmd_list_clients_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
{
|
||||
struct args *args = self->args;
|
||||
struct client *c;
|
||||
struct session *s;
|
||||
u_int i;
|
||||
const char *s_utf8;
|
||||
struct args *args = self->args;
|
||||
struct client *c;
|
||||
struct session *s;
|
||||
struct format_tree *ft;
|
||||
const char *template;
|
||||
u_int i;
|
||||
char *line;
|
||||
|
||||
if (args_has(args, 't')) {
|
||||
s = cmd_find_session(ctx, args_get(args, 't'), 0);
|
||||
@@ -56,21 +58,32 @@ cmd_list_clients_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
} else
|
||||
s = NULL;
|
||||
|
||||
template = args_get(args, 'F');
|
||||
if (template == NULL) {
|
||||
template = "#{client_tty}: #{session_name} "
|
||||
"[#{client_width}x#{client_height} #{client_termname}]"
|
||||
"#{?client_utf8, (utf8),}"
|
||||
"#{?client_readonly, (ro),}";
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
|
||||
c = ARRAY_ITEM(&clients, i);
|
||||
if (c == NULL || c->session == NULL)
|
||||
continue;
|
||||
|
||||
if (c->tty.flags & TTY_UTF8)
|
||||
s_utf8 = " (utf8)";
|
||||
else
|
||||
s_utf8 = "";
|
||||
|
||||
if (s != NULL && s != c->session)
|
||||
continue;
|
||||
ctx->print(ctx, "%s: %s [%ux%u %s]%s", c->tty.path,
|
||||
c->session->name, c->tty.sx, c->tty.sy,
|
||||
c->tty.termname, s_utf8);
|
||||
|
||||
ft = format_create();
|
||||
format_add(ft, "line", "%u", i);
|
||||
format_session(ft, c->session);
|
||||
format_client(ft, c);
|
||||
|
||||
line = format_expand(ft, template);
|
||||
ctx->print(ctx, "%s", line);
|
||||
xfree(line);
|
||||
|
||||
format_free(ft);
|
||||
}
|
||||
|
||||
return (0);
|
||||
|
||||
@@ -54,9 +54,8 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
return (cmd_list_keys_table(self, ctx));
|
||||
|
||||
width = 0;
|
||||
*flags = '\0';
|
||||
|
||||
SPLAY_FOREACH(bd, key_bindings, &key_bindings) {
|
||||
RB_FOREACH(bd, key_bindings, &key_bindings) {
|
||||
key = key_string_lookup_key(bd->key & ~KEYC_PREFIX);
|
||||
if (key == NULL)
|
||||
continue;
|
||||
@@ -73,11 +72,12 @@ cmd_list_keys_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
width = keywidth;
|
||||
}
|
||||
|
||||
SPLAY_FOREACH(bd, key_bindings, &key_bindings) {
|
||||
RB_FOREACH(bd, key_bindings, &key_bindings) {
|
||||
key = key_string_lookup_key(bd->key & ~KEYC_PREFIX);
|
||||
if (key == NULL)
|
||||
continue;
|
||||
|
||||
*flags = '\0';
|
||||
if (!(bd->key & KEYC_PREFIX)) {
|
||||
if (bd->can_repeat)
|
||||
xsnprintf(flags, sizeof flags, "-rn ");
|
||||
@@ -116,7 +116,7 @@ cmd_list_keys_table(struct cmd *self, struct cmd_ctx *ctx)
|
||||
|
||||
width = 0;
|
||||
any_mode = 0;
|
||||
SPLAY_FOREACH(mbind, mode_key_tree, mtab->tree) {
|
||||
RB_FOREACH(mbind, mode_key_tree, mtab->tree) {
|
||||
key = key_string_lookup_key(mbind->key);
|
||||
if (key == NULL)
|
||||
continue;
|
||||
@@ -129,7 +129,7 @@ cmd_list_keys_table(struct cmd *self, struct cmd_ctx *ctx)
|
||||
width = keywidth;
|
||||
}
|
||||
|
||||
SPLAY_FOREACH(mbind, mode_key_tree, mtab->tree) {
|
||||
RB_FOREACH(mbind, mode_key_tree, mtab->tree) {
|
||||
key = key_string_lookup_key(mbind->key);
|
||||
if (key == NULL)
|
||||
continue;
|
||||
|
||||
106
cmd-list-panes.c
106
cmd-list-panes.c
@@ -28,15 +28,16 @@
|
||||
|
||||
int cmd_list_panes_exec(struct cmd *, struct cmd_ctx *);
|
||||
|
||||
void cmd_list_panes_server(struct cmd_ctx *);
|
||||
void cmd_list_panes_session(struct session *, struct cmd_ctx *, int);
|
||||
void cmd_list_panes_window(
|
||||
void cmd_list_panes_server(struct cmd *, struct cmd_ctx *);
|
||||
void cmd_list_panes_session(
|
||||
struct cmd *, struct session *, struct cmd_ctx *, int);
|
||||
void cmd_list_panes_window(struct cmd *,
|
||||
struct session *, struct winlink *, struct cmd_ctx *, int);
|
||||
|
||||
const struct cmd_entry cmd_list_panes_entry = {
|
||||
"list-panes", "lsp",
|
||||
"ast:", 0, 0,
|
||||
"[-as] [-t target]",
|
||||
"asF:t:", 0, 0,
|
||||
"[-as] [-F format] [-t target]",
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
@@ -51,87 +52,92 @@ cmd_list_panes_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
struct winlink *wl;
|
||||
|
||||
if (args_has(args, 'a'))
|
||||
cmd_list_panes_server(ctx);
|
||||
cmd_list_panes_server(self, ctx);
|
||||
else if (args_has(args, 's')) {
|
||||
s = cmd_find_session(ctx, args_get(args, 't'), 0);
|
||||
if (s == NULL)
|
||||
return (-1);
|
||||
cmd_list_panes_session(s, ctx, 1);
|
||||
cmd_list_panes_session(self, s, ctx, 1);
|
||||
} else {
|
||||
wl = cmd_find_window(ctx, args_get(args, 't'), &s);
|
||||
if (wl == NULL)
|
||||
return (-1);
|
||||
cmd_list_panes_window(s, wl, ctx, 0);
|
||||
cmd_list_panes_window(self, s, wl, ctx, 0);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
cmd_list_panes_server(struct cmd_ctx *ctx)
|
||||
cmd_list_panes_server(struct cmd *self, struct cmd_ctx *ctx)
|
||||
{
|
||||
struct session *s;
|
||||
|
||||
RB_FOREACH(s, sessions, &sessions)
|
||||
cmd_list_panes_session(s, ctx, 2);
|
||||
cmd_list_panes_session(self, s, ctx, 2);
|
||||
}
|
||||
|
||||
void
|
||||
cmd_list_panes_session(struct session *s, struct cmd_ctx *ctx, int type)
|
||||
cmd_list_panes_session(
|
||||
struct cmd *self, struct session *s, struct cmd_ctx *ctx, int type)
|
||||
{
|
||||
struct winlink *wl;
|
||||
|
||||
RB_FOREACH(wl, winlinks, &s->windows)
|
||||
cmd_list_panes_window(s, wl, ctx, type);
|
||||
cmd_list_panes_window(self, s, wl, ctx, type);
|
||||
}
|
||||
|
||||
void
|
||||
cmd_list_panes_window(
|
||||
cmd_list_panes_window(struct cmd *self,
|
||||
struct session *s, struct winlink *wl, struct cmd_ctx *ctx, int type)
|
||||
{
|
||||
struct args *args = self->args;
|
||||
struct window_pane *wp;
|
||||
struct grid *gd;
|
||||
struct grid_line *gl;
|
||||
u_int i, n;
|
||||
unsigned long long size;
|
||||
u_int n;
|
||||
struct format_tree *ft;
|
||||
const char *template;
|
||||
char *line;
|
||||
|
||||
template = args_get(args, 'F');
|
||||
if (template == NULL) {
|
||||
switch (type) {
|
||||
case 0:
|
||||
template = "#{pane_index}: "
|
||||
"[#{pane_width}x#{pane_height}] [history "
|
||||
"#{history_size}/#{history_limit}, "
|
||||
"#{history_bytes} bytes] #{pane_id}"
|
||||
"#{?pane_active, (active),}#{?pane_dead, (dead),}";
|
||||
break;
|
||||
case 1:
|
||||
template = "#{window_index}.#{pane_index}: "
|
||||
"[#{pane_width}x#{pane_height}] [history "
|
||||
"#{history_size}/#{history_limit}, "
|
||||
"#{history_bytes} bytes] #{pane_id}"
|
||||
"#{?pane_active, (active),}#{?pane_dead, (dead),}";
|
||||
break;
|
||||
case 2:
|
||||
template = "#{session_name}:#{window_index}.#{pane_index}: "
|
||||
"[#{pane_width}x#{pane_height}] [history "
|
||||
"#{history_size}/#{history_limit}, "
|
||||
"#{history_bytes} bytes] #{pane_id}"
|
||||
"#{?pane_active, (active),}#{?pane_dead, (dead),}";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
n = 0;
|
||||
TAILQ_FOREACH(wp, &wl->window->panes, entry) {
|
||||
gd = wp->base.grid;
|
||||
ft = format_create();
|
||||
format_add(ft, "line", "%u", n);
|
||||
format_session(ft, s);
|
||||
format_winlink(ft, s, wl);
|
||||
format_window_pane(ft, wp);
|
||||
|
||||
size = 0;
|
||||
for (i = 0; i < gd->hsize; i++) {
|
||||
gl = &gd->linedata[i];
|
||||
size += gl->cellsize * sizeof *gl->celldata;
|
||||
size += gl->utf8size * sizeof *gl->utf8data;
|
||||
}
|
||||
size += gd->hsize * sizeof *gd->linedata;
|
||||
line = format_expand(ft, template);
|
||||
ctx->print(ctx, "%s", line);
|
||||
xfree(line);
|
||||
|
||||
switch (type) {
|
||||
case 0:
|
||||
ctx->print(ctx,
|
||||
"%u: [%ux%u] [history %u/%u, %llu bytes] %%%u%s%s",
|
||||
n, wp->sx, wp->sy, gd->hsize, gd->hlimit, size,
|
||||
wp->id, wp == wp->window->active ? " (active)" : "",
|
||||
wp->fd == -1 ? " (dead)" : "");
|
||||
break;
|
||||
case 1:
|
||||
ctx->print(ctx,
|
||||
"%d.%u: [%ux%u] [history %u/%u, %llu bytes] "
|
||||
"%%%u%s%s", wl->idx,
|
||||
n, wp->sx, wp->sy, gd->hsize, gd->hlimit, size,
|
||||
wp->id, wp == wp->window->active ? " (active)" : "",
|
||||
wp->fd == -1 ? " (dead)" : "");
|
||||
break;
|
||||
case 2:
|
||||
ctx->print(ctx,
|
||||
"%s:%d.%u: [%ux%u] [history %u/%u, %llu bytes] "
|
||||
"%%%u%s%s", s->name, wl->idx,
|
||||
n, wp->sx, wp->sy, gd->hsize, gd->hlimit, size,
|
||||
wp->id, wp == wp->window->active ? " (active)" : "",
|
||||
wp->fd == -1 ? " (dead)" : "");
|
||||
break;
|
||||
}
|
||||
format_free(ft);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,40 +31,45 @@ int cmd_list_sessions_exec(struct cmd *, struct cmd_ctx *);
|
||||
|
||||
const struct cmd_entry cmd_list_sessions_entry = {
|
||||
"list-sessions", "ls",
|
||||
"", 0, 0,
|
||||
"",
|
||||
"F:", 0, 0,
|
||||
"[-F format]",
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
cmd_list_sessions_exec
|
||||
};
|
||||
|
||||
/* ARGSUSED */
|
||||
int
|
||||
cmd_list_sessions_exec(unused struct cmd *self, struct cmd_ctx *ctx)
|
||||
cmd_list_sessions_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
{
|
||||
struct args *args = self->args;
|
||||
struct session *s;
|
||||
struct session_group *sg;
|
||||
char *tim, tmp[64];
|
||||
u_int idx;
|
||||
time_t t;
|
||||
u_int n;
|
||||
struct format_tree *ft;
|
||||
const char *template;
|
||||
char *line;
|
||||
|
||||
template = args_get(args, 'F');
|
||||
if (template == NULL) {
|
||||
template = "#{session_name}: #{session_windows} windows "
|
||||
"(created #{session_created_string}) [#{session_width}x"
|
||||
"#{session_height}]#{?session_grouped, (group ,}"
|
||||
"#{session_group}#{?session_grouped,),}"
|
||||
"#{?session_attached, (attached),}";
|
||||
}
|
||||
|
||||
n = 0;
|
||||
RB_FOREACH(s, sessions, &sessions) {
|
||||
sg = session_group_find(s);
|
||||
if (sg == NULL)
|
||||
*tmp = '\0';
|
||||
else {
|
||||
idx = session_group_index(sg);
|
||||
xsnprintf(tmp, sizeof tmp, " (group %u)", idx);
|
||||
}
|
||||
ft = format_create();
|
||||
format_add(ft, "line", "%u", n);
|
||||
format_session(ft, s);
|
||||
|
||||
t = s->creation_time.tv_sec;
|
||||
tim = ctime(&t);
|
||||
*strchr(tim, '\n') = '\0';
|
||||
line = format_expand(ft, template);
|
||||
ctx->print(ctx, "%s", line);
|
||||
xfree(line);
|
||||
|
||||
ctx->print(ctx, "%s: %u windows (created %s) [%ux%u]%s%s",
|
||||
s->name, winlink_count(&s->windows), tim, s->sx, s->sy,
|
||||
tmp, s->flags & SESSION_UNATTACHED ? "" : " (attached)");
|
||||
format_free(ft);
|
||||
n++;
|
||||
}
|
||||
|
||||
return (0);
|
||||
|
||||
@@ -28,13 +28,14 @@
|
||||
|
||||
int cmd_list_windows_exec(struct cmd *, struct cmd_ctx *);
|
||||
|
||||
void cmd_list_windows_server(struct cmd_ctx *);
|
||||
void cmd_list_windows_session(struct session *, struct cmd_ctx *, int);
|
||||
void cmd_list_windows_server(struct cmd *, struct cmd_ctx *);
|
||||
void cmd_list_windows_session(
|
||||
struct cmd *, struct session *, struct cmd_ctx *, int);
|
||||
|
||||
const struct cmd_entry cmd_list_windows_entry = {
|
||||
"list-windows", "lsw",
|
||||
"at:", 0, 0,
|
||||
"[-a] " CMD_TARGET_SESSION_USAGE,
|
||||
"aF:t:", 0, 0,
|
||||
"[-a] [-F format] " CMD_TARGET_SESSION_USAGE,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
@@ -48,45 +49,69 @@ cmd_list_windows_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
struct session *s;
|
||||
|
||||
if (args_has(args, 'a'))
|
||||
cmd_list_windows_server(ctx);
|
||||
cmd_list_windows_server(self, ctx);
|
||||
else {
|
||||
s = cmd_find_session(ctx, args_get(args, 't'), 0);
|
||||
if (s == NULL)
|
||||
return (-1);
|
||||
cmd_list_windows_session(s, ctx, 0);
|
||||
cmd_list_windows_session(self, s, ctx, 0);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
cmd_list_windows_server(struct cmd_ctx *ctx)
|
||||
cmd_list_windows_server(struct cmd *self, struct cmd_ctx *ctx)
|
||||
{
|
||||
struct session *s;
|
||||
|
||||
RB_FOREACH(s, sessions, &sessions)
|
||||
cmd_list_windows_session(s, ctx, 1);
|
||||
cmd_list_windows_session(self, s, ctx, 1);
|
||||
}
|
||||
|
||||
void
|
||||
cmd_list_windows_session(struct session *s, struct cmd_ctx *ctx, int type)
|
||||
cmd_list_windows_session(
|
||||
struct cmd *self, struct session *s, struct cmd_ctx *ctx, int type)
|
||||
{
|
||||
struct winlink *wl;
|
||||
char *layout;
|
||||
struct args *args = self->args;
|
||||
struct winlink *wl;
|
||||
u_int n;
|
||||
struct format_tree *ft;
|
||||
const char *template;
|
||||
char *line;
|
||||
|
||||
RB_FOREACH(wl, winlinks, &s->windows) {
|
||||
layout = layout_dump(wl->window);
|
||||
if (type) {
|
||||
ctx->print(ctx, "%s:%d: %s [%ux%u] [layout %s]%s",
|
||||
s->name, wl->idx, wl->window->name, wl->window->sx,
|
||||
wl->window->sy, layout,
|
||||
wl == s->curw ? " (active)" : "");
|
||||
} else {
|
||||
ctx->print(ctx, "%d: %s [%ux%u] [layout %s]%s",
|
||||
wl->idx, wl->window->name, wl->window->sx,
|
||||
wl->window->sy, layout,
|
||||
wl == s->curw ? " (active)" : "");
|
||||
template = args_get(args, 'F');
|
||||
if (template == NULL) {
|
||||
switch (type) {
|
||||
case 0:
|
||||
template = "#{window_index}: "
|
||||
"#{window_name} "
|
||||
"[#{window_width}x#{window_height}] "
|
||||
"[layout #{window_layout}]"
|
||||
"#{?window_active, (active),}";
|
||||
break;
|
||||
case 1:
|
||||
template = "#{session_name}:#{window_index}: "
|
||||
"#{window_name} "
|
||||
"[#{window_width}x#{window_height}] "
|
||||
"[layout #{window_layout}]"
|
||||
"#{?window_active, (active),}";
|
||||
break;
|
||||
}
|
||||
xfree(layout);
|
||||
}
|
||||
|
||||
n = 0;
|
||||
RB_FOREACH(wl, winlinks, &s->windows) {
|
||||
ft = format_create();
|
||||
format_add(ft, "line", "%u", n);
|
||||
format_session(ft, s);
|
||||
format_winlink(ft, s, wl);
|
||||
|
||||
line = format_expand(ft, template);
|
||||
ctx->print(ctx, "%s", line);
|
||||
xfree(line);
|
||||
|
||||
format_free(ft);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include "tmux.h"
|
||||
|
||||
/*
|
||||
* Loads a session paste buffer from a file.
|
||||
* Loads a paste buffer from a file.
|
||||
*/
|
||||
|
||||
int cmd_load_buffer_exec(struct cmd *, struct cmd_ctx *);
|
||||
@@ -48,8 +48,9 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
{
|
||||
struct args *args = self->args;
|
||||
struct client *c = ctx->cmdclient;
|
||||
struct session *s;
|
||||
FILE *f;
|
||||
const char *path;
|
||||
const char *path, *newpath, *wd;
|
||||
char *pdata, *new_pdata, *cause;
|
||||
size_t psize;
|
||||
u_int limit;
|
||||
@@ -93,6 +94,19 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (c != NULL)
|
||||
wd = c->cwd;
|
||||
else if ((s = cmd_current_session(ctx, 0)) != NULL) {
|
||||
wd = options_get_string(&s->options, "default-path");
|
||||
if (*wd == '\0')
|
||||
wd = s->cwd;
|
||||
} else
|
||||
wd = NULL;
|
||||
if (wd != NULL && *wd != '\0') {
|
||||
newpath = get_full_path(wd, path);
|
||||
if (newpath != NULL)
|
||||
path = newpath;
|
||||
}
|
||||
if ((f = fopen(path, "rb")) == NULL) {
|
||||
ctx->error(ctx, "%s: %s", path, strerror(errno));
|
||||
return (-1);
|
||||
@@ -125,6 +139,7 @@ cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
}
|
||||
if (paste_replace(&global_buffers, buffer, pdata, psize) != 0) {
|
||||
ctx->error(ctx, "no buffer %d", buffer);
|
||||
xfree(pdata);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
|
||||
@@ -154,9 +154,17 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
}
|
||||
|
||||
/* Find new session size. */
|
||||
if (detached) {
|
||||
if (ctx->cmdclient != NULL) {
|
||||
sx = ctx->cmdclient->tty.sx;
|
||||
sy = ctx->cmdclient->tty.sy;
|
||||
} else if (ctx->curclient != NULL) {
|
||||
sx = ctx->curclient->tty.sx;
|
||||
sy = ctx->curclient->tty.sy;
|
||||
} else {
|
||||
sx = 80;
|
||||
sy = 24;
|
||||
}
|
||||
if (detached) {
|
||||
if (args_has(args, 'x')) {
|
||||
sx = strtonum(
|
||||
args_get(args, 'x'), 1, USHRT_MAX, &errstr);
|
||||
@@ -173,12 +181,6 @@ cmd_new_session_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
} else if (ctx->cmdclient != NULL) {
|
||||
sx = ctx->cmdclient->tty.sx;
|
||||
sy = ctx->cmdclient->tty.sy;
|
||||
} else {
|
||||
sx = ctx->curclient->tty.sx;
|
||||
sy = ctx->curclient->tty.sy;
|
||||
}
|
||||
if (sy > 0 && options_get_number(&global_s_options, "status"))
|
||||
sy--;
|
||||
|
||||
@@ -44,7 +44,8 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
struct args *args = self->args;
|
||||
struct session *s;
|
||||
struct winlink *wl;
|
||||
char *cmd, *cwd, *cause;
|
||||
const char *cmd, *cwd;
|
||||
char *cause;
|
||||
int idx, last, detached;
|
||||
|
||||
if (args_has(args, 'a')) {
|
||||
@@ -98,13 +99,7 @@ cmd_new_window_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
cmd = options_get_string(&s->options, "default-command");
|
||||
else
|
||||
cmd = args->argv[0];
|
||||
cwd = options_get_string(&s->options, "default-path");
|
||||
if (*cwd == '\0') {
|
||||
if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL)
|
||||
cwd = ctx->cmdclient->cwd;
|
||||
else
|
||||
cwd = s->cwd;
|
||||
}
|
||||
cwd = cmd_get_default_path(ctx);
|
||||
|
||||
if (idx == -1)
|
||||
idx = -1 - options_get_number(&s->options, "base-index");
|
||||
|
||||
@@ -38,7 +38,7 @@ void cmd_pipe_pane_error_callback(struct bufferevent *, short, void *);
|
||||
const struct cmd_entry cmd_pipe_pane_entry = {
|
||||
"pipe-pane", "pipep",
|
||||
"ot:", 0, 1,
|
||||
CMD_TARGET_PANE_USAGE "[-o] [command]",
|
||||
"[-o] " CMD_TARGET_PANE_USAGE " [command]",
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
@@ -54,11 +54,9 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
char *command;
|
||||
int old_fd, pipe_fd[2], null_fd;
|
||||
|
||||
if ((c = cmd_find_client(ctx, NULL)) == NULL)
|
||||
return (-1);
|
||||
|
||||
if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL)
|
||||
return (-1);
|
||||
c = cmd_find_client(ctx, NULL);
|
||||
|
||||
/* Destroy the old pipe. */
|
||||
old_fd = wp->pipe_fd;
|
||||
|
||||
@@ -28,8 +28,8 @@ int cmd_refresh_client_exec(struct cmd *, struct cmd_ctx *);
|
||||
|
||||
const struct cmd_entry cmd_refresh_client_entry = {
|
||||
"refresh-client", "refresh",
|
||||
"t:", 0, 0,
|
||||
CMD_TARGET_CLIENT_USAGE,
|
||||
"St:", 0, 0,
|
||||
"[-S] " CMD_TARGET_CLIENT_USAGE,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
@@ -45,7 +45,11 @@ cmd_refresh_client_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
if ((c = cmd_find_client(ctx, args_get(args, 't'))) == NULL)
|
||||
return (-1);
|
||||
|
||||
server_redraw_client(c);
|
||||
if (args_has(args, 'S')) {
|
||||
status_update_jobs(c);
|
||||
server_status_client(c);
|
||||
} else
|
||||
server_redraw_client(c);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -49,15 +49,18 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
struct session *s;
|
||||
struct environ env;
|
||||
const char *cmd;
|
||||
char *cause;
|
||||
char *cause;
|
||||
u_int idx;
|
||||
|
||||
if ((wl = cmd_find_pane(ctx, args_get(args, 't'), &s, &wp)) == NULL)
|
||||
return (-1);
|
||||
w = wl->window;
|
||||
|
||||
if (!args_has(self->args, 'k') && wp->fd != -1) {
|
||||
if (window_pane_index(wp, &idx) != 0)
|
||||
fatalx("index not found");
|
||||
ctx->error(ctx, "pane still active: %s:%u.%u",
|
||||
s->name, wl->idx, window_pane_index(w, wp));
|
||||
s->name, wl->idx, idx);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include "tmux.h"
|
||||
|
||||
/*
|
||||
* Saves a session paste buffer to a file.
|
||||
* Saves a paste buffer to a file.
|
||||
*/
|
||||
|
||||
int cmd_save_buffer_exec(struct cmd *, struct cmd_ctx *);
|
||||
@@ -45,8 +45,9 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
{
|
||||
struct args *args = self->args;
|
||||
struct client *c = ctx->cmdclient;
|
||||
struct session *s;
|
||||
struct paste_buffer *pb;
|
||||
const char *path;
|
||||
const char *path, *newpath, *wd;
|
||||
char *cause;
|
||||
int buffer;
|
||||
mode_t mask;
|
||||
@@ -80,6 +81,20 @@ cmd_save_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
}
|
||||
bufferevent_write(c->stdout_event, pb->data, pb->size);
|
||||
} else {
|
||||
if (c != NULL)
|
||||
wd = c->cwd;
|
||||
else if ((s = cmd_current_session(ctx, 0)) != NULL) {
|
||||
wd = options_get_string(&s->options, "default-path");
|
||||
if (*wd == '\0')
|
||||
wd = s->cwd;
|
||||
} else
|
||||
wd = NULL;
|
||||
if (wd != NULL && *wd != '\0') {
|
||||
newpath = get_full_path(wd, path);
|
||||
if (newpath != NULL)
|
||||
path = newpath;
|
||||
}
|
||||
|
||||
mask = umask(S_IRWXG | S_IRWXO);
|
||||
if (args_has(self->args, 'a'))
|
||||
f = fopen(path, "ab");
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
@@ -30,8 +31,8 @@ int cmd_send_keys_exec(struct cmd *, struct cmd_ctx *);
|
||||
|
||||
const struct cmd_entry cmd_send_keys_entry = {
|
||||
"send-keys", "send",
|
||||
"t:", 0, -1,
|
||||
"[-t target-pane] key ...",
|
||||
"Rt:", 0, -1,
|
||||
"[-R] [-t target-pane] key ...",
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
@@ -44,12 +45,29 @@ cmd_send_keys_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
struct args *args = self->args;
|
||||
struct window_pane *wp;
|
||||
struct session *s;
|
||||
struct input_ctx *ictx;
|
||||
const char *str;
|
||||
int i, key;
|
||||
|
||||
if (cmd_find_pane(ctx, args_get(args, 't'), &s, &wp) == NULL)
|
||||
return (-1);
|
||||
|
||||
if (args_has(args, 'R')) {
|
||||
ictx = &wp->ictx;
|
||||
|
||||
memcpy(&ictx->cell, &grid_default_cell, sizeof ictx->cell);
|
||||
memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
|
||||
ictx->old_cx = 0;
|
||||
ictx->old_cy = 0;
|
||||
|
||||
if (wp->mode == NULL)
|
||||
screen_write_start(&ictx->ctx, wp, &wp->base);
|
||||
else
|
||||
screen_write_start(&ictx->ctx, NULL, &wp->base);
|
||||
screen_write_reset(&ictx->ctx);
|
||||
screen_write_stop(&ictx->ctx);
|
||||
}
|
||||
|
||||
for (i = 0; i < args->argc; i++) {
|
||||
str = args->argv[i];
|
||||
|
||||
|
||||
@@ -28,8 +28,8 @@ int cmd_send_prefix_exec(struct cmd *, struct cmd_ctx *);
|
||||
|
||||
const struct cmd_entry cmd_send_prefix_entry = {
|
||||
"send-prefix", NULL,
|
||||
"t:", 0, 0,
|
||||
CMD_TARGET_PANE_USAGE,
|
||||
"2t:", 0, 0,
|
||||
"[-2] " CMD_TARGET_PANE_USAGE,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
@@ -42,13 +42,16 @@ cmd_send_prefix_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
struct args *args = self->args;
|
||||
struct session *s;
|
||||
struct window_pane *wp;
|
||||
struct keylist *keylist;
|
||||
int key;
|
||||
|
||||
if (cmd_find_pane(ctx, args_get(args, 't'), &s, &wp) == NULL)
|
||||
return (-1);
|
||||
|
||||
keylist = options_get_data(&s->options, "prefix");
|
||||
window_pane_key(wp, s, ARRAY_FIRST(keylist));
|
||||
if (args_has(args, '2'))
|
||||
key = options_get_number(&s->options, "prefix2");
|
||||
else
|
||||
key = options_get_number(&s->options, "prefix");
|
||||
window_pane_key(wp, s, key);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "tmux.h"
|
||||
|
||||
/*
|
||||
* Add or set a session paste buffer.
|
||||
* Add or set a paste buffer.
|
||||
*/
|
||||
|
||||
int cmd_set_buffer_exec(struct cmd *, struct cmd_ctx *);
|
||||
|
||||
@@ -45,7 +45,7 @@ struct options_entry *cmd_set_option_string(struct cmd *, struct cmd_ctx *,
|
||||
struct options_entry *cmd_set_option_number(struct cmd *, struct cmd_ctx *,
|
||||
const struct options_table_entry *, struct options *,
|
||||
const char *);
|
||||
struct options_entry *cmd_set_option_keys(struct cmd *, struct cmd_ctx *,
|
||||
struct options_entry *cmd_set_option_key(struct cmd *, struct cmd_ctx *,
|
||||
const struct options_table_entry *, struct options *,
|
||||
const char *);
|
||||
struct options_entry *cmd_set_option_colour(struct cmd *, struct cmd_ctx *,
|
||||
@@ -236,8 +236,8 @@ cmd_set_option_set(struct cmd *self, struct cmd_ctx *ctx,
|
||||
case OPTIONS_TABLE_NUMBER:
|
||||
o = cmd_set_option_number(self, ctx, oe, oo, value);
|
||||
break;
|
||||
case OPTIONS_TABLE_KEYS:
|
||||
o = cmd_set_option_keys(self, ctx, oe, oo, value);
|
||||
case OPTIONS_TABLE_KEY:
|
||||
o = cmd_set_option_key(self, ctx, oe, oo, value);
|
||||
break;
|
||||
case OPTIONS_TABLE_COLOUR:
|
||||
o = cmd_set_option_colour(self, ctx, oe, oo, value);
|
||||
@@ -298,31 +298,19 @@ cmd_set_option_number(unused struct cmd *self, struct cmd_ctx *ctx,
|
||||
return (options_set_number(oo, oe->name, ll));
|
||||
}
|
||||
|
||||
/* Set a keys option. */
|
||||
/* Set a key option. */
|
||||
struct options_entry *
|
||||
cmd_set_option_keys(unused struct cmd *self, struct cmd_ctx *ctx,
|
||||
cmd_set_option_key(unused struct cmd *self, struct cmd_ctx *ctx,
|
||||
const struct options_table_entry *oe, struct options *oo, const char *value)
|
||||
{
|
||||
struct keylist *keylist;
|
||||
char *copy, *ptr, *s;
|
||||
int key;
|
||||
int key;
|
||||
|
||||
keylist = xmalloc(sizeof *keylist);
|
||||
ARRAY_INIT(keylist);
|
||||
|
||||
ptr = copy = xstrdup(value);
|
||||
while ((s = strsep(&ptr, ",")) != NULL) {
|
||||
if ((key = key_string_lookup_string(s)) == KEYC_NONE) {
|
||||
ctx->error(ctx, "unknown key: %s", s);
|
||||
xfree(copy);
|
||||
xfree(keylist);
|
||||
return (NULL);
|
||||
}
|
||||
ARRAY_ADD(keylist, key);
|
||||
if ((key = key_string_lookup_string(value)) == KEYC_NONE) {
|
||||
ctx->error(ctx, "bad key: %s", value);
|
||||
return (NULL);
|
||||
}
|
||||
xfree(copy);
|
||||
|
||||
return (options_set_data(oo, oe->name, keylist, xfree));
|
||||
return (options_set_number(oo, oe->name, key));
|
||||
}
|
||||
|
||||
/* Set a colour option. */
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "tmux.h"
|
||||
|
||||
/*
|
||||
* Show a session paste buffer.
|
||||
* Show a paste buffer.
|
||||
*/
|
||||
|
||||
int cmd_show_buffer_exec(struct cmd *, struct cmd_ctx *);
|
||||
|
||||
@@ -57,8 +57,8 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
struct window *w;
|
||||
struct window_pane *wp, *new_wp = NULL;
|
||||
struct environ env;
|
||||
char *cmd, *cwd, *cause;
|
||||
const char *shell;
|
||||
const char *cmd, *cwd, *shell;
|
||||
char *cause, *new_cause;
|
||||
u_int hlimit, paneidx;
|
||||
int size, percentage;
|
||||
enum layout_type type;
|
||||
@@ -77,13 +77,7 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
cmd = options_get_string(&s->options, "default-command");
|
||||
else
|
||||
cmd = args->argv[0];
|
||||
cwd = options_get_string(&s->options, "default-path");
|
||||
if (*cwd == '\0') {
|
||||
if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL)
|
||||
cwd = ctx->cmdclient->cwd;
|
||||
else
|
||||
cwd = s->cwd;
|
||||
}
|
||||
cwd = cmd_get_default_path(ctx);
|
||||
|
||||
type = LAYOUT_TOPBOTTOM;
|
||||
if (args_has(args, 'h'))
|
||||
@@ -93,16 +87,18 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
if (args_has(args, 'l')) {
|
||||
size = args_strtonum(args, 'l', 0, INT_MAX, &cause);
|
||||
if (cause != NULL) {
|
||||
ctx->error(ctx, "size %s", cause);
|
||||
xasprintf(&new_cause, "size %s", cause);
|
||||
xfree(cause);
|
||||
return (-1);
|
||||
cause = new_cause;
|
||||
goto error;
|
||||
}
|
||||
} else if (args_has(args, 'p')) {
|
||||
percentage = args_strtonum(args, 'p', 0, INT_MAX, &cause);
|
||||
if (cause != NULL) {
|
||||
ctx->error(ctx, "percentage %s", cause);
|
||||
xasprintf(&new_cause, "percentage %s", cause);
|
||||
xfree(cause);
|
||||
return (-1);
|
||||
cause = new_cause;
|
||||
goto error;
|
||||
}
|
||||
if (type == LAYOUT_TOPBOTTOM)
|
||||
size = (wp->sy * percentage) / 100;
|
||||
@@ -137,7 +133,8 @@ cmd_split_window_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
environ_free(&env);
|
||||
|
||||
if (args_has(args, 'P')) {
|
||||
paneidx = window_pane_index(wl->window, new_wp);
|
||||
if (window_pane_index(new_wp, &paneidx) != 0)
|
||||
fatalx("index not found");
|
||||
ctx->print(ctx, "%s:%u.%u", s->name, wl->idx, paneidx);
|
||||
}
|
||||
return (0);
|
||||
|
||||
@@ -32,9 +32,9 @@ int cmd_switch_client_exec(struct cmd *, struct cmd_ctx *);
|
||||
|
||||
const struct cmd_entry cmd_switch_client_entry = {
|
||||
"switch-client", "switchc",
|
||||
"lc:npt:", 0, 0,
|
||||
"[-lnp] [-c target-client] [-t target-session]",
|
||||
0,
|
||||
"lc:npt:r", 0, 0,
|
||||
"[-lnpr] [-c target-client] [-t target-session]",
|
||||
CMD_READONLY,
|
||||
cmd_switch_client_key_binding,
|
||||
NULL,
|
||||
cmd_switch_client_exec
|
||||
@@ -67,6 +67,16 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
if ((c = cmd_find_client(ctx, args_get(args, 'c'))) == NULL)
|
||||
return (-1);
|
||||
|
||||
if (args_has(args, 'r')) {
|
||||
if (c->flags & CLIENT_READONLY) {
|
||||
c->flags &= ~CLIENT_READONLY;
|
||||
ctx->info(ctx, "made client writable");
|
||||
} else {
|
||||
c->flags |= CLIENT_READONLY;
|
||||
ctx->info(ctx, "made client read-only");
|
||||
}
|
||||
}
|
||||
|
||||
s = NULL;
|
||||
if (args_has(args, 'n')) {
|
||||
if ((s = session_next_session(c->session)) == NULL) {
|
||||
@@ -98,6 +108,7 @@ cmd_switch_client_exec(struct cmd *self, struct cmd_ctx *ctx)
|
||||
recalculate_sizes();
|
||||
server_check_unattached();
|
||||
server_redraw_client(c);
|
||||
s->curw->flags &= ~WINLINK_ALERTFLAGS;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -57,11 +57,9 @@ cmd_unbind_key_exec(struct cmd *self, unused struct cmd_ctx *ctx)
|
||||
int key;
|
||||
|
||||
if (args_has(args, 'a')) {
|
||||
while (!SPLAY_EMPTY(&key_bindings)) {
|
||||
bd = SPLAY_ROOT(&key_bindings);
|
||||
SPLAY_REMOVE(key_bindings, &key_bindings, bd);
|
||||
cmd_list_free(bd->cmdlist);
|
||||
xfree(bd);
|
||||
while (!RB_EMPTY(&key_bindings)) {
|
||||
bd = RB_ROOT(&key_bindings);
|
||||
key_bindings_remove(bd->key);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
@@ -97,8 +95,8 @@ cmd_unbind_key_table(struct cmd *self, struct cmd_ctx *ctx, int key)
|
||||
|
||||
mtmp.key = key;
|
||||
mtmp.mode = !!args_has(args, 'c');
|
||||
if ((mbind = SPLAY_FIND(mode_key_tree, mtab->tree, &mtmp)) != NULL) {
|
||||
SPLAY_REMOVE(mode_key_tree, mtab->tree, mbind);
|
||||
if ((mbind = RB_FIND(mode_key_tree, mtab->tree, &mtmp)) != NULL) {
|
||||
RB_REMOVE(mode_key_tree, mtab->tree, mbind);
|
||||
xfree(mbind);
|
||||
}
|
||||
return (0);
|
||||
|
||||
32
cmd.c
32
cmd.c
@@ -1212,3 +1212,35 @@ cmd_template_replace(char *template, const char *s, int idx)
|
||||
|
||||
return (buf);
|
||||
}
|
||||
|
||||
/* Return the default path for a new pane. */
|
||||
const char *
|
||||
cmd_get_default_path(struct cmd_ctx *ctx)
|
||||
{
|
||||
const char *cwd;
|
||||
struct session *s;
|
||||
struct window_pane *wp;
|
||||
struct environ_entry *envent;
|
||||
|
||||
if ((s = cmd_current_session(ctx, 0)) == NULL)
|
||||
return (NULL);
|
||||
|
||||
cwd = options_get_string(&s->options, "default-path");
|
||||
if ((cwd[0] == '~' && cwd[1] == '\0') || !strcmp(cwd, "$HOME")) {
|
||||
envent = environ_find(&global_environ, "HOME");
|
||||
if (envent != NULL && *envent->value != '\0')
|
||||
return envent->value;
|
||||
cwd = "";
|
||||
}
|
||||
if (*cwd == '\0') {
|
||||
if (ctx->cmdclient != NULL && ctx->cmdclient->cwd != NULL)
|
||||
return (ctx->cmdclient->cwd);
|
||||
if (ctx->curclient != NULL) {
|
||||
wp = s->curw->window->active;
|
||||
if ((cwd = osdep_get_cwd(wp->pid)) != NULL)
|
||||
return (cwd);
|
||||
}
|
||||
return (s->cwd);
|
||||
}
|
||||
return (cwd);
|
||||
}
|
||||
|
||||
52
colour.c
52
colour.c
@@ -19,7 +19,6 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -41,7 +40,7 @@ struct colour_rgb {
|
||||
struct colour_rgb *colour_rgb_256;
|
||||
|
||||
void colour_rgb_generate256(void);
|
||||
double colour_rgb_distance(struct colour_rgb *, struct colour_rgb *);
|
||||
u_int colour_rgb_distance(struct colour_rgb *, struct colour_rgb *);
|
||||
int colour_rgb_find(struct colour_rgb *);
|
||||
|
||||
/* Generate 256 colour RGB table. */
|
||||
@@ -91,7 +90,7 @@ colour_rgb_generate256(void)
|
||||
}
|
||||
|
||||
/* Get colour RGB distance. */
|
||||
double
|
||||
u_int
|
||||
colour_rgb_distance(struct colour_rgb *rgb1, struct colour_rgb *rgb2)
|
||||
{
|
||||
int r, g, b;
|
||||
@@ -99,21 +98,20 @@ colour_rgb_distance(struct colour_rgb *rgb1, struct colour_rgb *rgb2)
|
||||
r = rgb1->r - rgb2->r;
|
||||
g = rgb1->g - rgb2->g;
|
||||
b = rgb1->b - rgb2->b;
|
||||
return (sqrt(r * r + g * g + b * b));
|
||||
return (r * r + g * g + b * b);
|
||||
}
|
||||
|
||||
/* Work out the nearest colour from the 256 colour set. */
|
||||
int
|
||||
colour_rgb_find(struct colour_rgb *rgb)
|
||||
{
|
||||
double distance, lowest;
|
||||
u_int colour, i;
|
||||
u_int distance, lowest, colour, i;
|
||||
|
||||
if (colour_rgb_256 == NULL)
|
||||
colour_rgb_generate256();
|
||||
|
||||
colour = 16;
|
||||
lowest = INFINITY;
|
||||
lowest = UINT_MAX;
|
||||
for (i = 0; i < 240; i++) {
|
||||
distance = colour_rgb_distance(&colour_rgb_256[i], rgb);
|
||||
if (distance < lowest) {
|
||||
@@ -172,6 +170,22 @@ colour_tostring(int c)
|
||||
return ("white");
|
||||
case 8:
|
||||
return ("default");
|
||||
case 90:
|
||||
return ("brightblack");
|
||||
case 91:
|
||||
return ("brightred");
|
||||
case 92:
|
||||
return ("brightgreen");
|
||||
case 93:
|
||||
return ("brightyellow");
|
||||
case 94:
|
||||
return ("brightblue");
|
||||
case 95:
|
||||
return ("brightmagenta");
|
||||
case 96:
|
||||
return ("brightcyan");
|
||||
case 97:
|
||||
return ("brightwhite");
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
@@ -221,6 +235,30 @@ colour_fromstring(const char *s)
|
||||
return (7);
|
||||
if (strcasecmp(s, "default") == 0 || (s[0] == '8' && s[1] == '\0'))
|
||||
return (8);
|
||||
if (strcasecmp(s, "brightblack") == 0 ||
|
||||
(s[0] == '9' && s[1] == '0' && s[1] == '\0'))
|
||||
return (90);
|
||||
if (strcasecmp(s, "brightred") == 0 ||
|
||||
(s[0] == '9' && s[1] == '1' && s[1] == '\0'))
|
||||
return (91);
|
||||
if (strcasecmp(s, "brightgreen") == 0 ||
|
||||
(s[0] == '9' && s[1] == '2' && s[1] == '\0'))
|
||||
return (92);
|
||||
if (strcasecmp(s, "brightyellow") == 0 ||
|
||||
(s[0] == '9' && s[1] == '3' && s[1] == '\0'))
|
||||
return (93);
|
||||
if (strcasecmp(s, "brightblue") == 0 ||
|
||||
(s[0] == '9' && s[1] == '4' && s[1] == '\0'))
|
||||
return (94);
|
||||
if (strcasecmp(s, "brightmagenta") == 0 ||
|
||||
(s[0] == '9' && s[1] == '5' && s[1] == '\0'))
|
||||
return (95);
|
||||
if (strcasecmp(s, "brightcyan") == 0 ||
|
||||
(s[0] == '9' && s[1] == '6' && s[1] == '\0'))
|
||||
return (96);
|
||||
if (strcasecmp(s, "brightwhite") == 0 ||
|
||||
(s[0] == '9' && s[1] == '7' && s[1] == '\0'))
|
||||
return (97);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
|
||||
5
compat.h
5
compat.h
@@ -196,6 +196,11 @@ size_t strlcat(char *, const char *, size_t);
|
||||
int daemon(int, int);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_B64_NTOP
|
||||
/* b64_ntop.c */
|
||||
int b64_ntop(const char *, size_t, char *, size_t);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_FORKPTY
|
||||
/* forkpty.c */
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
@@ -44,12 +44,15 @@ int
|
||||
vasprintf(char **ret, const char *fmt, va_list ap)
|
||||
{
|
||||
int n;
|
||||
va_list ap2;
|
||||
|
||||
va_copy(ap2, ap);
|
||||
|
||||
if ((n = vsnprintf(NULL, 0, fmt, ap)) < 0)
|
||||
goto error;
|
||||
|
||||
*ret = xmalloc(n + 1);
|
||||
if ((n = vsnprintf(*ret, n + 1, fmt, ap)) < 0) {
|
||||
if ((n = vsnprintf(*ret, n + 1, fmt, ap2)) < 0) {
|
||||
xfree(*ret);
|
||||
goto error;
|
||||
}
|
||||
|
||||
182
compat/b64_ntop.c
Normal file
182
compat/b64_ntop.c
Normal file
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 1998 by Internet Software Consortium.
|
||||
*
|
||||
* 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 INTERNET SOFTWARE CONSORTIUM DISCLAIMS
|
||||
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
|
||||
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Portions Copyright (c) 1995 by International Business Machines, Inc.
|
||||
*
|
||||
* International Business Machines, Inc. (hereinafter called IBM) grants
|
||||
* permission under its copyrights to use, copy, modify, and distribute this
|
||||
* Software with or without fee, provided that the above copyright notice and
|
||||
* all paragraphs of this notice appear in all copies, and that the name of IBM
|
||||
* not be used in connection with the marketing of any product incorporating
|
||||
* the Software or modifications thereof, without specific, written prior
|
||||
* permission.
|
||||
*
|
||||
* To the extent it has a right to do so, IBM grants an immunity from suit
|
||||
* under its patents, if any, for the use, sale or manufacture of products to
|
||||
* the extent that such products are used for performing Domain Name System
|
||||
* dynamic updates in TCP/IP networks by means of the Software. No immunity is
|
||||
* granted for any product per se or for any other function of any product.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
|
||||
* DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
|
||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
|
||||
* IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define Assert(Cond) if (!(Cond)) abort()
|
||||
|
||||
static const char Base64[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
static const char Pad64 = '=';
|
||||
|
||||
/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
|
||||
The following encoding technique is taken from RFC 1521 by Borenstein
|
||||
and Freed. It is reproduced here in a slightly edited form for
|
||||
convenience.
|
||||
|
||||
A 65-character subset of US-ASCII is used, enabling 6 bits to be
|
||||
represented per printable character. (The extra 65th character, "=",
|
||||
is used to signify a special processing function.)
|
||||
|
||||
The encoding process represents 24-bit groups of input bits as output
|
||||
strings of 4 encoded characters. Proceeding from left to right, a
|
||||
24-bit input group is formed by concatenating 3 8-bit input groups.
|
||||
These 24 bits are then treated as 4 concatenated 6-bit groups, each
|
||||
of which is translated into a single digit in the base64 alphabet.
|
||||
|
||||
Each 6-bit group is used as an index into an array of 64 printable
|
||||
characters. The character referenced by the index is placed in the
|
||||
output string.
|
||||
|
||||
Table 1: The Base64 Alphabet
|
||||
|
||||
Value Encoding Value Encoding Value Encoding Value Encoding
|
||||
0 A 17 R 34 i 51 z
|
||||
1 B 18 S 35 j 52 0
|
||||
2 C 19 T 36 k 53 1
|
||||
3 D 20 U 37 l 54 2
|
||||
4 E 21 V 38 m 55 3
|
||||
5 F 22 W 39 n 56 4
|
||||
6 G 23 X 40 o 57 5
|
||||
7 H 24 Y 41 p 58 6
|
||||
8 I 25 Z 42 q 59 7
|
||||
9 J 26 a 43 r 60 8
|
||||
10 K 27 b 44 s 61 9
|
||||
11 L 28 c 45 t 62 +
|
||||
12 M 29 d 46 u 63 /
|
||||
13 N 30 e 47 v
|
||||
14 O 31 f 48 w (pad) =
|
||||
15 P 32 g 49 x
|
||||
16 Q 33 h 50 y
|
||||
|
||||
Special processing is performed if fewer than 24 bits are available
|
||||
at the end of the data being encoded. A full encoding quantum is
|
||||
always completed at the end of a quantity. When fewer than 24 input
|
||||
bits are available in an input group, zero bits are added (on the
|
||||
right) to form an integral number of 6-bit groups. Padding at the
|
||||
end of the data is performed using the '=' character.
|
||||
|
||||
Since all base64 input is an integral number of octets, only the
|
||||
-------------------------------------------------
|
||||
following cases can arise:
|
||||
|
||||
(1) the final quantum of encoding input is an integral
|
||||
multiple of 24 bits; here, the final unit of encoded
|
||||
output will be an integral multiple of 4 characters
|
||||
with no "=" padding,
|
||||
(2) the final quantum of encoding input is exactly 8 bits;
|
||||
here, the final unit of encoded output will be two
|
||||
characters followed by two "=" padding characters, or
|
||||
(3) the final quantum of encoding input is exactly 16 bits;
|
||||
here, the final unit of encoded output will be three
|
||||
characters followed by one "=" padding character.
|
||||
*/
|
||||
|
||||
int
|
||||
b64_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize) {
|
||||
size_t datalength = 0;
|
||||
uint8_t input[3];
|
||||
uint8_t output[4];
|
||||
size_t i;
|
||||
|
||||
while (2 < srclength) {
|
||||
input[0] = *src++;
|
||||
input[1] = *src++;
|
||||
input[2] = *src++;
|
||||
srclength -= 3;
|
||||
|
||||
output[0] = input[0] >> 2;
|
||||
output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
|
||||
output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
|
||||
output[3] = input[2] & 0x3f;
|
||||
Assert(output[0] < 64);
|
||||
Assert(output[1] < 64);
|
||||
Assert(output[2] < 64);
|
||||
Assert(output[3] < 64);
|
||||
|
||||
if (datalength + 4 > targsize)
|
||||
return (-1);
|
||||
target[datalength++] = Base64[output[0]];
|
||||
target[datalength++] = Base64[output[1]];
|
||||
target[datalength++] = Base64[output[2]];
|
||||
target[datalength++] = Base64[output[3]];
|
||||
}
|
||||
|
||||
/* Now we worry about padding. */
|
||||
if (0 != srclength) {
|
||||
/* Get what's left. */
|
||||
input[0] = input[1] = input[2] = '\0';
|
||||
for (i = 0; i < srclength; i++)
|
||||
input[i] = *src++;
|
||||
|
||||
output[0] = input[0] >> 2;
|
||||
output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
|
||||
output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
|
||||
Assert(output[0] < 64);
|
||||
Assert(output[1] < 64);
|
||||
Assert(output[2] < 64);
|
||||
|
||||
if (datalength + 4 > targsize)
|
||||
return (-1);
|
||||
target[datalength++] = Base64[output[0]];
|
||||
target[datalength++] = Base64[output[1]];
|
||||
if (srclength == 1)
|
||||
target[datalength++] = Pad64;
|
||||
else
|
||||
target[datalength++] = Base64[output[2]];
|
||||
target[datalength++] = Pad64;
|
||||
}
|
||||
if (datalength >= targsize)
|
||||
return (-1);
|
||||
target[datalength] = '\0'; /* Returned value doesn't count \0. */
|
||||
return (datalength);
|
||||
}
|
||||
95
configure.ac
95
configure.ac
@@ -1,7 +1,7 @@
|
||||
# $Id$
|
||||
|
||||
# Miscellaneous autofoo bullshit.
|
||||
AC_INIT(tmux, 1.5)
|
||||
AC_INIT(tmux, 1.6)
|
||||
|
||||
AC_CONFIG_AUX_DIR(etc)
|
||||
AM_INIT_AUTOMAKE([foreign])
|
||||
@@ -12,6 +12,7 @@ AC_CANONICAL_HOST
|
||||
# autoconf will automatically use CFLAGS="-O2 -g". Prevent that by using an
|
||||
# empty default.
|
||||
: ${CFLAGS=""}
|
||||
|
||||
# Set up the compiler in two different ways and say yes we may want to install.
|
||||
AC_PROG_CC
|
||||
AM_PROG_CC_C_O
|
||||
@@ -52,9 +53,8 @@ AM_CONDITIONAL(IS_DEBUG, test "x$found_debug" = xyes)
|
||||
AC_ARG_ENABLE(
|
||||
static,
|
||||
AC_HELP_STRING(--enable-static, create a static build),
|
||||
[found_static=$enable_static]
|
||||
[LDFLAGS="$LDFLAGS -static"]
|
||||
)
|
||||
AM_CONDITIONAL(IS_STATIC, test "x" = xyes)
|
||||
|
||||
# Is this gcc?
|
||||
AM_CONDITIONAL(IS_GCC, test "x$GCC" = xyes)
|
||||
@@ -102,12 +102,28 @@ AM_CONDITIONAL(IS_GLIBC, test "x$found_glibc" = xyes)
|
||||
AC_MSG_RESULT($found_glibc)
|
||||
|
||||
# Look for clock_gettime. Must come before event_init.
|
||||
AC_CHECK_LIB(rt, clock_gettime)
|
||||
AC_SEARCH_LIBS(clock_gettime, rt)
|
||||
|
||||
# Look for libevent.
|
||||
AC_SEARCH_LIBS(event_init, [event event-1.4 event2], found_libevent=yes, found_libevent=no)
|
||||
PKG_CHECK_MODULES(
|
||||
LIBEVENT,
|
||||
libevent,
|
||||
[
|
||||
CPPFLAGS="$LIBEVENT_CFLAGS $CPPFLAGS"
|
||||
LIBS="$LIBEVENT_LIBS $LIBS"
|
||||
found_libevent=yes
|
||||
],
|
||||
[
|
||||
AC_SEARCH_LIBS(
|
||||
event_init,
|
||||
[event event-1.4 event2],
|
||||
found_libevent=yes,
|
||||
found_libevent=no
|
||||
)
|
||||
]
|
||||
)
|
||||
if test "x$found_libevent" = xno; then
|
||||
AC_MSG_ERROR("libevent not found")
|
||||
AC_MSG_ERROR("libevent not found")
|
||||
fi
|
||||
|
||||
# Look for curses.
|
||||
@@ -121,16 +137,48 @@ if test "x$found_curses" = xno; then
|
||||
AC_MSG_ERROR("curses not found")
|
||||
fi
|
||||
|
||||
# Check for b64_ntop.
|
||||
AC_MSG_CHECKING(for b64_ntop)
|
||||
AC_TRY_LINK(
|
||||
[
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <resolv.h>
|
||||
],
|
||||
[b64_ntop(NULL, 0, NULL, 0);],
|
||||
found_b64_ntop=yes,
|
||||
found_b64_ntop=no
|
||||
)
|
||||
if test "x$found_b64_ntop" = xno; then
|
||||
AC_MSG_RESULT(no)
|
||||
|
||||
AC_MSG_CHECKING(for b64_ntop with -lresolv)
|
||||
LIBS="$LIBS -lresolv"
|
||||
AC_TRY_LINK(
|
||||
[
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <resolv.h>
|
||||
],
|
||||
[b64_ntop(NULL, 0, NULL, 0);],
|
||||
found_b64_ntop=yes,
|
||||
found_b64_ntop=no
|
||||
)
|
||||
if test "x$found_b64_ntop" = xno; then
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
fi
|
||||
if test "x$found_b64_ntop" = xyes; then
|
||||
AC_DEFINE(HAVE_B64_NTOP)
|
||||
AC_MSG_RESULT(yes)
|
||||
fi
|
||||
AM_CONDITIONAL(NO_B64_NTOP, [test "x$found_b64_ntop" = xno])
|
||||
|
||||
# Look for networking libraries.
|
||||
AC_SEARCH_LIBS(b64_ntop, resolv)
|
||||
AC_SEARCH_LIBS(__b64_ntop, resolv)
|
||||
AC_SEARCH_LIBS(inet_ntoa, nsl)
|
||||
AC_SEARCH_LIBS(socket, socket)
|
||||
AC_CHECK_LIB(xnet, socket)
|
||||
|
||||
# Look for sqrt.
|
||||
AC_SEARCH_LIBS(sqrt, m)
|
||||
|
||||
# Check for CMSG_DATA. Some platforms require _XOPEN_SOURCE_EXTENDED (for
|
||||
# example see xopen_networking(7) on HP-UX).
|
||||
XOPEN_DEFINES=
|
||||
@@ -291,6 +339,7 @@ AM_CONDITIONAL(NO_GETOPT, [test "x$found_getopt" = xno])
|
||||
AC_CHECK_FUNCS(
|
||||
[ \
|
||||
bzero \
|
||||
dirfd \
|
||||
setproctitle \
|
||||
sysconf \
|
||||
]
|
||||
@@ -298,7 +347,7 @@ AC_CHECK_FUNCS(
|
||||
|
||||
# Check for BSD-style integer types.
|
||||
AC_MSG_CHECKING(for BSD-style unsigned types)
|
||||
AC_COMPILE_IFELSE(
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE(
|
||||
[
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_STDINT_H
|
||||
@@ -308,7 +357,7 @@ AC_COMPILE_IFELSE(
|
||||
#endif
|
||||
int main(void)
|
||||
{ u_int8_t u8; u_int16_t u16; u_int32_t u32; u_int64_t u64; }
|
||||
],
|
||||
])],
|
||||
[AC_DEFINE(HAVE_BSD_TYPES) AC_MSG_RESULT(yes)],
|
||||
AC_MSG_RESULT(no)
|
||||
)
|
||||
@@ -332,7 +381,7 @@ fi
|
||||
|
||||
# Look for __progname.
|
||||
AC_MSG_CHECKING(for __progname)
|
||||
AC_LINK_IFELSE(
|
||||
AC_LINK_IFELSE([AC_LANG_SOURCE(
|
||||
[
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -342,7 +391,7 @@ AC_LINK_IFELSE(
|
||||
printf("%s\n", cp);
|
||||
exit(0);
|
||||
}
|
||||
],
|
||||
])],
|
||||
[AC_DEFINE(HAVE___PROGNAME) AC_MSG_RESULT(yes)],
|
||||
AC_MSG_RESULT(no)
|
||||
)
|
||||
@@ -364,15 +413,6 @@ else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
# Look for /proc/$$/fd.
|
||||
AC_MSG_CHECKING(for /proc/\$\$/fd)
|
||||
if test -d /proc/$$/fd; then
|
||||
AC_DEFINE(HAVE_DIRFD)
|
||||
AC_MSG_RESULT(yes)
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
# Figure out the platform for osdep-*.c and forkpty-*.c.
|
||||
AC_MSG_CHECKING(platform)
|
||||
case "$host_os" in
|
||||
@@ -385,11 +425,15 @@ case "$host_os" in
|
||||
AC_DEFINE(BROKEN_CMSG_FIRSTHDR)
|
||||
PLATFORM=darwin
|
||||
;;
|
||||
*dragonfly*)
|
||||
AC_MSG_RESULT(dragonfly)
|
||||
PLATFORM=dragonfly
|
||||
;;
|
||||
*linux*)
|
||||
AC_MSG_RESULT(linux)
|
||||
PLATFORM=linux
|
||||
;;
|
||||
*freebsd*|*dragonfly*)
|
||||
*freebsd*)
|
||||
AC_MSG_RESULT(freebsd)
|
||||
PLATFORM=freebsd
|
||||
;;
|
||||
@@ -421,6 +465,7 @@ esac
|
||||
AC_SUBST(PLATFORM)
|
||||
AM_CONDITIONAL(IS_AIX, test "x$PLATFORM" = xaix)
|
||||
AM_CONDITIONAL(IS_DARWIN, test "x$PLATFORM" = xdarwin)
|
||||
AM_CONDITIONAL(IS_DRAGONFLY, test "x$PLATFORM" = xdragonfly)
|
||||
AM_CONDITIONAL(IS_LINUX, test "x$PLATFORM" = xlinux)
|
||||
AM_CONDITIONAL(IS_FREEBSD, test "x$PLATFORM" = xfreebsd)
|
||||
AM_CONDITIONAL(IS_NETBSD, test "x$PLATFORM" = xnetbsd)
|
||||
|
||||
@@ -26,7 +26,7 @@ bind x lock-server
|
||||
# screen ^C c
|
||||
unbind ^C
|
||||
bind ^C new-window
|
||||
bind c
|
||||
unbind c
|
||||
bind c new-window
|
||||
|
||||
# detach ^D d
|
||||
|
||||
@@ -47,11 +47,11 @@ syn keyword tmuxCmds capture-pane joinp join-pane choose-buffer
|
||||
syn keyword tmuxOptsSet prefix status status-fg status-bg bell-action
|
||||
syn keyword tmuxOptsSet default-command history-limit status-left status-right
|
||||
syn keyword tmuxOptsSet status-interval set-titles display-time buffer-limit
|
||||
syn keyword tmuxOptsSet status-left-length status-right-length message-fg
|
||||
syn keyword tmuxOptsSet message-bg lock-after-time default-path repeat-time
|
||||
syn keyword tmuxOptsSet message-attr status-attr status-keys set-remain-on-exit
|
||||
syn keyword tmuxOptsSet status-utf8 default-terminal visual-activity
|
||||
syn keyword tmuxOptsSet visual-bell visual-content status-justify
|
||||
syn keyword tmuxOptsSet status-left-length status-right-length
|
||||
syn keyword tmuxOptsSet message-[command-]bg lock-after-time default-path
|
||||
syn keyword tmuxOptsSet message-[command-]attr status-attr set-remain-on-exit
|
||||
syn keyword tmuxOptsSet status-utf8 default-terminal visual-activity repeat-time
|
||||
syn keyword tmuxOptsSet visual-bell visual-content status-justify status-keys
|
||||
syn keyword tmuxOptsSet terminal-overrides status-left-attr status-left-bg
|
||||
syn keyword tmuxOptsSet status-left-fg status-right-attr status-right-bg
|
||||
syn keyword tmuxOptsSet status-right-fg update-environment base-index
|
||||
@@ -59,9 +59,11 @@ syn keyword tmuxOptsSet display-panes-colour display-panes-time default-shell
|
||||
syn keyword tmuxOptsSet set-titles-string lock-command lock-server
|
||||
syn keyword tmuxOptsSet mouse-select-pane message-limit quiet escape-time
|
||||
syn keyword tmuxOptsSet pane-active-border-bg pane-active-border-fg
|
||||
syn keyword tmuxOptsSet pane-border-bg pane-border-fg
|
||||
syn keyword tmuxOptsSet pane-border-bg pane-border-fg message-[command-]fg
|
||||
syn keyword tmuxOptsSet display-panes-active-colour alternate-screen
|
||||
syn keyword tmuxOptsSet detach-on-destroy
|
||||
syn keyword tmuxOptsSet detach-on-destroy word-separators
|
||||
syn keyword tmuxOptsSet destroy-unattached exit-unattached set-clipboard
|
||||
syn keyword tmuxOptsSet bell-on-alert mouse-select-window mouse-utf8
|
||||
|
||||
syn keyword tmuxOptsSetw monitor-activity aggressive-resize force-width
|
||||
syn keyword tmuxOptsSetw force-height remain-on-exit uft8 mode-fg mode-bg
|
||||
@@ -72,12 +74,13 @@ syn keyword tmuxOptsSetw main-pane-width main-pane-height monitor-content
|
||||
syn keyword tmuxOptsSetw window-status-current-attr window-status-current-bg
|
||||
syn keyword tmuxOptsSetw window-status-current-fg mode-mouse synchronize-panes
|
||||
syn keyword tmuxOptsSetw window-status-format window-status-current-format
|
||||
syn keyword tmuxOptsSetw word-separators window-status-alert-alert
|
||||
syn keyword tmuxOptsSetw window-status-alert-attr
|
||||
syn keyword tmuxOptsSetw window-status-alert-bg window-status-alert-fg
|
||||
syn keyword tmuxOptsSetw pane-base-index other-pane-height other-pane-width
|
||||
|
||||
syn keyword tmuxTodo FIXME NOTE TODO XXX contained
|
||||
|
||||
syn match tmuxKey /\(C-\|M-\|\^\)\p/ display
|
||||
syn match tmuxKey /\(C-\|M-\|\^\)\+\S\+/ display
|
||||
syn match tmuxNumber /\d\+/ display
|
||||
syn match tmuxOptions /\s-\a\+/ display
|
||||
syn match tmuxVariable /\w\+=/ display
|
||||
|
||||
393
format.c
Normal file
393
format.c
Normal file
@@ -0,0 +1,393 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2011 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
*
|
||||
* 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 <netdb.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
/*
|
||||
* Build a list of key-value pairs and use them to expand #{key} entries in a
|
||||
* string.
|
||||
*/
|
||||
|
||||
int format_replace(struct format_tree *,
|
||||
const char *, size_t, char **, size_t *, size_t *);
|
||||
|
||||
/* Format key-value replacement entry. */
|
||||
RB_GENERATE(format_tree, format_entry, entry, format_cmp);
|
||||
|
||||
/* Format tree comparison function. */
|
||||
int
|
||||
format_cmp(struct format_entry *fe1, struct format_entry *fe2)
|
||||
{
|
||||
return (strcmp(fe1->key, fe2->key));
|
||||
}
|
||||
|
||||
/* Single-character aliases. */
|
||||
const char *format_aliases[26] = {
|
||||
NULL, /* A */
|
||||
NULL, /* B */
|
||||
NULL, /* C */
|
||||
"pane_id", /* D */
|
||||
NULL, /* E */
|
||||
"window_flags", /* F */
|
||||
NULL, /* G */
|
||||
"host", /* H */
|
||||
"window_index", /* I */
|
||||
NULL, /* J */
|
||||
NULL, /* K */
|
||||
NULL, /* L */
|
||||
NULL, /* M */
|
||||
NULL, /* N */
|
||||
NULL, /* O */
|
||||
"pane_index", /* P */
|
||||
NULL, /* Q */
|
||||
NULL, /* R */
|
||||
"session_name", /* S */
|
||||
"pane_title", /* T */
|
||||
NULL, /* U */
|
||||
NULL, /* V */
|
||||
"window_name", /* W */
|
||||
NULL, /* X */
|
||||
NULL, /* Y */
|
||||
NULL /* Z */
|
||||
};
|
||||
|
||||
/* Create a new tree. */
|
||||
struct format_tree *
|
||||
format_create(void)
|
||||
{
|
||||
struct format_tree *ft;
|
||||
char host[MAXHOSTNAMELEN];
|
||||
|
||||
ft = xmalloc(sizeof *ft);
|
||||
RB_INIT(ft);
|
||||
|
||||
if (gethostname(host, sizeof host) == 0)
|
||||
format_add(ft, "host", "%s", host);
|
||||
|
||||
return (ft);
|
||||
}
|
||||
|
||||
/* Free a tree. */
|
||||
void
|
||||
format_free(struct format_tree *ft)
|
||||
{
|
||||
struct format_entry *fe, *fe_next;
|
||||
|
||||
fe_next = RB_MIN(format_tree, ft);
|
||||
while (fe_next != NULL) {
|
||||
fe = fe_next;
|
||||
fe_next = RB_NEXT(format_tree, ft, fe);
|
||||
|
||||
RB_REMOVE(format_tree, ft, fe);
|
||||
xfree(fe->value);
|
||||
xfree(fe->key);
|
||||
xfree(fe);
|
||||
}
|
||||
|
||||
xfree (ft);
|
||||
}
|
||||
|
||||
/* Add a key-value pair. */
|
||||
void
|
||||
format_add(struct format_tree *ft, const char *key, const char *fmt, ...)
|
||||
{
|
||||
struct format_entry *fe;
|
||||
va_list ap;
|
||||
|
||||
fe = xmalloc(sizeof *fe);
|
||||
fe->key = xstrdup(key);
|
||||
|
||||
va_start(ap, fmt);
|
||||
xvasprintf(&fe->value, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
RB_INSERT(format_tree, ft, fe);
|
||||
}
|
||||
|
||||
/* Find a format entry. */
|
||||
const char *
|
||||
format_find(struct format_tree *ft, const char *key)
|
||||
{
|
||||
struct format_entry *fe, fe_find;
|
||||
|
||||
fe_find.key = (char *) key;
|
||||
fe = RB_FIND(format_tree, ft, &fe_find);
|
||||
if (fe == NULL)
|
||||
return (NULL);
|
||||
return (fe->value);
|
||||
}
|
||||
|
||||
/*
|
||||
* Replace a key/value pair in buffer. #{blah} is expanded directly,
|
||||
* #{?blah,a,b} is replace with a if blah exists and is nonzero else b.
|
||||
*/
|
||||
int
|
||||
format_replace(struct format_tree *ft,
|
||||
const char *key, size_t keylen, char **buf, size_t *len, size_t *off)
|
||||
{
|
||||
char *copy, *ptr;
|
||||
const char *value;
|
||||
size_t valuelen;
|
||||
|
||||
/* Make a copy of the key. */
|
||||
copy = xmalloc(keylen + 1);
|
||||
memcpy(copy, key, keylen);
|
||||
copy[keylen] = '\0';
|
||||
|
||||
/*
|
||||
* Is this a conditional? If so, check it exists and extract either the
|
||||
* first or second element. If not, look up the key directly.
|
||||
*/
|
||||
if (*copy == '?') {
|
||||
ptr = strchr(copy, ',');
|
||||
if (ptr == NULL)
|
||||
goto fail;
|
||||
*ptr = '\0';
|
||||
|
||||
value = format_find(ft, copy + 1);
|
||||
if (value != NULL && (value[0] != '0' || value[1] != '\0')) {
|
||||
value = ptr + 1;
|
||||
ptr = strchr(value, ',');
|
||||
if (ptr == NULL)
|
||||
goto fail;
|
||||
*ptr = '\0';
|
||||
} else {
|
||||
ptr = strchr(ptr + 1, ',');
|
||||
if (ptr == NULL)
|
||||
goto fail;
|
||||
value = ptr + 1;
|
||||
}
|
||||
} else {
|
||||
value = format_find(ft, copy);
|
||||
if (value == NULL)
|
||||
value = "";
|
||||
}
|
||||
valuelen = strlen(value);
|
||||
|
||||
/* Expand the buffer and copy in the value. */
|
||||
while (*len - *off < valuelen + 1) {
|
||||
*buf = xrealloc(*buf, 2, *len);
|
||||
*len *= 2;
|
||||
}
|
||||
memcpy(*buf + *off, value, valuelen);
|
||||
*off += valuelen;
|
||||
|
||||
xfree(copy);
|
||||
return (0);
|
||||
|
||||
fail:
|
||||
xfree(copy);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Expand keys in a template. */
|
||||
char *
|
||||
format_expand(struct format_tree *ft, const char *fmt)
|
||||
{
|
||||
char *buf, *ptr;
|
||||
const char *s;
|
||||
size_t off, len, n;
|
||||
int ch;
|
||||
|
||||
len = 64;
|
||||
buf = xmalloc(len);
|
||||
off = 0;
|
||||
|
||||
while (*fmt != '\0') {
|
||||
if (*fmt != '#') {
|
||||
while (len - off < 2) {
|
||||
buf = xrealloc(buf, 2, len);
|
||||
len *= 2;
|
||||
}
|
||||
buf[off++] = *fmt++;
|
||||
continue;
|
||||
}
|
||||
fmt++;
|
||||
|
||||
ch = (u_char) *fmt++;
|
||||
switch (ch) {
|
||||
case '{':
|
||||
ptr = strchr(fmt, '}');
|
||||
if (ptr == NULL)
|
||||
break;
|
||||
n = ptr - fmt;
|
||||
|
||||
if (format_replace(ft, fmt, n, &buf, &len, &off) != 0)
|
||||
break;
|
||||
fmt += n + 1;
|
||||
continue;
|
||||
default:
|
||||
if (ch >= 'A' && ch <= 'Z') {
|
||||
s = format_aliases[ch - 'A'];
|
||||
if (s != NULL) {
|
||||
n = strlen(s);
|
||||
if (format_replace (
|
||||
ft, s, n, &buf, &len, &off) != 0)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
while (len - off < 2) {
|
||||
buf = xrealloc(buf, 2, len);
|
||||
len *= 2;
|
||||
}
|
||||
buf[off++] = ch;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
buf[off] = '\0';
|
||||
|
||||
return (buf);
|
||||
}
|
||||
|
||||
/* Set default format keys for a session. */
|
||||
void
|
||||
format_session(struct format_tree *ft, struct session *s)
|
||||
{
|
||||
struct session_group *sg;
|
||||
char *tim;
|
||||
time_t t;
|
||||
|
||||
format_add(ft, "session_name", "%s", s->name);
|
||||
format_add(ft, "session_windows", "%u", winlink_count(&s->windows));
|
||||
format_add(ft, "session_width", "%u", s->sx);
|
||||
format_add(ft, "session_height", "%u", s->sy);
|
||||
|
||||
sg = session_group_find(s);
|
||||
format_add(ft, "session_grouped", "%d", sg != NULL);
|
||||
if (sg != NULL)
|
||||
format_add(ft, "session_group", "%u", session_group_index(sg));
|
||||
|
||||
t = s->creation_time.tv_sec;
|
||||
format_add(ft, "session_created", "%ld", (long) t);
|
||||
tim = ctime(&t);
|
||||
*strchr(tim, '\n') = '\0';
|
||||
format_add(ft, "session_created_string", "%s", tim);
|
||||
|
||||
if (s->flags & SESSION_UNATTACHED)
|
||||
format_add(ft, "session_attached", "%d", 0);
|
||||
else
|
||||
format_add(ft, "session_attached", "%d", 1);
|
||||
}
|
||||
|
||||
/* Set default format keys for a client. */
|
||||
void
|
||||
format_client(struct format_tree *ft, struct client *c)
|
||||
{
|
||||
char *tim;
|
||||
time_t t;
|
||||
|
||||
format_add(ft, "client_cwd", "%s", c->cwd);
|
||||
format_add(ft, "client_height", "%u", c->tty.sx);
|
||||
format_add(ft, "client_width", "%u", c->tty.sy);
|
||||
format_add(ft, "client_tty", "%s", c->tty.path);
|
||||
format_add(ft, "client_termname", "%s", c->tty.termname);
|
||||
|
||||
t = c->creation_time.tv_sec;
|
||||
format_add(ft, "client_created", "%ld", (long) t);
|
||||
tim = ctime(&t);
|
||||
*strchr(tim, '\n') = '\0';
|
||||
format_add(ft, "client_created_string", "%s", tim);
|
||||
|
||||
t = c->activity_time.tv_sec;
|
||||
format_add(ft, "client_activity", "%ld", (long) t);
|
||||
tim = ctime(&t);
|
||||
*strchr(tim, '\n') = '\0';
|
||||
format_add(ft, "client_activity_string", "%s", tim);
|
||||
|
||||
if (c->tty.flags & TTY_UTF8)
|
||||
format_add(ft, "client_utf8", "%d", 1);
|
||||
else
|
||||
format_add(ft, "client_utf8", "%d", 0);
|
||||
|
||||
if (c->flags & CLIENT_READONLY)
|
||||
format_add(ft, "client_readonly", "%d", 1);
|
||||
else
|
||||
format_add(ft, "client_readonly", "%d", 0);
|
||||
}
|
||||
|
||||
/* Set default format keys for a winlink. */
|
||||
void
|
||||
format_winlink(struct format_tree *ft, struct session *s, struct winlink *wl)
|
||||
{
|
||||
struct window *w = wl->window;
|
||||
char *layout, *flags;
|
||||
|
||||
layout = layout_dump(w);
|
||||
flags = window_printable_flags(s, wl);
|
||||
|
||||
format_add(ft, "window_index", "%d", wl->idx);
|
||||
format_add(ft, "window_name", "%s", w->name);
|
||||
format_add(ft, "window_width", "%u", w->sx);
|
||||
format_add(ft, "window_height", "%u", w->sy);
|
||||
format_add(ft, "window_flags", "%s", flags);
|
||||
format_add(ft, "window_layout", "%s", layout);
|
||||
format_add(ft, "window_active", "%d", wl == s->curw);
|
||||
|
||||
xfree(flags);
|
||||
xfree(layout);
|
||||
}
|
||||
|
||||
/* Set default format keys for a window pane. */
|
||||
void
|
||||
format_window_pane(struct format_tree *ft, struct window_pane *wp)
|
||||
{
|
||||
struct grid *gd = wp->base.grid;
|
||||
struct grid_line *gl;
|
||||
unsigned long long size;
|
||||
u_int i;
|
||||
u_int idx;
|
||||
|
||||
size = 0;
|
||||
for (i = 0; i < gd->hsize; i++) {
|
||||
gl = &gd->linedata[i];
|
||||
size += gl->cellsize * sizeof *gl->celldata;
|
||||
size += gl->utf8size * sizeof *gl->utf8data;
|
||||
}
|
||||
size += gd->hsize * sizeof *gd->linedata;
|
||||
|
||||
if (window_pane_index(wp, &idx) != 0)
|
||||
fatalx("index not found");
|
||||
|
||||
format_add(ft, "pane_width", "%u", wp->sx);
|
||||
format_add(ft, "pane_height", "%u", wp->sy);
|
||||
format_add(ft, "pane_title", "%s", wp->base.title);
|
||||
format_add(ft, "pane_index", "%u", idx);
|
||||
format_add(ft, "history_size", "%u", gd->hsize);
|
||||
format_add(ft, "history_limit", "%u", gd->hlimit);
|
||||
format_add(ft, "history_bytes", "%llu", size);
|
||||
format_add(ft, "pane_id", "%%%u", wp->id);
|
||||
format_add(ft, "pane_active", "%d", wp == wp->window->active);
|
||||
format_add(ft, "pane_dead", "%d", wp->fd == -1);
|
||||
if (wp->cmd != NULL)
|
||||
format_add(ft, "pane_start_command", "%s", wp->cmd);
|
||||
if (wp->cwd != NULL)
|
||||
format_add(ft, "pane_start_path", "%s", wp->cwd);
|
||||
format_add(ft, "pane_pid", "%ld", (long) wp->pid);
|
||||
format_add(ft, "pane_tty", "%s", wp->tty);
|
||||
}
|
||||
@@ -203,6 +203,7 @@ input_mouse(struct window_pane *wp, struct mouse_event *m)
|
||||
{
|
||||
char buf[10];
|
||||
size_t len;
|
||||
int value;
|
||||
|
||||
if (wp->screen->mode & ALL_MOUSE_MODES) {
|
||||
if (wp->screen->mode & MODE_MOUSE_UTF8) {
|
||||
@@ -220,7 +221,8 @@ input_mouse(struct window_pane *wp, struct mouse_event *m)
|
||||
}
|
||||
bufferevent_write(wp->event, buf, len);
|
||||
} else if ((m->b & MOUSE_BUTTON) != MOUSE_2) {
|
||||
if (options_get_number(&wp->window->options, "mode-mouse") &&
|
||||
value = options_get_number(&wp->window->options, "mode-mouse");
|
||||
if (value == 1 &&
|
||||
window_pane_set_mode(wp, &window_copy_mode) == 0) {
|
||||
window_copy_init_from_pane(wp);
|
||||
if (wp->mode->mouse != NULL)
|
||||
|
||||
52
input.c
52
input.c
@@ -119,6 +119,8 @@ const struct input_table_entry input_esc_table[] = {
|
||||
/* Control (CSI) commands. */
|
||||
enum input_csi_type {
|
||||
INPUT_CSI_CBT,
|
||||
INPUT_CSI_CNL,
|
||||
INPUT_CSI_CPL,
|
||||
INPUT_CSI_CUB,
|
||||
INPUT_CSI_CUD,
|
||||
INPUT_CSI_CUF,
|
||||
@@ -135,8 +137,10 @@ enum input_csi_type {
|
||||
INPUT_CSI_HPA,
|
||||
INPUT_CSI_ICH,
|
||||
INPUT_CSI_IL,
|
||||
INPUT_CSI_RCP,
|
||||
INPUT_CSI_RM,
|
||||
INPUT_CSI_RM_PRIVATE,
|
||||
INPUT_CSI_SCP,
|
||||
INPUT_CSI_SGR,
|
||||
INPUT_CSI_SM,
|
||||
INPUT_CSI_SM_PRIVATE,
|
||||
@@ -151,6 +155,8 @@ const struct input_table_entry input_csi_table[] = {
|
||||
{ 'B', "", INPUT_CSI_CUD },
|
||||
{ 'C', "", INPUT_CSI_CUF },
|
||||
{ 'D', "", INPUT_CSI_CUB },
|
||||
{ 'E', "", INPUT_CSI_CNL },
|
||||
{ 'F', "", INPUT_CSI_CPL },
|
||||
{ 'G', "", INPUT_CSI_HPA },
|
||||
{ 'H', "", INPUT_CSI_CUP },
|
||||
{ 'J', "", INPUT_CSI_ED },
|
||||
@@ -171,6 +177,8 @@ const struct input_table_entry input_csi_table[] = {
|
||||
{ 'n', "", INPUT_CSI_DSR },
|
||||
{ 'q', " ", INPUT_CSI_DECSCUSR },
|
||||
{ 'r', "", INPUT_CSI_DECSTBM },
|
||||
{ 's', "", INPUT_CSI_SCP },
|
||||
{ 'u', "", INPUT_CSI_RCP },
|
||||
};
|
||||
|
||||
/* Input transition. */
|
||||
@@ -970,17 +978,7 @@ input_esc_dispatch(struct input_ctx *ictx)
|
||||
ictx->old_cx = 0;
|
||||
ictx->old_cy = 0;
|
||||
|
||||
screen_reset_tabs(sctx->s);
|
||||
|
||||
screen_write_scrollregion(sctx, 0, screen_size_y(sctx->s) - 1);
|
||||
|
||||
screen_write_insertmode(sctx, 0);
|
||||
screen_write_kcursormode(sctx, 0);
|
||||
screen_write_kkeypadmode(sctx, 0);
|
||||
screen_write_mousemode_off(sctx);
|
||||
|
||||
screen_write_clearscreen(sctx);
|
||||
screen_write_cursormove(sctx, 0, 0);
|
||||
screen_write_reset(sctx);
|
||||
break;
|
||||
case INPUT_ESC_IND:
|
||||
screen_write_linefeed(sctx, 0);
|
||||
@@ -1081,6 +1079,14 @@ input_csi_dispatch(struct input_ctx *ictx)
|
||||
case INPUT_CSI_CUU:
|
||||
screen_write_cursorup(sctx, input_get(ictx, 0, 1, 1));
|
||||
break;
|
||||
case INPUT_CSI_CNL:
|
||||
screen_write_carriagereturn(sctx);
|
||||
screen_write_cursordown(sctx, input_get(ictx, 0, 1, 1));
|
||||
break;
|
||||
case INPUT_CSI_CPL:
|
||||
screen_write_carriagereturn(sctx);
|
||||
screen_write_cursorup(sctx, input_get(ictx, 0, 1, 1));
|
||||
break;
|
||||
case INPUT_CSI_DA:
|
||||
switch (input_get(ictx, 0, 0, 0)) {
|
||||
case 0:
|
||||
@@ -1126,6 +1132,17 @@ input_csi_dispatch(struct input_ctx *ictx)
|
||||
case 2:
|
||||
screen_write_clearscreen(sctx);
|
||||
break;
|
||||
case 3:
|
||||
switch (input_get(ictx, 1, 0, 0)) {
|
||||
case 0:
|
||||
/*
|
||||
* Linux console extension to clear history
|
||||
* (for example before locking the screen).
|
||||
*/
|
||||
screen_write_clearhistory(sctx);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
||||
break;
|
||||
@@ -1157,6 +1174,10 @@ input_csi_dispatch(struct input_ctx *ictx)
|
||||
case INPUT_CSI_IL:
|
||||
screen_write_insertline(sctx, input_get(ictx, 0, 1, 1));
|
||||
break;
|
||||
case INPUT_CSI_RCP:
|
||||
memcpy(&ictx->cell, &ictx->old_cell, sizeof ictx->cell);
|
||||
screen_write_cursormove(sctx, ictx->old_cx, ictx->old_cy);
|
||||
break;
|
||||
case INPUT_CSI_RM:
|
||||
switch (input_get(ictx, 0, 0, -1)) {
|
||||
case 4: /* IRM */
|
||||
@@ -1196,6 +1217,11 @@ input_csi_dispatch(struct input_ctx *ictx)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case INPUT_CSI_SCP:
|
||||
memcpy(&ictx->old_cell, &ictx->cell, sizeof ictx->old_cell);
|
||||
ictx->old_cx = s->cx;
|
||||
ictx->old_cy = s->cy;
|
||||
break;
|
||||
case INPUT_CSI_SGR:
|
||||
input_csi_dispatch_sgr(ictx);
|
||||
break;
|
||||
@@ -1410,7 +1436,7 @@ input_csi_dispatch_sgr(struct input_ctx *ictx)
|
||||
case 106:
|
||||
case 107:
|
||||
gc->flags &= ~GRID_FLAG_BG256;
|
||||
gc->bg = n;
|
||||
gc->bg = n - 10;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1522,6 +1548,8 @@ input_exit_rename(struct input_ctx *ictx)
|
||||
{
|
||||
if (ictx->flags & INPUT_DISCARD)
|
||||
return;
|
||||
if (!options_get_number(&ictx->wp->window->options, "allow-rename"))
|
||||
return;
|
||||
log_debug("%s: \"%s\"", __func__, ictx->input_buf);
|
||||
|
||||
xfree(ictx->wp->window->name);
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
SPLAY_GENERATE(key_bindings, key_binding, entry, key_bindings_cmp);
|
||||
RB_GENERATE(key_bindings, key_binding, entry, key_bindings_cmp);
|
||||
|
||||
struct key_bindings key_bindings;
|
||||
struct key_bindings dead_key_bindings;
|
||||
@@ -52,7 +52,7 @@ key_bindings_lookup(int key)
|
||||
struct key_binding bd;
|
||||
|
||||
bd.key = key;
|
||||
return (SPLAY_FIND(key_bindings, &key_bindings, &bd));
|
||||
return (RB_FIND(key_bindings, &key_bindings, &bd));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -64,7 +64,7 @@ key_bindings_add(int key, int can_repeat, struct cmd_list *cmdlist)
|
||||
|
||||
bd = xmalloc(sizeof *bd);
|
||||
bd->key = key;
|
||||
SPLAY_INSERT(key_bindings, &key_bindings, bd);
|
||||
RB_INSERT(key_bindings, &key_bindings, bd);
|
||||
|
||||
bd->can_repeat = can_repeat;
|
||||
bd->cmdlist = cmdlist;
|
||||
@@ -77,8 +77,8 @@ key_bindings_remove(int key)
|
||||
|
||||
if ((bd = key_bindings_lookup(key)) == NULL)
|
||||
return;
|
||||
SPLAY_REMOVE(key_bindings, &key_bindings, bd);
|
||||
SPLAY_INSERT(key_bindings, &dead_key_bindings, bd);
|
||||
RB_REMOVE(key_bindings, &key_bindings, bd);
|
||||
RB_INSERT(key_bindings, &dead_key_bindings, bd);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -86,9 +86,9 @@ key_bindings_clean(void)
|
||||
{
|
||||
struct key_binding *bd;
|
||||
|
||||
while (!SPLAY_EMPTY(&dead_key_bindings)) {
|
||||
bd = SPLAY_ROOT(&dead_key_bindings);
|
||||
SPLAY_REMOVE(key_bindings, &dead_key_bindings, bd);
|
||||
while (!RB_EMPTY(&dead_key_bindings)) {
|
||||
bd = RB_ROOT(&dead_key_bindings);
|
||||
RB_REMOVE(key_bindings, &dead_key_bindings, bd);
|
||||
cmd_list_free(bd->cmdlist);
|
||||
xfree(bd);
|
||||
}
|
||||
@@ -179,7 +179,7 @@ key_bindings_init(void)
|
||||
struct cmd *cmd;
|
||||
struct cmd_list *cmdlist;
|
||||
|
||||
SPLAY_INIT(&key_bindings);
|
||||
RB_INIT(&key_bindings);
|
||||
|
||||
for (i = 0; i < nitems(table); i++) {
|
||||
cmdlist = xmalloc(sizeof *cmdlist);
|
||||
|
||||
@@ -55,7 +55,11 @@ const struct {
|
||||
{ "Home", KEYC_HOME },
|
||||
{ "End", KEYC_END },
|
||||
{ "NPage", KEYC_NPAGE },
|
||||
{ "PageDown", KEYC_NPAGE },
|
||||
{ "PgDn", KEYC_NPAGE },
|
||||
{ "PPage", KEYC_PPAGE },
|
||||
{ "PageUp", KEYC_PPAGE },
|
||||
{ "PgUp", KEYC_PPAGE },
|
||||
{ "Tab", '\011' },
|
||||
{ "BTab", KEYC_BTAB },
|
||||
{ "Space", ' ' },
|
||||
@@ -184,6 +188,10 @@ key_string_lookup_key(int key)
|
||||
|
||||
*out = '\0';
|
||||
|
||||
/* Handle no key. */
|
||||
if (key == KEYC_NONE)
|
||||
return ("none");
|
||||
|
||||
/*
|
||||
* Special case: display C-@ as C-Space. Could do this below in
|
||||
* the (key >= 0 && key <= 32), but this way we let it be found
|
||||
|
||||
@@ -260,8 +260,8 @@ layout_set_main_h(struct window *w)
|
||||
* If an other pane height was specified, honour it so long as it
|
||||
* doesn't shrink the main height to less than the main-pane-height
|
||||
*/
|
||||
if (otherheight > 1 && w->sx - otherheight > mainheight)
|
||||
mainheight = w->sx - otherheight;
|
||||
if (otherheight > 1 && w->sy - otherheight > mainheight)
|
||||
mainheight = w->sy - otherheight;
|
||||
if (mainheight < PANE_MINIMUM + 1)
|
||||
mainheight = PANE_MINIMUM + 1;
|
||||
|
||||
|
||||
53
mode-key.c
53
mode-key.c
@@ -49,11 +49,18 @@ const struct mode_key_cmdstr mode_key_cmdstr_edit[] = {
|
||||
{ MODEKEYEDIT_DELETE, "delete" },
|
||||
{ MODEKEYEDIT_DELETELINE, "delete-line" },
|
||||
{ MODEKEYEDIT_DELETETOENDOFLINE, "delete-end-of-line" },
|
||||
{ MODEKEYEDIT_DELETEWORD, "delete-word" },
|
||||
{ MODEKEYEDIT_ENDOFLINE, "end-of-line" },
|
||||
{ MODEKEYEDIT_ENTER, "enter" },
|
||||
{ MODEKEYEDIT_HISTORYDOWN, "history-down" },
|
||||
{ MODEKEYEDIT_HISTORYUP, "history-up" },
|
||||
{ MODEKEYEDIT_NEXTSPACE, "next-space" },
|
||||
{ MODEKEYEDIT_NEXTSPACEEND, "next-space-end" },
|
||||
{ MODEKEYEDIT_NEXTWORD, "next-word" },
|
||||
{ MODEKEYEDIT_NEXTWORDEND, "next-word-end" },
|
||||
{ MODEKEYEDIT_PASTE, "paste" },
|
||||
{ MODEKEYEDIT_PREVIOUSSPACE, "previous-space" },
|
||||
{ MODEKEYEDIT_PREVIOUSWORD, "previous-word" },
|
||||
{ MODEKEYEDIT_STARTOFLINE, "start-of-line" },
|
||||
{ MODEKEYEDIT_SWITCHMODE, "switch-mode" },
|
||||
{ MODEKEYEDIT_SWITCHMODEAPPEND, "switch-mode-append" },
|
||||
@@ -94,6 +101,8 @@ const struct mode_key_cmdstr mode_key_cmdstr_copy[] = {
|
||||
{ MODEKEYCOPY_JUMPAGAIN, "jump-again" },
|
||||
{ MODEKEYCOPY_JUMPREVERSE, "jump-reverse" },
|
||||
{ MODEKEYCOPY_JUMPBACK, "jump-backward" },
|
||||
{ MODEKEYCOPY_JUMPTO, "jump-to-forward" },
|
||||
{ MODEKEYCOPY_JUMPTOBACK, "jump-to-backward" },
|
||||
{ MODEKEYCOPY_LEFT, "cursor-left" },
|
||||
{ MODEKEYCOPY_RECTANGLETOGGLE, "rectangle-toggle" },
|
||||
{ MODEKEYCOPY_MIDDLELINE, "middle-line" },
|
||||
@@ -126,28 +135,43 @@ const struct mode_key_cmdstr mode_key_cmdstr_copy[] = {
|
||||
const struct mode_key_entry mode_key_vi_edit[] = {
|
||||
{ '\003' /* C-c */, 0, MODEKEYEDIT_CANCEL },
|
||||
{ '\010' /* C-h */, 0, MODEKEYEDIT_BACKSPACE },
|
||||
{ '\025' /* C-u */, 0, MODEKEYEDIT_DELETELINE },
|
||||
{ '\011' /* Tab */, 0, MODEKEYEDIT_COMPLETE },
|
||||
{ '\025' /* C-u */, 0, MODEKEYEDIT_DELETELINE },
|
||||
{ '\027' /* C-w */, 0, MODEKEYEDIT_DELETEWORD },
|
||||
{ '\033' /* Escape */, 0, MODEKEYEDIT_SWITCHMODE },
|
||||
{ '\r', 0, MODEKEYEDIT_ENTER },
|
||||
{ KEYC_BSPACE, 0, MODEKEYEDIT_BACKSPACE },
|
||||
{ KEYC_DC, 0, MODEKEYEDIT_DELETE },
|
||||
{ KEYC_DOWN, 0, MODEKEYEDIT_HISTORYDOWN },
|
||||
{ KEYC_LEFT, 0, MODEKEYEDIT_CURSORLEFT },
|
||||
{ KEYC_RIGHT, 0, MODEKEYEDIT_CURSORRIGHT },
|
||||
{ KEYC_UP, 0, MODEKEYEDIT_HISTORYUP },
|
||||
{ KEYC_HOME, 0, MODEKEYEDIT_STARTOFLINE },
|
||||
{ KEYC_END, 0, MODEKEYEDIT_ENDOFLINE },
|
||||
|
||||
{ '$', 1, MODEKEYEDIT_ENDOFLINE },
|
||||
{ '0', 1, MODEKEYEDIT_STARTOFLINE },
|
||||
{ 'B', 1, MODEKEYEDIT_PREVIOUSSPACE },
|
||||
{ 'D', 1, MODEKEYEDIT_DELETETOENDOFLINE },
|
||||
{ 'E', 1, MODEKEYEDIT_NEXTSPACEEND },
|
||||
{ 'W', 1, MODEKEYEDIT_NEXTSPACE },
|
||||
{ 'X', 1, MODEKEYEDIT_BACKSPACE },
|
||||
{ '\003' /* C-c */, 1, MODEKEYEDIT_CANCEL },
|
||||
{ '\010' /* C-h */, 1, MODEKEYEDIT_BACKSPACE },
|
||||
{ '\r', 1, MODEKEYEDIT_ENTER },
|
||||
{ '^', 1, MODEKEYEDIT_STARTOFLINE },
|
||||
{ 'a', 1, MODEKEYEDIT_SWITCHMODEAPPEND },
|
||||
{ 'b', 1, MODEKEYEDIT_PREVIOUSWORD },
|
||||
{ 'd', 1, MODEKEYEDIT_DELETELINE },
|
||||
{ 'e', 1, MODEKEYEDIT_NEXTWORDEND },
|
||||
{ 'h', 1, MODEKEYEDIT_CURSORLEFT },
|
||||
{ 'i', 1, MODEKEYEDIT_SWITCHMODE },
|
||||
{ 'j', 1, MODEKEYEDIT_HISTORYDOWN },
|
||||
{ 'k', 1, MODEKEYEDIT_HISTORYUP },
|
||||
{ 'l', 1, MODEKEYEDIT_CURSORRIGHT },
|
||||
{ 'p', 1, MODEKEYEDIT_PASTE },
|
||||
{ 'w', 1, MODEKEYEDIT_NEXTWORD },
|
||||
{ 'x', 1, MODEKEYEDIT_DELETE },
|
||||
{ KEYC_BSPACE, 1, MODEKEYEDIT_BACKSPACE },
|
||||
{ KEYC_DC, 1, MODEKEYEDIT_DELETE },
|
||||
{ KEYC_DOWN, 1, MODEKEYEDIT_HISTORYDOWN },
|
||||
@@ -211,6 +235,7 @@ const struct mode_key_entry mode_key_vi_copy[] = {
|
||||
{ 'L', 0, MODEKEYCOPY_BOTTOMLINE },
|
||||
{ 'M', 0, MODEKEYCOPY_MIDDLELINE },
|
||||
{ 'N', 0, MODEKEYCOPY_SEARCHREVERSE },
|
||||
{ 'T', 0, MODEKEYCOPY_JUMPTOBACK },
|
||||
{ 'W', 0, MODEKEYCOPY_NEXTSPACE },
|
||||
{ '\002' /* C-b */, 0, MODEKEYCOPY_PREVIOUSPAGE },
|
||||
{ '\003' /* C-c */, 0, MODEKEYCOPY_CANCEL },
|
||||
@@ -232,6 +257,7 @@ const struct mode_key_entry mode_key_vi_copy[] = {
|
||||
{ 'k', 0, MODEKEYCOPY_UP },
|
||||
{ 'l', 0, MODEKEYCOPY_RIGHT },
|
||||
{ 'n', 0, MODEKEYCOPY_SEARCHAGAIN },
|
||||
{ 't', 0, MODEKEYCOPY_JUMPTO },
|
||||
{ 'q', 0, MODEKEYCOPY_CANCEL },
|
||||
{ 'v', 0, MODEKEYCOPY_RECTANGLETOGGLE },
|
||||
{ 'w', 0, MODEKEYCOPY_NEXTWORD },
|
||||
@@ -255,18 +281,21 @@ const struct mode_key_entry mode_key_emacs_edit[] = {
|
||||
{ '\002' /* C-b */, 0, MODEKEYEDIT_CURSORLEFT },
|
||||
{ '\003' /* C-c */, 0, MODEKEYEDIT_CANCEL },
|
||||
{ '\004' /* C-d */, 0, MODEKEYEDIT_DELETE },
|
||||
{ '\005' /* C-e */, 0, MODEKEYEDIT_ENDOFLINE },
|
||||
{ '\005' /* C-e */, 0, MODEKEYEDIT_ENDOFLINE },
|
||||
{ '\006' /* C-f */, 0, MODEKEYEDIT_CURSORRIGHT },
|
||||
{ '\010' /* C-H */, 0, MODEKEYEDIT_BACKSPACE },
|
||||
{ '\011' /* Tab */, 0, MODEKEYEDIT_COMPLETE },
|
||||
{ '\013' /* C-k */, 0, MODEKEYEDIT_DELETETOENDOFLINE },
|
||||
{ '\010' /* C-H */, 0, MODEKEYEDIT_BACKSPACE },
|
||||
{ '\011' /* Tab */, 0, MODEKEYEDIT_COMPLETE },
|
||||
{ '\013' /* C-k */, 0, MODEKEYEDIT_DELETETOENDOFLINE },
|
||||
{ '\016' /* C-n */, 0, MODEKEYEDIT_HISTORYDOWN },
|
||||
{ '\020' /* C-p */, 0, MODEKEYEDIT_HISTORYUP },
|
||||
{ '\024' /* C-t */, 0, MODEKEYEDIT_TRANSPOSECHARS },
|
||||
{ '\025' /* C-u */, 0, MODEKEYEDIT_DELETELINE },
|
||||
{ '\025' /* C-u */, 0, MODEKEYEDIT_DELETELINE },
|
||||
{ '\027' /* C-w */, 0, MODEKEYEDIT_DELETEWORD },
|
||||
{ '\031' /* C-y */, 0, MODEKEYEDIT_PASTE },
|
||||
{ '\033' /* Escape */, 0, MODEKEYEDIT_CANCEL },
|
||||
{ '\r', 0, MODEKEYEDIT_ENTER },
|
||||
{ 'b' | KEYC_ESCAPE, 0, MODEKEYEDIT_PREVIOUSWORD },
|
||||
{ 'f' | KEYC_ESCAPE, 0, MODEKEYEDIT_NEXTWORDEND },
|
||||
{ 'm' | KEYC_ESCAPE, 0, MODEKEYEDIT_STARTOFLINE },
|
||||
{ KEYC_BSPACE, 0, MODEKEYEDIT_BACKSPACE },
|
||||
{ KEYC_DC, 0, MODEKEYEDIT_DELETE },
|
||||
@@ -274,6 +303,8 @@ const struct mode_key_entry mode_key_emacs_edit[] = {
|
||||
{ KEYC_LEFT, 0, MODEKEYEDIT_CURSORLEFT },
|
||||
{ KEYC_RIGHT, 0, MODEKEYEDIT_CURSORRIGHT },
|
||||
{ KEYC_UP, 0, MODEKEYEDIT_HISTORYUP },
|
||||
{ KEYC_HOME, 0, MODEKEYEDIT_STARTOFLINE },
|
||||
{ KEYC_END, 0, MODEKEYEDIT_ENDOFLINE },
|
||||
|
||||
{ 0, -1, 0 }
|
||||
};
|
||||
@@ -320,6 +351,7 @@ const struct mode_key_entry mode_key_emacs_copy[] = {
|
||||
{ 'N', 0, MODEKEYCOPY_SEARCHREVERSE },
|
||||
{ 'R' | KEYC_ESCAPE, 0, MODEKEYCOPY_TOPLINE },
|
||||
{ 'R', 0, MODEKEYCOPY_RECTANGLETOGGLE },
|
||||
{ 'T', 0, MODEKEYCOPY_JUMPTOBACK },
|
||||
{ '\000' /* C-Space */, 0, MODEKEYCOPY_STARTSELECTION },
|
||||
{ '\001' /* C-a */, 0, MODEKEYCOPY_STARTOFLINE },
|
||||
{ '\002' /* C-b */, 0, MODEKEYCOPY_LEFT },
|
||||
@@ -344,6 +376,7 @@ const struct mode_key_entry mode_key_emacs_copy[] = {
|
||||
{ 'n', 0, MODEKEYCOPY_SEARCHAGAIN },
|
||||
{ 'q', 0, MODEKEYCOPY_CANCEL },
|
||||
{ 'r' | KEYC_ESCAPE, 0, MODEKEYCOPY_MIDDLELINE },
|
||||
{ 't', 0, MODEKEYCOPY_JUMPTO },
|
||||
{ 'v' | KEYC_ESCAPE, 0, MODEKEYCOPY_PREVIOUSPAGE },
|
||||
{ 'w' | KEYC_ESCAPE, 0, MODEKEYCOPY_COPYSELECTION },
|
||||
{ KEYC_DOWN | KEYC_CTRL,0, MODEKEYCOPY_SCROLLDOWN },
|
||||
@@ -379,7 +412,7 @@ const struct mode_key_table mode_key_tables[] = {
|
||||
{ NULL, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
SPLAY_GENERATE(mode_key_tree, mode_key_binding, entry, mode_key_cmp);
|
||||
RB_GENERATE(mode_key_tree, mode_key_binding, entry, mode_key_cmp);
|
||||
|
||||
int
|
||||
mode_key_cmp(struct mode_key_binding *mbind1, struct mode_key_binding *mbind2)
|
||||
@@ -429,13 +462,13 @@ mode_key_init_trees(void)
|
||||
struct mode_key_binding *mbind;
|
||||
|
||||
for (mtab = mode_key_tables; mtab->name != NULL; mtab++) {
|
||||
SPLAY_INIT(mtab->tree);
|
||||
RB_INIT(mtab->tree);
|
||||
for (ment = mtab->table; ment->mode != -1; ment++) {
|
||||
mbind = xmalloc(sizeof *mbind);
|
||||
mbind->key = ment->key;
|
||||
mbind->mode = ment->mode;
|
||||
mbind->cmd = ment->cmd;
|
||||
SPLAY_INSERT(mode_key_tree, mtab->tree, mbind);
|
||||
RB_INSERT(mode_key_tree, mtab->tree, mbind);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -454,7 +487,7 @@ mode_key_lookup(struct mode_key_data *mdata, int key)
|
||||
|
||||
mtmp.key = key;
|
||||
mtmp.mode = mdata->mode;
|
||||
if ((mbind = SPLAY_FIND(mode_key_tree, mdata->tree, &mtmp)) == NULL) {
|
||||
if ((mbind = RB_FIND(mode_key_tree, mdata->tree, &mtmp)) == NULL) {
|
||||
if (mdata->mode != 0)
|
||||
return (MODEKEY_NONE);
|
||||
return (MODEKEY_OTHER);
|
||||
|
||||
106
options-table.c
106
options-table.c
@@ -35,6 +35,9 @@
|
||||
const char *options_table_mode_keys_list[] = {
|
||||
"emacs", "vi", NULL
|
||||
};
|
||||
const char *options_table_mode_mouse_list[] = {
|
||||
"off", "on", "copy-mode", NULL
|
||||
};
|
||||
const char *options_table_clock_mode_style_list[] = {
|
||||
"12", "24", NULL
|
||||
};
|
||||
@@ -190,6 +193,21 @@ const struct options_table_entry session_options_table[] = {
|
||||
.default_num = 3
|
||||
},
|
||||
|
||||
{ .name = "message-command-attr",
|
||||
.type = OPTIONS_TABLE_ATTRIBUTES,
|
||||
.default_num = 0
|
||||
},
|
||||
|
||||
{ .name = "message-command-bg",
|
||||
.type = OPTIONS_TABLE_COLOUR,
|
||||
.default_num = 0
|
||||
},
|
||||
|
||||
{ .name = "message-command-fg",
|
||||
.type = OPTIONS_TABLE_COLOUR,
|
||||
.default_num = 3
|
||||
},
|
||||
|
||||
{ .name = "message-fg",
|
||||
.type = OPTIONS_TABLE_COLOUR,
|
||||
.default_num = 0
|
||||
@@ -243,8 +261,13 @@ const struct options_table_entry session_options_table[] = {
|
||||
},
|
||||
|
||||
{ .name = "prefix",
|
||||
.type = OPTIONS_TABLE_KEYS,
|
||||
/* set in main() */
|
||||
.type = OPTIONS_TABLE_KEY,
|
||||
.default_num = '\002',
|
||||
},
|
||||
|
||||
{ .name = "prefix2",
|
||||
.type = OPTIONS_TABLE_KEY,
|
||||
.default_num = KEYC_NONE,
|
||||
},
|
||||
|
||||
{ .name = "repeat-time",
|
||||
@@ -372,7 +395,7 @@ const struct options_table_entry session_options_table[] = {
|
||||
.default_str = "*88col*:colors=88,*256col*:colors=256"
|
||||
",xterm*:XT:Ms=\\E]52;%p1%s;%p2%s\\007"
|
||||
":Cc=\\E]12;%p1%s\\007:Cr=\\E]112\\007"
|
||||
":Cs=\\E[%p1%d q:Csr=\\E[2 q"
|
||||
":Cs=\\E[%p1%d q:Csr=\\E[2 q,screen*:XT"
|
||||
},
|
||||
|
||||
{ .name = "update-environment",
|
||||
@@ -402,6 +425,11 @@ const struct options_table_entry session_options_table[] = {
|
||||
.default_num = 0
|
||||
},
|
||||
|
||||
{ .name = "word-separators",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.default_str = " -_@"
|
||||
},
|
||||
|
||||
{ .name = NULL }
|
||||
};
|
||||
|
||||
@@ -412,6 +440,11 @@ const struct options_table_entry window_options_table[] = {
|
||||
.default_num = 0
|
||||
},
|
||||
|
||||
{ .name = "allow-rename",
|
||||
.type = OPTIONS_TABLE_FLAG,
|
||||
.default_num = 1
|
||||
},
|
||||
|
||||
{ .name = "alternate-screen",
|
||||
.type = OPTIONS_TABLE_FLAG,
|
||||
.default_num = 1
|
||||
@@ -483,7 +516,8 @@ const struct options_table_entry window_options_table[] = {
|
||||
},
|
||||
|
||||
{ .name = "mode-mouse",
|
||||
.type = OPTIONS_TABLE_FLAG,
|
||||
.type = OPTIONS_TABLE_CHOICE,
|
||||
.choices = options_table_mode_mouse_list,
|
||||
.default_num = 0
|
||||
},
|
||||
|
||||
@@ -518,6 +552,13 @@ const struct options_table_entry window_options_table[] = {
|
||||
.default_num = 0
|
||||
},
|
||||
|
||||
{ .name = "pane-base-index",
|
||||
.type = OPTIONS_TABLE_NUMBER,
|
||||
.minimum = 0,
|
||||
.maximum = USHRT_MAX,
|
||||
.default_num = 0
|
||||
},
|
||||
|
||||
{ .name = "remain-on-exit",
|
||||
.type = OPTIONS_TABLE_FLAG,
|
||||
.default_num = 0
|
||||
@@ -533,17 +574,47 @@ const struct options_table_entry window_options_table[] = {
|
||||
.default_num = 0 /* overridden in main() */
|
||||
},
|
||||
|
||||
{ .name = "window-status-alert-attr",
|
||||
{ .name = "window-status-bell-attr",
|
||||
.type = OPTIONS_TABLE_ATTRIBUTES,
|
||||
.default_num = GRID_ATTR_REVERSE
|
||||
},
|
||||
|
||||
{ .name = "window-status-alert-bg",
|
||||
{ .name = "window-status-bell-bg",
|
||||
.type = OPTIONS_TABLE_COLOUR,
|
||||
.default_num = 8
|
||||
},
|
||||
|
||||
{ .name = "window-status-alert-fg",
|
||||
{ .name = "window-status-bell-fg",
|
||||
.type = OPTIONS_TABLE_COLOUR,
|
||||
.default_num = 8
|
||||
},
|
||||
|
||||
{ .name = "window-status-content-attr",
|
||||
.type = OPTIONS_TABLE_ATTRIBUTES,
|
||||
.default_num = GRID_ATTR_REVERSE
|
||||
},
|
||||
|
||||
{ .name = "window-status-content-bg",
|
||||
.type = OPTIONS_TABLE_COLOUR,
|
||||
.default_num = 8
|
||||
},
|
||||
|
||||
{ .name = "window-status-content-fg",
|
||||
.type = OPTIONS_TABLE_COLOUR,
|
||||
.default_num = 8
|
||||
},
|
||||
|
||||
{ .name = "window-status-activity-attr",
|
||||
.type = OPTIONS_TABLE_ATTRIBUTES,
|
||||
.default_num = GRID_ATTR_REVERSE
|
||||
},
|
||||
|
||||
{ .name = "window-status-activity-bg",
|
||||
.type = OPTIONS_TABLE_COLOUR,
|
||||
.default_num = 8
|
||||
},
|
||||
|
||||
{ .name = "window-status-activity-fg",
|
||||
.type = OPTIONS_TABLE_COLOUR,
|
||||
.default_num = 8
|
||||
},
|
||||
@@ -588,11 +659,6 @@ const struct options_table_entry window_options_table[] = {
|
||||
.default_str = "#I:#W#F"
|
||||
},
|
||||
|
||||
{ .name = "word-separators",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.default_str = " -_@"
|
||||
},
|
||||
|
||||
{ .name = "xterm-keys",
|
||||
.type = OPTIONS_TABLE_FLAG,
|
||||
.default_num = 0
|
||||
@@ -621,10 +687,8 @@ const char *
|
||||
options_table_print_entry(
|
||||
const struct options_table_entry *oe, struct options_entry *o)
|
||||
{
|
||||
static char out[BUFSIZ];
|
||||
const char *s;
|
||||
struct keylist *keylist;
|
||||
u_int i;
|
||||
static char out[BUFSIZ];
|
||||
const char *s;
|
||||
|
||||
*out = '\0';
|
||||
switch (oe->type) {
|
||||
@@ -634,14 +698,8 @@ options_table_print_entry(
|
||||
case OPTIONS_TABLE_NUMBER:
|
||||
xsnprintf(out, sizeof out, "%lld", o->num);
|
||||
break;
|
||||
case OPTIONS_TABLE_KEYS:
|
||||
keylist = o->data;
|
||||
for (i = 0; i < ARRAY_LENGTH(keylist); i++) {
|
||||
s = key_string_lookup_key(ARRAY_ITEM(keylist, i));
|
||||
strlcat(out, s, sizeof out);
|
||||
if (i != ARRAY_LENGTH(keylist) - 1)
|
||||
strlcat(out, ",", sizeof out);
|
||||
}
|
||||
case OPTIONS_TABLE_KEY:
|
||||
xsnprintf(out, sizeof out, "%s", key_string_lookup_key(o->num));
|
||||
break;
|
||||
case OPTIONS_TABLE_COLOUR:
|
||||
s = colour_tostring(o->num);
|
||||
|
||||
63
options.c
63
options.c
@@ -28,7 +28,7 @@
|
||||
* a splay tree.
|
||||
*/
|
||||
|
||||
SPLAY_GENERATE(options_tree, options_entry, entry, options_cmp);
|
||||
RB_GENERATE(options_tree, options_entry, entry, options_cmp);
|
||||
|
||||
int
|
||||
options_cmp(struct options_entry *o1, struct options_entry *o2)
|
||||
@@ -39,7 +39,7 @@ options_cmp(struct options_entry *o1, struct options_entry *o2)
|
||||
void
|
||||
options_init(struct options *oo, struct options *parent)
|
||||
{
|
||||
SPLAY_INIT(&oo->tree);
|
||||
RB_INIT(&oo->tree);
|
||||
oo->parent = parent;
|
||||
}
|
||||
|
||||
@@ -48,14 +48,12 @@ options_free(struct options *oo)
|
||||
{
|
||||
struct options_entry *o;
|
||||
|
||||
while (!SPLAY_EMPTY(&oo->tree)) {
|
||||
o = SPLAY_ROOT(&oo->tree);
|
||||
SPLAY_REMOVE(options_tree, &oo->tree, o);
|
||||
while (!RB_EMPTY(&oo->tree)) {
|
||||
o = RB_ROOT(&oo->tree);
|
||||
RB_REMOVE(options_tree, &oo->tree, o);
|
||||
xfree(o->name);
|
||||
if (o->type == OPTIONS_STRING)
|
||||
xfree(o->str);
|
||||
else if (o->type == OPTIONS_DATA)
|
||||
o->freefn(o->data);
|
||||
xfree(o);
|
||||
}
|
||||
}
|
||||
@@ -66,7 +64,7 @@ options_find1(struct options *oo, const char *name)
|
||||
struct options_entry p;
|
||||
|
||||
p.name = (char *) name;
|
||||
return (SPLAY_FIND(options_tree, &oo->tree, &p));
|
||||
return (RB_FIND(options_tree, &oo->tree, &p));
|
||||
}
|
||||
|
||||
struct options_entry *
|
||||
@@ -75,12 +73,12 @@ options_find(struct options *oo, const char *name)
|
||||
struct options_entry *o, p;
|
||||
|
||||
p.name = (char *) name;
|
||||
o = SPLAY_FIND(options_tree, &oo->tree, &p);
|
||||
o = RB_FIND(options_tree, &oo->tree, &p);
|
||||
while (o == NULL) {
|
||||
oo = oo->parent;
|
||||
if (oo == NULL)
|
||||
break;
|
||||
o = SPLAY_FIND(options_tree, &oo->tree, &p);
|
||||
o = RB_FIND(options_tree, &oo->tree, &p);
|
||||
}
|
||||
return (o);
|
||||
}
|
||||
@@ -93,12 +91,10 @@ options_remove(struct options *oo, const char *name)
|
||||
if ((o = options_find1(oo, name)) == NULL)
|
||||
return;
|
||||
|
||||
SPLAY_REMOVE(options_tree, &oo->tree, o);
|
||||
RB_REMOVE(options_tree, &oo->tree, o);
|
||||
xfree(o->name);
|
||||
if (o->type == OPTIONS_STRING)
|
||||
xfree(o->str);
|
||||
else if (o->type == OPTIONS_DATA)
|
||||
o->freefn(o->data);
|
||||
xfree(o);
|
||||
}
|
||||
|
||||
@@ -111,11 +107,9 @@ options_set_string(struct options *oo, const char *name, const char *fmt, ...)
|
||||
if ((o = options_find1(oo, name)) == NULL) {
|
||||
o = xmalloc(sizeof *o);
|
||||
o->name = xstrdup(name);
|
||||
SPLAY_INSERT(options_tree, &oo->tree, o);
|
||||
RB_INSERT(options_tree, &oo->tree, o);
|
||||
} else if (o->type == OPTIONS_STRING)
|
||||
xfree(o->str);
|
||||
else if (o->type == OPTIONS_DATA)
|
||||
o->freefn(o->data);
|
||||
|
||||
va_start(ap, fmt);
|
||||
o->type = OPTIONS_STRING;
|
||||
@@ -144,11 +138,9 @@ options_set_number(struct options *oo, const char *name, long long value)
|
||||
if ((o = options_find1(oo, name)) == NULL) {
|
||||
o = xmalloc(sizeof *o);
|
||||
o->name = xstrdup(name);
|
||||
SPLAY_INSERT(options_tree, &oo->tree, o);
|
||||
RB_INSERT(options_tree, &oo->tree, o);
|
||||
} else if (o->type == OPTIONS_STRING)
|
||||
xfree(o->str);
|
||||
else if (o->type == OPTIONS_DATA)
|
||||
o->freefn(o->data);
|
||||
|
||||
o->type = OPTIONS_NUMBER;
|
||||
o->num = value;
|
||||
@@ -166,36 +158,3 @@ options_get_number(struct options *oo, const char *name)
|
||||
fatalx("option not a number");
|
||||
return (o->num);
|
||||
}
|
||||
|
||||
struct options_entry *
|
||||
options_set_data(
|
||||
struct options *oo, const char *name, void *value, void (*freefn)(void *))
|
||||
{
|
||||
struct options_entry *o;
|
||||
|
||||
if ((o = options_find1(oo, name)) == NULL) {
|
||||
o = xmalloc(sizeof *o);
|
||||
o->name = xstrdup(name);
|
||||
SPLAY_INSERT(options_tree, &oo->tree, o);
|
||||
} else if (o->type == OPTIONS_STRING)
|
||||
xfree(o->str);
|
||||
else if (o->type == OPTIONS_DATA)
|
||||
o->freefn(o->data);
|
||||
|
||||
o->type = OPTIONS_DATA;
|
||||
o->data = value;
|
||||
o->freefn = freefn;
|
||||
return (o);
|
||||
}
|
||||
|
||||
void *
|
||||
options_get_data(struct options *oo, const char *name)
|
||||
{
|
||||
struct options_entry *o;
|
||||
|
||||
if ((o = options_find(oo, name)) == NULL)
|
||||
fatalx("missing option");
|
||||
if (o->type != OPTIONS_DATA)
|
||||
fatalx("option not data");
|
||||
return (o->data);
|
||||
}
|
||||
|
||||
@@ -28,6 +28,12 @@ osdep_get_name(unused int fd, unused char *tty)
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
char *
|
||||
osdep_get_cwd(pid_t pid)
|
||||
{
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
struct event_base *
|
||||
osdep_event_init(void)
|
||||
{
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <unistd.h>
|
||||
|
||||
char *osdep_get_name(int, char *);
|
||||
char *osdep_get_cwd(pid_t);
|
||||
struct event_base *osdep_event_init(void);
|
||||
|
||||
#define unused __attribute__ ((unused))
|
||||
@@ -48,6 +49,12 @@ osdep_get_name(int fd, unused char *tty)
|
||||
return (strdup(kp.kp_proc.p_comm));
|
||||
}
|
||||
|
||||
char *
|
||||
osdep_get_cwd(pid_t pid)
|
||||
{
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
struct event_base *
|
||||
osdep_event_init(void)
|
||||
{
|
||||
|
||||
133
osdep-dragonfly.c
Normal file
133
osdep-dragonfly.c
Normal file
@@ -0,0 +1,133 @@
|
||||
/* $Id$ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicm@users.sourceforge.net>
|
||||
*
|
||||
* 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/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/user.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <event.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
struct kinfo_proc *cmp_procs(struct kinfo_proc *, struct kinfo_proc *);
|
||||
char *osdep_get_name(int, char *);
|
||||
char *osdep_get_cwd(pid_t);
|
||||
struct event_base *osdep_event_init(void);
|
||||
|
||||
#ifndef nitems
|
||||
#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
|
||||
#endif
|
||||
|
||||
#define is_runnable(p) \
|
||||
((p)->kp_stat == SACTIVE || (p)->kp_stat == SIDL)
|
||||
#define is_stopped(p) \
|
||||
((p)->kp_stat == SSTOP || (p)->kp_stat == SZOMB)
|
||||
|
||||
struct kinfo_proc *
|
||||
cmp_procs(struct kinfo_proc *p1, struct kinfo_proc *p2)
|
||||
{
|
||||
if (is_runnable(p1) && !is_runnable(p2))
|
||||
return (p1);
|
||||
if (!is_runnable(p1) && is_runnable(p2))
|
||||
return (p2);
|
||||
|
||||
if (is_stopped(p1) && !is_stopped(p2))
|
||||
return (p1);
|
||||
if (!is_stopped(p1) && is_stopped(p2))
|
||||
return (p2);
|
||||
|
||||
if (strcmp(p1->kp_comm, p2->kp_comm) < 0)
|
||||
return (p1);
|
||||
if (strcmp(p1->kp_comm, p2->kp_comm) > 0)
|
||||
return (p2);
|
||||
|
||||
if (p1->kp_pid > p2->kp_pid)
|
||||
return (p1);
|
||||
return (p2);
|
||||
}
|
||||
|
||||
char *
|
||||
osdep_get_name(int fd, char *tty)
|
||||
{
|
||||
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PGRP, 0 };
|
||||
struct stat sb;
|
||||
size_t len;
|
||||
struct kinfo_proc *buf, *newbuf, *bestp;
|
||||
u_int i;
|
||||
char *name;
|
||||
|
||||
buf = NULL;
|
||||
|
||||
if (stat(tty, &sb) == -1)
|
||||
return (NULL);
|
||||
if ((mib[3] = tcgetpgrp(fd)) == -1)
|
||||
return (NULL);
|
||||
|
||||
retry:
|
||||
if (sysctl(mib, nitems(mib), NULL, &len, NULL, 0) == -1)
|
||||
return (NULL);
|
||||
len = (len * 5) / 4;
|
||||
|
||||
if ((newbuf = realloc(buf, len)) == NULL)
|
||||
goto error;
|
||||
buf = newbuf;
|
||||
|
||||
if (sysctl(mib, nitems(mib), buf, &len, NULL, 0) == -1) {
|
||||
if (errno == ENOMEM)
|
||||
goto retry;
|
||||
goto error;
|
||||
}
|
||||
|
||||
bestp = NULL;
|
||||
for (i = 0; i < len / sizeof (struct kinfo_proc); i++) {
|
||||
if (buf[i].kp_tdev != sb.st_rdev)
|
||||
continue;
|
||||
if (bestp == NULL)
|
||||
bestp = &buf[i];
|
||||
else
|
||||
bestp = cmp_procs(&buf[i], bestp);
|
||||
}
|
||||
|
||||
name = NULL;
|
||||
if (bestp != NULL)
|
||||
name = strdup(bestp->kp_comm);
|
||||
|
||||
free(buf);
|
||||
return (name);
|
||||
|
||||
error:
|
||||
free(buf);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
char *
|
||||
osdep_get_cwd(pid_t pid)
|
||||
{
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
struct event_base *
|
||||
osdep_event_init(void)
|
||||
{
|
||||
return (event_init());
|
||||
}
|
||||
@@ -29,9 +29,11 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <libutil.h>
|
||||
|
||||
struct kinfo_proc *cmp_procs(struct kinfo_proc *, struct kinfo_proc *);
|
||||
char *osdep_get_name(int, char *);
|
||||
char *osdep_get_cwd(pid_t);
|
||||
struct event_base *osdep_event_init(void);
|
||||
|
||||
#ifndef nitems
|
||||
@@ -130,6 +132,28 @@ error:
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
char *
|
||||
osdep_get_cwd(pid_t pid)
|
||||
{
|
||||
static char wd[PATH_MAX];
|
||||
struct kinfo_file *info = NULL;
|
||||
int nrecords, i;
|
||||
|
||||
if ((info = kinfo_getfile(pid, &nrecords)) == NULL)
|
||||
return (NULL);
|
||||
|
||||
for (i = 0; i < nrecords; i++) {
|
||||
if (info[i].kf_fd == KF_FD_TYPE_CWD) {
|
||||
strlcpy(wd, info[i].kf_path, sizeof wd);
|
||||
free(info);
|
||||
return (wd);
|
||||
}
|
||||
}
|
||||
|
||||
free(info);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
struct event_base *
|
||||
osdep_event_init(void)
|
||||
{
|
||||
|
||||
@@ -28,6 +28,12 @@ osdep_get_name(unused int fd, unused char *tty)
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
char *
|
||||
osdep_get_cwd(pid_t pid)
|
||||
{
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
struct event_base *
|
||||
osdep_event_init(void)
|
||||
{
|
||||
|
||||
@@ -60,6 +60,23 @@ osdep_get_name(int fd, unused char *tty)
|
||||
return (buf);
|
||||
}
|
||||
|
||||
char *
|
||||
osdep_get_cwd(pid_t pid)
|
||||
{
|
||||
static char target[MAXPATHLEN + 1];
|
||||
char *path;
|
||||
ssize_t n;
|
||||
|
||||
xasprintf(&path, "/proc/%d/cwd", pid);
|
||||
n = readlink(path, target, MAXPATHLEN);
|
||||
xfree(path);
|
||||
if (n > 0) {
|
||||
target[n] = '\0';
|
||||
return (target);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
struct event_base *
|
||||
osdep_event_init(void)
|
||||
{
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
|
||||
struct kinfo_proc2 *cmp_procs(struct kinfo_proc2 *, struct kinfo_proc2 *);
|
||||
char *osdep_get_name(int, char *);
|
||||
char *osdep_get_cwd(pid_t);
|
||||
struct event_base *osdep_event_init(void);
|
||||
|
||||
struct kinfo_proc2 *
|
||||
@@ -123,6 +124,12 @@ error:
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
char *
|
||||
osdep_get_cwd(pid_t pid)
|
||||
{
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
struct event_base *
|
||||
osdep_event_init(void)
|
||||
{
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
|
||||
struct kinfo_proc *cmp_procs(struct kinfo_proc *, struct kinfo_proc *);
|
||||
char *osdep_get_name(int, char *);
|
||||
char *osdep_get_cwd(pid_t);
|
||||
struct event_base *osdep_event_init(void);
|
||||
|
||||
struct kinfo_proc *
|
||||
@@ -133,6 +134,18 @@ error:
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
char*
|
||||
osdep_get_cwd(pid_t pid)
|
||||
{
|
||||
int name[] = { CTL_KERN, KERN_PROC_CWD, (int)pid };
|
||||
static char path[MAXPATHLEN];
|
||||
size_t pathlen = sizeof path;
|
||||
|
||||
if (sysctl(name, 3, path, &pathlen, NULL, 0) != 0)
|
||||
return (NULL);
|
||||
return (path);
|
||||
}
|
||||
|
||||
struct event_base *
|
||||
osdep_event_init(void)
|
||||
{
|
||||
|
||||
@@ -41,14 +41,13 @@ osdep_get_name(int fd, char *tty)
|
||||
if ((f = open(tty, O_RDONLY)) < 0)
|
||||
return (NULL);
|
||||
|
||||
if ((fstat(f, &st) != 0) ||
|
||||
(ioctl(f, TIOCGPGRP, &pgrp) != 0)) {
|
||||
if (fstat(f, &st) != 0 || ioctl(f, TIOCGPGRP, &pgrp) != 0) {
|
||||
close(f);
|
||||
return (NULL);
|
||||
}
|
||||
close(f);
|
||||
|
||||
xasprintf(&path, "/proc/%hu/psinfo", pgrp);
|
||||
xasprintf(&path, "/proc/%u/psinfo", (u_int) pgrp);
|
||||
f = open(path, O_RDONLY);
|
||||
xfree(path);
|
||||
if (f < 0)
|
||||
@@ -65,6 +64,23 @@ osdep_get_name(int fd, char *tty)
|
||||
return (xstrdup(p.pr_fname));
|
||||
}
|
||||
|
||||
char *
|
||||
osdep_get_cwd(pid_t pid)
|
||||
{
|
||||
static char target[MAXPATHLEN + 1];
|
||||
char *path;
|
||||
ssize_t n;
|
||||
|
||||
xasprintf(&path, "/proc/%u/path/cwd", (u_int) pid);
|
||||
n = readlink(path, target, MAXPATHLEN);
|
||||
xfree(path);
|
||||
if (n > 0) {
|
||||
target[n] = '\0';
|
||||
return (target);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
struct event_base *
|
||||
osdep_event_init(void)
|
||||
{
|
||||
|
||||
@@ -28,6 +28,12 @@ osdep_get_name(unused int fd, unused char *tty)
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
char *
|
||||
osdep_get_cwd(pid_t pid)
|
||||
{
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
struct event_base *
|
||||
osdep_event_init(void)
|
||||
{
|
||||
|
||||
@@ -264,7 +264,7 @@ screen_redraw_draw_number(struct client *c, struct window_pane *wp)
|
||||
{
|
||||
struct tty *tty = &c->tty;
|
||||
struct session *s = c->session;
|
||||
struct options *oo = &s->options;
|
||||
struct options *oo = &s->options;
|
||||
struct window *w = wp->window;
|
||||
struct grid_cell gc;
|
||||
u_int idx, px, py, i, j, xoff, yoff;
|
||||
@@ -272,7 +272,8 @@ screen_redraw_draw_number(struct client *c, struct window_pane *wp)
|
||||
char buf[16], *ptr;
|
||||
size_t len;
|
||||
|
||||
idx = window_pane_index(w, wp);
|
||||
if (window_pane_index(wp, &idx) != 0)
|
||||
fatalx("index not found");
|
||||
len = xsnprintf(buf, sizeof buf, "%u", idx);
|
||||
|
||||
if (wp->sx < len)
|
||||
@@ -285,15 +286,7 @@ screen_redraw_draw_number(struct client *c, struct window_pane *wp)
|
||||
|
||||
if (wp->sx < len * 6 || wp->sy < 5) {
|
||||
tty_cursor(tty, xoff + px - len / 2, yoff + py);
|
||||
memcpy(&gc, &grid_default_cell, sizeof gc);
|
||||
gc.data = '_'; /* not space */
|
||||
if (w->active == wp)
|
||||
colour_set_fg(&gc, active_colour);
|
||||
else
|
||||
colour_set_fg(&gc, colour);
|
||||
tty_attributes(tty, &gc);
|
||||
tty_puts(tty, buf);
|
||||
return;
|
||||
goto draw_text;
|
||||
}
|
||||
|
||||
px -= len * 3;
|
||||
@@ -320,4 +313,21 @@ screen_redraw_draw_number(struct client *c, struct window_pane *wp)
|
||||
}
|
||||
px += 6;
|
||||
}
|
||||
|
||||
len = xsnprintf(buf, sizeof buf, "%ux%u", wp->sx, wp->sy);
|
||||
if (wp->sx < len || wp->sy < 6)
|
||||
return;
|
||||
tty_cursor(tty, xoff + wp->sx - len, yoff);
|
||||
|
||||
draw_text:
|
||||
memcpy(&gc, &grid_default_cell, sizeof gc);
|
||||
gc.data = '_'; /* not space */
|
||||
if (w->active == wp)
|
||||
colour_set_fg(&gc, active_colour);
|
||||
else
|
||||
colour_set_fg(&gc, colour);
|
||||
tty_attributes(tty, &gc);
|
||||
tty_puts(tty, buf);
|
||||
|
||||
tty_cursor(tty, 0, 0);
|
||||
}
|
||||
|
||||
@@ -46,6 +46,24 @@ screen_write_stop(unused struct screen_write_ctx *ctx)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/* Reset screen state. */
|
||||
void
|
||||
screen_write_reset(struct screen_write_ctx *ctx)
|
||||
{
|
||||
screen_reset_tabs(ctx->s);
|
||||
|
||||
screen_write_scrollregion(ctx, 0, screen_size_y(ctx->s) - 1);
|
||||
|
||||
screen_write_insertmode(ctx, 0);
|
||||
screen_write_kcursormode(ctx, 0);
|
||||
screen_write_kkeypadmode(ctx, 0);
|
||||
screen_write_mousemode_off(ctx);
|
||||
|
||||
screen_write_clearscreen(ctx);
|
||||
screen_write_cursormove(ctx, 0, 0);
|
||||
}
|
||||
|
||||
/* Write character. */
|
||||
void
|
||||
screen_write_putc(
|
||||
@@ -985,6 +1003,17 @@ screen_write_clearscreen(struct screen_write_ctx *ctx)
|
||||
tty_write(tty_cmd_clearscreen, &ttyctx);
|
||||
}
|
||||
|
||||
/* Clear entire history. */
|
||||
void
|
||||
screen_write_clearhistory(struct screen_write_ctx *ctx)
|
||||
{
|
||||
struct screen *s = ctx->s;
|
||||
struct grid *gd = s->grid;
|
||||
|
||||
grid_move_lines(gd, 0, gd->hsize, gd->sy);
|
||||
gd->hsize = 0;
|
||||
}
|
||||
|
||||
/* Write cell data. */
|
||||
void
|
||||
screen_write_cell(struct screen_write_ctx *ctx,
|
||||
|
||||
@@ -170,6 +170,8 @@ server_client_lost(struct client *c)
|
||||
if (c->cwd != NULL)
|
||||
xfree(c->cwd);
|
||||
|
||||
environ_free(&c->environ);
|
||||
|
||||
close(c->ibuf.fd);
|
||||
imsg_clear(&c->ibuf);
|
||||
event_del(&c->event);
|
||||
@@ -270,9 +272,7 @@ server_client_handle_key(int key, struct mouse_event *mouse, void *data)
|
||||
struct options *oo;
|
||||
struct timeval tv;
|
||||
struct key_binding *bd;
|
||||
struct keylist *keylist;
|
||||
int xtimeout, isprefix;
|
||||
u_int i;
|
||||
|
||||
/* Check the client is good to accept input. */
|
||||
if ((c->flags & (CLIENT_DEAD|CLIENT_SUSPENDED)) != 0)
|
||||
@@ -317,6 +317,8 @@ server_client_handle_key(int key, struct mouse_event *mouse, void *data)
|
||||
if (c->flags & CLIENT_READONLY)
|
||||
return;
|
||||
if (options_get_number(oo, "mouse-select-pane") &&
|
||||
(!(options_get_number(oo, "status") &&
|
||||
mouse->y + 1 == c->tty.sy)) &&
|
||||
((!(mouse->b & MOUSE_DRAG) && mouse->b != MOUSE_UP) ||
|
||||
wp->mode != &window_copy_mode)) {
|
||||
/*
|
||||
@@ -355,14 +357,12 @@ server_client_handle_key(int key, struct mouse_event *mouse, void *data)
|
||||
}
|
||||
|
||||
/* Is this a prefix key? */
|
||||
keylist = options_get_data(&c->session->options, "prefix");
|
||||
isprefix = 0;
|
||||
for (i = 0; i < ARRAY_LENGTH(keylist); i++) {
|
||||
if (key == ARRAY_ITEM(keylist, i)) {
|
||||
isprefix = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (key == options_get_number(&c->session->options, "prefix"))
|
||||
isprefix = 1;
|
||||
else if (key == options_get_number(&c->session->options, "prefix2"))
|
||||
isprefix = 1;
|
||||
else
|
||||
isprefix = 0;
|
||||
|
||||
/* No previous prefix key. */
|
||||
if (!(c->flags & CLIENT_PREFIX)) {
|
||||
@@ -560,50 +560,6 @@ server_client_check_exit(struct client *c)
|
||||
c->flags &= ~CLIENT_EXIT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the client should backoff. During backoff, data from external
|
||||
* programs is not written to the terminal. When the existing data drains, the
|
||||
* client is redrawn.
|
||||
*
|
||||
* There are two backoff phases - both the tty and client have backoff flags -
|
||||
* the first to allow existing data to drain and the latter to ensure backoff
|
||||
* is disabled until the redraw has finished and prevent the redraw triggering
|
||||
* another backoff.
|
||||
*/
|
||||
void
|
||||
server_client_check_backoff(struct client *c)
|
||||
{
|
||||
struct tty *tty = &c->tty;
|
||||
size_t used;
|
||||
|
||||
used = EVBUFFER_LENGTH(tty->event->output);
|
||||
|
||||
/*
|
||||
* If in the second backoff phase (redrawing), don't check backoff
|
||||
* until the redraw has completed (or enough of it to drop below the
|
||||
* backoff threshold).
|
||||
*/
|
||||
if (c->flags & CLIENT_BACKOFF) {
|
||||
if (used > BACKOFF_THRESHOLD)
|
||||
return;
|
||||
c->flags &= ~CLIENT_BACKOFF;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Once drained, allow data through again and schedule redraw. */
|
||||
if (tty->flags & TTY_BACKOFF) {
|
||||
if (used != 0)
|
||||
return;
|
||||
tty->flags &= ~TTY_BACKOFF;
|
||||
c->flags |= (CLIENT_BACKOFF|CLIENT_REDRAWWINDOW|CLIENT_STATUS);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If too much data, start backoff. */
|
||||
if (used > BACKOFF_THRESHOLD)
|
||||
tty->flags |= TTY_BACKOFF;
|
||||
}
|
||||
|
||||
/* Check for client redraws. */
|
||||
void
|
||||
server_client_check_redraw(struct client *c)
|
||||
|
||||
21
server-fn.c
21
server-fn.c
@@ -237,6 +237,7 @@ server_lock_client(struct client *c)
|
||||
tty_stop_tty(&c->tty);
|
||||
tty_raw(&c->tty, tty_term_string(c->tty.term, TTYC_SMCUP));
|
||||
tty_raw(&c->tty, tty_term_string(c->tty.term, TTYC_CLEAR));
|
||||
tty_raw(&c->tty, tty_term_string(c->tty.term, TTYC_E3));
|
||||
|
||||
c->flags |= CLIENT_SUSPENDED;
|
||||
server_write_client(c, MSG_LOCK, &lockdata, sizeof lockdata);
|
||||
@@ -329,16 +330,32 @@ server_unlink_window(struct session *s, struct winlink *wl)
|
||||
void
|
||||
server_destroy_pane(struct window_pane *wp)
|
||||
{
|
||||
struct window *w = wp->window;
|
||||
struct window *w = wp->window;
|
||||
int old_fd;
|
||||
struct screen_write_ctx ctx;
|
||||
struct grid_cell gc;
|
||||
|
||||
old_fd = wp->fd;
|
||||
if (wp->fd != -1) {
|
||||
close(wp->fd);
|
||||
bufferevent_free(wp->event);
|
||||
wp->fd = -1;
|
||||
}
|
||||
|
||||
if (options_get_number(&w->options, "remain-on-exit"))
|
||||
if (options_get_number(&w->options, "remain-on-exit")) {
|
||||
if (old_fd == -1)
|
||||
return;
|
||||
screen_write_start(&ctx, wp, &wp->base);
|
||||
screen_write_scrollregion(&ctx, 0, screen_size_y(ctx.s) - 1);
|
||||
screen_write_cursormove(&ctx, 0, screen_size_y(ctx.s) - 1);
|
||||
screen_write_linefeed(&ctx, 1);
|
||||
memcpy(&gc, &grid_default_cell, sizeof gc);
|
||||
gc.attr |= GRID_ATTR_BRIGHT;
|
||||
screen_write_puts(&ctx, &gc, "Pane is dead");
|
||||
screen_write_stop(&ctx);
|
||||
wp->flags |= PANE_REDRAW;
|
||||
return;
|
||||
}
|
||||
|
||||
layout_close_pane(wp);
|
||||
window_remove_pane(w, wp);
|
||||
|
||||
@@ -56,8 +56,10 @@ server_window_loop(void)
|
||||
server_status_session(s);
|
||||
TAILQ_FOREACH(wp, &w->panes, entry)
|
||||
server_window_check_content(s, wl, wp);
|
||||
|
||||
if (!(s->flags & SESSION_UNATTACHED))
|
||||
w->flags &= ~(WINDOW_BELL|WINDOW_ACTIVITY);
|
||||
}
|
||||
w->flags &= ~(WINDOW_BELL|WINDOW_ACTIVITY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +74,7 @@ server_window_check_bell(struct session *s, struct winlink *wl)
|
||||
|
||||
if (!(w->flags & WINDOW_BELL) || wl->flags & WINLINK_BELL)
|
||||
return (0);
|
||||
if (s->curw != wl)
|
||||
if (s->curw != wl || s->flags & SESSION_UNATTACHED)
|
||||
wl->flags |= WINLINK_BELL;
|
||||
|
||||
action = options_get_number(&s->options, "bell-action");
|
||||
@@ -86,7 +88,7 @@ server_window_check_bell(struct session *s, struct winlink *wl)
|
||||
if (c == NULL || c->session != s)
|
||||
continue;
|
||||
if (!visual) {
|
||||
tty_putcode(&c->tty, TTYC_BEL);
|
||||
tty_bell(&c->tty);
|
||||
continue;
|
||||
}
|
||||
if (c->session->curw->window == w) {
|
||||
@@ -108,7 +110,7 @@ server_window_check_bell(struct session *s, struct winlink *wl)
|
||||
if (c->session->curw->window != w)
|
||||
continue;
|
||||
if (!visual) {
|
||||
tty_putcode(&c->tty, TTYC_BEL);
|
||||
tty_bell(&c->tty);
|
||||
continue;
|
||||
}
|
||||
status_message_set(c, "Bell in current window");
|
||||
@@ -129,7 +131,7 @@ server_window_check_activity(struct session *s, struct winlink *wl)
|
||||
|
||||
if (!(w->flags & WINDOW_ACTIVITY) || wl->flags & WINLINK_ACTIVITY)
|
||||
return (0);
|
||||
if (s->curw == wl)
|
||||
if (s->curw == wl && !(s->flags & SESSION_UNATTACHED))
|
||||
return (0);
|
||||
|
||||
if (!options_get_number(&w->options, "monitor-activity"))
|
||||
@@ -165,7 +167,7 @@ server_window_check_silence(struct session *s, struct winlink *wl)
|
||||
if (!(w->flags & WINDOW_SILENCE) || wl->flags & WINLINK_SILENCE)
|
||||
return (0);
|
||||
|
||||
if (s->curw == wl) {
|
||||
if (s->curw == wl && !(s->flags & SESSION_UNATTACHED)) {
|
||||
/*
|
||||
* Reset the timer for this window if we've focused it. We
|
||||
* don't want the timer tripping as soon as we've switched away
|
||||
@@ -217,7 +219,7 @@ server_window_check_content(
|
||||
/* Activity flag must be set for new content. */
|
||||
if (!(w->flags & WINDOW_ACTIVITY) || wl->flags & WINLINK_CONTENT)
|
||||
return (0);
|
||||
if (s->curw == wl)
|
||||
if (s->curw == wl && !(s->flags & SESSION_UNATTACHED))
|
||||
return (0);
|
||||
|
||||
ptr = options_get_string(&w->options, "monitor-content");
|
||||
@@ -254,6 +256,6 @@ ring_bell(struct session *s)
|
||||
for (i = 0; i < ARRAY_LENGTH(&clients); i++) {
|
||||
c = ARRAY_ITEM(&clients, i);
|
||||
if (c != NULL && c->session == s)
|
||||
tty_putcode(&c->tty, TTYC_BEL);
|
||||
tty_bell(&c->tty);
|
||||
}
|
||||
}
|
||||
|
||||
15
session.c
15
session.c
@@ -118,11 +118,18 @@ session_create(const char *name, const char *cmd, const char *cwd,
|
||||
s->sx = sx;
|
||||
s->sy = sy;
|
||||
|
||||
s->idx = next_session++;
|
||||
if (name != NULL)
|
||||
if (name != NULL) {
|
||||
s->name = xstrdup(name);
|
||||
else
|
||||
xasprintf(&s->name, "%u", s->idx);
|
||||
s->idx = next_session++;
|
||||
} else {
|
||||
s->name = NULL;
|
||||
do {
|
||||
s->idx = next_session++;
|
||||
if (s->name != NULL)
|
||||
xfree (s->name);
|
||||
xasprintf(&s->name, "%u", s->idx);
|
||||
} while (RB_FIND(sessions, &sessions, s) != NULL);
|
||||
}
|
||||
RB_INSERT(sessions, &sessions, s);
|
||||
|
||||
if (cmd != NULL) {
|
||||
|
||||
165
status.c
165
status.c
@@ -372,6 +372,7 @@ status_replace1(struct client *c, struct session *s, struct winlink *wl,
|
||||
char ch, tmp[256], *ptr, *endptr, *freeptr;
|
||||
size_t ptrlen;
|
||||
long limit;
|
||||
u_int idx;
|
||||
|
||||
if (s == NULL)
|
||||
s = c->session;
|
||||
@@ -422,8 +423,10 @@ status_replace1(struct client *c, struct session *s, struct winlink *wl,
|
||||
ptr = tmp;
|
||||
goto do_replace;
|
||||
case 'P':
|
||||
if (window_pane_index(wp, &idx) != 0)
|
||||
fatalx("index not found");
|
||||
xsnprintf(
|
||||
tmp, sizeof tmp, "%u", window_pane_index(wl->window, wp));
|
||||
tmp, sizeof tmp, "%u", idx);
|
||||
ptr = tmp;
|
||||
goto do_replace;
|
||||
case 'S':
|
||||
@@ -551,8 +554,10 @@ status_find_job(struct client *c, char **iptr)
|
||||
/* First try in the new tree. */
|
||||
so_find.cmd = cmd;
|
||||
so = RB_FIND(status_out_tree, &c->status_new, &so_find);
|
||||
if (so != NULL && so->out != NULL)
|
||||
if (so != NULL && so->out != NULL) {
|
||||
xfree(cmd);
|
||||
return (so->out);
|
||||
}
|
||||
|
||||
/* If not found at all, start the job and add to the tree. */
|
||||
if (so == NULL) {
|
||||
@@ -679,14 +684,34 @@ status_print(
|
||||
fmt = options_get_string(oo, "window-status-current-format");
|
||||
}
|
||||
|
||||
if (wl->flags & WINLINK_ALERTFLAGS) {
|
||||
fg = options_get_number(oo, "window-status-alert-fg");
|
||||
if (wl->flags & WINLINK_BELL) {
|
||||
fg = options_get_number(oo, "window-status-bell-fg");
|
||||
if (fg != 8)
|
||||
colour_set_fg(gc, fg);
|
||||
bg = options_get_number(oo, "window-status-alert-bg");
|
||||
bg = options_get_number(oo, "window-status-bell-bg");
|
||||
if (bg != 8)
|
||||
colour_set_bg(gc, bg);
|
||||
attr = options_get_number(oo, "window-status-alert-attr");
|
||||
attr = options_get_number(oo, "window-status-bell-attr");
|
||||
if (attr != 0)
|
||||
gc->attr = attr;
|
||||
} else if (wl->flags & WINLINK_CONTENT) {
|
||||
fg = options_get_number(oo, "window-status-content-fg");
|
||||
if (fg != 8)
|
||||
colour_set_fg(gc, fg);
|
||||
bg = options_get_number(oo, "window-status-content-bg");
|
||||
if (bg != 8)
|
||||
colour_set_bg(gc, bg);
|
||||
attr = options_get_number(oo, "window-status-content-attr");
|
||||
if (attr != 0)
|
||||
gc->attr = attr;
|
||||
} else if (wl->flags & (WINLINK_ACTIVITY|WINLINK_SILENCE)) {
|
||||
fg = options_get_number(oo, "window-status-activity-fg");
|
||||
if (fg != 8)
|
||||
colour_set_fg(gc, fg);
|
||||
bg = options_get_number(oo, "window-status-activity-bg");
|
||||
if (bg != 8)
|
||||
colour_set_bg(gc, bg);
|
||||
attr = options_get_number(oo, "window-status-activity-attr");
|
||||
if (attr != 0)
|
||||
gc->attr = attr;
|
||||
}
|
||||
@@ -917,9 +942,16 @@ status_prompt_redraw(struct client *c)
|
||||
off = 0;
|
||||
|
||||
memcpy(&gc, &grid_default_cell, sizeof gc);
|
||||
colour_set_fg(&gc, options_get_number(&s->options, "message-fg"));
|
||||
colour_set_bg(&gc, options_get_number(&s->options, "message-bg"));
|
||||
gc.attr |= options_get_number(&s->options, "message-attr");
|
||||
/* Change colours for command mode. */
|
||||
if (c->prompt_mdata.mode == 1) {
|
||||
colour_set_fg(&gc, options_get_number(&s->options, "message-command-fg"));
|
||||
colour_set_bg(&gc, options_get_number(&s->options, "message-command-bg"));
|
||||
gc.attr |= options_get_number(&s->options, "message-command-attr");
|
||||
} else {
|
||||
colour_set_fg(&gc, options_get_number(&s->options, "message-fg"));
|
||||
colour_set_bg(&gc, options_get_number(&s->options, "message-bg"));
|
||||
gc.attr |= options_get_number(&s->options, "message-attr");
|
||||
}
|
||||
|
||||
screen_write_start(&ctx, NULL, &c->status);
|
||||
|
||||
@@ -961,9 +993,12 @@ status_prompt_redraw(struct client *c)
|
||||
void
|
||||
status_prompt_key(struct client *c, int key)
|
||||
{
|
||||
struct session *sess = c->session;
|
||||
struct options *oo = &sess->options;
|
||||
struct paste_buffer *pb;
|
||||
char *s, *first, *last, word[64], swapc;
|
||||
const char *histstr;
|
||||
char *s, *first, *last, word[64], swapc;
|
||||
const char *histstr;
|
||||
const char *wsep = NULL;
|
||||
u_char ch;
|
||||
size_t size, n, off, idx;
|
||||
|
||||
@@ -975,7 +1010,12 @@ status_prompt_key(struct client *c, int key)
|
||||
c->flags |= CLIENT_STATUS;
|
||||
}
|
||||
break;
|
||||
case MODEKEYEDIT_SWITCHMODE:
|
||||
c->flags |= CLIENT_STATUS;
|
||||
break;
|
||||
case MODEKEYEDIT_SWITCHMODEAPPEND:
|
||||
c->flags |= CLIENT_STATUS;
|
||||
/* FALLTHROUGH */
|
||||
case MODEKEYEDIT_CURSORRIGHT:
|
||||
if (c->prompt_index < size) {
|
||||
c->prompt_index++;
|
||||
@@ -1075,11 +1115,112 @@ status_prompt_key(struct client *c, int key)
|
||||
c->flags |= CLIENT_STATUS;
|
||||
}
|
||||
break;
|
||||
case MODEKEYEDIT_DELETEWORD:
|
||||
wsep = options_get_string(oo, "word-separators");
|
||||
idx = c->prompt_index;
|
||||
|
||||
/* Find a non-separator. */
|
||||
while (idx != 0) {
|
||||
idx--;
|
||||
if (!strchr(wsep, c->prompt_buffer[idx]))
|
||||
break;
|
||||
}
|
||||
|
||||
/* Find the separator at the beginning of the word. */
|
||||
while (idx != 0) {
|
||||
idx--;
|
||||
if (strchr(wsep, c->prompt_buffer[idx])) {
|
||||
/* Go back to the word. */
|
||||
idx++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
memmove(c->prompt_buffer + idx,
|
||||
c->prompt_buffer + c->prompt_index,
|
||||
size + 1 - c->prompt_index);
|
||||
memset(c->prompt_buffer + size - (c->prompt_index - idx),
|
||||
'\0', c->prompt_index - idx);
|
||||
c->prompt_index = idx;
|
||||
c->flags |= CLIENT_STATUS;
|
||||
break;
|
||||
case MODEKEYEDIT_NEXTSPACE:
|
||||
wsep = " ";
|
||||
/* FALLTHROUGH */
|
||||
case MODEKEYEDIT_NEXTWORD:
|
||||
if (wsep == NULL)
|
||||
wsep = options_get_string(oo, "word-separators");
|
||||
|
||||
/* Find a separator. */
|
||||
while (c->prompt_index != size) {
|
||||
c->prompt_index++;
|
||||
if (strchr(wsep, c->prompt_buffer[c->prompt_index]))
|
||||
break;
|
||||
}
|
||||
|
||||
/* Find the word right after the separation. */
|
||||
while (c->prompt_index != size) {
|
||||
c->prompt_index++;
|
||||
if (!strchr(wsep, c->prompt_buffer[c->prompt_index]))
|
||||
break;
|
||||
}
|
||||
|
||||
c->flags |= CLIENT_STATUS;
|
||||
break;
|
||||
case MODEKEYEDIT_NEXTSPACEEND:
|
||||
wsep = " ";
|
||||
/* FALLTHROUGH */
|
||||
case MODEKEYEDIT_NEXTWORDEND:
|
||||
if (wsep == NULL)
|
||||
wsep = options_get_string(oo, "word-separators");
|
||||
|
||||
/* Find a word. */
|
||||
while (c->prompt_index != size) {
|
||||
c->prompt_index++;
|
||||
if (!strchr(wsep, c->prompt_buffer[c->prompt_index]))
|
||||
break;
|
||||
}
|
||||
|
||||
/* Find the separator at the end of the word. */
|
||||
while (c->prompt_index != size) {
|
||||
c->prompt_index++;
|
||||
if (strchr(wsep, c->prompt_buffer[c->prompt_index]))
|
||||
break;
|
||||
}
|
||||
|
||||
c->flags |= CLIENT_STATUS;
|
||||
break;
|
||||
case MODEKEYEDIT_PREVIOUSSPACE:
|
||||
wsep = " ";
|
||||
/* FALLTHROUGH */
|
||||
case MODEKEYEDIT_PREVIOUSWORD:
|
||||
if (wsep == NULL)
|
||||
wsep = options_get_string(oo, "word-separators");
|
||||
|
||||
/* Find a non-separator. */
|
||||
while (c->prompt_index != 0) {
|
||||
c->prompt_index--;
|
||||
if (!strchr(wsep, c->prompt_buffer[c->prompt_index]))
|
||||
break;
|
||||
}
|
||||
|
||||
/* Find the separator at the beginning of the word. */
|
||||
while (c->prompt_index != 0) {
|
||||
c->prompt_index--;
|
||||
if (strchr(wsep, c->prompt_buffer[c->prompt_index])) {
|
||||
/* Go back to the word. */
|
||||
c->prompt_index++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
c->flags |= CLIENT_STATUS;
|
||||
break;
|
||||
case MODEKEYEDIT_HISTORYUP:
|
||||
histstr = status_prompt_up_history(&c->prompt_hindex);
|
||||
if (histstr == NULL)
|
||||
break;
|
||||
xfree(c->prompt_buffer);
|
||||
xfree(c->prompt_buffer);
|
||||
c->prompt_buffer = xstrdup(histstr);
|
||||
c->prompt_index = strlen(c->prompt_buffer);
|
||||
c->flags |= CLIENT_STATUS;
|
||||
|
||||
419
tmux.1
419
tmux.1
@@ -14,7 +14,7 @@
|
||||
.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
.\"
|
||||
.Dd $Mdocdate: July 8 2011 $
|
||||
.Dd $Mdocdate: December 4 2011 $
|
||||
.Dt TMUX 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -495,7 +495,8 @@ $ tmux bind-key F1 set-window-option force-width 81
|
||||
Multiple commands may be specified together as part of a
|
||||
.Em command sequence .
|
||||
Each command should be separated by spaces and a semicolon;
|
||||
commands are executed sequentially from left to right.
|
||||
commands are executed sequentially from left to right and
|
||||
lines ending with a backslash continue on to the next line.
|
||||
A literal semicolon may be included by escaping it with a backslash (for
|
||||
example, when specifying a command sequence to
|
||||
.Ic bind-key ) .
|
||||
@@ -511,6 +512,9 @@ rename-session -tfirst newname
|
||||
set-window-option -t:0 monitor-activity on
|
||||
|
||||
new-window ; split-window -d
|
||||
|
||||
bind-key R source-file ~/.tmux.conf \e; \e
|
||||
display-message "source-file done"
|
||||
.Ed
|
||||
.Pp
|
||||
Or from
|
||||
@@ -562,7 +566,9 @@ is specified, any other clients attached to the session are detached.
|
||||
.Fl r
|
||||
signifies the client is read-only (only keys bound to the
|
||||
.Ic detach-client
|
||||
command have any effect)
|
||||
or
|
||||
.Ic switch-client
|
||||
commands have any effect)
|
||||
.Pp
|
||||
If no server is started,
|
||||
.Ic attach-session
|
||||
@@ -587,7 +593,7 @@ session.
|
||||
.D1 (alias: Ic detach )
|
||||
Detach the current client if bound to a key, the client specified with
|
||||
.Fl t ,
|
||||
or all clients currently attached to to the session specified by
|
||||
or all clients currently attached to the session specified by
|
||||
.Fl s .
|
||||
If
|
||||
.Fl P
|
||||
@@ -604,9 +610,17 @@ server and clients and destroy all sessions.
|
||||
.It Ic kill-session Op Fl t Ar target-session
|
||||
Destroy the given session, closing any windows linked to it and no other
|
||||
sessions, and detaching all clients attached to it.
|
||||
.It Ic list-clients Op Fl t Ar target-session
|
||||
.It Xo Ic list-clients
|
||||
.Op Fl F Ar format
|
||||
.Op Fl t Ar target-session
|
||||
.Xc
|
||||
.D1 (alias: Ic lsc )
|
||||
List all clients attached to the server.
|
||||
For the meaning of the
|
||||
.Fl F
|
||||
flag, see the
|
||||
.Sx FORMATS
|
||||
section.
|
||||
If
|
||||
.Ar target-session
|
||||
is specified, list only clients connected to that session.
|
||||
@@ -614,9 +628,14 @@ is specified, list only clients connected to that session.
|
||||
.D1 (alias: Ic lscm )
|
||||
List the syntax of all commands supported by
|
||||
.Nm .
|
||||
.It Ic list-sessions
|
||||
.It Ic list-sessions Op Fl F Ar format
|
||||
.D1 (alias: Ic ls )
|
||||
List all sessions managed by the server.
|
||||
For the meaning of the
|
||||
.Fl F
|
||||
flag, see the
|
||||
.Sx FORMATS
|
||||
section.
|
||||
.It Ic lock-client Op Fl t Ar target-client
|
||||
.D1 (alias: Ic lockc )
|
||||
Lock
|
||||
@@ -679,11 +698,17 @@ or
|
||||
are invalid if
|
||||
.Fl t
|
||||
is used.
|
||||
.It Ic refresh-client Op Fl t Ar target-client
|
||||
.It Xo Ic refresh-client
|
||||
.Op Fl S
|
||||
.Op Fl t Ar target-client
|
||||
.Xc
|
||||
.D1 (alias: Ic refresh )
|
||||
Refresh the current client if bound to a key, or a single client if one is given
|
||||
with
|
||||
.Fl t .
|
||||
If
|
||||
.Fl S
|
||||
is specified, only update the client's status bar.
|
||||
.It Xo Ic rename-session
|
||||
.Op Fl t Ar target-session
|
||||
.Ar new-name
|
||||
@@ -718,7 +743,7 @@ Suspend a client by sending
|
||||
.Dv SIGTSTP
|
||||
(tty stop).
|
||||
.It Xo Ic switch-client
|
||||
.Op Fl lnp
|
||||
.Op Fl lnpr
|
||||
.Op Fl c Ar target-client
|
||||
.Op Fl t Ar target-session
|
||||
.Xc
|
||||
@@ -734,6 +759,10 @@ or
|
||||
.Fl p
|
||||
is used, the client is moved to the last, next or previous session
|
||||
respectively.
|
||||
.Fl r
|
||||
toggles whether a client is read-only (see the
|
||||
.Ic attach-session
|
||||
command).
|
||||
.El
|
||||
.Sh WINDOWS AND PANES
|
||||
A
|
||||
@@ -778,7 +807,9 @@ The following keys are supported as appropriate for the mode:
|
||||
.It Li "Half page down" Ta "C-d" Ta "M-Down"
|
||||
.It Li "Half page up" Ta "C-u" Ta "M-Up"
|
||||
.It Li "Jump forward" Ta "f" Ta "f"
|
||||
.It Li "Jump to forward" Ta "t" Ta ""
|
||||
.It Li "Jump backward" Ta "F" Ta "F"
|
||||
.It Li "Jump to backward" Ta "T" Ta ""
|
||||
.It Li "Jump again" Ta ";" Ta ";"
|
||||
.It Li "Jump again in reverse" Ta "," Ta ","
|
||||
.It Li "Next page" Ta "C-f" Ta "Page down"
|
||||
@@ -812,7 +843,7 @@ and
|
||||
characters as word delimiters by default, but this can be adjusted by
|
||||
setting the
|
||||
.Em word-separators
|
||||
window option.
|
||||
session option.
|
||||
Next word moves to the start of the next word, next word end to the end of the
|
||||
next word and previous word to the start of the previous word.
|
||||
The three next and previous space keys work similarly but use a space alone as
|
||||
@@ -839,6 +870,9 @@ in emacs mode, and
|
||||
.Ql 10w
|
||||
in vi.
|
||||
.Pp
|
||||
When copying the selection, the repeat count indicates the buffer index to
|
||||
replace, if used.
|
||||
.Pp
|
||||
Mode key bindings are defined in a set of named tables:
|
||||
.Em vi-edit
|
||||
and
|
||||
@@ -1141,6 +1175,7 @@ If
|
||||
is given, the newly linked window is not selected.
|
||||
.It Xo Ic list-panes
|
||||
.Op Fl as
|
||||
.Op Fl F Ar format
|
||||
.Op Fl t Ar target
|
||||
.Xc
|
||||
.D1 (alias: Ic lsp )
|
||||
@@ -1157,8 +1192,14 @@ is a session (or the current session).
|
||||
If neither is given,
|
||||
.Ar target
|
||||
is a window (or the current window).
|
||||
For the meaning of the
|
||||
.Fl F
|
||||
flag, see the
|
||||
.Sx FORMATS
|
||||
section.
|
||||
.It Xo Ic list-windows
|
||||
.Op Fl a
|
||||
.Op Fl F Ar format
|
||||
.Op Fl t Ar target-session
|
||||
.Xc
|
||||
.D1 (alias: Ic lsw )
|
||||
@@ -1167,6 +1208,11 @@ If
|
||||
is given, list all windows on the server.
|
||||
Otherwise, list windows in the current session or in
|
||||
.Ar target-session .
|
||||
For the meaning of the
|
||||
.Fl F
|
||||
flag, see the
|
||||
.Sx FORMATS
|
||||
section.
|
||||
.It Xo Ic move-window
|
||||
.Op Fl dk
|
||||
.Op Fl s Ar src-window
|
||||
@@ -1511,10 +1557,8 @@ to
|
||||
.Em Home ,
|
||||
.Em IC
|
||||
(Insert),
|
||||
.Em NPage
|
||||
(Page Up),
|
||||
.Em PPage
|
||||
(Page Down),
|
||||
.Em NPage/PageDown/PgDn ,
|
||||
.Em PPage/PageUp/PgUp ,
|
||||
.Em Space ,
|
||||
and
|
||||
.Em Tab .
|
||||
@@ -1594,6 +1638,7 @@ are listed; this may be one of:
|
||||
or
|
||||
.Em emacs-copy .
|
||||
.It Xo Ic send-keys
|
||||
.Fl R
|
||||
.Op Fl t Ar target-pane
|
||||
.Ar key Ar ...
|
||||
.Xc
|
||||
@@ -1608,9 +1653,16 @@ or
|
||||
) to send; if the string is not recognised as a key, it is sent as a series of
|
||||
characters.
|
||||
All arguments are sent sequentially from first to last.
|
||||
.It Ic send-prefix Op Fl t Ar target-pane
|
||||
Send the prefix key to a window as if it was pressed.
|
||||
If multiple prefix keys are configured, only the first is sent.
|
||||
The
|
||||
.Fl R
|
||||
flag causes the terminal state to be reset.
|
||||
.It Xo Ic send-prefix
|
||||
.Op Fl 2
|
||||
.Op Fl t Ar target-pane
|
||||
.Xc
|
||||
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 acn
|
||||
.Op Fl t Ar key-table
|
||||
@@ -1726,6 +1778,22 @@ Available server options are:
|
||||
Set the number of buffers; as new buffers are added to the top of the stack,
|
||||
old ones are removed from the bottom if necessary to maintain this maximum
|
||||
length.
|
||||
.It Ic escape-time Ar time
|
||||
Set the time in milliseconds for which
|
||||
.Nm
|
||||
waits after an escape is input to determine if it is part of a function or meta
|
||||
key sequences.
|
||||
The default is 500 milliseconds.
|
||||
.It Xo Ic exit-unattached
|
||||
.Op Ic on | off
|
||||
.Xc
|
||||
If enabled, the server will exit when there are no attached clients.
|
||||
.It Xo Ic quiet
|
||||
.Op Ic on | off
|
||||
.Xc
|
||||
Enable or disable the display of various informational messages (see also the
|
||||
.Fl q
|
||||
command line flag).
|
||||
.It Xo Ic set-clipboard
|
||||
.Op Ic on | off
|
||||
.Xc
|
||||
@@ -1748,22 +1816,6 @@ disallowedWindowOps: 20,21,SetXprop
|
||||
Or changing this property from the
|
||||
.Xr xterm 1
|
||||
interactive menu when required.
|
||||
.It Ic escape-time Ar time
|
||||
Set the time in milliseconds for which
|
||||
.Nm
|
||||
waits after an escape is input to determine if it is part of a function or meta
|
||||
key sequences.
|
||||
The default is 500 milliseconds.
|
||||
.It Xo Ic exit-unattached
|
||||
.Op Ic on | off
|
||||
.Xc
|
||||
If enabled, the server will exit when there are no attached clients.
|
||||
.It Xo Ic quiet
|
||||
.Op Ic on | off
|
||||
.Xc
|
||||
Enable or disable the display of various informational messages (see also the
|
||||
.Fl q
|
||||
command line flag).
|
||||
.El
|
||||
.Pp
|
||||
Available session options are:
|
||||
@@ -1801,10 +1853,20 @@ to create a login shell using the value of the
|
||||
.Ic default-shell
|
||||
option.
|
||||
.It Ic default-path Ar path
|
||||
Set the default working directory for processes created from keys, or
|
||||
interactively from the prompt.
|
||||
The default is empty, which means to use the working directory of the shell
|
||||
from which the server was started if it is available or the user's home if not.
|
||||
Set the default working directory for new panes.
|
||||
If empty (the default), the working directory is determined from the process
|
||||
running in the active pane, from the command line environment or from the
|
||||
working directory where the session was created.
|
||||
If
|
||||
.Ar path
|
||||
is "$HOME" or "~", the value of the
|
||||
.Ev HOME
|
||||
environment variable is used.
|
||||
If
|
||||
.Ar path
|
||||
is ".", the working directory when
|
||||
.Nm
|
||||
was started is used.
|
||||
.It Ic default-shell Ar path
|
||||
Specify the default shell.
|
||||
This is used as the login shell for new windows when the
|
||||
@@ -1922,6 +1984,10 @@ is one of:
|
||||
.Ic magenta ,
|
||||
.Ic cyan ,
|
||||
.Ic white ,
|
||||
aixterm bright variants (if supported:
|
||||
.Ic brightred ,
|
||||
.Ic brightgreen ,
|
||||
and so on),
|
||||
.Ic colour0
|
||||
to
|
||||
.Ic colour255
|
||||
@@ -1930,6 +1996,12 @@ from the 256-colour set,
|
||||
or a hexadecimal RGB string such as
|
||||
.Ql #ffffff ,
|
||||
which chooses the closest match from the default 256-colour set.
|
||||
.It Ic message-command-attr Ar attributes
|
||||
Set status line message attributes when in command mode.
|
||||
.It Ic message-command-bg Ar colour
|
||||
Set status line message background colour when in command mode.
|
||||
.It Ic message-command-fg Ar colour
|
||||
Set status line message foreground colour when in command mode.
|
||||
.It Ic message-fg Ar colour
|
||||
Set status line message foreground colour.
|
||||
.It Ic message-limit Ar number
|
||||
@@ -1955,17 +2027,20 @@ The mouse click is also passed through to the application as normal.
|
||||
.Xc
|
||||
If on, clicking the mouse on a window name in the status line will select that
|
||||
window.
|
||||
.It Xo Ic mouse-utf8
|
||||
.Op Ic on | off
|
||||
.Xc
|
||||
If enabled, request mouse input as UTF-8 on UTF-8 terminals.
|
||||
.It Ic pane-active-border-bg Ar colour
|
||||
.It Ic pane-active-border-fg Ar colour
|
||||
Set the pane border colour for the currently active pane.
|
||||
.It Ic pane-border-bg Ar colour
|
||||
.It Ic pane-border-fg Ar colour
|
||||
Set the pane border colour for panes aside from the active pane.
|
||||
.It Ic prefix Ar keys
|
||||
Set the keys accepted as a prefix key.
|
||||
.Ar keys
|
||||
is a comma-separated list of key names, each of which individually behave as
|
||||
the prefix key.
|
||||
.It Ic prefix Ar key
|
||||
Set the key accepted as a prefix key.
|
||||
.It Ic prefix2 Ar key
|
||||
Set a secondary key accepted as a prefix key.
|
||||
.It Ic repeat-time Ar time
|
||||
Allow multiple commands to be entered without pressing the prefix-key again
|
||||
in the specified
|
||||
@@ -1978,10 +2053,6 @@ flag to
|
||||
Repeat is enabled for the default keys bound to the
|
||||
.Ic resize-pane
|
||||
command.
|
||||
.It Xo Ic mouse-utf8
|
||||
.Op Ic on | off
|
||||
.Xc
|
||||
If enabled, request mouse input as UTF-8 on UTF-8 terminals.
|
||||
.It Xo Ic set-remain-on-exit
|
||||
.Op Ic on | off
|
||||
.Xc
|
||||
@@ -1998,7 +2069,14 @@ command to destroy it.
|
||||
.It Xo Ic set-titles
|
||||
.Op Ic on | off
|
||||
.Xc
|
||||
Attempt to set the window title using the \ee]2;...\e007 xterm code if
|
||||
Attempt to set the client terminal title using the
|
||||
.Em tsl
|
||||
and
|
||||
.Em fsl
|
||||
.Xr terminfo 5
|
||||
entries if they exist.
|
||||
.Nm
|
||||
automatically sets these to the \ee]2;...\e007 sequence if
|
||||
the terminal appears to be an xterm.
|
||||
This option is off by default.
|
||||
Note that elinks
|
||||
@@ -2064,7 +2142,7 @@ may contain any of the following special character sequences:
|
||||
.It Li "#I" Ta "Current window index"
|
||||
.It Li "#P" Ta "Current pane index"
|
||||
.It Li "#S" Ta "Session name"
|
||||
.It Li "#T" Ta "Current window title"
|
||||
.It Li "#T" Ta "Current pane title"
|
||||
.It Li "#W" Ta "Current window name"
|
||||
.It Li "##" Ta "A literal" Ql #
|
||||
.El
|
||||
@@ -2083,13 +2161,9 @@ global environment set (see the
|
||||
.Sx ENVIRONMENT
|
||||
section).
|
||||
.Pp
|
||||
The window title (#T) is the title set by the program running within the window
|
||||
using the OSC title setting sequence, for example:
|
||||
.Bd -literal -offset indent
|
||||
$ printf '\e033]2;My Title\e033\e\e'
|
||||
.Ed
|
||||
.Pp
|
||||
When a window is first created, its title is the hostname.
|
||||
For details on how the names and titles can be set see the
|
||||
.Sx "NAMES AND TITLES"
|
||||
section.
|
||||
.Pp
|
||||
#[attributes] allows a comma-separated list of attributes to be specified,
|
||||
these may be
|
||||
@@ -2244,6 +2318,12 @@ window option is enabled.
|
||||
If
|
||||
.Ic monitor-silence
|
||||
is enabled, prints a message after the interval has expired on a given window.
|
||||
.It Ic word-separators Ar string
|
||||
Sets the session's conception of what characters are considered word
|
||||
separators, for the purposes of the next and previous word commands in
|
||||
copy mode.
|
||||
The default is
|
||||
.Ql \ -_@ .
|
||||
.El
|
||||
.It Xo Ic set-window-option
|
||||
.Op Fl agu
|
||||
@@ -2277,6 +2357,13 @@ this option is good for full-screen programs which support
|
||||
.Dv SIGWINCH
|
||||
and poor for interactive programs such as shells.
|
||||
.Pp
|
||||
.It Xo Ic allow-rename
|
||||
.Op Ic on | off
|
||||
.Xc
|
||||
Allow programs to change the window name using a terminal escape
|
||||
sequence (\\033k...\\033\\\\).
|
||||
The default is on.
|
||||
.Pp
|
||||
.It Xo Ic alternate-screen
|
||||
.Op Ic on | off
|
||||
.Xc
|
||||
@@ -2307,7 +2394,8 @@ is specified at creation with
|
||||
or
|
||||
.Ic new-session ,
|
||||
or later with
|
||||
.Ic rename-window .
|
||||
.Ic rename-window ,
|
||||
or with a terminal escape sequence.
|
||||
It may be switched off globally with:
|
||||
.Bd -literal -offset indent
|
||||
set-window-option -g automatic-rename off
|
||||
@@ -2362,12 +2450,16 @@ contains
|
||||
.Ql vi .
|
||||
.Pp
|
||||
.It Xo Ic mode-mouse
|
||||
.Op Ic on | off
|
||||
.Op Ic on | off | copy-mode
|
||||
.Xc
|
||||
Mouse state in modes.
|
||||
If on, the mouse may be used to enter copy mode and copy a selection by
|
||||
dragging, to enter copy mode and scroll with the mouse wheel, or to select an
|
||||
option in choice mode.
|
||||
If set to
|
||||
.Em copy-mode ,
|
||||
the mouse behaves as set to on, but cannot be used to enter copy
|
||||
mode.
|
||||
.Pp
|
||||
.It Xo Ic monitor-activity
|
||||
.Op Ic on | off
|
||||
@@ -2412,6 +2504,11 @@ but set the width of other panes in the
|
||||
.Ic main-vertical
|
||||
layout.
|
||||
.Pp
|
||||
.It Ic pane-base-index Ar index
|
||||
Like
|
||||
.Ic base-index ,
|
||||
but set the starting index for pane numbers.
|
||||
.Pp
|
||||
.It Xo Ic remain-on-exit
|
||||
.Op Ic on | off
|
||||
.Xc
|
||||
@@ -2434,33 +2531,39 @@ Instructs
|
||||
.Nm
|
||||
to expect UTF-8 sequences to appear in this window.
|
||||
.Pp
|
||||
.It Ic window-status-bell-attr Ar attributes
|
||||
Set status line attributes for windows which have a bell alert.
|
||||
.Pp
|
||||
.It Ic window-status-bell-bg Ar colour
|
||||
Set status line background colour for windows with a bell alert.
|
||||
.Pp
|
||||
.It Ic window-status-bell-fg Ar colour
|
||||
Set status line foreground colour for windows with a bell alert.
|
||||
.Pp
|
||||
.It Ic window-status-content-attr Ar attributes
|
||||
Set status line attributes for windows which have a content alert.
|
||||
.Pp
|
||||
.It Ic window-status-content-bg Ar colour
|
||||
Set status line background colour for windows with a content alert.
|
||||
.Pp
|
||||
.It Ic window-status-content-fg Ar colour
|
||||
Set status line foreground colour for windows with a content alert.
|
||||
.Pp
|
||||
.It Ic window-status-activity-attr Ar attributes
|
||||
Set status line attributes for windows which have an activity (or silence) alert.
|
||||
.Pp
|
||||
.It Ic window-status-activity-bg Ar colour
|
||||
Set status line background colour for windows with an activity alert.
|
||||
.Pp
|
||||
.It Ic window-status-activity-fg Ar colour
|
||||
Set status line foreground colour for windows with an activity alert.
|
||||
.Pp
|
||||
.It Ic window-status-attr Ar attributes
|
||||
Set status line attributes for a single window.
|
||||
.Pp
|
||||
.It Ic window-status-bg Ar colour
|
||||
Set status line background colour for a single window.
|
||||
.Pp
|
||||
.It Ic window-status-fg Ar colour
|
||||
Set status line foreground colour for a single window.
|
||||
.Pp
|
||||
.It Ic window-status-format Ar string
|
||||
Set the format in which the window is displayed in the status line window list.
|
||||
See the
|
||||
.Ar status-left
|
||||
option for details of special character sequences available.
|
||||
The default is
|
||||
.Ql #I:#W#F .
|
||||
.Pp
|
||||
.It Ic window-status-alert-attr Ar attributes
|
||||
Set status line attributes for windows which have an alert (bell, activity
|
||||
or content).
|
||||
.Pp
|
||||
.It Ic window-status-alert-bg Ar colour
|
||||
Set status line background colour for windows with an alert.
|
||||
.Pp
|
||||
.It Ic window-status-alert-fg Ar colour
|
||||
Set status line foreground colour for windows with an alert.
|
||||
.Pp
|
||||
.It Ic window-status-current-attr Ar attributes
|
||||
Set status line attributes for the currently active window.
|
||||
.Pp
|
||||
@@ -2475,12 +2578,16 @@ Like
|
||||
.Ar window-status-format ,
|
||||
but is the format used when the window is the current window.
|
||||
.Pp
|
||||
.It Ic word-separators Ar string
|
||||
Sets the window's conception of what characters are considered word
|
||||
separators, for the purposes of the next and previous word commands in
|
||||
copy mode.
|
||||
.It Ic window-status-fg Ar colour
|
||||
Set status line foreground colour for a single window.
|
||||
.Pp
|
||||
.It Ic window-status-format Ar string
|
||||
Set the format in which the window is displayed in the status line window list.
|
||||
See the
|
||||
.Ar status-left
|
||||
option for details of special character sequences available.
|
||||
The default is
|
||||
.Ql \ -_@ .
|
||||
.Ql #I:#W#F .
|
||||
.Pp
|
||||
.It Xo Ic xterm-keys
|
||||
.Op Ic on | off
|
||||
@@ -2520,6 +2627,142 @@ or the global window options if
|
||||
.Fl g
|
||||
is used.
|
||||
.El
|
||||
.Sh FORMATS
|
||||
The
|
||||
.Ic list-clients ,
|
||||
.Ic list-sessions ,
|
||||
.Ic list-windows
|
||||
and
|
||||
.Ic list-panes
|
||||
commands accept the
|
||||
.Fl F
|
||||
flag with a
|
||||
.Ar format
|
||||
argument.
|
||||
This is a string which controls the output format of the command.
|
||||
Special character sequences are replaced as documented under the
|
||||
.Ic status-left
|
||||
option and an additional long form is accepted.
|
||||
Replacement variables are enclosed in
|
||||
.Ql #{
|
||||
and
|
||||
.Ql } ,
|
||||
for example
|
||||
.Ql #{session_name}
|
||||
is equivalent to
|
||||
.Ql #S .
|
||||
Conditionals are also accepted by prefixing with
|
||||
.Ql \&?
|
||||
and separating two alternatives with a comma;
|
||||
if the specified variable exists and is not zero, the first alternative
|
||||
is chosen, otherwise the second is used.
|
||||
For example
|
||||
.Ql #{?session_attached,attached,not attached}
|
||||
will include the string
|
||||
.Ql attached
|
||||
if the session is attached and the string
|
||||
.Ql not attached
|
||||
if it is unattached.
|
||||
.Pp
|
||||
The following variables are available, where appropriate:
|
||||
.Bl -column "session_created_string" "Replaced with" -offset indent
|
||||
.It Sy "Variable name" Ta Sy "Replaced with"
|
||||
.It Li "client_activity" Ta "Integer time client last had activity"
|
||||
.It Li "client_activity_string" Ta "String time client last had activity"
|
||||
.It Li "client_created" Ta "Integer time client created"
|
||||
.It Li "client_created_string" Ta "String time client created"
|
||||
.It Li "client_cwd" Ta "Working directory of client"
|
||||
.It Li "client_height" Ta "Height of client"
|
||||
.It Li "client_readonly" Ta "1 if client is readonly"
|
||||
.It Li "client_termname" Ta "Terminal name of client"
|
||||
.It Li "client_tty" Ta "Pseudo terminal of client"
|
||||
.It Li "client_utf8" Ta "1 if client supports utf8"
|
||||
.It Li "client_width" Ta "Width of client"
|
||||
.It Li "host" Ta "Hostname of local host"
|
||||
.It Li "line" Ta "Line number in the list"
|
||||
.It Li "pane_active" Ta "1 if active pane"
|
||||
.It Li "pane_dead" Ta "1 if pane is dead"
|
||||
.It Li "pane_height" Ta "Height of pane"
|
||||
.It Li "pane_id" Ta "Unique pane id"
|
||||
.It Li "pane_pid" Ta "PID of first process in pane"
|
||||
.It Li "pane_start_command" Ta "Command pane started with"
|
||||
.It Li "pane_start_path" Ta "Path pane started with"
|
||||
.It Li "pane_title" Ta "Title of pane"
|
||||
.It Li "pane_tty" Ta "Pseudo terminal of pane"
|
||||
.It Li "pane_width" Ta "Width of pane"
|
||||
.It Li "session_attached" Ta "1 if session attached"
|
||||
.It Li "session_created" Ta "Integer time session created"
|
||||
.It Li "session_created_string" Ta "String time session created"
|
||||
.It Li "session_group" Ta "Number of session group"
|
||||
.It Li "session_grouped" Ta "1 if session in a group"
|
||||
.It Li "session_height" Ta "Height of session"
|
||||
.It Li "session_name" Ta "Name of session"
|
||||
.It Li "session_width" Ta "Width of session"
|
||||
.It Li "session_windows" Ta "Number of windows in session"
|
||||
.It Li "window_active" Ta "1 if window active"
|
||||
.It Li "window_flags" Ta "Window flags"
|
||||
.It Li "window_height" Ta "Height of window"
|
||||
.It Li "window_index" Ta "Index of window"
|
||||
.It Li "window_layout" Ta "Window layout description"
|
||||
.It Li "window_name" Ta "Name of window"
|
||||
.It Li "window_width" Ta "Width of window"
|
||||
.El
|
||||
.Sh NAMES AND TITLES
|
||||
.Nm
|
||||
distinguishes between names and titles.
|
||||
Windows and sessions have names, which may be used to specify them in targets
|
||||
and are displayed in the status line and various lists: the name is the
|
||||
.Nm
|
||||
identifier for a window or session.
|
||||
Only panes have titles.
|
||||
A pane's title is typically set by the program running inside the pane and
|
||||
is not modified by
|
||||
.Nm .
|
||||
It is the same mechanism used to set for example the
|
||||
.Xr xterm 1
|
||||
window title in an
|
||||
.Xr X 7
|
||||
window manager.
|
||||
Windows themselves do not have titles - a window's title is the title of its
|
||||
active pane.
|
||||
.Nm
|
||||
itself may set the title of the terminal in which the client is running, see
|
||||
the
|
||||
.Ic set-titles
|
||||
option.
|
||||
.Pp
|
||||
A session's name is set with the
|
||||
.Ic new-session
|
||||
and
|
||||
.Ic rename-session
|
||||
commands.
|
||||
A window's name is set with one of:
|
||||
.Bl -enum -width Ds
|
||||
.It
|
||||
A command argument (such as
|
||||
.Fl n
|
||||
for
|
||||
.Ic new-window
|
||||
or
|
||||
.Ic new-session ) .
|
||||
.It
|
||||
An escape sequence:
|
||||
.Bd -literal -offset indent
|
||||
$ printf '\e033kWINDOW_NAME\e033\e\e'
|
||||
.Ed
|
||||
.It
|
||||
Automatic renaming, which sets the name to the active command in the window's
|
||||
active pane.
|
||||
See the
|
||||
.Ic automatic-rename
|
||||
option.
|
||||
.El
|
||||
.Pp
|
||||
When a pane is first created, its title is the hostname.
|
||||
A pane's title can be set via the OSC title setting sequence, for example:
|
||||
.Bd -literal -offset indent
|
||||
$ printf '\e033]2;My Title\e033\e\e'
|
||||
.Ed
|
||||
.Sh ENVIRONMENT
|
||||
When the server is started,
|
||||
.Nm
|
||||
@@ -2583,8 +2826,8 @@ terminal.
|
||||
By default, the status line is enabled (it may be disabled with the
|
||||
.Ic status
|
||||
session option) and contains, from left-to-right: the name of the current
|
||||
session in square brackets; the window list; the current window title in double
|
||||
quotes; and the time and date.
|
||||
session in square brackets; the window list; the title of the active pane
|
||||
in double quotes; and the time and date.
|
||||
.Pp
|
||||
The status line is made of three parts: configurable left and right sections
|
||||
(which may contain dynamic content such as the time or output from a shell
|
||||
@@ -2846,13 +3089,15 @@ Miscellaneous commands are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Ic clock-mode Op Fl t Ar target-pane
|
||||
Display a large clock.
|
||||
.It Ic if-shell Ar shell-command command
|
||||
.It Ic if-shell Ar shell-command command Op Ar command
|
||||
.D1 (alias: Ic if )
|
||||
Execute
|
||||
Execute the first
|
||||
.Ar command
|
||||
if
|
||||
.Ar shell-command
|
||||
returns success.
|
||||
returns success or the second
|
||||
.Ar command
|
||||
otherwise.
|
||||
.It Ic lock-server
|
||||
.D1 (alias: Ic lock )
|
||||
Lock each client individually by running the command specified by the
|
||||
|
||||
31
tmux.c
31
tmux.c
@@ -101,7 +101,9 @@ getshell(void)
|
||||
int
|
||||
checkshell(const char *shell)
|
||||
{
|
||||
if (shell == NULL || *shell == '\0' || areshell(shell))
|
||||
if (shell == NULL || *shell == '\0' || *shell != '/')
|
||||
return (0);
|
||||
if (areshell(shell))
|
||||
return (0);
|
||||
if (access(shell, X_OK) != 0)
|
||||
return (0);
|
||||
@@ -125,6 +127,22 @@ areshell(const char *shell)
|
||||
return (0);
|
||||
}
|
||||
|
||||
const char*
|
||||
get_full_path(const char *wd, const char *path)
|
||||
{
|
||||
static char newpath[MAXPATHLEN];
|
||||
char oldpath[MAXPATHLEN];
|
||||
|
||||
if (getcwd(oldpath, sizeof oldpath) == NULL)
|
||||
return (NULL);
|
||||
if (chdir(wd) != 0)
|
||||
return (NULL);
|
||||
if (realpath(path, newpath) != 0)
|
||||
return (NULL);
|
||||
chdir(oldpath);
|
||||
return (newpath);
|
||||
}
|
||||
|
||||
void
|
||||
parseenvironment(void)
|
||||
{
|
||||
@@ -217,7 +235,6 @@ int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct passwd *pw;
|
||||
struct keylist *keylist;
|
||||
char *s, *path, *label, *home, **var;
|
||||
int opt, flags, quiet, keys;
|
||||
|
||||
@@ -293,8 +310,8 @@ main(int argc, char **argv)
|
||||
* if not they know that output from UTF-8-capable programs may
|
||||
* be wrong.
|
||||
*/
|
||||
if ((s = getenv("LC_ALL")) == NULL) {
|
||||
if ((s = getenv("LC_CTYPE")) == NULL)
|
||||
if ((s = getenv("LC_ALL")) == NULL || *s == '\0') {
|
||||
if ((s = getenv("LC_CTYPE")) == NULL || *s == '\0')
|
||||
s = getenv("LANG");
|
||||
}
|
||||
if (s != NULL && (strcasestr(s, "UTF-8") != NULL ||
|
||||
@@ -317,12 +334,6 @@ main(int argc, char **argv)
|
||||
options_init(&global_w_options, NULL);
|
||||
options_table_populate_tree(window_options_table, &global_w_options);
|
||||
|
||||
/* Set the prefix option (its a list, so not in the table). */
|
||||
keylist = xmalloc(sizeof *keylist);
|
||||
ARRAY_INIT(keylist);
|
||||
ARRAY_ADD(keylist, '\002');
|
||||
options_set_data(&global_s_options, "prefix", keylist, xfree);
|
||||
|
||||
/* Enable UTF-8 if the first client is on UTF-8 terminal. */
|
||||
if (flags & IDENTIFY_UTF8) {
|
||||
options_set_number(&global_s_options, "status-utf8", 1);
|
||||
|
||||
74
tmux.h
74
tmux.h
@@ -202,6 +202,7 @@ enum tty_code_code {
|
||||
TTYC_DIM, /* enter_dim_mode, mh */
|
||||
TTYC_DL, /* parm_delete_line, DL */
|
||||
TTYC_DL1, /* delete_line, dl */
|
||||
TTYC_E3,
|
||||
TTYC_EL, /* clr_eol, ce */
|
||||
TTYC_EL1, /* clr_bol, cb */
|
||||
TTYC_ENACS, /* ena_acs, eA */
|
||||
@@ -437,11 +438,18 @@ enum mode_key_cmd {
|
||||
MODEKEYEDIT_DELETE,
|
||||
MODEKEYEDIT_DELETELINE,
|
||||
MODEKEYEDIT_DELETETOENDOFLINE,
|
||||
MODEKEYEDIT_DELETEWORD,
|
||||
MODEKEYEDIT_ENDOFLINE,
|
||||
MODEKEYEDIT_ENTER,
|
||||
MODEKEYEDIT_HISTORYDOWN,
|
||||
MODEKEYEDIT_HISTORYUP,
|
||||
MODEKEYEDIT_NEXTSPACE,
|
||||
MODEKEYEDIT_NEXTSPACEEND,
|
||||
MODEKEYEDIT_NEXTWORD,
|
||||
MODEKEYEDIT_NEXTWORDEND,
|
||||
MODEKEYEDIT_PASTE,
|
||||
MODEKEYEDIT_PREVIOUSSPACE,
|
||||
MODEKEYEDIT_PREVIOUSWORD,
|
||||
MODEKEYEDIT_STARTOFLINE,
|
||||
MODEKEYEDIT_SWITCHMODE,
|
||||
MODEKEYEDIT_SWITCHMODEAPPEND,
|
||||
@@ -476,6 +484,8 @@ enum mode_key_cmd {
|
||||
MODEKEYCOPY_JUMPAGAIN,
|
||||
MODEKEYCOPY_JUMPREVERSE,
|
||||
MODEKEYCOPY_JUMPBACK,
|
||||
MODEKEYCOPY_JUMPTO,
|
||||
MODEKEYCOPY_JUMPTOBACK,
|
||||
MODEKEYCOPY_LEFT,
|
||||
MODEKEYCOPY_MIDDLELINE,
|
||||
MODEKEYCOPY_NEXTPAGE,
|
||||
@@ -531,9 +541,9 @@ struct mode_key_binding {
|
||||
int mode;
|
||||
enum mode_key_cmd cmd;
|
||||
|
||||
SPLAY_ENTRY(mode_key_binding) entry;
|
||||
RB_ENTRY(mode_key_binding) entry;
|
||||
};
|
||||
SPLAY_HEAD(mode_key_tree, mode_key_binding);
|
||||
RB_HEAD(mode_key_tree, mode_key_binding);
|
||||
|
||||
/* Command to string mapping. */
|
||||
struct mode_key_cmdstr {
|
||||
@@ -659,21 +669,15 @@ struct options_entry {
|
||||
|
||||
char *str;
|
||||
long long num;
|
||||
void *data;
|
||||
|
||||
void (*freefn)(void *);
|
||||
|
||||
SPLAY_ENTRY(options_entry) entry;
|
||||
RB_ENTRY(options_entry) entry;
|
||||
};
|
||||
|
||||
struct options {
|
||||
SPLAY_HEAD(options_tree, options_entry) tree;
|
||||
RB_HEAD(options_tree, options_entry) tree;
|
||||
struct options *parent;
|
||||
};
|
||||
|
||||
/* Key list for prefix option. */
|
||||
ARRAY_DECL(keylist, int);
|
||||
|
||||
/* Scheduled job. */
|
||||
struct job {
|
||||
char *cmd;
|
||||
@@ -1160,8 +1164,7 @@ struct client {
|
||||
#define CLIENT_DEAD 0x200
|
||||
#define CLIENT_BORDERS 0x400
|
||||
#define CLIENT_READONLY 0x800
|
||||
#define CLIENT_BACKOFF 0x1000
|
||||
#define CLIENT_REDRAWWINDOW 0x2000
|
||||
#define CLIENT_REDRAWWINDOW 0x1000
|
||||
int flags;
|
||||
|
||||
struct event identify_timer;
|
||||
@@ -1268,9 +1271,9 @@ struct key_binding {
|
||||
struct cmd_list *cmdlist;
|
||||
int can_repeat;
|
||||
|
||||
SPLAY_ENTRY(key_binding) entry;
|
||||
RB_ENTRY(key_binding) entry;
|
||||
};
|
||||
SPLAY_HEAD(key_bindings, key_binding);
|
||||
RB_HEAD(key_bindings, key_binding);
|
||||
|
||||
/*
|
||||
* Option table entries. The option table is the user-visible part of the
|
||||
@@ -1280,7 +1283,7 @@ SPLAY_HEAD(key_bindings, key_binding);
|
||||
enum options_table_type {
|
||||
OPTIONS_TABLE_STRING,
|
||||
OPTIONS_TABLE_NUMBER,
|
||||
OPTIONS_TABLE_KEYS,
|
||||
OPTIONS_TABLE_KEY,
|
||||
OPTIONS_TABLE_COLOUR,
|
||||
OPTIONS_TABLE_ATTRIBUTES,
|
||||
OPTIONS_TABLE_FLAG,
|
||||
@@ -1299,6 +1302,15 @@ struct options_table_entry {
|
||||
long long default_num;
|
||||
};
|
||||
|
||||
/* Tree of format entries. */
|
||||
struct format_entry {
|
||||
char *key;
|
||||
char *value;
|
||||
|
||||
RB_ENTRY(format_entry) entry;
|
||||
};
|
||||
RB_HEAD(format_tree, format_entry);
|
||||
|
||||
/* List of configuration causes. */
|
||||
ARRAY_DECL(causelist, char *);
|
||||
|
||||
@@ -1332,6 +1344,7 @@ void logfile(const char *);
|
||||
const char *getshell(void);
|
||||
int checkshell(const char *);
|
||||
int areshell(const char *);
|
||||
const char* get_full_path(const char *, const char *);
|
||||
void setblocking(int, int);
|
||||
__dead void shell_exec(const char *, const char *);
|
||||
|
||||
@@ -1341,6 +1354,21 @@ extern struct causelist cfg_causes;
|
||||
void printflike2 cfg_add_cause(struct causelist *, const char *, ...);
|
||||
int load_cfg(const char *, struct cmd_ctx *, struct causelist *);
|
||||
|
||||
/* format.c */
|
||||
int format_cmp(struct format_entry *, struct format_entry *);
|
||||
RB_PROTOTYPE(format_tree, format_entry, entry, format_cmp);
|
||||
struct format_tree *format_create(void);
|
||||
void format_free(struct format_tree *);
|
||||
void format_add(
|
||||
struct format_tree *, const char *, const char *, ...);
|
||||
const char *format_find(struct format_tree *, const char *);
|
||||
char *format_expand(struct format_tree *, const char *);
|
||||
void format_session(struct format_tree *, struct session *);
|
||||
void format_client(struct format_tree *, struct client *);
|
||||
void format_winlink(
|
||||
struct format_tree *, struct session *, struct winlink *);
|
||||
void format_window_pane(struct format_tree *, struct window_pane *);
|
||||
|
||||
/* mode-key.c */
|
||||
extern const struct mode_key_table mode_key_tables[];
|
||||
extern struct mode_key_tree mode_key_tree_vi_edit;
|
||||
@@ -1350,7 +1378,7 @@ extern struct mode_key_tree mode_key_tree_emacs_edit;
|
||||
extern struct mode_key_tree mode_key_tree_emacs_choice;
|
||||
extern struct mode_key_tree mode_key_tree_emacs_copy;
|
||||
int mode_key_cmp(struct mode_key_binding *, struct mode_key_binding *);
|
||||
SPLAY_PROTOTYPE(mode_key_tree, mode_key_binding, entry, mode_key_cmp);
|
||||
RB_PROTOTYPE(mode_key_tree, mode_key_binding, entry, mode_key_cmp);
|
||||
const char *mode_key_tostring(const struct mode_key_cmdstr *,
|
||||
enum mode_key_cmd);
|
||||
enum mode_key_cmd mode_key_fromstring(const struct mode_key_cmdstr *,
|
||||
@@ -1362,7 +1390,7 @@ enum mode_key_cmd mode_key_lookup(struct mode_key_data *, int);
|
||||
|
||||
/* options.c */
|
||||
int options_cmp(struct options_entry *, struct options_entry *);
|
||||
SPLAY_PROTOTYPE(options_tree, options_entry, entry, options_cmp);
|
||||
RB_PROTOTYPE(options_tree, options_entry, entry, options_cmp);
|
||||
void options_init(struct options *, struct options *);
|
||||
void options_free(struct options *);
|
||||
struct options_entry *options_find1(struct options *, const char *);
|
||||
@@ -1374,9 +1402,6 @@ char *options_get_string(struct options *, const char *);
|
||||
struct options_entry *options_set_number(
|
||||
struct options *, const char *, long long);
|
||||
long long options_get_number(struct options *, const char *);
|
||||
struct options_entry *options_set_data(
|
||||
struct options *, const char *, void *, void (*)(void *));
|
||||
void *options_get_data(struct options *, const char *);
|
||||
|
||||
/* options-table.c */
|
||||
extern const struct options_table_entry server_options_table[];
|
||||
@@ -1454,6 +1479,7 @@ void tty_cmd_utf8character(struct tty *, const struct tty_ctx *);
|
||||
void tty_cmd_reverseindex(struct tty *, const struct tty_ctx *);
|
||||
void tty_cmd_setselection(struct tty *, const struct tty_ctx *);
|
||||
void tty_cmd_rawstring(struct tty *, const struct tty_ctx *);
|
||||
void tty_bell(struct tty *);
|
||||
|
||||
/* tty-term.c */
|
||||
extern struct tty_terms tty_terms;
|
||||
@@ -1525,6 +1551,7 @@ int cmd_find_index(
|
||||
struct winlink *cmd_find_pane(struct cmd_ctx *,
|
||||
const char *, struct session **, struct window_pane **);
|
||||
char *cmd_template_replace(char *, const char *, int);
|
||||
const char *cmd_get_default_path(struct cmd_ctx *ctx);
|
||||
extern const struct cmd_entry *cmd_table[];
|
||||
extern const struct cmd_entry cmd_attach_session_entry;
|
||||
extern const struct cmd_entry cmd_bind_key_entry;
|
||||
@@ -1625,7 +1652,7 @@ int client_main(int, char **, int);
|
||||
/* key-bindings.c */
|
||||
extern struct key_bindings key_bindings;
|
||||
int key_bindings_cmp(struct key_binding *, struct key_binding *);
|
||||
SPLAY_PROTOTYPE(key_bindings, key_binding, entry, key_bindings_cmp);
|
||||
RB_PROTOTYPE(key_bindings, key_binding, entry, key_bindings_cmp);
|
||||
struct key_binding *key_bindings_lookup(int);
|
||||
void key_bindings_add(int, int, struct cmd_list *);
|
||||
void key_bindings_remove(int);
|
||||
@@ -1791,6 +1818,7 @@ char *grid_view_string_cells(struct grid *, u_int, u_int, u_int);
|
||||
void screen_write_start(
|
||||
struct screen_write_ctx *, struct window_pane *, struct screen *);
|
||||
void screen_write_stop(struct screen_write_ctx *);
|
||||
void screen_write_reset(struct screen_write_ctx *);
|
||||
size_t printflike2 screen_write_cstrlen(int, const char *, ...);
|
||||
void printflike5 screen_write_cnputs(struct screen_write_ctx *,
|
||||
ssize_t, struct grid_cell *, int, const char *, ...);
|
||||
@@ -1836,6 +1864,7 @@ void screen_write_kkeypadmode(struct screen_write_ctx *, int);
|
||||
void screen_write_clearendofscreen(struct screen_write_ctx *);
|
||||
void screen_write_clearstartofscreen(struct screen_write_ctx *);
|
||||
void screen_write_clearscreen(struct screen_write_ctx *);
|
||||
void screen_write_clearhistory(struct screen_write_ctx *);
|
||||
void screen_write_cell(struct screen_write_ctx *,
|
||||
const struct grid_cell *, const struct utf8_data *);
|
||||
void screen_write_setselection(struct screen_write_ctx *, u_char *, u_int);
|
||||
@@ -1899,7 +1928,7 @@ struct window_pane *window_pane_next_by_number(struct window *,
|
||||
struct window_pane *, u_int);
|
||||
struct window_pane *window_pane_previous_by_number(struct window *,
|
||||
struct window_pane *, u_int);
|
||||
u_int window_pane_index(struct window *, struct window_pane *);
|
||||
int window_pane_index(struct window_pane *, u_int *);
|
||||
u_int window_count_panes(struct window *);
|
||||
void window_destroy_panes(struct window *);
|
||||
struct window_pane *window_pane_find_by_id(u_int);
|
||||
@@ -2041,6 +2070,7 @@ u_int utf8_split2(u_int, u_char *);
|
||||
|
||||
/* osdep-*.c */
|
||||
char *osdep_get_name(int, char *);
|
||||
char *osdep_get_cwd(pid_t);
|
||||
struct event_base *osdep_event_init(void);
|
||||
|
||||
/* log.c */
|
||||
|
||||
@@ -64,6 +64,7 @@ const struct tty_term_code_entry tty_term_codes[NTTYCODE] = {
|
||||
{ TTYC_DIM, TTYCODE_STRING, "dim" },
|
||||
{ TTYC_DL, TTYCODE_STRING, "dl" },
|
||||
{ TTYC_DL1, TTYCODE_STRING, "dl1" },
|
||||
{ TTYC_E3, TTYCODE_STRING, "E3" },
|
||||
{ TTYC_EL, TTYCODE_STRING, "el" },
|
||||
{ TTYC_EL1, TTYCODE_STRING, "el1" },
|
||||
{ TTYC_ENACS, TTYCODE_STRING, "enacs" },
|
||||
@@ -265,6 +266,8 @@ tty_term_override(struct tty_term *term, const char *overrides)
|
||||
} else
|
||||
val = xstrdup("");
|
||||
|
||||
log_debug("%s override: %s %s",
|
||||
term->name, entstr, removeflag ? "@" : val);
|
||||
for (i = 0; i < NTTYCODE; i++) {
|
||||
ent = &tty_term_codes[i];
|
||||
if (strcmp(entstr, ent->name) != 0)
|
||||
|
||||
19
tty.c
19
tty.c
@@ -969,7 +969,10 @@ tty_cmd_cell(struct tty *tty, const struct tty_ctx *ctx)
|
||||
* move as far left as possible and redraw the last
|
||||
* cell to move into the last position.
|
||||
*/
|
||||
cx = screen_size_x(s) - width;
|
||||
if (ctx->last_cell.flags & GRID_FLAG_UTF8)
|
||||
cx = screen_size_x(s) - ctx->last_utf8.width;
|
||||
else
|
||||
cx = screen_size_x(s) - 1;
|
||||
tty_cursor_pane(tty, ctx, cx, ctx->ocy);
|
||||
tty_cell(tty, &ctx->last_cell, &ctx->last_utf8);
|
||||
}
|
||||
@@ -1437,7 +1440,7 @@ tty_check_bg(struct tty *tty, struct grid_cell *gc)
|
||||
|
||||
/* Is this an aixterm colour? */
|
||||
colours = tty_term_number(tty->term, TTYC_COLORS);
|
||||
if (gc->bg >= 100 && gc->bg <= 107 && colours < 16) {
|
||||
if (gc->bg >= 90 && gc->bg <= 97 && colours < 16) {
|
||||
gc->bg -= 90;
|
||||
gc->attr |= GRID_ATTR_BRIGHT;
|
||||
}
|
||||
@@ -1497,14 +1500,14 @@ tty_colours_bg(struct tty *tty, const struct grid_cell *gc)
|
||||
}
|
||||
|
||||
/* Is this an aixterm bright colour? */
|
||||
if (bg >= 100 && bg <= 107) {
|
||||
if (bg >= 90 && bg <= 97) {
|
||||
/* 16 colour terminals or above only. */
|
||||
if (tty_term_number(tty->term, TTYC_COLORS) >= 16) {
|
||||
xsnprintf(s, sizeof s, "\033[%dm", bg);
|
||||
xsnprintf(s, sizeof s, "\033[%dm", bg + 10);
|
||||
tty_puts(tty, s);
|
||||
goto save_bg;
|
||||
}
|
||||
bg -= 100;
|
||||
bg -= 90;
|
||||
/* no such thing as a bold background */
|
||||
}
|
||||
|
||||
@@ -1546,3 +1549,9 @@ tty_try_88(struct tty *tty, u_char colour, const char *type)
|
||||
tty_puts(tty, s);
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
tty_bell(struct tty *tty)
|
||||
{
|
||||
tty_putcode(tty, TTYC_BEL);
|
||||
}
|
||||
|
||||
149
window-copy.c
149
window-copy.c
@@ -52,7 +52,7 @@ void window_copy_goto_line(struct window_pane *, const char *);
|
||||
void window_copy_update_cursor(struct window_pane *, u_int, u_int);
|
||||
void window_copy_start_selection(struct window_pane *);
|
||||
int window_copy_update_selection(struct window_pane *);
|
||||
void window_copy_copy_selection(struct window_pane *);
|
||||
void window_copy_copy_selection(struct window_pane *, int);
|
||||
void window_copy_clear_selection(struct window_pane *);
|
||||
void window_copy_copy_line(
|
||||
struct window_pane *, char **, size_t *, u_int, u_int, u_int);
|
||||
@@ -67,6 +67,8 @@ void window_copy_cursor_up(struct window_pane *, int);
|
||||
void window_copy_cursor_down(struct window_pane *, int);
|
||||
void window_copy_cursor_jump(struct window_pane *);
|
||||
void window_copy_cursor_jump_back(struct window_pane *);
|
||||
void window_copy_cursor_jump_to(struct window_pane *);
|
||||
void window_copy_cursor_jump_to_back(struct window_pane *);
|
||||
void window_copy_cursor_next_word(struct window_pane *, const char *);
|
||||
void window_copy_cursor_next_word_end(struct window_pane *, const char *);
|
||||
void window_copy_cursor_previous_word(struct window_pane *, const char *);
|
||||
@@ -90,6 +92,8 @@ enum window_copy_input_type {
|
||||
WINDOW_COPY_SEARCHDOWN,
|
||||
WINDOW_COPY_JUMPFORWARD,
|
||||
WINDOW_COPY_JUMPBACK,
|
||||
WINDOW_COPY_JUMPTOFORWARD,
|
||||
WINDOW_COPY_JUMPTOBACK,
|
||||
WINDOW_COPY_GOTOLINE,
|
||||
};
|
||||
|
||||
@@ -132,9 +136,9 @@ struct window_copy_mode_data {
|
||||
|
||||
enum window_copy_input_type inputtype;
|
||||
const char *inputprompt;
|
||||
char *inputstr;
|
||||
char *inputstr;
|
||||
|
||||
u_int numprefix;
|
||||
int numprefix;
|
||||
|
||||
enum window_copy_input_type searchtype;
|
||||
char *searchstr;
|
||||
@@ -165,7 +169,7 @@ window_copy_init(struct window_pane *wp)
|
||||
data->inputtype = WINDOW_COPY_OFF;
|
||||
data->inputprompt = NULL;
|
||||
data->inputstr = xstrdup("");
|
||||
data->numprefix = 0;
|
||||
data->numprefix = -1;
|
||||
|
||||
data->searchtype = WINDOW_COPY_OFF;
|
||||
data->searchstr = NULL;
|
||||
@@ -358,25 +362,33 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
|
||||
const char *word_separators;
|
||||
struct window_copy_mode_data *data = wp->modedata;
|
||||
struct screen *s = &data->screen;
|
||||
u_int n, np;
|
||||
int keys;
|
||||
u_int n;
|
||||
int np, keys;
|
||||
enum mode_key_cmd cmd;
|
||||
|
||||
np = data->numprefix;
|
||||
if (np == 0)
|
||||
if (np <= 0)
|
||||
np = 1;
|
||||
|
||||
if (data->inputtype == WINDOW_COPY_JUMPFORWARD ||
|
||||
data->inputtype == WINDOW_COPY_JUMPBACK) {
|
||||
data->inputtype == WINDOW_COPY_JUMPBACK ||
|
||||
data->inputtype == WINDOW_COPY_JUMPTOFORWARD ||
|
||||
data->inputtype == WINDOW_COPY_JUMPTOBACK) {
|
||||
/* Ignore keys with modifiers. */
|
||||
if ((key & KEYC_MASK_MOD) == 0) {
|
||||
data->jumpchar = key;
|
||||
if (data->inputtype == WINDOW_COPY_JUMPFORWARD) {
|
||||
for (; np != 0; np--)
|
||||
window_copy_cursor_jump(wp);
|
||||
} else {
|
||||
} else if (data->inputtype == WINDOW_COPY_JUMPBACK) {
|
||||
for (; np != 0; np--)
|
||||
window_copy_cursor_jump_back(wp);
|
||||
} else if (data->inputtype == WINDOW_COPY_JUMPTOFORWARD) {
|
||||
for (; np != 0; np--)
|
||||
window_copy_cursor_jump_to(wp);
|
||||
} else if (data->inputtype == WINDOW_COPY_JUMPTOBACK) {
|
||||
for (; np != 0; np--)
|
||||
window_copy_cursor_jump_to_back(wp);
|
||||
}
|
||||
}
|
||||
data->jumptype = data->inputtype;
|
||||
@@ -513,7 +525,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
|
||||
if (sess != NULL &&
|
||||
(cmd == MODEKEYCOPY_COPYLINE ||
|
||||
cmd == MODEKEYCOPY_COPYENDOFLINE)) {
|
||||
window_copy_copy_selection(wp);
|
||||
window_copy_copy_selection(wp, -1);
|
||||
window_pane_reset_mode(wp);
|
||||
return;
|
||||
}
|
||||
@@ -524,7 +536,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
|
||||
break;
|
||||
case MODEKEYCOPY_COPYSELECTION:
|
||||
if (sess != NULL) {
|
||||
window_copy_copy_selection(wp);
|
||||
window_copy_copy_selection(wp, data->numprefix);
|
||||
window_pane_reset_mode(wp);
|
||||
return;
|
||||
}
|
||||
@@ -548,13 +560,13 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
|
||||
break;
|
||||
case MODEKEYCOPY_NEXTWORD:
|
||||
word_separators =
|
||||
options_get_string(&wp->window->options, "word-separators");
|
||||
options_get_string(&sess->options, "word-separators");
|
||||
for (; np != 0; np--)
|
||||
window_copy_cursor_next_word(wp, word_separators);
|
||||
break;
|
||||
case MODEKEYCOPY_NEXTWORDEND:
|
||||
word_separators =
|
||||
options_get_string(&wp->window->options, "word-separators");
|
||||
options_get_string(&sess->options, "word-separators");
|
||||
for (; np != 0; np--)
|
||||
window_copy_cursor_next_word_end(wp, word_separators);
|
||||
break;
|
||||
@@ -564,7 +576,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
|
||||
break;
|
||||
case MODEKEYCOPY_PREVIOUSWORD:
|
||||
word_separators =
|
||||
options_get_string(&wp->window->options, "word-separators");
|
||||
options_get_string(&sess->options, "word-separators");
|
||||
for (; np != 0; np--)
|
||||
window_copy_cursor_previous_word(wp, word_separators);
|
||||
break;
|
||||
@@ -581,6 +593,12 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
|
||||
} else if (data->jumptype == WINDOW_COPY_JUMPBACK) {
|
||||
for (; np != 0; np--)
|
||||
window_copy_cursor_jump_back(wp);
|
||||
} else if (data->jumptype == WINDOW_COPY_JUMPTOFORWARD) {
|
||||
for (; np != 0; np--)
|
||||
window_copy_cursor_jump_to(wp);
|
||||
} else if (data->jumptype == WINDOW_COPY_JUMPTOBACK) {
|
||||
for (; np != 0; np--)
|
||||
window_copy_cursor_jump_to_back(wp);
|
||||
}
|
||||
break;
|
||||
case MODEKEYCOPY_JUMPREVERSE:
|
||||
@@ -590,6 +608,12 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
|
||||
} else if (data->jumptype == WINDOW_COPY_JUMPBACK) {
|
||||
for (; np != 0; np--)
|
||||
window_copy_cursor_jump(wp);
|
||||
} else if (data->jumptype == WINDOW_COPY_JUMPTOFORWARD) {
|
||||
for (; np != 0; np--)
|
||||
window_copy_cursor_jump_to_back(wp);
|
||||
} else if (data->jumptype == WINDOW_COPY_JUMPTOBACK) {
|
||||
for (; np != 0; np--)
|
||||
window_copy_cursor_jump_to(wp);
|
||||
}
|
||||
break;
|
||||
case MODEKEYCOPY_JUMPBACK:
|
||||
@@ -598,6 +622,18 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
|
||||
*data->inputstr = '\0';
|
||||
window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
|
||||
return; /* skip numprefix reset */
|
||||
case MODEKEYCOPY_JUMPTO:
|
||||
data->inputtype = WINDOW_COPY_JUMPTOFORWARD;
|
||||
data->inputprompt = "Jump To";
|
||||
*data->inputstr = '\0';
|
||||
window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
|
||||
return; /* skip numprefix reset */
|
||||
case MODEKEYCOPY_JUMPTOBACK:
|
||||
data->inputtype = WINDOW_COPY_JUMPTOBACK;
|
||||
data->inputprompt = "Jump To Back";
|
||||
*data->inputstr = '\0';
|
||||
window_copy_redraw_lines(wp, screen_size_y(s) - 1, 1);
|
||||
return; /* skip numprefix reset */
|
||||
case MODEKEYCOPY_SEARCHUP:
|
||||
data->inputtype = WINDOW_COPY_SEARCHUP;
|
||||
data->inputprompt = "Search Up";
|
||||
@@ -613,6 +649,8 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
|
||||
case WINDOW_COPY_GOTOLINE:
|
||||
case WINDOW_COPY_JUMPFORWARD:
|
||||
case WINDOW_COPY_JUMPBACK:
|
||||
case WINDOW_COPY_JUMPTOFORWARD:
|
||||
case WINDOW_COPY_JUMPTOBACK:
|
||||
case WINDOW_COPY_NUMERICPREFIX:
|
||||
break;
|
||||
case WINDOW_COPY_SEARCHUP:
|
||||
@@ -664,7 +702,7 @@ window_copy_key(struct window_pane *wp, struct session *sess, int key)
|
||||
break;
|
||||
}
|
||||
|
||||
data->numprefix = 0;
|
||||
data->numprefix = -1;
|
||||
return;
|
||||
|
||||
input_on:
|
||||
@@ -696,11 +734,11 @@ window_copy_key_input(struct window_pane *wp, int key)
|
||||
struct window_copy_mode_data *data = wp->modedata;
|
||||
struct screen *s = &data->screen;
|
||||
size_t inputlen;
|
||||
u_int np;
|
||||
int np;
|
||||
|
||||
switch (mode_key_lookup(&data->mdata, key)) {
|
||||
case MODEKEYEDIT_CANCEL:
|
||||
data->numprefix = 0;
|
||||
data->numprefix = -1;
|
||||
return (-1);
|
||||
case MODEKEYEDIT_BACKSPACE:
|
||||
inputlen = strlen(data->inputstr);
|
||||
@@ -712,13 +750,15 @@ window_copy_key_input(struct window_pane *wp, int key)
|
||||
break;
|
||||
case MODEKEYEDIT_ENTER:
|
||||
np = data->numprefix;
|
||||
if (np == 0)
|
||||
if (np <= 0)
|
||||
np = 1;
|
||||
|
||||
switch (data->inputtype) {
|
||||
case WINDOW_COPY_OFF:
|
||||
case WINDOW_COPY_JUMPFORWARD:
|
||||
case WINDOW_COPY_JUMPBACK:
|
||||
case WINDOW_COPY_JUMPTOFORWARD:
|
||||
case WINDOW_COPY_JUMPTOBACK:
|
||||
case WINDOW_COPY_NUMERICPREFIX:
|
||||
break;
|
||||
case WINDOW_COPY_SEARCHUP:
|
||||
@@ -738,7 +778,7 @@ window_copy_key_input(struct window_pane *wp, int key)
|
||||
*data->inputstr = '\0';
|
||||
break;
|
||||
}
|
||||
data->numprefix = 0;
|
||||
data->numprefix = -1;
|
||||
return (1);
|
||||
case MODEKEY_OTHER:
|
||||
if (key < 32 || key > 126)
|
||||
@@ -767,7 +807,7 @@ window_copy_key_numeric_prefix(struct window_pane *wp, int key)
|
||||
if (key < '0' || key > '9')
|
||||
return 1;
|
||||
|
||||
if (data->numprefix >= 100) /* no more than three digits */
|
||||
if (data->numprefix >= 100) /* no more than three digits */
|
||||
return 0;
|
||||
data->numprefix = data->numprefix * 10 + key - '0';
|
||||
|
||||
@@ -834,7 +874,7 @@ reset_mode:
|
||||
s->mode &= ~MODE_MOUSE_BUTTON;
|
||||
s->mode |= MODE_MOUSE_STANDARD;
|
||||
if (sess != NULL) {
|
||||
window_copy_copy_selection(wp);
|
||||
window_copy_copy_selection(wp, -1);
|
||||
window_pane_reset_mode(wp);
|
||||
}
|
||||
}
|
||||
@@ -1235,7 +1275,7 @@ window_copy_update_selection(struct window_pane *wp)
|
||||
}
|
||||
|
||||
void
|
||||
window_copy_copy_selection(struct window_pane *wp)
|
||||
window_copy_copy_selection(struct window_pane *wp, int idx)
|
||||
{
|
||||
struct window_copy_mode_data *data = wp->modedata;
|
||||
struct screen *s = &data->screen;
|
||||
@@ -1315,7 +1355,7 @@ window_copy_copy_selection(struct window_pane *wp)
|
||||
} else {
|
||||
if (keys == MODEKEY_EMACS)
|
||||
lastex = ex;
|
||||
else
|
||||
else
|
||||
lastex = ex + 1;
|
||||
restex = xx;
|
||||
firstsx = sx;
|
||||
@@ -1347,8 +1387,11 @@ window_copy_copy_selection(struct window_pane *wp)
|
||||
screen_write_setselection(&wp->ictx.ctx, buf, off);
|
||||
|
||||
/* Add the buffer to the stack. */
|
||||
limit = options_get_number(&global_options, "buffer-limit");
|
||||
paste_add(&global_buffers, buf, off, limit);
|
||||
if (idx == -1) {
|
||||
limit = options_get_number(&global_options, "buffer-limit");
|
||||
paste_add(&global_buffers, buf, off, limit);
|
||||
} else
|
||||
paste_replace(&global_buffers, idx, buf, off);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1709,6 +1752,62 @@ window_copy_cursor_jump_back(struct window_pane *wp)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
window_copy_cursor_jump_to(struct window_pane *wp)
|
||||
{
|
||||
struct window_copy_mode_data *data = wp->modedata;
|
||||
struct screen *back_s = data->backing;
|
||||
const struct grid_cell *gc;
|
||||
u_int px, py, xx;
|
||||
|
||||
px = data->cx + 1;
|
||||
py = screen_hsize(back_s) + data->cy - data->oy;
|
||||
xx = window_copy_find_length(wp, py);
|
||||
|
||||
while (px < xx) {
|
||||
gc = grid_peek_cell(back_s->grid, px, py);
|
||||
if ((gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8)) == 0
|
||||
&& gc->data == data->jumpchar) {
|
||||
|
||||
window_copy_update_cursor(wp, px - 1, data->cy);
|
||||
if (window_copy_update_selection(wp))
|
||||
window_copy_redraw_lines(wp, data->cy, 1);
|
||||
return;
|
||||
}
|
||||
px++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
window_copy_cursor_jump_to_back(struct window_pane *wp)
|
||||
{
|
||||
struct window_copy_mode_data *data = wp->modedata;
|
||||
struct screen *back_s = data->backing;
|
||||
const struct grid_cell *gc;
|
||||
u_int px, py;
|
||||
|
||||
px = data->cx;
|
||||
py = screen_hsize(back_s) + data->cy - data->oy;
|
||||
|
||||
if (px > 0)
|
||||
px--;
|
||||
|
||||
for (;;) {
|
||||
gc = grid_peek_cell(back_s->grid, px, py);
|
||||
if ((gc->flags & (GRID_FLAG_PADDING|GRID_FLAG_UTF8)) == 0
|
||||
&& gc->data == data->jumpchar) {
|
||||
|
||||
window_copy_update_cursor(wp, px + 1, data->cy);
|
||||
if (window_copy_update_selection(wp))
|
||||
window_copy_redraw_lines(wp, data->cy, 1);
|
||||
return;
|
||||
}
|
||||
if (px == 0)
|
||||
break;
|
||||
px--;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
window_copy_cursor_next_word(struct window_pane *wp, const char *separators)
|
||||
{
|
||||
|
||||
26
window.c
26
window.c
@@ -451,7 +451,7 @@ window_pane_at_index(struct window *w, u_int idx)
|
||||
struct window_pane *wp;
|
||||
u_int n;
|
||||
|
||||
n = 0;
|
||||
n = options_get_number(&w->options, "pane-base-index");
|
||||
TAILQ_FOREACH(wp, &w->panes, entry) {
|
||||
if (n == idx)
|
||||
return (wp);
|
||||
@@ -483,19 +483,21 @@ window_pane_previous_by_number(struct window *w, struct window_pane *wp,
|
||||
return (wp);
|
||||
}
|
||||
|
||||
u_int
|
||||
window_pane_index(struct window *w, struct window_pane *wp)
|
||||
int
|
||||
window_pane_index(struct window_pane *wp, u_int *i)
|
||||
{
|
||||
struct window_pane *wq;
|
||||
u_int n;
|
||||
struct window *w = wp->window;
|
||||
|
||||
n = 0;
|
||||
*i = options_get_number(&w->options, "pane-base-index");
|
||||
TAILQ_FOREACH(wq, &w->panes, entry) {
|
||||
if (wp == wq)
|
||||
break;
|
||||
n++;
|
||||
if (wp == wq) {
|
||||
return (0);
|
||||
}
|
||||
(*i)++;
|
||||
}
|
||||
return (n);
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
u_int
|
||||
@@ -679,6 +681,10 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell,
|
||||
if (tio != NULL)
|
||||
memcpy(tio2.c_cc, tio->c_cc, sizeof tio2.c_cc);
|
||||
tio2.c_cc[VERASE] = '\177';
|
||||
#ifdef IUTF8
|
||||
if (options_get_number(&wp->window->options, "utf8"))
|
||||
tio2.c_iflag |= IUTF8;
|
||||
#endif
|
||||
if (tcsetattr(STDIN_FILENO, TCSANOW, &tio2) != 0)
|
||||
fatal("tcgetattr failed");
|
||||
|
||||
@@ -694,7 +700,7 @@ window_pane_spawn(struct window_pane *wp, const char *cmd, const char *shell,
|
||||
if (*wp->cmd != '\0') {
|
||||
/* Set SHELL but only if it is currently not useful. */
|
||||
shell = getenv("SHELL");
|
||||
if (shell == NULL || *shell == '\0' || areshell(shell))
|
||||
if (checkshell(shell))
|
||||
setenv("SHELL", wp->shell, 1);
|
||||
|
||||
execl(_PATH_BSHELL, "sh", "-c", wp->cmd, (char *) NULL);
|
||||
|
||||
@@ -3,33 +3,33 @@
|
||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xml:lang="en" lang="en" xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>tmux</title>
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="main.css"/>
|
||||
<title>tmux</title>
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="main.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div id="body-wrapper">
|
||||
<div id="left-menu-container">
|
||||
<p id="upper-left-title">tmux</p>
|
||||
<ul id="left-menu">
|
||||
<li><a href="http://downloads.sourceforge.net/tmux/tmux-%%VERSION%%.tar.gz">Download</a></li>
|
||||
<li><a href="http://tmux.svn.sourceforge.net/viewvc/tmux/trunk/NOTES">Release Notes</a></li>
|
||||
<li><a href="http://tmux.svn.sourceforge.net/viewvc/tmux/trunk/CHANGES">Changelog</a></li>
|
||||
<li><a href="http://tmux.svn.sourceforge.net/viewvc/tmux/trunk/FAQ">FAQ</a></li>
|
||||
<div id="body-wrapper">
|
||||
<div id="left-menu-container">
|
||||
<p id="upper-left-title">tmux</p>
|
||||
<ul id="left-menu">
|
||||
<li><a href="http://downloads.sourceforge.net/tmux/tmux-%%VERSION%%.tar.gz">Download</a></li>
|
||||
<li><a href="http://tmux.svn.sourceforge.net/viewvc/tmux/trunk/NOTES">Release Notes</a></li>
|
||||
<li><a href="http://www.openbsd.org/cgi-bin/man.cgi?query=tmux&sektion=1">Manual Page</a></li>
|
||||
<li><a href="http://tmux.svn.sourceforge.net/viewvc/tmux/trunk/FAQ">FAQ</a></li>
|
||||
<li><a href="http://www.openbsd.org/faq/faq7.html#tmux">tmux in the OpenBSD FAQ</a></li>
|
||||
<li><a href="http://tmux.svn.sourceforge.net/viewvc/tmux/trunk/examples/">Examples</a></li>
|
||||
<li> </li>
|
||||
<li class="menu-headings">Source Code</li>
|
||||
<li> </li>
|
||||
<li class="menu-headings">Source Code</li>
|
||||
<li><a href="http://tmux.svn.sourceforge.net/viewvc/tmux/trunk/">SourceForge</a></li>
|
||||
<li><a href="http://www.openbsd.org/cgi-bin/cvsweb/src/usr.bin/tmux/">OpenBSD</a></li>
|
||||
<li> </li>
|
||||
<li class="menu-headings">Support</li>
|
||||
<li><a href="https://lists.sourceforge.net/lists/listinfo/tmux-users">tmux-users</a></li>
|
||||
<li><a href="https://lists.sourceforge.net/lists/listinfo/tmux-cvs">tmux-cvs</a></li>
|
||||
<li>IRC: #tmux on Freenode</li>
|
||||
<li><a href="http://sf.net/projects/tmux">SourceForge Project Page</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="main-content-wrapper">
|
||||
<li> </li>
|
||||
<li class="menu-headings">Support</li>
|
||||
<li><a href="https://lists.sourceforge.net/lists/listinfo/tmux-users">tmux-users</a></li>
|
||||
<li><a href="https://lists.sourceforge.net/lists/listinfo/tmux-cvs">tmux-cvs</a></li>
|
||||
<li>IRC: #tmux on Freenode</li>
|
||||
<li><a href="http://sf.net/projects/tmux">SourceForge Project Page</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="main-content-wrapper">
|
||||
|
||||
<p>tmux is a terminal multiplexer: it enables a number of terminals (or
|
||||
windows), each running a separate program, to be created, accessed, and
|
||||
@@ -74,13 +74,12 @@ terminfo implementation (normally <a href="http://invisible-island.net/ncurses/"
|
||||
<a href="https://github.com/lmartinking/tmux-applets">tmux-applets</a> and
|
||||
<a href="https://github.com/remiprev/teamocil">teamocil</a>.</p>
|
||||
|
||||
<div id="screenshots">
|
||||
<a href="tmux3.png"><img src="small-tmux3.png" alt="Screenshot"/></a>
|
||||
<a href="tmux4.png"><img src="small-tmux4.png" alt="Screenshot"/></a>
|
||||
<a href="tmux5.png"><img src="small-tmux5.png" alt="Screenshot"/></a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="screenshots">
|
||||
<a href="tmux3.png"><img src="small-tmux3.png" alt="Screenshot"/></a>
|
||||
<a href="tmux4.png"><img src="small-tmux4.png" alt="Screenshot"/></a>
|
||||
<a href="tmux5.png"><img src="small-tmux5.png" alt="Screenshot"/></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user