rusty-vipe
Pop $EDITOR mid-pipe to edit buffered bytes, then resume the pipeline. Rust port of moreutils vipe(1).
Default mode adds --help, --version, --editor=<cmd>, & a completions subcommand. Strict mode mirrors moreutils' error layout for drop-in migration. Cross-platform: Windows console-host editors work via shell-words argv splitting; vi falls back to notepad.exe on Windows.
Part of the Rusty portfolio.
Install
# or, with prebuilt binaries:
# or, download directly from GitHub Releases:
# https://github.com/jsh562/rusty-vipe/releases
To also install a vipe binary alias (argv[0] auto-detect routes into Strict mode):
Usage
# Edit mid-pipe before sending lines to a destructive command
| |
# Tell the editor what filetype to highlight as
| |
# Override which editor opens (Default mode only)
| |
# Abort the pipeline by exiting the editor with an error (e.g. `:cq` in vim)
| |
# Strict moreutils-compat mode (drop-in moreutils vipe replacement)
| |
RUSTY_VIPE_STRICT=1 | |
| |
# Shell completions
Library API
The crate exposes a Read -> Write runtime so library consumers can drive the pipeline against in-memory buffers in tests or TUI apps without hijacking process stdio.
use ;
use Cursor;
let mut input = new;
let mut output: = Vecnew;
let mut vipe = new
.editor
.suffix
.compat
.build?;
vipe.run?;
# Ok::
For library-only consumers without CLI deps see the Cargo Features section.
Cargo Features
default enables full, which (for this single-capability port) resolves to the cli umbrella. vipe-classic reproduces v0.1.x bare-port behavior matching upstream moreutils vipe 1:1. To strip the CLI surface use default-features = false or --no-default-features & add the features you want.
rusty-vipe is a single-capability port: its one documented job is "pop $EDITOR mid-pipe & resume the pipeline with the edited output". No optional feature leaves are carved beyond the required umbrellas; see docs/feature-layout.md for why.
Feature matrix
| Feature | Description | Umbrella(s) |
|---|---|---|
cli |
All CLI-only dependencies (clap, clap_complete, anyhow, signal-hook) and the binary entry point, signal-handler install, mode resolver, and Strict-mode pre-scanner. Library consumers strip via default-features = false. |
full, vipe-classic, vipe-minimal, vipe-alias |
vipe-alias |
Installs an additional vipe binary alongside rusty-vipe. Both share source; argv[0] auto-detect routes vipe invocations into Strict mode. |
(standalone, implies cli) |
bench |
Pulls criterion and enables benches/throughput.rs. Dev-tooling only; outside the convention's leaf surface. Name preserved verbatim from v0.1.x. |
(standalone) |
dev-helpers |
Gates the fake-editor [[bin]] used by integration tests. Never installed by cargo install; enable with cargo test --features dev-helpers. Dev-tooling only. |
(standalone) |
Preset bundles
| Bundle | Composition | Use case |
|---|---|---|
vipe-classic |
cli |
Drop-in upstream moreutils vipe replacement. Strict mode is invoked via --strict, RUSTY_VIPE_STRICT, or vipe-alias argv[0] auto-detect. |
vipe-minimal |
cli |
Explicit minimal-CLI alias for users who prefer the <port>-minimal naming convention seen across other portfolio ports. Identical composition to vipe-classic. |
Keep-list workaround (Cargo features are union-only)
Cargo features cannot subtract from default. To get "everything except a specific feature," disable defaults & enumerate the features you want:
# → bare CLI with no vipe-alias binary, no bench tooling.
# → CLI + the vipe alias binary.
For the common cases the named preset bundles are usually sufficient.
Library-only consumers
[]
= { = "0.2", = false }
This strips clap, clap_complete, anyhow, & signal-hook. The resulting build pulls only tempfile, thiserror, shell-words, & the target-conditional always-on deps (libc on Unix, windows-sys on Windows; both required for TTY reattachment regardless of feature selection).
Convention authority
This layout follows the portfolio-wide Cargo Features Convention. The "why" lives in ADR-0006; the "what" lives in project-instructions.md §Cargo Feature Surface. Every Rusty port from v0.2 onward exposes the same umbrella set (default / full / cli / <port>-classic), per-port leaves named in kebab-case, & 2 to 4 preset bundles.
Compatibility
rusty-vipe has two modes:
- Default mode. clap-styled flag parser.
--help,--version,--editor=<cmd>, & thecompletionssubcommand are all available. Editor resolution order:--editor=>$VISUAL>$EDITOR>/usr/bin/editor(Unix executable check) >vi(Unix) ornotepad.exe(Windows). - Strict mode (activated by
--strict,RUSTY_VIPE_STRICT=1, or invoking the binary asvipe). Mirrors moreutils' PerlGetopt::Longerror layout.--help,--version,--editor=, &completionsMUST be rejected. Pinned upstream version: moreutils 0.69 (same baseline asrusty-sponge).
Pipeline-safety guarantee
When the editor exits non-zero, rusty-vipe MUST NOT forward the tempfile bytes downstream & MUST exit non-zero. The editor's exit code passes through verbatim where possible (clamped to 1 on Windows for codes > 254). This is the safety contract that lets users abort dangerous pipelines via :cq in vim.
Documented intentional divergences
--help/--version/--editor=flags +completionssubcommand. Default-mode additions; rejected in Strict.- Unknown-flag stderr in Strict. Emits only the first unknown-flag error (
rusty-vipe: invalid option -- 'X'). moreutils' POSIXGetopt::Longiterates per-character for malformed long flags; we don't replicate that for undocumented inputs. - Windows editor fallback.
notepad.exe(always present). moreutils Perl source assumes Unixvi. - No controlling TTY. Emits a precise error & exits non-zero rather than scrambling the pipeline by reading from the producer's pipe stdin.
- Exit-code clamping on Windows. Editor exits 1-254 pass through verbatim; codes > 254 or negative collapse to 1. Unix passes 1-255 verbatim. moreutils on Windows isn't well-defined here.
shell-wordsargv splitting.EDITOR&--editor=are split using POSIX shell-quoting rules. Quoted paths likeEDITOR='"/Program Files/Code/bin/code" --wait'work correctly; moreutils breaks on these.- Windows console-host support.
cmd.exe& PowerShell are first-class.mintty(Git Bash, MSYS2) is a documented divergence; wrap withwinpty rusty-vipe ...if needed.
See docs/COMPATIBILITY.md for the full per-flag matrix.
vipe-alias PATH-collision warning
Building with --features vipe-alias installs a second binary named vipe alongside rusty-vipe. If moreutils is also on the same PATH, whichever directory comes first wins. Invoke rusty-vipe (always unambiguous) or omit the vipe-alias feature when moreutils is also present.
What's not shipped
- Per-character iteration over malformed long flags the way moreutils' Perl
Getopt::Longdoes. Strict mode emits only the first unknown-flag error. Same posture asrusty-sponge. minttyconsole-host support on Windows. Wrap withwinpty rusty-vipe ....cmd.exe& PowerShell are first-class.- Source-code derivation from moreutils. This is a clean-room reimplementation. The moreutils
vipePerl source is GPL'd & untouched. Behavioral interfaces (flag set, exit codes, editor invocation order) aren't copyrightable, so a clean-room reimplementation under a different license is well-established practice. Same posture asuutils/coreutils.
MSRV
Rust 1.85 (edition 2024). Re-verified against the portfolio's stable-minus-two policy at each release.
License
Dual-licensed under MIT or Apache-2.0 at your option.