2 Commits
3.6 ... 3.1c

Author SHA1 Message Date
Nicholas Marriott
25cae5d86f 3.1c. 2020-10-30 12:11:02 +00:00
nicm
d0ad34e94d Do not write after the end of the array and overwrite the stack when
colon-separated SGR sequences contain empty arguments. Reported by Sergey
Nizovtsev.
2020-10-30 12:09:52 +00:00
230 changed files with 12652 additions and 49459 deletions

View File

@@ -29,7 +29,7 @@ uname -sp && tmux -V && echo $TERM
Also include: Also include:
- Your platform (Linux, macOS, or whatever). - Your platform (Linux, OS X, or whatever).
- A brief description of the problem with steps to reproduce. - A brief description of the problem with steps to reproduce.
@@ -37,8 +37,7 @@ Also include:
- Your terminal, and `$TERM` inside and outside of tmux. - Your terminal, and `$TERM` inside and outside of tmux.
- Logs from tmux (see below). Please attach logs to the issue directly rather - Logs from tmux (see below).
than using a download site or pastebin. Put in a zip file if necessary.
- At most one or two screenshots, if helpful. - At most one or two screenshots, if helpful.
@@ -77,8 +76,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
@@ -23,11 +14,9 @@ built from the latest code in Git.
### Required information ### Required information
Please provide the following information. These are **required**. Note that bug reports without logs may be ignored or closed without comment. Please provide the following information:
* tmux version (`tmux -V`). * tmux version (`tmux -V`).
* Platform (`uname -sp`). * Platform (`uname -sp`).
* Terminal in use (xterm, rxvt, etc). * $TERM inside and outside of tmux (`echo $TERM`).
* $TERM *inside* tmux (`echo $TERM`).
* $TERM *outside* tmux (`echo $TERM`).
* Logs from tmux (`tmux kill-server; tmux -vv new`). * Logs from tmux (`tmux kill-server; tmux -vv new`).

View File

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

18
.github/README.md vendored
View File

@@ -4,7 +4,7 @@ tmux is a terminal multiplexer: it enables a number of terminals to be created,
accessed, and controlled from a single screen. tmux may be detached from a accessed, and controlled from a single screen. tmux may be detached from a
screen and continue running in the background, then later reattached. screen and continue running in the background, then later reattached.
This release runs on OpenBSD, FreeBSD, NetBSD, Linux, macOS and Solaris. This release runs on OpenBSD, FreeBSD, NetBSD, Linux, OS X and Solaris.
## Dependencies ## Dependencies
@@ -14,17 +14,8 @@ page](https://github.com/libevent/libevent/releases/latest).
It also depends on [ncurses](https://www.gnu.org/software/ncurses/), available It also depends on [ncurses](https://www.gnu.org/software/ncurses/), available
from [this page](https://invisible-mirror.net/archives/ncurses/). from [this page](https://invisible-mirror.net/archives/ncurses/).
To build tmux, a C compiler (for example gcc or clang), make, pkg-config and a
suitable yacc (yacc or bison) are needed.
## Installation ## Installation
### Binary packages
Some platforms provide binary packages for tmux, although these are sometimes
out of date. Examples are listed on
[this page](https://github.com/tmux/tmux/wiki/Installing).
### From release tarball ### From release tarball
To build and install tmux from a release tarball, use: To build and install tmux from a release tarball, use:
@@ -37,9 +28,6 @@ sudo make install
tmux can use the utempter library to update utmp(5), if it is installed - run tmux can use the utempter library to update utmp(5), if it is installed - run
configure with `--enable-utempter` to enable this. configure with `--enable-utempter` to enable this.
For more detailed instructions on building and installing tmux, see
[this page](https://github.com/tmux/tmux/wiki/Installing).
### From version control ### From version control
To get and build the latest from version control - note that this requires To get and build the latest from version control - note that this requires
@@ -79,9 +67,9 @@ 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.
## Support ## Support

10
.github/lock.yml vendored Normal file
View File

@@ -0,0 +1,10 @@
daysUntilLock: 180
skipCreatedBefore: false
exemptLabels: []
lockLabel: false
lockComment: >
This thread has been automatically locked since there has not been
any recent activity after it was closed. Please open a new issue for
related bugs.
setLockReason: false
#only: issues

View File

@@ -1,24 +0,0 @@
#!/bin/sh
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
sudo apt-get update -qq
sudo apt-get -y install bison \
autotools-dev \
libncurses5-dev \
libevent-dev \
pkg-config \
libutempter-dev \
build-essential
if [ "$BUILD" = "musl" -o "$BUILD" = "musl-static" ]; then
sudo apt-get -y install musl-dev \
musl-tools
fi
fi
if [ "$TRAVIS_OS_NAME" = "freebsd" ]; then
sudo pkg install -y \
automake \
libevent \
pkgconf
fi

View File

@@ -1,38 +0,0 @@
#!/bin/sh
BUILD=$PWD/build
LIBEVENT=https://github.com/libevent/libevent/releases/download/release-2.1.11-stable/libevent-2.1.11-stab\
le.tar.gz
NCURSES=https://ftp.gnu.org/gnu/ncurses/ncurses-6.2.tar.gz
wget -4q $LIBEVENT || exit 1
tar -zxf libevent-*.tar.gz || exit 1
(cd libevent-*/ &&
./configure --prefix=$BUILD \
--enable-shared \
--disable-libevent-regress \
--disable-samples &&
make && make install) || exit 1
wget -4q $NCURSES || exit 1
tar -zxf ncurses-*.tar.gz || exit 1
(cd ncurses-*/ &&
CPPFLAGS=-P ./configure --prefix=$BUILD \
--with-shared \
--with-termlib \
--without-ada \
--without-cxx \
--without-manpages \
--without-progs \
--without-tests \
--without-tack \
--disable-database \
--enable-termcap \
--enable-pc-files \
--with-pkg-config-libdir=$BUILD/lib/pkgconfig &&
make && make install) || exit 1
sh autogen.sh || exit 1
PKG_CONFIG_PATH=$BUILD/lib/pkgconfig ./configure --prefix=$BUILD "$@"
make && make install || (cat config.log; exit 1)

View File

@@ -1,25 +0,0 @@
#!/bin/sh
sh autogen.sh || exit 1
case "$BUILD" in
static)
./configure --enable-static || exit 1
exec make
;;
all)
sh $(dirname $0)/build-all.sh
exec make
;;
musl)
CC=musl-gcc sh $(dirname $0)/build-all.sh
exec make
;;
musl-static)
CC=musl-gcc sh $(dirname $0)/build-all.sh --enable-static
exec make
;;
*)
./configure || exit 1
exec make
;;
esac

View File

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

25
.gitignore vendored
View File

@@ -1,24 +1,21 @@
*.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

View File

@@ -1,88 +1,16 @@
language: c language: c
os: os:
- linux - linux
- freebsd - osx
- osx
compiler: compiler:
- gcc - gcc
- clang - clang
arch:
- amd64
- arm64
env:
- BUILD=
- BUILD=static
- BUILD=all
- BUILD=musl
- BUILD=musl-static
jobs:
exclude:
# Static builds are broken on OS X (by Apple)
- os: osx
compiler: gcc
env: BUILD=static
- os: osx
compiler: clang
env: BUILD=static
# No musl on FreeBSD
- os: freebsd
compiler: gcc
env: BUILD=musl
- os: freebsd
compiler: clang
env: BUILD=musl
- os: freebsd
compiler: gcc
env: BUILD=musl-static
- os: freebsd
compiler: clang
env: BUILD=musl-static
# No musl on OS X
- os: osx
compiler: gcc
env: BUILD=musl
- os: osx
compiler: clang
env: BUILD=musl
- os: osx
compiler: gcc
env: BUILD=musl-static
- os: osx
compiler: clang
env: BUILD=musl-static
# arm64 doesn't link ncurses
- os: linux
compiler: gcc
arch: arm64
env: BUILD=all
- os: linux
compiler: clang
arch: arm64
env: BUILD=all
- os: linux
compiler: gcc
arch: arm64
env: BUILD=musl
- os: linux
compiler: clang
arch: arm64
env: BUILD=musl
- os: linux
compiler: gcc
arch: arm64
env: BUILD=musl-static
- os: linux
compiler: clang
arch: arm64
env: BUILD=musl-static
before_install: before_install:
- sh .github/travis/before-install.sh - if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get update -qq; fi
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get -y install bison autotools-dev libncurses5-dev libevent-dev pkg-config libutempter-dev build-essential; fi
script: script:
- sh .github/travis/build.sh - ./autogen.sh && ./configure && make

983
CHANGES

File diff suppressed because it is too large Load Diff

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
@@ -10,10 +12,8 @@ dist_EXTRA_tmux_SOURCES = compat/*.[ch]
# Preprocessor flags. # Preprocessor flags.
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:~/.config/tmux/tmux.conf\""
-DTMUX_LOCK_CMD='"@DEFAULT_LOCK_CMD@"' \
-DTMUX_TERM='"@DEFAULT_TERM@"'
# Additional object files. # Additional object files.
LDADD = $(LIBOBJS) LDADD = $(LIBOBJS)
@@ -28,10 +28,7 @@ AM_CFLAGS += -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations
AM_CFLAGS += -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare AM_CFLAGS += -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare
AM_CFLAGS += -Wundef -Wbad-function-cast -Winline -Wcast-align 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
if IS_DARWIN
AM_CFLAGS += -Wno-deprecated-declarations -Wno-cast-align -Wno-macro-redefined
endif
AM_CPPFLAGS += -DDEBUG AM_CPPFLAGS += -DDEBUG
endif endif
AM_CPPFLAGS += -iquote. AM_CPPFLAGS += -iquote.
@@ -61,16 +58,6 @@ if IS_NETBSD
AM_CPPFLAGS += -D_OPENBSD_SOURCE AM_CPPFLAGS += -D_OPENBSD_SOURCE
endif endif
# Set flags for Haiku.
if IS_HAIKU
AM_CPPFLAGS += -D_BSD_SOURCE
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 \
@@ -127,14 +114,12 @@ dist_tmux_SOURCES = \
cmd-select-pane.c \ cmd-select-pane.c \
cmd-select-window.c \ cmd-select-window.c \
cmd-send-keys.c \ cmd-send-keys.c \
cmd-server-access.c \
cmd-set-buffer.c \ cmd-set-buffer.c \
cmd-set-environment.c \ cmd-set-environment.c \
cmd-set-option.c \ cmd-set-option.c \
cmd-show-environment.c \ cmd-show-environment.c \
cmd-show-messages.c \ cmd-show-messages.c \
cmd-show-options.c \ cmd-show-options.c \
cmd-show-prompt-history.c \
cmd-source-file.c \ cmd-source-file.c \
cmd-split-window.c \ cmd-split-window.c \
cmd-swap-pane.c \ cmd-swap-pane.c \
@@ -151,10 +136,8 @@ dist_tmux_SOURCES = \
file.c \ file.c \
format.c \ format.c \
format-draw.c \ format-draw.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 \
@@ -171,14 +154,12 @@ dist_tmux_SOURCES = \
options-table.c \ options-table.c \
options.c \ options.c \
paste.c \ paste.c \
popup.c \
proc.c \ proc.c \
regsub.c \ regsub.c \
resize.c \ resize.c \
screen-redraw.c \ screen-redraw.c \
screen-write.c \ screen-write.c \
screen.c \ screen.c \
server-acl.c \
server-client.c \ server-client.c \
server-fn.c \ server-fn.c \
server.c \ server.c \
@@ -188,23 +169,20 @@ dist_tmux_SOURCES = \
style.c \ style.c \
tmux.c \ tmux.c \
tmux.h \ tmux.h \
tmux-protocol.h \
tty-acs.c \ tty-acs.c \
tty-features.c \
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 \
window-clock.c \ window-clock.c \
window-copy.c \ window-copy.c \
window-customize.c \
window-tree.c \ window-tree.c \
window.c \ window.c \
xmalloc.c \ xmalloc.c \
xmalloc.h xmalloc.h \
xterm-keys.c
nodist_tmux_SOURCES = osdep-@PLATFORM@.c nodist_tmux_SOURCES = osdep-@PLATFORM@.c
# Add compat file for forkpty. # Add compat file for forkpty.
@@ -212,27 +190,11 @@ if NEED_FORKPTY
nodist_tmux_SOURCES += compat/forkpty-@PLATFORM@.c nodist_tmux_SOURCES += compat/forkpty-@PLATFORM@.c
endif endif
# Add compat file for systemd.
if HAVE_SYSTEMD
nodist_tmux_SOURCES += compat/systemd.c
endif
# Add compat file for utf8proc. # Add compat file for utf8proc.
if HAVE_UTF8PROC 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
check_PROGRAMS = fuzz/input-fuzzer
fuzz_input_fuzzer_LDFLAGS = $(FUZZING_LIBS)
fuzz_input_fuzzer_LDADD = $(LDADD) $(tmux_OBJECTS)
endif
# Install tmux.1 in the right format. # Install tmux.1 in the right format.
install-exec-hook: install-exec-hook:
if test x@MANFORMAT@ = xmdoc; then \ if test x@MANFORMAT@ = xmdoc; then \

16
README
View File

@@ -4,7 +4,7 @@ tmux is a terminal multiplexer: it enables a number of terminals to be created,
accessed, and controlled from a single screen. tmux may be detached from a accessed, and controlled from a single screen. tmux may be detached from a
screen and continue running in the background, then later reattached. screen and continue running in the background, then later reattached.
This release runs on OpenBSD, FreeBSD, NetBSD, Linux, macOS and Solaris. This release runs on OpenBSD, FreeBSD, NetBSD, Linux, OS X and Solaris.
* Dependencies * Dependencies
@@ -16,9 +16,6 @@ It also depends on ncurses, available from:
https://invisible-mirror.net/archives/ncurses/ https://invisible-mirror.net/archives/ncurses/
To build tmux, a C compiler (for example gcc or clang), make, pkg-config and a
suitable yacc (yacc or bison) are needed.
* Installation * Installation
To build and install tmux from a release tarball, use: To build and install tmux from a release tarball, use:
@@ -36,7 +33,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
@@ -56,17 +52,9 @@ source tree with:
A small example configuration is in example_tmux.conf. A small example configuration is in example_tmux.conf.
Other documentation is available in the wiki:
https://github.com/tmux/tmux/wiki
Also see the tmux FAQ at:
https://github.com/tmux/tmux/wiki/FAQ
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

@@ -3,7 +3,7 @@ tmuxへようこそ!
tmuxはターミナルマルチプレクサーです。複数のターミナルを一つのスクリーン内に作成し、操作することができます。 tmuxはターミナルマルチプレクサーです。複数のターミナルを一つのスクリーン内に作成し、操作することができます。
バックグラウンドで処理を実行中に一度スクリーンから離れて後から復帰することも可能です。 バックグラウンドで処理を実行中に一度スクリーンから離れて後から復帰することも可能です。
OpenBSD、FreeBSD、NetBSD、Linux、macOS、Solarisで実行できます。 OpenBSD、FreeBSD、NetBSD、Linux、OS X、Solarisで実行できます。
tmuxはlibevent 2.x.に依存します。 下記からダウンロードしてください。 tmuxはlibevent 2.x.に依存します。 下記からダウンロードしてください。
@@ -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」を指定することでデバッグモードでの起動が可能です。カレントディレクトリにサーバーやクライアントのログファイルが生成されます。

34
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,17 +82,17 @@ 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
Adding in the fake history points 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

@@ -18,6 +18,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <event.h>
#include <stdlib.h> #include <stdlib.h>
#include "tmux.h" #include "tmux.h"
@@ -199,7 +200,7 @@ alerts_check_bell(struct window *w)
* not check WINLINK_BELL). * not check WINLINK_BELL).
*/ */
s = wl->session; s = wl->session;
if (s->curw != wl || s->attached == 0) { if (s->curw != wl) {
wl->flags |= WINLINK_BELL; wl->flags |= WINLINK_BELL;
server_status_session(s); server_status_session(s);
} }
@@ -235,7 +236,7 @@ alerts_check_activity(struct window *w)
if (wl->flags & WINLINK_ACTIVITY) if (wl->flags & WINLINK_ACTIVITY)
continue; continue;
s = wl->session; s = wl->session;
if (s->curw != wl || s->attached == 0) { if (s->curw != wl) {
wl->flags |= WINLINK_ACTIVITY; wl->flags |= WINLINK_ACTIVITY;
server_status_session(s); server_status_session(s);
} }
@@ -271,7 +272,7 @@ alerts_check_silence(struct window *w)
if (wl->flags & WINLINK_SILENCE) if (wl->flags & WINLINK_SILENCE)
continue; continue;
s = wl->session; s = wl->session;
if (s->curw != wl || s->attached == 0) { if (s->curw != wl) {
wl->flags |= WINLINK_SILENCE; wl->flags |= WINLINK_SILENCE;
server_status_session(s); server_status_session(s);
} }
@@ -314,12 +315,9 @@ alerts_set_message(struct winlink *wl, const char *type, const char *option)
tty_putcode(&c->tty, TTYC_BEL); tty_putcode(&c->tty, TTYC_BEL);
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, "%s in current window", type);
"%s in current window", type); else
} else { status_message_set(c, "%s in window %d", type, wl->idx);
status_message_set(c, -1, 1, 0, 0,
"%s in window %d", type, wl->idx);
}
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -31,8 +31,7 @@ attributes_tostring(int attr)
if (attr == 0) if (attr == 0)
return ("none"); return ("none");
len = xsnprintf(buf, sizeof buf, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s", len = xsnprintf(buf, sizeof buf, "%s%s%s%s%s%s%s%s%s%s%s%s%s",
(attr & GRID_ATTR_CHARSET) ? "acs," : "",
(attr & GRID_ATTR_BRIGHT) ? "bright," : "", (attr & GRID_ATTR_BRIGHT) ? "bright," : "",
(attr & GRID_ATTR_DIM) ? "dim," : "", (attr & GRID_ATTR_DIM) ? "dim," : "",
(attr & GRID_ATTR_UNDERSCORE) ? "underscore," : "", (attr & GRID_ATTR_UNDERSCORE) ? "underscore," : "",
@@ -63,7 +62,6 @@ attributes_fromstring(const char *str)
const char *name; const char *name;
int attr; int attr;
} table[] = { } table[] = {
{ "acs", GRID_ATTR_CHARSET },
{ "bright", GRID_ATTR_BRIGHT }, { "bright", GRID_ATTR_BRIGHT },
{ "bold", GRID_ATTR_BRIGHT }, { "bold", GRID_ATTR_BRIGHT },
{ "dim", GRID_ATTR_DIM }, { "dim", GRID_ATTR_DIM },

138
cfg.c
View File

@@ -27,15 +27,12 @@
#include "tmux.h" #include "tmux.h"
struct client *cfg_client; struct client *cfg_client;
static char *cfg_file;
int cfg_finished; int cfg_finished;
static char **cfg_causes; static char **cfg_causes;
static u_int cfg_ncauses; static u_int cfg_ncauses;
static struct cmdq_item *cfg_item; static struct cmdq_item *cfg_item;
int cfg_quiet = 1;
char **cfg_files;
u_int cfg_nfiles;
static enum cmd_retval static enum cmd_retval
cfg_client_done(__unused struct cmdq_item *item, __unused void *data) cfg_client_done(__unused struct cmdq_item *item, __unused void *data)
{ {
@@ -51,7 +48,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);
@@ -61,12 +59,52 @@ cfg_done(__unused struct cmdq_item *item, __unused void *data)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
void
set_cfg_file(const char *path)
{
free(cfg_file);
cfg_file = xstrdup(path);
}
static char *
expand_cfg_file(const char *path, const char *home)
{
char *expanded, *name;
const char *end;
struct environ_entry *value;
if (strncmp(path, "~/", 2) == 0) {
if (home == NULL)
return (NULL);
xasprintf(&expanded, "%s%s", home, path + 1);
return (expanded);
}
if (*path == '$') {
end = strchr(path, '/');
if (end == NULL)
name = xstrdup(path + 1);
else
name = xstrndup(path + 1, end - path - 1);
value = environ_find(global_environ, name);
free(name);
if (value == NULL)
return (NULL);
if (end == NULL)
end = "";
xasprintf(&expanded, "%s%s", value->value, end);
return (expanded);
}
return (xstrdup(path));
}
void void
start_cfg(void) start_cfg(void)
{ {
struct client *c; const char *home = find_home();
u_int i; struct client *c;
int flags = 0; char *path, *copy, *next, *expanded;
/* /*
* Configuration files are loaded without a client, so commands are run * Configuration files are loaded without a client, so commands are run
@@ -84,23 +122,33 @@ start_cfg(void)
cmdq_append(c, cfg_item); cmdq_append(c, cfg_item);
} }
if (cfg_quiet) if (cfg_file == NULL) {
flags = CMD_PARSE_QUIET; path = copy = xstrdup(TMUX_CONF);
for (i = 0; i < cfg_nfiles; i++) while ((next = strsep(&path, ":")) != NULL) {
load_cfg(cfg_files[i], c, NULL, NULL, flags, NULL); expanded = expand_cfg_file(next, home);
if (expanded == NULL) {
log_debug("couldn't expand %s", next);
continue;
}
log_debug("expanded %s to %s", next, expanded);
load_cfg(expanded, c, NULL, CMD_PARSE_QUIET, NULL);
free(expanded);
}
free(copy);
} else
load_cfg(cfg_file, c, NULL, 0, NULL);
cmdq_append(NULL, cmdq_get_callback(cfg_done, NULL)); 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;
struct cmd_parse_result *pr; struct cmd_parse_result *pr;
struct cmdq_item *new_item0; struct cmdq_item *new_item0;
struct cmdq_state *state;
if (new_item != NULL) if (new_item != NULL)
*new_item = NULL; *new_item = NULL;
@@ -122,6 +170,8 @@ load_cfg(const char *path, struct client *c, struct cmdq_item *item,
pr = cmd_parse_from_file(f, &pi); pr = cmd_parse_from_file(f, &pi);
fclose(f); fclose(f);
if (pr->status == CMD_PARSE_EMPTY)
return (0);
if (pr->status == CMD_PARSE_ERROR) { if (pr->status == CMD_PARSE_ERROR) {
cfg_add_cause("%s", pr->error); cfg_add_cause("%s", pr->error);
free(pr->error); free(pr->error);
@@ -132,19 +182,12 @@ load_cfg(const char *path, struct client *c, struct cmdq_item *item,
return (0); return (0);
} }
if (item != NULL) new_item0 = cmdq_get_command(pr->cmdlist, NULL, NULL, 0);
state = cmdq_copy_state(cmdq_get_state(item), current);
else
state = cmdq_new_state(NULL, NULL, 0);
cmdq_add_format(state, "current_file", "%s", pi.file);
new_item0 = cmdq_get_command(pr->cmdlist, state);
if (item != NULL) if (item != NULL)
new_item0 = cmdq_insert_after(item, new_item0); new_item0 = cmdq_insert_after(item, new_item0);
else else
new_item0 = cmdq_append(NULL, new_item0); new_item0 = cmdq_append(NULL, new_item0);
cmd_list_free(pr->cmdlist); cmd_list_free(pr->cmdlist);
cmdq_free_state(state);
if (new_item != NULL) if (new_item != NULL)
*new_item = new_item0; *new_item = new_item0;
@@ -153,13 +196,12 @@ 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;
struct cmdq_item *new_item0; struct cmdq_item *new_item0;
struct cmdq_state *state;
if (new_item != NULL) if (new_item != NULL)
*new_item = NULL; *new_item = NULL;
@@ -174,6 +216,8 @@ load_cfg_from_buffer(const void *buf, size_t len, const char *path,
pi.c = c; pi.c = c;
pr = cmd_parse_from_buffer(buf, len, &pi); pr = cmd_parse_from_buffer(buf, len, &pi);
if (pr->status == CMD_PARSE_EMPTY)
return (0);
if (pr->status == CMD_PARSE_ERROR) { if (pr->status == CMD_PARSE_ERROR) {
cfg_add_cause("%s", pr->error); cfg_add_cause("%s", pr->error);
free(pr->error); free(pr->error);
@@ -184,19 +228,12 @@ load_cfg_from_buffer(const void *buf, size_t len, const char *path,
return (0); return (0);
} }
if (item != NULL) new_item0 = cmdq_get_command(pr->cmdlist, NULL, NULL, 0);
state = cmdq_copy_state(cmdq_get_state(item), current);
else
state = cmdq_new_state(NULL, NULL, 0);
cmdq_add_format(state, "current_file", "%s", pi.file);
new_item0 = cmdq_get_command(pr->cmdlist, state);
if (item != NULL) if (item != NULL)
new_item0 = cmdq_insert_after(item, new_item0); new_item0 = cmdq_insert_after(item, new_item0);
else else
new_item0 = cmdq_append(NULL, new_item0); new_item0 = cmdq_append(NULL, new_item0);
cmd_list_free(pr->cmdlist); cmd_list_free(pr->cmdlist);
cmdq_free_state(state);
if (new_item != NULL) if (new_item != NULL)
*new_item = new_item0; *new_item = new_item0;
@@ -221,14 +258,10 @@ cfg_add_cause(const char *fmt, ...)
void void
cfg_print_causes(struct cmdq_item *item) cfg_print_causes(struct cmdq_item *item)
{ {
struct client *c = cmdq_get_client(item); u_int i;
u_int i;
for (i = 0; i < cfg_ncauses; i++) { for (i = 0; i < cfg_ncauses; i++) {
if (c != NULL && (c->flags & CLIENT_CONTROL)) cmdq_print(item, "%s", cfg_causes[i]);
control_write(c, "%%config-error %s", cfg_causes[i]);
else
cmdq_print(item, "%s", cfg_causes[i]);
free(cfg_causes[i]); free(cfg_causes[i]);
} }
@@ -240,41 +273,22 @@ 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;
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)
window_pane_set_mode(wp, NULL, &window_view_mode, NULL, NULL); window_pane_set_mode(wp, &window_view_mode, NULL, NULL);
for (i = 0; i < cfg_ncauses; i++) { for (i = 0; i < cfg_ncauses; i++) {
window_copy_add(wp, 0, "%s", cfg_causes[i]); window_copy_add(wp, "%s", cfg_causes[i]);
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;

543
client.c
View File

@@ -18,12 +18,12 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/uio.h>
#include <sys/un.h> #include <sys/un.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <sys/file.h> #include <sys/file.h>
#include <errno.h> #include <errno.h>
#include <event.h>
#include <fcntl.h> #include <fcntl.h>
#include <signal.h> #include <signal.h>
#include <stdlib.h> #include <stdlib.h>
@@ -34,8 +34,7 @@
static struct tmuxproc *client_proc; static struct tmuxproc *client_proc;
static struct tmuxpeer *client_peer; static struct tmuxpeer *client_peer;
static uint64_t client_flags; static int client_flags;
static int client_suspended;
static enum { static enum {
CLIENT_EXIT_NONE, CLIENT_EXIT_NONE,
CLIENT_EXIT_DETACHED, CLIENT_EXIT_DETACHED,
@@ -45,13 +44,11 @@ static enum {
CLIENT_EXIT_LOST_SERVER, CLIENT_EXIT_LOST_SERVER,
CLIENT_EXIT_EXITED, CLIENT_EXIT_EXITED,
CLIENT_EXIT_SERVER_EXITED, CLIENT_EXIT_SERVER_EXITED,
CLIENT_EXIT_MESSAGE_PROVIDED
} client_exitreason = CLIENT_EXIT_NONE; } client_exitreason = CLIENT_EXIT_NONE;
static int client_exitflag; static int client_exitflag;
static int client_exitval; static int client_exitval;
static enum msgtype client_exittype; static enum msgtype client_exittype;
static const char *client_exitsession; static const char *client_exitsession;
static char *client_exitmessage;
static const char *client_execshell; static const char *client_execshell;
static const char *client_execcmd; static const char *client_execcmd;
static int client_attached; static int client_attached;
@@ -59,10 +56,8 @@ static struct client_files client_files = RB_INITIALIZER(&client_files);
static __dead void client_exec(const char *,const char *); static __dead void client_exec(const char *,const char *);
static int client_get_lock(char *); static int client_get_lock(char *);
static int client_connect(struct event_base *, const char *, static int client_connect(struct event_base *, const char *, int);
uint64_t); static void client_send_identify(const char *, const char *);
static void client_send_identify(const char *, const char *,
char **, u_int, const char *, int);
static void client_signal(int); static void client_signal(int);
static void client_dispatch(struct imsg *, void *); static void client_dispatch(struct imsg *, void *);
static void client_dispatch_attached(struct imsg *); static void client_dispatch_attached(struct imsg *);
@@ -102,7 +97,7 @@ client_get_lock(char *lockfile)
/* Connect client to server. */ /* Connect client to server. */
static int static int
client_connect(struct event_base *base, const char *path, uint64_t flags) client_connect(struct event_base *base, const char *path, int start_server)
{ {
struct sockaddr_un sa; struct sockaddr_un sa;
size_t size; size_t size;
@@ -127,9 +122,7 @@ retry:
log_debug("connect failed: %s", strerror(errno)); log_debug("connect failed: %s", strerror(errno));
if (errno != ECONNREFUSED && errno != ENOENT) if (errno != ECONNREFUSED && errno != ENOENT)
goto failed; goto failed;
if (flags & CLIENT_NOSTARTSERVER) if (!start_server)
goto failed;
if (~flags & CLIENT_STARTSERVER)
goto failed; goto failed;
close(fd); close(fd);
@@ -161,7 +154,7 @@ retry:
close(lockfd); close(lockfd);
return (-1); return (-1);
} }
fd = server_start(client_proc, flags, base, lockfd, lockfile); fd = server_start(client_proc, base, lockfd, lockfile);
} }
if (locked && lockfd >= 0) { if (locked && lockfd >= 0) {
@@ -213,8 +206,6 @@ client_exit_message(void)
return ("exited"); return ("exited");
case CLIENT_EXIT_SERVER_EXITED: case CLIENT_EXIT_SERVER_EXITED:
return ("server exited"); return ("server exited");
case CLIENT_EXIT_MESSAGE_PROVIDED:
return (client_exitmessage);
} }
return ("unknown reason"); return ("unknown reason");
} }
@@ -223,71 +214,76 @@ client_exit_message(void)
static void static void
client_exit(void) client_exit(void)
{ {
if (!file_write_left(&client_files)) struct client_file *cf;
size_t left;
int waiting = 0;
RB_FOREACH (cf, client_files, &client_files) {
if (cf->event == NULL)
continue;
left = EVBUFFER_LENGTH(cf->event->output);
if (left != 0) {
waiting++;
log_debug("file %u %zu bytes left", cf->stream, left);
}
}
if (waiting == 0)
proc_exit(client_proc); proc_exit(client_proc);
} }
/* Client main loop. */ /* Client main loop. */
int int
client_main(struct event_base *base, int argc, char **argv, uint64_t flags, client_main(struct event_base *base, int argc, char **argv, int flags)
int feat)
{ {
struct cmd_parse_result *pr; struct cmd_parse_result *pr;
struct cmd *cmd;
struct msg_command *data; struct msg_command *data;
int fd, i; int cmdflags, fd, i;
const char *ttynam, *termname, *cwd; const char *ttynam, *cwd;
pid_t ppid; pid_t ppid;
enum msgtype msg; enum msgtype msg;
struct termios tio, saved_tio; struct termios tio, saved_tio;
size_t size, linesize = 0; size_t size;
ssize_t linelen;
char *line = NULL, **caps = NULL, *cause; /* Ignore SIGCHLD now or daemon() in the server will leave a zombie. */
u_int ncaps = 0; signal(SIGCHLD, SIG_IGN);
struct args_value *values;
/* Save the flags. */
client_flags = flags;
/* Set up the initial command. */ /* Set up the initial command. */
cmdflags = 0;
if (shell_command != NULL) { if (shell_command != NULL) {
msg = MSG_SHELL; msg = MSG_SHELL;
flags |= CLIENT_STARTSERVER; cmdflags = CMD_STARTSERVER;
} else if (argc == 0) { } else if (argc == 0) {
msg = MSG_COMMAND; msg = MSG_COMMAND;
flags |= CLIENT_STARTSERVER; cmdflags = CMD_STARTSERVER;
} else { } else {
msg = MSG_COMMAND; msg = MSG_COMMAND;
/* /*
* It's annoying parsing the command string twice (in client * It sucks parsing the command string twice (in client and
* and later in server) but it is necessary to get the start * later in server) but it is necessary to get the start server
* server flag. * flag.
*/ */
values = args_from_vector(argc, argv); pr = cmd_parse_from_arguments(argc, argv, NULL);
pr = cmd_parse_from_arguments(values, argc, NULL);
if (pr->status == CMD_PARSE_SUCCESS) { if (pr->status == CMD_PARSE_SUCCESS) {
if (cmd_list_any_have(pr->cmdlist, CMD_STARTSERVER)) TAILQ_FOREACH(cmd, &pr->cmdlist->list, qentry) {
flags |= CLIENT_STARTSERVER; if (cmd->entry->flags & CMD_STARTSERVER)
cmdflags |= CMD_STARTSERVER;
}
cmd_list_free(pr->cmdlist); cmd_list_free(pr->cmdlist);
} else } else
free(pr->error); free(pr->error);
args_free_values(values, argc);
free(values);
} }
/* Create client process structure (starts logging). */ /* Create client process structure (starts logging). */
client_proc = proc_start("client"); client_proc = proc_start("client");
proc_set_signals(client_proc, client_signal); proc_set_signals(client_proc, client_signal);
/* Save the flags. */
client_flags = 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 fd = client_connect(base, socket_path, cmdflags & CMD_STARTSERVER);
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);
if (fd == -1) { if (fd == -1) {
if (errno == ECONNREFUSED) { if (errno == ECONNREFUSED) {
fprintf(stderr, "no server running on %s\n", fprintf(stderr, "no server running on %s\n",
@@ -305,8 +301,6 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
cwd = "/"; cwd = "/";
if ((ttynam = ttyname(STDIN_FILENO)) == NULL) if ((ttynam = ttyname(STDIN_FILENO)) == NULL)
ttynam = ""; ttynam = "";
if ((termname = getenv("TERM")) == NULL)
termname = "";
/* /*
* Drop privileges for client. "proc exec" is needed for -c and for * Drop privileges for client. "proc exec" is needed for -c and for
@@ -322,16 +316,6 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
NULL) != 0) NULL) != 0)
fatal("pledge failed"); fatal("pledge failed");
/* Load terminfo entry if any. */
if (isatty(STDIN_FILENO) &&
*termname != '\0' &&
tty_term_read_list(termname, STDIN_FILENO, &caps, &ncaps,
&cause) != 0) {
fprintf(stderr, "%s\n", cause);
free(cause);
return (1);
}
/* Free stuff that is not used in the client. */ /* Free stuff that is not used in the client. */
if (ptm_fd != -1) if (ptm_fd != -1)
close(ptm_fd); close(ptm_fd);
@@ -362,9 +346,7 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
} }
/* Send identify messages. */ /* Send identify messages. */
client_send_identify(ttynam, termname, caps, ncaps, cwd, feat); client_send_identify(ttynam, cwd);
tty_term_free_list(caps, ncaps);
proc_flush_peer(client_peer);
/* Send first command. */ /* Send first command. */
if (msg == MSG_COMMAND) { if (msg == MSG_COMMAND) {
@@ -407,11 +389,6 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
client_exec(client_execshell, client_execcmd); client_exec(client_execshell, client_execcmd);
} }
/* Restore streams to blocking. */
setblocking(STDIN_FILENO, 1);
setblocking(STDOUT_FILENO, 1);
setblocking(STDERR_FILENO, 1);
/* Print the exit message, if any, and exit. */ /* Print the exit message, if any, and exit. */
if (client_attached) { if (client_attached) {
if (client_exitreason != CLIENT_EXIT_NONE) if (client_exitreason != CLIENT_EXIT_NONE)
@@ -420,66 +397,42 @@ client_main(struct event_base *base, int argc, char **argv, uint64_t flags,
ppid = getppid(); ppid = getppid();
if (client_exittype == MSG_DETACHKILL && ppid > 1) if (client_exittype == MSG_DETACHKILL && ppid > 1)
kill(ppid, SIGHUP); kill(ppid, SIGHUP);
} else if (client_flags & CLIENT_CONTROL) { } else if (client_flags & CLIENT_CONTROLCONTROL) {
if (client_exitreason != CLIENT_EXIT_NONE) if (client_exitreason != CLIENT_EXIT_NONE)
printf("%%exit %s\n", client_exit_message()); printf("%%exit %s\n", client_exit_message());
else else
printf("%%exit\n"); printf("%%exit\n");
fflush(stdout); printf("\033\\");
if (client_flags & CLIENT_CONTROL_WAITEXIT) { tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio);
setvbuf(stdin, NULL, _IOLBF, 0);
for (;;) {
linelen = getline(&line, &linesize, stdin);
if (linelen <= 1)
break;
}
free(line);
}
if (client_flags & CLIENT_CONTROLCONTROL) {
printf("\033\\");
fflush(stdout);
tcsetattr(STDOUT_FILENO, TCSAFLUSH, &saved_tio);
}
} else if (client_exitreason != CLIENT_EXIT_NONE) } else if (client_exitreason != CLIENT_EXIT_NONE)
fprintf(stderr, "%s\n", client_exit_message()); fprintf(stderr, "%s\n", client_exit_message());
setblocking(STDIN_FILENO, 1);
return (client_exitval); return (client_exitval);
} }
/* Send identify messages to server. */ /* Send identify messages to server. */
static void static void
client_send_identify(const char *ttynam, const char *termname, char **caps, client_send_identify(const char *ttynam, const char *cwd)
u_int ncaps, const char *cwd, int feat)
{ {
char **ss; const char *s;
size_t sslen; char **ss;
int fd; size_t sslen;
uint64_t flags = client_flags; int fd, flags = client_flags;
pid_t pid; pid_t pid;
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,
sizeof client_flags);
proc_send(client_peer, MSG_IDENTIFY_TERM, -1, termname, if ((s = getenv("TERM")) == NULL)
strlen(termname) + 1); s = "";
proc_send(client_peer, MSG_IDENTIFY_FEATURES, -1, &feat, sizeof feat); proc_send(client_peer, MSG_IDENTIFY_TERM, -1, s, strlen(s) + 1);
proc_send(client_peer, MSG_IDENTIFY_TTYNAME, -1, ttynam, proc_send(client_peer, MSG_IDENTIFY_TTYNAME, -1, ttynam,
strlen(ttynam) + 1); strlen(ttynam) + 1);
proc_send(client_peer, MSG_IDENTIFY_CWD, -1, cwd, strlen(cwd) + 1); proc_send(client_peer, MSG_IDENTIFY_CWD, -1, cwd, strlen(cwd) + 1);
for (i = 0; i < ncaps; i++) {
proc_send(client_peer, MSG_IDENTIFY_TERMINFO, -1,
caps[i], strlen(caps[i]) + 1);
}
if ((fd = dup(STDIN_FILENO)) == -1) if ((fd = dup(STDIN_FILENO)) == -1)
fatal("dup failed"); fatal("dup failed");
proc_send(client_peer, MSG_IDENTIFY_STDIN, fd, NULL, 0); proc_send(client_peer, MSG_IDENTIFY_STDIN, fd, NULL, 0);
if ((fd = dup(STDOUT_FILENO)) == -1)
fatal("dup failed");
proc_send(client_peer, MSG_IDENTIFY_STDOUT, fd, NULL, 0);
pid = getpid(); pid = getpid();
proc_send(client_peer, MSG_IDENTIFY_CLIENTPID, -1, &pid, sizeof pid); proc_send(client_peer, MSG_IDENTIFY_CLIENTPID, -1, &pid, sizeof pid);
@@ -494,14 +447,275 @@ client_send_identify(const char *ttynam, const char *termname, char **caps,
proc_send(client_peer, MSG_IDENTIFY_DONE, -1, NULL, 0); proc_send(client_peer, MSG_IDENTIFY_DONE, -1, NULL, 0);
} }
/* File write error callback. */
static void
client_write_error_callback(__unused struct bufferevent *bev,
__unused short what, void *arg)
{
struct client_file *cf = arg;
log_debug("write error file %d", cf->stream);
bufferevent_free(cf->event);
cf->event = NULL;
close(cf->fd);
cf->fd = -1;
if (client_exitflag)
client_exit();
}
/* File write callback. */
static void
client_write_callback(__unused struct bufferevent *bev, void *arg)
{
struct client_file *cf = arg;
if (cf->closed && EVBUFFER_LENGTH(cf->event->output) == 0) {
bufferevent_free(cf->event);
close(cf->fd);
RB_REMOVE(client_files, &client_files, cf);
file_free(cf);
}
if (client_exitflag)
client_exit();
}
/* Open write file. */
static void
client_write_open(void *data, size_t datalen)
{
struct msg_write_open *msg = data;
const char *path;
struct msg_write_ready reply;
struct client_file find, *cf;
const int flags = O_NONBLOCK|O_WRONLY|O_CREAT;
int error = 0;
if (datalen < sizeof *msg)
fatalx("bad MSG_WRITE_OPEN size");
if (datalen == sizeof *msg)
path = "-";
else
path = (const char *)(msg + 1);
log_debug("open write file %d %s", msg->stream, path);
find.stream = msg->stream;
if ((cf = RB_FIND(client_files, &client_files, &find)) == NULL) {
cf = file_create(NULL, msg->stream, NULL, NULL);
RB_INSERT(client_files, &client_files, cf);
} else {
error = EBADF;
goto reply;
}
if (cf->closed) {
error = EBADF;
goto reply;
}
cf->fd = -1;
if (msg->fd == -1)
cf->fd = open(path, msg->flags|flags, 0644);
else {
if (msg->fd != STDOUT_FILENO && msg->fd != STDERR_FILENO)
errno = EBADF;
else {
cf->fd = dup(msg->fd);
if (~client_flags & CLIENT_CONTROL)
close(msg->fd); /* can only be used once */
}
}
if (cf->fd == -1) {
error = errno;
goto reply;
}
cf->event = bufferevent_new(cf->fd, NULL, client_write_callback,
client_write_error_callback, cf);
bufferevent_enable(cf->event, EV_WRITE);
goto reply;
reply:
reply.stream = msg->stream;
reply.error = error;
proc_send(client_peer, MSG_WRITE_READY, -1, &reply, sizeof reply);
}
/* Write to client file. */
static void
client_write_data(void *data, size_t datalen)
{
struct msg_write_data *msg = data;
struct client_file find, *cf;
size_t size = datalen - sizeof *msg;
if (datalen < sizeof *msg)
fatalx("bad MSG_WRITE size");
find.stream = msg->stream;
if ((cf = RB_FIND(client_files, &client_files, &find)) == NULL)
fatalx("unknown stream number");
log_debug("write %zu to file %d", size, cf->stream);
if (cf->event != NULL)
bufferevent_write(cf->event, msg + 1, size);
}
/* Close client file. */
static void
client_write_close(void *data, size_t datalen)
{
struct msg_write_close *msg = data;
struct client_file find, *cf;
if (datalen != sizeof *msg)
fatalx("bad MSG_WRITE_CLOSE size");
find.stream = msg->stream;
if ((cf = RB_FIND(client_files, &client_files, &find)) == NULL)
fatalx("unknown stream number");
log_debug("close file %d", cf->stream);
if (cf->event == NULL || EVBUFFER_LENGTH(cf->event->output) == 0) {
if (cf->event != NULL)
bufferevent_free(cf->event);
if (cf->fd != -1)
close(cf->fd);
RB_REMOVE(client_files, &client_files, cf);
file_free(cf);
}
}
/* File read callback. */
static void
client_read_callback(__unused struct bufferevent *bev, void *arg)
{
struct client_file *cf = arg;
void *bdata;
size_t bsize;
struct msg_read_data *msg;
size_t msglen;
msg = xmalloc(sizeof *msg);
for (;;) {
bdata = EVBUFFER_DATA(cf->event->input);
bsize = EVBUFFER_LENGTH(cf->event->input);
if (bsize == 0)
break;
if (bsize > MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg)
bsize = MAX_IMSGSIZE - IMSG_HEADER_SIZE - sizeof *msg;
log_debug("read %zu from file %d", bsize, cf->stream);
msglen = (sizeof *msg) + bsize;
msg = xrealloc(msg, msglen);
msg->stream = cf->stream;
memcpy(msg + 1, bdata, bsize);
proc_send(client_peer, MSG_READ, -1, msg, msglen);
evbuffer_drain(cf->event->input, bsize);
}
free(msg);
}
/* File read error callback. */
static void
client_read_error_callback(__unused struct bufferevent *bev,
__unused short what, void *arg)
{
struct client_file *cf = arg;
struct msg_read_done msg;
log_debug("read error file %d", cf->stream);
msg.stream = cf->stream;
msg.error = 0;
proc_send(client_peer, MSG_READ_DONE, -1, &msg, sizeof msg);
bufferevent_free(cf->event);
close(cf->fd);
RB_REMOVE(client_files, &client_files, cf);
file_free(cf);
}
/* Open read file. */
static void
client_read_open(void *data, size_t datalen)
{
struct msg_read_open *msg = data;
const char *path;
struct msg_read_done reply;
struct client_file find, *cf;
const int flags = O_NONBLOCK|O_RDONLY;
int error = 0;
if (datalen < sizeof *msg)
fatalx("bad MSG_READ_OPEN size");
if (datalen == sizeof *msg)
path = "-";
else
path = (const char *)(msg + 1);
log_debug("open read file %d %s", msg->stream, path);
find.stream = msg->stream;
if ((cf = RB_FIND(client_files, &client_files, &find)) == NULL) {
cf = file_create(NULL, msg->stream, NULL, NULL);
RB_INSERT(client_files, &client_files, cf);
} else {
error = EBADF;
goto reply;
}
if (cf->closed) {
error = EBADF;
goto reply;
}
cf->fd = -1;
if (msg->fd == -1)
cf->fd = open(path, flags);
else {
if (msg->fd != STDIN_FILENO)
errno = EBADF;
else {
cf->fd = dup(msg->fd);
if (~client_flags & CLIENT_CONTROL)
close(msg->fd); /* can only be used once */
}
}
if (cf->fd == -1) {
error = errno;
goto reply;
}
cf->event = bufferevent_new(cf->fd, client_read_callback, NULL,
client_read_error_callback, cf);
bufferevent_enable(cf->event, EV_READ);
return;
reply:
reply.stream = msg->stream;
reply.error = error;
proc_send(client_peer, MSG_READ_DONE, -1, &reply, sizeof reply);
}
/* Run command in shell; used for -c. */ /* Run command in shell; used for -c. */
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,23 +735,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)); if (sig == SIGCHLD)
if (sig == SIGCHLD) { waitpid(WAIT_ANY, &status, WNOHANG);
for (;;) { else if (!client_attached) {
pid = waitpid(WAIT_ANY, &status, WNOHANG); if (sig == SIGTERM)
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)
proc_exit(client_proc); proc_exit(client_proc);
} else { } else {
switch (sig) { switch (sig) {
@@ -547,8 +749,7 @@ client_signal(int sig)
proc_send(client_peer, MSG_EXITING, -1, NULL, 0); proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
break; break;
case SIGTERM: case SIGTERM:
if (!client_suspended) client_exitreason = CLIENT_EXIT_TERMINATED;
client_exitreason = CLIENT_EXIT_TERMINATED;
client_exitval = 1; client_exitval = 1;
proc_send(client_peer, MSG_EXITING, -1, NULL, 0); proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
break; break;
@@ -563,31 +764,18 @@ client_signal(int sig)
if (sigaction(SIGTSTP, &sigact, NULL) != 0) if (sigaction(SIGTSTP, &sigact, NULL) != 0)
fatal("sigaction failed"); fatal("sigaction failed");
proc_send(client_peer, MSG_WAKEUP, -1, NULL, 0); proc_send(client_peer, MSG_WAKEUP, -1, NULL, 0);
client_suspended = 0;
break; break;
} }
} }
} }
/* Callback for file write error or close. */
static void
client_file_check_cb(__unused struct client *c, __unused const char *path,
__unused int error, __unused int closed, __unused struct evbuffer *buffer,
__unused void *data)
{
if (client_exitflag)
client_exit();
}
/* Callback for client read events. */ /* Callback for client read events. */
static void static void
client_dispatch(struct imsg *imsg, __unused void *arg) client_dispatch(struct imsg *imsg, __unused void *arg)
{ {
if (imsg == NULL) { if (imsg == NULL) {
if (!client_exitflag) { client_exitreason = CLIENT_EXIT_LOST_SERVER;
client_exitreason = CLIENT_EXIT_LOST_SERVER; client_exitval = 1;
client_exitval = 1;
}
proc_exit(client_proc); proc_exit(client_proc);
return; return;
} }
@@ -598,38 +786,13 @@ client_dispatch(struct imsg *imsg, __unused void *arg)
client_dispatch_wait(imsg); client_dispatch_wait(imsg);
} }
/* Process an exit message. */
static void
client_dispatch_exit_message(char *data, size_t datalen)
{
int retval;
if (datalen < sizeof retval && datalen != 0)
fatalx("bad MSG_EXIT size");
if (datalen >= sizeof retval) {
memcpy(&retval, data, sizeof retval);
client_exitval = retval;
}
if (datalen > sizeof retval) {
datalen -= sizeof retval;
data += sizeof retval;
client_exitmessage = xmalloc(datalen);
memcpy(client_exitmessage, data, datalen);
client_exitmessage[datalen - 1] = '\0';
client_exitreason = CLIENT_EXIT_MESSAGE_PROVIDED;
}
}
/* Dispatch imsgs when in wait state (before MSG_READY). */ /* Dispatch imsgs when in wait state (before MSG_READY). */
static void static void
client_dispatch_wait(struct imsg *imsg) client_dispatch_wait(struct imsg *imsg)
{ {
char *data; char *data;
ssize_t datalen; ssize_t datalen;
int retval;
static int pledge_applied; static int pledge_applied;
/* /*
@@ -652,7 +815,12 @@ client_dispatch_wait(struct imsg *imsg)
switch (imsg->hdr.type) { switch (imsg->hdr.type) {
case MSG_EXIT: case MSG_EXIT:
case MSG_SHUTDOWN: case MSG_SHUTDOWN:
client_dispatch_exit_message(data, datalen); if (datalen != sizeof retval && datalen != 0)
fatalx("bad MSG_EXIT size");
if (datalen == sizeof retval) {
memcpy(&retval, data, sizeof retval);
client_exitval = retval;
}
client_exitflag = 1; client_exitflag = 1;
client_exit(); client_exit();
break; break;
@@ -673,14 +841,6 @@ client_dispatch_wait(struct imsg *imsg)
client_exitval = 1; client_exitval = 1;
proc_exit(client_proc); proc_exit(client_proc);
break; break;
case MSG_FLAGS:
if (datalen != sizeof client_flags)
fatalx("bad MSG_FLAGS string");
memcpy(&client_flags, data, sizeof client_flags);
log_debug("new flags are %#llx",
(unsigned long long)client_flags);
break;
case MSG_SHELL: case MSG_SHELL:
if (datalen == 0 || data[datalen - 1] != '\0') if (datalen == 0 || data[datalen - 1] != '\0')
fatalx("bad MSG_SHELL string"); fatalx("bad MSG_SHELL string");
@@ -695,23 +855,16 @@ client_dispatch_wait(struct imsg *imsg)
proc_exit(client_proc); proc_exit(client_proc);
break; break;
case MSG_READ_OPEN: case MSG_READ_OPEN:
file_read_open(&client_files, client_peer, imsg, 1, client_read_open(data, datalen);
!(client_flags & CLIENT_CONTROL), client_file_check_cb,
NULL);
break;
case MSG_READ_CANCEL:
file_read_cancel(&client_files, imsg);
break; break;
case MSG_WRITE_OPEN: case MSG_WRITE_OPEN:
file_write_open(&client_files, client_peer, imsg, 1, client_write_open(data, datalen);
!(client_flags & CLIENT_CONTROL), client_file_check_cb,
NULL);
break; break;
case MSG_WRITE: case MSG_WRITE:
file_write_data(&client_files, imsg); client_write_data(data, datalen);
break; break;
case MSG_WRITE_CLOSE: case MSG_WRITE_CLOSE:
file_write_close(&client_files, imsg); client_write_close(data, datalen);
break; break;
case MSG_OLDSTDERR: case MSG_OLDSTDERR:
case MSG_OLDSTDIN: case MSG_OLDSTDIN:
@@ -734,14 +887,6 @@ client_dispatch_attached(struct imsg *imsg)
datalen = imsg->hdr.len - IMSG_HEADER_SIZE; datalen = imsg->hdr.len - IMSG_HEADER_SIZE;
switch (imsg->hdr.type) { switch (imsg->hdr.type) {
case MSG_FLAGS:
if (datalen != sizeof client_flags)
fatalx("bad MSG_FLAGS string");
memcpy(&client_flags, data, sizeof client_flags);
log_debug("new flags are %#llx",
(unsigned long long)client_flags);
break;
case MSG_DETACH: case MSG_DETACH:
case MSG_DETACHKILL: case MSG_DETACHKILL:
if (datalen == 0 || data[datalen - 1] != '\0') if (datalen == 0 || data[datalen - 1] != '\0')
@@ -766,10 +911,11 @@ client_dispatch_attached(struct imsg *imsg)
proc_send(client_peer, MSG_EXITING, -1, NULL, 0); proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
break; break;
case MSG_EXIT: case MSG_EXIT:
client_dispatch_exit_message(data, datalen); if (datalen != 0 && datalen != sizeof (int))
if (client_exitreason == CLIENT_EXIT_NONE) fatalx("bad MSG_EXIT size");
client_exitreason = CLIENT_EXIT_EXITED;
proc_send(client_peer, MSG_EXITING, -1, NULL, 0); proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
client_exitreason = CLIENT_EXIT_EXITED;
break; break;
case MSG_EXITED: case MSG_EXITED:
if (datalen != 0) if (datalen != 0)
@@ -795,7 +941,6 @@ client_dispatch_attached(struct imsg *imsg)
sigact.sa_handler = SIG_DFL; sigact.sa_handler = SIG_DFL;
if (sigaction(SIGTSTP, &sigact, NULL) != 0) if (sigaction(SIGTSTP, &sigact, NULL) != 0)
fatal("sigaction failed"); fatal("sigaction failed");
client_suspended = 1;
kill(getpid(), SIGTSTP); kill(getpid(), SIGTSTP);
break; break;
case MSG_LOCK: case MSG_LOCK:

View File

@@ -37,29 +37,27 @@ const struct cmd_entry cmd_attach_session_entry = {
.name = "attach-session", .name = "attach-session",
.alias = "attach", .alias = "attach",
.args = { "c:dEf:rt:x", 0, 0, NULL }, .args = { "c:dErt:x", 0, 0 },
.usage = "[-dErx] [-c working-directory] [-f flags] " .usage = "[-dErx] [-c working-directory] " CMD_TARGET_SESSION_USAGE,
CMD_TARGET_SESSION_USAGE,
/* -t is special */ /* -t is special */
.flags = CMD_STARTSERVER|CMD_READONLY, .flags = CMD_STARTSERVER,
.exec = cmd_attach_session_exec .exec = cmd_attach_session_exec
}; };
enum cmd_retval enum cmd_retval
cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag, cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
int xflag, int rflag, const char *cflag, int Eflag, const char *fflag) int xflag, int rflag, const char *cflag, int Eflag)
{ {
struct cmd_find_state *current = cmdq_get_current(item); struct cmd_find_state *current = &item->shared->current;
struct cmd_find_state target;
enum cmd_find_type type; enum cmd_find_type type;
int flags; int flags;
struct client *c = cmdq_get_client(item), *c_loop; struct client *c = item->client, *c_loop;
struct session *s; struct session *s;
struct winlink *wl; struct winlink *wl;
struct window_pane *wp; struct window_pane *wp;
char *cwd, *cause; char *cause;
enum msgtype msgtype; enum msgtype msgtype;
if (RB_EMPTY(&sessions)) { if (RB_EMPTY(&sessions)) {
@@ -69,7 +67,6 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
if (c == NULL) if (c == NULL)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
if (server_client_check_nested(c)) { if (server_client_check_nested(c)) {
cmdq_error(item, "sessions should be nested with care, " cmdq_error(item, "sessions should be nested with care, "
"unset $TMUX to force"); "unset $TMUX to force");
@@ -83,11 +80,11 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
type = CMD_FIND_SESSION; type = CMD_FIND_SESSION;
flags = CMD_FIND_PREFER_UNATTACHED; flags = CMD_FIND_PREFER_UNATTACHED;
} }
if (cmd_find_target(&target, item, tflag, type, flags) != 0) if (cmd_find_target(&item->target, item, tflag, type, flags) != 0)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
s = target.s; s = item->target.s;
wl = target.wl; wl = item->target.wl;
wp = target.wp; wp = item->target.wp;
if (wl != NULL) { if (wl != NULL) {
if (wp != NULL) if (wp != NULL)
@@ -100,14 +97,9 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
} }
if (cflag != NULL) { if (cflag != NULL) {
cwd = format_single(item, cflag, c, s, wl, wp);
free((void *)s->cwd); free((void *)s->cwd);
s->cwd = cwd; s->cwd = format_single(item, cflag, c, s, wl, wp);
} }
if (fflag)
server_client_set_flags(c, fflag);
if (rflag)
c->flags |= (CLIENT_READONLY|CLIENT_IGNORESIZE);
c->last_session = c->session; c->last_session = c->session;
if (c->session != NULL) { if (c->session != NULL) {
@@ -125,15 +117,25 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
if (!Eflag) if (!Eflag)
environ_update(s->options, c->environ, s->environ); environ_update(s->options, c->environ, s->environ);
server_client_set_session(c, s); c->session = s;
if (~cmdq_get_flags(item) & CMDQ_STATE_REPEAT) if (~item->shared->flags & CMDQ_SHARED_REPEAT)
server_client_set_key_table(c, NULL); server_client_set_key_table(c, NULL);
tty_update_client_offset(c);
status_timer_start(c);
notify_client("client-session-changed", c);
session_update_activity(s, NULL);
gettimeofday(&s->last_attached_time, NULL);
server_redraw_client(c);
s->curw->flags &= ~WINLINK_ALERTFLAGS;
s->curw->window->latest = c;
} else { } else {
if (server_client_open(c, &cause) != 0) { if (server_client_open(c, &cause) != 0) {
cmdq_error(item, "open terminal failed: %s", cause); cmdq_error(item, "open terminal failed: %s", cause);
free(cause); free(cause);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (rflag)
c->flags |= CLIENT_READONLY;
if (dflag || xflag) { if (dflag || xflag) {
if (xflag) if (xflag)
@@ -149,17 +151,25 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
if (!Eflag) if (!Eflag)
environ_update(s->options, c->environ, s->environ); environ_update(s->options, c->environ, s->environ);
server_client_set_session(c, s); c->session = s;
server_client_set_key_table(c, NULL); server_client_set_key_table(c, NULL);
tty_update_client_offset(c);
status_timer_start(c);
notify_client("client-session-changed", c);
session_update_activity(s, NULL);
gettimeofday(&s->last_attached_time, NULL);
server_redraw_client(c);
s->curw->flags &= ~WINLINK_ALERTFLAGS;
s->curw->window->latest = c;
if (~c->flags & CLIENT_CONTROL) if (~c->flags & CLIENT_CONTROL)
proc_send(c->peer, MSG_READY, -1, NULL, 0); proc_send(c->peer, MSG_READY, -1, NULL, 0);
notify_client("client-attached", c); notify_client("client-attached", c);
c->flags |= CLIENT_ATTACHED; c->flags |= CLIENT_ATTACHED;
} }
recalculate_sizes();
if (cfg_finished) alerts_check_session(s);
cfg_show_causes(s); server_update_socket();
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
@@ -167,9 +177,9 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
static enum cmd_retval static enum cmd_retval
cmd_attach_session_exec(struct cmd *self, struct cmdq_item *item) cmd_attach_session_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
return (cmd_attach_session(item, args_get(args, 't'), return (cmd_attach_session(item, args_get(args, 't'),
args_has(args, 'd'), args_has(args, 'x'), args_has(args, 'r'), args_has(args, 'd'), args_has(args, 'x'), args_has(args, 'r'),
args_get(args, 'c'), args_has(args, 'E'), args_get(args, 'f'))); args_get(args, 'c'), args_has(args, 'E')));
} }

View File

@@ -27,44 +27,33 @@
* Bind a key to a command. * Bind a key to a command.
*/ */
static enum args_parse_type cmd_bind_key_args_parse(struct args *, u_int, static enum cmd_retval cmd_bind_key_exec(struct cmd *, struct cmdq_item *);
char **);
static enum cmd_retval cmd_bind_key_exec(struct cmd *,
struct cmdq_item *);
const struct cmd_entry cmd_bind_key_entry = { const struct cmd_entry cmd_bind_key_entry = {
.name = "bind-key", .name = "bind-key",
.alias = "bind", .alias = "bind",
.args = { "nrN:T:", 1, -1, cmd_bind_key_args_parse }, .args = { "nrN:T:", 2, -1 },
.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
}; };
static enum args_parse_type
cmd_bind_key_args_parse(__unused struct args *args, __unused u_int idx,
__unused char **cause)
{
return (ARGS_PARSE_COMMANDS_OR_STRING);
}
static enum cmd_retval static enum cmd_retval
cmd_bind_key_exec(struct cmd *self, struct cmdq_item *item) cmd_bind_key_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
key_code key; key_code key;
const char *tablename, *note = args_get(args, 'N'); const char *tablename, *note;
struct cmd_parse_result *pr; struct cmd_parse_result *pr;
int repeat; char **argv = args->argv;
struct args_value *value; int argc = args->argc, repeat;
u_int count = args_count(args);
key = key_string_lookup_string(args_string(args, 0)); key = key_string_lookup_string(argv[0]);
if (key == KEYC_NONE || key == KEYC_UNKNOWN) { if (key == KEYC_NONE || key == KEYC_UNKNOWN) {
cmdq_error(item, "unknown key: %s", args_string(args, 0)); cmdq_error(item, "unknown key: %s", argv[0]);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
@@ -76,25 +65,14 @@ cmd_bind_key_exec(struct cmd *self, struct cmdq_item *item)
tablename = "prefix"; tablename = "prefix";
repeat = args_has(args, 'r'); repeat = args_has(args, 'r');
if (count == 1) { if (argc == 2)
key_bindings_add(tablename, key, note, repeat, NULL); pr = cmd_parse_from_string(argv[1], NULL);
return (CMD_RETURN_NORMAL); else
} pr = cmd_parse_from_arguments(argc - 1, argv + 1, NULL);
value = args_value(args, 1);
if (count == 2 && value->type == ARGS_COMMANDS) {
key_bindings_add(tablename, key, note, repeat, value->cmdlist);
value->cmdlist->references++;
return (CMD_RETURN_NORMAL);
}
if (count == 2)
pr = cmd_parse_from_string(args_string(args, 1), NULL);
else {
pr = cmd_parse_from_arguments(args_values(args) + 1, count - 1,
NULL);
}
switch (pr->status) { switch (pr->status) {
case CMD_PARSE_EMPTY:
cmdq_error(item, "empty command");
return (CMD_RETURN_ERROR);
case CMD_PARSE_ERROR: case CMD_PARSE_ERROR:
cmdq_error(item, "%s", pr->error); cmdq_error(item, "%s", pr->error);
free(pr->error); free(pr->error);
@@ -102,6 +80,7 @@ cmd_bind_key_exec(struct cmd *self, struct cmdq_item *item)
case CMD_PARSE_SUCCESS: case CMD_PARSE_SUCCESS:
break; break;
} }
note = args_get(args, 'N');
key_bindings_add(tablename, key, note, repeat, pr->cmdlist); key_bindings_add(tablename, key, note, repeat, pr->cmdlist);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@@ -34,8 +34,8 @@ const struct cmd_entry cmd_break_pane_entry = {
.name = "break-pane", .name = "break-pane",
.alias = "breakp", .alias = "breakp",
.args = { "abdPF:n:s:t:", 0, 0, NULL }, .args = { "dPF:n:s:t:", 0, 0 },
.usage = "[-abdP] [-F format] [-n window-name] [-s src-pane] " .usage = "[-dP] [-F format] [-n window-name] [-s src-pane] "
"[-t dst-window]", "[-t dst-window]",
.source = { 's', CMD_FIND_PANE, 0 }, .source = { 's', CMD_FIND_PANE, 0 },
@@ -48,64 +48,40 @@ const struct cmd_entry cmd_break_pane_entry = {
static enum cmd_retval static enum cmd_retval
cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item) cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *current = cmdq_get_current(item); struct cmd_find_state *current = &item->shared->current;
struct cmd_find_state *target = cmdq_get_target(item); struct client *c = cmd_find_client(item, NULL, 1);
struct cmd_find_state *source = cmdq_get_source(item); struct winlink *wl = item->source.wl;
struct client *tc = cmdq_get_target_client(item); struct session *src_s = item->source.s;
struct winlink *wl = source->wl; struct session *dst_s = item->target.s;
struct session *src_s = source->s; struct window_pane *wp = item->source.wp;
struct session *dst_s = target->s;
struct window_pane *wp = source->wp;
struct window *w = wl->window; struct window *w = wl->window;
char *name, *cause, *cp; char *name, *cause;
int idx = target->idx, before; int idx = item->target.idx;
const char *template; const char *template;
char *cp;
before = args_has(args, 'b');
if (args_has(args, 'a') || before) {
if (target->wl != NULL)
idx = winlink_shuffle_up(dst_s, target->wl, before);
else
idx = winlink_shuffle_up(dst_s, dst_s->curw, before);
if (idx == -1)
return (CMD_RETURN_ERROR);
}
server_unzoom_window(w);
if (window_count_panes(w) == 1) {
if (server_link_window(src_s, wl, dst_s, idx, 0,
!args_has(args, 'd'), &cause) != 0) {
cmdq_error(item, "%s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
if (args_has(args, 'n')) {
window_set_name(w, args_get(args, 'n'));
options_set_number(w->options, "automatic-rename", 0);
}
server_unlink_window(src_s, wl);
wl = winlink_find_by_window(&dst_s->windows, w);
if (wl == NULL)
return (CMD_RETURN_ERROR);
goto out;
}
if (idx != -1 && winlink_find_by_index(&dst_s->windows, idx) != NULL) { if (idx != -1 && winlink_find_by_index(&dst_s->windows, idx) != NULL) {
cmdq_error(item, "index in use: %d", idx); cmdq_error(item, "index %d already in use", idx);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (window_count_panes(w) == 1) {
cmdq_error(item, "can't break with only one pane");
return (CMD_RETURN_ERROR);
}
server_unzoom_window(w);
TAILQ_REMOVE(&w->panes, wp, entry); TAILQ_REMOVE(&w->panes, wp, entry);
server_client_remove_pane(wp);
window_lost_pane(w, wp); window_lost_pane(w, wp);
layout_close_pane(wp); layout_close_pane(wp);
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 = c;
if (!args_has(args, 'n')) { if (!args_has(args, 'n')) {
name = default_window_name(w); name = default_window_name(w);
@@ -118,12 +94,11 @@ 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");
wl = session_attach(dst_s, w, idx, &cause); /* can't fail */ wl = session_attach(dst_s, w, idx, &cause); /* can't fail */
if (!args_has(args, 'd')) { if (!args_has(self->args, 'd')) {
session_select(dst_s, wl->idx); session_select(dst_s, wl->idx);
cmd_find_from_session(current, dst_s, 0); cmd_find_from_session(current, dst_s, 0);
} }
@@ -135,11 +110,10 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
if (src_s != dst_s) if (src_s != dst_s)
server_status_session_group(dst_s); server_status_session_group(dst_s);
out:
if (args_has(args, 'P')) { if (args_has(args, 'P')) {
if ((template = args_get(args, 'F')) == NULL) if ((template = args_get(args, 'F')) == NULL)
template = BREAK_PANE_TEMPLATE; template = BREAK_PANE_TEMPLATE;
cp = format_single(item, template, tc, dst_s, wl, wp); cp = format_single(item, template, c, dst_s, wl, wp);
cmdq_print(item, "%s", cp); cmdq_print(item, "%s", cp);
free(cp); free(cp);
} }

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 },
.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 },
.usage = "[-H] " CMD_TARGET_PANE_USAGE, .usage = CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
@@ -80,7 +80,7 @@ cmd_capture_pane_pending(struct args *args, struct window_pane *wp,
size_t linelen; size_t linelen;
u_int i; u_int i;
pending = input_pending(wp->ictx); pending = input_pending(wp);
if (pending == NULL) if (pending == NULL)
return (xstrdup("")); return (xstrdup(""));
@@ -107,20 +107,18 @@ 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')) {
gd = wp->base.saved_grid; gd = wp->saved_grid;
if (gd == NULL) { if (gd == NULL) {
if (!args_has(args, 'q')) { if (!args_has(args, 'q')) {
cmdq_error(item, "no alternate screen"); cmdq_error(item, "no alternate screen");
@@ -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);
@@ -212,18 +192,16 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
static enum cmd_retval static enum cmd_retval
cmd_capture_pane_exec(struct cmd *self, struct cmdq_item *item) cmd_capture_pane_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct client *c = cmdq_get_client(item); struct client *c = item->client;
struct window_pane *wp = cmdq_get_target(item)->wp; struct window_pane *wp = item->target.wp;
char *buf, *cause; char *buf, *cause;
const char *bufname; const char *bufname;
size_t len; size_t len;
if (cmd_get_entry(self) == &cmd_clear_history_entry) { if (self->entry == &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);
} }
@@ -236,19 +214,14 @@ cmd_capture_pane_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
if (args_has(args, 'p')) { if (args_has(args, 'p')) {
if (len > 0 && buf[len - 1] == '\n') if (!file_can_print(c)) {
len--; cmdq_error(item, "can't write output to client");
if (c->flags & CLIENT_CONTROL) free(buf);
control_write(c, "%.*s", (int)len, buf); return (CMD_RETURN_ERROR);
else {
if (!file_can_print(c)) {
cmdq_error(item, "can't write to client");
free(buf);
return (CMD_RETURN_ERROR);
}
file_print_buffer(c, buf, len);
file_print(c, "\n");
} }
file_print_buffer(c, buf, len);
if (args_has(args, 'P') && len > 0)
file_print(c, "\n");
free(buf); free(buf);
} else { } else {
bufname = NULL; bufname = NULL;

View File

@@ -24,18 +24,15 @@
* Enter a mode. * Enter a mode.
*/ */
static enum args_parse_type cmd_choose_tree_args_parse(struct args *args, static enum cmd_retval cmd_choose_tree_exec(struct cmd *, struct cmdq_item *);
u_int idx, char **cause);
static enum cmd_retval cmd_choose_tree_exec(struct cmd *,
struct cmdq_item *);
const struct cmd_entry cmd_choose_tree_entry = { 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:Gf:NO:rst:wZ", 0, 1 },
.usage = "[-GNrswZ] [-F format] [-f filter] [-K key-format] " .usage = "[-GNrswZ] [-F format] [-f filter] [-O sort-order] "
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]", CMD_TARGET_PANE_USAGE " [template]",
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
@@ -47,9 +44,9 @@ 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:NO:rt:Z", 0, 1 },
.usage = "[-NrZ] [-F format] [-f filter] [-K key-format] " .usage = "[-NrZ] [-F format] [-f filter] [-O sort-order] "
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]", CMD_TARGET_PANE_USAGE " [template]",
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
@@ -61,9 +58,9 @@ 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:NO:rt:Z", 0, 1 },
.usage = "[-NrZ] [-F format] [-f filter] [-K key-format] " .usage = "[-NrZ] [-F format] [-f filter] [-O sort-order] "
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]", CMD_TARGET_PANE_USAGE " [template]",
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
@@ -71,47 +68,24 @@ const struct cmd_entry cmd_choose_buffer_entry = {
.exec = cmd_choose_tree_exec .exec = cmd_choose_tree_exec
}; };
const struct cmd_entry cmd_customize_mode_entry = {
.name = "customize-mode",
.alias = NULL,
.args = { "F:f:Nt:yZ", 0, 0, NULL },
.usage = "[-NZ] [-F format] [-f filter] " CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 },
.flags = 0,
.exec = cmd_choose_tree_exec
};
static enum args_parse_type
cmd_choose_tree_args_parse(__unused struct args *args, __unused u_int idx,
__unused char **cause)
{
return (ARGS_PARSE_COMMANDS_OR_STRING);
}
static enum cmd_retval static enum cmd_retval
cmd_choose_tree_exec(struct cmd *self, struct cmdq_item *item) cmd_choose_tree_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item); struct window_pane *wp = item->target.wp;
struct window_pane *wp = target->wp;
const struct window_mode *mode; const struct window_mode *mode;
if (cmd_get_entry(self) == &cmd_choose_buffer_entry) { if (self->entry == &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 (self->entry == &cmd_choose_client_entry) {
if (server_client_how_many() == 0) if (server_client_how_many() == 0)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
mode = &window_client_mode; mode = &window_client_mode;
} else if (cmd_get_entry(self) == &cmd_customize_mode_entry) } else
mode = &window_customize_mode;
else
mode = &window_tree_mode; mode = &window_tree_mode;
window_pane_set_mode(wp, NULL, mode, target, args); window_pane_set_mode(wp, mode, &item->target, args);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@@ -29,10 +29,8 @@
* Prompt for command in client. * Prompt for command in client.
*/ */
static enum args_parse_type cmd_command_prompt_args_parse(struct args *, static enum cmd_retval cmd_command_prompt_exec(struct cmd *,
u_int, char **); struct cmdq_item *);
static enum cmd_retval cmd_command_prompt_exec(struct cmd *,
struct cmdq_item *);
static int cmd_command_prompt_callback(struct client *, void *, static int cmd_command_prompt_callback(struct client *, void *,
const char *, int); const char *, int);
@@ -42,118 +40,81 @@ const struct cmd_entry cmd_command_prompt_entry = {
.name = "command-prompt", .name = "command-prompt",
.alias = NULL, .alias = NULL,
.args = { "1bFkliI:Np:t:T:", 0, 1, cmd_command_prompt_args_parse }, .args = { "1kiI:Np:t:", 0, 1 },
.usage = "[-1bFkliN] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE .usage = "[-1kiN] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE " "
" [-T prompt-type] [template]", "[template]",
.flags = CMD_CLIENT_TFLAG, .flags = 0,
.exec = cmd_command_prompt_exec .exec = cmd_command_prompt_exec
}; };
struct cmd_command_prompt_prompt {
char *input;
char *prompt;
};
struct cmd_command_prompt_cdata { struct cmd_command_prompt_cdata {
struct cmdq_item *item; int flags;
struct args_command_state *state;
int flags; char *inputs;
enum prompt_type prompt_type; char *next_input;
struct cmd_command_prompt_prompt *prompts; char *prompts;
u_int count; char *next_prompt;
u_int current;
int argc; char *template;
char **argv; int idx;
}; };
static enum args_parse_type
cmd_command_prompt_args_parse(__unused struct args *args, __unused u_int idx,
__unused char **cause)
{
return (ARGS_PARSE_COMMANDS_OR_STRING);
}
static enum cmd_retval static enum cmd_retval
cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item) cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct client *tc = cmdq_get_target_client(item); const char *inputs, *prompts;
struct cmd_find_state *target = cmdq_get_target(item);
const char *type, *s, *input;
struct cmd_command_prompt_cdata *cdata; struct cmd_command_prompt_cdata *cdata;
char *tmp, *prompts, *prompt, *next_prompt; struct client *c;
char *inputs = NULL, *next_input; char *prompt, *ptr, *input = NULL;
u_int count = args_count(args); size_t n;
int wait = !args_has(args, 'b'), space = 1;
if (tc->prompt_string != NULL) if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
if (c->prompt_string != NULL)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
if (args_has(args, 'i'))
wait = 0;
cdata = xcalloc(1, sizeof *cdata); cdata = xcalloc(1, sizeof *cdata);
if (wait)
cdata->item = item;
cdata->state = args_make_commands_prepare(self, item, 0, "%1", wait,
args_has(args, 'F'));
if ((s = args_get(args, 'p')) == NULL) { cdata->inputs = NULL;
if (count != 0) { cdata->next_input = NULL;
tmp = args_make_commands_get_command(cdata->state);
xasprintf(&prompts, "(%s)", tmp); cdata->prompts = NULL;
free(tmp); cdata->next_prompt = NULL;
} else {
prompts = xstrdup(":"); cdata->template = NULL;
space = 0; cdata->idx = 1;
}
next_prompt = prompts; if (args->argc != 0)
} else cdata->template = xstrdup(args->argv[0]);
next_prompt = prompts = xstrdup(s);
if ((s = args_get(args, 'I')) != NULL)
next_input = inputs = xstrdup(s);
else else
next_input = NULL; cdata->template = xstrdup("%1");
if (args_has(args, 'l')) {
cdata->prompts = xcalloc(1, sizeof *cdata->prompts);
cdata->prompts[0].prompt = prompts;
cdata->prompts[0].input = inputs;
cdata->count = 1;
} else {
while ((prompt = strsep(&next_prompt, ",")) != NULL) {
cdata->prompts = xreallocarray(cdata->prompts,
cdata->count + 1, sizeof *cdata->prompts);
if (!space)
tmp = xstrdup(prompt);
else
xasprintf(&tmp, "%s ", prompt);
cdata->prompts[cdata->count].prompt = tmp;
if (next_input != NULL) { if ((prompts = args_get(args, 'p')) != NULL)
input = strsep(&next_input, ","); cdata->prompts = xstrdup(prompts);
if (input == NULL) else if (args->argc != 0) {
input = ""; n = strcspn(cdata->template, " ,");
} else xasprintf(&cdata->prompts, "(%.*s) ", (int) n, cdata->template);
input = "";
cdata->prompts[cdata->count].input = xstrdup(input);
cdata->count++;
}
free(inputs);
free(prompts);
}
if ((type = args_get(args, 'T')) != NULL) {
cdata->prompt_type = status_prompt_type(type);
if (cdata->prompt_type == PROMPT_TYPE_INVALID) {
cmdq_error(item, "unknown type: %s", type);
cmd_command_prompt_free(cdata);
return (CMD_RETURN_ERROR);
}
} else } else
cdata->prompt_type = PROMPT_TYPE_COMMAND; cdata->prompts = xstrdup(":");
/* Get first prompt. */
cdata->next_prompt = cdata->prompts;
ptr = strsep(&cdata->next_prompt, ",");
if (prompts == NULL)
prompt = xstrdup(ptr);
else
xasprintf(&prompt, "%s ", ptr);
/* Get initial prompt input. */
if ((inputs = args_get(args, 'I')) != NULL) {
cdata->inputs = xstrdup(inputs);
cdata->next_input = cdata->inputs;
input = strsep(&cdata->next_input, ",");
}
if (args_has(args, '1')) if (args_has(args, '1'))
cdata->flags |= PROMPT_SINGLE; cdata->flags |= PROMPT_SINGLE;
@@ -163,71 +124,69 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
cdata->flags |= PROMPT_INCREMENTAL; cdata->flags |= PROMPT_INCREMENTAL;
else if (args_has(args, 'k')) else if (args_has(args, 'k'))
cdata->flags |= PROMPT_KEY; cdata->flags |= PROMPT_KEY;
status_prompt_set(tc, target, cdata->prompts[0].prompt, status_prompt_set(c, prompt, input, cmd_command_prompt_callback,
cdata->prompts[0].input, cmd_command_prompt_callback, cmd_command_prompt_free, cdata, cdata->flags);
cmd_command_prompt_free, cdata, cdata->flags, cdata->prompt_type); free(prompt);
if (!wait) return (CMD_RETURN_NORMAL);
return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT);
} }
static int static int
cmd_command_prompt_callback(struct client *c, void *data, const char *s, cmd_command_prompt_callback(struct client *c, void *data, const char *s,
int done) int done)
{ {
struct cmd_command_prompt_cdata *cdata = data; struct cmd_command_prompt_cdata *cdata = data;
char *error; struct cmdq_item *new_item;
struct cmdq_item *item = cdata->item, *new_item; char *new_template, *prompt, *ptr;
struct cmd_list *cmdlist; char *input = NULL;
struct cmd_command_prompt_prompt *prompt; struct cmd_parse_result *pr;
int argc = 0;
char **argv = NULL;
if (s == NULL) if (s == NULL)
goto out; return (0);
if (done && (cdata->flags & PROMPT_INCREMENTAL))
return (0);
new_template = cmd_template_replace(cdata->template, s, cdata->idx);
if (done) { if (done) {
if (cdata->flags & PROMPT_INCREMENTAL) free(cdata->template);
goto out; cdata->template = new_template;
cmd_append_argv(&cdata->argc, &cdata->argv, s);
if (++cdata->current != cdata->count) {
prompt = &cdata->prompts[cdata->current];
status_prompt_update(c, prompt->prompt, prompt->input);
return (1);
}
} }
argc = cdata->argc; /*
argv = cmd_copy_argv(cdata->argc, cdata->argv); * Check if there are more prompts; if so, get its respective input
if (!done) * and update the prompt data.
cmd_append_argv(&argc, &argv, s); */
if (done && (ptr = strsep(&cdata->next_prompt, ",")) != NULL) {
xasprintf(&prompt, "%s ", ptr);
input = strsep(&cdata->next_input, ",");
status_prompt_update(c, prompt, input);
if (done) { free(prompt);
cmd_free_argv(cdata->argc, cdata->argv); cdata->idx++;
cdata->argc = argc; return (1);
cdata->argv = cmd_copy_argv(argc, argv);
} }
cmdlist = args_make_commands(cdata->state, argc, argv, &error); pr = cmd_parse_from_string(new_template, NULL);
if (cmdlist == NULL) { switch (pr->status) {
cmdq_append(c, cmdq_get_error(error)); case CMD_PARSE_EMPTY:
free(error); new_item = NULL;
} else if (item == NULL) { break;
new_item = cmdq_get_command(cmdlist, NULL); case CMD_PARSE_ERROR:
new_item = cmdq_get_error(pr->error);
free(pr->error);
cmdq_append(c, new_item); cmdq_append(c, new_item);
} else { break;
new_item = cmdq_get_command(cmdlist, cmdq_get_state(item)); case CMD_PARSE_SUCCESS:
cmdq_insert_after(item, new_item); new_item = cmdq_get_command(pr->cmdlist, NULL, NULL, 0);
cmd_list_free(pr->cmdlist);
cmdq_append(c, new_item);
break;
} }
cmd_free_argv(argc, argv);
if (!done)
free(new_template);
if (c->prompt_inputcb != cmd_command_prompt_callback) if (c->prompt_inputcb != cmd_command_prompt_callback)
return (1); return (1);
out:
if (item != NULL)
cmdq_continue(item);
return (0); return (0);
} }
@@ -235,14 +194,9 @@ static void
cmd_command_prompt_free(void *data) cmd_command_prompt_free(void *data)
{ {
struct cmd_command_prompt_cdata *cdata = data; struct cmd_command_prompt_cdata *cdata = data;
u_int i;
for (i = 0; i < cdata->count; i++) { free(cdata->inputs);
free(cdata->prompts[i].prompt);
free(cdata->prompts[i].input);
}
free(cdata->prompts); free(cdata->prompts);
cmd_free_argv(cdata->argc, cdata->argv); free(cdata->template);
args_make_commands_free(cdata->state);
free(cdata); free(cdata);
} }

View File

@@ -28,10 +28,8 @@
* Asks for confirmation before executing a command. * Asks for confirmation before executing a command.
*/ */
static enum args_parse_type cmd_confirm_before_args_parse(struct args *, static enum cmd_retval cmd_confirm_before_exec(struct cmd *,
u_int, char **); struct cmdq_item *);
static enum cmd_retval cmd_confirm_before_exec(struct cmd *,
struct cmdq_item *);
static int cmd_confirm_before_callback(struct client *, void *, static int cmd_confirm_before_callback(struct client *, void *,
const char *, int); const char *, int);
@@ -41,80 +39,47 @@ 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 = { "p:t:", 1, 1 },
.usage = "[-by] [-c confirm-key] [-p prompt] " CMD_TARGET_CLIENT_USAGE .usage = "[-p prompt] " CMD_TARGET_CLIENT_USAGE " command",
" command",
.flags = CMD_CLIENT_TFLAG, .flags = 0,
.exec = cmd_confirm_before_exec .exec = cmd_confirm_before_exec
}; };
struct cmd_confirm_before_data { struct cmd_confirm_before_data {
struct cmdq_item *item; char *cmd;
struct cmd_list *cmdlist;
u_char confirm_key;
int default_yes;
}; };
static enum args_parse_type
cmd_confirm_before_args_parse(__unused struct args *args, __unused u_int idx,
__unused char **cause)
{
return (ARGS_PARSE_COMMANDS_OR_STRING);
}
static enum cmd_retval static enum cmd_retval
cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item) cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_confirm_before_data *cdata; struct cmd_confirm_before_data *cdata;
struct client *tc = cmdq_get_target_client(item); struct client *c;
struct cmd_find_state *target = cmdq_get_target(item); char *cmd, *copy, *new_prompt, *ptr;
char *new_prompt; const char *prompt;
const char *confirm_key, *prompt, *cmd;
int wait = !args_has(args, 'b');
cdata = xcalloc(1, sizeof *cdata); if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
cdata->cmdlist = args_make_commands_now(self, item, 0, 1);
if (cdata->cmdlist == NULL) {
free(cdata);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
}
if (wait)
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; ptr = copy = xstrdup(args->argv[0]);
xasprintf(&new_prompt, "Confirm '%s'? (%c/n) ", cmd, cmd = strsep(&ptr, " \t");
cdata->confirm_key); xasprintf(&new_prompt, "Confirm '%s'? (y/n) ", cmd);
free(copy);
} }
status_prompt_set(tc, target, new_prompt, NULL, cdata = xmalloc(sizeof *cdata);
cmd_confirm_before_callback, cmd_confirm_before_free, cdata, cdata->cmd = xstrdup(args->argv[0]);
PROMPT_SINGLE, PROMPT_TYPE_COMMAND);
free(new_prompt);
if (!wait) status_prompt_set(c, new_prompt, NULL,
return (CMD_RETURN_NORMAL); cmd_confirm_before_callback, cmd_confirm_before_free, cdata,
return (CMD_RETURN_WAIT); PROMPT_SINGLE);
free(new_prompt);
return (CMD_RETURN_NORMAL);
} }
static int static int
@@ -122,34 +87,34 @@ cmd_confirm_before_callback(struct client *c, void *data, const char *s,
__unused int done) __unused int done)
{ {
struct cmd_confirm_before_data *cdata = data; struct cmd_confirm_before_data *cdata = data;
struct cmdq_item *item = cdata->item, *new_item; struct cmdq_item *new_item;
int retcode = 1; struct cmd_parse_result *pr;
if (c->flags & CLIENT_DEAD) if (c->flags & CLIENT_DEAD)
goto out; return (0);
if (s == NULL) if (s == NULL || *s == '\0')
goto out; return (0);
if (s[0] != cdata->confirm_key && (s[0] != '\r' || !cdata->default_yes)) if (tolower((u_char)s[0]) != 'y' || s[1] != '\0')
goto out; return (0);
retcode = 0;
if (item == NULL) { pr = cmd_parse_from_string(cdata->cmd, NULL);
new_item = cmdq_get_command(cdata->cmdlist, NULL); switch (pr->status) {
case CMD_PARSE_EMPTY:
new_item = NULL;
break;
case CMD_PARSE_ERROR:
new_item = cmdq_get_error(pr->error);
free(pr->error);
cmdq_append(c, new_item); cmdq_append(c, new_item);
} else { break;
new_item = cmdq_get_command(cdata->cmdlist, case CMD_PARSE_SUCCESS:
cmdq_get_state(item)); new_item = cmdq_get_command(pr->cmdlist, NULL, NULL, 0);
cmdq_insert_after(item, new_item); cmd_list_free(pr->cmdlist);
cmdq_append(c, new_item);
break;
} }
out:
if (item != NULL) {
if (cmdq_get_client(item) != NULL &&
cmdq_get_client(item)->session == NULL)
cmdq_get_client(item)->retval = retcode;
cmdq_continue(item);
}
return (0); return (0);
} }
@@ -158,6 +123,6 @@ cmd_confirm_before_free(void *data)
{ {
struct cmd_confirm_before_data *cdata = data; struct cmd_confirm_before_data *cdata = data;
cmd_list_free(cdata->cmdlist); free(cdata->cmd);
free(cdata); free(cdata);
} }

View File

@@ -30,10 +30,9 @@ 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 = { "eHMt:uq", 0, 0 },
.usage = "[-deHMqSu] [-s src-pane] " CMD_TARGET_PANE_USAGE, .usage = "[-eHMuq] " CMD_TARGET_PANE_USAGE,
.source = { 's', CMD_FIND_PANE, 0 },
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
@@ -44,7 +43,7 @@ const struct cmd_entry cmd_clock_mode_entry = {
.name = "clock-mode", .name = "clock-mode",
.alias = NULL, .alias = NULL,
.args = { "t:", 0, 0, NULL }, .args = { "t:", 0, 0 },
.usage = CMD_TARGET_PANE_USAGE, .usage = CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
@@ -56,13 +55,11 @@ const struct cmd_entry cmd_clock_mode_entry = {
static enum cmd_retval static enum cmd_retval
cmd_copy_mode_exec(struct cmd *self, struct cmdq_item *item) cmd_copy_mode_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct key_event *event = cmdq_get_event(item); struct cmdq_shared *shared = item->shared;
struct cmd_find_state *source = cmdq_get_source(item); struct client *c = item->client;
struct cmd_find_state *target = cmdq_get_target(item);
struct client *c = cmdq_get_client(item);
struct session *s; struct session *s;
struct window_pane *wp = target->wp, *swp; struct window_pane *wp = item->target.wp;
if (args_has(args, 'q')) { if (args_has(args, 'q')) {
window_pane_reset_mode_all(wp); window_pane_reset_mode_all(wp);
@@ -70,34 +67,23 @@ cmd_copy_mode_exec(struct cmd *self, struct cmdq_item *item)
} }
if (args_has(args, 'M')) { if (args_has(args, 'M')) {
if ((wp = cmd_mouse_pane(&event->m, &s, NULL)) == NULL) if ((wp = cmd_mouse_pane(&shared->mouse, &s, NULL)) == NULL)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
if (c == NULL || c->session != s) if (c == NULL || c->session != s)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (cmd_get_entry(self) == &cmd_clock_mode_entry) { if (self->entry == &cmd_clock_mode_entry) {
window_pane_set_mode(wp, NULL, &window_clock_mode, NULL, NULL); window_pane_set_mode(wp, &window_clock_mode, NULL, NULL);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (args_has(args, 's')) if (!window_pane_set_mode(wp, &window_copy_mode, NULL, args)) {
swp = source->wp;
else
swp = wp;
if (!window_pane_set_mode(wp, swp, &window_copy_mode, NULL, args)) {
if (args_has(args, 'M')) if (args_has(args, 'M'))
window_copy_start_drag(c, &event->m); window_copy_start_drag(c, &shared->mouse);
} }
if (args_has(args, 'u')) if (args_has(self->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

@@ -33,13 +33,13 @@ const struct cmd_entry cmd_detach_client_entry = {
.name = "detach-client", .name = "detach-client",
.alias = "detach", .alias = "detach",
.args = { "aE:s:t:P", 0, 0, NULL }, .args = { "aE:s:t:P", 0, 0 },
.usage = "[-aP] [-E shell-command] " .usage = "[-aP] [-E shell-command] "
"[-s target-session] " CMD_TARGET_CLIENT_USAGE, "[-s target-session] " CMD_TARGET_CLIENT_USAGE,
.source = { 's', CMD_FIND_SESSION, CMD_FIND_CANFAIL }, .source = { 's', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
.flags = CMD_READONLY|CMD_CLIENT_TFLAG, .flags = CMD_READONLY,
.exec = cmd_detach_client_exec .exec = cmd_detach_client_exec
}; };
@@ -47,25 +47,27 @@ const struct cmd_entry cmd_suspend_client_entry = {
.name = "suspend-client", .name = "suspend-client",
.alias = "suspendc", .alias = "suspendc",
.args = { "t:", 0, 0, NULL }, .args = { "t:", 0, 0 },
.usage = CMD_TARGET_CLIENT_USAGE, .usage = CMD_TARGET_CLIENT_USAGE,
.flags = CMD_CLIENT_TFLAG, .flags = 0,
.exec = cmd_detach_client_exec .exec = cmd_detach_client_exec
}; };
static enum cmd_retval static enum cmd_retval
cmd_detach_client_exec(struct cmd *self, struct cmdq_item *item) cmd_detach_client_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *source = cmdq_get_source(item); struct client *c, *cloop;
struct client *tc = cmdq_get_target_client(item), *loop; struct session *s;
struct session *s; enum msgtype msgtype;
enum msgtype msgtype; const char *cmd = args_get(args, 'E');
const char *cmd = args_get(args, 'E');
if (cmd_get_entry(self) == &cmd_suspend_client_entry) { if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
server_client_suspend(tc); return (CMD_RETURN_ERROR);
if (self->entry == &cmd_suspend_client_entry) {
server_client_suspend(c);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
@@ -75,35 +77,35 @@ cmd_detach_client_exec(struct cmd *self, struct cmdq_item *item)
msgtype = MSG_DETACH; msgtype = MSG_DETACH;
if (args_has(args, 's')) { if (args_has(args, 's')) {
s = source->s; s = item->source.s;
if (s == NULL) if (s == NULL)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
TAILQ_FOREACH(loop, &clients, entry) { TAILQ_FOREACH(cloop, &clients, entry) {
if (loop->session == s) { if (cloop->session == s) {
if (cmd != NULL) if (cmd != NULL)
server_client_exec(loop, cmd); server_client_exec(cloop, cmd);
else else
server_client_detach(loop, msgtype); server_client_detach(cloop, msgtype);
} }
} }
return (CMD_RETURN_STOP); return (CMD_RETURN_STOP);
} }
if (args_has(args, 'a')) { if (args_has(args, 'a')) {
TAILQ_FOREACH(loop, &clients, entry) { TAILQ_FOREACH(cloop, &clients, entry) {
if (loop->session != NULL && loop != tc) { if (cloop->session != NULL && cloop != c) {
if (cmd != NULL) if (cmd != NULL)
server_client_exec(loop, cmd); server_client_exec(cloop, cmd);
else else
server_client_detach(loop, msgtype); server_client_detach(cloop, msgtype);
} }
} }
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (cmd != NULL) if (cmd != NULL)
server_client_exec(tc, cmd); server_client_exec(c, cmd);
else else
server_client_detach(tc, msgtype); server_client_detach(c, msgtype);
return (CMD_RETURN_STOP); return (CMD_RETURN_STOP);
} }

View File

@@ -27,324 +27,75 @@
* Display a menu on a client. * Display a menu on a client.
*/ */
static enum args_parse_type cmd_display_menu_args_parse(struct args *, static enum cmd_retval cmd_display_menu_exec(struct cmd *,
u_int, char **); struct cmdq_item *);
static enum cmd_retval cmd_display_menu_exec(struct cmd *,
struct cmdq_item *);
static enum cmd_retval cmd_display_popup_exec(struct cmd *,
struct cmdq_item *);
const struct cmd_entry cmd_display_menu_entry = { 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:T:x:y:", 1, -1 },
.usage = "[-MO] [-b border-lines] [-c target-client] " .usage = "[-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 },
.flags = CMD_AFTERHOOK|CMD_CLIENT_CFLAG, .flags = CMD_AFTERHOOK,
.exec = cmd_display_menu_exec .exec = cmd_display_menu_exec
}; };
const struct cmd_entry cmd_display_popup_entry = {
.name = "display-popup",
.alias = "popup",
.args = { "Bb:Cc:d:e:Eh:kNs:S:t:T:w:x:y:", 0, -1, NULL },
.usage = "[-BCEkN] [-b border-lines] [-c target-client] "
"[-d start-directory] [-e environment] [-h height] "
"[-s style] [-S border-style] " CMD_TARGET_PANE_USAGE
" [-T title] [-w width] [-x position] [-y position] "
"[shell-command [argument ...]]",
.target = { 't', CMD_FIND_PANE, 0 },
.flags = CMD_AFTERHOOK|CMD_CLIENT_CFLAG,
.exec = cmd_display_popup_exec
};
static enum args_parse_type
cmd_display_menu_args_parse(struct args *args, u_int idx, __unused char **cause)
{
u_int i = 0;
enum args_parse_type type = ARGS_PARSE_STRING;
for (;;) {
type = ARGS_PARSE_STRING;
if (i == idx)
break;
if (*args_string(args, i++) == '\0')
continue;
type = ARGS_PARSE_STRING;
if (i++ == idx)
break;
type = ARGS_PARSE_COMMANDS_OR_STRING;
if (i++ == idx)
break;
}
return (type);
}
static int
cmd_display_menu_get_pos(struct client *tc, struct cmdq_item *item,
struct args *args, u_int *px, u_int *py, u_int w, u_int h)
{
struct tty *tty = &tc->tty;
struct cmd_find_state *target = cmdq_get_target(item);
struct key_event *event = cmdq_get_event(item);
struct session *s = tc->session;
struct winlink *wl = target->wl;
struct window_pane *wp = target->wp;
struct style_ranges *ranges = NULL;
struct style_range *sr = NULL;
const char *xp, *yp;
char *p;
int top;
u_int line, ox, oy, sx, sy, lines, position;
long n;
struct format_tree *ft;
/*
* Work out the position from the -x and -y arguments. This is the
* bottom-left position.
*/
/* If the popup is too big, stop now. */
if (w > tty->sx || h > tty->sy)
return (0);
/* Create format with mouse position if any. */
ft = format_create_from_target(item);
if (event->m.valid) {
format_add(ft, "popup_mouse_x", "%u", event->m.x);
format_add(ft, "popup_mouse_y", "%u", event->m.y);
}
/*
* If there are any status lines, add this window position and the
* status line position.
*/
top = status_at_line(tc);
if (top != -1) {
lines = status_line_size(tc);
if (top == 0)
top = lines;
else
top = 0;
position = options_get_number(s->options, "status-position");
for (line = 0; line < lines; line++) {
ranges = &tc->status.entries[line].ranges;
TAILQ_FOREACH(sr, ranges, entry) {
if (sr->type != STYLE_RANGE_WINDOW)
continue;
if (sr->argument == (u_int)wl->idx)
break;
}
if (sr != NULL)
break;
}
if (sr != NULL) {
format_add(ft, "popup_window_status_line_x", "%u",
sr->start);
if (position == 0) {
format_add(ft, "popup_window_status_line_y",
"%u", line + 1 + h);
} else {
format_add(ft, "popup_window_status_line_y",
"%u", tty->sy - lines + line);
}
}
if (position == 0)
format_add(ft, "popup_status_line_y", "%u", lines + h);
else {
format_add(ft, "popup_status_line_y", "%u",
tty->sy - lines);
}
} else
top = 0;
/* Popup width and height. */
format_add(ft, "popup_width", "%u", w);
format_add(ft, "popup_height", "%u", h);
/* Position so popup is in the centre. */
n = (long)(tty->sx - 1) / 2 - w / 2;
if (n < 0)
format_add(ft, "popup_centre_x", "%u", 0);
else
format_add(ft, "popup_centre_x", "%ld", n);
n = (tty->sy - 1) / 2 + h / 2;
if (n >= tty->sy)
format_add(ft, "popup_centre_y", "%u", tty->sy - h);
else
format_add(ft, "popup_centre_y", "%ld", n);
/* Position of popup relative to mouse. */
if (event->m.valid) {
n = (long)event->m.x - w / 2;
if (n < 0)
format_add(ft, "popup_mouse_centre_x", "%u", 0);
else
format_add(ft, "popup_mouse_centre_x", "%ld", n);
n = event->m.y - h / 2;
if (n + h >= tty->sy) {
format_add(ft, "popup_mouse_centre_y", "%u",
tty->sy - h);
} else
format_add(ft, "popup_mouse_centre_y", "%ld", n);
n = (long)event->m.y + h;
if (n >= tty->sy)
format_add(ft, "popup_mouse_top", "%u", tty->sy - 1);
else
format_add(ft, "popup_mouse_top", "%ld", n);
n = event->m.y - h;
if (n < 0)
format_add(ft, "popup_mouse_bottom", "%u", 0);
else
format_add(ft, "popup_mouse_bottom", "%ld", n);
}
/* Position in pane. */
tty_window_offset(&tc->tty, &ox, &oy, &sx, &sy);
n = top + wp->yoff - oy + h;
if (n >= tty->sy)
format_add(ft, "popup_pane_top", "%u", tty->sy - h);
else
format_add(ft, "popup_pane_top", "%ld", n);
format_add(ft, "popup_pane_bottom", "%u", top + wp->yoff + wp->sy - oy);
format_add(ft, "popup_pane_left", "%u", wp->xoff - ox);
n = (long)wp->xoff + wp->sx - ox - w;
if (n < 0)
format_add(ft, "popup_pane_right", "%u", 0);
else
format_add(ft, "popup_pane_right", "%ld", n);
/* Expand horizontal position. */
xp = args_get(args, 'x');
if (xp == NULL || strcmp(xp, "C") == 0)
xp = "#{popup_centre_x}";
else if (strcmp(xp, "R") == 0)
xp = "#{popup_pane_right}";
else if (strcmp(xp, "P") == 0)
xp = "#{popup_pane_left}";
else if (strcmp(xp, "M") == 0)
xp = "#{popup_mouse_centre_x}";
else if (strcmp(xp, "W") == 0)
xp = "#{popup_window_status_line_x}";
p = format_expand(ft, xp);
n = strtol(p, NULL, 10);
if (n + w >= tty->sx)
n = tty->sx - w;
else if (n < 0)
n = 0;
*px = n;
log_debug("%s: -x: %s = %s = %u (-w %u)", __func__, xp, p, *px, w);
free(p);
/* Expand vertical position */
yp = args_get(args, 'y');
if (yp == NULL || strcmp(yp, "C") == 0)
yp = "#{popup_centre_y}";
else if (strcmp(yp, "P") == 0)
yp = "#{popup_pane_bottom}";
else if (strcmp(yp, "M") == 0)
yp = "#{popup_mouse_top}";
else if (strcmp(yp, "S") == 0)
yp = "#{popup_status_line_y}";
else if (strcmp(yp, "W") == 0)
yp = "#{popup_window_status_line_y}";
p = format_expand(ft, yp);
n = strtol(p, NULL, 10);
if (n < h)
n = 0;
else
n -= h;
if (n + h >= tty->sy)
n = tty->sy - h;
else if (n < 0)
n = 0;
*py = n;
log_debug("%s: -y: %s = %s = %u (-h %u)", __func__, yp, p, *py, h);
free(p);
format_free(ft);
return (1);
}
static enum cmd_retval static enum cmd_retval
cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item) cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item); struct client *c;
struct key_event *event = cmdq_get_event(item); struct session *s = item->target.s;
struct client *tc = cmdq_get_target_client(item); struct winlink *wl = item->target.wl;
struct window_pane *wp = item->target.wp;
struct cmd_find_state *fs = &item->target;
struct menu *menu = NULL; struct menu *menu = NULL;
struct style_range *sr;
struct menu_item menu_item; struct menu_item menu_item;
const char *key, *name, *value; const char *xp, *yp, *key;
const char *style = args_get(args, 's'); char *title, *name;
const char *border_style = args_get(args, 'S'); int at, flags, i;
const char *selected_style = args_get(args, 'H'); u_int px, py, ox, oy, sx, sy;
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);
struct options *o = target->s->curw->window->options;
struct options_entry *oe;
if ((c = cmd_find_client(item, args_get(args, 'c'), 0)) == NULL)
if (tc->overlay_draw != NULL) return (CMD_RETURN_ERROR);
if (c->overlay_draw != NULL)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
at = status_at_line(c);
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(NULL, args_get(args, 'T'), c, s, wl, wp);
else else
title = xstrdup(""); title = xstrdup("");
menu = menu_create(title);
free(title);
for (i = 0; i != count; /* nothing */) { menu = menu_create(title);
name = args_string(args, i++);
for (i = 0; i != args->argc; /* nothing */) {
name = args->argv[i++];
if (*name == '\0') { if (*name == '\0') {
menu_add_item(menu, NULL, item, tc, target); menu_add_item(menu, NULL, item, c, fs);
continue; continue;
} }
if (count - i < 2) { if (args->argc - 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);
} }
key = args_string(args, i++); key = args->argv[i++];
menu_item.name = name; menu_item.name = name;
menu_item.key = key_string_lookup_string(key); menu_item.key = key_string_lookup_string(key);
menu_item.command = args_string(args, i++); menu_item.command = args->argv[i++];
menu_add_item(menu, &menu_item, item, tc, target); menu_add_item(menu, &menu_item, item, c, fs);
} }
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);
@@ -353,176 +104,75 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
menu_free(menu); menu_free(menu);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (!cmd_display_menu_get_pos(tc, item, args, &px, &py, menu->width + 4,
menu->count + 2)) {
menu_free(menu);
return (CMD_RETURN_NORMAL);
}
value = args_get(args, 'b'); xp = args_get(args, 'x');
if (value != NULL) { if (xp == NULL)
oe = options_get(o, "menu-border-lines"); px = 0;
lines = options_find_choice(options_table_entry(oe), value, else if (strcmp(xp, "R") == 0)
&cause); px = c->tty.sx - 1;
if (lines == -1) { else if (strcmp(xp, "P") == 0) {
cmdq_error(item, "menu-border-lines %s", cause); tty_window_offset(&c->tty, &ox, &oy, &sx, &sy);
free(cause); if (wp->xoff >= ox)
return (CMD_RETURN_ERROR); px = wp->xoff - ox;
}
}
if (args_has(args, 'O'))
flags |= MENU_STAYOPEN;
if (!event->m.valid && !args_has(args, 'M'))
flags |= MENU_NOMOUSE;
if (menu_display(menu, flags, starting_choice, item, px, py, tc, lines,
style, selected_style, border_style, target, NULL, NULL) != 0)
return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT);
}
static enum cmd_retval
cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct session *s = target->s;
struct client *tc = cmdq_get_target_client(item);
struct tty *tty = &tc->tty;
const char *value, *shell, *shellcmd = NULL;
const char *style = args_get(args, 's');
const char *border_style = args_get(args, 'S');
char *cwd = NULL, *cause = NULL, **argv = NULL;
char *title;
int modify = popup_present(tc);
int flags = -1, argc = 0;
enum box_lines lines = BOX_LINES_DEFAULT;
u_int px, py, w, h, count = args_count(args);
struct args_value *av;
struct environ *env = NULL;
struct options *o = s->curw->window->options;
struct options_entry *oe;
if (args_has(args, 'C')) {
server_client_clear_overlay(tc);
return (CMD_RETURN_NORMAL);
}
if (!modify && tc->overlay_draw != NULL)
return (CMD_RETURN_NORMAL);
if (!modify) {
h = tty->sy / 2;
if (args_has(args, 'h')) {
h = args_percentage(args, 'h', 1, tty->sy, tty->sy,
&cause);
if (cause != NULL) {
cmdq_error(item, "height %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
}
w = tty->sx / 2;
if (args_has(args, 'w')) {
w = args_percentage(args, 'w', 1, tty->sx, tty->sx,
&cause);
if (cause != NULL) {
cmdq_error(item, "width %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
}
if (w > tty->sx)
w = tty->sx;
if (h > tty->sy)
h = tty->sy;
if (!cmd_display_menu_get_pos(tc, item, args, &px, &py, w, h))
return (CMD_RETURN_NORMAL);
value = args_get(args, 'd');
if (value != NULL)
cwd = format_single_from_target(item, value);
else else
cwd = xstrdup(server_client_get_cwd(tc, s)); px = 0;
if (count == 0) { } else if (strcmp(xp, "M") == 0 && item->shared->mouse.valid) {
shellcmd = options_get_string(s->options, if (item->shared->mouse.x > (menu->width + 4) / 2)
"default-command"); px = item->shared->mouse.x - (menu->width + 4) / 2;
} else if (count == 1) else
shellcmd = args_string(args, 0); px = 0;
if (count <= 1 && (shellcmd == NULL || *shellcmd == '\0')) { }
shellcmd = NULL; else if (strcmp(xp, "W") == 0) {
shell = options_get_string(s->options, "default-shell"); if (at == -1)
if (!checkshell(shell)) px = 0;
shell = _PATH_BSHELL; else {
cmd_append_argv(&argc, &argv, shell); TAILQ_FOREACH(sr, &c->status.entries[0].ranges, entry) {
} else if (sr->type != STYLE_RANGE_WINDOW)
args_to_vector(args, &argc, &argv); continue;
if (sr->argument == (u_int)wl->idx)
if (args_has(args, 'e') >= 1) { break;
env = environ_create();
av = args_first_value(args, 'e');
while (av != NULL) {
environ_put(env, av->string, 0);
av = args_next_value(av);
} }
if (sr != NULL)
px = sr->start;
else
px = 0;
} }
} } else
px = strtoul(xp, NULL, 10);
if (px + menu->width + 4 >= c->tty.sx)
px = c->tty.sx - menu->width - 4;
value = args_get(args, 'b'); yp = args_get(args, 'y');
if (args_has(args, 'B')) if (yp == NULL)
lines = BOX_LINES_NONE; py = 0;
else if (value != NULL) { else if (strcmp(yp, "P") == 0) {
oe = options_get(o, "popup-border-lines"); tty_window_offset(&c->tty, &ox, &oy, &sx, &sy);
lines = options_find_choice(options_table_entry(oe), value, if (wp->yoff + wp->sy >= oy)
&cause); py = wp->yoff + wp->sy - oy;
if (cause != NULL) { else
cmdq_error(item, "popup-border-lines %s", cause); py = 0;
free(cause); } else if (strcmp(yp, "M") == 0 && item->shared->mouse.valid)
return (CMD_RETURN_ERROR); py = item->shared->mouse.y + menu->count + 2;
} else if (strcmp(yp, "S") == 0) {
} if (at == -1)
py = c->tty.sy;
if (args_has(args, 'T')) else if (at == 0)
title = format_single_from_target(item, args_get(args, 'T')); py = status_line_size(c) + menu->count + 2;
else
py = at;
} else
py = strtoul(yp, NULL, 10);
if (py < menu->count + 2)
py = 0;
else else
title = xstrdup(""); py -= menu->count + 2;
if (py + menu->count + 2 >= c->tty.sy)
py = c->tty.sy - menu->count - 2;
if (args_has(args, 'N') || !modify) flags = 0;
flags = 0; if (!item->shared->mouse.valid)
if (args_has(args, 'E') > 1) { flags |= MENU_NOMOUSE;
if (flags == -1) if (menu_display(menu, flags, item, px, py, c, fs, NULL, NULL) != 0)
flags = 0;
flags |= POPUP_CLOSEEXITZERO;
} else if (args_has(args, 'E')) {
if (flags == -1)
flags = 0;
flags |= POPUP_CLOSEEXIT;
}
if (args_has(args, 'k')) {
if (flags == -1)
flags = 0;
flags |= POPUP_CLOSEANYKEY;
}
if (modify) {
popup_modify(tc, title, style, border_style, lines, flags);
free(title);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
}
if (popup_display(flags, lines, item, px, py, w, h, env, shellcmd, argc,
argv, cwd, title, tc, s, style, border_style, NULL, NULL) != 0) {
cmd_free_argv(argc, argv);
if (env != NULL)
environ_free(env);
free(cwd);
free(title);
return (CMD_RETURN_NORMAL);
}
if (env != NULL)
environ_free(env);
free(cwd);
free(title);
cmd_free_argv(argc, argv);
return (CMD_RETURN_WAIT); return (CMD_RETURN_WAIT);
} }

View File

@@ -39,13 +39,13 @@ 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:Ipt:F:v", 0, 1 },
.usage = "[-aCIlNpv] [-c target-client] [-d delay] [-F format] " .usage = "[-aIpv] [-c target-client] [-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, 0 },
.flags = CMD_AFTERHOOK|CMD_CLIENT_CFLAG|CMD_CLIENT_CANFAIL, .flags = CMD_AFTERHOOK,
.exec = cmd_display_message_exec .exec = cmd_display_message_exec
}; };
@@ -60,53 +60,33 @@ cmd_display_message_each(const char *key, const char *value, void *arg)
static enum cmd_retval static enum cmd_retval
cmd_display_message_exec(struct cmd *self, struct cmdq_item *item) cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item); struct client *c, *target_c;
struct client *tc = cmdq_get_target_client(item), *c; struct session *s = item->target.s;
struct session *s = target->s; struct winlink *wl = item->target.wl;
struct winlink *wl = target->wl; struct window_pane *wp = item->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 Cflag = args_has(args, 'C');
struct format_tree *ft; struct format_tree *ft;
u_int count = args_count(args); int flags;
struct evbuffer *evb;
if (args_has(args, 'I')) { if (args_has(args, 'I')) {
if (wp == NULL) if (window_pane_start_input(wp, item, &cause) != 0) {
return (CMD_RETURN_NORMAL);
switch (window_pane_start_input(wp, item, &cause)) {
case -1:
cmdq_error(item, "%s", cause); cmdq_error(item, "%s", cause);
free(cause); free(cause);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
case 1:
return (CMD_RETURN_NORMAL);
case 0:
return (CMD_RETURN_WAIT);
} }
return (CMD_RETURN_WAIT);
} }
if (args_has(args, 'F') && count != 0) { if (args_has(args, 'F') && args->argc != 0) {
cmdq_error(item, "only one of -F or argument must be given"); cmdq_error(item, "only one of -F or argument must be given");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (args_has(args, 'd')) { template = args_get(args, 'F');
delay = args_strtonum(args, 'd', 0, UINT_MAX, &cause); if (args->argc != 0)
if (cause != NULL) { template = args->argv[0];
cmdq_error(item, "delay %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
}
if (count != 0)
template = args_string(args, 0);
else
template = args_get(args, 'F');
if (template == NULL) if (template == NULL)
template = DISPLAY_MESSAGE_TEMPLATE; template = DISPLAY_MESSAGE_TEMPLATE;
@@ -116,42 +96,28 @@ cmd_display_message_exec(struct cmd *self, struct cmdq_item *item)
* formats too, assuming it matches the session. If it doesn't, use the * formats too, assuming it matches the session. If it doesn't, use the
* best client for the session. * best client for the session.
*/ */
if (tc != NULL && tc->session == s) c = cmd_find_client(item, args_get(args, 'c'), 1);
c = tc; if (c != NULL && c->session == s)
else if (s != NULL) target_c = c;
c = cmd_find_best_client(s);
else else
c = NULL; target_c = cmd_find_best_client(s);
if (args_has(args, 'v')) if (args_has(self->args, 'v'))
flags = FORMAT_VERBOSE; flags = FORMAT_VERBOSE;
else else
flags = 0; flags = 0;
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, flags); ft = format_create(item->client, item, FORMAT_NONE, flags);
format_defaults(ft, c, s, wl, wp); format_defaults(ft, target_c, s, wl, wp);
if (args_has(args, 'a')) { if (args_has(args, 'a')) {
format_each(ft, cmd_display_message_each, item); format_each(ft, cmd_display_message_each, item);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (args_has(args, 'l')) msg = format_expand_time(ft, template);
msg = xstrdup(template); if (args_has(self->args, 'p'))
else
msg = format_expand_time(ft, template);
if (cmdq_get_client(item) == NULL)
cmdq_error(item, "%s", msg);
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 (c != NULL)
evb = evbuffer_new(); status_message_set(c, "%s", msg);
if (evb == NULL)
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

@@ -27,34 +27,25 @@
* Display panes on a client. * Display panes on a client.
*/ */
static enum args_parse_type cmd_display_panes_args_parse(struct args *, static enum cmd_retval cmd_display_panes_exec(struct cmd *,
u_int, char **); struct cmdq_item *);
static enum cmd_retval cmd_display_panes_exec(struct cmd *,
struct cmdq_item *);
const struct cmd_entry cmd_display_panes_entry = { const struct cmd_entry cmd_display_panes_entry = {
.name = "display-panes", .name = "display-panes",
.alias = "displayp", .alias = "displayp",
.args = { "bd:Nt:", 0, 1, cmd_display_panes_args_parse }, .args = { "bd:t:", 0, 1 },
.usage = "[-bN] [-d duration] " CMD_TARGET_CLIENT_USAGE " [template]", .usage = "[-b] [-d duration] " CMD_TARGET_CLIENT_USAGE " [template]",
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG, .flags = CMD_AFTERHOOK,
.exec = cmd_display_panes_exec .exec = cmd_display_panes_exec
}; };
struct cmd_display_panes_data { struct cmd_display_panes_data {
struct cmdq_item *item; struct cmdq_item *item;
struct args_command_state *state; char *command;
}; };
static enum args_parse_type
cmd_display_panes_args_parse(__unused struct args *args, __unused u_int idx,
__unused char **cause)
{
return (ARGS_PARSE_COMMANDS_OR_STRING);
}
static void static void
cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx, cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
struct window_pane *wp) struct window_pane *wp)
@@ -64,11 +55,11 @@ cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
struct session *s = c->session; struct session *s = c->session;
struct options *oo = s->options; struct options *oo = s->options;
struct window *w = wp->window; struct window *w = wp->window;
struct grid_cell fgc, bgc; struct grid_cell gc;
u_int pane, idx, px, py, i, j, xoff, yoff, sx, sy; u_int idx, px, py, i, j, xoff, yoff, sx, sy;
int colour, active_colour; int colour, active_colour;
char buf[16], lbuf[16], rbuf[16], *ptr; char buf[16], *ptr;
size_t len, llen, rlen; size_t len;
if (wp->xoff + wp->sx <= ctx->ox || if (wp->xoff + wp->sx <= ctx->ox ||
wp->xoff >= ctx->ox + ctx->sx || wp->xoff >= ctx->ox + ctx->sx ||
@@ -118,50 +109,31 @@ cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
px = sx / 2; px = sx / 2;
py = sy / 2; py = sy / 2;
if (window_pane_index(wp, &pane) != 0) if (window_pane_index(wp, &idx) != 0)
fatalx("index not found"); fatalx("index not found");
len = xsnprintf(buf, sizeof buf, "%u", pane); len = xsnprintf(buf, sizeof buf, "%u", idx);
if (sx < len) if (sx < len)
return; return;
colour = options_get_number(oo, "display-panes-colour"); colour = options_get_number(oo, "display-panes-colour");
active_colour = options_get_number(oo, "display-panes-active-colour"); active_colour = options_get_number(oo, "display-panes-active-colour");
memcpy(&fgc, &grid_default_cell, sizeof fgc);
memcpy(&bgc, &grid_default_cell, sizeof bgc);
if (w->active == wp) {
fgc.fg = active_colour;
bgc.bg = active_colour;
} else {
fgc.fg = colour;
bgc.bg = colour;
}
rlen = xsnprintf(rbuf, sizeof rbuf, "%ux%u", wp->sx, wp->sy);
if (pane > 9 && pane < 35)
llen = xsnprintf(lbuf, sizeof lbuf, "%c", 'a' + (pane - 10));
else
llen = 0;
if (sx < len * 6 || sy < 5) { if (sx < len * 6 || sy < 5) {
tty_attributes(tty, &fgc, &grid_default_cell, NULL, NULL); tty_cursor(tty, xoff + px - len / 2, yoff + py);
if (sx >= len + llen + 1) { goto draw_text;
len += llen + 1;
tty_cursor(tty, xoff + px - len / 2, yoff + py);
tty_putn(tty, buf, len, len);
tty_putn(tty, " ", 1, 1);
tty_putn(tty, lbuf, llen, llen);
} else {
tty_cursor(tty, xoff + px - len / 2, yoff + py);
tty_putn(tty, buf, len, len);
}
goto out;
} }
px -= len * 3; px -= len * 3;
py -= 2; py -= 2;
tty_attributes(tty, &bgc, &grid_default_cell, NULL, NULL); memcpy(&gc, &grid_default_cell, sizeof gc);
if (w->active == wp)
gc.bg = active_colour;
else
gc.bg = colour;
gc.flags |= GRID_FLAG_NOPALETTE;
tty_attributes(tty, &gc, wp);
for (ptr = buf; *ptr != '\0'; ptr++) { for (ptr = buf; *ptr != '\0'; ptr++) {
if (*ptr < '0' || *ptr > '9') if (*ptr < '0' || *ptr > '9')
continue; continue;
@@ -177,26 +149,27 @@ cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
px += 6; px += 6;
} }
if (sy <= 6) len = xsnprintf(buf, sizeof buf, "%ux%u", wp->sx, wp->sy);
goto out; if (sx < len || sy < 6)
tty_attributes(tty, &fgc, &grid_default_cell, NULL, NULL); return;
if (rlen != 0 && sx >= rlen) { tty_cursor(tty, xoff + sx - len, yoff);
tty_cursor(tty, xoff + sx - rlen, yoff);
tty_putn(tty, rbuf, rlen, rlen); draw_text:
} memcpy(&gc, &grid_default_cell, sizeof gc);
if (llen != 0) { if (w->active == wp)
tty_cursor(tty, xoff + sx / 2 + len * 3 - llen - 1, gc.fg = active_colour;
yoff + py + 5); else
tty_putn(tty, lbuf, llen, llen); gc.fg = colour;
} gc.flags |= GRID_FLAG_NOPALETTE;
tty_attributes(tty, &gc, wp);
tty_puts(tty, buf);
out:
tty_cursor(tty, 0, 0); tty_cursor(tty, 0, 0);
} }
static void static void
cmd_display_panes_draw(struct client *c, __unused void *data, cmd_display_panes_draw(struct client *c, struct screen_redraw_ctx *ctx)
struct screen_redraw_ctx *ctx)
{ {
struct window *w = c->session->curw->window; struct window *w = c->session->curw->window;
struct window_pane *wp; struct window_pane *wp;
@@ -210,58 +183,55 @@ cmd_display_panes_draw(struct client *c, __unused void *data,
} }
static void static void
cmd_display_panes_free(__unused struct client *c, void *data) cmd_display_panes_free(struct client *c)
{ {
struct cmd_display_panes_data *cdata = data; struct cmd_display_panes_data *cdata = c->overlay_data;
if (cdata->item != NULL) if (cdata->item != NULL)
cmdq_continue(cdata->item); cmdq_continue(cdata->item);
args_make_commands_free(cdata->state); free(cdata->command);
free(cdata); free(cdata);
} }
static int static int
cmd_display_panes_key(struct client *c, void *data, struct key_event *event) cmd_display_panes_key(struct client *c, struct key_event *event)
{ {
struct cmd_display_panes_data *cdata = data; struct cmd_display_panes_data *cdata = c->overlay_data;
char *expanded, *error; struct cmdq_item *new_item;
struct cmdq_item *item = cdata->item, *new_item; char *cmd, *expanded;
struct cmd_list *cmdlist;
struct window *w = c->session->curw->window; struct window *w = c->session->curw->window;
struct window_pane *wp; struct window_pane *wp;
u_int index; struct cmd_parse_result *pr;
key_code key;
if (event->key >= '0' && event->key <= '9') if (event->key < '0' || event->key > '9')
index = event->key - '0';
else if ((event->key & KEYC_MASK_MODIFIERS) == 0) {
key = (event->key & KEYC_MASK_KEY);
if (key >= 'a' && key <= 'z')
index = 10 + (key - 'a');
else
return (-1);
} else
return (-1); return (-1);
wp = window_pane_at_index(w, index); wp = window_pane_at_index(w, event->key - '0');
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);
cmd = cmd_template_replace(cdata->command, expanded, 1);
cmdlist = args_make_commands(cdata->state, 1, &expanded, &error); pr = cmd_parse_from_string(cmd, NULL);
if (cmdlist == NULL) { switch (pr->status) {
cmdq_append(c, cmdq_get_error(error)); case CMD_PARSE_EMPTY:
free(error); new_item = NULL;
} else if (item == NULL) { break;
new_item = cmdq_get_command(cmdlist, NULL); case CMD_PARSE_ERROR:
new_item = cmdq_get_error(pr->error);
free(pr->error);
cmdq_append(c, new_item); cmdq_append(c, new_item);
} else { break;
new_item = cmdq_get_command(cmdlist, cmdq_get_state(item)); case CMD_PARSE_SUCCESS:
cmdq_insert_after(item, new_item); new_item = cmdq_get_command(pr->cmdlist, NULL, NULL, 0);
cmd_list_free(pr->cmdlist);
cmdq_append(c, new_item);
break;
} }
free(cmd);
free(expanded); free(expanded);
return (1); return (1);
} }
@@ -269,15 +239,18 @@ cmd_display_panes_key(struct client *c, void *data, struct key_event *event)
static enum cmd_retval static enum cmd_retval
cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item) cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct client *tc = cmdq_get_target_client(item); struct client *c;
struct session *s = tc->session; struct session *s;
u_int delay; u_int delay;
char *cause; char *cause;
struct cmd_display_panes_data *cdata; struct cmd_display_panes_data *cdata;
int wait = !args_has(args, 'b');
if (tc->overlay_draw != NULL) if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
s = c->session;
if (c->overlay_draw != NULL)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
if (args_has(args, 'd')) { if (args_has(args, 'd')) {
@@ -290,23 +263,20 @@ cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item)
} else } else
delay = options_get_number(s->options, "display-panes-time"); delay = options_get_number(s->options, "display-panes-time");
cdata = xcalloc(1, sizeof *cdata); cdata = xmalloc(sizeof *cdata);
if (wait) if (args->argc != 0)
cdata->command = xstrdup(args->argv[0]);
else
cdata->command = xstrdup("select-pane -t '%%'");
if (args_has(args, 'b'))
cdata->item = NULL;
else
cdata->item = item; cdata->item = item;
cdata->state = args_make_commands_prepare(self, item, 0,
"select-pane -t \"%%%\"", wait, 0);
if (args_has(args, 'N')) { server_client_set_overlay(c, delay, cmd_display_panes_draw,
server_client_set_overlay(tc, delay, NULL, NULL, cmd_display_panes_key, cmd_display_panes_free, cdata);
cmd_display_panes_draw, NULL, cmd_display_panes_free, NULL,
cdata);
} else {
server_client_set_overlay(tc, delay, NULL, NULL,
cmd_display_panes_draw, cmd_display_panes_key,
cmd_display_panes_free, NULL, cdata);
}
if (!wait) if (args_has(args, 'b'))
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT); return (CMD_RETURN_WAIT);
} }

View File

@@ -32,8 +32,8 @@ const struct cmd_entry cmd_find_window_entry = {
.name = "find-window", .name = "find-window",
.alias = "findw", .alias = "findw",
.args = { "CiNrt:TZ", 1, 1, NULL }, .args = { "CNrt:TZ", 1, 1 },
.usage = "[-CiNrTZ] " CMD_TARGET_PANE_USAGE " match-string", .usage = "[-CNrTZ] " CMD_TARGET_PANE_USAGE " match-string",
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
@@ -44,73 +44,82 @@ const struct cmd_entry cmd_find_window_entry = {
static enum cmd_retval static enum cmd_retval
cmd_find_window_exec(struct cmd *self, struct cmdq_item *item) cmd_find_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self), *new_args; struct args *args = self->args, *new_args;
struct cmd_find_state *target = cmdq_get_target(item); struct window_pane *wp = item->target.wp;
struct window_pane *wp = target->wp; const char *s = args->argv[0];
const char *s = args_string(args, 0), *suffix = ""; char *filter, *argv = { NULL };
const char *star = "*";
struct args_value *filter;
int C, N, T; int C, N, T;
C = args_has(args, 'C'); C = args_has(args, 'C');
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'))
suffix = "/ri";
else if (args_has(args, 'r'))
suffix = "/r";
else if (args_has(args, 'i'))
suffix = "/i";
if (!C && !N && !T) if (!C && !N && !T)
C = N = T = 1; C = N = T = 1;
filter = xcalloc(1, sizeof *filter); if (!args_has(args, 'r')) {
filter->type = ARGS_STRING; if (C && N && T) {
xasprintf(&filter,
if (C && N && T) { "#{||:"
xasprintf(&filter->string, "#{C:%s},#{||:#{m:*%s*,#{window_name}},"
"#{||:" "#{m:*%s*,#{pane_title}}}}",
"#{C%s:%s},#{||:#{m%s:%s%s%s,#{window_name}}," s, s, s);
"#{m%s:%s%s%s,#{pane_title}}}}", } else if (C && N) {
suffix, s, suffix, star, s, star, suffix, star, s, star); xasprintf(&filter,
} else if (C && N) { "#{||:#{C:%s},#{m:*%s*,#{window_name}}}",
xasprintf(&filter->string, s, s);
"#{||:#{C%s:%s},#{m%s:%s%s%s,#{window_name}}}", } else if (C && T) {
suffix, s, suffix, star, s, star); xasprintf(&filter,
} else if (C && T) { "#{||:#{C:%s},#{m:*%s*,#{pane_title}}}",
xasprintf(&filter->string, s, s);
"#{||:#{C%s:%s},#{m%s:%s%s%s,#{pane_title}}}", } else if (N && T) {
suffix, s, suffix, star, s, star); xasprintf(&filter,
} else if (N && T) { "#{||:#{m:*%s*,#{window_name}},"
xasprintf(&filter->string, "#{m:*%s*,#{pane_title}}}",
"#{||:#{m%s:%s%s%s,#{window_name}}," s, s);
"#{m%s:%s%s%s,#{pane_title}}}", } else if (C)
suffix, star, s, star, suffix, star, s, star); xasprintf(&filter, "#{C:%s}", s);
} else if (C) { else if (N)
xasprintf(&filter->string, xasprintf(&filter, "#{m:*%s*,#{window_name}}", s);
"#{C%s:%s}", else
suffix, s); xasprintf(&filter, "#{m:*%s*,#{pane_title}}", s);
} else if (N) {
xasprintf(&filter->string,
"#{m%s:%s%s%s,#{window_name}}",
suffix, star, s, star);
} else { } else {
xasprintf(&filter->string, if (C && N && T) {
"#{m%s:%s%s%s,#{pane_title}}", xasprintf(&filter,
suffix, star, s, star); "#{||:"
"#{C/r:%s},#{||:#{m/r:%s,#{window_name}},"
"#{m/r:%s,#{pane_title}}}}",
s, s, s);
} else if (C && N) {
xasprintf(&filter,
"#{||:#{C/r:%s},#{m/r:%s,#{window_name}}}",
s, s);
} else if (C && T) {
xasprintf(&filter,
"#{||:#{C/r:%s},#{m/r:%s,#{pane_title}}}",
s, s);
} else if (N && T) {
xasprintf(&filter,
"#{||:#{m/r:%s,#{window_name}},"
"#{m/r:%s,#{pane_title}}}",
s, s);
} else if (C)
xasprintf(&filter, "#{C/r:%s}", s);
else if (N)
xasprintf(&filter, "#{m/r:%s,#{window_name}}", s);
else
xasprintf(&filter, "#{m/r:%s,#{pane_title}}", s);
} }
new_args = args_create(); new_args = args_parse("", 1, &argv);
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, &window_tree_mode, &item->target, new_args);
window_pane_set_mode(wp, NULL, &window_tree_mode, target, new_args);
args_free(new_args); args_free(new_args);
free(filter);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@@ -582,7 +582,7 @@ 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);
@@ -866,18 +866,7 @@ cmd_find_from_client(struct cmd_find_state *fs, struct client *c, int flags)
/* If this is an attached client, all done. */ /* If this is an attached client, all done. */
if (c->session != NULL) { if (c->session != NULL) {
cmd_find_clear_state(fs, flags); cmd_find_from_session(fs, c->session, flags);
fs->wp = server_client_get_pane(c);
if (fs->wp == NULL) {
cmd_find_from_session(fs, c->session, flags);
return (0);
}
fs->s = c->session;
fs->wl = fs->s->curw;
fs->w = fs->wl->window;
cmd_find_log_state(__func__, fs);
return (0); return (0);
} }
cmd_find_clear_state(fs, flags); cmd_find_clear_state(fs, flags);
@@ -971,11 +960,10 @@ cmd_find_target(struct cmd_find_state *fs, struct cmdq_item *item,
if (server_check_marked() && (flags & CMD_FIND_DEFAULT_MARKED)) { if (server_check_marked() && (flags & CMD_FIND_DEFAULT_MARKED)) {
fs->current = &marked_pane; fs->current = &marked_pane;
log_debug("%s: current is marked pane", __func__); log_debug("%s: current is marked pane", __func__);
} else if (cmd_find_valid_state(cmdq_get_current(item))) { } else if (cmd_find_valid_state(&item->shared->current)) {
fs->current = cmdq_get_current(item); fs->current = &item->shared->current;
log_debug("%s: current is from queue", __func__); log_debug("%s: current is from queue", __func__);
} else if (cmd_find_from_client(&current, cmdq_get_client(item), } else if (cmd_find_from_client(&current, item->client, flags) == 0) {
flags) == 0) {
fs->current = &current; fs->current = &current;
log_debug("%s: current is from client", __func__); log_debug("%s: current is from client", __func__);
} else { } else {
@@ -992,7 +980,7 @@ cmd_find_target(struct cmd_find_state *fs, struct cmdq_item *item,
/* Mouse target is a plain = or {mouse}. */ /* Mouse target is a plain = or {mouse}. */
if (strcmp(target, "=") == 0 || strcmp(target, "{mouse}") == 0) { if (strcmp(target, "=") == 0 || strcmp(target, "{mouse}") == 0) {
m = &cmdq_get_event(item)->m; m = &item->shared->mouse;
switch (type) { switch (type) {
case CMD_FIND_PANE: case CMD_FIND_PANE:
fs->wp = cmd_mouse_pane(m, &fs->s, &fs->wl); fs->wp = cmd_mouse_pane(m, &fs->s, &fs->wl);
@@ -1242,31 +1230,29 @@ no_pane:
static struct client * static struct client *
cmd_find_current_client(struct cmdq_item *item, int quiet) cmd_find_current_client(struct cmdq_item *item, int quiet)
{ {
struct client *c = NULL, *found; struct client *c;
struct session *s; struct session *s;
struct window_pane *wp; struct window_pane *wp;
struct cmd_find_state fs; struct cmd_find_state fs;
if (item != NULL) if (item->client != NULL && item->client->session != NULL)
c = cmdq_get_client(item); return (item->client);
if (c != NULL && c->session != NULL)
return (c);
found = NULL; c = NULL;
if (c != NULL && (wp = cmd_find_inside_pane(c)) != NULL) { if ((wp = cmd_find_inside_pane(item->client)) != NULL) {
cmd_find_clear_state(&fs, CMD_FIND_QUIET); cmd_find_clear_state(&fs, CMD_FIND_QUIET);
fs.w = wp->window; fs.w = wp->window;
if (cmd_find_best_session_with_window(&fs) == 0) if (cmd_find_best_session_with_window(&fs) == 0)
found = cmd_find_best_client(fs.s); c = cmd_find_best_client(fs.s);
} else { } else {
s = cmd_find_best_session(NULL, 0, CMD_FIND_QUIET); s = cmd_find_best_session(NULL, 0, CMD_FIND_QUIET);
if (s != NULL) if (s != NULL)
found = cmd_find_best_client(s); c = cmd_find_best_client(s);
} }
if (found == NULL && item != NULL && !quiet) if (c == NULL && !quiet)
cmdq_error(item, "no current client"); cmdq_error(item, "no current client");
log_debug("%s: no target, return %p", __func__, found); log_debug("%s: no target, return %p", __func__, c);
return (found); return (c);
} }
/* Find the target client or report an error and return NULL. */ /* Find the target client or report an error and return NULL. */

View File

@@ -20,7 +20,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <ctype.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -30,19 +29,16 @@
* Executes a tmux command if a shell command returns true or false. * Executes a tmux command if a shell command returns true or false.
*/ */
static enum args_parse_type cmd_if_shell_args_parse(struct args *, u_int, static enum cmd_retval cmd_if_shell_exec(struct cmd *, struct cmdq_item *);
char **);
static enum cmd_retval cmd_if_shell_exec(struct cmd *,
struct cmdq_item *);
static void cmd_if_shell_callback(struct job *); static void cmd_if_shell_callback(struct job *);
static void cmd_if_shell_free(void *); static void cmd_if_shell_free(void *);
const struct cmd_entry cmd_if_shell_entry = { const struct cmd_entry cmd_if_shell_entry = {
.name = "if-shell", .name = "if-shell",
.alias = "if", .alias = "if",
.args = { "bFt:", 2, 3, cmd_if_shell_args_parse }, .args = { "bFt:", 2, 3 },
.usage = "[-bF] " CMD_TARGET_PANE_USAGE " shell-command command " .usage = "[-bF] " CMD_TARGET_PANE_USAGE " shell-command command "
"[command]", "[command]",
@@ -53,83 +49,110 @@ const struct cmd_entry cmd_if_shell_entry = {
}; };
struct cmd_if_shell_data { struct cmd_if_shell_data {
struct args_command_state *cmd_if; struct cmd_parse_input input;
struct args_command_state *cmd_else;
struct client *client; char *cmd_if;
struct cmdq_item *item; char *cmd_else;
struct client *client;
struct cmdq_item *item;
struct mouse_event mouse;
}; };
static enum args_parse_type
cmd_if_shell_args_parse(__unused struct args *args, u_int idx,
__unused char **cause)
{
if (idx == 1 || idx == 2)
return (ARGS_PARSE_COMMANDS_OR_STRING);
return (ARGS_PARSE_STRING);
}
static enum cmd_retval static enum cmd_retval
cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item) cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item); struct mouse_event *m = &item->shared->mouse;
struct cmd_if_shell_data *cdata; struct cmd_if_shell_data *cdata;
char *shellcmd, *cmd;
struct cmdq_item *new_item; struct cmdq_item *new_item;
char *shellcmd; struct cmd_find_state *fs = &item->target;
struct client *tc = cmdq_get_target_client(item); struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = target->s; struct session *s = fs->s;
struct cmd_list *cmdlist; struct winlink *wl = fs->wl;
u_int count = args_count(args); struct window_pane *wp = fs->wp;
int wait = !args_has(args, 'b'); struct cmd_parse_input pi;
struct cmd_parse_result *pr;
shellcmd = format_single_from_target(item, args_string(args, 0)); shellcmd = format_single(item, args->argv[0], c, s, wl, wp);
if (args_has(args, 'F')) { if (args_has(args, 'F')) {
if (*shellcmd != '0' && *shellcmd != '\0') if (*shellcmd != '0' && *shellcmd != '\0')
cmdlist = args_make_commands_now(self, item, 1, 0); cmd = args->argv[1];
else if (count == 3) else if (args->argc == 3)
cmdlist = args_make_commands_now(self, item, 2, 0); cmd = args->argv[2];
else { else
free(shellcmd); cmd = NULL;
return (CMD_RETURN_NORMAL);
}
free(shellcmd); free(shellcmd);
if (cmdlist == NULL) if (cmd == NULL)
return (CMD_RETURN_NORMAL);
memset(&pi, 0, sizeof pi);
if (self->file != NULL)
pi.file = self->file;
pi.line = self->line;
pi.item = item;
pi.c = c;
cmd_find_copy_state(&pi.fs, fs);
pr = cmd_parse_from_string(cmd, &pi);
switch (pr->status) {
case CMD_PARSE_EMPTY:
break;
case CMD_PARSE_ERROR:
cmdq_error(item, "%s", pr->error);
free(pr->error);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
new_item = cmdq_get_command(cmdlist, cmdq_get_state(item)); case CMD_PARSE_SUCCESS:
cmdq_insert_after(item, new_item); new_item = cmdq_get_command(pr->cmdlist, fs, m, 0);
cmdq_insert_after(item, new_item);
cmd_list_free(pr->cmdlist);
break;
}
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
cdata = xcalloc(1, sizeof *cdata); cdata = xcalloc(1, sizeof *cdata);
cdata->cmd_if = args_make_commands_prepare(self, item, 1, NULL, wait, cdata->cmd_if = xstrdup(args->argv[1]);
0); if (args->argc == 3)
if (count == 3) { cdata->cmd_else = xstrdup(args->argv[2]);
cdata->cmd_else = args_make_commands_prepare(self, item, 2, else
NULL, wait, 0); cdata->cmd_else = NULL;
} memcpy(&cdata->mouse, m, sizeof cdata->mouse);
if (wait) { if (!args_has(args, 'b'))
cdata->client = cmdq_get_client(item); cdata->client = item->client;
cdata->item = item; else
} else cdata->client = c;
cdata->client = tc;
if (cdata->client != NULL) if (cdata->client != NULL)
cdata->client->references++; cdata->client->references++;
if (job_run(shellcmd, 0, NULL, NULL, s, if (!args_has(args, 'b'))
server_client_get_cwd(cmdq_get_client(item), s), NULL, cdata->item = item;
cmd_if_shell_callback, cmd_if_shell_free, cdata, 0, -1, else
-1) == NULL) { cdata->item = NULL;
memset(&cdata->input, 0, sizeof cdata->input);
if (self->file != NULL)
cdata->input.file = xstrdup(self->file);
cdata->input.line = self->line;
cdata->input.item = cdata->item;
cdata->input.c = c;
if (cdata->input.c != NULL)
cdata->input.c->references++;
cmd_find_copy_state(&cdata->input.fs, fs);
if (job_run(shellcmd, s, server_client_get_cwd(item->client, s), NULL,
cmd_if_shell_callback, cmd_if_shell_free, cdata, 0) == NULL) {
cmdq_error(item, "failed to run command: %s", shellcmd); cmdq_error(item, "failed to run command: %s", shellcmd);
free(shellcmd); free(shellcmd);
cmd_if_shell_free(cdata); free(cdata);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
free(shellcmd); free(shellcmd);
if (!wait) if (args_has(args, 'b'))
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT); return (CMD_RETURN_WAIT);
} }
@@ -139,34 +162,39 @@ cmd_if_shell_callback(struct job *job)
{ {
struct cmd_if_shell_data *cdata = job_get_data(job); struct cmd_if_shell_data *cdata = job_get_data(job);
struct client *c = cdata->client; struct client *c = cdata->client;
struct cmdq_item *item = cdata->item, *new_item; struct mouse_event *m = &cdata->mouse;
struct args_command_state *state; struct cmdq_item *new_item = NULL;
struct cmd_list *cmdlist; char *cmd;
char *error;
int status; int status;
struct cmd_parse_result *pr;
status = job_get_status(job); status = job_get_status(job);
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
state = cdata->cmd_else; cmd = cdata->cmd_else;
else else
state = cdata->cmd_if; cmd = cdata->cmd_if;
if (state == NULL) if (cmd == NULL)
goto out; goto out;
cmdlist = args_make_commands(state, 0, NULL, &error); pr = cmd_parse_from_string(cmd, &cdata->input);
if (cmdlist == NULL) { switch (pr->status) {
if (cdata->item == NULL) { case CMD_PARSE_EMPTY:
*error = toupper((u_char)*error); break;
status_message_set(c, -1, 1, 0, 0, "%s", error); case CMD_PARSE_ERROR:
} else if (cdata->item != NULL)
cmdq_error(cdata->item, "%s", error); cmdq_error(cdata->item, "%s", pr->error);
free(error); free(pr->error);
} else if (item == NULL) { break;
new_item = cmdq_get_command(cmdlist, NULL); case CMD_PARSE_SUCCESS:
cmdq_append(c, new_item); new_item = cmdq_get_command(pr->cmdlist, NULL, m, 0);
} else { cmd_list_free(pr->cmdlist);
new_item = cmdq_get_command(cmdlist, cmdq_get_state(item)); break;
cmdq_insert_after(item, new_item); }
if (new_item != NULL) {
if (cdata->item == NULL)
cmdq_append(c, new_item);
else
cmdq_insert_after(cdata->item, new_item);
} }
out: out:
@@ -182,9 +210,12 @@ cmd_if_shell_free(void *data)
if (cdata->client != NULL) if (cdata->client != NULL)
server_client_unref(cdata->client); server_client_unref(cdata->client);
if (cdata->cmd_else != NULL) free(cdata->cmd_else);
args_make_commands_free(cdata->cmd_else); free(cdata->cmd_if);
args_make_commands_free(cdata->cmd_if);
if (cdata->input.c != NULL)
server_client_unref(cdata->input.c);
free((void *)cdata->input.file);
free(cdata); free(cdata);
} }

View File

@@ -35,7 +35,7 @@ const struct cmd_entry cmd_join_pane_entry = {
.name = "join-pane", .name = "join-pane",
.alias = "joinp", .alias = "joinp",
.args = { "bdfhvp:l:s:t:", 0, 0, NULL }, .args = { "bdfhvp:l:s:t:", 0, 0 },
.usage = "[-bdfhv] [-l size] " CMD_SRCDST_PANE_USAGE, .usage = "[-bdfhv] [-l size] " CMD_SRCDST_PANE_USAGE,
.source = { 's', CMD_FIND_PANE, CMD_FIND_DEFAULT_MARKED }, .source = { 's', CMD_FIND_PANE, CMD_FIND_DEFAULT_MARKED },
@@ -49,8 +49,8 @@ const struct cmd_entry cmd_move_pane_entry = {
.name = "move-pane", .name = "move-pane",
.alias = "movep", .alias = "movep",
.args = { "bdfhvp:l:s:t:", 0, 0, NULL }, .args = { "bdhvp:l:s:t:", 0, 0 },
.usage = "[-bdfhv] [-l size] " CMD_SRCDST_PANE_USAGE, .usage = "[-bdhv] [-p percentage|-l size] " CMD_SRCDST_PANE_USAGE,
.source = { 's', CMD_FIND_PANE, CMD_FIND_DEFAULT_MARKED }, .source = { 's', CMD_FIND_PANE, CMD_FIND_DEFAULT_MARKED },
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
@@ -62,34 +62,42 @@ const struct cmd_entry cmd_move_pane_entry = {
static enum cmd_retval static enum cmd_retval
cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item) cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *current = cmdq_get_current(item); struct cmd_find_state *current = &item->shared->current;
struct cmd_find_state *target = cmdq_get_target(item);
struct cmd_find_state *source = cmdq_get_source(item);
struct session *dst_s; struct session *dst_s;
struct winlink *src_wl, *dst_wl; struct winlink *src_wl, *dst_wl;
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, *copy;
int size, dst_idx; const char *errstr, *p;
size_t plen;
int size, percentage, dst_idx, not_same_window;
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; if (self->entry == &cmd_join_pane_entry)
dst_wl = target->wl; not_same_window = 1;
dst_wp = target->wp; else
not_same_window = 0;
dst_s = item->target.s;
dst_wl = item->target.wl;
dst_wp = item->target.wp;
dst_w = dst_wl->window; dst_w = dst_wl->window;
dst_idx = dst_wl->idx; dst_idx = dst_wl->idx;
server_unzoom_window(dst_w); server_unzoom_window(dst_w);
src_wl = source->wl; src_wl = item->source.wl;
src_wp = source->wp; src_wp = item->source.wp;
src_w = src_wl->window; src_w = src_wl->window;
server_unzoom_window(src_w); server_unzoom_window(src_w);
if (src_wp == dst_wp) { if (not_same_window && src_w == dst_w) {
cmdq_error(item, "can't join a pane to its own window");
return (CMD_RETURN_ERROR);
}
if (!not_same_window && src_wp == dst_wp) {
cmdq_error(item, "source and target panes must be different"); cmdq_error(item, "source and target panes must be different");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
@@ -98,35 +106,41 @@ 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 ((p = args_get(args, 'l')) != NULL) {
size = args_percentage_and_expand(args, 'l', 0, INT_MAX, curval, plen = strlen(p);
item, &cause); if (p[plen - 1] == '%') {
copy = xstrdup(p);
copy[plen - 1] = '\0';
percentage = strtonum(copy, 0, INT_MAX, &errstr);
free(copy);
if (errstr != NULL) {
cmdq_error(item, "percentage %s", errstr);
return (CMD_RETURN_ERROR);
}
if (type == LAYOUT_TOPBOTTOM)
size = (dst_wp->sy * percentage) / 100;
else
size = (dst_wp->sx * percentage) / 100;
} else {
size = args_strtonum(args, 'l', 0, INT_MAX, &cause);
if (cause != NULL) {
cmdq_error(item, "size %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
}
} else if (args_has(args, 'p')) { } 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) cmdq_error(item, "percentage %s", cause);
size = curval * size / 100; free(cause);
} return (CMD_RETURN_ERROR);
if (cause != NULL) { }
cmdq_error(item, "size %s", cause); if (type == LAYOUT_TOPBOTTOM)
free(cause); size = (dst_wp->sy * percentage) / 100;
return (CMD_RETURN_ERROR); else
size = (dst_wp->sx * percentage) / 100;
} }
flags = 0; flags = 0;
@@ -143,19 +157,14 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
layout_close_pane(src_wp); layout_close_pane(src_wp);
server_client_remove_pane(src_wp);
window_lost_pane(src_w, src_wp); window_lost_pane(src_w, src_wp);
TAILQ_REMOVE(&src_w->panes, src_wp, entry); TAILQ_REMOVE(&src_w->panes, src_wp, entry);
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) TAILQ_INSERT_AFTER(&dst_w->panes, dst_wp, src_wp, entry);
TAILQ_INSERT_BEFORE(dst_wp, src_wp, entry); layout_assign_pane(lc, src_wp);
else
TAILQ_INSERT_AFTER(&dst_w->panes, dst_wp, src_wp, entry);
layout_assign_pane(lc, src_wp, 0);
colour_palette_from_option(&src_wp->palette, src_wp->options);
recalculate_sizes(); recalculate_sizes();
@@ -171,7 +180,7 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
server_status_session(dst_s); server_status_session(dst_s);
if (window_count_panes(src_w) == 0) if (window_count_panes(src_w) == 0)
server_kill_window(src_w, 1); server_kill_window(src_w);
else else
notify_window("window-layout-changed", src_w); notify_window("window-layout-changed", src_w);
notify_window("window-layout-changed", dst_w); notify_window("window-layout-changed", dst_w);

View File

@@ -32,7 +32,7 @@ const struct cmd_entry cmd_kill_pane_entry = {
.name = "kill-pane", .name = "kill-pane",
.alias = "killp", .alias = "killp",
.args = { "at:", 0, 0, NULL }, .args = { "at:", 0, 0 },
.usage = "[-a] " CMD_TARGET_PANE_USAGE, .usage = "[-a] " CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
@@ -44,17 +44,14 @@ const struct cmd_entry cmd_kill_pane_entry = {
static enum cmd_retval static enum cmd_retval
cmd_kill_pane_exec(struct cmd *self, struct cmdq_item *item) cmd_kill_pane_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct winlink *wl = item->target.wl;
struct cmd_find_state *target = cmdq_get_target(item); struct window_pane *loopwp, *tmpwp, *wp = item->target.wp;
struct winlink *wl = target->wl;
struct window_pane *loopwp, *tmpwp, *wp = target->wp;
if (args_has(args, 'a')) { if (args_has(self->args, 'a')) {
server_unzoom_window(wl->window); server_unzoom_window(wl->window);
TAILQ_FOREACH_SAFE(loopwp, &wl->window->panes, entry, tmpwp) { TAILQ_FOREACH_SAFE(loopwp, &wl->window->panes, entry, tmpwp) {
if (loopwp == wp) if (loopwp == wp)
continue; continue;
server_client_remove_pane(loopwp);
layout_close_pane(loopwp); layout_close_pane(loopwp);
window_remove_pane(wl->window, loopwp); window_remove_pane(wl->window, loopwp);
} }

View File

@@ -33,7 +33,7 @@ const struct cmd_entry cmd_kill_server_entry = {
.name = "kill-server", .name = "kill-server",
.alias = NULL, .alias = NULL,
.args = { "", 0, 0, NULL }, .args = { "", 0, 0 },
.usage = "", .usage = "",
.flags = 0, .flags = 0,
@@ -44,7 +44,7 @@ const struct cmd_entry cmd_start_server_entry = {
.name = "start-server", .name = "start-server",
.alias = "start", .alias = "start",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0 },
.usage = "", .usage = "",
.flags = CMD_STARTSERVER, .flags = CMD_STARTSERVER,
@@ -54,7 +54,7 @@ const struct cmd_entry cmd_start_server_entry = {
static enum cmd_retval static enum cmd_retval
cmd_kill_server_exec(struct cmd *self, __unused struct cmdq_item *item) cmd_kill_server_exec(struct cmd *self, __unused struct cmdq_item *item)
{ {
if (cmd_get_entry(self) == &cmd_kill_server_entry) if (self->entry == &cmd_kill_server_entry)
kill(getpid(), SIGTERM); kill(getpid(), SIGTERM);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);

View File

@@ -33,7 +33,7 @@ const struct cmd_entry cmd_kill_session_entry = {
.name = "kill-session", .name = "kill-session",
.alias = NULL, .alias = NULL,
.args = { "aCt:", 0, 0, NULL }, .args = { "aCt:", 0, 0 },
.usage = "[-aC] " CMD_TARGET_SESSION_USAGE, .usage = "[-aC] " CMD_TARGET_SESSION_USAGE,
.target = { 't', CMD_FIND_SESSION, 0 }, .target = { 't', CMD_FIND_SESSION, 0 },
@@ -45,10 +45,11 @@ const struct cmd_entry cmd_kill_session_entry = {
static enum cmd_retval static enum cmd_retval
cmd_kill_session_exec(struct cmd *self, struct cmdq_item *item) cmd_kill_session_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item); struct session *s, *sloop, *stmp;
struct session *s = target->s, *sloop, *stmp; struct winlink *wl;
struct winlink *wl;
s = item->target.s;
if (args_has(args, 'C')) { if (args_has(args, 'C')) {
RB_FOREACH(wl, winlinks, &s->windows) { RB_FOREACH(wl, winlinks, &s->windows) {

View File

@@ -30,7 +30,7 @@ const struct cmd_entry cmd_kill_window_entry = {
.name = "kill-window", .name = "kill-window",
.alias = "killw", .alias = "killw",
.args = { "at:", 0, 0, NULL }, .args = { "at:", 0, 0 },
.usage = "[-a] " CMD_TARGET_WINDOW_USAGE, .usage = "[-a] " CMD_TARGET_WINDOW_USAGE,
.target = { 't', CMD_FIND_WINDOW, 0 }, .target = { 't', CMD_FIND_WINDOW, 0 },
@@ -43,7 +43,7 @@ const struct cmd_entry cmd_unlink_window_entry = {
.name = "unlink-window", .name = "unlink-window",
.alias = "unlinkw", .alias = "unlinkw",
.args = { "kt:", 0, 0, NULL }, .args = { "kt:", 0, 0 },
.usage = "[-k] " CMD_TARGET_WINDOW_USAGE, .usage = "[-k] " CMD_TARGET_WINDOW_USAGE,
.target = { 't', CMD_FIND_WINDOW, 0 }, .target = { 't', CMD_FIND_WINDOW, 0 },
@@ -55,56 +55,27 @@ const struct cmd_entry cmd_unlink_window_entry = {
static enum cmd_retval static enum cmd_retval
cmd_kill_window_exec(struct cmd *self, struct cmdq_item *item) cmd_kill_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item); struct winlink *wl = item->target.wl, *wl2, *wl3;
struct winlink *wl = target->wl, *loop;
struct window *w = wl->window; struct window *w = wl->window;
struct session *s = target->s; struct session *s = item->target.s;
u_int found;
if (cmd_get_entry(self) == &cmd_unlink_window_entry) { if (self->entry == &cmd_unlink_window_entry) {
if (!args_has(args, 'k') && !session_is_linked(s, w)) { if (!args_has(self->args, 'k') && !session_is_linked(s, w)) {
cmdq_error(item, "window only linked to one session"); cmdq_error(item, "window only linked to one session");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
server_unlink_window(s, wl); server_unlink_window(s, wl);
recalculate_sizes(); } else {
return (CMD_RETURN_NORMAL); if (args_has(args, 'a')) {
} RB_FOREACH_SAFE(wl2, winlinks, &s->windows, wl3) {
if (wl != wl2)
if (args_has(args, 'a')) { server_kill_window(wl2->window);
if (RB_PREV(winlinks, &s->windows, wl) == NULL &&
RB_NEXT(winlinks, &s->windows, wl) == NULL)
return (CMD_RETURN_NORMAL);
/* Kill all windows except the current one. */
do {
found = 0;
RB_FOREACH(loop, winlinks, &s->windows) {
if (loop->window != wl->window) {
server_kill_window(loop->window, 0);
found++;
break;
}
} }
} while (found != 0); } else
server_kill_window(wl->window);
/*
* If the current window appears in the session more than once,
* kill it as well.
*/
found = 0;
RB_FOREACH(loop, winlinks, &s->windows) {
if (loop->window == wl->window)
found++;
}
if (found > 1)
server_kill_window(wl->window, 0);
server_renumber_all();
return (CMD_RETURN_NORMAL);
} }
server_kill_window(wl->window, 1); recalculate_sizes();
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@@ -36,8 +36,8 @@ const struct cmd_entry cmd_list_buffers_entry = {
.name = "list-buffers", .name = "list-buffers",
.alias = "lsb", .alias = "lsb",
.args = { "F:f:", 0, 0, NULL }, .args = { "F:", 0, 0 },
.usage = "[-F format] [-f filter]", .usage = "[-F format]",
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_list_buffers_exec .exec = cmd_list_buffers_exec
@@ -46,33 +46,23 @@ const struct cmd_entry cmd_list_buffers_entry = {
static enum cmd_retval static enum cmd_retval
cmd_list_buffers_exec(struct cmd *self, struct cmdq_item *item) cmd_list_buffers_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct paste_buffer *pb; struct paste_buffer *pb;
struct format_tree *ft; struct format_tree *ft;
const char *template, *filter; char *line;
char *line, *expanded; const char *template;
int flag;
if ((template = args_get(args, 'F')) == NULL) if ((template = args_get(args, 'F')) == NULL)
template = LIST_BUFFERS_TEMPLATE; template = LIST_BUFFERS_TEMPLATE;
filter = args_get(args, 'f');
pb = NULL; pb = NULL;
while ((pb = paste_walk(pb)) != NULL) { while ((pb = paste_walk(pb)) != NULL) {
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0); ft = format_create(item->client, item, FORMAT_NONE, 0);
format_defaults_paste_buffer(ft, pb); format_defaults_paste_buffer(ft, pb);
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

@@ -28,12 +28,10 @@
* List all clients. * List all clients.
*/ */
#define LIST_CLIENTS_TEMPLATE \ #define LIST_CLIENTS_TEMPLATE \
"#{client_name}: #{session_name} " \ "#{client_name}: #{session_name} " \
"[#{client_width}x#{client_height} #{client_termname}] " \ "[#{client_width}x#{client_height} #{client_termname}]" \
"#{?#{!=:#{client_uid},#{uid}}," \ "#{?client_utf8, (utf8),} #{?client_readonly, (ro),}"
"[user #{?client_user,#{client_user},#{client_uid},}] ,}" \
"#{?client_flags,(,}#{client_flags}#{?client_flags,),}"
static enum cmd_retval cmd_list_clients_exec(struct cmd *, struct cmdq_item *); static enum cmd_retval cmd_list_clients_exec(struct cmd *, struct cmdq_item *);
@@ -41,8 +39,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 },
.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 },
@@ -53,45 +51,34 @@ const struct cmd_entry cmd_list_clients_entry = {
static enum cmd_retval static enum cmd_retval
cmd_list_clients_exec(struct cmd *self, struct cmdq_item *item) cmd_list_clients_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(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 = item->target.s;
else else
s = NULL; s = NULL;
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) {
if (c->session == NULL || (s != NULL && s != c->session)) if (c->session == NULL || (s != NULL && s != c->session))
continue; continue;
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0); ft = format_create(item->client, item, FORMAT_NONE, 0);
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

@@ -36,7 +36,7 @@ const struct cmd_entry cmd_list_keys_entry = {
.name = "list-keys", .name = "list-keys",
.alias = "lsk", .alias = "lsk",
.args = { "1aNP:T:", 0, 1, NULL }, .args = { "1aNP:T:", 0, 1 },
.usage = "[-1aN] [-P prefix-string] [-T key-table] [key]", .usage = "[-1aN] [-P prefix-string] [-T key-table] [key]",
.flags = CMD_STARTSERVER|CMD_AFTERHOOK, .flags = CMD_STARTSERVER|CMD_AFTERHOOK,
@@ -47,7 +47,7 @@ const struct cmd_entry cmd_list_commands_entry = {
.name = "list-commands", .name = "list-commands",
.alias = "lscm", .alias = "lscm",
.args = { "F:", 0, 1, NULL }, .args = { "F:", 0, 1 },
.usage = "[-F format] [command]", .usage = "[-F format] [command]",
.flags = CMD_STARTSERVER|CMD_AFTERHOOK, .flags = CMD_STARTSERVER|CMD_AFTERHOOK,
@@ -68,12 +68,11 @@ cmd_list_keys_get_width(const char *tablename, key_code only)
while (bd != NULL) { while (bd != NULL) {
if ((only != KEYC_UNKNOWN && bd->key != only) || if ((only != KEYC_UNKNOWN && bd->key != only) ||
KEYC_IS_MOUSE(bd->key) || KEYC_IS_MOUSE(bd->key) ||
bd->note == NULL || bd->note == NULL) {
*bd->note == '\0') {
bd = key_bindings_next(table, bd); bd = key_bindings_next(table, bd);
continue; continue;
} }
width = utf8_cstrwidth(key_string_lookup_key(bd->key, 0)); width = utf8_cstrwidth(key_string_lookup_key(bd->key));
if (width > keywidth) if (width > keywidth)
keywidth = width; keywidth = width;
@@ -86,12 +85,12 @@ static int
cmd_list_keys_print_notes(struct cmdq_item *item, struct args *args, cmd_list_keys_print_notes(struct cmdq_item *item, struct args *args,
const char *tablename, u_int keywidth, key_code only, const char *prefix) const char *tablename, u_int keywidth, key_code only, const char *prefix)
{ {
struct client *tc = cmdq_get_target_client(item); struct client *c = cmd_find_client(item, NULL, 1);
struct key_table *table; struct key_table *table;
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)
@@ -100,23 +99,21 @@ cmd_list_keys_print_notes(struct cmdq_item *item, struct args *args,
while (bd != NULL) { while (bd != NULL) {
if ((only != KEYC_UNKNOWN && bd->key != only) || if ((only != KEYC_UNKNOWN && bd->key != only) ||
KEYC_IS_MOUSE(bd->key) || KEYC_IS_MOUSE(bd->key) ||
((bd->note == NULL || *bd->note == '\0') && (bd->note == NULL && !args_has(args, 'a'))) {
!args_has(args, 'a'))) {
bd = key_bindings_next(table, bd); bd = key_bindings_next(table, bd);
continue; continue;
} }
found = 1; found = 1;
key = key_string_lookup_key(bd->key, 0); key = key_string_lookup_key(bd->key);
if (bd->note == NULL || *bd->note == '\0') if (bd->note == NULL)
note = cmd_list_print(bd->cmdlist, 1); note = cmd_list_print(bd->cmdlist, 1);
else else
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') && c != NULL)
status_message_set(tc, -1, 1, 0, 0, "%s%s%s", prefix, status_message_set(c, "%s%s%s", prefix, tmp, note);
tmp, 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);
free(note); free(note);
@@ -136,7 +133,7 @@ cmd_list_keys_get_prefix(struct args *args, key_code *prefix)
*prefix = options_get_number(global_s_options, "prefix"); *prefix = options_get_number(global_s_options, "prefix");
if (!args_has(args, 'P')) { if (!args_has(args, 'P')) {
if (*prefix != KEYC_NONE) if (*prefix != KEYC_NONE)
xasprintf(&s, "%s ", key_string_lookup_key(*prefix, 0)); xasprintf(&s, "%s ", key_string_lookup_key(*prefix));
else else
s = xstrdup(""); s = xstrdup("");
} else } else
@@ -147,26 +144,24 @@ cmd_list_keys_get_prefix(struct args *args, key_code *prefix)
static enum cmd_retval 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 = self->args;
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;
char *key, *cp, *tmp, *start, *empty; char *key, *cp, *tmp, *start, *empty;
key_code prefix, only = KEYC_UNKNOWN; key_code prefix, only = KEYC_UNKNOWN;
int repeat, width, tablewidth, keywidth, found = 0; int repeat, width, tablewidth, keywidth, found = 0;
size_t tmpsize, tmpused, cplen; size_t tmpsize, tmpused, cplen;
if (cmd_get_entry(self) == &cmd_list_commands_entry) if (self->entry == &cmd_list_commands_entry)
return (cmd_list_keys_commands(self, item)); return (cmd_list_keys_commands(self, item));
if ((keystr = args_string(args, 0)) != NULL) { if (args->argc != 0) {
only = key_string_lookup_string(keystr); only = key_string_lookup_string(args->argv[0]);
if (only == KEYC_UNKNOWN) { if (only == KEYC_UNKNOWN) {
cmdq_error(item, "invalid key: %s", keystr); cmdq_error(item, "invalid key: %s", args->argv[0]);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
only &= (KEYC_MASK_KEY|KEYC_MASK_MODIFIERS);
} }
tablename = args_get(args, 'T'); tablename = args_get(args, 'T');
@@ -212,7 +207,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
repeat = 0; repeat = 0;
tablewidth = keywidth = 0; tablewidth = keywidth = 0;
table = key_bindings_first_table(); table = key_bindings_first_table ();
while (table != NULL) { while (table != NULL) {
if (tablename != NULL && strcmp(table->name, tablename) != 0) { if (tablename != NULL && strcmp(table->name, tablename) != 0) {
table = key_bindings_next_table(table); table = key_bindings_next_table(table);
@@ -224,7 +219,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
bd = key_bindings_next(table, bd); bd = key_bindings_next(table, bd);
continue; continue;
} }
key = args_escape(key_string_lookup_key(bd->key, 0)); key = args_escape(key_string_lookup_key(bd->key));
if (bd->flags & KEY_BINDING_REPEAT) if (bd->flags & KEY_BINDING_REPEAT)
repeat = 1; repeat = 1;
@@ -245,7 +240,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
tmpsize = 256; tmpsize = 256;
tmp = xmalloc(tmpsize); tmp = xmalloc(tmpsize);
table = key_bindings_first_table(); table = key_bindings_first_table ();
while (table != NULL) { while (table != NULL) {
if (tablename != NULL && strcmp(table->name, tablename) != 0) { if (tablename != NULL && strcmp(table->name, tablename) != 0) {
table = key_bindings_next_table(table); table = key_bindings_next_table(table);
@@ -258,7 +253,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
continue; continue;
} }
found = 1; found = 1;
key = args_escape(key_string_lookup_key(bd->key, 0)); key = args_escape(key_string_lookup_key(bd->key));
if (!repeat) if (!repeat)
r = ""; r = "";
@@ -274,7 +269,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
tmpsize *= 2; tmpsize *= 2;
tmp = xrealloc(tmp, tmpsize); tmp = xrealloc(tmp, tmpsize);
} }
strlcat(tmp, cp, tmpsize); tmpused = strlcat(tmp, cp, tmpsize);
tmpused = strlcat(tmp, " ", tmpsize); tmpused = strlcat(tmp, " ", tmpsize);
free(cp); free(cp);
@@ -284,7 +279,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
tmpsize *= 2; tmpsize *= 2;
tmp = xrealloc(tmp, tmpsize); tmp = xrealloc(tmp, tmpsize);
} }
strlcat(tmp, cp, tmpsize); tmpused = strlcat(tmp, cp, tmpsize);
tmpused = strlcat(tmp, " ", tmpsize); tmpused = strlcat(tmp, " ", tmpsize);
free(cp); free(cp);
@@ -297,15 +292,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);
@@ -315,46 +304,24 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
out: out:
if (only != KEYC_UNKNOWN && !found) { if (only != KEYC_UNKNOWN && !found) {
cmdq_error(item, "unknown key: %s", args_string(args, 0)); cmdq_error(item, "unknown key: %s", args->argv[0]);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
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)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
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 = NULL;
char *cause; char *line;
if (args->argc != 0)
command = args->argv[0];
if ((template = args_get(args, 'F')) == NULL) { if ((template = args_get(args, 'F')) == NULL) {
template = "#{command_list_name}" template = "#{command_list_name}"
@@ -362,23 +329,33 @@ cmd_list_keys_commands(struct cmd *self, struct cmdq_item *item)
"#{command_list_usage}"; "#{command_list_usage}";
} }
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0); ft = format_create(item->client, item, FORMAT_NONE, 0);
format_defaults(ft, NULL, NULL, NULL, NULL); format_defaults(ft, NULL, NULL, NULL, NULL);
command = args_string(args, 0); for (entryp = cmd_table; *entryp != NULL; entryp++) {
if (command == NULL) { entry = *entryp;
for (entryp = cmd_table; *entryp != NULL; entryp++) if (command != NULL &&
cmd_list_single_command(*entryp, ft, template, item); (strcmp(entry->name, command) != 0 &&
} else { (entry->alias == NULL ||
entry = cmd_find(command, &cause); strcmp(entry->alias, command) != 0)))
if (entry != NULL) continue;
cmd_list_single_command(entry, ft, template, item);
else { format_add(ft, "command_list_name", "%s", entry->name);
cmdq_error(item, "%s", cause); if (entry->alias != NULL)
free(cause); s = entry->alias;
format_free(ft); else
return (CMD_RETURN_ERROR); 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

@@ -38,8 +38,8 @@ const struct cmd_entry cmd_list_panes_entry = {
.name = "list-panes", .name = "list-panes",
.alias = "lsp", .alias = "lsp",
.args = { "asF:f:t:", 0, 0, NULL }, .args = { "asF:t:", 0, 0 },
.usage = "[-as] [-F format] [-f filter] " CMD_TARGET_WINDOW_USAGE, .usage = "[-as] [-F format] " CMD_TARGET_WINDOW_USAGE,
.target = { 't', CMD_FIND_WINDOW, 0 }, .target = { 't', CMD_FIND_WINDOW, 0 },
@@ -50,10 +50,9 @@ const struct cmd_entry cmd_list_panes_entry = {
static enum cmd_retval static enum cmd_retval
cmd_list_panes_exec(struct cmd *self, struct cmdq_item *item) cmd_list_panes_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item); struct session *s = item->target.s;
struct session *s = target->s; struct winlink *wl = item->target.wl;
struct winlink *wl = target->wl;
if (args_has(args, 'a')) if (args_has(args, 'a'))
cmd_list_panes_server(self, item); cmd_list_panes_server(self, item);
@@ -88,13 +87,12 @@ static void
cmd_list_panes_window(struct cmd *self, struct session *s, struct winlink *wl, cmd_list_panes_window(struct cmd *self, struct session *s, struct winlink *wl,
struct cmdq_item *item, int type) struct cmdq_item *item, int type)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct window_pane *wp; struct window_pane *wp;
u_int n; u_int n;
struct format_tree *ft; struct format_tree *ft;
const char *template, *filter; const char *template;
char *line, *expanded; char *line;
int flag;
template = args_get(args, 'F'); template = args_get(args, 'F');
if (template == NULL) { if (template == NULL) {
@@ -122,25 +120,16 @@ cmd_list_panes_window(struct cmd *self, struct session *s, struct winlink *wl,
break; break;
} }
} }
filter = args_get(args, 'f');
n = 0; n = 0;
TAILQ_FOREACH(wp, &wl->window->panes, entry) { TAILQ_FOREACH(wp, &wl->window->panes, entry) {
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0); ft = format_create(item->client, item, FORMAT_NONE, 0);
format_add(ft, "line", "%u", n); format_add(ft, "line", "%u", n);
format_defaults(ft, NULL, s, wl, wp); format_defaults(ft, NULL, s, wl, wp);
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);
n++; n++;

View File

@@ -42,8 +42,8 @@ const struct cmd_entry cmd_list_sessions_entry = {
.name = "list-sessions", .name = "list-sessions",
.alias = "ls", .alias = "ls",
.args = { "F:f:", 0, 0, NULL }, .args = { "F:", 0, 0 },
.usage = "[-F format] [-f filter]", .usage = "[-F format]",
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_list_sessions_exec .exec = cmd_list_sessions_exec
@@ -52,35 +52,25 @@ const struct cmd_entry cmd_list_sessions_entry = {
static enum cmd_retval static enum cmd_retval
cmd_list_sessions_exec(struct cmd *self, struct cmdq_item *item) cmd_list_sessions_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct session *s; struct session *s;
u_int n; u_int n;
struct format_tree *ft; struct format_tree *ft;
const char *template, *filter; const char *template;
char *line, *expanded; char *line;
int flag;
if ((template = args_get(args, 'F')) == NULL) if ((template = args_get(args, 'F')) == NULL)
template = LIST_SESSIONS_TEMPLATE; template = LIST_SESSIONS_TEMPLATE;
filter = args_get(args, 'f');
n = 0; n = 0;
RB_FOREACH(s, sessions, &sessions) { RB_FOREACH(s, sessions, &sessions) {
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0); ft = format_create(item->client, item, FORMAT_NONE, 0);
format_add(ft, "line", "%u", n); format_add(ft, "line", "%u", n);
format_defaults(ft, NULL, s, NULL, NULL); format_defaults(ft, NULL, s, 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);
n++; n++;

View File

@@ -28,14 +28,14 @@
*/ */
#define LIST_WINDOWS_TEMPLATE \ #define LIST_WINDOWS_TEMPLATE \
"#{window_index}: #{window_name}#{window_raw_flags} " \ "#{window_index}: #{window_name}#{window_flags} " \
"(#{window_panes} panes) " \ "(#{window_panes} panes) " \
"[#{window_width}x#{window_height}] " \ "[#{window_width}x#{window_height}] " \
"[layout #{window_layout}] #{window_id}" \ "[layout #{window_layout}] #{window_id}" \
"#{?window_active, (active),}"; "#{?window_active, (active),}";
#define LIST_WINDOWS_WITH_SESSION_TEMPLATE \ #define LIST_WINDOWS_WITH_SESSION_TEMPLATE \
"#{session_name}:" \ "#{session_name}:" \
"#{window_index}: #{window_name}#{window_raw_flags} " \ "#{window_index}: #{window_name}#{window_flags} " \
"(#{window_panes} panes) " \ "(#{window_panes} panes) " \
"[#{window_width}x#{window_height}] " "[#{window_width}x#{window_height}] "
@@ -49,8 +49,8 @@ const struct cmd_entry cmd_list_windows_entry = {
.name = "list-windows", .name = "list-windows",
.alias = "lsw", .alias = "lsw",
.args = { "F:f:at:", 0, 0, NULL }, .args = { "F:at:", 0, 0 },
.usage = "[-a] [-F format] [-f filter] " CMD_TARGET_SESSION_USAGE, .usage = "[-a] [-F format] " CMD_TARGET_SESSION_USAGE,
.target = { 't', CMD_FIND_SESSION, 0 }, .target = { 't', CMD_FIND_SESSION, 0 },
@@ -61,13 +61,12 @@ const struct cmd_entry cmd_list_windows_entry = {
static enum cmd_retval static enum cmd_retval
cmd_list_windows_exec(struct cmd *self, struct cmdq_item *item) cmd_list_windows_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item);
if (args_has(args, 'a')) if (args_has(args, 'a'))
cmd_list_windows_server(self, item); cmd_list_windows_server(self, item);
else else
cmd_list_windows_session(self, target->s, item, 0); cmd_list_windows_session(self, item->target.s, item, 0);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
@@ -85,13 +84,12 @@ static void
cmd_list_windows_session(struct cmd *self, struct session *s, cmd_list_windows_session(struct cmd *self, struct session *s,
struct cmdq_item *item, int type) struct cmdq_item *item, int type)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct winlink *wl; struct winlink *wl;
u_int n; u_int n;
struct format_tree *ft; struct format_tree *ft;
const char *template, *filter; const char *template;
char *line, *expanded; char *line;
int flag;
template = args_get(args, 'F'); template = args_get(args, 'F');
if (template == NULL) { if (template == NULL) {
@@ -104,25 +102,16 @@ cmd_list_windows_session(struct cmd *self, struct session *s,
break; break;
} }
} }
filter = args_get(args, 'f');
n = 0; n = 0;
RB_FOREACH(wl, winlinks, &s->windows) { RB_FOREACH(wl, winlinks, &s->windows) {
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0); ft = format_create(item->client, item, FORMAT_NONE, 0);
format_add(ft, "line", "%u", n); format_add(ft, "line", "%u", n);
format_defaults(ft, NULL, s, wl, NULL); format_defaults(ft, NULL, s, wl, 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);
n++; n++;

View File

@@ -37,15 +37,14 @@ const struct cmd_entry cmd_load_buffer_entry = {
.name = "load-buffer", .name = "load-buffer",
.alias = "loadb", .alias = "loadb",
.args = { "b:t:w", 1, 1, NULL }, .args = { "b:", 1, 1 },
.usage = CMD_BUFFER_USAGE " " CMD_TARGET_CLIENT_USAGE " path", .usage = CMD_BUFFER_USAGE " path",
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG|CMD_CLIENT_CANFAIL, .flags = CMD_AFTERHOOK,
.exec = cmd_load_buffer_exec .exec = cmd_load_buffer_exec
}; };
struct cmd_load_buffer_data { struct cmd_load_buffer_data {
struct client *client;
struct cmdq_item *item; struct cmdq_item *item;
char *name; char *name;
}; };
@@ -55,7 +54,6 @@ cmd_load_buffer_done(__unused struct client *c, const char *path, int error,
int closed, struct evbuffer *buffer, void *data) int closed, struct evbuffer *buffer, void *data)
{ {
struct cmd_load_buffer_data *cdata = data; struct cmd_load_buffer_data *cdata = data;
struct client *tc = cdata->client;
struct cmdq_item *item = cdata->item; struct cmdq_item *item = cdata->item;
void *bdata = EVBUFFER_DATA(buffer); void *bdata = EVBUFFER_DATA(buffer);
size_t bsize = EVBUFFER_LENGTH(buffer); size_t bsize = EVBUFFER_LENGTH(buffer);
@@ -66,7 +64,7 @@ cmd_load_buffer_done(__unused struct client *c, const char *path, int error,
return; return;
if (error != 0) if (error != 0)
cmdq_error(item, "%s: %s", strerror(error), path); cmdq_error(item, "%s: %s", path, strerror(error));
else if (bsize != 0) { else if (bsize != 0) {
copy = xmalloc(bsize); copy = xmalloc(bsize);
memcpy(copy, bdata, bsize); memcpy(copy, bdata, bsize);
@@ -74,12 +72,7 @@ cmd_load_buffer_done(__unused struct client *c, const char *path, int error,
cmdq_error(item, "%s", cause); cmdq_error(item, "%s", cause);
free(cause); free(cause);
free(copy); free(copy);
} else if (tc != NULL && }
tc->session != NULL &&
(~tc->flags & CLIENT_DEAD))
tty_set_selection(&tc->tty, "", copy, bsize);
if (tc != NULL)
server_client_unref(tc);
} }
cmdq_continue(item); cmdq_continue(item);
@@ -90,23 +83,24 @@ cmd_load_buffer_done(__unused struct client *c, const char *path, int error,
static enum cmd_retval static enum cmd_retval
cmd_load_buffer_exec(struct cmd *self, struct cmdq_item *item) cmd_load_buffer_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct client *tc = cmdq_get_target_client(item);
struct cmd_load_buffer_data *cdata; struct cmd_load_buffer_data *cdata;
struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct window_pane *wp = item->target.wp;
const char *bufname = args_get(args, 'b'); const char *bufname = args_get(args, 'b');
char *path; char *path;
cdata = xcalloc(1, sizeof *cdata); cdata = xmalloc(sizeof *cdata);
cdata->item = item; cdata->item = item;
if (bufname != NULL) if (bufname != NULL)
cdata->name = xstrdup(bufname); cdata->name = xstrdup(bufname);
if (args_has(args, 'w') && tc != NULL) { else
cdata->client = tc; cdata->name = NULL;
cdata->client->references++;
}
path = format_single_from_target(item, args_string(args, 0)); path = format_single(item, args->argv[0], c, s, wl, wp);
file_read(cmdq_get_client(item), path, cmd_load_buffer_done, cdata); file_read(item->client, path, cmd_load_buffer_done, cdata);
free(path); free(path);
return (CMD_RETURN_WAIT); return (CMD_RETURN_WAIT);

View File

@@ -30,7 +30,7 @@ const struct cmd_entry cmd_lock_server_entry = {
.name = "lock-server", .name = "lock-server",
.alias = "lock", .alias = "lock",
.args = { "", 0, 0, NULL }, .args = { "", 0, 0 },
.usage = "", .usage = "",
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
@@ -41,7 +41,7 @@ const struct cmd_entry cmd_lock_session_entry = {
.name = "lock-session", .name = "lock-session",
.alias = "locks", .alias = "locks",
.args = { "t:", 0, 0, NULL }, .args = { "t:", 0, 0 },
.usage = CMD_TARGET_SESSION_USAGE, .usage = CMD_TARGET_SESSION_USAGE,
.target = { 't', CMD_FIND_SESSION, 0 }, .target = { 't', CMD_FIND_SESSION, 0 },
@@ -54,25 +54,28 @@ const struct cmd_entry cmd_lock_client_entry = {
.name = "lock-client", .name = "lock-client",
.alias = "lockc", .alias = "lockc",
.args = { "t:", 0, 0, NULL }, .args = { "t:", 0, 0 },
.usage = CMD_TARGET_CLIENT_USAGE, .usage = CMD_TARGET_CLIENT_USAGE,
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG, .flags = CMD_AFTERHOOK,
.exec = cmd_lock_server_exec .exec = cmd_lock_server_exec
}; };
static enum cmd_retval static enum cmd_retval
cmd_lock_server_exec(struct cmd *self, struct cmdq_item *item) cmd_lock_server_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct cmd_find_state *target = cmdq_get_target(item); struct args *args = self->args;
struct client *tc = cmdq_get_target_client(item); struct client *c;
if (cmd_get_entry(self) == &cmd_lock_server_entry) if (self->entry == &cmd_lock_server_entry)
server_lock(); server_lock();
else if (cmd_get_entry(self) == &cmd_lock_session_entry) else if (self->entry == &cmd_lock_session_entry)
server_lock_session(target->s); server_lock_session(item->target.s);
else else {
server_lock_client(tc); if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
server_lock_client(c);
}
recalculate_sizes(); recalculate_sizes();
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);

View File

@@ -32,8 +32,8 @@ const struct cmd_entry cmd_move_window_entry = {
.name = "move-window", .name = "move-window",
.alias = "movew", .alias = "movew",
.args = { "abdkrs:t:", 0, 0, NULL }, .args = { "adkrs:t:", 0, 0 },
.usage = "[-abdkr] " CMD_SRCDST_WINDOW_USAGE, .usage = "[-dkr] " CMD_SRCDST_WINDOW_USAGE,
.source = { 's', CMD_FIND_WINDOW, 0 }, .source = { 's', CMD_FIND_WINDOW, 0 },
/* -t is special */ /* -t is special */
@@ -46,8 +46,8 @@ const struct cmd_entry cmd_link_window_entry = {
.name = "link-window", .name = "link-window",
.alias = "linkw", .alias = "linkw",
.args = { "abdks:t:", 0, 0, NULL }, .args = { "adks:t:", 0, 0 },
.usage = "[-abdk] " CMD_SRCDST_WINDOW_USAGE, .usage = "[-dk] " CMD_SRCDST_WINDOW_USAGE,
.source = { 's', CMD_FIND_WINDOW, 0 }, .source = { 's', CMD_FIND_WINDOW, 0 },
/* -t is special */ /* -t is special */
@@ -59,53 +59,49 @@ const struct cmd_entry cmd_link_window_entry = {
static enum cmd_retval static enum cmd_retval
cmd_move_window_exec(struct cmd *self, struct cmdq_item *item) cmd_move_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *source = cmdq_get_source(item); const char *tflag = args_get(args, 't');
struct cmd_find_state target; struct session *src;
const char *tflag = args_get(args, 't'); struct session *dst;
struct session *src = source->s; struct winlink *wl;
struct session *dst; char *cause;
struct winlink *wl = source->wl; int idx, kflag, dflag, sflag;
char *cause;
int idx, kflag, dflag, sflag, before;
if (args_has(args, 'r')) { if (args_has(args, 'r')) {
if (cmd_find_target(&target, item, tflag, CMD_FIND_SESSION, if (cmd_find_target(&item->target, item, tflag,
CMD_FIND_QUIET) != 0) CMD_FIND_SESSION, CMD_FIND_QUIET) != 0)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
session_renumber_windows(target.s); session_renumber_windows(item->target.s);
recalculate_sizes(); recalculate_sizes();
server_status_session(target.s); server_status_session(item->target.s);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (cmd_find_target(&target, item, tflag, CMD_FIND_WINDOW, if (cmd_find_target(&item->target, item, tflag, CMD_FIND_WINDOW,
CMD_FIND_WINDOW_INDEX) != 0) CMD_FIND_WINDOW_INDEX) != 0)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
dst = target.s; src = item->source.s;
idx = target.idx; dst = item->target.s;
wl = item->source.wl;
idx = item->target.idx;
kflag = args_has(args, 'k'); kflag = args_has(self->args, 'k');
dflag = args_has(args, 'd'); dflag = args_has(self->args, 'd');
sflag = args_has(args, 's'); sflag = args_has(self->args, 's');
before = args_has(args, 'b'); if (args_has(self->args, 'a')) {
if (args_has(args, 'a') || before) { if ((idx = winlink_shuffle_up(dst, dst->curw)) == -1)
if (target.wl != NULL)
idx = winlink_shuffle_up(dst, target.wl, before);
else
idx = winlink_shuffle_up(dst, dst->curw, before);
if (idx == -1)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (server_link_window(src, wl, dst, idx, kflag, !dflag, &cause) != 0) { if (server_link_window(src, wl, dst, idx, kflag, !dflag,
cmdq_error(item, "%s", cause); &cause) != 0) {
cmdq_error(item, "can't link window: %s", cause);
free(cause); free(cause);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (cmd_get_entry(self) == &cmd_move_window_entry) if (self->entry == &cmd_move_window_entry)
server_unlink_window(src, wl); server_unlink_window(src, wl);
/* /*

View File

@@ -39,11 +39,10 @@ const struct cmd_entry cmd_new_session_entry = {
.name = "new-session", .name = "new-session",
.alias = "new", .alias = "new",
.args = { "Ac:dDe:EF:f:n:Ps:t:x:Xy:", 0, -1, NULL }, .args = { "Ac:dDEF:n:Ps:t:x:Xy:", 0, -1 },
.usage = "[-AdDEPX] [-c start-directory] [-e environment] [-F format] " .usage = "[-AdDEPX] [-c start-directory] [-F format] [-n window-name] "
"[-f flags] [-n window-name] [-s session-name] " "[-s session-name] " CMD_TARGET_SESSION_USAGE " [-x width] "
CMD_TARGET_SESSION_USAGE " [-x width] [-y height] " "[-y height] [command]",
"[shell-command [argument ...]]",
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL }, .target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
@@ -55,7 +54,7 @@ const struct cmd_entry cmd_has_session_entry = {
.name = "has-session", .name = "has-session",
.alias = "has", .alias = "has",
.args = { "t:", 0, 0, NULL }, .args = { "t:", 0, 0 },
.usage = CMD_TARGET_SESSION_USAGE, .usage = CMD_TARGET_SESSION_USAGE,
.target = { 't', CMD_FIND_SESSION, 0 }, .target = { 't', CMD_FIND_SESSION, 0 },
@@ -67,26 +66,22 @@ const struct cmd_entry cmd_has_session_entry = {
static enum cmd_retval static enum cmd_retval
cmd_new_session_exec(struct cmd *self, struct cmdq_item *item) cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *current = cmdq_get_current(item); struct client *c = item->client;
struct cmd_find_state *target = cmdq_get_target(item); struct session *s, *as, *groupwith;
struct client *c = cmdq_get_client(item);
struct session *s, *as, *groupwith = NULL;
struct environ *env; struct environ *env;
struct options *oo; struct options *oo;
struct termios tio, *tiop; struct termios tio, *tiop;
struct session_group *sg = NULL; struct session_group *sg;
const char *errstr, *template, *group, *tmp; const char *errstr, *template, *group, *prefix, *tmp;
char *cause, *cwd = NULL, *cp, *newname = NULL; char *cause, *cwd = NULL, *cp, *newname = NULL;
char *name, *prefix = NULL;
int detached, already_attached, is_control = 0; int detached, already_attached, is_control = 0;
u_int sx, sy, dsx, dsy, count = args_count(args); u_int sx, sy, dsx, dsy;
struct spawn_context sc = { 0 }; struct spawn_context sc;
enum cmd_retval retval; enum cmd_retval retval;
struct cmd_find_state fs; struct cmd_find_state fs;
struct args_value *av;
if (cmd_get_entry(self) == &cmd_has_session_entry) { if (self->entry == &cmd_has_session_entry) {
/* /*
* cmd_find_target() will fail if the session cannot be found, * cmd_find_target() will fail if the session cannot be found,
* so always return success here. * so always return success here.
@@ -94,31 +89,28 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (args_has(args, 't') && (count != 0 || args_has(args, 'n'))) { if (args_has(args, 't') && (args->argc != 0 || args_has(args, 'n'))) {
cmdq_error(item, "command or window name given with target"); cmdq_error(item, "command or window name given with target");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
tmp = args_get(args, 's'); tmp = args_get(args, 's');
if (tmp != NULL) { if (tmp != NULL) {
name = format_single(item, tmp, c, NULL, NULL, NULL); newname = format_single(item, tmp, c, NULL, NULL, NULL);
newname = session_check_name(name); if (!session_check_name(newname)) {
if (newname == NULL) { cmdq_error(item, "bad session name: %s", newname);
cmdq_error(item, "invalid session: %s", name); goto fail;
free(name);
return (CMD_RETURN_ERROR);
} }
free(name);
} }
if (args_has(args, 'A')) { if (args_has(args, 'A')) {
if (newname != NULL) if (newname != NULL)
as = session_find(newname); as = session_find(newname);
else else
as = target->s; as = item->target.s;
if (as != NULL) { if (as != NULL) {
retval = cmd_attach_session(item, as->name, retval = cmd_attach_session(item, as->name,
args_has(args, 'D'), args_has(args, 'X'), 0, NULL, args_has(args, 'D'), args_has(args, 'X'), 0, NULL,
args_has(args, 'E'), args_get(args, 'f')); args_has(args, 'E'));
free(newname); free(newname);
return (retval); return (retval);
} }
@@ -131,23 +123,25 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
/* Is this going to be part of a session group? */ /* Is this going to be part of a session group? */
group = args_get(args, 't'); group = args_get(args, 't');
if (group != NULL) { if (group != NULL) {
groupwith = target->s; groupwith = item->target.s;
if (groupwith == NULL) if (groupwith == NULL) {
sg = session_group_find(group); if (!session_check_name(group)) {
else cmdq_error(item, "bad group name: %s", group);
sg = session_group_contains(groupwith);
if (sg != NULL)
prefix = xstrdup(sg->name);
else if (groupwith != NULL)
prefix = xstrdup(groupwith->name);
else {
prefix = session_check_name(group);
if (prefix == NULL) {
cmdq_error(item, "invalid session group: %s",
group);
goto fail; goto fail;
} }
} sg = session_group_find(group);
} else
sg = session_group_contains(groupwith);
if (sg != NULL)
prefix = sg->name;
else if (groupwith != NULL)
prefix = groupwith->name;
else
prefix = group;
} else {
groupwith = NULL;
sg = NULL;
prefix = NULL;
} }
/* Set -d if no client. */ /* Set -d if no client. */
@@ -177,16 +171,13 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
* the terminal as that calls tcsetattr() to prepare for tmux taking * the terminal as that calls tcsetattr() to prepare for tmux taking
* over. * over.
*/ */
if (!detached && if (!detached && !already_attached && c->tty.fd != -1) {
!already_attached && if (server_client_check_nested(item->client)) {
c->fd != -1 &&
(~c->flags & CLIENT_CONTROL)) {
if (server_client_check_nested(cmdq_get_client(item))) {
cmdq_error(item, "sessions should be nested with care, " cmdq_error(item, "sessions should be nested with care, "
"unset $TMUX to force"); "unset $TMUX to force");
goto fail; goto fail;
} }
if (tcgetattr(c->fd, &tio) != 0) if (tcgetattr(c->tty.fd, &tio) != 0)
fatal("tcgetattr failed"); fatal("tcgetattr failed");
tiop = &tio; tiop = &tio;
} else } else
@@ -216,8 +207,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
goto fail; goto fail;
} }
} }
} else }
dsx = 80;
if (args_has(args, 'y')) { if (args_has(args, 'y')) {
tmp = args_get(args, 'y'); tmp = args_get(args, 'y');
if (strcmp(tmp, "-") == 0) { if (strcmp(tmp, "-") == 0) {
@@ -232,8 +222,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
goto fail; goto fail;
} }
} }
} else }
dsy = 24;
/* Find new session size. */ /* Find new session size. */
if (!detached && !is_control) { if (!detached && !is_control) {
@@ -244,14 +233,13 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
} else { } else {
tmp = options_get_string(global_s_options, "default-size"); tmp = options_get_string(global_s_options, "default-size");
if (sscanf(tmp, "%ux%u", &sx, &sy) != 2) { if (sscanf(tmp, "%ux%u", &sx, &sy) != 2) {
sx = dsx; sx = 80;
sy = dsy; sy = 24;
} else {
if (args_has(args, 'x'))
sx = dsx;
if (args_has(args, 'y'))
sy = dsy;
} }
if (args_has(args, 'x'))
sx = dsx;
if (args_has(args, 'y'))
sy = dsy;
} }
if (sx == 0) if (sx == 0)
sx = 1; sx = 1;
@@ -270,21 +258,17 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
env = environ_create(); env = environ_create();
if (c != NULL && !args_has(args, 'E')) if (c != NULL && !args_has(args, 'E'))
environ_update(global_s_options, c->environ, env); environ_update(global_s_options, c->environ, env);
av = args_first_value(args, 'e');
while (av != NULL) {
environ_put(env, av->string, 0);
av = args_next_value(av);
}
s = session_create(prefix, newname, cwd, env, oo, tiop); s = session_create(prefix, newname, cwd, env, oo, tiop);
/* Spawn the initial window. */ /* Spawn the initial window. */
memset(&sc, 0, sizeof sc);
sc.item = item; sc.item = item;
sc.s = s; sc.s = s;
if (!detached) sc.c = c;
sc.tc = c;
sc.name = args_get(args, 'n'); sc.name = args_get(args, 'n');
args_to_vector(args, &sc.argc, &sc.argv); sc.argc = args->argc;
sc.argv = args->argv;
sc.idx = -1; sc.idx = -1;
sc.cwd = args_get(args, 'c'); sc.cwd = args_get(args, 'c');
@@ -321,17 +305,30 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
* taking this session and needs to get MSG_READY and stay around. * taking this session and needs to get MSG_READY and stay around.
*/ */
if (!detached) { if (!detached) {
if (args_has(args, 'f'))
server_client_set_flags(c, args_get(args, 'f'));
if (!already_attached) { if (!already_attached) {
if (~c->flags & CLIENT_CONTROL) if (~c->flags & CLIENT_CONTROL)
proc_send(c->peer, MSG_READY, -1, NULL, 0); proc_send(c->peer, MSG_READY, -1, NULL, 0);
} else if (c->session != NULL) } else if (c->session != NULL)
c->last_session = c->session; c->last_session = c->session;
server_client_set_session(c, s); c->session = s;
if (~cmdq_get_flags(item) & CMDQ_STATE_REPEAT) if (~item->shared->flags & CMDQ_SHARED_REPEAT)
server_client_set_key_table(c, NULL); server_client_set_key_table(c, NULL);
tty_update_client_offset(c);
status_timer_start(c);
notify_client("client-session-changed", c);
session_update_activity(s, NULL);
gettimeofday(&s->last_attached_time, NULL);
server_redraw_client(c);
} }
recalculate_sizes();
server_update_socket();
/*
* 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')) {
@@ -342,29 +339,20 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
free(cp); free(cp);
} }
if (!detached) if (!detached) {
c->flags |= CLIENT_ATTACHED; c->flags |= CLIENT_ATTACHED;
if (!args_has(args, 'd')) cmd_find_from_session(&item->shared->current, s, 0);
cmd_find_from_session(current, s, 0); }
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)
cmd_free_argv(sc.argc, sc.argv);
free(cwd); free(cwd);
free(newname); free(newname);
free(prefix);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
fail: fail:
if (sc.argv != NULL)
cmd_free_argv(sc.argc, sc.argv);
free(cwd); free(cwd);
free(newname); free(newname);
free(prefix);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }

View File

@@ -38,10 +38,9 @@ const struct cmd_entry cmd_new_window_entry = {
.name = "new-window", .name = "new-window",
.alias = "neww", .alias = "neww",
.args = { "abc:de:F:kn:PSt:", 0, -1, NULL }, .args = { "ac:de:F:kn:Pt:", 0, -1 },
.usage = "[-abdkPS] [-c start-directory] [-e environment] [-F format] " .usage = "[-adkP] [-c start-directory] [-e environment] [-F format] "
"[-n window-name] " CMD_TARGET_WINDOW_USAGE "[-n window-name] " CMD_TARGET_WINDOW_USAGE " [command]",
" [shell-command [argument ...]]",
.target = { 't', CMD_FIND_WINDOW, CMD_FIND_WINDOW_INDEX }, .target = { 't', CMD_FIND_WINDOW, CMD_FIND_WINDOW_INDEX },
@@ -52,70 +51,38 @@ const struct cmd_entry cmd_new_window_entry = {
static enum cmd_retval static enum cmd_retval
cmd_new_window_exec(struct cmd *self, struct cmdq_item *item) cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct client *c = cmdq_get_client(item); struct cmd_find_state *current = &item->shared->current;
struct cmd_find_state *current = cmdq_get_current(item); struct spawn_context sc;
struct cmd_find_state *target = cmdq_get_target(item); struct client *c = cmd_find_client(item, NULL, 1);
struct spawn_context sc = { 0 }; struct session *s = item->target.s;
struct client *tc = cmdq_get_target_client(item); struct winlink *wl = item->target.wl;
struct session *s = target->s; int idx = item->target.idx;
struct winlink *wl = target->wl, *new_wl = NULL; struct winlink *new_wl;
int idx = target->idx, before; char *cause = NULL, *cp;
char *cause = NULL, *cp, *expanded; const char *template, *add;
const char *template, *name;
struct cmd_find_state fs; struct cmd_find_state fs;
struct args_value *av; struct args_value *value;
/* if (args_has(args, 'a') && (idx = winlink_shuffle_up(s, wl)) == -1) {
* If -S and -n are given and -t is not and a single window with this cmdq_error(item, "couldn't get a window index");
* name already exists, select it. return (CMD_RETURN_ERROR);
*/
name = args_get(args, 'n');
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) {
if (strcmp(wl->window->name, expanded) != 0)
continue;
if (new_wl == NULL) {
new_wl = wl;
continue;
}
cmdq_error(item, "multiple windows named %s", name);
free(expanded);
return (CMD_RETURN_ERROR);
}
free(expanded);
if (new_wl != NULL) {
if (args_has(args, 'd'))
return (CMD_RETURN_NORMAL);
if (session_set_current(s, new_wl) == 0)
server_redraw_session(s);
if (c != NULL && c->session != NULL)
s->curw->window->latest = c;
recalculate_sizes();
return (CMD_RETURN_NORMAL);
}
}
before = args_has(args, 'b');
if (args_has(args, 'a') || before) {
idx = winlink_shuffle_up(s, wl, before);
if (idx == -1)
idx = target->idx;
} }
memset(&sc, 0, sizeof sc);
sc.item = item; sc.item = item;
sc.s = s; sc.s = s;
sc.tc = tc; sc.c = c;
sc.name = args_get(args, 'n'); sc.name = args_get(args, 'n');
args_to_vector(args, &sc.argc, &sc.argv); sc.argc = args->argc;
sc.argv = args->argv;
sc.environ = environ_create(); sc.environ = environ_create();
av = args_first_value(args, 'e'); add = args_first_value(args, 'e', &value);
while (av != NULL) { while (add != NULL) {
environ_put(sc.environ, av->string, 0); environ_put(sc.environ, add);
av = args_next_value(av); add = args_next_value(&value);
} }
sc.idx = idx; sc.idx = idx;
@@ -130,9 +97,6 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
if ((new_wl = spawn_window(&sc, &cause)) == NULL) { if ((new_wl = spawn_window(&sc, &cause)) == NULL) {
cmdq_error(item, "create window failed: %s", cause); cmdq_error(item, "create window failed: %s", cause);
free(cause); free(cause);
if (sc.argv != NULL)
cmd_free_argv(sc.argc, sc.argv);
environ_free(sc.environ);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (!args_has(args, 'd') || new_wl == s->curw) { if (!args_has(args, 'd') || new_wl == s->curw) {
@@ -144,8 +108,8 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(args, 'P')) { if (args_has(args, 'P')) {
if ((template = args_get(args, 'F')) == NULL) if ((template = args_get(args, 'F')) == NULL)
template = NEW_WINDOW_TEMPLATE; template = NEW_WINDOW_TEMPLATE;
cp = format_single(item, template, tc, s, new_wl, cp = format_single(item, template, c, s, new_wl,
new_wl->window->active); new_wl->window->active);
cmdq_print(item, "%s", cp); cmdq_print(item, "%s", cp);
free(cp); free(cp);
} }
@@ -153,8 +117,6 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
cmd_find_from_winlink(&fs, new_wl, 0); cmd_find_from_winlink(&fs, new_wl, 0);
cmdq_insert_hook(s, item, &fs, "after-new-window"); cmdq_insert_hook(s, item, &fs, "after-new-window");
if (sc.argv != NULL)
cmd_free_argv(sc.argc, sc.argv);
environ_free(sc.environ); environ_free(sc.environ);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

File diff suppressed because it is too large Load Diff

View File

@@ -33,7 +33,7 @@ const struct cmd_entry cmd_paste_buffer_entry = {
.name = "paste-buffer", .name = "paste-buffer",
.alias = "pasteb", .alias = "pasteb",
.args = { "db:prs:t:", 0, 0, NULL }, .args = { "db:prs:t:", 0, 0 },
.usage = "[-dpr] [-s separator] " CMD_BUFFER_USAGE " " .usage = "[-dpr] [-s separator] " CMD_BUFFER_USAGE " "
CMD_TARGET_PANE_USAGE, CMD_TARGET_PANE_USAGE,
@@ -46,19 +46,13 @@ const struct cmd_entry cmd_paste_buffer_entry = {
static enum cmd_retval static enum cmd_retval
cmd_paste_buffer_exec(struct cmd *self, struct cmdq_item *item) cmd_paste_buffer_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item); struct window_pane *wp = item->target.wp;
struct window_pane *wp = target->wp;
struct paste_buffer *pb; struct paste_buffer *pb;
const char *sepstr, *bufname, *bufdata, *bufend, *line; const char *sepstr, *bufname, *bufdata, *bufend, *line;
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

@@ -43,8 +43,8 @@ const struct cmd_entry cmd_pipe_pane_entry = {
.name = "pipe-pane", .name = "pipe-pane",
.alias = "pipep", .alias = "pipep",
.args = { "IOot:", 0, 1, NULL }, .args = { "IOot:", 0, 1 },
.usage = "[-IOo] " CMD_TARGET_PANE_USAGE " [shell-command]", .usage = "[-IOo] " CMD_TARGET_PANE_USAGE " [command]",
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
@@ -55,23 +55,15 @@ const struct cmd_entry cmd_pipe_pane_entry = {
static enum cmd_retval static enum cmd_retval
cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item) cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item); struct client *c = cmd_find_client(item, NULL, 1);
struct client *tc = cmdq_get_target_client(item); struct window_pane *wp = item->target.wp;
struct window_pane *wp = target->wp; struct session *s = item->target.s;
struct session *s = target->s; struct winlink *wl = item->target.wl;
struct winlink *wl = target->wl; char *cmd;
struct window_pane_offset *wpo = &wp->pipe_offset; int old_fd, pipe_fd[2], null_fd, in, out;
char *cmd; struct format_tree *ft;
int old_fd, pipe_fd[2], null_fd, in, out; sigset_t set, oldset;
struct format_tree *ft;
sigset_t set, oldset;
/* Do nothing if pane is dead. */
if (window_pane_exited(wp)) {
cmdq_error(item, "target pane has exited");
return (CMD_RETURN_ERROR);
}
/* Destroy the old pipe. */ /* Destroy the old pipe. */
old_fd = wp->pipe_fd; old_fd = wp->pipe_fd;
@@ -87,7 +79,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
} }
/* If no pipe command, that is enough. */ /* If no pipe command, that is enough. */
if (args_count(args) == 0 || *args_string(args, 0) == '\0') if (args->argc == 0 || *args->argv[0] == '\0')
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
/* /*
@@ -96,13 +88,13 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
* *
* bind ^p pipep -o 'cat >>~/output' * bind ^p pipep -o 'cat >>~/output'
*/ */
if (args_has(args, 'o') && old_fd != -1) if (args_has(self->args, 'o') && old_fd != -1)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
/* What do we want to do? Neither -I or -O is -O. */ /* What do we want to do? Neither -I or -O is -O. */
if (args_has(args, 'I')) { if (args_has(self->args, 'I')) {
in = 1; in = 1;
out = args_has(args, 'O'); out = args_has(self->args, 'O');
} else { } else {
in = 0; in = 0;
out = 1; out = 1;
@@ -115,9 +107,9 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
} }
/* Expand the command. */ /* Expand the command. */
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0); ft = format_create(item->client, item, FORMAT_NONE, 0);
format_defaults(ft, tc, s, wl, wp); format_defaults(ft, c, s, wl, wp);
cmd = format_expand_time(ft, args_string(args, 0)); cmd = format_expand_time(ft, args->argv[0]);
format_free(ft); format_free(ft);
/* Fork the child. */ /* Fork the child. */
@@ -136,7 +128,7 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
sigprocmask(SIG_SETMASK, &oldset, NULL); sigprocmask(SIG_SETMASK, &oldset, NULL);
close(pipe_fd[0]); close(pipe_fd[0]);
null_fd = open(_PATH_DEVNULL, O_WRONLY); null_fd = open(_PATH_DEVNULL, O_WRONLY, 0);
if (out) { if (out) {
if (dup2(pipe_fd[1], STDIN_FILENO) == -1) if (dup2(pipe_fd[1], STDIN_FILENO) == -1)
_exit(1); _exit(1);
@@ -165,7 +157,10 @@ cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item)
close(pipe_fd[1]); close(pipe_fd[1]);
wp->pipe_fd = pipe_fd[0]; wp->pipe_fd = pipe_fd[0];
memcpy(wpo, &wp->offset, sizeof *wpo); if (wp->fd != -1)
wp->pipe_off = EVBUFFER_LENGTH(wp->event->input);
else
wp->pipe_off = 0;
setblocking(wp->pipe_fd, 0); setblocking(wp->pipe_fd, 0);
wp->pipe_event = bufferevent_new(wp->pipe_fd, wp->pipe_event = bufferevent_new(wp->pipe_fd,

View File

@@ -19,77 +19,14 @@
#include <sys/types.h> #include <sys/types.h>
#include <ctype.h> #include <ctype.h>
#include <pwd.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include <unistd.h>
#include "tmux.h" #include "tmux.h"
/* Command queue flags. */ /* Global command queue. */
#define CMDQ_FIRED 0x1 static struct cmdq_list global_queue = TAILQ_HEAD_INITIALIZER(global_queue);
#define CMDQ_WAITING 0x2
/* Command queue item type. */
enum cmdq_type {
CMDQ_COMMAND,
CMDQ_CALLBACK,
};
/* Command queue item. */
struct cmdq_item {
char *name;
struct cmdq_list *queue;
struct cmdq_item *next;
struct client *client;
struct client *target_client;
enum cmdq_type type;
u_int group;
u_int number;
time_t time;
int flags;
struct cmdq_state *state;
struct cmd_find_state source;
struct cmd_find_state target;
struct cmd_list *cmdlist;
struct cmd *cmd;
cmdq_cb cb;
void *data;
TAILQ_ENTRY(cmdq_item) entry;
};
TAILQ_HEAD(cmdq_item_list, cmdq_item);
/*
* Command queue state. This is the context for commands on the command queue.
* It holds information about how the commands were fired (the key and flags),
* any additional formats for the commands, and the current default target.
* Multiple commands can share the same state and a command may update the
* default target.
*/
struct cmdq_state {
int references;
int flags;
struct format_tree *formats;
struct key_event event;
struct cmd_find_state current;
};
/* Command queue. */
struct cmdq_list {
struct cmdq_item *item;
struct cmdq_item_list list;
};
/* Get command queue name. */ /* Get command queue name. */
static const char * static const char *
@@ -110,190 +47,9 @@ cmdq_name(struct client *c)
static struct cmdq_list * static struct cmdq_list *
cmdq_get(struct client *c) cmdq_get(struct client *c)
{ {
static struct cmdq_list *global_queue; if (c == NULL)
return (&global_queue);
if (c == NULL) { return (&c->queue);
if (global_queue == NULL)
global_queue = cmdq_new();
return (global_queue);
}
return (c->queue);
}
/* Create a queue. */
struct cmdq_list *
cmdq_new(void)
{
struct cmdq_list *queue;
queue = xcalloc(1, sizeof *queue);
TAILQ_INIT (&queue->list);
return (queue);
}
/* Free a queue. */
void
cmdq_free(struct cmdq_list *queue)
{
if (!TAILQ_EMPTY(&queue->list))
fatalx("queue not empty");
free(queue);
}
/* Get item name. */
const char *
cmdq_get_name(struct cmdq_item *item)
{
return (item->name);
}
/* Get item client. */
struct client *
cmdq_get_client(struct cmdq_item *item)
{
return (item->client);
}
/* Get item target client. */
struct client *
cmdq_get_target_client(struct cmdq_item *item)
{
return (item->target_client);
}
/* Get item state. */
struct cmdq_state *
cmdq_get_state(struct cmdq_item *item)
{
return (item->state);
}
/* Get item target. */
struct cmd_find_state *
cmdq_get_target(struct cmdq_item *item)
{
return (&item->target);
}
/* Get item source. */
struct cmd_find_state *
cmdq_get_source(struct cmdq_item *item)
{
return (&item->source);
}
/* Get state event. */
struct key_event *
cmdq_get_event(struct cmdq_item *item)
{
return (&item->state->event);
}
/* Get state current target. */
struct cmd_find_state *
cmdq_get_current(struct cmdq_item *item)
{
return (&item->state->current);
}
/* Get state flags. */
int
cmdq_get_flags(struct cmdq_item *item)
{
return (item->state->flags);
}
/* Create a new state. */
struct cmdq_state *
cmdq_new_state(struct cmd_find_state *current, struct key_event *event,
int flags)
{
struct cmdq_state *state;
state = xcalloc(1, sizeof *state);
state->references = 1;
state->flags = flags;
if (event != NULL)
memcpy(&state->event, event, sizeof state->event);
else
state->event.key = KEYC_NONE;
if (current != NULL && cmd_find_valid_state(current))
cmd_find_copy_state(&state->current, current);
else
cmd_find_clear_state(&state->current, 0);
return (state);
}
/* Add a reference to a state. */
struct cmdq_state *
cmdq_link_state(struct cmdq_state *state)
{
state->references++;
return (state);
}
/* Make a copy of a state. */
struct cmdq_state *
cmdq_copy_state(struct cmdq_state *state, struct cmd_find_state *current)
{
if (current != NULL)
return (cmdq_new_state(current, &state->event, state->flags));
return (cmdq_new_state(&state->current, &state->event, state->flags));
}
/* Free a state. */
void
cmdq_free_state(struct cmdq_state *state)
{
if (--state->references != 0)
return;
if (state->formats != NULL)
format_free(state->formats);
free(state);
}
/* Add a format to command queue. */
void
cmdq_add_format(struct cmdq_state *state, const char *key, const char *fmt, ...)
{
va_list ap;
char *value;
va_start(ap, fmt);
xvasprintf(&value, fmt, ap);
va_end(ap);
if (state->formats == NULL)
state->formats = format_create(NULL, NULL, FORMAT_NONE, 0);
format_add(state->formats, key, "%s", value);
free(value);
}
/* Add formats to command queue. */
void
cmdq_add_formats(struct cmdq_state *state, struct format_tree *ft)
{
if (state->formats == NULL)
state->formats = format_create(NULL, NULL, FORMAT_NONE, 0);
format_merge(state->formats, ft);
}
/* Merge formats from item. */
void
cmdq_merge_formats(struct cmdq_item *item, struct format_tree *ft)
{
const struct cmd_entry *entry;
if (item->cmd != NULL) {
entry = cmd_get_entry(item->cmd);
format_add(ft, "command", "%s", entry->name);
}
if (item->state->formats != NULL)
format_merge(ft, item->state->formats);
} }
/* Append an item. */ /* Append an item. */
@@ -312,12 +68,12 @@ cmdq_append(struct client *c, struct cmdq_item *item)
item->client = c; item->client = c;
item->queue = queue; item->queue = queue;
TAILQ_INSERT_TAIL(&queue->list, item, entry); TAILQ_INSERT_TAIL(queue, item, entry);
log_debug("%s %s: %s", __func__, cmdq_name(c), item->name); log_debug("%s %s: %s", __func__, cmdq_name(c), item->name);
item = next; item = next;
} while (item != NULL); } while (item != NULL);
return (TAILQ_LAST(&queue->list, cmdq_item_list)); return (TAILQ_LAST(queue, cmdq_list));
} }
/* Insert an item. */ /* Insert an item. */
@@ -338,7 +94,7 @@ cmdq_insert_after(struct cmdq_item *after, struct cmdq_item *item)
item->client = c; item->client = c;
item->queue = queue; item->queue = queue;
TAILQ_INSERT_AFTER(&queue->list, after, item, entry); TAILQ_INSERT_AFTER(queue, after, item, entry);
log_debug("%s %s: %s after %s", __func__, cmdq_name(c), log_debug("%s %s: %s after %s", __func__, cmdq_name(c),
item->name, after->name); item->name, after->name);
@@ -351,25 +107,17 @@ cmdq_insert_after(struct cmdq_item *after, struct cmdq_item *item)
/* Insert a hook. */ /* Insert a hook. */
void void
cmdq_insert_hook(struct session *s, struct cmdq_item *item, cmdq_insert_hook(struct session *s, struct cmdq_item *item,
struct cmd_find_state *current, const char *fmt, ...) struct cmd_find_state *fs, const char *fmt, ...)
{ {
struct cmdq_state *state = item->state;
struct cmd *cmd = item->cmd;
struct args *args = cmd_get_args(cmd);
struct args_entry *ae;
struct args_value *av;
struct options *oo; struct options *oo;
va_list ap; va_list ap;
char *name, tmp[32], flag, *arguments; char *name;
u_int i;
const char *value;
struct cmdq_item *new_item; struct cmdq_item *new_item;
struct cmdq_state *new_state;
struct options_entry *o; struct options_entry *o;
struct options_array_item *a; struct options_array_item *a;
struct cmd_list *cmdlist; struct cmd_list *cmdlist;
if (item->state->flags & CMDQ_STATE_NOHOOKS) if (item->flags & CMDQ_NOHOOKS)
return; return;
if (s == NULL) if (s == NULL)
oo = global_s_options; oo = global_s_options;
@@ -387,58 +135,24 @@ cmdq_insert_hook(struct session *s, struct cmdq_item *item,
} }
log_debug("running hook %s (parent %p)", name, item); log_debug("running hook %s (parent %p)", name, item);
/*
* The hooks get a new state because they should not update the current
* target or formats for any subsequent commands.
*/
new_state = cmdq_new_state(current, &state->event, CMDQ_STATE_NOHOOKS);
cmdq_add_format(new_state, "hook", "%s", name);
arguments = args_print(args);
cmdq_add_format(new_state, "hook_arguments", "%s", arguments);
free(arguments);
for (i = 0; i < args_count(args); i++) {
xsnprintf(tmp, sizeof tmp, "hook_argument_%d", i);
cmdq_add_format(new_state, tmp, "%s", args_string(args, i));
}
flag = args_first(args, &ae);
while (flag != 0) {
value = args_get(args, flag);
if (value == NULL) {
xsnprintf(tmp, sizeof tmp, "hook_flag_%c", flag);
cmdq_add_format(new_state, tmp, "1");
} else {
xsnprintf(tmp, sizeof tmp, "hook_flag_%c", flag);
cmdq_add_format(new_state, tmp, "%s", value);
}
i = 0;
av = args_first_value(args, flag);
while (av != NULL) {
xsnprintf(tmp, sizeof tmp, "hook_flag_%c_%d", flag, i);
cmdq_add_format(new_state, tmp, "%s", av->string);
i++;
av = args_next_value(av);
}
flag = args_next(&ae);
}
a = options_array_first(o); a = options_array_first(o);
while (a != NULL) { while (a != NULL) {
cmdlist = options_array_item_value(a)->cmdlist; cmdlist = options_array_item_value(a)->cmdlist;
if (cmdlist != NULL) { if (cmdlist == NULL) {
new_item = cmdq_get_command(cmdlist, new_state); a = options_array_next(a);
if (item != NULL) continue;
item = cmdq_insert_after(item, new_item);
else
item = cmdq_append(NULL, new_item);
} }
new_item = cmdq_get_command(cmdlist, fs, NULL, CMDQ_NOHOOKS);
cmdq_format(new_item, "hook", "%s", name);
if (item != NULL)
item = cmdq_insert_after(item, new_item);
else
item = cmdq_append(NULL, new_item);
a = options_array_next(a); a = options_array_next(a);
} }
cmdq_free_state(new_state);
free(name); free(name);
} }
@@ -453,13 +167,19 @@ cmdq_continue(struct cmdq_item *item)
static void static void
cmdq_remove(struct cmdq_item *item) cmdq_remove(struct cmdq_item *item)
{ {
if (item->shared != NULL && --item->shared->references == 0) {
if (item->shared->formats != NULL)
format_free(item->shared->formats);
free(item->shared);
}
if (item->client != NULL) if (item->client != NULL)
server_client_unref(item->client); server_client_unref(item->client);
if (item->cmdlist != NULL) if (item->cmdlist != NULL)
cmd_list_free(item->cmdlist); cmd_list_free(item->cmdlist);
cmdq_free_state(item->state);
TAILQ_REMOVE(&item->queue->list, item, entry); TAILQ_REMOVE(item->queue, item, entry);
free(item->name); free(item->name);
free(item); free(item);
@@ -482,57 +202,50 @@ cmdq_remove_group(struct cmdq_item *item)
} }
} }
/* Empty command callback. */
static enum cmd_retval
cmdq_empty_command(__unused struct cmdq_item *item, __unused void *data)
{
return (CMD_RETURN_NORMAL);
}
/* Get a command for the command queue. */ /* Get a command for the command queue. */
struct cmdq_item * struct cmdq_item *
cmdq_get_command(struct cmd_list *cmdlist, struct cmdq_state *state) cmdq_get_command(struct cmd_list *cmdlist, struct cmd_find_state *current,
struct mouse_event *m, int flags)
{ {
struct cmdq_item *item, *first = NULL, *last = NULL; struct cmdq_item *item, *first = NULL, *last = NULL;
struct cmd *cmd; struct cmd *cmd;
const struct cmd_entry *entry; struct cmdq_shared *shared = NULL;
int created = 0; u_int group = 0;
if ((cmd = cmd_list_first(cmdlist)) == NULL) TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
return (cmdq_get_callback(cmdq_empty_command, NULL)); if (cmd->group != group) {
shared = xcalloc(1, sizeof *shared);
if (state == NULL) { if (current != NULL)
state = cmdq_new_state(NULL, NULL, 0); cmd_find_copy_state(&shared->current, current);
created = 1; else
} cmd_find_clear_state(&shared->current, 0);
if (m != NULL)
while (cmd != NULL) { memcpy(&shared->mouse, m, sizeof shared->mouse);
entry = cmd_get_entry(cmd); group = cmd->group;
}
item = xcalloc(1, sizeof *item); item = xcalloc(1, sizeof *item);
xasprintf(&item->name, "[%s/%p]", entry->name, item); xasprintf(&item->name, "[%s/%p]", cmd->entry->name, item);
item->type = CMDQ_COMMAND; item->type = CMDQ_COMMAND;
item->group = cmd_get_group(cmd); item->group = cmd->group;
item->state = cmdq_link_state(state); item->flags = flags;
item->shared = shared;
item->cmdlist = cmdlist; item->cmdlist = cmdlist;
item->cmd = cmd; item->cmd = cmd;
cmdlist->references++;
log_debug("%s: %s group %u", __func__, item->name, item->group); log_debug("%s: %s group %u", __func__, item->name, item->group);
shared->references++;
cmdlist->references++;
if (first == NULL) if (first == NULL)
first = item; first = item;
if (last != NULL) if (last != NULL)
last->next = item; last->next = item;
last = item; last = item;
cmd = cmd_list_next(cmd);
} }
if (created)
cmdq_free_state(state);
return (first); return (first);
} }
@@ -544,11 +257,11 @@ cmdq_find_flag(struct cmdq_item *item, struct cmd_find_state *fs,
const char *value; const char *value;
if (flag->flag == 0) { if (flag->flag == 0) {
cmd_find_from_client(fs, item->target_client, 0); cmd_find_clear_state(fs, 0);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
value = args_get(cmd_get_args(item->cmd), flag->flag); value = args_get(item->cmd->args, flag->flag);
if (cmd_find_target(fs, item, value, flag->type, flag->flags) != 0) { if (cmd_find_target(fs, item, value, flag->type, flag->flags) != 0) {
cmd_find_clear_state(fs, 0); cmd_find_clear_state(fs, 0);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
@@ -556,89 +269,31 @@ cmdq_find_flag(struct cmdq_item *item, struct cmd_find_state *fs,
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
/* Add message with command. */
static void
cmdq_add_message(struct cmdq_item *item)
{
struct client *c = item->client;
struct cmdq_state *state = item->state;
const char *key;
char *tmp;
uid_t uid;
struct passwd *pw;
char *user = NULL;
tmp = cmd_print(item->cmd);
if (c != NULL) {
uid = proc_get_peer_uid(c->peer);
if (uid != (uid_t)-1 && uid != getuid()) {
if ((pw = getpwuid(uid)) != NULL)
xasprintf(&user, "[%s]", pw->pw_name);
else
user = xstrdup("[unknown]");
} else
user = xstrdup("");
if (c->session != NULL && state->event.key != KEYC_NONE) {
key = key_string_lookup_key(state->event.key, 0);
server_add_message("%s%s key %s: %s", c->name, user,
key, tmp);
} else {
server_add_message("%s%s command: %s", c->name, user,
tmp);
}
free(user);
} else
server_add_message("command: %s", tmp);
free(tmp);
}
/* Fire command on command queue. */ /* Fire command on command queue. */
static enum cmd_retval static enum cmd_retval
cmdq_fire_command(struct cmdq_item *item) cmdq_fire_command(struct cmdq_item *item)
{ {
const char *name = cmdq_name(item->client); struct client *c = item->client;
struct cmdq_state *state = item->state; const char *name = cmdq_name(c);
struct cmdq_shared *shared = item->shared;
struct cmd *cmd = item->cmd; struct cmd *cmd = item->cmd;
struct args *args = cmd_get_args(cmd); const struct cmd_entry *entry = cmd->entry;
const struct cmd_entry *entry = cmd_get_entry(cmd);
struct client *tc, *saved = item->client;
enum cmd_retval retval; enum cmd_retval retval;
struct cmd_find_state *fsp, fs; struct cmd_find_state *fsp, fs;
int flags, quiet = 0; int flags;
char *tmp; char *tmp;
if (cfg_finished)
cmdq_add_message(item);
if (log_get_level() > 1) { if (log_get_level() > 1) {
tmp = cmd_print(cmd); tmp = cmd_print(cmd);
log_debug("%s %s: (%u) %s", __func__, name, item->group, tmp); log_debug("%s %s: (%u) %s", __func__, name, item->group, tmp);
free(tmp); free(tmp);
} }
flags = !!(state->flags & CMDQ_STATE_CONTROL); flags = !!(shared->flags & CMDQ_SHARED_CONTROL);
cmdq_guard(item, "begin", flags); cmdq_guard(item, "begin", flags);
if (item->client == NULL) if (item->client == NULL)
item->client = cmd_find_client(item, NULL, 1); item->client = cmd_find_client(item, NULL, 1);
if (entry->flags & CMD_CLIENT_CANFAIL)
quiet = 1;
if (entry->flags & CMD_CLIENT_CFLAG) {
tc = cmd_find_client(item, args_get(args, 'c'), quiet);
if (tc == NULL && !quiet) {
retval = CMD_RETURN_ERROR;
goto out;
}
} else if (entry->flags & CMD_CLIENT_TFLAG) {
tc = cmd_find_client(item, args_get(args, 't'), quiet);
if (tc == NULL && !quiet) {
retval = CMD_RETURN_ERROR;
goto out;
}
} else
tc = cmd_find_client(item, NULL, 1);
item->target_client = tc;
retval = cmdq_find_flag(item, &item->source, &entry->source); retval = cmdq_find_flag(item, &item->source, &entry->source);
if (retval == CMD_RETURN_ERROR) if (retval == CMD_RETURN_ERROR)
goto out; goto out;
@@ -653,8 +308,8 @@ cmdq_fire_command(struct cmdq_item *item)
if (entry->flags & CMD_AFTERHOOK) { if (entry->flags & CMD_AFTERHOOK) {
if (cmd_find_valid_state(&item->target)) if (cmd_find_valid_state(&item->target))
fsp = &item->target; fsp = &item->target;
else if (cmd_find_valid_state(&item->state->current)) else if (cmd_find_valid_state(&item->shared->current))
fsp = &item->state->current; fsp = &item->shared->current;
else if (cmd_find_from_client(&fs, item->client, 0) == 0) else if (cmd_find_from_client(&fs, item->client, 0) == 0)
fsp = &fs; fsp = &fs;
else else
@@ -663,19 +318,10 @@ cmdq_fire_command(struct cmdq_item *item)
} }
out: out:
item->client = saved; item->client = c;
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);
} }
@@ -691,7 +337,7 @@ cmdq_get_callback1(const char *name, cmdq_cb cb, void *data)
item->type = CMDQ_CALLBACK; item->type = CMDQ_CALLBACK;
item->group = 0; item->group = 0;
item->state = cmdq_new_state(NULL, NULL, 0); item->flags = 0;
item->cb = cb; item->cb = cb;
item->data = data; item->data = data;
@@ -725,6 +371,25 @@ cmdq_fire_callback(struct cmdq_item *item)
return (item->cb(item, item->data)); return (item->cb(item, item->data));
} }
/* Add a format to command queue. */
void
cmdq_format(struct cmdq_item *item, const char *key, const char *fmt, ...)
{
struct cmdq_shared *shared = item->shared;
va_list ap;
char *value;
va_start(ap, fmt);
xvasprintf(&value, fmt, ap);
va_end(ap);
if (shared->formats == NULL)
shared->formats = format_create(NULL, NULL, FORMAT_NONE, 0);
format_add(shared->formats, key, "%s", value);
free(value);
}
/* Process next item on command queue. */ /* Process next item on command queue. */
u_int u_int
cmdq_next(struct client *c) cmdq_next(struct client *c)
@@ -736,18 +401,18 @@ cmdq_next(struct client *c)
u_int items = 0; u_int items = 0;
static u_int number; static u_int number;
if (TAILQ_EMPTY(&queue->list)) { if (TAILQ_EMPTY(queue)) {
log_debug("%s %s: empty", __func__, name); log_debug("%s %s: empty", __func__, name);
return (0); return (0);
} }
if (TAILQ_FIRST(&queue->list)->flags & CMDQ_WAITING) { if (TAILQ_FIRST(queue)->flags & CMDQ_WAITING) {
log_debug("%s %s: waiting", __func__, name); log_debug("%s %s: waiting", __func__, name);
return (0); return (0);
} }
log_debug("%s %s: enter", __func__, name); log_debug("%s %s: enter", __func__, name);
for (;;) { for (;;) {
item = queue->item = TAILQ_FIRST(&queue->list); item = TAILQ_FIRST(queue);
if (item == NULL) if (item == NULL)
break; break;
log_debug("%s %s: %s (%d), flags %x", __func__, name, log_debug("%s %s: %s (%d), flags %x", __func__, name,
@@ -797,7 +462,6 @@ cmdq_next(struct client *c)
} }
cmdq_remove(item); cmdq_remove(item);
} }
queue->item = NULL;
log_debug("%s %s: exit (empty)", __func__, name); log_debug("%s %s: exit (empty)", __func__, name);
return (items); return (items);
@@ -807,19 +471,6 @@ waiting:
return (items); return (items);
} }
/* Get running item if any. */
struct cmdq_item *
cmdq_running(struct client *c)
{
struct cmdq_list *queue = cmdq_get(c);
if (queue->item == NULL)
return (NULL);
if (queue->item->flags & CMDQ_WAITING)
return (NULL);
return (queue->item);
}
/* Print a guard line. */ /* Print a guard line. */
void void
cmdq_guard(struct cmdq_item *item, const char *guard, int flags) cmdq_guard(struct cmdq_item *item, const char *guard, int flags)
@@ -829,33 +480,43 @@ cmdq_guard(struct cmdq_item *item, const char *guard, int flags)
u_int number = item->number; u_int number = item->number;
if (c != NULL && (c->flags & CLIENT_CONTROL)) if (c != NULL && (c->flags & CLIENT_CONTROL))
control_write(c, "%%%s %ld %u %d", guard, t, number, flags); file_print(c, "%%%s %ld %u %d\n", 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);
}
file_print(c, "%s\n", msg);
} else {
wp = c->session->curw->window->active;
wme = TAILQ_FIRST(&wp->modes);
if (wme == NULL || wme->mode != &window_view_mode)
window_pane_set_mode(wp, &window_view_mode, NULL, NULL);
window_copy_add(wp, "%s", msg);
}
free(msg);
} }
/* Show error from command. */ /* Show error from command. */
@@ -865,9 +526,8 @@ cmdq_error(struct cmdq_item *item, const char *fmt, ...)
struct client *c = item->client; struct client *c = item->client;
struct cmd *cmd = item->cmd; struct cmd *cmd = item->cmd;
va_list ap; va_list ap;
char *msg, *tmp; char *msg;
const char *file; char *tmp;
u_int line;
va_start(ap, fmt); va_start(ap, fmt);
xvasprintf(&msg, fmt, ap); xvasprintf(&msg, fmt, ap);
@@ -875,24 +535,22 @@ cmdq_error(struct cmdq_item *item, const char *fmt, ...)
log_debug("%s: %s", __func__, msg); log_debug("%s: %s", __func__, msg);
if (c == NULL) { if (c == NULL)
cmd_get_source(cmd, &file, &line); cfg_add_cause("%s:%u: %s", cmd->file, cmd->line, msg);
cfg_add_cause("%s:%u: %s", file, line, msg); else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {
} else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {
server_add_message("%s message: %s", c->name, msg);
if (~c->flags & CLIENT_UTF8) { if (~c->flags & CLIENT_UTF8) {
tmp = msg; tmp = msg;
msg = utf8_sanitize(tmp); msg = utf8_sanitize(tmp);
free(tmp); free(tmp);
} }
if (c->flags & CLIENT_CONTROL) if (c->flags & CLIENT_CONTROL)
control_write(c, "%s", msg); file_print(c, "%s\n", msg);
else else
file_error(c, "%s\n", msg); file_error(c, "%s\n", msg);
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, "%s", msg);
} }
free(msg); free(msg);

View File

@@ -34,204 +34,28 @@ 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 = { "cC:DF:lLRSt:U", 0, 1 },
.usage = "[-cDlLRSU] [-A pane:state] [-B name:what:format] " .usage = "[-cDlLRSU] [-C XxY] [-F flags] " CMD_TARGET_CLIENT_USAGE
"[-C XxY] [-f flags] [-r pane:report] " CMD_TARGET_CLIENT_USAGE " [adjustment]",
" [adjustment]",
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG, .flags = CMD_AFTERHOOK,
.exec = cmd_refresh_client_exec .exec = cmd_refresh_client_exec
}; };
static void
cmd_refresh_client_update_subscription(struct client *tc, const char *value)
{
char *copy, *split, *name, *what;
enum control_sub_type subtype;
int subid = -1;
copy = name = xstrdup(value);
if ((split = strchr(copy, ':')) == NULL) {
control_remove_sub(tc, copy);
goto out;
}
*split++ = '\0';
what = split;
if ((split = strchr(what, ':')) == NULL)
goto out;
*split++ = '\0';
if (strcmp(what, "%*") == 0)
subtype = CONTROL_SUB_ALL_PANES;
else if (sscanf(what, "%%%d", &subid) == 1 && subid >= 0)
subtype = CONTROL_SUB_PANE;
else if (strcmp(what, "@*") == 0)
subtype = CONTROL_SUB_ALL_WINDOWS;
else if (sscanf(what, "@%d", &subid) == 1 && subid >= 0)
subtype = CONTROL_SUB_WINDOW;
else
subtype = CONTROL_SUB_SESSION;
control_add_sub(tc, name, subtype, subid, split);
out:
free(copy);
}
static enum cmd_retval
cmd_refresh_client_control_client_size(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct client *tc = cmdq_get_target_client(item);
const char *size = args_get(args, 'C');
u_int w, x, y;
struct client_window *cw;
if (sscanf(size, "@%u:%ux%u", &w, &x, &y) == 3) {
if (x < WINDOW_MINIMUM || x > WINDOW_MAXIMUM ||
y < WINDOW_MINIMUM || y > WINDOW_MAXIMUM) {
cmdq_error(item, "size too small or too big");
return (CMD_RETURN_ERROR);
}
log_debug("%s: client %s window @%u: size %ux%u", __func__,
tc->name, w, x, y);
cw = server_client_add_client_window(tc, w);
cw->sx = x;
cw->sy = y;
tc->flags |= CLIENT_WINDOWSIZECHANGED;
recalculate_sizes_now(1);
return (CMD_RETURN_NORMAL);
}
if (sscanf(size, "@%u:", &w) == 1) {
cw = server_client_get_client_window(tc, w);
if (cw != NULL) {
log_debug("%s: client %s window @%u: no size", __func__,
tc->name, w);
cw->sx = 0;
cw->sy = 0;
recalculate_sizes_now(1);
}
return (CMD_RETURN_NORMAL);
}
if (sscanf(size, "%u,%u", &x, &y) != 2 &&
sscanf(size, "%ux%u", &x, &y) != 2) {
cmdq_error(item, "bad size argument");
return (CMD_RETURN_ERROR);
}
if (x < WINDOW_MINIMUM || x > WINDOW_MAXIMUM ||
y < WINDOW_MINIMUM || y > WINDOW_MAXIMUM) {
cmdq_error(item, "size too small or too big");
return (CMD_RETURN_ERROR);
}
tty_set_size(&tc->tty, x, y, 0, 0);
tc->flags |= CLIENT_SIZECHANGED;
recalculate_sizes_now(1);
return (CMD_RETURN_NORMAL);
}
static void
cmd_refresh_client_update_offset(struct client *tc, const char *value)
{
struct window_pane *wp;
char *copy, *split;
u_int pane;
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;
if (strcmp(split, "on") == 0)
control_set_pane_on(tc, wp);
else if (strcmp(split, "off") == 0)
control_set_pane_off(tc, wp);
else if (strcmp(split, "continue") == 0)
control_continue_pane(tc, wp);
else if (strcmp(split, "pause") == 0)
control_pause_pane(tc, wp);
out:
free(copy);
}
static enum cmd_retval
cmd_refresh_client_clipboard(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct client *tc = cmdq_get_target_client(item);
const char *p;
u_int i;
struct cmd_find_state fs;
p = args_get(args, 'l');
if (p == NULL) {
if (tc->flags & CLIENT_CLIPBOARDBUFFER)
return (CMD_RETURN_NORMAL);
tc->flags |= CLIENT_CLIPBOARDBUFFER;
} else {
if (cmd_find_target(&fs, item, p, CMD_FIND_PANE, 0) != 0)
return (CMD_RETURN_ERROR);
for (i = 0; i < tc->clipboard_npanes; i++) {
if (tc->clipboard_panes[i] == fs.wp->id)
break;
}
if (i != tc->clipboard_npanes)
return (CMD_RETURN_NORMAL);
tc->clipboard_panes = xreallocarray(tc->clipboard_panes,
tc->clipboard_npanes + 1, sizeof *tc->clipboard_panes);
tc->clipboard_panes[tc->clipboard_npanes++] = fs.wp->id;
}
tty_clipboard_query(&tc->tty);
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)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct client *tc = cmdq_get_target_client(item); struct client *c;
struct tty *tty = &tc->tty; struct tty *tty;
struct window *w; struct window *w;
const char *errstr; const char *size, *errstr;
u_int adjust; char *copy, *next, *s;
struct args_value *av; u_int x, y, adjust;
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
tty = &c->tty;
if (args_has(args, 'c') || if (args_has(args, 'c') ||
args_has(args, 'L') || args_has(args, 'L') ||
@@ -239,11 +63,10 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
args_has(args, 'U') || args_has(args, 'U') ||
args_has(args, 'D')) args_has(args, 'D'))
{ {
if (args_count(args) == 0) if (args->argc == 0)
adjust = 1; adjust = 1;
else { else {
adjust = strtonum(args_string(args, 0), 1, INT_MAX, adjust = strtonum(args->argv[0], 1, INT_MAX, &errstr);
&errstr);
if (errstr != NULL) { if (errstr != NULL) {
cmdq_error(item, "adjustment %s", errstr); cmdq_error(item, "adjustment %s", errstr);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
@@ -251,85 +74,88 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
} }
if (args_has(args, 'c')) if (args_has(args, 'c'))
tc->pan_window = NULL; c->pan_window = NULL;
else { else {
w = tc->session->curw->window; w = c->session->curw->window;
if (tc->pan_window != w) { if (c->pan_window != w) {
tc->pan_window = w; c->pan_window = w;
tc->pan_ox = tty->oox; c->pan_ox = tty->oox;
tc->pan_oy = tty->ooy; c->pan_oy = tty->ooy;
} }
if (args_has(args, 'L')) { if (args_has(args, 'L')) {
if (tc->pan_ox > adjust) if (c->pan_ox > adjust)
tc->pan_ox -= adjust; c->pan_ox -= adjust;
else else
tc->pan_ox = 0; c->pan_ox = 0;
} else if (args_has(args, 'R')) { } else if (args_has(args, 'R')) {
tc->pan_ox += adjust; c->pan_ox += adjust;
if (tc->pan_ox > w->sx - tty->osx) if (c->pan_ox > w->sx - tty->osx)
tc->pan_ox = w->sx - tty->osx; c->pan_ox = w->sx - tty->osx;
} else if (args_has(args, 'U')) { } else if (args_has(args, 'U')) {
if (tc->pan_oy > adjust) if (c->pan_oy > adjust)
tc->pan_oy -= adjust; c->pan_oy -= adjust;
else else
tc->pan_oy = 0; c->pan_oy = 0;
} else if (args_has(args, 'D')) { } else if (args_has(args, 'D')) {
tc->pan_oy += adjust; c->pan_oy += adjust;
if (tc->pan_oy > w->sy - tty->osy) if (c->pan_oy > w->sy - tty->osy)
tc->pan_oy = w->sy - tty->osy; c->pan_oy = w->sy - tty->osy;
} }
} }
tty_update_client_offset(tc); tty_update_client_offset(c);
server_redraw_client(tc); server_redraw_client(c);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (args_has(args, 'l')) if (args_has(args, 'l')) {
return (cmd_refresh_client_clipboard(self, item)); if (c->session != NULL)
tty_putcode_ptr2(&c->tty, TTYC_MS, "", "?");
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'F')) /* -F is an alias for -f */ if (args_has(args, 'C') || args_has(args, 'F')) {
server_client_set_flags(tc, args_get(args, 'F')); if (args_has(args, 'C')) {
if (args_has(args, 'f')) if (!(c->flags & CLIENT_CONTROL)) {
server_client_set_flags(tc, args_get(args, 'f')); cmdq_error(item, "not a control client");
if (args_has(args, 'r')) return (CMD_RETURN_ERROR);
cmd_refresh_report(tty, args_get(args, 'r')); }
size = args_get(args, 'C');
if (args_has(args, 'A')) { if (sscanf(size, "%u,%u", &x, &y) != 2 &&
if (~tc->flags & CLIENT_CONTROL) sscanf(size, "%ux%u", &x, &y) != 2) {
goto not_control_client; cmdq_error(item, "bad size argument");
av = args_first_value(args, 'A'); return (CMD_RETURN_ERROR);
while (av != NULL) { }
cmd_refresh_client_update_offset(tc, av->string); if (x < WINDOW_MINIMUM || x > WINDOW_MAXIMUM ||
av = args_next_value(av); y < WINDOW_MINIMUM || y > WINDOW_MAXIMUM) {
cmdq_error(item, "size too small or too big");
return (CMD_RETURN_ERROR);
}
tty_set_size(&c->tty, x, y, 0, 0);
c->flags |= CLIENT_SIZECHANGED;
recalculate_sizes();
}
if (args_has(args, 'F')) {
if (!(c->flags & CLIENT_CONTROL)) {
cmdq_error(item, "not a control client");
return (CMD_RETURN_ERROR);
}
s = copy = xstrdup(args_get(args, 'F'));
while ((next = strsep(&s, ",")) != NULL) {
/* Unknown flags are ignored. */
if (strcmp(next, "no-output") == 0)
c->flags |= CLIENT_CONTROL_NOOUTPUT;
}
free(copy);
} }
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (args_has(args, 'B')) {
if (~tc->flags & CLIENT_CONTROL)
goto not_control_client;
av = args_first_value(args, 'B');
while (av != NULL) {
cmd_refresh_client_update_subscription(tc, av->string);
av = args_next_value(av);
}
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'C')) {
if (~tc->flags & CLIENT_CONTROL)
goto not_control_client;
return (cmd_refresh_client_control_client_size(self, item));
}
if (args_has(args, 'S')) { if (args_has(args, 'S')) {
tc->flags |= CLIENT_STATUSFORCE; c->flags |= CLIENT_STATUSFORCE;
server_status_client(tc); server_status_client(c);
} else { } else {
tc->flags |= CLIENT_STATUSFORCE; c->flags |= CLIENT_STATUSFORCE;
server_redraw_client(tc); server_redraw_client(c);
} }
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
not_control_client:
cmdq_error(item, "not a control client");
return (CMD_RETURN_ERROR);
} }

View File

@@ -34,7 +34,7 @@ const struct cmd_entry cmd_rename_session_entry = {
.name = "rename-session", .name = "rename-session",
.alias = "rename", .alias = "rename",
.args = { "t:", 1, 1, NULL }, .args = { "t:", 1, 1 },
.usage = CMD_TARGET_SESSION_USAGE " new-name", .usage = CMD_TARGET_SESSION_USAGE " new-name",
.target = { 't', CMD_FIND_SESSION, 0 }, .target = { 't', CMD_FIND_SESSION, 0 },
@@ -46,23 +46,22 @@ const struct cmd_entry cmd_rename_session_entry = {
static enum cmd_retval static enum cmd_retval
cmd_rename_session_exec(struct cmd *self, struct cmdq_item *item) cmd_rename_session_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item); struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = target->s; struct session *s = item->target.s;
char *newname, *tmp; char *newname;
tmp = format_single_from_target(item, args_string(args, 0)); newname = format_single(item, args->argv[0], c, s, NULL, NULL);
newname = session_check_name(tmp);
if (newname == NULL) {
cmdq_error(item, "invalid session: %s", tmp);
free(tmp);
return (CMD_RETURN_ERROR);
}
free(tmp);
if (strcmp(newname, s->name) == 0) { if (strcmp(newname, s->name) == 0) {
free(newname); free(newname);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (!session_check_name(newname)) {
cmdq_error(item, "bad session name: %s", newname);
free(newname);
return (CMD_RETURN_ERROR);
}
if (session_find(newname) != NULL) { if (session_find(newname) != NULL) {
cmdq_error(item, "duplicate session: %s", newname); cmdq_error(item, "duplicate session: %s", newname);
free(newname); free(newname);

View File

@@ -33,7 +33,7 @@ const struct cmd_entry cmd_rename_window_entry = {
.name = "rename-window", .name = "rename-window",
.alias = "renamew", .alias = "renamew",
.args = { "t:", 1, 1, NULL }, .args = { "t:", 1, 1 },
.usage = CMD_TARGET_WINDOW_USAGE " new-name", .usage = CMD_TARGET_WINDOW_USAGE " new-name",
.target = { 't', CMD_FIND_WINDOW, 0 }, .target = { 't', CMD_FIND_WINDOW, 0 },
@@ -45,16 +45,16 @@ const struct cmd_entry cmd_rename_window_entry = {
static enum cmd_retval static enum cmd_retval
cmd_rename_window_exec(struct cmd *self, struct cmdq_item *item) cmd_rename_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item); struct client *c = cmd_find_client(item, NULL, 1);
struct winlink *wl = target->wl; struct session *s = item->target.s;
char *newname; struct winlink *wl = item->target.wl;
char *newname;
newname = format_single_from_target(item, args_string(args, 0)); newname = format_single(item, args->argv[0], c, s, wl, NULL);
window_set_name(wl->window, newname); window_set_name(wl->window, newname);
options_set_number(wl->window->options, "automatic-rename", 0); options_set_number(wl->window->options, "automatic-rename", 0);
server_redraw_window_borders(wl->window);
server_status_window(wl->window); server_status_window(wl->window);
free(newname); free(newname);

View File

@@ -36,8 +36,8 @@ const struct cmd_entry cmd_resize_pane_entry = {
.name = "resize-pane", .name = "resize-pane",
.alias = "resizep", .alias = "resizep",
.args = { "DLMRTt:Ux:y:Z", 0, 1, NULL }, .args = { "DLMRt:Ux:y:Z", 0, 1 },
.usage = "[-DLMRTUZ] [-x width] [-y height] " CMD_TARGET_PANE_USAGE " " .usage = "[-DLMRUZ] [-x width] [-y height] " CMD_TARGET_PANE_USAGE " "
"[adjustment]", "[adjustment]",
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
@@ -49,88 +49,102 @@ const struct cmd_entry cmd_resize_pane_entry = {
static enum cmd_retval static enum cmd_retval
cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item) cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item); struct cmdq_shared *shared = item->shared;
struct key_event *event = cmdq_get_event(item); struct window_pane *wp = item->target.wp;
struct window_pane *wp = target->wp; struct winlink *wl = item->target.wl;
struct winlink *wl = target->wl;
struct window *w = wl->window; struct window *w = wl->window;
struct client *c = cmdq_get_client(item); struct client *c = item->client;
struct session *s = target->s; struct session *s = item->target.s;
const char *errstr; const char *errstr, *p;
char *cause; char *cause, *copy;
u_int adjust; u_int adjust;
int x, y, status; int x, y, percentage;
struct grid *gd = wp->base.grid; size_t plen;
if (args_has(args, 'T')) {
if (!TAILQ_EMPTY(&wp->modes))
return (CMD_RETURN_NORMAL);
adjust = screen_size_y(&wp->base) - 1 - wp->base.cy;
if (adjust > gd->hsize)
adjust = gd->hsize;
grid_remove_history(gd, adjust);
wp->base.cy += adjust;
wp->flags |= PANE_REDRAW;
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'M')) { if (args_has(args, 'M')) {
if (!event->m.valid || cmd_mouse_window(&event->m, &s) == NULL) if (cmd_mouse_window(&shared->mouse, &s) == NULL)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
if (c == NULL || c->session != s) if (c == NULL || c->session != s)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
c->tty.mouse_drag_update = cmd_resize_pane_mouse_update; c->tty.mouse_drag_update = cmd_resize_pane_mouse_update;
cmd_resize_pane_mouse_update(c, &event->m); cmd_resize_pane_mouse_update(c, &shared->mouse);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
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);
server_status_window(w);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
server_unzoom_window(w); server_unzoom_window(w);
if (args_count(args) == 0) if (args->argc == 0)
adjust = 1; adjust = 1;
else { else {
adjust = strtonum(args_string(args, 0), 1, INT_MAX, &errstr); adjust = strtonum(args->argv[0], 1, INT_MAX, &errstr);
if (errstr != NULL) { if (errstr != NULL) {
cmdq_error(item, "adjustment %s", errstr); cmdq_error(item, "adjustment %s", errstr);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} }
if (args_has(args, 'x')) { if ((p = args_get(args, 'x')) != NULL) {
x = args_percentage(args, 'x', 0, INT_MAX, w->sx, &cause); plen = strlen(p);
if (cause != NULL) { if (p[plen - 1] == '%') {
cmdq_error(item, "width %s", cause); copy = xstrdup(p);
free(cause); copy[plen - 1] = '\0';
return (CMD_RETURN_ERROR); percentage = strtonum(copy, 0, INT_MAX, &errstr);
free(copy);
if (errstr != NULL) {
cmdq_error(item, "width %s", errstr);
return (CMD_RETURN_ERROR);
}
x = (w->sx * percentage) / 100;
if (x < PANE_MINIMUM)
x = PANE_MINIMUM;
if (x > INT_MAX)
x = INT_MAX;
} else {
x = args_strtonum(args, 'x', PANE_MINIMUM, INT_MAX,
&cause);
if (cause != NULL) {
cmdq_error(item, "width %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
} }
layout_resize_pane_to(wp, LAYOUT_LEFTRIGHT, x); layout_resize_pane_to(wp, LAYOUT_LEFTRIGHT, x);
} }
if (args_has(args, 'y')) { if ((p = args_get(args, 'y')) != NULL) {
y = args_percentage(args, 'y', 0, INT_MAX, w->sy, &cause); plen = strlen(p);
if (cause != NULL) { if (p[plen - 1] == '%') {
cmdq_error(item, "height %s", cause); copy = xstrdup(p);
free(cause); copy[plen - 1] = '\0';
return (CMD_RETURN_ERROR); percentage = strtonum(copy, 0, INT_MAX, &errstr);
free(copy);
if (errstr != NULL) {
cmdq_error(item, "height %s", errstr);
return (CMD_RETURN_ERROR);
}
y = (w->sy * percentage) / 100;
if (y < PANE_MINIMUM)
y = PANE_MINIMUM;
if (y > INT_MAX)
y = INT_MAX;
} }
status = options_get_number(w->options, "pane-border-status"); else {
switch (status) { y = args_strtonum(args, 'y', PANE_MINIMUM, INT_MAX,
case PANE_STATUS_TOP: &cause);
if (y != INT_MAX && wp->yoff == 1) if (cause != NULL) {
y++; cmdq_error(item, "height %s", cause);
break; free(cause);
case PANE_STATUS_BOTTOM: return (CMD_RETURN_ERROR);
if (y != INT_MAX && wp->yoff + wp->sy == w->sy - 1) }
y++;
break;
} }
layout_resize_pane_to(wp, LAYOUT_TOPBOTTOM, y); layout_resize_pane_to(wp, LAYOUT_TOPBOTTOM, y);
} }

View File

@@ -33,7 +33,7 @@ const struct cmd_entry cmd_resize_window_entry = {
.name = "resize-window", .name = "resize-window",
.alias = "resizew", .alias = "resizew",
.args = { "aADLRt:Ux:y:", 0, 1, NULL }, .args = { "aADLRt:Ux:y:", 0, 1 },
.usage = "[-aADLRU] [-x width] [-y height] " CMD_TARGET_WINDOW_USAGE " " .usage = "[-aADLRU] [-x width] [-y height] " CMD_TARGET_WINDOW_USAGE " "
"[adjustment]", "[adjustment]",
@@ -46,19 +46,19 @@ const struct cmd_entry cmd_resize_window_entry = {
static enum cmd_retval static enum cmd_retval
cmd_resize_window_exec(struct cmd *self, struct cmdq_item *item) cmd_resize_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item); struct winlink *wl = item->target.wl;
struct winlink *wl = target->wl;
struct window *w = wl->window; struct window *w = wl->window;
struct session *s = target->s; struct session *s = item->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->argc == 0)
adjust = 1; adjust = 1;
else { else {
adjust = strtonum(args_string(args, 0), 1, INT_MAX, &errstr); adjust = strtonum(args->argv[0], 1, INT_MAX, &errstr);
if (errstr != NULL) { if (errstr != NULL) {
cmdq_error(item, "adjustment %s", errstr); cmdq_error(item, "adjustment %s", errstr);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
@@ -107,9 +107,7 @@ cmd_resize_window_exec(struct cmd *self, struct cmdq_item *item)
} }
options_set_number(w->options, "window-size", WINDOW_SIZE_MANUAL); options_set_number(w->options, "window-size", WINDOW_SIZE_MANUAL);
w->manual_sx = sx; resize_window(w, sx, sy, xpixel, ypixel);
w->manual_sy = sy;
recalculate_size(w, 1);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@@ -34,9 +34,9 @@ const struct cmd_entry cmd_respawn_pane_entry = {
.name = "respawn-pane", .name = "respawn-pane",
.alias = "respawnp", .alias = "respawnp",
.args = { "c:e:kt:", 0, -1, NULL }, .args = { "c:e:kt:", 0, -1 },
.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 " [command]",
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
@@ -47,28 +47,32 @@ const struct cmd_entry cmd_respawn_pane_entry = {
static enum cmd_retval static enum cmd_retval
cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item) cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item); struct spawn_context sc;
struct spawn_context sc = { 0 }; struct session *s = item->target.s;
struct session *s = target->s; struct winlink *wl = item->target.wl;
struct winlink *wl = target->wl; struct window_pane *wp = item->target.wp;
struct window_pane *wp = target->wp;
char *cause = NULL; char *cause = NULL;
struct args_value *av; const char *add;
struct args_value *value;
memset(&sc, 0, sizeof sc);
sc.item = item; sc.item = item;
sc.s = s; sc.s = s;
sc.wl = wl; sc.wl = wl;
sc.wp0 = wp; sc.wp0 = wp;
sc.lc = NULL;
args_to_vector(args, &sc.argc, &sc.argv); sc.name = NULL;
sc.argc = args->argc;
sc.argv = args->argv;
sc.environ = environ_create(); sc.environ = environ_create();
av = args_first_value(args, 'e'); add = args_first_value(args, 'e', &value);
while (av != NULL) { while (add != NULL) {
environ_put(sc.environ, av->string, 0); environ_put(sc.environ, add);
av = args_next_value(av); add = args_next_value(&value);
} }
sc.idx = -1; sc.idx = -1;
@@ -81,18 +85,12 @@ cmd_respawn_pane_exec(struct cmd *self, struct cmdq_item *item)
if (spawn_pane(&sc, &cause) == NULL) { if (spawn_pane(&sc, &cause) == NULL) {
cmdq_error(item, "respawn pane failed: %s", cause); cmdq_error(item, "respawn pane failed: %s", cause);
free(cause); free(cause);
if (sc.argv != NULL)
cmd_free_argv(sc.argc, sc.argv);
environ_free(sc.environ);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
wp->flags |= PANE_REDRAW; wp->flags |= PANE_REDRAW;
server_redraw_window_borders(wp->window);
server_status_window(wp->window); server_status_window(wp->window);
if (sc.argv != NULL)
cmd_free_argv(sc.argc, sc.argv);
environ_free(sc.environ); environ_free(sc.environ);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@@ -34,9 +34,9 @@ const struct cmd_entry cmd_respawn_window_entry = {
.name = "respawn-window", .name = "respawn-window",
.alias = "respawnw", .alias = "respawnw",
.args = { "c:e:kt:", 0, -1, NULL }, .args = { "c:e:kt:", 0, -1 },
.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 " [command]",
.target = { 't', CMD_FIND_WINDOW, 0 }, .target = { 't', CMD_FIND_WINDOW, 0 },
@@ -47,27 +47,29 @@ const struct cmd_entry cmd_respawn_window_entry = {
static enum cmd_retval static enum cmd_retval
cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item) cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item); struct spawn_context sc;
struct spawn_context sc = { 0 }; struct session *s = item->target.s;
struct client *tc = cmdq_get_target_client(item); struct winlink *wl = item->target.wl;
struct session *s = target->s;
struct winlink *wl = target->wl;
char *cause = NULL; char *cause = NULL;
struct args_value *av; const char *add;
struct args_value *value;
memset(&sc, 0, sizeof sc);
sc.item = item; sc.item = item;
sc.s = s; sc.s = s;
sc.wl = wl; sc.wl = wl;
sc.tc = tc; sc.c = cmd_find_client(item, NULL, 1);
args_to_vector(args, &sc.argc, &sc.argv); sc.name = NULL;
sc.argc = args->argc;
sc.argv = args->argv;
sc.environ = environ_create(); sc.environ = environ_create();
av = args_first_value(args, 'e'); add = args_first_value(args, 'e', &value);
while (av != NULL) { while (add != NULL) {
environ_put(sc.environ, av->string, 0); environ_put(sc.environ, add);
av = args_next_value(av); add = args_next_value(&value);
} }
sc.idx = -1; sc.idx = -1;
@@ -80,16 +82,11 @@ cmd_respawn_window_exec(struct cmd *self, struct cmdq_item *item)
if (spawn_window(&sc, &cause) == NULL) { if (spawn_window(&sc, &cause) == NULL) {
cmdq_error(item, "respawn window failed: %s", cause); cmdq_error(item, "respawn window failed: %s", cause);
free(cause); free(cause);
if (sc.argv != NULL)
cmd_free_argv(sc.argc, sc.argv);
environ_free(sc.environ);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
server_redraw_window(wl->window); server_redraw_window(wl->window);
if (sc.argv != NULL)
cmd_free_argv(sc.argc, sc.argv);
environ_free(sc.environ); environ_free(sc.environ);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@@ -31,7 +31,7 @@ const struct cmd_entry cmd_rotate_window_entry = {
.name = "rotate-window", .name = "rotate-window",
.alias = "rotatew", .alias = "rotatew",
.args = { "Dt:UZ", 0, 0, NULL }, .args = { "Dt:UZ", 0, 0 },
.usage = "[-DUZ] " CMD_TARGET_WINDOW_USAGE, .usage = "[-DUZ] " CMD_TARGET_WINDOW_USAGE,
.target = { 't', CMD_FIND_WINDOW, 0 }, .target = { 't', CMD_FIND_WINDOW, 0 },
@@ -43,18 +43,16 @@ const struct cmd_entry cmd_rotate_window_entry = {
static enum cmd_retval static enum cmd_retval
cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item) cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct cmd_find_state *current = &item->shared->current;
struct cmd_find_state *current = cmdq_get_current(item); struct winlink *wl = item->target.wl;
struct cmd_find_state *target = cmdq_get_target(item);
struct winlink *wl = target->wl;
struct window *w = wl->window; struct window *w = wl->window;
struct window_pane *wp, *wp2; struct window_pane *wp, *wp2;
struct layout_cell *lc; struct layout_cell *lc;
u_int sx, sy, xoff, yoff; u_int sx, sy, xoff, yoff;
window_push_zoom(w, 0, args_has(args, 'Z')); window_push_zoom(w, args_has(self->args, 'Z'));
if (args_has(args, 'D')) { if (args_has(self->args, 'D')) {
wp = TAILQ_LAST(&w->panes, window_panes); wp = TAILQ_LAST(&w->panes, window_panes);
TAILQ_REMOVE(&w->panes, wp, entry); TAILQ_REMOVE(&w->panes, wp, entry);
TAILQ_INSERT_HEAD(&w->panes, wp, entry); TAILQ_INSERT_HEAD(&w->panes, wp, entry);

View File

@@ -20,7 +20,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <ctype.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -30,12 +29,8 @@
* Runs a command without a window. * Runs a command without a window.
*/ */
static enum args_parse_type cmd_run_shell_args_parse(struct args *, u_int, static enum cmd_retval cmd_run_shell_exec(struct cmd *, struct cmdq_item *);
char **);
static enum cmd_retval cmd_run_shell_exec(struct cmd *,
struct cmdq_item *);
static void cmd_run_shell_timer(int, short, void *);
static void cmd_run_shell_callback(struct job *); static void cmd_run_shell_callback(struct job *);
static void cmd_run_shell_free(void *); static void cmd_run_shell_free(void *);
static void cmd_run_shell_print(struct job *, const char *); static void cmd_run_shell_print(struct job *, const char *);
@@ -44,9 +39,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 = { "bt:", 1, 1 },
.usage = "[-bCE] [-c start-directory] [-d delay] " CMD_TARGET_PANE_USAGE .usage = "[-b] " CMD_TARGET_PANE_USAGE " shell-command",
" [shell-command]",
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL }, .target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
@@ -55,26 +49,11 @@ const struct cmd_entry cmd_run_shell_entry = {
}; };
struct cmd_run_shell_data { struct cmd_run_shell_data {
struct client *client; char *cmd;
char *cmd; struct cmdq_item *item;
struct args_command_state *state; int wp_id;
char *cwd;
struct cmdq_item *item;
struct session *s;
int wp_id;
struct event timer;
int flags;
}; };
static enum args_parse_type
cmd_run_shell_args_parse(struct args *args, __unused u_int idx,
__unused char **cause)
{
if (args_has(args, 'C'))
return (ARGS_PARSE_COMMANDS_OR_STRING);
return (ARGS_PARSE_STRING);
}
static void static void
cmd_run_shell_print(struct job *job, const char *msg) cmd_run_shell_print(struct job *job, const char *msg)
{ {
@@ -90,153 +69,63 @@ cmd_run_shell_print(struct job *job, const char *msg)
cmdq_print(cdata->item, "%s", msg); cmdq_print(cdata->item, "%s", msg);
return; return;
} }
if (cdata->item != NULL && cdata->client != NULL) if (cmd_find_from_nothing(&fs, 0) != 0)
wp = server_client_get_pane(cdata->client); return;
if (wp == NULL && cmd_find_from_nothing(&fs, 0) == 0) wp = fs.wp;
wp = fs.wp;
if (wp == NULL) if (wp == NULL)
return; 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)
window_pane_set_mode(wp, NULL, &window_view_mode, NULL, NULL); window_pane_set_mode(wp, &window_view_mode, NULL, NULL);
window_copy_add(wp, 1, "%s", msg); window_copy_add(wp, "%s", msg);
} }
static enum cmd_retval static enum cmd_retval
cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item) cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
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 *c = cmd_find_client(item, NULL, 1);
struct client *tc = cmdq_get_target_client(item); struct session *s = item->target.s;
struct session *s = target->s; struct winlink *wl = item->target.wl;
struct window_pane *wp = target->wp; struct window_pane *wp = item->target.wp;
const char *delay, *cmd;
double d;
struct timeval tv;
char *end;
int wait = !args_has(args, 'b');
if ((delay = args_get(args, 'd')) != NULL) {
d = strtod(delay, &end);
if (*end != '\0') {
cmdq_error(item, "invalid delay time: %s", delay);
return (CMD_RETURN_ERROR);
}
} else if (args_count(args) == 0)
return (CMD_RETURN_NORMAL);
cdata = xcalloc(1, sizeof *cdata); cdata = xcalloc(1, sizeof *cdata);
if (!args_has(args, 'C')) { cdata->cmd = format_single(item, args->argv[0], c, s, wl, wp);
cmd = args_string(args, 0);
if (cmd != NULL)
cdata->cmd = format_single_from_target(item, cmd);
} else {
cdata->state = args_make_commands_prepare(self, item, 0, NULL,
wait, 1);
}
if (args_has(args, 't') && wp != NULL) if (args_has(args, 't') && wp != NULL)
cdata->wp_id = wp->id; cdata->wp_id = wp->id;
else else
cdata->wp_id = -1; cdata->wp_id = -1;
if (wait) { if (!args_has(args, 'b'))
cdata->client = c;
cdata->item = item; cdata->item = item;
} else {
cdata->client = tc; if (job_run(cdata->cmd, s, server_client_get_cwd(item->client, s), NULL,
cdata->flags |= JOB_NOWAIT; cmd_run_shell_callback, cmd_run_shell_free, cdata, 0) == NULL) {
cmdq_error(item, "failed to run command: %s", cdata->cmd);
free(cdata);
return (CMD_RETURN_ERROR);
} }
if (cdata->client != NULL)
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')) if (args_has(args, 'b'))
cdata->flags |= JOB_SHOWSTDERR;
cdata->s = s;
if (s != NULL)
session_add_ref(s, __func__);
evtimer_set(&cdata->timer, cmd_run_shell_timer, cdata);
if (delay != NULL) {
timerclear(&tv);
tv.tv_sec = (time_t)d;
tv.tv_usec = (d - (double)tv.tv_sec) * 1000000U;
evtimer_add(&cdata->timer, &tv);
} else
event_active(&cdata->timer, EV_TIMEOUT, 1);
if (!wait)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
return (CMD_RETURN_WAIT); return (CMD_RETURN_WAIT);
} }
static void
cmd_run_shell_timer(__unused int fd, __unused short events, void* arg)
{
struct cmd_run_shell_data *cdata = arg;
struct client *c = cdata->client;
const char *cmd = cdata->cmd;
struct cmdq_item *item = cdata->item, *new_item;
struct cmd_list *cmdlist;
char *error;
if (cdata->state == NULL) {
if (cmd == NULL) {
if (cdata->item != NULL)
cmdq_continue(cdata->item);
cmd_run_shell_free(cdata);
return;
}
if (job_run(cmd, 0, NULL, NULL, cdata->s, cdata->cwd, NULL,
cmd_run_shell_callback, cmd_run_shell_free, cdata,
cdata->flags, -1, -1) == NULL)
cmd_run_shell_free(cdata);
return;
}
cmdlist = args_make_commands(cdata->state, 0, NULL, &error);
if (cmdlist == NULL) {
if (cdata->item == NULL) {
*error = toupper((u_char)*error);
status_message_set(c, -1, 1, 0, 0, "%s", error);
} else
cmdq_error(cdata->item, "%s", error);
free(error);
} else if (item == NULL) {
new_item = cmdq_get_command(cmdlist, NULL);
cmdq_append(c, new_item);
} else {
new_item = cmdq_get_command(cmdlist, cmdq_get_state(item));
cmdq_insert_after(item, new_item);
}
if (cdata->item != NULL)
cmdq_continue(cdata->item);
cmd_run_shell_free(cdata);
}
static void static void
cmd_run_shell_callback(struct job *job) cmd_run_shell_callback(struct job *job)
{ {
struct cmd_run_shell_data *cdata = job_get_data(job); struct cmd_run_shell_data *cdata = job_get_data(job);
struct bufferevent *event = job_get_event(job); struct bufferevent *event = job_get_event(job);
struct cmdq_item *item = cdata->item;
char *cmd = cdata->cmd, *msg = NULL, *line; char *cmd = cdata->cmd, *msg = NULL, *line;
size_t size; size_t size;
int retcode, status; int retcode, status;
do { do {
line = evbuffer_readln(event->input, NULL, EVBUFFER_EOL_LF); if ((line = evbuffer_readline(event->input)) != NULL) {
if (line != NULL) {
cmd_run_shell_print(job, line); cmd_run_shell_print(job, line);
free(line); free(line);
} }
@@ -260,19 +149,13 @@ cmd_run_shell_callback(struct job *job)
} else if (WIFSIGNALED(status)) { } else if (WIFSIGNALED(status)) {
retcode = WTERMSIG(status); retcode = WTERMSIG(status);
xasprintf(&msg, "'%s' terminated by signal %d", cmd, retcode); xasprintf(&msg, "'%s' terminated by signal %d", cmd, retcode);
retcode += 128; }
} else
retcode = 0;
if (msg != NULL) if (msg != NULL)
cmd_run_shell_print(job, msg); cmd_run_shell_print(job, msg);
free(msg); free(msg);
if (item != NULL) { if (cdata->item != NULL)
if (cmdq_get_client(item) != NULL && cmdq_continue(cdata->item);
cmdq_get_client(item)->session == NULL)
cmdq_get_client(item)->retval = retcode;
cmdq_continue(item);
}
} }
static void static void
@@ -280,14 +163,6 @@ cmd_run_shell_free(void *data)
{ {
struct cmd_run_shell_data *cdata = data; struct cmd_run_shell_data *cdata = data;
evtimer_del(&cdata->timer);
if (cdata->s != NULL)
session_remove_ref(cdata->s, __func__);
if (cdata->client != NULL)
server_client_unref(cdata->client);
if (cdata->state != NULL)
args_make_commands_free(cdata->state);
free(cdata->cwd);
free(cdata->cmd); free(cdata->cmd);
free(cdata); free(cdata);
} }

View File

@@ -37,7 +37,7 @@ const struct cmd_entry cmd_save_buffer_entry = {
.name = "save-buffer", .name = "save-buffer",
.alias = "saveb", .alias = "saveb",
.args = { "ab:", 1, 1, NULL }, .args = { "ab:", 1, 1 },
.usage = "[-a] " CMD_BUFFER_USAGE " path", .usage = "[-a] " CMD_BUFFER_USAGE " path",
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
@@ -48,7 +48,7 @@ const struct cmd_entry cmd_show_buffer_entry = {
.name = "show-buffer", .name = "show-buffer",
.alias = "showb", .alias = "showb",
.args = { "b:", 0, 0, NULL }, .args = { "b:", 0, 0 },
.usage = CMD_BUFFER_USAGE, .usage = CMD_BUFFER_USAGE,
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
@@ -65,21 +65,23 @@ cmd_save_buffer_done(__unused struct client *c, const char *path, int error,
return; return;
if (error != 0) if (error != 0)
cmdq_error(item, "%s: %s", strerror(error), path); cmdq_error(item, "%s: %s", path, strerror(error));
cmdq_continue(item); cmdq_continue(item);
} }
static enum cmd_retval static enum cmd_retval
cmd_save_buffer_exec(struct cmd *self, struct cmdq_item *item) cmd_save_buffer_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct client *c = cmdq_get_client(item); struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct window_pane *wp = item->target.wp;
struct paste_buffer *pb; struct paste_buffer *pb;
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;
struct evbuffer *evb;
if (bufname == NULL) { if (bufname == NULL) {
if ((pb = paste_get_top(NULL)) == NULL) { if ((pb = paste_get_top(NULL)) == NULL) {
@@ -95,24 +97,15 @@ cmd_save_buffer_exec(struct cmd *self, struct cmdq_item *item)
} }
bufdata = paste_buffer_data(pb, &bufsize); bufdata = paste_buffer_data(pb, &bufsize);
if (cmd_get_entry(self) == &cmd_show_buffer_entry) { if (self->entry == &cmd_show_buffer_entry)
if (c->session != NULL || (c->flags & CLIENT_CONTROL)) {
evb = evbuffer_new();
if (evb == NULL)
fatalx("out of memory");
evbuffer_add(evb, bufdata, bufsize);
cmdq_print_data(item, evb);
evbuffer_free(evb);
return (CMD_RETURN_NORMAL);
}
path = xstrdup("-"); path = xstrdup("-");
} else else
path = format_single_from_target(item, args_string(args, 0)); path = format_single(item, args->argv[0], c, s, wl, wp);
if (args_has(args, 'a')) if (args_has(self->args, 'a'))
flags = O_APPEND; flags = O_APPEND;
else else
flags = O_TRUNC; flags = 0;
file_write(cmdq_get_client(item), path, flags, bufdata, bufsize, file_write(item->client, path, flags, bufdata, bufsize,
cmd_save_buffer_done, item); cmd_save_buffer_done, item);
free(path); free(path);

View File

@@ -33,7 +33,7 @@ const struct cmd_entry cmd_select_layout_entry = {
.name = "select-layout", .name = "select-layout",
.alias = "selectl", .alias = "selectl",
.args = { "Enopt:", 0, 1, NULL }, .args = { "Enopt:", 0, 1 },
.usage = "[-Enop] " CMD_TARGET_PANE_USAGE " [layout-name]", .usage = "[-Enop] " CMD_TARGET_PANE_USAGE " [layout-name]",
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
@@ -46,7 +46,7 @@ const struct cmd_entry cmd_next_layout_entry = {
.name = "next-layout", .name = "next-layout",
.alias = "nextl", .alias = "nextl",
.args = { "t:", 0, 0, NULL }, .args = { "t:", 0, 0 },
.usage = CMD_TARGET_WINDOW_USAGE, .usage = CMD_TARGET_WINDOW_USAGE,
.target = { 't', CMD_FIND_WINDOW, 0 }, .target = { 't', CMD_FIND_WINDOW, 0 },
@@ -59,7 +59,7 @@ const struct cmd_entry cmd_previous_layout_entry = {
.name = "previous-layout", .name = "previous-layout",
.alias = "prevl", .alias = "prevl",
.args = { "t:", 0, 0, NULL }, .args = { "t:", 0, 0 },
.usage = CMD_TARGET_WINDOW_USAGE, .usage = CMD_TARGET_WINDOW_USAGE,
.target = { 't', CMD_FIND_WINDOW, 0 }, .target = { 't', CMD_FIND_WINDOW, 0 },
@@ -71,21 +71,20 @@ const struct cmd_entry cmd_previous_layout_entry = {
static enum cmd_retval static enum cmd_retval
cmd_select_layout_exec(struct cmd *self, struct cmdq_item *item) cmd_select_layout_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item); struct winlink *wl = item->target.wl;
struct winlink *wl = target->wl;
struct window *w = wl->window; struct window *w = wl->window;
struct window_pane *wp = target->wp; struct window_pane *wp = item->target.wp;
const char *layoutname; const char *layoutname;
char *oldlayout, *cause; char *oldlayout;
int next, previous, layout; int next, previous, layout;
server_unzoom_window(w); server_unzoom_window(w);
next = (cmd_get_entry(self) == &cmd_next_layout_entry); next = self->entry == &cmd_next_layout_entry;
if (args_has(args, 'n')) if (args_has(args, 'n'))
next = 1; next = 1;
previous = (cmd_get_entry(self) == &cmd_previous_layout_entry); previous = self->entry == &cmd_previous_layout_entry;
if (args_has(args, 'p')) if (args_has(args, 'p'))
previous = 1; previous = 1;
@@ -105,28 +104,27 @@ cmd_select_layout_exec(struct cmd *self, struct cmdq_item *item)
goto changed; goto changed;
} }
if (args_count(args) != 0)
layoutname = args_string(args, 0);
else if (args_has(args, 'o'))
layoutname = oldlayout;
else
layoutname = NULL;
if (!args_has(args, 'o')) { if (!args_has(args, 'o')) {
if (layoutname == NULL) if (args->argc == 0)
layout = w->lastlayout; layout = w->lastlayout;
else else
layout = layout_set_lookup(layoutname); layout = layout_set_lookup(args->argv[0]);
if (layout != -1) { if (layout != -1) {
layout_set_select(w, layout); layout_set_select(w, layout);
goto changed; goto changed;
} }
} }
if (args->argc != 0)
layoutname = args->argv[0];
else if (args_has(args, 'o'))
layoutname = oldlayout;
else
layoutname = NULL;
if (layoutname != NULL) { if (layoutname != NULL) {
if (layout_parse(w, layoutname, &cause) == -1) { if (layout_parse(w, layoutname) == -1) {
cmdq_error(item, "%s: %s", cause, layoutname); cmdq_error(item, "can't set layout: %s", layoutname);
free(cause);
goto error; goto error;
} }
goto changed; goto changed;

View File

@@ -33,7 +33,7 @@ const struct cmd_entry cmd_select_pane_entry = {
.name = "select-pane", .name = "select-pane",
.alias = "selectp", .alias = "selectp",
.args = { "DdegLlMmP:RT:t:UZ", 0, 0, NULL }, /* -P and -g deprecated */ .args = { "DdegLlMmP:RT:t:UZ", 0, 0 }, /* -P and -g deprecated */
.usage = "[-DdeLlMmRUZ] [-T title] " CMD_TARGET_PANE_USAGE, .usage = "[-DdeLlMmRUZ] [-T title] " CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
@@ -46,7 +46,7 @@ const struct cmd_entry cmd_last_pane_entry = {
.name = "last-pane", .name = "last-pane",
.alias = "lastp", .alias = "lastp",
.args = { "det:Z", 0, 0, NULL }, .args = { "det:Z", 0, 0 },
.usage = "[-deZ] " CMD_TARGET_WINDOW_USAGE, .usage = "[-deZ] " CMD_TARGET_WINDOW_USAGE,
.target = { 't', CMD_FIND_WINDOW, 0 }, .target = { 't', CMD_FIND_WINDOW, 0 },
@@ -83,26 +83,20 @@ cmd_select_pane_redraw(struct window *w)
static enum cmd_retval static enum cmd_retval
cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item) cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
const struct cmd_entry *entry = cmd_get_entry(self); struct cmd_find_state *current = &item->shared->current;
struct cmd_find_state *current = cmdq_get_current(item); struct client *c = cmd_find_client(item, NULL, 1);
struct cmd_find_state *target = cmdq_get_target(item); struct winlink *wl = item->target.wl;
struct client *c = cmdq_get_client(item);
struct winlink *wl = target->wl;
struct window *w = wl->window; struct window *w = wl->window;
struct session *s = target->s; struct session *s = item->target.s;
struct window_pane *wp = target->wp, *activewp, *lastwp, *markedwp; struct window_pane *wp = item->target.wp, *lastwp, *markedwp;
struct options *oo = wp->options; char *pane_title;
char *title;
const char *style; const char *style;
struct style *sy;
struct options_entry *o; struct options_entry *o;
if (entry == &cmd_last_pane_entry || args_has(args, 'l')) { if (self->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)
@@ -112,16 +106,12 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "no last pane"); cmdq_error(item, "no last pane");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (args_has(args, 'e')) { if (args_has(self->args, 'e'))
lastwp->flags &= ~PANE_INPUTOFF; lastwp->flags &= ~PANE_INPUTOFF;
server_redraw_window_borders(lastwp->window); else if (args_has(self->args, 'd'))
server_status_window(lastwp->window);
} else if (args_has(args, 'd')) {
lastwp->flags |= PANE_INPUTOFF; lastwp->flags |= PANE_INPUTOFF;
server_redraw_window_borders(lastwp->window); else {
server_status_window(lastwp->window); if (window_push_zoom(w, args_has(self->args, 'Z')))
} else {
if (window_push_zoom(w, 0, args_has(args, 'Z')))
server_redraw_window(w); server_redraw_window(w);
window_redraw_active_switch(w, lastwp); window_redraw_active_switch(w, lastwp);
if (window_set_active_pane(w, lastwp, 1)) { if (window_set_active_pane(w, lastwp, 1)) {
@@ -137,10 +127,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(args, 'm') || args_has(args, 'M')) { if (args_has(args, 'm') || args_has(args, 'M')) {
if (args_has(args, 'm') && !window_pane_visible(wp)) if (args_has(args, 'm') && !window_pane_visible(wp))
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
if (server_check_marked()) lastwp = marked_pane.wp;
lastwp = marked_pane.wp;
else
lastwp = NULL;
if (args_has(args, 'M') || server_is_marked(s, wl, wp)) if (args_has(args, 'M') || server_is_marked(s, wl, wp))
server_clear_marked(); server_clear_marked();
@@ -149,94 +136,83 @@ 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|
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|
PANE_THEMECHANGED);
server_redraw_window_borders(markedwp->window); server_redraw_window_borders(markedwp->window);
server_status_window(markedwp->window); server_status_window(markedwp->window);
} }
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
style = args_get(args, 'P'); if (args_has(self->args, 'P') || args_has(self->args, 'g')) {
if (style != NULL) { if ((style = args_get(args, 'P')) != NULL) {
o = options_set_string(oo, "window-style", 0, "%s", style); o = options_set_style(wp->options, "window-style", 0,
if (o == NULL) { style);
cmdq_error(item, "bad style: %s", style); if (o == NULL) {
return (CMD_RETURN_ERROR); cmdq_error(item, "bad style: %s", style);
return (CMD_RETURN_ERROR);
}
options_set_style(wp->options, "window-active-style", 0,
style);
wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED);
}
if (args_has(self->args, 'g')) {
sy = options_get_style(wp->options, "window-style");
cmdq_print(item, "%s", style_tostring(sy));
} }
options_set_string(oo, "window-active-style", 0, "%s", style);
wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED|PANE_THEMECHANGED);
}
if (args_has(args, 'g')) {
cmdq_print(item, "%s", options_get_string(oo, "window-style"));
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (args_has(args, 'L')) { if (args_has(self->args, 'L')) {
window_push_zoom(w, 0, 1); window_push_zoom(w, 1);
wp = window_pane_find_left(wp); wp = window_pane_find_left(wp);
window_pop_zoom(w); window_pop_zoom(w);
} else if (args_has(args, 'R')) { } else if (args_has(self->args, 'R')) {
window_push_zoom(w, 0, 1); window_push_zoom(w, 1);
wp = window_pane_find_right(wp); wp = window_pane_find_right(wp);
window_pop_zoom(w); window_pop_zoom(w);
} else if (args_has(args, 'U')) { } else if (args_has(self->args, 'U')) {
window_push_zoom(w, 0, 1); window_push_zoom(w, 1);
wp = window_pane_find_up(wp); wp = window_pane_find_up(wp);
window_pop_zoom(w); window_pop_zoom(w);
} else if (args_has(args, 'D')) { } else if (args_has(self->args, 'D')) {
window_push_zoom(w, 0, 1); window_push_zoom(w, 1);
wp = window_pane_find_down(wp); wp = window_pane_find_down(wp);
window_pop_zoom(w); window_pop_zoom(w);
} }
if (wp == NULL) if (wp == NULL)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
if (args_has(args, 'e')) { if (args_has(self->args, 'e')) {
wp->flags &= ~PANE_INPUTOFF; wp->flags &= ~PANE_INPUTOFF;
server_redraw_window_borders(wp->window);
server_status_window(wp->window);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (args_has(args, 'd')) { if (args_has(self->args, 'd')) {
wp->flags |= PANE_INPUTOFF; wp->flags |= PANE_INPUTOFF;
server_redraw_window_borders(wp->window);
server_status_window(wp->window);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (args_has(args, 'T')) { if (args_has(self->args, 'T')) {
title = format_single_from_target(item, args_get(args, 'T')); pane_title = format_single(item, args_get(self->args, 'T'),
if (screen_set_title(&wp->base, title)) { c, s, wl, wp);
notify_pane("pane-title-changed", wp); if (screen_set_title(&wp->base, pane_title))
server_redraw_window_borders(wp->window);
server_status_window(wp->window); server_status_window(wp->window);
} free(pane_title);
free(title);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (c != NULL && c->session != NULL && (c->flags & CLIENT_ACTIVEPANE)) if (wp == w->active)
activewp = server_client_get_pane(c);
else
activewp = w->active;
if (wp == activewp)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
if (window_push_zoom(w, 0, args_has(args, 'Z'))) if (window_push_zoom(w, args_has(self->args, 'Z')))
server_redraw_window(w); server_redraw_window(w);
window_redraw_active_switch(w, wp); window_redraw_active_switch(w, wp);
if (c != NULL && c->session != NULL && (c->flags & CLIENT_ACTIVEPANE)) if (window_set_active_pane(w, wp, 1)) {
server_client_set_pane(c, wp);
else if (window_set_active_pane(w, wp, 1))
cmd_find_from_winlink_pane(current, wl, wp, 0); cmd_find_from_winlink_pane(current, wl, wp, 0);
cmdq_insert_hook(s, item, current, "after-select-pane"); cmdq_insert_hook(s, item, current, "after-select-pane");
cmd_select_pane_redraw(w); cmd_select_pane_redraw(w);
}
if (window_pop_zoom(w)) if (window_pop_zoom(w))
server_redraw_window(w); server_redraw_window(w);

View File

@@ -33,7 +33,7 @@ const struct cmd_entry cmd_select_window_entry = {
.name = "select-window", .name = "select-window",
.alias = "selectw", .alias = "selectw",
.args = { "lnpTt:", 0, 0, NULL }, .args = { "lnpTt:", 0, 0 },
.usage = "[-lnpT] " CMD_TARGET_WINDOW_USAGE, .usage = "[-lnpT] " CMD_TARGET_WINDOW_USAGE,
.target = { 't', CMD_FIND_WINDOW, 0 }, .target = { 't', CMD_FIND_WINDOW, 0 },
@@ -46,7 +46,7 @@ const struct cmd_entry cmd_next_window_entry = {
.name = "next-window", .name = "next-window",
.alias = "next", .alias = "next",
.args = { "at:", 0, 0, NULL }, .args = { "at:", 0, 0 },
.usage = "[-a] " CMD_TARGET_SESSION_USAGE, .usage = "[-a] " CMD_TARGET_SESSION_USAGE,
.target = { 't', CMD_FIND_SESSION, 0 }, .target = { 't', CMD_FIND_SESSION, 0 },
@@ -59,7 +59,7 @@ const struct cmd_entry cmd_previous_window_entry = {
.name = "previous-window", .name = "previous-window",
.alias = "prev", .alias = "prev",
.args = { "at:", 0, 0, NULL }, .args = { "at:", 0, 0 },
.usage = "[-a] " CMD_TARGET_SESSION_USAGE, .usage = "[-a] " CMD_TARGET_SESSION_USAGE,
.target = { 't', CMD_FIND_SESSION, 0 }, .target = { 't', CMD_FIND_SESSION, 0 },
@@ -72,7 +72,7 @@ const struct cmd_entry cmd_last_window_entry = {
.name = "last-window", .name = "last-window",
.alias = "last", .alias = "last",
.args = { "t:", 0, 0, NULL }, .args = { "t:", 0, 0 },
.usage = CMD_TARGET_SESSION_USAGE, .usage = CMD_TARGET_SESSION_USAGE,
.target = { 't', CMD_FIND_SESSION, 0 }, .target = { 't', CMD_FIND_SESSION, 0 },
@@ -84,26 +84,23 @@ const struct cmd_entry cmd_last_window_entry = {
static enum cmd_retval static enum cmd_retval
cmd_select_window_exec(struct cmd *self, struct cmdq_item *item) cmd_select_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct cmd_find_state *current = &item->shared->current;
struct client *c = cmdq_get_client(item); struct winlink *wl = item->target.wl;
struct cmd_find_state *current = cmdq_get_current(item); struct session *s = item->target.s;
struct cmd_find_state *target = cmdq_get_target(item);
struct winlink *wl = target->wl;
struct session *s = target->s;
int next, previous, last, activity; int next, previous, last, activity;
next = (cmd_get_entry(self) == &cmd_next_window_entry); next = self->entry == &cmd_next_window_entry;
if (args_has(args, 'n')) if (args_has(self->args, 'n'))
next = 1; next = 1;
previous = (cmd_get_entry(self) == &cmd_previous_window_entry); previous = self->entry == &cmd_previous_window_entry;
if (args_has(args, 'p')) if (args_has(self->args, 'p'))
previous = 1; previous = 1;
last = (cmd_get_entry(self) == &cmd_last_window_entry); last = self->entry == &cmd_last_window_entry;
if (args_has(args, 'l')) if (args_has(self->args, 'l'))
last = 1; last = 1;
if (next || previous || last) { if (next || previous || last) {
activity = args_has(args, 'a'); activity = args_has(self->args, 'a');
if (next) { if (next) {
if (session_next(s, activity) != 0) { if (session_next(s, activity) != 0) {
cmdq_error(item, "no next window"); cmdq_error(item, "no next window");
@@ -128,7 +125,7 @@ cmd_select_window_exec(struct cmd *self, struct cmdq_item *item)
* If -T and select-window is invoked on same window as * If -T and select-window is invoked on same window as
* current, switch to previous window. * current, switch to previous window.
*/ */
if (args_has(args, 'T') && wl == s->curw) { if (args_has(self->args, 'T') && wl == s->curw) {
if (session_last(s) != 0) { if (session_last(s) != 0) {
cmdq_error(item, "no last window"); cmdq_error(item, "no last window");
return (-1); return (-1);
@@ -142,8 +139,6 @@ cmd_select_window_exec(struct cmd *self, struct cmdq_item *item)
} }
cmdq_insert_hook(s, item, current, "after-select-window"); cmdq_insert_hook(s, item, current, "after-select-window");
} }
if (c != NULL && c->session != NULL)
s->curw->window->latest = c;
recalculate_sizes(); recalculate_sizes();
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);

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 },
.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
}; };
@@ -47,7 +47,7 @@ const struct cmd_entry cmd_send_prefix_entry = {
.name = "send-prefix", .name = "send-prefix",
.alias = NULL, .alias = NULL,
.args = { "2t:", 0, 0, NULL }, .args = { "2t:", 0, 0 },
.usage = "[-2] " CMD_TARGET_PANE_USAGE, .usage = "[-2] " CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
@@ -57,56 +57,43 @@ 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 client *c, struct cmd_find_state *fs,
struct args *args, key_code key) struct cmdq_item *item, key_code key)
{ {
struct cmd_find_state *target = cmdq_get_target(item); struct session *s = fs->s;
struct client *tc = cmdq_get_target_client(item); struct winlink *wl = fs->wl;
struct session *s = target->s; struct window_pane *wp = fs->wp;
struct winlink *wl = target->wl;
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')) { wme = TAILQ_FIRST(&fs->wp->modes);
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);
if (wme == NULL || wme->mode->key_table == NULL) { if (wme == NULL || wme->mode->key_table == NULL) {
if (window_pane_key(wp, tc, s, wl, key, NULL) != 0) if (options_get_number(fs->wp->window->options, "xterm-keys"))
key |= KEYC_XTERM;
if (window_pane_key(wp, item->client, s, wl, key, NULL) != 0)
return (NULL); return (NULL);
return (item); return (item);
} }
table = key_bindings_get_table(wme->mode->key_table(wme), 1); table = key_bindings_get_table(wme->mode->key_table(wme), 1);
bd = key_bindings_get(table, key & ~KEYC_MASK_FLAGS); bd = key_bindings_get(table, key & ~KEYC_XTERM);
if (bd != NULL) { if (bd != NULL) {
table->references++; table->references++;
after = key_bindings_dispatch(bd, after, tc, NULL, target); item = key_bindings_dispatch(bd, item, c, NULL, &item->target);
key_bindings_unref_table(table); key_bindings_unref_table(table);
} }
return (after); return (item);
} }
static struct cmdq_item * static struct cmdq_item *
cmd_send_keys_inject_string(struct cmdq_item *item, struct cmdq_item *after, cmd_send_keys_inject_string(struct client *c, struct cmd_find_state *fs,
struct args *args, int i) struct cmdq_item *item, struct args *args, int i)
{ {
const char *s = args_string(args, i); const char *s = args->argv[i];
struct utf8_data *ud, *loop; struct cmdq_item *new_item;
utf8_char uc; struct utf8_data *ud, *uc;
wchar_t wc;
key_code key; key_code key;
char *endptr; char *endptr;
long n; long n;
@@ -116,67 +103,56 @@ 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(c, fs, item, 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, new_item = cmd_send_keys_inject_key(c, fs, item, key);
key); if (new_item != NULL)
if (after != NULL) return (new_item);
return (after);
} }
literal = 1; literal = 1;
} }
if (literal) { if (literal) {
ud = utf8_fromcstr(s); ud = utf8_fromcstr(s);
for (loop = ud; loop->size != 0; loop++) { for (uc = ud; uc->size != 0; uc++) {
if (loop->size == 1 && loop->data[0] <= 0x7f) if (utf8_combine(uc, &wc) != UTF8_DONE)
key = loop->data[0]; continue;
else { item = cmd_send_keys_inject_key(c, fs, item, wc);
if (utf8_from_data(loop, &uc) != UTF8_DONE)
continue;
key = uc;
}
after = cmd_send_keys_inject_key(item, after, args,
key);
} }
free(ud); free(ud);
} }
return (after); return (item);
} }
static enum cmd_retval static enum cmd_retval
cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item) cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item); struct client *c = cmd_find_client(item, NULL, 1);
struct client *tc = cmdq_get_target_client(item); struct cmd_find_state *fs = &item->target;
struct session *s = target->s; struct window_pane *wp = item->target.wp;
struct winlink *wl = target->wl; struct session *s = item->target.s;
struct window_pane *wp = target->wp; struct winlink *wl = item->target.wl;
struct key_event *event = cmdq_get_event(item); struct mouse_event *m = &item->shared->mouse;
struct mouse_event *m = &event->m;
struct window_mode_entry *wme = TAILQ_FIRST(&wp->modes); struct window_mode_entry *wme = TAILQ_FIRST(&wp->modes);
struct cmdq_item *after = item; int i;
key_code key; key_code key;
u_int i, np = 1; u_int np = 1;
u_int count = args_count(args);
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);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (wme != NULL && (args_has(args, 'X') || count == 0)) { if (wme != NULL && (args_has(args, 'X') || args->argc == 0)) {
if (wme->mode->command == NULL) { if (wme == NULL || wme->mode->command == NULL) {
cmdq_error(item, "not in a mode"); cmdq_error(item, "not in a mode");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
@@ -191,7 +167,7 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
} }
if (!m->valid) if (!m->valid)
m = NULL; m = NULL;
wme->mode->command(wme, tc, s, wl, args, m); wme->mode->command(wme, c, s, wl, args, m);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
@@ -201,38 +177,27 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "no mouse target"); cmdq_error(item, "no mouse target");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
window_pane_key(wp, tc, s, wl, m->key, m); window_pane_key(wp, item->client, s, wl, m->key, m);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (cmd_get_entry(self) == &cmd_send_prefix_entry) { if (self->entry == &cmd_send_prefix_entry) {
if (args_has(args, '2')) if (args_has(args, '2'))
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(c, fs, 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); window_pane_reset_palette(wp);
input_reset(wp->ictx, 1); input_reset(wp, 1);
wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED|PANE_REDRAW);
}
if (count == 0) {
if (args_has(args, 'N') || args_has(args, 'R'))
return (CMD_RETURN_NORMAL);
for (; np != 0; np--)
cmd_send_keys_inject_key(item, NULL, args, event->key);
return (CMD_RETURN_NORMAL);
} }
for (; np != 0; np--) { for (; np != 0; np--) {
for (i = 0; i < count; i++) { for (i = 0; i < args->argc; i++)
after = cmd_send_keys_inject_string(item, after, args, item = cmd_send_keys_inject_string(c, fs, item, args, i);
i);
}
} }
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);

View File

@@ -1,147 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2021 Dallas Lyons <dallasdlyons@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/stat.h>
#include <sys/types.h>
#include <pwd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "tmux.h"
/*
* Controls access to session.
*/
static enum cmd_retval cmd_server_access_exec(struct cmd *, struct cmdq_item *);
const struct cmd_entry cmd_server_access_entry = {
.name = "server-access",
.alias = NULL,
.args = { "adlrw", 0, 1, NULL },
.usage = "[-adlrw] " CMD_TARGET_PANE_USAGE " [user]",
.flags = CMD_CLIENT_CANFAIL,
.exec = cmd_server_access_exec
};
static enum cmd_retval
cmd_server_access_deny(struct cmdq_item *item, struct passwd *pw)
{
struct client *loop;
struct server_acl_user *user;
uid_t uid;
if ((user = server_acl_user_find(pw->pw_uid)) == NULL) {
cmdq_error(item, "user %s not found", pw->pw_name);
return (CMD_RETURN_ERROR);
}
TAILQ_FOREACH(loop, &clients, entry) {
uid = proc_get_peer_uid(loop->peer);
if (uid == server_acl_get_uid(user)) {
loop->exit_message = xstrdup("access not allowed");
loop->flags |= CLIENT_EXIT;
}
}
server_acl_user_deny(pw->pw_uid);
return (CMD_RETURN_NORMAL);
}
static enum cmd_retval
cmd_server_access_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
struct client *c = cmdq_get_target_client(item);
char *name;
struct passwd *pw = NULL;
if (args_has(args, 'l')) {
server_acl_display(item);
return (CMD_RETURN_NORMAL);
}
if (args_count(args) == 0) {
cmdq_error(item, "missing user argument");
return (CMD_RETURN_ERROR);
}
name = format_single(item, args_string(args, 0), c, NULL, NULL, NULL);
if (*name != '\0')
pw = getpwnam(name);
if (pw == NULL) {
cmdq_error(item, "unknown user: %s", name);
return (CMD_RETURN_ERROR);
}
free(name);
if (pw->pw_uid == 0 || pw->pw_uid == getuid()) {
cmdq_error(item, "%s owns the server, can't change access",
pw->pw_name);
return (CMD_RETURN_ERROR);
}
if (args_has(args, 'a') && args_has(args, 'd')) {
cmdq_error(item, "-a and -d cannot be used together");
return (CMD_RETURN_ERROR);
}
if (args_has(args, 'w') && args_has(args, 'r')) {
cmdq_error(item, "-r and -w cannot be used together");
return (CMD_RETURN_ERROR);
}
if (args_has(args, 'd'))
return (cmd_server_access_deny(item, pw));
if (args_has(args, 'a')) {
if (server_acl_user_find(pw->pw_uid) != NULL) {
cmdq_error(item, "user %s is already added",
pw->pw_name);
return (CMD_RETURN_ERROR);
}
server_acl_user_allow(pw->pw_uid);
/* Do not return - allow -r or -w with -a. */
} else if (args_has(args, 'r') || args_has(args, 'w')) {
/* -r or -w implies -a if user does not exist. */
if (server_acl_user_find(pw->pw_uid) == NULL)
server_acl_user_allow(pw->pw_uid);
}
if (args_has(args, 'w')) {
if (server_acl_user_find(pw->pw_uid) == NULL) {
cmdq_error(item, "user %s not found", pw->pw_name);
return (CMD_RETURN_ERROR);
}
server_acl_user_allow_write(pw->pw_uid);
return (CMD_RETURN_NORMAL);
}
if (args_has(args, 'r')) {
if (server_acl_user_find(pw->pw_uid) == NULL) {
cmdq_error(item, "user %s not found", pw->pw_name);
return (CMD_RETURN_ERROR);
}
server_acl_user_deny_write(pw->pw_uid);
return (CMD_RETURN_NORMAL);
}
return (CMD_RETURN_NORMAL);
}

View File

@@ -33,11 +33,10 @@ const struct cmd_entry cmd_set_buffer_entry = {
.name = "set-buffer", .name = "set-buffer",
.alias = "setb", .alias = "setb",
.args = { "ab:t:n:w", 0, 1, NULL }, .args = { "ab:n:", 0, 1 },
.usage = "[-aw] " CMD_BUFFER_USAGE " [-n new-buffer-name] " .usage = "[-a] " CMD_BUFFER_USAGE " [-n new-buffer-name] data",
CMD_TARGET_CLIENT_USAGE " [data]",
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG|CMD_CLIENT_CANFAIL, .flags = CMD_AFTERHOOK,
.exec = cmd_set_buffer_exec .exec = cmd_set_buffer_exec
}; };
@@ -45,7 +44,7 @@ const struct cmd_entry cmd_delete_buffer_entry = {
.name = "delete-buffer", .name = "delete-buffer",
.alias = "deleteb", .alias = "deleteb",
.args = { "b:", 0, 0, NULL }, .args = { "b:", 0, 0 },
.usage = CMD_BUFFER_USAGE, .usage = CMD_BUFFER_USAGE,
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
@@ -55,8 +54,7 @@ const struct cmd_entry cmd_delete_buffer_entry = {
static enum cmd_retval static enum cmd_retval
cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item) cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct client *tc = cmdq_get_target_client(item);
struct paste_buffer *pb; struct paste_buffer *pb;
char *bufdata, *cause; char *bufdata, *cause;
const char *bufname, *olddata; const char *bufname, *olddata;
@@ -68,14 +66,9 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
else else
pb = paste_get_name(bufname); pb = paste_get_name(bufname);
if (cmd_get_entry(self) == &cmd_delete_buffer_entry) { if (self->entry == &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 +78,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);
@@ -104,11 +92,11 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (args_count(args) != 1) { if (args->argc != 1) {
cmdq_error(item, "no data specified"); cmdq_error(item, "no data specified");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if ((newsize = strlen(args_string(args, 0))) == 0) if ((newsize = strlen(args->argv[0])) == 0)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
bufsize = 0; bufsize = 0;
@@ -121,7 +109,7 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
} }
bufdata = xrealloc(bufdata, bufsize + newsize); bufdata = xrealloc(bufdata, bufsize + newsize);
memcpy(bufdata + bufsize, args_string(args, 0), newsize); memcpy(bufdata + bufsize, args->argv[0], newsize);
bufsize += newsize; bufsize += newsize;
if (paste_set(bufdata, bufsize, bufname, &cause) != 0) { if (paste_set(bufdata, bufsize, bufname, &cause) != 0) {
@@ -130,8 +118,6 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
free(cause); free(cause);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (args_has(args, 'w') && tc != NULL)
tty_set_selection(&tc->tty, "", bufdata, bufsize);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@@ -34,8 +34,8 @@ const struct cmd_entry cmd_set_environment_entry = {
.name = "set-environment", .name = "set-environment",
.alias = "setenv", .alias = "setenv",
.args = { "Fhgrt:u", 1, 2, NULL }, .args = { "grt:u", 1, 2 },
.usage = "[-Fhgru] " CMD_TARGET_SESSION_USAGE " variable [value]", .usage = "[-gru] " CMD_TARGET_SESSION_USAGE " name [value]",
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL }, .target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
@@ -46,14 +46,11 @@ const struct cmd_entry cmd_set_environment_entry = {
static enum cmd_retval static enum cmd_retval
cmd_set_environment_exec(struct cmd *self, struct cmdq_item *item) cmd_set_environment_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item); struct environ *env;
struct environ *env; const char *name, *value, *target;
const char *name = args_string(args, 0), *value;
const char *tflag;
char *expanded = NULL;
enum cmd_retval retval = CMD_RETURN_NORMAL;
name = args->argv[0];
if (*name == '\0') { if (*name == '\0') {
cmdq_error(item, "empty variable name"); cmdq_error(item, "empty variable name");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
@@ -63,57 +60,44 @@ cmd_set_environment_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (args_count(args) < 2) if (args->argc < 2)
value = NULL; value = NULL;
else else
value = args_string(args, 1); value = args->argv[1];
if (value != NULL && args_has(args, 'F')) {
expanded = format_single_from_target(item, value); if (args_has(self->args, 'g'))
value = expanded;
}
if (args_has(args, 'g'))
env = global_environ; env = global_environ;
else { else {
if (target->s == NULL) { if (item->target.s == NULL) {
tflag = args_get(args, 't'); target = args_get(args, 't');
if (tflag != NULL) if (target != NULL)
cmdq_error(item, "no such session: %s", tflag); cmdq_error(item, "no such session: %s", target);
else else
cmdq_error(item, "no current session"); cmdq_error(item, "no current session");
retval = CMD_RETURN_ERROR; return (CMD_RETURN_ERROR);
goto out;
} }
env = target->s->environ; env = item->target.s->environ;
} }
if (args_has(args, 'u')) { if (args_has(self->args, 'u')) {
if (value != NULL) { if (value != NULL) {
cmdq_error(item, "can't specify a value with -u"); cmdq_error(item, "can't specify a value with -u");
retval = CMD_RETURN_ERROR; return (CMD_RETURN_ERROR);
goto out;
} }
environ_unset(env, name); environ_unset(env, name);
} else if (args_has(args, 'r')) { } else if (args_has(self->args, 'r')) {
if (value != NULL) { if (value != NULL) {
cmdq_error(item, "can't specify a value with -r"); cmdq_error(item, "can't specify a value with -r");
retval = CMD_RETURN_ERROR; return (CMD_RETURN_ERROR);
goto out;
} }
environ_clear(env, name); environ_clear(env, name);
} else { } else {
if (value == NULL) { if (value == NULL) {
cmdq_error(item, "no value specified"); cmdq_error(item, "no value specified");
retval = CMD_RETURN_ERROR; return (CMD_RETURN_ERROR);
goto out;
} }
environ_set(env, name, "%s", value);
if (args_has(args, 'h'))
environ_set(env, name, ENVIRON_HIDDEN, "%s", value);
else
environ_set(env, name, 0, "%s", value);
} }
out: return (CMD_RETURN_NORMAL);
free(expanded);
return (retval);
} }

View File

@@ -18,6 +18,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <fnmatch.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -27,17 +28,23 @@
* Set an option. * Set an option.
*/ */
static enum args_parse_type cmd_set_option_args_parse(struct args *, static enum cmd_retval cmd_set_option_exec(struct cmd *, struct cmdq_item *);
u_int, char **);
static enum cmd_retval cmd_set_option_exec(struct cmd *, static int cmd_set_option_set(struct cmd *, struct cmdq_item *,
struct cmdq_item *); struct options *, struct options_entry *, const char *);
static int cmd_set_option_flag(struct cmdq_item *,
const struct options_table_entry *, struct options *,
const char *);
static int cmd_set_option_choice(struct cmdq_item *,
const struct options_table_entry *, struct options *,
const char *);
const struct cmd_entry cmd_set_option_entry = { const struct cmd_entry cmd_set_option_entry = {
.name = "set-option", .name = "set-option",
.alias = "set", .alias = "set",
.args = { "aFgopqst:uUw", 1, 2, cmd_set_option_args_parse }, .args = { "aFgopqst:uw", 1, 2 },
.usage = "[-aFgopqsuUw] " CMD_TARGET_PANE_USAGE " option [value]", .usage = "[-aFgopqsuw] " CMD_TARGET_PANE_USAGE " option [value]",
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL }, .target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
@@ -49,7 +56,7 @@ const struct cmd_entry cmd_set_window_option_entry = {
.name = "set-window-option", .name = "set-window-option",
.alias = "setw", .alias = "setw",
.args = { "aFgoqt:u", 1, 2, cmd_set_option_args_parse }, .args = { "aFgoqt:u", 1, 2 },
.usage = "[-aFgoqu] " CMD_TARGET_WINDOW_USAGE " option [value]", .usage = "[-aFgoqu] " CMD_TARGET_WINDOW_USAGE " option [value]",
.target = { 't', CMD_FIND_WINDOW, CMD_FIND_CANFAIL }, .target = { 't', CMD_FIND_WINDOW, CMD_FIND_CANFAIL },
@@ -62,46 +69,41 @@ const struct cmd_entry cmd_set_hook_entry = {
.name = "set-hook", .name = "set-hook",
.alias = NULL, .alias = NULL,
.args = { "agpRt:uw", 1, 2, cmd_set_option_args_parse }, .args = { "agRt:u", 1, 2 },
.usage = "[-agpRuw] " CMD_TARGET_PANE_USAGE " hook [command]", .usage = "[-agRu] " CMD_TARGET_SESSION_USAGE " hook [command]",
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL }, .target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_set_option_exec .exec = cmd_set_option_exec
}; };
static enum args_parse_type
cmd_set_option_args_parse(__unused struct args *args, u_int idx,
__unused char **cause)
{
if (idx == 1)
return (ARGS_PARSE_COMMANDS_OR_STRING);
return (ARGS_PARSE_STRING);
}
static enum cmd_retval static enum cmd_retval
cmd_set_option_exec(struct cmd *self, struct cmdq_item *item) cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
int append = args_has(args, 'a'); int append = args_has(args, 'a');
struct cmd_find_state *target = cmdq_get_target(item); struct cmd_find_state *fs = &item->target;
struct window_pane *loop; struct client *c, *loop;
struct session *s = fs->s;
struct winlink *wl = fs->wl;
struct window *w;
struct window_pane *wp;
struct options *oo; struct options *oo;
struct options_entry *parent, *o, *po; struct options_entry *parent, *o;
char *name, *argument, *expanded = NULL; char *name, *argument, *value = NULL, *cause;
char *cause;
const char *value;
int window, idx, already, error, ambiguous; int window, idx, already, error, ambiguous;
int scope; int scope;
struct style *sy;
window = (cmd_get_entry(self) == &cmd_set_window_option_entry); window = (self->entry == &cmd_set_window_option_entry);
/* Expand argument. */ /* Expand argument. */
argument = format_single_from_target(item, args_string(args, 0)); c = cmd_find_client(item, NULL, 1);
argument = format_single(item, args->argv[0], c, s, wl, NULL);
/* If set-hook -R, fire the hook straight away. */ /* If set-hook -R, fire the hook straight away. */
if (cmd_get_entry(self) == &cmd_set_hook_entry && args_has(args, 'R')) { if (self->entry == &cmd_set_hook_entry && args_has(args, 'R')) {
notify_hook(item, argument); notify_hook(item, argument);
free(argument); free(argument);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
@@ -118,18 +120,15 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
cmdq_error(item, "invalid option: %s", argument); cmdq_error(item, "invalid option: %s", argument);
goto fail; goto fail;
} }
if (args_count(args) < 2) if (args->argc < 2)
value = NULL; value = NULL;
else if (args_has(args, 'F'))
value = format_single(item, args->argv[1], c, s, wl, NULL);
else else
value = args_string(args, 1); value = xstrdup(args->argv[1]);
if (value != NULL && args_has(args, 'F')) {
expanded = format_single_from_target(item, value);
value = expanded;
}
/* Get the scope and table for the option .*/ /* Get the scope and table for the option .*/
scope = options_scope_from_name(args, window, name, target, &oo, scope = options_scope_from_name(args, window, name, fs, &oo, &cause);
&cause);
if (scope == OPTIONS_TABLE_NONE) { if (scope == OPTIONS_TABLE_NONE) {
if (args_has(args, 'q')) if (args_has(args, 'q'))
goto out; goto out;
@@ -141,7 +140,7 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
parent = options_get(oo, name); parent = options_get(oo, name);
/* Check that array options and indexes match up. */ /* Check that array options and indexes match up. */
if (idx != -1 && (*name == '@' || !options_is_array(parent))) { if (idx != -1 && (*name == '@' || !options_isarray(parent))) {
cmdq_error(item, "not an array: %s", argument); cmdq_error(item, "not an array: %s", argument);
goto fail; goto fail;
} }
@@ -165,22 +164,19 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
} }
/* Change the option. */ /* Change the option. */
if (args_has(args, 'U') && scope == OPTIONS_TABLE_WINDOW) { if (args_has(args, 'u')) {
TAILQ_FOREACH(loop, &target->w->panes, entry) {
po = options_get_only(loop->options, name);
if (po == NULL)
continue;
if (options_remove_or_default(po, idx, &cause) != 0) {
cmdq_error(item, "%s", cause);
free(cause);
goto fail;
}
}
}
if (args_has(args, 'u') || args_has(args, 'U')) {
if (o == NULL) if (o == NULL)
goto out; goto out;
if (options_remove_or_default(o, idx, &cause) != 0) { if (idx == -1) {
if (*name == '@')
options_remove(o);
else if (oo == global_options ||
oo == global_s_options ||
oo == global_w_options)
options_default(oo, options_table_entry(o));
else
options_remove(o);
} else if (options_array_set(o, idx, NULL, 0, &cause) != 0) {
cmdq_error(item, "%s", cause); cmdq_error(item, "%s", cause);
free(cause); free(cause);
goto fail; goto fail;
@@ -191,15 +187,10 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
goto fail; goto fail;
} }
options_set_string(oo, name, append, "%s", value); options_set_string(oo, name, append, "%s", value);
} else if (idx == -1 && !options_is_array(parent)) { } else if (idx == -1 && !options_isarray(parent)) {
error = options_from_string(oo, options_table_entry(parent), error = cmd_set_option_set(self, item, oo, parent, value);
options_table_entry(parent)->name, value, if (error != 0)
args_has(args, 'a'), &cause);
if (error != 0) {
cmdq_error(item, "%s", cause);
free(cause);
goto fail; goto fail;
}
} else { } else {
if (value == NULL) { if (value == NULL) {
cmdq_error(item, "empty value"); cmdq_error(item, "empty value");
@@ -223,17 +214,198 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
} }
} }
options_push_changes(name); /* Update timers and so on for various options. */
if (strcmp(name, "automatic-rename") == 0) {
RB_FOREACH(w, windows, &windows) {
if (w->active == NULL)
continue;
if (options_get_number(w->options, "automatic-rename"))
w->active->flags |= PANE_CHANGED;
}
}
if (strcmp(name, "key-table") == 0) {
TAILQ_FOREACH(loop, &clients, entry)
server_client_set_key_table(loop, NULL);
}
if (strcmp(name, "user-keys") == 0) {
TAILQ_FOREACH(loop, &clients, entry) {
if (loop->tty.flags & TTY_OPENED)
tty_keys_build(&loop->tty);
}
}
if (strcmp(name, "status-fg") == 0 || strcmp(name, "status-bg") == 0) {
sy = options_get_style(oo, "status-style");
sy->gc.fg = options_get_number(oo, "status-fg");
sy->gc.bg = options_get_number(oo, "status-bg");
}
if (strcmp(name, "status-style") == 0) {
sy = options_get_style(oo, "status-style");
options_set_number(oo, "status-fg", sy->gc.fg);
options_set_number(oo, "status-bg", sy->gc.bg);
}
if (strcmp(name, "status") == 0 ||
strcmp(name, "status-interval") == 0)
status_timer_start_all();
if (strcmp(name, "monitor-silence") == 0)
alerts_reset_all();
if (strcmp(name, "window-style") == 0 ||
strcmp(name, "window-active-style") == 0) {
RB_FOREACH(wp, window_pane_tree, &all_window_panes)
wp->flags |= PANE_STYLECHANGED;
}
if (strcmp(name, "pane-border-status") == 0) {
RB_FOREACH(w, windows, &windows)
layout_fix_panes(w);
}
RB_FOREACH(s, sessions, &sessions)
status_update_cache(s);
/*
* Update sizes and redraw. May not always be necessary but do it
* anyway.
*/
recalculate_sizes();
TAILQ_FOREACH(loop, &clients, entry) {
if (loop->session != NULL)
server_redraw_client(loop);
}
out: out:
free(argument); free(argument);
free(expanded); free(value);
free(name); free(name);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
fail: fail:
free(argument); free(argument);
free(expanded); free(value);
free(name); free(name);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
static int
cmd_set_option_set(struct cmd *self, struct cmdq_item *item, struct options *oo,
struct options_entry *parent, const char *value)
{
const struct options_table_entry *oe;
struct args *args = self->args;
int append = args_has(args, 'a');
struct options_entry *o;
long long number;
const char *errstr, *new;
char *old;
key_code key;
oe = options_table_entry(parent);
if (value == NULL &&
oe->type != OPTIONS_TABLE_FLAG &&
oe->type != OPTIONS_TABLE_CHOICE) {
cmdq_error(item, "empty value");
return (-1);
}
switch (oe->type) {
case OPTIONS_TABLE_STRING:
old = xstrdup(options_get_string(oo, oe->name));
options_set_string(oo, oe->name, append, "%s", value);
new = options_get_string(oo, oe->name);
if (oe->pattern != NULL && fnmatch(oe->pattern, new, 0) != 0) {
options_set_string(oo, oe->name, 0, "%s", old);
free(old);
cmdq_error(item, "value is invalid: %s", value);
return (-1);
}
free(old);
return (0);
case OPTIONS_TABLE_NUMBER:
number = strtonum(value, oe->minimum, oe->maximum, &errstr);
if (errstr != NULL) {
cmdq_error(item, "value is %s: %s", errstr, value);
return (-1);
}
options_set_number(oo, oe->name, number);
return (0);
case OPTIONS_TABLE_KEY:
key = key_string_lookup_string(value);
if (key == KEYC_UNKNOWN) {
cmdq_error(item, "bad key: %s", value);
return (-1);
}
options_set_number(oo, oe->name, key);
return (0);
case OPTIONS_TABLE_COLOUR:
if ((number = colour_fromstring(value)) == -1) {
cmdq_error(item, "bad colour: %s", value);
return (-1);
}
options_set_number(oo, oe->name, number);
return (0);
case OPTIONS_TABLE_FLAG:
return (cmd_set_option_flag(item, oe, oo, value));
case OPTIONS_TABLE_CHOICE:
return (cmd_set_option_choice(item, oe, oo, value));
case OPTIONS_TABLE_STYLE:
o = options_set_style(oo, oe->name, append, value);
if (o == NULL) {
cmdq_error(item, "bad style: %s", value);
return (-1);
}
return (0);
case OPTIONS_TABLE_COMMAND:
break;
}
return (-1);
}
static int
cmd_set_option_flag(struct cmdq_item *item,
const struct options_table_entry *oe, struct options *oo,
const char *value)
{
int flag;
if (value == NULL || *value == '\0')
flag = !options_get_number(oo, oe->name);
else if (strcmp(value, "1") == 0 ||
strcasecmp(value, "on") == 0 ||
strcasecmp(value, "yes") == 0)
flag = 1;
else if (strcmp(value, "0") == 0 ||
strcasecmp(value, "off") == 0 ||
strcasecmp(value, "no") == 0)
flag = 0;
else {
cmdq_error(item, "bad value: %s", value);
return (-1);
}
options_set_number(oo, oe->name, flag);
return (0);
}
static int
cmd_set_option_choice(struct cmdq_item *item,
const struct options_table_entry *oe, struct options *oo,
const char *value)
{
const char **cp;
int n, choice = -1;
if (value == NULL) {
choice = options_get_number(oo, oe->name);
if (choice < 2)
choice = !choice;
} else {
n = 0;
for (cp = oe->choices; *cp != NULL; cp++) {
if (strcmp(*cp, value) == 0)
choice = n;
n++;
}
if (choice == -1) {
cmdq_error(item, "unknown value: %s", value);
return (-1);
}
}
options_set_number(oo, oe->name, choice);
return (0);
}

View File

@@ -38,8 +38,8 @@ const struct cmd_entry cmd_show_environment_entry = {
.name = "show-environment", .name = "show-environment",
.alias = "showenv", .alias = "showenv",
.args = { "hgst:", 0, 1, NULL }, .args = { "gst:", 0, 1 },
.usage = "[-hgs] " CMD_TARGET_SESSION_USAGE " [variable]", .usage = "[-gs] " CMD_TARGET_SESSION_USAGE " [name]",
.target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL }, .target = { 't', CMD_FIND_SESSION, CMD_FIND_CANFAIL },
@@ -69,15 +69,9 @@ static void
cmd_show_environment_print(struct cmd *self, struct cmdq_item *item, cmd_show_environment_print(struct cmd *self, struct cmdq_item *item,
struct environ_entry *envent) struct environ_entry *envent)
{ {
struct args *args = cmd_get_args(self); char *escaped;
char *escaped;
if (!args_has(args, 'h') && (envent->flags & ENVIRON_HIDDEN)) if (!args_has(self->args, 's')) {
return;
if (args_has(args, 'h') && (~envent->flags & ENVIRON_HIDDEN))
return;
if (!args_has(args, 's')) {
if (envent->value != NULL) if (envent->value != NULL)
cmdq_print(item, "%s=%s", envent->name, envent->value); cmdq_print(item, "%s=%s", envent->name, envent->value);
else else
@@ -97,37 +91,36 @@ cmd_show_environment_print(struct cmd *self, struct cmdq_item *item,
static enum cmd_retval static enum cmd_retval
cmd_show_environment_exec(struct cmd *self, struct cmdq_item *item) cmd_show_environment_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item);
struct environ *env; struct environ *env;
struct environ_entry *envent; struct environ_entry *envent;
const char *tflag, *name = args_string(args, 0); const char *target;
if ((tflag = args_get(args, 't')) != NULL) { if ((target = args_get(args, 't')) != NULL) {
if (target->s == NULL) { if (item->target.s == NULL) {
cmdq_error(item, "no such session: %s", tflag); cmdq_error(item, "no such session: %s", target);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} }
if (args_has(args, 'g')) if (args_has(self->args, 'g'))
env = global_environ; env = global_environ;
else { else {
if (target->s == NULL) { if (item->target.s == NULL) {
tflag = args_get(args, 't'); target = args_get(args, 't');
if (tflag != NULL) if (target != NULL)
cmdq_error(item, "no such session: %s", tflag); cmdq_error(item, "no such session: %s", target);
else else
cmdq_error(item, "no current session"); cmdq_error(item, "no current session");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
env = target->s->environ; env = item->target.s->environ;
} }
if (name != NULL) { if (args->argc != 0) {
envent = environ_find(env, name); envent = environ_find(env, args->argv[0]);
if (envent == NULL) { if (envent == NULL) {
cmdq_error(item, "unknown variable: %s", name); cmdq_error(item, "unknown variable: %s", args->argv[0]);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
cmd_show_environment_print(self, item, envent); cmd_show_environment_print(self, item, envent);

View File

@@ -18,19 +18,16 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h>
#include <unistd.h> #include <unistd.h>
#include "tmux.h" #include "tmux.h"
/* /*
* Show message log. * Show client message log.
*/ */
#define SHOW_MESSAGES_TEMPLATE \
"#{t/p:message_time}: #{message_text}"
static enum cmd_retval cmd_show_messages_exec(struct cmd *, static enum cmd_retval cmd_show_messages_exec(struct cmd *,
struct cmdq_item *); struct cmdq_item *);
@@ -38,31 +35,29 @@ const struct cmd_entry cmd_show_messages_entry = {
.name = "show-messages", .name = "show-messages",
.alias = "showmsgs", .alias = "showmsgs",
.args = { "JTt:", 0, 0, NULL }, .args = { "JTt:", 0, 0 },
.usage = "[-JT] " CMD_TARGET_CLIENT_USAGE, .usage = "[-JT] " CMD_TARGET_CLIENT_USAGE,
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG|CMD_CLIENT_CANFAIL, .flags = CMD_AFTERHOOK,
.exec = cmd_show_messages_exec .exec = cmd_show_messages_exec
}; };
static int cmd_show_messages_terminals(struct cmdq_item *, int);
static int static int
cmd_show_messages_terminals(struct cmd *self, struct cmdq_item *item, int blank) cmd_show_messages_terminals(struct cmdq_item *item, int blank)
{ {
struct args *args = cmd_get_args(self);
struct client *tc = cmdq_get_target_client(item);
struct tty_term *term; struct tty_term *term;
u_int i, n; u_int i, n;
n = 0; n = 0;
LIST_FOREACH(term, &tty_terms, entry) { LIST_FOREACH(term, &tty_terms, entry) {
if (args_has(args, 't') && tc != NULL && term != tc->tty.term)
continue;
if (blank) { if (blank) {
cmdq_print(item, "%s", ""); cmdq_print(item, "%s", "");
blank = 0; blank = 0;
} }
cmdq_print(item, "Terminal %u: %s for %s, flags=0x%x:", n, cmdq_print(item, "Terminal %u: %s [references=%u, flags=0x%x]:",
term->name, term->tty->client->name, term->flags); n, term->name, term->references, term->flags);
n++; n++;
for (i = 0; i < tty_term_ncodes(); i++) for (i = 0; i < tty_term_ncodes(); i++)
cmdq_print(item, "%s", tty_term_describe(term, i)); cmdq_print(item, "%s", tty_term_describe(term, i));
@@ -73,15 +68,18 @@ cmd_show_messages_terminals(struct cmd *self, struct cmdq_item *item, int blank)
static enum cmd_retval static enum cmd_retval
cmd_show_messages_exec(struct cmd *self, struct cmdq_item *item) cmd_show_messages_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct client *c;
struct message_entry *msg; struct message_entry *msg;
char *s; char *tim;
int done, blank; int done, blank;
struct format_tree *ft;
if ((c = cmd_find_client(item, args_get(args, 't'), 0)) == NULL)
return (CMD_RETURN_ERROR);
done = blank = 0; done = blank = 0;
if (args_has(args, 'T')) { if (args_has(args, 'T')) {
blank = cmd_show_messages_terminals(self, item, blank); blank = cmd_show_messages_terminals(item, blank);
done = 1; done = 1;
} }
if (args_has(args, 'J')) { if (args_has(args, 'J')) {
@@ -91,17 +89,12 @@ cmd_show_messages_exec(struct cmd *self, struct cmdq_item *item)
if (done) if (done)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
ft = format_create_from_target(item); TAILQ_FOREACH(msg, &c->message_log, entry) {
TAILQ_FOREACH_REVERSE(msg, &message_log, message_list, entry) { tim = ctime(&msg->msg_time);
format_add(ft, "message_text", "%s", msg->msg); *strchr(tim, '\n') = '\0';
format_add(ft, "message_number", "%u", msg->msg_num);
format_add_tv(ft, "message_time", &msg->msg_time);
s = format_expand(ft, SHOW_MESSAGES_TEMPLATE); cmdq_print(item, "%s %s", tim, msg->msg);
cmdq_print(item, "%s", s);
free(s);
} }
format_free(ft);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@@ -38,7 +38,7 @@ const struct cmd_entry cmd_show_options_entry = {
.name = "show-options", .name = "show-options",
.alias = "show", .alias = "show",
.args = { "AgHpqst:vw", 0, 1, NULL }, .args = { "AgHpqst:vw", 0, 1 },
.usage = "[-AgHpqsvw] " CMD_TARGET_PANE_USAGE " [option]", .usage = "[-AgHpqsvw] " CMD_TARGET_PANE_USAGE " [option]",
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL }, .target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
@@ -51,7 +51,7 @@ const struct cmd_entry cmd_show_window_options_entry = {
.name = "show-window-options", .name = "show-window-options",
.alias = "showw", .alias = "showw",
.args = { "gvt:", 0, 1, NULL }, .args = { "gvt:", 0, 1 },
.usage = "[-gv] " CMD_TARGET_WINDOW_USAGE " [option]", .usage = "[-gv] " CMD_TARGET_WINDOW_USAGE " [option]",
.target = { 't', CMD_FIND_WINDOW, CMD_FIND_CANFAIL }, .target = { 't', CMD_FIND_WINDOW, CMD_FIND_CANFAIL },
@@ -64,10 +64,10 @@ const struct cmd_entry cmd_show_hooks_entry = {
.name = "show-hooks", .name = "show-hooks",
.alias = NULL, .alias = NULL,
.args = { "gpt:w", 0, 1, NULL }, .args = { "gt:", 0, 1 },
.usage = "[-gpw] " CMD_TARGET_PANE_USAGE " [hook]", .usage = "[-g] " CMD_TARGET_SESSION_USAGE,
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL }, .target = { 't', CMD_FIND_SESSION, 0 },
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_show_options_exec .exec = cmd_show_options_exec
@@ -76,18 +76,20 @@ const struct cmd_entry cmd_show_hooks_entry = {
static enum cmd_retval static enum cmd_retval
cmd_show_options_exec(struct cmd *self, struct cmdq_item *item) cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *target = cmdq_get_target(item); struct cmd_find_state *fs = &item->target;
struct client *c = cmd_find_client(item, NULL, 1);
struct session *s = item->target.s;
struct winlink *wl = item->target.wl;
struct options *oo; struct options *oo;
char *argument, *name = NULL, *cause; char *argument, *name = NULL, *cause;
int window, idx, ambiguous, parent, scope; int window, idx, ambiguous, parent, scope;
struct options_entry *o; struct options_entry *o;
window = (cmd_get_entry(self) == &cmd_show_window_options_entry); window = (self->entry == &cmd_show_window_options_entry);
if (args_count(args) == 0) { if (args->argc == 0) {
scope = options_scope_from_flags(args, window, target, &oo, scope = options_scope_from_flags(args, window, fs, &oo, &cause);
&cause);
if (scope == OPTIONS_TABLE_NONE) { if (scope == OPTIONS_TABLE_NONE) {
if (args_has(args, 'q')) if (args_has(args, 'q'))
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
@@ -97,23 +99,22 @@ cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
} }
return (cmd_show_options_all(self, item, scope, oo)); return (cmd_show_options_all(self, item, scope, oo));
} }
argument = format_single_from_target(item, args_string(args, 0)); argument = format_single(item, args->argv[0], c, s, wl, NULL);
name = options_match(argument, &idx, &ambiguous); name = options_match(argument, &idx, &ambiguous);
if (name == NULL) { if (name == NULL) {
if (args_has(args, 'q')) if (args_has(args, 'q'))
goto out; goto fail;
if (ambiguous) if (ambiguous)
cmdq_error(item, "ambiguous option: %s", argument); cmdq_error(item, "ambiguous option: %s", argument);
else else
cmdq_error(item, "invalid option: %s", argument); cmdq_error(item, "invalid option: %s", argument);
goto fail; goto fail;
} }
scope = options_scope_from_name(args, window, name, target, &oo, scope = options_scope_from_name(args, window, name, fs, &oo, &cause);
&cause);
if (scope == OPTIONS_TABLE_NONE) { if (scope == OPTIONS_TABLE_NONE) {
if (args_has(args, 'q')) if (args_has(args, 'q'))
goto out; goto fail;
cmdq_error(item, "%s", cause); cmdq_error(item, "%s", cause);
free(cause); free(cause);
goto fail; goto fail;
@@ -126,14 +127,7 @@ cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
parent = 0; parent = 0;
if (o != NULL) if (o != NULL)
cmd_show_options_print(self, item, o, idx, parent); cmd_show_options_print(self, item, o, idx, parent);
else if (*name == '@') {
if (args_has(args, 'q'))
goto out;
cmdq_error(item, "invalid option: %s", argument);
goto fail;
}
out:
free(name); free(name);
free(argument); free(argument);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
@@ -148,7 +142,6 @@ static void
cmd_show_options_print(struct cmd *self, struct cmdq_item *item, cmd_show_options_print(struct cmd *self, struct cmdq_item *item,
struct options_entry *o, int idx, int parent) struct options_entry *o, int idx, int parent)
{ {
struct args *args = cmd_get_args(self);
struct options_array_item *a; struct options_array_item *a;
const char *name = options_name(o); const char *name = options_name(o);
char *value, *tmp = NULL, *escaped; char *value, *tmp = NULL, *escaped;
@@ -157,10 +150,10 @@ cmd_show_options_print(struct cmd *self, struct cmdq_item *item,
xasprintf(&tmp, "%s[%d]", name, idx); xasprintf(&tmp, "%s[%d]", name, idx);
name = tmp; name = tmp;
} else { } else {
if (options_is_array(o)) { if (options_isarray(o)) {
a = options_array_first(o); a = options_array_first(o);
if (a == NULL) { if (a == NULL) {
if (!args_has(args, 'v')) if (!args_has(self->args, 'v'))
cmdq_print(item, "%s", name); cmdq_print(item, "%s", name);
return; return;
} }
@@ -174,10 +167,10 @@ cmd_show_options_print(struct cmd *self, struct cmdq_item *item,
} }
} }
value = options_to_string(o, idx, 0); value = options_tostring(o, idx, 0);
if (args_has(args, 'v')) if (args_has(self->args, 'v'))
cmdq_print(item, "%s", value); cmdq_print(item, "%s", value);
else if (options_is_string(o)) { else if (options_isstring(o)) {
escaped = args_escape(value); escaped = args_escape(value);
if (parent) if (parent)
cmdq_print(item, "%s* %s", name, escaped); cmdq_print(item, "%s* %s", name, escaped);
@@ -199,7 +192,6 @@ static enum cmd_retval
cmd_show_options_all(struct cmd *self, struct cmdq_item *item, int scope, cmd_show_options_all(struct cmd *self, struct cmdq_item *item, int scope,
struct options *oo) struct options *oo)
{ {
struct args *args = cmd_get_args(self);
const struct options_table_entry *oe; const struct options_table_entry *oe;
struct options_entry *o; struct options_entry *o;
struct options_array_item *a; struct options_array_item *a;
@@ -207,28 +199,28 @@ cmd_show_options_all(struct cmd *self, struct cmdq_item *item, int scope,
u_int idx; u_int idx;
int parent; int parent;
if (cmd_get_entry(self) != &cmd_show_hooks_entry) { o = options_first(oo);
o = options_first(oo); while (o != NULL) {
while (o != NULL) { if (options_table_entry(o) == NULL)
if (options_table_entry(o) == NULL) cmd_show_options_print(self, item, o, -1, 0);
cmd_show_options_print(self, item, o, -1, 0); o = options_next(o);
o = options_next(o);
}
} }
for (oe = options_table; oe->name != NULL; oe++) { for (oe = options_table; oe->name != NULL; oe++) {
if (~oe->scope & scope) if (~oe->scope & scope)
continue; continue;
if ((cmd_get_entry(self) != &cmd_show_hooks_entry && if ((self->entry != &cmd_show_hooks_entry &&
!args_has(args, 'H') && !args_has(self->args, 'H') &&
oe != NULL &&
(oe->flags & OPTIONS_TABLE_IS_HOOK)) || (oe->flags & OPTIONS_TABLE_IS_HOOK)) ||
(cmd_get_entry(self) == &cmd_show_hooks_entry && (self->entry == &cmd_show_hooks_entry &&
(~oe->flags & OPTIONS_TABLE_IS_HOOK))) (oe == NULL ||
(~oe->flags & OPTIONS_TABLE_IS_HOOK))))
continue; continue;
o = options_get_only(oo, oe->name); o = options_get_only(oo, oe->name);
if (o == NULL) { if (o == NULL) {
if (!args_has(args, 'A')) if (!args_has(self->args, 'A'))
continue; continue;
o = options_get(oo, oe->name); o = options_get(oo, oe->name);
if (o == NULL) if (o == NULL)
@@ -237,10 +229,10 @@ cmd_show_options_all(struct cmd *self, struct cmdq_item *item, int scope,
} else } else
parent = 0; parent = 0;
if (!options_is_array(o)) if (!options_isarray(o))
cmd_show_options_print(self, item, o, -1, parent); cmd_show_options_print(self, item, o, -1, parent);
else if ((a = options_array_first(o)) == NULL) { else if ((a = options_array_first(o)) == NULL) {
if (!args_has(args, 'v')) { if (!args_has(self->args, 'v')) {
name = options_name(o); name = options_name(o);
if (parent) if (parent)
cmdq_print(item, "%s*", name); cmdq_print(item, "%s*", name);

View File

@@ -1,108 +0,0 @@
/* $OpenBSD$ */
/*
* Copyright (c) 2021 Anindya Mukherjee <anindya49@hotmail.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 "tmux.h"
#include <stdlib.h>
/*
* Show or clear prompt history.
*/
static enum cmd_retval cmd_show_prompt_history_exec(struct cmd *,
struct cmdq_item *);
const struct cmd_entry cmd_show_prompt_history_entry = {
.name = "show-prompt-history",
.alias = "showphist",
.args = { "T:", 0, 0, NULL },
.usage = "[-T prompt-type]",
.flags = CMD_AFTERHOOK,
.exec = cmd_show_prompt_history_exec
};
const struct cmd_entry cmd_clear_prompt_history_entry = {
.name = "clear-prompt-history",
.alias = "clearphist",
.args = { "T:", 0, 0, NULL },
.usage = "[-T prompt-type]",
.flags = CMD_AFTERHOOK,
.exec = cmd_show_prompt_history_exec
};
static enum cmd_retval
cmd_show_prompt_history_exec(struct cmd *self, struct cmdq_item *item)
{
struct args *args = cmd_get_args(self);
const char *typestr = args_get(args, 'T');
enum prompt_type type;
u_int tidx, hidx;
if (cmd_get_entry(self) == &cmd_clear_prompt_history_entry) {
if (typestr == NULL) {
for (tidx = 0; tidx < PROMPT_NTYPES; tidx++) {
free(status_prompt_hlist[tidx]);
status_prompt_hlist[tidx] = NULL;
status_prompt_hsize[tidx] = 0;
}
} else {
type = status_prompt_type(typestr);
if (type == PROMPT_TYPE_INVALID) {
cmdq_error(item, "invalid type: %s", typestr);
return (CMD_RETURN_ERROR);
}
free(status_prompt_hlist[type]);
status_prompt_hlist[type] = NULL;
status_prompt_hsize[type] = 0;
}
return (CMD_RETURN_NORMAL);
}
if (typestr == NULL) {
for (tidx = 0; tidx < PROMPT_NTYPES; tidx++) {
cmdq_print(item, "History for %s:\n",
status_prompt_type_string(tidx));
for (hidx = 0; hidx < status_prompt_hsize[tidx];
hidx++) {
cmdq_print(item, "%d: %s", hidx + 1,
status_prompt_hlist[tidx][hidx]);
}
cmdq_print(item, "%s", "");
}
} else {
type = status_prompt_type(typestr);
if (type == PROMPT_TYPE_INVALID) {
cmdq_error(item, "invalid type: %s", typestr);
return (CMD_RETURN_ERROR);
}
cmdq_print(item, "History for %s:\n",
status_prompt_type_string(type));
for (hidx = 0; hidx < status_prompt_hsize[type]; hidx++) {
cmdq_print(item, "%d: %s", hidx + 1,
status_prompt_hlist[type][hidx]);
}
cmdq_print(item, "%s", "");
}
return (CMD_RETURN_NORMAL);
}

View File

@@ -18,7 +18,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <ctype.h>
#include <errno.h> #include <errno.h>
#include <glob.h> #include <glob.h>
#include <stdlib.h> #include <stdlib.h>
@@ -30,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 = { "nqv", 1, -1 },
.usage = "[-Fnqv] " CMD_TARGET_PANE_USAGE " path ...", .usage = "[-nqv] path ...",
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
.flags = 0, .flags = 0,
.exec = cmd_source_file_exec .exec = cmd_source_file_exec
@@ -63,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);
} }
@@ -81,19 +65,14 @@ static void
cmd_source_file_complete(struct client *c, struct cmd_source_file_data *cdata) cmd_source_file_complete(struct client *c, struct cmd_source_file_data *cdata)
{ {
struct cmdq_item *new_item; struct cmdq_item *new_item;
u_int i;
if (cfg_finished) { if (cfg_finished) {
if (cdata->retval == CMD_RETURN_ERROR && if (cdata->retval == CMD_RETURN_ERROR && c->session == NULL)
c != NULL &&
c->session == NULL)
c->retval = 1; c->retval = 1;
new_item = cmdq_get_callback(cmd_source_file_complete_cb, NULL); new_item = cmdq_get_callback(cmd_source_file_complete_cb, NULL);
cmdq_insert_after(cdata->after, new_item); cmdq_insert_after(cdata->after, new_item);
} }
for (i = 0; i < cdata->nfiles; i++)
free(cdata->files[i]);
free(cdata->files); free(cdata->files);
free(cdata); free(cdata);
} }
@@ -108,16 +87,15 @@ 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;
if (error != 0) if (error != 0)
cmdq_error(item, "%s: %s", strerror(error), path); 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;
@@ -141,49 +119,18 @@ cmd_source_file_add(struct cmd_source_file_data *cdata, const char *path)
cdata->files[cdata->nfiles++] = xstrdup(path); cdata->files[cdata->nfiles++] = xstrdup(path);
} }
static char *
cmd_source_file_quote_for_glob(const char *path)
{
char *quoted = xmalloc(2 * strlen(path) + 1), *q = quoted;
const char *p = path;
while (*p != '\0') {
if ((u_char)*p < 128 && !isalnum((u_char)*p) && *p != '/')
*q++ = '\\';
*q++ = *p++;
}
*q = '\0';
return (quoted);
}
static enum cmd_retval static enum cmd_retval
cmd_source_file_exec(struct cmd *self, struct cmdq_item *item) cmd_source_file_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_source_file_data *cdata; struct cmd_source_file_data *cdata;
struct client *c = cmdq_get_client(item); struct client *c = item->client;
enum cmd_retval retval = CMD_RETURN_NORMAL; enum cmd_retval retval = CMD_RETURN_NORMAL;
char *pattern, *cwd, *expanded = NULL; char *pattern, *cwd;
const char *path, *error; const char *path, *error;
glob_t g; glob_t g;
int result, parse_flags; int i, result;
u_int i, j; u_int 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;
@@ -192,21 +139,13 @@ cmd_source_file_exec(struct cmd *self, struct cmdq_item *item)
cdata->flags |= CMD_PARSE_QUIET; cdata->flags |= CMD_PARSE_QUIET;
if (args_has(args, 'n')) if (args_has(args, 'n'))
cdata->flags |= CMD_PARSE_PARSEONLY; cdata->flags |= CMD_PARSE_PARSEONLY;
if (c == NULL || ~c->flags & CLIENT_CONTROL) { if (args_has(args, 'v'))
parse_flags = cmd_get_parse_flags(self); cdata->flags |= CMD_PARSE_VERBOSE;
if (args_has(args, 'v') || (parse_flags & CMD_PARSE_VERBOSE))
cdata->flags |= CMD_PARSE_VERBOSE;
}
cwd = cmd_source_file_quote_for_glob(server_client_get_cwd(c, NULL)); utf8_stravis(&cwd, server_client_get_cwd(c, NULL), VIS_GLOB);
for (i = 0; i < args_count(args); i++) { for (i = 0; i < args->argc; i++) {
path = args_string(args, i); path = args->argv[i];
if (args_has(args, 'F')) {
free(expanded);
expanded = format_single_from_target(item, path);
path = expanded;
}
if (strcmp(path, "-") == 0) { if (strcmp(path, "-") == 0) {
cmd_source_file_add(cdata, "-"); cmd_source_file_add(cdata, "-");
continue; continue;
@@ -227,10 +166,9 @@ cmd_source_file_exec(struct cmd *self, struct cmdq_item *item)
error = strerror(ENOMEM); error = strerror(ENOMEM);
else else
error = strerror(EINVAL); error = strerror(EINVAL);
cmdq_error(item, "%s: %s", error, path); cmdq_error(item, "%s: %s", path, error);
retval = CMD_RETURN_ERROR; retval = CMD_RETURN_ERROR;
} }
globfree(&g);
free(pattern); free(pattern);
continue; continue;
} }
@@ -238,9 +176,7 @@ cmd_source_file_exec(struct cmd *self, struct cmdq_item *item)
for (j = 0; j < g.gl_pathc; j++) for (j = 0; j < g.gl_pathc; j++)
cmd_source_file_add(cdata, g.gl_pathv[j]); cmd_source_file_add(cdata, g.gl_pathv[j]);
globfree(&g);
} }
free(expanded);
cdata->after = item; cdata->after = item;
cdata->retval = retval; cdata->retval = retval;

View File

@@ -39,10 +39,9 @@ const struct cmd_entry cmd_split_window_entry = {
.name = "split-window", .name = "split-window",
.alias = "splitw", .alias = "splitw",
.args = { "bc:de:fF:hIl:p:Pt:vZ", 0, -1, NULL }, .args = { "bc:de:fF:hIl:p:Pt:v", 0, -1 },
.usage = "[-bdefhIPvZ] [-c start-directory] [-e environment] " .usage = "[-bdefhIPv] [-c start-directory] [-e environment] "
"[-F format] [-l size] " CMD_TARGET_PANE_USAGE "[-F format] [-l size] " CMD_TARGET_PANE_USAGE " [command]",
" [shell-command [argument ...]]",
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
@@ -53,68 +52,72 @@ const struct cmd_entry cmd_split_window_entry = {
static enum cmd_retval static enum cmd_retval
cmd_split_window_exec(struct cmd *self, struct cmdq_item *item) cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *current = cmdq_get_current(item); struct cmd_find_state *current = &item->shared->current;
struct cmd_find_state *target = cmdq_get_target(item); struct spawn_context sc;
struct spawn_context sc = { 0 }; struct client *c = cmd_find_client(item, NULL, 1);
struct client *tc = cmdq_get_target_client(item); struct session *s = item->target.s;
struct session *s = target->s; struct winlink *wl = item->target.wl;
struct winlink *wl = target->wl; struct window_pane *wp = item->target.wp, *new_wp;
struct window *w = wl->window;
struct window_pane *wp = target->wp, *new_wp;
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, *add, *errstr, *p;
char *cause = NULL, *cp; char *cause, *cp, *copy;
struct args_value *av; size_t plen;
u_int count = args_count(args), curval = 0; struct args_value *value;
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) {
if (args_has(args, 'f')) { plen = strlen(p);
if (p[plen - 1] == '%') {
copy = xstrdup(p);
copy[plen - 1] = '\0';
percentage = strtonum(copy, 0, INT_MAX, &errstr);
free(copy);
if (errstr != NULL) {
cmdq_error(item, "percentage %s", errstr);
return (CMD_RETURN_ERROR);
}
if (type == LAYOUT_TOPBOTTOM) if (type == LAYOUT_TOPBOTTOM)
curval = w->sy; size = (wp->sy * percentage) / 100;
else else
curval = w->sx; size = (wp->sx * percentage) / 100;
} else { } else {
if (type == LAYOUT_TOPBOTTOM) size = args_strtonum(args, 'l', 0, INT_MAX, &cause);
curval = wp->sy; if (cause != NULL) {
else cmdq_error(item, "lines %s", cause);
curval = wp->sx; free(cause);
return (CMD_RETURN_ERROR);
}
} }
}
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')) { } else if (args_has(args, 'p')) {
size = args_strtonum_and_expand(args, 'p', 0, 100, item, percentage = args_strtonum(args, 'p', 0, INT_MAX, &cause);
&cause); if (cause != NULL) {
if (cause == NULL) cmdq_error(item, "create pane failed: -p %s", cause);
size = curval * size / 100; free(cause);
} return (CMD_RETURN_ERROR);
if (cause != NULL) { }
cmdq_error(item, "size %s", cause); if (type == LAYOUT_TOPBOTTOM)
free(cause); size = (wp->sy * percentage) / 100;
return (CMD_RETURN_ERROR); else
} size = (wp->sx * percentage) / 100;
} else
size = -1;
window_push_zoom(wp->window, 1, args_has(args, 'Z')); server_unzoom_window(wp->window);
input = (args_has(args, 'I') && count == 0); input = (args_has(args, 'I') && args->argc == 0);
flags = 0; flags = 0;
if (args_has(args, 'b')) if (args_has(args, 'b'))
flags |= SPAWN_BEFORE; flags |= SPAWN_BEFORE;
if (args_has(args, 'f')) if (args_has(args, 'f'))
flags |= SPAWN_FULLSIZE; flags |= SPAWN_FULLSIZE;
if (input || (count == 1 && *args_string(args, 0) == '\0')) if (input || (args->argc == 1 && *args->argv[0] == '\0'))
flags |= SPAWN_EMPTY; flags |= SPAWN_EMPTY;
lc = layout_split_pane(wp, type, size, flags); lc = layout_split_pane(wp, type, size, flags);
@@ -123,6 +126,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
memset(&sc, 0, sizeof sc);
sc.item = item; sc.item = item;
sc.s = s; sc.s = s;
sc.wl = wl; sc.wl = wl;
@@ -130,13 +134,15 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
sc.wp0 = wp; sc.wp0 = wp;
sc.lc = lc; sc.lc = lc;
args_to_vector(args, &sc.argc, &sc.argv); sc.name = NULL;
sc.argc = args->argc;
sc.argv = args->argv;
sc.environ = environ_create(); sc.environ = environ_create();
av = args_first_value(args, 'e'); add = args_first_value(args, 'e', &value);
while (av != NULL) { while (add != NULL) {
environ_put(sc.environ, av->string, 0); environ_put(sc.environ, add);
av = args_next_value(av); add = args_next_value(&value);
} }
sc.idx = -1; sc.idx = -1;
@@ -145,44 +151,28 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
sc.flags = flags; sc.flags = flags;
if (args_has(args, 'd')) if (args_has(args, 'd'))
sc.flags |= SPAWN_DETACHED; sc.flags |= SPAWN_DETACHED;
if (args_has(args, 'Z'))
sc.flags |= SPAWN_ZOOM;
if ((new_wp = spawn_pane(&sc, &cause)) == NULL) { if ((new_wp = spawn_pane(&sc, &cause)) == NULL) {
cmdq_error(item, "create pane failed: %s", cause); cmdq_error(item, "create pane failed: %s", cause);
free(cause); free(cause);
if (sc.argv != NULL)
cmd_free_argv(sc.argc, sc.argv);
environ_free(sc.environ);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
if (input) { if (input && window_pane_start_input(new_wp, item, &cause) != 0) {
switch (window_pane_start_input(new_wp, item, &cause)) { layout_close_pane(new_wp);
case -1: window_remove_pane(wp->window, new_wp);
server_client_remove_pane(new_wp); cmdq_error(item, "%s", cause);
layout_close_pane(new_wp); free(cause);
window_remove_pane(wp->window, new_wp); return (CMD_RETURN_ERROR);
cmdq_error(item, "%s", cause);
free(cause);
if (sc.argv != NULL)
cmd_free_argv(sc.argc, sc.argv);
environ_free(sc.environ);
return (CMD_RETURN_ERROR);
case 1:
input = 0;
break;
}
} }
if (!args_has(args, 'd')) if (!args_has(args, 'd'))
cmd_find_from_winlink_pane(current, wl, new_wp, 0); cmd_find_from_winlink_pane(current, wl, new_wp, 0);
window_pop_zoom(wp->window);
server_redraw_window(wp->window); server_redraw_window(wp->window);
server_status_session(s); server_status_session(s);
if (args_has(args, 'P')) { if (args_has(args, 'P')) {
if ((template = args_get(args, 'F')) == NULL) if ((template = args_get(args, 'F')) == NULL)
template = SPLIT_WINDOW_TEMPLATE; template = SPLIT_WINDOW_TEMPLATE;
cp = format_single(item, template, tc, s, wl, new_wp); cp = format_single(item, template, c, s, wl, new_wp);
cmdq_print(item, "%s", cp); cmdq_print(item, "%s", cp);
free(cp); free(cp);
} }
@@ -190,8 +180,6 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
cmd_find_from_winlink_pane(&fs, wl, new_wp, 0); cmd_find_from_winlink_pane(&fs, wl, new_wp, 0);
cmdq_insert_hook(s, item, &fs, "after-split-window"); cmdq_insert_hook(s, item, &fs, "after-split-window");
if (sc.argv != NULL)
cmd_free_argv(sc.argc, sc.argv);
environ_free(sc.environ); environ_free(sc.environ);
if (input) if (input)
return (CMD_RETURN_WAIT); return (CMD_RETURN_WAIT);

View File

@@ -32,7 +32,7 @@ const struct cmd_entry cmd_swap_pane_entry = {
.name = "swap-pane", .name = "swap-pane",
.alias = "swapp", .alias = "swapp",
.args = { "dDs:t:UZ", 0, 0, NULL }, .args = { "dDs:t:UZ", 0, 0 },
.usage = "[-dDUZ] " CMD_SRCDST_PANE_USAGE, .usage = "[-dDUZ] " CMD_SRCDST_PANE_USAGE,
.source = { 's', CMD_FIND_PANE, CMD_FIND_DEFAULT_MARKED }, .source = { 's', CMD_FIND_PANE, CMD_FIND_DEFAULT_MARKED },
@@ -45,20 +45,18 @@ const struct cmd_entry cmd_swap_pane_entry = {
static enum cmd_retval static enum cmd_retval
cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item) cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *source = cmdq_get_source(item);
struct cmd_find_state *target = cmdq_get_target(item);
struct window *src_w, *dst_w; struct window *src_w, *dst_w;
struct window_pane *tmp_wp, *src_wp, *dst_wp; struct window_pane *tmp_wp, *src_wp, *dst_wp;
struct layout_cell *src_lc, *dst_lc; struct layout_cell *src_lc, *dst_lc;
u_int sx, sy, xoff, yoff; u_int sx, sy, xoff, yoff;
dst_w = target->wl->window; dst_w = item->target.wl->window;
dst_wp = target->wp; dst_wp = item->target.wp;
src_w = source->wl->window; src_w = item->source.wl->window;
src_wp = source->wp; src_wp = item->source.wp;
if (window_push_zoom(dst_w, 0, args_has(args, 'Z'))) if (window_push_zoom(dst_w, args_has(args, 'Z')))
server_redraw_window(dst_w); server_redraw_window(dst_w);
if (args_has(args, 'D')) { if (args_has(args, 'D')) {
@@ -73,15 +71,12 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
src_wp = TAILQ_LAST(&dst_w->panes, window_panes); src_wp = TAILQ_LAST(&dst_w->panes, window_panes);
} }
if (src_w != dst_w && window_push_zoom(src_w, 0, args_has(args, 'Z'))) if (src_w != dst_w && window_push_zoom(src_w, args_has(args, 'Z')))
server_redraw_window(src_w); server_redraw_window(src_w);
if (src_wp == dst_wp) if (src_wp == dst_wp)
goto out; goto out;
server_client_remove_pane(src_wp);
server_client_remove_pane(dst_wp);
tmp_wp = TAILQ_PREV(dst_wp, window_panes, entry); tmp_wp = TAILQ_PREV(dst_wp, window_panes, entry);
TAILQ_REMOVE(&dst_w->panes, dst_wp, entry); TAILQ_REMOVE(&dst_w->panes, dst_wp, entry);
TAILQ_REPLACE(&src_w->panes, src_wp, dst_wp, entry); TAILQ_REPLACE(&src_w->panes, src_wp, dst_wp, entry);
@@ -101,10 +96,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,20 +123,14 @@ 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);
if (src_w != dst_w)
notify_window("window-layout-changed", dst_w);
out: out:
if (window_pop_zoom(src_w)) if (window_pop_zoom(src_w))
server_redraw_window(src_w); server_redraw_window(src_w);

View File

@@ -32,7 +32,7 @@ const struct cmd_entry cmd_swap_window_entry = {
.name = "swap-window", .name = "swap-window",
.alias = "swapw", .alias = "swapw",
.args = { "ds:t:", 0, 0, NULL }, .args = { "ds:t:", 0, 0 },
.usage = "[-d] " CMD_SRCDST_WINDOW_USAGE, .usage = "[-d] " CMD_SRCDST_WINDOW_USAGE,
.source = { 's', CMD_FIND_WINDOW, CMD_FIND_DEFAULT_MARKED }, .source = { 's', CMD_FIND_WINDOW, CMD_FIND_DEFAULT_MARKED },
@@ -45,20 +45,20 @@ const struct cmd_entry cmd_swap_window_entry = {
static enum cmd_retval static enum cmd_retval
cmd_swap_window_exec(struct cmd *self, struct cmdq_item *item) cmd_swap_window_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct session *src, *dst;
struct cmd_find_state *source = cmdq_get_source(item);
struct cmd_find_state *target = cmdq_get_target(item);
struct session *src = source->s, *dst = target->s;
struct session_group *sg_src, *sg_dst; struct session_group *sg_src, *sg_dst;
struct winlink *wl_src = source->wl, *wl_dst = target->wl; struct winlink *wl_src, *wl_dst;
struct window *w_src, *w_dst; struct window *w_src, *w_dst;
wl_src = item->source.wl;
src = item->source.s;
sg_src = session_group_contains(src); sg_src = session_group_contains(src);
wl_dst = item->target.wl;
dst = item->target.s;
sg_dst = session_group_contains(dst); sg_dst = session_group_contains(dst);
if (src != dst && if (src != dst && sg_src != NULL && sg_dst != NULL &&
sg_src != NULL &&
sg_dst != NULL &&
sg_src == sg_dst) { sg_src == sg_dst) {
cmdq_error(item, "can't move window, sessions are grouped"); cmdq_error(item, "can't move window, sessions are grouped");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
@@ -77,9 +77,7 @@ cmd_swap_window_exec(struct cmd *self, struct cmdq_item *item)
wl_src->window = w_dst; wl_src->window = w_dst;
TAILQ_INSERT_TAIL(&w_dst->winlinks, wl_src, wentry); TAILQ_INSERT_TAIL(&w_dst->winlinks, wl_src, wentry);
if (marked_pane.wl == wl_src) if (args_has(self->args, 'd')) {
marked_pane.wl = wl_dst;
if (args_has(args, 'd')) {
session_select(dst, wl_dst->idx); session_select(dst, wl_dst->idx);
if (src != dst) if (src != dst)
session_select(src, wl_src->idx); session_select(src, wl_src->idx);

View File

@@ -34,26 +34,24 @@ const struct cmd_entry cmd_switch_client_entry = {
.name = "switch-client", .name = "switch-client",
.alias = "switchc", .alias = "switchc",
.args = { "lc:EFnpt:rT:Z", 0, 0, NULL }, .args = { "lc:Enpt:rT:Z", 0, 0 },
.usage = "[-ElnprZ] [-c target-client] [-t target-session] " .usage = "[-ElnprZ] [-c target-client] [-t target-session] "
"[-T key-table]", "[-T key-table]",
/* -t is special */ /* -t is special */
.flags = CMD_READONLY|CMD_CLIENT_CFLAG, .flags = CMD_READONLY,
.exec = cmd_switch_client_exec .exec = cmd_switch_client_exec
}; };
static enum cmd_retval static enum cmd_retval
cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item) cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
struct cmd_find_state *current = cmdq_get_current(item);
struct cmd_find_state target;
const char *tflag = args_get(args, 't'); const char *tflag = args_get(args, 't');
enum cmd_find_type type; enum cmd_find_type type;
int flags; int flags;
struct client *tc = cmdq_get_target_client(item); struct client *c;
struct session *s; struct session *s;
struct winlink *wl; struct winlink *wl;
struct window *w; struct window *w;
@@ -61,26 +59,25 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
const char *tablename; const char *tablename;
struct key_table *table; struct key_table *table;
if (tflag != NULL && if ((c = cmd_find_client(item, args_get(args, 'c'), 0)) == NULL)
(tflag[strcspn(tflag, ":.%")] != '\0' || strcmp(tflag, "=") == 0)) { return (CMD_RETURN_ERROR);
if (tflag != NULL && tflag[strcspn(tflag, ":.%")] != '\0') {
type = CMD_FIND_PANE; type = CMD_FIND_PANE;
flags = 0; flags = 0;
} else { } else {
type = CMD_FIND_SESSION; type = CMD_FIND_SESSION;
flags = CMD_FIND_PREFER_UNATTACHED; flags = CMD_FIND_PREFER_UNATTACHED;
} }
if (cmd_find_target(&target, item, tflag, type, flags) != 0) if (cmd_find_target(&item->target, item, tflag, type, flags) != 0)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
s = target.s; s = item->target.s;
wl = target.wl; wl = item->target.wl;
wp = target.wp; w = wl->window;
wp = item->target.wp;
if (args_has(args, 'r')) { if (args_has(args, 'r'))
if (tc->flags & CLIENT_READONLY) c->flags ^= CLIENT_READONLY;
tc->flags &= ~(CLIENT_READONLY|CLIENT_IGNORESIZE);
else
tc->flags |= (CLIENT_READONLY|CLIENT_IGNORESIZE);
}
tablename = args_get(args, 'T'); tablename = args_get(args, 'T');
if (tablename != NULL) { if (tablename != NULL) {
@@ -90,24 +87,24 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
table->references++; table->references++;
key_bindings_unref_table(tc->keytable); key_bindings_unref_table(c->keytable);
tc->keytable = table; c->keytable = table;
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (args_has(args, 'n')) { if (args_has(args, 'n')) {
if ((s = session_next_session(tc->session)) == NULL) { if ((s = session_next_session(c->session)) == NULL) {
cmdq_error(item, "can't find next session"); cmdq_error(item, "can't find next session");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} else if (args_has(args, 'p')) { } else if (args_has(args, 'p')) {
if ((s = session_previous_session(tc->session)) == NULL) { if ((s = session_previous_session(c->session)) == NULL) {
cmdq_error(item, "can't find previous session"); cmdq_error(item, "can't find previous session");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} else if (args_has(args, 'l')) { } else if (args_has(args, 'l')) {
if (tc->last_session != NULL && session_alive(tc->last_session)) if (c->last_session != NULL && session_alive(c->last_session))
s = tc->last_session; s = c->last_session;
else else
s = NULL; s = NULL;
if (s == NULL) { if (s == NULL) {
@@ -115,11 +112,10 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} else { } else {
if (cmdq_get_client(item) == NULL) if (item->client == NULL)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
if (wl != NULL && wp != NULL && wp != wl->window->active) { if (wl != NULL && wp != NULL) {
w = wl->window; if (window_push_zoom(w, args_has(self->args, 'Z')))
if (window_push_zoom(w, 0, args_has(args, 'Z')))
server_redraw_window(w); server_redraw_window(w);
window_redraw_active_switch(w, wp); window_redraw_active_switch(w, wp);
window_set_active_pane(w, wp, 1); window_set_active_pane(w, wp, 1);
@@ -128,16 +124,30 @@ cmd_switch_client_exec(struct cmd *self, struct cmdq_item *item)
} }
if (wl != NULL) { if (wl != NULL) {
session_set_current(s, wl); session_set_current(s, wl);
cmd_find_from_session(current, s, 0); cmd_find_from_session(&item->shared->current, s, 0);
} }
} }
if (!args_has(args, 'E')) if (!args_has(args, 'E'))
environ_update(s->options, tc->environ, s->environ); environ_update(s->options, c->environ, s->environ);
server_client_set_session(tc, s); if (c->session != NULL && c->session != s)
if (~cmdq_get_flags(item) & CMDQ_STATE_REPEAT) c->last_session = c->session;
server_client_set_key_table(tc, NULL); c->session = s;
if (~item->shared->flags & CMDQ_SHARED_REPEAT)
server_client_set_key_table(c, NULL);
tty_update_client_offset(c);
status_timer_start(c);
notify_client("client-session-changed", c);
session_update_activity(s, NULL);
gettimeofday(&s->last_attached_time, NULL);
server_check_unattached();
server_redraw_client(c);
s->curw->flags &= ~WINLINK_ALERTFLAGS;
s->curw->window->latest = c;
recalculate_sizes();
alerts_check_session(s);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@@ -32,8 +32,8 @@ const struct cmd_entry cmd_unbind_key_entry = {
.name = "unbind-key", .name = "unbind-key",
.alias = "unbind", .alias = "unbind",
.args = { "anqT:", 0, 1, NULL }, .args = { "anT:", 0, 1 },
.usage = "[-anq] [-T key-table] key", .usage = "[-an] [-T key-table] key",
.flags = CMD_AFTERHOOK, .flags = CMD_AFTERHOOK,
.exec = cmd_unbind_key_exec .exec = cmd_unbind_key_exec
@@ -42,57 +42,47 @@ const struct cmd_entry cmd_unbind_key_entry = {
static enum cmd_retval static enum cmd_retval
cmd_unbind_key_exec(struct cmd *self, struct cmdq_item *item) cmd_unbind_key_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
key_code key; key_code key;
const char *tablename, *keystr = args_string(args, 0); const char *tablename;
int quiet = args_has(args, 'q');
if (args_has(args, 'a')) { if (!args_has(args, 'a')) {
if (keystr != NULL) { if (args->argc != 1) {
if (!quiet) cmdq_error(item, "missing key");
cmdq_error(item, "key given with -a");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
key = key_string_lookup_string(args->argv[0]);
if (key == KEYC_NONE || key == KEYC_UNKNOWN) {
cmdq_error(item, "unknown key: %s", args->argv[0]);
return (CMD_RETURN_ERROR);
}
} else {
if (args->argc != 0) {
cmdq_error(item, "key given with -a");
return (CMD_RETURN_ERROR);
}
key = KEYC_UNKNOWN;
}
if (key == KEYC_UNKNOWN) {
tablename = args_get(args, 'T'); tablename = args_get(args, 'T');
if (tablename == NULL) { if (tablename == NULL) {
if (args_has(args, 'n')) key_bindings_remove_table("root");
tablename = "root"; key_bindings_remove_table("prefix");
else return (CMD_RETURN_NORMAL);
tablename = "prefix";
} }
if (key_bindings_get_table(tablename, 0) == NULL) { if (key_bindings_get_table(tablename, 0) == NULL) {
if (!quiet) { cmdq_error(item, "table %s doesn't exist", tablename);
cmdq_error(item, "table %s doesn't exist" ,
tablename);
}
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
key_bindings_remove_table(tablename); key_bindings_remove_table(tablename);
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
if (keystr == NULL) {
if (!quiet)
cmdq_error(item, "missing key");
return (CMD_RETURN_ERROR);
}
key = key_string_lookup_string(keystr);
if (key == KEYC_NONE || key == KEYC_UNKNOWN) {
if (!quiet)
cmdq_error(item, "unknown key: %s", keystr);
return (CMD_RETURN_ERROR);
}
if (args_has(args, 'T')) { if (args_has(args, 'T')) {
tablename = args_get(args, 'T'); tablename = args_get(args, 'T');
if (key_bindings_get_table(tablename, 0) == NULL) { if (key_bindings_get_table(tablename, 0) == NULL) {
if (!quiet) { cmdq_error(item, "table %s doesn't exist", tablename);
cmdq_error(item, "table %s doesn't exist" ,
tablename);
}
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} else if (args_has(args, 'n')) } else if (args_has(args, 'n'))

View File

@@ -34,7 +34,7 @@ const struct cmd_entry cmd_wait_for_entry = {
.name = "wait-for", .name = "wait-for",
.alias = "wait", .alias = "wait",
.args = { "LSU", 1, 1, NULL }, .args = { "LSU", 1, 1 },
.usage = "[-L|-S|-U] channel", .usage = "[-L|-S|-U] channel",
.flags = 0, .flags = 0,
@@ -120,12 +120,12 @@ cmd_wait_for_remove(struct wait_channel *wc)
static enum cmd_retval static enum cmd_retval
cmd_wait_for_exec(struct cmd *self, struct cmdq_item *item) cmd_wait_for_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = self->args;
const char *name = args_string(args, 0); const char *name = args->argv[0];
struct wait_channel *wc, find; struct wait_channel *wc, wc0;
find.name = name; wc0.name = name;
wc = RB_FIND(wait_channels, &wait_channels, &find); wc = RB_FIND(wait_channels, &wait_channels, &wc0);
if (args_has(args, 'S')) if (args_has(args, 'S'))
return (cmd_wait_for_signal(item, name, wc)); return (cmd_wait_for_signal(item, name, wc));
@@ -167,7 +167,7 @@ static enum cmd_retval
cmd_wait_for_wait(struct cmdq_item *item, const char *name, cmd_wait_for_wait(struct cmdq_item *item, const char *name,
struct wait_channel *wc) struct wait_channel *wc)
{ {
struct client *c = cmdq_get_client(item); struct client *c = item->client;
struct wait_item *wi; struct wait_item *wi;
if (c == NULL) { if (c == NULL) {
@@ -198,7 +198,7 @@ cmd_wait_for_lock(struct cmdq_item *item, const char *name,
{ {
struct wait_item *wi; struct wait_item *wi;
if (cmdq_get_client(item) == NULL) { if (item->client == NULL) {
cmdq_error(item, "not able to lock"); cmdq_error(item, "not able to lock");
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }

304
cmd.c
View File

@@ -35,18 +35,16 @@ extern const struct cmd_entry cmd_choose_buffer_entry;
extern const struct cmd_entry cmd_choose_client_entry; extern const struct cmd_entry cmd_choose_client_entry;
extern const struct cmd_entry cmd_choose_tree_entry; extern const struct cmd_entry cmd_choose_tree_entry;
extern const struct cmd_entry cmd_clear_history_entry; extern const struct cmd_entry cmd_clear_history_entry;
extern const struct cmd_entry cmd_clear_prompt_history_entry;
extern const struct cmd_entry cmd_clock_mode_entry; extern const struct cmd_entry cmd_clock_mode_entry;
extern const struct cmd_entry cmd_command_prompt_entry; extern const struct cmd_entry cmd_command_prompt_entry;
extern const struct cmd_entry cmd_confirm_before_entry; extern const struct cmd_entry cmd_confirm_before_entry;
extern const struct cmd_entry cmd_copy_mode_entry; extern const struct cmd_entry cmd_copy_mode_entry;
extern const struct cmd_entry cmd_customize_mode_entry;
extern const struct cmd_entry cmd_delete_buffer_entry; extern const struct cmd_entry cmd_delete_buffer_entry;
extern const struct cmd_entry cmd_detach_client_entry; extern const struct cmd_entry cmd_detach_client_entry;
extern const struct cmd_entry cmd_display_menu_entry; 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_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;
@@ -94,7 +92,6 @@ extern const struct cmd_entry cmd_select_pane_entry;
extern const struct cmd_entry cmd_select_window_entry; extern const struct cmd_entry cmd_select_window_entry;
extern const struct cmd_entry cmd_send_keys_entry; extern const struct cmd_entry cmd_send_keys_entry;
extern const struct cmd_entry cmd_send_prefix_entry; extern const struct cmd_entry cmd_send_prefix_entry;
extern const struct cmd_entry cmd_server_access_entry;
extern const struct cmd_entry cmd_set_buffer_entry; extern const struct cmd_entry cmd_set_buffer_entry;
extern const struct cmd_entry cmd_set_environment_entry; extern const struct cmd_entry cmd_set_environment_entry;
extern const struct cmd_entry cmd_set_hook_entry; extern const struct cmd_entry cmd_set_hook_entry;
@@ -105,7 +102,6 @@ extern const struct cmd_entry cmd_show_environment_entry;
extern const struct cmd_entry cmd_show_hooks_entry; extern const struct cmd_entry cmd_show_hooks_entry;
extern const struct cmd_entry cmd_show_messages_entry; extern const struct cmd_entry cmd_show_messages_entry;
extern const struct cmd_entry cmd_show_options_entry; extern const struct cmd_entry cmd_show_options_entry;
extern const struct cmd_entry cmd_show_prompt_history_entry;
extern const struct cmd_entry cmd_show_window_options_entry; extern const struct cmd_entry cmd_show_window_options_entry;
extern const struct cmd_entry cmd_source_file_entry; extern const struct cmd_entry cmd_source_file_entry;
extern const struct cmd_entry cmd_split_window_entry; extern const struct cmd_entry cmd_split_window_entry;
@@ -116,6 +112,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[] = {
@@ -127,17 +124,14 @@ const struct cmd_entry *cmd_table[] = {
&cmd_choose_client_entry, &cmd_choose_client_entry,
&cmd_choose_tree_entry, &cmd_choose_tree_entry,
&cmd_clear_history_entry, &cmd_clear_history_entry,
&cmd_clear_prompt_history_entry,
&cmd_clock_mode_entry, &cmd_clock_mode_entry,
&cmd_command_prompt_entry, &cmd_command_prompt_entry,
&cmd_confirm_before_entry, &cmd_confirm_before_entry,
&cmd_copy_mode_entry, &cmd_copy_mode_entry,
&cmd_customize_mode_entry,
&cmd_delete_buffer_entry, &cmd_delete_buffer_entry,
&cmd_detach_client_entry, &cmd_detach_client_entry,
&cmd_display_menu_entry, &cmd_display_menu_entry,
&cmd_display_message_entry, &cmd_display_message_entry,
&cmd_display_popup_entry,
&cmd_display_panes_entry, &cmd_display_panes_entry,
&cmd_find_window_entry, &cmd_find_window_entry,
&cmd_has_session_entry, &cmd_has_session_entry,
@@ -186,7 +180,6 @@ const struct cmd_entry *cmd_table[] = {
&cmd_select_window_entry, &cmd_select_window_entry,
&cmd_send_keys_entry, &cmd_send_keys_entry,
&cmd_send_prefix_entry, &cmd_send_prefix_entry,
&cmd_server_access_entry,
&cmd_set_buffer_entry, &cmd_set_buffer_entry,
&cmd_set_environment_entry, &cmd_set_environment_entry,
&cmd_set_hook_entry, &cmd_set_hook_entry,
@@ -197,7 +190,6 @@ const struct cmd_entry *cmd_table[] = {
&cmd_show_hooks_entry, &cmd_show_hooks_entry,
&cmd_show_messages_entry, &cmd_show_messages_entry,
&cmd_show_options_entry, &cmd_show_options_entry,
&cmd_show_prompt_history_entry,
&cmd_show_window_options_entry, &cmd_show_window_options_entry,
&cmd_source_file_entry, &cmd_source_file_entry,
&cmd_split_window_entry, &cmd_split_window_entry,
@@ -212,24 +204,8 @@ const struct cmd_entry *cmd_table[] = {
NULL NULL
}; };
/* Instance of a command. */
struct cmd {
const struct cmd_entry *entry;
struct args *args;
u_int group;
char *file;
u_int line;
int parse_flags;
TAILQ_ENTRY(cmd) qentry;
};
TAILQ_HEAD(cmds, cmd);
/* Next group number for new command list. */
static u_int cmd_list_next_group = 1; static u_int cmd_list_next_group = 1;
/* Log an argument vector. */
void printflike(3, 4) void printflike(3, 4)
cmd_log_argv(int argc, char **argv, const char *fmt, ...) cmd_log_argv(int argc, char **argv, const char *fmt, ...)
{ {
@@ -246,9 +222,8 @@ cmd_log_argv(int argc, char **argv, const char *fmt, ...)
free(prefix); free(prefix);
} }
/* Prepend to an argument vector. */
void void
cmd_prepend_argv(int *argc, char ***argv, const char *arg) cmd_prepend_argv(int *argc, char ***argv, char *arg)
{ {
char **new_argv; char **new_argv;
int i; int i;
@@ -263,15 +238,13 @@ cmd_prepend_argv(int *argc, char ***argv, const char *arg)
(*argc)++; (*argc)++;
} }
/* Append to an argument vector. */
void void
cmd_append_argv(int *argc, char ***argv, const char *arg) cmd_append_argv(int *argc, char ***argv, char *arg)
{ {
*argv = xreallocarray(*argv, (*argc) + 1, sizeof **argv); *argv = xreallocarray(*argv, (*argc) + 1, sizeof **argv);
(*argv)[(*argc)++] = xstrdup(arg); (*argv)[(*argc)++] = xstrdup(arg);
} }
/* Pack an argument vector up into a buffer. */
int int
cmd_pack_argv(int argc, char **argv, char *buf, size_t len) cmd_pack_argv(int argc, char **argv, char *buf, size_t len)
{ {
@@ -294,7 +267,6 @@ cmd_pack_argv(int argc, char **argv, char *buf, size_t len)
return (0); return (0);
} }
/* Unpack an argument vector from a packed buffer. */
int int
cmd_unpack_argv(char *buf, size_t len, int argc, char ***argv) cmd_unpack_argv(char *buf, size_t len, int argc, char ***argv)
{ {
@@ -323,7 +295,6 @@ cmd_unpack_argv(char *buf, size_t len, int argc, char ***argv)
return (0); return (0);
} }
/* Copy an argument vector, ensuring it is terminated by NULL. */
char ** char **
cmd_copy_argv(int argc, char **argv) cmd_copy_argv(int argc, char **argv)
{ {
@@ -340,7 +311,6 @@ cmd_copy_argv(int argc, char **argv)
return (new_argv); return (new_argv);
} }
/* Free an argument vector. */
void void
cmd_free_argv(int argc, char **argv) cmd_free_argv(int argc, char **argv)
{ {
@@ -353,74 +323,32 @@ cmd_free_argv(int argc, char **argv)
free(argv); free(argv);
} }
/* Convert argument vector to a string. */
char * char *
cmd_stringify_argv(int argc, char **argv) cmd_stringify_argv(int argc, char **argv)
{ {
char *buf = NULL, *s; char *buf;
size_t len = 0;
int i; int i;
size_t len;
if (argc == 0) if (argc == 0)
return (xstrdup("")); return (xstrdup(""));
for (i = 0; i < argc; i++) { len = 0;
s = args_escape(argv[i]); buf = NULL;
log_debug("%s: %u %s = %s", __func__, i, argv[i], s);
len += strlen(s) + 1; for (i = 0; i < argc; i++) {
len += strlen(argv[i]) + 1;
buf = xrealloc(buf, len); buf = xrealloc(buf, len);
if (i == 0) if (i == 0)
*buf = '\0'; *buf = '\0';
else else
strlcat(buf, " ", len); strlcat(buf, " ", len);
strlcat(buf, s, len); strlcat(buf, argv[i], len);
free(s);
} }
return (buf); return (buf);
} }
/* Get entry for command. */
const struct cmd_entry *
cmd_get_entry(struct cmd *cmd)
{
return (cmd->entry);
}
/* Get arguments for command. */
struct args *
cmd_get_args(struct cmd *cmd)
{
return (cmd->args);
}
/* Get group for command. */
u_int
cmd_get_group(struct cmd *cmd)
{
return (cmd->group);
}
/* Get file and line for command. */
void
cmd_get_source(struct cmd *cmd, const char **file, u_int *line)
{
if (file != NULL)
*file = cmd->file;
if (line != NULL)
*line = cmd->line;
}
/* Get parse flags for command. */
int
cmd_get_parse_flags(struct cmd *cmd)
{
return (cmd->parse_flags);
}
/* Look for an alias for a command. */
char * char *
cmd_get_alias(const char *name) cmd_get_alias(const char *name)
{ {
@@ -451,8 +379,7 @@ cmd_get_alias(const char *name)
return (NULL); return (NULL);
} }
/* Look up a command entry by name. */ static const struct cmd_entry *
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;
@@ -501,75 +428,66 @@ ambiguous:
return (NULL); return (NULL);
} }
/* Parse a single command from an argument vector. */
struct cmd * struct cmd *
cmd_parse(struct args_value *values, u_int count, const char *file, u_int line, cmd_parse(int argc, char **argv, const char *file, u_int line, char **cause)
int parse_flags, char **cause)
{ {
const struct cmd_entry *entry; const struct cmd_entry *entry;
const char *name;
struct cmd *cmd; struct cmd *cmd;
struct args *args; struct args *args;
char *error = NULL;
if (count == 0 || values[0].type != ARGS_STRING) { if (argc == 0) {
xasprintf(cause, "no command"); xasprintf(cause, "no command");
return (NULL); return (NULL);
} }
entry = cmd_find(values[0].string, cause); name = argv[0];
entry = cmd_find(name, cause);
if (entry == NULL) if (entry == NULL)
return (NULL); return (NULL);
cmd_log_argv(argc, argv, "%s: %s", __func__, entry->name);
args = args_parse(&entry->args, values, count, &error); args = args_parse(entry->args.template, argc, argv);
if (args == NULL && error == NULL) { if (args == NULL)
xasprintf(cause, "usage: %s %s", entry->name, entry->usage); goto usage;
return (NULL); if (entry->args.lower != -1 && args->argc < entry->args.lower)
} goto usage;
if (args == NULL) { if (entry->args.upper != -1 && args->argc > entry->args.upper)
xasprintf(cause, "command %s: %s", entry->name, error); goto usage;
free(error);
return (NULL);
}
cmd = xcalloc(1, sizeof *cmd); cmd = xcalloc(1, sizeof *cmd);
cmd->entry = entry; cmd->entry = entry;
cmd->args = args; cmd->args = args;
cmd->parse_flags = parse_flags;
if (file != NULL) if (file != NULL)
cmd->file = xstrdup(file); cmd->file = xstrdup(file);
cmd->line = line; cmd->line = line;
cmd->alias = NULL;
cmd->argc = argc;
cmd->argv = cmd_copy_argv(argc, argv);
return (cmd); return (cmd);
usage:
if (args != NULL)
args_free(args);
xasprintf(cause, "usage: %s %s", entry->name, entry->usage);
return (NULL);
} }
/* Free a command. */
void void
cmd_free(struct cmd *cmd) cmd_free(struct cmd *cmd)
{ {
free(cmd->alias);
cmd_free_argv(cmd->argc, cmd->argv);
free(cmd->file); free(cmd->file);
args_free(cmd->args); args_free(cmd->args);
free(cmd); free(cmd);
} }
/* Copy a command. */
struct cmd *
cmd_copy(struct cmd *cmd, int argc, char **argv)
{
struct cmd *new_cmd;
new_cmd = xcalloc(1, sizeof *new_cmd);
new_cmd->entry = cmd->entry;
new_cmd->args = args_copy(cmd->args, argc, argv);
if (cmd->file != NULL)
new_cmd->file = xstrdup(cmd->file);
new_cmd->line = cmd->line;
return (new_cmd);
}
/* Get a command as a string. */
char * char *
cmd_print(struct cmd *cmd) cmd_print(struct cmd *cmd)
{ {
@@ -585,7 +503,6 @@ cmd_print(struct cmd *cmd)
return (out); return (out);
} }
/* Create a new command list. */
struct cmd_list * struct cmd_list *
cmd_list_new(void) cmd_list_new(void)
{ {
@@ -594,39 +511,29 @@ cmd_list_new(void)
cmdlist = xcalloc(1, sizeof *cmdlist); cmdlist = xcalloc(1, sizeof *cmdlist);
cmdlist->references = 1; cmdlist->references = 1;
cmdlist->group = cmd_list_next_group++; cmdlist->group = cmd_list_next_group++;
cmdlist->list = xcalloc(1, sizeof *cmdlist->list); TAILQ_INIT(&cmdlist->list);
TAILQ_INIT(cmdlist->list);
return (cmdlist); return (cmdlist);
} }
/* Append a command to a command list. */
void void
cmd_list_append(struct cmd_list *cmdlist, struct cmd *cmd) cmd_list_append(struct cmd_list *cmdlist, struct cmd *cmd)
{ {
cmd->group = cmdlist->group; cmd->group = cmdlist->group;
TAILQ_INSERT_TAIL(cmdlist->list, cmd, qentry); TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry);
} }
/* Append all commands from one list to another. */
void
cmd_list_append_all(struct cmd_list *cmdlist, struct cmd_list *from)
{
struct cmd *cmd;
TAILQ_FOREACH(cmd, from->list, qentry)
cmd->group = cmdlist->group;
TAILQ_CONCAT(cmdlist->list, from->list, qentry);
}
/* Move all commands from one command list to another. */
void void
cmd_list_move(struct cmd_list *cmdlist, struct cmd_list *from) cmd_list_move(struct cmd_list *cmdlist, struct cmd_list *from)
{ {
TAILQ_CONCAT(cmdlist->list, from->list, qentry); struct cmd *cmd, *cmd1;
TAILQ_FOREACH_SAFE(cmd, &from->list, qentry, cmd1) {
TAILQ_REMOVE(&from->list, cmd, qentry);
TAILQ_INSERT_TAIL(&cmdlist->list, cmd, qentry);
}
cmdlist->group = cmd_list_next_group++; cmdlist->group = cmd_list_next_group++;
} }
/* Free a command list. */
void void
cmd_list_free(struct cmd_list *cmdlist) cmd_list_free(struct cmd_list *cmdlist)
{ {
@@ -635,77 +542,36 @@ cmd_list_free(struct cmd_list *cmdlist)
if (--cmdlist->references != 0) if (--cmdlist->references != 0)
return; return;
TAILQ_FOREACH_SAFE(cmd, cmdlist->list, qentry, cmd1) { TAILQ_FOREACH_SAFE(cmd, &cmdlist->list, qentry, cmd1) {
TAILQ_REMOVE(cmdlist->list, cmd, qentry); TAILQ_REMOVE(&cmdlist->list, cmd, qentry);
cmd_free(cmd); cmd_free(cmd);
} }
free(cmdlist->list);
free(cmdlist); free(cmdlist);
} }
/* Copy a command list, expanding %s in arguments. */ char *
struct cmd_list * cmd_list_print(struct cmd_list *cmdlist, int escaped)
cmd_list_copy(const struct cmd_list *cmdlist, int argc, char **argv)
{ {
struct cmd *cmd; struct cmd *cmd;
struct cmd_list *new_cmdlist;
struct cmd *new_cmd;
u_int group = cmdlist->group;
char *s;
s = cmd_list_print(cmdlist, 0);
log_debug("%s: %s", __func__, s);
free(s);
new_cmdlist = cmd_list_new();
TAILQ_FOREACH(cmd, cmdlist->list, qentry) {
if (cmd->group != group) {
new_cmdlist->group = cmd_list_next_group++;
group = cmd->group;
}
new_cmd = cmd_copy(cmd, argc, argv);
cmd_list_append(new_cmdlist, new_cmd);
}
s = cmd_list_print(new_cmdlist, 0);
log_debug("%s: %s", __func__, s);
free(s);
return (new_cmdlist);
}
/* Get a command list as a string. */
char *
cmd_list_print(const struct cmd_list *cmdlist, int escaped)
{
struct cmd *cmd, *next;
char *buf, *this; char *buf, *this;
size_t len; size_t len;
len = 1; len = 1;
buf = xcalloc(1, len); buf = xcalloc(1, len);
TAILQ_FOREACH(cmd, cmdlist->list, qentry) { TAILQ_FOREACH(cmd, &cmdlist->list, qentry) {
this = cmd_print(cmd); this = cmd_print(cmd);
len += strlen(this) + 6; len += strlen(this) + 4;
buf = xrealloc(buf, len); buf = xrealloc(buf, len);
strlcat(buf, this, len); strlcat(buf, this, len);
if (TAILQ_NEXT(cmd, qentry) != NULL) {
next = TAILQ_NEXT(cmd, qentry); if (escaped)
if (next != NULL) { strlcat(buf, " \\; ", len);
if (cmd->group != next->group) { else
if (escaped) strlcat(buf, " ; ", len);
strlcat(buf, " \\;\\; ", len);
else
strlcat(buf, " ;; ", len);
} else {
if (escaped)
strlcat(buf, " \\; ", len);
else
strlcat(buf, " ; ", len);
}
} }
free(this); free(this);
@@ -714,46 +580,6 @@ cmd_list_print(const struct cmd_list *cmdlist, int escaped)
return (buf); return (buf);
} }
/* Get first command in list. */
struct cmd *
cmd_list_first(struct cmd_list *cmdlist)
{
return (TAILQ_FIRST(cmdlist->list));
}
/* Get next command in list. */
struct cmd *
cmd_list_next(struct cmd *cmd)
{
return (TAILQ_NEXT(cmd, qentry));
}
/* Do all of the commands in this command list have this flag? */
int
cmd_list_all_have(struct cmd_list *cmdlist, int flag)
{
struct cmd *cmd;
TAILQ_FOREACH(cmd, cmdlist->list, qentry) {
if (~cmd->entry->flags & flag)
return (0);
}
return (1);
}
/* Do any of the commands in this command list have this flag? */
int
cmd_list_any_have(struct cmd_list *cmdlist, int flag)
{
struct cmd *cmd;
TAILQ_FOREACH(cmd, cmdlist->list, qentry) {
if (cmd->entry->flags & flag)
return (1);
}
return (0);
}
/* Adjust current mouse position for a pane. */ /* Adjust current mouse position for a pane. */
int int
cmd_mouse_at(struct window_pane *wp, struct mouse_event *m, u_int *xp, cmd_mouse_at(struct window_pane *wp, struct mouse_event *m, u_int *xp,
@@ -819,14 +645,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;

829
colour.c
View File

@@ -22,7 +22,6 @@
#include <ctype.h> #include <ctype.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <math.h>
#include "tmux.h" #include "tmux.h"
@@ -105,21 +104,6 @@ colour_split_rgb(int c, u_char *r, u_char *g, u_char *b)
*b = c & 0xff; *b = c & 0xff;
} }
/* Force colour to RGB if not already. */
int
colour_force_rgb(int c)
{
if (c & COLOUR_FLAG_RGB)
return (c);
if (c & COLOUR_FLAG_256)
return (colour_256toRGB(c));
if (c >= 0 && c <= 7)
return (colour_256toRGB(c));
if (c >= 90 && c <= 97)
return (colour_256toRGB(8 + c - 90));
return (-1);
}
/* Convert colour to a string. */ /* Convert colour to a string. */
const char * const char *
colour_tostring(int c) colour_tostring(int c)
@@ -127,9 +111,6 @@ colour_tostring(int c)
static char s[32]; static char s[32];
u_char r, g, b; u_char r, g, b;
if (c == -1)
return ("none");
if (c & COLOUR_FLAG_RGB) { if (c & COLOUR_FLAG_RGB) {
colour_split_rgb(c, &r, &g, &b); colour_split_rgb(c, &r, &g, &b);
xsnprintf(s, sizeof s, "#%02x%02x%02x", r, g, b); xsnprintf(s, sizeof s, "#%02x%02x%02x", r, g, b);
@@ -182,46 +163,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)
@@ -248,12 +189,6 @@ colour_fromstring(const char *s)
return (-1); return (-1);
return (n | COLOUR_FLAG_256); return (n | COLOUR_FLAG_256);
} }
if (strncasecmp(s, "color", (sizeof "color") - 1) == 0) {
n = strtonum(s + (sizeof "color") - 1, 0, 255, &errstr);
if (errstr != NULL)
return (-1);
return (n | COLOUR_FLAG_256);
}
if (strcasecmp(s, "default") == 0) if (strcasecmp(s, "default") == 0)
return (8); return (8);
@@ -292,7 +227,7 @@ colour_fromstring(const char *s)
return (96); return (96);
if (strcasecmp(s, "brightwhite") == 0 || strcmp(s, "97") == 0) if (strcasecmp(s, "brightwhite") == 0 || strcmp(s, "97") == 0)
return (97); return (97);
return (colour_byname(s)); return (-1);
} }
/* Convert 256 colour to RGB colour. */ /* Convert 256 colour to RGB colour. */
@@ -394,765 +329,3 @@ colour_256to16(int c)
return (table[c & 0xff]); return (table[c & 0xff]);
} }
/* Get colour by X11 colour name. */
int
colour_byname(const char *name)
{
static const struct {
const char *name;
int c;
} colours[] = {
{ "AliceBlue", 0xf0f8ff },
{ "AntiqueWhite", 0xfaebd7 },
{ "AntiqueWhite1", 0xffefdb },
{ "AntiqueWhite2", 0xeedfcc },
{ "AntiqueWhite3", 0xcdc0b0 },
{ "AntiqueWhite4", 0x8b8378 },
{ "BlanchedAlmond", 0xffebcd },
{ "BlueViolet", 0x8a2be2 },
{ "CadetBlue", 0x5f9ea0 },
{ "CadetBlue1", 0x98f5ff },
{ "CadetBlue2", 0x8ee5ee },
{ "CadetBlue3", 0x7ac5cd },
{ "CadetBlue4", 0x53868b },
{ "CornflowerBlue", 0x6495ed },
{ "DarkBlue", 0x00008b },
{ "DarkCyan", 0x008b8b },
{ "DarkGoldenrod", 0xb8860b },
{ "DarkGoldenrod1", 0xffb90f },
{ "DarkGoldenrod2", 0xeead0e },
{ "DarkGoldenrod3", 0xcd950c },
{ "DarkGoldenrod4", 0x8b6508 },
{ "DarkGray", 0xa9a9a9 },
{ "DarkGreen", 0x006400 },
{ "DarkGrey", 0xa9a9a9 },
{ "DarkKhaki", 0xbdb76b },
{ "DarkMagenta", 0x8b008b },
{ "DarkOliveGreen", 0x556b2f },
{ "DarkOliveGreen1", 0xcaff70 },
{ "DarkOliveGreen2", 0xbcee68 },
{ "DarkOliveGreen3", 0xa2cd5a },
{ "DarkOliveGreen4", 0x6e8b3d },
{ "DarkOrange", 0xff8c00 },
{ "DarkOrange1", 0xff7f00 },
{ "DarkOrange2", 0xee7600 },
{ "DarkOrange3", 0xcd6600 },
{ "DarkOrange4", 0x8b4500 },
{ "DarkOrchid", 0x9932cc },
{ "DarkOrchid1", 0xbf3eff },
{ "DarkOrchid2", 0xb23aee },
{ "DarkOrchid3", 0x9a32cd },
{ "DarkOrchid4", 0x68228b },
{ "DarkRed", 0x8b0000 },
{ "DarkSalmon", 0xe9967a },
{ "DarkSeaGreen", 0x8fbc8f },
{ "DarkSeaGreen1", 0xc1ffc1 },
{ "DarkSeaGreen2", 0xb4eeb4 },
{ "DarkSeaGreen3", 0x9bcd9b },
{ "DarkSeaGreen4", 0x698b69 },
{ "DarkSlateBlue", 0x483d8b },
{ "DarkSlateGray", 0x2f4f4f },
{ "DarkSlateGray1", 0x97ffff },
{ "DarkSlateGray2", 0x8deeee },
{ "DarkSlateGray3", 0x79cdcd },
{ "DarkSlateGray4", 0x528b8b },
{ "DarkSlateGrey", 0x2f4f4f },
{ "DarkTurquoise", 0x00ced1 },
{ "DarkViolet", 0x9400d3 },
{ "DeepPink", 0xff1493 },
{ "DeepPink1", 0xff1493 },
{ "DeepPink2", 0xee1289 },
{ "DeepPink3", 0xcd1076 },
{ "DeepPink4", 0x8b0a50 },
{ "DeepSkyBlue", 0x00bfff },
{ "DeepSkyBlue1", 0x00bfff },
{ "DeepSkyBlue2", 0x00b2ee },
{ "DeepSkyBlue3", 0x009acd },
{ "DeepSkyBlue4", 0x00688b },
{ "DimGray", 0x696969 },
{ "DimGrey", 0x696969 },
{ "DodgerBlue", 0x1e90ff },
{ "DodgerBlue1", 0x1e90ff },
{ "DodgerBlue2", 0x1c86ee },
{ "DodgerBlue3", 0x1874cd },
{ "DodgerBlue4", 0x104e8b },
{ "FloralWhite", 0xfffaf0 },
{ "ForestGreen", 0x228b22 },
{ "GhostWhite", 0xf8f8ff },
{ "GreenYellow", 0xadff2f },
{ "HotPink", 0xff69b4 },
{ "HotPink1", 0xff6eb4 },
{ "HotPink2", 0xee6aa7 },
{ "HotPink3", 0xcd6090 },
{ "HotPink4", 0x8b3a62 },
{ "IndianRed", 0xcd5c5c },
{ "IndianRed1", 0xff6a6a },
{ "IndianRed2", 0xee6363 },
{ "IndianRed3", 0xcd5555 },
{ "IndianRed4", 0x8b3a3a },
{ "LavenderBlush", 0xfff0f5 },
{ "LavenderBlush1", 0xfff0f5 },
{ "LavenderBlush2", 0xeee0e5 },
{ "LavenderBlush3", 0xcdc1c5 },
{ "LavenderBlush4", 0x8b8386 },
{ "LawnGreen", 0x7cfc00 },
{ "LemonChiffon", 0xfffacd },
{ "LemonChiffon1", 0xfffacd },
{ "LemonChiffon2", 0xeee9bf },
{ "LemonChiffon3", 0xcdc9a5 },
{ "LemonChiffon4", 0x8b8970 },
{ "LightBlue", 0xadd8e6 },
{ "LightBlue1", 0xbfefff },
{ "LightBlue2", 0xb2dfee },
{ "LightBlue3", 0x9ac0cd },
{ "LightBlue4", 0x68838b },
{ "LightCoral", 0xf08080 },
{ "LightCyan", 0xe0ffff },
{ "LightCyan1", 0xe0ffff },
{ "LightCyan2", 0xd1eeee },
{ "LightCyan3", 0xb4cdcd },
{ "LightCyan4", 0x7a8b8b },
{ "LightGoldenrod", 0xeedd82 },
{ "LightGoldenrod1", 0xffec8b },
{ "LightGoldenrod2", 0xeedc82 },
{ "LightGoldenrod3", 0xcdbe70 },
{ "LightGoldenrod4", 0x8b814c },
{ "LightGoldenrodYellow", 0xfafad2 },
{ "LightGray", 0xd3d3d3 },
{ "LightGreen", 0x90ee90 },
{ "LightGrey", 0xd3d3d3 },
{ "LightPink", 0xffb6c1 },
{ "LightPink1", 0xffaeb9 },
{ "LightPink2", 0xeea2ad },
{ "LightPink3", 0xcd8c95 },
{ "LightPink4", 0x8b5f65 },
{ "LightSalmon", 0xffa07a },
{ "LightSalmon1", 0xffa07a },
{ "LightSalmon2", 0xee9572 },
{ "LightSalmon3", 0xcd8162 },
{ "LightSalmon4", 0x8b5742 },
{ "LightSeaGreen", 0x20b2aa },
{ "LightSkyBlue", 0x87cefa },
{ "LightSkyBlue1", 0xb0e2ff },
{ "LightSkyBlue2", 0xa4d3ee },
{ "LightSkyBlue3", 0x8db6cd },
{ "LightSkyBlue4", 0x607b8b },
{ "LightSlateBlue", 0x8470ff },
{ "LightSlateGray", 0x778899 },
{ "LightSlateGrey", 0x778899 },
{ "LightSteelBlue", 0xb0c4de },
{ "LightSteelBlue1", 0xcae1ff },
{ "LightSteelBlue2", 0xbcd2ee },
{ "LightSteelBlue3", 0xa2b5cd },
{ "LightSteelBlue4", 0x6e7b8b },
{ "LightYellow", 0xffffe0 },
{ "LightYellow1", 0xffffe0 },
{ "LightYellow2", 0xeeeed1 },
{ "LightYellow3", 0xcdcdb4 },
{ "LightYellow4", 0x8b8b7a },
{ "LimeGreen", 0x32cd32 },
{ "MediumAquamarine", 0x66cdaa },
{ "MediumBlue", 0x0000cd },
{ "MediumOrchid", 0xba55d3 },
{ "MediumOrchid1", 0xe066ff },
{ "MediumOrchid2", 0xd15fee },
{ "MediumOrchid3", 0xb452cd },
{ "MediumOrchid4", 0x7a378b },
{ "MediumPurple", 0x9370db },
{ "MediumPurple1", 0xab82ff },
{ "MediumPurple2", 0x9f79ee },
{ "MediumPurple3", 0x8968cd },
{ "MediumPurple4", 0x5d478b },
{ "MediumSeaGreen", 0x3cb371 },
{ "MediumSlateBlue", 0x7b68ee },
{ "MediumSpringGreen", 0x00fa9a },
{ "MediumTurquoise", 0x48d1cc },
{ "MediumVioletRed", 0xc71585 },
{ "MidnightBlue", 0x191970 },
{ "MintCream", 0xf5fffa },
{ "MistyRose", 0xffe4e1 },
{ "MistyRose1", 0xffe4e1 },
{ "MistyRose2", 0xeed5d2 },
{ "MistyRose3", 0xcdb7b5 },
{ "MistyRose4", 0x8b7d7b },
{ "NavajoWhite", 0xffdead },
{ "NavajoWhite1", 0xffdead },
{ "NavajoWhite2", 0xeecfa1 },
{ "NavajoWhite3", 0xcdb38b },
{ "NavajoWhite4", 0x8b795e },
{ "NavyBlue", 0x000080 },
{ "OldLace", 0xfdf5e6 },
{ "OliveDrab", 0x6b8e23 },
{ "OliveDrab1", 0xc0ff3e },
{ "OliveDrab2", 0xb3ee3a },
{ "OliveDrab3", 0x9acd32 },
{ "OliveDrab4", 0x698b22 },
{ "OrangeRed", 0xff4500 },
{ "OrangeRed1", 0xff4500 },
{ "OrangeRed2", 0xee4000 },
{ "OrangeRed3", 0xcd3700 },
{ "OrangeRed4", 0x8b2500 },
{ "PaleGoldenrod", 0xeee8aa },
{ "PaleGreen", 0x98fb98 },
{ "PaleGreen1", 0x9aff9a },
{ "PaleGreen2", 0x90ee90 },
{ "PaleGreen3", 0x7ccd7c },
{ "PaleGreen4", 0x548b54 },
{ "PaleTurquoise", 0xafeeee },
{ "PaleTurquoise1", 0xbbffff },
{ "PaleTurquoise2", 0xaeeeee },
{ "PaleTurquoise3", 0x96cdcd },
{ "PaleTurquoise4", 0x668b8b },
{ "PaleVioletRed", 0xdb7093 },
{ "PaleVioletRed1", 0xff82ab },
{ "PaleVioletRed2", 0xee799f },
{ "PaleVioletRed3", 0xcd6889 },
{ "PaleVioletRed4", 0x8b475d },
{ "PapayaWhip", 0xffefd5 },
{ "PeachPuff", 0xffdab9 },
{ "PeachPuff1", 0xffdab9 },
{ "PeachPuff2", 0xeecbad },
{ "PeachPuff3", 0xcdaf95 },
{ "PeachPuff4", 0x8b7765 },
{ "PowderBlue", 0xb0e0e6 },
{ "RebeccaPurple", 0x663399 },
{ "RosyBrown", 0xbc8f8f },
{ "RosyBrown1", 0xffc1c1 },
{ "RosyBrown2", 0xeeb4b4 },
{ "RosyBrown3", 0xcd9b9b },
{ "RosyBrown4", 0x8b6969 },
{ "RoyalBlue", 0x4169e1 },
{ "RoyalBlue1", 0x4876ff },
{ "RoyalBlue2", 0x436eee },
{ "RoyalBlue3", 0x3a5fcd },
{ "RoyalBlue4", 0x27408b },
{ "SaddleBrown", 0x8b4513 },
{ "SandyBrown", 0xf4a460 },
{ "SeaGreen", 0x2e8b57 },
{ "SeaGreen1", 0x54ff9f },
{ "SeaGreen2", 0x4eee94 },
{ "SeaGreen3", 0x43cd80 },
{ "SeaGreen4", 0x2e8b57 },
{ "SkyBlue", 0x87ceeb },
{ "SkyBlue1", 0x87ceff },
{ "SkyBlue2", 0x7ec0ee },
{ "SkyBlue3", 0x6ca6cd },
{ "SkyBlue4", 0x4a708b },
{ "SlateBlue", 0x6a5acd },
{ "SlateBlue1", 0x836fff },
{ "SlateBlue2", 0x7a67ee },
{ "SlateBlue3", 0x6959cd },
{ "SlateBlue4", 0x473c8b },
{ "SlateGray", 0x708090 },
{ "SlateGray1", 0xc6e2ff },
{ "SlateGray2", 0xb9d3ee },
{ "SlateGray3", 0x9fb6cd },
{ "SlateGray4", 0x6c7b8b },
{ "SlateGrey", 0x708090 },
{ "SpringGreen", 0x00ff7f },
{ "SpringGreen1", 0x00ff7f },
{ "SpringGreen2", 0x00ee76 },
{ "SpringGreen3", 0x00cd66 },
{ "SpringGreen4", 0x008b45 },
{ "SteelBlue", 0x4682b4 },
{ "SteelBlue1", 0x63b8ff },
{ "SteelBlue2", 0x5cacee },
{ "SteelBlue3", 0x4f94cd },
{ "SteelBlue4", 0x36648b },
{ "VioletRed", 0xd02090 },
{ "VioletRed1", 0xff3e96 },
{ "VioletRed2", 0xee3a8c },
{ "VioletRed3", 0xcd3278 },
{ "VioletRed4", 0x8b2252 },
{ "WebGray", 0x808080 },
{ "WebGreen", 0x008000 },
{ "WebGrey", 0x808080 },
{ "WebMaroon", 0x800000 },
{ "WebPurple", 0x800080 },
{ "WhiteSmoke", 0xf5f5f5 },
{ "X11Gray", 0xbebebe },
{ "X11Green", 0x00ff00 },
{ "X11Grey", 0xbebebe },
{ "X11Maroon", 0xb03060 },
{ "X11Purple", 0xa020f0 },
{ "YellowGreen", 0x9acd32 },
{ "alice blue", 0xf0f8ff },
{ "antique white", 0xfaebd7 },
{ "aqua", 0x00ffff },
{ "aquamarine", 0x7fffd4 },
{ "aquamarine1", 0x7fffd4 },
{ "aquamarine2", 0x76eec6 },
{ "aquamarine3", 0x66cdaa },
{ "aquamarine4", 0x458b74 },
{ "azure", 0xf0ffff },
{ "azure1", 0xf0ffff },
{ "azure2", 0xe0eeee },
{ "azure3", 0xc1cdcd },
{ "azure4", 0x838b8b },
{ "beige", 0xf5f5dc },
{ "bisque", 0xffe4c4 },
{ "bisque1", 0xffe4c4 },
{ "bisque2", 0xeed5b7 },
{ "bisque3", 0xcdb79e },
{ "bisque4", 0x8b7d6b },
{ "black", 0x000000 },
{ "blanched almond", 0xffebcd },
{ "blue violet", 0x8a2be2 },
{ "blue", 0x0000ff },
{ "blue1", 0x0000ff },
{ "blue2", 0x0000ee },
{ "blue3", 0x0000cd },
{ "blue4", 0x00008b },
{ "brown", 0xa52a2a },
{ "brown1", 0xff4040 },
{ "brown2", 0xee3b3b },
{ "brown3", 0xcd3333 },
{ "brown4", 0x8b2323 },
{ "burlywood", 0xdeb887 },
{ "burlywood1", 0xffd39b },
{ "burlywood2", 0xeec591 },
{ "burlywood3", 0xcdaa7d },
{ "burlywood4", 0x8b7355 },
{ "cadet blue", 0x5f9ea0 },
{ "chartreuse", 0x7fff00 },
{ "chartreuse1", 0x7fff00 },
{ "chartreuse2", 0x76ee00 },
{ "chartreuse3", 0x66cd00 },
{ "chartreuse4", 0x458b00 },
{ "chocolate", 0xd2691e },
{ "chocolate1", 0xff7f24 },
{ "chocolate2", 0xee7621 },
{ "chocolate3", 0xcd661d },
{ "chocolate4", 0x8b4513 },
{ "coral", 0xff7f50 },
{ "coral1", 0xff7256 },
{ "coral2", 0xee6a50 },
{ "coral3", 0xcd5b45 },
{ "coral4", 0x8b3e2f },
{ "cornflower blue", 0x6495ed },
{ "cornsilk", 0xfff8dc },
{ "cornsilk1", 0xfff8dc },
{ "cornsilk2", 0xeee8cd },
{ "cornsilk3", 0xcdc8b1 },
{ "cornsilk4", 0x8b8878 },
{ "crimson", 0xdc143c },
{ "cyan", 0x00ffff },
{ "cyan1", 0x00ffff },
{ "cyan2", 0x00eeee },
{ "cyan3", 0x00cdcd },
{ "cyan4", 0x008b8b },
{ "dark blue", 0x00008b },
{ "dark cyan", 0x008b8b },
{ "dark goldenrod", 0xb8860b },
{ "dark gray", 0xa9a9a9 },
{ "dark green", 0x006400 },
{ "dark grey", 0xa9a9a9 },
{ "dark khaki", 0xbdb76b },
{ "dark magenta", 0x8b008b },
{ "dark olive green", 0x556b2f },
{ "dark orange", 0xff8c00 },
{ "dark orchid", 0x9932cc },
{ "dark red", 0x8b0000 },
{ "dark salmon", 0xe9967a },
{ "dark sea green", 0x8fbc8f },
{ "dark slate blue", 0x483d8b },
{ "dark slate gray", 0x2f4f4f },
{ "dark slate grey", 0x2f4f4f },
{ "dark turquoise", 0x00ced1 },
{ "dark violet", 0x9400d3 },
{ "deep pink", 0xff1493 },
{ "deep sky blue", 0x00bfff },
{ "dim gray", 0x696969 },
{ "dim grey", 0x696969 },
{ "dodger blue", 0x1e90ff },
{ "firebrick", 0xb22222 },
{ "firebrick1", 0xff3030 },
{ "firebrick2", 0xee2c2c },
{ "firebrick3", 0xcd2626 },
{ "firebrick4", 0x8b1a1a },
{ "floral white", 0xfffaf0 },
{ "forest green", 0x228b22 },
{ "fuchsia", 0xff00ff },
{ "gainsboro", 0xdcdcdc },
{ "ghost white", 0xf8f8ff },
{ "gold", 0xffd700 },
{ "gold1", 0xffd700 },
{ "gold2", 0xeec900 },
{ "gold3", 0xcdad00 },
{ "gold4", 0x8b7500 },
{ "goldenrod", 0xdaa520 },
{ "goldenrod1", 0xffc125 },
{ "goldenrod2", 0xeeb422 },
{ "goldenrod3", 0xcd9b1d },
{ "goldenrod4", 0x8b6914 },
{ "green yellow", 0xadff2f },
{ "green", 0x00ff00 },
{ "green1", 0x00ff00 },
{ "green2", 0x00ee00 },
{ "green3", 0x00cd00 },
{ "green4", 0x008b00 },
{ "honeydew", 0xf0fff0 },
{ "honeydew1", 0xf0fff0 },
{ "honeydew2", 0xe0eee0 },
{ "honeydew3", 0xc1cdc1 },
{ "honeydew4", 0x838b83 },
{ "hot pink", 0xff69b4 },
{ "indian red", 0xcd5c5c },
{ "indigo", 0x4b0082 },
{ "ivory", 0xfffff0 },
{ "ivory1", 0xfffff0 },
{ "ivory2", 0xeeeee0 },
{ "ivory3", 0xcdcdc1 },
{ "ivory4", 0x8b8b83 },
{ "khaki", 0xf0e68c },
{ "khaki1", 0xfff68f },
{ "khaki2", 0xeee685 },
{ "khaki3", 0xcdc673 },
{ "khaki4", 0x8b864e },
{ "lavender blush", 0xfff0f5 },
{ "lavender", 0xe6e6fa },
{ "lawn green", 0x7cfc00 },
{ "lemon chiffon", 0xfffacd },
{ "light blue", 0xadd8e6 },
{ "light coral", 0xf08080 },
{ "light cyan", 0xe0ffff },
{ "light goldenrod yellow", 0xfafad2 },
{ "light goldenrod", 0xeedd82 },
{ "light gray", 0xd3d3d3 },
{ "light green", 0x90ee90 },
{ "light grey", 0xd3d3d3 },
{ "light pink", 0xffb6c1 },
{ "light salmon", 0xffa07a },
{ "light sea green", 0x20b2aa },
{ "light sky blue", 0x87cefa },
{ "light slate blue", 0x8470ff },
{ "light slate gray", 0x778899 },
{ "light slate grey", 0x778899 },
{ "light steel blue", 0xb0c4de },
{ "light yellow", 0xffffe0 },
{ "lime green", 0x32cd32 },
{ "lime", 0x00ff00 },
{ "linen", 0xfaf0e6 },
{ "magenta", 0xff00ff },
{ "magenta1", 0xff00ff },
{ "magenta2", 0xee00ee },
{ "magenta3", 0xcd00cd },
{ "magenta4", 0x8b008b },
{ "maroon", 0xb03060 },
{ "maroon1", 0xff34b3 },
{ "maroon2", 0xee30a7 },
{ "maroon3", 0xcd2990 },
{ "maroon4", 0x8b1c62 },
{ "medium aquamarine", 0x66cdaa },
{ "medium blue", 0x0000cd },
{ "medium orchid", 0xba55d3 },
{ "medium purple", 0x9370db },
{ "medium sea green", 0x3cb371 },
{ "medium slate blue", 0x7b68ee },
{ "medium spring green", 0x00fa9a },
{ "medium turquoise", 0x48d1cc },
{ "medium violet red", 0xc71585 },
{ "midnight blue", 0x191970 },
{ "mint cream", 0xf5fffa },
{ "misty rose", 0xffe4e1 },
{ "moccasin", 0xffe4b5 },
{ "navajo white", 0xffdead },
{ "navy blue", 0x000080 },
{ "navy", 0x000080 },
{ "old lace", 0xfdf5e6 },
{ "olive drab", 0x6b8e23 },
{ "olive", 0x808000 },
{ "orange red", 0xff4500 },
{ "orange", 0xffa500 },
{ "orange1", 0xffa500 },
{ "orange2", 0xee9a00 },
{ "orange3", 0xcd8500 },
{ "orange4", 0x8b5a00 },
{ "orchid", 0xda70d6 },
{ "orchid1", 0xff83fa },
{ "orchid2", 0xee7ae9 },
{ "orchid3", 0xcd69c9 },
{ "orchid4", 0x8b4789 },
{ "pale goldenrod", 0xeee8aa },
{ "pale green", 0x98fb98 },
{ "pale turquoise", 0xafeeee },
{ "pale violet red", 0xdb7093 },
{ "papaya whip", 0xffefd5 },
{ "peach puff", 0xffdab9 },
{ "peru", 0xcd853f },
{ "pink", 0xffc0cb },
{ "pink1", 0xffb5c5 },
{ "pink2", 0xeea9b8 },
{ "pink3", 0xcd919e },
{ "pink4", 0x8b636c },
{ "plum", 0xdda0dd },
{ "plum1", 0xffbbff },
{ "plum2", 0xeeaeee },
{ "plum3", 0xcd96cd },
{ "plum4", 0x8b668b },
{ "powder blue", 0xb0e0e6 },
{ "purple", 0xa020f0 },
{ "purple1", 0x9b30ff },
{ "purple2", 0x912cee },
{ "purple3", 0x7d26cd },
{ "purple4", 0x551a8b },
{ "rebecca purple", 0x663399 },
{ "red", 0xff0000 },
{ "red1", 0xff0000 },
{ "red2", 0xee0000 },
{ "red3", 0xcd0000 },
{ "red4", 0x8b0000 },
{ "rosy brown", 0xbc8f8f },
{ "royal blue", 0x4169e1 },
{ "saddle brown", 0x8b4513 },
{ "salmon", 0xfa8072 },
{ "salmon1", 0xff8c69 },
{ "salmon2", 0xee8262 },
{ "salmon3", 0xcd7054 },
{ "salmon4", 0x8b4c39 },
{ "sandy brown", 0xf4a460 },
{ "sea green", 0x2e8b57 },
{ "seashell", 0xfff5ee },
{ "seashell1", 0xfff5ee },
{ "seashell2", 0xeee5de },
{ "seashell3", 0xcdc5bf },
{ "seashell4", 0x8b8682 },
{ "sienna", 0xa0522d },
{ "sienna1", 0xff8247 },
{ "sienna2", 0xee7942 },
{ "sienna3", 0xcd6839 },
{ "sienna4", 0x8b4726 },
{ "silver", 0xc0c0c0 },
{ "sky blue", 0x87ceeb },
{ "slate blue", 0x6a5acd },
{ "slate gray", 0x708090 },
{ "slate grey", 0x708090 },
{ "snow", 0xfffafa },
{ "snow1", 0xfffafa },
{ "snow2", 0xeee9e9 },
{ "snow3", 0xcdc9c9 },
{ "snow4", 0x8b8989 },
{ "spring green", 0x00ff7f },
{ "steel blue", 0x4682b4 },
{ "tan", 0xd2b48c },
{ "tan1", 0xffa54f },
{ "tan2", 0xee9a49 },
{ "tan3", 0xcd853f },
{ "tan4", 0x8b5a2b },
{ "teal", 0x008080 },
{ "thistle", 0xd8bfd8 },
{ "thistle1", 0xffe1ff },
{ "thistle2", 0xeed2ee },
{ "thistle3", 0xcdb5cd },
{ "thistle4", 0x8b7b8b },
{ "tomato", 0xff6347 },
{ "tomato1", 0xff6347 },
{ "tomato2", 0xee5c42 },
{ "tomato3", 0xcd4f39 },
{ "tomato4", 0x8b3626 },
{ "turquoise", 0x40e0d0 },
{ "turquoise1", 0x00f5ff },
{ "turquoise2", 0x00e5ee },
{ "turquoise3", 0x00c5cd },
{ "turquoise4", 0x00868b },
{ "violet red", 0xd02090 },
{ "violet", 0xee82ee },
{ "web gray", 0x808080 },
{ "web green", 0x008000 },
{ "web grey", 0x808080 },
{ "web maroon", 0x800000 },
{ "web purple", 0x800080 },
{ "wheat", 0xf5deb3 },
{ "wheat1", 0xffe7ba },
{ "wheat2", 0xeed8ae },
{ "wheat3", 0xcdba96 },
{ "wheat4", 0x8b7e66 },
{ "white smoke", 0xf5f5f5 },
{ "white", 0xffffff },
{ "x11 gray", 0xbebebe },
{ "x11 green", 0x00ff00 },
{ "x11 grey", 0xbebebe },
{ "x11 maroon", 0xb03060 },
{ "x11 purple", 0xa020f0 },
{ "yellow green", 0x9acd32 },
{ "yellow", 0xffff00 },
{ "yellow1", 0xffff00 },
{ "yellow2", 0xeeee00 },
{ "yellow3", 0xcdcd00 },
{ "yellow4", 0x8b8b00 }
};
u_int i;
int c;
const char *errstr;
if (strncasecmp(name, "grey", 4) == 0 ||
strncasecmp(name, "gray", 4) == 0) {
if (name[4] == '\0')
return (0xbebebe|COLOUR_FLAG_RGB);
c = strtonum(name + 4, 0, 100, &errstr);
if (errstr != NULL)
return (-1);
c = round(2.55 * c);
if (c < 0 || c > 255)
return (-1);
return (colour_join_rgb(c, c, c));
}
for (i = 0; i < nitems(colours); i++) {
if (strcasecmp(colours[i].name, name) == 0)
return (colours[i].c|COLOUR_FLAG_RGB);
}
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. */
void
colour_palette_init(struct colour_palette *p)
{
p->fg = 8;
p->bg = 8;
p->palette = NULL;
p->default_palette = NULL;
}
/* Clear palette. */
void
colour_palette_clear(struct colour_palette *p)
{
if (p != NULL) {
p->fg = 8;
p->bg = 8;
free(p->palette);
p->palette = NULL;
}
}
/* Free a palette. */
void
colour_palette_free(struct colour_palette *p)
{
if (p != NULL) {
free(p->palette);
p->palette = NULL;
free(p->default_palette);
p->default_palette = NULL;
}
}
/* Get a colour from a palette. */
int
colour_palette_get(struct colour_palette *p, int c)
{
if (p == NULL)
return (-1);
if (c >= 90 && c <= 97)
c = 8 + c - 90;
else if (c & COLOUR_FLAG_256)
c &= ~COLOUR_FLAG_256;
else if (c >= 8)
return (-1);
if (p->palette != NULL && p->palette[c] != -1)
return (p->palette[c]);
if (p->default_palette != NULL && p->default_palette[c] != -1)
return (p->default_palette[c]);
return (-1);
}
/* Set a colour in a palette. */
int
colour_palette_set(struct colour_palette *p, int n, int c)
{
u_int i;
if (p == NULL || n > 255)
return (0);
if (c == -1 && p->palette == NULL)
return (0);
if (c != -1 && p->palette == NULL) {
if (p->palette == NULL)
p->palette = xcalloc(256, sizeof *p->palette);
for (i = 0; i < 256; i++)
p->palette[i] = -1;
}
p->palette[n] = c;
return (1);
}
/* Build palette defaults from an option. */
void
colour_palette_from_option(struct colour_palette *p, struct options *oo)
{
struct options_entry *o;
struct options_array_item *a;
u_int i, n;
int c;
if (p == NULL)
return;
o = options_get(oo, "pane-colours");
if ((a = options_array_first(o)) == NULL) {
if (p->default_palette != NULL) {
free(p->default_palette);
p->default_palette = NULL;
}
return;
}
if (p->default_palette == NULL)
p->default_palette = xcalloc(256, sizeof *p->default_palette);
for (i = 0; i < 256; i++)
p->default_palette[i] = -1;
while (a != NULL) {
n = options_array_item_index(a);
if (n < 256) {
c = options_array_item_value(a)->number;
p->default_palette[n] = c;
}
a = options_array_next(a);
}
}

105
compat.h
View File

@@ -27,43 +27,10 @@
#include <termios.h> #include <termios.h>
#include <wchar.h> #include <wchar.h>
#ifdef HAVE_EVENT2_EVENT_H
#include <event2/event.h>
#include <event2/event_compat.h>
#include <event2/event_struct.h>
#include <event2/buffer.h>
#include <event2/buffer_compat.h>
#include <event2/bufferevent.h>
#include <event2/bufferevent_struct.h>
#include <event2/bufferevent_compat.h>
#else
#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
#ifdef HAVE_MALLOC_TRIM
#include <malloc.h>
#endif
#ifdef HAVE_UTF8PROC
#include <utf8proc.h>
#endif
#ifndef __GNUC__ #ifndef __GNUC__
#define __attribute__(a) #define __attribute__(a)
#endif #endif
#ifdef BROKEN___DEAD
#undef __dead
#endif
#ifndef __unused #ifndef __unused
#define __unused __attribute__ ((__unused__)) #define __unused __attribute__ ((__unused__))
#endif #endif
@@ -73,9 +40,6 @@
#ifndef __packed #ifndef __packed
#define __packed __attribute__ ((__packed__)) #define __packed __attribute__ ((__packed__))
#endif #endif
#ifndef __weak
#define __weak __attribute__ ((__weak__))
#endif
#ifndef ECHOPRT #ifndef ECHOPRT
#define ECHOPRT 0 #define ECHOPRT 0
@@ -126,18 +90,10 @@ void warnx(const char *, ...);
#define _PATH_DEFPATH "/usr/bin:/bin" #define _PATH_DEFPATH "/usr/bin:/bin"
#endif #endif
#ifndef _PATH_VI
#define _PATH_VI "/usr/bin/vi"
#endif
#ifndef __OpenBSD__ #ifndef __OpenBSD__
#define pledge(s, p) (0) #define pledge(s, p) (0)
#endif #endif
#ifndef IMAXBEL
#define IMAXBEL 0
#endif
#ifdef HAVE_STDINT_H #ifdef HAVE_STDINT_H
#include <stdint.h> #include <stdint.h>
#else #else
@@ -273,13 +229,6 @@ void warnx(const char *, ...);
#define HOST_NAME_MAX 255 #define HOST_NAME_MAX 255
#endif #endif
#ifndef CLOCK_REALTIME
#define CLOCK_REALTIME 0
#endif
#ifndef CLOCK_MONOTONIC
#define CLOCK_MONOTONIC CLOCK_REALTIME
#endif
#ifndef HAVE_FLOCK #ifndef HAVE_FLOCK
#define LOCK_SH 0 #define LOCK_SH 0
#define LOCK_EX 0 #define LOCK_EX 0
@@ -297,11 +246,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,23 +291,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
/* getpeereid.c */
int getpeereid(int, uid_t *, gid_t *);
#endif
#ifndef HAVE_DAEMON #ifndef HAVE_DAEMON
/* daemon.c */ /* daemon.c */
int daemon(int, int); int daemon(int, int);
@@ -379,11 +306,6 @@ const char *getprogname(void);
void setproctitle(const char *, ...); void setproctitle(const char *, ...);
#endif #endif
#ifndef HAVE_CLOCK_GETTIME
/* clock_gettime.c */
int clock_gettime(int, struct timespec *);
#endif
#ifndef HAVE_B64_NTOP #ifndef HAVE_B64_NTOP
/* base64.c */ /* base64.c */
#undef b64_ntop #undef b64_ntop
@@ -415,11 +337,6 @@ int vasprintf(char **, const char *, va_list);
char *fgetln(FILE *, size_t *); char *fgetln(FILE *, size_t *);
#endif #endif
#ifndef HAVE_GETLINE
/* getline.c */
ssize_t getline(char **, size_t *, FILE *);
#endif
#ifndef HAVE_SETENV #ifndef HAVE_SETENV
/* setenv.c */ /* setenv.c */
int setenv(const char *, const char *, int); int setenv(const char *, const char *, int);
@@ -446,13 +363,6 @@ void *reallocarray(void *, size_t, size_t);
void *recallocarray(void *, size_t, size_t, size_t); void *recallocarray(void *, size_t, size_t, size_t);
#endif #endif
#ifdef HAVE_SYSTEMD
/* systemd.c */
int systemd_activated(void);
int systemd_create_socket(int, char **);
int systemd_move_to_new_cgroup(char **);
#endif
#ifdef HAVE_UTF8PROC #ifdef HAVE_UTF8PROC
/* utf8proc.c */ /* utf8proc.c */
int utf8proc_wcwidth(wchar_t); int utf8proc_wcwidth(wchar_t);
@@ -460,17 +370,12 @@ int utf8proc_mbtowc(wchar_t *, const char *, size_t);
int utf8proc_wctomb(char *, wchar_t); int utf8proc_wctomb(char *, wchar_t);
#endif #endif
#ifdef NEED_FUZZING
/* tmux.c */
#define main __weak main
#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

@@ -1,37 +0,0 @@
/*
* Copyright (c) 2021 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 <sys/time.h>
#include "compat.h"
#ifndef TIMEVAL_TO_TIMESPEC
#define TIMEVAL_TO_TIMESPEC(tv, ts) do { \
(ts)->tv_sec = (tv)->tv_sec; \
(ts)->tv_nsec = (tv)->tv_usec * 1000; \
} while (0)
#endif
int
clock_gettime(__unused int clock, struct timespec *ts)
{
struct timeval tv;
gettimeofday(&tv, NULL);
TIMEVAL_TO_TIMESPEC(&tv, ts);
return 0;
}

View File

@@ -44,9 +44,6 @@
# include <ndir.h> # include <ndir.h>
# endif # endif
#endif #endif
#if defined(HAVE_LIBPROC_H)
# include <libproc.h>
#endif
#include "compat.h" #include "compat.h"
@@ -58,15 +55,39 @@
__unused static const char rcsid[] = "$Sudo: closefrom.c,v 1.11 2006/08/17 15:26:54 millert Exp $"; __unused static const char rcsid[] = "$Sudo: closefrom.c,v 1.11 2006/08/17 15:26:54 millert Exp $";
#endif /* lint */ #endif /* lint */
#ifndef HAVE_FCNTL_CLOSEM
/* /*
* Close all file descriptors greater than or equal to lowfd. * Close all file descriptors greater than or equal to lowfd.
*/ */
static void #ifdef HAVE_FCNTL_CLOSEM
closefrom_fallback(int lowfd) void
closefrom(int lowfd)
{ {
long fd, maxfd; (void) fcntl(lowfd, F_CLOSEM, 0);
}
#else
void
closefrom(int lowfd)
{
long fd, maxfd;
#if defined(HAVE_DIRFD) && defined(HAVE_PROC_PID)
char fdpath[PATH_MAX], *endp;
struct dirent *dent;
DIR *dirp;
int len;
/* Check for a /proc/$$/fd directory. */
len = snprintf(fdpath, sizeof(fdpath), "/proc/%ld/fd", (long)getpid());
if (len > 0 && (size_t)len <= sizeof(fdpath) && (dirp = opendir(fdpath))) {
while ((dent = readdir(dirp)) != NULL) {
fd = strtol(dent->d_name, &endp, 10);
if (dent->d_name != endp && *endp == '\0' &&
fd >= 0 && fd < INT_MAX && fd >= lowfd && fd != dirfd(dirp))
(void) close((int) fd);
}
(void) closedir(dirp);
} else
#endif
{
/* /*
* Fall back on sysconf() or getdtablesize(). We avoid checking * Fall back on sysconf() or getdtablesize(). We avoid checking
* resource limits since it is possible to open a file descriptor * resource limits since it is possible to open a file descriptor
@@ -78,78 +99,11 @@ closefrom_fallback(int lowfd)
maxfd = getdtablesize(); maxfd = getdtablesize();
#endif /* HAVE_SYSCONF */ #endif /* HAVE_SYSCONF */
if (maxfd < 0) if (maxfd < 0)
maxfd = OPEN_MAX; maxfd = OPEN_MAX;
for (fd = lowfd; fd < maxfd; fd++) for (fd = lowfd; fd < maxfd; fd++)
(void) close((int) fd); (void) close((int) fd);
}
#endif /* HAVE_FCNTL_CLOSEM */
#ifdef HAVE_FCNTL_CLOSEM
void
closefrom(int lowfd)
{
(void) fcntl(lowfd, F_CLOSEM, 0);
}
#elif defined(HAVE_LIBPROC_H) && defined(HAVE_PROC_PIDINFO)
void
closefrom(int lowfd)
{
int i, r, sz;
pid_t pid = getpid();
struct proc_fdinfo *fdinfo_buf = NULL;
sz = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0);
if (sz == 0)
return; /* no fds, really? */
else if (sz == -1)
goto fallback;
if ((fdinfo_buf = malloc(sz)) == NULL)
goto fallback;
r = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fdinfo_buf, sz);
if (r < 0 || r > sz)
goto fallback;
for (i = 0; i < r / (int)PROC_PIDLISTFD_SIZE; i++) {
if (fdinfo_buf[i].proc_fd >= lowfd)
close(fdinfo_buf[i].proc_fd);
}
free(fdinfo_buf);
return;
fallback:
free(fdinfo_buf);
closefrom_fallback(lowfd);
return;
}
#elif defined(HAVE_DIRFD) && defined(HAVE_PROC_PID)
void
closefrom(int lowfd)
{
long fd;
char fdpath[PATH_MAX], *endp;
struct dirent *dent;
DIR *dirp;
int len;
/* Check for a /proc/$$/fd directory. */
len = snprintf(fdpath, sizeof(fdpath), "/proc/%ld/fd", (long)getpid());
if (len > 0 && (size_t)len < sizeof(fdpath) && (dirp = opendir(fdpath))) {
while ((dent = readdir(dirp)) != NULL) {
fd = strtol(dent->d_name, &endp, 10);
if (dent->d_name != endp && *endp == '\0' &&
fd >= 0 && fd < INT_MAX && fd >= lowfd && fd != dirfd(dirp))
(void) close((int) fd);
}
(void) closedir(dirp);
return;
} }
/* /proc/$$/fd strategy failed, fall back to brute force closure */
closefrom_fallback(lowfd);
}
#else
void
closefrom(int lowfd)
{
closefrom_fallback(lowfd);
} }
#endif /* !HAVE_FCNTL_CLOSEM */ #endif /* !HAVE_FCNTL_CLOSEM */
#endif /* HAVE_CLOSEFROM */ #endif /* HAVE_CLOSEFROM */

View File

@@ -49,12 +49,12 @@
#include <mach/mach.h> #include <mach/mach.h>
#include <AvailabilityMacros.h> #include <Availability.h>
#include <unistd.h> #include <unistd.h>
void daemon_darwin(void); void daemon_darwin(void);
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101000 #ifdef __MAC_10_10
extern kern_return_t bootstrap_look_up_per_user(mach_port_t, const char *, extern kern_return_t bootstrap_look_up_per_user(mach_port_t, const char *,
uid_t, mach_port_t *); uid_t, mach_port_t *);

View File

@@ -1,82 +0,0 @@
/*
* Copyright (c) 2008 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 <sys/ioctl.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include "compat.h"
void fatal(const char *, ...);
void fatalx(const char *, ...);
pid_t
forkpty(int *master, char *name, struct termios *tio, struct winsize *ws)
{
int slave = -1;
char *path;
pid_t pid;
if ((*master = open("/dev/ptmx", O_RDWR|O_NOCTTY)) == -1)
return (-1);
if (grantpt(*master) != 0)
goto out;
if (unlockpt(*master) != 0)
goto out;
if ((path = ptsname(*master)) == NULL)
goto out;
if (name != NULL)
strlcpy(name, path, TTY_NAME_MAX);
if ((slave = open(path, O_RDWR|O_NOCTTY)) == -1)
goto out;
switch (pid = fork()) {
case -1:
goto out;
case 0:
close(*master);
setsid();
if (ioctl(slave, TIOCSCTTY, NULL) == -1)
fatal("ioctl failed");
if (tio != NULL && tcsetattr(slave, TCSAFLUSH, tio) == -1)
fatal("tcsetattr failed");
if (ioctl(slave, TIOCSWINSZ, ws) == -1)
fatal("ioctl failed");
dup2(slave, 0);
dup2(slave, 1);
dup2(slave, 2);
if (slave > 2)
close(slave);
return (0);
}
close(slave);
return (pid);
out:
if (*master != -1)
close(*master);
if (slave != -1)
close(slave);
return (-1);
}

View File

@@ -18,28 +18,13 @@
#include <glob.h> #include <glob.h>
#include <unistd.h> #include <unistd.h>
#if defined(HAVE_LIBPROC_H)
#include <libproc.h>
#endif
#include "compat.h" #include "compat.h"
void fatal(const char *, ...); void fatal(const char *, ...);
void fatalx(const char *, ...); void fatalx(const char *, ...);
#if defined(HAVE_LIBPROC_H) && defined(HAVE_PROC_PIDINFO) #ifdef HAVE_PROC_PID
int
getdtablecount(void)
{
int sz;
pid_t pid = getpid();
sz = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0);
if (sz == -1)
return (0);
return (sz / PROC_PIDLISTFD_SIZE);
}
#elif defined(HAVE_PROC_PID)
int int
getdtablecount(void) getdtablecount(void)
{ {

View File

@@ -1,29 +0,0 @@
/*
* Copyright (c) 2020 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <unistd.h>
#include "compat.h"
#ifdef HAVE_SYSCONF
int
getdtablesize(void)
{
return (sysconf(_SC_OPEN_MAX));
}
#endif

View File

@@ -1,93 +0,0 @@
/* $NetBSD: getline.c,v 1.1.1.6 2015/01/02 20:34:27 christos Exp $ */
/* NetBSD: getline.c,v 1.2 2014/09/16 17:23:50 christos Exp */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Christos Zoulas.
*
* 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.
*/
/* NETBSD ORIGINAL: external/bsd/file/dist/src/getline.c */
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include "tmux.h"
static ssize_t
getdelim(char **buf, size_t *bufsiz, int delimiter, FILE *fp)
{
char *ptr, *eptr;
if (*buf == NULL || *bufsiz == 0) {
if ((*buf = malloc(BUFSIZ)) == NULL)
return -1;
*bufsiz = BUFSIZ;
}
for (ptr = *buf, eptr = *buf + *bufsiz;;) {
int c = fgetc(fp);
if (c == -1) {
if (feof(fp)) {
ssize_t diff = (ssize_t)(ptr - *buf);
if (diff != 0) {
*ptr = '\0';
return diff;
}
}
return -1;
}
*ptr++ = c;
if (c == delimiter) {
*ptr = '\0';
return ptr - *buf;
}
if (ptr + 2 >= eptr) {
char *nbuf;
size_t nbufsiz = *bufsiz * 2;
ssize_t d = ptr - *buf;
if ((nbuf = realloc(*buf, nbufsiz)) == NULL)
return -1;
*buf = nbuf;
*bufsiz = nbufsiz;
eptr = nbuf + nbufsiz;
ptr = nbuf + d;
}
}
}
ssize_t
getline(char **buf, size_t *bufsiz, FILE *fp)
{
return getdelim(buf, bufsiz, '\n', fp);
}

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

@@ -1,57 +0,0 @@
/*
* Copyright (c) 2022 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 <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#ifdef HAVE_UCRED_H
#include <ucred.h>
#endif
#include "compat.h"
int
getpeereid(int s, uid_t *uid, gid_t *gid)
{
#ifdef HAVE_SO_PEERCRED
struct ucred uc;
int len = sizeof uc;
if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &uc, &len) == -1)
return (-1);
*uid = uc.uid;
*gid = uc.gid;
return (0);
#elif defined(HAVE_GETPEERUCRED)
ucred_t *ucred = NULL;
if (getpeerucred(s, &ucred) == -1)
return (-1);
if ((*uid = ucred_geteuid(ucred)) == -1)
return (-1);
if ((*gid = ucred_getrgid(ucred)) == -1)
return (-1);
ucred_free(ucred);
return (0);
#else
*uid = geteuid();
*gid = getegid();
return (0);
#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

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