zcmdcat: zsh completion: group commands by category

This commit is contained in:
Daniel Shahaf 2015-07-20 05:31:36 +00:00 committed by Paul Beckingham
parent 5ca1dd540e
commit c78fc47402
4 changed files with 59 additions and 10 deletions

View file

@ -58,7 +58,7 @@ _task_conjunctions=(
'>'
)
_task_cmds=($(task _commands; task _aliases))
_task_zshcmds=( ${(f)"$(task _zshcommands)"} )
_task_zshcmds=( ${(f)"$(task _zshcommands)"} sentinel:sentinel:sentinel )
_task_aliases=($(task _aliases))
@ -224,6 +224,34 @@ _task_id() {
_describe -t values 'task IDs' _task_zshids
}
# subcommand-only function
(( $+functions[_task_subcommands] )) ||
_task_subcommands() {
local -a subcommands
local _zshcmd
local cmd category desc
local lastcategory=''
# The list is sorted by category, in the right order.
for _zshcmd in "$_task_zshcmds[@]"; do
# Parse out the three fields
cmd=${_zshcmd%%:*}
category=${${_zshcmd#*:}%%:*}
desc=${_zshcmd#*:*:}
# Present each category as soon as the first entry in the *next* category
# is seen.
if [[ $category != $lastcategory && -n $lastcategory ]]; then
_describe -t ${lastcategory}-commands "task ${lastcategory} command" subcommands
subcommands=()
fi
# Log the subcommand; we will process it in some future iteration.
subcommands+=( "$cmd:$desc" )
lastcategory=$category
done
}
## first level completion => task sub-command completion
(( $+functions[_task_default] )) ||
_task_default() {
@ -245,8 +273,8 @@ _task_default() {
# update IDs
_task_zshids=( ${(f)"$(task _zshids)"} )
_describe -t commands 'task command' _task_zshcmds
_describe -t values 'task IDs' _task_zshids
_task_subcommands
_describe -t tasks 'task IDs' _task_zshids
_describe -t aliases 'task aliases' _task_aliases
_call_function ret _task_filter

View file

@ -80,18 +80,22 @@ CmdZshCommands::CmdZshCommands ()
////////////////////////////////////////////////////////////////////////////////
int CmdZshCommands::execute (std::string& output)
{
// Get a list of all commands.
std::vector <std::string> commands;
// Get a list of all command descriptions, sorted by category and then
// alphabetically by command name.
typedef std::tuple <Command::Category, std::string, std::string> Element;
std::vector <Element> commands;
for (auto& command : context.commands)
commands.push_back (command.first);
// Sort alphabetically.
commands.push_back (std::make_tuple (command.second->_category,
command.first,
command.second->description()));
std::sort (commands.begin (), commands.end ());
// Emit the commands in order.
std::stringstream out;
for (auto& c : commands)
out << c << ":" << context.commands[c]->description () << "\n";
out << std::get<1> (c) << ":"
<< Command::categoryNames.at (std::get<0> (c)) << ":"
<< std::get<2> (c) << "\n";
output = out.str ();
return 0;

View file

@ -50,6 +50,7 @@ public:
enum class Category
{
unassigned,
// In presentation ("usefulness") order: frequently-used categories first.
interrogator,
report,
operation,

View file

@ -63,6 +63,22 @@ class TestAliasesCompletion(TestCase):
self.assertIn("information", out)
self.assertNotIn("samplealias", out)
class TestZshCompletion(TestCase):
"""Test _zshcommands and related completion subcommands"""
def setUp(self):
self.t = Task()
self.t.config("report.foobar.columns", "id")
def test_categories(self):
"""test _zshcommands categories"""
code, out, err = self.t("_zshcommands")
self.assertIn("\nfoobar:report:", out)
self.assertIn("\ninformation:interrogator:", out)
self.assertIn("\nexport:migration:", out)
self.assertNotIn(":unassigned:", out)
if __name__ == "__main__":
from simpletap import TAPTestRunner