diff options
author | Mathias Fußenegger <mfussenegger@users.noreply.github.com> | 2023-03-01 15:33:13 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-03-01 15:33:13 +0100 |
commit | 896d672736b32a8f4a4fa51844b44f266dcdcc6c (patch) | |
tree | 9d1d76c626640a9aab6c0dd2782416e342342036 | |
parent | d66832c76d6fce1627c33ae60a1b8efec1e32bdd (diff) | |
download | rneovim-896d672736b32a8f4a4fa51844b44f266dcdcc6c.tar.gz rneovim-896d672736b32a8f4a4fa51844b44f266dcdcc6c.tar.bz2 rneovim-896d672736b32a8f4a4fa51844b44f266dcdcc6c.zip |
fix(lsp): use buffer scheme for files not stored on disk (#22407)
Sending `didOpen` with a `file` scheme causes problems with some
language servers because they expect the file to exist on disk.
See https://github.com/microsoft/language-server-protocol/pull/1679
-rw-r--r-- | runtime/lua/vim/lsp.lua | 54 | ||||
-rw-r--r-- | runtime/lua/vim/lsp/util.lua | 9 | ||||
-rw-r--r-- | test/functional/fixtures/fake-lsp-server.lua | 37 |
3 files changed, 70 insertions, 30 deletions
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua index fed56ff846..a6d550f48f 100644 --- a/runtime/lua/vim/lsp.lua +++ b/runtime/lua/vim/lsp.lua @@ -367,7 +367,7 @@ do --- @field offset_encoding "utf-8"|"utf-16"|"utf-32" --- --- @class CTBufferState - --- @field name string name of the buffer + --- @field uri string uri of the buffer --- @field lines string[] snapshot of buffer lines from last didChange --- @field lines_tmp string[] --- @field pending_changes table[] List of debounced changes in incremental sync mode @@ -486,8 +486,12 @@ do if buf_state then buf_state.refs = buf_state.refs + 1 else + local uri = vim.uri_from_bufnr(bufnr) + if not uv.fs_stat(api.nvim_buf_get_name(bufnr)) then + uri = uri:gsub('^file://', 'buffer://') + end buf_state = { - name = api.nvim_buf_get_name(bufnr), + uri = uri, lines = {}, lines_tmp = {}, pending_changes = {}, @@ -502,12 +506,26 @@ do end ---@private - function changetracking._get_and_set_name(client, bufnr, name) + ---@param client table + ---@param bufnr integer + ---@return string uri + function changetracking._get_uri(client, bufnr) local state = state_by_group[get_group(client)] or {} local buf_state = (state.buffers or {})[bufnr] - local old_name = buf_state.name - buf_state.name = name - return old_name + return assert(buf_state.uri, 'Must have an URI set') + end + + ---@private + ---@param client table + ---@param bufnr integer + ---@param uri string + ---@return string uri + function changetracking._get_and_set_uri(client, bufnr, uri) + local state = state_by_group[get_group(client)] or {} + local buf_state = (state.buffers or {})[bufnr] + local old_uri = buf_state.uri + buf_state.uri = uri + return old_uri end ---@private @@ -594,7 +612,7 @@ do { text = buf_get_full_text(bufnr) }, } end - local uri = vim.uri_from_bufnr(bufnr) + local uri = buf_state.uri for _, client in pairs(state.clients) do if not client.is_stopped() and lsp.buf_is_attached(bufnr, client.id) then client.notify('textDocument/didChange', { @@ -707,11 +725,14 @@ local function text_document_did_open_handler(bufnr, client) return end local filetype = nvim_buf_get_option(bufnr, 'filetype') - + local uri = vim.uri_from_bufnr(bufnr) + if not uv.fs_stat(api.nvim_buf_get_name(bufnr)) then + uri = uri:gsub('^file://', 'buffer://') + end local params = { textDocument = { version = 0, - uri = vim.uri_from_bufnr(bufnr), + uri = uri, languageId = client.config.get_language_id(bufnr, filetype), text = buf_get_full_text(bufnr), }, @@ -1560,8 +1581,13 @@ local function text_document_did_save_handler(bufnr) local text = once(buf_get_full_text) for_each_buffer_client(bufnr, function(client) local name = api.nvim_buf_get_name(bufnr) - local old_name = changetracking._get_and_set_name(client, bufnr, name) - if old_name and name ~= old_name then + local old_uri = changetracking._get_and_set_uri(client, bufnr, uri) + if old_uri and name ~= old_uri then + client.notify('textDocument/didClose', { + textDocument = { + uri = old_uri, + }, + }) client.notify('textDocument/didOpen', { textDocument = { version = 0, @@ -1664,8 +1690,12 @@ function lsp.buf_attach_client(bufnr, client_id) end) end, on_detach = function() - local params = { textDocument = { uri = uri } } for_each_buffer_client(bufnr, function(client, _) + local params = { + textDocument = { + uri = changetracking._get_uri(client, bufnr), + }, + } changetracking.reset_buf(client, bufnr) if vim.tbl_get(client.server_capabilities, 'textDocumentSync', 'openClose') then client.notify('textDocument/didClose', params) diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 4beb4fc367..554e26022c 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -2032,7 +2032,12 @@ end ---@returns `TextDocumentIdentifier` ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentIdentifier function M.make_text_document_params(bufnr) - return { uri = vim.uri_from_bufnr(bufnr or 0) } + bufnr = bufnr or 0 + local uri = vim.uri_from_bufnr(bufnr) + if not uv.fs_stat(api.nvim_buf_get_name(bufnr)) then + uri = uri:gsub('^file://', 'buffer://') + end + return { uri = uri } end --- Create the workspace params @@ -2065,7 +2070,7 @@ function M.make_formatting_params(options) insertSpaces = vim.bo.expandtab, }) return { - textDocument = { uri = vim.uri_from_bufnr(0) }, + textDocument = M.make_text_document_params(0), options = options, } end diff --git a/test/functional/fixtures/fake-lsp-server.lua b/test/functional/fixtures/fake-lsp-server.lua index db0c8c0c3f..dbb66a42e8 100644 --- a/test/functional/fixtures/fake-lsp-server.lua +++ b/test/functional/fixtures/fake-lsp-server.lua @@ -272,6 +272,7 @@ function tests.text_document_save_did_open() end; body = function() notify('start') + expect_notification('textDocument/didClose') expect_notification('textDocument/didOpen') expect_notification('textDocument/didSave') notify('shutdown') @@ -292,6 +293,8 @@ function tests.text_document_sync_save_bool() end; body = function() notify('start') + expect_notification('textDocument/didClose') + expect_notification('textDocument/didOpen') expect_notification('textDocument/didSave', {textDocument = { uri = "file://" }}) notify('shutdown') end; @@ -313,6 +316,8 @@ function tests.text_document_sync_save_includeText() end; body = function() notify('start') + expect_notification('textDocument/didClose') + expect_notification('textDocument/didOpen') expect_notification('textDocument/didSave', { textDocument = { uri = "file://" @@ -459,7 +464,7 @@ function tests.basic_check_buffer_open() textDocument = { languageId = ""; text = table.concat({"testing"; "123"}, "\n") .. '\n'; - uri = "file://"; + uri = "buffer://"; version = 0; }; }) @@ -486,13 +491,13 @@ function tests.basic_check_buffer_open_and_change() textDocument = { languageId = ""; text = table.concat({"testing"; "123"}, "\n") .. '\n'; - uri = "file://"; + uri = "buffer://"; version = 0; }; }) expect_notification('textDocument/didChange', { textDocument = { - uri = "file://"; + uri = "buffer://"; version = 3; }; contentChanges = { @@ -522,13 +527,13 @@ function tests.basic_check_buffer_open_and_change_noeol() textDocument = { languageId = ""; text = table.concat({"testing"; "123"}, "\n"); - uri = "file://"; + uri = "buffer://"; version = 0; }; }) expect_notification('textDocument/didChange', { textDocument = { - uri = "file://"; + uri = "buffer://"; version = 3; }; contentChanges = { @@ -557,13 +562,13 @@ function tests.basic_check_buffer_open_and_change_multi() textDocument = { languageId = ""; text = table.concat({"testing"; "123"}, "\n") .. '\n'; - uri = "file://"; + uri = "buffer://"; version = 0; }; }) expect_notification('textDocument/didChange', { textDocument = { - uri = "file://"; + uri = "buffer://"; version = 3; }; contentChanges = { @@ -572,7 +577,7 @@ function tests.basic_check_buffer_open_and_change_multi() }) expect_notification('textDocument/didChange', { textDocument = { - uri = "file://"; + uri = "buffer://"; version = 4; }; contentChanges = { @@ -602,13 +607,13 @@ function tests.basic_check_buffer_open_and_change_multi_and_close() textDocument = { languageId = ""; text = table.concat({"testing"; "123"}, "\n") .. '\n'; - uri = "file://"; + uri = "buffer://"; version = 0; }; }) expect_notification('textDocument/didChange', { textDocument = { - uri = "file://"; + uri = "buffer://"; version = 3; }; contentChanges = { @@ -617,7 +622,7 @@ function tests.basic_check_buffer_open_and_change_multi_and_close() }) expect_notification('textDocument/didChange', { textDocument = { - uri = "file://"; + uri = "buffer://"; version = 4; }; contentChanges = { @@ -626,7 +631,7 @@ function tests.basic_check_buffer_open_and_change_multi_and_close() }) expect_notification('textDocument/didClose', { textDocument = { - uri = "file://"; + uri = "buffer://"; }; }) expect_notification("finish") @@ -660,13 +665,13 @@ function tests.basic_check_buffer_open_and_change_incremental() textDocument = { languageId = ""; text = table.concat({"testing"; "123"}, "\n") .. '\n'; - uri = "file://"; + uri = "buffer://"; version = 0; }; }) expect_notification('textDocument/didChange', { textDocument = { - uri = "file://"; + uri = "buffer://"; version = 3; }; contentChanges = { @@ -703,13 +708,13 @@ function tests.basic_check_buffer_open_and_change_incremental_editing() textDocument = { languageId = ""; text = table.concat({"testing"; "123"}, "\n"); - uri = "file://"; + uri = "buffer://"; version = 0; }; }) expect_notification('textDocument/didChange', { textDocument = { - uri = "file://"; + uri = "buffer://"; version = 3; }; contentChanges = { |