diff options
| author | kiyan42 <yazdani.kiyan@protonmail.com> | 2020-05-08 11:22:59 +0200 |
|---|---|---|
| committer | kiyan42 <yazdani.kiyan@protonmail.com> | 2020-05-12 16:16:48 +0200 |
| commit | 45dcebb15f1a954eba2bcb3ae4c1a03f710a1f2a (patch) | |
| tree | 50cbca8e9615d69a8ff9aca6b33a35abb32f9363 /lua/nvim-treesitter/state.lua | |
| parent | 307c78aa1e2cc5e499469fe892108b7fcf6cdb5e (diff) | |
refacto/feat: better handling of parser updates
features:
- node_movement is moving between scopes.
- add selection initialization from normal mode
- add a decremental selection
improvements:
- attach to buffer to run tree parsing on change
- run state update on CursorMoved
- the buffer state is:
```
{
cursor_pos = { row=row, col=col },
current_node = node_under_cursor,
selection = {
range = nil, -- activates when starting a selection
nodes = {} -- filling up when starting an incremental selection
},
parser = parser, -- parser for current buffer
}
```
- refacto all the modules reliant on parsing the tree, update the current nodes, get the current nodes...
fixes:
- fix has_parser to look for .so libraries
- fix should select the whole file when selection root in selection
Diffstat (limited to 'lua/nvim-treesitter/state.lua')
| -rw-r--r-- | lua/nvim-treesitter/state.lua | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/lua/nvim-treesitter/state.lua b/lua/nvim-treesitter/state.lua new file mode 100644 index 00000000..9da07ae1 --- /dev/null +++ b/lua/nvim-treesitter/state.lua @@ -0,0 +1,114 @@ +local api = vim.api + +local utils = require'nvim-treesitter.utils' + +local M = {} + +local buffers = {} + +local g_mode = api.nvim_get_mode().mode + +local function get_selection_range() + local _, vstart_row, vstart_col, _ = unpack(vim.fn.getpos("v")) + local _, cursor_row, cursor_col, _ = unpack(vim.fn.getpos(".")) + if vstart_row < cursor_row then + return vstart_row, vstart_col, cursor_row, cursor_col + else + return cursor_row, cursor_col, vstart_row, vstart_col + end +end + +function M.update() + local bufnr = api.nvim_get_current_buf() + local buf_config = buffers[bufnr] + if not buf_config then return end + + local mode = api.nvim_get_mode().mode + local cursor = api.nvim_win_get_cursor(0) + local row = cursor[1] + local col = cursor[2] + if row == buf_config.cursor_pos.row + and col == buf_config.cursor_pos.col + and mode == g_mode + then + return + end + + local root = buf_config.parser.tree:root() + if not root then return end + + local new_node = root:named_descendant_for_range(row - 1, col, row - 1, col) + + if new_node ~= buf_config.current_node then + buf_config.current_node = new_node + end + + -- We only want to update the range when the incremental selection has not started yet + if mode == "v" and #buf_config.selection.nodes == 0 then + local row_start, col_start, row_end, col_end = get_selection_range() + buf_config.selection.range = { row_start, col_start, row_end, col_end } + elseif mode ~= "v" then + buf_config.selection.nodes = {} + buf_config.selection.range = nil + end + + g_mode = mode + buf_config.cursor_pos.row = row + buf_config.cursor_pos.col = col +end + +function M.insert_selection_node(bufnr, range) + local buf_config = buffers[bufnr] + if not buf_config then return end + + table.insert(buffers[bufnr].selection.nodes, range) +end + +function M.pop_selection_node(bufnr) + local buf_config = buffers[bufnr] + if not buf_config then return end + + table.remove( + buffers[bufnr].selection.nodes, + #buffers[bufnr].selection.nodes + ) +end + +function M.run_update() + local cmd = "lua require'nvim-treesitter.state'.update()" + api.nvim_command('autocmd NvimTreesitter CursorMoved * '..cmd) +end + +function M.attach_to_buffer(ft) + local bufnr = api.nvim_get_current_buf() + local ft = ft or api.nvim_buf_get_option(bufnr, 'ft') + + if buffers[bufnr] then return end + + local parser = utils.get_parser(bufnr, ft) + if not parser then return end + + buffers[bufnr] = { + cursor_pos = {}, + current_node = nil, + selection = { + range = nil, + nodes = {} + }, + parser = parser, + } + + M.update() + api.nvim_buf_attach(bufnr, false, { + -- TODO(kyazdani): on lines should only parse the changed content + -- TODO(kyazdani): add a timer to avoid too frequent updates + on_lines = function(_, buf) buffers[buf].parser:parse() end, + on_detach = function(bufnr) buffers[bufnr] = nil end, + }) +end + +function M.get_buf_state(bufnr) + return buffers[bufnr] +end + +return M |
