language.lua 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. local api = vim.api
  2. local M = {}
  3. ---@type table<string,string>
  4. local ft_to_lang = {
  5. help = 'vimdoc',
  6. }
  7. --- Returns the filetypes for which a parser named {lang} is used.
  8. ---
  9. --- The list includes {lang} itself plus all filetypes registered via
  10. --- |vim.treesitter.language.register()|.
  11. ---
  12. --- @param lang string Name of parser
  13. --- @return string[] filetypes
  14. function M.get_filetypes(lang)
  15. local r = { lang } ---@type string[]
  16. for ft, p in pairs(ft_to_lang) do
  17. if p == lang then
  18. r[#r + 1] = ft
  19. end
  20. end
  21. return r
  22. end
  23. --- Returns the language name to be used when loading a parser for {filetype}.
  24. ---
  25. --- If no language has been explicitly registered via |vim.treesitter.language.register()|,
  26. --- default to {filetype}. For composite filetypes like `html.glimmer`, only the main filetype is
  27. --- returned.
  28. ---
  29. --- @param filetype string
  30. --- @return string|nil
  31. function M.get_lang(filetype)
  32. if filetype == '' then
  33. return
  34. end
  35. if ft_to_lang[filetype] then
  36. return ft_to_lang[filetype]
  37. end
  38. -- for subfiletypes like html.glimmer use only "main" filetype
  39. filetype = vim.split(filetype, '.', { plain = true })[1]
  40. return ft_to_lang[filetype] or filetype
  41. end
  42. ---@deprecated
  43. function M.require_language(lang, path, silent, symbol_name)
  44. vim.deprecate(
  45. 'vim.treesitter.language.require_language()',
  46. 'vim.treesitter.language.add()',
  47. '0.12'
  48. )
  49. local opts = {
  50. silent = silent,
  51. path = path,
  52. symbol_name = symbol_name,
  53. }
  54. if silent then
  55. local installed = pcall(M.add, lang, opts)
  56. return installed
  57. end
  58. return M.add(lang, opts)
  59. end
  60. --- Load wasm or native parser (wrapper)
  61. --- todo(clason): move to C
  62. ---
  63. ---@param path string Path of parser library
  64. ---@param lang string Language name
  65. ---@param symbol_name? string Internal symbol name for the language to load (default lang)
  66. ---@return boolean? True if parser is loaded
  67. local function loadparser(path, lang, symbol_name)
  68. if vim.endswith(path, '.wasm') then
  69. return vim._ts_add_language_from_wasm and vim._ts_add_language_from_wasm(path, lang)
  70. else
  71. return vim._ts_add_language_from_object(path, lang, symbol_name)
  72. end
  73. end
  74. ---@class vim.treesitter.language.add.Opts
  75. ---@inlinedoc
  76. ---
  77. ---Optional path the parser is located at
  78. ---@field path? string
  79. ---
  80. ---Internal symbol name for the language to load
  81. ---@field symbol_name? string
  82. --- Load parser with name {lang}
  83. ---
  84. --- Parsers are searched in the `parser` runtime directory, or the provided {path}.
  85. --- Can be used to check for available parsers before enabling treesitter features, e.g.,
  86. --- ```lua
  87. --- if vim.treesitter.language.add('markdown') then
  88. --- vim.treesitter.start(bufnr, 'markdown')
  89. --- end
  90. --- ```
  91. ---
  92. ---@param lang string Name of the parser (alphanumerical and `_` only)
  93. ---@param opts? vim.treesitter.language.add.Opts Options:
  94. ---@return boolean? True if parser is loaded
  95. ---@return string? Error if parser cannot be loaded
  96. function M.add(lang, opts)
  97. opts = opts or {}
  98. local path = opts.path
  99. local symbol_name = opts.symbol_name
  100. vim.validate('lang', lang, 'string')
  101. vim.validate('path', path, 'string', true)
  102. vim.validate('symbol_name', symbol_name, 'string', true)
  103. -- parser names are assumed to be lowercase (consistent behavior on case-insensitive file systems)
  104. lang = lang:lower()
  105. if vim._ts_has_language(lang) then
  106. return true
  107. end
  108. if path == nil then
  109. -- allow only safe language names when looking for libraries to load
  110. if not (lang and lang:match('[%w_]+') == lang) then
  111. return nil, string.format('Invalid language name "%s"', lang)
  112. end
  113. local fname = 'parser/' .. lang .. '.*'
  114. local paths = api.nvim_get_runtime_file(fname, false)
  115. if #paths == 0 then
  116. return nil, string.format('No parser for language "%s"', lang)
  117. end
  118. path = paths[1]
  119. end
  120. return loadparser(path, lang, symbol_name) or nil,
  121. string.format('Cannot load parser %s for language "%s"', path, lang)
  122. end
  123. --- @param x string|string[]
  124. --- @return string[]
  125. local function ensure_list(x)
  126. if type(x) == 'table' then
  127. return x
  128. end
  129. return { x }
  130. end
  131. --- Register a parser named {lang} to be used for {filetype}(s).
  132. ---
  133. --- Note: this adds or overrides the mapping for {filetype}, any existing mappings from other
  134. --- filetypes to {lang} will be preserved.
  135. ---
  136. --- @param lang string Name of parser
  137. --- @param filetype string|string[] Filetype(s) to associate with lang
  138. function M.register(lang, filetype)
  139. vim.validate('lang', lang, 'string')
  140. vim.validate('filetype', filetype, { 'string', 'table' })
  141. for _, f in ipairs(ensure_list(filetype)) do
  142. if f ~= '' then
  143. ft_to_lang[f] = lang
  144. end
  145. end
  146. end
  147. --- Inspects the provided language.
  148. ---
  149. --- Inspecting provides some useful information on the language like node and field names, ABI
  150. --- version, and whether the language came from a WASM module.
  151. ---
  152. --- Node names are returned in a table mapping each node name to a `boolean` indicating whether or
  153. --- not the node is named (i.e., not anonymous). Anonymous nodes are surrounded with double quotes
  154. --- (`"`).
  155. ---
  156. ---@param lang string Language
  157. ---@return table
  158. function M.inspect(lang)
  159. M.add(lang)
  160. return vim._ts_inspect_language(lang)
  161. end
  162. return M