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 <CmdPrepend.h>
29 #include <iostream>
30 #include <Context.h>
31 #include <Filter.h>
32 #include <shared.h>
33 #include <format.h>
34 #include <main.h>
35
36 ////////////////////////////////////////////////////////////////////////////////
CmdPrepend()37 CmdPrepend::CmdPrepend ()
38 {
39 _keyword = "prepend";
40 _usage = "task <filter> prepend <mods>";
41 _description = "Prepends text to an existing task description";
42 _read_only = false;
43 _displays_id = false;
44 _needs_gc = false;
45 _uses_context = true;
46 _accepts_filter = true;
47 _accepts_modifications = true;
48 _accepts_miscellaneous = false;
49 _category = Command::Category::operation;
50 }
51
52 ////////////////////////////////////////////////////////////////////////////////
execute(std::string &)53 int CmdPrepend::execute (std::string&)
54 {
55 int rc = 0;
56 int count = 0;
57
58 // Apply filter.
59 Filter filter;
60 std::vector <Task> filtered;
61 filter.subset (filtered);
62 if (filtered.size () == 0)
63 {
64 Context::getContext ().footnote ("No tasks specified.");
65 return 1;
66 }
67
68 // TODO Complain when no modifications are specified.
69
70 // Accumulated project change notifications.
71 std::map <std::string, std::string> projectChanges;
72
73 if(filtered.size() > 1) {
74 feedback_affected("This command will alter {1} tasks.", filtered.size());
75 }
76 for (auto& task : filtered)
77 {
78 Task before (task);
79
80 // Prepend to the specified task.
81 std::string question = format ("Prepend to task {1} '{2}'?",
82 task.identifier (true),
83 task.get ("description"));
84
85 task.modify (Task::modPrepend, true);
86
87 if (permission (before.diff (task) + question, filtered.size ()))
88 {
89 Context::getContext ().tdb2.modify (task);
90 ++count;
91 feedback_affected ("Prepending to task {1} '{2}'.", task);
92 if (Context::getContext ().verbose ("project"))
93 projectChanges[task.get ("project")] = onProjectChange (task, false);
94
95 // Prepend to siblings.
96 if (task.has ("parent"))
97 {
98 if ((Context::getContext ().config.get ("recurrence.confirmation") == "prompt"
99 && confirm ("This is a recurring task. Do you want to prepend to all pending recurrences of this same task?")) ||
100 Context::getContext ().config.getBoolean ("recurrence.confirmation"))
101 {
102 std::vector <Task> siblings = Context::getContext ().tdb2.siblings (task);
103 for (auto& sibling : siblings)
104 {
105 sibling.modify (Task::modPrepend, true);
106 Context::getContext ().tdb2.modify (sibling);
107 ++count;
108 feedback_affected ("Prepending to recurring task {1} '{2}'.", sibling);
109 }
110
111 // Prepend to the parent
112 Task parent;
113 Context::getContext ().tdb2.get (task.get ("parent"), parent);
114 parent.modify (Task::modPrepend, true);
115 Context::getContext ().tdb2.modify (parent);
116 }
117 }
118 }
119 else
120 {
121 std::cout << "Task not prepended.\n";
122 rc = 1;
123 if (_permission_quit)
124 break;
125 }
126 }
127
128 // Now list the project changes.
129 for (auto& change : projectChanges)
130 if (change.first != "")
131 Context::getContext ().footnote (change.second);
132
133 feedback_affected (count == 1 ? "Prepended {1} task." : "Prepended {1} tasks.", count);
134 return rc;
135 }
136
137 ////////////////////////////////////////////////////////////////////////////////
138