aboutsummaryrefslogtreecommitdiff
path: root/contrib/epee/include
diff options
context:
space:
mode:
authorjethro <jtg@xtrabass.com>2017-05-29 18:39:49 -0400
committerjethro <jtg@xtrabass.com>2017-06-18 10:08:37 -0400
commite1f3dfccc8a099eb08e0d9ef758b216d035afd78 (patch)
treeabf35aacb54779d49ef4616d7a2b13ed718fc709 /contrib/epee/include
parentMerge pull request #2055 (diff)
downloadmonero-e1f3dfccc8a099eb08e0d9ef758b216d035afd78.tar.xz
Add readline support to cli
This PR adds readline support to the daemon and monero-wallet-cli. Only GNU readline is supported (e.g. not libedit) and there are cmake checks to ensure this. There is a cmake variable, Readline_ROOT_DIR that can specify a directory to find readline, otherwise some default paths are searched. There is also a cmake option, USE_READLINE, that defaults to ON. If set to ON, if readline is not found, the build continues but without readline support. One negative side effect of using readline is that the color prompt in the wallet-cli now has no color and just uses terminal default. I know how to fix this but it's quite a big change so will tackle another time.
Diffstat (limited to 'contrib/epee/include')
-rw-r--r--contrib/epee/include/console_handler.h41
-rw-r--r--contrib/epee/include/readline_buffer.h40
2 files changed, 81 insertions, 0 deletions
diff --git a/contrib/epee/include/console_handler.h b/contrib/epee/include/console_handler.h
index 54e3e966d..bb20faa65 100644
--- a/contrib/epee/include/console_handler.h
+++ b/contrib/epee/include/console_handler.h
@@ -38,6 +38,10 @@
#endif
#include <boost/thread.hpp>
+#ifdef HAVE_READLINE
+ #include "readline_buffer.h"
+#endif
+
namespace epee
{
class async_stdin_reader
@@ -49,6 +53,10 @@ namespace epee
, m_read_status(state_init)
{
m_reader_thread = boost::thread(std::bind(&async_stdin_reader::reader_thread_func, this));
+#ifdef HAVE_READLINE
+ m_readline_buffer.start();
+ m_readline_thread = boost::thread(std::bind(&async_stdin_reader::readline_thread_func, this));
+#endif
}
~async_stdin_reader()
@@ -56,6 +64,13 @@ namespace epee
stop();
}
+#ifdef HAVE_READLINE
+ rdln::readline_buffer& get_readline_buffer()
+ {
+ return m_readline_buffer;
+ }
+#endif
+
// Not thread safe. Only one thread can call this method at once.
bool get_line(std::string& line)
{
@@ -98,6 +113,10 @@ namespace epee
m_request_cv.notify_one();
m_reader_thread.join();
+#ifdef HAVE_READLINE
+ m_readline_buffer.stop();
+ m_readline_thread.join();
+#endif
}
}
@@ -174,6 +193,16 @@ namespace epee
return true;
}
+#ifdef HAVE_READLINE
+ void readline_thread_func()
+ {
+ while (m_run.load(std::memory_order_relaxed))
+ {
+ m_readline_buffer.process();
+ }
+ }
+#endif
+
void reader_thread_func()
{
while (true)
@@ -187,7 +216,11 @@ namespace epee
{
if (m_run.load(std::memory_order_relaxed))
{
+#ifdef HAVE_READLINE
+ m_readline_buffer.get_line(line);
+#else
std::getline(std::cin, line);
+#endif
read_ok = !std::cin.eof() && !std::cin.fail();
}
}
@@ -229,6 +262,10 @@ namespace epee
private:
boost::thread m_reader_thread;
std::atomic<bool> m_run;
+#ifdef HAVE_READLINE
+ boost::thread m_readline_thread;
+ rdln::readline_buffer m_readline_buffer;
+#endif
std::string m_line;
bool m_has_read_request;
@@ -277,12 +314,16 @@ namespace epee
{
if (!m_prompt.empty())
{
+#ifdef HAVE_READLINE
+ m_stdin_reader.get_readline_buffer().set_prompt(m_prompt);
+#else
epee::set_console_color(epee::console_color_yellow, true);
std::cout << m_prompt;
if (' ' != m_prompt.back())
std::cout << ' ';
epee::reset_console_color();
std::cout.flush();
+#endif
}
}
diff --git a/contrib/epee/include/readline_buffer.h b/contrib/epee/include/readline_buffer.h
new file mode 100644
index 000000000..7d929bc4c
--- /dev/null
+++ b/contrib/epee/include/readline_buffer.h
@@ -0,0 +1,40 @@
+#pragma once
+
+#include <streambuf>
+#include <sstream>
+#include <iostream>
+
+namespace rdln
+{
+ class readline_buffer : public std::stringbuf
+ {
+ public:
+ readline_buffer();
+ void start();
+ void stop();
+ int process();
+ bool is_running()
+ {
+ return m_cout_buf != NULL;
+ }
+ void get_line(std::string& line);
+ void set_prompt(const std::string& prompt);
+
+ protected:
+ virtual int sync();
+
+ private:
+ std::streambuf* m_cout_buf;
+ };
+
+ class suspend_readline
+ {
+ public:
+ suspend_readline();
+ ~suspend_readline();
+ private:
+ readline_buffer* m_buffer;
+ bool m_restart;
+ };
+}
+