diff options
| author | Maxime Coste <frrrwww@gmail.com> | 2012-10-23 22:55:44 +0200 |
|---|---|---|
| committer | Maxime Coste <frrrwww@gmail.com> | 2012-10-23 22:55:44 +0200 |
| commit | b9eb939e05f8b63354f54d1986b74c2bb8dde75e (patch) | |
| tree | 50a5fc1216aa42e673e13857d88672f44e4606aa /src | |
| parent | b1637119637e2dc3e10635a08ac06e256018ea78 (diff) | |
Add some remote client support protocol code
Diffstat (limited to 'src')
| -rw-r--r-- | src/display_buffer.hh | 4 | ||||
| -rw-r--r-- | src/remote.cc | 230 | ||||
| -rw-r--r-- | src/remote.hh | 47 |
3 files changed, 281 insertions, 0 deletions
diff --git a/src/display_buffer.hh b/src/display_buffer.hh index 869ef7a6..5a5f1558 100644 --- a/src/display_buffer.hh +++ b/src/display_buffer.hh @@ -129,6 +129,8 @@ public: using const_iterator = AtomList::const_iterator; explicit DisplayLine(LineCount buffer_line) : m_buffer_line(buffer_line) {} + DisplayLine(LineCount buffer_line, AtomList atoms) + : m_buffer_line(buffer_line), m_atoms(std::move(atoms)) {} LineCount buffer_line() const { return m_buffer_line; } @@ -138,6 +140,8 @@ public: const_iterator begin() const { return m_atoms.begin(); } const_iterator end() const { return m_atoms.end(); } + const AtomList& atoms() const { return m_atoms; } + // Split atom pointed by it at pos, returns an iterator to the first atom iterator split(iterator it, BufferIterator pos); diff --git a/src/remote.cc b/src/remote.cc new file mode 100644 index 00000000..4dadeeba --- /dev/null +++ b/src/remote.cc @@ -0,0 +1,230 @@ +#include "remote.hh" + +#include "display_buffer.hh" + +#include <sys/types.h> +#include <sys/socket.h> + +namespace Kakoune +{ + +enum class RemoteUIMsg +{ + PrintStatus, + MenuShow, + MenuSelect, + MenuHide, + Draw +}; + +class Message +{ +public: + Message(int sock) : m_socket(sock) {} + ~Message() { ::write(m_socket, m_stream.data(), m_stream.size()); } + + void write(const char* val, size_t size) + { + m_stream.insert(m_stream.end(), val, val + size); + } + +private: + std::vector<char> m_stream; + int m_socket; +}; + +template<typename T> +void write(Message& msg, const T& val) +{ + msg.write((const char*)&val, sizeof(val)); +}; + +void write(Message& msg, const String& str) +{ + write(msg, str.length()); + msg.write(str.c_str(), (int)str.length()); +}; + +template<typename T> +void write(Message& msg, const memoryview<T>& view) +{ + write<uint32_t>(msg, view.size()); + for (auto& val : view) + write(msg, val); +}; + +template<typename T> +void write(Message& msg, const std::vector<T>& vec) +{ + write(msg, memoryview<T>(vec)); +} + +void write(Message& msg, const DisplayAtom& atom) +{ + write(msg, atom.fg_color); + write(msg, atom.bg_color); + write(msg, atom.attribute); + write(msg, atom.content.content()); +} + +void write(Message& msg, const DisplayLine& line) +{ + write(msg, line.atoms()); +} + +void write(Message& msg, const DisplayBuffer& display_buffer) +{ + write(msg, display_buffer.lines()); +} + +template<typename T> +T read(int socket) +{ + char value[sizeof(T)]; + auto res = ::read(socket, value, sizeof(T)); + assert(res == sizeof(T)); + return *(T*)(value); +}; + +template<> +String read<String>(int socket) +{ + ByteCount length = read<ByteCount>(socket); + char buffer[2048]; + assert(length < 2048); + auto res = ::read(socket, buffer, (int)length); + assert(res == (int)length); + return String(buffer, buffer+(int)length); +}; + +template<typename T> +std::vector<T> read_vector(int socket) +{ + uint32_t size = read<uint32_t>(socket); + std::vector<T> res; + res.reserve(size); + while (size--) + res.push_back(read<T>(socket)); + return res; +}; + +template<> +DisplayAtom read<DisplayAtom>(int socket) +{ + Color fg_color = read<Color>(socket); + Color bg_color = read<Color>(socket); + Attribute attribute = read<Attribute>(socket); + DisplayAtom atom(AtomContent(read<String>(socket))); + atom.fg_color = fg_color; + atom.bg_color = bg_color; + atom.attribute = attribute; + return atom; +} +template<> +DisplayLine read<DisplayLine>(int socket) +{ + return DisplayLine(0, read_vector<DisplayAtom>(socket)); +} + +template<> +DisplayBuffer read<DisplayBuffer>(int socket) +{ + DisplayBuffer db; + db.lines() = read_vector<DisplayLine>(socket); + return db; +} + +void RemoteUI::print_status(const String& status, CharCount cursor_pos) +{ + Message msg(m_socket); + write(msg, RemoteUIMsg::PrintStatus); + write(msg, status); + write(msg, cursor_pos); +} + +void RemoteUI::menu_show(const memoryview<String>& choices, + const DisplayCoord& anchor, MenuStyle style) +{ + Message msg(m_socket); + write(msg, RemoteUIMsg::MenuShow); + write(msg, choices); + write(msg, anchor); + write(msg, style); +} + +void RemoteUI::menu_select(int selected) +{ + Message msg(m_socket); + write(msg, RemoteUIMsg::MenuSelect); + write(msg, selected); +} + +void RemoteUI::menu_hide() +{ + Message msg(m_socket); + write(msg, RemoteUIMsg::MenuHide); +} + +void RemoteUI::draw(const DisplayBuffer& display_buffer, + const String& status_line) +{ + Message msg(m_socket); + write(msg, RemoteUIMsg::Draw); + write(msg, display_buffer); + write(msg, status_line); +} + +Key RemoteUI::get_key() +{ + Key key = read<Key>(m_socket); + return key; +} + +DisplayCoord RemoteUI::dimensions() +{ + return m_dimensions; +} + +void RemoteClient::process_next_message() +{ + RemoteUIMsg msg = read<RemoteUIMsg>(m_socket); + switch (msg) + { + case RemoteUIMsg::PrintStatus: + { + auto status = read<String>(m_socket); + auto cursor_pos = read<CharCount>(m_socket); + m_ui->print_status(status, cursor_pos); + break; + } + case RemoteUIMsg::MenuShow: + { + auto choices = read_vector<String>(m_socket); + auto anchor = read<DisplayCoord>(m_socket); + auto style = read<MenuStyle>(m_socket); + m_ui->menu_show(choices, anchor, style); + break; + } + case RemoteUIMsg::MenuSelect: + m_ui->menu_select(read<int>(m_socket)); + break; + case RemoteUIMsg::MenuHide: + m_ui->menu_hide(); + break; + case RemoteUIMsg::Draw: + { + DisplayBuffer display_buffer = read<DisplayBuffer>(m_socket); + String status_line = read<String>(m_socket); + m_ui->draw(display_buffer, status_line); + break; + } + } +} + +void RemoteClient::write_next_key() +{ + Message msg(m_socket); + write(msg, m_ui->get_key()); +} + +} diff --git a/src/remote.hh b/src/remote.hh new file mode 100644 index 00000000..0717e7ed --- /dev/null +++ b/src/remote.hh @@ -0,0 +1,47 @@ +#ifndef remote_hh_INCLUDED +#define remote_hh_INCLUDED + +#include "user_interface.hh" +#include "display_buffer.hh" + +namespace Kakoune +{ + +class RemoteUI : public UserInterface +{ +public: + RemoteUI(int socket) : m_socket(socket) {} + + void print_status(const String& status, CharCount cursor_pos) override; + void menu_show(const memoryview<String>& choices, + const DisplayCoord& anchor, MenuStyle style) override; + void menu_select(int selected) override; + void menu_hide() override; + void draw(const DisplayBuffer& display_buffer, + const String& status_line) override; + Key get_key() override; + DisplayCoord dimensions() override; + void set_dimensions(const DisplayCoord dim) { m_dimensions = dim; } + +private: + int m_socket; + DisplayCoord m_dimensions; +}; + +class RemoteClient +{ +public: + RemoteClient(int socket, UserInterface* ui) : m_ui(ui), m_socket(socket) {} + + void process_next_message(); + void write_next_key(); + +private: + int m_socket; + std::unique_ptr<UserInterface> m_ui; +}; + +} + +#endif // remote_hh_INCLUDED + |
