Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Run textobject queries across injections #9320

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

the-mikedavis
Copy link
Member

Textobjects currently only work on the root layer which can be limiting for languages that use injections extensively like Vue or HTML. We can run textobject queries across all injection layers to be able to use things like ]f/[f/mif/maf/etc, for example in HTML:

#2857 has a few commits that add a function to Syntax that creates an iterator similar to tree_sitter::QueryCaptures that works across injection layers. This PR cherry-picks those commits and adds another that refactors textobject queries to use that function instead. The novel part of this PR is only the last commit. Textobject queries are relocated from LanguageConfiguration to HighlightConfiguration so they are accessible from LanguageLayer within queries. In the future, the indentation query should also be refactored like this but that has some extra work involved, see #7364.

Closes #4618 (the other half of that issue is covered by issue #2311)

@the-mikedavis the-mikedavis added C-enhancement Category: Improvements A-tree-sitter Area: Tree-sitter S-waiting-on-review Status: Awaiting review from a maintainer. labels Jan 12, 2024
@pascalkuthe
Copy link
Member

I wonder if we want to create a way to turn this back off somehow. For HTML it makes a lot of sense but if we have doc comment injections in the future I could see this making text objects less useful. For example if navigating crates with detailed documentation each function may have multiple functions in its doc comments so ]f becomes a lot less useful

@the-mikedavis
Copy link
Member Author

Ah I see what you mean, I wouldn't want to select a closure in a doc comment that's a rust codefence inside markdown for example. I think that wouldn't be too hard to add - we could add a property like (#set! injection.no-textobjects-within) to exclude those layers and all of their children recursively from the query iterator.

@pascalkuthe
Copy link
Member

Yeah exactlt. I didnt event think about closures (I always forgot ]f junps to those :D) that is an even better exampl.

A property like that sounds like a grear solution

the-mikedavis and others added 6 commits February 26, 2024 06:37
This can be used to calculate rainbow highlights (see the child commit)
or indents or textobjects and be accurate to the injected content
rather than just the root layer. This is useful for languages which
use injections heavily like Vue or JavaScript within HTML but are also
useful in common scenarios like within codeblocks in Markdown.

This iterator shares some code with the HighlightIter and
HighlightIterLayer but that iterator emits HighlightEvents, so it cares
about the beginnings and ends of highlight events rather than captures.
This is brings the fix from d5f17d3 to the QueryIter layers. A trait
for getting the cursor and sort-key from each layer helps cut down on
code duplicated between these iterators.
The code in the `sort_layers` function was fully duplicated between
the HighlightIter and the QueryIter. This change adds a common
`sort_layers` function that accepts a layer Vec from both.
This deduplicates some somewhat complex code between the highlight_iter
and query_iter.
It's easy to mistakenly use-after-free the cursor and captures iterator
here because of the transmute. Ideally this could be fixed upstream in
tree-sitter by introducing an API with lifetimes/types that reflect the
lifetimes of the underlying data.

Co-authored-by: Pascal Kuthe <[email protected]>
With this change textobjects work even within injection layers, so you
can use `]f` to jump to a function definition in a JavaScript `<script>`
tag within HTML for example.

This requires `Syntax::query_iter` - a utility function for running a
query from `HighlightConfiguration` across injection layers - which
comes from the rainbow brackets branch (merged into my driver).
We need to relocate the textobject query from the `LanguageConfiguration`
to the `HighlightConfiguration` in order to access it
per-injection-layer, like we do for the rainbow brackets query. With
that, the only necessary change is to port the contents of
`TextObjectQuery::capture_nodes_any` to a new function that uses
`query_iter` and update callers.

The callers end up being a bit cleaner: they only need to take `Syntax`
now and not `LanguageConfiguration` and the root layer's root
`tree_sitter::Node`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-tree-sitter Area: Tree-sitter C-enhancement Category: Improvements S-waiting-on-review Status: Awaiting review from a maintainer.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Multi-language documents don't benefit from navigation by tree-sitter
3 participants