Commit
+50 -28 +/-3 browse
1 | diff --git a/lib/cmd.ml b/lib/cmd.ml |
2 | index c402032..15cdf75 100644 |
3 | --- a/lib/cmd.ml |
4 | +++ b/lib/cmd.ml |
5 | @@ -64,16 +64,16 @@ let list_style_arg = |
6 | let filter_args = |
7 | let open Command.Let_syntax in |
8 | [%map_open |
9 | - let title = |
10 | + let titles = |
11 | flag "title" |
12 | - (optional (search_arg `Title)) |
13 | + (listed (search_arg `Title)) |
14 | ~doc:"regular expression matching the note title" |
15 | and tags = |
16 | flag "tag" |
17 | (listed (search_arg `Tags)) |
18 | ~doc:"sequence of regular expressions matching note tags" |
19 | and operator = flag "and" no_arg ~doc:"logical AND instead of default OR" in |
20 | - (title, tags, operator)] |
21 | + (titles, tags, operator)] |
22 | |
23 | (* |
24 | * commands |
25 | @@ -89,7 +89,7 @@ note to stdout as plain text however the encoding can be adjusted to yaml or |
26 | json for consumption by other tools. |
27 | |}) |
28 | [%map_open |
29 | - let title, tags, operator = filter_args |
30 | + let titles, tags, operator = filter_args |
31 | and encoding = |
32 | flag "encoding" |
33 | (optional_with_default cfg.encoding encoding_arg) |
34 | @@ -98,7 +98,7 @@ json for consumption by other tools. |
35 | fun () -> |
36 | let notes = |
37 | Note.find_many |
38 | - ~term:{ title; tags; operator = flag_to_op operator } |
39 | + ~term:{ titles; tags; operator = flag_to_op operator } |
40 | get_notes |
41 | in |
42 | List.iter |
43 | @@ -163,12 +163,12 @@ let delete_note = |
44 | Delete the first note that matches the filter criteria. |
45 | |}) |
46 | [%map_open |
47 | - let title, tags, operator = filter_args in |
48 | + let titles, tags, operator = filter_args in |
49 | fun () -> |
50 | let notes = get_notes in |
51 | let note = |
52 | Note.find_one |
53 | - ~term:{ title; tags; operator = flag_to_op operator } |
54 | + ~term:{ titles; tags; operator = flag_to_op operator } |
55 | notes |
56 | in |
57 | match note with |
58 | @@ -185,11 +185,11 @@ let edit_note = |
59 | Select a note that matches the filter criteria and open it in your text editor. |
60 | |}) |
61 | [%map_open |
62 | - let title, tags, operator = filter_args in |
63 | + let titles, tags, operator = filter_args in |
64 | fun () -> |
65 | let note = |
66 | Note.find_one |
67 | - ~term:{ title; tags; operator = flag_to_op operator } |
68 | + ~term:{ titles; tags; operator = flag_to_op operator } |
69 | get_notes |
70 | in |
71 | match note with |
72 | @@ -207,7 +207,7 @@ List one or more notes that match the filter criteria, if no filter criteria |
73 | is provided then all notes will be listed. |
74 | |}) |
75 | [%map_open |
76 | - let title, tags, operator = filter_args |
77 | + let titles, tags, operator = filter_args |
78 | and style = |
79 | flag "style" |
80 | (optional_with_default cfg.list_style list_style_arg) |
81 | @@ -220,7 +220,7 @@ is provided then all notes will be listed. |
82 | fun () -> |
83 | let notes = |
84 | Note.find_many |
85 | - ~term:{ title; tags; operator = flag_to_op operator } |
86 | + ~term:{ titles; tags; operator = flag_to_op operator } |
87 | get_notes |
88 | in |
89 | let styles = cfg.styles in |
90 | diff --git a/lib/note.ml b/lib/note.ml |
91 | index e73442b..607e3dc 100644 |
92 | --- a/lib/note.ml |
93 | +++ b/lib/note.ml |
94 | @@ -3,7 +3,7 @@ open Core |
95 | type operator = And | Or |
96 | |
97 | and term = { |
98 | - title : Re.Str.regexp option; |
99 | + titles : Re.Str.regexp list; |
100 | tags : Re.Str.regexp list; |
101 | operator : operator; |
102 | } |
103 | @@ -143,19 +143,21 @@ end |
104 | |
105 | let find_many ~term notes = |
106 | let open Re.Str in |
107 | - if Option.is_none term.title && List.length term.tags = 0 then notes |
108 | + let n_titles, n_tags = (List.length term.titles, List.length term.tags) in |
109 | + if n_titles + n_tags = 0 then notes |
110 | else |
111 | List.filter |
112 | ~f:(fun note -> |
113 | let has_title = |
114 | - match term.title with |
115 | - | Some title -> string_match title (get_title note) 0 |
116 | - | None -> false |
117 | - in |
118 | - let has_title = Option.is_none term.title || has_title in |
119 | - let has_tags = |
120 | let result = |
121 | - List.find |
122 | + List.count |
123 | + ~f:(fun expr -> string_match expr (get_title note) 0) |
124 | + term.titles |
125 | + in |
126 | + match term.operator with Or -> result > 0 | And -> result = n_titles |
127 | + and has_tags = |
128 | + let result = |
129 | + List.count |
130 | ~f:(fun expr -> |
131 | Option.is_some |
132 | (List.find |
133 | @@ -163,9 +165,8 @@ let find_many ~term notes = |
134 | (get_tags note))) |
135 | term.tags |
136 | in |
137 | - Option.is_some result |
138 | + match term.operator with Or -> result > 0 | And -> result = n_tags |
139 | in |
140 | - let has_tags = List.length term.tags = 0 || has_tags in |
141 | match term.operator with |
142 | | Or -> has_title || has_tags |
143 | | And -> has_title && has_tags) |
144 | diff --git a/test/search.ml b/test/search.ml |
145 | index e7cb68a..c98dfb4 100644 |
146 | --- a/test/search.ml |
147 | +++ b/test/search.ml |
148 | @@ -22,26 +22,47 @@ let test_filter_by_keys = |
149 | Note.find_many |
150 | ~term: |
151 | { |
152 | - title = None; |
153 | + titles = [ Re.Str.regexp "A Very Important Note" ]; |
154 | + tags = []; |
155 | + operator = Note.Or; |
156 | + } |
157 | + notes |
158 | + in |
159 | + assert (List.length result = 1); |
160 | + let result = |
161 | + Note.find_many |
162 | + ~term: |
163 | + { |
164 | + titles = [ Re.Str.regexp "A Very Important Note" ]; |
165 | + tags = []; |
166 | + operator = Note.Or; |
167 | + } |
168 | + notes |
169 | + in |
170 | + assert (List.length result = 1); |
171 | + let result = |
172 | + Note.find_many |
173 | + ~term: |
174 | + { |
175 | + titles = []; |
176 | tags = |
177 | [ Re.Str.regexp "fuu"; Re.Str.regexp "bar"; Re.Str.regexp "baz" ]; |
178 | - operator = Note.Or; |
179 | + operator = Note.And; |
180 | } |
181 | notes |
182 | in |
183 | - assert (List.length result = 3) |
184 | + assert (List.length result = 2) |
185 | |
186 | let test_filter_by_title_find_one = |
187 | let notes = make_notes in |
188 | let result = |
189 | Note.find_one |
190 | - ~term:{ title = None; tags = [ Re.Str.regexp "fuu" ]; operator = Note.Or } |
191 | + ~term:{ titles = [Re.Str.regexp "^A.*"]; tags = []; operator = Note.Or } |
192 | notes |
193 | in |
194 | assert (Option.is_some result); |
195 | let note = Option.get result in |
196 | - (* title should take priority *) |
197 | - assert (Note.get_title note = "fuu") |
198 | + assert (Note.get_title note = "A Very Important Note") |
199 | |
200 | let () = |
201 | test_filter_by_keys; |