diff options
author | Steven Sojka <Steven.Sojka@tdameritrade.com> | 2020-11-04 11:03:36 -0600 |
---|---|---|
committer | Thomas Vigouroux <tomvig38@gmail.com> | 2020-11-23 08:06:17 +0100 |
commit | 1a631026a942b3311adec0bee6d9b0b932c5de31 (patch) | |
tree | f74318cb686ccdd5467cd3860280c01eca6cfcf9 /runtime/lua/vim/treesitter.lua | |
parent | cd691f2b6f605bc7fc13961e275823673d9871ad (diff) | |
download | rneovim-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.lua | 141 |
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 |