From 81daf86b3e8f9254b52b88208421b41f30ab213d Mon Sep 17 00:00:00 2001 From: Thomas Vigouroux Date: Mon, 27 Jul 2020 11:41:00 +0200 Subject: [PATCH] wip --- lua/nvim-treesitter/highlight.lua | 16 ++++--- lua/nvim-treesitter/language_tree.lua | 63 +++++++++++++++++++++++++++ queries/markdown/injection.scm | 3 ++ tests/nvim_treesitter_spec.lua | 43 ++++++++++++++++++ 4 files changed, 120 insertions(+), 5 deletions(-) create mode 100644 lua/nvim-treesitter/language_tree.lua create mode 100644 queries/markdown/injection.scm create mode 100644 tests/nvim_treesitter_spec.lua diff --git a/lua/nvim-treesitter/highlight.lua b/lua/nvim-treesitter/highlight.lua index 867c70caf..756752946 100644 --- a/lua/nvim-treesitter/highlight.lua +++ b/lua/nvim-treesitter/highlight.lua @@ -9,7 +9,9 @@ local M = { highlighters = {} } -local hlmap = vim.treesitter.TSHighlighter.hl_map +local TSHighlighter = vim.treesitter.TSHighlighter + +local hlmap = TSHighlighter.hl_map -- Misc hlmap.error = "TSError" @@ -52,6 +54,13 @@ hlmap["type.builtin"] = "TSTypeBuiltin" hlmap["structure"] = "TSStructure" hlmap["include"] = "TSInclude" +function M.create_highlighter(bufnr, lang) + local query = queries.get_query(lang, "highlights") + if not query then return end + + M.highlighters[bufnr] = ts.TSHighlighter.new(query, bufnr, lang) +end + function M.attach(bufnr, lang) local bufnr = bufnr or api.nvim_get_current_buf() local lang = lang or parsers.get_buf_lang(bufnr) @@ -61,10 +70,7 @@ function M.attach(bufnr, lang) hlmap[k] = v end - local query = queries.get_query(lang, "highlights") - if not query then return end - - M.highlighters[bufnr] = ts.TSHighlighter.new(query, bufnr, lang) + create_highlighter(bufnr, lang) end function M.detach(bufnr) diff --git a/lua/nvim-treesitter/language_tree.lua b/lua/nvim-treesitter/language_tree.lua new file mode 100644 index 000000000..d79286114 --- /dev/null +++ b/lua/nvim-treesitter/language_tree.lua @@ -0,0 +1,63 @@ +local api = vim.api +local ts = vim.treesitter +local parsers = require"nvim-tresitter.parsers" +local query = require"nvim-treesitter.query" +local hl = require"nvim-treesitter.highlight" + +local ts_hs_ns = api.nvim_get_namespaces()["treesitter_hl"] + +local M = {} + +local LanguageTree = {} + +function LanguageTree.new(bufnr, language, ranges) + local buffer = bufnr or api.nvim_get_current_buf() + local lang = language or parsers.get_buf_lang(bufnr) + + if ranges then + parser.set_included_ranges(ranges) + end + + local hl_query = hl.create_highlighter(bufnr, lang) + local injection_query = query.get_query(lang, "injections") + + local self = setmetatable({ + buf = buffer, + hl_query = hl_query, + injection_query = injection_query, + children = {} + }, LanguageTree) + + self.parser = ts.get_parser(buffer, lang, { + on_changedtree = function(...) self:on_changedtree(...) end + }) + + return end + +function LanguageTree:on_changedtree(changes) + -- Get a fresh root + if not self.injection_query then return end + local root = self.parser.tree:root() + + for _, ch in ipairs(changes or {}) do + + for match in query.iter_prepared_matches(self.injection_query, changed_node, self.buf, ch[1], ch[3] + 1) do + if match.content then + local start_row, start_col, end_row, end_col = match.content:range() + -- TODO(vigoux): this might be quite wrong + api.nvim_buf_clear_namespace(self.buf, ts_hs_ns, start_row, end_row) + + -- Language injection here + if match.lang then + + -- Prepare the child if not already done + if not self.children[match.lang] then + self.children[match.lang] = { ranges = {} } + end + end + end + end + end +end + +return M diff --git a/queries/markdown/injection.scm b/queries/markdown/injection.scm new file mode 100644 index 000000000..12d02c34d --- /dev/null +++ b/queries/markdown/injection.scm @@ -0,0 +1,3 @@ +(fenced_code_block + (info_string) @injection.lang + (code_fence_content) @injection.content) diff --git a/tests/nvim_treesitter_spec.lua b/tests/nvim_treesitter_spec.lua new file mode 100644 index 000000000..2fe297108 --- /dev/null +++ b/tests/nvim_treesitter_spec.lua @@ -0,0 +1,43 @@ +local helpers = require('test.functional.helpers')(after_each) +local Screen = require('test.functional.ui.screen') +local clear, command = helpers.clear, helpers.command +local feed, alter_slashes = helpers.feed, helpers.alter_slashes +local insert = helpers.insert + +describe('nvim-treesitter', function() + local screen + + before_each(function() + clear() + screen = Screen.new(81, 15) + screen:attach() + end) + + after_each(function() + screen:detach() + end) + + it('basically works', function() + insert("This is a line") + + screen:expect([[ + This is a lin^e | + {2:~ }| + {2:~ }| + {2:~ }| + {2:~ }| + {2:~ }| + {2:~ }| + {2:~ }| + {2:~ }| + {2:~ }| + {2:~ }| + {2:~ }| + {2:~ }| + {2:~ }| + | +]], {[2] = {bold = true, foreground = Screen.colors.Blue1}}) + + end) + +end)