refactor(refactor): use higher local apis and some cleanup

This commit is contained in:
Steven Sojka 2020-06-29 09:58:51 -05:00 committed by Kiyan Yazdani
parent 6f8e4c97a4
commit d73500eaa6
10 changed files with 103 additions and 69 deletions

View file

@ -102,9 +102,23 @@ require'nvim-treesitter.configs'.setup {
init_selection = 'gnn', -- maps in normal mode to init the node/scope selection init_selection = 'gnn', -- maps in normal mode to init the node/scope selection
node_incremental = "grn", -- increment to the upper named parent node_incremental = "grn", -- increment to the upper named parent
scope_incremental = "grc", -- increment to the upper scope (as defined in locals.scm) scope_incremental = "grc", -- increment to the upper scope (as defined in locals.scm)
node_decremental = "grm", -- decrement to the previous node node_decremental = "grm", -- decrement to the previous node
} }
}, },
refactor = {
highlight_defintions = {
enable = true
},
smart_rename = {
enable = true,
smart_rename = "grr" -- mapping to rename reference under cursor
},
navigation = {
enable = true,
goto_definition = "gnd", -- mapping to go to definition of symbol under cursor
list_definitions = "gnD" -- mapping to list all definitions in current file
}
},
ensure_installed = 'all' -- one of 'all', 'language', or a list of languages ensure_installed = 'all' -- one of 'all', 'language', or a list of languages
} }
EOF EOF
@ -134,6 +148,16 @@ Some of these features are :
You can find the roadmap [here](https://github.com/nvim-treesitter/nvim-treesitter/projects/1). You can find the roadmap [here](https://github.com/nvim-treesitter/nvim-treesitter/projects/1).
The roadmap and all features of this plugin are open to change, and any suggestion will be highly appreciated! The roadmap and all features of this plugin are open to change, and any suggestion will be highly appreciated!
## Available Modules
- `highlight`: Consistent syntax highlighting.
- `incremental_selection`: Syntax based selection.
- `refactor.highlight_definitions`: Syntax based definition and usage highlighting.
- `refactor.smart_rename`: Syntax based definition and usage renaming.
- `refactor.navigation`: Syntax based definition listing and navigation.
* List all definitions
* Go to definition
## Utils ## Utils
you can get some utility functions with you can get some utility functions with

View file

@ -237,21 +237,19 @@ end
function M.setup(user_data) function M.setup(user_data)
if not user_data then return end if not user_data then return end
for mod, data in pairs(user_data) do M.setup_module(config.modules, user_data)
if config.modules[mod] then
M.setup_module(config.modules[mod], data)
elseif mod == 'ensure_installed' then
config.ensure_installed = data
require'nvim-treesitter.install'.ensure_installed(data)
end
end
end end
--- Sets up a single module or all submodules of a group -- Sets up a single module or all submodules of a group.
-- Note, this method is recursive.
-- @param mod the module or group of modules -- @param mod the module or group of modules
-- @param data user defined configuration for the module -- @param data user defined configuration for the module
function M.setup_module(mod, data) -- @param mod_name name of the module if it exists
if M.is_module(mod) then function M.setup_module(mod, data, mod_name)
if mod_name == 'ensure_installed' then
config.ensure_installed = data
require'nvim-treesitter.install'.ensure_installed(data)
elseif M.is_module(mod) then
if type(data.enable) == 'boolean' then if type(data.enable) == 'boolean' then
mod.enable = data.enable mod.enable = data.enable
end end
@ -267,7 +265,7 @@ function M.setup_module(mod, data)
end end
elseif type(data) == 'table' and type(mod) == 'table' then elseif type(data) == 'table' and type(mod) == 'table' then
for key, value in pairs(data) do for key, value in pairs(data) do
M.setup_module(mod[key], value) M.setup_module(mod[key], value, key)
end end
end end
end end

View file

@ -11,7 +11,7 @@ local M = {
locals = {} locals = {}
} }
function M.collect_locals(bufnr, root) function M.collect_locals(bufnr)
local lang = parsers.ft_to_lang(api.nvim_buf_get_option(bufnr, "ft")) local lang = parsers.ft_to_lang(api.nvim_buf_get_option(bufnr, "ft"))
if not lang then return end if not lang then return end
@ -21,7 +21,7 @@ function M.collect_locals(bufnr, root)
local parser = parsers.get_parser(bufnr, lang) local parser = parsers.get_parser(bufnr, lang)
if not parser then return end if not parser then return end
local root = root or parser:parse():root() local root = parser:parse():root()
local start_row, _, end_row, _ = root:range() local start_row, _, end_row, _ = root:range()
local locals = {} local locals = {}

View file

@ -15,8 +15,11 @@ function M.highlight_usages(bufnr)
M.clear_usage_highlights(bufnr) M.clear_usage_highlights(bufnr)
local node_at_point = ts_utils.get_node_at_cursor() local node_at_point = ts_utils.get_node_at_cursor()
local references = locals.get_references(bufnr)
if not node_at_point then return end if not node_at_point or not vim.tbl_contains(references, node_at_point) then
return
end
local def_node, scope = ts_utils.find_definition(node_at_point, bufnr) local def_node, scope = ts_utils.find_definition(node_at_point, bufnr)
local usages = ts_utils.find_usages(node_at_point, scope) local usages = ts_utils.find_usages(node_at_point, scope)
@ -28,25 +31,23 @@ function M.highlight_usages(bufnr)
api.nvim_buf_add_highlight( api.nvim_buf_add_highlight(
bufnr, bufnr,
usage_namespace, usage_namespace,
'Visual', 'TSDefinitionUsage',
start_row, start_row,
start_col, start_col,
end_col) end_col)
end end
end end
if def_node then if def_node ~= node_at_point then
local start_row, start_col, _, end_col = def_node:range() local start_row, start_col, _, end_col = def_node:range()
if def_node ~= node_at_point then api.nvim_buf_add_highlight(
api.nvim_buf_add_highlight( bufnr,
bufnr, usage_namespace,
usage_namespace, 'TSDefinition',
'Search', start_row,
start_row, start_col,
start_col, end_col)
end_col)
end
end end
end end

View file

@ -26,12 +26,6 @@ function M.goto_definition(bufnr)
if not node_at_point then return end if not node_at_point then return end
local definition, _ = ts_utils.find_definition(node_at_point, bufnr) local definition, _ = ts_utils.find_definition(node_at_point, bufnr)
if not definition then
print('No definition found')
return
end
local start_row, start_col, _ = definition:start() local start_row, start_col, _ = definition:start()
api.nvim_win_set_cursor(0, { start_row + 1, start_col }) api.nvim_win_set_cursor(0, { start_row + 1, start_col })

View file

@ -3,6 +3,7 @@
local ts_utils = require'nvim-treesitter.ts_utils' local ts_utils = require'nvim-treesitter.ts_utils'
local configs = require'nvim-treesitter.configs' local configs = require'nvim-treesitter.configs'
local utils = require'nvim-treesitter.utils'
local api = vim.api local api = vim.api
local M = {} local M = {}
@ -12,7 +13,7 @@ function M.smart_rename(bufnr)
local node_at_point = ts_utils.get_node_at_cursor() local node_at_point = ts_utils.get_node_at_cursor()
if not node_at_point then if not node_at_point then
print('No node to rename!') utils.print_warning("No node to rename!")
return return
end end
@ -29,23 +30,16 @@ function M.smart_rename(bufnr)
table.insert(nodes_to_rename, node_at_point) table.insert(nodes_to_rename, node_at_point)
end end
if definition and not vim.tbl_contains(nodes_to_rename, definition) then if not vim.tbl_contains(nodes_to_rename, definition) then
table.insert(nodes_to_rename, definition) table.insert(nodes_to_rename, definition)
end end
if #nodes_to_rename < 1 then
print('No nodes to rename!')
return
end
for _, node in ipairs(nodes_to_rename) do for _, node in ipairs(nodes_to_rename) do
local start_row, start_col, end_row, end_col = node:range() 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] local line = api.nvim_buf_get_lines(bufnr, start_row, start_row + 1, false)[1]
if line then if line then
local new_line = line:sub(1, start_col) .. new_name .. line:sub(end_col + 1, -1) 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 }) api.nvim_buf_set_lines(bufnr, start_row, start_row + 1, false, { new_line })
end end
end end
@ -53,12 +47,10 @@ end
function M.attach(bufnr) function M.attach(bufnr)
local bufnr = bufnr or api.nvim_get_current_buf() local bufnr = bufnr or api.nvim_get_current_buf()
local config = configs.get_module('refactor.smart_rename') local config = configs.get_module('refactor.smart_rename')
for fn_name, mapping in pairs(config.keymaps) do 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) 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 }) api.nvim_buf_set_keymap(bufnr, 'n', mapping, cmd, { silent = true })
end end
end end

View file

@ -223,29 +223,33 @@ function M.find_definition(node, bufnr)
local node_text = M.get_node_text(node)[1] local node_text = M.get_node_text(node)[1]
local current_scope = M.containing_scope(node) local current_scope = M.containing_scope(node)
local _, _, node_start = node:start() local _, _, node_start = node:start()
local matching_def_nodes = {}
-- If a scope wasn't found then use the root node -- If a scope wasn't found then use the root node
if current_scope == node then if current_scope == node then
current_scope = parsers.get_parser(bufnr).tree:root() current_scope = parsers.get_parser(bufnr).tree:root()
end end
while current_scope ~= nil and current_scope ~= node do
for _, def in ipairs(locals.collect_locals(bufnr, current_scope)) do
if def.definition then
for _, def_node in ipairs(M.get_local_nodes(def.definition)) do
local _, _, def_start = def_node:start()
if M.get_node_text(def_node)[1] == node_text and def_start < node_start then -- Get all definitions that match the node text
return def_node, current_scope for _, def in ipairs(locals.get_definitions(bufnr)) do
end for _, def_node in ipairs(M.get_local_nodes(def)) do
end if M.get_node_text(def_node)[1] == node_text then
table.insert(matching_def_nodes, def_node)
end end
end end
end
-- Continue up each scope until we find the scope that contains the definition
while current_scope do
for _, def_node in ipairs(matching_def_nodes) do
if M.is_parent(current_scope, def_node) then
return def_node, current_scope
end
end
current_scope = M.containing_scope(current_scope:parent()) current_scope = M.containing_scope(current_scope:parent())
end end
return nil, nil return node, parsers.get_parser(bufnr).tree:root()
end end
-- Gets all nodes from a local list result. -- Gets all nodes from a local list result.
@ -285,26 +289,41 @@ function M.recurse_local_nodes(local_def, accumulator, full_match, last_match)
end end
end end
-- Finds usages of a node in a particula scope -- Finds usages of a node in a given scope
-- @param node the node to find usages for -- @param node the node to find usages for
-- @param scope_node the node to look within -- @param scope_node the node to look within
-- @returns a list of nodes -- @returns a list of nodes
function M.find_usages(node, scope_node) function M.find_usages(node, scope_node, bufnr)
local usages = {} local bufnr = bufnr or api.nvim_get_current_buf()
local node_text = M.get_node_text(node)[1] local node_text = M.get_node_text(node)[1]
if not node_text or #node_text < 1 then return {} end if not node_text or #node_text < 1 then return {} end
for _, def in ipairs(locals.collect_locals(bufnr, scope_node)) do local scope_node = scope_node or parsers.get_parser(bufnr).tree:root()
if def.reference local references = locals.get_references(bufnr)
and def.reference.node local usages = {}
and M.get_node_text(def.reference.node)[1] == node_text then
M.recurse_tree(scope_node, function(iter_node, _, next)
table.insert(usages, def.reference.node) if vim.tbl_contains(references, iter_node) and M.get_node_text(iter_node)[1] == node_text then
table.insert(usages, iter_node)
end end
end next()
end)
return usages return usages
end end
-- Recurses all child nodes of a tree.
-- The callback is provided the child node, parent_node, and a callback to recurse into
-- the child node. This allows for the ability to short circuit the recursion
-- if we found what we are looking for, we can then stop the recursion or skip a node
-- if need be.
-- @param tree the node root
-- @param cb the callback for each node
function M.recurse_tree(tree, cb)
for _, child in ipairs(M.get_named_children(tree)) do
cb(child, tree, function(next_node) M.recurse_tree(next_node or child, cb) end)
end
end
return M return M

View file

@ -45,7 +45,7 @@ function M.get_cache_dir()
return nil, 'Invalid cache rights, $XDG_CACHE_HOME or /tmp should be read/write' return nil, 'Invalid cache rights, $XDG_CACHE_HOME or /tmp should be read/write'
end end
--- Gets a property at path -- Gets a property at path
-- @param tbl the table to access -- @param tbl the table to access
-- @param path the '.' seperated path -- @param path the '.' seperated path
-- @returns the value at path or nil -- @returns the value at path or nil
@ -62,4 +62,10 @@ function M.get_at_path(tbl, path)
return result return result
end end
-- Prints a warning message
-- @param text the text message
function M.print_warning(text)
api.nvim_command(string.format([[echohl WarningMsg | echo "%s" | echohl None]], text))
end
return M return M

View file

@ -57,3 +57,6 @@ highlight default link TSTypeBuiltin Type
highlight default link TSStructure Structure highlight default link TSStructure Structure
highlight default link TSInclude Include highlight default link TSInclude Include
highlight default link TSDefinitionUsage Visual
highlight default link TSDefinition Search

View file

@ -28,9 +28,6 @@
(variable_declarator (variable_declarator
name: (identifier) @definition) name: (identifier) @definition)
(import_specifier
(identifier) @definition)
; References ; References
;------------ ;------------