Expression

- Added configurable 'abbreviation.minimum' (default:2) setting to
  control how auto-completion works.
This commit is contained in:
Paul Beckingham 2011-07-20 10:48:59 -04:00
parent a6fadaee67
commit 197524a5fc
16 changed files with 139 additions and 52 deletions

2
NEWS
View file

@ -56,6 +56,8 @@ New configuration options in taskwarrior 2.0.0
- New 'exit.on.missing.db' control causes an exit if the ~/.task directory - New 'exit.on.missing.db' control causes an exit if the ~/.task directory
(or override) is missing. (or override) is missing.
- New 'color.completed' and 'color.deleted' color rules. - New 'color.completed' and 'color.deleted' color rules.
- New 'abbreviation.minimum' setting controls how short an abbreviated
command or value may be.
Newly deprecated features in taskwarrior 2.0.0 Newly deprecated features in taskwarrior 2.0.0

View file

@ -387,6 +387,11 @@ of the longer-term rate. The calculation is as follows:
rate = (long-term-rate * (1 - bias)) + (short-term-rate * bias) rate = (long-term-rate * (1 - bias)) + (short-term-rate * bias)
.TP
.B abbreviation.minimum=2
Minimum length of any abbreviated command/value. This means that "ve", "ver",
"vers", "versi", "versio" will all equate to "version", but "v" will not.
Default is 2.
.TP .TP
.B debug=off .B debug=off
Taskwarrior has a debug mode that causes diagnostic output to be displayed. Taskwarrior has a debug mode that causes diagnostic output to be displayed.

View file

@ -798,7 +798,10 @@ bool Arguments::is_command (
std::string& command) std::string& command)
{ {
std::vector <std::string> matches; std::vector <std::string> matches;
if (autoComplete (command, keywords, matches) == 1) if (autoComplete (command,
keywords,
matches,
context.config.getInteger ("abbreviation.minimum")) == 1)
{ {
command = matches[0]; command = matches[0];
return true; return true;
@ -1090,7 +1093,10 @@ bool Arguments::is_attribute (const std::string& input, std::string& canonical)
} }
std::vector <std::string> matches; std::vector <std::string> matches;
autoComplete (input, candidates, matches); autoComplete (input,
candidates,
matches,
context.config.getInteger ("abbreviation.minimum"));
if (matches.size () == 1) if (matches.size () == 1)
{ {
@ -1116,7 +1122,10 @@ bool Arguments::is_modifier (const std::string& input)
} }
std::vector <std::string> matches; std::vector <std::string> matches;
autoComplete (input, candidates, matches); autoComplete (input,
candidates,
matches,
context.config.getInteger ("abbreviation.minimum"));
if (matches.size () == 1) if (matches.size () == 1)
return true; return true;

View file

@ -301,7 +301,10 @@ bool Att::validNameValue (
candidates.push_back (modifiableNames[i]); candidates.push_back (modifiableNames[i]);
std::vector <std::string> matches; std::vector <std::string> matches;
autoComplete (name, candidates, matches); autoComplete (name,
candidates,
matches,
context.config.getInteger ("abbreviation.minimum"));
if (matches.size () == 0) if (matches.size () == 0)
return false; return false;
@ -327,7 +330,10 @@ bool Att::validNameValue (
candidates.push_back (modifierNames[i]); candidates.push_back (modifierNames[i]);
matches.clear (); matches.clear ();
autoComplete (mod, candidates, matches); autoComplete (mod,
candidates,
matches,
context.config.getInteger ("abbreviation.minimum"));
if (matches.size () == 0) if (matches.size () == 0)
throw std::string ("Unrecognized modifier '") + mod + "'."; throw std::string ("Unrecognized modifier '") + mod + "'.";
@ -454,7 +460,10 @@ bool Att::validNameValue (
candidates.push_back ("deleted"); candidates.push_back ("deleted");
candidates.push_back ("recurring"); candidates.push_back ("recurring");
candidates.push_back ("waiting"); candidates.push_back ("waiting");
autoComplete (value, candidates, matches); autoComplete (value,
candidates,
matches,
context.config.getInteger ("abbreviation.minimum"));
if (matches.size () == 1) if (matches.size () == 1)
value = matches[0]; value = matches[0];

View file

@ -102,6 +102,7 @@ std::string Config::defaults =
"expressions=on # Support for algebraic expressions\n" "expressions=on # Support for algebraic expressions\n"
"patterns=on # Support for regex patterns\n" "patterns=on # Support for regex patterns\n"
"json.array=off # Enclose JSON output in [ ]\n" "json.array=off # Enclose JSON output in [ ]\n"
"abbreviation.minimum=2 # Shortest allowed abbreviation\n"
"\n" "\n"
"# Dates\n" "# Dates\n"
"dateformat=m/d/Y # Preferred input and display date format\n" "dateformat=m/d/Y # Preferred input and display date format\n"

View file

@ -27,7 +27,6 @@
#define L10N // Localization complete. #define L10N // Localization complete.
#include <iostream> // TODO Remove
#include <sstream> #include <sstream>
#include <Context.h> #include <Context.h>
#include <Nibbler.h> #include <Nibbler.h>
@ -192,16 +191,16 @@ const std::string DOM::get (const std::string& name)
// TODO <uuid>.recur // TODO <uuid>.recur
// TODO <uuid>.depends // TODO <uuid>.depends
// //
// {.entry,.start,.end,.due,.until,.wait} // {entry,start,end,due,until,wait}
// .description // description
// .project // project
// .priority // priority
// .parent // parent
// .status // status
// .tags // tags
// .urgency // urgency
// .recur // recur
// .depends // depends
// //
const std::string DOM::get (const std::string& name, const Task& task) const std::string DOM::get (const std::string& name, const Task& task)
{ {
@ -295,7 +294,6 @@ bool DOM::is_literal (std::string& input)
if (Date::valid (input, context.config.get ("dateformat"))) if (Date::valid (input, context.config.get ("dateformat")))
{ {
input = Date (input).toEpochString (); input = Date (input).toEpochString ();
std::cout << "# DOM::is_literal '" << input << "' --> date\n";
return true; return true;
} }
@ -323,7 +321,6 @@ bool DOM::is_literal (std::string& input)
if (n.getInt (i) && n.depleted ()) if (n.getInt (i) && n.depleted ())
return true; return true;
// std::cout << "# DOM::is_literal '" << input << "' --> unknown\n";
return false; return false;
} }

View file

@ -27,6 +27,7 @@
#define L10N // Localization complete. #define L10N // Localization complete.
#include <iostream> // TODO Remove.
#include <iomanip> #include <iomanip>
#include <sstream> #include <sstream>
#include <time.h> #include <time.h>
@ -175,17 +176,18 @@ void Date::toMDY (int& m, int& d, int& y)
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
const std::string Date::toString (const std::string& format /*= "m/d/Y" */) const const std::string Date::toString (
const std::string& format /*= "m/d/Y" */) const
{ {
// Making this local copy seems to fix a bug. Remove the local copy and you'll // Making this local copy seems to fix a bug. Remove the local copy and
// see segmentation faults and all kinds of gibberish. // you'll see segmentation faults and all kinds of gibberish.
std::string localFormat = format; std::string localFormat = format;
char buffer[12]; char buffer[12];
std::string formatted; std::string formatted;
for (unsigned int i = 0; i < localFormat.length (); ++i) for (unsigned int i = 0; i < localFormat.length (); ++i)
{ {
char c = localFormat[i]; int c = localFormat[i];
switch (c) switch (c)
{ {
case 'm': sprintf (buffer, "%d", this->month ()); break; case 'm': sprintf (buffer, "%d", this->month ()); break;
@ -794,8 +796,9 @@ bool Date::isRelativeDate (const std::string& input)
supported.push_back ("later"); supported.push_back ("later");
supported.push_back ("someday"); supported.push_back ("someday");
// Hard-coded 3, despite rc.abbreviation.minimum.
std::vector <std::string> matches; std::vector <std::string> matches;
if (autoComplete (in, supported, matches) == 1) if (autoComplete (in, supported, matches, 3) == 1)
{ {
std::string found = matches[0]; std::string found = matches[0];

View file

@ -33,6 +33,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <Context.h>
#include <text.h> #include <text.h>
#include <util.h> #include <util.h>
#include <i18n.h> #include <i18n.h>
@ -91,6 +92,8 @@ static const char* durations[] =
#define NUM_DURATIONS (sizeof (durations) / sizeof (durations[0])) #define NUM_DURATIONS (sizeof (durations) / sizeof (durations[0]))
extern Context context;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
Duration::Duration () Duration::Duration ()
: mSecs (0) : mSecs (0)
@ -339,7 +342,10 @@ bool Duration::valid (const std::string& input)
supported.push_back (durations[i]); supported.push_back (durations[i]);
std::vector <std::string> matches; std::vector <std::string> matches;
if (autoComplete (units, supported, matches) == 1) if (autoComplete (units,
supported,
matches,
context.config.getInteger ("abbreviation.minimum")) == 1)
return true; return true;
return false; return false;
@ -376,7 +382,10 @@ void Duration::parse (const std::string& input)
mSecs = 0; mSecs = 0;
std::vector <std::string> matches; std::vector <std::string> matches;
if (autoComplete (units, supported, matches) == 1) if (autoComplete (units,
supported,
matches,
context.config.getInteger ("abbreviation.minimum")) == 1)
{ {
std::string match = matches[0]; std::string match = matches[0];

View file

@ -174,7 +174,7 @@ void Expression::eval (const Task& task, std::vector <Variant>& value_stack)
right._raw_type = value_stack.back ()._raw_type; right._raw_type = value_stack.back ()._raw_type;
} }
value_stack.pop_back (); value_stack.pop_back ();
// std::cout << "# right raw=" << right._raw << " type=" << right._type << " value=" << right._string << "\n"; // std::cout << "# right variant " << right.dump () << "\n";
// lvalue (dom). // lvalue (dom).
Variant left (value_stack.back ()); Variant left (value_stack.back ());
@ -185,7 +185,7 @@ void Expression::eval (const Task& task, std::vector <Variant>& value_stack)
left._raw_type = value_stack.back ()._raw_type; left._raw_type = value_stack.back ()._raw_type;
} }
value_stack.pop_back (); value_stack.pop_back ();
// std::cout << "# left raw=" << left._raw << " type=" << left._type << " value=" << left._string << "\n"; // std::cout << "# left variant " << left.dump () << "\n";
// Now the binary operators. // Now the binary operators.
if (arg->_first == "and") if (arg->_first == "and")
@ -463,7 +463,7 @@ void Expression::create_variant (
const std::string& value, const std::string& value,
const std::string& type) const std::string& type)
{ {
// std::cout << "# operand '" << value << "' as " << type << "\n"; // std::cout << "# create_variant " << value << "/" << type << "\n";
// DOM references are not resolved until the operator is processed. This // DOM references are not resolved until the operator is processed. This
// preserves the original name, which helps determine how to apply the // preserves the original name, which helps determine how to apply the

View file

@ -41,6 +41,12 @@ Variant::Variant ()
: _type (v_unknown) : _type (v_unknown)
, _raw ("") , _raw ("")
, _raw_type ("") , _raw_type ("")
, _bool (false)
, _integer (0)
, _double (0.0)
, _string ("")
, _date (0)
, _duration (0)
{ {
} }
@ -66,44 +72,86 @@ Variant::Variant (const Variant& other)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
Variant::Variant (const bool input) Variant::Variant (const bool input)
: _type (v_boolean)
, _raw ("")
, _raw_type ("")
, _bool (input)
, _integer (0)
, _double (0.0)
, _string ("")
, _date (0)
, _duration (0)
{ {
_type = v_boolean;
_bool = input;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
Variant::Variant (const int input) Variant::Variant (const int input)
: _type (v_integer)
, _raw ("")
, _raw_type ("")
, _bool (false)
, _integer (input)
, _double (0.0)
, _string ("")
, _date (0)
, _duration (0)
{ {
_type = v_integer;
_integer = input;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
Variant::Variant (const double& input) Variant::Variant (const double& input)
: _type (v_double)
, _raw ("")
, _raw_type ("")
, _bool (false)
, _integer (0)
, _double (input)
, _string ("")
, _date (0)
, _duration (0)
{ {
_type = v_double;
_double = input;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
Variant::Variant (const std::string& input) Variant::Variant (const std::string& input)
: _type (v_string)
, _raw ("")
, _raw_type ("")
, _bool (false)
, _integer (0)
, _double (0.0)
, _string (input)
, _date (0)
, _duration (0)
{ {
_type = v_string;
_string = input;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
Variant::Variant (const Date& input) Variant::Variant (const Date& input)
: _type (v_date)
, _raw ("")
, _raw_type ("")
, _bool (false)
, _integer (0)
, _double (0.0)
, _string ("")
, _date (input)
, _duration (0)
{ {
_type = v_date;
_date = input;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
Variant::Variant (const Duration& input) Variant::Variant (const Duration& input)
: _type (v_duration)
, _raw ("")
, _raw_type ("")
, _bool (false)
, _integer (0)
, _double (0.0)
, _string ("")
, _date (0)
, _duration (input)
{ {
_type = v_duration;
_duration = input;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View file

@ -123,11 +123,11 @@ int CmdCalendar::execute (std::string& output)
for (arg = args.begin (); arg != args.end (); ++arg) for (arg = args.begin (); arg != args.end (); ++arg)
{ {
// Some version of "calendar". // Some version of "calendar".
if (autoComplete (lowerCase (*arg), commandNames, matches) == 1) if (autoComplete (lowerCase (*arg), commandNames, matches, context.config.getInteger ("abbreviation.minimum")) == 1)
continue; continue;
// "due". // "due".
else if (autoComplete (lowerCase (*arg), keywordNames, matches) == 1) else if (autoComplete (lowerCase (*arg), keywordNames, matches, context.config.getInteger ("abbreviation.minimum")) == 1)
getpendingdate = true; getpendingdate = true;
// "y". // "y".
@ -147,7 +147,7 @@ int CmdCalendar::execute (std::string& output)
} }
// "January" etc. // "January" etc.
else if (autoComplete (lowerCase (*arg), monthNames, matches) == 1) else if (autoComplete (lowerCase (*arg), monthNames, matches, context.config.getInteger ("abbreviation.minimum")) == 1)
{ {
argMonth = Date::monthOfYear (matches[0]); argMonth = Date::monthOfYear (matches[0]);
if (argMonth == -1) if (argMonth == -1)

View file

@ -67,6 +67,7 @@ int CmdShow::execute (std::string& output)
// Note that there is a leading and trailing space, to make it easier to // Note that there is a leading and trailing space, to make it easier to
// search for whole words. // search for whole words.
std::string recognized = std::string recognized =
" abbreviation.minimum"
" active.indicator" " active.indicator"
" annotations" " annotations"
" avoidlastcolumn" " avoidlastcolumn"

View file

@ -74,7 +74,7 @@ void initializeColorRules ()
{ {
// Add the leading "color." string. // Add the leading "color." string.
std::string rule = "color." + *p; std::string rule = "color." + *p;
autoComplete (rule, rules, results); autoComplete (rule, rules, results, 3); // Hard-coded 3.
std::vector <std::string>::iterator r; std::vector <std::string>::iterator r;
for (r = results.begin (); r != results.end (); ++r) for (r = results.begin (); r != results.end (); ++r)

View file

@ -482,7 +482,8 @@ void guess (
std::string& candidate) std::string& candidate)
{ {
std::vector <std::string> matches; std::vector <std::string> matches;
autoComplete (candidate, options, matches); autoComplete (candidate, options, matches,
context.config.getInteger ("abbreviation.minimum"));
if (1 == matches.size ()) if (1 == matches.size ())
candidate = matches[0]; candidate = matches[0];

View file

@ -75,7 +75,7 @@ bool confirm (const std::string& question)
std::getline (std::cin, answer); std::getline (std::cin, answer);
answer = std::cin.eof() ? STRING_UTIL_CONFIRM_NO : lowerCase (trim (answer)); answer = std::cin.eof() ? STRING_UTIL_CONFIRM_NO : lowerCase (trim (answer));
autoComplete (answer, options, matches); autoComplete (answer, options, matches, 1); // Hard-coded 1.
} }
while (matches.size () != 1); while (matches.size () != 1);
@ -109,7 +109,7 @@ int confirm3 (const std::string& question)
std::getline (std::cin, answer); std::getline (std::cin, answer);
answer = trim (answer); answer = trim (answer);
autoComplete (answer, options, matches); autoComplete (answer, options, matches, 1); // Hard-coded 1.
} }
while (matches.size () != 1); while (matches.size () != 1);
@ -150,7 +150,7 @@ int confirm4 (const std::string& question)
std::getline (std::cin, answer); std::getline (std::cin, answer);
answer = trim (answer); answer = trim (answer);
autoComplete (answer, options, matches); autoComplete (answer, options, matches, 1); // Hard-coded 1.
} }
while (matches.size () != 1); while (matches.size () != 1);
@ -190,7 +190,8 @@ std::string formatBytes (size_t bytes)
int autoComplete ( int autoComplete (
const std::string& partial, const std::string& partial,
const std::vector<std::string>& list, const std::vector<std::string>& list,
std::vector<std::string>& matches) std::vector<std::string>& matches,
int minimum/* = 2*/)
{ {
matches.clear (); matches.clear ();
@ -211,7 +212,8 @@ int autoComplete (
} }
// Maintain a list of partial matches. // Maintain a list of partial matches.
else if (length <= item->length () && else if (length >= (unsigned) minimum &&
length <= item->length () &&
partial == item->substr (0, length)) partial == item->substr (0, length))
matches.push_back (*item); matches.push_back (*item);
} }

View file

@ -62,7 +62,7 @@ int confirm3 (const std::string&);
int confirm4 (const std::string&); int confirm4 (const std::string&);
void delay (float); void delay (float);
std::string formatBytes (size_t); std::string formatBytes (size_t);
int autoComplete (const std::string&, const std::vector<std::string>&, std::vector<std::string>&); int autoComplete (const std::string&, const std::vector<std::string>&, std::vector<std::string>&, int minimum = 1);
#if defined(HAVE_UUID) && !defined(HAVE_UUID_UNPARSE_LOWER) #if defined(HAVE_UUID) && !defined(HAVE_UUID_UNPARSE_LOWER)
void uuid_unparse_lower (uuid_t uu, char *out); void uuid_unparse_lower (uuid_t uu, char *out);