Refactor commands handling and parsing in a CommandManager class
This commit is contained in:
parent
8baf43ece1
commit
03f1520b43
60
src/command_manager.cc
Normal file
60
src/command_manager.cc
Normal 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
37
src/command_manager.hh
Normal 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
|
70
src/main.cc
70
src/main.cc
|
@ -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();
|
Buffer& buffer = *current_window->buffer();
|
||||||
write_buffer_to_file(buffer,
|
std::string filename = params.empty() ? buffer.name() : params[0];
|
||||||
filename.empty() ? buffer.name() : filename);
|
|
||||||
}
|
write_buffer_to_file(buffer, 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() + ")");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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>");
|
||||||
|
|
Loading…
Reference in New Issue
Block a user