From c8f861b739b4703b1198dc1f88b09edbeb0d9f2e Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sat, 15 Jun 2019 12:10:12 +0200 Subject: tree-sitter: rename tree_sitter => treesitter for consistency --- runtime/lua/vim/treesitter.lua | 57 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 runtime/lua/vim/treesitter.lua (limited to 'runtime/lua/vim/treesitter.lua') diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua new file mode 100644 index 0000000000..1b5f416b67 --- /dev/null +++ b/runtime/lua/vim/treesitter.lua @@ -0,0 +1,57 @@ +local a = vim.api + +local Parser = {} +Parser.__index = Parser + +function Parser:parse_tree(force) + if self.valid and not force then + return self.tree + end + self.tree = self._parser:parse_buf(self.bufnr) + self.valid = true + return self.tree +end + +local function change_cb(self, ev, bufnr, tick, start_row, oldstopline, stop_row) + local start_byte = a.nvim_buf_get_offset(bufnr,start_row) + -- a bit messy, should we expose edited but not reparsed tree? + -- are multiple edits safe in general? + local root = self._parser:tree():root() + -- TODO: add proper lookup function! + local inode = root:descendant_for_point_range(oldstopline+9000,0, oldstopline,0) + if inode == nil then + local stop_byte = a.nvim_buf_get_offset(bufnr,stop_row) + self._parser:edit(start_byte,stop_byte,stop_byte,start_row,0,stop_row,0,stop_row,0) + else + local fakeoldstoprow, fakeoldstopcol, fakebyteoldstop = inode:start() + local fake_rows = fakeoldstoprow-oldstopline + local fakestop = stop_row+fake_rows + local fakebytestop = a.nvim_buf_get_offset(bufnr,fakestop)+fakeoldstopcol + self._parser:edit(start_byte,fakebyteoldstop,fakebytestop,start_row,0,fakeoldstoprow,fakeoldstopcol,fakestop,fakeoldstopcol) + end + self.valid = false +end + +local function create_parser(bufnr, ft) + if bufnr == 0 then + bufnr = a.nvim_get_current_buf() + end + if ft == nil then + ft = a.nvim_buf_get_option(bufnr, "filetype") + end + local self = setmetatable({bufnr=bufnr, valid=false}, Parser) + self._parser = vim._create_ts_parser(ft) + self:parse_tree() + local function cb(ev, ...) + -- TODO: use weakref to self, so that the parser is free'd is no plugin is + -- using it. + return change_cb(self, ev, ...) + end + a.nvim_buf_attach(self.bufnr, false, {on_lines=cb}) + return self +end + +-- TODO: weak table with reusable parser per buffer. + +return {create_parser=create_parser, add_language=vim._ts_add_language} + -- cgit From d24dec596c25690aba0aca658546ffdfcc6a952c Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sat, 15 Jun 2019 14:05:35 +0200 Subject: tree-sitter: inspect language --- runtime/lua/vim/treesitter.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'runtime/lua/vim/treesitter.lua') diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua index 1b5f416b67..3a1b1fc4b3 100644 --- a/runtime/lua/vim/treesitter.lua +++ b/runtime/lua/vim/treesitter.lua @@ -53,5 +53,9 @@ end -- TODO: weak table with reusable parser per buffer. -return {create_parser=create_parser, add_language=vim._ts_add_language} +return { + create_parser=create_parser, + add_language=vim._ts_add_language, + inspect_language=vim._ts_inspect_language, +} -- cgit From 167a1cfdef0c4b3526830ad0356f06bf480df6af Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Mon, 17 Jun 2019 21:46:31 +0200 Subject: tree-sitter: improve parser API (shared parser between plugins) --- runtime/lua/vim/treesitter.lua | 57 +++++++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 15 deletions(-) (limited to 'runtime/lua/vim/treesitter.lua') diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua index 3a1b1fc4b3..f26d63d6ce 100644 --- a/runtime/lua/vim/treesitter.lua +++ b/runtime/lua/vim/treesitter.lua @@ -3,8 +3,13 @@ local a = vim.api local Parser = {} Parser.__index = Parser -function Parser:parse_tree(force) - if self.valid and not force then +-- 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 = {} + +function Parser:parse() + if self.valid then return self.tree end self.tree = self._parser:parse_buf(self.bufnr) @@ -12,7 +17,7 @@ function Parser:parse_tree(force) return self.tree end -local function change_cb(self, ev, bufnr, tick, start_row, oldstopline, stop_row) +local function on_lines(self, bufnr, _, start_row, oldstopline, stop_row) local start_byte = a.nvim_buf_get_offset(bufnr,start_row) -- a bit messy, should we expose edited but not reparsed tree? -- are multiple edits safe in general? @@ -21,41 +26,63 @@ local function change_cb(self, ev, bufnr, tick, start_row, oldstopline, stop_row local inode = root:descendant_for_point_range(oldstopline+9000,0, oldstopline,0) if inode == nil then local stop_byte = a.nvim_buf_get_offset(bufnr,stop_row) - self._parser:edit(start_byte,stop_byte,stop_byte,start_row,0,stop_row,0,stop_row,0) + self._parser:edit(start_byte,stop_byte,stop_byte, + start_row,0,stop_row,0,stop_row,0) else local fakeoldstoprow, fakeoldstopcol, fakebyteoldstop = inode:start() local fake_rows = fakeoldstoprow-oldstopline local fakestop = stop_row+fake_rows local fakebytestop = a.nvim_buf_get_offset(bufnr,fakestop)+fakeoldstopcol - self._parser:edit(start_byte,fakebyteoldstop,fakebytestop,start_row,0,fakeoldstoprow,fakeoldstopcol,fakestop,fakeoldstopcol) + self._parser:edit(start_byte, fakebyteoldstop, fakebytestop, + start_row, 0, + fakeoldstoprow, fakeoldstopcol, + fakestop, fakeoldstopcol) end self.valid = false end -local function create_parser(bufnr, ft) +local function create_parser(bufnr, ft, id) if bufnr == 0 then bufnr = a.nvim_get_current_buf() end - if ft == nil then - ft = a.nvim_buf_get_option(bufnr, "filetype") - end local self = setmetatable({bufnr=bufnr, valid=false}, Parser) self._parser = vim._create_ts_parser(ft) - self:parse_tree() - local function cb(ev, ...) + self:parse() -- TODO: use weakref to self, so that the parser is free'd is no plugin is -- using it. - return change_cb(self, ev, ...) + local function lines_cb(ev, ...) + return on_lines(self, ...) end - a.nvim_buf_attach(self.bufnr, false, {on_lines=cb}) + local detach_cb = nil + if id ~= nil then + detach_cb = function() + if parsers[id] == self then + parsers[id] = nil + end + end + end + a.nvim_buf_attach(self.bufnr, false, {on_lines=lines_cb, on_detach=detach_cb}) return self end --- TODO: weak table with reusable parser per buffer. +local function get_parser(bufnr, ft) + if bufnr == nil or bufnr == 0 then + bufnr = a.nvim_get_current_buf() + end + if ft == nil then + ft = a.nvim_buf_get_option(bufnr, "filetype") + end + local id = tostring(bufnr)..'_'..ft + + if parsers[id] == nil then + parsers[id] = create_parser(bufnr, ft, id) + end + return parsers[id] +end return { + get_parser=get_parser, create_parser=create_parser, add_language=vim._ts_add_language, inspect_language=vim._ts_inspect_language, } - -- cgit From 06ee45b9b1c14c7ce6cb23403cdbe2852d495cad Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Fri, 21 Jun 2019 14:14:51 +0200 Subject: tree-sitter: fix lint, delete "demo" plugin (replaced by functional tests) --- runtime/lua/vim/treesitter.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim/treesitter.lua') diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua index f26d63d6ce..8aa170061b 100644 --- a/runtime/lua/vim/treesitter.lua +++ b/runtime/lua/vim/treesitter.lua @@ -50,7 +50,7 @@ local function create_parser(bufnr, ft, id) self:parse() -- TODO: use weakref to self, so that the parser is free'd is no plugin is -- using it. - local function lines_cb(ev, ...) + local function lines_cb(_, ...) return on_lines(self, ...) end local detach_cb = nil -- cgit From f86a2c33a2e54193598be1d8c856363e02b91e37 Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Mon, 5 Aug 2019 19:37:17 +0200 Subject: tree-sitter: simplify editing using the new old_byte_size parameter --- runtime/lua/vim/treesitter.lua | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) (limited to 'runtime/lua/vim/treesitter.lua') diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua index 8aa170061b..69b1ac8716 100644 --- a/runtime/lua/vim/treesitter.lua +++ b/runtime/lua/vim/treesitter.lua @@ -17,27 +17,12 @@ function Parser:parse() return self.tree end -local function on_lines(self, bufnr, _, start_row, oldstopline, stop_row) +local function on_lines(self, bufnr, _, start_row, old_stop_row, stop_row, old_byte_size) local start_byte = a.nvim_buf_get_offset(bufnr,start_row) - -- a bit messy, should we expose edited but not reparsed tree? - -- are multiple edits safe in general? - local root = self._parser:tree():root() - -- TODO: add proper lookup function! - local inode = root:descendant_for_point_range(oldstopline+9000,0, oldstopline,0) - if inode == nil then - local stop_byte = a.nvim_buf_get_offset(bufnr,stop_row) - self._parser:edit(start_byte,stop_byte,stop_byte, - start_row,0,stop_row,0,stop_row,0) - else - local fakeoldstoprow, fakeoldstopcol, fakebyteoldstop = inode:start() - local fake_rows = fakeoldstoprow-oldstopline - local fakestop = stop_row+fake_rows - local fakebytestop = a.nvim_buf_get_offset(bufnr,fakestop)+fakeoldstopcol - self._parser:edit(start_byte, fakebyteoldstop, fakebytestop, - start_row, 0, - fakeoldstoprow, fakeoldstopcol, - fakestop, fakeoldstopcol) - end + local stop_byte = a.nvim_buf_get_offset(bufnr,stop_row) + local old_stop_byte = start_byte + old_byte_size + self._parser:edit(start_byte,old_stop_byte,stop_byte, + start_row,0,old_stop_row,0,stop_row,0) self.valid = false end -- cgit From c844f986d4c8f34bbe60591270178504b7045a7a Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sat, 28 Sep 2019 14:04:05 +0200 Subject: tree-sitter: use "module" pattern in lua source --- runtime/lua/vim/treesitter.lua | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'runtime/lua/vim/treesitter.lua') diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua index 69b1ac8716..e0202927bb 100644 --- a/runtime/lua/vim/treesitter.lua +++ b/runtime/lua/vim/treesitter.lua @@ -1,13 +1,13 @@ local a = vim.api -local Parser = {} -Parser.__index = Parser - -- 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 + function Parser:parse() if self.valid then return self.tree @@ -17,7 +17,7 @@ function Parser:parse() return self.tree end -local function on_lines(self, bufnr, _, start_row, old_stop_row, stop_row, old_byte_size) +function Parser:_on_lines(bufnr, _, start_row, old_stop_row, stop_row, old_byte_size) local start_byte = a.nvim_buf_get_offset(bufnr,start_row) local stop_byte = a.nvim_buf_get_offset(bufnr,stop_row) local old_stop_byte = start_byte + old_byte_size @@ -26,17 +26,22 @@ local function on_lines(self, bufnr, _, start_row, old_stop_row, stop_row, old_b self.valid = false end -local function create_parser(bufnr, ft, id) +local module = { + add_language=vim._ts_add_language, + inspect_language=vim._ts_inspect_language, +} + +function module.create_parser(bufnr, ft, id) if bufnr == 0 then bufnr = a.nvim_get_current_buf() end local self = setmetatable({bufnr=bufnr, valid=false}, Parser) self._parser = vim._create_ts_parser(ft) self:parse() - -- TODO: use weakref to self, so that the parser is free'd is no plugin is + -- TODO(bfredl): use weakref to self, so that the parser is free'd is no plugin is -- using it. local function lines_cb(_, ...) - return on_lines(self, ...) + return self:_on_lines(...) end local detach_cb = nil if id ~= nil then @@ -50,7 +55,7 @@ local function create_parser(bufnr, ft, id) return self end -local function get_parser(bufnr, ft) +function module.get_parser(bufnr, ft) if bufnr == nil or bufnr == 0 then bufnr = a.nvim_get_current_buf() end @@ -60,14 +65,9 @@ local function get_parser(bufnr, ft) local id = tostring(bufnr)..'_'..ft if parsers[id] == nil then - parsers[id] = create_parser(bufnr, ft, id) + parsers[id] = module.create_parser(bufnr, ft, id) end return parsers[id] end -return { - get_parser=get_parser, - create_parser=create_parser, - add_language=vim._ts_add_language, - inspect_language=vim._ts_inspect_language, -} +return module -- cgit From 440695c29696f261337227e5c419aa1cf313c2dd Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sat, 28 Sep 2019 14:27:20 +0200 Subject: tree-sitter: implement query functionality and highlighting prototype [skip.lint] --- runtime/lua/vim/treesitter.lua | 120 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 112 insertions(+), 8 deletions(-) (limited to 'runtime/lua/vim/treesitter.lua') diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua index e0202927bb..aa8b8fcdd1 100644 --- a/runtime/lua/vim/treesitter.lua +++ b/runtime/lua/vim/treesitter.lua @@ -12,9 +12,13 @@ function Parser:parse() if self.valid then return self.tree end - self.tree = self._parser:parse_buf(self.bufnr) + local changes + self.tree, changes = self._parser:parse_buf(self.bufnr) self.valid = true - return self.tree + for _, cb in ipairs(self.change_cbs) do + cb(changes) + end + return self.tree, changes end function Parser:_on_lines(bufnr, _, start_row, old_stop_row, stop_row, old_byte_size) @@ -26,17 +30,28 @@ function Parser:_on_lines(bufnr, _, start_row, old_stop_row, stop_row, old_byte_ self.valid = false end -local module = { +local M = { add_language=vim._ts_add_language, inspect_language=vim._ts_inspect_language, + parse_query = vim._ts_parse_query, } -function module.create_parser(bufnr, ft, id) +setmetatable(M, { + __index = function (t, k) + if k == "TSHighlighter" then + t[k] = require'vim.tshighlighter' + return t[k] + end + end + }) + +function M.create_parser(bufnr, ft, id) if bufnr == 0 then bufnr = a.nvim_get_current_buf() end - local self = setmetatable({bufnr=bufnr, valid=false}, Parser) + local self = setmetatable({bufnr=bufnr, lang=ft, valid=false}, Parser) self._parser = vim._create_ts_parser(ft) + self.change_cbs = {} self:parse() -- TODO(bfredl): use weakref to self, so that the parser is free'd is no plugin is -- using it. @@ -55,7 +70,7 @@ function module.create_parser(bufnr, ft, id) return self end -function module.get_parser(bufnr, ft) +function M.get_parser(bufnr, ft, cb) if bufnr == nil or bufnr == 0 then bufnr = a.nvim_get_current_buf() end @@ -65,9 +80,98 @@ function module.get_parser(bufnr, ft) local id = tostring(bufnr)..'_'..ft if parsers[id] == nil then - parsers[id] = module.create_parser(bufnr, ft, id) + parsers[id] = M.create_parser(bufnr, ft, id) + end + if cb ~= nil then + table.insert(parsers[id].change_cbs, cb) end return parsers[id] end -return module +-- query: pattern matching on trees +-- predicate matching is implemented in lua +local Query = {} +Query.__index = Query + +function M.parse_query(lang, query) + local self = setmetatable({}, Query) + self.query = vim._ts_parse_query(lang, query) + self.info = self.query:inspect() + self.captures = self.info.captures + return self +end + +local function get_node_text(node, bufnr) + local start_row, start_col, end_row, end_col = node:range() + if start_row ~= end_row then + return nil + end + local line = a.nvim_buf_get_lines(bufnr, start_row, start_row+1, true)[1] + return string.sub(line, start_col+1, end_col) +end + +local function match_preds(match, preds, bufnr) + for _, pred in pairs(preds) do + if pred[1] == "eq?" then + local node = match[pred[2]] + local node_text = get_node_text(node, bufnr) + + local str + if type(pred[3]) == "string" then + -- (eq? @aa "foo") + str = pred[3] + else + -- (eq? @aa @bb) + str = get_node_text(match[pred[3]], bufnr) + end + + if node_text ~= str or str == nil then + return false + end + else + return false + end + end + return true +end + +function Query:iter_captures(node, bufnr, start, stop) + if bufnr == 0 then + bufnr = vim.api.nvim_get_current_buf() + end + local raw_iter = node:_rawquery(self.query,true,start,stop) + local function iter() + local capture, captured_node, match = raw_iter() + if match ~= nil then + local preds = self.info.patterns[match.pattern] + local active = match_preds(match, preds, bufnr) + match.active = active + if not active then + return iter() -- tail call: try next match + end + end + return capture, captured_node + end + return iter +end + +function Query:iter_matches(node, bufnr, start, stop) + if bufnr == 0 then + bufnr = vim.api.nvim_get_current_buf() + end + local raw_iter = node:_rawquery(self.query,false,start,stop) + local function iter() + local pattern, match = raw_iter() + if match ~= nil then + local preds = self.info.patterns[pattern] + local active = (not preds) or match_preds(match, preds, bufnr) + if not active then + return iter() -- tail call: try next match + end + end + return pattern, match + end + return iter +end + +return M -- cgit From 00c57c98dfb2df58875a3d9ad8fc557ec9a24cba Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Sat, 25 Jan 2020 13:43:41 +0100 Subject: treesitter: add standard &rtp/parser/ search path for parsers --- runtime/lua/vim/treesitter.lua | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) (limited to 'runtime/lua/vim/treesitter.lua') diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua index aa8b8fcdd1..0d0e22adb3 100644 --- a/runtime/lua/vim/treesitter.lua +++ b/runtime/lua/vim/treesitter.lua @@ -31,8 +31,6 @@ function Parser:_on_lines(bufnr, _, start_row, old_stop_row, stop_row, old_byte_ end local M = { - add_language=vim._ts_add_language, - inspect_language=vim._ts_inspect_language, parse_query = vim._ts_parse_query, } @@ -45,12 +43,34 @@ setmetatable(M, { end }) -function M.create_parser(bufnr, ft, id) +function M.require_language(lang, path) + if vim._ts_has_language(lang) then + return true + end + if path == nil then + local fname = 'parser/' .. lang .. '.*' + local paths = a.nvim_get_runtime_file(fname, false) + if #paths == 0 then + -- TODO(bfredl): help tag? + error("no parser for '"..lang.."' language") + end + path = paths[1] + end + vim._ts_add_language(path, lang) +end + +function M.inspect_language(lang) + M.require_language(lang) + return vim._ts_inspect_language(lang) +end + +function M.create_parser(bufnr, lang, id) + M.require_language(lang) if bufnr == 0 then bufnr = a.nvim_get_current_buf() end - local self = setmetatable({bufnr=bufnr, lang=ft, valid=false}, Parser) - self._parser = vim._create_ts_parser(ft) + local self = setmetatable({bufnr=bufnr, lang=lang, valid=false}, Parser) + self._parser = vim._create_ts_parser(lang) self.change_cbs = {} self:parse() -- TODO(bfredl): use weakref to self, so that the parser is free'd is no plugin is @@ -94,6 +114,7 @@ local Query = {} Query.__index = Query function M.parse_query(lang, query) + M.require_language(lang) local self = setmetatable({}, Query) self.query = vim._ts_parse_query(lang, query) self.info = self.query:inspect() -- cgit From 9c00fea585ccab56a6044a174ce8d9a2c605c6cd Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Mon, 4 Nov 2019 20:40:30 +0100 Subject: lua: add regex support, and `@match` support in treesitter queries --- runtime/lua/vim/treesitter.lua | 46 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 6 deletions(-) (limited to 'runtime/lua/vim/treesitter.lua') diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua index 0d0e22adb3..8dacfa11cf 100644 --- a/runtime/lua/vim/treesitter.lua +++ b/runtime/lua/vim/treesitter.lua @@ -113,12 +113,33 @@ end local Query = {} Query.__index = Query +local magic_prefixes = {['\\v']=true, ['\\m']=true, ['\\M']=true, ['\\V']=true} +local function check_magic(str) + if string.len(str) < 2 or magic_prefixes[string.sub(str,1,2)] then + return str + end + return '\\v'..str +end + function M.parse_query(lang, query) M.require_language(lang) local self = setmetatable({}, Query) self.query = vim._ts_parse_query(lang, query) self.info = self.query:inspect() self.captures = self.info.captures + self.regexes = {} + for id,preds in pairs(self.info.patterns) do + local regexes = {} + for i, pred in ipairs(preds) do + if (pred[1] == "match?" and type(pred[2]) == "number" + and type(pred[3]) == "string") then + regexes[i] = vim.regex(check_magic(pred[3])) + end + end + if next(regexes) then + self.regexes[id] = regexes + end + end return self end @@ -131,8 +152,13 @@ local function get_node_text(node, bufnr) return string.sub(line, start_col+1, end_col) end -local function match_preds(match, preds, bufnr) - for _, pred in pairs(preds) do +function Query:match_preds(match, pattern, bufnr) + local preds = self.info.patterns[pattern] + if not preds then + return true + end + local regexes = self.regexes[pattern] + for i, pred in pairs(preds) do if pred[1] == "eq?" then local node = match[pred[2]] local node_text = get_node_text(node, bufnr) @@ -149,6 +175,16 @@ local function match_preds(match, preds, bufnr) if node_text ~= str or str == nil then return false end + elseif pred[1] == "match?" then + if not regexes or not regexes[i] then + return false + end + local node = match[pred[2]] + local start_row, start_col, end_row, end_col = node:range() + if start_row ~= end_row then + return false + end + return regexes[i]:match_line(bufnr, start_row, start_col, end_col) else return false end @@ -164,8 +200,7 @@ function Query:iter_captures(node, bufnr, start, stop) local function iter() local capture, captured_node, match = raw_iter() if match ~= nil then - local preds = self.info.patterns[match.pattern] - local active = match_preds(match, preds, bufnr) + local active = self:match_preds(match, match.pattern, bufnr) match.active = active if not active then return iter() -- tail call: try next match @@ -184,8 +219,7 @@ function Query:iter_matches(node, bufnr, start, stop) local function iter() local pattern, match = raw_iter() if match ~= nil then - local preds = self.info.patterns[pattern] - local active = (not preds) or match_preds(match, preds, bufnr) + local active = self:match_preds(match, pattern, bufnr) if not active then return iter() -- tail call: try next match end -- cgit From 1fb44ba8356e06b9d90a43599c4526ad4d625618 Mon Sep 17 00:00:00 2001 From: Thomas Vigouroux Date: Fri, 17 Apr 2020 17:24:04 +0200 Subject: treesitter: escape backslashes in queries Treesitter changed their decoders and apparently thus causing this change. This decoder change happened on ee9a3c0ebb218990cf391ed987be7f2448c54a73. --- runtime/lua/vim/treesitter.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim/treesitter.lua') diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua index 8dacfa11cf..1836227540 100644 --- a/runtime/lua/vim/treesitter.lua +++ b/runtime/lua/vim/treesitter.lua @@ -124,7 +124,7 @@ end function M.parse_query(lang, query) M.require_language(lang) local self = setmetatable({}, Query) - self.query = vim._ts_parse_query(lang, query) + self.query = vim._ts_parse_query(lang, vim.fn.escape(query,'\\')) self.info = self.query:inspect() self.captures = self.info.captures self.regexes = {} -- cgit From e5022c61ed769153dab5a91752c52a8f9ad3b504 Mon Sep 17 00:00:00 2001 From: Thomas Vigouroux <39092278+vigoux@users.noreply.github.com> Date: Fri, 1 May 2020 07:43:30 +0200 Subject: treesitter: unknown predicates always match #12173 --- runtime/lua/vim/treesitter.lua | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'runtime/lua/vim/treesitter.lua') diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua index 1836227540..d3b78a7f73 100644 --- a/runtime/lua/vim/treesitter.lua +++ b/runtime/lua/vim/treesitter.lua @@ -159,6 +159,9 @@ function Query:match_preds(match, pattern, bufnr) end local regexes = self.regexes[pattern] for i, pred in pairs(preds) do + -- Here we only want to return if a predicate DOES NOT match, and + -- continue on the other case. This way unknown predicates will not be considered, + -- which allows some testing and easier user extensibility (#12173). if pred[1] == "eq?" then local node = match[pred[2]] local node_text = get_node_text(node, bufnr) @@ -184,9 +187,9 @@ function Query:match_preds(match, pattern, bufnr) if start_row ~= end_row then return false end - return regexes[i]:match_line(bufnr, start_row, start_col, end_col) - else - return false + if not regexes[i]:match_line(bufnr, start_row, start_col, end_col) then + return false + end end end return true -- cgit From 6a93077475d298f46ac19c8030ed5b4a723685dc Mon Sep 17 00:00:00 2001 From: Thomas Vigouroux Date: Wed, 3 Jun 2020 19:58:02 +0200 Subject: treesitter: fix tests --- runtime/lua/vim/treesitter.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'runtime/lua/vim/treesitter.lua') diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua index d3b78a7f73..c502e45bd0 100644 --- a/runtime/lua/vim/treesitter.lua +++ b/runtime/lua/vim/treesitter.lua @@ -162,16 +162,17 @@ function Query:match_preds(match, pattern, bufnr) -- Here we only want to return if a predicate DOES NOT match, and -- continue on the other case. This way unknown predicates will not be considered, -- which allows some testing and easier user extensibility (#12173). + -- Also, tree-sitter strips the leading # from predicates for us. if pred[1] == "eq?" then local node = match[pred[2]] local node_text = get_node_text(node, bufnr) local str if type(pred[3]) == "string" then - -- (eq? @aa "foo") + -- (#eq? @aa "foo") str = pred[3] else - -- (eq? @aa @bb) + -- (#eq? @aa @bb) str = get_node_text(match[pred[3]], bufnr) end -- cgit From 333f3f19db612acc893791f04624da174efe04b5 Mon Sep 17 00:00:00 2001 From: Thomas Vigouroux Date: Sun, 7 Jun 2020 16:37:11 +0200 Subject: treesitter: add set_included_ranges to the parser This is the first step towards language injection using treesitter. --- runtime/lua/vim/treesitter.lua | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'runtime/lua/vim/treesitter.lua') diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua index c502e45bd0..d5bc8e0a1b 100644 --- a/runtime/lua/vim/treesitter.lua +++ b/runtime/lua/vim/treesitter.lua @@ -30,6 +30,12 @@ function Parser:_on_lines(bufnr, _, start_row, old_stop_row, stop_row, old_byte_ self.valid = false end +function Parser:set_included_ranges(ranges) + self._parser:set_included_ranges(self.bufnr, ranges) + -- The buffer will need to be parsed again later + self.valid = false +end + local M = { parse_query = vim._ts_parse_query, } -- cgit From b652f74ca3a6722ad0d185a0f4093907a6af65d7 Mon Sep 17 00:00:00 2001 From: Thomas Vigouroux Date: Tue, 16 Jun 2020 08:17:25 +0200 Subject: treesitter: use nodes to mark ranges --- runtime/lua/vim/treesitter.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/lua/vim/treesitter.lua') diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua index d5bc8e0a1b..f356673839 100644 --- a/runtime/lua/vim/treesitter.lua +++ b/runtime/lua/vim/treesitter.lua @@ -31,7 +31,7 @@ function Parser:_on_lines(bufnr, _, start_row, old_stop_row, stop_row, old_byte_ end function Parser:set_included_ranges(ranges) - self._parser:set_included_ranges(self.bufnr, ranges) + self._parser:set_included_ranges(ranges) -- The buffer will need to be parsed again later self.valid = false end -- cgit From 529251d5e49ed869aa9b4b3a168e97c8e30211d6 Mon Sep 17 00:00:00 2001 From: Thomas Vigouroux <39092278+vigoux@users.noreply.github.com> Date: Fri, 10 Jul 2020 15:33:27 +0200 Subject: treesitter: call bufload before parsing (#12603) --- runtime/lua/vim/treesitter.lua | 3 +++ 1 file changed, 3 insertions(+) (limited to 'runtime/lua/vim/treesitter.lua') diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua index f356673839..edff94af0b 100644 --- a/runtime/lua/vim/treesitter.lua +++ b/runtime/lua/vim/treesitter.lua @@ -75,6 +75,9 @@ function M.create_parser(bufnr, lang, id) if bufnr == 0 then bufnr = a.nvim_get_current_buf() end + + vim.fn.bufload(bufnr) + local self = setmetatable({bufnr=bufnr, lang=lang, valid=false}, Parser) self._parser = vim._create_ts_parser(lang) self.change_cbs = {} -- cgit From 341e139992e7bcfe02f41575ac4a9450d33dae26 Mon Sep 17 00:00:00 2001 From: Thomas Vigouroux Date: Wed, 8 Jul 2020 22:47:57 +0200 Subject: treesitter: add parser on_lines callbacks --- runtime/lua/vim/treesitter.lua | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) (limited to 'runtime/lua/vim/treesitter.lua') diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua index edff94af0b..927456708c 100644 --- a/runtime/lua/vim/treesitter.lua +++ b/runtime/lua/vim/treesitter.lua @@ -15,19 +15,27 @@ function Parser:parse() local changes self.tree, changes = self._parser:parse_buf(self.bufnr) self.valid = true - for _, cb in ipairs(self.change_cbs) do - cb(changes) + + if not vim.tbl_isempty(changes) then + for _, cb in ipairs(self.changedtree_cbs) do + cb(changes) + end end + return self.tree, changes end -function Parser:_on_lines(bufnr, _, start_row, old_stop_row, stop_row, old_byte_size) +function Parser:_on_lines(bufnr, changed_tick, start_row, old_stop_row, stop_row, old_byte_size) local start_byte = a.nvim_buf_get_offset(bufnr,start_row) local stop_byte = a.nvim_buf_get_offset(bufnr,stop_row) local old_stop_byte = start_byte + old_byte_size self._parser:edit(start_byte,old_stop_byte,stop_byte, start_row,0,old_stop_row,0,stop_row,0) self.valid = false + + for _, cb in ipairs(self.lines_cbs) do + cb(bufnr, changed_tick, start_row, old_stop_row, stop_row, old_byte_size) + end end function Parser:set_included_ranges(ranges) @@ -80,7 +88,8 @@ function M.create_parser(bufnr, lang, id) local self = setmetatable({bufnr=bufnr, lang=lang, valid=false}, Parser) self._parser = vim._create_ts_parser(lang) - self.change_cbs = {} + self.changedtree_cbs = {} + self.lines_cbs = {} self:parse() -- TODO(bfredl): use weakref to self, so that the parser is free'd is no plugin is -- using it. @@ -99,7 +108,7 @@ function M.create_parser(bufnr, lang, id) return self end -function M.get_parser(bufnr, ft, cb) +function M.get_parser(bufnr, ft, buf_attach_cbs) if bufnr == nil or bufnr == 0 then bufnr = a.nvim_get_current_buf() end @@ -111,9 +120,15 @@ function M.get_parser(bufnr, ft, cb) if parsers[id] == nil then parsers[id] = M.create_parser(bufnr, ft, id) end - if cb ~= nil then - table.insert(parsers[id].change_cbs, cb) + + if buf_attach_cbs and buf_attach_cbs.on_changedtree then + table.insert(parsers[id].changedtree_cbs, buf_attach_cbs.on_changedtree) + end + + if buf_attach_cbs and buf_attach_cbs.on_lines then + table.insert(parsers[id].lines_cbs, buf_attach_cbs.on_lines) end + return parsers[id] end -- cgit