Add command switches information, and automatically display it
This commit is contained in:
parent
7f9f887b4a
commit
9451782648
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
49
src/main.cc
49
src/main.cc
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue
Block a user