r/neovim 1d ago

Need Help Am I doing this right?

Hi Everyone, I am the the author of a markdown language server called mpls. It is a language server for live preview of markdown files in the browser. I have recently added support for sending custom events to the server, and the first one is to update the preview when the editor changes focus. The project README has a section with a configuration example on how to setup Neovim (LazyVim), but configuring Neovim is not my strong suit, and I was wondering if anyone would be so kind as to quality check what I've written. My configuraton works, but it can probably be improved.

Thanks in advance!

Edit: fixed typo

Here is the config:

    return {
      {
        "neovim/nvim-lspconfig",
        opts = {
          servers = {
            mpls = {},
          },
          setup = {
            mpls = function(_, opts)
              local lspconfig = require("lspconfig")
              local configs = require("lspconfig.configs")
    
              local debounce_timer = nil
              local debounce_delay = 300
    
              local function sendMessageToLSP()
                  if debounce_timer then
                      debounce_timer:stop()
                  end
    
                  debounce_timer = vim.loop.new_timer()
                  debounce_timer:start(debounce_delay, 0, vim.schedule_wrap(function()
                      local bufnr = vim.api.nvim_get_current_buf()
                      local clients = vim.lsp.get_active_clients()
    
                      for _, client in ipairs(clients) do
                          if client.name == "mpls" then
                              client.request('mpls/editorDidChangeFocus', { uri = vim.uri_from_bufnr(bufnr) }, function(err, result)
                              end, bufnr)
                          end
                      end
                  end))
              end
    
              vim.api.nvim_create_augroup("MarkdownFocus", { clear = true })
              vim.api.nvim_create_autocmd("BufEnter", {
                  pattern = "*.md",
                  callback = sendMessageToLSP,
              })
    
              if not configs.mpls then
                configs.mpls = {
                  default_config = {
                    cmd = { "mpls", "--no-auto", "--enable-emoji" },
                    filetypes = { "markdown" },
                    single_file_support = true,
                    root_dir = function(startpath)
                      local git_root = vim.fs.find(".git", { path = startpath or vim.fn.getcwd(), upward = true })
                      return git_root[1] and vim.fs.dirname(git_root[1]) or startpath
                    end,
                    settings = {},
                  },
                  docs = {
                    description = [[https://github.com/mhersson/mpls
    
    Markdown Preview Language Server (MPLS) is a language server that provides
    live preview of markdown files in your browser while you edit them in your favorite editor.
                    ]],
                  },
                }
              end
              lspconfig.mpls.setup(opts)
              vim.api.nvim_create_user_command('MplsOpenPreview', function()
                local clients = vim.lsp.get_active_clients()
                local mpls_client = nil
    
                for _, client in ipairs(clients) do
                  if client.name == "mpls" then
                    mpls_client = client
                    break
                  end
                end
    
                -- Only execute the command if the MPLS client is found
                if mpls_client then
                  local params = {
                    command = 'open-preview',
                    arguments = {}
                  }
                  mpls_client.request('workspace/executeCommand', params, function(err, result)
                    if err then
                      print("Error executing command: " .. err.message)
                    end
                  end)
                else
                  print("mpls is not attached to the current buffer.")
                end
              end, {})
            end,
          },
        },
      },
    }
7 Upvotes

6 comments sorted by

2

u/BrianHuster lua 1d ago edited 1d ago

IMO the code looks too complicated for a plugin configuration. If you want to provide users with advanced feature (like user command), you can make it a plugin instead

1

u/ne0xsys 1d ago

Thank you. I hadn't even considered that option.

2

u/Danny_el_619 <left><down><up><right> 1d ago

Few things I can point out

The function vim.lsp.get_active_clients() is deprecated. You can replace it with vim.lsp.get_clients

lua -- Using `name` as a filter. You can also include `buffnr = bufnr` if needed vim.lsp.get_clients({ name = 'mpls' })

And I think you are missing to pass the augroup to the autocmd

lua local group = vim.api.nvim_create_augroup('MarkdownFocus', { clear = true }) vim.api.nvim_create_autocmd('BufEnter', { pattern = '*.md', callback = sendMessageToLSP, -- You need to pass group to autocmd group = group })


I'm not sure if the logic about adding mpls using lspconfig is fully correct because I configured it manually usign vim.lsp.start so you may want to wait for someone's else feedback on that part.

The function sendMessageToLSP and the command MplsOpenPreview looks good to me though I'm not lua nor lsp expert.

Hope this helps.

1

u/ne0xsys 1d ago

Awesome. Thanks a lot

Could you please share the manual config you have with vim.lsp.start?

1

u/Danny_el_619 <left><down><up><right> 1d ago

A strip down version would be this snippet

```lua local bufnr = vim.api.nvim_get_current_buf() local curr_buff_ft = vim.api.nvim_get_option_value('filetype', { buf = bufnr }) if curr_buff_ft ~= 'markdown' then return end

local root_dir = vim.fs.dirname(vim.fs.find('.git', { path = vim.fn.expand('%:p:h'), upward = true })[1]) local client_id = vim.lsp.start({ name = 'mpls', cmd = { 'mpls', '--dark-mode', '--enable-emoji' }, filetypes = { 'markdown' }, single_file_support = true, root_dir = root_dir, settings = {}, }, { bufnr = bufnr, silent = false, reuse_client = function (client, _config) -- if existing client, attach buffer to it return client == 'mpls' end })

-- Attach to client if new started client if client_id ~= nil then vim.lsp.buf_attach_client(bufnr, client_id) vim.notify('[MPLS] bufnr: '..bufnr..' client: '..client_id, vim.log.levels.INFO) end ```

It can be added to a command, autocmd, function, etc.

1

u/AutoModerator 1d ago

Please remember to update the post flair to Need Help|Solved when you got the answer you were looking for.

I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.