Skip to content

Nushell 0.116: vp and vpr completion shows nothing when fish is not installed #3272

Closed

Description

@naokihaba

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 null to 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 null rather than a list of suggestions. null means "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 -n

In 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

Activity

  1. self-assigned this
    on Oct 29, 2026
  2. added theissue type on Oct 29, 2026
  3. voidzero-bot commented on Oct 29, 2026

    @voidzero-bot
    • Reproduced: Yes
    • Exploration: Yes — View branch
    • Unit Test: Yes — crates/vp_global_cli/src/commands/env/setup.rs
    • Priority: P2: Has Workaround. This only happens when Nushell 0.116 is used without fish on PATH; 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.nu defines nu-complete vp and nu-complete vpr in crates/vp_global_cli/src/commands/env/setup.rs. Both helpers run ^fish --command ... to delegate to Fish completions, and when fish is 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 missing fish binary; it intentionally does not wrap the ^fish call in try/catch, so real failures when fish is installed are still surfaced. A regression test in crates/vp_global_cli/src/commands/env/setup.rs checks that both the % sigil and Legacy renderings include the guard.

    Full Triage Report

    Triage Report: gh-3272

    Issue Summary

    Title: Nushell 0.116: vp and vpr completion shows nothing when fish is not installed

    When the Nushell env.nu generated by vp env setup is loaded, the parameter completers for vp and vpr run ^fish to delegate to Fish completion. If fish is not on PATH, 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 after vp therefore shows nothing.

    Environment

    • Repository: /home/runner/work/vite-plus/vite-plus
    • Branch: triagebot/fix-3272
    • vp (local checkout): vp v1.4.0
    • Node.js: v22.23.4
    • pnpm: 12.11.2
    • OS: Ubuntu (GitHub Actions runner, x86_64)
    • Nushell under test: 0.116.1
    • fish: 3.7.0

    Reproduction

    With Nushell 0.116.1 and no usable fish binary:

    export VP_HOME=$(mktemp -d)
    export VP_SELF_SETUP_NO_MODIFY_PATH=1
    vp env setup --refresh
    cd "$VP_HOME"
    nu -n -c 'source env.nu; $env.PATH = ($env.PATH | where { not ($in | path join fish | path exists) }); which fish; "vp " | commandline complete'
    # empty list

    Control case with fish on PATH:

    nu -n -c 'source env.nu; which fish; "vp " | commandline complete | length'
    # 35

    Diagnosis

    • Affected file: crates/vp_global_cli/src/commands/env/setup.rs
    • Affected template: ENV_TEMPLATE_NU (lines ~954–1046), specifically:
      • def "nu-complete vp" [context: string] { ... }
      • def "nu-complete vpr" [context: string] { ... }
    • Root cause: Both completers directly execute ^fish --command ... without checking whether fish is installed. When it is absent, the completer fails and Nushell 0.116 returns an empty list.
    • Suggested fix: Add 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 null from a parameter completer to decline and let the default completion source answer. The reporter’s proposed guard matches this idiom. Wrapping the entire ^fish call in try { ... } catch { null } was intentionally avoided so that real completion failures when fish is installed are not silently hidden.

    Verdict: bug
    Confidence: high

    Fix

    Changed file

    • crates/vp_global_cli/src/commands/env/setup.rs
      • Added if (%which fish | %is-empty) { return null } to nu-complete vp.
      • Added if (%which fish | %is-empty) { return null } to nu-complete vpr.
      • Added assertions to test_render_env_content_nu_syntax to 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:

    let sigil = render_env_content(EnvShell::Nu, &config, NuSyntax::BuiltinSigil);
    assert!(
        sigil.contains("if (%which fish | %is-empty) { return null }"),
        "got: {sigil}"
    );
    assert_eq!(
        sigil.matches("if (%which fish | %is-empty) { return null }").count(),
        2,
        "guard should appear in both vp and vpr completers, got: {sigil}"
    );
    
    let legacy = render_env_content(EnvShell::Nu, &config, NuSyntax::Legacy);
    assert!(
        legacy.contains("if (which fish | is-empty) { return null }"),
        "got: {legacy}"
    );
    assert_eq!(
        legacy.matches("if (which fish | is-empty) { return null }").count(),
        2,
        "guard should appear in both vp and vpr completers, got: {legacy}"
    );

    Validation

    1. Unit tests:

      cargo test -p vp_global_cli commands::env::setup::tests

      Result: 36 passed.

    2. Lint/format:

      cargo fmt --all -- --check
      cargo clippy -p vp_global_cli --all-targets -- -D warnings

      Result: both passed.

    3. End-to-end with generated env.nu:

      • Built the global CLI release binary.
      • Installed it into a fresh VP_HOME.
      • With Nushell 0.116.1 and fish removed from PATH, commandline complete for "vp " returned file completions.
      • With fish on PATH, the same command returned 35 Fish-backed completions.
      • Re-ran the setup with Nushell 0.116.1 on PATH to exercise the % sigil path; the generated env.nu contained if (%which fish | %is-empty) { return null } and also fell back to file completions.

    Result

    • fixed: true
    • The original reproduction now returns file completions instead of an empty list when fish is absent, while full completions continue to work when fish is present.
    1. Full crate test suite:

      cargo test -p vp_global_cli

      Result: 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

  4. naokihaba commented on Oct 29, 2026

    @naokihaba
    CollaboratorAuthor

    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 fish helper. It also adds a snapshot test that runs Nushell without fish, and it updates shell_integration_cwd_templates.md. I suggest that we close #3273 when I open the PR.

  5. added a commit that references this issue on Oct 29, 2026
    f075433
  6. added a commit that references this issue on Oct 30, 2026
    b567b23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

Fields

Priority

None yet

Effort

None yet

Target date

None yet

Start date

None yet

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions