Add some remote client support protocol code
This commit is contained in:
parent
b163711963
commit
b9eb939e05
|
@ -129,6 +129,8 @@ public:
|
||||||
using const_iterator = AtomList::const_iterator;
|
using const_iterator = AtomList::const_iterator;
|
||||||
|
|
||||||
explicit DisplayLine(LineCount buffer_line) : m_buffer_line(buffer_line) {}
|
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; }
|
LineCount buffer_line() const { return m_buffer_line; }
|
||||||
|
|
||||||
|
@ -138,6 +140,8 @@ public:
|
||||||
const_iterator begin() const { return m_atoms.begin(); }
|
const_iterator begin() const { return m_atoms.begin(); }
|
||||||
const_iterator end() const { return m_atoms.end(); }
|
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
|
// Split atom pointed by it at pos, returns an iterator to the first atom
|
||||||
iterator split(iterator it, BufferIterator pos);
|
iterator split(iterator it, BufferIterator pos);
|
||||||
|
|
||||||
|
|
230
src/remote.cc
Normal file
230
src/remote.cc
Normal file
|
@ -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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
47
src/remote.hh
Normal file
47
src/remote.hh
Normal file
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue
Block a user