diff --git a/crates/nu-std/src/lib.rs b/crates/nu-std/src/lib.rs index 4932425175..088cff7e55 100644 --- a/crates/nu-std/src/lib.rs +++ b/crates/nu-std/src/lib.rs @@ -19,16 +19,18 @@ pub fn load_standard_library( let mut std_files = vec![ ("mod.nu", include_str!("../std/mod.nu")), ("core.nu", include_str!("../std/core.nu")), + ("assert.nu", include_str!("../std/assert.nu")), + ("bench.nu", include_str!("../std/bench.nu")), ("dirs.nu", include_str!("../std/dirs.nu")), ("dt.nu", include_str!("../std/dt.nu")), + ("formats.nu", include_str!("../std/formats.nu")), ("help.nu", include_str!("../std/help.nu")), + ("input.nu", include_str!("../std/input.nu")), ("iter.nu", include_str!("../std/iter.nu")), ("log.nu", include_str!("../std/log.nu")), - ("assert.nu", include_str!("../std/assert.nu")), - ("xml.nu", include_str!("../std/xml.nu")), - ("input.nu", include_str!("../std/input.nu")), ("math.nu", include_str!("../std/math.nu")), - ("formats.nu", include_str!("../std/formats.nu")), + ("util.nu", include_str!("../std/util.nu")), + ("xml.nu", include_str!("../std/xml.nu")), ]; let mut working_set = StateWorkingSet::new(engine_state); diff --git a/crates/nu-std/std/bench.nu b/crates/nu-std/std/bench.nu new file mode 100644 index 0000000000..61baa21a2f --- /dev/null +++ b/crates/nu-std/std/bench.nu @@ -0,0 +1,71 @@ +# run a piece of `nushell` code multiple times and measure the time of execution. +# +# this command returns a benchmark report of the following form: +# ``` +# record< +# mean: duration +# std: duration +# times: list +# > +# ``` +# +# > **Note** +# > `std bench --pretty` will return a `string`. +# +# # Examples +# measure the performance of simple addition +# > std bench { 1 + 2 } -n 10 | table -e +# ╭───────┬────────────────────╮ +# │ mean │ 4µs 956ns │ +# │ std │ 4µs 831ns │ +# │ │ ╭───┬────────────╮ │ +# │ times │ │ 0 │ 19µs 402ns │ │ +# │ │ │ 1 │ 4µs 322ns │ │ +# │ │ │ 2 │ 3µs 352ns │ │ +# │ │ │ 3 │ 2µs 966ns │ │ +# │ │ │ 4 │ 3µs │ │ +# │ │ │ 5 │ 3µs 86ns │ │ +# │ │ │ 6 │ 3µs 84ns │ │ +# │ │ │ 7 │ 3µs 604ns │ │ +# │ │ │ 8 │ 3µs 98ns │ │ +# │ │ │ 9 │ 3µs 653ns │ │ +# │ │ ╰───┴────────────╯ │ +# ╰───────┴────────────────────╯ +# +# get a pretty benchmark report +# > std bench { 1 + 2 } --pretty +# 3µs 125ns +/- 2µs 408ns +export def main [ + code: closure # the piece of `nushell` code to measure the performance of + --rounds (-n): int = 50 # the number of benchmark rounds (hopefully the more rounds the less variance) + --verbose (-v) # be more verbose (namely prints the progress) + --pretty # shows the results in human-readable format: " +/- " +] { + let times = ( + seq 1 $rounds | each {|i| + if $verbose { print -n $"($i) / ($rounds)\r" } + timeit { do $code } | into int | into float + } + ) + + if $verbose { print $"($rounds) / ($rounds)" } + + let report = { + mean: ($times | math avg | from ns) + min: ($times | math min | from ns) + max: ($times | math max | from ns) + std: ($times | math stddev | from ns) + times: ($times | each { from ns }) + } + + if $pretty { + $"($report.mean) +/- ($report.std)" + } else { + $report + } +} + +# convert an integer amount of nanoseconds to a real duration +def "from ns" [] { + [$in "ns"] | str join | into duration +} \ No newline at end of file diff --git a/crates/nu-std/std/mod.nu b/crates/nu-std/std/mod.nu index 6e46c15306..ab42a17e4a 100644 --- a/crates/nu-std/std/mod.nu +++ b/crates/nu-std/std/mod.nu @@ -1,6 +1,7 @@ # std.nu, `used` to load all standard library components export module core.nu +export module bench.nu export module assert.nu export module dirs.nu export module dt.nu @@ -10,205 +11,9 @@ export module input.nu export module iter.nu export module log.nu export module math.nu +export module util.nu export module xml.nu export-env { use dirs.nu [] use log.nu [] -} - -# 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 equal $env.PATH ["bar" "baz" "foo" "fooo"] -# -# print (std path add "returned" --ret) -# } -# ╭───┬──────────╮ -# │ 0 │ returned │ -# │ 1 │ bar │ -# │ 2 │ baz │ -# │ 3 │ foo │ -# │ 4 │ fooo │ -# ╰───┴──────────╯ -# ``` -# - adding paths based on the operating system -# ```nushell -# >_ std path add {linux: "foo", windows: "bar", darwin: "baz"} -# ``` -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 span = (metadata $paths).span - let paths = $paths | flatten - - if ($paths | is-empty) or ($paths | length) == 0 { - error make {msg: "Empty input", label: { - text: "Provide at least one string or a record", - span: $span - }} - } - - let path_name = if "PATH" in $env { "PATH" } else { "Path" } - - let paths = $paths | each {|p| - let p = match ($p | describe | str replace --regex '<.*' '') { - "string" => $p, - "record" => { $p | get --ignore-errors $nu.os-info.name }, - } - - $p | path expand --no-symlink - } - - if null in $paths or ($paths | is-empty) { - error make {msg: "Empty input", label: { - text: $"Received a record, that does not contain a ($nu.os-info.name) key", - span: $span - }} - } - - load-env {$path_name: ( - $env - | get $path_name - | split row (char esep) - | if $append { append $paths } else { prepend $paths } - )} - - if $ret { - $env | get $path_name - } -} - -# convert an integer amount of nanoseconds to a real duration -def "from ns" [] { - [$in "ns"] | str join | into duration -} - -# run a piece of `nushell` code multiple times and measure the time of execution. -# -# this command returns a benchmark report of the following form: -# ``` -# record< -# mean: duration -# std: duration -# times: list -# > -# ``` -# -# > **Note** -# > `std bench --pretty` will return a `string`. -# -# # Examples -# measure the performance of simple addition -# > std bench { 1 + 2 } -n 10 | table -e -# ╭───────┬────────────────────╮ -# │ mean │ 4µs 956ns │ -# │ std │ 4µs 831ns │ -# │ │ ╭───┬────────────╮ │ -# │ times │ │ 0 │ 19µs 402ns │ │ -# │ │ │ 1 │ 4µs 322ns │ │ -# │ │ │ 2 │ 3µs 352ns │ │ -# │ │ │ 3 │ 2µs 966ns │ │ -# │ │ │ 4 │ 3µs │ │ -# │ │ │ 5 │ 3µs 86ns │ │ -# │ │ │ 6 │ 3µs 84ns │ │ -# │ │ │ 7 │ 3µs 604ns │ │ -# │ │ │ 8 │ 3µs 98ns │ │ -# │ │ │ 9 │ 3µs 653ns │ │ -# │ │ ╰───┴────────────╯ │ -# ╰───────┴────────────────────╯ -# -# get a pretty benchmark report -# > std bench { 1 + 2 } --pretty -# 3µs 125ns +/- 2µs 408ns -export def bench [ - code: closure # the piece of `nushell` code to measure the performance of - --rounds (-n): int = 50 # the number of benchmark rounds (hopefully the more rounds the less variance) - --verbose (-v) # be more verbose (namely prints the progress) - --pretty # shows the results in human-readable format: " +/- " -] { - let times = ( - seq 1 $rounds | each {|i| - if $verbose { print -n $"($i) / ($rounds)\r" } - timeit { do $code } | into int | into float - } - ) - - if $verbose { print $"($rounds) / ($rounds)" } - - let report = { - mean: ($times | math avg | from ns) - min: ($times | math min | from ns) - max: ($times | math max | from ns) - std: ($times | math stddev | from ns) - times: ($times | each { from ns }) - } - - if $pretty { - $"($report.mean) +/- ($report.std)" - } else { - $report - } -} - -# the cute and friendly mascot of Nushell :) -export def ellie [] { - let ellie = [ - " __ ,", - " .--()°'.'", - "'|, . ,'", - " !_-(_\\", - ] - - $ellie | str join "\n" | $"(ansi green)($in)(ansi reset)" -} - -# repeat anything a bunch of times, yielding a list of *n* times the input -# -# # Examples -# repeat a string -# > "foo" | std repeat 3 | str join -# "foofoofoo" -export def repeat [ - n: int # the number of repetitions, must be positive -]: any -> list { - let item = $in - - if $n < 0 { - let span = metadata $n | get span - error make { - msg: $"(ansi red_bold)invalid_argument(ansi reset)" - label: { - text: $"n should be a positive integer, found ($n)" - span: $span - } - } - } - - if $n == 0 { - return [] - } - - 1..$n | each { $item } -} - -# return a null device file. -# -# # Examples -# run a command and ignore it's stderr output -# > cat xxx.txt e> (null-device) -export def null-device []: nothing -> path { - if ($nu.os-info.name | str downcase) == "windows" { - '\\.\NUL' - } else { - "/dev/null" - } -} +} \ No newline at end of file diff --git a/crates/nu-std/std/util.nu b/crates/nu-std/std/util.nu new file mode 100644 index 0000000000..c6b332c396 --- /dev/null +++ b/crates/nu-std/std/util.nu @@ -0,0 +1,124 @@ +# 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 equal $env.PATH ["bar" "baz" "foo" "fooo"] +# +# print (std path add "returned" --ret) +# } +# ╭───┬──────────╮ +# │ 0 │ returned │ +# │ 1 │ bar │ +# │ 2 │ baz │ +# │ 3 │ foo │ +# │ 4 │ fooo │ +# ╰───┴──────────╯ +# ``` +# - adding paths based on the operating system +# ```nushell +# >_ std path add {linux: "foo", windows: "bar", darwin: "baz"} +# ``` +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 span = (metadata $paths).span + let paths = $paths | flatten + + if ($paths | is-empty) or ($paths | length) == 0 { + error make {msg: "Empty input", label: { + text: "Provide at least one string or a record", + span: $span + }} + } + + let path_name = if "PATH" in $env { "PATH" } else { "Path" } + + let paths = $paths | each {|p| + let p = match ($p | describe | str replace --regex '<.*' '') { + "string" => $p, + "record" => { $p | get --ignore-errors $nu.os-info.name }, + } + + $p | path expand --no-symlink + } + + if null in $paths or ($paths | is-empty) { + error make {msg: "Empty input", label: { + text: $"Received a record, that does not contain a ($nu.os-info.name) key", + span: $span + }} + } + + load-env {$path_name: ( + $env + | get $path_name + | split row (char esep) + | if $append { append $paths } else { prepend $paths } + )} + + if $ret { + $env | get $path_name + } +} + +# the cute and friendly mascot of Nushell :) +export def ellie [] { + let ellie = [ + " __ ,", + " .--()°'.'", + "'|, . ,'", + " !_-(_\\", + ] + + $ellie | str join "\n" | $"(ansi green)($in)(ansi reset)" +} + +# repeat anything a bunch of times, yielding a list of *n* times the input +# +# # Examples +# repeat a string +# > "foo" | std repeat 3 | str join +# "foofoofoo" +export def repeat [ + n: int # the number of repetitions, must be positive +]: any -> list { + let item = $in + + if $n < 0 { + let span = metadata $n | get span + error make { + msg: $"(ansi red_bold)invalid_argument(ansi reset)" + label: { + text: $"n should be a positive integer, found ($n)" + span: $span + } + } + } + + if $n == 0 { + return [] + } + + 1..$n | each { $item } +} + +# return a null device file. +# +# # Examples +# run a command and ignore it's stderr output +# > cat xxx.txt e> (null-device) +export def null-device []: nothing -> path { + if ($nu.os-info.name | str downcase) == "windows" { + '\\.\NUL' + } else { + "/dev/null" + } +} diff --git a/crates/nu-std/tests/test_std.nu b/crates/nu-std/tests/test_util.nu similarity index 75% rename from crates/nu-std/tests/test_std.nu rename to crates/nu-std/tests/test_util.nu index cdf6823111..ad7c435e47 100644 --- a/crates/nu-std/tests/test_std.nu +++ b/crates/nu-std/tests/test_util.nu @@ -1,4 +1,4 @@ -use std +use std util #[test] def path_add [] { @@ -11,19 +11,19 @@ def path_add [] { assert equal (get_path) [] - std path add "/foo/" + util path add "/foo/" assert equal (get_path) (["/foo/"] | path expand) - std path add "/bar/" "/baz/" + util path add "/bar/" "/baz/" assert equal (get_path) (["/bar/", "/baz/", "/foo/"] | path expand) load-env {$path_name: []} - std path add "foo" - std path add "bar" "baz" --append + util path add "foo" + util path add "bar" "baz" --append assert equal (get_path) (["foo", "bar", "baz"] | path expand) - assert equal (std path add "fooooo" --ret) (["fooooo", "foo", "bar", "baz"] | path expand) + assert equal (util path add "fooooo" --ret) (["fooooo", "foo", "bar", "baz"] | path expand) assert equal (get_path) (["fooooo", "foo", "bar", "baz"] | path expand) load-env {$path_name: []} @@ -35,11 +35,11 @@ def path_add [] { android: "quux", } - std path add $target_paths + util path add $target_paths assert equal (get_path) ([($target_paths | get $nu.os-info.name)] | path expand) load-env {$path_name: [$"(["/foo", "/bar"] | path expand | str join (char esep))"]} - std path add "~/foo" + util path add "~/foo" assert equal (get_path) (["~/foo", "/foo", "/bar"] | path expand) } } @@ -63,7 +63,7 @@ def path_add_expand [] { with-env {$path_name: []} { def get_path [] { $env | get $path_name } - std path add $link_dir + util path add $link_dir assert equal (get_path) ([$link_dir]) } @@ -72,11 +72,12 @@ def path_add_expand [] { #[test] def repeat_things [] { - std assert error { "foo" | std repeat -1 } + use std assert + assert error { "foo" | util repeat -1 } for x in ["foo", [1 2], {a: 1}] { - std assert equal ($x | std repeat 0) [] - std assert equal ($x | std repeat 1) [$x] - std assert equal ($x | std repeat 2) [$x $x] + assert equal ($x | util repeat 0) [] + assert equal ($x | util repeat 1) [$x] + assert equal ($x | util repeat 2) [$x $x] } }