diff --git a/src/command_manager.cc b/src/command_manager.cc new file mode 100644 index 00000000..aa1237d5 --- /dev/null +++ b/src/command_manager.cc @@ -0,0 +1,60 @@ +#include "command_manager.hh" + +#include "utils.hh" +#include + +namespace Kakoune +{ + +void CommandManager::register_command(const std::string& command_name, Command command) +{ + m_commands[command_name] = command; +} + +void CommandManager::register_command(const std::vector& command_names, Command command) +{ + for (auto command_name : command_names) + register_command(command_name, command); +} + +static std::vector split(const std::string& line) +{ + std::vector result; + + size_t pos = 0; + while (pos != line.length()) + { + while(line[pos] == ' ' and pos != line.length()) + ++pos; + + size_t token_start = pos; + + while((line[pos] != ' ' or line[pos-1] == '\\') and pos != line.length()) + ++pos; + + result.push_back(line.substr(token_start, pos - token_start)); + } + return result; +} + +struct command_not_found : public std::runtime_error +{ + command_not_found(const std::string& what) + : std::runtime_error("command not found: " + what) {} +}; + +void CommandManager::execute(const std::string& command_line) +{ + std::vector tokens = split(command_line); + if (tokens.empty()) + return; + + auto command_it = m_commands.find(tokens[0]); + if (command_it == m_commands.end()) + throw command_not_found(tokens[0]); + + CommandParameters params(tokens.begin() + 1, tokens.end()); + command_it->second(params); +} + +} diff --git a/src/command_manager.hh b/src/command_manager.hh new file mode 100644 index 00000000..9656b8e8 --- /dev/null +++ b/src/command_manager.hh @@ -0,0 +1,37 @@ +#ifndef command_manager_hh_INCLUDED +#define command_manager_hh_INCLUDED + +#include +#include +#include +#include +#include + + +namespace Kakoune +{ + +struct wrong_argument_count : public std::runtime_error +{ + wrong_argument_count() + : std::runtime_error("wrong argument count") {} +}; + +typedef std::vector CommandParameters; +typedef std::function Command; + +class CommandManager +{ +public: + void execute(const std::string& command_line); + + void register_command(const std::string& command_name, Command command); + void register_command(const std::vector& command_names, Command command); + +private: + std::unordered_map m_commands; +}; + +} + +#endif // command_manager_hh_INCLUDED diff --git a/src/main.cc b/src/main.cc index f4d53b49..491d48f1 100644 --- a/src/main.cc +++ b/src/main.cc @@ -3,6 +3,7 @@ #include "buffer.hh" #include "file.hh" #include "regex_selector.hh" +#include "command_manager.hh" #include #include @@ -153,8 +154,12 @@ void do_insert(Window& window) std::shared_ptr current_window; -void edit(const std::string& filename) +void edit(const CommandParameters& params) { + if (params.size() != 1) + throw wrong_argument_count(); + + std::string filename = params[0]; try { std::shared_ptr buffer(create_buffer_from_file(filename)); @@ -163,68 +168,45 @@ void edit(const std::string& filename) } catch (file_not_found& what) { + print_status("new file " + filename); current_window = std::make_shared(std::make_shared(filename)); } - catch (open_file_error& what) - { - print_status("error opening '" + filename + "' (" + what.what() + ")"); - } } -void write_buffer(const std::string& filename) +void write_buffer(const CommandParameters& params) { - try - { - Buffer& buffer = *current_window->buffer(); - write_buffer_to_file(buffer, - filename.empty() ? buffer.name() : filename); - } - catch(open_file_error& what) - { - print_status("error opening " + filename + "(" + what.what() + ")"); - } - catch(write_file_error& what) - { - print_status("error writing " + filename + "(" + what.what() + ")"); - } + if (params.size() > 1) + throw wrong_argument_count(); + + Buffer& buffer = *current_window->buffer(); + std::string filename = params.empty() ? buffer.name() : params[0]; + + write_buffer_to_file(buffer, filename); } bool quit_requested = false; -void quit(const std::string&) +void quit(const CommandParameters& params) { + if (params.size() != 0) + throw wrong_argument_count(); + quit_requested = true; } -std::unordered_map> cmdmap = -{ - { "e", edit }, - { "edit", edit }, - { "q", quit }, - { "quit", quit }, - { "w", write_buffer }, - { "write", write_buffer }, -}; +CommandManager command_manager; void do_command() { try { - std::string cmd = prompt(":"); - - size_t cmd_end = cmd.find_first_of(' '); - std::string cmd_name = cmd.substr(0, cmd_end); - size_t param_start = cmd.find_first_not_of(' ', cmd_end); - std::string param; - if (param_start != std::string::npos) - param = cmd.substr(param_start, cmd.length() - param_start); - - if (cmdmap.find(cmd_name) != cmdmap.end()) - cmdmap[cmd_name](param); - else - print_status(cmd_name + ": no such command"); + command_manager.execute(prompt(":")); } catch (prompt_aborted&) {} + catch (std::runtime_error& err) + { + print_status(err.what()); + } } bool is_blank(char c) @@ -304,6 +286,10 @@ int main() { init_ncurses(); + command_manager.register_command(std::vector{ "e", "edit" }, edit); + command_manager.register_command(std::vector{ "q", "quit" }, quit); + command_manager.register_command(std::vector{ "w", "write" }, write_buffer); + try { auto buffer = std::make_shared("");