Scheme help with Tree Sitter symbol queries

I’m admittedly new to Scheme and running into a few issues when trying to create symbols. Right now I’m trying to create symbols for impl blocks (collection of methods) and here’s what I have for methods that don’t implement a trait (interface):

((impl_item
    type: (type_identifier) @name @displayname
    !trait) @subtree
(#set! role category)
(#append! @displayname " methods"))

The main issue here is that " methods" isn’t appended to the displayed name. Is the append! predicate not allowed for display names and I should opt for a display name query?

Next up I have the inverse, where the method(s) implement a specific trait (interface):

((impl_item
    type: (type_identifier) @name
    trait: (_) 
    ) @displayname.target @subtree
(#set! role category)
(#set! displayname.query "symbols/impl_item.scm"))

This results in breaking symbol queries so no symbols are shown and this error appears in the Extension Console:

[rust] Error evaluating structure query: Invalid structure:
    trait: (_)) @displayname.target @subtree
~~~~^

This is my Scheme ignorance showing, but that looked like a valid query to me. Can anyone help me fix this error?

For my final issue, if I ignore the trait field to have my display name queries run, then with the following queries:

((impl_item
    type: (type_identifier) @result)
(#append! @result ": "))

(impl_item
    trait: (type_identifier) @result)

…an example impl block of impl Default for MyStruct {} becomes:

DefaultMyStruct:

Whereas I was targeting

MyStruct: Default

I take it the display name isn’t assembled according to the order of my queries, but rather according to the order nodes show up in the syntax tree?

I wonder if you figure out this one.

Im also trying to get my hands dirty with tree-sitter and Nova’s “symbols.scm”

Seems like predicates (the #set, #append, #replace, etc) are not handled directly by the Tree-sitter C library and are implemented by Nova. I found a hint of that on the Tree-sitter documentation and just searching the tree-sitter repo for more clues.

I was never able to get “append” or “replace” to work even on the most basic symbols that I know are working.

I notice that Nova always uses “displayname.query” when modifying a symbol name, I was unable to find a single transformation predicate in theirs symbols.scm files except for strip used on docs.

I found useful tree-sitter cli parse and query commands.

tree-sitter query ../Queries/symbols.scm ../test.js
tree-sitter parse ../test.js

With that you can check if “trait” is in fact a named field for “impl_item”.

It seems nova picks very specific things from the query results.

I’m using Nova’s Inspector tool, so I know it sees the trait field:

I find it weird that it works to query if the field is missing (!trait) but fails when querying if the field is set with anything (trait: (_)).

Cool that you verified that #append! doesn’t seem to work for @displayname ! I guess I’ll have to create a query file for any custom display names.

I (mostly) found the answers to my questions.

  • As @ctkjose pointed out, #append! predicate works in a display name query
  • Naming query captures/results are displayed in document order. I wasn’t able to rearrange components of a symbol name.
  • I had better results when I combined shallow symbol queries with deeper naming queries (details follow)

I still don’t fully grok Scheme and Tree Sitter queries, but the solution to my above “invalid structure” error was to remove the type field I was using to capture @name, and instead capturing it in a naming query. So, these were my queries:

symbols/symbols.scm (main symbols query file)

; methods that aren't trait implementations
((impl_item
    type: (type_identifier) @name
    !trait) @subtree @displayname.target
(#set! role category)
(#set! displayname.query "symbols/impl_item.scm"))

; trait implementations
((impl_item
    trait: (_)) @name.target @displayname.target @subtree
(#set! role category)
(#set! name.query "symbols/impl_trait_name.scm")
(#set! displayname.query "symbols/impl_trait_display.scm"))

symbols/impl_item.scm - display name query for “plain” methods

((impl_item
    type: (type_identifier) @result)
(#append! @result " methods"))

symbols/impl_trait_name.scm - name query for trait implementations

((impl_item
    type: (type_identifier) @result))

symbols/impl_trait_display.scm - display name query for trait impementation


((impl_item
    type: (type_identifier) @result)
(#prefix! @result " (")
(#append! @result ")"))

((impl_item
    trait: (type_identifier) @result)
(#append! @result " trait"))

((impl_item
    trait: (generic_type) @result)
(#append! @result " trait"))

The results look like this, with methods (and types) nested under these nicely named “categories”:

1 Like

One small note – @logan in the docs the name query example is currently a display name example. A very minor thing that’s easy to puzzle out :wink: but I figured Panic might like to know.