diff options
author | Bram Moolenaar <Bram@vim.org> | 2019-09-15 23:02:04 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2019-09-15 23:02:04 +0200 |
commit | 8aeec40207b5adcd3a155277dc4f29189343b963 (patch) | |
tree | 4c62d41b6474eaddb0d2ad4c088bb6931b39b9ce /src | |
parent | ea8dcf8346f488786023fd03ec1c013cda243040 (diff) | |
download | vim-git-8aeec40207b5adcd3a155277dc4f29189343b963.tar.gz |
patch 8.1.2044: no easy way to process postponed workv8.1.2044
Problem: No easy way to process postponed work. (Paul Jolly)
Solution: Add the SafeState autocommand event.
Diffstat (limited to 'src')
-rw-r--r-- | src/autocmd.c | 1 | ||||
-rw-r--r-- | src/channel.c | 33 | ||||
-rw-r--r-- | src/edit.c | 5 | ||||
-rw-r--r-- | src/ex_getln.c | 3 | ||||
-rw-r--r-- | src/main.c | 65 | ||||
-rw-r--r-- | src/proto/main.pro | 3 | ||||
-rw-r--r-- | src/version.c | 2 | ||||
-rw-r--r-- | src/vim.h | 1 |
8 files changed, 102 insertions, 11 deletions
diff --git a/src/autocmd.c b/src/autocmd.c index 8a6896bae..fb6c84491 100644 --- a/src/autocmd.c +++ b/src/autocmd.c @@ -155,6 +155,7 @@ static struct event_name {"QuickFixCmdPre", EVENT_QUICKFIXCMDPRE}, {"QuitPre", EVENT_QUITPRE}, {"RemoteReply", EVENT_REMOTEREPLY}, + {"SafeState", EVENT_SAFESTATE}, {"SessionLoadPost", EVENT_SESSIONLOADPOST}, {"ShellCmdPost", EVENT_SHELLCMDPOST}, {"ShellFilterPost", EVENT_SHELLFILTERPOST}, diff --git a/src/channel.c b/src/channel.c index e4dbcf603..3792b354b 100644 --- a/src/channel.c +++ b/src/channel.c @@ -3589,10 +3589,17 @@ channel_read_json_block( sock_T fd; int timeout; chanpart_T *chanpart = &channel->ch_part[part]; + int retval = FAIL; ch_log(channel, "Blocking read JSON for id %d", id); + + // Not considered a safe state here, since we are processing a JSON message + // and parsing other messages while waiting. + enter_unsafe_state(); + if (id >= 0) channel_add_block_id(chanpart, id); + for (;;) { more = channel_parse_json(channel, part); @@ -3600,10 +3607,9 @@ channel_read_json_block( // search for message "id" if (channel_get_json(channel, part, id, TRUE, rettv) == OK) { - if (id >= 0) - channel_remove_block_id(chanpart, id); ch_log(channel, "Received JSON for id %d", id); - return OK; + retval = OK; + break; } if (!more) @@ -3659,7 +3665,11 @@ channel_read_json_block( } if (id >= 0) channel_remove_block_id(chanpart, id); - return FAIL; + + // This may trigger a SafeState autocommand. + leave_unsafe_state(); + + return retval; } /* @@ -4195,9 +4205,9 @@ ch_raw_common(typval_T *argvars, typval_T *rettv, int eval) free_job_options(&opt); } -# define KEEP_OPEN_TIME 20 /* msec */ +#define KEEP_OPEN_TIME 20 /* msec */ -# if (defined(UNIX) && !defined(HAVE_SELECT)) || defined(PROTO) +#if (defined(UNIX) && !defined(HAVE_SELECT)) || defined(PROTO) /* * Add open channels to the poll struct. * Return the adjusted struct index. @@ -4288,9 +4298,9 @@ channel_poll_check(int ret_in, void *fds_in) return ret; } -# endif /* UNIX && !HAVE_SELECT */ +#endif /* UNIX && !HAVE_SELECT */ -# if (!defined(MSWIN) && defined(HAVE_SELECT)) || defined(PROTO) +#if (!defined(MSWIN) && defined(HAVE_SELECT)) || defined(PROTO) /* * The "fd_set" type is hidden to avoid problems with the function proto. @@ -4381,7 +4391,7 @@ channel_select_check(int ret_in, void *rfds_in, void *wfds_in) if (ret > 0 && in_part->ch_fd != INVALID_FD && FD_ISSET(in_part->ch_fd, wfds)) { - /* Clear the flag first, ch_fd may change in channel_write_input(). */ + // Clear the flag first, ch_fd may change in channel_write_input(). FD_CLR(in_part->ch_fd, wfds); channel_write_input(channel); --ret; @@ -4390,11 +4400,12 @@ channel_select_check(int ret_in, void *rfds_in, void *wfds_in) return ret; } -# endif /* !MSWIN && HAVE_SELECT */ +#endif // !MSWIN && HAVE_SELECT /* * Execute queued up commands. - * Invoked from the main loop when it's safe to execute received commands. + * Invoked from the main loop when it's safe to execute received commands, + * and during a blocking wait for ch_evalexpr(). * Return TRUE when something was done. */ int diff --git a/src/edit.c b/src/edit.c index cc41d49cc..67141448f 100644 --- a/src/edit.c +++ b/src/edit.c @@ -1509,6 +1509,11 @@ ins_redraw(int ready) // not busy with something (linenr_T)(curwin->w_cursor.lnum + 1)); } + // Trigger SafeState if nothing is pending. + may_trigger_safestate(ready + && !ins_compl_active() + && !pum_visible()); + #if defined(FEAT_CONCEAL) if ((conceal_update_lines && (conceal_old_cursor_line != conceal_new_cursor_line diff --git a/src/ex_getln.c b/src/ex_getln.c index 5e32f2b6c..4c88bc86b 100644 --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -971,6 +971,9 @@ getcmdline_int( that occurs while typing a command should cause the command not to be executed. */ + // Trigger SafeState if nothing is pending. + may_trigger_safestate(xpc.xp_numfiles <= 0); + cursorcmd(); /* set the cursor on the right spot */ /* Get a character. Ignore K_IGNORE and K_NOP, they should not do diff --git a/src/main.c b/src/main.c index d1d9e32e4..94bb84680 100644 --- a/src/main.c +++ b/src/main.c @@ -1028,6 +1028,64 @@ is_not_a_term() return params.not_a_term; } + +static int was_safe = FALSE; +static int not_safe_now = 0; + +/* + * Trigger SafeState if currently in a safe state for main_loop(). + */ + static void +may_trigger_safestate_main(oparg_T *oap) +{ + may_trigger_safestate( + !finish_op + && oap->prev_opcount > 0 + && oap->prev_count0 == 0 + && oap->op_type == OP_NOP + && oap->regname == NUL + && restart_edit == 0); +} + +/* + * Trigger SafeState if currently in s safe state, that is "safe" is TRUE and + * there is no typeahead. + */ + void +may_trigger_safestate(int safe) +{ + int is_safe = safe + && stuff_empty() + && typebuf.tb_len == 0 + && !global_busy; + + if (is_safe) + apply_autocmds(EVENT_SAFESTATE, NULL, NULL, FALSE, curbuf); + was_safe = is_safe; +} + +/* + * Entering a not-safe state. + */ + void +enter_unsafe_state(void) +{ + ++not_safe_now; +} + +/* + * Leaving a not-safe state. Trigger SafeState if we were in a safe state + * before first calling enter_not_safe_state(). + */ + void +leave_unsafe_state(void) +{ + --not_safe_now; + if (not_safe_now == 0 && was_safe) + apply_autocmds(EVENT_SAFESTATE, NULL, NULL, FALSE, curbuf); +} + + /* * Main loop: Execute Normal mode commands until exiting Vim. * Also used to handle commands in the command-line window, until the window @@ -1133,6 +1191,9 @@ main_loop( msg_scroll = FALSE; quit_more = FALSE; + // it's not safe unless may_trigger_safestate_main() is called + was_safe = FALSE; + /* * If skip redraw is set (for ":" in wait_return()), don't redraw now. * If there is nothing in the stuff_buffer or do_redraw is TRUE, @@ -1211,6 +1272,10 @@ main_loop( curbuf->b_last_changedtick = CHANGEDTICK(curbuf); } + // If nothing is pending and we are going to wait for the user to + // type a character, trigger SafeState. + may_trigger_safestate_main(&oa); + #if defined(FEAT_DIFF) // Updating diffs from changed() does not always work properly, // esp. updating folds. Do an update just before redrawing if diff --git a/src/proto/main.pro b/src/proto/main.pro index 278d1addf..a6b9784a3 100644 --- a/src/proto/main.pro +++ b/src/proto/main.pro @@ -2,6 +2,9 @@ int vim_main2(void); void common_init(mparm_T *paramp); int is_not_a_term(void); +void may_trigger_safestate(int safe); +void enter_unsafe_state(void); +void leave_unsafe_state(void); void main_loop(int cmdwin, int noexmode); void getout_preserve_modified(int exitval); void getout(int exitval); diff --git a/src/version.c b/src/version.c index 919d8fdf3..c23fc839b 100644 --- a/src/version.c +++ b/src/version.c @@ -758,6 +758,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 2044, +/**/ 2043, /**/ 2042, @@ -1315,6 +1315,7 @@ enum auto_event EVENT_QUICKFIXCMDPRE, // before :make, :grep etc. EVENT_QUITPRE, // before :quit EVENT_REMOTEREPLY, // upon string reception from a remote vim + EVENT_SAFESTATE, // going to wait for a character EVENT_SESSIONLOADPOST, // after loading a session file EVENT_SHELLCMDPOST, // after ":!cmd" EVENT_SHELLFILTERPOST, // after ":1,2!cmd", ":w !cmd", ":r !cmd". |