Support specifying an exit status on quit
commands
The current client exit status can be specified as an optional parameter, is nothing is given the exit status will be 0. Fixes #1230
This commit is contained in:
parent
3efc406d57
commit
f7bed9eb18
|
@ -682,11 +682,14 @@ command `q!` has to be used).
|
||||||
permissions are temporarily changed to allow saving the buffer and
|
permissions are temporarily changed to allow saving the buffer and
|
||||||
restored afterwards when the write! command is used.
|
restored afterwards when the write! command is used.
|
||||||
* `w[rite]a[ll]`: write all buffers that are associated to a file.
|
* `w[rite]a[ll]`: write all buffers that are associated to a file.
|
||||||
* `q[uit][!]`: exit Kakoune, use quit! to force quitting even if there is some
|
* `q[uit][!] [<exit status>]`: exit Kakoune, use quit! to force quitting even
|
||||||
unsaved buffers remaining.
|
if there is some unsaved buffers remaining. If specified, the client exit
|
||||||
|
status will be set to <exit status>.
|
||||||
|
* `w[a]q[!] [<exit status>]`: write the current buffer (or all buffers when
|
||||||
|
`waq` is used) and quit. If specified, the client exit status will be set
|
||||||
|
to <exit status>.
|
||||||
* `kill[!]`: terminate the current session, all the clients as well as the server,
|
* `kill[!]`: terminate the current session, all the clients as well as the server,
|
||||||
use kill! to ignore unsaved buffers
|
use kill! to ignore unsaved buffers
|
||||||
* `w[a]q[!]`: write the current buffer (or all buffers when `waq` is used) and quit
|
|
||||||
* `b[uffer] <name>`: switch to buffer <name>
|
* `b[uffer] <name>`: switch to buffer <name>
|
||||||
* `b[uffer]n[ext]`: switch to the next buffer
|
* `b[uffer]n[ext]`: switch to the next buffer
|
||||||
* `b[uffer]p[rev]`: switch to the previous buffer
|
* `b[uffer]p[rev]`: switch to the previous buffer
|
||||||
|
|
|
@ -33,16 +33,18 @@ command *q!* has to be used).
|
||||||
*w[rite]a[ll]*::
|
*w[rite]a[ll]*::
|
||||||
write all buffers that are associated to a file
|
write all buffers that are associated to a file
|
||||||
|
|
||||||
*q[uit][!]*::
|
*q[uit][!]* [<exit status>]::
|
||||||
exit Kakoune, use quit! to force quitting even if there is some
|
exit Kakoune, use quit! to force quitting even if there is some
|
||||||
unsaved buffers remaining
|
unsaved buffers remaining. If specified, the client exit status
|
||||||
|
will be set to <exit status>
|
||||||
|
|
||||||
|
*w[a]q[!]* [<exit status>]::
|
||||||
|
write the current buffer (or all buffers when *waq* is used) and quit.
|
||||||
|
If specified, the client exit status will be set to <exit status>
|
||||||
|
|
||||||
*kill*::
|
*kill*::
|
||||||
terminate the current session, all the clients as well as the server
|
terminate the current session, all the clients as well as the server
|
||||||
|
|
||||||
*w[a]q[!]*::
|
|
||||||
write the current buffer (or all buffers when *waq* is used) and quit
|
|
||||||
|
|
||||||
*b[uffer]* <name>::
|
*b[uffer]* <name>::
|
||||||
switch to buffer <name>
|
switch to buffer <name>
|
||||||
|
|
||||||
|
|
|
@ -26,8 +26,10 @@ Client::Client(std::unique_ptr<UserInterface>&& ui,
|
||||||
std::unique_ptr<Window>&& window,
|
std::unique_ptr<Window>&& window,
|
||||||
SelectionList selections,
|
SelectionList selections,
|
||||||
EnvVarMap env_vars,
|
EnvVarMap env_vars,
|
||||||
String name)
|
String name,
|
||||||
|
OnExitCallback on_exit)
|
||||||
: m_ui{std::move(ui)}, m_window{std::move(window)},
|
: m_ui{std::move(ui)}, m_window{std::move(window)},
|
||||||
|
m_on_exit{std::move(on_exit)},
|
||||||
m_input_handler{std::move(selections), Context::Flags::None,
|
m_input_handler{std::move(selections), Context::Flags::None,
|
||||||
std::move(name)},
|
std::move(name)},
|
||||||
m_env_vars(std::move(env_vars))
|
m_env_vars(std::move(env_vars))
|
||||||
|
|
|
@ -21,15 +21,17 @@ enum class EventMode;
|
||||||
enum class InfoStyle;
|
enum class InfoStyle;
|
||||||
enum class MenuStyle;
|
enum class MenuStyle;
|
||||||
|
|
||||||
|
|
||||||
class Client : public SafeCountable, public OptionManagerWatcher
|
class Client : public SafeCountable, public OptionManagerWatcher
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
using OnExitCallback = std::function<void (int status)>;
|
||||||
|
|
||||||
Client(std::unique_ptr<UserInterface>&& ui,
|
Client(std::unique_ptr<UserInterface>&& ui,
|
||||||
std::unique_ptr<Window>&& window,
|
std::unique_ptr<Window>&& window,
|
||||||
SelectionList selections,
|
SelectionList selections,
|
||||||
EnvVarMap env_vars,
|
EnvVarMap env_vars,
|
||||||
String name);
|
String name,
|
||||||
|
OnExitCallback on_exit);
|
||||||
~Client();
|
~Client();
|
||||||
|
|
||||||
Client(Client&&) = delete;
|
Client(Client&&) = delete;
|
||||||
|
@ -65,6 +67,8 @@ public:
|
||||||
Buffer* last_buffer() const { return m_last_buffer.get(); }
|
Buffer* last_buffer() const { return m_last_buffer.get(); }
|
||||||
void set_last_buffer(Buffer* last_buffer) { m_last_buffer = last_buffer; }
|
void set_last_buffer(Buffer* last_buffer) { m_last_buffer = last_buffer; }
|
||||||
|
|
||||||
|
void exit(int status) { m_on_exit(status); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void on_option_changed(const Option& option) override;
|
void on_option_changed(const Option& option) override;
|
||||||
|
|
||||||
|
@ -79,6 +83,8 @@ private:
|
||||||
std::unique_ptr<UserInterface> m_ui;
|
std::unique_ptr<UserInterface> m_ui;
|
||||||
std::unique_ptr<Window> m_window;
|
std::unique_ptr<Window> m_window;
|
||||||
|
|
||||||
|
OnExitCallback m_on_exit;
|
||||||
|
|
||||||
EnvVarMap m_env_vars;
|
EnvVarMap m_env_vars;
|
||||||
|
|
||||||
InputHandler m_input_handler;
|
InputHandler m_input_handler;
|
||||||
|
|
|
@ -40,13 +40,14 @@ String ClientManager::generate_name() const
|
||||||
|
|
||||||
Client* ClientManager::create_client(std::unique_ptr<UserInterface>&& ui,
|
Client* ClientManager::create_client(std::unique_ptr<UserInterface>&& ui,
|
||||||
EnvVarMap env_vars, StringView init_cmds,
|
EnvVarMap env_vars, StringView init_cmds,
|
||||||
Optional<BufferCoord> init_coord)
|
Optional<BufferCoord> init_coord,
|
||||||
|
Client::OnExitCallback on_exit)
|
||||||
{
|
{
|
||||||
Buffer& buffer = BufferManager::instance().get_first_buffer();
|
Buffer& buffer = BufferManager::instance().get_first_buffer();
|
||||||
WindowAndSelections ws = get_free_window(buffer);
|
WindowAndSelections ws = get_free_window(buffer);
|
||||||
Client* client = new Client{std::move(ui), std::move(ws.window),
|
Client* client = new Client{std::move(ui), std::move(ws.window),
|
||||||
std::move(ws.selections), std::move(env_vars),
|
std::move(ws.selections), std::move(env_vars),
|
||||||
generate_name()};
|
generate_name(), std::move(on_exit)};
|
||||||
m_clients.emplace_back(client);
|
m_clients.emplace_back(client);
|
||||||
|
|
||||||
if (init_coord)
|
if (init_coord)
|
||||||
|
@ -88,7 +89,7 @@ void ClientManager::process_pending_inputs() const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientManager::remove_client(Client& client, bool graceful)
|
void ClientManager::remove_client(Client& client, bool graceful, int status)
|
||||||
{
|
{
|
||||||
auto it = find(m_clients, &client);
|
auto it = find(m_clients, &client);
|
||||||
if (it == m_clients.end())
|
if (it == m_clients.end())
|
||||||
|
@ -96,6 +97,7 @@ void ClientManager::remove_client(Client& client, bool graceful)
|
||||||
kak_assert(contains(m_client_trash, &client));
|
kak_assert(contains(m_client_trash, &client));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
client.exit(status);
|
||||||
m_client_trash.push_back(std::move(*it));
|
m_client_trash.push_back(std::move(*it));
|
||||||
m_clients.erase(it);
|
m_clients.erase(it);
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,8 @@ public:
|
||||||
|
|
||||||
Client* create_client(std::unique_ptr<UserInterface>&& ui,
|
Client* create_client(std::unique_ptr<UserInterface>&& ui,
|
||||||
EnvVarMap env_vars, StringView init_cmds,
|
EnvVarMap env_vars, StringView init_cmds,
|
||||||
Optional<BufferCoord> init_coord);
|
Optional<BufferCoord> init_coord,
|
||||||
|
Client::OnExitCallback on_exit);
|
||||||
|
|
||||||
bool empty() const { return m_clients.empty(); }
|
bool empty() const { return m_clients.empty(); }
|
||||||
size_t count() const { return m_clients.size(); }
|
size_t count() const { return m_clients.size(); }
|
||||||
|
@ -39,7 +40,7 @@ public:
|
||||||
Client* get_client_ifp(StringView name);
|
Client* get_client_ifp(StringView name);
|
||||||
Client& get_client(StringView name);
|
Client& get_client(StringView name);
|
||||||
bool validate_client_name(StringView name) const;
|
bool validate_client_name(StringView name) const;
|
||||||
void remove_client(Client& client, bool graceful);
|
void remove_client(Client& client, bool graceful, int status);
|
||||||
|
|
||||||
using ClientList = Vector<std::unique_ptr<Client>, MemoryDomain::Client>;
|
using ClientList = Vector<std::unique_ptr<Client>, MemoryDomain::Client>;
|
||||||
using iterator = ClientList::const_iterator;
|
using iterator = ClientList::const_iterator;
|
||||||
|
|
|
@ -423,24 +423,26 @@ const CommandDesc force_kill_cmd = {
|
||||||
};
|
};
|
||||||
|
|
||||||
template<bool force>
|
template<bool force>
|
||||||
void quit(Context& context)
|
void quit(const ParametersParser& parser, Context& context, const ShellContext&)
|
||||||
{
|
{
|
||||||
if (not force and ClientManager::instance().count() == 1)
|
if (not force and ClientManager::instance().count() == 1)
|
||||||
ensure_all_buffers_are_saved();
|
ensure_all_buffers_are_saved();
|
||||||
|
|
||||||
ClientManager::instance().remove_client(context.client(), true);
|
const int status = parser.positional_count() > 0 ? str_to_int(parser[0]) : 0;
|
||||||
|
ClientManager::instance().remove_client(context.client(), true, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
const CommandDesc quit_cmd = {
|
const CommandDesc quit_cmd = {
|
||||||
"quit",
|
"quit",
|
||||||
"q",
|
"q",
|
||||||
"quit current client, and the kakoune session if the client is the last "
|
"quit current client, and the kakoune session if the client is the last "
|
||||||
"(if not running in daemon mode)",
|
"(if not running in daemon mode). An optional integer parameter can set "
|
||||||
no_params,
|
"the client exit status",
|
||||||
|
{ {}, ParameterDesc::Flags::SwitchesAsPositional, 0, 1 },
|
||||||
CommandFlags::None,
|
CommandFlags::None,
|
||||||
CommandHelper{},
|
CommandHelper{},
|
||||||
CommandCompleter{},
|
CommandCompleter{},
|
||||||
[](const ParametersParser&, Context& context, const ShellContext&){ quit<false>(context); }
|
quit<false>
|
||||||
};
|
};
|
||||||
|
|
||||||
const CommandDesc force_quit_cmd = {
|
const CommandDesc force_quit_cmd = {
|
||||||
|
@ -448,27 +450,29 @@ const CommandDesc force_quit_cmd = {
|
||||||
"q!",
|
"q!",
|
||||||
"quit current client, and the kakoune session if the client is the last "
|
"quit current client, and the kakoune session if the client is the last "
|
||||||
"(if not running in daemon mode). force quit even if the client is the "
|
"(if not running in daemon mode). force quit even if the client is the "
|
||||||
"last and some buffers are not saved.",
|
"last and some buffers are not saved. An optional integer parameter can "
|
||||||
no_params,
|
"set the client exit status",
|
||||||
|
{ {}, ParameterDesc::Flags::SwitchesAsPositional, 0, 1 },
|
||||||
CommandFlags::None,
|
CommandFlags::None,
|
||||||
CommandHelper{},
|
CommandHelper{},
|
||||||
CommandCompleter{},
|
CommandCompleter{},
|
||||||
[](const ParametersParser&, Context& context, const ShellContext&){ quit<true>(context); }
|
quit<true>
|
||||||
};
|
};
|
||||||
|
|
||||||
template<bool force>
|
template<bool force>
|
||||||
void write_quit(const ParametersParser& parser, Context& context,
|
void write_quit(const ParametersParser& parser, Context& context,
|
||||||
const ShellContext& shell_context)
|
const ShellContext& shell_context)
|
||||||
{
|
{
|
||||||
write_buffer(parser, context, shell_context);
|
write_buffer({{}, {}}, context, shell_context);
|
||||||
quit<force>(context);
|
quit<force>(parser, context, shell_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
const CommandDesc write_quit_cmd = {
|
const CommandDesc write_quit_cmd = {
|
||||||
"write-quit",
|
"write-quit",
|
||||||
"wq",
|
"wq",
|
||||||
"write current buffer and quit current client",
|
"write current buffer and quit current client. An optional integer"
|
||||||
no_params,
|
"parameter can set the client exit status",
|
||||||
|
{ {}, ParameterDesc::Flags::SwitchesAsPositional, 0, 1 },
|
||||||
CommandFlags::None,
|
CommandFlags::None,
|
||||||
CommandHelper{},
|
CommandHelper{},
|
||||||
CommandCompleter{},
|
CommandCompleter{},
|
||||||
|
@ -479,8 +483,8 @@ const CommandDesc force_write_quit_cmd = {
|
||||||
"write-quit!",
|
"write-quit!",
|
||||||
"wq!",
|
"wq!",
|
||||||
"write current buffer and quit current client, even if other buffers are "
|
"write current buffer and quit current client, even if other buffers are "
|
||||||
"not saved",
|
"not saved. An optional integer parameter can set the client exit status",
|
||||||
no_params,
|
{ {}, ParameterDesc::Flags::SwitchesAsPositional, 0, 1 },
|
||||||
CommandFlags::None,
|
CommandFlags::None,
|
||||||
CommandHelper{},
|
CommandHelper{},
|
||||||
CommandCompleter{},
|
CommandCompleter{},
|
||||||
|
@ -490,15 +494,16 @@ const CommandDesc force_write_quit_cmd = {
|
||||||
const CommandDesc write_all_quit_cmd = {
|
const CommandDesc write_all_quit_cmd = {
|
||||||
"write-all-quit",
|
"write-all-quit",
|
||||||
"waq",
|
"waq",
|
||||||
"write all buffers associated to a file and quit current client",
|
"write all buffers associated to a file and quit current client. An "
|
||||||
no_params,
|
"optional integer parameter can set the client exit status",
|
||||||
|
{ {}, ParameterDesc::Flags::SwitchesAsPositional, 0, 1 },
|
||||||
CommandFlags::None,
|
CommandFlags::None,
|
||||||
CommandHelper{},
|
CommandHelper{},
|
||||||
CommandCompleter{},
|
CommandCompleter{},
|
||||||
[](const ParametersParser& parser, Context& context, const ShellContext&)
|
[](const ParametersParser& parser, Context& context, const ShellContext& shell_context)
|
||||||
{
|
{
|
||||||
write_all_buffers(context);
|
write_all_buffers(context);
|
||||||
quit<false>(context);
|
quit<false>(parser, context, shell_context);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
21
src/main.cc
21
src/main.cc
|
@ -328,6 +328,7 @@ void register_options()
|
||||||
}
|
}
|
||||||
|
|
||||||
static Client* local_client = nullptr;
|
static Client* local_client = nullptr;
|
||||||
|
static int local_client_exit = 0;
|
||||||
static UserInterface* local_ui = nullptr;
|
static UserInterface* local_ui = nullptr;
|
||||||
static bool convert_to_client_pending = false;
|
static bool convert_to_client_pending = false;
|
||||||
|
|
||||||
|
@ -403,7 +404,7 @@ std::unique_ptr<UserInterface> create_local_ui(UIType ui_type)
|
||||||
kak_assert(not local_ui);
|
kak_assert(not local_ui);
|
||||||
local_ui = this;
|
local_ui = this;
|
||||||
m_old_sighup = set_signal_handler(SIGHUP, [](int) {
|
m_old_sighup = set_signal_handler(SIGHUP, [](int) {
|
||||||
ClientManager::instance().remove_client(*local_client, false);
|
ClientManager::instance().remove_client(*local_client, false, -1);
|
||||||
static_cast<LocalUI*>(local_ui)->on_sighup();
|
static_cast<LocalUI*>(local_ui)->on_sighup();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -441,7 +442,7 @@ std::unique_ptr<UserInterface> create_local_ui(UIType ui_type)
|
||||||
if (fork_server_to_background())
|
if (fork_server_to_background())
|
||||||
{
|
{
|
||||||
this->NCursesUI::~NCursesUI();
|
this->NCursesUI::~NCursesUI();
|
||||||
exit(0);
|
exit(local_client_exit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -475,16 +476,15 @@ int run_client(StringView session, StringView client_init,
|
||||||
{
|
{
|
||||||
EventManager event_manager;
|
EventManager event_manager;
|
||||||
RemoteClient client{session, make_ui(ui_type), get_env_vars(), client_init, std::move(init_coord)};
|
RemoteClient client{session, make_ui(ui_type), get_env_vars(), client_init, std::move(init_coord)};
|
||||||
while (true)
|
while (not client.exit_status())
|
||||||
event_manager.handle_next_events(EventMode::Normal);
|
event_manager.handle_next_events(EventMode::Normal);
|
||||||
|
return *client.exit_status();
|
||||||
}
|
}
|
||||||
catch (disconnected& e)
|
catch (disconnected& e)
|
||||||
{
|
{
|
||||||
if (!e.m_graceful)
|
|
||||||
write_stderr(format("{}\ndisconnecting\n", e.what()));
|
write_stderr(format("{}\ndisconnecting\n", e.what()));
|
||||||
return e.m_graceful ? 0 : -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct convert_to_client_mode
|
struct convert_to_client_mode
|
||||||
|
@ -614,7 +614,8 @@ int run_server(StringView session, StringView server_init,
|
||||||
if (not (flags & ServerFlags::Daemon))
|
if (not (flags & ServerFlags::Daemon))
|
||||||
{
|
{
|
||||||
local_client = client_manager.create_client(
|
local_client = client_manager.create_client(
|
||||||
create_local_ui(ui_type), get_env_vars(), client_init, std::move(init_coord));
|
create_local_ui(ui_type), get_env_vars(), client_init, std::move(init_coord),
|
||||||
|
[](int status) { local_client_exit = status; });
|
||||||
|
|
||||||
if (startup_error)
|
if (startup_error)
|
||||||
local_client->print_status({
|
local_client->print_status({
|
||||||
|
@ -640,7 +641,7 @@ int run_server(StringView session, StringView server_init,
|
||||||
String buffer_name = local_client->context().buffer().name();
|
String buffer_name = local_client->context().buffer().name();
|
||||||
String selections = selection_list_to_string(local_client->context().selections());
|
String selections = selection_list_to_string(local_client->context().selections());
|
||||||
|
|
||||||
ClientManager::instance().remove_client(*local_client, true);
|
ClientManager::instance().remove_client(*local_client, true, 0);
|
||||||
client_manager.clear_client_trash();
|
client_manager.clear_client_trash();
|
||||||
convert_to_client_pending = false;
|
convert_to_client_pending = false;
|
||||||
|
|
||||||
|
@ -660,7 +661,7 @@ int run_server(StringView session, StringView server_init,
|
||||||
global_scope.hooks().run_hook("KakEnd", "", empty_context);
|
global_scope.hooks().run_hook("KakEnd", "", empty_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return local_client_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
int run_filter(StringView keystr, StringView commands, ConstArrayView<StringView> files, bool quiet, StringView suffix_backup)
|
int run_filter(StringView keystr, StringView commands, ConstArrayView<StringView> files, bool quiet, StringView suffix_backup)
|
||||||
|
@ -743,7 +744,7 @@ int run_pipe(StringView session)
|
||||||
catch (disconnected& e)
|
catch (disconnected& e)
|
||||||
{
|
{
|
||||||
write_stderr(format("{}\ndisconnecting\n", e.what()));
|
write_stderr(format("{}\ndisconnecting\n", e.what()));
|
||||||
return e.m_graceful ? 0 : -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,8 @@ enum class MessageType : uint8_t
|
||||||
SetCursor,
|
SetCursor,
|
||||||
Refresh,
|
Refresh,
|
||||||
SetOptions,
|
SetOptions,
|
||||||
Key
|
Exit,
|
||||||
|
Key,
|
||||||
};
|
};
|
||||||
|
|
||||||
class MsgWriter
|
class MsgWriter
|
||||||
|
@ -252,8 +253,7 @@ private:
|
||||||
kak_assert(m_write_pos + size <= m_stream.size());
|
kak_assert(m_write_pos + size <= m_stream.size());
|
||||||
int res = ::read(sock, m_stream.data() + m_write_pos, size);
|
int res = ::read(sock, m_stream.data() + m_write_pos, size);
|
||||||
if (res <= 0)
|
if (res <= 0)
|
||||||
throw disconnected{res ? format("socket read failed: {}", strerror(errno))
|
throw disconnected{format("socket read failed: {}", strerror(errno))};
|
||||||
: "peer disconnected", res == 0};
|
|
||||||
m_write_pos += res;
|
m_write_pos += res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,6 +352,8 @@ public:
|
||||||
void set_client(Client* client) { m_client = client; }
|
void set_client(Client* client) { m_client = client; }
|
||||||
Client* client() const { return m_client.get(); }
|
Client* client() const { return m_client.get(); }
|
||||||
|
|
||||||
|
void exit(int status);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FDWatcher m_socket_watcher;
|
FDWatcher m_socket_watcher;
|
||||||
MsgReader m_reader;
|
MsgReader m_reader;
|
||||||
|
@ -368,8 +370,7 @@ static bool send_data(int fd, RemoteBuffer& buffer)
|
||||||
{
|
{
|
||||||
int res = ::write(fd, buffer.data(), buffer.size());
|
int res = ::write(fd, buffer.data(), buffer.size());
|
||||||
if (res <= 0)
|
if (res <= 0)
|
||||||
throw disconnected{res ? format("socket write failed: {}", strerror(errno))
|
throw disconnected{format("socket write failed: {}", strerror(errno))};
|
||||||
: "peer disconnected", res == 0};
|
|
||||||
buffer.erase(buffer.begin(), buffer.begin() + res);
|
buffer.erase(buffer.begin(), buffer.begin() + res);
|
||||||
}
|
}
|
||||||
return buffer.empty();
|
return buffer.empty();
|
||||||
|
@ -393,7 +394,7 @@ RemoteUI::RemoteUI(int socket, DisplayCoord dimensions)
|
||||||
|
|
||||||
if (m_reader.type() != MessageType::Key)
|
if (m_reader.type() != MessageType::Key)
|
||||||
{
|
{
|
||||||
ClientManager::instance().remove_client(*m_client, false);
|
ClientManager::instance().remove_client(*m_client, false, -1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,7 +408,7 @@ RemoteUI::RemoteUI(int socket, DisplayCoord dimensions)
|
||||||
catch (const disconnected& err)
|
catch (const disconnected& err)
|
||||||
{
|
{
|
||||||
write_to_debug_buffer(format("Error while transfering remote messages: {}", err.what()));
|
write_to_debug_buffer(format("Error while transfering remote messages: {}", err.what()));
|
||||||
ClientManager::instance().remove_client(*m_client, false);
|
ClientManager::instance().remove_client(*m_client, false, -1);
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
m_dimensions(dimensions)
|
m_dimensions(dimensions)
|
||||||
|
@ -417,6 +418,9 @@ RemoteUI::RemoteUI(int socket, DisplayCoord dimensions)
|
||||||
|
|
||||||
RemoteUI::~RemoteUI()
|
RemoteUI::~RemoteUI()
|
||||||
{
|
{
|
||||||
|
// Try to send the remaining data if possible, as it might contain the desired exit status
|
||||||
|
send_data(m_socket_watcher.fd(), m_send_buffer);
|
||||||
|
|
||||||
write_to_debug_buffer(format("remote client disconnected: {}", m_socket_watcher.fd()));
|
write_to_debug_buffer(format("remote client disconnected: {}", m_socket_watcher.fd()));
|
||||||
m_socket_watcher.close_fd();
|
m_socket_watcher.close_fd();
|
||||||
}
|
}
|
||||||
|
@ -510,6 +514,13 @@ void RemoteUI::set_ui_options(const Options& options)
|
||||||
m_socket_watcher.events() |= FdEvents::Write;
|
m_socket_watcher.events() |= FdEvents::Write;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RemoteUI::exit(int status)
|
||||||
|
{
|
||||||
|
MsgWriter msg{m_send_buffer, MessageType::Exit};
|
||||||
|
msg.write(status);
|
||||||
|
m_socket_watcher.events() |= FdEvents::Write;
|
||||||
|
}
|
||||||
|
|
||||||
static sockaddr_un session_addr(StringView session)
|
static sockaddr_un session_addr(StringView session)
|
||||||
{
|
{
|
||||||
sockaddr_un addr;
|
sockaddr_un addr;
|
||||||
|
@ -637,6 +648,11 @@ RemoteClient::RemoteClient(StringView session, std::unique_ptr<UserInterface>&&
|
||||||
case MessageType::SetOptions:
|
case MessageType::SetOptions:
|
||||||
m_ui->set_ui_options(reader.read_hash_map<String, String, MemoryDomain::Options>());
|
m_ui->set_ui_options(reader.read_hash_map<String, String, MemoryDomain::Options>());
|
||||||
break;
|
break;
|
||||||
|
case MessageType::Exit:
|
||||||
|
m_exit_status = reader.read<int>();
|
||||||
|
m_socket_watcher->close_fd();
|
||||||
|
m_socket_watcher.reset();
|
||||||
|
return; // This lambda is now dead
|
||||||
default:
|
default:
|
||||||
kak_assert(false);
|
kak_assert(false);
|
||||||
}
|
}
|
||||||
|
@ -697,7 +713,8 @@ private:
|
||||||
auto* ui = new RemoteUI{sock, dimensions};
|
auto* ui = new RemoteUI{sock, dimensions};
|
||||||
if (auto* client = ClientManager::instance().create_client(
|
if (auto* client = ClientManager::instance().create_client(
|
||||||
std::unique_ptr<UserInterface>(ui),
|
std::unique_ptr<UserInterface>(ui),
|
||||||
std::move(env_vars), init_cmds, init_coord))
|
std::move(env_vars), init_cmds, init_coord,
|
||||||
|
[ui](int status) { ui->exit(status); }))
|
||||||
ui->set_client(client);
|
ui->set_client(client);
|
||||||
|
|
||||||
Server::instance().remove_accepter(this);
|
Server::instance().remove_accepter(this);
|
||||||
|
|
|
@ -13,10 +13,7 @@ namespace Kakoune
|
||||||
|
|
||||||
struct disconnected : runtime_error
|
struct disconnected : runtime_error
|
||||||
{
|
{
|
||||||
disconnected(String what, bool graceful = false)
|
using runtime_error::runtime_error;
|
||||||
: runtime_error{std::move(what)}, m_graceful{graceful} {}
|
|
||||||
|
|
||||||
const bool m_graceful;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class FDWatcher;
|
class FDWatcher;
|
||||||
|
@ -36,10 +33,12 @@ public:
|
||||||
const EnvVarMap& env_vars, StringView init_command,
|
const EnvVarMap& env_vars, StringView init_command,
|
||||||
Optional<BufferCoord> init_coord);
|
Optional<BufferCoord> init_coord);
|
||||||
|
|
||||||
|
const Optional<int>& exit_status() const { return m_exit_status; }
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<UserInterface> m_ui;
|
std::unique_ptr<UserInterface> m_ui;
|
||||||
std::unique_ptr<FDWatcher> m_socket_watcher;
|
std::unique_ptr<FDWatcher> m_socket_watcher;
|
||||||
RemoteBuffer m_send_buffer;
|
RemoteBuffer m_send_buffer;
|
||||||
|
Optional<int> m_exit_status;
|
||||||
};
|
};
|
||||||
|
|
||||||
void send_command(StringView session, StringView command);
|
void send_command(StringView session, StringView command);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user