mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-07-07 20:06:36 +02:00
Commands - add, log
- Implemented add and log commands using new infrastructure. - Relaxed restriction about creating completed tasks with no dependencies. - Localized CmdAdd.cpp CmdLog.cpp. - Implemented Command::modify_task to apply command line arguments to a specified task. - Implemented Command::apply_defaults to apply various initial values to a specified task, such as entry date.
This commit is contained in:
parent
3c1c900b5b
commit
9603864924
6 changed files with 193 additions and 129 deletions
|
@ -72,7 +72,6 @@ public:
|
|||
static bool is_modifier (const std::string&);
|
||||
static bool is_expression (const std::string&);
|
||||
|
||||
// TODO Decide if these are really useful.
|
||||
static bool extract_attr (const std::string&, std::string&, std::string&);
|
||||
static bool extract_attmod (const std::string&, std::string&, std::string&, std::string&, std::string&);
|
||||
static bool extract_subst (const std::string&, std::string&, std::string&, bool&);
|
||||
|
|
|
@ -25,10 +25,13 @@
|
|||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define L10N // Localization complete.
|
||||
|
||||
#include <sstream>
|
||||
#include <stdlib.h>
|
||||
#include <Context.h>
|
||||
#include <text.h>
|
||||
#include <i18n.h>
|
||||
#include <util.h>
|
||||
#include <main.h>
|
||||
#include <CmdAdd.h>
|
||||
|
@ -40,7 +43,7 @@ CmdAdd::CmdAdd ()
|
|||
{
|
||||
_keyword = "add";
|
||||
_usage = "task add [tags] [attrs] desc...";
|
||||
_description = "Adds a new task.";
|
||||
_description = STRING_CMD_ADD_USAGE;
|
||||
_read_only = false;
|
||||
_displays_id = false;
|
||||
}
|
||||
|
@ -49,100 +52,39 @@ CmdAdd::CmdAdd ()
|
|||
int CmdAdd::execute (std::string& output)
|
||||
{
|
||||
int rc = 0;
|
||||
/*
|
||||
std::stringstream out;
|
||||
|
||||
context.task.set ("uuid", uuid ());
|
||||
context.task.setEntry ();
|
||||
|
||||
// Recurring tasks get a special status.
|
||||
if (context.task.has ("due") &&
|
||||
context.task.has ("recur"))
|
||||
{
|
||||
context.task.setStatus (Task::recurring);
|
||||
context.task.set ("mask", "");
|
||||
}
|
||||
|
||||
// Tasks with a wait: date get a special status.
|
||||
else if (context.task.has ("wait"))
|
||||
context.task.setStatus (Task::waiting);
|
||||
|
||||
// By default, tasks are pending.
|
||||
else
|
||||
context.task.setStatus (Task::pending);
|
||||
|
||||
// Override with default.project, if not specified.
|
||||
if (context.task.get ("project") == "")
|
||||
context.task.set ("project", context.config.get ("default.project"));
|
||||
|
||||
// Override with default.priority, if not specified.
|
||||
if (context.task.get ("priority") == "")
|
||||
{
|
||||
std::string defaultPriority = context.config.get ("default.priority");
|
||||
if (Att::validNameValue ("priority", "", defaultPriority))
|
||||
context.task.set ("priority", defaultPriority);
|
||||
}
|
||||
|
||||
// Override with default.due, if not specified.
|
||||
if (context.task.get ("due") == "")
|
||||
{
|
||||
std::string defaultDue = context.config.get ("default.due");
|
||||
if (defaultDue != "" &&
|
||||
Att::validNameValue ("due", "", defaultDue))
|
||||
context.task.set ("due", defaultDue);
|
||||
}
|
||||
|
||||
// Include tags.
|
||||
std::vector <std::string>::iterator tag;
|
||||
for (tag = context.tagAdditions.begin ();
|
||||
tag != context.tagAdditions.end ();
|
||||
++tag)
|
||||
context.task.addTag (*tag);
|
||||
|
||||
// Must load pending to resolve dependencies, and to provide a new ID.
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
|
||||
std::vector <Task> all;
|
||||
Filter none;
|
||||
context.tdb.loadPending (all, none);
|
||||
context.tdb.loadPending (all);
|
||||
|
||||
// Resolve dependencies.
|
||||
if (context.task.has ("depends"))
|
||||
{
|
||||
// Convert ID to UUID.
|
||||
std::vector <std::string> deps;
|
||||
split (deps, context.task.get ("depends"), ',');
|
||||
// Every task needs a UUID.
|
||||
Task task;
|
||||
task.set ("uuid", uuid ());
|
||||
|
||||
// Eliminate the ID-based set.
|
||||
context.task.set ("depends", "");
|
||||
|
||||
std::vector <std::string>::iterator i;
|
||||
for (i = deps.begin (); i != deps.end (); i++)
|
||||
{
|
||||
int id = strtol (i->c_str (), NULL, 10);
|
||||
if (id < 0)
|
||||
context.task.removeDependency (-id);
|
||||
else
|
||||
context.task.addDependency (id);
|
||||
}
|
||||
}
|
||||
// Apply the command line modifications to the new task.
|
||||
Arguments modifications = context.args.extract_modifications ();
|
||||
modify_task (task, modifications);
|
||||
apply_defaults (task);
|
||||
|
||||
// Only valid tasks can be added.
|
||||
context.task.validate ();
|
||||
task.validate ();
|
||||
|
||||
context.tdb.add (context.task);
|
||||
context.tdb.add (task);
|
||||
|
||||
std::stringstream out;
|
||||
// TODO This should be a call in to feedback.cpp.
|
||||
#ifdef FEATURE_NEW_ID
|
||||
out << "Created task " << context.tdb.nextId () << ".\n";
|
||||
#endif
|
||||
|
||||
context.footnote (onProjectChange (context.task));
|
||||
context.footnote (onProjectChange (task));
|
||||
|
||||
context.tdb.commit ();
|
||||
context.tdb.unlock ();
|
||||
|
||||
output = out.str ();
|
||||
*/
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,9 +25,12 @@
|
|||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define L10N // Localization complete.
|
||||
|
||||
#include <sstream>
|
||||
#include <Context.h>
|
||||
#include <text.h>
|
||||
#include <i18n.h>
|
||||
#include <util.h>
|
||||
#include <main.h>
|
||||
#include <CmdLog.h>
|
||||
|
@ -39,7 +42,7 @@ CmdLog::CmdLog ()
|
|||
{
|
||||
_keyword = "log";
|
||||
_usage = "task log [tags] [attrs] desc...";
|
||||
_description = "Adds a new task that is already completed.";
|
||||
_description = STRING_CMD_LOG_USAGE;
|
||||
_read_only = false;
|
||||
_displays_id = false;
|
||||
}
|
||||
|
@ -48,70 +51,49 @@ CmdLog::CmdLog ()
|
|||
int CmdLog::execute (std::string& output)
|
||||
{
|
||||
int rc = 0;
|
||||
/*
|
||||
std::stringstream out;
|
||||
|
||||
context.task.setStatus (Task::completed);
|
||||
context.task.set ("uuid", uuid ());
|
||||
context.task.setEntry ();
|
||||
// Must load pending to resolve dependencies, and to provide a new ID.
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
|
||||
// Add an end date.
|
||||
char entryTime[16];
|
||||
sprintf (entryTime, "%u", (unsigned int) time (NULL));
|
||||
context.task.set ("end", entryTime);
|
||||
std::vector <Task> all;
|
||||
context.tdb.loadPending (all);
|
||||
|
||||
// Every task needs a UUID.
|
||||
Task task;
|
||||
task.set ("uuid", uuid ());
|
||||
|
||||
// Apply the command line modifications to the new task.
|
||||
Arguments modifications = context.args.extract_modifications ();
|
||||
modify_task (task, modifications);
|
||||
apply_defaults (task);
|
||||
|
||||
// Recurring tasks get a special status.
|
||||
if (context.task.has ("recur"))
|
||||
if (task.has ("recur"))
|
||||
throw std::string ("You cannot log recurring tasks.");
|
||||
|
||||
if (context.task.has ("wait"))
|
||||
if (task.has ("wait"))
|
||||
throw std::string ("You cannot log waiting tasks.");
|
||||
|
||||
// It makes no sense to add dependencies to an already-completed task.
|
||||
if (context.task.get ("depends") != "")
|
||||
throw std::string ("You cannot specify dependencies on a completed task.");
|
||||
// Override with log-specific changes.
|
||||
task.setStatus (Task::completed);
|
||||
|
||||
// Override with default.project, if not specified.
|
||||
if (context.task.get ("project") == "")
|
||||
context.task.set ("project", context.config.get ("default.project"));
|
||||
|
||||
// Override with default.priority, if not specified.
|
||||
if (context.task.get ("priority") == "")
|
||||
{
|
||||
std::string defaultPriority = context.config.get ("default.priority");
|
||||
if (Att::validNameValue ("priority", "", defaultPriority))
|
||||
context.task.set ("priority", defaultPriority);
|
||||
}
|
||||
|
||||
// Override with default.due, if not specified.
|
||||
if (context.task.get ("due") == "")
|
||||
{
|
||||
std::string defaultDue = context.config.get ("default.due");
|
||||
if (defaultDue != "" &&
|
||||
Att::validNameValue ("due", "", defaultDue))
|
||||
context.task.set ("due", defaultDue);
|
||||
}
|
||||
|
||||
// Include tags.
|
||||
std::vector <std::string>::iterator tag;
|
||||
for (tag = tagAdditions.begin 90; tag != tagAdditions.end (); ++tag)
|
||||
context.task.addTag (*tag);
|
||||
// Provide an end date unless user already specified one.
|
||||
if (task.get ("end") == "")
|
||||
task.set ("end", task.get ("entry"));
|
||||
|
||||
// Only valid tasks can be added.
|
||||
context.task.validate ();
|
||||
task.validate ();
|
||||
|
||||
context.tdb.add (task);
|
||||
|
||||
context.footnote (onProjectChange (task));
|
||||
|
||||
context.tdb.lock (context.config.getBoolean ("locking"));
|
||||
context.tdb.add (context.task);
|
||||
context.tdb.commit ();
|
||||
|
||||
if (context.config.getBoolean ("echo.command"))
|
||||
out << "Logged task.\n";
|
||||
|
||||
context.footnote (onProjectChange (context.task));
|
||||
context.tdb.unlock ();
|
||||
|
||||
output = out.str ();
|
||||
*/
|
||||
if (context.config.getBoolean ("echo.command"))
|
||||
output = "Logged task.\n";
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,10 +25,15 @@
|
|||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define L10N // Localization complete.
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <Expression.h>
|
||||
#include <Att.h>
|
||||
#include <Timer.h>
|
||||
#include <text.h>
|
||||
#include <i18n.h>
|
||||
#include <Command.h>
|
||||
|
||||
#include <CmdAdd.h>
|
||||
|
@ -77,6 +82,10 @@
|
|||
#include <CmdVersion.h>
|
||||
#include <Context.h>
|
||||
|
||||
#include <ColProject.h>
|
||||
#include <ColPriority.h>
|
||||
#include <ColDue.h>
|
||||
|
||||
extern Context context;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -162,9 +171,7 @@ void Command::factory (std::map <std::string, Command*>& all)
|
|||
{
|
||||
// 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.";
|
||||
throw format (STRING_CMD_CONFLICT, *report);
|
||||
|
||||
c = new CmdCustom (
|
||||
*report,
|
||||
|
@ -271,3 +278,129 @@ void Command::filter (std::vector <Task>& input, std::vector <Task>& output)
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Apply the modifications in arguments to the task.
|
||||
void Command::modify_task (Task& task, Arguments& arguments)
|
||||
{
|
||||
std::string description;
|
||||
|
||||
std::vector <std::pair <std::string, std::string> >::iterator arg;
|
||||
for (arg = arguments.begin (); arg != arguments.end (); ++arg)
|
||||
{
|
||||
// Attributes are essentially name:value pairs, and correspond directly
|
||||
// to stored attributes.
|
||||
if (arg->second == "attr")
|
||||
{
|
||||
std::string name;
|
||||
std::string value;
|
||||
Arguments::extract_attr (arg->first, name, value);
|
||||
|
||||
// Dependencies must be resolved to UUIDs.
|
||||
if (name == "depends")
|
||||
{
|
||||
// Convert ID to UUID.
|
||||
std::vector <std::string> deps;
|
||||
split (deps, value, ',');
|
||||
|
||||
// Apply or remove dendencies in turn.
|
||||
std::vector <std::string>::iterator i;
|
||||
for (i = deps.begin (); i != deps.end (); i++)
|
||||
{
|
||||
int id = strtol (i->c_str (), NULL, 10);
|
||||
if (id < 0)
|
||||
task.removeDependency (-id);
|
||||
else
|
||||
task.addDependency (id);
|
||||
}
|
||||
}
|
||||
|
||||
// By default, just add it.
|
||||
else
|
||||
task.set (name, value);
|
||||
}
|
||||
|
||||
// Tags need special handling because they are essentially a vector stored
|
||||
// in a single string, therefore Task::{add,remove}Tag must be called as
|
||||
// appropriate.
|
||||
else if (arg->second == "tag")
|
||||
{
|
||||
char type;
|
||||
std::string value;
|
||||
Arguments::extract_tag (arg->first, type, value);
|
||||
|
||||
if (type == '+')
|
||||
task.addTag (value);
|
||||
else
|
||||
task.removeTag (value);
|
||||
}
|
||||
|
||||
// Words and operators are aggregated into a description.
|
||||
else if (arg->second == "word" ||
|
||||
arg->second == "op")
|
||||
{
|
||||
if (description.length ())
|
||||
description += " ";
|
||||
|
||||
description += arg->first;
|
||||
}
|
||||
|
||||
// Any additional argument types are indicative of a failure in
|
||||
// Arguments::extract_modifications.
|
||||
else
|
||||
throw format (STRING_CMD_MOD_UNEXPECTED, arg->first);
|
||||
}
|
||||
|
||||
task.set ("description", description);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void Command::apply_defaults (Task& task)
|
||||
{
|
||||
// Provide an entry date unless user already specified one.
|
||||
if (task.get ("entry") == "")
|
||||
task.setEntry ();
|
||||
|
||||
// Recurring tasks get a special status.
|
||||
if (task.has ("due") &&
|
||||
task.has ("recur"))
|
||||
{
|
||||
task.setStatus (Task::recurring);
|
||||
task.set ("mask", "");
|
||||
}
|
||||
|
||||
// Tasks with a wait: date get a special status.
|
||||
else if (task.has ("wait"))
|
||||
task.setStatus (Task::waiting);
|
||||
|
||||
// By default, tasks are pending.
|
||||
else
|
||||
task.setStatus (Task::pending);
|
||||
|
||||
// Override with default.project, if not specified.
|
||||
if (task.get ("project") == "")
|
||||
{
|
||||
std::string defaultProject = context.config.get ("default.project");
|
||||
if (defaultProject != "" &&
|
||||
context.columns["project"]->validate (defaultProject))
|
||||
task.set ("project", defaultProject);
|
||||
}
|
||||
|
||||
// Override with default.priority, if not specified.
|
||||
if (task.get ("priority") == "")
|
||||
{
|
||||
std::string defaultPriority = context.config.get ("default.priority");
|
||||
if (defaultPriority != "" &&
|
||||
context.columns["priority"]->validate (defaultPriority))
|
||||
task.set ("priority", defaultPriority);
|
||||
}
|
||||
|
||||
// Override with default.due, if not specified.
|
||||
if (task.get ("due") == "")
|
||||
{
|
||||
std::string defaultDue = context.config.get ("default.due");
|
||||
if (defaultDue != "" &&
|
||||
context.columns["due"]->validate (defaultDue))
|
||||
task.set ("due", defaultDue);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <vector>
|
||||
#include <string>
|
||||
#include <Task.h>
|
||||
#include <Arguments.h>
|
||||
|
||||
class Command
|
||||
{
|
||||
|
@ -51,7 +52,10 @@ public:
|
|||
bool displays_id () const;
|
||||
virtual int execute (std::string&) = 0;
|
||||
|
||||
protected:
|
||||
void filter (std::vector <Task>&, std::vector <Task>&);
|
||||
void modify_task (Task&, Arguments&);
|
||||
void apply_defaults (Task&);
|
||||
|
||||
protected:
|
||||
std::string _keyword;
|
||||
|
|
|
@ -143,6 +143,7 @@
|
|||
#define STRING_COLUMN_LABEL_URGENCY "Urgency"
|
||||
|
||||
// commands/Cmd*
|
||||
#define STRING_CMD_CONFLICT "Custom report '{1}' conflicts with built-in task command."
|
||||
#define STRING_CMD_VERSION_USAGE "Shows the taskwarrior version number."
|
||||
#define STRING_CMD_VERSION_USAGE2 "Shows only the taskwarrior version number."
|
||||
#define STRING_CMD_VERSION_GPL "Taskwarrior may be copied only under the terms of the GNU General Public License, which may be found in the taskwarrior source kit."
|
||||
|
@ -157,6 +158,9 @@
|
|||
#define STRING_CMD_URGENCY_USAGE "Displays the urgency measure of a task."
|
||||
#define STRING_CMD_URGENCY_NO_TASKS "No tasks specified."
|
||||
#define STRING_CMD_URGENCY_RESULT "task {1} urgency {2}"
|
||||
#define STRING_CMD_ADD_USAGE "Adds a new task."
|
||||
#define STRING_CMD_MOD_UNEXPECTED "Unexpected argument '{1}' found while modifying a task."
|
||||
#define STRING_CMD_LOG_USAGE "Adds a new task that is already completed."
|
||||
|
||||
// Config
|
||||
#define STRING_CONFIG_OVERNEST "Configuration file nested to more than 10 levels deep - this has to be a mistake."
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue