Merge pull request #37 from theHamsta/node-movement

Add 'nvim-treesitter/node-movement'
This commit is contained in:
Thomas Vigouroux 2020-05-03 11:19:28 +02:00 committed by GitHub
commit 5cc7407c7f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 196 additions and 14 deletions

View file

@ -92,7 +92,7 @@ require'nvim-treesitter.configs'.setup {
enable = true, -- false will disable the whole extension enable = true, -- false will disable the whole extension
disable = { 'c', 'rust' }, -- list of language that will be disabled disable = { 'c', 'rust' }, -- list of language that will be disabled
}, },
textobj = { -- this enables incremental selection incremental_selection = { -- this enables incremental selection
enable = true, enable = true,
disable = { 'cpp', 'lua' }, disable = { 'cpp', 'lua' },
keymaps = { -- mappings for incremental selection (visual mappings) keymaps = { -- mappings for incremental selection (visual mappings)
@ -100,6 +100,16 @@ require'nvim-treesitter.configs'.setup {
scope_incremental = "<leader>f" -- "grc" by default scope_incremental = "<leader>f" -- "grc" by default
} }
}, },
node_movement = { -- this cursor movement in node hierachy
enable = true,
disable = { 'cpp', 'rust' },
keymaps = { -- mappings for node movement (normal mappings)
move_up = "<a-k>", -- default is to move with alt key hold
move_down = "<a-j>",
move_left = "<a-h>",
move_right = "<a-l>",
}
},
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
@ -124,6 +134,7 @@ Some of these features are :
- [x] Incremental selection - [x] Incremental selection
- [ ] Syntax based code folding - [ ] Syntax based code folding
- [x] Consistent syntax highlighting (the api is not quite stable yet) - [x] Consistent syntax highlighting (the api is not quite stable yet)
- [x] Cursor movement in node hierachy
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!

View file

@ -30,19 +30,29 @@ By default, everything is disabled. To enable support for features, in your `ini
> >
lua <<EOF lua <<EOF
require'nvim-treesitter.configs'.setup { require'nvim-treesitter.configs'.setup {
highlight = { highlight = {
enable = true, -- false will disable the whole extension enable = true, -- false will disable the whole extension
disable = { 'c', 'rust' }, -- list of language that will be disabled disable = { 'c', 'rust' }, -- list of language that will be disabled
}, },
textobj = { -- this enables incremental selection incremental_selection = { -- this enables incremental selection
enable = true, enable = true,
disable = { 'cpp', 'lua' }, disable = { 'cpp', 'lua' },
keymaps = { -- mappings for visual selection keymaps = { -- mappings for incremental selection (visual mappings)
node_incremental = "<leader>e", -- "grn" by default, node_incremental = "<leader>e", -- "grn" by default,
scope_incremental = "<leader>f" -- "grc" by default scope_incremental = "<leader>f" -- "grc" by default
} }
}, },
ensure_installed = 'all' -- can be one of 'all', 'language' or {'language1', 'language2' ... } node_movement = { -- this cursor movement in node hierachy
enable = true,
disable = { 'cpp', 'rust' },
keymaps = { -- mappings for node movement (normal mappings)
move_up = "<a-k>", -- default is to move with alt key hold
move_down = "<a-j>",
move_left = "<a-h>",
move_right = "<a-l>",
}
},
ensure_installed = 'all' -- one of 'all', 'language', or a list of languages
} }
< <

View file

@ -223,6 +223,17 @@ local config = {
}, },
is_supported = function() return true end is_supported = function() return true end
}, },
node_movement = {
enable = false,
disable = {},
is_supported = function() return true end,
keymaps = {
move_up = "<a-k>",
move_down = "<a-j>",
move_left = "<a-h>",
move_right = "<a-l>",
},
},
-- folding = { -- folding = {
-- enable = false, -- enable = false,
-- disable = {}, -- disable = {},

View file

@ -0,0 +1,91 @@
local api = vim.api
local parsers = require'nvim-treesitter.parsers'
local utils = require'nvim-treesitter.utils'
local M = {}
M.NodeMovementKind = {
up = 'up',
down = 'down',
left = 'left',
right = 'right',
}
M.current_node = {}
local function node_start_to_vim(node)
if not node then return end
local row, col = node:start()
local exec_command = string.format('call cursor(%d, %d)', row+1, col+1)
api.nvim_exec(exec_command, false)
end
M.do_node_movement = function(kind)
local buf, line, col = unpack(vim.fn.getpos("."))
local current_node = M.current_node[buf]
if current_node then
local node_line, node_col = current_node:start()
if line-1 ~= node_line or col-1 ~= node_col then
current_node = nil
end
end
local destination_node
if parsers.has_parser() then
local root = parsers.get_parser():parse():root()
if not current_node then
current_node = root:named_descendant_for_range(line-1, col-1, line-1, col)
end
if kind == M.NodeMovementKind.up then
destination_node = current_node:parent()
elseif kind == M.NodeMovementKind.down then
if current_node:named_child_count() > 0 then
destination_node = current_node:named_child(0)
else
local next_node = utils.get_next_node(current_node)
if next_node and next_node:named_child_count() > 0 then
destination_node = next_node:named_child(0)
end
end
elseif kind == M.NodeMovementKind.left then
destination_node = utils.get_previous_node(current_node, true, true)
elseif kind == M.NodeMovementKind.right then
destination_node = utils.get_next_node(current_node, true, true)
end
M.current_node[buf] = destination_node or current_node
end
if destination_node then
node_start_to_vim(destination_node)
end
end
M.move_up = function() M.do_node_movement(M.NodeMovementKind.up) end
M.move_down = function() M.do_node_movement(M.NodeMovementKind.down) end
M.move_left = function() M.do_node_movement(M.NodeMovementKind.left) end
M.move_right = function() M.do_node_movement(M.NodeMovementKind.right) end
function M.attach(bufnr)
local buf = bufnr or api.nvim_get_current_buf()
local config = require'nvim-treesitter.configs'.get_module('node_movement')
for funcname, mapping in pairs(config.keymaps) do
api.nvim_buf_set_keymap(buf, 'n', mapping,
string.format(":lua require'nvim-treesitter.node_movement'.%s()<CR>", funcname), { silent = true })
end
end
function M.detach(bufnr)
local buf = bufnr or api.nvim_get_current_buf()
local config = require'nvim-treesitter.configs'.get_module('node_movement')
for _, mapping in pairs(config.keymaps) do
api.nvim_buf_del_keymap(buf, 'n', mapping)
end
end
return M

View file

@ -93,4 +93,63 @@ function M.smallest_containing_scope(node, bufnr)
return current or root return current or root
end end
--- Get next node with same parent
-- @param node node
-- @param allow_switch_parents allow switching parents if last node
-- @param allow_next_parent allow next parent if last node and next parent without children
function M.get_next_node(node, allow_switch_parents, allow_next_parent)
local destination_node
local parent = node:parent()
if parent then
local found_pos = 0
for i = 0,parent:named_child_count()-1,1 do
if parent:named_child(i) == node then
found_pos = i
break
end
end
if parent:named_child_count() > found_pos + 1 then
destination_node = parent:named_child(found_pos + 1)
elseif allow_switch_parents then
local next_node = M.get_next_node(node:parent())
if next_node and next_node:named_child_count() > 0 then
destination_node = next_node:named_child(0)
elseif next_node and allow_next_parent then
destination_node = next_node
end
end
end
return destination_node
end
--- Get previous node with same parent
-- @param node node
-- @param allow_switch_parents allow switching parents if first node
-- @param allow_previous_parent allow previous parent if first node and previous parent without children
function M.get_previous_node(node, allow_switch_parents, allow_previous_parent)
local destination_node
local parent = node:parent()
if parent then
local found_pos = 0
for i = 0,parent:named_child_count()-1,1 do
if parent:named_child(i) == node then
found_pos = i
break
end
end
if 0 < found_pos then
destination_node = parent:named_child(found_pos - 1)
elseif allow_switch_parents then
local previous_node = M.get_previous_node(node:parent())
if previous_node and previous_node:named_child_count() > 0 then
destination_node = previous_node:named_child(previous_node:named_child_count() - 1)
elseif previous_node and allow_previous_parent then
destination_node = previous_node
end
end
end
return destination_node
end
return M return M