Bug Fix - custom report filters

- Added support for using parent in a filter.
- Fixed bug that ignored custom report filters.
- Made Context::parse and Context::autoFilter reentrant.
This commit is contained in:
Paul Beckingham 2009-06-18 01:41:15 -04:00
parent 4d43b77441
commit b932d9b9b7
4 changed files with 67 additions and 28 deletions

View file

@ -42,6 +42,8 @@ static const char* internalNames[] =
"entry",
"start",
"end",
"parent",
"uuid",
"mask",
"imask",
"limit",
@ -378,8 +380,16 @@ bool Att::validNameValue (
"\" is not a valid status. Use 'pending', 'completed', 'deleted' or 'recurring'.";
}
else if (name == "parent")
{
}
else if (name == "uuid")
{
}
else
throw std::string ("'") + name + "' is an unrecognized attribute.";
throw std::string ("'") + name + "' is not a recognized attribute.";
return true;
}

View file

@ -339,6 +339,18 @@ void Context::loadCorrectConfigFile ()
////////////////////////////////////////////////////////////////////////////////
void Context::parse ()
{
parse (args, cmd, task, sequence, subst, filter);
}
////////////////////////////////////////////////////////////////////////////////
void Context::parse (
std::vector <std::string>& parseArgs,
Cmd& parseCmd,
Task& parseTask,
Sequence& parseSequence,
Subst& parseSubst,
Filter& parseFilter)
{
Att attribute;
tagAdditions.clear ();
@ -348,7 +360,7 @@ void Context::parse ()
bool foundSequence = false;
bool foundSomethingAfterSequence = false;
foreach (arg, args)
foreach (arg, parseArgs)
{
if (!terminated)
{
@ -361,12 +373,12 @@ void Context::parse ()
// Sequence
// Note: "add" doesn't require an ID
else if (cmd.command != "add" &&
else if (parseCmd.command != "add" &&
! foundSomethingAfterSequence &&
sequence.valid (*arg))
parseSequence.valid (*arg))
{
header ("parse sequence '" + *arg + "'");
sequence.parse (*arg);
parseSequence.parse (*arg);
foundSequence = true;
}
@ -379,8 +391,12 @@ void Context::parse ()
if (foundSequence)
foundSomethingAfterSequence = true;
if (arg->find (',') != std::string::npos)
throw stringtable.get (TAGS_NO_COMMA,
"Tags are not permitted to contain commas.");
tagAdditions.push_back (arg->substr (1, std::string::npos));
task.addTag (arg->substr (1, std::string::npos));
parseTask.addTag (arg->substr (1, std::string::npos));
}
// Tags to remove begin with '-'.
@ -417,25 +433,25 @@ void Context::parse ()
attribute.mod (mod);
attribute.value (value);
task[attribute.name ()] = attribute;
parseTask[attribute.name ()] = attribute;
}
// Substitution of description and/or annotation text.
else if (subst.valid (*arg))
else if (parseSubst.valid (*arg))
{
if (foundSequence)
foundSomethingAfterSequence = true;
header ("parse subst '" + *arg + "'");
subst.parse (*arg);
parseSubst.parse (*arg);
}
// It might be a command if one has not already been found.
else if (cmd.command == "" &&
cmd.valid (*arg))
else if (parseCmd.command == "" &&
parseCmd.valid (*arg))
{
header ("parse cmd '" + *arg + "'");
cmd.parse (*arg);
parseCmd.parse (*arg);
if (foundSequence)
foundSomethingAfterSequence = true;
@ -469,26 +485,26 @@ void Context::parse ()
if (descCandidate != "" && noVerticalSpace (descCandidate))
{
header ("parse description '" + descCandidate + "'");
task.set ("description", descCandidate);
parseTask.set ("description", descCandidate);
}
// TODO task.validate () ?
// Read-only command (reports, status, info ...) use filters. Write commands
// (add, done ...) do not.
if (cmd.isReadOnlyCommand ())
autoFilter ();
if (parseCmd.isReadOnlyCommand ())
autoFilter (parseTask, parseFilter);
// If no command was specified, and there were no command line arguments
// then invoke the default command.
if (cmd.command == "" && args.size () == 0)
if (parseCmd.command == "" && parseArgs.size () == 0)
{
std::string defaultCommand = config.get ("default.command");
if (defaultCommand != "")
{
// Stuff the command line.
args.clear ();
split (args, defaultCommand, ' ');
parseArgs.clear ();
split (parseArgs, defaultCommand, ' ');
header ("[task " + defaultCommand + "]");
// Reinitialize the context and recurse.
@ -500,9 +516,9 @@ void Context::parse ()
////////////////////////////////////////////////////////////////////////////////
// Add all the attributes in the task to the filter. All except uuid.
void Context::autoFilter ()
void Context::autoFilter (Task& t, Filter& f)
{
foreach (att, task)
foreach (att, t)
{
// Words are found in the description using the .has modifier.
if (att->first == "description")
@ -511,7 +527,7 @@ void Context::autoFilter ()
split (words, att->second.value (), ' ');
foreach (word, words)
{
filter.push_back (Att ("description", "has", *word));
f.push_back (Att ("description", "has", *word));
header ("auto filter: " + att->first + ".has:" + *word);
}
}
@ -519,7 +535,7 @@ void Context::autoFilter ()
// Projects are matched left-most.
else if (att->first == "project")
{
filter.push_back (Att ("project", "startswith", att->second.value ()));
f.push_back (Att ("project", "startswith", att->second.value ()));
header ("auto filter: " + att->first + ".startswith:" + att->second.value ());
}
@ -529,7 +545,7 @@ void Context::autoFilter ()
else if (att->first != "uuid" &&
att->first != "tags")
{
filter.push_back (att->second);
f.push_back (att->second);
header ("auto filter: " + att->first + ":" + att->second.value ());
}
}
@ -537,14 +553,14 @@ void Context::autoFilter ()
// Include tagAdditions.
foreach (tag, tagAdditions)
{
filter.push_back (Att ("tags", "has", *tag));
f.push_back (Att ("tags", "has", *tag));
header ("auto filter: +" + *tag);
}
// Include tagRemovals.
foreach (tag, tagRemovals)
{
filter.push_back (Att ("tags", "hasnt", *tag));
f.push_back (Att ("tags", "hasnt", *tag));
header ("auto filter: -" + *tag);
}
}

View file

@ -58,10 +58,11 @@ public:
void clearMessages ();
void parse ();
void parse (std::vector <std::string>&, Cmd&, Task&, Sequence&, Subst&, Filter&);
private:
void loadCorrectConfigFile ();
void autoFilter ();
void autoFilter (Task&, Filter&);
public:
Config config;

View file

@ -72,7 +72,7 @@ std::string handleCustomReport (const std::string& report)
for (unsigned int i = 0; i < columns.size (); ++i)
columnLabels[columns[i]] = labels[i];
std::string sortList = context.config.get ("report." + report + ".sort");
std::string sortList = context.config.get ("report." + report + ".sort");
std::vector <std::string> sortOrder;
split (sortOrder, sortList, ',');
validSortColumns (columns, sortOrder);
@ -80,11 +80,23 @@ std::string handleCustomReport (const std::string& report)
std::string filterList = context.config.get ("report." + report + ".filter");
std::vector <std::string> filterArgs;
split (filterArgs, filterList, ' ');
{
Cmd cmd (report);
Task task;
Sequence sequence;
Subst subst;
Filter filter;
context.parse (filterArgs, cmd, task, sequence, subst, filter);
context.sequence.combine (sequence);
foreach (att, filter)
context.filter.push_back (*att);
}
// Get all the tasks.
std::vector <Task> tasks;
context.tdb.lock (context.config.get ("locking", true));
// TODO Include filter from custom report.
context.tdb.load (tasks, context.filter);
handleRecurrence (tasks);
context.tdb.commit ();