File 6.3.040 of Package kvim
To: vim-dev@vim.org
Subject: Patch 6.3.040
Fcc: outbox
From: Bram Moolenaar <Bram@moolenaar.net>
Mime-Version: 1.0
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 8bit
------------
Patch 6.3.040
Problem: Error handling does not always work properly and may cause a
buffer to be marked as if it's viewed in a window while it isn't.
Also when selecting "Abort" at the attention prompt.
Solution: Add enter_cleanup() and leave_cleanup() functions to move
saving/restoring things for error handling to one place.
Clear a buffer read error when it's unloaded.
Files: src/buffer.c, src/ex_docmd.c, src/ex_eval.c,
src/proto/ex_eval.pro, src/structs.h, src/vim.h
*** ../vim-6.3.039/src/buffer.c Wed Jun 9 14:56:27 2004
--- src/buffer.c Sun Dec 5 16:15:05 2004
***************
*** 408,415 ****
if (!buf_valid(buf))
return;
# ifdef FEAT_EVAL
! /* Autocommands may abort script processing. */
! if (aborting())
return;
# endif
--- 408,414 ----
if (!buf_valid(buf))
return;
# ifdef FEAT_EVAL
! if (aborting()) /* autocmds may abort script processing */
return;
# endif
***************
*** 564,569 ****
--- 563,569 ----
#ifdef FEAT_SYN_HL
syntax_clear(buf); /* reset syntax info */
#endif
+ buf->b_flags &= ~BF_READERR; /* a read error is no longer relevant */
}
/*
***************
*** 666,674 ****
--- 666,688 ----
&& (defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG))
if (swap_exists_action == SEA_QUIT && *eap->cmd == 's')
{
+ # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
+ cleanup_T cs;
+
+ /* Reset the error/interrupt/exception state here so that
+ * aborting() returns FALSE when closing a window. */
+ enter_cleanup(&cs);
+ # endif
+
/* Quitting means closing the split window, nothing else. */
win_close(curwin, TRUE);
swap_exists_action = SEA_NONE;
+
+ # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
+ /* Restore the error/interrupt/exception state if not discarded by a
+ * new aborting error, interrupt, or uncaught exception. */
+ leave_cleanup(&cs);
+ # endif
}
else
handle_swap_exists(old_curbuf);
***************
*** 685,712 ****
handle_swap_exists(old_curbuf)
buf_T *old_curbuf;
{
if (swap_exists_action == SEA_QUIT)
{
/* User selected Quit at ATTENTION prompt. Go back to previous
* buffer. If that buffer is gone or the same as the current one,
* open a new, empty buffer. */
swap_exists_action = SEA_NONE; /* don't want it again */
close_buffer(curwin, curbuf, DOBUF_UNLOAD);
if (!buf_valid(old_curbuf) || old_curbuf == curbuf)
! old_curbuf = buflist_new(NULL, NULL, 1L,
! BLN_CURBUF | BLN_LISTED | BLN_FORCE);
if (old_curbuf != NULL)
enter_buffer(old_curbuf);
/* If "old_curbuf" is NULL we are in big trouble here... */
}
else if (swap_exists_action == SEA_RECOVER)
{
/* User selected Recover at ATTENTION prompt. */
msg_scroll = TRUE;
ml_recover();
MSG_PUTS("\n"); /* don't overwrite the last message */
cmdline_row = msg_row;
do_modelines();
}
swap_exists_action = SEA_NONE;
}
--- 699,753 ----
handle_swap_exists(old_curbuf)
buf_T *old_curbuf;
{
+ # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
+ cleanup_T cs;
+ # endif
+
if (swap_exists_action == SEA_QUIT)
{
+ # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
+ /* Reset the error/interrupt/exception state here so that
+ * aborting() returns FALSE when closing a buffer. */
+ enter_cleanup(&cs);
+ # endif
+
/* User selected Quit at ATTENTION prompt. Go back to previous
* buffer. If that buffer is gone or the same as the current one,
* open a new, empty buffer. */
swap_exists_action = SEA_NONE; /* don't want it again */
close_buffer(curwin, curbuf, DOBUF_UNLOAD);
if (!buf_valid(old_curbuf) || old_curbuf == curbuf)
! old_curbuf = buflist_new(NULL, NULL, 1L, BLN_CURBUF | BLN_LISTED);
if (old_curbuf != NULL)
enter_buffer(old_curbuf);
/* If "old_curbuf" is NULL we are in big trouble here... */
+
+ # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
+ /* Restore the error/interrupt/exception state if not discarded by a
+ * new aborting error, interrupt, or uncaught exception. */
+ leave_cleanup(&cs);
+ # endif
}
else if (swap_exists_action == SEA_RECOVER)
{
+ # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
+ /* Reset the error/interrupt/exception state here so that
+ * aborting() returns FALSE when closing a buffer. */
+ enter_cleanup(&cs);
+ # endif
+
/* User selected Recover at ATTENTION prompt. */
msg_scroll = TRUE;
ml_recover();
MSG_PUTS("\n"); /* don't overwrite the last message */
cmdline_row = msg_row;
do_modelines();
+
+ # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
+ /* Restore the error/interrupt/exception state if not discarded by a
+ * new aborting error, interrupt, or uncaught exception. */
+ leave_cleanup(&cs);
+ # endif
}
swap_exists_action = SEA_NONE;
}
***************
*** 1380,1386 ****
* If (flags & BLN_CURBUF) is TRUE, may use current buffer.
* If (flags & BLN_LISTED) is TRUE, add new buffer to buffer list.
* If (flags & BLN_DUMMY) is TRUE, don't count it as a real buffer.
- * If (flags & BLN_FORCE) is TRUE, don't abort on an error.
* This is the ONLY way to create a new buffer.
*/
static int top_file_num = 1; /* highest file number */
--- 1421,1426 ----
***************
*** 1455,1462 ****
if (buf == curbuf)
apply_autocmds(EVENT_BUFWIPEOUT, NULL, NULL, FALSE, curbuf);
# ifdef FEAT_EVAL
! /* autocmds may abort script processing */
! if (!(flags & BLN_FORCE) && aborting())
return NULL;
# endif
#endif
--- 1495,1501 ----
if (buf == curbuf)
apply_autocmds(EVENT_BUFWIPEOUT, NULL, NULL, FALSE, curbuf);
# ifdef FEAT_EVAL
! if (aborting()) /* autocmds may abort script processing */
return NULL;
# endif
#endif
***************
*** 1509,1516 ****
if (buf != curbuf) /* autocommands deleted the buffer! */
return NULL;
#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
! /* autocmds may abort script processing */
! if (!(flags & BLN_FORCE) && aborting())
return NULL;
#endif
/* buf->b_nwindows = 0; why was this here? */
--- 1548,1554 ----
if (buf != curbuf) /* autocommands deleted the buffer! */
return NULL;
#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
! if (aborting()) /* autocmds may abort script processing */
return NULL;
#endif
/* buf->b_nwindows = 0; why was this here? */
***************
*** 1586,1593 ****
if (flags & BLN_LISTED)
apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, buf);
# ifdef FEAT_EVAL
! /* autocmds may abort script processing */
! if (!(flags & BLN_FORCE) && aborting())
return NULL;
# endif
}
--- 1624,1630 ----
if (flags & BLN_LISTED)
apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, buf);
# ifdef FEAT_EVAL
! if (aborting()) /* autocmds may abort script processing */
return NULL;
# endif
}
***************
*** 4217,4229 ****
#endif
set_curbuf(buf, DOBUF_GOTO);
#ifdef FEAT_AUTOCMD
- # ifdef FEAT_EVAL
- /* Autocommands deleted the buffer or aborted script
- * processing!!! */
- if (!buf_valid(buf) || aborting())
- # else
if (!buf_valid(buf)) /* autocommands deleted the buffer!!! */
- # endif
{
#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
swap_exists_action = SEA_NONE;
--- 4254,4260 ----
***************
*** 4234,4243 ****
--- 4265,4289 ----
#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
if (swap_exists_action == SEA_QUIT)
{
+ # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
+ cleanup_T cs;
+
+ /* Reset the error/interrupt/exception state here so that
+ * aborting() returns FALSE when closing a window. */
+ enter_cleanup(&cs);
+ # endif
+
/* User selected Quit at ATTENTION prompt; close this window. */
win_close(curwin, TRUE);
--open_wins;
swap_exists_action = SEA_NONE;
+
+ # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
+ /* Restore the error/interrupt/exception state if not
+ * discarded by a new aborting error, interrupt, or uncaught
+ * exception. */
+ leave_cleanup(&cs);
+ # endif
}
else
handle_swap_exists(NULL);
***************
*** 4250,4255 ****
--- 4296,4306 ----
(void)vgetc(); /* only break the file loading, not the rest */
break;
}
+ #ifdef FEAT_EVAL
+ /* Autocommands deleted the buffer or aborted script processing!!! */
+ if (aborting())
+ break;
+ #endif
}
#ifdef FEAT_AUTOCMD
--autocmd_no_enter;
*** ../vim-6.3.039/src/ex_docmd.c Wed Jun 9 14:59:11 2004
--- src/ex_docmd.c Sun Dec 5 15:24:08 2004
***************
*** 6610,6619 ****
--- 6610,6633 ----
need_hide = (curbufIsChanged() && curbuf->b_nwindows <= 1);
if (!need_hide || P_HID(curbuf))
{
+ # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
+ cleanup_T cs;
+
+ /* Reset the error/interrupt/exception state here so that
+ * aborting() returns FALSE when closing a window. */
+ enter_cleanup(&cs);
+ # endif
# ifdef FEAT_GUI
need_mouse_correct = TRUE;
# endif
win_close(curwin, !need_hide && !P_HID(curbuf));
+
+ # if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
+ /* Restore the error/interrupt/exception state if not
+ * discarded by a new aborting error, interrupt, or
+ * uncaught exception. */
+ leave_cleanup(&cs);
+ # endif
}
}
#endif
*** ../vim-6.3.039/src/ex_eval.c Wed Jun 9 14:56:26 2004
--- src/ex_eval.c Sun Dec 5 15:25:04 2004
***************
*** 1820,1825 ****
--- 1820,1979 ----
}
/*
+ * enter_cleanup() and leave_cleanup()
+ *
+ * Functions to be called before/after invoking a sequence of autocommands for
+ * cleanup for a failed command. (Failure means here that a call to emsg()
+ * has been made, an interrupt occurred, or there is an uncaught exception
+ * from a previous autocommand execution of the same command.)
+ *
+ * Call enter_cleanup() with a pointer to a cleanup_T and pass the same
+ * pointer to leave_cleanup(). The cleanup_T structure stores the pending
+ * error/interrupt/exception state.
+ */
+
+ /*
+ * This function works a bit like ex_finally() except that there was not
+ * actually an extra try block around the part that failed and an error or
+ * interrupt has not (yet) been converted to an exception. This function
+ * saves the error/interrupt/ exception state and prepares for the call to
+ * do_cmdline() that is going to be made for the cleanup autocommand
+ * execution.
+ */
+ void
+ enter_cleanup(csp)
+ cleanup_T *csp;
+ {
+ int pending = CSTP_NONE;
+
+ /*
+ * Postpone did_emsg, got_int, did_throw. The pending values will be
+ * restored by leave_cleanup() except if there was an aborting error,
+ * interrupt, or uncaught exception after this function ends.
+ */
+ if (did_emsg || got_int || did_throw || need_rethrow)
+ {
+ csp->pending = (did_emsg ? CSTP_ERROR : 0)
+ | (got_int ? CSTP_INTERRUPT : 0)
+ | (did_throw ? CSTP_THROW : 0)
+ | (need_rethrow ? CSTP_THROW : 0);
+
+ /* If we are currently throwing an exception (did_throw), save it as
+ * well. On an error not yet converted to an exception, update
+ * "force_abort" and reset "cause_abort" (as do_errthrow() would do).
+ * This is needed for the do_cmdline() call that is going to be made
+ * for autocommand execution. We need not save *msg_list because
+ * there is an extra instance for every call of do_cmdline(), anyway.
+ */
+ if (did_throw || need_rethrow)
+ csp->exception = current_exception;
+ else
+ {
+ csp->exception = NULL;
+ if (did_emsg)
+ {
+ force_abort |= cause_abort;
+ cause_abort = FALSE;
+ }
+ }
+ did_emsg = got_int = did_throw = need_rethrow = FALSE;
+
+ /* Report if required by the 'verbose' option or when debugging. */
+ report_make_pending(pending, csp->exception);
+ }
+ else
+ {
+ csp->pending = CSTP_NONE;
+ csp->exception = NULL;
+ }
+ }
+
+ /*
+ * See comment above enter_cleanup() for how this function is used.
+ *
+ * This function is a bit like ex_endtry() except that there was not actually
+ * an extra try block around the part that failed and an error or interrupt
+ * had not (yet) been converted to an exception when the cleanup autocommand
+ * sequence was invoked.
+ *
+ * This function has to be called with the address of the cleanup_T structure
+ * filled by enter_cleanup() as an argument; it restores the error/interrupt/
+ * exception state saved by that function - except there was an aborting
+ * error, an interrupt or an uncaught exception during execution of the
+ * cleanup autocommands. In the latter case, the saved error/interrupt/
+ * exception state is discarded.
+ */
+ void
+ leave_cleanup(csp)
+ cleanup_T *csp;
+ {
+ int pending = csp->pending;
+
+ if (pending == CSTP_NONE) /* nothing to do */
+ return;
+
+ /* If there was an aborting error, an interrupt, or an uncaught exception
+ * after the corresponding call to enter_cleanup(), discard what has been
+ * made pending by it. Report this to the user if required by the
+ * 'verbose' option or when debugging. */
+ if (aborting() || need_rethrow)
+ {
+ if (pending & CSTP_THROW)
+ /* Cancel the pending exception (includes report). */
+ discard_exception((except_T *)csp->exception, FALSE);
+ else
+ report_discard_pending(pending, NULL);
+
+ /* If an error was about to be converted to an exception when
+ * enter_cleanup() was called, free the message list. */
+ free_msglist(*msg_list);
+ *msg_list = NULL;
+ }
+
+ /*
+ * If there was no new error, interrupt, or throw between the calls
+ * to enter_cleanup() and leave_cleanup(), restore the pending
+ * error/interrupt/exception state.
+ */
+ else
+ {
+ /*
+ * If there was an exception being thrown when enter_cleanup() was
+ * called, we need to rethrow it. Make it the exception currently
+ * being thrown.
+ */
+ if (pending & CSTP_THROW)
+ current_exception = csp->exception;
+
+ /*
+ * If an error was about to be converted to an exception when
+ * enter_cleanup() was called, let "cause_abort" take the part of
+ * "force_abort" (as done by cause_errthrow()).
+ */
+ else if (pending & CSTP_ERROR)
+ {
+ cause_abort = force_abort;
+ force_abort = FALSE;
+ }
+
+ /*
+ * Restore the pending values of did_emsg, got_int, and did_throw.
+ */
+ if (pending & CSTP_ERROR)
+ did_emsg = TRUE;
+ if (pending & CSTP_INTERRUPT)
+ got_int = TRUE;
+ if (pending & CSTP_THROW)
+ need_rethrow = TRUE; /* did_throw will be set by do_one_cmd() */
+
+ /* Report if required by the 'verbose' option or when debugging. */
+ report_resume_pending(pending,
+ (pending & CSTP_THROW) ? (void *)current_exception : NULL);
+ }
+ }
+
+
+ /*
* Make conditionals inactive and discard what's pending in finally clauses
* until the conditional type searched for or a try conditional not in its
* finally clause is reached. If this is in an active catch clause, finish the
*** ../vim-6.3.039/src/proto/ex_eval.pro Wed Jun 9 14:56:24 2004
--- src/proto/ex_eval.pro Sun Dec 5 15:25:27 2004
***************
*** 23,28 ****
--- 23,30 ----
void ex_catch __ARGS((exarg_T *eap));
void ex_finally __ARGS((exarg_T *eap));
void ex_endtry __ARGS((exarg_T *eap));
+ void enter_cleanup __ARGS((cleanup_T *csp));
+ void leave_cleanup __ARGS((cleanup_T *csp));
int cleanup_conditionals __ARGS((struct condstack *cstack, int searched_cond, int inclusive));
void ex_endfunction __ARGS((exarg_T *eap));
int has_while_cmd __ARGS((char_u *p));
*** ../vim-6.3.039/src/structs.h Sat Sep 18 20:28:07 2004
--- src/structs.h Sun Dec 5 15:26:11 2004
***************
*** 665,670 ****
--- 665,681 ----
#define ET_ERROR 1 /* error exception */
#define ET_INTERRUPT 2 /* interrupt exception triggered by Ctrl-C */
+ /*
+ * Structure to save the error/interrupt/exception state between calls to
+ * enter_cleanup() and leave_cleanup(). Must be allocated as an automatic
+ * variable by the (common) caller of these functions.
+ */
+ typedef struct cleanup_stuff cleanup_T;
+ struct cleanup_stuff
+ {
+ int pending; /* error/interrupt/exception state */
+ except_T *exception; /* exception value */
+ };
#ifdef FEAT_SYN_HL
/* struct passed to in_id_list() */
*** ../vim-6.3.039/src/vim.h Sat Sep 4 19:43:59 2004
--- src/vim.h Sun Dec 5 15:26:56 2004
***************
*** 714,720 ****
#define BLN_CURBUF 1 /* May re-use curbuf for new buffer */
#define BLN_LISTED 2 /* Put new buffer in buffer list */
#define BLN_DUMMY 4 /* Allocating dummy buffer */
- #define BLN_FORCE 8 /* Don't abort on error */
/* Values for in_cinkeys() */
#define KEY_OPEN_FORW 0x101
--- 714,719 ----
*** ../vim-6.3.039/src/version.c Sun Dec 5 14:57:15 2004
--- src/version.c Sun Dec 5 16:16:22 2004
***************
*** 643,644 ****
--- 643,646 ----
{ /* Add new patch number below this line */
+ /**/
+ 40,
/**/
--
If your company is not involved in something called "ISO 9000" you probably
have no idea what it is. If your company _is_ involved in ISO 9000 then you
definitely have no idea what it is.
(Scott Adams - The Dilbert principle)
/// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\
/// Sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ Project leader for A-A-P -- http://www.A-A-P.org ///
\\\ Buy LOTR 3 and help AIDS victims -- http://ICCF.nl/lotr.html ///