Reorganize code in main.cc

This commit is contained in:
Maxime Coste 2017-02-14 13:54:45 +00:00
parent d470bd2cc9
commit 9e0f085b86

View File

@ -33,11 +33,12 @@
#include <unistd.h> #include <unistd.h>
#include <pwd.h> #include <pwd.h>
using namespace Kakoune; namespace Kakoune
struct startup_error : Kakoune::runtime_error
{ {
using Kakoune::runtime_error::runtime_error;
struct startup_error : runtime_error
{
using runtime_error::runtime_error;
}; };
inline void write_stdout(StringView str) { write(1, str); } inline void write_stdout(StringView str) { write(1, str); }
@ -298,12 +299,9 @@ void register_options()
""_str); ""_str);
} }
struct convert_to_client_mode static Client* local_client = nullptr;
{ static UserInterface* local_ui = nullptr;
String session; static bool convert_to_client_pending = false;
String buffer_name;
String selections;
};
enum class UIType enum class UIType
{ {
@ -312,21 +310,13 @@ enum class UIType
Dummy, Dummy,
}; };
static Client* local_client = nullptr; UIType parse_ui_type(StringView ui_name)
static UserInterface* local_ui = nullptr;
static bool convert_to_client_pending = false;
pid_t fork_server_to_background()
{ {
if (pid_t pid = fork()) if (ui_name == "ncurses") return UIType::NCurses;
return pid; if (ui_name == "json") return UIType::Json;
if (ui_name == "dummy") return UIType::Dummy;
if (fork()) // double fork to orphan the server throw parameter_error(format("error: unknown ui type: '{}'", ui_name));
exit(0);
write_stderr(format("Kakoune forked server to background ({}), for session '{}'\n",
getpid(), Server::instance().session()));
return 0;
} }
std::unique_ptr<UserInterface> make_ui(UIType ui_type) std::unique_ptr<UserInterface> make_ui(UIType ui_type)
@ -346,7 +336,7 @@ std::unique_ptr<UserInterface> make_ui(UIType ui_type)
void draw_status(const DisplayLine&, const DisplayLine&, const Face&) override {} void draw_status(const DisplayLine&, const DisplayLine&, const Face&) override {}
DisplayCoord dimensions() override { return {24,80}; } DisplayCoord dimensions() override { return {24,80}; }
void refresh(bool) override {} void refresh(bool) override {}
void set_on_key(OnKeyCallback callback) override {} void set_on_key(OnKeyCallback) override {}
void set_ui_options(const Options&) override {} void set_ui_options(const Options&) override {}
}; };
@ -359,6 +349,19 @@ std::unique_ptr<UserInterface> make_ui(UIType ui_type)
throw logic_error{}; throw logic_error{};
} }
pid_t fork_server_to_background()
{
if (pid_t pid = fork())
return pid;
if (fork()) // double fork to orphan the server
exit(0);
write_stderr(format("Kakoune forked server to background ({}), for session '{}'\n",
getpid(), Server::instance().session()));
return 0;
}
std::unique_ptr<UserInterface> create_local_ui(UIType ui_type) std::unique_ptr<UserInterface> create_local_ui(UIType ui_type)
{ {
if (ui_type != UIType::NCurses) if (ui_type != UIType::NCurses)
@ -436,37 +439,6 @@ std::unique_ptr<UserInterface> create_local_ui(UIType ui_type)
return make_unique<LocalUI>(); return make_unique<LocalUI>();
} }
void signal_handler(int signal)
{
NCursesUI::abort();
const char* text = nullptr;
switch (signal)
{
case SIGSEGV: text = "SIGSEGV"; break;
case SIGFPE: text = "SIGFPE"; break;
case SIGQUIT: text = "SIGQUIT"; break;
case SIGTERM: text = "SIGTERM"; break;
case SIGPIPE: text = "SIGPIPE"; break;
}
if (signal != SIGTERM)
{
auto msg = format("Received {}, exiting.\nPid: {}\nCallstack:\n{}",
text, getpid(), Backtrace{}.desc());
write_stderr(msg);
notify_fatal_error(msg);
}
if (Server::has_instance())
Server::instance().close_session();
if (BufferManager::has_instance())
BufferManager::instance().backup_modified_buffers();
if (signal == SIGTERM)
exit(-1);
else
abort();
}
int run_client(StringView session, StringView init_cmds, int run_client(StringView session, StringView init_cmds,
Optional<BufferCoord> init_coord, UIType ui_type) Optional<BufferCoord> init_coord, UIType ui_type)
{ {
@ -486,13 +458,29 @@ int run_client(StringView session, StringView init_cmds,
return 0; return 0;
} }
struct convert_to_client_mode
{
String session;
String buffer_name;
String selections;
};
enum class ServerFlags
{
None = 0,
IgnoreKakrc = 1 << 0,
Daemon = 1 << 1,
ReadOnly = 1 << 2,
};
template<> struct WithBitOps<ServerFlags> : std::true_type {};
int run_server(StringView session, int run_server(StringView session,
StringView init_cmds, Optional<BufferCoord> init_coord, StringView init_cmds, Optional<BufferCoord> init_coord,
bool ignore_kakrc, bool daemon, bool readonly, UIType ui_type, ServerFlags flags, UIType ui_type,
ConstArrayView<StringView> files) ConstArrayView<StringView> files)
{ {
static bool terminate = false; static bool terminate = false;
if (daemon) if (flags & ServerFlags::Daemon)
{ {
if (session.empty()) if (session.empty())
{ {
@ -531,18 +519,18 @@ int run_server(StringView session,
write_to_debug_buffer("*** This is the debug buffer, where debug info will be written ***"); write_to_debug_buffer("*** This is the debug buffer, where debug info will be written ***");
GlobalScope::instance().options().get_local_option("readonly").set(readonly); GlobalScope::instance().options().get_local_option("readonly").set<bool>(flags & ServerFlags::ReadOnly);
Server server{session.empty() ? to_string(getpid()) : session.str()}; Server server{session.empty() ? to_string(getpid()) : session.str()};
bool startup_error = false; bool startup_error = false;
if (not ignore_kakrc) try if (not (flags & ServerFlags::IgnoreKakrc)) try
{ {
Context initialisation_context{Context::EmptyContextFlag{}}; Context initialisation_context{Context::EmptyContextFlag{}};
command_manager.execute(format("source {}/kakrc", runtime_directory()), command_manager.execute(format("source {}/kakrc", runtime_directory()),
initialisation_context); initialisation_context);
} }
catch (Kakoune::runtime_error& error) catch (runtime_error& error)
{ {
startup_error = true; startup_error = true;
write_to_debug_buffer(format("error while parsing kakrc:\n" write_to_debug_buffer(format("error while parsing kakrc:\n"
@ -563,10 +551,10 @@ int run_server(StringView session,
try try
{ {
Buffer *buffer = open_or_create_file_buffer(file); Buffer *buffer = open_or_create_file_buffer(file);
if (readonly) if (flags & ServerFlags::ReadOnly)
buffer->flags() |= Buffer::Flags::ReadOnly; buffer->flags() |= Buffer::Flags::ReadOnly;
} }
catch (Kakoune::runtime_error& error) catch (runtime_error& error)
{ {
startup_error = true; startup_error = true;
write_to_debug_buffer(format("error while opening file '{}':\n" write_to_debug_buffer(format("error while opening file '{}':\n"
@ -574,14 +562,14 @@ int run_server(StringView session,
} }
} }
} }
catch (Kakoune::runtime_error& error) catch (runtime_error& error)
{ {
write_to_debug_buffer(format("error while opening command line files: {}", error.what())); write_to_debug_buffer(format("error while opening command line files: {}", error.what()));
} }
try try
{ {
if (not 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(), init_cmds, init_coord); create_local_ui(ui_type), get_env_vars(), init_cmds, init_coord);
@ -591,7 +579,7 @@ int run_server(StringView session,
get_face("Error") get_face("Error")
}); });
while (not terminate and (not client_manager.empty() or daemon)) while (not terminate and (not client_manager.empty() or (flags & ServerFlags::Daemon)))
{ {
client_manager.redraw_clients(); client_manager.redraw_clients();
event_manager.handle_next_events(EventMode::Normal); event_manager.handle_next_events(EventMode::Normal);
@ -665,7 +653,7 @@ int run_filter(StringView keystr, StringView commands, ConstArrayView<StringView
for (auto& key : keys) for (auto& key : keys)
input_handler.handle_key(key); input_handler.handle_key(key);
} }
catch (Kakoune::runtime_error& err) catch (runtime_error& err)
{ {
if (not quiet) if (not quiet)
write_stderr(format("error while applying keys to buffer '{}': {}\n", write_stderr(format("error while applying keys to buffer '{}': {}\n",
@ -690,7 +678,7 @@ int run_filter(StringView keystr, StringView commands, ConstArrayView<StringView
buffer_manager.delete_buffer(buffer); buffer_manager.delete_buffer(buffer);
} }
} }
catch (Kakoune::runtime_error& err) catch (runtime_error& err)
{ {
write_stderr(format("error: {}\n", err.what())); write_stderr(format("error: {}\n", err.what()));
} }
@ -724,17 +712,43 @@ int run_pipe(StringView session)
return 0; return 0;
} }
UIType parse_ui_type(StringView ui_name) void signal_handler(int signal)
{ {
if (ui_name == "ncurses") return UIType::NCurses; NCursesUI::abort();
if (ui_name == "json") return UIType::Json; const char* text = nullptr;
if (ui_name == "dummy") return UIType::Dummy; switch (signal)
{
case SIGSEGV: text = "SIGSEGV"; break;
case SIGFPE: text = "SIGFPE"; break;
case SIGQUIT: text = "SIGQUIT"; break;
case SIGTERM: text = "SIGTERM"; break;
case SIGPIPE: text = "SIGPIPE"; break;
}
if (signal != SIGTERM)
{
auto msg = format("Received {}, exiting.\nPid: {}\nCallstack:\n{}",
text, getpid(), Backtrace{}.desc());
write_stderr(msg);
notify_fatal_error(msg);
}
if (Server::has_instance())
Server::instance().close_session();
if (BufferManager::has_instance())
BufferManager::instance().backup_modified_buffers();
if (signal == SIGTERM)
exit(-1);
else
abort();
}
throw parameter_error(format("error: unknown ui type: '{}'", ui_name));
} }
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
using namespace Kakoune;
setlocale(LC_ALL, ""); setlocale(LC_ALL, "");
set_signal_handler(SIGSEGV, signal_handler); set_signal_handler(SIGSEGV, signal_handler);
@ -746,7 +760,7 @@ int main(int argc, char* argv[])
set_signal_handler(SIGCHLD, [](int){}); set_signal_handler(SIGCHLD, [](int){});
Vector<String> params; Vector<String> params;
for (size_t i = 1; i < argc; ++i) for (int i = 1; i < argc; ++i)
params.emplace_back(argv[i]); params.emplace_back(argv[i]);
const ParameterDesc param_desc{ const ParameterDesc param_desc{
@ -875,11 +889,10 @@ int main(int argc, char* argv[])
StringView session = parser.get_switch("s").value_or(StringView{}); StringView session = parser.get_switch("s").value_or(StringView{});
try try
{ {
return run_server(session, init_cmds, init_coord, auto flags = (parser.get_switch("n") ? ServerFlags::IgnoreKakrc : ServerFlags::None) |
(bool)parser.get_switch("n"), (parser.get_switch("d") ? ServerFlags::Daemon : ServerFlags::None) |
(bool)parser.get_switch("d"), (parser.get_switch("ro") ? ServerFlags::ReadOnly : ServerFlags::None);
(bool)parser.get_switch("ro"), return run_server(session, init_cmds, init_coord, flags, ui_type, files);
ui_type, files);
} }
catch (convert_to_client_mode& convert) catch (convert_to_client_mode& convert)
{ {
@ -890,7 +903,7 @@ int main(int argc, char* argv[])
} }
} }
} }
catch (Kakoune::parameter_error& error) catch (parameter_error& error)
{ {
write_stderr(format("Error while parsing parameters: {}\n" write_stderr(format("Error while parsing parameters: {}\n"
"Valid switches:\n" "Valid switches:\n"