1
- local utils = require (' orgmode.utils' )
2
1
--- @class OrgAgendaFilter
3
2
--- @field value string
4
- --- @field available_tags table<string , boolean>
5
- --- @field available_categories table<string , boolean>
6
- --- @field filter_type ' include' | ' exclude'
7
- --- @field tags table[]
8
- --- @field categories table[]
3
+ --- @field available_values table<string , boolean>
4
+ --- @field values table[]
9
5
--- @field term string
10
6
--- @field parsed boolean
11
- --- @field applying boolean
12
7
local AgendaFilter = {}
13
8
9
+ --- @return OrgAgendaFilter
14
10
function AgendaFilter :new ()
15
11
local data = {
16
12
value = ' ' ,
17
- available_tags = {},
18
- available_categories = {},
19
- filter_type = ' exclude' ,
20
- tags = {},
21
- categories = {},
13
+ available_values = {},
14
+ values = {},
22
15
term = ' ' ,
23
16
parsed = false ,
24
- applying = false ,
25
17
}
26
18
setmetatable (data , self )
27
19
self .__index = self
@@ -40,156 +32,92 @@ function AgendaFilter:matches(headline)
40
32
return true
41
33
end
42
34
local term_match = vim .trim (self .term ) == ' '
43
- local tag_cat_match_empty = # self .tags == 0 and # self . categories == 0
35
+ local values_match_empty = # self .values == 0
44
36
45
37
if not term_match then
46
38
local rgx = vim .regex (self .term ) --[[ @as vim.regex]]
47
39
term_match = rgx :match_str (headline :get_title ()) and true or false
48
40
end
49
41
50
- if tag_cat_match_empty then
42
+ if values_match_empty then
51
43
return term_match
52
44
end
53
45
54
- local tag_cat_match = false
55
-
56
- if self .filter_type == ' include' then
57
- tag_cat_match = self :_matches_include (headline )
58
- else
59
- tag_cat_match = self :_matches_exclude (headline )
60
- end
46
+ local tag_cat_match = self :_match (headline )
61
47
62
48
return tag_cat_match and term_match
63
49
end
64
50
65
- --- @param headline OrgHeadline
66
51
--- @private
67
- function AgendaFilter :_matches_exclude (headline )
68
- for _ , tag in ipairs (self .tags ) do
69
- if headline :has_tag (tag .value ) then
70
- return false
71
- end
72
- end
73
-
74
- for _ , category in ipairs (self .categories ) do
75
- if headline :matches_category (category .value ) then
76
- return false
77
- end
78
- end
79
-
80
- return true
81
- end
82
-
83
52
--- @param headline OrgHeadline
84
- --- @private
85
- function AgendaFilter :_matches_include (headline )
86
- local tags_to_check = {}
87
- local categories_to_check = {}
88
-
89
- for _ , tag in ipairs (self .tags ) do
90
- if tag .operator == ' -' then
91
- if headline :has_tag (tag .value ) then
92
- return false
93
- end
94
- else
95
- table.insert (tags_to_check , tag .value )
96
- end
97
- end
98
-
99
- for _ , category in ipairs (self .categories ) do
100
- if category .operator == ' -' then
101
- if headline :matches_category (category .value ) then
53
+ --- @return boolean
54
+ function AgendaFilter :_match (headline )
55
+ for _ , value in ipairs (self .values ) do
56
+ if value .operator == ' -' then
57
+ if headline :has_tag (value .value ) or headline :matches_category (value .value ) then
102
58
return false
103
59
end
104
- else
105
- table.insert (categories_to_check , category .value )
106
- end
107
- end
108
-
109
- local tags_passed = # tags_to_check == 0
110
- local categories_passed = # categories_to_check == 0
111
-
112
- for _ , category in ipairs (categories_to_check ) do
113
- if headline :matches_category (category ) then
114
- categories_passed = true
115
- break
116
- end
117
- end
118
-
119
- for _ , tag in ipairs (tags_to_check ) do
120
- if headline :has_tag (tag ) then
121
- tags_passed = true
122
- break
60
+ elseif not headline :has_tag (value .value ) and not headline :matches_category (value .value ) then
61
+ return false
123
62
end
124
63
end
125
64
126
- return tags_passed and categories_passed
65
+ return true
127
66
end
128
67
129
68
--- @param filter string
130
69
--- @param skip_check ? boolean do not check if given values exist in the current view
131
70
function AgendaFilter :parse (filter , skip_check )
132
71
filter = filter or ' '
133
72
self .value = filter
134
- self .tags = {}
135
- self .categories = {}
73
+ self .values = {}
136
74
local search_rgx = ' /[^/]*/?'
137
75
local search_term = filter :match (search_rgx )
138
76
if search_term then
139
77
search_term = search_term :gsub (' ^/*' , ' ' ):gsub (' /*$' , ' ' )
140
78
end
141
79
filter = filter :gsub (search_rgx , ' ' )
142
80
for operator , tag_cat in string.gmatch (filter , ' ([%+%-]*)([^%-%+]+)' ) do
143
- if not operator or operator == ' ' or operator == ' +' then
144
- self .filter_type = ' include'
145
- end
146
81
local val = vim .trim (tag_cat )
147
82
if val ~= ' ' then
148
- if self .available_tags [val ] or skip_check then
149
- table.insert (self .tags , { operator = operator , value = val })
150
- elseif self .available_categories [val ] or skip_check then
151
- table.insert (self .categories , { operator = operator , value = val })
83
+ if self .available_values [val ] or skip_check then
84
+ table.insert (self .values , { operator = operator , value = val })
152
85
end
153
86
end
154
87
end
155
88
self .term = search_term or ' '
156
- self .applying = true
157
- if skip_check then
158
- self .parsed = true
159
- end
89
+ return self
160
90
end
161
91
162
92
function AgendaFilter :reset ()
163
93
self .value = ' '
164
94
self .term = ' '
165
95
self .parsed = false
166
- self .applying = false
167
96
end
168
97
169
- --- @param content table []
170
- function AgendaFilter :parse_tags_and_categories ( content )
98
+ --- @param agenda_views OrgAgendaViewType []
99
+ function AgendaFilter :parse_available_filters ( agenda_views )
171
100
if self .parsed then
172
101
return
173
102
end
174
- local tags = {}
175
- local categories = {}
176
- for _ , item in ipairs (content ) do
177
- if item .jumpable and item .headline then
178
- categories [item .headline :get_category ():lower ()] = true
179
- for _ , tag in ipairs (item .headline :get_tags ()) do
180
- tags [tag :lower ()] = true
103
+ local values = {}
104
+ for _ , agenda_view in ipairs (agenda_views ) do
105
+ for _ , line in ipairs (agenda_view :get_lines ()) do
106
+ if line .headline then
107
+ values [line .headline :get_category ()] = true
108
+ for _ , tag in ipairs (line .headline :get_tags ()) do
109
+ values [tag ] = true
110
+ end
181
111
end
182
112
end
183
113
end
184
- self .available_tags = tags
185
- self .available_categories = categories
114
+ self .available_values = values
186
115
self .parsed = true
187
116
end
188
117
189
118
--- @return string[]
190
119
function AgendaFilter :get_completion_list ()
191
- local list = vim .tbl_keys (self .available_tags )
192
- return utils .concat (list , vim .tbl_keys (self .available_categories ), true )
120
+ return vim .tbl_keys (self .available_values )
193
121
end
194
122
195
123
return AgendaFilter
0 commit comments