0
0
mirror of https://github.com/vim/vim.git synced 2025-07-26 11:04:33 -04:00

patch 8.1.2044: no easy way to process postponed work

Problem:    No easy way to process postponed work. (Paul Jolly)
Solution:   Add the SafeState autocommand event.
This commit is contained in:
Bram Moolenaar 2019-09-15 23:02:04 +02:00
parent ea8dcf8346
commit 8aeec40207
9 changed files with 126 additions and 11 deletions

View File

@ -355,6 +355,9 @@ Name triggered by ~
when popup menu visible when popup menu visible
|TextYankPost| after text has been yanked or deleted |TextYankPost| after text has been yanked or deleted
|SafeState| nothing pending, going to wait for the user to type a
character
|ColorSchemePre| before loading a color scheme |ColorSchemePre| before loading a color scheme
|ColorScheme| after loading a color scheme |ColorScheme| after loading a color scheme
@ -955,6 +958,27 @@ RemoteReply When a reply from a Vim that functions as
Note that even if an autocommand is defined, Note that even if an autocommand is defined,
the reply should be read with |remote_read()| the reply should be read with |remote_read()|
to consume it. to consume it.
*SafeState*
SafeState When nothing is pending, going to wait for the
user to type a character.
This will not be triggered when:
- an operator is pending
- a register was entered with "r
- halfway executing a command
- executing a mapping
- there is typeahead
- Insert mode completion is active
- Command line completion is active
You can use `mode()` to find out what state
Vim is in. That may be:
- VIsual mode
- Normal mode
- Insert mode
- Command-line mode
Depending on what you want to do, you may also
check more with `state()`, e.g. whether the
screen was scrolled for messages.
*SessionLoadPost* *SessionLoadPost*
SessionLoadPost After loading the session file created using SessionLoadPost After loading the session file created using
the |:mksession| command. the |:mksession| command.

View File

@ -155,6 +155,7 @@ static struct event_name
{"QuickFixCmdPre", EVENT_QUICKFIXCMDPRE}, {"QuickFixCmdPre", EVENT_QUICKFIXCMDPRE},
{"QuitPre", EVENT_QUITPRE}, {"QuitPre", EVENT_QUITPRE},
{"RemoteReply", EVENT_REMOTEREPLY}, {"RemoteReply", EVENT_REMOTEREPLY},
{"SafeState", EVENT_SAFESTATE},
{"SessionLoadPost", EVENT_SESSIONLOADPOST}, {"SessionLoadPost", EVENT_SESSIONLOADPOST},
{"ShellCmdPost", EVENT_SHELLCMDPOST}, {"ShellCmdPost", EVENT_SHELLCMDPOST},
{"ShellFilterPost", EVENT_SHELLFILTERPOST}, {"ShellFilterPost", EVENT_SHELLFILTERPOST},

View File

@ -3589,10 +3589,17 @@ channel_read_json_block(
sock_T fd; sock_T fd;
int timeout; int timeout;
chanpart_T *chanpart = &channel->ch_part[part]; chanpart_T *chanpart = &channel->ch_part[part];
int retval = FAIL;
ch_log(channel, "Blocking read JSON for id %d", id); 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) if (id >= 0)
channel_add_block_id(chanpart, id); channel_add_block_id(chanpart, id);
for (;;) for (;;)
{ {
more = channel_parse_json(channel, part); more = channel_parse_json(channel, part);
@ -3600,10 +3607,9 @@ channel_read_json_block(
// search for message "id" // search for message "id"
if (channel_get_json(channel, part, id, TRUE, rettv) == OK) 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); ch_log(channel, "Received JSON for id %d", id);
return OK; retval = OK;
break;
} }
if (!more) if (!more)
@ -3659,7 +3665,11 @@ channel_read_json_block(
} }
if (id >= 0) if (id >= 0)
channel_remove_block_id(chanpart, id); channel_remove_block_id(chanpart, id);
return FAIL;
// This may trigger a SafeState autocommand.
leave_unsafe_state();
return retval;
} }
/* /*
@ -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 if (ret > 0 && in_part->ch_fd != INVALID_FD
&& FD_ISSET(in_part->ch_fd, wfds)) && 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); FD_CLR(in_part->ch_fd, wfds);
channel_write_input(channel); channel_write_input(channel);
--ret; --ret;
@ -4390,11 +4400,12 @@ channel_select_check(int ret_in, void *rfds_in, void *wfds_in)
return ret; return ret;
} }
# endif /* !MSWIN && HAVE_SELECT */ #endif // !MSWIN && HAVE_SELECT
/* /*
* Execute queued up commands. * 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. * Return TRUE when something was done.
*/ */
int int

View File

@ -1509,6 +1509,11 @@ ins_redraw(int ready) // not busy with something
(linenr_T)(curwin->w_cursor.lnum + 1)); (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 defined(FEAT_CONCEAL)
if ((conceal_update_lines if ((conceal_update_lines
&& (conceal_old_cursor_line != conceal_new_cursor_line && (conceal_old_cursor_line != conceal_new_cursor_line

View File

@ -971,6 +971,9 @@ getcmdline_int(
that occurs while typing a command should that occurs while typing a command should
cause the command not to be executed. */ 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 */ cursorcmd(); /* set the cursor on the right spot */
/* Get a character. Ignore K_IGNORE and K_NOP, they should not do /* Get a character. Ignore K_IGNORE and K_NOP, they should not do

View File

@ -1028,6 +1028,64 @@ is_not_a_term()
return params.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. * Main loop: Execute Normal mode commands until exiting Vim.
* Also used to handle commands in the command-line window, until the window * Also used to handle commands in the command-line window, until the window
@ -1133,6 +1191,9 @@ main_loop(
msg_scroll = FALSE; msg_scroll = FALSE;
quit_more = 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 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, * 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); 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) #if defined(FEAT_DIFF)
// Updating diffs from changed() does not always work properly, // Updating diffs from changed() does not always work properly,
// esp. updating folds. Do an update just before redrawing if // esp. updating folds. Do an update just before redrawing if

View File

@ -2,6 +2,9 @@
int vim_main2(void); int vim_main2(void);
void common_init(mparm_T *paramp); void common_init(mparm_T *paramp);
int is_not_a_term(void); 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 main_loop(int cmdwin, int noexmode);
void getout_preserve_modified(int exitval); void getout_preserve_modified(int exitval);
void getout(int exitval); void getout(int exitval);

View File

@ -757,6 +757,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
2044,
/**/ /**/
2043, 2043,
/**/ /**/

View File

@ -1315,6 +1315,7 @@ enum auto_event
EVENT_QUICKFIXCMDPRE, // before :make, :grep etc. EVENT_QUICKFIXCMDPRE, // before :make, :grep etc.
EVENT_QUITPRE, // before :quit EVENT_QUITPRE, // before :quit
EVENT_REMOTEREPLY, // upon string reception from a remote vim 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_SESSIONLOADPOST, // after loading a session file
EVENT_SHELLCMDPOST, // after ":!cmd" EVENT_SHELLCMDPOST, // after ":!cmd"
EVENT_SHELLFILTERPOST, // after ":1,2!cmd", ":w !cmd", ":r !cmd". EVENT_SHELLFILTERPOST, // after ":1,2!cmd", ":w !cmd", ":r !cmd".