All commands now take directly a parameter parser

The command parameters description are now stored in a ParameterDesc
structure.
This commit is contained in:
Maxime Coste 2014-02-08 01:02:58 +00:00
parent 92c425ad52
commit 7f9f887b4a
6 changed files with 285 additions and 218 deletions

View File

@ -18,19 +18,21 @@ bool CommandManager::command_defined(const String& command_name) const
void CommandManager::register_command(String command_name,
Command command,
ParameterDesc param_desc,
CommandFlags flags,
CommandCompleter completer)
{
m_commands[command_name] = { std::move(command), flags, std::move(completer) };
m_commands[command_name] = { std::move(command), std::move(param_desc), flags, std::move(completer) };
}
void CommandManager::register_commands(memoryview<String> command_names,
Command command,
ParameterDesc param_desc,
CommandFlags flags,
CommandCompleter completer)
{
kak_assert(not command_names.empty());
m_commands[command_names[0]] = { std::move(command), flags, completer };
m_commands[command_names[0]] = { std::move(command), std::move(param_desc), flags, completer };
for (size_t i = 1; i < command_names.size(); ++i)
m_aliases[command_names[i]] = command_names[0];
}
@ -281,7 +283,7 @@ void CommandManager::execute_single_command(CommandParameters params,
auto command_it = find_command(params[0]);
if (command_it == m_commands.end())
throw command_not_found(params[0]);
command_it->second.command(param_view, context);
command_it->second.command(ParametersParser(param_view, command_it->second.param_desc), context);
}
void CommandManager::execute(const String& command_line,

View File

@ -4,6 +4,7 @@
#include "completion.hh"
#include "memoryview.hh"
#include "shell_manager.hh"
#include "parameters_parser.hh"
#include "string.hh"
#include "utils.hh"
@ -16,7 +17,7 @@ namespace Kakoune
class Context;
using CommandParameters = memoryview<String>;
using Command = std::function<void (CommandParameters, Context& context)>;
using Command = std::function<void (const ParametersParser& parser, Context& context)>;
using CommandCompleter = std::function<Completions (const Context& context,
CompletionFlags,
CommandParameters,
@ -69,10 +70,12 @@ public:
bool command_defined(const String& command_name) const;
void register_command(String command_name, Command command,
ParameterDesc param_desc,
CommandFlags flags = CommandFlags::None,
CommandCompleter completer = CommandCompleter());
void register_commands(memoryview<String> command_names, Command command,
ParameterDesc param_desc,
CommandFlags flags = CommandFlags::None,
CommandCompleter completer = CommandCompleter());
@ -83,6 +86,7 @@ private:
struct CommandDescriptor
{
Command command;
ParameterDesc param_desc;
CommandFlags flags;
CommandCompleter completer;
};

View File

@ -84,13 +84,14 @@ Buffer* open_fifo(const String& name , const String& filename, Context& context)
return buffer;
}
template<bool force_reload>
void edit(CommandParameters params, Context& context)
{
ParametersParser parser(params, { { "scratch", false },
{ "fifo", true } },
ParametersParser::Flags::None, 1, 3);
static const ParameterDesc edit_params{
OptionMap{ { "scratch", false }, { "fifo", true } },
ParameterDesc::Flags::None, 1, 3
};
template<bool force_reload>
void edit(const ParametersParser& parser, Context& context)
{
const String name = parser[0];
Buffer* buffer = nullptr;
@ -130,27 +131,32 @@ void edit(CommandParameters params, Context& context)
}
}
void write_buffer(CommandParameters params, Context& context)
{
if (params.size() > 1)
throw wrong_argument_count();
static const ParameterDesc write_params{
OptionMap{},
ParameterDesc::Flags::None, 0, 1
};
void write_buffer(const ParametersParser& parser, Context& context)
{
Buffer& buffer = context.buffer();
if (params.empty() and !(buffer.flags() & Buffer::Flags::File))
if (parser.positional_count() == 0 and !(buffer.flags() & Buffer::Flags::File))
throw runtime_error("cannot write a non file buffer without a filename");
String filename = params.empty() ? buffer.name()
: parse_filename(params[0]);
String filename = parser.positional_count() == 0 ? buffer.name()
: parse_filename(parser[0]);
write_buffer_to_file(buffer, filename);
}
void write_all_buffers(CommandParameters params, Context& context)
{
if (params.size() != 0)
throw wrong_argument_count();
static const ParameterDesc no_params{
OptionMap{},
ParameterDesc::Flags::None, 0, 0
};
void write_all_buffers(const ParametersParser& parser, Context& context)
{
for (auto& buffer : BufferManager::instance())
{
if ((buffer->flags() & Buffer::Flags::File) and buffer->is_modified())
@ -159,11 +165,8 @@ void write_all_buffers(CommandParameters params, Context& context)
}
template<bool force>
void quit(CommandParameters params, Context& context)
void quit(const ParametersParser& parser, Context& context)
{
if (params.size() != 0)
throw wrong_argument_count();
if (not force and ClientManager::instance().count() == 1)
{
std::vector<String> names;
@ -190,18 +193,17 @@ void quit(CommandParameters params, Context& context)
}
template<bool force>
void write_and_quit(CommandParameters params, Context& context)
void write_and_quit(const ParametersParser& parser, Context& context)
{
write_buffer(params, context);
quit<force>(CommandParameters(), context);
write_buffer(parser, context);
quit<force>(ParametersParser{memoryview<String>{}, no_params}, context);
}
void show_buffer(CommandParameters params, Context& context)
{
if (params.size() != 1)
throw wrong_argument_count();
static const ParameterDesc single_name_params{ OptionMap{}, ParameterDesc::Flags::None, 1, 1 };
Buffer& buffer = BufferManager::instance().get_buffer(params[0]);
void show_buffer(const ParametersParser& parser, Context& context)
{
Buffer& buffer = BufferManager::instance().get_buffer(parser[0]);
BufferManager::instance().set_last_used_buffer(buffer);
if (&buffer != &context.buffer())
@ -211,14 +213,13 @@ void show_buffer(CommandParameters params, Context& context)
}
}
template<bool force>
void delete_buffer(CommandParameters params, Context& context)
{
if (params.size() > 1)
throw wrong_argument_count();
static const ParameterDesc single_opt_name_params{ OptionMap{}, ParameterDesc::Flags::None, 0, 1 };
template<bool force>
void delete_buffer(const ParametersParser& parser, Context& context)
{
BufferManager& manager = BufferManager::instance();
Buffer& buffer = params.empty() ? context.buffer() : manager.get_buffer(params[0]);
Buffer& buffer = parser.positional_count() == 0 ? context.buffer() : manager.get_buffer(parser[0]);
if (not force and (buffer.flags() & Buffer::Flags::File) and buffer.is_modified())
throw runtime_error("buffer " + buffer.name() + " is modified");
@ -228,26 +229,25 @@ void delete_buffer(CommandParameters params, Context& context)
manager.delete_buffer(buffer);
}
void set_buffer_name(CommandParameters params, Context& context)
void set_buffer_name(const ParametersParser& parser, Context& context)
{
ParametersParser parser(params, OptionMap{},
ParametersParser::Flags::None, 1, 1);
if (not context.buffer().set_name(parser[0]))
throw runtime_error("unable to change buffer name to " + parser[0]);
}
void define_highlighter(CommandParameters params, Context& context)
void define_highlighter(const ParametersParser& parser, Context& context)
{
if (params.size() != 1)
throw wrong_argument_count();
const String& name = params[0];
const String& name = parser[0];
DefinedHighlighters::instance().append({name, HighlighterGroup{}});
}
void add_highlighter(CommandParameters params, Context& context)
static const ParameterDesc add_highlighter_params{
OptionMap{ { "group", true }, { "def-group", true } },
ParameterDesc::Flags::None, 1
};
void add_highlighter(const ParametersParser& parser, Context& context)
{
ParametersParser parser(params, { { "group", true }, { "def-group", true } }, ParametersParser::Flags::None, 1);
HighlighterRegistry& registry = HighlighterRegistry::instance();
auto begin = parser.begin();
@ -274,10 +274,12 @@ void add_highlighter(CommandParameters params, Context& context)
group->append(registry[name](highlighter_params));
}
void rm_highlighter(CommandParameters params, Context& context)
{
ParametersParser parser(params, { { "group", true } }, ParametersParser::Flags::None, 1, 1);
static const ParameterDesc rm_highlighter_params{
OptionMap{ { "group", true } }, ParameterDesc::Flags::None, 1, 1
};
void rm_highlighter(const ParametersParser& parser, Context& context)
{
HighlighterGroup& window_hl = context.window().highlighters();
HighlighterGroup& group = parser.has_option("group") ?
window_hl.get_group(parser.option_value("group"), '/')
@ -297,9 +299,12 @@ static HookManager& get_hook_manager(const String& scope, Context& context)
throw runtime_error("error: no such hook container " + scope);
}
void add_hook(CommandParameters params, Context& context)
static const ParameterDesc add_hook_params{
OptionMap{ { "id", true } }, ParameterDesc::Flags::None, 4, 4
};
void add_hook(const ParametersParser& parser, Context& context)
{
ParametersParser parser(params, { { "id", true } }, ParametersParser::Flags::None, 4, 4);
// copy so that the lambda gets a copy as well
Regex regex(parser[2].begin(), parser[2].end());
String command = parser[3];
@ -312,36 +317,48 @@ void add_hook(CommandParameters params, Context& context)
get_hook_manager(parser[0], context).add_hook(parser[1], id, hook_func);
}
void rm_hooks(CommandParameters params, Context& context)
static const ParameterDesc rm_hooks_params{
OptionMap{}, ParameterDesc::Flags::None, 2, 2
};
void rm_hooks(const ParametersParser& parser, Context& context)
{
ParametersParser parser(params, OptionMap{}, ParametersParser::Flags::None, 2, 2);
get_hook_manager(parser[0], context).remove_hooks(parser[1]);
}
EnvVarMap params_to_env_var_map(CommandParameters params)
EnvVarMap params_to_env_var_map(const ParametersParser& parser)
{
std::unordered_map<String, String> vars;
char param_name[] = "param0";
for (size_t i = 0; i < params.size(); ++i)
for (size_t i = 0; i < parser.positional_count(); ++i)
{
param_name[sizeof(param_name) - 2] = '0' + i;
vars[param_name] = params[i];
vars[param_name] = parser[i];
}
return vars;
}
void define_command(CommandParameters params, Context& context)
std::vector<String> params_to_shell(const ParametersParser& parser)
{
ParametersParser parser(params,
{ { "env-params", false },
std::vector<String> vars;
for (size_t i = 0; i < parser.positional_count(); ++i)
vars.push_back(parser[i]);
return vars;
}
static const ParameterDesc define_command_params{
OptionMap{ { "env-params", false },
{ "shell-params", false },
{ "allow-override", false },
{ "file-completion", false },
{ "hidden", false },
{ "shell-completion", true } },
ParametersParser::Flags::None,
2, 2);
ParameterDesc::Flags::None,
2, 2
};
void define_command(const ParametersParser& parser, Context& context)
{
auto begin = parser.begin();
const String& cmd_name = *begin;
@ -355,24 +372,26 @@ void define_command(CommandParameters params, Context& context)
String commands = parser[1];
Command cmd;
ParameterDesc desc;
if (parser.has_option("env-params"))
{
cmd = [=](CommandParameters params, Context& context) {
desc = ParameterDesc{ OptionMap{}, ParameterDesc::Flags::None };
cmd = [=](const ParametersParser& parser, Context& context) {
CommandManager::instance().execute(commands, context, {},
params_to_env_var_map(params));
params_to_env_var_map(parser));
};
}
if (parser.has_option("shell-params"))
{
cmd = [=](CommandParameters params, Context& context) {
CommandManager::instance().execute(commands, context, params);
desc = ParameterDesc{ OptionMap{}, ParameterDesc::Flags::None };
cmd = [=](const ParametersParser& parser, Context& context) {
CommandManager::instance().execute(commands, context, params_to_shell(parser));
};
}
else
{
cmd = [=](CommandParameters params, Context& context) {
if (not params.empty())
throw wrong_argument_count();
desc = ParameterDesc{ OptionMap{}, ParameterDesc::Flags::None, 0, 0 };
cmd = [=](const ParametersParser& parser, Context& context) {
CommandManager::instance().execute(commands, context);
};
}
@ -408,13 +427,16 @@ void define_command(CommandParameters params, Context& context)
return Completions{ 0_byte, params[token_to_complete].length(), split(output, '\n') };
};
}
CommandManager::instance().register_command(cmd_name, cmd, flags, completer);
CommandManager::instance().register_command(cmd_name, cmd, desc, flags, completer);
}
void echo_message(CommandParameters params, Context& context)
static const ParameterDesc echo_message_params{
{ { "color", true } },
ParameterDesc::Flags::OptionsOnlyAtStart
};
void echo_message(const ParametersParser& parser, Context& context)
{
ParametersParser parser(params, { { "color", true } },
ParametersParser::Flags::OptionsOnlyAtStart);
String message;
for (auto& param : parser)
message += param + " ";
@ -423,28 +445,36 @@ void echo_message(CommandParameters params, Context& context)
context.print_status({ std::move(message), color } );
}
void write_debug_message(CommandParameters params, Context&)
static const ParameterDesc write_debug_message_params{
OptionMap{},
ParameterDesc::Flags::OptionsOnlyAtStart
};
void write_debug_message(const ParametersParser& parser, Context&)
{
String message;
for (auto& param : params)
for (auto& param : parser)
message += param + " ";
write_debug(message);
}
void exec_commands_in_file(CommandParameters params,
static const ParameterDesc exec_commands_in_file_params{
OptionMap{},
ParameterDesc::Flags::None,
1, 1
};
void exec_commands_in_file(const ParametersParser& parser,
Context& context)
{
if (params.size() != 1)
throw wrong_argument_count();
String file_content = read_file(parse_filename(params[0]));
String file_content = read_file(parse_filename(parser[0]));
try
{
CommandManager::instance().execute(file_content, context);
}
catch (Kakoune::runtime_error& err)
{
write_debug("error while executing commands in file '" + params[0]
write_debug("error while executing commands in file '" + parser[0]
+ "'\n " + err.what());
throw;
}
@ -463,12 +493,15 @@ static OptionManager& get_options(const String& scope, const Context& context)
throw runtime_error("error: no such option container " + scope);
}
void set_option(CommandParameters params, Context& context)
{
ParametersParser parser(params, { { "add", false } },
ParametersParser::Flags::OptionsOnlyAtStart,
3, 3);
static const ParameterDesc set_option_params{
{ { "add", false } },
ParameterDesc::Flags::OptionsOnlyAtStart,
3, 3
};
void set_option(const ParametersParser& parser, Context& context)
{
Option& opt = get_options(parser[0], context).get_local_option(parser[1]);
if (parser.has_option("add"))
opt.add_from_string(parser[2]);
@ -476,11 +509,14 @@ void set_option(CommandParameters params, Context& context)
opt.set_from_string(parser[2]);
}
void declare_option(CommandParameters params, Context& context)
static const ParameterDesc declare_option_params{
{ { "hidden", false } },
ParameterDesc::Flags::OptionsOnlyAtStart,
2, 3
};
void declare_option(const ParametersParser& parser, Context& context)
{
ParametersParser parser(params, { { "hidden", false } },
ParametersParser::Flags::OptionsOnlyAtStart,
2, 3);
Option* opt = nullptr;
Option::Flags flags = Option::Flags::None;
@ -531,28 +567,32 @@ KeymapMode parse_keymap_mode(const String& str)
throw runtime_error("unknown keymap mode '" + str + "'");
}
void map_key(CommandParameters params, Context& context)
static const ParameterDesc map_key_params{
OptionMap{}, ParameterDesc::Flags::None, 4, 4
};
void map_key(const ParametersParser& parser, Context& context)
{
ParametersParser parser(params, OptionMap{}, ParametersParser::Flags::None, 4, 4);
KeymapManager& keymaps = get_keymap_manager(parser[0], context);
KeymapMode keymap_mode = parse_keymap_mode(parser[1]);
KeymapManager& keymaps = get_keymap_manager(params[0], context);
KeymapMode keymap_mode = parse_keymap_mode(params[1]);
KeyList key = parse_keys(params[2]);
KeyList key = parse_keys(parser[2]);
if (key.size() != 1)
throw runtime_error("only a single key can be mapped");
KeyList mapping = parse_keys(params[3]);
KeyList mapping = parse_keys(parser[3]);
keymaps.map_key(key[0], keymap_mode, std::move(mapping));
}
template<typename Func>
void context_wrap(CommandParameters params, Context& context, Func func)
{
ParametersParser parser(params, { { "client", true }, { "try-client", true },
const ParameterDesc context_wrap_params = {
{ { "client", true }, { "try-client", true },
{ "draft", false }, { "itersel", false } },
ParametersParser::Flags::OptionsOnlyAtStart, 1);
ParameterDesc::Flags::OptionsOnlyAtStart, 1
};
template<typename Func>
void context_wrap(const ParametersParser& parser, Context& context, Func func)
{
ClientManager& cm = ClientManager::instance();
Context* real_context = &context;
if (parser.has_option("client"))
@ -598,9 +638,9 @@ void context_wrap(CommandParameters params, Context& context, Func func)
real_context->window().forget_timestamp();
}
void exec_string(CommandParameters params, Context& context)
void exec_string(const ParametersParser& parser, Context& context)
{
context_wrap(params, context, [](const ParametersParser& parser, Context& context) {
context_wrap(parser, context, [](const ParametersParser& parser, Context& context) {
KeyList keys;
for (auto& param : parser)
{
@ -611,9 +651,9 @@ void exec_string(CommandParameters params, Context& context)
});
}
void eval_string(CommandParameters params, Context& context)
void eval_string(const ParametersParser& parser, Context& context)
{
context_wrap(params, context, [](const ParametersParser& parser, Context& context) {
context_wrap(parser, context, [](const ParametersParser& parser, Context& context) {
String command;
for (auto& param : parser)
command += param + " ";
@ -621,11 +661,11 @@ void eval_string(CommandParameters params, Context& context)
});
}
void menu(CommandParameters params, Context& context)
{
ParametersParser parser(params, { { "auto-single", false },
{ "select-cmds", false } });
static const ParameterDesc menu_params{ { { "auto-single", false },
{ "select-cmds", false } } };
void menu(const ParametersParser& parser, Context& context)
{
const bool with_select_cmds = parser.has_option("select-cmds");
const size_t modulo = with_select_cmds ? 3 : 2;
@ -659,11 +699,13 @@ void menu(CommandParameters params, Context& context)
});
}
void info(CommandParameters params, Context& context)
{
ParametersParser parser(params, { { "anchor", true }, { "title", true } },
ParametersParser::Flags::None, 0, 1);
static const ParameterDesc info_params{
{ { "anchor", true }, { "title", true } },
ParameterDesc::Flags::None, 0, 1
};
void info(const ParametersParser& parser, Context& context)
{
context.ui().info_hide();
if (parser.positional_count() > 0)
{
@ -689,62 +731,71 @@ void info(CommandParameters params, Context& context)
}
}
void try_catch(CommandParameters params, Context& context)
static const ParameterDesc try_catch_params{
OptionMap{}, ParameterDesc::Flags::None, 1, 3
};
void try_catch(const ParametersParser& parser, Context& context)
{
if (params.size() != 1 and params.size() != 3)
if (parser.positional_count() == 2)
throw wrong_argument_count();
const bool do_catch = params.size() == 3;
if (do_catch and params[1] != "catch")
const bool do_catch = parser.positional_count() == 3;
if (do_catch and parser[1] != "catch")
throw runtime_error("usage: try <commands> [catch <on error commands>]");
CommandManager& command_manager = CommandManager::instance();
try
{
command_manager.execute(params[0], context);
command_manager.execute(parser[0], context);
}
catch (Kakoune::runtime_error& e)
{
if (do_catch)
command_manager.execute(params[2], context);
command_manager.execute(parser[2], context);
}
}
void define_color_alias(CommandParameters params, Context& context)
static const ParameterDesc define_color_alias_params{
OptionMap{}, ParameterDesc::Flags::None, 2, 2
};
void define_color_alias(const ParametersParser& parser, Context& context)
{
ParametersParser parser(params, OptionMap{},
ParametersParser::Flags::None, 2, 2);
ColorRegistry::instance().register_alias(
parser[0], parser[1], true);
ColorRegistry::instance().register_alias(parser[0], parser[1], true);
}
void set_client_name(CommandParameters params, Context& context)
static const ParameterDesc set_client_name_params{
OptionMap{}, ParameterDesc::Flags::None, 1, 1
};
void set_client_name(const ParametersParser& parser, Context& context)
{
ParametersParser parser(params, OptionMap{},
ParametersParser::Flags::None, 1, 1);
if (ClientManager::instance().validate_client_name(params[0]))
context.set_name(params[0]);
else if (context.name() != params[0])
throw runtime_error("client name '" + params[0] + "' is not unique");
if (ClientManager::instance().validate_client_name(parser[0]))
context.set_name(parser[0]);
else if (context.name() != parser[0])
throw runtime_error("client name '" + parser[0] + "' is not unique");
}
void set_register(CommandParameters params, Context& context)
{
if (params.size() != 2)
throw wrong_argument_count();
static const ParameterDesc set_register_params{
OptionMap{}, ParameterDesc::Flags::None, 2, 2
};
if (params[0].length() != 1)
void set_register(const ParametersParser& parser, Context& context)
{
if (parser[0].length() != 1)
throw runtime_error("register names are single character");
RegisterManager::instance()[params[0][0]] = memoryview<String>(params[1]);
RegisterManager::instance()[parser[0][0]] = memoryview<String>(parser[1]);
}
void change_working_directory(CommandParameters params, Context&)
{
if (params.size() != 1)
throw wrong_argument_count();
static const ParameterDesc change_working_directory_params{
OptionMap{}, ParameterDesc::Flags::None, 1, 1
};
if (chdir(parse_filename(params[0]).c_str()) != 0)
throw runtime_error("cannot change to directory " + params[0]);
void change_working_directory(const ParametersParser& parser, Context&)
{
if (chdir(parse_filename(parser[0]).c_str()) != 0)
throw runtime_error("cannot change to directory " + parser[0]);
}
template<typename GetRootGroup>
@ -825,7 +876,7 @@ void register_commands()
{
CommandManager& cm = CommandManager::instance();
cm.register_commands({"nop"}, [](CommandParameters, Context&){});
cm.register_commands({"nop"}, [](const ParametersParser&, Context&){}, {});
PerArgumentCommandCompleter filename_completer({
[](const Context& context, CompletionFlags flags, const String& prefix, ByteCount cursor_pos)
@ -834,31 +885,31 @@ void register_commands()
context.options()["ignored_files"].get<Regex>(),
cursor_pos) }; }
});
cm.register_commands({ "edit", "e" }, edit<false>, CommandFlags::None, filename_completer);
cm.register_commands({ "edit!", "e!" }, edit<true>, CommandFlags::None, filename_completer);
cm.register_commands({ "write", "w" }, write_buffer, CommandFlags::None, filename_completer);
cm.register_commands({ "writeall", "wa" }, write_all_buffers);
cm.register_commands({ "quit", "q" }, quit<false>);
cm.register_commands({ "quit!", "q!" }, quit<true>);
cm.register_command("wq", write_and_quit<false>);
cm.register_command("wq!", write_and_quit<true>);
cm.register_commands({ "edit", "e" }, edit<false>, edit_params, CommandFlags::None, filename_completer);
cm.register_commands({ "edit!", "e!" }, edit<true>, edit_params, CommandFlags::None, filename_completer);
cm.register_commands({ "write", "w" }, write_buffer, write_params, CommandFlags::None, filename_completer);
cm.register_commands({ "writeall", "wa" }, write_all_buffers, no_params);
cm.register_commands({ "quit", "q" }, quit<false>, no_params);
cm.register_commands({ "quit!", "q!" }, quit<true>, no_params);
cm.register_command("wq", write_and_quit<false>, no_params);
cm.register_command("wq!", write_and_quit<true>, no_params);
PerArgumentCommandCompleter buffer_completer({
[](const Context& context, CompletionFlags flags, const String& prefix, ByteCount cursor_pos)
{ return Completions{ 0_byte, prefix.length(),
BufferManager::instance().complete_buffername(prefix, cursor_pos) }; }
});
cm.register_commands({ "buffer", "b" }, show_buffer, CommandFlags::None, buffer_completer);
cm.register_commands({ "delbuf", "db" }, delete_buffer<false>, CommandFlags::None, buffer_completer);
cm.register_commands({ "delbuf!", "db!" }, delete_buffer<true>, CommandFlags::None, buffer_completer);
cm.register_commands({ "namebuf", "nb" }, set_buffer_name);
cm.register_commands({ "buffer", "b" }, show_buffer, single_name_params, CommandFlags::None, buffer_completer);
cm.register_commands({ "delbuf", "db" }, delete_buffer<false>, single_opt_name_params, CommandFlags::None, buffer_completer);
cm.register_commands({ "delbuf!", "db!" }, delete_buffer<true>, single_opt_name_params, CommandFlags::None, buffer_completer);
cm.register_commands({ "namebuf", "nb" }, set_buffer_name, single_name_params);
auto get_highlighters = [](const Context& c) -> HighlighterGroup& { return c.window().highlighters(); };
cm.register_commands({ "addhl", "ah" }, add_highlighter, CommandFlags::None, group_add_completer<HighlighterRegistry>(get_highlighters));
cm.register_commands({ "rmhl", "rh" }, rm_highlighter, CommandFlags::None, group_rm_completer(get_highlighters));
cm.register_commands({ "defhl", "dh" }, define_highlighter);
cm.register_commands({ "addhl", "ah" }, add_highlighter, add_highlighter_params, CommandFlags::None, group_add_completer<HighlighterRegistry>(get_highlighters));
cm.register_commands({ "rmhl", "rh" }, rm_highlighter, rm_highlighter_params, CommandFlags::None, group_rm_completer(get_highlighters));
cm.register_commands({ "defhl", "dh" }, define_highlighter, single_name_params);
cm.register_command("hook", add_hook, CommandFlags::None,
cm.register_command("hook", add_hook, add_hook_params, CommandFlags::None,
[](const Context& context, CompletionFlags flags,
CommandParameters params, size_t token_to_complete, ByteCount pos_in_token)
{
@ -872,24 +923,24 @@ void register_commands()
}
return Completions{};
});
cm.register_command("rmhooks", rm_hooks);
cm.register_command("rmhooks", rm_hooks, rm_hooks_params);
cm.register_command("source", exec_commands_in_file, CommandFlags::None, filename_completer);
cm.register_command("source", exec_commands_in_file, exec_commands_in_file_params, CommandFlags::None, filename_completer);
cm.register_command("exec", exec_string);
cm.register_command("eval", eval_string);
cm.register_command("menu", menu);
cm.register_command("info", info);
cm.register_command("try", try_catch);
cm.register_command("reg", set_register);
cm.register_command("exec", exec_string, context_wrap_params);
cm.register_command("eval", eval_string, context_wrap_params);
cm.register_command("menu", menu, menu_params);
cm.register_command("info", info, info_params);
cm.register_command("try", try_catch, try_catch_params);
cm.register_command("reg", set_register, set_register_params);
cm.register_command("def", define_command);
cm.register_command("decl", declare_option);
cm.register_command("def", define_command, define_command_params);
cm.register_command("decl", declare_option, declare_option_params);
cm.register_command("echo", echo_message);
cm.register_command("debug", write_debug_message);
cm.register_command("echo", echo_message, echo_message_params);
cm.register_command("debug", write_debug_message, write_debug_message_params);
cm.register_command("set", set_option, CommandFlags::None,
cm.register_command("set", set_option, set_option_params, CommandFlags::None,
[](const Context& context, CompletionFlags,
CommandParameters params, size_t token_to_complete,
ByteCount pos_in_token) -> Completions
@ -906,10 +957,10 @@ void register_commands()
return Completions{};
} );
cm.register_commands({ "colalias", "ca" }, define_color_alias);
cm.register_commands({ "nameclient", "nc" }, set_client_name);
cm.register_commands({ "colalias", "ca" }, define_color_alias, define_color_alias_params);
cm.register_commands({ "nameclient", "nc" }, set_client_name, set_client_name_params);
cm.register_command("cd", change_working_directory, CommandFlags::None, filename_completer);
cm.register_command("map", map_key);
cm.register_command("cd", change_working_directory, change_working_directory_params, CommandFlags::None, filename_completer);
cm.register_command("map", map_key, map_key_params);
}
}

View File

@ -233,11 +233,14 @@ int run_client(const String& session, const String& init_command)
int kakoune(memoryview<String> params)
{
ParametersParser parser(params, { { "c", true },
const ParameterDesc param_desc{
OptionMap{ { "c", true },
{ "e", true },
{ "n", false },
{ "s", true },
{ "d", false } });
{ "d", false } }
};
ParametersParser parser(params, param_desc);
String init_command;
if (parser.has_option("e"))
init_command = parser.option_value("e");

View File

@ -3,13 +3,10 @@
namespace Kakoune
{
ParametersParser::ParametersParser(const ParameterList& params,
std::unordered_map<String, bool> options,
Flags flags,
size_t min_positionals,
size_t max_positionals)
ParametersParser::ParametersParser(ParameterList params,
const ParameterDesc& desc)
: m_params(params),
m_options(std::move(options))
m_desc(desc)
{
bool only_pos = false;
for (size_t i = 0; i < params.size(); ++i)
@ -18,8 +15,8 @@ ParametersParser::ParametersParser(const ParameterList& params,
only_pos = true;
else if (not only_pos and params[i][0] == '-')
{
auto it = m_options.find(params[i].substr(1_byte));
if (it == m_options.end())
auto it = m_desc.options.find(params[i].substr(1_byte));
if (it == m_desc.options.end())
throw unknown_option(params[i]);
if (it->second)
@ -31,19 +28,19 @@ ParametersParser::ParametersParser(const ParameterList& params,
}
else
{
if (flags & Flags::OptionsOnlyAtStart)
if (desc.flags & ParameterDesc::Flags::OptionsOnlyAtStart)
only_pos = true;
m_positional_indices.push_back(i);
}
}
size_t count = m_positional_indices.size();
if (count > max_positionals or count < min_positionals)
if (count > desc.max_positionals or count < desc.min_positionals)
throw wrong_argument_count();
}
bool ParametersParser::has_option(const String& name) const
{
kak_assert(m_options.find(name) != m_options.end());
kak_assert(m_desc.options.find(name) != m_desc.options.end());
for (auto& param : m_params)
{
if (param[0] == '-' and param.substr(1_byte) == name)
@ -58,8 +55,8 @@ bool ParametersParser::has_option(const String& name) const
const String& ParametersParser::option_value(const String& name) const
{
#ifdef KAK_DEBUG
auto it = m_options.find(name);
kak_assert(it != m_options.end());
auto it = m_desc.options.find(name);
kak_assert(it != m_desc.options.end());
kak_assert(it->second == true);
#endif

View File

@ -36,12 +36,7 @@ struct wrong_argument_count : public parameter_error
using OptionMap = std::unordered_map<String, bool>;
// ParameterParser provides tools to parse command parameters.
// There are 3 types of parameters:
// * unnamed options, which are accessed by position (ignoring named ones)
// * named boolean options, which are enabled using '-name' syntax
// * named string options, which are defined using '-name value' syntax
struct ParametersParser
struct ParameterDesc
{
enum class Flags
{
@ -57,14 +52,29 @@ struct ParametersParser
return ((int) lhs & (int) rhs) != 0;
}
ParameterDesc() = default;
ParameterDesc(OptionMap options, Flags flags = Flags::None,
size_t min_positionals = 0, size_t max_positionals = -1)
: options(std::move(options)), flags(flags),
min_positionals(min_positionals), max_positionals(max_positionals) {}
OptionMap options;
Flags flags = Flags::None;
size_t min_positionals = 0;
size_t max_positionals = -1;
};
// ParametersParser provides tools to parse command parameters.
// There are 3 types of parameters:
// * unnamed options, which are accessed by position (ignoring named ones)
// * named boolean options, which are enabled using '-name' syntax
// * named string options, which are defined using '-name value' syntax
struct ParametersParser
{
// the options defines named options, if they map to true, then
// they are understood as string options, else they are understood as
// boolean option.
ParametersParser(const ParameterList& params,
OptionMap options,
Flags flags = Flags::None,
size_t min_positionals = 0,
size_t max_positionals = -1);
ParametersParser(ParameterList params, const ParameterDesc& desc);
// check if a named option (either string or boolean) is specified
bool has_option(const String& name) const;
@ -133,7 +143,7 @@ struct ParametersParser
private:
ParameterList m_params;
std::vector<size_t> m_positional_indices;
std::unordered_map<String, bool> m_options;
const ParameterDesc& m_desc;
};
}