12071 Commits
Author SHA1 Message Date
Lucas 9970552848 Fix OSC 7 directory URL escaping (#19358)
Hello

## Description

Use `Url::from_file_path` to encode OSC 7 directory paths. Keep the
shell hostname for local paths, including numeric names. UNC paths now
use the file server as the URL host.

## User-facing changes (Release notes)

Fixed terminal directory tracking for directory names containing `#`,
`?`, `%`, or `;`. UNC paths now report the file server as the host, so
terminals that require a local host may ignore them.

## Additional notes

Fixes #19357.
2026-10-27 10:39:15 -05:00
Darren Schroeder c7c8ebaa9e Bump webpage and zstd-sys, ignore the other zstd advisories to clear the RustSec audit (#19359)
## Description

The `Security audit` job fails on main and on every PR that touches
`Cargo.toml` or `Cargo.lock` (#19358 is one). The advisory database now
lists five vulnerabilities:

| Crate | Locked | Fixed in | Advisory | This PR |
| --- | --- | --- | --- | --- |
| `webpage` | 2.0.1 | 2.1.0 | RUSTSEC-2026-0407 | bump |
| `zstd-sys` | 2.0.16 | 2.1.2 | RUSTSEC-2026-0410 | bump (lockfile only)
|
| `zstd` | 0.13.3 | 0.14.3 | RUSTSEC-2026-0391 | ignore |
| `zstd-safe` | 7.2.4 | 8.2.0 | RUSTSEC-2026-0398, -0403 | ignore |

`webpage` is a direct dependency of `nu_plugin_query`. The advisory
covers URL fetching (`HTTP::fetch`, `Webpage::from_url`), and the plugin
never fetches. It only calls `HTML::from_string` on its input. Version
2.1.0 also moves `webpage` to html5ever 0.39, which `scraper` already
uses, so the lockfile drops html5ever 0.27 and the seven crates that
came with it.

The zstd crates come only from polars 0.55.2 in `nu_plugin_polars`.
zstd-safe 7.2.4 accepts `zstd-sys ^2.0.15`, so the lockfile can take
zstd-sys 2.1.2. That fixes the wasm32 allocator bug in
RUSTSEC-2026-0410. zstd and zstd-safe can't move, because polars 0.55.2
is the latest release and requires `zstd ^0.13`. polars main is already
on zstd 0.14. Until polars releases, `.cargo/audit.toml` ignores the
remaining 13 zstd-safe and zstd advisories, with a reason for each.
Three of them are vulnerabilities and ten are `unsound` warnings:

- 0391 is reachable. polars-parquet reuses one zstd context per column
chunk through `Decoder::with_context`, so a crafted file can make a page
start with leftover output from an earlier page. The context lives only
as long as that column chunk's reader, so the leftover data always comes
from the same file.
- 0403 affects only `stream::write::Decoder`, and polars uses the read
`Decoder`.
- The other eleven need zstd features that are off (`experimental`,
`seekable`, `zstdmt`), or APIs that neither polars nor the `zstd`
crate's stream and bulk code call.

## User-facing changes (Release notes)

## Additional notes
<!--
Optional.

Examples:
- fixes #123
- closes #456
- related #789

Anything else reviewers should know.
Remove this section if not needed.
-->
2026-10-27 09:19:12 -05:00
qodelicious 131b82a921 fix(std/dirs): make dirs drop a no-op when only one directory is left (#19355)
## Description

`dirs drop` says it has no effect when there's only one directory in the
list. But it still called `_fetch -1 --forget_current --always_cd`,
which `cd`s to whatever is saved in that one slot. That slot isn't
updated when you plain `cd` somewhere, so it usually still holds the
directory nushell started in (or wherever the module was loaded). So `cd
/tmp; dirs drop` would jump you back to your home dir or the startup
dir.

Now `dirs drop` returns early when the list has one entry or less, so it
really does nothing, as the help says. Dropping with two or more entries
works like before.

Added `dirs_drop_single_entry` to `crates/nu-std/tests/test_dirs.nu`. It
fails on main (PWD goes back to the base dir) and passes with the fix.

## User-facing changes (Release notes)

Fixed `dirs drop` changing the working directory when the directory list
has only one entry. It now leaves you where you are.

## Additional notes

Fixes #12578
2026-10-27 06:31:28 -05:00
Tyarel8 36c057c973 feat(docs): document $env.cmd_duration_ms and how to check for startup with it (#19350)
<!--
Thanks for contributing to Nushell!

Before submitting, please read the contributing guide:
https://github.com/nushell/nushell/blob/main/CONTRIBUTING.md

This template helps reviewers understand your changes and allows us to
generate high-quality release notes.
-->

## Description
ref
[discord](https://discord.com/channels/601130461678272522/615329862395101194/1564256320184524906)
Make the way to check for startup (useful when creating a custom prompt)
discoverable.

## User-facing changes (Release notes)
Document in `config nu --doc` the `$env.CMD_DURATION_MS` variable and
how to use it to determine startup.
2026-10-26 09:02:22 -05:00
Darren Schroeder faa166c374 Don't let Tab's partial completion drop suggestions that replace a different span (#19344)
## Description

With `completions.partial` on (the default), Tab inserts the prefix that
every suggestion shares. nushell worked that prefix out itself in
`partial_of`, using only the suggestions with the first suggestion's
span. An extern's subcommands replace the whole `foo re`, while a file
replaces only `re`. So when a file sorted first, it was the shared
prefix on its own. In a directory with `README.md`, `foo re<Tab>` became
`foo README.md` once the background completer answered. With a module of
`git <sub>` externs loaded, `git re<Tab>` became `git README.md`.

When the completer passes no prefix, reedline derives one. Since
nushell/reedline#1261, which main picked up in #19342, reedline lines up
suggestions that replace different spans and keeps only what all of them
share. Any prefix `partial_of` returned was one reedline derives anyway,
so this PR deletes `partial_of` and lets reedline decide.

The stale fallback dropped a group too. After `foo r<Tab>`, Esc,
`e<Tab>`, Tab answers at once from the cached `foo r` answer, narrowed
to `foo re`. The narrowing kept only the suggestions sharing the last
suggestion's span. Those were the subcommands, so reedline inserted `foo
reb` and `README.md` was gone. Now a cached answer that mixes spans
gives no fallback. Until the fresh answer arrives, Tab inserts nothing
and an open menu keeps its last answer, as on the first Tab of a line.

## User-facing changes (Release notes)

Fixed Tab replacing a partly typed subcommand with a file name, such as
`git re<Tab>` becoming `git README.md` in a directory that has a
`README.md`.

## Additional notes
<!--
Optional.

Examples:
- fixes #123
- closes #456
- related #789

Anything else reviewers should know.
Remove this section if not needed.
-->
2026-10-26 08:01:17 -05:00
Darren Schroeder 706259d6f8 Shorter table escape sequences, and a new ansi opt command (#19340)
## Description

With the default colors, nushell's tables repeat escape sequences that
change nothing on screen. Every border character is written as
`\e[39m│\e[0m`, and a cell colored with the default foreground is
wrapped in `\e[39m…\e[0m`, which leaves two resets after every file name
in `ls`. This PR does two things:

1. **Plain borders.** With the default separator style (`separator:
default`), nu-table keeps the color only on the borders that start a
line: every horizontal line, and the first vertical border of each row.
It writes the other borders without color, and the cells colored only
with the default foreground too. Every line looks the same, with fewer
bytes: 19% fewer for `ls`, 28% for a nested table, 43% for a 300-row
stream.
2. **`ansi opt`.** A new command shortens the escape sequences in a
string, binary or byte stream with the
[ansiopt](https://github.com/fdncred/ansiopt) optimizer, without
changing what a terminal shows. It can also report what it changed.

Nushell doesn't rewrite anything on its own at print time. Nothing but
table rendering changes, and only in a way the screen can't show, for a
whole table and for a line taken out of one.

### Before and After

```
main
\e[39m╭───┬──────╮\e[0m
\e[39m│\e[0m \e[1;32m#\e[0m \e[39m│\e[0m \e[1;32mname\e[0m \e[39m│\e[0m
\e[39m├───┼──────┤\e[0m
\e[39m│\e[0m \e[1;32m0\e[0m \e[39m│\e[0m \e[39m\e[38;5;81msrc\e[0m\e[0m  \e[39m│\e[0m
\e[39m╰───┴──────╯\e[0m

branch
\e[39m╭───┬──────╮\e[0m
\e[39m│\e[0m \e[1;32m#\e[0m │ \e[1;32mname\e[0m │
\e[39m├───┼──────┤\e[0m
\e[39m│\e[0m \e[1;32m0\e[0m │ \e[38;5;81msrc\e[0m  │
\e[39m╰───┴──────╯\e[0m
```

`ansi opt` on a string:

```nushell
> $'(ansi reset)(ansi reset)(ansi red)hi(ansi reset)' | ansi opt --show
\e[;31mhi\e[m
> "\e[0m\e[31m──── \e[0m \e[31m────\e[0m" | ansi opt --visual --rep --show
\e[;31m─\e[3b  ─\e[3b\e[m
> $'(ansi reset)(ansi reset)(ansi red)hi(ansi reset)' | ansi opt --explain
╭───┬──────────┬─────────┬───────────┬─────────┬───────────────────╮
│ # │ sequence │ meaning │  outcome  │ output  │        why        │
├───┼──────────┼─────────┼───────────┼─────────┼───────────────────┤
│ 0 │ \e[0m    │ reset   │ folded    │ \e[;31m │                   │
│ 1 │ \e[0m    │ reset   │ no effect │         │ already in effect │
│ 2 │ \e[31m   │ fg red  │ folded    │ \e[;31m │                   │
│ 3 │ \e[0m    │ reset   │ folded    │ \e[m    │                   │
╰───┴──────────┴─────────┴───────────┴─────────┴───────────────────╯
```

## User-facing changes (Release notes)

- Tables with the default colors are written with fewer escape
sequences: about a fifth fewer bytes for `ls` and records, and up to two
fifths for longer tables. They look exactly the same, also when a line
is taken out of a table and printed on its own.
- New `ansi opt` command, which shortens the ANSI escape sequences in a
string, binary or byte stream without changing what a terminal shows.
`--stats`, `--diff`, `--explain`, `--hotspot`, `--show` and `--html`
return what it changed instead, as records, tables or an HTML report.

## Additional notes
2026-10-25 15:07:02 -05:00
berce f3cc93329c fix(try): drain a piped stderr before collecting an external (#19339)
## Description

`ignore`, `save`, `complete` and `tee` ask for an external's stdout and
stderr on their own pipes (`PipeSeparate`), so an external at the end of
a `try` block that is piped into one of them gets a stderr pipe too. A
`try` with `catch` or `finally` then collects the block's output with
`try-collect`, and `collect` calls `into_value` on the child stream.
`ChildProcess::into_bytes` refuses a child that still has a stderr pipe
("internal error: stderr should not exist"), so the error went to
`catch` even though the external exited 0.

A value can't carry a separate stderr, so `try-collect` now leaves such
a child as a stream instead of turning it into a value:

- `ChildProcess::buffer_output` reads stdout and stderr to the end
(stderr on its own thread, with the reader that `wait_with_output`
already used, now shared as `collect_pipes`), waits for the child,
checks its exit status the way `into_bytes` does, and puts the output
back so it can still be read. `do` already rebuilds a finished child
from buffers in a similar way.
- `try_collect` in `eval_ir.rs` does this for a child with a stderr pipe
and passes it on, so the command after the `try` gets stdout, stderr and
the exit status as if there were no `try`. Failing externals still error
inside the `try`, so `catch` still runs for them. Everything else still
goes through `collect`.
- The pipes are read before the pipefail exit check. Waiting for the
exit first hung on a child that filled its stderr pipe.
- `finally` gets a copy of the result, and only a value can be copied.
So at `begin-finally`, a child passed on like this becomes its stdout,
and its stderr goes to the block's stderr, the same as for `let x =
^external`.

`into_bytes` keeps its check: a caller that wants a value can't keep
stderr.

## User-facing changes (Release notes)

Fixed `try { ^external } catch { ... } | ignore` (also with `save
--stderr`, `complete`, `tee --stderr`, and inside `do` or a custom
command) running the `catch` block with "internal error: stderr should
not exist" when the external succeeded. The external's stderr now
reaches the next command the same way it does without the `try`.

With `finally`, the `try` doesn't fail that way anymore either, but the
result is still turned into a value so `finally` can see it. The next
command gets the external's stdout as a value and its stderr is printed,
like for `let x = ^external`. So `save --stderr` after `try ... finally`
gets an empty stderr, and `complete` still says it only works with
external commands.

## Additional notes

Fixes #19335

Tests in `tests/shell/mod.rs`:
- `try_catch_keeps_a_piped_stderr_of_a_successful_external` runs `try {
X } catch { print caught } | C` and `X | C` and checks that stdout and
stderr match. `C` is each of `ignore`, `ignore --stdout`, `ignore
--stderr`, `complete`, and `save --stderr`. `X` is either a short
stdout+stderr external or one that writes 200KB to stderr.
- `try_catch_piped_into_ignore_catches_only_a_failing_external` covers
the same inside a `def`, `finally` with and without `catch`, and a
failing external that is still caught.

On main, 8 of the 14 cases fail, the 5 with 200KB of stderr hang until
killed, and only the failing-external case passes.

- `cargo test --test tests`: 2421 passed
- `cargo test -p nu-protocol -p nu-engine -p nu-cmd-lang`, `cargo test
-p nu-command -- complete ignore save tee try_`: passed
- `cargo fmt --all -- --check`, `cargo clippy -p nu-engine -p
nu-protocol -p nu-cmd-lang --all-targets --no-deps -- -D warnings`, and
`cargo check -p nu-engine --no-default-features` with `-D warnings`:
clean (toolchain 1.99.1)

More than 64KB of stdout with no stderr pipe still hangs with pipefail
on, as on 0.116.2; that path isn't touched here.
2026-10-25 15:05:35 -05:00
Martin Kronberger 75eeb21fa6 chore: bump reedline to c8d81b2 (#19342)
## Description

Bumps reedline to `c8d81b2`, five PRs past `39db5e3`:

- nushell/reedline#1256 `fix(vi): repaint whenever the mode changes`
- nushell/reedline#1244 `feat(hints): let hinters and highlighters
handle hints before auto-pair closers`
- nushell/reedline#1261 `fix(menu): take the partial completion across
all suggestion spans`
- nushell/reedline#1263 `fix(engine): treat Ctrl+J as a line ending when
draining the input batch`
- nushell/reedline#1257 `feat(external_printer): ungate the printer and
commit messages in one frame`

`#1244` replaces the unreleased `#1239` behavior with hooks that default
to the last release, so hints before auto-pair closers come back with
nushell/nushell#19199

`#1261` only changes the partial reedline derives itself, and nushell
passes its own, so `foo re<Tab>` keeps its current behavior until the
nushell side follows

### User-facing changes (Release notes)

- Fixed the vi prompt indicator not switching to insert on `a`, `A` or
`I` when the cursor does not move.
- Fixed piped input with several LF-terminated lines dropping every line
after the first.
2026-10-25 19:45:05 +01:00
Martin Kronberger 6d47cd0e72 chore: bump ctutils, tokio and clipboard-win to clear the RustSec audit (#19343)
## Description

Clears the security audit, which fails on main since 2026-10-23

- `ctutils` 0.4.2 -> 0.4.5: RUSTSEC-2026-0385, non-constant-time
comparisons. Only reaches `nu_plugin_polars`.
- `tokio` 1.53.1 -> 1.54.1: RUSTSEC-2026-0386, `AsyncFd::new` unsound.
- `clipboard-win` 5.4.1 -> 5.4.3: 5.4.1 is yanked.

## User-facing changes (Release notes)

None.
2026-10-25 18:46:53 +01:00
Jianjun Wangandwangjianjun 23392cdc47 fix(dc-glob): honor negated character classes (#19309)
## Description

With the experimental dc-glob backend enabled, `glob '[!f]*'` selects
`foo` instead of `bar` because `!` is treated as a member of a positive
character class.

Recognize a leading `!` as negation and invert the existing character
membership check after case handling. A later `!` remains literal.
Regression tests cover file traversal, ranges, Unicode, component
boundaries, and the existing ASCII-only ignore-case behavior.

Partially addresses #19256: this fixes negated character classes only.
The invalid-pattern and relative-path traversal cases remain separate.

## User-facing changes (Release notes)

Fixed negated character classes in the experimental dc-glob backend:
patterns such as `[!f]*` now exclude names beginning with `f`.

## Additional notes

Validation on Linux with Rust 1.97.1:

- Both new regression tests fail against the unchanged base
implementation.
- `cargo test --locked --profile ci -p nu-glob`: 82 unit tests and 6
doctests pass; 1 doctest ignored.
- `cargo fmt --all -- --check`, `cargo nuclippy`, and `typos` pass.
- Built `nu` with `cargo build --locked --profile ci -p nu` and checked
an actual `foo`/`bar` directory: both the legacy and dc-glob backends
return `[bar]`.

Full workspace tests and cross-platform CI were not run locally.

AI assistance: Codex assisted the investigation, implementation, tests,
and an independent agent review of the patch.

---------

Co-authored-by: wangjianjun <passionworkeer@users.noreply.github.com>
2026-10-25 07:26:30 -05:00
赤坂理子 b1a32d194f Reset stale REPL interrupts before running a new command (#19337)
## Description

Related to #18989 and follows up on #19163

The REPL resets interrupt signals at the start of each iteration, before
evaluating the prompt
An interrupted prompt can leave the signal set for the transient prompt,
line editor callbacks, and the next command

- Recover interrupted signals after normal prompt evaluation, before
constructing the transient prompt and entering the line editor
- Keep command-boundary recovery before pre-execution hooks for
interruptions from editor callbacks
- Only reset at these recovery points when interrupted, avoiding extra
plugin Reset messages on normal commands
- Keep normal prompt errors visible and retain cancellation of running
commands
- Extend the existing regression test to cover the interrupted prompt
result, transient prompt, custom completion, and a subsequent editor
interrupt followed by a hook and command
- Disable all shell-integration flags in the regression test and explain
why its expressions use `match` to reach signal checks

### Reproduction

- Start an interactive session with a slow prompt closure such as `{
sleep 1min; "prompt" }`
- Press Ctrl-C while the prompt is evaluating
- Try a custom completer that polls interruption signals, or a transient
prompt closure containing `sleep`
- Without prompt-boundary recovery, these callbacks inherit the
interrupt until the next command is submitted
- Enter `match 1 { 1 => 42 }`
- Without command-boundary recovery, the command and its pre-execution
hooks can inherit an interrupt from the prompt or editor
- With both recovery points, the transient prompt, completion, hook, and
new command run normally

The macOS PTY probe compared the previous PR commit `0c3e8f749` with the
updated code
The previous PR binary reported normal and transient prompt interruption
errors and offered no custom completion before Enter
The updated binary reported only the normal prompt interruption, offered
completion before Enter, and rendered the transient prompt
The next hook and command succeeded in both probes, including after a
separate SIGINT while waiting for input

A separate PTY probe kept a background thread job and a frozen external
process registered during prompt interruption and verified cancellation
of a later foreground command

## User-facing changes (Release notes)

Fixed stale prompt interrupts affecting completions, transient prompts,
and the next interactive command with its pre-execution hooks

## Validation

Local checks on macOS aarch64 with Rust 1.97.1 at `2bcf4099e`

| Command | Result |
| --- | --- |
| `cargo test --locked --profile ci -p nu-cli --lib --
command_after_interrupted_prompt_runs_hooks_and_command` | Fails without
prompt-boundary recovery at the transient prompt assertion, passes with
the fix |
| `cargo build --locked --profile ci --bin nu` | Passed |
| `cargo test --locked --profile ci -p nu-cli --no-fail-fast` | 200 unit
tests and 295 integration tests passed, 2 ignored |
| `cargo test --locked --profile ci --test tests -- shell::` | 341
passed, 6 ignored, including all 29 background-job tests |
| `cargo test --locked --profile ci --bin nu -- signals::` | 3 passed |
| `cargo nuclippy` | Passed |
| `cargo check --locked --profile ci --no-default-features --bin nu` |
Passed |
| `cargo fmt --all` and `cargo fmt --all --check` | Passed |
| `typos` 1.51.1 | Passed |
| `git diff --check` | Passed |

Manual PTY checks passed for prompt errors remaining visible, completion
and transient-prompt recovery before Enter, subsequent hook and command
execution, editor-interrupt recovery, background and frozen job
preservation, and foreground cancellation
The regression test emitted no shell-integration OSC or application-mode
reset sequences

## Additional notes

The command-boundary recovery retains a short race for a SIGINT arriving
after Enter but before the reset
This is a trade-off to recover editor interruptions, not a claim that
the race is eliminated

One initial baseline PTY launch in this follow-up timed out after 30
seconds without output, while the rerun and updated-binary probes passed
The earlier validation also recorded one 60-second PTY startup timeout
The causes were not established and the passing reruns do not erase
those observations

This reproduction did not demonstrate actual job deletion, so this PR
does not claim to resolve every scenario in #18989 or close that issue

Windows and Linux runtime validation is deferred to GitHub CI and is not
included in the local results above
2026-10-24 18:54:48 -05:00
Tarık KöşkerandClaude Sonnet 5.5 1cc2a97be3 fix(cd): resolve Windows drive-relative paths like d: the way cmd does (#19332)
## Description

On Windows, `cd d:` didn't work because `d:` is a drive-relative path
and nu just joined it onto the current directory. This makes nu handle
drive-relative paths (`d:`, `d:foo`, `d:..`) the way cmd does. It's one
helper, `nu_path::resolve_drive_relative`, used by both `cd` and
auto-cd:

- If it's the same drive as `$env.PWD`, it resolves against `$env.PWD`.
So `cd c:` in `C:\work` stays in `C:\work`, and `cd c:sub` goes to
`C:\work\sub`.
- If it's another drive, you end up in that drive's current directory
inherited from the parent process, or its root.

`cd -P` follows the same rule, and errors show the path as you typed it.

## User-facing changes (Release notes)

On Windows, `cd d:`, `cd d:folder` and just typing `d:` (auto-cd) now
work. If you're already on that drive you stay where you are. Otherwise
you land in that drive's current directory from the parent shell, or its
root.

## Additional notes

Refs #13091

Used Claude Code to draft this change; I reviewed the diff and the test
results.

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 07:51:03 -05:00
Darren Schroeder e68ab52e43 Add generate completions to auto-generate extern definitions, with completions, from carapace, zsh, fish, man pages and --help (#19314)
## Description

Nushell checks a call to an internal command before it runs, but an
external command only gets that once someone writes an `extern` for it,
flag by flag, and completions only once someone writes a completer for
it. Other tools already describe thousands of commands: carapace specs,
fish and zsh completion files, man pages, and each command's `--help`.
`generate completions <command>` reads one of them and returns the text
of a module of `export extern` definitions, with completer commands.

You save that text and `use` or `source` it, or save it in an autoload
dir. For `use`, the file needs a name other than the tool's, such as
`git-completions.nu`, because `use` names the module after the file and
a module can't export an extern with its own name.

- carapace (`carapace <tool> export`), fish and zsh give the whole
subcommand tree. man and `--help` give the flags of the named command,
so `generate completions "git status"` reads `man git-status` or `git
status --help`.
- Without `--source`, the first source that knows any flags wins, in the
order carapace, fish, zsh, man, help. `--source all` merges every source
that knows any flags. When sources disagree, the earlier source wins. A
flag they disagree on taking a value becomes a switch, and a flag any
source says takes an optional value is left undeclared.
- Piped text is read as the source `--source` names, as in `^git status
-h | generate completions "git status" --source help`.
- A signature can't declare flags with an optional value
(`--color[=when]`) or single-dash long options (`-name`). Those are
listed in each extern's extra description, and they still reach the
tool.

With `@complete external`, an external completer like carapace also
lists the flags the signature declares, so flag completion showed each
of them twice. Flag-name completion now drops command-wide suggestions
that repeat a declared flag.

## User-facing changes (Release notes)

- The new `generate completions` command writes `extern` definitions for
an external command from its carapace spec, fish or zsh completions, man
page or `--help` text, and `--source all` merges what every source
knows:

  ```nushell
generate completions git | save ($nu.user-autoload-dirs | first | path
join git-completions.nu)
  ```

The module completes flag values and arguments the source knows about:
fixed lists, commands that fish runs (git branches, remotes, tags),
shared lists such as users and hosts, and, for tools built with cobra
such as gh, docker and kubectl, the tool's own answers.
- Flag-name completion no longer lists a flag twice when an extern with
`@complete external` declares it and the external completer lists it
too.

## Additional notes

- Every module generated from fish's 1,070 completion files (782
modules, 186 with completers), zsh's 966 (681 modules) and Homebrew's
139 zsh files (129 modules) passes `nu-check --as-module`. So does every
module from each source for git, ssh, make, rg, gh, tar, brew, curl,
cargo, kubectl and docker, and from `--source all`.
- `generate completions` refuses a command named like a nushell keyword
(fish ships completions for `if`, `source`, `while`), since an extern
can't have that name.
- bash and PowerShell aren't sources. bash completions are code that
mostly calls `_parse_help` on `--help`, which the help source already
reads, and PowerShell's completers for native commands are script blocks
registered at runtime.
- The help source runs `<command> --help` with no input, the man source
runs `man` with `MANPAGER=cat`, and a tool with a `completion`
subcommand is asked `<tool> __complete ""` to find out whether it's
built with cobra.
2026-10-24 07:05:21 -05:00
Tarık KöşkerandClaude Sonnet 5.5 8b3ce32f1b fix: don't rewrite path separators for external args that merely contain ... (#19333)
## Description
`expand_ndots_safe` decided to run `expand_ndots` whenever the argument
contained the substring `...`. `expand_ndots` normalizes the whole path,
so on Windows an argument such as `origin/main...` (a git revision
range) came out as `origin\main...`, breaking `git diff --name-only
origin/main...`.

Now n-dots expansion only runs when a whole path component (split on `/`
or `\`) consists solely of 3+ dots (e.g. `.../foo`, `a/.../b`).
`is_ndots` was hoisted from `expand_ndots` to module level to be shared.
The `://` and `./` exclusions are unchanged.

## Before / after (Windows)
```
> cmd /c echo origin/main...
origin\main...        # before
origin/main...        # after
> cmd /c echo a/b/...
a\b\..\..             # unchanged (real n-dots component)
```

## Tests
- Added `dots_inside_component_untouched` in `nu-path`
(`origin/main...`, `a.../b`).
- `cargo test -p nu-path`: 68 passed; `cargo test --test tests -- dots
external`: 158 passed.
- `cargo fmt --all`, `cargo clippy -p nu-path --all-targets -- -D
warnings -D clippy::unwrap_used` clean.

## User-facing changes (Release notes)
External command arguments containing `...` inside a path component
(e.g. `origin/main...`) are no longer rewritten with backslashes on
Windows.

## Additional notes
Fixes #16858

Used Claude Code to draft this change; I reviewed the diff and the test
results.

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-23 19:07:27 -05:00
Aradhya Jain a0b69c9f99 uniq: add --keep-last, matching uniq-by (#19326)
## Description

`uniq-by` has a `--keep-last` switch ("return the last occurrence of
each
unique value instead of the first"), but plain `uniq` never got the same
flag -- even though the shared `uniq()` function both commands call
already reads the `"keep-last"` flag unconditionally. Because `Uniq`'s
`signature()` never declared it, the parser wouldn't even let you type
`uniq --keep-last`.

This adds the same `--keep-last` switch to `uniq`, copying `uniq-by`'s
existing declaration. No new logic -- the shared `uniq()` function
already
implements the behavior. Also skips the sqlite `SELECT DISTINCT`
pushdown
optimization when the flag is set, since that pushdown can't honor "last
occurrence" semantics.

## User-facing changes (Release notes)

- Added a `--keep-last`/`-l` flag to `uniq`, matching `uniq-by`, to keep
  the last occurrence of each duplicate value instead of the first.

## Additional notes

n/a
2026-10-23 14:06:41 -05:00
Darren Schroeder c77c34bc93 Add @structured attribute so an extern can return data (#19316)
## Description

Getting data out of an external tool means remembering its JSON flag and
piping it through `from json`, every time. `@structured [args] { decode
}` puts that in the extern once:

```nushell
@structured [--json=v2] { from json | get formulae }
extern "brew outdated" []

brew outdated | where pinned == false   # nu runs `brew outdated --json=v2` and decodes it
brew outdated                           # brew's own text, as before
```
### Example
With the `@structured` in the script above:
```nushell
> brew outdated
brotli (1.2.0_1) < 1.2.1
node (26.12.0) < 26.12.1
pspg (5.8.16) < 5.9.0
ruby (4.0.7_1) < 4.0.8
```
But when you pipe it:
```nushell
> brew outdated | where pinned == false
╭───┬────────┬────────────────────┬─────────────────┬────────┬────────────────╮
│ # │  name  │ installed_versions │ current_version │ pinned │ pinned_version │
├───┼────────┼────────────────────┼─────────────────┼────────┼────────────────┤
│ 0 │ brotli │ ╭───┬─────────╮    │ 1.2.1           │ false  │                │
│   │        │ │ 0 │ 1.2.0_1 │    │                 │        │                │
│   │        │ ╰───┴─────────╯    │                 │        │                │
│ 1 │ node   │ ╭───┬─────────╮    │ 26.12.1         │ false  │                │
│   │        │ │ 0 │ 26.12.0 │    │                 │        │                │
│   │        │ ╰───┴─────────╯    │                 │        │                │
│ 2 │ pspg   │ ╭───┬────────╮     │ 5.9.0           │ false  │                │
│   │        │ │ 0 │ 5.8.16 │     │                 │        │                │
│   │        │ ╰───┴────────╯     │                 │        │                │
│ 3 │ ruby   │ ╭───┬─────────╮    │ 4.0.8           │ false  │                │
│   │        │ │ 0 │ 4.0.7_1 │    │                 │        │                │
│   │        │ ╰───┴─────────╯    │                 │        │                │
╰───┴────────┴────────────────────┴─────────────────┴────────┴────────────────╯
```

## User-facing changes (Release notes)

- The new `@structured [args] { decode }` attribute lets an extern
return data. When nushell uses the output as data (piped into an
internal command, or saved with `let`), it adds the args to the call and
decodes the output with the block. At the terminal, through `print`, in
a file or piped into another external command, the tool's own output is
unchanged:

  ```nushell
@structured [--porcelain] { lines | parse --regex '^(?<status>..)
(?<file>.+)$' }
  extern "git status" []

git status | where status =~ M | get file # runs `git status
--porcelain` and parses it
  git status                                  # git's own text
  ```

When you run the extern by itself:
```nushell
> git status
On branch extern_structured
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   crates/nu-cli/src/commands/print.rs
        modified:   crates/nu-cmd-lang/src/core_commands/attr/mod.rs
        modified:   crates/nu-cmd-lang/src/core_commands/do_.rs
        modified:   crates/nu-cmd-lang/src/core_commands/ignore.rs

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        crates/nu-cmd-lang/src/core_commands/attr/structured.rs
        crates/nu-command/tests/commands/attr_structured.rs

no changes added to commit (use "git add" and/or "git commit -a")
```
But when you pipe it, it's now able to be converted to nushell data.
```nushell
> git status | where status =~ M
╭────┬────────┬──────────────────────────────────────────────────╮
│  # │ status │                       file                       │
├────┼────────┼──────────────────────────────────────────────────┤
│  0 │  M     │ crates/nu-cli/src/commands/print.rs              │
│  1 │  M     │ crates/nu-cmd-lang/src/core_commands/attr/mod.rs │
│  2 │  M     │ crates/nu-cmd-lang/src/core_commands/do_.rs      │
│  3 │  M     │ crates/nu-cmd-lang/src/core_commands/ignore.rs   │
╰────┴────────┴──────────────────────────────────────────────────╯
```
## Additional notes

- When the tool fails, the pipeline stops with the tool's own error
output and exit code, as `^tool --json | from json` does today.
- The user's arguments come after the structured args, so a flag that
picks another output format (`kubectl get pods -o wide | lines`) wins
and the decode fails. `^kubectl get pods -o wide` runs as written. When
an extern has more than one `@structured`, the last one is used. Both
are in `help attr structured`.
- `tee` gets the tool's own output and passes that text on, so `brew
outdated | tee { save -f log.txt } | lines` works on brew's text.
- Only errors raised while the decode block runs get the label at the
call. An error from a stream the block returns, read later, points at
the block only.
- `brew outdated | do { ^cat }` still decodes: the next command is `do`,
which doesn't look into its block for `pipe_redirection()`.
- `OutDest` and `RedirectMode` in `nu-protocol` each gain a variant, so
an exhaustive `match` on either outside this repo needs a `PipeRaw` arm.
2026-10-23 07:56:35 -05:00
Darren Schroeder d2340dc1c5 Remove file accidentially committed (#19331)
<!--
Thanks for contributing to Nushell!

Before submitting, please read the contributing guide:
https://github.com/nushell/nushell/blob/main/CONTRIBUTING.md

This template helps reviewers understand your changes and allows us to
generate high-quality release notes.
-->

## Description

just remove a file accidentally committed
<!--
Explain what this PR does and why.

This section is intentionally flexible:
- Describe the problem
- Explain your approach
- Include technical details if relevant

Good examples:
- "In this PR, I fixed..."
- "In this PR, I added support for..."
- "This change improves X by..."

Write as much or as little as needed for reviewers to understand your
changes.
-->

## User-facing changes (Release notes)
<!--
This section is used (mostly as-is) for https://www.nushell.sh/blog/

Describe how Nushell behavior changes from a user's perspective.
Do NOT describe internal Rust changes here.

Write in a release note style, for example:
- "Added support for..."
- "Fixed an issue where..."
- "Nushell now supports..."
- "Improved performance of..."

If your changes do NOT affect users (internal refactors, cleanup, etc.),
just write:
- "n/a"
- "nan"
- or similar

This tells us the change should not appear in the changelog.

Tips:
- Focus on observable behavior
- Include examples if helpful
- Keep it concise

You can:
- Write a short paragraph (will appear as a bullet point), OR
- Use headings (###) if your change needs more structure

Avoid writing things like:
- "In this PR, I refactored..."
- "This updates internal code..."

You may leave this blank until the PR is ready.
-->

## Additional notes
<!--
Optional.

Examples:
- fixes #123
- closes #456
- related #789

Anything else reviewers should know.
Remove this section if not needed.
-->
2026-10-23 07:48:28 -05:00
Darren Schroeder 02d39b88e9 Add extern --strict to reject undeclared flags (#19313)
## Description

An `extern` signature drives completions, but it doesn't guard anything.
`extern "git status" [--short(-s)]; git status --shrt` passes `--shrt`
to git, and git prints its own usage error. That's because externs
accept unknown arguments, so nushell can wrap a tool without declaring
every flag it has.

`extern --strict` (and `export extern --strict`) turns a flag the
signature doesn't declare into a parse error, with the "Did you mean"
hint that internal commands already give. Everything else an extern
accepts still works: positional arguments, `--` and the arguments after
it all reach the tool. `--help` is always allowed, so `git status
--help` still shows git's help. `-h` isn't exempt, since it means
something else for some tools (`ls -h`, `grep -h`).

### Before & After

| Command | Before PR | After PR |
| --- | --- | --- |
| `extern --strict "git status" [--short(-s)]; git status --shrt` |
``The `extern` command doesn't have flag `strict`.`` | ``The `git
status` command doesn't have flag `shrt`.``, help: ``Did you mean:
`--short`?`` |
| `extern --strict "git status" [--short(-s)]; git status -x` | same
`strict` error | ``The `git status` command doesn't have flag `-x`.`` |
| `extern --strict "git status" [--short(-s)]; git status -s -- --shrt`
| same `strict` error | runs `git status -s -- --shrt` |
| `extern --strict "git status" [--short(-s)]; git status --help` | same
`strict` error | git's help |
| `module g { export extern --strict "git status" [--short(-s)] }; use g
"git status"; git status --shrt` | same `strict` error | ``The `git
status` command doesn't have flag `shrt`.`` |
| `extern "git status" [--short(-s)]; git status --shrt` | git: ``error:
unknown option `shrt'`` | same |
| `extern --strict printf []; printf "%s\|" -10` | same `strict` error |
`-10\|` |
| `extern --strict printf []; let n = 3; let f = "x"; printf "%s\|" -$n
-($n) --($f)` | same `strict` error | `-$n\|-3\|--x\|` |
| `extern printf [--x: string]; printf "%s\|" --x (ls --bogus) hello` |
`--x\|hello\|` | ``The `ls` command doesn't have flag `bogus`.`` |
| `def --wrapped w [--x: string, ...rest] { $rest \| to nuon }; w --x
(ls --bogus) hello` | `[--x, hello]` | ``The `ls` command doesn't have
flag `bogus`.`` |

## User-facing changes (Release notes)

- `extern --strict` makes a flag that the signature doesn't declare a
parse error, with a "Did you mean" hint. `--`, the arguments after it,
and `--help` still reach the external command.
- An unknown flag inside the value of a declared flag, as in `cmd --x
(ls --bogus)`, is now reported for externs and `def --wrapped` commands.
Before, the error was dropped and `--x` reached the command without its
value.

## Additional notes
<!--
Optional.

Examples:
- fixes #123
- closes #456
- related #789

Anything else reviewers should know.
Remove this section if not needed.
-->
2026-10-23 07:39:45 -05:00
Jack Wright 25639896e0 Allow Custom Types to be used in type signatures (#19311)
## Description

Changes the way that custom types are exposed in order to allow them to
be used in type signatures. This also enabled them to be resolved
correctly in the LSP.

## User-facing changes (Release notes)

- Custom types can now be used within type signatures. For plugins,
custom types for all installed plugins can be use. They will resolve
appropriately in the Nushell LSP. The following example show how to set
the return type for a command

```
def f [v: semver]: semver -> semver { $v }                              │

def ls-df [ ]: nothing -> polars_dataframe {
  ls | polars into-df 
}
```
2026-10-23 07:24:11 -05:00
Darren Schroeder 89e6efe441 fix(nu-mcp): keep $history indices stable, run evaluations one at a time, and correct stale guidance in the MCP instructions and AGENTS.md (#19318)
## Description

Once `$history` was full, each new evaluation shifted every older entry
down by one. `History::push` returned the buffer length after evicting,
so an index from an earlier response could point at a later result,
while the instructions promised "indices do not shift, older ones simply
become unavailable". This PR makes that promise true: indices only
increase, and an evicted index reads as `null`. `push` also evicts until
the buffer fits the limit instead of dropping one entry per push, so
lowering `NU_MCP_HISTORY_LIMIT` trims `$history` to the new limit.

Two `evaluate` calls sent at once (agents send parallel tool calls) each
forked the same state, and the one that finished last overwrote the
other. Both responses reported the same `history_index`, and the other
call's `$history` entry and `$env` changes were lost. Evaluations now
run one at a time, like lines typed into a REPL: a lock is held from
fork to commit and released early when an evaluation is promoted to a
background job. `list_commands` and `command_help` don't wait for it.

The rest of the text `nu --mcp` sends to agents (`instructions.md`,
`evaluate_tool.md`, and the `list_commands` / `command_help`
descriptions) also gave advice that nushell contradicts. It said `ls
**/*` walks hidden directories and `glob` avoids them, when the reverse
is true. It used a `job spawn --tag` flag that was renamed in #17496,
and said `command_help` shows input/output types, which it doesn't. The
`evaluate` tool description still told agents to avoid large output,
which contradicts the server instructions sent in the same session. This
PR rewrites those passages to match nushell, tones down the all-caps
"THE RULE" section while keeping the rule and its reason, and fills in
the two short tool descriptions with their real output format and
limits.

In `AGENTS.md`, it fixes the claim that `cargo nuclippy-tests` runs all
tests (it runs clippy), says how integration-test targets are named in
crates without a `tests` target, states three wordy or hedged rules more
plainly, and fixes a typo.

## User-facing changes (Release notes)

- In `nu --mcp`, `$history` indices no longer shift when old entries are
evicted. An evicted index reads as `null`, and `$history | length`
counts every result stored in the session. Lowering
`NU_MCP_HISTORY_LIMIT` now trims `$history` to the new limit.
- `nu --mcp` now runs `evaluate` calls one at a time. Before, two calls
sent together could get the same `history_index`, and one call's
`$history` entry and `$env` changes were lost.
- The MCP server's instructions and tool descriptions now match
nushell's behavior for `ls` vs `glob` on hidden directories, `job spawn
--description`, `command_help` output, and `\u{...}` escapes.
- The `evaluate` tool description no longer tells agents to avoid large
output. Output over the limit already comes back as a `note` pointing at
`$history`.

## Additional notes
<!--
Optional.

Examples:
- fixes #123
- closes #456
- related #789

Anything else reviewers should know.
Remove this section if not needed.
-->
2026-10-23 06:04:39 -05:00
Jack Wright de7d7584cb Added the local_socket feature for nu-plugin-test-support for formats… (#19319) 2026-10-22 22:20:14 -07:00
Jack Wright a12aca2606 Fix polars test breakages (#19317)
## Description

The local_socket feature needed to be added to the
nu-plugin-test-support dep.
2026-10-22 13:01:14 -05:00
Manish d1064f1ae1 fix(print): surface external failures instead of masking exit code (#19227) (#19260)
## Description

Fixes #19227. `print` ignored failures of external commands because it
called `ignore_error(true)` on the child's byte streams, so a pipeline
such as a failing external command piped into `print` exited with 0
while the same failure from an internal command exited with 1. This
removes the suppression so non-zero exits propagate. Tests were added to
`pipefail_feature` (`fail 30 | print`, `print --raw`, `print -e`) plus
`pipefail_print_keeps_output_before_failure` and
`pipefail_print_stderr_keeps_output_before_failure`, which check that
output still reaches stdout / stderr before the failure exit code.

`^cmd | print <args>` still drops the piped input without waiting on the
child, so with pipefail off it still exits 0, the same as `| ignore`.

Tests run: `cargo test --test tests -- pipefail_feature`, `cargo clippy
--tests`, `cargo fmt --all -- --check`.

## User-facing changes (Release notes)

Fixed an issue where `print` hid the failure of an external command: a
failing external command piped into `print` now makes the pipeline fail
with its non-zero exit code instead of exiting with 0. This is a
behavior change for scripts that relied on the old result, for example
`^grep pat file | print` with no match now errors, and `do -i { ^false }
| print` now fails like `do -i { ^false } | collect` already does.

## Additional notes

fixes #19227
2026-10-21 14:20:16 -05:00
Darren Schroeder f196eaf8a7 fix(table): shrink the widest columns first and honor width priorities everywhere (#19303)
## Description

Since #19007, `table --expand` squeezed short columns to 4 characters
whenever another column held a nested table. The nested-table column
took every spare character before any other column grew, so an `env`
listing printed `SOME_BIG_SESSION_ENV_VAR` as seven 4-character lines.
`table --expand` also ignored `metadata set
--table-width-priority-columns`. So did `table` at 120 columns or less,
unless wrapping and header-on-separator were both on.

An `env`-style listing with nested values, `table -e`, header on the
separator, 100 wide:

```nushell
$env.config.table.header_on_separator = true; [[key value]; [CLAUDE_CODE_CHILD_SESSION 1] [HOME /Users/fdncred] [PATH [/Users/fdncred/.local/bin /usr/local/bin /opt/homebrew/opt/python/libexec/bin /Users/fdncred/.cargo/bin /opt/homebrew/opt/uutils-coreutils/libexec/uubin]] [FPATH "/Users/fdncred/.grok/completions/zsh:/Users/fdncred/.zsh:/opt/homebrew/share/zsh/site-functions:/usr/local/share/zsh/site-functions"]] | table -e -w 100
```

Before:
```nushell
╭─#─┬─key──┬─────────────────────────────────────────value─────────────────────────────────────────╮
│ 0 │ CLAU │                                                                                     1 │
│   │ DE_C │                                                                                       │
│   │ ODE_ │                                                                                       │
│   │ CHIL │                                                                                       │
│   │ D_SE │                                                                                       │
│   │ SSIO │                                                                                       │
│   │ N    │                                                                                       │
│ 1 │ HOME │ /Users/fdncred                                                                        │
│ 2 │ PATH │ ╭───┬──────────────────────────────────────────────────╮                              │
│   │      │ │ 0 │ /Users/fdncred/.local/bin                        │                              │
│   │      │ │ 1 │ /usr/local/bin                                   │                              │
│   │      │ │ 2 │ /opt/homebrew/opt/python/libexec/bin             │                              │
│   │      │ │ 3 │ /Users/fdncred/.cargo/bin                        │                              │
│   │      │ │ 4 │ /opt/homebrew/opt/uutils-coreutils/libexec/uubin │                              │
│   │      │ ╰───┴──────────────────────────────────────────────────╯                              │
│ 3 │ FPAT │ /Users/fdncred/.grok/completions/zsh:/Users/fdncred/.zsh:/opt/homebrew/share/zsh/site │
│   │ H    │ -functions:/                                                                          │
│   │      │ usr/local/share/zsh/site-functions                                                    │
╰───┴──────┴───────────────────────────────────────────────────────────────────────────────────────╯
```

After:
```nushell
╭─#─┬────────────key────────────┬──────────────────────────────value───────────────────────────────╮
│ 0 │ CLAUDE_CODE_CHILD_SESSION │                                                                1 │
│ 1 │ HOME                      │ /Users/fdncred                                                   │
│ 2 │ PATH                      │ ╭───┬──────────────────────────────────────────────────╮         │
│   │                           │ │ 0 │ /Users/fdncred/.local/bin                        │         │
│   │                           │ │ 1 │ /usr/local/bin                                   │         │
│   │                           │ │ 2 │ /opt/homebrew/opt/python/libexec/bin             │         │
│   │                           │ │ 3 │ /Users/fdncred/.cargo/bin                        │         │
│   │                           │ │ 4 │ /opt/homebrew/opt/uutils-coreutils/libexec/uubin │         │
│   │                           │ ╰───┴──────────────────────────────────────────────────╯         │
│ 3 │ FPATH                     │ /Users/fdncred/.grok/completions/zsh:/Users/fdncred/.zsh:/opt/ho │
│   │                           │ mebrew/share/zsh/site-functions:/usr/local/share/zsh/site-functi │
│   │                           │ ons                                                              │
╰───┴───────────────────────────┴──────────────────────────────────────────────────────────────────╯
```

A `plugin list`-shaped table, `table -e`, 120 wide:

```nushell
[[name version status pid filename shell commands]; [dns 4.0.13-alpha.1 loaded null C:\Users\x\.cargo\bin\nu_plugin_dns.exe null [[name description]; ["dns query" "Perform a DNS query"]]] [file 0.27.0 loaded null C:\Users\x\.cargo\bin\nu_plugin_file.exe null [[name description]; [file "View file format information"]]]] | table -e -w 120
```

Before:
```nushell
╭───┬──────┬────────────────┬────────┬─────┬──────────────────────────────────────────┬───────┬────────────────────────╮
│ # │ name │    version     │ status │ pid │                 filename                 │ shell │        commands        │
├───┼──────┼────────────────┼────────┼─────┼──────────────────────────────────────────┼───────┼────────────────────────┤
│ 0 │ dns  │ 4.0.13-alpha.1 │ loaded │     │ C:\Users\x\.cargo\bin\nu_plugin_dns.exe  │       │ ╭───┬───────────╮      │
│   │      │                │        │     │                                          │       │ │ # │   name    │      │
│   │      │                │        │     │                                          │       │ ├───┼───────────┤      │
│   │      │                │        │     │                                          │       │ │ 0 │ dns query │      │
│   │      │                │        │     │                                          │       │ ╰───┴───────────╯      │
│ 1 │ file │ 0.27.0         │ loaded │     │ C:\Users\x\.cargo\bin\nu_plugin_file.exe │       │ ╭───┬──────┬─────────╮ │
│   │      │                │        │     │                                          │       │ │ # │ name │ descrip │ │
│   │      │                │        │     │                                          │       │ │   │      │ tion    │ │
│   │      │                │        │     │                                          │       │ ├───┼──────┼─────────┤ │
│   │      │                │        │     │                                          │       │ │ 0 │ file │ View    │ │
│   │      │                │        │     │                                          │       │ │   │      │ file    │ │
│   │      │                │        │     │                                          │       │ │   │      │ format  │ │
│   │      │                │        │     │                                          │       │ │   │      │ informa │ │
│   │      │                │        │     │                                          │       │ │   │      │ tion    │ │
│   │      │                │        │     │                                          │       │ ╰───┴──────┴─────────╯ │
╰───┴──────┴────────────────┴────────┴─────┴──────────────────────────────────────────┴───────┴────────────────────────╯
```

After:
```nushell
╭───┬──────┬────────────────┬────────┬─────┬─────────────────────────────────┬───────┬─────────────────────────────────╮
│ # │ name │    version     │ status │ pid │            filename             │ shell │            commands             │
├───┼──────┼────────────────┼────────┼─────┼─────────────────────────────────┼───────┼─────────────────────────────────┤
│ 0 │ dns  │ 4.0.13-alpha.1 │ loaded │     │ C:\Users\x\.cargo\bin\nu_plugin │       │ ╭───┬───────────┬─────────────╮ │
│   │      │                │        │     │ _dns.exe                        │       │ │ # │   name    │ description │ │
│   │      │                │        │     │                                 │       │ ├───┼───────────┼─────────────┤ │
│   │      │                │        │     │                                 │       │ │ 0 │ dns query │ Perform a   │ │
│   │      │                │        │     │                                 │       │ │   │           │ DNS query   │ │
│   │      │                │        │     │                                 │       │ ╰───┴───────────┴─────────────╯ │
│ 1 │ file │ 0.27.0         │ loaded │     │ C:\Users\x\.cargo\bin\nu_plugin │       │ ╭───┬──────┬──────────────────╮ │
│   │      │                │        │     │ _file.exe                       │       │ │ # │ name │   description    │ │
│   │      │                │        │     │                                 │       │ ├───┼──────┼──────────────────┤ │
│   │      │                │        │     │                                 │       │ │ 0 │ file │ View file format │ │
│   │      │                │        │     │                                 │       │ │   │      │  information     │ │
│   │      │                │        │     │                                 │       │ ╰───┴──────┴──────────────────╯ │
╰───┴──────┴────────────────┴────────┴─────┴─────────────────────────────────┴───────┴─────────────────────────────────╯
```

A record with a 100-character key, `table -w 60`:

```nushell
{("k" | fill -c k -w 100): 1, b: 2} | table -w 60
```

Before:
```nushell
╭────────────────────────────────────────────────────┬─────╮
│ kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk │ ... │
│ kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk │     │
│ b                                                  │ ... │
╰────────────────────────────────────────────────────┴─────╯
```

After:
```nushell
╭──────────────────────────────────────────────────────┬───╮
│ kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk │ 1 │
│ kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk     │   │
│ b                                                    │ 2 │
╰──────────────────────────────────────────────────────┴───╯
```

CJK headers with `header_on_separator`, `table -e`: This intentionally
doesn't draw the characters on the headers, even when the setting is set
to true, in order to avoid misaligned tables. (images convey this better
below)

```nushell
$env.config.table.header_on_separator = true; [[id 名前 inner]; [1 漢字 [[鍵 a]; [x 1]]]] | table -e
```

Before:
<img width="1672" height="718" alt="image"
src="https://github.com/user-attachments/assets/773cd8f2-9fe1-4185-bf0c-c0a1637e7deb"
/>

After:
<img width="1672" height="924" alt="image"
src="https://github.com/user-attachments/assets/09cdbc27-0425-4547-a8e2-902ff725e6dd"
/>



## User-facing changes (Release notes)

- `table` and `table --expand` shrink the widest columns first, so short
columns such as keys, names and sizes keep their width next to long text
or nested tables.
- `metadata set --table-width-priority-columns`, which `ls` and `ps`
also set, now works with `table --expand` and at every terminal width. A
priority column shows wherever it would without the priority, and
columns to its right hide to leave it up to a third of the table width.
- `table --expand` draws a nested table whenever it fits, hiding columns
to its right first and collapsing the nested table's own columns behind
`...`, instead of showing `[table N rows]`. Nested tables no longer drop
columns without a `...` marker.
- Tables keep each visible column at least 10 characters wide (or its
natural width), hiding columns from the right when they don't fit.
Without `header_on_separator` this shows more columns on narrow
terminals; with it, fewer, since columns are no longer squeezed to 4
characters.
- Record keys wrap when a key is too long for the terminal, instead of
hiding the values.
- With `header_on_separator`, headers with CJK characters, emoji or
Arabic ligatures are drawn in their own row, so the table border lines
up.

## Additional notes
<!--
Optional.

Examples:
- fixes #123
- closes #456
- related #789

Anything else reviewers should know.
Remove this section if not needed.
-->
2026-10-21 09:10:05 -05:00
dependabot[bot]andDarren Schroeder 68451e6b28 build(deps): bump tango-bench from 0.8.0 to 0.9.0 (#19305)
Bumps [tango-bench](https://github.com/bazhenov/tango) from 0.8.0 to
0.9.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/bazhenov/tango/releases">tango-bench's
releases</a>.</em></p>
<blockquote>
<h2>v0.9.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Add --strip-candidate/--strip-baseline to compare benchmarks from
the same executable by <a
href="https://github.com/bazhenov"><code>@​bazhenov</code></a> in <a
href="https://redirect.github.com/bazhenov/tango/pull/83">bazhenov/tango#83</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/bazhenov/tango/compare/v0.8.0...v0.9.0">https://github.com/bazhenov/tango/compare/v0.8.0...v0.9.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/bazhenov/tango/commit/6226638e0b40a094e87e83ffd5da5aa66ddee26a"><code>6226638</code></a>
Release 0.9.0</li>
<li><a
href="https://github.com/bazhenov/tango/commit/1d033ad9dc51d9bd7865c3b60b9170acb7a75c7c"><code>1d033ad</code></a>
Adding script to check how stable cputime is in GH CI</li>
<li><a
href="https://github.com/bazhenov/tango/commit/c8150c430a1348a9b81bcd52e3e5ff32c842f5cf"><code>c8150c4</code></a>
Increasing number of iterations in cputime test</li>
<li><a
href="https://github.com/bazhenov/tango/commit/a6b0547b84fcf886259390bad40e2ac61c16aa99"><code>a6b0547</code></a>
IndexedBenchmark type added to protected agains index shifting when
filtering...</li>
<li><a
href="https://github.com/bazhenov/tango/commit/03a24743a0cb1a900cd1a24acf9155e085504e46"><code>03a2474</code></a>
Delete dead code</li>
<li><a
href="https://github.com/bazhenov/tango/commit/1ef340141e02398116b7c0b7d808db2cd1010584"><code>1ef3401</code></a>
Merging binary search benchmarks into a single one</li>
<li><a
href="https://github.com/bazhenov/tango/commit/4a59272827e80c0e0c21dee11cbd4f4312438141"><code>4a59272</code></a>
Preserving order of benchmarks</li>
<li><a
href="https://github.com/bazhenov/tango/commit/801fdf0e3739462c18023806d990274abae1c940"><code>801fdf0</code></a>
Add --strip-candidate/--strip-baseline to compare benchmarks from the
same ex...</li>
<li>See full diff in <a
href="https://github.com/bazhenov/tango/compare/v0.8.0...v0.9.0">compare
view</a></li>
</ul>
</details>
<br />

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com>
2026-10-21 08:58:41 -05:00
Shubham 9a4454138f Take update cells columns as rest arguments and deprecate --columns (#19125)
## Description

`update cells` now takes the columns to update as rest arguments, and
`--columns` is deprecated. That's the direction agreed in #15477 and
matches `select`, `reject` and the `into` commands.

This picks up #17815, which was closed because the author stopped
responding (credit to @tauanbinato for the original change). I rebased
the idea onto current main, which also has `--recursive` now, and made
the follow-up changes @fdncred asked for there:

- the two `update cells -c [...]` calls in
`crates/nu-std/tests/test_std-rfc_tables.nu` now use rest arguments
- the `open` test in `crates/nu-command/tests/commands/open.rs` already
uses no `-c`, so it didn't need a change

A couple of details:

- `--columns` still works and shows the deprecation warning on first
use. If someone passes both, the two lists are merged.
- `-c []` still means "update no columns", and an empty spread like
`...$cols` with `$cols = []` means the same. Only calling it with no
flag and no columns at all updates everything, same as before.
- The rest parameter is named `rest`, like `select` and `reject`, so it
doesn't share a name with the deprecated `--columns` flag.
- Rest columns go through the same string coercion as `-c`, so int
column names work either way (`let cols = [1]; {"1": 1} | update cells {
$in + 1 } ...$cols`).
- The deprecation `since` is `0.117.0`, since 0.116.0 shipped without
it.

Checked with a local build:

```
> {a: 1, b: 2, c: 3} | update cells { $in + 10 } a c | to nuon
{a: 11, b: 2, c: 13}
> {a: 1, b: 2, c: 3} | update cells -c [a] { $in + 10 } | to nuon   # warns once, still works
{a: 11, b: 2, c: 3}
> {a: 1, b: 2, c: 3} | update cells -c [] { $in + 10 } | to nuon
{a: 1, b: 2, c: 3}
> {a: 1, b: 2, c: 3} | update cells -c [a] { $in + 10 } c | to nuon
{a: 11, b: 2, c: 13}
> let cols = []; {a: 1, b: 2, c: 3} | update cells { $in + 10 } ...$cols | to nuon
{a: 1, b: 2, c: 3}
> let cols = [1]; {"1": 1, b: 2} | update cells { $in + 1 } ...$cols | to nuon
{"1": 2, b: 2}
```

The converted example fails on main with `ExtraPositional` and passes
here. The new tests in
`crates/nu-cmd-extra/tests/commands/filters/update_cells.rs` cover
`--columns`, merging it with rest columns, empty column lists and int
column names. `cargo fmt --all -- --check`, `cargo clippy -p
nu-cmd-extra --all-targets -- -D warnings`, `cargo test -p nu-cmd-extra`
and the std test suite (`testing run-tests --path crates/nu-std`, 251
tests) all pass.

## User-facing changes (Release notes)

`update cells` now accepts the columns to update as rest arguments, and
the `--columns` (`-c`) flag is deprecated:

```nushell
# before
[[name val1 val2]; [foo 1 4] [bar 8 3]] | update cells -c [val1 val2] { $in * 2 }
# after
[[name val1 val2]; [foo 1 4] [bar 8 3]] | update cells { $in * 2 } val1 val2
```

## Additional notes

closes #15477
2026-10-21 08:35:57 -05:00
dependabot[bot] b05939d48c build(deps): bump arboard from 3.6.1 to 3.7.0 (#19307)
Bumps [arboard](https://github.com/1Password/arboard) from 3.6.1 to
3.7.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/1Password/arboard/releases">arboard's
releases</a>.</em></p>
<blockquote>
<h2>v3.7.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Return a conversion failure error when CGImageCreate fails by <a
href="https://github.com/complexspaces"><code>@​complexspaces</code></a>
in <a
href="https://redirect.github.com/1Password/arboard/pull/205">1Password/arboard#205</a></li>
<li>Properly encode/decode MIME=text/uri-list by <a
href="https://github.com/luca020400"><code>@​luca020400</code></a> in <a
href="https://redirect.github.com/1Password/arboard/pull/217">1Password/arboard#217</a></li>
<li>Increase windows-sys lower bound to 0.62 by <a
href="https://github.com/T-256"><code>@​T-256</code></a> in <a
href="https://redirect.github.com/1Password/arboard/pull/220">1Password/arboard#220</a></li>
<li>Add example to <code>Get</code> and <code>Set</code> by <a
href="https://github.com/Its-Just-Nans"><code>@​Its-Just-Nans</code></a>
in <a
href="https://redirect.github.com/1Password/arboard/pull/224">1Password/arboard#224</a></li>
<li>Add a <code>wait_once</code> to support waiting for just one
clipboard request by <a
href="https://github.com/joshtriplett"><code>@​joshtriplett</code></a>
in <a
href="https://redirect.github.com/1Password/arboard/pull/213">1Password/arboard#213</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/luca020400"><code>@​luca020400</code></a> made
their first contribution in <a
href="https://redirect.github.com/1Password/arboard/pull/217">1Password/arboard#217</a></li>
<li><a href="https://github.com/T-256"><code>@​T-256</code></a> made
their first contribution in <a
href="https://redirect.github.com/1Password/arboard/pull/220">1Password/arboard#220</a></li>
<li><a
href="https://github.com/Its-Just-Nans"><code>@​Its-Just-Nans</code></a>
made their first contribution in <a
href="https://redirect.github.com/1Password/arboard/pull/224">1Password/arboard#224</a></li>
<li><a
href="https://github.com/joshtriplett"><code>@​joshtriplett</code></a>
made their first contribution in <a
href="https://redirect.github.com/1Password/arboard/pull/213">1Password/arboard#213</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/1Password/arboard/compare/v3.6.1...v3.7.0">https://github.com/1Password/arboard/compare/v3.6.1...v3.7.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/1Password/arboard/commit/5f5c8637911ba219edee619105a19b4f74e66a9f"><code>5f5c863</code></a>
Release 3.7.0</li>
<li><a
href="https://github.com/1Password/arboard/commit/ab9663be5d27478399b215c1ab57f1d6574f74fc"><code>ab9663b</code></a>
Add example demonstrating <code>wait_once</code></li>
<li><a
href="https://github.com/1Password/arboard/commit/b9000b17a6a0c89e9c27f469f00d4e50c3910486"><code>b9000b1</code></a>
Add a <code>wait_once</code> to support waiting for just one clipboard
request</li>
<li><a
href="https://github.com/1Password/arboard/commit/2ea0ff6ddbcc80cc3b9f1a951879d416f775f753"><code>2ea0ff6</code></a>
wayland: Factor out option setting into a method</li>
<li><a
href="https://github.com/1Password/arboard/commit/b7e47c8d3b6b1c2d90e02e55969d0f92c543c2ed"><code>b7e47c8</code></a>
Update lib.rs</li>
<li><a
href="https://github.com/1Password/arboard/commit/2b2050eba1f6017721433a8640a9b2aae92014ba"><code>2b2050e</code></a>
Bump step-security/setup-rust-toolchain from 1.16.1 to 2.0.0</li>
<li><a
href="https://github.com/1Password/arboard/commit/6b0968206393df5a14c66d584f0d9f1f4afe9a1a"><code>6b09682</code></a>
Bump step-security/harden-runner from 2.20.0 to 2.21.1</li>
<li><a
href="https://github.com/1Password/arboard/commit/9f7b05ca9178e3c28ec5e59a522786a8ea591cce"><code>9f7b05c</code></a>
Bump actions/checkout from 4.3.1 to 7.0.0</li>
<li><a
href="https://github.com/1Password/arboard/commit/890e919929125f927e6f292091f7fbf9b37889e1"><code>890e919</code></a>
Apply GitHub Actions security best practices</li>
<li><a
href="https://github.com/1Password/arboard/commit/d7c6cc971baca5e7d6fe45c3c28cd828f351558e"><code>d7c6cc9</code></a>
bump windows-sys lower bound</li>
<li>Additional commits viewable in <a
href="https://github.com/1Password/arboard/compare/v3.6.1...v3.7.0">compare
view</a></li>
</ul>
</details>
<br />

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-21 08:07:31 -05:00
dependabot[bot] 2d2108decd build(deps): bump serde-saphyr from 1.3.0 to 2.0.0 (#19306)
Bumps [serde-saphyr](https://github.com/bourumir-wyngs/serde-saphyr)
from 1.3.0 to 2.0.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/bourumir-wyngs/serde-saphyr/releases">serde-saphyr's
releases</a>.</em></p>
<blockquote>
<h2>2.0.0 Performance and compliance release</h2>
<p>Breaking changes</p>
<ul>
<li>There is a new capture_comments feature that is default on and can
be disabled, winning about 10 % percent of performance. This feature was
the main reason to advance the first version digit, because formally
this is a breaking change.</li>
<li>Preserving inner error in alias errors in the newly added field in
<code>AliasError</code>. The old field (text representation) is still
present, but deprecated. Another formally breaking change, even if
unlikely to be a problem.</li>
<li>from_multiple, from_multiple_with_options, from_slice_multiple, and
from_slice_multiple_with_options now accept T: Deserialize&lt;'de&gt;
instead of T: DeserializeOwned, allowing values to borrow from the
input. Direct calls require no changes. Function pointers or callbacks
may need adjustments.</li>
<li>granit_parser 2.0.0 has some corner formally breaking changes, but
mostly in very obscure parts (see its changelog for details).</li>
</ul>
<p>All other changes are backward compatible:</p>
<ul>
<li>For projects aiming for very strict YAML compliance rather than
drop-in compatibility with mainstream libraries, it is not possible to
disable all compromises with <code>strict_indentation</code> flag in
Options.</li>
<li>Value serialization target can now receive <code>Inf</code> and
<code>NaN</code> if so configured. Even if most common serde_json::Value
cannot take them (produces <code>null</code> instead), many other
abstract value receivers can.</li>
<li>Made <code>huge_documents</code> and
<code>serde_derived_types</code> enable <code>deserialize</code>, fixing
isolated feature
builds with <code>--no-default-features</code>, including autopkgtests
of Debian team (as <a
href="https://dfsg-new-queue.debian.org/reviews/rust-serde-saphyr">observed</a>).</li>
<li>Fix borrow support for untagged enum (PR <a
href="https://redirect.github.com/bourumir-wyngs/serde-saphyr/issues/195">#195</a>,
thanks <a
href="https://github.com/Guiguiprim"><code>@​Guiguiprim</code></a>
).</li>
<li>Added <code>SerializerOptions::no_lang_directive</code> (default
<code>false</code>) to suppress the <code>%YAML 1.2</code> directive
independently of <code>yaml_12</code>'s quoting (requirement obvious
from <a
href="https://github.com/nushell/nushell/blob/d7cb4e589ea53bd1a0bb29dd78d63b76fcb59862/crates/nu-heavy-utils/src/yaml/serialize.rs#L158-L200">Nushell
code work work arrounds</a>).</li>
<li>Property interpolation can now be configured to be fully Docker
Compose compliant if preferred (we are not fans of undefined property
defaulting to empty but may be opinion-based).</li>
<li>It is possible to deserialize multiple documents into collection
other than vector: <a
href="https://docs.rs/serde-saphyr/latest/serde_saphyr/fn.from_str_multiple.html"><code>serde_saphyr::from_str_multiple</code></a>
supports any collection implementing <code>Default +
Extend&lt;T&gt;</code>, such as <code>Vec&lt;T&gt;</code>,
<code>VecDeque&lt;T&gt;</code>, <code>BTreeSet&lt;T&gt;</code>, or
custom storage like <a
href="https://docs.rs/smallvec/latest/smallvec/struct.SmallVec.html"><code>SmallVec&lt;T&gt;</code></a>.</li>
</ul>
<p>Other fixes</p>
<ul>
<li>Keep span offsets relative to the caller's input after a BOM (<a
href="https://redirect.github.com/bourumir-wyngs/serde-saphyr/issues/212">#212</a>)</li>
<li>Compare mapping keys regardless of entry order (<a
href="https://redirect.github.com/bourumir-wyngs/serde-saphyr/issues/211">#211</a>)</li>
<li>Report a collection where &amp;str is expected, not end of input (<a
href="https://redirect.github.com/bourumir-wyngs/serde-saphyr/issues/210">#210</a>)</li>
<li>Replace non-printable characters in Commented comments (<a
href="https://redirect.github.com/bourumir-wyngs/serde-saphyr/issues/209">#209</a>)</li>
<li>Implement dedicated YAML trim (<a
href="https://redirect.github.com/bourumir-wyngs/serde-saphyr/issues/206">#206</a>).
Default Rust trim() considers special Unicode whitespace chars that YAML
calls to be ignored.</li>
<li>Improve multi-snippet error rendering (<a
href="https://redirect.github.com/bourumir-wyngs/serde-saphyr/issues/208">#208</a>).
Do not rely on error texts for functionallity.</li>
<li>Fix serializer indentation after - and ? so output reads back- <a
href="https://redirect.github.com/bourumir-wyngs/serde-saphyr/issues/207">#207</a></li>
<li>Report a parser error after an implicit document end in
single-document entry points- <a
href="https://redirect.github.com/bourumir-wyngs/serde-saphyr/issues/220">#220</a>
<a
href="https://redirect.github.com/bourumir-wyngs/serde-saphyr/issues/220">#220</a>,
thanks <a
href="https://github.com/pcshrosbree"><code>@​pcshrosbree</code></a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/bourumir-wyngs/serde-saphyr/blob/master/CHANGELOG.md">serde-saphyr's
changelog</a>.</em></p>
<blockquote>
<h2>2.0.0</h2>
<h3>YAML changes</h3>
<ul>
<li>Tags selecting unit enum variants now reject non-null payloads
instead of silently
discarding them (<a
href="https://redirect.github.com/bourumir-wyngs/serde-saphyr/issues/236">#236</a>).
Use a bare variant name, a tag with empty content, or a
tag followed by <code>~</code> or <code>null</code>; quoted strings and
collections are rejected.</li>
<li>Composite mapping keys are not compared regardless of entry order
(thanks <a
href="https://github.com/yuxi-liu-wired"><code>@​yuxi-liu-wired</code></a>)
.</li>
<li>Commented<!-- raw HTML omitted --> now writes its output replacing
characters not allowed in comments (non printable) by spaces.</li>
</ul>
<h3>Added</h3>
<ul>
<li>Added public <code>path_map::PathKind</code>,
<code>PathKey::segments()</code>, and
<code>PathMap::locations_for()</code>
for inspecting validation paths and resolving their YAML use/definition
locations,
including best-effort spelling matches and recorded ancestor/root
fallback.</li>
<li>Added <code>RenderOptions::line_offset</code> and
<code>RenderOptions::source_name</code> for displaying
embedded YAML diagnostics at their containing document's line numbers
and naming
the root source in snippet headers, including the new
<code>miette::to_miette_report_with_options</code> entry point. Included
files retain their own
names and coordinates, and stored error locations and spans are
unchanged.</li>
<li>Added <code>PropertySyntax::DockerCompose</code> for
Compose-compatible property interpolation.</li>
<li>Added the default-enabled <code>comments</code> feature, forwarding
to granit-parser's matching
feature. Builds with <code>default-features = false</code> must enable
it to use <code>Commented&lt;T&gt;</code>,
<code>CommentPosition</code>, comment options, or comment budget fields
and reports. Without it,
YAML comments are still accepted and validated, but their text is not
retained.</li>
<li>Added <code>Options::non_finite_float_policy</code> with
<code>NonFiniteFloatPolicy::{PassThrough, Reject, AsString}</code>
to configure non-finite floats delivered through
<code>deserialize_any</code>. Explicit policies override
the legacy boolean; leaving the field unconfigured preserves its
behavior.</li>
<li>Added the <code>borrowed_context</code> example showing recursive
<code>Serialize</code> adapters that borrow
an existing value tree and per-call formatting context, composing with
<code>Tagged&lt;T&gt;</code> and
style wrappers without building a second container tree or using
thread-local state.</li>
<li>Added <code>SerializerOptions::no_lang_directive</code> (default
<code>false</code>) to suppress the
<code>%YAML 1.2</code> directive and its leading <code>---</code> marker
independently of <code>yaml_12</code>'s quoting.</li>
<li>Added <code>from_str_multiple</code>,
<code>from_bytes_multiple</code>, and their <code>_with_options</code>
variants to
deserialize multiple YAML documents into any <code>C: Default +
Extend&lt;T&gt;</code>, including vectors,
queues, sets, and custom accumulators. Values can borrow from the input
string or UTF-8 byte
slice. Explicit type arguments specify both the document and collection
types, for example
<code>from_str_multiple::&lt;String,
Vec&lt;_&gt;&gt;(input)</code>.</li>
<li>Added an <code>error: Box&lt;Error&gt;</code> field to
<code>Error::AliasError</code>, which keeps the original error
when an aliased value fails to deserialize. A custom
<code>MessageFormatter</code> or <code>Localizer</code>
now applies to that error, and <code>std::error::Error::source</code>
returns it
(<a
href="https://redirect.github.com/bourumir-wyngs/serde-saphyr/issues/199">#199</a>).</li>
</ul>
<h3>Changed</h3>
<ul>
<li><strong>Breaking:</strong> <code>from_multiple</code>,
<code>from_multiple_with_options</code>,
<code>from_slice_multiple</code>, and
<code>from_slice_multiple_with_options</code> now accept <code>T:
Deserialize&lt;'de&gt;</code> so values can borrow from
the input. They retain their names, single type parameter, and
<code>Vec&lt;T&gt;</code> returns and are not
deprecated. Ordinary calls, including
<code>from_multiple::&lt;Config&gt;(input)</code> and generic callers
with <code>T: DeserializeOwned</code>, continue to work. Function
pointers or callbacks accepting arbitrary
input lifetimes may need forwarding closures, such as <code>|input|
from_multiple::&lt;String&gt;(input)</code>.</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/bourumir-wyngs/serde-saphyr/commit/e3a4566ef2692f6b9c906a103f6841441a1924ba"><code>e3a4566</code></a>
Clarified borrowing usage and fixed borrowing test.</li>
<li><a
href="https://github.com/bourumir-wyngs/serde-saphyr/commit/fc4c875c2d1ae7a3368b8900739d26b88d13d55d"><code>fc4c875</code></a>
Merge remote-tracking branch 'origin/master'</li>
<li><a
href="https://github.com/bourumir-wyngs/serde-saphyr/commit/e2f8eb3d67d3043b137f00fdb586eab72beda43f"><code>e2f8eb3</code></a>
Make fuzz and miri mandatory steps for release workflow. use
granit-parser fr...</li>
<li><a
href="https://github.com/bourumir-wyngs/serde-saphyr/commit/9728ccb466d251059f05123dc44a8304c0eae35d"><code>9728ccb</code></a>
Report a parser error after an implicit document end in single-document
entry...</li>
<li><a
href="https://github.com/bourumir-wyngs/serde-saphyr/commit/fb50b1bc88fc1c4746cef4211ecba7712ae35f23"><code>fb50b1b</code></a>
Improve documentation</li>
<li><a
href="https://github.com/bourumir-wyngs/serde-saphyr/commit/f3f3786b92c25d83b0d55cd73a6d2e7ccb4e568e"><code>f3f3786</code></a>
Improve documentation</li>
<li><a
href="https://github.com/bourumir-wyngs/serde-saphyr/commit/d43a925d3b12dabbe3adfd3a6e4fbcb06f4db7a7"><code>d43a925</code></a>
Removed some too aggressive deprecations, this is not required with the
major...</li>
<li><a
href="https://github.com/bourumir-wyngs/serde-saphyr/commit/2db19936273a9b8382a0770f22b4cff0ebd9c683"><code>2db1993</code></a>
bw/i205 (<a
href="https://redirect.github.com/bourumir-wyngs/serde-saphyr/issues/215">#215</a>)</li>
<li><a
href="https://github.com/bourumir-wyngs/serde-saphyr/commit/c09c094ae054cafbb4b14daceb216546023d8ac0"><code>c09c094</code></a>
Bump granit-parser from <code>03889c5</code> to <code>f4bf73a</code> (<a
href="https://redirect.github.com/bourumir-wyngs/serde-saphyr/issues/216">#216</a>)</li>
<li><a
href="https://github.com/bourumir-wyngs/serde-saphyr/commit/70272b71d7d36254c5521585439714014bca5ed3"><code>70272b7</code></a>
Update cargo to use granit parser 2.0.0</li>
<li>Additional commits viewable in <a
href="https://github.com/bourumir-wyngs/serde-saphyr/compare/1.3.0...2.0.0">compare
view</a></li>
</ul>
</details>
<br />

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-21 08:07:12 -05:00
Darren Schroeder 965ad78430 Bump webpki crates to clear the RustSec audit (#19308)
<!--
Thanks for contributing to Nushell!

Before submitting, please read the contributing guide:
https://github.com/nushell/nushell/blob/main/CONTRIBUTING.md

This template helps reviewers understand your changes and allows us to
generate high-quality release notes.
-->

## Description

The `Security audit` job fails on every PR that touches `Cargo.toml` or
`Cargo.lock` (for example #19306). The advisory database now flags three
crates for CVE-2026-111943. Their certificate checks can accept chains
through emSign intermediates whose private keys have leaked. Each crate
has a patched release, so this PR moves all three to it:

| Crate | Old | New | Advisory | Pulled in by |
| --- | --- | --- | --- | --- |
| `rustls-webpki` | 0.103.15 | 0.103.16 | RUSTSEC-2026-0382 | `rustls`
(all TLS connections) |
| `webpki-roots` | 1.0.9 | 1.0.10 | RUSTSEC-2026-0381 | `nu-command`
(direct workspace dependency) |
| `webpki-root-certs` | 1.0.6 | 1.0.10 | RUSTSEC-2026-0383 |
`rustls-platform-verifier` (wasm32 only) |

`webpki-roots` is a direct workspace dependency, so `Cargo.toml` now
requires the patched `1.0.10` instead of only pinning it in the
lockfile. The other two crates are transitive, so only `Cargo.lock`
changes for them (`cargo update -p rustls-webpki -p webpki-roots -p
webpki-root-certs`). Nothing else in the lockfile moves.

<!--
Explain what this PR does and why.

This section is intentionally flexible:
- Describe the problem
- Explain your approach
- Include technical details if relevant

Good examples:
- "In this PR, I fixed..."
- "In this PR, I added support for..."
- "This change improves X by..."

Write as much or as little as needed for reviewers to understand your
changes.
-->

## User-facing changes (Release notes)

- Bumped `rustls-webpki`, `webpki-roots` and `webpki-root-certs` for
CVE-2026-111943 (distrusted emSign intermediates).

<!--
This section is used (mostly as-is) for https://www.nushell.sh/blog/

Describe how Nushell behavior changes from a user's perspective.
Do NOT describe internal Rust changes here.

Write in a release note style, for example:
- "Added support for..."
- "Fixed an issue where..."
- "Nushell now supports..."
- "Improved performance of..."

If your changes do NOT affect users (internal refactors, cleanup, etc.),
just write:
- "n/a"
- "nan"
- or similar

This tells us the change should not appear in the changelog.

Tips:
- Focus on observable behavior
- Include examples if helpful
- Keep it concise

You can:
- Write a short paragraph (will appear as a bullet point), OR
- Use headings (###) if your change needs more structure

Avoid writing things like:
- "In this PR, I refactored..."
- "This updates internal code..."

You may leave this blank until the PR is ready.
-->

## Additional notes

- `cargo audit` 0.22.2 (advisory database of 2026-10-21) on main's
`Cargo.lock`: 3 vulnerabilities, exit 1. On this branch: 0
vulnerabilities, exit 0.
- `cargo audit` still warns that `bincode` (RUSTSEC-2025-0141) and
`yaml-rust` (RUSTSEC-2024-0320) are unmaintained, the same as on main.
These warnings are informational, so the job does not fail on them.
- CI's clippy step (`clippy --workspace --all-targets --profile ci -- -D
warnings` with `.cargo/ci.toml`, plugins included) and `cargo nuclippy`
both pass on macOS.
<!--
Optional.

Examples:
- fixes #123
- closes #456
- related #789

Anything else reviewers should know.
Remove this section if not needed.
-->
2026-10-21 06:24:16 -05:00
Manoj 64915f00e4 Fix roll panic on empty lists and records (#19285)
## Description
`roll` panics when the input is empty. On current main:

> [] | roll down
panicked: assertion failed: k <= self.len()

> {} | roll left
panicked: assertion failed: mid <= self.len()

> [] | roll up --by 3
panicked: attempt to calculate the remainder with a divisor of zero

I found these by running commands against empty and edge-case input. The
cause is in `vertical_rotate_value` and `horizontal_rotate_value`. Both
do `n % len`, which divides by zero when the list or record is empty.
Without `--by`, the default rotation of 1 on an empty slice also
asserts.

The fix uses `checked_rem`, so an empty list or record gets a rotation
of 0 and is returned unchanged. I added tests for `roll up`, `roll
down`, `roll left` and `roll right` on empty input, one for empty
records inside a list, and one for a table where only one row is empty.

I ran the `roll` tests locally and they pass (13). I haven't run the
full test suite, so I'm relying on CI for that.


## User-facing changes (Release notes)
Fixed a panic when using `roll up`, `roll down`, `roll left` or `roll
right` on an empty list or record.

## Additional notes
n/a

---------

Signed-off-by: manoj-1407 <manojkumar148700@gmail.com>
Signed-off-by: G. Manoj Kumar <manojkumar148700@gmail.com>
2026-10-21 06:10:21 -05:00
dependabot[bot] dd0a08cd4b build(deps): bump taiki-e/install-action from 2.87.27 to 2.87.29 (#19304)
Bumps
[taiki-e/install-action](https://github.com/taiki-e/install-action) from
2.87.27 to 2.87.29.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/taiki-e/install-action/releases">taiki-e/install-action's
releases</a>.</em></p>
<blockquote>
<h2>2.87.29</h2>
<ul>
<li>
<p>Update <code>zizmor@latest</code> to 1.31.0.</p>
</li>
<li>
<p>Update <code>wasmtime@latest</code> to 49.0.3.</p>
</li>
<li>
<p>Update <code>wasm-tools@latest</code> to 1.262.0.</p>
</li>
<li>
<p>Update <code>uv@latest</code> to 0.13.1.</p>
</li>
<li>
<p>Update <code>trivy@latest</code> to 0.76.0.</p>
</li>
<li>
<p>Update <code>tombi@latest</code> to 1.8.4.</p>
</li>
<li>
<p>Update <code>release-plz@latest</code> to 0.3.172.</p>
</li>
<li>
<p>Update <code>osv-scanner@latest</code> to 2.7.0.</p>
</li>
<li>
<p>Update <code>mise@latest</code> to 2026.10.11.</p>
</li>
<li>
<p>Update <code>mdbook-d2@latest</code> to 0.3.9.</p>
</li>
<li>
<p>Update <code>kingfisher@latest</code> to 2.13.0.</p>
</li>
<li>
<p>Update <code>kache@latest</code> to 1.2.1.</p>
</li>
<li>
<p>Update <code>just@latest</code> to 1.59.0.</p>
</li>
<li>
<p>Update <code>dprint@latest</code> to 0.63.0.</p>
</li>
<li>
<p>Update <code>cargo-crap@latest</code> to 0.8.0.</p>
</li>
<li>
<p>Update <code>bpf-linker@latest</code> to 0.12.0.</p>
</li>
</ul>
<h2>2.87.28</h2>
<ul>
<li>
<p>Update <code>dprint@latest</code> to 0.62.0.</p>
</li>
<li>
<p>Update <code>vacuum@latest</code> to 0.33.0.</p>
</li>
<li>
<p>Update <code>uv@latest</code> to 0.13.0.</p>
</li>
<li>
<p>Update <code>tombi@latest</code> to 1.8.1.</p>
</li>
<li>
<p>Update <code>release-plz@latest</code> to 0.3.171.</p>
</li>
<li>
<p>Update <code>rclone@latest</code> to 1.75.2.</p>
</li>
<li>
<p>Update <code>mise@latest</code> to 2026.10.7.</p>
</li>
<li>
<p>Update <code>cargo-binstall@latest</code> to 1.25.3.</p>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md">taiki-e/install-action's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<p>All notable changes to this project will be documented in this
file.</p>
<p>This project adheres to <a href="https://semver.org">Semantic
Versioning</a>.</p>
<!-- raw HTML omitted -->
<h2>[Unreleased]</h2>
<h2>[2.87.29] - 2026-10-16</h2>
<ul>
<li>
<p>Update <code>zizmor@latest</code> to 1.31.0.</p>
</li>
<li>
<p>Update <code>wasmtime@latest</code> to 49.0.3.</p>
</li>
<li>
<p>Update <code>wasm-tools@latest</code> to 1.262.0.</p>
</li>
<li>
<p>Update <code>uv@latest</code> to 0.13.1.</p>
</li>
<li>
<p>Update <code>trivy@latest</code> to 0.76.0.</p>
</li>
<li>
<p>Update <code>tombi@latest</code> to 1.8.4.</p>
</li>
<li>
<p>Update <code>release-plz@latest</code> to 0.3.172.</p>
</li>
<li>
<p>Update <code>osv-scanner@latest</code> to 2.7.0.</p>
</li>
<li>
<p>Update <code>mise@latest</code> to 2026.10.11.</p>
</li>
<li>
<p>Update <code>mdbook-d2@latest</code> to 0.3.9.</p>
</li>
<li>
<p>Update <code>kingfisher@latest</code> to 2.13.0.</p>
</li>
<li>
<p>Update <code>kache@latest</code> to 1.2.1.</p>
</li>
<li>
<p>Update <code>just@latest</code> to 1.59.0.</p>
</li>
<li>
<p>Update <code>dprint@latest</code> to 0.63.0.</p>
</li>
<li>
<p>Update <code>cargo-crap@latest</code> to 0.8.0.</p>
</li>
<li>
<p>Update <code>bpf-linker@latest</code> to 0.12.0.</p>
</li>
</ul>
<h2>[2.87.28] - 2026-10-12</h2>
<ul>
<li>Update <code>dprint@latest</code> to 0.62.0.</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/taiki-e/install-action/commit/8cca0918f8471c33515202b73f56ab27f2bed283"><code>8cca091</code></a>
Release 2.87.29</li>
<li><a
href="https://github.com/taiki-e/install-action/commit/fc26824601b40bd3b26712c48942016e2b2d12f6"><code>fc26824</code></a>
Update wasmtime manifest</li>
<li><a
href="https://github.com/taiki-e/install-action/commit/5018b2ebebbb2657068e91071ea73d9a53a44f2d"><code>5018b2e</code></a>
Update <code>zizmor@latest</code> to 1.31.0</li>
<li><a
href="https://github.com/taiki-e/install-action/commit/d0e52041f440d731eae552c575c81c4cccd601c8"><code>d0e5204</code></a>
Update <code>wasmtime@latest</code> to 49.0.3</li>
<li><a
href="https://github.com/taiki-e/install-action/commit/517774f2ae949bb5d89258edba4466e75f1a33be"><code>517774f</code></a>
Update <code>wasm-tools@latest</code> to 1.262.0</li>
<li><a
href="https://github.com/taiki-e/install-action/commit/4bc69b1c8214eb6efb50b217dfb04ae04d8af1f5"><code>4bc69b1</code></a>
Update vacuum manifest</li>
<li><a
href="https://github.com/taiki-e/install-action/commit/0470a3f16345a16a36a8b4b51fd72f0de5cc6b5b"><code>0470a3f</code></a>
Update <code>uv@latest</code> to 0.13.1</li>
<li><a
href="https://github.com/taiki-e/install-action/commit/7a2b747eb5f89f888d956c73464777912a182a35"><code>7a2b747</code></a>
Update <code>trivy@latest</code> to 0.76.0</li>
<li><a
href="https://github.com/taiki-e/install-action/commit/7efb5337f67975eb612c46a52d9c7790a5829f97"><code>7efb533</code></a>
Update <code>tombi@latest</code> to 1.8.4</li>
<li><a
href="https://github.com/taiki-e/install-action/commit/e5d37d6fd4d56d59f3bdc428d4138afa60276954"><code>e5d37d6</code></a>
Update <code>release-plz@latest</code> to 0.3.172</li>
<li>Additional commits viewable in <a
href="https://github.com/taiki-e/install-action/compare/ab6895351a88b908e96a4697860d4ffea5e57dbe...8cca0918f8471c33515202b73f56ab27f2bed283">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=taiki-e/install-action&package-manager=github_actions&previous-version=2.87.27&new-version=2.87.29)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-10-21 05:48:29 -05:00
Raj Aryan 7257a46841 fix(detect type): preserve whitespace-padded strings (#19299)
## Description

In this PR I fixed #16872.

detect type matches some strings as numbers or booleans but fails when
parsing them. It now keeps the original input and metadata when
conversion fails, including integers that are too large to fit in i64.

Strings with leading or trailing whitespace now stay strings across all
types, including durations. This follows panicbit’s suggestion in the
issue discussion.

Numeric patterns now use ASCII digits, and booleans use ASCII
case-insensitive matching. Integers with a leading + are supported,
while numbers with mixed separators, such as "1,000_000", stay strings.

Updated the help text and regression tests. Each whitespace variant now
runs as a separate test so failures are easier to identify.

Fixes #16872

## User-facing changes (Release notes)

Fixed detect type returning conversion errors for whitespace-prefixed
numbers, Unicode digits, and out-of-range integers. Inputs that fail
conversion now remain unchanged.

Strings with surrounding whitespace, including durations such as " 5ns",
now stay strings. Integers with a leading +, such as "+42", are now
converted. Numbers with mixed comma and underscore separators remain
strings.

## Additional notes

Adds tested help examples and regression tests covering whitespace,
Unicode inputs, integer boundaries, invalid dates, metadata
preservation, and existing conversions.

Validation passed:

> 861 library tests, including command examples; 2 ignored
> 476 detect type integration tests
> cargo fmt --all
> cargo nuclippy
> typos v1.51.1
> git diff --check
2026-10-20 06:56:39 -05:00
Tyarel8 324696443a fix(version check): propagate error and use github token (#19298)
<!--
Thanks for contributing to Nushell!

Before submitting, please read the contributing guide:
https://github.com/nushell/nushell/blob/main/CONTRIBUTING.md

This template helps reviewers understand your changes and allows us to
generate high-quality release notes.
-->

## Description
<!--
Explain what this PR does and why.

This section is intentionally flexible:
- Describe the problem
- Explain your approach
- Include technical details if relevant

Good examples:
- "In this PR, I fixed..."
- "In this PR, I added support for..."
- "This change improves X by..."

Write as much or as little as needed for reviewers to understand your
changes.
-->

## User-facing changes (Release notes)
<!--
This section is used (mostly as-is) for https://www.nushell.sh/blog/

Describe how Nushell behavior changes from a user's perspective.
Do NOT describe internal Rust changes here.

Write in a release note style, for example:
- "Added support for..."
- "Fixed an issue where..."
- "Nushell now supports..."
- "Improved performance of..."

If your changes do NOT affect users (internal refactors, cleanup, etc.),
just write:
- "n/a"
- "nan"
- or similar

This tells us the change should not appear in the changelog.

Tips:
- Focus on observable behavior
- Include examples if helpful
- Keep it concise

You can:
- Write a short paragraph (will appear as a bullet point), OR
- Use headings (###) if your change needs more structure

Avoid writing things like:
- "In this PR, I refactored..."
- "This updates internal code..."

You may leave this blank until the PR is ready.
-->
Previously, the `version check` command would say you are on the latest
release if the lookup failed, now, lookup errors will result in an error
on the command too. Also, if a github token is available on the
environment (`GITHUB_TOKEN` or `GH_TOKEN`) it will be used for the
request to bypass the unauthenticated 60-requests-per-hour github api
rate limit.
2026-10-20 06:40:51 -05:00
Manoj 77726d8d22 Fix table --abbreviated crash when the row count is too large to allocate (#19296)
## Description
`table --abbreviated` crashes when the count is too large to allocate.
On current main:

> 1..5 | table --abbreviated 9223372036854775807
panicked: capacity overflow

> [[a]; [1]] | table --abbreviated 9223372036854775807
panicked: capacity overflow

`stream_collect_abbreviated` reserves the head and the tail with
`with_capacity(size)`, where `size` is the number the user typed. Both
buffers only ever hold rows that are actually read, so they are now
sized from the iterator's size hint: `head` reserves `hint.min(2 * size
+ 1)`, which is its final length with the `...` row, and `tail` reserves
`hint.saturating_sub(size).min(size)`. Inputs without a hint, like a
range or `every`, start empty and grow.

The output doesn't change: a count larger than the input shows every
row, as before. This is the same problem as #19286 (`chunks`), #19288
(`window`) and #19295 (`last`).

I added tests that a huge count prints the same table as a normal count,
for a plain list and for a list stream, and a huge-count range case in
`table_abbreviation_cut`. I ran the `table::abbreviation` tests locally
and they pass. I did not run the full workspace suite.

AI assistance: I used Claude to help find the issue and draft the
change. I reviewed and tested it myself.

## User-facing changes (Release notes)
Fixed a crash when `table --abbreviated` is given a row count too large
to allocate, such as 9223372036854775807.

## Additional notes
n/a

---------

Signed-off-by: G. Manoj Kumar <manojkumar148700@gmail.com>
2026-10-20 06:34:34 -05:00
Manoj ab781520a8 Fix window crash when the window size is too large to allocate (#19288)
## Description
`window` crashes when the window size is too large to allocate. On
current main:

> [1 2 3] | window 9223372036854775807
panicked: capacity overflow

> [1 2 3] | window 9223372036854775807 --stride 9223372036854775807
panicked: capacity overflow

Both come from `Vec::with_capacity` taking the size the user typed.
`WindowOverlapIter` reserved it in `new`, and `WindowGapIter` reserved
it on every call to `next`.

The overlapping iterator also used `self.window.capacity()` as the
window size, so it depended on the reservation. It now keeps `size` as a
field. The overlap buffer starts empty and is filled with `extend`, and
the gap iterator collects its window, so neither reserves the typed
size.

This is the same problem that #19286 fixed for `chunks`. With
`--remainder` and a stride equal to the size, `window` hands off to
`chunks`, so that case works now too.

I added tests for a huge size on a list, with a huge stride, on list
streams (both iterators), and with `--remainder`, where they check the
actual windows. I ran the `window` and `chunks` tests locally and they
pass. I did not run the full workspace suite.

AI assistance: I used Claude to help find the issue and draft the
change. I reviewed and tested it myself.

## User-facing changes (Release notes)
Fixed a crash when `window` is given a window size too large to
allocate, such as 9223372036854775807.

## Additional notes
n/a

---------

Signed-off-by: G. Manoj Kumar <manojkumar148700@gmail.com>
2026-10-20 06:33:01 -05:00
04ba9838b8 feat: enable spread operator for get command rest args (#18220)
## Summary

`get` now takes its cell paths as a single `...rest` parameter, so a
list of paths can be spread into it: `get ...$paths`. Before this, `get`
required a first cell path followed by a rest, and there was no way to
pass a dynamically built list of paths.

## Behavior

- `get` with no paths returns its input unchanged. With an empty
pipeline it reports `Pipeline empty`, the same as `select`.
- `get a` with one cell path and no spread returns the value at that
path, as before.
- Several paths, or any spread argument, return a list with one value
per path. A spread always produces a list, so `get ...$cols` has the
same shape whatever `$cols` holds: one name gives a one-element list,
and an empty spread gives an empty list.
- Strings in a spread are single column names, so `...[a.b]` looks for a
column named `a.b`. Nested paths are spread as cell-path values, for
example `let paths = [$.a.b]` or `into cell-path`.

## Changes

- `crates/nu-command/src/filters/get.rs`: the signature is `get
...(rest)`. `action` takes the full `Vec<CellPath>`, checks for an empty
pipeline first, then branches on zero paths, one path without a spread,
and everything else. A small helper reads whether the call has a spread
argument (AST and IR calls). The help text and examples describe the
zero, one and many cases and nested spread paths.
- `crates/nu-command/tests/commands/get.rs`: tests for literal before
and after a spread, one-element spreads on a table and a record, empty
literal and variable spreads, a nested cell-path spread, a const spread,
and the empty pipeline with no paths and with an empty spread.

## Testing

On the merged branch: `cargo fmt --all -- --check`, `cargo clippy -p
nu-command --all-targets -- -D warnings` (with `.cargo/ci.toml`), `cargo
test -p nu-command --test tests -- commands::get` (39 passed) and the
`get` examples test all pass. Against the previous `get.rs`, 8 of the 10
new tests fail; the two mixed-order tests pass on both, since that
ordering already worked.

## Release notes

- `get` accepts spread cell paths (`get ...$paths`). Its signature
changes from `get <cell_path> ...(rest)` to `get ...(rest)`.
- `get` with no arguments is no longer a parse error: it returns its
input, or reports `Pipeline empty` when there is no input.
- A `get` call with a spread argument always returns a list, one value
per path.

Fixes #15801

---------

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 16:06:23 -05:00
qodelicious 2deff7fc5b fix(cli): show the script name instead of main in errors about a script's arguments (#19282)
## Description
`nu script.nu` runs the script's `main` by evaluating `main <args>`, so
an error about the arguments showed `main` in the source snippet, even
though the usage line already uses the script name:

```
Error: nu::parser::missing_positional

  × Missing required positional argument.
   ╭─[<commandline>:1:5]
 1 │ main
   ·     ▲
   ·     ╰── missing foo
   ╰────
  help: Usage: script.nu <foo> . Use `--help` for more information.
```

`evaluate_file` already adds the script name to the overlay as another
name for `main` (and `script.nu foo` for `main foo`), so the call can
use it. This now builds the command line as `script.nu <args>` when that
parses as a call to the script's renamed `main` (checked with a single
probe parse), and falls back to `main <args>` otherwise. The snippet
then shows `script.nu`:

```
   ╭─[<commandline>:1:10]
 1 │ script.nu
   ·          ▲
   ·          ╰── missing foo
   ╰────
  help: Usage: script.nu <foo> . Use `--help` for more information.
```

The script name is only used when it parses as a command. Scripts named
after a parser keyword (`for`, `source`, `use`, `module`, `alias`, ...)
always call `main` directly, and names that parse as something else,
such as `10kb`, `true`, `it's.nu` or `a #b.nu`, still show `main`. Names
with a space (`my script.nu`) use the script name. Scripts without a
`main` aren't affected.

Tests added in `tests/shell/mod.rs`:
- `main_script_missing_argument_uses_script_name`
- `main_script_subcommand_missing_argument_uses_script_name`
- `main_script_with_space_in_name_uses_script_name`
- `main_script_named_like_a_parser_keyword_still_runs`
- `main_script_named_like_a_value_still_runs` (checks the fallback to
`main`)
- `script_without_main_is_unaffected`

## User-facing changes (Release notes)
- Errors about the arguments passed to a script's `main` (such as a
missing positional argument) now show the script name instead of `main`,
when the script name parses as a command. Other names (for example
`10kb` or `it's.nu`) still show `main`.

## Additional notes
Fixes #10191

Tests + formatting:
- `cargo fmt --all -- --check`
- `cargo clippy -p nu-config -p nu-cmd-lang -p nu-command -p nu-cli -p
nu-explore --all-targets -- -D warnings -D clippy::unwrap_used`
- `cargo clippy -p nu -p nu-cli --all-targets -- -D warnings -D
clippy::unwrap_used`
- `cargo test --test tests -- shell::`
- `cargo test -p nu-cli --lib eval_file`

The script name is only used when the call resolves to main, so names
like 10kb, it's.nu or main;… still show main.
2026-10-19 06:18:24 -05:00
qodelicious 877ed65f0a fix(run-external): explain a missing shebang interpreter instead of showing an internal error (#19280)
## Description
Running a script whose shebang interpreter doesn't exist gave an
internal error that pointed at a Rust source location:

```
Error: nu::shell::io::not_found

  × Not found
  ╰─▶   × Could not spawn foreground child: No such file or directory (os error 2)

   ╭────
 1 │ crates/nu-command/src/system/run_external.rs:323:17
   · ─────────────────────────┬─────────────────────────
   ·                          ╰── Not found
   ╰────
```

By the time the child is spawned, `which` has already found the
executable, so on Unix a "not found" error from spawning means something
the OS needs to start it is missing. Nushell now reads the first line of
the file: if it starts with `#!` and that interpreter doesn't exist, the
help names it, like bash, zsh and fish do. Otherwise it says a file the
program needs (such as a shared library or its program loader) wasn't
found, which is the `ldd` case in the issue. The help includes the
resolved path, so it's clear which file was run:

```
Error: nu::shell::external_command

  × External command failed
   ╭─[entry #1:1:1]
 1 │ ./script.sh
   · ─────┬─────
   ·      ╰── `./script.sh` exists but could not be started
   ╰────
  help: `/path/to/script.sh` starts with `#!/nonexistent/interpreter`, but `/nonexistent/interpreter` was not found (No such file or directory (os error 2))
```

This hint is Unix-only and only used when the file still exists; on
Windows, or when the file was removed after `which` found it, you get
the normal not-found error with the path. Other spawn errors (permission
denied, argument list too long, exec format error) are now reported
against the command and its path instead of a Rust source line.

Tests in `crates/nu-command/tests/commands/run_external.rs` (Unix only,
for the bare, `^` and `run-external` forms):
- `missing_shebang_interpreter_error`
- `non_executable_shebang_interpreter_error` (a `#!` pointing at a file
that isn't executable, which now gives a permission error instead of the
internal one)

Both retry once if the run fails with `ExecutableFileBusy`, to avoid the
Linux "Text file busy" flake.

## User-facing changes (Release notes)
- Running a script whose shebang interpreter is missing now names the
interpreter, and a program missing a file it needs (such as a shared
library) says so, instead of showing an internal "Could not spawn
foreground child" error with a Rust source location. Other errors from
starting an external command point at the command and its path.

## Additional notes
Fixes #15970

Tests + formatting:
- `cargo fmt --all -- --check`
- `cargo clippy -p nu-config -p nu-cmd-lang -p nu-command -p nu-cli -p
nu-explore --all-targets -- -D warnings -D clippy::unwrap_used`
- `cargo test -p nu-command --test tests -- commands::run_external`
2026-10-19 06:09:36 -05:00
Manoj e03b706d72 Fix last crash when the count is too large to allocate (#19295)
## Description
`last` crashes on byte streams when the count is too large to allocate.
On current main:

> random binary 16b | last 9223372036854775807 | length
panicked: capacity overflow

It comes from `VecDeque::with_capacity(rows + TAKE as usize)`, where
`rows` is the number the user typed. The loop already drains the buffer
down to `rows` after every read, so the buffer only needs to grow with
the data that is actually read.

The buffer now starts empty, so memory use follows the data and not the
argument. This is the same problem as #19286 (`chunks`) and #19288
(`window`).

I added tests for a huge count on a byte stream and on binary input,
comparing the values. I ran the `last` tests locally and they pass. I
did not run the full workspace suite.

AI assistance: I used Claude to help find the issue and draft the
change. I reviewed and tested it myself.

## User-facing changes (Release notes)
Fixed a crash when `last` is given a count too large to allocate, such
as 9223372036854775807, on byte stream input.

## Additional notes
n/a

Signed-off-by: G. Manoj Kumar <manojkumar148700@gmail.com>
2026-10-19 06:00:15 -05:00
Darren Schroeder cb42a1a4c8 Merge remote-tracking branch 'upstream/main' into fix_unlet_const 2026-10-18 18:52:39 -05:00
Darren Schroeder 27f09f90eb fix(unlet): hide a constant's name instead of rejecting it 2026-10-18 18:51:09 -05:00
AP 199cf98b4f fix(du): count a hard-linked file once, not once per link (#19283)
## Description

`du` walked every path and added each file's size independently, so a
file with N hard links was counted N times and both size columns
over-reported.

The walk now tracks the identities of files it has already counted and
skips the repeats. The set holds `uucore::fs::FileInformation`
(device+inode on Unix, volume serial+file index on Windows) instead of a
Unix-only `(dev, ino)` pair, so the dedup applies on Linux, macOS and
Windows; the gate is `not(wasm32)`. One set covers the whole `du`
invocation following the POSIX/GNU rule: a file counts once even across
different path operands, so `du` and `du d1 d2` agree (first occurrence
wins). Only files with more than one link enter the set; single-link
files never touch it. `DirBuilder` stays settings-only — the set is
threaded through as `&mut` rather than living in a cloned struct. `ls
--du` uses the new signature; within each listed directory a hard-linked
file now counts once, matching `du`.

Adds regression tests: a file with multiple hard links contributes its
size exactly once, including when the links sit under different path
operands.

## User-facing changes (Release notes)

- Fixed `du` over-reporting sizes for hard-linked files: a file with
multiple hard links is now counted once instead of once per link, on all
platforms (Linux, macOS, Windows).
- `du --long` lists the first-seen link only, matching GNU `du -a`.
- `ls --du` now counts a hard-linked file once inside each listed
directory, like `du` does.
- First link wins: when the same file is reachable through multiple hard
links, only the first occurrence is counted and listed — e.g. `du c b a`
on three links to one file shows a single row for `c`. This matches
POSIX/BSD/GNU `du`, but scripts that expect one row per operand will see
fewer rows.

## Additional notes

- Fixes #19019
2026-10-18 16:49:07 -05:00
Tino a4e1065511 disallow setting a negative indentation level in to xml (#19292)
## Description

`to xml` allows setting a negative value for the `indent` argument, even
though none of the other `to` commands with similar arguments allow
doing so. Giving a value of -1 makes it warp into usize::MAX, which
makes Nushell freeze regardless of the input.

## User-facing changes (Release notes)

`to xml` now disallows setting a negative indentation amount.

## Additional notes

Closes https://github.com/nushell/nushell/issues/19291
2026-10-18 16:45:29 -05:00
Manoj a714117bb0 Fix chunks crash when the chunk size is too large to allocate (#19286)
## Description
`chunks` crashes when the chunk size is too large to allocate. On
current main:

> [1 2 3] | chunks 9223372036854775807
panicked: capacity overflow

> 0x[11 22 33] | chunks 9223372036854775807
memory allocation of 9223372036854775807 bytes failed

The stream versions (`[0 1 2] | every 1 | chunks 9223372036854775807`
and `random binary 16b | chunks 9223372036854775807`) crash the same
way, as pointed out in review.

All of them come from `Vec::with_capacity(self.size)`, where `size` is
the number the user typed. The whole chunk size is reserved before any
input is read.

For lists, each chunk is now built with
`once(first).chain(..).collect()`. That has an exact size hint for list
input, so it allocates once, and nothing is reserved from the user's
number. For binary input, `ChunkRead` starts with an empty buffer and
grows it with the bytes it reads.

Trade-off: stream and binary input now grow by doubling instead of one
up-front allocation, so there is a bit more copying. Memory use follows
the data, not the argument.

I added tests for a huge chunk size on a list, a list stream, a binary
and a byte stream. I ran the `chunks` tests locally and they pass. I did
not run the full workspace suite.

`window` has the same pattern and I'm sending it as a separate PR.

AI assistance: I used Claude to help find the issue and draft the
change. I reviewed and tested it myself.

## User-facing changes (Release notes)
Fixed a crash when `chunks` is given a chunk size too large to allocate,
such as 9223372036854775807.

## Additional notes
n/a

---------

Signed-off-by: G. Manoj Kumar <manojkumar148700@gmail.com>
2026-10-18 12:52:38 -05:00
Jaideep Pyne 9b7771489d test(parser): pin exact whole-number unit literals and scaled overflow (#18898)
## Description

Filesize and duration literals lose precision because `parse_unit_value`
parses the numeric part through an `f64`. `Filesize` is backed by an
`i64`, so large exact integers get silently rounded — e.g.
`6504534684301572998b` parses as `6504534684301573120b`, off by 122
bytes (#10612).

This parses the numeric part as an `i64` when it's a whole number and
computes the base-unit value (bytes / nanoseconds) with checked integer
arithmetic. Fractional literals, and anything that would overflow `i64`,
fall back to the existing `f64` path, so everything that already worked
is unchanged. The unit factors are all whole numbers, so the integer
conversion is lossless.

## User-facing changes (Release notes)

- Fixed large whole-number filesize and duration literals (e.g.
`6504534684301572998b`) losing precision when parsed.

## Additional notes

Fixes #10612
2026-10-18 12:39:05 -05:00
Martin Kronberger 684b4dff76 chore: bump reedline to 39db5e3 (#19290)
## Description

Bumps reedline to `39db5e3`, six PRs past `d704744`:

- nushell/reedline#1132 `feat(engine): add opt-in paste hooks for
interception and burst detection`
- nushell/reedline#1243 `fix(painter): print external messages from the
prompt's start row`
- nushell/reedline#1249 `test(painter): assert on a vt100 screen instead
of emitted bytes`
- nushell/reedline#1247 `chore: add .claude to gitignore`
- nushell/reedline#1248 `feat(history)!: drop chrono from the public API
with a millisecond HistoryTimestamp`
- nushell/reedline#1254 `Fix large completion menus and synchronized
repainting`

#1248 needs the only change on the nushell side: `repl.rs` now stamps
history with `HistoryTimestamp::now()`, and `history import` converts
its `date` field to millis, so its input type stays the same.

## User-facing changes (Release notes)

- Fixed external messages leaving prompt rows behind or erasing output
above the prompt.
- Fixed completion menus with more entries than fit in terminal
coordinates.
- Repaints are bracketed with synchronized terminal updates, which
reduces flicker on supporting terminals.
2026-10-18 12:31:23 -05:00
qodelicious ae6793e49d Tone down the tutor echo intro (#19287)
## Description
Fixes #12927.

`tutor echo` opened by calling `echo` "a powerful tool for not only
seeing values, but also for creating new ones", which oversells it. The
intro now just says what `echo` does and points out that a value on its
own, like `"Hello"`, works the same as `echo "Hello"`, as suggested in
the issue. I also fixed a small grammar slip further down ("to later
processes these values"). The examples are unchanged.

## User-facing changes (Release notes)
- The `tutor echo` intro is now more accurate and mentions that a plain
value works the same as passing it to `echo`.
2026-10-18 07:13:40 -05:00
qodelicious 4089cf963a fix(into string): explain in help that binary input needs decode (#19284)
## Description

Fixes #15513.

`help into string` lists `binary -> string` as an input/output type, but
`0x[31 32 33] | into string` always fails with `can't convert binary to
string`. The help and the behaviour disagree.

As noted in the issue, the easy fix (dropping `binary` from the
signature) would make the parser reject binary input up front with a
generic input type error, and users would no longer see the hint to use
`decode`. So this PR keeps `binary` in the signature and makes the help
say what actually happens:

- `into string` now has an extra description explaining that binary
input is only accepted so it can point you to `decode`, because `into
string` does not decode bytes. It shows up in `help into string` right
under the description.
- The value path and the byte stream path now build the same error from
one helper, and the hint is a bit more specific: "`into string` does not
decode bytes; use the `decode` command instead, for example `decode
utf-8`".
- Added tests: binary input returns `CantConvert` from `binary` to
`string` with a hint mentioning `decode`, and `help into string`
mentions `decode`.

I went with this over removing `binary` from the signature because it
keeps the hint, and over decoding bytes as UTF-8 inside `into string`
because that would duplicate `decode` and quietly pick an encoding for
the user.

## User-facing changes (Release notes)

`help into string` now explains that `into string` does not convert
binary data: binary input returns an error that points to `decode`, for
example `0x[68 69] | decode utf-8`. The error hint for binary input is
also clearer.

## Additional notes

Tests run locally:

- `cargo fmt --all -- --check`: clean
- `cargo clippy -p nu-command --all-targets -- -D warnings -D
clippy::unwrap_used`: clean
- `cargo test -p nu-command --lib conversions::into`: 126 passed
- `cargo test -p nu-command --test tests -- into_string`: 54 passed
(includes the 2 new tests)
- `cargo test -p nu-command --lib test_examples`: 259 passed, 2 ignored
2026-10-18 07:10:48 -05:00
qodelicious f163d7c559 fix(tee): keep the last help example short (#19281)
## Description
The last example in `help tee` prints 10000 lines (`10000 | tee { 1..$in
| print } | $in * 5`), which is a lot of output for a help example and
can scroll everything else out of view. This changes it to 100 (result
500), which shows the same thing in a short example.

`tee.rs` had no example test, so I added one (`test_examples`). It runs
the examples that have a result and parses the rest.

## User-facing changes (Release notes)
- The last `help tee` example now prints 100 lines instead of 10000.

## Additional notes
Related: #16374. This keeps the help example short. It doesn't change
how large outputs are printed.

Tests + formatting:
- `cargo fmt --all -- --check`
- `cargo clippy -p nu-config -p nu-cmd-lang -p nu-command -p nu-cli -p
nu-explore --all-targets -- -D warnings -D clippy::unwrap_used`
- `cargo test -p nu-command --lib tee`
2026-10-18 07:04:42 -05:00
qodelicious d214ff7175 fix(hide): describe the required argument as the name of what to hide (#19279)
## Description
`hide`'s required argument was called `module` and described as "Module
or module file.", but `hide` mostly takes the name of an alias, a custom
command or a type alias, and all three examples in `help hide` do that.
A module name works too (`hide spam` after `use spam`), with the
optional `members` argument picking which of its members to hide.

This renames the argument to `name` and describes it as "Alias, command,
type alias, or module to hide.", so the signature matches the
description and the examples. Only the help text changes; the parser
handles `hide` as a keyword and doesn't look the argument up by name.

Argument completion for `hide` (also mentioned in the issue) is not
changed here.

## User-facing changes (Release notes)
- `help hide` now describes the required argument as the name of the
alias, command, type alias, or module to hide, instead of "Module or
module file.".

## Additional notes
Part of #15527 (the signature part; completion isn't touched).

Tests + formatting:
- `cargo fmt --all -- --check`
- `cargo clippy -p nu-config -p nu-cmd-lang -p nu-command -p nu-cli -p
nu-explore --all-targets -- -D warnings -D clippy::unwrap_used`
- `cargo test -p nu-cmd-lang`
2026-10-18 07:00:31 -05:00