Skip to content

Commit 38b73f9

Browse files
committed
Factor logging logic out of search parser
1 parent 34f977c commit 38b73f9

File tree

2 files changed

+86
-76
lines changed

2 files changed

+86
-76
lines changed

lua/orgmode/parser/search.lua

Lines changed: 17 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
--TODO: Support regex search
22

33
local Date = require('orgmode.objects.date')
4+
local parsing = require('orgmode.utils.parsing')
45

56
---@class Search
67
---@field term string
@@ -88,66 +89,6 @@ local OPERATORS = {
8889
end,
8990
}
9091

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-
15192
---@param term string
15293
---@return Search
15394
function Search:new(term)
@@ -190,7 +131,7 @@ end
190131
function Search:_parse()
191132
local input = self.term
192133
-- 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)
194135
return OrItem:parse(i)
195136
end, '%|')
196137

@@ -220,7 +161,7 @@ function OrItem:parse(input)
220161
local and_items
221162
local original_input = input
222163

223-
and_items, input = parse_delimited_sequence(input, function(i)
164+
and_items, input = parsing.parse_delimited_sequence(input, function(i)
224165
return AndItem:parse(i)
225166
end, '%&')
226167

@@ -269,7 +210,7 @@ function AndItem:parse(input)
269210
local operator
270211
local original_input = input
271212

272-
operator, input = parse_pattern(input, '[%+%-]?')
213+
operator, input = parsing.parse_pattern(input, '[%+%-]?')
273214

274215
-- A '+' operator is implied if none is present
275216
if operator == '' then
@@ -300,7 +241,7 @@ function AndItem:parse(input)
300241
end
301242

302243
-- Attempt to parse the next operator
303-
operator, input = parse_pattern(input, '[%+%-]')
244+
operator, input = parsing.parse_pattern(input, '[%+%-]')
304245
end
305246

306247
return and_item, input
@@ -339,7 +280,7 @@ end
339280
---@return TagMatch?, string
340281
function TagMatch:parse(input)
341282
local tag
342-
tag, input = parse_pattern(input, '[%w_@#%%]+')
283+
tag, input = parsing.parse_pattern(input, '[%w_@#%%]+')
343284
if not tag then
344285
return nil, input
345286
end
@@ -371,7 +312,7 @@ function PropertyMatch:parse(input)
371312
local name, operator, string_str, number_str, date_str
372313
local original_input = input
373314

374-
name, input = parse_pattern(input, '[^=<>]+')
315+
name, input = parsing.parse_pattern(input, '[^=<>]+')
375316
if not name then
376317
return nil, original_input
377318
end
@@ -383,14 +324,14 @@ function PropertyMatch:parse(input)
383324
end
384325

385326
-- Number property
386-
number_str, input = parse_pattern(input, '%d+')
327+
number_str, input = parsing.parse_pattern(input, '%d+')
387328
if number_str then
388329
local number = tonumber(number_str) --[[@as number]]
389330
return PropertyNumberMatch:new(name, operator, number), input
390331
end
391332

392333
-- Date property
393-
date_str, input = parse_pattern(input, '"(<[^>]+>)"')
334+
date_str, input = parsing.parse_pattern(input, '"(<[^>]+>)"')
394335
if date_str then
395336
---@type string?, Date?
396337
local date_content, date_value
@@ -422,7 +363,7 @@ function PropertyMatch:parse(input)
422363
end
423364

424365
-- String property
425-
string_str, input = parse_pattern(input, '"[^"]+"')
366+
string_str, input = parsing.parse_pattern(input, '"[^"]+"')
426367
if string_str then
427368
---@type string
428369
local unquote_string = string_str:match('^"([^"]+)"$')
@@ -437,7 +378,7 @@ end
437378
---@param input string
438379
---@return PropertyMatchOperator, string
439380
function PropertyMatch:_parse_operator(input)
440-
return parse_pattern_choice(input, '%=', '%<%>', '%<%=', '%<', '%>%=', '%>') --[[@as PropertyMatchOperator]]
381+
return parsing.parse_pattern_choice(input, '%=', '%<%>', '%<%=', '%<', '%>%=', '%>') --[[@as PropertyMatchOperator]]
441382
end
442383

443384
---Constructs a PropertyNumberMatch
@@ -559,16 +500,16 @@ function TodoMatch:parse(input)
559500
-- Parse the '/' or '/!' prefix that indicates a TodoMatch
560501
---@type string?
561502
local prefix
562-
prefix, input = parse_pattern(input, '%/[%!]?')
503+
prefix, input = parsing.parse_pattern(input, '%/[%!]?')
563504
if not prefix then
564505
return nil, original_input
565506
end
566507

567508
-- Parse a whitelist of keywords
568509
--- @type string[]?
569510
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+')
572513
end, '%|')
573514
if anyOf and #anyOf > 0 then
574515
-- Successfully parsed the whitelist, return it
@@ -580,11 +521,11 @@ function TodoMatch:parse(input)
580521
-- Parse a blacklist of keywords
581522
---@type string?
582523
local negation
583-
negation, input = parse_pattern(input, '-')
524+
negation, input = parsing.parse_pattern(input, '-')
584525
if negation then
585526
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+')
588529
end, '%-')
589530

590531
if negative_items then

lua/orgmode/utils/parsing.lua

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
local M = {}
2+
3+
---Parses a pattern from the beginning of an input using Lua's pattern syntax
4+
---@param input string
5+
---@param pattern string
6+
---@return string?, string
7+
function M.parse_pattern(input, pattern)
8+
local value = input:match('^' .. pattern)
9+
if value then
10+
return value, input:sub(#value + 1)
11+
else
12+
return nil, input
13+
end
14+
end
15+
16+
---Parses the first of a sequence of patterns
17+
---@param input string The input to parse
18+
---@param ... string The patterns to accept
19+
---@return string?, string
20+
function M.parse_pattern_choice(input, ...)
21+
for _, pattern in ipairs({ ... }) do
22+
local value, remaining = M.parse_pattern(input, pattern)
23+
if value then
24+
return value, remaining
25+
end
26+
end
27+
28+
return nil, input
29+
end
30+
31+
---@generic T
32+
---@param input string
33+
---@param item_parser fun(input: string): (T?, string)
34+
---@param delimiter_pattern string
35+
---@return (T[])?, string
36+
function M.parse_delimited_sequence(input, item_parser, delimiter_pattern)
37+
local sequence, item, delimiter = {}, nil, nil
38+
local original_input = input
39+
40+
-- Parse the first item
41+
item, input = item_parser(input)
42+
if not item then
43+
return sequence, input
44+
end
45+
table.insert(sequence, item)
46+
47+
--- @type string
48+
local snapshot = input
49+
50+
-- Continue parsing items while there's a trailing delimiter
51+
delimiter, input = M.parse_pattern(input, delimiter_pattern)
52+
while delimiter do
53+
item, input = item_parser(input)
54+
55+
-- If not another element, eturn the previously parsed items
56+
if not item then
57+
return sequence, snapshot
58+
end
59+
60+
table.insert(sequence, item)
61+
snapshot = input
62+
63+
delimiter, input = M.parse_pattern(input, delimiter_pattern)
64+
end
65+
66+
return sequence, input
67+
end
68+
69+
return M

0 commit comments

Comments
 (0)