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
(or override) is missing.
- 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

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

View file

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

View file

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

View file

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

View file

@ -27,6 +27,7 @@
#define L10N // Localization complete.
#include <iostream> // TODO Remove.
#include <iomanip>
#include <sstream>
#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
// see segmentation faults and all kinds of gibberish.
// Making this local copy seems to fix a bug. Remove the local copy and
// you'll see segmentation faults and all kinds of gibberish.
std::string localFormat = format;
char buffer[12];
std::string formatted;
for (unsigned int i = 0; i < localFormat.length (); ++i)
{
char c = localFormat[i];
int c = localFormat[i];
switch (c)
{
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 ("someday");
// Hard-coded 3, despite rc.abbreviation.minimum.
std::vector <std::string> matches;
if (autoComplete (in, supported, matches) == 1)
if (autoComplete (in, supported, matches, 3) == 1)
{
std::string found = matches[0];

View file

@ -33,6 +33,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <Context.h>
#include <text.h>
#include <util.h>
#include <i18n.h>
@ -91,6 +92,8 @@ static const char* durations[] =
#define NUM_DURATIONS (sizeof (durations) / sizeof (durations[0]))
extern Context context;
////////////////////////////////////////////////////////////////////////////////
Duration::Duration ()
: mSecs (0)
@ -339,7 +342,10 @@ bool Duration::valid (const std::string& input)
supported.push_back (durations[i]);
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 false;
@ -376,7 +382,10 @@ void Duration::parse (const std::string& input)
mSecs = 0;
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];

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;
}
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).
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;
}
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.
if (arg->_first == "and")
@ -463,7 +463,7 @@ void Expression::create_variant (
const std::string& value,
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
// preserves the original name, which helps determine how to apply the

View file

@ -41,6 +41,12 @@ Variant::Variant ()
: _type (v_unknown)
, _raw ("")
, _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)
: _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)
: _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)
: _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)
: _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)
: _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)
: _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)
{
// Some version of "calendar".
if (autoComplete (lowerCase (*arg), commandNames, matches) == 1)
if (autoComplete (lowerCase (*arg), commandNames, matches, context.config.getInteger ("abbreviation.minimum")) == 1)
continue;
// "due".
else if (autoComplete (lowerCase (*arg), keywordNames, matches) == 1)
else if (autoComplete (lowerCase (*arg), keywordNames, matches, context.config.getInteger ("abbreviation.minimum")) == 1)
getpendingdate = true;
// "y".
@ -147,7 +147,7 @@ int CmdCalendar::execute (std::string& output)
}
// "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]);
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
// search for whole words.
std::string recognized =
" abbreviation.minimum"
" active.indicator"
" annotations"
" avoidlastcolumn"

View file

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

View file

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

View file

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

View file

@ -62,7 +62,7 @@ int confirm3 (const std::string&);
int confirm4 (const std::string&);
void delay (float);
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)
void uuid_unparse_lower (uuid_t uu, char *out);