Open Tarnadas opened 3 years ago
It's enough for basic usage. But if we want --use-on-cd
we might want to add functions or whatever it is called in nushell. I really want to try nushell again so it might be a nice experiment ๐
In the meanwhile - you can get the path edit via:
/home/orta> fnm env | lines | split column '"' | first | get Column2
/tmp/fnm_multishells/10174_1623514914978/bin
Then the rest of the env vars via:
fnm env | str find-replace -a "export " '' | str find-replace -a '"' '' | lines | split column = | rename name value | last 5
โโโโฌโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# โ name โ value
โโโโผโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
0 โ FNM_MULTISHELL_PATH โ "/tmp/fnm_multishells/10210_1623514981704"
1 โ FNM_DIR โ "/home/orta/.fnm"
2 โ FNM_LOGLEVEL โ "info"
3 โ FNM_NODE_DIST_MIRROR โ "https://nodejs.org/dist"
4 โ FNM_ARCH โ "x64"
โโโโดโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
So to mix it all together:
#Update paths
echo $nu.path | append (fnm env | lines | split column '"' | first | get Column2) | config set_into path
# Add env vars
fnm env | str find-replace -a "export " '' | str find-replace -a '"' '' | lines | split column = | rename name value | last 5 | load-env
And at least from some current messing around it seems to work
Nushell added pathvar command for dynamic path updates. To make work fnm in nushell, add these two commands in the startup:
#load env variables
fnm env --shell bash | lines | last 5 | str find-replace 'export ' '' | str find-replace -a '"' '' | split column = | rename name value | load-env
#add dynamic fnm path
pathvar add $nu.env.FNM_MULTISHELL_PATH
Info: Requires nushell v0.34+ (pathvar command is supported only with v0.34 and above)
I had to change the path like this:
pathvar add ($nu.env.FNM_MULTISHELL_PATH + /bin)
Nushell has from json
so a quick easy way to support this and other experimental shells would be to expose environment variables as a simple JSON object.
I made a super quick Go program for this: https://github.com/Southclaws/fnm-nushell
Install with go install github.com/Southclaws/fnm-nushell@latest
then run a short pipeline: fnm env --shell powershell | fnm-nushell | from json | load-env
in your nushell config.
This is the code I added to my env.nu using nushell 0.61.0 that works:
#load env variables
load-env (fnm env --shell bash | lines | str replace 'export ' '' | str replace -a '"' '' | split column = | rename name value | where name != "FNM_ARCH" && name != "PATH" | reduce -f {} {|it, acc| $acc | upsert $it.name $it.value })
#add dynamic fnm path
let-env PATH = $"($env.FNM_MULTISHELL_PATH)/bin:($env.PATH)"
This is my first experience with nu
, so it needs to be tested, but it seems to work:
# FNM
# load env variables
load-env (fnm env --shell bash | lines | str replace 'export ' '' | str replace -a '"' '' | split column = | rename name value | where name != "FNM_ARCH" && name != "PATH" | reduce -f {} {|it, acc| $acc | upsert $it.name $it.value })
# add dynamic fnm path
let-env PATH = ($env.PATH | prepend $"($env.FNM_MULTISHELL_PATH)/bin")
# add fnm with cd
def-env fnmcd [path: string] {
let-env PWD = ($path | path expand)
if (['.node-version' '.nvmrc'] | any? ($env.PWD | path join $it | path exists)) {
fnm use --silent-if-unchanged
}
}
alias cd = fnmcd
Could you at least add something like fnm env --json
with outputting only fnm related variables there (without modified PATH
that is)? In that case we could maintain fnm integration ourselves since nushell is constantly changing. I myself don't really need on-cd functionality and am using fnm as simple nodejs sdk manager.
This is the code I added to my env.nu using nushell 0.64.0 that works on WINDOWS:
# FNM for windows
# load env variables
load-env (fnm env --shell cmd | lines | str replace 'SET ' '' | split column = | rename name value | where name != "FNM_ARCH" && name != "PATH" | reduce -f {} {|it, acc| $acc | upsert $it.name $it.value })
# add dynamic fnm path
let-env Path = ($env.Path | prepend $env.FNM_MULTISHELL_PATH)
Nu has changed a lot. It is better now. Any plan for fnm to have built-in support for Nushell?
Current workaround inspired by https://github.com/Schniz/fnm/issues/463#issuecomment-1106868402: Nu 0.67.0, GNU/Linux.
# FNM config
# Parse FNM env from other supported shell. It result should looks like this:
# โ FNM_VERSION_FILE_STRATEGY โ local โ
# โ FNM_DIR โ /home/user/.fnm |
# Then load these value key pair to Nushell env
load-env (fnm env --shell bash | lines | str replace 'export ' '' | str replace -a '"' '' | split column = | rename name value | where name != "FNM_ARCH" && name != "PATH" | reduce -f {} {|it, acc| $acc | upsert $it.name $it.value })
# Add dynamic FNM path
let-env PATH = ($env.PATH | append [
$"($env.FNM_MULTISHELL_PATH)/bin"
])
It seems nushell support is on the way: #801
For the meantime the solution from @azzamsa works for me, but with prepend
in the PATH
setting.
Nushell has very handy hook feature that can be used to pick node version on directory change. I added this to my config.nu
:
let-env config = {
โฆ
hooks: {
env_change: {
PWD: [{|before, after|
if ([.nvmrc .node-version] | path exists | any? ($it == true)) {
fnm use
}
}]
}
}
โฆ
}
Now that #800 landed in 1.32.0, the setup for nu already got much nicer using the fnm env --json
command ๐
The PR mentions this script:
fnm env --json | from json | load-env let-env PATH = ($env.PATH | prepend ($env.FNM_MULTISHELL_PATH + "/bin"))
Personally I use this:
^fnm env --json | from json | load-env
let-env PATH = ([([$env.FNM_MULTISHELL_PATH "bin"] | path join) $env.PATH] | str join (char esep))
I concatenate the paths as strings, because this is part of my env.nu
where the $env.PATH
is not yet parsed as a nu list unless one manually did so. (And I like to rely on path join
for adding to a path)
Ok so, this is currently in my env.nu
, and seems to at least not have nushell 0.71 errors
# FNM
# load env variables
fnm env --json | from json | load-env
# add dynamic fnm path
let-env PATH = ($env.PATH | split row (char esep) | prepend ([$env.FNM_MULTISHELL_PATH "bin"] | path join))
# add fnm with cd
def-env fnmcd [path: string] {
let-env PWD = ($path | path expand)
if (['.node-version' '.nvmrc'] | any ($env.PWD | path join $it | path exists)) {
fnm use --silent-if-unchanged
}
}
alias cd = fnmcd
Ok so, this is currently in my
env.nu
, and seems to at least not have nushell 0.71 errors# FNM # load env variables fnm env --json | from json | load-env # add dynamic fnm path let-env PATH = ($env.PATH | split row (char esep) | prepend ([$env.FNM_MULTISHELL_PATH "bin"] | path join)) # add fnm with cd def-env fnmcd [path: string] { let-env PWD = ($path | path expand) if (['.node-version' '.nvmrc'] | any ($env.PWD | path join $it | path exists)) { fnm use --silent-if-unchanged } } alias cd = fnmcd
Updated the snippet to work under 0.72:
# FNM
# load env variables
fnm env --json | from json | load-env
# add dynamic fnm path
let-env PATH = ($env.PATH | split row (char esep) | prepend ([$env.FNM_MULTISHELL_PATH "bin"] | path join))
# add fnm with cd
def-env fnmcd [path?: string] {
if ($path == null) {
cd
} else {
cd ($path | path expand)
}
if (['.node-version' '.nvmrc'] | any ($env.PWD | path join $it | path exists)) {
fnm use --silent-if-unchanged
}
}
alias cd = fnmcd
Ok so, this is currently in my
env.nu
, and seems to at least not have nushell 0.71 errors# FNM # load env variables fnm env --json | from json | load-env # add dynamic fnm path let-env PATH = ($env.PATH | split row (char esep) | prepend ([$env.FNM_MULTISHELL_PATH "bin"] | path join)) # add fnm with cd def-env fnmcd [path: string] { let-env PWD = ($path | path expand) if (['.node-version' '.nvmrc'] | any ($env.PWD | path join $it | path exists)) { fnm use --silent-if-unchanged } } alias cd = fnmcd
Updated the snippet to work under 0.72:
# FNM # load env variables fnm env --json | from json | load-env # add dynamic fnm path let-env PATH = ($env.PATH | split row (char esep) | prepend ([$env.FNM_MULTISHELL_PATH "bin"] | path join)) # add fnm with cd def-env fnmcd [path?: string] { if ($path == null) { cd } else { cd ($path | path expand) } if (['.node-version' '.nvmrc'] | any ($env.PWD | path join $it | path exists)) { fnm use --silent-if-unchanged } } alias cd = fnmcd
Thank you for this, saved me a ton of time. Had to make these small changes for it to work for me on windows, but I can't say if it's correct or not confidently.
# FNM
# load env variables
fnm env --json | from json | load-env
# add dynamic fnm path
let-env Path = ($env.Path | split row (char esep) | prepend ([$env.FNM_MULTISHELL_PATH] | path join))
# add fnm with cd
def-env fnmcd [path?: string] {
if ($path == null) {
cd
} else {
cd ($path | path expand)
}
if (['.node-version' '.nvmrc'] | any ($env.PWD | path join $it | path exists)) {
fnm use --silent-if-unchanged
}
}
alias cd = fnmcd
Update for nushell v0.73:
It seems that $it
has been removed for any
, so any ($env.PWD | path join $it | path exists)
needs to be changed to any {|it| $env.PWD | path join $it | path exists}
.
We might be using too many unstable features of nushell in the script :joy:
That's why I simply wrote it in Go instead ๐
Full fnm script for nu 0.73
# FNM
# load env variables
fnm env --json | from json | load-env
# add dynamic fnm path
let-env PATH = ($env.PATH | split row (char esep) | prepend ([$env.FNM_MULTISHELL_PATH "bin"] | path join))
# add fnm with cd
def-env fnmcd [path?: string] {
if ($path == null) {
cd
} else {
cd ($path | path expand)
}
if (['.node-version' '.nvmrc'] | any {|it| $env.PWD | path join $it | path exists}) {
fnm use --silent-if-unchanged
}
}
alias cd = fnmcd
On mac I'm getting
65 โ # load env variables
66 โ fnm env --json | from json | load-env
ยท โโฌโ
ยท โฐโโ did you mean 'fnmcd'?
67 โ
โฐโโโโ
help: No such file or directory (os error 2)
How can I solve this? :D
@sr-mothership You need to have fnm in your PATH first. Add something like let-env PATH = ($env.PATH | split row (char esep) | prepend '/home/ubuntu/.cargo/bin')
(change the path to the directory of your fnm binary) before the snippet given above.
@sr-mothership You need to have fnm in your PATH first. Add something like
let-env PATH = ($env.PATH | split row (char esep) | prepend '/home/ubuntu/.cargo/bin')
(change the path to the directory of your fnm binary) before the snippet given above.
That is so weird, since I already have let-env PATH = ($env.PATH |split row ":"| prepend $"($env.HOME)/.cargo/bin")
in my config.nu ๐ค
@sr-mothership It should be in env.nu
instead. Both the let-env
command and the snippet above.
@sr-mothership It should be in
env.nu
instead. Both thelet-env
command and the snippet above.
Damn that solved it, haha. Thanks ๐
In Nushell 0.77, there is a breaking change related to the use of alias
. If you try to use the snippet above, it will break on aliasing cd
to the snippet. You can simply rename alias
to old-alias
, for the time being.
It seems nushell support is on the way: #801
For the meantime the solution from @azzamsa works for me, but with
prepend
in thePATH
setting.Nushell has very handy hook feature that can be used to pick node version on directory change. I added this to my
config.nu
:let-env config = { โฆ hooks: { env_change: { PWD: [{|before, after| if ([.nvmrc .node-version] | path exists | any? ($it == true)) { fnm use } }] } } โฆ }
For nu
0.79.1 I had to change the hook a little bit:
env_change: {
PWD: [{|before, after|
if ([.nvmrc .node-version] | path exists | any {|it| ($it == true)}) {
fnm use
}
}]
}
So to summarize:
add to env.nu
:
if not (which fnm | is-empty) {
^fnm env --json | from json | load-env
let-env PATH = ($env.PATH | prepend [
$"($env.FNM_MULTISHELL_PATH)/bin"
])
}
add to config.nu
:
let-env config = {
[โฆ]
hooks: {
[โฆ]
env_change: {
PWD: [{ |before, after|
if ('FNM_DIR' in $env) and ([.nvmrc .node-version] | path exists | any { |it| $it }) {
fnm use
}
}]
}
[โฆ]
}
[โฆ]
}
If you have fnm on every machine, you can leave out the not (which fnm | is-empty)
and 'FNM_DIR' in $env
checks.
For fnm
1.3.5 and nu
0.83:
# env.nu
if not (which fnm | is-empty) {
^fnm env --json | from json | load-env
# Checking `Path` for Windows
let path = if 'Path' in $env { $env.Path } else { $env.PATH }
let node_path = if (sys).host.name == 'Windows' {
$"($env.FNM_MULTISHELL_PATH)"
} else {
$"($env.FNM_MULTISHELL_PATH)/bin"
}
$env.PATH = ($path | prepend [ $node_path ])
}
# config.nu
$env.config = {
hooks: {
env_change: {
PWD: [{ |before, after|
if ('FNM_DIR' in $env) and ([.nvmrc .node-version] | path exists | any { |it| $it }) {
fnm use
}
}]
}
}
}
For
fnm
1.3.5 andnu
0.83:
@hustcer your solution works for me, but I always get this warning:
warning: The current Node.js path is not on your PATH environment variable.
You should setup your shell profile to evaluate `fnm env`, see https://github.com/Schniz/fnm#shell-setup on how to do this
Check out our documentation for more information: https://fnm.vercel.app```
@marcelarie It works for me, However, You can give this PR a try: https://github.com/nushell/nu_scripts/pull/593/files
use this: above v0.85 nushell
anywhere: fnm.nu
load-env (fnm env --shell bash | lines | str replace 'export ' '' | str replace -a '"' '' | split column = | rename name value | where name != "FNM_ARCH" and name != "PATH" | reduce -f {} {|it, acc| $acc | upsert $it.name $it.value })
# Add dynamic FNM path
$env.Path = ($env.Path | append [
$env.FNM_MULTISHELL_PATH
])
then source it in $nu.config-path
source /path/to/fnm.nu
use this: above v0.85 nushell anywhere: fnm.nu
load-env (fnm env --shell bash | lines | str replace 'export ' '' | str replace -a '"' '' | split column = | rename name value | where name != "FNM_ARCH" and name != "PATH" | reduce -f {} {|it, acc| $acc | upsert $it.name $it.value }) # Add dynamic FNM path $env.Path = ($env.Path | append [ $env.FNM_MULTISHELL_PATH ])
then source it in $nu.config-path
source /path/to/fnm.nu
Work for me.
But how to config for fnm use on cd?
For me, this works like a charm:
$env.config = {
hooks: {
env_change: {
PWD: [{ |before, after|
let is_node_dir = [.nvmrc .node-version] | path exists | any { |it| $it }
if ('FNM_DIR' in $env) and $is_node_dir {
fnm use # Personally I prefer to use fnm --log-level=quiet use
}
}]
}
}
}
if not (which fnm | is-empty) {
^fnm env --json | from json | load-env
# Checking `Path` for Windows
let path = if 'Path' in $env { $env.Path } else { $env.PATH }
let node_path = if (sys).host.name == 'Windows' {
$"($env.FNM_MULTISHELL_PATH)"
} else {
$"($env.FNM_MULTISHELL_PATH)/bin"
}
$env.PATH = ($path | prepend [ $node_path ])
}
A slight tweak to the if not
block from @marcelarie that I needed to change for my set up (on Windows).
if not (which fnm | is-empty) {
^fnm env --json | from json | load-env
let node_path = if (sys).host.name == 'Windows' {
$"($env.FNM_MULTISHELL_PATH)"
} else {
$"($env.FNM_MULTISHELL_PATH)/bin"
}
# Checking `Path` for Windows
if 'Path' in $env {
$env.Path = ($env.Path | split row (char esp) | prepend $node_path)
} else {
$env.PATH = ($env.PATH | split row (char esp) | prepend $node_path)
}
}
Of course, I only tried the Windows side. (And we could probably combine the two if-else blocks together.)
Edit: I added the split row
bit from the path configuration nushell docs
This could be simplified a bit further, no need for windows patch check in the end.
# File: config.nu
use std "path add"
if not (which fnm | is-empty) {
^fnm env --json | from json | load-env
let node_path = match $nu.os-info.name {
"windows" => $"($env.FNM_MULTISHELL_PATH)",
_ => $"($env.FNM_MULTISHELL_PATH)/bin",
}
path add $node_path
}
Another tweak to what @marcelarie provided. It seems that the solution was somehow conflicting with my existing config as the banner returned after having been set to False and all of my other custom hooks were no longer taking affect. So I went with this.
export-env {
$env.config = ($env.config | upsert hooks {
env_change: {
PWD: ($env.config.hooks.env_change.PWD ++
[{
condition: {|before, after| [.nvmrc .node-version] | path exists | any { |it| $it }}
code: {|before, after|
if ('FNM_DIR' in $env) {
fnm use # Personally I prefer to use fnm --log-level=quiet use
}
}
}]
)
}
})
}
if not (which fnm | is-empty) {
^fnm env --json | from json | load-env
# Checking `Path` for Windows
let path = if 'Path' in $env { $env.Path } else { $env.PATH }
let node_path = if (sys).host.name == 'Windows' {
$"($env.FNM_MULTISHELL_PATH)"
} else {
$"($env.FNM_MULTISHELL_PATH)/bin"
}
$env.PATH = ($path | prepend [ $node_path ])
}
@gclarkjr5 improvement - sys is deprecated.
(sys).host.name
can be updated to (sys host).name
if not (which fnm | is-empty) {
^fnm env --resolve-engines --corepack-enabled --json | from json | load-env
let node_path = match $nu.os-info.name {
"windows" => $"($env.FNM_MULTISHELL_PATH)",
_ => $"($env.FNM_MULTISHELL_PATH)/bin",
}
$env.PATH = ($env.PATH | prepend [ $node_path ])
}
$env.config = ($env.config | merge {
hooks: {
env_change: {
PWD: [{
if ([.nvmrc .node-version] | path exists | any { |it| $it }) {
fnm use
} else {
fnm --log-level=quiet use default
}
}]
}
}
})
Now that nushell has an eval-like mechanism for setting environment variables, Iโd like to open this feature request to also add support for it.
Via the
load-env
command, one can set multiple environment variables, see here: https://github.com/nushell/nushell/issues/3481Is that enough to make it possible or is something missing?