Add optional helper for commands, to get parameter dependent help

Use for the set command to document options.
This commit is contained in:
Maxime Coste 2015-02-08 19:04:20 +00:00
parent 0a2f2c2247
commit a94c554a7b
3 changed files with 78 additions and 2 deletions

View File

@ -22,12 +22,14 @@ void CommandManager::register_command(String command_name,
String docstring, String docstring,
ParameterDesc param_desc, ParameterDesc param_desc,
CommandFlags flags, CommandFlags flags,
CommandHelper helper,
CommandCompleter completer) CommandCompleter completer)
{ {
m_commands[command_name] = { std::move(command), m_commands[command_name] = { std::move(command),
std::move(docstring), std::move(docstring),
std::move(param_desc), std::move(param_desc),
flags, flags,
std::move(helper),
std::move(completer) }; std::move(completer) };
} }
@ -458,6 +460,25 @@ CommandInfo CommandManager::command_info(const Context& context, StringView comm
if (not cmd->second.docstring.empty()) if (not cmd->second.docstring.empty())
res.second += cmd->second.docstring + "\n"; res.second += cmd->second.docstring + "\n";
if (cmd->second.helper)
{
Vector<String> params;
for (auto it = tokens.begin() + cmd_idx + 1;
it != tokens.end() and it->type() != Token::Type::CommandSeparator;
++it)
{
if (it->type() == Token::Type::Raw or it->type() == Token::Type::RawEval)
params.push_back(it->content());
}
String helpstr = cmd->second.helper(context, params);
if (not helpstr.empty())
{
if (helpstr.back() != '\n')
helpstr += '\n';
res.second += helpstr;
}
}
String aliases; String aliases;
for (auto& alias : context.aliases().aliases_for(cmd->first)) for (auto& alias : context.aliases().aliases_for(cmd->first))
aliases += " " + alias; aliases += " " + alias;

View File

@ -24,6 +24,8 @@ using CommandCompleter = std::function<Completions (const Context& context,
CompletionFlags, CompletionFlags,
CommandParameters, CommandParameters,
size_t, ByteCount)>; size_t, ByteCount)>;
using CommandHelper = std::function<String (const Context& context, CommandParameters)>;
enum class CommandFlags enum class CommandFlags
{ {
None = 0, None = 0,
@ -74,6 +76,7 @@ public:
String docstring, String docstring,
ParameterDesc param_desc, ParameterDesc param_desc,
CommandFlags flags = CommandFlags::None, CommandFlags flags = CommandFlags::None,
CommandHelper helper = CommandHelper(),
CommandCompleter completer = CommandCompleter()); CommandCompleter completer = CommandCompleter());
private: private:
@ -86,6 +89,7 @@ private:
String docstring; String docstring;
ParameterDesc param_desc; ParameterDesc param_desc;
CommandFlags flags; CommandFlags flags;
CommandHelper helper;
CommandCompleter completer; CommandCompleter completer;
}; };
using CommandMap = UnorderedMap<String, CommandDescriptor, MemoryDomain::Commands>; using CommandMap = UnorderedMap<String, CommandDescriptor, MemoryDomain::Commands>;

View File

@ -127,6 +127,7 @@ struct CommandDesc
const char* docstring; const char* docstring;
ParameterDesc params; ParameterDesc params;
CommandFlags flags; CommandFlags flags;
CommandHelper helper;
CommandCompleter completer; CommandCompleter completer;
void (*func)(const ParametersParser&, Context&); void (*func)(const ParametersParser&, Context&);
}; };
@ -202,6 +203,7 @@ const CommandDesc edit_cmd = {
"edit <switches> <filename>: open the given filename in a buffer", "edit <switches> <filename>: open the given filename in a buffer",
edit_params, edit_params,
CommandFlags::None, CommandFlags::None,
CommandHelper{},
filename_completer, filename_completer,
edit<false> edit<false>
}; };
@ -212,6 +214,7 @@ const CommandDesc force_edit_cmd = {
"edit! <switches> <filename>: open the given filename in a buffer, force reload if needed", "edit! <switches> <filename>: open the given filename in a buffer, force reload if needed",
edit_params, edit_params,
CommandFlags::None, CommandFlags::None,
CommandHelper{},
filename_completer, filename_completer,
edit<true> edit<true>
}; };
@ -235,6 +238,7 @@ const CommandDesc write_cmd = {
"write [filename]: write the current buffer to it's file or to [filename] if specified", "write [filename]: write the current buffer to it's file or to [filename] if specified",
single_optional_name_param, single_optional_name_param,
CommandFlags::None, CommandFlags::None,
CommandHelper{},
filename_completer, filename_completer,
write_buffer, write_buffer,
}; };
@ -254,6 +258,7 @@ const CommandDesc writeall_cmd = {
"write all buffers that are associated to a file", "write all buffers that are associated to a file",
no_params, no_params,
CommandFlags::None, CommandFlags::None,
CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser&, Context&){ write_all_buffers(); } [](const ParametersParser&, Context&){ write_all_buffers(); }
}; };
@ -292,6 +297,7 @@ const CommandDesc quit_cmd = {
"quit current client, and the kakoune session if the client is the last (if not running in daemon mode)", "quit current client, and the kakoune session if the client is the last (if not running in daemon mode)",
no_params, no_params,
CommandFlags::None, CommandFlags::None,
CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser&, Context&){ quit<false>(); } [](const ParametersParser&, Context&){ quit<false>(); }
}; };
@ -303,6 +309,7 @@ const CommandDesc force_quit_cmd = {
"force quit even if the client is the last and some buffers are not saved.", "force quit even if the client is the last and some buffers are not saved.",
no_params, no_params,
CommandFlags::None, CommandFlags::None,
CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser&, Context&){ quit<true>(); } [](const ParametersParser&, Context&){ quit<true>(); }
}; };
@ -313,6 +320,7 @@ const CommandDesc write_quit_cmd = {
"write current buffer and quit current client", "write current buffer and quit current client",
no_params, no_params,
CommandFlags::None, CommandFlags::None,
CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context)
{ {
@ -327,6 +335,7 @@ const CommandDesc force_write_quit_cmd = {
"write current buffer and quit current client, even if other buffers are not saved", "write current buffer and quit current client, even if other buffers are not saved",
no_params, no_params,
CommandFlags::None, CommandFlags::None,
CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context)
{ {
@ -341,6 +350,7 @@ const CommandDesc writeall_quit_cmd = {
"write all buffers associated to a file and quit current client", "write all buffers associated to a file and quit current client",
no_params, no_params,
CommandFlags::None, CommandFlags::None,
CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context)
{ {
@ -355,6 +365,7 @@ const CommandDesc buffer_cmd = {
"buffer <name>: set buffer to edit in current client", "buffer <name>: set buffer to edit in current client",
single_name_param, single_name_param,
CommandFlags::None, CommandFlags::None,
CommandHelper{},
buffer_completer, buffer_completer,
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context)
{ {
@ -389,6 +400,7 @@ const CommandDesc delbuf_cmd = {
"delbuf [name]: delete the current buffer or the buffer named <name> if given", "delbuf [name]: delete the current buffer or the buffer named <name> if given",
single_optional_name_param, single_optional_name_param,
CommandFlags::None, CommandFlags::None,
CommandHelper{},
buffer_completer, buffer_completer,
delete_buffer<false> delete_buffer<false>
}; };
@ -399,6 +411,7 @@ const CommandDesc force_delbuf_cmd = {
"delbuf! [name]: delete the current buffer or the buffer named <name> if given, even if the buffer is unsaved", "delbuf! [name]: delete the current buffer or the buffer named <name> if given, even if the buffer is unsaved",
single_optional_name_param, single_optional_name_param,
CommandFlags::None, CommandFlags::None,
CommandHelper{},
buffer_completer, buffer_completer,
delete_buffer<true> delete_buffer<true>
}; };
@ -409,6 +422,7 @@ const CommandDesc namebuf_cmd = {
"namebuf <name>: change current buffer name", "namebuf <name>: change current buffer name",
single_name_param, single_name_param,
CommandFlags::None, CommandFlags::None,
CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context)
{ {
@ -491,6 +505,7 @@ const CommandDesc add_highlighter_cmd = {
SwitchMap{ { "group", { true, "specify the group in which to put the highlighter" } } }, SwitchMap{ { "group", { true, "specify the group in which to put the highlighter" } } },
ParameterDesc::Flags::SwitchesOnlyAtStart, 1 }, ParameterDesc::Flags::SwitchesOnlyAtStart, 1 },
CommandFlags::None, CommandFlags::None,
CommandHelper{},
add_highlighter_completer, add_highlighter_completer,
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context)
{ {
@ -521,6 +536,7 @@ const CommandDesc rm_highlighter_cmd = {
ParameterDesc::Flags::None, 1, 1 ParameterDesc::Flags::None, 1, 1
}, },
CommandFlags::None, CommandFlags::None,
CommandHelper{},
rm_highlighter_completer, rm_highlighter_completer,
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context)
{ {
@ -548,6 +564,7 @@ const CommandDesc add_hook_cmd = {
ParameterDesc::Flags::None, 4, 4 ParameterDesc::Flags::None, 4, 4
}, },
CommandFlags::None, CommandFlags::None,
CommandHelper{},
[](const Context& context, CompletionFlags flags, [](const Context& context, CompletionFlags flags,
CommandParameters params, size_t token_to_complete, CommandParameters params, size_t token_to_complete,
ByteCount pos_in_token) -> Completions ByteCount pos_in_token) -> Completions
@ -591,6 +608,7 @@ const CommandDesc rm_hook_cmd = {
"rmhooks <scope> <group>: remove all hooks whose group is <group>", "rmhooks <scope> <group>: remove all hooks whose group is <group>",
ParameterDesc{ SwitchMap{}, ParameterDesc::Flags::None, 2, 2 }, ParameterDesc{ SwitchMap{}, ParameterDesc::Flags::None, 2, 2 },
CommandFlags::None, CommandFlags::None,
CommandHelper{},
[](const Context& context, CompletionFlags flags, [](const Context& context, CompletionFlags flags,
CommandParameters params, size_t token_to_complete, CommandParameters params, size_t token_to_complete,
ByteCount pos_in_token) -> Completions ByteCount pos_in_token) -> Completions
@ -711,7 +729,7 @@ void define_command(const ParametersParser& parser, Context& context)
} }
auto& cm = CommandManager::instance(); auto& cm = CommandManager::instance();
cm.register_command(cmd_name, cmd, std::move(docstring), desc, flags, completer); cm.register_command(cmd_name, cmd, std::move(docstring), desc, flags, CommandHelper{}, completer);
} }
const CommandDesc define_command_cmd = { const CommandDesc define_command_cmd = {
@ -731,6 +749,7 @@ const CommandDesc define_command_cmd = {
2, 2 2, 2
}, },
CommandFlags::None, CommandFlags::None,
CommandHelper{},
CommandCompleter{}, CommandCompleter{},
define_command define_command
}; };
@ -741,6 +760,7 @@ const CommandDesc alias_cmd = {
"alias <scope> <alias> <command>: define a command alias in given scope", "alias <scope> <alias> <command>: define a command alias in given scope",
ParameterDesc{SwitchMap{}, ParameterDesc::Flags::None, 3, 3}, ParameterDesc{SwitchMap{}, ParameterDesc::Flags::None, 3, 3},
CommandFlags::None, CommandFlags::None,
CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context)
{ {
@ -756,6 +776,7 @@ const CommandDesc unalias_cmd = {
"if <expected> is specified, the alias is removed only if its value is <expected>", "if <expected> is specified, the alias is removed only if its value is <expected>",
ParameterDesc{SwitchMap{}, ParameterDesc::Flags::None, 2, 3}, ParameterDesc{SwitchMap{}, ParameterDesc::Flags::None, 2, 3},
CommandFlags::None, CommandFlags::None,
CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context)
{ {
@ -777,6 +798,7 @@ const CommandDesc echo_cmd = {
ParameterDesc::Flags::SwitchesOnlyAtStart ParameterDesc::Flags::SwitchesOnlyAtStart
}, },
CommandFlags::None, CommandFlags::None,
CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context)
{ {
@ -800,6 +822,7 @@ const CommandDesc debug_cmd = {
" existing commands: info, buffers", " existing commands: info, buffers",
ParameterDesc{ SwitchMap{}, ParameterDesc::Flags::SwitchesOnlyAtStart, 1 }, ParameterDesc{ SwitchMap{}, ParameterDesc::Flags::SwitchesOnlyAtStart, 1 },
CommandFlags::None, CommandFlags::None,
CommandHelper{},
PerArgumentCommandCompleter({ PerArgumentCommandCompleter({
[](const Context& context, CompletionFlags flags, [](const Context& context, CompletionFlags flags,
const String& prefix, ByteCount cursor_pos) -> Completions { const String& prefix, ByteCount cursor_pos) -> Completions {
@ -855,6 +878,7 @@ const CommandDesc source_cmd = {
"source <filename>: execute commands contained in <filename>", "source <filename>: execute commands contained in <filename>",
single_name_param, single_name_param,
CommandFlags::None, CommandFlags::None,
CommandHelper{},
filename_completer, filename_completer,
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context)
{ {
@ -881,6 +905,21 @@ const CommandDesc set_option_cmd = {
3, 3 3, 3
}, },
CommandFlags::None, CommandFlags::None,
[](const Context& context, CommandParameters params) -> String
{
if (params.size() < 2)
return "";
try
{
OptionManager& options = get_scope(params[0], context).options();
const String& docstring = options[params[1]].docstring();
if (not docstring.empty())
return params[1] + ": " + docstring;
}
catch (runtime_error&) {}
return "";
},
[](const Context& context, CompletionFlags, [](const Context& context, CompletionFlags,
CommandParameters params, size_t token_to_complete, CommandParameters params, size_t token_to_complete,
ByteCount pos_in_token) -> Completions ByteCount pos_in_token) -> Completions
@ -934,6 +973,7 @@ const CommandDesc declare_option_cmd = {
2, 3 2, 3
}, },
CommandFlags::None, CommandFlags::None,
CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context)
{ {
@ -1002,6 +1042,7 @@ const CommandDesc map_key_cmd = {
" user\n", " user\n",
ParameterDesc{ SwitchMap{}, ParameterDesc::Flags::None, 4, 4 }, ParameterDesc{ SwitchMap{}, ParameterDesc::Flags::None, 4, 4 },
CommandFlags::None, CommandFlags::None,
CommandHelper{},
[](const Context& context, CompletionFlags flags, [](const Context& context, CompletionFlags flags,
CommandParameters params, size_t token_to_complete, CommandParameters params, size_t token_to_complete,
ByteCount pos_in_token) -> Completions ByteCount pos_in_token) -> Completions
@ -1152,6 +1193,7 @@ const CommandDesc exec_string_cmd = {
"exec <switches> <keys>: execute given keys as if entered by user", "exec <switches> <keys>: execute given keys as if entered by user",
context_wrap_params, context_wrap_params,
CommandFlags::None, CommandFlags::None,
CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context)
{ {
@ -1173,6 +1215,7 @@ const CommandDesc eval_string_cmd = {
"eval <switches> <commands>...: execute commands as if entered by user", "eval <switches> <commands>...: execute commands as if entered by user",
context_wrap_params, context_wrap_params,
CommandFlags::None, CommandFlags::None,
CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context)
{ {
@ -1195,6 +1238,7 @@ const CommandDesc prompt_cmd = {
ParameterDesc::Flags::None, 3, 3 ParameterDesc::Flags::None, 3, 3
}, },
CommandFlags::None, CommandFlags::None,
CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser& params, Context& context) [](const ParametersParser& params, Context& context)
{ {
@ -1229,6 +1273,7 @@ const CommandDesc menu_cmd = {
{ "select-cmds", { false, "each item specify an additional command to run when selected" } } } { "select-cmds", { false, "each item specify an additional command to run when selected" } } }
}, },
CommandFlags::None, CommandFlags::None,
CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context)
{ {
@ -1277,6 +1322,7 @@ const CommandDesc info_cmd = {
ParameterDesc::Flags::None, 0, 1 ParameterDesc::Flags::None, 0, 1
}, },
CommandFlags::None, CommandFlags::None,
CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context)
{ {
@ -1321,6 +1367,7 @@ const CommandDesc try_catch_cmd = {
"The error is not propagated further.", "The error is not propagated further.",
ParameterDesc{ SwitchMap{}, ParameterDesc::Flags::None, 1, 3 }, ParameterDesc{ SwitchMap{}, ParameterDesc::Flags::None, 1, 3 },
CommandFlags::None, CommandFlags::None,
CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context)
{ {
@ -1357,6 +1404,7 @@ const CommandDesc face_cmd = {
"face <name> <facespec>: set face <name> to refer to <facespec>\n", "face <name> <facespec>: set face <name> to refer to <facespec>\n",
ParameterDesc{ SwitchMap{}, ParameterDesc::Flags::None, 2, 2 }, ParameterDesc{ SwitchMap{}, ParameterDesc::Flags::None, 2, 2 },
CommandFlags::None, CommandFlags::None,
CommandHelper{},
PerArgumentCommandCompleter({ complete_face, complete_face }), PerArgumentCommandCompleter({ complete_face, complete_face }),
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context)
{ {
@ -1370,6 +1418,7 @@ const CommandDesc set_client_name_cmd = {
"nameclient <name>: set current client name to <name>", "nameclient <name>: set current client name to <name>",
single_name_param, single_name_param,
CommandFlags::None, CommandFlags::None,
CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context)
{ {
@ -1386,6 +1435,7 @@ const CommandDesc set_register_cmd = {
"reg <name> <value>: set register <name> to <value>", "reg <name> <value>: set register <name> to <value>",
ParameterDesc{ SwitchMap{}, ParameterDesc::Flags::None, 2, 2 }, ParameterDesc{ SwitchMap{}, ParameterDesc::Flags::None, 2, 2 },
CommandFlags::None, CommandFlags::None,
CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser& parser, Context& context) [](const ParametersParser& parser, Context& context)
{ {
@ -1399,6 +1449,7 @@ const CommandDesc change_working_directory_cmd = {
"cd <dir>: change server working directory to <dir>", "cd <dir>: change server working directory to <dir>",
single_name_param, single_name_param,
CommandFlags::None, CommandFlags::None,
CommandHelper{},
filename_completer, filename_completer,
[](const ParametersParser& parser, Context&) [](const ParametersParser& parser, Context&)
{ {
@ -1440,7 +1491,7 @@ void exec_keys(ArrayView<Key> keys, Context& context)
static void register_command(CommandManager& cm, const CommandDesc& c) static void register_command(CommandManager& cm, const CommandDesc& c)
{ {
cm.register_command(c.name, c.func, c.docstring, c.params, c.flags, c.completer); cm.register_command(c.name, c.func, c.docstring, c.params, c.flags, c.helper, c.completer);
if (c.alias) if (c.alias)
GlobalScope::instance().aliases().add_alias(c.alias, c.name); GlobalScope::instance().aliases().add_alias(c.alias, c.name);
} }