From d82defe6a9ae43252c7a2cb07118fdf197782f38 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Tue, 16 Dec 2014 12:22:02 +0100 Subject: [PATCH] Add readline support for the "repl" command fixes #8091 --- CMakeLists.txt | 1 + config.h.cmake | 1 + debian/control | 1 + icinga2.spec | 6 ++++++ lib/base/console.cpp | 8 ++++++-- lib/base/console.hpp | 2 ++ lib/cli/CMakeLists.txt | 2 +- lib/cli/replcommand.cpp | 42 ++++++++++++++++++++++++++++++++++++++--- 8 files changed, 57 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 93358fc57..20067a5de 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -152,6 +152,7 @@ check_function_exists(pipe2 HAVE_PIPE2) check_function_exists(nice HAVE_NICE) check_library_exists(dl dladdr "dlfcn.h" HAVE_DLADDR) check_library_exists(execinfo backtrace_symbols "" HAVE_LIBEXECINFO) +check_library_exists(readline readline "" HAVE_LIBREADLINE) check_include_file_cxx(cxxabi.h HAVE_CXXABI_H) if(HAVE_LIBEXECINFO) diff --git a/config.h.cmake b/config.h.cmake index 24c38ef27..bf4ed8b1b 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -9,6 +9,7 @@ #cmakedefine HAVE_LIBEXECINFO #cmakedefine HAVE_CXXABI_H #cmakedefine HAVE_NICE +#cmakedefine HAVE_LIBREADLINE #cmakedefine ICINGA2_UNITY_BUILD diff --git a/debian/control b/debian/control index b5817b509..3d31cad94 100644 --- a/debian/control +++ b/debian/control @@ -20,6 +20,7 @@ Build-Depends: bison, libpq-dev, libssl-dev, libyajl-dev, + libreadline-dev, make (>= 3.81), po-debconf Standards-Version: 3.9.5 diff --git a/icinga2.spec b/icinga2.spec index 6328821cf..d7e577c12 100644 --- a/icinga2.spec +++ b/icinga2.spec @@ -98,6 +98,12 @@ BuildRequires: flex >= 2.5.35 BuildRequires: bison BuildRequires: make +%if "%{_vendor}" == "suse" +BuildRequires: libreadline-devel +%else +BuildRequires: readline-devel +%endif + %if "%{_vendor}" == "redhat" && (0%{?el5} || 0%{?rhel} == 5 || "%{?dist}" == ".el5") # el5 requires packages.icinga.org BuildRequires: boost153-devel diff --git a/lib/base/console.cpp b/lib/base/console.cpp index 72b923f2c..caca79a6e 100644 --- a/lib/base/console.cpp +++ b/lib/base/console.cpp @@ -28,13 +28,17 @@ INITIALIZE_ONCE(&Console::DetectType); static ConsoleType l_ConsoleType = Console_Dumb; ConsoleColorTag::ConsoleColorTag(int color) - : m_Color(color) + : m_Color(color), m_ConsoleType(-1) +{ } + +ConsoleColorTag::ConsoleColorTag(int color, ConsoleType consoleType) + : m_Color(color), m_ConsoleType(consoleType) { } std::ostream& icinga::operator<<(std::ostream& fp, const ConsoleColorTag& cct) { #ifndef _WIN32 - if (Console::GetType(fp) == Console_VT100) + if (cct.m_ConsoleType == Console_VT100 || Console::GetType(fp) == Console_VT100) Console::PrintVT100ColorCode(fp, cct.m_Color); #else /* _WIN32 */ if (Console::GetType(fp) == Console_Windows) { diff --git a/lib/base/console.hpp b/lib/base/console.hpp index 3cf9a802a..8fb4c4c86 100644 --- a/lib/base/console.hpp +++ b/lib/base/console.hpp @@ -68,11 +68,13 @@ class I2_BASE_API ConsoleColorTag { public: ConsoleColorTag(int color); + ConsoleColorTag(int color, ConsoleType consoleType); friend I2_BASE_API std::ostream& operator<<(std::ostream& fp, const ConsoleColorTag& cct); private: int m_Color; + int m_ConsoleType; }; I2_BASE_API std::ostream& operator<<(std::ostream& fp, const ConsoleColorTag& cct); diff --git a/lib/cli/CMakeLists.txt b/lib/cli/CMakeLists.txt index 4eb5d7286..57b6ae368 100644 --- a/lib/cli/CMakeLists.txt +++ b/lib/cli/CMakeLists.txt @@ -35,7 +35,7 @@ endif() add_library(cli SHARED ${cli_SOURCES}) -target_link_libraries(cli ${Boost_LIBRARIES} base config remote) +target_link_libraries(cli ${Boost_LIBRARIES} readline base config remote) set_target_properties ( cli PROPERTIES diff --git a/lib/cli/replcommand.cpp b/lib/cli/replcommand.cpp index 4c1cfcec1..b1b0c94a4 100644 --- a/lib/cli/replcommand.cpp +++ b/lib/cli/replcommand.cpp @@ -25,6 +25,13 @@ #include "base/application.hpp" #include +#ifdef HAVE_LIBREADLINE +extern "C" { +#include +#include +} +#endif /* HAVE_LIBREADLINE */ + using namespace icinga; namespace po = boost::program_options; @@ -72,12 +79,41 @@ int ReplCommand::Run(const po::variables_map& vm, const std::vector String fileName = "<" + Convert::ToString(next_line) + ">"; next_line++; - std::cout << ConsoleColorTag(Console_ForegroundCyan) - << fileName << ConsoleColorTag(Console_ForegroundRed) << " => " - << ConsoleColorTag(Console_Normal); +#ifdef HAVE_LIBREADLINE + ConsoleType type = Console::GetType(std::cout); + std::stringstream prompt_sbuf; + + prompt_sbuf << RL_PROMPT_START_IGNORE << ConsoleColorTag(Console_ForegroundCyan, type) + << RL_PROMPT_END_IGNORE << fileName + << RL_PROMPT_START_IGNORE << ConsoleColorTag(Console_ForegroundRed, type) + << RL_PROMPT_END_IGNORE << " => " + << RL_PROMPT_START_IGNORE << ConsoleColorTag(Console_Normal, type); +#else /* HAVE_LIBREADLINE */ + std::cout << ConsoleColorTag(Console_ForegroundCyan) + << fileName + << ConsoleColorTag(Console_ForegroundRed) + << " => " + << ConsoleColorTag(Console_Normal); +#endif /* HAVE_LIBREADLINE */ + +#ifdef HAVE_LIBREADLINE + String prompt = prompt_sbuf.str(); + + char *rline = readline(prompt.CStr()); + + if (!rline) + break; + + if (*rline) + add_history(rline); + + String line = rline; + free(rline); +#else /* HAVE_LIBREADLINE */ std::string line; std::getline(std::cin, line); +#endif /* HAVE_LIBREADLINE */ Expression *expr;