- Implemented CmdHelp object that replaces the report.cpp longUsage
  function, and builds the output dynamically from other Command
  objects.  This is also why the help text right now is very short,
  as only a few commands are migrated.
- Obsoleted longUsage function.
- Updated task.1 man page with 'execute' command details.
- Modified command.lua sample to include command usage.
- Removed "help" from old Context::dispatch, which means "help" is
  the first migrated command.
- Added usage and description to all Cmd* objects.
- Implemented Command::usage and Command::description as base class
  methods that simply return data that is specified by the derived
  classes.
This commit is contained in:
Paul Beckingham 2011-05-15 01:14:13 -04:00
parent afc97d566c
commit bc756637da
15 changed files with 477 additions and 91 deletions

View file

@ -32,7 +32,7 @@
'blanklines'.
+ The 'verbose' configuration variable now accepts a specific list of items to
be verbose about. See taskrc(5).
+ New 'exec' command that runs external programs.
+ New 'execute' command that runs external programs.
# Tracked Features, sorted by ID.
+ Added feature #330, which supports the 'inverse' color attribute.

2
NEWS
View file

@ -16,7 +16,7 @@ New Features in taskwarrior 2.0.0
- Performance enhancements.
- New 'next' report, that gauges urgency and reports the most urgent tasks.
- Fine control of verbosity through the 'verbose=' configuration variable.
- New 'exec' command that runs external scripts/programs.
- New 'execute' command that runs external scripts/programs.
Please refer to the ChangeLog file for full details. There are too many to
list here.

View file

@ -209,6 +209,12 @@ to achieve this:
This example first gets the IDs for the project:Home filter, then sets
the priority to H for each of those tasks.
.TP
.B execute <external command>
Executes the specified command. Not useful by itself, but when used in
conjunction with aliases and extensions can provide seamless extension
integration.
.TP
.B version
Shows the taskwarrior version number
@ -217,7 +223,7 @@ Shows the taskwarrior version number
.B help
Shows the long usage text.
.TP
.TP
.B show [all | substring]"
Shows all the current settings in the taskwarrior configuration file. If a
substring is specified just the settings containing that substring will be

View file

@ -15,6 +15,12 @@ function install ()
'© 2011, Göteborg Bit Factory' -- Copyright
end
-- Arguments: None
-- Returns: Usage syntax, such as "task random"
function usage ()
return 'task random'
end
-- Arguments: None
-- Returns: Valid Taskwarrior BNF, minimally defining a production rule that
-- has the same name as the command itself

View file

@ -119,7 +119,8 @@ void Context::initialize2 (int argc, char** argv)
// TODO Load relevant rc file.
// Instantiate built-in command objects.
commands["exec"] = Command::factory ("exec");
commands["execute"] = Command::factory ("execute");
commands["help"] = Command::factory ("help");
commands["install"] = Command::factory ("install");
commands["logo"] = Command::factory ("_logo");
@ -280,7 +281,6 @@ int Context::dispatch (std::string &out)
else if (cmd.command == "version") { rc = handleVersion (out); }
else if (cmd.command == "config") { rc = handleConfig (out); }
else if (cmd.command == "show") { rc = handleShow (out); }
else if (cmd.command == "help") { rc = longUsage (out); }
else if (cmd.command == "stats") { rc = handleReportStats (out); }
else if (cmd.command == "info") { rc = handleInfo (out); }
else if (cmd.command == "history.monthly") { rc = handleReportHistoryMonthly (out); }

View file

@ -6,6 +6,7 @@ include_directories (${CMAKE_SOURCE_DIR}/src
set (commands_SRCS Command.cpp Command.h
CmdExec.cpp CmdExec.h
CmdHelp.cpp CmdHelp.h
CmdInstall.cpp CmdInstall.h
CmdLogo.cpp CmdLogo.h)

View file

@ -35,6 +35,8 @@ extern Context context;
CmdExec::CmdExec ()
: _external_command ("")
{
_usage = "task execute <external command>";
_description = "Executes external commands and scripts";
_read_only = false;
_displays_id = true;
}
@ -42,8 +44,12 @@ CmdExec::CmdExec ()
////////////////////////////////////////////////////////////////////////////////
bool CmdExec::implements (const std::string& command_line)
{
_external_command = "";
if (context.args.size () > 1 &&
(context.args[0] == "exec" ||
(context.args[0] == "execute" ||
context.args[0] == "execut" ||
context.args[0] == "execu" ||
context.args[0] == "exec" ||
context.args[0] == "exe" ||
context.args[0] == "ex"))
{

374
src/commands/CmdHelp.cpp Normal file
View file

@ -0,0 +1,374 @@
////////////////////////////////////////////////////////////////////////////////
// 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 <CmdHelp.h>
#include <ViewText.h>
#include <Context.h>
#include <util.h>
extern Context context;
////////////////////////////////////////////////////////////////////////////////
CmdHelp::CmdHelp ()
{
_usage = "task help";
_description = "Displays this usage help text";
_read_only = true;
_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)
{
ViewText view;
view.width (context.getWidth ());
view.add (Column::factory ("string.left", ""));
view.add (Column::factory ("string.left", ""));
view.add (Column::factory ("string.left", ""));
// Static first row.
int row = view.addRow ();
view.set (row, 0, "Usage:");
view.set (row, 1, "task");
// Obsolete method of getting a list of all commands.
std::vector <std::string> all;
std::map <std::string, Command*>::iterator i;
for (i = context.commands.begin (); i != context.commands.end (); ++i)
all.push_back (i->first);
// Sort alphabetically.
std::sort (all.begin (), all.end ());
foreach (name, all)
{
row = view.addRow ();
view.set (row, 1, context.commands[*name]->usage ());
view.set (row, 2, context.commands[*name]->description ());
}
/*
row = view.addRow ();
view.set (row, 1, "task add [tags] [attrs] desc...");
view.set (row, 2, "Adds a new task.");
row = view.addRow ();
view.set (row, 1, "task log [tags] [attrs] desc...");
view.set (row, 2, "Adds a new task that is already completed.");
row = view.addRow ();
view.set (row, 1, "task append ID [tags] [attrs] desc...");
view.set (row, 2, "Appends more description to an existing task.");
row = view.addRow ();
view.set (row, 1, "task prepend ID [tags] [attrs] desc...");
view.set (row, 2, "Prepends more description to an existing task.");
row = view.addRow ();
view.set (row, 1, "task annotate ID desc...");
view.set (row, 2, "Adds an annotation to an existing task.");
row = view.addRow ();
view.set (row, 1, "task denotate ID desc...");
view.set (row, 2, "Deletes an annotation of an existing task.");
row = view.addRow ();
view.set (row, 1, "task ID [tags] [attrs] [desc...]");
view.set (row, 2, "Modifies the existing task with provided arguments.");
row = view.addRow ();
view.set (row, 1, "task ID /from/to/g");
view.set (row, 2, "Performs substitution on the task description and "
"annotations. The 'g' is optional, and causes "
"substitutions for all matching text, not just the "
"first occurrence.");
row = view.addRow ();
view.set (row, 1, "task ID");
view.set (row, 2, "Specifying an ID without a command invokes the 'info' command.");
row = view.addRow ();
view.set (row, 1, "task edit ID");
view.set (row, 2, "Launches an editor to let you modify all aspects of a task directly, therefore it is to be used carefully.");
row = view.addRow ();
view.set (row, 1, "task undo");
view.set (row, 2, "Reverts the most recent action.");
row = view.addRow ();
view.set (row, 1, "task shell");
view.set (row, 2, "Launches an interactive shell.");
row = view.addRow ();
view.set (row, 1, "task duplicate ID [tags] [attrs] [desc...]");
view.set (row, 2, "Duplicates the specified task, and allows modifications.");
row = view.addRow ();
view.set (row, 1, "task delete ID");
view.set (row, 2, "Deletes the specified task.");
row = view.addRow ();
view.set (row, 1, "task info ID");
view.set (row, 2, "Shows all data, metadata for specified task.");
row = view.addRow ();
view.set (row, 1, "task start ID");
view.set (row, 2, "Marks specified task as started.");
row = view.addRow ();
view.set (row, 1, "task stop ID");
view.set (row, 2, "Removes the 'start' time from a task.");
row = view.addRow ();
view.set (row, 1, "task done ID [tags] [attrs] [desc...]");
view.set (row, 2, "Marks the specified task as completed.");
row = view.addRow ();
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.");
row = view.addRow ();
view.set (row, 1, "task timesheet [weeks]");
view.set (row, 2, "Shows a weekly report of tasks completed and started.");
row = view.addRow ();
view.set (row, 1, "task history");
view.set (row, 2, "Shows a report of task history, by month. Alias to history.monthly.");
row = view.addRow ();
view.set (row, 1, "task history.annual");
view.set (row, 2, "Shows a report of task history, by year.");
row = view.addRow ();
view.set (row, 1, "task ghistory");
view.set (row, 2, "Shows a graphical report of task history, by month. Alias to ghistory.monthly.");
row = view.addRow ();
view.set (row, 1, "task ghistory.annual");
view.set (row, 2, "Shows a graphical report of task history, by year.");
row = view.addRow ();
view.set (row, 1, "task burndown.daily");
view.set (row, 2, "Shows a graphical burndown chart, by day.");
row = view.addRow ();
view.set (row, 1, "task burndown.weekly");
view.set (row, 2, "Shows a graphical burndown chart, by week.");
row = view.addRow ();
view.set (row, 1, "task burndown.monthly");
view.set (row, 2, "Shows a graphical burndown chart, by month.");
row = view.addRow ();
view.set (row, 1, "task calendar [due|month year|year]");
view.set (row, 2, "Shows a calendar, with due tasks marked.");
row = view.addRow ();
view.set (row, 1, "task stats");
view.set (row, 2, "Shows task database statistics.");
row = view.addRow ();
view.set (row, 1, "task import");
view.set (row, 2, "Imports tasks from a variety of formats.");
row = view.addRow ();
view.set (row, 1, "task export");
view.set (row, 2, "Lists all tasks in CSV format. Alias to export.csv");
row = view.addRow ();
view.set (row, 1, "task export.csv");
view.set (row, 2, "Lists all tasks in CSV format.");
row = view.addRow ();
view.set (row, 1, "task export.ical");
view.set (row, 2, "Lists all tasks in iCalendar format.");
row = view.addRow ();
view.set (row, 1, "task export.yaml");
view.set (row, 2, "Lists all tasks in YAML format.");
row = view.addRow ();
view.set (row, 1, "task merge URL");
view.set (row, 2, "Merges the specified undo.data file with the local data files.");
row = view.addRow ();
view.set (row, 1, "task push URL");
view.set (row, 2, "Pushes the local *.data files to the URL.");
row = view.addRow ();
view.set (row, 1, "task pull URL");
view.set (row, 2, "Overwrites the local *.data files with those found at the URL.");
row = view.addRow ();
view.set (row, 1, "task color [sample | legend]");
view.set (row, 2, "Displays all possible colors, a named sample, or a "
"legend containing all currently defined colors.");
row = view.addRow ();
view.set (row, 1, "task count [filter]");
view.set (row, 2, "Shows only the number of matching tasks.");
row = view.addRow ();
view.set (row, 1, "task ids [filter]");
view.set (row, 2, "Shows only the IDs of matching tasks, in the form of a range.");
row = view.addRow ();
view.set (row, 1, "task version");
view.set (row, 2, "Shows the task version number.");
row = view.addRow ();
view.set (row, 1, "task show [all | substring]");
view.set (row, 2, "Shows the entire task configuration variables or the ones containing substring.");
row = view.addRow ();
view.set (row, 1, "task config [name [value | '']]");
view.set (row, 2, "Add, modify and remove settings in the task configuration.");
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 <std::string> 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"
+ view.render ()
+ "\n"
+ "Documentation for taskwarrior can be found using 'man task', "
"'man taskrc', 'man task-tutorial', 'man task-color', 'man task-faq' "
"or at http://taskwarrior.org"
+ "\n"
+ "\n"
+ "ID is the numeric identifier displayed by the 'task list' command. "
"You can specify multiple IDs for task commands, and multiple tasks "
"will be affected. To specify multiple IDs make sure you use one "
"of these forms:\n"
" task delete 1,2,3\n"
" task info 1-3\n"
" task pri:H 1,2-5,19\n"
"\n"
"Tags are arbitrary words, any quantity:\n"
" +tag The + means add the tag\n"
" -tag The - means remove the tag\n"
"\n"
"Attributes are:\n"
" project: Project name\n"
" priority: Priority\n"
" due: Due date\n"
" recur: Recurrence frequency\n"
" until: Recurrence end date\n"
" fg: Foreground color\n"
" bg: Background color\n"
" limit: Desired number of rows in report, or 'page'\n"
" wait: Date until task becomes pending\n"
"\n"
"Attribute modifiers improve filters. Supported modifiers are:\n"
" before (synonyms under, below)\n"
" after (synonyms over, above)\n"
" none\n"
" any\n"
" is (synonym equals)\n"
" isnt (synonym not)\n"
" has (synonym contains)\n"
" hasnt\n"
" startswith (synonym left)\n"
" endswith (synonym right)\n"
" word\n"
" noword\n"
"\n"
" For example:\n"
" task list due.before:eom priority.not:L\n"
"\n"
" Modifiers can be inverted with the ~ character:\n"
" project.~is is equivalent to project.isnt\n"
"\n"
"The default .taskrc file can be overridden with:\n"
" task rc:<alternate file> ...\n"
"\n"
"The values in .taskrc (or alternate) can be overridden with:\n"
" task ... rc.<name>:<value>\n"
"\n"
"Any command or attribute name may be abbreviated if still unique:\n"
" task list project:Home\n"
" task li pro:Home\n"
"\n"
"Some task descriptions need to be escaped because of the shell:\n"
" task add \"quoted ' quote\"\n"
" task add escaped \\' quote\n"
"\n"
"The argument -- tells taskwarrior to treat all other args as description.\n"
" task add -- project:Home needs scheduling\n"
"\n"
"Many characters have special meaning to the shell, including:\n"
" $ ! ' \" ( ) ; \\ ` * ? { } [ ] < > | & % # ~\n"
"\n";
return 0;
}
////////////////////////////////////////////////////////////////////////////////

43
src/commands/CmdHelp.h Normal file
View file

@ -0,0 +1,43 @@
////////////////////////////////////////////////////////////////////////////////
// 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_CMDHELP
#define INCLUDED_CMDHELP
#include <string>
#include <Command.h>
class CmdHelp : public Command
{
public:
CmdHelp ();
bool implements (const std::string&);
int execute (const std::string&, std::string&);
};
#endif
////////////////////////////////////////////////////////////////////////////////

View file

@ -34,6 +34,8 @@ extern Context context;
////////////////////////////////////////////////////////////////////////////////
CmdInstall::CmdInstall ()
{
_usage = "task install <extension> [<extension> ...]";
_description = "Installs extensions and external scripts";
_read_only = true;
_displays_id = false;
}

View file

@ -25,7 +25,6 @@
//
////////////////////////////////////////////////////////////////////////////////
#include <iostream> // TODO Remove.
#include <CmdLogo.h>
#include <Context.h>
#include <text.h>
@ -35,6 +34,8 @@ extern Context context;
////////////////////////////////////////////////////////////////////////////////
CmdLogo::CmdLogo ()
{
_usage = "task logo";
_description = "Displays the Taskwarrior logo";
_read_only = true;
_displays_id = false;
}

View file

@ -28,6 +28,7 @@
#include <iostream>
#include <Command.h>
#include <CmdExec.h>
#include <CmdHelp.h>
#include <CmdInstall.h>
#include <CmdLogo.h>
#include <Context.h>
@ -38,7 +39,8 @@ extern Context context;
Command* Command::factory (const std::string& name)
{
Command* command;
if (name == "exec") command = new CmdExec ();
if (name == "execute") command = new CmdExec ();
else if (name == "help") command = new CmdHelp ();
else if (name == "install") command = new CmdInstall ();
else if (name == "_logo") command = new CmdLogo ();
else
@ -51,7 +53,9 @@ Command* Command::factory (const std::string& name)
////////////////////////////////////////////////////////////////////////////////
Command::Command ()
: _read_only (true)
: _usage ("")
, _description ("")
, _read_only (true)
, _displays_id (true)
{
}
@ -59,6 +63,8 @@ Command::Command ()
////////////////////////////////////////////////////////////////////////////////
Command::Command (const Command& other)
{
_usage = other._usage;
_description = other._description;
_read_only = other._read_only;
_displays_id = other._displays_id;
}
@ -68,6 +74,8 @@ Command& Command::operator= (const Command& other)
{
if (this != &other)
{
_usage = other._usage;
_description = other._description;
_read_only = other._read_only;
_displays_id = other._displays_id;
}
@ -78,7 +86,9 @@ Command& Command::operator= (const Command& other)
////////////////////////////////////////////////////////////////////////////////
bool Command::operator== (const Command& other) const
{
return _read_only == other._read_only &&
return _usage == other._usage &&
_description == other._description &&
_read_only == other._read_only &&
_displays_id == other._displays_id;
}
@ -87,6 +97,18 @@ Command::~Command ()
{
}
////////////////////////////////////////////////////////////////////////////////
std::string Command::usage () const
{
return _usage;
}
////////////////////////////////////////////////////////////////////////////////
std::string Command::description () const
{
return _description;
}
////////////////////////////////////////////////////////////////////////////////
bool Command::read_only () const
{

View file

@ -40,14 +40,18 @@ public:
static Command* factory (const std::string&);
std::string usage () const;
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:
bool _read_only;
bool _displays_id;
std::string _usage;
std::string _description;
bool _read_only;
bool _displays_id;
};
#endif

View file

@ -99,7 +99,6 @@ int handleEdit (std::string&);
// report.cpp
int shortUsage (std::string&);
int longUsage (std::string&);
int handleInfo (std::string&);
int handleReportSummary (std::string&);
int handleReportCalendar (std::string&);

View file

@ -285,84 +285,6 @@ int shortUsage (std::string& outs)
return 0;
}
////////////////////////////////////////////////////////////////////////////////
int longUsage (std::string& outs)
{
int rc = 0;
std::string shortUsageString;
std::stringstream out;
(void)shortUsage(shortUsageString);
out << shortUsageString
<< "ID is the numeric identifier displayed by the 'task list' command. "
<< "You can specify multiple IDs for task commands, and multiple tasks "
<< "will be affected. To specify multiple IDs make sure you use one "
<< "of these forms:" << "\n"
<< " task delete 1,2,3" << "\n"
<< " task info 1-3" << "\n"
<< " task pri:H 1,2-5,19" << "\n"
<< "\n"
<< "Tags are arbitrary words, any quantity:" << "\n"
<< " +tag The + means add the tag" << "\n"
<< " -tag The - means remove the tag" << "\n"
<< "\n"
<< "Attributes are:" << "\n"
<< " project: Project name" << "\n"
<< " priority: Priority" << "\n"
<< " due: Due date" << "\n"
<< " recur: Recurrence frequency" << "\n"
<< " until: Recurrence end date" << "\n"
<< " fg: Foreground color" << "\n"
<< " bg: Background color" << "\n"
<< " limit: Desired number of rows in report, or 'page'" << "\n"
<< " wait: Date until task becomes pending" << "\n"
<< "\n"
<< "Attribute modifiers improve filters. Supported modifiers are:" << "\n"
<< " before (synonyms under, below)" << "\n"
<< " after (synonyms over, above)" << "\n"
<< " none" << "\n"
<< " any" << "\n"
<< " is (synonym equals)" << "\n"
<< " isnt (synonym not)" << "\n"
<< " has (synonym contains)" << "\n"
<< " hasnt" << "\n"
<< " startswith (synonym left)" << "\n"
<< " endswith (synonym right)" << "\n"
<< " word" << "\n"
<< " noword" << "\n"
<< "\n"
<< " For example:" << "\n"
<< " task list due.before:eom priority.not:L" << "\n"
<< "\n"
<< " Modifiers can be inverted with the ~ character:" << "\n"
<< " project.~is is equivalent to project.isnt" << "\n"
<< "\n"
<< "The default .taskrc file can be overridden with:" << "\n"
<< " task rc:<alternate file> ..." << "\n"
<< "\n"
<< "The values in .taskrc (or alternate) can be overridden with:" << "\n"
<< " task ... rc.<name>:<value>" << "\n"
<< "\n"
<< "Any command or attribute name may be abbreviated if still unique:" << "\n"
<< " task list project:Home" << "\n"
<< " task li pro:Home" << "\n"
<< "\n"
<< "Some task descriptions need to be escaped because of the shell:" << "\n"
<< " task add \"quoted ' quote\"" << "\n"
<< " task add escaped \\' quote" << "\n"
<< "\n"
<< "The argument -- tells taskwarrior to treat all other args as description." << "\n"
<< " task add -- project:Home needs scheduling" << "\n"
<< "\n"
<< "Many characters have special meaning to the shell, including:" << "\n"
<< " $ ! ' \" ( ) ; \\ ` * ? { } [ ] < > | & % # ~" << "\n"
<< "\n";
outs = out.str();
return rc;
}
////////////////////////////////////////////////////////////////////////////////
// Display all information for the given task.
int handleInfo (std::string& outs)