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 <pwd.h>
using namespace Kakoune;
struct startup_error : Kakoune::runtime_error
namespace Kakoune
{
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); }
@ -298,12 +299,9 @@ void register_options()
""_str);
}
struct convert_to_client_mode
{
String session;
String buffer_name;
String selections;
};
static Client* local_client = nullptr;
static UserInterface* local_ui = nullptr;
static bool convert_to_client_pending = false;
enum class UIType
{
@ -312,21 +310,13 @@ enum class UIType
Dummy,
};
static Client* local_client = nullptr;
static UserInterface* local_ui = nullptr;
static bool convert_to_client_pending = false;
pid_t fork_server_to_background()
UIType parse_ui_type(StringView ui_name)
{
if (pid_t pid = fork())
return pid;
if (ui_name == "ncurses") return UIType::NCurses;
if (ui_name == "json") return UIType::Json;
if (ui_name == "dummy") return UIType::Dummy;
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;
throw parameter_error(format("error: unknown ui type: '{}'", ui_name));
}
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 {}
DisplayCoord dimensions() override { return {24,80}; }
void refresh(bool) override {}
void set_on_key(OnKeyCallback callback) override {}
void set_on_key(OnKeyCallback) override {}
void set_ui_options(const Options&) override {}
};
@ -359,6 +349,19 @@ std::unique_ptr<UserInterface> make_ui(UIType ui_type)
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)
{
if (ui_type != UIType::NCurses)
@ -436,37 +439,6 @@ std::unique_ptr<UserInterface> create_local_ui(UIType ui_type)
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,
Optional<BufferCoord> init_coord, UIType ui_type)
{
@ -486,13 +458,29 @@ int run_client(StringView session, StringView init_cmds,
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,
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)
{
static bool terminate = false;
if (daemon)
if (flags & ServerFlags::Daemon)
{
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 ***");
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()};
bool startup_error = false;
if (not ignore_kakrc) try
if (not (flags & ServerFlags::IgnoreKakrc)) try
{
Context initialisation_context{Context::EmptyContextFlag{}};
command_manager.execute(format("source {}/kakrc", runtime_directory()),
initialisation_context);
}
catch (Kakoune::runtime_error& error)
catch (runtime_error& error)
{
startup_error = true;
write_to_debug_buffer(format("error while parsing kakrc:\n"
@ -563,10 +551,10 @@ int run_server(StringView session,
try
{
Buffer *buffer = open_or_create_file_buffer(file);
if (readonly)
if (flags & ServerFlags::ReadOnly)
buffer->flags() |= Buffer::Flags::ReadOnly;
}
catch (Kakoune::runtime_error& error)
catch (runtime_error& error)
{
startup_error = true;
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()));
}
try
{
if (not daemon)
if (not (flags & ServerFlags::Daemon))
local_client = client_manager.create_client(
create_local_ui(ui_type), get_env_vars(), init_cmds, init_coord);
@ -591,7 +579,7 @@ int run_server(StringView session,
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();
event_manager.handle_next_events(EventMode::Normal);
@ -665,7 +653,7 @@ int run_filter(StringView keystr, StringView commands, ConstArrayView<StringView
for (auto& key : keys)
input_handler.handle_key(key);
}
catch (Kakoune::runtime_error& err)
catch (runtime_error& err)
{
if (not quiet)
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);
}
}
catch (Kakoune::runtime_error& err)
catch (runtime_error& err)
{
write_stderr(format("error: {}\n", err.what()));
}
@ -724,17 +712,43 @@ int run_pipe(StringView session)
return 0;
}
UIType parse_ui_type(StringView ui_name)
void signal_handler(int signal)
{
if (ui_name == "ncurses") return UIType::NCurses;
if (ui_name == "json") return UIType::Json;
if (ui_name == "dummy") return UIType::Dummy;
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();
}
throw parameter_error(format("error: unknown ui type: '{}'", ui_name));
}
int main(int argc, char* argv[])
{
using namespace Kakoune;
setlocale(LC_ALL, "");
set_signal_handler(SIGSEGV, signal_handler);
@ -746,7 +760,7 @@ int main(int argc, char* argv[])
set_signal_handler(SIGCHLD, [](int){});
Vector<String> params;
for (size_t i = 1; i < argc; ++i)
for (int i = 1; i < argc; ++i)
params.emplace_back(argv[i]);
const ParameterDesc param_desc{
@ -875,11 +889,10 @@ int main(int argc, char* argv[])
StringView session = parser.get_switch("s").value_or(StringView{});
try
{
return run_server(session, init_cmds, init_coord,
(bool)parser.get_switch("n"),
(bool)parser.get_switch("d"),
(bool)parser.get_switch("ro"),
ui_type, files);
auto flags = (parser.get_switch("n") ? ServerFlags::IgnoreKakrc : ServerFlags::None) |
(parser.get_switch("d") ? ServerFlags::Daemon : ServerFlags::None) |
(parser.get_switch("ro") ? ServerFlags::ReadOnly : ServerFlags::None);
return run_server(session, init_cmds, init_coord, flags, ui_type, files);
}
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"
"Valid switches:\n"