summaryrefslogtreecommitdiff
path: root/lua/nvim-treesitter/state.lua
diff options
context:
space:
mode:
Diffstat (limited to 'lua/nvim-treesitter/state.lua')
-rw-r--r--lua/nvim-treesitter/state.lua114
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