aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRanjith Hegde <ranjithshegde@gmail.com>2022-08-23 16:03:20 +0200
committerGitHub <noreply@github.com>2022-08-23 07:03:20 -0700
commitfe7a6f41e59654db6bbc9eb2d084decc54b295e4 (patch)
treec7967bb5b649ad7f8f00c697bedc2f60db9e507a
parentRevert "docs: vim.lsp.buf.formatting() is deprecated #2077 (diff)
downloadnvim-lspconfig-fe7a6f41e59654db6bbc9eb2d084decc54b295e4.tar
nvim-lspconfig-fe7a6f41e59654db6bbc9eb2d084decc54b295e4.tar.gz
nvim-lspconfig-fe7a6f41e59654db6bbc9eb2d084decc54b295e4.tar.bz2
nvim-lspconfig-fe7a6f41e59654db6bbc9eb2d084decc54b295e4.tar.lz
nvim-lspconfig-fe7a6f41e59654db6bbc9eb2d084decc54b295e4.tar.xz
nvim-lspconfig-fe7a6f41e59654db6bbc9eb2d084decc54b295e4.tar.zst
nvim-lspconfig-fe7a6f41e59654db6bbc9eb2d084decc54b295e4.zip
feat!: 0.7 API update (#1984)
* switch to lua api for autocommands * switch to nvim_create_user_command * move to lua plugin initialization NOTICE: Defining commands in server configurations will be deprecated in future releases. See `:help lspconfig.txt` to setup the same in an `on_attach` function. Co-authored-by: Michael Lingelbach <m.j.lbach@gmail.com>
-rw-r--r--doc/lspconfig.txt63
-rw-r--r--lua/lspconfig.lua76
-rw-r--r--lua/lspconfig/configs.lua61
-rw-r--r--lua/lspconfig/server_configurations/nickel_ls.lua2
-rw-r--r--lua/lspconfig/util.lua77
-rw-r--r--plugin/lspconfig.lua91
-rw-r--r--plugin/lspconfig.vim16
-rw-r--r--test/lspconfig_spec.lua42
-rw-r--r--test/minimal_init.lua14
9 files changed, 249 insertions, 193 deletions
diff --git a/doc/lspconfig.txt b/doc/lspconfig.txt
index 70339a8b..b5f2c4aa 100644
--- a/doc/lspconfig.txt
+++ b/doc/lspconfig.txt
@@ -215,12 +215,12 @@ The global defaults for all servers can be overridden by extending the
if params and params.type <= vim.lsp.protocol.MessageType.Log then
vim.lsp.handlers["window/logMessage"](err, method, params, client_id)
end
- end;
+ end,
["window/showMessage"] = function(err, method, params, client_id)
if params and params.type <= vim.lsp.protocol.MessageType.Warning.Error then
vim.lsp.handlers["window/showMessage"](err, method, params, client_id)
end
- end;
+ end,
}
}
)
@@ -264,35 +264,49 @@ The `configs` module is a singleton where configs are defined. The schema for
validating using `vim.validate` is:
>
configs.SERVER_NAME = {
- default_config = {'t'};
- on_new_config = {'f', true};
- on_attach = {'f', true};
- commands = {'t', true};
- docs = {'t', true};
+ default_config = {'t'},
+ on_new_config = {'f', true},
+ on_attach = {'f', true},
+ commands = {'t', true},
+ docs = {'t', true},
}
<
where the structure of the docs table is as follows:
>
docs = {
- description = {'s', true};
- default_config = {'t', true};
+ description = {'s', true},
+ default_config = {'t', true},
}
<
`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`. Example:
+or special keys like `description`.
+
+Warning: Commands is deprecated and will be removed in future releases.
+It is recommended to use `vim.api.nvim_create_user_command()` instead in an `on_attach` function.
+
+Example:
>
- commands = {
- TexlabBuild = {
- function()
- buf_build(0)
- end;
- "-range";
- description = "Build the current buffer";
- };
- };
+ local function organize_imports()
+ local params = {
+ command = 'pyright.organizeimports',
+ arguments = { vim.uri_from_bufnr(0) },
+ }
+ vim.lsp.buf.execute_command(params)
+ end
+
+ local on_attach = function(client, bufnr)
+ if client.name == "pyright" then
+ vim.api.nvim_create_user_command("PyrightOrganizeImports", organize_imports, {desc = 'Organize Imports'})
+ end
+ end
+
+ require("lspconfig")['pyright'].setup({
+ on_attach = on_attach
+ })
<
+
The `configs.__newindex` metamethod consumes the config definition and returns
an object with a `setup()` method, to be invoked by users:
>
@@ -305,6 +319,7 @@ Example:
>
configs.texlab.buf_build = buf_build
<
+
==============================================================================
ADDING NEW SERVERS *lspconfig-new*
@@ -320,13 +335,13 @@ The steps for adding and enabling a new server configuration are:
if not configs.foo_lsp then
configs.foo_lsp = {
default_config = {
- cmd = {'/home/neovim/lua-language-server/run.sh'};
- filetypes = {'lua'};
+ cmd = {'/home/neovim/lua-language-server/run.sh'},
+ filetypes = {'lua'},
root_dir = function(fname)
return lspconfig.util.find_git_ancestor(fname)
- end;
- settings = {};
- };
+ end,
+ settings = {},
+ },
}
end
diff --git a/lua/lspconfig.lua b/lua/lspconfig.lua
index b46ef65d..1178202e 100644
--- a/lua/lspconfig.lua
+++ b/lua/lspconfig.lua
@@ -4,82 +4,6 @@ local M = {
util = require 'lspconfig.util',
}
-M._root = {}
-
-function M.available_servers()
- local servers = {}
- for server, config in pairs(configs) do
- if config.manager ~= nil then
- table.insert(servers, server)
- end
- end
- return servers
-end
-
--- Called from plugin/lspconfig.vim because it requires knowing that the last
--- script in scriptnames to be executed is lspconfig.
-function M._root._setup()
- M._root.commands = {
- LspInfo = {
- function()
- require 'lspconfig.ui.lspinfo'()
- end,
- '-nargs=0',
- description = '`:LspInfo` Displays attached, active, and configured language servers',
- },
- LspLog = {
- function()
- vim.cmd(string.format('tabnew %s', vim.lsp.get_log_path()))
- end,
- '-nargs=0',
- description = '`:LspLog` Opens the Nvim LSP client log.',
- },
- LspStart = {
- function(server_name)
- if server_name then
- if configs[server_name] then
- configs[server_name].launch()
- end
- else
- local buffer_filetype = vim.bo.filetype
- for _, config in pairs(configs) do
- for _, filetype_match in ipairs(config.filetypes or {}) do
- if buffer_filetype == filetype_match then
- config.launch()
- end
- end
- end
- end
- end,
- '-nargs=? -complete=custom,v:lua.lsp_complete_configured_servers',
- description = '`:LspStart` Manually launches a language server.',
- },
- LspStop = {
- function(cmd_args)
- for _, client in ipairs(M.util.get_clients_from_cmd_args(cmd_args)) do
- client.stop()
- end
- end,
- '-nargs=? -complete=customlist,v:lua.lsp_get_active_client_ids',
- description = '`:LspStop` Manually stops the given language client(s).',
- },
- LspRestart = {
- function(cmd_args)
- for _, client in ipairs(M.util.get_clients_from_cmd_args(cmd_args)) do
- client.stop()
- vim.defer_fn(function()
- configs[client.name].launch()
- end, 500)
- end
- end,
- '-nargs=? -complete=customlist,v:lua.lsp_get_active_client_ids',
- description = '`:LspRestart` Manually restart the given language client(s).',
- },
- }
-
- M.util.create_module_commands('_root', M._root.commands)
-end
-
local mt = {}
function mt:__index(k)
if configs[k] == nil then
diff --git a/lua/lspconfig/configs.lua b/lua/lspconfig/configs.lua
index 07672a33..a0129776 100644
--- a/lua/lspconfig/configs.lua
+++ b/lua/lspconfig/configs.lua
@@ -31,6 +31,8 @@ function configs.__newindex(t, config_name, config_def)
default_config.name = config_name
function M.setup(config)
+ local lsp_group = vim.api.nvim_create_augroup('lspconfig', { clear = false })
+
validate {
cmd = { config.cmd, 't', true },
root_dir = { config.root_dir, 'f', true },
@@ -64,14 +66,17 @@ function configs.__newindex(t, config_name, config_def)
event = 'BufReadPost'
pattern = '*'
end
- api.nvim_command(
- string.format(
- "autocmd %s %s unsilent lua require'lspconfig'[%q].manager.try_add()",
- event,
- pattern,
+ vim.api.nvim_create_autocmd(event, {
+ pattern = pattern,
+ callback = function()
+ M.manager.try_add()
+ end,
+ group = lsp_group,
+ desc = string.format(
+ 'Checks whether server %s should start a new instance or attach to an existing one.',
config.name
- )
- )
+ ),
+ })
end
local get_root_dir = config.root_dir
@@ -88,15 +93,18 @@ function configs.__newindex(t, config_name, config_def)
end
if root_dir then
- -- Lazy-launching: attach when a buffer in this directory is opened.
- api.nvim_command(
- string.format(
- "autocmd BufReadPost %s/* unsilent lua require'lspconfig'[%q].manager.try_add_wrapper()",
- vim.fn.fnameescape(root_dir),
- config.name
- )
- )
- -- Attach for all existing buffers in this directory.
+ vim.api.nvim_create_autocmd('BufReadPost', {
+ pattern = vim.fn.fnameescape(root_dir) .. '/*',
+ callback = function()
+ M.manager.try_add_wrapper()
+ end,
+ group = lsp_group,
+ desc = string.format(
+ 'Checks whether server %s should attach to a newly opened buffer inside workspace %q.',
+ config.name,
+ root_dir
+ ),
+ })
for _, bufnr in ipairs(vim.api.nvim_list_bufs()) do
local bufname = api.nvim_buf_get_name(bufnr)
if util.bufname_valid(bufname) then
@@ -183,15 +191,15 @@ function configs.__newindex(t, config_name, config_def)
M._setup_buffer(client.id, bufnr)
else
if vim.api.nvim_buf_is_valid(bufnr) then
- api.nvim_command(
- string.format(
- "autocmd BufEnter <buffer=%d> ++once lua require'lspconfig'[%q]._setup_buffer(%d,%d)",
- bufnr,
- config_name,
- client.id,
- bufnr
- )
- )
+ vim.api.nvim_create_autocmd('BufEnter', {
+ callback = function()
+ M._setup_buffer(client.id, bufnr)
+ end,
+ group = lsp_group,
+ buffer = bufnr,
+ once = true,
+ desc = 'Reattaches the server with the updated configurations if changed.',
+ })
end
end
end)
@@ -283,13 +291,10 @@ function configs.__newindex(t, config_name, config_def)
M.commands = vim.tbl_deep_extend('force', M.commands, client.config.commands)
end
if not M.commands_created and not vim.tbl_isempty(M.commands) then
- -- Create the module commands
util.create_module_commands(config_name, M.commands)
- M.commands_created = true
end
end
- M.commands_created = false
M.commands = config_def.commands
M.name = config_name
M.document_config = config_def
diff --git a/lua/lspconfig/server_configurations/nickel_ls.lua b/lua/lspconfig/server_configurations/nickel_ls.lua
index 3a9387e8..391abfee 100644
--- a/lua/lspconfig/server_configurations/nickel_ls.lua
+++ b/lua/lspconfig/server_configurations/nickel_ls.lua
@@ -30,7 +30,7 @@ cd nickel/lsp/nls
cargo install --path .
```
-In order to have lspconfig detect Nickel filetypes (a prequisite for autostarting a server),
+In order to have lspconfig detect Nickel filetypes (a prerequisite for autostarting a server),
install the [Nickel vim plugin](https://github.com/nickel-lang/vim-nickel).
]],
},
diff --git a/lua/lspconfig/util.lua b/lua/lspconfig/util.lua
index 956be435..0729430f 100644
--- a/lua/lspconfig/util.lua
+++ b/lua/lspconfig/util.lua
@@ -3,7 +3,6 @@ local validate = vim.validate
local api = vim.api
local lsp = vim.lsp
local uv = vim.loop
-local fn = vim.fn
local M = {}
@@ -61,39 +60,39 @@ function M.add_hook_after(func, new_fn)
end
end
-function M.create_module_commands(module_name, commands)
- for command_name, def in pairs(commands) do
- local parts = { 'command!' }
- -- Insert attributes.
- for k, v in pairs(def) do
- if type(k) == 'string' and type(v) == 'boolean' and v then
- table.insert(parts, '-' .. k)
- elseif type(k) == 'number' and type(v) == 'string' and v:match '^%-' then
- table.insert(parts, v)
+-- Maps lspconfig-style command options to nvim_create_user_command (i.e. |command-attributes|) option names.
+local opts_aliases = {
+ ['description'] = 'desc',
+}
+
+---@param command_definition table<string | integer, any>
+function M._parse_user_command_options(command_definition)
+ ---@type table<string, string | boolean | number>
+ local opts = {}
+ for k, v in pairs(command_definition) do
+ if type(k) == 'string' then
+ local attribute = k.gsub(k, '^%-+', '')
+ opts[opts_aliases[attribute] or attribute] = v
+ elseif type(k) == 'number' and type(v) == 'string' and v:match '^%-' then
+ -- Splits strings like "-nargs=* -complete=customlist,v:lua.something" into { "-nargs=*", "-complete=customlist,v:lua.something" }
+ for _, command_attribute in ipairs(vim.split(v, '%s')) do
+ -- Splits attribute into a key-value pair, like "-nargs=*" to { "-nargs", "*" }
+ local attribute, value = unpack(vim.split(command_attribute, '=', { plain = true }))
+ attribute = attribute.gsub(attribute, '^%-+', '')
+ opts[opts_aliases[attribute] or attribute] = value or true
end
end
- table.insert(parts, command_name)
- -- The command definition.
- table.insert(
- parts,
- string.format("lua require'lspconfig'[%q].commands[%q][1](<f-args>)", module_name, command_name)
- )
- api.nvim_command(table.concat(parts, ' '))
end
+ return opts
end
-function M.has_bins(...)
- for i = 1, select('#', ...) do
- if 0 == fn.executable((select(i, ...))) then
- return false
- end
+function M.create_module_commands(module_name, commands)
+ for command_name, def in pairs(commands) do
+ local opts = M._parse_user_command_options(def)
+ api.nvim_create_user_command(command_name, function(info)
+ require('lspconfig')[module_name].commands[command_name][1](unpack(info.fargs))
+ end, opts)
end
- return true
-end
-
-M.script_path = function()
- local str = debug.getinfo(2, 'S').source:sub(2)
- return str:match '(.*[/\\])'
end
-- Some path utilities
@@ -409,17 +408,6 @@ function M.get_other_matching_providers(filetype)
return other_matching_configs
end
-function M.get_clients_from_cmd_args(arg)
- local result = {}
- for id in (arg or ''):gmatch '(%d+)' do
- result[id] = vim.lsp.get_client_by_id(tonumber(id))
- end
- if vim.tbl_isempty(result) then
- return M.get_managed_clients()
- end
- return vim.tbl_values(result)
-end
-
function M.get_active_client_by_name(bufnr, servername)
for _, client in pairs(vim.lsp.buf_get_clients(bufnr)) do
if client.name == servername then
@@ -440,6 +428,17 @@ function M.get_managed_clients()
return clients
end
+function M.available_servers()
+ local servers = {}
+ local configs = require 'lspconfig.configs'
+ for server, config in pairs(configs) do
+ if config.manager ~= nil then
+ table.insert(servers, server)
+ end
+ end
+ return servers
+end
+
-- For zipfile: or tarfile: virtual paths, returns the path to the archive.
-- Other paths are returned unaltered.
function M.strip_archive_subpath(path)
diff --git a/plugin/lspconfig.lua b/plugin/lspconfig.lua
new file mode 100644
index 00000000..fd22a206
--- /dev/null
+++ b/plugin/lspconfig.lua
@@ -0,0 +1,91 @@
+if vim.g.lspconfig ~= nil then
+ return
+end
+vim.g.lspconfig = 1
+
+local version_info = vim.version()
+if vim.fn.has 'nvim-0.7' ~= 1 then
+ local warning_str = string.format(
+ '[lspconfig] requires neovim 0.7 or later. Detected neovim version: 0.%s.%s',
+ version_info.minor,
+ version_info.patch
+ )
+ vim.notify_once(warning_str)
+ return
+end
+
+local lsp_complete_configured_servers = function(arg)
+ return vim.tbl_filter(function(s)
+ return s:sub(1, #arg) == arg
+ end, vim.tbl_keys(require 'lspconfig.configs'))
+end
+
+local lsp_get_active_client_ids = function(arg)
+ local clients = vim.tbl_map(function(client)
+ return ('%d (%s)'):format(client.id, client.name)
+ end, require('lspconfig.util').get_managed_clients())
+
+ return vim.tbl_filter(function(s)
+ return s:sub(1, #arg) == arg
+ end, clients)
+end
+
+local get_clients_from_cmd_args = function(arg)
+ local result = {}
+ for id in (arg or ''):gmatch '(%d+)' do
+ result[id] = vim.lsp.get_client_by_id(tonumber(id))
+ end
+ if vim.tbl_isempty(result) then
+ return require('lspconfig.util').get_managed_clients()
+ end
+ return vim.tbl_values(result)
+end
+
+-- Called from plugin/lspconfig.vim because it requires knowing that the last
+-- script in scriptnames to be executed is lspconfig.
+vim.api.nvim_create_user_command('LspInfo', function()
+ require 'lspconfig.ui.lspinfo'()
+end, {
+ desc = 'Displays attached, active, and configured language servers',
+})
+
+vim.api.nvim_create_user_command('LspStart', function(info)
+ local server_name = info.args[1] ~= '' and info.args
+ if server_name then
+ local config = require('lspconfig.configs')[server_name]
+ if config then
+ config.launch()
+ end
+ else
+ local other_matching_configs = require('lspconfig.util').get_other_matching_providers(vim.bo.filetype)
+ for _, config in ipairs(other_matching_configs) do
+ config.launch()
+ end
+ end
+end, {
+ desc = 'Manually launches a language server',
+ nargs = '?',
+ complete = lsp_complete_configured_servers,
+})
+vim.api.nvim_create_user_command('LspRestart', function(info)
+ for _, client in ipairs(get_clients_from_cmd_args(info.args)) do
+ client.stop()
+ vim.defer_fn(function()
+ require('lspconfig.configs')[client.name].launch()
+ end, 500)
+ end
+end, {
+ desc = 'Manually restart the given language client(s)',
+ nargs = '?',
+ complete = lsp_get_active_client_ids,
+})
+
+vim.api.nvim_create_user_command('LspStop', function(info)
+ for _, client in ipairs(get_clients_from_cmd_args(info.args)) do
+ client.stop()
+ end
+end, {
+ desc = 'Manually stops the given language client(s)',
+ nargs = '?',
+ complete = lsp_get_active_client_ids,
+})
diff --git a/plugin/lspconfig.vim b/plugin/lspconfig.vim
deleted file mode 100644
index 5c52d4e1..00000000
--- a/plugin/lspconfig.vim
+++ /dev/null
@@ -1,16 +0,0 @@
-if exists('g:lspconfig')
- finish
-endif
-let g:lspconfig = 1
-
-lua << EOF
-lsp_complete_configured_servers = function()
- return table.concat(require'lspconfig'.available_servers(), '\n')
-end
-lsp_get_active_client_ids = function()
- return vim.tbl_map(function(client)
- return ("%d (%s)"):format(client.id, client.name)
- end, require'lspconfig.util'.get_managed_clients())
-end
-require'lspconfig'._root._setup()
-EOF
diff --git a/test/lspconfig_spec.lua b/test/lspconfig_spec.lua
index 89effd47..f98568c1 100644
--- a/test/lspconfig_spec.lua
+++ b/test/lspconfig_spec.lua
@@ -32,7 +32,7 @@ describe('lspconfig', function()
ok(exec_lua [[
local lspconfig = require("lspconfig")
- local not_exist_dir = vim.fn.getcwd().."/not/exsts"
+ local not_exist_dir = vim.fn.getcwd().."/not/exists"
return lspconfig.util.path.exists(not_exist_dir) == false
]])
end)
@@ -76,7 +76,7 @@ describe('lspconfig', function()
ok(exec_lua [[
local lspconfig = require("lspconfig")
- local not_exist_dir = vim.fn.getcwd().."/not/exsts"
+ local not_exist_dir = vim.fn.getcwd().."/not/exists"
return not lspconfig.util.path.is_dir(not_exist_dir)
]])
end)
@@ -213,7 +213,43 @@ describe('lspconfig', function()
]])
end)
end)
+
+ describe('user commands', function()
+ it('should translate command definition to nvim_create_user_command options', function()
+ eq(
+ {
+ nargs = '*',
+ complete = 'custom,v:lua.some_global',
+ },
+ exec_lua [[
+ local util = require("lspconfig.util")
+ return util._parse_user_command_options({
+ function () end,
+ "-nargs=* -complete=custom,v:lua.some_global"
+ })
+ ]]
+ )
+
+ eq(
+ {
+ desc = 'My awesome description.',
+ nargs = '*',
+ complete = 'custom,v:lua.another_global',
+ },
+ exec_lua [[
+ local util = require("lspconfig.util")
+ return util._parse_user_command_options({
+ function () end,
+ ["-nargs"] = "*",
+ "-complete=custom,v:lua.another_global",
+ description = "My awesome description."
+ })
+ ]]
+ )
+ end)
+ end)
end)
+
describe('config', function()
it('normalizes user, server, and base default configs', function()
eq(
@@ -283,7 +319,7 @@ describe('lspconfig', function()
local _ = lspconfig.sumneko_lua
local _ = lspconfig.tsserver
lspconfig.rust_analyzer.setup {}
- return lspconfig.available_servers()
+ return require("lspconfig.util").available_servers()
]],
{ 'rust_analyzer' }
)
diff --git a/test/minimal_init.lua b/test/minimal_init.lua
index 8c7ad55a..ba2ae3fc 100644
--- a/test/minimal_init.lua
+++ b/test/minimal_init.lua
@@ -29,11 +29,9 @@ local function load_plugins()
}
end
-_G.load_config = function()
+local 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
+ require('vim.lsp.log').set_format_func(vim.inspect)
local nvim_lsp = require 'lspconfig'
local on_attach = function(_, bufnr)
local function buf_set_option(...)
@@ -86,9 +84,13 @@ 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()]]
+ local packer_group = vim.api.nvim_create_augroup('Packer', { clear = true })
+ vim.api.nvim_create_autocmd(
+ 'User',
+ { pattern = 'PackerComplete', callback = load_config, group = packer_group, once = true }
+ )
else
load_plugins()
require('packer').sync()
- _G.load_config()
+ load_config()
end