williamboman / nvim-lsp-installer

Further development has moved to https://github.com/williamboman/mason.nvim!
https://github.com/williamboman/mason.nvim
Apache License 2.0
2k stars 123 forks source link

config specific LS #191

Closed shaeinst closed 2 years ago

shaeinst commented 3 years ago

i was using nvim-lspinstall. with it, i used to use following config for LUA


require'lspconfig'.lua.setup{ -- for Lua
  on_attach = on_attach,
  settings = {
    Lua = {
      diagnostics = {
        -- Get the language server to recognize the 'vim', 'use' global
        globals = {'vim', 'use'},
      },
      workspace = {
        -- Make the server aware of Neovim runtime files
        library = vim.api.nvim_get_runtime_file("", true),
      },
      -- Do not send telemetry data containing a randomized but unique identifier
      telemetry = {
        enable = false,
      },
    },
  }
}

how to do this with nvim-lsp-installer?

williamboman commented 3 years ago

Hey did you read the README or :help nvim-lsp-installer?

shaeinst commented 3 years ago

sorry for wasting your time but yes, i did read the README and :help nvim-lsp-installer both. But i didn't get it worked. here is my config

local lsp_installer = require("nvim-lsp-installer")

-- Provide settings first!
lsp_installer.settings {
    ui = {
        icons = {
            server_installed = "✓",
            server_pending = "➜",
            server_uninstalled = "✗",
        },
    },

    -- Limit for the maximum amount of servers to be installed at the same time. Once this limit is reached, any further
    -- servers that are requested to be installed will be put in a queue.
    max_concurrent_installers = 4,
}

lsp_installer.on_server_ready(function(server)
    local opts = {}

    -- (optional) Customize the options passed to the server
    -- if server.name == "tsserver" then
    --     opts.root_dir = function() ... end
    -- end

    -- This setup() function is exactly the same as lspconfig's setup function (:help lspconfig-quickstart)
    server:setup(opts)
    vim.cmd [[ do User LspAttachBuffers ]]
end)

local function setup_server(server)
  local lsp_installer_servers = require'nvim-lsp-installer.servers'
  local ok, server_analyzer = lsp_installer_servers.get_server(server)
  if ok then
    if not server_analyzer:is_installed() then
      server_analyzer:install(server)   -- will install in background
      -- lsp_installer.install(server)     -- install window will popup

    end
  end
end

local servers = {
  "sumneko_lua",        -- for Lua
  "rust_analyzer",      -- for Rust
  "pyright",            -- for Python
  "clangd",             -- for C/C++
  "bashls",             -- for Bash
}

for _, server in ipairs(servers) do
  setup_server(server)
end
williamboman commented 2 years ago

Ah gotcha! So the options you want to pass to a language server is done in the server:setup(opts) method.

So in your case it'd look something like this:

lsp_installer.on_server_ready(function (server)
  local opts = {}

  if server.name == "sumneko_lua" then
   -- only apply these settings for the "sumneko_lua" server
    opts.settings = {
      Lua = {
        diagnostics = {
          -- Get the language server to recognize the 'vim', 'use' global
          globals = {'vim', 'use'},
        },
        workspace = {
          -- Make the server aware of Neovim runtime files
          library = vim.api.nvim_get_runtime_file("", true),
        },
        -- Do not send telemetry data containing a randomized but unique identifier
        telemetry = {
          enable = false,
        },
      },
    }
  end

  server:setup(opts)
end)

The way you structure your control flow is up to you, above we use the simple form of if statements, but one could also do this with tables or even separate it into lua modules, like:

local server_configs = {
  ["sumneko_lua"] = {
    settings = {
        Lua = {
          diagnostics = {
            -- Get the language server to recognize the 'vim', 'use' global
            globals = {'vim', 'use'},
          },
          workspace = {
            -- Make the server aware of Neovim runtime files
            library = vim.api.nvim_get_runtime_file("", true),
          },
          -- Do not send telemetry data containing a randomized but unique identifier
          telemetry = {
            enable = false,
          },
        },
      }
  }
}

lsp_installer.on_server_ready(function (server)
  server:setup(server_configs[server.name] or {})
end)

-- or

lsp_installer.on_server_ready(function (server)
  local custom_config_ok, custom_config = pcall(require, "my.lsp.configs." .. server.name)
  if custom_config_ok then
    server:setup(custom_config)
  else
    server:setup()
  end
end)
shaeinst commented 2 years ago

thank you @williamboman here is my complete working config


local on_attach = function(client, 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

  -- Enable completion triggered by <c-x><c-o>
  buf_set_option('omnifunc', 'v:lua.vim.lsp.omnifunc')

  -- Mappings.
  local opts = { noremap=true, silent=true }

  -- See `:help vim.lsp.*` for documentation on any of the below functions
--─────────────────────────────────────────────────--
  buf_set_keymap('n', '[ds',    '<cmd>lua vim.lsp.diagnostic.show_line_diagnostics()<CR>',  opts)
  buf_set_keymap('n', '[g',     '<cmd>lua vim.lsp.diagnostic.goto_prev()<CR>',              opts)
  buf_set_keymap('n', ']g',     '<cmd>lua vim.lsp.diagnostic.goto_next()<CR>',              opts)
  buf_set_keymap('n', '[dl',    '<cmd>lua vim.lsp.diagnostic.set_loclist()<CR>',            opts)
  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', '[lh',    '<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', '[ls',    '<cmd>lua vim.lsp.buf.signature_help()<CR>',                opts)
  buf_set_keymap('n', '[D',     '<cmd>lua vim.lsp.buf.type_definition()<CR>',               opts)
  buf_set_keymap('n', '[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", "[lf",    '<cmd>lua vim.lsp.buf.formatting()<CR>',                    opts)

end
--━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━--
--━━━━━━━━━━━━━━━━━❰ end Mappings ❱━━━━━━━━━━━━━━━━--
--━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━--

--━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━--
--━━━━━━━━━━━━━━━━━━━❰ configs ❱━━━━━━━━━━━━━━━━━━━--
--━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━--
local lsp_installer = require("nvim-lsp-installer")

-- Provide settings first!
lsp_installer.settings {
    ui = {
        icons = {
            server_installed = "✓",
            server_pending = "➜",
            server_uninstalled = "✗",
        },
    },

    -- Limit for the maximum amount of servers to be installed at the same time. Once this limit is reached, any further
    -- servers that are requested to be installed will be put in a queue.
    max_concurrent_installers = 4,
}

--─────────────────────────────────────────────────--
local function make_server_ready(attach)
  lsp_installer.on_server_ready(function(server)
      local opts = {}
      opts.on_attach = attach

      -- for lua
      if server.name == "sumneko_lua" then
        -- only apply these settings for the "sumneko_lua" server
          opts.settings = {
            Lua = {
              diagnostics = {
                -- Get the language server to recognize the 'vim', 'use' global
                globals = {'vim', 'use', 'require'},
              },
              workspace = {
                -- Make the server aware of Neovim runtime files
                library = vim.api.nvim_get_runtime_file("", true),
              },
              -- Do not send telemetry data containing a randomized but unique identifier
              telemetry = {
                enable = false,
              },
            },
          }
      end

      -- This setup() function is exactly the same as lspconfig's setup function (:help lspconfig-quickstart)
      server:setup(opts)
      vim.cmd [[ do User LspAttachBuffers ]]
  end)
end
--─────────────────────────────────────────────────--

--─────────────────────────────────────────────────--
local function install_server(server)
  local lsp_installer_servers = require'nvim-lsp-installer.servers'
  local ok, server_analyzer = lsp_installer_servers.get_server(server)
  if ok then
    if not server_analyzer:is_installed() then
      server_analyzer:install(server)   -- will install in background
      -- lsp_installer.install(server)     -- install window will popup
    end
  end
end
--─────────────────────────────────────────────────--

--─────────────────────────────────────────────────--
local servers = {
  "sumneko_lua",        -- for Lua
  "rust_analyzer",      -- for Rust
  "pyright",            -- for Python
  "clangd",             -- for C/C++
  "bashls",             -- for Bash
}

-- setup the LS
make_server_ready(on_attach)    -- LSP mappings

-- install the LS
for _, server in ipairs(servers) do
  install_server(server)
end
--─────────────────────────────────────────────────--

--━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━--
--━━━━━━━━━━━━━━━━━❰ end configs ❱━━━━━━━━━━━━━━━━━--
--━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━--
shaeinst commented 2 years ago

@williamboman any feedback on my config would be nice. i have solved my problem

williamboman commented 2 years ago

I think it looks great, :clap:! Some things I observed:

whompyjaw commented 2 years ago

I have run into a similar issue as @shaeinst. I looked at his config and it seems pretty similar to mine, but my custom settings don't seem to get applied... I am wondering if I can get some eyes on it.

local on_attach = function(client, 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

  -- Enable completion triggered by <c-x><c-o>
  buf_set_option('omnifunc', 'v:lua.vim.lsp.omnifunc')

  -- Mappings.
  local opts = { noremap=true, silent=true }

  -- See `:help vim.lsp.*` for documentation on any of the below functions
  buf_set_keymap('n', 'gD', '<cmd>lua vim.lsp.buf.declaration()<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', 'gd', '<cmd>lua vim.lsp.buf.definition()<CR>', opts)
  buf_set_keymap('n', 'gr', '<cmd>lua vim.lsp.buf.references()<CR>', opts)
  buf_set_keymap('n', '<C-k>', '<cmd>lua vim.lsp.buf.signature_help()<CR>', opts)
  buf_set_keymap('n', '<Leader>wa', '<cmd>lua vim.lsp.buf.add_workspace_folder()<CR>', opts)
  buf_set_keymap('n', '<Leader>wr', '<cmd>lua vim.lsp.buf.remove_workspace_folder()<CR>', opts)
  buf_set_keymap('n', '<Leader>wl', '<cmd>lua print(vim.inspect(vim.lsp.buf.list_workspace_folders()))<CR>', opts)
  buf_set_keymap('n', '<Leader>D', '<cmd>lua vim.lsp.buf.type_definition()<CR>', opts)
  buf_set_keymap('n', '<Leader>rn', '<cmd>lua vim.lsp.buf.rename()<CR>', opts)
  buf_set_keymap('n', '<Leader>ca', '<cmd>lua vim.lsp.buf.code_action()<CR>', opts)
  buf_set_keymap('n', '<Leader>d', '<cmd>lua vim.diagnostic.show_line_diagnostics()<CR>', opts)
  buf_set_keymap('n', '[d', '<cmd>lua vim.diagnostic.goto_prev()<CR>', opts)
  buf_set_keymap('n', ']d', '<cmd>lua vim.diagnostic.goto_next()<CR>', opts)
  buf_set_keymap('n', '<Leader>q', '<cmd>lua vim.diagnostic.set_loclist()<CR>', opts)
  buf_set_keymap('n', '<Leader>f', '<cmd>lua vim.lsp.buf.formatting()<CR>', opts)
end

-- ref: https://github.com/williamboman/nvim-lsp-installer/wiki/Advanced-Configuration#overriding-the-default-lsp-server-options
local enhance_server_opts = {
  ["texlab"] = function(opts)
    opts.settings = {
      texlab = {
        build = {
          executable = "zathura",
          onSave = true,
        },
        chktex = {
          onOpenAndSave = true,
          onEdit = true,
        }
      },
    }
  end,
  ["pyright"] = function(opts)
    opts.settings = {
      python = {
        venvPath = "."
      }
    }
  end,
}

-- LSPINSTALLER
-- Register a handler that will be called for all installed servers.
-- Alternatively, you may also register handlers on specific server instances instead (see example below).
local capabilities = require('cmp_nvim_lsp').update_capabilities(vim.lsp.protocol.make_client_capabilities())
lsp_installer.on_server_ready(function(server)
  local opts = {
    on_attach = on_attach,
  }
  capabilities = capabilities
  -- ref: https://github.com/williamboman/nvim-lsp-installer/wiki/Advanced-Configuration#overriding-the-default-lsp-server-options
  if enhance_server_opts[server.name] then
    enhance_server_opts[server.name](opts)
  end
    -- This setup() function is exactly the same as lspconfig's setup function.
    -- Refer to https://github.com/neovim/nvim-lspconfig/blob/master/doc/server_configurations.md
  server:setup(opts)
end)

I am not sure what else I need to do. Is there some way to check the settings of a server that has been loaded?

I have read over: https://github.com/williamboman/nvim-lsp-installer/wiki/Advanced-Configuration#overriding-the-default-lsp-server-options https://github.com/neovim/nvim-lspconfig/blob/master/doc/server_configurations.md#texlab and https://github.com/latex-lsp/texlab/blob/master/docs/options.md And I must be missing something... Any help would be greatly appreciated.

shaeinst commented 2 years ago

checkout my lsp-installer config here lspconfig lsp-installer

williamboman commented 2 years ago

@saltsucker I can't see anything wrong with your config at first glance. Are you sure the settings you're providing are valid for those servers?

whompyjaw commented 2 years ago

@williamboman I am pretty sure they are: i.e: texlab.build.executable is equivalent to:

settings = {
  texlab = {
    build = {
      executable = 'something'
    }
  }
}

Right? Dot notation = nesting of properties right?

whompyjaw commented 2 years ago

@shaeinst Mine seems pretty similar, not sure how yours works but mine doesn't... :/

whompyjaw commented 2 years ago

Nevermind. I think it is working. When I set the onEdit and onOpenAndSave the linting doesn't occur when I save the file. But does when I set them to boolean. The issue I ran into was that it wasn't opening zathura after I compiled it. I instead just set my default PDF viewer to zathura and that works instead.

DavidePatria commented 2 years ago

after the new changes in this plugin I have tried setting the same options for sumneko_lua as op did, but they are not working. since now the setup is demanded to lspconfig, are the options recognised? in my case I cannot solve the error undefined global vim with this config:

local servers = { 'pylsp', 'clangd', 'lemminx', 'sumneko_lua', 'cmake', 'bashls' }

require('nvim-lsp-installer').setup({
    ensure_installed = servers,
    automatic_installation = true,

for _, lsp in pairs(servers) do
    if lsp == 'sumneko_lua' then

        lspconfig[lsp].setup{
            on_attach = on_attach,
            -- capabilities = capabilities,

            settings = {
                Lua = {
                    runtime = {
                        version = 'LuaJIT',
                        path = runtime_path,
                    },
                    diagnostics = {
                        globals = {'vim'},
                    },
                    workspace = {
                        library = vim.api.nvim_get_runtime_file("", true),
                    },
                },
            },
        }
    end

which is taken directly from lspconfig readme, but doesn't work. any idea about the role of nvim-lsp-installer in this? })

williamboman commented 2 years ago

Hey @DavidePatria. Exactly, nvim-lsp-installer is no longer explicitly involved in the setting up of servers. Apart from your snippet being syntactically incorrect, I'd probably do something like the following instead. It sets up sumneko_lua separately because custom settings are applied for it, and only set up the remaining servers in the loop (and apply the same default settings to them).

local servers = { 'pylsp', 'clangd', 'lemminx',  'cmake', 'bashls' }

require('nvim-lsp-installer').setup({
  automatic_installation = true,
})

lspconfig.sumneko_lua.setup {
    on_attach = on_attach,
    settings = {
      Lua = {
        runtime = {
          version = 'LuaJIT',
          path = runtime_path,
        },
        diagnostics = {
          globals = {'vim'},
        },
        workspace = {
          library = vim.api.nvim_get_runtime_file("", true),
        },
      },
    },
}

for _, lsp in pairs(servers) do
  lspconfig[lsp].setup {
    on_attach = on_attach,
  }
end
DavidePatria commented 2 years ago

the ifs are ugly, but it is the first way I could do it to only keep one table for the list of servers to use in both lspconfig and nvim-lsp-installer. turns out the error in the config was my fault. sorry