From 45e606b1fddbfeee8fe28385b5371ca6f2fba71b Mon Sep 17 00:00:00 2001 From: Riley Bruins Date: Wed, 18 Dec 2024 10:48:33 -0800 Subject: feat(treesitter): async parsing **Problem:** Parsing can be slow for large files, and it is a blocking operation which can be disruptive and annoying. **Solution:** Provide a function for asynchronous parsing, which accepts a callback to be run after parsing completes. Co-authored-by: Lewis Russell Co-authored-by: Luuk van Baal Co-authored-by: VanaIgr --- runtime/doc/news.txt | 4 ++++ runtime/doc/options.txt | 4 ++-- runtime/doc/treesitter.txt | 38 +++++++++++++++++++++++++++----------- 3 files changed, 33 insertions(+), 13 deletions(-) (limited to 'runtime/doc') diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt index 4f4bfe9ecc..96f0ec1aa7 100644 --- a/runtime/doc/news.txt +++ b/runtime/doc/news.txt @@ -297,6 +297,8 @@ PERFORMANCE • Strong |treesitter-query| caching makes repeat |vim.treesitter.query.get()| and |vim.treesitter.query.parse()| calls significantly faster for large queries. +• Treesitter highlighting is now asynchronous. To force synchronous parsing, + use `vim.g._ts_force_sync_parsing = true`. PLUGINS @@ -339,6 +341,8 @@ TREESITTER • New |TSNode:child_with_descendant()|, which is nearly identical to |TSNode:child_containing_descendant()| except that it can return the descendant itself. +• |LanguageTree:parse()| optionally supports asynchronous invocation, which is + activated by passing the `on_parse` callback parameter. TUI diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 80b391d8c9..8d171183d6 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -4657,8 +4657,8 @@ A jump table for the options with a short description can be found at |Q_op|. 'redrawtime' 'rdt' number (default 2000) global Time in milliseconds for redrawing the display. Applies to - 'hlsearch', 'inccommand', |:match| highlighting and syntax - highlighting. + 'hlsearch', 'inccommand', |:match| highlighting, syntax highlighting, + and async |LanguageTree:parse()|. When redrawing takes more than this many milliseconds no further matches will be highlighted. For syntax highlighting the time applies per window. When over the diff --git a/runtime/doc/treesitter.txt b/runtime/doc/treesitter.txt index 80d8f92af2..41679f80ca 100644 --- a/runtime/doc/treesitter.txt +++ b/runtime/doc/treesitter.txt @@ -1090,6 +1090,9 @@ start({bufnr}, {lang}) *vim.treesitter.start()* required for some plugins. In this case, add `vim.bo.syntax = 'on'` after the call to `start`. + Note: By default, the highlighter parses code asynchronously, using a + segment time of 3ms. + Example: >lua vim.api.nvim_create_autocmd( 'FileType', { pattern = 'tex', callback = function(args) @@ -1401,8 +1404,8 @@ Query:iter_captures({node}, {source}, {start}, {stop}) Defaults to `node:end_()`. Return: ~ - (`fun(end_line: integer?): integer, TSNode, vim.treesitter.query.TSMetadata, TSQueryMatch`) - capture id, capture node, metadata, match + (`fun(end_line: integer?): integer, TSNode, vim.treesitter.query.TSMetadata, TSQueryMatch, TSTree`) + capture id, capture node, metadata, match, tree *Query:iter_matches()* Query:iter_matches({node}, {source}, {start}, {stop}, {opts}) @@ -1447,8 +1450,8 @@ Query:iter_matches({node}, {source}, {start}, {stop}, {opts}) compatibility and will be removed in a future release. Return: ~ - (`fun(): integer, table, vim.treesitter.query.TSMetadata`) - pattern id, match, metadata + (`fun(): integer, table, vim.treesitter.query.TSMetadata, TSTree`) + pattern id, match, metadata, tree set({lang}, {query_name}, {text}) *vim.treesitter.query.set()* Sets the runtime query named {query_name} for {lang} @@ -1611,7 +1614,7 @@ LanguageTree:node_for_range({range}, {opts}) Return: ~ (`TSNode?`) -LanguageTree:parse({range}) *LanguageTree:parse()* +LanguageTree:parse({range}, {on_parse}) *LanguageTree:parse()* Recursively parse all regions in the language tree using |treesitter-parsers| for the corresponding languages and run injection queries on the parsed trees to determine whether child trees should be @@ -1622,14 +1625,27 @@ LanguageTree:parse({range}) *LanguageTree:parse()* if {range} is `true`). Parameters: ~ - • {range} (`boolean|Range?`) Parse this range in the parser's source. - Set to `true` to run a complete parse of the source (Note: - Can be slow!) Set to `false|nil` to only parse regions with - empty ranges (typically only the root tree without - injections). + • {range} (`boolean|Range?`) Parse this range in the parser's + source. Set to `true` to run a complete parse of the + source (Note: Can be slow!) Set to `false|nil` to only + parse regions with empty ranges (typically only the root + tree without injections). + • {on_parse} (`fun(err?: string, trees?: table)?`) + Function invoked when parsing completes. When provided and + `vim.g._ts_force_sync_parsing` is not set, parsing will + run asynchronously. The first argument to the function is + a string respresenting the error type, in case of a + failure (currently only possible for timeouts). The second + argument is the list of trees returned by the parse (upon + success), or `nil` if the parse timed out (determined by + 'redrawtime'). + + If parsing was still able to finish synchronously (within + 3ms), `parse()` returns the list of trees. Otherwise, it + returns `nil`. Return: ~ - (`table`) + (`table?`) *LanguageTree:register_cbs()* LanguageTree:register_cbs({cbs}, {recursive}) -- cgit