CHANGED FROM 3.1b TO 3.1c

* Do not write after the end of the array and overwrite the stack when
  colon-separated SGR sequences contain empty arguments.

CHANGES FROM 3.1a TO 3.1b

* Fix build on systems without sys/queue.h.

* Fix crash when allow-rename is on and an empty name is set.

CHANGES FROM 3.1 TO 3.1a

* Do not close stdout prematurely in control mode since it is needed to print
  exit messages. Prevents hanging when detaching with iTerm2.

CHANGES FROM 3.0a TO 3.1

* Only search the visible part of the history when marking (highlighting)
  search terms. This is much faster than searching the whole history and solves
  problems with large histories. The count of matches shown is now the visible
  matches rather than all matches.

* Search using regular expressions in copy mode. search-forward and
  search-backward use regular expressions by default; the incremental versions
  do not.

* Turn off mouse mode 1003 as well as the rest when exiting.

* Add selection_active format for when the selection is present but not moving
  with the cursor.

* Fix dragging with modifier keys, so binding keys such as C-MouseDrag1Pane and
  C-MouseDragEnd1Pane now work.

* Add -a to list-keys to also list keys without notes with -N.

* Do not jump to next word end if already on a word end when selecting a word;
  fixes select-word with single character words and vi(1) keys.

* Fix top and bottom pane calculation with pane border status enabled.

* Add support for adding a note to a key binding (with bind-key -N) and use
  this to add descriptions to the default key bindings. A new -N flag to
  list-keys shows key bindings with notes. Change the default ? binding to use
  this to show a readable summary of keys. Also extend command-prompt to return
  the name of the key pressed and add a default binding (/) to show the note
  for the next key pressed.

* Add support for the iTerm2 DSR 1337 sequence to get the terminal version.

* Treat plausible but invalid keys (like C-BSpace) as literal like any other
  unrecognised string passed to send-keys.

* Detect iTerm2 and enable use of DECSLRM (much faster with horizontally split
  windows).

* Add -Z to default switch-client command in tree mode.

* Add ~ to quoted characters for %%%.

* Document client exit messages in the manual page.

* Do not let read-only clients limit the size, unless all clients are
  read-only.

* Add a number of new formats to inspect what sessions and clients a window is
  present or active in.

* Change file reading and writing to go through the client if necessary. This
  fixes commands like "tmux loadb /dev/fd/X". Also modify source-file to
  support "-" for standard input, like load-buffer and save-buffer.

* Add ~/.config/tmux/tmux.conf to the default search path for configuration
  files.

* Bump the escape sequence timeout to five seconds to allow for longer
  legitimate sequences.

* Make a best effort to set xpixel and ypixel for each pane and add formats for
  them.

* Add push-default to status-left and status-right in status-format[0].

* Do not clear search marks on cursor movement with vi(1) keys.

* Add p format modifier for padding to width and allow multiple substitutions
  in a single format.

* Add -f for full size to join-pane (like split-window).

* Do not use bright when emulating 256 colours on an 8 colour terminal because
  it is also bold on some terminals.

* Make select-pane -P set window-active-style also to match previous behaviour.

* Do not truncate list-keys output.

* Turn automatic-rename back on if the \033k rename escape sequence is used
  with an empty name.

* Add support for percentage sizes for resize-pane ("-x 10%"). Also change
  split-window and join-pane -l to accept similar percentages and deprecate the
  -p flag.

* Add -F flag to send-keys to expand formats in search-backward and forward
  copy mode commands and copy_cursor_word and copy_cursor_line formats for word
  and line at cursor in copy mode. Use for default # and * binding with vi(1)
  keys.

* Add formats for word and line at cursor position in copy mode.

* Add formats for cursor and selection position in copy mode.

* Support all the forms of RGB colour strings in OSC sequences rather than
  requiring two digits.

* Limit lazy resize to panes in attached sessions only.

* Add an option to set the key sent by backspace for those whose system uses ^H
  rather than ^?.

* Change new-session -A without a session name (that is, no -s option also) to
  attach to the best existing session like attach-session rather than a new
  one.

* Add a "latest" window-size option which tries to size windows based on the
  most recently used client. This is now the default.

* Add simple support for OSC 7 (result is available in the pane_path format).

* Add push-default and pop-default for styles which change the colours and
  attributes used for #[default]. These are used in status-format to restore
  the behaviour of window-status-style being the default for
  window-status-format.

* Add window_marked_flag.

* Add cursor-down-and-cancel in copy mode.

* Default to previous search string for search-forward and search-backward.

* Add -Z flag to rotate-window, select-pane, swap-pane, switch-client to
  preserve zoomed state.

* Add -N to capture-pane to preserve trailing spaces.

* Add reverse sorting in tree, client and buffer modes.
This commit is contained in:
christos 2020-11-01 14:52:00 +00:00
parent f2b8838b93
commit aa83ff61b0
39 changed files with 1668 additions and 596 deletions

View File

@ -1,4 +1,152 @@
CHANGES FROM 3.0 to 3.0a
CHANGED FROM 3.1b TO 3.1c
* Fix a stack overflow on colon-separated CSI parsing.
CHANGES FROM 3.1a TO 3.1b
* Fix build on systems without sys/queue.h.
* Fix crash when allow-rename is on and an empty name is set.
CHANGES FROM 3.1 TO 3.1a
* Do not close stdout prematurely in control mode since it is needed to print
exit messages. Prevents hanging when detaching with iTerm2.
CHANGES FROM 3.0a TO 3.1
* Only search the visible part of the history when marking (highlighting)
search terms. This is much faster than searching the whole history and solves
problems with large histories. The count of matches shown is now the visible
matches rather than all matches.
* Search using regular expressions in copy mode. search-forward and
search-backward use regular expressions by default; the incremental versions
do not.
* Turn off mouse mode 1003 as well as the rest when exiting.
* Add selection_active format for when the selection is present but not moving
with the cursor.
* Fix dragging with modifier keys, so binding keys such as C-MouseDrag1Pane and
C-MouseDragEnd1Pane now work.
* Add -a to list-keys to also list keys without notes with -N.
* Do not jump to next word end if already on a word end when selecting a word;
fixes select-word with single character words and vi(1) keys.
* Fix top and bottom pane calculation with pane border status enabled.
* Add support for adding a note to a key binding (with bind-key -N) and use
this to add descriptions to the default key bindings. A new -N flag to
list-keys shows key bindings with notes. Change the default ? binding to use
this to show a readable summary of keys. Also extend command-prompt to return
the name of the key pressed and add a default binding (/) to show the note
for the next key pressed.
* Add support for the iTerm2 DSR 1337 sequence to get the terminal version.
* Treat plausible but invalid keys (like C-BSpace) as literal like any other
unrecognised string passed to send-keys.
* Detect iTerm2 and enable use of DECSLRM (much faster with horizontally split
windows).
* Add -Z to default switch-client command in tree mode.
* Add ~ to quoted characters for %%%.
* Document client exit messages in the manual page.
* Do not let read-only clients limit the size, unless all clients are
read-only.
* Add a number of new formats to inspect what sessions and clients a window is
present or active in.
* Change file reading and writing to go through the client if necessary. This
fixes commands like "tmux loadb /dev/fd/X". Also modify source-file to
support "-" for standard input, like load-buffer and save-buffer.
* Add ~/.config/tmux/tmux.conf to the default search path for configuration
files.
* Bump the escape sequence timeout to five seconds to allow for longer
legitimate sequences.
* Make a best effort to set xpixel and ypixel for each pane and add formats for
them.
* Add push-default to status-left and status-right in status-format[0].
* Do not clear search marks on cursor movement with vi(1) keys.
* Add p format modifier for padding to width and allow multiple substitutions
in a single format.
* Add -f for full size to join-pane (like split-window).
* Do not use bright when emulating 256 colours on an 8 colour terminal because
it is also bold on some terminals.
* Make select-pane -P set window-active-style also to match previous behaviour.
* Do not truncate list-keys output.
* Turn automatic-rename back on if the \033k rename escape sequence is used
with an empty name.
* Add support for percentage sizes for resize-pane ("-x 10%"). Also change
split-window and join-pane -l to accept similar percentages and deprecate the
-p flag.
* Add -F flag to send-keys to expand formats in search-backward and forward
copy mode commands and copy_cursor_word and copy_cursor_line formats for word
and line at cursor in copy mode. Use for default # and * binding with vi(1)
keys.
* Add formats for word and line at cursor position in copy mode.
* Add formats for cursor and selection position in copy mode.
* Support all the forms of RGB colour strings in OSC sequences rather than
requiring two digits.
* Limit lazy resize to panes in attached sessions only.
* Add an option to set the key sent by backspace for those whose system uses ^H
rather than ^?.
* Change new-session -A without a session name (that is, no -s option also) to
attach to the best existing session like attach-session rather than a new
one.
* Add a "latest" window-size option which tries to size windows based on the
most recently used client. This is now the default.
* Add simple support for OSC 7 (result is available in the pane_path format).
* Add push-default and pop-default for styles which change the colours and
attributes used for #[default]. These are used in status-format to restore
the behaviour of window-status-style being the default for
window-status-format.
* Add window_marked_flag.
* Add cursor-down-and-cancel in copy mode.
* Default to previous search string for search-forward and search-backward.
* Add -Z flag to rotate-window, select-pane, swap-pane, switch-client to
preserve zoomed state.
* Add -N to capture-pane to preserve trailing spaces.
* Add reverse sorting in tree, client and buffer modes.
CHANGES FROM 3.0 TO 3.0a
* Do not require REG_STARTEND.
@ -12,7 +160,7 @@ CHANGES FROM 3.0 to 3.0a
* Do not crash when restoring a layout with only one pane.
CHANGES FROM 2.9 to 3.0
CHANGES FROM 2.9 TO 3.0
* Workaround invalid layout strings generated by older tmux versions and add
some additional sanity checks
@ -102,7 +250,7 @@ CHANGES FROM 2.9 to 3.0
* Add the ability to create simple menus. Introduces new command
display-menu. Default menus are bound to MouseDown3 on the status line;
MouseDown3 or M-MouseDown3 on panes; MouseDown3 in tree, client and
buffer modes; and C-b C-m and C-b M-m.
buffer modes; and C-b < and >.
* Allow panes to be empty (no command). They can be created either by piping to
split-window -I, or by passing an empty command ('') to split-window. Output
@ -137,11 +285,11 @@ CHANGES FROM 2.9 to 3.0
* Add the ability to infer an option type (server, session, window) from its
name to show-options (it was already present in set-option).
CHANGES FROM 2.9 to 2.9a
CHANGES FROM 2.9 TO 2.9a
* Fix bugs in select-pane and the main-horizontal and main-vertical layouts.
CHANGES FROM 2.8 to 2.9
CHANGES FROM 2.8 TO 2.9
* Attempt to preserve horizontal cursor position as well as vertical with
reflow.
@ -266,7 +414,7 @@ CHANGES FROM 2.8 to 2.9
moves up, down, left or right and -c returns to automatic cursor
tracking. The position is reset when the current window is changed.
CHANGES FROM 2.7 to 2.8
CHANGES FROM 2.7 TO 2.8
* Make display-panes block the client until a pane is chosen or it
times out.

View File

@ -6,11 +6,14 @@ CLEANFILES = tmux.1.mdoc tmux.1.man cmd-parse.c
# Distribution tarball options.
EXTRA_DIST = \
CHANGES README README.ja COPYING example_tmux.conf compat/*.[ch] \
CHANGES README README.ja COPYING example_tmux.conf \
osdep-*.c mdoc2man.awk tmux.1
dist_EXTRA_tmux_SOURCES = compat/*.[ch]
# Preprocessor flags.
AM_CPPFLAGS += @XOPEN_DEFINES@ -DTMUX_CONF="\"$(sysconfdir)/tmux.conf\""
AM_CPPFLAGS += @XOPEN_DEFINES@ \
-DTMUX_VERSION="\"@VERSION@\"" \
-DTMUX_CONF="\"$(sysconfdir)/tmux.conf:~/.tmux.conf:~/.config/tmux/tmux.conf\""
# Additional object files.
LDADD = $(LIBOBJS)
@ -130,6 +133,7 @@ dist_tmux_SOURCES = \
control-notify.c \
control.c \
environ.c \
file.c \
format.c \
format-draw.c \
grid-view.c \

View File

@ -175,15 +175,15 @@ dist_tmux_OBJECTS = alerts.$(OBJEXT) arguments.$(OBJEXT) \
cmd-swap-window.$(OBJEXT) cmd-switch-client.$(OBJEXT) \
cmd-unbind-key.$(OBJEXT) cmd-wait-for.$(OBJEXT) cmd.$(OBJEXT) \
colour.$(OBJEXT) control-notify.$(OBJEXT) control.$(OBJEXT) \
environ.$(OBJEXT) format.$(OBJEXT) format-draw.$(OBJEXT) \
grid-view.$(OBJEXT) grid.$(OBJEXT) input-keys.$(OBJEXT) \
input.$(OBJEXT) job.$(OBJEXT) key-bindings.$(OBJEXT) \
key-string.$(OBJEXT) layout-custom.$(OBJEXT) \
layout-set.$(OBJEXT) layout.$(OBJEXT) log.$(OBJEXT) \
menu.$(OBJEXT) mode-tree.$(OBJEXT) names.$(OBJEXT) \
notify.$(OBJEXT) options-table.$(OBJEXT) options.$(OBJEXT) \
paste.$(OBJEXT) proc.$(OBJEXT) regsub.$(OBJEXT) \
resize.$(OBJEXT) screen-redraw.$(OBJEXT) \
environ.$(OBJEXT) file.$(OBJEXT) format.$(OBJEXT) \
format-draw.$(OBJEXT) grid-view.$(OBJEXT) grid.$(OBJEXT) \
input-keys.$(OBJEXT) input.$(OBJEXT) job.$(OBJEXT) \
key-bindings.$(OBJEXT) key-string.$(OBJEXT) \
layout-custom.$(OBJEXT) layout-set.$(OBJEXT) layout.$(OBJEXT) \
log.$(OBJEXT) menu.$(OBJEXT) mode-tree.$(OBJEXT) \
names.$(OBJEXT) notify.$(OBJEXT) options-table.$(OBJEXT) \
options.$(OBJEXT) paste.$(OBJEXT) proc.$(OBJEXT) \
regsub.$(OBJEXT) resize.$(OBJEXT) screen-redraw.$(OBJEXT) \
screen-write.$(OBJEXT) screen.$(OBJEXT) \
server-client.$(OBJEXT) server-fn.$(OBJEXT) server.$(OBJEXT) \
session.$(OBJEXT) spawn.$(OBJEXT) status.$(OBJEXT) \
@ -238,8 +238,9 @@ am__v_YACC_ = $(am__v_YACC_@AM_DEFAULT_V@)
am__v_YACC_0 = @echo " YACC " $@;
am__v_YACC_1 =
YLWRAP = $(top_srcdir)/etc/ylwrap
SOURCES = $(dist_tmux_SOURCES) $(nodist_tmux_SOURCES)
DIST_SOURCES = $(dist_tmux_SOURCES)
SOURCES = $(dist_tmux_SOURCES) $(nodist_tmux_SOURCES) \
$(dist_EXTRA_tmux_SOURCES)
DIST_SOURCES = $(dist_tmux_SOURCES) $(dist_EXTRA_tmux_SOURCES)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
@ -319,9 +320,10 @@ AM_CFLAGS = @AM_CFLAGS@ $(am__append_1) $(am__append_2) \
# Preprocessor flags.
AM_CPPFLAGS = @AM_CPPFLAGS@ @XOPEN_DEFINES@ \
-DTMUX_CONF="\"$(sysconfdir)/tmux.conf\"" $(am__append_3) \
$(am__append_4) $(am__append_5) $(am__append_6) \
$(am__append_8) $(am__append_9)
-DTMUX_VERSION="\"@VERSION@\"" \
-DTMUX_CONF="\"$(sysconfdir)/tmux.conf:~/.tmux.conf:~/.config/tmux/tmux.conf\"" \
$(am__append_3) $(am__append_4) $(am__append_5) \
$(am__append_6) $(am__append_8) $(am__append_9)
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AM_LDFLAGS = @AM_LDFLAGS@
AUTOCONF = @AUTOCONF@
@ -422,6 +424,7 @@ pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
runstatedir = @runstatedir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
@ -434,9 +437,10 @@ CLEANFILES = tmux.1.mdoc tmux.1.man cmd-parse.c
# Distribution tarball options.
EXTRA_DIST = \
CHANGES README README.ja COPYING example_tmux.conf compat/*.[ch] \
CHANGES README README.ja COPYING example_tmux.conf \
osdep-*.c mdoc2man.awk tmux.1
dist_EXTRA_tmux_SOURCES = compat/*.[ch]
# Additional object files.
LDADD = $(LIBOBJS)
@ -516,6 +520,7 @@ dist_tmux_SOURCES = \
control-notify.c \
control.c \
environ.c \
file.c \
format.c \
format-draw.c \
grid-view.c \
@ -741,6 +746,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/control-notify.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/control.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/environ.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/format-draw.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/format.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/grid-view.Po@am__quote@

View File

@ -74,6 +74,7 @@ args_parse(const char *template, int argc, char **argv)
optreset = 1;
optind = 1;
optarg = NULL;
while ((opt = getopt(argc, argv, template)) != -1) {
if (opt < 0)
@ -83,6 +84,7 @@ args_parse(const char *template, int argc, char **argv)
return (NULL);
}
args_set(args, opt, optarg);
optarg = NULL;
}
argc -= optind;
argv += optind;

View File

@ -59,8 +59,8 @@ attributes_fromstring(const char *str)
size_t end;
u_int i;
struct {
const char* name;
int attr;
const char *name;
int attr;
} table[] = {
{ "bright", GRID_ATTR_BRIGHT },
{ "bold", GRID_ATTR_BRIGHT },

View File

@ -66,12 +66,45 @@ set_cfg_file(const char *path)
cfg_file = xstrdup(path);
}
static char *
expand_cfg_file(const char *path, const char *home)
{
char *expanded, *name;
const char *end;
struct environ_entry *value;
if (strncmp(path, "~/", 2) == 0) {
if (home == NULL)
return (NULL);
xasprintf(&expanded, "%s%s", home, path + 1);
return (expanded);
}
if (*path == '$') {
end = strchr(path, '/');
if (end == NULL)
name = xstrdup(path + 1);
else
name = xstrndup(path + 1, end - path - 1);
value = environ_find(global_environ, name);
free(name);
if (value == NULL)
return (NULL);
if (end == NULL)
end = "";
xasprintf(&expanded, "%s%s", value->value, end);
return (expanded);
}
return (xstrdup(path));
}
void
start_cfg(void)
{
const char *home;
int flags = 0;
const char *home = find_home();
struct client *c;
char *path, *copy, *next, *expanded;
/*
* Configuration files are loaded without a client, so commands are run
@ -89,15 +122,21 @@ start_cfg(void)
cmdq_append(c, cfg_item);
}
if (cfg_file == NULL)
load_cfg(TMUX_CONF, c, NULL, CMD_PARSE_QUIET, NULL);
if (cfg_file == NULL && (home = find_home()) != NULL) {
xasprintf(&cfg_file, "%s/.tmux.conf", home);
flags = CMD_PARSE_QUIET;
}
if (cfg_file != NULL)
load_cfg(cfg_file, c, NULL, flags, NULL);
if (cfg_file == NULL) {
path = copy = xstrdup(TMUX_CONF);
while ((next = strsep(&path, ":")) != NULL) {
expanded = expand_cfg_file(next, home);
if (expanded == NULL) {
log_debug("couldn't expand %s", next);
continue;
}
log_debug("expanded %s to %s", next, expanded);
load_cfg(expanded, c, NULL, CMD_PARSE_QUIET, NULL);
free(expanded);
}
free(copy);
} else
load_cfg(cfg_file, c, NULL, 0, NULL);
cmdq_append(NULL, cmdq_get_callback(cfg_done, NULL));
}
@ -145,9 +184,55 @@ load_cfg(const char *path, struct client *c, struct cmdq_item *item, int flags,
new_item0 = cmdq_get_command(pr->cmdlist, NULL, NULL, 0);
if (item != NULL)
cmdq_insert_after(item, new_item0);
new_item0 = cmdq_insert_after(item, new_item0);
else
cmdq_append(NULL, new_item0);
new_item0 = cmdq_append(NULL, new_item0);
cmd_list_free(pr->cmdlist);
if (new_item != NULL)
*new_item = new_item0;
return (0);
}
int
load_cfg_from_buffer(const void *buf, size_t len, const char *path,
struct client *c, struct cmdq_item *item, int flags,
struct cmdq_item **new_item)
{
struct cmd_parse_input pi;
struct cmd_parse_result *pr;
struct cmdq_item *new_item0;
if (new_item != NULL)
*new_item = NULL;
log_debug("loading %s", path);
memset(&pi, 0, sizeof pi);
pi.flags = flags;
pi.file = path;
pi.line = 1;
pi.item = item;
pi.c = c;
pr = cmd_parse_from_buffer(buf, len, &pi);
if (pr->status == CMD_PARSE_EMPTY)
return (0);
if (pr->status == CMD_PARSE_ERROR) {
cfg_add_cause("%s", pr->error);
free(pr->error);
return (-1);
}
if (flags & CMD_PARSE_PARSEONLY) {
cmd_list_free(pr->cmdlist);
return (0);
}
new_item0 = cmdq_get_command(pr->cmdlist, NULL, NULL, 0);
if (item != NULL)
new_item0 = cmdq_insert_after(item, new_item0);
else
new_item0 = cmdq_append(NULL, new_item0);
cmd_list_free(pr->cmdlist);
if (new_item != NULL)

View File

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

View File

@ -76,11 +76,12 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
window_lost_pane(w, wp);
layout_close_pane(wp);
w = wp->window = window_create(w->sx, w->sy);
w = wp->window = window_create(w->sx, w->sy, w->xpixel, w->ypixel);
options_set_parent(wp->options, w->options);
wp->flags |= PANE_STYLECHANGED;
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
w->active = wp;
w->latest = c;
if (!args_has(args, 'n')) {
name = default_window_name(w);

View File

@ -30,8 +30,8 @@ const struct cmd_entry cmd_choose_tree_entry = {
.name = "choose-tree",
.alias = NULL,
.args = { "F:Gf:NO:st:wZ", 0, 1 },
.usage = "[-GNsw] [-F format] [-f filter] [-O sort-order] "
.args = { "F:Gf:NO:rst:wZ", 0, 1 },
.usage = "[-GNrswZ] [-F format] [-f filter] [-O sort-order] "
CMD_TARGET_PANE_USAGE " [template]",
.target = { 't', CMD_FIND_PANE, 0 },
@ -44,8 +44,8 @@ const struct cmd_entry cmd_choose_client_entry = {
.name = "choose-client",
.alias = NULL,
.args = { "F:f:NO:t:Z", 0, 1 },
.usage = "[-N] [-F format] [-f filter] [-O sort-order] "
.args = { "F:f:NO:rt:Z", 0, 1 },
.usage = "[-NrZ] [-F format] [-f filter] [-O sort-order] "
CMD_TARGET_PANE_USAGE " [template]",
.target = { 't', CMD_FIND_PANE, 0 },
@ -58,8 +58,8 @@ const struct cmd_entry cmd_choose_buffer_entry = {
.name = "choose-buffer",
.alias = NULL,
.args = { "F:f:NO:t:Z", 0, 1 },
.usage = "[-N] [-F format] [-f filter] [-O sort-order] "
.args = { "F:f:NO:rt:Z", 0, 1 },
.usage = "[-NrZ] [-F format] [-f filter] [-O sort-order] "
CMD_TARGET_PANE_USAGE " [template]",
.target = { 't', CMD_FIND_PANE, 0 },

View File

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

View File

@ -30,8 +30,8 @@ const struct cmd_entry cmd_copy_mode_entry = {
.name = "copy-mode",
.alias = NULL,
.args = { "Met:u", 0, 0 },
.usage = "[-Mu] " CMD_TARGET_PANE_USAGE,
.args = { "eHMt:uq", 0, 0 },
.usage = "[-eHMuq] " CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 },
@ -61,6 +61,11 @@ cmd_copy_mode_exec(struct cmd *self, struct cmdq_item *item)
struct session *s;
struct window_pane *wp = item->target.wp;
if (args_has(args, 'q')) {
window_pane_reset_mode_all(wp);
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'M')) {
if ((wp = cmd_mouse_pane(&shared->mouse, &s, NULL)) == NULL)
return (CMD_RETURN_NORMAL);

View File

@ -20,6 +20,7 @@
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "tmux.h"
@ -34,8 +35,8 @@ const struct cmd_entry cmd_join_pane_entry = {
.name = "join-pane",
.alias = "joinp",
.args = { "bdhvp:l:s:t:", 0, 0 },
.usage = "[-bdhv] [-p percentage|-l size] " CMD_SRCDST_PANE_USAGE,
.args = { "bdfhvp:l:s:t:", 0, 0 },
.usage = "[-bdfhv] [-l size] " CMD_SRCDST_PANE_USAGE,
.source = { 's', CMD_FIND_PANE, CMD_FIND_DEFAULT_MARKED },
.target = { 't', CMD_FIND_PANE, 0 },
@ -51,7 +52,7 @@ const struct cmd_entry cmd_move_pane_entry = {
.args = { "bdhvp:l:s:t:", 0, 0 },
.usage = "[-bdhv] [-p percentage|-l size] " CMD_SRCDST_PANE_USAGE,
.source = { 's', CMD_FIND_PANE, 0 },
.source = { 's', CMD_FIND_PANE, CMD_FIND_DEFAULT_MARKED },
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,
@ -67,11 +68,13 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
struct winlink *src_wl, *dst_wl;
struct window *src_w, *dst_w;
struct window_pane *src_wp, *dst_wp;
char *cause;
int size, percentage, dst_idx;
char *cause, *copy;
const char *errstr, *p;
size_t plen;
int size, percentage, dst_idx, not_same_window;
int flags;
enum layout_type type;
struct layout_cell *lc;
int not_same_window, flags;
if (self->entry == &cmd_join_pane_entry)
not_same_window = 1;
@ -104,12 +107,28 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
type = LAYOUT_LEFTRIGHT;
size = -1;
if (args_has(args, 'l')) {
size = args_strtonum(args, 'l', 0, INT_MAX, &cause);
if (cause != NULL) {
cmdq_error(item, "size %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
if ((p = args_get(args, 'l')) != NULL) {
plen = strlen(p);
if (p[plen - 1] == '%') {
copy = xstrdup(p);
copy[plen - 1] = '\0';
percentage = strtonum(copy, 0, INT_MAX, &errstr);
free(copy);
if (errstr != NULL) {
cmdq_error(item, "percentage %s", errstr);
return (CMD_RETURN_ERROR);
}
if (type == LAYOUT_TOPBOTTOM)
size = (dst_wp->sy * percentage) / 100;
else
size = (dst_wp->sx * percentage) / 100;
} else {
size = args_strtonum(args, 'l', 0, INT_MAX, &cause);
if (cause != NULL) {
cmdq_error(item, "size %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
}
} else if (args_has(args, 'p')) {
percentage = args_strtonum(args, 'p', 0, 100, &cause);
@ -123,10 +142,13 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
else
size = (dst_wp->sx * percentage) / 100;
}
flags = 0;
if (args_has(args, 'b'))
flags = SPAWN_BEFORE;
else
flags = 0;
flags |= SPAWN_BEFORE;
if (args_has(args, 'f'))
flags |= SPAWN_FULLSIZE;
lc = layout_split_pane(dst_wp, type, size, flags);
if (lc == NULL) {
cmdq_error(item, "create pane failed: pane too small");

View File

@ -37,7 +37,7 @@ const struct cmd_entry cmd_kill_pane_entry = {
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,
.flags = CMD_AFTERHOOK,
.exec = cmd_kill_pane_exec
};

View File

@ -36,8 +36,8 @@ const struct cmd_entry cmd_list_keys_entry = {
.name = "list-keys",
.alias = "lsk",
.args = { "T:", 0, 0 },
.usage = "[-T key-table]",
.args = { "1aNP:T:", 0, 1 },
.usage = "[-1aN] [-P prefix-string] [-T key-table] [key]",
.flags = CMD_STARTSERVER|CMD_AFTERHOOK,
.exec = cmd_list_keys_exec
@ -47,13 +47,100 @@ const struct cmd_entry cmd_list_commands_entry = {
.name = "list-commands",
.alias = "lscm",
.args = { "F:", 0, 0 },
.usage = "[-F format]",
.args = { "F:", 0, 1 },
.usage = "[-F format] [command]",
.flags = CMD_STARTSERVER|CMD_AFTERHOOK,
.exec = cmd_list_keys_exec
};
static u_int
cmd_list_keys_get_width(const char *tablename, key_code only)
{
struct key_table *table;
struct key_binding *bd;
u_int width, keywidth = 0;
table = key_bindings_get_table(tablename, 0);
if (table == NULL)
return (0);
bd = key_bindings_first(table);
while (bd != NULL) {
if ((only != KEYC_UNKNOWN && bd->key != only) ||
KEYC_IS_MOUSE(bd->key) ||
bd->note == NULL) {
bd = key_bindings_next(table, bd);
continue;
}
width = utf8_cstrwidth(key_string_lookup_key(bd->key));
if (width > keywidth)
keywidth = width;
bd = key_bindings_next(table, bd);
}
return (keywidth);
}
static int
cmd_list_keys_print_notes(struct cmdq_item *item, struct args *args,
const char *tablename, u_int keywidth, key_code only, const char *prefix)
{
struct client *c = cmd_find_client(item, NULL, 1);
struct key_table *table;
struct key_binding *bd;
const char *key;
char *tmp, *note;
int found = 0;
table = key_bindings_get_table(tablename, 0);
if (table == NULL)
return (0);
bd = key_bindings_first(table);
while (bd != NULL) {
if ((only != KEYC_UNKNOWN && bd->key != only) ||
KEYC_IS_MOUSE(bd->key) ||
(bd->note == NULL && !args_has(args, 'a'))) {
bd = key_bindings_next(table, bd);
continue;
}
found = 1;
key = key_string_lookup_key(bd->key);
if (bd->note == NULL)
note = cmd_list_print(bd->cmdlist, 1);
else
note = xstrdup(bd->note);
tmp = utf8_padcstr(key, keywidth + 1);
if (args_has(args, '1') && c != NULL)
status_message_set(c, "%s%s%s", prefix, tmp, note);
else
cmdq_print(item, "%s%s%s", prefix, tmp, note);
free(tmp);
free(note);
if (args_has(args, '1'))
break;
bd = key_bindings_next(table, bd);
}
return (found);
}
static char *
cmd_list_keys_get_prefix(struct args *args, key_code *prefix)
{
char *s;
*prefix = options_get_number(global_s_options, "prefix");
if (!args_has(args, 'P')) {
if (*prefix != KEYC_NONE)
xasprintf(&s, "%s ", key_string_lookup_key(*prefix));
else
s = xstrdup("");
} else
s = xstrdup(args_get(args, 'P'));
return (s);
}
static enum cmd_retval
cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
{
@ -61,19 +148,63 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
struct key_table *table;
struct key_binding *bd;
const char *tablename, *r;
char *key, *cp, *tmp;
int repeat, width, tablewidth, keywidth;
char *key, *cp, *tmp, *start, *empty;
key_code prefix, only = KEYC_UNKNOWN;
int repeat, width, tablewidth, keywidth, found = 0;
size_t tmpsize, tmpused, cplen;
if (self->entry == &cmd_list_commands_entry)
return (cmd_list_keys_commands(self, item));
if (args->argc != 0) {
only = key_string_lookup_string(args->argv[0]);
if (only == KEYC_UNKNOWN) {
cmdq_error(item, "invalid key: %s", args->argv[0]);
return (CMD_RETURN_ERROR);
}
}
tablename = args_get(args, 'T');
if (tablename != NULL && key_bindings_get_table(tablename, 0) == NULL) {
cmdq_error(item, "table %s doesn't exist", tablename);
return (CMD_RETURN_ERROR);
}
if (args_has(args, 'N')) {
if (tablename == NULL) {
start = cmd_list_keys_get_prefix(args, &prefix);
keywidth = cmd_list_keys_get_width("root", only);
if (prefix != KEYC_NONE) {
width = cmd_list_keys_get_width("prefix", only);
if (width == 0)
prefix = KEYC_NONE;
else if (width > keywidth)
keywidth = width;
}
empty = utf8_padcstr("", utf8_cstrwidth(start));
found = cmd_list_keys_print_notes(item, args, "root",
keywidth, only, empty);
if (prefix != KEYC_NONE) {
if (cmd_list_keys_print_notes(item, args,
"prefix", keywidth, only, start))
found = 1;
}
free(empty);
} else {
if (args_has(args, 'P'))
start = xstrdup(args_get(args, 'P'));
else
start = xstrdup("");
keywidth = cmd_list_keys_get_width(tablename, only);
found = cmd_list_keys_print_notes(item, args, tablename,
keywidth, only, start);
}
free(start);
goto out;
}
repeat = 0;
tablewidth = keywidth = 0;
table = key_bindings_first_table ();
@ -84,6 +215,10 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
}
bd = key_bindings_first(table);
while (bd != NULL) {
if (only != KEYC_UNKNOWN && bd->key != only) {
bd = key_bindings_next(table, bd);
continue;
}
key = args_escape(key_string_lookup_key(bd->key));
if (bd->flags & KEY_BINDING_REPEAT)
@ -113,6 +248,11 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
}
bd = key_bindings_first(table);
while (bd != NULL) {
if (only != KEYC_UNKNOWN && bd->key != only) {
bd = key_bindings_next(table, bd);
continue;
}
found = 1;
key = args_escape(key_string_lookup_key(bd->key));
if (!repeat)
@ -162,19 +302,27 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
free(tmp);
out:
if (only != KEYC_UNKNOWN && !found) {
cmdq_error(item, "unknown key: %s", args->argv[0]);
return (CMD_RETURN_ERROR);
}
return (CMD_RETURN_NORMAL);
}
static enum cmd_retval
cmd_list_keys_commands(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct args *args = self->args;
const struct cmd_entry **entryp;
const struct cmd_entry *entry;
struct format_tree *ft;
const char *template, *s;
const char *template, *s, *command = NULL;
char *line;
if (args->argc != 0)
command = args->argv[0];
if ((template = args_get(args, 'F')) == NULL) {
template = "#{command_list_name}"
"#{?command_list_alias, (#{command_list_alias}),} "
@ -186,6 +334,11 @@ cmd_list_keys_commands(struct cmd *self, struct cmdq_item *item)
for (entryp = cmd_table; *entryp != NULL; entryp++) {
entry = *entryp;
if (command != NULL &&
(strcmp(entry->name, command) != 0 &&
(entry->alias == NULL ||
strcmp(entry->alias, command) != 0)))
continue;
format_add(ft, "command_list_name", "%s", entry->name);
if (entry->alias != NULL)

View File

@ -130,7 +130,7 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "size too small or too big");
return (CMD_RETURN_ERROR);
}
tty_set_size(&c->tty, x, y);
tty_set_size(&c->tty, x, y, 0, 0);
c->flags |= CLIENT_SIZECHANGED;
recalculate_sizes();
}

View File

@ -19,6 +19,7 @@
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "tmux.h"
@ -55,10 +56,11 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
struct window *w = wl->window;
struct client *c = item->client;
struct session *s = item->target.s;
const char *errstr;
char *cause;
const char *errstr, *p;
char *cause, *copy;
u_int adjust;
int x, y;
int x, y, percentage;
size_t plen;
if (args_has(args, 'M')) {
if (cmd_mouse_window(&shared->mouse, &s) == NULL)
@ -91,21 +93,58 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
}
}
if (args_has(args, 'x')) {
x = args_strtonum(args, 'x', PANE_MINIMUM, INT_MAX, &cause);
if (cause != NULL) {
cmdq_error(item, "width %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
if ((p = args_get(args, 'x')) != NULL) {
plen = strlen(p);
if (p[plen - 1] == '%') {
copy = xstrdup(p);
copy[plen - 1] = '\0';
percentage = strtonum(copy, 0, INT_MAX, &errstr);
free(copy);
if (errstr != NULL) {
cmdq_error(item, "width %s", errstr);
return (CMD_RETURN_ERROR);
}
x = (w->sx * percentage) / 100;
if (x < PANE_MINIMUM)
x = PANE_MINIMUM;
if (x > INT_MAX)
x = INT_MAX;
} else {
x = args_strtonum(args, 'x', PANE_MINIMUM, INT_MAX,
&cause);
if (cause != NULL) {
cmdq_error(item, "width %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
}
layout_resize_pane_to(wp, LAYOUT_LEFTRIGHT, x);
}
if (args_has(args, 'y')) {
y = args_strtonum(args, 'y', PANE_MINIMUM, INT_MAX, &cause);
if (cause != NULL) {
cmdq_error(item, "height %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
if ((p = args_get(args, 'y')) != NULL) {
plen = strlen(p);
if (p[plen - 1] == '%') {
copy = xstrdup(p);
copy[plen - 1] = '\0';
percentage = strtonum(copy, 0, INT_MAX, &errstr);
free(copy);
if (errstr != NULL) {
cmdq_error(item, "height %s", errstr);
return (CMD_RETURN_ERROR);
}
y = (w->sy * percentage) / 100;
if (y < PANE_MINIMUM)
y = PANE_MINIMUM;
if (y > INT_MAX)
y = INT_MAX;
}
else {
y = args_strtonum(args, 'y', PANE_MINIMUM, INT_MAX,
&cause);
if (cause != NULL) {
cmdq_error(item, "height %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
}
layout_resize_pane_to(wp, LAYOUT_TOPBOTTOM, y);
}

View File

@ -53,6 +53,7 @@ cmd_resize_window_exec(struct cmd *self, struct cmdq_item *item)
const char *errstr;
char *cause;
u_int adjust, sx, sy;
int xpixel = -1, ypixel = -1;
if (args->argc == 0)
adjust = 1;
@ -97,13 +98,16 @@ cmd_resize_window_exec(struct cmd *self, struct cmdq_item *item)
} else if (args_has(args, 'D'))
sy += adjust;
if (args_has(args, 'A'))
default_window_size(s, w, &sx, &sy, WINDOW_SIZE_LARGEST);
else if (args_has(args, 'a'))
default_window_size(s, w, &sx, &sy, WINDOW_SIZE_SMALLEST);
if (args_has(args, 'A')) {
default_window_size(NULL, s, w, &sx, &sy, &xpixel, &ypixel,
WINDOW_SIZE_LARGEST);
} else if (args_has(args, 'a')) {
default_window_size(NULL, s, w, &sx, &sy, &xpixel, &ypixel,
WINDOW_SIZE_SMALLEST);
}
options_set_number(w->options, "window-size", WINDOW_SIZE_MANUAL);
resize_window(w, sx, sy);
resize_window(w, sx, sy, xpixel, ypixel);
return (CMD_RETURN_NORMAL);
}

View File

@ -59,6 +59,7 @@ cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item)
sc.item = item;
sc.s = s;
sc.wl = wl;
sc.c = cmd_find_client(item, NULL, 1);
sc.name = NULL;
sc.argc = args->argc;

View File

@ -31,8 +31,8 @@ const struct cmd_entry cmd_rotate_window_entry = {
.name = "rotate-window",
.alias = "rotatew",
.args = { "Dt:U", 0, 0 },
.usage = "[-DU] " CMD_TARGET_WINDOW_USAGE,
.args = { "Dt:UZ", 0, 0 },
.usage = "[-DUZ] " CMD_TARGET_WINDOW_USAGE,
.target = { 't', CMD_FIND_WINDOW, 0 },
@ -50,7 +50,7 @@ cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item)
struct layout_cell *lc;
u_int sx, sy, xoff, yoff;
server_unzoom_window(w);
window_push_zoom(w, args_has(self->args, 'Z'));
if (args_has(self->args, 'D')) {
wp = TAILQ_LAST(&w->panes, window_panes);
@ -77,9 +77,6 @@ cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item)
if ((wp = TAILQ_PREV(w->active, window_panes, entry)) == NULL)
wp = TAILQ_LAST(&w->panes, window_panes);
window_set_active_pane(w, wp, 1);
cmd_find_from_winlink_pane(current, wl, wp, 0);
server_redraw_window(w);
} else {
wp = TAILQ_FIRST(&w->panes);
TAILQ_REMOVE(&w->panes, wp, entry);
@ -105,10 +102,12 @@ cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item)
if ((wp = TAILQ_NEXT(w->active, entry)) == NULL)
wp = TAILQ_FIRST(&w->panes);
window_set_active_pane(w, wp, 1);
cmd_find_from_winlink_pane(current, wl, wp, 0);
server_redraw_window(w);
}
window_set_active_pane(w, wp, 1);
cmd_find_from_winlink_pane(current, wl, wp, 0);
window_pop_zoom(w);
server_redraw_window(w);
return (CMD_RETURN_NORMAL);
}

View File

@ -55,6 +55,20 @@ const struct cmd_entry cmd_show_buffer_entry = {
.exec = cmd_save_buffer_exec
};
static void
cmd_save_buffer_done(__unused struct client *c, const char *path, int error,
__unused int closed, __unused struct evbuffer *buffer, void *data)
{
struct cmdq_item *item = data;
if (!closed)
return;
if (error != 0)
cmdq_error(item, "%s: %s", path, strerror(error));
cmdq_continue(item);
}
static enum cmd_retval
cmd_save_buffer_exec(struct cmd *self, struct cmdq_item *item)
{
@ -64,18 +78,17 @@ cmd_save_buffer_exec(struct cmd *self, struct cmdq_item *item)
struct winlink *wl = item->target.wl;
struct window_pane *wp = item->target.wp;
struct paste_buffer *pb;
const char *bufname, *bufdata, *start, *end, *flags;
char *msg, *path, *file;
size_t size, used, msglen, bufsize;
FILE *f;
int flags;
const char *bufname = args_get(args, 'b'), *bufdata;
size_t bufsize;
char *path;
if (!args_has(args, 'b')) {
if (bufname == NULL) {
if ((pb = paste_get_top(NULL)) == NULL) {
cmdq_error(item, "no buffers");
return (CMD_RETURN_ERROR);
}
} else {
bufname = args_get(args, 'b');
pb = paste_get_name(bufname);
if (pb == NULL) {
cmdq_error(item, "no buffer %s", bufname);
@ -88,74 +101,13 @@ cmd_save_buffer_exec(struct cmd *self, struct cmdq_item *item)
path = xstrdup("-");
else
path = format_single(item, args->argv[0], c, s, wl, wp);
if (strcmp(path, "-") == 0) {
free(path);
c = item->client;
if (c == NULL) {
cmdq_error(item, "can't write to stdout");
return (CMD_RETURN_ERROR);
}
if (c->session == NULL || (c->flags & CLIENT_CONTROL))
goto do_stdout;
goto do_print;
}
flags = "wb";
if (args_has(self->args, 'a'))
flags = "ab";
file = server_client_get_path(item->client, path);
flags = O_APPEND;
else
flags = 0;
file_write(item->client, path, flags, bufdata, bufsize,
cmd_save_buffer_done, item);
free(path);
f = fopen(file, flags);
if (f == NULL) {
cmdq_error(item, "%s: %s", file, strerror(errno));
free(file);
return (CMD_RETURN_ERROR);
}
if (fwrite(bufdata, 1, bufsize, f) != bufsize) {
cmdq_error(item, "%s: write error", file);
fclose(f);
free(file);
return (CMD_RETURN_ERROR);
}
fclose(f);
free(file);
return (CMD_RETURN_NORMAL);
do_stdout:
evbuffer_add(c->stdout_data, bufdata, bufsize);
server_client_push_stdout(c);
return (CMD_RETURN_NORMAL);
do_print:
if (bufsize > (INT_MAX / 4) - 1) {
cmdq_error(item, "buffer too big");
return (CMD_RETURN_ERROR);
}
msg = NULL;
used = 0;
while (used != bufsize) {
start = bufdata + used;
end = memchr(start, '\n', bufsize - used);
if (end != NULL)
size = end - start;
else
size = bufsize - used;
msglen = size * 4 + 1;
msg = xrealloc(msg, msglen);
strvisx(msg, start, size, VIS_OCTAL|VIS_TAB);
cmdq_print(item, "%s", msg);
used += size + (end != NULL);
}
free(msg);
return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT);
}

View File

@ -33,8 +33,8 @@ const struct cmd_entry cmd_select_pane_entry = {
.name = "select-pane",
.alias = "selectp",
.args = { "DdegLlMmP:RT:t:U", 0, 0 }, /* -P and -g deprecated */
.usage = "[-DdeLlMmRU] [-T title] " CMD_TARGET_PANE_USAGE,
.args = { "DdegLlMmP:RT:t:UZ", 0, 0 }, /* -P and -g deprecated */
.usage = "[-DdeLlMmRUZ] [-T title] " CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 },
@ -46,8 +46,8 @@ const struct cmd_entry cmd_last_pane_entry = {
.name = "last-pane",
.alias = "lastp",
.args = { "det:", 0, 0 },
.usage = "[-de] " CMD_TARGET_WINDOW_USAGE,
.args = { "det:Z", 0, 0 },
.usage = "[-deZ] " CMD_TARGET_WINDOW_USAGE,
.target = { 't', CMD_FIND_WINDOW, 0 },
@ -111,12 +111,15 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
else if (args_has(self->args, 'd'))
lastwp->flags |= PANE_INPUTOFF;
else {
server_unzoom_window(w);
if (window_push_zoom(w, args_has(self->args, 'Z')))
server_redraw_window(w);
window_redraw_active_switch(w, lastwp);
if (window_set_active_pane(w, lastwp, 1)) {
cmd_find_from_winlink(current, wl, 0);
cmd_select_pane_redraw(w);
}
if (window_pop_zoom(w))
server_redraw_window(w);
}
return (CMD_RETURN_NORMAL);
}
@ -163,17 +166,21 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
}
if (args_has(self->args, 'L')) {
server_unzoom_window(wp->window);
window_push_zoom(w, 1);
wp = window_pane_find_left(wp);
window_pop_zoom(w);
} else if (args_has(self->args, 'R')) {
server_unzoom_window(wp->window);
window_push_zoom(w, 1);
wp = window_pane_find_right(wp);
window_pop_zoom(w);
} else if (args_has(self->args, 'U')) {
server_unzoom_window(wp->window);
window_push_zoom(w, 1);
wp = window_pane_find_up(wp);
window_pop_zoom(w);
} else if (args_has(self->args, 'D')) {
server_unzoom_window(wp->window);
window_push_zoom(w, 1);
wp = window_pane_find_down(wp);
window_pop_zoom(w);
}
if (wp == NULL)
return (CMD_RETURN_NORMAL);
@ -190,21 +197,24 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(self->args, 'T')) {
pane_title = format_single(item, args_get(self->args, 'T'),
c, s, wl, wp);
screen_set_title(&wp->base, pane_title);
server_status_window(wp->window);
if (screen_set_title(&wp->base, pane_title))
server_status_window(wp->window);
free(pane_title);
return (CMD_RETURN_NORMAL);
}
if (wp == w->active)
return (CMD_RETURN_NORMAL);
server_unzoom_window(wp->window);
if (window_push_zoom(w, args_has(self->args, 'Z')))
server_redraw_window(w);
window_redraw_active_switch(w, wp);
if (window_set_active_pane(w, wp, 1)) {
cmd_find_from_winlink_pane(current, wl, wp, 0);
cmdq_insert_hook(s, item, current, "after-select-pane");
cmd_select_pane_redraw(w);
}
if (window_pop_zoom(w))
server_redraw_window(w);
return (CMD_RETURN_NORMAL);
}

View File

@ -31,8 +31,6 @@
static enum cmd_retval cmd_source_file_exec(struct cmd *, struct cmdq_item *);
static enum cmd_retval cmd_source_file_done(struct cmdq_item *, void *);
const struct cmd_entry cmd_source_file_entry = {
.name = "source-file",
.alias = "source",
@ -44,40 +42,130 @@ const struct cmd_entry cmd_source_file_entry = {
.exec = cmd_source_file_exec
};
struct cmd_source_file_data {
struct cmdq_item *item;
int flags;
struct cmdq_item *after;
enum cmd_retval retval;
u_int current;
char **files;
u_int nfiles;
};
static enum cmd_retval
cmd_source_file_complete_cb(struct cmdq_item *item, __unused void *data)
{
cfg_print_causes(item);
return (CMD_RETURN_NORMAL);
}
static void
cmd_source_file_complete(struct client *c, struct cmd_source_file_data *cdata)
{
struct cmdq_item *new_item;
if (cfg_finished) {
if (cdata->retval == CMD_RETURN_ERROR && c->session == NULL)
c->retval = 1;
new_item = cmdq_get_callback(cmd_source_file_complete_cb, NULL);
cmdq_insert_after(cdata->after, new_item);
}
free(cdata->files);
free(cdata);
}
static void
cmd_source_file_done(struct client *c, const char *path, int error,
int closed, struct evbuffer *buffer, void *data)
{
struct cmd_source_file_data *cdata = data;
struct cmdq_item *item = cdata->item;
void *bdata = EVBUFFER_DATA(buffer);
size_t bsize = EVBUFFER_LENGTH(buffer);
u_int n;
struct cmdq_item *new_item;
if (!closed)
return;
if (error != 0)
cmdq_error(item, "%s: %s", path, strerror(error));
else if (bsize != 0) {
if (load_cfg_from_buffer(bdata, bsize, path, c, cdata->after,
cdata->flags, &new_item) < 0)
cdata->retval = CMD_RETURN_ERROR;
else if (new_item != NULL)
cdata->after = new_item;
}
n = ++cdata->current;
if (n < cdata->nfiles)
file_read(c, cdata->files[n], cmd_source_file_done, cdata);
else {
cmd_source_file_complete(c, cdata);
cmdq_continue(item);
}
}
static void
cmd_source_file_add(struct cmd_source_file_data *cdata, const char *path)
{
log_debug("%s: %s", __func__, path);
cdata->files = xreallocarray(cdata->files, cdata->nfiles + 1,
sizeof *cdata->files);
cdata->files[cdata->nfiles++] = xstrdup(path);
}
static enum cmd_retval
cmd_source_file_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
int flags = 0;
struct client *c = item->client;
struct cmdq_item *new_item, *after;
enum cmd_retval retval;
char *pattern, *cwd;
const char *path, *error;
glob_t g;
int i;
u_int j;
struct args *args = self->args;
struct cmd_source_file_data *cdata;
struct client *c = item->client;
enum cmd_retval retval = CMD_RETURN_NORMAL;
char *pattern, *cwd;
const char *path, *error;
glob_t g;
int i, result;
u_int j;
cdata = xcalloc(1, sizeof *cdata);
cdata->item = item;
if (args_has(args, 'q'))
flags |= CMD_PARSE_QUIET;
cdata->flags |= CMD_PARSE_QUIET;
if (args_has(args, 'n'))
flags |= CMD_PARSE_PARSEONLY;
cdata->flags |= CMD_PARSE_PARSEONLY;
if (args_has(args, 'v'))
flags |= CMD_PARSE_VERBOSE;
cdata->flags |= CMD_PARSE_VERBOSE;
utf8_stravis(&cwd, server_client_get_cwd(c, NULL), VIS_GLOB);
retval = CMD_RETURN_NORMAL;
for (i = 0; i < args->argc; i++) {
path = args->argv[i];
if (strcmp(path, "-") == 0) {
cmd_source_file_add(cdata, "-");
continue;
}
if (*path == '/')
pattern = xstrdup(path);
else
xasprintf(&pattern, "%s/%s", cwd, path);
log_debug("%s: %s", __func__, pattern);
if (glob(pattern, 0, NULL, &g) != 0) {
error = strerror(errno);
if (errno != ENOENT || (~flags & CMD_PARSE_QUIET)) {
if ((result = glob(pattern, 0, NULL, &g)) != 0) {
if (result != GLOB_NOMATCH ||
(~cdata->flags & CMD_PARSE_QUIET)) {
if (result == GLOB_NOMATCH)
error = strerror(ENOENT);
else if (result == GLOB_NOSPACE)
error = strerror(ENOMEM);
else
error = strerror(EINVAL);
cmdq_error(item, "%s: %s", path, error);
retval = CMD_RETURN_ERROR;
}
@ -86,30 +174,19 @@ cmd_source_file_exec(struct cmd *self, struct cmdq_item *item)
}
free(pattern);
after = item;
for (j = 0; j < g.gl_pathc; j++) {
path = g.gl_pathv[j];
if (load_cfg(path, c, after, flags, &new_item) < 0)
retval = CMD_RETURN_ERROR;
else if (new_item != NULL)
after = new_item;
}
globfree(&g);
}
if (cfg_finished) {
if (retval == CMD_RETURN_ERROR && c->session == NULL)
c->retval = 1;
new_item = cmdq_get_callback(cmd_source_file_done, NULL);
cmdq_insert_after(item, new_item);
for (j = 0; j < g.gl_pathc; j++)
cmd_source_file_add(cdata, g.gl_pathv[j]);
}
cdata->after = item;
cdata->retval = retval;
if (cdata->nfiles != 0) {
file_read(c, cdata->files[0], cmd_source_file_done, cdata);
retval = CMD_RETURN_WAIT;
} else
cmd_source_file_complete(c, cdata);
free(cwd);
return (retval);
}
static enum cmd_retval
cmd_source_file_done(struct cmdq_item *item, __unused void *data)
{
cfg_print_causes(item);
return (CMD_RETURN_NORMAL);
}

View File

@ -32,8 +32,8 @@ const struct cmd_entry cmd_swap_pane_entry = {
.name = "swap-pane",
.alias = "swapp",
.args = { "dDs:t:U", 0, 0 },
.usage = "[-dDU] " CMD_SRCDST_PANE_USAGE,
.args = { "dDs:t:UZ", 0, 0 },
.usage = "[-dDUZ] " CMD_SRCDST_PANE_USAGE,
.source = { 's', CMD_FIND_PANE, CMD_FIND_DEFAULT_MARKED },
.target = { 't', CMD_FIND_PANE, 0 },
@ -45,6 +45,7 @@ const struct cmd_entry cmd_swap_pane_entry = {
static enum cmd_retval
cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = self->args;
struct window *src_w, *dst_w;
struct window_pane *tmp_wp, *src_wp, *dst_wp;
struct layout_cell *src_lc, *dst_lc;
@ -54,23 +55,27 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
dst_wp = item->target.wp;
src_w = item->source.wl->window;
src_wp = item->source.wp;
server_unzoom_window(dst_w);
if (args_has(self->args, 'D')) {
if (window_push_zoom(dst_w, args_has(args, 'Z')))
server_redraw_window(dst_w);
if (args_has(args, 'D')) {
src_w = dst_w;
src_wp = TAILQ_NEXT(dst_wp, entry);
if (src_wp == NULL)
src_wp = TAILQ_FIRST(&dst_w->panes);
} else if (args_has(self->args, 'U')) {
} else if (args_has(args, 'U')) {
src_w = dst_w;
src_wp = TAILQ_PREV(dst_wp, window_panes, entry);
if (src_wp == NULL)
src_wp = TAILQ_LAST(&dst_w->panes, window_panes);
}
server_unzoom_window(src_w);
if (src_w != dst_w && window_push_zoom(src_w, args_has(args, 'Z')))
server_redraw_window(src_w);
if (src_wp == dst_wp)
return (CMD_RETURN_NORMAL);
goto out;
tmp_wp = TAILQ_PREV(dst_wp, window_panes, entry);
TAILQ_REMOVE(&dst_w->panes, dst_wp, entry);
@ -103,7 +108,7 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
dst_wp->xoff = xoff; dst_wp->yoff = yoff;
window_pane_resize(dst_wp, sx, sy);
if (!args_has(self->args, 'd')) {
if (!args_has(args, 'd')) {
if (src_w != dst_w) {
window_set_active_pane(src_w, dst_wp, 1);
window_set_active_pane(dst_w, src_wp, 1);
@ -126,5 +131,10 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
server_redraw_window(src_w);
server_redraw_window(dst_w);
out:
if (window_pop_zoom(src_w))
server_redraw_window(src_w);
if (src_w != dst_w && window_pop_zoom(dst_w))
server_redraw_window(dst_w);
return (CMD_RETURN_NORMAL);
}

View File

@ -34,8 +34,8 @@ const struct cmd_entry cmd_switch_client_entry = {
.name = "switch-client",
.alias = "switchc",
.args = { "lc:Enpt:rT:", 0, 0 },
.usage = "[-Elnpr] [-c target-client] [-t target-session] "
.args = { "lc:Enpt:rT:Z", 0, 0 },
.usage = "[-ElnprZ] [-c target-client] [-t target-session] "
"[-T key-table]",
/* -t is special */
@ -54,6 +54,7 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
struct client *c;
struct session *s;
struct winlink *wl;
struct window *w;
struct window_pane *wp;
const char *tablename;
struct key_table *table;
@ -72,6 +73,7 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR);
s = item->target.s;
wl = item->target.wl;
w = wl->window;
wp = item->target.wp;
if (args_has(args, 'r'))
@ -112,12 +114,15 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
} else {
if (item->client == NULL)
return (CMD_RETURN_NORMAL);
if (wl != NULL && wp != NULL) {
if (window_push_zoom(w, args_has(self->args, 'Z')))
server_redraw_window(w);
window_redraw_active_switch(w, wp);
window_set_active_pane(w, wp, 1);
if (window_pop_zoom(w))
server_redraw_window(w);
}
if (wl != NULL) {
server_unzoom_window(wl->window);
if (wp != NULL) {
window_redraw_active_switch(wp->window, wp);
window_set_active_pane(wp->window, wp, 1);
}
session_set_current(s, wl);
cmd_find_from_session(&item->shared->current, s, 0);
}
@ -137,10 +142,11 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
session_update_activity(s, NULL);
gettimeofday(&s->last_attached_time, NULL);
recalculate_sizes();
server_check_unattached();
server_redraw_client(c);
s->curw->flags &= ~WINLINK_ALERTFLAGS;
s->curw->window->latest = c;
recalculate_sizes();
alerts_check_session(s);
return (CMD_RETURN_NORMAL);

View File

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

View File

@ -21,6 +21,7 @@
#include <sys/ioctl.h>
#include <sys/uio.h>
#include <fnmatch.h>
#include <limits.h>
#include <stdio.h>
#include <termios.h>
@ -61,12 +62,31 @@ void warn(const char *, ...);
void warnx(const char *, ...);
#endif
#ifndef HAVE_PATHS_H
#define _PATH_BSHELL "/bin/sh"
#define _PATH_TMP "/tmp/"
#ifdef HAVE_PATHS_H
#include <paths.h>
#endif
#ifndef _PATH_BSHELL
#define _PATH_BSHELL "/bin/sh"
#endif
#ifndef _PATH_TMP
#define _PATH_TMP "/tmp/"
#endif
#ifndef _PATH_DEVNULL
#define _PATH_DEVNULL "/dev/null"
#endif
#ifndef _PATH_TTY
#define _PATH_TTY "/dev/tty"
#endif
#ifndef _PATH_DEV
#define _PATH_DEV "/dev/"
#endif
#ifndef _PATH_DEFPATH
#define _PATH_DEFPATH "/usr/bin:/bin"
#endif
@ -98,10 +118,6 @@ void warnx(const char *, ...);
#include "compat/bitstring.h"
#endif
#ifdef HAVE_PATHS_H
#include <paths.h>
#endif
#ifdef HAVE_LIBUTIL_H
#include <libutil.h>
#endif
@ -154,6 +170,14 @@ void warnx(const char *, ...);
#define O_DIRECTORY 0
#endif
#ifndef FNM_CASEFOLD
#ifdef FNM_IGNORECASE
#define FNM_CASEFOLD FNM_IGNORECASE
#else
#define FNM_CASEFOLD 0
#endif
#endif
#ifndef INFTIM
#define INFTIM -1
#endif
@ -346,7 +370,6 @@ int utf8proc_mbtowc(wchar_t *, const char *, size_t);
int utf8proc_wctomb(char *, wchar_t);
#endif
#ifndef HAVE_GETOPT
/* getopt.c */
extern int BSDopterr;
extern int BSDoptind;
@ -360,6 +383,5 @@ int BSDgetopt(int, char *const *, const char *);
#define optopt BSDoptopt
#define optreset BSDoptreset
#define optarg BSDoptarg
#endif
#endif /* COMPAT_H */

View File

@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for tmux 3.0a.
# Generated by GNU Autoconf 2.69 for tmux 3.1c.
#
#
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@ -577,8 +577,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='tmux'
PACKAGE_TARNAME='tmux'
PACKAGE_VERSION='3.0a'
PACKAGE_STRING='tmux 3.0a'
PACKAGE_VERSION='3.1c'
PACKAGE_STRING='tmux 3.1c'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
@ -744,6 +744,7 @@ infodir
docdir
oldincludedir
includedir
runstatedir
localstatedir
sharedstatedir
sysconfdir
@ -831,6 +832,7 @@ datadir='${datarootdir}'
sysconfdir='${prefix}/etc'
sharedstatedir='${prefix}/com'
localstatedir='${prefix}/var'
runstatedir='${localstatedir}/run'
includedir='${prefix}/include'
oldincludedir='/usr/include'
docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
@ -1083,6 +1085,15 @@ do
| -silent | --silent | --silen | --sile | --sil)
silent=yes ;;
-runstatedir | --runstatedir | --runstatedi | --runstated \
| --runstate | --runstat | --runsta | --runst | --runs \
| --run | --ru | --r)
ac_prev=runstatedir ;;
-runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
| --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
| --run=* | --ru=* | --r=*)
runstatedir=$ac_optarg ;;
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
ac_prev=sbindir ;;
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@ -1220,7 +1231,7 @@ fi
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
datadir sysconfdir sharedstatedir localstatedir includedir \
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
libdir localedir mandir
libdir localedir mandir runstatedir
do
eval ac_val=\$$ac_var
# Remove trailing slashes.
@ -1333,7 +1344,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures tmux 3.0a to adapt to many kinds of systems.
\`configure' configures tmux 3.1c to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1373,6 +1384,7 @@ Fine tuning of the installation directories:
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
--runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
--libdir=DIR object code libraries [EPREFIX/lib]
--includedir=DIR C header files [PREFIX/include]
--oldincludedir=DIR C header files for non-gcc [/usr/include]
@ -1403,7 +1415,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of tmux 3.0a:";;
short | recursive ) echo "Configuration of tmux 3.1c:";;
esac
cat <<\_ACEOF
@ -1524,7 +1536,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
tmux configure 3.0a
tmux configure 3.1c
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@ -1935,7 +1947,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by tmux $as_me 3.0a, which was
It was created by tmux $as_me 3.1c, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@ -2801,7 +2813,7 @@ fi
# Define the identity of the package.
PACKAGE='tmux'
VERSION='3.0a'
VERSION='3.1c'
cat >>confdefs.h <<_ACEOF
@ -5360,6 +5372,17 @@ if test "$ac_res" != no; then :
fi
# Always use our getopt because 1) glibc's doesn't enforce argument order 2)
# musl does not set optarg to NULL for flags without arguments (although it is
# not required to, but it is helpful) 3) there are probably other weird
# implementations.
case " $LIBOBJS " in
*" getopt.$ac_objext "* ) ;;
*) LIBOBJS="$LIBOBJS getopt.$ac_objext"
;;
esac
# Look for libevent.
pkg_failed=no
@ -6656,110 +6679,6 @@ esac
fi
# Look for getopt. glibc's getopt does not enforce argument order and the ways
# of making it do so are stupid, so just use our own instead.
ac_fn_c_check_func "$LINENO" "getopt" "ac_cv_func_getopt"
if test "x$ac_cv_func_getopt" = xyes; then :
found_getopt=yes
else
found_getopt=no
fi
if test "x$found_getopt" != xno; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if getopt is suitable" >&5
$as_echo_n "checking if getopt is suitable... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <features.h>
#ifdef __GLIBC__
yes
#endif
_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
$EGREP "yes" >/dev/null 2>&1; then :
found_getopt=no
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }
fi
rm -f conftest*
fi
if test "x$found_getopt" != xno; then
ac_fn_c_check_decl "$LINENO" "optarg" "ac_cv_have_decl_optarg" "
#include <unistd.h>
"
if test "x$ac_cv_have_decl_optarg" = xyes; then :
ac_have_decl=1
else
ac_have_decl=0
fi
cat >>confdefs.h <<_ACEOF
#define HAVE_DECL_OPTARG $ac_have_decl
_ACEOF
if test $ac_have_decl = 1; then :
else
found_getopt=no
fi
ac_fn_c_check_decl "$LINENO" "optind" "ac_cv_have_decl_optind" "
#include <unistd.h>
"
if test "x$ac_cv_have_decl_optind" = xyes; then :
ac_have_decl=1
else
ac_have_decl=0
fi
cat >>confdefs.h <<_ACEOF
#define HAVE_DECL_OPTIND $ac_have_decl
_ACEOF
if test $ac_have_decl = 1; then :
else
found_getopt=no
fi
ac_fn_c_check_decl "$LINENO" "optreset" "ac_cv_have_decl_optreset" "
#include <unistd.h>
"
if test "x$ac_cv_have_decl_optreset" = xyes; then :
ac_have_decl=1
else
ac_have_decl=0
fi
cat >>confdefs.h <<_ACEOF
#define HAVE_DECL_OPTRESET $ac_have_decl
_ACEOF
if test $ac_have_decl = 1; then :
else
found_getopt=no
fi
fi
if test "x$found_getopt" != xno; then
$as_echo "#define HAVE_GETOPT 1" >>confdefs.h
else
case " $LIBOBJS " in
*" getopt.$ac_objext "* ) ;;
*) LIBOBJS="$LIBOBJS getopt.$ac_objext"
;;
esac
fi
# Look for fdforkpty and forkpty in libutil.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing fdforkpty" >&5
$as_echo_n "checking for library containing fdforkpty... " >&6; }
@ -7899,7 +7818,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by tmux $as_me 3.0a, which was
This file was extended by tmux $as_me 3.1c, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@ -7956,7 +7875,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
tmux config.status 3.0a
tmux config.status 3.1c
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"

View File

@ -1,6 +1,6 @@
# configure.ac
AC_INIT([tmux], 3.0a)
AC_INIT([tmux], 3.1c)
AC_PREREQ([2.60])
AC_CONFIG_AUX_DIR(etc)
@ -125,6 +125,12 @@ AC_FUNC_STRNLEN
# Look for clock_gettime. Must come before event_init.
AC_SEARCH_LIBS(clock_gettime, rt)
# Always use our getopt because 1) glibc's doesn't enforce argument order 2)
# musl does not set optarg to NULL for flags without arguments (although it is
# not required to, but it is helpful) 3) there are probably other weird
# implementations.
AC_LIBOBJ(getopt)
# Look for libevent.
PKG_CHECK_MODULES(
LIBEVENT,
@ -424,40 +430,6 @@ else
AC_LIBOBJ(unvis)
fi
# Look for getopt. glibc's getopt does not enforce argument order and the ways
# of making it do so are stupid, so just use our own instead.
AC_CHECK_FUNC(getopt, found_getopt=yes, found_getopt=no)
if test "x$found_getopt" != xno; then
AC_MSG_CHECKING(if getopt is suitable)
AC_EGREP_CPP(
yes,
[
#include <features.h>
#ifdef __GLIBC__
yes
#endif
],
[
found_getopt=no
AC_MSG_RESULT(no)
],
AC_MSG_RESULT(yes))
fi
if test "x$found_getopt" != xno; then
AC_CHECK_DECLS(
[optarg, optind, optreset],
,
found_getopt=no,
[
#include <unistd.h>
])
fi
if test "x$found_getopt" != xno; then
AC_DEFINE(HAVE_GETOPT)
else
AC_LIBOBJ(getopt)
fi
# Look for fdforkpty and forkpty in libutil.
AC_SEARCH_LIBS(fdforkpty, util, found_fdforkpty=yes, found_fdforkpty=no)
if test "x$found_fdforkpty" = xyes; then

View File

@ -54,7 +54,8 @@ control_notify_input(struct client *c, struct window_pane *wp,
else
evbuffer_add_printf(message, "%c", buf[i]);
}
control_write_buffer(c, message);
evbuffer_add(message, "", 1);
control_write(c, "%s", EVBUFFER_DATA(message));
evbuffer_free(message);
}
}

View File

@ -30,23 +30,12 @@
void
control_write(struct client *c, const char *fmt, ...)
{
va_list ap;
va_list ap;
va_start(ap, fmt);
evbuffer_add_vprintf(c->stdout_data, fmt, ap);
file_vprint(c, fmt, ap);
file_print(c, "\n");
va_end(ap);
evbuffer_add(c->stdout_data, "\n", 1);
server_client_push_stdout(c);
}
/* Write a buffer, adding a terminal newline. Empties buffer. */
void
control_write_buffer(struct client *c, struct evbuffer *buffer)
{
evbuffer_add_buffer(c->stdout_data, buffer);
evbuffer_add(c->stdout_data, "\n", 1);
server_client_push_stdout(c);
}
/* Control error callback. */
@ -65,20 +54,22 @@ control_error(struct cmdq_item *item, void *data)
}
/* Control input callback. Read lines and fire commands. */
void
control_callback(struct client *c, int closed, __unused void *data)
static void
control_callback(__unused struct client *c, __unused const char *path,
int error, int closed, struct evbuffer *buffer, __unused void *data)
{
char *line;
struct cmdq_item *item;
struct cmd_parse_result *pr;
if (closed)
if (closed || error != 0)
c->flags |= CLIENT_EXIT;
for (;;) {
line = evbuffer_readln(c->stdin_data, NULL, EVBUFFER_EOL_LF);
line = evbuffer_readln(buffer, NULL, EVBUFFER_EOL_LF);
if (line == NULL)
break;
log_debug("%s: %s", __func__, line);
if (*line == '\0') { /* empty line exit */
free(line);
c->flags |= CLIENT_EXIT;
@ -104,3 +95,12 @@ control_callback(struct client *c, int closed, __unused void *data)
free(line);
}
}
void
control_start(struct client *c)
{
file_read(c, "-", control_callback, c);
if (c->flags & CLIENT_CONTROLCONTROL)
file_print(c, "\033P1000p");
}

413
external/bsd/tmux/dist/file.c vendored Normal file
View File

@ -0,0 +1,413 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "tmux.h"
static int file_next_stream = 3;
RB_GENERATE(client_files, client_file, entry, file_cmp);
static char *
file_get_path(struct client *c, const char *file)
{
char *path;
if (*file == '/')
path = xstrdup(file);
else
xasprintf(&path, "%s/%s", server_client_get_cwd(c, NULL), file);
return (path);
}
int
file_cmp(struct client_file *cf1, struct client_file *cf2)
{
if (cf1->stream < cf2->stream)
return (-1);
if (cf1->stream > cf2->stream)
return (1);
return (0);
}
struct client_file *
file_create(struct client *c, int stream, client_file_cb cb, void *cbdata)
{
struct client_file *cf;
cf = xcalloc(1, sizeof *cf);
cf->c = c;
cf->references = 1;
cf->stream = stream;
cf->buffer = evbuffer_new();
if (cf->buffer == NULL)
fatalx("out of memory");
cf->cb = cb;
cf->data = cbdata;
if (cf->c != NULL) {
RB_INSERT(client_files, &cf->c->files, cf);
cf->c->references++;
}
return (cf);
}
void
file_free(struct client_file *cf)
{
if (--cf->references != 0)
return;
evbuffer_free(cf->buffer);
free(cf->path);
if (cf->c != NULL) {
RB_REMOVE(client_files, &cf->c->files, cf);
server_client_unref(cf->c);
}
free(cf);
}
static void
file_fire_done_cb(__unused int fd, __unused short events, void *arg)
{
struct client_file *cf = arg;
struct client *c = cf->c;
if (cf->cb != NULL && (c == NULL || (~c->flags & CLIENT_DEAD)))
cf->cb(c, cf->path, cf->error, 1, cf->buffer, cf->data);
file_free(cf);
}
void
file_fire_done(struct client_file *cf)
{
event_once(-1, EV_TIMEOUT, file_fire_done_cb, cf, NULL);
}
void
file_fire_read(struct client_file *cf)
{
struct client *c = cf->c;
if (cf->cb != NULL)
cf->cb(c, cf->path, cf->error, 0, cf->buffer, cf->data);
}
int
file_can_print(struct client *c)
{
if (c == NULL)
return (0);
if (c->session != NULL && (~c->flags & CLIENT_CONTROL))
return (0);
return (1);
}
void
file_print(struct client *c, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
file_vprint(c, fmt, ap);
va_end(ap);
}
void
file_vprint(struct client *c, const char *fmt, va_list ap)
{
struct client_file find, *cf;
struct msg_write_open msg;
if (!file_can_print(c))
return;
find.stream = 1;
if ((cf = RB_FIND(client_files, &c->files, &find)) == NULL) {
cf = file_create(c, 1, NULL, NULL);
cf->path = xstrdup("-");
evbuffer_add_vprintf(cf->buffer, fmt, ap);
msg.stream = 1;
msg.fd = STDOUT_FILENO;
msg.flags = 0;
proc_send(c->peer, MSG_WRITE_OPEN, -1, &msg, sizeof msg);
} else {
evbuffer_add_vprintf(cf->buffer, fmt, ap);
file_push(cf);
}
}
void
file_print_buffer(struct client *c, void *data, size_t size)
{
struct client_file find, *cf;
struct msg_write_open msg;
if (!file_can_print(c))
return;
find.stream = 1;
if ((cf = RB_FIND(client_files, &c->files, &find)) == NULL) {
cf = file_create(c, 1, NULL, NULL);
cf->path = xstrdup("-");
evbuffer_add(cf->buffer, data, size);
msg.stream = 1;
msg.fd = STDOUT_FILENO;
msg.flags = 0;
proc_send(c->peer, MSG_WRITE_OPEN, -1, &msg, sizeof msg);
} else {
evbuffer_add(cf->buffer, data, size);
file_push(cf);
}
}
void
file_error(struct client *c, const char *fmt, ...)
{
struct client_file find, *cf;
struct msg_write_open msg;
va_list ap;
if (!file_can_print(c))
return;
va_start(ap, fmt);
find.stream = 2;
if ((cf = RB_FIND(client_files, &c->files, &find)) == NULL) {
cf = file_create(c, 2, NULL, NULL);
cf->path = xstrdup("-");
evbuffer_add_vprintf(cf->buffer, fmt, ap);
msg.stream = 2;
msg.fd = STDERR_FILENO;
msg.flags = 0;
proc_send(c->peer, MSG_WRITE_OPEN, -1, &msg, sizeof msg);
} else {
evbuffer_add_vprintf(cf->buffer, fmt, ap);
file_push(cf);
}
va_end(ap);
}
void
file_write(struct client *c, const char *path, int flags, const void *bdata,
size_t bsize, client_file_cb cb, void *cbdata)
{
struct client_file *cf;
FILE *f;
struct msg_write_open *msg;
size_t msglen;
int fd = -1;
const char *mode;
if (strcmp(path, "-") == 0) {
cf = file_create(c, file_next_stream++, cb, cbdata);
cf->path = xstrdup("-");
fd = STDOUT_FILENO;
if (c == NULL || c->flags & CLIENT_ATTACHED) {
cf->error = EBADF;
goto done;
}
goto skip;
}
cf = file_create(c, file_next_stream++, cb, cbdata);
cf->path = file_get_path(c, path);
if (c == NULL || c->flags & CLIENT_ATTACHED) {
if (flags & O_APPEND)
mode = "ab";
else
mode = "wb";
f = fopen(cf->path, mode);
if (f == NULL) {
cf->error = errno;
goto done;
}
if (fwrite(bdata, 1, bsize, f) != bsize) {
fclose(f);
cf->error = EIO;
goto done;
}
fclose(f);
goto done;
}
skip:
evbuffer_add(cf->buffer, bdata, bsize);
msglen = strlen(cf->path) + 1 + sizeof *msg;
if (msglen > MAX_IMSGSIZE - IMSG_HEADER_SIZE) {
cf->error = E2BIG;
goto done;
}
msg = xmalloc(msglen);
msg->stream = cf->stream;
msg->fd = fd;
msg->flags = flags;
memcpy(msg + 1, cf->path, msglen - sizeof *msg);
if (proc_send(c->peer, MSG_WRITE_OPEN, -1, msg, msglen) != 0) {
free(msg);
cf->error = EINVAL;
goto done;
}
free(msg);
return;
done:
file_fire_done(cf);
}
void
file_read(struct client *c, const char *path, client_file_cb cb, void *cbdata)
{
struct client_file *cf;
FILE *f;
struct msg_read_open *msg;
size_t msglen, size;
int fd = -1;
char buffer[BUFSIZ];
if (strcmp(path, "-") == 0) {
cf = file_create(c, file_next_stream++, cb, cbdata);
cf->path = xstrdup("-");
fd = STDIN_FILENO;
if (c == NULL || c->flags & CLIENT_ATTACHED) {
cf->error = EBADF;
goto done;
}
goto skip;
}
cf = file_create(c, file_next_stream++, cb, cbdata);
cf->path = file_get_path(c, path);
if (c == NULL || c->flags & CLIENT_ATTACHED) {
f = fopen(cf->path, "rb");
if (f == NULL) {
cf->error = errno;
goto done;
}
for (;;) {
size = fread(buffer, 1, sizeof buffer, f);
if (evbuffer_add(cf->buffer, buffer, size) != 0) {
cf->error = ENOMEM;
goto done;
}
if (size != sizeof buffer)
break;
}
if (ferror(f)) {
cf->error = EIO;
goto done;
}
fclose(f);
goto done;
}
skip:
msglen = strlen(cf->path) + 1 + sizeof *msg;
if (msglen > MAX_IMSGSIZE - IMSG_HEADER_SIZE) {
cf->error = E2BIG;
goto done;
}
msg = xmalloc(msglen);
msg->stream = cf->stream;
msg->fd = fd;
memcpy(msg + 1, cf->path, msglen - sizeof *msg);
if (proc_send(c->peer, MSG_READ_OPEN, -1, msg, msglen) != 0) {
free(msg);
cf->error = EINVAL;
goto done;
}
free(msg);
return;
done:
file_fire_done(cf);
}
static void
file_push_cb(__unused int fd, __unused short events, void *arg)
{
struct client_file *cf = arg;
struct client *c = cf->c;
if (~c->flags & CLIENT_DEAD)
file_push(cf);
file_free(cf);
}
void
file_push(struct client_file *cf)
{
struct client *c = cf->c;
struct msg_write_data *msg;
size_t msglen, sent, left;
struct msg_write_close close;
msg = xmalloc(sizeof *msg);
left = EVBUFFER_LENGTH(cf->buffer);
while (left != 0) {
sent = left;
if (sent > MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg)
sent = MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg;
msglen = (sizeof *msg) + sent;
msg = xrealloc(msg, msglen);
msg->stream = cf->stream;
memcpy(msg + 1, EVBUFFER_DATA(cf->buffer), sent);
if (proc_send(c->peer, MSG_WRITE, -1, msg, msglen) != 0)
break;
evbuffer_drain(cf->buffer, sent);
left = EVBUFFER_LENGTH(cf->buffer);
log_debug("%s: file %d sent %zu, left %zu", c->name, cf->stream,
sent, left);
}
if (left != 0) {
cf->references++;
event_once(-1, EV_TIMEOUT, file_push_cb, cf, NULL);
} else if (cf->stream > 2) {
close.stream = cf->stream;
proc_send(c->peer, MSG_WRITE_CLOSE, -1, &close, sizeof close);
file_fire_done(cf);
}
free(msg);
}

View File

@ -142,7 +142,8 @@ format_draw_put_list(struct screen_write_ctx *octx,
width -= list_left->cx;
}
if (start + width < list->cx && width > list_right->cx) {
screen_write_cursormove(octx, ocx + offset + width - 1, ocy, 0);
screen_write_cursormove(octx, ocx + offset + width -
list_right->cx, ocy, 0);
screen_write_fast_copy(octx, list_right, 0, 0, list_right->cx,
1);
width -= list_right->cx;
@ -513,8 +514,8 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
int focus_start = -1, focus_end = -1;
int list_state = -1, fill = -1;
enum style_align list_align = STYLE_ALIGN_DEFAULT;
struct grid_cell gc;
struct style sy;
struct grid_cell gc, current_default;
struct style sy, saved_sy;
struct utf8_data *ud = &sy.gc.data;
const char *cp, *end;
enum utf8_state more;
@ -523,7 +524,8 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
struct format_ranges frs;
struct style_range *sr;
style_set(&sy, base);
memcpy(&current_default, base, sizeof current_default);
style_set(&sy, &current_default);
TAILQ_INIT(&frs);
log_debug("%s: %s", __func__, expanded);
@ -535,7 +537,7 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
for (i = 0; i < TOTAL; i++) {
screen_init(&s[i], size, 1, 0);
screen_write_start(&ctx[i], NULL, &s[i]);
screen_write_clearendofline(&ctx[i], base->bg);
screen_write_clearendofline(&ctx[i], current_default.bg);
width[i] = 0;
}
@ -581,7 +583,8 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
goto out;
}
tmp = xstrndup(cp + 2, end - (cp + 2));
if (style_parse(&sy, base, tmp) != 0) {
style_copy(&saved_sy, &sy);
if (style_parse(&sy, &current_default, tmp) != 0) {
log_debug("%s: invalid style '%s'", __func__, tmp);
free(tmp);
cp = end + 1;
@ -595,6 +598,15 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
if (sy.fill != 8)
fill = sy.fill;
/* If this style pushed or popped the default, update it. */
if (sy.default_type == STYLE_DEFAULT_PUSH) {
memcpy(&current_default, &saved_sy.gc, sizeof current_default);
sy.default_type = STYLE_DEFAULT_BASE;
} else if (sy.default_type == STYLE_DEFAULT_POP) {
memcpy(&current_default, base, sizeof current_default);
sy.default_type = STYLE_DEFAULT_BASE;
}
/* Check the list state. */
switch (sy.list) {
case STYLE_LIST_ON:
@ -838,8 +850,10 @@ format_trim_left(const char *expanded, u_int limit)
out += ud.size;
}
width += ud.width;
} else
} else {
cp -= ud.have;
cp++;
}
} else if (*cp > 0x1f && *cp < 0x7f) {
if (width + 1 <= limit)
*out++ = *cp;
@ -885,8 +899,10 @@ format_trim_right(const char *expanded, u_int limit)
out += ud.size;
}
width += ud.width;
} else
} else {
cp -= ud.have;
cp++;
}
} else if (*cp > 0x1f && *cp < 0x7f) {
if (width >= skip)
*out++ = *cp;

View File

@ -159,7 +159,7 @@ key_string_get_modifiers(const char **string)
key_code
key_string_lookup_string(const char *string)
{
static const char *other = "!#()+,-.0123456789:;<=>?'\r\t";
static const char *other = "!#()+,-.0123456789:;<=>'\r\t";
key_code key;
u_int u;
key_code modifiers;
@ -196,7 +196,7 @@ key_string_lookup_string(const char *string)
/* Is this a standard ASCII key? */
if (string[1] == '\0' && (u_char)string[0] <= 127) {
key = (u_char)string[0];
if (key < 32 || key == 127)
if (key < 32)
return (KEYC_UNKNOWN);
} else {
/* Try as a UTF-8 key. */
@ -226,6 +226,8 @@ key_string_lookup_string(const char *string)
key -= 64;
else if (key == 32)
key = 0;
else if (key == '?')
key = 127;
else if (key == 63)
key = KEYC_BSPACE;
else
@ -240,64 +242,24 @@ key_string_lookup_string(const char *string)
const char *
key_string_lookup_key(key_code key)
{
static char out[32];
char tmp[8];
u_int i;
struct utf8_data ud;
size_t off;
static char out[32];
char tmp[8];
const char *s;
u_int i;
struct utf8_data ud;
size_t off;
*out = '\0';
/* Handle no key. */
if (key == KEYC_NONE)
return ("None");
/* Handle special keys. */
if (key == KEYC_UNKNOWN)
return ("Unknown");
if (key == KEYC_ANY)
return ("Any");
if (key == KEYC_FOCUS_IN)
return ("FocusIn");
if (key == KEYC_FOCUS_OUT)
return ("FocusOut");
if (key == KEYC_PASTE_START)
return ("PasteStart");
if (key == KEYC_PASTE_END)
return ("PasteEnd");
if (key == KEYC_MOUSE)
return ("Mouse");
if (key == KEYC_DRAGGING)
return ("Dragging");
if (key == KEYC_MOUSEMOVE_PANE)
return ("MouseMovePane");
if (key == KEYC_MOUSEMOVE_STATUS)
return ("MouseMoveStatus");
if (key == KEYC_MOUSEMOVE_STATUS_LEFT)
return ("MouseMoveStatusLeft");
if (key == KEYC_MOUSEMOVE_STATUS_RIGHT)
return ("MouseMoveStatusRight");
if (key == KEYC_MOUSEMOVE_BORDER)
return ("MouseMoveBorder");
if (key >= KEYC_USER && key < KEYC_USER + KEYC_NUSER) {
snprintf(out, sizeof out, "User%u", (u_int)(key - KEYC_USER));
return (out);
}
/* Literal keys are themselves. */
if (key & KEYC_LITERAL) {
snprintf(out, sizeof out, "%c", (int)(key & 0xff));
return (out);
}
/*
* 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
* in key_string_table, for the unlikely chance that we might
* change its name.
*/
/* Display C-@ as C-Space. */
if ((key & KEYC_MASK_KEY) == 0)
key = ' ' | KEYC_CTRL | (key & KEYC_MASK_MOD);
key = ' ' | KEYC_CTRL | (key & KEYC_MASK_MOD);
/* Fill in the modifiers. */
if (key & KEYC_CTRL)
@ -308,6 +270,69 @@ key_string_lookup_key(key_code key)
strlcat(out, "S-", sizeof out);
key &= KEYC_MASK_KEY;
/* Handle no key. */
if (key == KEYC_NONE)
return ("None");
/* Handle special keys. */
if (key == KEYC_UNKNOWN) {
s = "Unknown";
goto append;
}
if (key == KEYC_ANY) {
s = "Any";
goto append;
}
if (key == KEYC_FOCUS_IN) {
s = "FocusIn";
goto append;
}
if (key == KEYC_FOCUS_OUT) {
s = "FocusOut";
goto append;
}
if (key == KEYC_PASTE_START) {
s = "PasteStart";
goto append;
}
if (key == KEYC_PASTE_END) {
s = "PasteEnd";
goto append;
}
if (key == KEYC_MOUSE) {
s = "Mouse";
goto append;
}
if (key == KEYC_DRAGGING) {
s = "Dragging";
goto append;
}
if (key == KEYC_MOUSEMOVE_PANE) {
s = "MouseMovePane";
goto append;
}
if (key == KEYC_MOUSEMOVE_STATUS) {
s = "MouseMoveStatus";
goto append;
}
if (key == KEYC_MOUSEMOVE_STATUS_LEFT) {
s = "MouseMoveStatusLeft";
goto append;
}
if (key == KEYC_MOUSEMOVE_STATUS_RIGHT) {
s = "MouseMoveStatusRight";
goto append;
}
if (key == KEYC_MOUSEMOVE_BORDER) {
s = "MouseMoveBorder";
goto append;
}
if (key >= KEYC_USER && key < KEYC_USER + KEYC_NUSER) {
snprintf(tmp, sizeof tmp, "User%u", (u_int)(key - KEYC_USER));
strlcat(out, tmp, sizeof out);
return (out);
}
/* Try the key against the string table. */
for (i = 0; i < nitems(key_string_table); i++) {
if (key == key_string_table[i].key)
@ -329,7 +354,7 @@ key_string_lookup_key(key_code key)
}
/* Invalid keys are errors. */
if (key == 127 || key > 255) {
if (key > 255) {
snprintf(out, sizeof out, "Invalid#%llx", key);
return (out);
}
@ -343,9 +368,15 @@ key_string_lookup_key(key_code key)
} else if (key >= 32 && key <= 126) {
tmp[0] = key;
tmp[1] = '\0';
} else if (key >= 128)
} else if (key == 127)
xsnprintf(tmp, sizeof tmp, "C-?");
else if (key >= 128)
xsnprintf(tmp, sizeof tmp, "\\%llo", key);
strlcat(out, tmp, sizeof out);
return (out);
append:
strlcat(out, s, sizeof out);
return (out);
}

View File

@ -221,7 +221,7 @@ layout_parse(struct window *w, const char *layout)
return (-1);
/* Resize to the layout size. */
window_resize(w, lc->sx, lc->sy);
window_resize(w, lc->sx, lc->sy, -1, -1);
/* Destroy the old layout and swap to the new. */
layout_free_cell(w->layout_root);

View File

@ -163,7 +163,7 @@ layout_set_even(struct window *w, enum layout_type type)
layout_print_cell(w->layout_root, __func__, 1);
window_resize(w, lc->sx, lc->sy);
window_resize(w, lc->sx, lc->sy, -1, -1);
notify_window("window-layout-changed", w);
server_redraw_window(w);
}
@ -262,7 +262,7 @@ layout_set_main_h(struct window *w)
layout_print_cell(w->layout_root, __func__, 1);
window_resize(w, lc->sx, lc->sy);
window_resize(w, lc->sx, lc->sy, -1, -1);
notify_window("window-layout-changed", w);
server_redraw_window(w);
}
@ -349,7 +349,7 @@ layout_set_main_v(struct window *w)
layout_print_cell(w->layout_root, __func__, 1);
window_resize(w, lc->sx, lc->sy);
window_resize(w, lc->sx, lc->sy, -1, -1);
notify_window("window-layout-changed", w);
server_redraw_window(w);
}
@ -458,7 +458,7 @@ layout_set_tiled(struct window *w)
layout_print_cell(w->layout_root, __func__, 1);
window_resize(w, lc->sx, lc->sy);
window_resize(w, lc->sx, lc->sy, -1, -1);
notify_window("window-layout-changed", w);
server_redraw_window(w);
}

View File

@ -1,6 +1,6 @@
#!/usr/bin/awk
#
# Id: mdoc2man.awk,v 1.9 2009/10/24 00:52:42 dtucker Exp
# $Id: mdoc2man.awk,v 1.1.1.3 2020/11/01 14:52:01 christos Exp $
#
# Version history:
# v4+ Adapted for OpenSSH Portable (see cvs Id and history)

View File

@ -63,13 +63,16 @@ static const char *options_table_set_clipboard_list[] = {
"off", "external", "on", NULL
};
static const char *options_table_window_size_list[] = {
"largest", "smallest", "manual", NULL
"largest", "smallest", "manual", "latest", NULL
};
/* Status line format. */
#define OPTIONS_TABLE_STATUS_FORMAT1 \
"#[align=left range=left #{status-left-style}]" \
"#{T;=/#{status-left-length}:status-left}#[norange default]" \
"#[push-default]" \
"#{T;=/#{status-left-length}:status-left}" \
"#[pop-default]" \
"#[norange default]" \
"#[list=on align=#{status-justify}]" \
"#[list=left-marker]<#[list=right-marker]>#[list=on]" \
"#{W:" \
@ -91,7 +94,9 @@ static const char *options_table_window_size_list[] = {
"}" \
"}" \
"]" \
"#[push-default]" \
"#{T:window-status-format}" \
"#[pop-default]" \
"#[norange default]" \
"#{?window_end_flag,,#{window-status-separator}}" \
"," \
@ -116,12 +121,17 @@ static const char *options_table_window_size_list[] = {
"}" \
"}" \
"]" \
"#[push-default]" \
"#{T:window-status-current-format}" \
"#[pop-default]" \
"#[norange list=on default]" \
"#{?window_end_flag,,#{window-status-separator}}" \
"}" \
"#[nolist align=right range=right #{status-right-style}]" \
"#{T;=/#{status-right-length}:status-right}#[norange default]"
"#[push-default]" \
"#{T;=/#{status-right-length}:status-right}" \
"#[pop-default]" \
"#[norange default]"
#define OPTIONS_TABLE_STATUS_FORMAT2 \
"#[align=centre]#{P:#{?pane_active,#[reverse],}" \
"#{pane_index}[#{pane_width}x#{pane_height}]#[default] }"
@ -142,6 +152,12 @@ static const char *options_table_status_format_default[] = {
/* Top-level options. */
const struct options_table_entry options_table[] = {
/* Server options. */
{ .name = "backspace",
.type = OPTIONS_TABLE_KEY,
.scope = OPTIONS_TABLE_SERVER,
.default_num = '\177',
},
{ .name = "buffer-limit",
.type = OPTIONS_TABLE_NUMBER,
.scope = OPTIONS_TABLE_SERVER,
@ -719,7 +735,7 @@ const struct options_table_entry options_table[] = {
.type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_WINDOW,
.choices = options_table_window_size_list,
.default_num = WINDOW_SIZE_SMALLEST
.default_num = WINDOW_SIZE_LATEST
},
{ .name = "window-style",

View File

@ -23,7 +23,7 @@
#include "tmux.h"
void
resize_window(struct window *w, u_int sx, u_int sy)
resize_window(struct window *w, u_int sx, u_int sy, int xpixel, int ypixel)
{
int zoomed;
@ -50,7 +50,7 @@ resize_window(struct window *w, u_int sx, u_int sy)
sx = w->layout_root->sx;
if (sy < w->layout_root->sy)
sy = w->layout_root->sy;
window_resize(w, sx, sy);
window_resize(w, sx, sy, xpixel, ypixel);
log_debug("%s: @%u resized to %u,%u; layout %u,%u", __func__, w->id,
sx, sy, w->layout_root->sx, w->layout_root->sy);
@ -66,68 +66,144 @@ resize_window(struct window *w, u_int sx, u_int sy)
static int
ignore_client_size(struct client *c)
{
struct client *loop;
if (c->session == NULL)
return (1);
if (c->flags & CLIENT_NOSIZEFLAGS)
return (1);
if (c->flags & CLIENT_READONLY) {
/*
* Ignore readonly clients if there are any attached clients
* that aren't readonly.
*/
TAILQ_FOREACH (loop, &clients, entry) {
if (loop->session == NULL)
continue;
if (loop->flags & CLIENT_NOSIZEFLAGS)
continue;
if (~loop->flags & CLIENT_READONLY)
return (1);
}
}
if ((c->flags & CLIENT_CONTROL) && (~c->flags & CLIENT_SIZECHANGED))
return (1);
return (0);
}
void
default_window_size(struct session *s, struct window *w, u_int *sx, u_int *sy,
int type)
default_window_size(struct client *c, struct session *s, struct window *w,
u_int *sx, u_int *sy, u_int *xpixel, u_int *ypixel, int type)
{
struct client *c;
u_int cx, cy;
struct client *loop;
u_int cx, cy, n;
const char *value;
if (type == -1)
type = options_get_number(global_w_options, "window-size");
if (type == WINDOW_SIZE_MANUAL)
goto manual;
if (type == WINDOW_SIZE_LARGEST) {
switch (type) {
case WINDOW_SIZE_LARGEST:
*sx = *sy = 0;
TAILQ_FOREACH(c, &clients, entry) {
if (ignore_client_size(c))
*xpixel = *ypixel = 0;
TAILQ_FOREACH(loop, &clients, entry) {
if (ignore_client_size(loop))
continue;
if (w != NULL && !session_has(c->session, w))
if (w != NULL && !session_has(loop->session, w))
continue;
if (w == NULL && c->session != s)
if (w == NULL && loop->session != s)
continue;
cx = c->tty.sx;
cy = c->tty.sy - status_line_size(c);
cx = loop->tty.sx;
cy = loop->tty.sy - status_line_size(loop);
if (cx > *sx)
*sx = cx;
if (cy > *sy)
*sy = cy;
if (loop->tty.xpixel > *xpixel &&
loop->tty.ypixel > *ypixel) {
*xpixel = loop->tty.xpixel;
*ypixel = loop->tty.ypixel;
}
}
if (*sx == 0 || *sy == 0)
goto manual;
} else {
break;
case WINDOW_SIZE_SMALLEST:
*sx = *sy = UINT_MAX;
TAILQ_FOREACH(c, &clients, entry) {
if (ignore_client_size(c))
*xpixel = *ypixel = 0;
TAILQ_FOREACH(loop, &clients, entry) {
if (ignore_client_size(loop))
continue;
if (w != NULL && !session_has(c->session, w))
if (w != NULL && !session_has(loop->session, w))
continue;
if (w == NULL && c->session != s)
if (w == NULL && loop->session != s)
continue;
cx = c->tty.sx;
cy = c->tty.sy - status_line_size(c);
cx = loop->tty.sx;
cy = loop->tty.sy - status_line_size(loop);
if (cx < *sx)
*sx = cx;
if (cy < *sy)
*sy = cy;
if (loop->tty.xpixel > *xpixel &&
loop->tty.ypixel > *ypixel) {
*xpixel = loop->tty.xpixel;
*ypixel = loop->tty.ypixel;
}
}
if (*sx == UINT_MAX || *sy == UINT_MAX)
goto manual;
break;
case WINDOW_SIZE_LATEST:
if (c != NULL && !ignore_client_size(c)) {
*sx = c->tty.sx;
*sy = c->tty.sy - status_line_size(c);
*xpixel = c->tty.xpixel;
*ypixel = c->tty.ypixel;
} else {
if (w == NULL)
goto manual;
n = 0;
TAILQ_FOREACH(loop, &clients, entry) {
if (!ignore_client_size(loop) &&
session_has(loop->session, w)) {
if (++n > 1)
break;
}
}
*sx = *sy = UINT_MAX;
*xpixel = *ypixel = 0;
TAILQ_FOREACH(loop, &clients, entry) {
if (ignore_client_size(loop))
continue;
if (n > 1 && loop != w->latest)
continue;
s = loop->session;
cx = loop->tty.sx;
cy = loop->tty.sy - status_line_size(loop);
if (cx < *sx)
*sx = cx;
if (cy < *sy)
*sy = cy;
if (loop->tty.xpixel > *xpixel &&
loop->tty.ypixel > *ypixel) {
*xpixel = loop->tty.xpixel;
*ypixel = loop->tty.ypixel;
}
}
if (*sx == UINT_MAX || *sy == UINT_MAX)
goto manual;
}
break;
case WINDOW_SIZE_MANUAL:
goto manual;
}
goto done;
@ -149,14 +225,145 @@ done:
*sy = WINDOW_MAXIMUM;
}
void
recalculate_size(struct window *w)
{
struct session *s;
struct client *c;
u_int sx, sy, cx, cy, xpixel = 0, ypixel = 0, n;
int type, current, has, changed;
if (w->active == NULL)
return;
log_debug("%s: @%u is %u,%u", __func__, w->id, w->sx, w->sy);
type = options_get_number(w->options, "window-size");
current = options_get_number(w->options, "aggressive-resize");
changed = 1;
switch (type) {
case WINDOW_SIZE_LARGEST:
sx = sy = 0;
TAILQ_FOREACH(c, &clients, entry) {
if (ignore_client_size(c))
continue;
s = c->session;
if (current)
has = (s->curw->window == w);
else
has = session_has(s, w);
if (!has)
continue;
cx = c->tty.sx;
cy = c->tty.sy - status_line_size(c);
if (cx > sx)
sx = cx;
if (cy > sy)
sy = cy;
if (c->tty.xpixel > xpixel && c->tty.ypixel > ypixel) {
xpixel = c->tty.xpixel;
ypixel = c->tty.ypixel;
}
}
if (sx == 0 || sy == 0)
changed = 0;
break;
case WINDOW_SIZE_SMALLEST:
sx = sy = UINT_MAX;
TAILQ_FOREACH(c, &clients, entry) {
if (ignore_client_size(c))
continue;
s = c->session;
if (current)
has = (s->curw->window == w);
else
has = session_has(s, w);
if (!has)
continue;
cx = c->tty.sx;
cy = c->tty.sy - status_line_size(c);
if (cx < sx)
sx = cx;
if (cy < sy)
sy = cy;
if (c->tty.xpixel > xpixel && c->tty.ypixel > ypixel) {
xpixel = c->tty.xpixel;
ypixel = c->tty.ypixel;
}
}
if (sx == UINT_MAX || sy == UINT_MAX)
changed = 0;
break;
case WINDOW_SIZE_LATEST:
n = 0;
TAILQ_FOREACH(c, &clients, entry) {
if (!ignore_client_size(c) &&
session_has(c->session, w)) {
if (++n > 1)
break;
}
}
sx = sy = UINT_MAX;
TAILQ_FOREACH(c, &clients, entry) {
if (ignore_client_size(c))
continue;
if (n > 1 && c != w->latest)
continue;
s = c->session;
if (current)
has = (s->curw->window == w);
else
has = session_has(s, w);
if (!has)
continue;
cx = c->tty.sx;
cy = c->tty.sy - status_line_size(c);
if (cx < sx)
sx = cx;
if (cy < sy)
sy = cy;
if (c->tty.xpixel > xpixel && c->tty.ypixel > ypixel) {
xpixel = c->tty.xpixel;
ypixel = c->tty.ypixel;
}
}
if (sx == UINT_MAX || sy == UINT_MAX)
changed = 0;
break;
case WINDOW_SIZE_MANUAL:
changed = 0;
break;
}
if (changed && w->sx == sx && w->sy == sy)
changed = 0;
if (!changed) {
tty_update_window_offset(w);
return;
}
log_debug("%s: @%u changed to %u,%u (%ux%u)", __func__, w->id, sx, sy,
xpixel, ypixel);
resize_window(w, sx, sy, xpixel, ypixel);
}
void
recalculate_sizes(void)
{
struct session *s;
struct client *c;
struct window *w;
u_int sx, sy, cx, cy;
int type, current, has, changed;
/*
* Clear attached count and update saved status line information for
@ -172,85 +379,18 @@ recalculate_sizes(void)
* client.
*/
TAILQ_FOREACH(c, &clients, entry) {
s = c->session;
if (s != NULL && !(c->flags & CLIENT_UNATTACHEDFLAGS))
s->attached++;
if (ignore_client_size(c))
continue;
s = c->session;
if (c->tty.sy <= s->statuslines || (c->flags & CLIENT_CONTROL))
c->flags |= CLIENT_STATUSOFF;
else
c->flags &= ~CLIENT_STATUSOFF;
s->attached++;
}
/* Walk each window and adjust the size. */
RB_FOREACH(w, windows, &windows) {
if (w->active == NULL)
continue;
log_debug("%s: @%u is %u,%u", __func__, w->id, w->sx, w->sy);
type = options_get_number(w->options, "window-size");
if (type == WINDOW_SIZE_MANUAL)
continue;
current = options_get_number(w->options, "aggressive-resize");
changed = 1;
if (type == WINDOW_SIZE_LARGEST) {
sx = sy = 0;
TAILQ_FOREACH(c, &clients, entry) {
if (ignore_client_size(c))
continue;
s = c->session;
if (current)
has = (s->curw->window == w);
else
has = session_has(s, w);
if (!has)
continue;
cx = c->tty.sx;
cy = c->tty.sy - status_line_size(c);
if (cx > sx)
sx = cx;
if (cy > sy)
sy = cy;
}
if (sx == 0 || sy == 0)
changed = 0;
} else {
sx = sy = UINT_MAX;
TAILQ_FOREACH(c, &clients, entry) {
if (ignore_client_size(c))
continue;
s = c->session;
if (current)
has = (s->curw->window == w);
else
has = session_has(s, w);
if (!has)
continue;
cx = c->tty.sx;
cy = c->tty.sy - status_line_size(c);
if (cx < sx)
sx = cx;
if (cy < sy)
sy = cy;
}
if (sx == UINT_MAX || sy == UINT_MAX)
changed = 0;
}
if (w->sx == sx && w->sy == sy)
changed = 0;
if (!changed) {
tty_update_window_offset(w);
continue;
}
log_debug("%s: @%u changed to %u,%u", __func__, w->id, sx, sy);
resize_window(w, sx, sy);
}
RB_FOREACH(w, windows, &windows)
recalculate_size(w);
}

View File

@ -71,6 +71,20 @@ xreallocarray(void *ptr, size_t nmemb, size_t size)
return new_ptr;
}
void *
xrecallocarray(void *ptr, size_t oldnmemb, size_t nmemb, size_t size)
{
void *new_ptr;
if (nmemb == 0 || size == 0)
fatalx("xrecallocarray: zero size");
new_ptr = recallocarray(ptr, oldnmemb, nmemb, size);
if (new_ptr == NULL)
fatalx("xrecallocarray: allocating %zu * %zu bytes: %s",
nmemb, size, strerror(errno));
return new_ptr;
}
char *
xstrdup(const char *str)
{