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>::: *-title* <text>:::
set the title of the message box 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 prevent an error in *commands* from aborting the whole command
execution, execute *on_error_commands* instead. If nothing is to be 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*:: *nop*::
does nothing, but arguments will be evaluated (e.g. shell expansion) 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 = { const CommandDesc try_catch_cmd = {
"try", "try",
nullptr, nullptr,
"try <cmds> [catch <error_cmds>]: execute <cmds> in current context.\n" "try <cmds> [catch <error_cmds>]...: execute <cmds> in current context.\n"
"if an error is raised and <error_cmds> is specified, execute it; " "if an error is raised and <error_cmds> is specified, execute it and do\n"
"The error is not propagated further.", "not propagate that error. If <error_cmds> raises an error and another\n"
ParameterDesc{{}, ParameterDesc::Flags::None, 1, 3}, "<error_cmds> is provided, execute this one and so-on\n",
ParameterDesc{{}, ParameterDesc::Flags::None, 1},
CommandFlags::None, CommandFlags::None,
CommandHelper{}, CommandHelper{},
CommandCompleter{}, CommandCompleter{},
[](const ParametersParser& parser, Context& context, const ShellContext& shell_context) [](const ParametersParser& parser, Context& context, const ShellContext& shell_context)
{ {
if (parser.positional_count() == 2) if ((parser.positional_count() % 2) != 1)
throw wrong_argument_count(); throw wrong_argument_count();
const bool do_catch = parser.positional_count() == 3; for (size_t i = 1; i < parser.positional_count(); i += 2)
if (do_catch and parser[1] != "catch") {
throw runtime_error("usage: try <commands> [catch <on error commands>]"); if (parser[i] != "catch")
throw runtime_error("usage: try <commands> [catch <on error commands>]...");
}
CommandManager& command_manager = CommandManager::instance(); 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)
} {
catch (Kakoune::runtime_error& e) try {
{ command_manager.execute(parser[i], context, shell_context);
if (do_catch) return;
command_manager.execute(parser[2], context, shell_context); } catch (runtime_error&) {}
}
else
command_manager.execute(parser[i], context, shell_context);
} }
} }
}; };