nvim-lspconfig icon indicating copy to clipboard operation
nvim-lspconfig copied to clipboard

How to set per-client commands to start_client?

Open Aetf opened this issue 2 years ago • 5 comments

Description

neovim/neovim#16101 makes it possible to use per-client command handlers. However, there seems to be no way to actually pass this to start_client call.

Neovim version

NVIM v0.6.1 Build type: Release LuaJIT 2.1.0-beta3

Nvim-lspconfig version

c276536bcdb03f2e1c353b04abb1a719814d4197

Operating system and version

ArchLinux 5.16.11-zen1-1-zen

Affected language servers

all

Steps to reproduce

The setup{} function takes a table which contains a superset of the keys listed in :help vim.lsp.start_client() with the following unique entries

Per documentation, the following should work, but in fact doesn't:

require('lspconfig').ltex.setup {
    commands = {
        ['_ltex.addToDictionary'] = function() end,
    }
}

Because lspconfig takes the commands key as a different meaning, as explained in the lspconfig-configurations section of the documentation.

commands is a map of name:definition key:value pairs, where definition is a list whose first value is a function implementing the command, and the rest are either array values which will be formed into flags for the command, or special keys like description.

So the above code errors out as it doesn't pass the check.

I'm aware of vim.lsp.commands as a workaround but I think it should be possible to make use of neovim/neovim#16101 and set custom command handlers. Or at least the documentation should be updated to mention the different meaning of the commands key when passed to setup.

Actual behavior

Error during start up:

...m/site/pack/paqs/opt/lspconfig/lua/lspconfig/configs.lua:46: attempt to index local 'v' (a function value)

Expected behavior

No response

Minimal config

local on_windows = vim.loop.os_uname().version:match 'Windows'

local function join_paths(...)
  local path_sep = on_windows and '\\' or '/'
  local result = table.concat({ ... }, path_sep)
  return result
end

vim.cmd [[set runtimepath=$VIMRUNTIME]]

local temp_dir = vim.loop.os_getenv 'TEMP' or '/tmp'

vim.cmd('set packpath=' .. join_paths(temp_dir, 'nvim', 'site'))

local package_root = join_paths(temp_dir, 'nvim', 'site', 'pack')
local install_path = join_paths(package_root, 'packer', 'start', 'packer.nvim')
local compile_path = join_paths(install_path, 'plugin', 'packer_compiled.lua')

local function load_plugins()
  require('packer').startup {
    {
      'wbthomason/packer.nvim',
      'neovim/nvim-lspconfig',
    },
    config = {
      package_root = package_root,
      compile_path = compile_path,
    },
  }
end

_G.load_config = function()
  vim.lsp.set_log_level 'trace'
  if vim.fn.has 'nvim-0.5.1' == 1 then
    require('vim.lsp.log').set_format_func(vim.inspect)
  end
  local nvim_lsp = require 'lspconfig'
  local on_attach = function(_, bufnr)
    local function buf_set_keymap(...)
      vim.api.nvim_buf_set_keymap(bufnr, ...)
    end
    local function buf_set_option(...)
      vim.api.nvim_buf_set_option(bufnr, ...)
    end

    buf_set_option('omnifunc', 'v:lua.vim.lsp.omnifunc')

    -- Mappings.
    local opts = { noremap = true, silent = true }
    buf_set_keymap('n', 'gD', '<Cmd>lua vim.lsp.buf.declaration()<CR>', opts)
    buf_set_keymap('n', 'gd', '<Cmd>lua vim.lsp.buf.definition()<CR>', opts)
    buf_set_keymap('n', 'K', '<Cmd>lua vim.lsp.buf.hover()<CR>', opts)
    buf_set_keymap('n', 'gi', '<cmd>lua vim.lsp.buf.implementation()<CR>', opts)
    buf_set_keymap('n', '<C-k>', '<cmd>lua vim.lsp.buf.signature_help()<CR>', opts)
    buf_set_keymap('n', '<space>wa', '<cmd>lua vim.lsp.buf.add_workspace_folder()<CR>', opts)
    buf_set_keymap('n', '<space>wr', '<cmd>lua vim.lsp.buf.remove_workspace_folder()<CR>', opts)
    buf_set_keymap('n', '<space>wl', '<cmd>lua print(vim.inspect(vim.lsp.buf.list_workspace_folders()))<CR>', opts)
    buf_set_keymap('n', '<space>D', '<cmd>lua vim.lsp.buf.type_definition()<CR>', opts)
    buf_set_keymap('n', '<space>rn', '<cmd>lua vim.lsp.buf.rename()<CR>', opts)
    buf_set_keymap('n', 'gr', '<cmd>lua vim.lsp.buf.references()<CR>', opts)
    buf_set_keymap('n', '<space>e', '<cmd>lua vim.lsp.diagnostic.show_line_diagnostics()<CR>', opts)
    buf_set_keymap('n', '[d', '<cmd>lua vim.lsp.diagnostic.goto_prev()<CR>', opts)
    buf_set_keymap('n', ']d', '<cmd>lua vim.lsp.diagnostic.goto_next()<CR>', opts)
    buf_set_keymap('n', '<space>q', '<cmd>lua vim.lsp.diagnostic.set_loclist()<CR>', opts)
  end

  -- Add the server that troubles you here
  local name = 'ltex'
  if not name then
    print 'You have not defined a server name, please edit minimal_init.lua'
  end
  if not nvim_lsp[name].document_config.default_config.cmd and not cmd then
    print [[You have not defined a server default cmd for a server
      that requires it please edit minimal_init.lua]]
  end

  nvim_lsp[name].setup {
    cmd = cmd,
    on_attach = on_attach,
    commands = {
      ['_ltex.addToDictionary'] = function() end,
    }
  }

  print [[You can find your log at $HOME/.cache/nvim/lsp.log. Please paste in a github issue under a details tag as described in the issue template.]]
end

if vim.fn.isdirectory(install_path) == 0 then
  vim.fn.system { 'git', 'clone', 'https://github.com/wbthomason/packer.nvim', install_path }
  load_plugins()
  require('packer').sync()
  vim.cmd [[autocmd User PackerComplete ++once lua load_config()]]
else
  load_plugins()
  require('packer').sync()
  _G.load_config()
end

LSP log

https://gist.github.com/Aetf/a7279f4adde759bb2060aeb773961b42

Aetf avatar Feb 28 '22 22:02 Aetf

Hmm, yes. I'm not quite sure what to do with this. Maybe commands was an unfortunate naming choice on our part in core.

mjlbach avatar Mar 01 '22 20:03 mjlbach

Is the problem here that the commands property of the client dictionary is being used to create command :SomeCustomCommand and also used as the handlers for clientside code action and code lenses?

I am running into a similar thing. i can bypass the error the OP here sees by setting the value in the commands dictionary to a list

    commands = {
      ["elixir.lens.test.run"] = {
        function()
          -- stuff
        end,
      },
    },

but when it actually goes to run the the client side command in response when attempting to run the code lens (in this case, run a unit test), it fails because the command is a table and not a function.

E5108: Error executing lua ...m/ref-master/share/nvim/runtime/lua/vim/lsp/codelens.lua:39: attempt to call local 'fn' (a table value)
stack traceback:
        ...m/ref-master/share/nvim/runtime/lua/vim/lsp/codelens.lua:39: in function 'execute_lens'
        ...m/ref-master/share/nvim/runtime/lua/vim/lsp/codelens.lua:92: in function 'run'
        [string ":lua"]:1: in main chunk

Sorry if I just repeated something obvious, but wanted to clarify this.

mhanberg avatar Mar 22 '22 19:03 mhanberg

Also, because the key in the command table needs to be the command sent by the code lens, i get a failure when it tries to create neovim commands from the name

Error executing vim.schedule lua callback: .../pack/packer/start/nvim-lspconfig/lua/lspconfig/util.lua:78: Vim(command):E182: Invalid command name
stack traceback:
        [C]: in function 'nvim_command'
        .../pack/packer/start/nvim-lspconfig/lua/lspconfig/util.lua:78: in function 'create_module_commands'
        ...ck/packer/start/nvim-lspconfig/lua/lspconfig/configs.lua:282: in function '_setup_buffer'
        ...ck/packer/start/nvim-lspconfig/lua/lspconfig/configs.lua:185: in function ''
        vim/_editor.lua: in function <vim/_editor.lua:0>

mhanberg avatar Mar 22 '22 19:03 mhanberg

Is the problem here that the commands property of the client dictionary is being used to create command :SomeCustomCommand and also used as the handlers for clientside code action and code lenses?

It is only used for the former. And it's not possible to pass client side command handlers this way, thus this issue.

I've found a workaround, though. You can actually set the per-client command handler in on_init. See https://github.com/Aetf/ucw.nvim/blob/main/lua/ucw/lsp/lang/ltex.lua#L135-L139

Aetf avatar Mar 22 '22 20:03 Aetf

https://github.com/neovim/nvim-lspconfig/pull/1838 should address this by renaming the key for creating user_commands (via nvim_create_user_commands) to user_commands which will free up commands

mjlbach avatar Apr 15 '22 22:04 mjlbach