mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-06-26 10:54:26 +02:00
Enhancements - validation
- Implemented Cmd::isReadOnlyCommand. - Implemented Cmd::isWriteCommand. - Added unit tests for above.
This commit is contained in:
parent
bc8aba26a9
commit
0b14efbb76
7 changed files with 217 additions and 322 deletions
|
@ -258,8 +258,8 @@ bool Att::match (const Att& other) const
|
|||
// TODO after
|
||||
// TODO not <-- could be a problem
|
||||
// TODO synth
|
||||
// TODO under
|
||||
// TODO over
|
||||
// TODO under/below
|
||||
// TODO over/above
|
||||
// TODO first
|
||||
// TODO last
|
||||
// TODO this
|
||||
|
|
47
src/Cmd.cpp
47
src/Cmd.cpp
|
@ -173,3 +173,50 @@ void Cmd::allCustomReports (std::vector <std::string>& all) const
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Commands that do not directly modify the data files.
|
||||
bool Cmd::isReadOnlyCommand ()
|
||||
{
|
||||
if (command == context.stringtable.get (CMD_ACTIVE, "active") || // R
|
||||
command == context.stringtable.get (CMD_CALENDAR, "calendar") || // R
|
||||
command == context.stringtable.get (CMD_COLORS, "colors") || // R
|
||||
command == context.stringtable.get (CMD_COMPLETED, "completed") || // R
|
||||
command == context.stringtable.get (CMD_EXPORT, "export") || // R
|
||||
command == context.stringtable.get (CMD_HELP, "help") || // R
|
||||
command == context.stringtable.get (CMD_HISTORY, "history") || // R
|
||||
command == context.stringtable.get (CMD_GHISTORY, "ghistory") || // R
|
||||
command == context.stringtable.get (CMD_INFO, "info") || // R
|
||||
command == context.stringtable.get (CMD_NEXT, "next") || // R
|
||||
command == context.stringtable.get (CMD_OVERDUE, "overdue") || // R
|
||||
command == context.stringtable.get (CMD_PROJECTS, "projects") || // R
|
||||
command == context.stringtable.get (CMD_STATS, "stats") || // R
|
||||
command == context.stringtable.get (CMD_SUMMARY, "summary") || // R
|
||||
command == context.stringtable.get (CMD_TAGS, "tags") || // R
|
||||
command == context.stringtable.get (CMD_TIMESHEET, "timesheet") || // R
|
||||
command == context.stringtable.get (CMD_VERSION, "version")) // R
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Commands that directly modify the data files.
|
||||
bool Cmd::isWriteCommand ()
|
||||
{
|
||||
if (command == context.stringtable.get (CMD_ADD, "add") || // W
|
||||
command == context.stringtable.get (CMD_APPEND, "append") || // W
|
||||
command == context.stringtable.get (CMD_ANNOTATE, "annotate") || // W
|
||||
command == context.stringtable.get (CMD_DELETE, "delete") || // W
|
||||
command == context.stringtable.get (CMD_DONE, "done") || // W
|
||||
command == context.stringtable.get (CMD_DUPLICATE, "duplicate") || // W
|
||||
command == context.stringtable.get (CMD_EDIT, "edit") || // W
|
||||
command == context.stringtable.get (CMD_IMPORT, "import") || // W
|
||||
command == context.stringtable.get (CMD_START, "start") || // W
|
||||
command == context.stringtable.get (CMD_STOP, "stop") || // W
|
||||
command == context.stringtable.get (CMD_UNDELETE, "undelete") || // W
|
||||
command == context.stringtable.get (CMD_UNDO, "undo")) // W
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -43,6 +43,9 @@ public:
|
|||
void parse (const std::string&);
|
||||
void allCustomReports (std::vector <std::string>&) const;
|
||||
|
||||
bool isReadOnlyCommand ();
|
||||
bool isWriteCommand ();
|
||||
|
||||
public:
|
||||
std::string command;
|
||||
|
||||
|
|
|
@ -361,7 +361,8 @@ std::cout << "[1;31m# parse sequence '" << *arg << "'[0m" << std::endl;
|
|||
|
||||
// Tags to include begin with '+'.
|
||||
else if (arg->length () > 1 &&
|
||||
(*arg)[0] == '+')
|
||||
(*arg)[0] == '+' &&
|
||||
validTag (*arg))
|
||||
{
|
||||
std::cout << "[1;31m# parse tag addition '" << *arg << "'[0m" << std::endl;
|
||||
if (foundSequence)
|
||||
|
@ -372,7 +373,8 @@ std::cout << "[1;31m# parse tag addition '" << *arg << "'[0m" << std::endl;
|
|||
|
||||
// Tags to remove begin with '-'.
|
||||
else if (arg->length () > 1 &&
|
||||
(*arg)[0] == '-')
|
||||
(*arg)[0] == '-' &&
|
||||
validTag (*arg))
|
||||
{
|
||||
std::cout << "[1;31m# parse tag removal '" << *arg << "'[0m" << std::endl;
|
||||
if (foundSequence)
|
||||
|
@ -445,6 +447,10 @@ std::cout << "[1;31m# parse post-termination description '" << *arg << "'[0m"
|
|||
if (validDescription (descCandidate))
|
||||
task.set ("description", descCandidate);
|
||||
|
||||
// TODO task.validate ()
|
||||
// TODO if readOnlyCommand (cmd.command) then any attributes are allowed
|
||||
// TODO if writeCommand (cmd.command) then only modifiable attributes are allowed
|
||||
|
||||
constructFilter ();
|
||||
|
||||
// If no command was specified, and there were no command line arguments
|
||||
|
|
11
src/main.h
11
src/main.h
|
@ -37,20 +37,21 @@
|
|||
#include "../auto.h"
|
||||
|
||||
// valid.cpp
|
||||
void guess (const std::string&, const char**, std::string&);
|
||||
bool validPriority (const std::string&);
|
||||
bool validDate (std::string&);
|
||||
bool validDuration (std::string&);
|
||||
bool validDescription (const std::string&);
|
||||
bool validDuration (std::string&);
|
||||
void validReportColumns (const std::vector <std::string>&);
|
||||
void validSortColumns (const std::vector <std::string>&, const std::vector <std::string>&);
|
||||
bool isModifiableAttribute (const std::string&);
|
||||
bool validAttribute (std::string&, std::string&);
|
||||
bool validId (const std::string&);
|
||||
bool validTag (const std::string&);
|
||||
|
||||
// task.cpp
|
||||
void gatherNextTasks (/*const TDB&,*/ T&, std::vector <T>&, std::vector <int>&);
|
||||
void onChangeCallback ();
|
||||
/*
|
||||
std::string runTaskCommand (int, char**, TDB&, bool gc = true, bool shadow = true);
|
||||
std::string runTaskCommand (std::vector <std::string>&, TDB&, bool gc = false, bool shadow = false);
|
||||
*/
|
||||
|
||||
// recur.cpp
|
||||
void handleRecurrence ();
|
||||
|
|
|
@ -33,11 +33,127 @@ Context context;
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
int main (int argc, char** argv)
|
||||
{
|
||||
UnitTest t (18);
|
||||
UnitTest t (76);
|
||||
|
||||
context.config.set ("report.foo.columns", "id");
|
||||
|
||||
Cmd cmd;
|
||||
cmd.command = "active";
|
||||
t.ok (cmd.isReadOnlyCommand (), "isReadOnlyCommand active");
|
||||
t.notok (cmd.isWriteCommand (), "not isWriteCommand active");
|
||||
|
||||
cmd.command = "calendar";
|
||||
t.ok (cmd.isReadOnlyCommand (), "isReadOnlyCommand calendar");
|
||||
t.notok (cmd.isWriteCommand (), "not isWriteCommand calendar");
|
||||
|
||||
cmd.command = "colors";
|
||||
t.ok (cmd.isReadOnlyCommand (), "isReadOnlyCommand colors");
|
||||
t.notok (cmd.isWriteCommand (), "not isWriteCommand colors");
|
||||
|
||||
cmd.command = "completed";
|
||||
t.ok (cmd.isReadOnlyCommand (), "isReadOnlyCommand completed");
|
||||
t.notok (cmd.isWriteCommand (), "not isWriteCommand completed");
|
||||
|
||||
cmd.command = "export";
|
||||
t.ok (cmd.isReadOnlyCommand (), "isReadOnlyCommand export");
|
||||
t.notok (cmd.isWriteCommand (), "not isWriteCommand export");
|
||||
|
||||
cmd.command = "help";
|
||||
t.ok (cmd.isReadOnlyCommand (), "isReadOnlyCommand help");
|
||||
t.notok (cmd.isWriteCommand (), "not isWriteCommand help");
|
||||
|
||||
cmd.command = "history";
|
||||
t.ok (cmd.isReadOnlyCommand (), "isReadOnlyCommand history");
|
||||
t.notok (cmd.isWriteCommand (), "not isWriteCommand history");
|
||||
|
||||
cmd.command = "ghistory";
|
||||
t.ok (cmd.isReadOnlyCommand (), "isReadOnlyCommand ghistory");
|
||||
t.notok (cmd.isWriteCommand (), "not isWriteCommand ghistory");
|
||||
|
||||
cmd.command = "info";
|
||||
t.ok (cmd.isReadOnlyCommand (), "isReadOnlyCommand info");
|
||||
t.notok (cmd.isWriteCommand (), "not isWriteCommand info");
|
||||
|
||||
cmd.command = "next";
|
||||
t.ok (cmd.isReadOnlyCommand (), "isReadOnlyCommand next");
|
||||
t.notok (cmd.isWriteCommand (), "not isWriteCommand next");
|
||||
|
||||
cmd.command = "overdue";
|
||||
t.ok (cmd.isReadOnlyCommand (), "isReadOnlyCommand overdue");
|
||||
t.notok (cmd.isWriteCommand (), "not isWriteCommand overdue");
|
||||
|
||||
cmd.command = "projects";
|
||||
t.ok (cmd.isReadOnlyCommand (), "isReadOnlyCommand projects");
|
||||
t.notok (cmd.isWriteCommand (), "not isWriteCommand projects");
|
||||
|
||||
cmd.command = "stats";
|
||||
t.ok (cmd.isReadOnlyCommand (), "isReadOnlyCommand stats");
|
||||
t.notok (cmd.isWriteCommand (), "not isWriteCommand stats");
|
||||
|
||||
cmd.command = "summary";
|
||||
t.ok (cmd.isReadOnlyCommand (), "isReadOnlyCommand summary");
|
||||
t.notok (cmd.isWriteCommand (), "not isWriteCommand summary");
|
||||
|
||||
cmd.command = "tags";
|
||||
t.ok (cmd.isReadOnlyCommand (), "isReadOnlyCommand tags");
|
||||
t.notok (cmd.isWriteCommand (), "not isWriteCommand tags");
|
||||
|
||||
cmd.command = "timesheet";
|
||||
t.ok (cmd.isReadOnlyCommand (), "isReadOnlyCommand timesheet");
|
||||
t.notok (cmd.isWriteCommand (), "not isWriteCommand timesheet");
|
||||
|
||||
cmd.command = "version";
|
||||
t.ok (cmd.isReadOnlyCommand (), "isReadOnlyCommand version");
|
||||
t.notok (cmd.isWriteCommand (), "not isWriteCommand version");
|
||||
|
||||
cmd.command = "add";
|
||||
t.notok (cmd.isReadOnlyCommand (), "not isReadOnlyCommand add");
|
||||
t.ok (cmd.isWriteCommand (), "isWriteCommand add");
|
||||
|
||||
cmd.command = "append";
|
||||
t.notok (cmd.isReadOnlyCommand (), "not isReadOnlyCommand append");
|
||||
t.ok (cmd.isWriteCommand (), "isWriteCommand append");
|
||||
|
||||
cmd.command = "annotate";
|
||||
t.notok (cmd.isReadOnlyCommand (), "not isReadOnlyCommand annotate");
|
||||
t.ok (cmd.isWriteCommand (), "isWriteCommand annotate");
|
||||
|
||||
cmd.command = "delete";
|
||||
t.notok (cmd.isReadOnlyCommand (), "not isReadOnlyCommand delete");
|
||||
t.ok (cmd.isWriteCommand (), "isWriteCommand delete");
|
||||
|
||||
cmd.command = "done";
|
||||
t.notok (cmd.isReadOnlyCommand (), "not isReadOnlyCommand done");
|
||||
t.ok (cmd.isWriteCommand (), "isWriteCommand done");
|
||||
|
||||
cmd.command = "duplicate";
|
||||
t.notok (cmd.isReadOnlyCommand (), "not isReadOnlyCommand duplicate");
|
||||
t.ok (cmd.isWriteCommand (), "isWriteCommand duplicate");
|
||||
|
||||
cmd.command = "edit";
|
||||
t.notok (cmd.isReadOnlyCommand (), "not isReadOnlyCommand edit");
|
||||
t.ok (cmd.isWriteCommand (), "isWriteCommand edit");
|
||||
|
||||
cmd.command = "import";
|
||||
t.notok (cmd.isReadOnlyCommand (), "not isReadOnlyCommand import");
|
||||
t.ok (cmd.isWriteCommand (), "isWriteCommand import");
|
||||
|
||||
cmd.command = "start";
|
||||
t.notok (cmd.isReadOnlyCommand (), "not isReadOnlyCommand start");
|
||||
t.ok (cmd.isWriteCommand (), "isWriteCommand start");
|
||||
|
||||
cmd.command = "stop";
|
||||
t.notok (cmd.isReadOnlyCommand (), "not isReadOnlyCommand stop");
|
||||
t.ok (cmd.isWriteCommand (), "isWriteCommand stop");
|
||||
|
||||
cmd.command = "undelete";
|
||||
t.notok (cmd.isReadOnlyCommand (), "not isReadOnlyCommand undelete");
|
||||
t.ok (cmd.isWriteCommand (), "isWriteCommand undelete");
|
||||
|
||||
cmd.command = "undo";
|
||||
t.notok (cmd.isReadOnlyCommand (), "not isReadOnlyCommand undo");
|
||||
t.ok (cmd.isWriteCommand (), "isWriteCommand undo");
|
||||
|
||||
t.ok (cmd.valid ("annotate"), "Cmd::valid annotate");
|
||||
t.ok (cmd.valid ("annotat"), "Cmd::valid annotat");
|
||||
t.ok (cmd.valid ("annota"), "Cmd::valid annota");
|
||||
|
|
346
src/valid.cpp
346
src/valid.cpp
|
@ -42,6 +42,7 @@ extern Context context;
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
// NOTE: These are static arrays only because there is no initializer list for
|
||||
// std::vector.
|
||||
// TODO Obsolete
|
||||
static const char* colors[] =
|
||||
{
|
||||
"bold",
|
||||
|
@ -104,6 +105,7 @@ static const char* colors[] =
|
|||
"",
|
||||
};
|
||||
|
||||
// TODO Obsolete
|
||||
static const char* attributes[] =
|
||||
{
|
||||
"project",
|
||||
|
@ -118,44 +120,23 @@ static const char* attributes[] =
|
|||
"until",
|
||||
"mask",
|
||||
"imask",
|
||||
// "limit",
|
||||
"",
|
||||
};
|
||||
|
||||
// Alphabetical please.
|
||||
static const char* commands[] =
|
||||
static const char* modifiableAttributes[] =
|
||||
{
|
||||
"active",
|
||||
"add",
|
||||
"append",
|
||||
"annotate",
|
||||
"calendar",
|
||||
"colors",
|
||||
"completed",
|
||||
"delete",
|
||||
"done",
|
||||
"duplicate",
|
||||
"edit",
|
||||
"export",
|
||||
"help",
|
||||
"history",
|
||||
"ghistory",
|
||||
"import",
|
||||
"info",
|
||||
"next",
|
||||
"overdue",
|
||||
"projects",
|
||||
"start",
|
||||
"stats",
|
||||
"stop",
|
||||
"summary",
|
||||
"tags",
|
||||
"timesheet",
|
||||
"undelete",
|
||||
"undo",
|
||||
"version",
|
||||
"project",
|
||||
"priority",
|
||||
"fg",
|
||||
"bg",
|
||||
"due",
|
||||
"recur",
|
||||
"until",
|
||||
"",
|
||||
};
|
||||
|
||||
// TODO Relocate inside Context.
|
||||
static std::vector <std::string> customReports;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -171,25 +152,6 @@ void guess (
|
|||
guess (type, options, candidate);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
static bool isCommand (const std::string& candidate)
|
||||
{
|
||||
std::vector <std::string> options;
|
||||
for (int i = 0; commands[i][0]; ++i)
|
||||
options.push_back (commands[i]);
|
||||
|
||||
std::vector <std::string> matches;
|
||||
autoComplete (candidate, options, matches);
|
||||
if (0 == matches.size ())
|
||||
{
|
||||
autoComplete (candidate, customReports, matches);
|
||||
if (0 == matches.size ())
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool validDate (std::string& date)
|
||||
{
|
||||
|
@ -217,9 +179,26 @@ bool validPriority (const std::string& input)
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
static bool validAttribute (
|
||||
std::string& name,
|
||||
std::string& value)
|
||||
// Only attributes that are written to the data files.
|
||||
// TODO Relocate to Att.cpp.
|
||||
bool isModifiableAttribute (const std::string& name)
|
||||
{
|
||||
if (name == "project" ||
|
||||
name == "priority" ||
|
||||
name == "fg" ||
|
||||
name == "bg" ||
|
||||
name == "due" ||
|
||||
name == "recur" ||
|
||||
name == "until")
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// All attributes, regardless of usage.
|
||||
// TODO Relocate to Att.cpp.
|
||||
bool validAttribute (std::string& name, std::string& value)
|
||||
{
|
||||
guess ("attribute", attributes, name);
|
||||
if (name != "")
|
||||
|
@ -256,7 +235,7 @@ static bool validAttribute (
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
static bool validId (const std::string& input)
|
||||
bool validId (const std::string& input)
|
||||
{
|
||||
if (input.length () == 0)
|
||||
return false;
|
||||
|
@ -269,59 +248,7 @@ static bool validId (const std::string& input)
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// 1,2-4,6
|
||||
static bool validSequence (
|
||||
const std::string& input,
|
||||
std::vector <int>& ids)
|
||||
{
|
||||
std::vector <std::string> ranges;
|
||||
split (ranges, input, ',');
|
||||
|
||||
std::vector <std::string>::iterator it;
|
||||
for (it = ranges.begin (); it != ranges.end (); ++it)
|
||||
{
|
||||
std::vector <std::string> range;
|
||||
split (range, *it, '-');
|
||||
|
||||
switch (range.size ())
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
if (! validId (range[0]))
|
||||
return false;
|
||||
|
||||
int id = ::atoi (range[0].c_str ());
|
||||
ids.push_back (id);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
{
|
||||
if (! validId (range[0]) ||
|
||||
! validId (range[1]))
|
||||
return false;
|
||||
|
||||
int low = ::atoi (range[0].c_str ());
|
||||
int high = ::atoi (range[1].c_str ());
|
||||
if (low >= high)
|
||||
return false;
|
||||
|
||||
for (int i = low; i <= high; ++i)
|
||||
ids.push_back (i);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ids.size () ? true : false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
static bool validTag (const std::string& input)
|
||||
bool validTag (const std::string& input)
|
||||
{
|
||||
if ((input[0] == '-' || input[0] == '+') &&
|
||||
input.length () > 1)
|
||||
|
@ -342,62 +269,6 @@ bool validDescription (const std::string& input)
|
|||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool validCommand (std::string& input)
|
||||
{
|
||||
std::string copy = input;
|
||||
guess ("command", commands, copy);
|
||||
if (copy == "")
|
||||
{
|
||||
copy = input;
|
||||
guess ("command", customReports, copy);
|
||||
if (copy == "")
|
||||
return false;
|
||||
}
|
||||
|
||||
input = copy;
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
static bool validSubstitution (
|
||||
std::string& input,
|
||||
std::string& from,
|
||||
std::string& to,
|
||||
bool& global)
|
||||
{
|
||||
size_t first = input.find ('/');
|
||||
if (first != std::string::npos)
|
||||
{
|
||||
size_t second = input.find ('/', first + 1);
|
||||
if (second != std::string::npos)
|
||||
{
|
||||
size_t third = input.find ('/', second + 1);
|
||||
if (third != std::string::npos)
|
||||
{
|
||||
if (first == 0 &&
|
||||
first < second &&
|
||||
second < third &&
|
||||
(third == input.length () - 1 ||
|
||||
third == input.length () - 2))
|
||||
{
|
||||
from = input.substr (first + 1, second - first - 1);
|
||||
to = input.substr (second + 1, third - second - 1);
|
||||
|
||||
global = false;
|
||||
if (third == input.length () - 2 &&
|
||||
input.find ('g', third + 1) != std::string::npos)
|
||||
global = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool validDuration (std::string& input)
|
||||
{
|
||||
|
@ -406,155 +277,6 @@ bool validDuration (std::string& input)
|
|||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Token EBNF
|
||||
// ------- ----------------------------------
|
||||
// command first non-id recognized argument
|
||||
//
|
||||
// substitution ::= "/" from "/" to "/g"
|
||||
// | "/" from "/" to "/" ;
|
||||
//
|
||||
// tags ::= "+" word
|
||||
// | "-" word ;
|
||||
//
|
||||
// attributes ::= word ":" value
|
||||
// | word ":"
|
||||
//
|
||||
// sequence ::= \d+ "," sequence
|
||||
// | \d+ "-" \d+ ;
|
||||
//
|
||||
// description (whatever isn't one of the above)
|
||||
/*
|
||||
void parse (
|
||||
std::vector <std::string>& args,
|
||||
std::string& command,
|
||||
T& task)
|
||||
{
|
||||
command = "";
|
||||
|
||||
bool terminated = false;
|
||||
bool foundSequence = false;
|
||||
bool foundSomethingAfterSequence = false;
|
||||
|
||||
std::string descCandidate = "";
|
||||
for (size_t i = 0; i < args.size (); ++i)
|
||||
{
|
||||
std::string arg (args[i]);
|
||||
|
||||
if (!terminated)
|
||||
{
|
||||
size_t colon; // Pointer to colon in argument.
|
||||
std::string from;
|
||||
std::string to;
|
||||
bool global;
|
||||
std::vector <int> sequence;
|
||||
|
||||
// The '--' argument shuts off all parsing - everything is an argument.
|
||||
if (arg == "--")
|
||||
terminated = true;
|
||||
|
||||
// An id is the first argument found that contains all digits.
|
||||
else if (lowerCase (command) != "add" && // "add" doesn't require an ID
|
||||
validSequence (arg, sequence) &&
|
||||
! foundSomethingAfterSequence)
|
||||
{
|
||||
foundSequence = true;
|
||||
foreach (id, sequence)
|
||||
task.addId (*id);
|
||||
}
|
||||
|
||||
// Tags begin with + or - and contain arbitrary text.
|
||||
else if (validTag (arg))
|
||||
{
|
||||
if (foundSequence)
|
||||
foundSomethingAfterSequence = true;
|
||||
|
||||
if (arg[0] == '+')
|
||||
task.addTag (arg.substr (1, std::string::npos));
|
||||
else if (arg[0] == '-')
|
||||
task.addRemoveTag (arg.substr (1, std::string::npos));
|
||||
}
|
||||
|
||||
// Attributes contain a constant string followed by a colon, followed by a
|
||||
// value.
|
||||
else if ((colon = arg.find (":")) != std::string::npos)
|
||||
{
|
||||
if (foundSequence)
|
||||
foundSomethingAfterSequence = true;
|
||||
|
||||
std::string name = lowerCase (arg.substr (0, colon));
|
||||
std::string value = arg.substr (colon + 1, std::string::npos);
|
||||
|
||||
if (validAttribute (name, value))
|
||||
{
|
||||
if (name != "recur" || validDuration (value))
|
||||
task.setAttribute (name, value);
|
||||
}
|
||||
|
||||
// If it is not a valid attribute, then allow the argument as part of
|
||||
// the description.
|
||||
else
|
||||
{
|
||||
if (descCandidate.length ())
|
||||
descCandidate += " ";
|
||||
descCandidate += arg;
|
||||
}
|
||||
}
|
||||
|
||||
// Substitution of description text.
|
||||
else if (validSubstitution (arg, from, to, global))
|
||||
{
|
||||
if (foundSequence)
|
||||
foundSomethingAfterSequence = true;
|
||||
|
||||
task.setSubstitution (from, to, global);
|
||||
}
|
||||
|
||||
// Command.
|
||||
else if (command == "")
|
||||
{
|
||||
if (foundSequence)
|
||||
foundSomethingAfterSequence = true;
|
||||
|
||||
std::string l = lowerCase (arg);
|
||||
if (isCommand (l) && validCommand (l))
|
||||
command = l;
|
||||
else
|
||||
{
|
||||
if (descCandidate.length ())
|
||||
descCandidate += " ";
|
||||
descCandidate += arg;
|
||||
}
|
||||
}
|
||||
|
||||
// Anything else is just considered description.
|
||||
else
|
||||
{
|
||||
if (foundSequence)
|
||||
foundSomethingAfterSequence = true;
|
||||
|
||||
if (descCandidate.length ())
|
||||
descCandidate += " ";
|
||||
descCandidate += arg;
|
||||
}
|
||||
}
|
||||
// terminated, therefore everything subsequently is a description.
|
||||
else
|
||||
{
|
||||
if (foundSequence)
|
||||
foundSomethingAfterSequence = true;
|
||||
|
||||
if (descCandidate.length ())
|
||||
descCandidate += " ";
|
||||
descCandidate += arg;
|
||||
}
|
||||
}
|
||||
|
||||
if (validDescription (descCandidate))
|
||||
task.setDescription (descCandidate);
|
||||
}
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void validReportColumns (const std::vector <std::string>& columns)
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue