aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/ci/lint.sh (renamed from .github/ci/run_sanitizer.sh)12
-rw-r--r--.github/workflows/lint.yml2
-rw-r--r--CONTRIBUTING.md49
-rw-r--r--lsp/basedpyright.lua24
-rw-r--r--lsp/denols.lua28
-rw-r--r--lsp/pyright.lua26
-rw-r--r--lsp/texlab.lua10
-rw-r--r--lsp/zk.lua18
-rwxr-xr-xscripts/docgen.lua3
9 files changed, 87 insertions, 85 deletions
diff --git a/.github/ci/run_sanitizer.sh b/.github/ci/lint.sh
index 6f1577da..38ea57eb 100644
--- a/.github/ci/run_sanitizer.sh
+++ b/.github/ci/lint.sh
@@ -1,7 +1,7 @@
#!/usr/bin/env bash
# USAGE: To run locally:
-# bash .github/ci/run_sanitizer.sh origin/master HEAD
+# bash .github/ci/lint.sh origin/master HEAD
set -e
@@ -27,6 +27,15 @@ _check_lsp_cmd_prefix() {
fi
}
+# Enforce client:exec_cmd().
+_check_exec_cmd() {
+ if git grep -P 'workspace.executeCommand' -- 'lsp/*.lua' ; then
+ echo
+ echo 'Use client:exec_cmd() instead of calling request("workspace/executeCommand") directly. Example: lsp/pyright.lua'
+ exit 1
+ fi
+}
+
_check_deprecated_utils() {
# checks for added lines that contain search pattern and prints them
SEARCH_PATTERN='(path\.dirname|fn\.cwd)'
@@ -50,4 +59,5 @@ _check_deprecated_utils() {
_check_cmd_buflocal
_check_lsp_cmd_prefix
+_check_exec_cmd
_check_deprecated_utils
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 346ad478..20b9b6ae 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -17,7 +17,7 @@ jobs:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha }}
- run: |
- if ! bash .github/ci/run_sanitizer.sh ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }}; then
+ if ! bash .github/ci/lint.sh ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }}; then
exit 1
fi
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 44c394f9..4c3e8e1f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,3 +1,5 @@
+# Contributing to nvim-lspconfig
+
## Requirements
- [Lint requirements](#lint)
@@ -6,7 +8,8 @@
## Scope of nvim-lspconfig
-The point of lspconfig is to provide the minimal configuration necessary for a server to act in compliance with the language server protocol. In general, if a server requires custom client-side commands or off-spec handlers, then the server configuration should be added *without* those in lspconfig and receive a dedicated plugin such as nvim-jdtls, nvim-metals, etc.
+The purpose of nvim-lspconfig is to provide configuration so that users can activate LSP with a single `vim.lsp.enable('foo')` call.
+It must not provide its own "framework". Any "framework" or "util" code must be upstreamed to Nvim core.
## Pull requests (PRs)
@@ -15,7 +18,9 @@ The point of lspconfig is to provide the minimal configuration necessary for a s
- Use a **rebase workflow** for small PRs.
- After addressing review comments, it's fine to rebase and force-push.
-## Adding a server to lspconfig
+## New config
+
+### Criteria
New configs must meet these criteria (to avoid spam/quasi-marketing/vanity projects):
@@ -25,28 +30,37 @@ New configs must meet these criteria (to avoid spam/quasi-marketing/vanity proje
This helps ensure that we only include actively maintained and widely used servers to provide a better experience for
the community.
-To add a new language server, start with a minimal skeleton. See `:help lspconfig-new` and other configurations in `lsp/`.
+### Walkthrough
+
+To add a new config, copy an existing config from `lsp/`. Start with `lsp/lua_ls.lua` for a simple a config, or `lsp/jdtls.lua` or `lsp/pyright.lua` for more complex examples.
When choosing a config name, convert dashes (`-`) to underscores (`_`). If the name of the server is a unique name (`pyright`, `clangd`) or a commonly used abbreviation (`zls`), prefer this as the server name. If the server instead follows the pattern x-language-server, prefer the convention `x_ls` (`jsonnet_ls`).
-`default_config` should include:
+The minimal config properties are:
-* `cmd`: a list which includes the executable name as the first entry, with arguments constituting subsequent list elements (`--stdio` is common).
+* `cmd`: command defined as a string list, where the first item is an executable and following items are its arguments (`--stdio` is common).
```lua
cmd = { 'typescript-language-server', '--stdio' }
```
* `filetypes`: list of filetypes that should activate this config.
-* `root_markers`: a list of files that mark the root of the project.
- * See `:help lspconfig-new`.
+* `root_markers`: a list of files that mark the root of the project/workspace.
+ * See `:help lsp-config`.
* See `vim.fs.root()`
-An example for adding a new config `lsp/pyright.lua` is shown below:
+### Commands
-```lua
-local function organize_imports()
- -- executes lsp command. See `lsp/pyright.lua` for the full example.
-end
+LSP servers may provide custom `workspace/executeCommand` commands. Because LSP does not provide any way for clients to programmatically discover/list these commands, configs may define Nvim commands which invoke the `workspace/executeCommand` commands. To keep things maintainable and discoverable, configs must follow these guidelines:
+- Commands must be buffer-local.
+- Commands must be prefixed with `:Lsp`. This is a crude way to improve "discoverability".
+- Do NOT create commands that merely alias existing *code-actions* or *code-lenses*, which are *already* auto-discoverable via the ["gra" keymap](https://neovim.io/doc/user/lsp.html#gra) (or `vim.lsp.buf.code_action()`)
+- Use `client:exec_cmd()` (instead of `request(..., 'workspace/executeCommand')`)
+
+### Example
+
+Following is an example new config for `lsp/pyright.lua`:
+
+```lua
---@brief
---
--- https://github.com/microsoft/pyright
@@ -72,8 +86,15 @@ return {
},
},
},
- on_attach = function()
- vim.api.nvim_buf_create_user_command(0, 'LspPyrightOrganizeImports', organize_imports, {})
+ on_attach = function(client, bufnr)
+ vim.api.nvim_buf_create_user_command(bufnr, 'LspPyrightOrganizeImports', function()
+ client:exec_cmd({
+ command = 'pyright.organizeimports',
+ arguments = { vim.uri_from_bufnr(bufnr) },
+ })
+ end, {
+ desc = 'Organize Imports',
+ })
end,
}
```
diff --git a/lsp/basedpyright.lua b/lsp/basedpyright.lua
index f78bbd21..8872ea14 100644
--- a/lsp/basedpyright.lua
+++ b/lsp/basedpyright.lua
@@ -4,21 +4,6 @@
---
--- `basedpyright`, a static type checker and language server for python
-local function organize_imports()
- local params = {
- command = 'basedpyright.organizeimports',
- arguments = { vim.uri_from_bufnr(0) },
- }
-
- local clients = vim.lsp.get_clients {
- bufnr = vim.api.nvim_get_current_buf(),
- name = 'basedpyright',
- }
- for _, client in ipairs(clients) do
- client.request('workspace/executeCommand', params, nil, 0)
- end
-end
-
local function set_python_path(path)
local clients = vim.lsp.get_clients {
bufnr = vim.api.nvim_get_current_buf(),
@@ -55,8 +40,13 @@ return {
},
},
},
- on_attach = function()
- vim.api.nvim_buf_create_user_command(0, 'LspPyrightOrganizeImports', organize_imports, {
+ on_attach = function(client, bufnr)
+ vim.api.nvim_buf_create_user_command(bufnr, 'LspPyrightOrganizeImports', function()
+ client:exec_cmd({
+ command = 'basedpyright.organizeimports',
+ arguments = { vim.uri_from_bufnr(bufnr) },
+ })
+ end, {
desc = 'Organize Imports',
})
diff --git a/lsp/denols.lua b/lsp/denols.lua
index 80ff679e..b7a6466a 100644
--- a/lsp/denols.lua
+++ b/lsp/denols.lua
@@ -15,19 +15,6 @@
local lsp = vim.lsp
-local function buf_cache(bufnr, client)
- local params = {
- command = 'deno.cache',
- arguments = { {}, vim.uri_from_bufnr(bufnr) },
- }
- client.request('workspace/executeCommand', params, function(err, _result, ctx)
- if err then
- local uri = ctx.params.arguments[2]
- vim.api.nvim_err_writeln('cache command failed for ' .. vim.uri_to_fname(uri))
- end
- end, bufnr)
-end
-
local function virtual_text_document_handler(uri, res, client)
if not res then
return nil
@@ -105,12 +92,17 @@ return {
['textDocument/typeDefinition'] = denols_handler,
['textDocument/references'] = denols_handler,
},
- on_attach = function()
+ on_attach = function(client, bufnr)
vim.api.nvim_buf_create_user_command(0, 'LspDenolsCache', function()
- local clients = vim.lsp.get_clients { bufnr = 0, name = 'denols' }
- if #clients > 0 then
- buf_cache(0, clients[#clients])
- end
+ client:exec_cmd({
+ command = 'deno.cache',
+ arguments = { {}, vim.uri_from_bufnr(bufnr) },
+ }, { bufnr = bufnr }, function(err, _result, ctx)
+ if err then
+ local uri = ctx.params.arguments[2]
+ vim.api.nvim_err_writeln('cache command failed for ' .. vim.uri_to_fname(uri))
+ end
+ end)
end, {
desc = 'Cache a module and all of its dependencies.',
})
diff --git a/lsp/pyright.lua b/lsp/pyright.lua
index 161b8e0e..c44fecfa 100644
--- a/lsp/pyright.lua
+++ b/lsp/pyright.lua
@@ -4,21 +4,6 @@
---
--- `pyright`, a static type checker and language server for python
-local function organize_imports()
- local params = {
- command = 'pyright.organizeimports',
- arguments = { vim.uri_from_bufnr(0) },
- }
-
- local clients = vim.lsp.get_clients {
- bufnr = vim.api.nvim_get_current_buf(),
- name = 'pyright',
- }
- for _, client in ipairs(clients) do
- client.request('workspace/executeCommand', params, nil, 0)
- end
-end
-
local function set_python_path(path)
local clients = vim.lsp.get_clients {
bufnr = vim.api.nvim_get_current_buf(),
@@ -55,11 +40,16 @@ return {
},
},
},
- on_attach = function()
- vim.api.nvim_buf_create_user_command(0, 'LspPyrightOrganizeImports', organize_imports, {
+ on_attach = function(client, bufnr)
+ vim.api.nvim_buf_create_user_command(bufnr, 'LspPyrightOrganizeImports', function()
+ client:exec_cmd({
+ command = 'pyright.organizeimports',
+ arguments = { vim.uri_from_bufnr(bufnr) },
+ })
+ end, {
desc = 'Organize Imports',
})
- vim.api.nvim_buf_create_user_command(0, 'LspPyrightSetPythonPath', set_python_path, {
+ vim.api.nvim_buf_create_user_command(bufnr, 'LspPyrightSetPythonPath', set_python_path, {
desc = 'Reconfigure pyright with the provided python path',
nargs = 1,
complete = 'file',
diff --git a/lsp/texlab.lua b/lsp/texlab.lua
index 8123d5b7..5636b031 100644
--- a/lsp/texlab.lua
+++ b/lsp/texlab.lua
@@ -63,12 +63,12 @@ local function buf_cancel_build(client, bufnr)
end
local function dependency_graph(client)
- client.request('workspace/executeCommand', { command = 'texlab.showDependencyGraph' }, function(err, result)
+ client:exec_cmd({ command = 'texlab.showDependencyGraph' }, { bufnr = 0 }, function(err, result)
if err then
return vim.notify(err.code .. ': ' .. err.message, vim.log.levels.ERROR)
end
vim.notify('The dependency graph has been generated:\n' .. result, vim.log.levels.INFO)
- end, 0)
+ end)
end
local function command_factory(cmd)
@@ -102,10 +102,10 @@ end
local function buf_find_envs(client, bufnr)
local win = vim.api.nvim_get_current_win()
- client.request('workspace/executeCommand', {
+ client:exec_cmd({
command = 'texlab.findEnvironments',
arguments = { vim.lsp.util.make_position_params(win, client.offset_encoding) },
- }, function(err, result)
+ }, { bufnr = bufnr }, function(err, result)
if err then
return vim.notify(err.code .. ': ' .. err.message, vim.log.levels.ERROR)
end
@@ -126,7 +126,7 @@ local function buf_find_envs(client, bufnr)
border = 'single',
title = 'Environments',
})
- end, bufnr)
+ end)
end
local function buf_change_env(client, bufnr)
diff --git a/lsp/zk.lua b/lsp/zk.lua
index f659cb25..98b19460 100644
--- a/lsp/zk.lua
+++ b/lsp/zk.lua
@@ -16,11 +16,11 @@ return {
cmd = { 'zk', 'lsp' },
filetypes = { 'markdown' },
root_markers = { '.zk' },
- on_attach = function()
- vim.api.nvim_buf_create_user_command(0, 'LspZkIndex', function()
+ on_attach = function(client, bufnr)
+ vim.api.nvim_buf_create_user_command(bufnr, 'LspZkIndex', function()
vim.lsp.buf.execute_command {
command = 'zk.index',
- arguments = { vim.api.nvim_buf_get_name(0) },
+ arguments = { vim.api.nvim_buf_get_name(bufnr) },
}
end, {
desc = 'ZkIndex',
@@ -30,10 +30,10 @@ return {
local bufpath = vim.api.nvim_buf_get_name(0)
local root = find_zk_root(bufpath)
- vim.lsp.buf_request(0, 'workspace/executeCommand', {
+ client:exec_cmd({
command = 'zk.list',
arguments = { root, { select = { 'path' } } },
- }, function(_, result, _, _)
+ }, { bufnr = bufnr }, function(_err, result)
if not result then
return
end
@@ -48,14 +48,14 @@ return {
desc = 'ZkList',
})
- vim.api.nvim_buf_create_user_command(0, 'LspZkNew', function(...)
- vim.lsp.buf_request(0, 'workspace/executeCommand', {
+ vim.api.nvim_buf_create_user_command(bufnr, 'LspZkNew', function(...)
+ client:exec_cmd({
command = 'zk.new',
arguments = {
- vim.api.nvim_buf_get_name(0),
+ vim.api.nvim_buf_get_name(bufnr),
...,
},
- }, function(_, result, _, _)
+ }, { bufnr = bufnr }, function(_err, result)
if not (result and result.path) then
return
end
diff --git a/scripts/docgen.lua b/scripts/docgen.lua
index 956541ca..8695e209 100755
--- a/scripts/docgen.lua
+++ b/scripts/docgen.lua
@@ -3,7 +3,6 @@ local root = vim.trim(vim.system({ 'git', 'rev-parse', '--show-toplevel' }):wait
vim.opt.rtp:append(root)
local util = require 'lspconfig.util'
-local inspect = vim.inspect
local function template(s, params)
return (s:gsub('{{([^{}]+)}}', params))
@@ -147,7 +146,7 @@ local function make_lsp_sections(is_markdown)
if type(v) == 'boolean' then
return ('- `%s` : `%s`'):format(k, v)
elseif type(v) ~= 'function' and k ~= 'root_dir' then
- return ('- `%s` :\n ```lua\n%s\n ```'):format(k, indent(2, inspect(v)))
+ return ('- `%s` :\n ```lua\n%s\n ```'):format(k, indent(2, vim.inspect(v)))
end
local file = assert(io.open(config_file, 'r'))