From 97bea3163a3fe50359e7f6ffda747e28974a818a Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Wed, 13 Dec 2023 12:00:11 +0000 Subject: feat(lsp): more annotations --- runtime/lua/vim/lsp/util.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'runtime/lua/vim/lsp/util.lua') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 32b220746f..dc8fb25563 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -2089,7 +2089,7 @@ end --- Creates a `DocumentFormattingParams` object for the current buffer and cursor position. --- ---@param options table|nil with valid `FormattingOptions` entries ----@return `DocumentFormattingParams` object +---@return lsp.DocumentFormattingParams object ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_formatting function M.make_formatting_params(options) validate({ options = { options, 't', true } }) @@ -2228,6 +2228,6 @@ end M._get_line_byte_from_position = get_line_byte_from_position ---@nodoc -M.buf_versions = {} +M.buf_versions = {} ---@type table return M -- cgit From db0ec84fb46b8235f8651d5aa25eb56a9b117eb5 Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Fri, 22 Dec 2023 11:38:02 +0100 Subject: feat(lsp): add type annotations for lsp.util.locations_to_items (#26694) Problem: luals reported many warnings Solution: Add type annotations --- runtime/lua/vim/lsp/util.lua | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'runtime/lua/vim/lsp/util.lua') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index dc8fb25563..63c4c1e7fc 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -1754,6 +1754,13 @@ local position_sort = sort_by_key(function(v) return { v.start.line, v.start.character } end) +---@class vim.lsp.util.LocationItem +---@field filename string +---@field lnum integer 1-indexed line number +---@field col integer 1-indexed column +---@field text string +---@field user_data lsp.Location|lsp.LocationLink + --- Returns the items with the byte position calculated correctly and in sorted --- order, for display in quickfix and location lists. --- @@ -1763,10 +1770,10 @@ end) --- The result can be passed to the {list} argument of |setqflist()| or --- |setloclist()|. --- ----@param locations table list of `Location`s or `LocationLink`s +---@param locations lsp.Location[]|lsp.LocationLink[] ---@param offset_encoding string offset_encoding for locations utf-8|utf-16|utf-32 --- default to first client of buffer ----@return table list of items +---@return vim.lsp.util.LocationItem[] list of items function M.locations_to_items(locations, offset_encoding) if offset_encoding == nil then vim.notify_once( @@ -1777,6 +1784,7 @@ function M.locations_to_items(locations, offset_encoding) end local items = {} + ---@type table local grouped = setmetatable({}, { __index = function(t, k) local v = {} @@ -1791,6 +1799,7 @@ function M.locations_to_items(locations, offset_encoding) table.insert(grouped[uri], { start = range.start, location = d }) end + ---@type string[] local keys = vim.tbl_keys(grouped) table.sort(keys) -- TODO(ashkan) I wish we could do this lazily. @@ -1799,16 +1808,13 @@ function M.locations_to_items(locations, offset_encoding) table.sort(rows, position_sort) local filename = vim.uri_to_fname(uri) - -- list of row numbers - local uri_rows = {} + local line_numbers = {} for _, temp in ipairs(rows) do - local pos = temp.start - local row = pos.line - table.insert(uri_rows, row) + table.insert(line_numbers, temp.start.line) end -- get all the lines for this uri - local lines = get_lines(vim.uri_to_bufnr(uri), uri_rows) + local lines = get_lines(vim.uri_to_bufnr(uri), line_numbers) for _, temp in ipairs(rows) do local pos = temp.start -- cgit From 5f9d4d8afeb5dc3d5df4965c24cbb4c6e01694f7 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Mon, 25 Dec 2023 21:28:28 +0100 Subject: refactor: use vim.deprecate on all deprecated functions --- runtime/lua/vim/lsp/util.lua | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'runtime/lua/vim/lsp/util.lua') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 63c4c1e7fc..ba7ce3c2b6 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -180,6 +180,7 @@ local _str_byteindex_enc = M._str_byteindex_enc ---@param new_lines (table) list of strings to replace the original ---@return table The modified {lines} object function M.set_lines(lines, A, B, new_lines) + vim.deprecate('vim.lsp.util.set_lines()', 'nil', '0.12') -- 0-indexing to 1-indexing local i_0 = A[1] + 1 -- If it extends past the end, truncate it to the end. This is because the @@ -346,7 +347,7 @@ end ---@private ---@deprecated Use vim.lsp.status() or access client.progress directly function M.get_progress_messages() - vim.deprecate('vim.lsp.util.get_progress_messages', 'vim.lsp.status', '0.11.0') + vim.deprecate('vim.lsp.util.get_progress_messages()', 'vim.lsp.status()', '0.11') local new_messages = {} local progress_remove = {} @@ -552,7 +553,7 @@ end ---@return lsp.CompletionItem[] List of completion items ---@see https://microsoft.github.io/language-server-protocol/specification#textDocument_completion function M.extract_completion_items(result) - vim.deprecate('vim.lsp.util.extract_completion_items', nil, '0.11') + vim.deprecate('vim.lsp.util.extract_completion_items()', nil, '0.11') if type(result) == 'table' and result.items then -- result is a `CompletionList` return result.items @@ -612,7 +613,7 @@ end ---@param input string unparsed snippet ---@return string parsed snippet function M.parse_snippet(input) - vim.deprecate('vim.lsp.util.parse_snippet', nil, '0.11') + vim.deprecate('vim.lsp.util.parse_snippet()', nil, '0.11') local ok, parsed = pcall(function() return snippet.parse(input) end) @@ -634,7 +635,7 @@ end ---@return table[] items ---@see complete-items function M.text_document_completion_list_to_complete_items(result, prefix) - vim.deprecate('vim.lsp.util.text_document_completion_list_to_complete_items', nil, '0.11') + vim.deprecate('vim.lsp.util.text_document_completion_list_to_complete_items()', nil, '0.11') return require('vim.lsp._completion')._lsp_to_complete_items(result, prefix) end @@ -1885,6 +1886,7 @@ end ---@param lines table list of lines to trim ---@return table trimmed list of lines function M.trim_empty_lines(lines) + vim.deprecate('vim.lsp.util.trim_empty_lines()', 'vim.split() with `trimempty`', '0.12') local start = 1 for i = 1, #lines do if lines[i] ~= nil and #lines[i] > 0 then @@ -1911,6 +1913,7 @@ end ---@param lines table list of lines ---@return string filetype or "markdown" if it was unchanged. function M.try_trim_markdown_code_blocks(lines) + vim.deprecate('vim.lsp.util.try_trim_markdown_code_blocks()', 'nil', '0.12') local language_id = lines[1]:match('^```(.*)') if language_id then local has_inner_code_fence = false -- cgit From 5cb906e91cb56302d0737aa80e2d890dde452029 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Tue, 26 Dec 2023 15:16:45 +0100 Subject: fix: correct versions in deprecation warnings The following functions should be removed in 0.12 according to the deprecation strategy in MAINTAIN.md: - vim.lsp.util.extract_completion_items() - vim.lsp.util.parse_snippet() - vim.lsp.util.text_document_completion_list_to_complete_items() --- runtime/lua/vim/lsp/util.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'runtime/lua/vim/lsp/util.lua') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index ba7ce3c2b6..90e2f28ef4 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -553,7 +553,7 @@ end ---@return lsp.CompletionItem[] List of completion items ---@see https://microsoft.github.io/language-server-protocol/specification#textDocument_completion function M.extract_completion_items(result) - vim.deprecate('vim.lsp.util.extract_completion_items()', nil, '0.11') + vim.deprecate('vim.lsp.util.extract_completion_items()', nil, '0.12') if type(result) == 'table' and result.items then -- result is a `CompletionList` return result.items @@ -613,7 +613,7 @@ end ---@param input string unparsed snippet ---@return string parsed snippet function M.parse_snippet(input) - vim.deprecate('vim.lsp.util.parse_snippet()', nil, '0.11') + vim.deprecate('vim.lsp.util.parse_snippet()', nil, '0.12') local ok, parsed = pcall(function() return snippet.parse(input) end) @@ -635,7 +635,7 @@ end ---@return table[] items ---@see complete-items function M.text_document_completion_list_to_complete_items(result, prefix) - vim.deprecate('vim.lsp.util.text_document_completion_list_to_complete_items()', nil, '0.11') + vim.deprecate('vim.lsp.util.text_document_completion_list_to_complete_items()', nil, '0.12') return require('vim.lsp._completion')._lsp_to_complete_items(result, prefix) end -- cgit From e0eb4188bfabefac54dd7cdcfe57fbb6ddb724b5 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Wed, 27 Dec 2023 09:42:30 +0100 Subject: revert: "fix: correct versions in deprecation warnings" This reverts commit 5cb906e91cb56302d0737aa80e2d890dde452029. They were intentionally fast-tracked. - `parse_snippet()` because of limited scope, and given that it's kinda semi-broken (arbitrary formatting rules, not that useful for what it was used for) - `extract_completion_items()` doesn't work if we want to add the LSP completionlist capability - `text_document_completion_list_to_complete_items()` also doesn't work for completionlist --- runtime/lua/vim/lsp/util.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'runtime/lua/vim/lsp/util.lua') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 90e2f28ef4..ba7ce3c2b6 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -553,7 +553,7 @@ end ---@return lsp.CompletionItem[] List of completion items ---@see https://microsoft.github.io/language-server-protocol/specification#textDocument_completion function M.extract_completion_items(result) - vim.deprecate('vim.lsp.util.extract_completion_items()', nil, '0.12') + vim.deprecate('vim.lsp.util.extract_completion_items()', nil, '0.11') if type(result) == 'table' and result.items then -- result is a `CompletionList` return result.items @@ -613,7 +613,7 @@ end ---@param input string unparsed snippet ---@return string parsed snippet function M.parse_snippet(input) - vim.deprecate('vim.lsp.util.parse_snippet()', nil, '0.12') + vim.deprecate('vim.lsp.util.parse_snippet()', nil, '0.11') local ok, parsed = pcall(function() return snippet.parse(input) end) @@ -635,7 +635,7 @@ end ---@return table[] items ---@see complete-items function M.text_document_completion_list_to_complete_items(result, prefix) - vim.deprecate('vim.lsp.util.text_document_completion_list_to_complete_items()', nil, '0.12') + vim.deprecate('vim.lsp.util.text_document_completion_list_to_complete_items()', nil, '0.11') return require('vim.lsp._completion')._lsp_to_complete_items(result, prefix) end -- cgit From 67f53323446d45bad7a22e92493f6402316a8ba1 Mon Sep 17 00:00:00 2001 From: Jongwook Choi Date: Thu, 28 Dec 2023 18:00:30 -0500 Subject: fix(docs): clean up non-docstring comments for vimdoc gen These non-docstring comments can be included into doxygen's brief description and then appear in the succeeding function documentation. --- runtime/lua/vim/lsp/util.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim/lsp/util.lua') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index ba7ce3c2b6..44465f6cff 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -1069,7 +1069,7 @@ function M.show_document(location, offset_encoding, opts) -- location may be Location or LocationLink local range = location.range or location.targetSelectionRange if range then - --- Jump to new location (adjusting for encoding of characters) + -- Jump to new location (adjusting for encoding of characters) local row = range.start.line local col = get_line_byte_from_position(bufnr, range.start, offset_encoding) api.nvim_win_set_cursor(win, { row + 1, col }) -- cgit From 2f9ee9b6cfc61a0504fc0bc22bdf481828e2ea91 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Tue, 9 Jan 2024 17:36:46 +0000 Subject: fix(doc): improve doc generation of types using lpeg Added a lpeg grammar for LuaCATS and use it in lua2dox.lua --- runtime/lua/vim/lsp/util.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'runtime/lua/vim/lsp/util.lua') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 44465f6cff..a2cc81781a 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -790,7 +790,7 @@ end --- Note that if the input is of type `MarkupContent` and its kind is `plaintext`, --- then the corresponding value is returned without further modifications. --- ----@param input (`MarkedString` | `MarkedString[]` | `MarkupContent`) +---@param input (lsp.MarkedString | lsp.MarkedString[] | lsp.MarkupContent) ---@param contents (table|nil) List of strings to extend with converted lines. Defaults to {}. ---@return string[] extended with lines of converted markdown. ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_hover @@ -2115,8 +2115,8 @@ end --- Returns the UTF-32 and UTF-16 offsets for a position in a certain buffer. --- ---@param buf integer buffer number (0 for current) ----@param row 0-indexed line ----@param col 0-indexed byte offset in line +---@param row integer 0-indexed line +---@param col integer 0-indexed byte offset in line ---@param offset_encoding string utf-8|utf-16|utf-32 defaults to `offset_encoding` of first client of `buf` ---@return integer `offset_encoding` index of the character in line {row} column {col} in buffer {buf} function M.character_offset(buf, row, col, offset_encoding) -- cgit From 4d91604c8868b7afaf429cc16b72192ce89ea698 Mon Sep 17 00:00:00 2001 From: Jongwook Choi Date: Sun, 14 Jan 2024 22:37:07 -0500 Subject: docs: add lua typing for `vim.NIL` --- runtime/lua/vim/lsp/util.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim/lsp/util.lua') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index a2cc81781a..50890e37ce 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -2139,7 +2139,7 @@ end --- ---@param settings table language server settings ---@param section string indicating the field of the settings table ----@return table|string The value of settings accessed via section +---@return table|string|vim.NIL The value of settings accessed via section. `vim.NIL` if not found. function M.lookup_section(settings, section) for part in vim.gsplit(section, '.', { plain = true }) do settings = settings[part] -- cgit From 3973a5e40505422c7ac42692eaecc1ff84f89e7f Mon Sep 17 00:00:00 2001 From: Jongwook Choi Date: Sun, 14 Jan 2024 23:12:54 -0500 Subject: refactor(lsp): deprecate `vim.lsp.util.lookup_section` This function is used only in the `workspace/configuration` handler, and does not warrant a public API because of its confusing return types. The only caller `vim.lsp.handlers["workspace.configuration"]` is also refactored to use `vim.tbl_get()` instead. --- runtime/lua/vim/lsp/util.lua | 2 ++ 1 file changed, 2 insertions(+) (limited to 'runtime/lua/vim/lsp/util.lua') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 50890e37ce..cee09d85e0 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -2140,7 +2140,9 @@ end ---@param settings table language server settings ---@param section string indicating the field of the settings table ---@return table|string|vim.NIL The value of settings accessed via section. `vim.NIL` if not found. +---@deprecated function M.lookup_section(settings, section) + vim.deprecate('vim.lsp.util.lookup_section()', 'vim.tbl_get() with `vim.split`', '0.12') for part in vim.gsplit(section, '.', { plain = true }) do settings = settings[part] if settings == nil then -- cgit From 2e982f1aad9f1a03562b7a451d642f76b04c37cb Mon Sep 17 00:00:00 2001 From: dundargoc Date: Mon, 22 Jan 2024 18:23:28 +0100 Subject: refactor: create function for deferred loading The benefit of this is that users only pay for what they use. If e.g. only `vim.lsp.buf_get_clients()` is called then they don't need to load all modules under `vim.lsp` which could lead to significant startuptime saving. Also `vim.lsp.module` is a bit nicer to user compared to `require("vim.lsp.module")`. This isn't used for some nested modules such as `filetype` as it breaks tests with error messages such as "attempt to index field 'detect'". It's not entirely certain the reason for this, but it is likely it is due to filetype being precompiled which would imply deferred loading isn't needed for performance reasons. --- runtime/lua/vim/lsp/util.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'runtime/lua/vim/lsp/util.lua') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index cee09d85e0..b5e15e135c 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -3,7 +3,7 @@ local snippet = require('vim.lsp._snippet_grammar') local validate = vim.validate local api = vim.api local list_extend = vim.list_extend -local highlight = require('vim.highlight') +local highlight = vim.highlight local uv = vim.uv local npcall = vim.F.npcall @@ -636,7 +636,7 @@ end ---@see complete-items function M.text_document_completion_list_to_complete_items(result, prefix) vim.deprecate('vim.lsp.util.text_document_completion_list_to_complete_items()', nil, '0.11') - return require('vim.lsp._completion')._lsp_to_complete_items(result, prefix) + return vim.lsp._completion._lsp_to_complete_items(result, prefix) end --- Like vim.fn.bufwinid except it works across tabpages. -- cgit From f0e61e6d92b5ce115388f8a03f8d34f00a3dea92 Mon Sep 17 00:00:00 2001 From: Tomasz N Date: Thu, 8 Feb 2024 22:06:54 +0100 Subject: fix(lsp): rename fails on missing parent directory #27291 Problem: If a rename results in a path that has missing parent directory(s), it will fail. Solution: Do a recursive mkdir before attempting the rename. --- runtime/lua/vim/lsp/util.lua | 3 +++ 1 file changed, 3 insertions(+) (limited to 'runtime/lua/vim/lsp/util.lua') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index b5e15e135c..86bef1ac8a 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -693,6 +693,9 @@ function M.rename(old_fname, new_fname, opts) end) end + local newdir = assert(vim.fs.dirname(new_fname)) + vim.fn.mkdir(newdir, 'p') + local ok, err = os.rename(old_fname, new_fname) assert(ok, err) -- cgit From d09957e0a06f350443c750d9838b5f1016c0cccc Mon Sep 17 00:00:00 2001 From: Tomasz N Date: Wed, 14 Feb 2024 21:11:29 +0100 Subject: fix(lsp): rename: load and list new buffer if attached to window (#27408) --- runtime/lua/vim/lsp/util.lua | 2 ++ 1 file changed, 2 insertions(+) (limited to 'runtime/lua/vim/lsp/util.lua') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 86bef1ac8a..4abc58ee3c 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -702,6 +702,8 @@ function M.rename(old_fname, new_fname, opts) if vim.fn.isdirectory(new_fname) == 0 then local newbuf = vim.fn.bufadd(new_fname) if win then + vim.fn.bufload(newbuf) + vim.bo[newbuf].buflisted = true api.nvim_win_set_buf(win, newbuf) end end -- cgit From 90f6d999b12a93bb8a2aa9a735d2d77fc97b94db Mon Sep 17 00:00:00 2001 From: Jaehwang Jung Date: Sat, 24 Feb 2024 21:14:12 +0900 Subject: refactor(lsp): remove redundant code (#27601) * use builtin function * buffer:// was removed in 236c20795eb9f11e21e0719b735ea741711acc08. --- runtime/lua/vim/lsp/util.lua | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) (limited to 'runtime/lua/vim/lsp/util.lua') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 4abc58ee3c..418eb5e159 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -639,21 +639,12 @@ function M.text_document_completion_list_to_complete_items(result, prefix) return vim.lsp._completion._lsp_to_complete_items(result, prefix) end ---- Like vim.fn.bufwinid except it works across tabpages. -local function bufwinid(bufnr) - for _, win in ipairs(api.nvim_list_wins()) do - if api.nvim_win_get_buf(win) == bufnr then - return win - end - end -end - --- Get list of buffers for a directory local function get_dir_bufs(path) path = path:gsub('([^%w])', '%%%1') local buffers = {} for _, v in ipairs(vim.api.nvim_list_bufs()) do - local bufname = vim.api.nvim_buf_get_name(v):gsub('buffer://', '') + local bufname = vim.api.nvim_buf_get_name(v) if bufname:find(path) then table.insert(buffers, v) end @@ -682,7 +673,7 @@ function M.rename(old_fname, new_fname, opts) else local oldbuf = vim.fn.bufadd(old_fname) table.insert(oldbufs, oldbuf) - win = bufwinid(oldbuf) + win = vim.fn.win_findbuf(oldbuf)[1] end for _, b in ipairs(oldbufs) do @@ -1061,7 +1052,7 @@ function M.show_document(location, offset_encoding, opts) vim.fn.settagstack(vim.fn.win_getid(), { items = items }, 't') end - local win = opts.reuse_win and bufwinid(bufnr) + local win = opts.reuse_win and vim.fn.win_findbuf(bufnr)[1] or focus and api.nvim_get_current_win() or create_window_without_focus() -- cgit From 8addd27504e698da62176824209ae2d3d24247c0 Mon Sep 17 00:00:00 2001 From: Jaehwang Jung Date: Sun, 25 Feb 2024 00:47:34 +0900 Subject: fix(lsp): when renaming directory, check path prefix of buffer names (#27603) For example, when renaming /path/to/dir, buffers like fern://drawer/file:///path/to/dir, /path/to/dir123 should not be matched. --- runtime/lua/vim/lsp/util.lua | 53 ++++++++++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 14 deletions(-) (limited to 'runtime/lua/vim/lsp/util.lua') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 418eb5e159..444354fdc3 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -639,13 +639,28 @@ function M.text_document_completion_list_to_complete_items(result, prefix) return vim.lsp._completion._lsp_to_complete_items(result, prefix) end ---- Get list of buffers for a directory -local function get_dir_bufs(path) - path = path:gsub('([^%w])', '%%%1') +local function path_components(path) + return vim.split(path, '/', { plain = true }) +end + +local function path_under_prefix(path, prefix) + for i, c in ipairs(prefix) do + if c ~= path[i] then + return false + end + end + return true +end + +--- Get list of buffers whose filename matches the given path prefix (normalized full path) +---@return integer[] +local function get_bufs_with_prefix(prefix) + prefix = path_components(prefix) local buffers = {} for _, v in ipairs(vim.api.nvim_list_bufs()) do - local bufname = vim.api.nvim_buf_get_name(v) - if bufname:find(path) then + local bname = vim.api.nvim_buf_get_name(v) + local path = path_components(vim.fs.normalize(bname, { expand_env = false })) + if path_under_prefix(path, prefix) then table.insert(buffers, v) end end @@ -654,24 +669,34 @@ end --- Rename old_fname to new_fname --- ----@param opts (table) --- overwrite? bool --- ignoreIfExists? bool +---@param old_fname string +---@param new_fname string +---@param opts? table options +--- - overwrite? boolean +--- - ignoreIfExists? boolean function M.rename(old_fname, new_fname, opts) opts = opts or {} + local skip = not opts.overwrite or opts.ignoreIfExists + + local old_fname_full = vim.uv.fs_realpath(vim.fs.normalize(old_fname, { expand_env = false })) + if not old_fname_full then + vim.notify('Invalid path: ' .. old_fname, vim.log.levels.ERROR) + return + end + local target_exists = uv.fs_stat(new_fname) ~= nil - if target_exists and not opts.overwrite or opts.ignoreIfExists then - vim.notify('Rename target already exists. Skipping rename.') + if target_exists and skip then + vim.notify(new_fname .. ' already exists. Skipping rename.', vim.log.levels.ERROR) return end local oldbufs = {} local win = nil - if vim.fn.isdirectory(old_fname) == 1 then - oldbufs = get_dir_bufs(old_fname) + if vim.fn.isdirectory(old_fname_full) == 1 then + oldbufs = get_bufs_with_prefix(old_fname_full) else - local oldbuf = vim.fn.bufadd(old_fname) + local oldbuf = vim.fn.bufadd(old_fname_full) table.insert(oldbufs, oldbuf) win = vim.fn.win_findbuf(oldbuf)[1] end @@ -687,7 +712,7 @@ function M.rename(old_fname, new_fname, opts) local newdir = assert(vim.fs.dirname(new_fname)) vim.fn.mkdir(newdir, 'p') - local ok, err = os.rename(old_fname, new_fname) + local ok, err = os.rename(old_fname_full, new_fname) assert(ok, err) if vim.fn.isdirectory(new_fname) == 0 then -- cgit From 2e1f5055acdef650c27efc4afdf8606037ec021b Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Sat, 24 Feb 2024 19:21:57 -0600 Subject: fix(lsp): add assertion for explicit bufnr in apply_text_edits (#27614) Assert that the buffer number passed to apply_text_edits is fully resolved (not 0 or null). Pass the known buffer number to apply_text_edits from lsp.formatexpr(). --- runtime/lua/vim/lsp/util.lua | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'runtime/lua/vim/lsp/util.lua') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 444354fdc3..b60135f851 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -419,6 +419,9 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding) if not next(text_edits) then return end + + assert(bufnr ~= 0, 'Explicit buffer number is required') + if not api.nvim_buf_is_loaded(bufnr) then vim.fn.bufload(bufnr) end @@ -457,7 +460,7 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding) -- save and restore local marks since they get deleted by nvim_buf_set_lines local marks = {} - for _, m in pairs(vim.fn.getmarklist(bufnr or vim.api.nvim_get_current_buf())) do + for _, m in pairs(vim.fn.getmarklist(bufnr)) do if m.mark:match("^'[a-z]$") then marks[m.mark:sub(2, 2)] = { m.pos[2], m.pos[3] - 1 } -- api-indexed end @@ -516,7 +519,7 @@ function M.apply_text_edits(text_edits, bufnr, offset_encoding) local max = api.nvim_buf_line_count(bufnr) -- no need to restore marks that still exist - for _, m in pairs(vim.fn.getmarklist(bufnr or vim.api.nvim_get_current_buf())) do + for _, m in pairs(vim.fn.getmarklist(bufnr)) do marks[m.mark:sub(2, 2)] = nil end -- restore marks -- cgit From 9beb40a4db5613601fc1a4b828a44e5977eca046 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 15 Feb 2024 17:16:04 +0000 Subject: feat(docs): replace lua2dox.lua Problem: The documentation flow (`gen_vimdoc.py`) has several issues: - it's not very versatile - depends on doxygen - doesn't work well with Lua code as it requires an awkward filter script to convert it into pseudo-C. - The intermediate XML files and filters makes it too much like a rube goldberg machine. Solution: Re-implement the flow using Lua, LPEG and treesitter. - `gen_vimdoc.py` is now replaced with `gen_vimdoc.lua` and replicates a portion of the logic. - `lua2dox.lua` is gone! - No more XML files. - Doxygen is now longer used and instead we now use: - LPEG for comment parsing (see `scripts/luacats_grammar.lua` and `scripts/cdoc_grammar.lua`). - LPEG for C parsing (see `scripts/cdoc_parser.lua`) - Lua patterns for Lua parsing (see `scripts/luacats_parser.lua`). - Treesitter for Markdown parsing (see `scripts/text_utils.lua`). - The generated `runtime/doc/*.mpack` files have been removed. - `scripts/gen_eval_files.lua` now instead uses `scripts/cdoc_parser.lua` directly. - Text wrapping is implemented in `scripts/text_utils.lua` and appears to produce more consistent results (the main contributer to the diff of this change). --- runtime/lua/vim/lsp/util.lua | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'runtime/lua/vim/lsp/util.lua') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index b60135f851..e371cb0e15 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -574,6 +574,7 @@ end --- ---@param text_document_edit table: a `TextDocumentEdit` object ---@param index integer: Optional index of the edit, if from a list of edits (or nil, if not from a list) +---@param offset_encoding? string ---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocumentEdit function M.apply_text_document_edit(text_document_edit, index, offset_encoding) local text_document = text_document_edit.textDocument @@ -770,7 +771,7 @@ end --- ---@param workspace_edit table `WorkspaceEdit` ---@param offset_encoding string utf-8|utf-16|utf-32 (required) ---see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit +---@see https://microsoft.github.io/language-server-protocol/specifications/specification-current/#workspace_applyEdit function M.apply_workspace_edit(workspace_edit, offset_encoding) if offset_encoding == nil then vim.notify_once( @@ -1130,6 +1131,7 @@ end --- - for LocationLink, targetRange is shown (e.g., body of function definition) --- ---@param location table a single `Location` or `LocationLink` +---@param opts table ---@return integer|nil buffer id of float window ---@return integer|nil window id of float window function M.preview_location(location, opts) @@ -1243,6 +1245,7 @@ end --- --- If you want to open a popup with fancy markdown, use `open_floating_preview` instead --- +---@param bufnr integer ---@param contents table of lines to show in window ---@param opts table with optional fields --- - height of floating window @@ -1603,7 +1606,7 @@ end ---@param contents table of lines to show in window ---@param syntax string of syntax to set for opened buffer ---@param opts table with optional fields (additional keys are filtered with |vim.lsp.util.make_floating_popup_options()| ---- before they are passed on to |nvim_open_win()|) +--- before they are passed on to |nvim_open_win()|) --- - height: (integer) height of floating window --- - width: (integer) width of floating window --- - wrap: (boolean, default true) wrap long lines @@ -1868,6 +1871,7 @@ end --- Converts symbols to quickfix list items. --- ---@param symbols table DocumentSymbol[] or SymbolInformation[] +---@param bufnr integer function M.symbols_to_items(symbols, bufnr) local function _symbols_to_items(_symbols, _items, _bufnr) for _, symbol in ipairs(_symbols) do -- cgit From 63f9c2da9aab52fa698fcbfdbc58ffd41794d28a Mon Sep 17 00:00:00 2001 From: Maria José Solano Date: Mon, 26 Feb 2024 11:42:51 -0800 Subject: feat(lsp): support completion itemDefaults --- runtime/lua/vim/lsp/util.lua | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'runtime/lua/vim/lsp/util.lua') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index e371cb0e15..3973e606f8 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -551,6 +551,10 @@ end --- Can be used to extract the completion items from a --- `textDocument/completion` request, which may return one of --- `CompletionItem[]`, `CompletionList` or null. +--- +--- Note that this method doesn't apply `itemDefaults` to `CompletionList`s, and hence the returned +--- results might be incorrect. +--- ---@deprecated ---@param result table The result of a `textDocument/completion` request ---@return lsp.CompletionItem[] List of completion items -- cgit From 7311958e1238559db7a0b1f490f15f618f51af06 Mon Sep 17 00:00:00 2001 From: Jaehwang Jung Date: Thu, 29 Feb 2024 01:32:25 +0900 Subject: fix(lsp): remove unnecessary file load/write when renaming (#27621) Previously rename would unconditionally read the to-be-renamed file from the disk and write it to the disk. This is redundant in some cases If the file is not already loaded, it's not attached to lsp client, so nvim doesn't need to care about this file. If the file is loaded but has no change, it doesn't need to be written. --- runtime/lua/vim/lsp/util.lua | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'runtime/lua/vim/lsp/util.lua') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 3973e606f8..d2a5d9a08e 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -710,11 +710,12 @@ function M.rename(old_fname, new_fname, opts) end for _, b in ipairs(oldbufs) do - vim.fn.bufload(b) - -- The there may be pending changes in the buffer - api.nvim_buf_call(b, function() - vim.cmd('w!') - end) + -- There may be pending changes in the buffer + if api.nvim_buf_is_loaded(b) then + api.nvim_buf_call(b, function() + vim.cmd('update!') + end) + end end local newdir = assert(vim.fs.dirname(new_fname)) -- cgit From b413f5d048ab8676d5a77d0f2b3c20587a270673 Mon Sep 17 00:00:00 2001 From: Jaehwang Jung Date: Sat, 2 Mar 2024 02:31:54 +0900 Subject: fix(lsp): rename undofile when renaming (#27684) Problem: After `rename()`, the undo information for the renamed file(s) are lost. Solution: Rename the undofile as well. --- runtime/lua/vim/lsp/util.lua | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'runtime/lua/vim/lsp/util.lua') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index d2a5d9a08e..0553d39851 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -724,6 +724,13 @@ function M.rename(old_fname, new_fname, opts) local ok, err = os.rename(old_fname_full, new_fname) assert(ok, err) + local old_undofile = vim.fn.undofile(old_fname_full) + if uv.fs_stat(old_undofile) ~= nil then + local new_undofile = vim.fn.undofile(new_fname) + vim.fn.mkdir(assert(vim.fs.dirname(new_undofile)), 'p') + os.rename(old_undofile, new_undofile) + end + if vim.fn.isdirectory(new_fname) == 0 then local newbuf = vim.fn.bufadd(new_fname) if win then -- cgit From a5fe8f59d98398d04bed8586cee73864bbcdde92 Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Tue, 27 Feb 2024 15:20:32 +0000 Subject: docs: improve/add documentation of Lua types - Added `@inlinedoc` so single use Lua types can be inlined into the functions docs. E.g. ```lua --- @class myopts --- @inlinedoc --- --- Documentation for some field --- @field somefield integer --- @param opts myOpts function foo(opts) end ``` Will be rendered as ``` foo(opts) Parameters: - {opts} (table) Object with the fields: - somefield (integer) Documentation for some field ``` - Marked many classes with with `@nodoc` or `(private)`. We can eventually introduce these when we want to. --- runtime/lua/vim/lsp/util.lua | 91 +++++++++++++++++++++++++++++--------------- 1 file changed, 60 insertions(+), 31 deletions(-) (limited to 'runtime/lua/vim/lsp/util.lua') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 0553d39851..60d0f0cc83 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -675,13 +675,15 @@ local function get_bufs_with_prefix(prefix) return buffers end +--- @class vim.lsp.util.rename.Opts +--- @inlinedoc +--- @field overwrite? boolean +--- @field ignoreIfExists? boolean + --- Rename old_fname to new_fname ---- ----@param old_fname string ----@param new_fname string ----@param opts? table options ---- - overwrite? boolean ---- - ignoreIfExists? boolean +--- @param old_fname string +--- @param new_fname string +--- @param opts? vim.lsp.util.rename.Opts Options: function M.rename(old_fname, new_fname, opts) opts = opts or {} local skip = not opts.overwrite or opts.ignoreIfExists @@ -1450,7 +1452,7 @@ function M.stylize_markdown(bufnr, contents, opts) return stripped end ---- @class lsp.util.NormalizeMarkdownOptions +--- @class (private) vim.lsp.util._normalize_markdown.Opts --- @field width integer Thematic breaks are expanded to this size. Defaults to 80. --- Normalizes Markdown input to a canonical form. @@ -1466,7 +1468,7 @@ end --- ---@private ---@param contents string[] ----@param opts? lsp.util.NormalizeMarkdownOptions +---@param opts? vim.lsp.util._normalize_markdown.Opts ---@return string[] table of lines containing normalized Markdown ---@see https://github.github.com/gfm function M._normalize_markdown(contents, opts) @@ -1537,7 +1539,7 @@ local function close_preview_autocmd(events, winnr, bufnrs) end end ----@internal +---@private --- Computes size of float needed to show contents (with optional wrapping) --- ---@param contents table of lines to show in window @@ -1613,24 +1615,50 @@ function M._make_floating_popup_size(contents, opts) return width, height end +--- @class vim.lsp.util.open_floating_preview.Opts +--- @inlinedoc +--- +--- Height of floating window +--- @field height? integer +--- +--- Width of floating window +--- @field width? integer +--- +--- Wrap long lines +--- (default: `true`) +--- @field wrap? boolean +--- +--- Character to wrap at for computing height when wrap is enabled +--- @field wrap_at? integer +--- +--- Maximal width of floating window +--- @field max_width? integer +--- +--- Maximal height of floating window +--- @field max_height? integer +--- +--- If a popup with this id is opened, then focus it +--- @field focus_id? string +--- +--- List of events that closes the floating window +--- @field close_events? table +--- +--- Make float focusable. +--- (default: `true`) +--- @field focusable? boolean +--- +--- If `true`, and if {focusable} is also `true`, focus an existing floating +--- window with the same {focus_id} +--- (default: `true`) +--- @field focus? boolean + --- Shows contents in a floating window. --- ---@param contents table of lines to show in window ---@param syntax string of syntax to set for opened buffer ----@param opts table with optional fields (additional keys are filtered with |vim.lsp.util.make_floating_popup_options()| ---- before they are passed on to |nvim_open_win()|) ---- - height: (integer) height of floating window ---- - width: (integer) width of floating window ---- - wrap: (boolean, default true) wrap long lines ---- - wrap_at: (integer) character to wrap at for computing height when wrap is enabled ---- - max_width: (integer) maximal width of floating window ---- - max_height: (integer) maximal height of floating window ---- - focus_id: (string) if a popup with this id is opened, then focus it ---- - close_events: (table) list of events that closes the floating window ---- - focusable: (boolean, default true) Make float focusable ---- - focus: (boolean, default true) If `true`, and if {focusable} ---- is also `true`, focus an existing floating window with the same ---- {focus_id} +---@param opts? vim.lsp.util.open_floating_preview.Opts with optional fields +--- (additional keys are filtered with |vim.lsp.util.make_floating_popup_options()| +--- before they are passed on to |nvim_open_win()|) ---@return integer bufnr of newly created float window ---@return integer winid of newly created float window preview window function M.open_floating_preview(contents, syntax, opts) @@ -1794,7 +1822,8 @@ local position_sort = sort_by_key(function(v) return { v.start.line, v.start.character } end) ----@class vim.lsp.util.LocationItem +---@class vim.lsp.util.locations_to_items.ret +---@inlinedoc ---@field filename string ---@field lnum integer 1-indexed line number ---@field col integer 1-indexed column @@ -1813,7 +1842,7 @@ end) ---@param locations lsp.Location[]|lsp.LocationLink[] ---@param offset_encoding string offset_encoding for locations utf-8|utf-16|utf-32 --- default to first client of buffer ----@return vim.lsp.util.LocationItem[] list of items +---@return vim.lsp.util.locations_to_items.ret[] function M.locations_to_items(locations, offset_encoding) if offset_encoding == nil then vim.notify_once( @@ -2221,16 +2250,16 @@ local function make_line_range_params(bufnr, start_line, end_line, offset_encodi } end ----@private ---- Request updated LSP information for a buffer. ---- ----@class lsp.util.RefreshOptions +---@class (private) vim.lsp.util._refresh.Opts ---@field bufnr integer? Buffer to refresh (default: 0) ---@field only_visible? boolean Whether to only refresh for the visible regions of the buffer (default: false) ---@field client_id? integer Client ID to refresh (default: all clients) --- + +---@private +--- Request updated LSP information for a buffer. +--- ---@param method string LSP method to call ----@param opts? lsp.util.RefreshOptions Options table +---@param opts? vim.lsp.util._refresh.Opts Options table function M._refresh(method, opts) opts = opts or {} local bufnr = opts.bufnr -- cgit From dc8c086c7e73a9035c34be6416e7c465d61edc0e Mon Sep 17 00:00:00 2001 From: Jaehwang Jung Date: Sat, 2 Mar 2024 23:21:53 +0900 Subject: fix(lsp): directly rename the existing buffers when renaming (#27690) Problem: `vim.lsp.util.rename()` deletes the buffers that are affected by renaming. This has undesireable side effects. For example, when renaming a directory, all buffers under that directory are deleted and windows displaying those buffers are closed. Also, buffer options may change after renaming. Solution: Rename the buffers with :saveas. An alternative approach is to record all the relevant states and restore it after renaming, but that seems to be more complex. In fact, the older version was attempting to restore the states but only partially and incorrectly. --- runtime/lua/vim/lsp/util.lua | 78 ++++++++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 28 deletions(-) (limited to 'runtime/lua/vim/lsp/util.lua') diff --git a/runtime/lua/vim/lsp/util.lua b/runtime/lua/vim/lsp/util.lua index 60d0f0cc83..f8e5b6a90d 100644 --- a/runtime/lua/vim/lsp/util.lua +++ b/runtime/lua/vim/lsp/util.lua @@ -675,12 +675,23 @@ local function get_bufs_with_prefix(prefix) return buffers end +local function escape_gsub_repl(s) + return (s:gsub('%%', '%%%%')) +end + --- @class vim.lsp.util.rename.Opts --- @inlinedoc --- @field overwrite? boolean --- @field ignoreIfExists? boolean --- Rename old_fname to new_fname +--- +--- Existing buffers are renamed as well, while maintaining their bufnr. +--- +--- It deletes existing buffers that conflict with the renamed file name only when +--- * `opts` requests overwriting; or +--- * the conflicting buffers are not loaded, so that deleting thme does not result in data loss. +--- --- @param old_fname string --- @param new_fname string --- @param opts? vim.lsp.util.rename.Opts Options: @@ -700,24 +711,36 @@ function M.rename(old_fname, new_fname, opts) return end - local oldbufs = {} - local win = nil - - if vim.fn.isdirectory(old_fname_full) == 1 then - oldbufs = get_bufs_with_prefix(old_fname_full) - else - local oldbuf = vim.fn.bufadd(old_fname_full) - table.insert(oldbufs, oldbuf) - win = vim.fn.win_findbuf(oldbuf)[1] - end - - for _, b in ipairs(oldbufs) do - -- There may be pending changes in the buffer - if api.nvim_buf_is_loaded(b) then - api.nvim_buf_call(b, function() - vim.cmd('update!') - end) + local buf_rename = {} ---@type table + local old_fname_pat = '^' .. vim.pesc(old_fname_full) + for b in + vim.iter(get_bufs_with_prefix(old_fname_full)):filter(function(b) + -- No need to care about unloaded or nofile buffers. Also :saveas won't work for them. + return api.nvim_buf_is_loaded(b) + and not vim.list_contains({ 'nofile', 'nowrite' }, vim.bo[b].buftype) + end) + do + -- Renaming a buffer may conflict with another buffer that happens to have the same name. In + -- most cases, this would have been already detected by the file conflict check above, but the + -- conflicting buffer may not be associated with a file. For example, 'buftype' can be "nofile" + -- or "nowrite", or the buffer can be a normal buffer but has not been written to the file yet. + -- Renaming should fail in such cases to avoid losing the contents of the conflicting buffer. + local old_bname = vim.api.nvim_buf_get_name(b) + local new_bname = old_bname:gsub(old_fname_pat, escape_gsub_repl(new_fname)) + if vim.fn.bufexists(new_bname) == 1 then + local existing_buf = vim.fn.bufnr(new_bname) + if api.nvim_buf_is_loaded(existing_buf) and skip then + vim.notify( + new_bname .. ' already exists in the buffer list. Skipping rename.', + vim.log.levels.ERROR + ) + return + end + -- no need to preserve if such a buffer is empty + api.nvim_buf_delete(existing_buf, {}) end + + buf_rename[b] = { from = old_bname, to = new_bname } end local newdir = assert(vim.fs.dirname(new_fname)) @@ -733,17 +756,16 @@ function M.rename(old_fname, new_fname, opts) os.rename(old_undofile, new_undofile) end - if vim.fn.isdirectory(new_fname) == 0 then - local newbuf = vim.fn.bufadd(new_fname) - if win then - vim.fn.bufload(newbuf) - vim.bo[newbuf].buflisted = true - api.nvim_win_set_buf(win, newbuf) - end - end - - for _, b in ipairs(oldbufs) do - api.nvim_buf_delete(b, {}) + for b, rename in pairs(buf_rename) do + -- Rename with :saveas. This does two things: + -- * Unset BF_WRITE_MASK, so that users don't get E13 when they do :write. + -- * Send didClose and didOpen via textDocument/didSave handler. + api.nvim_buf_call(b, function() + vim.cmd('keepalt saveas! ' .. vim.fn.fnameescape(rename.to)) + end) + -- Delete the new buffer with the old name created by :saveas. nvim_buf_delete and + -- :bwipeout are futile because the buffer will be added again somewhere else. + vim.cmd('bdelete! ' .. vim.fn.bufnr(rename.from)) end end -- cgit