mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
feat(lsp): overwrite omnifunc/tagfunc set by ftplugin #22267
Problem: Some built-in ftplugins set omnifunc/tagfunc/formatexpr which causes lsp.lua:set_defaults() to skip setup of defaults for those filetypes. For example the C++ ftplugin has: omnifunc=ccomplete#Complete Last set from /usr/share/nvim/runtime/ftplugin/c.vim line 30 so the changes done in #95c65a6b221fe6e1cf91e8322e7d7571dc511a71 will always be skipped for C++ files. Solution: Overwrite omnifunc/tagfunc/formatexpr options that were set by stock ftplugin. Fixes #21001
This commit is contained in:
parent
ce0fddf5ae
commit
9ef7297ef1
@ -51,8 +51,11 @@ Starting a LSP client will automatically report diagnostics via
|
||||
|vim.diagnostic|. Read |vim.diagnostic.config()| to learn how to customize the
|
||||
display.
|
||||
|
||||
It also sets some buffer options if the options are otherwise empty and if the
|
||||
language server supports the functionality.
|
||||
It also sets some buffer options if the language server supports the
|
||||
functionality and if the options are otherwise empty or have the default
|
||||
values set by Nvim runtime files (e.g. a ftplugin). In the latter case,
|
||||
the default values are not restored when the LSP client is detached from
|
||||
the buffer.
|
||||
|
||||
- 'omnifunc' is set to |vim.lsp.omnifunc()|. This allows to trigger completion
|
||||
using |i_CTRL-X_CTRL-O|
|
||||
|
@ -1112,19 +1112,43 @@ function lsp.start_client(config)
|
||||
end
|
||||
end
|
||||
|
||||
---@private
|
||||
-- Determines whether the given option can be set by `set_defaults`.
|
||||
local function is_empty_or_default(bufnr, option)
|
||||
if vim.bo[bufnr][option] == '' then
|
||||
return true
|
||||
end
|
||||
|
||||
local old_bufnr = vim.fn.bufnr('')
|
||||
local last_set_from = vim.fn.gettext('\n\tLast set from ')
|
||||
local line = vim.fn.gettext(' line ')
|
||||
|
||||
vim.cmd.buffer(bufnr)
|
||||
local scriptname = vim.fn
|
||||
.execute('verbose set ' .. option .. '?')
|
||||
:match(last_set_from .. '(.*)' .. line .. '%d+')
|
||||
vim.cmd.buffer(old_bufnr)
|
||||
|
||||
if not scriptname then
|
||||
return false
|
||||
end
|
||||
local vimruntime = vim.fn.getenv('VIMRUNTIME')
|
||||
return vim.startswith(vim.fn.expand(scriptname), vim.fn.expand(vimruntime))
|
||||
end
|
||||
|
||||
---@private
|
||||
local function set_defaults(client, bufnr)
|
||||
local capabilities = client.server_capabilities
|
||||
if capabilities.definitionProvider and vim.bo[bufnr].tagfunc == '' then
|
||||
if capabilities.definitionProvider and is_empty_or_default(bufnr, 'tagfunc') then
|
||||
vim.bo[bufnr].tagfunc = 'v:lua.vim.lsp.tagfunc'
|
||||
end
|
||||
if capabilities.completionProvider and vim.bo[bufnr].omnifunc == '' then
|
||||
if capabilities.completionProvider and is_empty_or_default(bufnr, 'omnifunc') then
|
||||
vim.bo[bufnr].omnifunc = 'v:lua.vim.lsp.omnifunc'
|
||||
end
|
||||
if
|
||||
capabilities.documentRangeFormattingProvider
|
||||
and vim.bo[bufnr].formatprg == ''
|
||||
and vim.bo[bufnr].formatexpr == ''
|
||||
and is_empty_or_default(bufnr, 'formatprg')
|
||||
and is_empty_or_default(bufnr, 'formatexpr')
|
||||
then
|
||||
vim.bo[bufnr].formatexpr = 'v:lua.vim.lsp.formatexpr()'
|
||||
end
|
||||
|
@ -932,6 +932,23 @@ function tests.basic_formatting()
|
||||
}
|
||||
end
|
||||
|
||||
function tests.set_defaults_all_capabilities()
|
||||
skeleton {
|
||||
on_init = function(_)
|
||||
return {
|
||||
capabilities = {
|
||||
definitionProvider = true,
|
||||
completionProvider = true,
|
||||
documentRangeFormattingProvider = true,
|
||||
}
|
||||
}
|
||||
end;
|
||||
body = function()
|
||||
notify('test')
|
||||
end;
|
||||
}
|
||||
end
|
||||
|
||||
-- Tests will be indexed by test_name
|
||||
local test_name = arg[1]
|
||||
local timeout = arg[2]
|
||||
|
@ -31,6 +31,11 @@ local fake_lsp_code = lsp_helpers.fake_lsp_code
|
||||
local fake_lsp_logfile = lsp_helpers.fake_lsp_logfile
|
||||
local test_rpc_server = lsp_helpers.test_rpc_server
|
||||
|
||||
local function get_buf_option(name, bufnr)
|
||||
bufnr = bufnr or "BUFFER"
|
||||
return exec_lua(string.format("return vim.api.nvim_buf_get_option(%s, '%s')", bufnr, name))
|
||||
end
|
||||
|
||||
-- TODO(justinmk): hangs on Windows https://github.com/neovim/neovim/pull/11837
|
||||
if skip(is_os('win')) then return end
|
||||
|
||||
@ -313,6 +318,104 @@ describe('LSP', function()
|
||||
}
|
||||
end)
|
||||
|
||||
it('should set default options on attach', function()
|
||||
local client
|
||||
test_rpc_server {
|
||||
test_name = "set_defaults_all_capabilities";
|
||||
on_setup = function()
|
||||
exec_lua [[
|
||||
BUFFER = vim.api.nvim_create_buf(false, true)
|
||||
]]
|
||||
end;
|
||||
on_init = function(_client)
|
||||
client = _client
|
||||
exec_lua("lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)")
|
||||
end;
|
||||
on_handler = function(_, _, ctx)
|
||||
if ctx.method == 'test' then
|
||||
eq('v:lua.vim.lsp.tagfunc', get_buf_option("tagfunc"))
|
||||
eq('v:lua.vim.lsp.omnifunc', get_buf_option("omnifunc"))
|
||||
eq('v:lua.vim.lsp.formatexpr()', get_buf_option("formatexpr"))
|
||||
client.stop()
|
||||
end
|
||||
end;
|
||||
on_exit = function(_, _)
|
||||
eq('', get_buf_option("tagfunc"))
|
||||
eq('', get_buf_option("omnifunc"))
|
||||
eq('', get_buf_option("formatexpr"))
|
||||
end;
|
||||
}
|
||||
end)
|
||||
|
||||
it('should overwrite options set by ftplugins', function()
|
||||
local client
|
||||
test_rpc_server {
|
||||
test_name = "set_defaults_all_capabilities";
|
||||
on_setup = function()
|
||||
exec_lua [[
|
||||
vim.api.nvim_command('filetype plugin on')
|
||||
BUFFER_1 = vim.api.nvim_create_buf(false, true)
|
||||
BUFFER_2 = vim.api.nvim_create_buf(false, true)
|
||||
vim.api.nvim_buf_set_option(BUFFER_1, 'filetype', 'man')
|
||||
vim.api.nvim_buf_set_option(BUFFER_2, 'filetype', 'xml')
|
||||
]]
|
||||
eq('v:lua.require\'man\'.goto_tag', get_buf_option("tagfunc", "BUFFER_1"))
|
||||
eq('xmlcomplete#CompleteTags', get_buf_option("omnifunc", "BUFFER_2"))
|
||||
eq('xmlformat#Format()', get_buf_option("formatexpr", "BUFFER_2"))
|
||||
end;
|
||||
on_init = function(_client)
|
||||
client = _client
|
||||
exec_lua("lsp.buf_attach_client(BUFFER_1, TEST_RPC_CLIENT_ID)")
|
||||
exec_lua("lsp.buf_attach_client(BUFFER_2, TEST_RPC_CLIENT_ID)")
|
||||
end;
|
||||
on_handler = function(_, _, ctx)
|
||||
if ctx.method == 'test' then
|
||||
eq('v:lua.vim.lsp.tagfunc', get_buf_option("tagfunc", "BUFFER_1"))
|
||||
eq('v:lua.vim.lsp.omnifunc', get_buf_option("omnifunc", "BUFFER_2"))
|
||||
eq('v:lua.vim.lsp.formatexpr()', get_buf_option("formatexpr", "BUFFER_2"))
|
||||
client.stop()
|
||||
end
|
||||
end;
|
||||
on_exit = function(_, _)
|
||||
eq('', get_buf_option("tagfunc", "BUFFER_1"))
|
||||
eq('', get_buf_option("omnifunc", "BUFFER_2"))
|
||||
eq('', get_buf_option("formatexpr", "BUFFER_2"))
|
||||
end;
|
||||
}
|
||||
end)
|
||||
|
||||
it('should not overwrite user-defined options', function()
|
||||
local client
|
||||
test_rpc_server {
|
||||
test_name = "set_defaults_all_capabilities";
|
||||
on_setup = function()
|
||||
exec_lua [[
|
||||
BUFFER = vim.api.nvim_create_buf(false, true)
|
||||
vim.api.nvim_buf_set_option(BUFFER, 'tagfunc', 'tfu')
|
||||
vim.api.nvim_buf_set_option(BUFFER, 'omnifunc', 'ofu')
|
||||
vim.api.nvim_buf_set_option(BUFFER, 'formatexpr', 'fex')
|
||||
]]
|
||||
end;
|
||||
on_init = function(_client)
|
||||
client = _client
|
||||
exec_lua("lsp.buf_attach_client(BUFFER, TEST_RPC_CLIENT_ID)")
|
||||
end;
|
||||
on_handler = function(_, _, ctx)
|
||||
if ctx.method == 'test' then
|
||||
eq('tfu', get_buf_option("tagfunc"))
|
||||
eq('ofu', get_buf_option("omnifunc"))
|
||||
eq('fex', get_buf_option("formatexpr"))
|
||||
client.stop()
|
||||
end
|
||||
end;
|
||||
on_exit = function(_, _)
|
||||
eq('tfu', get_buf_option("tagfunc"))
|
||||
eq('ofu', get_buf_option("omnifunc"))
|
||||
eq('fex', get_buf_option("formatexpr"))
|
||||
end;
|
||||
}
|
||||
end)
|
||||
|
||||
it('should detach buffer on bufwipe', function()
|
||||
clear()
|
||||
exec_lua(create_server_definition)
|
||||
|
Loading…
Reference in New Issue
Block a user