mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-06-26 10:54:26 +02:00
Expressions
- Support and documentation for rc.patterns, which enables/disables support for /pattern/ command line arguments. - Support and documentation for rc.expressions, which enables/disables support for command line expressions. - Now canonicalizes attribute names. - Now canonicalizes modifier names. - New colorization (temporary) that colors all Arguments::dump output green when processed. - New distinction between 'old' and 'new' style command lines. Old style is "pro:A +foo pri.not:M" with implicit "and" operators. New style includes operators but does not include "+foo" and "/foo/". - Many tokens are converted directly to primitive types (int, number, string) when no further processing is required. - Restored CmdShow to functionality, and linearized the list of supported configuration variables, for easier insertion. - Modified arguments.t.cpp unit tests.
This commit is contained in:
parent
94fa671522
commit
c8d9a2a268
8 changed files with 462 additions and 157 deletions
|
@ -299,6 +299,16 @@ among users that are not comfortable with regular expressions.
|
|||
.B xterm.title=no
|
||||
Sets the xterm window title when reports are run. Defaults to off.
|
||||
|
||||
.TP
|
||||
.B patterns=on
|
||||
Enables or disables pattern support on the command line, such as /foo/.
|
||||
Defaults to on.
|
||||
|
||||
.TP
|
||||
.B expressions=on
|
||||
Enables or disables algebraic expression support on the command line, such as
|
||||
"due<eom and (pri=H or pri=M)". Defaults to on.
|
||||
|
||||
.TP
|
||||
.B _forcecolor=no
|
||||
Taskwarrior shuts off color automatically when the output is not sent directly
|
||||
|
|
|
@ -41,6 +41,36 @@
|
|||
|
||||
extern Context context;
|
||||
|
||||
static const char* attributeNames[] =
|
||||
{
|
||||
"entry",
|
||||
"start",
|
||||
"end",
|
||||
"parent",
|
||||
"uuid",
|
||||
"mask",
|
||||
"imask",
|
||||
"limit",
|
||||
"status",
|
||||
"description",
|
||||
"tags",
|
||||
"urgency",
|
||||
// Note that annotations are not listed.
|
||||
};
|
||||
|
||||
static const char* modifiableAttributeNames[] =
|
||||
{
|
||||
"project",
|
||||
"priority",
|
||||
"fg",
|
||||
"bg",
|
||||
"due",
|
||||
"recur",
|
||||
"until",
|
||||
"wait",
|
||||
"depends",
|
||||
};
|
||||
|
||||
// Supported modifiers, synonyms on the same line.
|
||||
static const char* modifierNames[] =
|
||||
{
|
||||
|
@ -64,49 +94,52 @@ static struct
|
|||
std::string op;
|
||||
int precedence;
|
||||
char type;
|
||||
int symbol;
|
||||
char associativity;
|
||||
} operators[] =
|
||||
{
|
||||
// Operator Precedence Type Associativity
|
||||
{ "^", 16, 'b', 'r' }, // Exponent
|
||||
// Operator Precedence Type Symbol Associativity
|
||||
{ "^", 16, 'b', 1, 'r' }, // Exponent
|
||||
|
||||
{ "!", 15, 'u', 'r' }, // Not
|
||||
{ "not", 15, 'u', 'r' }, // Not
|
||||
{ "-", 15, 'u', 'r' }, // Unary minus
|
||||
{ "!", 15, 'u', 1, 'r' }, // Not
|
||||
{ "not", 15, 'u', 0, 'r' }, // Not
|
||||
{ "-", 15, 'u', 1, 'r' }, // Unary minus
|
||||
|
||||
{ "*", 13, 'b', 'l' }, // Multiplication
|
||||
{ "/", 13, 'b', 'l' }, // Division
|
||||
{ "%", 13, 'b', 'l' }, // Modulus
|
||||
{ "*", 13, 'b', 1, 'l' }, // Multiplication
|
||||
{ "/", 13, 'b', 1, 'l' }, // Division
|
||||
{ "%", 13, 'b', 1, 'l' }, // Modulus
|
||||
|
||||
{ "+", 12, 'b', 'l' }, // Addition
|
||||
{ "-", 12, 'b', 'l' }, // Subtraction
|
||||
{ "+", 12, 'b', 1, 'l' }, // Addition
|
||||
{ "-", 12, 'b', 1, 'l' }, // Subtraction
|
||||
|
||||
{ "<", 10, 'b', 'l' }, // Less than
|
||||
{ "lt", 10, 'b', 'l' }, // Less than
|
||||
{ "<=", 10, 'b', 'l' }, // Less than or equal
|
||||
{ "le", 10, 'b', 'l' }, // Less than or equal
|
||||
{ ">=", 10, 'b', 'l' }, // Greater than or equal
|
||||
{ "ge", 10, 'b', 'l' }, // Greater than or equal
|
||||
{ ">", 10, 'b', 'l' }, // Greater than
|
||||
{ "gt", 10, 'b', 'l' }, // Greater than
|
||||
{ "<", 10, 'b', 1, 'l' }, // Less than
|
||||
{ "lt", 10, 'b', 0, 'l' }, // Less than
|
||||
{ "<=", 10, 'b', 1, 'l' }, // Less than or equal
|
||||
{ "le", 10, 'b', 0, 'l' }, // Less than or equal
|
||||
{ ">=", 10, 'b', 1, 'l' }, // Greater than or equal
|
||||
{ "ge", 10, 'b', 0, 'l' }, // Greater than or equal
|
||||
{ ">", 10, 'b', 1, 'l' }, // Greater than
|
||||
{ "gt", 10, 'b', 0, 'l' }, // Greater than
|
||||
|
||||
{ "~", 9, 'b', 'l' }, // Regex match
|
||||
{ "!~", 9, 'b', 'l' }, // Regex non-match
|
||||
{ "=", 9, 'b', 'l' }, // Equal
|
||||
{ "eq", 9, 'b', 'l' }, // Equal
|
||||
{ "!=", 9, 'b', 'l' }, // Inequal
|
||||
{ "ne", 9, 'b', 'l' }, // Inequal
|
||||
{ "~", 9, 'b', 1, 'l' }, // Regex match
|
||||
{ "!~", 9, 'b', 1, 'l' }, // Regex non-match
|
||||
{ "=", 9, 'b', 1, 'l' }, // Equal
|
||||
{ "eq", 9, 'b', 0, 'l' }, // Equal
|
||||
{ "!=", 9, 'b', 1, 'l' }, // Inequal
|
||||
{ "ne", 9, 'b', 0, 'l' }, // Inequal
|
||||
|
||||
{ "and", 5, 'b', 'l' }, // Conjunction
|
||||
{ "and", 5, 'b', 0, 'l' }, // Conjunction
|
||||
|
||||
{ "or", 4, 'b', 'l' }, // Disjunction
|
||||
{ "or", 4, 'b', 0, 'l' }, // Disjunction
|
||||
|
||||
{ "(", 0, 'b', 'l' }, // Precedence start
|
||||
{ ")", 0, 'b', 'l' }, // Precedence end
|
||||
{ "(", 0, 'b', 1, 'l' }, // Precedence start
|
||||
{ ")", 0, 'b', 1, 'l' }, // Precedence end
|
||||
};
|
||||
|
||||
#define NUM_MODIFIER_NAMES (sizeof (modifierNames) / sizeof (modifierNames[0]))
|
||||
#define NUM_OPERATORS (sizeof (operators) / sizeof (operators[0]))
|
||||
#define NUM_ATT_NAMES (sizeof (attributeNames) / sizeof (attributeNames[0]))
|
||||
#define NUM_MODIFIABLE_ATT_NAMES (sizeof (modifiableAttributeNames) / sizeof (modifiableAttributeNames[0]))
|
||||
#define NUM_MODIFIER_NAMES (sizeof (modifierNames) / sizeof (modifierNames[0]))
|
||||
#define NUM_OPERATORS (sizeof (operators) / sizeof (operators[0]))
|
||||
|
||||
static const char* non_word_chars = " +-*/%()=<>!~";
|
||||
|
||||
|
@ -181,6 +214,10 @@ void Arguments::categorize ()
|
|||
bool found_something_after_sequence = false;
|
||||
bool found_non_sequence = false;
|
||||
|
||||
// Configurable support.
|
||||
bool enable_expressions = context.config.getBoolean ("expressions");
|
||||
bool enable_patterns = context.config.getBoolean ("patterns");
|
||||
|
||||
// Generate a vector of command keywords against which autoComplete can run.
|
||||
std::vector <std::string> keywords;
|
||||
std::map <std::string, Command*>::iterator k;
|
||||
|
@ -312,7 +349,7 @@ void Arguments::categorize ()
|
|||
}
|
||||
|
||||
// /pattern/
|
||||
else if (is_pattern (arg->first))
|
||||
else if (enable_patterns && is_pattern (arg->first))
|
||||
{
|
||||
found_non_sequence = true;
|
||||
if (found_sequence)
|
||||
|
@ -332,7 +369,7 @@ void Arguments::categorize ()
|
|||
}
|
||||
|
||||
// <expression>
|
||||
else if (is_expression (arg->first))
|
||||
else if (enable_expressions && is_expression (arg->first))
|
||||
{
|
||||
found_non_sequence = true;
|
||||
if (found_sequence)
|
||||
|
@ -636,8 +673,9 @@ bool Arguments::is_attr (const std::string& input)
|
|||
n.getUntilEOS (value) ||
|
||||
n.depleted ())
|
||||
{
|
||||
// TODO Validate and expand attribute name
|
||||
return true;
|
||||
// Validate and canonicalize attribute name.
|
||||
if (is_attribute (name, name))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -688,9 +726,10 @@ bool Arguments::is_attmod (const std::string& input)
|
|||
{
|
||||
return ! is_expression (value);
|
||||
|
||||
// TODO Validate and expand attribute name
|
||||
// TODO Validate and expand modifier name
|
||||
return true;
|
||||
// Validate and canonicalize attribute and modifier names.
|
||||
if (is_attribute (name, name) &&
|
||||
is_modifier (modifier))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -844,6 +883,57 @@ bool Arguments::is_operator (
|
|||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Arguments::is_symbol_operator (const std::string& input)
|
||||
{
|
||||
for (unsigned int i = 0; i < NUM_OPERATORS; ++i)
|
||||
if (operators[i].symbol &&
|
||||
operators[i].op == input)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Arguments::is_attribute (const std::string& input, std::string& canonical)
|
||||
{
|
||||
// Guess at the full attribute name.
|
||||
std::vector <std::string> candidates;
|
||||
for (unsigned i = 0; i < NUM_ATT_NAMES; ++i)
|
||||
candidates.push_back (attributeNames[i]);
|
||||
|
||||
for (unsigned i = 0; i < NUM_MODIFIABLE_ATT_NAMES; ++i)
|
||||
candidates.push_back (modifiableAttributeNames[i]);
|
||||
|
||||
std::vector <std::string> matches;
|
||||
autoComplete (input, candidates, matches);
|
||||
|
||||
if (matches.size () == 1)
|
||||
{
|
||||
canonical = matches[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Arguments::is_modifier (const std::string& input)
|
||||
{
|
||||
// Guess at the full attribute name.
|
||||
std::vector <std::string> candidates;
|
||||
for (unsigned i = 0; i < NUM_MODIFIER_NAMES; ++i)
|
||||
candidates.push_back (modifierNames[i]);
|
||||
|
||||
std::vector <std::string> matches;
|
||||
autoComplete (input, candidates, matches);
|
||||
|
||||
if (matches.size () == 1)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool Arguments::is_expression (const std::string& input)
|
||||
{
|
||||
|
@ -1322,16 +1412,23 @@ void Arguments::dump (const std::string& label)
|
|||
color_map["command"] = Color ("black on cyan");
|
||||
color_map["rc"] = Color ("bold white on red");
|
||||
color_map["override"] = Color ("white on red");
|
||||
color_map["tag"] = Color ("green on gray3");
|
||||
color_map["pattern"] = Color ("cyan on gray3");
|
||||
color_map["attr"] = Color ("bold red on gray3");
|
||||
color_map["attmod"] = Color ("bold red on gray3");
|
||||
color_map["id"] = Color ("yellow on gray3");
|
||||
color_map["uuid"] = Color ("yellow on gray3");
|
||||
color_map["subst"] = Color ("bold cyan on gray3");
|
||||
color_map["op"] = Color ("bold blue on gray3");
|
||||
color_map["exp"] = Color ("bold green on gray5");
|
||||
color_map["none"] = Color ("white on gray3");
|
||||
color_map["tag"] = Color ("green on gray2");
|
||||
color_map["pattern"] = Color ("cyan on gray2");
|
||||
color_map["attr"] = Color ("bold red on gray2");
|
||||
color_map["attmod"] = Color ("bold red on gray2");
|
||||
color_map["id"] = Color ("yellow on gray2");
|
||||
color_map["uuid"] = Color ("yellow on gray2");
|
||||
color_map["subst"] = Color ("bold cyan on gray2");
|
||||
color_map["exp"] = Color ("bold green on gray2");
|
||||
color_map["none"] = Color ("white on gray2");
|
||||
|
||||
// Fundamentals.
|
||||
color_map["lvalue"] = Color ("bold green on rgb010");
|
||||
color_map["op"] = Color ("white on rgb010");
|
||||
color_map["int"] = Color ("bold yellow on rgb010");
|
||||
color_map["number"] = Color ("bold yellow on rgb010");
|
||||
color_map["string"] = Color ("bold yellow on rgb010");
|
||||
color_map["rx"] = Color ("bold red on rgb010");
|
||||
|
||||
Color color_debug (context.config.get ("color.debug"));
|
||||
std::stringstream out;
|
||||
|
|
|
@ -66,6 +66,9 @@ public:
|
|||
static bool is_tag (const std::string&);
|
||||
static bool is_operator (const std::string&);
|
||||
static bool is_operator (const std::string&, char&, int&, char&);
|
||||
static bool is_symbol_operator (const std::string&);
|
||||
static bool is_attribute (const std::string&, std::string&);
|
||||
static bool is_modifier (const std::string&);
|
||||
static bool is_expression (const std::string&);
|
||||
|
||||
// TODO Decide if these are really useful.
|
||||
|
|
|
@ -95,6 +95,8 @@ std::string Config::defaults =
|
|||
"burndown.bias=0.666 # Weighted mean bias toward recent data\n"
|
||||
"regex=no # Assume all search/filter strings are regexes\n"
|
||||
"xterm.title=no # Sets xterm title for some commands\n"
|
||||
"expressions=on # Support for algebraic expressions\n"
|
||||
"patterns=on # Support for regex patterns\n"
|
||||
"\n"
|
||||
"# Dates\n"
|
||||
"dateformat=m/d/Y # Preferred input and display date format\n"
|
||||
|
|
|
@ -25,12 +25,12 @@
|
|||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <iostream> // TODO Remove.
|
||||
#include <sstream>
|
||||
#include <Context.h>
|
||||
#include <Lexer.h>
|
||||
#include <Date.h>
|
||||
#include <Duration.h>
|
||||
#include <Nibbler.h>
|
||||
#include <Variant.h>
|
||||
#include <text.h>
|
||||
#include <Expression.h>
|
||||
|
@ -44,15 +44,26 @@ Expression::Expression (Arguments& arguments)
|
|||
{
|
||||
_args.dump ("Expression::Expression");
|
||||
|
||||
expand_sequence ();
|
||||
implicit_and ();
|
||||
expand_tag ();
|
||||
expand_pattern (); // Configurable
|
||||
expand_attr ();
|
||||
expand_attmod ();
|
||||
expand_word ();
|
||||
expand_expression (); // Configurable
|
||||
postfix ();
|
||||
if (is_new_style () && context.config.getBoolean ("expressions"))
|
||||
{
|
||||
context.debug ("Filter --> new");
|
||||
expand_sequence ();
|
||||
expand_tokens ();
|
||||
postfix ();
|
||||
}
|
||||
else
|
||||
{
|
||||
context.debug ("Filter --> old");
|
||||
expand_sequence ();
|
||||
implicit_and ();
|
||||
expand_tag ();
|
||||
expand_pattern ();
|
||||
expand_attr ();
|
||||
expand_attmod ();
|
||||
expand_word ();
|
||||
expand_expression ();
|
||||
postfix ();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -174,6 +185,42 @@ void Expression::expand_sequence ()
|
|||
_args.dump ("Expression::expand_sequence");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Nibble the whole thing.
|
||||
void Expression::expand_tokens ()
|
||||
{
|
||||
Arguments temp;
|
||||
|
||||
// Get a list of all operators.
|
||||
std::vector <std::string> operators = Arguments::operator_list ();
|
||||
|
||||
// Look at all args.
|
||||
std::string s;
|
||||
int i;
|
||||
double d;
|
||||
std::vector <std::pair <std::string, std::string> >::iterator arg;
|
||||
for (arg = _args.begin (); arg != _args.end (); ++arg)
|
||||
{
|
||||
Nibbler n (arg->first);
|
||||
|
||||
if (n.getQuoted ('"', s, true) ||
|
||||
n.getQuoted ('\'', s, true))
|
||||
temp.push_back (std::make_pair (s, "string"));
|
||||
|
||||
else if (n.getNumber (d))
|
||||
temp.push_back (std::make_pair (format (d), "number"));
|
||||
|
||||
else if (n.getInt (i))
|
||||
temp.push_back (std::make_pair (format (i), "int"));
|
||||
|
||||
else
|
||||
temp.push_back (*arg);
|
||||
}
|
||||
|
||||
_args.swap (temp);
|
||||
_args.dump ("Expression::expand_tokens");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Inserts the 'and' operator by default between terms that are not separated by
|
||||
// at least one operator.
|
||||
|
@ -230,7 +277,7 @@ void Expression::expand_tag ()
|
|||
|
||||
temp.push_back (std::make_pair ("tags", "lvalue"));
|
||||
temp.push_back (std::make_pair (type == '+' ? "~" : "!~", "op"));
|
||||
temp.push_back (std::make_pair (value, "rvalue"));
|
||||
temp.push_back (std::make_pair (value, "string"));
|
||||
delta = true;
|
||||
}
|
||||
else
|
||||
|
@ -262,7 +309,7 @@ void Expression::expand_pattern ()
|
|||
|
||||
temp.push_back (std::make_pair ("description", "lvalue"));
|
||||
temp.push_back (std::make_pair ("~", "op"));
|
||||
temp.push_back (std::make_pair (value, "rvalue"));
|
||||
temp.push_back (std::make_pair (value, "rx"));
|
||||
delta = true;
|
||||
}
|
||||
else
|
||||
|
@ -293,6 +340,7 @@ void Expression::expand_attr ()
|
|||
std::string name;
|
||||
std::string value;
|
||||
Arguments::extract_attr (arg->first, name, value);
|
||||
Arguments::is_attribute (name, name);
|
||||
|
||||
// Always quote the value, so that empty values, or values containing spaces
|
||||
// are preserved.
|
||||
|
@ -327,13 +375,13 @@ void Expression::expand_attmod ()
|
|||
{
|
||||
if (arg->second == "attmod")
|
||||
{
|
||||
// TODO Should canonicalize 'name'.
|
||||
std::string name;
|
||||
// TODO Should canonicalize 'mod'.
|
||||
std::string mod;
|
||||
std::string value;
|
||||
std::string sense;
|
||||
Arguments::extract_attmod (arg->first, name, mod, value, sense);
|
||||
Arguments::is_attribute (name, name);
|
||||
Arguments::is_modifier (mod);
|
||||
|
||||
// Always quote the value, so that empty values, or values containing spaces
|
||||
// are preserved.
|
||||
|
@ -356,13 +404,13 @@ void Expression::expand_attmod ()
|
|||
{
|
||||
temp.push_back (std::make_pair (name, "lvalue"));
|
||||
temp.push_back (std::make_pair ("==", "op"));
|
||||
temp.push_back (std::make_pair ("\"\"", "rvalue"));
|
||||
temp.push_back (std::make_pair ("\"\"", "string"));
|
||||
}
|
||||
else if (mod == "any")
|
||||
{
|
||||
temp.push_back (std::make_pair (name, "lvalue"));
|
||||
temp.push_back (std::make_pair ("!=", "op"));
|
||||
temp.push_back (std::make_pair ("\"\"", "rvalue"));
|
||||
temp.push_back (std::make_pair ("\"\"", "string"));
|
||||
}
|
||||
else if (mod == "is" || mod == "equals")
|
||||
{
|
||||
|
@ -443,7 +491,7 @@ void Expression::expand_word ()
|
|||
{
|
||||
temp.push_back (std::make_pair ("description", "lvalue"));
|
||||
temp.push_back (std::make_pair ("~", "op"));
|
||||
temp.push_back (std::make_pair (arg->first, "rvalue"));
|
||||
temp.push_back (std::make_pair ("\"" + arg->first + "\"", "rvalue"));
|
||||
|
||||
delta = true;
|
||||
}
|
||||
|
@ -477,34 +525,75 @@ void Expression::expand_expression ()
|
|||
{
|
||||
if (arg->second == "exp")
|
||||
{
|
||||
// Remove quotes.
|
||||
arg->first = unquoteText (arg->first);
|
||||
// Split expression into space-separated tokens.
|
||||
std::vector <std::string> tokens;
|
||||
split (tokens, unquoteText (arg->first), ' ');
|
||||
|
||||
if (Date::valid (arg->first, context.config.get ("dateformat")))
|
||||
temp.push_back (std::make_pair (arg->first, "date"));
|
||||
|
||||
else if (Duration::valid (arg->first))
|
||||
temp.push_back (std::make_pair (arg->first, "duration"));
|
||||
|
||||
// The expression does not appear to be syntactic sugar, so it should be
|
||||
// lexed.
|
||||
else
|
||||
std::vector <std::string>::iterator token;
|
||||
for (token = tokens.begin (); token != tokens.end (); ++token)
|
||||
{
|
||||
Lexer lexer (arg->first);
|
||||
lexer.skipWhitespace (true);
|
||||
lexer.coalesceAlpha (true);
|
||||
lexer.coalesceDigits (true);
|
||||
lexer.coalesceQuoted (true);
|
||||
if (Date::valid (*token, context.config.get ("dateformat")))
|
||||
temp.push_back (std::make_pair (*token, "date"));
|
||||
|
||||
std::vector <std::string> tokens;
|
||||
lexer.tokenize (tokens);
|
||||
else if (Duration::valid (*token))
|
||||
temp.push_back (std::make_pair (*token, "duration"));
|
||||
|
||||
std::vector <std::string>::iterator token;
|
||||
for (token = tokens.begin (); token != tokens.end (); ++token)
|
||||
temp.push_back (
|
||||
std::make_pair (
|
||||
*token,
|
||||
(_args.is_operator (*token) ? "op" : "dom")));
|
||||
else if (Arguments::is_id (*token))
|
||||
temp.push_back (std::make_pair (*token, "int"));
|
||||
|
||||
else if (Arguments::is_uuid (*token))
|
||||
temp.push_back (std::make_pair (*token, "string"));
|
||||
|
||||
else if (Arguments::is_operator (*token))
|
||||
temp.push_back (std::make_pair (*token, "op"));
|
||||
|
||||
// The expression does not appear to be syntactic sugar, so it should be
|
||||
// lexed.
|
||||
else
|
||||
{
|
||||
Lexer lexer (*token);
|
||||
lexer.skipWhitespace (true);
|
||||
lexer.coalesceAlpha (true);
|
||||
lexer.coalesceDigits (true);
|
||||
lexer.coalesceQuoted (true);
|
||||
|
||||
// Each operator of length > 1 is a special token.
|
||||
std::vector <std::string>::iterator op;
|
||||
for (op = operators.begin (); op != operators.end (); ++op)
|
||||
if (op->length () > 1)
|
||||
lexer.specialToken (*op);
|
||||
|
||||
std::vector <std::string> ltokens;
|
||||
lexer.tokenize (ltokens);
|
||||
|
||||
std::vector <std::string>::iterator ltoken;
|
||||
for (ltoken = ltokens.begin (); ltoken != ltokens.end (); ++ltoken)
|
||||
{
|
||||
if (Date::valid (*ltoken, context.config.get ("dateformat")))
|
||||
temp.push_back (std::make_pair (*ltoken, "date"));
|
||||
|
||||
else if (Duration::valid (*ltoken))
|
||||
temp.push_back (std::make_pair (*ltoken, "duration"));
|
||||
|
||||
else if (Arguments::is_id (*ltoken))
|
||||
temp.push_back (std::make_pair (*ltoken, "int"));
|
||||
|
||||
else if (Arguments::is_uuid (*ltoken))
|
||||
temp.push_back (std::make_pair (*ltoken, "string"));
|
||||
|
||||
else if (Arguments::is_operator (*ltoken))
|
||||
temp.push_back (std::make_pair (*ltoken, "op"));
|
||||
|
||||
else if (Arguments::is_id (*ltoken))
|
||||
temp.push_back (std::make_pair (*ltoken, "int"));
|
||||
|
||||
else if (Arguments::is_uuid (*ltoken))
|
||||
temp.push_back (std::make_pair (*ltoken, "string"));
|
||||
|
||||
else
|
||||
temp.push_back (std::make_pair (*ltoken, "lvalue"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delta = true;
|
||||
|
@ -624,3 +713,21 @@ void Expression::postfix ()
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Test whether the _original arguments are old style or new style.
|
||||
//
|
||||
// Old style: no single argument corresponds to an operator, ie no 'and', 'or',
|
||||
// etc.
|
||||
//
|
||||
// New style: at least one argument that is an operator.
|
||||
//
|
||||
bool Expression::is_new_style ()
|
||||
{
|
||||
std::vector <std::pair <std::string, std::string> >::iterator arg;
|
||||
for (arg = _args.begin (); arg != _args.end (); ++arg)
|
||||
if (Arguments::is_symbol_operator (arg->first))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -49,8 +49,11 @@ private:
|
|||
void expand_attmod ();
|
||||
void expand_word ();
|
||||
void expand_expression ();
|
||||
void expand_tokens ();
|
||||
void postfix ();
|
||||
|
||||
bool is_new_style ();
|
||||
|
||||
private:
|
||||
Arguments _args;
|
||||
};
|
||||
|
|
|
@ -53,7 +53,6 @@ CmdShow::CmdShow ()
|
|||
int CmdShow::execute (std::string& output)
|
||||
{
|
||||
int rc = 0;
|
||||
/*
|
||||
std::stringstream out;
|
||||
|
||||
// Obtain the arguments from the description. That way, things like '--'
|
||||
|
@ -68,42 +67,141 @@ int CmdShow::execute (std::string& output)
|
|||
// Note that there is a leading and trailing space, to make it easier to
|
||||
// search for whole words.
|
||||
std::string recognized =
|
||||
" annotations avoidlastcolumn bulk burndown.bias calendar.details "
|
||||
"calendar.details.report calendar.holidays calendar.legend color "
|
||||
"calendar.offset calendar.offset.value color.active color.due "
|
||||
"color.due.today color.blocked color.burndown.done color.burndown.pending "
|
||||
"color.burndown.started color.overdue color.pri.H color.pri.L color.pri.M "
|
||||
"color.pri.none color.recurring color.tagged color.footnote color.header "
|
||||
"color.debug color.alternate color.calendar.today color.calendar.due "
|
||||
"color.calendar.due.today color.calendar.overdue regex "
|
||||
"color.calendar.weekend color.calendar.holiday color.calendar.weeknumber "
|
||||
"color.summary.background color.summary.bar color.history.add "
|
||||
"color.history.done color.history.delete color.undo.before color.label "
|
||||
"color.sync.added color.sync.changed color.sync.rejected color.undo.after "
|
||||
"confirmation data.location dateformat dateformat.holiday "
|
||||
"dateformat.report dateformat.annotation debug default.command default.due "
|
||||
"default.priority default.project defaultwidth dependency.indicator due "
|
||||
"dependency.confirmation dependency.reminder detection locale "
|
||||
"displayweeknumber export.ical.class echo.command fontunderline gc locking "
|
||||
"monthsperline nag journal.time journal.time.start.annotation journal.info "
|
||||
"journal.time.stop.annotation project shadow.command shadow.file "
|
||||
"shadow.notify weekstart editor edit.verbose import.synonym.id "
|
||||
"import.synonym.uuid complete.all.projects complete.all.tags "
|
||||
"search.case.sensitive extensions active.indicator tag.indicator "
|
||||
"recurrence.indicator recurrence.limit list.all.projects list.all.tags "
|
||||
"undo.style verbose rule.precedence.color merge.autopush merge.default.uri "
|
||||
"pull.default.uri push.default.uri xterm.title shell.prompt "
|
||||
"indent.annotation indent.report column.spacing row.padding column.padding "
|
||||
"import.synonym.status import.synonym.tags import.synonym.entry "
|
||||
"import.synonym.start import.synonym.due import.synonym.recur "
|
||||
"import.synonym.end import.synonym.project import.synonym.priority "
|
||||
"import.synonym.fg import.synonym.bg import.synonym.description "
|
||||
|
||||
"urgency.next.coefficient urgency.blocking.coefficient "
|
||||
"urgency.blocked.coefficient urgency.due.coefficient "
|
||||
"urgency.priority.coefficient urgency.waiting.coefficient "
|
||||
"urgency.active.coefficient urgency.project.coefficient "
|
||||
"urgency.tags.coefficient urgency.annotations.coefficient ";
|
||||
" active.indicator"
|
||||
" annotations"
|
||||
" avoidlastcolumn"
|
||||
" bulk"
|
||||
" burndown.bias"
|
||||
" calendar.details"
|
||||
" calendar.details.report"
|
||||
" calendar.holidays"
|
||||
" calendar.legend"
|
||||
" calendar.offset"
|
||||
" calendar.offset.value"
|
||||
" color"
|
||||
" color.active"
|
||||
" color.alternate"
|
||||
" color.blocked"
|
||||
" color.burndown.done"
|
||||
" color.burndown.pending"
|
||||
" color.burndown.started"
|
||||
" color.calendar.due"
|
||||
" color.calendar.due.today"
|
||||
" color.calendar.holiday"
|
||||
" color.calendar.overdue"
|
||||
" color.calendar.today"
|
||||
" color.calendar.weekend"
|
||||
" color.calendar.weeknumber"
|
||||
" color.debug"
|
||||
" color.due"
|
||||
" color.due.today"
|
||||
" color.footnote"
|
||||
" color.header"
|
||||
" color.history.add"
|
||||
" color.history.delete"
|
||||
" color.history.done"
|
||||
" color.label"
|
||||
" color.overdue"
|
||||
" color.pri.H"
|
||||
" color.pri.L"
|
||||
" color.pri.M"
|
||||
" color.pri.none"
|
||||
" color.recurring"
|
||||
" color.summary.background"
|
||||
" color.summary.bar"
|
||||
" color.sync.added"
|
||||
" color.sync.changed"
|
||||
" color.sync.rejected"
|
||||
" color.tagged"
|
||||
" color.undo.after"
|
||||
" color.undo.before"
|
||||
" column.padding"
|
||||
" column.spacing"
|
||||
" complete.all.projects"
|
||||
" complete.all.tags"
|
||||
" confirmation"
|
||||
" data.location"
|
||||
" dateformat"
|
||||
" dateformat.annotation"
|
||||
" dateformat.holiday"
|
||||
" dateformat.report"
|
||||
" debug"
|
||||
" default.command"
|
||||
" default.due"
|
||||
" default.priority"
|
||||
" default.project"
|
||||
" defaultwidth"
|
||||
" dependency.confirmation"
|
||||
" dependency.indicator"
|
||||
" dependency.reminder"
|
||||
" detection"
|
||||
" displayweeknumber"
|
||||
" due"
|
||||
" echo.command"
|
||||
" edit.verbose"
|
||||
" editor"
|
||||
" export.ical.class"
|
||||
" expressions"
|
||||
" extensions"
|
||||
" fontunderline"
|
||||
" gc"
|
||||
" import.synonym.bg"
|
||||
" import.synonym.description"
|
||||
" import.synonym.due"
|
||||
" import.synonym.end"
|
||||
" import.synonym.entry"
|
||||
" import.synonym.fg"
|
||||
" import.synonym.id"
|
||||
" import.synonym.priority"
|
||||
" import.synonym.project"
|
||||
" import.synonym.recur"
|
||||
" import.synonym.start"
|
||||
" import.synonym.status"
|
||||
" import.synonym.tags"
|
||||
" import.synonym.uuid"
|
||||
" indent.annotation"
|
||||
" indent.report"
|
||||
" journal.info"
|
||||
" journal.time"
|
||||
" journal.time.start.annotation"
|
||||
" journal.time.stop.annotation"
|
||||
" list.all.projects"
|
||||
" list.all.tags"
|
||||
" locale"
|
||||
" locking"
|
||||
" merge.autopush"
|
||||
" merge.default.uri"
|
||||
" monthsperline"
|
||||
" nag"
|
||||
" patterns"
|
||||
" project"
|
||||
" pull.default.uri"
|
||||
" push.default.uri"
|
||||
" recurrence.indicator"
|
||||
" recurrence.limit"
|
||||
" regex"
|
||||
" row.padding"
|
||||
" rule.precedence.color"
|
||||
" search.case.sensitive"
|
||||
" shadow.command"
|
||||
" shadow.file"
|
||||
" shadow.notify"
|
||||
" shell.prompt"
|
||||
" tag.indicator"
|
||||
" undo.style"
|
||||
" urgency.active.coefficient"
|
||||
" urgency.annotations.coefficient"
|
||||
" urgency.blocked.coefficient"
|
||||
" urgency.blocking.coefficient"
|
||||
" urgency.due.coefficient"
|
||||
" urgency.next.coefficient"
|
||||
" urgency.priority.coefficient"
|
||||
" urgency.project.coefficient"
|
||||
" urgency.tags.coefficient"
|
||||
" urgency.waiting.coefficient"
|
||||
" verbose"
|
||||
" weekstart"
|
||||
" xterm.title";
|
||||
|
||||
// This configuration variable is supported, but not documented. It exists
|
||||
// so that unit tests can force color to be on even when the output from task
|
||||
|
@ -159,8 +257,24 @@ int CmdShow::execute (std::string& output)
|
|||
|
||||
std::string section;
|
||||
|
||||
// Look for the first plausible argument which could be a pattern
|
||||
// TODO Replace this 'section' assessment with something that scans the
|
||||
// arguments and pulls out either <word> or <pattern> strings to use as
|
||||
// search items.
|
||||
/*
|
||||
if (context.args.size () == 2)
|
||||
section = context.args[1];
|
||||
*/
|
||||
/*
|
||||
Arguments args = context.args.extract_read_only_filter ();
|
||||
std::vector <std::pair <std::string, std::string> >::iterator arg;
|
||||
for (arg = args.begin (); arg != args.end (); ++arg)
|
||||
{
|
||||
if (arg->second == "string")
|
||||
{
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
if (section == "all")
|
||||
section = "";
|
||||
|
@ -309,7 +423,6 @@ int CmdShow::execute (std::string& output)
|
|||
}
|
||||
|
||||
output = out.str ();
|
||||
*/
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ Context context;
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
int main (int argc, char** argv)
|
||||
{
|
||||
UnitTest t (113);
|
||||
UnitTest t (103);
|
||||
|
||||
const char* fake[] =
|
||||
{
|
||||
|
@ -72,12 +72,6 @@ int main (int argc, char** argv)
|
|||
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");
|
||||
|
||||
|
@ -88,12 +82,6 @@ int main (int argc, char** argv)
|
|||
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= -> 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");
|
||||
|
||||
|
@ -203,24 +191,6 @@ int main (int argc, char** argv)
|
|||
t.ok (Arguments::valid_modifier ("noword"), "noword -> modifier");
|
||||
t.notok (Arguments::valid_modifier ("duck"), "duck -> not modified");
|
||||
|
||||
// TODO void extract_uuids (std::vector <std::string>&);
|
||||
// TODO void extract_filter ();
|
||||
// TODO void extract_modifications ();
|
||||
// TODO void extract_text ();
|
||||
|
||||
// TODO bool extract_attr (const std::string&, std::string&, std::string&);
|
||||
// TODO bool extract_attmod (const std::string&, std::string&, std::string&, std::string&, std::string&);
|
||||
// TODO bool extract_subst (const std::string&, std::string&, std::string&, bool&);
|
||||
// TODO bool extract_pattern (const std::string&, std::string&);
|
||||
// TODO bool extract_id (const std::string&, std::vector <int>&);
|
||||
// TODO bool extract_uuid (const std::string&, std::vector <std::string>&);
|
||||
// TODO bool extract_tag (const std::string&, char&, std::string&);
|
||||
// TODO bool extract_operator (const std::string&, std::string&);
|
||||
|
||||
// TODO Arguments extract_read_only_filter ();
|
||||
// TODO Arguments extract_write_filter ();
|
||||
// TODO Arguments extract_modifications ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue