mirror of
https://github.com/neovim/neovim.git
synced 2025-09-06 03:18:16 +00:00
Merge pull request #21274 from zeertzjq/vim-8.2.3992
vim-patch:8.2.{3992,4261,4262},9.0.{0110,0577}
This commit is contained in:
@@ -8003,7 +8003,7 @@ stridx({haystack}, {needle} [, {start}]) *stridx()*
|
|||||||
|
|
||||||
Can also be used as a |method|: >
|
Can also be used as a |method|: >
|
||||||
GetHaystack()->stridx(needle)
|
GetHaystack()->stridx(needle)
|
||||||
|
<
|
||||||
*string()*
|
*string()*
|
||||||
string({expr}) Return {expr} converted to a String. If {expr} is a Number,
|
string({expr}) Return {expr} converted to a String. If {expr} is a Number,
|
||||||
Float, String, Blob or a composition of them, then the result
|
Float, String, Blob or a composition of them, then the result
|
||||||
|
@@ -1780,7 +1780,7 @@ v:exiting Exit code, or |v:null| before invoking the |VimLeavePre|
|
|||||||
and |VimLeave| autocmds. See |:q|, |:x| and |:cquit|.
|
and |VimLeave| autocmds. See |:q|, |:x| and |:cquit|.
|
||||||
Example: >
|
Example: >
|
||||||
:au VimLeave * echo "Exit value is " .. v:exiting
|
:au VimLeave * echo "Exit value is " .. v:exiting
|
||||||
|
<
|
||||||
*v:echospace* *echospace-variable*
|
*v:echospace* *echospace-variable*
|
||||||
v:echospace Number of screen cells that can be used for an `:echo` message
|
v:echospace Number of screen cells that can be used for an `:echo` message
|
||||||
in the last screen line before causing the |hit-enter-prompt|.
|
in the last screen line before causing the |hit-enter-prompt|.
|
||||||
|
@@ -1420,108 +1420,107 @@ void ex_finally(exarg_T *eap)
|
|||||||
int pending = CSTP_NONE;
|
int pending = CSTP_NONE;
|
||||||
cstack_T *const cstack = eap->cstack;
|
cstack_T *const cstack = eap->cstack;
|
||||||
|
|
||||||
if (cstack->cs_trylevel <= 0 || cstack->cs_idx < 0) {
|
for (idx = cstack->cs_idx; idx >= 0; idx--) {
|
||||||
|
if (cstack->cs_flags[idx] & CSF_TRY) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cstack->cs_trylevel <= 0 || idx < 0) {
|
||||||
eap->errmsg = _("E606: :finally without :try");
|
eap->errmsg = _("E606: :finally without :try");
|
||||||
} else {
|
return;
|
||||||
if (!(cstack->cs_flags[cstack->cs_idx] & CSF_TRY)) {
|
}
|
||||||
eap->errmsg = get_end_emsg(cstack);
|
|
||||||
for (idx = cstack->cs_idx - 1; idx > 0; idx--) {
|
if (!(cstack->cs_flags[cstack->cs_idx] & CSF_TRY)) {
|
||||||
if (cstack->cs_flags[idx] & CSF_TRY) {
|
eap->errmsg = get_end_emsg(cstack);
|
||||||
break;
|
// Make this error pending, so that the commands in the following
|
||||||
}
|
// finally clause can be executed. This overrules also a pending
|
||||||
}
|
// ":continue", ":break", ":return", or ":finish".
|
||||||
// Make this error pending, so that the commands in the following
|
pending = CSTP_ERROR;
|
||||||
// finally clause can be executed. This overrules also a pending
|
}
|
||||||
// ":continue", ":break", ":return", or ":finish".
|
|
||||||
pending = CSTP_ERROR;
|
if (cstack->cs_flags[idx] & CSF_FINALLY) {
|
||||||
} else {
|
// Give up for a multiple ":finally" and ignore it.
|
||||||
idx = cstack->cs_idx;
|
eap->errmsg = _("E607: multiple :finally");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
rewind_conditionals(cstack, idx, CSF_WHILE | CSF_FOR,
|
||||||
|
&cstack->cs_looplevel);
|
||||||
|
|
||||||
|
// Don't do something when the corresponding try block never got active
|
||||||
|
// (because of an inactive surrounding conditional or after an error or
|
||||||
|
// interrupt or throw) or for a ":finally" without ":try" or a multiple
|
||||||
|
// ":finally". After every other error (did_emsg or the conditional
|
||||||
|
// errors detected above) or after an interrupt (got_int) or an
|
||||||
|
// exception (did_throw), the finally clause must be executed.
|
||||||
|
skip = !(cstack->cs_flags[cstack->cs_idx] & CSF_TRUE);
|
||||||
|
|
||||||
|
if (!skip) {
|
||||||
|
// When debugging or a breakpoint was encountered, display the
|
||||||
|
// debug prompt (if not already done). The user then knows that the
|
||||||
|
// finally clause is executed.
|
||||||
|
if (dbg_check_skipped(eap)) {
|
||||||
|
// Handle a ">quit" debug command as if an interrupt had
|
||||||
|
// occurred before the ":finally". That is, discard the
|
||||||
|
// original exception and replace it by an interrupt
|
||||||
|
// exception.
|
||||||
|
(void)do_intthrow(cstack);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cstack->cs_flags[idx] & CSF_FINALLY) {
|
// If there is a preceding catch clause and it caught the exception,
|
||||||
// Give up for a multiple ":finally" and ignore it.
|
// finish the exception now. This happens also after errors except
|
||||||
eap->errmsg = _("E607: multiple :finally");
|
// when this is a multiple ":finally" or one not within a ":try".
|
||||||
return;
|
// After an error or interrupt, this also discards a pending
|
||||||
}
|
// ":continue", ":break", ":finish", or ":return" from the preceding
|
||||||
rewind_conditionals(cstack, idx, CSF_WHILE | CSF_FOR,
|
// try block or catch clause.
|
||||||
&cstack->cs_looplevel);
|
cleanup_conditionals(cstack, CSF_TRY, false);
|
||||||
|
|
||||||
// Don't do something when the corresponding try block never got active
|
// Make did_emsg, got_int, did_throw pending. If set, they overrule
|
||||||
// (because of an inactive surrounding conditional or after an error or
|
// a pending ":continue", ":break", ":return", or ":finish". Then
|
||||||
// interrupt or throw) or for a ":finally" without ":try" or a multiple
|
// we have particularly to discard a pending return value (as done
|
||||||
// ":finally". After every other error (did_emsg or the conditional
|
// by the call to cleanup_conditionals() above when did_emsg or
|
||||||
// errors detected above) or after an interrupt (got_int) or an
|
// got_int is set). The pending values are restored by the
|
||||||
// exception (did_throw), the finally clause must be executed.
|
// ":endtry", except if there is a new error, interrupt, exception,
|
||||||
skip = !(cstack->cs_flags[cstack->cs_idx] & CSF_TRUE);
|
// ":continue", ":break", ":return", or ":finish" in the following
|
||||||
|
// finally clause. A missing ":endwhile", ":endfor" or ":endif"
|
||||||
if (!skip) {
|
// detected here is treated as if did_emsg and did_throw had
|
||||||
// When debugging or a breakpoint was encountered, display the
|
// already been set, respectively in case that the error is not
|
||||||
// debug prompt (if not already done). The user then knows that the
|
// converted to an exception, did_throw had already been unset.
|
||||||
// finally clause is executed.
|
// We must not set did_emsg here since that would suppress the
|
||||||
if (dbg_check_skipped(eap)) {
|
// error message.
|
||||||
// Handle a ">quit" debug command as if an interrupt had
|
if (pending == CSTP_ERROR || did_emsg || got_int || did_throw) {
|
||||||
// occurred before the ":finally". That is, discard the
|
if (cstack->cs_pending[cstack->cs_idx] == CSTP_RETURN) {
|
||||||
// original exception and replace it by an interrupt
|
report_discard_pending(CSTP_RETURN,
|
||||||
// exception.
|
cstack->cs_rettv[cstack->cs_idx]);
|
||||||
(void)do_intthrow(cstack);
|
discard_pending_return(cstack->cs_rettv[cstack->cs_idx]);
|
||||||
}
|
}
|
||||||
|
if (pending == CSTP_ERROR && !did_emsg) {
|
||||||
// If there is a preceding catch clause and it caught the exception,
|
pending |= (THROW_ON_ERROR ? CSTP_THROW : 0);
|
||||||
// finish the exception now. This happens also after errors except
|
} else {
|
||||||
// when this is a multiple ":finally" or one not within a ":try".
|
pending |= (did_throw ? CSTP_THROW : 0);
|
||||||
// After an error or interrupt, this also discards a pending
|
|
||||||
// ":continue", ":break", ":finish", or ":return" from the preceding
|
|
||||||
// try block or catch clause.
|
|
||||||
cleanup_conditionals(cstack, CSF_TRY, false);
|
|
||||||
|
|
||||||
// Make did_emsg, got_int, did_throw pending. If set, they overrule
|
|
||||||
// a pending ":continue", ":break", ":return", or ":finish". Then
|
|
||||||
// we have particularly to discard a pending return value (as done
|
|
||||||
// by the call to cleanup_conditionals() above when did_emsg or
|
|
||||||
// got_int is set). The pending values are restored by the
|
|
||||||
// ":endtry", except if there is a new error, interrupt, exception,
|
|
||||||
// ":continue", ":break", ":return", or ":finish" in the following
|
|
||||||
// finally clause. A missing ":endwhile", ":endfor" or ":endif"
|
|
||||||
// detected here is treated as if did_emsg and did_throw had
|
|
||||||
// already been set, respectively in case that the error is not
|
|
||||||
// converted to an exception, did_throw had already been unset.
|
|
||||||
// We must not set did_emsg here since that would suppress the
|
|
||||||
// error message.
|
|
||||||
if (pending == CSTP_ERROR || did_emsg || got_int || did_throw) {
|
|
||||||
if (cstack->cs_pending[cstack->cs_idx] == CSTP_RETURN) {
|
|
||||||
report_discard_pending(CSTP_RETURN,
|
|
||||||
cstack->cs_rettv[cstack->cs_idx]);
|
|
||||||
discard_pending_return(cstack->cs_rettv[cstack->cs_idx]);
|
|
||||||
}
|
|
||||||
if (pending == CSTP_ERROR && !did_emsg) {
|
|
||||||
pending |= (THROW_ON_ERROR ? CSTP_THROW : 0);
|
|
||||||
} else {
|
|
||||||
pending |= (did_throw ? CSTP_THROW : 0);
|
|
||||||
}
|
|
||||||
pending |= did_emsg ? CSTP_ERROR : 0;
|
|
||||||
pending |= got_int ? CSTP_INTERRUPT : 0;
|
|
||||||
assert(pending >= CHAR_MIN && pending <= CHAR_MAX);
|
|
||||||
cstack->cs_pending[cstack->cs_idx] = (char)pending;
|
|
||||||
|
|
||||||
// It's mandatory that the current exception is stored in the
|
|
||||||
// cstack so that it can be rethrown at the ":endtry" or be
|
|
||||||
// discarded if the finally clause is left by a ":continue",
|
|
||||||
// ":break", ":return", ":finish", error, interrupt, or another
|
|
||||||
// exception. When emsg() is called for a missing ":endif" or
|
|
||||||
// a missing ":endwhile"/":endfor" detected here, the
|
|
||||||
// exception will be discarded.
|
|
||||||
if (did_throw && cstack->cs_exception[cstack->cs_idx] != current_exception) {
|
|
||||||
internal_error("ex_finally()");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
pending |= did_emsg ? CSTP_ERROR : 0;
|
||||||
|
pending |= got_int ? CSTP_INTERRUPT : 0;
|
||||||
|
assert(pending >= CHAR_MIN && pending <= CHAR_MAX);
|
||||||
|
cstack->cs_pending[cstack->cs_idx] = (char)pending;
|
||||||
|
|
||||||
// Set CSL_HAD_FINA, so do_cmdline() will reset did_emsg,
|
// It's mandatory that the current exception is stored in the
|
||||||
// got_int, and did_throw and make the finally clause active.
|
// cstack so that it can be rethrown at the ":endtry" or be
|
||||||
// This will happen after emsg() has been called for a missing
|
// discarded if the finally clause is left by a ":continue",
|
||||||
// ":endif" or a missing ":endwhile"/":endfor" detected here, so
|
// ":break", ":return", ":finish", error, interrupt, or another
|
||||||
// that the following finally clause will be executed even then.
|
// exception. When emsg() is called for a missing ":endif" or
|
||||||
cstack->cs_lflags |= CSL_HAD_FINA;
|
// a missing ":endwhile"/":endfor" detected here, the
|
||||||
|
// exception will be discarded.
|
||||||
|
if (did_throw && cstack->cs_exception[cstack->cs_idx] != current_exception) {
|
||||||
|
internal_error("ex_finally()");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set CSL_HAD_FINA, so do_cmdline() will reset did_emsg,
|
||||||
|
// got_int, and did_throw and make the finally clause active.
|
||||||
|
// This will happen after emsg() has been called for a missing
|
||||||
|
// ":endif" or a missing ":endwhile"/":endfor" detected here, so
|
||||||
|
// that the following finally clause will be executed even then.
|
||||||
|
cstack->cs_lflags |= CSL_HAD_FINA;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1534,165 +1533,167 @@ void ex_endtry(exarg_T *eap)
|
|||||||
void *rettv = NULL;
|
void *rettv = NULL;
|
||||||
cstack_T *const cstack = eap->cstack;
|
cstack_T *const cstack = eap->cstack;
|
||||||
|
|
||||||
if (cstack->cs_trylevel <= 0 || cstack->cs_idx < 0) {
|
for (idx = cstack->cs_idx; idx >= 0; idx--) {
|
||||||
|
if (cstack->cs_flags[idx] & CSF_TRY) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cstack->cs_trylevel <= 0 || idx < 0) {
|
||||||
eap->errmsg = _("E602: :endtry without :try");
|
eap->errmsg = _("E602: :endtry without :try");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't do something after an error, interrupt or throw in the try
|
||||||
|
// block, catch clause, or finally clause preceding this ":endtry" or
|
||||||
|
// when an error or interrupt occurred after a ":continue", ":break",
|
||||||
|
// ":return", or ":finish" in a try block or catch clause preceding this
|
||||||
|
// ":endtry" or when the try block never got active (because of an
|
||||||
|
// inactive surrounding conditional or after an error or interrupt or
|
||||||
|
// throw) or when there is a surrounding conditional and it has been
|
||||||
|
// made inactive by a ":continue", ":break", ":return", or ":finish" in
|
||||||
|
// the finally clause. The latter case need not be tested since then
|
||||||
|
// anything pending has already been discarded.
|
||||||
|
bool skip = did_emsg || got_int || did_throw || !(cstack->cs_flags[cstack->cs_idx] & CSF_TRUE);
|
||||||
|
|
||||||
|
if (!(cstack->cs_flags[cstack->cs_idx] & CSF_TRY)) {
|
||||||
|
eap->errmsg = get_end_emsg(cstack);
|
||||||
|
|
||||||
|
// Find the matching ":try" and report what's missing.
|
||||||
|
rewind_conditionals(cstack, idx, CSF_WHILE | CSF_FOR,
|
||||||
|
&cstack->cs_looplevel);
|
||||||
|
skip = true;
|
||||||
|
|
||||||
|
// If an exception is being thrown, discard it to prevent it from
|
||||||
|
// being rethrown at the end of this function. It would be
|
||||||
|
// discarded by the error message, anyway. Resets did_throw.
|
||||||
|
// This does not affect the script termination due to the error
|
||||||
|
// since "trylevel" is decremented after emsg() has been called.
|
||||||
|
if (did_throw) {
|
||||||
|
discard_current_exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
// report eap->errmsg, also when there already was an error
|
||||||
|
did_emsg = false;
|
||||||
} else {
|
} else {
|
||||||
// Don't do something after an error, interrupt or throw in the try
|
idx = cstack->cs_idx;
|
||||||
// block, catch clause, or finally clause preceding this ":endtry" or
|
|
||||||
// when an error or interrupt occurred after a ":continue", ":break",
|
|
||||||
// ":return", or ":finish" in a try block or catch clause preceding this
|
|
||||||
// ":endtry" or when the try block never got active (because of an
|
|
||||||
// inactive surrounding conditional or after an error or interrupt or
|
|
||||||
// throw) or when there is a surrounding conditional and it has been
|
|
||||||
// made inactive by a ":continue", ":break", ":return", or ":finish" in
|
|
||||||
// the finally clause. The latter case need not be tested since then
|
|
||||||
// anything pending has already been discarded.
|
|
||||||
bool skip = did_emsg || got_int || did_throw || !(cstack->cs_flags[cstack->cs_idx] & CSF_TRUE);
|
|
||||||
|
|
||||||
if (!(cstack->cs_flags[cstack->cs_idx] & CSF_TRY)) {
|
// If we stopped with the exception currently being thrown at this
|
||||||
eap->errmsg = get_end_emsg(cstack);
|
// try conditional since we didn't know that it doesn't have
|
||||||
|
// a finally clause, we need to rethrow it after closing the try
|
||||||
|
// conditional.
|
||||||
|
if (did_throw
|
||||||
|
&& (cstack->cs_flags[idx] & CSF_TRUE)
|
||||||
|
&& !(cstack->cs_flags[idx] & CSF_FINALLY)) {
|
||||||
|
rethrow = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Find the matching ":try" and report what's missing.
|
// If there was no finally clause, show the user when debugging or
|
||||||
idx = cstack->cs_idx;
|
// a breakpoint was encountered that the end of the try conditional has
|
||||||
do {
|
// been reached: display the debug prompt (if not already done). Do
|
||||||
idx--;
|
// this on normal control flow or when an exception was thrown, but not
|
||||||
} while (idx > 0 && !(cstack->cs_flags[idx] & CSF_TRY));
|
// on an interrupt or error not converted to an exception or when
|
||||||
rewind_conditionals(cstack, idx, CSF_WHILE | CSF_FOR,
|
// a ":break", ":continue", ":return", or ":finish" is pending. These
|
||||||
&cstack->cs_looplevel);
|
// actions are carried out immediately.
|
||||||
|
if ((rethrow || (!skip
|
||||||
|
&& !(cstack->cs_flags[idx] & CSF_FINALLY)
|
||||||
|
&& !cstack->cs_pending[idx]))
|
||||||
|
&& dbg_check_skipped(eap)) {
|
||||||
|
// Handle a ">quit" debug command as if an interrupt had occurred
|
||||||
|
// before the ":endtry". That is, throw an interrupt exception and
|
||||||
|
// set "skip" and "rethrow".
|
||||||
|
if (got_int) {
|
||||||
skip = true;
|
skip = true;
|
||||||
|
(void)do_intthrow(cstack);
|
||||||
// If an exception is being thrown, discard it to prevent it from
|
// The do_intthrow() call may have reset did_throw or
|
||||||
// being rethrown at the end of this function. It would be
|
// cstack->cs_pending[idx].
|
||||||
// discarded by the error message, anyway. Resets did_throw.
|
rethrow = false;
|
||||||
// This does not affect the script termination due to the error
|
if (did_throw && !(cstack->cs_flags[idx] & CSF_FINALLY)) {
|
||||||
// since "trylevel" is decremented after emsg() has been called.
|
|
||||||
if (did_throw) {
|
|
||||||
discard_current_exception();
|
|
||||||
}
|
|
||||||
|
|
||||||
// report eap->errmsg, also when there already was an error
|
|
||||||
did_emsg = false;
|
|
||||||
} else {
|
|
||||||
idx = cstack->cs_idx;
|
|
||||||
|
|
||||||
// If we stopped with the exception currently being thrown at this
|
|
||||||
// try conditional since we didn't know that it doesn't have
|
|
||||||
// a finally clause, we need to rethrow it after closing the try
|
|
||||||
// conditional.
|
|
||||||
if (did_throw
|
|
||||||
&& (cstack->cs_flags[idx] & CSF_TRUE)
|
|
||||||
&& !(cstack->cs_flags[idx] & CSF_FINALLY)) {
|
|
||||||
rethrow = true;
|
rethrow = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If there was no finally clause, show the user when debugging or
|
// If a ":return" is pending, we need to resume it after closing the
|
||||||
// a breakpoint was encountered that the end of the try conditional has
|
// try conditional; remember the return value. If there was a finally
|
||||||
// been reached: display the debug prompt (if not already done). Do
|
// clause making an exception pending, we need to rethrow it. Make it
|
||||||
// this on normal control flow or when an exception was thrown, but not
|
// the exception currently being thrown.
|
||||||
// on an interrupt or error not converted to an exception or when
|
if (!skip) {
|
||||||
// a ":break", ":continue", ":return", or ":finish" is pending. These
|
pending = cstack->cs_pending[idx];
|
||||||
// actions are carried out immediately.
|
cstack->cs_pending[idx] = CSTP_NONE;
|
||||||
if ((rethrow || (!skip
|
if (pending == CSTP_RETURN) {
|
||||||
&& !(cstack->cs_flags[idx] & CSF_FINALLY)
|
rettv = cstack->cs_rettv[idx];
|
||||||
&& !cstack->cs_pending[idx]))
|
} else if (pending & CSTP_THROW) {
|
||||||
&& dbg_check_skipped(eap)) {
|
current_exception = cstack->cs_exception[idx];
|
||||||
// Handle a ">quit" debug command as if an interrupt had occurred
|
}
|
||||||
// before the ":endtry". That is, throw an interrupt exception and
|
}
|
||||||
// set "skip" and "rethrow".
|
|
||||||
if (got_int) {
|
// Discard anything pending on an error, interrupt, or throw in the
|
||||||
skip = true;
|
// finally clause. If there was no ":finally", discard a pending
|
||||||
(void)do_intthrow(cstack);
|
// ":continue", ":break", ":return", or ":finish" if an error or
|
||||||
// The do_intthrow() call may have reset did_throw or
|
// interrupt occurred afterwards, but before the ":endtry" was reached.
|
||||||
// cstack->cs_pending[idx].
|
// If an exception was caught by the last of the catch clauses and there
|
||||||
rethrow = false;
|
// was no finally clause, finish the exception now. This happens also
|
||||||
if (did_throw && !(cstack->cs_flags[idx] & CSF_FINALLY)) {
|
// after errors except when this ":endtry" is not within a ":try".
|
||||||
rethrow = true;
|
// Restore "emsg_silent" if it has been reset by this try conditional.
|
||||||
}
|
(void)cleanup_conditionals(cstack, CSF_TRY | CSF_SILENT, true);
|
||||||
|
|
||||||
|
if (cstack->cs_idx >= 0 && (cstack->cs_flags[cstack->cs_idx] & CSF_TRY)) {
|
||||||
|
cstack->cs_idx--;
|
||||||
|
}
|
||||||
|
cstack->cs_trylevel--;
|
||||||
|
|
||||||
|
if (!skip) {
|
||||||
|
report_resume_pending(pending,
|
||||||
|
(pending == CSTP_RETURN) ? rettv :
|
||||||
|
(pending & CSTP_THROW) ? (void *)current_exception : NULL);
|
||||||
|
switch (pending) {
|
||||||
|
case CSTP_NONE:
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Reactivate a pending ":continue", ":break", ":return",
|
||||||
|
// ":finish" from the try block or a catch clause of this try
|
||||||
|
// conditional. This is skipped, if there was an error in an
|
||||||
|
// (unskipped) conditional command or an interrupt afterwards
|
||||||
|
// or if the finally clause is present and executed a new error,
|
||||||
|
// interrupt, throw, ":continue", ":break", ":return", or
|
||||||
|
// ":finish".
|
||||||
|
case CSTP_CONTINUE:
|
||||||
|
ex_continue(eap);
|
||||||
|
break;
|
||||||
|
case CSTP_BREAK:
|
||||||
|
ex_break(eap);
|
||||||
|
break;
|
||||||
|
case CSTP_RETURN:
|
||||||
|
do_return(eap, false, false, rettv);
|
||||||
|
break;
|
||||||
|
case CSTP_FINISH:
|
||||||
|
do_finish(eap, false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// When the finally clause was entered due to an error,
|
||||||
|
// interrupt or throw (as opposed to a ":continue", ":break",
|
||||||
|
// ":return", or ":finish"), restore the pending values of
|
||||||
|
// did_emsg, got_int, and did_throw. This is skipped, if there
|
||||||
|
// was a new error, interrupt, throw, ":continue", ":break",
|
||||||
|
// ":return", or ":finish". in the finally clause.
|
||||||
|
default:
|
||||||
|
if (pending & CSTP_ERROR) {
|
||||||
|
did_emsg = true;
|
||||||
}
|
}
|
||||||
}
|
if (pending & CSTP_INTERRUPT) {
|
||||||
|
got_int = true;
|
||||||
// If a ":return" is pending, we need to resume it after closing the
|
|
||||||
// try conditional; remember the return value. If there was a finally
|
|
||||||
// clause making an exception pending, we need to rethrow it. Make it
|
|
||||||
// the exception currently being thrown.
|
|
||||||
if (!skip) {
|
|
||||||
pending = cstack->cs_pending[idx];
|
|
||||||
cstack->cs_pending[idx] = CSTP_NONE;
|
|
||||||
if (pending == CSTP_RETURN) {
|
|
||||||
rettv = cstack->cs_rettv[idx];
|
|
||||||
} else if (pending & CSTP_THROW) {
|
|
||||||
current_exception = cstack->cs_exception[idx];
|
|
||||||
}
|
}
|
||||||
}
|
if (pending & CSTP_THROW) {
|
||||||
|
rethrow = true;
|
||||||
// Discard anything pending on an error, interrupt, or throw in the
|
|
||||||
// finally clause. If there was no ":finally", discard a pending
|
|
||||||
// ":continue", ":break", ":return", or ":finish" if an error or
|
|
||||||
// interrupt occurred afterwards, but before the ":endtry" was reached.
|
|
||||||
// If an exception was caught by the last of the catch clauses and there
|
|
||||||
// was no finally clause, finish the exception now. This happens also
|
|
||||||
// after errors except when this ":endtry" is not within a ":try".
|
|
||||||
// Restore "emsg_silent" if it has been reset by this try conditional.
|
|
||||||
(void)cleanup_conditionals(cstack, CSF_TRY | CSF_SILENT, true);
|
|
||||||
|
|
||||||
if (cstack->cs_idx >= 0 && (cstack->cs_flags[cstack->cs_idx] & CSF_TRY)) {
|
|
||||||
cstack->cs_idx--;
|
|
||||||
}
|
|
||||||
cstack->cs_trylevel--;
|
|
||||||
|
|
||||||
if (!skip) {
|
|
||||||
report_resume_pending(pending,
|
|
||||||
(pending == CSTP_RETURN) ? rettv :
|
|
||||||
(pending & CSTP_THROW) ? (void *)current_exception : NULL);
|
|
||||||
switch (pending) {
|
|
||||||
case CSTP_NONE:
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Reactivate a pending ":continue", ":break", ":return",
|
|
||||||
// ":finish" from the try block or a catch clause of this try
|
|
||||||
// conditional. This is skipped, if there was an error in an
|
|
||||||
// (unskipped) conditional command or an interrupt afterwards
|
|
||||||
// or if the finally clause is present and executed a new error,
|
|
||||||
// interrupt, throw, ":continue", ":break", ":return", or
|
|
||||||
// ":finish".
|
|
||||||
case CSTP_CONTINUE:
|
|
||||||
ex_continue(eap);
|
|
||||||
break;
|
|
||||||
case CSTP_BREAK:
|
|
||||||
ex_break(eap);
|
|
||||||
break;
|
|
||||||
case CSTP_RETURN:
|
|
||||||
do_return(eap, false, false, rettv);
|
|
||||||
break;
|
|
||||||
case CSTP_FINISH:
|
|
||||||
do_finish(eap, false);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// When the finally clause was entered due to an error,
|
|
||||||
// interrupt or throw (as opposed to a ":continue", ":break",
|
|
||||||
// ":return", or ":finish"), restore the pending values of
|
|
||||||
// did_emsg, got_int, and did_throw. This is skipped, if there
|
|
||||||
// was a new error, interrupt, throw, ":continue", ":break",
|
|
||||||
// ":return", or ":finish". in the finally clause.
|
|
||||||
default:
|
|
||||||
if (pending & CSTP_ERROR) {
|
|
||||||
did_emsg = true;
|
|
||||||
}
|
|
||||||
if (pending & CSTP_INTERRUPT) {
|
|
||||||
got_int = true;
|
|
||||||
}
|
|
||||||
if (pending & CSTP_THROW) {
|
|
||||||
rethrow = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (rethrow) {
|
if (rethrow) {
|
||||||
// Rethrow the current exception (within this cstack).
|
// Rethrow the current exception (within this cstack).
|
||||||
do_throw(cstack);
|
do_throw(cstack);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -743,28 +743,26 @@ void fix_help_buffer(void)
|
|||||||
// If foo.abx is found use it instead of foo.txt in
|
// If foo.abx is found use it instead of foo.txt in
|
||||||
// the same directory.
|
// the same directory.
|
||||||
for (int i1 = 0; i1 < fcount; i1++) {
|
for (int i1 = 0; i1 < fcount; i1++) {
|
||||||
for (int i2 = 0; i2 < fcount; i2++) {
|
const char *const f1 = fnames[i1];
|
||||||
if (i1 == i2) {
|
const char *const t1 = path_tail(f1);
|
||||||
continue;
|
const char *const e1 = strrchr(t1, '.');
|
||||||
}
|
if (path_fnamecmp(e1, ".txt") != 0
|
||||||
if (fnames[i1] == NULL || fnames[i2] == NULL) {
|
&& path_fnamecmp(e1, fname + 4) != 0) {
|
||||||
continue;
|
// Not .txt and not .abx, remove it.
|
||||||
}
|
XFREE_CLEAR(fnames[i1]);
|
||||||
const char *const f1 = fnames[i1];
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i2 = i1 + 1; i2 < fcount; i2++) {
|
||||||
const char *const f2 = fnames[i2];
|
const char *const f2 = fnames[i2];
|
||||||
const char *const t1 = path_tail(f1);
|
if (f2 == NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
const char *const t2 = path_tail(f2);
|
const char *const t2 = path_tail(f2);
|
||||||
const char *const e1 = strrchr(t1, '.');
|
|
||||||
const char *const e2 = strrchr(t2, '.');
|
const char *const e2 = strrchr(t2, '.');
|
||||||
if (e1 == NULL || e2 == NULL) {
|
if (e1 == NULL || e2 == NULL) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (path_fnamecmp(e1, ".txt") != 0
|
|
||||||
&& path_fnamecmp(e1, fname + 4) != 0) {
|
|
||||||
// Not .txt and not .abx, remove it.
|
|
||||||
XFREE_CLEAR(fnames[i1]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (e1 - f1 != e2 - f2
|
if (e1 - f1 != e2 - f2
|
||||||
|| path_fnamencmp(f1, f2, (size_t)(e1 - f1)) != 0) {
|
|| path_fnamencmp(f1, f2, (size_t)(e1 - f1)) != 0) {
|
||||||
continue;
|
continue;
|
||||||
@@ -943,6 +941,7 @@ static void helptags_one(char *dir, const char *ext, const char *tagfname, bool
|
|||||||
}
|
}
|
||||||
const char *const fname = files[fi] + dirlen + 1;
|
const char *const fname = files[fi] + dirlen + 1;
|
||||||
|
|
||||||
|
bool in_example = false;
|
||||||
bool firstline = true;
|
bool firstline = true;
|
||||||
while (!vim_fgets(IObuff, IOSIZE, fd) && !got_int) {
|
while (!vim_fgets(IObuff, IOSIZE, fd) && !got_int) {
|
||||||
if (firstline) {
|
if (firstline) {
|
||||||
@@ -973,6 +972,13 @@ static void helptags_one(char *dir, const char *ext, const char *tagfname, bool
|
|||||||
}
|
}
|
||||||
firstline = false;
|
firstline = false;
|
||||||
}
|
}
|
||||||
|
if (in_example) {
|
||||||
|
// skip over example; a non-white in the first column ends it
|
||||||
|
if (vim_strchr(" \t\n\r", IObuff[0])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
in_example = false;
|
||||||
|
}
|
||||||
p1 = vim_strchr((char *)IObuff, '*'); // find first '*'
|
p1 = vim_strchr((char *)IObuff, '*'); // find first '*'
|
||||||
while (p1 != NULL) {
|
while (p1 != NULL) {
|
||||||
p2 = strchr((const char *)p1 + 1, '*'); // Find second '*'.
|
p2 = strchr((const char *)p1 + 1, '*'); // Find second '*'.
|
||||||
@@ -992,7 +998,7 @@ static void helptags_one(char *dir, const char *ext, const char *tagfname, bool
|
|||||||
|| s[1] == '\0')) {
|
|| s[1] == '\0')) {
|
||||||
*p2 = '\0';
|
*p2 = '\0';
|
||||||
p1++;
|
p1++;
|
||||||
size_t s_len= (size_t)(p2 - p1) + strlen(fname) + 2;
|
size_t s_len = (size_t)(p2 - p1) + strlen(fname) + 2;
|
||||||
s = xmalloc(s_len);
|
s = xmalloc(s_len);
|
||||||
GA_APPEND(char *, &ga, s);
|
GA_APPEND(char *, &ga, s);
|
||||||
snprintf(s, s_len, "%s\t%s", p1, fname);
|
snprintf(s, s_len, "%s\t%s", p1, fname);
|
||||||
@@ -1003,6 +1009,11 @@ static void helptags_one(char *dir, const char *ext, const char *tagfname, bool
|
|||||||
}
|
}
|
||||||
p1 = p2;
|
p1 = p2;
|
||||||
}
|
}
|
||||||
|
size_t len = strlen(IObuff);
|
||||||
|
if ((len == 2 && strcmp(&IObuff[len - 2], ">\n") == 0)
|
||||||
|
|| (len >= 3 && strcmp(&IObuff[len - 3], " >\n") == 0)) {
|
||||||
|
in_example = true;
|
||||||
|
}
|
||||||
line_breakcheck();
|
line_breakcheck();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1094,8 +1094,8 @@ static bool reg_match_visual(void)
|
|||||||
colnr_T start2, end2;
|
colnr_T start2, end2;
|
||||||
colnr_T curswant;
|
colnr_T curswant;
|
||||||
|
|
||||||
// Check if the buffer is the current buffer.
|
// Check if the buffer is the current buffer and not using a string.
|
||||||
if (rex.reg_buf != curbuf || VIsual.lnum == 0) {
|
if (rex.reg_buf != curbuf || VIsual.lnum == 0 || !REG_MULTI) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -105,7 +105,7 @@ set nomore
|
|||||||
lang mess C
|
lang mess C
|
||||||
|
|
||||||
" Nvim: append runtime from build dir, which contains the generated doc/tags.
|
" Nvim: append runtime from build dir, which contains the generated doc/tags.
|
||||||
let &runtimepath .= ','.expand($BUILD_DIR).'/runtime/'
|
let &runtimepath ..= ',' .. expand($BUILD_DIR) .. '/runtime/'
|
||||||
|
|
||||||
let s:t_bold = &t_md
|
let s:t_bold = &t_md
|
||||||
let s:t_normal = &t_me
|
let s:t_normal = &t_me
|
||||||
|
@@ -2,6 +2,9 @@
|
|||||||
|
|
||||||
source shared.vim
|
source shared.vim
|
||||||
source check.vim
|
source check.vim
|
||||||
|
source term_util.vim
|
||||||
|
source screendump.vim
|
||||||
|
source vim9.vim
|
||||||
|
|
||||||
" Must be done first, since the alternate buffer must be unset.
|
" Must be done first, since the alternate buffer must be unset.
|
||||||
func Test_00_bufexists()
|
func Test_00_bufexists()
|
||||||
@@ -2518,7 +2521,7 @@ func Test_builtin_check()
|
|||||||
vim9script
|
vim9script
|
||||||
var s:trim = (x) => " " .. x
|
var s:trim = (x) => " " .. x
|
||||||
END
|
END
|
||||||
" call CheckScriptFailure(lines, 'E704:')
|
call CheckScriptFailure(lines, 'E704:')
|
||||||
|
|
||||||
call assert_fails('call extend(g:, #{foo: { -> "foo" }})', 'E704:')
|
call assert_fails('call extend(g:, #{foo: { -> "foo" }})', 'E704:')
|
||||||
let g:bar = 123
|
let g:bar = 123
|
||||||
|
@@ -1,6 +1,22 @@
|
|||||||
" Tests for :help
|
" Tests for :help
|
||||||
|
|
||||||
source check.vim
|
source check.vim
|
||||||
|
source vim9.vim
|
||||||
|
|
||||||
|
func SetUp()
|
||||||
|
let s:vimruntime = $VIMRUNTIME
|
||||||
|
let s:runtimepath = &runtimepath
|
||||||
|
" Set $VIMRUNTIME to $BUILD_DIR/runtime and remove the original $VIMRUNTIME
|
||||||
|
" path from &runtimepath so that ":h local-additions" won't pick up builtin
|
||||||
|
" help files.
|
||||||
|
let $VIMRUNTIME = expand($BUILD_DIR) .. '/runtime'
|
||||||
|
set runtimepath-=../../../runtime
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func TearDown()
|
||||||
|
let $VIMRUNTIME = s:vimruntime
|
||||||
|
let &runtimepath = s:runtimepath
|
||||||
|
endfunc
|
||||||
|
|
||||||
func Test_help_restore_snapshot()
|
func Test_help_restore_snapshot()
|
||||||
help
|
help
|
||||||
@@ -81,16 +97,42 @@ func Test_help_local_additions()
|
|||||||
call writefile(['*mydoc-ext.txt* my extended awesome doc'], 'Xruntime/doc/mydoc-ext.txt')
|
call writefile(['*mydoc-ext.txt* my extended awesome doc'], 'Xruntime/doc/mydoc-ext.txt')
|
||||||
let rtp_save = &rtp
|
let rtp_save = &rtp
|
||||||
set rtp+=./Xruntime
|
set rtp+=./Xruntime
|
||||||
help
|
help local-additions
|
||||||
1
|
let lines = getline(line(".") + 1, search("^$") - 1)
|
||||||
call search('mydoc.txt')
|
call assert_equal([
|
||||||
call assert_equal('|mydoc.txt| my awesome doc', getline('.'))
|
\ '|mydoc-ext.txt| my extended awesome doc',
|
||||||
1
|
\ '|mydoc.txt| my awesome doc'
|
||||||
call search('mydoc-ext.txt')
|
\ ], lines)
|
||||||
call assert_equal('|mydoc-ext.txt| my extended awesome doc', getline('.'))
|
call delete('Xruntime/doc/mydoc-ext.txt')
|
||||||
|
close
|
||||||
|
|
||||||
|
call mkdir('Xruntime-ja/doc', 'p')
|
||||||
|
call writefile(["local-additions\thelp.jax\t/*local-additions*"], 'Xruntime-ja/doc/tags-ja')
|
||||||
|
call writefile(['*help.txt* This is jax file', '',
|
||||||
|
\ 'LOCAL ADDITIONS: *local-additions*', ''], 'Xruntime-ja/doc/help.jax')
|
||||||
|
call writefile(['*work.txt* This is jax file'], 'Xruntime-ja/doc/work.jax')
|
||||||
|
call writefile(['*work2.txt* This is jax file'], 'Xruntime-ja/doc/work2.jax')
|
||||||
|
set rtp+=./Xruntime-ja
|
||||||
|
|
||||||
|
help local-additions@en
|
||||||
|
let lines = getline(line(".") + 1, search("^$") - 1)
|
||||||
|
call assert_equal([
|
||||||
|
\ '|mydoc.txt| my awesome doc'
|
||||||
|
\ ], lines)
|
||||||
|
close
|
||||||
|
|
||||||
|
help local-additions@ja
|
||||||
|
let lines = getline(line(".") + 1, search("^$") - 1)
|
||||||
|
call assert_equal([
|
||||||
|
\ '|mydoc.txt| my awesome doc',
|
||||||
|
\ '|help.txt| This is jax file',
|
||||||
|
\ '|work.txt| This is jax file',
|
||||||
|
\ '|work2.txt| This is jax file',
|
||||||
|
\ ], lines)
|
||||||
close
|
close
|
||||||
|
|
||||||
call delete('Xruntime', 'rf')
|
call delete('Xruntime', 'rf')
|
||||||
|
call delete('Xruntime-ja', 'rf')
|
||||||
let &rtp = rtp_save
|
let &rtp = rtp_save
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
@@ -114,6 +156,13 @@ func Test_helptag_cmd()
|
|||||||
call assert_equal(["help-tags\ttags\t1"], readfile('Xdir/tags'))
|
call assert_equal(["help-tags\ttags\t1"], readfile('Xdir/tags'))
|
||||||
call delete('Xdir/tags')
|
call delete('Xdir/tags')
|
||||||
|
|
||||||
|
" Test parsing tags
|
||||||
|
call writefile(['*tag1*', 'Example: >', ' *notag*', 'Example end: *tag2*'],
|
||||||
|
\ 'Xdir/a/doc/sample.txt')
|
||||||
|
helptags Xdir
|
||||||
|
call assert_equal(["tag1\ta/doc/sample.txt\t/*tag1*",
|
||||||
|
\ "tag2\ta/doc/sample.txt\t/*tag2*"], readfile('Xdir/tags'))
|
||||||
|
|
||||||
" Duplicate tags in the help file
|
" Duplicate tags in the help file
|
||||||
call writefile(['*tag1*', '*tag1*', '*tag2*'], 'Xdir/a/doc/sample.txt')
|
call writefile(['*tag1*', '*tag1*', '*tag2*'], 'Xdir/a/doc/sample.txt')
|
||||||
call assert_fails('helptags Xdir', 'E154:')
|
call assert_fails('helptags Xdir', 'E154:')
|
||||||
@@ -166,5 +215,15 @@ func Test_help_long_argument()
|
|||||||
endtry
|
endtry
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func Test_help_using_visual_match()
|
||||||
|
let lines =<< trim END
|
||||||
|
call setline(1, ' ')
|
||||||
|
/^
|
||||||
|
exe "normal \<C-V>\<C-V>"
|
||||||
|
h5\%V]
|
||||||
|
END
|
||||||
|
call CheckScriptFailure(lines, 'E149:')
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
|
||||||
" vim: shiftwidth=2 sts=2 expandtab
|
" vim: shiftwidth=2 sts=2 expandtab
|
||||||
|
@@ -1,17 +1,5 @@
|
|||||||
" Tests for :help! {subject}
|
" Tests for :help! {subject}
|
||||||
|
|
||||||
func SetUp()
|
|
||||||
" v:progpath is …/build/bin/nvim and we need …/build/runtime
|
|
||||||
" to be added to &rtp
|
|
||||||
let builddir = fnamemodify(exepath(v:progpath), ':h:h')
|
|
||||||
let s:rtp = &rtp
|
|
||||||
let &rtp .= printf(',%s/runtime', builddir)
|
|
||||||
endfunc
|
|
||||||
|
|
||||||
func TearDown()
|
|
||||||
let &rtp = s:rtp
|
|
||||||
endfunc
|
|
||||||
|
|
||||||
func Test_help_tagjump()
|
func Test_help_tagjump()
|
||||||
help
|
help
|
||||||
call assert_equal("help", &filetype)
|
call assert_equal("help", &filetype)
|
||||||
|
@@ -1535,7 +1535,7 @@ func Test_completefunc_callback()
|
|||||||
assert_equal([[1, ''], [0, 'three']], g:LocalCompleteFuncArgs)
|
assert_equal([[1, ''], [0, 'three']], g:LocalCompleteFuncArgs)
|
||||||
bw!
|
bw!
|
||||||
END
|
END
|
||||||
" call CheckScriptSuccess(lines)
|
call CheckScriptSuccess(lines)
|
||||||
|
|
||||||
" cleanup
|
" cleanup
|
||||||
set completefunc&
|
set completefunc&
|
||||||
@@ -1792,7 +1792,7 @@ func Test_omnifunc_callback()
|
|||||||
assert_equal([[1, ''], [0, 'three']], g:LocalOmniFuncArgs)
|
assert_equal([[1, ''], [0, 'three']], g:LocalOmniFuncArgs)
|
||||||
bw!
|
bw!
|
||||||
END
|
END
|
||||||
" call CheckScriptSuccess(lines)
|
call CheckScriptSuccess(lines)
|
||||||
|
|
||||||
" cleanup
|
" cleanup
|
||||||
set omnifunc&
|
set omnifunc&
|
||||||
@@ -2085,7 +2085,7 @@ func Test_thesaurusfunc_callback()
|
|||||||
assert_equal([[1, ''], [0, 'three']], g:LocalTsrFuncArgs)
|
assert_equal([[1, ''], [0, 'three']], g:LocalTsrFuncArgs)
|
||||||
bw!
|
bw!
|
||||||
END
|
END
|
||||||
" call CheckScriptSuccess(lines)
|
call CheckScriptSuccess(lines)
|
||||||
|
|
||||||
" cleanup
|
" cleanup
|
||||||
set thesaurusfunc&
|
set thesaurusfunc&
|
||||||
|
@@ -695,7 +695,7 @@ func Test_opfunc_callback()
|
|||||||
assert_equal(['char'], g:LocalOpFuncArgs)
|
assert_equal(['char'], g:LocalOpFuncArgs)
|
||||||
bw!
|
bw!
|
||||||
END
|
END
|
||||||
" call CheckScriptSuccess(lines)
|
call CheckScriptSuccess(lines)
|
||||||
|
|
||||||
" setting 'opfunc' to a script local function outside of a script context
|
" setting 'opfunc' to a script local function outside of a script context
|
||||||
" should fail
|
" should fail
|
||||||
|
@@ -380,7 +380,7 @@ func Test_tagfunc_callback()
|
|||||||
assert_equal(['a12', '', {}], g:LocalTagFuncArgs)
|
assert_equal(['a12', '', {}], g:LocalTagFuncArgs)
|
||||||
bw!
|
bw!
|
||||||
END
|
END
|
||||||
" call CheckScriptSuccess(lines)
|
call CheckScriptSuccess(lines)
|
||||||
|
|
||||||
" cleanup
|
" cleanup
|
||||||
delfunc TagFunc1
|
delfunc TagFunc1
|
||||||
|
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
source check.vim
|
source check.vim
|
||||||
source shared.vim
|
source shared.vim
|
||||||
|
source vim9.vim
|
||||||
|
|
||||||
"-------------------------------------------------------------------------------
|
"-------------------------------------------------------------------------------
|
||||||
" Test environment {{{1
|
" Test environment {{{1
|
||||||
@@ -2007,6 +2008,27 @@ func Test_try_catch_errors()
|
|||||||
call assert_fails('try | for i in range(5) | endif | endtry', 'E580:')
|
call assert_fails('try | for i in range(5) | endif | endtry', 'E580:')
|
||||||
call assert_fails('try | while v:true | endtry', 'E170:')
|
call assert_fails('try | while v:true | endtry', 'E170:')
|
||||||
call assert_fails('try | if v:true | endtry', 'E171:')
|
call assert_fails('try | if v:true | endtry', 'E171:')
|
||||||
|
|
||||||
|
" this was using a negative index in cstack[]
|
||||||
|
let lines =<< trim END
|
||||||
|
try
|
||||||
|
for
|
||||||
|
if
|
||||||
|
endwhile
|
||||||
|
if
|
||||||
|
finally
|
||||||
|
END
|
||||||
|
call CheckScriptFailure(lines, 'E690:')
|
||||||
|
|
||||||
|
let lines =<< trim END
|
||||||
|
try
|
||||||
|
for
|
||||||
|
if
|
||||||
|
endwhile
|
||||||
|
if
|
||||||
|
endtry
|
||||||
|
END
|
||||||
|
call CheckScriptFailure(lines, 'E690:')
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
" Test for verbose messages with :try :catch, and :finally {{{1
|
" Test for verbose messages with :try :catch, and :finally {{{1
|
||||||
|
@@ -2,6 +2,38 @@
|
|||||||
" Use a different file name for each run.
|
" Use a different file name for each run.
|
||||||
let s:sequence = 1
|
let s:sequence = 1
|
||||||
|
|
||||||
|
func CheckScriptFailure(lines, error, lnum = -3)
|
||||||
|
if get(a:lines, 0, '') ==# 'vim9script'
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
let cwd = getcwd()
|
||||||
|
let fname = 'XScriptFailure' .. s:sequence
|
||||||
|
let s:sequence += 1
|
||||||
|
call writefile(a:lines, fname)
|
||||||
|
try
|
||||||
|
call assert_fails('so ' .. fname, a:error, a:lines, a:lnum)
|
||||||
|
finally
|
||||||
|
call chdir(cwd)
|
||||||
|
call delete(fname)
|
||||||
|
endtry
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func CheckScriptSuccess(lines)
|
||||||
|
if get(a:lines, 0, '') ==# 'vim9script'
|
||||||
|
return
|
||||||
|
endif
|
||||||
|
let cwd = getcwd()
|
||||||
|
let fname = 'XScriptSuccess' .. s:sequence
|
||||||
|
let s:sequence += 1
|
||||||
|
call writefile(a:lines, fname)
|
||||||
|
try
|
||||||
|
exe 'so ' .. fname
|
||||||
|
finally
|
||||||
|
call chdir(cwd)
|
||||||
|
call delete(fname)
|
||||||
|
endtry
|
||||||
|
endfunc
|
||||||
|
|
||||||
" Check that "lines" inside a legacy function has no error.
|
" Check that "lines" inside a legacy function has no error.
|
||||||
func CheckLegacySuccess(lines)
|
func CheckLegacySuccess(lines)
|
||||||
let cwd = getcwd()
|
let cwd = getcwd()
|
||||||
|
Reference in New Issue
Block a user