From bedc28f51771c302d31f6cec198bc80b6e1c6901 Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Tue, 24 May 2011 19:25:33 -0400 Subject: [PATCH] Commands - Eliminated the Command::implements method. - Implemented CmdCustom to handle all custom reports. - Implemented CmdTags. --- src/Cmd.cpp | 6 +- src/commands/CMakeLists.txt | 2 + src/commands/CmdCustom.cpp | 318 ++++++++++++++++++++++++++++++++++++ src/commands/CmdCustom.h | 46 ++++++ src/commands/CmdExec.cpp | 35 +--- src/commands/CmdExec.h | 5 - src/commands/CmdHelp.cpp | 41 +---- src/commands/CmdHelp.h | 2 - src/commands/CmdInstall.cpp | 6 - src/commands/CmdInstall.h | 4 - src/commands/CmdLogo.cpp | 12 +- src/commands/CmdLogo.h | 4 - src/commands/CmdTags.cpp | 123 ++++++++++++++ src/commands/CmdTags.h | 41 +++++ src/commands/CmdTip.cpp | 15 -- src/commands/CmdTip.h | 5 - src/commands/Command.cpp | 38 +++++ src/commands/Command.h | 1 - 18 files changed, 575 insertions(+), 129 deletions(-) create mode 100644 src/commands/CmdCustom.cpp create mode 100644 src/commands/CmdCustom.h create mode 100644 src/commands/CmdTags.cpp create mode 100644 src/commands/CmdTags.h diff --git a/src/Cmd.cpp b/src/Cmd.cpp index e9762fd7d..c1b1aaef1 100644 --- a/src/Cmd.cpp +++ b/src/Cmd.cpp @@ -85,10 +85,12 @@ bool Cmd::validCustom (const std::string& input) autoComplete (lowerCase (input), commands, matches); if (matches.size () == 1) { +/* std::string canonical = context.canonicalize (matches[0]); matches.clear (); autoComplete (canonical, customReports, matches); if (matches.size () == 1) +*/ return true; } @@ -106,7 +108,7 @@ void Cmd::parse (const std::string& input) std::vector matches; autoComplete (input, commands, matches); if (1 == matches.size ()) - command = context.canonicalize (matches[0]); + /*command = context.canonicalize (matches[0])*/; else if (0 == matches.size ()) command = ""; @@ -173,7 +175,6 @@ void Cmd::load () commands.push_back ("stats"); commands.push_back ("stop"); commands.push_back ("summary"); - commands.push_back ("tags"); commands.push_back ("timesheet"); commands.push_back ("undo"); commands.push_back ("version"); @@ -270,7 +271,6 @@ bool Cmd::isReadOnlyCommand () command == "shell" || command == "stats" || command == "summary" || - command == "tags" || command == "timesheet" || command == "version" || validCustom (command)) diff --git a/src/commands/CMakeLists.txt b/src/commands/CMakeLists.txt index 5d134c030..8cd06d4ee 100644 --- a/src/commands/CMakeLists.txt +++ b/src/commands/CMakeLists.txt @@ -5,10 +5,12 @@ include_directories (${CMAKE_SOURCE_DIR}/src ${TASK_INCLUDE_DIRS}) set (commands_SRCS Command.cpp Command.h + CmdCustom.cpp CmdCustom.h CmdExec.cpp CmdExec.h CmdHelp.cpp CmdHelp.h CmdInstall.cpp CmdInstall.h CmdLogo.cpp CmdLogo.h + CmdTags.cpp CmdTags.h CmdTip.cpp CmdTip.h) add_library (commands STATIC ${commands_SRCS}) diff --git a/src/commands/CmdCustom.cpp b/src/commands/CmdCustom.cpp new file mode 100644 index 000000000..be0cbb40a --- /dev/null +++ b/src/commands/CmdCustom.cpp @@ -0,0 +1,318 @@ +//////////////////////////////////////////////////////////////////////////////// +// taskwarrior - a command line task list manager. +// +// Copyright 2006 - 2011, Paul Beckingham, Federico Hernandez. +// All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free Software +// Foundation; either version 2 of the License, or (at your option) any later +// version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +// details. +// +// You should have received a copy of the GNU General Public License along with +// this program; if not, write to the +// +// Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, +// Boston, MA +// 02110-1301 +// USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern Context context; + +//////////////////////////////////////////////////////////////////////////////// +CmdCustom::CmdCustom ( + const std::string& k, + const std::string& u, + const std::string& d) +{ + _keyword = k; + _usage = u; + _description = d; + _read_only = true; + _displays_id = true; +} + +//////////////////////////////////////////////////////////////////////////////// +int CmdCustom::execute (const std::string& command_line, std::string& output) +{ + int rc = 0; + + // Load report configuration. + std::string reportColumns = context.config.get ("report." + _keyword + ".columns"); + std::string reportLabels = context.config.get ("report." + _keyword + ".labels"); + std::string reportSort = context.config.get ("report." + _keyword + ".sort"); + std::string reportFilter = context.config.get ("report." + _keyword + ".filter"); + + std::vector columns; + split (columns, reportColumns, ','); + validateReportColumns (columns); + + std::vector labels; + split (labels, reportLabels, ','); + + if (columns.size () != labels.size () && labels.size () != 0) + throw std::string ("There are different numbers of columns and labels ") + + "for report '" + _keyword + "'."; + + std::map columnLabels; + if (labels.size ()) + for (unsigned int i = 0; i < columns.size (); ++i) + columnLabels[columns[i]] = labels[i]; + + std::vector sortOrder; + split (sortOrder, reportSort, ','); + validateSortColumns (sortOrder); + + // Apply rc overrides. + std::vector filterArgs; + std::vector filteredArgs; + split (filterArgs, reportFilter, ' '); +// context.applyOverrides (filterArgs, filteredArgs); + + { + Cmd cmd (_keyword); + Task task; + Sequence sequence; + Subst subst; + Filter filter; + context.parse (filteredArgs, cmd, task, sequence, subst, filter); + + context.sequence.combine (sequence); + + // Special case: Allow limit to be overridden by the command line. + if (!context.task.has ("limit") && task.has ("limit")) + context.task.set ("limit", task.get ("limit")); + + Filter::iterator att; + for (att = filter.begin (); att != filter.end (); ++att) + context.filter.push_back (*att); + } + + // Get all the tasks. + std::vector tasks; + context.tdb.lock (context.config.getBoolean ("locking")); + handleRecurrence (); + context.tdb.load (tasks, context.filter); + context.tdb.commit (); + context.tdb.unlock (); + + // Filter sequence. + if (context.sequence.size ()) + context.filter.applySequence (tasks, context.sequence); + + // Sort the tasks. + std::vector sequence; + for (int i = 0; i < tasks.size (); ++i) + sequence.push_back (i); + + sort_tasks (tasks, sequence, reportSort); + + // Configure the view. + ViewTask view; + view.width (context.getWidth ()); + view.leftMargin (context.config.getInteger ("indent.report")); + view.extraPadding (context.config.getInteger ("row.padding")); + view.intraPadding (context.config.getInteger ("column.padding")); + + Color label (context.config.get ("color.label")); + view.colorHeader (label); + + Color alternate (context.config.get ("color.alternate")); + view.colorOdd (alternate); + view.intraColorOdd (alternate); + + // Add the columns and labels. + for (int i = 0; i < columns.size (); ++i) + { + Column* c = Column::factory (columns[i], _keyword); + c->setLabel (labels[i]); + view.add (c); + } + + // How many lines taken up by table header? + int table_header; + if (context.color () && context.config.getBoolean ("fontunderline")) + table_header = 1; // Underlining doesn't use extra line. + else + table_header = 2; // Dashes use an extra line. + + // Report output can be limited by rows or lines. + int maxrows = 0; + int maxlines = 0; + getLimits (_keyword, maxrows, maxlines); + + // Adjust for fluff in the output. + if (maxlines) + maxlines -= (context.verbose ("blank") ? 1 : 0) + + table_header + + context.headers.size () + + context.footnotes.size (); + + // Render. + std::stringstream out; + if (tasks.size ()) + { + view.truncateRows (maxrows); + view.truncateLines (maxlines); + + out << optionalBlankLine () + << view.render (tasks, sequence) + << optionalBlankLine () + << tasks.size () + << (tasks.size () == 1 ? " task" : " tasks"); + + if (maxrows && maxrows < tasks.size ()) + out << ", " << maxrows << " shown"; + + if (maxlines && maxlines < tasks.size ()) + out << ", truncated to " << maxlines - table_header << " lines"; + + out << "\n"; + } + else + { + out << "No matches." + << std::endl; + rc = 1; + } + + output = out.str (); + return rc; +} + +//////////////////////////////////////////////////////////////////////////////// +void CmdCustom::validateReportColumns (std::vector & columns) +{ + // One-time initialization, on demand. + static std::map legacyMap; + if (! legacyMap.size ()) + { + legacyMap["priority_long"] = "priority.long"; + legacyMap["entry_time"] = "entry"; + legacyMap["start_time"] = "start"; + legacyMap["end_time"] = "end"; + legacyMap["countdown"] = "due.countdown"; + legacyMap["countdown_compact"] = "due.countdown"; + legacyMap["age"] = "entry.age"; + legacyMap["age_compact"] = "entry.age"; + legacyMap["active"] = "start.active"; + legacyMap["recurrence_indicator"] = "recur.indicator"; + legacyMap["tag_indicator"] = "tags.indicator"; + legacyMap["description_only"] = "description.desc"; + } + + std::vector ::iterator i; + for (i = columns.begin (); i != columns.end (); ++i) + { + // If a legacy column was used, complain about it, but modify it anyway. + std::map ::iterator found = legacyMap.find (*i); + if (found != legacyMap.end ()) + { + context.footnote (std::string ("Deprecated report field '") + + *i + + "' used. Please modify this to '" + + found->second + + "'."); + *i = found->second; + } + } +} + +//////////////////////////////////////////////////////////////////////////////// +void CmdCustom::validateSortColumns (std::vector & columns) +{ + // One-time initialization, on demand. + static std::map legacyMap; + if (! legacyMap.size ()) + { + legacyMap["priority_long"] = "priority"; + legacyMap["entry_time"] = "entry"; + legacyMap["start_time"] = "start"; + legacyMap["end_time"] = "end"; + legacyMap["countdown"] = "due"; + legacyMap["countdown_compact"] = "due"; + legacyMap["age"] = "entry"; + legacyMap["age_compact"] = "entry"; + legacyMap["active"] = "start"; + legacyMap["recurrence_indicator"] = "recur"; + legacyMap["tag_indicator"] = "tags"; + legacyMap["description_only"] = "description"; + } + + std::vector ::iterator i; + for (i = columns.begin (); i != columns.end (); ++i) + { + // If a legacy column was used, complain about it, but modify it anyway. + std::map ::iterator found = legacyMap.find (*i); + if (found != legacyMap.end ()) + { + context.footnote (std::string ("Deprecated sort field '") + + *i + + "' used. Please modify this to '" + + found->second + + "'."); + *i = found->second; + } + } +} + +//////////////////////////////////////////////////////////////////////////////// +// A value of zero mean unlimited. +// A value of 'page' means however many screen lines there are. +// A value of a positive integer is a row/task limit. +void CmdCustom::getLimits (const std::string& report, int& rows, int& lines) +{ + rows = 0; + lines = 0; + + int screenheight = 0; + + // If a report has a stated limit, use it. + if (report != "") + { + std::string name = "report." + report + ".limit"; + if (context.config.get (name) == "page") + lines = screenheight = context.getHeight (); + else + rows = context.config.getInteger (name); + } + + // If the custom report has a defined limit, then allow a numeric override. + // This is an integer specified as a filter (limit:10). + if (context.task.has ("limit")) + { + if (context.task.get ("limit") == "page") + { + if (screenheight == 0) + screenheight = context.getHeight (); + + rows = 0; + lines = screenheight; + } + else + { + rows = atoi (context.task.get ("limit").c_str ()); + lines = 0; + } + } +} + +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/commands/CmdCustom.h b/src/commands/CmdCustom.h new file mode 100644 index 000000000..887bf5dfb --- /dev/null +++ b/src/commands/CmdCustom.h @@ -0,0 +1,46 @@ +//////////////////////////////////////////////////////////////////////////////// +// taskwarrior - a command line task list manager. +// +// Copyright 2006 - 2011, Paul Beckingham, Federico Hernandez. +// All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free Software +// Foundation; either version 2 of the License, or (at your option) any later +// version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +// details. +// +// You should have received a copy of the GNU General Public License along with +// this program; if not, write to the +// +// Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, +// Boston, MA +// 02110-1301 +// USA +// +//////////////////////////////////////////////////////////////////////////////// +#ifndef INCLUDED_CMDCUSTOM +#define INCLUDED_CMDCUSTOM + +#include +#include + +class CmdCustom : public Command +{ +public: + CmdCustom (const std::string&, const std::string&, const std::string&); + int execute (const std::string&, std::string&); + +private: + void validateReportColumns (std::vector &); + void validateSortColumns (std::vector &); + void getLimits (const std::string&, int&, int&); +}; + +#endif +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/commands/CmdExec.cpp b/src/commands/CmdExec.cpp index 12954e6d2..7124de103 100644 --- a/src/commands/CmdExec.cpp +++ b/src/commands/CmdExec.cpp @@ -27,13 +27,9 @@ #include #include -#include - -extern Context context; //////////////////////////////////////////////////////////////////////////////// CmdExec::CmdExec () -: _external_command ("") { _keyword = "execute"; _usage = "task execute "; @@ -43,36 +39,9 @@ CmdExec::CmdExec () } //////////////////////////////////////////////////////////////////////////////// -bool CmdExec::implements (const std::string& command_line) +int CmdExec::execute (const std::string& command_line, std::string& output) { - _external_command = ""; - if (context.args.size () > 1 && - (context.args[0] == "execute" || - context.args[0] == "execut" || - context.args[0] == "execu" || - context.args[0] == "exec" || - context.args[0] == "exe" || - context.args[0] == "ex")) - { - for (int i = 1; i < context.args.size (); ++i) - { - if (i > 1) - _external_command += " "; - - _external_command += context.args[i]; - } - - return true; - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -int CmdExec::execute (const std::string&, std::string&) -{ - system (_external_command.c_str ()); - return 0; + return system (command_line.c_str ()); } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/commands/CmdExec.h b/src/commands/CmdExec.h index 3e19ce298..441aedf80 100644 --- a/src/commands/CmdExec.h +++ b/src/commands/CmdExec.h @@ -34,12 +34,7 @@ class CmdExec : public Command { public: CmdExec (); - - bool implements (const std::string&); int execute (const std::string&, std::string&); - -private: - std::string _external_command; }; #endif diff --git a/src/commands/CmdHelp.cpp b/src/commands/CmdHelp.cpp index 15cfb834a..0c60e19ac 100644 --- a/src/commands/CmdHelp.cpp +++ b/src/commands/CmdHelp.cpp @@ -43,20 +43,6 @@ CmdHelp::CmdHelp () _displays_id = false; } -//////////////////////////////////////////////////////////////////////////////// -bool CmdHelp::implements (const std::string& command_line) -{ - if (context.args.size () && - (context.args[0] == "help" || - context.args[0] == "hel" || - context.args[0] == "he")) - { - return true; - } - - return false; -} - //////////////////////////////////////////////////////////////////////////////// int CmdHelp::execute (const std::string& command_line, std::string& output) { @@ -77,7 +63,7 @@ int CmdHelp::execute (const std::string& command_line, std::string& output) for (i = context.commands.begin (); i != context.commands.end (); ++i) all.push_back (i->first); - // Sort alphabetically. + // Sort alphabetically by usage. std::sort (all.begin (), all.end ()); foreach (name, all) @@ -167,10 +153,6 @@ int CmdHelp::execute (const std::string& command_line, std::string& output) view.set (row, 1, "task projects"); view.set (row, 2, "Shows a list of all project names used, and how many tasks are in each."); - row = view.addRow (); - view.set (row, 1, "task tags"); - view.set (row, 2, "Shows a list of all tags used."); - row = view.addRow (); view.set (row, 1, "task summary"); view.set (row, 2, "Shows a report of task status by project."); @@ -275,27 +257,6 @@ int CmdHelp::execute (const std::string& command_line, std::string& output) row = view.addRow (); view.set (row, 1, "task diagnostics"); view.set (row, 2, "Information needed when reporting a problem."); - - row = view.addRow (); - view.set (row, 1, "task help"); - view.set (row, 2, "Shows the long usage text."); -*/ - -/* - // TODO Add custom reports here... - std::vector all; - context.cmd.allCustomReports (all); - foreach (report, all) - { - std::string command = std::string ("task ") + *report + std::string (" [tags] [attrs] desc..."); - std::string description = context.config.get (std::string ("report.") + *report + ".description"); - if (description == "") - description = "(missing description)"; - - row = view.addRow (); - view.set (row, 1, command); - view.set (row, 2, description); - } */ output = "\n" diff --git a/src/commands/CmdHelp.h b/src/commands/CmdHelp.h index bfbe06610..7f2b3b514 100644 --- a/src/commands/CmdHelp.h +++ b/src/commands/CmdHelp.h @@ -34,8 +34,6 @@ class CmdHelp : public Command { public: CmdHelp (); - - bool implements (const std::string&); int execute (const std::string&, std::string&); }; diff --git a/src/commands/CmdInstall.cpp b/src/commands/CmdInstall.cpp index 57660469a..7f8f2e3b8 100644 --- a/src/commands/CmdInstall.cpp +++ b/src/commands/CmdInstall.cpp @@ -41,12 +41,6 @@ CmdInstall::CmdInstall () _displays_id = false; } -//////////////////////////////////////////////////////////////////////////////// -bool CmdInstall::implements (const std::string& command_line) -{ - return false; -} - //////////////////////////////////////////////////////////////////////////////// // Algorithm: // Copy file rc.data.location/extensions diff --git a/src/commands/CmdInstall.h b/src/commands/CmdInstall.h index c22c206ef..7454e4326 100644 --- a/src/commands/CmdInstall.h +++ b/src/commands/CmdInstall.h @@ -34,11 +34,7 @@ class CmdInstall : public Command { public: CmdInstall (); - - bool implements (const std::string&); int execute (const std::string&, std::string&); - -private: }; #endif diff --git a/src/commands/CmdLogo.cpp b/src/commands/CmdLogo.cpp index 3615f8a90..0cdc18e4a 100644 --- a/src/commands/CmdLogo.cpp +++ b/src/commands/CmdLogo.cpp @@ -41,16 +41,6 @@ CmdLogo::CmdLogo () _displays_id = false; } -//////////////////////////////////////////////////////////////////////////////// -bool CmdLogo::implements (const std::string& command_line) -{ - // TODO Upgrade to a parsed value. - if (command_line.find ("_logo") != std::string::npos) - return true; - - return false; -} - //////////////////////////////////////////////////////////////////////////////// // Algorithm: // Copy file rc.data.location/extensions @@ -93,7 +83,7 @@ int CmdLogo::execute (const std::string& commandLine, std::string& output) }; if (!context.color ()) - throw std::string ("The _logo command requires that color support is enabled."); + throw std::string ("The logo command requires that color support is enabled."); std::string indent (context.config.getInteger ("indent.report"), ' '); output += optionalBlankLine (); diff --git a/src/commands/CmdLogo.h b/src/commands/CmdLogo.h index bd9ca4c25..c5c5c4b02 100644 --- a/src/commands/CmdLogo.h +++ b/src/commands/CmdLogo.h @@ -34,11 +34,7 @@ class CmdLogo : public Command { public: CmdLogo (); - - bool implements (const std::string&); int execute (const std::string&, std::string&); - -private: }; #endif diff --git a/src/commands/CmdTags.cpp b/src/commands/CmdTags.cpp new file mode 100644 index 000000000..a600849e7 --- /dev/null +++ b/src/commands/CmdTags.cpp @@ -0,0 +1,123 @@ +//////////////////////////////////////////////////////////////////////////////// +// taskwarrior - a command line task list manager. +// +// Copyright 2006 - 2011, Paul Beckingham, Federico Hernandez. +// All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free Software +// Foundation; either version 2 of the License, or (at your option) any later +// version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +// details. +// +// You should have received a copy of the GNU General Public License along with +// this program; if not, write to the +// +// Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, +// Boston, MA +// 02110-1301 +// USA +// +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include + +extern Context context; + +//////////////////////////////////////////////////////////////////////////////// +CmdTags::CmdTags () +{ + _keyword = "tags"; + _usage = "task tags"; + _description = "Shows a list of all tags used."; + _read_only = true; + _displays_id = false; +} + +//////////////////////////////////////////////////////////////////////////////// +int CmdTags::execute (const std::string& command_line, std::string& output) +{ + int rc = 0; + std::stringstream out; + + std::vector tasks; + context.tdb.lock (context.config.getBoolean ("locking")); + int quantity = 0; + if (context.config.getBoolean ("list.all.tags")) + quantity += context.tdb.load (tasks, context.filter); + else + quantity += context.tdb.loadPending (tasks, context.filter); + + context.tdb.commit (); + context.tdb.unlock (); + + // Scan all the tasks for their project name, building a map using project + // names as keys. + std::map unique; + std::vector ::iterator t; + for (t = tasks.begin (); t != tasks.end (); ++t) + { + std::vector tags; + t->getTags (tags); + + std::vector ::iterator tag; + for (tag = tags.begin (); tag != tags.end (); ++tag) + if (unique.find (*tag) != unique.end ()) + unique[*tag]++; + else + unique[*tag] = 1; + } + + if (unique.size ()) + { + // Render a list of tags names from the map. + ViewText view; + view.width (context.getWidth ()); + view.add (Column::factory ("string", "Tag")); + view.add (Column::factory ("string.right", "Count")); + + Color bold ("bold"); + bool special = false; + std::map ::iterator i; + for (i = unique.begin (); i != unique.end (); ++i) + { + // Highlight the special tags. + special = (context.color () && + (i->first == "nocolor" || + i->first == "nonag" || + i->first == "next")) ? true : false; + + int row = view.addRow (); + view.set (row, 0, i->first, special ? bold : Color ()); + view.set (row, 1, i->second, special ? bold : Color ()); + } + + out << optionalBlankLine () + << view.render () + << optionalBlankLine () + << unique.size () + << (unique.size () == 1 ? " tag" : " tags") + << " (" << quantity << (quantity == 1 ? " task" : " tasks") << ")\n"; + } + else + { + out << "No tags.\n"; + rc = 1; + } + + output = out.str (); + return rc; +} + +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/commands/CmdTags.h b/src/commands/CmdTags.h new file mode 100644 index 000000000..fdb169d75 --- /dev/null +++ b/src/commands/CmdTags.h @@ -0,0 +1,41 @@ +//////////////////////////////////////////////////////////////////////////////// +// taskwarrior - a command line task list manager. +// +// Copyright 2006 - 2011, Paul Beckingham, Federico Hernandez. +// All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free Software +// Foundation; either version 2 of the License, or (at your option) any later +// version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +// details. +// +// You should have received a copy of the GNU General Public License along with +// this program; if not, write to the +// +// Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, +// Boston, MA +// 02110-1301 +// USA +// +//////////////////////////////////////////////////////////////////////////////// +#ifndef INCLUDED_CMDTAGS +#define INCLUDED_CMDTAGS + +#include +#include + +class CmdTags : public Command +{ +public: + CmdTags (); + int execute (const std::string&, std::string&); +}; + +#endif +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/commands/CmdTip.cpp b/src/commands/CmdTip.cpp index c755ce539..d2f1ef925 100644 --- a/src/commands/CmdTip.cpp +++ b/src/commands/CmdTip.cpp @@ -33,7 +33,6 @@ extern Context context; //////////////////////////////////////////////////////////////////////////////// CmdTip::CmdTip () -: _external_command ("") { _keyword = "tip"; _usage = "task tip"; @@ -42,20 +41,6 @@ CmdTip::CmdTip () _displays_id = false; } -//////////////////////////////////////////////////////////////////////////////// -bool CmdTip::implements (const std::string& command_line) -{ - _external_command = ""; - if (context.args.size () > 1 && - (context.args[0] == "tip" || - context.args[0] == "ti")) - { - return true; - } - - return false; -} - //////////////////////////////////////////////////////////////////////////////// int CmdTip::execute (const std::string&, std::string&) { diff --git a/src/commands/CmdTip.h b/src/commands/CmdTip.h index e6c731d8b..82bab29f6 100644 --- a/src/commands/CmdTip.h +++ b/src/commands/CmdTip.h @@ -34,12 +34,7 @@ class CmdTip : public Command { public: CmdTip (); - - bool implements (const std::string&); int execute (const std::string&, std::string&); - -private: - std::string _external_command; }; #endif diff --git a/src/commands/Command.cpp b/src/commands/Command.cpp index c11aaa40c..ee5be5b18 100644 --- a/src/commands/Command.cpp +++ b/src/commands/Command.cpp @@ -26,11 +26,14 @@ //////////////////////////////////////////////////////////////////////////////// #include +#include #include +#include #include #include #include #include +#include #include #include @@ -45,7 +48,42 @@ void Command::factory (std::map & all) c = new CmdHelp (); all[c->keyword ()] = c; c = new CmdInstall (); all[c->keyword ()] = c; c = new CmdLogo (); all[c->keyword ()] = c; + c = new CmdTags (); all[c->keyword ()] = c; c = new CmdTip (); all[c->keyword ()] = c; + + // Instantiate a command object for each custom report. + std::vector variables; + context.config.all (variables); + + std::vector reports; + std::vector ::iterator i; + for (i = variables.begin (); i != variables.end (); ++i) + { + if (i->substr (0, 7) == "report.") + { + std::string report = i->substr (7); + std::string::size_type columns = report.find (".columns"); + if (columns != std::string::npos) + reports.push_back (report.substr (0, columns)); + } + } + + std::vector ::iterator report; + for (report = reports.begin (); report != reports.end (); ++report) + { + // Make sure a custom report does not clash with a built-in command. + if (all.find (*report) != all.end ()) + throw std::string ("Custom report '") + + *report + + "' conflicts with built-in task command."; + + c = new CmdCustom ( + *report, + "task " + *report + " [tags] [attrs] desc...", + context.config.get ("report." + *report + ".description")); + + all[c->keyword ()] = c; + } } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/commands/Command.h b/src/commands/Command.h index fd38985cd..9065b62f5 100644 --- a/src/commands/Command.h +++ b/src/commands/Command.h @@ -46,7 +46,6 @@ public: std::string description () const; bool read_only () const; bool displays_id () const; - virtual bool implements (const std::string&) = 0; virtual int execute (const std::string&, std::string&) = 0; protected: