Skip to content

Move zoxide completer from external_completers to custom_completions #1847

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion book/custom_completions.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,29 @@ cat rat bat

Because we made matching case-insensitive and used `positional: false`, Nushell will find the substring "a" in all of the completion suggestions. Additionally, because we set `sort: false`, the completions will be left in their original order. This is useful if your completions are already sorted in a particular order unrelated to their text (e.g. by date).

## Another Practical Example - Zoxide Path Completions

[Zoxide](https://github.com/ajeetdsouza/zoxide) allows easily jumping between visited folders in the system. It's possible to autocomplete matching folders with this completer:

```nu
def "nu-complete zoxide path" [context: string] {
let parts = $context | split row " " | skip 1
{
options: {
sort: false,
completion_algorithm: prefix,
positional: false,
case_sensitive: false,
},
completions: (zoxide query --list --exclude $env.PWD -- ...$parts | lines),
}
}
Comment on lines +79 to +90
Copy link
Member

@132ikl 132ikl Mar 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we even specify the options here, or just provide the simplest example, and let users add the options if they desire?

ex:

def "nu-complete zoxide path" [context: string] {
  let parts = $context | split row " " | skip 1
  zoxide query --list --exclude $env.PWD -- ...$parts | lines
}

Copy link
Contributor

@fdncred fdncred Mar 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking the same thing but, in this instance, I'd show both. One showing the minimal for comparison and then further down the "fancy" one to showing and describing the somewhat unknown trick of using options in the completer. Or maybe link to wherever options are documented, if they are.

Copy link
Member

@132ikl 132ikl Mar 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think linking to the options is a good idea (in a tip below the minimal example? we could also include the "fancy" version there). It looks like they're documented here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmmm this actually seems to require positional: false to work, not entirely sure why

Copy link
Member

@ysthakur ysthakur Mar 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since Zoxide uses substring matching, positional: false makes it so that Nushell also does substring matching (which reminds me, we need a Substring matching algorithm rather than using positional). With plain prefix matching, even if Zoxide provides some completions, Nushell might filter them out because the prefix doesn't match. So I think the options are necessary for the completer to work for everyone.

I've been meaning to add an option to stop Nushell from doing any filtering and sorting of its own.


def --env --wrapped z [...rest: string@"nu-complete zoxide path"] {
__zoxide_z ...$rest
}
```

## Modules and Custom Completions

Since completion commands aren't meant to be called directly, it's common to define them in modules.
Expand Down Expand Up @@ -230,4 +253,4 @@ let carapace_completer = {|spans|
}
```

[More examples of custom completers can be found in the cookbook](../cookbook/external_completers.md).
[More examples of external completers can be found in the cookbook](../cookbook/external_completers.md).
32 changes: 0 additions & 32 deletions cookbook/external_completers.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,36 +32,6 @@ A couple of things to note on this command:
- The output of the fish completer does not contain a header (name of the columns), so we add `--noheaders` to prevent `from tsv` from treating the first row as headers and later give the columns their names using `rename`.
- `--no-infer` is optional. `from tsv` will infer the data type of the result, so a numeric value like some git hashes will be inferred as a number. `--no-infer` will keep everything as a string. It doesn't make a difference in practice but it will print a more consistent output if the completer is ran on it's own.

### Zoxide completer

[Zoxide](https://github.com/ajeetdsouza/zoxide) allows easily jumping between visited folders in the system. It's possible to autocomplete matching folders with this completer:

```nu
let zoxide_completer = {|spans|
$spans | skip 1 | zoxide query -l ...$in | lines | where {|x| $x != $env.PWD}
}
```

This completer is not usable for almost every other command, so it's recommended to add it as an override in the [multiple completer](#multiple-completer):

```nu
{
z => $zoxide_completer
zi => $zoxide_completer
}
```

> **Note**
> Zoxide sets an alias (`z` by default) that calls the `__zoxide_z` function.
> If [alias completions](#alias-completions) are supported, the following snippet can be used instead:
>
> ```nu
> {
> __zoxide_z => $zoxide_completer
> __zoxide_zi => $zoxide_completer
> }
> ```

### Multiple completer

Sometimes, a single external completer is not flexible enough. Luckily, as many as needed can be combined into a single one. The following example uses `$default_completer` for all commands except the ones explicitly defined in the record:
Expand Down Expand Up @@ -154,8 +124,6 @@ let external_completer = {|spans|
git => $fish_completer
# carapace doesn't have completions for asdf
asdf => $fish_completer
# use zoxide completions for zoxide commands
__zoxide_z | __zoxide_zi => $zoxide_completer
_ => $carapace_completer
} | do $in $spans
}
Expand Down