diff options
| author | Steven Sojka <Steven.Sojka@tdameritrade.com> | 2020-06-26 11:11:21 -0500 |
|---|---|---|
| committer | Kiyan Yazdani <yazdani.kiyan@protonmail.com> | 2020-06-30 08:21:01 +0200 |
| commit | 64838e51c0fcb9def4be912391a1544b4d9a9d27 (patch) | |
| tree | e2a66a26be775d27a74e916dabfc66664a99644b | |
| parent | feat(refactor): highlight usages module (diff) | |
| download | nvim-treesitter-64838e51c0fcb9def4be912391a1544b4d9a9d27.tar nvim-treesitter-64838e51c0fcb9def4be912391a1544b4d9a9d27.tar.gz nvim-treesitter-64838e51c0fcb9def4be912391a1544b4d9a9d27.tar.bz2 nvim-treesitter-64838e51c0fcb9def4be912391a1544b4d9a9d27.tar.lz nvim-treesitter-64838e51c0fcb9def4be912391a1544b4d9a9d27.tar.xz nvim-treesitter-64838e51c0fcb9def4be912391a1544b4d9a9d27.tar.zst nvim-treesitter-64838e51c0fcb9def4be912391a1544b4d9a9d27.zip | |
feat(refactor): add smart rename module
| -rw-r--r-- | lua/nvim-treesitter/configs.lua | 8 | ||||
| -rw-r--r-- | lua/nvim-treesitter/query.lua | 8 | ||||
| -rw-r--r-- | lua/nvim-treesitter/refactor/highlight_definitions.lua | 20 | ||||
| -rw-r--r-- | lua/nvim-treesitter/refactor/smart_rename.lua | 75 | ||||
| -rw-r--r-- | lua/nvim-treesitter/ts_utils.lua | 28 |
5 files changed, 115 insertions, 24 deletions
diff --git a/lua/nvim-treesitter/configs.lua b/lua/nvim-treesitter/configs.lua index 30c2114ce..595c2e759 100644 --- a/lua/nvim-treesitter/configs.lua +++ b/lua/nvim-treesitter/configs.lua @@ -31,6 +31,14 @@ local config = { enable = false, disable = {}, is_supported = queries.has_locals + }, + smart_rename = { + enable = false, + disable = {}, + is_supported = queries.has_locals, + keymaps = { + smart_rename = "grr" + } } } }, diff --git a/lua/nvim-treesitter/query.lua b/lua/nvim-treesitter/query.lua index d04e368a6..6c76fc237 100644 --- a/lua/nvim-treesitter/query.lua +++ b/lua/nvim-treesitter/query.lua @@ -13,7 +13,9 @@ local function read_query_files(filenames) return table.concat(contents, '\n') end -local function get_query_gaurd(query) +-- Creates a function that checks whether a certain query exists +-- for a specific language. +local function get_query_guard(query) return function(lang) return M.get_query(lang, query) ~= nil end @@ -27,8 +29,8 @@ M.base_language_map = { tsx = {'typescript', 'javascript'}, } -M.has_locals = get_query_gaurd('locals') -M.has_highlights = get_query_gaurd('highlights') +M.has_locals = get_query_guard('locals') +M.has_highlights = get_query_guard('highlights') function M.get_query(lang, query_name) local query_files = api.nvim_get_runtime_file(string.format('queries/%s/%s.scm', lang, query_name), true) diff --git a/lua/nvim-treesitter/refactor/highlight_definitions.lua b/lua/nvim-treesitter/refactor/highlight_definitions.lua index ef415bb77..6279e4708 100644 --- a/lua/nvim-treesitter/refactor/highlight_definitions.lua +++ b/lua/nvim-treesitter/refactor/highlight_definitions.lua @@ -11,24 +11,6 @@ local M = {} local usage_namespace = api.nvim_create_namespace('nvim-treesitter-usages') -local function find_usages(node, scope_node) - local usages = {} - local node_text = ts_utils.get_node_text(node)[1] - - if not node_text or #node_text < 1 then return end - - for _, def in ipairs(locals.collect_locals(bufnr, scope_node)) do - if def.reference - and def.reference.node - and ts_utils.get_node_text(def.reference.node)[1] == node_text then - - table.insert(usages, def.reference.node) - end - end - - return usages -end - function M.highlight_usages(bufnr) M.clear_usage_highlights(bufnr) @@ -37,7 +19,7 @@ function M.highlight_usages(bufnr) if not node_at_point then return end local def_node, scope = ts_utils.find_definition(node_at_point, bufnr) - local usages = find_usages(node_at_point, scope) + local usages = ts_utils.find_usages(node_at_point, scope) for _, usage_node in ipairs(usages) do local start_row, start_col, _, end_col = usage_node:range() diff --git a/lua/nvim-treesitter/refactor/smart_rename.lua b/lua/nvim-treesitter/refactor/smart_rename.lua new file mode 100644 index 000000000..5b7562eb4 --- /dev/null +++ b/lua/nvim-treesitter/refactor/smart_rename.lua @@ -0,0 +1,75 @@ +-- Binds a keybinding to smart rename definitions and usages. +-- Can be used directly using the `smart_rename` function. + +local ts_utils = require'nvim-treesitter.ts_utils' +local configs = require'nvim-treesitter.configs' +local api = vim.api + +local M = {} + +function M.smart_rename(bufnr) + local bufnr = bufnr or api.nvim_get_current_buf() + local node_at_point = ts_utils.get_node_at_cursor() + + if not node_at_point then + print('No node to rename!') + return + end + + local node_text = ts_utils.get_node_text(node_at_point)[1] + local new_name = vim.fn.input('New name: ', node_text or '') + + -- Empty name cancels the interaction or ESC + if not new_name or #new_name < 1 then return end + + local definition, scope = ts_utils.find_definition(node_at_point, bufnr) + local nodes_to_rename = ts_utils.find_usages(node_at_point, scope) + + if not vim.tbl_contains(nodes_to_rename, node_at_point) then + table.insert(nodes_to_rename, node_at_point) + end + + if definition and not vim.tbl_contains(nodes_to_rename, definition) then + table.insert(nodes_to_rename, definition) + end + + if #nodes_to_rename < 1 then + print('No nodes to rename!') + return + end + + for _, node in ipairs(nodes_to_rename) do + local start_row, start_col, end_row, end_col = node:range() + + local line = api.nvim_buf_get_lines(bufnr, start_row, start_row + 1, false)[1] + + if line then + local new_line = line:sub(1, start_col) .. new_name .. line:sub(end_col + 1, -1) + + api.nvim_buf_set_lines(bufnr, start_row, start_row + 1, false, { new_line }) + end + end +end + +function M.attach(bufnr) + local bufnr = bufnr or api.nvim_get_current_buf() + + local config = configs.get_module('refactor.smart_rename') + + for fn_name, mapping in pairs(config.keymaps) do + local cmd = string.format([[:lua require'nvim-treesitter.refactor.smart_rename'.%s(%d)<CR>]], fn_name, bufnr) + + api.nvim_buf_set_keymap(bufnr, 'n', mapping, cmd, { silent = true }) + end +end + +function M.detach(bufnr) + local buf = bufnr or api.nvim_get_current_buf() + local config = configs.get_module('refactor.smart_rename') + + for fn_name, mapping in pairs(config.keymaps) do + api.nvim_buf_del_keymap(bufnr, 'n', mapping) + end +end + +return M diff --git a/lua/nvim-treesitter/ts_utils.lua b/lua/nvim-treesitter/ts_utils.lua index 363d26374..90dc3d262 100644 --- a/lua/nvim-treesitter/ts_utils.lua +++ b/lua/nvim-treesitter/ts_utils.lua @@ -15,14 +15,16 @@ function M.get_node_text(node, bufnr) -- We have to remember that end_col is end-exclusive local start_row, start_col, end_row, end_col = node:range() + if start_row ~= end_row then local lines = api.nvim_buf_get_lines(bufnr, start_row, end_row+1, false) lines[1] = string.sub(lines[1], start_col+1) lines[#lines] = string.sub(lines[#lines], 1, end_col) return lines else - local line = api.nvim_buf_get_lines(bufnr, start_row, start_row+1, true)[1] - return { string.sub(line, start_col+1, end_col) } + local line = api.nvim_buf_get_lines(bufnr, start_row, start_row+1, false)[1] + -- If line is nil then the line is empty + return line and { string.sub(line, start_col+1, end_col) } or {} end end @@ -263,4 +265,26 @@ function M.get_local_nodes(local_def) end end +-- Finds usages of a node in a particula scope +-- @param node the node to find usages for +-- @param scope_node the node to look within +-- @returns a list of nodes +function M.find_usages(node, scope_node) + local usages = {} + local node_text = M.get_node_text(node)[1] + + if not node_text or #node_text < 1 then return {} end + + for _, def in ipairs(locals.collect_locals(bufnr, scope_node)) do + if def.reference + and def.reference.node + and M.get_node_text(def.reference.node)[1] == node_text then + + table.insert(usages, def.reference.node) + end + end + + return usages +end + return M |
