From cd9dfd574492d828f78fb64db274bcb46c121ccb Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Wed, 18 Mar 2015 07:17:15 +0100 Subject: [PATCH] Implement auto-completion support for 'icinga2 console' refs #8776 --- lib/cli/consolecommand.cpp | 78 +++++++++++++++++++++++++++++++++++++- lib/cli/editline.hpp | 4 ++ 2 files changed, 80 insertions(+), 2 deletions(-) diff --git a/lib/cli/consolecommand.cpp b/lib/cli/consolecommand.cpp index 227ab6be5..cd8389a81 100644 --- a/lib/cli/consolecommand.cpp +++ b/lib/cli/consolecommand.cpp @@ -22,6 +22,7 @@ #include "base/json.hpp" #include "base/console.hpp" #include "base/application.hpp" +#include "base/objectlock.hpp" #include "base/unixsocket.hpp" #include "base/utility.hpp" #include "base/networkstream.hpp" @@ -33,6 +34,8 @@ using namespace icinga; namespace po = boost::program_options; +static ScriptFrame l_ScriptFrame; + REGISTER_CLICOMMAND("console", ConsoleCommand); String ConsoleCommand::GetDescription(void) const @@ -58,6 +61,74 @@ void ConsoleCommand::InitParameters(boost::program_options::options_description& ; } +#ifdef HAVE_EDITLINE +static void AddSuggestion(std::vector& matches, const String& word, const String& suggestion) +{ + if (suggestion.Find(word) != 0) + return; + + matches.push_back(suggestion); +} + +static char *ConsoleCompleteHelper(const char *word, int state) +{ + static std::vector matches; + String aword = word; + + if (state == 0) { + matches.clear(); + + AddSuggestion(matches, word, "object"); + AddSuggestion(matches, word, "template"); + AddSuggestion(matches, word, "include"); + AddSuggestion(matches, word, "include_recursive"); + AddSuggestion(matches, word, "library"); + AddSuggestion(matches, word, "null"); + AddSuggestion(matches, word, "true"); + AddSuggestion(matches, word, "false"); + AddSuggestion(matches, word, "const"); + AddSuggestion(matches, word, "var"); + AddSuggestion(matches, word, "this"); + AddSuggestion(matches, word, "globals"); + AddSuggestion(matches, word, "locals"); + AddSuggestion(matches, word, "use"); + AddSuggestion(matches, word, "apply"); + AddSuggestion(matches, word, "to"); + AddSuggestion(matches, word, "where"); + AddSuggestion(matches, word, "import"); + AddSuggestion(matches, word, "assign"); + AddSuggestion(matches, word, "ignore"); + AddSuggestion(matches, word, "function"); + AddSuggestion(matches, word, "return"); + AddSuggestion(matches, word, "break"); + AddSuggestion(matches, word, "continue"); + AddSuggestion(matches, word, "for"); + AddSuggestion(matches, word, "if"); + AddSuggestion(matches, word, "else"); + AddSuggestion(matches, word, "while"); + + { + ObjectLock olock(l_ScriptFrame.Locals); + BOOST_FOREACH(const Dictionary::Pair& kv, l_ScriptFrame.Locals) { + AddSuggestion(matches, word, kv.first); + } + } + + { + ObjectLock olock(ScriptGlobal::GetGlobals()); + BOOST_FOREACH(const Dictionary::Pair& kv, ScriptGlobal::GetGlobals()) { + AddSuggestion(matches, word, kv.first); + } + } + } + + if (state >= matches.size()) + return NULL; + + return strdup(matches[state].CStr()); +} +#endif /* HAVE_EDITLINE */ + /** * The entry point for the "console" CLI command. * @@ -65,10 +136,13 @@ void ConsoleCommand::InitParameters(boost::program_options::options_description& */ int ConsoleCommand::Run(const po::variables_map& vm, const std::vector& ap) const { - ScriptFrame frame; std::map lines; int next_line = 1; +#ifdef HAVE_EDITLINE + rl_completion_entry_function = ConsoleCompleteHelper; +#endif /* HAVE_EDITLINE */ + String addr, session; if (vm.count("connect")) { @@ -139,7 +213,7 @@ incomplete: expr = ConfigCompiler::CompileText(fileName, command); if (expr) { - Value result = expr->Evaluate(frame); + Value result = expr->Evaluate(l_ScriptFrame); std::cout << ConsoleColorTag(Console_ForegroundCyan); if (!result.IsObject() || result.IsObjectType() || result.IsObjectType()) std::cout << JsonEncode(result); diff --git a/lib/cli/editline.hpp b/lib/cli/editline.hpp index 141991fe4..2ae7ab7b5 100644 --- a/lib/cli/editline.hpp +++ b/lib/cli/editline.hpp @@ -25,6 +25,10 @@ extern "C" { char *readline(const char *prompt); int add_history(const char *line); +typedef char *ELFunction(const char *, int); + +extern ELFunction *rl_completion_entry_function; + } #endif /* EDITLINE_H */