Using https://github.com/meain/esa to create tree-sitter queries for https://github.com/meain/evil-textobj-tree-sitter using https://github.com/meain/tree-sitter-debugger
-
-
Save meain/70c6e9d113ead32c87395427cb1bd4ba to your computer and use it in GitHub Desktop.
Agent: +tree (esa/agents/tree.toml
)
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 tsg to view the Tree-sitter parse tree of the code
- Test the query against the code using tsg
- 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
golang loop textobj
I'll help you create Tree-sitter textobject queries for Golang loops. Let's first understand the structure of different loop types in Go by examining a sample code with loops.
Tool Calls
Tool: show_tree_structure
(ID: tooluse_t9kxixmsSwOuNTEtQ0oLwQ
)
language
: go
content
package main
func main() {
// For loop
for i := 0; i < 10; i++ {
println(i)
}
// For-range loop
nums := []int{1, 2, 3}
for i, num := range nums {
println(i, num)
}
// While-style for loop
j := 0
for j < 5 {
j++
}
// Infinite loop
for {
break
}
}
Tool Result (for call tooluse_t9kxixmsSwOuNTEtQ0oLwQ
, tool show_tree_structure
):
Command: tsg --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 "// For-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 "i")
","
(identifier "num")
)
":="
"range"
(identifier "nums")
)
(block
"{"
(expression_statement
(call_expression
(identifier "println")
(argument_list
"("
(identifier "i")
","
(identifier "num")
")"
)
)
)
"\n"
"}"
)
)
"\n"
(comment "// While-style for loop")
(short_var_declaration
(expression_list
(identifier "j")
)
":="
(expression_list
(int_literal "0")
)
)
"\n"
(for_statement
"for"
(binary_expression
(identifier "j")
"<"
(int_literal "5")
)
(block
"{"
(inc_statement
(identifier "j")
"++"
)
"\n"
"}"
)
)
"\n"
(comment "// Infinite loop")
(for_statement
"for"
(block
"{"
(break_statement
"break"
)
"\n"
"}"
)
)
"\n"
"}"
)
)
)
Now I'll create a query for loop textobjects in Go and test it on the sample code:
Tool Calls
Tool: run_query
(ID: tooluse_rVEvqr5DQSyiWOzTmoEwvw
)
language
: go
content
package main
func main() {
// For loop
for i := 0; i < 10; i++ {
println(i)
}
// For-range loop
nums := []int{1, 2, 3}
for i, num := range nums {
println(i, num)
}
// While-style for loop
j := 0
for j < 5 {
j++
}
// Infinite loop
for {
break
}
}
query
;; Standard for loop
(for_statement
(for_clause)
(block) @loop.inner) @loop.outer
;; For-range loop
(for_statement
(range_clause)
(block) @loop.inner) @loop.outer
;; Condition-only for loop (while-style)
(for_statement
(binary_expression)
(block) @loop.inner) @loop.outer
;; Infinite for loop
(for_statement
(block) @loop.inner) @loop.outer
Tool Result (for call tooluse_rVEvqr5DQSyiWOzTmoEwvw
, tool run_query
):
Command: tsg --lang go --query ';; Standard for loop (for_statement (for_clause) (block) @loop.inner) @loop.outer ;; For-range loop (for_statement (range_clause) (block) @loop.inner) @loop.outer ;; Condition-only for loop (while-style) (for_statement (binary_expression) (block) @loop.inner) @loop.outer ;; Infinite for loop (for_statement (block) @loop.inner) @loop.outer'
Output:
No matches found
It seems the query formatting might have issues. Let's try a simplified version:
Tool Calls
Tool: run_query
(ID: tooluse_F_M20Ev2Rc2vuw3ucNvWRw
)
content
package main
func main() {
// For loop
for i := 0; i < 10; i++ {
println(i)
}
// For-range loop
nums := []int{1, 2, 3}
for i, num := range nums {
println(i, num)
}
// While-style for loop
j := 0
for j < 5 {
j++
}
// Infinite loop
for {
break
}
}
query
(for_statement
(block) @loop.inner) @loop.outer
language
: go
Tool Result (for call tooluse_F_M20Ev2Rc2vuw3ucNvWRw
, tool run_query
):
Command: tsg --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: 13:5
content:
for i, num := range nums {
println(i, num)
}
@loop.inner
start: 11:29
end: 13:5
content:
{
println(i, num)
}
@loop.outer
start: 17:4
end: 19:5
content:
for j < 5 {
j++
}
@loop.inner
start: 17:14
end: 19:5
content:
{
j++
}
@loop.outer
start: 22:4
end: 24:5
content:
for {
break
}
@loop.inner
start: 22:8
end: 24:5
content:
{
break
}
Perfect! The basic query works for all types of Go loops. Now let's refine it to be clearer and more specific for the different loop types in Go:
Tool Calls
Tool: run_query
(ID: tooluse_8Cwybz-SRIOLpTZtEZ4TTg
)
language
: go
content
package main
func main() {
// For loop
for i := 0; i < 10; i++ {
println(i)
}
// For-range loop
nums := []int{1, 2, 3}
for i, num := range nums {
println(i, num)
}
// While-style for loop
j := 0
for j < 5 {
j++
}
// Infinite loop
for {
break
}
}
query
;; All for loops (captures all types)
(for_statement
(block) @loop.inner) @loop.outer
Tool Result (for call tooluse_8Cwybz-SRIOLpTZtEZ4TTg
, tool run_query
):
Command: tsg --lang go --query ';; All for loops (captures all types) (for_statement (block) @loop.inner) @loop.outer'
Output:
No matches found
Let's try again with a clean query without comments:
Tool Calls
Tool: run_query
(ID: tooluse_1xXyzr5lTdm_pkersUXRYA
)
language
: go
content
package main
func main() {
// For loop
for i := 0; i < 10; i++ {
println(i)
}
// For-range loop
nums := []int{1, 2, 3}
for i, num := range nums {
println(i, num)
}
// While-style for loop
j := 0
for j < 5 {
j++
}
// Infinite loop
for {
break
}
}
query
(for_statement
(block) @loop.inner) @loop.outer
Tool Result (for call tooluse_1xXyzr5lTdm_pkersUXRYA
, tool run_query
):
Command: tsg --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: 13:5
content:
for i, num := range nums {
println(i, num)
}
@loop.inner
start: 11:29
end: 13:5
content:
{
println(i, num)
}
@loop.outer
start: 17:4
end: 19:5
content:
for j < 5 {
j++
}
@loop.inner
start: 17:14
end: 19:5
content:
{
j++
}
@loop.outer
start: 22:4
end: 24:5
content:
for {
break
}
@loop.inner
start: 22:8
end: 24:5
content:
{
break
}
Great! Here's the Tree-sitter query for Go loop textobjects:
(for_statement
(block) @loop.inner) @loop.outer
This query works for all types of Go loops:
-
Standard for loops with initialization, condition, and increment:
for i := 0; i < 10; i++ { ... }
-
For-range loops:
for i, num := range nums { ... }
-
While-style loops (condition-only for loops):
for j < 5 { ... }
-
Infinite loops:
for { ... }
The query captures:
@loop.outer
: The entire for statement including the loop keyword, any conditions/clauses, and the block@loop.inner
: Just the block contents (the body of the loop)
This is a simple but effective textobject query that handles all Go loop variants with a single pattern.
do the same for rust
I'll help you create Tree-sitter textobject queries for Rust loops. Let's first understand the structure of different loop types in Rust by examining a sample code with loops.
Tool Calls
Tool: show_tree_structure
(ID: tooluse_KM0RC8GETj6EJ4uT8RQqEQ
)
language
: rust
content
fn main() {
// For loop
for i in 0..10 {
println!("{}", i);
}
// While loop
let mut j = 0;
while j < 5 {
j += 1;
}
// Loop (infinite)
loop {
break;
}
// While let loop
let mut optional = Some(0);
while let Some(i) = optional {
if i > 3 {
optional = None;
} else {
optional = Some(i + 1);
}
}
// For loop with pattern
let pairs = vec![(1, 2), (3, 4)];
for (x, y) in pairs {
println!("({}, {})", x, y);
}
}
Tool Result (for call tooluse_KM0RC8GETj6EJ4uT8RQqEQ
, tool show_tree_structure
):
Command: tsg --lang rust
Output:
(source_file
(function_item
"fn"
(identifier "main")
(parameters
"("
")"
)
(block
"{"
(line_comment
"//"
)
(expression_statement
(for_expression
"for"
(identifier "i")
"in"
(range_expression
(integer_literal "0")
".."
(integer_literal "10")
)
(block
"{"
(expression_statement
(macro_invocation
(identifier "println")
"!"
(token_tree
"("
(string_literal
"""
(string_content "{}")
"""
)
","
(identifier "i")
")"
)
)
";"
)
"}"
)
)
)
(line_comment
"//"
)
(let_declaration
"let"
(mutable_specifier "mut")
(identifier "j")
"="
(integer_literal "0")
";"
)
(expression_statement
(while_expression
"while"
(binary_expression
(identifier "j")
"<"
(integer_literal "5")
)
(block
"{"
(expression_statement
(compound_assignment_expr
(identifier "j")
"+="
(integer_literal "1")
)
";"
)
"}"
)
)
)
(line_comment
"//"
)
(expression_statement
(loop_expression
"loop"
(block
"{"
(expression_statement
(break_expression
"break"
)
";"
)
"}"
)
)
)
(line_comment
"//"
)
(let_declaration
"let"
(mutable_specifier "mut")
(identifier "optional")
"="
(call_expression
(identifier "Some")
(arguments
"("
(integer_literal "0")
")"
)
)
";"
)
(expression_statement
(while_expression
"while"
(let_condition
"let"
(tuple_struct_pattern
(identifier "Some")
"("
(identifier "i")
")"
)
"="
(identifier "optional")
)
(block
"{"
(expression_statement
(if_expression
"if"
(binary_expression
(identifier "i")
">"
(integer_literal "3")
)
(block
"{"
(expression_statement
(assignment_expression
(identifier "optional")
"="
(identifier "None")
)
";"
)
"}"
)
(else_clause
"else"
(block
"{"
(expression_statement
(assignment_expression
(identifier "optional")
"="
(call_expression
(identifier "Some")
(arguments
"("
(binary_expression
(identifier "i")
"+"
(integer_literal "1")
)
")"
)
)
)
";"
)
"}"
)
)
)
)
"}"
)
)
)
(line_comment
"//"
)
(let_declaration
"let"
(identifier "pairs")
"="
(macro_invocation
(identifier "vec")
"!"
(token_tree
"["
(token_tree
"("
(integer_literal "1")
","
(integer_literal "2")
")"
)
","
(token_tree
"("
(integer_literal "3")
","
(integer_literal "4")
")"
)
"]"
)
)
";"
)
(expression_statement
(for_expression
"for"
(tuple_pattern
"("
(identifier "x")
","
(identifier "y")
")"
)
"in"
(identifier "pairs")
(block
"{"
(expression_statement
(macro_invocation
(identifier "println")
"!"
(token_tree
"("
(string_literal
"""
(string_content "({}, {})")
"""
)
","
(identifier "x")
","
(identifier "y")
")"
)
)
";"
)
"}"
)
)
)
"}"
)
)
)
Now I'll create a query for loop textobjects in Rust and test it on the sample code:
Tool Calls
Tool: run_query
(ID: tooluse_2Hm2hAiiTSGMf-i2H5YgCA
)
language
: rust
content
fn main() {
// For loop
for i in 0..10 {
println!("{}", i);
}
// While loop
let mut j = 0;
while j < 5 {
j += 1;
}
// Loop (infinite)
loop {
break;
}
// While let loop
let mut optional = Some(0);
while let Some(i) = optional {
if i > 3 {
optional = None;
} else {
optional = Some(i + 1);
}
}
// For loop with pattern
let pairs = vec![(1, 2), (3, 4)];
for (x, y) in pairs {
println!("({}, {})", x, y);
}
}
query
(for_expression
(block) @loop.inner) @loop.outer
(while_expression
(block) @loop.inner) @loop.outer
(loop_expression
(block) @loop.inner) @loop.outer
Tool Result (for call tooluse_2Hm2hAiiTSGMf-i2H5YgCA
, tool run_query
):
Command: tsg --lang rust --query '(for_expression (block) @loop.inner) @loop.outer (while_expression (block) @loop.inner) @loop.outer (loop_expression (block) @loop.inner) @loop.outer'
Output:
@loop.outer
start: 3:4
end: 5:5
content:
for i in 0..10 {
println!("{}", i);
}
@loop.inner
start: 3:19
end: 5:5
content:
{
println!("{}", i);
}
@loop.outer
start: 9:4
end: 11:5
content:
while j < 5 {
j += 1;
}
@loop.inner
start: 9:16
end: 11:5
content:
{
j += 1;
}
@loop.outer
start: 14:4
end: 16:5
content:
loop {
break;
}
@loop.inner
start: 14:9
end: 16:5
content:
{
break;
}
@loop.outer
start: 20:4
end: 26:5
content:
while let Some(i) = optional {
if i > 3 {
optional = None;
} else {
optional = Some(i + 1);
}
}
@loop.inner
start: 20:33
end: 26:5
content:
{
if i > 3 {
optional = None;
} else {
optional = Some(i + 1);
}
}
@loop.outer
start: 30:4
end: 32:5
content:
for (x, y) in pairs {
println!("({}, {})", x, y);
}
@loop.inner
start: 30:24
end: 32:5
content:
{
println!("({}, {})", x, y);
}
Perfect! The query works for all types of Rust loops. Let's finalize the query definition:
Tool Calls
Tool: run_query
(ID: tooluse_WCS2bdseTcyvPMe0Zt7WNw
)
language
: rust
content
fn main() {
// For loop
for i in 0..10 {
println!("{}", i);
}
// While loop
let mut j = 0;
while j < 5 {
j += 1;
}
// Loop (infinite)
loop {
break;
}
// While let loop
let mut optional = Some(0);
while let Some(i) = optional {
if i > 3 {
optional = None;
} else {
optional = Some(i + 1);
}
}
}
query
(for_expression
(block) @loop.inner) @loop.outer
(while_expression
(block) @loop.inner) @loop.outer
(loop_expression
(block) @loop.inner) @loop.outer
Tool Result (for call tooluse_WCS2bdseTcyvPMe0Zt7WNw
, tool run_query
):
Command: tsg --lang rust --query '(for_expression (block) @loop.inner) @loop.outer (while_expression (block) @loop.inner) @loop.outer (loop_expression (block) @loop.inner) @loop.outer'
Output:
@loop.outer
start: 3:4
end: 5:5
content:
for i in 0..10 {
println!("{}", i);
}
@loop.inner
start: 3:19
end: 5:5
content:
{
println!("{}", i);
}
@loop.outer
start: 9:4
end: 11:5
content:
while j < 5 {
j += 1;
}
@loop.inner
start: 9:16
end: 11:5
content:
{
j += 1;
}
@loop.outer
start: 14:4
end: 16:5
content:
loop {
break;
}
@loop.inner
start: 14:9
end: 16:5
content:
{
break;
}
@loop.outer
start: 20:4
end: 26:5
content:
while let Some(i) = optional {
if i > 3 {
optional = None;
} else {
optional = Some(i + 1);
}
}
@loop.inner
start: 20:33
end: 26:5
content:
{
if i > 3 {
optional = None;
} else {
optional = Some(i + 1);
}
}
Great! Here's the Tree-sitter query for Rust loop textobjects:
(for_expression
(block) @loop.inner) @loop.outer
(while_expression
(block) @loop.inner) @loop.outer
(loop_expression
(block) @loop.inner) @loop.outer
This query works for all types of Rust loops:
-
For loops:
for i in 0..10 { ... }
Including for loops with patterns:
for (x, y) in pairs { ... }
-
While loops:
while j < 5 { ... }
Including while-let loops:
while let Some(i) = optional { ... }
-
Infinite loops (using the
loop
keyword):loop { ... }
The query captures:
@loop.outer
: The entire loop expression including the loop keyword, any conditions/iterators, and the block@loop.inner
: Just the block contents (the body of the loop)
This query effectively handles all Rust loop variants with three simple patterns, giving you inner and outer text objects for each loop type.
now for python
I'll help you create Tree-sitter textobject queries for Python loops. Let's first understand the structure of different loop types in Python by examining a sample code with loops.
Tool Calls
Tool: show_tree_structure
(ID: tooluse_SNmidszwRQa7Z-puPteApw
)
language
: python
content
def main():
# For loop
for i in range(10):
print(i)
# For loop with else
for i in range(5):
print(i)
else:
print("Loop completed")
# While loop
j = 0
while j < 5:
j += 1
print(j)
# While loop with else
k = 0
while k < 3:
k += 1
else:
print("While loop completed")
# Nested loops
for i in range(3):
for j in range(2):
print(i, j)
# For loop with comprehension
squares = [x*x for x in range(10)]
# Dictionary comprehension
square_dict = {x: x*x for x in range(5)}
if __name__ == "__main__":
main()
Tool Result (for call tooluse_SNmidszwRQa7Z-puPteApw
, tool show_tree_structure
):
Command: tree-sitter-debugger --lang python
Output:
(module
(function_definition
"def"
(identifier "main")
(parameters
"("
")"
)
":"
(comment "# For loop")
(block
(for_statement
"for"
(identifier "i")
"in"
(call
(identifier "range")
(argument_list
"("
(integer "10")
")"
)
)
":"
(block
(expression_statement
(call
(identifier "print")
(argument_list
"("
(identifier "i")
")"
)
)
)
)
)
(comment "# For loop with else")
(for_statement
"for"
(identifier "i")
"in"
(call
(identifier "range")
(argument_list
"("
(integer "5")
")"
)
)
":"
(block
(expression_statement
(call
(identifier "print")
(argument_list
"("
(identifier "i")
")"
)
)
)
)
(else_clause
"else"
":"
(block
(expression_statement
(call
(identifier "print")
(argument_list
"("
(string
(string_start """)
(string_content "Loop completed")
(string_end """)
)
")"
)
)
)
)
)
)
(comment "# While loop")
(expression_statement
(assignment
(identifier "j")
"="
(integer "0")
)
)
(while_statement
"while"
(comparison_operator
(identifier "j")
"<"
(integer "5")
)
":"
(block
(expression_statement
(augmented_assignment
(identifier "j")
"+="
(integer "1")
)
)
(expression_statement
(call
(identifier "print")
(argument_list
"("
(identifier "j")
")"
)
)
)
)
)
(comment "# While loop with else")
(expression_statement
(assignment
(identifier "k")
"="
(integer "0")
)
)
(while_statement
"while"
(comparison_operator
(identifier "k")
"<"
(integer "3")
)
":"
(block
(expression_statement
(augmented_assignment
(identifier "k")
"+="
(integer "1")
)
)
)
(else_clause
"else"
":"
(block
(expression_statement
(call
(identifier "print")
(argument_list
"("
(string
(string_start """)
(string_content "While loop completed")
(string_end """)
)
")"
)
)
)
)
)
)
(comment "# Nested loops")
(for_statement
"for"
(identifier "i")
"in"
(call
(identifier "range")
(argument_list
"("
(integer "3")
")"
)
)
":"
(block
(for_statement
"for"
(identifier "j")
"in"
(call
(identifier "range")
(argument_list
"("
(integer "2")
")"
)
)
":"
(block
(expression_statement
(call
(identifier "print")
(argument_list
"("
(identifier "i")
","
(identifier "j")
")"
)
)
)
)
)
)
)
(comment "# For loop with comprehension")
(expression_statement
(assignment
(identifier "squares")
"="
(list_comprehension
"["
(binary_operator
(identifier "x")
"*"
(identifier "x")
)
(for_in_clause
"for"
(identifier "x")
"in"
(call
(identifier "range")
(argument_list
"("
(integer "10")
")"
)
)
)
"]"
)
)
)
(comment "# Dictionary comprehension")
(expression_statement
(assignment
(identifier "square_dict")
"="
(dictionary_comprehension
"{"
(pair
(identifier "x")
":"
(binary_operator
(identifier "x")
"*"
(identifier "x")
)
)
(for_in_clause
"for"
(identifier "x")
"in"
(call
(identifier "range")
(argument_list
"("
(integer "5")
")"
)
)
)
"}"
)
)
)
)
)
(if_statement
"if"
(comparison_operator
(identifier "__name__")
"=="
(string
(string_start """)
(string_content "__main__")
(string_end """)
)
)
":"
(block
(expression_statement
(call
(identifier "main")
(argument_list
"("
")"
)
)
)
)
)
)
Now I'll create a query for loop textobjects in Python and test it on the sample code:
Tool Calls
Tool: run_query
(ID: tooluse_l7NsioBkQzCsPNn2ObLCXQ
)
language
: python
content
def main():
# For loop
for i in range(10):
print(i)
# For loop with else
for i in range(5):
print(i)
else:
print("Loop completed")
# While loop
j = 0
while j < 5:
j += 1
print(j)
# While loop with else
k = 0
while k < 3:
k += 1
else:
print("While loop completed")
# Nested loops
for i in range(3):
for j in range(2):
print(i, j)
# For loop with comprehension
squares = [x*x for x in range(10)]
# Dictionary comprehension
square_dict = {x: x*x for x in range(5)}
if __name__ == "__main__":
main()
query
(for_statement
(block) @loop.inner) @loop.outer
(while_statement
(block) @loop.inner) @loop.outer
(list_comprehension
(for_in_clause) @loop.inner) @loop.outer
(dictionary_comprehension
(for_in_clause) @loop.inner) @loop.outer
Tool Result (for call tooluse_l7NsioBkQzCsPNn2ObLCXQ
, tool run_query
):
Command: tree-sitter-debugger --lang python --query '(for_statement (block) @loop.inner) @loop.outer (while_statement (block) @loop.inner) @loop.outer (list_comprehension (for_in_clause) @loop.inner) @loop.outer (dictionary_comprehension (for_in_clause) @loop.inner) @loop.outer'
Output:
@loop.outer
start: 3:4
end: 4:16
content:
for i in range(10):
print(i)
@loop.inner
start: 4:8
end: 4:16
content:
print(i)
@loop.outer
start: 7:4
end: 10:31
content:
for i in range(5):
print(i)
else:
print("Loop completed")
@loop.inner
start: 8:8
end: 8:16
content:
print(i)
@loop.outer
start: 14:4
end: 16:16
content:
while j < 5:
j += 1
print(j)
@loop.inner
start: 15:8
end: 16:16
content:
j += 1
print(j)
@loop.outer
start: 20:4
end: 23:37
content:
while k < 3:
k += 1
else:
print("While loop completed")
@loop.inner
start: 21:8
end: 21:14
content:
k += 1
@loop.outer
start: 26:4
end: 28:23
content:
for i in range(3):
for j in range(2):
print(i, j)
@loop.inner
start: 27:8
end: 28:23
content:
for j in range(2):
print(i, j)
@loop.outer
start: 27:8
end: 28:23
content:
for j in range(2):
print(i, j)
@loop.inner
start: 28:12
end: 28:23
content:
print(i, j)
@loop.outer
start: 31:14
end: 31:38
content:
[x*x for x in range(10)]
@loop.inner
start: 31:19
end: 31:37
content:
for x in range(10)
@loop.outer
start: 34:18
end: 34:44
content:
{x: x*x for x in range(5)}
@loop.inner
start: 34:26
end: 34:43
content:
for x in range(5)
The query is almost correct, but there are some adjustments needed, especially for comprehensions. Let me refine the query:
Tool Calls
Tool: run_query
(ID: tooluse_TzT4zap7RQGSwTOk6CuFzg
)
content
def main():
# For loop
for i in range(10):
print(i)
# For loop with else
for i in range(5):
print(i)
else:
print("Loop completed")
# While loop
j = 0
while j < 5:
j += 1
print(j)
# While loop with else
k = 0
while k < 3:
k += 1
else:
print("While loop completed")
# Nested loops
for i in range(3):
for j in range(2):
print(i, j)
if __name__ == "__main__":
main()
query
(for_statement
body: (block) @loop.inner) @loop.outer
(while_statement
body: (block) @loop.inner) @loop.outer
language
: python
Tool Result (for call tooluse_TzT4zap7RQGSwTOk6CuFzg
, tool run_query
):
Command: tree-sitter-debugger --lang python --query '(for_statement body: (block) @loop.inner) @loop.outer (while_statement body: (block) @loop.inner) @loop.outer'
Output:
@loop.outer
start: 3:4
end: 4:16
content:
for i in range(10):
print(i)
@loop.inner
start: 4:8
end: 4:16
content:
print(i)
@loop.outer
start: 7:4
end: 10:31
content:
for i in range(5):
print(i)
else:
print("Loop completed")
@loop.inner
start: 8:8
end: 8:16
content:
print(i)
@loop.outer
start: 14:4
end: 16:16
content:
while j < 5:
j += 1
print(j)
@loop.inner
start: 15:8
end: 16:16
content:
j += 1
print(j)
@loop.outer
start: 20:4
end: 23:37
content:
while k < 3:
k += 1
else:
print("While loop completed")
@loop.inner
start: 21:8
end: 21:14
content:
k += 1
@loop.outer
start: 26:4
end: 28:23
content:
for i in range(3):
for j in range(2):
print(i, j)
@loop.inner
start: 27:8
end: 28:23
content:
for j in range(2):
print(i, j)
@loop.outer
start: 27:8
end: 28:23
content:
for j in range(2):
print(i, j)
@loop.inner
start: 28:12
end: 28:23
content:
print(i, j)
The query works correctly for the regular for and while loops. Let's try another approach to simplify the query:
Tool Calls
Tool: run_query
(ID: tooluse_xe4jIkimSvWPYDVj8H7qbg
)
language
: python
content
def main():
# For loop
for i in range(10):
print(i)
# For loop with else
for i in range(5):
print(i)
else:
print("Loop completed")
# While loop
j = 0
while j < 5:
j += 1
print(j)
# While loop with else
k = 0
while k < 3:
k += 1
else:
print("While loop completed")
# Nested loops
for i in range(3):
for j in range(2):
print(i, j)
# For loop with comprehension
squares = [x*x for x in range(10)]
# Dictionary comprehension
square_dict = {x: x*x for x in range(5)}
if __name__ == "__main__":
main()
query
(for_statement
(block) @loop.inner) @loop.outer
(while_statement
(block) @loop.inner) @loop.outer
Tool Result (for call tooluse_xe4jIkimSvWPYDVj8H7qbg
, tool run_query
):
Command: tree-sitter-debugger --lang python --query '(for_statement (block) @loop.inner) @loop.outer (while_statement (block) @loop.inner) @loop.outer'
Output:
@loop.outer
start: 3:4
end: 4:16
content:
for i in range(10):
print(i)
@loop.inner
start: 4:8
end: 4:16
content:
print(i)
@loop.outer
start: 7:4
end: 10:31
content:
for i in range(5):
print(i)
else:
print("Loop completed")
@loop.inner
start: 8:8
end: 8:16
content:
print(i)
@loop.outer
start: 14:4
end: 16:16
content:
while j < 5:
j += 1
print(j)
@loop.inner
start: 15:8
end: 16:16
content:
j += 1
print(j)
@loop.outer
start: 20:4
end: 23:37
content:
while k < 3:
k += 1
else:
print("While loop completed")
@loop.inner
start: 21:8
end: 21:14
content:
k += 1
@loop.outer
start: 26:4
end: 28:23
content:
for i in range(3):
for j in range(2):
print(i, j)
@loop.inner
start: 27:8
end: 28:23
content:
for j in range(2):
print(i, j)
@loop.outer
start: 27:8
end: 28:23
content:
for j in range(2):
print(i, j)
@loop.inner
start: 28:12
end: 28:23
content:
print(i, j)
Let's add a separate query for comprehensions:
Tool Calls
Tool: run_query
(ID: tooluse_hE5SHVuYTC6xbmlMYd3Mkw
)
language
: python
content
def main():
# For loop with comprehension
squares = [x*x for x in range(10)]
# Dictionary comprehension
square_dict = {x: x*x for x in range(5)}
if __name__ == "__main__":
main()
query
(list_comprehension) @loop.outer
(dictionary_comprehension) @loop.outer
Tool Result (for call tooluse_hE5SHVuYTC6xbmlMYd3Mkw
, tool run_query
):
Command: tree-sitter-debugger --lang python --query '(list_comprehension) @loop.outer (dictionary_comprehension) @loop.outer'
Output:
@loop.outer
start: 3:14
end: 3:38
content:
[x*x for x in range(10)]
@loop.outer
start: 6:18
end: 6:44
content:
{x: x*x for x in range(5)}
Great! Now I have all the pieces for a complete Python loop textobject query. Let me put it all together:
Tool Calls
Tool: run_query
(ID: tooluse_-HP7c0kOSBiUA-Ru8w-T1Q
)
language
: python
content
def main():
# For loop
for i in range(10):
print(i)
# For loop with else
for i in range(5):
print(i)
else:
print("Loop completed")
# While loop
j = 0
while j < 5:
j += 1
print(j)
# While loop with else
k = 0
while k < 3:
k += 1
else:
print("While loop completed")
# Nested loops
for i in range(3):
for j in range(2):
print(i, j)
# For loop with comprehension
squares = [x*x for x in range(10)]
# Dictionary comprehension
square_dict = {x: x*x for x in range(5)}
if __name__ == "__main__":
main()
query
(for_statement
(block) @loop.inner) @loop.outer
(while_statement
(block) @loop.inner) @loop.outer
(list_comprehension) @loop.outer
(dictionary_comprehension) @loop.outer
Tool Result (for call tooluse_-HP7c0kOSBiUA-Ru8w-T1Q
, tool run_query
):
Command: tree-sitter-debugger --lang python --query '(for_statement (block) @loop.inner) @loop.outer (while_statement (block) @loop.inner) @loop.outer (list_comprehension) @loop.outer (dictionary_comprehension) @loop.outer'
Output:
@loop.outer
start: 3:4
end: 4:16
content:
for i in range(10):
print(i)
@loop.inner
start: 4:8
end: 4:16
content:
print(i)
@loop.outer
start: 7:4
end: 10:31
content:
for i in range(5):
print(i)
else:
print("Loop completed")
@loop.inner
start: 8:8
end: 8:16
content:
print(i)
@loop.outer
start: 14:4
end: 16:16
content:
while j < 5:
j += 1
print(j)
@loop.inner
start: 15:8
end: 16:16
content:
j += 1
print(j)
@loop.outer
start: 20:4
end: 23:37
content:
while k < 3:
k += 1
else:
print("While loop completed")
@loop.inner
start: 21:8
end: 21:14
content:
k += 1
@loop.outer
start: 26:4
end: 28:23
content:
for i in range(3):
for j in range(2):
print(i, j)
@loop.inner
start: 27:8
end: 28:23
content:
for j in range(2):
print(i, j)
@loop.outer
start: 27:8
end: 28:23
content:
for j in range(2):
print(i, j)
@loop.inner
start: 28:12
end: 28:23
content:
print(i, j)
@loop.outer
start: 31:14
end: 31:38
content:
[x*x for x in range(10)]
@loop.outer
start: 34:18
end: 34:44
content:
{x: x*x for x in range(5)}
Now let's define inner nodes for comprehensions:
Tool Calls
Tool: run_query
(ID: tooluse_BBTods4fSCWlSbK1KGoIHA
)
query
(list_comprehension
(for_in_clause) @loop.inner) @loop.outer
(dictionary_comprehension
(for_in_clause) @loop.inner) @loop.outer
language
: python
content
def main():
# For loop with comprehension
squares = [x*x for x in range(10)]
# Dictionary comprehension
square_dict = {x: x*x for x in range(5)}
if __name__ == "__main__":
main()
Tool Result (for call tooluse_BBTods4fSCWlSbK1KGoIHA
, tool run_query
):
Command: tree-sitter-debugger --lang python --query '(list_comprehension (for_in_clause) @loop.inner) @loop.outer (dictionary_comprehension (for_in_clause) @loop.inner) @loop.outer'
Output:
@loop.outer
start: 3:14
end: 3:38
content:
[x*x for x in range(10)]
@loop.inner
start: 3:19
end: 3:37
content:
for x in range(10)
@loop.outer
start: 6:18
end: 6:44
content:
{x: x*x for x in range(5)}
@loop.inner
start: 6:26
end: 6:43
content:
for x in range(5)
Perfect! Now I have all the necessary components for a comprehensive Python loop textobject query. Let's finalize it:
Tool Calls
Tool: run_query
(ID: tooluse_hzN14UKQQdKTz97Qz5EDMA
)
language
: python
content
def main():
# For loop
for i in range(10):
print(i)
# For loop with else
for i in range(5):
print(i)
else:
print("Loop completed")
# While loop
j = 0
while j < 5:
j += 1
print(j)
# While loop with else
k = 0
while k < 3:
k += 1
else:
print("While loop completed")
# Nested loops
for i in range(3):
for j in range(2):
print(i, j)
# For loop with comprehension
squares = [x*x for x in range(10)]
# Dictionary comprehension
square_dict = {x: x*x for x in range(5)}
if __name__ == "__main__":
main()
query
(for_statement
(block) @loop.inner) @loop.outer
(while_statement
(block) @loop.inner) @loop.outer
(list_comprehension
(for_in_clause) @loop.inner) @loop.outer
(dictionary_comprehension
(for_in_clause) @loop.inner) @loop.outer
Tool Result (for call tooluse_hzN14UKQQdKTz97Qz5EDMA
, tool run_query
):
Command: tree-sitter-debugger --lang python --query '(for_statement (block) @loop.inner) @loop.outer (while_statement (block) @loop.inner) @loop.outer (list_comprehension (for_in_clause) @loop.inner) @loop.outer (dictionary_comprehension (for_in_clause) @loop.inner) @loop.outer'
Output:
@loop.outer
start: 3:4
end: 4:16
content:
for i in range(10):
print(i)
@loop.inner
start: 4:8
end: 4:16
content:
print(i)
@loop.outer
start: 7:4
end: 10:31
content:
for i in range(5):
print(i)
else:
print("Loop completed")
@loop.inner
start: 8:8
end: 8:16
content:
print(i)
@loop.outer
start: 14:4
end: 16:16
content:
while j < 5:
j += 1
print(j)
@loop.inner
start: 15:8
end: 16:16
content:
j += 1
print(j)
@loop.outer
start: 20:4
end: 23:37
content:
while k < 3:
k += 1
else:
print("While loop completed")
@loop.inner
start: 21:8
end: 21:14
content:
k += 1
@loop.outer
start: 26:4
end: 28:23
content:
for i in range(3):
for j in range(2):
print(i, j)
@loop.inner
start: 27:8
end: 28:23
content:
for j in range(2):
print(i, j)
@loop.outer
start: 27:8
end: 28:23
content:
for j in range(2):
print(i, j)
@loop.inner
start: 28:12
end: 28:23
content:
print(i, j)
@loop.outer
start: 31:14
end: 31:38
content:
[x*x for x in range(10)]
@loop.inner
start: 31:19
end: 31:37
content:
for x in range(10)
@loop.outer
start: 34:18
end: 34:44
content:
{x: x*x for x in range(5)}
@loop.inner
start: 34:26
end: 34:43
content:
for x in range(5)
Here's the Tree-sitter query for Python loop textobjects:
(for_statement
(block) @loop.inner) @loop.outer
(while_statement
(block) @loop.inner) @loop.outer
(list_comprehension
(for_in_clause) @loop.inner) @loop.outer
(dictionary_comprehension
(for_in_clause) @loop.inner) @loop.outer
This query works for all types of Python loops:
-
Regular for loops:
for i in range(10): print(i)
Including those with else clauses:
for i in range(5): print(i) else: print("Loop completed")
-
While loops:
while j < 5: j += 1
Including those with else clauses:
while k < 3: k += 1 else: print("While loop completed")
-
List comprehensions:
squares = [x*x for x in range(10)]
-
Dictionary comprehensions:
square_dict = {x: x*x for x in range(5)}
The query captures:
-
For regular loops (for and while):
@loop.outer
: The entire loop statement including keywords and the body@loop.inner
: Just the block contents (the body of the loop)
-
For comprehensions (list and dictionary):
@loop.outer
: The entire comprehension expression@loop.inner
: The for_in_clause part of the comprehension
This query effectively handles all Python loop variants with clear inner and outer textobjects for each loop type.
# Tree sitter esa agent config | |
name = "Treesiter Query Assistant" | |
description = "An agent that helps generate textobject queries using tree-sitter-debugger" | |
system_prompt = """ | |
You are a Treesiter Query Assistant specializing in generating and testing Tree-sitter textobject queries. Your expertise includes: | |
1. Understanding Tree-sitter syntax and query patterns | |
2. Creating queries for different programming languages | |
3. Testing and debugging Tree-sitter queries | |
4. Understanding Abstract Syntax Tree (AST) structures | |
When a user asks for a query: | |
1. Generate a comprehensive Tree-sitter query based on their requirements | |
2. Save the user's code to a temporary file | |
3. Use tree-sitter-debugger to view the Tree-sitter parse tree of the code | |
4. Test the query against the code using tree-sitter-debugger | |
5. Provide the results along with explanations | |
{{$tree-sitter-debugger --list-languages}} | |
Example: | |
<user_query> | |
I need a query to select conditional statement in golang | |
</user_query> | |
<response> | |
(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 | |
</response> | |
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 | |
""" | |
[[functions]] | |
name = "show_tree_structure" | |
description = "Display the Tree-sitter parse tree for a file" | |
command = "tree-sitter-debugger --lang {{language}}" | |
stdin = "{{content}}" | |
safe = true | |
[[functions.parameters]] | |
name = "language" | |
type = "string" | |
description = "Programming language of the file (e.g., python, javascript, rust)" | |
required = true | |
[[functions.parameters]] | |
name = "content" | |
type = "string" | |
description = "Code to show the tree structure of. Always provide valid code" | |
required = true | |
[[functions]] | |
name = "run_query" | |
description = "Run a Tree-sitter query on a file" | |
command = "tree-sitter-debugger --lang {{language}} --query '{{query}}'" | |
stdin = "{{content}}" | |
safe = true | |
[[functions.parameters]] | |
name = "language" | |
type = "string" | |
description = "Programming language of the file (e.g., python, javascript, rust)" | |
required = true | |
[[functions.parameters]] | |
name = "query" | |
type = "string" | |
description = "Tree-sitter query to run" | |
required = true | |
[[functions.parameters]] | |
name = "content" | |
type = "string" | |
description = "Code to show the tree structure of. Always provide valid code" | |
required = true |