Skip to content

Commit 92d147b

Browse files
committed
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.
1 parent fda95e7 commit 92d147b

8 files changed

Lines changed: 202 additions & 115 deletions

File tree

src/ex_docmd.c

Lines changed: 89 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -7859,57 +7859,37 @@ ex_shell(exarg_T *eap UNUSED)
78597859
do_shell(NULL, 0);
78607860
}
78617861

7862-
#if defined(HAVE_DROP_FILE) \
7863-
|| (defined(FEAT_GUI_GTK) && defined(FEAT_DND)) \
7864-
|| defined(FEAT_GUI_MSWIN) \
7865-
|| defined(FEAT_GUI_MAC) \
7866-
|| defined(PROTO)
7862+
#if defined(HAVE_DROP_FILE) || defined(PROTO)
78677863

7868-
/*
7869-
* Handle a file drop. The code is here because a drop is *nearly* like an
7870-
* :args command, but not quite (we have a list of exact filenames, so we
7871-
* don't want to (a) parse a command line, or (b) expand wildcards. So the
7872-
* code is very similar to :args and hence needs access to a lot of the static
7873-
* functions in this file.
7874-
*
7875-
* The list should be allocated using alloc(), as should each item in the
7876-
* list. This function takes over responsibility for freeing the list.
7877-
*
7878-
* XXX The list is made into the argument list. This is freed using
7879-
* FreeWild(), which does a series of vim_free() calls.
7880-
*/
7881-
void
7882-
handle_drop(
7883-
int filec, /* the number of files dropped */
7884-
char_u **filev, /* the list of files dropped */
7885-
int split) /* force splitting the window */
7864+
static int drop_busy = FALSE;
7865+
static int drop_filec;
7866+
static char_u **drop_filev = NULL;
7867+
static int drop_split;
7868+
static void (*drop_callback)(void *);
7869+
static void *drop_cookie;
7870+
7871+
static void
7872+
handle_drop_internal(void)
78867873
{
78877874
exarg_T ea;
78887875
int save_msg_scroll = msg_scroll;
78897876

7890-
/* Postpone this while editing the command line. */
7891-
if (text_locked())
7892-
return;
7893-
if (curbuf_locked())
7894-
return;
7895-
7896-
/* When the screen is being updated we should not change buffers and
7897-
* windows structures, it may cause freed memory to be used. */
7898-
if (updating_screen)
7899-
return;
7877+
// Setting the argument list may cause screen updates and being called
7878+
// recursively. Avoid that by setting drop_busy.
7879+
drop_busy = TRUE;
79007880

79017881
/* Check whether the current buffer is changed. If so, we will need
79027882
* to split the current window or data could be lost.
79037883
* We don't need to check if the 'hidden' option is set, as in this
79047884
* case the buffer won't be lost.
79057885
*/
7906-
if (!buf_hide(curbuf) && !split)
7886+
if (!buf_hide(curbuf) && !drop_split)
79077887
{
79087888
++emsg_off;
7909-
split = check_changed(curbuf, CCGD_AW);
7889+
drop_split = check_changed(curbuf, CCGD_AW);
79107890
--emsg_off;
79117891
}
7912-
if (split)
7892+
if (drop_split)
79137893
{
79147894
if (win_split(0, 0) == FAIL)
79157895
return;
@@ -7924,7 +7904,7 @@ handle_drop(
79247904
/*
79257905
* Set up the new argument list.
79267906
*/
7927-
alist_set(ALIST(curwin), filec, filev, FALSE, NULL, 0);
7907+
alist_set(ALIST(curwin), drop_filec, drop_filev, FALSE, NULL, 0);
79287908

79297909
/*
79307910
* Move to the first file.
@@ -7942,6 +7922,78 @@ handle_drop(
79427922
* unexpectedly. The screen will be redrawn by the caller, thus
79437923
* msg_scroll being set by displaying a message is irrelevant. */
79447924
msg_scroll = save_msg_scroll;
7925+
7926+
if (drop_callback != NULL)
7927+
drop_callback(drop_cookie);
7928+
7929+
drop_filev = NULL;
7930+
drop_busy = FALSE;
7931+
}
7932+
7933+
/*
7934+
* Handle a file drop. The code is here because a drop is *nearly* like an
7935+
* :args command, but not quite (we have a list of exact filenames, so we
7936+
* don't want to (a) parse a command line, or (b) expand wildcards. So the
7937+
* code is very similar to :args and hence needs access to a lot of the static
7938+
* functions in this file.
7939+
*
7940+
* The "filev" list must have been allocated using alloc(), as should each item
7941+
* in the list. This function takes over responsibility for freeing the "filev"
7942+
* list.
7943+
*/
7944+
void
7945+
handle_drop(
7946+
int filec, // the number of files dropped
7947+
char_u **filev, // the list of files dropped
7948+
int split, // force splitting the window
7949+
void (*callback)(void *), // to be called after setting the argument
7950+
// list
7951+
void *cookie) // argument for "callback" (allocated)
7952+
{
7953+
// Cannot handle recursive drops, finish the pending one.
7954+
if (drop_busy)
7955+
{
7956+
FreeWild(filec, filev);
7957+
vim_free(cookie);
7958+
return;
7959+
}
7960+
7961+
// When calling handle_drop() more than once in a row we only use the last
7962+
// one.
7963+
if (drop_filev != NULL)
7964+
{
7965+
FreeWild(drop_filec, drop_filev);
7966+
vim_free(drop_cookie);
7967+
}
7968+
7969+
drop_filec = filec;
7970+
drop_filev = filev;
7971+
drop_split = split;
7972+
drop_callback = callback;
7973+
drop_cookie = cookie;
7974+
7975+
// Postpone this when:
7976+
// - editing the command line
7977+
// - not possible to change the current buffer
7978+
// - updating the screen
7979+
// As it may change buffers and window structures that are in use and cause
7980+
// freed memory to be used.
7981+
if (text_locked() || curbuf_locked() || updating_screen)
7982+
return;
7983+
7984+
handle_drop_internal();
7985+
}
7986+
7987+
/*
7988+
* To be called when text is unlocked, curbuf is unlocked or updating_screen is
7989+
* reset: Handle a postponed drop.
7990+
*/
7991+
void
7992+
handle_any_postponed_drop(void)
7993+
{
7994+
if (!drop_busy && drop_filev != NULL
7995+
&& !text_locked() && !curbuf_locked() && !updating_screen)
7996+
handle_drop_internal();
79457997
}
79467998
#endif
79477999

src/gui.c

Lines changed: 39 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5383,10 +5383,7 @@ gui_do_findrepl(
53835383

53845384
#endif
53855385

5386-
#if (defined(FEAT_DND) && defined(FEAT_GUI_GTK)) \
5387-
|| defined(FEAT_GUI_MSWIN) \
5388-
|| defined(FEAT_GUI_MAC) \
5389-
|| defined(PROTO)
5386+
#if defined(HAVE_DROP_FILE) || defined(PROTO)
53905387

53915388
static void gui_wingoto_xy(int x, int y);
53925389

@@ -5408,6 +5405,42 @@ gui_wingoto_xy(int x, int y)
54085405
}
54095406
}
54105407

5408+
/*
5409+
* Function passed to handle_drop() for the actions to be done after the
5410+
* argument list has been updated.
5411+
*/
5412+
static void
5413+
drop_callback(void *cookie)
5414+
{
5415+
char_u *p = cookie;
5416+
5417+
/* If Shift held down, change to first file's directory. If the first
5418+
* item is a directory, change to that directory (and let the explorer
5419+
* plugin show the contents). */
5420+
if (p != NULL)
5421+
{
5422+
if (mch_isdir(p))
5423+
{
5424+
if (mch_chdir((char *)p) == 0)
5425+
shorten_fnames(TRUE);
5426+
}
5427+
else if (vim_chdirfile(p, "drop") == OK)
5428+
shorten_fnames(TRUE);
5429+
vim_free(p);
5430+
}
5431+
5432+
/* Update the screen display */
5433+
update_screen(NOT_VALID);
5434+
# ifdef FEAT_MENU
5435+
gui_update_menus(0);
5436+
# endif
5437+
#ifdef FEAT_TITLE
5438+
maketitle();
5439+
#endif
5440+
setcursor();
5441+
out_flush_cursor(FALSE, FALSE);
5442+
}
5443+
54115444
/*
54125445
* Process file drop. Mouse cursor position, key modifiers, name of files
54135446
* and count of files are given. Argument "fnames[count]" has full pathnames
@@ -5488,33 +5521,8 @@ gui_handle_drop(
54885521
vim_free(fnames);
54895522
}
54905523
else
5491-
handle_drop(count, fnames, (modifiers & MOUSE_CTRL) != 0);
5492-
5493-
/* If Shift held down, change to first file's directory. If the first
5494-
* item is a directory, change to that directory (and let the explorer
5495-
* plugin show the contents). */
5496-
if (p != NULL)
5497-
{
5498-
if (mch_isdir(p))
5499-
{
5500-
if (mch_chdir((char *)p) == 0)
5501-
shorten_fnames(TRUE);
5502-
}
5503-
else if (vim_chdirfile(p, "drop") == OK)
5504-
shorten_fnames(TRUE);
5505-
vim_free(p);
5506-
}
5507-
5508-
/* Update the screen display */
5509-
update_screen(NOT_VALID);
5510-
# ifdef FEAT_MENU
5511-
gui_update_menus(0);
5512-
# endif
5513-
#ifdef FEAT_TITLE
5514-
maketitle();
5515-
#endif
5516-
setcursor();
5517-
out_flush_cursor(FALSE, FALSE);
5524+
handle_drop(count, fnames, (modifiers & MOUSE_CTRL) != 0,
5525+
drop_callback, (void *)p);
55185526
}
55195527

55205528
entered = FALSE;

src/gui.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,9 @@
6565
/*
6666
* GUIs that support dropping files on a running Vim.
6767
*/
68-
#if defined(FEAT_GUI_MSWIN) || defined(FEAT_GUI_MAC) \
69-
|| defined(FEAT_GUI_GTK)
68+
#if (defined(FEAT_DND) && defined(FEAT_GUI_GTK)) \
69+
|| defined(FEAT_GUI_MSWIN) \
70+
|| defined(FEAT_GUI_MAC)
7071
# define HAVE_DROP_FILE
7172
#endif
7273

src/gui_mac.c

Lines changed: 53 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,6 +1007,55 @@ struct SelectionRange /* for handling kCoreClassEvent:kOpenDocuments:keyAEPositi
10071007
long theDate; // modification date/time
10081008
};
10091009

1010+
static long drop_numFiles;
1011+
static short drop_gotPosition;
1012+
static SelectionRange drop_thePosition;
1013+
1014+
static void
1015+
drop_callback(void *cookie UNUSED)
1016+
{
1017+
/* TODO: Handle the goto/select line more cleanly */
1018+
if ((drop_numFiles == 1) & (drop_gotPosition))
1019+
{
1020+
if (drop_thePosition.lineNum >= 0)
1021+
{
1022+
lnum = drop_thePosition.lineNum + 1;
1023+
/* oap->motion_type = MLINE;
1024+
setpcmark();*/
1025+
if (lnum < 1L)
1026+
lnum = 1L;
1027+
else if (lnum > curbuf->b_ml.ml_line_count)
1028+
lnum = curbuf->b_ml.ml_line_count;
1029+
curwin->w_cursor.lnum = lnum;
1030+
curwin->w_cursor.col = 0;
1031+
/* beginline(BL_SOL | BL_FIX);*/
1032+
}
1033+
else
1034+
goto_byte(drop_thePosition.startRange + 1);
1035+
}
1036+
1037+
/* Update the screen display */
1038+
update_screen(NOT_VALID);
1039+
1040+
/* Select the text if possible */
1041+
if (drop_gotPosition)
1042+
{
1043+
VIsual_active = TRUE;
1044+
VIsual_select = FALSE;
1045+
VIsual = curwin->w_cursor;
1046+
if (drop_thePosition.lineNum < 0)
1047+
{
1048+
VIsual_mode = 'v';
1049+
goto_byte(drop_thePosition.endRange);
1050+
}
1051+
else
1052+
{
1053+
VIsual_mode = 'V';
1054+
VIsual.col = 0;
1055+
}
1056+
}
1057+
}
1058+
10101059
/* The IDE uses the optional keyAEPosition parameter to tell the ed-
10111060
itor the selection range. If lineNum is zero or greater, scroll the text
10121061
to the specified line. If lineNum is less than zero, use the values in
@@ -1113,48 +1162,10 @@ HandleODocAE(const AppleEvent *theAEvent, AppleEvent *theReply, long refCon)
11131162
}
11141163

11151164
/* Handle the drop, :edit to get to the file */
1116-
handle_drop(numFiles, fnames, FALSE);
1117-
1118-
/* TODO: Handle the goto/select line more cleanly */
1119-
if ((numFiles == 1) & (gotPosition))
1120-
{
1121-
if (thePosition.lineNum >= 0)
1122-
{
1123-
lnum = thePosition.lineNum + 1;
1124-
/* oap->motion_type = MLINE;
1125-
setpcmark();*/
1126-
if (lnum < 1L)
1127-
lnum = 1L;
1128-
else if (lnum > curbuf->b_ml.ml_line_count)
1129-
lnum = curbuf->b_ml.ml_line_count;
1130-
curwin->w_cursor.lnum = lnum;
1131-
curwin->w_cursor.col = 0;
1132-
/* beginline(BL_SOL | BL_FIX);*/
1133-
}
1134-
else
1135-
goto_byte(thePosition.startRange + 1);
1136-
}
1137-
1138-
/* Update the screen display */
1139-
update_screen(NOT_VALID);
1140-
1141-
/* Select the text if possible */
1142-
if (gotPosition)
1143-
{
1144-
VIsual_active = TRUE;
1145-
VIsual_select = FALSE;
1146-
VIsual = curwin->w_cursor;
1147-
if (thePosition.lineNum < 0)
1148-
{
1149-
VIsual_mode = 'v';
1150-
goto_byte(thePosition.endRange);
1151-
}
1152-
else
1153-
{
1154-
VIsual_mode = 'V';
1155-
VIsual.col = 0;
1156-
}
1157-
}
1165+
drop_numFiles = numFiles;
1166+
drop_gotPosition = gotPosition;
1167+
drop_thePosition = thePosition;
1168+
handle_drop(numFiles, fnames, FALSE, drop_callback, NULL);
11581169

11591170
setcursor();
11601171
out_flush();

src/main.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -911,7 +911,7 @@ vim_main2(void)
911911

912912
/*
913913
* Call the main command loop. This never returns.
914-
*/
914+
*/
915915
main_loop(FALSE, FALSE);
916916

917917
#endif /* NO_VIM_MAIN */
@@ -1155,9 +1155,15 @@ main_loop(
11551155
else if (do_redraw || stuff_empty())
11561156
{
11571157
#ifdef FEAT_GUI
1158-
/* If ui_breakcheck() was used a resize may have been postponed. */
1158+
// If ui_breakcheck() was used a resize may have been postponed.
11591159
gui_may_resize_shell();
11601160
#endif
1161+
#ifdef HAVE_DROP_FILE
1162+
// If files were dropped while text was locked or the curbuf was
1163+
// locked, this would be a good time to handle the drop.
1164+
handle_any_postponed_drop();
1165+
#endif
1166+
11611167
/* Trigger CursorMoved if the cursor moved. */
11621168
if (!finish_op && (
11631169
has_cursormoved()

0 commit comments

Comments
 (0)