]> git.armaanb.net Git - gen-shell.git/blob - src/review.cpp.bak
started to remove tw specifics
[gen-shell.git] / src / review.cpp.bak
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright 2006 - 2017, 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 // http://www.opensource.org/licenses/mit-license.php
24 //
25 ////////////////////////////////////////////////////////////////////////////////
26
27 #include <cmake.h>
28 #include <iostream>
29 #include <sstream>
30 #include <vector>
31 #include <string>
32 #include <algorithm>
33 #include <stdlib.h>
34
35 #ifdef HAVE_READLINE
36 #include <readline/readline.h>
37 #include <readline/history.h>
38 #endif
39
40 #include <unistd.h>
41 #include <sys/ioctl.h>
42
43 #ifdef SOLARIS
44 #include <sys/termios.h>
45 #endif
46
47 #include <Color.h>
48 #include <Lexer.h>
49 #include <shared.h>
50 #include <format.h>
51
52 std::string getResponse (const std::string&);
53
54 ////////////////////////////////////////////////////////////////////////////////
55 static unsigned int getWidth ()
56 {
57   // Determine window size.
58 //  int width = config.getInteger ("defaultwidth");
59   static auto width = 0;
60
61   if (width == 0)
62   {
63     unsigned short buff[4];
64     if (ioctl (STDOUT_FILENO, TIOCGWINSZ, &buff) != -1)
65       width = buff[1];
66   }
67
68   return width;
69 }
70
71 ////////////////////////////////////////////////////////////////////////////////
72 static void editTask (const std::string& uuid)
73 {
74   std::string command = "task rc.confirmation:no rc.verbose:nothing " + uuid + " edit";
75   system (command.c_str ());
76
77   command = "task rc.confirmation:no rc.verbose:nothing " + uuid + " modify reviewed:now";
78   system (command.c_str ());
79   std::cout << "Modified.\n\n\n\n";
80 }
81
82 ////////////////////////////////////////////////////////////////////////////////
83 static void modifyTask (const std::string& uuid)
84 {
85   Color text ("color15 on gray6");
86   std::string modifications;
87   do
88   {
89     modifications = getResponse (text.colorize (" Enter modification args [example: +tag -tag /teh/the/ project:X] ") + " ");
90   }
91   while (modifications == "");
92
93   std::string command = "task rc.confirmation:no rc.verbose:nothing " + uuid + " modify " + modifications;
94   system (command.c_str ());
95
96   std::cout << "Modified.\n\n\n\n";
97 }
98
99 ////////////////////////////////////////////////////////////////////////////////
100 static void reviewTask (const std::string& uuid)
101 {
102   std::string command = "task rc.confirmation:no rc.verbose:nothing " + uuid + " modify reviewed:now";
103   system (command.c_str ());
104   std::cout << "Marked as reviewed.\n\n\n\n";
105 }
106
107 ////////////////////////////////////////////////////////////////////////////////
108 static void completeTask (const std::string& uuid)
109 {
110   std::string command = "task rc.confirmation:no rc.verbose:nothing " + uuid + " done";
111   system (command.c_str ());
112   std::cout << "Completed.\n\n\n\n";
113 }
114
115 ////////////////////////////////////////////////////////////////////////////////
116 static void deleteTask (const std::string& uuid)
117 {
118   std::string command = "task rc.confirmation:no rc.verbose:nothing " + uuid + " delete";
119   system (command.c_str ());
120   std::cout << "Deleted.\n\n\n\n";
121 }
122
123 ////////////////////////////////////////////////////////////////////////////////
124 static const std::string reviewNothing ()
125 {
126   return "\nThere are no tasks needing review.\n\n";
127 }
128
129 ////////////////////////////////////////////////////////////////////////////////
130 static const std::string reviewStart (
131   unsigned int width)
132 {
133   std::string welcome = "The review process is important for keeping your list "
134                         "accurate, so you are working on the right tasks.\n"
135                         "\n"
136                         "For each task you are shown, look at the metadata. "
137                         "Determine whether the task needs to be changed (enter "
138                         "'e' to edit), or whether it is accurate ('enter' or "
139                         "'r' to mark as reviewed). You may skip a task ('s') "
140                         "but a skipped task is not considered reviewed.\n"
141                         "\n"
142                         "You may stop at any time, and resume later right "
143                         "where you left off. See 'man tasksh' for more details.";
144
145   std::vector <std::string> lines;
146   wrapText (lines, welcome, width, false);
147   welcome = join ("\n", lines);
148
149   return "\n" + welcome + "\n\n";
150 }
151
152 ////////////////////////////////////////////////////////////////////////////////
153 static const std::string banner (
154   unsigned int current,
155   unsigned int total,
156   unsigned int width,
157   const std::string& message)
158 {
159   std::stringstream progress;
160   progress << " ["
161            << current
162            << " of "
163            << total
164            << "] ";
165
166   Color progressColor ("color15 on color9");
167   Color descColor     ("color15 on gray6");
168
169   std::string composed;
170   if (progress.str ().length () + message.length () + 1 < width)
171     composed = progressColor.colorize (progress.str ()) +
172                descColor.colorize (" " + message +
173                  std::string (width - progress.str ().length () - message.length () - 1, ' '));
174   else
175     composed = progressColor.colorize (progress.str ()) +
176                descColor.colorize (" " + message.substr (0, message.length () - 3) + "...");
177
178   return composed + "\n";
179 }
180
181 ////////////////////////////////////////////////////////////////////////////////
182 static const std::string menu ()
183 {
184   return Color ("color15 on gray6").colorize (" (Enter) Mark as reviewed, (s)kip, (e)dit, (m)odify, (c)omplete, (d)elete, (q)uit ") + " ";
185 }
186
187 ////////////////////////////////////////////////////////////////////////////////
188 static void reviewLoop (const std::vector <std::string>& uuids, unsigned int limit, bool autoClear)
189 {
190   auto width = getWidth ();
191   unsigned int reviewed = 0;
192
193   // If a limit was specified ('review 10'), then it should override the data
194   // set size, if it is smaller.
195   unsigned int total = uuids.size ();
196   if (limit)
197     total = std::min (total, limit);
198
199   if (total == 0)
200   {
201     std::cout << reviewNothing ();
202     return;
203   }
204
205   std::cout << reviewStart (width);
206
207   unsigned int current = 0;
208   while (current < total &&
209          (limit == 0 || reviewed < limit))
210   {
211     // Run 'info' report for task.
212     auto uuid = uuids[current];
213
214     // Display banner for this task.
215     std::string dummy;
216     std::string description;
217     execute ("task",
218              {"_get", uuid + ".description"},
219              dummy,
220              description);
221
222     std::string response;
223     bool repeat;
224     do
225     {
226       repeat = false;
227       std::cout << banner (current + 1, total, width, Lexer::trimRight (description, "\n"));
228
229       // Use 'system' to run the command and show the output.
230       std::string command = "task " + uuid + " information";
231       system (command.c_str ());
232
233       // Display prompt, get input.
234       response = getResponse (menu ());
235
236            if (response == "e") { editTask (uuid);                                   }
237       else if (response == "m") { modifyTask (uuid);          repeat = true;         }
238       else if (response == "s") { std::cout << "Skipped\n\n"; ++current;             }
239       else if (response == "c") { completeTask (uuid);        ++current; ++reviewed; }
240       else if (response == "d") { deleteTask (uuid);          ++current; ++reviewed; }
241       else if (response == "")  { reviewTask (uuid);          ++current; ++reviewed; }
242       else if (response == "r") { reviewTask (uuid);          ++current; ++reviewed; }
243       else if (response == "q") { break;                                             }
244
245       else
246       {
247         std::cout << format ("Command '{1}' is not recognized.", response) << "\n";
248       }
249
250       // Note that just hitting <Enter> yields an empty command, which does
251       // nothing but advance to the next task.
252
253       if (autoClear)
254         std::cout << "\033[2J\033[0;0H";
255     }
256     while (repeat);
257
258     if (response == "q")
259       break;
260   }
261
262   std::cout << "\n"
263             << format ("End of review. {1} out of {2} tasks reviewed.", reviewed, total)
264             << "\n\n";
265 }
266
267 ////////////////////////////////////////////////////////////////////////////////
268 int cmdReview (const std::vector <std::string>& args, bool autoClear)
269 {
270   // Is there a specified limit?
271   unsigned int limit = 0;
272   if (args.size () == 2)
273     limit = strtol (args[1].c_str (), NULL, 10);
274
275   // Configure 'reviewed' UDA, but only if necessary.
276   std::string input;
277   std::string output;
278   auto status = execute ("task", {"_get", "rc.uda.reviewed.type"}, input, output);
279   if (status || output != "date\n")
280   {
281     if (confirm ("Tasksh needs to define a 'reviewed' UDA of type 'date' for all tasks.  Ok to proceed?"))
282     {
283       execute ("task", {"rc.confirmation:no", "rc.verbose:nothing", "config", "uda.reviewed.type",  "date"},     input, output);
284       execute ("task", {"rc.confirmation:no", "rc.verbose:nothing", "config", "uda.reviewed.label", "Reviewed"}, input, output);
285     }
286   }
287
288   // Configure '_reviewed' report, but only if necessary.
289   status = execute ("task", {"_get", "rc.report._reviewed.columns"}, input, output);
290   if (status || output != "uuid\n")
291   {
292     if (confirm ("Tasksh needs to define a '_reviewed' report to identify tasks needing review.  Ok to proceed?"))
293     {
294       execute ("task", {"rc.confirmation:no", "rc.verbose:nothing", "config", "report._reviewed.description",
295                         "Tasksh review report.  Adjust the filter to your needs."                                              }, input, output);
296       execute ("task", {"rc.confirmation:no", "rc.verbose:nothing", "config", "report._reviewed.columns", "uuid"               }, input, output);
297       execute ("task", {"rc.confirmation:no", "rc.verbose:nothing", "config", "report._reviewed.sort",    "reviewed+,modified+"}, input, output);
298       execute ("task", {"rc.confirmation:no", "rc.verbose:nothing", "config", "report._reviewed.filter",
299                         "( reviewed.none: or reviewed.before:now-6days ) and ( +PENDING or +WAITING )"                         }, input, output);
300     }
301   }
302
303   // Obtain a list of UUIDs to review.
304   status = execute ("task",
305                     {
306                       "rc.color=off",
307                       "rc.detection=off",
308                       "rc._forcecolor=off",
309                       "rc.verbose=nothing",
310                       "_reviewed"
311                     },
312                     input, output);
313
314   // Review the set of UUIDs.
315   auto uuids = split (Lexer::trimRight (output, "\n"), '\n');
316   reviewLoop (uuids, limit, autoClear);
317   return 0;
318 }
319
320 ////////////////////////////////////////////////////////////////////////////////