From 71b89e0133827117019a6a788f59b4780fc4bfbe Mon Sep 17 00:00:00 2001 From: Darren Schroeder <343840+fdncred@users.noreply.github.com> Date: Fri, 16 Oct 2026 09:43:24 -0500 Subject: [PATCH] updates since 0.116.0 + mcp + dap + new commands --- .vuepress/configs/sidebar/en.ts | 2 + book/advanced.md | 5 +- book/aliases.md | 39 ++- book/background_jobs.md | 10 + book/coming_from_bash.md | 5 + book/configuration.md | 4 +- book/control_flow.md | 31 +- book/custom_commands.md | 50 ++- book/custom_completions.md | 16 +- book/debugging.md | 93 +++++ book/default_shell.md | 9 + book/how_nushell_code_gets_run.md | 2 +- book/line_editor.md | 318 +++++++++--------- book/loading_data.md | 9 + book/mcp.md | 103 ++++++ book/metadata.md | 9 + book/modules/creating_modules.md | 1 + book/modules/using_modules.md | 19 ++ book/programming_in_nu.md | 3 +- book/quick_tour.md | 34 +- book/special_variables.md | 6 +- book/table_of_contents.md | 2 + book/tui.md | 52 ++- book/types_of_data.md | 13 +- book/working_with_records.md | 77 +++++ book/working_with_tables.md | 27 ++ commands/docs/export_type.md | 56 +++ commands/docs/record.md | 43 +++ commands/docs/record_apply.md | 89 +++++ commands/docs/record_each.md | 83 +++++ commands/docs/record_walk.md | 124 +++++++ commands/docs/record_where.md | 99 ++++++ commands/docs/type.md | 73 ++++ cookbook/jq_v_nushell.md | 6 +- cookbook/system.md | 39 ++- lang-guide/chapters/declarations.md | 53 ++- lang-guide/chapters/filters/where-filter.md | 11 + lang-guide/chapters/flow_control/match.md | 38 ++- .../chapters/types/basic_types/closure.md | 16 + .../chapters/types/basic_types/record.md | 7 + lang-guide/chapters/types/related_commands.md | 7 + lang-guide/chapters/types/type_signatures.md | 67 ++++ 42 files changed, 1493 insertions(+), 257 deletions(-) create mode 100644 book/debugging.md create mode 100644 book/mcp.md create mode 100644 commands/docs/export_type.md create mode 100644 commands/docs/record.md create mode 100644 commands/docs/record_apply.md create mode 100644 commands/docs/record_each.md create mode 100644 commands/docs/record_walk.md create mode 100644 commands/docs/record_where.md create mode 100644 commands/docs/type.md diff --git a/.vuepress/configs/sidebar/en.ts b/.vuepress/configs/sidebar/en.ts index ca2a3b6f498..820b09f5679 100644 --- a/.vuepress/configs/sidebar/en.ts +++ b/.vuepress/configs/sidebar/en.ts @@ -64,6 +64,7 @@ export const sidebarEn: SidebarConfig = { '/book/overlays.md', '/book/sorting.md', '/book/testing.md', + '/book/debugging.md', '/book/style_guide.md', ], }, @@ -119,6 +120,7 @@ export const sidebarEn: SidebarConfig = { '/book/plugins.md', '/book/explore.md', '/book/tui.md', + '/book/mcp.md', ], }, ], diff --git a/book/advanced.md b/book/advanced.md index 36b473999a5..33686e619f7 100644 --- a/book/advanced.md +++ b/book/advanced.md @@ -6,6 +6,7 @@ next: text: Standard Library link: /book/standard_library.md --- + # (Not so) Advanced While the "Advanced" title might sound daunting and you might be tempted to skip this chapter, in fact, some of the most interesting and powerful features can be found here. @@ -24,5 +25,7 @@ Thanks to Nushell's strict scoping rules, it is very easy to [iterate over colle You can [interactively explore data](explore.md) with the [`explore`](/commands/docs/explore.md) command, and you can [build your own terminal user interfaces](tui.md), such as pickers, dialogs, and dashboards, with the `tui` family of commands. -Finally, you can extend Nushell's functionality with [plugins](plugins.md). +You can extend Nushell's functionality with [plugins](plugins.md). Almost anything can be a plugin as long as it communicates with Nushell in a protocol that Nushell understands. + +Finally, Nushell can run as an [MCP server](mcp.md), so AI agents and other Model Context Protocol clients can look up its commands and run Nushell code. diff --git a/book/aliases.md b/book/aliases.md index 5defa4cb455..9cd639b1625 100644 --- a/book/aliases.md +++ b/book/aliases.md @@ -45,7 +45,7 @@ Running `help` on an alias shows what it expands to, followed by the help for th def greet [name: string] { $"Hello, ($name)!" } alias hi = greet help hi -# => Alias for greet +# => Alias for `greet` # => # => Alias: hi # => @@ -74,6 +74,43 @@ help hi # => ╰───┴───────┴────────╯ ``` +When an alias runs a subcommand, `help` on the parent command lists the alias under its own name, right after the subcommand it runs: + +```nu +# Manage notes +def notes [] {} +# Add a note +def "notes add" [text: string] {} +# List notes +def "notes list" [] {} +alias nl = notes list +help notes +# => Manage notes +# => +# => Usage: +# => > notes +# => +# => Subcommands: +# => notes add (custom) - Add a note +# => notes list (custom) - List notes +# => nl (alias) - Alias for `notes list` +# => +# => Flags: +# => -h, --help: Display the help message for this command +# => +# => Command Type: +# => > custom +# => +# => Input/output types: +# => ╭───┬───────┬────────╮ +# => │ # │ input │ output │ +# => ├───┼───────┼────────┤ +# => │ 0 │ any │ any │ +# => ╰───┴───────┴────────╯ +``` + +The same works for built-in commands: after `alias st = str trim`, `help str` lists `st (alias)` right after `str trim`. Hidden commands and aliases are left out. + ## Persisting To make your aliases persistent they must be added to your _config.nu_ file by running `config nu` to open an editor and inserting them, and then restarting nushell. diff --git a/book/background_jobs.md b/book/background_jobs.md index f3dda6e88f6..6ea2217a3ad 100644 --- a/book/background_jobs.md +++ b/book/background_jobs.md @@ -3,6 +3,7 @@ next: text: Coming to Nu link: /book/coming_to_nu.md --- + # Background Jobs Nushell currently has experimental support for thread-based background jobs. @@ -175,3 +176,12 @@ for spawning independent background processes (see [#15201](https://github.com/n Additionally, if the user is running an interactive Nushell session and runs [`exit`](/commands/docs/exit.md) while there are background jobs running, the shell will warn about them before prompting the user to confirm `exit`. + +Pressing Ctrl+C at the REPL interrupts only the command running in the foreground. +Background jobs and frozen jobs keep running. + +When Nushell runs a script or a command given with `nu -c`, it stops any jobs that are still running, +along with their child processes, before it exits. This also happens when the script was interrupted +with Ctrl+C and the interruption was caught. + +Calling `exit` inside a job's closure ends that job, not the shell. diff --git a/book/coming_from_bash.md b/book/coming_from_bash.md index 5382444d836..78100935413 100644 --- a/book/coming_from_bash.md +++ b/book/coming_from_bash.md @@ -57,6 +57,7 @@ $env.Path = ($env.Path | prepend 'C:\Program Files\Git\usr\bin') | `sed` | `str replace` | Find and replace a pattern in a string | | `grep ` | `where $it =~ ` or `find ` | Filter strings that contain the substring | | `grep -i ` | `find -i ` | Filter strings that contain the substring, ignoring case | +| `grep -o ` | `find -o -r ` | Output only the matched text, one value per match | | `man ` | `help ` | Get the help for a given command | | | `help commands` | List all available commands | | | `help --find ` | Search for match in all available commands | @@ -87,6 +88,10 @@ $env.Path = ($env.Path | prepend 'C:\Program Files\Git\usr\bin') | `read var` | `let var = input` | Get input from the user | | `read -s secret` | `let secret = input -s` | Get a secret value from the user without printing keystrokes | +::: tip +In Nushell, `type` is the keyword that declares a [type alias](./custom_commands.md#type-aliases), so `type FOO` is a parse error rather than a command lookup. Use `which FOO` instead. If your system has an external `type` program (macOS has `/usr/bin/type`), run it as `^type FOO`. +::: + ## History Substitutions and Default Keybindings: | Bash | Nu | Task | diff --git a/book/configuration.md b/book/configuration.md index 318011b7f67..848a3a11ed0 100644 --- a/book/configuration.md +++ b/book/configuration.md @@ -240,6 +240,8 @@ $env.PROMPT_COMMAND_RIGHT = { `commandline set-prompt` sets the left prompt by default. Use `--right`, `--indicator`, `--vi-insert`, `--vi-normal`, or `--multiline` to set the other prompt components. The new text lasts until the next prompt is drawn. +A job started from a prompt closure, or from a `pre_prompt` or `env_change` [hook](./hooks.md), can finish before the prompt is drawn, for example when `git` answers quickly. Its `commandline set-prompt` still shows on that prompt. The same is true when a hook or prompt closure calls `commandline set-prompt` directly: the pushed text replaces what the prompt variable gives that segment. + ### ENV_CONVERSIONS Certain variables, such as those containing multiple paths, are often stored as a @@ -665,6 +667,7 @@ The following stages and their steps _may_ occur during startup, based on the fl - ❌ Does not enter the REPL - ❌ Does not source the files in `vendor-autoload-dirs` - ❌ Does not source the files in `user-autoload-dirs` + - `nu -l -c "ls"`: - ✅ Makes the Standard Library available @@ -751,4 +754,3 @@ The following stages and their steps _may_ occur during startup, based on the fl - ❌ Does not enter the REPL - ❌ Does not source the files in `vendor-autoload-dirs` - ❌ Does not source the files in `user-autoload-dirs` - diff --git a/book/control_flow.md b/book/control_flow.md index 503b05f5265..5664791cb8f 100644 --- a/book/control_flow.md +++ b/book/control_flow.md @@ -117,6 +117,18 @@ match $foo { The `_` in the second branch means it matches any record with field `name` and `count`, not just ones where `name` is `'bar'`. +Lists unpack the same way. In a list pattern, `..` stands for any number of items, and it can go at the start, in the middle, or at the end. `..$name` also binds those items to a variable: + +```nu +let steps = [build test done] +match $steps { + [] => 'nothing to do', + [.., 'done'] => 'finished', + [$current, ..] => $"running ($current)" +} +# => finished +``` + #### Guards You can also add an additional condition to each branch called a "guard" to determine if the branch should be matched. To do so, after the matched pattern put `if` and then the condition before the `=>`. @@ -218,30 +230,21 @@ $result # => ╰───┴───╯ ``` -When creating custom errors, loops have an advantage over pipelines because they don't fail evaluation. - -Creating an error in a pipeline yields a pipeline evaluation error *and* the custom error: +Errors, on the other hand, are not a reason to pick one over the other. When the closure given to `each` fails, Nushell reports the closure's own error, with an extra `source value` label on the input item that was being processed: ```nu [0] | each { error make { msg: "Custom error" } | default '' } -# => Error: nu::shell::eval_block_with_input +# => Error: nu::shell::error # => -# => × Eval block failed with pipeline input +# => × Custom error # => ╭─[repl_entry #1:1:2] # => 1 │ [0] | each { error make { msg: "Custom error" } | default '' } -# => · ┬ +# => · ┬ ─────────────────────── # => · ╰── source value # => ╰──── -# => -# => Error: -# => × Custom error -# => ╭─[repl_entry #1:1:25] -# => 1 │ [0] | each { error make { msg: "Custom error" } | default '' } -# => · ─────────────────────── -# => ╰──── ``` -When using a loop, a `for` loop in this example, evaluation succeeds and only the created error occurs: +A `for` loop reports the same error, without the `source value` label: ```nu for x in [0] { error make { msg: "Custom error" } } diff --git a/book/custom_commands.md b/book/custom_commands.md index b225c1d9559..6c29d151214 100644 --- a/book/custom_commands.md +++ b/book/custom_commands.md @@ -271,10 +271,11 @@ Strings which might be confused with other parser patterns should be avoided. Fo - `1`, `"1"`, or `"1.5"`: Nushell will not allow numbers to be used as command names - `4MiB` or `"4MiB"`: Nushell will not allow filesizes to be used as command names -- `"number#four"` or `"number^four"`: Carets and hash symbols are not allowed in command names +- `"number#four"`, `"number^four"`, or `"number%four"`: Carets, hash symbols, and percent signs are not allowed in command names +- `"foo bar"`, `" foo"`, or `"foo "`: The words of a command name must be separated by single spaces, with no leading or trailing whitespace. Such a name could never be called, so `def`, `extern`, and `alias` reject it. - `-a`, `"{foo}"`, `"(bar)"`: Will not be callable, as Nushell will interpret them as flags, closures, or expressions. -Parser keywords such as `if`, `for`, `let`, `def`, `use` or `where` can't be used as command names at all, because shadowing them would break the language constructs they implement: +Parser keywords such as `if`, `for`, `let`, `def`, `type`, `use` or `where` can't be used as command names at all, because shadowing them would break the language constructs they implement: ```nu def if [] { "my if" } @@ -553,7 +554,7 @@ Most types can be used as type-annotations. In addition, there are a few "shapes - `path`: A string that is treated as a filesystem path. A leading `~` is expanded to the home directory, and "n-dot" shorthands such as `...` are expanded to `../..`. Relative paths stay relative: `.` stays `.`, and `foo/../bar` becomes `bar`. See [Path](/lang-guide/chapters/types/other_types/path.html) in the Language Reference Guide for example usage. - `directory`: A subset of `path` (above). Only directories will be offered when using tab-completion for the parameter. Expansions take place just as with `path`. - `external_arg`: Parses the argument the way an [external command](./running_externals.md) would. A bare word is kept exactly as typed, so `0001` or `true` is not turned into an `int` or `bool`, while quoted strings, variables and subexpressions keep their own value. This is mainly useful for the `main` command of a [script](./scripts.md) that receives arguments from another shell. -- `oneof<...>`: Accepts any one of the listed types, for example `oneof`. +- `oneof<...>`: Accepts any one of the listed types, for example `oneof`. A literal argument gets the first listed type that it matches, with the text-like types (`string`, `path`, `directory`, `glob`, `cell-path`, `external_arg`, and `any`) tried last whatever their position. So with `oneof>`, `[foo bar]` is a list, and with `oneof`, `5` (and `007`) is an `int`. Quote the argument if you need the text. - `error`: Available, but currently no known valid usage. See [Error](/lang-guide/chapters/types/other_types/error.html) in the Language Reference Guide for more information. For example, compare an untyped parameter with an `external_arg` parameter: @@ -590,6 +591,49 @@ The following [types](./types_of_data.html) can be used for parameter annotation ::: +### Type Aliases + +When several commands take or return the same structured data, writing out a type like `record` each time gets long and easy to get wrong. The [`type`](/commands/docs/type.md) keyword gives a type a name: + +```nu +type Point = record +type Polygon = list + +def first-x [poly: Polygon]: nothing -> float { $poly.0.x } + +first-x [{x: 1.0, y: 2.0} {x: 3.0, y: 4.0}] +# => 1.0 +``` + +A type alias is only a shorter way to write its type. The parser replaces the name with the full type wherever the name is used, so `help`, [`describe`](/commands/docs/describe.md), and error messages show the full type: + +```nu +type Point = record +def length-of [p: Point]: nothing -> float { ($p.x ** 2 + $p.y ** 2) | math sqrt } + +length-of {x: 1, y: 2} +# => Error: nu::parser::type_mismatch +# => +# => × Type mismatch. +# => ╭─[repl_entry #3:1:11] +# => 1 │ length-of {x: 1, y: 2} +# => · ──────┬───── +# => · ╰── expected record, found record +# => ╰──── +``` + +You can use a type alias anywhere a type annotation goes: positional parameters, flags, rest parameters, closure parameters, input/output types, the annotations of `let`, `mut`, and `const`, inside other types (such as `list`), and on the right-hand side of another `type`. + +A few rules apply: + +- Like [`alias`](./aliases.md) and `const`, a type alias is visible from its definition to the end of the enclosing block. It must be defined above its first use, and it can't refer to itself. +- A custom completer belongs to the parameter, not the type. Write it on the parameter, as in `def paint [color: Color@[red green blue]] { ... }`. `type Color = string@[red green blue]` is an error. +- In a module, a type alias is private unless it is defined with `export type`. See [Modules](./modules/creating_modules.md#exports) for how to export one and [Using Modules](./modules/using_modules.md#importing-type-aliases) for how to import it. + +::: warning +`type` is a parser keyword, so a custom command, alias, or extern can't be named `type`. To run an external command named `type`, call it as `^type`, or use Nushell's [`which`](/commands/docs/which.md) to see what a command name refers to. +::: + ### Flags In addition to positional parameters, you can also define named flags. diff --git a/book/custom_completions.md b/book/custom_completions.md index be460ef9992..f79b74aee0d 100644 --- a/book/custom_completions.md +++ b/book/custom_completions.md @@ -309,6 +309,20 @@ def --wrapped jc [...args] { } ``` +A `def --wrapped` command passes flags it doesn't declare on to its rest parameter. So a completer on that rest parameter is also called for arguments that start with `-`, and its suggestions are listed together with the command's own flags: + +```nu +def "nu-complete what" [] { [--verbose --color=always plain] } +def --wrapped what [--local, ...args: string@"nu-complete what"] { $args } + +'what --' | commandline complete +# => ╭───┬────────────────╮ +# => │ 0 │ --local │ +# => │ 1 │ --color=always │ +# => │ 2 │ --verbose │ +# => ╰───┴────────────────╯ +``` + ## Custom Descriptions and Styles As an alternative to returning a list of strings, a completion function can also return a list of records with a `value` field and any of these optional fields: @@ -370,7 +384,7 @@ def open-file [path: string@pick-file] { } ``` -Typing `open-file ` and pressing Tab opens `fzf`, and the file you pick is inserted into the command line. +Typing `open-file ` and pressing Tab opens `fzf`, and the file you pick is inserted into the command line. If you cancel the picker instead (for example with Esc), nothing is inserted and no menu stays open; pressing Tab again opens the picker again. ## Testing Completers diff --git a/book/debugging.md b/book/debugging.md new file mode 100644 index 00000000000..89686df2f21 --- /dev/null +++ b/book/debugging.md @@ -0,0 +1,93 @@ +# Debugging Scripts + +Nushell includes a debugger for scripts. Running `nu --dap` starts a [Debug Adapter Protocol](https://microsoft.github.io/debug-adapter-protocol/) (DAP) server, the protocol that editors such as VS Code, Neovim, and Zed use to drive debuggers. Once your editor is set up to use it, you can set breakpoints in a `.nu` file, step through the script line by line and into pipeline stages, look at variables and `$env`, evaluate expressions while the script is paused, and even step backward through what already ran. + +## Setting Up Your Editor + +The editor starts `nu --dap` itself and talks to it over the process's standard input and output, so all it needs to know is the command to run (`nu`, with the argument `--dap`) and which script to launch. The debugger is part of the default build (the `dap` [Cargo feature](./installation.md)). + +For example, with [nvim-dap](https://github.com/mfussenegger/nvim-dap) in Neovim: + +```lua +local dap = require('dap') + +dap.adapters.nu = { + type = 'executable', + command = 'nu', + args = { '--dap' }, +} + +dap.configurations.nu = { + { + type = 'nu', + request = 'launch', + name = 'Debug this script', + program = '${file}', + }, +} +``` + +VS Code needs an extension that registers a debugger for Nushell, which then reads the same launch settings from `launch.json`. + +The debugger loads your `env.nu` and `config.nu` before it runs the script, so the script sees the same custom commands, aliases, and environment as your shell does. Add `-n` to the arguments (`args = { '--dap', '-n' }`) to start from the defaults instead. While the configuration files run, [`$nu.is-dap`](./special_variables.md#nu) is `true`. + +### Launch Settings + +These are the settings a launch configuration can have: + +| Setting | Default | Description | +| -------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | +| `program` | | The absolute path of the `.nu` script to debug. Required. | +| `args` | `[]` | Arguments for `main`, or for the `entryPoint` command, as a list of strings. They are parsed the way `nu