diff options
author | Bram Moolenaar <Bram@vim.org> | 2018-07-29 17:35:23 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2018-07-29 17:35:23 +0200 |
commit | 92d147be959e689f8f58fd5d138a31835e160289 (patch) | |
tree | 5ba25e99d246153860ba91d9fc7629b67801d993 /src/ex_docmd.c | |
parent | fda95e75721fb221495c69e493ec2761b5d85123 (diff) | |
download | vim-git-92d147be959e689f8f58fd5d138a31835e160289.tar.gz |
patch 8.1.0228: dropping files is ignored while Vim is busyv8.1.0228
Problem: Dropping files is ignored while Vim is busy.
Solution: Postpone the effect of dropping files until it's safe.
Diffstat (limited to 'src/ex_docmd.c')
-rw-r--r-- | src/ex_docmd.c | 126 |
1 files changed, 89 insertions, 37 deletions
diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 54fb6aba1..668228621 100644 --- a/src/ex_docmd.c +++ b/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 |