new REPL command parsing & handling system

This commit is contained in:
Robert Bendun 2022-10-11 11:01:01 +02:00
parent cfa0513226
commit 78b1e7d703
2 changed files with 57 additions and 23 deletions

View File

@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* Added [rtmidi](https://github.com/thestk/rtmidi/) dependency which should provide multiplatform MIDI support * Added [rtmidi](https://github.com/thestk/rtmidi/) dependency which should provide multiplatform MIDI support
* Support for Windows (with only basic REPL) (`make os=windows`) * Support for Windows (with only basic REPL) (`make os=windows`)
* Release package now with compiled Windows binary * Release package now with compiled Windows binary
* `:load` REPL command to load Musique files inside Musique session. Allows for delayed file execution after a connection
* `:quit` REPL command that mirrors `:exit` command
### Changed ### Changed

View File

@ -228,38 +228,70 @@ bool is_tty()
/// Handles commands inside REPL session (those starting with ':') /// Handles commands inside REPL session (those starting with ':')
/// ///
/// Returns if one of command matched /// Returns if one of command matched
static Result<bool> handle_repl_session_commands(std::string_view command, Runner &runner) static Result<bool> handle_repl_session_commands(std::string_view input, Runner &runner)
{ {
if (command == "exit") { using Handler = std::optional<Error>(*)(Runner &runner, std::optional<std::string_view> arg);
std::exit(0); using Command = std::pair<std::string_view, Handler>;
} static constexpr auto Commands = std::array {
Command { "exit",
+[](Runner&, std::optional<std::string_view>) -> std::optional<Error> {
std::exit(0);
}
},
Command { "quit",
+[](Runner&, std::optional<std::string_view>) -> std::optional<Error> {
std::exit(0);
}
},
Command { "clear",
+[](Runner&, std::optional<std::string_view>) -> std::optional<Error> {
std::cout << "\x1b[1;1H\x1b[2J" << std::flush;
return {};
}
},
Command { "help",
+[](Runner&, std::optional<std::string_view>) -> std::optional<Error> {
print_repl_help();
return {};
}
},
Command { "load",
+[](Runner& runner, std::optional<std::string_view> arg) -> std::optional<Error> {
if (not arg.has_value()) {
std::cerr << ":load subcommand requires path to file that will be loaded" << std::endl;
return {};
}
auto path = *arg;
std::ifstream source_file{std::string(path)};
if (not source_file.is_open()) {
std::cerr << ":load cannot find file " << path << std::endl;
return {};
}
eternal_sources.emplace_back(std::istreambuf_iterator<char>(source_file), std::istreambuf_iterator<char>());
Lines::the.add_file(std::string(path), eternal_sources.back());
return runner.run(eternal_sources.back(), path);
}
},
};
if (command == "clear") { if (input.starts_with('!')) {
std::cout << "\x1b[1;1H\x1b[2J" << std::flush;
return true;
}
if (command.starts_with('!')) {
// TODO Maybe use different shell invoking mechanism then system // TODO Maybe use different shell invoking mechanism then system
// since on Windows it uses cmd.exe and not powershell which is // since on Windows it uses cmd.exe and not powershell which is
// strictly superior // strictly superior
Ignore(system(command.data() + 1)); Ignore(system(input.data() + 1));
return true; return true;
} }
if (command == "help") { auto ws = input.find_first_of(" \t\n");
print_repl_help(); auto provided_command = input.substr(0, input.find_first_of(" \t\n"));
return true; auto arg = ws == std::string_view::npos ? std::string_view{} : input.substr(ws);
} trim(arg);
if (command.starts_with("load")) { for (auto [command_name, handler] : Commands) {
command = command.substr("load"sv.size()); if (provided_command == command_name) {
trim(command); Try(handler(runner, arg));
std::ifstream source_file{std::string(command)}; return true;
eternal_sources.emplace_back(std::istreambuf_iterator<char>(source_file), std::istreambuf_iterator<char>()); }
Lines::the.add_file(std::string(command), eternal_sources.back());
Try(runner.run(eternal_sources.back(), command));
return true;
} }
return false; return false;