ParPar is a Neovim plugin that blends Parinfer and Paredit modes together for the best lisp editing experience.
It combines best of both, ease of use of Parinfer and extra power of advanced Paredit operations.
It works by integrating nvim-parinfer and nvim-paredit plugins and making them play well together.
Using lazy.nvim and default paredit bindings:
{
"dundalek/parpar.nvim",
dependencies = { "gpanders/nvim-parinfer", "julienvincent/nvim-paredit" },
opts = { }
},
You can customize paredit options and add custom bindings which are automatically wrapped to work with parinfer:
{
"dundalek/parpar.nvim",
dependencies = { "gpanders/nvim-parinfer", "julienvincent/nvim-paredit" },
config = function()
local paredit = require("nvim-paredit")
require("parpar").setup {
paredit = {
-- pass any nvim-paredit options here
keys = {
-- custom bindings are automatically wrapped
["<A-H>"] = { paredit.api.slurp_backwards, "Slurp backwards" },
["<A-J>"] = { paredit.api.barf_backwards, "Barf backwards" },
["<A-K>"] = { paredit.api.barf_forwards, "Barf forwards" },
["<A-L>"] = { paredit.api.slurp_forwards, "Slurp forwards" },
}
}
}
end
},
If you need extra control you can also manually wrap callback functions with parpar.wrap()
:
local parpar = require("parpar")
require("nvim-paredit").setup {
keys = {
["<A-H>"] = { parpar.wrap(paredit.api.slurp_backwards), "Slurp backwards" },
["<A-J>"] = { parpar.wrap(paredit.api.barf_backwards), "Barf backwards" },
["<A-K>"] = { parpar.wrap(paredit.api.barf_forwards), "Barf forwards" },
["<A-L>"] = { parpar.wrap(paredit.api.slurp_forwards), "Slurp forwards" },
}
}
The custom bindings example above binds Alt+Shift with H, J, K, L to slurp/barf actions. These are based on original vim-sexp bindings. Figuring out whether to tirgger slurp or barf and in which direction can be confusing, but there is a simple mnemonic.
It helps to imagine the parentheses are placed between keys.
The H, J keys manipulate opening parenthesis (left) and K, L manipulate closing parenthesis (right). Then for example opening parenthesis H moves it to the left, J to the right.
( )
🠤 🠦 🠤 🠦
H J K L
Parinfer can interfere with AI completion plugins like Copilot or Codeium. Here is an example how to make parinfer work with the codeium.vim plugin. It uses parpar.pause()
to pause parinfer, then accept the completion and finally resume parinfer asynchronously using a callback to vim.schedule()
.
{
"Exafunction/codeium.vim",
dependencies = { "dundalek/parpar.nvim" },
init = function()
vim.g.codeium_disable_bindings = 1
end,
config = function()
local parpar = require("parpar")
local accept = function()
vim.schedule(parpar.pause())
return vim.fn["codeium#Accept"]()
end
vim.keymap.set("i", "<Tab>", accept, { expr = true })
end
},
The plugin is a thin wrapper over paredit actions:
- Temporarily disable parinfer.
Avoids parinfer interfering with the following paredit action. - Perform the paredit action.
- Enable parinfer again and re-run in paren mode.
This corrects the indentation to make sure it ends up consistent.