Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# User commands that shadow the built-ins env.nu uses (#3092). Nushell resolves
# names at parse time, so env.nu must call the built-ins with the `%` sigil.
# This script itself uses only keywords and commands that are not shadowed.
def update [] { "user update" }
def length [] { "user length" }
def skip [] { }
def lines [] { }
def parse [] { }
def get [] { }
def default [] { }
def insert [] { }
def reduce [] { }
def is-not-empty [] { }
def load-env [] { }
def hide-env [] { }
def with-env [] { }
def prepend [] { }
def append [] { }
def "str starts-with" [] { }
def "str replace" [] { }
def "path expand" [] { }
def "path exists" [] { }
def "from tsv" [] { }
def rename [] { }
def any [] { }
def fish [] { }

source env.nu

vp env use 20.18.0 --no-install
if ("VP_NODE_VERSION" not-in $env) {
error make { msg: "vp env use did not set VP_NODE_VERSION" }
}
if $env.VP_NODE_VERSION != "20.18.0" {
error make { msg: $"VP_NODE_VERSION mismatch: expected 20.18.0, got ($env.VP_NODE_VERSION)" }
}

vp env use --unset
if ("VP_NODE_VERSION" in $env) {
error make { msg: "vp env use --unset did not remove VP_NODE_VERSION" }
}

if (update) != "user update" {
error make { msg: "env.nu replaced the user's update command" }
}

print "env.nu loads and works with shadowed built-ins"
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,14 @@ steps = [
{ argv = ["vpt", "cp", "assert_dirs.nu", "config-$USER-\"quote\"-'single'-`tick`-\\slash/vite-plus/assert_dirs.nu"], snapshot = false },
{ argv = ["nu", "config-$USER-\"quote\"-'single'-`tick`-\\slash/vite-plus/assert_dirs.nu"], comment = "Nushell loads env.nu, preserves a PATH with shell metacharacters, and omits internal directory variables", envs = [["HOME", "${workspace}/shell-home"], ["USERPROFILE", "${workspace}/shell-home"], ["VP_HOME", ""], ["EXPECTED_VP_BIN_DIR", "${workspace}/bin-$USER-\"quote\"-'single'-`tick`-\\slash"], ["PATH", "${workspace}/bin-$USER-\"quote\"-'single'-`tick`-\\slash:${workspace}/bin-$USER-\"quote\"-'single'-`tick`-\\slash:${PATH}"]] },
]

[[case]]
name = "command_env_nushell_shadowed_builtins"
vp = "global"
skip-platforms = ["windows"]
requires = ["nu"]
steps = [
{ argv = ["vp", "env", "setup", "--refresh"], envs = [["VP_HOME", "${workspace}/home"]], snapshot = false },
{ argv = ["vpt", "cp", "assert_shadowed.nu", "home/assert_shadowed.nu"], snapshot = false },
{ argv = ["nu", "assert_shadowed.nu"], cwd = "home", comment = "env.nu loads and runs `vp env use` when user commands shadow the built-ins it calls (#3092)", envs = [["VP_HOME", "${workspace}/home"]] },
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# command_env_nushell_shadowed_builtins

## `VP_HOME=${workspace}/home vp env setup --refresh`


## `vpt cp assert_shadowed.nu home/assert_shadowed.nu`


## `cd home && VP_HOME=${workspace}/home nu assert_shadowed.nu`

env.nu loads and runs `vp env use` when user commands shadow the built-ins it calls (#3092)

```
Using Node.js <version> (resolved from 20.18.0)
Reverted selected components to project environment resolution
env.nu loads and works with shadowed built-ins
```
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "shell_integration_cwd_templates"
vp = "global"
skip-platforms = ["windows"]
steps = [
{ argv = ["vp", "env", "setup", "--refresh"], envs = [["VP_HOME", "${workspace}/home"]], snapshot = false },
{ argv = ["vp", "env", "setup", "--refresh"], envs = [["VP_HOME", "${workspace}/home"], ["VP_NU_VERSION", "0.112.1"]], comment = "VP_NU_VERSION keeps env.nu independent of the installed Nushell", snapshot = false },
{ argv = ["vpt", "print-file", "home/env"], comment = "POSIX wrapper and zsh vpr completion keep global -C before env use/run" },
{ argv = ["vpt", "print-file", "home/env.fish"], comment = "fish wrapper and vpr completion keep global -C before env use/run" },
{ argv = ["vpt", "print-file", "home/env.nu"], comment = "Nushell wrapper and vpr completion keep global -C before env use/run" },
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# shell_integration_cwd_templates

## `VP_HOME=${workspace}/home vp env setup --refresh`
## `VP_HOME=${workspace}/home VP_NU_VERSION=0.112.1 vp env setup --refresh`

VP_NU_VERSION keeps env.nu independent of the installed Nushell


## `vpt print-file home/env`
Expand Down Expand Up @@ -206,39 +208,39 @@ Nushell wrapper and vpr completion keep global -C before env use/run

```
# Vite+ environment setup (https://viteplus.dev)
$env.VP_HOME = ("<workspace>/home" | path expand --no-symlink)
$env.PATH = ($env.PATH | where { $in != "<workspace>/home/bin" and $in != "<workspace>/home/fallback-bin" } | prepend "<workspace>/home/bin" | append "<workspace>/home/fallback-bin")
$env.VP_HOME = ("<workspace>/home" | %path expand --no-symlink)
$env.PATH = ($env.PATH | where { $in != "<workspace>/home/bin" and $in != "<workspace>/home/fallback-bin" } | %prepend "<workspace>/home/bin" | %append "<workspace>/home/fallback-bin")

# Shell function wrapper: intercepts `vp env use` to parse its stdout,
# which sets/unsets VP_NODE_VERSION in the current shell session.
def --env --wrapped vp [...args: string@"nu-complete vp"] {
let command_args = if ($args | length) >= 2 and $args.0 == "-C" {
$args | skip 2
} else if ($args | length) >= 1 and ($args.0 | str starts-with "-C") and $args.0 != "-C" {
$args | skip 1
let command_args = if ($args | %length) >= 2 and $args.0 == "-C" {
$args | %skip 2
} else if ($args | %length) >= 1 and ($args.0 | %str starts-with "-C") and $args.0 != "-C" {
$args | %skip 1
} else {
$args
}
if ($command_args | length) >= 2 and $command_args.0 == "env" and $command_args.1 == "use" {
if ($command_args | %length) >= 2 and $command_args.0 == "env" and $command_args.1 == "use" {
if ("-h" in $args) or ("--help" in $args) {
^vp ...$args
return
}
let out = (with-env { VP_ENV_USE_EVAL_ENABLE: "1", VP_SHELL: "nu" } {
let out = (%with-env { VP_ENV_USE_EVAL_ENABLE: "1", VP_SHELL: "nu" } {
^vp ...$args
})
let lines = ($out | lines)
let exports = ($lines | where { $in =~ '^\$env\.' } | parse '$env.{key} = "{value}"')
let export_keys = ($exports | get key? | default [])
let lines = ($out | %lines)
let exports = ($lines | where { $in =~ '^\$env\.' } | %parse '$env.{key} = "{value}"')
let export_keys = ($exports | %get key? | %default [])
# Exclude keys that also appear in exports: when vp emits `hide-env X` then
# `$env.X = "v"` (e.g. `vp env use` with no args resolving from .node-version),
# the set should win.
let unsets = ($lines | where { $in =~ '^hide-env ' } | parse 'hide-env {key}' | get key? | default [] | where { $in not-in $export_keys })
if ($exports | is-not-empty) {
load-env ($exports | reduce -f {} {|it, acc| $acc | insert $it.key $it.value})
let unsets = ($lines | where { $in =~ '^hide-env ' } | %parse 'hide-env {key}' | %get key? | %default [] | where { $in not-in $export_keys })
if ($exports | %is-not-empty) {
%load-env ($exports | %reduce -f {} {|it, acc| $acc | %insert $it.key $it.value})
}
for key in $unsets {
if ($key in $env) { hide-env $key }
if ($key in $env) { %hide-env $key }
}
} else {
^vp ...$args
Expand All @@ -248,33 +250,33 @@ def --env --wrapped vp [...args: string@"nu-complete vp"] {
# Shell completion for nushell (delegates to fish completions dynamically)
def "nu-complete vp" [context: string] {
let fish_cmd = $"VP_COMPLETE=fish command vp | source; complete '--do-complete=($context)'"
fish --command $fish_cmd | from tsv --flexible --noheaders --no-infer | rename value description | update value {|row|
^fish --command $fish_cmd | %from tsv --flexible --noheaders --no-infer | %rename value description | %update value {|row|
let value = $row.value
let need_quote = ['\' ',' '[' ']' '(' ')' ' ' '\t' "'" '"' "`"] | any {$in in $value}
if ($need_quote and ($value | path exists)) {
let expanded_path = if ($value starts-with ~) {$value | path expand --no-symlink} else {$value}
$'"($expanded_path | str replace --all "\"" "\\\"")"'
let need_quote = ['\' ',' '[' ']' '(' ')' ' ' '\t' "'" '"' "`"] | %any {$in in $value}
if ($need_quote and ($value | %path exists)) {
let expanded_path = if ($value starts-with ~) {$value | %path expand --no-symlink} else {$value}
$'"($expanded_path | %str replace --all "\"" "\\\"")"'
} else {$value}
}
}
# Completion logic for vpr (translates context to 'vp run ...')
def "nu-complete vpr" [context: string] {
let modified_context = if ($context =~ '^vpr(?<cwd>\s+-C\s+(?:"[^"]*"|\x27[^\x27]*\x27|\S+))\s') {
$context | str replace -r '^vpr(?<cwd>\s+-C\s+(?:"[^"]*"|\x27[^\x27]*\x27|\S+))\s' 'vp$cwd run '
$context | %str replace -r '^vpr(?<cwd>\s+-C\s+(?:"[^"]*"|\x27[^\x27]*\x27|\S+))\s' 'vp$cwd run '
} else if ($context =~ '^vpr(?<cwd>\s+-C=?(?:"[^"]*"|\x27[^\x27]*\x27|\S+))\s') {
$context | str replace -r '^vpr(?<cwd>\s+-C=?(?:"[^"]*"|\x27[^\x27]*\x27|\S+))\s' 'vp$cwd run '
$context | %str replace -r '^vpr(?<cwd>\s+-C=?(?:"[^"]*"|\x27[^\x27]*\x27|\S+))\s' 'vp$cwd run '
} else if ($context =~ '^vpr\s+-C') {
$context | str replace -r '^vpr' 'vp'
$context | %str replace -r '^vpr' 'vp'
} else {
$context | str replace -r '^vpr' 'vp run'
$context | %str replace -r '^vpr' 'vp run'
}
let fish_cmd = $"VP_COMPLETE=fish command vp | source; complete '--do-complete=($modified_context)'"
fish --command $fish_cmd | from tsv --flexible --noheaders --no-infer | rename value description | update value {|row|
^fish --command $fish_cmd | %from tsv --flexible --noheaders --no-infer | %rename value description | %update value {|row|
let value = $row.value
let need_quote = ['\' ',' '[' ']' '(' ')' ' ' '\t' "'" '"' "`"] | any {$in in $value}
if ($need_quote and ($value | path exists)) {
let expanded_path = if ($value starts-with ~) {$value | path expand --no-symlink} else {$value}
$'"($expanded_path | str replace --all "\"" "\\\"")"'
let need_quote = ['\' ',' '[' ']' '(' ')' ' ' '\t' "'" '"' "`"] | %any {$in in $value}
if ($need_quote and ($value | %path exists)) {
let expanded_path = if ($value starts-with ~) {$value | %path expand --no-symlink} else {$value}
$'"($expanded_path | %str replace --all "\"" "\\\"")"'
} else {$value}
}
}
Expand Down
Loading
Loading