2012-10-30 17:00:44 +04:00
|
|
|
#include "client_manager.hh"
|
|
|
|
|
2012-11-07 17:02:23 +04:00
|
|
|
#include "buffer_manager.hh"
|
2012-12-19 00:20:36 +04:00
|
|
|
#include "command_manager.hh"
|
2014-12-23 16:54:09 +03:00
|
|
|
#include "containers.hh"
|
2013-04-09 21:39:03 +04:00
|
|
|
#include "event_manager.hh"
|
2014-07-11 03:27:04 +04:00
|
|
|
#include "face_registry.hh"
|
2013-03-25 22:11:26 +04:00
|
|
|
#include "file.hh"
|
2013-04-09 21:39:03 +04:00
|
|
|
#include "user_interface.hh"
|
|
|
|
#include "window.hh"
|
2012-10-31 17:23:44 +04:00
|
|
|
|
2012-10-30 17:00:44 +04:00
|
|
|
namespace Kakoune
|
|
|
|
{
|
|
|
|
|
2013-02-07 22:25:42 +04:00
|
|
|
ClientManager::ClientManager() = default;
|
2015-08-26 21:34:19 +03:00
|
|
|
ClientManager::~ClientManager()
|
|
|
|
{
|
|
|
|
// So that clients destructor find the client manager empty
|
|
|
|
// so that local UI does not fork.
|
|
|
|
ClientList clients = std::move(m_clients);
|
|
|
|
}
|
2013-02-07 22:25:42 +04:00
|
|
|
|
2013-01-07 16:59:09 +04:00
|
|
|
String ClientManager::generate_name() const
|
|
|
|
{
|
|
|
|
for (int i = 0; true; ++i)
|
|
|
|
{
|
2015-03-31 01:56:33 +03:00
|
|
|
String name = format("unnamed{}", i);
|
2013-09-13 02:01:47 +04:00
|
|
|
if (validate_client_name(name))
|
2013-01-07 16:59:09 +04:00
|
|
|
return name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-13 01:47:23 +04:00
|
|
|
Client* ClientManager::create_client(std::unique_ptr<UserInterface>&& ui,
|
2014-04-08 00:25:44 +04:00
|
|
|
EnvVarMap env_vars,
|
2014-10-20 22:18:38 +04:00
|
|
|
StringView init_commands)
|
2012-10-30 17:00:44 +04:00
|
|
|
{
|
2012-12-28 16:51:14 +04:00
|
|
|
Buffer& buffer = **BufferManager::instance().begin();
|
2013-12-21 00:10:08 +04:00
|
|
|
WindowAndSelections ws = get_free_window(buffer);
|
2014-01-28 00:28:38 +04:00
|
|
|
Client* client = new Client{std::move(ui), std::move(ws.window),
|
2014-04-08 00:25:44 +04:00
|
|
|
std::move(ws.selections), std::move(env_vars),
|
|
|
|
generate_name()};
|
2013-04-15 16:28:21 +04:00
|
|
|
m_clients.emplace_back(client);
|
2012-12-19 21:56:47 +04:00
|
|
|
try
|
|
|
|
{
|
2015-12-14 22:06:30 +03:00
|
|
|
try
|
|
|
|
{
|
|
|
|
CommandManager::instance().execute(init_commands, client->context());
|
|
|
|
}
|
|
|
|
catch (Kakoune::runtime_error& error)
|
|
|
|
{
|
|
|
|
client->context().print_status({ error.what().str(), get_face("Error") });
|
|
|
|
client->context().hooks().run_hook("RuntimeError", error.what(),
|
|
|
|
client->context());
|
|
|
|
}
|
2012-12-19 21:56:47 +04:00
|
|
|
}
|
2015-10-08 15:43:39 +03:00
|
|
|
catch (Kakoune::client_removed& removed)
|
2012-12-19 21:56:47 +04:00
|
|
|
{
|
2015-10-08 15:43:39 +03:00
|
|
|
remove_client(*client, removed.graceful);
|
2013-04-15 16:28:21 +04:00
|
|
|
return nullptr;
|
2012-12-19 21:56:47 +04:00
|
|
|
}
|
|
|
|
|
2014-11-25 04:00:18 +03:00
|
|
|
client->ui().set_input_callback([client](EventMode mode) {
|
|
|
|
client->handle_available_input(mode);
|
2012-10-31 17:23:44 +04:00
|
|
|
});
|
2013-04-15 16:28:21 +04:00
|
|
|
|
|
|
|
return client;
|
2012-10-30 17:00:44 +04:00
|
|
|
}
|
|
|
|
|
2014-11-29 23:14:52 +03:00
|
|
|
void ClientManager::handle_pending_inputs() const
|
2014-11-25 04:00:18 +03:00
|
|
|
{
|
|
|
|
for (auto& client : m_clients)
|
2014-11-29 23:14:52 +03:00
|
|
|
client->handle_available_input(EventMode::Pending);
|
2014-11-25 04:00:18 +03:00
|
|
|
}
|
|
|
|
|
2015-10-08 15:43:39 +03:00
|
|
|
void ClientManager::remove_client(Client& client, bool graceful)
|
2012-10-30 17:00:44 +04:00
|
|
|
{
|
2015-08-26 21:33:52 +03:00
|
|
|
auto it = find_if(m_clients,
|
|
|
|
[&](const std::unique_ptr<Client>& ptr)
|
|
|
|
{ return ptr.get() == &client; });
|
|
|
|
kak_assert(it != m_clients.end());
|
|
|
|
m_clients.erase(it);
|
2015-10-08 15:43:39 +03:00
|
|
|
|
|
|
|
if (not graceful and m_clients.empty())
|
|
|
|
BufferManager::instance().backup_modified_buffers();
|
2012-10-30 17:00:44 +04:00
|
|
|
}
|
|
|
|
|
2013-12-21 00:10:08 +04:00
|
|
|
WindowAndSelections ClientManager::get_free_window(Buffer& buffer)
|
2012-11-05 22:15:42 +04:00
|
|
|
{
|
2015-03-14 14:27:01 +03:00
|
|
|
auto it = find_if(reversed(m_free_windows),
|
|
|
|
[&](const WindowAndSelections& ws)
|
|
|
|
{ return &ws.window->buffer() == &buffer; });
|
|
|
|
|
|
|
|
if (it == m_free_windows.rend())
|
2015-05-26 20:42:09 +03:00
|
|
|
return { make_unique<Window>(buffer), { buffer, Selection{} } };
|
2015-03-14 14:27:01 +03:00
|
|
|
|
2015-06-21 21:56:23 +03:00
|
|
|
it->window->force_redraw();
|
2015-03-14 14:27:01 +03:00
|
|
|
WindowAndSelections res = std::move(*it);
|
|
|
|
m_free_windows.erase(it.base()-1);
|
|
|
|
res.selections.update();
|
|
|
|
return res;
|
2013-12-21 00:10:08 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void ClientManager::add_free_window(std::unique_ptr<Window>&& window, SelectionList selections)
|
|
|
|
{
|
2015-01-26 22:41:10 +03:00
|
|
|
window->clear_display_buffer();
|
2013-12-21 00:10:08 +04:00
|
|
|
Buffer& buffer = window->buffer();
|
2014-05-13 02:25:15 +04:00
|
|
|
m_free_windows.push_back({ std::move(window), SelectionList{ std::move(selections) }, buffer.timestamp() });
|
2012-11-05 22:15:42 +04:00
|
|
|
}
|
|
|
|
|
2012-11-07 17:02:23 +04:00
|
|
|
void ClientManager::ensure_no_client_uses_buffer(Buffer& buffer)
|
|
|
|
{
|
|
|
|
for (auto& client : m_clients)
|
|
|
|
{
|
2013-01-28 16:48:34 +04:00
|
|
|
client->context().forget_jumps_to_buffer(buffer);
|
2015-11-07 21:24:08 +03:00
|
|
|
if (client->last_buffer() == &buffer)
|
|
|
|
client->set_last_buffer(nullptr);
|
2012-11-12 22:59:25 +04:00
|
|
|
|
2013-01-28 16:48:34 +04:00
|
|
|
if (&client->context().buffer() != &buffer)
|
2012-11-07 17:02:23 +04:00
|
|
|
continue;
|
|
|
|
|
2013-12-15 22:07:51 +04:00
|
|
|
if (client->context().is_editing())
|
2015-06-01 23:15:59 +03:00
|
|
|
throw runtime_error(format("client '{}' is inserting in buffer '{}'",
|
|
|
|
client->context().name(),
|
|
|
|
buffer.display_name()));
|
2013-04-10 20:54:01 +04:00
|
|
|
|
2015-11-10 16:52:48 +03:00
|
|
|
if (Buffer* last_buffer = client->last_buffer())
|
|
|
|
{
|
|
|
|
client->context().change_buffer(*last_buffer);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2012-11-07 17:02:23 +04:00
|
|
|
for (auto& buf : BufferManager::instance())
|
|
|
|
{
|
2015-02-23 23:39:56 +03:00
|
|
|
if (buf.get() != &buffer)
|
2012-11-07 17:02:23 +04:00
|
|
|
{
|
2013-12-21 00:10:08 +04:00
|
|
|
client->context().change_buffer(*buf);
|
2012-11-07 17:02:23 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-12-21 00:10:08 +04:00
|
|
|
auto end = std::remove_if(m_free_windows.begin(), m_free_windows.end(),
|
|
|
|
[&buffer](const WindowAndSelections& ws)
|
2014-01-28 00:28:38 +04:00
|
|
|
{ return &ws.window->buffer() == &buffer; });
|
2013-12-21 00:10:08 +04:00
|
|
|
m_free_windows.erase(end, m_free_windows.end());
|
2012-11-07 17:02:23 +04:00
|
|
|
}
|
|
|
|
|
2014-10-20 22:18:38 +04:00
|
|
|
bool ClientManager::validate_client_name(StringView name) const
|
2012-12-03 21:56:53 +04:00
|
|
|
{
|
2015-03-14 14:27:01 +03:00
|
|
|
return const_cast<ClientManager*>(this)->get_client_ifp(name) == nullptr;
|
2012-12-03 21:56:53 +04:00
|
|
|
}
|
|
|
|
|
2014-10-20 22:18:38 +04:00
|
|
|
Client* ClientManager::get_client_ifp(StringView name)
|
2013-01-07 16:59:09 +04:00
|
|
|
{
|
|
|
|
for (auto& client : m_clients)
|
|
|
|
{
|
2013-11-15 00:51:25 +04:00
|
|
|
if (client->context().name() == name)
|
2013-12-07 17:43:48 +04:00
|
|
|
return client.get();
|
2013-01-07 16:59:09 +04:00
|
|
|
}
|
2013-12-07 17:43:48 +04:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2014-10-20 22:18:38 +04:00
|
|
|
Client& ClientManager::get_client(StringView name)
|
2013-12-07 17:43:48 +04:00
|
|
|
{
|
2015-01-05 01:34:36 +03:00
|
|
|
if (Client* client = get_client_ifp(name))
|
|
|
|
return *client;
|
2015-06-01 23:15:59 +03:00
|
|
|
throw runtime_error(format("no client named '{}'", name));
|
2012-12-03 21:56:53 +04:00
|
|
|
}
|
|
|
|
|
2012-11-05 22:58:04 +04:00
|
|
|
void ClientManager::redraw_clients() const
|
|
|
|
{
|
|
|
|
for (auto& client : m_clients)
|
2013-09-16 22:15:13 +04:00
|
|
|
client->redraw_ifn();
|
2012-11-05 22:58:04 +04:00
|
|
|
}
|
|
|
|
|
2014-04-18 17:02:14 +04:00
|
|
|
CandidateList ClientManager::complete_client_name(StringView prefix,
|
2014-04-08 00:43:55 +04:00
|
|
|
ByteCount cursor_pos) const
|
|
|
|
{
|
2014-12-23 16:54:09 +03:00
|
|
|
auto c = transformed(m_clients, [](const std::unique_ptr<Client>& c){ return c->context().name(); });
|
|
|
|
return complete(prefix, cursor_pos, c, prefix_match, subsequence_match);
|
2014-04-08 00:43:55 +04:00
|
|
|
}
|
|
|
|
|
2012-10-30 17:00:44 +04:00
|
|
|
}
|