# parinfer-rust infers your parentheses from how you type

> parinfer-rust is a Rust port of parinfer that keeps Lisp-family source balanced while you edit, in smart mode rather than by switching between paren and indent modes, with plugins for Vim, Neovim, Kakoune and Emacs, a WebAssembly build and a standalone CLI.

**eraserhd/parinfer-rust** — A Rust port of parinfer.

- Repository: https://github.com/eraserhd/parinfer-rust
- Stars: 632 · Forks: 55
- Language: Rust
- License: ISC
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/eraserhd-parinfer-rust

## The problem parinfer solves

parinfer-rust infers parentheses for Clojure, Lisp and Scheme, and it is a full-featured, fast implementation of Shaun Lebron's parinfer. The upstream project is credited in the contributor list with inventing parinfer and doing the math behind it, and this repository is the Rust port of it.

The problem is the one every Lisp-family editor faces. Parentheses are not decoration, they are structure, and a file with one missing closing paren is not merely ugly, it is unreadable to the tooling. The traditional fix is to be careful, and the traditional tool is a formatter that you run afterwards.

Parinfer takes a different approach. Instead of checking the file after the fact, it infers the parens from what you are doing as you type, so the file stays balanced at all times. It works on the raw text, which is why it can run on a file that is momentarily unbalanced, and the inference is driven by the shape of the edit rather than by a full parse of the buffer.

The repository ships plugins for Vim, Neovim and Kakoune, and an Emacs plugin by Justin Barclay is available separately. The Rust library itself can be called from other editors that can load dynamic libraries, which is the reason the crate is built as both a library and a cdylib.

The audience is therefore a Lisp or Clojure developer who spends the day in Vim, Neovim or Kakoune and who wants the paren problem to stop being their problem.

## Smart mode instead of a mode switch

The README makes one design claim explicitly, and it is the claim that distinguishes this implementation from the other Vim plugins available.

Those other plugins implement paren mode or indent mode, and the user picks one. parinfer-rust implements the smart mode. Rather than switching between paren mode and indent mode, parinfer uses information about how the user is changing the file to decide what to do.

The distinction matters in practice. In paren mode, typing a closing paren inserts a closing paren. In indent mode, the closing paren is inferred and the editor's own indentation rules are respected. Smart mode looks at the edit itself to work out which behaviour is appropriate, so a developer who is closing a form by hand gets their paren, and a developer who is reindenting a block gets the indentation, without a setting to flip.

That inference is the whole intellectual content of parinfer, and the Rust port carries the same algorithms. The performance claim follows from the implementation: this is a compiled Rust implementation, which is why the README calls it fast.

The cost of the port is a toolchain. Building it needs a Rust compiler, and the dependency list in the README includes clang and libclang-dev packages or the equivalent for your operating system, along with a Rust version of about 1.83 or newer.

## Building the CLI, and the Emacs feature flag

The standalone command line route is two cargo commands, and the README presents it as the option for people who just want to run parinfer-rust from the command line:

```bash
$ cargo build --release
$ cargo install
```

The build produces the release binary, and the install puts it on your path. The Makefile does the same pair of steps with a forced install, and adds the Kakoune-specific part:

```make
install:
	cargo build --release
	cargo install --force
	mkdir -p ~/.config/kak/autoload/
```

That Makefile target also links the rc files into the Kakoune autoload directory, which is how the Kakoune plugin finds its commands.

There is one build option worth knowing about. If you use Emacs, you add the corresponding feature flag during compilation:

```bash
$ cargo build --release --features emacs
```

The Cargo manifest shows how that flag is wired. The emacs dependency is an optional one, and the crate is declared with crate-type = ["lib", "cdylib"], which is what lets the same code be loaded as a dynamic library by an editor that supports it, in addition to being used as a Rust library and as a command line binary. There is also a separate binary target named parinfer-rust with its path at src/main.rs.

The rest of the dependency set is modest: getopts for the command line, serde and serde_json for the data formats, libc for the system layer, unicode-segmentation and unicode-width for text handling, and platform-specific entries, stdweb for the wasm32 target and winapi with the libloaderapi feature for Windows. The Windows dependency is there because the editors load the library through the platform's loader.

## Vim and Neovim, through five different plugin managers

The editor integration is the longest part of the README, and that is a fair signal of how much of the work is in the plumbing rather than the algorithm.

For Neovim 0.12 and later, the plugin is added with vim.pack.add, and a build step is wired to an autocmd so the binary is compiled when the plugin is installed or updated:

```lua
vim.api.nvim_create_autocmd('PackChanged', {
  callback = function(ev)
    local name, kind = ev.data.spec.name, ev.data.kind
    if name == 'parinfer-rust' and (kind == 'install' or kind == 'update') then
      vim.system({ 'cargo', 'build', '--release' }, { cwd = ev.data.path })
    end
  end,
})

vim.pack.add { 'https://github.com/eraserhd/parinfer-rust' }
```

For pathogen users, the repository is cloned into the bundle directory and built with cargo, and the vim-plug and lazy.nvim routes follow the same pattern with a build command in the plugin declaration. lazy.nvim takes the shortest form, with build = "cargo build --release" in the setup table.

There is a Nix route as well, for people who build their editor configuration with Nix and Home Manager, where the plugin becomes an attribute of the neovim program.

Every one of these routes ends in the same place: a cargo build --release in the plugin directory. That is the recurring cost of this project, and it is the reason the build is not optional the way a pure Vim script plugin would be.

## Kakoune: a filetype hook and a build command

The Kakoune integration is a good example of how little ceremony a plugin needs when the host editor is scriptable, and how much of the ceremony is the build.

With plug.kak, the plugin declaration carries both a build block and a configuration block. The build runs cargo install --force --path ., and the configuration hooks into the global WinSetOption event so that the plugin is enabled for a set of file types:

```kak
plug "eraserhd/parinfer-rust" do %{
    cargo install --force --path .
} config %{
    hook global WinSetOption filetype=(clojure|lisp|picolisp|racket|scheme) %{
        parinfer-enable-window -smart
    }
}
```

After that you re-source the kakrc or restart Kakoune and run the plug-install command, which downloads, builds and installs the plugin. The README also suggests adding a cargo clean line to the do block so the plugin loads faster, since the build artefacts no longer need to be scanned.

The manual route is a clone, a make install and a cargo build and install, followed by the same hook in the kakrc, this time with the smart mode flag on the enable command.

The filetype list is worth noting on its own: clojure, lisp, picolisp, racket and scheme. The contributor list credits Mitsuhiro Nakamura with support for Common Lisp and Scheme, and Sunjay Cauligi with support for Hy, and the ElKowar entry mentions user-defined string-delimiters and support for Yuck, which is the kind of dialect-specific detail that shows the port is kept in step with the original's language coverage.

## WebAssembly and how the tests are run

There is a WebAssembly build, and it has a specific toolchain requirement. The README says WebAssembly currently needs the nightly toolchain, and lists the commands:

```bash
$ rustup update
$ rustup install nightly
$ rustup target add wasm32-unknown-unknown --toolchain nightly
$ cargo +nightly install cargo-web
```

and then the build itself is cargo +nightly web build --release. The package.json script for it chains the cargo web build with a copy of the generated parinfer_rust.js and parinfer_rust.wasm into the dist directory, and the main entry point of that package is dist/wrapper.js. That is the path for embedding parinfer-rust in a web page.

The test story is more interesting than the build story. The CI server uses Nix to make reproducible build and test environments, and the README says it is a good idea to run the tests with it:

```bash
$ nix flake check                        # Build and test everything
$ cargo +nightly web test                # Test the WebAssembly version
$ vim --clean -u tests/vim/run.vim       # Test against locally-installed Vim
$ ( cd tests/kakoune && ./run.sh )       # Test against locally-installed Kakoune
```

The tests run against the real editors rather than against a mock, which is the right approach for a plugin whose job is to behave correctly inside somebody's buffer. The Vim tests are in a readable format in tests/vim/test-cases.md, and the README asks for tests for new features and for old ones too. There is also a VIM_TO_TEST environment variable to point the suite at a different Vim build, for testing unusual versions.

The repository layout supports all of this: plugin for the editor code, rc for the Kakoune configuration, src for the Rust, tests for the editor test suites, benches for the benchmarks, and a flake.nix and derivation.nix for the Nix side.

## Licence, version state and who did the work

The licence is ISC, recorded in the package metadata and in the repository's LICENSE.md file, and the README links to it directly. ISC is a short permissive licence with an attribution requirement and no copyleft obligation, which is a common choice for a tool of this kind because it stays out of the way of whatever the user does with their Lisp source.

The version state is the one thing a reader has to interpret carefully. The published release tags are v0.4.3 on 2020-02-23, v0.4.2 on 2020-01-05 and v0.4.1 on 2020-01-04, all from early 2020, while the crate and package versions in the repository are 0.5.0. The last push to the repository was on 2026-08-15 and the repository is not archived.

So the tags are old and the working tree is ahead of them, which for a plugin distributed by clone and cargo build is a normal arrangement rather than a problem. The practical consequence is that you build from a commit, not from a release, and you should record which commit you used.

The contributor list is worth reading because it shows the port is a community effort rather than a single person's translation. Shaun Lebron is credited with inventing parinfer and doing the math. Case Nelson wrote the nvim-parinfer, from which the VimL code and some inspiration were taken. Justin Barclay provided the Emacs module. Michael Camilleri added user-defined comments, Mitsuhiro Nakamura added support for Common Lisp and Scheme, ElKowar added user-defined string-delimiters and support for Yuck, Graham Enos updated the Rust edition, and Sunjay Cauligi added support for Hy.

That list also answers a question the documentation does not: how much of the behaviour of the original parinfer is actually in this port. The answer is most of it.

## Conclusion

parinfer-rust fits a Lisp or Clojure developer who edits in a Vim-family editor and wants balanced parentheses without choosing a mode, and who is comfortable compiling a Rust binary and wiring a plugin into their configuration. It is the wrong choice for an editor with no plugin mechanism, and the wrong choice for a team that would rather settle the formatting question in the toolchain with a formatter than in the editor. Before adopting it, check the editor integration you use against the plugin managers documented here, and note that the published release tags stop in 2020 while the crate version has moved on, so pin deliberately and expect to build from source.

## FAQ

### What does parinfer-rust do?

It infers parentheses for Clojure, Lisp and Scheme as you edit, and it is a Rust port of Shaun Lebron's parinfer. Rather than switching between paren mode and indent mode, it uses information about how the user is changing the file to decide what to do.

### Which editors does parinfer-rust support?

The repository ships plugins for Vim, Neovim and Kakoune, an Emacs plugin is available separately from Justin Barclay's parinfer-rust-mode, and the Rust library can be called from other editors that can load dynamic libraries.

### How do I build and install the parinfer-rust command line tool?

Run cargo build --release followed by cargo install. If you use Emacs, compile with the emacs feature flag instead, using cargo build --release --features emacs. The dependencies are a Rust toolchain of about 1.83 or newer plus clang and libclang-dev or the equivalent for your system.

### How do I enable parinfer in Kakoune?

With plug.kak, declare the plugin with a do block running cargo install --force --path . and a config block that hooks global WinSetOption for the clojure, lisp, picolisp, racket and scheme file types and calls parinfer-enable-window -smart. Then run the plug-install command.

### How are the parinfer-rust tests run?

The CI server uses Nix for reproducible environments, and the README recommends nix flake check. There are also commands for testing the WebAssembly build with cargo +nightly web test, testing against a locally installed Vim with vim --clean -u tests/vim/run.vim, and testing against Kakoune with the script in tests/kakoune.

## Sources

- [eraserhd/parinfer-rust on GitHub](https://github.com/eraserhd/parinfer-rust)
- [Issues](https://github.com/eraserhd/parinfer-rust/issues)
- [License: ISC](https://github.com/eraserhd/parinfer-rust/blob/master/LICENSE)
- [README](https://github.com/eraserhd/parinfer-rust/blob/master/README.md)
- [Releases](https://github.com/eraserhd/parinfer-rust/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/eraserhd-parinfer-rust
