Refactor commands handling and parsing in a CommandManager class

This commit is contained in:
Maxime Coste 2011-09-07 18:16:56 +00:00
parent 8baf43ece1
commit 03f1520b43
3 changed files with 126 additions and 43 deletions

60
src/command_manager.cc Normal file
View File

@ -0,0 +1,60 @@
#include "command_manager.hh"
#include "utils.hh"
#include <algorithm>
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<std::string>& command_names, Command command)
{
for (auto command_name : command_names)
register_command(command_name, command);
}
static std::vector<std::string> split(const std::string& line)
{
std::vector<std::string> 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<std::string> 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);
}
}

37
src/command_manager.hh Normal file
View File

@ -0,0 +1,37 @@
#ifndef command_manager_hh_INCLUDED
#define command_manager_hh_INCLUDED
#include <string>
#include <vector>
#include <unordered_map>
#include <stdexcept>
#include <functional>
namespace Kakoune
{
struct wrong_argument_count : public std::runtime_error
{
wrong_argument_count()
: std::runtime_error("wrong argument count") {}
};
typedef std::vector<std::string> CommandParameters;
typedef std::function<void (const CommandParameters&)> 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<std::string>& command_names, Command command);
private:
std::unordered_map<std::string, Command> m_commands;
};
}
#endif // command_manager_hh_INCLUDED

View File

@ -3,6 +3,7 @@
#include "buffer.hh" #include "buffer.hh"
#include "file.hh" #include "file.hh"
#include "regex_selector.hh" #include "regex_selector.hh"
#include "command_manager.hh"
#include <unordered_map> #include <unordered_map>
#include <cassert> #include <cassert>
@ -153,8 +154,12 @@ void do_insert(Window& window)
std::shared_ptr<Window> current_window; std::shared_ptr<Window> 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 try
{ {
std::shared_ptr<Buffer> buffer(create_buffer_from_file(filename)); std::shared_ptr<Buffer> buffer(create_buffer_from_file(filename));
@ -163,68 +168,45 @@ void edit(const std::string& filename)
} }
catch (file_not_found& what) catch (file_not_found& what)
{ {
print_status("new file " + filename);
current_window = std::make_shared<Window>(std::make_shared<Buffer>(filename)); current_window = std::make_shared<Window>(std::make_shared<Buffer>(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 if (params.size() > 1)
{ throw wrong_argument_count();
Buffer& buffer = *current_window->buffer();
write_buffer_to_file(buffer, Buffer& buffer = *current_window->buffer();
filename.empty() ? buffer.name() : filename); std::string filename = params.empty() ? buffer.name() : params[0];
}
catch(open_file_error& what) write_buffer_to_file(buffer, filename);
{
print_status("error opening " + filename + "(" + what.what() + ")");
}
catch(write_file_error& what)
{
print_status("error writing " + filename + "(" + what.what() + ")");
}
} }
bool quit_requested = false; 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; quit_requested = true;
} }
std::unordered_map<std::string, std::function<void (const std::string& param)>> cmdmap = CommandManager command_manager;
{
{ "e", edit },
{ "edit", edit },
{ "q", quit },
{ "quit", quit },
{ "w", write_buffer },
{ "write", write_buffer },
};
void do_command() void do_command()
{ {
try try
{ {
std::string cmd = prompt(":"); command_manager.execute(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");
} }
catch (prompt_aborted&) {} catch (prompt_aborted&) {}
catch (std::runtime_error& err)
{
print_status(err.what());
}
} }
bool is_blank(char c) bool is_blank(char c)
@ -304,6 +286,10 @@ int main()
{ {
init_ncurses(); init_ncurses();
command_manager.register_command(std::vector<std::string>{ "e", "edit" }, edit);
command_manager.register_command(std::vector<std::string>{ "q", "quit" }, quit);
command_manager.register_command(std::vector<std::string>{ "w", "write" }, write_buffer);
try try
{ {
auto buffer = std::make_shared<Buffer>("<scratch>"); auto buffer = std::make_shared<Buffer>("<scratch>");