diff --git a/ChangeLog b/ChangeLog index fe8c25e35..90a15587c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -56,8 +56,8 @@ their descriptions. # Tracked Bugs, sorted by ID. - + Fixed bug #475, which allowed a blank annotation command to be entered (thanks - to Andreas Kalex). + + Fixed bug #475, which allowed a blank annotation command to be entered + (thanks to Andreas Kalex). + Fixed bug #511, which caused display problem on Cygwin when colored output used the full width of the terminal. The 'avoidlastcolumn' configuration variable forces taskwarrior to never use the last column. diff --git a/src/Arguments.cpp b/src/Arguments.cpp index 006dfde7b..0b6e00334 100644 --- a/src/Arguments.cpp +++ b/src/Arguments.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -107,6 +108,8 @@ static struct #define NUM_MODIFIER_NAMES (sizeof (modifierNames) / sizeof (modifierNames[0])) #define NUM_OPERATORS (sizeof (operators) / sizeof (operators[0])) +static const char* non_word_chars = " +-*/%()=<>!~"; + //////////////////////////////////////////////////////////////////////////////// Arguments::Arguments () { @@ -603,6 +606,9 @@ bool Arguments::is_attr (const std::string& input) if (name.length () == 0) return false; + if (name.find_first_of (non_word_chars) != std::string::npos) + return false; + if (n.skip (':') || n.skip ('=')) { @@ -642,6 +648,9 @@ bool Arguments::is_attmod (const std::string& input) if (name.length () == 0) return false; + if (name.find_first_of (non_word_chars) != std::string::npos) + return false; + if (n.skip ('.')) { n.skip ('~'); @@ -820,8 +829,14 @@ bool Arguments::is_operator ( //////////////////////////////////////////////////////////////////////////////// bool Arguments::is_expression (const std::string& input) { + Lexer lexer (unquoteText (input)); + lexer.skipWhitespace (true); + lexer.coalesceAlpha (true); + lexer.coalesceDigits (true); + lexer.coalesceQuoted (true); + std::vector tokens; - splitq (tokens, input, ' '); + lexer.tokenize (tokens); std::vector ::iterator token; for (token = tokens.begin (); token != tokens.end (); ++token) diff --git a/src/commands/CmdCustom.cpp b/src/commands/CmdCustom.cpp index beaec7118..76c314314 100644 --- a/src/commands/CmdCustom.cpp +++ b/src/commands/CmdCustom.cpp @@ -25,6 +25,7 @@ // //////////////////////////////////////////////////////////////////////////////// +#include #include #include #include @@ -96,14 +97,16 @@ int CmdCustom::execute (std::string& output) Arguments f = context.args.extract_read_only_filter (); Expression e (f); -return 0; - std::vector filtered; std::vector ::iterator task; for (task = tasks.begin (); task != tasks.end (); ++task) if (e.eval (*task)) filtered.push_back (*task); + std::cout << "# tasks=" << tasks.size () << "\n" + << "# filtered=" << filtered.size () << "\n"; +return 0; + //////////////////////////////////// // Sort the tasks. diff --git a/test/arguments.t.cpp b/test/arguments.t.cpp index 4dfcce0a5..53d228107 100644 --- a/test/arguments.t.cpp +++ b/test/arguments.t.cpp @@ -34,7 +34,7 @@ Context context; //////////////////////////////////////////////////////////////////////////////// int main (int argc, char** argv) { - UnitTest t (109); + UnitTest t (113); const char* fake[] = { @@ -66,58 +66,64 @@ int main (int argc, char** argv) "combine good"); // bool is_attr (const std::string&); - t.ok (Arguments::is_attr ("name:"), "name: -> attr"); - t.ok (Arguments::is_attr ("name:\"\""), "name:\"\" -> attr"); - t.ok (Arguments::is_attr ("name:one"), "name:one -> attr"); - t.ok (Arguments::is_attr ("name:\"one\""), "name:\"one\" -> attr"); - t.ok (Arguments::is_attr ("name:\"one two\""), "name:\"one two\" -> attr"); + t.ok (Arguments::is_attr ("name:"), "name: -> attr"); + t.ok (Arguments::is_attr ("name:\"\""), "name:\"\" -> attr"); + t.ok (Arguments::is_attr ("name:one"), "name:one -> attr"); + t.ok (Arguments::is_attr ("name:\"one\""), "name:\"one\" -> attr"); + t.ok (Arguments::is_attr ("name:\"one two\""), "name:\"one two\" -> attr"); - t.ok (Arguments::is_attr ("name="), "name= -> attr"); - t.ok (Arguments::is_attr ("name=\"\""), "name=\"\" -> attr"); - t.ok (Arguments::is_attr ("name=one"), "name=one -> attr"); - t.ok (Arguments::is_attr ("name=\"one\""), "name=\"one\" -> attr"); - t.ok (Arguments::is_attr ("name=\"one two\""), "name=\"one two\" -> attr"); + t.ok (Arguments::is_attr ("name="), "name= -> attr"); + t.ok (Arguments::is_attr ("name=\"\""), "name=\"\" -> attr"); + t.ok (Arguments::is_attr ("name=one"), "name=one -> attr"); + t.ok (Arguments::is_attr ("name=\"one\""), "name=\"one\" -> attr"); + t.ok (Arguments::is_attr ("name=\"one two\""), "name=\"one two\" -> attr"); + + t.notok (Arguments::is_attr ("name"), "name -> not attr"); + t.notok (Arguments::is_attr ("(name=val and 1<2)"), "(name=val and 1<2) -> not attr"); // bool is_attmod (const std::string&); - t.ok (Arguments::is_attmod ("name.is:"), "name.is: -> attr"); - t.ok (Arguments::is_attmod ("name.is:\"\""), "name.is:\"\" -> attr"); - t.ok (Arguments::is_attmod ("name.is:one"), "name.is:one -> attr"); - t.ok (Arguments::is_attmod ("name.is:\"one\""), "name.is:\"one\" -> attr"); - t.ok (Arguments::is_attmod ("name.is:\"one two\""), "name.is:\"one two\" -> attr"); + t.ok (Arguments::is_attmod ("name.is:"), "name.is: -> attmod"); + t.ok (Arguments::is_attmod ("name.is:\"\""), "name.is:\"\" -> attmod"); + t.ok (Arguments::is_attmod ("name.is:one"), "name.is:one -> attmod"); + t.ok (Arguments::is_attmod ("name.is:\"one\""), "name.is:\"one\" -> attmod"); + t.ok (Arguments::is_attmod ("name.is:\"one two\""), "name.is:\"one two\" -> attmod"); - t.ok (Arguments::is_attmod ("name.is="), "name.is= -> attr"); - t.ok (Arguments::is_attmod ("name.is=\"\""), "name.is=\"\" -> attr"); - t.ok (Arguments::is_attmod ("name.is=one"), "name.is=one -> attr"); - t.ok (Arguments::is_attmod ("name.is=\"one\""), "name.is=\"one\" -> attr"); - t.ok (Arguments::is_attmod ("name.is=\"one two\""), "name.is=\"one two\" -> attr"); + t.ok (Arguments::is_attmod ("name.is="), "name.is= -> attmod"); + t.ok (Arguments::is_attmod ("name.is=\"\""), "name.is=\"\" -> attmod"); + t.ok (Arguments::is_attmod ("name.is=one"), "name.is=one -> attmod"); + t.ok (Arguments::is_attmod ("name.is=\"one\""), "name.is=\"one\" -> attmod"); + t.ok (Arguments::is_attmod ("name.is=\"one two\""), "name.is=\"one two\" -> attmod"); + + t.notok (Arguments::is_attmod ("name"), "name -> not attmod"); + t.notok (Arguments::is_attmod ("(name=value and 1<2"), "(name=value and 1<2 -> not attmod"); // bool is_subst (const std::string&); - t.notok (Arguments::is_subst ("///"), "/// -> not subst"); - t.notok (Arguments::is_subst ("//to/"), "//to/ -> not subst"); - t.ok (Arguments::is_subst ("/from//"), "/from// -> subst"); - t.ok (Arguments::is_subst ("/from/to/"), "/from/to/ -> subst"); - t.ok (Arguments::is_subst ("/from from/to to/"), "/from from/to to/ -> subst"); + t.notok (Arguments::is_subst ("///"), "/// -> not subst"); + t.notok (Arguments::is_subst ("//to/"), "//to/ -> not subst"); + t.ok (Arguments::is_subst ("/from//"), "/from// -> subst"); + t.ok (Arguments::is_subst ("/from/to/"), "/from/to/ -> subst"); + t.ok (Arguments::is_subst ("/from from/to to/"), "/from from/to to/ -> subst"); - t.notok (Arguments::is_subst ("///g"), "///g -> not subst"); - t.notok (Arguments::is_subst ("//to/g"), "//to/g -> not subst"); - t.ok (Arguments::is_subst ("/from//g"), "/from//g -> subst"); - t.ok (Arguments::is_subst ("/from/to/g"), "/from/to/g -> subst"); - t.ok (Arguments::is_subst ("/from from/to to/g"), "/from from/to to/g -> subst"); + t.notok (Arguments::is_subst ("///g"), "///g -> not subst"); + t.notok (Arguments::is_subst ("//to/g"), "//to/g -> not subst"); + t.ok (Arguments::is_subst ("/from//g"), "/from//g -> subst"); + t.ok (Arguments::is_subst ("/from/to/g"), "/from/to/g -> subst"); + t.ok (Arguments::is_subst ("/from from/to to/g"), "/from from/to to/g -> subst"); // bool is_pattern (const std::string&); - t.notok (Arguments::is_pattern ("//"), "// -> not pattern"); - t.notok (Arguments::is_pattern ("///"), "/// -> not pattern"); - t.ok (Arguments::is_pattern ("/one/"), "/one/ -> pattern"); - t.ok (Arguments::is_pattern ("/one two/"), "/one two/ -> pattern"); - t.ok (Arguments::is_pattern ("/ /"), "/ / -> pattern"); + t.notok (Arguments::is_pattern ("//"), "// -> not pattern"); + t.notok (Arguments::is_pattern ("///"), "/// -> not pattern"); + t.ok (Arguments::is_pattern ("/one/"), "/one/ -> pattern"); + t.ok (Arguments::is_pattern ("/one two/"), "/one two/ -> pattern"); + t.ok (Arguments::is_pattern ("/ /"), "/ / -> pattern"); // bool is_id (const std::string&); - t.ok (Arguments::is_id ("1"), "1 -> id"); - t.ok (Arguments::is_id ("1,2"), "1,2 -> id"); - t.ok (Arguments::is_id ("1-2"), "1-2 -> id"); - t.ok (Arguments::is_id ("1,2,3"), "1,2,3 -> id"); - t.ok (Arguments::is_id ("1-2,3,4-5"), "1-2,3,4-5 -> id"); - t.notok (Arguments::is_id ("1-2-3"), "1-2-3 -> no id"); + t.ok (Arguments::is_id ("1"), "1 -> id"); + t.ok (Arguments::is_id ("1,2"), "1,2 -> id"); + t.ok (Arguments::is_id ("1-2"), "1-2 -> id"); + t.ok (Arguments::is_id ("1,2,3"), "1,2,3 -> id"); + t.ok (Arguments::is_id ("1-2,3,4-5"), "1-2,3,4-5 -> id"); + t.notok (Arguments::is_id ("1-2-3"), "1-2-3 -> no id"); // bool is_uuid (const std::string&); t.ok (Arguments::is_uuid ("00000000-0000-0000-0000-000000000000"), @@ -126,15 +132,15 @@ int main (int argc, char** argv) "eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee,ffffffff-ffff-ffff-ffff-ffffffffffff -> uuid"); // bool is_tag (const std::string&); - t.ok (Arguments::is_tag ("+one"), "+one -> tag"); - t.ok (Arguments::is_tag ("-one"), "-one -> tag"); - t.notok (Arguments::is_tag ("+one "), "+one -> not tag"); - t.notok (Arguments::is_tag ("-one "), "-one -> not tag"); - t.notok (Arguments::is_tag ("+"), "+ -> not tag"); - t.notok (Arguments::is_tag ("-"), "- -> not tag"); - t.notok (Arguments::is_tag ("++"), "++ -> not tag"); - t.notok (Arguments::is_tag ("--"), "-- -> not tag"); - t.notok (Arguments::is_tag ("+one two"), "+one two -> not tag"); + t.ok (Arguments::is_tag ("+one"), "+one -> tag"); + t.ok (Arguments::is_tag ("-one"), "-one -> tag"); + t.notok (Arguments::is_tag ("+one "), "+one -> not tag"); + t.notok (Arguments::is_tag ("-one "), "-one -> not tag"); + t.notok (Arguments::is_tag ("+"), "+ -> not tag"); + t.notok (Arguments::is_tag ("-"), "- -> not tag"); + t.notok (Arguments::is_tag ("++"), "++ -> not tag"); + t.notok (Arguments::is_tag ("--"), "-- -> not tag"); + t.notok (Arguments::is_tag ("+one two"), "+one two -> not tag"); // bool is_operator (const std::string&); t.ok (Arguments::is_operator ("^"), "^ -> operator");