summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaxime Coste <mawww@kakoune.org>2023-09-26 17:50:56 +1000
committerMaxime Coste <mawww@kakoune.org>2023-09-26 17:50:56 +1000
commit23afed056b14f66b345a4b36dd742848bec91ea2 (patch)
tree3df6e22749386d9db986393b8bff034c8d01be2a
parent3bf16c0fb12509934334593aa284730f137dda08 (diff)
Add a daemonize-session command and refactor local client handling
Make it possible to move the current session to a daemon one after the fact, which is useful to ensure the session state survives client disconnecting, for example when working from ssh.
-rw-r--r--doc/pages/changelog.asciidoc3
-rw-r--r--src/commands.cc12
-rw-r--r--src/main.cc70
-rw-r--r--src/remote.hh1
4 files changed, 41 insertions, 45 deletions
diff --git a/doc/pages/changelog.asciidoc b/doc/pages/changelog.asciidoc
index f60b9ce2..e8331d13 100644
--- a/doc/pages/changelog.asciidoc
+++ b/doc/pages/changelog.asciidoc
@@ -8,6 +8,9 @@ released versions.
* `+` only duplicates identical selections a single time to avoid surprising
and slow exponential growth in the number of selections.
+* `daemonize-session` command makes it possible to convert the current session
+ to a deamon one (which will not exit on last client disconnecting)
+
== Kakoune 2023.08.08
* Fix compilation errors on FreeBSD and MacOS using clang
diff --git a/src/commands.cc b/src/commands.cc
index fe986c42..685ced82 100644
--- a/src/commands.cc
+++ b/src/commands.cc
@@ -688,6 +688,17 @@ const CommandDesc force_kill_cmd = {
kill<true>
};
+const CommandDesc daemonize_session_cmd = {
+ "daemonize-session",
+ nullptr,
+ "daemonize-session: set the session server not to quit on last client exit",
+ { {} },
+ CommandFlags::None,
+ CommandHelper{},
+ CommandCompleter{},
+ [](const ParametersParser&, Context&, const ShellContext&) { Server::instance().daemonize(); }
+};
+
template<bool force>
void quit(const ParametersParser& parser, Context& context, const ShellContext&)
{
@@ -2756,6 +2767,7 @@ void register_commands()
register_command(write_all_quit_cmd);
register_command(kill_cmd);
register_command(force_kill_cmd);
+ register_command(daemonize_session_cmd);
register_command(quit_cmd);
register_command(force_quit_cmd);
register_command(write_quit_cmd);
diff --git a/src/main.cc b/src/main.cc
index 411e7dfe..438a3012 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -47,6 +47,7 @@ struct {
} constexpr version_notes[] = { {
0,
"» {+b}+{} only duplicates identical selections a single time\n"
+ "» {+u}daemonize-session{} command\n"
}, {
20230805,
"» Fix FreeBSD/MacOS clang compilation\n"
@@ -603,7 +604,6 @@ void register_options()
}
static Client* local_client = nullptr;
-static int local_client_exit = 0;
static bool convert_to_client_pending = false;
enum class UIType
@@ -671,38 +671,7 @@ pid_t fork_server_to_background()
std::unique_ptr<UserInterface> create_local_ui(UIType ui_type)
{
- if (ui_type != UIType::Terminal)
- return make_ui(ui_type);
-
- struct LocalUI : TerminalUI
- {
- LocalUI()
- {
- set_signal_handler(SIGTSTP, [](int) {
- if (ClientManager::instance().count() == 1 and
- *ClientManager::instance().begin() == local_client)
- TerminalUI::instance().suspend();
- else
- convert_to_client_pending = true;
- });
- }
-
- ~LocalUI() override
- {
- local_client = nullptr;
- if (convert_to_client_pending or
- ClientManager::instance().empty())
- return;
-
- if (fork_server_to_background())
- {
- this->TerminalUI::~TerminalUI();
- exit(local_client_exit);
- }
- }
- };
-
- if (not isatty(0))
+ if (ui_type == UIType::Terminal and not isatty(0))
{
// move stdin to another fd, and restore tty as stdin
int fd = dup(0);
@@ -712,7 +681,19 @@ std::unique_ptr<UserInterface> create_local_ui(UIType ui_type)
create_fifo_buffer("*stdin*", fd, Buffer::Flags::None);
}
- return std::make_unique<LocalUI>();
+ auto ui = make_ui(ui_type);
+
+ static SignalHandler old_handler = set_signal_handler(SIGTSTP, [](int sig) {
+ if (ClientManager::instance().count() == 1 and
+ *ClientManager::instance().begin() == local_client)
+ old_handler(sig);
+ else
+ {
+ convert_to_client_pending = true;
+ set_signal_handler(SIGTSTP, old_handler);
+ }
+ });
+ return ui;
}
int run_client(StringView session, StringView name, StringView client_init,
@@ -875,13 +856,14 @@ int run_server(StringView session, StringView server_init,
write_to_debug_buffer(format("error while opening command line files: {}", error.what()));
}
+ int exit_status = 0;
try
{
if (not server.is_daemon())
{
local_client = client_manager.create_client(
create_local_ui(ui_type), getpid(), {}, get_env_vars(), client_init, init_buffer, std::move(init_coord),
- [](int status) { local_client_exit = status; });
+ [&](int status) { exit_status = status; });
if (startup_error and local_client)
local_client->print_status({
@@ -920,24 +902,22 @@ int run_server(StringView session, StringView server_init,
global_scope.option_registry().clear_option_trash();
if (local_client and not contains(client_manager, local_client))
- local_client = nullptr;
- else if (local_client and not local_client->is_ui_ok())
{
- ClientManager::instance().remove_client(*local_client, false, -1);
local_client = nullptr;
- if (not client_manager.empty() and fork_server_to_background())
- return 0;
+ if ((not client_manager.empty() or server.is_daemon()) and fork_server_to_background())
+ exit(exit_status); // We do not want to run destructors and hooks here
}
else if (convert_to_client_pending)
{
kak_assert(local_client);
auto& local_context = local_client->context();
- const String client_name = local_context.name();
- const String buffer_name = local_context.buffer().name();
- const String selections = selection_list_to_string(ColumnType::Byte, local_context.selections());
+ String client_name = local_context.name();
+ String buffer_name = local_context.buffer().name();
+ String selections = selection_list_to_string(ColumnType::Byte, local_context.selections());
ClientManager::instance().remove_client(*local_client, true, 0);
client_manager.clear_client_trash();
+ local_client = nullptr;
convert_to_client_pending = false;
if (fork_server_to_background())
@@ -952,7 +932,7 @@ int run_server(StringView session, StringView server_init,
}
catch (const kill_session& kill)
{
- local_client_exit = kill.exit_status;
+ exit_status = kill.exit_status;
}
{
@@ -960,7 +940,7 @@ int run_server(StringView session, StringView server_init,
global_scope.hooks().run_hook(Hook::KakEnd, "", empty_context);
}
- return local_client_exit;
+ return exit_status;
}
int run_filter(StringView keystr, ConstArrayView<StringView> files, bool quiet, StringView suffix_backup)
diff --git a/src/remote.hh b/src/remote.hh
index 903e03f1..99e60cbd 100644
--- a/src/remote.hh
+++ b/src/remote.hh
@@ -59,6 +59,7 @@ struct Server : public Singleton<Server>
bool negotiating() const { return not m_accepters.empty(); }
+ void daemonize() { m_is_daemon = true; }
bool is_daemon() const { return m_is_daemon; }
private: