Bug 445 - The command 'task h' should be ambiguous, yet works
- Fixed bug #445, which caused task to not notice that the command 'h' is ambiguous. This was caused by mistakenly first autoCompleting against a set of alias names, during canonicalization, instead of autoCompleting against the whole set of possible commands and aliases, then doing the canonicalization. The order was reversed. - Also populated list of all commands with alias names, so the above could be corrected.
This commit is contained in:
@@ -36,6 +36,8 @@
|
|||||||
+ Fixed bug #439, which ignored dateformat.annotation for sparse annotations.
|
+ Fixed bug #439, which ignored dateformat.annotation for sparse annotations.
|
||||||
+ Fixed bug #441, which misparsed '/a/a:/' as an attribute, rather than a
|
+ Fixed bug #441, which misparsed '/a/a:/' as an attribute, rather than a
|
||||||
substitution (thanks to Michelle Crane).
|
substitution (thanks to Michelle Crane).
|
||||||
|
+ Fixed bug #445, which caused task to not notice that the command 'h' is
|
||||||
|
ambiguous.
|
||||||
+ Fixed problem with command line configuration overrides that had no
|
+ Fixed problem with command line configuration overrides that had no
|
||||||
values.
|
values.
|
||||||
|
|
||||||
|
|||||||
148
src/Cmd.cpp
148
src/Cmd.cpp
@@ -56,44 +56,64 @@ Cmd::~Cmd ()
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Determines whether the string represents a unique command name or custom
|
// Determines whether the string represents a unique command name or custom
|
||||||
// report name.
|
// report name.
|
||||||
|
//
|
||||||
|
// To be a valid command:
|
||||||
|
// 1. 'input' should autocomplete to one of 'commands'.
|
||||||
bool Cmd::valid (const std::string& input)
|
bool Cmd::valid (const std::string& input)
|
||||||
{
|
{
|
||||||
load ();
|
load ();
|
||||||
|
|
||||||
std::vector <std::string> matches;
|
std::vector <std::string> matches;
|
||||||
autoComplete (lowerCase (context.canonicalize (input)), commands, matches);
|
autoComplete (lowerCase (input), commands, matches);
|
||||||
return matches.size () == 1 ? true : false;
|
if (matches.size () == 1)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Determines whether the string represents a valid custom report name.
|
// Determines whether the string represents a valid custom report name.
|
||||||
|
//
|
||||||
|
// To be a valid custom command:
|
||||||
|
// 1. 'input' should autocomplete to one of 'commands'.
|
||||||
|
// 2. the result, canonicalized, should autocomplete to one of 'customreports'.
|
||||||
bool Cmd::validCustom (const std::string& input)
|
bool Cmd::validCustom (const std::string& input)
|
||||||
{
|
{
|
||||||
load ();
|
load ();
|
||||||
|
|
||||||
std::vector <std::string> matches;
|
std::vector <std::string> matches;
|
||||||
autoComplete (lowerCase (context.canonicalize (input)), customReports, matches);
|
autoComplete (lowerCase (input), commands, matches);
|
||||||
return matches.size () == 1 ? true : false;
|
if (matches.size () == 1)
|
||||||
|
{
|
||||||
|
std::string canonical = context.canonicalize (matches[0]);
|
||||||
|
matches.clear ();
|
||||||
|
autoComplete (canonical, customReports, matches);
|
||||||
|
if (matches.size () == 1)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// To be a valid custom command:
|
||||||
|
// 1. 'input' should autocomplete to one of 'commands'.
|
||||||
|
// 2. the result may then canonicalize to another command.
|
||||||
void Cmd::parse (const std::string& input)
|
void Cmd::parse (const std::string& input)
|
||||||
{
|
{
|
||||||
load ();
|
load ();
|
||||||
|
|
||||||
std::string candidate = lowerCase (context.canonicalize (input));
|
|
||||||
|
|
||||||
std::vector <std::string> matches;
|
std::vector <std::string> matches;
|
||||||
autoComplete (candidate, commands, matches);
|
autoComplete (input, commands, matches);
|
||||||
if (1 == matches.size ())
|
if (1 == matches.size ())
|
||||||
command = matches[0];
|
command = context.canonicalize (matches[0]);
|
||||||
|
|
||||||
else if (0 == matches.size ())
|
else if (0 == matches.size ())
|
||||||
command = "";
|
command = "";
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::string error = "Ambiguous command '" + candidate + "' - could be either of "; // TODO i18n
|
std::string error = "Ambiguous command '" + input + "' - could be either of "; // TODO i18n
|
||||||
|
|
||||||
std::sort (matches.begin (), matches.end ());
|
std::sort (matches.begin (), matches.end ());
|
||||||
std::string combined;
|
std::string combined;
|
||||||
@@ -124,35 +144,35 @@ void Cmd::load ()
|
|||||||
commands.push_back ("ghistory.annual");
|
commands.push_back ("ghistory.annual");
|
||||||
|
|
||||||
// Commands whose names are localized.
|
// Commands whose names are localized.
|
||||||
commands.push_back (context.stringtable.get (CMD_ADD, "add"));
|
commands.push_back (context.stringtable.get (CMD_ADD, "add"));
|
||||||
commands.push_back (context.stringtable.get (CMD_APPEND, "append"));
|
commands.push_back (context.stringtable.get (CMD_APPEND, "append"));
|
||||||
commands.push_back (context.stringtable.get (CMD_ANNOTATE, "annotate"));
|
commands.push_back (context.stringtable.get (CMD_ANNOTATE, "annotate"));
|
||||||
commands.push_back (context.stringtable.get (CMD_DENOTATE, "denotate"));
|
commands.push_back (context.stringtable.get (CMD_DENOTATE, "denotate"));
|
||||||
commands.push_back (context.stringtable.get (CMD_CALENDAR, "calendar"));
|
commands.push_back (context.stringtable.get (CMD_CALENDAR, "calendar"));
|
||||||
commands.push_back (context.stringtable.get (CMD_COLORS, "colors"));
|
commands.push_back (context.stringtable.get (CMD_COLORS, "colors"));
|
||||||
commands.push_back (context.stringtable.get (CMD_CONFIG, "config"));
|
commands.push_back (context.stringtable.get (CMD_CONFIG, "config"));
|
||||||
commands.push_back (context.stringtable.get (CMD_SHOW, "show"));
|
commands.push_back (context.stringtable.get (CMD_SHOW, "show"));
|
||||||
commands.push_back (context.stringtable.get (CMD_DELETE, "delete"));
|
commands.push_back (context.stringtable.get (CMD_DELETE, "delete"));
|
||||||
commands.push_back (context.stringtable.get (CMD_DONE, "done"));
|
commands.push_back (context.stringtable.get (CMD_DONE, "done"));
|
||||||
commands.push_back (context.stringtable.get (CMD_DUPLICATE, "duplicate"));
|
commands.push_back (context.stringtable.get (CMD_DUPLICATE, "duplicate"));
|
||||||
commands.push_back (context.stringtable.get (CMD_EDIT, "edit"));
|
commands.push_back (context.stringtable.get (CMD_EDIT, "edit"));
|
||||||
commands.push_back (context.stringtable.get (CMD_HELP, "help"));
|
commands.push_back (context.stringtable.get (CMD_HELP, "help"));
|
||||||
commands.push_back (context.stringtable.get (CMD_IMPORT, "import"));
|
commands.push_back (context.stringtable.get (CMD_IMPORT, "import"));
|
||||||
commands.push_back (context.stringtable.get (CMD_INFO, "info"));
|
commands.push_back (context.stringtable.get (CMD_INFO, "info"));
|
||||||
commands.push_back (context.stringtable.get (CMD_LOG, "log"));
|
commands.push_back (context.stringtable.get (CMD_LOG, "log"));
|
||||||
commands.push_back (context.stringtable.get (CMD_PREPEND, "prepend"));
|
commands.push_back (context.stringtable.get (CMD_PREPEND, "prepend"));
|
||||||
commands.push_back (context.stringtable.get (CMD_PROJECTS, "projects"));
|
commands.push_back (context.stringtable.get (CMD_PROJECTS, "projects"));
|
||||||
#ifdef FEATURE_SHELL
|
#ifdef FEATURE_SHELL
|
||||||
commands.push_back (context.stringtable.get (CMD_SHELL, "shell"));
|
commands.push_back (context.stringtable.get (CMD_SHELL, "shell"));
|
||||||
#endif
|
#endif
|
||||||
commands.push_back (context.stringtable.get (CMD_START, "start"));
|
commands.push_back (context.stringtable.get (CMD_START, "start"));
|
||||||
commands.push_back (context.stringtable.get (CMD_STATS, "stats"));
|
commands.push_back (context.stringtable.get (CMD_STATS, "stats"));
|
||||||
commands.push_back (context.stringtable.get (CMD_STOP, "stop"));
|
commands.push_back (context.stringtable.get (CMD_STOP, "stop"));
|
||||||
commands.push_back (context.stringtable.get (CMD_SUMMARY, "summary"));
|
commands.push_back (context.stringtable.get (CMD_SUMMARY, "summary"));
|
||||||
commands.push_back (context.stringtable.get (CMD_TAGS, "tags"));
|
commands.push_back (context.stringtable.get (CMD_TAGS, "tags"));
|
||||||
commands.push_back (context.stringtable.get (CMD_TIMESHEET, "timesheet"));
|
commands.push_back (context.stringtable.get (CMD_TIMESHEET, "timesheet"));
|
||||||
commands.push_back (context.stringtable.get (CMD_UNDO, "undo"));
|
commands.push_back (context.stringtable.get (CMD_UNDO, "undo"));
|
||||||
commands.push_back (context.stringtable.get (CMD_VERSION, "version"));
|
commands.push_back (context.stringtable.get (CMD_VERSION, "version"));
|
||||||
|
|
||||||
// Now load the custom reports.
|
// Now load the custom reports.
|
||||||
std::vector <std::string> all;
|
std::vector <std::string> all;
|
||||||
@@ -180,6 +200,10 @@ void Cmd::load ()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now load the aliases.
|
||||||
|
foreach (i, context.aliases)
|
||||||
|
commands.push_back (i->first);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,32 +226,32 @@ void Cmd::allCommands (std::vector <std::string>& all) const
|
|||||||
// Commands that do not directly modify the data files.
|
// Commands that do not directly modify the data files.
|
||||||
bool Cmd::isReadOnlyCommand ()
|
bool Cmd::isReadOnlyCommand ()
|
||||||
{
|
{
|
||||||
if (command == "_projects" ||
|
if (command == "_projects" ||
|
||||||
command == "_tags" ||
|
command == "_tags" ||
|
||||||
command == "_commands" ||
|
command == "_commands" ||
|
||||||
command == "_ids" ||
|
command == "_ids" ||
|
||||||
command == "_config" ||
|
command == "_config" ||
|
||||||
command == "_version" ||
|
command == "_version" ||
|
||||||
command == "export.csv" ||
|
command == "export.csv" ||
|
||||||
command == "export.ical" ||
|
command == "export.ical" ||
|
||||||
command == "export.yaml" ||
|
command == "export.yaml" ||
|
||||||
command == "history.monthly" ||
|
command == "history.monthly" ||
|
||||||
command == "history.annual" ||
|
command == "history.annual" ||
|
||||||
command == "ghistory.monthly" ||
|
command == "ghistory.monthly" ||
|
||||||
command == "ghistory.annual" ||
|
command == "ghistory.annual" ||
|
||||||
command == context.stringtable.get (CMD_CALENDAR, "calendar") ||
|
command == context.stringtable.get (CMD_CALENDAR, "calendar") ||
|
||||||
command == context.stringtable.get (CMD_COLORS, "colors") ||
|
command == context.stringtable.get (CMD_COLORS, "colors") ||
|
||||||
command == context.stringtable.get (CMD_CONFIG, "config") ||
|
command == context.stringtable.get (CMD_CONFIG, "config") ||
|
||||||
command == context.stringtable.get (CMD_SHOW, "show") ||
|
command == context.stringtable.get (CMD_SHOW, "show") ||
|
||||||
command == context.stringtable.get (CMD_HELP, "help") ||
|
command == context.stringtable.get (CMD_HELP, "help") ||
|
||||||
command == context.stringtable.get (CMD_INFO, "info") ||
|
command == context.stringtable.get (CMD_INFO, "info") ||
|
||||||
command == context.stringtable.get (CMD_PROJECTS, "projects") ||
|
command == context.stringtable.get (CMD_PROJECTS, "projects") ||
|
||||||
command == context.stringtable.get (CMD_SHELL, "shell") ||
|
command == context.stringtable.get (CMD_SHELL, "shell") ||
|
||||||
command == context.stringtable.get (CMD_STATS, "stats") ||
|
command == context.stringtable.get (CMD_STATS, "stats") ||
|
||||||
command == context.stringtable.get (CMD_SUMMARY, "summary") ||
|
command == context.stringtable.get (CMD_SUMMARY, "summary") ||
|
||||||
command == context.stringtable.get (CMD_TAGS, "tags") ||
|
command == context.stringtable.get (CMD_TAGS, "tags") ||
|
||||||
command == context.stringtable.get (CMD_TIMESHEET, "timesheet") ||
|
command == context.stringtable.get (CMD_TIMESHEET, "timesheet") ||
|
||||||
command == context.stringtable.get (CMD_VERSION, "version") ||
|
command == context.stringtable.get (CMD_VERSION, "version") ||
|
||||||
validCustom (command))
|
validCustom (command))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
|||||||
@@ -475,10 +475,6 @@ int handleCompletionCommands (std::string &outs)
|
|||||||
std::vector <std::string> commands;
|
std::vector <std::string> commands;
|
||||||
context.cmd.allCommands (commands);
|
context.cmd.allCommands (commands);
|
||||||
|
|
||||||
// Concatenate a list of all aliases.
|
|
||||||
foreach (name, context.aliases)
|
|
||||||
commands.push_back (name->first);
|
|
||||||
|
|
||||||
// Sort alphabetically.
|
// Sort alphabetically.
|
||||||
std::sort (commands.begin (), commands.end ());
|
std::sort (commands.begin (), commands.end ());
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user