aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua/vim/treesitter.lua
diff options
context:
space:
mode:
authorSteven Sojka <Steven.Sojka@tdameritrade.com>2020-11-04 11:03:36 -0600
committerThomas Vigouroux <tomvig38@gmail.com>2020-11-23 08:06:17 +0100
commit1a631026a942b3311adec0bee6d9b0b932c5de31 (patch)
treef74318cb686ccdd5467cd3860280c01eca6cfcf9 /runtime/lua/vim/treesitter.lua
parentcd691f2b6f605bc7fc13961e275823673d9871ad (diff)
downloadrneovim-1a631026a942b3311adec0bee6d9b0b932c5de31.tar.gz
rneovim-1a631026a942b3311adec0bee6d9b0b932c5de31.tar.bz2
rneovim-1a631026a942b3311adec0bee6d9b0b932c5de31.zip
feat(treesitter): add language tree
Implement the LanguageTree structure to enable language injection. This is done be removing the old Parser metatable and replacing by the new structure, with the same API (almost). Some noticeable differences : - `parser:parse()` now returns a table of trees - There is no incremental parsing for child (injected) languages Co-authored-by: Thomas Vigouroux <tomvig38@gmail.com>
Diffstat (limited to 'runtime/lua/vim/treesitter.lua')
-rw-r--r--runtime/lua/vim/treesitter.lua141
1 files changed, 25 insertions, 116 deletions
diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua
index 19ef148afc..6886f0c178 100644
--- a/runtime/lua/vim/treesitter.lua
+++ b/runtime/lua/vim/treesitter.lua
@@ -1,98 +1,13 @@
local a = vim.api
local query = require'vim.treesitter.query'
local language = require'vim.treesitter.language'
+local LanguageTree = require'vim.treesitter.languagetree'
-- TODO(bfredl): currently we retain parsers for the lifetime of the buffer.
-- Consider use weak references to release parser if all plugins are done with
-- it.
local parsers = {}
-local Parser = {}
-Parser.__index = Parser
-
---- Parses the buffer if needed and returns a tree.
---
--- Calling this will call the on_changedtree callbacks if the tree has changed.
---
--- @returns An up to date tree
--- @returns If the tree changed with this call, the changed ranges
-function Parser:parse()
- if self.valid then
- return self._tree_immutable
- end
- local changes
-
- self._tree, changes = self._parser:parse(self._tree, self:input_source())
-
- self._tree_immutable = self._tree:copy()
-
- self.valid = true
-
- if not vim.tbl_isempty(changes) then
- for _, cb in ipairs(self.changedtree_cbs) do
- cb(changes)
- end
- end
-
- return self._tree_immutable, changes
-end
-
-function Parser:input_source()
- return self.bufnr or self.str
-end
-
-function Parser:_on_bytes(bufnr, changed_tick,
- start_row, start_col, start_byte,
- old_row, old_col, old_byte,
- new_row, new_col, new_byte)
- local old_end_col = old_col + ((old_row == 0) and start_col or 0)
- local new_end_col = new_col + ((new_row == 0) and start_col or 0)
- self._tree:edit(start_byte,start_byte+old_byte,start_byte+new_byte,
- start_row, start_col,
- start_row+old_row, old_end_col,
- start_row+new_row, new_end_col)
- self.valid = false
-
- for _, cb in ipairs(self.bytes_cbs) do
- cb(bufnr, changed_tick,
- start_row, start_col, start_byte,
- old_row, old_col, old_byte,
- new_row, new_col, new_byte)
- end
-end
-
---- Registers callbacks for the parser
--- @param cbs An `nvim_buf_attach`-like table argument with the following keys :
--- `on_bytes` : see `nvim_buf_attach`, but this will be called _after_ the parsers callback.
--- `on_changedtree` : a callback that will be called everytime the tree has syntactical changes.
--- it will only be passed one argument, that is a table of the ranges (as node ranges) that
--- changed.
-function Parser:register_cbs(cbs)
- if not cbs then return end
-
- if cbs.on_changedtree then
- table.insert(self.changedtree_cbs, cbs.on_changedtree)
- end
-
- if cbs.on_bytes then
- table.insert(self.bytes_cbs, cbs.on_bytes)
- end
-end
-
---- Sets the included ranges for the current parser
---
--- @param ranges A table of nodes that will be used as the ranges the parser should include.
-function Parser:set_included_ranges(ranges)
- self._parser:set_included_ranges(ranges)
- -- The buffer will need to be parsed again later
- self.valid = false
-end
-
---- Gets the included ranges for the parsers
-function Parser:included_ranges()
- return self._parser:included_ranges()
-end
-
local M = vim.tbl_extend("error", query, language)
setmetatable(M, {
@@ -113,9 +28,9 @@ setmetatable(M, {
-- It is not recommended to use this, use vim.treesitter.get_parser() instead.
--
-- @param bufnr The buffer the parser will be tied to
--- @param lang The language of the parser.
--- @param id The id the parser will have
-function M._create_parser(bufnr, lang, id)
+-- @param lang The language of the parser
+-- @param opts Options to pass to the language tree
+function M._create_parser(bufnr, lang, opts)
language.require_language(lang)
if bufnr == 0 then
bufnr = a.nvim_get_current_buf()
@@ -123,25 +38,22 @@ function M._create_parser(bufnr, lang, id)
vim.fn.bufload(bufnr)
- local self = setmetatable({bufnr=bufnr, lang=lang, valid=false}, Parser)
- self._parser = vim._create_ts_parser(lang)
- self.changedtree_cbs = {}
- self.bytes_cbs = {}
- self:parse()
- -- TODO(bfredl): use weakref to self, so that the parser is free'd is no plugin is
- -- using it.
+ local self = LanguageTree.new(bufnr, lang, opts)
+
local function bytes_cb(_, ...)
- return self:_on_bytes(...)
+ self:_on_bytes(...)
end
- local detach_cb = nil
- if id ~= nil then
- detach_cb = function()
- if parsers[id] == self then
- parsers[id] = nil
- end
+
+ local function detach_cb()
+ if parsers[bufnr] == self then
+ parsers[bufnr] = nil
end
end
+
a.nvim_buf_attach(self.bufnr, false, {on_bytes=bytes_cb, on_detach=detach_cb})
+
+ self:parse()
+
return self
end
@@ -152,39 +64,36 @@ end
--
-- @param bufnr The buffer the parser should be tied to
-- @param ft The filetype of this parser
--- @param buf_attach_cbs See Parser:register_cbs
+-- @param opts Options object to pass to the parser
--
-- @returns The parser
-function M.get_parser(bufnr, lang, buf_attach_cbs)
+function M.get_parser(bufnr, lang, opts)
+ opts = opts or {}
+
if bufnr == nil or bufnr == 0 then
bufnr = a.nvim_get_current_buf()
end
if lang == nil then
lang = a.nvim_buf_get_option(bufnr, "filetype")
end
- local id = tostring(bufnr)..'_'..lang
- if parsers[id] == nil then
- parsers[id] = M._create_parser(bufnr, lang, id)
+ if parsers[bufnr] == nil then
+ parsers[bufnr] = M._create_parser(bufnr, lang, opts)
end
- parsers[id]:register_cbs(buf_attach_cbs)
+ parsers[bufnr]:register_cbs(opts.buf_attach_cbs)
- return parsers[id]
+ return parsers[bufnr]
end
-function M.get_string_parser(str, lang)
+function M.get_string_parser(str, lang, opts)
vim.validate {
str = { str, 'string' },
lang = { lang, 'string' }
}
language.require_language(lang)
- local self = setmetatable({str=str, lang=lang, valid=false}, Parser)
- self._parser = vim._create_ts_parser(lang)
- self:parse()
-
- return self
+ return LanguageTree.new(str, lang, opts)
end
return M