state.c (9721B)
1 #include <stdbool.h> 2 #include <string.h> 3 4 #include "nvim/ascii_defs.h" 5 #include "nvim/autocmd.h" 6 #include "nvim/autocmd_defs.h" 7 #include "nvim/buffer_defs.h" 8 #include "nvim/drawscreen.h" 9 #include "nvim/eval.h" 10 #include "nvim/eval/typval.h" 11 #include "nvim/eval/typval_defs.h" 12 #include "nvim/event/defs.h" 13 #include "nvim/event/loop.h" 14 #include "nvim/event/multiqueue.h" 15 #include "nvim/ex_getln.h" 16 #include "nvim/getchar.h" 17 #include "nvim/globals.h" 18 #include "nvim/insexpand.h" 19 #include "nvim/keycodes.h" 20 #include "nvim/log.h" 21 #include "nvim/macros_defs.h" 22 #include "nvim/main.h" 23 #include "nvim/memory.h" 24 #include "nvim/option.h" 25 #include "nvim/option_vars.h" 26 #include "nvim/os/input.h" 27 #include "nvim/state.h" 28 #include "nvim/strings.h" 29 #include "nvim/types_defs.h" 30 #include "nvim/ui.h" 31 32 #include "state.c.generated.h" 33 34 void state_enter(VimState *s) 35 FUNC_ATTR_NONNULL_ALL 36 { 37 while (true) { 38 int check_result = s->check ? s->check(s) : 1; 39 40 if (!check_result) { 41 break; // Terminate this state. 42 } else if (check_result == -1) { 43 continue; // check() again. 44 } 45 // Execute this state. 46 47 int key; 48 49 getkey: 50 // Apply mappings first by calling vpeekc() directly. 51 // - If vpeekc() returns non-NUL, there is a character already available for processing, so 52 // don't block for events. vgetc() may still block, in case of an incomplete UTF-8 sequence. 53 // - If vpeekc() returns NUL, vgetc() will block, and there are three cases: 54 // - There is no input available. 55 // - All of available input maps to an empty string. 56 // - There is an incomplete mapping. 57 // A blocking wait for a character should only be done in the third case, which is the only 58 // case of the three where typebuf.tb_len > 0 after vpeekc() returns NUL. 59 if (vpeekc() != NUL || typebuf.tb_len > 0) { 60 key = safe_vgetc(); 61 } else if (!multiqueue_empty(main_loop.events)) { 62 // No input available and processing events may take time, flush now. 63 ui_flush(); 64 // Event was made available after the last multiqueue_process_events call 65 key = K_EVENT; 66 } else { 67 // Ensure the screen is fully updated before blocking for input. Because of the duality of 68 // redraw_later, this can't be done in command-line or when waiting for "Press ENTER". 69 // In many of those cases the redraw is expected AFTER the key press, while normally it should 70 // update the screen immediately. 71 if (must_redraw != 0 && !need_wait_return && (State & MODE_CMDLINE) == 0) { 72 update_screen(); 73 setcursor(); // put cursor back where it belongs 74 } 75 // Flush screen updates before blocking. 76 ui_flush(); 77 // Call `input_get` directly to block for events or user input without consuming anything from 78 // `os/input.c:input_buffer` or calling the mapping engine. 79 input_get(NULL, 0, -1, typebuf.tb_change_cnt, main_loop.events); 80 // If an event was put into the queue, we send K_EVENT directly. 81 if (!input_available() && !multiqueue_empty(main_loop.events)) { 82 key = K_EVENT; 83 } else { 84 goto getkey; 85 } 86 } 87 88 if (key == K_EVENT) { 89 // An event handler may use the value of reg_executing. 90 // Clear it if it should be cleared when getting the next character. 91 check_end_reg_executing(true); 92 may_sync_undo(); 93 } 94 95 #ifdef NVIM_LOG_DEBUG 96 char *keyname = key == K_EVENT ? "K_EVENT" : get_special_key_name(key, mod_mask); 97 DLOG("input: %s", keyname); 98 #endif 99 100 int execute_result = s->execute(s, key); 101 if (!execute_result) { 102 break; 103 } else if (execute_result == -1) { 104 goto getkey; 105 } 106 } 107 } 108 109 /// process events on main_loop, but interrupt if input is available 110 /// 111 /// This should be used to handle K_EVENT in states accepting input 112 /// otherwise bursts of events can block break checking indefinitely. 113 void state_handle_k_event(void) 114 { 115 while (true) { 116 Event event = multiqueue_get(main_loop.events); 117 if (event.handler) { 118 event.handler(event.argv); 119 } 120 121 if (multiqueue_empty(main_loop.events)) { 122 // don't breakcheck before return, caller should return to main-loop 123 // and handle input already. 124 return; 125 } 126 127 // TODO(bfredl): as an further micro-optimization, we could check whether 128 // event.handler already checked input. 129 os_breakcheck(); 130 if (input_available() || got_int) { 131 return; 132 } 133 } 134 } 135 136 /// Return true if in the current mode we need to use virtual. 137 bool virtual_active(win_T *wp) 138 { 139 // While an operator is being executed we return "virtual_op", because 140 // VIsual_active has already been reset, thus we can't check for "block" 141 // being used. 142 if (virtual_op != kNone) { 143 return virtual_op; 144 } 145 146 // In Terminal mode the cursor can be positioned anywhere by the application 147 if (State & MODE_TERMINAL) { 148 return true; 149 } 150 151 unsigned cur_ve_flags = get_ve_flags(wp); 152 153 return cur_ve_flags == kOptVeFlagAll 154 || ((cur_ve_flags & kOptVeFlagBlock) && VIsual_active && VIsual_mode == Ctrl_V) 155 || ((cur_ve_flags & kOptVeFlagInsert) && (State & MODE_INSERT)); 156 } 157 158 /// MODE_VISUAL, MODE_SELECT and MODE_OP_PENDING State are never set, they are 159 /// equal to MODE_NORMAL State with a condition. This function returns the real 160 /// State. 161 int get_real_state(void) 162 { 163 if (State & MODE_NORMAL) { 164 if (VIsual_active) { 165 if (VIsual_select) { 166 return MODE_SELECT; 167 } 168 return MODE_VISUAL; 169 } else if (finish_op) { 170 return MODE_OP_PENDING; 171 } 172 } 173 return State; 174 } 175 176 /// Returns the current mode as a string in "buf[MODE_MAX_LENGTH]", NUL 177 /// terminated. 178 /// The first character represents the major mode, the following ones the minor 179 /// ones. 180 void get_mode(char *buf) 181 FUNC_ATTR_NONNULL_ALL 182 { 183 int i = 0; 184 185 if (State == MODE_HITRETURN || State == MODE_ASKMORE || State == MODE_SETWSIZE 186 || ((State & MODE_CMDLINE) && get_cmdline_info()->one_key)) { 187 buf[i++] = 'r'; 188 if (State == MODE_ASKMORE) { 189 buf[i++] = 'm'; 190 } else if (State & MODE_CMDLINE) { 191 buf[i++] = '?'; 192 } 193 } else if (State == MODE_EXTERNCMD) { 194 buf[i++] = '!'; 195 } else if (State & MODE_INSERT) { 196 if (State & VREPLACE_FLAG) { 197 buf[i++] = 'R'; 198 buf[i++] = 'v'; 199 } else { 200 if (State & REPLACE_FLAG) { 201 buf[i++] = 'R'; 202 } else { 203 buf[i++] = 'i'; 204 } 205 } 206 if (ins_compl_active()) { 207 buf[i++] = 'c'; 208 } else if (ctrl_x_mode_not_defined_yet()) { 209 buf[i++] = 'x'; 210 } 211 } else if ((State & MODE_CMDLINE) || exmode_active) { 212 buf[i++] = 'c'; 213 if (exmode_active) { 214 buf[i++] = 'v'; 215 } 216 if ((State & MODE_CMDLINE) && cmdline_overstrike()) { 217 buf[i++] = 'r'; 218 } 219 } else if (State & MODE_TERMINAL) { 220 buf[i++] = 't'; 221 } else if (VIsual_active) { 222 if (VIsual_select) { 223 buf[i++] = (char)(VIsual_mode + 's' - 'v'); 224 } else { 225 buf[i++] = (char)VIsual_mode; 226 if (restart_VIsual_select) { 227 buf[i++] = 's'; 228 } 229 } 230 } else { 231 buf[i++] = 'n'; 232 if (finish_op) { 233 buf[i++] = 'o'; 234 // to be able to detect force-linewise/blockwise/charwise operations 235 buf[i++] = (char)motion_force; 236 } else if (curbuf->terminal) { 237 buf[i++] = 't'; 238 if (restart_edit == 'I') { 239 buf[i++] = 'T'; 240 } 241 } else if (restart_edit == 'I' || restart_edit == 'R' || restart_edit == 'V') { 242 buf[i++] = 'i'; 243 buf[i++] = (char)restart_edit; 244 } 245 } 246 247 buf[i] = NUL; 248 } 249 250 /// Fires a ModeChanged autocmd if appropriate. 251 void may_trigger_modechanged(void) 252 { 253 // Skip this when got_int is set, the autocommand will not be executed. 254 // Better trigger it next time. 255 if (!has_event(EVENT_MODECHANGED) || got_int) { 256 return; 257 } 258 259 char curr_mode[MODE_MAX_LENGTH]; 260 char pattern_buf[2 * MODE_MAX_LENGTH]; 261 262 get_mode(curr_mode); 263 if (strcmp(curr_mode, last_mode) == 0) { 264 return; 265 } 266 267 save_v_event_T save_v_event; 268 dict_T *v_event = get_v_event(&save_v_event); 269 tv_dict_add_str(v_event, S_LEN("new_mode"), curr_mode); 270 tv_dict_add_str(v_event, S_LEN("old_mode"), last_mode); 271 tv_dict_set_keys_readonly(v_event); 272 273 // concatenate modes in format "old_mode:new_mode" 274 vim_snprintf(pattern_buf, sizeof(pattern_buf), "%s:%s", last_mode, curr_mode); 275 276 apply_autocmds(EVENT_MODECHANGED, pattern_buf, NULL, false, curbuf); 277 STRCPY(last_mode, curr_mode); 278 279 restore_v_event(v_event, &save_v_event); 280 } 281 282 /// When true in a safe state when starting to wait for a character. 283 static bool was_safe = false; 284 285 /// Return whether currently it is safe, assuming it was safe before (high level 286 /// state didn't change). 287 static bool is_safe_now(void) 288 { 289 return stuff_empty() 290 && typebuf.tb_len == 0 291 && !using_script() 292 && !global_busy 293 && !debug_mode; 294 } 295 296 /// Trigger SafeState if currently in a safe state, that is "safe" is true and 297 /// there is no typeahead. 298 void may_trigger_safestate(bool safe) 299 { 300 bool is_safe = safe && is_safe_now(); 301 302 if (was_safe != is_safe) { 303 // Only log when the state changes, otherwise it happens at nearly 304 // every key stroke. 305 DLOG(is_safe ? "SafeState: Start triggering" : "SafeState: Stop triggering"); 306 } 307 if (is_safe) { 308 apply_autocmds(EVENT_SAFESTATE, NULL, NULL, false, curbuf); 309 } 310 was_safe = is_safe; 311 } 312 313 /// Something changed which causes the state possibly to be unsafe, e.g. a 314 /// character was typed. It will remain unsafe until the next call to 315 /// may_trigger_safestate(). 316 void state_no_longer_safe(const char *reason) 317 { 318 if (was_safe && reason != NULL) { 319 DLOG("SafeState reset: %s", reason); 320 } 321 was_safe = false; 322 } 323 324 bool get_was_safe_state(void) 325 { 326 return was_safe; 327 }