Compare commits

..

No commits in common. "master" and "3.3a" have entirely different histories.
master ... 3.3a

152 changed files with 3651 additions and 15226 deletions

View File

@ -77,8 +77,3 @@ The log files are:
- `tmux-out*.log`: output log file. - `tmux-out*.log`: output log file.
Please attach the log files to your issue. Please attach the log files to your issue.
## What does it mean if an issue is closed?
All it means is that work on the issue is not planned for the near future. See
the issue's comments to find out if contributions would be welcome.

View File

@ -1,12 +1,3 @@
---
name: Use this issue template
about: Please read https://github.com/tmux/tmux/blob/master/.github/CONTRIBUTING.md
title: ''
labels: ''
assignees: ''
---
### Issue description ### Issue description
Please read https://github.com/tmux/tmux/blob/master/.github/CONTRIBUTING.md Please read https://github.com/tmux/tmux/blob/master/.github/CONTRIBUTING.md

View File

@ -1 +0,0 @@
blank_issues_enabled: false

2
.github/README.md vendored
View File

@ -79,7 +79,7 @@ A small example configuration is in `example_tmux.conf`.
And a bash(1) completion file at: And a bash(1) completion file at:
https://github.com/scop/bash-completion/blob/main/completions/tmux https://github.com/imomaliev/tmux-bash-completion
For debugging, run tmux with `-v` or `-vv` to generate server and client log For debugging, run tmux with `-v` or `-vv` to generate server and client log
files in the current directory. files in the current directory.

View File

@ -3,32 +3,21 @@ name: 'Lock Threads'
on: on:
schedule: schedule:
- cron: '0 0 * * *' - cron: '0 0 * * *'
workflow_dispatch:
permissions:
issues: write
pull-requests: write
discussions: write
concurrency:
group: lock-threads
jobs: jobs:
action: lock:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: dessant/lock-threads@v5 - uses: dessant/lock-threads@v2
with: with:
github-token: ${{ github.token }} github-token: ${{ github.token }}
issue-inactive-days: '30' issue-lock-inactive-days: '30'
issue-comment: > pr-lock-inactive-days: '60'
issue-lock-comment: >
This issue has been automatically locked since there This issue has been automatically locked since there
has not been any recent activity after it was closed. has not been any recent activity after it was closed.
pr-inactive-days: '60' Please open a new issue for related bugs.
pr-comment: > pr-lock-comment: >
This pull request has been automatically locked since there This pull request has been automatically locked since there
has not been any recent activity after it was closed. has not been any recent activity after it was closed.
discussion-inactive-days: '60' Please open a new issue for related bugs.
discussion-comment: >
This discussion has been automatically locked since there
has not been any recent activity after it was closed.

27
.gitignore vendored
View File

@ -1,24 +1,23 @@
*.core
*.dSYM
*.diff
*.o *.o
*.patch
*.swp
*~ *~
*.diff
*.patch
*.core
core
tags
.deps/ .deps/
.dirstamp compat/.dirstamp
Makefile
Makefile.in
aclocal.m4 aclocal.m4
autom4te.cache/ autom4te.cache/
cmd-parse.c
compat/.dirstamp
config.log config.log
config.status config.status
configure
core
etc/ etc/
fuzz/*-fuzzer
tags
tmux tmux
Makefile
Makefile.in
configure
tmux.1.* tmux.1.*
*.dSYM
cmd-parse.c
fuzz/*-fuzzer
.dirstamp

206
CHANGES
View File

@ -1,205 +1,3 @@
CHANGES FROM 3.4 TO 3.5
* Revamp extended keys support to more closely match xterm and support mode 2
as well as mode 1. This is a substantial change to key handling which changes
tmux to always request mode 2 from parent terminal, changes to an unambiguous
internal representation of keys, and adds an option (extended-keys-format) to
control the format similar to the xterm(1) formatOtherKeys resource.
* Clear an overlay (popup or menu) when command prompt is entered.
* Add copy-mode -d flag to scroll a page down if in copy mode already (matching
-e).
* Display hyperlinks in copy mode and add copy_cursor_hyperlink format to get
the hyperlink under the cursor.
* Add a prefix timeout option.
* Mouse move keys are not useful as key bindings because we do not turn them on
unless the application requests them. Ignore them so they do not cause the
prefix to be canceled
* Add search_count and search_count_partial formats in copy mode.
* Do not reset mouse pane if clicked on status line,
* Add mirrored versions of the main-horizontal and main-vertical layouts where
the main pane is bottom or right instead of top or left.
* Allow REP to work with Unicode characters.
* Fix size calculation of terminators for clipboard escape sequences.
* Treat CRLF as LF in config files where it is easy to do so.
* The Linux console has some bugs with bright colours, so add some workarounds
for it.
* If built with systemd, remove some environment variables it uses.
* Adjust the logic when deleting last buffer to better preserve the selection:
if selecting the element below the deleted one fails (because as the last
one), select the one above it instead.
* Add --enable-jemalloc to build with jemalloc memory allocator (since glibc
malloc is so poor).
* Add a way (refresh-client -r) for control mode clients to provide OSC 10 and
11 responses to tmux so they can set the default foreground and background
colours.
* Add N to search backwards in tree modes.
* Use default-shell for command prompt, #() and popups.
* Revert part of a change intended to improve search performance by skipping
parts of lines already searched, but which in fact skipped the ends of lines
altogether.
* Add a command-error hook when a command fails.
* Add an option allow-set-title to forbid applications from changing the pane
title.
* Correct handling of mouse up events (don't ignore all but the last released
button), and always process down event for double click.
* Fix a crash if focusing a pane that is exiting.
* Pick newest session (as documented) when looking for next session for
detach-on-destroy.
* Reduce default escape-time to 10 milliseconds.
* Add display-menu -M to always turn mouse on in a menu.
* Look for feature code 21 for DECSLRM and 28 for DECFRA in the device
attributes and also accept level 1.
* Fix crash if built with SIXEL and the SIXEL colour register is invalid; also
remove SIXEL images before reflow.
* Do not notify window-layout-changed if the window is about to be destroyed.
* Do not consider a selection present if it is empty for the selection_active
and selection_present format variables.
* Fix split-window -p.
CHANGES FROM 3.3a TO 3.4
* Add options keep-last and keep-group to destroy-unattached to keep the last
session whether in a group.
* Don't allow paste-buffer into dead panes.
* Add -t to source-file.
* Rewrite combined character handling to be more consistent and to support
newer Unicode combined characters.
* Add basic support for SIXEL if built with --enable-sixel.
* Add a session, pane and user mouse range types for the status line and add
format variables for mouse_status_line and mouse_status_range so they can be
associated with different commands in the key bindings.
* Add flag (-o) to next-prompt/previous-prompt to go to OSC 133 command output.
* Add options and flags for menu styles (menu-style, menu-border-style) similar
to those existing for popups.
* Add support for marking lines with a shell prompt based on the OSC 133 extension.
* Check for libterminfo for NetBSD.
* Add "us" to styles for underscore colour.
* Add flags (-c and -y) to change the confirm key and default behaviour of
confirm-before.
* Use ncurses' new tparm_s function (added in 6.4-20230424) instead of tparm so
it does not object to string arguments in c apabilities it doesn't already
know. Also ignore errors from tparm if using previous ncurses versions.
* Set default lock command to vlock on Linux if present at build time.
* Discard mouse sequences that have the right form but actually are invalid.
* Add support for spawning panes in separate cgroups with systemd and a
configure flag (--disable-cgroups) to turn off.
* Add a format (pane_unseen_changes) to show if there are unseen changes while
in a mode.
* Remove old buffer when renaming rather than complaining.
* Add an L modifier like P, W, S to loop over clients.
* Add -f to list-clients like the other list commands.
* Extend display-message to work for control clients.
* Add a flag to display-menu to select the manu item selected when the menu is
open.
* Have tmux recognise pasted text wrapped in bracket paste sequences, rather
than only forwarding them to the program inside.
* Have client return 1 if process is interrupted to an input pane.
* Query the client terminal for foreground and background colours and if OSC 10
or 11 is received but no colour has been set inside tmux, return the colour
from the first attached client.
* Add send-keys -K to handle keys directly as if typed (so look up in key
table).
* Process escape sequences in show-buffer.
* Add a -l flag to display-message to disable format expansion.
* Add paste-buffer-deleted notification and fix name of paste-buffer-changed.
* Do not attempt to connect to the socket as a client if systemd is active.
* Add scroll-top and scroll-bottom commands to scroll so cursor is at top or
bottom.
* Add a -T flag to capture-pane to stop at the last used cell instead of the
full width. Restore the previous behaviour by making it default to off unless
-J is used.
* Add message-line option to control where message and prompt go.
* Notification when a paste buffer is deleted.
* Add a Nobr terminfo(5) capability to tell tmux the terminal does not use bright
colours for bold.
* Change g and G to go to top and bottom in menus.
* Add a third state "all" to allow-passthrough to work even in invisible panes.
* Add support for OSC 8 hyperlinks.
* Store the time lines are scrolled into history and display in copy mode.
* Add a %config-error reply to control mode for configuration file errors since
reporting them in view mode is useless.
* A new feature flag (ignorefkeys) to ignore terminfo(5) function key
definitions for rxvt.
* Pass through first argument to OSC 52 (which clipboards to set) if the
application provides it.
* Expand arguments to send-keys, capture-pane, split-window, join-pane where it
makes sense to do so.
* Ignore named buffers when choosing a buffer if one is not specified by the user.
CHANGES FROM 3.3 TO 3.3a CHANGES FROM 3.3 TO 3.3a
* Do not crash when run-shell produces output from a config file. * Do not crash when run-shell produces output from a config file.
@ -389,7 +187,7 @@ CHANGES FROM 3.2 TO 3.2a
* Do not expand the filename given to -f so it can contain colons. * Do not expand the filename given to -f so it can contain colons.
* Fixes for problems with extended keys and modifiers, scroll region, * Fixes for problems with extended keys and modifiers, scroll region,
source-file, cross compiling, format modifiers and other minor issues. source-file, crosscompiling, format modifiers and other minor issues.
CHANGES FROM 3.1c TO 3.2 CHANGES FROM 3.1c TO 3.2
@ -1504,7 +1302,7 @@ Incompatible Changes
bind -Tcopy-mode C-r command-prompt -i -p'search up' "send -X search-backward-incremental '%%'" bind -Tcopy-mode C-r command-prompt -i -p'search up' "send -X search-backward-incremental '%%'"
There are also some new commands available with send -X, such as There are also some new commmands available with send -X, such as
copy-pipe-and-cancel. copy-pipe-and-cancel.
* set-remain-on-exit has gone -- can be achieved with hooks instead. * set-remain-on-exit has gone -- can be achieved with hooks instead.
* Hooks: before hooks have been removed and only a selection of commands now * Hooks: before hooks have been removed and only a selection of commands now

View File

@ -1,3 +1,5 @@
# Makefile.am
# Obvious program stuff. # Obvious program stuff.
bin_PROGRAMS = tmux bin_PROGRAMS = tmux
CLEANFILES = tmux.1.mdoc tmux.1.man cmd-parse.c CLEANFILES = tmux.1.mdoc tmux.1.man cmd-parse.c
@ -12,7 +14,6 @@ dist_EXTRA_tmux_SOURCES = compat/*.[ch]
AM_CPPFLAGS += @XOPEN_DEFINES@ \ AM_CPPFLAGS += @XOPEN_DEFINES@ \
-DTMUX_VERSION='"@VERSION@"' \ -DTMUX_VERSION='"@VERSION@"' \
-DTMUX_CONF='"$(sysconfdir)/tmux.conf:~/.tmux.conf:$$XDG_CONFIG_HOME/tmux/tmux.conf:~/.config/tmux/tmux.conf"' \ -DTMUX_CONF='"$(sysconfdir)/tmux.conf:~/.tmux.conf:$$XDG_CONFIG_HOME/tmux/tmux.conf:~/.config/tmux/tmux.conf"' \
-DTMUX_LOCK_CMD='"@DEFAULT_LOCK_CMD@"' \
-DTMUX_TERM='"@DEFAULT_TERM@"' -DTMUX_TERM='"@DEFAULT_TERM@"'
# Additional object files. # Additional object files.
@ -30,7 +31,7 @@ AM_CFLAGS += -Wundef -Wbad-function-cast -Winline -Wcast-align
AM_CFLAGS += -Wdeclaration-after-statement -Wno-pointer-sign -Wno-attributes AM_CFLAGS += -Wdeclaration-after-statement -Wno-pointer-sign -Wno-attributes
AM_CFLAGS += -Wno-unused-result -Wno-format-y2k AM_CFLAGS += -Wno-unused-result -Wno-format-y2k
if IS_DARWIN if IS_DARWIN
AM_CFLAGS += -Wno-deprecated-declarations -Wno-cast-align -Wno-macro-redefined AM_CFLAGS += -Wno-deprecated-declarations -Wno-cast-align
endif endif
AM_CPPFLAGS += -DDEBUG AM_CPPFLAGS += -DDEBUG
endif endif
@ -66,11 +67,6 @@ if IS_HAIKU
AM_CPPFLAGS += -D_BSD_SOURCE AM_CPPFLAGS += -D_BSD_SOURCE
endif endif
# Set flags for Cygwin.
if IS_CYGWIN
AM_CPPFLAGS += -DTMUX_SOCK_PERM=0
endif
# List of sources. # List of sources.
dist_tmux_SOURCES = \ dist_tmux_SOURCES = \
alerts.c \ alerts.c \
@ -154,7 +150,6 @@ dist_tmux_SOURCES = \
grid-reader.c \ grid-reader.c \
grid-view.c \ grid-view.c \
grid.c \ grid.c \
hyperlinks.c \
input-keys.c \ input-keys.c \
input.c \ input.c \
job.c \ job.c \
@ -194,7 +189,6 @@ dist_tmux_SOURCES = \
tty-keys.c \ tty-keys.c \
tty-term.c \ tty-term.c \
tty.c \ tty.c \
utf8-combined.c \
utf8.c \ utf8.c \
window-buffer.c \ window-buffer.c \
window-client.c \ window-client.c \
@ -222,11 +216,6 @@ if HAVE_UTF8PROC
nodist_tmux_SOURCES += compat/utf8proc.c nodist_tmux_SOURCES += compat/utf8proc.c
endif endif
# Enable sixel support.
if ENABLE_SIXEL
dist_tmux_SOURCES += image.c image-sixel.c
endif
if NEED_FUZZING if NEED_FUZZING
check_PROGRAMS = fuzz/input-fuzzer check_PROGRAMS = fuzz/input-fuzzer
fuzz_input_fuzzer_LDFLAGS = $(FUZZING_LIBS) fuzz_input_fuzzer_LDFLAGS = $(FUZZING_LIBS)

3
README
View File

@ -36,7 +36,6 @@ autoconf, automake and pkg-config:
$ cd tmux $ cd tmux
$ sh autogen.sh $ sh autogen.sh
$ ./configure && make $ ./configure && make
$ sudo make install
* Contributing * Contributing
@ -66,7 +65,7 @@ Also see the tmux FAQ at:
A bash(1) completion file is at: A bash(1) completion file is at:
https://github.com/scop/bash-completion/blob/main/completions/tmux https://github.com/imomaliev/tmux-bash-completion
For debugging, run tmux with -v and -vv to generate server and client log files For debugging, run tmux with -v and -vv to generate server and client log files
in the current directory. in the current directory.

View File

@ -38,7 +38,7 @@ tmuxのドキュメントについてはtmux.1マニュアルをご覧くださ
サンプル設定は本リポジトリのexample_tmux.confに サンプル設定は本リポジトリのexample_tmux.confに
また、bash-completionファイルは下記にあります。 また、bash-completionファイルは下記にあります。
https://github.com/scop/bash-completion/blob/main/completions/tmux https://github.com/imomaliev/tmux-bash-completion
「-v」や「-vv」を指定することでデバッグモードでの起動が可能です。カレントディレクトリにサーバーやクライアントのログファイルが生成されます。 「-v」や「-vv」を指定することでデバッグモードでの起動が可能です。カレントディレクトリにサーバーやクライアントのログファイルが生成されます。

32
SYNCING
View File

@ -1,17 +1,17 @@
Preamble Preamble
======== ========
Tmux portable relies on repositories "tmux" and "tmux-obsd". Tmux portable relies on repositories "tmux" and "tmux-openbsd".
Here's a description of them: Here's a description of them:
* "tmux" is the portable version, the one which contains code for other * "tmux" is the portable version, the one which contains code for other
operating systems, and autotools, etc., which isn't found or needed in the operating systems, and autotools, etc., which isn't found or needed in the
OpenBSD base system. OpenBSD base system.
* "tmux-obsd" is the version of tmux in OpenBSD base system which provides * "tmux-openbsd" is the version of tmux in OpenBSD base system which provides
the basis of the portable tmux version. the basis of the portable tmux version.
Note: The "tmux-obsd" repository is actually handled by "git cvsimport" Note: The "tmux-openbsd" repository is actually handled by "git cvsimport"
running at 15 minute intervals, so a commit made to OpenBSD's tmux CVS running at 15 minute intervals, so a commit made to OpenBSD's tmux CVS
repository will take at least that long to appear in this git repository. repository will take at least that long to appear in this git repository.
(It might take longer, depending on the CVS mirror used to import the (It might take longer, depending on the CVS mirror used to import the
@ -34,11 +34,11 @@ this information has ever been set before.
Cloning repositories Cloning repositories
==================== ====================
This involves having both tmux and tmux-obsd cloned, as in: This involves having both tmux and tmux-openbsd cloned, as in:
% cd /some/where/useful % cd /some/where/useful
% git clone https://github.com/tmux/tmux.git % git clone https://github.com/tmux/tmux.git
% git clone https://github.com/ThomasAdam/tmux-obsd.git % git clone https://github.com/ThomasAdam/tmux-openbsd.git
Note that you do not need additional checkouts to manage the sync -- an Note that you do not need additional checkouts to manage the sync -- an
existing clone of either repositories will suffice. So if you already have existing clone of either repositories will suffice. So if you already have
@ -47,30 +47,30 @@ these checkouts existing, skip that.
Adding in git-remotes Adding in git-remotes
===================== =====================
Because the portable "tmux" git repository and the "tmux-obsd" Because the portable "tmux" git repository and the "tmux-openbsd"
repository do not inherently share any history between each other, the repository do not inherently share any history between each other, the
history has been faked between them. This "faking of history" is something history has been faked between them. This "faking of history" is something
which has to be told to git for the purposes of comparing the "tmux" and which has to be told to git for the purposes of comparing the "tmux" and
"tmux-obsd" repositories for syncing. To do this, we must reference the "tmux-openbsd" repositories for syncing. To do this, we must reference the
clone of the "tmux-obsd" repository from the "tmux" repository, as clone of the "tmux-openbsd" repository from the "tmux" repository, as
shown by the following command: shown by the following command:
% cd /path/to/tmux % cd /path/to/tmux
% git remote add obsd-tmux file:///path/to/tmux-obsd % git remote add obsd-tmux file:///path/to/tmux-openbsd
So that now, the remote "obsd-tmux" can be used to reference branches and So that now, the remote "obsd-tmux" can be used to reference branches and
commits from the "tmux-obsd" repository, but from the context of the commits from the "tmux-openbsd" repository, but from the context of the
portable "tmux" repository, which makes sense because it's the "tmux" portable "tmux" repository, which makes sense because it's the "tmux"
repository which will have the updates applied to them. repository which will have the updates applied to them.
Fetching updates Fetching updates
================ ================
To ensure the latest commits from "tmux-obsd" can be found from within To ensure the latest commits from "tmux-openbsd" can be found from within
"tmux", we have to ensure the "master" branch from "tmux-obsd" is "tmux", we have to ensure the "master" branch from "tmux-openbsd" is
up-to-date first, and then reference that update in "tmux", as in: up-to-date first, and then reference that update in "tmux", as in:
% cd /path/to/tmux-obsd % cd /path/to/tmux-openbsd
% git checkout master % git checkout master
% git pull % git pull
@ -82,9 +82,9 @@ Then back in "tmux":
Creating the necessary branches Creating the necessary branches
=============================== ===============================
Now that "tmux" can see commits and branches from "tmux-obsd" by way Now that "tmux" can see commits and branches from "tmux-openbsd" by way
of the remote name "obsd-tmux", we can now create the master branch from of the remote name "obsd-tmux", we can now create the master branch from
"tmux-obsd" in the "tmux" repository: "tmux-openbsd" in the "tmux" repository:
% git checkout -b obsd-master obsd-tmux/master % git checkout -b obsd-master obsd-tmux/master
@ -92,7 +92,7 @@ Adding in the fake history points
================================= =================================
To tie both the "master" branch from "tmux" and the "obsd-master" To tie both the "master" branch from "tmux" and the "obsd-master"
branch from "tmux-obsd" together, the fake history points added to the branch from "tmux-openbsd" together, the fake history points added to the
"tmux" repository need to be added. To do this, we must add an "tmux" repository need to be added. To do this, we must add an
additional refspec line, as in: additional refspec line, as in:

View File

@ -315,11 +315,11 @@ alerts_set_message(struct winlink *wl, const char *type, const char *option)
if (visual == VISUAL_OFF) if (visual == VISUAL_OFF)
continue; continue;
if (c->session->curw == wl) { if (c->session->curw == wl) {
status_message_set(c, -1, 1, 0, 0, status_message_set(c, -1, 1, 0, "%s in current window",
"%s in current window", type); type);
} else { } else {
status_message_set(c, -1, 1, 0, 0, status_message_set(c, -1, 1, 0, "%s in window %d", type,
"%s in window %d", type, wl->idx); wl->idx);
} }
} }
} }

View File

@ -37,10 +37,6 @@ struct args_entry {
u_char flag; u_char flag;
struct args_values values; struct args_values values;
u_int count; u_int count;
int flags;
#define ARGS_ENTRY_OPTIONAL_VALUE 0x1
RB_ENTRY(args_entry) entry; RB_ENTRY(args_entry) entry;
}; };
@ -98,22 +94,6 @@ args_copy_value(struct args_value *to, struct args_value *from)
} }
} }
/* Type to string. */
static const char *
args_type_to_string (enum args_type type)
{
switch (type)
{
case ARGS_NONE:
return "NONE";
case ARGS_STRING:
return "STRING";
case ARGS_COMMANDS:
return "COMMANDS";
}
return "INVALID";
}
/* Get value as string. */ /* Get value as string. */
static const char * static const char *
args_value_as_string(struct args_value *value) args_value_as_string(struct args_value *value)
@ -142,103 +122,6 @@ args_create(void)
return (args); return (args);
} }
/* Parse a single flag. */
static int
args_parse_flag_argument(struct args_value *values, u_int count, char **cause,
struct args *args, u_int *i, const char *string, int flag,
int optional_argument)
{
struct args_value *argument, *new;
const char *s;
new = xcalloc(1, sizeof *new);
if (*string != '\0') {
new->type = ARGS_STRING;
new->string = xstrdup(string);
goto out;
}
if (*i == count)
argument = NULL;
else {
argument = &values[*i];
if (argument->type != ARGS_STRING) {
xasprintf(cause, "-%c argument must be a string", flag);
args_free_value(new);
free(new);
return (-1);
}
}
if (argument == NULL) {
args_free_value(new);
free(new);
if (optional_argument) {
log_debug("%s: -%c (optional)", __func__, flag);
args_set(args, flag, NULL, ARGS_ENTRY_OPTIONAL_VALUE);
return (0); /* either - or end */
}
xasprintf(cause, "-%c expects an argument", flag);
return (-1);
}
args_copy_value(new, argument);
(*i)++;
out:
s = args_value_as_string(new);
log_debug("%s: -%c = %s", __func__, flag, s);
args_set(args, flag, new, 0);
return (0);
}
/* Parse flags argument. */
static int
args_parse_flags(const struct args_parse *parse, struct args_value *values,
u_int count, char **cause, struct args *args, u_int *i)
{
struct args_value *value;
u_char flag;
const char *found, *string;
int optional_argument;
value = &values[*i];
if (value->type != ARGS_STRING)
return (1);
string = value->string;
log_debug("%s: next %s", __func__, string);
if (*string++ != '-' || *string == '\0')
return (1);
(*i)++;
if (string[0] == '-' && string[1] == '\0')
return (1);
for (;;) {
flag = *string++;
if (flag == '\0')
return (0);
if (flag == '?')
return (-1);
if (!isalnum(flag)) {
xasprintf(cause, "invalid flag -%c", flag);
return (-1);
}
found = strchr(parse->template, flag);
if (found == NULL) {
xasprintf(cause, "unknown flag -%c", flag);
return (-1);
}
if (found[1] != ':') {
log_debug("%s: -%c", __func__, flag);
args_set(args, flag, NULL, 0);
continue;
}
optional_argument = (found[2] == ':');
return (args_parse_flag_argument(values, count, cause, args, i,
string, flag, optional_argument));
}
}
/* Parse arguments into a new argument set. */ /* Parse arguments into a new argument set. */
struct args * struct args *
args_parse(const struct args_parse *parse, struct args_value *values, args_parse(const struct args_parse *parse, struct args_value *values,
@ -248,21 +131,86 @@ args_parse(const struct args_parse *parse, struct args_value *values,
u_int i; u_int i;
enum args_parse_type type; enum args_parse_type type;
struct args_value *value, *new; struct args_value *value, *new;
const char *s; u_char flag;
int stop; const char *found, *string, *s;
int optional_argument;
if (count == 0) if (count == 0)
return (args_create()); return (args_create());
args = args_create(); args = args_create();
for (i = 1; i < count; /* nothing */) { for (i = 1; i < count; /* nothing */) {
stop = args_parse_flags(parse, values, count, cause, args, &i); value = &values[i];
if (stop == -1) { if (value->type != ARGS_STRING)
args_free(args);
return (NULL);
}
if (stop == 1)
break; break;
string = value->string;
if (*string++ != '-' || *string == '\0')
break;
i++;
if (string[0] == '-' && string[1] == '\0')
break;
for (;;) {
flag = *string++;
if (flag == '\0')
break;
if (flag == '?') {
args_free(args);
return (NULL);
}
if (!isalnum(flag)) {
xasprintf(cause, "invalid flag -%c", flag);
args_free(args);
return (NULL);
}
found = strchr(parse->template, flag);
if (found == NULL) {
xasprintf(cause, "unknown flag -%c", flag);
args_free(args);
return (NULL);
}
if (*++found != ':') {
log_debug("%s: -%c", __func__, flag);
args_set(args, flag, NULL);
continue;
}
if (*found == ':') {
optional_argument = 1;
found++;
}
new = xcalloc(1, sizeof *new);
if (*string != '\0') {
new->type = ARGS_STRING;
new->string = xstrdup(string);
} else {
if (i == count) {
if (optional_argument) {
log_debug("%s: -%c", __func__,
flag);
args_set(args, flag, NULL);
continue;
}
xasprintf(cause,
"-%c expects an argument",
flag);
args_free(args);
return (NULL);
}
if (values[i].type != ARGS_STRING) {
xasprintf(cause,
"-%c argument must be a string",
flag);
args_free(args);
return (NULL);
}
args_copy_value(new, &values[i++]);
}
s = args_value_as_string(new);
log_debug("%s: -%c = %s", __func__, flag, s);
args_set(args, flag, new);
break;
}
} }
log_debug("%s: flags end at %u of %u", __func__, i, count); log_debug("%s: flags end at %u of %u", __func__, i, count);
if (i != count) { if (i != count) {
@ -270,8 +218,8 @@ args_parse(const struct args_parse *parse, struct args_value *values,
value = &values[i]; value = &values[i];
s = args_value_as_string(value); s = args_value_as_string(value);
log_debug("%s: %u = %s (type %s)", __func__, i, s, log_debug("%s: %u = %s (type %d)", __func__, i, s,
args_type_to_string (value->type)); value->type);
if (parse->cb != NULL) { if (parse->cb != NULL) {
type = parse->cb(args, args->count, cause); type = parse->cb(args, args->count, cause);
@ -375,13 +323,13 @@ args_copy(struct args *args, int argc, char **argv)
RB_FOREACH(entry, args_tree, &args->tree) { RB_FOREACH(entry, args_tree, &args->tree) {
if (TAILQ_EMPTY(&entry->values)) { if (TAILQ_EMPTY(&entry->values)) {
for (i = 0; i < entry->count; i++) for (i = 0; i < entry->count; i++)
args_set(new_args, entry->flag, NULL, 0); args_set(new_args, entry->flag, NULL);
continue; continue;
} }
TAILQ_FOREACH(value, &entry->values, entry) { TAILQ_FOREACH(value, &entry->values, entry) {
new_value = xcalloc(1, sizeof *new_value); new_value = xcalloc(1, sizeof *new_value);
args_copy_copy_value(new_value, value, argc, argv); args_copy_copy_value(new_value, value, argc, argv);
args_set(new_args, entry->flag, new_value, 0); args_set(new_args, entry->flag, new_value);
} }
} }
if (args->count == 0) if (args->count == 0)
@ -539,7 +487,6 @@ args_print(struct args *args)
char *buf; char *buf;
u_int i, j; u_int i, j;
struct args_entry *entry; struct args_entry *entry;
struct args_entry *last = NULL;
struct args_value *value; struct args_value *value;
len = 1; len = 1;
@ -547,8 +494,6 @@ args_print(struct args *args)
/* Process the flags first. */ /* Process the flags first. */
RB_FOREACH(entry, args_tree, &args->tree) { RB_FOREACH(entry, args_tree, &args->tree) {
if (entry->flags & ARGS_ENTRY_OPTIONAL_VALUE)
continue;
if (!TAILQ_EMPTY(&entry->values)) if (!TAILQ_EMPTY(&entry->values))
continue; continue;
@ -560,16 +505,6 @@ args_print(struct args *args)
/* Then the flags with arguments. */ /* Then the flags with arguments. */
RB_FOREACH(entry, args_tree, &args->tree) { RB_FOREACH(entry, args_tree, &args->tree) {
if (entry->flags & ARGS_ENTRY_OPTIONAL_VALUE) {
if (*buf != '\0')
args_print_add(&buf, &len, " -%c", entry->flag);
else
args_print_add(&buf, &len, "-%c", entry->flag);
last = entry;
continue;
}
if (TAILQ_EMPTY(&entry->values))
continue;
TAILQ_FOREACH(value, &entry->values, entry) { TAILQ_FOREACH(value, &entry->values, entry) {
if (*buf != '\0') if (*buf != '\0')
args_print_add(&buf, &len, " -%c", entry->flag); args_print_add(&buf, &len, " -%c", entry->flag);
@ -577,10 +512,7 @@ args_print(struct args *args)
args_print_add(&buf, &len, "-%c", entry->flag); args_print_add(&buf, &len, "-%c", entry->flag);
args_print_add_value(&buf, &len, value); args_print_add_value(&buf, &len, value);
} }
last = entry;
} }
if (last && (last->flags & ARGS_ENTRY_OPTIONAL_VALUE))
args_print_add(&buf, &len, " --");
/* And finally the argument vector. */ /* And finally the argument vector. */
for (i = 0; i < args->count; i++) for (i = 0; i < args->count; i++)
@ -650,7 +582,7 @@ args_has(struct args *args, u_char flag)
/* Set argument value in the arguments tree. */ /* Set argument value in the arguments tree. */
void void
args_set(struct args *args, u_char flag, struct args_value *value, int flags) args_set(struct args *args, u_char flag, struct args_value *value)
{ {
struct args_entry *entry; struct args_entry *entry;
@ -659,15 +591,12 @@ args_set(struct args *args, u_char flag, struct args_value *value, int flags)
entry = xcalloc(1, sizeof *entry); entry = xcalloc(1, sizeof *entry);
entry->flag = flag; entry->flag = flag;
entry->count = 1; entry->count = 1;
entry->flags = flags;
TAILQ_INIT(&entry->values); TAILQ_INIT(&entry->values);
RB_INSERT(args_tree, &args->tree, entry); RB_INSERT(args_tree, &args->tree, entry);
} else } else
entry->count++; entry->count++;
if (value != NULL && value->type != ARGS_NONE) if (value != NULL && value->type != ARGS_NONE)
TAILQ_INSERT_TAIL(&entry->values, value, entry); TAILQ_INSERT_TAIL(&entry->values, value, entry);
else
free(value);
} }
/* Get argument value. Will be NULL if it isn't present. */ /* Get argument value. Will be NULL if it isn't present. */
@ -767,7 +696,6 @@ args_make_commands_prepare(struct cmd *self, struct cmdq_item *item, u_int idx,
struct args_value *value; struct args_value *value;
struct args_command_state *state; struct args_command_state *state;
const char *cmd; const char *cmd;
const char *file;
state = xcalloc(1, sizeof *state); state = xcalloc(1, sizeof *state);
@ -794,9 +722,7 @@ args_make_commands_prepare(struct cmd *self, struct cmdq_item *item, u_int idx,
if (wait) if (wait)
state->pi.item = item; state->pi.item = item;
cmd_get_source(self, &file, &state->pi.line); cmd_get_source(self, &state->pi.file, &state->pi.line);
if (file != NULL)
state->pi.file = xstrdup(file);
state->pi.c = tc; state->pi.c = tc;
if (state->pi.c != NULL) if (state->pi.c != NULL)
state->pi.c->references++; state->pi.c->references++;
@ -821,8 +747,6 @@ args_make_commands(struct args_command_state *state, int argc, char **argv,
} }
cmd = xstrdup(state->cmd); cmd = xstrdup(state->cmd);
log_debug("%s: %s", __func__, cmd);
cmd_log_argv(argc, argv, __func__);
for (i = 0; i < argc; i++) { for (i = 0; i < argc; i++) {
new_cmd = cmd_template_replace(cmd, argv[i], i + 1); new_cmd = cmd_template_replace(cmd, argv[i], i + 1);
log_debug("%s: %%%u %s: %s", __func__, i + 1, argv[i], new_cmd); log_debug("%s: %%%u %s: %s", __func__, i + 1, argv[i], new_cmd);
@ -851,7 +775,6 @@ args_make_commands_free(struct args_command_state *state)
cmd_list_free(state->cmdlist); cmd_list_free(state->cmdlist);
if (state->pi.c != NULL) if (state->pi.c != NULL)
server_client_unref(state->pi.c); server_client_unref(state->pi.c);
free((void *)state->pi.file);
free(state->cmd); free(state->cmd);
free(state); free(state);
} }
@ -925,41 +848,6 @@ args_strtonum(struct args *args, u_char flag, long long minval,
return (ll); return (ll);
} }
/* Convert an argument value to a number, and expand formats. */
long long
args_strtonum_and_expand(struct args *args, u_char flag, long long minval,
long long maxval, struct cmdq_item *item, char **cause)
{
const char *errstr;
char *formatted;
long long ll;
struct args_entry *entry;
struct args_value *value;
if ((entry = args_find(args, flag)) == NULL) {
*cause = xstrdup("missing");
return (0);
}
value = TAILQ_LAST(&entry->values, args_values);
if (value == NULL ||
value->type != ARGS_STRING ||
value->string == NULL) {
*cause = xstrdup("missing");
return (0);
}
formatted = format_single_from_target(item, value->string);
ll = strtonum(formatted, minval, maxval, &errstr);
free(formatted);
if (errstr != NULL) {
*cause = xstrdup(errstr);
return (0);
}
*cause = NULL;
return (ll);
}
/* Convert an argument to a number which may be a percentage. */ /* Convert an argument to a number which may be a percentage. */
long long long long
args_percentage(struct args *args, u_char flag, long long minval, args_percentage(struct args *args, u_char flag, long long minval,
@ -972,10 +860,6 @@ args_percentage(struct args *args, u_char flag, long long minval,
*cause = xstrdup("missing"); *cause = xstrdup("missing");
return (0); return (0);
} }
if (TAILQ_EMPTY(&entry->values)) {
*cause = xstrdup("empty");
return (0);
}
value = TAILQ_LAST(&entry->values, args_values)->string; value = TAILQ_LAST(&entry->values, args_values)->string;
return (args_string_percentage(value, minval, maxval, curval, cause)); return (args_string_percentage(value, minval, maxval, curval, cause));
} }
@ -990,10 +874,6 @@ args_string_percentage(const char *value, long long minval, long long maxval,
size_t valuelen = strlen(value); size_t valuelen = strlen(value);
char *copy; char *copy;
if (valuelen == 0) {
*cause = xstrdup("empty");
return (0);
}
if (value[valuelen - 1] == '%') { if (value[valuelen - 1] == '%') {
copy = xstrdup(value); copy = xstrdup(value);
copy[valuelen - 1] = '\0'; copy[valuelen - 1] = '\0';
@ -1024,74 +904,3 @@ args_string_percentage(const char *value, long long minval, long long maxval,
*cause = NULL; *cause = NULL;
return (ll); return (ll);
} }
/*
* Convert an argument to a number which may be a percentage, and expand
* formats.
*/
long long
args_percentage_and_expand(struct args *args, u_char flag, long long minval,
long long maxval, long long curval, struct cmdq_item *item, char **cause)
{
const char *value;
struct args_entry *entry;
if ((entry = args_find(args, flag)) == NULL) {
*cause = xstrdup("missing");
return (0);
}
if (TAILQ_EMPTY(&entry->values)) {
*cause = xstrdup("empty");
return (0);
}
value = TAILQ_LAST(&entry->values, args_values)->string;
return (args_string_percentage_and_expand(value, minval, maxval, curval,
item, cause));
}
/*
* Convert a string to a number which may be a percentage, and expand formats.
*/
long long
args_string_percentage_and_expand(const char *value, long long minval,
long long maxval, long long curval, struct cmdq_item *item, char **cause)
{
const char *errstr;
long long ll;
size_t valuelen = strlen(value);
char *copy, *f;
if (value[valuelen - 1] == '%') {
copy = xstrdup(value);
copy[valuelen - 1] = '\0';
f = format_single_from_target(item, copy);
ll = strtonum(f, 0, 100, &errstr);
free(f);
free(copy);
if (errstr != NULL) {
*cause = xstrdup(errstr);
return (0);
}
ll = (curval * ll) / 100;
if (ll < minval) {
*cause = xstrdup("too small");
return (0);
}
if (ll > maxval) {
*cause = xstrdup("too large");
return (0);
}
} else {
f = format_single_from_target(item, value);
ll = strtonum(f, minval, maxval, &errstr);
free(f);
if (errstr != NULL) {
*cause = xstrdup(errstr);
return (0);
}
}
*cause = NULL;
return (ll);
}

47
cfg.c
View File

@ -51,7 +51,8 @@ cfg_done(__unused struct cmdq_item *item, __unused void *data)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
cfg_finished = 1; cfg_finished = 1;
cfg_show_causes(NULL); if (!RB_EMPTY(&sessions))
cfg_show_causes(RB_MIN(sessions, &sessions));
if (cfg_item != NULL) if (cfg_item != NULL)
cmdq_continue(cfg_item); cmdq_continue(cfg_item);
@ -66,7 +67,6 @@ start_cfg(void)
{ {
struct client *c; struct client *c;
u_int i; u_int i;
int flags = 0;
/* /*
* Configuration files are loaded without a client, so commands are run * Configuration files are loaded without a client, so commands are run
@ -84,17 +84,19 @@ start_cfg(void)
cmdq_append(c, cfg_item); cmdq_append(c, cfg_item);
} }
if (cfg_quiet) for (i = 0; i < cfg_nfiles; i++) {
flags = CMD_PARSE_QUIET; if (cfg_quiet)
for (i = 0; i < cfg_nfiles; i++) load_cfg(cfg_files[i], c, NULL, CMD_PARSE_QUIET, NULL);
load_cfg(cfg_files[i], c, NULL, NULL, flags, NULL); else
load_cfg(cfg_files[i], c, NULL, 0, NULL);
}
cmdq_append(NULL, cmdq_get_callback(cfg_done, NULL)); cmdq_append(NULL, cmdq_get_callback(cfg_done, NULL));
} }
int int
load_cfg(const char *path, struct client *c, struct cmdq_item *item, load_cfg(const char *path, struct client *c, struct cmdq_item *item, int flags,
struct cmd_find_state *current, int flags, struct cmdq_item **new_item) struct cmdq_item **new_item)
{ {
FILE *f; FILE *f;
struct cmd_parse_input pi; struct cmd_parse_input pi;
@ -133,7 +135,7 @@ load_cfg(const char *path, struct client *c, struct cmdq_item *item,
} }
if (item != NULL) if (item != NULL)
state = cmdq_copy_state(cmdq_get_state(item), current); state = cmdq_copy_state(cmdq_get_state(item));
else else
state = cmdq_new_state(NULL, NULL, 0); state = cmdq_new_state(NULL, NULL, 0);
cmdq_add_format(state, "current_file", "%s", pi.file); cmdq_add_format(state, "current_file", "%s", pi.file);
@ -153,8 +155,8 @@ load_cfg(const char *path, struct client *c, struct cmdq_item *item,
int int
load_cfg_from_buffer(const void *buf, size_t len, const char *path, load_cfg_from_buffer(const void *buf, size_t len, const char *path,
struct client *c, struct cmdq_item *item, struct cmd_find_state *current, struct client *c, struct cmdq_item *item, int flags,
int flags, struct cmdq_item **new_item) struct cmdq_item **new_item)
{ {
struct cmd_parse_input pi; struct cmd_parse_input pi;
struct cmd_parse_result *pr; struct cmd_parse_result *pr;
@ -185,7 +187,7 @@ load_cfg_from_buffer(const void *buf, size_t len, const char *path,
} }
if (item != NULL) if (item != NULL)
state = cmdq_copy_state(cmdq_get_state(item), current); state = cmdq_copy_state(cmdq_get_state(item));
else else
state = cmdq_new_state(NULL, NULL, 0); state = cmdq_new_state(NULL, NULL, 0);
cmdq_add_format(state, "current_file", "%s", pi.file); cmdq_add_format(state, "current_file", "%s", pi.file);
@ -236,29 +238,11 @@ cfg_print_causes(struct cmdq_item *item)
void void
cfg_show_causes(struct session *s) cfg_show_causes(struct session *s)
{ {
struct client *c = TAILQ_FIRST(&clients);
struct window_pane *wp; struct window_pane *wp;
struct window_mode_entry *wme; struct window_mode_entry *wme;
u_int i; u_int i;
if (cfg_ncauses == 0) if (s == NULL || cfg_ncauses == 0)
return;
if (c != NULL && (c->flags & CLIENT_CONTROL)) {
for (i = 0; i < cfg_ncauses; i++) {
control_write(c, "%%config-error %s", cfg_causes[i]);
free(cfg_causes[i]);
}
goto out;
}
if (s == NULL) {
if (c != NULL && c->session != NULL)
s = c->session;
else
s = RB_MIN(sessions, &sessions);
}
if (s == NULL || s->attached == 0) /* wait for an attached session */
return; return;
wp = s->curw->window->active; wp = s->curw->window->active;
@ -270,7 +254,6 @@ cfg_show_causes(struct session *s)
free(cfg_causes[i]); free(cfg_causes[i]);
} }
out:
free(cfg_causes); free(cfg_causes);
cfg_causes = NULL; cfg_causes = NULL;
cfg_ncauses = 0; cfg_ncauses = 0;

View File

@ -245,6 +245,9 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
u_int ncaps = 0; u_int ncaps = 0;
struct args_value *values; struct args_value *values;
/* Ignore SIGCHLD now or daemon() in the server will leave a zombie. */
signal(SIGCHLD, SIG_IGN);
/* Set up the initial command. */ /* Set up the initial command. */
if (shell_command != NULL) { if (shell_command != NULL) {
msg = MSG_SHELL; msg = MSG_SHELL;
@ -281,12 +284,6 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
log_debug("flags are %#llx", (unsigned long long)client_flags); log_debug("flags are %#llx", (unsigned long long)client_flags);
/* Initialize the client socket and start the server. */ /* Initialize the client socket and start the server. */
#ifdef HAVE_SYSTEMD
if (systemd_activated()) {
/* socket-based activation, do not even try to be a client. */
fd = server_start(client_proc, flags, base, 0, NULL);
} else
#endif
fd = client_connect(base, socket_path, client_flags); fd = client_connect(base, socket_path, client_flags);
if (fd == -1) { if (fd == -1) {
if (errno == ECONNREFUSED) { if (errno == ECONNREFUSED) {
@ -452,12 +449,11 @@ client_send_identify(const char *ttynam, const char *termname, char **caps,
{ {
char **ss; char **ss;
size_t sslen; size_t sslen;
int fd; int fd, flags = client_flags;
uint64_t flags = client_flags;
pid_t pid; pid_t pid;
u_int i; u_int i;
proc_send(client_peer, MSG_IDENTIFY_LONGFLAGS, -1, &flags, sizeof flags); proc_send(client_peer, MSG_IDENTIFY_FLAGS, -1, &flags, sizeof flags);
proc_send(client_peer, MSG_IDENTIFY_LONGFLAGS, -1, &client_flags, proc_send(client_peer, MSG_IDENTIFY_LONGFLAGS, -1, &client_flags,
sizeof client_flags); sizeof client_flags);
@ -498,10 +494,20 @@ client_send_identify(const char *ttynam, const char *termname, char **caps,
static __dead void static __dead void
client_exec(const char *shell, const char *shellcmd) client_exec(const char *shell, const char *shellcmd)
{ {
char *argv0; const char *name, *ptr;
char *argv0;
log_debug("shell %s, command %s", shell, shellcmd); log_debug("shell %s, command %s", shell, shellcmd);
argv0 = shell_argv0(shell, !!(client_flags & CLIENT_LOGIN));
ptr = strrchr(shell, '/');
if (ptr != NULL && *(ptr + 1) != '\0')
name = ptr + 1;
else
name = shell;
if (client_flags & CLIENT_LOGIN)
xasprintf(&argv0, "-%s", name);
else
xasprintf(&argv0, "%s", name);
setenv("SHELL", shell, 1); setenv("SHELL", shell, 1);
proc_clear_signals(client_proc, 1); proc_clear_signals(client_proc, 1);
@ -521,22 +527,11 @@ client_signal(int sig)
{ {
struct sigaction sigact; struct sigaction sigact;
int status; int status;
pid_t pid;
log_debug("%s: %s", __func__, strsignal(sig)); log_debug("%s: %s", __func__, strsignal(sig));
if (sig == SIGCHLD) { if (sig == SIGCHLD)
for (;;) { waitpid(WAIT_ANY, &status, WNOHANG);
pid = waitpid(WAIT_ANY, &status, WNOHANG); else if (!client_attached) {
if (pid == 0)
break;
if (pid == -1) {
if (errno == ECHILD)
break;
log_debug("waitpid failed: %s",
strerror(errno));
}
}
} else if (!client_attached) {
if (sig == SIGTERM || sig == SIGHUP) if (sig == SIGTERM || sig == SIGHUP)
proc_exit(client_proc); proc_exit(client_proc);
} else { } else {
@ -699,9 +694,6 @@ client_dispatch_wait(struct imsg *imsg)
!(client_flags & CLIENT_CONTROL), client_file_check_cb, !(client_flags & CLIENT_CONTROL), client_file_check_cb,
NULL); NULL);
break; break;
case MSG_READ_CANCEL:
file_read_cancel(&client_files, imsg);
break;
case MSG_WRITE_OPEN: case MSG_WRITE_OPEN:
file_write_open(&client_files, client_peer, imsg, 1, file_write_open(&client_files, client_peer, imsg, 1,
!(client_flags & CLIENT_CONTROL), client_file_check_cb, !(client_flags & CLIENT_CONTROL), client_file_check_cb,

View File

@ -158,9 +158,6 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
c->flags |= CLIENT_ATTACHED; c->flags |= CLIENT_ATTACHED;
} }
if (cfg_finished)
cfg_show_causes(s);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@ -38,7 +38,7 @@ const struct cmd_entry cmd_bind_key_entry = {
.args = { "nrN:T:", 1, -1, cmd_bind_key_args_parse }, .args = { "nrN:T:", 1, -1, cmd_bind_key_args_parse },
.usage = "[-nr] [-T key-table] [-N note] key " .usage = "[-nr] [-T key-table] [-N note] key "
"[command [argument ...]]", "[command [arguments]]",
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_bind_key_exec .exec = cmd_bind_key_exec

View File

@ -99,7 +99,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
w = wp->window = window_create(w->sx, w->sy, w->xpixel, w->ypixel); w = wp->window = window_create(w->sx, w->sy, w->xpixel, w->ypixel);
options_set_parent(wp->options, w->options); options_set_parent(wp->options, w->options);
wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED); wp->flags |= PANE_STYLECHANGED;
TAILQ_INSERT_HEAD(&w->panes, wp, entry); TAILQ_INSERT_HEAD(&w->panes, wp, entry);
w->active = wp; w->active = wp;
w->latest = tc; w->latest = tc;
@ -115,7 +115,6 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
layout_init(w, wp); layout_init(w, wp);
wp->flags |= PANE_CHANGED; wp->flags |= PANE_CHANGED;
colour_palette_from_option(&wp->palette, wp->options);
if (idx == -1) if (idx == -1)
idx = -1 - options_get_number(dst_s->options, "base-index"); idx = -1 - options_get_number(dst_s->options, "base-index");

View File

@ -39,8 +39,8 @@ const struct cmd_entry cmd_capture_pane_entry = {
.name = "capture-pane", .name = "capture-pane",
.alias = "capturep", .alias = "capturep",
.args = { "ab:CeE:JMNpPqS:Tt:", 0, 0, NULL }, .args = { "ab:CeE:JNpPqS:t:", 0, 0, NULL },
.usage = "[-aCeJMNpPqT] " CMD_BUFFER_USAGE " [-E end-line] " .usage = "[-aCeJNpPq] " CMD_BUFFER_USAGE " [-E end-line] "
"[-S start-line] " CMD_TARGET_PANE_USAGE, "[-S start-line] " CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
@ -53,8 +53,8 @@ const struct cmd_entry cmd_clear_history_entry = {
.name = "clear-history", .name = "clear-history",
.alias = "clearhist", .alias = "clearhist",
.args = { "Ht:", 0, 0, NULL }, .args = { "t:", 0, 0, NULL },
.usage = "[-H] " CMD_TARGET_PANE_USAGE, .usage = CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
@ -107,16 +107,14 @@ static char *
cmd_capture_pane_history(struct args *args, struct cmdq_item *item, cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
struct window_pane *wp, size_t *len) struct window_pane *wp, size_t *len)
{ {
struct grid *gd; struct grid *gd;
const struct grid_line *gl; const struct grid_line *gl;
struct screen *s; struct grid_cell *gc = NULL;
struct grid_cell *gc = NULL; int n, with_codes, escape_c0, join_lines, no_trim;
struct window_mode_entry *wme; u_int i, sx, top, bottom, tmp;
int n, join_lines, flags = 0; char *cause, *buf, *line;
u_int i, sx, top, bottom, tmp; const char *Sflag, *Eflag;
char *cause, *buf, *line; size_t linelen;
const char *Sflag, *Eflag;
size_t linelen;
sx = screen_size_x(&wp->base); sx = screen_size_x(&wp->base);
if (args_has(args, 'a')) { if (args_has(args, 'a')) {
@ -128,27 +126,14 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
} }
return (xstrdup("")); return (xstrdup(""));
} }
s = &wp->base; } else
} else if (args_has(args, 'M')) {
wme = TAILQ_FIRST(&wp->modes);
if (wme != NULL && wme->mode->get_screen != NULL) {
s = wme->mode->get_screen (wme);
gd = s->grid;
} else {
s = &wp->base;
gd = wp->base.grid;
}
} else {
s = &wp->base;
gd = wp->base.grid; gd = wp->base.grid;
}
Sflag = args_get(args, 'S'); Sflag = args_get(args, 'S');
if (Sflag != NULL && strcmp(Sflag, "-") == 0) if (Sflag != NULL && strcmp(Sflag, "-") == 0)
top = 0; top = 0;
else { else {
n = args_strtonum_and_expand(args, 'S', INT_MIN, SHRT_MAX, n = args_strtonum(args, 'S', INT_MIN, SHRT_MAX, &cause);
item, &cause);
if (cause != NULL) { if (cause != NULL) {
top = gd->hsize; top = gd->hsize;
free(cause); free(cause);
@ -164,8 +149,7 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
if (Eflag != NULL && strcmp(Eflag, "-") == 0) if (Eflag != NULL && strcmp(Eflag, "-") == 0)
bottom = gd->hsize + gd->sy - 1; bottom = gd->hsize + gd->sy - 1;
else { else {
n = args_strtonum_and_expand(args, 'E', INT_MIN, SHRT_MAX, n = args_strtonum(args, 'E', INT_MIN, SHRT_MAX, &cause);
item, &cause);
if (cause != NULL) { if (cause != NULL) {
bottom = gd->hsize + gd->sy - 1; bottom = gd->hsize + gd->sy - 1;
free(cause); free(cause);
@ -183,19 +167,15 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
top = tmp; top = tmp;
} }
with_codes = args_has(args, 'e');
escape_c0 = args_has(args, 'C');
join_lines = args_has(args, 'J'); join_lines = args_has(args, 'J');
if (args_has(args, 'e')) no_trim = args_has(args, 'N');
flags |= GRID_STRING_WITH_SEQUENCES;
if (args_has(args, 'C'))
flags |= GRID_STRING_ESCAPE_SEQUENCES;
if (!join_lines && !args_has(args, 'T'))
flags |= GRID_STRING_EMPTY_CELLS;
if (!join_lines && !args_has(args, 'N'))
flags |= GRID_STRING_TRIM_SPACES;
buf = NULL; buf = NULL;
for (i = top; i <= bottom; i++) { for (i = top; i <= bottom; i++) {
line = grid_string_cells(gd, 0, i, sx, &gc, flags, s); line = grid_string_cells(gd, 0, i, sx, &gc, with_codes,
escape_c0, !join_lines && !no_trim);
linelen = strlen(line); linelen = strlen(line);
buf = cmd_capture_pane_append(buf, len, line, linelen); buf = cmd_capture_pane_append(buf, len, line, linelen);
@ -222,8 +202,6 @@ cmd_capture_pane_exec(struct cmd *self, struct cmdq_item *item)
if (cmd_get_entry(self) == &cmd_clear_history_entry) { if (cmd_get_entry(self) == &cmd_clear_history_entry) {
window_pane_reset_mode_all(wp); window_pane_reset_mode_all(wp);
grid_clear_history(wp->base.grid); grid_clear_history(wp->base.grid);
if (args_has(args, 'H'))
screen_reset_hyperlinks(wp->screen);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@ -33,7 +33,7 @@ const struct cmd_entry cmd_choose_tree_entry = {
.name = "choose-tree", .name = "choose-tree",
.alias = NULL, .alias = NULL,
.args = { "F:f:GK:NO:rst:wyZ", 0, 1, cmd_choose_tree_args_parse }, .args = { "F:f:GK:NO:rst:wZ", 0, 1, cmd_choose_tree_args_parse },
.usage = "[-GNrswZ] [-F format] [-f filter] [-K key-format] " .usage = "[-GNrswZ] [-F format] [-f filter] [-K key-format] "
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]", "[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
@ -47,7 +47,7 @@ const struct cmd_entry cmd_choose_client_entry = {
.name = "choose-client", .name = "choose-client",
.alias = NULL, .alias = NULL,
.args = { "F:f:K:NO:rt:yZ", 0, 1, cmd_choose_tree_args_parse }, .args = { "F:f:K:NO:rt:Z", 0, 1, cmd_choose_tree_args_parse },
.usage = "[-NrZ] [-F format] [-f filter] [-K key-format] " .usage = "[-NrZ] [-F format] [-f filter] [-K key-format] "
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]", "[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
@ -61,7 +61,7 @@ const struct cmd_entry cmd_choose_buffer_entry = {
.name = "choose-buffer", .name = "choose-buffer",
.alias = NULL, .alias = NULL,
.args = { "F:f:K:NO:rt:yZ", 0, 1, cmd_choose_tree_args_parse }, .args = { "F:f:K:NO:rt:Z", 0, 1, cmd_choose_tree_args_parse },
.usage = "[-NrZ] [-F format] [-f filter] [-K key-format] " .usage = "[-NrZ] [-F format] [-f filter] [-K key-format] "
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]", "[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
@ -75,7 +75,7 @@ const struct cmd_entry cmd_customize_mode_entry = {
.name = "customize-mode", .name = "customize-mode",
.alias = NULL, .alias = NULL,
.args = { "F:f:Nt:yZ", 0, 0, NULL }, .args = { "F:f:Nt:Z", 0, 0, NULL },
.usage = "[-NZ] [-F format] [-f filter] " CMD_TARGET_PANE_USAGE, .usage = "[-NZ] [-F format] [-f filter] " CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
@ -100,7 +100,7 @@ cmd_choose_tree_exec(struct cmd *self, struct cmdq_item *item)
const struct window_mode *mode; const struct window_mode *mode;
if (cmd_get_entry(self) == &cmd_choose_buffer_entry) { if (cmd_get_entry(self) == &cmd_choose_buffer_entry) {
if (paste_is_empty()) if (paste_get_top(NULL) == NULL)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
mode = &window_buffer_mode; mode = &window_buffer_mode;
} else if (cmd_get_entry(self) == &cmd_choose_client_entry) { } else if (cmd_get_entry(self) == &cmd_choose_client_entry) {

View File

@ -44,7 +44,7 @@ const struct cmd_entry cmd_command_prompt_entry = {
.args = { "1bFkiI:Np:t:T:", 0, 1, cmd_command_prompt_args_parse }, .args = { "1bFkiI:Np:t:T:", 0, 1, cmd_command_prompt_args_parse },
.usage = "[-1bFkiN] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE .usage = "[-1bFkiN] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE
" [-T prompt-type] [template]", " [-T type] [template]",
.flags = CMD_CLIENT_TFLAG, .flags = CMD_CLIENT_TFLAG,
.exec = cmd_command_prompt_exec .exec = cmd_command_prompt_exec
@ -143,7 +143,6 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
cdata->prompt_type = status_prompt_type(type); cdata->prompt_type = status_prompt_type(type);
if (cdata->prompt_type == PROMPT_TYPE_INVALID) { if (cdata->prompt_type == PROMPT_TYPE_INVALID) {
cmdq_error(item, "unknown type: %s", type); cmdq_error(item, "unknown type: %s", type);
cmd_command_prompt_free(cdata);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} else } else
@ -180,10 +179,10 @@ cmd_command_prompt_callback(struct client *c, void *data, const char *s,
if (s == NULL) if (s == NULL)
goto out; goto out;
if (done) { if (done) {
if (cdata->flags & PROMPT_INCREMENTAL) if (cdata->flags & PROMPT_INCREMENTAL)
goto out; goto out;
cmd_append_argv(&cdata->argc, &cdata->argv, s); cmd_append_argv(&cdata->argc, &cdata->argv, s);
if (++cdata->current != cdata->count) { if (++cdata->current != cdata->count) {
prompt = &cdata->prompts[cdata->current]; prompt = &cdata->prompts[cdata->current];
@ -194,11 +193,8 @@ cmd_command_prompt_callback(struct client *c, void *data, const char *s,
argc = cdata->argc; argc = cdata->argc;
argv = cmd_copy_argv(cdata->argc, cdata->argv); argv = cmd_copy_argv(cdata->argc, cdata->argv);
if (!done) cmd_append_argv(&argc, &argv, s);
cmd_append_argv(&argc, &argv, s);
if (done) { if (done) {
cmd_free_argv(cdata->argc, cdata->argv);
cdata->argc = argc; cdata->argc = argc;
cdata->argv = cmd_copy_argv(argc, argv); cdata->argv = cmd_copy_argv(argc, argv);
} }

View File

@ -41,9 +41,8 @@ const struct cmd_entry cmd_confirm_before_entry = {
.name = "confirm-before", .name = "confirm-before",
.alias = "confirm", .alias = "confirm",
.args = { "bc:p:t:y", 1, 1, cmd_confirm_before_args_parse }, .args = { "bp:t:", 1, 1, cmd_confirm_before_args_parse },
.usage = "[-by] [-c confirm-key] [-p prompt] " CMD_TARGET_CLIENT_USAGE .usage = "[-b] [-p prompt] " CMD_TARGET_CLIENT_USAGE " command",
" command",
.flags = CMD_CLIENT_TFLAG, .flags = CMD_CLIENT_TFLAG,
.exec = cmd_confirm_before_exec .exec = cmd_confirm_before_exec
@ -52,8 +51,6 @@ const struct cmd_entry cmd_confirm_before_entry = {
struct cmd_confirm_before_data { struct cmd_confirm_before_data {
struct cmdq_item *item; struct cmdq_item *item;
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
u_char confirm_key;
int default_yes;
}; };
static enum args_parse_type static enum args_parse_type
@ -71,40 +68,22 @@ cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item)
struct client *tc = cmdq_get_target_client(item); struct client *tc = cmdq_get_target_client(item);
struct cmd_find_state *target = cmdq_get_target(item); struct cmd_find_state *target = cmdq_get_target(item);
char *new_prompt; char *new_prompt;
const char *confirm_key, *prompt, *cmd; const char *prompt, *cmd;
int wait = !args_has(args, 'b'); int wait = !args_has(args, 'b');
cdata = xcalloc(1, sizeof *cdata); cdata = xcalloc(1, sizeof *cdata);
cdata->cmdlist = args_make_commands_now(self, item, 0, 1); cdata->cmdlist = args_make_commands_now(self, item, 0, 1);
if (cdata->cmdlist == NULL) { if (cdata->cmdlist == NULL)
free(cdata);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
}
if (wait) if (wait)
cdata->item = item; cdata->item = item;
cdata->default_yes = args_has(args, 'y');
if ((confirm_key = args_get(args, 'c')) != NULL) {
if (confirm_key[1] == '\0' &&
confirm_key[0] > 31 &&
confirm_key[0] < 127)
cdata->confirm_key = confirm_key[0];
else {
cmdq_error(item, "invalid confirm key");
free(cdata);
return (CMD_RETURN_ERROR);
}
}
else
cdata->confirm_key = 'y';
if ((prompt = args_get(args, 'p')) != NULL) if ((prompt = args_get(args, 'p')) != NULL)
xasprintf(&new_prompt, "%s ", prompt); xasprintf(&new_prompt, "%s ", prompt);
else { else {
cmd = cmd_get_entry(cmd_list_first(cdata->cmdlist))->name; cmd = cmd_get_entry(cmd_list_first(cdata->cmdlist))->name;
xasprintf(&new_prompt, "Confirm '%s'? (%c/n) ", cmd, xasprintf(&new_prompt, "Confirm '%s'? (y/n) ", cmd);
cdata->confirm_key);
} }
status_prompt_set(tc, target, new_prompt, NULL, status_prompt_set(tc, target, new_prompt, NULL,
@ -128,9 +107,9 @@ cmd_confirm_before_callback(struct client *c, void *data, const char *s,
if (c->flags & CLIENT_DEAD) if (c->flags & CLIENT_DEAD)
goto out; goto out;
if (s == NULL) if (s == NULL || *s == '\0')
goto out; goto out;
if (s[0] != cdata->confirm_key && (s[0] != '\r' || !cdata->default_yes)) if (tolower((u_char)s[0]) != 'y' || s[1] != '\0')
goto out; goto out;
retcode = 0; retcode = 0;
@ -144,12 +123,12 @@ cmd_confirm_before_callback(struct client *c, void *data, const char *s,
} }
out: out:
if (item != NULL) { if (item != NULL) {
if (cmdq_get_client(item) != NULL && if (cmdq_get_client(item) != NULL &&
cmdq_get_client(item)->session == NULL) cmdq_get_client(item)->session == NULL)
cmdq_get_client(item)->retval = retcode; cmdq_get_client(item)->retval = retcode;
cmdq_continue(item); cmdq_continue(item);
} }
return (0); return (0);
} }

View File

@ -30,8 +30,8 @@ const struct cmd_entry cmd_copy_mode_entry = {
.name = "copy-mode", .name = "copy-mode",
.alias = NULL, .alias = NULL,
.args = { "deHMqSs:t:u", 0, 0, NULL }, .args = { "eHMs:t:uq", 0, 0, NULL },
.usage = "[-deHMqSu] [-s src-pane] " CMD_TARGET_PANE_USAGE, .usage = "[-eHMuq] [-s src-pane] " CMD_TARGET_PANE_USAGE,
.source = { 's', CMD_FIND_PANE, 0 }, .source = { 's', CMD_FIND_PANE, 0 },
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
@ -91,13 +91,6 @@ cmd_copy_mode_exec(struct cmd *self, struct cmdq_item *item)
} }
if (args_has(args, 'u')) if (args_has(args, 'u'))
window_copy_pageup(wp, 0); window_copy_pageup(wp, 0);
if (args_has(args, 'd'))
window_copy_pagedown(wp, 0, args_has(args, 'e'));
if (args_has(args, 'S')) {
window_copy_scroll(wp, c->tty.mouse_slider_mpos, event->m.y,
args_has(args, 'e'));
return (CMD_RETURN_NORMAL);
}
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@ -38,11 +38,9 @@ const struct cmd_entry cmd_display_menu_entry = {
.name = "display-menu", .name = "display-menu",
.alias = "menu", .alias = "menu",
.args = { "b:c:C:H:s:S:MOt:T:x:y:", 1, -1, cmd_display_menu_args_parse }, .args = { "c:t:OT:x:y:", 1, -1, cmd_display_menu_args_parse },
.usage = "[-MO] [-b border-lines] [-c target-client] " .usage = "[-O] [-c target-client] " CMD_TARGET_PANE_USAGE " [-T title] "
"[-C starting-choice] [-H selected-style] [-s style] " "[-x position] [-y position] name key command ...",
"[-S border-style] " CMD_TARGET_PANE_USAGE " [-T title] "
"[-x position] [-y position] name [key] [command] ...",
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
@ -58,8 +56,8 @@ const struct cmd_entry cmd_display_popup_entry = {
.usage = "[-BCE] [-b border-lines] [-c target-client] " .usage = "[-BCE] [-b border-lines] [-c target-client] "
"[-d start-directory] [-e environment] [-h height] " "[-d start-directory] [-e environment] [-h height] "
"[-s style] [-S border-style] " CMD_TARGET_PANE_USAGE "[-s style] [-S border-style] " CMD_TARGET_PANE_USAGE
" [-T title] [-w width] [-x position] [-y position] " "[-T title] [-w width] [-x position] [-y position] "
"[shell-command [argument ...]]", "[shell-command]",
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
@ -276,7 +274,6 @@ cmd_display_menu_get_position(struct client *tc, struct cmdq_item *item,
log_debug("%s: -y: %s = %s = %u (-h %u)", __func__, yp, p, *py, h); log_debug("%s: -y: %s = %s = %u (-h %u)", __func__, yp, p, *py, h);
free(p); free(p);
format_free(ft);
return (1); return (1);
} }
@ -289,41 +286,19 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
struct client *tc = cmdq_get_target_client(item); struct client *tc = cmdq_get_target_client(item);
struct menu *menu = NULL; struct menu *menu = NULL;
struct menu_item menu_item; struct menu_item menu_item;
const char *key, *name, *value; const char *key, *name;
const char *style = args_get(args, 's'); char *title;
const char *border_style = args_get(args, 'S'); int flags = 0;
const char *selected_style = args_get(args, 'H');
enum box_lines lines = BOX_LINES_DEFAULT;
char *title, *cause;
int flags = 0, starting_choice = 0;
u_int px, py, i, count = args_count(args); u_int px, py, i, count = args_count(args);
struct options *o = target->s->curw->window->options;
struct options_entry *oe;
if (tc->overlay_draw != NULL) if (tc->overlay_draw != NULL)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
if (args_has(args, 'C')) {
if (strcmp(args_get(args, 'C'), "-") == 0)
starting_choice = -1;
else {
starting_choice = args_strtonum(args, 'C', 0, UINT_MAX,
&cause);
if (cause != NULL) {
cmdq_error(item, "starting choice %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
}
}
if (args_has(args, 'T')) if (args_has(args, 'T'))
title = format_single_from_target(item, args_get(args, 'T')); title = format_single_from_target(item, args_get(args, 'T'));
else else
title = xstrdup(""); title = xstrdup("");
menu = menu_create(title); menu = menu_create(title);
free(title);
for (i = 0; i != count; /* nothing */) { for (i = 0; i != count; /* nothing */) {
name = args_string(args, i++); name = args_string(args, i++);
@ -334,6 +309,7 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
if (count - i < 2) { if (count - i < 2) {
cmdq_error(item, "not enough arguments"); cmdq_error(item, "not enough arguments");
free(title);
menu_free(menu); menu_free(menu);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
@ -345,6 +321,7 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
menu_add_item(menu, &menu_item, item, tc, target); menu_add_item(menu, &menu_item, item, tc, target);
} }
free(title);
if (menu == NULL) { if (menu == NULL) {
cmdq_error(item, "invalid menu arguments"); cmdq_error(item, "invalid menu arguments");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
@ -359,24 +336,12 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
value = args_get(args, 'b');
if (value != NULL) {
oe = options_get(o, "menu-border-lines");
lines = options_find_choice(options_table_entry(oe), value,
&cause);
if (lines == -1) {
cmdq_error(item, "menu-border-lines %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
}
if (args_has(args, 'O')) if (args_has(args, 'O'))
flags |= MENU_STAYOPEN; flags |= MENU_STAYOPEN;
if (!event->m.valid && !args_has(args, 'M')) if (!event->m.valid)
flags |= MENU_NOMOUSE; flags |= MENU_NOMOUSE;
if (menu_display(menu, flags, starting_choice, item, px, py, tc, lines, if (menu_display(menu, flags, item, px, py, tc, target, NULL,
style, selected_style, border_style, target, NULL, NULL) != 0) NULL) != 0)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT); return (CMD_RETURN_WAIT);
} }
@ -489,13 +454,11 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
cmd_free_argv(argc, argv); cmd_free_argv(argc, argv);
if (env != NULL) if (env != NULL)
environ_free(env); environ_free(env);
free(cwd);
free(title); free(title);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (env != NULL) if (env != NULL)
environ_free(env); environ_free(env);
free(cwd);
free(title); free(title);
cmd_free_argv(argc, argv); cmd_free_argv(argc, argv);
return (CMD_RETURN_WAIT); return (CMD_RETURN_WAIT);

View File

@ -39,8 +39,8 @@ const struct cmd_entry cmd_display_message_entry = {
.name = "display-message", .name = "display-message",
.alias = "display", .alias = "display",
.args = { "aCc:d:lINpt:F:v", 0, 1, NULL }, .args = { "ac:d:INpt:F:v", 0, 1, NULL },
.usage = "[-aCIlNpv] [-c target-client] [-d delay] [-F format] " .usage = "[-aINpv] [-c target-client] [-d delay] [-F format] "
CMD_TARGET_PANE_USAGE " [message]", CMD_TARGET_PANE_USAGE " [message]",
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL }, .target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
@ -68,11 +68,9 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
struct window_pane *wp = target->wp; struct window_pane *wp = target->wp;
const char *template; const char *template;
char *msg, *cause; char *msg, *cause;
int delay = -1, flags, Nflag = args_has(args, 'N'); int delay = -1, flags;
int Cflag = args_has(args, 'C');
struct format_tree *ft; struct format_tree *ft;
u_int count = args_count(args); u_int count = args_count(args);
struct evbuffer *evb;
if (args_has(args, 'I')) { if (args_has(args, 'I')) {
if (wp == NULL) if (wp == NULL)
@ -134,24 +132,15 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (args_has(args, 'l')) msg = format_expand_time(ft, template);
msg = xstrdup(template);
else
msg = format_expand_time(ft, template);
if (cmdq_get_client(item) == NULL) if (cmdq_get_client(item) == NULL)
cmdq_error(item, "%s", msg); cmdq_error(item, "%s", msg);
else if (args_has(args, 'p')) else if (args_has(args, 'p'))
cmdq_print(item, "%s", msg); cmdq_print(item, "%s", msg);
else if (tc != NULL && (tc->flags & CLIENT_CONTROL)) { else if (tc != NULL) {
evb = evbuffer_new(); status_message_set(tc, delay, 0, args_has(args, 'N'), "%s",
if (evb == NULL) msg);
fatalx("out of memory"); }
evbuffer_add_printf(evb, "%%message %s", msg);
server_client_print(tc, 0, evb);
evbuffer_free(evb);
} else if (tc != NULL)
status_message_set(tc, delay, 0, Nflag, Cflag, "%s", msg);
free(msg); free(msg);
format_free(ft); format_free(ft);

View File

@ -144,7 +144,7 @@ cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
llen = 0; llen = 0;
if (sx < len * 6 || sy < 5) { if (sx < len * 6 || sy < 5) {
tty_attributes(tty, &fgc, &grid_default_cell, NULL, NULL); tty_attributes(tty, &fgc, &grid_default_cell, NULL);
if (sx >= len + llen + 1) { if (sx >= len + llen + 1) {
len += llen + 1; len += llen + 1;
tty_cursor(tty, xoff + px - len / 2, yoff + py); tty_cursor(tty, xoff + px - len / 2, yoff + py);
@ -161,7 +161,7 @@ cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
px -= len * 3; px -= len * 3;
py -= 2; py -= 2;
tty_attributes(tty, &bgc, &grid_default_cell, NULL, NULL); tty_attributes(tty, &bgc, &grid_default_cell, NULL);
for (ptr = buf; *ptr != '\0'; ptr++) { for (ptr = buf; *ptr != '\0'; ptr++) {
if (*ptr < '0' || *ptr > '9') if (*ptr < '0' || *ptr > '9')
continue; continue;
@ -179,7 +179,7 @@ cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
if (sy <= 6) if (sy <= 6)
goto out; goto out;
tty_attributes(tty, &fgc, &grid_default_cell, NULL, NULL); tty_attributes(tty, &fgc, &grid_default_cell, NULL);
if (rlen != 0 && sx >= rlen) { if (rlen != 0 && sx >= rlen) {
tty_cursor(tty, xoff + sx - rlen, yoff); tty_cursor(tty, xoff + sx - rlen, yoff);
tty_putn(tty, rbuf, rlen, rlen); tty_putn(tty, rbuf, rlen, rlen);
@ -246,7 +246,7 @@ cmd_display_panes_key(struct client *c, void *data, struct key_event *event)
wp = window_pane_at_index(w, index); wp = window_pane_at_index(w, index);
if (wp == NULL) if (wp == NULL)
return (1); return (1);
window_unzoom(w, 1); window_unzoom(w);
xasprintf(&expanded, "%%%u", wp->id); xasprintf(&expanded, "%%%u", wp->id);

View File

@ -48,7 +48,6 @@ cmd_find_window_exec(struct cmd *self, struct cmdq_item *item)
struct cmd_find_state *target = cmdq_get_target(item); struct cmd_find_state *target = cmdq_get_target(item);
struct window_pane *wp = target->wp; struct window_pane *wp = target->wp;
const char *s = args_string(args, 0), *suffix = ""; const char *s = args_string(args, 0), *suffix = "";
const char *star = "*";
struct args_value *filter; struct args_value *filter;
int C, N, T; int C, N, T;
@ -56,8 +55,6 @@ cmd_find_window_exec(struct cmd *self, struct cmdq_item *item)
N = args_has(args, 'N'); N = args_has(args, 'N');
T = args_has(args, 'T'); T = args_has(args, 'T');
if (args_has(args, 'r'))
star = "";
if (args_has(args, 'r') && args_has(args, 'i')) if (args_has(args, 'r') && args_has(args, 'i'))
suffix = "/ri"; suffix = "/ri";
else if (args_has(args, 'r')) else if (args_has(args, 'r'))
@ -74,40 +71,40 @@ cmd_find_window_exec(struct cmd *self, struct cmdq_item *item)
if (C && N && T) { if (C && N && T) {
xasprintf(&filter->string, xasprintf(&filter->string,
"#{||:" "#{||:"
"#{C%s:%s},#{||:#{m%s:%s%s%s,#{window_name}}," "#{C%s:%s},#{||:#{m%s:*%s*,#{window_name}},"
"#{m%s:%s%s%s,#{pane_title}}}}", "#{m%s:*%s*,#{pane_title}}}}",
suffix, s, suffix, star, s, star, suffix, star, s, star); suffix, s, suffix, s, suffix, s);
} else if (C && N) { } else if (C && N) {
xasprintf(&filter->string, xasprintf(&filter->string,
"#{||:#{C%s:%s},#{m%s:%s%s%s,#{window_name}}}", "#{||:#{C%s:%s},#{m%s:*%s*,#{window_name}}}",
suffix, s, suffix, star, s, star); suffix, s, suffix, s);
} else if (C && T) { } else if (C && T) {
xasprintf(&filter->string, xasprintf(&filter->string,
"#{||:#{C%s:%s},#{m%s:%s%s%s,#{pane_title}}}", "#{||:#{C%s:%s},#{m%s:*%s*,#{pane_title}}}",
suffix, s, suffix, star, s, star); suffix, s, suffix, s);
} else if (N && T) { } else if (N && T) {
xasprintf(&filter->string, xasprintf(&filter->string,
"#{||:#{m%s:%s%s%s,#{window_name}}," "#{||:#{m%s:*%s*,#{window_name}},"
"#{m%s:%s%s%s,#{pane_title}}}", "#{m%s:*%s*,#{pane_title}}}",
suffix, star, s, star, suffix, star, s, star); suffix, s, suffix, s);
} else if (C) { } else if (C) {
xasprintf(&filter->string, xasprintf(&filter->string,
"#{C%s:%s}", "#{C%s:%s}",
suffix, s); suffix, s);
} else if (N) { } else if (N) {
xasprintf(&filter->string, xasprintf(&filter->string,
"#{m%s:%s%s%s,#{window_name}}", "#{m%s:*%s*,#{window_name}}",
suffix, star, s, star); suffix, s);
} else { } else {
xasprintf(&filter->string, xasprintf(&filter->string,
"#{m%s:%s%s%s,#{pane_title}}", "#{m%s:*%s*,#{pane_title}}",
suffix, star, s, star); suffix, s);
} }
new_args = args_create(); new_args = args_create();
if (args_has(args, 'Z')) if (args_has(args, 'Z'))
args_set(new_args, 'Z', NULL, 0); args_set(new_args, 'Z', NULL);
args_set(new_args, 'f', filter, 0); args_set(new_args, 'f', filter);
window_pane_set_mode(wp, NULL, &window_tree_mode, target, new_args); window_pane_set_mode(wp, NULL, &window_tree_mode, target, new_args);
args_free(new_args); args_free(new_args);

View File

@ -582,27 +582,27 @@ cmd_find_get_pane_with_window(struct cmd_find_state *fs, const char *pane)
/* Try special characters. */ /* Try special characters. */
if (strcmp(pane, "!") == 0) { if (strcmp(pane, "!") == 0) {
fs->wp = TAILQ_FIRST(&fs->w->last_panes); fs->wp = fs->w->last;
if (fs->wp == NULL) if (fs->wp == NULL)
return (-1); return (-1);
return (0); return (0);
} else if (strcmp(pane, "{up-of}") == 0) { } else if (strcmp(pane, "{up-of}") == 0) {
fs->wp = window_pane_find_up(fs->w->active); fs->wp = window_pane_find_up(fs->current->wp);
if (fs->wp == NULL) if (fs->wp == NULL)
return (-1); return (-1);
return (0); return (0);
} else if (strcmp(pane, "{down-of}") == 0) { } else if (strcmp(pane, "{down-of}") == 0) {
fs->wp = window_pane_find_down(fs->w->active); fs->wp = window_pane_find_down(fs->current->wp);
if (fs->wp == NULL) if (fs->wp == NULL)
return (-1); return (-1);
return (0); return (0);
} else if (strcmp(pane, "{left-of}") == 0) { } else if (strcmp(pane, "{left-of}") == 0) {
fs->wp = window_pane_find_left(fs->w->active); fs->wp = window_pane_find_left(fs->current->wp);
if (fs->wp == NULL) if (fs->wp == NULL)
return (-1); return (-1);
return (0); return (0);
} else if (strcmp(pane, "{right-of}") == 0) { } else if (strcmp(pane, "{right-of}") == 0) {
fs->wp = window_pane_find_right(fs->w->active); fs->wp = window_pane_find_right(fs->current->wp);
if (fs->wp == NULL) if (fs->wp == NULL)
return (-1); return (-1);
return (0); return (0);
@ -614,7 +614,7 @@ cmd_find_get_pane_with_window(struct cmd_find_state *fs, const char *pane)
n = strtonum(pane + 1, 1, INT_MAX, NULL); n = strtonum(pane + 1, 1, INT_MAX, NULL);
else else
n = 1; n = 1;
wp = fs->w->active; wp = fs->current->wp;
if (pane[0] == '+') if (pane[0] == '+')
fs->wp = window_pane_next_by_number(fs->w, wp, n); fs->wp = window_pane_next_by_number(fs->w, wp, n);
else else

View File

@ -157,7 +157,7 @@ cmd_if_shell_callback(struct job *job)
if (cmdlist == NULL) { if (cmdlist == NULL) {
if (cdata->item == NULL) { if (cdata->item == NULL) {
*error = toupper((u_char)*error); *error = toupper((u_char)*error);
status_message_set(c, -1, 1, 0, 0, "%s", error); status_message_set(c, -1, 1, 0, "%s", error);
} else } else
cmdq_error(cdata->item, "%s", error); cmdq_error(cdata->item, "%s", error);
free(error); free(error);

View File

@ -71,11 +71,10 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
struct window *src_w, *dst_w; struct window *src_w, *dst_w;
struct window_pane *src_wp, *dst_wp; struct window_pane *src_wp, *dst_wp;
char *cause = NULL; char *cause = NULL;
int size, dst_idx; int size, percentage, dst_idx;
int flags; int flags;
enum layout_type type; enum layout_type type;
struct layout_cell *lc; struct layout_cell *lc;
u_int curval = 0;
dst_s = target->s; dst_s = target->s;
dst_wl = target->wl; dst_wl = target->wl;
@ -98,30 +97,23 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(args, 'h')) if (args_has(args, 'h'))
type = LAYOUT_LEFTRIGHT; type = LAYOUT_LEFTRIGHT;
/* If the 'p' flag is dropped then this bit can be moved into 'l'. */
if (args_has(args, 'l') || args_has(args, 'p')) {
if (args_has(args, 'f')) {
if (type == LAYOUT_TOPBOTTOM)
curval = dst_w->sy;
else
curval = dst_w->sx;
} else {
if (type == LAYOUT_TOPBOTTOM)
curval = dst_wp->sy;
else
curval = dst_wp->sx;
}
}
size = -1; size = -1;
if (args_has(args, 'l')) { if (args_has(args, 'l')) {
size = args_percentage_and_expand(args, 'l', 0, INT_MAX, curval, if (type == LAYOUT_TOPBOTTOM) {
item, &cause); size = args_percentage(args, 'l', 0, INT_MAX,
dst_wp->sy, &cause);
} else {
size = args_percentage(args, 'l', 0, INT_MAX,
dst_wp->sx, &cause);
}
} else if (args_has(args, 'p')) { } else if (args_has(args, 'p')) {
size = args_strtonum_and_expand(args, 'l', 0, 100, item, percentage = args_strtonum(args, 'p', 0, 100, &cause);
&cause); if (cause == NULL) {
if (cause == NULL) if (type == LAYOUT_TOPBOTTOM)
size = curval * size / 100; size = (dst_wp->sy * percentage) / 100;
else
size = (dst_wp->sx * percentage) / 100;
}
} }
if (cause != NULL) { if (cause != NULL) {
cmdq_error(item, "size %s", cause); cmdq_error(item, "size %s", cause);
@ -149,13 +141,12 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
src_wp->window = dst_w; src_wp->window = dst_w;
options_set_parent(src_wp->options, dst_w->options); options_set_parent(src_wp->options, dst_w->options);
src_wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED); src_wp->flags |= PANE_STYLECHANGED;
if (flags & SPAWN_BEFORE) if (flags & SPAWN_BEFORE)
TAILQ_INSERT_BEFORE(dst_wp, src_wp, entry); TAILQ_INSERT_BEFORE(dst_wp, src_wp, entry);
else else
TAILQ_INSERT_AFTER(&dst_w->panes, dst_wp, src_wp, entry); TAILQ_INSERT_AFTER(&dst_w->panes, dst_wp, src_wp, entry);
layout_assign_pane(lc, src_wp, 0); layout_assign_pane(lc, src_wp, 0);
colour_palette_from_option(&src_wp->palette, src_wp->options);
recalculate_sizes(); recalculate_sizes();

View File

@ -41,8 +41,8 @@ const struct cmd_entry cmd_list_clients_entry = {
.name = "list-clients", .name = "list-clients",
.alias = "lsc", .alias = "lsc",
.args = { "F:f:t:", 0, 0, NULL }, .args = { "F:t:", 0, 0, NULL },
.usage = "[-F format] [-f filter] " CMD_TARGET_SESSION_USAGE, .usage = "[-F format] " CMD_TARGET_SESSION_USAGE,
.target = { 't', CMD_FIND_SESSION, 0 }, .target = { 't', CMD_FIND_SESSION, 0 },
@ -58,10 +58,9 @@ cmd_list_clients_exec(struct cmd *self, struct cmdq_item *item)
struct client *c; struct client *c;
struct session *s; struct session *s;
struct format_tree *ft; struct format_tree *ft;
const char *template, *filter; const char *template;
u_int idx; u_int idx;
char *line, *expanded; char *line;
int flag;
if (args_has(args, 't')) if (args_has(args, 't'))
s = target->s; s = target->s;
@ -70,7 +69,6 @@ cmd_list_clients_exec(struct cmd *self, struct cmdq_item *item)
if ((template = args_get(args, 'F')) == NULL) if ((template = args_get(args, 'F')) == NULL)
template = LIST_CLIENTS_TEMPLATE; template = LIST_CLIENTS_TEMPLATE;
filter = args_get(args, 'f');
idx = 0; idx = 0;
TAILQ_FOREACH(c, &clients, entry) { TAILQ_FOREACH(c, &clients, entry) {
@ -81,17 +79,9 @@ cmd_list_clients_exec(struct cmd *self, struct cmdq_item *item)
format_add(ft, "line", "%u", idx); format_add(ft, "line", "%u", idx);
format_defaults(ft, c, NULL, NULL, NULL); format_defaults(ft, c, NULL, NULL, NULL);
if (filter != NULL) { line = format_expand(ft, template);
expanded = format_expand(ft, filter); cmdq_print(item, "%s", line);
flag = format_true(expanded); free(line);
free(expanded);
} else
flag = 1;
if (flag) {
line = format_expand(ft, template);
cmdq_print(item, "%s", line);
free(line);
}
format_free(ft); format_free(ft);

View File

@ -91,7 +91,7 @@ cmd_list_keys_print_notes(struct cmdq_item *item, struct args *args,
struct key_binding *bd; struct key_binding *bd;
const char *key; const char *key;
char *tmp, *note; char *tmp, *note;
int found = 0; int found = 0;
table = key_bindings_get_table(tablename, 0); table = key_bindings_get_table(tablename, 0);
if (table == NULL) if (table == NULL)
@ -114,8 +114,8 @@ cmd_list_keys_print_notes(struct cmdq_item *item, struct args *args,
note = xstrdup(bd->note); note = xstrdup(bd->note);
tmp = utf8_padcstr(key, keywidth + 1); tmp = utf8_padcstr(key, keywidth + 1);
if (args_has(args, '1') && tc != NULL) { if (args_has(args, '1') && tc != NULL) {
status_message_set(tc, -1, 1, 0, 0, "%s%s%s", prefix, status_message_set(tc, -1, 1, 0, "%s%s%s", prefix, tmp,
tmp, note); note);
} else } else
cmdq_print(item, "%s%s%s", prefix, tmp, note); cmdq_print(item, "%s%s%s", prefix, tmp, note);
free(tmp); free(tmp);
@ -148,7 +148,6 @@ static enum cmd_retval
cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item) cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = cmd_get_args(self);
struct client *tc = cmdq_get_target_client(item);
struct key_table *table; struct key_table *table;
struct key_binding *bd; struct key_binding *bd;
const char *tablename, *r, *keystr; const char *tablename, *r, *keystr;
@ -297,15 +296,9 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
strlcat(tmp, cp, tmpsize); strlcat(tmp, cp, tmpsize);
free(cp); free(cp);
if (args_has(args, '1') && tc != NULL) { cmdq_print(item, "bind-key %s", tmp);
status_message_set(tc, -1, 1, 0, 0,
"bind-key %s", tmp);
} else
cmdq_print(item, "bind-key %s", tmp);
free(key);
if (args_has(args, '1')) free(key);
break;
bd = key_bindings_next(table, bd); bd = key_bindings_next(table, bd);
} }
table = key_bindings_next_table(table); table = key_bindings_next_table(table);
@ -321,31 +314,6 @@ out:
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
static void
cmd_list_single_command(const struct cmd_entry *entry, struct format_tree *ft,
const char *template, struct cmdq_item *item)
{
const char *s;
char *line;
format_add(ft, "command_list_name", "%s", entry->name);
if (entry->alias != NULL)
s = entry->alias;
else
s = "";
format_add(ft, "command_list_alias", "%s", s);
if (entry->usage != NULL)
s = entry->usage;
else
s = "";
format_add(ft, "command_list_usage", "%s", s);
line = format_expand(ft, template);
if (*line != '\0')
cmdq_print(item, "%s", line);
free(line);
}
static enum cmd_retval static enum cmd_retval
cmd_list_keys_commands(struct cmd *self, struct cmdq_item *item) cmd_list_keys_commands(struct cmd *self, struct cmdq_item *item)
{ {
@ -353,8 +321,8 @@ cmd_list_keys_commands(struct cmd *self, struct cmdq_item *item)
const struct cmd_entry **entryp; const struct cmd_entry **entryp;
const struct cmd_entry *entry; const struct cmd_entry *entry;
struct format_tree *ft; struct format_tree *ft;
const char *template, *command; const char *template, *s, *command;
char *cause; char *line;
if ((template = args_get(args, 'F')) == NULL) { if ((template = args_get(args, 'F')) == NULL) {
template = "#{command_list_name}" template = "#{command_list_name}"
@ -366,19 +334,30 @@ cmd_list_keys_commands(struct cmd *self, struct cmdq_item *item)
format_defaults(ft, NULL, NULL, NULL, NULL); format_defaults(ft, NULL, NULL, NULL, NULL);
command = args_string(args, 0); command = args_string(args, 0);
if (command == NULL) { for (entryp = cmd_table; *entryp != NULL; entryp++) {
for (entryp = cmd_table; *entryp != NULL; entryp++) entry = *entryp;
cmd_list_single_command(*entryp, ft, template, item); if (command != NULL &&
} else { (strcmp(entry->name, command) != 0 &&
entry = cmd_find(command, &cause); (entry->alias == NULL ||
if (entry != NULL) strcmp(entry->alias, command) != 0)))
cmd_list_single_command(entry, ft, template, item); continue;
else {
cmdq_error(item, "%s", cause); format_add(ft, "command_list_name", "%s", entry->name);
free(cause); if (entry->alias != NULL)
format_free(ft); s = entry->alias;
return (CMD_RETURN_ERROR); else
} s = "";
format_add(ft, "command_list_alias", "%s", s);
if (entry->usage != NULL)
s = entry->usage;
else
s = "";
format_add(ft, "command_list_usage", "%s", s);
line = format_expand(ft, template);
if (*line != '\0')
cmdq_print(item, "%s", line);
free(line);
} }
format_free(ft); format_free(ft);

View File

@ -77,7 +77,7 @@ cmd_load_buffer_done(__unused struct client *c, const char *path, int error,
} else if (tc != NULL && } else if (tc != NULL &&
tc->session != NULL && tc->session != NULL &&
(~tc->flags & CLIENT_DEAD)) (~tc->flags & CLIENT_DEAD))
tty_set_selection(&tc->tty, "", copy, bsize); tty_set_selection(&tc->tty, copy, bsize);
if (tc != NULL) if (tc != NULL)
server_client_unref(tc); server_client_unref(tc);
} }

View File

@ -43,7 +43,7 @@ const struct cmd_entry cmd_new_session_entry = {
.usage = "[-AdDEPX] [-c start-directory] [-e environment] [-F format] " .usage = "[-AdDEPX] [-c start-directory] [-e environment] [-F format] "
"[-f flags] [-n window-name] [-s session-name] " "[-f flags] [-n window-name] [-s session-name] "
CMD_TARGET_SESSION_USAGE " [-x width] [-y height] " CMD_TARGET_SESSION_USAGE " [-x width] [-y height] "
"[shell-command [argument ...]]", "[shell-command]",
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL }, .target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
@ -333,6 +333,13 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
server_client_set_key_table(c, NULL); server_client_set_key_table(c, NULL);
} }
/*
* If there are still configuration file errors to display, put the new
* session's current window into more mode and display them now.
*/
if (cfg_finished)
cfg_show_causes(s);
/* Print if requested. */ /* Print if requested. */
if (args_has(args, 'P')) { if (args_has(args, 'P')) {
if ((template = args_get(args, 'F')) == NULL) if ((template = args_get(args, 'F')) == NULL)
@ -350,9 +357,6 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
cmd_find_from_session(&fs, s, 0); cmd_find_from_session(&fs, s, 0);
cmdq_insert_hook(s, item, &fs, "after-new-session"); cmdq_insert_hook(s, item, &fs, "after-new-session");
if (cfg_finished)
cfg_show_causes(s);
if (sc.argv != NULL) if (sc.argv != NULL)
cmd_free_argv(sc.argc, sc.argv); cmd_free_argv(sc.argc, sc.argv);
free(cwd); free(cwd);

View File

@ -40,8 +40,7 @@ const struct cmd_entry cmd_new_window_entry = {
.args = { "abc:de:F:kn:PSt:", 0, -1, NULL }, .args = { "abc:de:F:kn:PSt:", 0, -1, NULL },
.usage = "[-abdkPS] [-c start-directory] [-e environment] [-F format] " .usage = "[-abdkPS] [-c start-directory] [-e environment] [-F format] "
"[-n window-name] " CMD_TARGET_WINDOW_USAGE "[-n window-name] " CMD_TARGET_WINDOW_USAGE " [shell-command]",
" [shell-command [argument ...]]",
.target = { 't', CMD_FIND_WINDOW, CMD_FIND_WINDOW_INDEX }, .target = { 't', CMD_FIND_WINDOW, CMD_FIND_WINDOW_INDEX },
@ -61,7 +60,7 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
struct session *s = target->s; struct session *s = target->s;
struct winlink *wl = target->wl, *new_wl = NULL; struct winlink *wl = target->wl, *new_wl = NULL;
int idx = target->idx, before; int idx = target->idx, before;
char *cause = NULL, *cp, *expanded; char *cause = NULL, *cp;
const char *template, *name; const char *template, *name;
struct cmd_find_state fs; struct cmd_find_state fs;
struct args_value *av; struct args_value *av;
@ -72,19 +71,16 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
*/ */
name = args_get(args, 'n'); name = args_get(args, 'n');
if (args_has(args, 'S') && name != NULL && target->idx == -1) { if (args_has(args, 'S') && name != NULL && target->idx == -1) {
expanded = format_single(item, name, c, s, NULL, NULL);
RB_FOREACH(wl, winlinks, &s->windows) { RB_FOREACH(wl, winlinks, &s->windows) {
if (strcmp(wl->window->name, expanded) != 0) if (strcmp(wl->window->name, name) != 0)
continue; continue;
if (new_wl == NULL) { if (new_wl == NULL) {
new_wl = wl; new_wl = wl;
continue; continue;
} }
cmdq_error(item, "multiple windows named %s", name); cmdq_error(item, "multiple windows named %s", name);
free(expanded);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
free(expanded);
if (new_wl != NULL) { if (new_wl != NULL) {
if (args_has(args, 'd')) if (args_has(args, 'd'))
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);

View File

@ -223,16 +223,9 @@ assignment : EQUALS
{ {
struct cmd_parse_state *ps = &parse_state; struct cmd_parse_state *ps = &parse_state;
int flags = ps->input->flags; int flags = ps->input->flags;
int flag = 1;
struct cmd_parse_scope *scope;
if (ps->scope != NULL) { if ((~flags & CMD_PARSE_PARSEONLY) &&
flag = ps->scope->flag; (ps->scope == NULL || ps->scope->flag))
TAILQ_FOREACH(scope, &ps->stack, entry)
flag = flag && scope->flag;
}
if ((~flags & CMD_PARSE_PARSEONLY) && flag)
environ_put(global_environ, $1, 0); environ_put(global_environ, $1, 0);
free($1); free($1);
} }
@ -241,16 +234,9 @@ hidden_assignment : HIDDEN EQUALS
{ {
struct cmd_parse_state *ps = &parse_state; struct cmd_parse_state *ps = &parse_state;
int flags = ps->input->flags; int flags = ps->input->flags;
int flag = 1;
struct cmd_parse_scope *scope;
if (ps->scope != NULL) { if ((~flags & CMD_PARSE_PARSEONLY) &&
flag = ps->scope->flag; (ps->scope == NULL || ps->scope->flag))
TAILQ_FOREACH(scope, &ps->stack, entry)
flag = flag && scope->flag;
}
if ((~flags & CMD_PARSE_PARSEONLY) && flag)
environ_put(global_environ, $2, ENVIRON_HIDDEN); environ_put(global_environ, $2, ENVIRON_HIDDEN);
free($2); free($2);
} }
@ -1100,8 +1086,7 @@ cmd_parse_from_arguments(struct args_value *values, u_int count,
arg->type = CMD_PARSE_STRING; arg->type = CMD_PARSE_STRING;
arg->string = copy; arg->string = copy;
TAILQ_INSERT_TAIL(&cmd->arguments, arg, entry); TAILQ_INSERT_TAIL(&cmd->arguments, arg, entry);
} else }
free(copy);
} else if (values[i].type == ARGS_COMMANDS) { } else if (values[i].type == ARGS_COMMANDS) {
arg = xcalloc(1, sizeof *arg); arg = xcalloc(1, sizeof *arg);
arg->type = CMD_PARSE_PARSED_COMMANDS; arg->type = CMD_PARSE_PARSED_COMMANDS;
@ -1287,16 +1272,6 @@ yylex(void)
continue; continue;
} }
if (ch == '\r') {
/*
* Treat \r\n as \n.
*/
ch = yylex_getc();
if (ch != '\n') {
yylex_ungetc(ch);
ch = '\r';
}
}
if (ch == '\n') { if (ch == '\n') {
/* /*
* End of line. Update the line number. * End of line. Update the line number.
@ -1627,7 +1602,6 @@ yylex_token_tilde(char **buf, size_t *len)
static char * static char *
yylex_token(int ch) yylex_token(int ch)
{ {
struct cmd_parse_state *ps = &parse_state;
char *buf; char *buf;
size_t len; size_t len;
enum { START, enum { START,
@ -1640,34 +1614,13 @@ yylex_token(int ch)
for (;;) { for (;;) {
/* EOF or \n are always the end of the token. */ /* EOF or \n are always the end of the token. */
if (ch == EOF) { if (ch == EOF || (state == NONE && ch == '\n'))
log_debug("%s: end at EOF", __func__);
break; break;
}
if (state == NONE && ch == '\r') {
ch = yylex_getc();
if (ch != '\n') {
yylex_ungetc(ch);
ch = '\r';
}
}
if (ch == '\n') {
if (state == NONE) {
log_debug("%s: end at EOL", __func__);
break;
}
ps->input->line++;
}
/* Whitespace or ; or } ends a token unless inside quotes. */ /* Whitespace or ; or } ends a token unless inside quotes. */
if (state == NONE && (ch == ' ' || ch == '\t')) { if ((ch == ' ' || ch == '\t' || ch == ';' || ch == '}') &&
log_debug("%s: end at WS", __func__); state == NONE)
break; break;
}
if (state == NONE && (ch == ';' || ch == '}')) {
log_debug("%s: end at %c", __func__, ch);
break;
}
/* /*
* Spaces and comments inside quotes after \n are removed but * Spaces and comments inside quotes after \n are removed but

View File

@ -54,11 +54,6 @@ cmd_paste_buffer_exec(struct cmd *self, struct cmdq_item *item)
size_t seplen, bufsize; size_t seplen, bufsize;
int bracket = args_has(args, 'p'); int bracket = args_has(args, 'p');
if (window_pane_exited(wp)) {
cmdq_error(item, "target pane has exited");
return (CMD_RETURN_ERROR);
}
bufname = NULL; bufname = NULL;
if (args_has(args, 'b')) if (args_has(args, 'b'))
bufname = args_get(args, 'b'); bufname = args_get(args, 'b');

View File

@ -68,7 +68,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
sigset_t set, oldset; sigset_t set, oldset;
/* Do nothing if pane is dead. */ /* Do nothing if pane is dead. */
if (window_pane_exited(wp)) { if (wp->fd == -1 || (wp->flags & PANE_EXITED)) {
cmdq_error(item, "target pane has exited"); cmdq_error(item, "target pane has exited");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }

View File

@ -236,10 +236,8 @@ cmdq_link_state(struct cmdq_state *state)
/* Make a copy of a state. */ /* Make a copy of a state. */
struct cmdq_state * struct cmdq_state *
cmdq_copy_state(struct cmdq_state *state, struct cmd_find_state *current) cmdq_copy_state(struct cmdq_state *state)
{ {
if (current != NULL)
return (cmdq_new_state(current, &state->event, state->flags));
return (cmdq_new_state(&state->current, &state->event, state->flags)); return (cmdq_new_state(&state->current, &state->event, state->flags));
} }
@ -664,18 +662,9 @@ cmdq_fire_command(struct cmdq_item *item)
out: out:
item->client = saved; item->client = saved;
if (retval == CMD_RETURN_ERROR) { if (retval == CMD_RETURN_ERROR)
fsp = NULL;
if (cmd_find_valid_state(&item->target))
fsp = &item->target;
else if (cmd_find_valid_state(&item->state->current))
fsp = &item->state->current;
else if (cmd_find_from_client(&fs, item->client, 0) == 0)
fsp = &fs;
cmdq_insert_hook(fsp != NULL ? fsp->s : NULL, item, fsp,
"command-error");
cmdq_guard(item, "error", flags); cmdq_guard(item, "error", flags);
} else else
cmdq_guard(item, "end", flags); cmdq_guard(item, "end", flags);
return (retval); return (retval);
} }
@ -814,10 +803,10 @@ cmdq_running(struct client *c)
struct cmdq_list *queue = cmdq_get(c); struct cmdq_list *queue = cmdq_get(c);
if (queue->item == NULL) if (queue->item == NULL)
return (NULL); return (NULL);
if (queue->item->flags & CMDQ_WAITING) if (queue->item->flags & CMDQ_WAITING)
return (NULL); return (NULL);
return (queue->item); return (queue->item);
} }
/* Print a guard line. */ /* Print a guard line. */
@ -832,30 +821,45 @@ cmdq_guard(struct cmdq_item *item, const char *guard, int flags)
control_write(c, "%%%s %ld %u %d", guard, t, number, flags); control_write(c, "%%%s %ld %u %d", guard, t, number, flags);
} }
/* Show message from command. */
void
cmdq_print_data(struct cmdq_item *item, struct evbuffer *evb)
{
server_client_print(item->client, 1, evb);
}
/* Show message from command. */ /* Show message from command. */
void void
cmdq_print(struct cmdq_item *item, const char *fmt, ...) cmdq_print(struct cmdq_item *item, const char *fmt, ...)
{ {
va_list ap; struct client *c = item->client;
struct evbuffer *evb; struct window_pane *wp;
struct window_mode_entry *wme;
evb = evbuffer_new(); va_list ap;
if (evb == NULL) char *tmp, *msg;
fatalx("out of memory");
va_start(ap, fmt); va_start(ap, fmt);
evbuffer_add_vprintf(evb, fmt, ap); xvasprintf(&msg, fmt, ap);
va_end(ap); va_end(ap);
cmdq_print_data(item, evb); log_debug("%s: %s", __func__, msg);
evbuffer_free(evb);
if (c == NULL)
/* nothing */;
else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {
if (~c->flags & CLIENT_UTF8) {
tmp = msg;
msg = utf8_sanitize(tmp);
free(tmp);
}
if (c->flags & CLIENT_CONTROL)
control_write(c, "%s", msg);
else
file_print(c, "%s\n", msg);
} else {
wp = server_client_get_pane(c);
wme = TAILQ_FIRST(&wp->modes);
if (wme == NULL || wme->mode != &window_view_mode) {
window_pane_set_mode(wp, NULL, &window_view_mode, NULL,
NULL);
}
window_copy_add(wp, 0, "%s", msg);
}
free(msg);
} }
/* Show error from command. */ /* Show error from command. */
@ -892,7 +896,7 @@ cmdq_error(struct cmdq_item *item, const char *fmt, ...)
c->retval = 1; c->retval = 1;
} else { } else {
*msg = toupper((u_char) *msg); *msg = toupper((u_char) *msg);
status_message_set(c, -1, 1, 0, 0, "%s", msg); status_message_set(c, -1, 1, 0, "%s", msg);
} }
free(msg); free(msg);

View File

@ -34,10 +34,9 @@ const struct cmd_entry cmd_refresh_client_entry = {
.name = "refresh-client", .name = "refresh-client",
.alias = "refresh", .alias = "refresh",
.args = { "A:B:cC:Df:r:F:l::LRSt:U", 0, 1, NULL }, .args = { "A:B:cC:Df:F:l::LRSt:U", 0, 1, NULL },
.usage = "[-cDlLRSU] [-A pane:state] [-B name:what:format] " .usage = "[-cDlLRSU] [-A pane:state] [-B name:what:format] "
"[-C XxY] [-f flags] [-r pane:report] " CMD_TARGET_CLIENT_USAGE "[-C XxY] [-f flags] " CMD_TARGET_CLIENT_USAGE " [adjustment]",
" [adjustment]",
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG, .flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG,
.exec = cmd_refresh_client_exec .exec = cmd_refresh_client_exec
@ -194,34 +193,6 @@ cmd_refresh_client_clipboard(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
static void
cmd_refresh_report(struct tty *tty, const char *value)
{
struct window_pane *wp;
u_int pane;
size_t size = 0;
char *copy, *split;
if (*value != '%')
return;
copy = xstrdup(value);
if ((split = strchr(copy, ':')) == NULL)
goto out;
*split++ = '\0';
if (sscanf(copy, "%%%u", &pane) != 1)
goto out;
wp = window_pane_find_by_id(pane);
if (wp == NULL)
goto out;
tty_keys_colours(tty, split, strlen(split), &size, &wp->control_fg,
&wp->control_bg);
out:
free(copy);
}
static enum cmd_retval static enum cmd_retval
cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item) cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
{ {
@ -291,8 +262,6 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
server_client_set_flags(tc, args_get(args, 'F')); server_client_set_flags(tc, args_get(args, 'F'));
if (args_has(args, 'f')) if (args_has(args, 'f'))
server_client_set_flags(tc, args_get(args, 'f')); server_client_set_flags(tc, args_get(args, 'f'));
if (args_has(args, 'r'))
cmd_refresh_report(tty, args_get(args, 'r'));
if (args_has(args, 'A')) { if (args_has(args, 'A')) {
if (~tc->flags & CLIENT_CONTROL) if (~tc->flags & CLIENT_CONTROL)

View File

@ -87,7 +87,7 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(args, 'Z')) { if (args_has(args, 'Z')) {
if (w->flags & WINDOW_ZOOMED) if (w->flags & WINDOW_ZOOMED)
window_unzoom(w, 1); window_unzoom(w);
else else
window_zoom(wp); window_zoom(wp);
server_redraw_window(w); server_redraw_window(w);

View File

@ -53,7 +53,8 @@ cmd_resize_window_exec(struct cmd *self, struct cmdq_item *item)
struct session *s = target->s; struct session *s = target->s;
const char *errstr; const char *errstr;
char *cause; char *cause;
u_int adjust, sx, sy, xpixel = 0, ypixel = 0; u_int adjust, sx, sy;
int xpixel = -1, ypixel = -1;
if (args_count(args) == 0) if (args_count(args) == 0)
adjust = 1; adjust = 1;

View File

@ -36,7 +36,7 @@ const struct cmd_entry cmd_respawn_pane_entry = {
.args = { "c:e:kt:", 0, -1, NULL }, .args = { "c:e:kt:", 0, -1, NULL },
.usage = "[-k] [-c start-directory] [-e environment] " .usage = "[-k] [-c start-directory] [-e environment] "
CMD_TARGET_PANE_USAGE " [shell-command [argument ...]]", CMD_TARGET_PANE_USAGE " [shell-command]",
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },

View File

@ -36,7 +36,7 @@ const struct cmd_entry cmd_respawn_window_entry = {
.args = { "c:e:kt:", 0, -1, NULL }, .args = { "c:e:kt:", 0, -1, NULL },
.usage = "[-k] [-c start-directory] [-e environment] " .usage = "[-k] [-c start-directory] [-e environment] "
CMD_TARGET_WINDOW_USAGE " [shell-command [argument ...]]", CMD_TARGET_WINDOW_USAGE " [shell-command]",
.target = { 't', CMD_FIND_WINDOW, 0 }, .target = { 't', CMD_FIND_WINDOW, 0 },

View File

@ -44,9 +44,8 @@ const struct cmd_entry cmd_run_shell_entry = {
.name = "run-shell", .name = "run-shell",
.alias = "run", .alias = "run",
.args = { "bd:Ct:Es:c:", 0, 1, cmd_run_shell_args_parse }, .args = { "bd:Ct:", 0, 1, cmd_run_shell_args_parse },
.usage = "[-bCE] [-c start-directory] [-d delay] " CMD_TARGET_PANE_USAGE .usage = "[-bC] [-d delay] " CMD_TARGET_PANE_USAGE " [shell-command]",
" [shell-command]",
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL }, .target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
@ -85,18 +84,12 @@ cmd_run_shell_print(struct job *job, const char *msg)
if (cdata->wp_id != -1) if (cdata->wp_id != -1)
wp = window_pane_find_by_id(cdata->wp_id); wp = window_pane_find_by_id(cdata->wp_id);
if (wp == NULL) { if (wp == NULL && cdata->item != NULL && cdata->client != NULL)
if (cdata->item != NULL) { wp = server_client_get_pane(cdata->client);
cmdq_print(cdata->item, "%s", msg); if (wp == NULL && cmd_find_from_nothing(&fs, 0) == 0)
return; wp = fs.wp;
} if (wp == NULL)
if (cdata->item != NULL && cdata->client != NULL) return;
wp = server_client_get_pane(cdata->client);
if (wp == NULL && cmd_find_from_nothing(&fs, 0) == 0)
wp = fs.wp;
if (wp == NULL)
return;
}
wme = TAILQ_FIRST(&wp->modes); wme = TAILQ_FIRST(&wp->modes);
if (wme == NULL || wme->mode != &window_view_mode) if (wme == NULL || wme->mode != &window_view_mode)
@ -110,7 +103,6 @@ cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
struct args *args = cmd_get_args(self); struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item); struct cmd_find_state *target = cmdq_get_target(item);
struct cmd_run_shell_data *cdata; struct cmd_run_shell_data *cdata;
struct client *c = cmdq_get_client(item);
struct client *tc = cmdq_get_target_client(item); struct client *tc = cmdq_get_target_client(item);
struct session *s = target->s; struct session *s = target->s;
struct window_pane *wp = target->wp; struct window_pane *wp = target->wp;
@ -145,7 +137,7 @@ cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
cdata->wp_id = -1; cdata->wp_id = -1;
if (wait) { if (wait) {
cdata->client = c; cdata->client = cmdq_get_client(item);
cdata->item = item; cdata->item = item;
} else { } else {
cdata->client = tc; cdata->client = tc;
@ -153,13 +145,8 @@ cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
} }
if (cdata->client != NULL) if (cdata->client != NULL)
cdata->client->references++; cdata->client->references++;
if (args_has(args, 'c'))
cdata->cwd = xstrdup(args_get(args, 'c'));
else
cdata->cwd = xstrdup(server_client_get_cwd(c, s));
if (args_has(args, 'E')) cdata->cwd = xstrdup(server_client_get_cwd(cmdq_get_client(item), s));
cdata->flags |= JOB_SHOWSTDERR;
cdata->s = s; cdata->s = s;
if (s != NULL) if (s != NULL)
@ -207,7 +194,7 @@ cmd_run_shell_timer(__unused int fd, __unused short events, void* arg)
if (cmdlist == NULL) { if (cmdlist == NULL) {
if (cdata->item == NULL) { if (cdata->item == NULL) {
*error = toupper((u_char)*error); *error = toupper((u_char)*error);
status_message_set(c, -1, 1, 0, 0, "%s", error); status_message_set(c, -1, 1, 0, "%s", error);
} else } else
cmdq_error(cdata->item, "%s", error); cmdq_error(cdata->item, "%s", error);
free(error); free(error);

View File

@ -78,8 +78,7 @@ cmd_save_buffer_exec(struct cmd *self, struct cmdq_item *item)
int flags; int flags;
const char *bufname = args_get(args, 'b'), *bufdata; const char *bufname = args_get(args, 'b'), *bufdata;
size_t bufsize; size_t bufsize;
char *path; char *path, *tmp;
struct evbuffer *evb;
if (bufname == NULL) { if (bufname == NULL) {
if ((pb = paste_get_top(NULL)) == NULL) { if ((pb = paste_get_top(NULL)) == NULL) {
@ -97,12 +96,10 @@ cmd_save_buffer_exec(struct cmd *self, struct cmdq_item *item)
if (cmd_get_entry(self) == &cmd_show_buffer_entry) { if (cmd_get_entry(self) == &cmd_show_buffer_entry) {
if (c->session != NULL || (c->flags & CLIENT_CONTROL)) { if (c->session != NULL || (c->flags & CLIENT_CONTROL)) {
evb = evbuffer_new(); utf8_stravisx(&tmp, bufdata, bufsize,
if (evb == NULL) VIS_OCTAL|VIS_CSTYLE|VIS_TAB);
fatalx("out of memory"); cmdq_print(item, "%s", tmp);
evbuffer_add(evb, bufdata, bufsize); free(tmp);
cmdq_print_data(item, evb);
evbuffer_free(evb);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
path = xstrdup("-"); path = xstrdup("-");

View File

@ -98,11 +98,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
struct options_entry *o; struct options_entry *o;
if (entry == &cmd_last_pane_entry || args_has(args, 'l')) { if (entry == &cmd_last_pane_entry || args_has(args, 'l')) {
/* lastwp = w->last;
* Check for no last pane found in case the other pane was
* spawned without being visited (for example split-window -d).
*/
lastwp = TAILQ_FIRST(&w->last_panes);
if (lastwp == NULL && window_count_panes(w) == 2) { if (lastwp == NULL && window_count_panes(w) == 2) {
lastwp = TAILQ_PREV(w->active, window_panes, entry); lastwp = TAILQ_PREV(w->active, window_panes, entry);
if (lastwp == NULL) if (lastwp == NULL)
@ -149,14 +145,12 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
markedwp = marked_pane.wp; markedwp = marked_pane.wp;
if (lastwp != NULL) { if (lastwp != NULL) {
lastwp->flags |= (PANE_REDRAW|PANE_STYLECHANGED| lastwp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
PANE_THEMECHANGED);
server_redraw_window_borders(lastwp->window); server_redraw_window_borders(lastwp->window);
server_status_window(lastwp->window); server_status_window(lastwp->window);
} }
if (markedwp != NULL) { if (markedwp != NULL) {
markedwp->flags |= (PANE_REDRAW|PANE_STYLECHANGED| markedwp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
PANE_THEMECHANGED);
server_redraw_window_borders(markedwp->window); server_redraw_window_borders(markedwp->window);
server_status_window(markedwp->window); server_status_window(markedwp->window);
} }
@ -171,7 +165,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
options_set_string(oo, "window-active-style", 0, "%s", style); options_set_string(oo, "window-active-style", 0, "%s", style);
wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED|PANE_THEMECHANGED); wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
} }
if (args_has(args, 'g')) { if (args_has(args, 'g')) {
cmdq_print(item, "%s", options_get_string(oo, "window-style")); cmdq_print(item, "%s", options_get_string(oo, "window-style"));

View File

@ -33,13 +33,13 @@ const struct cmd_entry cmd_send_keys_entry = {
.name = "send-keys", .name = "send-keys",
.alias = "send", .alias = "send",
.args = { "c:FHKlMN:Rt:X", 0, -1, NULL }, .args = { "FHlMN:Rt:X", 0, -1, NULL },
.usage = "[-FHKlMRX] [-c target-client] [-N repeat-count] " .usage = "[-FHlMRX] [-N repeat-count] " CMD_TARGET_PANE_USAGE
CMD_TARGET_PANE_USAGE " [key ...]", " key ...",
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK|CMD_CLIENT_CFLAG|CMD_CLIENT_CANFAIL, .flags = CMD_AFTERHOOK,
.exec = cmd_send_keys_exec .exec = cmd_send_keys_exec
}; };
@ -58,7 +58,7 @@ const struct cmd_entry cmd_send_prefix_entry = {
static struct cmdq_item * static struct cmdq_item *
cmd_send_keys_inject_key(struct cmdq_item *item, struct cmdq_item *after, cmd_send_keys_inject_key(struct cmdq_item *item, struct cmdq_item *after,
struct args *args, key_code key) key_code key)
{ {
struct cmd_find_state *target = cmdq_get_target(item); struct cmd_find_state *target = cmdq_get_target(item);
struct client *tc = cmdq_get_target_client(item); struct client *tc = cmdq_get_target_client(item);
@ -66,22 +66,8 @@ cmd_send_keys_inject_key(struct cmdq_item *item, struct cmdq_item *after,
struct winlink *wl = target->wl; struct winlink *wl = target->wl;
struct window_pane *wp = target->wp; struct window_pane *wp = target->wp;
struct window_mode_entry *wme; struct window_mode_entry *wme;
struct key_table *table = NULL; struct key_table *table;
struct key_binding *bd; struct key_binding *bd;
struct key_event *event;
if (args_has(args, 'K')) {
if (tc == NULL)
return (item);
event = xcalloc(1, sizeof *event);
event->key = key|KEYC_SENT;
memset(&event->m, 0, sizeof event->m);
if (server_client_handle_key(tc, event) == 0) {
free(event->buf);
free(event);
}
return (item);
}
wme = TAILQ_FIRST(&wp->modes); wme = TAILQ_FIRST(&wp->modes);
if (wme == NULL || wme->mode->key_table == NULL) { if (wme == NULL || wme->mode->key_table == NULL) {
@ -116,16 +102,14 @@ cmd_send_keys_inject_string(struct cmdq_item *item, struct cmdq_item *after,
n = strtol(s, &endptr, 16); n = strtol(s, &endptr, 16);
if (*s =='\0' || n < 0 || n > 0xff || *endptr != '\0') if (*s =='\0' || n < 0 || n > 0xff || *endptr != '\0')
return (item); return (item);
return (cmd_send_keys_inject_key(item, after, args, return (cmd_send_keys_inject_key(item, after, KEYC_LITERAL|n));
KEYC_LITERAL|n));
} }
literal = args_has(args, 'l'); literal = args_has(args, 'l');
if (!literal) { if (!literal) {
key = key_string_lookup_string(s); key = key_string_lookup_string(s);
if (key != KEYC_NONE && key != KEYC_UNKNOWN) { if (key != KEYC_NONE && key != KEYC_UNKNOWN) {
after = cmd_send_keys_inject_key(item, after, args, after = cmd_send_keys_inject_key(item, after, key);
key);
if (after != NULL) if (after != NULL)
return (after); return (after);
} }
@ -141,8 +125,7 @@ cmd_send_keys_inject_string(struct cmdq_item *item, struct cmdq_item *after,
continue; continue;
key = uc; key = uc;
} }
after = cmd_send_keys_inject_key(item, after, args, after = cmd_send_keys_inject_key(item, after, key);
key);
} }
free(ud); free(ud);
} }
@ -168,8 +151,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
char *cause = NULL; char *cause = NULL;
if (args_has(args, 'N')) { if (args_has(args, 'N')) {
np = args_strtonum_and_expand(args, 'N', 1, UINT_MAX, item, np = args_strtonum(args, 'N', 1, UINT_MAX, &cause);
&cause);
if (cause != NULL) { if (cause != NULL) {
cmdq_error(item, "repeat count %s", cause); cmdq_error(item, "repeat count %s", cause);
free(cause); free(cause);
@ -210,21 +192,21 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
key = options_get_number(s->options, "prefix2"); key = options_get_number(s->options, "prefix2");
else else
key = options_get_number(s->options, "prefix"); key = options_get_number(s->options, "prefix");
cmd_send_keys_inject_key(item, item, args, key); cmd_send_keys_inject_key(item, item, key);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (args_has(args, 'R')) { if (args_has(args, 'R')) {
colour_palette_clear(&wp->palette); colour_palette_clear(&wp->palette);
input_reset(wp->ictx, 1); input_reset(wp->ictx, 1);
wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED|PANE_REDRAW); wp->flags |= (PANE_STYLECHANGED|PANE_REDRAW);
} }
if (count == 0) { if (count == 0) {
if (args_has(args, 'N') || args_has(args, 'R')) if (args_has(args, 'N') || args_has(args, 'R'))
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
for (; np != 0; np--) for (; np != 0; np--)
cmd_send_keys_inject_key(item, NULL, args, event->key); cmd_send_keys_inject_key(item, NULL, event->key);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@ -35,7 +35,7 @@ const struct cmd_entry cmd_set_buffer_entry = {
.args = { "ab:t:n:w", 0, 1, NULL }, .args = { "ab:t:n:w", 0, 1, NULL },
.usage = "[-aw] " CMD_BUFFER_USAGE " [-n new-buffer-name] " .usage = "[-aw] " CMD_BUFFER_USAGE " [-n new-buffer-name] "
CMD_TARGET_CLIENT_USAGE " [data]", CMD_TARGET_CLIENT_USAGE " data",
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG|CMD_CLIENT_CANFAIL, .flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG|CMD_CLIENT_CANFAIL,
.exec = cmd_set_buffer_exec .exec = cmd_set_buffer_exec
@ -69,13 +69,8 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
pb = paste_get_name(bufname); pb = paste_get_name(bufname);
if (cmd_get_entry(self) == &cmd_delete_buffer_entry) { if (cmd_get_entry(self) == &cmd_delete_buffer_entry) {
if (pb == NULL) { if (pb == NULL)
if (bufname != NULL) {
cmdq_error(item, "unknown buffer: %s", bufname);
return (CMD_RETURN_ERROR);
}
pb = paste_get_top(&bufname); pb = paste_get_top(&bufname);
}
if (pb == NULL) { if (pb == NULL) {
cmdq_error(item, "no buffer"); cmdq_error(item, "no buffer");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
@ -85,13 +80,8 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
} }
if (args_has(args, 'n')) { if (args_has(args, 'n')) {
if (pb == NULL) { if (pb == NULL)
if (bufname != NULL) {
cmdq_error(item, "unknown buffer: %s", bufname);
return (CMD_RETURN_ERROR);
}
pb = paste_get_top(&bufname); pb = paste_get_top(&bufname);
}
if (pb == NULL) { if (pb == NULL) {
cmdq_error(item, "no buffer"); cmdq_error(item, "no buffer");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
@ -131,7 +121,7 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (args_has(args, 'w') && tc != NULL) if (args_has(args, 'w') && tc != NULL)
tty_set_selection(&tc->tty, "", bufdata, bufsize); tty_set_selection(&tc->tty, bufdata, bufsize);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@ -35,7 +35,7 @@ const struct cmd_entry cmd_set_environment_entry = {
.alias = "setenv", .alias = "setenv",
.args = { "Fhgrt:u", 1, 2, NULL }, .args = { "Fhgrt:u", 1, 2, NULL },
.usage = "[-Fhgru] " CMD_TARGET_SESSION_USAGE " variable [value]", .usage = "[-Fhgru] " CMD_TARGET_SESSION_USAGE " name [value]",
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL }, .target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },

View File

@ -39,7 +39,7 @@ const struct cmd_entry cmd_show_environment_entry = {
.alias = "showenv", .alias = "showenv",
.args = { "hgst:", 0, 1, NULL }, .args = { "hgst:", 0, 1, NULL },
.usage = "[-hgs] " CMD_TARGET_SESSION_USAGE " [variable]", .usage = "[-hgs] " CMD_TARGET_SESSION_USAGE " [name]",
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL }, .target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },

View File

@ -65,7 +65,7 @@ const struct cmd_entry cmd_show_hooks_entry = {
.alias = NULL, .alias = NULL,
.args = { "gpt:w", 0, 1, NULL }, .args = { "gpt:w", 0, 1, NULL },
.usage = "[-gpw] " CMD_TARGET_PANE_USAGE " [hook]", .usage = "[-gpw] " CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL }, .target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },

View File

@ -32,7 +32,7 @@ const struct cmd_entry cmd_show_prompt_history_entry = {
.alias = "showphist", .alias = "showphist",
.args = { "T:", 0, 0, NULL }, .args = { "T:", 0, 0, NULL },
.usage = "[-T prompt-type]", .usage = "[-T type]",
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_show_prompt_history_exec .exec = cmd_show_prompt_history_exec
@ -43,7 +43,7 @@ const struct cmd_entry cmd_clear_prompt_history_entry = {
.alias = "clearphist", .alias = "clearphist",
.args = { "T:", 0, 0, NULL }, .args = { "T:", 0, 0, NULL },
.usage = "[-T prompt-type]", .usage = "[-T type]",
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_show_prompt_history_exec .exec = cmd_show_prompt_history_exec

View File

@ -29,19 +29,14 @@
* Sources a configuration file. * Sources a configuration file.
*/ */
#define CMD_SOURCE_FILE_DEPTH_LIMIT 50
static u_int cmd_source_file_depth;
static enum cmd_retval cmd_source_file_exec(struct cmd *, struct cmdq_item *); static enum cmd_retval cmd_source_file_exec(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_source_file_entry = { const struct cmd_entry cmd_source_file_entry = {
.name = "source-file", .name = "source-file",
.alias = "source", .alias = "source",
.args = { "t:Fnqv", 1, -1, NULL }, .args = { "Fnqv", 1, -1, NULL },
.usage = "[-Fnqv] " CMD_TARGET_PANE_USAGE " path ...", .usage = "[-Fnqv] path ...",
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
.flags = 0, .flags = 0,
.exec = cmd_source_file_exec .exec = cmd_source_file_exec
@ -62,16 +57,6 @@ struct cmd_source_file_data {
static enum cmd_retval static enum cmd_retval
cmd_source_file_complete_cb(struct cmdq_item *item, __unused void *data) cmd_source_file_complete_cb(struct cmdq_item *item, __unused void *data)
{ {
struct client *c = cmdq_get_client(item);
if (c == NULL) {
cmd_source_file_depth--;
log_debug("%s: depth now %u", __func__, cmd_source_file_depth);
} else {
c->source_file_depth--;
log_debug("%s: depth now %u", __func__, c->source_file_depth);
}
cfg_print_causes(item); cfg_print_causes(item);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
@ -107,7 +92,6 @@ cmd_source_file_done(struct client *c, const char *path, int error,
size_t bsize = EVBUFFER_LENGTH(buffer); size_t bsize = EVBUFFER_LENGTH(buffer);
u_int n; u_int n;
struct cmdq_item *new_item; struct cmdq_item *new_item;
struct cmd_find_state *target = cmdq_get_target(item);
if (!closed) if (!closed)
return; return;
@ -116,7 +100,7 @@ cmd_source_file_done(struct client *c, const char *path, int error,
cmdq_error(item, "%s: %s", path, strerror(error)); cmdq_error(item, "%s: %s", path, strerror(error));
else if (bsize != 0) { else if (bsize != 0) {
if (load_cfg_from_buffer(bdata, bsize, path, c, cdata->after, if (load_cfg_from_buffer(bdata, bsize, path, c, cdata->after,
target, cdata->flags, &new_item) < 0) cdata->flags, &new_item) < 0)
cdata->retval = CMD_RETURN_ERROR; cdata->retval = CMD_RETURN_ERROR;
else if (new_item != NULL) else if (new_item != NULL)
cdata->after = new_item; cdata->after = new_item;
@ -134,16 +118,7 @@ cmd_source_file_done(struct client *c, const char *path, int error,
static void static void
cmd_source_file_add(struct cmd_source_file_data *cdata, const char *path) cmd_source_file_add(struct cmd_source_file_data *cdata, const char *path)
{ {
char resolved[PATH_MAX];
if (realpath(path, resolved) == NULL) {
log_debug("%s: realpath(\"%s\") failed: %s", __func__,
path, strerror(errno));
} else
path = resolved;
log_debug("%s: %s", __func__, path); log_debug("%s: %s", __func__, path);
cdata->files = xreallocarray(cdata->files, cdata->nfiles + 1, cdata->files = xreallocarray(cdata->files, cdata->nfiles + 1,
sizeof *cdata->files); sizeof *cdata->files);
cdata->files[cdata->nfiles++] = xstrdup(path); cdata->files[cdata->nfiles++] = xstrdup(path);
@ -162,22 +137,6 @@ cmd_source_file_exec(struct cmd *self, struct cmdq_item *item)
int result; int result;
u_int i, j; u_int i, j;
if (c == NULL) {
if (cmd_source_file_depth >= CMD_SOURCE_FILE_DEPTH_LIMIT) {
cmdq_error(item, "too many nested files");
return (CMD_RETURN_ERROR);
}
cmd_source_file_depth++;
log_debug("%s: depth now %u", __func__, cmd_source_file_depth);
} else {
if (c->source_file_depth >= CMD_SOURCE_FILE_DEPTH_LIMIT) {
cmdq_error(item, "too many nested files");
return (CMD_RETURN_ERROR);
}
c->source_file_depth++;
log_debug("%s: depth now %u", __func__, c->source_file_depth);
}
cdata = xcalloc(1, sizeof *cdata); cdata = xcalloc(1, sizeof *cdata);
cdata->item = item; cdata->item = item;

View File

@ -42,7 +42,7 @@ const struct cmd_entry cmd_split_window_entry = {
.args = { "bc:de:fF:hIl:p:Pt:vZ", 0, -1, NULL }, .args = { "bc:de:fF:hIl:p:Pt:vZ", 0, -1, NULL },
.usage = "[-bdefhIPvZ] [-c start-directory] [-e environment] " .usage = "[-bdefhIPvZ] [-c start-directory] [-e environment] "
"[-F format] [-l size] " CMD_TARGET_PANE_USAGE "[-F format] [-l size] " CMD_TARGET_PANE_USAGE
" [shell-command [argument ...]]", "[shell-command]",
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
@ -65,46 +65,67 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
enum layout_type type; enum layout_type type;
struct layout_cell *lc; struct layout_cell *lc;
struct cmd_find_state fs; struct cmd_find_state fs;
int size, flags, input; int size, percentage, flags, input;
const char *template; const char *template, *errstr, *p;
char *cause = NULL, *cp; char *cause, *cp, *copy;
size_t plen;
struct args_value *av; struct args_value *av;
u_int count = args_count(args), curval = 0; u_int count = args_count(args);
type = LAYOUT_TOPBOTTOM;
if (args_has(args, 'h')) if (args_has(args, 'h'))
type = LAYOUT_LEFTRIGHT; type = LAYOUT_LEFTRIGHT;
else
/* If the 'p' flag is dropped then this bit can be moved into 'l'. */ type = LAYOUT_TOPBOTTOM;
if (args_has(args, 'l') || args_has(args, 'p')) { 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 (args_has(args, 'f')) {
if (type == LAYOUT_TOPBOTTOM)
size = (w->sy * percentage) / 100;
else
size = (w->sx * percentage) / 100;
} else {
if (type == LAYOUT_TOPBOTTOM)
size = (wp->sy * percentage) / 100;
else
size = (wp->sx * percentage) / 100;
}
} else {
size = args_strtonum(args, 'l', 0, INT_MAX, &cause);
if (cause != NULL) {
cmdq_error(item, "lines %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
}
} else if (args_has(args, 'p')) {
percentage = args_strtonum(args, 'p', 0, INT_MAX, &cause);
if (cause != NULL) {
cmdq_error(item, "create pane failed: -p %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
if (args_has(args, 'f')) { if (args_has(args, 'f')) {
if (type == LAYOUT_TOPBOTTOM) if (type == LAYOUT_TOPBOTTOM)
curval = w->sy; size = (w->sy * percentage) / 100;
else else
curval = w->sx; size = (w->sx * percentage) / 100;
} else { } else {
if (type == LAYOUT_TOPBOTTOM) if (type == LAYOUT_TOPBOTTOM)
curval = wp->sy; size = (wp->sy * percentage) / 100;
else else
curval = wp->sx; size = (wp->sx * percentage) / 100;
} }
} } else
size = -1;
size = -1;
if (args_has(args, 'l')) {
size = args_percentage_and_expand(args, 'l', 0, INT_MAX, curval,
item, &cause);
} else if (args_has(args, 'p')) {
size = args_strtonum_and_expand(args, 'p', 0, 100, item,
&cause);
if (cause == NULL)
size = curval * size / 100;
}
if (cause != NULL) {
cmdq_error(item, "size %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
window_push_zoom(wp->window, 1, args_has(args, 'Z')); window_push_zoom(wp->window, 1, args_has(args, 'Z'));
input = (args_has(args, 'I') && count == 0); input = (args_has(args, 'I') && count == 0);

View File

@ -101,10 +101,10 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
src_wp->window = dst_w; src_wp->window = dst_w;
options_set_parent(src_wp->options, dst_w->options); options_set_parent(src_wp->options, dst_w->options);
src_wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED); src_wp->flags |= PANE_STYLECHANGED;
dst_wp->window = src_w; dst_wp->window = src_w;
options_set_parent(dst_wp->options, src_w->options); options_set_parent(dst_wp->options, src_w->options);
dst_wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED); dst_wp->flags |= PANE_STYLECHANGED;
sx = src_wp->sx; sy = src_wp->sy; sx = src_wp->sx; sy = src_wp->sy;
xoff = src_wp->xoff; yoff = src_wp->yoff; xoff = src_wp->xoff; yoff = src_wp->yoff;
@ -128,16 +128,13 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
window_set_active_pane(dst_w, src_wp, 1); window_set_active_pane(dst_w, src_wp, 1);
} }
if (src_w != dst_w) { if (src_w != dst_w) {
window_pane_stack_remove(&src_w->last_panes, src_wp); if (src_w->last == src_wp)
window_pane_stack_remove(&dst_w->last_panes, dst_wp); src_w->last = NULL;
colour_palette_from_option(&src_wp->palette, src_wp->options); if (dst_w->last == dst_wp)
colour_palette_from_option(&dst_wp->palette, dst_wp->options); dst_w->last = NULL;
layout_fix_panes(src_w, NULL);
server_redraw_window(src_w);
} }
layout_fix_panes(dst_w, NULL); server_redraw_window(src_w);
server_redraw_window(dst_w); server_redraw_window(dst_w);
notify_window("window-layout-changed", src_w); notify_window("window-layout-changed", src_w);
if (src_w != dst_w) if (src_w != dst_w)
notify_window("window-layout-changed", dst_w); notify_window("window-layout-changed", dst_w);

20
cmd.c
View File

@ -47,6 +47,7 @@ extern const struct cmd_entry cmd_display_menu_entry;
extern const struct cmd_entry cmd_display_message_entry; extern const struct cmd_entry cmd_display_message_entry;
extern const struct cmd_entry cmd_display_popup_entry; extern const struct cmd_entry cmd_display_popup_entry;
extern const struct cmd_entry cmd_display_panes_entry; extern const struct cmd_entry cmd_display_panes_entry;
extern const struct cmd_entry cmd_down_pane_entry;
extern const struct cmd_entry cmd_find_window_entry; extern const struct cmd_entry cmd_find_window_entry;
extern const struct cmd_entry cmd_has_session_entry; extern const struct cmd_entry cmd_has_session_entry;
extern const struct cmd_entry cmd_if_shell_entry; extern const struct cmd_entry cmd_if_shell_entry;
@ -116,6 +117,7 @@ extern const struct cmd_entry cmd_swap_window_entry;
extern const struct cmd_entry cmd_switch_client_entry; extern const struct cmd_entry cmd_switch_client_entry;
extern const struct cmd_entry cmd_unbind_key_entry; extern const struct cmd_entry cmd_unbind_key_entry;
extern const struct cmd_entry cmd_unlink_window_entry; extern const struct cmd_entry cmd_unlink_window_entry;
extern const struct cmd_entry cmd_up_pane_entry;
extern const struct cmd_entry cmd_wait_for_entry; extern const struct cmd_entry cmd_wait_for_entry;
const struct cmd_entry *cmd_table[] = { const struct cmd_entry *cmd_table[] = {
@ -444,7 +446,7 @@ cmd_get_alias(const char *name)
} }
/* Look up a command entry by name. */ /* Look up a command entry by name. */
const struct cmd_entry * static const struct cmd_entry *
cmd_find(const char *name, char **cause) cmd_find(const char *name, char **cause)
{ {
const struct cmd_entry **loop, *entry, *found = NULL; const struct cmd_entry **loop, *entry, *found = NULL;
@ -636,7 +638,7 @@ cmd_list_free(struct cmd_list *cmdlist)
/* Copy a command list, expanding %s in arguments. */ /* Copy a command list, expanding %s in arguments. */
struct cmd_list * struct cmd_list *
cmd_list_copy(const struct cmd_list *cmdlist, int argc, char **argv) cmd_list_copy(struct cmd_list *cmdlist, int argc, char **argv)
{ {
struct cmd *cmd; struct cmd *cmd;
struct cmd_list *new_cmdlist; struct cmd_list *new_cmdlist;
@ -667,7 +669,7 @@ cmd_list_copy(const struct cmd_list *cmdlist, int argc, char **argv)
/* Get a command list as a string. */ /* Get a command list as a string. */
char * char *
cmd_list_print(const struct cmd_list *cmdlist, int escaped) cmd_list_print(struct cmd_list *cmdlist, int escaped)
{ {
struct cmd *cmd, *next; struct cmd *cmd, *next;
char *buf, *this; char *buf, *this;
@ -810,14 +812,10 @@ cmd_mouse_pane(struct mouse_event *m, struct session **sp,
if ((wl = cmd_mouse_window(m, sp)) == NULL) if ((wl = cmd_mouse_window(m, sp)) == NULL)
return (NULL); return (NULL);
if (m->wp == -1) if ((wp = window_pane_find_by_id(m->wp)) == NULL)
wp = wl->window->active; return (NULL);
else { if (!window_has_pane(wl->window, wp))
if ((wp = window_pane_find_by_id(m->wp)) == NULL) return (NULL);
return (NULL);
if (!window_has_pane(wl->window, wp))
return (NULL);
}
if (wlp != NULL) if (wlp != NULL)
*wlp = wl; *wlp = wl;

View File

@ -182,46 +182,6 @@ colour_tostring(int c)
return ("invalid"); return ("invalid");
} }
/* Convert background colour to theme. */
enum client_theme
colour_totheme(int c)
{
int r, g, b, brightness;
if (c == -1)
return (THEME_UNKNOWN);
if (c & COLOUR_FLAG_RGB) {
r = (c >> 16) & 0xff;
g = (c >> 8) & 0xff;
b = (c >> 0) & 0xff;
brightness = r + g + b;
if (brightness > 382)
return (THEME_LIGHT);
return (THEME_DARK);
}
if (c & COLOUR_FLAG_256)
return (colour_totheme(colour_256toRGB(c)));
switch (c) {
case 0:
case 90:
return (THEME_DARK);
case 7:
case 97:
return (THEME_LIGHT);
default:
if (c >= 0 && c <= 7)
return (colour_totheme(colour_256toRGB(c)));
if (c >= 90 && c <= 97)
return (colour_totheme(colour_256toRGB(8 + c - 90)));
break;
}
return (THEME_UNKNOWN);
}
/* Convert colour from string. */ /* Convert colour from string. */
int int
colour_fromstring(const char *s) colour_fromstring(const char *s)
@ -982,17 +942,13 @@ colour_byname(const char *name)
{ "yellow3", 0xcdcd00 }, { "yellow3", 0xcdcd00 },
{ "yellow4", 0x8b8b00 } { "yellow4", 0x8b8b00 }
}; };
u_int i; u_int i;
int c; int c;
const char *errstr;
if (strncmp(name, "grey", 4) == 0 || strncmp(name, "gray", 4) == 0) { if (strncmp(name, "grey", 4) == 0 || strncmp(name, "gray", 4) == 0) {
if (name[4] == '\0') if (!isdigit((u_char)name[4]))
return (0xbebebe|COLOUR_FLAG_RGB); return (0xbebebe|COLOUR_FLAG_RGB);
c = strtonum(name + 4, 0, 100, &errstr); c = round(2.55 * atoi(name + 4));
if (errstr != NULL)
return (-1);
c = round(2.55 * c);
if (c < 0 || c > 255) if (c < 0 || c > 255)
return (-1); return (-1);
return (colour_join_rgb(c, c, c)); return (colour_join_rgb(c, c, c));
@ -1004,47 +960,6 @@ colour_byname(const char *name)
return (-1); return (-1);
} }
/* Parse colour from an X11 string. */
int
colour_parseX11(const char *p)
{
double c, m, y, k = 0;
u_int r, g, b;
size_t len = strlen(p);
int colour = -1;
char *copy;
if ((len == 12 && sscanf(p, "rgb:%02x/%02x/%02x", &r, &g, &b) == 3) ||
(len == 7 && sscanf(p, "#%02x%02x%02x", &r, &g, &b) == 3) ||
sscanf(p, "%d,%d,%d", &r, &g, &b) == 3)
colour = colour_join_rgb(r, g, b);
else if ((len == 18 &&
sscanf(p, "rgb:%04x/%04x/%04x", &r, &g, &b) == 3) ||
(len == 13 && sscanf(p, "#%04x%04x%04x", &r, &g, &b) == 3))
colour = colour_join_rgb(r >> 8, g >> 8, b >> 8);
else if ((sscanf(p, "cmyk:%lf/%lf/%lf/%lf", &c, &m, &y, &k) == 4 ||
sscanf(p, "cmy:%lf/%lf/%lf", &c, &m, &y) == 3) &&
c >= 0 && c <= 1 && m >= 0 && m <= 1 &&
y >= 0 && y <= 1 && k >= 0 && k <= 1) {
colour = colour_join_rgb(
(1 - c) * (1 - k) * 255,
(1 - m) * (1 - k) * 255,
(1 - y) * (1 - k) * 255);
} else {
while (len != 0 && *p == ' ') {
p++;
len--;
}
while (len != 0 && p[len - 1] == ' ')
len--;
copy = xstrndup(p, len);
colour = colour_byname(copy);
free(copy);
}
log_debug("%s: %s = %s", __func__, p, colour_tostring(colour));
return (colour);
}
/* Initialize palette. */ /* Initialize palette. */
void void
colour_palette_init(struct colour_palette *p) colour_palette_init(struct colour_palette *p)
@ -1154,4 +1069,5 @@ colour_palette_from_option(struct colour_palette *p, struct options *oo)
} }
a = options_array_next(a); a = options_array_next(a);
} }
} }

View File

@ -38,14 +38,6 @@
#include <event2/bufferevent_compat.h> #include <event2/bufferevent_compat.h>
#else #else
#include <event.h> #include <event.h>
#ifndef EVBUFFER_EOL_LF
/*
* This doesn't really work because evbuffer_readline is broken, but gets us to
* build with very old (older than 1.4.14) libevent.
*/
#define EVBUFFER_EOL_LF
#define evbuffer_readln(a, b, c) evbuffer_readline(a)
#endif
#endif #endif
#ifdef HAVE_MALLOC_TRIM #ifdef HAVE_MALLOC_TRIM
@ -297,11 +289,6 @@ void explicit_bzero(void *, size_t);
int getdtablecount(void); int getdtablecount(void);
#endif #endif
#ifndef HAVE_GETDTABLESIZE
/* getdtablesize.c */
int getdtablesize(void);
#endif
#ifndef HAVE_CLOSEFROM #ifndef HAVE_CLOSEFROM
/* closefrom.c */ /* closefrom.c */
void closefrom(int); void closefrom(int);
@ -347,18 +334,6 @@ char *strndup(const char *, size_t);
void *memmem(const void *, size_t, const void *, size_t); void *memmem(const void *, size_t, const void *, size_t);
#endif #endif
#ifndef HAVE_HTONLL
/* htonll.c */
#undef htonll
uint64_t htonll(uint64_t);
#endif
#ifndef HAVE_NTOHLL
/* ntohll.c */
#undef ntohll
uint64_t ntohll(uint64_t);
#endif
#ifndef HAVE_GETPEEREID #ifndef HAVE_GETPEEREID
/* getpeereid.c */ /* getpeereid.c */
int getpeereid(int, uid_t *, gid_t *); int getpeereid(int, uid_t *, gid_t *);
@ -448,9 +423,7 @@ void *recallocarray(void *, size_t, size_t, size_t);
#ifdef HAVE_SYSTEMD #ifdef HAVE_SYSTEMD
/* systemd.c */ /* systemd.c */
int systemd_activated(void);
int systemd_create_socket(int, char **); int systemd_create_socket(int, char **);
int systemd_move_to_new_cgroup(char **);
#endif #endif
#ifdef HAVE_UTF8PROC #ifdef HAVE_UTF8PROC
@ -466,11 +439,11 @@ int utf8proc_wctomb(char *, wchar_t);
#endif #endif
/* getopt.c */ /* getopt.c */
extern int BSDopterr; extern int BSDopterr;
extern int BSDoptind; extern int BSDoptind;
extern int BSDoptopt; extern int BSDoptopt;
extern int BSDoptreset; extern int BSDoptreset;
extern char *BSDoptarg; extern char *BSDoptarg;
int BSDgetopt(int, char *const *, const char *); int BSDgetopt(int, char *const *, const char *);
#define getopt(ac, av, o) BSDgetopt(ac, av, o) #define getopt(ac, av, o) BSDgetopt(ac, av, o)
#define opterr BSDopterr #define opterr BSDopterr

View File

@ -27,7 +27,7 @@
#endif #endif
int int
clock_gettime(__unused int clock, struct timespec *ts) clock_gettime(int clock, struct timespec *ts)
{ {
struct timeval tv; struct timeval tv;

115
compat/getopt.c Normal file
View File

@ -0,0 +1,115 @@
/*
* Copyright (c) 1987, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/* OPENBSD ORIGINAL: lib/libc/stdlib/getopt.c */
#include "compat.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int BSDopterr = 1, /* if error message should be printed */
BSDoptind = 1, /* index into parent argv vector */
BSDoptopt, /* character checked for validity */
BSDoptreset; /* reset getopt */
char *BSDoptarg; /* argument associated with option */
#define BADCH (int)'?'
#define BADARG (int)':'
#define EMSG ""
/*
* getopt --
* Parse argc/argv argument vector.
*/
int
BSDgetopt(int nargc, char *const *nargv, const char *ostr)
{
static const char *place = EMSG; /* option letter processing */
char *oli; /* option letter list index */
if (ostr == NULL)
return (-1);
if (BSDoptreset || !*place) { /* update scanning pointer */
BSDoptreset = 0;
if (BSDoptind >= nargc || *(place = nargv[BSDoptind]) != '-') {
place = EMSG;
return (-1);
}
if (place[1] && *++place == '-') { /* found "--" */
if (place[1])
return (BADCH);
++BSDoptind;
place = EMSG;
return (-1);
}
} /* option letter okay? */
if ((BSDoptopt = (int)*place++) == (int)':' ||
!(oli = strchr(ostr, BSDoptopt))) {
/*
* if the user didn't specify '-' as an option,
* assume it means -1.
*/
if (BSDoptopt == (int)'-')
return (-1);
if (!*place)
++BSDoptind;
if (BSDopterr && *ostr != ':')
(void)fprintf(stderr,
"%s: unknown option -- %c\n", getprogname(),
BSDoptopt);
return (BADCH);
}
if (*++oli != ':') { /* don't need argument */
BSDoptarg = NULL;
if (!*place)
++BSDoptind;
}
else { /* need an argument */
if (*place) /* no white space */
BSDoptarg = (char *)place;
else if (nargc <= ++BSDoptind) { /* no arg */
place = EMSG;
if (*ostr == ':')
return (BADARG);
if (BSDopterr)
(void)fprintf(stderr,
"%s: option requires an argument -- %c\n",
getprogname(), BSDoptopt);
return (BADCH);
}
else /* white space */
BSDoptarg = nargv[BSDoptind];
place = EMSG;
++BSDoptind;
}
return (BSDoptopt); /* dump back option letter */
}

View File

@ -1,577 +0,0 @@
/* This file is obtained from OpenSSH:
* Repository: https://github.com/openssh/openssh-portable
* Commit: b5b405fee7f3e79d44e2d2971a4b6b4cc53f112e
* File: /openbsd-compat/getopt_long.c */
/*
* Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.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 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.
*
* Sponsored in part by the Defense Advanced Research Projects
* Agency (DARPA) and Air Force Research Laboratory, Air Force
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
*/
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dieter Baron and Thomas Klausner.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/* OPENBSD ORIGINAL: lib/libc/stdlib/getopt_long.c */
#include "compat.h"
/* The following macro constants are taken from getopt.h of OpenSSH:
* Repository: https://github.com/openssh/openssh-portable
* Commit: b5b405fee7f3e79d44e2d2971a4b6b4cc53f112e
* File: /openbsd-compat/getopt.h
*
* ---- BEGIN - Copyright notice and license of getopt.h ----
* Copyright (c) 2000 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dieter Baron and Thomas Klausner.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* ---- END ----
*/
#define no_argument 0
#define required_argument 1
#define optional_argument 2
#if !defined(HAVE_GETOPT) || !defined(HAVE_GETOPT_OPTRESET)
#if 0
#include <err.h>
#include <getopt.h>
#endif
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
struct option {
/* name of long option */
const char *name;
/*
* one of no_argument, required_argument, and optional_argument:
* whether option takes an argument
*/
int has_arg;
/* if not NULL, set *flag to val when option found */
int *flag;
/* if flag not NULL, value to set *flag to; else return value */
int val;
};
int opterr = 1; /* if error message should be printed */
int optind = 1; /* index into parent argv vector */
int optopt = '?'; /* character checked for validity */
int optreset; /* reset getopt */
char *optarg; /* argument associated with option */
#define PRINT_ERROR ((opterr) && (*options != ':'))
#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
/* return values */
#define BADCH (int)'?'
#define BADARG ((*options == ':') ? (int)':' : (int)'?')
#define INORDER (int)1
#define EMSG (char *)""
static int getopt_internal(int, char * const *, const char *,
const struct option *, int *, int);
static int parse_long_options(char * const *, const char *,
const struct option *, int *, int);
static int gcd(int, int);
static void permute_args(int, int, int, char * const *);
static char *place = EMSG; /* option letter processing */
/* XXX: set optreset to 1 rather than these two */
static int nonopt_start = -1; /* first non option argument (for permute) */
static int nonopt_end = -1; /* first option after non options (for permute) */
/* Error messages */
static const char recargchar[] = "option requires an argument -- %c";
static const char recargstring[] = "option requires an argument -- %s";
static const char ambig[] = "ambiguous option -- %.*s";
static const char noarg[] = "option doesn't take an argument -- %.*s";
static const char illoptchar[] = "unknown option -- %c";
static const char illoptstring[] = "unknown option -- %s";
/*
* Compute the greatest common divisor of a and b.
*/
static int
gcd(int a, int b)
{
int c;
c = a % b;
while (c != 0) {
a = b;
b = c;
c = a % b;
}
return (b);
}
/*
* Exchange the block from nonopt_start to nonopt_end with the block
* from nonopt_end to opt_end (keeping the same order of arguments
* in each block).
*/
static void
permute_args(int panonopt_start, int panonopt_end, int opt_end,
char * const *nargv)
{
int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
char *swap;
/*
* compute lengths of blocks and number and size of cycles
*/
nnonopts = panonopt_end - panonopt_start;
nopts = opt_end - panonopt_end;
ncycle = gcd(nnonopts, nopts);
cyclelen = (opt_end - panonopt_start) / ncycle;
for (i = 0; i < ncycle; i++) {
cstart = panonopt_end+i;
pos = cstart;
for (j = 0; j < cyclelen; j++) {
if (pos >= panonopt_end)
pos -= nnonopts;
else
pos += nopts;
swap = nargv[pos];
/* LINTED const cast */
((char **) nargv)[pos] = nargv[cstart];
/* LINTED const cast */
((char **)nargv)[cstart] = swap;
}
}
}
/*
* parse_long_options --
* Parse long options in argc/argv argument vector.
* Returns -1 if short_too is set and the option does not match long_options.
*/
static int
parse_long_options(char * const *nargv, const char *options,
const struct option *long_options, int *idx, int short_too)
{
char *current_argv, *has_equal;
size_t current_argv_len;
int i, match;
current_argv = place;
match = -1;
optind++;
if ((has_equal = strchr(current_argv, '=')) != NULL) {
/* argument found (--option=arg) */
current_argv_len = has_equal - current_argv;
has_equal++;
} else
current_argv_len = strlen(current_argv);
for (i = 0; long_options[i].name; i++) {
/* find matching long option */
if (strncmp(current_argv, long_options[i].name,
current_argv_len))
continue;
if (strlen(long_options[i].name) == current_argv_len) {
/* exact match */
match = i;
break;
}
/*
* If this is a known short option, don't allow
* a partial match of a single character.
*/
if (short_too && current_argv_len == 1)
continue;
if (match == -1) /* partial match */
match = i;
else {
/* ambiguous abbreviation */
if (PRINT_ERROR)
warnx(ambig, (int)current_argv_len,
current_argv);
optopt = 0;
return (BADCH);
}
}
if (match != -1) { /* option found */
if (long_options[match].has_arg == no_argument
&& has_equal) {
if (PRINT_ERROR)
warnx(noarg, (int)current_argv_len,
current_argv);
/*
* XXX: GNU sets optopt to val regardless of flag
*/
if (long_options[match].flag == NULL)
optopt = long_options[match].val;
else
optopt = 0;
return (BADARG);
}
if (long_options[match].has_arg == required_argument ||
long_options[match].has_arg == optional_argument) {
if (has_equal)
optarg = has_equal;
else if (long_options[match].has_arg ==
required_argument) {
/*
* optional argument doesn't use next nargv
*/
optarg = nargv[optind++];
}
}
if ((long_options[match].has_arg == required_argument)
&& (optarg == NULL)) {
/*
* Missing argument; leading ':' indicates no error
* should be generated.
*/
if (PRINT_ERROR)
warnx(recargstring,
current_argv);
/*
* XXX: GNU sets optopt to val regardless of flag
*/
if (long_options[match].flag == NULL)
optopt = long_options[match].val;
else
optopt = 0;
--optind;
return (BADARG);
}
} else { /* unknown option */
if (short_too) {
--optind;
return (-1);
}
if (PRINT_ERROR)
warnx(illoptstring, current_argv);
optopt = 0;
return (BADCH);
}
if (idx)
*idx = match;
if (long_options[match].flag) {
*long_options[match].flag = long_options[match].val;
return (0);
} else
return (long_options[match].val);
}
/*
* getopt_internal --
* Parse argc/argv argument vector. Called by user level routines.
*/
static int
getopt_internal(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx, int flags)
{
char *oli; /* option letter list index */
int optchar, short_too;
static int posixly_correct = -1;
if (options == NULL)
return (-1);
/*
* XXX Some GNU programs (like cvs) set optind to 0 instead of
* XXX using optreset. Work around this braindamage.
*/
if (optind == 0)
optind = optreset = 1;
/*
* Disable GNU extensions if POSIXLY_CORRECT is set or options
* string begins with a '+'.
*/
if (posixly_correct == -1 || optreset)
posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
if (*options == '-')
flags |= FLAG_ALLARGS;
else if (posixly_correct || *options == '+')
flags &= ~FLAG_PERMUTE;
if (*options == '+' || *options == '-')
options++;
optarg = NULL;
if (optreset)
nonopt_start = nonopt_end = -1;
start:
if (optreset || !*place) { /* update scanning pointer */
optreset = 0;
if (optind >= nargc) { /* end of argument vector */
place = EMSG;
if (nonopt_end != -1) {
/* do permutation, if we have to */
permute_args(nonopt_start, nonopt_end,
optind, nargv);
optind -= nonopt_end - nonopt_start;
}
else if (nonopt_start != -1) {
/*
* If we skipped non-options, set optind
* to the first of them.
*/
optind = nonopt_start;
}
nonopt_start = nonopt_end = -1;
return (-1);
}
if (*(place = nargv[optind]) != '-' ||
(place[1] == '\0' && strchr(options, '-') == NULL)) {
place = EMSG; /* found non-option */
if (flags & FLAG_ALLARGS) {
/*
* GNU extension:
* return non-option as argument to option 1
*/
optarg = nargv[optind++];
return (INORDER);
}
if (!(flags & FLAG_PERMUTE)) {
/*
* If no permutation wanted, stop parsing
* at first non-option.
*/
return (-1);
}
/* do permutation */
if (nonopt_start == -1)
nonopt_start = optind;
else if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end,
optind, nargv);
nonopt_start = optind -
(nonopt_end - nonopt_start);
nonopt_end = -1;
}
optind++;
/* process next argument */
goto start;
}
if (nonopt_start != -1 && nonopt_end == -1)
nonopt_end = optind;
/*
* If we have "-" do nothing, if "--" we are done.
*/
if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
optind++;
place = EMSG;
/*
* We found an option (--), so if we skipped
* non-options, we have to permute.
*/
if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end,
optind, nargv);
optind -= nonopt_end - nonopt_start;
}
nonopt_start = nonopt_end = -1;
return (-1);
}
}
/*
* Check long options if:
* 1) we were passed some
* 2) the arg is not just "-"
* 3) either the arg starts with -- we are getopt_long_only()
*/
if (long_options != NULL && place != nargv[optind] &&
(*place == '-' || (flags & FLAG_LONGONLY))) {
short_too = 0;
if (*place == '-')
place++; /* --foo long option */
else if (*place != ':' && strchr(options, *place) != NULL)
short_too = 1; /* could be short option too */
optchar = parse_long_options(nargv, options, long_options,
idx, short_too);
if (optchar != -1) {
place = EMSG;
return (optchar);
}
}
if ((optchar = (int)*place++) == (int)':' ||
(optchar == (int)'-' && *place != '\0') ||
(oli = strchr(options, optchar)) == NULL) {
/*
* If the user specified "-" and '-' isn't listed in
* options, return -1 (non-option) as per POSIX.
* Otherwise, it is an unknown option character (or ':').
*/
if (optchar == (int)'-' && *place == '\0')
return (-1);
if (!*place)
++optind;
if (PRINT_ERROR)
warnx(illoptchar, optchar);
optopt = optchar;
return (BADCH);
}
if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
/* -W long-option */
if (*place) /* no space */
/* NOTHING */;
else if (++optind >= nargc) { /* no arg */
place = EMSG;
if (PRINT_ERROR)
warnx(recargchar, optchar);
optopt = optchar;
return (BADARG);
} else /* white space */
place = nargv[optind];
optchar = parse_long_options(nargv, options, long_options,
idx, 0);
place = EMSG;
return (optchar);
}
if (*++oli != ':') { /* doesn't take argument */
if (!*place)
++optind;
} else { /* takes (optional) argument */
optarg = NULL;
if (*place) /* no white space */
optarg = place;
else if (oli[1] != ':') { /* arg not optional */
if (++optind >= nargc) { /* no arg */
place = EMSG;
if (PRINT_ERROR)
warnx(recargchar, optchar);
optopt = optchar;
return (BADARG);
} else
optarg = nargv[optind];
}
place = EMSG;
++optind;
}
/* dump back option letter */
return (optchar);
}
/*
* getopt --
* Parse argc/argv argument vector.
*
* [eventually this will replace the BSD getopt]
*/
int
getopt(int nargc, char * const *nargv, const char *options)
{
/*
* We don't pass FLAG_PERMUTE to getopt_internal() since
* the BSD getopt(3) (unlike GNU) has never done this.
*
* Furthermore, since many privileged programs call getopt()
* before dropping privileges it makes sense to keep things
* as simple (and bug-free) as possible.
*/
return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
}
#if 0
/*
* getopt_long --
* Parse argc/argv argument vector.
*/
int
getopt_long(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx)
{
return (getopt_internal(nargc, nargv, options, long_options, idx,
FLAG_PERMUTE));
}
/*
* getopt_long_only --
* Parse argc/argv argument vector.
*/
int
getopt_long_only(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx)
{
return (getopt_internal(nargc, nargv, options, long_options, idx,
FLAG_PERMUTE|FLAG_LONGONLY));
}
#endif
#endif /* !defined(HAVE_GETOPT) || !defined(HAVE_OPTRESET) */

View File

@ -18,7 +18,6 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <stdio.h> #include <stdio.h>
#include <unistd.h>
#ifdef HAVE_UCRED_H #ifdef HAVE_UCRED_H
#include <ucred.h> #include <ucred.h>
@ -50,8 +49,6 @@ getpeereid(int s, uid_t *uid, gid_t *gid)
ucred_free(ucred); ucred_free(ucred);
return (0); return (0);
#else #else
*uid = geteuid(); return (getuid());
*gid = getegid();
return (0);
#endif #endif
} }

View File

@ -1,31 +0,0 @@
/*
* Copyright (c) 2024 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 <arpa/inet.h>
#include <sys/types.h>
#include "compat.h"
uint64_t
htonll(uint64_t v)
{
uint32_t b;
uint32_t t;
b = htonl (v & 0xffffffff);
t = htonl (v >> 32);
return ((uint64_t)b << 32 | t);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,6 @@
/* $OpenBSD: imsg.c,v 1.37 2024/11/26 13:57:31 claudio Exp $ */ /* $OpenBSD: imsg.c,v 1.16 2017/12/14 09:27:44 kettenis Exp $ */
/* /*
* Copyright (c) 2023 Claudio Jeker <claudio@openbsd.org>
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
* *
* Permission to use, copy, modify, and distribute this software for any * Permission to use, copy, modify, and distribute this software for any
@ -22,7 +21,6 @@
#include <sys/uio.h> #include <sys/uio.h>
#include <errno.h> #include <errno.h>
#include <stddef.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
@ -30,288 +28,203 @@
#include "compat.h" #include "compat.h"
#include "imsg.h" #include "imsg.h"
#define IMSG_ALLOW_FDPASS 0x01 int imsg_fd_overhead = 0;
#define IMSG_FD_MARK 0x80000000U
static struct ibuf *imsg_parse_hdr(struct ibuf *, void *, int *); static int imsg_get_fd(struct imsgbuf *);
int
imsgbuf_init(struct imsgbuf *imsgbuf, int fd)
{
imsgbuf->w = msgbuf_new_reader(IMSG_HEADER_SIZE, imsg_parse_hdr,
imsgbuf);
if (imsgbuf->w == NULL)
return (-1);
imsgbuf->pid = getpid();
imsgbuf->maxsize = MAX_IMSGSIZE;
imsgbuf->fd = fd;
imsgbuf->flags = 0;
return (0);
}
void void
imsgbuf_allow_fdpass(struct imsgbuf *imsgbuf) imsg_init(struct imsgbuf *ibuf, int fd)
{ {
imsgbuf->flags |= IMSG_ALLOW_FDPASS; msgbuf_init(&ibuf->w);
} memset(&ibuf->r, 0, sizeof(ibuf->r));
ibuf->fd = fd;
int ibuf->w.fd = fd;
imsgbuf_set_maxsize(struct imsgbuf *imsgbuf, uint32_t maxsize) ibuf->pid = getpid();
{ TAILQ_INIT(&ibuf->fds);
if (maxsize < IMSG_HEADER_SIZE || maxsize & IMSG_FD_MARK) {
errno = EINVAL;
return (-1);
}
imsgbuf->maxsize = maxsize;
return (0);
}
int
imsgbuf_read(struct imsgbuf *imsgbuf)
{
if (imsgbuf->flags & IMSG_ALLOW_FDPASS)
return msgbuf_read(imsgbuf->fd, imsgbuf->w);
else
return ibuf_read(imsgbuf->fd, imsgbuf->w);
}
int
imsgbuf_write(struct imsgbuf *imsgbuf)
{
if (imsgbuf->flags & IMSG_ALLOW_FDPASS)
return msgbuf_write(imsgbuf->fd, imsgbuf->w);
else
return ibuf_write(imsgbuf->fd, imsgbuf->w);
}
int
imsgbuf_flush(struct imsgbuf *imsgbuf)
{
while (imsgbuf_queuelen(imsgbuf) > 0) {
if (imsgbuf_write(imsgbuf) == -1)
return (-1);
}
return (0);
}
void
imsgbuf_clear(struct imsgbuf *imsgbuf)
{
msgbuf_free(imsgbuf->w);
imsgbuf->w = NULL;
}
uint32_t
imsgbuf_queuelen(struct imsgbuf *imsgbuf)
{
return msgbuf_queuelen(imsgbuf->w);
} }
ssize_t ssize_t
imsg_get(struct imsgbuf *imsgbuf, struct imsg *imsg) imsg_read(struct imsgbuf *ibuf)
{ {
struct imsg m; struct msghdr msg;
struct ibuf *buf; struct cmsghdr *cmsg;
union {
struct cmsghdr hdr;
char buf[CMSG_SPACE(sizeof(int) * 1)];
} cmsgbuf;
struct iovec iov;
ssize_t n = -1;
int fd;
struct imsg_fd *ifd;
if ((buf = msgbuf_get(imsgbuf->w)) == NULL) memset(&msg, 0, sizeof(msg));
memset(&cmsgbuf, 0, sizeof(cmsgbuf));
iov.iov_base = ibuf->r.buf + ibuf->r.wpos;
iov.iov_len = sizeof(ibuf->r.buf) - ibuf->r.wpos;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = &cmsgbuf.buf;
msg.msg_controllen = sizeof(cmsgbuf.buf);
if ((ifd = calloc(1, sizeof(struct imsg_fd))) == NULL)
return (-1);
again:
if (getdtablecount() + imsg_fd_overhead +
(int)((CMSG_SPACE(sizeof(int))-CMSG_SPACE(0))/sizeof(int))
>= getdtablesize()) {
errno = EAGAIN;
free(ifd);
return (-1);
}
if ((n = recvmsg(ibuf->fd, &msg, 0)) == -1) {
if (errno == EINTR)
goto again;
goto fail;
}
ibuf->r.wpos += n;
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
if (cmsg->cmsg_level == SOL_SOCKET &&
cmsg->cmsg_type == SCM_RIGHTS) {
int i;
int j;
/*
* We only accept one file descriptor. Due to C
* padding rules, our control buffer might contain
* more than one fd, and we must close them.
*/
j = ((char *)cmsg + cmsg->cmsg_len -
(char *)CMSG_DATA(cmsg)) / sizeof(int);
for (i = 0; i < j; i++) {
fd = ((int *)CMSG_DATA(cmsg))[i];
if (ifd != NULL) {
ifd->fd = fd;
TAILQ_INSERT_TAIL(&ibuf->fds, ifd,
entry);
ifd = NULL;
} else
close(fd);
}
}
/* we do not handle other ctl data level */
}
fail:
free(ifd);
return (n);
}
ssize_t
imsg_get(struct imsgbuf *ibuf, struct imsg *imsg)
{
size_t av, left, datalen;
av = ibuf->r.wpos;
if (IMSG_HEADER_SIZE > av)
return (0); return (0);
if (ibuf_get(buf, &m.hdr, sizeof(m.hdr)) == -1) memcpy(&imsg->hdr, ibuf->r.buf, sizeof(imsg->hdr));
if (imsg->hdr.len < IMSG_HEADER_SIZE ||
imsg->hdr.len > MAX_IMSGSIZE) {
errno = ERANGE;
return (-1);
}
if (imsg->hdr.len > av)
return (0);
datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
ibuf->r.rptr = ibuf->r.buf + IMSG_HEADER_SIZE;
if (datalen == 0)
imsg->data = NULL;
else if ((imsg->data = malloc(datalen)) == NULL)
return (-1); return (-1);
if (ibuf_size(buf)) if (imsg->hdr.flags & IMSGF_HASFD)
m.data = ibuf_data(buf); imsg->fd = imsg_get_fd(ibuf);
else else
m.data = NULL; imsg->fd = -1;
m.buf = buf;
m.hdr.len &= ~IMSG_FD_MARK;
*imsg = m; memcpy(imsg->data, ibuf->r.rptr, datalen);
return (ibuf_size(buf) + IMSG_HEADER_SIZE);
if (imsg->hdr.len < av) {
left = av - imsg->hdr.len;
memmove(&ibuf->r.buf, ibuf->r.buf + imsg->hdr.len, left);
ibuf->r.wpos = left;
} else
ibuf->r.wpos = 0;
return (datalen + IMSG_HEADER_SIZE);
} }
int int
imsg_get_ibuf(struct imsg *imsg, struct ibuf *ibuf) imsg_compose(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid, pid_t pid,
{ int fd, const void *data, uint16_t datalen)
if (ibuf_size(imsg->buf) == 0) {
errno = EBADMSG;
return (-1);
}
return ibuf_get_ibuf(imsg->buf, ibuf_size(imsg->buf), ibuf);
}
int
imsg_get_data(struct imsg *imsg, void *data, size_t len)
{
if (len == 0) {
errno = EINVAL;
return (-1);
}
if (ibuf_size(imsg->buf) != len) {
errno = EBADMSG;
return (-1);
}
return ibuf_get(imsg->buf, data, len);
}
int
imsg_get_fd(struct imsg *imsg)
{
return ibuf_fd_get(imsg->buf);
}
uint32_t
imsg_get_id(struct imsg *imsg)
{
return (imsg->hdr.peerid);
}
size_t
imsg_get_len(struct imsg *imsg)
{
return ibuf_size(imsg->buf);
}
pid_t
imsg_get_pid(struct imsg *imsg)
{
return (imsg->hdr.pid);
}
uint32_t
imsg_get_type(struct imsg *imsg)
{
return (imsg->hdr.type);
}
int
imsg_compose(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id, pid_t pid,
int fd, const void *data, size_t datalen)
{ {
struct ibuf *wbuf; struct ibuf *wbuf;
if ((wbuf = imsg_create(imsgbuf, type, id, pid, datalen)) == NULL) if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL)
return (-1); return (-1);
if (imsg_add(wbuf, data, datalen) == -1) if (imsg_add(wbuf, data, datalen) == -1)
return (-1); return (-1);
ibuf_fd_set(wbuf, fd); wbuf->fd = fd;
imsg_close(imsgbuf, wbuf);
imsg_close(ibuf, wbuf);
return (1); return (1);
} }
int int
imsg_composev(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id, pid_t pid, imsg_composev(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid, pid_t pid,
int fd, const struct iovec *iov, int iovcnt) int fd, const struct iovec *iov, int iovcnt)
{ {
struct ibuf *wbuf; struct ibuf *wbuf;
int i; int i, datalen = 0;
size_t datalen = 0;
for (i = 0; i < iovcnt; i++) for (i = 0; i < iovcnt; i++)
datalen += iov[i].iov_len; datalen += iov[i].iov_len;
if ((wbuf = imsg_create(imsgbuf, type, id, pid, datalen)) == NULL) if ((wbuf = imsg_create(ibuf, type, peerid, pid, datalen)) == NULL)
return (-1); return (-1);
for (i = 0; i < iovcnt; i++) for (i = 0; i < iovcnt; i++)
if (imsg_add(wbuf, iov[i].iov_base, iov[i].iov_len) == -1) if (imsg_add(wbuf, iov[i].iov_base, iov[i].iov_len) == -1)
return (-1); return (-1);
ibuf_fd_set(wbuf, fd); wbuf->fd = fd;
imsg_close(imsgbuf, wbuf);
imsg_close(ibuf, wbuf);
return (1); return (1);
} }
/* /* ARGSUSED */
* Enqueue imsg with payload from ibuf buf. fd passing is not possible
* with this function.
*/
int
imsg_compose_ibuf(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id,
pid_t pid, struct ibuf *buf)
{
struct ibuf *hdrbuf = NULL;
struct imsg_hdr hdr;
int save_errno;
if (ibuf_size(buf) + IMSG_HEADER_SIZE > imsgbuf->maxsize) {
errno = ERANGE;
goto fail;
}
hdr.type = type;
hdr.len = ibuf_size(buf) + IMSG_HEADER_SIZE;
hdr.peerid = id;
if ((hdr.pid = pid) == 0)
hdr.pid = imsgbuf->pid;
if ((hdrbuf = ibuf_open(IMSG_HEADER_SIZE)) == NULL)
goto fail;
if (imsg_add(hdrbuf, &hdr, sizeof(hdr)) == -1)
goto fail;
ibuf_close(imsgbuf->w, hdrbuf);
ibuf_close(imsgbuf->w, buf);
return (1);
fail:
save_errno = errno;
ibuf_free(buf);
ibuf_free(hdrbuf);
errno = save_errno;
return (-1);
}
/*
* Forward imsg to another channel. Any attached fd is closed.
*/
int
imsg_forward(struct imsgbuf *imsgbuf, struct imsg *msg)
{
struct ibuf *wbuf;
size_t len;
ibuf_rewind(msg->buf);
ibuf_skip(msg->buf, sizeof(msg->hdr));
len = ibuf_size(msg->buf);
if ((wbuf = imsg_create(imsgbuf, msg->hdr.type, msg->hdr.peerid,
msg->hdr.pid, len)) == NULL)
return (-1);
if (len != 0) {
if (ibuf_add_ibuf(wbuf, msg->buf) == -1) {
ibuf_free(wbuf);
return (-1);
}
}
imsg_close(imsgbuf, wbuf);
return (1);
}
struct ibuf * struct ibuf *
imsg_create(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id, pid_t pid, imsg_create(struct imsgbuf *ibuf, uint32_t type, uint32_t peerid, pid_t pid,
size_t datalen) uint16_t datalen)
{ {
struct ibuf *wbuf; struct ibuf *wbuf;
struct imsg_hdr hdr; struct imsg_hdr hdr;
datalen += IMSG_HEADER_SIZE; datalen += IMSG_HEADER_SIZE;
if (datalen > imsgbuf->maxsize) { if (datalen > MAX_IMSGSIZE) {
errno = ERANGE; errno = ERANGE;
return (NULL); return (NULL);
} }
hdr.type = type; hdr.type = type;
hdr.peerid = id; hdr.flags = 0;
hdr.peerid = peerid;
if ((hdr.pid = pid) == 0) if ((hdr.pid = pid) == 0)
hdr.pid = imsgbuf->pid; hdr.pid = ibuf->pid;
if ((wbuf = ibuf_dynamic(datalen, imsgbuf->maxsize)) == NULL) { if ((wbuf = ibuf_dynamic(datalen, MAX_IMSGSIZE)) == NULL) {
return (NULL); return (NULL);
} }
if (imsg_add(wbuf, &hdr, sizeof(hdr)) == -1) if (imsg_add(wbuf, &hdr, sizeof(hdr)) == -1)
@ -321,7 +234,7 @@ imsg_create(struct imsgbuf *imsgbuf, uint32_t type, uint32_t id, pid_t pid,
} }
int int
imsg_add(struct ibuf *msg, const void *data, size_t datalen) imsg_add(struct ibuf *msg, const void *data, uint16_t datalen)
{ {
if (datalen) if (datalen)
if (ibuf_add(msg, data, datalen) == -1) { if (ibuf_add(msg, data, datalen) == -1) {
@ -332,47 +245,58 @@ imsg_add(struct ibuf *msg, const void *data, size_t datalen)
} }
void void
imsg_close(struct imsgbuf *imsgbuf, struct ibuf *msg) imsg_close(struct imsgbuf *ibuf, struct ibuf *msg)
{ {
struct imsg_hdr *hdr; struct imsg_hdr *hdr;
uint32_t len;
len = ibuf_size(msg); hdr = (struct imsg_hdr *)msg->buf;
if (ibuf_fd_avail(msg))
len |= IMSG_FD_MARK; hdr->flags &= ~IMSGF_HASFD;
(void)ibuf_set_h32(msg, offsetof(struct imsg_hdr, len), len); if (msg->fd != -1)
ibuf_close(imsgbuf->w, msg); hdr->flags |= IMSGF_HASFD;
hdr->len = (uint16_t)msg->wpos;
ibuf_close(&ibuf->w, msg);
} }
void void
imsg_free(struct imsg *imsg) imsg_free(struct imsg *imsg)
{ {
ibuf_free(imsg->buf); freezero(imsg->data, imsg->hdr.len - IMSG_HEADER_SIZE);
} }
static struct ibuf * static int
imsg_parse_hdr(struct ibuf *buf, void *arg, int *fd) imsg_get_fd(struct imsgbuf *ibuf)
{ {
struct imsgbuf *imsgbuf = arg; int fd;
struct imsg_hdr hdr; struct imsg_fd *ifd;
struct ibuf *b;
uint32_t len;
if (ibuf_get(buf, &hdr, sizeof(hdr)) == -1) if ((ifd = TAILQ_FIRST(&ibuf->fds)) == NULL)
return (NULL); return (-1);
len = hdr.len & ~IMSG_FD_MARK; fd = ifd->fd;
TAILQ_REMOVE(&ibuf->fds, ifd, entry);
free(ifd);
if (len < IMSG_HEADER_SIZE || len > imsgbuf->maxsize) { return (fd);
errno = ERANGE; }
return (NULL);
} int
if ((b = ibuf_open(len)) == NULL) imsg_flush(struct imsgbuf *ibuf)
return (NULL); {
if (hdr.len & IMSG_FD_MARK) { while (ibuf->w.queued)
ibuf_fd_set(b, *fd); if (msgbuf_write(&ibuf->w) <= 0)
*fd = -1; return (-1);
} return (0);
}
return b;
void
imsg_clear(struct imsgbuf *ibuf)
{
int fd;
msgbuf_clear(&ibuf->w);
while ((fd = imsg_get_fd(ibuf)) != -1)
close(fd);
} }

View File

@ -1,7 +1,6 @@
/* $OpenBSD: imsg.h,v 1.19 2024/11/26 13:57:31 claudio Exp $ */ /* $OpenBSD: imsg.h,v 1.5 2019/01/20 02:50:03 bcook Exp $ */
/* /*
* Copyright (c) 2023 Claudio Jeker <claudio@openbsd.org>
* Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org> * Copyright (c) 2006, 2007 Pierre-Yves Ritschard <pyr@openbsd.org>
* Copyright (c) 2006, 2007, 2008 Reyk Floeter <reyk@openbsd.org> * Copyright (c) 2006, 2007, 2008 Reyk Floeter <reyk@openbsd.org>
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@ -22,7 +21,7 @@
#ifndef _IMSG_H_ #ifndef _IMSG_H_
#define _IMSG_H_ #define _IMSG_H_
#include <sys/types.h> #include <stdint.h>
#define IBUF_READ_SIZE 65535 #define IBUF_READ_SIZE 65535
#define IMSG_HEADER_SIZE sizeof(struct imsg_hdr) #define IMSG_HEADER_SIZE sizeof(struct imsg_hdr)
@ -38,116 +37,77 @@ struct ibuf {
int fd; int fd;
}; };
struct msgbuf; struct msgbuf {
TAILQ_HEAD(, ibuf) bufs;
uint32_t queued;
int fd;
};
struct ibuf_read {
unsigned char buf[IBUF_READ_SIZE];
unsigned char *rptr;
size_t wpos;
};
struct imsg_fd {
TAILQ_ENTRY(imsg_fd) entry;
int fd;
};
struct imsgbuf { struct imsgbuf {
struct msgbuf *w; TAILQ_HEAD(, imsg_fd) fds;
pid_t pid; struct ibuf_read r;
uint32_t maxsize; struct msgbuf w;
int fd; int fd;
int flags; pid_t pid;
}; };
#define IMSGF_HASFD 1
struct imsg_hdr { struct imsg_hdr {
uint32_t type; uint32_t type;
uint32_t len; uint16_t len;
uint16_t flags;
uint32_t peerid; uint32_t peerid;
uint32_t pid; uint32_t pid;
}; };
struct imsg { struct imsg {
struct imsg_hdr hdr; struct imsg_hdr hdr;
int fd;
void *data; void *data;
struct ibuf *buf;
}; };
struct iovec;
/* imsg-buffer.c */ /* buffer.c */
struct ibuf *ibuf_open(size_t); struct ibuf *ibuf_open(size_t);
struct ibuf *ibuf_dynamic(size_t, size_t); struct ibuf *ibuf_dynamic(size_t, size_t);
int ibuf_add(struct ibuf *, const void *, size_t); int ibuf_add(struct ibuf *, const void *, size_t);
int ibuf_add_ibuf(struct ibuf *, const struct ibuf *);
int ibuf_add_zero(struct ibuf *, size_t);
int ibuf_add_n8(struct ibuf *, uint64_t);
int ibuf_add_n16(struct ibuf *, uint64_t);
int ibuf_add_n32(struct ibuf *, uint64_t);
int ibuf_add_n64(struct ibuf *, uint64_t);
int ibuf_add_h16(struct ibuf *, uint64_t);
int ibuf_add_h32(struct ibuf *, uint64_t);
int ibuf_add_h64(struct ibuf *, uint64_t);
void *ibuf_reserve(struct ibuf *, size_t); void *ibuf_reserve(struct ibuf *, size_t);
void *ibuf_seek(struct ibuf *, size_t, size_t); void *ibuf_seek(struct ibuf *, size_t, size_t);
int ibuf_set(struct ibuf *, size_t, const void *, size_t); size_t ibuf_size(struct ibuf *);
int ibuf_set_n8(struct ibuf *, size_t, uint64_t); size_t ibuf_left(struct ibuf *);
int ibuf_set_n16(struct ibuf *, size_t, uint64_t);
int ibuf_set_n32(struct ibuf *, size_t, uint64_t);
int ibuf_set_n64(struct ibuf *, size_t, uint64_t);
int ibuf_set_h16(struct ibuf *, size_t, uint64_t);
int ibuf_set_h32(struct ibuf *, size_t, uint64_t);
int ibuf_set_h64(struct ibuf *, size_t, uint64_t);
void *ibuf_data(const struct ibuf *);
size_t ibuf_size(const struct ibuf *);
size_t ibuf_left(const struct ibuf *);
int ibuf_truncate(struct ibuf *, size_t);
void ibuf_rewind(struct ibuf *);
void ibuf_close(struct msgbuf *, struct ibuf *); void ibuf_close(struct msgbuf *, struct ibuf *);
void ibuf_from_buffer(struct ibuf *, void *, size_t); int ibuf_write(struct msgbuf *);
void ibuf_from_ibuf(struct ibuf *, const struct ibuf *);
int ibuf_get(struct ibuf *, void *, size_t);
int ibuf_get_ibuf(struct ibuf *, size_t, struct ibuf *);
int ibuf_get_n8(struct ibuf *, uint8_t *);
int ibuf_get_n16(struct ibuf *, uint16_t *);
int ibuf_get_n32(struct ibuf *, uint32_t *);
int ibuf_get_n64(struct ibuf *, uint64_t *);
int ibuf_get_h16(struct ibuf *, uint16_t *);
int ibuf_get_h32(struct ibuf *, uint32_t *);
int ibuf_get_h64(struct ibuf *, uint64_t *);
char *ibuf_get_string(struct ibuf *, size_t);
int ibuf_skip(struct ibuf *, size_t);
void ibuf_free(struct ibuf *); void ibuf_free(struct ibuf *);
int ibuf_fd_avail(struct ibuf *); void msgbuf_init(struct msgbuf *);
int ibuf_fd_get(struct ibuf *);
void ibuf_fd_set(struct ibuf *, int);
struct msgbuf *msgbuf_new(void);
struct msgbuf *msgbuf_new_reader(size_t,
struct ibuf *(*)(struct ibuf *, void *, int *), void *);
void msgbuf_free(struct msgbuf *);
void msgbuf_clear(struct msgbuf *); void msgbuf_clear(struct msgbuf *);
uint32_t msgbuf_queuelen(struct msgbuf *); int msgbuf_write(struct msgbuf *);
int ibuf_write(int, struct msgbuf *); void msgbuf_drain(struct msgbuf *, size_t);
int msgbuf_write(int, struct msgbuf *);
int ibuf_read(int, struct msgbuf *);
int msgbuf_read(int, struct msgbuf *);
struct ibuf *msgbuf_get(struct msgbuf *);
/* imsg.c */ /* imsg.c */
int imsgbuf_init(struct imsgbuf *, int); void imsg_init(struct imsgbuf *, int);
void imsgbuf_allow_fdpass(struct imsgbuf *imsgbuf); ssize_t imsg_read(struct imsgbuf *);
int imsgbuf_set_maxsize(struct imsgbuf *, uint32_t);
int imsgbuf_read(struct imsgbuf *);
int imsgbuf_write(struct imsgbuf *);
int imsgbuf_flush(struct imsgbuf *);
void imsgbuf_clear(struct imsgbuf *);
uint32_t imsgbuf_queuelen(struct imsgbuf *);
ssize_t imsg_get(struct imsgbuf *, struct imsg *); ssize_t imsg_get(struct imsgbuf *, struct imsg *);
int imsg_get_ibuf(struct imsg *, struct ibuf *);
int imsg_get_data(struct imsg *, void *, size_t);
int imsg_get_fd(struct imsg *);
uint32_t imsg_get_id(struct imsg *);
size_t imsg_get_len(struct imsg *);
pid_t imsg_get_pid(struct imsg *);
uint32_t imsg_get_type(struct imsg *);
int imsg_forward(struct imsgbuf *, struct imsg *);
int imsg_compose(struct imsgbuf *, uint32_t, uint32_t, pid_t, int, int imsg_compose(struct imsgbuf *, uint32_t, uint32_t, pid_t, int,
const void *, size_t); const void *, uint16_t);
int imsg_composev(struct imsgbuf *, uint32_t, uint32_t, pid_t, int, int imsg_composev(struct imsgbuf *, uint32_t, uint32_t, pid_t, int,
const struct iovec *, int); const struct iovec *, int);
int imsg_compose_ibuf(struct imsgbuf *, uint32_t, uint32_t, pid_t, struct ibuf *imsg_create(struct imsgbuf *, uint32_t, uint32_t, pid_t, uint16_t);
struct ibuf *); int imsg_add(struct ibuf *, const void *, uint16_t);
struct ibuf *imsg_create(struct imsgbuf *, uint32_t, uint32_t, pid_t, size_t);
int imsg_add(struct ibuf *, const void *, size_t);
void imsg_close(struct imsgbuf *, struct ibuf *); void imsg_close(struct imsgbuf *, struct ibuf *);
void imsg_free(struct imsg *); void imsg_free(struct imsg *);
int imsg_flush(struct imsgbuf *);
void imsg_clear(struct imsgbuf *);
#endif #endif

View File

@ -1,31 +0,0 @@
/*
* Copyright (c) 2024 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 <arpa/inet.h>
#include <sys/types.h>
#include "compat.h"
uint64_t
ntohll(uint64_t v)
{
uint32_t b;
uint32_t t;
b = ntohl (v & 0xffffffff);
t = ntohl (v >> 32);
return ((uint64_t)b << 32 | t);
}

View File

@ -32,8 +32,8 @@
* @(#)queue.h 8.5 (Berkeley) 8/20/94 * @(#)queue.h 8.5 (Berkeley) 8/20/94
*/ */
#ifndef _COMPAT_QUEUE_H_ #ifndef _SYS_QUEUE_H_
#define _COMPAT_QUEUE_H_ #define _SYS_QUEUE_H_
/* /*
* This file defines five types of data structures: singly-linked lists, * This file defines five types of data structures: singly-linked lists,
@ -530,4 +530,4 @@ struct { \
} \ } \
} while (0) } while (0)
#endif /* !_COMPAT_QUEUE_H_ */ #endif /* !_SYS_QUEUE_H_ */

View File

@ -17,7 +17,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "compat.h" #include "compat.h"

View File

@ -19,35 +19,17 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/un.h> #include <sys/un.h>
#include <systemd/sd-bus.h>
#include <systemd/sd-daemon.h> #include <systemd/sd-daemon.h>
#include <systemd/sd-login.h>
#include <systemd/sd-id128.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "tmux.h" #include "tmux.h"
#ifndef SD_ID128_UUID_FORMAT_STR
#define SD_ID128_UUID_FORMAT_STR \
"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x"
#endif
int
systemd_activated(void)
{
return (sd_listen_fds(0) >= 1);
}
int int
systemd_create_socket(int flags, char **cause) systemd_create_socket(int flags, char **cause)
{ {
int fds; int fds;
int fd; int fd;
struct sockaddr_un sa; struct sockaddr_un sa;
socklen_t addrlen = sizeof sa; int addrlen = sizeof sa;
fds = sd_listen_fds(0); fds = sd_listen_fds(0);
if (fds > 1) { /* too many file descriptors */ if (fds > 1) { /* too many file descriptors */
@ -74,253 +56,3 @@ fail:
xasprintf(cause, "systemd socket error (%s)", strerror(errno)); xasprintf(cause, "systemd socket error (%s)", strerror(errno));
return (-1); return (-1);
} }
struct systemd_job_watch {
const char *path;
int done;
};
static int
job_removed_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error)
{
struct systemd_job_watch *watch = userdata;
const char *path = NULL;
uint32_t id;
int r;
/* This handler could be called during the sd_bus_call. */
if (watch->path == NULL)
return 0;
r = sd_bus_message_read(m, "uo", &id, &path);
if (r < 0)
return (r);
if (strcmp(path, watch->path) == 0)
watch->done = 1;
return (0);
}
int
systemd_move_to_new_cgroup(char **cause)
{
sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus_message *m = NULL, *reply = NULL;
sd_bus *bus = NULL;
sd_bus_slot *slot = NULL;
char *name, *desc, *slice;
sd_id128_t uuid;
int r;
uint64_t elapsed_usec;
pid_t pid, parent_pid;
struct timeval start, now;
struct systemd_job_watch watch = {};
gettimeofday(&start, NULL);
/* Connect to the session bus. */
r = sd_bus_default_user(&bus);
if (r < 0) {
xasprintf(cause, "failed to connect to session bus: %s",
strerror(-r));
goto finish;
}
/* Start watching for JobRemoved events */
r = sd_bus_match_signal(bus, &slot,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"JobRemoved",
job_removed_handler,
&watch);
if (r < 0) {
xasprintf(cause, "failed to create match signal: %s",
strerror(-r));
goto finish;
}
/* Start building the method call. */
r = sd_bus_message_new_method_call(bus, &m,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"StartTransientUnit");
if (r < 0) {
xasprintf(cause, "failed to create bus message: %s",
strerror(-r));
goto finish;
}
/* Generate a unique name for the new scope, to avoid collisions. */
r = sd_id128_randomize(&uuid);
if (r < 0) {
xasprintf(cause, "failed to generate uuid: %s", strerror(-r));
goto finish;
}
xasprintf(&name, "tmux-spawn-" SD_ID128_UUID_FORMAT_STR ".scope",
SD_ID128_FORMAT_VAL(uuid));
r = sd_bus_message_append(m, "s", name);
free(name);
if (r < 0) {
xasprintf(cause, "failed to append to bus message: %s",
strerror(-r));
goto finish;
}
/* Mode: fail if there's a queued unit with the same name. */
r = sd_bus_message_append(m, "s", "fail");
if (r < 0) {
xasprintf(cause, "failed to append to bus message: %s",
strerror(-r));
goto finish;
}
/* Start properties array. */
r = sd_bus_message_open_container(m, 'a', "(sv)");
if (r < 0) {
xasprintf(cause, "failed to start properties array: %s",
strerror(-r));
goto finish;
}
pid = getpid();
parent_pid = getppid();
xasprintf(&desc, "tmux child pane %ld launched by process %ld",
(long)pid, (long)parent_pid);
r = sd_bus_message_append(m, "(sv)", "Description", "s", desc);
free(desc);
if (r < 0) {
xasprintf(cause, "failed to append to properties: %s",
strerror(-r));
goto finish;
}
/*
* Make sure that the session shells are terminated with SIGHUP since
* bash and friends tend to ignore SIGTERM.
*/
r = sd_bus_message_append(m, "(sv)", "SendSIGHUP", "b", 1);
if (r < 0) {
xasprintf(cause, "failed to append to properties: %s",
strerror(-r));
goto finish;
}
/*
* Inherit the slice from the parent process, or default to
* "app-tmux.slice" if that fails.
*/
r = sd_pid_get_user_slice(parent_pid, &slice);
if (r < 0) {
slice = xstrdup("app-tmux.slice");
}
r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
free(slice);
if (r < 0) {
xasprintf(cause, "failed to append to properties: %s",
strerror(-r));
goto finish;
}
/* PIDs to add to the scope: length - 1 array of uint32_t. */
r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
if (r < 0) {
xasprintf(cause, "failed to append to properties: %s",
strerror(-r));
goto finish;
}
/* Clean up the scope even if it fails. */
r = sd_bus_message_append(m, "(sv)", "CollectMode", "s",
"inactive-or-failed");
if (r < 0) {
xasprintf(cause, "failed to append to properties: %s",
strerror(-r));
goto finish;
}
/* End properties array. */
r = sd_bus_message_close_container(m);
if (r < 0) {
xasprintf(cause, "failed to end properties array: %s",
strerror(-r));
goto finish;
}
/* aux is currently unused and should be passed an empty array. */
r = sd_bus_message_append(m, "a(sa(sv))", 0);
if (r < 0) {
xasprintf(cause, "failed to append to bus message: %s",
strerror(-r));
goto finish;
}
/* Call the method with a timeout of 1 second = 1e6 us. */
r = sd_bus_call(bus, m, 1000000, &error, &reply);
if (r < 0) {
if (error.message != NULL) {
/* We have a specific error message from sd-bus. */
xasprintf(cause, "StartTransientUnit call failed: %s",
error.message);
} else {
xasprintf(cause, "StartTransientUnit call failed: %s",
strerror(-r));
}
goto finish;
}
/* Get the job (object path) from the reply */
r = sd_bus_message_read(reply, "o", &watch.path);
if (r < 0) {
xasprintf(cause, "failed to parse method reply: %s",
strerror(-r));
goto finish;
}
while (!watch.done) {
/* Process events including callbacks. */
r = sd_bus_process(bus, NULL);
if (r < 0) {
xasprintf(cause,
"failed waiting for cgroup allocation: %s",
strerror(-r));
goto finish;
}
/*
* A positive return means we handled an event and should keep
* processing; zero indicates no events available, so wait.
*/
if (r > 0)
continue;
gettimeofday(&now, NULL);
elapsed_usec = (now.tv_sec - start.tv_sec) * 1000000 +
now.tv_usec - start.tv_usec;
if (elapsed_usec >= 1000000) {
xasprintf(cause,
"timeout waiting for cgroup allocation");
goto finish;
}
r = sd_bus_wait(bus, 1000000 - elapsed_usec);
if (r < 0) {
xasprintf(cause,
"failed waiting for cgroup allocation: %s",
strerror(-r));
goto finish;
}
}
finish:
sd_bus_error_free(&error);
sd_bus_message_unref(m);
sd_bus_message_unref(reply);
sd_bus_slot_unref(slot);
sd_bus_unref(bus);
return (r);
}

View File

@ -1,6 +1,6 @@
# configure.ac # configure.ac
AC_INIT([tmux], next-3.6) AC_INIT([tmux], 3.3a)
AC_PREREQ([2.60]) AC_PREREQ([2.60])
AC_CONFIG_AUX_DIR(etc) AC_CONFIG_AUX_DIR(etc)
@ -44,7 +44,7 @@ fi
# Set up the compiler in two different ways and say yes we may want to install. # Set up the compiler in two different ways and say yes we may want to install.
AC_PROG_CC AC_PROG_CC
AM_PROG_CC_C_O AM_PROG_CC_C_O
m4_version_prereq(2.70, [AC_PROG_CC], [AC_PROG_CC_C99]) AC_PROG_CC_C99
AC_PROG_CPP AC_PROG_CPP
AC_PROG_EGREP AC_PROG_EGREP
AC_PROG_INSTALL AC_PROG_INSTALL
@ -56,11 +56,10 @@ AC_USE_SYSTEM_EXTENSIONS
test "$sysconfdir" = '${prefix}/etc' && sysconfdir=/etc test "$sysconfdir" = '${prefix}/etc' && sysconfdir=/etc
# Is this --enable-debug? # Is this --enable-debug?
case "x$VERSION" in xnext*) enable_debug=yes;; esac
AC_ARG_ENABLE( AC_ARG_ENABLE(
debug, debug,
AS_HELP_STRING(--enable-debug, enable debug build flags), AS_HELP_STRING(--enable-debug, enable debug build flags),
,
[case "x$VERSION" in xnext*) enable_debug=yes;; esac]
) )
AM_CONDITIONAL(IS_DEBUG, test "x$enable_debug" = xyes) AM_CONDITIONAL(IS_DEBUG, test "x$enable_debug" = xyes)
@ -149,7 +148,7 @@ AC_CHECK_FUNCS([ \
prctl \ prctl \
proc_pidinfo \ proc_pidinfo \
getpeerucred \ getpeerucred \
sysconf sysconf \
]) ])
# Check for functions with a compatibility implementation. # Check for functions with a compatibility implementation.
@ -166,9 +165,7 @@ AC_REPLACE_FUNCS([ \
getpeereid \ getpeereid \
getline \ getline \
getprogname \ getprogname \
htonll \
memmem \ memmem \
ntohll \
setenv \ setenv \
setproctitle \ setproctitle \
strcasestr \ strcasestr \
@ -219,7 +216,7 @@ AC_SEARCH_LIBS(clock_gettime, rt)
# musl does not set optarg to NULL for flags without arguments (although it is # 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 # not required to, but it is helpful) 3) there are probably other weird
# implementations. # implementations.
AC_LIBOBJ(getopt_long) AC_LIBOBJ(getopt)
# Look for libevent. Try libevent_core or libevent with pkg-config first then # Look for libevent. Try libevent_core or libevent with pkg-config first then
# look for the library. # look for the library.
@ -270,12 +267,6 @@ if test "x$found_libevent" = xno; then
AC_MSG_ERROR("libevent not found") AC_MSG_ERROR("libevent not found")
fi fi
# Look for yacc.
AC_CHECK_PROG(found_yacc, $YACC, yes, no)
if test "x$found_yacc" = xno; then
AC_MSG_ERROR("yacc not found")
fi
# Look for ncurses or curses. Try pkg-config first then directly for the # Look for ncurses or curses. Try pkg-config first then directly for the
# library. # library.
PKG_CHECK_MODULES( PKG_CHECK_MODULES(
@ -318,7 +309,7 @@ fi
if test "x$found_ncurses" = xno; then if test "x$found_ncurses" = xno; then
AC_SEARCH_LIBS( AC_SEARCH_LIBS(
setupterm, setupterm,
[tinfo terminfo ncurses ncursesw], [tinfo ncurses ncursesw],
found_ncurses=yes, found_ncurses=yes,
found_ncurses=no found_ncurses=no
) )
@ -353,10 +344,6 @@ else
AC_MSG_ERROR("curses not found") AC_MSG_ERROR("curses not found")
fi fi
fi fi
AC_CHECK_FUNCS([ \
tiparm \
tiparm_s \
])
# Look for utempter. # Look for utempter.
AC_ARG_ENABLE( AC_ARG_ENABLE(
@ -386,15 +373,6 @@ AC_ARG_ENABLE(
AS_HELP_STRING(--enable-utf8proc, use utf8proc if it is installed) AS_HELP_STRING(--enable-utf8proc, use utf8proc if it is installed)
) )
if test "x$enable_utf8proc" = xyes; then if test "x$enable_utf8proc" = xyes; then
PKG_CHECK_MODULES(
LIBUTF8PROC,
libutf8proc,
[
AM_CPPFLAGS="$LIBUTF8PROC_CFLAGS $AM_CPPFLAGS"
CPPFLAGS="$LIBUTF8PROC_CFLAGS $SAVED_CPPFLAGS"
LIBS="$LIBUTF8PROC_LIBS $LIBS"
]
)
AC_CHECK_HEADER(utf8proc.h, enable_utf8proc=yes, enable_utf8proc=no) AC_CHECK_HEADER(utf8proc.h, enable_utf8proc=yes, enable_utf8proc=no)
if test "x$enable_utf8proc" = xyes; then if test "x$enable_utf8proc" = xyes; then
AC_SEARCH_LIBS( AC_SEARCH_LIBS(
@ -436,35 +414,10 @@ if test x"$enable_systemd" = xyes; then
fi fi
fi fi
AM_CONDITIONAL(HAVE_SYSTEMD, [test "x$found_systemd" = xyes]) AM_CONDITIONAL(HAVE_SYSTEMD, [test "x$found_systemd" = xyes])
AC_ARG_ENABLE(
cgroups,
AS_HELP_STRING(--disable-cgroups, disable adding panes to new cgroups with systemd)
)
if test "x$enable_cgroups" = x; then
# Default to the same as $enable_systemd.
enable_cgroups=$enable_systemd
fi
if test "x$enable_cgroups" = xyes; then
if test "x$found_systemd" = xyes; then
AC_DEFINE(ENABLE_CGROUPS)
else
AC_MSG_ERROR("cgroups requires systemd to be enabled")
fi
fi
# Enable sixel support.
AC_ARG_ENABLE(
sixel,
AS_HELP_STRING(--enable-sixel, enable sixel images)
)
if test "x$enable_sixel" = xyes; then
AC_DEFINE(ENABLE_SIXEL)
fi
AM_CONDITIONAL(ENABLE_SIXEL, [test "x$enable_sixel" = xyes])
# Check for b64_ntop. If we have b64_ntop, we assume b64_pton as well. # Check for b64_ntop. If we have b64_ntop, we assume b64_pton as well.
AC_MSG_CHECKING(for b64_ntop) AC_MSG_CHECKING(for b64_ntop)
AC_LINK_IFELSE([AC_LANG_PROGRAM( AC_LINK_IFELSE([AC_LANG_PROGRAM(
[ [
#include <sys/types.h> #include <sys/types.h>
#include <netinet/in.h> #include <netinet/in.h>
@ -549,24 +502,6 @@ if test "x$found_malloc_trim" = xyes; then
AC_DEFINE(HAVE_MALLOC_TRIM) AC_DEFINE(HAVE_MALLOC_TRIM)
fi fi
# Build against jemalloc if requested.
AC_ARG_ENABLE(
jemalloc,
AS_HELP_STRING(--enable-jemalloc, use jemalloc if it is installed)
)
if test "x$enable_jemalloc" = xyes; then
PKG_CHECK_MODULES(
JEMALLOC,
jemalloc,
[
AM_CPPFLAGS="$JEMALLOC_CFLAGS $AM_CPPFLAGS"
CPPFLAGS="$AM_CPPFLAGS $SAVED_CPPFLAGS"
LIBS="$LIBS $JEMALLOC_LIBS"
],
AC_MSG_ERROR("jemalloc not found")
)
fi
# Check for CMSG_DATA. On some platforms like HP-UX this requires UNIX 95 # Check for CMSG_DATA. On some platforms like HP-UX this requires UNIX 95
# (_XOPEN_SOURCE and _XOPEN_SOURCE_EXTENDED) (see xopen_networking(7)). On # (_XOPEN_SOURCE and _XOPEN_SOURCE_EXTENDED) (see xopen_networking(7)). On
# others, UNIX 03 (_XOPEN_SOURCE 600, see standards(7) on Solaris). # others, UNIX 03 (_XOPEN_SOURCE 600, see standards(7) on Solaris).
@ -638,9 +573,9 @@ else
AC_LIBOBJ(err) AC_LIBOBJ(err)
fi fi
# Look for imsg_add in libutil. # Look for imsg_init in libutil.
AC_SEARCH_LIBS(imsg_add, util, found_imsg_add=yes, found_imsg_add=no) AC_SEARCH_LIBS(imsg_init, util, found_imsg_init=yes, found_imsg_init=no)
if test "x$found_imsg_add" = xyes; then if test "x$found_imsg_init" = xyes; then
AC_DEFINE(HAVE_IMSG) AC_DEFINE(HAVE_IMSG)
else else
AC_LIBOBJ(imsg) AC_LIBOBJ(imsg)
@ -945,13 +880,8 @@ case "$host_os" in
MANFORMAT=mdoc MANFORMAT=mdoc
;; ;;
*) *)
if test `uname -o 2>/dev/null` = illumos; then # Solaris 2.0 to 11.3 use AT&T nroff.
# Illumos uses mandoc. MANFORMAT=man
MANFORMAT=mdoc
else
# Solaris 2.0 to 11.3 use AT&T nroff.
MANFORMAT=man
fi
;; ;;
esac esac
;; ;;
@ -982,23 +912,9 @@ AM_CONDITIONAL(IS_NETBSD, test "x$PLATFORM" = xnetbsd)
AM_CONDITIONAL(IS_OPENBSD, test "x$PLATFORM" = xopenbsd) AM_CONDITIONAL(IS_OPENBSD, test "x$PLATFORM" = xopenbsd)
AM_CONDITIONAL(IS_SUNOS, test "x$PLATFORM" = xsunos) AM_CONDITIONAL(IS_SUNOS, test "x$PLATFORM" = xsunos)
AM_CONDITIONAL(IS_HPUX, test "x$PLATFORM" = xhpux) AM_CONDITIONAL(IS_HPUX, test "x$PLATFORM" = xhpux)
AM_CONDITIONAL(IS_CYGWIN, test "x$PLATFORM" = xcygwin)
AM_CONDITIONAL(IS_HAIKU, test "x$PLATFORM" = xhaiku) AM_CONDITIONAL(IS_HAIKU, test "x$PLATFORM" = xhaiku)
AM_CONDITIONAL(IS_UNKNOWN, test "x$PLATFORM" = xunknown) AM_CONDITIONAL(IS_UNKNOWN, test "x$PLATFORM" = xunknown)
# Set the default lock command
DEFAULT_LOCK_CMD="lock -np"
AC_MSG_CHECKING(lock-command)
if test "x$PLATFORM" = xlinux; then
AC_CHECK_PROG(found_vlock, vlock, yes, no)
if test "x$found_vlock" = xyes; then
DEFAULT_LOCK_CMD="vlock"
fi
fi
AC_MSG_RESULT($DEFAULT_LOCK_CMD)
AC_SUBST(DEFAULT_LOCK_CMD)
# Save our CFLAGS/CPPFLAGS/LDFLAGS for the Makefile and restore the old user # Save our CFLAGS/CPPFLAGS/LDFLAGS for the Makefile and restore the old user
# variables. # variables.
AC_SUBST(AM_CPPFLAGS) AC_SUBST(AM_CPPFLAGS)

View File

@ -234,29 +234,3 @@ control_notify_session_window_changed(struct session *s)
s->curw->window->id); s->curw->window->id);
} }
} }
void
control_notify_paste_buffer_changed(const char *name)
{
struct client *c;
TAILQ_FOREACH(c, &clients, entry) {
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
continue;
control_write(c, "%%paste-buffer-changed %s", name);
}
}
void
control_notify_paste_buffer_deleted(const char *name)
{
struct client *c;
TAILQ_FOREACH(c, &clients, entry) {
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
continue;
control_write(c, "%%paste-buffer-deleted %s", name);
}
}

View File

@ -775,16 +775,13 @@ control_start(struct client *c)
cs->read_event = bufferevent_new(c->fd, control_read_callback, cs->read_event = bufferevent_new(c->fd, control_read_callback,
control_write_callback, control_error_callback, c); control_write_callback, control_error_callback, c);
if (cs->read_event == NULL) bufferevent_enable(cs->read_event, EV_READ);
fatalx("out of memory");
if (c->flags & CLIENT_CONTROLCONTROL) if (c->flags & CLIENT_CONTROLCONTROL)
cs->write_event = cs->read_event; cs->write_event = cs->read_event;
else { else {
cs->write_event = bufferevent_new(c->out_fd, NULL, cs->write_event = bufferevent_new(c->out_fd, NULL,
control_write_callback, control_error_callback, c); control_write_callback, control_error_callback, c);
if (cs->write_event == NULL)
fatalx("out of memory");
} }
bufferevent_setwatermark(cs->write_event, EV_WRITE, CONTROL_BUFFER_LOW, bufferevent_setwatermark(cs->write_event, EV_WRITE, CONTROL_BUFFER_LOW,
0); 0);
@ -795,13 +792,6 @@ control_start(struct client *c)
} }
} }
/* Control client ready. */
void
control_ready(struct client *c)
{
bufferevent_enable(c->control_state->read_event, EV_READ);
}
/* Discard all output for a client. */ /* Discard all output for a client. */
void void
control_discard(struct client *c) control_discard(struct client *c)

View File

@ -182,11 +182,9 @@ void
environ_update(struct options *oo, struct environ *src, struct environ *dst) environ_update(struct options *oo, struct environ *src, struct environ *dst)
{ {
struct environ_entry *envent; struct environ_entry *envent;
struct environ_entry *envent1;
struct options_entry *o; struct options_entry *o;
struct options_array_item *a; struct options_array_item *a;
union options_value *ov; union options_value *ov;
int found;
o = options_get(oo, "update-environment"); o = options_get(oo, "update-environment");
if (o == NULL) if (o == NULL)
@ -194,15 +192,14 @@ environ_update(struct options *oo, struct environ *src, struct environ *dst)
a = options_array_first(o); a = options_array_first(o);
while (a != NULL) { while (a != NULL) {
ov = options_array_item_value(a); ov = options_array_item_value(a);
found = 0; RB_FOREACH(envent, environ, src) {
RB_FOREACH_SAFE(envent, environ, src, envent1) { if (fnmatch(ov->string, envent->name, 0) == 0)
if (fnmatch(ov->string, envent->name, 0) == 0) { break;
environ_set(dst, envent->name, 0, "%s", envent->value);
found = 1;
}
} }
if (!found) if (envent == NULL)
environ_clear(dst, ov->string); environ_clear(dst, ov->string);
else
environ_set(dst, envent->name, 0, "%s", envent->value);
a = options_array_next(a); a = options_array_next(a);
} }
} }
@ -264,12 +261,6 @@ environ_for_session(struct session *s, int no_TERM)
environ_set(env, "TERM_PROGRAM_VERSION", 0, "%s", getversion()); environ_set(env, "TERM_PROGRAM_VERSION", 0, "%s", getversion());
} }
#ifdef HAVE_SYSTEMD
environ_clear(env, "LISTEN_PID");
environ_clear(env, "LISTEN_FDS");
environ_clear(env, "LISTEN_FDNAMES");
#endif
if (s != NULL) if (s != NULL)
idx = s->id; idx = s->id;
else else

View File

@ -14,7 +14,7 @@ set -g status-bg red
%endif %endif
# Enable RGB colour if running in xterm(1) # Enable RGB colour if running in xterm(1)
set-option -sa terminal-features ",xterm*:RGB" set-option -sa terminal-overrides ",xterm*:Tc"
# Change the default $TERM to tmux-256color # Change the default $TERM to tmux-256color
set -g default-terminal "tmux-256color" set -g default-terminal "tmux-256color"

54
file.c
View File

@ -149,8 +149,7 @@ file_fire_done_cb(__unused int fd, __unused short events, void *arg)
struct client_file *cf = arg; struct client_file *cf = arg;
struct client *c = cf->c; struct client *c = cf->c;
if (cf->cb != NULL && if (cf->cb != NULL && (c == NULL || (~c->flags & CLIENT_DEAD)))
(cf->closed || c == NULL || (~c->flags & CLIENT_DEAD)))
cf->cb(c, cf->path, cf->error, 1, cf->buffer, cf->data); cf->cb(c, cf->path, cf->error, 1, cf->buffer, cf->data);
file_free(cf); file_free(cf);
} }
@ -174,9 +173,9 @@ file_fire_read(struct client_file *cf)
int int
file_can_print(struct client *c) file_can_print(struct client *c)
{ {
if (c == NULL || if (c == NULL)
(c->flags & CLIENT_ATTACHED) || return (0);
(c->flags & CLIENT_CONTROL)) if (c->session != NULL && (~c->flags & CLIENT_CONTROL))
return (0); return (0);
return (1); return (1);
} }
@ -353,7 +352,7 @@ done:
} }
/* Read a file. */ /* Read a file. */
struct client_file * void
file_read(struct client *c, const char *path, client_file_cb cb, void *cbdata) file_read(struct client *c, const char *path, client_file_cb cb, void *cbdata)
{ {
struct client_file *cf; struct client_file *cf;
@ -421,27 +420,10 @@ skip:
goto done; goto done;
} }
free(msg); free(msg);
return cf; return;
done: done:
file_fire_done(cf); file_fire_done(cf);
return NULL;
}
/* Cancel a file read. */
void
file_cancel(struct client_file *cf)
{
struct msg_read_cancel msg;
log_debug("read cancel file %d", cf->stream);
if (cf->closed)
return;
cf->closed = 1;
msg.stream = cf->stream;
proc_send(cf->peer, MSG_READ_CANCEL, -1, &msg, sizeof msg);
} }
/* Push event, fired if there is more writing to be done. */ /* Push event, fired if there is more writing to be done. */
@ -603,8 +585,6 @@ file_write_open(struct client_files *files, struct tmuxpeer *peer,
cf->event = bufferevent_new(cf->fd, NULL, file_write_callback, cf->event = bufferevent_new(cf->fd, NULL, file_write_callback,
file_write_error_callback, cf); file_write_error_callback, cf);
if (cf->event == NULL)
fatalx("out of memory");
bufferevent_enable(cf->event, EV_WRITE); bufferevent_enable(cf->event, EV_WRITE);
goto reply; goto reply;
@ -764,8 +744,6 @@ file_read_open(struct client_files *files, struct tmuxpeer *peer,
cf->event = bufferevent_new(cf->fd, file_read_callback, NULL, cf->event = bufferevent_new(cf->fd, file_read_callback, NULL,
file_read_error_callback, cf); file_read_error_callback, cf);
if (cf->event == NULL)
fatalx("out of memory");
bufferevent_enable(cf->event, EV_READ); bufferevent_enable(cf->event, EV_READ);
return; return;
@ -775,24 +753,6 @@ reply:
proc_send(peer, MSG_READ_DONE, -1, &reply, sizeof reply); proc_send(peer, MSG_READ_DONE, -1, &reply, sizeof reply);
} }
/* Handle a read cancel message (client). */
void
file_read_cancel(struct client_files *files, struct imsg *imsg)
{
struct msg_read_cancel *msg = imsg->data;
size_t msglen = imsg->hdr.len - IMSG_HEADER_SIZE;
struct client_file find, *cf;
if (msglen != sizeof *msg)
fatalx("bad MSG_READ_CANCEL size");
find.stream = msg->stream;
if ((cf = RB_FIND(client_files, files, &find)) == NULL)
fatalx("unknown stream number");
log_debug("cancel file %d", cf->stream);
file_read_error_callback(NULL, 0, cf);
}
/* Handle a write ready message (server). */ /* Handle a write ready message (server). */
void void
file_write_ready(struct client_files *files, struct imsg *imsg) file_write_ready(struct client_files *files, struct imsg *imsg)
@ -830,7 +790,7 @@ file_read_data(struct client_files *files, struct imsg *imsg)
return; return;
log_debug("file %d read %zu bytes", cf->stream, bsize); log_debug("file %d read %zu bytes", cf->stream, bsize);
if (cf->error == 0 && !cf->closed) { if (cf->error == 0) {
if (evbuffer_add(cf->buffer, bdata, bsize) != 0) { if (evbuffer_add(cf->buffer, bdata, bsize) != 0) {
cf->error = ENOMEM; cf->error = ENOMEM;
file_fire_done(cf); file_fire_done(cf);

View File

@ -33,7 +33,6 @@ struct format_range {
enum style_range_type type; enum style_range_type type;
u_int argument; u_int argument;
char string[16];
TAILQ_ENTRY(format_range) entry; TAILQ_ENTRY(format_range) entry;
}; };
@ -45,18 +44,9 @@ format_is_type(struct format_range *fr, struct style *sy)
{ {
if (fr->type != sy->range_type) if (fr->type != sy->range_type)
return (0); return (0);
switch (fr->type) { if (fr->type == STYLE_RANGE_WINDOW &&
case STYLE_RANGE_NONE: fr->argument != sy->range_argument)
case STYLE_RANGE_LEFT: return (0);
case STYLE_RANGE_RIGHT:
return (1);
case STYLE_RANGE_PANE:
case STYLE_RANGE_WINDOW:
case STYLE_RANGE_SESSION:
return (fr->argument == sy->range_argument);
case STYLE_RANGE_USER:
return (strcmp(fr->string, sy->range_string) == 0);
}
return (1); return (1);
} }
@ -719,7 +709,7 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
int focus_start = -1, focus_end = -1; int focus_start = -1, focus_end = -1;
int list_state = -1, fill = -1, even; int list_state = -1, fill = -1, even;
enum style_align list_align = STYLE_ALIGN_DEFAULT; enum style_align list_align = STYLE_ALIGN_DEFAULT;
struct grid_cell gc, current_default, base_default; struct grid_cell gc, current_default;
struct style sy, saved_sy; struct style sy, saved_sy;
struct utf8_data *ud = &sy.gc.data; struct utf8_data *ud = &sy.gc.data;
const char *cp, *end; const char *cp, *end;
@ -729,9 +719,7 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
struct format_ranges frs; struct format_ranges frs;
struct style_range *sr; struct style_range *sr;
memcpy(&base_default, base, sizeof base_default);
memcpy(&current_default, base, sizeof current_default); memcpy(&current_default, base, sizeof current_default);
base = &base_default;
style_set(&sy, &current_default); style_set(&sy, &current_default);
TAILQ_INIT(&frs); TAILQ_INIT(&frs);
log_debug("%s: %s", __func__, expanded); log_debug("%s: %s", __func__, expanded);
@ -849,12 +837,6 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
} else if (sy.default_type == STYLE_DEFAULT_POP) { } else if (sy.default_type == STYLE_DEFAULT_POP) {
memcpy(&current_default, base, sizeof current_default); memcpy(&current_default, base, sizeof current_default);
sy.default_type = STYLE_DEFAULT_BASE; sy.default_type = STYLE_DEFAULT_BASE;
} else if (sy.default_type == STYLE_DEFAULT_SET) {
memcpy(&base_default, &saved_sy.gc,
sizeof base_default);
memcpy(&current_default, &saved_sy.gc,
sizeof current_default);
sy.default_type = STYLE_DEFAULT_BASE;
} }
/* Check the list state. */ /* Check the list state. */
@ -960,8 +942,6 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
fr->type = sy.range_type; fr->type = sy.range_type;
fr->argument = sy.range_argument; fr->argument = sy.range_argument;
strlcpy(fr->string, sy.range_string,
sizeof fr->string);
} }
} }
@ -1033,39 +1013,13 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
sr = xcalloc(1, sizeof *sr); sr = xcalloc(1, sizeof *sr);
sr->type = fr->type; sr->type = fr->type;
sr->argument = fr->argument; sr->argument = fr->argument;
strlcpy(sr->string, fr->string, sizeof sr->string);
sr->start = fr->start; sr->start = fr->start;
sr->end = fr->end; sr->end = fr->end;
TAILQ_INSERT_TAIL(srs, sr, entry); TAILQ_INSERT_TAIL(srs, sr, entry);
switch (sr->type) { log_debug("%s: range %d|%u at %u-%u", __func__, sr->type,
case STYLE_RANGE_NONE: sr->argument, sr->start, sr->end);
break;
case STYLE_RANGE_LEFT:
log_debug("%s: range left at %u-%u", __func__,
sr->start, sr->end);
break;
case STYLE_RANGE_RIGHT:
log_debug("%s: range right at %u-%u", __func__,
sr->start, sr->end);
break;
case STYLE_RANGE_PANE:
log_debug("%s: range pane|%%%u at %u-%u", __func__,
sr->argument, sr->start, sr->end);
break;
case STYLE_RANGE_WINDOW:
log_debug("%s: range window|%u at %u-%u", __func__,
sr->argument, sr->start, sr->end);
break;
case STYLE_RANGE_SESSION:
log_debug("%s: range session|$%u at %u-%u", __func__,
sr->argument, sr->start, sr->end);
break;
case STYLE_RANGE_USER:
log_debug("%s: range user|%u at %u-%u", __func__,
sr->argument, sr->start, sr->end);
break;
}
format_free_range(&frs, fr); format_free_range(&frs, fr);
} }
@ -1129,7 +1083,7 @@ format_trim_left(const char *expanded, u_int limit)
struct utf8_data ud; struct utf8_data ud;
enum utf8_state more; enum utf8_state more;
out = copy = xcalloc(2, strlen(expanded) + 1); out = copy = xcalloc(1, strlen(expanded) + 1);
while (*cp != '\0') { while (*cp != '\0') {
if (width >= limit) if (width >= limit)
break; break;
@ -1196,7 +1150,7 @@ format_trim_right(const char *expanded, u_int limit)
return (xstrdup(expanded)); return (xstrdup(expanded));
skip = total_width - limit; skip = total_width - limit;
out = copy = xcalloc(2, strlen(expanded) + 1); out = copy = xcalloc(1, strlen(expanded) + 1);
while (*cp != '\0') { while (*cp != '\0') {
if (*cp == '#') { if (*cp == '#') {
end = format_leading_hashes(cp, &n, &leading_width); end = format_leading_hashes(cp, &n, &leading_width);

825
format.c

File diff suppressed because it is too large Load Diff

View File

@ -35,7 +35,7 @@ LLVMFuzzerTestOneInput(const u_char *data, size_t size)
int error; int error;
/* /*
* Since AFL doesn't support -max_len parameter we have to * Since AFL doesn't support -max_len paramenter we have to
* discard long inputs manually. * discard long inputs manually.
*/ */
if (size > FUZZER_MAXLEN) if (size > FUZZER_MAXLEN)

View File

@ -180,14 +180,19 @@ grid_reader_handle_wrap(struct grid_reader *gr, u_int *xx, u_int *yy)
int int
grid_reader_in_set(struct grid_reader *gr, const char *set) grid_reader_in_set(struct grid_reader *gr, const char *set)
{ {
return (grid_in_set(gr->gd, gr->cx, gr->cy, set)); struct grid_cell gc;
grid_get_cell(gr->gd, gr->cx, gr->cy, &gc);
if (gc.flags & GRID_FLAG_PADDING)
return (0);
return (utf8_cstrhas(set, &gc.data));
} }
/* Move cursor to the start of the next word. */ /* Move cursor to the start of the next word. */
void void
grid_reader_cursor_next_word(struct grid_reader *gr, const char *separators) grid_reader_cursor_next_word(struct grid_reader *gr, const char *separators)
{ {
u_int xx, yy, width; u_int xx, yy;
/* Do not break up wrapped words. */ /* Do not break up wrapped words. */
if (grid_get_line(gr->gd, gr->cy)->flags & GRID_LINE_WRAPPED) if (grid_get_line(gr->gd, gr->cy)->flags & GRID_LINE_WRAPPED)
@ -224,8 +229,8 @@ grid_reader_cursor_next_word(struct grid_reader *gr, const char *separators)
} }
} }
while (grid_reader_handle_wrap(gr, &xx, &yy) && while (grid_reader_handle_wrap(gr, &xx, &yy) &&
(width = grid_reader_in_set(gr, WHITESPACE))) grid_reader_in_set(gr, WHITESPACE))
gr->cx += width; gr->cx++;
} }
/* Move cursor to the end of the next word. */ /* Move cursor to the end of the next word. */
@ -333,20 +338,6 @@ grid_reader_cursor_previous_word(struct grid_reader *gr, const char *separators,
gr->cy = oldy; gr->cy = oldy;
} }
/* Compare grid cell to UTF-8 data. Return 1 if equal, 0 if not. */
static int
grid_reader_cell_equals_data(const struct grid_cell *gc,
const struct utf8_data *ud)
{
if (gc->flags & GRID_FLAG_PADDING)
return (0);
if (gc->flags & GRID_FLAG_TAB && ud->size == 1 && *ud->data == '\t')
return (1);
if (gc->data.size != ud->size)
return (0);
return (memcmp(gc->data.data, ud->data, gc->data.size) == 0);
}
/* Jump forward to character. */ /* Jump forward to character. */
int int
grid_reader_cursor_jump(struct grid_reader *gr, const struct utf8_data *jc) grid_reader_cursor_jump(struct grid_reader *gr, const struct utf8_data *jc)
@ -361,7 +352,9 @@ grid_reader_cursor_jump(struct grid_reader *gr, const struct utf8_data *jc)
xx = grid_line_length(gr->gd, py); xx = grid_line_length(gr->gd, py);
while (px < xx) { while (px < xx) {
grid_get_cell(gr->gd, px, py, &gc); grid_get_cell(gr->gd, px, py, &gc);
if (grid_reader_cell_equals_data(&gc, jc)) { if (!(gc.flags & GRID_FLAG_PADDING) &&
gc.data.size == jc->size &&
memcmp(gc.data.data, jc->data, gc.data.size) == 0) {
gr->cx = px; gr->cx = px;
gr->cy = py; gr->cy = py;
return (1); return (1);
@ -389,7 +382,9 @@ grid_reader_cursor_jump_back(struct grid_reader *gr, const struct utf8_data *jc)
for (py = gr->cy + 1; py > 0; py--) { for (py = gr->cy + 1; py > 0; py--) {
for (px = xx; px > 0; px--) { for (px = xx; px > 0; px--) {
grid_get_cell(gr->gd, px - 1, py - 1, &gc); grid_get_cell(gr->gd, px - 1, py - 1, &gc);
if (grid_reader_cell_equals_data(&gc, jc)) { if (!(gc.flags & GRID_FLAG_PADDING) &&
gc.data.size == jc->size &&
memcmp(gc.data.data, jc->data, gc.data.size) == 0) {
gr->cx = px - 1; gr->cx = px - 1;
gr->cy = py - 1; gr->cy = py - 1;
return (1); return (1);
@ -420,9 +415,7 @@ grid_reader_cursor_back_to_indentation(struct grid_reader *gr)
xx = grid_line_length(gr->gd, py); xx = grid_line_length(gr->gd, py);
for (px = 0; px < xx; px++) { for (px = 0; px < xx; px++) {
grid_get_cell(gr->gd, px, py, &gc); grid_get_cell(gr->gd, px, py, &gc);
if ((gc.data.size != 1 || *gc.data.data != ' ') && if (gc.data.size != 1 || *gc.data.data != ' ') {
~gc.flags & GRID_FLAG_TAB &&
~gc.flags & GRID_FLAG_PADDING) {
gr->cx = px; gr->cx = px;
gr->cy = py; gr->cy = py;
return; return;

View File

@ -231,5 +231,5 @@ grid_view_string_cells(struct grid *gd, u_int px, u_int py, u_int nx)
px = grid_view_x(gd, px); px = grid_view_x(gd, px);
py = grid_view_y(gd, py); py = grid_view_y(gd, py);
return (grid_string_cells(gd, px, py, nx, NULL, 0, NULL)); return (grid_string_cells(gd, px, py, nx, NULL, 0, 0, 0));
} }

228
grid.c
View File

@ -37,7 +37,7 @@
/* Default grid cell data. */ /* Default grid cell data. */
const struct grid_cell grid_default_cell = { const struct grid_cell grid_default_cell = {
{ { ' ' }, 0, 1, 1 }, 0, 0, 8, 8, 8, 0 { { ' ' }, 0, 1, 1 }, 0, 0, 8, 8, 0
}; };
/* /*
@ -45,15 +45,15 @@ const struct grid_cell grid_default_cell = {
* appears in the grid - because of this, they are always extended cells. * appears in the grid - because of this, they are always extended cells.
*/ */
static const struct grid_cell grid_padding_cell = { static const struct grid_cell grid_padding_cell = {
{ { '!' }, 0, 0, 0 }, 0, GRID_FLAG_PADDING, 8, 8, 8, 0 { { '!' }, 0, 0, 0 }, 0, GRID_FLAG_PADDING, 8, 8, 0
}; };
/* Cleared grid cell data. */ /* Cleared grid cell data. */
static const struct grid_cell grid_cleared_cell = { static const struct grid_cell grid_cleared_cell = {
{ { ' ' }, 0, 1, 1 }, 0, GRID_FLAG_CLEARED, 8, 8, 8, 0 { { ' ' }, 0, 1, 1 }, 0, GRID_FLAG_CLEARED, 8, 8, 0
}; };
static const struct grid_cell_entry grid_cleared_entry = { static const struct grid_cell_entry grid_cleared_entry = {
{ .data = { 0, 8, 8, ' ' } }, GRID_FLAG_CLEARED GRID_FLAG_CLEARED, { .data = { 0, 8, 8, ' ' } }
}; };
/* Store cell in entry. */ /* Store cell in entry. */
@ -84,15 +84,11 @@ grid_need_extended_cell(const struct grid_cell_entry *gce,
return (1); return (1);
if (gc->attr > 0xff) if (gc->attr > 0xff)
return (1); return (1);
if (gc->data.size > 1 || gc->data.width > 1) if (gc->data.size != 1 || gc->data.width != 1)
return (1); return (1);
if ((gc->fg & COLOUR_FLAG_RGB) || (gc->bg & COLOUR_FLAG_RGB)) if ((gc->fg & COLOUR_FLAG_RGB) || (gc->bg & COLOUR_FLAG_RGB))
return (1); return (1);
if (gc->us != 8) /* only supports 256 or RGB */ if (gc->us != 0) /* only supports 256 or RGB */
return (1);
if (gc->link != 0)
return (1);
if (gc->flags & GRID_FLAG_TAB)
return (1); return (1);
return (0); return (0);
} }
@ -126,10 +122,7 @@ grid_extended_cell(struct grid_line *gl, struct grid_cell_entry *gce,
fatalx("offset too big"); fatalx("offset too big");
gl->flags |= GRID_LINE_EXTENDED; gl->flags |= GRID_LINE_EXTENDED;
if (gc->flags & GRID_FLAG_TAB) utf8_from_data(&gc->data, &uc);
uc = gc->data.width;
else
utf8_from_data(&gc->data, &uc);
gee = &gl->extddata[gce->offset]; gee = &gl->extddata[gce->offset];
gee->data = uc; gee->data = uc;
@ -138,7 +131,6 @@ grid_extended_cell(struct grid_line *gl, struct grid_cell_entry *gce,
gee->fg = gc->fg; gee->fg = gc->fg;
gee->bg = gc->bg; gee->bg = gc->bg;
gee->us = gc->us; gee->us = gc->us;
gee->link = gc->link;
return (gee); return (gee);
} }
@ -235,15 +227,9 @@ grid_check_y(struct grid *gd, const char *from, u_int py)
int int
grid_cells_look_equal(const struct grid_cell *gc1, const struct grid_cell *gc2) grid_cells_look_equal(const struct grid_cell *gc1, const struct grid_cell *gc2)
{ {
int flags1 = gc1->flags, flags2 = gc2->flags;;
if (gc1->fg != gc2->fg || gc1->bg != gc2->bg) if (gc1->fg != gc2->fg || gc1->bg != gc2->bg)
return (0); return (0);
if (gc1->attr != gc2->attr) if (gc1->attr != gc2->attr || gc1->flags != gc2->flags)
return (0);
if ((flags1 & ~GRID_FLAG_CLEARED) != (flags2 & ~GRID_FLAG_CLEARED))
return (0);
if (gc1->link != gc2->link)
return (0); return (0);
return (1); return (1);
} }
@ -261,16 +247,6 @@ grid_cells_equal(const struct grid_cell *gc1, const struct grid_cell *gc2)
return (memcmp(gc1->data.data, gc2->data.data, gc1->data.size) == 0); return (memcmp(gc1->data.data, gc2->data.data, gc1->data.size) == 0);
} }
/* Set grid cell to a tab. */
void
grid_set_tab(struct grid_cell *gc, u_int width)
{
memset(gc->data.data, 0, sizeof gc->data.data);
gc->flags |= GRID_FLAG_TAB;
gc->data.width = gc->data.size = gc->data.have = width;
memset(gc->data.data, ' ', gc->data.size);
}
/* Free one line. */ /* Free one line. */
static void static void
grid_free_line(struct grid *gd, u_int py) grid_free_line(struct grid *gd, u_int py)
@ -423,7 +399,6 @@ grid_scroll_history(struct grid *gd, u_int bg)
gd->hscrolled++; gd->hscrolled++;
grid_compact_line(&gd->linedata[gd->hsize]); grid_compact_line(&gd->linedata[gd->hsize]);
gd->linedata[gd->hsize].time = current_time;
gd->hsize++; gd->hsize++;
} }
@ -463,7 +438,6 @@ grid_scroll_history_region(struct grid *gd, u_int upper, u_int lower, u_int bg)
/* Move the line into the history. */ /* Move the line into the history. */
memcpy(gl_history, gl_upper, sizeof *gl_history); memcpy(gl_history, gl_upper, sizeof *gl_history);
gl_history->time = current_time;
/* Then move the region up and clear the bottom line. */ /* Then move the region up and clear the bottom line. */
memmove(gl_upper, gl_upper + 1, (lower - upper) * sizeof *gl_upper); memmove(gl_upper, gl_upper + 1, (lower - upper) * sizeof *gl_upper);
@ -533,12 +507,7 @@ grid_get_cell1(struct grid_line *gl, u_int px, struct grid_cell *gc)
gc->fg = gee->fg; gc->fg = gee->fg;
gc->bg = gee->bg; gc->bg = gee->bg;
gc->us = gee->us; gc->us = gee->us;
gc->link = gee->link; utf8_to_data(gee->data, &gc->data);
if (gc->flags & GRID_FLAG_TAB)
grid_set_tab(gc, gee->data);
else
utf8_to_data(gee->data, &gc->data);
} }
return; return;
} }
@ -551,9 +520,8 @@ grid_get_cell1(struct grid_line *gl, u_int px, struct grid_cell *gc)
gc->bg = gce->data.bg; gc->bg = gce->data.bg;
if (gce->flags & GRID_FLAG_BG256) if (gce->flags & GRID_FLAG_BG256)
gc->bg |= COLOUR_FLAG_256; gc->bg |= COLOUR_FLAG_256;
gc->us = 8; gc->us = 0;
utf8_set(&gc->data, gce->data.data); utf8_set(&gc->data, gce->data.data);
gc->link = 0;
} }
/* Get cell for reading. */ /* Get cell for reading. */
@ -884,60 +852,28 @@ grid_string_cells_us(const struct grid_cell *gc, int *values)
/* Add on SGR code. */ /* Add on SGR code. */
static void static void
grid_string_cells_add_code(char *buf, size_t len, u_int n, int *s, int *newc, grid_string_cells_add_code(char *buf, size_t len, u_int n, int *s, int *newc,
int *oldc, size_t nnewc, size_t noldc, int flags) int *oldc, size_t nnewc, size_t noldc, int escape_c0)
{ {
u_int i; u_int i;
char tmp[64]; char tmp[64];
int reset = (n != 0 && s[0] == 0);
if (nnewc == 0) if (nnewc != 0 &&
return; /* no code to add */ (nnewc != noldc ||
if (!reset && memcmp(newc, oldc, nnewc * sizeof newc[0]) != 0 ||
nnewc == noldc && (n != 0 && s[0] == 0))) {
memcmp(newc, oldc, nnewc * sizeof newc[0]) == 0) if (escape_c0)
return; /* no reset and colour unchanged */ strlcat(buf, "\\033[", len);
if (reset && (newc[0] == 49 || newc[0] == 39))
return; /* reset and colour default */
if (flags & GRID_STRING_ESCAPE_SEQUENCES)
strlcat(buf, "\\033[", len);
else
strlcat(buf, "\033[", len);
for (i = 0; i < nnewc; i++) {
if (i + 1 < nnewc)
xsnprintf(tmp, sizeof tmp, "%d;", newc[i]);
else else
xsnprintf(tmp, sizeof tmp, "%d", newc[i]); strlcat(buf, "\033[", len);
strlcat(buf, tmp, len); for (i = 0; i < nnewc; i++) {
if (i + 1 < nnewc)
xsnprintf(tmp, sizeof tmp, "%d;", newc[i]);
else
xsnprintf(tmp, sizeof tmp, "%d", newc[i]);
strlcat(buf, tmp, len);
}
strlcat(buf, "m", len);
} }
strlcat(buf, "m", len);
}
static int
grid_string_cells_add_hyperlink(char *buf, size_t len, const char *id,
const char *uri, int flags)
{
char *tmp;
if (strlen(uri) + strlen(id) + 17 >= len)
return (0);
if (flags & GRID_STRING_ESCAPE_SEQUENCES)
strlcat(buf, "\\033]8;", len);
else
strlcat(buf, "\033]8;", len);
if (*id != '\0') {
xasprintf(&tmp, "id=%s;", id);
strlcat(buf, tmp, len);
free(tmp);
} else
strlcat(buf, ";", len);
strlcat(buf, uri, len);
if (flags & GRID_STRING_ESCAPE_SEQUENCES)
strlcat(buf, "\\033\\\\", len);
else
strlcat(buf, "\033\\", len);
return (1);
} }
/* /*
@ -946,16 +882,14 @@ grid_string_cells_add_hyperlink(char *buf, size_t len, const char *id,
*/ */
static void static void
grid_string_cells_code(const struct grid_cell *lastgc, grid_string_cells_code(const struct grid_cell *lastgc,
const struct grid_cell *gc, char *buf, size_t len, int flags, const struct grid_cell *gc, char *buf, size_t len, int escape_c0)
struct screen *sc, int *has_link)
{ {
int oldc[64], newc[64], s[128]; int oldc[64], newc[64], s[128];
size_t noldc, nnewc, n, i; size_t noldc, nnewc, n, i;
u_int attr = gc->attr, lastattr = lastgc->attr; u_int attr = gc->attr, lastattr = lastgc->attr;
char tmp[64]; char tmp[64];
const char *uri, *id;
static const struct { struct {
u_int mask; u_int mask;
u_int code; u_int code;
} attrs[] = { } attrs[] = {
@ -979,7 +913,7 @@ grid_string_cells_code(const struct grid_cell *lastgc,
for (i = 0; i < nitems(attrs); i++) { for (i = 0; i < nitems(attrs); i++) {
if (((~attr & attrs[i].mask) && if (((~attr & attrs[i].mask) &&
(lastattr & attrs[i].mask)) || (lastattr & attrs[i].mask)) ||
(lastgc->us != 8 && gc->us == 8)) { (lastgc->us != 0 && gc->us == 0)) {
s[n++] = 0; s[n++] = 0;
lastattr &= GRID_ATTR_CHARSET; lastattr &= GRID_ATTR_CHARSET;
break; break;
@ -994,7 +928,7 @@ grid_string_cells_code(const struct grid_cell *lastgc,
/* Write the attributes. */ /* Write the attributes. */
*buf = '\0'; *buf = '\0';
if (n > 0) { if (n > 0) {
if (flags & GRID_STRING_ESCAPE_SEQUENCES) if (escape_c0)
strlcat(buf, "\\033[", len); strlcat(buf, "\\033[", len);
else else
strlcat(buf, "\033[", len); strlcat(buf, "\033[", len);
@ -1016,59 +950,46 @@ grid_string_cells_code(const struct grid_cell *lastgc,
nnewc = grid_string_cells_fg(gc, newc); nnewc = grid_string_cells_fg(gc, newc);
noldc = grid_string_cells_fg(lastgc, oldc); noldc = grid_string_cells_fg(lastgc, oldc);
grid_string_cells_add_code(buf, len, n, s, newc, oldc, nnewc, noldc, grid_string_cells_add_code(buf, len, n, s, newc, oldc, nnewc, noldc,
flags); escape_c0);
/* If the background colour changed, append its parameters. */ /* If the background colour changed, append its parameters. */
nnewc = grid_string_cells_bg(gc, newc); nnewc = grid_string_cells_bg(gc, newc);
noldc = grid_string_cells_bg(lastgc, oldc); noldc = grid_string_cells_bg(lastgc, oldc);
grid_string_cells_add_code(buf, len, n, s, newc, oldc, nnewc, noldc, grid_string_cells_add_code(buf, len, n, s, newc, oldc, nnewc, noldc,
flags); escape_c0);
/* If the underscore colour changed, append its parameters. */ /* If the underscore colour changed, append its parameters. */
nnewc = grid_string_cells_us(gc, newc); nnewc = grid_string_cells_us(gc, newc);
noldc = grid_string_cells_us(lastgc, oldc); noldc = grid_string_cells_us(lastgc, oldc);
grid_string_cells_add_code(buf, len, n, s, newc, oldc, nnewc, noldc, grid_string_cells_add_code(buf, len, n, s, newc, oldc, nnewc, noldc,
flags); escape_c0);
/* Append shift in/shift out if needed. */ /* Append shift in/shift out if needed. */
if ((attr & GRID_ATTR_CHARSET) && !(lastattr & GRID_ATTR_CHARSET)) { if ((attr & GRID_ATTR_CHARSET) && !(lastattr & GRID_ATTR_CHARSET)) {
if (flags & GRID_STRING_ESCAPE_SEQUENCES) if (escape_c0)
strlcat(buf, "\\016", len); /* SO */ strlcat(buf, "\\016", len); /* SO */
else else
strlcat(buf, "\016", len); /* SO */ strlcat(buf, "\016", len); /* SO */
} }
if (!(attr & GRID_ATTR_CHARSET) && (lastattr & GRID_ATTR_CHARSET)) { if (!(attr & GRID_ATTR_CHARSET) && (lastattr & GRID_ATTR_CHARSET)) {
if (flags & GRID_STRING_ESCAPE_SEQUENCES) if (escape_c0)
strlcat(buf, "\\017", len); /* SI */ strlcat(buf, "\\017", len); /* SI */
else else
strlcat(buf, "\017", len); /* SI */ strlcat(buf, "\017", len); /* SI */
} }
/* Add hyperlink if changed. */
if (sc != NULL && sc->hyperlinks != NULL && lastgc->link != gc->link) {
if (hyperlinks_get(sc->hyperlinks, gc->link, &uri, &id, NULL)) {
*has_link = grid_string_cells_add_hyperlink(buf, len,
id, uri, flags);
} else if (*has_link) {
grid_string_cells_add_hyperlink(buf, len, "", "",
flags);
*has_link = 0;
}
}
} }
/* Convert cells into a string. */ /* Convert cells into a string. */
char * char *
grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx, grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx,
struct grid_cell **lastgc, int flags, struct screen *s) struct grid_cell **lastgc, int with_codes, int escape_c0, int trim)
{ {
struct grid_cell gc; struct grid_cell gc;
static struct grid_cell lastgc1; static struct grid_cell lastgc1;
const char *data; const char *data;
char *buf, code[8192]; char *buf, code[128];
size_t len, off, size, codelen; size_t len, off, size, codelen;
u_int xx, end; u_int xx;
int has_link = 0;
const struct grid_line *gl; const struct grid_line *gl;
if (lastgc != NULL && *lastgc == NULL) { if (lastgc != NULL && *lastgc == NULL) {
@ -1081,37 +1002,26 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx,
off = 0; off = 0;
gl = grid_peek_line(gd, py); gl = grid_peek_line(gd, py);
if (flags & GRID_STRING_EMPTY_CELLS)
end = gl->cellsize;
else
end = gl->cellused;
for (xx = px; xx < px + nx; xx++) { for (xx = px; xx < px + nx; xx++) {
if (gl == NULL || xx >= end) if (gl == NULL || xx >= gl->cellused)
break; break;
grid_get_cell(gd, xx, py, &gc); grid_get_cell(gd, xx, py, &gc);
if (gc.flags & GRID_FLAG_PADDING) if (gc.flags & GRID_FLAG_PADDING)
continue; continue;
if (flags & GRID_STRING_WITH_SEQUENCES) { if (with_codes) {
grid_string_cells_code(*lastgc, &gc, code, sizeof code, grid_string_cells_code(*lastgc, &gc, code, sizeof code,
flags, s, &has_link); escape_c0);
codelen = strlen(code); codelen = strlen(code);
memcpy(*lastgc, &gc, sizeof **lastgc); memcpy(*lastgc, &gc, sizeof **lastgc);
} else } else
codelen = 0; codelen = 0;
if (gc.flags & GRID_FLAG_TAB) { data = gc.data.data;
data = "\t"; size = gc.data.size;
size = 1; if (escape_c0 && size == 1 && *data == '\\') {
} else { data = "\\\\";
data = gc.data.data; size = 2;
size = gc.data.size;
if ((flags & GRID_STRING_ESCAPE_SEQUENCES) &&
size == 1 &&
*data == '\\') {
data = "\\\\";
size = 2;
}
} }
while (len < off + size + codelen + 1) { while (len < off + size + codelen + 1) {
@ -1127,19 +1037,7 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx,
off += size; off += size;
} }
if (has_link) { if (trim) {
grid_string_cells_add_hyperlink(code, sizeof code, "", "",
flags);
codelen = strlen(code);
while (len < off + size + codelen + 1) {
buf = xreallocarray(buf, 2, len);
len *= 2;
}
memcpy(buf + off, code, codelen);
off += codelen;
}
if (flags & GRID_STRING_TRIM_SPACES) {
while (off > 0 && buf[off - 1] == ' ') while (off > 0 && buf[off - 1] == ' ')
off--; off--;
} }
@ -1561,27 +1459,3 @@ grid_line_length(struct grid *gd, u_int py)
} }
return (px); return (px);
} }
/* Check if character is in set. */
int
grid_in_set(struct grid *gd, u_int px, u_int py, const char *set)
{
struct grid_cell gc, tmp_gc;
u_int pxx;
grid_get_cell(gd, px, py, &gc);
if (strchr(set, '\t')) {
if (gc.flags & GRID_FLAG_PADDING) {
pxx = px;
do
grid_get_cell(gd, --pxx, py, &tmp_gc);
while (pxx > 0 && tmp_gc.flags & GRID_FLAG_PADDING);
if (tmp_gc.flags & GRID_FLAG_TAB)
return (tmp_gc.data.width - (px - pxx));
} else if (gc.flags & GRID_FLAG_TAB)
return (gc.data.width);
}
if (gc.flags & GRID_FLAG_PADDING)
return (0);
return (utf8_cstrhas(set, &gc.data));
}

View File

@ -1,239 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2021 Will <author@will.party>
* Copyright (c) 2022 Jeff Chiang <pobomp@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 <stdlib.h>
#include <string.h>
#include "tmux.h"
/*
* OSC 8 hyperlinks, described at:
*
* https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda
*
* Each hyperlink and ID combination is assigned a number ("inner" in this
* file) which is stored in an extended grid cell and maps into a tree here.
*
* Each URI has one inner number and one external ID (which tmux uses to send
* the hyperlink to the terminal) and one internal ID (which is received from
* the sending application inside tmux).
*
* Anonymous hyperlinks are each unique and are not reused even if they have
* the same URI (terminals will not want to tie them together).
*/
#define MAX_HYPERLINKS 5000
static long long hyperlinks_next_external_id = 1;
static u_int global_hyperlinks_count;
struct hyperlinks_uri {
struct hyperlinks *tree;
u_int inner;
const char *internal_id;
const char *external_id;
const char *uri;
TAILQ_ENTRY(hyperlinks_uri) list_entry;
RB_ENTRY(hyperlinks_uri) by_inner_entry;
RB_ENTRY(hyperlinks_uri) by_uri_entry; /* by internal ID and URI */
};
RB_HEAD(hyperlinks_by_uri_tree, hyperlinks_uri);
RB_HEAD(hyperlinks_by_inner_tree, hyperlinks_uri);
TAILQ_HEAD(hyperlinks_list, hyperlinks_uri);
static struct hyperlinks_list global_hyperlinks =
TAILQ_HEAD_INITIALIZER(global_hyperlinks);
struct hyperlinks {
u_int next_inner;
struct hyperlinks_by_inner_tree by_inner;
struct hyperlinks_by_uri_tree by_uri;
u_int references;
};
static int
hyperlinks_by_uri_cmp(struct hyperlinks_uri *left, struct hyperlinks_uri *right)
{
int r;
if (*left->internal_id == '\0' || *right->internal_id == '\0') {
/*
* If both URIs are anonymous, use the inner for comparison so
* that they do not match even if the URI is the same - each
* anonymous URI should be unique.
*/
if (*left->internal_id != '\0')
return (-1);
if (*right->internal_id != '\0')
return (1);
return (left->inner - right->inner);
}
r = strcmp(left->internal_id, right->internal_id);
if (r != 0)
return (r);
return (strcmp(left->uri, right->uri));
}
RB_PROTOTYPE_STATIC(hyperlinks_by_uri_tree, hyperlinks_uri, by_uri_entry,
hyperlinks_by_uri_cmp);
RB_GENERATE_STATIC(hyperlinks_by_uri_tree, hyperlinks_uri, by_uri_entry,
hyperlinks_by_uri_cmp);
static int
hyperlinks_by_inner_cmp(struct hyperlinks_uri *left,
struct hyperlinks_uri *right)
{
return (left->inner - right->inner);
}
RB_PROTOTYPE_STATIC(hyperlinks_by_inner_tree, hyperlinks_uri, by_inner_entry,
hyperlinks_by_inner_cmp);
RB_GENERATE_STATIC(hyperlinks_by_inner_tree, hyperlinks_uri, by_inner_entry,
hyperlinks_by_inner_cmp);
/* Remove a hyperlink. */
static void
hyperlinks_remove(struct hyperlinks_uri *hlu)
{
struct hyperlinks *hl = hlu->tree;
TAILQ_REMOVE(&global_hyperlinks, hlu, list_entry);
global_hyperlinks_count--;
RB_REMOVE(hyperlinks_by_inner_tree, &hl->by_inner, hlu);
RB_REMOVE(hyperlinks_by_uri_tree, &hl->by_uri, hlu);
free((void *)hlu->internal_id);
free((void *)hlu->external_id);
free((void *)hlu->uri);
free(hlu);
}
/* Store a new hyperlink or return if it already exists. */
u_int
hyperlinks_put(struct hyperlinks *hl, const char *uri_in,
const char *internal_id_in)
{
struct hyperlinks_uri find, *hlu;
char *uri, *internal_id, *external_id;
/*
* Anonymous URI are stored with an empty internal ID and the tree
* comparator will make sure they never match each other (so each
* anonymous URI is unique).
*/
if (internal_id_in == NULL)
internal_id_in = "";
utf8_stravis(&uri, uri_in, VIS_OCTAL|VIS_CSTYLE);
utf8_stravis(&internal_id, internal_id_in, VIS_OCTAL|VIS_CSTYLE);
if (*internal_id_in != '\0') {
find.uri = uri;
find.internal_id = internal_id;
hlu = RB_FIND(hyperlinks_by_uri_tree, &hl->by_uri, &find);
if (hlu != NULL) {
free (uri);
free (internal_id);
return (hlu->inner);
}
}
xasprintf(&external_id, "tmux%llX", hyperlinks_next_external_id++);
hlu = xcalloc(1, sizeof *hlu);
hlu->inner = hl->next_inner++;
hlu->internal_id = internal_id;
hlu->external_id = external_id;
hlu->uri = uri;
hlu->tree = hl;
RB_INSERT(hyperlinks_by_uri_tree, &hl->by_uri, hlu);
RB_INSERT(hyperlinks_by_inner_tree, &hl->by_inner, hlu);
TAILQ_INSERT_TAIL(&global_hyperlinks, hlu, list_entry);
if (++global_hyperlinks_count == MAX_HYPERLINKS)
hyperlinks_remove(TAILQ_FIRST(&global_hyperlinks));
return (hlu->inner);
}
/* Get hyperlink by inner number. */
int
hyperlinks_get(struct hyperlinks *hl, u_int inner, const char **uri_out,
const char **internal_id_out, const char **external_id_out)
{
struct hyperlinks_uri find, *hlu;
find.inner = inner;
hlu = RB_FIND(hyperlinks_by_inner_tree, &hl->by_inner, &find);
if (hlu == NULL)
return (0);
if (internal_id_out != NULL)
*internal_id_out = hlu->internal_id;
if (external_id_out != NULL)
*external_id_out = hlu->external_id;
*uri_out = hlu->uri;
return (1);
}
/* Initialize hyperlink set. */
struct hyperlinks *
hyperlinks_init(void)
{
struct hyperlinks *hl;
hl = xcalloc(1, sizeof *hl);
hl->next_inner = 1;
RB_INIT(&hl->by_uri);
RB_INIT(&hl->by_inner);
hl->references = 1;
return (hl);
}
/* Copy hyperlink set. */
struct hyperlinks *
hyperlinks_copy(struct hyperlinks *hl)
{
hl->references++;
return (hl);
}
/* Free all hyperlinks but not the set itself. */
void
hyperlinks_reset(struct hyperlinks *hl)
{
struct hyperlinks_uri *hlu, *hlu1;
RB_FOREACH_SAFE(hlu, hyperlinks_by_inner_tree, &hl->by_inner, hlu1)
hyperlinks_remove(hlu);
}
/* Free hyperlink set. */
void
hyperlinks_free(struct hyperlinks *hl)
{
if (--hl->references == 0) {
hyperlinks_reset(hl);
free(hl);
}
}

View File

@ -1,679 +0,0 @@
/* $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 <stdlib.h>
#include <string.h>
#include "tmux.h"
#define SIXEL_WIDTH_LIMIT 10000
#define SIXEL_HEIGHT_LIMIT 10000
struct sixel_line {
u_int x;
uint16_t *data;
};
struct sixel_image {
u_int x;
u_int y;
u_int xpixel;
u_int ypixel;
u_int set_ra;
u_int ra_x;
u_int ra_y;
u_int *colours;
u_int ncolours;
u_int p2;
u_int dx;
u_int dy;
u_int dc;
struct sixel_line *lines;
};
struct sixel_chunk {
u_int next_x;
u_int next_y;
u_int count;
char pattern;
char next_pattern;
size_t len;
size_t used;
char *data;
};
static int
sixel_parse_expand_lines(struct sixel_image *si, u_int y)
{
if (y <= si->y)
return (0);
if (y > SIXEL_HEIGHT_LIMIT)
return (1);
si->lines = xrecallocarray(si->lines, si->y, y, sizeof *si->lines);
si->y = y;
return (0);
}
static int
sixel_parse_expand_line(struct sixel_image *si, struct sixel_line *sl, u_int x)
{
if (x <= sl->x)
return (0);
if (x > SIXEL_WIDTH_LIMIT)
return (1);
if (x > si->x)
si->x = x;
sl->data = xrecallocarray(sl->data, sl->x, si->x, sizeof *sl->data);
sl->x = si->x;
return (0);
}
static u_int
sixel_get_pixel(struct sixel_image *si, u_int x, u_int y)
{
struct sixel_line *sl;
if (y >= si->y)
return (0);
sl = &si->lines[y];
if (x >= sl->x)
return (0);
return (sl->data[x]);
}
static int
sixel_set_pixel(struct sixel_image *si, u_int x, u_int y, u_int c)
{
struct sixel_line *sl;
if (sixel_parse_expand_lines(si, y + 1) != 0)
return (1);
sl = &si->lines[y];
if (sixel_parse_expand_line(si, sl, x + 1) != 0)
return (1);
sl->data[x] = c;
return (0);
}
static int
sixel_parse_write(struct sixel_image *si, u_int ch)
{
struct sixel_line *sl;
u_int i;
if (sixel_parse_expand_lines(si, si->dy + 6) != 0)
return (1);
sl = &si->lines[si->dy];
for (i = 0; i < 6; i++) {
if (sixel_parse_expand_line(si, sl, si->dx + 1) != 0)
return (1);
if (ch & (1 << i))
sl->data[si->dx] = si->dc;
sl++;
}
return (0);
}
static const char *
sixel_parse_attributes(struct sixel_image *si, const char *cp, const char *end)
{
const char *last;
char *endptr;
u_int x, y;
last = cp;
while (last != end) {
if (*last != ';' && (*last < '0' || *last > '9'))
break;
last++;
}
strtoul(cp, &endptr, 10);
if (endptr == last || *endptr != ';')
return (last);
strtoul(endptr + 1, &endptr, 10);
if (endptr == last)
return (last);
if (*endptr != ';') {
log_debug("%s: missing ;", __func__);
return (NULL);
}
x = strtoul(endptr + 1, &endptr, 10);
if (endptr == last || *endptr != ';') {
log_debug("%s: missing ;", __func__);
return (NULL);
}
if (x > SIXEL_WIDTH_LIMIT) {
log_debug("%s: image is too wide", __func__);
return (NULL);
}
y = strtoul(endptr + 1, &endptr, 10);
if (endptr != last) {
log_debug("%s: extra ;", __func__);
return (NULL);
}
if (y > SIXEL_HEIGHT_LIMIT) {
log_debug("%s: image is too tall", __func__);
return (NULL);
}
si->x = x;
sixel_parse_expand_lines(si, y);
si->set_ra = 1;
si->ra_x = x;
si->ra_y = y;
return (last);
}
static const char *
sixel_parse_colour(struct sixel_image *si, const char *cp, const char *end)
{
const char *last;
char *endptr;
u_int c, type, r, g, b;
last = cp;
while (last != end) {
if (*last != ';' && (*last < '0' || *last > '9'))
break;
last++;
}
c = strtoul(cp, &endptr, 10);
if (c > SIXEL_COLOUR_REGISTERS) {
log_debug("%s: too many colours", __func__);
return (NULL);
}
si->dc = c + 1;
if (endptr == last || *endptr != ';')
return (last);
type = strtoul(endptr + 1, &endptr, 10);
if (endptr == last || *endptr != ';') {
log_debug("%s: missing ;", __func__);
return (NULL);
}
r = strtoul(endptr + 1, &endptr, 10);
if (endptr == last || *endptr != ';') {
log_debug("%s: missing ;", __func__);
return (NULL);
}
g = strtoul(endptr + 1, &endptr, 10);
if (endptr == last || *endptr != ';') {
log_debug("%s: missing ;", __func__);
return (NULL);
}
b = strtoul(endptr + 1, &endptr, 10);
if (endptr != last) {
log_debug("%s: missing ;", __func__);
return (NULL);
}
if (type != 1 && type != 2) {
log_debug("%s: invalid type %d", __func__, type);
return (NULL);
}
if (c + 1 > si->ncolours) {
si->colours = xrecallocarray(si->colours, si->ncolours, c + 1,
sizeof *si->colours);
si->ncolours = c + 1;
}
si->colours[c] = (type << 24) | (r << 16) | (g << 8) | b;
return (last);
}
static const char *
sixel_parse_repeat(struct sixel_image *si, const char *cp, const char *end)
{
const char *last;
char tmp[32], ch;
u_int n = 0, i;
const char *errstr = NULL;
last = cp;
while (last != end) {
if (*last < '0' || *last > '9')
break;
tmp[n++] = *last++;
if (n == (sizeof tmp) - 1) {
log_debug("%s: repeat not terminated", __func__);
return (NULL);
}
}
if (n == 0 || last == end) {
log_debug("%s: repeat not terminated", __func__);
return (NULL);
}
tmp[n] = '\0';
n = strtonum(tmp, 1, SIXEL_WIDTH_LIMIT, &errstr);
if (n == 0 || errstr != NULL) {
log_debug("%s: repeat too wide", __func__);
return (NULL);
}
ch = (*last++) - 0x3f;
for (i = 0; i < n; i++) {
if (sixel_parse_write(si, ch) != 0) {
log_debug("%s: width limit reached", __func__);
return (NULL);
}
si->dx++;
}
return (last);
}
struct sixel_image *
sixel_parse(const char *buf, size_t len, u_int p2, u_int xpixel, u_int ypixel)
{
struct sixel_image *si;
const char *cp = buf, *end = buf + len;
char ch;
if (len == 0 || len == 1 || *cp++ != 'q') {
log_debug("%s: empty image", __func__);
return (NULL);
}
si = xcalloc (1, sizeof *si);
si->xpixel = xpixel;
si->ypixel = ypixel;
si->p2 = p2;
while (cp != end) {
ch = *cp++;
switch (ch) {
case '"':
cp = sixel_parse_attributes(si, cp, end);
if (cp == NULL)
goto bad;
break;
case '#':
cp = sixel_parse_colour(si, cp, end);
if (cp == NULL)
goto bad;
break;
case '!':
cp = sixel_parse_repeat(si, cp, end);
if (cp == NULL)
goto bad;
break;
case '-':
si->dx = 0;
si->dy += 6;
break;
case '$':
si->dx = 0;
break;
default:
if (ch < 0x20)
break;
if (ch < 0x3f || ch > 0x7e)
goto bad;
if (sixel_parse_write(si, ch - 0x3f) != 0) {
log_debug("%s: width limit reached", __func__);
goto bad;
}
si->dx++;
break;
}
}
if (si->x == 0 || si->y == 0)
goto bad;
return (si);
bad:
free(si);
return (NULL);
}
void
sixel_free(struct sixel_image *si)
{
u_int y;
for (y = 0; y < si->y; y++)
free(si->lines[y].data);
free(si->lines);
free(si->colours);
free(si);
}
void
sixel_log(struct sixel_image *si)
{
struct sixel_line *sl;
char s[SIXEL_WIDTH_LIMIT + 1];
u_int i, x, y, cx, cy;
sixel_size_in_cells(si, &cx, &cy);
log_debug("%s: image %ux%u (%ux%u)", __func__, si->x, si->y, cx, cy);
for (i = 0; i < si->ncolours; i++)
log_debug("%s: colour %u is %07x", __func__, i, si->colours[i]);
for (y = 0; y < si->y; y++) {
sl = &si->lines[y];
for (x = 0; x < si->x; x++) {
if (x >= sl->x)
s[x] = '_';
else if (sl->data[x] != 0)
s[x] = '0' + (sl->data[x] - 1) % 10;
else
s[x] = '.';
}
s[x] = '\0';
log_debug("%s: %4u: %s", __func__, y, s);
}
}
void
sixel_size_in_cells(struct sixel_image *si, u_int *x, u_int *y)
{
if ((si->x % si->xpixel) == 0)
*x = (si->x / si->xpixel);
else
*x = 1 + (si->x / si->xpixel);
if ((si->y % si->ypixel) == 0)
*y = (si->y / si->ypixel);
else
*y = 1 + (si->y / si->ypixel);
}
struct sixel_image *
sixel_scale(struct sixel_image *si, u_int xpixel, u_int ypixel, u_int ox,
u_int oy, u_int sx, u_int sy, int colours)
{
struct sixel_image *new;
u_int cx, cy, pox, poy, psx, psy, tsx, tsy, px, py;
u_int x, y, i;
/*
* We want to get the section of the image at ox,oy in image cells and
* map it onto the same size in terminal cells, remembering that we
* can only draw vertical sections of six pixels.
*/
sixel_size_in_cells(si, &cx, &cy);
if (ox >= cx)
return (NULL);
if (oy >= cy)
return (NULL);
if (ox + sx >= cx)
sx = cx - ox;
if (oy + sy >= cy)
sy = cy - oy;
if (xpixel == 0)
xpixel = si->xpixel;
if (ypixel == 0)
ypixel = si->ypixel;
pox = ox * si->xpixel;
poy = oy * si->ypixel;
psx = sx * si->xpixel;
psy = sy * si->ypixel;
tsx = sx * xpixel;
tsy = ((sy * ypixel) / 6) * 6;
new = xcalloc (1, sizeof *si);
new->xpixel = xpixel;
new->ypixel = ypixel;
new->p2 = si->p2;
new->set_ra = si->set_ra;
/* clamp to slice end */
new->ra_x = si->ra_x < psx ? si->ra_x : psx;
new->ra_y = si->ra_y < psy ? si->ra_y : psy;
/* subtract slice origin */
new->ra_x = new->ra_x > pox ? new->ra_x - pox : 0;
new->ra_y = new->ra_y > poy ? new->ra_y - poy : 0;
/* resize */
new->ra_x = new->ra_x * xpixel / si->xpixel;
new->ra_y = new->ra_y * ypixel / si->ypixel;
for (y = 0; y < tsy; y++) {
py = poy + ((double)y * psy / tsy);
for (x = 0; x < tsx; x++) {
px = pox + ((double)x * psx / tsx);
sixel_set_pixel(new, x, y, sixel_get_pixel(si, px, py));
}
}
if (colours) {
new->colours = xmalloc(si->ncolours * sizeof *new->colours);
for (i = 0; i < si->ncolours; i++)
new->colours[i] = si->colours[i];
new->ncolours = si->ncolours;
}
return (new);
}
static void
sixel_print_add(char **buf, size_t *len, size_t *used, const char *s,
size_t slen)
{
if (*used + slen >= *len + 1) {
(*len) *= 2;
*buf = xrealloc(*buf, *len);
}
memcpy(*buf + *used, s, slen);
(*used) += slen;
}
static void
sixel_print_repeat(char **buf, size_t *len, size_t *used, u_int count, char ch)
{
char tmp[16];
size_t tmplen;
if (count == 1)
sixel_print_add(buf, len, used, &ch, 1);
else if (count == 2) {
sixel_print_add(buf, len, used, &ch, 1);
sixel_print_add(buf, len, used, &ch, 1);
} else if (count == 3) {
sixel_print_add(buf, len, used, &ch, 1);
sixel_print_add(buf, len, used, &ch, 1);
sixel_print_add(buf, len, used, &ch, 1);
} else if (count != 0) {
tmplen = xsnprintf(tmp, sizeof tmp, "!%u%c", count, ch);
sixel_print_add(buf, len, used, tmp, tmplen);
}
}
static void
sixel_print_compress_colors(struct sixel_image *si, struct sixel_chunk *chunks,
u_int y, u_int *active, u_int *nactive)
{
u_int i, x, c, dx, colors[6];
struct sixel_chunk *chunk = NULL;
struct sixel_line *sl;
for (x = 0; x < si->x; x++) {
for (i = 0; i < 6; i++) {
colors[i] = 0;
if (y + i < si->y) {
sl = &si->lines[y + i];
if (x < sl->x && sl->data[x] != 0) {
colors[i] = sl->data[x];
c = sl->data[x] - 1;
chunks[c].next_pattern |= 1 << i;
}
}
}
for (i = 0; i < 6; i++) {
if (colors[i] == 0)
continue;
c = colors[i] - 1;
chunk = &chunks[c];
if (chunk->next_x == x + 1)
continue;
if (chunk->next_y < y + 1) {
chunk->next_y = y + 1;
active[(*nactive)++] = c;
}
dx = x - chunk->next_x;
if (chunk->pattern != chunk->next_pattern || dx != 0) {
sixel_print_repeat(&chunk->data, &chunk->len,
&chunk->used, chunk->count,
chunk->pattern + 0x3f);
sixel_print_repeat(&chunk->data, &chunk->len,
&chunk->used, dx, '?');
chunk->pattern = chunk->next_pattern;
chunk->count = 0;
}
chunk->count++;
chunk->next_pattern = 0;
chunk->next_x = x + 1;
}
}
}
char *
sixel_print(struct sixel_image *si, struct sixel_image *map, size_t *size)
{
char *buf, tmp[64];
size_t len, used = 0, tmplen;
u_int *colours, ncolours, i, c, y, *active, nactive;
struct sixel_chunk *chunks, *chunk;
if (map != NULL) {
colours = map->colours;
ncolours = map->ncolours;
} else {
colours = si->colours;
ncolours = si->ncolours;
}
if (ncolours == 0)
return (NULL);
len = 8192;
buf = xmalloc(len);
tmplen = xsnprintf(tmp, sizeof tmp, "\033P0;%uq", si->p2);
sixel_print_add(&buf, &len, &used, tmp, tmplen);
if (si->set_ra) {
tmplen = xsnprintf(tmp, sizeof tmp, "\"1;1;%u;%u", si->ra_x,
si->ra_y);
sixel_print_add(&buf, &len, &used, tmp, tmplen);
}
chunks = xcalloc(ncolours, sizeof *chunks);
active = xcalloc(ncolours, sizeof *active);
for (i = 0; i < ncolours; i++) {
c = colours[i];
tmplen = xsnprintf(tmp, sizeof tmp, "#%u;%u;%u;%u;%u",
i, c >> 24, (c >> 16) & 0xff, (c >> 8) & 0xff, c & 0xff);
sixel_print_add(&buf, &len, &used, tmp, tmplen);
chunk = &chunks[i];
chunk->len = 8;
chunk->data = xmalloc(chunk->len);
}
for (y = 0; y < si->y; y += 6) {
nactive = 0;
sixel_print_compress_colors(si, chunks, y, active, &nactive);
for (i = 0; i < nactive; i++) {
c = active[i];
chunk = &chunks[c];
tmplen = xsnprintf(tmp, sizeof tmp, "#%u", c);
sixel_print_add(&buf, &len, &used, tmp, tmplen);
sixel_print_add(&buf, &len, &used, chunk->data,
chunk->used);
sixel_print_repeat(&buf, &len, &used, chunk->count,
chunk->pattern + 0x3f);
sixel_print_add(&buf, &len, &used, "$", 1);
chunk->used = chunk->next_x = chunk->count = 0;
}
if (buf[used - 1] == '$')
used--;
sixel_print_add(&buf, &len, &used, "-", 1);
}
if (buf[used - 1] == '-')
used--;
sixel_print_add(&buf, &len, &used, "\033\\", 2);
buf[used] = '\0';
if (size != NULL)
*size = used;
for (i = 0; i < ncolours; i++)
free(chunks[i].data);
free(active);
free(chunks);
return (buf);
}
struct screen *
sixel_to_screen(struct sixel_image *si)
{
struct screen *s;
struct screen_write_ctx ctx;
struct grid_cell gc;
u_int x, y, sx, sy;
sixel_size_in_cells(si, &sx, &sy);
s = xmalloc(sizeof *s);
screen_init(s, sx, sy, 0);
memcpy(&gc, &grid_default_cell, sizeof gc);
gc.attr |= (GRID_ATTR_CHARSET|GRID_ATTR_DIM);
utf8_set(&gc.data, '~');
screen_write_start(&ctx, s);
if (sx == 1 || sy == 1) {
for (y = 0; y < sy; y++) {
for (x = 0; x < sx; x++)
grid_view_set_cell(s->grid, x, y, &gc);
}
} else {
screen_write_box(&ctx, sx, sy, BOX_LINES_DEFAULT, NULL, NULL);
for (y = 1; y < sy - 1; y++) {
for (x = 1; x < sx - 1; x++)
grid_view_set_cell(s->grid, x, y, &gc);
}
}
screen_write_stop(&ctx);
return (s);
}

186
image.c
View File

@ -1,186 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2007 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 <stdlib.h>
#include <string.h>
#include "tmux.h"
static struct images all_images = TAILQ_HEAD_INITIALIZER(all_images);
static u_int all_images_count;
static void
image_free(struct image *im)
{
struct screen *s = im->s;
TAILQ_REMOVE(&all_images, im, all_entry);
all_images_count--;
TAILQ_REMOVE(&s->images, im, entry);
sixel_free(im->data);
free(im->fallback);
free(im);
}
int
image_free_all(struct screen *s)
{
struct image *im, *im1;
int redraw = !TAILQ_EMPTY(&s->images);
TAILQ_FOREACH_SAFE(im, &s->images, entry, im1)
image_free(im);
return (redraw);
}
/* Create text placeholder for an image. */
static void
image_fallback(char **ret, u_int sx, u_int sy)
{
char *buf, *label;
u_int py, size, lsize;
/* Allocate first line. */
lsize = xasprintf(&label, "SIXEL IMAGE (%ux%u)\r\n", sx, sy) + 1;
if (sx < lsize - 3)
size = lsize - 1;
else
size = sx + 2;
/* Remaining lines. Every placeholder line has \r\n at the end. */
size += (sx + 2) * (sy - 1) + 1;
*ret = buf = xmalloc(size);
/* Render first line. */
if (sx < lsize - 3) {
memcpy(buf, label, lsize);
buf += lsize - 1;
} else {
memcpy(buf, label, lsize - 3);
buf += lsize - 3;
memset(buf, '+', sx - lsize + 3);
buf += sx - lsize + 3;
snprintf(buf, 3, "\r\n");
buf += 2;
}
/* Remaining lines. */
for (py = 1; py < sy; py++) {
memset(buf, '+', sx);
buf += sx;
snprintf(buf, 3, "\r\n");
buf += 2;
}
free(label);
}
struct image*
image_store(struct screen *s, struct sixel_image *si)
{
struct image *im;
im = xcalloc(1, sizeof *im);
im->s = s;
im->data = si;
im->px = s->cx;
im->py = s->cy;
sixel_size_in_cells(si, &im->sx, &im->sy);
image_fallback(&im->fallback, im->sx, im->sy);
TAILQ_INSERT_TAIL(&s->images, im, entry);
TAILQ_INSERT_TAIL(&all_images, im, all_entry);
if (++all_images_count == 10/*XXX*/)
image_free(TAILQ_FIRST(&all_images));
return (im);
}
int
image_check_line(struct screen *s, u_int py, u_int ny)
{
struct image *im, *im1;
int redraw = 0;
TAILQ_FOREACH_SAFE(im, &s->images, entry, im1) {
if (py + ny > im->py && py < im->py + im->sy) {
image_free(im);
redraw = 1;
}
}
return (redraw);
}
int
image_check_area(struct screen *s, u_int px, u_int py, u_int nx, u_int ny)
{
struct image *im, *im1;
int redraw = 0;
TAILQ_FOREACH_SAFE(im, &s->images, entry, im1) {
if (py + ny <= im->py || py >= im->py + im->sy)
continue;
if (px + nx <= im->px || px >= im->px + im->sx)
continue;
image_free(im);
redraw = 1;
}
return (redraw);
}
int
image_scroll_up(struct screen *s, u_int lines)
{
struct image *im, *im1;
int redraw = 0;
u_int sx, sy;
struct sixel_image *new;
TAILQ_FOREACH_SAFE(im, &s->images, entry, im1) {
if (im->py >= lines) {
im->py -= lines;
redraw = 1;
continue;
}
if (im->py + im->sy <= lines) {
image_free(im);
redraw = 1;
continue;
}
sx = im->sx;
sy = (im->py + im->sy) - lines;
new = sixel_scale(im->data, 0, 0, 0, im->sy - sy, sx, sy, 1);
sixel_free(im->data);
im->data = new;
im->py = 0;
sixel_size_in_cells(im->data, &im->sx, &im->sy);
free(im->fallback);
image_fallback(&im->fallback, im->sx, im->sy);
redraw = 1;
}
return (redraw);
}

View File

@ -53,15 +53,9 @@ static struct input_key_entry input_key_defaults[] = {
{ .key = KEYC_PASTE_START, { .key = KEYC_PASTE_START,
.data = "\033[200~" .data = "\033[200~"
}, },
{ .key = KEYC_PASTE_START|KEYC_IMPLIED_META,
.data = "\033[200~"
},
{ .key = KEYC_PASTE_END, { .key = KEYC_PASTE_END,
.data = "\033[201~" .data = "\033[201~"
}, },
{ .key = KEYC_PASTE_END|KEYC_IMPLIED_META,
.data = "\033[201~"
},
/* Function keys. */ /* Function keys. */
{ .key = KEYC_F1, { .key = KEYC_F1,
@ -312,13 +306,7 @@ static struct input_key_entry input_key_defaults[] = {
}, },
{ .key = KEYC_DC|KEYC_BUILD_MODIFIERS, { .key = KEYC_DC|KEYC_BUILD_MODIFIERS,
.data = "\033[3;_~" .data = "\033[3;_~"
}, }
{ .key = KEYC_REPORT_DARK_THEME,
.data = "\033[?997;1n"
},
{ .key = KEYC_REPORT_LIGHT_THEME,
.data = "\033[?997;2n"
},
}; };
static const key_code input_key_modifiers[] = { static const key_code input_key_modifiers[] = {
0, 0,
@ -424,18 +412,118 @@ input_key_write(const char *from, struct bufferevent *bev, const char *data,
bufferevent_write(bev, data, size); bufferevent_write(bev, data, size);
} }
/* /* Translate a key code into an output key sequence. */
* Encode and write an extended key escape sequence in one of the two int
* possible formats, depending on the configured output mode. input_key(struct screen *s, struct bufferevent *bev, key_code key)
*/
static int
input_key_extended(struct bufferevent *bev, key_code key)
{ {
char tmp[64], modifier; struct input_key_entry *ike;
struct utf8_data ud; key_code justkey, newkey, outkey, modifiers;
wchar_t wc; struct utf8_data ud;
char tmp[64], modifier;
switch (key & KEYC_MASK_MODIFIERS) { /* Mouse keys need a pane. */
if (KEYC_IS_MOUSE(key))
return (0);
/* Literal keys go as themselves (can't be more than eight bits). */
if (key & KEYC_LITERAL) {
ud.data[0] = (u_char)key;
input_key_write(__func__, bev, &ud.data[0], 1);
return (0);
}
/* Is this backspace? */
if ((key & KEYC_MASK_KEY) == KEYC_BSPACE) {
newkey = options_get_number(global_options, "backspace");
if (newkey >= 0x7f)
newkey = '\177';
key = newkey|(key & (KEYC_MASK_MODIFIERS|KEYC_MASK_FLAGS));
}
/*
* If this is a normal 7-bit key, just send it, with a leading escape
* if necessary. If it is a UTF-8 key, split it and send it.
*/
justkey = (key & ~(KEYC_META|KEYC_IMPLIED_META));
if (justkey <= 0x7f) {
if (key & KEYC_META)
input_key_write(__func__, bev, "\033", 1);
ud.data[0] = justkey;
input_key_write(__func__, bev, &ud.data[0], 1);
return (0);
}
if (KEYC_IS_UNICODE(justkey)) {
if (key & KEYC_META)
input_key_write(__func__, bev, "\033", 1);
utf8_to_data(justkey, &ud);
input_key_write(__func__, bev, ud.data, ud.size);
return (0);
}
/*
* Look up in the tree. If not in application keypad or cursor mode,
* remove the flags from the key.
*/
if (~s->mode & MODE_KKEYPAD)
key &= ~KEYC_KEYPAD;
if (~s->mode & MODE_KCURSOR)
key &= ~KEYC_CURSOR;
ike = input_key_get(key);
if (ike == NULL && (key & KEYC_META) && (~key & KEYC_IMPLIED_META))
ike = input_key_get(key & ~KEYC_META);
if (ike == NULL && (key & KEYC_CURSOR))
ike = input_key_get(key & ~KEYC_CURSOR);
if (ike == NULL && (key & KEYC_KEYPAD))
ike = input_key_get(key & ~KEYC_KEYPAD);
if (ike != NULL) {
log_debug("found key 0x%llx: \"%s\"", key, ike->data);
if ((key & KEYC_META) && (~key & KEYC_IMPLIED_META))
input_key_write(__func__, bev, "\033", 1);
input_key_write(__func__, bev, ike->data, strlen(ike->data));
return (0);
}
/* No builtin key sequence; construct an extended key sequence. */
if (~s->mode & MODE_KEXTENDED) {
if ((key & KEYC_MASK_MODIFIERS) != KEYC_CTRL)
goto missing;
justkey = (key & KEYC_MASK_KEY);
switch (justkey) {
case ' ':
case '2':
key = 0|(key & ~KEYC_MASK_KEY);
break;
case '|':
key = 28|(key & ~KEYC_MASK_KEY);
break;
case '6':
key = 30|(key & ~KEYC_MASK_KEY);
break;
case '-':
case '/':
key = 31|(key & ~KEYC_MASK_KEY);
break;
case '?':
key = 127|(key & ~KEYC_MASK_KEY);
break;
default:
if (justkey >= 'A' && justkey <= '_')
key = (justkey - 'A')|(key & ~KEYC_MASK_KEY);
else if (justkey >= 'a' && justkey <= '~')
key = (justkey - 96)|(key & ~KEYC_MASK_KEY);
else
return (0);
break;
}
return (input_key(s, bev, key & ~KEYC_CTRL));
}
outkey = (key & KEYC_MASK_KEY);
modifiers = (key & KEYC_MASK_MODIFIERS);
if (outkey < 32 && outkey != 9 && outkey != 13 && outkey != 27) {
outkey = 64 + outkey;
modifiers |= KEYC_CTRL;
}
switch (modifiers) {
case KEYC_SHIFT: case KEYC_SHIFT:
modifier = '2'; modifier = '2';
break; break;
@ -458,261 +546,17 @@ input_key_extended(struct bufferevent *bev, key_code key)
modifier = '8'; modifier = '8';
break; break;
default: default:
return (-1); goto missing;
} }
xsnprintf(tmp, sizeof tmp, "\033[%llu;%cu", outkey, modifier);
if (KEYC_IS_UNICODE(key)) {
utf8_to_data(key & KEYC_MASK_KEY, &ud);
if (utf8_towc(&ud, &wc) == UTF8_DONE)
key = wc;
else
return (-1);
} else
key &= KEYC_MASK_KEY;
if (options_get_number(global_options, "extended-keys-format") == 1)
xsnprintf(tmp, sizeof tmp, "\033[27;%c;%llu~", modifier, key);
else
xsnprintf(tmp, sizeof tmp, "\033[%llu;%cu", key, modifier);
input_key_write(__func__, bev, tmp, strlen(tmp)); input_key_write(__func__, bev, tmp, strlen(tmp));
return (0); return (0);
}
/*
* Outputs the key in the "standard" mode. This is by far the most
* complicated output mode, with a lot of remapping in order to
* emulate quirks of terminals that today can be only found in museums.
*/
static int
input_key_vt10x(struct bufferevent *bev, key_code key)
{
struct utf8_data ud;
key_code onlykey;
char *p;
static const char *standard_map[2] = {
"1!9(0)=+;:'\",<.>/-8? 2",
"119900=+;;'',,..\x1f\x1f\x7f\x7f\0\0",
};
log_debug("%s: key in %llx", __func__, key);
if (key & KEYC_META)
input_key_write(__func__, bev, "\033", 1);
/*
* There's no way to report modifiers for unicode keys in standard mode
* so lose the modifiers.
*/
if (KEYC_IS_UNICODE(key)) {
utf8_to_data(key, &ud);
input_key_write(__func__, bev, ud.data, ud.size);
return (0);
}
/*
* Prevent TAB, CR and LF from being swallowed by the C0 remapping
* logic.
*/
onlykey = key & KEYC_MASK_KEY;
if (onlykey == '\r' || onlykey == '\n' || onlykey == '\t')
key &= ~KEYC_CTRL;
/*
* Convert keys with Ctrl modifier into corresponding C0 control codes,
* with the exception of *some* keys, which are remapped into printable
* ASCII characters.
*
* There is no special handling for Shift modifier, which is pretty
* much redundant anyway, as no terminal will send <base key>|SHIFT,
* but only <shifted key>|SHIFT.
*/
if (key & KEYC_CTRL) {
p = strchr(standard_map[0], onlykey);
if (p != NULL)
key = standard_map[1][p - standard_map[0]];
else if (onlykey >= '3' && onlykey <= '7')
key = onlykey - '\030';
else if (onlykey >= '@' && onlykey <= '~')
key = onlykey & 0x1f;
else
return (-1);
}
log_debug("%s: key out %llx", __func__, key);
ud.data[0] = key & 0x7f;
input_key_write(__func__, bev, &ud.data[0], 1);
return (0);
}
/* Pick keys that are reported as vt10x keys in modifyOtherKeys=1 mode. */
static int
input_key_mode1(struct bufferevent *bev, key_code key)
{
key_code onlykey;
log_debug("%s: key in %llx", __func__, key);
/* A regular or shifted key + Meta. */
if ((key & (KEYC_CTRL | KEYC_META)) == KEYC_META)
return (input_key_vt10x(bev, key));
/*
* As per
* https://invisible-island.net/xterm/modified-keys-us-pc105.html.
*/
onlykey = key & KEYC_MASK_KEY;
if ((key & KEYC_CTRL) &&
(onlykey == ' ' ||
onlykey == '/' ||
onlykey == '@' ||
onlykey == '^' ||
(onlykey >= '2' && onlykey <= '8') ||
(onlykey >= '@' && onlykey <= '~')))
return (input_key_vt10x(bev, key));
missing:
log_debug("key 0x%llx missing", key);
return (-1); return (-1);
} }
/* Translate a key code into an output key sequence. */
int
input_key(struct screen *s, struct bufferevent *bev, key_code key)
{
struct input_key_entry *ike = NULL;
key_code newkey;
struct utf8_data ud;
/* Mouse keys need a pane. */
if (KEYC_IS_MOUSE(key))
return (0);
/* Literal keys go as themselves (can't be more than eight bits). */
if (key & KEYC_LITERAL) {
ud.data[0] = (u_char)key;
input_key_write(__func__, bev, &ud.data[0], 1);
return (0);
}
/* Is this backspace? */
if ((key & KEYC_MASK_KEY) == KEYC_BSPACE) {
newkey = options_get_number(global_options, "backspace");
log_debug("%s: key 0x%llx is backspace -> 0x%llx", __func__,
key, newkey);
if ((key & KEYC_MASK_MODIFIERS) == 0) {
ud.data[0] = 255;
if ((newkey & KEYC_MASK_MODIFIERS) == 0)
ud.data[0] = newkey;
else if ((newkey & KEYC_MASK_MODIFIERS) == KEYC_CTRL) {
newkey &= KEYC_MASK_KEY;
if (newkey >= 'A' && newkey <= 'Z')
ud.data[0] = newkey - 0x40;
else if (newkey >= 'a' && newkey <= 'z')
ud.data[0] = newkey - 0x60;
}
if (ud.data[0] != 255)
input_key_write(__func__, bev, &ud.data[0], 1);
return (0);
}
key = newkey|(key & (KEYC_MASK_FLAGS|KEYC_MASK_MODIFIERS));
}
/* Is this backtab? */
if ((key & KEYC_MASK_KEY) == KEYC_BTAB) {
if (s->mode & MODE_KEYS_EXTENDED_2) {
/* When in xterm extended mode, remap into S-Tab. */
key = '\011' | (key & ~KEYC_MASK_KEY) | KEYC_SHIFT;
} else {
/* Otherwise clear modifiers. */
key &= ~KEYC_MASK_MODIFIERS;
}
}
/*
* A trivial case, that is a 7-bit key, excluding C0 control characters
* that can't be entered from the keyboard, and no modifiers; or a UTF-8
* key and no modifiers.
*/
if (!(key & ~KEYC_MASK_KEY)) {
if (key == C0_HT ||
key == C0_CR ||
key == C0_ESC ||
(key >= 0x20 && key <= 0x7f)) {
ud.data[0] = key;
input_key_write(__func__, bev, &ud.data[0], 1);
return (0);
}
if (KEYC_IS_UNICODE(key)) {
utf8_to_data(key, &ud);
input_key_write(__func__, bev, ud.data, ud.size);
return (0);
}
}
/*
* Look up the standard VT10x keys in the tree. If not in application
* keypad or cursor mode, remove the respective flags from the key.
*/
if (~s->mode & MODE_KKEYPAD)
key &= ~KEYC_KEYPAD;
if (~s->mode & MODE_KCURSOR)
key &= ~KEYC_CURSOR;
if (ike == NULL)
ike = input_key_get(key);
if (ike == NULL && (key & KEYC_META) && (~key & KEYC_IMPLIED_META))
ike = input_key_get(key & ~KEYC_META);
if (ike == NULL && (key & KEYC_CURSOR))
ike = input_key_get(key & ~KEYC_CURSOR);
if (ike == NULL && (key & KEYC_KEYPAD))
ike = input_key_get(key & ~KEYC_KEYPAD);
if (ike != NULL) {
log_debug("%s: found key 0x%llx: \"%s\"", __func__, key,
ike->data);
if (KEYC_IS_PASTE(key) && (~s->mode & MODE_BRACKETPASTE))
return (0);
if ((key & KEYC_META) && (~key & KEYC_IMPLIED_META))
input_key_write(__func__, bev, "\033", 1);
input_key_write(__func__, bev, ike->data, strlen(ike->data));
return (0);
}
/* Ignore internal function key codes. */
if ((key >= KEYC_BASE && key < KEYC_BASE_END) ||
(key >= KEYC_USER && key < KEYC_USER_END)) {
log_debug("%s: ignoring key 0x%llx", __func__, key);
return (0);
}
/*
* No builtin key sequence; construct an extended key sequence
* depending on the client mode.
*
* If something invalid reaches here, an invalid output may be
* produced. For example Ctrl-Shift-2 is invalid (as there's
* no way to enter it). The correct form is Ctrl-Shift-@, at
* least in US English keyboard layout.
*/
switch (s->mode & EXTENDED_KEY_MODES) {
case MODE_KEYS_EXTENDED_2:
/*
* The simplest mode to handle - *all* modified keys are
* reported in the extended form.
*/
return (input_key_extended(bev, key));
case MODE_KEYS_EXTENDED:
/*
* Some keys are still reported in standard mode, to maintain
* compatibility with applications unaware of extended keys.
*/
if (input_key_mode1(bev, key) == -1)
return (input_key_extended(bev, key));
return (0);
default:
/* The standard mode. */
return (input_key_vt10x(bev, key));
}
}
/* Get mouse event string. */ /* Get mouse event string. */
int int
input_key_get_mouse(struct screen *s, struct mouse_event *m, u_int x, u_int y, input_key_get_mouse(struct screen *s, struct mouse_event *m, u_int x, u_int y,

455
input.c
View File

@ -93,6 +93,7 @@ struct input_ctx {
size_t param_len; size_t param_len;
#define INPUT_BUF_START 32 #define INPUT_BUF_START 32
#define INPUT_BUF_LIMIT 1048576
u_char *input_buf; u_char *input_buf;
size_t input_len; size_t input_len;
size_t input_space; size_t input_space;
@ -108,11 +109,10 @@ struct input_ctx {
int utf8started; int utf8started;
int ch; int ch;
struct utf8_data last; int last;
int flags; int flags;
#define INPUT_DISCARD 0x1 #define INPUT_DISCARD 0x1
#define INPUT_LAST 0x2
const struct input_state *state; const struct input_state *state;
@ -133,9 +133,8 @@ static void printflike(2, 3) input_reply(struct input_ctx *, const char *, ...);
static void input_set_state(struct input_ctx *, static void input_set_state(struct input_ctx *,
const struct input_transition *); const struct input_transition *);
static void input_reset_cell(struct input_ctx *); static void input_reset_cell(struct input_ctx *);
static void input_report_current_theme(struct input_ctx *);
static void input_osc_4(struct input_ctx *, const char *); static void input_osc_4(struct input_ctx *, const char *);
static void input_osc_8(struct input_ctx *, const char *);
static void input_osc_10(struct input_ctx *, const char *); static void input_osc_10(struct input_ctx *, const char *);
static void input_osc_11(struct input_ctx *, const char *); static void input_osc_11(struct input_ctx *, const char *);
static void input_osc_12(struct input_ctx *, const char *); static void input_osc_12(struct input_ctx *, const char *);
@ -144,7 +143,6 @@ static void input_osc_104(struct input_ctx *, const char *);
static void input_osc_110(struct input_ctx *, const char *); static void input_osc_110(struct input_ctx *, const char *);
static void input_osc_111(struct input_ctx *, const char *); static void input_osc_111(struct input_ctx *, const char *);
static void input_osc_112(struct input_ctx *, const char *); static void input_osc_112(struct input_ctx *, const char *);
static void input_osc_133(struct input_ctx *, const char *);
/* Transition entry/exit handlers. */ /* Transition entry/exit handlers. */
static void input_clear(struct input_ctx *); static void input_clear(struct input_ctx *);
@ -169,7 +167,6 @@ static void input_csi_dispatch_rm(struct input_ctx *);
static void input_csi_dispatch_rm_private(struct input_ctx *); static void input_csi_dispatch_rm_private(struct input_ctx *);
static void input_csi_dispatch_sm(struct input_ctx *); static void input_csi_dispatch_sm(struct input_ctx *);
static void input_csi_dispatch_sm_private(struct input_ctx *); static void input_csi_dispatch_sm_private(struct input_ctx *);
static void input_csi_dispatch_sm_graphics(struct input_ctx *);
static void input_csi_dispatch_winops(struct input_ctx *); static void input_csi_dispatch_winops(struct input_ctx *);
static void input_csi_dispatch_sgr_256(struct input_ctx *, int, u_int *); static void input_csi_dispatch_sgr_256(struct input_ctx *, int, u_int *);
static void input_csi_dispatch_sgr_rgb(struct input_ctx *, int, u_int *); static void input_csi_dispatch_sgr_rgb(struct input_ctx *, int, u_int *);
@ -204,7 +201,7 @@ enum input_esc_type {
INPUT_ESC_SCSG0_ON, INPUT_ESC_SCSG0_ON,
INPUT_ESC_SCSG1_OFF, INPUT_ESC_SCSG1_OFF,
INPUT_ESC_SCSG1_ON, INPUT_ESC_SCSG1_ON,
INPUT_ESC_ST INPUT_ESC_ST,
}; };
/* Escape command table. */ /* Escape command table. */
@ -243,7 +240,6 @@ enum input_csi_type {
INPUT_CSI_DECSTBM, INPUT_CSI_DECSTBM,
INPUT_CSI_DL, INPUT_CSI_DL,
INPUT_CSI_DSR, INPUT_CSI_DSR,
INPUT_CSI_DSR_PRIVATE,
INPUT_CSI_ECH, INPUT_CSI_ECH,
INPUT_CSI_ED, INPUT_CSI_ED,
INPUT_CSI_EL, INPUT_CSI_EL,
@ -252,7 +248,6 @@ enum input_csi_type {
INPUT_CSI_IL, INPUT_CSI_IL,
INPUT_CSI_MODOFF, INPUT_CSI_MODOFF,
INPUT_CSI_MODSET, INPUT_CSI_MODSET,
INPUT_CSI_QUERY_PRIVATE,
INPUT_CSI_RCP, INPUT_CSI_RCP,
INPUT_CSI_REP, INPUT_CSI_REP,
INPUT_CSI_RM, INPUT_CSI_RM,
@ -261,13 +256,12 @@ enum input_csi_type {
INPUT_CSI_SD, INPUT_CSI_SD,
INPUT_CSI_SGR, INPUT_CSI_SGR,
INPUT_CSI_SM, INPUT_CSI_SM,
INPUT_CSI_SM_GRAPHICS,
INPUT_CSI_SM_PRIVATE, INPUT_CSI_SM_PRIVATE,
INPUT_CSI_SU, INPUT_CSI_SU,
INPUT_CSI_TBC, INPUT_CSI_TBC,
INPUT_CSI_VPA, INPUT_CSI_VPA,
INPUT_CSI_WINOPS, INPUT_CSI_WINOPS,
INPUT_CSI_XDA INPUT_CSI_XDA,
}; };
/* Control (CSI) command table. */ /* Control (CSI) command table. */
@ -287,7 +281,6 @@ static const struct input_table_entry input_csi_table[] = {
{ 'M', "", INPUT_CSI_DL }, { 'M', "", INPUT_CSI_DL },
{ 'P', "", INPUT_CSI_DCH }, { 'P', "", INPUT_CSI_DCH },
{ 'S', "", INPUT_CSI_SU }, { 'S', "", INPUT_CSI_SU },
{ 'S', "?", INPUT_CSI_SM_GRAPHICS },
{ 'T', "", INPUT_CSI_SD }, { 'T', "", INPUT_CSI_SD },
{ 'X', "", INPUT_CSI_ECH }, { 'X', "", INPUT_CSI_ECH },
{ 'Z', "", INPUT_CSI_CBT }, { 'Z', "", INPUT_CSI_CBT },
@ -306,14 +299,12 @@ static const struct input_table_entry input_csi_table[] = {
{ 'm', ">", INPUT_CSI_MODSET }, { 'm', ">", INPUT_CSI_MODSET },
{ 'n', "", INPUT_CSI_DSR }, { 'n', "", INPUT_CSI_DSR },
{ 'n', ">", INPUT_CSI_MODOFF }, { 'n', ">", INPUT_CSI_MODOFF },
{ 'n', "?", INPUT_CSI_DSR_PRIVATE },
{ 'p', "?$", INPUT_CSI_QUERY_PRIVATE },
{ 'q', " ", INPUT_CSI_DECSCUSR }, { 'q', " ", INPUT_CSI_DECSCUSR },
{ 'q', ">", INPUT_CSI_XDA }, { 'q', ">", INPUT_CSI_XDA },
{ 'r', "", INPUT_CSI_DECSTBM }, { 'r', "", INPUT_CSI_DECSTBM },
{ 's', "", INPUT_CSI_SCP }, { 's', "", INPUT_CSI_SCP },
{ 't', "", INPUT_CSI_WINOPS }, { 't', "", INPUT_CSI_WINOPS },
{ 'u', "", INPUT_CSI_RCP } { 'u', "", INPUT_CSI_RCP },
}; };
/* Input transition. */ /* Input transition. */
@ -732,9 +723,6 @@ static const struct input_transition input_state_consume_st_table[] = {
{ -1, -1, NULL, NULL } { -1, -1, NULL, NULL }
}; };
/* Maximum of bytes allowed to read in a single input. */
static size_t input_buffer_size = INPUT_BUF_DEFAULT_SIZE;
/* Input table compare. */ /* Input table compare. */
static int static int
input_table_compare(const void *key, const void *value) input_table_compare(const void *key, const void *value)
@ -874,6 +862,8 @@ input_reset(struct input_ctx *ictx, int clear)
input_clear(ictx); input_clear(ictx);
ictx->last = -1;
ictx->state = &input_state_ground; ictx->state = &input_state_ground;
ictx->flags = 0; ictx->flags = 0;
} }
@ -980,10 +970,6 @@ input_parse_buffer(struct window_pane *wp, u_char *buf, size_t len)
window_update_activity(wp->window); window_update_activity(wp->window);
wp->flags |= PANE_CHANGED; wp->flags |= PANE_CHANGED;
/* Flag new input while in a mode. */
if (!TAILQ_EMPTY(&wp->modes))
wp->flags |= PANE_UNSEENCHANGES;
/* NULL wp if there is a mode set as don't want to update the tty. */ /* NULL wp if there is a mode set as don't want to update the tty. */
if (TAILQ_EMPTY(&wp->modes)) if (TAILQ_EMPTY(&wp->modes))
screen_write_start_pane(sctx, wp, &wp->base); screen_write_start_pane(sctx, wp, &wp->base);
@ -1099,7 +1085,6 @@ input_reply(struct input_ctx *ictx, const char *fmt, ...)
xvasprintf(&reply, fmt, ap); xvasprintf(&reply, fmt, ap);
va_end(ap); va_end(ap);
log_debug("%s: %s", __func__, reply);
bufferevent_write(bev, reply, strlen(reply)); bufferevent_write(bev, reply, strlen(reply));
free(reply); free(reply);
} }
@ -1151,11 +1136,10 @@ input_print(struct input_ctx *ictx)
ictx->cell.cell.attr |= GRID_ATTR_CHARSET; ictx->cell.cell.attr |= GRID_ATTR_CHARSET;
else else
ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET; ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET;
utf8_set(&ictx->cell.cell.data, ictx->ch); utf8_set(&ictx->cell.cell.data, ictx->ch);
screen_write_collect_add(sctx, &ictx->cell.cell); screen_write_collect_add(sctx, &ictx->cell.cell);
ictx->last = ictx->ch;
utf8_copy(&ictx->last, &ictx->cell.cell.data);
ictx->flags |= INPUT_LAST;
ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET; ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET;
@ -1199,7 +1183,7 @@ input_input(struct input_ctx *ictx)
available = ictx->input_space; available = ictx->input_space;
while (ictx->input_len + 1 >= available) { while (ictx->input_len + 1 >= available) {
available *= 2; available *= 2;
if (available > input_buffer_size) { if (available > INPUT_BUF_LIMIT) {
ictx->flags |= INPUT_DISCARD; ictx->flags |= INPUT_DISCARD;
return (0); return (0);
} }
@ -1219,10 +1203,6 @@ input_c0_dispatch(struct input_ctx *ictx)
struct screen_write_ctx *sctx = &ictx->ctx; struct screen_write_ctx *sctx = &ictx->ctx;
struct window_pane *wp = ictx->wp; struct window_pane *wp = ictx->wp;
struct screen *s = sctx->s; struct screen *s = sctx->s;
struct grid_cell gc, first_gc;
u_int cx = s->cx, line = s->cy + s->grid->hsize;
u_int width;
int has_content = 0;
ictx->utf8started = 0; /* can't be valid UTF-8 */ ictx->utf8started = 0; /* can't be valid UTF-8 */
@ -1244,28 +1224,11 @@ input_c0_dispatch(struct input_ctx *ictx)
break; break;
/* Find the next tab point, or use the last column if none. */ /* Find the next tab point, or use the last column if none. */
grid_get_cell(s->grid, s->cx, line, &first_gc);
do { do {
if (!has_content) { s->cx++;
grid_get_cell(s->grid, cx, line, &gc); if (bit_test(s->tabs, s->cx))
if (gc.data.size != 1 ||
*gc.data.data != ' ' ||
!grid_cells_look_equal(&gc, &first_gc))
has_content = 1;
}
cx++;
if (bit_test(s->tabs, cx))
break; break;
} while (cx < screen_size_x(s) - 1); } while (s->cx < screen_size_x(s) - 1);
width = cx - s->cx;
if (has_content || width > sizeof gc.data.data)
s->cx = cx;
else {
grid_get_cell(s->grid, s->cx, line, &gc);
grid_set_tab(&gc, width);
screen_write_collect_add(sctx, &gc);
}
break; break;
case '\012': /* LF */ case '\012': /* LF */
case '\013': /* VT */ case '\013': /* VT */
@ -1288,7 +1251,7 @@ input_c0_dispatch(struct input_ctx *ictx)
break; break;
} }
ictx->flags &= ~INPUT_LAST; ictx->last = -1;
return (0); return (0);
} }
@ -1364,7 +1327,7 @@ input_esc_dispatch(struct input_ctx *ictx)
break; break;
} }
ictx->flags &= ~INPUT_LAST; ictx->last = -1;
return (0); return (0);
} }
@ -1375,14 +1338,14 @@ input_csi_dispatch(struct input_ctx *ictx)
struct screen_write_ctx *sctx = &ictx->ctx; struct screen_write_ctx *sctx = &ictx->ctx;
struct screen *s = sctx->s; struct screen *s = sctx->s;
struct input_table_entry *entry; struct input_table_entry *entry;
int i, n, m, ek, set; int i, n, m;
u_int cx, bg = ictx->cell.cell.bg; u_int cx, bg = ictx->cell.cell.bg;
if (ictx->flags & INPUT_DISCARD) if (ictx->flags & INPUT_DISCARD)
return (0); return (0);
log_debug("%s: '%c' \"%s\" \"%s\"", __func__, ictx->ch, log_debug("%s: '%c' \"%s\" \"%s\"",
ictx->interm_buf, ictx->param_buf); __func__, ictx->ch, ictx->interm_buf, ictx->param_buf);
if (input_split(ictx) != 0) if (input_split(ictx) != 0)
return (0); return (0);
@ -1433,36 +1396,18 @@ input_csi_dispatch(struct input_ctx *ictx)
break; break;
case INPUT_CSI_MODSET: case INPUT_CSI_MODSET:
n = input_get(ictx, 0, 0, 0); n = input_get(ictx, 0, 0, 0);
if (n != 4)
break;
m = input_get(ictx, 1, 0, 0); m = input_get(ictx, 1, 0, 0);
if (options_get_number(global_options, "extended-keys") == 2)
/*
* Set the extended key reporting mode as per the client
* request, unless "extended-keys" is set to "off".
*/
ek = options_get_number(global_options, "extended-keys");
if (ek == 0)
break; break;
screen_write_mode_clear(sctx, EXTENDED_KEY_MODES); if (n == 0 || (n == 4 && m == 0))
if (m == 2) screen_write_mode_clear(sctx, MODE_KEXTENDED);
screen_write_mode_set(sctx, MODE_KEYS_EXTENDED_2); else if (n == 4 && (m == 1 || m == 2))
else if (m == 1 || ek == 2) screen_write_mode_set(sctx, MODE_KEXTENDED);
screen_write_mode_set(sctx, MODE_KEYS_EXTENDED);
break; break;
case INPUT_CSI_MODOFF: case INPUT_CSI_MODOFF:
n = input_get(ictx, 0, 0, 0); n = input_get(ictx, 0, 0, 0);
if (n != 4) if (n == 4)
break; screen_write_mode_clear(sctx, MODE_KEXTENDED);
/*
* Clear the extended key reporting mode as per the client
* request, unless "extended-keys always" forces into mode 1.
*/
screen_write_mode_clear(sctx,
MODE_KEYS_EXTENDED|MODE_KEYS_EXTENDED_2);
if (options_get_number(global_options, "extended-keys") == 2)
screen_write_mode_set(sctx, MODE_KEYS_EXTENDED);
break; break;
case INPUT_CSI_WINOPS: case INPUT_CSI_WINOPS:
input_csi_dispatch_winops(ictx); input_csi_dispatch_winops(ictx);
@ -1491,11 +1436,7 @@ input_csi_dispatch(struct input_ctx *ictx)
case -1: case -1:
break; break;
case 0: case 0:
#ifdef ENABLE_SIXEL
input_reply(ictx, "\033[?1;2;4c");
#else
input_reply(ictx, "\033[?1;2c"); input_reply(ictx, "\033[?1;2c");
#endif
break; break;
default: default:
log_debug("%s: unknown '%c'", __func__, ictx->ch); log_debug("%s: unknown '%c'", __func__, ictx->ch);
@ -1535,20 +1476,6 @@ input_csi_dispatch(struct input_ctx *ictx)
if (n != -1) if (n != -1)
screen_write_deleteline(sctx, n, bg); screen_write_deleteline(sctx, n, bg);
break; break;
case INPUT_CSI_DSR_PRIVATE:
switch (input_get(ictx, 0, 0, 0)) {
case 996:
input_report_current_theme(ictx);
break;
}
break;
case INPUT_CSI_QUERY_PRIVATE:
switch (input_get(ictx, 0, 0, 0)) {
case 2031:
input_reply(ictx, "\033[?2031;2$y");
break;
}
break;
case INPUT_CSI_DSR: case INPUT_CSI_DSR:
switch (input_get(ictx, 0, 0, 0)) { switch (input_get(ictx, 0, 0, 0)) {
case -1: case -1:
@ -1633,17 +1560,12 @@ input_csi_dispatch(struct input_ctx *ictx)
if (n > m) if (n > m)
n = m; n = m;
if (~ictx->flags & INPUT_LAST) if (ictx->last == -1)
break; break;
ictx->ch = ictx->last;
set = ictx->cell.set == 0 ? ictx->cell.g0set : ictx->cell.g1set;
if (set == 1)
ictx->cell.cell.attr |= GRID_ATTR_CHARSET;
else
ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET;
utf8_copy(&ictx->cell.cell.data, &ictx->last);
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
screen_write_collect_add(sctx, &ictx->cell.cell); input_print(ictx);
break; break;
case INPUT_CSI_RCP: case INPUT_CSI_RCP:
input_restore_state(ictx); input_restore_state(ictx);
@ -1666,9 +1588,6 @@ input_csi_dispatch(struct input_ctx *ictx)
case INPUT_CSI_SM_PRIVATE: case INPUT_CSI_SM_PRIVATE:
input_csi_dispatch_sm_private(ictx); input_csi_dispatch_sm_private(ictx);
break; break;
case INPUT_CSI_SM_GRAPHICS:
input_csi_dispatch_sm_graphics(ictx);
break;
case INPUT_CSI_SU: case INPUT_CSI_SU:
n = input_get(ictx, 0, 1, 1); n = input_get(ictx, 0, 1, 1);
if (n != -1) if (n != -1)
@ -1713,7 +1632,7 @@ input_csi_dispatch(struct input_ctx *ictx)
} }
ictx->flags &= ~INPUT_LAST; ictx->last = -1;
return (0); return (0);
} }
@ -1799,9 +1718,6 @@ input_csi_dispatch_rm_private(struct input_ctx *ictx)
case 2004: case 2004:
screen_write_mode_clear(sctx, MODE_BRACKETPASTE); screen_write_mode_clear(sctx, MODE_BRACKETPASTE);
break; break;
case 2031:
screen_write_mode_clear(sctx, MODE_THEME_UPDATES);
break;
default: default:
log_debug("%s: unknown '%c'", __func__, ictx->ch); log_debug("%s: unknown '%c'", __func__, ictx->ch);
break; break;
@ -1838,6 +1754,7 @@ static void
input_csi_dispatch_sm_private(struct input_ctx *ictx) input_csi_dispatch_sm_private(struct input_ctx *ictx)
{ {
struct screen_write_ctx *sctx = &ictx->ctx; struct screen_write_ctx *sctx = &ictx->ctx;
struct window_pane *wp = ictx->wp;
struct grid_cell *gc = &ictx->cell.cell; struct grid_cell *gc = &ictx->cell.cell;
u_int i; u_int i;
@ -1879,7 +1796,17 @@ input_csi_dispatch_sm_private(struct input_ctx *ictx)
screen_write_mode_set(sctx, MODE_MOUSE_ALL); screen_write_mode_set(sctx, MODE_MOUSE_ALL);
break; break;
case 1004: case 1004:
if (sctx->s->mode & MODE_FOCUSON)
break;
screen_write_mode_set(sctx, MODE_FOCUSON); screen_write_mode_set(sctx, MODE_FOCUSON);
if (wp == NULL)
break;
if (!options_get_number(global_options, "focus-events"))
break;
if (wp->flags & PANE_FOCUSED)
bufferevent_write(wp->event, "\033[I", 3);
else
bufferevent_write(wp->event, "\033[O", 3);
break; break;
case 1005: case 1005:
screen_write_mode_set(sctx, MODE_MOUSE_UTF8); screen_write_mode_set(sctx, MODE_MOUSE_UTF8);
@ -1897,9 +1824,6 @@ input_csi_dispatch_sm_private(struct input_ctx *ictx)
case 2004: case 2004:
screen_write_mode_set(sctx, MODE_BRACKETPASTE); screen_write_mode_set(sctx, MODE_BRACKETPASTE);
break; break;
case 2031:
screen_write_mode_set(sctx, MODE_THEME_UPDATES);
break;
default: default:
log_debug("%s: unknown '%c'", __func__, ictx->ch); log_debug("%s: unknown '%c'", __func__, ictx->ch);
break; break;
@ -1907,26 +1831,6 @@ input_csi_dispatch_sm_private(struct input_ctx *ictx)
} }
} }
/* Handle CSI graphics SM. */
static void
input_csi_dispatch_sm_graphics(__unused struct input_ctx *ictx)
{
#ifdef ENABLE_SIXEL
int n, m, o;
if (ictx->param_list_len > 3)
return;
n = input_get(ictx, 0, 0, 0);
m = input_get(ictx, 1, 0, 0);
o = input_get(ictx, 2, 0, 0);
if (n == 1 && (m == 1 || m == 2 || m == 4))
input_reply(ictx, "\033[?%d;0;%uS", n, SIXEL_COLOUR_REGISTERS);
else
input_reply(ictx, "\033[?%d;3;%dS", n, o);
#endif
}
/* Handle CSI window operations. */ /* Handle CSI window operations. */
static void static void
input_csi_dispatch_winops(struct input_ctx *ictx) input_csi_dispatch_winops(struct input_ctx *ictx)
@ -1934,13 +1838,9 @@ input_csi_dispatch_winops(struct input_ctx *ictx)
struct screen_write_ctx *sctx = &ictx->ctx; struct screen_write_ctx *sctx = &ictx->ctx;
struct screen *s = sctx->s; struct screen *s = sctx->s;
struct window_pane *wp = ictx->wp; struct window_pane *wp = ictx->wp;
struct window *w = NULL;
u_int x = screen_size_x(s), y = screen_size_y(s); u_int x = screen_size_x(s), y = screen_size_y(s);
int n, m; int n, m;
if (wp != NULL)
w = wp->window;
m = 0; m = 0;
while ((n = input_get(ictx, m, 0, -1)) != -1) { while ((n = input_get(ictx, m, 0, -1)) != -1) {
switch (n) { switch (n) {
@ -1951,6 +1851,8 @@ input_csi_dispatch_winops(struct input_ctx *ictx)
case 7: case 7:
case 11: case 11:
case 13: case 13:
case 14:
case 19:
case 20: case 20:
case 21: case 21:
case 24: case 24:
@ -1968,30 +1870,6 @@ input_csi_dispatch_winops(struct input_ctx *ictx)
if (input_get(ictx, m, 0, -1) == -1) if (input_get(ictx, m, 0, -1) == -1)
return; return;
break; break;
case 14:
if (w == NULL)
break;
input_reply(ictx, "\033[4;%u;%ut", y * w->ypixel,
x * w->xpixel);
break;
case 15:
if (w == NULL)
break;
input_reply(ictx, "\033[5;%u;%ut", y * w->ypixel,
x * w->xpixel);
break;
case 16:
if (w == NULL)
break;
input_reply(ictx, "\033[6;%u;%ut", w->ypixel,
w->xpixel);
break;
case 18:
input_reply(ictx, "\033[8;%u;%ut", y, x);
break;
case 19:
input_reply(ictx, "\033[9;%u;%ut", y, x);
break;
case 22: case 22:
m++; m++;
switch (input_get(ictx, m, 0, -1)) { switch (input_get(ictx, m, 0, -1)) {
@ -2014,11 +1892,14 @@ input_csi_dispatch_winops(struct input_ctx *ictx)
if (wp == NULL) if (wp == NULL)
break; break;
notify_pane("pane-title-changed", wp); notify_pane("pane-title-changed", wp);
server_redraw_window_borders(w); server_redraw_window_borders(wp->window);
server_status_window(w); server_status_window(wp->window);
break; break;
} }
break; break;
case 18:
input_reply(ictx, "\033[8;%u;%ut", x, y);
break;
default: default:
log_debug("%s: unknown '%c'", __func__, ictx->ch); log_debug("%s: unknown '%c'", __func__, ictx->ch);
break; break;
@ -2189,7 +2070,7 @@ static void
input_csi_dispatch_sgr(struct input_ctx *ictx) input_csi_dispatch_sgr(struct input_ctx *ictx)
{ {
struct grid_cell *gc = &ictx->cell.cell; struct grid_cell *gc = &ictx->cell.cell;
u_int i, link; u_int i;
int n; int n;
if (ictx->param_list_len == 0) { if (ictx->param_list_len == 0) {
@ -2221,9 +2102,7 @@ input_csi_dispatch_sgr(struct input_ctx *ictx)
switch (n) { switch (n) {
case 0: case 0:
link = gc->link;
memcpy(gc, &grid_default_cell, sizeof *gc); memcpy(gc, &grid_default_cell, sizeof *gc);
gc->link = link;
break; break;
case 1: case 1:
gc->attr |= GRID_ATTR_BRIGHT; gc->attr |= GRID_ATTR_BRIGHT;
@ -2309,7 +2188,7 @@ input_csi_dispatch_sgr(struct input_ctx *ictx)
gc->attr &= ~GRID_ATTR_OVERLINE; gc->attr &= ~GRID_ATTR_OVERLINE;
break; break;
case 59: case 59:
gc->us = 8; gc->us = 0;
break; break;
case 90: case 90:
case 91: case 91:
@ -2354,7 +2233,7 @@ input_enter_dcs(struct input_ctx *ictx)
input_clear(ictx); input_clear(ictx);
input_start_timer(ictx); input_start_timer(ictx);
ictx->flags &= ~INPUT_LAST; ictx->last = -1;
} }
/* DCS terminator (ST) received. */ /* DCS terminator (ST) received. */
@ -2367,44 +2246,17 @@ input_dcs_dispatch(struct input_ctx *ictx)
size_t len = ictx->input_len; size_t len = ictx->input_len;
const char prefix[] = "tmux;"; const char prefix[] = "tmux;";
const u_int prefixlen = (sizeof prefix) - 1; const u_int prefixlen = (sizeof prefix) - 1;
long long allow_passthrough = 0;
#ifdef ENABLE_SIXEL
struct window *w;
struct sixel_image *si;
int p2;
#endif
if (wp == NULL) if (wp == NULL)
return (0); return (0);
if (ictx->flags & INPUT_DISCARD)
if (ictx->flags & INPUT_DISCARD) {
log_debug("%s: %zu bytes (discard)", __func__, len);
return (0); return (0);
} if (!options_get_number(ictx->wp->options, "allow-passthrough"))
#ifdef ENABLE_SIXEL
w = wp->window;
if (buf[0] == 'q' && ictx->interm_len == 0) {
if (input_split(ictx) != 0)
return (0);
p2 = input_get(ictx, 1, 0, 0);
if (p2 == -1)
p2 = 0;
si = sixel_parse(buf, len, p2, w->xpixel, w->ypixel);
if (si != NULL)
screen_write_sixelimage(sctx, si, ictx->cell.cell.bg);
}
#endif
allow_passthrough = options_get_number(wp->options, "allow-passthrough");
if (!allow_passthrough)
return (0); return (0);
log_debug("%s: \"%s\"", __func__, buf); log_debug("%s: \"%s\"", __func__, buf);
if (len >= prefixlen && strncmp(buf, prefix, prefixlen) == 0) { if (len >= prefixlen && strncmp(buf, prefix, prefixlen) == 0)
screen_write_rawstring(sctx, buf + prefixlen, len - prefixlen, screen_write_rawstring(sctx, buf + prefixlen, len - prefixlen);
allow_passthrough == 2);
}
return (0); return (0);
} }
@ -2417,7 +2269,7 @@ input_enter_osc(struct input_ctx *ictx)
input_clear(ictx); input_clear(ictx);
input_start_timer(ictx); input_start_timer(ictx);
ictx->flags &= ~INPUT_LAST; ictx->last = -1;
} }
/* OSC terminator (ST) received. */ /* OSC terminator (ST) received. */
@ -2440,17 +2292,13 @@ input_exit_osc(struct input_ctx *ictx)
option = 0; option = 0;
while (*p >= '0' && *p <= '9') while (*p >= '0' && *p <= '9')
option = option * 10 + *p++ - '0'; option = option * 10 + *p++ - '0';
if (*p != ';' && *p != '\0')
return;
if (*p == ';') if (*p == ';')
p++; p++;
switch (option) { switch (option) {
case 0: case 0:
case 2: case 2:
if (wp != NULL && if (screen_set_title(sctx->s, p) && wp != NULL) {
options_get_number(wp->options, "allow-set-title") &&
screen_set_title(sctx->s, p)) {
notify_pane("pane-title-changed", wp); notify_pane("pane-title-changed", wp);
server_redraw_window_borders(wp->window); server_redraw_window_borders(wp->window);
server_status_window(wp->window); server_status_window(wp->window);
@ -2468,9 +2316,6 @@ input_exit_osc(struct input_ctx *ictx)
} }
} }
break; break;
case 8:
input_osc_8(ictx, p);
break;
case 10: case 10:
input_osc_10(ictx, p); input_osc_10(ictx, p);
break; break;
@ -2495,9 +2340,6 @@ input_exit_osc(struct input_ctx *ictx)
case 112: case 112:
input_osc_112(ictx, p); input_osc_112(ictx, p);
break; break;
case 133:
input_osc_133(ictx, p);
break;
default: default:
log_debug("%s: unknown '%u'", __func__, option); log_debug("%s: unknown '%u'", __func__, option);
break; break;
@ -2512,7 +2354,7 @@ input_enter_apc(struct input_ctx *ictx)
input_clear(ictx); input_clear(ictx);
input_start_timer(ictx); input_start_timer(ictx);
ictx->flags &= ~INPUT_LAST; ictx->last = -1;
} }
/* APC terminator (ST) received. */ /* APC terminator (ST) received. */
@ -2541,7 +2383,7 @@ input_enter_rename(struct input_ctx *ictx)
input_clear(ictx); input_clear(ictx);
input_start_timer(ictx); input_start_timer(ictx);
ictx->flags &= ~INPUT_LAST; ictx->last = -1;
} }
/* Rename terminator (ST) received. */ /* Rename terminator (ST) received. */
@ -2585,7 +2427,7 @@ input_top_bit_set(struct input_ctx *ictx)
struct screen_write_ctx *sctx = &ictx->ctx; struct screen_write_ctx *sctx = &ictx->ctx;
struct utf8_data *ud = &ictx->utf8data; struct utf8_data *ud = &ictx->utf8data;
ictx->flags &= ~INPUT_LAST; ictx->last = -1;
if (!ictx->utf8started) { if (!ictx->utf8started) {
if (utf8_open(ud, ictx->ch) != UTF8_MORE) if (utf8_open(ud, ictx->ch) != UTF8_MORE)
@ -2611,12 +2453,50 @@ input_top_bit_set(struct input_ctx *ictx)
utf8_copy(&ictx->cell.cell.data, ud); utf8_copy(&ictx->cell.cell.data, ud);
screen_write_collect_add(sctx, &ictx->cell.cell); screen_write_collect_add(sctx, &ictx->cell.cell);
utf8_copy(&ictx->last, &ictx->cell.cell.data);
ictx->flags |= INPUT_LAST;
return (0); return (0);
} }
/* Parse colour from OSC. */
static int
input_osc_parse_colour(const char *p)
{
double c, m, y, k = 0;
u_int r, g, b;
size_t len = strlen(p);
int colour = -1;
char *copy;
if ((len == 12 && sscanf(p, "rgb:%02x/%02x/%02x", &r, &g, &b) == 3) ||
(len == 7 && sscanf(p, "#%02x%02x%02x", &r, &g, &b) == 3) ||
sscanf(p, "%d,%d,%d", &r, &g, &b) == 3)
colour = colour_join_rgb(r, g, b);
else if ((len == 18 &&
sscanf(p, "rgb:%04x/%04x/%04x", &r, &g, &b) == 3) ||
(len == 13 && sscanf(p, "#%04x%04x%04x", &r, &g, &b) == 3))
colour = colour_join_rgb(r >> 8, g >> 8, b >> 8);
else if ((sscanf(p, "cmyk:%lf/%lf/%lf/%lf", &c, &m, &y, &k) == 4 ||
sscanf(p, "cmy:%lf/%lf/%lf", &c, &m, &y) == 3) &&
c >= 0 && c <= 1 && m >= 0 && m <= 1 &&
y >= 0 && y <= 1 && k >= 0 && k <= 1) {
colour = colour_join_rgb(
(1 - c) * (1 - k) * 255,
(1 - m) * (1 - k) * 255,
(1 - y) * (1 - k) * 255);
} else {
while (len != 0 && *p == ' ') {
p++;
len--;
}
while (len != 0 && p[len - 1] == ' ')
len--;
copy = xstrndup(p, len);
colour = colour_byname(copy);
free(copy);
}
log_debug("%s: %s = %s", __func__, p, colour_tostring(colour));
return (colour);
}
/* Reply to a colour request. */ /* Reply to a colour request. */
static void static void
input_osc_colour_reply(struct input_ctx *ictx, u_int n, int c) input_osc_colour_reply(struct input_ctx *ictx, u_int n, int c)
@ -2665,7 +2545,7 @@ input_osc_4(struct input_ctx *ictx, const char *p)
input_osc_colour_reply(ictx, 4, c); input_osc_colour_reply(ictx, 4, c);
continue; continue;
} }
if ((c = colour_parseX11(s)) == -1) { if ((c = input_osc_parse_colour(s)) == -1) {
s = next; s = next;
continue; continue;
} }
@ -2680,48 +2560,6 @@ input_osc_4(struct input_ctx *ictx, const char *p)
free(copy); free(copy);
} }
/* Handle the OSC 8 sequence for embedding hyperlinks. */
static void
input_osc_8(struct input_ctx *ictx, const char *p)
{
struct hyperlinks *hl = ictx->ctx.s->hyperlinks;
struct grid_cell *gc = &ictx->cell.cell;
const char *start, *end, *uri;
char *id = NULL;
for (start = p; (end = strpbrk(start, ":;")) != NULL; start = end + 1) {
if (end - start >= 4 && strncmp(start, "id=", 3) == 0) {
if (id != NULL)
goto bad;
id = xstrndup(start + 3, end - start - 3);
}
/* The first ; is the end of parameters and start of the URI. */
if (*end == ';')
break;
}
if (end == NULL || *end != ';')
goto bad;
uri = end + 1;
if (*uri == '\0') {
gc->link = 0;
free(id);
return;
}
gc->link = hyperlinks_put(hl, uri, id);
if (id == NULL)
log_debug("hyperlink (anonymous) %s = %u", uri, gc->link);
else
log_debug("hyperlink (id=%s) %s = %u", id, uri, gc->link);
free(id);
return;
bad:
log_debug("bad OSC 8 %s", p);
free(id);
}
/* Handle the OSC 10 sequence for setting and querying foreground colour. */ /* Handle the OSC 10 sequence for setting and querying foreground colour. */
static void static void
input_osc_10(struct input_ctx *ictx, const char *p) input_osc_10(struct input_ctx *ictx, const char *p)
@ -2731,21 +2569,14 @@ input_osc_10(struct input_ctx *ictx, const char *p)
int c; int c;
if (strcmp(p, "?") == 0) { if (strcmp(p, "?") == 0) {
if (wp == NULL) if (wp != NULL) {
return;
c = window_pane_get_fg_control_client(wp);
if (c == -1) {
tty_default_colours(&defaults, wp); tty_default_colours(&defaults, wp);
if (COLOUR_DEFAULT(defaults.fg)) input_osc_colour_reply(ictx, 10, defaults.fg);
c = window_pane_get_fg(wp);
else
c = defaults.fg;
} }
input_osc_colour_reply(ictx, 10, c);
return; return;
} }
if ((c = colour_parseX11(p)) == -1) { if ((c = input_osc_parse_colour(p)) == -1) {
log_debug("bad OSC 10: %s", p); log_debug("bad OSC 10: %s", p);
return; return;
} }
@ -2778,24 +2609,25 @@ static void
input_osc_11(struct input_ctx *ictx, const char *p) input_osc_11(struct input_ctx *ictx, const char *p)
{ {
struct window_pane *wp = ictx->wp; struct window_pane *wp = ictx->wp;
struct grid_cell defaults;
int c; int c;
if (strcmp(p, "?") == 0) { if (strcmp(p, "?") == 0) {
if (wp == NULL) if (wp != NULL) {
return; tty_default_colours(&defaults, wp);
c = window_pane_get_bg(wp); input_osc_colour_reply(ictx, 11, defaults.bg);
input_osc_colour_reply(ictx, 11, c); }
return; return;
} }
if ((c = colour_parseX11(p)) == -1) { if ((c = input_osc_parse_colour(p)) == -1) {
log_debug("bad OSC 11: %s", p); log_debug("bad OSC 11: %s", p);
return; return;
} }
if (ictx->palette != NULL) { if (ictx->palette != NULL) {
ictx->palette->bg = c; ictx->palette->bg = c;
if (wp != NULL) if (wp != NULL)
wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED); wp->flags |= PANE_STYLECHANGED;
screen_write_fullredraw(&ictx->ctx); screen_write_fullredraw(&ictx->ctx);
} }
} }
@ -2811,7 +2643,7 @@ input_osc_111(struct input_ctx *ictx, const char *p)
if (ictx->palette != NULL) { if (ictx->palette != NULL) {
ictx->palette->bg = 8; ictx->palette->bg = 8;
if (wp != NULL) if (wp != NULL)
wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED); wp->flags |= PANE_STYLECHANGED;
screen_write_fullredraw(&ictx->ctx); screen_write_fullredraw(&ictx->ctx);
} }
} }
@ -2833,7 +2665,7 @@ input_osc_12(struct input_ctx *ictx, const char *p)
return; return;
} }
if ((c = colour_parseX11(p)) == -1) { if ((c = input_osc_parse_colour(p)) == -1) {
log_debug("bad OSC 12: %s", p); log_debug("bad OSC 12: %s", p);
return; return;
} }
@ -2848,27 +2680,6 @@ input_osc_112(struct input_ctx *ictx, const char *p)
screen_set_cursor_colour(ictx->ctx.s, -1); screen_set_cursor_colour(ictx->ctx.s, -1);
} }
/* Handle the OSC 133 sequence. */
static void
input_osc_133(struct input_ctx *ictx, const char *p)
{
struct grid *gd = ictx->ctx.s->grid;
u_int line = ictx->ctx.s->cy + gd->hsize;
struct grid_line *gl;
if (line > gd->hsize + gd->sy - 1)
return;
gl = grid_get_line(gd, line);
switch (*p) {
case 'A':
gl->flags |= GRID_LINE_START_PROMPT;
break;
case 'C':
gl->flags |= GRID_LINE_START_OUTPUT;
break;
}
}
/* Handle the OSC 52 sequence for setting the clipboard. */ /* Handle the OSC 52 sequence for setting the clipboard. */
static void static void
@ -2882,9 +2693,6 @@ input_osc_52(struct input_ctx *ictx, const char *p)
int outlen, state; int outlen, state;
struct screen_write_ctx ctx; struct screen_write_ctx ctx;
struct paste_buffer *pb; struct paste_buffer *pb;
const char* allow = "cpqs01234567";
char flags[sizeof "cpqs01234567"] = "";
u_int i, j = 0;
if (wp == NULL) if (wp == NULL)
return; return;
@ -2899,12 +2707,6 @@ input_osc_52(struct input_ctx *ictx, const char *p)
return; return;
log_debug("%s: %s", __func__, end); log_debug("%s: %s", __func__, end);
for (i = 0; p + i != end; i++) {
if (strchr(allow, p[i]) != NULL && strchr(flags, p[i]) == NULL)
flags[j++] = p[i];
}
log_debug("%s: %.*s %s", __func__, (int)(end - p - 1), p, flags);
if (strcmp(end, "?") == 0) { if (strcmp(end, "?") == 0) {
if ((pb = paste_get_top(NULL)) != NULL) if ((pb = paste_get_top(NULL)) != NULL)
buf = paste_buffer_data(pb, &len); buf = paste_buffer_data(pb, &len);
@ -2926,7 +2728,7 @@ input_osc_52(struct input_ctx *ictx, const char *p)
} }
screen_write_start_pane(&ctx, wp, NULL); screen_write_start_pane(&ctx, wp, NULL);
screen_write_setselection(&ctx, flags, out, outlen); screen_write_setselection(&ctx, out, outlen);
screen_write_stop(&ctx); screen_write_stop(&ctx);
notify_pane("pane-set-clipboard", wp); notify_pane("pane-set-clipboard", wp);
@ -2975,11 +2777,9 @@ input_reply_clipboard(struct bufferevent *bev, const char *buf, size_t len,
const char *end) const char *end)
{ {
char *out = NULL; char *out = NULL;
int outlen = 0; size_t outlen = 0;
if (buf != NULL && len != 0) { if (buf != NULL && len != 0) {
if (len >= ((size_t)INT_MAX * 3 / 4) - 1)
return;
outlen = 4 * ((len + 2) / 3) + 1; outlen = 4 * ((len + 2) / 3) + 1;
out = xmalloc(outlen); out = xmalloc(outlen);
if ((outlen = b64_ntop(buf, len, out, outlen)) == -1) { if ((outlen = b64_ntop(buf, len, out, outlen)) == -1) {
@ -2994,26 +2794,3 @@ input_reply_clipboard(struct bufferevent *bev, const char *buf, size_t len,
bufferevent_write(bev, end, strlen(end)); bufferevent_write(bev, end, strlen(end));
free(out); free(out);
} }
/* Set input buffer size. */
void
input_set_buffer_size(size_t buffer_size)
{
log_debug("%s: %lu -> %lu", __func__, input_buffer_size, buffer_size);
input_buffer_size = buffer_size;
}
static void
input_report_current_theme(struct input_ctx *ictx)
{
switch (window_pane_get_theme(ictx->wp)) {
case THEME_DARK:
input_reply(ictx, "\033[?997;1n");
break;
case THEME_LIGHT:
input_reply(ictx, "\033[?997;2n");
break;
case THEME_UNKNOWN:
break;
}
}

77
job.c
View File

@ -69,43 +69,27 @@ static LIST_HEAD(joblist, job) all_jobs = LIST_HEAD_INITIALIZER(all_jobs);
/* Start a job running. */ /* Start a job running. */
struct job * struct job *
job_run(const char *cmd, int argc, char **argv, struct environ *e, job_run(const char *cmd, int argc, char **argv, struct environ *e, struct session *s,
struct session *s, const char *cwd, job_update_cb updatecb, const char *cwd, job_update_cb updatecb, job_complete_cb completecb,
job_complete_cb completecb, job_free_cb freecb, void *data, int flags, job_free_cb freecb, void *data, int flags, int sx, int sy)
int sx, int sy)
{ {
struct job *job; struct job *job;
struct environ *env; struct environ *env;
pid_t pid; pid_t pid;
int nullfd, out[2], master, do_close = 1; int nullfd, out[2], master;
const char *home, *shell; const char *home;
sigset_t set, oldset; sigset_t set, oldset;
struct winsize ws; struct winsize ws;
char **argvp, tty[TTY_NAME_MAX], *argv0; char **argvp, tty[TTY_NAME_MAX];
struct options *oo;
/* /*
* Do not set TERM during .tmux.conf (second argument here), it is nice * Do not set TERM during .tmux.conf, it is nice to be able to use
* to be able to use if-shell to decide on default-terminal based on * if-shell to decide on default-terminal based on outside TERM.
* outside TERM.
*/ */
env = environ_for_session(s, !cfg_finished); env = environ_for_session(s, !cfg_finished);
if (e != NULL) if (e != NULL)
environ_copy(e, env); environ_copy(e, env);
if (~flags & JOB_DEFAULTSHELL)
shell = _PATH_BSHELL;
else {
if (s != NULL)
oo = s->options;
else
oo = global_s_options;
shell = options_get_string(oo, "default-shell");
if (!checkshell(shell))
shell = _PATH_BSHELL;
}
argv0 = shell_argv0(shell, 0);
sigfillset(&set); sigfillset(&set);
sigprocmask(SIG_BLOCK, &set, &oldset); sigprocmask(SIG_BLOCK, &set, &oldset);
@ -121,11 +105,10 @@ job_run(const char *cmd, int argc, char **argv, struct environ *e,
} }
if (cmd == NULL) { if (cmd == NULL) {
cmd_log_argv(argc, argv, "%s:", __func__); cmd_log_argv(argc, argv, "%s:", __func__);
log_debug("%s: cwd=%s, shell=%s", __func__, log_debug("%s: cwd=%s", __func__, cwd == NULL ? "" : cwd);
cwd == NULL ? "" : cwd, shell);
} else { } else {
log_debug("%s: cmd=%s, cwd=%s, shell=%s", __func__, cmd, log_debug("%s: cmd=%s, cwd=%s", __func__, cmd,
cwd == NULL ? "" : cwd, shell); cwd == NULL ? "" : cwd);
} }
switch (pid) { switch (pid) {
@ -150,33 +133,24 @@ job_run(const char *cmd, int argc, char **argv, struct environ *e,
if (~flags & JOB_PTY) { if (~flags & JOB_PTY) {
if (dup2(out[1], STDIN_FILENO) == -1) if (dup2(out[1], STDIN_FILENO) == -1)
fatal("dup2 failed"); fatal("dup2 failed");
do_close = do_close && out[1] != STDIN_FILENO;
if (dup2(out[1], STDOUT_FILENO) == -1) if (dup2(out[1], STDOUT_FILENO) == -1)
fatal("dup2 failed"); fatal("dup2 failed");
do_close = do_close && out[1] != STDOUT_FILENO; if (out[1] != STDIN_FILENO && out[1] != STDOUT_FILENO)
if (flags & JOB_SHOWSTDERR) {
if (dup2(out[1], STDERR_FILENO) == -1)
fatal("dup2 failed");
do_close = do_close && out[1] != STDERR_FILENO;
} else {
nullfd = open(_PATH_DEVNULL, O_RDWR);
if (nullfd == -1)
fatal("open failed");
if (dup2(nullfd, STDERR_FILENO) == -1)
fatal("dup2 failed");
if (nullfd != STDERR_FILENO)
close(nullfd);
}
if (do_close)
close(out[1]); close(out[1]);
close(out[0]); close(out[0]);
nullfd = open(_PATH_DEVNULL, O_RDWR);
if (nullfd == -1)
fatal("open failed");
if (dup2(nullfd, STDERR_FILENO) == -1)
fatal("dup2 failed");
if (nullfd != STDERR_FILENO)
close(nullfd);
} }
closefrom(STDERR_FILENO + 1); closefrom(STDERR_FILENO + 1);
if (cmd != NULL) { if (cmd != NULL) {
if (flags & JOB_DEFAULTSHELL) execl(_PATH_BSHELL, "sh", "-c", cmd, (char *) NULL);
setenv("SHELL", shell, 1);
execl(shell, argv0, "-c", cmd, (char *)NULL);
fatal("execl failed"); fatal("execl failed");
} else { } else {
argvp = cmd_copy_argv(argc, argv); argvp = cmd_copy_argv(argc, argv);
@ -187,9 +161,8 @@ job_run(const char *cmd, int argc, char **argv, struct environ *e,
sigprocmask(SIG_SETMASK, &oldset, NULL); sigprocmask(SIG_SETMASK, &oldset, NULL);
environ_free(env); environ_free(env);
free(argv0);
job = xcalloc(1, sizeof *job); job = xmalloc(sizeof *job);
job->state = JOB_RUNNING; job->state = JOB_RUNNING;
job->flags = flags; job->flags = flags;
@ -198,8 +171,7 @@ job_run(const char *cmd, int argc, char **argv, struct environ *e,
else else
job->cmd = cmd_stringify_argv(argc, argv); job->cmd = cmd_stringify_argv(argc, argv);
job->pid = pid; job->pid = pid;
if (flags & JOB_PTY) strlcpy(job->tty, tty, sizeof job->tty);
strlcpy(job->tty, tty, sizeof job->tty);
job->status = 0; job->status = 0;
LIST_INSERT_HEAD(&all_jobs, job, entry); LIST_INSERT_HEAD(&all_jobs, job, entry);
@ -222,13 +194,12 @@ job_run(const char *cmd, int argc, char **argv, struct environ *e,
fatalx("out of memory"); fatalx("out of memory");
bufferevent_enable(job->event, EV_READ|EV_WRITE); bufferevent_enable(job->event, EV_READ|EV_WRITE);
log_debug("run job %p: %s, pid %ld", job, job->cmd, (long)job->pid); log_debug("run job %p: %s, pid %ld", job, job->cmd, (long) job->pid);
return (job); return (job);
fail: fail:
sigprocmask(SIG_SETMASK, &oldset, NULL); sigprocmask(SIG_SETMASK, &oldset, NULL);
environ_free(env); environ_free(env);
free(argv0);
return (NULL); return (NULL);
} }

View File

@ -49,14 +49,11 @@
" '#{?#{m/r:(copy|view)-mode,#{pane_mode}},Go To Top,}' '<' {send -X history-top}" \ " '#{?#{m/r:(copy|view)-mode,#{pane_mode}},Go To Top,}' '<' {send -X history-top}" \
" '#{?#{m/r:(copy|view)-mode,#{pane_mode}},Go To Bottom,}' '>' {send -X history-bottom}" \ " '#{?#{m/r:(copy|view)-mode,#{pane_mode}},Go To Bottom,}' '>' {send -X history-bottom}" \
" ''" \ " ''" \
" '#{?mouse_word,Search For #[underscore]#{=/9/...:mouse_word},}' 'C-r' {if -F '#{?#{m/r:(copy|view)-mode,#{pane_mode}},0,1}' 'copy-mode -t='; send -Xt= search-backward -- \"#{q:mouse_word}\"}" \ " '#{?mouse_word,Search For #[underscore]#{=/9/...:mouse_word},}' 'C-r' {if -F '#{?#{m/r:(copy|view)-mode,#{pane_mode}},0,1}' 'copy-mode -t='; send -Xt= search-backward \"#{q:mouse_word}\"}" \
" '#{?mouse_word,Type #[underscore]#{=/9/...:mouse_word},}' 'C-y' {copy-mode -q; send-keys -l -- \"#{q:mouse_word}\"}" \ " '#{?mouse_word,Type #[underscore]#{=/9/...:mouse_word},}' 'C-y' {copy-mode -q; send-keys -l -- \"#{q:mouse_word}\"}" \
" '#{?mouse_word,Copy #[underscore]#{=/9/...:mouse_word},}' 'c' {copy-mode -q; set-buffer -- \"#{q:mouse_word}\"}" \ " '#{?mouse_word,Copy #[underscore]#{=/9/...:mouse_word},}' 'c' {copy-mode -q; set-buffer -- \"#{q:mouse_word}\"}" \
" '#{?mouse_line,Copy Line,}' 'l' {copy-mode -q; set-buffer -- \"#{q:mouse_line}\"}" \ " '#{?mouse_line,Copy Line,}' 'l' {copy-mode -q; set-buffer -- \"#{q:mouse_line}\"}" \
" ''" \ " ''" \
" '#{?mouse_hyperlink,Type #[underscore]#{=/9/...:mouse_hyperlink},}' 'C-h' {copy-mode -q; send-keys -l -- \"#{q:mouse_hyperlink}\"}" \
" '#{?mouse_hyperlink,Copy #[underscore]#{=/9/...:mouse_hyperlink},}' 'h' {copy-mode -q; set-buffer -- \"#{q:mouse_hyperlink}\"}" \
" ''" \
" 'Horizontal Split' 'h' {split-window -h}" \ " 'Horizontal Split' 'h' {split-window -h}" \
" 'Vertical Split' 'v' {split-window -v}" \ " 'Vertical Split' 'v' {split-window -v}" \
" ''" \ " ''" \
@ -197,12 +194,11 @@ key_bindings_add(const char *name, key_code key, const char *note, int repeat,
bd = key_bindings_get(table, key & ~KEYC_MASK_FLAGS); bd = key_bindings_get(table, key & ~KEYC_MASK_FLAGS);
if (cmdlist == NULL) { if (cmdlist == NULL) {
if (bd != NULL) { if (bd != NULL) {
if (note != NULL) { free((void *)bd->note);
free((void *)bd->note); if (note != NULL)
bd->note = xstrdup(note); bd->note = xstrdup(note);
} else
if (repeat) bd->note = NULL;
bd->flags |= KEY_BINDING_REPEAT;
} }
return; return;
} }
@ -345,7 +341,7 @@ key_bindings_init_done(__unused struct cmdq_item *item, __unused void *data)
void void
key_bindings_init(void) key_bindings_init(void)
{ {
static const char *const defaults[] = { static const char *defaults[] = {
/* Prefix keys. */ /* Prefix keys. */
"bind -N 'Send the prefix key' C-b { send-prefix }", "bind -N 'Send the prefix key' C-b { send-prefix }",
"bind -N 'Rotate through the panes' C-o { rotate-window }", "bind -N 'Rotate through the panes' C-o { rotate-window }",
@ -378,7 +374,7 @@ key_bindings_init(void)
"bind -N 'Move to the previously active pane' \\; { last-pane }", "bind -N 'Move to the previously active pane' \\; { last-pane }",
"bind -N 'Choose a paste buffer from a list' = { choose-buffer -Z }", "bind -N 'Choose a paste buffer from a list' = { choose-buffer -Z }",
"bind -N 'List key bindings' ? { list-keys -N }", "bind -N 'List key bindings' ? { list-keys -N }",
"bind -N 'Choose and detach a client from a list' D { choose-client -Z }", "bind -N 'Choose a client from a list' D { choose-client -Z }",
"bind -N 'Spread panes out evenly' E { select-layout -E }", "bind -N 'Spread panes out evenly' E { select-layout -E }",
"bind -N 'Switch to the last client' L { switch-client -l }", "bind -N 'Switch to the last client' L { switch-client -l }",
"bind -N 'Clear the marked pane' M { select-pane -M }", "bind -N 'Clear the marked pane' M { select-pane -M }",
@ -414,8 +410,6 @@ key_bindings_init(void)
"bind -N 'Set the main-horizontal layout' M-3 { select-layout main-horizontal }", "bind -N 'Set the main-horizontal layout' M-3 { select-layout main-horizontal }",
"bind -N 'Set the main-vertical layout' M-4 { select-layout main-vertical }", "bind -N 'Set the main-vertical layout' M-4 { select-layout main-vertical }",
"bind -N 'Select the tiled layout' M-5 { select-layout tiled }", "bind -N 'Select the tiled layout' M-5 { select-layout tiled }",
"bind -N 'Set the main-horizontal-mirrored layout' M-6 { select-layout main-horizontal-mirrored }",
"bind -N 'Set the main-vertical-mirrored layout' M-7 { select-layout main-vertical-mirrored }",
"bind -N 'Select the next window with an alert' M-n { next-window -a }", "bind -N 'Select the next window with an alert' M-n { next-window -a }",
"bind -N 'Rotate through the panes in reverse' M-o { rotate-window -D }", "bind -N 'Rotate through the panes in reverse' M-o { rotate-window -D }",
"bind -N 'Select the previous window with an alert' M-p { previous-window -a }", "bind -N 'Select the previous window with an alert' M-p { previous-window -a }",
@ -434,9 +428,8 @@ key_bindings_init(void)
"bind -N 'Resize the pane right' -r C-Right { resize-pane -R }", "bind -N 'Resize the pane right' -r C-Right { resize-pane -R }",
/* Menu keys */ /* Menu keys */
"bind -N 'Display window menu' < { display-menu -xW -yW -T '#[align=centre]#{window_index}:#{window_name}' " DEFAULT_WINDOW_MENU " }", "bind < { display-menu -xW -yW -T '#[align=centre]#{window_index}:#{window_name}' " DEFAULT_WINDOW_MENU " }",
"bind -N 'Display pane menu' > { display-menu -xP -yP -T '#[align=centre]#{pane_index} (#{pane_id})' " DEFAULT_PANE_MENU " }", "bind > { display-menu -xP -yP -T '#[align=centre]#{pane_index} (#{pane_id})' " DEFAULT_PANE_MENU " }",
/* Mouse button 1 down on pane. */ /* Mouse button 1 down on pane. */
"bind -n MouseDown1Pane { select-pane -t=; send -M }", "bind -n MouseDown1Pane { select-pane -t=; send -M }",
@ -470,21 +463,14 @@ key_bindings_init(void)
/* Mouse button 3 down on status left. */ /* Mouse button 3 down on status left. */
"bind -n MouseDown3StatusLeft { display-menu -t= -xM -yW -T '#[align=centre]#{session_name}' " DEFAULT_SESSION_MENU " }", "bind -n MouseDown3StatusLeft { display-menu -t= -xM -yW -T '#[align=centre]#{session_name}' " DEFAULT_SESSION_MENU " }",
"bind -n M-MouseDown3StatusLeft { display-menu -t= -xM -yW -T '#[align=centre]#{session_name}' " DEFAULT_SESSION_MENU " }",
/* Mouse button 3 down on status line. */ /* Mouse button 3 down on status line. */
"bind -n MouseDown3Status { display-menu -t= -xW -yW -T '#[align=centre]#{window_index}:#{window_name}' " DEFAULT_WINDOW_MENU "}", "bind -n MouseDown3Status { display-menu -t= -xW -yW -T '#[align=centre]#{window_index}:#{window_name}' " DEFAULT_WINDOW_MENU "}",
"bind -n M-MouseDown3Status { display-menu -t= -xW -yW -T '#[align=centre]#{window_index}:#{window_name}' " DEFAULT_WINDOW_MENU "}",
/* Mouse button 3 down on pane. */ /* Mouse button 3 down on pane. */
"bind -n MouseDown3Pane { if -Ft= '#{||:#{mouse_any_flag},#{&&:#{pane_in_mode},#{?#{m/r:(copy|view)-mode,#{pane_mode}},0,1}}}' { select-pane -t=; send -M } { display-menu -t= -xM -yM -T '#[align=centre]#{pane_index} (#{pane_id})' " DEFAULT_PANE_MENU " } }", "bind -n MouseDown3Pane { if -Ft= '#{||:#{mouse_any_flag},#{&&:#{pane_in_mode},#{?#{m/r:(copy|view)-mode,#{pane_mode}},0,1}}}' { select-pane -t=; send -M } { display-menu -t= -xM -yM -T '#[align=centre]#{pane_index} (#{pane_id})' " DEFAULT_PANE_MENU " } }",
"bind -n M-MouseDown3Pane { display-menu -t= -xM -yM -T '#[align=centre]#{pane_index} (#{pane_id})' " DEFAULT_PANE_MENU " }", "bind -n M-MouseDown3Pane { display-menu -t= -xM -yM -T '#[align=centre]#{pane_index} (#{pane_id})' " DEFAULT_PANE_MENU " }",
/* Mouse on scrollbar. */
"bind -n MouseDown1ScrollbarUp { copy-mode -u }",
"bind -n MouseDown1ScrollbarDown { copy-mode -d }",
"bind -n MouseDrag1ScrollbarSlider { copy-mode -S }",
/* Copy mode (emacs) keys. */ /* Copy mode (emacs) keys. */
"bind -Tcopy-mode C-Space { send -X begin-selection }", "bind -Tcopy-mode C-Space { send -X begin-selection }",
"bind -Tcopy-mode C-a { send -X start-of-line }", "bind -Tcopy-mode C-a { send -X start-of-line }",
@ -496,26 +482,26 @@ key_bindings_init(void)
"bind -Tcopy-mode C-k { send -X copy-pipe-end-of-line-and-cancel }", "bind -Tcopy-mode C-k { send -X copy-pipe-end-of-line-and-cancel }",
"bind -Tcopy-mode C-n { send -X cursor-down }", "bind -Tcopy-mode C-n { send -X cursor-down }",
"bind -Tcopy-mode C-p { send -X cursor-up }", "bind -Tcopy-mode C-p { send -X cursor-up }",
"bind -Tcopy-mode C-r { command-prompt -T search -ip'(search up)' -I'#{pane_search_string}' { send -X search-backward-incremental -- '%%' } }", "bind -Tcopy-mode C-r { command-prompt -T search -ip'(search up)' -I'#{pane_search_string}' { send -X search-backward-incremental '%%' } }",
"bind -Tcopy-mode C-s { command-prompt -T search -ip'(search down)' -I'#{pane_search_string}' { send -X search-forward-incremental -- '%%' } }", "bind -Tcopy-mode C-s { command-prompt -T search -ip'(search down)' -I'#{pane_search_string}' { send -X search-forward-incremental '%%' } }",
"bind -Tcopy-mode C-v { send -X page-down }", "bind -Tcopy-mode C-v { send -X page-down }",
"bind -Tcopy-mode C-w { send -X copy-pipe-and-cancel }", "bind -Tcopy-mode C-w { send -X copy-pipe-and-cancel }",
"bind -Tcopy-mode Escape { send -X cancel }", "bind -Tcopy-mode Escape { send -X cancel }",
"bind -Tcopy-mode Space { send -X page-down }", "bind -Tcopy-mode Space { send -X page-down }",
"bind -Tcopy-mode , { send -X jump-reverse }", "bind -Tcopy-mode , { send -X jump-reverse }",
"bind -Tcopy-mode \\; { send -X jump-again }", "bind -Tcopy-mode \\; { send -X jump-again }",
"bind -Tcopy-mode F { command-prompt -1p'(jump backward)' { send -X jump-backward -- '%%' } }", "bind -Tcopy-mode F { command-prompt -1p'(jump backward)' { send -X jump-backward '%%' } }",
"bind -Tcopy-mode N { send -X search-reverse }", "bind -Tcopy-mode N { send -X search-reverse }",
"bind -Tcopy-mode P { send -X toggle-position }", "bind -Tcopy-mode P { send -X toggle-position }",
"bind -Tcopy-mode R { send -X rectangle-toggle }", "bind -Tcopy-mode R { send -X rectangle-toggle }",
"bind -Tcopy-mode T { command-prompt -1p'(jump to backward)' { send -X jump-to-backward -- '%%' } }", "bind -Tcopy-mode T { command-prompt -1p'(jump to backward)' { send -X jump-to-backward '%%' } }",
"bind -Tcopy-mode X { send -X set-mark }", "bind -Tcopy-mode X { send -X set-mark }",
"bind -Tcopy-mode f { command-prompt -1p'(jump forward)' { send -X jump-forward -- '%%' } }", "bind -Tcopy-mode f { command-prompt -1p'(jump forward)' { send -X jump-forward '%%' } }",
"bind -Tcopy-mode g { command-prompt -p'(goto line)' { send -X goto-line -- '%%' } }", "bind -Tcopy-mode g { command-prompt -p'(goto line)' { send -X goto-line '%%' } }",
"bind -Tcopy-mode n { send -X search-again }", "bind -Tcopy-mode n { send -X search-again }",
"bind -Tcopy-mode q { send -X cancel }", "bind -Tcopy-mode q { send -X cancel }",
"bind -Tcopy-mode r { send -X refresh-from-pane }", "bind -Tcopy-mode r { send -X refresh-from-pane }",
"bind -Tcopy-mode t { command-prompt -1p'(jump to forward)' { send -X jump-to-forward -- '%%' } }", "bind -Tcopy-mode t { command-prompt -1p'(jump to forward)' { send -X jump-to-forward '%%' } }",
"bind -Tcopy-mode Home { send -X start-of-line }", "bind -Tcopy-mode Home { send -X start-of-line }",
"bind -Tcopy-mode End { send -X end-of-line }", "bind -Tcopy-mode End { send -X end-of-line }",
"bind -Tcopy-mode MouseDown1Pane select-pane", "bind -Tcopy-mode MouseDown1Pane select-pane",
@ -560,8 +546,8 @@ key_bindings_init(void)
"bind -Tcopy-mode C-Down { send -X scroll-down }", "bind -Tcopy-mode C-Down { send -X scroll-down }",
/* Copy mode (vi) keys. */ /* Copy mode (vi) keys. */
"bind -Tcopy-mode-vi '#' { send -FX search-backward -- '#{copy_cursor_word}' }", "bind -Tcopy-mode-vi '#' { send -FX search-backward '#{copy_cursor_word}' }",
"bind -Tcopy-mode-vi * { send -FX search-forward -- '#{copy_cursor_word}' }", "bind -Tcopy-mode-vi * { send -FX search-forward '#{copy_cursor_word}' }",
"bind -Tcopy-mode-vi C-c { send -X cancel }", "bind -Tcopy-mode-vi C-c { send -X cancel }",
"bind -Tcopy-mode-vi C-d { send -X halfpage-down }", "bind -Tcopy-mode-vi C-d { send -X halfpage-down }",
"bind -Tcopy-mode-vi C-e { send -X scroll-down }", "bind -Tcopy-mode-vi C-e { send -X scroll-down }",
@ -577,7 +563,7 @@ key_bindings_init(void)
"bind -Tcopy-mode-vi Space { send -X begin-selection }", "bind -Tcopy-mode-vi Space { send -X begin-selection }",
"bind -Tcopy-mode-vi '$' { send -X end-of-line }", "bind -Tcopy-mode-vi '$' { send -X end-of-line }",
"bind -Tcopy-mode-vi , { send -X jump-reverse }", "bind -Tcopy-mode-vi , { send -X jump-reverse }",
"bind -Tcopy-mode-vi / { command-prompt -T search -p'(search down)' { send -X search-forward -- '%%' } }", "bind -Tcopy-mode-vi / { command-prompt -T search -p'(search down)' { send -X search-forward '%%' } }",
"bind -Tcopy-mode-vi 0 { send -X start-of-line }", "bind -Tcopy-mode-vi 0 { send -X start-of-line }",
"bind -Tcopy-mode-vi 1 { command-prompt -Np'(repeat)' -I1 { send -N '%%' } }", "bind -Tcopy-mode-vi 1 { command-prompt -Np'(repeat)' -I1 { send -N '%%' } }",
"bind -Tcopy-mode-vi 2 { command-prompt -Np'(repeat)' -I2 { send -N '%%' } }", "bind -Tcopy-mode-vi 2 { command-prompt -Np'(repeat)' -I2 { send -N '%%' } }",
@ -588,14 +574,14 @@ key_bindings_init(void)
"bind -Tcopy-mode-vi 7 { command-prompt -Np'(repeat)' -I7 { send -N '%%' } }", "bind -Tcopy-mode-vi 7 { command-prompt -Np'(repeat)' -I7 { send -N '%%' } }",
"bind -Tcopy-mode-vi 8 { command-prompt -Np'(repeat)' -I8 { send -N '%%' } }", "bind -Tcopy-mode-vi 8 { command-prompt -Np'(repeat)' -I8 { send -N '%%' } }",
"bind -Tcopy-mode-vi 9 { command-prompt -Np'(repeat)' -I9 { send -N '%%' } }", "bind -Tcopy-mode-vi 9 { command-prompt -Np'(repeat)' -I9 { send -N '%%' } }",
"bind -Tcopy-mode-vi : { command-prompt -p'(goto line)' { send -X goto-line -- '%%' } }", "bind -Tcopy-mode-vi : { command-prompt -p'(goto line)' { send -X goto-line '%%' } }",
"bind -Tcopy-mode-vi \\; { send -X jump-again }", "bind -Tcopy-mode-vi \\; { send -X jump-again }",
"bind -Tcopy-mode-vi ? { command-prompt -T search -p'(search up)' { send -X search-backward -- '%%' } }", "bind -Tcopy-mode-vi ? { command-prompt -T search -p'(search up)' { send -X search-backward '%%' } }",
"bind -Tcopy-mode-vi A { send -X append-selection-and-cancel }", "bind -Tcopy-mode-vi A { send -X append-selection-and-cancel }",
"bind -Tcopy-mode-vi B { send -X previous-space }", "bind -Tcopy-mode-vi B { send -X previous-space }",
"bind -Tcopy-mode-vi D { send -X copy-pipe-end-of-line-and-cancel }", "bind -Tcopy-mode-vi D { send -X copy-pipe-end-of-line-and-cancel }",
"bind -Tcopy-mode-vi E { send -X next-space-end }", "bind -Tcopy-mode-vi E { send -X next-space-end }",
"bind -Tcopy-mode-vi F { command-prompt -1p'(jump backward)' { send -X jump-backward -- '%%' } }", "bind -Tcopy-mode-vi F { command-prompt -1p'(jump backward)' { send -X jump-backward '%%' } }",
"bind -Tcopy-mode-vi G { send -X history-bottom }", "bind -Tcopy-mode-vi G { send -X history-bottom }",
"bind -Tcopy-mode-vi H { send -X top-line }", "bind -Tcopy-mode-vi H { send -X top-line }",
"bind -Tcopy-mode-vi J { send -X scroll-down }", "bind -Tcopy-mode-vi J { send -X scroll-down }",
@ -604,32 +590,29 @@ key_bindings_init(void)
"bind -Tcopy-mode-vi M { send -X middle-line }", "bind -Tcopy-mode-vi M { send -X middle-line }",
"bind -Tcopy-mode-vi N { send -X search-reverse }", "bind -Tcopy-mode-vi N { send -X search-reverse }",
"bind -Tcopy-mode-vi P { send -X toggle-position }", "bind -Tcopy-mode-vi P { send -X toggle-position }",
"bind -Tcopy-mode-vi T { command-prompt -1p'(jump to backward)' { send -X jump-to-backward -- '%%' } }", "bind -Tcopy-mode-vi T { command-prompt -1p'(jump to backward)' { send -X jump-to-backward '%%' } }",
"bind -Tcopy-mode-vi V { send -X select-line }", "bind -Tcopy-mode-vi V { send -X select-line }",
"bind -Tcopy-mode-vi W { send -X next-space }", "bind -Tcopy-mode-vi W { send -X next-space }",
"bind -Tcopy-mode-vi X { send -X set-mark }", "bind -Tcopy-mode-vi X { send -X set-mark }",
"bind -Tcopy-mode-vi ^ { send -X back-to-indentation }", "bind -Tcopy-mode-vi ^ { send -X back-to-indentation }",
"bind -Tcopy-mode-vi b { send -X previous-word }", "bind -Tcopy-mode-vi b { send -X previous-word }",
"bind -Tcopy-mode-vi e { send -X next-word-end }", "bind -Tcopy-mode-vi e { send -X next-word-end }",
"bind -Tcopy-mode-vi f { command-prompt -1p'(jump forward)' { send -X jump-forward -- '%%' } }", "bind -Tcopy-mode-vi f { command-prompt -1p'(jump forward)' { send -X jump-forward '%%' } }",
"bind -Tcopy-mode-vi g { send -X history-top }", "bind -Tcopy-mode-vi g { send -X history-top }",
"bind -Tcopy-mode-vi h { send -X cursor-left }", "bind -Tcopy-mode-vi h { send -X cursor-left }",
"bind -Tcopy-mode-vi j { send -X cursor-down }", "bind -Tcopy-mode-vi j { send -X cursor-down }",
"bind -Tcopy-mode-vi k { send -X cursor-up }", "bind -Tcopy-mode-vi k { send -X cursor-up }",
"bind -Tcopy-mode-vi z { send -X scroll-middle }",
"bind -Tcopy-mode-vi l { send -X cursor-right }", "bind -Tcopy-mode-vi l { send -X cursor-right }",
"bind -Tcopy-mode-vi n { send -X search-again }", "bind -Tcopy-mode-vi n { send -X search-again }",
"bind -Tcopy-mode-vi o { send -X other-end }", "bind -Tcopy-mode-vi o { send -X other-end }",
"bind -Tcopy-mode-vi q { send -X cancel }", "bind -Tcopy-mode-vi q { send -X cancel }",
"bind -Tcopy-mode-vi r { send -X refresh-from-pane }", "bind -Tcopy-mode-vi r { send -X refresh-from-pane }",
"bind -Tcopy-mode-vi t { command-prompt -1p'(jump to forward)' { send -X jump-to-forward -- '%%' } }", "bind -Tcopy-mode-vi t { command-prompt -1p'(jump to forward)' { send -X jump-to-forward '%%' } }",
"bind -Tcopy-mode-vi v { send -X rectangle-toggle }", "bind -Tcopy-mode-vi v { send -X rectangle-toggle }",
"bind -Tcopy-mode-vi w { send -X next-word }", "bind -Tcopy-mode-vi w { send -X next-word }",
"bind -Tcopy-mode-vi '{' { send -X previous-paragraph }", "bind -Tcopy-mode-vi '{' { send -X previous-paragraph }",
"bind -Tcopy-mode-vi '}' { send -X next-paragraph }", "bind -Tcopy-mode-vi '}' { send -X next-paragraph }",
"bind -Tcopy-mode-vi % { send -X next-matching-bracket }", "bind -Tcopy-mode-vi % { send -X next-matching-bracket }",
"bind -Tcopy-mode-vi Home { send -X start-of-line }",
"bind -Tcopy-mode-vi End { send -X end-of-line }",
"bind -Tcopy-mode-vi MouseDown1Pane { select-pane }", "bind -Tcopy-mode-vi MouseDown1Pane { select-pane }",
"bind -Tcopy-mode-vi MouseDrag1Pane { select-pane; send -X begin-selection }", "bind -Tcopy-mode-vi MouseDrag1Pane { select-pane; send -X begin-selection }",
"bind -Tcopy-mode-vi MouseDragEnd1Pane { send -X copy-pipe-and-cancel }", "bind -Tcopy-mode-vi MouseDragEnd1Pane { send -X copy-pipe-and-cancel }",

View File

@ -18,7 +18,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <ctype.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <wchar.h> #include <wchar.h>
@ -57,47 +56,12 @@ static const struct {
{ "PPage", KEYC_PPAGE|KEYC_IMPLIED_META }, { "PPage", KEYC_PPAGE|KEYC_IMPLIED_META },
{ "PageUp", KEYC_PPAGE|KEYC_IMPLIED_META }, { "PageUp", KEYC_PPAGE|KEYC_IMPLIED_META },
{ "PgUp", KEYC_PPAGE|KEYC_IMPLIED_META }, { "PgUp", KEYC_PPAGE|KEYC_IMPLIED_META },
{ "Tab", '\011' },
{ "BTab", KEYC_BTAB }, { "BTab", KEYC_BTAB },
{ "Space", ' ' }, { "Space", ' ' },
{ "BSpace", KEYC_BSPACE }, { "BSpace", KEYC_BSPACE },
{ "Enter", '\r' },
/* { "Escape", '\033' },
* C0 control characters, with the exception of Tab, Enter,
* and Esc, should never appear as keys. We still render them,
* so to be able to spot them in logs in case of an abnormality.
*/
{ "[NUL]", C0_NUL },
{ "[SOH]", C0_SOH },
{ "[STX]", C0_STX },
{ "[ETX]", C0_ETX },
{ "[EOT]", C0_EOT },
{ "[ENQ]", C0_ENQ },
{ "[ASC]", C0_ASC },
{ "[BEL]", C0_BEL },
{ "[BS]", C0_BS },
{ "Tab", C0_HT },
{ "[LF]", C0_LF },
{ "[VT]", C0_VT },
{ "[FF]", C0_FF },
{ "Enter", C0_CR },
{ "[SO]", C0_SO },
{ "[SI]", C0_SI },
{ "[DLE]", C0_DLE },
{ "[DC1]", C0_DC1 },
{ "[DC2]", C0_DC2 },
{ "[DC3]", C0_DC3 },
{ "[DC4]", C0_DC4 },
{ "[NAK]", C0_NAK },
{ "[SYN]", C0_SYN },
{ "[ETB]", C0_ETB },
{ "[CAN]", C0_CAN },
{ "[EM]", C0_EM },
{ "[SUB]", C0_SUB },
{ "Escape", C0_ESC },
{ "[FS]", C0_FS },
{ "[GS]", C0_GS },
{ "[RS]", C0_RS },
{ "[US]", C0_US },
/* Arrow keys. */ /* Arrow keys. */
{ "Up", KEYC_UP|KEYC_CURSOR|KEYC_IMPLIED_META }, { "Up", KEYC_UP|KEYC_CURSOR|KEYC_IMPLIED_META },
@ -242,7 +206,8 @@ key_string_get_modifiers(const char **string)
key_code key_code
key_string_lookup_string(const char *string) key_string_lookup_string(const char *string)
{ {
key_code key, modifiers = 0; static const char *other = "!#()+,-.0123456789:;<=>'\r\t\177`/";
key_code key, modifiers;
u_int u, i; u_int u, i;
struct utf8_data ud, *udp; struct utf8_data ud, *udp;
enum utf8_state more; enum utf8_state more;
@ -279,15 +244,12 @@ key_string_lookup_string(const char *string)
return (uc); return (uc);
} }
/* Check for short Ctrl key. */ /* Check for modifiers. */
modifiers = 0;
if (string[0] == '^' && string[1] != '\0') { if (string[0] == '^' && string[1] != '\0') {
if (string[2] == '\0')
return (tolower((u_char)string[1])|KEYC_CTRL);
modifiers |= KEYC_CTRL; modifiers |= KEYC_CTRL;
string++; string++;
} }
/* Check for modifiers. */
modifiers |= key_string_get_modifiers(&string); modifiers |= key_string_get_modifiers(&string);
if (string == NULL || string[0] == '\0') if (string == NULL || string[0] == '\0')
return (KEYC_UNKNOWN); return (KEYC_UNKNOWN);
@ -319,6 +281,26 @@ key_string_lookup_string(const char *string)
key &= ~KEYC_IMPLIED_META; key &= ~KEYC_IMPLIED_META;
} }
/* Convert the standard control keys. */
if (key <= 127 &&
(modifiers & KEYC_CTRL) &&
strchr(other, key) == NULL &&
key != 9 &&
key != 13 &&
key != 27) {
if (key >= 97 && key <= 122)
key -= 96;
else if (key >= 64 && key <= 95)
key -= 64;
else if (key == 32)
key = 0;
else if (key == 63)
key = 127;
else
return (KEYC_UNKNOWN);
modifiers &= ~KEYC_CTRL;
}
return (key|modifiers); return (key|modifiers);
} }
@ -342,6 +324,10 @@ key_string_lookup_key(key_code key, int with_flags)
goto out; goto out;
} }
/* Display C-@ as C-Space. */
if ((key & (KEYC_MASK_KEY|KEYC_MASK_MODIFIERS)) == 0)
key = ' '|KEYC_CTRL;
/* Fill in the modifiers. */ /* Fill in the modifiers. */
if (key & KEYC_CTRL) if (key & KEYC_CTRL)
strlcat(out, "C-", sizeof out); strlcat(out, "C-", sizeof out);
@ -410,7 +396,7 @@ key_string_lookup_key(key_code key, int with_flags)
s = "MouseMoveBorder"; s = "MouseMoveBorder";
goto append; goto append;
} }
if (key >= KEYC_USER && key < KEYC_USER_END) { if (key >= KEYC_USER && key < KEYC_USER + KEYC_NUSER) {
snprintf(tmp, sizeof tmp, "User%u", (u_int)(key - KEYC_USER)); snprintf(tmp, sizeof tmp, "User%u", (u_int)(key - KEYC_USER));
strlcat(out, tmp, sizeof out); strlcat(out, tmp, sizeof out);
goto out; goto out;
@ -441,8 +427,13 @@ key_string_lookup_key(key_code key, int with_flags)
goto out; goto out;
} }
/* Printable ASCII keys. */ /* Check for standard or control key. */
if (key > 32 && key <= 126) { if (key <= 32) {
if (key == 0 || key > 26)
xsnprintf(tmp, sizeof tmp, "C-%c", (int)(64 + key));
else
xsnprintf(tmp, sizeof tmp, "C-%c", (int)(96 + key));
} else if (key >= 32 && key <= 126) {
tmp[0] = key; tmp[0] = key;
tmp[1] = '\0'; tmp[1] = '\0';
} else if (key == 127) } else if (key == 127)
@ -469,8 +460,6 @@ out:
strlcat(out, "I", sizeof out); strlcat(out, "I", sizeof out);
if (saved & KEYC_BUILD_MODIFIERS) if (saved & KEYC_BUILD_MODIFIERS)
strlcat(out, "B", sizeof out); strlcat(out, "B", sizeof out);
if (saved & KEYC_SENT)
strlcat(out, "S", sizeof out);
strlcat(out, "]", sizeof out); strlcat(out, "]", sizeof out);
} }
return (out); return (out);

View File

@ -162,10 +162,8 @@ layout_parse(struct window *w, const char *layout, char **cause)
u_short csum; u_short csum;
/* Check validity. */ /* Check validity. */
if (sscanf(layout, "%hx,", &csum) != 1) { if (sscanf(layout, "%hx,", &csum) != 1)
*cause = xstrdup("invalid layout");
return (-1); return (-1);
}
layout += 5; layout += 5;
if (csum != layout_checksum(layout)) { if (csum != layout_checksum(layout)) {
*cause = xstrdup("invalid layout"); *cause = xstrdup("invalid layout");
@ -230,7 +228,7 @@ layout_parse(struct window *w, const char *layout, char **cause)
/* Check the new layout. */ /* Check the new layout. */
if (!layout_check(lc)) { if (!layout_check(lc)) {
*cause = xstrdup("size mismatch after applying layout"); *cause = xstrdup("size mismatch after applying layout");
goto fail; return (-1);
} }
/* Resize to the layout size. */ /* Resize to the layout size. */

View File

@ -31,9 +31,7 @@
static void layout_set_even_h(struct window *); static void layout_set_even_h(struct window *);
static void layout_set_even_v(struct window *); static void layout_set_even_v(struct window *);
static void layout_set_main_h(struct window *); static void layout_set_main_h(struct window *);
static void layout_set_main_h_mirrored(struct window *);
static void layout_set_main_v(struct window *); static void layout_set_main_v(struct window *);
static void layout_set_main_v_mirrored(struct window *);
static void layout_set_tiled(struct window *); static void layout_set_tiled(struct window *);
static const struct { static const struct {
@ -43,9 +41,7 @@ static const struct {
{ "even-horizontal", layout_set_even_h }, { "even-horizontal", layout_set_even_h },
{ "even-vertical", layout_set_even_v }, { "even-vertical", layout_set_even_v },
{ "main-horizontal", layout_set_main_h }, { "main-horizontal", layout_set_main_h },
{ "main-horizontal-mirrored", layout_set_main_h_mirrored },
{ "main-vertical", layout_set_main_v }, { "main-vertical", layout_set_main_v },
{ "main-vertical-mirrored", layout_set_main_v_mirrored },
{ "tiled", layout_set_tiled }, { "tiled", layout_set_tiled },
}; };
@ -55,10 +51,6 @@ layout_set_lookup(const char *name)
u_int i; u_int i;
int matched = -1; int matched = -1;
for (i = 0; i < nitems(layout_sets); i++) {
if (strcmp(layout_sets[i].name, name) == 0)
return (i);
}
for (i = 0; i < nitems(layout_sets); i++) { for (i = 0; i < nitems(layout_sets); i++) {
if (strncmp(layout_sets[i].name, name, strlen(name)) == 0) { if (strncmp(layout_sets[i].name, name, strlen(name)) == 0) {
if (matched != -1) /* ambiguous */ if (matched != -1) /* ambiguous */
@ -287,104 +279,6 @@ layout_set_main_h(struct window *w)
server_redraw_window(w); server_redraw_window(w);
} }
static void
layout_set_main_h_mirrored(struct window *w)
{
struct window_pane *wp;
struct layout_cell *lc, *lcmain, *lcother, *lcchild;
u_int n, mainh, otherh, sx, sy;
char *cause;
const char *s;
layout_print_cell(w->layout_root, __func__, 1);
/* Get number of panes. */
n = window_count_panes(w);
if (n <= 1)
return;
n--; /* take off main pane */
/* Find available height - take off one line for the border. */
sy = w->sy - 1;
/* Get the main pane height. */
s = options_get_string(w->options, "main-pane-height");
mainh = args_string_percentage(s, 0, sy, sy, &cause);
if (cause != NULL) {
mainh = 24;
free(cause);
}
/* Work out the other pane height. */
if (mainh + PANE_MINIMUM >= sy) {
if (sy <= PANE_MINIMUM + PANE_MINIMUM)
mainh = PANE_MINIMUM;
else
mainh = sy - PANE_MINIMUM;
otherh = PANE_MINIMUM;
} else {
s = options_get_string(w->options, "other-pane-height");
otherh = args_string_percentage(s, 0, sy, sy, &cause);
if (cause != NULL || otherh == 0) {
otherh = sy - mainh;
free(cause);
} else if (otherh > sy || sy - otherh < mainh)
otherh = sy - mainh;
else
mainh = sy - otherh;
}
/* Work out what width is needed. */
sx = (n * (PANE_MINIMUM + 1)) - 1;
if (sx < w->sx)
sx = w->sx;
/* Free old tree and create a new root. */
layout_free(w);
lc = w->layout_root = layout_create_cell(NULL);
layout_set_size(lc, sx, mainh + otherh + 1, 0, 0);
layout_make_node(lc, LAYOUT_TOPBOTTOM);
/* Create the other pane. */
lcother = layout_create_cell(lc);
layout_set_size(lcother, sx, otherh, 0, 0);
if (n == 1) {
wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry);
layout_make_leaf(lcother, wp);
TAILQ_INSERT_TAIL(&lc->cells, lcother, entry);
} else {
layout_make_node(lcother, LAYOUT_LEFTRIGHT);
TAILQ_INSERT_TAIL(&lc->cells, lcother, entry);
/* Add the remaining panes as children. */
TAILQ_FOREACH(wp, &w->panes, entry) {
if (wp == TAILQ_FIRST(&w->panes))
continue;
lcchild = layout_create_cell(lcother);
layout_set_size(lcchild, PANE_MINIMUM, otherh, 0, 0);
layout_make_leaf(lcchild, wp);
TAILQ_INSERT_TAIL(&lcother->cells, lcchild, entry);
}
layout_spread_cell(w, lcother);
}
/* Create the main pane. */
lcmain = layout_create_cell(lc);
layout_set_size(lcmain, sx, mainh, 0, 0);
layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes));
TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry);
/* Fix cell offsets. */
layout_fix_offsets(w);
layout_fix_panes(w, NULL);
layout_print_cell(w->layout_root, __func__, 1);
window_resize(w, lc->sx, lc->sy, -1, -1);
notify_window("window-layout-changed", w);
server_redraw_window(w);
}
static void static void
layout_set_main_v(struct window *w) layout_set_main_v(struct window *w)
{ {
@ -483,104 +377,6 @@ layout_set_main_v(struct window *w)
server_redraw_window(w); server_redraw_window(w);
} }
static void
layout_set_main_v_mirrored(struct window *w)
{
struct window_pane *wp;
struct layout_cell *lc, *lcmain, *lcother, *lcchild;
u_int n, mainw, otherw, sx, sy;
char *cause;
const char *s;
layout_print_cell(w->layout_root, __func__, 1);
/* Get number of panes. */
n = window_count_panes(w);
if (n <= 1)
return;
n--; /* take off main pane */
/* Find available width - take off one line for the border. */
sx = w->sx - 1;
/* Get the main pane width. */
s = options_get_string(w->options, "main-pane-width");
mainw = args_string_percentage(s, 0, sx, sx, &cause);
if (cause != NULL) {
mainw = 80;
free(cause);
}
/* Work out the other pane width. */
if (mainw + PANE_MINIMUM >= sx) {
if (sx <= PANE_MINIMUM + PANE_MINIMUM)
mainw = PANE_MINIMUM;
else
mainw = sx - PANE_MINIMUM;
otherw = PANE_MINIMUM;
} else {
s = options_get_string(w->options, "other-pane-width");
otherw = args_string_percentage(s, 0, sx, sx, &cause);
if (cause != NULL || otherw == 0) {
otherw = sx - mainw;
free(cause);
} else if (otherw > sx || sx - otherw < mainw)
otherw = sx - mainw;
else
mainw = sx - otherw;
}
/* Work out what height is needed. */
sy = (n * (PANE_MINIMUM + 1)) - 1;
if (sy < w->sy)
sy = w->sy;
/* Free old tree and create a new root. */
layout_free(w);
lc = w->layout_root = layout_create_cell(NULL);
layout_set_size(lc, mainw + otherw + 1, sy, 0, 0);
layout_make_node(lc, LAYOUT_LEFTRIGHT);
/* Create the other pane. */
lcother = layout_create_cell(lc);
layout_set_size(lcother, otherw, sy, 0, 0);
if (n == 1) {
wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry);
layout_make_leaf(lcother, wp);
TAILQ_INSERT_TAIL(&lc->cells, lcother, entry);
} else {
layout_make_node(lcother, LAYOUT_TOPBOTTOM);
TAILQ_INSERT_TAIL(&lc->cells, lcother, entry);
/* Add the remaining panes as children. */
TAILQ_FOREACH(wp, &w->panes, entry) {
if (wp == TAILQ_FIRST(&w->panes))
continue;
lcchild = layout_create_cell(lcother);
layout_set_size(lcchild, otherw, PANE_MINIMUM, 0, 0);
layout_make_leaf(lcchild, wp);
TAILQ_INSERT_TAIL(&lcother->cells, lcchild, entry);
}
layout_spread_cell(w, lcother);
}
/* Create the main pane. */
lcmain = layout_create_cell(lc);
layout_set_size(lcmain, mainw, sy, 0, 0);
layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes));
TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry);
/* Fix cell offsets. */
layout_fix_offsets(w);
layout_fix_panes(w, NULL);
layout_print_cell(w->layout_root, __func__, 1);
window_resize(w, lc->sx, lc->sy, -1, -1);
notify_window("window-layout-changed", w);
server_redraw_window(w);
}
void void
layout_set_tiled(struct window *w) layout_set_tiled(struct window *w)
{ {

110
layout.c
View File

@ -275,8 +275,7 @@ layout_cell_is_bottom(struct window *w, struct layout_cell *lc)
* the case for the most upper or lower panes only. * the case for the most upper or lower panes only.
*/ */
static int static int
layout_add_horizontal_border(struct window *w, struct layout_cell *lc, layout_add_border(struct window *w, struct layout_cell *lc, int status)
int status)
{ {
if (status == PANE_STATUS_TOP) if (status == PANE_STATUS_TOP)
return (layout_cell_is_top(w, lc)); return (layout_cell_is_top(w, lc));
@ -291,53 +290,22 @@ layout_fix_panes(struct window *w, struct window_pane *skip)
{ {
struct window_pane *wp; struct window_pane *wp;
struct layout_cell *lc; struct layout_cell *lc;
int status, scrollbars, sb_pos, sb_w, sb_pad; int status;
u_int sx, sy;
status = options_get_number(w->options, "pane-border-status"); status = options_get_number(w->options, "pane-border-status");
scrollbars = options_get_number(w->options, "pane-scrollbars");
sb_pos = options_get_number(w->options, "pane-scrollbars-position");
TAILQ_FOREACH(wp, &w->panes, entry) { TAILQ_FOREACH(wp, &w->panes, entry) {
if ((lc = wp->layout_cell) == NULL || wp == skip) if ((lc = wp->layout_cell) == NULL || wp == skip)
continue; continue;
wp->xoff = lc->xoff; wp->xoff = lc->xoff;
wp->yoff = lc->yoff; wp->yoff = lc->yoff;
sx = lc->sx;
sy = lc->sy;
if (layout_add_horizontal_border(w, lc, status)) { if (layout_add_border(w, lc, status)) {
if (status == PANE_STATUS_TOP) if (status == PANE_STATUS_TOP)
wp->yoff++; wp->yoff++;
sy--; window_pane_resize(wp, lc->sx, lc->sy - 1);
} } else
window_pane_resize(wp, lc->sx, lc->sy);
if (window_pane_show_scrollbar(wp, scrollbars)) {
sb_w = wp->scrollbar_style.width;
sb_pad = wp->scrollbar_style.pad;
if (sb_w < 1)
sb_w = 1;
if (sb_pad < 0)
sb_pad = 0;
if (sb_pos == PANE_SCROLLBARS_LEFT) {
if ((int)sx - sb_w < PANE_MINIMUM) {
wp->xoff = wp->xoff +
(int)sx - PANE_MINIMUM;
sx = PANE_MINIMUM;
} else {
sx = sx - sb_w - sb_pad;
wp->xoff = wp->xoff + sb_w + sb_pad;
}
} else /* sb_pos == PANE_SCROLLBARS_RIGHT */
if ((int)sx - sb_w - sb_pad < PANE_MINIMUM)
sx = PANE_MINIMUM;
else
sx = sx - sb_w - sb_pad;
wp->flags |= PANE_REDRAWSCROLLBAR;
}
window_pane_resize(wp, sx, sy);
} }
} }
@ -368,25 +336,18 @@ layout_resize_check(struct window *w, struct layout_cell *lc,
enum layout_type type) enum layout_type type)
{ {
struct layout_cell *lcchild; struct layout_cell *lcchild;
struct style *sb_style = &w->active->scrollbar_style;
u_int available, minimum; u_int available, minimum;
int status, scrollbars; int status;
status = options_get_number(w->options, "pane-border-status"); status = options_get_number(w->options, "pane-border-status");
scrollbars = options_get_number(w->options, "pane-scrollbars");
if (lc->type == LAYOUT_WINDOWPANE) { if (lc->type == LAYOUT_WINDOWPANE) {
/* Space available in this cell only. */ /* Space available in this cell only. */
if (type == LAYOUT_LEFTRIGHT) { if (type == LAYOUT_LEFTRIGHT) {
available = lc->sx; available = lc->sx;
if (scrollbars) minimum = PANE_MINIMUM;
minimum = PANE_MINIMUM + sb_style->width +
sb_style->pad;
else
minimum = PANE_MINIMUM;
} else { } else {
available = lc->sy; available = lc->sy;
if (layout_add_horizontal_border(w, lc, status)) if (layout_add_border(w, lc, status))
minimum = PANE_MINIMUM + 1; minimum = PANE_MINIMUM + 1;
else else
minimum = PANE_MINIMUM; minimum = PANE_MINIMUM;
@ -908,12 +869,10 @@ struct layout_cell *
layout_split_pane(struct window_pane *wp, enum layout_type type, int size, layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
int flags) int flags)
{ {
struct layout_cell *lc, *lcparent, *lcnew, *lc1, *lc2; struct layout_cell *lc, *lcparent, *lcnew, *lc1, *lc2;
struct style *sb_style = &wp->scrollbar_style; u_int sx, sy, xoff, yoff, size1, size2, minimum;
u_int sx, sy, xoff, yoff, size1, size2, minimum; u_int new_size, saved_size, resize_first = 0;
u_int new_size, saved_size, resize_first = 0; int full_size = (flags & SPAWN_FULLSIZE), status;
int full_size = (flags & SPAWN_FULLSIZE), status;
int scrollbars;
/* /*
* If full_size is specified, add a new cell at the top of the window * If full_size is specified, add a new cell at the top of the window
@ -924,7 +883,6 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
else else
lc = wp->layout_cell; lc = wp->layout_cell;
status = options_get_number(wp->window->options, "pane-border-status"); status = options_get_number(wp->window->options, "pane-border-status");
scrollbars = options_get_number(wp->window->options, "pane-scrollbars");
/* Copy the old cell size. */ /* Copy the old cell size. */
sx = lc->sx; sx = lc->sx;
@ -935,16 +893,11 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
/* Check there is enough space for the two new panes. */ /* Check there is enough space for the two new panes. */
switch (type) { switch (type) {
case LAYOUT_LEFTRIGHT: case LAYOUT_LEFTRIGHT:
if (scrollbars) { if (sx < PANE_MINIMUM * 2 + 1)
minimum = PANE_MINIMUM * 2 + sb_style->width +
sb_style->pad;
} else
minimum = PANE_MINIMUM * 2 + 1;
if (sx < minimum)
return (NULL); return (NULL);
break; break;
case LAYOUT_TOPBOTTOM: case LAYOUT_TOPBOTTOM:
if (layout_add_horizontal_border(wp->window, lc, status)) if (layout_add_border(wp->window, lc, status))
minimum = PANE_MINIMUM * 2 + 2; minimum = PANE_MINIMUM * 2 + 2;
else else
minimum = PANE_MINIMUM * 2 + 1; minimum = PANE_MINIMUM * 2 + 1;
@ -1100,9 +1053,8 @@ int
layout_spread_cell(struct window *w, struct layout_cell *parent) layout_spread_cell(struct window *w, struct layout_cell *parent)
{ {
struct layout_cell *lc; struct layout_cell *lc;
struct style *sb_style = &w->active->scrollbar_style; u_int number, each, size, this;
u_int number, each, size, this, remainder; int change, changed, status;
int change, changed, status, scrollbars;
number = 0; number = 0;
TAILQ_FOREACH (lc, &parent->cells, entry) TAILQ_FOREACH (lc, &parent->cells, entry)
@ -1110,16 +1062,11 @@ layout_spread_cell(struct window *w, struct layout_cell *parent)
if (number <= 1) if (number <= 1)
return (0); return (0);
status = options_get_number(w->options, "pane-border-status"); status = options_get_number(w->options, "pane-border-status");
scrollbars = options_get_number(w->options, "pane-scrollbars");
if (parent->type == LAYOUT_LEFTRIGHT) { if (parent->type == LAYOUT_LEFTRIGHT)
if (scrollbars) size = parent->sx;
size = parent->sx - sb_style->width + sb_style->pad;
else
size = parent->sx;
}
else if (parent->type == LAYOUT_TOPBOTTOM) { else if (parent->type == LAYOUT_TOPBOTTOM) {
if (layout_add_horizontal_border(w, parent, status)) if (layout_add_border(w, parent, status))
size = parent->sy - 1; size = parent->sy - 1;
else else
size = parent->sy; size = parent->sy;
@ -1130,31 +1077,20 @@ layout_spread_cell(struct window *w, struct layout_cell *parent)
each = (size - (number - 1)) / number; each = (size - (number - 1)) / number;
if (each == 0) if (each == 0)
return (0); return (0);
/*
* Remaining space after assigning that which can be evenly
* distributed.
*/
remainder = size - (number * (each + 1)) + 1;
changed = 0; changed = 0;
TAILQ_FOREACH (lc, &parent->cells, entry) { TAILQ_FOREACH (lc, &parent->cells, entry) {
if (TAILQ_NEXT(lc, entry) == NULL)
each = size - ((each + 1) * (number - 1));
change = 0; change = 0;
if (parent->type == LAYOUT_LEFTRIGHT) { if (parent->type == LAYOUT_LEFTRIGHT) {
change = each - (int)lc->sx; change = each - (int)lc->sx;
if (remainder > 0) {
change++;
remainder--;
}
layout_resize_adjust(w, lc, LAYOUT_LEFTRIGHT, change); layout_resize_adjust(w, lc, LAYOUT_LEFTRIGHT, change);
} else if (parent->type == LAYOUT_TOPBOTTOM) { } else if (parent->type == LAYOUT_TOPBOTTOM) {
if (layout_add_horizontal_border(w, lc, status)) if (layout_add_border(w, lc, status))
this = each + 1; this = each + 1;
else else
this = each; this = each;
if (remainder > 0) {
this++;
remainder--;
}
change = this - (int)lc->sy; change = this - (int)lc->sy;
layout_resize_adjust(w, lc, LAYOUT_TOPBOTTOM, change); layout_resize_adjust(w, lc, LAYOUT_TOPBOTTOM, change);
} }

186
menu.c
View File

@ -27,11 +27,6 @@ struct menu_data {
struct cmdq_item *item; struct cmdq_item *item;
int flags; int flags;
struct grid_cell style;
struct grid_cell border_style;
struct grid_cell selected_style;
enum box_lines border_lines;
struct cmd_find_state fs; struct cmd_find_state fs;
struct screen s; struct screen s;
@ -69,8 +64,6 @@ menu_add_item(struct menu *menu, const struct menu_item *item,
line = (item == NULL || item->name == NULL || *item->name == '\0'); line = (item == NULL || item->name == NULL || *item->name == '\0');
if (line && menu->count == 0) if (line && menu->count == 0)
return; return;
if (line && menu->items[menu->count - 1].name == NULL)
return;
menu->items = xreallocarray(menu->items, menu->count + 1, menu->items = xreallocarray(menu->items, menu->count + 1,
sizeof *menu->items); sizeof *menu->items);
@ -167,16 +160,11 @@ menu_free(struct menu *menu)
} }
struct screen * struct screen *
menu_mode_cb(__unused struct client *c, void *data, u_int *cx, u_int *cy) menu_mode_cb(__unused struct client *c, void *data, __unused u_int *cx,
__unused u_int *cy)
{ {
struct menu_data *md = data; struct menu_data *md = data;
*cx = md->px + 2;
if (md->choice == -1)
*cy = md->py;
else
*cy = md->py + 1 + md->choice;
return (&md->s); return (&md->s);
} }
@ -202,17 +190,13 @@ menu_draw_cb(struct client *c, void *data,
struct menu *menu = md->menu; struct menu *menu = md->menu;
struct screen_write_ctx ctx; struct screen_write_ctx ctx;
u_int i, px = md->px, py = md->py; u_int i, px = md->px, py = md->py;
struct grid_cell gc;
style_apply(&gc, c->session->curw->window->options, "mode-style", NULL);
screen_write_start(&ctx, s); screen_write_start(&ctx, s);
screen_write_clearscreen(&ctx, 8); screen_write_clearscreen(&ctx, 8);
screen_write_menu(&ctx, menu, md->choice, &gc);
if (md->border_lines != BOX_LINES_NONE) {
screen_write_box(&ctx, menu->width + 4, menu->count + 2,
md->border_lines, &md->border_style, menu->title);
}
screen_write_menu(&ctx, menu, md->choice, md->border_lines,
&md->style, &md->border_style, &md->selected_style);
screen_write_stop(&ctx); screen_write_stop(&ctx);
for (i = 0; i < screen_size_y(&md->s); i++) { for (i = 0; i < screen_size_y(&md->s); i++) {
@ -334,73 +318,36 @@ menu_key_cb(struct client *c, void *data, struct key_event *event)
} while ((name == NULL || *name == '-') && md->choice != old); } while ((name == NULL || *name == '-') && md->choice != old);
c->flags |= CLIENT_REDRAWOVERLAY; c->flags |= CLIENT_REDRAWOVERLAY;
return (0); return (0);
case KEYC_PPAGE:
case 'b'|KEYC_CTRL:
if (md->choice < 6)
md->choice = 0;
else {
i = 5;
while (i > 0) {
md->choice--;
name = menu->items[md->choice].name;
if (md->choice != 0 &&
(name != NULL && *name != '-'))
i--;
else if (md->choice == 0)
break;
}
}
c->flags |= CLIENT_REDRAWOVERLAY;
break;
case KEYC_NPAGE:
if (md->choice > count - 6) {
md->choice = count - 1;
name = menu->items[md->choice].name;
} else {
i = 5;
while (i > 0) {
md->choice++;
name = menu->items[md->choice].name;
if (md->choice != count - 1 &&
(name != NULL && *name != '-'))
i++;
else if (md->choice == count - 1)
break;
}
}
while (name == NULL || *name == '-') {
md->choice--;
name = menu->items[md->choice].name;
}
c->flags |= CLIENT_REDRAWOVERLAY;
break;
case 'g': case 'g':
case KEYC_HOME: case KEYC_PPAGE:
md->choice = 0; case '\002': /* C-b */
name = menu->items[md->choice].name; if (md->choice > 5)
while (name == NULL || *name == '-') { md->choice -= 5;
else
md->choice = 0;
while (md->choice != count && (name == NULL || *name == '-'))
md->choice++; md->choice++;
name = menu->items[md->choice].name; if (md->choice == count)
} md->choice = -1;
c->flags |= CLIENT_REDRAWOVERLAY; c->flags |= CLIENT_REDRAWOVERLAY;
break; break;
case 'G': case 'G':
case KEYC_END: case KEYC_NPAGE:
md->choice = count - 1; if (md->choice > count - 6)
name = menu->items[md->choice].name; md->choice = count - 1;
while (name == NULL || *name == '-') { else
md->choice += 5;
while (md->choice != -1 && (name == NULL || *name == '-'))
md->choice--; md->choice--;
name = menu->items[md->choice].name;
}
c->flags |= CLIENT_REDRAWOVERLAY; c->flags |= CLIENT_REDRAWOVERLAY;
break; break;
case 'f'|KEYC_CTRL: case '\006': /* C-f */
break; break;
case '\r': case '\r':
goto chosen; goto chosen;
case '\033': /* Escape */ case '\033': /* Escape */
case 'c'|KEYC_CTRL: case '\003': /* C-c */
case 'g'|KEYC_CTRL: case '\007': /* C-g */
case 'q': case 'q':
return (1); return (1);
} }
@ -437,35 +384,14 @@ chosen:
return (1); return (1);
} }
static void
menu_set_style(struct client *c, struct grid_cell *gc, const char *style,
const char *option)
{
struct style sytmp;
struct options *o = c->session->curw->window->options;
memcpy(gc, &grid_default_cell, sizeof *gc);
style_apply(gc, o, option, NULL);
if (style != NULL) {
style_set(&sytmp, &grid_default_cell);
if (style_parse(&sytmp, gc, style) == 0) {
gc->fg = sytmp.gc.fg;
gc->bg = sytmp.gc.bg;
}
}
}
struct menu_data * struct menu_data *
menu_prepare(struct menu *menu, int flags, int starting_choice, menu_prepare(struct menu *menu, int flags, struct cmdq_item *item, u_int px,
struct cmdq_item *item, u_int px, u_int py, struct client *c, u_int py, struct client *c, struct cmd_find_state *fs, menu_choice_cb cb,
enum box_lines lines, const char *style, const char *selected_style,
const char *border_style, struct cmd_find_state *fs, menu_choice_cb cb,
void *data) void *data)
{ {
struct menu_data *md; struct menu_data *md;
int choice; u_int i;
const char *name; const char *name;
struct options *o = c->session->curw->window->options;
if (c->tty.sx < menu->width + 4 || c->tty.sy < menu->count + 2) if (c->tty.sx < menu->width + 4 || c->tty.sy < menu->count + 2)
return (NULL); return (NULL);
@ -474,18 +400,9 @@ menu_prepare(struct menu *menu, int flags, int starting_choice,
if (py + menu->count + 2 > c->tty.sy) if (py + menu->count + 2 > c->tty.sy)
py = c->tty.sy - menu->count - 2; py = c->tty.sy - menu->count - 2;
if (lines == BOX_LINES_DEFAULT)
lines = options_get_number(o, "menu-border-lines");
md = xcalloc(1, sizeof *md); md = xcalloc(1, sizeof *md);
md->item = item; md->item = item;
md->flags = flags; md->flags = flags;
md->border_lines = lines;
menu_set_style(c, &md->style, style, "menu-style");
menu_set_style(c, &md->selected_style, selected_style,
"menu-selected-style");
menu_set_style(c, &md->border_style, border_style, "menu-border-style");
if (fs != NULL) if (fs != NULL)
cmd_find_copy_state(&md->fs, fs); cmd_find_copy_state(&md->fs, fs);
@ -498,38 +415,18 @@ menu_prepare(struct menu *menu, int flags, int starting_choice,
md->py = py; md->py = py;
md->menu = menu; md->menu = menu;
md->choice = -1;
if (md->flags & MENU_NOMOUSE) { if (md->flags & MENU_NOMOUSE) {
if (starting_choice >= (int)menu->count) { for (i = 0; i < menu->count; i++) {
starting_choice = menu->count - 1; name = menu->items[i].name;
choice = starting_choice + 1; if (name != NULL && *name != '-')
for (;;) { break;
name = menu->items[choice - 1].name;
if (name != NULL && *name != '-') {
md->choice = choice - 1;
break;
}
if (--choice == 0)
choice = menu->count;
if (choice == starting_choice + 1)
break;
}
} else if (starting_choice >= 0) {
choice = starting_choice;
for (;;) {
name = menu->items[choice].name;
if (name != NULL && *name != '-') {
md->choice = choice;
break;
}
if (++choice == (int)menu->count)
choice = 0;
if (choice == starting_choice)
break;
}
} }
} if (i != menu->count)
md->choice = i;
else
md->choice = -1;
} else
md->choice = -1;
md->cb = cb; md->cb = cb;
md->data = data; md->data = data;
@ -537,16 +434,13 @@ menu_prepare(struct menu *menu, int flags, int starting_choice,
} }
int int
menu_display(struct menu *menu, int flags, int starting_choice, menu_display(struct menu *menu, int flags, struct cmdq_item *item, u_int px,
struct cmdq_item *item, u_int px, u_int py, struct client *c, u_int py, struct client *c, struct cmd_find_state *fs, menu_choice_cb cb,
enum box_lines lines, const char *style, const char *selected_style,
const char *border_style, struct cmd_find_state *fs, menu_choice_cb cb,
void *data) void *data)
{ {
struct menu_data *md; struct menu_data *md;
md = menu_prepare(menu, flags, starting_choice, item, px, py, c, lines, md = menu_prepare(menu, flags, item, px, py, c, fs, cb, data);
style, selected_style, border_style, fs, cb, data);
if (md == NULL) if (md == NULL)
return (-1); return (-1);
server_client_set_overlay(c, 0, NULL, menu_mode_cb, menu_draw_cb, server_client_set_overlay(c, 0, NULL, menu_mode_cb, menu_draw_cb,

View File

@ -25,17 +25,6 @@
#include "tmux.h" #include "tmux.h"
enum mode_tree_search_dir {
MODE_TREE_SEARCH_FORWARD,
MODE_TREE_SEARCH_BACKWARD
};
enum mode_tree_preview {
MODE_TREE_PREVIEW_OFF,
MODE_TREE_PREVIEW_NORMAL,
MODE_TREE_PREVIEW_BIG
};
struct mode_tree_item; struct mode_tree_item;
TAILQ_HEAD(mode_tree_list, mode_tree_item); TAILQ_HEAD(mode_tree_list, mode_tree_item);
@ -58,7 +47,6 @@ struct mode_tree_data {
mode_tree_menu_cb menucb; mode_tree_menu_cb menucb;
mode_tree_height_cb heightcb; mode_tree_height_cb heightcb;
mode_tree_key_cb keycb; mode_tree_key_cb keycb;
mode_tree_swap_cb swapcb;
struct mode_tree_list children; struct mode_tree_list children;
struct mode_tree_list saved; struct mode_tree_list saved;
@ -67,7 +55,6 @@ struct mode_tree_data {
u_int line_size; u_int line_size;
u_int depth; u_int depth;
u_int maxdepth;
u_int width; u_int width;
u_int height; u_int height;
@ -81,7 +68,6 @@ struct mode_tree_data {
char *search; char *search;
char *filter; char *filter;
int no_matches; int no_matches;
enum mode_tree_search_dir search_dir;
}; };
struct mode_tree_item { struct mode_tree_item {
@ -102,7 +88,6 @@ struct mode_tree_item {
int draw_as_parent; int draw_as_parent;
int no_tag; int no_tag;
int align;
struct mode_tree_list children; struct mode_tree_list children;
TAILQ_ENTRY(mode_tree_item) entry; TAILQ_ENTRY(mode_tree_item) entry;
@ -199,8 +184,6 @@ mode_tree_build_lines(struct mode_tree_data *mtd,
int flat = 1; int flat = 1;
mtd->depth = depth; mtd->depth = depth;
if (depth > mtd->maxdepth)
mtd->maxdepth = depth;
TAILQ_FOREACH(mti, mtl, entry) { TAILQ_FOREACH(mti, mtl, entry) {
mtd->line_list = xreallocarray(mtd->line_list, mtd->line_list = xreallocarray(mtd->line_list,
mtd->line_size + 1, sizeof *mtd->line_list); mtd->line_size + 1, sizeof *mtd->line_list);
@ -272,50 +255,19 @@ mode_tree_up(struct mode_tree_data *mtd, int wrap)
} }
} }
int void
mode_tree_down(struct mode_tree_data *mtd, int wrap) mode_tree_down(struct mode_tree_data *mtd, int wrap)
{ {
if (mtd->current == mtd->line_size - 1) { if (mtd->current == mtd->line_size - 1) {
if (wrap) { if (wrap) {
mtd->current = 0; mtd->current = 0;
mtd->offset = 0; mtd->offset = 0;
} else }
return (0);
} else { } else {
mtd->current++; mtd->current++;
if (mtd->current > mtd->offset + mtd->height - 1) if (mtd->current > mtd->offset + mtd->height - 1)
mtd->offset++; mtd->offset++;
} }
return (1);
}
static void
mode_tree_swap(struct mode_tree_data *mtd, int direction)
{
u_int current_depth = mtd->line_list[mtd->current].depth;
u_int swap_with, swap_with_depth;
if (mtd->swapcb == NULL)
return;
/* Find the next line at the same depth with the same parent . */
swap_with = mtd->current;
do {
if (direction < 0 && swap_with < (u_int)-direction)
return;
if (direction > 0 && swap_with + direction >= mtd->line_size)
return;
swap_with += direction;
swap_with_depth = mtd->line_list[swap_with].depth;
} while (swap_with_depth > current_depth);
if (swap_with_depth != current_depth)
return;
if (mtd->swapcb(mtd->line_list[mtd->current].item->itemdata,
mtd->line_list[swap_with].item->itemdata)) {
mtd->current = swap_with;
mode_tree_build(mtd);
}
} }
void * void *
@ -390,13 +342,8 @@ mode_tree_set_current(struct mode_tree_data *mtd, uint64_t tag)
mtd->offset = 0; mtd->offset = 0;
return (1); return (1);
} }
if (mtd->current >= mtd->line_size) { mtd->current = 0;
mtd->current = mtd->line_size - 1; mtd->offset = 0;
if (mtd->current > mtd->height - 1)
mtd->offset = mtd->current - mtd->height + 1;
else
mtd->offset = 0;
}
return (0); return (0);
} }
@ -441,9 +388,9 @@ struct mode_tree_data *
mode_tree_start(struct window_pane *wp, struct args *args, mode_tree_start(struct window_pane *wp, struct args *args,
mode_tree_build_cb buildcb, mode_tree_draw_cb drawcb, mode_tree_build_cb buildcb, mode_tree_draw_cb drawcb,
mode_tree_search_cb searchcb, mode_tree_menu_cb menucb, mode_tree_search_cb searchcb, mode_tree_menu_cb menucb,
mode_tree_height_cb heightcb, mode_tree_key_cb keycb, mode_tree_height_cb heightcb, mode_tree_key_cb keycb, void *modedata,
mode_tree_swap_cb swapcb, void *modedata, const struct menu_item *menu, const struct menu_item *menu, const char **sort_list, u_int sort_size,
const char **sort_list, u_int sort_size, struct screen **s) struct screen **s)
{ {
struct mode_tree_data *mtd; struct mode_tree_data *mtd;
const char *sort; const char *sort;
@ -459,12 +406,7 @@ mode_tree_start(struct window_pane *wp, struct args *args,
mtd->sort_list = sort_list; mtd->sort_list = sort_list;
mtd->sort_size = sort_size; mtd->sort_size = sort_size;
if (args_has(args, 'N') > 1) mtd->preview = !args_has(args, 'N');
mtd->preview = MODE_TREE_PREVIEW_BIG;
else if (args_has(args, 'N'))
mtd->preview = MODE_TREE_PREVIEW_OFF;
else
mtd->preview = MODE_TREE_PREVIEW_NORMAL;
sort = args_get(args, 'O'); sort = args_get(args, 'O');
if (sort != NULL) { if (sort != NULL) {
@ -486,7 +428,6 @@ mode_tree_start(struct window_pane *wp, struct args *args,
mtd->menucb = menucb; mtd->menucb = menucb;
mtd->heightcb = heightcb; mtd->heightcb = heightcb;
mtd->keycb = keycb; mtd->keycb = keycb;
mtd->swapcb = swapcb;
TAILQ_INIT(&mtd->children); TAILQ_INIT(&mtd->children);
@ -521,21 +462,12 @@ mode_tree_set_height(struct mode_tree_data *mtd)
if (height < screen_size_y(s)) if (height < screen_size_y(s))
mtd->height = screen_size_y(s) - height; mtd->height = screen_size_y(s) - height;
} else { } else {
if (mtd->preview == MODE_TREE_PREVIEW_NORMAL) { mtd->height = (screen_size_y(s) / 3) * 2;
mtd->height = (screen_size_y(s) / 3) * 2; if (mtd->height > mtd->line_size)
if (mtd->height > mtd->line_size) mtd->height = screen_size_y(s) / 2;
mtd->height = screen_size_y(s) / 2;
if (mtd->height < 10)
mtd->height = screen_size_y(s);
} else if (mtd->preview == MODE_TREE_PREVIEW_BIG) {
mtd->height = screen_size_y(s) / 4;
if (mtd->height > mtd->line_size)
mtd->height = mtd->line_size;
if (mtd->height < 2)
mtd->height = 2;
} else
mtd->height = screen_size_y(s);
} }
if (mtd->height < 10)
mtd->height = screen_size_y(s);
if (screen_size_y(s) - mtd->height < 2) if (screen_size_y(s) - mtd->height < 2)
mtd->height = screen_size_y(s); mtd->height = screen_size_y(s);
} }
@ -563,15 +495,14 @@ mode_tree_build(struct mode_tree_data *mtd)
TAILQ_INIT(&mtd->saved); TAILQ_INIT(&mtd->saved);
mode_tree_clear_lines(mtd); mode_tree_clear_lines(mtd);
mtd->maxdepth = 0;
mode_tree_build_lines(mtd, &mtd->children, 0); mode_tree_build_lines(mtd, &mtd->children, 0);
if (mtd->line_list != NULL && tag == UINT64_MAX) if (tag == UINT64_MAX)
tag = mtd->line_list[mtd->current].item->tag; tag = mtd->line_list[mtd->current].item->tag;
mode_tree_set_current(mtd, tag); mode_tree_set_current(mtd, tag);
mtd->width = screen_size_x(s); mtd->width = screen_size_x(s);
if (mtd->preview != MODE_TREE_PREVIEW_OFF) if (mtd->preview)
mode_tree_set_height(mtd); mode_tree_set_height(mtd);
else else
mtd->height = screen_size_y(s); mtd->height = screen_size_y(s);
@ -668,16 +599,6 @@ mode_tree_no_tag(struct mode_tree_item *mti)
mti->no_tag = 1; mti->no_tag = 1;
} }
/*
* Set the alignment of mti->name: -1 to align left, 0 (default) to not align,
* or 1 to align right.
*/
void
mode_tree_align(struct mode_tree_item *mti, int align)
{
mti->align = align;
}
void void
mode_tree_remove(struct mode_tree_data *mtd, struct mode_tree_item *mti) mode_tree_remove(struct mode_tree_data *mtd, struct mode_tree_item *mti)
{ {
@ -704,7 +625,7 @@ mode_tree_draw(struct mode_tree_data *mtd)
char *text, *start, *key; char *text, *start, *key;
const char *tag, *symbol; const char *tag, *symbol;
size_t size, n; size_t size, n;
int keylen, pad, alignlen[mtd->maxdepth + 1]; int keylen, pad;
if (mtd->line_size == 0) if (mtd->line_size == 0)
return; return;
@ -728,16 +649,6 @@ mode_tree_draw(struct mode_tree_data *mtd)
keylen = mti->keylen + 3; keylen = mti->keylen + 3;
} }
for (i = 0; i < mtd->maxdepth + 1; i++)
alignlen[i] = 0;
for (i = 0; i < mtd->line_size; i++) {
line = &mtd->line_list[i];
mti = line->item;
if (mti->align &&
(int)strlen(mti->name) > alignlen[line->depth])
alignlen[line->depth] = strlen(mti->name);
}
for (i = 0; i < mtd->line_size; i++) { for (i = 0; i < mtd->line_size; i++) {
if (i < mtd->offset) if (i < mtd->offset)
continue; continue;
@ -787,9 +698,8 @@ mode_tree_draw(struct mode_tree_data *mtd)
tag = "*"; tag = "*";
else else
tag = ""; tag = "";
xasprintf(&text, "%-*s%s%*s%s%s", keylen, key, start, xasprintf(&text, "%-*s%s%s%s%s", keylen, key, start, mti->name,
mti->align * alignlen[line->depth], mti->name, tag, tag, (mti->text != NULL) ? ": " : "" );
(mti->text != NULL) ? ": " : "" );
width = utf8_cstrwidth(text); width = utf8_cstrwidth(text);
if (width > w) if (width > w)
width = w; width = w;
@ -824,11 +734,8 @@ mode_tree_draw(struct mode_tree_data *mtd)
} }
} }
if (mtd->preview == MODE_TREE_PREVIEW_OFF)
goto done;
sy = screen_size_y(s); sy = screen_size_y(s);
if (sy <= 4 || h < 2 || sy - h <= 4 || w <= 4) if (!mtd->preview || sy <= 4 || h <= 4 || sy - h <= 4 || w <= 4)
goto done; goto done;
line = &mtd->line_list[mtd->current]; line = &mtd->line_list[mtd->current];
@ -879,49 +786,7 @@ done:
} }
static struct mode_tree_item * static struct mode_tree_item *
mode_tree_search_backward(struct mode_tree_data *mtd) mode_tree_search_for(struct mode_tree_data *mtd)
{
struct mode_tree_item *mti, *last, *prev;
if (mtd->search == NULL)
return (NULL);
mti = last = mtd->line_list[mtd->current].item;
for (;;) {
if ((prev = TAILQ_PREV(mti, mode_tree_list, entry)) != NULL) {
/* Point to the last child in the previous subtree. */
while (!TAILQ_EMPTY(&prev->children))
prev = TAILQ_LAST(&prev->children, mode_tree_list);
mti = prev;
} else {
/* If prev is NULL, jump to the parent. */
mti = mti->parent;
}
if (mti == NULL) {
/* Point to the last child in the last root subtree. */
prev = TAILQ_LAST(&mtd->children, mode_tree_list);
while (!TAILQ_EMPTY(&prev->children))
prev = TAILQ_LAST(&prev->children, mode_tree_list);
mti = prev;
}
if (mti == last)
break;
if (mtd->searchcb == NULL) {
if (strstr(mti->name, mtd->search) != NULL)
return (mti);
continue;
}
if (mtd->searchcb(mtd->modedata, mti->itemdata, mtd->search))
return (mti);
}
return (NULL);
}
static struct mode_tree_item *
mode_tree_search_forward(struct mode_tree_data *mtd)
{ {
struct mode_tree_item *mti, *last, *next; struct mode_tree_item *mti, *last, *next;
@ -967,10 +832,7 @@ mode_tree_search_set(struct mode_tree_data *mtd)
struct mode_tree_item *mti, *loop; struct mode_tree_item *mti, *loop;
uint64_t tag; uint64_t tag;
if (mtd->search_dir == MODE_TREE_SEARCH_FORWARD) mti = mode_tree_search_for(mtd);
mti = mode_tree_search_forward(mtd);
else
mti = mode_tree_search_backward(mtd);
if (mti == NULL) if (mti == NULL)
return; return;
tag = mti->tag; tag = mti->tag;
@ -1100,12 +962,9 @@ mode_tree_display_menu(struct mode_tree_data *mtd, struct client *c, u_int x,
x -= (menu->width + 4) / 2; x -= (menu->width + 4) / 2;
else else
x = 0; x = 0;
if (menu_display(menu, 0, 0, NULL, x, y, c, BOX_LINES_DEFAULT, NULL, if (menu_display(menu, 0, NULL, x, y, c, NULL, mode_tree_menu_callback,
NULL, NULL, NULL, mode_tree_menu_callback, mtm) != 0) { mtm) != 0)
mode_tree_remove_ref(mtd);
free(mtm);
menu_free(menu); menu_free(menu);
}
} }
int int
@ -1129,7 +988,7 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
if (x > mtd->width || y > mtd->height) { if (x > mtd->width || y > mtd->height) {
if (*key == KEYC_MOUSEDOWN3_PANE) if (*key == KEYC_MOUSEDOWN3_PANE)
mode_tree_display_menu(mtd, c, x, y, 1); mode_tree_display_menu(mtd, c, x, y, 1);
if (mtd->preview == MODE_TREE_PREVIEW_OFF) if (!mtd->preview)
*key = KEYC_NONE; *key = KEYC_NONE;
return (0); return (0);
} }
@ -1176,30 +1035,22 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
switch (*key) { switch (*key) {
case 'q': case 'q':
case '\033': /* Escape */ case '\033': /* Escape */
case 'g'|KEYC_CTRL: case '\007': /* C-g */
return (1); return (1);
case KEYC_UP: case KEYC_UP:
case 'k': case 'k':
case KEYC_WHEELUP_PANE: case KEYC_WHEELUP_PANE:
case 'p'|KEYC_CTRL: case '\020': /* C-p */
mode_tree_up(mtd, 1); mode_tree_up(mtd, 1);
break; break;
case KEYC_DOWN: case KEYC_DOWN:
case 'j': case 'j':
case KEYC_WHEELDOWN_PANE: case KEYC_WHEELDOWN_PANE:
case 'n'|KEYC_CTRL: case '\016': /* C-n */
mode_tree_down(mtd, 1); mode_tree_down(mtd, 1);
break; break;
case KEYC_UP|KEYC_SHIFT:
case 'K':
mode_tree_swap(mtd, -1);
break;
case KEYC_DOWN|KEYC_SHIFT:
case 'J':
mode_tree_swap(mtd, 1);
break;
case KEYC_PPAGE: case KEYC_PPAGE:
case 'b'|KEYC_CTRL: case '\002': /* C-b */
for (i = 0; i < mtd->height; i++) { for (i = 0; i < mtd->height; i++) {
if (mtd->current == 0) if (mtd->current == 0)
break; break;
@ -1207,7 +1058,7 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
} }
break; break;
case KEYC_NPAGE: case KEYC_NPAGE:
case 'f'|KEYC_CTRL: case '\006': /* C-f */
for (i = 0; i < mtd->height; i++) { for (i = 0; i < mtd->height; i++) {
if (mtd->current == mtd->line_size - 1) if (mtd->current == mtd->line_size - 1)
break; break;
@ -1251,7 +1102,7 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
for (i = 0; i < mtd->line_size; i++) for (i = 0; i < mtd->line_size; i++)
mtd->line_list[i].item->tagged = 0; mtd->line_list[i].item->tagged = 0;
break; break;
case 't'|KEYC_CTRL: case '\024': /* C-t */
for (i = 0; i < mtd->line_size; i++) { for (i = 0; i < mtd->line_size; i++) {
if ((mtd->line_list[i].item->parent == NULL && if ((mtd->line_list[i].item->parent == NULL &&
!mtd->line_list[i].item->no_tag) || !mtd->line_list[i].item->no_tag) ||
@ -1307,18 +1158,13 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
break; break;
case '?': case '?':
case '/': case '/':
case 's'|KEYC_CTRL: case '\023': /* C-s */
mtd->references++; mtd->references++;
status_prompt_set(c, NULL, "(search) ", "", status_prompt_set(c, NULL, "(search) ", "",
mode_tree_search_callback, mode_tree_search_free, mtd, mode_tree_search_callback, mode_tree_search_free, mtd,
PROMPT_NOFORMAT, PROMPT_TYPE_SEARCH); PROMPT_NOFORMAT, PROMPT_TYPE_SEARCH);
break; break;
case 'n': case 'n':
mtd->search_dir = MODE_TREE_SEARCH_FORWARD;
mode_tree_search_set(mtd);
break;
case 'N':
mtd->search_dir = MODE_TREE_SEARCH_BACKWARD;
mode_tree_search_set(mtd); mode_tree_search_set(mtd);
break; break;
case 'f': case 'f':
@ -1328,19 +1174,9 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
PROMPT_NOFORMAT, PROMPT_TYPE_SEARCH); PROMPT_NOFORMAT, PROMPT_TYPE_SEARCH);
break; break;
case 'v': case 'v':
switch (mtd->preview) { mtd->preview = !mtd->preview;
case MODE_TREE_PREVIEW_OFF:
mtd->preview = MODE_TREE_PREVIEW_BIG;
break;
case MODE_TREE_PREVIEW_NORMAL:
mtd->preview = MODE_TREE_PREVIEW_OFF;
break;
case MODE_TREE_PREVIEW_BIG:
mtd->preview = MODE_TREE_PREVIEW_NORMAL;
break;
}
mode_tree_build(mtd); mode_tree_build(mtd);
if (mtd->preview != MODE_TREE_PREVIEW_OFF) if (mtd->preview)
mode_tree_check_selected(mtd); mode_tree_check_selected(mtd);
break; break;
} }
@ -1362,7 +1198,7 @@ mode_tree_run_command(struct client *c, struct cmd_find_state *fs,
if (status == CMD_PARSE_ERROR) { if (status == CMD_PARSE_ERROR) {
if (c != NULL) { if (c != NULL) {
*error = toupper((u_char)*error); *error = toupper((u_char)*error);
status_message_set(c, -1, 1, 0, 0, "%s", error); status_message_set(c, -1, 1, 0, "%s", error);
} }
free(error); free(error);
} }

View File

@ -32,7 +32,6 @@ struct notify_entry {
struct session *session; struct session *session;
struct window *window; struct window *window;
int pane; int pane;
const char *pbname;
}; };
static struct cmdq_item * static struct cmdq_item *
@ -150,10 +149,6 @@ notify_callback(struct cmdq_item *item, void *data)
control_notify_session_closed(ne->session); control_notify_session_closed(ne->session);
if (strcmp(ne->name, "session-window-changed") == 0) if (strcmp(ne->name, "session-window-changed") == 0)
control_notify_session_window_changed(ne->session); control_notify_session_window_changed(ne->session);
if (strcmp(ne->name, "paste-buffer-changed") == 0)
control_notify_paste_buffer_changed(ne->pbname);
if (strcmp(ne->name, "paste-buffer-deleted") == 0)
control_notify_paste_buffer_deleted(ne->pbname);
notify_insert_hook(item, ne); notify_insert_hook(item, ne);
@ -169,7 +164,6 @@ notify_callback(struct cmdq_item *item, void *data)
format_free(ne->formats); format_free(ne->formats);
free((void *)ne->name); free((void *)ne->name);
free((void *)ne->pbname);
free(ne); free(ne);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
@ -177,8 +171,7 @@ notify_callback(struct cmdq_item *item, void *data)
static void static void
notify_add(const char *name, struct cmd_find_state *fs, struct client *c, notify_add(const char *name, struct cmd_find_state *fs, struct client *c,
struct session *s, struct window *w, struct window_pane *wp, struct session *s, struct window *w, struct window_pane *wp)
const char *pbname)
{ {
struct notify_entry *ne; struct notify_entry *ne;
struct cmdq_item *item; struct cmdq_item *item;
@ -193,8 +186,7 @@ notify_add(const char *name, struct cmd_find_state *fs, struct client *c,
ne->client = c; ne->client = c;
ne->session = s; ne->session = s;
ne->window = w; ne->window = w;
ne->pane = (wp != NULL ? (int)wp->id : -1); ne->pane = (wp != NULL ? wp->id : -1);
ne->pbname = (pbname != NULL ? xstrdup(pbname) : NULL);
ne->formats = format_create(NULL, NULL, 0, FORMAT_NOJOBS); ne->formats = format_create(NULL, NULL, 0, FORMAT_NOJOBS);
format_add(ne->formats, "hook", "%s", name); format_add(ne->formats, "hook", "%s", name);
@ -240,7 +232,7 @@ notify_hook(struct cmdq_item *item, const char *name)
ne.client = cmdq_get_client(item); ne.client = cmdq_get_client(item);
ne.session = target->s; ne.session = target->s;
ne.window = target->w; ne.window = target->w;
ne.pane = (target->wp != NULL ? (int)target->wp->id : -1); ne.pane = (target->wp != NULL ? target->wp->id : -1);
ne.formats = format_create(NULL, NULL, 0, FORMAT_NOJOBS); ne.formats = format_create(NULL, NULL, 0, FORMAT_NOJOBS);
format_add(ne.formats, "hook", "%s", name); format_add(ne.formats, "hook", "%s", name);
@ -256,7 +248,7 @@ notify_client(const char *name, struct client *c)
struct cmd_find_state fs; struct cmd_find_state fs;
cmd_find_from_client(&fs, c, 0); cmd_find_from_client(&fs, c, 0);
notify_add(name, &fs, c, NULL, NULL, NULL, NULL); notify_add(name, &fs, c, NULL, NULL, NULL);
} }
void void
@ -268,7 +260,7 @@ notify_session(const char *name, struct session *s)
cmd_find_from_session(&fs, s, 0); cmd_find_from_session(&fs, s, 0);
else else
cmd_find_from_nothing(&fs, 0); cmd_find_from_nothing(&fs, 0);
notify_add(name, &fs, NULL, s, NULL, NULL, NULL); notify_add(name, &fs, NULL, s, NULL, NULL);
} }
void void
@ -277,7 +269,7 @@ notify_winlink(const char *name, struct winlink *wl)
struct cmd_find_state fs; struct cmd_find_state fs;
cmd_find_from_winlink(&fs, wl, 0); cmd_find_from_winlink(&fs, wl, 0);
notify_add(name, &fs, NULL, wl->session, wl->window, NULL, NULL); notify_add(name, &fs, NULL, wl->session, wl->window, NULL);
} }
void void
@ -286,7 +278,7 @@ notify_session_window(const char *name, struct session *s, struct window *w)
struct cmd_find_state fs; struct cmd_find_state fs;
cmd_find_from_session_window(&fs, s, w, 0); cmd_find_from_session_window(&fs, s, w, 0);
notify_add(name, &fs, NULL, s, w, NULL, NULL); notify_add(name, &fs, NULL, s, w, NULL);
} }
void void
@ -295,7 +287,7 @@ notify_window(const char *name, struct window *w)
struct cmd_find_state fs; struct cmd_find_state fs;
cmd_find_from_window(&fs, w, 0); cmd_find_from_window(&fs, w, 0);
notify_add(name, &fs, NULL, NULL, w, NULL, NULL); notify_add(name, &fs, NULL, NULL, w, NULL);
} }
void void
@ -304,20 +296,5 @@ notify_pane(const char *name, struct window_pane *wp)
struct cmd_find_state fs; struct cmd_find_state fs;
cmd_find_from_pane(&fs, wp, 0); cmd_find_from_pane(&fs, wp, 0);
notify_add(name, &fs, NULL, NULL, NULL, wp, NULL); notify_add(name, &fs, NULL, NULL, NULL, wp);
}
void
notify_paste_buffer(const char *pbname, int deleted)
{
struct cmd_find_state fs;
cmd_find_clear_state(&fs, 0);
if (deleted) {
notify_add("paste-buffer-deleted", &fs, NULL, NULL, NULL, NULL,
pbname);
} else {
notify_add("paste-buffer-changed", &fs, NULL, NULL, NULL, NULL,
pbname);
}
} }

View File

@ -41,9 +41,6 @@ static const char *options_table_clock_mode_style_list[] = {
static const char *options_table_status_list[] = { static const char *options_table_status_list[] = {
"off", "on", "2", "3", "4", "5", NULL "off", "on", "2", "3", "4", "5", NULL
}; };
static const char *options_table_message_line_list[] = {
"0", "1", "2", "3", "4", NULL
};
static const char *options_table_status_keys_list[] = { static const char *options_table_status_keys_list[] = {
"emacs", "vi", NULL "emacs", "vi", NULL
}; };
@ -63,12 +60,6 @@ static const char *options_table_cursor_style_list[] = {
"default", "blinking-block", "block", "blinking-underline", "underline", "default", "blinking-block", "block", "blinking-underline", "underline",
"blinking-bar", "bar", NULL "blinking-bar", "bar", NULL
}; };
static const char *options_table_pane_scrollbars_list[] = {
"off", "modal", "on", NULL
};
static const char *options_table_pane_scrollbars_position_list[] = {
"right", "left", NULL
};
static const char *options_table_pane_status_list[] = { static const char *options_table_pane_status_list[] = {
"off", "top", "bottom", NULL "off", "top", "bottom", NULL
}; };
@ -90,21 +81,12 @@ static const char *options_table_window_size_list[] = {
static const char *options_table_remain_on_exit_list[] = { static const char *options_table_remain_on_exit_list[] = {
"off", "on", "failed", NULL "off", "on", "failed", NULL
}; };
static const char *options_table_destroy_unattached_list[] = {
"off", "on", "keep-last", "keep-group", NULL
};
static const char *options_table_detach_on_destroy_list[] = { static const char *options_table_detach_on_destroy_list[] = {
"off", "on", "no-detached", "previous", "next", NULL "off", "on", "no-detached", NULL
}; };
static const char *options_table_extended_keys_list[] = { static const char *options_table_extended_keys_list[] = {
"off", "on", "always", NULL "off", "on", "always", NULL
}; };
static const char *options_table_extended_keys_format_list[] = {
"csi-u", "xterm", NULL
};
static const char *options_table_allow_passthrough_list[] = {
"off", "on", "all", NULL
};
/* Status line format. */ /* Status line format. */
#define OPTIONS_TABLE_STATUS_FORMAT1 \ #define OPTIONS_TABLE_STATUS_FORMAT1 \
@ -213,7 +195,6 @@ const struct options_name_map options_other_names[] = {
{ "display-panes-active-color", "display-panes-active-colour" }, { "display-panes-active-color", "display-panes-active-colour" },
{ "clock-mode-color", "clock-mode-colour" }, { "clock-mode-color", "clock-mode-colour" },
{ "cursor-color", "cursor-colour" }, { "cursor-color", "cursor-colour" },
{ "prompt-cursor-color", "prompt-cursor-colour" },
{ "pane-colors", "pane-colours" }, { "pane-colors", "pane-colours" },
{ NULL, NULL } { NULL, NULL }
}; };
@ -253,15 +234,6 @@ const struct options_table_entry options_table[] = {
"Each entry is an alias and a command separated by '='." "Each entry is an alias and a command separated by '='."
}, },
{ .name = "codepoint-widths",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
.flags = OPTIONS_TABLE_IS_ARRAY,
.default_str = "",
.separator = ",",
.text = "Array of override widths for Unicode codepoints."
},
{ .name = "copy-command", { .name = "copy-command",
.type = OPTIONS_TABLE_STRING, .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER, .scope = OPTIONS_TABLE_SERVER,
@ -285,13 +257,6 @@ const struct options_table_entry options_table[] = {
.text = "Style of the cursor." .text = "Style of the cursor."
}, },
{ .name = "default-client-command",
.type = OPTIONS_TABLE_COMMAND,
.scope = OPTIONS_TABLE_SERVER,
.default_str = "new-session",
.text = "Default command to run when tmux is run without a command."
},
{ .name = "default-terminal", { .name = "default-terminal",
.type = OPTIONS_TABLE_STRING, .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER, .scope = OPTIONS_TABLE_SERVER,
@ -311,7 +276,7 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_SERVER, .scope = OPTIONS_TABLE_SERVER,
.minimum = 0, .minimum = 0,
.maximum = INT_MAX, .maximum = INT_MAX,
.default_num = 10, .default_num = 500,
.unit = "milliseconds", .unit = "milliseconds",
.text = "Time to wait before assuming a key is Escape." .text = "Time to wait before assuming a key is Escape."
}, },
@ -340,14 +305,6 @@ const struct options_table_entry options_table[] = {
"that support it." "that support it."
}, },
{ .name = "extended-keys-format",
.type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_SERVER,
.choices = options_table_extended_keys_format_list,
.default_num = 1,
.text = "The format of emitted extended key sequences."
},
{ .name = "focus-events", { .name = "focus-events",
.type = OPTIONS_TABLE_FLAG, .type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_SERVER, .scope = OPTIONS_TABLE_SERVER,
@ -363,51 +320,6 @@ const struct options_table_entry options_table[] = {
"Empty does not write a history file." "Empty does not write a history file."
}, },
{ .name = "input-buffer-size",
.type = OPTIONS_TABLE_NUMBER,
.scope = OPTIONS_TABLE_SERVER,
.minimum = INPUT_BUF_DEFAULT_SIZE,
.maximum = UINT_MAX,
.default_num = INPUT_BUF_DEFAULT_SIZE,
.text = "Number of bytes accepted in a single input before dropping."
},
{ .name = "menu-style",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
.flags = OPTIONS_TABLE_IS_STYLE,
.default_str = "default",
.separator = ",",
.text = "Default style of menu."
},
{ .name = "menu-selected-style",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
.flags = OPTIONS_TABLE_IS_STYLE,
.default_str = "bg=yellow,fg=black",
.separator = ",",
.text = "Default style of selected menu item."
},
{ .name = "menu-border-style",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
.default_str = "default",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ",",
.text = "Default style of menu borders."
},
{ .name = "menu-border-lines",
.type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_WINDOW,
.choices = options_table_popup_border_lines_list,
.default_num = BOX_LINES_SINGLE,
.text = "Type of characters used to draw menu border lines. Some of "
"these are only supported on terminals with UTF-8 support."
},
{ .name = "message-limit", { .name = "message-limit",
.type = OPTIONS_TABLE_NUMBER, .type = OPTIONS_TABLE_NUMBER,
.scope = OPTIONS_TABLE_SERVER, .scope = OPTIONS_TABLE_SERVER,
@ -417,17 +329,6 @@ const struct options_table_entry options_table[] = {
.text = "Maximum number of server messages to keep." .text = "Maximum number of server messages to keep."
}, },
{ .name = "prefix-timeout",
.type = OPTIONS_TABLE_NUMBER,
.scope = OPTIONS_TABLE_SERVER,
.minimum = 0,
.maximum = INT_MAX,
.default_num = 0,
.unit = "milliseconds",
.text = "The timeout for the prefix key if no subsequent key is "
"pressed. Zero means disabled."
},
{ .name = "prompt-history-limit", { .name = "prompt-history-limit",
.type = OPTIONS_TABLE_NUMBER, .type = OPTIONS_TABLE_NUMBER,
.scope = OPTIONS_TABLE_SERVER, .scope = OPTIONS_TABLE_SERVER,
@ -451,7 +352,7 @@ const struct options_table_entry options_table[] = {
.type = OPTIONS_TABLE_STRING, .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER, .scope = OPTIONS_TABLE_SERVER,
.flags = OPTIONS_TABLE_IS_ARRAY, .flags = OPTIONS_TABLE_IS_ARRAY,
.default_str = "linux*:AX@", .default_str = "",
.separator = ",", .separator = ",",
.text = "List of terminal capabilities overrides." .text = "List of terminal capabilities overrides."
}, },
@ -461,8 +362,7 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_SERVER, .scope = OPTIONS_TABLE_SERVER,
.flags = OPTIONS_TABLE_IS_ARRAY, .flags = OPTIONS_TABLE_IS_ARRAY,
.default_str = "xterm*:clipboard:ccolour:cstyle:focus:title," .default_str = "xterm*:clipboard:ccolour:cstyle:focus:title,"
"screen*:title," "screen*:title",
"rxvt*:ignorefkeys",
.separator = ",", .separator = ",",
.text = "List of terminal features, used if they cannot be " .text = "List of terminal features, used if they cannot be "
"automatically detected." "automatically detected."
@ -479,14 +379,6 @@ const struct options_table_entry options_table[] = {
"'User0', 'User1' and so on." "'User0', 'User1' and so on."
}, },
{ .name = "variation-selector-always-wide",
.type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_SERVER,
.default_num = 1,
.text = "If the Unicode VS16 codepoint should always be treated as a "
"wide character."
},
/* Session options. */ /* Session options. */
{ .name = "activity-action", { .name = "activity-action",
.type = OPTIONS_TABLE_CHOICE, .type = OPTIONS_TABLE_CHOICE,
@ -548,12 +440,11 @@ const struct options_table_entry options_table[] = {
}, },
{ .name = "destroy-unattached", { .name = "destroy-unattached",
.type = OPTIONS_TABLE_CHOICE, .type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_SESSION, .scope = OPTIONS_TABLE_SESSION,
.choices = options_table_destroy_unattached_list,
.default_num = 0, .default_num = 0,
.text = "Whether to destroy sessions when they have no attached " .text = "Whether to destroy sessions when they have no attached "
"clients, or keep the last session whether in the group." "clients."
}, },
{ .name = "detach-on-destroy", { .name = "detach-on-destroy",
@ -611,18 +502,6 @@ const struct options_table_entry options_table[] = {
"If changed, the new value applies only to new panes." "If changed, the new value applies only to new panes."
}, },
{ .name = "initial-repeat-time",
.type = OPTIONS_TABLE_NUMBER,
.scope = OPTIONS_TABLE_SESSION,
.minimum = 0,
.maximum = 2000000,
.default_num = 0,
.unit = "milliseconds",
.text = "Time to wait for a key binding to repeat the first time the "
"key is pressed, if it is bound with the '-r' flag. "
"Subsequent presses use the 'repeat-time' option."
},
{ .name = "key-table", { .name = "key-table",
.type = OPTIONS_TABLE_STRING, .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SESSION, .scope = OPTIONS_TABLE_SESSION,
@ -644,7 +523,7 @@ const struct options_table_entry options_table[] = {
{ .name = "lock-command", { .name = "lock-command",
.type = OPTIONS_TABLE_STRING, .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SESSION, .scope = OPTIONS_TABLE_SESSION,
.default_str = TMUX_LOCK_CMD, .default_str = "lock -np",
.text = "Shell command to run to lock a client." .text = "Shell command to run to lock a client."
}, },
@ -658,21 +537,13 @@ const struct options_table_entry options_table[] = {
"'mode-keys' is set to 'vi'." "'mode-keys' is set to 'vi'."
}, },
{ .name = "message-line",
.type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_SESSION,
.choices = options_table_message_line_list,
.default_num = 0,
.text = "Position (line) of messages and the command prompt."
},
{ .name = "message-style", { .name = "message-style",
.type = OPTIONS_TABLE_STRING, .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SESSION, .scope = OPTIONS_TABLE_SESSION,
.default_str = "bg=yellow,fg=black", .default_str = "bg=yellow,fg=black",
.flags = OPTIONS_TABLE_IS_STYLE, .flags = OPTIONS_TABLE_IS_STYLE,
.separator = ",", .separator = ",",
.text = "Style of messages and the command prompt." .text = "Style of the command prompt."
}, },
{ .name = "mouse", { .name = "mouse",
@ -687,7 +558,7 @@ const struct options_table_entry options_table[] = {
{ .name = "prefix", { .name = "prefix",
.type = OPTIONS_TABLE_KEY, .type = OPTIONS_TABLE_KEY,
.scope = OPTIONS_TABLE_SESSION, .scope = OPTIONS_TABLE_SESSION,
.default_num = 'b'|KEYC_CTRL, .default_num = '\002',
.text = "The prefix key." .text = "The prefix key."
}, },
@ -710,7 +581,7 @@ const struct options_table_entry options_table[] = {
.type = OPTIONS_TABLE_NUMBER, .type = OPTIONS_TABLE_NUMBER,
.scope = OPTIONS_TABLE_SESSION, .scope = OPTIONS_TABLE_SESSION,
.minimum = 0, .minimum = 0,
.maximum = 2000000, .maximum = SHRT_MAX,
.default_num = 500, .default_num = 500,
.unit = "milliseconds", .unit = "milliseconds",
.text = "Time to wait for a key binding to repeat, if it is bound " .text = "Time to wait for a key binding to repeat, if it is bound "
@ -871,26 +742,11 @@ const struct options_table_entry options_table[] = {
.text = "Style of the status line." .text = "Style of the status line."
}, },
{ .name = "prompt-cursor-colour",
.type = OPTIONS_TABLE_COLOUR,
.scope = OPTIONS_TABLE_SESSION,
.default_num = 6,
.text = "Colour of the cursor when in the command prompt."
},
{ .name = "prompt-cursor-style",
.type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_SESSION,
.choices = options_table_cursor_style_list,
.default_num = 0,
.text = "Style of the cursor when in the command prompt."
},
{ .name = "update-environment", { .name = "update-environment",
.type = OPTIONS_TABLE_STRING, .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SESSION, .scope = OPTIONS_TABLE_SESSION,
.flags = OPTIONS_TABLE_IS_ARRAY, .flags = OPTIONS_TABLE_IS_ARRAY,
.default_str = "DISPLAY KRB5CCNAME MSYSTEM SSH_ASKPASS SSH_AUTH_SOCK " .default_str = "DISPLAY KRB5CCNAME SSH_ASKPASS SSH_AUTH_SOCK "
"SSH_AGENT_PID SSH_CONNECTION WINDOWID XAUTHORITY", "SSH_AGENT_PID SSH_CONNECTION WINDOWID XAUTHORITY",
.text = "List of environment variables to update in the session " .text = "List of environment variables to update in the session "
"environment when a client is attached." "environment when a client is attached."
@ -946,14 +802,11 @@ const struct options_table_entry options_table[] = {
}, },
{ .name = "allow-passthrough", { .name = "allow-passthrough",
.type = OPTIONS_TABLE_CHOICE, .type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE, .scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
.choices = options_table_allow_passthrough_list,
.default_num = 0, .default_num = 0,
.text = "Whether applications are allowed to use the escape sequence " .text = "Whether applications are allowed to use the escape sequence "
"to bypass tmux. Can be 'off' (disallowed), 'on' (allowed " "to bypass tmux."
"if the pane is visible), or 'all' (allowed even if the pane "
"is invisible)."
}, },
{ .name = "allow-rename", { .name = "allow-rename",
@ -964,14 +817,6 @@ const struct options_table_entry options_table[] = {
"to rename windows." "to rename windows."
}, },
{ .name = "allow-set-title",
.type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
.default_num = 1,
.text = "Whether applications are allowed to use the escape sequence "
"to set the pane title."
},
{ .name = "alternate-screen", { .name = "alternate-screen",
.type = OPTIONS_TABLE_FLAG, .type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE, .scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
@ -1037,36 +882,6 @@ const struct options_table_entry options_table[] = {
.text = "Style of the marked line in copy mode." .text = "Style of the marked line in copy mode."
}, },
{ .name = "copy-mode-position-format",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
.default_str = "#[align=right]"
"#{t/p:top_line_time}#{?#{e|>:#{top_line_time},0}, ,}"
"[#{scroll_position}/#{history_size}]"
"#{?search_timed_out, (timed out),"
"#{?search_count, (#{search_count}"
"#{?search_count_partial,+,} results),}}",
.text = "Format of the position indicator in copy mode."
},
{ .name = "copy-mode-position-style",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
.default_str = "#{E:mode-style}",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ",",
.text = "Style of position indicator in copy mode."
},
{ .name = "copy-mode-selection-style",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW,
.default_str = "#{E:mode-style}",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ",",
.text = "Style of selection in copy mode."
},
{ .name = "fill-character", { .name = "fill-character",
.type = OPTIONS_TABLE_STRING, .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW, .scope = OPTIONS_TABLE_WINDOW,
@ -1101,8 +916,8 @@ const struct options_table_entry options_table[] = {
{ .name = "mode-style", { .name = "mode-style",
.type = OPTIONS_TABLE_STRING, .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW, .scope = OPTIONS_TABLE_WINDOW,
.default_str = "bg=yellow,fg=black",
.flags = OPTIONS_TABLE_IS_STYLE, .flags = OPTIONS_TABLE_IS_STYLE,
.default_str = "noattr,bg=yellow,fg=black",
.separator = ",", .separator = ",",
.text = "Style of indicators and highlighting in modes." .text = "Style of indicators and highlighting in modes."
}, },
@ -1217,31 +1032,6 @@ const struct options_table_entry options_table[] = {
.text = "The default colour palette for colours zero to 255." .text = "The default colour palette for colours zero to 255."
}, },
{ .name = "pane-scrollbars",
.type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_WINDOW,
.choices = options_table_pane_scrollbars_list,
.default_num = PANE_SCROLLBARS_OFF,
.text = "Pane scrollbar state."
},
{ .name = "pane-scrollbars-style",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
.default_str = "bg=black,fg=white,width=1,pad=0",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ",",
.text = "Style of the pane scrollbar."
},
{ .name = "pane-scrollbars-position",
.type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_WINDOW,
.choices = options_table_pane_scrollbars_position_list,
.default_num = PANE_SCROLLBARS_RIGHT,
.text = "Pane scrollbar position."
},
{ .name = "popup-style", { .name = "popup-style",
.type = OPTIONS_TABLE_STRING, .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_WINDOW, .scope = OPTIONS_TABLE_WINDOW,
@ -1283,12 +1073,12 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE, .scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
.default_str = "Pane is dead (" .default_str = "Pane is dead ("
"#{?#{!=:#{pane_dead_status},}," "#{?#{!=:#{pane_dead_status},},"
"status #{pane_dead_status},}" "status #{pane_dead_status},}"
"#{?#{!=:#{pane_dead_signal},}," "#{?#{!=:#{pane_dead_signal},},"
"signal #{pane_dead_signal},}, " "signal #{pane_dead_signal},}, "
"#{t:pane_dead_time})", "#{t:pane_dead_time})",
.text = "Message shown after the program in a pane has exited, if " .text = "Message shown after the program in a pane has exited, if "
"remain-on-exit is enabled." "remain-on-exit is enabled."
}, },
{ .name = "scroll-on-clear", { .name = "scroll-on-clear",
@ -1469,9 +1259,6 @@ const struct options_table_entry options_table[] = {
OPTIONS_TABLE_HOOK("client-focus-out", ""), OPTIONS_TABLE_HOOK("client-focus-out", ""),
OPTIONS_TABLE_HOOK("client-resized", ""), OPTIONS_TABLE_HOOK("client-resized", ""),
OPTIONS_TABLE_HOOK("client-session-changed", ""), OPTIONS_TABLE_HOOK("client-session-changed", ""),
OPTIONS_TABLE_HOOK("client-light-theme", ""),
OPTIONS_TABLE_HOOK("client-dark-theme", ""),
OPTIONS_TABLE_HOOK("command-error", ""),
OPTIONS_TABLE_PANE_HOOK("pane-died", ""), OPTIONS_TABLE_PANE_HOOK("pane-died", ""),
OPTIONS_TABLE_PANE_HOOK("pane-exited", ""), OPTIONS_TABLE_PANE_HOOK("pane-exited", ""),
OPTIONS_TABLE_PANE_HOOK("pane-focus-in", ""), OPTIONS_TABLE_PANE_HOOK("pane-focus-in", ""),

114
options.c
View File

@ -260,7 +260,6 @@ options_default(struct options *oo, const struct options_table_entry *oe)
struct options_entry *o; struct options_entry *o;
union options_value *ov; union options_value *ov;
u_int i; u_int i;
struct cmd_parse_result *pr;
o = options_empty(oo, oe); o = options_empty(oo, oe);
ov = &o->value; ov = &o->value;
@ -279,17 +278,6 @@ options_default(struct options *oo, const struct options_table_entry *oe)
case OPTIONS_TABLE_STRING: case OPTIONS_TABLE_STRING:
ov->string = xstrdup(oe->default_str); ov->string = xstrdup(oe->default_str);
break; break;
case OPTIONS_TABLE_COMMAND:
pr = cmd_parse_from_string(oe->default_str, NULL);
switch (pr->status) {
case CMD_PARSE_ERROR:
free(pr->error);
break;
case CMD_PARSE_SUCCESS:
ov->cmdlist = pr->cmdlist;
break;
}
break;
default: default:
ov->number = oe->default_num; ov->number = oe->default_num;
break; break;
@ -590,28 +578,10 @@ char *
options_to_string(struct options_entry *o, int idx, int numeric) options_to_string(struct options_entry *o, int idx, int numeric)
{ {
struct options_array_item *a; struct options_array_item *a;
char *result = NULL;
char *last = NULL;
char *next;
if (OPTIONS_IS_ARRAY(o)) { if (OPTIONS_IS_ARRAY(o)) {
if (idx == -1) { if (idx == -1)
RB_FOREACH(a, options_array, &o->value.array) { return (xstrdup(""));
next = options_value_to_string(o, &a->value,
numeric);
if (last == NULL)
result = next;
else {
xasprintf(&result, "%s %s", last, next);
free(last);
free(next);
}
last = result;
}
if (result == NULL)
return (xstrdup(""));
return (result);
}
a = options_array_item(o, idx); a = options_array_item(o, idx);
if (a == NULL) if (a == NULL)
return (xstrdup("")); return (xstrdup(""));
@ -749,19 +719,6 @@ options_get_number(struct options *oo, const char *name)
return (o->value.number); return (o->value.number);
} }
const struct cmd_list *
options_get_command(struct options *oo, const char *name)
{
struct options_entry *o;
o = options_get(oo, name);
if (o == NULL)
fatalx("missing option %s", name);
if (!OPTIONS_IS_COMMAND(o))
fatalx("option %s is not a command", name);
return (o->value.cmdlist);
}
struct options_entry * struct options_entry *
options_set_string(struct options *oo, const char *name, int append, options_set_string(struct options *oo, const char *name, int append,
const char *fmt, ...) const char *fmt, ...)
@ -823,30 +780,6 @@ options_set_number(struct options *oo, const char *name, long long value)
return (o); return (o);
} }
struct options_entry *
options_set_command(struct options *oo, const char *name,
struct cmd_list *value)
{
struct options_entry *o;
if (*name == '@')
fatalx("user option %s must be a string", name);
o = options_get_only(oo, name);
if (o == NULL) {
o = options_default(oo, options_parent_table_entry(oo, name));
if (o == NULL)
return (NULL);
}
if (!OPTIONS_IS_COMMAND(o))
fatalx("option %s is not a command", name);
if (o->value.cmdlist != NULL)
cmd_list_free(o->value.cmdlist);
o->value.cmdlist = value;
return (o);
}
int int
options_scope_from_name(struct args *args, int window, options_scope_from_name(struct args *args, int window,
const char *name, struct cmd_find_state *fs, struct options **oo, const char *name, struct cmd_find_state *fs, struct options **oo,
@ -1103,7 +1036,6 @@ options_from_string(struct options *oo, const struct options_table_entry *oe,
const char *errstr, *new; const char *errstr, *new;
char *old; char *old;
key_code key; key_code key;
struct cmd_parse_result *pr;
if (oe != NULL) { if (oe != NULL) {
if (value == NULL && if (value == NULL &&
@ -1162,15 +1094,6 @@ options_from_string(struct options *oo, const struct options_table_entry *oe,
case OPTIONS_TABLE_CHOICE: case OPTIONS_TABLE_CHOICE:
return (options_from_string_choice(oe, oo, name, value, cause)); return (options_from_string_choice(oe, oo, name, value, cause));
case OPTIONS_TABLE_COMMAND: case OPTIONS_TABLE_COMMAND:
pr = cmd_parse_from_string(value, NULL);
switch (pr->status) {
case CMD_PARSE_ERROR:
*cause = pr->error;
return (-1);
case CMD_PARSE_SUCCESS:
options_set_command(oo, name, pr->cmdlist);
return (0);
}
break; break;
} }
return (-1); return (-1);
@ -1183,6 +1106,7 @@ options_push_changes(const char *name)
struct session *s; struct session *s;
struct window *w; struct window *w;
struct window_pane *wp; struct window_pane *wp;
int c;
log_debug("%s: %s", __func__, name); log_debug("%s: %s", __func__, name);
@ -1195,12 +1119,18 @@ options_push_changes(const char *name)
} }
} }
if (strcmp(name, "cursor-colour") == 0) { if (strcmp(name, "cursor-colour") == 0) {
RB_FOREACH(wp, window_pane_tree, &all_window_panes) RB_FOREACH(wp, window_pane_tree, &all_window_panes) {
window_pane_default_cursor(wp); c = options_get_number(wp->options, name);
wp->screen->default_ccolour = c;
}
} }
if (strcmp(name, "cursor-style") == 0) { if (strcmp(name, "cursor-style") == 0) {
RB_FOREACH(wp, window_pane_tree, &all_window_panes) RB_FOREACH(wp, window_pane_tree, &all_window_panes) {
window_pane_default_cursor(wp); wp->screen->default_mode = 0;
screen_set_cursor_style(options_get_number(wp->options,
name), &wp->screen->default_cstyle,
&wp->screen->default_mode);
}
} }
if (strcmp(name, "fill-character") == 0) { if (strcmp(name, "fill-character") == 0) {
RB_FOREACH(w, windows, &windows) RB_FOREACH(w, windows, &windows)
@ -1224,30 +1154,16 @@ options_push_changes(const char *name)
if (strcmp(name, "window-style") == 0 || if (strcmp(name, "window-style") == 0 ||
strcmp(name, "window-active-style") == 0) { strcmp(name, "window-active-style") == 0) {
RB_FOREACH(wp, window_pane_tree, &all_window_panes) RB_FOREACH(wp, window_pane_tree, &all_window_panes)
wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED); wp->flags |= PANE_STYLECHANGED;
} }
if (strcmp(name, "pane-colours") == 0) { if (strcmp(name, "pane-colours") == 0) {
RB_FOREACH(wp, window_pane_tree, &all_window_panes) RB_FOREACH(wp, window_pane_tree, &all_window_panes)
colour_palette_from_option(&wp->palette, wp->options); colour_palette_from_option(&wp->palette, wp->options);
} }
if (strcmp(name, "pane-border-status") == 0 || if (strcmp(name, "pane-border-status") == 0) {
strcmp(name, "pane-scrollbars") == 0 ||
strcmp(name, "pane-scrollbars-position") == 0) {
RB_FOREACH(w, windows, &windows) RB_FOREACH(w, windows, &windows)
layout_fix_panes(w, NULL); layout_fix_panes(w, NULL);
} }
if (strcmp(name, "pane-scrollbars-style") == 0) {
RB_FOREACH(wp, window_pane_tree, &all_window_panes) {
style_set_scrollbar_style_from_option(
&wp->scrollbar_style, wp->options);
}
RB_FOREACH(w, windows, &windows)
layout_fix_panes(w, NULL);
}
if (strcmp(name, "codepoint-widths") == 0)
utf8_update_width_cache();
if (strcmp(name, "input-buffer-size") == 0)
input_set_buffer_size(options_get_number(global_options, name));
RB_FOREACH(s, sessions, &sessions) RB_FOREACH(s, sessions, &sessions)
status_update_cache(s); status_update_cache(s);

28
paste.c
View File

@ -111,12 +111,6 @@ paste_walk(struct paste_buffer *pb)
return (RB_NEXT(paste_time_tree, &paste_by_time, pb)); return (RB_NEXT(paste_time_tree, &paste_by_time, pb));
} }
int
paste_is_empty(void)
{
return RB_ROOT(&paste_by_time) == NULL;
}
/* Get the most recent automatic buffer. */ /* Get the most recent automatic buffer. */
struct paste_buffer * struct paste_buffer *
paste_get_top(const char **name) paste_get_top(const char **name)
@ -124,8 +118,6 @@ paste_get_top(const char **name)
struct paste_buffer *pb; struct paste_buffer *pb;
pb = RB_MIN(paste_time_tree, &paste_by_time); pb = RB_MIN(paste_time_tree, &paste_by_time);
while (pb != NULL && !pb->automatic)
pb = RB_NEXT(paste_time_tree, &paste_by_time, pb);
if (pb == NULL) if (pb == NULL)
return (NULL); return (NULL);
if (name != NULL) if (name != NULL)
@ -150,8 +142,6 @@ paste_get_name(const char *name)
void void
paste_free(struct paste_buffer *pb) paste_free(struct paste_buffer *pb)
{ {
notify_paste_buffer(pb->name, 1);
RB_REMOVE(paste_name_tree, &paste_by_name, pb); RB_REMOVE(paste_name_tree, &paste_by_name, pb);
RB_REMOVE(paste_time_tree, &paste_by_time, pb); RB_REMOVE(paste_time_tree, &paste_by_time, pb);
if (pb->automatic) if (pb->automatic)
@ -208,8 +198,6 @@ paste_add(const char *prefix, char *data, size_t size)
pb->order = paste_next_order++; pb->order = paste_next_order++;
RB_INSERT(paste_name_tree, &paste_by_name, pb); RB_INSERT(paste_name_tree, &paste_by_name, pb);
RB_INSERT(paste_time_tree, &paste_by_time, pb); RB_INSERT(paste_time_tree, &paste_by_time, pb);
notify_paste_buffer(pb->name, 0);
} }
/* Rename a paste buffer. */ /* Rename a paste buffer. */
@ -240,10 +228,11 @@ paste_rename(const char *oldname, const char *newname, char **cause)
} }
pb_new = paste_get_name(newname); pb_new = paste_get_name(newname);
if (pb_new == pb) if (pb_new != NULL) {
return (0); if (cause != NULL)
if (pb_new != NULL) xasprintf(cause, "buffer %s already exists", newname);
paste_free(pb_new); return (-1);
}
RB_REMOVE(paste_name_tree, &paste_by_name, pb); RB_REMOVE(paste_name_tree, &paste_by_name, pb);
@ -256,9 +245,6 @@ paste_rename(const char *oldname, const char *newname, char **cause)
RB_INSERT(paste_name_tree, &paste_by_name, pb); RB_INSERT(paste_name_tree, &paste_by_name, pb);
notify_paste_buffer(oldname, 1);
notify_paste_buffer(newname, 0);
return (0); return (0);
} }
@ -307,8 +293,6 @@ paste_set(char *data, size_t size, const char *name, char **cause)
RB_INSERT(paste_name_tree, &paste_by_name, pb); RB_INSERT(paste_name_tree, &paste_by_name, pb);
RB_INSERT(paste_time_tree, &paste_by_time, pb); RB_INSERT(paste_time_tree, &paste_by_time, pb);
notify_paste_buffer(name, 0);
return (0); return (0);
} }
@ -319,8 +303,6 @@ paste_replace(struct paste_buffer *pb, char *data, size_t size)
free(pb->data); free(pb->data);
pb->data = data; pb->data = data;
pb->size = size; pb->size = size;
notify_paste_buffer(pb->name, 0);
} }
/* Convert start of buffer into a nice string. */ /* Convert start of buffer into a nice string. */

Some files were not shown because too many files have changed in this diff Show More