Skip to content
nobspromptby neg4n.dev
Esc
navigateopen⌘Jpreview
On this page

Autosuggestions

Use recent-history ghost text and point-in-time, path-aware directory suggestions without blocking foreground filesystem work.

The recommended setup enables autosuggestions with either prompt mode:

eval "$(nbsp init zsh --autosuggest)"

This is intentionally smaller than fish completion. It predicts one complete line; it does not generate option descriptions, parse command grammars, or replace Tab completion.

Selection order

At initialization, nobsprompt snapshots up to 4,096 nonempty history values while examining at most 8,192 descending Zsh event numbers. It updates that snapshot at each precmd, including the newest command when Zsh’s history ring is full. Ordinary commands search the snapshot for an exact, case-sensitive prefix. A chosen candidate can be reused while subsequent input still matches it, but all redraw eligibility checks - including the queued-input check - run before either cached reuse or a fresh search.

Safely parseable cd paths use a different rule: a validated point-in-time directory snapshot gates candidates and history is only a ranking signal. Nobsprompt:

  1. resolves the parent implied by the typed path;
  2. asynchronously reads that parent’s immediate child directories;
  3. offers the single captured prefix match; or
  4. when several captured children match, chooses the newest one also represented by matching cd history.

A historical directory missing when the parent snapshot is captured is not offered from that snapshot. For example, if history contains cd ~/Desktop/programming/work but only web/ exists, typing cd ~/Desktop/programming/w suggests eb/, not ork.

cd al stays empty when both alpha/ and alpine/ exist and neither has a matching history rank. Ordinary Tab completion remains available for every ambiguous or unsupported case.

Suggestions are suppressed for multiline input, leading whitespace, selections, a cursor before the end of the buffer, prefixes longer than 256 characters, complete results longer than 4,096 characters, and queued input. The engine does not separately label a buffer as typed versus recalled from history.

Supported directory paths

Path-aware suggestions accept one static operand in cd PATH or cd -- PATH. They support:

  • immediate and nested relative paths such as cd src/n;
  • explicit ./ and ../ parents;
  • absolute paths;
  • ~/ paths;
  • closed quotes and backslash-escaped spaces.

The parser performs Zsh lexical splitting and quote removal only. It never evaluates the command. It rejects operands whose source contains $, backticks, *, ?, [, ], {, }, (, ), <, >, |, &, ;, ^, or #, including quoted or backslash-escaped forms. Named directories such as ~user, an unquoted operand source beginning with =, unmatched quotes, multiple operands, and a leading - without cd -- also remain ordinary history or Tab-completion territory.

Explicit ., .., ./…, and ../… operands resolve from $PWD and bypass cdpath, as they do in Zsh. For other relative operands, nobsprompt scans $PWD only when it can prove that Zsh will try the current directory first. With POSIX_CD unset, that is true when cdpath is empty, when it contains no . or empty component (Zsh then tries $PWD implicitly first), or when its first component is . or empty. If a nonlocal component precedes an explicit . or empty component, nobsprompt does not guess. With POSIX_CD set, cdpath must be empty or its first component must be . or empty; otherwise cdpath is searched before the implicit current directory. This is the search order documented for Zsh cd and POSIX_CD.

The engine does not scan multiple CDPATH roots. If it cannot prove that its single $PWD snapshot describes the directory Zsh would choose, it leaves the case to history and Tab completion. Explicit dot-relative, absolute, and ~/ paths do not use CDPATH. A bare path without the cd command is ordinary command history because Zsh would try to execute it.

Directory cost and safety

The filesystem is not traversed on each keypress. The first eligible path starts one asynchronous nbsp dirs process for its resolved parent. Nested input such as ~/Desktop/programming/w still reads only the immediate children of ~/Desktop/programming; it does not walk from the home directory. The result is published only after a complete NUL-framed snapshot arrives. The worker has hard limits of:

  • 50 ms;
  • 1,024 immediate child directories;
  • 64 KiB of records.

It reads one level only, includes directory symlinks, and performs no recursive walk. A timeout, malformed frame, changed working directory, changed typed parent, closed descriptor, or exceeded limit discards the partial snapshot and shows no cd suggestion. It never falls back to an unvalidated history path.

A valid snapshot is sorted once and keyed by its parent. Prefix and history membership checks use binary search without filesystem syscalls. The snapshot is reused while the parent remains unchanged, replaced when input moves to a different parent, and invalidated at precmd and chpwd boundaries. It is not continuously revalidated: a child created or removed after capture may remain absent or present until invalidation, and a suggested path can disappear before acceptance. Appended directory text is shell-quoted before display or insertion; names are data, never evaluated as Zsh source.

Accepting and controlling suggestions

Right Arrow accepts ghost text in Zsh’s native Emacs and Vi insert keymaps. Nobsprompt claims a terminal sequence only when it is still bound to the keymap’s built-in forward-char or vi-forward-char widget during initialization. Existing user or plugin bindings are preserved.

The widgets are public for explicit bindings:

bindkey '^F' nbsp-autosuggest-accept
bindkey '^X^A' nbsp-autosuggest-toggle

Acceptance is ownership-checked: it inserts text only when the current POSTDISPLAY still equals the suffix produced by nobsprompt. Otherwise it falls back to the keymap’s original character-movement widget. Highlight ownership is similarly narrow, so unrelated ZLE integrations keep their display state.

Tab remains Zsh completion; it does not accept nobsprompt ghost text. An ambiguous completion can print a candidate list below the prompt, and Zsh’s default ALWAYS_LAST_PROMPT behavior leaves that list visible while returning the cursor to the command line. This is native completion output. To stop Zsh from listing ambiguous candidates automatically, add this separately to your shell configuration:

unsetopt AUTO_LIST

Nobsprompt deliberately does not clear completion lists or wrap completion widgets, so command-specific completions and completion plugins keep control.

Set the ghost-text style before initialization if the default fg=8 does not fit the terminal palette:

typeset -g NBSP_AUTOSUGGEST_HIGHLIGHT_STYLE='fg=242'
eval "$(nbsp init zsh --autosuggest)"

Plugin compatibility

If another engine is already loaded, nobsprompt reports the conflict and skips its own engine without setting its initialization guard. After removing that early conflict, re-sourcing nbsp init zsh --autosuggest can initialize the engine; repeated successful sourcing does not duplicate its hooks. If a conflicting engine appears later, nobsprompt disables itself and warns once at the next safe precmd boundary. Redraw-time detection remains silent and fail-closed so a warning cannot corrupt the active command line.

Nobsprompt does not wrap every widget or overwrite custom Right Arrow bindings. Unknown integrations that also own ZLE POSTDISPLAY are not guaranteed to be compatible, so configure only one ghost-text provider.

Without --autosuggest, the emitted Zsh integration and prompt behavior are unchanged.