]> granicus.if.org Git - vim/commitdiff
patch 8.1.2053: SafeStateAgain not triggered if callback uses feedkeys() v8.1.2053
authorBram Moolenaar <Bram@vim.org>
Wed, 18 Sep 2019 19:15:31 +0000 (21:15 +0200)
committerBram Moolenaar <Bram@vim.org>
Wed, 18 Sep 2019 19:15:31 +0000 (21:15 +0200)
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().

runtime/doc/eval.txt
src/getchar.c
src/main.c
src/proto/main.pro
src/version.c

index 7806120d6a705d77f7404d35110e4bd71eed009f..06219666592ad82b5494d1fb80a90241474d1a5c 100644 (file)
@@ -9060,7 +9060,8 @@ state([{what}])                                           *state()*
                added.  E.g, this checks if the screen has scrolled: >
                        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
                       stuffed command
                    o  operator pending or waiting for a command argument
@@ -9068,7 +9069,9 @@ state([{what}])                                           *state()*
                    x  executing an autocommand
                    w  blocked on waiting, e.g. ch_evalexpr() and
                       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
 
 str2float({expr})                                      *str2float()*
index 93d0d64ee0b42efbd0f84951de6fc6eee3601b6e..1056e938ed606ee8e0284e82d5fb856bc58742f9 100644 (file)
@@ -933,7 +933,7 @@ ins_typebuf(
     init_typebuf();
     if (++typebuf.tb_change_cnt == 0)
        typebuf.tb_change_cnt = 1;
-    state_no_longer_safe();
+    state_no_longer_safe("ins_typebuf()");
 
     addlen = (int)STRLEN(str);
 
@@ -1797,7 +1797,7 @@ vgetc(void)
     // Need to process the character before we know it's safe to do something
     // else.
     if (c != K_IGNORE)
-       state_no_longer_safe();
+       state_no_longer_safe("key typed");
 
     return c;
 }
@@ -2047,6 +2047,7 @@ parse_queued_messages(void)
     int            i;
     int            save_may_garbage_collect = may_garbage_collect;
     static int entered = 0;
+    int            was_safe = get_was_safe_state();
 
     // Do not handle messages while redrawing, because it may cause buffers to
     // 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
     // was safe before then this triggers a SafeStateAgain autocommand event.
-    if (entered == 1)
+    if (entered == 1 && was_safe)
        may_trigger_safestateagain();
 
     may_garbage_collect = save_may_garbage_collect;
index 52bbafe6c378a8433605efe5ef4c2357af66c935..8c56c17b50489fb4f601dd28873d773a2de7245d 100644 (file)
@@ -1048,6 +1048,19 @@ op_pending(void)
            && 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
  * there is no typeahead.
@@ -1055,18 +1068,14 @@ op_pending(void)
     void
 may_trigger_safestate(int safe)
 {
-    int is_safe = safe
-                   && stuff_empty()
-                   && typebuf.tb_len == 0
-                   && scriptin[curscript] == NULL
-                   && !global_busy;
+    int is_safe = safe && is_safe_now();
 
 #ifdef FEAT_JOB_CHANNEL
     if (was_safe != is_safe)
        // Only log when the state changes, otherwise it happens at nearly
        // every key stroke.
-       ch_log(NULL, is_safe ? "Start triggering SafeState"
-                                               : "Stop triggering SafeState");
+       ch_log(NULL, is_safe ? "SafeState: Start triggering"
+                                              : "SafeState: Stop triggering");
 #endif
     if (is_safe)
        apply_autocmds(EVENT_SAFESTATE, NULL, NULL, FALSE, curbuf);
@@ -1079,15 +1088,21 @@ may_trigger_safestate(int safe)
  * may_trigger_safestate().
  */
     void
-state_no_longer_safe(void)
+state_no_longer_safe(char *reason UNUSED)
 {
 #ifdef FEAT_JOB_CHANNEL
     if (was_safe)
-       ch_log(NULL, "safe state reset");
+       ch_log(NULL, "SafeState: reset: %s", reason);
 #endif
     was_safe = FALSE;
 }
 
+    int
+get_was_safe_state(void)
+{
+    return was_safe;
+}
+
 /*
  * Invoked when leaving code that invokes callbacks.  Then trigger
  * SafeStateAgain, if it was safe when starting to wait for a character.
@@ -1095,16 +1110,28 @@ state_no_longer_safe(void)
     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)
     {
 #ifdef FEAT_JOB_CHANNEL
-       ch_log(NULL, "Leaving unsafe area, triggering SafeStateAgain");
+       ch_log(NULL, "SafeState: back to waiting, triggering SafeStateAgain");
 #endif
        apply_autocmds(EVENT_SAFESTATEAGAIN, NULL, NULL, FALSE, curbuf);
     }
 #ifdef FEAT_JOB_CHANNEL
     else
-       ch_log(NULL, "Leaving unsafe area, not triggering SafeStateAgain");
+       ch_log(NULL,
+                 "SafeState: back to waiting, not triggering SafeStateAgain");
 #endif
 }
 
index 873255d8f70fde64599104e8c673aef0b76c2cac..c663cd2b15252a0b2c68abf0d6589e860b48db92 100644 (file)
@@ -4,7 +4,8 @@ void common_init(mparm_T *paramp);
 int is_not_a_term(void);
 int op_pending(void);
 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 main_loop(int cmdwin, int noexmode);
 void getout_preserve_modified(int exitval);
index c0d161aac186b0436d02950424627ff758e53888..debc3d7b1378a741916099146f5a027a87e06cff 100644 (file)
@@ -757,6 +757,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2053,
 /**/
     2052,
 /**/