diff options
Diffstat (limited to 'Sluift/EditlineTerminal.cpp')
-rw-r--r-- | Sluift/EditlineTerminal.cpp | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/Sluift/EditlineTerminal.cpp b/Sluift/EditlineTerminal.cpp new file mode 100644 index 0000000..ec2c7a2 --- /dev/null +++ b/Sluift/EditlineTerminal.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2013 Remko Tronçon + * Licensed under the GNU General Public License. + * See the COPYING file for more information. + */ + +#include <Sluift/EditlineTerminal.h> + +#include <boost/optional.hpp> +#include <iostream> +#include <editline/readline.h> +#include <boost/numeric/conversion/cast.hpp> +#include <cassert> +#include <vector> +#include <cstring> + +#include <Swiften/Base/Platform.h> +#include <Sluift/Completer.h> + +using namespace Swift; + +static EditlineTerminal* globalInstance = NULL; + +static int completionStart = -1; +static int completionEnd = -1; + +#if defined(SWIFTEN_PLATFORM_WINDOWS) +static char* getEmptyCompletions(const char*, int) { +#else +static int getEmptyCompletions(const char*, int) { +#endif + return 0; +} + +static char* getCompletions(const char*, int state) { + rl_completion_append_character = 0; +#if RL_READLINE_VERSION >= 0x0600 + rl_completion_suppress_append = 1; +#endif + + static std::vector<std::string> completions; + if (state == 0) { + assert(globalInstance); + completions.clear(); + if (globalInstance->getCompleter()) { + completions = globalInstance->getCompleter()->getCompletions(rl_line_buffer, completionStart, completionEnd); + } + } + if (boost::numeric_cast<size_t>(state) >= completions.size()) { + return 0; + } + return strdup(completions[boost::numeric_cast<size_t>(state)].c_str()); +} + +static char** getAttemptedCompletions(const char* text, int start, int end) { + completionStart = start; + completionEnd = end; + return rl_completion_matches(text, getCompletions); +} + +EditlineTerminal& EditlineTerminal::getInstance() { + static EditlineTerminal instance; + globalInstance = &instance; + return instance; +} + +EditlineTerminal::EditlineTerminal() { + rl_attempted_completion_function = getAttemptedCompletions; + rl_completion_entry_function = getEmptyCompletions; // Fallback. Do nothing. +#if defined(SWIFTEN_PLATFORM_WINDOWS) + // rl_basic_word_break is a cons char[] in MinGWEditLine. + // This one seems to work, although it doesn't on OS X for some reason. + rl_completer_word_break_characters = strdup(" \t\n.:+-*/><=;|&()[]{}"); +#else + rl_basic_word_break_characters = strdup(" \t\n.:+-*/><=;|&()[]{}"); +#endif +} + +EditlineTerminal::~EditlineTerminal() { +} + +void EditlineTerminal::printError(const std::string& message) { + std::cout << message << std::endl; +} + +boost::optional<std::string> EditlineTerminal::readLine(const std::string& prompt) { + const char* line = readline(prompt.c_str()); + return line ? std::string(line) : boost::optional<std::string>(); +} + +void EditlineTerminal::addToHistory(const std::string& line) { +#if defined(SWIFTEN_PLATFORM_WINDOWS) + // MinGWEditLine copies the string, so this is safe + add_history(const_cast<char*>(line.c_str())); +#else + add_history(line.c_str()); +#endif +} |