Extend try command to support multiple catches.

If a catch command fails, and another catch is availabe following
it, that following catch gets executed.
This commit is contained in:
Maxime Coste 2018-05-19 14:03:32 +10:00
parent 243cfbc4ae
commit ec0f8fe574
2 changed files with 26 additions and 17 deletions

View File

@ -225,10 +225,13 @@ but not really useful in that context.
*-title* <text>:::
set the title of the message box
*try* <commands> catch <on_error_commands>::
*try* <commands> [catch <on_error_commands>]...::
prevent an error in *commands* from aborting the whole command
execution, execute *on_error_commands* instead. If nothing is to be
done on error, the catch part can be omitted
done on error, the catch part can be omitted. If an error is raised
in the *on_error_commands*, that error is propagated, except if
another *catch* and *on_error_commands* parameter follows, in which
case those commands get executed, and so-on.
*nop*::
does nothing, but arguments will be evaluated (e.g. shell expansion)

View File

@ -1958,31 +1958,37 @@ const CommandDesc info_cmd = {
const CommandDesc try_catch_cmd = {
"try",
nullptr,
"try <cmds> [catch <error_cmds>]: execute <cmds> in current context.\n"
"if an error is raised and <error_cmds> is specified, execute it; "
"The error is not propagated further.",
ParameterDesc{{}, ParameterDesc::Flags::None, 1, 3},
"try <cmds> [catch <error_cmds>]...: execute <cmds> in current context.\n"
"if an error is raised and <error_cmds> is specified, execute it and do\n"
"not propagate that error. If <error_cmds> raises an error and another\n"
"<error_cmds> is provided, execute this one and so-on\n",
ParameterDesc{{}, ParameterDesc::Flags::None, 1},
CommandFlags::None,
CommandHelper{},
CommandCompleter{},
[](const ParametersParser& parser, Context& context, const ShellContext& shell_context)
{
if (parser.positional_count() == 2)
if ((parser.positional_count() % 2) != 1)
throw wrong_argument_count();
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>]");
for (size_t i = 1; i < parser.positional_count(); i += 2)
{
if (parser[i] != "catch")
throw runtime_error("usage: try <commands> [catch <on error commands>]...");
}
CommandManager& command_manager = CommandManager::instance();
try
for (size_t i = 0; i < parser.positional_count(); i += 2)
{
command_manager.execute(parser[0], context, shell_context);
if (i == 0 or i < parser.positional_count() - 1)
{
try {
command_manager.execute(parser[i], context, shell_context);
return;
} catch (runtime_error&) {}
}
catch (Kakoune::runtime_error& e)
{
if (do_catch)
command_manager.execute(parser[2], context, shell_context);
else
command_manager.execute(parser[i], context, shell_context);
}
}
};