diff --git a/crates/nu-cli/src/repl.rs b/crates/nu-cli/src/repl.rs index 3e2b01cfd1..4ea650074e 100644 --- a/crates/nu-cli/src/repl.rs +++ b/crates/nu-cli/src/repl.rs @@ -159,7 +159,7 @@ pub fn evaluate_repl( eval_source( engine_state, &mut unique_stack, - r#"use std banner; banner"#.as_bytes(), + r#"banner"#.as_bytes(), "show_banner", PipelineData::empty(), false, diff --git a/crates/nu-protocol/src/engine/state_working_set.rs b/crates/nu-protocol/src/engine/state_working_set.rs index 5735684f19..8c500ddd65 100644 --- a/crates/nu-protocol/src/engine/state_working_set.rs +++ b/crates/nu-protocol/src/engine/state_working_set.rs @@ -1007,14 +1007,17 @@ impl<'a> StateWorkingSet<'a> { } pub fn find_virtual_path(&self, name: &str) -> Option<&VirtualPath> { + // Platform appropriate virtual path (slashes or backslashes) + let virtual_path_name = Path::new(name); + for (virtual_name, virtual_path) in self.delta.virtual_paths.iter().rev() { - if virtual_name == name { + if Path::new(virtual_name) == virtual_path_name { return Some(virtual_path); } } for (virtual_name, virtual_path) in self.permanent_state.virtual_paths.iter().rev() { - if virtual_name == name { + if Path::new(virtual_name) == virtual_path_name { return Some(virtual_path); } } diff --git a/crates/nu-std/src/lib.rs b/crates/nu-std/src/lib.rs index 67c12b735d..ec5ced55ec 100644 --- a/crates/nu-std/src/lib.rs +++ b/crates/nu-std/src/lib.rs @@ -9,30 +9,33 @@ use nu_protocol::{ }; use std::path::PathBuf; -// Virtual std directory unlikely to appear in user's file system -const NU_STDLIB_VIRTUAL_DIR: &str = "NU_STDLIB_VIRTUAL_DIR"; - pub fn load_standard_library( engine_state: &mut nu_protocol::engine::EngineState, ) -> Result<(), miette::ErrReport> { trace!("load_standard_library"); let (block, delta) = { - // Using full virtual path to avoid potential conflicts with user having 'std' directory - // in their working directory. - let std_dir = PathBuf::from(NU_STDLIB_VIRTUAL_DIR).join("std"); + let std_dir = PathBuf::from("std"); let mut std_files = vec![ + // Loaded at startup + ("core", include_str!("../std/core.nu")), + // std module - Loads all commands and submodules ("mod.nu", include_str!("../std/mod.nu")), - ("dirs.nu", include_str!("../std/dirs.nu")), - ("dt.nu", include_str!("../std/dt.nu")), - ("help.nu", include_str!("../std/help.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")), + // std submodules + ("assert", include_str!("../std/assert.nu")), + ("bench", include_str!("../std/bench.nu")), + ("dirs", include_str!("../std/dirs.nu")), + ("dt", include_str!("../std/dt.nu")), + ("formats", include_str!("../std/formats.nu")), + ("help", include_str!("../std/help.nu")), + ("input", include_str!("../std/input.nu")), + ("iter", include_str!("../std/iter.nu")), + ("log", include_str!("../std/log.nu")), + ("math", include_str!("../std/math.nu")), + ("lib", include_str!("../std/lib.nu")), + ("xml", include_str!("../std/xml.nu")), + // Remove in following release + ("deprecated_dirs", include_str!("../std/deprecated_dirs.nu")), ]; let mut working_set = StateWorkingSet::new(engine_state); @@ -52,11 +55,9 @@ pub fn load_standard_library( let std_dir = std_dir.to_string_lossy().to_string(); let source = r#" -# Define the `std` module -module std - # Prelude -use std dirs [ +use std/core * +use std/deprecated_dirs [ enter shells g @@ -64,14 +65,13 @@ use std dirs [ p dexit ] -use std pwd "#; let _ = working_set.add_virtual_path(std_dir, VirtualPath::Dir(std_virt_paths)); // Add a placeholder file to the stack of files being evaluated. // The name of this file doesn't matter; it's only there to set the current working directory to NU_STDLIB_VIRTUAL_DIR. - let placeholder = PathBuf::from(NU_STDLIB_VIRTUAL_DIR).join("loading stdlib"); + let placeholder = PathBuf::from("load std/core"); working_set.files = FileStack::with_file(placeholder); let block = parse( 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/core.nu b/crates/nu-std/std/core.nu new file mode 100644 index 0000000000..1a777bcd0f --- /dev/null +++ b/crates/nu-std/std/core.nu @@ -0,0 +1,33 @@ +use dt [datetime-diff, pretty-print-duration] + +# Print a banner for nushell with information about the project +export def banner [] { +let dt = (datetime-diff (date now) 2019-05-10T09:59:12-07:00) +$"(ansi green) __ ,(ansi reset) +(ansi green) .--\(\)°'.' (ansi reset)Welcome to (ansi green)Nushell(ansi reset), +(ansi green)'|, . ,' (ansi reset)based on the (ansi green)nu(ansi reset) language, +(ansi green) !_-\(_\\ (ansi reset)where all data is structured! + +Please join our (ansi purple)Discord(ansi reset) community at (ansi purple)https://discord.gg/NtAbbGn(ansi reset) +Our (ansi green_bold)GitHub(ansi reset) repository is at (ansi green_bold)https://github.com/nushell/nushell(ansi reset) +Our (ansi green)Documentation(ansi reset) is located at (ansi green)https://nushell.sh(ansi reset) +(ansi cyan)Tweet(ansi reset) us at (ansi cyan_bold)@nu_shell(ansi reset) +Learn how to remove this at: (ansi green)https://nushell.sh/book/configuration.html#remove-welcome-message(ansi reset) + +It's been this long since (ansi green)Nushell(ansi reset)'s first commit: +(pretty-print-duration $dt) + +Startup Time: ($nu.startup-time) +" +} + +# Return the current working directory +export def pwd [ + --physical (-P) # resolve symbolic links +] { + if $physical { + $env.PWD | path expand + } else { + $env.PWD + } +} diff --git a/crates/nu-std/std/deprecated_dirs.nu b/crates/nu-std/std/deprecated_dirs.nu new file mode 100644 index 0000000000..4fc4e944ba --- /dev/null +++ b/crates/nu-std/std/deprecated_dirs.nu @@ -0,0 +1,161 @@ +# Maintain a list of working directories and navigate them + +# The directory stack. +# +# Exception: the entry for the current directory contains an +# irrelevant value. Instead, the source of truth for the working +# directory is $env.PWD. It has to be this way because cd doesn't +# know about this module. +# +# Example: the following state represents a user-facing directory +# stack of [/a, /var/tmp, /c], and we are currently in /var/tmp . +# +# PWD = /var/tmp +# DIRS_POSITION = 1 +# DIRS_LIST = [/a, /b, /c] +# +# This situation could arise if we started with [/a, /b, /c], then +# we changed directories from /b to /var/tmp. +export-env { + $env.DIRS_POSITION = 0 + $env.DIRS_LIST = [($env.PWD | path expand)] +} + +def deprecation_warning [ ] { +print -e $" +(ansi red)Warning:(ansi reset) The 'std dirs' module will no longer automatically +be loaded in the next release. To continue using the Shells +feature, and to remove this warning, please add the following +to your config.nu: + +use std/dirs shells-aliases * + +Or see the documentation for more options. +" +} + +# Add one or more directories to the list. +# PWD becomes first of the newly added directories. +export def --env add [ + ...paths: string # directory or directories to add to working list +] { + deprecation_warning + + mut abspaths = [] + for p in $paths { + let exp = ($p | path expand) + if ($exp | path type) != 'dir' { + let span = (metadata $p).span + error make {msg: "not a directory", label: {text: "not a directory", span: $span } } + } + $abspaths = ($abspaths | append $exp) + } + + $env.DIRS_LIST = ($env.DIRS_LIST | insert ($env.DIRS_POSITION + 1) $abspaths | flatten) + + _fetch 1 +} + +export alias enter = add + +# Advance to the next directory in the list or wrap to beginning. +export def --env next [ + N:int = 1 # number of positions to move. +] { + deprecation_warning + _fetch $N +} + +export alias n = next + +# Back up to the previous directory or wrap to the end. +export def --env prev [ + N:int = 1 # number of positions to move. +] { + deprecation_warning + _fetch (-1 * $N) +} + +export alias p = prev + +# Drop the current directory from the list, if it's not the only one. +# PWD becomes the next working directory +export def --env drop [] { + deprecation_warning + if ($env.DIRS_LIST | length) > 1 { + $env.DIRS_LIST = ($env.DIRS_LIST | reject $env.DIRS_POSITION) + if ($env.DIRS_POSITION >= ($env.DIRS_LIST | length)) {$env.DIRS_POSITION = 0} + } + + # step to previous slot + _fetch -1 --forget_current --always_cd + +} + +export alias dexit = drop + +# Display current working directories. +export def --env show [] { + deprecation_warning + mut out = [] + for $p in ($env.DIRS_LIST | enumerate) { + let is_act_slot = $p.index == $env.DIRS_POSITION + $out = ($out | append [ + [active, path]; + [($is_act_slot), + (if $is_act_slot {$env.PWD} else {$p.item}) # show current PWD in lieu of active slot + ] + ]) + } + + $out +} + +export alias shells = show + +export def --env goto [shell?: int] { + deprecation_warning + if $shell == null { + return (show) + } + + if $shell < 0 or $shell >= ($env.DIRS_LIST | length) { + let span = (metadata $shell | get span) + error make { + msg: $"(ansi red_bold)invalid_shell_index(ansi reset)" + label: { + text: $"`shell` should be between 0 and (($env.DIRS_LIST | length) - 1)" + span: $span + } + } + } + + _fetch ($shell - $env.DIRS_POSITION) +} + +export alias g = goto + +# fetch item helper +def --env _fetch [ + offset: int, # signed change to position + --forget_current # true to skip saving PWD + --always_cd # true to always cd +] { + if not ($forget_current) { + # first record current working dir in current slot of ring, to track what CD may have done. + $env.DIRS_LIST = ($env.DIRS_LIST | upsert $env.DIRS_POSITION $env.PWD) + } + + # figure out which entry to move to + # nushell 'mod' operator is really 'remainder', can return negative values. + # see: https://stackoverflow.com/questions/13683563/whats-the-difference-between-mod-and-remainder + let len = ($env.DIRS_LIST | length) + mut pos = ($env.DIRS_POSITION + $offset) mod $len + if ($pos < 0) { $pos += $len} + + # if using a different position in ring, CD there. + if ($always_cd or $pos != $env.DIRS_POSITION) { + $env.DIRS_POSITION = $pos + cd ($env.DIRS_LIST | get $pos ) + } +} diff --git a/crates/nu-std/std/dirs.nu b/crates/nu-std/std/dirs.nu index bf935a84b9..a26128a5d7 100644 --- a/crates/nu-std/std/dirs.nu +++ b/crates/nu-std/std/dirs.nu @@ -22,7 +22,8 @@ export-env { } # Add one or more directories to the list. -# PWD becomes first of the newly added directories. +# The first directory listed becomes the new +# active directory. export def --env add [ ...paths: string # directory or directories to add to working list ] { @@ -38,32 +39,33 @@ export def --env add [ $env.DIRS_LIST = ($env.DIRS_LIST | insert ($env.DIRS_POSITION + 1) $abspaths | flatten) - _fetch 1 } -export alias enter = add - -# Advance to the next directory in the list or wrap to beginning. +# Make the next directory on the list the active directory. +# If the currenta ctive directory is the last in the list, +# then cycle to the top of the list. export def --env next [ N:int = 1 # number of positions to move. ] { _fetch $N } -export alias n = next - -# Back up to the previous directory or wrap to the end. +# Make the previous directory on the list the active directory. +# If the current active directory is the first in the list, +# then cycle to the end of the list. export def --env prev [ N:int = 1 # number of positions to move. ] { _fetch (-1 * $N) } -export alias p = prev - -# Drop the current directory from the list, if it's not the only one. -# PWD becomes the next working directory +# Drop the current directory from the list. +# The previous directory in the list becomes +# the new active directory. +# +# If there is only one directory in the list, +# then this command has no effect. export def --env drop [] { if ($env.DIRS_LIST | length) > 1 { $env.DIRS_LIST = ($env.DIRS_LIST | reject $env.DIRS_POSITION) @@ -75,10 +77,8 @@ export def --env drop [] { } -export alias dexit = drop - -# Display current working directories. -export def --env show [] { +# Display current working directories +export def --env main [] { mut out = [] for $p in ($env.DIRS_LIST | enumerate) { let is_act_slot = $p.index == $env.DIRS_POSITION @@ -93,29 +93,26 @@ export def --env show [] { $out } -export alias shells = show - -export def --env goto [shell?: int] { - if $shell == null { - return (show) +# Jump to directory by index +export def --env goto [dir_idx?: int] { + if $dir_idx == null { + return (main) } - if $shell < 0 or $shell >= ($env.DIRS_LIST | length) { - let span = (metadata $shell | get span) + if $dir_idx < 0 or $dir_idx >= ($env.DIRS_LIST | length) { + let span = (metadata $dir_idx | get span) error make { - msg: $"(ansi red_bold)invalid_shell_index(ansi reset)" + msg: $"(ansi red_bold)invalid_dirs_index(ansi reset)" label: { - text: $"`shell` should be between 0 and (($env.DIRS_LIST | length) - 1)" + text: $"`idx` should be between 0 and (($env.DIRS_LIST | length) - 1)" span: $span } } } - _fetch ($shell - $env.DIRS_POSITION) + _fetch ($dir_idx - $env.DIRS_POSITION) } -export alias g = goto - # fetch item helper def --env _fetch [ offset: int, # signed change to position @@ -140,3 +137,12 @@ def --env _fetch [ cd ($env.DIRS_LIST | get $pos ) } } + +export module shells-aliases { + export alias shells = main + export alias enter = add + export alias dexit = drop + export alias p = prev + export alias n = next + export alias g = goto +} \ No newline at end of file diff --git a/crates/nu-std/std/lib.nu b/crates/nu-std/std/lib.nu new file mode 100644 index 0000000000..c6b332c396 --- /dev/null +++ b/crates/nu-std/std/lib.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/std/mod.nu b/crates/nu-std/std/mod.nu index 4d4f2bb0f1..c0d49d1685 100644 --- a/crates/nu-std/std/mod.nu +++ b/crates/nu-std/std/mod.nu @@ -1,247 +1,28 @@ # std.nu, `used` to load all standard library components -export module assert.nu -export module dirs.nu -export module dt.nu -export module formats.nu -export module help.nu -export module input.nu -export module iter.nu -export module log.nu -export module math.nu -export module xml.nu -export-env { - use dirs.nu [] - use log.nu [] -} - -use dt.nu [datetime-diff, pretty-print-duration] - -# 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 - } -} - -# Print a banner for nushell with information about the project -export def banner [] { -let dt = (datetime-diff (date now) 2019-05-10T09:59:12-07:00) -$"(ansi green) __ ,(ansi reset) -(ansi green) .--\(\)°'.' (ansi reset)Welcome to (ansi green)Nushell(ansi reset), -(ansi green)'|, . ,' (ansi reset)based on the (ansi green)nu(ansi reset) language, -(ansi green) !_-\(_\\ (ansi reset)where all data is structured! - -Please join our (ansi purple)Discord(ansi reset) community at (ansi purple)https://discord.gg/NtAbbGn(ansi reset) -Our (ansi green_bold)GitHub(ansi reset) repository is at (ansi green_bold)https://github.com/nushell/nushell(ansi reset) -Our (ansi green)Documentation(ansi reset) is located at (ansi green)https://nushell.sh(ansi reset) -(ansi cyan)Tweet(ansi reset) us at (ansi cyan_bold)@nu_shell(ansi reset) -Learn how to remove this at: (ansi green)https://nushell.sh/book/configuration.html#remove-welcome-message(ansi reset) - -It's been this long since (ansi green)Nushell(ansi reset)'s first commit: -(pretty-print-duration $dt) - -Startup Time: ($nu.startup-time) -" -} - -# the cute and friendly mascot of Nushell :) -export def ellie [] { - let ellie = [ - " __ ,", - " .--()°'.'", - "'|, . ,'", - " !_-(_\\", - ] - - $ellie | str join "\n" | $"(ansi green)($in)(ansi reset)" -} - -# Return the current working directory -export def pwd [ - --physical (-P) # resolve symbolic links -] { - if $physical { - $env.PWD | path expand - } else { - $env.PWD - } -} - -# 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" - } +# Top-level commands: ellie, repeat, null-device, and "path add" +export use lib * + +# std submodules +export module assert +export module bench +export module dt +export module formats +export module help +export module input +export module iter +export module log +export module math +export module xml + +# Load main dirs command and all subcommands +export use dirs main +export module dirs { + export use dirs [ + add + drop + next + prev + goto + ] } diff --git a/crates/nu-std/testing.nu b/crates/nu-std/testing.nu index 489430e462..003e1d1ebc 100644 --- a/crates/nu-std/testing.nu +++ b/crates/nu-std/testing.nu @@ -1,4 +1,8 @@ -use std log +use std/log +export-env { + # Place NU_FORMAT... environment variables in module-scope + export use std/log * +} def "nu-complete threads" [] { seq 1 (sys cpu | length) diff --git a/crates/nu-std/tests/logger_tests/test_basic_commands.nu b/crates/nu-std/tests/logger_tests/test_basic_commands.nu index cd1d4f3e08..3e22e10bb2 100644 --- a/crates/nu-std/tests/logger_tests/test_basic_commands.nu +++ b/crates/nu-std/tests/logger_tests/test_basic_commands.nu @@ -1,4 +1,4 @@ -use std * +use std/assert def run [ system_level, @@ -6,9 +6,9 @@ def run [ --short ] { if $short { - ^$nu.current-exe --no-config-file --commands $'use std; NU_LOG_LEVEL=($system_level) std log ($message_level) --short "test message"' + ^$nu.current-exe --no-config-file --commands $'use std; use std/log; NU_LOG_LEVEL=($system_level) log ($message_level) --short "test message"' } else { - ^$nu.current-exe --no-config-file --commands $'use std; NU_LOG_LEVEL=($system_level) std log ($message_level) "test message"' + ^$nu.current-exe --no-config-file --commands $'use std; use std/log; NU_LOG_LEVEL=($system_level) log ($message_level) "test message"' } | complete | get --ignore-errors stderr } diff --git a/crates/nu-std/tests/logger_tests/test_log_custom.nu b/crates/nu-std/tests/logger_tests/test_log_custom.nu index da11150032..3965752734 100644 --- a/crates/nu-std/tests/logger_tests/test_log_custom.nu +++ b/crates/nu-std/tests/logger_tests/test_log_custom.nu @@ -1,5 +1,4 @@ -use std * -use std log * +use std/assert use commons.nu * def run-command [ @@ -12,12 +11,12 @@ def run-command [ ] { if ($level_prefix | is-empty) { if ($ansi | is-empty) { - ^$nu.current-exe --no-config-file --commands $'use std; NU_LOG_LEVEL=($system_level) std log custom "($message)" "($format)" ($log_level)' + ^$nu.current-exe --no-config-file --commands $'use std/log; NU_LOG_LEVEL=($system_level) log custom "($message)" "($format)" ($log_level)' } else { - ^$nu.current-exe --no-config-file --commands $'use std; NU_LOG_LEVEL=($system_level) std log custom "($message)" "($format)" ($log_level) --ansi "($ansi)"' + ^$nu.current-exe --no-config-file --commands $'use std/log; NU_LOG_LEVEL=($system_level) log custom "($message)" "($format)" ($log_level) --ansi "($ansi)"' } } else { - ^$nu.current-exe --no-config-file --commands $'use std; NU_LOG_LEVEL=($system_level) std log custom "($message)" "($format)" ($log_level) --level-prefix "($level_prefix)" --ansi "($ansi)"' + ^$nu.current-exe --no-config-file --commands $'use std/log; NU_LOG_LEVEL=($system_level) log custom "($message)" "($format)" ($log_level) --level-prefix "($level_prefix)" --ansi "($ansi)"' } | complete | get --ignore-errors stderr } @@ -31,6 +30,7 @@ def errors_during_deduction [] { #[test] def valid_calls [] { + use std/log * assert equal (run-command "DEBUG" "msg" "%MSG%" 25 --level-prefix "abc" --ansi (ansi default) | str trim --right) "msg" assert equal (run-command "DEBUG" "msg" "%LEVEL% %MSG%" 20 | str trim --right) $"((log-prefix).INFO) msg" assert equal (run-command "DEBUG" "msg" "%LEVEL% %MSG%" --level-prefix "abc" 20 | str trim --right) "abc msg" @@ -39,6 +39,7 @@ def valid_calls [] { #[test] def log-level_handling [] { + use std/log * assert equal (run-command "DEBUG" "msg" "%LEVEL% %MSG%" 20 | str trim --right) $"((log-prefix).INFO) msg" assert equal (run-command "WARNING" "msg" "%LEVEL% %MSG%" 20 | str trim --right) "" } diff --git a/crates/nu-std/tests/logger_tests/test_log_format_flag.nu b/crates/nu-std/tests/logger_tests/test_log_format_flag.nu index 5306daabbe..112f42dbea 100644 --- a/crates/nu-std/tests/logger_tests/test_log_format_flag.nu +++ b/crates/nu-std/tests/logger_tests/test_log_format_flag.nu @@ -1,5 +1,6 @@ use std * -use std log * +use std/log * +use std/assert use commons.nu * def run-command [ @@ -10,9 +11,9 @@ def run-command [ --short ] { if $short { - ^$nu.current-exe --no-config-file --commands $'use std; NU_LOG_LEVEL=($system_level) std log ($message_level) --format "($format)" --short "($message)"' + ^$nu.current-exe --no-config-file --commands $'use std; use std/log; NU_LOG_LEVEL=($system_level) log ($message_level) --format "($format)" --short "($message)"' } else { - ^$nu.current-exe --no-config-file --commands $'use std; NU_LOG_LEVEL=($system_level) std log ($message_level) --format "($format)" "($message)"' + ^$nu.current-exe --no-config-file --commands $'use std; use std/log; NU_LOG_LEVEL=($system_level) log ($message_level) --format "($format)" "($message)"' } | complete | get --ignore-errors stderr } diff --git a/crates/nu-std/tests/logger_tests/test_logger_env.nu b/crates/nu-std/tests/logger_tests/test_logger_env.nu index 9aaa75c8f6..2890dd8929 100644 --- a/crates/nu-std/tests/logger_tests/test_logger_env.nu +++ b/crates/nu-std/tests/logger_tests/test_logger_env.nu @@ -1,5 +1,6 @@ -use std * -use std log * +use std/assert +use std/log +use std/log * #[test] def env_log-ansi [] { diff --git a/crates/nu-std/tests/test_asserts.nu b/crates/nu-std/tests/test_asserts.nu index 2447dfda1e..bc748891ba 100644 --- a/crates/nu-std/tests/test_asserts.nu +++ b/crates/nu-std/tests/test_asserts.nu @@ -1,4 +1,5 @@ use std * +use std/assert #[test] def assert_basic [] { diff --git a/crates/nu-std/tests/test_core.nu b/crates/nu-std/tests/test_core.nu new file mode 100644 index 0000000000..eca7cddd61 --- /dev/null +++ b/crates/nu-std/tests/test_core.nu @@ -0,0 +1,7 @@ +use std/assert + +#[test] +def banner [] { + use std/core + assert ((core banner | lines | length) == 15) +} diff --git a/crates/nu-std/tests/test_dirs.nu b/crates/nu-std/tests/test_dirs.nu index df9a39d784..c3ceb772e1 100644 --- a/crates/nu-std/tests/test_dirs.nu +++ b/crates/nu-std/tests/test_dirs.nu @@ -1,6 +1,5 @@ -use std assert -use std assert -use std log +use std/assert +use std/log # A couple of nuances to understand when testing module that exports environment: # Each 'use' for that module in the test script will execute the def --env block. @@ -48,7 +47,7 @@ def dirs_command [] { # must execute these uses for the UOT commands *after* the test and *not* just put them at top of test module. # the def --env gets messed up - use std dirs + use std/dirs # Stack: [BASE] assert equal [$c.base_path] $env.DIRS_LIST "list is just pwd after initialization" @@ -80,7 +79,7 @@ def dirs_command [] { assert length $env.DIRS_LIST 2 "drop removes from list" assert equal $env.PWD $c.path_b "drop changes PWD to previous in list (before dropped element)" - assert equal (dirs show) [[active path]; [false $c.base_path] [true $c.path_b]] "show table contains expected information" + assert equal (dirs) [[active path]; [false $c.base_path] [true $c.path_b]] "show table contains expected information" # Stack becomes: [BASE] dirs drop @@ -96,7 +95,7 @@ def dirs_next [] { cd $c.base_path assert equal $env.PWD $c.base_path "test setup" - use std dirs + use std/dirs cur_dir_check $c.base_path "use module test setup" dirs add $c.path_a $c.path_b @@ -117,7 +116,7 @@ def dirs_cd [] { # must set PWD *before* doing `use` that will run the def --env block in dirs module. cd $c.base_path - use std dirs + use std/dirs cur_dir_check $c.base_path "use module test setup" @@ -139,7 +138,7 @@ def dirs_cd [] { def dirs_goto_bug10696 [] { let $c = $in cd $c.base_path - use std dirs + use std/dirs dirs add $c.path_a cd $c.path_b @@ -153,7 +152,7 @@ def dirs_goto_bug10696 [] { def dirs_goto [] { let $c = $in cd $c.base_path - use std dirs + use std/dirs # check that goto can move *from* any position in the ring *to* any other position (correctly) @@ -174,4 +173,7 @@ def dirs_goto [] { assert equal $env.PWD ($exp_dir | get $other_pos) "goto changed working directory correctly" } } + + # check that 'dirs goto' with no argument maps to `dirs` (main) + assert length (dirs goto) 3 } diff --git a/crates/nu-std/tests/test_dt.nu b/crates/nu-std/tests/test_dt.nu index 72f608248c..28f3201839 100644 --- a/crates/nu-std/tests/test_dt.nu +++ b/crates/nu-std/tests/test_dt.nu @@ -1,5 +1,5 @@ -use std assert -use std dt * +use std/assert +use std/dt * #[test] def equal_times [] { diff --git a/crates/nu-std/tests/test_formats.nu b/crates/nu-std/tests/test_formats.nu index 59e7ddd94c..5fc1de2d01 100644 --- a/crates/nu-std/tests/test_formats.nu +++ b/crates/nu-std/tests/test_formats.nu @@ -1,4 +1,4 @@ -use std assert +use std/assert def test_data_multiline [] { let lines = [ @@ -19,7 +19,7 @@ def test_data_multiline [] { #[test] def from_ndjson_multiple_objects [] { - use std formats * + use std/formats * let result = test_data_multiline | from ndjson let expect = [{a:1},{a:2},{a:3},{a:4},{a:5},{a:6}] assert equal $result $expect "could not convert from NDJSON" @@ -27,7 +27,7 @@ def from_ndjson_multiple_objects [] { #[test] def from_ndjson_single_object [] { - use std formats * + use std/formats * let result = '{"a": 1}' | from ndjson let expect = [{a:1}] assert equal $result $expect "could not convert from NDJSON" @@ -35,13 +35,13 @@ def from_ndjson_single_object [] { #[test] def from_ndjson_invalid_object [] { - use std formats * + use std/formats * assert error { '{"a":1' | from ndjson } } #[test] def from_jsonl_multiple_objects [] { - use std formats * + use std/formats * let result = test_data_multiline | from jsonl let expect = [{a:1},{a:2},{a:3},{a:4},{a:5},{a:6}] assert equal $result $expect "could not convert from JSONL" @@ -49,7 +49,7 @@ def from_jsonl_multiple_objects [] { #[test] def from_jsonl_single_object [] { - use std formats * + use std/formats * let result = '{"a": 1}' | from jsonl let expect = [{a:1}] assert equal $result $expect "could not convert from JSONL" @@ -57,13 +57,13 @@ def from_jsonl_single_object [] { #[test] def from_jsonl_invalid_object [] { - use std formats * + use std/formats * assert error { '{"a":1' | from jsonl } } #[test] def to_ndjson_multiple_objects [] { - use std formats * + use std/formats * let result = [{a:1},{a:2},{a:3},{a:4},{a:5},{a:6}] | to ndjson | str trim let expect = test_data_multiline assert equal $result $expect "could not convert to NDJSON" @@ -71,7 +71,7 @@ def to_ndjson_multiple_objects [] { #[test] def to_ndjson_single_object [] { - use std formats * + use std/formats * let result = [{a:1}] | to ndjson | str trim let expect = "{\"a\":1}" assert equal $result $expect "could not convert to NDJSON" @@ -79,7 +79,7 @@ def to_ndjson_single_object [] { #[test] def to_jsonl_multiple_objects [] { - use std formats * + use std/formats * let result = [{a:1},{a:2},{a:3},{a:4},{a:5},{a:6}] | to jsonl | str trim let expect = test_data_multiline assert equal $result $expect "could not convert to JSONL" @@ -87,7 +87,7 @@ def to_jsonl_multiple_objects [] { #[test] def to_jsonl_single_object [] { - use std formats * + use std/formats * let result = [{a:1}] | to jsonl | str trim let expect = "{\"a\":1}" assert equal $result $expect "could not convert to JSONL" diff --git a/crates/nu-std/tests/test_help.nu b/crates/nu-std/tests/test_help.nu index b82e5072ef..07ea7c6e4c 100644 --- a/crates/nu-std/tests/test_help.nu +++ b/crates/nu-std/tests/test_help.nu @@ -1,5 +1,5 @@ -use std assert -use std help +use std/assert +use std/help #[test] def show_help_on_commands [] { diff --git a/crates/nu-std/tests/test_iter.nu b/crates/nu-std/tests/test_iter.nu index 7404d082de..2b768c3d9d 100644 --- a/crates/nu-std/tests/test_iter.nu +++ b/crates/nu-std/tests/test_iter.nu @@ -1,4 +1,5 @@ use std * +use std/assert #[test] def iter_find [] { diff --git a/crates/nu-std/tests/test_std.nu b/crates/nu-std/tests/test_lib.nu similarity index 73% rename from crates/nu-std/tests/test_std.nu rename to crates/nu-std/tests/test_lib.nu index 6ac7c6b9e0..1f1720de01 100644 --- a/crates/nu-std/tests/test_std.nu +++ b/crates/nu-std/tests/test_lib.nu @@ -1,8 +1,8 @@ -use std +use std/lib #[test] def path_add [] { - use std assert + use std/assert let path_name = if "PATH" in $env { "PATH" } else { "Path" } @@ -11,19 +11,19 @@ def path_add [] { assert equal (get_path) [] - std path add "/foo/" + lib path add "/foo/" assert equal (get_path) (["/foo/"] | path expand) - std path add "/bar/" "/baz/" + lib 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 + lib path add "foo" + lib 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 (lib 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,18 +35,18 @@ def path_add [] { android: "quux", } - std path add $target_paths + lib 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" + lib path add "~/foo" assert equal (get_path) (["~/foo", "/foo", "/bar"] | path expand) } } #[test] def path_add_expand [] { - use std assert + use std/assert # random paths to avoid collision, especially if left dangling on failure let real_dir = $nu.temp-path | path join $"real-dir-(random chars)" @@ -63,25 +63,21 @@ def path_add_expand [] { with-env {$path_name: []} { def get_path [] { $env | get $path_name } - std path add $link_dir + lib path add $link_dir assert equal (get_path) ([$link_dir]) } rm $real_dir $link_dir } -#[test] -def banner [] { - std assert ((std banner | lines | length) == 15) -} - #[test] def repeat_things [] { - std assert error { "foo" | std repeat -1 } + use std/assert + assert error { "foo" | lib 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 | lib repeat 0) [] + assert equal ($x | lib repeat 1) [$x] + assert equal ($x | lib repeat 2) [$x $x] } } diff --git a/crates/nu-std/tests/test_setup_teardown.nu b/crates/nu-std/tests/test_setup_teardown.nu index 60168ab6f3..d19ba915fb 100644 --- a/crates/nu-std/tests/test_setup_teardown.nu +++ b/crates/nu-std/tests/test_setup_teardown.nu @@ -1,5 +1,5 @@ -use std log -use std assert +use std/log +use std/assert #[before-each] def before-each [] { diff --git a/crates/nu-std/tests/test_std_postload.nu b/crates/nu-std/tests/test_std_postload.nu new file mode 100644 index 0000000000..6b1352350e --- /dev/null +++ b/crates/nu-std/tests/test_std_postload.nu @@ -0,0 +1,11 @@ +use std/assert +export use std * + +#[test] +def std_post_import [] { + assert length (scope commands | where name == "path add") 1 + assert length (scope commands | where name == "ellie") 1 + assert length (scope commands | where name == "repeat") 1 + assert length (scope commands | where name == "formats from jsonl") 1 + assert length (scope commands | where name == "dt datetime-diff") 1 +} \ No newline at end of file diff --git a/crates/nu-std/tests/test_std_preload.nu b/crates/nu-std/tests/test_std_preload.nu new file mode 100644 index 0000000000..a1f88249b6 --- /dev/null +++ b/crates/nu-std/tests/test_std_preload.nu @@ -0,0 +1,11 @@ +use std/assert + +#[test] +def std_pre_import [] { + # These commands shouldn't exist without an import + assert length (scope commands | where name == "path add") 0 + assert length (scope commands | where name == "ellie") 0 + assert length (scope commands | where name == "repeat") 0 + assert length (scope commands | where name == "from jsonl") 0 + assert length (scope commands | where name == "datetime-diff") 0 +} \ No newline at end of file diff --git a/crates/nu-std/tests/test_xml.nu b/crates/nu-std/tests/test_xml.nu index a74b6808e0..16cbb712bc 100644 --- a/crates/nu-std/tests/test_xml.nu +++ b/crates/nu-std/tests/test_xml.nu @@ -1,7 +1,5 @@ -use std xml xaccess -use std xml xupdate -use std xml xinsert -use std assert +use std/xml * +use std/assert #[before-each] def before-each [] { diff --git a/tests/repl/test_stdlib.rs b/tests/repl/test_stdlib.rs index 401fd3c0aa..b15a10dd22 100644 --- a/tests/repl/test_stdlib.rs +++ b/tests/repl/test_stdlib.rs @@ -1,15 +1,5 @@ use crate::repl::tests::{fail_test, run_test_std, TestResult}; -#[test] -fn library_loaded() -> TestResult { - run_test_std("scope modules | where name == 'std' | length", "1") -} - -#[test] -fn prelude_loaded() -> TestResult { - run_test_std("shells | length", "1") -} - #[test] fn not_loaded() -> TestResult { fail_test("log info", "") @@ -17,5 +7,5 @@ fn not_loaded() -> TestResult { #[test] fn use_command() -> TestResult { - run_test_std("use std assert; assert true; print 'it works'", "it works") + run_test_std("use std/assert; assert true; print 'it works'", "it works") } diff --git a/tests/shell/environment/env.rs b/tests/shell/environment/env.rs index e07259a500..35692fdee9 100644 --- a/tests/shell/environment/env.rs +++ b/tests/shell/environment/env.rs @@ -224,10 +224,10 @@ fn std_log_env_vars_are_not_overridden() { ("NU_LOG_DATE_FORMAT".to_string(), "%Y".to_string()), ], r#" - use std + use std/log print -e $env.NU_LOG_FORMAT print -e $env.NU_LOG_DATE_FORMAT - std log error "err" + log error "err" "# ); assert_eq!(actual.err, "%MSG%\n%Y\nerr\n"); @@ -237,7 +237,7 @@ fn std_log_env_vars_are_not_overridden() { fn std_log_env_vars_have_defaults() { let actual = nu_with_std!( r#" - use std + use std/log print -e $env.NU_LOG_FORMAT print -e $env.NU_LOG_DATE_FORMAT "#