Skip to content

Commit f75be5e

Browse files
authored
lsp: vim.lsp.diagnostic (#12655)
Breaking Changes: - Deprecated all `vim.lsp.util.{*diagnostics*}()` functions. - Instead, all functions must be found in vim.lsp.diagnostic - For now, they issue a warning ONCE per neovim session. In a "little while" we will remove them completely. - `vim.lsp.callbacks` has moved to `vim.lsp.handlers`. - For a "little while" we will just redirect `vim.lsp.callbacks` to `vim.lsp.handlers`. However, we will remove this at some point, so it is recommended that you change all of your references to `callbacks` into `handlers`. - This also means that for functions like |vim.lsp.start_client()| and similar, keyword style arguments have moved from "callbacks" to "handlers". Once again, these are currently being forward, but will cease to be forwarded in a "little while". - Changed the highlight groups for LspDiagnostic highlight as they were inconsistently named. - For more information, see |lsp-highlight-diagnostics| - Changed the sign group names as well, to be consistent with |lsp-highlight-diagnostics| General Enhancements: - Rewrote much of the getting started help document for lsp. It also provides a much nicer configuration strategy, so as to not recommend globally overwriting builtin neovim mappings. LSP Enhancements: - Introduced the concept of |lsp-handlers| which will allow much better customization for users without having to copy & paste entire files / functions / etc. Diagnostic Enhancements: - "goto next diagnostic" |vim.lsp.diagnostic.goto_next()| - "goto prev diagnostic" |vim.lsp.diagnostic.goto_prev()| - For each of the gotos, auto open diagnostics is available as a configuration option - Configurable diagnostic handling: - See |vim.lsp.diagnostic.on_publish_diagnostics()| - Delay display until after insert mode - Configure signs - Configure virtual text - Configure underline - Set the location list with the buffers diagnostics. - See |vim.lsp.diagnostic.set_loclist()| - Better performance for getting counts and line diagnostics - They are now cached on save, to enhance lookups. - Particularly useful for checking in statusline, etc. - Actual testing :) - See ./test/functional/plugin/lsp/diagnostic_spec.lua - Added `guisp` for underline highlighting NOTE: "a little while" means enough time to feel like most plugins and plugin authors have had a chance to refactor their code to use the updated calls. Then we will remove them completely. There is no need to keep them, because we don't have any released version of neovim that exposes these APIs. I'm trying to be nice to people following HEAD :) Co-authored: [Twitch Chat 2020](https://twitch.tv/teej_dv)
1 parent 4ae31c4 commit f75be5e

22 files changed

+3744
-1359
lines changed

runtime/doc/api.txt

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,9 @@ created for extmark changes.
475475
==============================================================================
476476
Global Functions *api-global*
477477

478+
nvim__get_hl_defs({ns_id}) *nvim__get_hl_defs()*
479+
TODO: Documentation
480+
478481
nvim__get_lib_dir() *nvim__get_lib_dir()*
479482
TODO: Documentation
480483

@@ -952,6 +955,9 @@ nvim_get_runtime_file({name}, {all}) *nvim_get_runtime_file()*
952955
It is not an error to not find any files. An empty array is
953956
returned then.
954957

958+
Attributes: ~
959+
{fast}
960+
955961
Parameters: ~
956962
{name} pattern of files to search for
957963
{all} whether to return all matches or only the first
@@ -987,6 +993,7 @@ nvim_input({keys}) *nvim_input()*
987993
Note:
988994
|keycodes| like <CR> are translated, so "<" is special. To
989995
input a literal "<", send <LT>.
996+
990997
Note:
991998
For mouse events use |nvim_input_mouse()|. The pseudokey
992999
form "<LeftMouse><col,row>" is deprecated since
@@ -1378,8 +1385,7 @@ nvim_select_popupmenu_item({item}, {insert}, {finish}, {opts})
13781385
{opts} Optional parameters. Reserved for future use.
13791386

13801387
*nvim_set_client_info()*
1381-
nvim_set_client_info({name}, {version}, {type}, {methods},
1382-
{attributes})
1388+
nvim_set_client_info({name}, {version}, {type}, {methods}, {attributes})
13831389
Self-identifies the client.
13841390

13851391
The client/plugin/application should call this after
@@ -1491,7 +1497,7 @@ nvim_set_decoration_provider({ns_id}, {opts})
14911497
disable the provider until the next redraw. Similarily, return
14921498
`false` in `on_win` will skip the `on_lines` calls for that
14931499
window (but any extmarks set in `on_win` will still be used).
1494-
A plugin managing multiple sources of decorations should
1500+
A plugin managing multiple sources of decoration should
14951501
ideally only set one provider, and merge the sources
14961502
internally. You can use multiple `ns_id` for the extmarks
14971503
set/modified inside the callback anyway.
@@ -1519,6 +1525,33 @@ nvim_set_decoration_provider({ns_id}, {opts})
15191525
• on_end: called at the end of a redraw cycle
15201526
["end", tick]
15211527

1528+
nvim_set_hl({ns_id}, {name}, {val}) *nvim_set_hl()*
1529+
Set a highlight group.
1530+
1531+
TODO: ns_id = 0, should modify :highlight namespace TODO val
1532+
should take update vs reset flag
1533+
1534+
Parameters: ~
1535+
{ns_id} number of namespace for this highlight
1536+
{name} highlight group name, like ErrorMsg
1537+
{val} highlight definiton map, like
1538+
|nvim_get_hl_by_name|.
1539+
1540+
nvim_set_hl_ns({ns_id}) *nvim_set_hl_ns()*
1541+
Set active namespace for highlights.
1542+
1543+
NB: this function can be called from async contexts, but the
1544+
semantics are not yet well-defined. To start with
1545+
|nvim_set_decoration_provider| on_win and on_line callbacks
1546+
are explicitly allowed to change the namespace during a redraw
1547+
cycle.
1548+
1549+
Attributes: ~
1550+
{fast}
1551+
1552+
Parameters: ~
1553+
{ns_id} the namespace to activate
1554+
15221555
nvim_set_keymap({mode}, {lhs}, {rhs}, {opts}) *nvim_set_keymap()*
15231556
Sets a global |mapping| for the given mode.
15241557

@@ -1618,8 +1651,8 @@ nvim__buf_stats({buffer}) *nvim__buf_stats()*
16181651
TODO: Documentation
16191652

16201653
*nvim_buf_add_highlight()*
1621-
nvim_buf_add_highlight({buffer}, {src_id}, {hl_group}, {line},
1622-
{col_start}, {col_end})
1654+
nvim_buf_add_highlight({buffer}, {src_id}, {hl_group}, {line}, {col_start},
1655+
{col_end})
16231656
Adds a highlight to buffer.
16241657

16251658
Useful for plugins that dynamically generate highlights to a
@@ -2067,8 +2100,7 @@ nvim_buf_set_keymap({buffer}, {mode}, {lhs}, {rhs}, {opts})
20672100
|nvim_set_keymap()|
20682101

20692102
*nvim_buf_set_lines()*
2070-
nvim_buf_set_lines({buffer}, {start}, {end}, {strict_indexing},
2071-
{replacement})
2103+
nvim_buf_set_lines({buffer}, {start}, {end}, {strict_indexing}, {replacement})
20722104
Sets (replaces) a line-range in the buffer.
20732105

20742106
Indexing is zero-based, end-exclusive. Negative indices are
@@ -2116,8 +2148,7 @@ nvim_buf_set_var({buffer}, {name}, {value}) *nvim_buf_set_var()*
21162148
{value} Variable value
21172149

21182150
*nvim_buf_set_virtual_text()*
2119-
nvim_buf_set_virtual_text({buffer}, {src_id}, {line}, {chunks},
2120-
{opts})
2151+
nvim_buf_set_virtual_text({buffer}, {src_id}, {line}, {chunks}, {opts})
21212152
Set the virtual text (annotation) for a buffer line.
21222153

21232154
By default (and currently the only option) the text will be
@@ -2449,8 +2480,8 @@ nvim_ui_pum_set_bounds({width}, {height}, {row}, {col})
24492480
Note that this method is not to be confused with
24502481
|nvim_ui_pum_set_height()|, which sets the number of visible
24512482
items in the popup menu, while this function sets the bounding
2452-
box of the popup menu, including visual decorations such as
2453-
boarders and sliders. Floats need not use the same font size,
2483+
box of the popup menu, including visual elements such as
2484+
borders and sliders. Floats need not use the same font size,
24542485
nor be anchored to exact grid corners, so one can set
24552486
floating-point numbers to the popup menu geometry.
24562487

runtime/doc/lsp-extension.txt

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
*lsp-extension.txt* LSP Extension
2+
3+
NVIM REFERENCE MANUAL
4+
5+
6+
The `vim.lsp` Lua module is a framework for building LSP plugins.
7+
8+
1. Start with |vim.lsp.start_client()| and |vim.lsp.buf_attach_client()|.
9+
2. Peek at the API: >
10+
:lua print(vim.inspect(vim.lsp))
11+
< 3. See |lsp-extension-example| for a full example.
12+
13+
================================================================================
14+
LSP EXAMPLE *lsp-extension-example*
15+
16+
This example is for plugin authors or users who want a lot of control. If you
17+
are just getting started see |lsp-quickstart|.
18+
19+
For more advanced configurations where just filtering by filetype isn't
20+
sufficient, you can use the `vim.lsp.start_client()` and
21+
`vim.lsp.buf_attach_client()` commands to easily customize the configuration
22+
however you please. For example, if you want to do your own filtering, or
23+
start a new LSP client based on the root directory for working with multiple
24+
projects in a single session. To illustrate, the following is a fully working
25+
Lua example.
26+
27+
The example will:
28+
1. Check for each new buffer whether or not we want to start an LSP client.
29+
2. Try to find a root directory by ascending from the buffer's path.
30+
3. Create a new LSP for that root directory if one doesn't exist.
31+
4. Attach the buffer to the client for that root directory.
32+
33+
>
34+
-- Some path manipulation utilities
35+
local function is_dir(filename)
36+
local stat = vim.loop.fs_stat(filename)
37+
return stat and stat.type == 'directory' or false
38+
end
39+
40+
local path_sep = vim.loop.os_uname().sysname == "Windows" and "\\" or "/"
41+
-- Assumes filepath is a file.
42+
local function dirname(filepath)
43+
local is_changed = false
44+
local result = filepath:gsub(path_sep.."([^"..path_sep.."]+)$", function()
45+
is_changed = true
46+
return ""
47+
end)
48+
return result, is_changed
49+
end
50+
51+
local function path_join(...)
52+
return table.concat(vim.tbl_flatten {...}, path_sep)
53+
end
54+
55+
-- Ascend the buffer's path until we find the rootdir.
56+
-- is_root_path is a function which returns bool
57+
local function buffer_find_root_dir(bufnr, is_root_path)
58+
local bufname = vim.api.nvim_buf_get_name(bufnr)
59+
if vim.fn.filereadable(bufname) == 0 then
60+
return nil
61+
end
62+
local dir = bufname
63+
-- Just in case our algo is buggy, don't infinite loop.
64+
for _ = 1, 100 do
65+
local did_change
66+
dir, did_change = dirname(dir)
67+
if is_root_path(dir, bufname) then
68+
return dir, bufname
69+
end
70+
-- If we can't ascend further, then stop looking.
71+
if not did_change then
72+
return nil
73+
end
74+
end
75+
end
76+
77+
-- A table to store our root_dir to client_id lookup. We want one LSP per
78+
-- root directory, and this is how we assert that.
79+
local javascript_lsps = {}
80+
-- Which filetypes we want to consider.
81+
local javascript_filetypes = {
82+
["javascript.jsx"] = true;
83+
["javascript"] = true;
84+
["typescript"] = true;
85+
["typescript.jsx"] = true;
86+
}
87+
88+
-- Create a template configuration for a server to start, minus the root_dir
89+
-- which we will specify later.
90+
local javascript_lsp_config = {
91+
name = "javascript";
92+
cmd = { path_join(os.getenv("JAVASCRIPT_LANGUAGE_SERVER_DIRECTORY"), "lib", "language-server-stdio.js") };
93+
}
94+
95+
-- This needs to be global so that we can call it from the autocmd.
96+
function check_start_javascript_lsp()
97+
local bufnr = vim.api.nvim_get_current_buf()
98+
-- Filter which files we are considering.
99+
if not javascript_filetypes[vim.api.nvim_buf_get_option(bufnr, 'filetype')] then
100+
return
101+
end
102+
-- Try to find our root directory. We will define this as a directory which contains
103+
-- node_modules. Another choice would be to check for `package.json`, or for `.git`.
104+
local root_dir = buffer_find_root_dir(bufnr, function(dir)
105+
return is_dir(path_join(dir, 'node_modules'))
106+
-- return vim.fn.filereadable(path_join(dir, 'package.json')) == 1
107+
-- return is_dir(path_join(dir, '.git'))
108+
end)
109+
-- We couldn't find a root directory, so ignore this file.
110+
if not root_dir then return end
111+
112+
-- Check if we have a client already or start and store it.
113+
local client_id = javascript_lsps[root_dir]
114+
if not client_id then
115+
local new_config = vim.tbl_extend("error", javascript_lsp_config, {
116+
root_dir = root_dir;
117+
})
118+
client_id = vim.lsp.start_client(new_config)
119+
javascript_lsps[root_dir] = client_id
120+
end
121+
-- Finally, attach to the buffer to track changes. This will do nothing if we
122+
-- are already attached.
123+
vim.lsp.buf_attach_client(bufnr, client_id)
124+
end
125+
126+
vim.api.nvim_command [[autocmd BufReadPost * lua check_start_javascript_lsp()]]
127+
<
128+
129+
vim:tw=78:ts=8:ft=help:norl:

0 commit comments

Comments
 (0)