diff --git a/src/command_manager.cc b/src/command_manager.cc index 0f0b700c..be7b3c72 100644 --- a/src/command_manager.cc +++ b/src/command_manager.cc @@ -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 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, diff --git a/src/command_manager.hh b/src/command_manager.hh index 83c865cc..d758aa6c 100644 --- a/src/command_manager.hh +++ b/src/command_manager.hh @@ -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; -using Command = std::function; +using Command = std::function; using CommandCompleter = std::function 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; }; diff --git a/src/commands.cc b/src/commands.cc index 6ed36482..046e8f13 100644 --- a/src/commands.cc +++ b/src/commands.cc @@ -84,13 +84,14 @@ Buffer* open_fifo(const String& name , const String& filename, Context& context) return buffer; } -template -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 +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 -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 names; @@ -190,18 +193,17 @@ void quit(CommandParameters params, Context& context) } template -void write_and_quit(CommandParameters params, Context& context) +void write_and_quit(const ParametersParser& parser, Context& context) { - write_buffer(params, context); - quit(CommandParameters(), context); + write_buffer(parser, context); + quit(ParametersParser{memoryview{}, 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 -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 +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 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 params_to_shell(const ParametersParser& parser) { - ParametersParser parser(params, - { { "env-params", false }, - { "shell-params", false }, - { "allow-override", false }, - { "file-completion", false }, - { "hidden", false }, - { "shell-completion", true } }, - ParametersParser::Flags::None, - 2, 2); + std::vector 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 } }, + 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 -void context_wrap(CommandParameters params, Context& context, Func func) -{ - ParametersParser parser(params, { { "client", true }, { "try-client", true }, - { "draft", false }, { "itersel", false } }, - ParametersParser::Flags::OptionsOnlyAtStart, 1); +const ParameterDesc context_wrap_params = { + { { "client", true }, { "try-client", true }, + { "draft", false }, { "itersel", false } }, + ParameterDesc::Flags::OptionsOnlyAtStart, 1 +}; +template +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 [catch ]"); 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(params[1]); + RegisterManager::instance()[parser[0][0]] = memoryview(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 @@ -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(), cursor_pos) }; } }); - cm.register_commands({ "edit", "e" }, edit, CommandFlags::None, filename_completer); - cm.register_commands({ "edit!", "e!" }, edit, 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); - cm.register_commands({ "quit!", "q!" }, quit); - cm.register_command("wq", write_and_quit); - cm.register_command("wq!", write_and_quit); + cm.register_commands({ "edit", "e" }, edit, edit_params, CommandFlags::None, filename_completer); + cm.register_commands({ "edit!", "e!" }, edit, 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, no_params); + cm.register_commands({ "quit!", "q!" }, quit, no_params); + cm.register_command("wq", write_and_quit, no_params); + cm.register_command("wq!", write_and_quit, 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, CommandFlags::None, buffer_completer); - cm.register_commands({ "delbuf!", "db!" }, delete_buffer, 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, single_opt_name_params, CommandFlags::None, buffer_completer); + cm.register_commands({ "delbuf!", "db!" }, delete_buffer, 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(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(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); } } diff --git a/src/main.cc b/src/main.cc index 4242d265..154e2819 100644 --- a/src/main.cc +++ b/src/main.cc @@ -233,11 +233,14 @@ int run_client(const String& session, const String& init_command) int kakoune(memoryview params) { - ParametersParser parser(params, { { "c", true }, - { "e", true }, - { "n", false }, - { "s", true }, - { "d", false } }); + const ParameterDesc param_desc{ + OptionMap{ { "c", true }, + { "e", true }, + { "n", false }, + { "s", true }, + { "d", false } } + }; + ParametersParser parser(params, param_desc); String init_command; if (parser.has_option("e")) init_command = parser.option_value("e"); diff --git a/src/parameters_parser.cc b/src/parameters_parser.cc index 959ec3ed..eb49521f 100644 --- a/src/parameters_parser.cc +++ b/src/parameters_parser.cc @@ -3,13 +3,10 @@ namespace Kakoune { -ParametersParser::ParametersParser(const ParameterList& params, - std::unordered_map 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 diff --git a/src/parameters_parser.hh b/src/parameters_parser.hh index 2230e3f2..6b82bd8d 100644 --- a/src/parameters_parser.hh +++ b/src/parameters_parser.hh @@ -36,12 +36,7 @@ struct wrong_argument_count : public parameter_error using OptionMap = std::unordered_map; -// 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; @@ -131,9 +141,9 @@ struct ParametersParser iterator end() const; private: - ParameterList m_params; - std::vector m_positional_indices; - std::unordered_map m_options; + ParameterList m_params; + std::vector m_positional_indices; + const ParameterDesc& m_desc; }; }