Add command switches information, and automatically display it

This commit is contained in:
Maxime Coste 2014-02-11 22:16:17 +00:00
parent 7f9f887b4a
commit 9451782648
7 changed files with 111 additions and 48 deletions

View File

@ -336,6 +336,35 @@ void CommandManager::execute(const String& command_line,
execute_single_command(params, context);
}
std::pair<String, String> CommandManager::command_info(const String& command_line) const
{
TokenList tokens = parse<false>(command_line);
size_t cmd_idx = 0;
for (size_t i = 0; i < tokens.size(); ++i)
{
if (tokens[i].type() == Token::Type::CommandSeparator)
cmd_idx = i+1;
}
std::pair<String, String> res;
if (cmd_idx == tokens.size() or tokens[cmd_idx].type() != Token::Type::Raw)
return res;
auto cmd = find_command(tokens[cmd_idx].content());
if (cmd == m_commands.end())
return res;
res.first = cmd->first;
auto& opts = cmd->second.param_desc.options;
if (not opts.empty())
{
res.second += "Flags:\n";
res.second += generate_flags_doc(opts);
}
return res;
}
Completions CommandManager::complete(const Context& context, CompletionFlags flags,
const String& command_line, ByteCount cursor_pos)
{

View File

@ -67,6 +67,8 @@ public:
Completions complete(const Context& context, CompletionFlags flags,
const String& command_line, ByteCount cursor_pos);
std::pair<String, String> command_info(const String& command_line) const;
bool command_defined(const String& command_name) const;
void register_command(String command_name, Command command,

View File

@ -85,7 +85,8 @@ Buffer* open_fifo(const String& name , const String& filename, Context& context)
}
static const ParameterDesc edit_params{
OptionMap{ { "scratch", false }, { "fifo", true } },
OptionMap{ { "scratch", { false, "create a scratch buffer, not linked to a file" } },
{ "fifo", { true, "create a buffer reading its content from a named fifo" } } },
ParameterDesc::Flags::None, 1, 3
};
@ -242,7 +243,8 @@ void define_highlighter(const ParametersParser& parser, Context& context)
}
static const ParameterDesc add_highlighter_params{
OptionMap{ { "group", true }, { "def-group", true } },
OptionMap{ { "group", { true, "add highlighter to named group" } },
{ "def-group", { true, "add highlighter to reusable defined group" } } },
ParameterDesc::Flags::None, 1
};
@ -275,7 +277,8 @@ void add_highlighter(const ParametersParser& parser, Context& context)
}
static const ParameterDesc rm_highlighter_params{
OptionMap{ { "group", true } }, ParameterDesc::Flags::None, 1, 1
OptionMap{ { "group", { true, "remove highlighter from given group" } } },
ParameterDesc::Flags::None, 1, 1
};
void rm_highlighter(const ParametersParser& parser, Context& context)
@ -300,7 +303,7 @@ static HookManager& get_hook_manager(const String& scope, Context& context)
}
static const ParameterDesc add_hook_params{
OptionMap{ { "id", true } }, ParameterDesc::Flags::None, 4, 4
OptionMap{ { "id", { true, "set hook id" } } }, ParameterDesc::Flags::None, 4, 4
};
void add_hook(const ParametersParser& parser, Context& context)
@ -347,12 +350,12 @@ std::vector<String> params_to_shell(const ParametersParser& parser)
}
static const ParameterDesc define_command_params{
OptionMap{ { "env-params", false },
{ "shell-params", false },
{ "allow-override", false },
{ "file-completion", false },
{ "hidden", false },
{ "shell-completion", true } },
OptionMap{ { "env-params", { false, "pass parameters as env variables param0..paramN" } },
{ "shell-params", { false, "pass parameters to each shell escape as $0..$N" } },
{ "allow-override", { false, "allow overriding existing command" } },
{ "file-completion", { false, "complete parameters using filename completion" } },
{ "hidden", { false, "do not display the command as completion candidate" } },
{ "shell-completion", { true, "complete the parameters using the given shell-script" } } },
ParameterDesc::Flags::None,
2, 2
};
@ -431,7 +434,7 @@ void define_command(const ParametersParser& parser, Context& context)
}
static const ParameterDesc echo_message_params{
{ { "color", true } },
OptionMap{ { "color", { true, "set message color" } } },
ParameterDesc::Flags::OptionsOnlyAtStart
};
@ -495,7 +498,7 @@ static OptionManager& get_options(const String& scope, const Context& context)
static const ParameterDesc set_option_params{
{ { "add", false } },
OptionMap{ { "add", { false, "add to option rather than replacing it" } } },
ParameterDesc::Flags::OptionsOnlyAtStart,
3, 3
};
@ -510,7 +513,7 @@ void set_option(const ParametersParser& parser, Context& context)
}
static const ParameterDesc declare_option_params{
{ { "hidden", false } },
OptionMap{ { "hidden", { false, "do not display option name when completing" } } },
ParameterDesc::Flags::OptionsOnlyAtStart,
2, 3
};
@ -585,8 +588,10 @@ void map_key(const ParametersParser& parser, Context& context)
}
const ParameterDesc context_wrap_params = {
{ { "client", true }, { "try-client", true },
{ "draft", false }, { "itersel", false } },
OptionMap{ { "client", { true, "run in given client context" } },
{ "try-client", { true, "run in given client context if it exists, or else in the current one" } },
{ "draft", { false, "run in a disposable context" } },
{ "itersel", { false, "run once for each selection with that selection as the only one" } } },
ParameterDesc::Flags::OptionsOnlyAtStart, 1
};
@ -661,8 +666,10 @@ void eval_string(const ParametersParser& parser, Context& context)
});
}
static const ParameterDesc menu_params{ { { "auto-single", false },
{ "select-cmds", false } } };
static const ParameterDesc menu_params{
OptionMap{ { "auto-single", { false, "instantly validate if only one item is available" } },
{ "select-cmds", { false, "each item specify an additional command to run when selected" } } }
};
void menu(const ParametersParser& parser, Context& context)
{
@ -700,7 +707,8 @@ void menu(const ParametersParser& parser, Context& context)
}
static const ParameterDesc info_params{
{ { "anchor", true }, { "title", true } },
OptionMap{ { "anchor", { true, "set info anchoring (left, right, or cursor)" } },
{ "title", { true, "set info title" } } },
ParameterDesc::Flags::None, 0, 1
};

View File

@ -231,16 +231,8 @@ int run_client(const String& session, const String& init_command)
return 0;
}
int kakoune(memoryview<String> params)
int kakoune(const ParametersParser& parser)
{
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");
@ -356,31 +348,34 @@ int kakoune(memoryview<String> params)
int main(int argc, char* argv[])
{
setlocale(LC_ALL, "");
signal(SIGSEGV, signal_handler);
signal(SIGFPE, signal_handler);
signal(SIGQUIT, signal_handler);
signal(SIGTERM, signal_handler);
std::vector<String> params;
for (size_t i = 1; i < argc; ++i)
params.push_back(argv[i]);
const ParameterDesc param_desc{
OptionMap{ { "c", { true, "connect to given session" } },
{ "e", { true, "execute argument on initialisation" } },
{ "n", { false, "do not source kakrc files on startup" } },
{ "s", { true, "set session name" } },
{ "d", { false, "run as a headless session (requires -s)" } } }
};
try
{
setlocale(LC_ALL, "");
signal(SIGSEGV, signal_handler);
signal(SIGFPE, signal_handler);
signal(SIGQUIT, signal_handler);
signal(SIGTERM, signal_handler);
std::vector<String> params;
for (size_t i = 1; i < argc; ++i)
params.push_back(argv[i]);
kakoune(params);
kakoune(ParametersParser(params, param_desc));
}
catch (Kakoune::parameter_error& error)
{
printf("Error: %s\n"
"Valid options:\n"
" -e <commands>: execute commands on initialisation\n"
" -c <session>: connect to the given session\n"
" -s <session>: set session name\n"
" -d: run as a headless session (requires -s)\n"
" -n: do not source kakrc files on startup\n",
error.what());
"%s",
error.what(), generate_flags_doc(param_desc.options).c_str());
return -1;
}
catch (Kakoune::exception& error)

View File

@ -418,6 +418,19 @@ void command(Context& context, int)
":", get_color("Prompt"),
std::bind(&CommandManager::complete, &CommandManager::instance(), _1, _2, _3, _4),
[](const String& cmdline, PromptEvent event, Context& context) {
if (context.has_ui())
{
context.ui().info_hide();
if (event == PromptEvent::Change)
{
auto info = CommandManager::instance().command_info(cmdline);
ColorPair col = get_color("Information");
DisplayCoord pos = context.window().dimensions();
pos.column -= 1;
if (not info.first.empty() and not info.second.empty())
context.ui().info_show(info.first, info.second, pos , col, MenuStyle::Prompt);
}
}
if (event == PromptEvent::Validate)
CommandManager::instance().execute(cmdline, context);
});

View File

@ -3,6 +3,14 @@
namespace Kakoune
{
String generate_flags_doc(const OptionMap& opts)
{
String res;
for (auto& opt : opts)
res += " -" + opt.first + (opt.second.takes_arg ? " <arg>: " : ": ") + opt.second.description + "\n";
return res;
}
ParametersParser::ParametersParser(ParameterList params,
const ParameterDesc& desc)
: m_params(params),
@ -19,7 +27,7 @@ ParametersParser::ParametersParser(ParameterList params,
if (it == m_desc.options.end())
throw unknown_option(params[i]);
if (it->second)
if (it->second.takes_arg)
{
++i;
if (i == params.size() or params[i][0] == '-')
@ -57,7 +65,7 @@ const String& ParametersParser::option_value(const String& name) const
#ifdef KAK_DEBUG
auto it = m_desc.options.find(name);
kak_assert(it != m_desc.options.end());
kak_assert(it->second == true);
kak_assert(it->second.takes_arg);
#endif
for (size_t i = 0; i < m_params.size(); ++i)

View File

@ -34,7 +34,15 @@ struct wrong_argument_count : public parameter_error
wrong_argument_count() : parameter_error("wrong argument count") {}
};
using OptionMap = std::unordered_map<String, bool>;
struct OptionDesc
{
bool takes_arg;
String description;
};
using OptionMap = std::unordered_map<String, OptionDesc>;
String generate_flags_doc(const OptionMap& opts);
struct ParameterDesc
{