mirror of
https://github.com/stevearc/aerial.nvim
synced 2024-09-16 14:34:08 +02:00
feat: support for renaming symbols from aerial buffer
This commit is contained in:
parent
89a61daba8
commit
7349f37f9d
2 changed files with 160 additions and 0 deletions
|
@ -33,6 +33,7 @@ M.keys = {
|
|||
{ "}", "<cmd>AerialNext<CR>", "Jump to the next symbol" },
|
||||
{ "[[", "<cmd>AerialPrevUp<CR>", "Jump up the tree, moving backwards" },
|
||||
{ "]]", "<cmd>AerialNextUp<CR>", "Jump up the tree, moving forwards" },
|
||||
{ "r", "<cmd>lua require'aerial'.rename()<CR>", "Rename the current symbol" },
|
||||
{ "q", "<cmd>AerialClose<CR>", "Close the aerial window" },
|
||||
{
|
||||
{ "o", "za" },
|
||||
|
|
|
@ -326,6 +326,165 @@ M.was_closed = function(default)
|
|||
end
|
||||
end
|
||||
|
||||
local function lsp_rename(bufnr, position, new_name, options, callback)
|
||||
options = options or {}
|
||||
local clients = vim.lsp.get_active_clients({
|
||||
bufnr = bufnr,
|
||||
name = options.name,
|
||||
})
|
||||
if options.filter then
|
||||
clients = vim.tbl_filter(options.filter, clients)
|
||||
end
|
||||
|
||||
-- Clients must at least support rename, prepareRename is optional
|
||||
clients = vim.tbl_filter(function(client)
|
||||
return client.supports_method("textDocument/rename")
|
||||
end, clients)
|
||||
|
||||
if #clients == 0 then
|
||||
vim.notify("[LSP] Rename, no matching language servers with rename capability.")
|
||||
end
|
||||
|
||||
local cword
|
||||
local function get_cword()
|
||||
if not cword then
|
||||
local aerial_pos = vim.api.nvim_win_get_cursor(0)
|
||||
vim.api.nvim_buf_call(bufnr, function()
|
||||
local prev_pos = vim.api.nvim_win_get_cursor(0)
|
||||
vim.api.nvim_win_set_cursor(0, position)
|
||||
cword = vim.fn.expand("<cword>")
|
||||
vim.api.nvim_win_set_cursor(0, prev_pos)
|
||||
end)
|
||||
vim.api.nvim_win_set_cursor(0, aerial_pos)
|
||||
end
|
||||
return cword
|
||||
end
|
||||
|
||||
local function get_text_at_range(range, offset_encoding)
|
||||
return vim.api.nvim_buf_get_text(
|
||||
bufnr,
|
||||
range.start.line,
|
||||
util._get_line_byte_from_position(bufnr, range.start, offset_encoding),
|
||||
range["end"].line,
|
||||
util._get_line_byte_from_position(bufnr, range["end"], offset_encoding),
|
||||
{}
|
||||
)[1]
|
||||
end
|
||||
|
||||
local line = vim.api.nvim_buf_get_lines(bufnr, position[1] - 1, position[1], true)[1]
|
||||
if not line then
|
||||
error("Invalid buffer position")
|
||||
end
|
||||
local function make_position_params(offset_encoding)
|
||||
local col = vim.lsp.util._str_utfindex_enc(line, position[2], offset_encoding)
|
||||
return {
|
||||
textDocument = vim.lsp.util.make_text_document_params(bufnr),
|
||||
position = { line = position[1] - 1, character = col },
|
||||
}
|
||||
end
|
||||
|
||||
local try_use_client
|
||||
try_use_client = function(idx, client)
|
||||
if not client then
|
||||
callback()
|
||||
return
|
||||
end
|
||||
|
||||
local function rename(name)
|
||||
local params = make_position_params(client.offset_encoding)
|
||||
params.newName = name
|
||||
local handler = client.handlers["textDocument/rename"]
|
||||
or vim.lsp.handlers["textDocument/rename"]
|
||||
client.request("textDocument/rename", params, function(...)
|
||||
handler(...)
|
||||
try_use_client(next(clients, idx))
|
||||
end, bufnr)
|
||||
end
|
||||
|
||||
if client.supports_method("textDocument/prepareRename") then
|
||||
local params = make_position_params(client.offset_encoding)
|
||||
client.request("textDocument/prepareRename", params, function(err, result)
|
||||
if err or result == nil then
|
||||
if next(clients, idx) then
|
||||
try_use_client(next(clients, idx))
|
||||
else
|
||||
local msg = err and ("Error on prepareRename: " .. (err.message or ""))
|
||||
or "Nothing to rename"
|
||||
vim.notify(msg, vim.log.levels.INFO)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if new_name then
|
||||
rename(new_name)
|
||||
return
|
||||
end
|
||||
|
||||
local prompt_opts = {
|
||||
prompt = "New Name: ",
|
||||
}
|
||||
-- result: Range | { range: Range, placeholder: string }
|
||||
if result.placeholder then
|
||||
prompt_opts.default = result.placeholder
|
||||
elseif result.start then
|
||||
prompt_opts.default = get_text_at_range(result, client.offset_encoding)
|
||||
elseif result.range then
|
||||
prompt_opts.default = get_text_at_range(result.range, client.offset_encoding)
|
||||
else
|
||||
prompt_opts.default = cword
|
||||
end
|
||||
vim.ui.input(prompt_opts, function(input)
|
||||
if not input or #input == 0 then
|
||||
return
|
||||
end
|
||||
rename(input)
|
||||
end)
|
||||
end, bufnr)
|
||||
else
|
||||
assert(
|
||||
client.supports_method("textDocument/rename"),
|
||||
"Client must support textDocument/rename"
|
||||
)
|
||||
if new_name then
|
||||
rename(new_name)
|
||||
return
|
||||
end
|
||||
|
||||
local prompt_opts = {
|
||||
prompt = "New Name: ",
|
||||
default = get_cword(),
|
||||
}
|
||||
vim.ui.input(prompt_opts, function(input)
|
||||
if not input or #input == 0 then
|
||||
return
|
||||
end
|
||||
rename(input)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
try_use_client(next(clients))
|
||||
end
|
||||
|
||||
M.rename = function(new_name, options)
|
||||
if not util.is_aerial_buffer() then
|
||||
error("aerial.rename() must be called from inside the aerial buffer")
|
||||
end
|
||||
local bufnr = util.get_source_buffer()
|
||||
if not data:has_symbols(bufnr) then
|
||||
vim.notify("No symbols found", vim.log.levels.ERROR)
|
||||
return
|
||||
end
|
||||
local lnum = vim.api.nvim_win_get_cursor(0)[1]
|
||||
local item = data:get_or_create(bufnr):item(lnum)
|
||||
local lnum = item.selection_range and item.selection_range.lnum or item.lnum
|
||||
local col = item.selection_range and item.selection_range.col or item.col
|
||||
lsp_rename(bufnr, { lnum, col }, new_name, options, function()
|
||||
local backend = backends.get(bufnr)
|
||||
backend.fetch_symbols(bufnr)
|
||||
end)
|
||||
end
|
||||
|
||||
_G.aerial_foldexpr = fold.foldexpr
|
||||
|
||||
return M
|
||||
|
|
Loading…
Reference in a new issue