Nushell 0.95.0

Nushell, or Nu for short, is a new shell that takes a modern, structured approach to your command line. It works seamlessly with the data from your filesystem, operating system, and a growing number of file formats to make it easy to build powerful command line pipelines.

Today, we're releasing version 0.95.0 of Nu. This release adds external command parsing improvements, plugin version reporting, parse-time evaluation for many more string commands, constants for cache and data directories, and many bug fixes!

Where to get it

Nu 0.95.0 is available as pre-built binariesopen in new window or from crates.ioopen in new window. If you have Rust installed you can install it using cargo install nu.

As part of this release, we also publish a set of optional plugins you can install and use with Nu. To install, use cargo install nu_plugin_<plugin name>.

Table of content

Highlights and themes of this release [toc]

External command parsing improvements [toc]

Breaking change

See a full overview of the breaking changes

A lot of the quirks of external command parsing have been cleaned up in #13089open in new window, with most of the actual string handling work being moved into nu-parser itself. Previously, the parser was doing some very special things to create expressions in a way that run-external would then finish parsing in order to handle quotes in external options, globs, tilde expansion, etc., but this was error prone and did not have great test coverage.

Resolving this made it easier to find some of the edge cases that were not being handled, as well as making some syntax behave in a way that feels more consistent with the rest of Nushell:

  • Bare word interpolation works for external command options, and otherwise embedded in other strings:

    ^echo --foo=(2 + 2) # prints --foo=4
    ^echo -foo=$"(2 + 2)" # prints -foo=4
    ^echo foo="(2 + 2)" # prints (no interpolation!) foo=(2 + 2)
    ^echo foo,(2 + 2),bar # prints foo,4,bar
    
  • Bare word interpolation expands for external command head/args:

    let name = "exa"
    ~/.cargo/bin/($name) # this works, and expands the tilde
    ^$"~/.cargo/bin/($name)" # this doesn't expand the tilde
    ^echo ~/($name)/* # this glob is expanded
    ^echo $"~/($name)/*" # this isn't expanded
    
  • Ndots are now supported for the head/args of an external command (^.../foo works, expanding to ^../../foo)

    • Because our ndots handling requires path normalization, it is disabled for bare arguments that don't contain at least three consecutive dots, and for arguments that contain the string :// as that is likely to be a URL.
  • Glob values are now supported for head/args of an external command, and expanded appropriately:

    ^("~/.cargo/bin/exa" | into glob) # the tilde is expanded
    ^echo ("*.txt" | into glob) # this glob is expanded
    

Plugin version reporting [toc]

Breaking change

See a full overview of the breaking changes

Plugins can now report their own version to Nushell, and have it displayed in plugin list and version. This can help users understand exactly which plugin version they have active in their shell.

This is a breaking change for the Rust API, as implementing it on the Plugin trait is now required. We recommend the following implementation, which will take the plugin version directly from the cargo package metadata:

fn version(&self) -> String {
    env!("CARGO_PKG_VERSION").into()
}

If not using the Rust plugin API, you need to implement the new Metadata call. Providing a version is optional, but highly recommended.

New $nu.data-dir and $nu.cache-dir Constants

To standardize the locations for user-level items such as completions, the constant $nu.data-dir has been introduced in #13122open in new window. The default value of NU_LIB_DIRS will now be:

$env.NU_LIB_DIRS = [
    ($nu.default-config-dir | path join 'scripts') # add <nushell-config-dir>/scripts
    ($nu.data-dir | path join 'completions')       # default home for nushell completions
]

Data Directory Locations

If the $XDG_DATA_HOME environment variable is present when nushell is launched, and it is a valid path, then the data directory will $XDG_DATA_HOME/nushell. Otherwise, the location of the data directory will vary based on the operating system:

PlatformValueExample
Linux$HOME/.local/share/nushell/home/alice/.local/share/nushell
macOS$HOME/Library/Application Support/nushell/home/alice/Library/Application Support/nushell
Windows{FOLDERID_RoamingAppData}\nushellC:\Users\Alice\AppData\Roaming\nushell

Cache Directory Locations

Additionally, the constant $nu.cache-dir has been added for future use. Like the data directory, if the $XDG_CACHE_HOME variable is present and valid, then the location of the cache directory will be $XDG_CACHE_HOME/nushell. Otherwise, the location of the cache directory will vary based on the operating system:

PlatformValueExample
Linux$HOME/.cache/nushell/home/alice/.cache/nushell
macOS$HOME/Library/Caches/nushell/home/alice/Library/Caches/nushell
Windows{FOLDERID_LocalAppData}\nushellC:\Users\Alice\AppData\Local\nushell

New constants for system-level items such as $nu.vendor-autoload-dir will be introduced in future releases.

Changes to commands [toc]

authortitlePR
@NotTheDr01dsopen in new windowSuppress column index for default cal output#13188open in new window
@NotTheDr01dsopen in new windowFixed generate command signature#13200open in new window
@ayax79open in new windowUse polars default infer schema amount of 100 rows instead of scanning entire CVS/json lines files#13193open in new window
@zhiburtopen in new windownu-explore: Add vertical lines && fix index/transpose issue#13147open in new window
@devynopen in new windowfix nu-system build on arm64 FreeBSD#13196open in new window
@NotTheDr01dsopen in new windowDo example#13190open in new window
@ayax79open in new windowAdded the ability to turn on performance debugging through and env var for the polars plugin#13191open in new window
@ayax79open in new windowAdded the ability to open json lines dataframes with polars lazy json lines reader.#13167open in new window
@NotTheDr01dsopen in new windowTable help rendering#13182open in new window
@fdncredopen in new windowupdate try command's help#13173open in new window
@weirdanopen in new windowUpdate sys users signature#13172open in new window
@WindSoilderopen in new windowImproves commands that support range input#13113open in new window
@NotTheDr01dsopen in new windowReturn an empty list when no std help --find results are found#13160open in new window
@NotTheDr01dsopen in new windowExpand tables in help examples in std#13146open in new window
@NotTheDr01dsopen in new windowAdded search terms to if#13145open in new window
@zhiburtopen in new windowImprove performance of explore - 1#13116open in new window
@NotTheDr01dsopen in new windowFixed help for banner#13138open in new window
@IanManskeopen in new windowRemove deprecated --not flag on str contains#13124open in new window
@fdncredopen in new windowupdate uutils crates#13130open in new window
@NotTheDr01dsopen in new windowFix multiple issues with def --wrapped help example#13123open in new window
@IanManskeopen in new windowpath type error and not found changes#13007open in new window
@IanManskeopen in new windowRemove old sys command behavior#13114open in new window
@NotTheDr01dsopen in new windowDeprecate --numbered from for#13112open in new window
@ayax79open in new windowAllow the addition of an index column to be optional#13097open in new window
@ayax79open in new windowFix the use of right hand expressions in operations#13096open in new window
@NotTheDr01dsopen in new windowFixes #13093 - Erroneous example in 'touch' help#13095open in new window
@IanManskeopen in new windowFix display formatting for command type in help commands#12996open in new window
@KAAtheWiseGitopen in new windowUse native toml datetime type in to toml#13018open in new window
@sholderbachopen in new windowMove format date to Category::Strings#13083open in new window
@rgwoodopen in new windowOverhaul explore config#13075open in new window
@rgwoodopen in new windowFix explore panic on empty lists#13074open in new window
@ayax79open in new windowUpgrade to polars 0.40#13069open in new window
@NotTheDr01dsopen in new windowcd/def --env examples#13068open in new window
@ayax79open in new windowAllow int values to be converted into floats.#13025open in new window
@abuschopen in new windowMake query xml return nodes in document order#13047open in new window
@abuschopen in new windowTry to preserve the ordering of elements in from toml#13045open in new window
@hqszopen in new windowsupport plus sign for "into filesize"#12974open in new window
@rgwoodopen in new windowMake LS_COLORS functionality faster in explore, especially on Windows#12984open in new window
@IanManskeopen in new windowDisallow more characters in arguments for internal cmd commands#13009open in new window
@WindSoilderopen in new windowfix do closure with both required, options, and rest args#13002open in new window

Breaking changes [toc]

path type [toc]

After #13007open in new window, if the input path to path type is determined to not exist, path type will now return null instead of an empty string. In most cases, this should not require you to change your scripts. E.g., ("some/path" | path type) == dir will still work as intended.

However, if the input path type was not able to be determined, path type will now create an error instead of silently returning an empty string. For example, invalid permissions for a path will now report an error:

> '/root/test' | path type
Error: nu::shell::io_error

  × I/O error
   ╭─[entry #1:1:1]
 1 '/root/test' | path type
   · ──────┬─────
   ·       ╰── Permission denied (os error 13)
   ╰────

to toml [toc]

Thanks to @KAAtheWiseGitopen in new window in #13018open in new window, to toml will now output nushell date values as toml date values instead of as toml strings.

help commands [toc]

In the last release, changes were made to the type column for scope commands and which. However, the command_type column for help commands was missed, and this release makes its output/formatting consistent with the other two commands. In particular, builtin will now be reported as built-in (#12996open in new window).

str contains --not [toc]

#13124open in new window removes the --not flag on str contains. This flag was deprecated in the last release. You can check the previous release notesopen in new window for migration examples.

sys [toc]

Last release deprecated the sys command in favor of new subcommands. In this release, the deprecated output of sys has been removed, and sys will now only report the available subcommands (#13114open in new window).

run-external [toc]

run-external now works more like any other command, without expecting a special call convention for its args:

> run-external echo "'foo'"
# 0.94: foo
# 0.95: 'foo'
> run-external echo "*.txt"
# 0.94: (glob is expanded)
# 0.95: *.txt

This argument handling is now implemented in the parser instead. See the previous section for more information on these changes.

Deprecations [toc]

for --numbered [toc]

Thanks to @NotTheDr01dsopen in new window in #13112open in new window, the obscure --numbered flag on for has been deprecated. Instead, please use the enumerate command.

for x in ([bob fred] | enumerate) {
    print $'($x.index) is ($x.item)'
}

Other changes [toc]

String command parse-time evaluation [toc]

Thanks to @Embers-of-the-Fireopen in new window in #13032open in new window, many more string-related commands can now be run during parse-time (i.e., used with const). This includes:

  • str trim
  • str contains
  • str distance
  • str ends-with
  • str expand
  • str index-of
  • str join
  • str replace
  • str reverse
  • str starts-with
  • str stats
  • str substring
  • str capitalize
  • str downcase
  • str upcase
  • split chars
  • split column
  • split list
  • split row
  • split words
  • format date
  • format duration
  • format filesize
  • parse
  • detect columns
  • encode
  • decode

Range slice changes [toc]

In #13113open in new window, str substring and bytes at were changed so that they no longer error if the end range index is greater than the start range index. Instead, an empty string or binary value will be returned. For example, this can happen if the end index is negative:

"aaa" | str substring 2..-3

from toml [toc]

Thanks to @abuschopen in new window in #13045open in new window, from toml will now preserve the order of keys/entries as they appear in the input.

into filesize [toc]

Thanks to @hqszopen in new window in #12974open in new window, into filesize can now parse (more) strings that start with a plus sign. In #13110open in new window, they also fixed a bug caused by integer casting.

sys users [toc]

Thanks to @weirdanopen in new window in #13172open in new window, the signature of sys users has been fixed. It used to say that a record would be returned, but sys users actually returns a table.

explore [toc]

#13074open in new window fixes a bug where explore would panic on an empty list.

All breaking changes [toc]

authortitlePR
@NotTheDr01dsopen in new windowSuppress column index for default cal output#13188open in new window
@IanManskeopen in new windowRemove deprecated --not flag on str contains#13124open in new window
@IanManskeopen in new windowpath type error and not found changes#13007open in new window
@IanManskeopen in new windowRemove old sys command behavior#13114open in new window
@NotTheDr01dsopen in new windowDeprecate --numbered from for#13112open in new window
@kubouchopen in new windowSpan ID Refactor (Step 2): Use SpanId of expressions in some places#13102open in new window
@IanManskeopen in new windowFix display formatting for command type in help commands#12996open in new window
@KAAtheWiseGitopen in new windowUse native toml datetime type in to toml#13018open in new window

Notes for plugin developers [toc]

API [toc]

  • The Plugin trait now has a required method fn version(&self) -> String. The following implementation should suffice in most cases:
    fn version(&self) -> String {
        env!("CARGO_PKG_VERSION").into()
    }
    
  • A new derive macro has been added (#13031open in new window) for FromValue and IntoValue conversion traits to make serialization to and from Nushell values easier. The API design is similar to serde-derive. We expect this to make certain kinds of plugins much easier to develop! Many thanks to @cptpiepmatzopen in new window.

Protocol [toc]

  • The plugin protocol has a new required call, Metadata, which is currently used to report version information on registration, but may be used for other plugin metadata in the future. The intention is that all fields are optional, and version is currently optional. This means that although the Rust API requires a version to be reported, it is perfectly allowed (but not recommended) for a plugin to not report a version.

Hall of fame [toc]

Thanks to all the contributors below for helping us solve issues and improve documentation 🙏

Bug fixes [toc]

authortitlePR
@ayax79open in new windowUse polars default infer schema amount of 100 rows instead of scanning entire CVS/json lines files#13193open in new window
@weirdanopen in new windowUpdate sys users signature#13172open in new window
@WindSoilderopen in new windowImproves commands that support range input#13113open in new window
@devynopen in new windowFix compilation for nu_protocol::value::from_value on 32-bit targets#13169open in new window
@NotTheDr01dsopen in new windowReturn an empty list when no std help --find results are found#13160open in new window
@NotTheDr01dsopen in new windowFixed help for banner#13138open in new window
@kubouchopen in new windowFix delta not being merged when evaluating menus#13120open in new window
@hqszopen in new windowfix wrong casting with into filesize#13110open in new window
@WindSoilderopen in new windowrun_external: remove inner quotes once nushell gets = sign#13073open in new window
@rgwoodopen in new windowFix explore panic on empty lists#13074open in new window
@hqszopen in new windowsupport plus sign for "into filesize"#12974open in new window
@rgwoodopen in new windowMake LS_COLORS functionality faster in explore, especially on Windows#12984open in new window
@IanManskeopen in new windowDisallow more characters in arguments for internal cmd commands#13009open in new window
@WindSoilderopen in new windowfix do closure with both required, options, and rest args#13002open in new window

Error messages

authortitlePR
@IanManskeopen in new windowpath type error and not found changes#13007open in new window
@hqszopen in new windowsupport plus sign for "into filesize"#12974open in new window
@ayax79open in new windowFixed incorrect parquet error messages for CSV files#13043open in new window
@IanManskeopen in new windowDisallow more characters in arguments for internal cmd commands#13009open in new window

Dataframes

authortitlePR
@ayax79open in new windowUse polars default infer schema amount of 100 rows instead of scanning entire CVS/json lines files#13193open in new window
@ayax79open in new windowAdded the ability to turn on performance debugging through and env var for the polars plugin#13191open in new window
@ayax79open in new windowAdded the ability to open json lines dataframes with polars lazy json lines reader.#13167open in new window
@ayax79open in new windowAllow the addition of an index column to be optional#13097open in new window
@ayax79open in new windowFix the use of right hand expressions in operations#13096open in new window
@ayax79open in new windowUpgrade to polars 0.40#13069open in new window
@ayax79open in new windowAllow int values to be converted into floats.#13025open in new window
@ayax79open in new windowFixed incorrect parquet error messages for CSV files#13043open in new window

Full changelog [toc]