irongit

A rust macro that allows regular expression creation through independent files. Allows fully typed named groups.

423 lines9.2 KBMarkdown
1# regex_folder_macro
2
3Allows for named groups in regular expressions to be generated from special files ending in `.re`.
4
5---
6
7## Usage
8
9### Warnings
10
11- Do not use rust syntax keywords such as type for field names in .re files
12
13### Initialization
14
15- Call the `load_regex_files!` macro on the directory that contains regex files.
16- Each file is loaded with the `m` and `x` flags
17 - `m` (multiline): `^` and `$` match the start and end of lines, not just the entire input.
18 - `x` (extended): allows whitespace and comments starting with `#` inside the regex.
19
20### Each regex file is a structure with the following implementations
21
221. `pub fn from_str(text: &str) -> Option<Self>` Finds a single precompiled struct within the given string.
232. `pub fn from_file(filename: &str) -> Result<Option<Self>, std::io::Error>` Finds a single precompiled struct after opening the given filename.
243. `pub fn vec_from_str(text: &str) -> Vec<Self>` Extracts all the precompiled structs in a given string.
254. `pub fn vec_from_file(filename: &str) -> Result<Vec<Self>, std::io::Error>` Extracts all the precompiled structs after opening the given filename.
265. `pub fn iter_from_str(text: &str) -> impl Iterator<Item = Self> + '_` Extracts all the precompiled structs in a given string.
276. `pub fn iter_from_file<'a>(buf: &'a mut String, filename: &str) -> Result<impl Iterator<Item = Self> + 'a, std::io::Error>` Extracts all the precompiled structs after opening the given filename.
287. `pub fn captures(text:&str) -> Option<regex::Captures<'_>>` Extracts the first match as raw captures.
298. `pub fn captures_iter(text: &str) -> impl Iterator<Item = regex::Captures<'_>> + '_` Extracts an iterator of raw captures.
309. `pub fn captures_from_file<'a>(buf: &'a mut String, filename: &str) -> Result<Option<regex::Captures<'a>>, std::io::Error>` Extracts the first match as raw captures from the given file.
3110. `pub fn captures_iter_from_file<'a>(buf: &'a mut String, filename: &str) -> Result<impl Iterator<Item = regex::Captures<'a>> + 'a, std::io::Error>` Extracts raw captures iter from contents of the given file.
32
33The abstract structure for matches within the regex_folder_macro library contains `start_pos`, `end_pos`, and public fields for each named group inside of the `.re` file. Each field then contains a `start_pos`, `end_pos`, and `val` field.
34
35### Tips
36
37- Use struct style naming convention for `.re` files. i.e. `Event.re` rather than `event.re`
38
39### Benefits
40
41- Files load automatically into precompiled struct with macros which allows rust-analyzer to use provide type hints.
42- Regular expressions can be split over multiple lines and use comments to improve readability for regular expressions.
43
44### Changes
45
46#### 1.0.1
47
48- Update the docs
49
50### Breaking changes
51
52#### 1.0.0
53
54- Functions from files require a buffer
55
56---
57
58## The events example
59
60### event.rs
61
62```rust
63use regex_folder_macro::load_regex_files;
64// Loads the regular expressions within the folder named regex
65load_regex_files!("regex");
66
67fn main() {
68 let events = EventRE::vec_from_file("samples/events.txt").unwrap();
69 println!("{}", serde_json::to_string_pretty(&events).unwrap());
70}
71```
72
73### events.txt
74
75```text
76๐Ÿง  Focused Dev + Growth Schedule
77
78Time Activity
797:30โ€“8:00 AM Wake up + hydrate + light stretch
808:00โ€“8:45 AM Gym (weights or intervals)
819:00โ€“9:30 AM Breakfast + cooldown + planning
829:30โ€“12:00PM Deep coding (core project)
8312:00โ€“12:45PM Lunch + decompress
8412:45โ€“2:30PM Coding or meetings if needed
852:30โ€“3:00 PM Break or walk
863:00โ€“5:00 PM Learning block (Rust, AI, etc)
875:00โ€“6:00 PM Chill / side project / cleanup
886:00โ€“7:00 PM Dinner + relax
897:00โ€“9:00 PM Optional: build/test/hack ideas
909:00โ€“10:00 PM Wind down (read, steam room, etc)
9110:00โ€“10:30PM Journal + sleep prep
92```
93
94### Event.re
95
96```text
97(?<start>\d{1,2}:\d{1,2})
98.
99(?<end>\d{1,2}:\d{1,2})
100\s{0,2}
101(?<ampm>[AMPM]{2})
102.
103(?<activity>.+)
104```
105
106### Parsed items
107
108```json
109[
110 {
111 "start_pos": 50,
112 "end_pos": 98,
113 "start": {
114 "start_pos": 50,
115 "end_pos": 54,
116 "val": "7:30"
117 },
118 "end": {
119 "start_pos": 57,
120 "end_pos": 61,
121 "val": "8:00"
122 },
123 "ampm": {
124 "start_pos": 62,
125 "end_pos": 64,
126 "val": "AM"
127 },
128 "activity": {
129 "start_pos": 65,
130 "end_pos": 98,
131 "val": "Wake up + hydrate + light stretch"
132 }
133 },
134 {
135 "start_pos": 99,
136 "end_pos": 140,
137 "start": {
138 "start_pos": 99,
139 "end_pos": 103,
140 "val": "8:00"
141 },
142 "end": {
143 "start_pos": 106,
144 "end_pos": 110,
145 "val": "8:45"
146 },
147 "ampm": {
148 "start_pos": 111,
149 "end_pos": 113,
150 "val": "AM"
151 },
152 "activity": {
153 "start_pos": 114,
154 "end_pos": 140,
155 "val": "Gym (weights or intervals)"
156 }
157 },
158 {
159 "start_pos": 141,
160 "end_pos": 187,
161 "start": {
162 "start_pos": 141,
163 "end_pos": 145,
164 "val": "9:00"
165 },
166 "end": {
167 "start_pos": 148,
168 "end_pos": 152,
169 "val": "9:30"
170 },
171 "ampm": {
172 "start_pos": 153,
173 "end_pos": 155,
174 "val": "AM"
175 },
176 "activity": {
177 "start_pos": 156,
178 "end_pos": 187,
179 "val": "Breakfast + cooldown + planning"
180 }
181 },
182 {
183 "start_pos": 188,
184 "end_pos": 229,
185 "start": {
186 "start_pos": 188,
187 "end_pos": 192,
188 "val": "9:30"
189 },
190 "end": {
191 "start_pos": 195,
192 "end_pos": 200,
193 "val": "12:00"
194 },
195 "ampm": {
196 "start_pos": 200,
197 "end_pos": 202,
198 "val": "PM"
199 },
200 "activity": {
201 "start_pos": 203,
202 "end_pos": 229,
203 "val": "Deep coding (core project)"
204 }
205 },
206 {
207 "start_pos": 230,
208 "end_pos": 264,
209 "start": {
210 "start_pos": 230,
211 "end_pos": 235,
212 "val": "12:00"
213 },
214 "end": {
215 "start_pos": 238,
216 "end_pos": 243,
217 "val": "12:45"
218 },
219 "ampm": {
220 "start_pos": 243,
221 "end_pos": 245,
222 "val": "PM"
223 },
224 "activity": {
225 "start_pos": 246,
226 "end_pos": 264,
227 "val": "Lunch + decompress"
228 }
229 },
230 {
231 "start_pos": 265,
232 "end_pos": 308,
233 "start": {
234 "start_pos": 265,
235 "end_pos": 270,
236 "val": "12:45"
237 },
238 "end": {
239 "start_pos": 273,
240 "end_pos": 277,
241 "val": "2:30"
242 },
243 "ampm": {
244 "start_pos": 277,
245 "end_pos": 279,
246 "val": "PM"
247 },
248 "activity": {
249 "start_pos": 280,
250 "end_pos": 308,
251 "val": "Coding or meetings if needed"
252 }
253 },
254 {
255 "start_pos": 309,
256 "end_pos": 337,
257 "start": {
258 "start_pos": 309,
259 "end_pos": 313,
260 "val": "2:30"
261 },
262 "end": {
263 "start_pos": 316,
264 "end_pos": 320,
265 "val": "3:00"
266 },
267 "ampm": {
268 "start_pos": 321,
269 "end_pos": 323,
270 "val": "PM"
271 },
272 "activity": {
273 "start_pos": 324,
274 "end_pos": 337,
275 "val": "Break or walk"
276 }
277 },
278 {
279 "start_pos": 338,
280 "end_pos": 383,
281 "start": {
282 "start_pos": 338,
283 "end_pos": 342,
284 "val": "3:00"
285 },
286 "end": {
287 "start_pos": 345,
288 "end_pos": 349,
289 "val": "5:00"
290 },
291 "ampm": {
292 "start_pos": 350,
293 "end_pos": 352,
294 "val": "PM"
295 },
296 "activity": {
297 "start_pos": 353,
298 "end_pos": 383,
299 "val": "Learning block (Rust, AI, etc)"
300 }
301 },
302 {
303 "start_pos": 384,
304 "end_pos": 429,
305 "start": {
306 "start_pos": 384,
307 "end_pos": 388,
308 "val": "5:00"
309 },
310 "end": {
311 "start_pos": 391,
312 "end_pos": 395,
313 "val": "6:00"
314 },
315 "ampm": {
316 "start_pos": 396,
317 "end_pos": 398,
318 "val": "PM"
319 },
320 "activity": {
321 "start_pos": 399,
322 "end_pos": 429,
323 "val": "Chill / side project / cleanup"
324 }
325 },
326 {
327 "start_pos": 430,
328 "end_pos": 459,
329 "start": {
330 "start_pos": 430,
331 "end_pos": 434,
332 "val": "6:00"
333 },
334 "end": {
335 "start_pos": 437,
336 "end_pos": 441,
337 "val": "7:00"
338 },
339 "ampm": {
340 "start_pos": 442,
341 "end_pos": 444,
342 "val": "PM"
343 },
344 "activity": {
345 "start_pos": 445,
346 "end_pos": 459,
347 "val": "Dinner + relax"
348 }
349 },
350 {
351 "start_pos": 460,
352 "end_pos": 506,
353 "start": {
354 "start_pos": 460,
355 "end_pos": 464,
356 "val": "7:00"
357 },
358 "end": {
359 "start_pos": 467,
360 "end_pos": 471,
361 "val": "9:00"
362 },
363 "ampm": {
364 "start_pos": 472,
365 "end_pos": 474,
366 "val": "PM"
367 },
368 "activity": {
369 "start_pos": 475,
370 "end_pos": 506,
371 "val": "Optional: build/test/hack ideas"
372 }
373 },
374 {
375 "start_pos": 507,
376 "end_pos": 556,
377 "start": {
378 "start_pos": 507,
379 "end_pos": 511,
380 "val": "9:00"
381 },
382 "end": {
383 "start_pos": 514,
384 "end_pos": 519,
385 "val": "10:00"
386 },
387 "ampm": {
388 "start_pos": 520,
389 "end_pos": 522,
390 "val": "PM"
391 },
392 "activity": {
393 "start_pos": 523,
394 "end_pos": 556,
395 "val": "Wind down (read, steam room, etc)"
396 }
397 },
398 {
399 "start_pos": 557,
400 "end_pos": 593,
401 "start": {
402 "start_pos": 557,
403 "end_pos": 562,
404 "val": "10:00"
405 },
406 "end": {
407 "start_pos": 565,
408 "end_pos": 570,
409 "val": "10:30"
410 },
411 "ampm": {
412 "start_pos": 570,
413 "end_pos": 572,
414 "val": "PM"
415 },
416 "activity": {
417 "start_pos": 573,
418 "end_pos": 593,
419 "val": "Journal + sleep prep"
420 }
421 }
422]
423```