diff options
-rw-r--r-- | runtime/doc/autocmd.txt | 21 | ||||
-rw-r--r-- | src/nvim/auevents.lua | 1 | ||||
-rw-r--r-- | src/nvim/edit.c | 5 | ||||
-rw-r--r-- | src/nvim/ex_getln.c | 5 | ||||
-rw-r--r-- | src/nvim/normal.c | 50 |
5 files changed, 82 insertions, 0 deletions
diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt index a7c28e25d0..90211fc5db 100644 --- a/runtime/doc/autocmd.txt +++ b/runtime/doc/autocmd.txt @@ -862,6 +862,27 @@ RecordingLeave When a macro stops recording. Sets these |v:event| keys: regcontents regname + *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. diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua index f023ee1340..696df7c534 100644 --- a/src/nvim/auevents.lua +++ b/src/nvim/auevents.lua @@ -85,6 +85,7 @@ return { 'RecordingEnter', -- when starting to record a macro 'RecordingLeave', -- just before a macro stops recording 'RemoteReply', -- upon string reception from a remote vim + 'SafeState', -- going to wait for a character 'SearchWrapped', -- after the search wrapped around 'SessionLoadPost', -- after loading a session file 'ShellCmdPost', -- after ":!cmd" diff --git a/src/nvim/edit.c b/src/nvim/edit.c index b8d2eca810..d980699162 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -1355,6 +1355,11 @@ void ins_redraw(bool ready) curbuf->b_changed_invalid = false; } + // Trigger SafeState if nothing is pending. + may_trigger_safestate(ready + && !ins_compl_active() + && !pum_visible()); + pum_check_clear(); show_cursor_info_later(false); if (must_redraw) { diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 89f5e92c33..6af79bfd21 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -943,6 +943,8 @@ theend: static int command_line_check(VimState *state) { + CommandLineState *s = (CommandLineState *)state; + redir_off = true; // Don't redirect the typed command. // Repeated, because a ":redir" inside // completion may switch it on. @@ -952,6 +954,9 @@ static int command_line_check(VimState *state) // that occurs while typing a command should // cause the command not to be executed. + // Trigger SafeState if nothing is pending. + may_trigger_safestate(s->xpc.xp_numfiles <= 0); + cursorcmd(); // set the cursor on the right spot ui_cursor_shape(); return 1; diff --git a/src/nvim/normal.c b/src/nvim/normal.c index e72a0fe385..253a3f288e 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -482,6 +482,40 @@ bool check_text_or_curbuf_locked(oparg_T *oap) return true; } +static bool was_safe = false; +static int not_safe_now = 0; + +/// Trigger SafeState if currently in s safe state, that is "safe" is TRUE and +/// there is no typeahead. +void may_trigger_safestate(bool safe) +{ + bool 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); + } +} + /// Normal state entry point. This is called on: /// /// - Startup, In this case the function never returns. @@ -1295,6 +1329,18 @@ static void normal_check_buffer_modified(NormalState *s) } } +/// If nothing is pending and we are going to wait for the user to +/// type a character, trigger SafeState. +static void normal_check_safe_state(NormalState *s) +{ + may_trigger_safestate(!finish_op + && s->oa.prev_opcount > 0 + && s->oa.prev_count0 == 0 + && s->oa.op_type == OP_NOP + && s->oa.regname == NUL + && restart_edit == 0); +} + static void normal_check_folds(NormalState *s) { // Include a closed fold completely in the Visual area. @@ -1387,6 +1433,9 @@ static int normal_check(VimState *state) } quit_more = false; + // it's not safe unless normal_check_safe_state() 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, // update cursor and redraw. @@ -1403,6 +1452,7 @@ static int normal_check(VimState *state) normal_check_text_changed(s); normal_check_window_scrolled(s); normal_check_buffer_modified(s); + normal_check_safe_state(s); // Updating diffs from changed() does not always work properly, // esp. updating folds. Do an update just before redrawing if |