mirror of
https://github.com/vim/vim.git
synced 2025-09-27 04:14:06 -04:00
patch 8.1.0228: dropping files is ignored while Vim is busy
Problem: Dropping files is ignored while Vim is busy. Solution: Postpone the effect of dropping files until it's safe.
This commit is contained in:
126
src/ex_docmd.c
126
src/ex_docmd.c
@@ -7859,57 +7859,37 @@ ex_shell(exarg_T *eap UNUSED)
|
||||
do_shell(NULL, 0);
|
||||
}
|
||||
|
||||
#if defined(HAVE_DROP_FILE) \
|
||||
|| (defined(FEAT_GUI_GTK) && defined(FEAT_DND)) \
|
||||
|| defined(FEAT_GUI_MSWIN) \
|
||||
|| defined(FEAT_GUI_MAC) \
|
||||
|| defined(PROTO)
|
||||
#if defined(HAVE_DROP_FILE) || defined(PROTO)
|
||||
|
||||
/*
|
||||
* Handle a file drop. The code is here because a drop is *nearly* like an
|
||||
* :args command, but not quite (we have a list of exact filenames, so we
|
||||
* don't want to (a) parse a command line, or (b) expand wildcards. So the
|
||||
* code is very similar to :args and hence needs access to a lot of the static
|
||||
* functions in this file.
|
||||
*
|
||||
* The list should be allocated using alloc(), as should each item in the
|
||||
* list. This function takes over responsibility for freeing the list.
|
||||
*
|
||||
* XXX The list is made into the argument list. This is freed using
|
||||
* FreeWild(), which does a series of vim_free() calls.
|
||||
*/
|
||||
void
|
||||
handle_drop(
|
||||
int filec, /* the number of files dropped */
|
||||
char_u **filev, /* the list of files dropped */
|
||||
int split) /* force splitting the window */
|
||||
static int drop_busy = FALSE;
|
||||
static int drop_filec;
|
||||
static char_u **drop_filev = NULL;
|
||||
static int drop_split;
|
||||
static void (*drop_callback)(void *);
|
||||
static void *drop_cookie;
|
||||
|
||||
static void
|
||||
handle_drop_internal(void)
|
||||
{
|
||||
exarg_T ea;
|
||||
int save_msg_scroll = msg_scroll;
|
||||
|
||||
/* Postpone this while editing the command line. */
|
||||
if (text_locked())
|
||||
return;
|
||||
if (curbuf_locked())
|
||||
return;
|
||||
|
||||
/* When the screen is being updated we should not change buffers and
|
||||
* windows structures, it may cause freed memory to be used. */
|
||||
if (updating_screen)
|
||||
return;
|
||||
// Setting the argument list may cause screen updates and being called
|
||||
// recursively. Avoid that by setting drop_busy.
|
||||
drop_busy = TRUE;
|
||||
|
||||
/* Check whether the current buffer is changed. If so, we will need
|
||||
* to split the current window or data could be lost.
|
||||
* We don't need to check if the 'hidden' option is set, as in this
|
||||
* case the buffer won't be lost.
|
||||
*/
|
||||
if (!buf_hide(curbuf) && !split)
|
||||
if (!buf_hide(curbuf) && !drop_split)
|
||||
{
|
||||
++emsg_off;
|
||||
split = check_changed(curbuf, CCGD_AW);
|
||||
drop_split = check_changed(curbuf, CCGD_AW);
|
||||
--emsg_off;
|
||||
}
|
||||
if (split)
|
||||
if (drop_split)
|
||||
{
|
||||
if (win_split(0, 0) == FAIL)
|
||||
return;
|
||||
@@ -7924,7 +7904,7 @@ handle_drop(
|
||||
/*
|
||||
* Set up the new argument list.
|
||||
*/
|
||||
alist_set(ALIST(curwin), filec, filev, FALSE, NULL, 0);
|
||||
alist_set(ALIST(curwin), drop_filec, drop_filev, FALSE, NULL, 0);
|
||||
|
||||
/*
|
||||
* Move to the first file.
|
||||
@@ -7942,6 +7922,78 @@ handle_drop(
|
||||
* unexpectedly. The screen will be redrawn by the caller, thus
|
||||
* msg_scroll being set by displaying a message is irrelevant. */
|
||||
msg_scroll = save_msg_scroll;
|
||||
|
||||
if (drop_callback != NULL)
|
||||
drop_callback(drop_cookie);
|
||||
|
||||
drop_filev = NULL;
|
||||
drop_busy = FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle a file drop. The code is here because a drop is *nearly* like an
|
||||
* :args command, but not quite (we have a list of exact filenames, so we
|
||||
* don't want to (a) parse a command line, or (b) expand wildcards. So the
|
||||
* code is very similar to :args and hence needs access to a lot of the static
|
||||
* functions in this file.
|
||||
*
|
||||
* The "filev" list must have been allocated using alloc(), as should each item
|
||||
* in the list. This function takes over responsibility for freeing the "filev"
|
||||
* list.
|
||||
*/
|
||||
void
|
||||
handle_drop(
|
||||
int filec, // the number of files dropped
|
||||
char_u **filev, // the list of files dropped
|
||||
int split, // force splitting the window
|
||||
void (*callback)(void *), // to be called after setting the argument
|
||||
// list
|
||||
void *cookie) // argument for "callback" (allocated)
|
||||
{
|
||||
// Cannot handle recursive drops, finish the pending one.
|
||||
if (drop_busy)
|
||||
{
|
||||
FreeWild(filec, filev);
|
||||
vim_free(cookie);
|
||||
return;
|
||||
}
|
||||
|
||||
// When calling handle_drop() more than once in a row we only use the last
|
||||
// one.
|
||||
if (drop_filev != NULL)
|
||||
{
|
||||
FreeWild(drop_filec, drop_filev);
|
||||
vim_free(drop_cookie);
|
||||
}
|
||||
|
||||
drop_filec = filec;
|
||||
drop_filev = filev;
|
||||
drop_split = split;
|
||||
drop_callback = callback;
|
||||
drop_cookie = cookie;
|
||||
|
||||
// Postpone this when:
|
||||
// - editing the command line
|
||||
// - not possible to change the current buffer
|
||||
// - updating the screen
|
||||
// As it may change buffers and window structures that are in use and cause
|
||||
// freed memory to be used.
|
||||
if (text_locked() || curbuf_locked() || updating_screen)
|
||||
return;
|
||||
|
||||
handle_drop_internal();
|
||||
}
|
||||
|
||||
/*
|
||||
* To be called when text is unlocked, curbuf is unlocked or updating_screen is
|
||||
* reset: Handle a postponed drop.
|
||||
*/
|
||||
void
|
||||
handle_any_postponed_drop(void)
|
||||
{
|
||||
if (!drop_busy && drop_filev != NULL
|
||||
&& !text_locked() && !curbuf_locked() && !updating_screen)
|
||||
handle_drop_internal();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
Reference in New Issue
Block a user