Patch 8.1.0228
Problem: Dropping files is ignored while Vim is busy.
Solution: Postpone the effect of dropping files until it's safe.
Files: src/ex_docmd.c, src/proto/ex_docmd.pro, src/gui.c, src/gui.h,
src/screen.c, src/main.c, src/gui_mac.c
*** ../vim-8.1.0227/src/ex_docmd.c 2018-07-28 17:07:48.608154066 +0200
--- src/ex_docmd.c 2018-07-29 17:22:20.940320176 +0200
***************
*** 7859,7915 ****
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)
! /*
! * 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 */
{
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;
/* 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)
{
++emsg_off;
! split = check_changed(curbuf, CCGD_AW);
--emsg_off;
}
! if (split)
{
if (win_split(0, 0) == FAIL)
return;
--- 7859,7895 ----
do_shell(NULL, 0);
}
! #if defined(HAVE_DROP_FILE) || defined(PROTO)
! 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;
! // 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) && !drop_split)
{
++emsg_off;
! drop_split = check_changed(curbuf, CCGD_AW);
--emsg_off;
}
! if (drop_split)
{
if (win_split(0, 0) == FAIL)
return;
***************
*** 7924,7930 ****
/*
* Set up the new argument list.
*/
! alist_set(ALIST(curwin), filec, filev, FALSE, NULL, 0);
/*
* Move to the first file.
--- 7904,7910 ----
/*
* Set up the new argument list.
*/
! alist_set(ALIST(curwin), drop_filec, drop_filev, FALSE, NULL, 0);
/*
* Move to the first file.
***************
*** 7942,7947 ****
--- 7922,7999 ----
* 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
*** ../vim-8.1.0227/src/proto/ex_docmd.pro 2018-05-17 13:52:34.000000000
+0200
--- src/proto/ex_docmd.pro 2018-07-29 16:58:19.612440949 +0200
***************
*** 31,37 ****
void tabpage_close(int forceit);
void tabpage_close_other(tabpage_T *tp, int forceit);
void ex_all(exarg_T *eap);
! void handle_drop(int filec, char_u **filev, int split);
void alist_clear(alist_T *al);
void alist_init(alist_T *al);
void alist_unlink(alist_T *al);
--- 31,38 ----
void tabpage_close(int forceit);
void tabpage_close_other(tabpage_T *tp, int forceit);
void ex_all(exarg_T *eap);
! void handle_drop(int filec, char_u **filev, int split, void (*callback)(void
*), void *cookie);
! void handle_any_postponed_drop(void);
void alist_clear(alist_T *al);
void alist_init(alist_T *al);
void alist_unlink(alist_T *al);
*** ../vim-8.1.0227/src/gui.c 2018-07-29 16:09:14.636945607 +0200
--- src/gui.c 2018-07-29 16:52:45.218249227 +0200
***************
*** 5383,5392 ****
#endif
! #if (defined(FEAT_DND) && defined(FEAT_GUI_GTK)) \
! || defined(FEAT_GUI_MSWIN) \
! || defined(FEAT_GUI_MAC) \
! || defined(PROTO)
static void gui_wingoto_xy(int x, int y);
--- 5383,5389 ----
#endif
! #if defined(HAVE_DROP_FILE) || defined(PROTO)
static void gui_wingoto_xy(int x, int y);
***************
*** 5409,5414 ****
--- 5406,5447 ----
}
/*
+ * Function passed to handle_drop() for the actions to be done after the
+ * argument list has been updated.
+ */
+ static void
+ drop_callback(void *cookie)
+ {
+ char_u *p = cookie;
+
+ /* If Shift held down, change to first file's directory. If the first
+ * item is a directory, change to that directory (and let the explorer
+ * plugin show the contents). */
+ if (p != NULL)
+ {
+ if (mch_isdir(p))
+ {
+ if (mch_chdir((char *)p) == 0)
+ shorten_fnames(TRUE);
+ }
+ else if (vim_chdirfile(p, "drop") == OK)
+ shorten_fnames(TRUE);
+ vim_free(p);
+ }
+
+ /* Update the screen display */
+ update_screen(NOT_VALID);
+ # ifdef FEAT_MENU
+ gui_update_menus(0);
+ # endif
+ #ifdef FEAT_TITLE
+ maketitle();
+ #endif
+ setcursor();
+ out_flush_cursor(FALSE, FALSE);
+ }
+
+ /*
* Process file drop. Mouse cursor position, key modifiers, name of files
* and count of files are given. Argument "fnames[count]" has full pathnames
* of dropped files, they will be freed in this function, and caller can't use
***************
*** 5488,5520 ****
vim_free(fnames);
}
else
! handle_drop(count, fnames, (modifiers & MOUSE_CTRL) != 0);
!
! /* If Shift held down, change to first file's directory. If the first
! * item is a directory, change to that directory (and let the explorer
! * plugin show the contents). */
! if (p != NULL)
! {
! if (mch_isdir(p))
! {
! if (mch_chdir((char *)p) == 0)
! shorten_fnames(TRUE);
! }
! else if (vim_chdirfile(p, "drop") == OK)
! shorten_fnames(TRUE);
! vim_free(p);
! }
!
! /* Update the screen display */
! update_screen(NOT_VALID);
! # ifdef FEAT_MENU
! gui_update_menus(0);
! # endif
! #ifdef FEAT_TITLE
! maketitle();
! #endif
! setcursor();
! out_flush_cursor(FALSE, FALSE);
}
entered = FALSE;
--- 5521,5528 ----
vim_free(fnames);
}
else
! handle_drop(count, fnames, (modifiers & MOUSE_CTRL) != 0,
! drop_callback, (void *)p);
}
entered = FALSE;
*** ../vim-8.1.0227/src/gui.h 2018-05-05 18:42:37.000000000 +0200
--- src/gui.h 2018-07-29 16:52:19.418385701 +0200
***************
*** 65,72 ****
/*
* GUIs that support dropping files on a running Vim.
*/
! #if defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_MAC) \
! || defined(FEAT_GUI_GTK)
# define HAVE_DROP_FILE
#endif
--- 65,73 ----
/*
* GUIs that support dropping files on a running Vim.
*/
! #if (defined(FEAT_DND) && defined(FEAT_GUI_GTK)) \
! || defined(FEAT_GUI_MSWIN) \
! || defined(FEAT_GUI_MAC)
# define HAVE_DROP_FILE
#endif
*** ../vim-8.1.0227/src/screen.c 2018-07-29 16:09:14.644945560 +0200
--- src/screen.c 2018-07-29 16:51:41.606584708 +0200
***************
*** 526,531 ****
--- 526,537 ----
#ifdef FEAT_TERMINAL
term_check_channel_closed_recently();
#endif
+
+ #ifdef HAVE_DROP_FILE
+ // If handle_drop() was called while updating_screen was TRUE need to
+ // handle the drop now.
+ handle_any_postponed_drop();
+ #endif
}
/*
*** ../vim-8.1.0227/src/main.c 2018-06-23 16:12:15.784258242 +0200
--- src/main.c 2018-07-29 17:02:36.091020303 +0200
***************
*** 911,917 ****
/*
* Call the main command loop. This never returns.
! */
main_loop(FALSE, FALSE);
#endif /* NO_VIM_MAIN */
--- 911,917 ----
/*
* Call the main command loop. This never returns.
! */
main_loop(FALSE, FALSE);
#endif /* NO_VIM_MAIN */
***************
*** 1155,1163 ****
else if (do_redraw || stuff_empty())
{
#ifdef FEAT_GUI
! /* If ui_breakcheck() was used a resize may have been postponed. */
gui_may_resize_shell();
#endif
/* Trigger CursorMoved if the cursor moved. */
if (!finish_op && (
has_cursormoved()
--- 1155,1169 ----
else if (do_redraw || stuff_empty())
{
#ifdef FEAT_GUI
! // If ui_breakcheck() was used a resize may have been postponed.
gui_may_resize_shell();
#endif
+ #ifdef HAVE_DROP_FILE
+ // If files were dropped while text was locked or the curbuf was
+ // locked, this would be a good time to handle the drop.
+ handle_any_postponed_drop();
+ #endif
+
/* Trigger CursorMoved if the cursor moved. */
if (!finish_op && (
has_cursormoved()
*** ../vim-8.1.0227/src/gui_mac.c 2018-03-06 18:53:06.000000000 +0100
--- src/gui_mac.c 2018-07-29 17:33:07.670760672 +0200
***************
*** 1007,1012 ****
--- 1007,1061 ----
long theDate; // modification date/time
};
+ static long drop_numFiles;
+ static short drop_gotPosition;
+ static SelectionRange drop_thePosition;
+
+ static void
+ drop_callback(void *cookie UNUSED)
+ {
+ /* TODO: Handle the goto/select line more cleanly */
+ if ((drop_numFiles == 1) & (drop_gotPosition))
+ {
+ if (drop_thePosition.lineNum >= 0)
+ {
+ lnum = drop_thePosition.lineNum + 1;
+ /* oap->motion_type = MLINE;
+ setpcmark();*/
+ if (lnum < 1L)
+ lnum = 1L;
+ else if (lnum > curbuf->b_ml.ml_line_count)
+ lnum = curbuf->b_ml.ml_line_count;
+ curwin->w_cursor.lnum = lnum;
+ curwin->w_cursor.col = 0;
+ /* beginline(BL_SOL | BL_FIX);*/
+ }
+ else
+ goto_byte(drop_thePosition.startRange + 1);
+ }
+
+ /* Update the screen display */
+ update_screen(NOT_VALID);
+
+ /* Select the text if possible */
+ if (drop_gotPosition)
+ {
+ VIsual_active = TRUE;
+ VIsual_select = FALSE;
+ VIsual = curwin->w_cursor;
+ if (drop_thePosition.lineNum < 0)
+ {
+ VIsual_mode = 'v';
+ goto_byte(drop_thePosition.endRange);
+ }
+ else
+ {
+ VIsual_mode = 'V';
+ VIsual.col = 0;
+ }
+ }
+ }
+
/* The IDE uses the optional keyAEPosition parameter to tell the ed-
itor the selection range. If lineNum is zero or greater, scroll the text
to the specified line. If lineNum is less than zero, use the values in
***************
*** 1113,1160 ****
}
/* Handle the drop, :edit to get to the file */
! handle_drop(numFiles, fnames, FALSE);
!
! /* TODO: Handle the goto/select line more cleanly */
! if ((numFiles == 1) & (gotPosition))
! {
! if (thePosition.lineNum >= 0)
! {
! lnum = thePosition.lineNum + 1;
! /* oap->motion_type = MLINE;
! setpcmark();*/
! if (lnum < 1L)
! lnum = 1L;
! else if (lnum > curbuf->b_ml.ml_line_count)
! lnum = curbuf->b_ml.ml_line_count;
! curwin->w_cursor.lnum = lnum;
! curwin->w_cursor.col = 0;
! /* beginline(BL_SOL | BL_FIX);*/
! }
! else
! goto_byte(thePosition.startRange + 1);
! }
!
! /* Update the screen display */
! update_screen(NOT_VALID);
!
! /* Select the text if possible */
! if (gotPosition)
! {
! VIsual_active = TRUE;
! VIsual_select = FALSE;
! VIsual = curwin->w_cursor;
! if (thePosition.lineNum < 0)
! {
! VIsual_mode = 'v';
! goto_byte(thePosition.endRange);
! }
! else
! {
! VIsual_mode = 'V';
! VIsual.col = 0;
! }
! }
setcursor();
out_flush();
--- 1162,1171 ----
}
/* Handle the drop, :edit to get to the file */
! drop_numFiles = numFiles;
! drop_gotPosition = gotPosition;
! drop_thePosition = thePosition;
! handle_drop(numFiles, fnames, FALSE, drop_callback, NULL);
setcursor();
out_flush();
*** ../vim-8.1.0227/src/version.c 2018-07-29 16:13:13.431551849 +0200
--- src/version.c 2018-07-29 16:44:55.344870301 +0200
***************
*** 796,797 ****
--- 796,799 ----
{ /* Add new patch number below this line */
+ /**/
+ 228,
/**/
--
We do not stumble over mountains, but over molehills.
Confucius
/// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.