From b706c4e8edd20dfe5ec126479c3fc7308896f9c7 Mon Sep 17 00:00:00 2001 From: Thomas Vigouroux Date: Sun, 19 Apr 2020 09:53:44 +0200 Subject: feat: first version of locals Locals will be the main interface to treesitter, through some functions: get_definitions(bufnr) : returns all the definitions in bufnr get_scopes(bufnr): returns all definitions in bufnr get_references(bufnr): returns all references in bufnr --- lua/nvim-treesitter/locals.lua | 82 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 lua/nvim-treesitter/locals.lua (limited to 'lua') diff --git a/lua/nvim-treesitter/locals.lua b/lua/nvim-treesitter/locals.lua new file mode 100644 index 000000000..cd8a3e306 --- /dev/null +++ b/lua/nvim-treesitter/locals.lua @@ -0,0 +1,82 @@ +-- Functions to handle locals +-- Locals are a generalization of definition and scopes +-- its the way nvim-treesitter uses to "understand" the code +local api = vim.api +local ts = vim.treesitter +local queries = require'nvim-treesitter.query' +local parsers = require'nvim-treesitter.parsers' + +local M = { + locals={} +} + +function M.collect_locals(bufnr) + local ft = api.nvim_buf_get_option(bufnr, "ft") + local query = queries.get_query(ft, "locals") + + if ft then + local query = queries.get_query(ft, 'locals') + local parser = parsers.get_parser(bufnr) + + if parser then + local root = parser:parse():root() + local start_row, _, end_row, _ = root:range() + + local locals = {} + + for prepared_match in queries.iter_prepared_matches(query, root, bufnr, start_row, end_row) do + table.insert(locals, prepared_match) + end + + return locals + end + end +end + +function M.on_lines(_, buf, _, firstline, lastline, new_lastline, _) + M.locals[buf] = M.collect_locals(buf) +end + +function M.get_definitions(bufnr) + local locals = M.locals[bufnr] + + local defs = {} + + for _, loc in ipairs(locals) do + if loc.definition then + table.insert(defs, {definition=loc.definition, kind=loc.kind}) + end + end + + return defs +end + +function M.get_scopes(bufnr) + local locals = M.locals[bufnr] + + local scopes = {} + + for _, loc in ipairs(locals) do + if loc.scope then + table.insert(scopes, loc.scope) + end + end + + return scopes +end + +function M.get_references(bufnr) + local locals = M.locals[bufnr or api.nvim_get_current_buf()] + + local refs = {} + + for _, loc in ipairs(locals) do + if loc.reference then + table.insert(refs, loc.reference) + end + end + + return refs +end + +return M -- cgit v1.2.3-70-g09d2 From b2b6e51a7c6a32b48148a88cf2171b9f663a2b9d Mon Sep 17 00:00:00 2001 From: Thomas Vigouroux Date: Sun, 19 Apr 2020 14:20:23 +0200 Subject: feat: add locals to setup procedure --- lua/nvim-treesitter.lua | 7 +++++++ lua/nvim-treesitter/locals.lua | 17 ++++++++++++----- 2 files changed, 19 insertions(+), 5 deletions(-) (limited to 'lua') diff --git a/lua/nvim-treesitter.lua b/lua/nvim-treesitter.lua index abb3b6d91..ef6c31506 100644 --- a/lua/nvim-treesitter.lua +++ b/lua/nvim-treesitter.lua @@ -1,6 +1,7 @@ local api = vim.api local parsers = require'nvim-treesitter.parsers' local install = require'nvim-treesitter.install' +local locals = require'nvim-treesitter.locals' local M = {} @@ -8,6 +9,12 @@ local M = {} -- this is the main interface through the plugin function M.setup(lang) if parsers.has_parser(lang) then + if locals.is_supported(lang) then + print("Locals setup for", lang) + api.nvim_command(string.format([[ + autocmd NvimTreesitter FileType %s lua vim.api.nvim_buf_attach(0, true, {on_lines=require'nvim-treesitter.locals'.on_lines}) + ]], lang)) + end end end diff --git a/lua/nvim-treesitter/locals.lua b/lua/nvim-treesitter/locals.lua index cd8a3e306..cd0c268db 100644 --- a/lua/nvim-treesitter/locals.lua +++ b/lua/nvim-treesitter/locals.lua @@ -10,9 +10,12 @@ local M = { locals={} } +function M.is_supported(lang) + return queries.get_query(lang, "locals") ~= nil +end + function M.collect_locals(bufnr) local ft = api.nvim_buf_get_option(bufnr, "ft") - local query = queries.get_query(ft, "locals") if ft then local query = queries.get_query(ft, 'locals') @@ -33,12 +36,16 @@ function M.collect_locals(bufnr) end end -function M.on_lines(_, buf, _, firstline, lastline, new_lastline, _) +function M.on_lines(_, buf, _, firstline, lastline, new_lastline) M.locals[buf] = M.collect_locals(buf) end +function M.get_locals(bufnr) + return M.locals[bufnr or api.nvim_get_current_buf()] or {} +end + function M.get_definitions(bufnr) - local locals = M.locals[bufnr] + local locals = M.get_locals(bufnr) local defs = {} @@ -52,7 +59,7 @@ function M.get_definitions(bufnr) end function M.get_scopes(bufnr) - local locals = M.locals[bufnr] + local locals = M.get_locals(bufnr) local scopes = {} @@ -66,7 +73,7 @@ function M.get_scopes(bufnr) end function M.get_references(bufnr) - local locals = M.locals[bufnr or api.nvim_get_current_buf()] + local locals = M.get_locals(bufnr) local refs = {} -- cgit v1.2.3-70-g09d2 From 51ca6a5069d55d8ea658873cd11081a3658bdf24 Mon Sep 17 00:00:00 2001 From: Thomas Vigouroux Date: Sun, 19 Apr 2020 14:55:08 +0200 Subject: fix(matches): better storage of nodes --- lua/nvim-treesitter/query.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lua') diff --git a/lua/nvim-treesitter/query.lua b/lua/nvim-treesitter/query.lua index be650c795..e9f671f93 100644 --- a/lua/nvim-treesitter/query.lua +++ b/lua/nvim-treesitter/query.lua @@ -54,7 +54,7 @@ function M.iter_prepared_matches(query, qnode, bufnr, start_row, end_row) local name = query.captures[id] -- name of the capture in the query if name ~= nil then local path = split(name) - insert_to_path(prepared_match, path, node) + insert_to_path(prepared_match, path, { node=node }) end end -- cgit v1.2.3-70-g09d2 From 5783e7d2480663298055b86357829e61d4e27fab Mon Sep 17 00:00:00 2001 From: Thomas Vigouroux Date: Sun, 19 Apr 2020 17:31:00 +0200 Subject: style: avoid overindenting things --- lua/nvim-treesitter/locals.lua | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'lua') diff --git a/lua/nvim-treesitter/locals.lua b/lua/nvim-treesitter/locals.lua index cd0c268db..d4a23d65a 100644 --- a/lua/nvim-treesitter/locals.lua +++ b/lua/nvim-treesitter/locals.lua @@ -17,23 +17,23 @@ end function M.collect_locals(bufnr) local ft = api.nvim_buf_get_option(bufnr, "ft") - if ft then - local query = queries.get_query(ft, 'locals') - local parser = parsers.get_parser(bufnr) + if not ft then return end - if parser then - local root = parser:parse():root() - local start_row, _, end_row, _ = root:range() + local query = queries.get_query(ft, 'locals') + local parser = parsers.get_parser(bufnr) - local locals = {} + if not parser then return end - for prepared_match in queries.iter_prepared_matches(query, root, bufnr, start_row, end_row) do - table.insert(locals, prepared_match) - end + local root = parser:parse():root() + local start_row, _, end_row, _ = root:range() - return locals - end + local locals = {} + + for prepared_match in queries.iter_prepared_matches(query, root, bufnr, start_row, end_row) do + table.insert(locals, prepared_match) end + + return locals end function M.on_lines(_, buf, _, firstline, lastline, new_lastline) -- cgit v1.2.3-70-g09d2 From d169c0614c55c69afd1cc880b6bef004e4184aa7 Mon Sep 17 00:00:00 2001 From: Thomas Vigouroux Date: Sun, 19 Apr 2020 17:54:27 +0200 Subject: fix: prepare injections mechanism --- lua/nvim-treesitter/locals.lua | 2 +- lua/nvim-treesitter/parsers.lua | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'lua') diff --git a/lua/nvim-treesitter/locals.lua b/lua/nvim-treesitter/locals.lua index d4a23d65a..e58e5fc58 100644 --- a/lua/nvim-treesitter/locals.lua +++ b/lua/nvim-treesitter/locals.lua @@ -20,7 +20,7 @@ function M.collect_locals(bufnr) if not ft then return end local query = queries.get_query(ft, 'locals') - local parser = parsers.get_parser(bufnr) + local parser = parsers.get_parser(bufnr, ft) if not parser then return end diff --git a/lua/nvim-treesitter/parsers.lua b/lua/nvim-treesitter/parsers.lua index c85177733..e046ca45c 100644 --- a/lua/nvim-treesitter/parsers.lua +++ b/lua/nvim-treesitter/parsers.lua @@ -8,13 +8,17 @@ function M.has_parser(lang) return #api.nvim_get_runtime_file('parser/' .. lang .. '.*', false) > 0 end -function M.get_parser(bufnr) +function M.get_parser(bufnr, lang) if M.has_parser() then local buf = bufnr or api.nvim_get_current_buf() + local lang = lang or api.nvim_buf_get_option(buf, 'ft') if not M[buf] then - M[buf] = ts.get_parser(buf) + M[buf] = {} end - return M[buf] + if not M[buf][lang] then + M[buf][lang] = ts.get_parser(buf, lang) + end + return M[buf][lang] end end -- cgit v1.2.3-70-g09d2 From d25549917de8047eb91d6f56ee2bdcd5e667d6ae Mon Sep 17 00:00:00 2001 From: Thomas Vigouroux Date: Sun, 19 Apr 2020 19:36:26 +0200 Subject: perf: don't compute locals on buffer updates Instead we lazily evaluate them on request. This allow two things : * better performances * being sure the locas are up to date --- lua/nvim-treesitter.lua | 6 ------ lua/nvim-treesitter/locals.lua | 20 +++++++++++--------- 2 files changed, 11 insertions(+), 15 deletions(-) (limited to 'lua') diff --git a/lua/nvim-treesitter.lua b/lua/nvim-treesitter.lua index ef6c31506..8dae7c33b 100644 --- a/lua/nvim-treesitter.lua +++ b/lua/nvim-treesitter.lua @@ -9,12 +9,6 @@ local M = {} -- this is the main interface through the plugin function M.setup(lang) if parsers.has_parser(lang) then - if locals.is_supported(lang) then - print("Locals setup for", lang) - api.nvim_command(string.format([[ - autocmd NvimTreesitter FileType %s lua vim.api.nvim_buf_attach(0, true, {on_lines=require'nvim-treesitter.locals'.on_lines}) - ]], lang)) - end end end diff --git a/lua/nvim-treesitter/locals.lua b/lua/nvim-treesitter/locals.lua index e58e5fc58..808b0f3ff 100644 --- a/lua/nvim-treesitter/locals.lua +++ b/lua/nvim-treesitter/locals.lua @@ -10,18 +10,14 @@ local M = { locals={} } -function M.is_supported(lang) - return queries.get_query(lang, "locals") ~= nil -end - function M.collect_locals(bufnr) local ft = api.nvim_buf_get_option(bufnr, "ft") - if not ft then return end local query = queries.get_query(ft, 'locals') - local parser = parsers.get_parser(bufnr, ft) + if not query then return end + local parser = parsers.get_parser(bufnr, ft) if not parser then return end local root = parser:parse():root() @@ -36,12 +32,18 @@ function M.collect_locals(bufnr) return locals end -function M.on_lines(_, buf, _, firstline, lastline, new_lastline) - M.locals[buf] = M.collect_locals(buf) +local function update_cached_locals(bufnr, changed_tick) + M.locals[bufnr] = {tick=changed_tick, cache=( M.collect_locals(bufnr) or {} )} end function M.get_locals(bufnr) - return M.locals[bufnr or api.nvim_get_current_buf()] or {} + local bufnr = bufnr or api.nvim_get_current_buf() + local cached_local = M.locals[bufnr] + if not cached_local or api.nvim_buf_get_changedtick(bufnr) < cached_local.tick then + update_cached_locals(bufnr,api.nvim_buf_get_changedtick(bufnr)) + end + + return M.locals[bufnr].cache end function M.get_definitions(bufnr) -- cgit v1.2.3-70-g09d2