feat: add --remote flag to call remote (--listen) instances (#915)

* feat: add `--remote` flag to call remote (`--listen`) instances

* chore: generate completions & manpage

* docs: update docs

---------

Co-authored-by: Skim bot <skim-bot@skim-rs.github.io>
This commit is contained in:
LoricAndre 2026-01-23 19:19:43 +01:00 committed by GitHub
parent 47e547a9ad
commit 1536eb9657
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 179 additions and 85 deletions

View file

@ -106,12 +106,17 @@ Any of the following applies:
$ # Add the resulting `target/release/sk` executable to your PATH
```
You will then have access to:
- The man page, which you can either write to the correct path or run `man --local-file <(sk --man)`
- The shell completions (and optional keybinds), using `source <(sk --shell \<shell> \[--shell-bindings])`, see below for details
# Usage
Skim can be used either as a general filter (similar to `grep`) or as an interactive
interface for running commands.
## As Vim plugin
## As Vim plugin (on neovim, checkout [fzf-lua](https://github.com/ibhagwan/fzf-lua) with the skim profile)
Via vim-plug (recommended):

View file

@ -8,7 +8,7 @@ sk \- Fuzzy Finder in rust!
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.SH SYNOPSIS
\fBsk\fR [\fB\-\-tac\fR] [\fB\-\-min\-query\-length\fR] [\fB\-\-no\-sort\fR] [\fB\-t\fR|\fB\-\-tiebreak\fR] [\fB\-n\fR|\fB\-\-nth\fR] [\fB\-\-with\-nth\fR] [\fB\-d\fR|\fB\-\-delimiter\fR] [\fB\-e\fR|\fB\-\-exact\fR] [\fB\-\-regex\fR] [\fB\-\-algo\fR] [\fB\-\-case\fR] [\fB\-\-split\-match\fR] [\fB\-b\fR|\fB\-\-bind\fR] [\fB\-m\fR|\fB\-\-multi\fR] [\fB\-\-no\-multi\fR] [\fB\-\-no\-mouse\fR] [\fB\-c\fR|\fB\-\-cmd\fR] [\fB\-i\fR|\fB\-\-interactive\fR] [\fB\-I \fR] [\fB\-\-color\fR] [\fB\-\-no\-hscroll\fR] [\fB\-\-keep\-right\fR] [\fB\-\-skip\-to\-pattern\fR] [\fB\-\-no\-clear\-if\-empty\fR] [\fB\-\-no\-clear\-start\fR] [\fB\-\-no\-clear\fR] [\fB\-\-show\-cmd\-error\fR] [\fB\-\-cycle\fR] [\fB\-\-disabled\fR] [\fB\-\-layout\fR] [\fB\-\-reverse\fR] [\fB\-\-height\fR] [\fB\-\-no\-height\fR] [\fB\-\-min\-height\fR] [\fB\-\-margin\fR] [\fB\-p\fR|\fB\-\-prompt\fR] [\fB\-\-cmd\-prompt\fR] [\fB\-\-selector\fR] [\fB\-\-multi\-selector\fR] [\fB\-\-ansi\fR] [\fB\-\-tabstop\fR] [\fB\-\-info\fR] [\fB\-\-no\-info\fR] [\fB\-\-inline\-info\fR] [\fB\-\-header\fR] [\fB\-\-header\-lines\fR] [\fB\-\-border\fR] [\fB\-\-wrap\fR] [\fB\-\-history\fR] [\fB\-\-history\-size\fR] [\fB\-\-cmd\-history\fR] [\fB\-\-cmd\-history\-size\fR] [\fB\-\-preview\fR] [\fB\-\-preview\-window\fR] [\fB\-q\fR|\fB\-\-query\fR] [\fB\-\-cmd\-query\fR] [\fB\-\-read0\fR] [\fB\-\-print0\fR] [\fB\-\-print\-query\fR] [\fB\-\-print\-cmd\fR] [\fB\-\-print\-score\fR] [\fB\-\-print\-header\fR] [\fB\-\-no\-strip\-ansi\fR] [\fB\-1\fR|\fB\-\-select\-1\fR] [\fB\-0\fR|\fB\-\-exit\-0\fR] [\fB\-\-sync\fR] [\fB\-\-pre\-select\-n\fR] [\fB\-\-pre\-select\-pat\fR] [\fB\-\-pre\-select\-items\fR] [\fB\-\-pre\-select\-file\fR] [\fB\-f\fR|\fB\-\-filter\fR] [\fB\-\-shell\fR] [\fB\-\-shell\-bindings\fR] [\fB\-\-man\fR] [\fB\-\-listen\fR] [\fB\-\-tmux\fR] [\fB\-\-log\-file\fR] [\fB\-\-expect\fR] [\fB\-h\fR|\fB\-\-help\fR] [\fB\-V\fR|\fB\-\-version\fR]
\fBsk\fR [\fB\-\-tac\fR] [\fB\-\-min\-query\-length\fR] [\fB\-\-no\-sort\fR] [\fB\-t\fR|\fB\-\-tiebreak\fR] [\fB\-n\fR|\fB\-\-nth\fR] [\fB\-\-with\-nth\fR] [\fB\-d\fR|\fB\-\-delimiter\fR] [\fB\-e\fR|\fB\-\-exact\fR] [\fB\-\-regex\fR] [\fB\-\-algo\fR] [\fB\-\-case\fR] [\fB\-\-split\-match\fR] [\fB\-b\fR|\fB\-\-bind\fR] [\fB\-m\fR|\fB\-\-multi\fR] [\fB\-\-no\-multi\fR] [\fB\-\-no\-mouse\fR] [\fB\-c\fR|\fB\-\-cmd\fR] [\fB\-i\fR|\fB\-\-interactive\fR] [\fB\-I \fR] [\fB\-\-color\fR] [\fB\-\-no\-hscroll\fR] [\fB\-\-keep\-right\fR] [\fB\-\-skip\-to\-pattern\fR] [\fB\-\-no\-clear\-if\-empty\fR] [\fB\-\-no\-clear\-start\fR] [\fB\-\-no\-clear\fR] [\fB\-\-show\-cmd\-error\fR] [\fB\-\-cycle\fR] [\fB\-\-disabled\fR] [\fB\-\-layout\fR] [\fB\-\-reverse\fR] [\fB\-\-height\fR] [\fB\-\-no\-height\fR] [\fB\-\-min\-height\fR] [\fB\-\-margin\fR] [\fB\-p\fR|\fB\-\-prompt\fR] [\fB\-\-cmd\-prompt\fR] [\fB\-\-selector\fR] [\fB\-\-multi\-selector\fR] [\fB\-\-ansi\fR] [\fB\-\-tabstop\fR] [\fB\-\-info\fR] [\fB\-\-no\-info\fR] [\fB\-\-inline\-info\fR] [\fB\-\-header\fR] [\fB\-\-header\-lines\fR] [\fB\-\-border\fR] [\fB\-\-wrap\fR] [\fB\-\-history\fR] [\fB\-\-history\-size\fR] [\fB\-\-cmd\-history\fR] [\fB\-\-cmd\-history\-size\fR] [\fB\-\-preview\fR] [\fB\-\-preview\-window\fR] [\fB\-q\fR|\fB\-\-query\fR] [\fB\-\-cmd\-query\fR] [\fB\-\-read0\fR] [\fB\-\-print0\fR] [\fB\-\-print\-query\fR] [\fB\-\-print\-cmd\fR] [\fB\-\-print\-score\fR] [\fB\-\-print\-header\fR] [\fB\-\-no\-strip\-ansi\fR] [\fB\-1\fR|\fB\-\-select\-1\fR] [\fB\-0\fR|\fB\-\-exit\-0\fR] [\fB\-\-sync\fR] [\fB\-\-pre\-select\-n\fR] [\fB\-\-pre\-select\-pat\fR] [\fB\-\-pre\-select\-items\fR] [\fB\-\-pre\-select\-file\fR] [\fB\-f\fR|\fB\-\-filter\fR] [\fB\-\-shell\fR] [\fB\-\-shell\-bindings\fR] [\fB\-\-man\fR] [\fB\-\-listen\fR] [\fB\-\-remote\fR] [\fB\-\-tmux\fR] [\fB\-\-log\-file\fR] [\fB\-\-expect\fR] [\fB\-h\fR|\fB\-\-help\fR] [\fB\-V\fR|\fB\-\-version\fR]
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.SH OPTIONS
@ -516,7 +516,12 @@ Generate man page and output it to stdout
\fB\-\-listen\fR [\fI<LISTEN>...\fR]
Run an IPC socket with optional name (defaults to sk)
The socket expects Actions in Ron format (similar to Rust code), see ./src/tui/event.rs for all possible Actions To write to it, you can use socat, for example with \-\-listen sk: echo \*(AqToggleIn\*(Aq | socat \-u STDIN ABSTRACT\-CONNECT:sk
The socket expects Actions in Ron format (similar to Rust code), see ./src/tui/event.rs for all possible Actions To write to it, see the \-\-remote option or the man page
.TP
\fB\-\-remote\fR [\fI<REMOTE>...\fR]
Send commands to an IPC socket with optional name (defaults to sk)
The commands are read from stdin, one per line, in the same format as the actions in the bind flag. They can also be chained using + as a separator. All other arguments will be ignored
.TP
\fB\-\-log\-file\fR \fI<LOG_FILE>\fR
Pipe log output to a file
@ -938,6 +943,26 @@ Example: `\-\-color \*(Aq16,normal\-fg:0+bold,matched\-fg:#ffffff+u,cursor\-bg:#
white) underlined foreground for matched parts and a #deadbe (pale rose, apparently) cursor background.
.br
.SH LISTEN/REMOTE
.br
skim can be controlled from other processes, using the `\-\-listen` (and optionally `\-\-remote`) flags.
.br
.br
To achieve this, run the server instance using `sk \-\-listen optional_address` (the address defaults to `sk`).
.br
It will then start listening on a named socket for instructions.
.br
.br
To send instructions, you can use `sk \-\-remote optional_address` or any other tool that allows us to interact with such sockets,
.br
such as `socat` on linux: `echo \*(AqToggleIn\*(Aq | socat \-u STDIN ABSTRACT\-CONNECT:optional_address`. Instructions correspond to skim\*(Aqs Actions and need to be sent in Ron format.
.br
When using `sk \-\-remote`, pipe in action chains (see the KEYBINDS section), for instance `echo \*(Aqup+select\-row\*(Aq | sk \-\-remote optional_address`
.br
.SH "EXIT CODES"
.br

View file

@ -23,7 +23,7 @@ _sk() {
case "${cmd}" in
sk)
opts="-t -n -d -e -b -m -c -i -I -p -q -1 -0 -f -x -h -V --tac --min-query-length --no-sort --tiebreak --nth --with-nth --delimiter --exact --regex --algo --case --split-match --bind --multi --no-multi --no-mouse --cmd --interactive --color --no-hscroll --keep-right --skip-to-pattern --no-clear-if-empty --no-clear-start --no-clear --show-cmd-error --cycle --disabled --layout --reverse --height --no-height --min-height --margin --prompt --cmd-prompt --selector --multi-selector --ansi --tabstop --info --no-info --inline-info --header --header-lines --border --wrap --history --history-size --cmd-history --cmd-history-size --preview --preview-window --query --cmd-query --read0 --print0 --print-query --print-cmd --print-score --print-header --no-strip-ansi --select-1 --exit-0 --sync --pre-select-n --pre-select-pat --pre-select-items --pre-select-file --filter --shell --shell-bindings --man --listen --tmux --log-file --extended --literal --hscroll-off --filepath-word --jump-labels --no-bold --phony --expect --help --version"
opts="-t -n -d -e -b -m -c -i -I -p -q -1 -0 -f -x -h -V --tac --min-query-length --no-sort --tiebreak --nth --with-nth --delimiter --exact --regex --algo --case --split-match --bind --multi --no-multi --no-mouse --cmd --interactive --color --no-hscroll --keep-right --skip-to-pattern --no-clear-if-empty --no-clear-start --no-clear --show-cmd-error --cycle --disabled --layout --reverse --height --no-height --min-height --margin --prompt --cmd-prompt --selector --multi-selector --ansi --tabstop --info --no-info --inline-info --header --header-lines --border --wrap --history --history-size --cmd-history --cmd-history-size --preview --preview-window --query --cmd-query --read0 --print0 --print-query --print-cmd --print-score --print-header --no-strip-ansi --select-1 --exit-0 --sync --pre-select-n --pre-select-pat --pre-select-items --pre-select-file --filter --shell --shell-bindings --man --listen --remote --tmux --log-file --extended --literal --hscroll-off --filepath-word --jump-labels --no-bold --phony --expect --help --version"
if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0
@ -221,6 +221,10 @@ _sk() {
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
--remote)
COMPREPLY=($(compgen -f "${cur}"))
return 0
;;
--tmux)
COMPREPLY=($(compgen -f "${cur}"))
return 0

View file

@ -61,6 +61,7 @@ nushell\t'Nushell (nu)'
power-shell\t'PowerShell'
zsh\t'Zsh'"
complete -c sk -l listen -d 'Run an IPC socket with optional name (defaults to sk)' -r
complete -c sk -l remote -d 'Send commands to an IPC socket with optional name (defaults to sk)' -r
complete -c sk -l tmux -d 'Run in a tmux popup' -r
complete -c sk -l log-file -d 'Pipe log output to a file' -r
complete -c sk -l hscroll-off -d 'Reserved for later use' -r

View file

@ -101,6 +101,7 @@ module completions {
--shell-bindings # Generate shell key bindings - only for bash, zsh and fish
--man # Generate man page and output it to stdout
--listen: string # Run an IPC socket with optional name (defaults to sk)
--remote: string # Send commands to an IPC socket with optional name (defaults to sk)
--tmux: string # Run in a tmux popup
--log-file: string # Pipe log output to a file
--extended(-x) # Reserved for later use

View file

@ -75,6 +75,7 @@ nushell\:"Nushell (nu)"
power-shell\:"PowerShell"
zsh\:"Zsh"))' \
'--listen=[Run an IPC socket with optional name (defaults to sk)]::LISTEN:_default' \
'--remote=[Send commands to an IPC socket with optional name (defaults to sk)]::REMOTE:_default' \
'--tmux=[Run in a tmux popup]::TMUX:_default' \
'--log-file=[Pipe log output to a file]:LOG_FILE:_default' \
'--hscroll-off=[Reserved for later use]:HSCROLL_OFF:_default' \

View file

@ -13,7 +13,11 @@ use clap::{Error, Parser};
use color_eyre::Result;
use color_eyre::eyre::eyre;
use derive_builder::Builder;
use interprocess::bound_util::RefWrite;
use interprocess::local_socket::ToNsName as _;
use interprocess::local_socket::traits::Stream as _;
use log::trace;
use skim::binds::parse_action_chain;
use skim::item::RankBuilder;
use skim::reader::CommandCollector;
use skim::tui::event::Action;
@ -105,6 +109,30 @@ fn main() -> Result<()> {
return Ok(());
}
if let Some(remote) = opts.remote {
let ns_name = remote
.to_ns_name::<interprocess::local_socket::GenericNamespaced>()
.unwrap();
let stream = interprocess::local_socket::Stream::connect(ns_name)?;
let mut action_chain = String::new();
loop {
action_chain.clear();
let len = std::io::stdin().read_line(&mut action_chain)?;
log::debug!("Got line {} from stdin", action_chain.trim());
if len == 0 {
break;
}
let actions = parse_action_chain(&action_chain.trim())?;
for act in actions {
stream
.as_write()
.write_all(&format!("{}\n", ron::ser::to_string(&act)?).as_bytes())?;
log::debug!("Sent action {act:?} to listener");
}
}
return Ok(());
}
match sk_main(opts) {
Ok(exit_code) => std::process::exit(exit_code),
Err(err) => {

View file

@ -202,7 +202,8 @@ where
/// Parses an action chain, separated by '+'s into the corresponding actions
pub fn parse_action_chain(action_chain: &str) -> Result<Vec<Action>> {
let mut actions: Vec<Action> = vec![];
let mut split = action_chain.split("+");
let lchain = action_chain.to_ascii_lowercase();
let mut split = lchain.split("+");
loop {
let Some(mut s) = split.next().map(String::from) else {
break;

View file

@ -177,6 +177,17 @@ const ACTIONS_SS: &str = "
* yank: ctrl-y
";
const REMOTE_SECTION: &str = "
skim can be controlled from other processes, using the `--listen` (and optionally `--remote`) flags.
To achieve this, run the server instance using `sk --listen optional_address` (the address defaults to `sk`).
It will then start listening on a named socket for instructions.
To send instructions, you can use `sk --remote optional_address` or any other tool that allows us to interact with such sockets,
such as `socat` on linux: `echo 'ToggleIn' | socat -u STDIN ABSTRACT-CONNECT:optional_address`. Instructions correspond to skim's Actions and need to be sent in Ron format.
When using `sk --remote`, pipe in action chains (see the KEYBINDS section), for instance `echo 'up+select-row' | sk --remote optional_address`
";
fn parse_str(src: &str) -> Vec<Inline> {
let mut res = Vec::new();
for line in src.lines() {
@ -313,6 +324,8 @@ It will expand to the corresponding fields, separated by the `--delimiter|-d` op
section(&mut custom, "THEME", THEME_SECTION);
section(&mut custom, "LISTEN/REMOTE", REMOTE_SECTION);
section(&mut custom, "EXIT CODES", EXIT_CODES_SECTION);
custom.to_writer(w)?;

View file

@ -656,11 +656,18 @@ pub struct SkimOptions {
/// Run an IPC socket with optional name (defaults to `sk`)
///
/// The socket expects Actions in Ron format (similar to Rust code), see `./src/tui/event.rs` for all possible Actions
/// To write to it, you can use socat, for example with `--listen sk`:
/// `echo 'ToggleIn' | socat -u STDIN ABSTRACT-CONNECT:sk`
/// To write to it, see the `--remote` option or the man page
#[cfg_attr(feature = "cli", arg(long, help_heading = "Scripting", default_missing_value = "sk", num_args=0..))]
pub listen: Option<String>,
/// Send commands to an IPC socket with optional name (defaults to `sk`)
///
/// The commands are read from stdin, one per line, in the same format as the actions in the
/// bind flag. They can also be chained using `+` as a separator.
/// All other arguments will be ignored
#[cfg_attr(feature = "cli", arg(long, help_heading = "Scripting", default_missing_value = "sk", num_args=0..))]
pub remote: Option<String>,
/// Run in a tmux popup
///
/// Format: `sk --tmux <center|top|bottom|left|right>[,SIZE[%]][,SIZE[%]]`
@ -754,6 +761,7 @@ impl Default for SkimOptions {
no_strip_ansi: false,
wrap_items: false,
listen: None,
remote: None,
print_header: false,
disabled: false,
tac: Default::default(),

View file

@ -3,24 +3,31 @@
mod common;
use common::tmux::Keys::*;
use interprocess::{
bound_util::RefWrite,
local_socket::{GenericNamespaced, Stream, ToNsName, traits::Stream as _},
};
use rand::{Rng as _, distr::Alphabetic};
use std::io::{Result, Write as _};
use std::{
io::{Result, Write as _},
process::{Child, Command, Stdio},
};
use common::tmux::TmuxController;
fn connect(name: &str) -> Result<Stream> {
let ns_name = name.to_ns_name::<GenericNamespaced>().unwrap();
Stream::connect(ns_name)
use crate::common::tmux::SK;
fn connect(name: &str) -> Result<Child> {
Command::new("/bin/sh")
.arg("-c")
.arg(&format!("{SK} --remote {name}"))
.stdin(Stdio::piped())
.spawn()
}
fn send(stream: &Stream, msg: &str) -> Result<()> {
stream.as_write().write_all(format!("{msg}\n").as_bytes())
fn send(child: &mut Child, msg: &str) -> Result<()> {
let mut b = msg.bytes().collect::<Vec<_>>();
b.push(b'\n');
child.stdin.as_mut().map(|s| s.write_all(&b));
Ok(())
}
fn setup(name: &str, extra_args: &[&str]) -> Result<(TmuxController, Stream)> {
fn setup(name: &str, extra_args: &[&str]) -> Result<(TmuxController, Child)> {
let mut tmux = TmuxController::new_named(name)?;
let socket_name = format!(
"sk-test-{name}{}",
@ -41,10 +48,10 @@ fn setup(name: &str, extra_args: &[&str]) -> Result<(TmuxController, Stream)> {
#[test]
fn listen_up() -> std::io::Result<()> {
let (tmux, stream) = setup("up", &[])?;
let (tmux, mut stream) = setup("up", &[])?;
sk_test!(@expand tmux;
@capture[2]starts_with("> a");
send(&stream,"Up(2)")? ;
send(&mut stream,"up(2)")? ;
@capture[2]trim().starts_with("a");
@capture[4]starts_with("> c");
);
@ -53,13 +60,13 @@ fn listen_up() -> std::io::Result<()> {
#[test]
fn listen_down() -> std::io::Result<()> {
let (tmux, stream) = setup("down", &[])?;
let (tmux, mut stream) = setup("down", &[])?;
sk_test!(@expand tmux;
@capture[2]starts_with("> a");
@keys Up, Up;
@capture[2]trim().starts_with("a");
@capture[4]starts_with("> c");
send(&stream, "Down(2)")?;
send(&mut stream, "down(2)")?;
@capture[2]starts_with("> a");
);
Ok(())
@ -67,9 +74,9 @@ fn listen_down() -> std::io::Result<()> {
#[test]
fn listen_abort() -> std::io::Result<()> {
let (tmux, stream) = setup("abort", &[])?;
let (tmux, mut stream) = setup("abort", &[])?;
sk_test!(@expand tmux;
send(&stream, "Abort")?;
send(&mut stream, "abort")?;
@capture[0]trim().contains("$");
);
Ok(())
@ -78,10 +85,10 @@ fn listen_abort() -> std::io::Result<()> {
// Test Accept action - adapted to use "a" instead of "apple"
#[test]
fn listen_accept() -> std::io::Result<()> {
let (tmux, stream) = setup("accept", &[])?;
let (tmux, mut stream) = setup("accept", &[])?;
sk_test!(@expand tmux;
@capture[2]starts_with("> a");
send(&stream, "Accept(None)")?;
send(&mut stream, "accept")?;
@output[0]eq("a");
);
Ok(())
@ -90,9 +97,9 @@ fn listen_accept() -> std::io::Result<()> {
// Test Accept with key - adapted to use "a" instead of "apple"
#[test]
fn listen_accept_key() -> std::io::Result<()> {
let (tmux, stream) = setup("accept_key", &[])?;
let (tmux, mut stream) = setup("accept_key", &[])?;
sk_test!(@expand tmux;
send(&stream, "Accept(Some(\"ctrl-a\"))")?;
send(&mut stream, "accept(ctrl-a)")?;
@output[0]eq("ctrl-a");
@output[1]eq("a");
);
@ -101,9 +108,9 @@ fn listen_accept_key() -> std::io::Result<()> {
#[test]
fn listen_add_char() -> std::io::Result<()> {
let (tmux, stream) = setup("add_char", &[])?;
let (tmux, mut stream) = setup("add_char", &[])?;
sk_test!(@expand tmux;
send(&stream, "AddChar('a')")?;
send(&mut stream, "add-char(a)")?;
@capture[0]trim().eq("> a");
);
Ok(())
@ -111,11 +118,11 @@ fn listen_add_char() -> std::io::Result<()> {
#[test]
fn listen_backward_char() -> std::io::Result<()> {
let (tmux, stream) = setup("backward_char", &[])?;
let (tmux, mut stream) = setup("backward_char", &[])?;
sk_test!(@expand tmux;
@keys Str("hello");
@capture[0]starts_with("> hello");
send(&stream, "BackwardChar")?;
send(&mut stream, "backward-char")?;
@keys Key('|');
@capture[0]trim().eq("> hell|o");
);
@ -124,11 +131,11 @@ fn listen_backward_char() -> std::io::Result<()> {
#[test]
fn listen_backward_delete_char() -> std::io::Result<()> {
let (tmux, stream) = setup("backward_delete_char", &[])?;
let (tmux, mut stream) = setup("backward_delete_char", &[])?;
sk_test!(@expand tmux;
@keys Str("test");
@capture[0]trim().eq("> test");
send(&stream, "BackwardDeleteChar")?;
send(&mut stream, "backward-delete-char")?;
@capture[0]trim().eq("> tes");
);
Ok(())
@ -136,11 +143,11 @@ fn listen_backward_delete_char() -> std::io::Result<()> {
#[test]
fn listen_backward_delete_char_eof() -> std::io::Result<()> {
let (tmux, stream) = setup("backward_delete_char_eof", &[])?;
let (tmux, mut stream) = setup("backward_delete_char_eof", &[])?;
sk_test!(@expand tmux;
@keys Str("x");
@capture[0]trim().eq("> x");
send(&stream, "BackwardDeleteCharEof")?;
send(&mut stream, "backward-delete-char/eof")?;
@capture[0]trim().eq(">");
);
Ok(())
@ -148,11 +155,11 @@ fn listen_backward_delete_char_eof() -> std::io::Result<()> {
#[test]
fn listen_backward_kill_word() -> std::io::Result<()> {
let (tmux, stream) = setup("backward_kill_word", &[])?;
let (tmux, mut stream) = setup("backward_kill_word", &[])?;
sk_test!(@expand tmux;
@keys Str("hello world");
@capture[0]trim().eq("> hello world");
send(&stream, "BackwardKillWord")?;
send(&mut stream, "backward-kill-word")?;
@capture[0]trim().eq("> hello");
);
Ok(())
@ -160,11 +167,11 @@ fn listen_backward_kill_word() -> std::io::Result<()> {
#[test]
fn listen_backward_word() -> std::io::Result<()> {
let (tmux, stream) = setup("backward_word", &[])?;
let (tmux, mut stream) = setup("backward_word", &[])?;
sk_test!(@expand tmux;
@keys Str("hello world");
@capture[0]starts_with("> hello world");
send(&stream, "BackwardWord")?;
send(&mut stream, "backward-word")?;
@keys Key('|');
@capture[0]trim().eq("> hello |world");
);
@ -173,12 +180,12 @@ fn listen_backward_word() -> std::io::Result<()> {
#[test]
fn listen_end_of_line() -> std::io::Result<()> {
let (tmux, stream) = setup("end_of_line", &[])?;
let (tmux, mut stream) = setup("end_of_line", &[])?;
sk_test!(@expand tmux;
@keys Str("hello");
@capture[0]trim().eq("> hello");
send(&stream, "BeginningOfLine")?;
send(&stream, "EndOfLine")?;
send(&mut stream, "beginning-of-line")?;
send(&mut stream, "end-of-line")?;
@keys Key('X');
@capture[0]trim().eq("> helloX");
);
@ -187,11 +194,11 @@ fn listen_end_of_line() -> std::io::Result<()> {
#[test]
fn listen_first() -> std::io::Result<()> {
let (tmux, stream) = setup("first", &[])?;
let (tmux, mut stream) = setup("first", &[])?;
sk_test!(@expand tmux;
@keys Up, Up;
@capture[4]starts_with("> c");
send(&stream, "First")?;
send(&mut stream, "first")?;
@capture[2]starts_with("> a");
);
Ok(())
@ -199,12 +206,12 @@ fn listen_first() -> std::io::Result<()> {
#[test]
fn listen_forward_char() -> std::io::Result<()> {
let (tmux, stream) = setup("forward_char", &[])?;
let (tmux, mut stream) = setup("forward_char", &[])?;
sk_test!(@expand tmux;
@keys Str("hello");
@capture[0]trim().eq("> hello");
send(&stream, "BeginningOfLine")?;
send(&stream, "ForwardChar")?;
send(&mut stream, "beginning-of-line")?;
send(&mut stream, "forward-char")?;
@keys Key('X');
@capture[0]trim().eq("> hXello");
);
@ -213,12 +220,12 @@ fn listen_forward_char() -> std::io::Result<()> {
#[test]
fn listen_forward_word() -> std::io::Result<()> {
let (tmux, stream) = setup("forward_word", &[])?;
let (tmux, mut stream) = setup("forward_word", &[])?;
sk_test!(@expand tmux;
@keys Str("hello world");
@capture[0]trim().eq("> hello world");
send(&stream, "BeginningOfLine")?;
send(&stream, "ForwardWord")?;
send(&mut stream, "beginning-of-line")?;
send(&mut stream, "forward-word")?;
@keys Key('X');
@capture[0]trim().eq("> helloX world");
);
@ -227,12 +234,12 @@ fn listen_forward_word() -> std::io::Result<()> {
#[test]
fn listen_kill_line() -> std::io::Result<()> {
let (tmux, stream) = setup("kill_line", &[])?;
let (tmux, mut stream) = setup("kill_line", &[])?;
sk_test!(@expand tmux;
@keys Str("hello world");
@capture[0]trim().eq("> hello world");
send(&stream, "BackwardWord")?;
send(&stream, "KillLine")?;
send(&mut stream, "backward-word")?;
send(&mut stream, "kill-line")?;
@capture[0]trim().eq("> hello");
);
Ok(())
@ -240,12 +247,12 @@ fn listen_kill_line() -> std::io::Result<()> {
#[test]
fn listen_kill_word() -> std::io::Result<()> {
let (tmux, stream) = setup("kill_word", &[])?;
let (tmux, mut stream) = setup("kill_word", &[])?;
sk_test!(@expand tmux;
@keys Str("hello world");
@capture[0]trim().eq("> hello world");
send(&stream, "BeginningOfLine")?;
send(&stream, "KillWord")?;
send(&mut stream, "beginning-of-line")?;
send(&mut stream, "kill-word")?;
@capture[0]trim().eq("> world");
);
Ok(())
@ -253,11 +260,11 @@ fn listen_kill_word() -> std::io::Result<()> {
#[test]
fn listen_last() -> std::io::Result<()> {
let (tmux, stream) = setup("last", &[])?;
let (tmux, mut stream) = setup("last", &[])?;
sk_test!(@expand tmux;
@capture[2]starts_with("> a");
@capture[5]trim().eq("d");
send(&stream, "Last")?;
send(&mut stream, "last")?;
@capture[5]starts_with("> d");
);
Ok(())
@ -266,10 +273,10 @@ fn listen_last() -> std::io::Result<()> {
// Test Reload action with command
#[test]
fn listen_reload_cmd() -> std::io::Result<()> {
let (tmux, stream) = setup("reload_cmd", &[])?;
let (tmux, mut stream) = setup("reload_cmd", &[])?;
sk_test!(@expand tmux;
@capture[1]trim().contains("4/4");
send(&stream, "Reload(Some(\"printf 'x\\\\ny\\\\nz'\"))")?;
send(&mut stream, "reload(printf 'x\\ny\\nz'))")?;
@capture[2]starts_with("> x");
);
Ok(())
@ -277,9 +284,9 @@ fn listen_reload_cmd() -> std::io::Result<()> {
#[test]
fn listen_select_all() -> std::io::Result<()> {
let (tmux, stream) = setup("select_all", &["-m"])?;
let (tmux, mut stream) = setup("select_all", &["-m"])?;
sk_test!(@expand tmux;
send(&stream, "SelectAll")?;
send(&mut stream, "select-all")?;
@capture[2]trim().eq(">>a");
@capture[3]trim().eq(">b");
@capture[4]trim().eq(">c");
@ -289,10 +296,10 @@ fn listen_select_all() -> std::io::Result<()> {
#[test]
fn listen_select_row() -> std::io::Result<()> {
let (tmux, stream) = setup("select_row", &["-m"])?;
let (tmux, mut stream) = setup("select_row", &["-m"])?;
sk_test!(@expand tmux;
@capture[2]starts_with("> a");
send(&stream, "SelectRow(2)")?;
send(&mut stream, "select-row(2)")?;
@capture[2]trim().eq("> a");
@capture[4]trim().eq(">c");
);
@ -301,9 +308,9 @@ fn listen_select_row() -> std::io::Result<()> {
#[test]
fn listen_select() -> std::io::Result<()> {
let (tmux, stream) = setup("select", &["-m"])?;
let (tmux, mut stream) = setup("select", &["-m"])?;
sk_test!(@expand tmux;
send(&stream, "Select")?;
send(&mut stream, "select")?;
@capture[2]starts_with(">>");
);
Ok(())
@ -311,11 +318,11 @@ fn listen_select() -> std::io::Result<()> {
#[test]
fn listen_toggle() -> std::io::Result<()> {
let (tmux, stream) = setup("toggle", &["-m"])?;
let (tmux, mut stream) = setup("toggle", &["-m"])?;
sk_test!(@expand tmux;
send(&stream, "Toggle")?;
send(&mut stream, "toggle")?;
@capture[2]starts_with(">>a");
send(&stream, "Toggle")?;
send(&mut stream, "toggle")?;
@capture[2]starts_with("> a");
);
Ok(())
@ -323,9 +330,9 @@ fn listen_toggle() -> std::io::Result<()> {
#[test]
fn listen_toggle_all() -> std::io::Result<()> {
let (tmux, stream) = setup("toggle_all", &["-m"])?;
let (tmux, mut stream) = setup("toggle_all", &["-m"])?;
sk_test!(@expand tmux;
send(&stream, "ToggleAll")?;
send(&mut stream, "toggle-all")?;
@capture[2]starts_with(">>a");
@capture[3]trim().eq(">b");
@capture[4]trim().eq(">c");
@ -335,12 +342,12 @@ fn listen_toggle_all() -> std::io::Result<()> {
#[test]
fn listen_toggle_in() -> std::io::Result<()> {
let (tmux, stream) = setup("toggle_in", &["-m"])?;
let (tmux, mut stream) = setup("toggle_in", &["-m"])?;
sk_test!(@expand tmux;
@keys Up;
@capture[2]trim().starts_with("a");
@capture[3]starts_with("> b");
send(&stream, "ToggleIn")?;
send(&mut stream, "toggle-in")?;
@capture[2]starts_with("> a");
@capture[3]trim().starts_with(">b");
);
@ -349,11 +356,11 @@ fn listen_toggle_in() -> std::io::Result<()> {
#[test]
fn listen_toggle_out() -> std::io::Result<()> {
let (tmux, stream) = setup("toggle_out", &["-m"])?;
let (tmux, mut stream) = setup("toggle_out", &["-m"])?;
sk_test!(@expand tmux;
@capture[2]starts_with("> a");
@capture[3]trim().starts_with("b");
send(&stream, "ToggleOut")?;
send(&mut stream, "toggle-out")?;
@capture[2]trim().starts_with(">a");
@capture[3]starts_with("> b");
);
@ -363,11 +370,11 @@ fn listen_toggle_out() -> std::io::Result<()> {
// Test Top action (alias for First)
#[test]
fn listen_top() -> std::io::Result<()> {
let (tmux, stream) = setup("top", &[])?;
let (tmux, mut stream) = setup("top", &[])?;
sk_test!(@expand tmux;
@keys Up, Up;
@capture[4]starts_with("> c");
send(&stream, "Top")?;
send(&mut stream, "top")?;
@capture[2]starts_with("> a");
);
Ok(())
@ -375,11 +382,11 @@ fn listen_top() -> std::io::Result<()> {
#[test]
fn listen_unix_line_discard() -> std::io::Result<()> {
let (tmux, stream) = setup("unix_line_discard", &[])?;
let (tmux, mut stream) = setup("unix_line_discard", &[])?;
sk_test!(@expand tmux;
@keys Str("hello world");
@capture[0]trim().eq("> hello world");
send(&stream, "UnixLineDiscard")?;
send(&mut stream, "unix-line-discard")?;
@capture[0]trim().eq(">");
);
Ok(())
@ -387,11 +394,11 @@ fn listen_unix_line_discard() -> std::io::Result<()> {
#[test]
fn listen_unix_word_rubout() -> std::io::Result<()> {
let (tmux, stream) = setup("unix_word_rubout", &[])?;
let (tmux, mut stream) = setup("unix_word_rubout", &[])?;
sk_test!(@expand tmux;
@keys Str("hello world");
@capture[0]trim().eq("> hello world");
send(&stream, "UnixWordRubout")?;
send(&mut stream, "unix-word-rubout")?;
@capture[0]trim().eq("> hello");
);
Ok(())
@ -399,13 +406,13 @@ fn listen_unix_word_rubout() -> std::io::Result<()> {
#[test]
fn listen_yank() -> std::io::Result<()> {
let (tmux, stream) = setup("yank", &[])?;
let (tmux, mut stream) = setup("yank", &[])?;
sk_test!(@expand tmux;
@keys Str("hello");
@capture[0]trim().eq("> hello");
send(&stream, "BackwardKillWord")?;
send(&mut stream, "backward-kill-word")?;
@capture[0]trim().eq(">");
send(&stream, "Yank")?;
send(&mut stream, "yank")?;
@capture[0]trim().eq("> hello");
);
Ok(())