//////////////////////////////////////////////////////////////////////////////// // // Copyright 2006 - 2021, Tomas Babej, Paul Beckingham, Federico Hernandez. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. // // https://www.opensource.org/licenses/mit-license.php // //////////////////////////////////////////////////////////////////////////////// #include // cmake.h include header must come first #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_EXECUTE #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //////////////////////////////////////////////////////////////////////////////// void Command::factory(std::map& all) { Command* c; c = new CmdAdd(); all[c->keyword()] = c; c = new CmdAnnotate(); all[c->keyword()] = c; c = new CmdAppend(); all[c->keyword()] = c; c = new CmdBurndownDaily(); all[c->keyword()] = c; c = new CmdBurndownMonthly(); all[c->keyword()] = c; c = new CmdBurndownWeekly(); all[c->keyword()] = c; c = new CmdCalc(); all[c->keyword()] = c; c = new CmdCalendar(); all[c->keyword()] = c; c = new CmdColor(); all[c->keyword()] = c; c = new CmdColumns(); all[c->keyword()] = c; c = new CmdCommands(); all[c->keyword()] = c; c = new CmdCompletionAliases(); all[c->keyword()] = c; c = new CmdCompletionColumns(); all[c->keyword()] = c; c = new CmdCompletionCommands(); all[c->keyword()] = c; c = new CmdCompletionConfig(); all[c->keyword()] = c; c = new CmdCompletionContext(); all[c->keyword()] = c; c = new CmdCompletionIds(); all[c->keyword()] = c; c = new CmdCompletionUDAs(); all[c->keyword()] = c; c = new CmdCompletionUuids(); all[c->keyword()] = c; c = new CmdCompletionProjects(); all[c->keyword()] = c; c = new CmdCompletionTags(); all[c->keyword()] = c; c = new CmdCompletionVersion(); all[c->keyword()] = c; c = new CmdConfig(); all[c->keyword()] = c; c = new CmdContext(); all[c->keyword()] = c; c = new CmdCount(); all[c->keyword()] = c; c = new CmdDelete(); all[c->keyword()] = c; c = new CmdDenotate(); all[c->keyword()] = c; c = new CmdDiagnostics(); all[c->keyword()] = c; c = new CmdDone(); all[c->keyword()] = c; c = new CmdDuplicate(); all[c->keyword()] = c; c = new CmdEdit(); all[c->keyword()] = c; #ifdef HAVE_EXECUTE c = new CmdExec(); all[c->keyword()] = c; #endif c = new CmdExport(); all[c->keyword()] = c; c = new CmdGet(); all[c->keyword()] = c; c = new CmdGHistoryDaily(); all[c->keyword()] = c; c = new CmdGHistoryWeekly(); all[c->keyword()] = c; c = new CmdGHistoryMonthly(); all[c->keyword()] = c; c = new CmdGHistoryAnnual(); all[c->keyword()] = c; c = new CmdHelp(); all[c->keyword()] = c; c = new CmdHistoryDaily(); all[c->keyword()] = c; c = new CmdHistoryWeekly(); all[c->keyword()] = c; c = new CmdHistoryMonthly(); all[c->keyword()] = c; c = new CmdHistoryAnnual(); all[c->keyword()] = c; c = new CmdIDs(); all[c->keyword()] = c; c = new CmdImport(); all[c->keyword()] = c; c = new CmdImportV2(); all[c->keyword()] = c; c = new CmdInfo(); all[c->keyword()] = c; c = new CmdLog(); all[c->keyword()] = c; c = new CmdLogo(); all[c->keyword()] = c; c = new CmdModify(); all[c->keyword()] = c; c = new CmdNews(); all[c->keyword()] = c; c = new CmdPrepend(); all[c->keyword()] = c; c = new CmdProjects(); all[c->keyword()] = c; c = new CmdPurge(); all[c->keyword()] = c; c = new CmdReports(); all[c->keyword()] = c; c = new CmdShow(); all[c->keyword()] = c; c = new CmdShowRaw(); all[c->keyword()] = c; c = new CmdStart(); all[c->keyword()] = c; c = new CmdStats(); all[c->keyword()] = c; c = new CmdStop(); all[c->keyword()] = c; c = new CmdSummary(); all[c->keyword()] = c; c = new CmdSync(); all[c->keyword()] = c; c = new CmdTags(); all[c->keyword()] = c; c = new CmdTimesheet(); all[c->keyword()] = c; c = new CmdUDAs(); all[c->keyword()] = c; c = new CmdUndo(); all[c->keyword()] = c; c = new CmdUnique(); all[c->keyword()] = c; c = new CmdUrgency(); all[c->keyword()] = c; c = new CmdUUIDs(); all[c->keyword()] = c; c = new CmdVersion(); all[c->keyword()] = c; c = new CmdZshAttributes(); all[c->keyword()] = c; c = new CmdZshCommands(); all[c->keyword()] = c; c = new CmdZshCompletionIds(); all[c->keyword()] = c; c = new CmdZshCompletionUuids(); all[c->keyword()] = c; // Instantiate a command object for each custom report. std::vector reports; for (auto& i : Context::getContext().config) { if (i.first.substr(0, 7) == "report.") { std::string report = i.first.substr(7); auto columns = report.find(".columns"); if (columns != std::string::npos) reports.push_back(report.substr(0, columns)); } } for (auto& report : reports) { // Make sure a custom report does not clash with a built-in command. if (all.find(report) != all.end()) throw format("Custom report '{1}' conflicts with built-in task command.", report); c = new CmdCustom(report, "task " + report, Context::getContext().config.get("report." + report + ".description")); all[c->keyword()] = c; } } //////////////////////////////////////////////////////////////////////////////// const std::map Command::categoryNames = { // These strings are intentionally not l10n'd: they are used as identifiers. {Command::Category::unassigned, "unassigned"} // should never happen , {Command::Category::metadata, "metadata"}, {Command::Category::report, "report"}, {Command::Category::operation, "operation"}, {Command::Category::context, "context"}, {Command::Category::graphs, "graphs"}, {Command::Category::config, "config"}, {Command::Category::migration, "migration"}, {Command::Category::misc, "misc"}, {Command::Category::internal, "internal"}, {Command::Category::UNDOCUMENTED, "undocumented"}}; //////////////////////////////////////////////////////////////////////////////// Command::Command() : _keyword(""), _usage(""), _description(""), _read_only(true), _displays_id(true), _needs_confirm(false), _needs_gc(true), _uses_context(false), _accepts_filter(false), _accepts_modifications(false), _accepts_miscellaneous(false), _category(Category::unassigned), _permission_quit(false), _permission_all(false), _first_iteration(true) {} //////////////////////////////////////////////////////////////////////////////// std::string Command::keyword() const { return _keyword; } //////////////////////////////////////////////////////////////////////////////// std::string Command::usage() const { return _usage; } //////////////////////////////////////////////////////////////////////////////// std::string Command::description() const { return _description; } //////////////////////////////////////////////////////////////////////////////// bool Command::read_only() const { return _read_only; } //////////////////////////////////////////////////////////////////////////////// bool Command::displays_id() const { return _displays_id; } //////////////////////////////////////////////////////////////////////////////// bool Command::needs_gc() const { return _needs_gc; } //////////////////////////////////////////////////////////////////////////////// bool Command::uses_context() const { return _uses_context; } //////////////////////////////////////////////////////////////////////////////// bool Command::accepts_filter() const { return _accepts_filter; } //////////////////////////////////////////////////////////////////////////////// bool Command::accepts_modifications() const { return _accepts_modifications; } //////////////////////////////////////////////////////////////////////////////// bool Command::accepts_miscellaneous() const { return _accepts_miscellaneous; } //////////////////////////////////////////////////////////////////////////////// Command::Category Command::category() const { return _category; } //////////////////////////////////////////////////////////////////////////////// // Returns true or false indicating whether to proceed with a write command, on // a per-task basis, after (potentially) asking for permission. // // Factors: // filtered.size () // rc.bulk // rc.confirmation // this->_read_only bool Command::permission(const std::string& question, unsigned int quantity) { // Read-only commands do not need to seek permission. Write commands are // granted permission automatically if the 'all' selection was made in an // earlier call. Or if the 'all' option has already been made. if (_read_only || _permission_all) return true; // If the 'quit' selection has already been made. if (_permission_quit) return false; // What remains are write commands that have not yet selected 'all' or 'quit'. // Describe the task. bool confirmation = Context::getContext().config.getBoolean("confirmation"); unsigned int bulk = Context::getContext().config.getInteger("bulk"); // Quantity 1 modifications have optional confirmation, and only (y/n). if (quantity == 1) { if (!_needs_confirm || !confirmation) return true; bool answer = confirm(question); return answer; } // 1 < Quantity < bulk modifications have optional confirmation, in the (y/n/a/q) // style. Bulk = 0 denotes infinite bulk. if ((bulk == 0 || quantity < bulk) && (!_needs_confirm || !confirmation)) return true; if (Context::getContext().verbose("blank") && !_first_iteration) std::cout << '\n'; int answer = confirm4(question); _first_iteration = false; switch (answer) { case 1: return true; // yes case 2: _permission_all = true; return true; // all case 3: _permission_quit = true; return false; // quit } return false; // This line keeps the compiler happy. } ////////////////////////////////////////////////////////////////////////////////