1
1
-- TODO: Support regex search
2
2
3
3
local Date = require (' orgmode.objects.date' )
4
+ local parsing = require (' orgmode.utils.parsing' )
4
5
5
6
--- @class Search
6
7
--- @field term string
@@ -88,66 +89,6 @@ local OPERATORS = {
88
89
end ,
89
90
}
90
91
91
- --- Parses a pattern from the beginning of an input using Lua's pattern syntax
92
- --- @param input string
93
- --- @param pattern string
94
- --- @return string ?, string
95
- local function parse_pattern (input , pattern )
96
- local value = input :match (' ^' .. pattern )
97
- if value then
98
- return value , input :sub (# value + 1 )
99
- else
100
- return nil , input
101
- end
102
- end
103
-
104
- --- Parses the first of a sequence of patterns
105
- --- @param input string The input to parse
106
- --- @param ... string The patterns to accept
107
- --- @return string ?, string
108
- local function parse_pattern_choice (input , ...)
109
- for _ , pattern in ipairs ({ ... }) do
110
- local value , remaining = parse_pattern (input , pattern )
111
- if value then
112
- return value , remaining
113
- end
114
- end
115
-
116
- return nil , input
117
- end
118
-
119
- --- @generic T
120
- --- @param input string
121
- --- @param item_parser fun ( input : string ): ( T ?, string )
122
- --- @param delimiter_pattern string
123
- --- @return (T[] )?, string
124
- local function parse_delimited_sequence (input , item_parser , delimiter_pattern )
125
- local sequence , item , delimiter = {}, nil , nil
126
- local original_input = input
127
-
128
- -- Parse the first item
129
- item , input = item_parser (input )
130
- if not item then
131
- return sequence , input
132
- end
133
- table.insert (sequence , item )
134
-
135
- -- Continue parsing items while there's a trailing delimiter
136
- delimiter , input = parse_pattern (input , delimiter_pattern )
137
- while delimiter do
138
- item , input = item_parser (input )
139
- if not item then
140
- return nil , original_input
141
- end
142
-
143
- table.insert (sequence , item )
144
-
145
- delimiter , input = parse_pattern (input , delimiter_pattern )
146
- end
147
-
148
- return sequence , input
149
- end
150
-
151
92
--- @param term string
152
93
--- @return Search
153
94
function Search :new (term )
190
131
function Search :_parse ()
191
132
local input = self .term
192
133
-- Parse the sequence of ORs
193
- self .or_items , input = parse_delimited_sequence (input , function (i )
134
+ self .or_items , input = parsing . parse_delimited_sequence (input , function (i )
194
135
return OrItem :parse (i )
195
136
end , ' %|' )
196
137
@@ -220,7 +161,7 @@ function OrItem:parse(input)
220
161
local and_items
221
162
local original_input = input
222
163
223
- and_items , input = parse_delimited_sequence (input , function (i )
164
+ and_items , input = parsing . parse_delimited_sequence (input , function (i )
224
165
return AndItem :parse (i )
225
166
end , ' %&' )
226
167
@@ -269,7 +210,7 @@ function AndItem:parse(input)
269
210
local operator
270
211
local original_input = input
271
212
272
- operator , input = parse_pattern (input , ' [%+%-]?' )
213
+ operator , input = parsing . parse_pattern (input , ' [%+%-]?' )
273
214
274
215
-- A '+' operator is implied if none is present
275
216
if operator == ' ' then
@@ -300,7 +241,7 @@ function AndItem:parse(input)
300
241
end
301
242
302
243
-- Attempt to parse the next operator
303
- operator , input = parse_pattern (input , ' [%+%-]' )
244
+ operator , input = parsing . parse_pattern (input , ' [%+%-]' )
304
245
end
305
246
306
247
return and_item , input
339
280
--- @return TagMatch ?, string
340
281
function TagMatch :parse (input )
341
282
local tag
342
- tag , input = parse_pattern (input , ' [%w_@#%%]+' )
283
+ tag , input = parsing . parse_pattern (input , ' [%w_@#%%]+' )
343
284
if not tag then
344
285
return nil , input
345
286
end
@@ -371,7 +312,7 @@ function PropertyMatch:parse(input)
371
312
local name , operator , string_str , number_str , date_str
372
313
local original_input = input
373
314
374
- name , input = parse_pattern (input , ' [^=<>]+' )
315
+ name , input = parsing . parse_pattern (input , ' [^=<>]+' )
375
316
if not name then
376
317
return nil , original_input
377
318
end
@@ -383,14 +324,14 @@ function PropertyMatch:parse(input)
383
324
end
384
325
385
326
-- Number property
386
- number_str , input = parse_pattern (input , ' %d+' )
327
+ number_str , input = parsing . parse_pattern (input , ' %d+' )
387
328
if number_str then
388
329
local number = tonumber (number_str ) --[[ @as number]]
389
330
return PropertyNumberMatch :new (name , operator , number ), input
390
331
end
391
332
392
333
-- Date property
393
- date_str , input = parse_pattern (input , ' "(<[^>]+>)"' )
334
+ date_str , input = parsing . parse_pattern (input , ' "(<[^>]+>)"' )
394
335
if date_str then
395
336
--- @type string ?, Date ?
396
337
local date_content , date_value
@@ -422,7 +363,7 @@ function PropertyMatch:parse(input)
422
363
end
423
364
424
365
-- String property
425
- string_str , input = parse_pattern (input , ' "[^"]+"' )
366
+ string_str , input = parsing . parse_pattern (input , ' "[^"]+"' )
426
367
if string_str then
427
368
--- @type string
428
369
local unquote_string = string_str :match (' ^"([^"]+)"$' )
437
378
--- @param input string
438
379
--- @return PropertyMatchOperator , string
439
380
function PropertyMatch :_parse_operator (input )
440
- return parse_pattern_choice (input , ' %=' , ' %<%>' , ' %<%=' , ' %<' , ' %>%=' , ' %>' ) --[[ @as PropertyMatchOperator]]
381
+ return parsing . parse_pattern_choice (input , ' %=' , ' %<%>' , ' %<%=' , ' %<' , ' %>%=' , ' %>' ) --[[ @as PropertyMatchOperator]]
441
382
end
442
383
443
384
--- Constructs a PropertyNumberMatch
@@ -559,16 +500,16 @@ function TodoMatch:parse(input)
559
500
-- Parse the '/' or '/!' prefix that indicates a TodoMatch
560
501
--- @type string ?
561
502
local prefix
562
- prefix , input = parse_pattern (input , ' %/[%!]?' )
503
+ prefix , input = parsing . parse_pattern (input , ' %/[%!]?' )
563
504
if not prefix then
564
505
return nil , original_input
565
506
end
566
507
567
508
-- Parse a whitelist of keywords
568
509
--- @type string[] ?
569
510
local anyOf
570
- anyOf , input = parse_delimited_sequence (input , function (i )
571
- return parse_pattern (i , ' %w+' )
511
+ anyOf , input = parsing . parse_delimited_sequence (input , function (i )
512
+ return parsing . parse_pattern (i , ' %w+' )
572
513
end , ' %|' )
573
514
if anyOf and # anyOf > 0 then
574
515
-- Successfully parsed the whitelist, return it
@@ -580,11 +521,11 @@ function TodoMatch:parse(input)
580
521
-- Parse a blacklist of keywords
581
522
--- @type string ?
582
523
local negation
583
- negation , input = parse_pattern (input , ' -' )
524
+ negation , input = parsing . parse_pattern (input , ' -' )
584
525
if negation then
585
526
local negative_items
586
- negative_items , input = parse_delimited_sequence (input , function (i )
587
- return parse_pattern (i , ' %w+' )
527
+ negative_items , input = parsing . parse_delimited_sequence (input , function (i )
528
+ return parsing . parse_pattern (i , ' %w+' )
588
529
end , ' %-' )
589
530
590
531
if negative_items then
0 commit comments