vlsh
vlsh is an interactive Unix shell written in V. It is designed to be simple, fast, and hackable — with a clean codebase that is easy to read, modify, and extend.
Features at a glance
- Pipes, redirection, and command chaining —
cmd1 | cmd2,> file,>> file,< file, and2>&1(merge stderr into captured stdout when piping or redirecting); AND-chains (&&), OR-chains (||), and unconditional sequences (;) - Glob expansion —
*.v,./*.deb,~/docs/**expanded before execution - Tilde and parameter expansion —
~/path,$VAR,${var:-word},${#var},${var#pat}/${var%pat}(glob*/?inpat), nested${…},VAR=val cmd; unquoted words split on sessionIFS(default space/tab/newline) (see docs/posix-inventory.md) - Command history — up/down arrow browsing and
Ctrl+Rincremental search; shared across all sessions (last 5000 entries in~/.vlsh_history); bash-style!!,!$,!n,!-n,!prefix,!?sub(see docs), interactive prompt only - Tab completion — files and directories; the first word also completes
command names found in
$PATH; aftercdwith a space, only directories are suggested; plugins can register custom completions (e.g. SSH hostname completion) - Inline autosuggestions — as you type, the most recent matching history
entry is shown as dimmed ghost text;
cdsuggestions are validated against the current filesystem and fall back to live directory listing when no valid history match exists; press→orEndto accept - Aliases — defined in
~/.vlshrcor managed live withaliases add/remove - Plugin system — plugins are installed from the official remote repository
into versioned directories under
~/.vlsh/plugins/<name>/<version>/; vlsh compiles them automatically. Plugins can add commands, decorate the prompt, run pre/post hooks around every command, capture command output via theoutput_hookcapability, provide custom tab completions, contribute live text to the mux status bar (mux_statuscapability), and expose their own help text via thehelpcapability (surfaced through the built-inhelpcommand). Search plugins by name or description withplugins search, install the latest version withplugins install, keep them up to date withplugins update, remove them withplugins delete, or purge and re-fetch the latest withplugins reinstall. The official repository is at https://github.com/vlshcc/plugins. - Terminal multiplexer — built-in
muxcommand splits the terminal into resizable panes, each running its own shell. Supports mouse selection, copy/paste, a status bar, per-pane scrollback history (up to 1000 lines, scrollable via mouse wheel orCtrl+V+PageUp/PageDown), and all common VT100 sequences so editors likevimandnanowork correctly inside panes. - Native
.vshscript support — execute V shell scripts directly without invokingv runmanually - POSIX environment variables —
export,unset, andVAR=val cmdprefix - Theming — prompt and UI colours configurable via
style setand~/.vlshrc
INSTALL
Pre-built packages (recommended)
The latest release is v1.2.0. Pre-built packages for 64-bit Linux are available on the releases page.
Debian / Ubuntu — install via .deb:
curl -LO https://github.com/vlshcc/vlsh/releases/download/v1.2.0/vlsh_1.2.0_amd64.deb sudo dpkg -i vlsh_1.2.0_amd64.deb
The package installs the binary to /usr/bin/vlsh and automatically adds it
to /etc/shells via the postinst script.
Fedora / RHEL — install via .rpm:
curl -LO https://github.com/vlshcc/vlsh/releases/download/v1.2.0/vlsh-1.2.0-1.x86_64.rpm sudo rpm -U vlsh-1.2.0-1.x86_64.rpm
Other Linux — standalone binary:
curl -LO https://github.com/vlshcc/vlsh/releases/download/v1.2.0/vlsh_1.2.0_amd64_linux chmod +x vlsh_1.2.0_amd64_linux sudo mv vlsh_1.2.0_amd64_linux /usr/local/bin/vlsh
Prerequisites (from source)
- V — install with
v upor from https://github.com/vlang/v
Build and run (try it out)
git clone https://github.com/vlshcc/vlsh.git cd vlsh v . ./vlsh
From the same directory, make help summarizes Makefile targets; make test runs the test suite (v test .), make build compiles (v .), and make clean removes the vlsh binary. make fuzz runs tools/fuzz_shell.v to stress parsers with random input (FUZZ_ITER, optional decimal FUZZ_SEED as a full integer string). Random lines can trigger stderr from parameter expansion diagnostics; use 2>/dev/null if you want a quiet run. Override the compiler with make V=/path/to/v.
make install installs the built vlsh into $(PREFIX)/bin (default /usr/local/bin). Use sudo make install, or set DESTDIR / PREFIX for a staged install.
Distribution builds — make dist (same as make dist-build) runs pkg/dist.sh build. Any existing matching artifacts already in builds/ are renamed with a timestamp so a new run does not silently overwrite them, then the script runs pkg/build.sh for:
- Linux —
.deb(needsdpkg-deb),.rpm(needsrpmbuild), and a standalonevlsh_*_*_linuxbinary - FreeBSD and DragonFly — cross-compiled binaries (needs
clangandlld; DragonFly also downloads an ISO once — usebsdtaror GNUtarto extract it, pluscurlandbunzip2) - NetBSD and OpenBSD — native builds only: when
distruns on Linux, these steps no-op; runpkg/build.sh --netbsdor--openbsdon NetBSD/OpenBSD to producebuilds/vlsh_*_*_netbsd/_openbsd(V does not yet ship a Linux→NetBSD/OpenBSD cross sysroot like FreeBSD).
FreeBSD cross-build — pkg/build.sh pre-clones the FreeBSD sysroot (same GitHub tree V uses for linking) before invoking v, because V currently builds third-party C objects before it downloads that sysroot; without this step, pthread.h and similar headers are missing during gc.o compilation.
make dist-install runs pkg/dist.sh install: it selects the newest suitable .deb, .rpm, or OS-specific binary in builds/ for the current platform (by modification time) and installs it (sudo when not root).
Running make dist build executes both the dist and build targets in order (a full distribution build, then an extra v . for the current tree — usually you only need make dist).
Or run directly without compiling first:
System-wide install
After building, install the binary to your PATH:
sudo make install
# or: sudo cp vlsh /usr/local/bin/vlshVerify it is accessible:
which vlsh # should print /usr/local/bin/vlsh vlsh --version 2>/dev/null || vlsh -c 'version'
Set vlsh as your default login shell
-
Add vlsh to the list of approved shells:
echo /usr/local/bin/vlsh | sudo tee -a /etc/shells
-
Change your login shell:
chsh -s /usr/local/bin/vlsh
-
Log out and back in (or open a new terminal). Your session should now start in vlsh.
To revert at any time:
chsh -s /bin/bash # or /bin/zsh, etc.USE
I'm using vlsh as my daily shell. That does not mean you should be. It is likely that you will run into bugs when using vlsh.
CONFIG
vlsh will look for the configuration file $HOME/.vlshrc.
Here's an example -file:
# Environment
export PATH="/usr/local/bin:/usr/bin:/bin:$PATH"
# Aliases
alias gs=git status
alias gps=git push
alias gpl=git pull
alias gd=git diff
alias gc=git commit -sa
alias gl=git log
alias vim=nvim
# Style (define in RGB colors)
#style_git_bg=44,59,71
#style_git_fg=251,255,234
#style_debug_bg=255,255,255
#style_debug_fb=251,255,234
DOCUMENTATION
Architecture overview
vlsh.v – main entry point, prompt rendering, read-eval loop
cfg/cfg.v – config file (~/.vlshrc) parsing, aliases, paths, style
cmds/cmds.v – built-in commands: help, cd
cmds/ls.v – built-in colorised ls
cmds/cp.v – built-in overwrite-copy (ocp)
exec/exec.v – external-command execution, pipe chains, I/O redirection
mux/mux.v – terminal multiplexer entry point and event loop
mux/pane.v – per-pane VT100 parser and cell grid
mux/layout.v – binary-tree layout engine (splits/resize/navigation)
mux/render.v – grid-to-terminal renderer
mux/input.v – key-sequence parser for mux prefix bindings
mux/pty.v – PTY helpers (thin wrappers around C functions)
mux/pty_helpers.h – C helpers: raw mode, winsize, select, forkpty, exec
utils/utils.v – shared helpers: parse_args, fail/warn/ok/debug
plugins/ – plugin loader and hook dispatcher
Config file (~/.vlshrc)
A plain-text file sourced at startup. Lines beginning with # are comments.
export and unset lines are executed as shell commands; alias and style
lines use the config syntax below.
| Directive | Example | Meaning |
|---|---|---|
export KEY=VALUE |
export PATH="/opt/bin:$PATH" |
Set an environment variable ($VAR is expanded) |
alias <name>=<cmd> |
alias gs=git status |
Define a command alias |
style_git_bg=r,g,b |
style_git_bg=44,59,71 |
Git-branch prompt background colour |
style_git_fg=r,g,b |
style_git_fg=251,255,234 |
Git-branch prompt foreground colour |
style_debug_bg=r,g,b |
Debug-output background (when VLSHDEBUG=true) |
|
style_debug_fg=r,g,b |
Debug-output foreground |
Built-in commands
| Command | Description |
|---|---|
aliases list |
List all defined aliases |
aliases add <name>=<cmd> |
Add or update an alias |
aliases remove <name> |
Remove an alias |
cd [dir] |
Change directory; ~ and ~/path expand to $HOME; home if omitted; cd - returns to the previous directory |
echo [args…] |
Print arguments; same parameter expansion as other commands ($VAR, ${var:-word}, ${#var}, …); supports > / >> |
exit [N] |
Exit the shell with optional status code (default 0) |
export [NAME=value …] |
Set environment variables; with no args, lists all exported variables |
help [cmd] |
Show command list, or detailed help for a specific command |
ls [dir] |
Colorised directory listing (falls through to system ls when flags are passed) |
mux |
Enter terminal multiplexer mode |
ocp <src> <dst> |
Copy file, overwriting destination |
plugins list |
List locally installed plugins with version and status |
plugins enable <name> |
Enable a disabled plugin by name |
plugins enable all |
Enable every plugin at once |
plugins disable <name> |
Disable a plugin by name |
plugins disable all |
Disable every plugin at once |
plugins reload |
Hot-reload all plugins |
plugins remote |
List remote plugins; shows installed version and available updates |
plugins search <query> |
Search remote plugins by name or description |
plugins install <name> |
Download and install the latest version of a plugin |
plugins update [name] |
Update one or all installed plugins to their latest version |
plugins delete <name> |
Delete an installed plugin |
plugins reinstall <name> |
Remove the local plugin and install the latest from the remote repository |
source <file> / . <file> |
Execute a script in the current shell context (respects # comments and blank lines) |
style list |
Show current style/colour settings |
style set <key> <r> <g> <b> |
Set a prompt colour (RGB 0–255) |
unset <NAME> … |
Remove one or more environment variables |
version |
Print the vlsh version |
Shell features
Pipes – chain commands with |:
Output redirection – write or append stdout to a file:
echo "hello" > file.txt
echo "world" >> file.txt
Merging stderr into stdout (2>&1) – for external commands, when the command’s stdout is captured (pipe, >, >>, or <), the token 2>&1 includes stderr in that capture. Typical use:
some_cmd > log.txt 2>&1
some_cmd 2>&1 | grep -i error
Captured stderr is concatenated after stdout (not byte-interleaved), which matches common logging use cases.
Input redirection – feed a file into a command's stdin with <:
wc -l < report.txt
grep error < app.log | wc -l
AND-chains – run the next command only if the previous one succeeds (exit 0):
touch /tmp/x && echo "file created"
OR-chains – run the next command only if the previous one fails (exit non-0):
ping -c1 host || echo "host unreachable"
Unconditional sequences – run commands one after another regardless of exit status:
echo hello ; echo world
make ; make install
Tilde expansion – ~ and ~/path are expanded to $HOME in both commands and arguments:
vi ~/.config/nvim/init.vim
Environment-variable prefix – set variables only for the duration of one command:
FIELD_LIST='used,avail' df -h --no-sync .
Parameter expansion – Applied when parsing command words (including arguments to echo and other commands): simple $VAR, $$, $?, $0, and POSIX-style brace forms such as ${VAR}, ${#VAR} (length), ${var:-word} (default if unset or empty), ${var:=word} (assign default), ${var:+word} (alternate if set), ${var:?word} (diagnostic if unset; vlsh prints to stderr and substitutes empty—see docs/posix-inventory.md), ${var#pat} / ${var##pat} (remove shortest / longest matching prefix; * and ? glob in pat; [] classes not implemented yet), and ${var%pat} / ${var%%pat} (shortest / longest suffix). Nested ${…} is supported. Word splitting: unquoted tokens are split on the session IFS (default space, tab, newline when IFS is unset); see the inventory for lexer vs strict POSIX field-splitting. Text in single quotes is literal (no expansion); double quotes allow expansion.
Last exit status – $? holds the exit code of the most recently run command and is updated after every command, including each step in && / || / ; chains:
false
echo $? # prints 1
true && echo $? # prints 0
Command history – up/down arrows browse history; Ctrl+R searches history.
All instances share a global history file at ~/.vlsh_history (last 5000 entries).
History expansion (bash-style, not POSIX) — runs on the raw line before
parsing, at the interactive prompt only:
!!— replaced with the expanded text of the previous command (e.g.sudo !!afterls -la→sudo ls -la). Errors if nothing has run yet.!$— replaced with the last word of that previous expanded line (same tokenisation as normal parsing, e.g. afterls -la /tmp→/tmp).!n— replaced with the nth stored history line (1-based): lines loaded from~/.vlsh_history(last 5000 non-empty lines, oldest =!1) plus each new line you type in this session, in order. This is not the same numbering as bash’shistoryevent IDs.!-n(n ≥ 1) — n lines back from the newest stored entry (!-1is the most recent line in the list — usually the same as the last command you typed, analogous to!!when that entry is the previous command).!prefix— the newest history line that starts withprefix(one non-empty word, no leading digit — those are!n). Example:!echoafterecho hello→echo hello.!?sub— the newest line containingsub. Use!?foo?to end the substring at the next?, or!?footo use a single word (foo).
Note: !! substitutes the last expanded command line, while !-1 (and
!n) refer to stored history text (what was typed). After you run !!,
history records the characters !!, not the expanded command — so !-1 can
differ from !! in that case.
If expansion fails (e.g. !99 out of range), vlsh prints an error and skips the
line. Lines from scripts (source, .vlshrc) do not append to this list or
update the “last command” used for !! / !$.
Tab completion – completes file and directory names. For the first word on the line (the command), names from $PATH are merged with matches in the current directory (unless you are typing a path that contains /, which is completed only as a filesystem path). When the command is cd, only directories are suggested. Plugins can register a completion capability to provide custom completions for their commands (e.g. SSH hostnames for ssh).
Inline autosuggestions – as you type, vlsh searches command history (most-recent first) for the first entry that starts with the current input and displays the untyped remainder as dimmed ghost text to the right of the cursor. Pressing → (right arrow) or End when the cursor is already at the end of the line accepts the full suggestion and inserts it into the input.
For cd commands, each history candidate is validated against the filesystem before being offered: if the target directory no longer exists the entry is skipped and the next matching history entry is tried. When no valid history entry is found, the shell falls back to the tab-completion engine to generate a filesystem suggestion — for cd this is the first alphabetically sorted directory in the current working directory (or inside the partial path already typed); for other commands it is the first matching file, $PATH command name, or plugin completion result.
The ghost text is erased cleanly when you press Enter, so only the text you actually typed appears in the executed command line.
POSIX compatibility
vlsh is not a POSIX-conformant shell, but it supports the most commonly used POSIX shell features so that everyday scripts and interactive habits carry over without surprises.
Roadmap: incremental POSIX subset
The goal is option (b): grow a documented, tested subset of POSIX sh behavior—without claiming full conformance and without removing vlsh-specific features.
Counted as vlsh-only (not part of the POSIX subset goal): plugins, .vsh / v run, mux, fish-style inline autosuggestions, and other extensions documented elsewhere.
Suggested phases
-
Stabilise the current surface — Treat parsing and execution that already exists as the contract: tokenisation and quotes (
parse_args), command lists (split_commandsfor&&/||/;),$expansion (expand_vars), globs, leadingVAR=valueassignments, builtins such asexport,unset,cd,source/., pipes, and redirection. Extendv test .whenever behavior is fixed or specified more precisely (seeutils/*_test.v,shellops/*_test.v,exec/*_test.v). A feature inventory (what is implemented vs not) is maintained indocs/posix-inventory.md. -
Parameter expansion and word splitting — Implemented:
${name},${#name},${var:-word},${var:=word},${var:+word},${var:?word}(partial vs strict POSIX—see inventory),${var#pat}/${var##pat}/${var%pat}/${var%%pat}(glob*/?inpat; no[]yet), nested${…}. IFS:parse_argsuses the sessionIFSwhen set (non-empty); default space/tab/newline when unset; see inventory for lexer vs post-expansion nuances. Implementation:expand_vars/expand_brace_param,ifs_chars_for_split/parse_argsinutils/utils.v; tests inutils/utils_test.v. README andhelpdescribe user-facing behaviour. -
Shell grammar —
for/while/until/case, functions, subshells, and here-documents are large; introduce one construct at a time with tests. -
Hardening — Port or adapt individual cases from public POSIX-style shell test suites where practical; full certification is not the target.
Contributing — Prefer small, test-backed changes that match existing modules (utils, shellops, exec, cmds) rather than large rewrites.
Command chaining operators
| Operator | Behaviour |
|---|---|
cmd1 && cmd2 |
Run cmd2 only if cmd1 exits 0 |
cmd1 || cmd2 |
Run cmd2 only if cmd1 exits non-0 |
cmd1 ; cmd2 |
Run cmd2 unconditionally after cmd1 |
All three operators respect single and double quotes (an operator inside quotes is treated as literal text), and a lone | is always treated as a pipe, not part of ||.
Input redirection
sort < unsorted.txt
diff <(sort a.txt) <(sort b.txt) # requires process substitution; not yet supported
grep pattern < file.txt | wc -l
Exit status ($?)
$? is set after every command — including each step in a chain — and can be read with echo $?. It is initialised to 0 when the shell starts.
export and unset
export is the standard way to set environment variables, including PATH.
It works both interactively and in ~/.vlshrc:
export PATH="/opt/bin:$PATH" # prepend to PATH ($PATH is expanded)
export EDITOR=nvim # set and mark variable for child processes
export # list all current environment variables
unset EDITOR # remove a variable from the environment
source / .
Execute a script file in the current shell context. The file is read line by line; blank lines and lines beginning with # are skipped. The return value is the exit code of the last command in the file.
source ~/.vlshrc
. ~/.vlshrc # POSIX dot-command synonym
export and unset lines in ~/.vlshrc are executed automatically at startup. You can use source to reload your config live after editing it.
cd improvements
| Invocation | Behaviour |
|---|---|
cd |
Change to $HOME |
cd ~ |
Change to $HOME |
cd ~/path |
Change to $HOME/path |
cd - |
Change to the previous working directory (stored in $OLDPWD) and print the new path |
cd /some/dir |
Change to the given path |
$PWD and $OLDPWD are kept in sync after every successful cd.
exit N
exit # exit with code 0
exit 1 # exit with code 1
exit 42 # exit with code 42
The exit code is visible to the parent process (echo $? in an outer shell).
Aliases that expand to builtins
Aliases whose expansion begins with a builtin command work correctly:
aliases add nav cd /tmp
nav # equivalent to: cd /tmp
aliases add home cd ~
home # equivalent to: cd ~
Plugins – installed from the remote repository into versioned directories under ~/.vlsh/plugins/<name>/<version>/. Each plugin can expose commands, pre/post-run hooks, output capture hooks (output_hook), prompt decorations, custom tab completions, and help text (help capability) shown by the built-in help command.
Aliases – defined in ~/.vlshrc or managed with the aliases built-in; resolved before PATH lookup.
Debug mode – set VLSHDEBUG=true in the environment to print internal debug output.
.vsh scripts – vlsh natively runs V shell scripts (.vsh files) via v run. You can execute them directly without specifying v run manually:
./myscript.vsh
~/bin/myscript.vsh
myscript.vsh # looked up in current directory
A .vsh file is a regular V source file with all os module functions available globally (no os. prefix needed). Use the following shebang to make the file directly executable outside vlsh too:
Example script (hello.vsh):
#!/usr/bin/env -S v println('Hello from a .vsh script!') files := ls('.') or { [] } for f in files { println(f) }
vlsh looks for the v binary in $PATH.
Plugins
Plugins extend vlsh with new commands and prompt decorations without modifying the shell binary.
How plugins work
- Install a plugin from the remote repository with
plugins install <name>. The source is stored in~/.vlsh/plugins/<name>/<version>/. - vlsh compiles it automatically on startup (requires
vin PATH) and caches the compiled binary in~/.vlsh/plugins/.bin/. - The binary is called by the shell with a single argument that tells it what to do (see the protocol below).
- Use the built-in
pluginscommand to manage them at runtime.
Plugin protocol
Your plugin's main() must handle these arguments:
| Argument | Description |
|---|---|
capabilities |
Print what the plugin provides, one item per line (see table below) |
run <command> [args…] |
Execute a registered command |
prompt |
Print a single line shown above the - prompt |
pre_hook <cmdline> |
Called before every command runs |
post_hook <cmdline> <exit_code> |
Called after every command finishes |
output_hook <cmdline> <exit_code> <output> |
Called after every command; <output> is the captured stdout (empty for interactive/direct-terminal commands not in a pipe chain) |
complete <input> |
Print one tab-completion candidate per line for the current input |
mux_status |
Print a single line shown centred in the mux status bar (polled ~1 s) |
help [command] |
Print help text for the plugin or a specific command (called by the built-in help command) |
Capability tokens (printed in response to capabilities):
| Token | Effect |
|---|---|
command <name> |
Registers <name> as a shell command dispatched via run |
prompt |
Shell calls prompt before each prompt and displays the output above - |
pre_hook |
Shell calls pre_hook <cmdline> before every command |
post_hook |
Shell calls post_hook <cmdline> <exit_code> after every command |
output_hook |
Shell calls output_hook <cmdline> <exit_code> <output> after every command with the captured stdout |
completion |
Shell calls complete <input> on Tab; plugin prints full replacement strings |
mux_status |
Shell calls mux_status roughly once per second in mux mode; plugin prints a single line that appears centred in the status bar |
help |
Shell calls help [command] when the user runs help <cmd> and the plugin owns that command; plugin prints its own help text |
Managing plugins
plugins list – list installed plugins with version and status
plugins enable <name> – enable a previously disabled plugin
plugins enable all – enable every plugin at once
plugins disable <name> – disable a plugin without deleting it
plugins disable all – disable every plugin at once
plugins reload – recompile and reload all plugins
plugins remote – list remote plugins; shows installed version and updates
plugins search <query> – search remote plugins by name or description
plugins install <name> – download and install the latest version
plugins update [name] – update one or all plugins to their latest version
plugins delete <name> – delete a locally installed plugin
plugins reinstall <name> – remove local copy and install latest from remote
Plugins are sourced from the official repository at
https://github.com/vlshcc/plugins. Each plugin has a DESC metadata file
with its name, author, and description — used by plugins search. No
external tooling is required; install downloads source directly. After
installing a plugin, run plugins reload to compile and activate it.
plugins reinstall removes the local copy, installs the latest from remote,
and reloads plugins in one step.
Example plugin (examples/hello_plugin.v)
A minimal template that shows all capabilities. Copy it to get started:
cp examples/hello_plugin.v ~/.vlsh/plugins/myplugin.vIt registers a hello [name] command, contributes a [ example plugin ] prompt line, has empty pre_hook / post_hook / output_hook stubs ready to be filled in, demonstrates the mux_status capability with a static label, and implements the help capability so that help hello prints usage text.
// Respond to 'capabilities' println('command hello') println('help') println('prompt') println('pre_hook') println('post_hook') println('mux_status') // Respond to 'run hello [name]' println('Hello, ${name}!') // Respond to 'help [command]' println('hello - greet someone (example plugin command)') println('') println('Usage:') println(' hello [name] Print "Hello, <name>!"') println('') println('If name is omitted, greets "world".') // Respond to 'prompt' println('[ example plugin ]') // Respond to 'output_hook <cmdline> <exit_code> <output>' // os.args[2] = cmdline, os.args[3] = exit code, os.args[4] = captured stdout // Respond to 'mux_status' println('[ example plugin ]')
Git prompt plugin
Shows the current git branch and short commit hash in the prompt, styled with your style_git_bg / style_git_fg colours.
plugins install git plugins reload
When inside a git repository the line above the - prompt becomes:
(coloured block using the 24-bit ANSI colour values from ~/.vlshrc)
The plugin reads colours from ~/.vlshrc; defaults are 44,59,71 (dark blue-grey background) and 251,255,234 (near-white foreground). Override them with:
style set style_git_bg 44 59 71
style set style_git_fg 251 255 234
SSH host completion plugin
ssh_hosts provides tab completion for SSH hostnames. When you type ssh <prefix> and press Tab, it returns matching hosts gathered from ~/.ssh/config and ~/.ssh/known_hosts. It also supports user@<prefix> notation.
plugins install ssh_hosts plugins reload
Usage:
ssh web<Tab> → ssh webserver, ssh web01 …
ssh root@db<Tab> → ssh root@db1, ssh root@db2 …
Sources read (automatically, no configuration needed):
~/.ssh/config—Hostentries (wildcard patterns like*are skipped)~/.ssh/known_hosts— all non-hashed entries (hashed|1|…lines are skipped)
V module documentation plugin
vman is a man-page style viewer for the official V module documentation at
modules.vlang.io. It fetches the HTML for any
standard-library module, strips the markup, and displays the result in less
(with ANSI colour support) so you can scroll, search, and quit just like a
regular man page.
plugins install v_man plugins reload
Usage:
vman os
vman strings
vman net.http
vman math
What it does:
- Fetches
https://modules.vlang.io/<module>.html. - Converts the HTML to ANSI-formatted text:
- headings become bold (h1 also underlined)
- inline
codeandpreblocks are cyan - lists, paragraphs, and horizontal rules are preserved
<script>,<style>, and<noscript>blocks are stripped
- Opens the result in
less -R(ormoreiflessis unavailable). Falls back to printing directly if neither pager is found.
Output log plugin (examples/output_log.v)
output_log uses the output_hook capability to record every command and its captured stdout to ~/.vlsh/output.log, one timestamped block per command. It also registers two commands: output_search <pattern> to grep through the log from within the shell, and output_log_clear to wipe it.
mkdir -p ~/.vlsh/plugins/output_log/v1.0.0 cp examples/output_log.v ~/.vlsh/plugins/output_log/v1.0.0/output_log.v plugins reload
Usage:
output_search error # find all log blocks containing "error"
output_log_clear # wipe the log
Note: output is captured only for commands run through a pipe chain or the
echobuilt-in. Interactive programs (vim,htop, etc.) and simple direct-terminal commands log a header with an empty body, preserving the timeline without breaking TTY behaviour.
Share plugin (plugins/share.v)
share uploads a file to dpaste.com and prints the resulting URL. It is available as a plugin in the official repository.
plugins install share plugins reload
Usage:
Multiplexer (mux)
Start with mux. A new vlsh session fills the terminal. All key sequences require the Ctrl+V prefix.
| Key | Action |
|---|---|
Ctrl+V + | |
Split active pane vertically (left / right) |
Ctrl+V + - |
Split active pane horizontally (top / bottom) |
Ctrl+V + ←/→/↑/↓ |
Navigate to the adjacent pane |
Ctrl+V + Ctrl+←/→ |
Resize pane horizontally |
Ctrl+V + Ctrl+↑/↓ |
Resize pane vertically |
Ctrl+V + o |
Cycle focus to the next pane |
Ctrl+V + PageUp |
Scroll active pane back into scrollback history |
Ctrl+V + PageDown |
Scroll active pane forward toward live output |
Ctrl+V + q |
Exit mux (only when all panes have been closed) |
Ctrl+V + Ctrl+V |
Send a literal Ctrl+V to the active pane |
| Mouse click | Click a pane to make it active |
| Mouse wheel | Scroll active pane up/down through scrollback history |
Each pane retains up to 1000 lines of scrollback history. While scrolled back, an orange indicator in the top-right corner of the pane shows how many lines above live output you are. Panes close automatically when their shell process exits. The terminal is fully restored on exit and a confirmation message is printed.
The status bar at the top shows vlsh mux on the left and the live pane count on the right. Plugins that declare the mux_status capability contribute text that is displayed centred between those labels and refreshed roughly once per second.
Module API summary
cfg – get() !Cfg, paths() ![]string, aliases() !map[string]string, style() !map[string][]int, add_path, remove_path, add_alias, remove_alias, set_style
exec – Task.prepare_task() !int runs a command string (with pipes, redirection, tilde expansion) and returns the exit code
utils – parse_args(string) []string tokenises a command line respecting single/double quotes; fail/warn/ok/debug for formatted output
mux – enter(status_providers []string) is the public entry point; internally uses Mux, Pane, LayoutNode, InputHandler
plugins – load() []Plugin, installed_list() []InstalledPlugin, available() []string, dispatch(…) bool, completions(loaded, input) []string, run_pre_hooks, run_post_hooks, run_output_hooks(loaded, cmdline, exit_code, output), prompt_segments(loaded) string, mux_status_binaries(loaded) []string, enable(name), disable(name), enable_all(), disable_all(), remote_plugin_names() ![]string, remote_versions(name) ![]string, latest_remote_version(name) !string, fetch_desc(name) !PluginDesc, install(name) !string, update_plugin(name) !string, delete_plugin(name) !, reinstall_plugin(name) !string, search_remote(query) ![]PluginDesc
DISCLAIMER
vlsh is provided as-is, without warranty of any kind. The creator and contributors are not liable for any damage, data loss, system instability, security issues, or any other consequence — direct or indirect — that may arise from using vlsh or any of its plugins. You use this software entirely at your own risk. This applies equally to the shell itself, the bundled example plugins, and any third-party plugins you install.
CREDITS
Originally created by onyxcode
LICENSE
MIT License
Copyright (c) [2021-2026] [David Satime Wallin david@snogerup.com]
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.