Skip to content

Commit d103ee7

Browse files
committed
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().
1 parent 7a9bd7c commit d103ee7

5 files changed

Lines changed: 51 additions & 17 deletions

File tree

runtime/doc/eval.txt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9060,15 +9060,18 @@ state([{what}]) *state()*
90609060
added. E.g, this checks if the screen has scrolled: >
90619061
if state('s') != ''
90629062
<
9063-
These characters indicate the state:
9063+
These characters indicate the state, generally indicating that
9064+
something is busy:
90649065
m halfway a mapping, :normal command, feedkeys() or
90659066
stuffed command
90669067
o operator pending or waiting for a command argument
90679068
a Insert mode autocomplete active
90689069
x executing an autocommand
90699070
w blocked on waiting, e.g. ch_evalexpr() and
90709071
ch_read(), ch_readraw() when reading json.
9071-
c callback invoked (repeats for recursiveness up to "ccc")
9072+
S not triggering SafeState or SafeStateAgain
9073+
c callback invoked, including timer (repeats for
9074+
recursiveness up to "ccc")
90729075
s screen has scrolled for messages
90739076

90749077
str2float({expr}) *str2float()*

src/getchar.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -933,7 +933,7 @@ ins_typebuf(
933933
init_typebuf();
934934
if (++typebuf.tb_change_cnt == 0)
935935
typebuf.tb_change_cnt = 1;
936-
state_no_longer_safe();
936+
state_no_longer_safe("ins_typebuf()");
937937

938938
addlen = (int)STRLEN(str);
939939

@@ -1797,7 +1797,7 @@ vgetc(void)
17971797
// Need to process the character before we know it's safe to do something
17981798
// else.
17991799
if (c != K_IGNORE)
1800-
state_no_longer_safe();
1800+
state_no_longer_safe("key typed");
18011801

18021802
return c;
18031803
}
@@ -2047,6 +2047,7 @@ parse_queued_messages(void)
20472047
int i;
20482048
int save_may_garbage_collect = may_garbage_collect;
20492049
static int entered = 0;
2050+
int was_safe = get_was_safe_state();
20502051

20512052
// Do not handle messages while redrawing, because it may cause buffers to
20522053
// change or be wiped while they are being redrawn.
@@ -2102,7 +2103,7 @@ parse_queued_messages(void)
21022103

21032104
// When not nested we'll go back to waiting for a typed character. If it
21042105
// was safe before then this triggers a SafeStateAgain autocommand event.
2105-
if (entered == 1)
2106+
if (entered == 1 && was_safe)
21062107
may_trigger_safestateagain();
21072108

21082109
may_garbage_collect = save_may_garbage_collect;

src/main.c

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1048,25 +1048,34 @@ op_pending(void)
10481048
&& current_oap->regname == NUL);
10491049
}
10501050

1051+
/*
1052+
* Return whether currently it is safe, assuming it was safe before (high level
1053+
* state didn't change).
1054+
*/
1055+
static int
1056+
is_safe_now(void)
1057+
{
1058+
return stuff_empty()
1059+
&& typebuf.tb_len == 0
1060+
&& scriptin[curscript] == NULL
1061+
&& !global_busy;
1062+
}
1063+
10511064
/*
10521065
* Trigger SafeState if currently in s safe state, that is "safe" is TRUE and
10531066
* there is no typeahead.
10541067
*/
10551068
void
10561069
may_trigger_safestate(int safe)
10571070
{
1058-
int is_safe = safe
1059-
&& stuff_empty()
1060-
&& typebuf.tb_len == 0
1061-
&& scriptin[curscript] == NULL
1062-
&& !global_busy;
1071+
int is_safe = safe && is_safe_now();
10631072

10641073
#ifdef FEAT_JOB_CHANNEL
10651074
if (was_safe != is_safe)
10661075
// Only log when the state changes, otherwise it happens at nearly
10671076
// every key stroke.
1068-
ch_log(NULL, is_safe ? "Start triggering SafeState"
1069-
: "Stop triggering SafeState");
1077+
ch_log(NULL, is_safe ? "SafeState: Start triggering"
1078+
: "SafeState: Stop triggering");
10701079
#endif
10711080
if (is_safe)
10721081
apply_autocmds(EVENT_SAFESTATE, NULL, NULL, FALSE, curbuf);
@@ -1079,32 +1088,50 @@ may_trigger_safestate(int safe)
10791088
* may_trigger_safestate().
10801089
*/
10811090
void
1082-
state_no_longer_safe(void)
1091+
state_no_longer_safe(char *reason UNUSED)
10831092
{
10841093
#ifdef FEAT_JOB_CHANNEL
10851094
if (was_safe)
1086-
ch_log(NULL, "safe state reset");
1095+
ch_log(NULL, "SafeState: reset: %s", reason);
10871096
#endif
10881097
was_safe = FALSE;
10891098
}
10901099

1100+
int
1101+
get_was_safe_state(void)
1102+
{
1103+
return was_safe;
1104+
}
1105+
10911106
/*
10921107
* Invoked when leaving code that invokes callbacks. Then trigger
10931108
* SafeStateAgain, if it was safe when starting to wait for a character.
10941109
*/
10951110
void
10961111
may_trigger_safestateagain(void)
10971112
{
1113+
if (!was_safe)
1114+
{
1115+
// If the safe state was reset in state_no_longer_safe(), e.g. because
1116+
// of calling feedkeys(), we check if it's now safe again (all keys
1117+
// were consumed).
1118+
was_safe = is_safe_now();
1119+
#ifdef FEAT_JOB_CHANNEL
1120+
if (was_safe)
1121+
ch_log(NULL, "SafeState: undo reset");
1122+
#endif
1123+
}
10981124
if (was_safe)
10991125
{
11001126
#ifdef FEAT_JOB_CHANNEL
1101-
ch_log(NULL, "Leaving unsafe area, triggering SafeStateAgain");
1127+
ch_log(NULL, "SafeState: back to waiting, triggering SafeStateAgain");
11021128
#endif
11031129
apply_autocmds(EVENT_SAFESTATEAGAIN, NULL, NULL, FALSE, curbuf);
11041130
}
11051131
#ifdef FEAT_JOB_CHANNEL
11061132
else
1107-
ch_log(NULL, "Leaving unsafe area, not triggering SafeStateAgain");
1133+
ch_log(NULL,
1134+
"SafeState: back to waiting, not triggering SafeStateAgain");
11081135
#endif
11091136
}
11101137

src/proto/main.pro

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ void common_init(mparm_T *paramp);
44
int is_not_a_term(void);
55
int op_pending(void);
66
void may_trigger_safestate(int safe);
7-
void state_no_longer_safe(void);
7+
void state_no_longer_safe(char *reason);
8+
int get_was_safe_state(void);
89
void may_trigger_safestateagain(void);
910
void main_loop(int cmdwin, int noexmode);
1011
void getout_preserve_modified(int exitval);

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -757,6 +757,8 @@ static char *(features[]) =
757757

758758
static int included_patches[] =
759759
{ /* Add new patch number below this line */
760+
/**/
761+
2053,
760762
/**/
761763
2052,
762764
/**/

0 commit comments

Comments
 (0)