mirror of
https://github.com/neovim/neovim.git
synced 2024-12-25 13:45:15 -07:00
f75be5e9d5
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)
130 lines
4.7 KiB
Plaintext
130 lines
4.7 KiB
Plaintext
*lsp-extension.txt* LSP Extension
|
|
|
|
NVIM REFERENCE MANUAL
|
|
|
|
|
|
The `vim.lsp` Lua module is a framework for building LSP plugins.
|
|
|
|
1. Start with |vim.lsp.start_client()| and |vim.lsp.buf_attach_client()|.
|
|
2. Peek at the API: >
|
|
:lua print(vim.inspect(vim.lsp))
|
|
< 3. See |lsp-extension-example| for a full example.
|
|
|
|
================================================================================
|
|
LSP EXAMPLE *lsp-extension-example*
|
|
|
|
This example is for plugin authors or users who want a lot of control. If you
|
|
are just getting started see |lsp-quickstart|.
|
|
|
|
For more advanced configurations where just filtering by filetype isn't
|
|
sufficient, you can use the `vim.lsp.start_client()` and
|
|
`vim.lsp.buf_attach_client()` commands to easily customize the configuration
|
|
however you please. For example, if you want to do your own filtering, or
|
|
start a new LSP client based on the root directory for working with multiple
|
|
projects in a single session. To illustrate, the following is a fully working
|
|
Lua example.
|
|
|
|
The example will:
|
|
1. Check for each new buffer whether or not we want to start an LSP client.
|
|
2. Try to find a root directory by ascending from the buffer's path.
|
|
3. Create a new LSP for that root directory if one doesn't exist.
|
|
4. Attach the buffer to the client for that root directory.
|
|
|
|
>
|
|
-- Some path manipulation utilities
|
|
local function is_dir(filename)
|
|
local stat = vim.loop.fs_stat(filename)
|
|
return stat and stat.type == 'directory' or false
|
|
end
|
|
|
|
local path_sep = vim.loop.os_uname().sysname == "Windows" and "\\" or "/"
|
|
-- Assumes filepath is a file.
|
|
local function dirname(filepath)
|
|
local is_changed = false
|
|
local result = filepath:gsub(path_sep.."([^"..path_sep.."]+)$", function()
|
|
is_changed = true
|
|
return ""
|
|
end)
|
|
return result, is_changed
|
|
end
|
|
|
|
local function path_join(...)
|
|
return table.concat(vim.tbl_flatten {...}, path_sep)
|
|
end
|
|
|
|
-- Ascend the buffer's path until we find the rootdir.
|
|
-- is_root_path is a function which returns bool
|
|
local function buffer_find_root_dir(bufnr, is_root_path)
|
|
local bufname = vim.api.nvim_buf_get_name(bufnr)
|
|
if vim.fn.filereadable(bufname) == 0 then
|
|
return nil
|
|
end
|
|
local dir = bufname
|
|
-- Just in case our algo is buggy, don't infinite loop.
|
|
for _ = 1, 100 do
|
|
local did_change
|
|
dir, did_change = dirname(dir)
|
|
if is_root_path(dir, bufname) then
|
|
return dir, bufname
|
|
end
|
|
-- If we can't ascend further, then stop looking.
|
|
if not did_change then
|
|
return nil
|
|
end
|
|
end
|
|
end
|
|
|
|
-- A table to store our root_dir to client_id lookup. We want one LSP per
|
|
-- root directory, and this is how we assert that.
|
|
local javascript_lsps = {}
|
|
-- Which filetypes we want to consider.
|
|
local javascript_filetypes = {
|
|
["javascript.jsx"] = true;
|
|
["javascript"] = true;
|
|
["typescript"] = true;
|
|
["typescript.jsx"] = true;
|
|
}
|
|
|
|
-- Create a template configuration for a server to start, minus the root_dir
|
|
-- which we will specify later.
|
|
local javascript_lsp_config = {
|
|
name = "javascript";
|
|
cmd = { path_join(os.getenv("JAVASCRIPT_LANGUAGE_SERVER_DIRECTORY"), "lib", "language-server-stdio.js") };
|
|
}
|
|
|
|
-- This needs to be global so that we can call it from the autocmd.
|
|
function check_start_javascript_lsp()
|
|
local bufnr = vim.api.nvim_get_current_buf()
|
|
-- Filter which files we are considering.
|
|
if not javascript_filetypes[vim.api.nvim_buf_get_option(bufnr, 'filetype')] then
|
|
return
|
|
end
|
|
-- Try to find our root directory. We will define this as a directory which contains
|
|
-- node_modules. Another choice would be to check for `package.json`, or for `.git`.
|
|
local root_dir = buffer_find_root_dir(bufnr, function(dir)
|
|
return is_dir(path_join(dir, 'node_modules'))
|
|
-- return vim.fn.filereadable(path_join(dir, 'package.json')) == 1
|
|
-- return is_dir(path_join(dir, '.git'))
|
|
end)
|
|
-- We couldn't find a root directory, so ignore this file.
|
|
if not root_dir then return end
|
|
|
|
-- Check if we have a client already or start and store it.
|
|
local client_id = javascript_lsps[root_dir]
|
|
if not client_id then
|
|
local new_config = vim.tbl_extend("error", javascript_lsp_config, {
|
|
root_dir = root_dir;
|
|
})
|
|
client_id = vim.lsp.start_client(new_config)
|
|
javascript_lsps[root_dir] = client_id
|
|
end
|
|
-- Finally, attach to the buffer to track changes. This will do nothing if we
|
|
-- are already attached.
|
|
vim.lsp.buf_attach_client(bufnr, client_id)
|
|
end
|
|
|
|
vim.api.nvim_command [[autocmd BufReadPost * lua check_start_javascript_lsp()]]
|
|
<
|
|
|
|
vim:tw=78:ts=8:ft=help:norl:
|