diff --git a/blog/2026-08-15-nushell_v0_115_0.md b/blog/2026-08-15-nushell_v0_115_0.md new file mode 100644 index 00000000000..3ca522c61a8 --- /dev/null +++ b/blog/2026-08-15-nushell_v0_115_0.md @@ -0,0 +1,1597 @@ +--- +title: Nushell 0.115.0 +author: The Nu Authors +author_site: https://www.nushell.sh/blog +author_image: https://www.nushell.sh/blog/images/nu_logo.png +excerpt: Today, we're releasing version 0.115.0 of Nu. This release brings a major YAML rework, the new `$ans` REPL variable for inspecting your last result, Helix-style editing, and a lot of internal cleanup and fixes. +--- + +# Nushell 0.115.0 + +Today, we're releasing version 0.115.0 of Nu. This release brings a major YAML rework, the new `$ans` REPL variable for inspecting your last result, Helix-style editing, and a lot of internal cleanup and fixes. + +# Where to get it + +Nu 0.115.0 is available as [pre-built binaries](https://github.com/nushell/nushell/releases/tag/0.115.0) or from [crates.io](https://crates.io/crates/nu). 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](https://www.nushell.sh/book/plugins.html) you can install and use with Nushell. + +# Table of contents + + + +# Highlights and themes of this release + +## YAML's Always More Labor + +Thanks to [@cptpiepmatz](https://github.com/cptpiepmatz), Nushell's YAML support got a proper rebuild. We now use a stable, modern, maintained implementation that no longer tries to make YAML 1.1, the scary one, and YAML 1.2 behave like one big YAML-shaped compromise. + +The two specs are now handled separately, `from yaml` defaults to YAML 1.2, tags work more deliberately, multi-document streams are supported, anchors and merge keys behave properly, and `to yaml` is clearer about values that cannot round-trip. + +Take a look at all the examples [here](#yaml-got-a-proper-rework). + +## Ah, the `$ans.last` pipeline took so long to run + +Ever had your last pipeline take forever, only to realize you forgot to assign the result to a variable? Worry no longer. Thanks to [@fdncred](https://github.com/fdncred), Nushell now has `$ans`, a Nushell-specific answer variable heavily inspired by calculators. + +`$ans` keeps track of the last REPL result, including the output, duration, exit code, and the command you typed. Storing the output is opt-in: set `$env.config.max_last_result_size` to a filesize of your choosing, and `$ans.last` will keep up to that much of the previous pipeline result. + +That means if your pipeline took 15 minutes and you do not want to run it again, you can finally breathe, do a quick `let took_too_long = $ans.last`, and you're golden. Take a closer look [here](#added-ans-for-accessing-the-last-repl-result). + +## Helix mode! + +Alongside Vim mode, Nushell now has `helix` edit mode too. Set it with `$env.config.edit_mode = helix`, and that's it. You get a selection-first, Helix/Kakoune-style editing experience with normal, select, and insert modes. + +Thanks to [@kronberger-droid](https://github.com/kronberger-droid) for the work here. More details are [here](#added-helix-edit-mode). + +## Lots of internal wrangling + +This release does not have a huge pile of public user-facing additions, but there was a lot of work inside Nushell. Be in awe of the long list of things happening in the ✨ [Hall of Fame](#hall-of-fame) ✨, and also check out the [long list of fixes](#bug-fixes). + +As always, a big shoutout to everyone contributing and making Nushell better. The internals may not always get the flashiest highlight section, but they are doing a lot of heavy lifting this time. + +# Changes + +## Breaking changes + +### YAML got a proper rework + +YAML has been a problem child for quite some time now. This release replaces the old `serde_yaml`-based implementation with a new one built on `serde-saphyr` and `granit-parser`. With that we now get clearer YAML behavior, better round-tripping, proper tag support, multi-document streams, anchors, aliases, merge keys, and a few new options for configuring how the output should look like. + +#### Breaking changes + +The big breaking change is that Nu no longer tries to parse YAML as an awkward mix of YAML 1.1 and YAML 1.2. We now default to YAML 1.2, which is usually the the less crazy choice. If your files or scripts relied on old YAML 1.1 scalar magic, pass `--spec 1.1`. + +```nushell +use std/assert + +# Default YAML 1.2 behavior: these stay strings. +assert equal ("yes" | from yaml) "yes" +assert equal ("off" | from yaml --spec 1.2) "off" + +# YAML 1.1 keeps the classic YAML oddities. +assert equal ("yes" | from yaml --spec 1.1) true +assert equal ("off" | from yaml --spec 1.1) false +``` + +This specifically breaks octal numbers. In the 1.1 spec, a value is interpreted as an octal number if it starts with the `0` digit. It is then parsed as an octal value. If the value is not valid octal, it is instead returned as a string. + +The 1.2 spec made this much more sensible by allowing leading zeros on regular numbers and requiring octal numbers to use the `0o` prefix. + +```nushell +use std/assert + +# YAML 1.1 uses a leading zero as an octal indicator. +assert equal ("0247" | from yaml --spec 1.1) 0o247 +assert equal ("0o247" | from yaml --spec 1.1) "0o247" + +# YAML 1.2 replaced that with the `0o` prefix. +assert equal ("0247" | from yaml --spec 1.2) 0247 +assert equal ("0o247" | from yaml --spec 1.2) 0o247 +``` + +Did you know that YAML 1.1 supports sexagesimal values like `190:20:30`? No, well in the 1.1 spec these as base-60 numbers that can be used to represent time but noone knows that, so 1.2 got rid of them. And as Nushell now defaults to 1.2 we interpret these as strings. + +```nushell +use std/assert + +assert equal ("190:20:30" | from yaml) "190:20:30" +assert equal ("190:20:30" | from yaml --spec 1.1) 685230 + +assert equal ("02472256" | from yaml) 2472256 +assert equal ("02472256" | from yaml --spec 1.1) 685230 +``` + +`from yaml` is stricter about mapping keys now, too. Nushell record keys are strings, so plain YAML keys that resolve to booleans, numbers, or null are rejected by default. If you want the old loose behavior, use `--key-resolution verbatim` and Nushell will keep the original key text. + +```nushell +'true: enabled' | from yaml +# Error: YAML key resolves to a boolean, but Nushell record keys are strings + +'true: enabled' | from yaml --key-resolution verbatim +# => {true: enabled} +``` + +Tags also mean tags now. Previously, tagged scalars weren't really handled properly, often they were just ignored and handled as plain strings but in YAML they describe the data, usually as some types. Now unknown tags error by default but you can use `--ignore-tags` to just ignore the tags and deal with them yourself. + +```nushell +'Key: !Sub ${AWS::StackName}' | from yaml +# Error: unknown YAML tag + +'Key: !Sub ${AWS::StackName}' | from yaml --ignore-tags +# => {Key: "${AWS::StackName}"} +``` + +`to yaml` is also more specific about values that cannot round-trip. By default it errors instead of quietly turning them into something else. If that is unwatned, choose the behavior explicitly with `--non-roundtrip null` or `--non-roundtrip lossy`. The `--serialize` flag is still available but will probably be deprecated in the future. + +```nushell +{|| $in } | to yaml +# Error: closures are not round-trippable through YAML + +{|| $in } | to yaml --non-roundtrip null +# => null + +{|| $in } | to yaml --serialize +# => !closure "{|| $in }" +``` + +One more relevant breaking change: generated YAML may not look exactly like it did before. The new serializer quotes strings more carefully, writes tags for Nushell-specific values, and lets you configure indentation. If you depended on a specific YAML output, you might need to check that. + +#### Tags and round-tripping + +Nushell now understands standard YAML tags like [`!!timestamp`](https://yaml.org/type/timestamp.html),[`!!binary`](https://yaml.org/type/binary.html), [`!!omap`](https://yaml.org/type/omap.html), [`!!pairs`](https://yaml.org/type/pairs.html), and [`!!set`](https://yaml.org/type/set.html). It also writes Nushell-specific local tags for values that YAML did not define globally, such as filesizes, durations, ranges, globs, and cell paths. + +```yaml +name: Cargo.toml +size: !filesize 17515 +modified: !!timestamp 2026-08-14T23:30:19.144306+02:00 +path: !cell-path $.items.0.name +``` + +Here, `!filesize` and `!cell-path` are Nushell tags, while `!!timestamp` is a standard YAML tag. When you read this back with `from yaml`, those fields come back as proper typed values instead of plain strings or integers. + +If you want the YAML version and Nushell tag prefix written out explicitly, use `to yaml --add-directives` or `to yaml -d`. + +```nushell +ls | where name == Cargo.toml | first | to yaml --add-directives +``` + +```yaml +%YAML 1.2 +%TAG ! tag:nushell.sh,2026: +--- +name: Cargo.toml +type: file +size: !filesize 17515 +modified: !!timestamp 2026-08-14T23:30:19.144306+02:00 +``` + +#### Multiple documents + +YAML streams with more than one document work properly now. By default, `from yaml` returns a single document directly, but returns a list if the stream has multiple documents. If you want to be explicit, use `--multiple list` to always get a list or `--multiple single` to reject multi-document input. + +```yaml +name: dev +--- +name: prod +``` + +```ansi :no-line-numbers +> $yaml | from yaml +╭───┬──────╮ +│ # │ name │ +├───┼──────┤ +│ 0 │ dev │ +│ 1 │ prod │ +╰───┴──────╯ +> 'name: dev' | from yaml --multiple list +╭───┬──────╮ +│ # │ name │ +├───┼──────┤ +│ 0 │ dev │ +╰───┴──────╯ +> $yaml | from yaml --multiple single +Error: shell::yaml::parse::too_many_documents + + × Too many documents + ╭─[repl_entry #8:1:9] + 1 │ $yaml | from yaml --multiple single + ·  ────┬──── + · ╰── Found more than one document, but requested only one + ╰──── + help: Try without `--multiple single` + +``` + +This also works the other way round. `to yaml --multiple` writes each item in a list as its own YAML document. + +```nushell +[{name: dev}, {name: prod}] | to yaml --multiple +``` + +```yaml +name: dev +--- +name: prod +``` + +#### Anchors, aliases, and merge keys + +Anchors and aliases are handled more completely now, including merge keys. Previously this just did not work at all. + +```yaml +defaults: &defaults + timeout: 30 + retries: 3 + +production: + <<: *defaults + timeout: 60 +``` + +```ansi +> $yaml | from yaml | get production +╭─────────┬────╮ +│ timeout │ 60 │ +│ retries │ 3 │ +╰─────────┴────╯ +``` + +#### Useful flags + +On the parsing side, the main new flags are `from yaml --spec 1.1|1.2`, `--multiple auto|list|single`, `--ignore-tags`, and `--key-resolution strict|verbatim`. + +On the writing side, the handy flags are `--spec`, `--add-directives`/`-d`, `--multiple`/`-m`, `--indent`/`-i`, `--compact-list-indent`, `--quote`/`-q`, `--non-roundtrip`, and `--serialize`/`-s`. + +For example, `--quote` and `--indent` can help when another tool expects a particular style. + +```nushell +{outer: {inner: value}} | to yaml --indent 4 --quote double +``` + +```yaml +outer: + inner: 'value' +``` + +### Disallowed shadowing parser keywords + +Trying to shadow a keyword will produce an error now. + +```ansi :no-line-numbers +> def def [] {} +Error: nu::parser::name_is_keyword + + × Can't use parser keyword `def` as command name. + ╭─[repl_entry #9:1:5] + 1 │ def def [] {} + ·  ─┬─ + · ╰── 'def' is a parser keyword + ╰──── + help: Parser keywords cannot be shadowed (including via module exports and `use *`). Choose a different command name + so language constructs keep working. + +``` + +### The `nu` binary no longer ships with `--testbin` + +The `nu` binary used to include a handful of test binaries for our integration tests. These were available through `nu --testbin`. To reduce the size and complexity of the binary, this option is no longer available. Everything the test binaries could do can also be done with Nushell itself. + +If your scripts depended on these test binaries, use an equivalent Nushell command or call `nu -n -c "some commands"` with the same behavior. + +### Other breaking changes + +- Removed the `idx import` and `idx export` commands, which had very little use case, as the search backend (FFF) is not designed for persistent disk caching. `idx init` is now the one way to build the in-memory index; watching remains enabled by default and can be disabled with `--no-watch`. ([#18679](https://github.com/nushell/nushell/pull/18679)) + +## Additions + +### `drop` now supports `binary` inputs, and `chunks`, `first`, `last`, `take`, `skip` and `drop` support `filesize` arguments + +These commands can work on `binary` data, it only makes sense for them to work with not just `int` but `filesize` arguments as well: + +```nushell +# split compressed file into 10MiB chunks +open --raw file.7z + | chunks 10MiB + | enumerate + | each {|chunk| + let suffix = $chunk.index + 1 | fill -a right -c '0' -w 3 + $chunk.item + | save $"file.7z.($suffix)" + } +``` + +### Added constant expressions in `match` arms + +The `match` command can now evaluate constants in match arms like this: + +```ansi +> match "test" { + ('t' + 'es' + 't') => { print 'OK' } +} +OK +``` + +or a more real-world case: + +```ansi :no-line-numbers +> const MY_DIR_CONST = 'D:\Projects\nushell' +> let path = pwd +> $path +D:\Projects\nushell\crates\nu-command +> match $path { + ($MY_DIR_CONST + '\sub-dir1') => { print "sub-dir" } + ($MY_DIR_CONST + '\crates\nu-command') => { print "nu-command" } +} +nu-command +``` + +### Added `external_arg` annotations for script parameters + +You can now do the following: + +```nushell title="script.nu" +def main [ + a: external_arg + b: external_arg + -c: external_arg + ...rest: external_arg +] { + [ + [label value type]; + [a $a ($a | describe)] + [b $b ($b | describe)] + [c $c ($c | describe)] + [rest $rest ($rest | describe)] + ] +} +``` + +Then: + +```ansi :no-line-numbers +> nu ./script.nu 0001 true -c true -- 001 true +╭───┬───────┬──────────────┬────────────╮ +│ # │ label │ value │ type │ +├───┼───────┼──────────────┼────────────┤ +│ 0 │ a │ 0001 │ glob │ +│ 1 │ b │ true │ glob │ +│ 2 │ c │ true │ glob │ +│ 3 │ rest │ ╭───┬──────╮ │ list │ +│ │ │ │ 0 │ 001 │ │ │ +│ │ │ │ 1 │ true │ │ │ +│ │ │ ╰───┴──────╯ │ │ +╰───┴───────┴──────────────┴────────────╯ +``` + +### `any` and `all` now accept row conditions just like `where` + +In addition to the current closure syntax, `any` and `all` can now be given row conditions to make writing filters more streamlined. + +```nushell +[9 8 7 6] | enumerate | any item == index * 2 +``` + +Just like with `where`, you can reference column names directly, and use the `$it` variable to construct predicates given to both commands, or continue to use closures for more extensive constructions. + +```nushell +[1sec 1min 1hr] | all ($it | describe) == 'duration' +``` + +### Added `matrix` custom value and 21 subcommands + +A new `matrix` custom value type enables high-performance matrix math in Nushell, backed by the ndarray library for Rust. + +**Constructors:** + +- `matrix zeros ` — create a matrix filled with zeros +- `matrix identity ` — create an n×n identity matrix +- `into matrix` — convert a table/list-of-lists/list-of-records into a matrix + +**Access:** + +- `matrix get-row ` — extract a row as a list +- `matrix get-col ` — extract a column as a list (2D only) +- `matrix set-row ` — replace a row +- `matrix set-col ` — replace a column (2D only) + +**Arithmetic:** + +- `matrix add ` — element-wise addition with optional `--broadcast` +- `matrix subtract ` — element-wise subtraction with optional `--broadcast` +- `matrix scale ` — multiply all elements by a scalar +- Matrix values also support `` expressions: `$m + $n`, `$m * 2.0`, `$m == $n` + +**Linear algebra:** + +- `matrix multiply ` — dot product (supports 1D×1D, 2D×1D, 1D×2D, 2D×2D) +- `matrix transpose` — swap rows and columns (nD reverses all axes) + +**Transforms:** + +- `matrix reshape ` — change dimensions +- `matrix reshape --flatten` — flatten to 1D + +**Element-wise:** (could rename this to matrix each if map is confusing) + +- `matrix map { |e| ... }` — apply a closure to each element, returning a new matrix + +**Reductions:** + +- `matrix sum` / `matrix sum --axis ` — sum all or along an axis +- `matrix mean` — arithmetic mean of all elements +- `matrix max` / `matrix max --axis ` — maximum all or along an axis +- `matrix reduce --fold { |acc e| ... }` — fold all elements to a single value + +**Output:** + +- `matrix into-nu` — convert to table (list of lists) +- `matrix into-nu --as-records` — convert to table of records with auto-generated column names + +#### Examples + +```ansi :no-line-numbers +> # Create and manipulate matrices +> [[1 2 3] [4 5 6]] | into matrix | matrix transpose | matrix into-nu | to nuon +[[1.0, 4.0], [2.0, 5.0], [3.0, 6.0]] +> matrix identity 3 | matrix scale 5 | matrix into-nu | to nuon +[[5.0, 0.0, 0.0], [0.0, 5.0, 0.0], [0.0, 0.0, 5.0]] + +> # Matrix multiplication +> [[1 2] [3 4]] | into matrix | matrix multiply ([[1 0] [0 1]] | into matrix) | matrix into-nu | to nuon +[[1.0, 2.0], [3.0, 4.0]] + +> # Element-wise operations +> [[1 2] [3 4]] | into matrix | matrix map { |e| $e * 2 } | matrix sum +20.0 + +> # Broadcasting +> matrix zeros 2 3 | matrix add --broadcast ([[1.0 2.0 3.0]] | into matrix) | matrix into-nu | to nuon +[[1.0, 2.0, 3.0], [1.0, 2.0, 3.0]] + +> # Row/column access +> matrix identity 2 | matrix get-row 1 | to nuon +[0.0, 1.0] + +> # Shape metadata via cell path +> matrix identity 2 | $in.shape +╭───┬───╮ +│ 0 │ 2 │ +│ 1 │ 2 │ +╰───┴───╯ +> matrix identity 2 | $in.ndim +2 +> matrix identity 2 | $in.size +4 +``` + +### Standard iterator commands redirect to matrix-specific ones + +- `each` on a matrix → errors: "Use `matrix map` for element-wise operations" +- `par-each` on a matrix → errors: "Use `matrix map` for element-wise operations" +- `reduce` on a matrix → errors: "Use `matrix reduce --fold { ... }`" + +### Added `std-rfc` `date floor` and `date ceil` commands + +Added two new `std-rfc` commands, `date floor` and `date ceil` for rounding datetime values down and up, respectively, to specified duration boundaries. + +```ansi :no-line-numbers +> use std-rfc/date * + +> # Round down to the nearest hour +> 2026-07-15T12:11:10-04:00 | date floor 1hr +Wed, 15 Jul 2026 12:00:00 -0400 (a month ago) +> 1969-12-31T23:30:00+00:00 | date floor 1hr +Wed, 31 Dec 1969 23:00:00 +0000 (56 years ago) + +> # Round date up to nearest hour +> 2026-07-15T12:11:10-04:00 | date ceil 1hr +Wed, 15 Jul 2026 13:00:00 -0400 (a month ago) +> 1969-12-31T23:30:00+00:00 | date ceil 1hr +Thu, 1 Jan 1970 00:00:00 +0000 (56 years ago) +``` + +### Added `idx watch` for streaming indexed filesystem changes + +Added `idx watch` to stream filesystem change events from a live `idx` index as tabular records (`kind`, `path`). Requires `idx init` with watching enabled. Optional pattern, `--ignore`, `--timeout`, and `--max-events` are supported for filtering and clean stream termination. Events respect gitignore/index ignores and can be piped into normal Nushell pipelines. + +Also updated the `fff-search` dependency to 0.10.0 (enables the watch subscription API). + +Examples: + +```nushell +idx init . --wait +idx watch +idx watch "**/*.rs" --ignore [target] +idx watch | where kind == "modified" | each {|e| print $"changed: ($e.path)"} +idx watch --max-events 1 --timeout 5sec +``` + +### Added comparison operators for `semver` values + +`semver` values can now be compared with `==`, `!=`, `<`, `<=`, `>`, and `>=`, using normal semantic version ordering: + +```ansi :no-line-numbers +> ('2.0.1' | into semver) > ('1.9.9' | into semver) +true + +> ('2.0.1' | into semver) < ('1.9.9' | into semver) +false + +> ('1.2.3' | into semver) == ('1.2.3' | into semver) +true + +> ('1.0.0-alpha' | into semver) < ('1.0.0' | into semver) +true +``` + +A version string on the right-hand side is also accepted when it is a valid semver: + +```ansi +> ('2.0.1' | into semver) > '1.9.9' +true +``` + +### Added `--include` to `take while` and `take until` + +`take until` and `take while` commands get a new `--include (-i)` flag, which allows you to take extra items after the stream would have otherwise stopped: + +```ansi :no-line-numbers +> date now +| into record +| transpose key val +| take until { $in.key == day } --include 1 +╭───┬───────┬──────╮ +│ # │ key │ val │ +├───┼───────┼──────┤ +│ 0 │ year │ 2026 │ +│ 1 │ month │ 8 │ +│ 2 │ day │ 15 │ +╰───┴───────┴──────╯ +``` + +### Improved completion caching, dispatch, and reliability + +- Added `$env.config.completions.cache_size` (default: `100`) to control that cap. +- Completion results now persist across prompts instead of being discarded on every new prompt,. +- Fixed a potential panic when narrowing file/directory completions on a path containing multi-byte (non-ASCII) characters. +- `commandline complete --type` now validates its `--type` argument and no longer panics on an out-of-range cursor. +- `use`, `overlay use`, `export use`, `source-env`, `hide-env`, `attr complete`, and `which` now go through the same completion dispatch as other builtins, fixing inconsistent/missing completions in a few of them + +### Added `commandline set-prompt` for async prompt updates + +Added the `commandline set-prompt` command for ad-hoc updates to a rendered prompt. + +#### Examples: + +Stand-in values, with background job spawn: + +```nushell +$env.PROMPT_COMMAND = { $"(ansi green)~(ansi reset)> " } + +$env.PROMPT_COMMAND_RIGHT = { + job spawn { + let branch = (git branch --show-current | complete | get stdout | str trim) + commandline set-prompt --right $"(ansi yellow)($branch)(ansi reset)" + } + + "" # show nothing on the right until the background job fills it in +} +``` + +```nushell +# Replace the left prompt with a freshly rendered string. +job spawn { sleep 1sec; commandline set-prompt $"(ansi green)me> (ansi reset)" } + +# Replace the right prompt. +job spawn { sleep 1sec; commandline set-prompt --right $"right (date now | format date '%H:%M:%S')" } + +# Replace the default/emacs indicator. +job spawn { sleep 1sec; commandline set-prompt --indicator $" (char prompt)" } + +# Replace the vi insert and normal mode indicators independently. +job spawn { sleep 1sec; commandline set-prompt --vi-insert ": " --vi-normal "n " } + +# Replace the multiline continuation indicator. +job spawn { sleep 1sec; commandline set-prompt --multiline "... " } + +# Replace multiple prompt segments in one call. +job spawn { sleep 1sec; commandline set-prompt --right "67" --indicator "69" } + +# Stream a slow prompt segment in from a background job. +job spawn { sleep 1sec; commandline set-prompt $"(git branch --show-current) > " } +``` + +### Added `$ans` for accessing the last REPL result + +`$ans` now stores information about the last successful Nushell result as a record, including its output, duration, and exit code. Like `$in`, `$nu`, and `$env`, `$ans` is now a reserved variable name, so scripts that use `let ans = ...` will need to be updated. + +The amount of memory used to store the last output can be controlled with `$env.config.max_last_result_size`. It accepts a filesize and defaults to `0b`, which disables storing the output in `$ans.last` and makes that part of the feature opt-in. The rest of the `$ans` record remains available. + +To enable `$ans.last`, set `$env.config.max_last_result_size` to a reasonable value such as `1Mb`. If the configured limit is reached, the stored output is truncated and a warning is shown when you access it. + +```ansi :no-line-numbers +> $env.config.max_last_result_size = 10mb +> ls | first 2 +╭───┬────────────────┬──────┬───────┬──────────────╮ +│ # │ name │ type │ size │ modified │ +├───┼────────────────┼──────┼───────┼──────────────┤ +│ 0 │ .cargo │ dir │ 0 B │ 2 weeks ago │ +│ 1 │ .gitattributes │ file │ 113 B │ 2 months ago │ +╰───┴────────────────┴──────┴───────┴──────────────╯ +> $ans +╭───────────┬──────────────────────────────────────────────────────╮ +│ │ ╭───┬────────────────┬──────┬───────┬──────────────╮ │ +│ last │ │ # │ name │ type │ size │ modified │ │ +│ │ ├───┼────────────────┼──────┼───────┼──────────────┤ │ +│ │ │ 0 │ .cargo │ dir │ 0 B │ 2 weeks ago │ │ +│ │ │ 1 │ .gitattributes │ file │ 113 B │ 2 months ago │ │ +│ │ ╰───┴────────────────┴──────┴───────┴──────────────╯ │ +│ exit_code │ 0 │ +│ duration │ 14ms 474µs 800ns │ +│ command │ ls | first 2 │ +╰───────────┴──────────────────────────────────────────────────────╯ +``` + +```nushell +$ans.last # previous pipeline value +$ans.exit_code # int (same idea as $env.LAST_EXIT_CODE) +$ans.duration # duration value (from the same timing as $env.CMD_DURATION_MS) +$ans.command # the last input as a raw string +``` + +### Added Helix edit mode + +Use `$env.config.edit_mode = helix` to enable a selection-first, Helix/Kakoune-style edit mode with normal, select, and insert modes. Motions extend or move the selection, while verbs act on it. + +Menu keybindings such as Tab, Ctrl-r, and F1 work as they do in the other edit modes. Custom keybindings can target `helix_normal`, `helix_insert`, and `helix_select`, and cursor shapes can be configured with `cursor_shape.helix_*`. + +Helix edit mode is included by default through the `helix` Cargo feature. To build without it, disable the default features with `--no-default-features`. + +### Added configurable visual selection styling + +Added `color_config.selection` and `color_config.selection_cursor` to style the line editor's visual selection and the cursor cell inside it: + +```nushell +$env.config.color_config.selection = { attr: r } # default +$env.config.color_config.selection_cursor = { attr: n } # default +``` + +With the defaults a block cursor looks as before; `underscore` and `line` cursor shapes are now visible inside selections. + +### Added KDL v1/v2 support and JSON-in-KDL output + +`from kdl` and `to kdl` now support KDL language versions with `--spec 1` or `--spec 2` (default **2**). Parsing is strict: v1 keyword style (`true`/`false`/`null`) and v2 style (`#true`/`#false`/`#null`) are not mixed unless you convert with an explicit emit spec. + +```ansi :no-line-numbers +> {a: 1, b: true} | to kdl --spec 1 +- a=1 b=true + +> {a: 1, b: true} | to kdl --spec 2 +- a=1 b=#true + +> "item 1 enabled=true" | from kdl --spec 1 | to kdl +item 1 enabled=true + +``` + +#### Nu type annotations (YAML-tag analogue) + +```ansi :no-line-numbers +> # Promote (filesize) on from +> 'node (filesize)1024' | from kdl | get 0.args.0 +1,0 kB + +> # Emit annotated Nu types +> {size: 1kb} | to kdl +- size=(filesize)1000 + +``` + +#### Dual data models: `nodes` and JSON-in-KDL + +- **`from kdl`** defaults to **`--format nodes`**: a list of node rows (`name`, `args`, `props`, `children`) suitable for real config documents. +- **`to kdl`** defaults to **`--format jik`**: [JSON-in-KDL](https://github.com/kdl-org/kdl/blob/main/JSON-IN-KDL.md) with a single top-level `-` node, so records and lists serialize predictably. + +```ansi :no-line-numbers +> {a: 1, b: true} | to kdl +- a=1 b=#true + +> [1 2 3] | to kdl +- 1 2 3 + +> 'node one; node two' | from kdl | to kdl +node one +node two + +``` + +This replaces the previous `to kdl` heuristic that flattened values under synthetic node names such as `root`. + +### Added deprecation metadata to `scope commands` + +You can now programmatically access information about deprecated flags and commands using `scope commands`. + +```ansi :no-line-numbers +> scope commands | where name == "str downcase" | first | get deprecation_info.0 +╭───────────────────────────┬─────────────────────────────────────────────────────────────────────────────────╮ +│ type │ Command │ +│ label │ str downcase was deprecated in 0.114.0 and will be removed in a future release. │ +│ flag │ │ +│ since │ 0.114.0 │ +│ expected_removal │ │ +│ help │ Use `str lowercase` instead. │ +╰───────────────────────────┴─────────────────────────────────────────────────────────────────────────────────╯ +``` + +### Added loose `semver` parsing and `semver` table coloring + +Semantic version values are now displayed in `cyan_bold` in tables, making them easier to distinguish from other data types. `into semver` and `into semver-range` also now support a `--loose` option for parsing versions with common `v`-style prefixes, including `v1.2.3`, `v.1.2.3`, `v:1.2.3`, `v-1.2.3`, and `v_1.2.3`. + +### Other additions + +- Added support for passing lists into `into semver`, and for providing cell paths to do things like `$nu.os-info | into semver kernel_version` or `["1.2.0", "0.3.12"] | into semver`. ([#18567](https://github.com/nushell/nushell/pull/18567)) +- `polars rolling` can now be used natively with lazy frames and be used in expressions. ([#18730](https://github.com/nushell/nushell/pull/18730)) +- Add support for additional arguments to `nu -c`/`nu --commands` with `--` ([#18576](https://github.com/nushell/nushell/pull/18576)) +- Added completions to `format duration`'s and `format filesize`'s unit argument. ([#18783](https://github.com/nushell/nushell/pull/18783)) +- In helix edit mode, keybindings with `mode: helix_select` now target select mode's own keybinding table instead of being shared with `helix_normal`. ([#18833](https://github.com/nushell/nushell/pull/18833)) +- Added `to txt` alongside `to text`, following the existing `to yaml` / `to yml` pattern. ([#18735](https://github.com/nushell/nushell/pull/18735)) +- `into binary` now accepts duration input (e.g. `1sec`, `1hr`, …). ([#18522](https://github.com/nushell/nushell/pull/18522)) + +## Performance + +### Faster large binary value processing + +Large binary values are now substantially cheaper to clone, stream, slice, and convert. + +Commands that repeatedly process large binary values now avoid copying the entire value at each step, with repeated slicing and integer conversion roughly 3.4x faster. + +### Faster large list and table access + +Large lists and tables are now much faster to read from, load from variables, and capture in closures. + +Accessing a small part of a large list, such as `$list.0`, no longer copies the entire list each time the variable is loaded. In a 100,000-element test, 200 repeated reads improved from roughly 131 ms to 138 µs (~950x faster). + +### Other performance improvements + +- Improved performance of `str replace --regex` and `str replace --multiline` when working with lists, tables, and records with many string values, roughly a 10x speed boost. ([#18508](https://github.com/nushell/nushell/pull/18508)) +- `lines` command with string _value_ (non-stream) input no longer eagerly creates a list. Instead it returns a list stream, producing items lazily just like it does with text/byte stream inputs. ([#18753](https://github.com/nushell/nushell/pull/18753)) +- Using built-in commands with `--regex` parameters should be faster in tight loops now because they are able to use the LRU cache for regex. ([#18797](https://github.com/nushell/nushell/pull/18797)) + +## Other changes + +- It is now not allowed to have `export main` in a module that is named to shadow an keyword. This shows and error now. ([#18619](https://github.com/nushell/nushell/pull/18619)) +- The default left and right prompts no longer include ansi color escapes if the user has disabled color. ([#18506](https://github.com/nushell/nushell/pull/18506)) +- Improved `hash md5` and `hash sha256` help to show that both commands support `list` and `list` inputs. ([#18638](https://github.com/nushell/nushell/pull/18638)) + +## Bug fixes + +### Fixed nested `try/finally` blocks interfering with outer error handling + +When nesting a `try/finally` block within a `try` or `try/catch` block, it no longer prevents the outer block from catching errors. + +This is showcased by the following code: + +```nushell +# try-inner.nu +try { + try { print "inner" } finally { print "finally" } + error make { msg: "error" } +} +print "outer" +``` + +Output before this change: + +```ansi :no-line-numbers +> run try-inner.nu +inner +finally +Error: nu::shell::error + + × error + ╭─[D:\Projects\nushell\scratch\try-inner.nu:3:14] + 2 │ try { print "inner" } finally { print "finally" } + 3 │ error make { msg: "error" } + ·  ──────────────── + 4 │ } + ╰──── + +``` + +Note that the error was surfaced despite being thrown inside a `try` block! + +Output after this change: + +```ansi +> run scratch/try-inner.nu +inner +finally +outer +``` + +### Fixed negative arguments for `oneof` parameters + +Parameters with `int`, `float` and `number` types can be supplied negative arguments: + +```ansi +> def foo [p: int] { $p } +> foo -2 +-2 +``` + +However this didn't work with parameters with types like `oneof`: + +```ansi :no-line-numbers +> def foo [p: oneof] { $p } +> foo -2 +Error: nu::parser::unknown_flag + + × The `foo` command doesn't have flag `-2`. + ╭─[repl_entry #9:1:6] + 1 │ foo -2 + ·  ┬ + · ╰── unknown flag + ╰──── + help: Use `--help` to see available flags + +``` + +This is now fixed: + +```ansi +> def foo [p: oneof] { $p } +> foo -2 +-2 +``` + +### Fixed `ps -l` failing when processes exit during collection + +Fixed a Linux race condition where `ps -l` could fail if a process exited while process information was being collected. + +The exited process is now skipped instead of causing the command to fail. + +#### Example + +Before: + +```text +Error getting process stat +File not found: /proc//stat +``` + +After: + +`ps -l` continues running and omits the exited process. + +### Fix panic and infinite loop in `seq` on overflow and zero increment + +`seq` now handles zero increments and integer overflow safely. Using `seq 0 ` returns an `increment cannot be 0` error instead of looping indefinitely or producing no output. Sequences that reach the `i64` boundary also terminate cleanly rather than panicking or wrapping around. + +### Fixed recursive glob behavior in the experimental `dc-glob` backend + +With `--experimental-options=[dc-glob]` enabled, recursive glob patterns now behave more consistently. A bare `**` expands to directories at any depth, including the current directory, while `**/*` lists files and directories below the starting path without including the starting directory itself. Prefixed patterns such as `foo/**` similarly include the prefix directory and its nested directories, but not regular files. + +Patterns with additional path segments, such as `**/*/*` and `**/*/*/*`, now once again enforce their expected minimum depth instead of ignoring the extra `/*` segments. This behavior differs slightly from the legacy `nu-glob` backend, but matches the common behavior of the `glob` crate. + +#### Examples + +```nushell +# enable dc-glob for the session +NU_EXPERIMENTAL_OPTIONS=dc-glob nu +# or: nu --experimental-options=[dc-glob] + +mkdir 0/1/2/3 +touch 0/1/2/3/file.txt +cd 0 + +glob '**' +# start dir + nested directories only (no file.txt) + +glob '**/*' +# everything under start ÔÇö not the start dir itself + +glob '**/*/*' +# paths at least 2 components deep + +glob '**/*/*/*' +# paths at least 3 components deep (e.g. 1/2/3 and 1/2/3/file.txt) + +mkdir foo/bar +touch foo/sibling.txt +glob 'foo/**' +# foo and foo/bar only (not sibling.txt) +``` + +Matcher-level checks (debug flags require dc-glob): + +```nushell +glob --dbg-matches '**/*/*' '1' # false +glob --dbg-matches '**/*/*' '1/2' # true +glob --dbg-matches '**/*/*/*' '1/2' # false +glob --dbg-matches '**/*/*/*' '1/2/3' # true +glob --dbg-matches '**/foo' 'foo' # true +glob --dbg-matches 'foo/**' 'foo' # true +glob --dbg-matches 'foo/**' 'foo/bar' # true +glob --dbg-matches 'foo/**' 'foobar' # false +glob --dbg-matches '*/*' '1' # false +``` + +### Fixed inconsistent `group-by` handling of null keys + +`group-by` no longer maps `null` to the empty string, and treats null the same for list values, cell paths, and closures. + +```ansi :no-line-numbers title="Before (inconsistent)" +> # list: null became "" → 2 groups +> [ a null ] | group-by | values | length +2 + +> # cell path: null dropped → 1 group +> [ { x: a } { x: null } ] | group-by x | values | length +1 + +> # closure: null became "" → 2 groups +> [ { x: a } { x: null } ] | group-by { get x } | values | length +2 + +> # null and "" collapsed into one group +> [ a "" null ] | group-by | to nuon --raw +{a:[a],"":["",null]} +``` + +```ansi :no-line-numbers title="After (consistent)" +> # All three return 1 (null omitted from record output) +> [ a null ] | group-by | values | length +1 +> [ { x: a } { x: null } ] | group-by x | values | length +1 +> [ { x: a } { x: null } ] | group-by { get x } | values | length +1 + +> # Use --to-table to keep null groups +> [ a null ] | group-by --to-table +╭───┬───────┬───────────╮ +│ # │ group │ items │ +├───┼───────┼───────────┤ +│ 0 │ a │ ╭───┬───╮ │ +│ │ │ │ 0 │ a │ │ +│ │ │ ╰───┴───╯ │ +│ 1 │ │ ╭───┬──╮ │ +│ │ │ │ 0 │ │ │ +│ │ │ ╰───┴──╯ │ +╰───┴───────┴───────────╯ +> [ { x: a } { x: null } ] | group-by x --to-table +╭───┬───┬───────────╮ +│ # │ x │ items │ +├───┼───┼───────────┤ +│ 0 │ a │ ╭───┬───╮ │ +│ │ │ │ # │ x │ │ +│ │ │ ├───┼───┤ │ +│ │ │ │ 0 │ a │ │ +│ │ │ ╰───┴───╯ │ +│ 1 │ │ ╭───┬───╮ │ +│ │ │ │ # │ x │ │ +│ │ │ ├───┼───┤ │ +│ │ │ │ 0 │ │ │ +│ │ │ ╰───┴───╯ │ +╰───┴───┴───────────╯ + +> # null and empty string stay separate +> [ "" null ] | group-by --to-table | to nuon --raw +[[group,items];["",[""]],[null,[null]]] + +> # record output: only "" remains; null is omitted +> [ a "" null ] | group-by | to nuon --raw +{a:[a],"":[""]} +``` + +```ansi :no-line-numbers title="Optional cell paths (unchanged)" +> # Missing optional column still skipped +> [{foo: 123}, {foo: 234}, {bar: 345}] | group-by foo? +╭─────┬─────────────╮ +│ │ ╭───┬─────╮ │ +│ 123 │ │ # │ foo │ │ +│ │ ├───┼─────┤ │ +│ │ │ 0 │ 123 │ │ +│ │ ╰───┴─────╯ │ +│ │ ╭───┬─────╮ │ +│ 234 │ │ # │ foo │ │ +│ │ ├───┼─────┤ │ +│ │ │ 0 │ 234 │ │ +│ │ ╰───┴─────╯ │ +╰─────┴─────────────╯ +> # only groups "123" and "234" + +> # Optional path with explicit null is also skipped +> [{x: a}, {x: null}] | group-by x? +╭───┬───────────╮ +│ │ ╭───┬───╮ │ +│ a │ │ # │ x │ │ +│ │ ├───┼───┤ │ +│ │ │ 0 │ a │ │ +│ │ ╰───┴───╯ │ +╰───┴───────────╯ +> # only group "a" +``` + +### Fixed `scope` commands to include local scopes + +Fixed `scope variables`, `scope commands`, `scope aliases`, `scope modules`, and `scope externs` so they report **both the current local scope and the global/permanent scope**. Nested definitions inside `do`, `if`/`for` bodies, and custom commands now appear while that scope is active (and disappear afterward). Outer variables remain visible inside closures (for example `let a = 1; do { let b = 2; scope variables }` lists both `$a` and `$b`). + +### After this change + +#### Outer + local variables + +```nushell +let a = 1 +do { + let b = 2 + scope variables | where name in ["$a", "$b"] | sort-by name | select name value +} +# name value +# $a 1 +# $b 2 +``` + +#### Local commands / aliases / modules + +```nushell +do { + def local-cmd [] { "hi" } + alias la = ls + use spam.nu # module file in the cwd + scope commands | where name == "local-cmd" | length # 1 + scope aliases | where name == "la" | length # 1 + scope modules | where name == "spam" | length # 1 +} +# after the block ends, those local names are gone again +``` + +#### Keyword blocks (IR-inlined) + +```nushell +if true { + def local-cmd [] { "hi" } + scope commands | where name == "local-cmd" | length # 1 +} +# after if: +scope commands | where name == "local-cmd" | length # 0 +``` + +#### `for` loop variable + locals + +```nushell +for i in 1..1 { + let d = 4 + # scope variables includes $i and $d (and outer globals) +} +``` + +#### Shadowed `let` + +```nushell +let x = "first" +# scope variables shows $x with value "first" after the first let +let x = "second" +# then shows the live second binding +``` + +### Fixed `source` losing visibility of outer variables + +Fixes the bugs found when a script or REPL input used `source` to run a `.nu` file, variables defined before the `source` call could become invisible inside the sourced file, producing a "variable not found" error. + +#### Example reproducing the bug + +```nushell title="lll.nu" +let xxx = 'let in script' +source sss.nu +``` + +Where `sss.nu` contains: + +```nushell +print $xxx +``` + +Running `nu lll.nu` would fail with: + +```nushell +Error: nu::shell::variable_not_found + + × Variable not found + ╭─[sss.nu:1:7] + 1 │ print $xxx + · ──┬─ + · ╰── variable not found + ╰──── +``` + +The same error could also appear in the REPL after re-declaring a variable: + +```nushell +❯ let xxx = 'value 1' +❯ source sss.nu # OK: prints "value 1" +❯ let xxx = 'value 2' +❯ source sss.nu # Error: variable not found +``` + +After this change the last statement above would print `value 2`. See the tests and the issue to see more variations. + +### Errors for... `error make`? + +Not specifying the span for error labels (or not doing so correctly) confusingly fell back to using the record's own span instead: + +```ansi :no-line-numbers title="Before w/o start + end" +> open first.nu | nu-highlight +let var = 2 +let span = (metadata $var).span + +error make { + msg: "my error" + label: { text: "two" } +} + +> run first.nu +Error: nu::shell::error + + × my error + ╭─[D:\Projects\nushell\scratch\first.nu:6:9] + 5 │ msg: "my error" + 6 │ label: { text: "two" } + ·  ───────┬─────── + · ╰── two + 7 │ } + ╰──── + +``` + +```ansi :no-line-numbers title="Before w/ start + end" +> open second.nu | nu-highlight +let var = 2 +let span = (metadata $var).span + +error make { + msg: "my error" + label: { text: "two", start: $span.start, end: $span.end } +} + +> run second.nu +Error: nu::shell::error + + × my error + ╭─[D:\Projects\nushell\scratch\second.nu:6:9] + 5 │ msg: "my error" + 6 │ label: { text: "two", start: $span.start, end: $span.end } + ·  ─────────────────────────┬───────────────────────── + · ╰── two + 7 │ } + ╰──── + +``` + +So `error make` succeeded instead of throwing an error. Well, it _did_ throw an error, the one user was trying to, not the one it should due to `error make` receiving an invalid argument. + +From now on `error make` will raise an error of its own when receiving an invalid argument. + +```ansi :no-line-numbers title="After w/o start + end" +> open first.nu | nu-highlight +let var = 2 +let span = (metadata $var).span + +error make { + msg: "my error" + label: { text: "two" } +} + +> run first.nu +Error: nu::shell::missing_required_columns + + × Value is missing required columns. + ╭─[D:\Projects\nushell\scratch\first.nu:6:9] + 5 │ msg: "my error" + 6 │ label: { text: "two" } + ·  ───────┬─────── + · ╰── missing `span: record` column + 7 │ } + ╰──── + +``` + +```ansi :no-line-numbers title="After w/ start + end" +> open second.nu | nu-highlight +let var = 2 +let span = (metadata $var).span + +error make { + msg: "my error" + label: { text: "two", start: $span.start, end: $span.end } +} + +> run second.nu +Error: nu::shell::missing_required_columns + + × Value is missing required columns. + ╭─[D:\Projects\nushell\scratch\second.nu:6:9] + 5 │ msg: "my error" + 6 │ label: { text: "two", start: $span.start, end: $span.end } + ·  ─────────────────────────┬───────────────────────── + · ╰── missing `span: record` column + 7 │ } + ╰──── + +``` + +### Math commands: records with list columns and optional cell paths + +Fixed reducing math commands on records whose columns are lists (including uneven lengths). For example: + +```ansi +> { alice: [0.1 0.6 0.2], bob: [0.8 0.3 0.2 0.9] } | math avg +╭───────┬──────╮ +│ alice │ 0.30 │ +│ bob │ 0.55 │ +╰───────┴──────╯ +``` + +All of the following math commands now accept optional cell paths / columns to operate on only those fields: + +**Reducing** (list cells become a scalar): +`math avg`, `math sum`, `math product`, `math max`, `math min`, `math median`, `math mode`, `math stddev`, `math variance` + +**Element-wise** (list cells stay lists): +`math abs`, `math cbrt`, `math ceil`, `math floor`, `math sqrt`, `math round`, `math log` + +```ansi :no-line-numbers +> # Reduce only one column +> { alice: [1 2 3], bob: [4 5 6] } | math avg alice +╭───────┬───────────╮ +│ alice │ 2.00 │ +│ │ ╭───┬───╮ │ +│ bob │ │ 0 │ 4 │ │ +│ │ │ 1 │ 5 │ │ +│ │ │ 2 │ 6 │ │ +│ │ ╰───┴───╯ │ +╰───────┴───────────╯ + +> # Element-wise on one column +> { alice: [-1 -2 -3], bob: [-4 -5] } | math abs alice +╭───────┬────────────╮ +│ │ ╭───┬───╮ │ +│ alice │ │ 0 │ 1 │ │ +│ │ │ 1 │ 2 │ │ +│ │ │ 2 │ 3 │ │ +│ │ ╰───┴───╯ │ +│ │ ╭───┬────╮ │ +│ bob │ │ 0 │ -4 │ │ +│ │ │ 1 │ -5 │ │ +│ │ ╰───┴────╯ │ +╰───────┴────────────╯ + +> # Works in const context too +> const data = {alice: [1 2 3], bob: [4 5 6]} +> $data | math sum alice +╭───────┬───────────╮ +│ alice │ 6 │ +│ │ ╭───┬───╮ │ +│ bob │ │ 0 │ 4 │ │ +│ │ │ 1 │ 5 │ │ +│ │ │ 2 │ 6 │ │ +│ │ ╰───┴───╯ │ +╰───────┴───────────╯ +``` + +Examples for each command: + +```nushell :no-line-numbers +let rec = { alice: [1 2 3], bob: [4 5 6] } + +$rec | math avg alice # alice: 2 +$rec | math sum alice # alice: 6 +$rec | math product alice # alice: 24 +$rec | math max bob # bob: 6 +$rec | math min bob # bob: 4 +$rec | math median alice # alice: 2 +$rec | math mode alice # alice: [1, 2, 3] modes as list +$rec | math stddev alice # alice: ~0.82 +$rec | math variance alice # alice: ~0.67 + +{ alice: [-1 -2], bob: [-3 -4] } | math abs alice | to nuon +# {alice: [1, 2], bob: [-3, -4]} +{ alice: [8 27], bob: [64] } | math cbrt alice | to nuon +# {alice: [2.0, 3.0], bob: [64]} +{ alice: [1.2 2.3], bob: [3.4] } | math ceil alice | to nuon +# {alice: [2, 3], bob: [3.4]} +{ alice: [1.2 2.3], bob: [3.4] } | math floor alice | to nuon +# {alice: [1, 2], bob: [3.4]} +{ alice: [4 9], bob: [16] } | math sqrt alice | to nuon +# {alice: [2.0, 3.0], bob: [16]} +{ alice: [1.2 2.7], bob: [3.1] } | math round alice | to nuon +# {alice: [1, 3], bob: [3.1]} +{ alice: [1 10 100], bob: [1000] } | math log 10 alice | to nuon +# {alice: [0.0, 1.0, 2.0], bob: [1000]} +``` + +Existing list, table, number, duration, and range inputs keep their previous behavior when no cell paths are given. + +Made error messages more consistent. +On the commands that make sense, I added int, float, duration, filesize. On others, product, sqrt, cbrt, and log, only work with ints and floats. + +### Fixed `math max` on empty streams + +Previously the empty list (top) would display and error but the empty stream (bottom) would not. This should now be fixed. + +```nushell +[] | math max +['x'] | each { try { into int } } | math max +``` + +### Clearer delimiter errors + +Nushell now reports **unclosed** and **unbalanced** delimiters with: + +- The **kind** of delimiter involved (`{`, `}`, `[`, `]`, `(`, `)`, `"`, `'`, `>`, `|`, …) +- **Where it opened** and **where the closer was expected** (when known) +- Help text that suggests a fix, sometimes with a structure hint (e.g. which `def` or record field is open) + +Common mistakes such as forgetting `[` before list elements, forgetting `(` before a grouped expression, forgetting `{` after `if`/`while`/`for`/`try`/`match`, or writing bare record fields without `{` point **near the mistake** instead of only at a distant `}` or EOF. + +### Fixed `path type` treating empty strings as directories + +`"" | path type` now returns `null` instead of `"dir"` + +### Fixed passing quoted `#` strings as script parameters + +Quotes strings with `"#"` in them like `"#00abcd"` are now allowed to be passed as parameters. + +#### Example + +```nushell title="test.nu" +def main [color: string] { + $"Your color is ($color)" +} +``` + +Pass a hex color as a parameter. + +```ansi :no-line-numbers +> let myColor = "#000000" +> run test.nu $myColor +Your color is #000000 +> run test.nu "#abcdef" +Your color is #abcdef +``` + +### Fixed config reloads duplicating unnamed keybindings + +Assigning `$env.config.keybindings` or `$env.config.menus` now merges into the defaults rather than replacing them, so `$env.config.keybindings = []` and `$env.config.menus = []` no longer clear anything. +Set `event: null` on a matching binding to unbind a key. + +### Other fixes + +- `ls` with `dc-glob` enabled no longer fails when encountering files named literally with glob syntax like `*`. ([#18632](https://github.com/nushell/nushell/pull/18632)) +- Fixed `idx` so deleted files and directories no longer appear as live index entries. ([#18673](https://github.com/nushell/nushell/pull/18673)) +- Fixed watched `idx import` runtimes so filesystem changes appear consistently in listings, find results, status, content search, and watch events. ([#18674](https://github.com/nushell/nushell/pull/18674)) +- Nushell now reports incompatible right-hand-side uses of `$in` in typed math expressions during parsing, matching the existing behavior for the left-hand side. ([#18723](https://github.com/nushell/nushell/pull/18723)) +- With the `dc-glob` experimental option enabled `ls **` now works again. ([#18724](https://github.com/nushell/nushell/pull/18724)) +- If you have a broken symlink for startup files in nushell, that should not prevent nushell from starting up with defaults. ([#18726](https://github.com/nushell/nushell/pull/18726)) +- Now it's easier to see what the default settings are when you don't have them configured. Show (nearly) all settings in `$env.config`. If you haven't set any, or launched with `nu -n`, it will show defaults. ([#18747](https://github.com/nushell/nushell/pull/18747)) +- Fixed `generate` rejecting `null` value pipeline input despite working with "empty" pipeline input. ([#18751](https://github.com/nushell/nushell/pull/18751)) +- If you set part of the color config, the defaults for the other parts will still be applied. ([#18770](https://github.com/nushell/nushell/pull/18770)) +- Fixed an issue where saving structured data (like a record or table) to a file with no known serializer (no extension, or an unknown one such as `.foo`) failed with a cryptic `Can't convert to string`. Nushell now explains that no serializer matches the file's extension and suggests `... | to json | save ` or `... | table | ansi strip | save `. ([#18773](https://github.com/nushell/nushell/pull/18773)) +- Fixed an issue where `stor import --file-name` with a path that does not exist created an empty file and discarded the contents of the in-memory database without reporting an error. It now fails with a file not found error and leaves the in-memory database untouched. ([#18809](https://github.com/nushell/nushell/pull/18809)) +- Quotes inside `(...)` subexpressions of interpolated strings now work: `$"('" "')"` prints `" "` instead of becoming an unclosable string. ([#18812](https://github.com/nushell/nushell/pull/18812)) +- Fixed an issue where the icon for a folder with a dot was treated as a file. ([#18817](https://github.com/nushell/nushell/pull/18817)) +- `$ans` works with TUIs better ([#18820](https://github.com/nushell/nushell/pull/18820)) +- Fixed module item completion for `use` commands to work without a string for possible items to match against. ([#18826](https://github.com/nushell/nushell/pull/18826)) +- Single semver values do not output as a table anymore ([#18834](https://github.com/nushell/nushell/pull/18834)) + +# Hall of fame + +Thanks to all the contributors below for helping us solve issues, improve documentation, refactor code, and more! :pray: + +| author | change | link | +| -------------------------------------------------------- | ----------------------------------------------------------------------------------------- | ------------------------------------------------------- | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Remove all tests that use `nu_with_plugins!` | [#18585](https://github.com/nushell/nushell/pull/18585) | +| [@Bahex](https://github.com/Bahex) | Add `test_value!` macro | [#18582](https://github.com/nushell/nushell/pull/18582) | +| [@m-novotny](https://github.com/m-novotny) | Fix default configuration links (#18598) | [#18599](https://github.com/nushell/nushell/pull/18599) | +| [@drbrain](https://github.com/drbrain) | Allow PluginCommand::get_dynamic_completion() to use EngineInterface::get_plugin_config() | [#18587](https://github.com/nushell/nushell/pull/18587) | +| [@sid-6581](https://github.com/sid-6581) | Fix submodule import in test_docker.nu | [#18606](https://github.com/nushell/nushell/pull/18606) | +| [@Bahex](https://github.com/Bahex) | `CompleteResult` type for working with `complete` in tests | [#18604](https://github.com/nushell/nushell/pull/18604) | +| [@Alb-O](https://github.com/Alb-O) | Fuse uniq-by validation and extraction | [#18507](https://github.com/nushell/nushell/pull/18507) | +| [@Bahex](https://github.com/Bahex) | Update some tests to use the new test infra | [#18651](https://github.com/nushell/nushell/pull/18651) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Update terminal tests | [#18663](https://github.com/nushell/nushell/pull/18663) | +| [@philocalyst](https://github.com/philocalyst) | Updates to use CompletionResult | [#18671](https://github.com/nushell/nushell/pull/18671) | +| [@pyz4](https://github.com/pyz4) | Date floor/ceil rounding for durations >= 1day | [#18696](https://github.com/nushell/nushell/pull/18696) | +| [@rvhelden](https://github.com/rvhelden) | Pass Stack to the IR debugger instruction callbacks | [#18708](https://github.com/nushell/nushell/pull/18708) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Do not run CI on lower layers of stacked PRs | [#18720](https://github.com/nushell/nushell/pull/18720) | +| [@ZayanKhan-12](https://github.com/ZayanKhan-12) | Fix devdocs links in AGENTS.md | [#18721](https://github.com/nushell/nushell/pull/18721) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Add test binaries as a separate crate | [#18644](https://github.com/nushell/nushell/pull/18644) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Add `test_*!` macro and more assertions to the testing prelude | [#18647](https://github.com/nushell/nushell/pull/18647) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Remove `use_nu_with_plugins` from `Test` | [#18645](https://github.com/nushell/nushell/pull/18645) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Add `run_multiple` to `NuTester` and update `ShellErrorExt` | [#18664](https://github.com/nushell/nushell/pull/18664) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Update the `table` tests | [#18648](https://github.com/nushell/nushell/pull/18648) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Update `overlay` tests | [#18658](https://github.com/nushell/nushell/pull/18658) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Update `modules/mod.rs` tests | [#18652](https://github.com/nushell/nushell/pull/18652) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Update `parser` tests | [#18668](https://github.com/nushell/nushell/pull/18668) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Update `hooks` tests | [#18669](https://github.com/nushell/nushell/pull/18669) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Refactor some tests | [#18712](https://github.com/nushell/nushell/pull/18712) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Update some more tests that used `nu_repl_code` | [#18649](https://github.com/nushell/nushell/pull/18649) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Refactor most test files that used `nu --testbin` | [#18713](https://github.com/nushell/nushell/pull/18713) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Update redirection tests | [#18714](https://github.com/nushell/nushell/pull/18714) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Update eval tests | [#18716](https://github.com/nushell/nushell/pull/18716) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Update `run external` tests | [#18715](https://github.com/nushell/nushell/pull/18715) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Update external commands tests | [#18717](https://github.com/nushell/nushell/pull/18717) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Update internal commands tests | [#18718](https://github.com/nushell/nushell/pull/18718) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Update the help text of test binaries | [#18739](https://github.com/nushell/nushell/pull/18739) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Refactor `open` tests | [#18740](https://github.com/nushell/nushell/pull/18740) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Refactor a handful of tests to use `test()` | [#18748](https://github.com/nushell/nushell/pull/18748) | +| [@fdncred](https://github.com/fdncred) | Update doc_config.nu / tweak explore section | [#18750](https://github.com/nushell/nushell/pull/18750) | +| [@Bahex](https://github.com/Bahex) | Job spawn closure should be ran with empty pipeline, not null | [#18752](https://github.com/nushell/nushell/pull/18752) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Stabilize unreliable tests in CI | [#18756](https://github.com/nushell/nushell/pull/18756) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | More updated tests | [#18768](https://github.com/nushell/nushell/pull/18768) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Remove `nu!` and update tests | [#18776](https://github.com/nushell/nushell/pull/18776) | +| [@fdncred](https://github.com/fdncred) | Reduce ast footprint, increase ir footprint - phase 0 | [#18808](https://github.com/nushell/nushell/pull/18808) | +| [@brandondong](https://github.com/brandondong) | Fix configuration book link in README | [#18831](https://github.com/nushell/nushell/pull/18831) | +| [@kronberger-droid](https://github.com/kronberger-droid) | Stop stat-ing all of PATH once the external cap is hit | [#18835](https://github.com/nushell/nushell/pull/18835) | + +# Full changelog + +| author | title | link | +| ---------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | +| [@Alb-O](https://github.com/Alb-O) | perf(filters): fuse uniq-by validation and extraction | [#18507](https://github.com/nushell/nushell/pull/18507) | +| [@Alb-O](https://github.com/Alb-O) | perf(str): prepare replace matcher once | [#18508](https://github.com/nushell/nushell/pull/18508) | +| [@Alb-O](https://github.com/Alb-O) | perf: avoid cloning binary values | [#18572](https://github.com/nushell/nushell/pull/18572) | +| [@Alb-O](https://github.com/Alb-O) | perf: avoid cloning list values | [#18636](https://github.com/nushell/nushell/pull/18636) | +| [@Alb-O](https://github.com/Alb-O) | fix(idx): exclude tombstoned entries | [#18673](https://github.com/nushell/nushell/pull/18673) | +| [@Alb-O](https://github.com/Alb-O) | fix(idx): keep watched imports live | [#18674](https://github.com/nushell/nushell/pull/18674) | +| [@Alb-O](https://github.com/Alb-O) | refactor(idx): remove import/export, keep single live index | [#18679](https://github.com/nushell/nushell/pull/18679) | +| [@Bahex](https://github.com/Bahex) | Add `test_value!` macro | [#18582](https://github.com/nushell/nushell/pull/18582) | +| [@Bahex](https://github.com/Bahex) | `CompleteResult` type for working with `complete` in tests | [#18604](https://github.com/nushell/nushell/pull/18604) | +| [@Bahex](https://github.com/Bahex) | `take while/until` commands can include items after the match | [#18623](https://github.com/nushell/nushell/pull/18623) | +| [@Bahex](https://github.com/Bahex) | Replace built-in `date floor/ceil` commands with nu rewrites | [#18640](https://github.com/nushell/nushell/pull/18640) | +| [@Bahex](https://github.com/Bahex) | Update some tests to use the new test infra | [#18651](https://github.com/nushell/nushell/pull/18651) | +| [@Bahex](https://github.com/Bahex) | fix(generate): handle `null` input the same as empty pipeline | [#18751](https://github.com/nushell/nushell/pull/18751) | +| [@Bahex](https://github.com/Bahex) | job spawn closure should be ran with empty pipeline, not null | [#18752](https://github.com/nushell/nushell/pull/18752) | +| [@Bahex](https://github.com/Bahex) | lines: do not prematurely collect output for string value input | [#18753](https://github.com/nushell/nushell/pull/18753) | +| [@Bahex](https://github.com/Bahex) | feat(error make)!: raise errors for invalid labels | [#18755](https://github.com/nushell/nushell/pull/18755) | +| [@Bahex](https://github.com/Bahex) | feat(format duration/filesize): add completions for units | [#18783](https://github.com/nushell/nushell/pull/18783) | +| [@Bahex](https://github.com/Bahex) | Fix module item completion | [#18826](https://github.com/nushell/nushell/pull/18826) | +| [@Mrfiregem](https://github.com/Mrfiregem) | feat(`any`/`all`): Allow using row conditions alongside closures | [#18353](https://github.com/nushell/nushell/pull/18353) | +| [@Mrfiregem](https://github.com/Mrfiregem) | fix: default left and right prompts respect user color settings | [#18506](https://github.com/nushell/nushell/pull/18506) | +| [@Mrfiregem](https://github.com/Mrfiregem) | feat(`into semver`): add cell-path support | [#18567](https://github.com/nushell/nushell/pull/18567) | +| [@Mrfiregem](https://github.com/Mrfiregem) | Show deprecation entries in `scope commands` output | [#18815](https://github.com/nushell/nushell/pull/18815) | +| [@Totara-thib](https://github.com/Totara-thib) | Pin CI actions to commit SHAs and declare workflow permissions | [#18787](https://github.com/nushell/nushell/pull/18787) | +| [@Tyarel8](https://github.com/Tyarel8) | feat(`chunks`, `first`, `last`, `take`, `drop` and `skip`): arg can now also be a filesize for binary | [#18511](https://github.com/nushell/nushell/pull/18511) | +| [@Tyarel8](https://github.com/Tyarel8) | fix parse_calls negative number detection | [#18514](https://github.com/nushell/nushell/pull/18514) | +| [@ZayanKhan-12](https://github.com/ZayanKhan-12) | docs: fix devdocs links in AGENTS.md | [#18721](https://github.com/nushell/nushell/pull/18721) | +| [@aionescu](https://github.com/aionescu) | fix(try): only pop error handler if it was pushed by current `try` block | [#18519](https://github.com/nushell/nushell/pull/18519) | +| [@alerque](https://github.com/alerque) | Bump pin of transient dependency causing unsound transmute | [#18581](https://github.com/nushell/nushell/pull/18581) | +| [@app/dependabot](https://github.com/app/dependabot) | build(deps): bump crate-ci/typos from 1.47.2 to 1.48.0 | [#18502](https://github.com/nushell/nushell/pull/18502) | +| [@app/dependabot](https://github.com/app/dependabot) | build(deps): bump plist from 1.8.0 to 1.10.0 | [#18544](https://github.com/nushell/nushell/pull/18544) | +| [@app/dependabot](https://github.com/app/dependabot) | build(deps): bump calamine from 0.35.0 to 0.36.0 | [#18547](https://github.com/nushell/nushell/pull/18547) | +| [@app/dependabot](https://github.com/app/dependabot) | build(deps): bump humantime from 2.3.0 to 2.4.0 | [#18548](https://github.com/nushell/nushell/pull/18548) | +| [@app/dependabot](https://github.com/app/dependabot) | build(deps): bump bstr from 1.12.1 to 1.13.0 | [#18608](https://github.com/nushell/nushell/pull/18608) | +| [@app/dependabot](https://github.com/app/dependabot) | build(deps): bump regex from 1.12.3 to 1.13.0 | [#18609](https://github.com/nushell/nushell/pull/18609) | +| [@app/dependabot](https://github.com/app/dependabot) | build(deps): bump open from 5.3.4 to 5.4.0 | [#18610](https://github.com/nushell/nushell/pull/18610) | +| [@app/dependabot](https://github.com/app/dependabot) | build(deps): bump aws-credential-types from 1.2.14 to 1.3.0 | [#18612](https://github.com/nushell/nushell/pull/18612) | +| [@app/dependabot](https://github.com/app/dependabot) | build(deps): bump actions/labeler from 6 to 7 | [#18687](https://github.com/nushell/nushell/pull/18687) | +| [@app/dependabot](https://github.com/app/dependabot) | build(deps): bump actions/setup-python from 6 to 7 | [#18688](https://github.com/nushell/nushell/pull/18688) | +| [@app/dependabot](https://github.com/app/dependabot) | build(deps): bump aws-config from 1.8.15 to 1.10.0 | [#18689](https://github.com/nushell/nushell/pull/18689) | +| [@app/dependabot](https://github.com/app/dependabot) | build(deps): bump http from 1.4.0 to 1.5.0 | [#18784](https://github.com/nushell/nushell/pull/18784) | +| [@app/dependabot](https://github.com/app/dependabot) | build(deps): bump Swatinem/rust-cache from 2.9.1 to 2.9.2 | [#18822](https://github.com/nushell/nushell/pull/18822) | +| [@app/dependabot](https://github.com/app/dependabot) | build(deps): bump actions-rust-lang/setup-rust-toolchain from 1.12.0 to 1.17.0 | [#18823](https://github.com/nushell/nushell/pull/18823) | +| [@app/dependabot](https://github.com/app/dependabot) | build(deps): bump taiki-e/install-action from 2.85.8 to 2.85.11 | [#18824](https://github.com/nushell/nushell/pull/18824) | +| [@app/dependabot](https://github.com/app/dependabot) | build(deps): bump bytesize from 2.4.0 to 2.7.0 | [#18825](https://github.com/nushell/nushell/pull/18825) | +| [@ayax79](https://github.com/ayax79) | Lazy and expression support for `polars rolling` | [#18730](https://github.com/nushell/nushell/pull/18730) | +| [@brandondong](https://github.com/brandondong) | Fix configuration book link in README | [#18831](https://github.com/nushell/nushell/pull/18831) | +| [@cacdu](https://github.com/cacdu) | fix(save): give actionable error when structured data has no serializer | [#18773](https://github.com/nushell/nushell/pull/18773) | +| [@cpea2506](https://github.com/cpea2506) | Bump devicons to 0.6.13 | [#18817](https://github.com/nushell/nushell/pull/18817) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Rework our YAML implementation using `serde-saphyr` | [#18487](https://github.com/nushell/nushell/pull/18487) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Do not run CI for draft PRs | [#18584](https://github.com/nushell/nushell/pull/18584) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Remove all tests that use `nu_with_plugins!` | [#18585](https://github.com/nushell/nushell/pull/18585) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Also trigger CI on `ready_for_review` | [#18586](https://github.com/nushell/nushell/pull/18586) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Add test binaries as a separate crate | [#18644](https://github.com/nushell/nushell/pull/18644) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Remove `use_nu_with_plugins` from `Test` | [#18645](https://github.com/nushell/nushell/pull/18645) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Add `test_*!` macro and more assertions to the testing prelude | [#18647](https://github.com/nushell/nushell/pull/18647) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Update the `table` tests | [#18648](https://github.com/nushell/nushell/pull/18648) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Update some more tests that used `nu_repl_code` | [#18649](https://github.com/nushell/nushell/pull/18649) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Update `modules/mod.rs` tests | [#18652](https://github.com/nushell/nushell/pull/18652) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Update `overlay` tests | [#18658](https://github.com/nushell/nushell/pull/18658) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Update terminal tests | [#18663](https://github.com/nushell/nushell/pull/18663) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Add `run_multiple` to `NuTester` and update `ShellErrorExt` | [#18664](https://github.com/nushell/nushell/pull/18664) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Update `parser` tests | [#18668](https://github.com/nushell/nushell/pull/18668) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Update `hooks` tests | [#18669](https://github.com/nushell/nushell/pull/18669) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Refactor some tests | [#18712](https://github.com/nushell/nushell/pull/18712) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Refactor most test files that used `nu --testbin` | [#18713](https://github.com/nushell/nushell/pull/18713) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Update redirection tests | [#18714](https://github.com/nushell/nushell/pull/18714) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Update `run external` tests | [#18715](https://github.com/nushell/nushell/pull/18715) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Update eval tests | [#18716](https://github.com/nushell/nushell/pull/18716) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Update external commands tests | [#18717](https://github.com/nushell/nushell/pull/18717) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Update internal commands tests | [#18718](https://github.com/nushell/nushell/pull/18718) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Remove `--testbin` from `nu` | [#18719](https://github.com/nushell/nushell/pull/18719) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Do not run CI on lower layers of stacked PRs | [#18720](https://github.com/nushell/nushell/pull/18720) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Update `kitest` | [#18727](https://github.com/nushell/nushell/pull/18727) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Update the help text of test binaries | [#18739](https://github.com/nushell/nushell/pull/18739) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Refactor `open` tests | [#18740](https://github.com/nushell/nushell/pull/18740) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Refactor a handful of tests to use `test()` | [#18748](https://github.com/nushell/nushell/pull/18748) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Stabilize unreliable tests in CI | [#18756](https://github.com/nushell/nushell/pull/18756) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | More updated tests | [#18768](https://github.com/nushell/nushell/pull/18768) | +| [@cptpiepmatz](https://github.com/cptpiepmatz) | Remove `nu!` and update tests | [#18776](https://github.com/nushell/nushell/pull/18776) | +| [@danielcadev](https://github.com/danielcadev) | Fix RHS pipeline input type checking (issue #18682) | [#18723](https://github.com/nushell/nushell/pull/18723) | +| [@danielcadev](https://github.com/danielcadev) | fix(save): serialize structured data to text files | [#18735](https://github.com/nushell/nushell/pull/18735) | +| [@dmatos2012](https://github.com/dmatos2012) | Add uutils `ln` command | [#18571](https://github.com/nushell/nushell/pull/18571) | +| [@drbrain](https://github.com/drbrain) | Allow PluginCommand::get_dynamic_completion() to use EngineInterface::get_plugin_config() | [#18587](https://github.com/nushell/nushell/pull/18587) | +| [@fdncred](https://github.com/fdncred) | reorganize nushell configuration | [#18510](https://github.com/nushell/nushell/pull/18510) | +| [@fdncred](https://github.com/fdncred) | The `source` command no longer breaks variable visibility | [#18538](https://github.com/nushell/nushell/pull/18538) | +| [@fdncred](https://github.com/fdncred) | Add `matrix` commands | [#18553](https://github.com/nushell/nushell/pull/18553) | +| [@fdncred](https://github.com/fdncred) | add const eval in match arms | [#18559](https://github.com/nushell/nushell/pull/18559) | +| [@fdncred](https://github.com/fdncred) | Revert "Add uutils `ln` command" | [#18605](https://github.com/nushell/nushell/pull/18605) | +| [@fdncred](https://github.com/fdncred) | disallow `export main` from modules with keyword names | [#18619](https://github.com/nushell/nushell/pull/18619) | +| [@fdncred](https://github.com/fdncred) | fix bug where `ls` with dc-glob would fail with literal `*` name files | [#18632](https://github.com/nushell/nushell/pull/18632) | +| [@fdncred](https://github.com/fdncred) | add `idx watch` command | [#18639](https://github.com/nushell/nushell/pull/18639) | +| [@fdncred](https://github.com/fdncred) | update nushell to latest reedline commit | [#18655](https://github.com/nushell/nushell/pull/18655) | +| [@fdncred](https://github.com/fdncred) | disallow keywords from being shadowed | [#18662](https://github.com/nushell/nushell/pull/18662) | +| [@fdncred](https://github.com/fdncred) | update some dependencies | [#18678](https://github.com/nushell/nushell/pull/18678) | +| [@fdncred](https://github.com/fdncred) | bump nushell to latest reedline commit a2c6e124 | [#18681](https://github.com/nushell/nushell/pull/18681) | +| [@fdncred](https://github.com/fdncred) | agent.md updates | [#18683](https://github.com/nushell/nushell/pull/18683) | +| [@fdncred](https://github.com/fdncred) | Make `scope` subcommands report local and global scope | [#18684](https://github.com/nushell/nushell/pull/18684) | +| [@fdncred](https://github.com/fdncred) | update fff-search to 0.10.1 and tokio to 1.53.1 | [#18693](https://github.com/nushell/nushell/pull/18693) | +| [@fdncred](https://github.com/fdncred) | bump reedline dep to latest commit 7eb9bf2 | [#18695](https://github.com/nushell/nushell/pull/18695) | +| [@fdncred](https://github.com/fdncred) | add splashboard to .gitignore | [#18701](https://github.com/nushell/nushell/pull/18701) | +| [@fdncred](https://github.com/fdncred) | better lex/parse errors | [#18702](https://github.com/nushell/nushell/pull/18702) | +| [@fdncred](https://github.com/fdncred) | fix `dc-glob` `ls **` and `ls **/*/*/*` among other things | [#18704](https://github.com/nushell/nushell/pull/18704) | +| [@fdncred](https://github.com/fdncred) | add comparison operators to semver like `>` `<`, `==` | [#18706](https://github.com/nushell/nushell/pull/18706) | +| [@fdncred](https://github.com/fdncred) | add more consistency with null types | [#18709](https://github.com/nushell/nushell/pull/18709) | +| [@fdncred](https://github.com/fdncred) | fix `ls **` when using dc-glob experimental option | [#18724](https://github.com/nushell/nushell/pull/18724) | +| [@fdncred](https://github.com/fdncred) | fix startup with dangling symlinks | [#18726](https://github.com/nushell/nushell/pull/18726) | +| [@fdncred](https://github.com/fdncred) | add `$ans` record for storing the last result from the repl | [#18729](https://github.com/nushell/nushell/pull/18729) | +| [@fdncred](https://github.com/fdncred) | make `$env.config` show default configuration when not set even with `nu -n` | [#18747](https://github.com/nushell/nushell/pull/18747) | +| [@fdncred](https://github.com/fdncred) | Update doc_config.nu / tweak explore section | [#18750](https://github.com/nushell/nushell/pull/18750) | +| [@fdncred](https://github.com/fdncred) | update math commands to handle records and support cell path rest params | [#18754](https://github.com/nushell/nushell/pull/18754) | +| [@fdncred](https://github.com/fdncred) | fix color config fallbacks | [#18770](https://github.com/nushell/nushell/pull/18770) | +| [@fdncred](https://github.com/fdncred) | fix math max empty list vs empty string | [#18772](https://github.com/nushell/nushell/pull/18772) | +| [@fdncred](https://github.com/fdncred) | update nushell to latest reedline commit 60d99674 | [#18775](https://github.com/nushell/nushell/pull/18775) | +| [@fdncred](https://github.com/fdncred) | upgrade `kdl` to support `--spec 1` or `--spec 2` | [#18779](https://github.com/nushell/nushell/pull/18779) | +| [@fdncred](https://github.com/fdncred) | bump deps | [#18780](https://github.com/nushell/nushell/pull/18780) | +| [@fdncred](https://github.com/fdncred) | allow parameters with `#` to be passed | [#18782](https://github.com/nushell/nushell/pull/18782) | +| [@fdncred](https://github.com/fdncred) | update uu-utils crates to v0.10.0 | [#18795](https://github.com/nushell/nushell/pull/18795) | +| [@fdncred](https://github.com/fdncred) | Allow all built-in commands with `--regex` to use LRU | [#18797](https://github.com/nushell/nushell/pull/18797) | +| [@fdncred](https://github.com/fdncred) | update deps | [#18802](https://github.com/nushell/nushell/pull/18802) | +| [@fdncred](https://github.com/fdncred) | reduce ast footprint, increase ir footprint - phase 0 | [#18808](https://github.com/nushell/nushell/pull/18808) | +| [@fdncred](https://github.com/fdncred) | fix: allow semver to have coloring, add `--loose` flag | [#18819](https://github.com/nushell/nushell/pull/18819) | +| [@fdncred](https://github.com/fdncred) | bug: make `$ans` work better with TUIs | [#18820](https://github.com/nushell/nushell/pull/18820) | +| [@fdncred](https://github.com/fdncred) | add `cli` key to `$ans` record, rename `last_result_size` to `max_last_result_size` | [#18827](https://github.com/nushell/nushell/pull/18827) | +| [@fdncred](https://github.com/fdncred) | fix: single semver output as table instead of value | [#18834](https://github.com/nushell/nushell/pull/18834) | +| [@fdncred](https://github.com/fdncred) | rename `$ans.cli` to `$ans.command` | [#18836](https://github.com/nushell/nushell/pull/18836) | +| [@hexbinoct](https://github.com/hexbinoct) | Lex quotes inside interpolated string subexpressions | [#18812](https://github.com/nushell/nushell/pull/18812) | +| [@ian-h-chamberlain](https://github.com/ian-h-chamberlain) | Support CLI args for commandline (`nu -c`) scripts | [#18576](https://github.com/nushell/nushell/pull/18576) | +| [@jakobwsmnn](https://github.com/jakobwsmnn) | fix: `into binary` not accepting Duration type as input | [#18522](https://github.com/nushell/nushell/pull/18522) | +| [@kobihikri](https://github.com/kobihikri) | ci: pin milestone-action to a full commit SHA | [#18601](https://github.com/nushell/nushell/pull/18601) | +| [@kronberger-droid](https://github.com/kronberger-droid) | chore(reedline): bump reedline to latest commit | [#18685](https://github.com/nushell/nushell/pull/18685) | +| [@kronberger-droid](https://github.com/kronberger-droid) | chore(reedline): bump reedline to latest commit 83c17a2 | [#18694](https://github.com/nushell/nushell/pull/18694) | +| [@kronberger-droid](https://github.com/kronberger-droid) | Bump reedline to e4fe8ed | [#18798](https://github.com/nushell/nushell/pull/18798) | +| [@kronberger-droid](https://github.com/kronberger-droid) | fix(completion): stop the cache reordering the answer it stands in for | [#18806](https://github.com/nushell/nushell/pull/18806) | +| [@kronberger-droid](https://github.com/kronberger-droid) | fix(config): match unnamed keybindings by the key they bind | [#18828](https://github.com/nushell/nushell/pull/18828) | +| [@kronberger-droid](https://github.com/kronberger-droid) | chore(reedline): bump to latest reedline commit 6b9115d | [#18829](https://github.com/nushell/nushell/pull/18829) | +| [@kronberger-droid](https://github.com/kronberger-droid) | chore(reedline): bump reedline to 61715da including helix-mode | [#18830](https://github.com/nushell/nushell/pull/18830) | +| [@kronberger-droid](https://github.com/kronberger-droid) | feat(config): give `helix_select` keybindings their own table | [#18833](https://github.com/nushell/nushell/pull/18833) | +| [@kronberger-droid](https://github.com/kronberger-droid) | fix(completion): stop stat-ing all of PATH once the external cap is hit | [#18835](https://github.com/nushell/nushell/pull/18835) | +| [@kronberger-droid](https://github.com/kronberger-droid) | feat(config): make the visual selection style configurable | [#18838](https://github.com/nushell/nushell/pull/18838) | +| [@latent-9](https://github.com/latent-9) | fix(stor): reject a missing file in stor import instead of discarding the in-memory database | [#18809](https://github.com/nushell/nushell/pull/18809) | +| [@m-novotny](https://github.com/m-novotny) | Fix default configuration links (#18598) | [#18599](https://github.com/nushell/nushell/pull/18599) | +| [@oh-summy](https://github.com/oh-summy) | fix(help): document list input support for hash md5/sha256 | [#18638](https://github.com/nushell/nushell/pull/18638) | +| [@pheenty](https://github.com/pheenty) | add lacy tool into the list of projects that support nushell | [#18618](https://github.com/nushell/nushell/pull/18618) | +| [@pheenty](https://github.com/pheenty) | treat empty string as an invalid path in path type | [#18785](https://github.com/nushell/nushell/pull/18785) | +| [@philocalyst](https://github.com/philocalyst) | non-blocking completions | [#18334](https://github.com/nushell/nushell/pull/18334) | +| [@philocalyst](https://github.com/philocalyst) | async prompt updating | [#18660](https://github.com/nushell/nushell/pull/18660) | +| [@philocalyst](https://github.com/philocalyst) | Updates to use CompletionResult | [#18671](https://github.com/nushell/nushell/pull/18671) | +| [@philocalyst](https://github.com/philocalyst) | Rework how completer works | [#18761](https://github.com/nushell/nushell/pull/18761) | +| [@pyz4](https://github.com/pyz4) | feat(date): add new commands `date floor` and `date ceil` | [#18620](https://github.com/nushell/nushell/pull/18620) | +| [@pyz4](https://github.com/pyz4) | fix: date floor/ceil rounding for durations >= 1day | [#18696](https://github.com/nushell/nushell/pull/18696) | +| [@rabindra789](https://github.com/rabindra789) | fix(ps): skip exited processes instead of erroring in ps -l | [#18542](https://github.com/nushell/nushell/pull/18542) | +| [@rvhelden](https://github.com/rvhelden) | Pass Stack to the IR debugger instruction callbacks | [#18708](https://github.com/nushell/nushell/pull/18708) | +| [@santhreal](https://github.com/santhreal) | Fix panic and infinite loop in `seq` on overflow and zero increment | [#18596](https://github.com/nushell/nushell/pull/18596) | +| [@sid-6581](https://github.com/sid-6581) | fix: fix submodule import in test_docker.nu | [#18606](https://github.com/nushell/nushell/pull/18606) | +| [@skyrocket1643](https://github.com/skyrocket1643) | parser: add external shape annotation | [#18512](https://github.com/nushell/nushell/pull/18512) | +| [@sylvestre](https://github.com/sylvestre) | docs: credit uutils/coreutils for built-in commands in dev FAQ | [#18529](https://github.com/nushell/nushell/pull/18529) | +| [@xtqqczze](https://github.com/xtqqczze) | build(deps): bump num-bigint from 0.4.6 to 0.4.8 | [#18746](https://github.com/nushell/nushell/pull/18746) |