You are a Treesiter Query Assistant specializing in generating and testing Tree-sitter textobject queries. Your expertise includes:
- Understanding Tree-sitter syntax and query patterns
- Creating queries for different programming languages
- Testing and debugging Tree-sitter queries
- Understanding Abstract Syntax Tree (AST) structures
When a user asks for a query:
- Generate a comprehensive Tree-sitter query based on their requirements
- Save the user's code to a temporary file
- Use tree-sitter-debugger to view the Tree-sitter parse tree of the code
- Test the query against the code using tree-sitter-debugger
- Provide the results along with explanations
Supported languages:
- bash
- c
- cpp
- css
- go
- html
- java
- javascript
- js
- php
- py
- python
- ruby
- rust
- ts
- tsx
- typescript
- yaml
- yml
Example: <user_query> I need a query to select conditional statement in golang </user_query>
(if_statement consequence: (block) @conditional.inner) @conditional.outer(if_statement alternative: (block) @conditional.inner)? @conditional.outer
(expression_switch_statement (expression_case) @conditional.inner) @conditional.outer
(type_switch_statement (type_case) @conditional.inner) @conditional.outer
(select_statement (communication_case) @conditional.inner) @conditional.outer
Always remember to:
- View the tree structure first to understand the syntax nodes
- Test queries thoroughly before presenting results
- Explain the query and how it matches the code
- Suggest improvements or alternatives if the query doesn't work as expected
- Keep the query simple and generic, do not be too specific. See the examples above
- Only provide simple inner and outer textobjects
- Give just the queries at the end of the session
- Never include comments in your query
golang loop textobj
I'll create Tree-sitter textobject queries for loops in Golang. First, let's understand the structure of different loop types in Go by examining their parse tree structure.
Tool Calls
Tool: show_tree_structure
(ID: tooluse_PzOeCujKQ8iAgef4XeC3UA
)
language
: go
content
package main
func main() {
// for loop
for i := 0; i < 10; i++ {
println(i)
}
// while-style loop
j := 0
for j < 10 {
println(j)
j++
}
// infinite loop
for {
break
}
// range loop
nums := []int{1, 2, 3}
for index, value := range nums {
println(index, value)
}
}
Tool Result (for call tooluse_PzOeCujKQ8iAgef4XeC3UA
, tool show_tree_structure
):
Command: tree-sitter-debugger --lang go
Output:
(source_file
(package_clause
"package"
(package_identifier "main")
)
"\n\n"
(function_declaration
"func"
(identifier "main")
(parameter_list
"("
")"
)
(block
"{"
(comment "// for loop")
(for_statement
"for"
(for_clause
(short_var_declaration
(expression_list
(identifier "i")
)
":="
(expression_list
(int_literal "0")
)
)
";"
(binary_expression
(identifier "i")
"<"
(int_literal "10")
)
";"
(inc_statement
(identifier "i")
"++"
)
)
(block
"{"
(expression_statement
(call_expression
(identifier "println")
(argument_list
"("
(identifier "i")
")"
)
)
)
"\n"
"}"
)
)
"\n"
(comment "// while-style loop")
(short_var_declaration
(expression_list
(identifier "j")
)
":="
(expression_list
(int_literal "0")
)
)
"\n"
(for_statement
"for"
(binary_expression
(identifier "j")
"<"
(int_literal "10")
)
(block
"{"
(expression_statement
(call_expression
(identifier "println")
(argument_list
"("
(identifier "j")
")"
)
)
)
"\n"
(inc_statement
(identifier "j")
"++"
)
"\n"
"}"
)
)
"\n"
(comment "// infinite loop")
(for_statement
"for"
(block
"{"
(break_statement
"break"
)
"\n"
"}"
)
)
"\n"
(comment "// range loop")
(short_var_declaration
(expression_list
(identifier "nums")
)
":="
(expression_list
(composite_literal
(slice_type
"["
"]"
(type_identifier "int")
)
(literal_value
"{"
(literal_element
(int_literal "1")
)
","
(literal_element
(int_literal "2")
)
","
(literal_element
(int_literal "3")
)
"}"
)
)
)
)
"\n"
(for_statement
"for"
(range_clause
(expression_list
(identifier "index")
","
(identifier "value")
)
":="
"range"
(identifier "nums")
)
(block
"{"
(expression_statement
(call_expression
(identifier "println")
(argument_list
"("
(identifier "index")
","
(identifier "value")
")"
)
)
)
"\n"
"}"
)
)
"\n"
"}"
)
)
)
Now that I can see the parse tree structure for various loop types in Go, I'll create textobject queries for them. In Go, there are several types of loops:
- Standard for loops (with init, condition, update)
- While-style loops (just condition)
- Infinite loops (no condition)
- Range-based loops (for ... range)
Let's create queries for these loops and test them:
Tool Calls
Tool: run_query
(ID: tooluse_yRje5DbmRlq_KAmPXCzM-Q
)
language
: go
content
package main
func main() {
// for loop
for i := 0; i < 10; i++ {
println(i)
}
// while-style loop
j := 0
for j < 10 {
println(j)
j++
}
// infinite loop
for {
break
}
// range loop
nums := []int{1, 2, 3}
for index, value := range nums {
println(index, value)
}
}
query
(for_statement
(block) @loop.inner) @loop.outer
Tool Result (for call tooluse_yRje5DbmRlq_KAmPXCzM-Q
, tool run_query
):
Command: tree-sitter-debugger --lang go --query '(for_statement (block) @loop.inner) @loop.outer'
Output:
@loop.outer
start: 5:4
end: 7:5
content:
for i := 0; i < 10; i++ {
println(i)
}
@loop.inner
start: 5:28
end: 7:5
content:
{
println(i)
}
@loop.outer
start: 11:4
end: 14:5
content:
for j < 10 {
println(j)
j++
}
@loop.inner
start: 11:15
end: 14:5
content:
{
println(j)
j++
}
@loop.outer
start: 17:4
end: 19:5
content:
for {
break
}
@loop.inner
start: 17:8
end: 19:5
content:
{
break
}
@loop.outer
start: 23:4
end: 25:5
content:
for index, value := range nums {
println(index, value)
}
@loop.inner
start: 23:35
end: 25:5
content:
{
println(index, value)
}
Great! This basic query successfully matches all types of for loops in Go. The query:
(for_statement
(block) @loop.inner) @loop.outer
Captures:
@loop.outer
: The entire for statement including thefor
keyword, any conditions or clauses, and the code block@loop.inner
: Just the block (code between curly braces)
Let's refine this to be more specific for different loop types:
Tool Calls
Tool: run_query
(ID: tooluse_V0pcEL48QmGJVkFA2WbYEA
)
language
: go
content
package main
func main() {
// for loop
for i := 0; i < 10; i++ {
println(i)
}
// while-style loop
j := 0
for j < 10 {
println(j)
j++
}
// infinite loop
for {
break
}
// range loop
nums := []int{1, 2, 3}
for index, value := range nums {
println(index, value)
}
}
query
(for_statement
(for_clause)
(block) @for_loop.inner) @for_loop.outer
(for_statement
(range_clause)
(block) @range_loop.inner) @range_loop.outer
(for_statement
condition: (_)
(block) @condition_loop.inner) @condition_loop.outer
(for_statement
(block) @infinite_loop.inner) @infinite_loop.outer
Tool Result (for call tooluse_V0pcEL48QmGJVkFA2WbYEA
, tool run_query
):
**ERROR:** Error: exit status 1
Command: tree-sitter-debugger --lang go --query '(for_statement (for_clause) (block) @for_loop.inner) @for_loop.outer (for_statement (range_clause) (block) @range_loop.inner) @range_loop.outer (for_statement condition: (_) (block) @condition_loop.inner) @condition_loop.outer (for_statement (block) @infinite_loop.inner) @infinite_loop.outer'
Output: Error executing query: invalid query: invalid unknown at line 1 column 0
condition: (_) (block) @condition_loop.inner) @condition_loop.outer (for_statement (block) @infinite_loop.inner) @infinite_loop.outer
^
I see the error in my query. Let me correct it by removing the field name that isn't in the AST:
Tool Calls
Tool: run_query
(ID: tooluse_cMmgip99SD2LUxp7CVf7pA
)
content
package main
func main() {
// for loop
for i := 0; i < 10; i++ {
println(i)
}
// while-style loop
j := 0
for j < 10 {
println(j)
j++
}
// infinite loop
for {
break
}
// range loop
nums := []int{1, 2, 3}
for index, value := range nums {
println(index, value)
}
}
query
(for_statement
(for_clause)
(block) @for_loop.inner) @for_loop.outer
(for_statement
(range_clause)
(block) @range_loop.inner) @range_loop.outer
language
: go
Tool Result (for call tooluse_cMmgip99SD2LUxp7CVf7pA
, tool run_query
):
Command: tree-sitter-debugger --lang go --query '(for_statement (for_clause) (block) @for_loop.inner) @for_loop.outer (for_statement (range_clause) (block) @range_loop.inner) @range_loop.outer'
Output:
@for_loop.outer
start: 5:4
end: 7:5
content:
for i := 0; i < 10; i++ {
println(i)
}
@for_loop.inner
start: 5:28
end: 7:5
content:
{
println(i)
}
@range_loop.outer
start: 23:4
end: 25:5
content:
for index, value := range nums {
println(index, value)
}
@range_loop.inner
start: 23:35
end: 25:5
content:
{
println(index, value)
}
Let's add the remaining loop types:
Tool Calls
Tool: run_query
(ID: tooluse_ZaODeiiJQm65YdtVH9NLXA
)
language
: go
content
package main
func main() {
// for loop
for i := 0; i < 10; i++ {
println(i)
}
// while-style loop
j := 0
for j < 10 {
println(j)
j++
}
// infinite loop
for {
break
}
// range loop
nums := []int{1, 2, 3}
for index, value := range nums {
println(index, value)
}
}
query
(for_statement
(_) @_cond
(block) @loop.inner) @loop.outer
(for_statement
(block) @loop.inner) @loop.outer
Tool Result (for call tooluse_ZaODeiiJQm65YdtVH9NLXA
, tool run_query
):
Command: tree-sitter-debugger --lang go --query '(for_statement (_) @_cond (block) @loop.inner) @loop.outer (for_statement (block) @loop.inner) @loop.outer'
Output:
@loop.outer
start: 5:4
end: 7:5
content:
for i := 0; i < 10; i++ {
println(i)
}
@_cond
start: 5:8
end: 5:27
content:
i := 0; i < 10; i++
@loop.inner
start: 5:28
end: 7:5
content:
{
println(i)
}
@loop.outer
start: 5:4
end: 7:5
content:
for i := 0; i < 10; i++ {
println(i)
}
@loop.inner
start: 5:28
end: 7:5
content:
{
println(i)
}
@loop.outer
start: 11:4
end: 14:5
content:
for j < 10 {
println(j)
j++
}
@_cond
start: 11:8
end: 11:14
content:
j < 10
@loop.inner
start: 11:15
end: 14:5
content:
{
println(j)
j++
}
@loop.outer
start: 11:4
end: 14:5
content:
for j < 10 {
println(j)
j++
}
@loop.inner
start: 11:15
end: 14:5
content:
{
println(j)
j++
}
@loop.outer
start: 17:4
end: 19:5
content:
for {
break
}
@loop.inner
start: 17:8
end: 19:5
content:
{
break
}
@loop.outer
start: 23:4
end: 25:5
content:
for index, value := range nums {
println(index, value)
}
@_cond
start: 23:8
end: 23:34
content:
index, value := range nums
@loop.inner
start: 23:35
end: 25:5
content:
{
println(index, value)
}
@loop.outer
start: 23:4
end: 25:5
content:
for index, value := range nums {
println(index, value)
}
@loop.inner
start: 23:35
end: 25:5
content:
{
println(index, value)
}
I notice there are some duplications in the captures because both patterns are matching. Let me create a more precise set of queries for different loop types:
Tool Calls
Tool: run_query
(ID: tooluse_-0K6bGbHRIKQT6DbpOEvYw
)
language
: go
content
package main
func main() {
// for loop
for i := 0; i < 10; i++ {
println(i)
}
// while-style loop
j := 0
for j < 10 {
println(j)
j++
}
// infinite loop
for {
break
}
// range loop
nums := []int{1, 2, 3}
for index, value := range nums {
println(index, value)
}
}
query
(for_statement
(block) @loop.inner) @loop.outer
Tool Result (for call tooluse_-0K6bGbHRIKQT6DbpOEvYw
, tool run_query
):
Command: tree-sitter-debugger --lang go --query '(for_statement (block) @loop.inner) @loop.outer'
Output:
@loop.outer
start: 5:4
end: 7:5
content:
for i := 0; i < 10; i++ {
println(i)
}
@loop.inner
start: 5:28
end: 7:5
content:
{
println(i)
}
@loop.outer
start: 11:4
end: 14:5
content:
for j < 10 {
println(j)
j++
}
@loop.inner
start: 11:15
end: 14:5
content:
{
println(j)
j++
}
@loop.outer
start: 17:4
end: 19:5
content:
for {
break
}
@loop.inner
start: 17:8
end: 19:5
content:
{
break
}
@loop.outer
start: 23:4
end: 25:5
content:
for index, value := range nums {
println(index, value)
}
@loop.inner
start: 23:35
end: 25:5
content:
{
println(index, value)
}
Perfect! After analyzing all the loop types in Go, I can see that a simple query works well for all cases:
(for_statement
(block) @loop.inner) @loop.outer
This query captures all types of loops in Go:
- Traditional for loops (with initialization, condition, and increment)
- While-style loops (just a condition)
- Infinite loops (no condition)
- Range-based loops (using
range
keyword)
For each loop:
@loop.outer
captures the entire loop statement including thefor
keyword, any conditions/clauses, and the code block@loop.inner
captures just the block content (the code between curly braces)
The query is simple and effective for all Go loop types. Since Go uses the same for
keyword for all loop constructs and they all have the same basic structure in the AST, a single pattern works well.
Here's the final textobject query for Go loops:
(for_statement
(block) @loop.inner) @loop.outer