Quality-of-life editor modules for Neovim: file, symbol and call trees, a key-hint popup, completion, a statusline, LSP and Treesitter setup, and a set of editor behaviour flags.
Each module is independent (it can be required and configured on its own) and
none is active unless you name it in setup().
Requires Neovim ≥ 0.11. No other plugins required.
With Neovim ≥ 0.12
vim.pack.add({ "https://github.com/mbfoss/keystone.nvim" })
-- Every module, with a starting point for which to enable. Flip any of these.
require("keystone").setup({
-- Language support
lspconfig = true, -- enables the LSP servers configured in lsp/
tsconfig = true, -- treesitter highlighting and folding
completion = true, -- drives insert-mode completion
-- Editor behaviour
tweaks = true, -- Behaviour tweaks (yank highlight, cursor restore, ...)
largefile = true, -- skips treesitter/LSP/ftplugins on large files
marksigns = true, -- shows the marks that are set in the sign column (0.12+)
animate = false, -- interpolated scrolling
-- Replaces something built in
statusline = true, -- sets 'statusline'
select = true, -- replaces vim.ui.select
notify = true, -- replaces vim.notify, adds :Notifications
clue = true, -- popup of the keys that can follow a trigger
-- Adds a command, does nothing until you run it
filetree = true, -- :FileTree
explore = true, -- :FileSelector
symboltree = false, -- :SymbolTree
calltree = false, -- :CallTree
unsaved = false, -- :DiffUnsaved
bufdelete = false, -- :BDelete, :BWipeout, :BDeleteHidden, :BWipeoutHidden
})Any other plugin manager works too; just point it at
mbfoss/keystone.nvim and call setup() yourself.
Installing only puts keystone on the runtimepath; the setup() call is what
decides which modules run. The four groups differ in how intrusive they are: the
last group only registers a command, while the "replaces something built in"
group takes over a global, so those are the ones to turn off if you already have
a statusline, a vim.notify or a key-hint plugin of your own.
You configure Keystone with a single setup() call. The table you pass has one
key per module you want to turn on. Nothing is enabled unless you list it,
modules you leave out stay off.
The value you give a module says how to turn it on:
| Value | Meaning |
|---|---|
true |
Enable the module with its default options. |
{ ... } |
Enable the module, overriding only the options you name. |
false |
Leave the module off (same as omitting it). |
So these two are equivalent, both enabling filetree with its defaults:
require("keystone").setup({ filetree = true })
require("keystone").setup({ filetree = {} })A fuller example:
require("keystone").setup({
clue = true, -- on, with defaults
filetree = { width_ratio = 0.2 }, -- on, with one option changed
tweaks = { highlight_on_yank = false }, -- on, with one option changed
notify = false, -- off (could also just omit it)
})Each module's available options are documented on its own page under Modules below.
The setup() above is a convenience wrapper. Every module is standalone, so it
can be configured directly instead: the table you pass is that module's
options, the same table that would follow its key above:
require("keystone.filetree").setup({ width_ratio = 0.2 })Each module has its own page in docs/:
| Module | What it does |
|---|---|
| filetree | A file explorer in a side window |
| explore | A file selector for navigating the filesystem |
| calltree | The LSP call hierarchy of the symbol under the cursor |
| symboltree | The LSP document symbols of the current buffer |
| clue | A popup listing the keys that can follow a trigger |
| completion | LSP-driven autocompletion with <Tab>/<CR> |
| statusline | A statusline assembled from configurable sections |
| lspconfig | Enables configured LSP servers, with log rotation |
| tsconfig | Treesitter highlighting and folding, per buffer |
| marksigns | Shows the marks that are set in the sign column |
| largefile | Opens large files without Treesitter, LSP or ftplugins |
| notify | A floating notification UI |
| select | A floating vim.ui.select prompt with fuzzy filtering |
| unsaved | Diff modified buffers against disk |
| bufdelete | Delete or wipe buffers, keeping the window layout |
| animate | Interpolated scrolling |
| tweaks | Seven editor behaviour flags |
Enabling the relevant module registers its command:
| Command | Module | Purpose |
|---|---|---|
:FileTree |
filetree | Open or close the file-tree side window |
:FileSelector |
explore | Open the file selector |
:CallTree |
calltree | Show the call hierarchy of the symbol under the cursor |
:SymbolTree |
symboltree | Toggle the document-symbol side window |
:Notifications |
notify | List or clear the notification history |
:DiffUnsaved |
unsaved | Diff unsaved buffers against disk |
:BDelete :BWipeout :BDeleteHidden :BWipeoutHidden |
bufdelete | Delete or wipe buffers, keeping the window layout |
:checkhealth keystoneReports the Neovim version, the modules whose setup() has run (active) and
those it has not (inactive), then a section per active module listing only the
options you changed from that module's defaults. Unrecognised option names are
reported as warnings: setup() merges the table you pass wholesale, so a
misspelled option would otherwise be accepted without complaint.
Some modules add a deeper check of their own: :checkhealth keystone.tsconfig
reports the installed parsers and any missing queries.
The module pages cover the common cases. For the complete, authoritative list,
each module documents every field as a Config class annotation near the top of
its file (lua/keystone/<module>.lua).
MIT. See ATTRIBUTIONS.md for third-party credits.
Contributing and internals: see DEVELOPMENT.md.