Skip to content

Configuring & Extending

Julian Berman edited this page May 9, 2024 · 19 revisions

This page collects a number of additional links or snippets which may be helpful for Lean.

Feel free to add your own, or add links to your dotfiles.

Generally Useful neovim Functionality

neovim of course has a large amount of non-Lean specific functionality whose use may not be familiar to all. Here are some examples of functionality you may want to be aware of, along with how you might use it in your Lean workflow:

Window Styling

It can be hard to see the contents of floating windows (such as those shown when hitting K to hover over something) without window borders. If you prefer having them (which is recommended) you want to set:

vim.lsp.handlers['textDocument/hover'] = vim.lsp.with(vim.lsp.handlers.hover, { border = "single" })

once globally somewhere in your neovim configuration, which will apply it to all languages.

There is a similar option for diagnostic floating windows which is set via e.g.:

vim.diagnostic.config{ severity_sort = true, float = { border = 'rounded' } }

Navigating Diagnostics

You will often want to move forward (or back) to the nearest error or warnings in your files. The mechanism for doing so is vim.diagnostic.goto_next() (respectively vim.diagnostic.goto_prev()). See the help for further details, though if you want a slightly cleverer improvement, you can find an example of how to combine jumping to the next diagnostic with opening a float only if the virtual text doesn't already show you the full error here.

Navigating Definitions

When jumping back and forth to view definitions of Lean declarations (via gd) you should be aware of a few built-in features:

  • Hit <C-w>] to open definitions in a split instead of in the current buffer (see :h CTRL-W_] for further details)
  • You also may be interested in a plugin which opens them in floating windows, such as rmagatti/goto-preview, or to do so inline in your own configuration. See here for an example.

The jumplist (:h jumplist) is also very much your friend! Neovim keeps a record each time you "jump" the cursor, and going to a definition is a jump. What this means in practice is that after you hit gd, you can use <C-o> to jump back to where you were previously!

Navigating Between Files in a Project

A fuzzy finder is arguably completely indispensable for modern editing with neovim. It allows you to type subsections of "thing"s and "act" on the result. Most simply, the "things" are often paths, and "acting" is "jumping to the file" -- so one can type something as short as alrinba<enter> and immediately jump to Mathlib/Algebra/Ring/Basic.lean.

Telescope is the most commonly used fuzzy finder for neovim at this point, so you're highly encouraged to use it.

Preventing the Progress Bars from Horizontally Shifting Your File

By default, (neo)vim will automatically show and hide the "sign column", which is where lean.nvim shows progress information (in highly technical terms, "orange bars").

Orange bars

If you prefer that the sign column be shown always, even when no orange bars are shown indicating progress, the vim option to do so is:

vim.opt.signcolumn = "yes"

which you can put in your configuration.

Mathlib Style Linting

The below configuration for nvim-lint:

      local lint = require('lint')

      lint.linters.mathlib4 = {
        name = 'mathlib',
        cmd = 'scripts/lint-style.py',
        stdin = false,
        stream = 'stdout',
        ignore_exitcode = true,
        parser = require('lint.parser').from_pattern(
          '::(%l+) file=([^:]+),line=(%d+),code=ERR_(%w+)::[^ ]+ ERR_%w+: (.+)',
          { 'severity', 'file', 'lnum', 'code', 'message' }
        ),
      }

      lint.linters_by_ft = {
        lean = { 'mathlib4' },
      }

should work for showing mathlib style lint errors inline:

linting

Live Grep

Configuration

asciicast

Automatically Moving the Infoview on Screen Resize

You can use the infoview.reposition function to move an infoview window to where it "belongs".

If you do so in an autocmd, specifically on VimResized events, you can move the infoview whenever the screen resizes:

vim.api.nvim_create_autocmd('VimResized', { callback = require('lean.infoview').reposition })

Semantic Highlighting

Lean and Neovim have joint support for semantic highlighting. This means the Lean server can tell Neovim information about what things you see in your Lean files represent, allowing for better syntax highlighting.

You can find brief information on semantic highlighting in the Lean Manual some of which is VSCode-specific (but some which is not).

In particular, you can tweak similar settings in Neovim if you do not find that variables, particularly autoImplicit ones, are well differentiated from "real" terms.

You can use e.g. vim.print(vim.lsp.semantic_highlighting.get_at_pos()) to see what semantic highlighting tokens the Lean server has sent for whatever is under your cursor.

You also should look at your own chosen Neovim theme to decide which highlight groups, if any, are ones you want to link highlights to -- in other words, if your theme has a Variable highlight group, you may want to link @lsp.type.variable to this group, making them the same color.

You likely will not need to map all of the LSP highlight groups, as Neovim maps many LSP groups to things your theme will likely color correctly by default, but it will depend on the theme. See :h lsp-semantic-highlight for a list of available groups, and the default mapping to other highlight groups.

To parallel what's in the Lean documentation, putting the below in a file such as ~/.config/nvim/after/syntax/lean.lua will map Lean variables to the Identifier highlight group (which should make them a different color than other terms):

local mappings = {
  ['@lsp.type.variable'] = 'Identifier',
}

for from, to in pairs(mappings) do
  vim.cmd.highlight('link ' .. from .. ' ' .. to)
end

Feel free to add additional entries to the above if you notice other mis-highlighted syntax using your own theme.

Session Saving

If you want to save your nvim session to disk to recover upon re-opening nvim, you need to be careful to avoid saving the infoview windows/buffers as part of that session data, as these are handled by the plugin, and doing so will result in extraneous windows being opened when you load the session.

The builtin :mksession command with its 'sessionoptions' unfortunately doesn't seem to provide the ability to filter out such buffers/windows (at least, I wasn't able to figure it out). For that reason, I recommend making use of the resession.nvim plugin, and configuring it like so:

local resession = require('resession')
resession.setup({
  buf_filter = function(bufnr)
    -- filter out infoview windows that start with "lean:" (if you have an existing filter condition then "and" this onto that)
    return not vim.startswith(vim.api.nvim_buf_get_name(bufnr), "lean:")
  end,                                                                                                                                         
  -- good to periodically save your sessions for the time being since this plugin tends to freeze while editing Lean 4 files :(                                                                                                             
  -- (you have to initially save/load your session to activate this)                                                                                
  autosave = {
    enabled = true,
    interval = 60,
    notify = false,
  },
})

vim.keymap.set('n', '<leader>sss', resession.save)
vim.keymap.set('n', '<leader>ssl', resession.load)
vim.keymap.set('n', '<leader>ssd', resession.delete)

Loogle integration

If telescope.nvim is installed you can run :Telescope loogle to use https://loogle.lean-lang.org from within your editor:

image image Pressing enter is going to insert the name of the theorem or definition you are hovering on at the current position of your cursor.