Nushell Auto-Completion
Nushell knows three ways to extend its auto-completion.
Natively, pressing tab gives you file path auto-completion. This serves as the fallback when no other completers are used.
Custom Completions
Custom Completions documents how you can extend a command argument with completion data with @
:
> def animals [] { ["cat", "dog", "eel" ] }
> def my-command [animal: string@animals] { print $animal }
>| my-command
cat dog eel
Beyond static lists, it can also offer completions according to context.
They can also be used on extern
commands (external commands) to integrate non-nushell commands into the shell with auto-completions.
Completions can be simple value lists, like in other shells, or include a description to values, for example to include descriptions you would otherwise have to look up in --help
argument and flag documentation.
External Completions
External Completions is intended for calling external completers to integrate them.
Integrating external completers can be useful for integrating completion frameworks as well as programs that offer their own completions.
For example, dotnet
and winget
offer their own completion interfaces with dotnet complete
and winget complete
.
You can also integrate other shells completions that may already have numerous command auto-completions defined like Fish shell, or you can integrate tools that specifically exist for generalized completion.
Concrete Completions and Caveats
Given that dotnet
and winget
natively offer completion it makes sense to integrate them with external completions, right?
Well, turns out they only return value lists. Which works, and works like in other shells, but misses out on Nushells capabilities of describing options.
Which is why the nu_scripts
repository (official community utils and resources repository) includes Custom Completions for winget
and for dotnet
.
The first is a custom implementation whereas the second is generated from existing fish shell definitions.
nu ❯ | dotnet
dotnet run Run the application from source
dotnet sln Modify Visual Studio solution files
dotnet add Add a package/reference
dotnet new Create a new .NET project
[…]
Adding External Completions
I struggled quite a bit trying to create external completions integration. But eventually I got it to work and understand it, how the passed spans differ between tab on last argument or spaced-after last argument, and how it cascades into further closures.
I also found what I think is a bug and crashes the process: External Completer Call Can Panic
config-external-completers.nu:
# https://www.nushell.sh/book/custom_completions.html#external-completions
# https://www.nushell.sh/cookbook/external_completers.html#carapace-completer
let multiple_completers = {|spans|
match $spans.0 {
# dotnet - nu_scripts has a completion which has item descriptions
# dotnet https://learn.microsoft.com/en-us/dotnet/core/tools/enable-tab-autocomplete#nushell
# `dotnet complete`: arg: args[1..], result: lines
#dotnet => {|| dotnet complete ($spans | skip 1 | str join " ") | lines }
dotnet => { dotnet complete ($spans | skip 1 | str join " ") | lines }
# winget - nu_scripts has a completion which has item descriptions
# winget https://learn.microsoft.com/en-us/windows/package-manager/winget/tab-completion
# winget https://github.com/microsoft/winget-cli/blob/master/doc/Completion.md
# winget - nushell has `commandline get-cursor` we could use, but word identification would be missing -> inconsistency breakage
winget => { winget complete --commandline ($spans | str join " ") --word ($spans | last) --position 999 | lines }
#winget => {|| dotnet-suggest get --executable winget -- ($spans | skip 1 | str join " ") | lines | skip 1 }
# dotnet System.CommandLine https://learn.microsoft.com/en-us/dotnet/standard/commandline/tab-completion
#_ => { dotnet-suggest get --executable ($spans | first) -- ($spans | skip 1 | str join " ") }
#aa => {|| [{value: ($in | length), description:'in count'}] }
#aa => {|| [{value: ($in), description:'in content'}] }
##aa => {|| [{value: ($spans | length), description:'spans count'}] }
##aa => {|| [{value: ($spans | str join "_" | collect), description:'spans joined'} {value:'second'}] }
#aa => {|| $in | str join "," | {|span| {value:$spans} } }
#aa => {|| $in | each {|span| {value:$spans} } }
#a => { $spans | skip 1 | each {|span| {value: $span, description:'ye'} } }
#_ => {|spans| [{value:'default'}] }
}
}
$env.config.completions.external.completer = $multiple_completers