aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua/vim
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/lua/vim')
-rw-r--r--runtime/lua/vim/fs.lua6
-rw-r--r--runtime/lua/vim/treesitter/_meta.lua4
-rw-r--r--runtime/lua/vim/treesitter/languagetree.lua67
3 files changed, 67 insertions, 10 deletions
diff --git a/runtime/lua/vim/fs.lua b/runtime/lua/vim/fs.lua
index 2a51bde263..7f9f3a2bce 100644
--- a/runtime/lua/vim/fs.lua
+++ b/runtime/lua/vim/fs.lua
@@ -73,10 +73,14 @@ function M.basename(file)
end
---@private
-local function join_paths(...)
+---@param ... string
+---@return string
+function M._join_paths(...)
return (table.concat({ ... }, '/'):gsub('//+', '/'))
end
+local join_paths = M._join_paths
+
---@alias Iterator fun(): string?, string?
--- Return an iterator over the files and directories located in {path}
diff --git a/runtime/lua/vim/treesitter/_meta.lua b/runtime/lua/vim/treesitter/_meta.lua
index c1009f5f5d..9ca4b560c6 100644
--- a/runtime/lua/vim/treesitter/_meta.lua
+++ b/runtime/lua/vim/treesitter/_meta.lua
@@ -45,6 +45,8 @@ function TSNode:_rawquery(query, captures, start, end_, opts) end
---@return fun(): string, any
function TSNode:_rawquery(query, captures, start, end_, opts) end
+---@alias TSLoggerCallback fun(logtype: 'parse'|'lex', msg: string)
+
---@class TSParser
---@field parse fun(self: TSParser, tree: TSTree?, source: integer|string, include_bytes: boolean?): TSTree, integer[]
---@field reset fun(self: TSParser)
@@ -52,6 +54,8 @@ function TSNode:_rawquery(query, captures, start, end_, opts) end
---@field set_included_ranges fun(self: TSParser, ranges: Range6[])
---@field set_timeout fun(self: TSParser, timeout: integer)
---@field timeout fun(self: TSParser): integer
+---@field _set_logger fun(self: TSParser, lex: boolean, parse: boolean, cb: TSLoggerCallback)
+---@field _logger fun(self: TSParser): TSLoggerCallback
---@class TSTree
---@field root fun(self: TSTree): TSNode
diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua
index 0efe3af85c..6c780f33c4 100644
--- a/runtime/lua/vim/treesitter/languagetree.lua
+++ b/runtime/lua/vim/treesitter/languagetree.lua
@@ -31,8 +31,17 @@
--- shouldn't be done directly in the change callback anyway as they will be very frequent. Rather
--- a plugin that does any kind of analysis on a tree should use a timer to throttle too frequent
--- updates.
+---
+
+-- Debugging:
+--
+-- vim.g.__ts_debug levels:
+-- - 1. Messages from languagetree.lua
+-- - 2. Parse messages from treesitter
+-- - 2. Lex messages from treesitter
+--
+-- Log file can be found in stdpath('log')/treesitter.log
-local api = vim.api
local query = require('vim.treesitter.query')
local language = require('vim.treesitter.language')
local Range = require('vim.treesitter._range')
@@ -75,6 +84,8 @@ local TSCallbackNames = {
---@field private _source (integer|string) Buffer or string to parse
---@field private _trees TSTree[] Reference to parsed tree (one for each language)
---@field private _valid boolean|table<integer,boolean> If the parsed tree is valid
+---@field private _logger? fun(logtype: string, msg: string)
+---@field private _logfile? file*
local LanguageTree = {}
---@class LanguageTreeOpts
@@ -114,6 +125,10 @@ function LanguageTree.new(source, lang, opts)
_callbacks_rec = {},
}, LanguageTree)
+ if vim.g.__ts_debug and type(vim.g.__ts_debug) == 'number' then
+ self:_set_logger()
+ end
+
for _, name in pairs(TSCallbackNames) do
self._callbacks[name] = {}
self._callbacks_rec[name] = {}
@@ -122,6 +137,33 @@ function LanguageTree.new(source, lang, opts)
return self
end
+function LanguageTree:_set_logger()
+ local source = self:source()
+ source = type(source) == 'string' and 'text' or tostring(source)
+
+ local lang = self:lang()
+
+ local logfilename = vim.fs._join_paths(vim.fn.stdpath('log'), 'treesitter.log')
+
+ local logfile, openerr = io.open(logfilename, 'a+')
+
+ if not logfile or openerr then
+ error(string.format('Could not open file (%s) for logging: %s', logfilename, openerr))
+ return
+ end
+
+ self._logfile = logfile
+
+ self._logger = function(logtype, msg)
+ self._logfile:write(string.format('%s:%s:(%s) %s\n', source, lang, logtype, msg))
+ self._logfile:flush()
+ end
+
+ local log_lex = vim.g.__ts_debug >= 3
+ local log_parse = vim.g.__ts_debug >= 2
+ self._parser:_set_logger(log_lex, log_parse, self._logger)
+end
+
---@private
---Measure execution time of a function
---@generic R1, R2, R3
@@ -139,7 +181,11 @@ end
---@private
---@vararg any
function LanguageTree:_log(...)
- if vim.g.__ts_debug == nil then
+ if not self._logger then
+ return
+ end
+
+ if not vim.g.__ts_debug or vim.g.__ts_debug < 1 then
return
end
@@ -150,19 +196,17 @@ function LanguageTree:_log(...)
local info = debug.getinfo(2, 'nl')
local nregions = #self:included_regions()
- local prefix =
- string.format('%s:%d: [%s:%d] ', info.name, info.currentline, self:lang(), nregions)
+ local prefix = string.format('%s:%d: (#regions=%d) ', info.name, info.currentline, nregions)
- api.nvim_out_write(prefix)
+ local msg = { prefix }
for _, x in ipairs(args) do
if type(x) == 'string' then
- api.nvim_out_write(x)
+ msg[#msg + 1] = x
else
- api.nvim_out_write(vim.inspect(x, { newline = ' ', indent = '' }))
+ msg[#msg + 1] = vim.inspect(x, { newline = ' ', indent = '' })
end
- api.nvim_out_write(' ')
end
- api.nvim_out_write('\n')
+ self._logger('nvim', table.concat(msg, ' '))
end
--- Invalidates this parser and all its children
@@ -876,6 +920,11 @@ end
function LanguageTree:_on_detach(...)
self:invalidate(true)
self:_do_callback('detach', ...)
+ if self._logfile then
+ self._logger('nvim', 'detaching')
+ self._logger = nil
+ self._logfile:close()
+ end
end
--- Registers callbacks for the |LanguageTree|.