add initial (and buggy) unix socket based client/server code
This commit is contained in:
parent
b9eb939e05
commit
0735c69a92
209
src/main.cc
209
src/main.cc
|
@ -20,6 +20,7 @@
|
||||||
#include "string.hh"
|
#include "string.hh"
|
||||||
#include "file.hh"
|
#include "file.hh"
|
||||||
#include "color_registry.hh"
|
#include "color_registry.hh"
|
||||||
|
#include "remote.hh"
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
#include <mach-o/dyld.h>
|
#include <mach-o/dyld.h>
|
||||||
|
@ -27,6 +28,8 @@
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
|
||||||
using namespace Kakoune;
|
using namespace Kakoune;
|
||||||
|
@ -450,6 +453,45 @@ std::unordered_map<Key, std::function<void (Context& context)>> keymap =
|
||||||
|
|
||||||
void run_unit_tests();
|
void run_unit_tests();
|
||||||
|
|
||||||
|
void register_env_vars()
|
||||||
|
{
|
||||||
|
ShellManager& shell_manager = ShellManager::instance();
|
||||||
|
|
||||||
|
shell_manager.register_env_var("bufname",
|
||||||
|
[](const String& name, const Context& context)
|
||||||
|
{ return context.buffer().name(); });
|
||||||
|
shell_manager.register_env_var("selection",
|
||||||
|
[](const String& name, const Context& context)
|
||||||
|
{ return context.editor().selections_content().back(); });
|
||||||
|
shell_manager.register_env_var("runtime",
|
||||||
|
[](const String& name, const Context& context)
|
||||||
|
{ return runtime_directory(); });
|
||||||
|
shell_manager.register_env_var("opt_.+",
|
||||||
|
[](const String& name, const Context& context)
|
||||||
|
{ return context.option_manager()[name.substr(4_byte)].as_string(); });
|
||||||
|
shell_manager.register_env_var("reg_.+",
|
||||||
|
[](const String& name, const Context& context)
|
||||||
|
{ return RegisterManager::instance()[name[4]].values(context)[0]; });
|
||||||
|
}
|
||||||
|
|
||||||
|
void register_registers()
|
||||||
|
{
|
||||||
|
RegisterManager& register_manager = RegisterManager::instance();
|
||||||
|
|
||||||
|
register_manager.register_dynamic_register('%', [](const Context& context) { return std::vector<String>(1, context.buffer().name()); });
|
||||||
|
register_manager.register_dynamic_register('.', [](const Context& context) { return context.editor().selections_content(); });
|
||||||
|
for (size_t i = 0; i < 10; ++i)
|
||||||
|
{
|
||||||
|
register_manager.register_dynamic_register('0'+i,
|
||||||
|
[i](const Context& context) {
|
||||||
|
std::vector<String> result;
|
||||||
|
for (auto& sel_and_cap : context.editor().selections())
|
||||||
|
result.emplace_back(i < sel_and_cap.captures.size() ? sel_and_cap.captures[i] : "");
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct Client
|
struct Client
|
||||||
{
|
{
|
||||||
std::unique_ptr<UserInterface> ui;
|
std::unique_ptr<UserInterface> ui;
|
||||||
|
@ -499,72 +541,129 @@ Client create_local_client(const String& file)
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
void register_env_vars()
|
std::vector<Client> clients;
|
||||||
{
|
|
||||||
ShellManager& shell_manager = ShellManager::instance();
|
|
||||||
|
|
||||||
shell_manager.register_env_var("bufname",
|
void setup_server()
|
||||||
[](const String& name, const Context& context)
|
{
|
||||||
{ return context.buffer().name(); });
|
auto filename = "/tmp/kak-" + int_to_str(getpid());
|
||||||
shell_manager.register_env_var("selection",
|
|
||||||
[](const String& name, const Context& context)
|
int listen_sock = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||||
{ return context.editor().selections_content().back(); });
|
sockaddr_un addr;
|
||||||
shell_manager.register_env_var("runtime",
|
addr.sun_family = AF_UNIX;
|
||||||
[](const String& name, const Context& context)
|
strncpy(addr.sun_path, filename.c_str(), sizeof(addr.sun_path) - 1);
|
||||||
{ return runtime_directory(); });
|
|
||||||
shell_manager.register_env_var("opt_.+",
|
if (bind(listen_sock, (sockaddr*) &addr, sizeof(sockaddr_un)) == -1)
|
||||||
[](const String& name, const Context& context)
|
throw runtime_error("unable to bind listen socket " + filename);
|
||||||
{ return context.option_manager()[name.substr(4_byte)].as_string(); });
|
|
||||||
shell_manager.register_env_var("reg_.+",
|
if (listen(listen_sock, 4) == -1)
|
||||||
[](const String& name, const Context& context)
|
throw runtime_error("unable to listen on socket " + filename);
|
||||||
{ return RegisterManager::instance()[name[4]].values(context)[0]; });
|
|
||||||
|
auto accepter = [=](int socket) {
|
||||||
|
sockaddr_un client_addr;
|
||||||
|
socklen_t client_addr_len = sizeof(sockaddr_un);
|
||||||
|
int sock = accept(socket, (sockaddr*) &client_addr, &client_addr_len);
|
||||||
|
if (sock == -1)
|
||||||
|
throw runtime_error("accept failed");
|
||||||
|
|
||||||
|
auto& buffer = *BufferManager::instance().begin();
|
||||||
|
RemoteUI* ui = new RemoteUI{sock};
|
||||||
|
ui->set_dimensions(DisplayCoord(24, 80));
|
||||||
|
Client client{ui, *buffer->get_or_create_window()};
|
||||||
|
InputHandler* input_handler = client.input_handler.get();
|
||||||
|
Context* context = client.context.get();
|
||||||
|
EventManager::instance().watch(sock, [=](int) {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
input_handler->handle_next_input(*context);
|
||||||
|
}
|
||||||
|
catch (Kakoune::runtime_error& error)
|
||||||
|
{
|
||||||
|
ui->print_status(error.description(), -1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
clients.push_back(std::move(client));
|
||||||
|
};
|
||||||
|
EventManager::instance().watch(listen_sock, accepter);
|
||||||
}
|
}
|
||||||
|
|
||||||
void register_registers()
|
RemoteClient* connect_to(const String& pid)
|
||||||
{
|
{
|
||||||
RegisterManager& register_manager = RegisterManager::instance();
|
auto filename = "/tmp/kak-" + pid;
|
||||||
|
|
||||||
register_manager.register_dynamic_register('%', [](const Context& context) { return std::vector<String>(1, context.buffer().name()); });
|
int sock = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
||||||
register_manager.register_dynamic_register('.', [](const Context& context) { return context.editor().selections_content(); });
|
sockaddr_un addr;
|
||||||
for (size_t i = 0; i < 10; ++i)
|
addr.sun_family = AF_UNIX;
|
||||||
{
|
strncpy(addr.sun_path, filename.c_str(), sizeof(addr.sun_path) - 1);
|
||||||
register_manager.register_dynamic_register('0'+i,
|
if (connect(sock, (sockaddr*)&addr, sizeof(addr.sun_path)) == -1)
|
||||||
[i](const Context& context) {
|
throw runtime_error("connect to " + filename + " failed");
|
||||||
std::vector<String> result;
|
|
||||||
for (auto& sel_and_cap : context.editor().selections())
|
NCursesUI* ui = new NCursesUI{};
|
||||||
result.emplace_back(i < sel_and_cap.captures.size() ? sel_and_cap.captures[i] : "");
|
RemoteClient* remote_client = new RemoteClient{sock, ui};
|
||||||
return result;
|
|
||||||
});
|
EventManager::instance().watch(sock, [=](int) {
|
||||||
}
|
try
|
||||||
|
{
|
||||||
|
remote_client->process_next_message();
|
||||||
|
}
|
||||||
|
catch (Kakoune::runtime_error& error)
|
||||||
|
{
|
||||||
|
ui->print_status(error.description(), -1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
EventManager::instance().watch(0, [=](int) {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
remote_client->write_next_key();
|
||||||
|
}
|
||||||
|
catch (Kakoune::runtime_error& error)
|
||||||
|
{
|
||||||
|
ui->print_status(error.description(), -1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return remote_client;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
EventManager event_manager;
|
|
||||||
GlobalOptionManager option_manager;
|
|
||||||
GlobalHookManager hook_manager;
|
|
||||||
ShellManager shell_manager;
|
|
||||||
CommandManager command_manager;
|
|
||||||
BufferManager buffer_manager;
|
|
||||||
RegisterManager register_manager;
|
|
||||||
HighlighterRegistry highlighter_registry;
|
|
||||||
FilterRegistry filter_registry;
|
|
||||||
ColorRegistry color_registry;
|
|
||||||
|
|
||||||
run_unit_tests();
|
|
||||||
|
|
||||||
register_env_vars();
|
|
||||||
register_registers();
|
|
||||||
register_commands();
|
|
||||||
register_highlighters();
|
|
||||||
register_filters();
|
|
||||||
|
|
||||||
write_debug("*** This is the debug buffer, where debug info will be written ***\n");
|
|
||||||
write_debug("utf-8 test: é á ï");
|
|
||||||
|
|
||||||
Client local_client;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
EventManager event_manager;
|
||||||
|
|
||||||
|
if (argc == 3 and String("-c") == argv[1])
|
||||||
|
{
|
||||||
|
std::unique_ptr<RemoteClient> client(connect_to(argv[2]));
|
||||||
|
while(not quit_requested)
|
||||||
|
event_manager.handle_next_events();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
GlobalOptionManager option_manager;
|
||||||
|
GlobalHookManager hook_manager;
|
||||||
|
ShellManager shell_manager;
|
||||||
|
CommandManager command_manager;
|
||||||
|
BufferManager buffer_manager;
|
||||||
|
RegisterManager register_manager;
|
||||||
|
HighlighterRegistry highlighter_registry;
|
||||||
|
FilterRegistry filter_registry;
|
||||||
|
ColorRegistry color_registry;
|
||||||
|
|
||||||
|
run_unit_tests();
|
||||||
|
|
||||||
|
register_env_vars();
|
||||||
|
register_registers();
|
||||||
|
register_commands();
|
||||||
|
register_highlighters();
|
||||||
|
register_filters();
|
||||||
|
|
||||||
|
write_debug("*** This is the debug buffer, where debug info will be written ***\n");
|
||||||
|
write_debug("pid: " + int_to_str(getpid()) + "\n");
|
||||||
|
write_debug("utf-8 test: é á ï");
|
||||||
|
|
||||||
|
setup_server();
|
||||||
|
|
||||||
|
Client local_client;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Context initialisation_context;
|
Context initialisation_context;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user