aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua/vim/treesitter.lua
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/lua/vim/treesitter.lua')
-rw-r--r--runtime/lua/vim/treesitter.lua64
1 files changed, 38 insertions, 26 deletions
diff --git a/runtime/lua/vim/treesitter.lua b/runtime/lua/vim/treesitter.lua
index db544c1ab1..ed7d31e1f7 100644
--- a/runtime/lua/vim/treesitter.lua
+++ b/runtime/lua/vim/treesitter.lua
@@ -76,36 +76,48 @@ end
---
--- If needed, this will create the parser.
---
+--- If no parser can be created, an error is thrown. Set `opts.error = false` to suppress this and
+--- return nil (and an error message) instead. WARNING: This behavior will become default in Nvim
+--- 0.12 and the option will be removed.
+---
---@param bufnr (integer|nil) Buffer the parser should be tied to (default: current buffer)
---@param lang (string|nil) Language of this parser (default: from buffer filetype)
---@param opts (table|nil) Options to pass to the created language tree
---
----@return vim.treesitter.LanguageTree object to use for parsing
+---@return vim.treesitter.LanguageTree? object to use for parsing
+---@return string? error message, if applicable
function M.get_parser(bufnr, lang, opts)
opts = opts or {}
+ local should_error = opts.error == nil or opts.error
if bufnr == nil or bufnr == 0 then
bufnr = api.nvim_get_current_buf()
end
if not valid_lang(lang) then
- lang = M.language.get_lang(vim.bo[bufnr].filetype) or vim.bo[bufnr].filetype
+ lang = M.language.get_lang(vim.bo[bufnr].filetype)
end
if not valid_lang(lang) then
if not parsers[bufnr] then
- error(
- string.format(
- 'There is no parser available for buffer %d and one could not be'
- .. ' created because lang could not be determined. Either pass lang'
- .. ' or set the buffer filetype',
- bufnr
- )
- )
+ local err_msg =
+ string.format('Parser not found for buffer %s: language could not be determined', bufnr)
+ if should_error then
+ error(err_msg)
+ end
+ return nil, err_msg
end
elseif parsers[bufnr] == nil or parsers[bufnr]:lang() ~= lang then
- assert(lang, 'lang should be valid')
- parsers[bufnr] = M._create_parser(bufnr, lang, opts)
+ local parser = vim.F.npcall(M._create_parser, bufnr, lang, opts)
+ if not parser then
+ local err_msg =
+ string.format('Parser could not be created for buffer %s and language "%s"', bufnr, lang)
+ if should_error then
+ error(err_msg)
+ end
+ return nil, err_msg
+ end
+ parsers[bufnr] = parser
end
parsers[bufnr]:register_cbs(opts.buf_attach_cbs)
@@ -140,16 +152,8 @@ function M.is_ancestor(dest, source)
return false
end
- local current = source ---@type TSNode?
- while current ~= nil do
- if current == dest then
- return true
- end
-
- current = current:parent()
- end
-
- return false
+ -- child_containing_descendant returns nil if dest is a direct parent
+ return source:parent() == dest or dest:child_containing_descendant(source) ~= nil
end
--- Returns the node's range or an unpacked range table
@@ -257,7 +261,7 @@ end
---@param row integer Position row
---@param col integer Position column
---
----@return {capture: string, lang: string, metadata: table}[]
+---@return {capture: string, lang: string, metadata: vim.treesitter.query.TSMetadata}[]
function M.get_captures_at_pos(bufnr, row, col)
if bufnr == 0 then
bufnr = api.nvim_get_current_buf()
@@ -335,13 +339,16 @@ end
---
--- 0-indexed (row, col) tuple. Defaults to cursor position in the
--- current window. Required if {bufnr} is not the current buffer
---- @field pos { [1]: integer, [2]: integer }?
+--- @field pos [integer, integer]?
---
--- Parser language. (default: from buffer filetype)
--- @field lang string?
---
--- Ignore injected languages (default true)
--- @field ignore_injections boolean?
+---
+--- Include anonymous nodes (default false)
+--- @field include_anonymous boolean?
--- Returns the smallest named node at the given position
---
@@ -383,11 +390,14 @@ function M.get_node(opts)
local ts_range = { row, col, row, col }
- local root_lang_tree = M.get_parser(bufnr, opts.lang)
+ local root_lang_tree = M.get_parser(bufnr, opts.lang, { error = false })
if not root_lang_tree then
return
end
+ if opts.include_anonymous then
+ return root_lang_tree:node_for_range(ts_range, opts)
+ end
return root_lang_tree:named_node_for_range(ts_range, opts)
end
@@ -413,7 +423,7 @@ end
---@param lang (string|nil) Language of the parser (default: from buffer filetype)
function M.start(bufnr, lang)
bufnr = bufnr or api.nvim_get_current_buf()
- local parser = M.get_parser(bufnr, lang)
+ local parser = assert(M.get_parser(bufnr, lang, { error = false }))
M.highlighter.new(parser)
end
@@ -437,6 +447,7 @@ end
---
--- Can also be shown with `:InspectTree`. [:InspectTree]()
---
+---@since 11
---@param opts table|nil Optional options table with the following possible keys:
--- - lang (string|nil): The language of the source buffer. If omitted, detect
--- from the filetype of the source buffer.
@@ -460,6 +471,7 @@ end
--- vim.wo.foldexpr = 'v:lua.vim.treesitter.foldexpr()'
--- ```
---
+---@since 11
---@param lnum integer|nil Line number to calculate fold level for
---@return string
function M.foldexpr(lnum)