mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-07-07 20:06:36 +02:00
CLI2: Handle empty parentheses expressions
Since taskwarrior is a CLI tool, it is likely that it is interacted with programmatically. As such, expressions that a human would not type, but are syntactically correct are bound to occur. In particular, task currently is not able to handle empty parentheses expressions: task +PENDING '(' ')' This is due to "and" operator being injected between +PENDING (which translates to '( status = pending )' and '('. Modify the insertJunctions to not insert the 'and' operator between two sub-expressions if one of them is an empty parentheses expression. Closes #1896.
This commit is contained in:
parent
c6fdb7e590
commit
456dfdc8cf
2 changed files with 47 additions and 4 deletions
50
src/CLI2.cpp
50
src/CLI2.cpp
|
@ -1940,6 +1940,40 @@ void CLI2::desugarFilterPlainArgs ()
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Detects if the bracket at iterator it is a start or end of an empty paren expression
|
||||
// Examples:
|
||||
// ( status = pending ) ( )
|
||||
// ^
|
||||
// it -----| => true
|
||||
//
|
||||
// ( status = pending ) ( project = Home )
|
||||
// ^
|
||||
// it -----| => false
|
||||
bool CLI2::isEmptyParenExpression (std::vector<A2>::iterator it, bool forward /* = true */) const
|
||||
{
|
||||
int open = 0;
|
||||
int closed = 0;
|
||||
|
||||
for (auto a = it; a != (forward ? _args.end (): _args.begin()); (forward ? ++a: --a))
|
||||
{
|
||||
if (a->attribute("raw") == "(")
|
||||
open++;
|
||||
else if (a->attribute("raw") == ")")
|
||||
closed++;
|
||||
else
|
||||
// Encountering a non-paren token means there is something between parenthees
|
||||
return false;
|
||||
|
||||
// Getting balanced parentheses means we have an empty paren expression
|
||||
if (open == closed && open != 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Should not end here.
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Two consecutive FILTER, non-OP arguments that are not "(" or ")" need an
|
||||
// "and" operator inserted between them.
|
||||
|
@ -1966,10 +2000,18 @@ void CLI2::insertJunctions ()
|
|||
// Insert AND between terms.
|
||||
else if (a != prev)
|
||||
{
|
||||
if ((prev->_lextype != Lexer::Type::op && a->attribute ("raw") == "(") ||
|
||||
(prev->_lextype != Lexer::Type::op && a->_lextype != Lexer::Type::op) ||
|
||||
(prev->attribute ("raw") == ")" && a->_lextype != Lexer::Type::op) ||
|
||||
(prev->attribute ("raw") == ")" && a->attribute ("raw") == "("))
|
||||
if ((prev->_lextype != Lexer::Type::op &&
|
||||
a->attribute ("raw") == "(" &&
|
||||
! isEmptyParenExpression(a, true) ) ||
|
||||
(prev->attribute ("raw") == ")" &&
|
||||
a->_lextype != Lexer::Type::op &&
|
||||
! isEmptyParenExpression(prev, false)) ||
|
||||
(prev->attribute ("raw") == ")" &&
|
||||
a->attribute ("raw") == "(" &&
|
||||
! isEmptyParenExpression(a, true) &&
|
||||
! isEmptyParenExpression(prev, false)) ||
|
||||
(prev->_lextype != Lexer::Type::op &&
|
||||
a->_lextype != Lexer::Type::op))
|
||||
{
|
||||
A2 opOr ("and", Lexer::Type::op);
|
||||
opOr.tag ("FILTER");
|
||||
|
|
|
@ -99,6 +99,7 @@ private:
|
|||
void findUUIDs ();
|
||||
void insertIDExpr ();
|
||||
void lexFilterArgs ();
|
||||
bool isEmptyParenExpression (std::vector<A2>::iterator it, bool forward = true) const;
|
||||
void desugarFilterPlainArgs ();
|
||||
void insertJunctions ();
|
||||
void defaultCommand ();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue