mirror of
https://github.com/tmux/tmux.git
synced 2026-08-02 21:48:59 +00:00
Merge branch 'master' into layout-custom-format
This commit is contained in:
1
.github/workflows/regress.yml
vendored
1
.github/workflows/regress.yml
vendored
@@ -75,7 +75,6 @@ jobs:
|
||||
- name: test
|
||||
run: |
|
||||
cd regress
|
||||
export ASAN_OPTIONS="abort_on_error=1:detect_leaks=0"
|
||||
${{ matrix.make }}
|
||||
|
||||
- name: logs
|
||||
|
||||
10
Makefile.am
10
Makefile.am
@@ -161,13 +161,16 @@ dist_tmux_SOURCES = \
|
||||
control-notify.c \
|
||||
control.c \
|
||||
environ.c \
|
||||
events-payload.c \
|
||||
events.c \
|
||||
file.c \
|
||||
format.c \
|
||||
format-draw.c \
|
||||
format.c \
|
||||
fuzzy.c \
|
||||
grid-reader.c \
|
||||
grid-view.c \
|
||||
grid.c \
|
||||
hooks.c \
|
||||
hyperlinks.c \
|
||||
input-keys.c \
|
||||
input.c \
|
||||
@@ -182,14 +185,13 @@ dist_tmux_SOURCES = \
|
||||
mode-tree.c \
|
||||
monitor.c \
|
||||
names.c \
|
||||
notify.c \
|
||||
options-table.c \
|
||||
options.c \
|
||||
paste.c \
|
||||
popup.c \
|
||||
proc.c \
|
||||
prompt.c \
|
||||
prompt-history.c \
|
||||
prompt.c \
|
||||
regsub.c \
|
||||
resize.c \
|
||||
screen-redraw.c \
|
||||
@@ -204,9 +206,9 @@ dist_tmux_SOURCES = \
|
||||
spawn.c \
|
||||
status.c \
|
||||
style.c \
|
||||
tmux-protocol.h \
|
||||
tmux.c \
|
||||
tmux.h \
|
||||
tmux-protocol.h \
|
||||
tty-acs.c \
|
||||
tty-draw.c \
|
||||
tty-features.c \
|
||||
|
||||
@@ -56,7 +56,7 @@ gitコミットについての連絡先
|
||||
|
||||
tmux-users@googlegroups.com
|
||||
|
||||
本ファイル、CHANGES、 FAQ、SYNCINGそしてTODOはISC licenseで保護されています。
|
||||
本ファイル、CHANGES、 FAQ、SYNCING.mdそしてTODOはISC licenseで保護されています。
|
||||
その他のファイルのライセンスや著作権については、ファイルの上部に明記されています。
|
||||
|
||||
-- Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
1
SECURITY.md
Normal file
1
SECURITY.md
Normal file
@@ -0,0 +1 @@
|
||||
Please report security issues to nicholas.marriott@gmail.com.
|
||||
173
SYNCING
173
SYNCING
@@ -1,173 +0,0 @@
|
||||
Preamble
|
||||
========
|
||||
|
||||
Tmux portable relies on repositories "tmux" and "tmux-obsd".
|
||||
Here's a description of them:
|
||||
|
||||
* "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
|
||||
OpenBSD base system.
|
||||
|
||||
* "tmux-obsd" is the version of tmux in OpenBSD base system which provides
|
||||
the basis of the portable tmux version.
|
||||
|
||||
Note: The "tmux-obsd" repository is actually handled by "git cvsimport"
|
||||
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.
|
||||
(It might take longer, depending on the CVS mirror used to import the
|
||||
OpenBSD code).
|
||||
|
||||
If you've never used git before, git tracks meta-data about the committer
|
||||
and the author, as part of a commit, hence:
|
||||
|
||||
% git config [--global] user.name "Your name"
|
||||
% git config [--global] user.email "you@yourdomain.com"
|
||||
|
||||
Note that, if you already have this in the global ~/.gitconfig option, then
|
||||
this will be used. Setting this per-repository would involve not using the
|
||||
"--global" flag above. If you wish to use the same credentials always,
|
||||
pass the "--global" option, as shown.
|
||||
|
||||
This is a one-off operation once the repository has been cloned, assuming
|
||||
this information has ever been set before.
|
||||
|
||||
Cloning repositories
|
||||
====================
|
||||
|
||||
This involves having both tmux and tmux-obsd cloned, as in:
|
||||
|
||||
% cd /some/where/useful
|
||||
% git clone https://github.com/tmux/tmux.git
|
||||
% git clone https://github.com/ThomasAdam/tmux-obsd.git
|
||||
|
||||
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
|
||||
these checkouts existing, skip that.
|
||||
|
||||
Adding in git-remotes
|
||||
=====================
|
||||
|
||||
Because the portable "tmux" git repository and the "tmux-obsd"
|
||||
repository do not inherently share any history between each other, the
|
||||
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
|
||||
"tmux-obsd" repositories for syncing. To do this, we must reference the
|
||||
clone of the "tmux-obsd" repository from the "tmux" repository, as
|
||||
shown by the following command:
|
||||
|
||||
% cd /path/to/tmux
|
||||
% git remote add obsd-tmux file:///path/to/tmux-obsd
|
||||
|
||||
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
|
||||
portable "tmux" repository, which makes sense because it's the "tmux"
|
||||
repository which will have the updates applied to them.
|
||||
|
||||
Fetching updates
|
||||
================
|
||||
|
||||
To ensure the latest commits from "tmux-obsd" can be found from within
|
||||
"tmux", we have to ensure the "master" branch from "tmux-obsd" is
|
||||
up-to-date first, and then reference that update in "tmux", as in:
|
||||
|
||||
% cd /path/to/tmux-obsd
|
||||
% git checkout master
|
||||
% git pull
|
||||
|
||||
Then back in "tmux":
|
||||
|
||||
% cd /path/to/tmux
|
||||
% git fetch obsd-tmux
|
||||
|
||||
Creating the necessary branches
|
||||
===============================
|
||||
|
||||
Now that "tmux" can see commits and branches from "tmux-obsd" by way
|
||||
of the remote name "obsd-tmux", we can now create the master branch from
|
||||
"tmux-obsd" in the "tmux" repository:
|
||||
|
||||
% git checkout -b obsd-master obsd-tmux/master
|
||||
|
||||
Adding in the fake history points
|
||||
=================================
|
||||
|
||||
To tie both the "master" branch from "tmux" and the "obsd-master"
|
||||
branch from "tmux-obsd" together, the fake history points added to the
|
||||
"tmux" repository need to be added. To do this, we must add an
|
||||
additional refspec line, as in:
|
||||
|
||||
% cd /path/to/tmux
|
||||
% git config --add remote.origin.fetch '+refs/replace/*:refs/replace/*'
|
||||
% git fetch origin
|
||||
|
||||
Performing the Sync
|
||||
===================
|
||||
|
||||
Make sure the "master" branch is checked out:
|
||||
|
||||
% git checkout master
|
||||
|
||||
The following will show commits on OpenBSD not yet synched with "tmux":
|
||||
|
||||
% git log master..obsd-master
|
||||
|
||||
From there, merge the result in, fixing up any conflicts which might arise.
|
||||
|
||||
% git merge obsd-master
|
||||
|
||||
Then ensure things look correct by BUILDING the result of that sync:
|
||||
|
||||
% make clean && ./autogen.sh && ./configure && make
|
||||
|
||||
Compare the git merge result with what's on origin/master -- that is, check
|
||||
which commits you're about to push:
|
||||
|
||||
% git log origin/master..master
|
||||
|
||||
And if happy:
|
||||
|
||||
% git push origin master
|
||||
|
||||
Keeping an eye on libutil in OpenBSD
|
||||
====================================
|
||||
|
||||
A lot of the compat/ code in tmux comes from libutil, especially imsg.
|
||||
Sometimes the API can change, etc., which might cause interesting problems
|
||||
trying to run the portable version of tmux. It's worth checking
|
||||
periodically for any changes to libutil in OpenBSD and syncing those files
|
||||
to compat/ as and when appropriate.
|
||||
|
||||
Release tmux for next version
|
||||
=============================
|
||||
|
||||
1. Update and commit README and CHANGES. The former should be checked for
|
||||
anything outdated and updated with a list of things that might break
|
||||
upgrades and the latter should mention all the major changes since
|
||||
the last version.
|
||||
|
||||
2. Make sure configure.ac has the new version number.
|
||||
|
||||
3. Tag with:
|
||||
|
||||
% git tag -a 2.X
|
||||
|
||||
Where "2.X" is the next version.
|
||||
|
||||
Push the tag out with:
|
||||
|
||||
% git push --tags
|
||||
|
||||
4. Build the tarball with 'make dist'.
|
||||
|
||||
5. Check the tarball. If it's good, go here to select the tag just pushed:
|
||||
|
||||
https://github.com/tmux/tmux/tags
|
||||
|
||||
Click the "Add release notes", upload the tarball and add a link in the
|
||||
description field to the CHANGES file.
|
||||
|
||||
6. Clone the tmux.github.io repository, and change the RELEASE version in the
|
||||
Makefile. Commit it, and run 'make' to replace %%RELEASE%%. Push the
|
||||
result out.
|
||||
|
||||
7. Change version back to master in configure.ac.
|
||||
234
SYNCING.md
Normal file
234
SYNCING.md
Normal file
@@ -0,0 +1,234 @@
|
||||
# Preamble
|
||||
|
||||
tmux portable is maintained from two repositories:
|
||||
|
||||
* `tmux` is the portable repository. It contains the portability layer,
|
||||
autotools build files, regression tests, documentation, and code needed for
|
||||
platforms outside OpenBSD.
|
||||
* `tmux-openbsd-cutover` is the OpenBSD tmux import repository. Its `master`
|
||||
branch is the OpenBSD tmux history after the OpenBSD Git cutover. Portable
|
||||
merges this branch when importing OpenBSD changes.
|
||||
|
||||
To create the commits in the tmux-openbsd-cutover repo, the source repo is the
|
||||
Github mirror of OpenBSD's src repo:
|
||||
|
||||
```text
|
||||
https://github.com/openbsd/src.git
|
||||
```
|
||||
|
||||
The update automation filters the OpenBSD source tree to `usr.bin/tmux/`,
|
||||
publishes that filtered history as `openbsd-git` in the cutover repository,
|
||||
cherry-picks new filtered commits onto cutover `master`, then merges cutover
|
||||
`master` into portable `master`.
|
||||
|
||||
If you've never used git before, configure your identity before committing:
|
||||
|
||||
```sh
|
||||
git config [--global] user.name "Your name"
|
||||
git config [--global] user.email "you@yourdomain.com"
|
||||
```
|
||||
|
||||
# Repository layout
|
||||
|
||||
The usual local layout is:
|
||||
|
||||
```sh
|
||||
cd /some/where/useful
|
||||
git clone https://github.com/tmux/tmux.git tmux-portable
|
||||
git clone https://github.com/ThomasAdam/tmux-obsd.git tmux-openbsd-cutover
|
||||
```
|
||||
|
||||
The exact directory names do not matter, but the examples below use:
|
||||
|
||||
```text
|
||||
/path/to/tmux-portable
|
||||
/path/to/tmux-openbsd-cutover
|
||||
```
|
||||
|
||||
The cutover repository has three important branches:
|
||||
|
||||
* `master` is the branch portable consumes. It should contain tmux source
|
||||
only, not automation files.
|
||||
* `openbsd-git` is the raw filtered OpenBSD tmux branch generated from
|
||||
OpenBSD src `master`.
|
||||
* `automation` is an orphan branch containing the GitHub Actions workflow. It
|
||||
is separate so that workflow files are not merged into portable.
|
||||
|
||||
# Adding the OpenBSD remote to portable
|
||||
|
||||
In the portable repository, add the cutover repository as a remote:
|
||||
|
||||
```sh
|
||||
cd /path/to/tmux-portable
|
||||
git remote add tmux-openbsd /path/to/tmux-openbsd-cutover
|
||||
git config remote.tmux-openbsd.tagOpt --no-tags
|
||||
```
|
||||
|
||||
If the remote already exists, update it instead:
|
||||
|
||||
```sh
|
||||
git remote set-url tmux-openbsd /path/to/tmux-openbsd-cutover
|
||||
git config remote.tmux-openbsd.tagOpt --no-tags
|
||||
```
|
||||
|
||||
Fetch the cutover master branch explicitly:
|
||||
|
||||
```sh
|
||||
git fetch --no-tags tmux-openbsd master:refs/remotes/tmux-openbsd/master
|
||||
```
|
||||
|
||||
# Automated syncing
|
||||
|
||||
The normal sync is performed by the GitHub Actions workflow in the
|
||||
`automation` branch of the cutover repository. That workflow:
|
||||
|
||||
1. Fetches or clones OpenBSD src using a blobless clone.
|
||||
2. Filters `usr.bin/tmux/` into a local `tmux-openbsd` branch.
|
||||
3. Updates `tmux-openbsd-cutover/openbsd-git`.
|
||||
4. Cherry-picks new `openbsd-git` commits onto cutover `master`.
|
||||
5. Merges cutover `master` into portable `master`.
|
||||
6. Pushes the changed repositories.
|
||||
|
||||
The workflow deliberately runs from the orphan `automation` branch but checks
|
||||
out cutover `master` as the branch to update. This keeps `.github/` out of
|
||||
cutover `master`, so portable does not import workflow files when it merges
|
||||
OpenBSD changes.
|
||||
|
||||
# Manual portable merge
|
||||
|
||||
If the workflow fails while merging into portable, do the merge locally and
|
||||
push the result.
|
||||
|
||||
Start from an up-to-date portable master:
|
||||
|
||||
```sh
|
||||
cd /path/to/tmux-portable
|
||||
git fetch origin
|
||||
git checkout master
|
||||
git pull --ff-only origin master
|
||||
```
|
||||
|
||||
Fetch the cutover branch:
|
||||
|
||||
```sh
|
||||
git remote add tmux-openbsd /path/to/tmux-openbsd-cutover 2>/dev/null || true
|
||||
git config remote.tmux-openbsd.tagOpt --no-tags
|
||||
git fetch --no-tags tmux-openbsd master:refs/remotes/tmux-openbsd/master
|
||||
```
|
||||
|
||||
Merge it:
|
||||
|
||||
```sh
|
||||
git merge --no-ff --log refs/remotes/tmux-openbsd/master
|
||||
```
|
||||
|
||||
Resolve conflicts by deciding whether portable or OpenBSD owns the file.
|
||||
|
||||
Useful commands:
|
||||
|
||||
```sh
|
||||
git checkout --ours path/to/file
|
||||
git add path/to/file
|
||||
```
|
||||
|
||||
This keeps the portable version of a conflicted file.
|
||||
|
||||
```sh
|
||||
git checkout --theirs path/to/file
|
||||
git add path/to/file
|
||||
```
|
||||
|
||||
This takes the OpenBSD/cutover version of a conflicted file.
|
||||
|
||||
Before committing, inspect the result:
|
||||
|
||||
```sh
|
||||
git status
|
||||
git diff --check
|
||||
git diff --cached --stat
|
||||
```
|
||||
|
||||
Then finish and publish:
|
||||
|
||||
```sh
|
||||
git commit
|
||||
git push origin master
|
||||
```
|
||||
|
||||
If the merge attempt is wrong, abort it:
|
||||
|
||||
```sh
|
||||
git merge --abort
|
||||
```
|
||||
|
||||
After pushing a manually resolved merge, rerun the workflow. It should either
|
||||
no-op or continue from the now-merged portable state.
|
||||
|
||||
# Manual cutover update
|
||||
|
||||
Normally this is handled by the workflow. If it must be done manually, update
|
||||
`openbsd-git` in the cutover repository from a filtered OpenBSD src checkout,
|
||||
then cherry-pick the new filtered commits onto cutover `master`.
|
||||
|
||||
The important range is:
|
||||
|
||||
```text
|
||||
origin/openbsd-git..openbsd-git
|
||||
```
|
||||
|
||||
where `origin/openbsd-git` is the previously published filtered OpenBSD tmux
|
||||
branch and `openbsd-git` is the newly generated filtered branch.
|
||||
|
||||
In the cutover repository:
|
||||
|
||||
```sh
|
||||
cd /path/to/tmux-openbsd-cutover
|
||||
git checkout master
|
||||
git cherry-pick origin/openbsd-git..openbsd-git
|
||||
git push origin master openbsd-git
|
||||
```
|
||||
|
||||
Do not put workflow files on cutover `master`; keep them on the orphan
|
||||
`automation` branch.
|
||||
|
||||
# Keeping an eye on libutil in OpenBSD
|
||||
|
||||
A lot of the `compat/` code in tmux comes from OpenBSD libraries, especially
|
||||
imsg. Sometimes APIs change in OpenBSD in ways that require corresponding
|
||||
portable changes. It is worth checking periodically for relevant OpenBSD
|
||||
libutil changes and syncing those files into `compat/` as appropriate.
|
||||
|
||||
# Release tmux for next version
|
||||
|
||||
1. Update and commit README and CHANGES. The former should be checked for
|
||||
anything outdated and updated with a list of things that might break
|
||||
upgrades and the latter should mention all the major changes since the last
|
||||
version.
|
||||
2. Make sure `configure.ac` has the new version number.
|
||||
3. Tag with:
|
||||
|
||||
```sh
|
||||
% git tag -a 2.X
|
||||
```
|
||||
|
||||
Where `2.X` is the next version.
|
||||
|
||||
Push the tag out with:
|
||||
|
||||
```sh
|
||||
% git push --tags
|
||||
```
|
||||
|
||||
4. Build the tarball with `make dist`.
|
||||
5. Check the tarball. If it is good, go here to select the tag just pushed:
|
||||
|
||||
```text
|
||||
https://github.com/tmux/tmux/tags
|
||||
```
|
||||
|
||||
Click "Add release notes", upload the tarball and add a link in the
|
||||
description field to the CHANGES file.
|
||||
6. Clone the tmux.github.io repository, and change the RELEASE version in the
|
||||
Makefile. Commit it, and run `make` to replace `%%RELEASE%%`. Push the
|
||||
result out.
|
||||
7. Change version back to master in `configure.ac`.
|
||||
8
alerts.c
8
alerts.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: alerts.c,v 1.35 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2015 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -205,7 +205,7 @@ alerts_check_bell(struct window *w)
|
||||
}
|
||||
if (!alerts_action_applies(wl, "bell-action"))
|
||||
continue;
|
||||
notify_winlink("alert-bell", wl);
|
||||
events_fire_winlink("alert-bell", wl);
|
||||
|
||||
if (s->flags & SESSION_ALERTED)
|
||||
continue;
|
||||
@@ -241,7 +241,7 @@ alerts_check_activity(struct window *w)
|
||||
}
|
||||
if (!alerts_action_applies(wl, "activity-action"))
|
||||
continue;
|
||||
notify_winlink("alert-activity", wl);
|
||||
events_fire_winlink("alert-activity", wl);
|
||||
|
||||
if (s->flags & SESSION_ALERTED)
|
||||
continue;
|
||||
@@ -277,7 +277,7 @@ alerts_check_silence(struct window *w)
|
||||
}
|
||||
if (!alerts_action_applies(wl, "silence-action"))
|
||||
continue;
|
||||
notify_winlink("alert-silence", wl);
|
||||
events_fire_winlink("alert-silence", wl);
|
||||
|
||||
if (s->flags & SESSION_ALERTED)
|
||||
continue;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: arguments.c,v 1.66 2026/06/26 09:54:56 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: attributes.c,v 1.13 2026/07/02 08:51:05 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Joshua Elsasser <josh@elsasser.org>
|
||||
|
||||
2
cfg.c
2
cfg.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cfg.c,v 1.89 2026/06/25 11:39:11 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
2
client.c
2
client.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: client.c,v 1.166 2026/07/10 15:45:11 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-attach-session.c,v 1.91 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -163,7 +163,7 @@ cmd_attach_session(struct cmdq_item *item, const char *tflag, int dflag,
|
||||
|
||||
if (~c->flags & CLIENT_CONTROL)
|
||||
proc_send(c->peer, MSG_READY, -1, NULL, 0);
|
||||
notify_client("client-attached", c);
|
||||
events_fire_client("client-attached", c);
|
||||
c->flags |= CLIENT_ATTACHED;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-bind-key.c,v 1.47 2025/04/09 07:03:04 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-break-pane.c,v 1.73 2026/07/13 13:01:14 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -80,7 +80,7 @@ cmd_break_pane_float(struct cmdq_item *item, struct args *args,
|
||||
window_set_active_pane(w, wp, 1);
|
||||
layout_fix_offsets(w);
|
||||
layout_fix_panes(w, NULL);
|
||||
notify_window("window-layout-changed", w);
|
||||
events_fire_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
@@ -98,9 +98,9 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct session *src_s = source->s;
|
||||
struct session *dst_s = target->s;
|
||||
struct window_pane *wp = source->wp;
|
||||
struct window *w = wl->window;
|
||||
char *newname, *cause, *cp;
|
||||
int idx = target->idx, before;
|
||||
struct window *w = wl->window, *old_w = w;
|
||||
char *cause, *cp;
|
||||
int idx = target->idx, before, old_idx = wl->idx;
|
||||
const char *template, *name = args_get(args, 'n');
|
||||
|
||||
if (args_has(args, 'W'))
|
||||
@@ -137,6 +137,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
wl = winlink_find_by_window(&dst_s->windows, w);
|
||||
if (wl == NULL)
|
||||
return (CMD_RETURN_ERROR);
|
||||
window_fire_pane_moved(wp, old_w, old_idx, w, wl->idx);
|
||||
goto out;
|
||||
}
|
||||
if (idx != -1 && winlink_find_by_index(&dst_s->windows, idx) != NULL) {
|
||||
@@ -151,6 +152,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
layout_close_pane(wp);
|
||||
|
||||
w = wp->window = window_create(w->sx, w->sy, w->xpixel, w->ypixel);
|
||||
window_add_ref(w, __func__);
|
||||
options_set_parent(wp->options, w->options);
|
||||
wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED);
|
||||
TAILQ_INSERT_HEAD(&w->panes, wp, entry);
|
||||
@@ -158,12 +160,11 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
w->active = wp;
|
||||
w->latest = tc;
|
||||
|
||||
if (name == NULL) {
|
||||
newname = default_window_name(w);
|
||||
window_set_name(w, newname, 0);
|
||||
free(newname);
|
||||
} else {
|
||||
window_set_name(w, name, 0);
|
||||
free(w->name);
|
||||
if (name == NULL)
|
||||
w->name = default_window_name(w);
|
||||
else {
|
||||
w->name = clean_name(name, 0);
|
||||
options_set_number(w->options, "automatic-rename", 0);
|
||||
}
|
||||
|
||||
@@ -174,6 +175,9 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (idx == -1)
|
||||
idx = -1 - options_get_number(dst_s->options, "base-index");
|
||||
wl = session_attach(dst_s, w, idx, &cause); /* can't fail */
|
||||
window_remove_ref(w, __func__);
|
||||
events_fire_window("window-created", w);
|
||||
window_fire_pane_moved(wp, old_w, old_idx, w, wl->idx);
|
||||
if (!args_has(args, 'd')) {
|
||||
session_select(dst_s, wl->idx);
|
||||
cmd_find_from_session(current, dst_s, 0);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-capture-pane.c,v 1.67 2026/07/02 10:34:14 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Jonathan Alvarado <radobobo@users.sourceforge.net>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-choose-tree.c,v 1.57 2026/06/26 14:40:30 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2012 Thomas Adam <thomas@xteddy.org>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-command-prompt.c,v 1.75 2026/06/25 11:39:11 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-confirm-before.c,v 1.61 2026/06/24 10:55:39 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-copy-mode.c,v 1.53 2026/07/08 08:07:42 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-detach-client.c,v 1.39 2026/05/22 15:22:43 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-display-menu.c,v 1.51 2026/07/07 09:45:09 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-display-message.c,v 1.65 2026/02/23 08:46:57 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-display-panes.c,v 1.56 2026/06/25 16:32:42 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-find-window.c,v 1.56 2023/12/27 20:42:01 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-find.c,v 1.86 2026/07/02 08:47:25 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2015 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-if-shell.c,v 1.86 2025/08/01 09:05:51 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-join-pane.c,v 1.71 2026/07/13 13:01:14 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2011 George Nachman <tmux@georgester.com>
|
||||
@@ -186,7 +186,7 @@ cmd_join_pane_place(struct cmdq_item *item, struct winlink *wl,
|
||||
lc->g.yoff = yoff;
|
||||
layout_fix_panes(w, NULL);
|
||||
}
|
||||
notify_window("window-layout-changed", w);
|
||||
events_fire_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
@@ -256,7 +256,7 @@ cmd_join_pane_move(struct cmdq_item *item, struct args *args,
|
||||
lc->g.xoff = xoff;
|
||||
lc->g.yoff = yoff;
|
||||
layout_fix_panes(w, NULL);
|
||||
notify_window("window-layout-changed", w);
|
||||
events_fire_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
}
|
||||
|
||||
@@ -358,7 +358,7 @@ cmd_join_pane_zindex(struct cmdq_item *item, struct winlink *wl,
|
||||
else
|
||||
TAILQ_INSERT_TAIL(&w->z_index, wp, zentry);
|
||||
|
||||
notify_window("window-layout-changed", w);
|
||||
events_fire_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
@@ -397,7 +397,7 @@ cmd_join_pane_tile(struct cmdq_item *item, struct args *args, struct window *w,
|
||||
window_set_active_pane(w, wp, 1);
|
||||
layout_fix_offsets(w);
|
||||
layout_fix_panes(w, NULL);
|
||||
notify_window("window-layout-changed", w);
|
||||
events_fire_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
@@ -458,6 +458,13 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
if (args_has(args, 'h'))
|
||||
flags |= SPAWN_HORIZONTAL;
|
||||
if (args_has(args, 'b'))
|
||||
flags |= SPAWN_BEFORE;
|
||||
if (args_has(args, 'f'))
|
||||
flags |= SPAWN_FULLSIZE;
|
||||
|
||||
lc = layout_get_tiled_cell(item, args, dst_w, dst_wp, flags, &cause);
|
||||
if (cause != NULL) {
|
||||
cmdq_error(item, "size or position %s", cause);
|
||||
@@ -498,11 +505,12 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
} else
|
||||
server_status_session(dst_s);
|
||||
|
||||
window_fire_pane_moved(src_wp, src_w, src_wl->idx, dst_w, dst_idx);
|
||||
if (window_count_panes(src_w, 1) == 0)
|
||||
server_kill_window(src_w, 1);
|
||||
else
|
||||
notify_window("window-layout-changed", src_w);
|
||||
notify_window("window-layout-changed", dst_w);
|
||||
events_fire_window("window-layout-changed", src_w);
|
||||
events_fire_window("window-layout-changed", dst_w);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-kill-pane.c,v 1.34 2026/06/09 21:22:22 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-kill-server.c,v 1.20 2021/08/21 10:22:39 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-kill-session.c,v 1.31 2026/06/09 12:57:40 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-kill-window.c,v 1.30 2026/06/09 12:57:40 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-list-buffers.c,v 1.41 2026/02/27 08:25:12 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-list-clients.c,v 1.42 2026/02/27 08:25:12 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-list-commands.c,v 1.15 2026/02/24 08:22:13 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-list-keys.c,v 1.78 2026/07/01 13:12:17 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-list-panes.c,v 1.40 2026/06/01 14:01:09 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-list-sessions.c,v 1.36 2026/02/27 08:25:12 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-list-windows.c,v 1.50 2026/02/27 08:25:12 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-load-buffer.c,v 1.66 2025/10/28 07:32:26 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-lock-server.c,v 1.31 2021/08/21 10:22:39 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-move-window.c,v 1.34 2021/08/21 10:22:39 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-new-session.c,v 1.152 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -325,7 +325,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
||||
session_group_synchronize_to(s);
|
||||
session_select(s, RB_MIN(winlinks, &s->windows)->idx);
|
||||
}
|
||||
notify_session("session-created", s);
|
||||
events_fire_session("session-created", s);
|
||||
|
||||
/*
|
||||
* Set the client to the new session. If a command client exists, it is
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-new-window.c,v 1.103 2026/07/08 08:07:42 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-parse.y,v 1.58 2026/04/27 12:31:11 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-paste-buffer.c,v 1.44 2026/03/04 07:19:32 tb Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-pipe-pane.c,v 1.63 2026/04/28 08:47:55 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
70
cmd-queue.c
70
cmd-queue.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-queue.c,v 1.120 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -350,74 +350,53 @@ cmdq_insert_after(struct cmdq_item *after, struct cmdq_item *item)
|
||||
|
||||
/* Insert a hook. */
|
||||
void
|
||||
cmdq_insert_hook(struct session *s, struct cmdq_item *item,
|
||||
cmdq_insert_hook(__unused struct session *s, struct cmdq_item *item,
|
||||
struct cmd_find_state *current, 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 event_payload *ep;
|
||||
va_list ap;
|
||||
char *name, tmp[32], flag, *arguments;
|
||||
u_int i;
|
||||
const char *value;
|
||||
struct cmdq_item *new_item;
|
||||
struct cmdq_state *new_state;
|
||||
struct options_entry *o;
|
||||
struct options_array_item *a;
|
||||
struct cmd_list *cmdlist;
|
||||
|
||||
if (item->state->flags & CMDQ_STATE_NOHOOKS)
|
||||
return;
|
||||
if (s == NULL)
|
||||
oo = global_s_options;
|
||||
else
|
||||
oo = s->options;
|
||||
|
||||
va_start(ap, fmt);
|
||||
xvasprintf(&name, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
o = options_get(oo, name);
|
||||
if (o == NULL) {
|
||||
free(name);
|
||||
return;
|
||||
}
|
||||
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);
|
||||
ep = event_payload_create();
|
||||
if (current != NULL)
|
||||
event_payload_set_target(ep, current);
|
||||
event_payload_set_pointer(ep, "_cmdq_item", item, NULL, NULL);
|
||||
|
||||
arguments = args_print(args);
|
||||
cmdq_add_format(new_state, "hook_arguments", "%s", arguments);
|
||||
event_payload_set_string(ep, "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));
|
||||
xsnprintf(tmp, sizeof tmp, "argument_%u", i);
|
||||
event_payload_set_string(ep, 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);
|
||||
}
|
||||
xsnprintf(tmp, sizeof tmp, "flag_%c", flag);
|
||||
if (value == NULL)
|
||||
event_payload_set_string(ep, tmp, "1");
|
||||
else
|
||||
event_payload_set_string(ep, 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);
|
||||
xsnprintf(tmp, sizeof tmp, "flag_%c_%u", flag, i);
|
||||
event_payload_set_string(ep, tmp, "%s", av->string);
|
||||
i++;
|
||||
av = args_next_value(av);
|
||||
}
|
||||
@@ -425,20 +404,7 @@ cmdq_insert_hook(struct session *s, struct cmdq_item *item,
|
||||
flag = args_next(&ae);
|
||||
}
|
||||
|
||||
a = options_array_first(o);
|
||||
while (a != NULL) {
|
||||
cmdlist = options_array_item_value(a)->cmdlist;
|
||||
if (cmdlist != NULL) {
|
||||
new_item = cmdq_get_command(cmdlist, new_state);
|
||||
if (item != NULL)
|
||||
item = cmdq_insert_after(item, new_item);
|
||||
else
|
||||
item = cmdq_append(NULL, new_item);
|
||||
}
|
||||
a = options_array_next(a);
|
||||
}
|
||||
|
||||
cmdq_free_state(new_state);
|
||||
events_fire(name, ep);
|
||||
free(name);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-refresh-client.c,v 1.54 2026/07/05 08:24:00 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-rename-session.c,v 1.39 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -49,6 +49,8 @@ cmd_rename_session_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 event_payload *ep;
|
||||
struct cmd_find_state fs;
|
||||
char *newname, *tmp;
|
||||
|
||||
tmp = format_single_from_target(item, args_string(args, 0));
|
||||
@@ -69,13 +71,20 @@ cmd_rename_session_exec(struct cmd *self, struct cmdq_item *item)
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
ep = event_payload_create();
|
||||
cmd_find_from_session(&fs, s, 0);
|
||||
event_payload_set_target(ep, &fs);
|
||||
event_payload_set_session(ep, "session", s);
|
||||
event_payload_set_string(ep, "old_name", "%s", s->name);
|
||||
event_payload_set_string(ep, "new_name", "%s", newname);
|
||||
|
||||
RB_REMOVE(sessions, &sessions, s);
|
||||
free(s->name);
|
||||
s->name = newname;
|
||||
RB_INSERT(sessions, &sessions, s);
|
||||
|
||||
server_status_session(s);
|
||||
notify_session("session-renamed", s);
|
||||
events_fire("session-renamed", ep);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-rename-window.c,v 1.30 2026/06/29 18:17:28 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-resize-pane.c,v 1.67 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -182,7 +182,7 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (lc->parent != NULL)
|
||||
layout_fix_offsets(w);
|
||||
layout_fix_panes(w, NULL);
|
||||
notify_window("window-layout-changed", w);
|
||||
events_fire_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-resize-window.c,v 1.10 2023/06/30 13:19:32 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2018 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-respawn-pane.c,v 1.40 2026/07/03 16:09:49 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-respawn-window.c,v 1.51 2026/07/03 16:09:49 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-rotate-window.c,v 1.34 2026/06/22 08:47:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-run-shell.c,v 1.91 2026/06/01 08:27:37 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-save-buffer.c,v 1.57 2025/10/28 07:32:26 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-select-layout.c,v 1.43 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -145,7 +145,7 @@ changed:
|
||||
free(oldlayout);
|
||||
recalculate_sizes();
|
||||
server_redraw_window(w);
|
||||
notify_window("window-layout-changed", w);
|
||||
events_fire_window("window-layout-changed", w);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
error:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-select-pane.c,v 1.76 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -80,6 +80,69 @@ cmd_select_pane_redraw(struct window *w)
|
||||
}
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_select_pane_marked_pane(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
struct event_payload *ep;
|
||||
struct cmd_find_state fs;
|
||||
struct winlink *wl = target->wl;
|
||||
struct window_pane *wp = target->wp, *lwp = NULL, *mwp;
|
||||
struct session *s = target->s;
|
||||
|
||||
if (args_has(args, 'm') && !window_pane_is_visible(wp))
|
||||
return (CMD_RETURN_NORMAL);
|
||||
if (server_check_marked())
|
||||
lwp = marked_pane.wp;
|
||||
|
||||
if (args_has(args, 'M') || server_is_marked(s, wl, wp))
|
||||
server_clear_marked();
|
||||
else
|
||||
server_set_marked(s, wl, wp);
|
||||
mwp = marked_pane.wp;
|
||||
|
||||
ep = event_payload_create();
|
||||
if (mwp != NULL)
|
||||
cmd_find_from_pane(&fs, mwp, 0);
|
||||
else if (lwp != NULL)
|
||||
cmd_find_from_pane(&fs, lwp, 0);
|
||||
else
|
||||
cmd_find_from_pane(&fs, wp, 0);
|
||||
event_payload_set_target(ep, &fs);
|
||||
if (mwp != NULL) {
|
||||
event_payload_set_pane(ep, "pane", mwp);
|
||||
event_payload_set_pane(ep, "new_pane", mwp);
|
||||
event_payload_set_window(ep, "window", mwp->window);
|
||||
} else if (lwp != NULL) {
|
||||
event_payload_set_pane(ep, "pane", lwp);
|
||||
event_payload_set_window(ep, "window", lwp->window);
|
||||
} else {
|
||||
event_payload_set_pane(ep, "pane", wp);
|
||||
event_payload_set_window(ep, "window", wp->window);
|
||||
}
|
||||
if (lwp != NULL)
|
||||
event_payload_set_pane(ep, "old_pane", lwp);
|
||||
event_payload_set_int(ep, "marked", mwp != NULL);
|
||||
events_fire("marked-pane-changed", ep);
|
||||
|
||||
if (lwp != NULL) {
|
||||
lwp->flags |= (PANE_REDRAW|PANE_STYLECHANGED|PANE_THEMECHANGED);
|
||||
server_redraw_window_borders(lwp->window);
|
||||
server_status_window(lwp->window);
|
||||
}
|
||||
if (mwp != NULL) {
|
||||
mwp->flags |= (PANE_REDRAW|PANE_STYLECHANGED|PANE_THEMECHANGED);
|
||||
server_redraw_window_borders(mwp->window);
|
||||
server_status_window(mwp->window);
|
||||
}
|
||||
if (window_pane_is_floating(wp)) {
|
||||
window_redraw_active_switch(wp->window, wp);
|
||||
window_set_active_pane(wp->window, wp, 1);
|
||||
}
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
@@ -88,10 +151,12 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct cmd_find_state *current = cmdq_get_current(item);
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
struct client *c = cmdq_get_client(item);
|
||||
struct event_payload *ep;
|
||||
struct cmd_find_state fs;
|
||||
struct winlink *wl = target->wl;
|
||||
struct window *w = wl->window;
|
||||
struct session *s = target->s;
|
||||
struct window_pane *wp = target->wp, *activewp, *lastwp, *markedwp;
|
||||
struct window_pane *wp = target->wp, *activewp, *lastwp;
|
||||
struct options *oo = wp->options;
|
||||
char *title;
|
||||
const char *style;
|
||||
@@ -134,38 +199,8 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
if (args_has(args, 'm') || args_has(args, 'M')) {
|
||||
if (args_has(args, 'm') && !window_pane_is_visible(wp))
|
||||
return (CMD_RETURN_NORMAL);
|
||||
if (server_check_marked())
|
||||
lastwp = marked_pane.wp;
|
||||
else
|
||||
lastwp = NULL;
|
||||
|
||||
if (args_has(args, 'M') || server_is_marked(s, wl, wp))
|
||||
server_clear_marked();
|
||||
else
|
||||
server_set_marked(s, wl, wp);
|
||||
markedwp = marked_pane.wp;
|
||||
|
||||
if (lastwp != NULL) {
|
||||
lastwp->flags |= (PANE_REDRAW|PANE_STYLECHANGED|
|
||||
PANE_THEMECHANGED);
|
||||
server_redraw_window_borders(lastwp->window);
|
||||
server_status_window(lastwp->window);
|
||||
}
|
||||
if (markedwp != NULL) {
|
||||
markedwp->flags |= (PANE_REDRAW|PANE_STYLECHANGED|
|
||||
PANE_THEMECHANGED);
|
||||
server_redraw_window_borders(markedwp->window);
|
||||
server_status_window(markedwp->window);
|
||||
}
|
||||
if (window_pane_is_floating(wp)) {
|
||||
window_redraw_active_switch(w, wp);
|
||||
window_set_active_pane(w, wp, 1);
|
||||
}
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
if (args_has(args, 'm') || args_has(args, 'M'))
|
||||
return (cmd_select_pane_marked_pane(self, item));
|
||||
|
||||
style = args_get(args, 'P');
|
||||
if (style != NULL) {
|
||||
@@ -218,7 +253,13 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (args_has(args, 'T')) {
|
||||
title = format_single_from_target(item, args_get(args, 'T'));
|
||||
if (screen_set_title(&wp->base, title, 0)) {
|
||||
notify_pane("pane-title-changed", wp);
|
||||
ep = event_payload_create();
|
||||
cmd_find_from_pane(&fs, wp, 0);
|
||||
event_payload_set_target(ep, &fs);
|
||||
event_payload_set_pane(ep, "pane", wp);
|
||||
event_payload_set_window(ep, "window", wp->window);
|
||||
event_payload_set_string(ep, "new_title", "%s", title);
|
||||
events_fire("pane-title-changed", ep);
|
||||
server_redraw_window_borders(wp->window);
|
||||
server_status_window(wp->window);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-select-window.c,v 1.30 2021/08/21 10:22:39 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-send-keys.c,v 1.81 2026/06/11 19:13:34 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-server-access.c,v 1.6 2026/06/09 12:58:40 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2021 Dallas Lyons <dallasdlyons@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-set-buffer.c,v 1.37 2026/02/15 17:43:26 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-set-environment.c,v 1.29 2025/04/09 06:27:43 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-set-option.c,v 1.146 2026/07/10 15:20:06 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -31,6 +31,8 @@ static enum args_parse_type cmd_set_option_args_parse(struct args *,
|
||||
u_int, char **);
|
||||
static enum cmd_retval cmd_set_option_exec(struct cmd *,
|
||||
struct cmdq_item *);
|
||||
static enum cmd_retval cmd_set_hook_event_exec(struct cmd *,
|
||||
struct cmdq_item *);
|
||||
static enum cmd_retval cmd_set_hook_monitor_exec(struct cmdq_item *,
|
||||
struct args *, int);
|
||||
|
||||
@@ -64,8 +66,8 @@ const struct cmd_entry cmd_set_hook_entry = {
|
||||
.name = "set-hook",
|
||||
.alias = NULL,
|
||||
|
||||
.args = { "agpRt:uB:w", 0, 2, cmd_set_option_args_parse },
|
||||
.usage = "[-agpRuw] [-B name:what:format] " CMD_TARGET_PANE_USAGE " "
|
||||
.args = { "agpERTt:uB:w", 0, 2, cmd_set_option_args_parse },
|
||||
.usage = "[-agpERTuw] [-B name:what:format] " CMD_TARGET_PANE_USAGE " "
|
||||
"[hook] [command]",
|
||||
|
||||
.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
|
||||
@@ -85,17 +87,63 @@ cmd_set_option_args_parse(struct args *args, u_int idx,
|
||||
return (ARGS_PARSE_STRING);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_set_hook_event_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 event_payload *ep;
|
||||
struct client *c;
|
||||
char *argument;
|
||||
|
||||
if (args_count(args) == 0) {
|
||||
cmdq_error(item, "missing argument");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
if (args_count(args) != 1) {
|
||||
cmdq_error(item, "too many arguments");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
argument = format_single_from_target(item, args_string(args, 0));
|
||||
if (*argument != '@') {
|
||||
cmdq_error(item, "event name must start with @");
|
||||
free(argument);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
ep = event_payload_create();
|
||||
event_payload_set_target(ep, target);
|
||||
c = cmdq_get_client(item);
|
||||
if (c != NULL)
|
||||
event_payload_set_client(ep, "client", c);
|
||||
if (target->s != NULL)
|
||||
event_payload_set_session(ep, "session", target->s);
|
||||
if (target->w != NULL)
|
||||
event_payload_set_window(ep, "window", target->w);
|
||||
if (target->wl != NULL)
|
||||
event_payload_set_int(ep, "window_index", target->wl->idx);
|
||||
else if (target->idx != -1)
|
||||
event_payload_set_int(ep, "window_index", target->idx);
|
||||
if (target->wp != NULL)
|
||||
event_payload_set_pane(ep, "pane", target->wp);
|
||||
events_fire(argument, ep);
|
||||
free(argument);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_set_hook_monitor_exec(struct cmdq_item *item, struct args *args, int window)
|
||||
{
|
||||
struct cmd_find_state *target = cmdq_get_target(item), fs;
|
||||
struct options *oo;
|
||||
struct options_entry *o;
|
||||
struct session *s = NULL;
|
||||
char *cause = NULL, *name = NULL, *format = NULL;
|
||||
char *expanded = NULL, *newvalue = NULL;
|
||||
const char *value, *old;
|
||||
enum monitor_type type;
|
||||
int id, scope;
|
||||
int id, scope, flags = 0;
|
||||
|
||||
if (args_count(args) > 1) {
|
||||
cmdq_error(item, "too many arguments");
|
||||
@@ -130,7 +178,7 @@ cmd_set_hook_monitor_exec(struct cmdq_item *item, struct args *args, int window)
|
||||
cmd_find_copy_state(&fs, target);
|
||||
|
||||
if (args_has(args, 'u')) {
|
||||
notify_monitor_remove(oo, name);
|
||||
hooks_monitor_remove(oo, name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -152,7 +200,13 @@ cmd_set_hook_monitor_exec(struct cmdq_item *item, struct args *args, int window)
|
||||
}
|
||||
}
|
||||
|
||||
notify_monitor_add(item, oo, name, type, id, format, &fs, target->s);
|
||||
if (oo != global_options &&
|
||||
oo != global_s_options &&
|
||||
oo != global_w_options)
|
||||
s = target->s;
|
||||
if (args_has(args, 'T'))
|
||||
flags |= MONITOR_NOTIFY_TRUE;
|
||||
hooks_monitor_add(item, oo, name, type, id, format, flags, &fs, s);
|
||||
|
||||
out:
|
||||
free(newvalue);
|
||||
@@ -185,6 +239,8 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
|
||||
int scope;
|
||||
|
||||
window = (cmd_get_entry(self) == &cmd_set_window_option_entry);
|
||||
if (cmd_get_entry(self) == &cmd_set_hook_entry && args_has(args, 'E'))
|
||||
return (cmd_set_hook_event_exec(self, item));
|
||||
if (cmd_get_entry(self) == &cmd_set_hook_entry && args_has(args, 'B'))
|
||||
return (cmd_set_hook_monitor_exec(item, args, window));
|
||||
if (args_count(args) == 0) {
|
||||
@@ -197,7 +253,7 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
|
||||
|
||||
/* If set-hook -R, fire the hook straight away. */
|
||||
if (cmd_get_entry(self) == &cmd_set_hook_entry && args_has(args, 'R')) {
|
||||
notify_hook(item, argument);
|
||||
hooks_run(item, argument);
|
||||
free(argument);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
@@ -289,6 +345,8 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
|
||||
goto fail;
|
||||
}
|
||||
options_set_string(oo, name, append, "%s", value);
|
||||
if (cmd_get_entry(self) == &cmd_set_hook_entry)
|
||||
hooks_add_event(name);
|
||||
} else if (array_key == NULL && !options_is_array(parent)) {
|
||||
error = options_from_string(oo, options_table_entry(parent),
|
||||
options_table_entry(parent)->name, value,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-show-environment.c,v 1.29 2025/04/09 06:27:43 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-show-messages.c,v 1.37 2025/11/18 08:37:54 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-show-options.c,v 1.73 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -215,7 +215,7 @@ cmd_show_hooks_print_monitor(struct cmdq_item *item, struct options_entry *o)
|
||||
{
|
||||
char *value;
|
||||
|
||||
value = notify_monitor_to_string(o);
|
||||
value = hooks_monitor_to_string(o);
|
||||
if (value == NULL)
|
||||
return;
|
||||
cmdq_print(item, "%s", value);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-show-prompt-history.c,v 1.5 2026/06/25 11:39:11 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2021 Anindya Mukherjee <anindya49@hotmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-source-file.c,v 1.62 2025/11/18 08:42:09 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Tiago Cunha <me@tiagocunha.org>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-split-window.c,v 1.143 2026/07/13 16:07:47 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -33,13 +33,15 @@
|
||||
#define SPLIT_WINDOW_TEMPLATE "#{session_name}:#{window_index}.#{pane_index}"
|
||||
|
||||
static enum cmd_retval cmd_split_window_exec(struct cmd *, struct cmdq_item *);
|
||||
static void cmd_split_window_mouse_resize(struct client *,
|
||||
struct mouse_event *);
|
||||
|
||||
const struct cmd_entry cmd_new_pane_entry = {
|
||||
.name = "new-pane",
|
||||
.alias = "newp",
|
||||
|
||||
.args = { "bB:c:de:EfF:hIkl:Lm:p:PR:s:S:t:T:vWx:X:y:Y:Z", 0, -1, NULL },
|
||||
.usage = "[-bdefhIklPvWZ] [-B border-lines] "
|
||||
.args = { "bB:c:de:EfF:hIkl:LMm:p:PR:s:S:t:T:vWx:X:y:Y:Z", 0, -1, NULL },
|
||||
.usage = "[-bdefhIklMPvWZ] [-B border-lines] "
|
||||
"[-c start-directory] [-e environment] "
|
||||
"[-F format] [-l size] [-m message] [-p percentage] "
|
||||
"[-s style] [-S active-border-style] "
|
||||
@@ -61,8 +63,8 @@ const struct cmd_entry cmd_split_window_entry = {
|
||||
.usage = "[-bdefhIklPvWZ] [-c start-directory] [-e environment] "
|
||||
"[-F format] [-l size] [-m message] [-p percentage] "
|
||||
"[-s style] [-S active-border-style] "
|
||||
"[-R inactive-border-style] [-T title] " CMD_TARGET_PANE_USAGE " "
|
||||
"[shell-command [argument ...]]",
|
||||
"[-R inactive-border-style] [-T title] "
|
||||
CMD_TARGET_PANE_USAGE " [shell-command [argument ...]]",
|
||||
|
||||
.target = { 't', CMD_FIND_PANE, 0 },
|
||||
|
||||
@@ -83,7 +85,9 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct window *w = wl->window;
|
||||
struct window_pane *wp = target->wp, *new_wp = NULL;
|
||||
struct layout_cell *lc = NULL;
|
||||
struct event_payload *ep;
|
||||
struct cmd_find_state fs;
|
||||
struct key_event *event = cmdq_get_event(item);
|
||||
int input, empty, is_floating, flags = 0;
|
||||
const char *template, *style, *value;
|
||||
char *cause = NULL, *cp, *title;
|
||||
@@ -94,14 +98,28 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
|
||||
if (cmd_get_entry(self) == &cmd_new_pane_entry)
|
||||
is_floating = !args_has(args, 'L');
|
||||
else
|
||||
else {
|
||||
is_floating = window_pane_is_floating(wp);
|
||||
flags |= SPAWN_SPLIT;
|
||||
}
|
||||
|
||||
flags = is_floating ? SPAWN_FLOATING : 0;
|
||||
if (args_has(args, 'M') && is_floating) {
|
||||
if (event == NULL || !event->m.valid || tc == NULL)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
if (is_floating)
|
||||
flags |= SPAWN_FLOATING;
|
||||
if (args_has(args, 'h'))
|
||||
flags |= SPAWN_HORIZONTAL;
|
||||
if (args_has(args, 'b'))
|
||||
flags |= SPAWN_BEFORE;
|
||||
if (args_has(args, 'f'))
|
||||
flags |= SPAWN_FULLSIZE;
|
||||
if (args_has(args, 'd'))
|
||||
flags |= SPAWN_DETACHED;
|
||||
if (args_has(args, 'Z'))
|
||||
flags |= SPAWN_ZOOM;
|
||||
|
||||
input = args_has(args, 'I');
|
||||
if (input || (count == 1 && *args_string(args, 0) == '\0'))
|
||||
@@ -129,9 +147,10 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
}
|
||||
}
|
||||
|
||||
if (is_floating)
|
||||
lc = layout_get_floating_cell(item, args, lines, w, wp, &cause);
|
||||
else
|
||||
if (flags & SPAWN_FLOATING) {
|
||||
lc = layout_get_floating_cell(item, args, lines, w, wp, flags,
|
||||
&cause);
|
||||
} else
|
||||
lc = layout_get_tiled_cell(item, args, w, wp, flags, &cause);
|
||||
if (cause != NULL) {
|
||||
cmdq_error(item, "%s", cause);
|
||||
@@ -157,12 +176,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
|
||||
sc.idx = -1;
|
||||
sc.cwd = args_get(args, 'c');
|
||||
|
||||
sc.flags = flags;
|
||||
if (args_has(args, 'd'))
|
||||
sc.flags |= SPAWN_DETACHED;
|
||||
if (args_has(args, 'Z'))
|
||||
sc.flags |= SPAWN_ZOOM;
|
||||
|
||||
if ((new_wp = spawn_pane(&sc, &cause)) == NULL) {
|
||||
cmdq_error(item, "create pane failed: %s", cause);
|
||||
@@ -217,7 +231,13 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (args_has(args, 'T')) {
|
||||
title = format_single_from_target(item, args_get(args, 'T'));
|
||||
screen_set_title(&new_wp->base, title, 0);
|
||||
notify_pane("pane-title-changed", new_wp);
|
||||
ep = event_payload_create();
|
||||
cmd_find_from_pane(&fs, new_wp, 0);
|
||||
event_payload_set_target(ep, &fs);
|
||||
event_payload_set_pane(ep, "pane", new_wp);
|
||||
event_payload_set_window(ep, "window", new_wp->window);
|
||||
event_payload_set_string(ep, "new_title", "%s", title);
|
||||
events_fire("pane-title-changed", ep);
|
||||
free(title);
|
||||
}
|
||||
|
||||
@@ -232,15 +252,21 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!args_has(args, 'd'))
|
||||
if (~flags & SPAWN_DETACHED)
|
||||
cmd_find_from_winlink_pane(current, wl, new_wp, 0);
|
||||
|
||||
if (!is_floating) {
|
||||
if (~flags & SPAWN_FLOATING) {
|
||||
window_pop_zoom(wp->window);
|
||||
server_redraw_window(wp->window);
|
||||
}
|
||||
server_redraw_session(s);
|
||||
|
||||
if (args_has(args, 'M') && is_floating) {
|
||||
tc->tty.mouse_last_pane = new_wp->id;
|
||||
tc->tty.mouse_drag_update = cmd_split_window_mouse_resize;
|
||||
cmd_split_window_mouse_resize(tc, &event->m);
|
||||
}
|
||||
|
||||
if (args_has(args, 'P')) {
|
||||
if ((template = args_get(args, 'F')) == NULL)
|
||||
template = SPLIT_WINDOW_TEMPLATE;
|
||||
@@ -288,3 +314,73 @@ fail:
|
||||
return (CMD_RETURN_ERROR);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_split_window_mouse_resize(struct client *c, struct mouse_event *m)
|
||||
{
|
||||
struct window_pane *wp;
|
||||
struct window *w;
|
||||
struct layout_cell *lc;
|
||||
enum pane_lines lines;
|
||||
u_int sx, sy;
|
||||
int x, y, xoff, yoff, border;
|
||||
|
||||
if (c->tty.mouse_last_pane == -1)
|
||||
return;
|
||||
wp = window_pane_find_by_id(c->tty.mouse_last_pane);
|
||||
if (wp == NULL || !window_pane_is_floating(wp)) {
|
||||
c->tty.mouse_drag_update = NULL;
|
||||
return;
|
||||
}
|
||||
w = wp->window;
|
||||
lc = wp->layout_cell;
|
||||
|
||||
x = m->x + m->ox;
|
||||
y = m->y + m->oy;
|
||||
if (m->statusat == 0 && y >= (int)m->statuslines)
|
||||
y -= m->statuslines;
|
||||
else if (m->statusat > 0 && y >= m->statusat)
|
||||
y = m->statusat - 1;
|
||||
|
||||
lines = window_pane_get_pane_lines(wp);
|
||||
border = (lines != PANE_LINES_NONE);
|
||||
|
||||
if (x >= (int)c->tty.mouse_drag_x) {
|
||||
xoff = c->tty.mouse_drag_x + border;
|
||||
sx = x - c->tty.mouse_drag_x + 1;
|
||||
} else {
|
||||
sx = c->tty.mouse_drag_x - x + 1;
|
||||
xoff = c->tty.mouse_drag_x - sx + 1;
|
||||
if (border)
|
||||
xoff++;
|
||||
}
|
||||
if (y >= (int)c->tty.mouse_drag_y) {
|
||||
yoff = c->tty.mouse_drag_y + border;
|
||||
sy = y - c->tty.mouse_drag_y + 1;
|
||||
} else {
|
||||
sy = c->tty.mouse_drag_y - y + 1;
|
||||
yoff = c->tty.mouse_drag_y - sy + 1;
|
||||
if (border)
|
||||
yoff++;
|
||||
}
|
||||
|
||||
if (border) {
|
||||
if (sx <= 2)
|
||||
sx = PANE_MINIMUM;
|
||||
else
|
||||
sx -= 2;
|
||||
if (sy <= 2)
|
||||
sy = PANE_MINIMUM;
|
||||
else
|
||||
sy -= 2;
|
||||
}
|
||||
if (sx < PANE_MINIMUM)
|
||||
sx = PANE_MINIMUM;
|
||||
if (sy < PANE_MINIMUM)
|
||||
sy = PANE_MINIMUM;
|
||||
|
||||
layout_set_size(lc, sx, sy, xoff, yoff);
|
||||
layout_fix_panes(w, NULL);
|
||||
server_redraw_window(w);
|
||||
server_redraw_window_borders(w);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-swap-pane.c,v 1.54 2026/07/13 13:01:14 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -68,11 +68,14 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct window_pane *tmp_wp, *src_wp, *dst_wp;
|
||||
struct layout_cell *src_lc, *dst_lc;
|
||||
u_int sx, sy, xoff, yoff;
|
||||
int src_idx, dst_idx;
|
||||
|
||||
dst_w = target->wl->window;
|
||||
dst_wp = target->wp;
|
||||
dst_idx = target->wl->idx;
|
||||
src_w = source->wl->window;
|
||||
src_wp = source->wp;
|
||||
src_idx = source->wl->idx;
|
||||
|
||||
if (window_push_zoom(dst_w, 0, args_has(args, 'Z')))
|
||||
server_redraw_window(dst_w);
|
||||
@@ -180,9 +183,13 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
redraw_invalidate_scene(dst_w);
|
||||
server_redraw_window(dst_w);
|
||||
|
||||
notify_window("window-layout-changed", src_w);
|
||||
if (src_w != dst_w) {
|
||||
window_fire_pane_moved(src_wp, src_w, src_idx, dst_w, dst_idx);
|
||||
window_fire_pane_moved(dst_wp, dst_w, dst_idx, src_w, src_idx);
|
||||
}
|
||||
events_fire_window("window-layout-changed", src_w);
|
||||
if (src_w != dst_w)
|
||||
notify_window("window-layout-changed", dst_w);
|
||||
events_fire_window("window-layout-changed", dst_w);
|
||||
|
||||
out:
|
||||
if (window_pop_zoom(src_w))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-swap-window.c,v 1.29 2025/10/30 13:52:08 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-switch-client.c,v 1.74 2026/05/22 15:22:43 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-unbind-key.c,v 1.34 2021/08/21 10:22:39 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
261
cmd-wait-for.c
261
cmd-wait-for.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd-wait-for.c,v 1.23 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -34,8 +34,8 @@ const struct cmd_entry cmd_wait_for_entry = {
|
||||
.name = "wait-for",
|
||||
.alias = "wait",
|
||||
|
||||
.args = { "LSU", 1, 1, NULL },
|
||||
.usage = "[-L|-S|-U] channel",
|
||||
.args = { "EF:LSUlvw:", 1, 1, NULL },
|
||||
.usage = "[-ELSUlv] [-F format] [-w waiter] name",
|
||||
|
||||
.flags = 0,
|
||||
.exec = cmd_wait_for_exec
|
||||
@@ -46,6 +46,17 @@ struct wait_item {
|
||||
TAILQ_ENTRY(wait_item) entry;
|
||||
};
|
||||
|
||||
struct wait_event_item {
|
||||
struct cmdq_item *item;
|
||||
struct events_sink *sink;
|
||||
char *name;
|
||||
char *filter;
|
||||
int verbose;
|
||||
TAILQ_ENTRY(wait_event_item) entry;
|
||||
};
|
||||
static TAILQ_HEAD(, wait_event_item) wait_event_items =
|
||||
TAILQ_HEAD_INITIALIZER(wait_event_items);
|
||||
|
||||
struct wait_channel {
|
||||
const char *name;
|
||||
int locked;
|
||||
@@ -76,9 +87,28 @@ static enum cmd_retval cmd_wait_for_lock(struct cmdq_item *, const char *,
|
||||
struct wait_channel *);
|
||||
static enum cmd_retval cmd_wait_for_unlock(struct cmdq_item *, const char *,
|
||||
struct wait_channel *);
|
||||
static enum cmd_retval cmd_wait_for_event(struct cmdq_item *, const char *,
|
||||
struct args *);
|
||||
static void cmd_wait_for_event_cb(const char *,
|
||||
struct event_payload *, void *);
|
||||
static void cmd_wait_for_event_free(struct wait_event_item *);
|
||||
static enum cmd_retval cmd_wait_for_event_list(struct cmdq_item *,
|
||||
const char *);
|
||||
static enum cmd_retval cmd_wait_for_event_wake(struct cmdq_item *,
|
||||
const char *, struct args *);
|
||||
static enum cmd_retval cmd_wait_for_list(struct cmdq_item *,
|
||||
struct wait_channel *);
|
||||
static enum cmd_retval cmd_wait_for_wake(struct cmdq_item *, const char *,
|
||||
struct args *, struct wait_channel *);
|
||||
|
||||
static struct wait_channel *cmd_wait_for_add(const char *);
|
||||
static void cmd_wait_for_remove(struct wait_channel *);
|
||||
static void cmd_wait_for_remove_empty(
|
||||
struct wait_channel *);
|
||||
static const char *cmd_wait_for_item_client_name(
|
||||
struct cmdq_item *);
|
||||
static const char *cmd_wait_for_client_name(
|
||||
struct wait_event_item *);
|
||||
|
||||
static struct wait_channel *
|
||||
cmd_wait_for_add(const char *name)
|
||||
@@ -117,16 +147,53 @@ cmd_wait_for_remove(struct wait_channel *wc)
|
||||
free(wc);
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_wait_for_remove_empty(struct wait_channel *wc)
|
||||
{
|
||||
if (wc->locked || wc->woken)
|
||||
return;
|
||||
if (!TAILQ_EMPTY(&wc->waiters) || !TAILQ_EMPTY(&wc->lockers))
|
||||
return;
|
||||
|
||||
log_debug("remove empty wait channel %s", wc->name);
|
||||
|
||||
RB_REMOVE(wait_channels, &wait_channels, wc);
|
||||
|
||||
free((void *)wc->name);
|
||||
free(wc);
|
||||
}
|
||||
|
||||
static const char *
|
||||
cmd_wait_for_item_client_name(struct cmdq_item *item)
|
||||
{
|
||||
struct client *c = cmdq_get_client(item);
|
||||
|
||||
if (c == NULL || c->name == NULL)
|
||||
return ("");
|
||||
return (c->name);
|
||||
}
|
||||
|
||||
static const char *
|
||||
cmd_wait_for_client_name(struct wait_event_item *wei)
|
||||
{
|
||||
return (cmd_wait_for_item_client_name(wei->item));
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_wait_for_exec(struct cmd *self, struct cmdq_item *item)
|
||||
{
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct args *args = cmd_get_args(self);
|
||||
const char *name = args_string(args, 0);
|
||||
struct wait_channel *wc, find;
|
||||
struct wait_channel *wc, find = { .name = name };
|
||||
|
||||
if (args_has(args, 'E'))
|
||||
return (cmd_wait_for_event(item, name, args));
|
||||
|
||||
find.name = name;
|
||||
wc = RB_FIND(wait_channels, &wait_channels, &find);
|
||||
|
||||
if (args_has(args, 'l'))
|
||||
return (cmd_wait_for_list(item, wc));
|
||||
if (args_has(args, 'w'))
|
||||
return (cmd_wait_for_wake(item, name, args, wc));
|
||||
if (args_has(args, 'S'))
|
||||
return (cmd_wait_for_signal(item, name, wc));
|
||||
if (args_has(args, 'L'))
|
||||
@@ -136,6 +203,179 @@ cmd_wait_for_exec(struct cmd *self, struct cmdq_item *item)
|
||||
return (cmd_wait_for_wait(item, name, wc));
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_wait_for_event_print(struct wait_event_item *wei, struct event_payload *ep)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
const char *key;
|
||||
char *value;
|
||||
|
||||
epi = event_payload_first(ep);
|
||||
while (epi != NULL) {
|
||||
key = event_payload_item_name(epi);
|
||||
if (*key != '_') {
|
||||
value = event_payload_item_print(epi);
|
||||
cmdq_print(wei->item, "%s=%s", key, value);
|
||||
free(value);
|
||||
}
|
||||
epi = event_payload_next(epi);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_wait_for_event_cb(__unused const char *name, struct event_payload *ep,
|
||||
void *item_data)
|
||||
{
|
||||
struct wait_event_item *wei = item_data;
|
||||
struct format_tree *ft;
|
||||
char *expanded;
|
||||
int flag;
|
||||
|
||||
if (wei->verbose)
|
||||
cmd_wait_for_event_print(wei, ep);
|
||||
|
||||
if (wei->filter != NULL) {
|
||||
ft = format_create(cmdq_get_client(wei->item), wei->item,
|
||||
FORMAT_NONE, FORMAT_NOJOBS);
|
||||
event_payload_add_formats(ep, ft, NULL);
|
||||
expanded = format_expand(ft, wei->filter);
|
||||
flag = format_true(expanded);
|
||||
free(expanded);
|
||||
format_free(ft);
|
||||
|
||||
if (!flag)
|
||||
return;
|
||||
}
|
||||
|
||||
TAILQ_REMOVE(&wait_event_items, wei, entry);
|
||||
cmdq_continue(wei->item);
|
||||
cmd_wait_for_event_free(wei);
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_wait_for_event_free(struct wait_event_item *wei)
|
||||
{
|
||||
events_remove_sink(wei->sink);
|
||||
free(wei->name);
|
||||
free(wei->filter);
|
||||
free(wei);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_wait_for_event(struct cmdq_item *item, const char *name, struct args *args)
|
||||
{
|
||||
struct wait_event_item *wei;
|
||||
const char *filter = args_get(args, 'F');
|
||||
|
||||
if (!hooks_valid_event_name(name)) {
|
||||
cmdq_error(item, "invalid event: %s", name);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
if (args_has(args, 'l'))
|
||||
return (cmd_wait_for_event_list(item, name));
|
||||
if (args_has(args, 'w'))
|
||||
return (cmd_wait_for_event_wake(item, name, args));
|
||||
|
||||
if (cmdq_get_client(item) == NULL) {
|
||||
cmdq_error(item, "not able to wait");
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
wei = xcalloc(1, sizeof *wei);
|
||||
wei->item = item;
|
||||
wei->name = xstrdup(name);
|
||||
wei->filter = (filter != NULL ? xstrdup(filter) : NULL);
|
||||
wei->verbose = args_has(args, 'v');
|
||||
wei->sink = events_add_sink(name, cmd_wait_for_event_cb, wei);
|
||||
TAILQ_INSERT_TAIL(&wait_event_items, wei, entry);
|
||||
|
||||
return (CMD_RETURN_WAIT);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_wait_for_event_list(struct cmdq_item *item, const char *name)
|
||||
{
|
||||
struct wait_event_item *wei;
|
||||
|
||||
TAILQ_FOREACH(wei, &wait_event_items, entry) {
|
||||
if (strcmp(wei->name, name) == 0)
|
||||
cmdq_print(item, "%s", cmd_wait_for_client_name(wei));
|
||||
}
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_wait_for_event_wake(struct cmdq_item *item, const char *name,
|
||||
struct args *args)
|
||||
{
|
||||
struct wait_event_item *wei, *wei1;
|
||||
const char *client_name = args_get(args, 'w');
|
||||
|
||||
TAILQ_FOREACH_SAFE(wei, &wait_event_items, entry, wei1) {
|
||||
if (strcmp(wei->name, name) != 0)
|
||||
continue;
|
||||
if (strcmp(cmd_wait_for_client_name(wei), client_name) != 0)
|
||||
continue;
|
||||
|
||||
TAILQ_REMOVE(&wait_event_items, wei, entry);
|
||||
cmdq_continue(wei->item);
|
||||
cmd_wait_for_event_free(wei);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
cmdq_error(item, "waiter %s not found", client_name);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_wait_for_list(struct cmdq_item *item, struct wait_channel *wc)
|
||||
{
|
||||
struct wait_item *wi;
|
||||
|
||||
if (wc == NULL)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
TAILQ_FOREACH(wi, &wc->waiters, entry)
|
||||
cmdq_print(item, "%s", cmd_wait_for_item_client_name(wi->item));
|
||||
TAILQ_FOREACH(wi, &wc->lockers, entry)
|
||||
cmdq_print(item, "%s", cmd_wait_for_item_client_name(wi->item));
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_wait_for_wake(__unused struct cmdq_item *item, const char *name,
|
||||
struct args *args, struct wait_channel *wc)
|
||||
{
|
||||
struct wait_item *wi, *wi1;
|
||||
const char *client_name = args_get(args, 'w');
|
||||
|
||||
if (wc != NULL) {
|
||||
TAILQ_FOREACH_SAFE(wi, &wc->waiters, entry, wi1) {
|
||||
name = cmd_wait_for_item_client_name(wi->item);
|
||||
if (strcmp(name, client_name) != 0)
|
||||
continue;
|
||||
cmdq_continue(wi->item);
|
||||
TAILQ_REMOVE(&wc->waiters, wi, entry);
|
||||
free(wi);
|
||||
cmd_wait_for_remove_empty(wc);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
TAILQ_FOREACH_SAFE(wi, &wc->lockers, entry, wi1) {
|
||||
name = cmd_wait_for_item_client_name(wi->item);
|
||||
if (strcmp(name, client_name) != 0)
|
||||
continue;
|
||||
cmdq_continue(wi->item);
|
||||
TAILQ_REMOVE(&wc->lockers, wi, entry);
|
||||
free(wi);
|
||||
cmd_wait_for_remove_empty(wc);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
}
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static enum cmd_retval
|
||||
cmd_wait_for_signal(__unused struct cmdq_item *item, const char *name,
|
||||
struct wait_channel *wc)
|
||||
@@ -245,6 +485,13 @@ cmd_wait_for_flush(void)
|
||||
{
|
||||
struct wait_channel *wc, *wc1;
|
||||
struct wait_item *wi, *wi1;
|
||||
struct wait_event_item *wei, *wei1;
|
||||
|
||||
TAILQ_FOREACH_SAFE(wei, &wait_event_items, entry, wei1) {
|
||||
TAILQ_REMOVE(&wait_event_items, wei, entry);
|
||||
cmdq_continue(wei->item);
|
||||
cmd_wait_for_event_free(wei);
|
||||
}
|
||||
|
||||
RB_FOREACH_SAFE(wc, wait_channels, &wait_channels, wc1) {
|
||||
TAILQ_FOREACH_SAFE(wi, &wc->waiters, entry, wi1) {
|
||||
|
||||
11
cmd.c
11
cmd.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: cmd.c,v 1.187 2026/07/13 09:37:39 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -845,7 +845,7 @@ cmd_template_replace(const char *template, const char *s, int idx)
|
||||
char ch, *buf;
|
||||
const char *ptr, *cp, quote[] = "\"\\$;~";
|
||||
int replaced, quoted;
|
||||
size_t len;
|
||||
size_t len, slen;
|
||||
|
||||
if (strchr(template, '%') == NULL)
|
||||
return (xstrdup(template));
|
||||
@@ -870,7 +870,10 @@ cmd_template_replace(const char *template, const char *s, int idx)
|
||||
if (quoted)
|
||||
ptr++;
|
||||
|
||||
buf = xrealloc(buf, len + (strlen(s) * 3) + 1);
|
||||
slen = strlen(s);
|
||||
if (slen >= SIZE_MAX / 3 || len > SIZE_MAX - (slen * 3) - 1)
|
||||
fatalx("argument too long");
|
||||
buf = xrealloc(buf, len + (slen * 3) + 1);
|
||||
for (cp = s; *cp != '\0'; cp++) {
|
||||
if (quoted && strchr(quote, *cp) != NULL)
|
||||
buf[len++] = '\\';
|
||||
@@ -879,6 +882,8 @@ cmd_template_replace(const char *template, const char *s, int idx)
|
||||
buf[len] = '\0';
|
||||
continue;
|
||||
}
|
||||
if (len > SIZE_MAX - 2)
|
||||
fatalx("argument too long");
|
||||
buf = xrealloc(buf, len + 2);
|
||||
buf[len++] = ch;
|
||||
buf[len] = '\0';
|
||||
|
||||
2
colour.c
2
colour.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: colour.c,v 1.35 2026/07/06 14:29:10 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
5
compat.h
5
compat.h
@@ -410,11 +410,6 @@ int asprintf(char **, const char *, ...);
|
||||
int vasprintf(char **, const char *, va_list);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_FGETLN
|
||||
/* fgetln.c */
|
||||
char *fgetln(FILE *, size_t *);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_GETLINE
|
||||
/* getline.c */
|
||||
ssize_t getline(char **, size_t *, FILE *);
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Joerg Jung <jung@openbsd.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* portable fgetln() version, NOT reentrant
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
char *
|
||||
fgetln(FILE *fp, size_t *len)
|
||||
{
|
||||
static char *buf = NULL;
|
||||
static size_t bufsz = 0;
|
||||
size_t r = 0;
|
||||
char *p;
|
||||
int c, e;
|
||||
|
||||
if (!fp || !len) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
if (!buf) {
|
||||
if (!(buf = calloc(1, BUFSIZ)))
|
||||
return NULL;
|
||||
bufsz = BUFSIZ;
|
||||
}
|
||||
while ((c = getc(fp)) != EOF) {
|
||||
buf[r++] = c;
|
||||
if (r == bufsz) {
|
||||
if (!(p = reallocarray(buf, 2, bufsz))) {
|
||||
e = errno;
|
||||
free(buf);
|
||||
errno = e;
|
||||
buf = NULL, bufsz = 0;
|
||||
return NULL;
|
||||
}
|
||||
buf = p, bufsz = 2 * bufsz;
|
||||
}
|
||||
if (c == '\n')
|
||||
break;
|
||||
}
|
||||
return (*len = r) ? buf : NULL;
|
||||
}
|
||||
@@ -74,8 +74,14 @@ getdelim(char **buf, size_t *bufsiz, int delimiter, FILE *fp)
|
||||
}
|
||||
if (ptr + 2 >= eptr) {
|
||||
char *nbuf;
|
||||
size_t nbufsiz = *bufsiz * 2;
|
||||
size_t nbufsiz;
|
||||
ssize_t d = ptr - *buf;
|
||||
|
||||
if (*bufsiz > SIZE_MAX / 2) {
|
||||
errno = EOVERFLOW;
|
||||
return -1;
|
||||
}
|
||||
nbufsiz = *bufsiz * 2;
|
||||
if ((nbuf = realloc(*buf, nbufsiz)) == NULL)
|
||||
return -1;
|
||||
*buf = nbuf;
|
||||
|
||||
@@ -177,7 +177,6 @@ AC_REPLACE_FUNCS([ \
|
||||
clock_gettime \
|
||||
closefrom \
|
||||
explicit_bzero \
|
||||
fgetln \
|
||||
freezero \
|
||||
getdtablecount \
|
||||
getdtablesize \
|
||||
|
||||
214
control-notify.c
214
control-notify.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: control-notify.c,v 1.37 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2012 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -23,32 +23,56 @@
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
/* Should this client be sent events? */
|
||||
#define CONTROL_SHOULD_NOTIFY_CLIENT(c) \
|
||||
((c) != NULL && ((c)->flags & CLIENT_CONTROL) && \
|
||||
((c) != NULL && \
|
||||
((c)->flags & CLIENT_CONTROL) && \
|
||||
(~(c)->flags & CLIENT_EXIT) && \
|
||||
(c)->control_state != NULL)
|
||||
|
||||
void
|
||||
control_notify_pane_mode_changed(int pane)
|
||||
/* Notify control clients that pane mode changed. */
|
||||
static void
|
||||
control_pane_mode_changed_cb(__unused const char *name,
|
||||
struct event_payload *ep, __unused void *sink_data)
|
||||
{
|
||||
struct client *c;
|
||||
struct window_pane *wp;
|
||||
struct client *c;
|
||||
char *value;
|
||||
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
|
||||
continue;
|
||||
|
||||
control_write(c, "%%pane-mode-changed %%%u", pane);
|
||||
wp = event_payload_get_pane(ep, "pane");
|
||||
if (wp != NULL) {
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
|
||||
continue;
|
||||
control_write(c, "%%pane-mode-changed %%%u", wp->id);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
value = event_payload_print(ep, "pane");
|
||||
if (value == NULL)
|
||||
return;
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (CONTROL_SHOULD_NOTIFY_CLIENT(c))
|
||||
control_write(c, "%%pane-mode-changed %s", value);
|
||||
}
|
||||
free(value);
|
||||
}
|
||||
|
||||
void
|
||||
control_notify_window_layout_changed(struct window *w)
|
||||
/* Notify control clients that window layout changed. */
|
||||
static void
|
||||
control_window_layout_changed_cb(__unused const char *name,
|
||||
struct event_payload *ep, __unused void *sink_data)
|
||||
{
|
||||
struct client *c;
|
||||
struct session *s;
|
||||
struct winlink *wl;
|
||||
const char *template;
|
||||
char *cp;
|
||||
struct client *c;
|
||||
struct session *s;
|
||||
struct winlink *wl;
|
||||
struct window *w = event_payload_get_window(ep, "window");
|
||||
const char *template;
|
||||
char *cp;
|
||||
|
||||
if (w == NULL)
|
||||
return;
|
||||
|
||||
template = "%layout-change #{window_id} #{window_layout} "
|
||||
"#{window_visible_layout} #{window_raw_flags}";
|
||||
@@ -73,12 +97,15 @@ control_notify_window_layout_changed(struct window *w)
|
||||
free(cp);
|
||||
}
|
||||
|
||||
void
|
||||
control_notify_window_pane_changed(struct window *w)
|
||||
/* Notify control clients that window pane changed. */
|
||||
static void
|
||||
control_window_pane_changed_cb(__unused const char *name,
|
||||
struct event_payload *ep, __unused void *sink_data)
|
||||
{
|
||||
struct client *c;
|
||||
struct window *w = event_payload_get_window(ep, "window");
|
||||
|
||||
if (w->active == NULL)
|
||||
if (w == NULL || w->active == NULL)
|
||||
return;
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
|
||||
@@ -89,12 +116,17 @@ control_notify_window_pane_changed(struct window *w)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
control_notify_window_unlinked(__unused struct session *s, struct window *w)
|
||||
/* Notify control clients that a window was unlinked. */
|
||||
static void
|
||||
control_window_unlinked_cb(__unused const char *name, struct event_payload *ep,
|
||||
__unused void *sink_data)
|
||||
{
|
||||
struct client *c;
|
||||
struct session *cs;
|
||||
struct client *c;
|
||||
struct session *cs;
|
||||
struct window *w = event_payload_get_window(ep, "window");
|
||||
|
||||
if (w == NULL)
|
||||
return;
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
|
||||
continue;
|
||||
@@ -107,12 +139,17 @@ control_notify_window_unlinked(__unused struct session *s, struct window *w)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
control_notify_window_linked(__unused struct session *s, struct window *w)
|
||||
/* Notify control clients that a window was linked. */
|
||||
static void
|
||||
control_window_linked_cb(__unused const char *name, struct event_payload *ep,
|
||||
__unused void *sink_data)
|
||||
{
|
||||
struct client *c;
|
||||
struct session *cs;
|
||||
struct client *c;
|
||||
struct session *cs;
|
||||
struct window *w = event_payload_get_window(ep, "window");
|
||||
|
||||
if (w == NULL)
|
||||
return;
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
|
||||
continue;
|
||||
@@ -125,12 +162,17 @@ control_notify_window_linked(__unused struct session *s, struct window *w)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
control_notify_window_renamed(struct window *w)
|
||||
/* Notify control clients that a window was renamed. */
|
||||
static void
|
||||
control_window_renamed_cb(__unused const char *name, struct event_payload *ep,
|
||||
__unused void *sink_data)
|
||||
{
|
||||
struct client *c;
|
||||
struct session *cs;
|
||||
struct client *c;
|
||||
struct session *cs;
|
||||
struct window *w = event_payload_get_window(ep, "window");
|
||||
|
||||
if (w == NULL)
|
||||
return;
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
|
||||
continue;
|
||||
@@ -146,13 +188,16 @@ control_notify_window_renamed(struct window *w)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
control_notify_client_session_changed(struct client *cc)
|
||||
/* Notify control clients that a client changed session. */
|
||||
static void
|
||||
control_client_session_changed_cb(__unused const char *name,
|
||||
struct event_payload *ep, __unused void *sink_data)
|
||||
{
|
||||
struct client *c;
|
||||
struct session *s;
|
||||
struct client *cc = event_payload_get_client(ep, "client");
|
||||
struct client *c;
|
||||
struct session *s;
|
||||
|
||||
if (cc->session == NULL)
|
||||
if (cc == NULL || cc->session == NULL)
|
||||
return;
|
||||
s = cc->session;
|
||||
|
||||
@@ -170,22 +215,32 @@ control_notify_client_session_changed(struct client *cc)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
control_notify_client_detached(struct client *cc)
|
||||
/* Notify control clients that a client detached. */
|
||||
static void
|
||||
control_client_detached_cb(__unused const char *name, struct event_payload *ep,
|
||||
__unused void *sink_data)
|
||||
{
|
||||
struct client *c;
|
||||
struct client *cc = event_payload_get_client(ep, "client");
|
||||
struct client *c;
|
||||
|
||||
if (cc == NULL)
|
||||
return;
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (CONTROL_SHOULD_NOTIFY_CLIENT(c))
|
||||
control_write(c, "%%client-detached %s", cc->name);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
control_notify_session_renamed(struct session *s)
|
||||
/* Notify control clients that a session was renamed. */
|
||||
static void
|
||||
control_session_renamed_cb(__unused const char *name, struct event_payload *ep,
|
||||
__unused void *sink_data)
|
||||
{
|
||||
struct client *c;
|
||||
struct session *s = event_payload_get_session(ep, "session");
|
||||
struct client *c;
|
||||
|
||||
if (s == NULL)
|
||||
return;
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
|
||||
continue;
|
||||
@@ -194,8 +249,10 @@ control_notify_session_renamed(struct session *s)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
control_notify_session_created(__unused struct session *s)
|
||||
/* Notify control clients that sessions changed. */
|
||||
static void
|
||||
control_session_created_cb(__unused const char *name,
|
||||
__unused struct event_payload *ep, __unused void *sink_data)
|
||||
{
|
||||
struct client *c;
|
||||
|
||||
@@ -207,8 +264,10 @@ control_notify_session_created(__unused struct session *s)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
control_notify_session_closed(__unused struct session *s)
|
||||
/* Notify control clients that sessions changed. */
|
||||
static void
|
||||
control_session_closed_cb(__unused const char *name,
|
||||
__unused struct event_payload *ep, __unused void *sink_data)
|
||||
{
|
||||
struct client *c;
|
||||
|
||||
@@ -220,9 +279,12 @@ control_notify_session_closed(__unused struct session *s)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
control_notify_session_window_changed(struct session *s)
|
||||
/* Notify control clients that the current window changed. */
|
||||
static void
|
||||
control_session_window_changed_cb(__unused const char *name,
|
||||
struct event_payload *ep, __unused void *sink_data)
|
||||
{
|
||||
struct session *s = event_payload_get_session(ep, "session");
|
||||
struct client *c;
|
||||
|
||||
/*
|
||||
@@ -230,7 +292,7 @@ control_notify_session_window_changed(struct session *s)
|
||||
* session has been destroyed (which sets curw to NULL) but is kept
|
||||
* alive by the notification's reference. Skip the notification.
|
||||
*/
|
||||
if (s->curw == NULL)
|
||||
if (s == NULL || s->curw == NULL)
|
||||
return;
|
||||
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
@@ -242,28 +304,68 @@ control_notify_session_window_changed(struct session *s)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
control_notify_paste_buffer_changed(const char *name)
|
||||
/* Notify control clients that a paste buffer changed. */
|
||||
static void
|
||||
control_paste_buffer_changed_cb(__unused const char *name,
|
||||
struct event_payload *ep, __unused void *sink_data)
|
||||
{
|
||||
const char *pbname = event_payload_get_string(ep, "paste_buffer");
|
||||
struct client *c;
|
||||
|
||||
if (pbname == NULL)
|
||||
return;
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
|
||||
continue;
|
||||
|
||||
control_write(c, "%%paste-buffer-changed %s", name);
|
||||
control_write(c, "%%paste-buffer-changed %s", pbname);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
control_notify_paste_buffer_deleted(const char *name)
|
||||
/* Notify control clients that a paste buffer was deleted. */
|
||||
static void
|
||||
control_paste_buffer_deleted_cb(__unused const char *name,
|
||||
struct event_payload *ep, __unused void *sink_data)
|
||||
{
|
||||
const char *pbname = event_payload_get_string(ep, "paste_buffer");
|
||||
struct client *c;
|
||||
|
||||
if (pbname == NULL)
|
||||
return;
|
||||
TAILQ_FOREACH(c, &clients, entry) {
|
||||
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
|
||||
continue;
|
||||
|
||||
control_write(c, "%%paste-buffer-deleted %s", name);
|
||||
control_write(c, "%%paste-buffer-deleted %s", pbname);
|
||||
}
|
||||
}
|
||||
|
||||
/* Build control event sinks. */
|
||||
void
|
||||
control_build_events(void)
|
||||
{
|
||||
/* Control event sink callbacks. */
|
||||
static struct {
|
||||
const char *name;
|
||||
events_cb cb;
|
||||
} events[] = {
|
||||
{ "pane-mode-changed", control_pane_mode_changed_cb },
|
||||
{ "window-layout-changed", control_window_layout_changed_cb },
|
||||
{ "window-pane-changed", control_window_pane_changed_cb },
|
||||
{ "window-unlinked", control_window_unlinked_cb },
|
||||
{ "window-linked", control_window_linked_cb },
|
||||
{ "window-renamed", control_window_renamed_cb },
|
||||
{ "client-session-changed", control_client_session_changed_cb },
|
||||
{ "client-detached", control_client_detached_cb },
|
||||
{ "session-renamed", control_session_renamed_cb },
|
||||
{ "session-created", control_session_created_cb },
|
||||
{ "session-closed", control_session_closed_cb },
|
||||
{ "session-window-changed", control_session_window_changed_cb },
|
||||
{ "paste-buffer-changed", control_paste_buffer_changed_cb },
|
||||
{ "paste-buffer-deleted", control_paste_buffer_deleted_cb }
|
||||
};
|
||||
u_int i;
|
||||
|
||||
for (i = 0; i < nitems(events); i++)
|
||||
events_add_sink(events[i].name, events[i].cb, NULL);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: control.c,v 1.61 2026/07/10 15:45:11 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2012 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: environ.c,v 1.31 2026/06/13 20:07:30 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
672
events-payload.c
Normal file
672
events-payload.c
Normal file
@@ -0,0 +1,672 @@
|
||||
/* $OpenBSD: events-payload.c,v 1.1 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2026 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 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 <event.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
/* Event payload item. */
|
||||
struct event_payload_item {
|
||||
char *name;
|
||||
enum event_payload_type type;
|
||||
|
||||
union {
|
||||
char *string;
|
||||
time_t time;
|
||||
int number;
|
||||
u_int unsigned_number;
|
||||
struct client *client;
|
||||
struct session *session;
|
||||
struct window *window;
|
||||
struct window_pane *pane;
|
||||
struct {
|
||||
void *ptr;
|
||||
event_payload_free_cb free_cb;
|
||||
event_payload_print_cb print_cb;
|
||||
} pointer;
|
||||
};
|
||||
|
||||
RB_ENTRY(event_payload_item) entry;
|
||||
};
|
||||
|
||||
RB_HEAD(event_payload_tree, event_payload_item);
|
||||
|
||||
struct event_payload {
|
||||
struct event_payload_tree items;
|
||||
struct cmd_find_state target;
|
||||
};
|
||||
|
||||
static int
|
||||
event_payload_cmp(struct event_payload_item *epi1,
|
||||
struct event_payload_item *epi2)
|
||||
{
|
||||
return (strcmp(epi1->name, epi2->name));
|
||||
}
|
||||
RB_GENERATE_STATIC(event_payload_tree, event_payload_item, entry,
|
||||
event_payload_cmp);
|
||||
|
||||
/* Find an item. */
|
||||
static struct event_payload_item *
|
||||
event_payload_find(struct event_payload *ep, const char *name)
|
||||
{
|
||||
struct event_payload_item find = { .name = (char *)name };
|
||||
|
||||
return (RB_FIND(event_payload_tree, &ep->items, &find));
|
||||
}
|
||||
|
||||
/* Free the target in a payload. */
|
||||
static void
|
||||
event_payload_free_target(struct event_payload *ep)
|
||||
{
|
||||
struct cmd_find_state *target = &ep->target;
|
||||
|
||||
if (target->s != NULL)
|
||||
session_remove_ref(target->s, __func__);
|
||||
if (target->w != NULL)
|
||||
window_remove_ref(target->w, __func__);
|
||||
if (target->wp != NULL)
|
||||
window_pane_remove_ref(target->wp, __func__);
|
||||
|
||||
cmd_find_clear_state(target, 0);
|
||||
}
|
||||
|
||||
/* Free the value in an item. */
|
||||
static void
|
||||
event_payload_free_value(struct event_payload_item *epi)
|
||||
{
|
||||
switch (epi->type) {
|
||||
case EVENT_PAYLOAD_STRING:
|
||||
free(epi->string);
|
||||
break;
|
||||
case EVENT_PAYLOAD_CLIENT:
|
||||
server_client_unref(epi->client);
|
||||
break;
|
||||
case EVENT_PAYLOAD_SESSION:
|
||||
session_remove_ref(epi->session, __func__);
|
||||
break;
|
||||
case EVENT_PAYLOAD_WINDOW:
|
||||
window_remove_ref(epi->window, __func__);
|
||||
break;
|
||||
case EVENT_PAYLOAD_PANE:
|
||||
window_pane_remove_ref(epi->pane, __func__);
|
||||
break;
|
||||
case EVENT_PAYLOAD_POINTER:
|
||||
if (epi->pointer.free_cb != NULL)
|
||||
epi->pointer.free_cb(epi->pointer.ptr);
|
||||
break;
|
||||
case EVENT_PAYLOAD_INT:
|
||||
case EVENT_PAYLOAD_UINT:
|
||||
case EVENT_PAYLOAD_TIME:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set an item. */
|
||||
static void
|
||||
event_payload_set_item(struct event_payload *ep, const char *name,
|
||||
struct event_payload_item *new)
|
||||
{
|
||||
struct event_payload_item *old;
|
||||
|
||||
new->name = xstrdup(name);
|
||||
old = RB_INSERT(event_payload_tree, &ep->items, new);
|
||||
if (old != NULL) {
|
||||
RB_REMOVE(event_payload_tree, &ep->items, old);
|
||||
event_payload_free_value(old);
|
||||
free(old->name);
|
||||
free(old);
|
||||
RB_INSERT(event_payload_tree, &ep->items, new);
|
||||
}
|
||||
}
|
||||
|
||||
/* Create an event payload. */
|
||||
struct event_payload *
|
||||
event_payload_create(void)
|
||||
{
|
||||
struct event_payload *ep;
|
||||
|
||||
ep = xcalloc(1, sizeof *ep);
|
||||
RB_INIT(&ep->items);
|
||||
cmd_find_clear_state(&ep->target, 0);
|
||||
return (ep);
|
||||
}
|
||||
|
||||
/* Free an event payload. */
|
||||
void
|
||||
event_payload_free(struct event_payload *ep)
|
||||
{
|
||||
struct event_payload_item *epi, *epi1;
|
||||
|
||||
if (ep != NULL) {
|
||||
RB_FOREACH_SAFE(epi, event_payload_tree, &ep->items, epi1) {
|
||||
RB_REMOVE(event_payload_tree, &ep->items, epi);
|
||||
event_payload_free_value(epi);
|
||||
free(epi->name);
|
||||
free(epi);
|
||||
}
|
||||
event_payload_free_target(ep);
|
||||
free(ep);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the target. */
|
||||
void
|
||||
event_payload_set_target(struct event_payload *ep, struct cmd_find_state *fs)
|
||||
{
|
||||
struct cmd_find_state *target = &ep->target;
|
||||
|
||||
event_payload_free_target(ep);
|
||||
|
||||
if (fs->s != NULL) {
|
||||
session_add_ref(fs->s, __func__);
|
||||
target->s = fs->s;
|
||||
}
|
||||
if (fs->wl != NULL) {
|
||||
target->idx = fs->wl->idx;
|
||||
if (target->s == NULL) {
|
||||
session_add_ref(fs->wl->session, __func__);
|
||||
target->s = fs->wl->session;
|
||||
}
|
||||
} else
|
||||
target->idx = -1;
|
||||
if (fs->w != NULL) {
|
||||
window_add_ref(fs->w, __func__);
|
||||
target->w = fs->w;
|
||||
} else if (fs->wl != NULL) {
|
||||
window_add_ref(fs->wl->window, __func__);
|
||||
target->w = fs->wl->window;
|
||||
}
|
||||
if (fs->wp != NULL) {
|
||||
window_pane_add_ref(fs->wp, __func__);
|
||||
target->wp = fs->wp;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the target. */
|
||||
int
|
||||
event_payload_get_target(struct event_payload *ep, struct cmd_find_state *fs)
|
||||
{
|
||||
struct cmd_find_state *t = &ep->target;
|
||||
struct winlink *wl = NULL;
|
||||
int flags = fs->flags;
|
||||
|
||||
if (t->idx != -1 &&
|
||||
t->s != NULL &&
|
||||
t->w != NULL &&
|
||||
session_alive(t->s)) {
|
||||
wl = winlink_find_by_index(&t->s->windows, t->idx);
|
||||
if (wl != NULL && wl->window != t->w)
|
||||
wl = NULL;
|
||||
}
|
||||
|
||||
cmd_find_clear_state(fs, flags);
|
||||
fs->s = t->s;
|
||||
fs->w = t->w;
|
||||
fs->wp = t->wp;
|
||||
fs->wl = wl;
|
||||
fs->idx = (wl != NULL ? wl->idx : -1);
|
||||
if (cmd_find_valid_state(fs))
|
||||
return (1);
|
||||
|
||||
if (wl != NULL &&
|
||||
t->wp != NULL &&
|
||||
window_has_pane(wl->window, t->wp)) {
|
||||
cmd_find_from_winlink_pane(fs, wl, t->wp, flags);
|
||||
if (cmd_find_valid_state(fs))
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (t->wp != NULL &&
|
||||
cmd_find_from_pane(fs, t->wp, flags) == 0 &&
|
||||
cmd_find_valid_state(fs))
|
||||
return (1);
|
||||
|
||||
if (wl != NULL) {
|
||||
cmd_find_from_winlink(fs, wl, flags);
|
||||
if (cmd_find_valid_state(fs))
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (t->s != NULL &&
|
||||
t->w != NULL &&
|
||||
session_alive(t->s) &&
|
||||
cmd_find_from_session_window(fs, t->s, t->w, flags) == 0 &&
|
||||
cmd_find_valid_state(fs))
|
||||
return (1);
|
||||
|
||||
if (t->s != NULL && session_alive(t->s)) {
|
||||
cmd_find_from_session(fs, t->s, flags);
|
||||
if (cmd_find_valid_state(fs))
|
||||
return (1);
|
||||
}
|
||||
|
||||
if (cmd_find_from_nothing(fs, flags) == 0)
|
||||
return (1);
|
||||
|
||||
cmd_find_clear_state(fs, flags);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Set a string item. */
|
||||
void
|
||||
event_payload_set_string(struct event_payload *ep, const char *name,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
||||
epi = xcalloc(1, sizeof *epi);
|
||||
epi->type = EVENT_PAYLOAD_STRING;
|
||||
xvasprintf(&epi->string, fmt, ap);
|
||||
event_payload_set_item(ep, name, epi);
|
||||
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
/* Set a time item. */
|
||||
void
|
||||
event_payload_set_time(struct event_payload *ep, const char *name,
|
||||
time_t value)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = xcalloc(1, sizeof *epi);
|
||||
epi->type = EVENT_PAYLOAD_TIME;
|
||||
epi->time = value;
|
||||
event_payload_set_item(ep, name, epi);
|
||||
}
|
||||
|
||||
/* Set a number item. */
|
||||
void
|
||||
event_payload_set_int(struct event_payload *ep, const char *name, int value)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = xcalloc(1, sizeof *epi);
|
||||
epi->type = EVENT_PAYLOAD_INT;
|
||||
epi->number = value;
|
||||
event_payload_set_item(ep, name, epi);
|
||||
}
|
||||
|
||||
/* Set an unsigned number item. */
|
||||
void
|
||||
event_payload_set_uint(struct event_payload *ep, const char *name, u_int value)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = xcalloc(1, sizeof *epi);
|
||||
epi->type = EVENT_PAYLOAD_UINT;
|
||||
epi->unsigned_number = value;
|
||||
event_payload_set_item(ep, name, epi);
|
||||
}
|
||||
|
||||
/* Set a client item. */
|
||||
void
|
||||
event_payload_set_client(struct event_payload *ep, const char *name,
|
||||
struct client *c)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
c->references++;
|
||||
|
||||
epi = xcalloc(1, sizeof *epi);
|
||||
epi->type = EVENT_PAYLOAD_CLIENT;
|
||||
epi->client = c;
|
||||
event_payload_set_item(ep, name, epi);
|
||||
}
|
||||
|
||||
/* Set a session item. */
|
||||
void
|
||||
event_payload_set_session(struct event_payload *ep, const char *name,
|
||||
struct session *s)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
session_add_ref(s, __func__);
|
||||
|
||||
epi = xcalloc(1, sizeof *epi);
|
||||
epi->type = EVENT_PAYLOAD_SESSION;
|
||||
epi->session = s;
|
||||
event_payload_set_item(ep, name, epi);
|
||||
}
|
||||
|
||||
/* Set a window item. */
|
||||
void
|
||||
event_payload_set_window(struct event_payload *ep, const char *name,
|
||||
struct window *w)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
window_add_ref(w, __func__);
|
||||
|
||||
epi = xcalloc(1, sizeof *epi);
|
||||
epi->type = EVENT_PAYLOAD_WINDOW;
|
||||
epi->window = w;
|
||||
event_payload_set_item(ep, name, epi);
|
||||
}
|
||||
|
||||
/* Set a pane item. */
|
||||
void
|
||||
event_payload_set_pane(struct event_payload *ep, const char *name,
|
||||
struct window_pane *wp)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
window_pane_add_ref(wp, __func__);
|
||||
|
||||
epi = xcalloc(1, sizeof *epi);
|
||||
epi->type = EVENT_PAYLOAD_PANE;
|
||||
epi->pane = wp;
|
||||
event_payload_set_item(ep, name, epi);
|
||||
}
|
||||
|
||||
/* Set a pointer item. */
|
||||
void
|
||||
event_payload_set_pointer(struct event_payload *ep, const char *name,
|
||||
void *ptr, event_payload_free_cb free_cb, event_payload_print_cb print_cb)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = xcalloc(1, sizeof *epi);
|
||||
epi->type = EVENT_PAYLOAD_POINTER;
|
||||
epi->pointer.ptr = ptr;
|
||||
epi->pointer.free_cb = free_cb;
|
||||
epi->pointer.print_cb = print_cb;
|
||||
event_payload_set_item(ep, name, epi);
|
||||
}
|
||||
|
||||
/* Get a string item. */
|
||||
const char *
|
||||
event_payload_get_string(struct event_payload *ep, const char *name)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = event_payload_find(ep, name);
|
||||
if (epi == NULL || epi->type != EVENT_PAYLOAD_STRING)
|
||||
return (NULL);
|
||||
return (epi->string);
|
||||
}
|
||||
|
||||
/* Print a payload item. */
|
||||
static void
|
||||
event_payload_add_item(struct event_payload_item *epi, struct evbuffer *evb)
|
||||
{
|
||||
switch (epi->type) {
|
||||
case EVENT_PAYLOAD_STRING:
|
||||
evbuffer_add_printf(evb, "%s", epi->string);
|
||||
break;
|
||||
case EVENT_PAYLOAD_TIME:
|
||||
evbuffer_add_printf(evb, "%lld", (long long)epi->time);
|
||||
break;
|
||||
case EVENT_PAYLOAD_INT:
|
||||
evbuffer_add_printf(evb, "%d", epi->number);
|
||||
break;
|
||||
case EVENT_PAYLOAD_UINT:
|
||||
evbuffer_add_printf(evb, "%u", epi->unsigned_number);
|
||||
break;
|
||||
case EVENT_PAYLOAD_CLIENT:
|
||||
evbuffer_add_printf(evb, "%s", epi->client->name);
|
||||
break;
|
||||
case EVENT_PAYLOAD_SESSION:
|
||||
evbuffer_add_printf(evb, "$%u", epi->session->id);
|
||||
break;
|
||||
case EVENT_PAYLOAD_WINDOW:
|
||||
evbuffer_add_printf(evb, "@%u", epi->window->id);
|
||||
break;
|
||||
case EVENT_PAYLOAD_PANE:
|
||||
evbuffer_add_printf(evb, "%%%u", epi->pane->id);
|
||||
break;
|
||||
case EVENT_PAYLOAD_POINTER:
|
||||
if (epi->pointer.print_cb != NULL)
|
||||
epi->pointer.print_cb(epi->pointer.ptr, evb);
|
||||
else
|
||||
evbuffer_add_printf(evb, "%p", epi->pointer.ptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Print a payload item. */
|
||||
char *
|
||||
event_payload_item_print(struct event_payload_item *epi)
|
||||
{
|
||||
struct evbuffer *evb;
|
||||
char *value = NULL;
|
||||
size_t size;
|
||||
|
||||
evb = evbuffer_new();
|
||||
if (evb == NULL)
|
||||
fatalx("out of memory");
|
||||
event_payload_add_item(epi, evb);
|
||||
if ((size = EVBUFFER_LENGTH(evb)) != 0)
|
||||
value = xmemdup(EVBUFFER_DATA(evb), size);
|
||||
else
|
||||
value = xstrdup("");
|
||||
evbuffer_free(evb);
|
||||
return (value);
|
||||
}
|
||||
|
||||
/* Print an item value. */
|
||||
char *
|
||||
event_payload_print(struct event_payload *ep, const char *name)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = event_payload_find(ep, name);
|
||||
if (epi == NULL)
|
||||
return (NULL);
|
||||
return (event_payload_item_print(epi));
|
||||
}
|
||||
|
||||
/* Add payload items as formats. */
|
||||
void
|
||||
event_payload_add_formats(struct event_payload *ep, struct format_tree *ft,
|
||||
const char *prefix)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
char *name, *value;
|
||||
const char *key;
|
||||
|
||||
if (prefix == NULL)
|
||||
prefix = "";
|
||||
|
||||
RB_FOREACH(epi, event_payload_tree, &ep->items) {
|
||||
key = epi->name;
|
||||
if (*key == '_')
|
||||
continue;
|
||||
|
||||
value = event_payload_item_print(epi);
|
||||
xasprintf(&name, "%s%s", prefix, key);
|
||||
format_add(ft, name, "%s", value);
|
||||
free(name);
|
||||
free(value);
|
||||
|
||||
if (epi->type == EVENT_PAYLOAD_SESSION) {
|
||||
xasprintf(&name, "%s%s_name", prefix, key);
|
||||
format_add(ft, name, "%s", epi->session->name);
|
||||
free(name);
|
||||
} else if (epi->type == EVENT_PAYLOAD_WINDOW) {
|
||||
xasprintf(&name, "%s%s_name", prefix, key);
|
||||
format_add(ft, name, "%s", epi->window->name);
|
||||
free(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the first payload item. */
|
||||
struct event_payload_item *
|
||||
event_payload_first(struct event_payload *ep)
|
||||
{
|
||||
return (RB_MIN(event_payload_tree, &ep->items));
|
||||
}
|
||||
|
||||
/* Get the next payload item. */
|
||||
struct event_payload_item *
|
||||
event_payload_next(struct event_payload_item *epi)
|
||||
{
|
||||
return (RB_NEXT(event_payload_tree, , epi));
|
||||
}
|
||||
|
||||
/* Get a payload item name. */
|
||||
const char *
|
||||
event_payload_item_name(struct event_payload_item *epi)
|
||||
{
|
||||
return (epi->name);
|
||||
}
|
||||
|
||||
/* Get a payload item type. */
|
||||
enum event_payload_type
|
||||
event_payload_item_type(struct event_payload_item *epi)
|
||||
{
|
||||
return (epi->type);
|
||||
}
|
||||
|
||||
/* Log a payload. */
|
||||
void
|
||||
event_payload_log(struct event_payload *ep, const char *fmt, ...)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
struct evbuffer *evb;
|
||||
va_list ap;
|
||||
char *prefix;
|
||||
|
||||
va_start(ap, fmt);
|
||||
xvasprintf(&prefix, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
evb = evbuffer_new();
|
||||
if (evb == NULL)
|
||||
fatalx("out of memory");
|
||||
if (ep != NULL) {
|
||||
RB_FOREACH(epi, event_payload_tree, &ep->items) {
|
||||
if (EVBUFFER_LENGTH(evb) != 0)
|
||||
evbuffer_add_printf(evb, ", ");
|
||||
evbuffer_add_printf(evb, "%s=", epi->name);
|
||||
event_payload_add_item(epi, evb);
|
||||
}
|
||||
}
|
||||
log_debug("%s%.*s", prefix, (int)EVBUFFER_LENGTH(evb),
|
||||
(char *)EVBUFFER_DATA(evb));
|
||||
evbuffer_free(evb);
|
||||
free(prefix);
|
||||
}
|
||||
|
||||
/* Get a time item. */
|
||||
time_t
|
||||
event_payload_get_time(struct event_payload *ep, const char *name)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = event_payload_find(ep, name);
|
||||
if (epi == NULL || epi->type != EVENT_PAYLOAD_TIME)
|
||||
return (0);
|
||||
return (epi->time);
|
||||
}
|
||||
|
||||
/* Get a number item. */
|
||||
int
|
||||
event_payload_get_int(struct event_payload *ep, const char *name, int *value)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = event_payload_find(ep, name);
|
||||
if (epi == NULL || epi->type != EVENT_PAYLOAD_INT)
|
||||
return (-1);
|
||||
*value = epi->number;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Get an unsigned number item. */
|
||||
int
|
||||
event_payload_get_uint(struct event_payload *ep, const char *name, u_int *value)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = event_payload_find(ep, name);
|
||||
if (epi == NULL || epi->type != EVENT_PAYLOAD_UINT)
|
||||
return (-1);
|
||||
*value = epi->unsigned_number;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Get a client item. */
|
||||
struct client *
|
||||
event_payload_get_client(struct event_payload *ep, const char *name)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = event_payload_find(ep, name);
|
||||
if (epi == NULL || epi->type != EVENT_PAYLOAD_CLIENT)
|
||||
return (NULL);
|
||||
return (epi->client);
|
||||
}
|
||||
|
||||
/* Get a session item. */
|
||||
struct session *
|
||||
event_payload_get_session(struct event_payload *ep, const char *name)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = event_payload_find(ep, name);
|
||||
if (epi == NULL || epi->type != EVENT_PAYLOAD_SESSION)
|
||||
return (NULL);
|
||||
return (epi->session);
|
||||
}
|
||||
|
||||
/* Get a window item. */
|
||||
struct window *
|
||||
event_payload_get_window(struct event_payload *ep, const char *name)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = event_payload_find(ep, name);
|
||||
if (epi == NULL || epi->type != EVENT_PAYLOAD_WINDOW)
|
||||
return (NULL);
|
||||
return (epi->window);
|
||||
}
|
||||
|
||||
/* Get a pane item. */
|
||||
struct window_pane *
|
||||
event_payload_get_pane(struct event_payload *ep, const char *name)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = event_payload_find(ep, name);
|
||||
if (epi == NULL || epi->type != EVENT_PAYLOAD_PANE)
|
||||
return (NULL);
|
||||
return (epi->pane);
|
||||
}
|
||||
|
||||
/* Get a pointer item. */
|
||||
void *
|
||||
event_payload_get_pointer(struct event_payload *ep, const char *name)
|
||||
{
|
||||
struct event_payload_item *epi;
|
||||
|
||||
epi = event_payload_find(ep, name);
|
||||
if (epi == NULL || epi->type != EVENT_PAYLOAD_POINTER)
|
||||
return (NULL);
|
||||
return (epi->pointer.ptr);
|
||||
}
|
||||
199
events.c
Normal file
199
events.c
Normal file
@@ -0,0 +1,199 @@
|
||||
/* $OpenBSD: events.c,v 1.1 2026/07/10 13:38:45 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2026 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 USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
/* Event sink. */
|
||||
struct events_sink {
|
||||
char *name;
|
||||
events_cb cb;
|
||||
void *data;
|
||||
int dead;
|
||||
u_int generation;
|
||||
|
||||
TAILQ_ENTRY(events_sink) entry;
|
||||
};
|
||||
|
||||
TAILQ_HEAD(events_sinks, events_sink);
|
||||
static struct events_sinks events_sinks = TAILQ_HEAD_INITIALIZER(events_sinks);
|
||||
|
||||
static u_int events_dispatching;
|
||||
static u_int events_generation;
|
||||
|
||||
/* Free an event sink. */
|
||||
static void
|
||||
events_free_sink(struct events_sink *es)
|
||||
{
|
||||
TAILQ_REMOVE(&events_sinks, es, entry);
|
||||
free(es->name);
|
||||
free(es);
|
||||
}
|
||||
|
||||
/* Free dead event sinks. */
|
||||
static void
|
||||
events_free_dead(void)
|
||||
{
|
||||
struct events_sink *es, *es1;
|
||||
|
||||
TAILQ_FOREACH_SAFE(es, &events_sinks, entry, es1) {
|
||||
if (es->dead)
|
||||
events_free_sink(es);
|
||||
}
|
||||
}
|
||||
|
||||
/* Add an event sink. */
|
||||
struct events_sink *
|
||||
events_add_sink(const char *name, events_cb cb, void *data)
|
||||
{
|
||||
struct events_sink *es;
|
||||
|
||||
es = xcalloc(1, sizeof *es);
|
||||
es->name = xstrdup(name);
|
||||
es->cb = cb;
|
||||
es->data = data;
|
||||
es->generation = ++events_generation;
|
||||
|
||||
TAILQ_INSERT_TAIL(&events_sinks, es, entry);
|
||||
return (es);
|
||||
}
|
||||
|
||||
/* Remove an event sink. */
|
||||
void
|
||||
events_remove_sink(struct events_sink *es)
|
||||
{
|
||||
if (es != NULL && !es->dead) {
|
||||
if (events_dispatching != 0)
|
||||
es->dead = 1;
|
||||
else
|
||||
events_free_sink(es);
|
||||
}
|
||||
}
|
||||
|
||||
/* Fire an event. */
|
||||
void
|
||||
events_fire(const char *name, struct event_payload *ep)
|
||||
{
|
||||
struct events_sink *es;
|
||||
u_int generation = events_generation;
|
||||
|
||||
event_payload_set_string(ep, "event", "%s", name);
|
||||
|
||||
if (log_get_level() != 0)
|
||||
event_payload_log(ep, "%s: %s: ", __func__, name);
|
||||
|
||||
events_dispatching++;
|
||||
TAILQ_FOREACH(es, &events_sinks, entry) {
|
||||
if (es->dead || es->generation > generation)
|
||||
continue;
|
||||
if (strcmp(es->name, name) == 0)
|
||||
es->cb(name, ep, es->data);
|
||||
}
|
||||
if (--events_dispatching == 0)
|
||||
events_free_dead();
|
||||
event_payload_free(ep);
|
||||
}
|
||||
|
||||
/* Fire a client event. */
|
||||
void
|
||||
events_fire_client(const char *name, struct client *c)
|
||||
{
|
||||
struct event_payload *ep;
|
||||
struct cmd_find_state fs;
|
||||
|
||||
ep = event_payload_create();
|
||||
cmd_find_from_client(&fs, c, 0);
|
||||
event_payload_set_target(ep, &fs);
|
||||
event_payload_set_client(ep, "client", c);
|
||||
if (fs.s != NULL)
|
||||
event_payload_set_session(ep, "session", fs.s);
|
||||
if (fs.w != NULL)
|
||||
event_payload_set_window(ep, "window", fs.w);
|
||||
if (fs.wl != NULL)
|
||||
event_payload_set_int(ep, "window_index", fs.wl->idx);
|
||||
else if (fs.idx != -1)
|
||||
event_payload_set_int(ep, "window_index", fs.idx);
|
||||
if (fs.wp != NULL)
|
||||
event_payload_set_pane(ep, "pane", fs.wp);
|
||||
events_fire(name, ep);
|
||||
}
|
||||
|
||||
/* Fire a session event. */
|
||||
void
|
||||
events_fire_session(const char *name, struct session *s)
|
||||
{
|
||||
struct event_payload *ep;
|
||||
struct cmd_find_state fs;
|
||||
|
||||
ep = event_payload_create();
|
||||
if (session_alive(s)) {
|
||||
cmd_find_from_session(&fs, s, 0);
|
||||
event_payload_set_target(ep, &fs);
|
||||
}
|
||||
event_payload_set_session(ep, "session", s);
|
||||
events_fire(name, ep);
|
||||
}
|
||||
|
||||
/* Fire a window event. */
|
||||
void
|
||||
events_fire_window(const char *name, struct window *w)
|
||||
{
|
||||
struct event_payload *ep;
|
||||
struct cmd_find_state fs;
|
||||
|
||||
ep = event_payload_create();
|
||||
cmd_find_from_window(&fs, w, 0);
|
||||
event_payload_set_target(ep, &fs);
|
||||
event_payload_set_window(ep, "window", w);
|
||||
events_fire(name, ep);
|
||||
}
|
||||
|
||||
/* Fire a pane event. */
|
||||
void
|
||||
events_fire_pane(const char *name, struct window_pane *wp)
|
||||
{
|
||||
struct event_payload *ep;
|
||||
struct cmd_find_state fs;
|
||||
|
||||
ep = event_payload_create();
|
||||
cmd_find_from_pane(&fs, wp, 0);
|
||||
event_payload_set_target(ep, &fs);
|
||||
event_payload_set_pane(ep, "pane", wp);
|
||||
event_payload_set_window(ep, "window", wp->window);
|
||||
events_fire(name, ep);
|
||||
}
|
||||
|
||||
/* Fire a winlink event. */
|
||||
void
|
||||
events_fire_winlink(const char *name, struct winlink *wl)
|
||||
{
|
||||
struct event_payload *ep;
|
||||
struct cmd_find_state fs;
|
||||
|
||||
ep = event_payload_create();
|
||||
cmd_find_from_winlink(&fs, wl, 0);
|
||||
event_payload_set_target(ep, &fs);
|
||||
event_payload_set_session(ep, "session", wl->session);
|
||||
event_payload_set_window(ep, "window", wl->window);
|
||||
event_payload_set_int(ep, "window_index", wl->idx);
|
||||
events_fire(name, ep);
|
||||
}
|
||||
2
file.c
2
file.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: file.c,v 1.20 2026/05/17 10:54:01 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: format-draw.c,v 1.33 2026/06/29 17:08:52 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
123
format.c
123
format.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: format.c,v 1.403 2026/07/10 15:20:06 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2011 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -2201,6 +2201,106 @@ format_cb_pane_dead_time(struct format_tree *ft)
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Callback for pane_last_output_time. */
|
||||
static void *
|
||||
format_cb_pane_last_output_time(struct format_tree *ft)
|
||||
{
|
||||
struct window_pane *wp = ft->wp;
|
||||
static struct timeval tv;
|
||||
|
||||
if (wp != NULL && wp->last_output_time != 0) {
|
||||
tv.tv_sec = wp->last_output_time;
|
||||
tv.tv_usec = 0;
|
||||
return (&tv);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Callback for pane_last_prompt_time. */
|
||||
static void *
|
||||
format_cb_pane_last_prompt_time(struct format_tree *ft)
|
||||
{
|
||||
struct window_pane *wp = ft->wp;
|
||||
static struct timeval tv;
|
||||
|
||||
if (wp != NULL && wp->last_prompt_time != 0) {
|
||||
tv.tv_sec = wp->last_prompt_time;
|
||||
tv.tv_usec = 0;
|
||||
return (&tv);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Callback for pane_command_start_time. */
|
||||
static void *
|
||||
format_cb_pane_command_start_time(struct format_tree *ft)
|
||||
{
|
||||
struct window_pane *wp = ft->wp;
|
||||
static struct timeval tv;
|
||||
|
||||
if (wp != NULL && wp->cmd_start_time != 0) {
|
||||
tv.tv_sec = wp->cmd_start_time;
|
||||
tv.tv_usec = 0;
|
||||
return (&tv);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Callback for pane_command_end_time. */
|
||||
static void *
|
||||
format_cb_pane_command_end_time(struct format_tree *ft)
|
||||
{
|
||||
struct window_pane *wp = ft->wp;
|
||||
static struct timeval tv;
|
||||
|
||||
if (wp != NULL && wp->cmd_end_time != 0) {
|
||||
tv.tv_sec = wp->cmd_end_time;
|
||||
tv.tv_usec = 0;
|
||||
return (&tv);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Callback for pane_command_running. */
|
||||
static void *
|
||||
format_cb_pane_command_running(struct format_tree *ft)
|
||||
{
|
||||
struct window_pane *wp = ft->wp;
|
||||
|
||||
if (wp != NULL)
|
||||
return (format_printf("%d", !!(wp->flags & PANE_CMDRUNNING)));
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Callback for pane_command_duration. */
|
||||
static void *
|
||||
format_cb_pane_command_duration(struct format_tree *ft)
|
||||
{
|
||||
struct window_pane *wp = ft->wp;
|
||||
time_t end;
|
||||
|
||||
if (wp == NULL || wp->cmd_start_time == 0)
|
||||
return (NULL);
|
||||
if (wp->flags & PANE_CMDRUNNING)
|
||||
end = time(NULL);
|
||||
else
|
||||
end = wp->cmd_end_time;
|
||||
if (end < wp->cmd_start_time)
|
||||
end = wp->cmd_start_time;
|
||||
return (format_printf("%lld", (long long)(end - wp->cmd_start_time)));
|
||||
}
|
||||
|
||||
/* Callback for pane_command_status. */
|
||||
static void *
|
||||
format_cb_pane_command_status(struct format_tree *ft)
|
||||
{
|
||||
struct window_pane *wp = ft->wp;
|
||||
|
||||
if (wp != NULL && wp->cmd_status != -1)
|
||||
return (format_printf("%d", wp->cmd_status));
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Callback for pane_format. */
|
||||
static void *
|
||||
format_cb_pane_format(struct format_tree *ft)
|
||||
@@ -3517,6 +3617,21 @@ static const struct format_table_entry format_table[] = {
|
||||
{ "pane_bottom", FORMAT_TABLE_STRING,
|
||||
format_cb_pane_bottom
|
||||
},
|
||||
{ "pane_command_duration", FORMAT_TABLE_STRING,
|
||||
format_cb_pane_command_duration
|
||||
},
|
||||
{ "pane_command_end_time", FORMAT_TABLE_TIME,
|
||||
format_cb_pane_command_end_time
|
||||
},
|
||||
{ "pane_command_running", FORMAT_TABLE_STRING,
|
||||
format_cb_pane_command_running
|
||||
},
|
||||
{ "pane_command_start_time", FORMAT_TABLE_TIME,
|
||||
format_cb_pane_command_start_time
|
||||
},
|
||||
{ "pane_command_status", FORMAT_TABLE_STRING,
|
||||
format_cb_pane_command_status
|
||||
},
|
||||
{ "pane_current_command", FORMAT_TABLE_STRING,
|
||||
format_cb_current_command
|
||||
},
|
||||
@@ -3568,6 +3683,12 @@ static const struct format_table_entry format_table[] = {
|
||||
{ "pane_last", FORMAT_TABLE_STRING,
|
||||
format_cb_pane_last
|
||||
},
|
||||
{ "pane_last_output_time", FORMAT_TABLE_TIME,
|
||||
format_cb_pane_last_output_time
|
||||
},
|
||||
{ "pane_last_prompt_time", FORMAT_TABLE_TIME,
|
||||
format_cb_pane_last_prompt_time
|
||||
},
|
||||
{ "pane_left", FORMAT_TABLE_STRING,
|
||||
format_cb_pane_left
|
||||
},
|
||||
|
||||
2
fuzzy.c
2
fuzzy.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: fuzzy.c,v 1.1 2026/06/26 14:40:30 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2026 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: grid-reader.c,v 1.10 2026/05/17 13:12:21 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2020 Anindya Mukherjee <anindya49@hotmail.com>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: grid-view.c,v 1.38 2026/01/22 08:55:01 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
2
grid.c
2
grid.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: grid.c,v 1.153 2026/07/02 08:51:05 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
461
hooks.c
Normal file
461
hooks.c
Normal file
@@ -0,0 +1,461 @@
|
||||
/* $OpenBSD: hooks.c,v 1.13 2026/07/10 15:20:06 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2026 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
* Copyright (c) 2012 George Nachman <tmux@georgester.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
/* Hook monitor state owned by an option entry. */
|
||||
struct hook_monitor {
|
||||
struct options *oo;
|
||||
|
||||
struct monitor_set *set;
|
||||
struct events_sink *sink;
|
||||
struct cmd_find_state fs;
|
||||
|
||||
enum monitor_type type;
|
||||
int id;
|
||||
char *format;
|
||||
};
|
||||
|
||||
/* Hook command data built from an event payload. */
|
||||
struct hooks_data {
|
||||
const char *name;
|
||||
struct cmd_find_state fs;
|
||||
struct format_tree *formats;
|
||||
struct options *oo;
|
||||
struct client *client;
|
||||
int expand;
|
||||
};
|
||||
|
||||
/* Hook event sink registered for a notify event name. */
|
||||
struct hooks_event {
|
||||
char *name;
|
||||
struct events_sink *sink;
|
||||
TAILQ_ENTRY(hooks_event) entry;
|
||||
};
|
||||
TAILQ_HEAD(hooks_events, hooks_event);
|
||||
static struct hooks_events hooks_events = TAILQ_HEAD_INITIALIZER(hooks_events);
|
||||
|
||||
/* Insert one hook command list. */
|
||||
static struct cmdq_item *
|
||||
hooks_insert_one(struct cmdq_item *item, struct hooks_data *hd,
|
||||
struct cmd_list *cmdlist, struct cmdq_state *state)
|
||||
{
|
||||
struct cmdq_item *new_item;
|
||||
char *s;
|
||||
|
||||
if (cmdlist == NULL)
|
||||
return (item);
|
||||
if (log_get_level() != 0) {
|
||||
s = cmd_list_print(cmdlist, 0);
|
||||
log_debug("%s: hook %s is: %s", __func__, hd->name, s);
|
||||
free(s);
|
||||
}
|
||||
new_item = cmdq_get_command(cmdlist, state);
|
||||
if (item != NULL)
|
||||
return (cmdq_insert_after(item, new_item));
|
||||
return (cmdq_append(NULL, new_item));
|
||||
}
|
||||
|
||||
/* Parse a hook command. */
|
||||
static struct cmd_parse_result *
|
||||
hooks_parse(struct hooks_data *hd, struct cmd_find_state *fs,
|
||||
const char *value)
|
||||
{
|
||||
struct cmd_parse_result *pr;
|
||||
struct format_tree *ft;
|
||||
char *expanded;
|
||||
|
||||
if (!hd->expand)
|
||||
return (cmd_parse_from_string(value, NULL));
|
||||
|
||||
ft = format_create_defaults(NULL, hd->client, fs->s, fs->wl, fs->wp);
|
||||
if (hd->formats != NULL)
|
||||
format_merge(ft, hd->formats);
|
||||
expanded = format_expand(ft, value);
|
||||
format_free(ft);
|
||||
|
||||
pr = cmd_parse_from_string(expanded, NULL);
|
||||
free(expanded);
|
||||
return (pr);
|
||||
}
|
||||
|
||||
/* Insert commands for a hook. */
|
||||
static void
|
||||
hooks_insert(struct cmdq_item *item, struct hooks_data *hd)
|
||||
{
|
||||
struct cmd_find_state fs;
|
||||
struct options *oo;
|
||||
struct cmdq_state *state;
|
||||
struct options_entry *o;
|
||||
struct options_array_item *a;
|
||||
struct cmd_list *cmdlist;
|
||||
const char *value;
|
||||
struct cmd_parse_result *pr;
|
||||
|
||||
log_debug("%s: inserting hook %s", __func__, hd->name);
|
||||
|
||||
cmd_find_clear_state(&fs, 0);
|
||||
if (cmd_find_empty_state(&hd->fs) || !cmd_find_valid_state(&hd->fs))
|
||||
cmd_find_from_nothing(&fs, 0);
|
||||
else
|
||||
cmd_find_copy_state(&fs, &hd->fs);
|
||||
|
||||
if (hd->oo != NULL) {
|
||||
oo = hd->oo;
|
||||
o = options_get_only(oo, hd->name);
|
||||
} else {
|
||||
if (fs.s == NULL)
|
||||
oo = global_s_options;
|
||||
else
|
||||
oo = fs.s->options;
|
||||
o = options_get(oo, hd->name);
|
||||
if (o == NULL && fs.wp != NULL) {
|
||||
oo = fs.wp->options;
|
||||
o = options_get(oo, hd->name);
|
||||
}
|
||||
if (o == NULL && fs.wl != NULL) {
|
||||
oo = fs.wl->window->options;
|
||||
o = options_get(oo, hd->name);
|
||||
}
|
||||
}
|
||||
if (o == NULL) {
|
||||
log_debug("%s: hook %s not found", __func__, hd->name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (item == NULL)
|
||||
state = cmdq_new_state(&fs, NULL, CMDQ_STATE_NOHOOKS);
|
||||
else {
|
||||
state = cmdq_new_state(&fs, cmdq_get_event(item),
|
||||
CMDQ_STATE_NOHOOKS);
|
||||
}
|
||||
cmdq_add_formats(state, hd->formats);
|
||||
|
||||
if (*hd->name == '@') {
|
||||
value = options_get_string(oo, hd->name);
|
||||
pr = hooks_parse(hd, &fs, value);
|
||||
switch (pr->status) {
|
||||
case CMD_PARSE_ERROR:
|
||||
log_debug("%s: can't parse hook %s: %s", __func__,
|
||||
hd->name, pr->error);
|
||||
free(pr->error);
|
||||
break;
|
||||
case CMD_PARSE_SUCCESS:
|
||||
hooks_insert_one(item, hd, pr->cmdlist, state);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
a = options_array_first(o);
|
||||
while (a != NULL) {
|
||||
if (hd->expand) {
|
||||
value = options_array_item_value(a)->string;
|
||||
pr = hooks_parse(hd, &fs, value);
|
||||
switch (pr->status) {
|
||||
case CMD_PARSE_ERROR:
|
||||
if (pr->error != NULL) {
|
||||
cmdq_error(item, "%s",
|
||||
pr->error);
|
||||
}
|
||||
break;
|
||||
case CMD_PARSE_SUCCESS:
|
||||
item = hooks_insert_one(item, hd,
|
||||
pr->cmdlist, state);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
cmdlist = options_array_item_value(a)->cmdlist;
|
||||
item = hooks_insert_one(item, hd, cmdlist,
|
||||
state);
|
||||
}
|
||||
a = options_array_next(a);
|
||||
}
|
||||
}
|
||||
|
||||
cmdq_free_state(state);
|
||||
}
|
||||
|
||||
/* Insert commands for a hook event. */
|
||||
static void
|
||||
hooks_insert_event(struct cmdq_item *item, const char *name,
|
||||
struct event_payload *ep, struct options *oo, int expand)
|
||||
{
|
||||
struct hooks_data hd;
|
||||
struct format_tree *ft;
|
||||
struct client *c;
|
||||
|
||||
if (item != NULL && (cmdq_get_flags(item) & CMDQ_STATE_NOHOOKS))
|
||||
return;
|
||||
|
||||
c = event_payload_get_client(ep, "client");
|
||||
ft = format_create(c, item, FORMAT_NONE, FORMAT_NOJOBS);
|
||||
event_payload_add_formats(ep, ft, "hook_");
|
||||
format_add(ft, "hook", "%s", name);
|
||||
format_log_debug(ft, __func__);
|
||||
|
||||
memset(&hd, 0, sizeof hd);
|
||||
hd.name = name;
|
||||
cmd_find_clear_state(&hd.fs, 0);
|
||||
event_payload_get_target(ep, &hd.fs);
|
||||
hd.formats = ft;
|
||||
hd.oo = oo;
|
||||
hd.client = c;
|
||||
hd.expand = expand;
|
||||
|
||||
hooks_insert(item, &hd);
|
||||
format_free(ft);
|
||||
}
|
||||
|
||||
/* Handle an event for hooks. */
|
||||
static void
|
||||
hooks_event_cb(const char *name, struct event_payload *ep,
|
||||
__unused void *sink_data)
|
||||
{
|
||||
struct cmdq_item *item;
|
||||
|
||||
if (event_payload_get_pointer(ep, "_hook_monitor") != NULL)
|
||||
return;
|
||||
|
||||
item = event_payload_get_pointer(ep, "_cmdq_item");
|
||||
if (item != NULL) {
|
||||
hooks_insert_event(item, name, ep, NULL, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
item = cmdq_running(NULL);
|
||||
if (item == NULL || (~cmdq_get_flags(item) & CMDQ_STATE_NOHOOKS))
|
||||
hooks_insert_event(NULL, name, ep, NULL, 0);
|
||||
}
|
||||
|
||||
/* Add a hook event sink. */
|
||||
void
|
||||
hooks_add_event(const char *name)
|
||||
{
|
||||
struct hooks_event *he;
|
||||
|
||||
TAILQ_FOREACH(he, &hooks_events, entry) {
|
||||
if (strcmp(he->name, name) == 0)
|
||||
return;
|
||||
}
|
||||
|
||||
he = xcalloc(1, sizeof *he);
|
||||
he->name = xstrdup(name);
|
||||
he->sink = events_add_sink(name, hooks_event_cb, NULL);
|
||||
TAILQ_INSERT_TAIL(&hooks_events, he, entry);
|
||||
}
|
||||
|
||||
/* Return if an event name can be fired through the hooks path. */
|
||||
int
|
||||
hooks_valid_event_name(const char *name)
|
||||
{
|
||||
const struct options_table_entry *oe;
|
||||
|
||||
if (*name == '@')
|
||||
return (1);
|
||||
oe = options_search(name);
|
||||
return (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_HOOK));
|
||||
}
|
||||
|
||||
/* Add hook event sinks for all built-in hooks. */
|
||||
void
|
||||
hooks_build_events(void)
|
||||
{
|
||||
const struct options_table_entry *oe;
|
||||
|
||||
for (oe = options_table; oe->name != NULL; oe++) {
|
||||
if (oe->flags & OPTIONS_TABLE_IS_HOOK)
|
||||
hooks_add_event(oe->name);
|
||||
}
|
||||
}
|
||||
|
||||
/* Run a hook immediately. */
|
||||
void
|
||||
hooks_run(struct cmdq_item *item, const char *name)
|
||||
{
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
struct hooks_data hd = { 0 };
|
||||
|
||||
hd.name = name;
|
||||
cmd_find_copy_state(&hd.fs, target);
|
||||
hd.client = cmdq_get_client(item);
|
||||
|
||||
hd.formats = format_create(NULL, NULL, 0, FORMAT_NOJOBS);
|
||||
format_add(hd.formats, "hook", "%s", name);
|
||||
format_log_debug(hd.formats, __func__);
|
||||
|
||||
hooks_insert(item, &hd);
|
||||
format_free(hd.formats);
|
||||
}
|
||||
|
||||
/* Free a hook monitor. */
|
||||
void
|
||||
hooks_monitor_free(void *data)
|
||||
{
|
||||
struct hook_monitor *hm = data;
|
||||
|
||||
events_remove_sink(hm->sink);
|
||||
monitor_destroy(hm->set);
|
||||
free(hm->format);
|
||||
free(hm);
|
||||
}
|
||||
|
||||
/* Remove a hook monitor. */
|
||||
void
|
||||
hooks_monitor_remove(struct options *oo, const char *name)
|
||||
{
|
||||
struct options_entry *o;
|
||||
struct hook_monitor *hm;
|
||||
|
||||
o = options_get_only(oo, name);
|
||||
if (o == NULL)
|
||||
return;
|
||||
|
||||
hm = options_get_monitor_data(o);
|
||||
if (hm != NULL) {
|
||||
options_set_monitor_data(o, NULL);
|
||||
hooks_monitor_free(hm);
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle a hook monitor event. */
|
||||
static void
|
||||
hooks_monitor_hook_cb(const char *name, struct event_payload *ep,
|
||||
void *sink_data)
|
||||
{
|
||||
struct hook_monitor *hm = sink_data;
|
||||
|
||||
if (event_payload_get_pointer(ep, "_hook_monitor") == hm)
|
||||
hooks_insert_event(cmdq_running(NULL), name, ep, hm->oo, 1);
|
||||
}
|
||||
|
||||
/* Fire a hook monitor event. */
|
||||
static void
|
||||
hooks_monitor_cb(struct monitor_change *change, void *data)
|
||||
{
|
||||
struct hook_monitor *hm = data;
|
||||
struct event_payload *ep;
|
||||
struct winlink *wl = change->wl;
|
||||
struct window_pane *wp = change->wp;
|
||||
struct cmd_find_state fs;
|
||||
|
||||
ep = event_payload_create();
|
||||
event_payload_set_pointer(ep, "_hook_monitor", data, NULL, NULL);
|
||||
|
||||
cmd_find_clear_state(&fs, 0);
|
||||
if (wl != NULL && wp != NULL && wp->window == wl->window)
|
||||
cmd_find_from_winlink_pane(&fs, wl, wp, 0);
|
||||
else if (wl != NULL)
|
||||
cmd_find_from_winlink(&fs, wl, 0);
|
||||
else if (wp != NULL)
|
||||
cmd_find_from_pane(&fs, wp, 0);
|
||||
else if (change->s != NULL)
|
||||
cmd_find_from_session(&fs, change->s, 0);
|
||||
else
|
||||
cmd_find_copy_state(&fs, &hm->fs);
|
||||
event_payload_set_target(ep, &fs);
|
||||
|
||||
if (change->value != NULL)
|
||||
event_payload_set_string(ep, "value", "%s", change->value);
|
||||
else
|
||||
event_payload_set_string(ep, "value", "%s", "");
|
||||
if (change->last != NULL)
|
||||
event_payload_set_string(ep, "last", "%s", change->last);
|
||||
else
|
||||
event_payload_set_string(ep, "last", "%s", "");
|
||||
|
||||
if (change->c != NULL)
|
||||
event_payload_set_client(ep, "client", change->c);
|
||||
if (change->s != NULL)
|
||||
event_payload_set_session(ep, "session", change->s);
|
||||
if (wl != NULL) {
|
||||
if (change->s == NULL)
|
||||
event_payload_set_session(ep, "session",
|
||||
wl->session);
|
||||
event_payload_set_window(ep, "window", wl->window);
|
||||
event_payload_set_int(ep, "window_index", wl->idx);
|
||||
}
|
||||
if (wp != NULL) {
|
||||
event_payload_set_pane(ep, "pane", wp);
|
||||
if (wl == NULL)
|
||||
event_payload_set_window(ep, "window", wp->window);
|
||||
}
|
||||
|
||||
events_fire(change->name, ep);
|
||||
}
|
||||
|
||||
/* Add a hook monitor. */
|
||||
void
|
||||
hooks_monitor_add(__unused struct cmdq_item *item, struct options *oo,
|
||||
const char *name, enum monitor_type type, int id, const char *format,
|
||||
int flags, struct cmd_find_state *fs, struct session *s)
|
||||
{
|
||||
struct options_entry *o;
|
||||
struct hook_monitor *hm;
|
||||
|
||||
hooks_monitor_remove(oo, name);
|
||||
o = options_get_only(oo, name);
|
||||
if (o == NULL)
|
||||
o = options_set_string(oo, name, 0, "%s", "");
|
||||
|
||||
hm = xcalloc(1, sizeof *hm);
|
||||
hm->oo = oo;
|
||||
cmd_find_copy_state(&hm->fs, fs);
|
||||
hm->type = type;
|
||||
hm->id = id;
|
||||
hm->format = xstrdup(format);
|
||||
hm->set = monitor_create_session(s, hooks_monitor_cb, hm);
|
||||
hm->sink = events_add_sink(name, hooks_monitor_hook_cb, hm);
|
||||
options_set_monitor_data(o, hm);
|
||||
monitor_add(hm->set, name, type, id, format, flags);
|
||||
}
|
||||
|
||||
/* Convert a hook monitor to its value. */
|
||||
char *
|
||||
hooks_monitor_to_string(struct options_entry *o)
|
||||
{
|
||||
struct hook_monitor *hm = options_get_monitor_data(o);
|
||||
const char *name = options_name(o);
|
||||
char *s;
|
||||
|
||||
if (hm == NULL)
|
||||
return (NULL);
|
||||
|
||||
switch (hm->type) {
|
||||
case MONITOR_SESSION:
|
||||
xasprintf(&s, "%s::%s", name, hm->format);
|
||||
break;
|
||||
case MONITOR_PANE:
|
||||
xasprintf(&s, "%s:%%%d:%s", name, hm->id, hm->format);
|
||||
break;
|
||||
case MONITOR_ALL_PANES:
|
||||
xasprintf(&s, "%s:%%*:%s", name, hm->format);
|
||||
break;
|
||||
case MONITOR_WINDOW:
|
||||
xasprintf(&s, "%s:@%d:%s", name, hm->id, hm->format);
|
||||
break;
|
||||
case MONITOR_ALL_WINDOWS:
|
||||
xasprintf(&s, "%s:@*:%s", name, hm->format);
|
||||
break;
|
||||
}
|
||||
return (s);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: hyperlinks.c,v 1.5 2026/06/29 16:44:06 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2021 Will <author@will.party>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: input-keys.c,v 1.114 2026/06/15 21:47:01 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
|
||||
120
input.c
120
input.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: input.c,v 1.268 2026/07/13 15:03:03 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -174,6 +174,8 @@ static void input_osc_110(struct input_ctx *, const char *);
|
||||
static void input_osc_111(struct input_ctx *, const char *);
|
||||
static void input_osc_112(struct input_ctx *, const char *);
|
||||
static void input_osc_133(struct input_ctx *, const char *);
|
||||
static void input_fire_pane_title_changed(struct window_pane *,
|
||||
const char *);
|
||||
|
||||
/* Transition entry/exit handlers. */
|
||||
static void input_clear(struct input_ctx *);
|
||||
@@ -210,6 +212,21 @@ static int input_end_bel(struct input_ctx *);
|
||||
/* Command table comparison function. */
|
||||
static int input_table_compare(const void *, const void *);
|
||||
|
||||
static void
|
||||
input_fire_pane_title_changed(struct window_pane *wp, const char *title)
|
||||
{
|
||||
struct event_payload *ep;
|
||||
struct cmd_find_state fs;
|
||||
|
||||
ep = event_payload_create();
|
||||
cmd_find_from_pane(&fs, wp, 0);
|
||||
event_payload_set_target(ep, &fs);
|
||||
event_payload_set_pane(ep, "pane", wp);
|
||||
event_payload_set_window(ep, "window", wp->window);
|
||||
event_payload_set_string(ep, "new_title", "%s", title);
|
||||
events_fire("pane-title-changed", ep);
|
||||
}
|
||||
|
||||
/* Command table entry. */
|
||||
struct input_table_entry {
|
||||
int ch;
|
||||
@@ -1017,6 +1034,8 @@ input_parse_pane(struct window_pane *wp)
|
||||
size_t new_size;
|
||||
|
||||
new_data = window_pane_get_new_data(wp, &wp->offset, &new_size);
|
||||
if (new_size != 0)
|
||||
wp->last_output_time = time(NULL);
|
||||
input_parse_buffer(wp, new_data, new_size);
|
||||
window_pane_update_used_data(wp, &wp->offset, new_size);
|
||||
}
|
||||
@@ -1032,6 +1051,10 @@ input_parse_buffer(struct window_pane *wp, const u_char *buf, size_t len)
|
||||
return;
|
||||
|
||||
window_update_activity(wp->window);
|
||||
if (~wp->flags & PANE_ACTIVITY) {
|
||||
wp->flags |= PANE_ACTIVITY;
|
||||
events_fire_pane("pane-activity", wp);
|
||||
}
|
||||
wp->flags |= PANE_CHANGED;
|
||||
|
||||
/* Flag new input while in a mode. */
|
||||
@@ -1297,8 +1320,10 @@ input_c0_dispatch(struct input_ctx *ictx)
|
||||
case '\000': /* NUL */
|
||||
break;
|
||||
case '\007': /* BEL */
|
||||
if (wp != NULL)
|
||||
if (wp != NULL) {
|
||||
events_fire_pane("pane-bell", wp);
|
||||
alerts_queue(wp->window, WINDOW_BELL);
|
||||
}
|
||||
break;
|
||||
case '\010': /* BS */
|
||||
screen_write_backspace(sctx);
|
||||
@@ -2180,7 +2205,7 @@ input_csi_dispatch_winops(struct input_ctx *ictx)
|
||||
screen_pop_title(sctx->s);
|
||||
if (wp == NULL)
|
||||
break;
|
||||
notify_pane("pane-title-changed", wp);
|
||||
input_fire_pane_title_changed(wp, sctx->s->title);
|
||||
server_redraw_window_borders(w);
|
||||
server_status_window(w);
|
||||
break;
|
||||
@@ -2700,7 +2725,7 @@ input_exit_osc(struct input_ctx *ictx)
|
||||
if (wp != NULL &&
|
||||
options_get_number(wp->options, "allow-set-title") &&
|
||||
screen_set_title(sctx->s, p, 1)) {
|
||||
notify_pane("pane-title-changed", wp);
|
||||
input_fire_pane_title_changed(wp, p);
|
||||
server_redraw_window_borders(wp->window);
|
||||
server_status_window(wp->window);
|
||||
}
|
||||
@@ -2778,7 +2803,7 @@ input_exit_apc(struct input_ctx *ictx)
|
||||
if (wp != NULL &&
|
||||
options_get_number(wp->options, "allow-set-title") &&
|
||||
screen_set_title(sctx->s, ictx->input_buf, 1)) {
|
||||
notify_pane("pane-title-changed", wp);
|
||||
input_fire_pane_title_changed(wp, ictx->input_buf);
|
||||
server_redraw_window_borders(wp->window);
|
||||
server_status_window(wp->window);
|
||||
}
|
||||
@@ -3146,7 +3171,8 @@ input_osc_12(struct input_ctx *ictx, const char *p)
|
||||
c = ictx->ctx.s->ccolour;
|
||||
if (c == -1)
|
||||
c = ictx->ctx.s->default_ccolour;
|
||||
input_osc_colour_reply(ictx, 1, 12, 0, c, ictx->input_end);
|
||||
input_osc_colour_reply(ictx, 1, 12, 0, c,
|
||||
ictx->input_end);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -3166,24 +3192,92 @@ input_osc_112(struct input_ctx *ictx, const char *p)
|
||||
screen_set_cursor_colour(ictx->ctx.s, -1);
|
||||
}
|
||||
|
||||
/* Fire an OSC 133 command event. */
|
||||
static void
|
||||
input_fire_command_event(struct window_pane *wp, const char *name)
|
||||
{
|
||||
struct event_payload *ep;
|
||||
struct cmd_find_state fs;
|
||||
time_t tstart = wp->cmd_start_time, end;
|
||||
time_t tend = wp->cmd_end_time;
|
||||
|
||||
ep = event_payload_create();
|
||||
cmd_find_from_pane(&fs, wp, 0);
|
||||
event_payload_set_target(ep, &fs);
|
||||
if (fs.s != NULL)
|
||||
event_payload_set_session(ep, "session", fs.s);
|
||||
if (fs.wl != NULL)
|
||||
event_payload_set_int(ep, "window_index", fs.wl->idx);
|
||||
event_payload_set_window(ep, "window", wp->window);
|
||||
event_payload_set_pane(ep, "pane", wp);
|
||||
|
||||
if (wp->cmd_status != -1)
|
||||
event_payload_set_int(ep, "command_status", wp->cmd_status);
|
||||
if (tstart != 0)
|
||||
event_payload_set_time(ep, "command_start_time", tstart);
|
||||
if (tend != 0)
|
||||
event_payload_set_time(ep, "command_end_time", tend);
|
||||
|
||||
if (tstart != 0) {
|
||||
if (wp->flags & PANE_CMDRUNNING)
|
||||
end = time(NULL);
|
||||
else
|
||||
end = tend;
|
||||
if (end < tstart)
|
||||
end = tstart;
|
||||
end -= tstart;
|
||||
event_payload_set_uint(ep, "command_duration", end);
|
||||
}
|
||||
|
||||
events_fire(name, ep);
|
||||
}
|
||||
|
||||
/* Handle the OSC 133 sequence. */
|
||||
static void
|
||||
input_osc_133(struct input_ctx *ictx, const char *p)
|
||||
{
|
||||
struct window_pane *wp = ictx->wp;
|
||||
struct grid *gd = ictx->ctx.s->grid;
|
||||
u_int line = ictx->ctx.s->cy + gd->hsize;
|
||||
struct grid_line *gl;
|
||||
struct grid_line *gl = NULL;
|
||||
const char *errstr;
|
||||
int status;
|
||||
|
||||
if (line > gd->hsize + gd->sy - 1)
|
||||
return;
|
||||
gl = grid_get_line(gd, line);
|
||||
if (line <= gd->hsize + gd->sy - 1)
|
||||
gl = grid_get_line(gd, line);
|
||||
|
||||
switch (*p) {
|
||||
case 'A':
|
||||
gl->flags |= GRID_LINE_START_PROMPT;
|
||||
if (gl != NULL)
|
||||
gl->flags |= GRID_LINE_START_PROMPT;
|
||||
if (wp != NULL) {
|
||||
wp->last_prompt_time = time(NULL);
|
||||
events_fire_pane("pane-shell-prompt", wp);
|
||||
}
|
||||
break;
|
||||
case 'C':
|
||||
gl->flags |= GRID_LINE_START_OUTPUT;
|
||||
if (gl != NULL)
|
||||
gl->flags |= GRID_LINE_START_OUTPUT;
|
||||
if (wp != NULL) {
|
||||
wp->cmd_start_time = time(NULL);
|
||||
wp->cmd_end_time = 0;
|
||||
wp->flags |= PANE_CMDRUNNING;
|
||||
wp->cmd_status = -1;
|
||||
input_fire_command_event(wp, "pane-command-started");
|
||||
}
|
||||
break;
|
||||
case 'D':
|
||||
if (wp != NULL) {
|
||||
wp->cmd_end_time = time(NULL);
|
||||
wp->flags &= ~PANE_CMDRUNNING;
|
||||
wp->cmd_status = -1;
|
||||
if (p[1] == ';' && p[2] != '\0') {
|
||||
status = strtonum(p + 2, 0, INT_MAX, &errstr);
|
||||
if (errstr == NULL)
|
||||
wp->cmd_status = status;
|
||||
}
|
||||
input_fire_command_event(wp, "pane-command-finished");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -3289,7 +3383,7 @@ input_osc_52(struct input_ctx *ictx, const char *p)
|
||||
screen_write_start_pane(&ctx, wp, NULL);
|
||||
screen_write_setselection(&ctx, clip, out, outlen);
|
||||
screen_write_stop(&ctx);
|
||||
notify_pane("pane-set-clipboard", wp);
|
||||
events_fire_pane("pane-set-clipboard", wp);
|
||||
paste_add(NULL, out, outlen);
|
||||
}
|
||||
}
|
||||
|
||||
18
job.c
18
job.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: job.c,v 1.75 2026/07/12 20:35:52 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -147,7 +147,7 @@ job_run(const char *cmd, int argc, char **argv, struct environ *e,
|
||||
else if (chdir("/") == 0)
|
||||
environ_set(env, "PWD", 0, "/");
|
||||
else
|
||||
fatal("chdir failed");
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
environ_push(env);
|
||||
@@ -155,21 +155,21 @@ job_run(const char *cmd, int argc, char **argv, struct environ *e,
|
||||
|
||||
if (~flags & JOB_PTY) {
|
||||
if (dup2(out[1], STDIN_FILENO) == -1)
|
||||
fatal("dup2 failed");
|
||||
_exit(1);
|
||||
do_close = do_close && out[1] != STDIN_FILENO;
|
||||
if (dup2(out[1], STDOUT_FILENO) == -1)
|
||||
fatal("dup2 failed");
|
||||
_exit(1);
|
||||
do_close = do_close && out[1] != STDOUT_FILENO;
|
||||
if (flags & JOB_SHOWSTDERR) {
|
||||
if (dup2(out[1], STDERR_FILENO) == -1)
|
||||
fatal("dup2 failed");
|
||||
_exit(1);
|
||||
do_close = do_close && out[1] != STDERR_FILENO;
|
||||
} else {
|
||||
nullfd = open(_PATH_DEVNULL, O_RDWR);
|
||||
if (nullfd == -1)
|
||||
fatal("open failed");
|
||||
_exit(1);
|
||||
if (dup2(nullfd, STDERR_FILENO) == -1)
|
||||
fatal("dup2 failed");
|
||||
_exit(1);
|
||||
if (nullfd != STDERR_FILENO)
|
||||
close(nullfd);
|
||||
}
|
||||
@@ -183,11 +183,11 @@ job_run(const char *cmd, int argc, char **argv, struct environ *e,
|
||||
if (flags & JOB_DEFAULTSHELL)
|
||||
setenv("SHELL", shell, 1);
|
||||
execl(shell, argv0, "-c", cmd, (char *)NULL);
|
||||
fatal("execl failed");
|
||||
_exit(1);
|
||||
} else {
|
||||
argvp = cmd_copy_argv(argc, argv);
|
||||
execvp(argvp[0], argvp);
|
||||
fatal("execvp failed");
|
||||
_exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD$ */
|
||||
/* $OpenBSD: key-bindings.c,v 1.188 2026/07/13 16:30:28 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -49,6 +49,9 @@
|
||||
" '#{?#{m/r:(copy|view)-mode,#{pane_mode}},Go To Top,}' '<' {send -X history-top}" \
|
||||
" '#{?#{m/r:(copy|view)-mode,#{pane_mode}},Go To Bottom,}' '>' {send -X history-bottom}" \
|
||||
" ''" \
|
||||
" '#{?#{==:#{pane_mode},copy-mode},#{?copy_line_numbers,Hide Line Numbers,Show Line Numbers},}' 'L' {send -X line-numbers-toggle}" \
|
||||
" '#{?#{==:#{pane_mode},copy-mode},#{?refresh_active,Refresh Off,Refresh On},}' 'r' {send -X refresh-toggle}" \
|
||||
" ''" \
|
||||
" '#{?#{&&:#{buffer_size},#{!:#{pane_in_mode}}},Paste #[underscore]#{=/9/...:buffer_sample},}' 'p' {paste-buffer}" \
|
||||
" ''" \
|
||||
" '#{?mouse_word,Search For #[underscore]#{=/9/...:mouse_word},}' 'C-r' {if -F '#{?#{m/r:(copy|view)-mode,#{pane_mode}},0,1}' 'copy-mode -t='; send -Xt= search-backward -- \"#{q:mouse_word}\"}" \
|
||||
@@ -496,10 +499,10 @@ key_bindings_init(void)
|
||||
|
||||
/* Mouse button 1 down on pane. */
|
||||
"bind -n MouseDown1Pane { select-pane -t=; send -M }",
|
||||
"bind -n C-MouseDown1Pane { swap-pane -s@ }",
|
||||
|
||||
/* Mouse button 1 drag on pane. */
|
||||
"bind -n MouseDrag1Pane { if -F '#{||:#{pane_in_mode},#{mouse_any_flag}}' { send -M } { copy-mode -M } }",
|
||||
"bind -n C-MouseDrag1Pane { new-pane -M }",
|
||||
"bind -n M-MouseDrag1Pane { move-pane -M }",
|
||||
|
||||
/* Mouse wheel up on pane. */
|
||||
@@ -576,6 +579,7 @@ key_bindings_init(void)
|
||||
"bind -Tcopy-mode , { send -X jump-reverse }",
|
||||
"bind -Tcopy-mode \\; { send -X jump-again }",
|
||||
"bind -Tcopy-mode F { command-prompt -P -1p'(jump backward)' { send -X jump-backward -- '%%' } }",
|
||||
"bind -Tcopy-mode L { send -X line-numbers-toggle }",
|
||||
"bind -Tcopy-mode N { send -X search-reverse }",
|
||||
"bind -Tcopy-mode P { send -X toggle-position }",
|
||||
"bind -Tcopy-mode R { send -X rectangle-toggle }",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user