Use LanguageTool with neovim

Sunday, December 24, 2023 · 3 minutes · 594 words

I do a lot of mistakes when typing. The use of a spellchecker in neovim is easy but not enough : I mostly do grammar mistakes.

So how can we leverage neovim to not only check for spelling but also for grammar ? And if possible, how to do it for multiple languages as I also write in French ?

We can integrate LanguageTool 1 with neovim using LTeX 2.

This is my plan

  • Install LTeX in neovim using Mason
  • Apply LanguageTool suggestion using Code Actions
  • Use Telescope for the code actions suggestion
  • Tips : force the language in Markdown

Install LTeX in neovim using Mason

You can manually install LTeX in neovim with the following command

:MasonInstall ltex-ls

But, if you want to make it permanent in your configuration, or you want to change its default options, you will need to add it to your neovim init.lua. I have a special section for neovim to install and configure all my language servers in neovim. I declare an array servers :

local servers = {
...
}

and inside, for each language, I have this sort of snippet :

  ltex = {
    ltex = {
      language = "fr"
    },
  },

This one is for LTeX, setting the default language to French. The first key is the language server name and the second is its settings object. It is not always the same as for ltex. See, for example, the Lua version :

  lua_ls = {
    Lua = {
      workspace = { checkThirdParty = false },
      telemetry = { enable = false },
    },
  },

Here we have lua_ls for the language server name and Lua for the object setting.

Then, I have this code to configure all servers via mason :

-- Ensure the servers are installed
local mason_lspconfig = require 'mason-lspconfig'
mason_lspconfig.setup {
  ensure_installed = vim.tbl_keys(servers), -- take every key entry to install the corresponding language server
}
mason_lspconfig.setup_handlers {
  function(server_name)
    require('lspconfig')[server_name].setup {
      capabilities = capabilities,
      on_attach = on_attach,
      settings = servers[server_name], -- associate each language server setting
    }
  end,
}

Apply LanguageTool suggestions

So now that we have LTeX configured, how can we use it ?

As LTeX works with LSP, like any other language server, we can use the Code Actions to apply suggestions.

For example, we can use this command :

:lua vim.lsp.buf.code_action()

This brings the default neovim ui to select an action.

You better remap this to a key combination to make it more easily actionable :

vim.keymap.set('n', '<leader>ca', vim.lsp.buf.code_action, {desc = 'Code Action'}, {noremap = true, silent = true})

Use Telescope as UI selector

The default code actions picker of neovim is minimalist : we have to type the number associated with the action we want to apply and then press enter.

There is a nice plugin to make Telescope the default ui selector. I added this lines to my init.lua :

  {
    'nvim-telescope/telescope-ui-select.nvim',
    config = function() require("telescope").load_extension("ui-select") end,
  }

Relaunch neovim and now, Telescope is used as a picker for the code actions.

Tips : force the language in Markdown

By default, LTeX will use the default language we have configured above. But, what if you need to write a post in another language ?

An easy way is to provide LTeX with a special header in the front matter of your markdown :

---
title: A nice title
date: 2023-12-25T01:18:29+01:00
lang: en-US
---

The lang entry contains the language code expected by LTeX as seen in https://valentjn.github.io/ltex/supported-languages.html


  1. LanguageTool is a multilingual spelling, style and grammar checker ↩︎

  2. LTeX plugs LanguageTool with editors via language server protocol (LSP) ↩︎