diff --git a/lua/LspUI/rename/init.lua b/lua/LspUI/rename/init.lua index f0ffa1b..b15e3ad 100644 --- a/lua/LspUI/rename/init.lua +++ b/lua/LspUI/rename/init.lua @@ -59,7 +59,7 @@ M.run = function() local old_name = fn.expand("") - util.render(clients, current_buffer, current_win, old_name --[[@as string]]) + util.done(clients, current_buffer, current_win, old_name) end return M diff --git a/lua/LspUI/rename/util.lua b/lua/LspUI/rename/util.lua index 833fdf2..ac6b03a 100644 --- a/lua/LspUI/rename/util.lua +++ b/lua/LspUI/rename/util.lua @@ -34,7 +34,7 @@ end --- @param buffer_id integer buffer id --- @param position_param lsp.RenameParams this param must be generated by `vim.lsp.util.make_position_params`, has newname attribute --- @param callback function -M.rename = function(client, buffer_id, position_param, callback) +local function rename(client, buffer_id, position_param, callback) local handler = client.handlers[rename_feature] or lsp.handlers[rename_feature] vim.schedule(function() @@ -51,7 +51,7 @@ end --- @param buffer_id integer buffer id --- @param position_param lsp.PrepareRenameParams this param must be generated by `vim.lsp.util.make_position_params` --- @param callback fun(result:LspUI_prepare_rename_res?) -M.prepare_rename = function(client, buffer_id, position_param, callback) +local function prepare_rename(client, buffer_id, position_param, callback) local function __tmp() client.request( prepare_rename_feature, @@ -63,7 +63,6 @@ M.prepare_rename = function(client, buffer_id, position_param, callback) lib_notify.Error( "error code:" .. err.code .. ", " .. err.message ) - return end --- @type LspUI_prepare_rename_res @@ -80,42 +79,79 @@ M.prepare_rename = function(client, buffer_id, position_param, callback) vim.schedule(__tmp) end +--- @param id integer +--- @param clients vim.lsp.Client[] lsp client instance, must be element of func `get_clients` +--- @param buffer_id integer buffer id +--- @param position_param lsp.PrepareRenameParams|lsp.RenameParams this param must be generated by `vim.lsp.util.make_position_params`, has newname attribute +--- @param callback fun(clients: vim.lsp.Client[]) +--- @param final_clients vim.lsp.Client[] +local function if_rename( + id, + clients, + buffer_id, + position_param, + callback, + final_clients +) + --- @param __final_clients vim.lsp.Client[] + local function __next_rename(__final_clients) + local next_id, _ = next(clients, id) + if_rename( + next_id, + clients, + buffer_id, + position_param, + callback, + __final_clients + ) + end + + if not id then + callback(final_clients) + return + end + + local client = clients[id] + + if client.supports_method(prepare_rename_feature) then + prepare_rename( + client, + buffer_id, + --- @cast position_param lsp.PrepareRenameParams + position_param, + -- we no need to resuse the result, we just use it todetect whether we can do rename + function(result) + if result then + table.insert(final_clients, client) + end + __next_rename(final_clients) + end + ) + return + end + table.insert(final_clients, client) + __next_rename(final_clients) +end + -- do rename, a wrap function for prepare_rename and rename --- @param id integer --- @param clients vim.lsp.Client[] lsp client instance, must be element of func `get_clients` --- @param buffer_id integer buffer id --- @param position_param lsp.PrepareRenameParams|lsp.RenameParams this param must be generated by `vim.lsp.util.make_position_params`, has newname attribute -M.do_rename = function(id, clients, buffer_id, position_param) +local function do_rename(id, clients, buffer_id, position_param) local function next_rename() local next_id, _ = next(clients, id) - M.do_rename(next_id, clients, buffer_id, position_param) + do_rename(next_id, clients, buffer_id, position_param) end local async = uv.new_async(function() - local client = clients[id] - if not client then + if not id then return end - if client.supports_method(prepare_rename_feature) then - M.prepare_rename( - client, - buffer_id, - --- @cast position_param lsp.PrepareRenameParams - position_param, - -- we no need to resuse the result, we just use it todetect whether we can do rename - function(result) - if not result then - next_rename() - return - end - --- @cast position_param lsp.RenameParams - M.rename(client, buffer_id, position_param, next_rename) - end - ) - else - --- @cast position_param lsp.RenameParams - M.rename(client, buffer_id, position_param, next_rename) - end + + local client = clients[id] + --- @cast position_param lsp.RenameParams + rename(client, buffer_id, position_param, next_rename) end) if async then @@ -137,81 +173,11 @@ end -- calculate display length --- @param str string -local calculate_length = function(str) +local function calculate_length(str) local len = fn.strdisplaywidth(str) + 2 return len > 10 and len or 10 end --- render the window ---- @param clients vim.lsp.Client[] ---- @param buffer_id integer ---- @param current_win integer ---- @param old_name string -M.render = function(clients, buffer_id, current_win, old_name) - local position_param = lsp.util.make_position_params(current_win) - - -- Here we need to define window - - local new_buffer = api.nvim_create_buf(false, true) - - -- note: this must set before modifiable, when modifiable is false, this function will fail - api.nvim_buf_set_lines(new_buffer, 0, -1, false, { - --- @cast old_name string - old_name, - }) - - api.nvim_set_option_value("filetype", "LspUI-rename", { buf = new_buffer }) - api.nvim_set_option_value("modifiable", true, { buf = new_buffer }) - api.nvim_set_option_value("bufhidden", "wipe", { buf = new_buffer }) - - local new_window_wrap = lib_windows.new_window(new_buffer) - - -- For aesthetics, the minimum width is 8 - local width = calculate_length(old_name) - - lib_windows.set_width_window(new_window_wrap, width) - lib_windows.set_height_window(new_window_wrap, 1) - lib_windows.set_enter_window(new_window_wrap, true) - lib_windows.set_anchor_window(new_window_wrap, "NW") - lib_windows.set_border_window(new_window_wrap, "rounded") - lib_windows.set_focusable_window(new_window_wrap, true) - lib_windows.set_relative_window(new_window_wrap, "cursor") - lib_windows.set_col_window(new_window_wrap, 1) - lib_windows.set_row_window(new_window_wrap, 1) - lib_windows.set_style_window(new_window_wrap, "minimal") - lib_windows.set_right_title_window(new_window_wrap, "rename") - - local window_id = lib_windows.display_window(new_window_wrap) - - api.nvim_set_option_value("winhighlight", "Normal:Normal", { - win = window_id, - }) - api.nvim_set_option_value("winblend", config.options.rename.transparency, { - win = window_id, - }) - - if config.options.rename.auto_select then - api.nvim_win_call(window_id, function() - vim.cmd([[normal! V]]) - api.nvim_feedkeys( - api.nvim_replace_termcodes("", true, true, true), - "n", - true - ) - end) - end - - -- keybinding and autocommand - M.keybinding_autocmd( - window_id, - old_name, - clients, - buffer_id, - new_buffer, - position_param - ) -end - -- keybinding and autocommand --- @param window_id integer rename float window's id --- @param old_name string the word's old name @@ -219,7 +185,7 @@ end --- @param old_buffer integer the buffer which word belongs to --- @param new_buffer integer the buffer which attach to rename float window --- @param position_param lsp.PrepareRenameParams|lsp.RenameParams this param must be generated by `vim.lsp.util.make_position_params` -M.keybinding_autocmd = function( +local function keybinding_autocmd( window_id, old_name, clients, @@ -241,7 +207,7 @@ M.keybinding_autocmd = function( local new_name = vim.trim(api.nvim_get_current_line()) if old_name ~= new_name then position_param.newName = new_name - M.do_rename(1, clients, old_buffer, position_param) + do_rename(1, clients, old_buffer, position_param) end close_window(window_id) end, @@ -300,4 +266,86 @@ M.keybinding_autocmd = function( }) end +-- render the window +--- @param clients vim.lsp.Client[] +--- @param buffer_id integer +--- @param old_name string +--- @param position_param lsp.PrepareRenameParams|lsp.RenameParams this param must be generated by `vim.lsp.util.make_position_params` +local function render(clients, buffer_id, old_name, position_param) + local new_buffer = api.nvim_create_buf(false, true) + + -- note: this must set before modifiable, when modifiable is false, this function will fail + api.nvim_buf_set_lines(new_buffer, 0, -1, false, { + --- @cast old_name string + old_name, + }) + + api.nvim_set_option_value("filetype", "LspUI-rename", { buf = new_buffer }) + api.nvim_set_option_value("modifiable", true, { buf = new_buffer }) + api.nvim_set_option_value("bufhidden", "wipe", { buf = new_buffer }) + + local new_window_wrap = lib_windows.new_window(new_buffer) + + -- For aesthetics, the minimum width is 8 + local width = calculate_length(old_name) + + lib_windows.set_width_window(new_window_wrap, width) + lib_windows.set_height_window(new_window_wrap, 1) + lib_windows.set_enter_window(new_window_wrap, true) + lib_windows.set_anchor_window(new_window_wrap, "NW") + lib_windows.set_border_window(new_window_wrap, "rounded") + lib_windows.set_focusable_window(new_window_wrap, true) + lib_windows.set_relative_window(new_window_wrap, "cursor") + lib_windows.set_col_window(new_window_wrap, 1) + lib_windows.set_row_window(new_window_wrap, 1) + lib_windows.set_style_window(new_window_wrap, "minimal") + lib_windows.set_right_title_window(new_window_wrap, "rename") + + local window_id = lib_windows.display_window(new_window_wrap) + + api.nvim_set_option_value("winhighlight", "Normal:Normal", { + win = window_id, + }) + api.nvim_set_option_value("winblend", config.options.rename.transparency, { + win = window_id, + }) + + if config.options.rename.auto_select then + api.nvim_win_call(window_id, function() + vim.cmd([[normal! V]]) + api.nvim_feedkeys( + api.nvim_replace_termcodes("", true, true, true), + "n", + true + ) + end) + end + + -- keybinding and autocommand + keybinding_autocmd( + window_id, + old_name, + clients, + buffer_id, + new_buffer, + position_param + ) +end + +-- render the window +--- @param clients vim.lsp.Client[] +--- @param buffer_id integer +--- @param current_win integer +--- @param old_name string +M.done = function(clients, buffer_id, current_win, old_name) + local position_param = lsp.util.make_position_params(current_win) + if_rename(1, clients, buffer_id, position_param, function(__clients) + if #__clients < 1 then + lib_notify.Info("This position can not rename!") + return + end + render(__clients, buffer_id, old_name, position_param) + end, {}) +end + return M