Patch 8.1.2044
Problem:    No easy way to process postponed work. (Paul Jolly)
Solution:   Add the SafeState autocommand event.
Files:      runtime/doc/autocmd.txt, src/main.c, src/proto/main.pro,
            src/vim.h, src/autocmd.c, src/channel.c, src/edit.c,
            src/ex_getln.c


*** ../vim-8.1.2043/runtime/doc/autocmd.txt     2019-09-09 18:35:28.119252725 
+0200
--- runtime/doc/autocmd.txt     2019-09-15 21:50:17.266633152 +0200
***************
*** 355,360 ****
--- 355,363 ----
                        when popup menu visible
  |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
  |ColorScheme|         after loading a color scheme
  
***************
*** 956,961 ****
--- 958,984 ----
                                Note that even if an autocommand is defined,
                                the reply should be read with |remote_read()|
                                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                       After loading the session file created 
using
                                the |:mksession| command.
*** ../vim-8.1.2043/src/main.c  2019-09-14 21:00:01.379100893 +0200
--- src/main.c  2019-09-15 22:53:15.929911499 +0200
***************
*** 1028,1033 ****
--- 1028,1091 ----
      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.
   * Also used to handle commands in the command-line window, until the window
***************
*** 1133,1138 ****
--- 1191,1199 ----
            msg_scroll = 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 there is nothing in the stuff_buffer or do_redraw is TRUE,
***************
*** 1211,1216 ****
--- 1272,1281 ----
                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)
            // Updating diffs from changed() does not always work properly,
            // esp. updating folds.  Do an update just before redrawing if
*** ../vim-8.1.2043/src/proto/main.pro  2018-05-17 13:52:42.000000000 +0200
--- src/proto/main.pro  2019-09-15 22:58:58.612143846 +0200
***************
*** 2,7 ****
--- 2,10 ----
  int vim_main2(void);
  void common_init(mparm_T *paramp);
  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 getout_preserve_modified(int exitval);
  void getout(int exitval);
*** ../vim-8.1.2043/src/vim.h   2019-09-15 14:32:49.552731470 +0200
--- src/vim.h   2019-09-15 21:28:08.518157203 +0200
***************
*** 1315,1320 ****
--- 1315,1321 ----
      EVENT_QUICKFIXCMDPRE,     // before :make, :grep etc.
      EVENT_QUITPRE,            // before :quit
      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_SHELLCMDPOST,               // after ":!cmd"
      EVENT_SHELLFILTERPOST,    // after ":1,2!cmd", ":w !cmd", ":r !cmd".
*** ../vim-8.1.2043/src/autocmd.c       2019-08-21 14:36:29.383376114 +0200
--- src/autocmd.c       2019-09-15 21:28:44.982046437 +0200
***************
*** 155,160 ****
--- 155,161 ----
      {"QuickFixCmdPre",        EVENT_QUICKFIXCMDPRE},
      {"QuitPre",               EVENT_QUITPRE},
      {"RemoteReply",   EVENT_REMOTEREPLY},
+     {"SafeState",     EVENT_SAFESTATE},
      {"SessionLoadPost",       EVENT_SESSIONLOADPOST},
      {"ShellCmdPost",  EVENT_SHELLCMDPOST},
      {"ShellFilterPost",       EVENT_SHELLFILTERPOST},
*** ../vim-8.1.2043/src/channel.c       2019-09-07 15:45:09.973228904 +0200
--- src/channel.c       2019-09-15 22:36:36.060000155 +0200
***************
*** 3589,3598 ****
--- 3589,3605 ----
      sock_T    fd;
      int               timeout;
      chanpart_T        *chanpart = &channel->ch_part[part];
+     int               retval = FAIL;
  
      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)
        channel_add_block_id(chanpart, id);
+ 
      for (;;)
      {
        more = channel_parse_json(channel, part);
***************
*** 3600,3609 ****
        // search for message "id"
        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);
!           return OK;
        }
  
        if (!more)
--- 3607,3615 ----
        // search for message "id"
        if (channel_get_json(channel, part, id, TRUE, rettv) == OK)
        {
            ch_log(channel, "Received JSON for id %d", id);
!           retval = OK;
!           break;
        }
  
        if (!more)
***************
*** 3659,3665 ****
      }
      if (id >= 0)
        channel_remove_block_id(chanpart, id);
!     return FAIL;
  }
  
  /*
--- 3665,3675 ----
      }
      if (id >= 0)
        channel_remove_block_id(chanpart, id);
! 
!     // This may trigger a SafeState autocommand.
!     leave_unsafe_state();
! 
!     return retval;
  }
  
  /*
***************
*** 4195,4203 ****
      free_job_options(&opt);
  }
  
! # define KEEP_OPEN_TIME 20  /* msec */
  
! # if (defined(UNIX) && !defined(HAVE_SELECT)) || defined(PROTO)
  /*
   * Add open channels to the poll struct.
   * Return the adjusted struct index.
--- 4205,4213 ----
      free_job_options(&opt);
  }
  
! #define KEEP_OPEN_TIME 20  /* msec */
  
! #if (defined(UNIX) && !defined(HAVE_SELECT)) || defined(PROTO)
  /*
   * Add open channels to the poll struct.
   * Return the adjusted struct index.
***************
*** 4288,4296 ****
  
      return ret;
  }
! # endif /* UNIX && !HAVE_SELECT */
  
! # if (!defined(MSWIN) && defined(HAVE_SELECT)) || defined(PROTO)
  
  /*
   * The "fd_set" type is hidden to avoid problems with the function proto.
--- 4298,4306 ----
  
      return ret;
  }
! #endif /* UNIX && !HAVE_SELECT */
  
! #if (!defined(MSWIN) && defined(HAVE_SELECT)) || defined(PROTO)
  
  /*
   * The "fd_set" type is hidden to avoid problems with the function proto.
***************
*** 4381,4387 ****
        if (ret > 0 && in_part->ch_fd != INVALID_FD
                                            && FD_ISSET(in_part->ch_fd, wfds))
        {
!           /* Clear the flag first, ch_fd may change in channel_write_input(). 
*/
            FD_CLR(in_part->ch_fd, wfds);
            channel_write_input(channel);
            --ret;
--- 4391,4397 ----
        if (ret > 0 && in_part->ch_fd != INVALID_FD
                                            && FD_ISSET(in_part->ch_fd, wfds))
        {
!           // Clear the flag first, ch_fd may change in channel_write_input().
            FD_CLR(in_part->ch_fd, wfds);
            channel_write_input(channel);
            --ret;
***************
*** 4390,4400 ****
  
      return ret;
  }
! # endif /* !MSWIN && HAVE_SELECT */
  
  /*
   * Execute queued up commands.
!  * Invoked from the main loop when it's safe to execute received commands.
   * Return TRUE when something was done.
   */
      int
--- 4400,4411 ----
  
      return ret;
  }
! #endif // !MSWIN && HAVE_SELECT
  
  /*
   * Execute queued up 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.
   */
      int
*** ../vim-8.1.2043/src/edit.c  2019-08-21 14:36:29.383376114 +0200
--- src/edit.c  2019-09-15 22:59:00.044136610 +0200
***************
*** 1509,1514 ****
--- 1509,1519 ----
                                        (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 ((conceal_update_lines
            && (conceal_old_cursor_line != conceal_new_cursor_line
*** ../vim-8.1.2043/src/ex_getln.c      2019-09-09 18:35:28.119252725 +0200
--- src/ex_getln.c      2019-09-15 22:59:05.552108785 +0200
***************
*** 971,976 ****
--- 971,979 ----
                                   that occurs while typing a command should
                                   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 */
  
        /* Get a character.  Ignore K_IGNORE and K_NOP, they should not do
*** ../vim-8.1.2043/src/version.c       2019-09-15 21:12:18.532950015 +0200
--- src/version.c       2019-09-15 23:00:29.339687077 +0200
***************
*** 759,760 ****
--- 759,762 ----
  {   /* Add new patch number below this line */
+ /**/
+     2044,
  /**/

-- 
GALAHAD:   Camelot ...
LAUNCELOT: Camelot ...
GAWAIN:    It's only a model.
                 "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD

 /// 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/201909152102.x8FL2b0n011692%40masaka.moolenaar.net.

Reply via email to