summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2019-09-16 21:58:13 +0200
committerBram Moolenaar <Bram@vim.org>2019-09-16 21:58:13 +0200
commit69198cb8c08f124729c41a4681f2d142228a9139 (patch)
tree12b2ba27e1239074e4bcb1f6f6524d23ab996158
parentdac1347b4d9c1a1aef6aa73fdea08a9d1077d6ea (diff)
downloadvim-git-69198cb8c08f124729c41a4681f2d142228a9139.tar.gz
patch 8.1.2046: SafeState may be triggered at the wrong momentv8.1.2046
Problem: SafeState may be triggered at the wrong moment. Solution: Move it up higher to after where messages are processed. Add a SafeStateAgain event to tigger there.
-rw-r--r--runtime/doc/autocmd.txt6
-rw-r--r--src/autocmd.c1
-rw-r--r--src/channel.c7
-rw-r--r--src/getchar.c19
-rw-r--r--src/main.c20
-rw-r--r--src/proto/main.pro2
-rw-r--r--src/version.c2
-rw-r--r--src/vim.h1
8 files changed, 40 insertions, 18 deletions
diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt
index d336ba9fa..85a554744 100644
--- a/runtime/doc/autocmd.txt
+++ b/runtime/doc/autocmd.txt
@@ -357,6 +357,7 @@ Name triggered by ~
|SafeState| nothing pending, going to wait for the user to type a
character
+|SafeStateAgain| repeated SafeState
|ColorSchemePre| before loading a color scheme
|ColorScheme| after loading a color scheme
@@ -978,6 +979,11 @@ SafeState When nothing is pending, going to wait for the
Depending on what you want to do, you may also
check more with `state()`, e.g. whether the
screen was scrolled for messages.
+ *SafeStateAgain*
+SafeStateAgain Like SafeState but after processing any
+ messages and invoking callbacks. This may be
+ triggered often, don't do something that takes
+ time.
*SessionLoadPost*
SessionLoadPost After loading the session file created using
diff --git a/src/autocmd.c b/src/autocmd.c
index fb6c84491..3f87e931c 100644
--- a/src/autocmd.c
+++ b/src/autocmd.c
@@ -156,6 +156,7 @@ static struct event_name
{"QuitPre", EVENT_QUITPRE},
{"RemoteReply", EVENT_REMOTEREPLY},
{"SafeState", EVENT_SAFESTATE},
+ {"SafeStateAgain", EVENT_SAFESTATEAGAIN},
{"SessionLoadPost", EVENT_SESSIONLOADPOST},
{"ShellCmdPost", EVENT_SHELLCMDPOST},
{"ShellFilterPost", EVENT_SHELLFILTERPOST},
diff --git a/src/channel.c b/src/channel.c
index 3792b354b..0dab3be5f 100644
--- a/src/channel.c
+++ b/src/channel.c
@@ -3593,10 +3593,6 @@ channel_read_json_block(
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);
@@ -3666,9 +3662,6 @@ channel_read_json_block(
if (id >= 0)
channel_remove_block_id(chanpart, id);
- // This may trigger a SafeState autocommand.
- leave_unsafe_state();
-
return retval;
}
diff --git a/src/getchar.c b/src/getchar.c
index 32e35504f..3f3c6bca5 100644
--- a/src/getchar.c
+++ b/src/getchar.c
@@ -933,6 +933,7 @@ ins_typebuf(
init_typebuf();
if (++typebuf.tb_change_cnt == 0)
typebuf.tb_change_cnt = 1;
+ state_no_longer_safe();
addlen = (int)STRLEN(str);
@@ -1779,10 +1780,11 @@ vgetc(void)
*/
may_garbage_collect = FALSE;
#endif
+
#ifdef FEAT_BEVAL_TERM
if (c != K_MOUSEMOVE && c != K_IGNORE && c != K_CURSORHOLD)
{
- /* Don't trigger 'balloonexpr' unless only the mouse was moved. */
+ // Don't trigger 'balloonexpr' unless only the mouse was moved.
bevalexpr_due_set = FALSE;
ui_remove_balloon();
}
@@ -1792,6 +1794,11 @@ vgetc(void)
c = K_IGNORE;
#endif
+ // 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;
}
@@ -2039,12 +2046,15 @@ parse_queued_messages(void)
int old_curbuf_fnum = curbuf->b_fnum;
int i;
int save_may_garbage_collect = may_garbage_collect;
+ static int entered = 0;
// Do not handle messages while redrawing, because it may cause buffers to
// change or be wiped while they are being redrawn.
if (updating_screen)
return;
+ ++entered;
+
// may_garbage_collect is set in main_loop() to do garbage collection when
// blocking to wait on a character. We don't want that while parsing
// messages, a callback may invoke vgetc() while lists and dicts are in use
@@ -2090,12 +2100,19 @@ parse_queued_messages(void)
break;
}
+ // 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)
+ leave_unsafe_state();
+
may_garbage_collect = save_may_garbage_collect;
// If the current window or buffer changed we need to bail out of the
// waiting loop. E.g. when a job exit callback closes the terminal window.
if (curwin->w_id != old_curwin_id || curbuf->b_fnum != old_curbuf_fnum)
ins_char_typebuf(K_IGNORE);
+
+ --entered;
}
#endif
diff --git a/src/main.c b/src/main.c
index 94bb84680..51e3915d9 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1029,8 +1029,8 @@ is_not_a_term()
}
+// When TRUE in a safe state when starting to wait for a character.
static int was_safe = FALSE;
-static int not_safe_now = 0;
/*
* Trigger SafeState if currently in a safe state for main_loop().
@@ -1057,6 +1057,7 @@ may_trigger_safestate(int safe)
int is_safe = safe
&& stuff_empty()
&& typebuf.tb_len == 0
+ && scriptin[curscript] == NULL
&& !global_busy;
if (is_safe)
@@ -1065,24 +1066,25 @@ may_trigger_safestate(int safe)
}
/*
- * Entering a not-safe state.
+ * Something changed which causes the state possibly to be unsafe, e.g. a
+ * character was typed. It will remain unsafe until the next call to
+ * may_trigger_safestate().
*/
void
-enter_unsafe_state(void)
+state_no_longer_safe(void)
{
- ++not_safe_now;
+ was_safe = FALSE;
}
/*
- * Leaving a not-safe state. Trigger SafeState if we were in a safe state
- * before first calling enter_not_safe_state().
+ * Invoked when leaving code that invokes callbacks. Then trigger
+ * SafeStateAgain, if it was safe when starting to wait for a character.
*/
void
leave_unsafe_state(void)
{
- --not_safe_now;
- if (not_safe_now == 0 && was_safe)
- apply_autocmds(EVENT_SAFESTATE, NULL, NULL, FALSE, curbuf);
+ if (was_safe)
+ apply_autocmds(EVENT_SAFESTATEAGAIN, NULL, NULL, FALSE, curbuf);
}
diff --git a/src/proto/main.pro b/src/proto/main.pro
index a6b9784a3..2c07ceab0 100644
--- a/src/proto/main.pro
+++ b/src/proto/main.pro
@@ -3,7 +3,7 @@ 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 state_no_longer_safe(void);
void leave_unsafe_state(void);
void main_loop(int cmdwin, int noexmode);
void getout_preserve_modified(int exitval);
diff --git a/src/version.c b/src/version.c
index 34e3e6bdf..02e8cfbb3 100644
--- a/src/version.c
+++ b/src/version.c
@@ -758,6 +758,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 2046,
+/**/
2045,
/**/
2044,
diff --git a/src/vim.h b/src/vim.h
index 4b817c599..8bfbcaf9f 100644
--- a/src/vim.h
+++ b/src/vim.h
@@ -1316,6 +1316,7 @@ enum auto_event
EVENT_QUITPRE, // before :quit
EVENT_REMOTEREPLY, // upon string reception from a remote vim
EVENT_SAFESTATE, // going to wait for a character
+ EVENT_SAFESTATEAGAIN, // still waiting for a character
EVENT_SESSIONLOADPOST, // after loading a session file
EVENT_SHELLCMDPOST, // after ":!cmd"
EVENT_SHELLFILTERPOST, // after ":1,2!cmd", ":w !cmd", ":r !cmd".