diff --git a/runtime/doc/treesitter.txt b/runtime/doc/treesitter.txt index 805876172d..f9a98250ea 100644 --- a/runtime/doc/treesitter.txt +++ b/runtime/doc/treesitter.txt @@ -1150,8 +1150,13 @@ get_lang({filetype}) *vim.treesitter.language.get_lang()* inspect({lang}) *vim.treesitter.language.inspect()* Inspects the provided language. - Inspecting provides some useful information on the language like node - names, ... + Inspecting provides some useful information on the language like node and + field names, ABI version, and whether the language came from a WASM + module. + + Node names are returned in a table mapping each node name to a `boolean` + indicating whether or not the node is named (i.e., not anonymous). + Anonymous nodes are surrounded with double quotes (`"`). Parameters: ~ • {lang} (`string`) Language diff --git a/runtime/lua/vim/treesitter/_query_linter.lua b/runtime/lua/vim/treesitter/_query_linter.lua index c5e4b86e1e..a825505378 100644 --- a/runtime/lua/vim/treesitter/_query_linter.lua +++ b/runtime/lua/vim/treesitter/_query_linter.lua @@ -240,8 +240,12 @@ function M.omnifunc(findstart, base) table.insert(items, text) end end - for _, s in pairs(parser_info.symbols) do - local text = s[2] and s[1] or string.format('%q', s[1]):gsub('\n', 'n') ---@type string + for text, named in + pairs(parser_info.symbols --[[@as table]]) + do + if not named then + text = string.format('%q', text:sub(2, -2)):gsub('\n', 'n') ---@type string + end if text:find(base, 1, true) then table.insert(items, text) end diff --git a/runtime/lua/vim/treesitter/language.lua b/runtime/lua/vim/treesitter/language.lua index 9f7807e036..aa1d38df97 100644 --- a/runtime/lua/vim/treesitter/language.lua +++ b/runtime/lua/vim/treesitter/language.lua @@ -170,7 +170,12 @@ end --- Inspects the provided language. --- ---- Inspecting provides some useful information on the language like node names, ... +--- Inspecting provides some useful information on the language like node and field names, ABI +--- version, and whether the language came from a WASM module. +--- +--- Node names are returned in a table mapping each node name to a `boolean` indicating whether or +--- not the node is named (i.e., not anonymous). Anonymous nodes are surrounded with double quotes +--- (`"`). --- ---@param lang string Language ---@return table diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c index 819ec41390..3ceb21b61a 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -271,12 +271,16 @@ int tslua_inspect_lang(lua_State *L) // not used by the API continue; } - lua_createtable(L, 2, 0); // [retval, symbols, elem] - lua_pushstring(L, ts_language_symbol_name(lang, (TSSymbol)i)); - lua_rawseti(L, -2, 1); - lua_pushboolean(L, t == TSSymbolTypeRegular); - lua_rawseti(L, -2, 2); // [retval, symbols, elem] - lua_rawseti(L, -2, (int)i); // [retval, symbols] + const char *name = ts_language_symbol_name(lang, (TSSymbol)i); + bool named = t == TSSymbolTypeRegular; + lua_pushboolean(L, named); // [retval, symbols, is_named] + if (!named) { + char buf[256]; + snprintf(buf, sizeof(buf), "\"%s\"", name); + lua_setfield(L, -2, buf); // [retval, symbols] + } else { + lua_setfield(L, -2, name); // [retval, symbols] + } } lua_setfield(L, -2, "symbols"); // [retval] diff --git a/test/functional/treesitter/language_spec.lua b/test/functional/treesitter/language_spec.lua index e1e34fcecc..633a2dc725 100644 --- a/test/functional/treesitter/language_spec.lua +++ b/test/functional/treesitter/language_spec.lua @@ -51,7 +51,7 @@ describe('treesitter language API', function() it('inspects language', function() local keys, fields, symbols = unpack(exec_lua(function() local lang = vim.treesitter.language.inspect('c') - local keys, symbols = {}, {} + local keys = {} for k, v in pairs(lang) do if type(v) == 'boolean' then keys[k] = v @@ -60,12 +60,7 @@ describe('treesitter language API', function() end end - -- symbols array can have "holes" and is thus not a valid msgpack array - -- but we don't care about the numbers here (checked in the parser test) - for _, v in pairs(lang.symbols) do - table.insert(symbols, v) - end - return { keys, lang.fields, symbols } + return { keys, lang.fields, lang.symbols } end)) eq({ fields = true, symbols = true, _abi_version = true, _wasm = false }, keys) @@ -79,16 +74,19 @@ describe('treesitter language API', function() eq(true, fset['initializer']) local has_named, has_anonymous - for _, s in pairs(symbols) do - eq('string', type(s[1])) - eq('boolean', type(s[2])) - if s[1] == 'for_statement' and s[2] == true then + for symbol, named in pairs(symbols) do + eq('string', type(symbol)) + eq('boolean', type(named)) + if symbol == 'for_statement' and named == true then has_named = true - elseif s[1] == '|=' and s[2] == false then + elseif symbol == '"|="' and named == false then has_anonymous = true end end - eq({ true, true }, { has_named, has_anonymous }) + eq( + { has_named = true, has_anonymous = true }, + { has_named = has_named, has_anonymous = has_anonymous } + ) end) it( diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua index c8829f4785..2f8d204d36 100644 --- a/test/functional/treesitter/parser_spec.lua +++ b/test/functional/treesitter/parser_spec.lua @@ -42,13 +42,13 @@ describe('treesitter parser API', function() eq('function_definition', exec_lua('return child:type()')) eq(true, exec_lua('return child:named()')) eq('number', type(exec_lua('return child:symbol()'))) - eq({ 'function_definition', true }, exec_lua('return lang.symbols[child:symbol()]')) + eq(true, exec_lua('return lang.symbols[child:type()]')) exec_lua('anon = root:descendant_for_range(0,8,0,9)') eq('(', exec_lua('return anon:type()')) eq(false, exec_lua('return anon:named()')) eq('number', type(exec_lua('return anon:symbol()'))) - eq({ '(', false }, exec_lua('return lang.symbols[anon:symbol()]')) + eq(false, exec_lua([=[return lang.symbols[string.format('"%s"', anon:type())]]=])) exec_lua('descendant = root:descendant_for_range(1,2,1,12)') eq('', exec_lua('return tostring(descendant)'))