mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-07-07 20:06:36 +02:00
Enhancements - filters
- The project attribute is now automatically filtered with project.startswith:<value> to provide leftmost matching (ie subprojects). - Unmodifiable attributes (uuid, start ...) are now prevented from being updated if the command is designated as a "write" command.
This commit is contained in:
parent
5691ed0588
commit
97d732e5f7
2 changed files with 42 additions and 30 deletions
50
src/Att.cpp
50
src/Att.cpp
|
@ -44,7 +44,7 @@ static const char* internalNames[] =
|
||||||
"end",
|
"end",
|
||||||
"mask",
|
"mask",
|
||||||
"imask",
|
"imask",
|
||||||
// "limit",
|
"limit",
|
||||||
"status",
|
"status",
|
||||||
"description",
|
"description",
|
||||||
};
|
};
|
||||||
|
@ -200,7 +200,6 @@ bool Att::validName (const std::string& name)
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// TODO Obsolete
|
|
||||||
bool Att::validModifiableName (const std::string& name)
|
bool Att::validModifiableName (const std::string& name)
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < NUM_MODIFIABLE_NAMES; ++i)
|
for (unsigned int i = 0; i < NUM_MODIFIABLE_NAMES; ++i)
|
||||||
|
@ -294,6 +293,14 @@ bool Att::validNameValue (
|
||||||
mod = matches[0];
|
mod = matches[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Some attributes are intended to be private, unless the command is read-
|
||||||
|
// only, in which cased these are perfectly valid elements of a filter.
|
||||||
|
if (context.cmd.isWriteCommand () &&
|
||||||
|
!validModifiableName (name))
|
||||||
|
throw std::string ("\"") +
|
||||||
|
name +
|
||||||
|
"\" is not an attribute you may modify directly.";
|
||||||
|
|
||||||
// Thirdly, make sure the value has the expected form or values.
|
// Thirdly, make sure the value has the expected form or values.
|
||||||
if (name == "project")
|
if (name == "project")
|
||||||
{
|
{
|
||||||
|
@ -333,13 +340,8 @@ bool Att::validNameValue (
|
||||||
Text::guessColor (value);
|
Text::guessColor (value);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (name == "due")
|
else if (name == "due" ||
|
||||||
{
|
name == "until")
|
||||||
if (value != "")
|
|
||||||
Date (value);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (name == "until")
|
|
||||||
{
|
{
|
||||||
if (value != "")
|
if (value != "")
|
||||||
Date (value);
|
Date (value);
|
||||||
|
@ -351,28 +353,30 @@ bool Att::validNameValue (
|
||||||
Duration (value);
|
Duration (value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Not ready for prime time.
|
|
||||||
else if (name == "limit")
|
else if (name == "limit")
|
||||||
{
|
{
|
||||||
if (value == "" || !digitsOnly (value))
|
if (value == "" || !digitsOnly (value))
|
||||||
throw std::string ("The '") + name + "' attribute must be an integer.";
|
throw std::string ("The '") + name + "' attribute must be an integer.";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some attributes are intended to be private, unless the command is read-
|
else if (name == "status")
|
||||||
// only, in which cased these are perfectly valid elements of a filter.
|
|
||||||
else if (name == "entry" ||
|
|
||||||
name == "start" ||
|
|
||||||
name == "end" ||
|
|
||||||
name == "mask" ||
|
|
||||||
name == "imask" ||
|
|
||||||
name == "uuid" ||
|
|
||||||
name == "status" ||
|
|
||||||
name == "description")
|
|
||||||
{
|
{
|
||||||
if (context.cmd.isWriteCommand ())
|
value = lowerCase (value);
|
||||||
|
|
||||||
|
std::vector <std::string> matches;
|
||||||
|
std::vector <std::string> candidates;
|
||||||
|
candidates.push_back ("pending");
|
||||||
|
candidates.push_back ("completed");
|
||||||
|
candidates.push_back ("deleted");
|
||||||
|
candidates.push_back ("recurring");
|
||||||
|
autoComplete (value, candidates, matches);
|
||||||
|
|
||||||
|
if (matches.size () == 1)
|
||||||
|
value = matches[0];
|
||||||
|
else
|
||||||
throw std::string ("\"") +
|
throw std::string ("\"") +
|
||||||
name +
|
value +
|
||||||
"\" is not an attribute you may modify directly.";
|
"\" is not a valid status. Use 'pending', 'completed', 'deleted' or 'recurring'.";
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
|
@ -494,7 +494,7 @@ void Context::constructFilter ()
|
||||||
{
|
{
|
||||||
foreach (att, task)
|
foreach (att, task)
|
||||||
{
|
{
|
||||||
// TODO this doesn't work.
|
// Words are found in the description using the .has modifier.
|
||||||
if (att->first == "description")
|
if (att->first == "description")
|
||||||
{
|
{
|
||||||
std::vector <std::string> words;
|
std::vector <std::string> words;
|
||||||
|
@ -502,19 +502,27 @@ void Context::constructFilter ()
|
||||||
foreach (word, words)
|
foreach (word, words)
|
||||||
{
|
{
|
||||||
filter.push_back (Att ("description", "has", *word));
|
filter.push_back (Att ("description", "has", *word));
|
||||||
std::cout << "Context::constructFilter " << att->first << "=" << *word << std::endl;
|
std::cout << "[1;31m# auto filter: " << att->first << ".has:" << *word << "[0m" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Projects are matched left-most.
|
||||||
|
else if (att->first == "project")
|
||||||
|
{
|
||||||
|
filter.push_back (Att ("project", "startswith", att->second.value ()));
|
||||||
|
std::cout << "[1;31m# auto filter: " << att->first << ".startswith:" << att->second.value () << "[0m" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO Don't create a uuid for every task?
|
// TODO Don't create a uuid for every task?
|
||||||
// Every task has a unique uuid by default, and it shouldn't be included.
|
// Every task has a unique uuid by default, and it shouldn't be included.
|
||||||
// The mechanism for filtering on tags is +/-<tag>, not tags:foo which
|
// The mechanism for filtering on tags is +/-<tag>, not tags:foo which
|
||||||
// means that there can only be one tag, "foo".
|
// means that there can only be one tag, "foo".
|
||||||
else if (att->first != "uuid" &&
|
else if (att->first != "uuid" &&
|
||||||
att->first != "tags")
|
att->first != "tags" &&
|
||||||
|
att->first != "project")
|
||||||
{
|
{
|
||||||
filter.push_back (att->second);
|
filter.push_back (att->second);
|
||||||
std::cout << "Context::constructFilter " << att->first << "=" << att->second.value () << std::endl;
|
std::cout << "[1;31m# auto filter: " << att->first << ":" << att->second.value () << "[0m" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -524,14 +532,14 @@ void Context::constructFilter ()
|
||||||
foreach (tag, tagAdditions)
|
foreach (tag, tagAdditions)
|
||||||
{
|
{
|
||||||
filter.push_back (Att ("tags", "has", *tag));
|
filter.push_back (Att ("tags", "has", *tag));
|
||||||
std::cout << "Context::constructFilter tags=+" << *tag << std::endl;
|
std::cout << "[1;31m# auto filter: +" << *tag << "[0m" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Include tagRemovals.
|
// Include tagRemovals.
|
||||||
foreach (tag, tagRemovals)
|
foreach (tag, tagRemovals)
|
||||||
{
|
{
|
||||||
filter.push_back (Att ("tags", "hasnt", *tag));
|
filter.push_back (Att ("tags", "hasnt", *tag));
|
||||||
std::cout << "Context::constructFilter tags=-" << *tag << std::endl;
|
std::cout << "[1;31m# auto filter: -" << *tag << "[0m" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue