add `dirs` command to std lib (#8368)
# Description
Prototype replacement for `enter`, `n`, `p`, `exit` built-ins
implemented as scripts in standard library.
MVP-level capabilities (rough hack), for feedback please. Not intended
to merge and ship as is.
_(Description of your pull request goes here. **Provide examples and/or
screenshots** if your changes affect the user experience.)_
# User-Facing Changes
New command in standard library
```nushell
〉use ~/src/rust/nushell/crates/nu-utils/standard_library/dirs.nu
---------------------------------------------- /home/bobhy ----------------------------------------------
〉help dirs
module dirs.nu -- maintain list of remembered directories + navigate them
todo:
* expand relative to absolute paths (or relative to some prefix?)
* what if user does `cd` by hand?
Module: dirs
Exported commands:
add (dirs add), drop, next (dirs next), prev (dirs prev), show (dirs show)
This module exports environment.
---------------------------------------------- /home/bobhy ----------------------------------------------
〉dirs add ~/src/rust/nushell /etc ~/.cargo
-------------------------------------- /home/bobhy/src/rust/nushell --------------------------------------
〉dirs next 2
------------------------------------------- /home/bobhy/.cargo -------------------------------------------
〉dirs show
╭───┬─────────┬────────────────────╮
│ # │ current │ path │
├───┼─────────┼────────────────────┤
│ 0 │ │ /home/bobhy │
│ 1 │ │ ~/src/rust/nushell │
│ 2 │ │ /etc │
│ 3 │ ==> │ ~/.cargo │
╰───┴─────────┴────────────────────╯
------------------------------------------- /home/bobhy/.cargo -------------------------------------------
〉dirs drop
---------------------------------------------- /home/bobhy ----------------------------------------------
〉dirs show
╭───┬─────────┬────────────────────╮
│ # │ current │ path │
├───┼─────────┼────────────────────┤
│ 0 │ ==> │ /home/bobhy │
│ 1 │ │ ~/src/rust/nushell │
│ 2 │ │ /etc │
╰───┴─────────┴────────────────────╯
---------------------------------------------- /home/bobhy ----------------------------------------------
〉
```
# Tests + Formatting
Haven't even looked at stdlib `tests.nu` yet.
Other todos:
* address module todos.
* integrate into std lib, rather than as standalone module. Somehow
arrange for `use .../standard_library/std.nu` to load this module
without having to put all the source in `std.nu`?
* Maybe command should be `std dirs ...`?
* what else do `enter` and `exit` do that this should do? Then deprecate
those commands.
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass
# After Submitting
If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
2023-03-11 22:31:09 +00:00
|
|
|
|
# std.nu, `used` to load all standard library components
|
|
|
|
|
|
|
|
|
|
# ----------- sub modules to be loaded as part of stdlib ------------------
|
|
|
|
|
# (choose flavor of import that puts your functions in the right namespace)
|
|
|
|
|
# This imports into std top-level namespace: std <subcommand>
|
|
|
|
|
# export use dirs.nu *
|
|
|
|
|
# This imports into std *sub* namespace: std dirs <subcommand>
|
|
|
|
|
# export use dirs.nu
|
|
|
|
|
# You could also advise the user to `use` your submodule directly
|
|
|
|
|
# to put the subcommands at the top level: dirs <subcommand>
|
|
|
|
|
|
|
|
|
|
export use dirs.nu
|
|
|
|
|
# the directory stack -- export-env from submodule doesn't work?
|
|
|
|
|
export-env {
|
|
|
|
|
let-env DIRS_POSITION = 0
|
|
|
|
|
let-env DIRS_LIST = [($env.PWD | path expand)]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# ---------------- builtin std functions --------------------
|
|
|
|
|
|
2023-02-27 23:52:47 +00:00
|
|
|
|
def _assert [
|
|
|
|
|
cond: bool
|
|
|
|
|
msg: string
|
|
|
|
|
] {
|
|
|
|
|
if not $cond {
|
|
|
|
|
error make {msg: $msg}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# ```nushell
|
|
|
|
|
# >_ assert ($a == 3)
|
|
|
|
|
# >_ assert ($a != 3)
|
|
|
|
|
# Error:
|
|
|
|
|
# × condition given to `assert` does not hold
|
|
|
|
|
# ╭─[entry #12:5:1]
|
|
|
|
|
# 5 │ if not $cond {
|
|
|
|
|
# 6 │ error make {msg: $msg}
|
|
|
|
|
# · ─────┬────
|
|
|
|
|
# · ╰── originates from here
|
|
|
|
|
# 7 │ }
|
|
|
|
|
# ╰────
|
|
|
|
|
# ```
|
|
|
|
|
export def assert [cond: bool] {
|
|
|
|
|
_assert $cond "condition given to `assert` does not hold"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# ```nushell
|
|
|
|
|
# >_ assert_eq $a "a string"
|
|
|
|
|
# Error:
|
|
|
|
|
# × left and right operand of `assert eq` should have the same type
|
|
|
|
|
# ╭─[entry #12:5:1]
|
|
|
|
|
# 5 │ if not $cond {
|
|
|
|
|
# 6 │ error make {msg: $msg}
|
|
|
|
|
# · ─────┬────
|
|
|
|
|
# · ╰── originates from here
|
|
|
|
|
# 7 │ }
|
|
|
|
|
# ╰────
|
|
|
|
|
#
|
|
|
|
|
# >_ assert_eq $a 3
|
|
|
|
|
# >_ assert_eq $a 1
|
|
|
|
|
# Error:
|
|
|
|
|
# × left is not equal to right
|
|
|
|
|
# ╭─[entry #12:5:1]
|
|
|
|
|
# 5 │ if not $cond {
|
|
|
|
|
# 6 │ error make {msg: $msg}
|
|
|
|
|
# · ─────┬────
|
|
|
|
|
# · ╰── originates from here
|
|
|
|
|
# 7 │ }
|
|
|
|
|
# ╰────
|
|
|
|
|
# ```
|
|
|
|
|
export def "assert eq" [left: any, right: any] {
|
|
|
|
|
_assert (($left | describe) == ($right | describe)) $"left and right operand of `assert eq` should have the same type"
|
|
|
|
|
_assert ($left == $right) "left is not equal to right"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# ```nushell
|
|
|
|
|
# >_ assert_ne $a "a string"
|
|
|
|
|
# Error:
|
|
|
|
|
# × left and right operand of `assert eq` should have the same type
|
|
|
|
|
# ╭─[entry #12:5:1]
|
|
|
|
|
# 5 │ if not $cond {
|
|
|
|
|
# 6 │ error make {msg: $msg}
|
|
|
|
|
# · ─────┬────
|
|
|
|
|
# · ╰── originates from here
|
|
|
|
|
# 7 │ }
|
|
|
|
|
# ╰────
|
|
|
|
|
#
|
|
|
|
|
# >_ assert_ne $a 1
|
|
|
|
|
# >_ assert_ne $a 3
|
|
|
|
|
# Error:
|
|
|
|
|
# × left is equal to right
|
|
|
|
|
# ╭─[entry #12:5:1]
|
|
|
|
|
# 5 │ if not $cond {
|
|
|
|
|
# 6 │ error make {msg: $msg}
|
|
|
|
|
# · ─────┬────
|
|
|
|
|
# · ╰── originates from here
|
|
|
|
|
# 7 │ }
|
|
|
|
|
# ╰────
|
|
|
|
|
# ```
|
|
|
|
|
export def "assert ne" [left: any, right: any] {
|
|
|
|
|
_assert (($left | describe) == ($right | describe)) $"left and right operand of `assert eq` should have the same type"
|
|
|
|
|
_assert ($left != $right) "left is equal to right"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# ```nushell
|
|
|
|
|
# >_ let branches = {
|
|
|
|
|
# ))) 1: { print "this is the 1st branch"}
|
|
|
|
|
# ))) 2: { print "this is the 2nd branch" }
|
|
|
|
|
# ))) 3: { print "this is the 3rd branch" }
|
|
|
|
|
# ))) 4: { print "this is the 4th branch" }
|
|
|
|
|
# ))) }
|
|
|
|
|
#
|
|
|
|
|
# >_ match 1 $branches
|
|
|
|
|
# ))) match 2 $branches
|
|
|
|
|
# ))) match 3 $branches
|
|
|
|
|
# ))) match 4 $branches
|
|
|
|
|
# ))) match 5 $branches
|
|
|
|
|
# this is the 1st branch
|
|
|
|
|
# this is the 2nd branch
|
|
|
|
|
# this is the 3rd branch
|
|
|
|
|
# this is the 4th branch
|
|
|
|
|
#
|
|
|
|
|
# >_ match 1 $branches { "this is the default branch" }
|
|
|
|
|
# ))) match 2 $branches { "this is the default branch" }
|
|
|
|
|
# ))) match 3 $branches { "this is the default branch" }
|
|
|
|
|
# ))) match 4 $branches { "this is the default branch" }
|
|
|
|
|
# ))) match 5 $branches { "this is the default branch" }
|
|
|
|
|
# this is the 1st branch
|
|
|
|
|
# this is the 2nd branch
|
|
|
|
|
# this is the 3rd branch
|
|
|
|
|
# this is the 4th branch
|
|
|
|
|
# this is the default branch
|
|
|
|
|
# ```
|
|
|
|
|
export def match [
|
|
|
|
|
input:string
|
|
|
|
|
matchers:record
|
|
|
|
|
default?: block
|
|
|
|
|
] {
|
|
|
|
|
if (($matchers | get -i $input) != null) {
|
|
|
|
|
$matchers | get $input | do $in
|
|
|
|
|
} else if ($default != null) {
|
|
|
|
|
do $default
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-03-07 23:06:14 +00:00
|
|
|
|
|
|
|
|
|
# Add the given paths to the PATH.
|
|
|
|
|
#
|
|
|
|
|
# # Example
|
|
|
|
|
# - adding some dummy paths to an empty PATH
|
|
|
|
|
# ```nushell
|
|
|
|
|
# >_ with-env [PATH []] {
|
|
|
|
|
# std path add "foo"
|
|
|
|
|
# std path add "bar" "baz"
|
|
|
|
|
# std path add "fooo" --append
|
|
|
|
|
#
|
|
|
|
|
# assert eq $env.PATH ["bar" "baz" "foo" "fooo"]
|
|
|
|
|
#
|
|
|
|
|
# print (std path add "returned" --ret)
|
|
|
|
|
# }
|
|
|
|
|
# ╭───┬──────────╮
|
|
|
|
|
# │ 0 │ returned │
|
|
|
|
|
# │ 1 │ bar │
|
|
|
|
|
# │ 2 │ baz │
|
|
|
|
|
# │ 3 │ foo │
|
|
|
|
|
# │ 4 │ fooo │
|
|
|
|
|
# ╰───┴──────────╯
|
|
|
|
|
# ```
|
|
|
|
|
export def-env "path add" [
|
|
|
|
|
--ret (-r) # return $env.PATH, useful in pipelines to avoid scoping.
|
|
|
|
|
--append (-a) # append to $env.PATH instead of prepending to.
|
|
|
|
|
...paths # the paths to add to $env.PATH.
|
|
|
|
|
] {
|
|
|
|
|
let-env PATH = (
|
|
|
|
|
$env.PATH
|
|
|
|
|
| if $append { append $paths }
|
|
|
|
|
else { prepend $paths }
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if $ret {
|
|
|
|
|
$env.PATH
|
|
|
|
|
}
|
|
|
|
|
}
|