mirror of
https://github.com/neovim/neovim.git
synced 2024-12-23 20:55:18 -07:00
feat(treesitter): start moving get_parser to return nil #30313
**Problem:** `vim.treesitter.get_parser` will throw an error if no parser can be found. - This means the caller is responsible for wrapping it in a `pcall`, which is easy to forget - It also makes it slightly harder to potentially memoize `get_parser` in the future - It's a bit unintuitive since many other `get_*` style functions conventionally return `nil` if no object is found (e.g. `get_node`, `get_lang`, `query.get`, etc.) **Solution:** Return `nil` if no parser can be found or created - This requires a function signature change, and some new assertions in places where the parser will always (or should always) be found. - This commit starts by making this change internally, since it is breaking. Eventually it will be rolled out to the public API.
This commit is contained in:
parent
8654a97006
commit
b9b408a56c
@ -9,8 +9,8 @@
|
||||
local function get_commentstring(ref_position)
|
||||
local buf_cs = vim.bo.commentstring
|
||||
|
||||
local has_ts_parser, ts_parser = pcall(vim.treesitter.get_parser)
|
||||
if not has_ts_parser then
|
||||
local ts_parser = vim.treesitter._get_parser()
|
||||
if not ts_parser then
|
||||
return buf_cs
|
||||
end
|
||||
|
||||
|
@ -74,14 +74,14 @@ end
|
||||
|
||||
--- Returns the parser for a specific buffer and attaches it to the buffer
|
||||
---
|
||||
--- If needed, this will create the parser.
|
||||
--- If needed, this will create the parser. If no parser can be found or created, returns `nil`.
|
||||
---
|
||||
---@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
|
||||
function M.get_parser(bufnr, lang, opts)
|
||||
---@return vim.treesitter.LanguageTree? object to use for parsing, or `nil` if not found
|
||||
function M._get_parser(bufnr, lang, opts)
|
||||
opts = opts or {}
|
||||
|
||||
if bufnr == nil or bufnr == 0 then
|
||||
@ -94,18 +94,14 @@ function M.get_parser(bufnr, lang, opts)
|
||||
|
||||
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
|
||||
)
|
||||
)
|
||||
return nil
|
||||
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
|
||||
return nil
|
||||
end
|
||||
parsers[bufnr] = parser
|
||||
end
|
||||
|
||||
parsers[bufnr]:register_cbs(opts.buf_attach_cbs)
|
||||
@ -113,6 +109,29 @@ function M.get_parser(bufnr, lang, opts)
|
||||
return parsers[bufnr]
|
||||
end
|
||||
|
||||
--- Returns the parser for a specific buffer and attaches it to the buffer
|
||||
---
|
||||
--- If needed, this will create the parser.
|
||||
---
|
||||
---@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
|
||||
function M.get_parser(bufnr, lang, opts)
|
||||
-- TODO(ribru17): Remove _get_parser and move that logic back here once the breaking function
|
||||
-- signature change is acceptable.
|
||||
local parser = M._get_parser(bufnr, lang, opts)
|
||||
if not parser then
|
||||
vim.notify_once(
|
||||
'WARNING: vim.treesitter.get_parser will return nil instead of raising an error in Neovim 0.12',
|
||||
vim.log.levels.WARN
|
||||
)
|
||||
error('Parser not found.')
|
||||
end
|
||||
return parser
|
||||
end
|
||||
|
||||
--- Returns a string parser
|
||||
---
|
||||
---@param str string Text to parse
|
||||
@ -386,7 +405,7 @@ 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)
|
||||
if not root_lang_tree then
|
||||
return
|
||||
end
|
||||
@ -419,7 +438,11 @@ 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 = M._get_parser(bufnr, lang)
|
||||
if not parser then
|
||||
vim.notify('No parser for the given buffer.', vim.log.levels.WARN)
|
||||
return
|
||||
end
|
||||
M.highlighter.new(parser)
|
||||
end
|
||||
|
||||
|
@ -114,7 +114,7 @@ local function compute_folds_levels(bufnr, info, srow, erow, parse_injections)
|
||||
srow = srow or 0
|
||||
erow = erow or api.nvim_buf_line_count(bufnr)
|
||||
|
||||
local parser = ts.get_parser(bufnr)
|
||||
local parser = assert(ts._get_parser(bufnr))
|
||||
|
||||
parser:parse(parse_injections and { srow, erow } or nil)
|
||||
|
||||
@ -392,7 +392,7 @@ function M.foldexpr(lnum)
|
||||
lnum = lnum or vim.v.lnum
|
||||
local bufnr = api.nvim_get_current_buf()
|
||||
|
||||
local parser = vim.F.npcall(ts.get_parser, bufnr)
|
||||
local parser = ts._get_parser(bufnr)
|
||||
if not parser then
|
||||
return '0'
|
||||
end
|
||||
|
@ -172,7 +172,7 @@ function M.lint(buf, opts)
|
||||
--- @type (table|nil)
|
||||
local parser_info = vim.F.npcall(vim.treesitter.language.inspect, lang)
|
||||
|
||||
local parser = vim.treesitter.get_parser(buf)
|
||||
local parser = assert(vim.treesitter._get_parser(buf), 'query parser not found.')
|
||||
parser:parse()
|
||||
parser:for_each_tree(function(tree, ltree)
|
||||
if ltree:lang() == 'query' then
|
||||
|
@ -76,10 +76,9 @@ end
|
||||
---
|
||||
---@package
|
||||
function TSTreeView:new(bufnr, lang)
|
||||
local ok, parser = pcall(vim.treesitter.get_parser, bufnr or 0, lang)
|
||||
if not ok then
|
||||
local err = parser --[[ @as string ]]
|
||||
return nil, 'No parser available for the given buffer:\n' .. err
|
||||
local parser = vim.treesitter._get_parser(bufnr or 0, lang)
|
||||
if not parser then
|
||||
return nil, 'No parser available for the given buffer.'
|
||||
end
|
||||
|
||||
-- For each child tree (injected language), find the root of the tree and locate the node within
|
||||
@ -539,7 +538,7 @@ local edit_ns = api.nvim_create_namespace('treesitter/dev-edit')
|
||||
local function update_editor_highlights(query_win, base_win, lang)
|
||||
local base_buf = api.nvim_win_get_buf(base_win)
|
||||
local query_buf = api.nvim_win_get_buf(query_win)
|
||||
local parser = vim.treesitter.get_parser(base_buf, lang)
|
||||
local parser = assert(vim.treesitter._get_parser(base_buf, lang))
|
||||
api.nvim_buf_clear_namespace(base_buf, edit_ns, 0, -1)
|
||||
local query_content = table.concat(api.nvim_buf_get_lines(query_buf, 0, -1, false), '\n')
|
||||
|
||||
@ -596,8 +595,8 @@ function M.edit_query(lang)
|
||||
end
|
||||
vim.cmd(cmd)
|
||||
|
||||
local ok, parser = pcall(vim.treesitter.get_parser, buf, lang)
|
||||
if not ok then
|
||||
local parser = vim.treesitter._get_parser(buf, lang)
|
||||
if not parser then
|
||||
return nil, 'No parser available for the given buffer'
|
||||
end
|
||||
lang = parser:lang()
|
||||
|
@ -33,7 +33,7 @@ end
|
||||
--- Show a table of contents for the help buffer in a loclist
|
||||
function M.show_toc()
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
local parser = vim.treesitter.get_parser(bufnr, 'vimdoc')
|
||||
local parser = assert(vim.treesitter._get_parser(bufnr, 'vimdoc'), 'vimdoc parser not found.')
|
||||
local query = vim.treesitter.query.parse(
|
||||
parser:lang(),
|
||||
[[
|
||||
|
@ -786,7 +786,7 @@ local function parse_buf(fname, parser_path)
|
||||
if parser_path then
|
||||
vim.treesitter.language.add('vimdoc', { path = parser_path })
|
||||
end
|
||||
local lang_tree = vim.treesitter.get_parser(buf)
|
||||
local lang_tree = assert(vim.treesitter._get_parser(buf), 'vimdoc parser not found.')
|
||||
return lang_tree, buf
|
||||
end
|
||||
|
||||
|
@ -8,6 +8,7 @@ local exec_lua = n.exec_lua
|
||||
local pcall_err = t.pcall_err
|
||||
local matches = t.matches
|
||||
local insert = n.insert
|
||||
local NIL = vim.NIL
|
||||
|
||||
before_each(clear)
|
||||
|
||||
@ -15,10 +16,12 @@ describe('treesitter language API', function()
|
||||
-- error tests not requiring a parser library
|
||||
it('handles missing language', function()
|
||||
eq(
|
||||
".../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers",
|
||||
'.../treesitter.lua:0: Parser not found.',
|
||||
pcall_err(exec_lua, "parser = vim.treesitter.get_parser(0, 'borklang')")
|
||||
)
|
||||
|
||||
eq(NIL, exec_lua("return vim.treesitter._get_parser(0, 'borklang')"))
|
||||
|
||||
-- actual message depends on platform
|
||||
matches(
|
||||
"Failed to load parser for language 'borklang': uv_dlopen: .+",
|
||||
@ -105,9 +108,10 @@ describe('treesitter language API', function()
|
||||
command('set filetype=borklang')
|
||||
-- Should throw an error when filetype changes to borklang
|
||||
eq(
|
||||
".../language.lua:0: no parser for 'borklang' language, see :help treesitter-parsers",
|
||||
'.../treesitter.lua:0: Parser not found.',
|
||||
pcall_err(exec_lua, "new_parser = vim.treesitter.get_parser(0, 'borklang')")
|
||||
)
|
||||
eq(NIL, exec_lua("return vim.treesitter._get_parser(0, 'borklang')"))
|
||||
end
|
||||
)
|
||||
|
||||
|
@ -135,9 +135,7 @@ void ui_refresh(void)
|
||||
insert(test_text)
|
||||
|
||||
eq(
|
||||
'.../treesitter.lua:0: There is no parser available for buffer 1 and one'
|
||||
.. ' could not be created because lang could not be determined. Either'
|
||||
.. ' pass lang or set the buffer filetype',
|
||||
'.../treesitter.lua:0: Parser not found.',
|
||||
pcall_err(exec_lua, 'vim.treesitter.get_parser(0)')
|
||||
)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user