From c78fc47402c398e13711e52bf8f082937954db88 Mon Sep 17 00:00:00 2001 From: Daniel Shahaf Date: Mon, 20 Jul 2015 05:31:36 +0000 Subject: [PATCH] zcmdcat: zsh completion: group commands by category --- scripts/zsh/_task | 34 +++++++++++++++++++++++++++++++--- src/commands/CmdCommands.cpp | 18 +++++++++++------- src/commands/Command.h | 1 + test/completion.t | 16 ++++++++++++++++ 4 files changed, 59 insertions(+), 10 deletions(-) diff --git a/scripts/zsh/_task b/scripts/zsh/_task index 698b29336..cd9d4505c 100644 --- a/scripts/zsh/_task +++ b/scripts/zsh/_task @@ -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 diff --git a/src/commands/CmdCommands.cpp b/src/commands/CmdCommands.cpp index f16f959cf..35b5c710a 100644 --- a/src/commands/CmdCommands.cpp +++ b/src/commands/CmdCommands.cpp @@ -80,18 +80,22 @@ CmdZshCommands::CmdZshCommands () //////////////////////////////////////////////////////////////////////////////// int CmdZshCommands::execute (std::string& output) { - // Get a list of all commands. - std::vector commands; - + // Get a list of all command descriptions, sorted by category and then + // alphabetically by command name. + typedef std::tuple Element; + std::vector 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; diff --git a/src/commands/Command.h b/src/commands/Command.h index 9715351df..ec47da50f 100644 --- a/src/commands/Command.h +++ b/src/commands/Command.h @@ -50,6 +50,7 @@ public: enum class Category { unassigned, + // In presentation ("usefulness") order: frequently-used categories first. interrogator, report, operation, diff --git a/test/completion.t b/test/completion.t index 3298485ef..a64e990c3 100755 --- a/test/completion.t +++ b/test/completion.t @@ -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