# Cliffy 1.2.0: fuzzy search, word navigation, and completeOnSubmit

*Published on 2026-06-04 by c4spar*

## Prompt

### Fuzzy search

Long option lists are hard to navigate with arrow keys alone. Select and
checkbox prompts already supported `search`, and the matching behind it is now a
`searchMode` option with four strategies:

- `"substring"`, a classic contiguous match.
- `"fuzzy"`, the typed characters in order but with gaps allowed, so `strubu`
  finds `structure-builder`.
- `"typo"`, tolerating misspellings, so `stroberry` finds `strawberry`.
- `"all"`, which combines the three and is the default.

So a searchable prompt gets fuzzy and typo matching without asking for it, and
`searchMode` narrows it to one strategy when you want only that one:

```ts
import { Select } from "@cliffy/prompt/select";

const module = await Select.prompt({
  message: "Pick a module",
  search: true,
  searchMode: "fuzzy",
  options: ["command", "prompt", "table", "ansi", "keypress"],
});
```

Substring matches always rank above fuzzy ones, which rank above typo-tolerant
ones, so the closest match stays at the top. The same option is available for
autocomplete suggestions on input prompts.

### Navigating while searching

With `search` enabled, the single-letter navigation keys (`j`, `k`, `n`, `p`)
are typed into the search input rather than moving the selection. `ctrl+n` and
`ctrl+p` now move the highlight through the filtered list without leaving the
input, alongside the arrow keys.

### Word navigation and deletion

Input prompts now understand the editing keys a shell gives you. `alt+left` and
`alt+right`, or `ctrl+left` and `ctrl+right`, move a word at a time. `ctrl+w`
and `alt+backspace` delete the word behind the cursor, and `alt+d` the word
ahead of it. Useful when a prompt collects something long, like a path or a URL,
and it applies to the search input of select and checkbox prompts too.

Those are defaults rather than fixed bindings. The `keys` option rebinds any of
them:

```ts
import { Input } from "@cliffy/prompt/input";

const path = await Input.prompt({
  message: "Path",
  keys: { moveWordLeft: ["alt+b"], moveWordRight: ["alt+f"] },
});
```

### `completeOnSubmit`

Autocomplete prompts can accept whatever is currently highlighted when you press
enter, instead of requiring a separate tab first:

```ts
import { Input } from "@cliffy/prompt/input";

const branch = await Input.prompt({
  message: "Branch",
  suggestions: ["main", "develop", "release"],
  completeOnSubmit: true,
});
```

## Command

### Inherited error handlers

Error handlers now inherit from every ancestor command, not just the immediate
parent, so a handler registered on the root command catches errors thrown deep
in a subcommand tree.

## Fixed in 1.1.1

Shipped in the patch since 1.1.0:

- The `upgrade` command respects `minimum-dependency-age` and `min-release-age`.
- `h` and `l` are treated as search input when a prompt has `search` enabled,
  rather than as vim navigation keys.
- A type error with Deno 2.8 and newer, caused by the return type of
  `setInterval` in the upgrade command's spinner, is fixed. It only showed up
  for anyone type checking their dependencies, with `deno check --all` or
  `deno run --check=all`.

## Acknowledgements

Thank you to everyone who filed the bug reports and questions that shaped this
release.

Contributions are welcome. The
[contributing guide](https://github.com/c4spar/cliffy/blob/main/CONTRIBUTING.md)
covers how to get started.
