1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright 2006 - 2021, Tomas Babej, Paul Beckingham, Federico Hernandez.
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included
13 // in all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 // SOFTWARE.
22 //
23 // https://www.opensource.org/licenses/mit-license.php
24 //
25 ////////////////////////////////////////////////////////////////////////////////
26
27 #include <cmake.h>
28 #include <CmdIDs.h>
29 #include <sstream>
30 #include <algorithm>
31 #include <Context.h>
32 #include <Filter.h>
33 #include <main.h>
34 #include <shared.h>
35
36 std::string zshColonReplacement = ",";
37
38 ////////////////////////////////////////////////////////////////////////////////
CmdIDs()39 CmdIDs::CmdIDs ()
40 {
41 _keyword = "ids";
42 _usage = "task <filter> ids";
43 _description = "Shows the IDs of matching tasks, as a range";
44 _read_only = true;
45 _displays_id = true;
46 _needs_gc = true;
47 _uses_context = false;
48 _accepts_filter = true;
49 _accepts_modifications = false;
50 _accepts_miscellaneous = false;
51 _category = Command::Category::metadata;
52 }
53
54 ////////////////////////////////////////////////////////////////////////////////
execute(std::string & output)55 int CmdIDs::execute (std::string& output)
56 {
57 // Apply filter.
58 handleUntil ();
59 handleRecurrence ();
60 Filter filter;
61 std::vector <Task> filtered;
62 filter.subset (filtered);
63
64 // Find number of matching tasks.
65 std::vector <int> ids;
66 for (auto& task : filtered)
67 if (task.id)
68 ids.push_back (task.id);
69
70 std::sort (ids.begin (), ids.end ());
71 output = compressIds (ids) + '\n';
72
73 Context::getContext ().headers.clear ();
74 return 0;
75 }
76
77 ////////////////////////////////////////////////////////////////////////////////
78 // The vector must be sorted first. This is a modified version of the run-
79 // length encoding algorithm.
80 //
81 // This function converts the vector:
82 //
83 // [1, 3, 4, 6, 7, 8, 9, 11]
84 //
85 // to ths string:
86 //
87 // 1,3-4,6-9,11
88 //
compressIds(const std::vector<int> & ids)89 std::string CmdIDs::compressIds (const std::vector <int>& ids)
90 {
91 std::stringstream result;
92
93 auto range_start = 0;
94 auto range_end = 0;
95
96 for (unsigned int i = 0; i < ids.size (); ++i)
97 {
98 if (i + 1 == ids.size ())
99 {
100 if (result.str ().length ())
101 result << ' ';
102
103 if (range_start < range_end)
104 result << ids[range_start] << '-' << ids[range_end];
105 else
106 result << ids[range_start];
107 }
108 else
109 {
110 if (ids[range_end] + 1 == ids[i + 1])
111 {
112 ++range_end;
113 }
114 else
115 {
116 if (result.str ().length ())
117 result << ' ';
118
119 if (range_start < range_end)
120 result << ids[range_start] << '-' << ids[range_end];
121 else
122 result << ids[range_start];
123
124 range_start = range_end = i + 1;
125 }
126 }
127 }
128
129 return result.str ();
130 }
131
132 ////////////////////////////////////////////////////////////////////////////////
CmdCompletionIds()133 CmdCompletionIds::CmdCompletionIds ()
134 {
135 _keyword = "_ids";
136 _usage = "task <filter> _ids";
137 _description = "Shows the IDs of matching tasks, in the form of a list";
138 _read_only = true;
139 _displays_id = true;
140 _needs_gc = true;
141 _uses_context = false;
142 _accepts_filter = true;
143 _accepts_modifications = false;
144 _accepts_miscellaneous = false;
145 _category = Command::Category::internal;
146 }
147
148 ////////////////////////////////////////////////////////////////////////////////
execute(std::string & output)149 int CmdCompletionIds::execute (std::string& output)
150 {
151 // Apply filter.
152 handleUntil ();
153 handleRecurrence ();
154 Filter filter;
155 std::vector <Task> filtered;
156 filter.subset (filtered);
157
158 std::vector <int> ids;
159 for (auto& task : filtered)
160 if (task.getStatus () != Task::deleted &&
161 task.getStatus () != Task::completed)
162 ids.push_back (task.id);
163
164 std::sort (ids.begin (), ids.end ());
165 output = join ("\n", ids) + '\n';
166
167 Context::getContext ().headers.clear ();
168 return 0;
169 }
170
171 ////////////////////////////////////////////////////////////////////////////////
CmdZshCompletionIds()172 CmdZshCompletionIds::CmdZshCompletionIds ()
173 {
174 _keyword = "_zshids";
175 _usage = "task <filter> _zshids";
176 _description = "Shows the IDs and descriptions of matching tasks";
177 _read_only = true;
178 _displays_id = true;
179 _needs_gc = true;
180 _uses_context = false;
181 _accepts_filter = true;
182 _accepts_modifications = false;
183 _accepts_miscellaneous = false;
184 _category = Command::Category::internal;
185 }
186
187 ////////////////////////////////////////////////////////////////////////////////
execute(std::string & output)188 int CmdZshCompletionIds::execute (std::string& output)
189 {
190 // Apply filter.
191 handleUntil ();
192 handleRecurrence ();
193 Filter filter;
194 std::vector <Task> filtered;
195 filter.subset (filtered);
196
197 std::stringstream out;
198 for (auto& task : filtered)
199 if (task.getStatus () != Task::deleted &&
200 task.getStatus () != Task::completed)
201 out << task.id
202 << ':'
203 << str_replace(task.get ("description"), ":", zshColonReplacement)
204 << '\n';
205
206 output = out.str ();
207
208 Context::getContext ().headers.clear ();
209 return 0;
210 }
211
212 ////////////////////////////////////////////////////////////////////////////////
CmdUUIDs()213 CmdUUIDs::CmdUUIDs ()
214 {
215 _keyword = "uuids";
216 _usage = "task <filter> uuids";
217 _description = "Shows the UUIDs of matching tasks, as a space-separated list";
218 _read_only = true;
219 _displays_id = false;
220 _needs_gc = true;
221 _uses_context = false;
222 _accepts_filter = true;
223 _accepts_modifications = false;
224 _accepts_miscellaneous = false;
225 _category = Command::Category::metadata;
226 }
227
228 ////////////////////////////////////////////////////////////////////////////////
execute(std::string & output)229 int CmdUUIDs::execute (std::string& output)
230 {
231 // Apply filter.
232 handleUntil ();
233 handleRecurrence ();
234 Filter filter;
235 std::vector <Task> filtered;
236 filter.subset (filtered);
237
238 std::vector <std::string> uuids;
239 uuids.reserve(filtered.size());
240 for (auto& task : filtered)
241 uuids.push_back (task.get ("uuid"));
242
243 std::sort (uuids.begin (), uuids.end ());
244 output = join (" ", uuids) + '\n';
245
246 Context::getContext ().headers.clear ();
247 return 0;
248 }
249
250 ////////////////////////////////////////////////////////////////////////////////
CmdCompletionUuids()251 CmdCompletionUuids::CmdCompletionUuids ()
252 {
253 _keyword = "_uuids";
254 _usage = "task <filter> _uuids";
255 _description = "Shows the UUIDs of matching tasks, as a list";
256 _read_only = true;
257 _displays_id = false;
258 _needs_gc = true;
259 _uses_context = false;
260 _accepts_filter = true;
261 _accepts_modifications = false;
262 _accepts_miscellaneous = false;
263 _category = Command::Category::internal;
264 }
265
266 ////////////////////////////////////////////////////////////////////////////////
execute(std::string & output)267 int CmdCompletionUuids::execute (std::string& output)
268 {
269 // Apply filter.
270 handleUntil ();
271 handleRecurrence ();
272 Filter filter;
273 std::vector <Task> filtered;
274 filter.subset (filtered);
275
276 std::vector <std::string> uuids;
277 uuids.reserve(filtered.size());
278 for (auto& task : filtered)
279 uuids.push_back (task.get ("uuid"));
280
281 std::sort (uuids.begin (), uuids.end ());
282 output = join ("\n", uuids) + '\n';
283
284 Context::getContext ().headers.clear ();
285 return 0;
286 }
287
288 ////////////////////////////////////////////////////////////////////////////////
CmdZshCompletionUuids()289 CmdZshCompletionUuids::CmdZshCompletionUuids ()
290 {
291 _keyword = "_zshuuids";
292 _usage = "task <filter> _zshuuids";
293 _description = "Shows the UUIDs and descriptions of matching tasks";
294 _read_only = true;
295 _displays_id = false;
296 _needs_gc = true;
297 _uses_context = false;
298 _accepts_filter = true;
299 _accepts_modifications = false;
300 _accepts_miscellaneous = false;
301 _category = Command::Category::internal;
302 }
303
304 ////////////////////////////////////////////////////////////////////////////////
execute(std::string & output)305 int CmdZshCompletionUuids::execute (std::string& output)
306 {
307 // Apply filter.
308 handleUntil ();
309 handleRecurrence ();
310 Filter filter;
311 std::vector <Task> filtered;
312 filter.subset (filtered);
313
314 std::stringstream out;
315 for (auto& task : filtered)
316 out << task.get ("uuid")
317 << ':'
318 << str_replace (task.get ("description"), ":", zshColonReplacement)
319 << '\n';
320
321 output = out.str ();
322
323 Context::getContext ().headers.clear ();
324 return 0;
325 }
326
327 ///////////////////////////////////////////////////////////////////////////////
328