Completion
Canonical Quirl project documentation synced from docs/completion.md.
Quirl's Tab key behaves like Zsh's default completion, then adds a menu with documentation beside each candidate. If you already rely on Zsh completion, the same keystrokes produce the same command lines in Quirl.
What Tab does
Press Tab in the middle of a word. Quirl gathers candidates from every source (see below), then acts once they have all answered:
| Situation | Result | Example |
|---|---|---|
| Exactly one match | The match is inserted, followed by a space | cat my → cat my\ file.txt␠ |
| One directory | The directory is inserted with a trailing /, ready for the next level | cd cr → cd crates/ |
| Several matches sharing a longer prefix | The word grows to the shared prefix and the menu lists the choices | ls Car → ls Cargo. |
| Several matches, no shared progress | The menu opens | git ch → menu |
| No matches | Nothing changes |
While the menu is open, each further Tab puts the next candidate on the
line, like Zsh's menu completion: ls Tab Tab gives ls Cargo.lock, and
another Tab gives ls Cargo.toml. Once cycling has started, the arrow keys
move through the same list. Enter accepts the candidate (adding the
separating space), Esc closes the menu and keeps what is on the line,
Ctrl-_ (undo) restores the line from before the candidate, and
Shift-Tab expands the list into the full picker.
Quirl never types a guess for you. When only a fuzzy match is available, such
as gco matching git checkout, the menu shows it for review instead of
replacing what you wrote.
Words that invite more typing do not get a trailing space: directories end in
/, option assignments such as --color= stay open, and so do host:
prefixes. A file completed inside an open quote also closes the quote:
cat "my → cat "my file.txt"␠.
Where candidates come from
| Source | Completes | Notes |
|---|---|---|
| Command catalog | Commands, subcommands, options, documented option values | Built from Quirl's curated catalog plus discovered Fish, Bash, and Zsh declarations, --help text, and man pages |
| Filesystem | Files and directories | cd offers only directories; hidden entries appear when the word starts with .; ~/ expands from HOME |
| Environment | $NAME and ${NAME | Shows each value; a variable that names a directory completes with a /, like Zsh's AUTO_PARAM_SLASH |
| Live Zsh | Any argument Zsh knows how to complete | Git branches and refs, Make targets, SSH hosts, process IDs, package names, and so on |
| Lua plugins | Whatever trusted plugins register | See the plugin platform documentation |
Candidates that produce the same command line are shown once, even if two
sources describe them differently. The plain file listing is a fallback: when
Zsh's function for the command answers, its choice wins, so git add offers
changed files rather than every file in the directory.
Ranking
Matches are ranked in three tiers:
- names that start with exactly what you typed;
- names that start with it when case is ignored;
- fuzzy subsequence matches.
Only the best tier that has any matches is shown, in alphabetical order with
an exact match first. Commands complete one word at a time, as in Zsh: gi
offers git and gist, and git ch offers git checkout, git cherry,
and git cherry-pick, but not every deeper git … path.
Live Zsh completion
For arguments, an explicit Tab also asks your installed Zsh. Quirl runs Zsh's own completion functions, so dynamic values such as branch names come from the same code that completes them in Zsh.
The request is deliberately contained:
- It runs only when you press Tab. As-you-type suggestions never start a shell.
- Zsh starts without your startup files (
.zshrcand friends) and with a cleared environment, exceptPATH,HOME,USER, andLOGNAME. - Each request is bounded to 1.5 seconds and 1,024 candidates, and its whole process group is cleaned up afterwards.
- Zsh's bundled completion functions take precedence. Site directories add
functions for commands Zsh does not ship: the system, Debian
vendor-completions, Homebrew, and Nixshare/zsh/site-functionsdirectories, the per-user~/.zfunc,~/.zsh/completions, and~/.local/share/zsh/site-functions, and rustup's toolchain folder, which carries_cargo. SetQUIRL_ZSH_PATHto a:-separated list to replace the site directories, for example to include a plugin manager's folder. - Without Zsh, or for a command with no Zsh completion function, the other sources still answer on their own.
- Set
QUIRL_ZSH_COMPLETION=offbefore starting Quirl to disable live Zsh completion for the session.
Results keep Zsh's display order: each group is sorted, unless Zsh added it
unsorted on purpose, such as recent commits after branch names. A candidate
containing /, such as the branch feature/login, is shown as a path only
when it names an existing file or directory.
The command's own completion
Many modern tools, including docker, kubectl, gh, helm, and podman,
are built on Cobra and complete their own arguments
through PROGRAM __complete ARGS.... When Zsh has no function for such a
command, an explicit Tab asks the program itself, so docker im offers
image and images with their descriptions.
Only a fixed list of known Cobra programs is asked, because any other program
would receive __complete as an ordinary argument. Each request runs only on
Tab, in its own contained process group, within 1.5 seconds and 256 KiB of
output; any failure simply contributes nothing. Set
QUIRL_TOOL_COMPLETION=off before starting Quirl to disable these requests.
Checking completion from a script
quirl complete prints the candidates an explicit Tab offers for a partial
command line, from the same engine and every source:
$ quirl complete "git checkout f"
feature/one
fix-twoUse --format json for machine-readable output with replacement ranges.
Automatic suggestions
While you type, Quirl can open an informational menu for exact commands and
option prefixes, and a selectable one for explicit paths. Enter keeps running
the command unless you have moved into the menu with Tab or the arrow keys.
The completion.auto and completion.min_chars configuration settings
control this behavior.