mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-07-07 20:06:36 +02:00
Enhancement - all attribute modifiers working
- Implemented before, below, under, after, above, over.
This commit is contained in:
parent
3bed6bb573
commit
cbecec263a
5 changed files with 97 additions and 28 deletions
75
src/Att.cpp
75
src/Att.cpp
|
@ -70,12 +70,12 @@ static const char* modifierNames[] =
|
||||||
"after", "over", "above",
|
"after", "over", "above",
|
||||||
"none",
|
"none",
|
||||||
"any",
|
"any",
|
||||||
"is",
|
"is", "equals",
|
||||||
"isnt", "not",
|
"isnt", "not",
|
||||||
"has", "contains",
|
"has", "contains",
|
||||||
"hasnt",
|
"hasnt",
|
||||||
"startswith",
|
"startswith", "left",
|
||||||
"endswith",
|
"endswith", "right",
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NUM_INTERNAL_NAMES (sizeof (internalNames) / sizeof (internalNames[0]))
|
#define NUM_INTERNAL_NAMES (sizeof (internalNames) / sizeof (internalNames[0]))
|
||||||
|
@ -385,7 +385,7 @@ bool Att::validMod (const std::string& mod)
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// The type of an attribute is useful for modifier evaluation.
|
// The type of an attribute is useful for modifier evaluation.
|
||||||
std::string type (const std::string& name)
|
std::string Att::type (const std::string& name) const
|
||||||
{
|
{
|
||||||
if (name == "due" ||
|
if (name == "due" ||
|
||||||
name == "until" ||
|
name == "until" ||
|
||||||
|
@ -468,14 +468,17 @@ void Att::parse (Nibbler& n)
|
||||||
// Record that does not have modifiers, but may have a value.
|
// Record that does not have modifiers, but may have a value.
|
||||||
bool Att::match (const Att& other) const
|
bool Att::match (const Att& other) const
|
||||||
{
|
{
|
||||||
// If there are no mods, just perform a straight compare on value.
|
// All matches are assumed to pass, any short-circuit on non-match.
|
||||||
if (mMod == "" && mValue != other.mValue)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Assume a match, and short-circuit on mismatch.
|
// If there are no mods, just perform a straight compare on value.
|
||||||
|
if (mMod == "")
|
||||||
|
{
|
||||||
|
if (mValue != other.mValue)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// is = equal. Nop.
|
// is = equal. Nop.
|
||||||
else if (mMod == "is") // TODO i18n
|
else if (mMod == "is" || mMod == "equals") // TODO i18n
|
||||||
{
|
{
|
||||||
if (mValue != other.mValue)
|
if (mValue != other.mValue)
|
||||||
return false;
|
return false;
|
||||||
|
@ -503,7 +506,7 @@ bool Att::match (const Att& other) const
|
||||||
}
|
}
|
||||||
|
|
||||||
// startswith = first characters must match.
|
// startswith = first characters must match.
|
||||||
else if (mMod == "startswith") // TODO i18n
|
else if (mMod == "startswith" || mMod == "left") // TODO i18n
|
||||||
{
|
{
|
||||||
if (other.mValue.length () < mValue.length ())
|
if (other.mValue.length () < mValue.length ())
|
||||||
return false;
|
return false;
|
||||||
|
@ -513,7 +516,7 @@ bool Att::match (const Att& other) const
|
||||||
}
|
}
|
||||||
|
|
||||||
// endswith = last characters must match.
|
// endswith = last characters must match.
|
||||||
else if (mMod == "endswith") // TODO i18n
|
else if (mMod == "endswith" || mMod == "right") // TODO i18n
|
||||||
{
|
{
|
||||||
if (other.mValue.length () < mValue.length ())
|
if (other.mValue.length () < mValue.length ())
|
||||||
return false;
|
return false;
|
||||||
|
@ -541,16 +544,62 @@ bool Att::match (const Att& other) const
|
||||||
// before = under = below = <
|
// before = under = below = <
|
||||||
else if (mMod == "before" || mMod == "under" || mMod == "below")
|
else if (mMod == "before" || mMod == "under" || mMod == "below")
|
||||||
{
|
{
|
||||||
// TODO Typed compare
|
std::string which = type (mName);
|
||||||
|
if (which == "duration")
|
||||||
|
{
|
||||||
|
Duration literal (mValue);
|
||||||
|
Duration variable ((time_t)::atoi (other.mValue.c_str ()));
|
||||||
|
if (!(variable < literal))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
else if (which == "date")
|
||||||
|
{
|
||||||
|
Date literal (mValue);
|
||||||
|
Date variable ((time_t)::atoi (other.mValue.c_str ()));
|
||||||
|
if (! (variable < literal))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (which == "number")
|
||||||
|
{
|
||||||
|
if (::atoi (mValue.c_str ()) >= ::atoi (other.mValue.c_str ()))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (which == "text")
|
||||||
|
{
|
||||||
|
if (::strcmp (mValue.c_str (), other.mValue.c_str ()) <= 0)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// after = over = above = >
|
// after = over = above = >
|
||||||
else if (mMod == "after" || mMod == "over" || mMod == "above")
|
else if (mMod == "after" || mMod == "over" || mMod == "above")
|
||||||
{
|
{
|
||||||
// TODO Typed compare
|
std::string which = type (mName);
|
||||||
|
if (which == "duration")
|
||||||
|
{
|
||||||
|
Duration literal (mValue);
|
||||||
|
Duration variable ((time_t)::atoi (other.mValue.c_str ()));
|
||||||
|
if (! (variable > literal))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
else if (which == "date")
|
||||||
|
{
|
||||||
|
Date literal (mValue);
|
||||||
|
Date variable ((time_t)::atoi (other.mValue.c_str ()));
|
||||||
|
if (! (variable > literal))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (which == "number")
|
||||||
|
{
|
||||||
|
if (::atoi (mValue.c_str ()) <= ::atoi (other.mValue.c_str ()))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (which == "text")
|
||||||
|
{
|
||||||
|
if (::strcmp (mValue.c_str (), other.mValue.c_str ()) >= 0)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ public:
|
||||||
static bool validNameValue (const std::string&, const std::string&, const std::string&);
|
static bool validNameValue (const std::string&, const std::string&, const std::string&);
|
||||||
static bool validNameValue (std::string&, std::string&, std::string&);
|
static bool validNameValue (std::string&, std::string&, std::string&);
|
||||||
static bool validMod (const std::string&);
|
static bool validMod (const std::string&);
|
||||||
static std::string type (const std::string&);
|
std::string type (const std::string&) const;
|
||||||
void parse (const std::string&);
|
void parse (const std::string&);
|
||||||
void parse (Nibbler&);
|
void parse (Nibbler&);
|
||||||
bool match (const Att&) const;
|
bool match (const Att&) const;
|
||||||
|
|
|
@ -540,7 +540,7 @@ void Context::autoFilter (Task& t, Filter& f)
|
||||||
foreach (att, t)
|
foreach (att, t)
|
||||||
{
|
{
|
||||||
// Words are found in the description using the .has modifier.
|
// Words are found in the description using the .has modifier.
|
||||||
if (att->first == "description")
|
if (att->first == "description" && att->second.mod () == "")
|
||||||
{
|
{
|
||||||
std::vector <std::string> words;
|
std::vector <std::string> words;
|
||||||
split (words, att->second.value (), ' ');
|
split (words, att->second.value (), ' ');
|
||||||
|
@ -552,7 +552,7 @@ void Context::autoFilter (Task& t, Filter& f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Projects are matched left-most.
|
// Projects are matched left-most.
|
||||||
else if (att->first == "project")
|
else if (att->first == "project" && att->second.mod () == "")
|
||||||
{
|
{
|
||||||
f.push_back (Att ("project", "startswith", att->second.value ()));
|
f.push_back (Att ("project", "startswith", att->second.value ()));
|
||||||
debug ("auto filter: " + att->first + ".startswith:" + att->second.value ());
|
debug ("auto filter: " + att->first + ".startswith:" + att->second.value ());
|
||||||
|
@ -564,14 +564,27 @@ void Context::autoFilter (Task& t, Filter& f)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
// because it is guaranteed to not match.
|
||||||
// means that there can only be one tag, "foo".
|
else if (att->first == "uuid")
|
||||||
else if (att->first != "uuid" &&
|
{
|
||||||
att->first != "tags")
|
}
|
||||||
|
|
||||||
|
// The mechanism for filtering on tags is +/-<tag>.
|
||||||
|
else if (att->first == "tags")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generic attribute matching.
|
||||||
|
else
|
||||||
{
|
{
|
||||||
f.push_back (att->second);
|
f.push_back (att->second);
|
||||||
debug ("auto filter: " + att->first + ":" + att->second.value ());
|
debug ("auto filter: " +
|
||||||
|
att->first +
|
||||||
|
(att->second.mod () != "" ?
|
||||||
|
("." + att->second.mod () + ":") :
|
||||||
|
":") +
|
||||||
|
att->second.value ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,12 @@ Duration::Duration ()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
Duration::Duration (time_t input)
|
||||||
|
{
|
||||||
|
mDays = input;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
Duration::Duration (const std::string& input)
|
Duration::Duration (const std::string& input)
|
||||||
{
|
{
|
||||||
|
|
|
@ -34,6 +34,7 @@ class Duration
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Duration (); // Default constructor
|
Duration (); // Default constructor
|
||||||
|
Duration (time_t); // Default constructor
|
||||||
Duration (const std::string&); // Parse
|
Duration (const std::string&); // Parse
|
||||||
bool operator< (const Duration&);
|
bool operator< (const Duration&);
|
||||||
bool operator> (const Duration&);
|
bool operator> (const Duration&);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue