1
0
forked from aniani/vim

patch 8.1.2053: SafeStateAgain not triggered if callback uses feedkeys()

Problem:    SafeStateAgain not triggered if callback uses feedkeys().
Solution:   Check for safe state in the input loop.  Make log messages easier
            to find. Add 'S' flag to state().
This commit is contained in:
Bram Moolenaar 2019-09-18 21:15:31 +02:00
parent 7a9bd7c1e0
commit d103ee7843
5 changed files with 51 additions and 17 deletions

View File

@ -9060,7 +9060,8 @@ state([{what}]) *state()*
added. E.g, this checks if the screen has scrolled: > added. E.g, this checks if the screen has scrolled: >
if state('s') != '' if state('s') != ''
< <
These characters indicate the state: These characters indicate the state, generally indicating that
something is busy:
m halfway a mapping, :normal command, feedkeys() or m halfway a mapping, :normal command, feedkeys() or
stuffed command stuffed command
o operator pending or waiting for a command argument o operator pending or waiting for a command argument
@ -9068,7 +9069,9 @@ state([{what}]) *state()*
x executing an autocommand x executing an autocommand
w blocked on waiting, e.g. ch_evalexpr() and w blocked on waiting, e.g. ch_evalexpr() and
ch_read(), ch_readraw() when reading json. ch_read(), ch_readraw() when reading json.
c callback invoked (repeats for recursiveness up to "ccc") S not triggering SafeState or SafeStateAgain
c callback invoked, including timer (repeats for
recursiveness up to "ccc")
s screen has scrolled for messages s screen has scrolled for messages
str2float({expr}) *str2float()* str2float({expr}) *str2float()*

View File

@ -933,7 +933,7 @@ ins_typebuf(
init_typebuf(); init_typebuf();
if (++typebuf.tb_change_cnt == 0) if (++typebuf.tb_change_cnt == 0)
typebuf.tb_change_cnt = 1; typebuf.tb_change_cnt = 1;
state_no_longer_safe(); state_no_longer_safe("ins_typebuf()");
addlen = (int)STRLEN(str); addlen = (int)STRLEN(str);
@ -1797,7 +1797,7 @@ vgetc(void)
// Need to process the character before we know it's safe to do something // Need to process the character before we know it's safe to do something
// else. // else.
if (c != K_IGNORE) if (c != K_IGNORE)
state_no_longer_safe(); state_no_longer_safe("key typed");
return c; return c;
} }
@ -2047,6 +2047,7 @@ parse_queued_messages(void)
int i; int i;
int save_may_garbage_collect = may_garbage_collect; int save_may_garbage_collect = may_garbage_collect;
static int entered = 0; static int entered = 0;
int was_safe = get_was_safe_state();
// Do not handle messages while redrawing, because it may cause buffers to // Do not handle messages while redrawing, because it may cause buffers to
// change or be wiped while they are being redrawn. // change or be wiped while they are being redrawn.
@ -2102,7 +2103,7 @@ parse_queued_messages(void)
// When not nested we'll go back to waiting for a typed character. If it // When not nested we'll go back to waiting for a typed character. If it
// was safe before then this triggers a SafeStateAgain autocommand event. // was safe before then this triggers a SafeStateAgain autocommand event.
if (entered == 1) if (entered == 1 && was_safe)
may_trigger_safestateagain(); may_trigger_safestateagain();
may_garbage_collect = save_may_garbage_collect; may_garbage_collect = save_may_garbage_collect;

View File

@ -1048,6 +1048,19 @@ op_pending(void)
&& current_oap->regname == NUL); && current_oap->regname == NUL);
} }
/*
* Return whether currently it is safe, assuming it was safe before (high level
* state didn't change).
*/
static int
is_safe_now(void)
{
return stuff_empty()
&& typebuf.tb_len == 0
&& scriptin[curscript] == NULL
&& !global_busy;
}
/* /*
* Trigger SafeState if currently in s safe state, that is "safe" is TRUE and * Trigger SafeState if currently in s safe state, that is "safe" is TRUE and
* there is no typeahead. * there is no typeahead.
@ -1055,18 +1068,14 @@ op_pending(void)
void void
may_trigger_safestate(int safe) may_trigger_safestate(int safe)
{ {
int is_safe = safe int is_safe = safe && is_safe_now();
&& stuff_empty()
&& typebuf.tb_len == 0
&& scriptin[curscript] == NULL
&& !global_busy;
#ifdef FEAT_JOB_CHANNEL #ifdef FEAT_JOB_CHANNEL
if (was_safe != is_safe) if (was_safe != is_safe)
// Only log when the state changes, otherwise it happens at nearly // Only log when the state changes, otherwise it happens at nearly
// every key stroke. // every key stroke.
ch_log(NULL, is_safe ? "Start triggering SafeState" ch_log(NULL, is_safe ? "SafeState: Start triggering"
: "Stop triggering SafeState"); : "SafeState: Stop triggering");
#endif #endif
if (is_safe) if (is_safe)
apply_autocmds(EVENT_SAFESTATE, NULL, NULL, FALSE, curbuf); apply_autocmds(EVENT_SAFESTATE, NULL, NULL, FALSE, curbuf);
@ -1079,15 +1088,21 @@ may_trigger_safestate(int safe)
* may_trigger_safestate(). * may_trigger_safestate().
*/ */
void void
state_no_longer_safe(void) state_no_longer_safe(char *reason UNUSED)
{ {
#ifdef FEAT_JOB_CHANNEL #ifdef FEAT_JOB_CHANNEL
if (was_safe) if (was_safe)
ch_log(NULL, "safe state reset"); ch_log(NULL, "SafeState: reset: %s", reason);
#endif #endif
was_safe = FALSE; was_safe = FALSE;
} }
int
get_was_safe_state(void)
{
return was_safe;
}
/* /*
* Invoked when leaving code that invokes callbacks. Then trigger * Invoked when leaving code that invokes callbacks. Then trigger
* SafeStateAgain, if it was safe when starting to wait for a character. * SafeStateAgain, if it was safe when starting to wait for a character.
@ -1095,16 +1110,28 @@ state_no_longer_safe(void)
void void
may_trigger_safestateagain(void) may_trigger_safestateagain(void)
{ {
if (!was_safe)
{
// If the safe state was reset in state_no_longer_safe(), e.g. because
// of calling feedkeys(), we check if it's now safe again (all keys
// were consumed).
was_safe = is_safe_now();
#ifdef FEAT_JOB_CHANNEL
if (was_safe)
ch_log(NULL, "SafeState: undo reset");
#endif
}
if (was_safe) if (was_safe)
{ {
#ifdef FEAT_JOB_CHANNEL #ifdef FEAT_JOB_CHANNEL
ch_log(NULL, "Leaving unsafe area, triggering SafeStateAgain"); ch_log(NULL, "SafeState: back to waiting, triggering SafeStateAgain");
#endif #endif
apply_autocmds(EVENT_SAFESTATEAGAIN, NULL, NULL, FALSE, curbuf); apply_autocmds(EVENT_SAFESTATEAGAIN, NULL, NULL, FALSE, curbuf);
} }
#ifdef FEAT_JOB_CHANNEL #ifdef FEAT_JOB_CHANNEL
else else
ch_log(NULL, "Leaving unsafe area, not triggering SafeStateAgain"); ch_log(NULL,
"SafeState: back to waiting, not triggering SafeStateAgain");
#endif #endif
} }

View File

@ -4,7 +4,8 @@ void common_init(mparm_T *paramp);
int is_not_a_term(void); int is_not_a_term(void);
int op_pending(void); int op_pending(void);
void may_trigger_safestate(int safe); void may_trigger_safestate(int safe);
void state_no_longer_safe(void); void state_no_longer_safe(char *reason);
int get_was_safe_state(void);
void may_trigger_safestateagain(void); void may_trigger_safestateagain(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);

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 */
/**/
2053,
/**/ /**/
2052, 2052,
/**/ /**/