diff --git a/src/A3.cpp b/src/A3.cpp index acf74569a..1ff492ae8 100644 --- a/src/A3.cpp +++ b/src/A3.cpp @@ -836,7 +836,7 @@ const A3 A3::expand (const A3& input) const std::string mod; std::string value; std::string sense; - Arguments::extract_attmod (arg->_raw, name, mod, value, sense); + extract_attmod (arg->_raw, name, mod, value, sense); // name.before:value --> name < value if (mod == "before" || mod == "under" || mod == "below") @@ -942,7 +942,7 @@ const A3 A3::expand (const A3& input) const { char type; std::string value; - A3::extract_tag (arg->_raw, type, value); + extract_tag (arg->_raw, type, value); expanded.push_back (Arg ("tags", "dom")); expanded.push_back (Arg (type == '+' ? "~" : "!~", "op")); @@ -961,7 +961,7 @@ const A3 A3::expand (const A3& input) const else if (arg->_category == "pattern") { std::string value; - A3::extract_pattern (arg->_raw, value); + extract_pattern (arg->_raw, value); expanded.push_back (Arg ("description", "dom")); expanded.push_back (Arg ("~", "op")); @@ -990,10 +990,10 @@ const A3 A3::sequence (const A3& input) const for (arg = input.begin (); arg != input.end (); ++arg) { if (arg->_category == "id") - A3::extract_id (arg->_raw, ids); + extract_id (arg->_raw, ids); else if (arg->_category == "uuid") - A3::extract_uuid (arg->_raw, uuids); + extract_uuid (arg->_raw, uuids); } // If there is no sequence, we're done. @@ -1109,13 +1109,13 @@ const A3 A3::postfix (const A3& input) const else throw std::string ("Mismatched parentheses in expression"); } - else if (A3::is_operator (arg->_raw, type, precedence, associativity)) + else if (is_operator (arg->_raw, type, precedence, associativity)) { char type2; int precedence2; char associativity2; while (op_stack.size () > 0 && - A3::is_operator (op_stack.back ()._raw, type2, precedence2, associativity2) && + is_operator (op_stack.back ()._raw, type2, precedence2, associativity2) && ((associativity == 'l' && precedence <= precedence2) || (associativity == 'r' && precedence < precedence2))) { diff --git a/src/Arguments.cpp b/src/Arguments.cpp deleted file mode 100644 index de981cdb6..000000000 --- a/src/Arguments.cpp +++ /dev/null @@ -1,1734 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// taskwarrior - a command line task list manager. -// -// Copyright 2006 - 2011, Paul Beckingham, Federico Hernandez. -// All rights reserved. -// -// This program is free software; you can redistribute it and/or modify it under -// the terms of the GNU General Public License as published by the Free Software -// Foundation; either version 2 of the License, or (at your option) any later -// version. -// -// This program is distributed in the hope that it will be useful, but WITHOUT -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -// details. -// -// You should have received a copy of the GNU General Public License along with -// this program; if not, write to the -// -// Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, -// Boston, MA -// 02110-1301 -// USA -// -//////////////////////////////////////////////////////////////////////////////// - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -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[] = -{ - "before", "under", "below", - "after", "over", "above", - "none", - "any", - "is", "equals", - "isnt", "not", - "has", "contains", - "hasnt", - "startswith", "left", - "endswith", "right", - "word", - "noword" -}; - -// Supported operators, borrowed from C++, particularly the precedence. -// Note: table is sorted by length of operator string, so searches match -// longest first. -static struct -{ - std::string op; - int precedence; - char type; - int symbol; - char associativity; -} operators[] = -{ - // Operator Precedence Type Symbol Associativity - { "and", 5, 'b', 0, 'l' }, // Conjunction - { "xor", 4, 'b', 0, 'l' }, // Disjunction - - { "or", 3, 'b', 0, 'l' }, // Disjunction - { "<=", 10, 'b', 1, 'l' }, // Less than or equal - { ">=", 10, 'b', 1, 'l' }, // Greater than or equal - { "!~", 9, 'b', 1, 'l' }, // Regex non-match - { "!=", 9, 'b', 1, 'l' }, // Inequal - - { "=", 9, 'b', 1, 'l' }, // Equal -// { "^", 16, 'b', 1, 'r' }, // Exponent - { ">", 10, 'b', 1, 'l' }, // Greater than - { "~", 9, 'b', 1, 'l' }, // Regex match - { "!", 15, 'u', 1, 'r' }, // Not -// { "-", 15, 'u', 1, 'r' }, // Unary minus - { "*", 13, 'b', 1, 'l' }, // Multiplication - { "/", 13, 'b', 1, 'l' }, // Division -// { "%", 13, 'b', 1, 'l' }, // Modulus - { "+", 12, 'b', 1, 'l' }, // Addition - { "-", 12, 'b', 1, 'l' }, // Subtraction - { "<", 10, 'b', 1, 'l' }, // Less than - { "(", 0, 'b', 1, 'l' }, // Precedence start - { ")", 0, 'b', 1, 'l' }, // Precedence end -}; - -#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 = " +-*/%()=<>!~"; - -//////////////////////////////////////////////////////////////////////////////// -Arguments::Arguments () -{ -} - -//////////////////////////////////////////////////////////////////////////////// -Arguments::~Arguments () -{ -} - -//////////////////////////////////////////////////////////////////////////////// -// Add a pair for every argument, with a category of "". -void Arguments::capture (int argc, const char** argv) -{ - for (int i = 0; i < argc; ++i) - { - // The "i &&" guarantees that argv[0] does not get split, because it may - // be an absolute path, and Expression::expand_tokens would make a dog's - // dinner out of it. - std::vector parts; - if (i && is_multipart (argv[i], parts)) - { - std::vector ::iterator part; - for (part = parts.begin (); part != parts.end (); ++part) - this->push_back (Triple (*part, "", "")); - } - else - this->push_back (Triple (argv[i], "", "")); - } - - categorize (); -} - -//////////////////////////////////////////////////////////////////////////////// -// Append a Triple with a blank category. -void Arguments::capture (const std::string& arg) -{ - std::vector parts; - if (is_multipart (arg, parts)) - { - std::vector ::iterator part; - for (part = parts.begin (); part != parts.end (); ++part) - this->push_back (Triple (*part, "", "")); - } - else - this->push_back (Triple (arg, "", "")); - - categorize (); -} - -//////////////////////////////////////////////////////////////////////////////// -// Prepend a Triple with a blank category. -void Arguments::capture_first (const std::string& arg) -{ - // Break the new argument into parts that comprise a series. - std::vector series; - - std::vector parts; - if (is_multipart (arg, parts)) - { - std::vector ::iterator part; - for (part = parts.begin (); part != parts.end (); ++part) - series.push_back (Triple (*part, "", "")); - } - else - series.push_back (Triple (arg, "", "")); - - // Locate an appropriate place to insert the series. This would be - // immediately after the program and command arguments. - std::vector ::iterator position; - for (position = this->begin (); position != this->end (); ++position) - if (position->_third != "program" && - position->_third != "command") - break; - - this->insert (position, series.begin (), series.end ()); - - categorize (); -} - -//////////////////////////////////////////////////////////////////////////////// -// Add a pair for every word from std::cin, with a category of "". -void Arguments::append_stdin () -{ - bool something_happened = false; - - // Use 'select' to determine whether there is any std::cin content buffered - // before trying to read it, to prevent blocking. - struct timeval tv; - fd_set fds; - tv.tv_sec = 0; - tv.tv_usec = 0; - FD_ZERO (&fds); - FD_SET (STDIN_FILENO, &fds); - select (STDIN_FILENO + 1, &fds, NULL, NULL, &tv); - if (FD_ISSET (0, &fds)) - { - std::string arg; - while (std::cin >> arg) - { - // It the terminator token is found, stop reading. - if (arg == "--") - break; - - this->push_back (Triple (arg, "", "")); - something_happened = true; - } - } - - if (something_happened) - categorize (); -} - -//////////////////////////////////////////////////////////////////////////////// -// Scan all the arguments, and assign a category for each one. The categories -// are used to identify arguments types, and when extracting filters and -// modifications. -// -// Categories and filters: -// -// ro wr mods words -// terminator - - - - -// program - - - - -// command - - - - -// rc - - - - -// override - - - - -// id Y Y Err Y -// uuid Y Y Err Y -// word Y < > Y -// tag Y < > Y -// attmod Y < Err - -// attr Y < > - -// substitution Err Err > Y -// pattern Y < Err Y -// op Y < > Y -// exp Y < Err Y -// -// Legend: -// Y Included -// - Excluded -// < Included if before -// > Included if after -// Err Error if present - -void Arguments::categorize () -{ - bool terminated = false; - bool found_command = false; - bool found_sequence = false; - bool found_something_after_sequence = false; - - // Track where the command is, if possible. -// int command_pos = -1; -// int distance_from_command = 0; - - // 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 keywords; - std::map ::iterator k; - for (k = context.commands.begin (); k != context.commands.end (); ++k) - keywords.push_back (k->first); - - // Now categorize every argument. - int counter = 0; - std::string ignored; - std::vector ::iterator arg; - for (arg = this->begin (); arg != this->end (); ++arg, ++counter) - { - if (!terminated) - { - // Nothing after -- is to be interpreted in any way. - if (arg->_first == "--") - { - terminated = true; - if (found_sequence) - found_something_after_sequence = true; - - arg->_third = "terminator"; - } - - // program - else if (arg == this->begin ()) - { - arg->_third = "program"; // TODO Is this a problem for expressions that do not contain a program name? - - - if ((arg->_first.length () >= 3 && - arg->_first.substr (arg->_first.length () - 3) == "cal") || - (arg->_first.length () >= 8 && - arg->_first.substr (arg->_first.length () - 8) == "calendar")) - { - arg->_first = "calendar"; - arg->_third = "command"; - found_command = true; - } - } - - // command - else if (!found_command && - is_command (keywords, arg->_first)) - { - found_command = true; - if (found_sequence) - found_something_after_sequence = true; - -// command_pos = counter; - - arg->_third = "command"; - } - - // rc: - // Note: This doesn't break a sequence chain. - else if (arg->_first.substr (0, 3) == "rc:") - { - arg->_third = "rc"; - } - - // rc.: - // Note: This doesn't break a sequence chain. - else if (arg->_first.substr (0, 3) == "rc.") - { - arg->_third = "override"; - } - - // [-][,...] - else if (is_id (arg->_first)) - { - if (found_something_after_sequence/* || - (command_pos != -1 && distance_from_command > 0)*/) - { - arg->_third = "word"; - } - else - { - found_sequence = true; - arg->_third = "id"; - } - } - - // [,...] - else if (is_uuid (arg->_first)) - { - if (found_something_after_sequence/* || - (command_pos != -1 && distance_from_command > 0)*/) - { - arg->_third = "word"; - } - else - { - found_sequence = true; - arg->_third = "uuid"; - } - } - - // [+-]tag - else if (is_tag (arg->_first)) - { - if (found_sequence) - found_something_after_sequence = true; - -// if (command_pos != -1) -// ++distance_from_command; - - arg->_third = "tag"; - } - - // .: - else if (is_attmod (arg->_first)) - { - if (found_sequence) - found_something_after_sequence = true; - -// if (command_pos != -1) -// ++distance_from_command; - - arg->_third = "attmod"; - } - - // : - else if (is_attr (arg->_first)) - { - if (found_sequence) - found_something_after_sequence = true; - -// if (command_pos != -1) -// ++distance_from_command; - - arg->_third = "attr"; - } - - // ///[g] - else if (is_subst (arg->_first)) - { - if (found_sequence) - found_something_after_sequence = true; - -// if (command_pos != -1) -// ++distance_from_command; - - arg->_third = "subst"; - } - - // /pattern/ - else if (enable_patterns && is_pattern (arg->_first)) - { - if (found_sequence) - found_something_after_sequence = true; - -// if (command_pos != -1) -// ++distance_from_command; - - arg->_third = "pattern"; - } - - // - else if (is_operator (arg->_first)) - { - if (found_sequence) - found_something_after_sequence = true; - -// if (command_pos != -1) -// ++distance_from_command; - - arg->_third = "op"; - } - - // - else if (enable_expressions && is_expression (arg->_first)) - { - if (found_sequence) - found_something_after_sequence = true; - -// if (command_pos != -1) -// ++distance_from_command; - - arg->_second = "exp"; - arg->_third = "exp"; - } - - // If the type is not known, it is treated as a generic word. - else - { - if (found_sequence) - found_something_after_sequence = true; - -// if (command_pos != -1) -// ++distance_from_command; - - arg->_third = "word"; - } - } - - // All post-termination arguments are simply words. - else - { - if (found_sequence) - found_something_after_sequence = true; - - arg->_third = "word"; - } - } -} - -//////////////////////////////////////////////////////////////////////////////// -void Arguments::rc_override ( - std::string& home, - File& rc) -{ - // Is there an override for rc:? - std::vector ::iterator arg; - for (arg = this->begin (); arg != this->end (); ++arg) - { - if (arg->_third == "rc") - { - rc = File (arg->_first.substr (3)); - home = rc; - - std::string::size_type last_slash = rc.data.rfind ("/"); - if (last_slash != std::string::npos) - home = rc.data.substr (0, last_slash); - else - home = "."; - - context.header ("Using alternate .taskrc file " + rc.data); - - // Keep scanning, because if there are multiple rc:file arguments, we - // want the last one to dominate. - } - } -} - -//////////////////////////////////////////////////////////////////////////////// -void Arguments::get_data_location (std::string& data) -{ - std::string location = context.config.get ("data.location"); - if (location != "") - data = location; - - // Are there any overrides for data.location? - std::vector ::iterator arg; - for (arg = this->begin (); arg != this->end (); ++arg) - { - if (arg->_third == "override") - { - if (arg->_first.substr (0, 16) == "rc.data.location" && - arg->_first[16] == ':') - { - data = arg->_first.substr (17); - context.header ("Using alternate data.location " + data); - } - } - - // Keep scanning, because if there are multiple rc:file arguments, we - // want the last one to dominate. - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Extracts any rc.name:value args and sets the name/value in context.config, -// leaving only the plain args. -void Arguments::apply_overrides () -{ - std::vector ::iterator arg; - for (arg = this->begin (); arg != this->end (); ++arg) - { - if (arg->_third == "override") - { - std::string name; - std::string value; - Nibbler n (arg->_first); - if (n.getLiteral ("rc.") && // rc. - n.getUntil (':', name) && // xxx - n.skip (':')) // : - { - n.getUntilEOS (value); // May be blank. - - context.config.set (name, value); - context.footnote ("Configuration override rc." + name + ":" + value); - } - else - context.footnote ("Problem with override: " + arg->_first); - } - } -} - -//////////////////////////////////////////////////////////////////////////////// -// An alias must be a distinct word on the command line. -// Aliases may not recurse. -void Arguments::resolve_aliases () -{ - std::vector expanded; - bool something; - int safety_valve = 10; - - do - { - something = false; - std::vector ::iterator arg; - for (arg = this->begin (); arg != this->end (); ++arg) - { - std::map ::iterator match = - context.aliases.find (arg->_first); - - if (match != context.aliases.end ()) - { - context.debug (std::string ("Arguments::resolve_aliases '") - + arg->_first - + "' --> '" - + context.aliases[arg->_first] - + "'"); - - std::vector words; - splitq (words, context.aliases[arg->_first], ' '); - - std::vector ::iterator word; - for (word = words.begin (); word != words.end (); ++word) - expanded.push_back (*word); - - something = true; - } - else - expanded.push_back (arg->_first); - } - - // Only overwrite if something happened. - if (something) - { - this->clear (); - std::vector ::iterator e; - for (e = expanded.begin (); e != expanded.end (); ++e) - this->push_back (Triple (*e, "", "")); - - expanded.clear (); - categorize (); - } - } - while (something && --safety_valve > 0); -} - -//////////////////////////////////////////////////////////////////////////////// -// These are some delicate heuristics here. Tread lightly. -void Arguments::inject_defaults () -{ - // Scan the arguments and detect what is present. - bool found_command = false; - bool found_sequence = false; - bool found_other = false; - - std::vector ::iterator arg; - for (arg = this->begin (); arg != this->end (); ++arg) - { - if (arg->_third == "command") - found_command = true; - - else if (arg->_third == "id" || - arg->_third == "uuid") - found_sequence = true; - - else if (arg->_third != "program" && - arg->_third != "override" && - arg->_third != "rc") - found_other = true; - } - - // If no command was specified, then a command will be inserted. - if (!found_command) - { - // Default command. - if (!found_sequence) - { - // Apply overrides, if any. - std::string defaultCommand = context.config.get ("default.command"); - if (defaultCommand != "") - { - capture_first (defaultCommand); - context.header ("[" + combine () + "]"); - } - else - throw std::string (STRING_TRIVIAL_INPUT); - } - else - { - // Modify command. - if (found_other) - { - capture_first ("modify"); - } - - // Information command. - else - { - context.header (STRING_ASSUME_INFO); - capture_first ("information"); - } - } - } -} - -//////////////////////////////////////////////////////////////////////////////// -std::vector Arguments::list () -{ - std::vector all; - std::vector ::iterator arg; - for (arg = this->begin (); arg != this->end (); ++arg) - all.push_back (arg->_first); - - return all; -} - -//////////////////////////////////////////////////////////////////////////////// -std::vector Arguments::operator_list () -{ - std::vector all; - for (unsigned int i = 0; i < NUM_OPERATORS; ++i) - all.push_back (operators[i].op); - - return all; -} - -//////////////////////////////////////////////////////////////////////////////// -std::string Arguments::combine () -{ - std::string combined; - - std::vector ::iterator arg; - for (arg = this->begin (); arg != this->end (); ++arg) - { - if (arg != this->begin ()) - combined += " "; - - combined += arg->_first; - } - - return combined; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Arguments::find_command (std::string& command) -{ - std::vector ::iterator arg; - for (arg = this->begin (); arg != this->end (); ++arg) - { - if (arg->_third == "command") - { - command = arg->_first; - return true; - } - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -std::string Arguments::find_limit () -{ - std::vector ::reverse_iterator arg; - for (arg = this->rbegin (); arg != this->rend (); ++arg) - if (arg->_first.find ("limit:") != std::string::npos) - return arg->_first.substr (6); - - return ""; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Arguments::is_multipart ( - const std::string& input, - std::vector & parts) -{ - parts.clear (); - Nibbler n (input); - std::string part; - while (n.getQuoted ('"', part) || - n.getQuoted ('\'', part) || -// n.getQuoted ('/', part) || <--- this line breaks subst. - n.getUntilWS (part)) - { - n.skipWS (); - parts.push_back (part); - } - - return parts.size () > 1 ? true : false; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Arguments::is_command ( - const std::vector & keywords, - std::string& command) -{ - std::vector matches; - if (autoComplete (command, - keywords, - matches, - context.config.getInteger ("abbreviation.minimum")) == 1) - { - command = matches[0]; - return true; - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// :['"][]['"] -bool Arguments::is_attr (const std::string& input) -{ - Nibbler n (input); - std::string name; - std::string value; - - if (n.getUntilOneOf ("=:", name)) - { - if (name.length () == 0) - return false; - - if (name.find_first_of (non_word_chars) != std::string::npos) - return false; - - if (n.skip (':')) - { - // Exclude certain URLs, that look like attrs. - if (input.find ('@') <= n.cursor () || - input.find ('/') <= n.cursor ()) - return false; - - // Both quoted and unquoted Att's are accepted. - // Consider removing this for a stricter parse. - if (n.getQuoted ('"', value) || - n.getQuoted ('\'', value) || - n.getUntil (' ', value) || - n.getUntilEOS (value) || - n.depleted ()) - { - // Validate and canonicalize attribute name. - if (is_attribute (name, name)) - return true; - } - } - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// .:['"]['"] -bool Arguments::is_attmod (const std::string& input) -{ - Nibbler n (input); - std::string name; - std::string modifier; - std::string value; - - if (n.getUntilOneOf (".", name)) - { - if (name.length () == 0) - return false; - - if (name.find_first_of (non_word_chars) != std::string::npos) - return false; - - if (n.skip ('.')) - { - n.skip ('~'); - n.getUntil (':', modifier); - - if (modifier.length () == 0) - return false; - } - - if (n.skip (':')) - { - // Exclude certain URLs, that look like attrs. - if (input.find ('@') <= n.cursor () || - input.find ('/') <= n.cursor ()) - return false; - - // Both quoted and unquoted Att's are accepted. - // Consider removing this for a stricter parse. - if (n.getQuoted ('"', value) || - n.getQuoted ('\'', value) || - n.getUntil (' ', value) || - n.getUntilEOS (value) || - n.depleted ()) - { - // Validate and canonicalize attribute and modifier names. - if (is_attribute (name, name) && - is_modifier (modifier)) - return true; - } - } - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// ///[g] -// -// Note: one problem with this is that substitutions start with a /, and so any -// two-directory absolute path, (or three-level, if the third directory is -// named 'g') can be misinterpreted. To help (but not solve) this, if a -// substition exists on the local disk, it is not considered a subst. -// This needs to be changed to a better solution. -bool Arguments::is_subst (const std::string& input) -{ - std::string from; - std::string to; - Nibbler n (input); - if (n.skip ('/') && - n.getUntil ('/', from) && - from.length () && - n.skip ('/') && - n.getUntil ('/', to) && - n.skip ('/')) - { - n.skip ('g'); - if (n.depleted () && - ! Directory (input).exists ()) // Ouch - expensive call. - return true; - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// // -bool Arguments::is_pattern (const std::string& input) -{ - std::string::size_type first = input.find ('/', 0); - std::string::size_type second = input.find ('/', first + 1); - std::string::size_type third = input.find ('/', second + 1); - - if (first == 0 && - second == input.length () - 1 && - third == std::string::npos && - second > 1) - return true; - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// [-][,[-]] -bool Arguments::is_id (const std::string& input) -{ - Nibbler n (input); - int id; - - if (n.getUnsignedInt (id)) - { - if (n.skip ('-')) - { - if (!n.getUnsignedInt (id)) - return false; - } - - while (n.skip (',')) - { - if (n.getUnsignedInt (id)) - { - if (n.skip ('-')) - { - if (!n.getUnsignedInt (id)) - return false; - } - } - else - return false; - } - } - else - return false; - - return n.depleted (); -} - -//////////////////////////////////////////////////////////////////////////////// -// [,...] -bool Arguments::is_uuid (const std::string& input) -{ - Nibbler n (input); - std::string uuid; - - if (n.getUUID (uuid)) - { - while (n.skip (',')) - { - if (!n.getUUID (uuid)) - return false; - } - } - else - return false; - - return n.depleted (); -} - -//////////////////////////////////////////////////////////////////////////////// -// [+-] -bool Arguments::is_tag (const std::string& input) -{ - if (input.length () > 1 && - (input[0] == '+' || - input[0] == '-') && - noSpaces (input) && - input.find ('+', 1) == std::string::npos && - input.find ('-', 1) == std::string::npos) - { - return true; - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Arguments::is_operator (const std::string& input) -{ - for (unsigned int i = 0; i < NUM_OPERATORS; ++i) - if (operators[i].op == input) - return true; - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Arguments::is_operator ( - const std::string& input, - char& type, - int& precedence, - char& associativity) -{ - for (unsigned int i = 0; i < NUM_OPERATORS; ++i) - if (operators[i].op == input) - { - type = operators[i].type; - precedence = operators[i].precedence; - associativity = operators[i].associativity; - return true; - } - - 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; -} - -//////////////////////////////////////////////////////////////////////////////// -// Canonicalize attribute names. -bool Arguments::is_attribute (const std::string& input, std::string& canonical) -{ - // Guess at the full attribute name. - std::vector candidates; - for (unsigned i = 0; i < NUM_ATT_NAMES; ++i) - { - // Short-circuit: exact matches cause immediate return. - if (attributeNames[i] == input) - { - canonical = input; - return true; - } - - candidates.push_back (attributeNames[i]); - } - - for (unsigned i = 0; i < NUM_MODIFIABLE_ATT_NAMES; ++i) - { - // Short-circuit: exact matches cause immediate return. - if (modifiableAttributeNames[i] == input) - { - canonical = input; - return true; - } - - candidates.push_back (modifiableAttributeNames[i]); - } - - std::vector matches; - autoComplete (input, - candidates, - matches, - context.config.getInteger ("abbreviation.minimum")); - - 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 candidates; - for (unsigned i = 0; i < NUM_MODIFIER_NAMES; ++i) - { - // Short-circuit: exact matches cause immediate return. - if (modifierNames[i] == input) - return true; - - candidates.push_back (modifierNames[i]); - } - - std::vector matches; - autoComplete (input, - candidates, - matches, - context.config.getInteger ("abbreviation.minimum")); - - if (matches.size () == 1) - return true; - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Arguments::is_expression (const std::string& input) -{ - std::string unquoted = unquoteText (input); - - // Look for space-separated operators. - std::vector tokens; - split (tokens, unquoted, ' '); - std::vector ::iterator token; - for (token = tokens.begin (); token != tokens.end (); ++token) - if (is_operator (*token)) - return true; - - // Look for bare or cuddled operators. - Lexer lexer (unquoted); - lexer.skipWhitespace (true); - lexer.coalesceAlpha (true); - lexer.coalesceDigits (true); - lexer.coalesceQuoted (true); - - tokens.clear (); - lexer.tokenize (tokens); - - for (token = tokens.begin (); token != tokens.end (); ++token) - if (is_operator (*token)) - return true; - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// :['"]['"] -bool Arguments::extract_attr ( - const std::string& input, - std::string& name, - std::string& value) -{ - Nibbler n (input); - - // Ensure a clean parse. - name = ""; - value = ""; - - if (n.getUntil (':', name)) - { - if (name.length () == 0) - throw std::string ("Missing attribute name"); - - if (n.skip (':')) - { - // Both quoted and unquoted Att's are accepted. - // Consider removing this for a stricter parse. - if (n.getQuoted ('"', value) || - n.getQuoted ('\'', value) || - n.getUntilEOS (value)) - { - return true; - } - } - else - throw std::string ("Missing : after attribute name."); - } - else - throw std::string ("Missing : after attribute name."); - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// .:['"]['"] -bool Arguments::extract_attmod ( - const std::string& input, - std::string& name, - std::string& modifier, - std::string& value, - std::string& sense) -{ - Nibbler n (input); - - // Ensure a clean parse. - name = ""; - value = ""; - modifier = ""; - sense = "positive"; - - if (n.getUntil (".", name)) - { - if (name.length () == 0) - throw std::string ("Missing attribute name"); - - if (n.skip ('.')) - { - if (n.skip ('~')) - sense = "negative"; - - if (n.getUntil (':', modifier)) - { - if (!Arguments::valid_modifier (modifier)) - throw std::string ("The name '") + modifier + "' is not a valid modifier."; - } - else - throw std::string ("Missing . or : after modifier."); - } - else - throw std::string ("Missing modifier."); - - if (n.skip (':')) - { - // Both quoted and unquoted Att's are accepted. - // Consider removing this for a stricter parse. - if (n.getQuoted ('"', value) || - n.getQuoted ('\'', value) || - n.getUntilEOS (value)) - { - return true; - } - } - else - throw std::string ("Missing : after attribute name."); - } - else - throw std::string ("Missing : after attribute name."); - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Arguments::extract_subst ( - const std::string& input, - std::string& from, - std::string& to, - bool& global) -{ - Nibbler n (input); - if (n.skip ('/') && - n.getUntil ('/', from) && - n.skip ('/') && - n.getUntil ('/', to) && - n.skip ('/')) - { - global = n.skip ('g'); - - if (from == "") - throw std::string ("Cannot substitute an empty string."); - - if (!n.depleted ()) - throw std::string ("Unrecognized character(s) at end of substitution."); - - return true; - } - else - throw std::string ("Malformed substitution."); - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Arguments::extract_pattern (const std::string& input, std::string& pattern) -{ - Nibbler n (input); - if (n.skip ('/') && - n.getUntil ('/', pattern) && - n.skip ('/')) - { - if (pattern == "") - throw std::string ("Cannot search for an empty pattern."); - - if (!n.depleted ()) - throw std::string ("Unrecognized character(s) at end of pattern."); - - return true; - } - else - throw std::string ("Malformed pattern."); - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -// A sequence can be: -// -// a single ID: 1 -// a list of IDs: 1,3,5 -// a list of IDs: 1 3 5 -// a range: 5-10 -// or a combination: 1,3,5-10 12 -// -// If a sequence is followed by a non-number, then subsequent numbers are not -// interpreted as IDs. For example: -// -// 1 2 three 4 -// -// The sequence is "1 2". -// -// The _first number found in the command line is assumed to be a sequence. If -// there are two sequences, only the _first is recognized, for example: -// -// 1,2 three 4,5 -// -// The sequence is "1,2". -// -bool Arguments::extract_id (const std::string& input, std::vector & sequence) -{ - Nibbler n (input); - - int id; - - if (n.getUnsignedInt (id)) - { - sequence.push_back (id); - - if (n.skip ('-')) - { - int end; - if (!n.getUnsignedInt (end)) - throw std::string ("Unrecognized ID after hyphen."); - - if (id > end) - throw std::string ("Inverted range 'high-low' instead of 'low-high'"); - - for (int n = id + 1; n <= end; ++n) - sequence.push_back (n); - } - - while (n.skip (',')) - { - if (n.getUnsignedInt (id)) - { - sequence.push_back (id); - - if (n.skip ('-')) - { - int end; - if (!n.getUnsignedInt (end)) - throw std::string ("Unrecognized ID after hyphen."); - - if (id > end) - throw std::string ("Inverted range 'high-low' instead of 'low-high'"); - - for (int n = id + 1; n <= end; ++n) - sequence.push_back (n); - } - } - else - throw std::string ("Malformed ID"); - } - } - else - throw std::string ("Malformed ID"); - - return n.depleted (); -} - -//////////////////////////////////////////////////////////////////////////////// -bool Arguments::extract_uuid ( - const std::string& input, - std::vector & sequence) -{ - Nibbler n (input); - - std::string uuid; - if (n.getUUID (uuid)) - { - sequence.push_back (uuid); - - while (n.skip (',')) - { - if (!n.getUUID (uuid)) - throw std::string ("Unrecognized UUID after comma."); - - sequence.push_back (uuid); - } - } - else - throw std::string ("Malformed UUID"); - - if (!n.depleted ()) - throw std::string ("Unrecognized character(s) at end of pattern."); - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Arguments::extract_tag ( - const std::string& input, - char& type, - std::string& tag) -{ - if (input.length () > 1) - { - type = input[0]; - tag = input.substr (1); - return true; - } - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Arguments::extract_operator ( - const std::string& input, - std::string& op) -{ - op = input; - return true; -} - -//////////////////////////////////////////////////////////////////////////////// -// Almost all arguments are filters, except: -// subst -// program -// command -// rc -// override -// -// Special case: attr "limit" is ignored. -Arguments Arguments::extract_read_only_filter () -{ - Arguments filter; - - std::vector ::iterator arg; - for (arg = this->begin (); arg != this->end (); ++arg) - { - // Excluded. - if (arg->_third == "program" || - arg->_third == "command" || - arg->_third == "rc" || - arg->_third == "override") - { - } - - // Included. - else if (arg->_third == "tag" || - arg->_third == "pattern" || - arg->_third == "attr" || - arg->_third == "attmod" || - arg->_third == "id" || - arg->_third == "uuid" || - arg->_third == "op" || - arg->_third == "exp" || - arg->_third == "word") - { - // "limit" is special - it is recognized but not included in filters. - if (arg->_first.find ("limit:") == std::string::npos) - filter.push_back (*arg); - } - - // Error. - else - { - // substitution - throw std::string ("A ") - + arg->_third - + " '" - + arg->_first - + "' is not allowed in a read-only filter."; - } - } - - return filter; -} - -//////////////////////////////////////////////////////////////////////////////// -// A write filter includes id/uuid anywhere on the command line, but any other -// filter elements must occur before the command. -// -// Special case: attr "limit" is ignored. -Arguments Arguments::extract_write_filter () -{ - Arguments filter; - bool before_command = true; - - std::vector ::iterator arg; - for (arg = this->begin (); arg != this->end (); ++arg) - { - // Only use args prior to command. - if (arg->_third == "command") - before_command = false; - - // Excluded. - else if (arg->_third == "program" || - arg->_third == "rc" || - arg->_third == "override") - { - } - - // Included regardless of position. - else if (arg->_third == "id" || - arg->_third == "uuid") - { - filter.push_back (*arg); - } - - // Included if prior to command. - else if (arg->_third == "tag" || - arg->_third == "pattern" || - arg->_third == "attr" || - arg->_third == "attmod" || - arg->_third == "op" || - arg->_third == "exp" || - arg->_third == "word") - { - if (before_command) - { - // "limit" is special - it is recognized but not included in filters. - if (arg->_first.find ("limit:") == std::string::npos) - filter.push_back (*arg); - } - } - - // Error. - else - { - if (before_command) - { - // substitution - throw std::string ("A substitution '") - + arg->_first - + "' is not allowed in a write command filter."; - } - } - } - - return filter; -} - -//////////////////////////////////////////////////////////////////////////////// -Arguments Arguments::extract_modifications (bool include_seq/* = false*/) -{ - Arguments modifications; - - bool seen_command = false; - std::vector ::iterator arg; - for (arg = this->begin (); arg != this->end (); ++arg) - { - // Only use args after command. - if (arg->_third == "command") - { - seen_command = true; - } - - // Sequence excluded regardless of location. - else if (arg->_third == "id" || - arg->_third == "uuid") - { - if (include_seq) - modifications.push_back (Triple (arg->_first, arg->_second, "word")); - } - - else if (seen_command) - { - // Excluded. - if (arg->_third == "program" || - arg->_third == "rc" || - arg->_third == "override") - { - } - - // Included. - else if (arg->_third == "tag" || - arg->_third == "attr" || - arg->_third == "subst" || - arg->_third == "op" || - arg->_third == "exp" || - arg->_third == "word") - { - // "limit" is special - it is recognized but not included in filters. - if (arg->_first.find ("limit:") == std::string::npos) - modifications.push_back (*arg); - } - - // Error. - else - { - // Instead of errors, simply downgrade these to 'word'. - if (arg->_third == "pattern" || - arg->_third == "attmod" || - arg->_third == "id" || - arg->_third == "uuid") - { - arg->_third = "word"; - modifications.push_back (*arg); - } - else - throw std::string ("Error: unrecognized argument in modifications."); - } - } - } - - return modifications; -} - -//////////////////////////////////////////////////////////////////////////////// -Arguments Arguments::extract_simple_words () -{ - Arguments filter; - - std::vector ::iterator arg; - for (arg = this->begin (); arg != this->end (); ++arg) - { - // Excluded. - if (arg->_third == "program" || - arg->_third == "command" || - arg->_third == "rc" || - arg->_third == "override" || - arg->_third == "attr" || - arg->_third == "attmod") - { - ; - } - - // Included. - else if (arg->_third == "tag" || - arg->_third == "pattern" || - arg->_third == "subst" || - arg->_third == "id" || - arg->_third == "uuid" || - arg->_third == "op" || - arg->_third == "exp" || - arg->_third == "word") - { - // "limit" is special - it is recognized but not included in filters. - if (arg->_first.find ("limit:") == std::string::npos) - filter.push_back (*arg); - } - - // Error. - else - throw std::string ("Argument '") + arg->_first + "' is not allowed " - "with this command."; - } - - return filter; -} - -//////////////////////////////////////////////////////////////////////////////// -bool Arguments::valid_modifier (const std::string& modifier) -{ - for (unsigned int i = 0; i < NUM_MODIFIER_NAMES; ++i) - if (modifierNames[i] == modifier) - return true; - - return false; -} - -//////////////////////////////////////////////////////////////////////////////// -void Arguments::dump (const std::string& label) -{ - // Set up a color mapping. - std::map color_map; - color_map["program"] = Color ("white on blue"); - 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 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; - out << color_debug.colorize (label) - << "\n"; - - ViewText view; - view.width (context.getWidth ()); - view.leftMargin (2); - for (unsigned int i = 0; i < this->size (); ++i) - view.add (Column::factory ("string", "")); - - view.addRow (); - view.addRow (); - view.addRow (); - - for (unsigned int i = 0; i < this->size (); ++i) - { - std::string arg = (*this)[i]._first; - std::string expanded = (*this)[i]._second; - std::string category = (*this)[i]._third; - - Color c; - if (color_map[expanded].nontrivial ()) - c = color_map[expanded]; - else if (color_map[category].nontrivial ()) - c = color_map[category]; - else - c = color_map["none"]; - - view.set (0, i, arg, c); - view.set (1, i, expanded, c); - view.set (2, i, category, c); - } - - out << view.render (); - context.debug (out.str ()); -} - -//////////////////////////////////////////////////////////////////////////////// diff --git a/src/Arguments.h b/src/Arguments.h deleted file mode 100644 index efc3fbc50..000000000 --- a/src/Arguments.h +++ /dev/null @@ -1,143 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// taskwarrior - a command line task list manager. -// -// Copyright 2006 - 2011, Paul Beckingham, Federico Hernandez. -// All rights reserved. -// -// This program is free software; you can redistribute it and/or modify it under -// the terms of the GNU General Public License as published by the Free Software -// Foundation; either version 2 of the License, or (at your option) any later -// version. -// -// This program is distributed in the hope that it will be useful, but WITHOUT -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -// details. -// -// You should have received a copy of the GNU General Public License along with -// this program; if not, write to the -// -// Free Software Foundation, Inc., -// 51 Franklin Street, Fifth Floor, -// Boston, MA -// 02110-1301 -// USA -// -//////////////////////////////////////////////////////////////////////////////// -#ifndef INCLUDED_ARGUMENTS -#define INCLUDED_ARGUMENTS -#define L10N // Localization complete. - -#include -#include -#include - -#define ARGUMENTS_SEQUENCE_MAX_RANGE 1000 - -class Triple -{ -public: - Triple ( - const std::string& one, - const std::string& two, - const std::string& three) - : _first (one) - , _second (two) - , _third (three) - { - } - - Triple (const Triple& other) - { - _first = other._first; - _second = other._second; - _third = other._third; - } - - Triple& operator= (const Triple& other) - { - if (this != &other) - { - _first = other._first; - _second = other._second; - _third = other._third; - } - - return *this; - } - - bool operator== (const Triple& other) const - { - return _first == other._first && - _second == other._second && - _third == other._third; - } - -public: - std::string _first; // Represents token to be evaluated - std::string _second; // Represents progressive token type - std::string _third; // Represent original category -}; - -class Arguments : public std::vector -{ -public: - Arguments (); - ~Arguments (); - - void capture (int, const char**); - void capture (const std::string&); - void capture_first (const std::string&); - void categorize (); - - void append_stdin (); - void rc_override (std::string&, File&); - void get_data_location (std::string&); - void apply_overrides (); - void resolve_aliases (); - void inject_defaults (); - - std::vector list (); - static std::vector operator_list (); - std::string combine (); - - bool find_command (std::string&); - std::string find_limit (); - - static bool is_multipart (const std::string&, std::vector &); - static bool is_command (const std::vector &, std::string&); - static bool is_attr (const std::string&); - static bool is_attmod (const std::string&); - static bool is_subst (const std::string&); - static bool is_pattern (const std::string&); - static bool is_id (const std::string&); - static bool is_uuid (const std::string&); - 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&); - - static bool extract_attr (const std::string&, std::string&, std::string&); - static bool extract_attmod (const std::string&, std::string&, std::string&, std::string&, std::string&); - static bool extract_subst (const std::string&, std::string&, std::string&, bool&); - static bool extract_pattern (const std::string&, std::string&); - static bool extract_id (const std::string&, std::vector &); - static bool extract_uuid (const std::string&, std::vector &); - static bool extract_tag (const std::string&, char&, std::string&); - static bool extract_operator (const std::string&, std::string&); - - Arguments extract_read_only_filter (); - Arguments extract_write_filter (); - Arguments extract_modifications (bool include_seq = false); - Arguments extract_simple_words (); - - static bool valid_modifier (const std::string&); - - void dump (const std::string&); -}; - -#endif -//////////////////////////////////////////////////////////////////////////////// diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 47b368513..419778396 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -7,7 +7,6 @@ include_directories (${CMAKE_SOURCE_DIR} set (task_SRCS A3.cpp A3.h API.cpp API.h - Arguments.cpp Arguments.h Att.cpp Att.h Color.cpp Color.h Config.cpp Config.h diff --git a/src/Context.cpp b/src/Context.cpp index 292e49e15..428079252 100644 --- a/src/Context.cpp +++ b/src/Context.cpp @@ -72,21 +72,18 @@ int Context::initialize (int argc, const char** argv) try { - // char** argv --> std::vector Context::args. - args.capture (argc, argv); + // char** argv --> std::vector Context::a3. a3.capture (argc, argv); // echo one two -- three | task zero --> task zero one two // 'three' is left in the input buffer. - args.append_stdin (); a3.append_stdin (); // Assume default .taskrc and .task locations. assumeLocations (); // Process 'rc:' command line override, and remove the argument from the - // Context::args. - args.rc_override (home_dir, rc_file); + // Context::a3. a3.categorize (); a3.rc_override (home_dir, rc_file); @@ -107,7 +104,6 @@ int Context::initialize (int argc, const char** argv) // Handle Aliases. loadAliases (); - args.resolve_aliases (); a3.resolve_aliases (); // Apply rc overrides to Context::config, capturing raw args for later use. @@ -124,11 +120,9 @@ int Context::initialize (int argc, const char** argv) Column::factory (columns); // Categorize all arguments one more time. THIS IS NECESSARY. - args.categorize (); a3.categorize (); // Handle default command and assumed 'info' command. - args.inject_defaults (); a3.inject_defaults (); a3.dump ("Context::initialize"); // TODO Remove. @@ -526,7 +520,7 @@ void Context::clear () { tdb.clear (); // TODO Obsolete // tdb2.clear (); - args.clear (); + a3.clear (); clearMessages (); } @@ -539,7 +533,7 @@ void Context::updateXtermTitle () if (config.getBoolean ("xterm.title")) { std::string command; - args.find_command (command); + a3.find_command (command); std::string title; join (title, " ", a3.list ()); diff --git a/src/Context.h b/src/Context.h index af533aaf5..46bbb8831 100644 --- a/src/Context.h +++ b/src/Context.h @@ -39,7 +39,6 @@ #include #include #include -#include #include class Context @@ -82,7 +81,6 @@ private: public: std::string program; - Arguments args; A3 a3; std::string home_dir; File rc_file; diff --git a/src/DOM.cpp b/src/DOM.cpp index b311f62cc..a8877ca5b 100644 --- a/src/DOM.cpp +++ b/src/DOM.cpp @@ -115,11 +115,11 @@ const std::string DOM::get (const std::string& name) name.substr (0, 8) == "context.") { if (name == "context.program") - return /*_cache[name] =*/ context.args[0]._first; + return /*_cache[name] =*/ context.a3[0]._raw; else if (name == "context.args") { - return /*_cache[name] =*/ context.args.combine (); + return /*_cache[name] =*/ context.a3.combine (); } else if (name == "context.width") { @@ -238,7 +238,7 @@ const std::string DOM::get (const std::string& name, const Task& task) return /*_cache[name] =*/ copy_name; // - else if (Arguments::is_attribute (name, canonical)) + else if (A3::is_attribute (name, canonical)) return task.get (canonical); // . diff --git a/src/commands/CmdAdd.cpp b/src/commands/CmdAdd.cpp index 68bca4b22..24dbd5b9a 100644 --- a/src/commands/CmdAdd.cpp +++ b/src/commands/CmdAdd.cpp @@ -56,8 +56,7 @@ int CmdAdd::execute (std::string& output) task.set ("uuid", uuid ()); // Apply the command line modifications to the new task. - Arguments modifications = context.args.extract_modifications (true); - modify_task_description_replace (task, modifications); + modify_task_description_replace (task, context.a3.extract_modifications ()); apply_defaults (task); // Only valid tasks can be added. diff --git a/src/commands/CmdAnnotate.cpp b/src/commands/CmdAnnotate.cpp index 57488d2a5..4e8186df9 100644 --- a/src/commands/CmdAnnotate.cpp +++ b/src/commands/CmdAnnotate.cpp @@ -69,7 +69,7 @@ int CmdAnnotate::execute (std::string& output) } // Apply the command line modifications to the completed task. - Arguments modifications = context.args.extract_modifications (); + A3 modifications = context.a3.extract_modifications (); if (!modifications.size ()) throw std::string (STRING_CMD_XPEND_NEED_TEXT); diff --git a/src/commands/CmdAppend.cpp b/src/commands/CmdAppend.cpp index 988ee6e75..aaebb84e9 100644 --- a/src/commands/CmdAppend.cpp +++ b/src/commands/CmdAppend.cpp @@ -69,7 +69,7 @@ int CmdAppend::execute (std::string& output) } // Apply the command line modifications to the started task. - Arguments modifications = context.args.extract_modifications (); + A3 modifications = context.a3.extract_modifications (); if (!modifications.size ()) throw std::string (STRING_CMD_XPEND_NEED_TEXT); diff --git a/src/commands/CmdBurndown.cpp b/src/commands/CmdBurndown.cpp index d092f649f..1eb7b52ee 100644 --- a/src/commands/CmdBurndown.cpp +++ b/src/commands/CmdBurndown.cpp @@ -998,10 +998,10 @@ int CmdBurndownMonthly::execute (std::string& output) Chart chart ('M'); // Use any filter as a title. - if (context.args.size () > 2) + if (context.a3.size () > 2) { std::string combined = "(" - + context.args.extract_read_only_filter ().combine () + + context.a3.extract_filter ().combine () + ")"; chart.description (combined); } @@ -1042,10 +1042,10 @@ int CmdBurndownWeekly::execute (std::string& output) Chart chart ('W'); // Use any filter as a title. - if (context.args.size () > 2) + if (context.a3.size () > 2) { std::string combined = "(" - + context.args.extract_read_only_filter ().combine () + + context.a3.extract_filter ().combine () + ")"; chart.description (combined); } @@ -1086,10 +1086,10 @@ int CmdBurndownDaily::execute (std::string& output) Chart chart ('D'); // Use any filter as a title. - if (context.args.size () > 2) + if (context.a3.size () > 2) { std::string combined = "(" - + context.args.extract_read_only_filter ().combine () + + context.a3.extract_filter ().combine () + ")"; chart.description (combined); } diff --git a/src/commands/CmdCustom.cpp b/src/commands/CmdCustom.cpp index 0871896e7..f7dc5b85b 100644 --- a/src/commands/CmdCustom.cpp +++ b/src/commands/CmdCustom.cpp @@ -86,10 +86,7 @@ int CmdCustom::execute (std::string& output) split (filterArgs, reportFilter, ' '); std::vector ::iterator arg; for (arg = filterArgs.begin (); arg != filterArgs.end (); ++ arg) - { - context.args.capture_first (*arg); context.a3.capture_first (*arg); - } context.a3.categorize (); context.a3.dump ("CmdCustom::execute"); @@ -290,7 +287,7 @@ void CmdCustom::getLimits (const std::string& report, int& rows, int& lines) // If the custom report has a defined limit, then allow a numeric override. // This is an integer specified as a filter (limit:10). - std::string limit = context.args.find_limit (); + std::string limit = context.a3.find_limit (); if (limit != "") { if (limit == "page") diff --git a/src/commands/CmdDelete.cpp b/src/commands/CmdDelete.cpp index 183b5fe2f..93401248e 100644 --- a/src/commands/CmdDelete.cpp +++ b/src/commands/CmdDelete.cpp @@ -70,7 +70,7 @@ int CmdDelete::execute (std::string& output) } // Apply the command line modifications to the new task. - Arguments modifications = context.args.extract_modifications (); + A3 modifications = context.a3.extract_modifications (); std::vector ::iterator task; for (task = filtered.begin (); task != filtered.end (); ++task) diff --git a/src/commands/CmdDone.cpp b/src/commands/CmdDone.cpp index 93c218124..b7df8e7af 100644 --- a/src/commands/CmdDone.cpp +++ b/src/commands/CmdDone.cpp @@ -69,7 +69,7 @@ int CmdDone::execute (std::string& output) } // Apply the command line modifications to the completed task. - Arguments modifications = context.args.extract_modifications (); + A3 modifications = context.a3.extract_modifications (); Permission permission; if (filtered.size () > (size_t) context.config.getInteger ("bulk")) diff --git a/src/commands/CmdDuplicate.cpp b/src/commands/CmdDuplicate.cpp index cf3e7cc75..fe8c2fdda 100644 --- a/src/commands/CmdDuplicate.cpp +++ b/src/commands/CmdDuplicate.cpp @@ -69,7 +69,7 @@ int CmdDuplicate::execute (std::string& output) } // Apply the command line modifications to the completed task. - Arguments modifications = context.args.extract_modifications (); + A3 modifications = context.a3.extract_modifications (); std::vector ::iterator task; for (task = filtered.begin (); task != filtered.end (); ++task) diff --git a/src/commands/CmdExec.cpp b/src/commands/CmdExec.cpp index 5c872f1cf..0feef0df2 100644 --- a/src/commands/CmdExec.cpp +++ b/src/commands/CmdExec.cpp @@ -48,12 +48,12 @@ CmdExec::CmdExec () int CmdExec::execute (std::string& output) { std::string command_line; - std::vector ::iterator arg; - for (arg = context.args.begin (); arg != context.args.end (); ++arg) + std::vector ::iterator arg; + for (arg = context.a3.begin (); arg != context.a3.end (); ++arg) { - if (arg != context.args.begin () && - arg->_first != "execute") - command_line += arg->_first; + if (arg != context.a3.begin () && + arg->_raw != "execute") + command_line += arg->_raw; } return system (command_line.c_str ()); diff --git a/src/commands/CmdLog.cpp b/src/commands/CmdLog.cpp index c7a176a77..2a80894ae 100644 --- a/src/commands/CmdLog.cpp +++ b/src/commands/CmdLog.cpp @@ -56,7 +56,7 @@ int CmdLog::execute (std::string& output) task.set ("uuid", uuid ()); // Apply the command line modifications to the new task. - Arguments modifications = context.args.extract_modifications (); + A3 modifications = context.a3.extract_modifications (); modify_task_description_replace (task, modifications); apply_defaults (task); diff --git a/src/commands/CmdModify.cpp b/src/commands/CmdModify.cpp index b4cfe6344..cb2ea6cbb 100644 --- a/src/commands/CmdModify.cpp +++ b/src/commands/CmdModify.cpp @@ -69,7 +69,7 @@ int CmdModify::execute (std::string& output) } // Apply the command line modifications to the new task. - Arguments modifications = context.args.extract_modifications (); + A3 modifications = context.a3.extract_modifications (); Permission permission; if (filtered.size () > (size_t) context.config.getInteger ("bulk")) diff --git a/src/commands/CmdPrepend.cpp b/src/commands/CmdPrepend.cpp index c4e204b58..0180fb6f5 100644 --- a/src/commands/CmdPrepend.cpp +++ b/src/commands/CmdPrepend.cpp @@ -69,7 +69,7 @@ int CmdPrepend::execute (std::string& output) } // Apply the command line modifications to the started task. - Arguments modifications = context.args.extract_modifications (); + A3 modifications = context.a3.extract_modifications (); if (!modifications.size ()) throw std::string (STRING_CMD_XPEND_NEED_TEXT); diff --git a/src/commands/CmdShow.cpp b/src/commands/CmdShow.cpp index 0e9d5b44c..4328f0b8e 100644 --- a/src/commands/CmdShow.cpp +++ b/src/commands/CmdShow.cpp @@ -57,7 +57,7 @@ int CmdShow::execute (std::string& output) // Obtain the arguments from the description. That way, things like '--' // have already been handled. - if (context.args.size () > 2) + if (context.a3.size () > 2) throw std::string (STRING_CMD_SHOW_ARGS); int width = context.getWidth (); diff --git a/src/commands/CmdStart.cpp b/src/commands/CmdStart.cpp index 2277d94fa..89d91f3b2 100644 --- a/src/commands/CmdStart.cpp +++ b/src/commands/CmdStart.cpp @@ -69,7 +69,7 @@ int CmdStart::execute (std::string& output) } // Apply the command line modifications to the started task. - Arguments modifications = context.args.extract_modifications (); + A3 modifications = context.a3.extract_modifications (); Permission permission; if (filtered.size () > (size_t) context.config.getInteger ("bulk")) diff --git a/src/commands/CmdStop.cpp b/src/commands/CmdStop.cpp index 5af30fd83..63be74fa8 100644 --- a/src/commands/CmdStop.cpp +++ b/src/commands/CmdStop.cpp @@ -69,7 +69,7 @@ int CmdStop::execute (std::string& output) } // Apply the command line modifications to the stopped task. - Arguments modifications = context.args.extract_modifications (); + A3 modifications = context.a3.extract_modifications (); Permission permission; if (filtered.size () > (size_t) context.config.getInteger ("bulk")) diff --git a/src/commands/Command.cpp b/src/commands/Command.cpp index cd8d8eacc..7eb8c1a48 100644 --- a/src/commands/Command.cpp +++ b/src/commands/Command.cpp @@ -271,13 +271,7 @@ void Command::filter (std::vector & input, std::vector & output) A3 filt = context.a3.extract_filter (); filt.dump ("extract_filter"); - Arguments f; - if (read_only ()) - f = context.args.extract_read_only_filter (); - else - f = context.args.extract_write_filter (); - - if (f.size ()) + if (filt.size ()) { E9 e (filt); @@ -299,13 +293,7 @@ void Command::filter (std::vector & output) A3 filt = context.a3.extract_filter (); filt.dump ("extract_filter"); - Arguments f; - if (read_only ()) - f = context.args.extract_read_only_filter (); - else - f = context.args.extract_write_filter (); - - if (f.size ()) + if (filt.size ()) { const std::vector & pending = context.tdb2.pending.get_tasks (); E9 e (filt); @@ -316,7 +304,7 @@ void Command::filter (std::vector & output) if (e.evalFilter (*task)) output.push_back (*task); - if (! filter_shortcut (f)) + if (! filter_shortcut (filt)) { const std::vector & completed = context.tdb2.completed.get_tasks (); // TODO Optional for (task = completed.begin (); task != completed.end (); ++task) @@ -343,23 +331,23 @@ void Command::filter (std::vector & output) //////////////////////////////////////////////////////////////////////////////// // If the filter contains the restriction "status:pending", as the first filter // term, then completed.data does not need to be loaded. -bool Command::filter_shortcut (const Arguments& filter) +bool Command::filter_shortcut (const A3& filter) { /**/ if (filter.size () >= 3) { - std::cout << "# filter[0] " << filter[0]._first << "\n" - << "# filter[1] " << filter[1]._first << "\n" - << "# filter[2] " << filter[2]._first << "\n"; + std::cout << "# filter[0] " << filter[0]._raw << "\n" + << "# filter[1] " << filter[1]._raw << "\n" + << "# filter[2] " << filter[2]._raw << "\n"; } /**/ // Postfix: <"pending"> <=> // 0 1 2 - if (filter.size () >= 3 && - filter[0]._first == "status" && - filter[1]._first.find ("pending") != std::string::npos && - filter[2]._first == "=") + if (filter.size () >= 3 && + filter[0]._raw == "status" && + filter[1]._raw.find ("pending") != std::string::npos && + filter[2]._raw == "=") return true; return false; @@ -367,7 +355,7 @@ bool Command::filter_shortcut (const Arguments& filter) //////////////////////////////////////////////////////////////////////////////// // Apply the modifications in arguments to the task. -void Command::modify_task_description_replace (Task& task, Arguments& arguments) +void Command::modify_task_description_replace (Task& task, const A3& arguments) { std::string description; modify_task (task, arguments, description); @@ -377,7 +365,7 @@ void Command::modify_task_description_replace (Task& task, Arguments& arguments) } //////////////////////////////////////////////////////////////////////////////// -void Command::modify_task_description_prepend (Task& task, Arguments& arguments) +void Command::modify_task_description_prepend (Task& task, const A3& arguments) { std::string description; modify_task (task, arguments, description); @@ -387,7 +375,7 @@ void Command::modify_task_description_prepend (Task& task, Arguments& arguments) } //////////////////////////////////////////////////////////////////////////////// -void Command::modify_task_description_append (Task& task, Arguments& arguments) +void Command::modify_task_description_append (Task& task, const A3& arguments) { std::string description; modify_task (task, arguments, description); @@ -397,7 +385,7 @@ void Command::modify_task_description_append (Task& task, Arguments& arguments) } //////////////////////////////////////////////////////////////////////////////// -void Command::modify_task_annotate (Task& task, Arguments& arguments) +void Command::modify_task_annotate (Task& task, const A3& arguments) { std::string description; modify_task (task, arguments, description); @@ -410,20 +398,20 @@ void Command::modify_task_annotate (Task& task, Arguments& arguments) // Worker function that does all the updates, but never overwrites description. void Command::modify_task ( Task& task, - Arguments& arguments, + const A3& arguments, std::string& description) { - std::vector ::iterator arg; + std::vector ::const_iterator arg; for (arg = arguments.begin (); arg != arguments.end (); ++arg) { // Attributes are essentially name:value pairs, and correspond directly // to stored attributes. - if (arg->_third == "attr") + if (arg->_category == "attr") { std::string name; std::string value; - Arguments::extract_attr (arg->_first, name, value); - if (Arguments::is_attribute (name, name)) // Canonicalize + A3::extract_attr (arg->_raw, name, value); + if (A3::is_attribute (name, name)) // Canonicalize { // All values must be eval'd first. A3 fragment; @@ -462,11 +450,11 @@ void Command::modify_task ( // Tags need special handling because they are essentially a vector stored // in a single string, therefore Task::{add,remove}Tag must be called as // appropriate. - else if (arg->_third == "tag") + else if (arg->_category == "tag") { char type; std::string value; - Arguments::extract_tag (arg->_first, type, value); + A3::extract_tag (arg->_raw, type, value); if (type == '+') task.addTag (value); @@ -475,29 +463,29 @@ void Command::modify_task ( } // Words and operators are aggregated into a description. - else if (arg->_third == "word" || - arg->_third == "op") + else if (arg->_category == "word" || + arg->_category == "op") { if (description.length ()) description += " "; - description += arg->_first; + description += arg->_raw; } // Substitutions. - else if (arg->_third == "subst") + else if (arg->_category == "subst") { std::string from; std::string to; bool global; - Arguments::extract_subst (arg->_first, from, to, global); + A3::extract_subst (arg->_raw, from, to, global); task.substitute (from, to, global); } // Any additional argument types are indicative of a failure in - // Arguments::extract_modifications. + // A3::extract_modifications. else - throw format (STRING_CMD_MOD_UNEXPECTED, arg->_first); + throw format (STRING_CMD_MOD_UNEXPECTED, arg->_raw); } } diff --git a/src/commands/Command.h b/src/commands/Command.h index a42ff551d..309c0ea4e 100644 --- a/src/commands/Command.h +++ b/src/commands/Command.h @@ -32,7 +32,7 @@ #include #include #include -#include +#include class Command { @@ -55,13 +55,13 @@ public: protected: void filter (std::vector &, std::vector &); void filter (std::vector &); - bool filter_shortcut (const Arguments&); + bool filter_shortcut (const A3&); - void modify_task_description_replace (Task&, Arguments&); - void modify_task_description_prepend (Task&, Arguments&); - void modify_task_description_append (Task&, Arguments&); - void modify_task_annotate (Task&, Arguments&); - void modify_task (Task&, Arguments&, std::string&); + void modify_task_description_replace (Task&, const A3&); + void modify_task_description_prepend (Task&, const A3&); + void modify_task_description_append (Task&, const A3&); + void modify_task_annotate (Task&, const A3&); + void modify_task (Task&, const A3&, std::string&); void apply_defaults (Task&); protected: