To: vim_dev@googlegroups.com Subject: Patch 8.1.2053 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ 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 -- Bram@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 ///