diff --git a/doc/pages/commands.asciidoc b/doc/pages/commands.asciidoc index 9a86b86d..cd79d26a 100644 --- a/doc/pages/commands.asciidoc +++ b/doc/pages/commands.asciidoc @@ -225,10 +225,13 @@ but not really useful in that context. *-title* ::: set the title of the message box -*try* catch :: +*try* [catch ]...:: 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) diff --git a/src/commands.cc b/src/commands.cc index e81528d6..7c41ba16 100644 --- a/src/commands.cc +++ b/src/commands.cc @@ -1958,31 +1958,37 @@ const CommandDesc info_cmd = { const CommandDesc try_catch_cmd = { "try", nullptr, - "try [catch ]: execute in current context.\n" - "if an error is raised and is specified, execute it; " - "The error is not propagated further.", - ParameterDesc{{}, ParameterDesc::Flags::None, 1, 3}, + "try [catch ]...: execute in current context.\n" + "if an error is raised and is specified, execute it and do\n" + "not propagate that error. If raises an error and another\n" + " 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 [catch ]"); + for (size_t i = 1; i < parser.positional_count(); i += 2) + { + if (parser[i] != "catch") + throw runtime_error("usage: try [catch ]..."); + } 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); - } - catch (Kakoune::runtime_error& e) - { - if (do_catch) - command_manager.execute(parser[2], 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&) {} + } + else + command_manager.execute(parser[i], context, shell_context); } } };