I'd like a treesitter query that matches a Rust struct together with all of its attributes. For example,
#[derive(Debug)]
#[serde(rename_all = "camel_case")]
pub struct MyType {
pub foo: i32,
}
The lines beginning with #
are attributes that are logically connected to the struct declaration. But the treesitter grammar for Rust parses attributes as adjacent nodes, not as children of the struct declaration:
(attribute_item ; [27, 0] - [27, 16]
(attribute ; [27, 2] - [27, 15]
(identifier) ; [27, 2] - [27, 8]
arguments: (token_tree ; [27, 8] - [27, 15]
(identifier)))) ; [27, 9] - [27, 14]
(attribute_item ; [28, 0] - [28, 35]
(attribute ; [28, 2] - [28, 34]
(identifier) ; [28, 2] - [28, 7]
arguments: (token_tree ; [28, 7] - [28, 34]
(identifier) ; [28, 8] - [28, 18]
(string_literal)))) ; [28, 21] - [28, 33]
(struct_item ; [29, 0] - [31, 1]
(visibility_modifier) ; [29, 0] - [29, 3]
name: (type_identifier) ; [29, 11] - [29, 17]
body: (field_declaration_list ; [29, 18] - [31, 1]
(field_declaration ; [30, 4] - [30, 16]
(visibility_modifier) ; [30, 4] - [30, 7]
name: (field_identifier) ; [30, 8] - [30, 11]
type: (primitive_type)))) ; [30, 13] - [30, 16]
How can I get produce a query that I can use in mini.ai that matches the struct, and all attributes?
I've tried this query using Neovim's new built-in :EditQuery
command:
((attribute_item)* . (struct_item)) @custom_capture.outer
It looks like it does what I want. But when I try using @custom_capture.outer
in mini.ai it matches the struct declaration, but not the attributes.
I tried using #make-range!
like this,
((attribute_item)* @_start . (struct_item) @_end
(#make-range! "custom_capture.outer" @_start @_end))
That matches the struct and the second attribute, but does not get the first attribute. I'm guessing that's because the .
specifies that nodes must be adjacent, and the second attribute is the only one that is adjacent to a struct_item. Following that thinking I tried this,
((attribute_item)? @_start . (attribute_item)* . (struct_item) @_end
(#make-range! "custom_capture.outer" @_start @_end))
That gets the struct and all the attributes, but only if my cursor is on the first attribute line when I use the textobject. If my cursor is on any subsequent line then I get the second attribute and the struct, but the first attribute is missed.
One problem is I'm not clear whether ((attribute_item) . (struct_item))
matches an attribute_item and a struct_item that are adjacent, or matches an attribute_item that precedes a struct_item, but does not also match the struct_item. I tried experimenting with the second interpretation and used this query,
(((attribute_item)
. [(attribute_item) (struct_item)])* @_start
(struct_item) @_end
(#make-range! "custom_capture.outer" @_start @_end))
That captures what I want, but in some cases if I have two struct declarations and I try to match only the second one the query selects both structs instead.
Is that the way to do a lookahead? Or is there another way?
I've kinda hit a wall looking at documentation, other examples, and running my own experiments. Does anyone have any pointers to help understand these queries on a deeper level?
Edit: It looks like this stuff is in flux, so I should mention that I'm using the latest nightly as of March 2 2024, and I made sure that all of my plugins are up-to-date.
From what I've learned revolutions are often accompanied by circumstances where people are desperate due to lack of basic necessities, especially food.
The French revolution was preceded by a serious food shortage. Remember that "let them eat cake" comment? One of the key events, the Women's March which displaced the king and queen from Versailles, was specifically motivated by demands for food.
The European People's Spring saw lots of revolutions across Europe in 1848-1849 including in France, Italy, Bavaria, Austria, Hungary. That was about the same time as a continent-wide grain shortage on top of an economic crisis.
The Russian revolution of 1917 came at a time when a combination of WW1, bad leadership, and an extra cold winter led to food shortages, and fuel shortages so people were starving and freezing at the same time.