mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-07-07 20:06:36 +02:00
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:
parent
4d43b77441
commit
b932d9b9b7
4 changed files with 67 additions and 28 deletions
12
src/Att.cpp
12
src/Att.cpp
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 ();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue