Repository navigation
Nushell 0.116: vp and vpr completion shows nothing when fish is not installed #3272
Description
Describe the bug
The env.nu completers for vp and vpr call ^fish to get completions. When fish is not on PATH, ^fish fails. Nushell 0.115 and earlier ignore the failure and show file completion. Nushell 0.116 returns no suggestions for a parameter completer that fails, so Tab after vp shows nothing.
If the completer returns null when fish is missing, Nushell 0.116 shows file completion again. This is the 0.115 behavior. I plan to submit a PR with this fix.
Cause
The 0.116 release notes describe the change in Unified custom completions. The change comes from nushell/nushell#18791.
Parameter completers that fail now return no suggestions instead of unexpectedly falling back to the working directory.
The same section also says:
A completer can now return
nullto decline and let another completion source answer, ...
The list of behavior changes names null only for command-wide and external completers. nu-complete vp is a parameter completer, because env.nu attaches it with string@"nu-complete vp". The Nushell Book gives the rule for parameter completers in Custom Completions:
To fall back to Nushell's built-in file completions, return
nullrather than a list of suggestions.nullmeans "I have no answer here", so the next completion source answers instead, while an empty list means "there is nothing to complete".
The 0.116.1 source agrees with the Book. See custom_completions/mod.rs#L439-L449. When a parameter completer fails, Nushell answers with an empty list. The source calls this kind of completer Narrowing::Engine. When a completer returns no output, Nushell declines and runs the next completion source. custom_completions/output.rs#L237 reads null as no output.
Proposed fix
Return null from nu-complete vp fish when fish is not on PATH:
def "nu-complete vp fish" [command: string] {
+ if (%which fish | %is-empty) { return null }
let fish_script = 'VP_COMPLETE=fish command vp | source; complete --do-complete=$argv[1]'The template is ENV_TEMPLATE_NU in crates/vp_global_cli/src/commands/env/setup.rs. For Nushell before 0.112.1, NuSyntax::Legacy removes the % sigils. The vpr completer also calls nu-complete vp fish, so this one line fixes both commands.
The guard checks only for a missing fish. I do not want to wrap the call in try { ... } catch { null }. With that wrapper, Nushell also shows file completion when fish is installed but the vp completion is broken. Users would then not see that failure.
Reproduction
https://github.com/voidzero-dev/vite-plus/blob/main/crates/vp_global_cli/src/commands/env/setup.rs
Steps to reproduce
You do not need a project. The bug is in the generated env.nu.
In zsh:
export VP_HOME=$(mktemp -d)
vp env setup --refresh
cd $VP_HOME
nu -nIn Nushell 0.116.1:
version | get version
# 0.116.1
$env.PATH = ($env.PATH | where { not ($in | path join fish | path exists) })
which fish
# empty list
source env.nu
"vp " | commandline complete
# ╭────────────╮
# │ empty list │
# ╰────────────╯In an interactive session, vp <Tab> also shows nothing.
These steps remove fish from PATH inside Nushell. With mise, nu and fish are in the same shims directory. If you remove that directory from PATH before you start Nushell, zsh cannot find nu.
To see the old behavior, do the same steps with Nushell 0.115.1.
System Info
$ vp env current
Node.js:
Version 22.23.4
Source .node-version
Bin Path /Users/naokihaba/.vite-plus/js_runtime/node/22.23.4/bin/node
Installed true
Mode managed
Package Manager:
Name pnpm
Version 12.11.2
Source packageManager
Bin Paths
pnpm /Users/naokihaba/.vite-plus/package_manager/pnpm/12.11.2/pnpm/bin/pnpm
pnpx /Users/naokihaba/.vite-plus/package_manager/pnpm/12.11.2/pnpm/bin/pnpx
Installed true
Mode managed
$ vp --version
vp v1.4.0
Local vite-plus:
vite-plus v1.4.0
Tools:
vite v8.3.2
rolldown v1.2.12
vitest v5.0.3
oxfmt v0.71.0
oxlint v1.86.0
oxlint-tsgolint v7.0.2003
tsdown v0.23.0
Environment:
Package manager pnpm v12.11.2
Node.js v22.23.4 (.node-version)Used Package Manager
pnpm
Logs
### 1. Nushell 0.116.1, `env.nu`, fish on `PATH`
❯ cd $VP_HOME
❯ nu -n -c 'source env.nu; "vp " | commandline complete | length'
35
### 2. Nushell 0.116.1, `env.nu`, without fish
Non-interactive:
❯ nu -n -c 'source env.nu
with-env { PATH: ($env.PATH | where { not ($in | path join fish | path exists) }) } {
"vp " | commandline complete
}'
╭────────────╮
│ empty list │
╰────────────╯
Interactive. I pressed Tab after `vp env`, and Nushell showed nothing:
❯ PATH=$NOFISH_PATH ~/.local/share/mise/installs/nushell/0.116.1/*/nu -n
/private/var/folders/zv/2c__5lqn00j_j14pxlf6zm_h0000gn/T/tmp.KNugJ9tOZ0> which fish
╭────────────╮
│ empty list │
╰────────────╯
/private/var/folders/zv/2c__5lqn00j_j14pxlf6zm_h0000gn/T/tmp.KNugJ9tOZ0> source env.nu
/private/var/folders/zv/2c__5lqn00j_j14pxlf6zm_h0000gn/T/tmp.KNugJ9tOZ0> vp env
### 3. Nushell 0.115.1, `env.nu`, without fish
Non-interactive, in the first `VP_HOME`:
❯ ~/.local/share/mise/installs/nushell/0.115.1/*/nu -n -c 'source env.nu
with-env { PATH: ($env.PATH | where { not ($in | path join fish | path exists) }) } {
"vp " | commandline complete
}'
╭───┬───────────────╮
│ 0 │ bin/ │
│ 1 │ cache/ │
│ 2 │ config.json │
│ 3 │ env │
│ 4 │ env.fish │
│ 5 │ env.nu │
│ 6 │ env.ps1 │
│ 7 │ fallback-bin/ │
│ 8 │ vp.ps1 │
╰───┴───────────────╯
Interactive, in a second `VP_HOME`. That directory also has `js_runtime/`:
❯ ~/.local/share/mise/installs/nushell/0.115.1/*/nu -n
/private/var/folders/zv/2c__5lqn00j_j14pxlf6zm_h0000gn/T/tmp.XPkZSjSPsm> version | get version
0.115.1
/private/var/folders/zv/2c__5lqn00j_j14pxlf6zm_h0000gn/T/tmp.XPkZSjSPsm> $env.PATH = ($env.PATH | where { not ($in | path join fish | path exists) })
/private/var/folders/zv/2c__5lqn00j_j14pxlf6zm_h0000gn/T/tmp.XPkZSjSPsm> which fish
╭────────────╮
│ empty list │
╰────────────╯
/private/var/folders/zv/2c__5lqn00j_j14pxlf6zm_h0000gn/T/tmp.XPkZSjSPsm> source env.nu
/private/var/folders/zv/2c__5lqn00j_j14pxlf6zm_h0000gn/T/tmp.XPkZSjSPsm> "vp " | commandline complete
╭───┬───────────────╮
│ 0 │ bin/ │
│ 1 │ cache/ │
│ 2 │ config.json │
│ 3 │ env │
│ 4 │ env.fish │
│ 5 │ env.nu │
│ 6 │ env.ps1 │
│ 7 │ fallback-bin/ │
│ 8 │ js_runtime/ │
│ 9 │ vp.ps1 │
╰───┴───────────────╯
### 4. Nushell 0.116.1, `env-a.nu` with the proposed fix, without fish
❯ cp env.nu env-a.nu
# I added the guard line to env-a.nu.
❯ diff env.nu env-a.nu
52a53
> if (%which fish | %is-empty) { return null }
❯ nu -n
/private/var/folders/zv/2c__5lqn00j_j14pxlf6zm_h0000gn/T/tmp.XPkZSjSPsm> version | get version
0.116.1
/private/var/folders/zv/2c__5lqn00j_j14pxlf6zm_h0000gn/T/tmp.XPkZSjSPsm> $env.PATH = ($env.PATH | where { not ($in | path join fish | path exists) })
/private/var/folders/zv/2c__5lqn00j_j14pxlf6zm_h0000gn/T/tmp.XPkZSjSPsm> source env-a.nu
"vp " | commandline complete
╭────┬───────────────╮
│ 0 │ bin/ │
│ 1 │ cache/ │
│ 2 │ config.json │
│ 3 │ env │
│ 4 │ env-a.nu │
│ 5 │ env.fish │
│ 6 │ env.nu │
│ 7 │ env.ps1 │
│ 8 │ fallback-bin/ │
│ 9 │ js_runtime/ │
│ 10 │ vp.ps1 │
╰────┴───────────────╯Validations
- Read the Contributing Guidelines.
- Check that there isn't already an issue for the same bug.
- Confirm this is a Vite+ issue and not an upstream issue (Vite, Vitest, tsdown, Rolldown, or Oxc).
- The provided reproduction is a minimal reproducible example.
Metadata
Metadata
Assignees
Labels
Type
Fields
Priority
Effort
Target date
Start date
Activity
voidzero-bot commentedon Oct 29, 2026
crates/vp_global_cli/src/commands/env/setup.rsfishonPATH; users can restore rich completions by installing fish manually. It is annoying because Tab shows nothing, but it does not break installs or builds.The generated
env.nudefinesnu-complete vpandnu-complete vprincrates/vp_global_cli/src/commands/env/setup.rs. Both helpers run^fish --command ...to delegate to Fish completions, and whenfishis absent the external command fails. Nushell 0.116 treats a failing parameter completer as an explicit empty list, so the built-in file completion fallback no longer runs.I found a potential fix for this issue. Adding
if (%which fish | %is-empty) { return null }at the top of both completers makes Nushell decline the custom completion and fall back to file completions. The guard only handles a missingfishbinary; it intentionally does not wrap the^fishcall intry/catch, so real failures when fish is installed are still surfaced. A regression test incrates/vp_global_cli/src/commands/env/setup.rschecks that both the%sigil and Legacy renderings include the guard.Full Triage Report
Triage Report: gh-3272
Issue Summary
Title: Nushell 0.116:
vpandvprcompletion shows nothing when fish is not installedWhen the Nushell
env.nugenerated byvp env setupis loaded, the parameter completers forvpandvprrun^fishto delegate to Fish completion. Iffishis not onPATH, the external command fails. Nushell 0.116 changed behavior so that a failing parameter completer returns an empty suggestion list instead of falling back to file completions. Pressing Tab aftervptherefore shows nothing.Environment
/home/runner/work/vite-plus/vite-plustriagebot/fix-3272vp v1.4.0v22.23.412.11.20.116.13.7.0Reproduction
With Nushell 0.116.1 and no usable
fishbinary:Control case with fish on
PATH:Diagnosis
crates/vp_global_cli/src/commands/env/setup.rsENV_TEMPLATE_NU(lines ~954–1046), specifically:def "nu-complete vp" [context: string] { ... }def "nu-complete vpr" [context: string] { ... }^fish --command ...without checking whetherfishis installed. When it is absent, the completer fails and Nushell 0.116 returns an empty list.if (%which fish | %is-empty) { return null }at the start of both completers. The%prefix is automatically stripped for Nushell versions older than 0.112.1 by the existing%→nu_syntax.builtin_prefix()substitution.Verification
The Nushell Book recommends returning
nullfrom a parameter completer to decline and let the default completion source answer. The reporter’s proposed guard matches this idiom. Wrapping the entire^fishcall intry { ... } catch { null }was intentionally avoided so that real completion failures when fish is installed are not silently hidden.Verdict:
bugConfidence:
highFix
Changed file
crates/vp_global_cli/src/commands/env/setup.rsif (%which fish | %is-empty) { return null }tonu-complete vp.if (%which fish | %is-empty) { return null }tonu-complete vpr.test_render_env_content_nu_syntaxto verify both the%sigil and Legacy renderings include the guard in both completers.Regression test
Updated
crates/vp_global_cli/src/commands/env/setup.rs:Validation
Unit tests:
cargo test -p vp_global_cli commands::env::setup::testsResult: 36 passed.
Lint/format:
Result: both passed.
End-to-end with generated
env.nu:VP_HOME.PATH,commandline completefor"vp "returned file completions.PATH, the same command returned 35 Fish-backed completions.PATHto exercise the%sigil path; the generatedenv.nucontainedif (%which fish | %is-empty) { return null }and also fell back to file completions.Result
trueFull crate test suite:
cargo test -p vp_global_cliResult: 543 passed; 0 failed.
This report was made by an LLM. The analysis may be wrong, and the potential fix might not work, but is intended as a starting point for exploring the issue.
I've opened a pull request with this fix: #3273
naokihaba commentedon Oct 29, 2026
I have a fix with a behavior test on my fork:
naokihaba/vite-plus@fix/nushell-completer-input...fix/nushell-completion-without-fish
It depends on #3267, so I will open the PR after #3267 merges. Compared with #3273, it adds the guard once in the shared
nu-complete vp fishhelper. It also adds a snapshot test that runs Nushell without fish, and it updatesshell_integration_cwd_templates.md. I suggest that we close #3273 when I open the PR.fix(env): fall back to file completion in Nushell without fish
fix(env): fall back to file completion in Nushell without fish (#3276)