Patch 8.1.2053
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().
Files:      src/main.c, src/proto/main.pro, src/getchar.c,
            runtime/doc/eval.txt


*** ../vim-8.1.2052/src/main.c  2019-09-17 20:54:26.396457149 +0200
--- src/main.c  2019-09-18 20:50:46.993967845 +0200
***************
*** 1049,1072 ****
  }
  
  /*
   * 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
!                   && scriptin[curscript] == NULL
!                   && !global_busy;
  
  #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");
  #endif
      if (is_safe)
        apply_autocmds(EVENT_SAFESTATE, NULL, NULL, FALSE, curbuf);
--- 1049,1081 ----
  }
  
  /*
+  * 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.
   */
      void
  may_trigger_safestate(int safe)
  {
!     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 ? "SafeState: Start triggering"
!                                              : "SafeState: Stop triggering");
  #endif
      if (is_safe)
        apply_autocmds(EVENT_SAFESTATE, NULL, NULL, FALSE, curbuf);
***************
*** 1079,1093 ****
   * may_trigger_safestate().
   */
      void
! state_no_longer_safe(void)
  {
  #ifdef FEAT_JOB_CHANNEL
      if (was_safe)
!       ch_log(NULL, "safe state reset");
  #endif
      was_safe = FALSE;
  }
  
  /*
   * Invoked when leaving code that invokes callbacks.  Then trigger
   * SafeStateAgain, if it was safe when starting to wait for a character.
--- 1088,1108 ----
   * may_trigger_safestate().
   */
      void
! state_no_longer_safe(char *reason UNUSED)
  {
  #ifdef FEAT_JOB_CHANNEL
      if (was_safe)
!       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,1110 ****
      void
  may_trigger_safestateagain(void)
  {
      if (was_safe)
      {
  #ifdef FEAT_JOB_CHANNEL
!       ch_log(NULL, "Leaving unsafe area, 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");
  #endif
  }
  
--- 1110,1137 ----
      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, "SafeState: back to waiting, triggering SafeStateAgain");
  #endif
        apply_autocmds(EVENT_SAFESTATEAGAIN, NULL, NULL, FALSE, curbuf);
      }
  #ifdef FEAT_JOB_CHANNEL
      else
!       ch_log(NULL,
!                 "SafeState: back to waiting, not triggering SafeStateAgain");
  #endif
  }
  
*** ../vim-8.1.2052/src/proto/main.pro  2019-09-17 20:28:34.148873666 +0200
--- src/proto/main.pro  2019-09-18 20:50:50.673973048 +0200
***************
*** 4,10 ****
  int is_not_a_term(void);
  int op_pending(void);
  void may_trigger_safestate(int safe);
! void state_no_longer_safe(void);
  void may_trigger_safestateagain(void);
  void main_loop(int cmdwin, int noexmode);
  void getout_preserve_modified(int exitval);
--- 4,11 ----
  int is_not_a_term(void);
  int op_pending(void);
  void may_trigger_safestate(int safe);
! 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);
*** ../vim-8.1.2052/src/getchar.c       2019-09-17 20:28:34.144873682 +0200
--- src/getchar.c       2019-09-18 20:51:19.650015118 +0200
***************
*** 933,939 ****
      init_typebuf();
      if (++typebuf.tb_change_cnt == 0)
        typebuf.tb_change_cnt = 1;
!     state_no_longer_safe();
  
      addlen = (int)STRLEN(str);
  
--- 933,939 ----
      init_typebuf();
      if (++typebuf.tb_change_cnt == 0)
        typebuf.tb_change_cnt = 1;
!     state_no_longer_safe("ins_typebuf()");
  
      addlen = (int)STRLEN(str);
  
***************
*** 1797,1803 ****
      // Need to process the character before we know it's safe to do something
      // else.
      if (c != K_IGNORE)
!       state_no_longer_safe();
  
      return c;
  }
--- 1797,1803 ----
      // Need to process the character before we know it's safe to do something
      // else.
      if (c != K_IGNORE)
!       state_no_longer_safe("key typed");
  
      return c;
  }
***************
*** 2047,2052 ****
--- 2047,2053 ----
      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,2108 ****
  
      // 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)
        may_trigger_safestateagain();
  
      may_garbage_collect = save_may_garbage_collect;
--- 2103,2109 ----
  
      // 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 && was_safe)
        may_trigger_safestateagain();
  
      may_garbage_collect = save_may_garbage_collect;
*** ../vim-8.1.2052/runtime/doc/eval.txt        2019-09-16 22:55:57.728006887 
+0200
--- runtime/doc/eval.txt        2019-09-18 20:52:32.730129074 +0200
***************
*** 9050,9056 ****
                added.  E.g, this checks if the screen has scrolled: >
                        if state('s') != ''
  <
!               These characters indicate the state:
                    m  halfway a mapping, :normal command, feedkeys() or
                       stuffed command
                    o  operator pending or waiting for a command argument
--- 9060,9067 ----
                added.  E.g, this checks if the screen has scrolled: >
                        if state('s') != ''
  <
!               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
***************
*** 9058,9064 ****
                    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  screen has scrolled for messages
  
  str2float({expr})                                     *str2float()*
--- 9069,9077 ----
                    x  executing an autocommand
                    w  blocked on waiting, e.g. ch_evalexpr() and
                       ch_read(), ch_readraw() when reading json.
!                   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()*
*** ../vim-8.1.2052/src/version.c       2019-09-17 22:42:51.997139914 +0200
--- src/version.c       2019-09-18 20:44:39.313651094 +0200
***************
*** 759,760 ****
--- 759,762 ----
  {   /* Add new patch number below this line */
+ /**/
+     2053,
  /**/

-- 
Facepalm statement #8: "Drive faster, the petrol is running out"

 /// Bram Moolenaar -- b...@moolenaar.net -- http://www.Moolenaar.net   \\\
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to vim_dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/201909181916.x8IJGPh1025795%40masaka.moolenaar.net.

Raspunde prin e-mail lui