neovim support for the Lean Theorem Prover.
lean.nvim.Demo.mp4
lean.nvim supports neovim 0.5 or a recent neovim nightly (one
newer than September 18, 2021).
If you are on neovim 0.5.1 or earlier, ensure you have set hidden
in your neovim init.lua or init.vim, otherwise you may see
degraded performance from the infoview when opening and closing Lean
files. See here for
details. Newer versions of neovim set hidden by default.
Install via your favorite plugin manager. E.g., with vim-plug via:
Plug 'Julian/lean.nvim'
Plug 'neovim/nvim-lspconfig'
Plug 'nvim-lua/plenary.nvim'
" Optional Dependencies:
Plug 'hrsh7th/nvim-compe' " For LSP completion
Plug 'hrsh7th/vim-vsnip' " For snippets
Plug 'andrewradev/switch.vim' " For Lean switch supportlean.nvim already includes syntax highlighting and Lean filetype
support, so installing the lean.vim (i.e. non-neovim) plugin is not
required or recommended.
lean.nvim supports both Lean 3 as well as the emerging
Lean 4.
For Lean 3 support, in addition to the instructions above, you should
install lean-language-server, which can be done via e.g.:
$ npm install -g lean-language-serverGiven that Lean 3's language server is separate from Lean itself, also ensure you've installed Lean 3 itself.
For Lean 4 support, a recent Lean 4 nightly build is recommended (one at least from mid-October 2021).
In addition to the instructions above, there is experimental nvim-treesitter support being developed in https://github.com/Julian/tree-sitter-lean which can be used for enhanced indentation (TODO), text object (TODO), syntax highlighting and querying but which is still very nascent.
If you wish to try it, it can be installed by adding e.g.:
Plug 'nvim-treesitter/nvim-treesitter'
Plug 'nvim-treesitter/nvim-treesitter-textobjects'if you do not already have tree sitter installed.
As above, many simple syntactical things are not yet implemented (help
is of course welcome). You likely will want to flip back and forth
between it and the standard syntax highlighting via :TSBufDisable
highlight whenever encountering misparsed terms. Bug reports (to the
aforementioned repository) are also welcome.
- Abbreviation (unicode character) insertion, can also provide a nvim-compe or snippets.nvim source.
- An infoview which can show persistent goal, term & tactic state, as well as interactive widgets in both Lean 4 and 3!
- Hover (preview) commands:
:LeanPlainGoalfor showing goal state in a preview window:LeanPlainTermGoalfor showing term-mode type information in a preview window
- switch.vim base definitions for Lean
- Simple snippets (in VSCode-compatible format, so usable with e.g. vim-vsnip)
- Lean library search path access via
lean.current_search_path(), suitable for use with e.g. telescope.nvim for live grepping. See the wiki for a sample configuration. - Simple (or simplistic) implementations of some editing helpers, such as
try thissuggestion replacement
The short version -- after following the installation instructions above,
add the below to ~/.config/nvim/plugin/lean.lua or an equivalent:
require('lean').setup{
abbreviations = { builtin = true },
lsp = { on_attach = on_attach },
lsp3 = { on_attach = on_attach },
mappings = true,
}where on_attach should be your preferred LSP attach handler.
If you do not already have a preferred setup which includes LSP key mappings and (auto)completion, you may find the fuller example here in the wiki helpful.
More detail on the full list of supported configuration options can be found below.
If you've set mappings = true in your configuration (or have called
lean.use_suggested_mappings() explicitly), a number of keys will be mapped
either within Lean source files or within Infoview windows:
| Key | Function |
|---|---|
<LocalLeader>i |
toggle the infoview open or closed |
<LocalLeader>p |
pause the current infoview |
<LocalLeader>x |
place an infoview pin |
<LocalLeader>c |
clear all current infoview pins |
<LocalLeader>s |
insert a sorry for each open goal |
<LocalLeader>t |
replace a "try this:" suggestion under the cursor |
<LocalLeader><Tab> |
jump into the infoview window associated with the current lean file |
<LocalLeader>\\ |
show what abbreviation produces the symbol under the cursor |
Note
See :help <LocalLeader> if you haven't previously interacted
with the local leader key. Some vim users remap this key to make it
easier to reach, so you may want to consider what key that means
for your own keyboard layout. My (Julian's) <Leader> is set to
<Space>, and my <LocalLeader> to <Space><Space>, which
may be a good choice for you if you have no other preference.
| Key | Function |
|---|---|
<CR> |
click a widget or interactive area of the infoview |
K |
click a widget or interactive area of the infoview |
<Tab> |
jump into a tooltip (from a widget click) |
<Shift-Tab> |
jump out of a tooltip and back to its parent |
<Esc> |
clear all open tooltips |
J |
jump into a tooltip (from a widget click) |
C |
clear all open tooltips |
u |
undo the last widget interaction |
I |
mouse-enter what is under the cursor |
i |
mouse-leave what is under the cursor |
U |
clear the stack of undo operations |
<LocalLeader><Tab> |
jump to the lean file associated with the current infoview window |
require('lean').setup{
-- Enable the Lean language server(s)?
--
-- false to disable, otherwise should be a table of options to pass to
-- `leanls` and/or `lean3ls`.
--
-- See https://github.com/neovim/nvim-lspconfig/blob/master/CONFIG.md#leanls for details.
-- Lean 4 (on_attach is as above, your LSP handler)
lsp = { on_attach = on_attach },
-- Lean 3 (on_attach is as above, your LSP handler)
lsp3 = { on_attach = on_attach },
-- What filetype should be associated with standalone Lean files?
-- Can be set to "lean3" if you prefer that default.
-- Having a leanpkg.toml or lean-toolchain file should always mean
-- autodetection works correctly.
ft = { default = "lean" },
-- Abbreviation support
abbreviations = {
-- Set one of the following to true to enable abbreviations
builtin = false, -- built-in expander
compe = false, -- nvim-compe source
snippets = false, -- snippets.nvim source
-- additional abbreviations:
extra = {
-- Add a \wknight abbreviation to insert ♘
--
-- Note that the backslash is implied, and that you of
-- course may also use a snippet engine directly to do
-- this if so desired.
wknight = '♘',
},
-- Change if you don't like the backslash
-- (comma is a popular choice on French keyboards)
leader = '\\',
},
-- Enable suggested mappings?
--
-- false by default, true to enable
mappings = false,
-- Infoview support
infoview = {
-- Automatically open an infoview on entering a Lean buffer?
autoopen = true,
-- Set the infoview windows' starting widths
width = 50,
-- Set the infoview windows' starting heights
-- (portrait windows are split horizontally)
height = 20,
},
-- Progress bar support
progress_bars = {
-- Enable the progress bars?
enable = true,
-- Use a different priority for the signs
priority = 10,
},
}Particularly if you're also a VSCode user, there may be other plugins you're interested in. Below is a (hopelessly incomplete) list of a few:
- nvim-lightbulb for signalling when code actions are available
- goto-preview for peeking definitions (instead of jumping to them)
- lsp-status.nvim for showing LSP information in your status bar
- lsp-trouble for showing a grouped view of diagnostics to pair with the "infauxview"
Contributions are most welcome, as is just letting me know you use this at this point :)
Running the tests can be done via the Makefile:
$ make testwhich will execute against a minimal vimrc isolated from your own setup.
Some linting and style checking is done via pre-commit, which once installed (via the linked instructions) can be run via:
$ make lintor on each commit automatically by running pre-commit install in your
repository checkout.