mirror of
https://github.com/neovim/neovim.git
synced 2026-07-31 20:59:11 +00:00
`lib/queue.h` implements a basic queue. `event/queue.c` implements a specialized data structure on top of lib/queue.h; it is not a "normal" queue. Rename the specialized multi-level queue implemented in event/queue.c to "multiqueue", to avoid confusion when reading the code. Before this change one can eventually notice that "macros (uppercase symbols) are for the normal queue, lowercase operations are for the multi-level queue", but that is unnecessary friction for new developers (or existing developers just visiting this part of the codebase).
98 lines
2.5 KiB
C
98 lines
2.5 KiB
C
#include <assert.h>
|
|
|
|
#include "nvim/lib/kvec.h"
|
|
|
|
#include "nvim/ascii.h"
|
|
#include "nvim/state.h"
|
|
#include "nvim/vim.h"
|
|
#include "nvim/main.h"
|
|
#include "nvim/getchar.h"
|
|
#include "nvim/option_defs.h"
|
|
#include "nvim/ui.h"
|
|
#include "nvim/os/input.h"
|
|
|
|
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
|
# include "state.c.generated.h"
|
|
#endif
|
|
|
|
|
|
void state_enter(VimState *s)
|
|
{
|
|
for (;;) {
|
|
int check_result = s->check ? s->check(s) : 1;
|
|
|
|
if (!check_result) {
|
|
break;
|
|
} else if (check_result == -1) {
|
|
continue;
|
|
}
|
|
|
|
int key;
|
|
|
|
getkey:
|
|
if (char_avail() || using_script() || input_available()) {
|
|
// Don't block for events if there's a character already available for
|
|
// processing. Characters can come from mappings, scripts and other
|
|
// sources, so this scenario is very common.
|
|
key = safe_vgetc();
|
|
} else if (!multiqueue_empty(main_loop.events)) {
|
|
// Event was made available after the last multiqueue_process_events call
|
|
key = K_EVENT;
|
|
} else {
|
|
input_enable_events();
|
|
// Flush screen updates before blocking
|
|
ui_flush();
|
|
// Call `os_inchar` directly to block for events or user input without
|
|
// consuming anything from `input_buffer`(os/input.c) or calling the
|
|
// mapping engine. If an event was put into the queue, we send K_EVENT
|
|
// directly.
|
|
(void)os_inchar(NULL, 0, -1, 0);
|
|
input_disable_events();
|
|
key = !multiqueue_empty(main_loop.events) ? K_EVENT : safe_vgetc();
|
|
}
|
|
|
|
if (key == K_EVENT) {
|
|
may_sync_undo();
|
|
}
|
|
|
|
int execute_result = s->execute(s, key);
|
|
if (!execute_result) {
|
|
break;
|
|
} else if (execute_result == -1) {
|
|
goto getkey;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Return TRUE if in the current mode we need to use virtual.
|
|
int virtual_active(void)
|
|
{
|
|
// While an operator is being executed we return "virtual_op", because
|
|
// VIsual_active has already been reset, thus we can't check for "block"
|
|
// being used.
|
|
if (virtual_op != MAYBE) {
|
|
return virtual_op;
|
|
}
|
|
return ve_flags == VE_ALL
|
|
|| ((ve_flags & VE_BLOCK) && VIsual_active && VIsual_mode == Ctrl_V)
|
|
|| ((ve_flags & VE_INSERT) && (State & INSERT));
|
|
}
|
|
|
|
/// VISUAL, SELECTMODE and OP_PENDING State are never set, they are equal to
|
|
/// NORMAL State with a condition. This function returns the real State.
|
|
int get_real_state(void)
|
|
{
|
|
if (State & NORMAL) {
|
|
if (VIsual_active) {
|
|
if (VIsual_select) {
|
|
return SELECTMODE;
|
|
}
|
|
return VISUAL;
|
|
} else if (finish_op) {
|
|
return OP_PENDING;
|
|
}
|
|
}
|
|
return State;
|
|
}
|
|
|