Add a ClientManager for managing client lifetimes

This commit is contained in:
Maxime Coste 2012-10-30 14:00:44 +01:00
parent bc7dfec44c
commit 1ea4b3998a
6 changed files with 100 additions and 33 deletions

24
src/client_manager.cc Normal file
View File

@ -0,0 +1,24 @@
#include "client_manager.hh"
namespace Kakoune
{
void ClientManager::add_client(Client&& client)
{
m_clients.emplace_back(std::move(client));
}
void ClientManager::remove_client_by_context(Context& context)
{
for (auto it = m_clients.begin(); it != m_clients.end(); ++it)
{
if (it->context.get() == &context)
{
m_clients.erase(it);
return;
}
}
assert(false);
}
}

42
src/client_manager.hh Normal file
View File

@ -0,0 +1,42 @@
#ifndef client_manager_hh_INCLUDED
#define client_manager_hh_INCLUDED
#include "context.hh"
#include "input_handler.hh"
namespace Kakoune
{
struct Client
{
std::unique_ptr<UserInterface> ui;
std::unique_ptr<InputHandler> input_handler;
std::unique_ptr<Context> context;
Client(UserInterface* ui, Window& window)
: ui(ui),
input_handler(new InputHandler{}),
context(new Context(*input_handler, window, *ui)) {}
Client(Client&&) = default;
Client& operator=(Client&&) = default;
};
struct client_removed{};
class ClientManager : public Singleton<ClientManager>
{
public:
void add_client(Client&& client);
void remove_client_by_context(Context& context);
bool empty() const { return m_clients.empty(); }
size_t count() const { return m_clients.size(); }
private:
std::vector<Client> m_clients;
};
}
#endif // client_manager_hh_INCLUDED

View File

@ -16,6 +16,7 @@
#include "shell_manager.hh" #include "shell_manager.hh"
#include "event_manager.hh" #include "event_manager.hh"
#include "color_registry.hh" #include "color_registry.hh"
#include "client_manager.hh"
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -334,7 +335,7 @@ void quit(const CommandParameters& params, Context& context)
if (params.size() != 0) if (params.size() != 0)
throw wrong_argument_count(); throw wrong_argument_count();
if (not force) if (not force and ClientManager::instance().count() == 1)
{ {
std::vector<String> names; std::vector<String> names;
for (auto& buffer : BufferManager::instance()) for (auto& buffer : BufferManager::instance())
@ -355,7 +356,8 @@ void quit(const CommandParameters& params, Context& context)
throw runtime_error(message); throw runtime_error(message);
} }
} }
quit_requested = true; ClientManager::instance().remove_client_by_context(context);
throw client_removed{};
} }
template<bool force> template<bool force>

View File

@ -21,6 +21,7 @@
#include "file.hh" #include "file.hh"
#include "color_registry.hh" #include "color_registry.hh"
#include "remote.hh" #include "remote.hh"
#include "client_manager.hh"
#if defined(__APPLE__) #if defined(__APPLE__)
#include <mach-o/dyld.h> #include <mach-o/dyld.h>
@ -38,8 +39,6 @@ using namespace std::placeholders;
namespace Kakoune namespace Kakoune
{ {
bool quit_requested = false;
template<InsertMode mode> template<InsertMode mode>
void do_insert(Context& context) void do_insert(Context& context)
{ {
@ -494,21 +493,7 @@ void register_registers()
} }
} }
struct Client void create_local_client(const String& file)
{
std::unique_ptr<UserInterface> ui;
std::unique_ptr<InputHandler> input_handler;
std::unique_ptr<Context> context;
Client(UserInterface* ui, Window& window)
: ui(ui),
input_handler(new InputHandler{}),
context(new Context(*input_handler, window, *ui)) {}
Client() {}
};
Client create_local_client(const String& file)
{ {
Buffer* buffer = nullptr; Buffer* buffer = nullptr;
UserInterface* ui = new NCursesUI{}; UserInterface* ui = new NCursesUI{};
@ -537,14 +522,16 @@ Client create_local_client(const String& file)
{ {
ui->print_status(error.description(), -1); ui->print_status(error.description(), -1);
} }
catch (Kakoune::client_removed&)
{
EventManager::instance().unwatch(0);
}
}); });
context->draw_ifn(); context->draw_ifn();
return client; ClientManager::instance().add_client(std::move(client));
} }
std::vector<Client> clients;
struct Server struct Server
{ {
Server() Server()
@ -583,8 +570,13 @@ struct Server
{ {
ui->print_status(error.description(), -1); ui->print_status(error.description(), -1);
} }
catch (Kakoune::client_removed&)
{
EventManager::instance().unwatch(sock);
close(sock);
}
}); });
clients.push_back(std::move(client)); ClientManager::instance().add_client(std::move(client));
}; };
EventManager::instance().watch(m_listen_sock, accepter); EventManager::instance().watch(m_listen_sock, accepter);
} }
@ -647,9 +639,16 @@ int main(int argc, char* argv[])
if (argc == 3 and String("-c") == argv[1]) if (argc == 3 and String("-c") == argv[1])
{ {
std::unique_ptr<RemoteClient> client(connect_to(argv[2])); try
while(not quit_requested) {
event_manager.handle_next_events(); std::unique_ptr<RemoteClient> client(connect_to(argv[2]));
while (true)
event_manager.handle_next_events();
}
catch (peer_disconnected&)
{
puts("disconnected");
}
return 0; return 0;
} }
@ -662,6 +661,7 @@ int main(int argc, char* argv[])
HighlighterRegistry highlighter_registry; HighlighterRegistry highlighter_registry;
FilterRegistry filter_registry; FilterRegistry filter_registry;
ColorRegistry color_registry; ColorRegistry color_registry;
ClientManager client_manager;
run_unit_tests(); run_unit_tests();
@ -677,7 +677,6 @@ int main(int argc, char* argv[])
Server server; Server server;
Client local_client;
try try
{ {
Context initialisation_context; Context initialisation_context;
@ -688,9 +687,10 @@ int main(int argc, char* argv[])
{ {
write_debug("error while parsing kakrc: " + error.description()); write_debug("error while parsing kakrc: " + error.description());
} }
local_client = create_local_client(argc > 1 ? argv[1] : "");
while(not quit_requested) create_local_client(argc > 1 ? argv[1] : "");
while (not client_manager.empty())
event_manager.handle_next_events(); event_manager.handle_next_events();
} }
catch (Kakoune::exception& error) catch (Kakoune::exception& error)

View File

@ -108,6 +108,8 @@ template<>
String read<String>(int socket) String read<String>(int socket)
{ {
ByteCount length = read<ByteCount>(socket); ByteCount length = read<ByteCount>(socket);
if (length == 0)
return String{};
char buffer[2048]; char buffer[2048];
assert(length < 2048); assert(length < 2048);
read(socket, buffer, (int)length); read(socket, buffer, (int)length);

View File

@ -7,10 +7,7 @@
namespace Kakoune namespace Kakoune
{ {
struct peer_disconnected : public runtime_error struct peer_disconnected {};
{
peer_disconnected() : runtime_error("peer disconnected") {}
};
class RemoteUI : public UserInterface class RemoteUI : public UserInterface
{ {