LSP: vale (prose linter)


I am trying to implement an lspconfig for vale, which is a customizable syntax-aware prose linter. The only thing I want it to do for now is to have the textDocument/publishDiagnostics LSP request.

My approach so far:

  1. vale provides both a server and a CLI (see their Creating a plugin guide, the output can also be inspected there). I am going with the CLI approach since it looks simpler, so I set the cmd to output JSON:
configs.vale = {
  default_config = {
    cmd = { "vale --output=JSON" },
    -- ...
  1. Since vale does not follow the LSP specification, I think I have to implement a handler:
    -- ...
    handlers = {
      ["textDocument/Diagnostic"] = vale_handler,
  1. Now, I copied the handler from the denols config:
local function vale_handler(err, method, result)
  if not result or vim.tbl_isempty(result) then
    return nil

  for _, res in pairs(result) do
  -- I have to handle uris somehow
  -- I have to map lines and spans to a range.
  -- I have to map Message to message

  lsp.handlers[method](err, method, result)

I have a lot of questions (I am not used to developing stuff in neovim, so reading :h lsp was a bit hard):

  1. Is this the way to go? :slight_smile:
  2. Inside the handler function, what is the input passed as arguments exactly? Is each thing in results a (uri, cmd-output) pair or something? If so, is cmd-output a raw string that I have to parse?
  3. What is lsp.handlers[method](err, method, result) expecting as result? I guess it is something in the LSP specification, but what type, a string, a table?

I hope I got something right about this. Also, let me know if someone is working in a prose linter integration like this one, like proselint or whatever, it is a functionality that I’d really like for my TEX and MD editing.

The handler isn’t the part that generates the diagnostics, but instead it is the function which is called if a language server sends diagnostics to the client.
You’d have to call the existing diagnostic handler with a fake lsp- client

 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                           β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
 β”‚ lsp.handlers          │◄──────────────────────────│lsp serverβ”‚
 β”‚  on_publishDiagnosticsβ”‚   (diagnostics result)    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      commnication via
                                nvim lsp client / rpc

There are already some options you can check out that allow you to use Vale via the vim.lsp.diagnostic interface

1 Like

Uh, I am going to give a try to null-ls, which looks super cool and exactly what I was trying (struggling) to do (I’ve also just seen it in this TJ youtube video).

Thank you so much!

In case someone is looking for this feat: builtin vale by carrascomj Β· Pull Request #30 Β· jose-elias-alvarez/null-ls.nvim Β· GitHub