mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
refactor(input): don't use a ring for input
Since paste data is handled via a separate channel, the data processed via `input_buffer` is typically just explicit keys as typed in by the user. Therefore it should be fine to use `memmove()` to always put the remaining data in front when refilling the buffer.
This commit is contained in:
parent
1d091e52f0
commit
6d6974eae6
@ -313,7 +313,7 @@ void nvim_feedkeys(String keys, String mode, Boolean escape_ks)
|
|||||||
keys_esc = keys.data;
|
keys_esc = keys.data;
|
||||||
}
|
}
|
||||||
if (lowlevel) {
|
if (lowlevel) {
|
||||||
input_enqueue_raw(cstr_as_string(keys_esc));
|
input_enqueue_raw(keys_esc, strlen(keys_esc));
|
||||||
} else {
|
} else {
|
||||||
ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
|
ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
|
||||||
insert ? 0 : typebuf.tb_len, !typed, false);
|
insert ? 0 : typebuf.tb_len, !typed, false);
|
||||||
|
@ -154,7 +154,6 @@ void event_init(void)
|
|||||||
loop_init(&main_loop, NULL);
|
loop_init(&main_loop, NULL);
|
||||||
resize_events = multiqueue_new_child(main_loop.events);
|
resize_events = multiqueue_new_child(main_loop.events);
|
||||||
|
|
||||||
input_init();
|
|
||||||
signal_init();
|
signal_init();
|
||||||
// mspgack-rpc initialization
|
// mspgack-rpc initialization
|
||||||
channel_init();
|
channel_init();
|
||||||
|
@ -882,7 +882,6 @@ void free_all_mem(void)
|
|||||||
|
|
||||||
decor_free_all_mem();
|
decor_free_all_mem();
|
||||||
drawline_free_all_mem();
|
drawline_free_all_mem();
|
||||||
input_free_all_mem();
|
|
||||||
|
|
||||||
if (ui_client_channel_id) {
|
if (ui_client_channel_id) {
|
||||||
ui_client_free_all_mem();
|
ui_client_free_all_mem();
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
#include "nvim/state_defs.h"
|
#include "nvim/state_defs.h"
|
||||||
|
|
||||||
#define READ_BUFFER_SIZE 0xfff
|
#define READ_BUFFER_SIZE 0xfff
|
||||||
#define INPUT_BUFFER_SIZE (READ_BUFFER_SIZE * 4)
|
#define INPUT_BUFFER_SIZE ((READ_BUFFER_SIZE * 4) + MAX_KEY_CODE_LEN)
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
kInputNone,
|
kInputNone,
|
||||||
@ -42,7 +42,10 @@ typedef enum {
|
|||||||
} InbufPollResult;
|
} InbufPollResult;
|
||||||
|
|
||||||
static RStream read_stream = { .s.closed = true }; // Input before UI starts.
|
static RStream read_stream = { .s.closed = true }; // Input before UI starts.
|
||||||
static RBuffer *input_buffer = NULL;
|
static char input_buffer[INPUT_BUFFER_SIZE];
|
||||||
|
static char *input_read_pos = input_buffer;
|
||||||
|
static char *input_write_pos = input_buffer;
|
||||||
|
|
||||||
static bool input_eof = false;
|
static bool input_eof = false;
|
||||||
static bool blocking = false;
|
static bool blocking = false;
|
||||||
static int cursorhold_time = 0; ///< time waiting for CursorHold event
|
static int cursorhold_time = 0; ///< time waiting for CursorHold event
|
||||||
@ -52,11 +55,6 @@ static int cursorhold_tb_change_cnt = 0; ///< tb_change_cnt when waiting starte
|
|||||||
# include "os/input.c.generated.h"
|
# include "os/input.c.generated.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void input_init(void)
|
|
||||||
{
|
|
||||||
input_buffer = rbuffer_new(INPUT_BUFFER_SIZE + MAX_KEY_CODE_LEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
void input_start(void)
|
void input_start(void)
|
||||||
{
|
{
|
||||||
if (!read_stream.s.closed) {
|
if (!read_stream.s.closed) {
|
||||||
@ -78,13 +76,6 @@ void input_stop(void)
|
|||||||
rstream_may_close(&read_stream);
|
rstream_may_close(&read_stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef EXITFREE
|
|
||||||
void input_free_all_mem(void)
|
|
||||||
{
|
|
||||||
rbuffer_free(input_buffer);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void cursorhold_event(void **argv)
|
static void cursorhold_event(void **argv)
|
||||||
{
|
{
|
||||||
event_T event = State & MODE_INSERT ? EVENT_CURSORHOLDI : EVENT_CURSORHOLD;
|
event_T event = State & MODE_INSERT ? EVENT_CURSORHOLDI : EVENT_CURSORHOLD;
|
||||||
@ -119,9 +110,12 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *e
|
|||||||
restart_cursorhold_wait(tb_change_cnt);
|
restart_cursorhold_wait(tb_change_cnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (maxlen && rbuffer_size(input_buffer)) {
|
if (maxlen && input_available()) {
|
||||||
restart_cursorhold_wait(tb_change_cnt);
|
restart_cursorhold_wait(tb_change_cnt);
|
||||||
return (int)rbuffer_read(input_buffer, (char *)buf, (size_t)maxlen);
|
size_t to_read = MIN((size_t)maxlen, input_available());
|
||||||
|
memcpy(buf, input_read_pos, to_read);
|
||||||
|
input_read_pos += to_read;
|
||||||
|
return (int)to_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No risk of a UI flood, so disable CTRL-C "interrupt" behavior if it's mapped.
|
// No risk of a UI flood, so disable CTRL-C "interrupt" behavior if it's mapped.
|
||||||
@ -161,11 +155,14 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *e
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (maxlen && rbuffer_size(input_buffer)) {
|
if (maxlen && input_available()) {
|
||||||
restart_cursorhold_wait(tb_change_cnt);
|
restart_cursorhold_wait(tb_change_cnt);
|
||||||
// Safe to convert rbuffer_read to int, it will never overflow since we use
|
// Safe to convert rbuffer_read to int, it will never overflow since
|
||||||
// relatively small buffers.
|
// INPUT_BUFFER_SIZE fits in an int
|
||||||
return (int)rbuffer_read(input_buffer, (char *)buf, (size_t)maxlen);
|
size_t to_read = MIN((size_t)maxlen, input_available());
|
||||||
|
memcpy(buf, input_read_pos, to_read);
|
||||||
|
input_read_pos += to_read;
|
||||||
|
return (int)to_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there are events, return the keys directly
|
// If there are events, return the keys directly
|
||||||
@ -247,11 +244,28 @@ bool os_isatty(int fd)
|
|||||||
return uv_guess_handle(fd) == UV_TTY;
|
return uv_guess_handle(fd) == UV_TTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
void input_enqueue_raw(String keys)
|
size_t input_available(void)
|
||||||
{
|
{
|
||||||
if (keys.size > 0) {
|
return (size_t)(input_write_pos - input_read_pos);
|
||||||
rbuffer_write(input_buffer, keys.data, keys.size);
|
}
|
||||||
|
|
||||||
|
static size_t input_space(void)
|
||||||
|
{
|
||||||
|
return (size_t)(input_buffer + INPUT_BUFFER_SIZE - input_write_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void input_enqueue_raw(const char *data, size_t size)
|
||||||
|
{
|
||||||
|
if (input_read_pos > input_buffer) {
|
||||||
|
size_t available = input_available();
|
||||||
|
memmove(input_buffer, input_read_pos, available);
|
||||||
|
input_read_pos = input_buffer;
|
||||||
|
input_write_pos = input_buffer + available;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t to_write = MIN(size, input_space());
|
||||||
|
memcpy(input_write_pos, data, to_write);
|
||||||
|
input_write_pos += to_write;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t input_enqueue(String keys)
|
size_t input_enqueue(String keys)
|
||||||
@ -259,7 +273,7 @@ size_t input_enqueue(String keys)
|
|||||||
const char *ptr = keys.data;
|
const char *ptr = keys.data;
|
||||||
const char *end = ptr + keys.size;
|
const char *end = ptr + keys.size;
|
||||||
|
|
||||||
while (rbuffer_space(input_buffer) >= 19 && ptr < end) {
|
while (input_space() >= 19 && ptr < end) {
|
||||||
// A "<x>" form occupies at least 1 characters, and produces up
|
// A "<x>" form occupies at least 1 characters, and produces up
|
||||||
// to 19 characters (1 + 5 * 3 for the char and 3 for a modifier).
|
// to 19 characters (1 + 5 * 3 for the char and 3 for a modifier).
|
||||||
// In the case of K_SPECIAL (0x80), 3 bytes are escaped and needed,
|
// In the case of K_SPECIAL (0x80), 3 bytes are escaped and needed,
|
||||||
@ -272,7 +286,7 @@ size_t input_enqueue(String keys)
|
|||||||
|
|
||||||
if (new_size) {
|
if (new_size) {
|
||||||
new_size = handle_mouse_event(&ptr, buf, new_size);
|
new_size = handle_mouse_event(&ptr, buf, new_size);
|
||||||
rbuffer_write(input_buffer, (char *)buf, new_size);
|
input_enqueue_raw((char *)buf, new_size);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,11 +307,11 @@ size_t input_enqueue(String keys)
|
|||||||
|
|
||||||
// copy the character, escaping K_SPECIAL
|
// copy the character, escaping K_SPECIAL
|
||||||
if ((uint8_t)(*ptr) == K_SPECIAL) {
|
if ((uint8_t)(*ptr) == K_SPECIAL) {
|
||||||
rbuffer_write(input_buffer, (char *)&(uint8_t){ K_SPECIAL }, 1);
|
input_enqueue_raw((char *)&(uint8_t){ K_SPECIAL }, 1);
|
||||||
rbuffer_write(input_buffer, (char *)&(uint8_t){ KS_SPECIAL }, 1);
|
input_enqueue_raw((char *)&(uint8_t){ KS_SPECIAL }, 1);
|
||||||
rbuffer_write(input_buffer, (char *)&(uint8_t){ KE_FILLER }, 1);
|
input_enqueue_raw((char *)&(uint8_t){ KE_FILLER }, 1);
|
||||||
} else {
|
} else {
|
||||||
rbuffer_write(input_buffer, ptr, 1);
|
input_enqueue_raw(ptr, 1);
|
||||||
}
|
}
|
||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
@ -422,7 +436,7 @@ static unsigned handle_mouse_event(const char **ptr, uint8_t *buf, unsigned bufs
|
|||||||
return bufsize;
|
return bufsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t input_enqueue_mouse(int code, uint8_t modifier, int grid, int row, int col)
|
void input_enqueue_mouse(int code, uint8_t modifier, int grid, int row, int col)
|
||||||
{
|
{
|
||||||
modifier |= check_multiclick(code, grid, row, col);
|
modifier |= check_multiclick(code, grid, row, col);
|
||||||
uint8_t buf[7];
|
uint8_t buf[7];
|
||||||
@ -442,8 +456,7 @@ size_t input_enqueue_mouse(int code, uint8_t modifier, int grid, int row, int co
|
|||||||
mouse_col = col;
|
mouse_col = col;
|
||||||
|
|
||||||
size_t written = 3 + (size_t)(p - buf);
|
size_t written = 3 + (size_t)(p - buf);
|
||||||
rbuffer_write(input_buffer, (char *)buf, written);
|
input_enqueue_raw((char *)buf, written);
|
||||||
return written;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @return true if the main loop is blocked and waiting for input.
|
/// @return true if the main loop is blocked and waiting for input.
|
||||||
@ -484,20 +497,15 @@ static InbufPollResult inbuf_poll(int ms, MultiQueue *events)
|
|||||||
return input_eof ? kInputEof : kInputNone;
|
return input_eof ? kInputEof : kInputNone;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool input_available(void)
|
|
||||||
{
|
|
||||||
return rbuffer_size(input_buffer) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void input_read_cb(RStream *stream, RBuffer *buf, size_t c, void *data, bool at_eof)
|
static void input_read_cb(RStream *stream, RBuffer *buf, size_t c, void *data, bool at_eof)
|
||||||
{
|
{
|
||||||
if (at_eof) {
|
if (at_eof) {
|
||||||
input_eof = true;
|
input_eof = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(rbuffer_space(input_buffer) >= rbuffer_size(buf));
|
assert(input_space() >= rbuffer_size(buf));
|
||||||
RBUFFER_UNTIL_EMPTY(buf, ptr, len) {
|
RBUFFER_UNTIL_EMPTY(buf, ptr, len) {
|
||||||
(void)rbuffer_write(input_buffer, ptr, len);
|
input_enqueue_raw(ptr, len);
|
||||||
rbuffer_consumed(buf, len);
|
rbuffer_consumed(buf, len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -508,23 +516,24 @@ static void process_ctrl_c(void)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t consume_count = 0;
|
size_t available = input_available();
|
||||||
RBUFFER_EACH_REVERSE(input_buffer, c, i) {
|
ssize_t i;
|
||||||
if ((uint8_t)c == Ctrl_C
|
for (i = (ssize_t)available - 1; i >= 0; i--) {
|
||||||
|| ((uint8_t)c == 'C' && i >= 3
|
uint8_t c = (uint8_t)input_read_pos[i];
|
||||||
&& (uint8_t)(*rbuffer_get(input_buffer, i - 3)) == K_SPECIAL
|
if (c == Ctrl_C
|
||||||
&& (uint8_t)(*rbuffer_get(input_buffer, i - 2)) == KS_MODIFIER
|
|| (c == 'C' && i >= 3
|
||||||
&& (uint8_t)(*rbuffer_get(input_buffer, i - 1)) == MOD_MASK_CTRL)) {
|
&& (uint8_t)input_read_pos[i - 3] == K_SPECIAL
|
||||||
*rbuffer_get(input_buffer, i) = Ctrl_C;
|
&& (uint8_t)input_read_pos[i - 2] == KS_MODIFIER
|
||||||
|
&& (uint8_t)input_read_pos[i - 1] == MOD_MASK_CTRL)) {
|
||||||
|
input_read_pos[i] = Ctrl_C;
|
||||||
got_int = true;
|
got_int = true;
|
||||||
consume_count = i;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (got_int && consume_count) {
|
if (got_int && i > 0) {
|
||||||
// Remove all unprocessed input (typeahead) before the CTRL-C.
|
// Remove all unprocessed input (typeahead) before the CTRL-C.
|
||||||
rbuffer_consumed(input_buffer, consume_count);
|
input_read_pos += i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -548,7 +557,7 @@ static int push_event_key(uint8_t *buf, int maxlen)
|
|||||||
bool os_input_ready(MultiQueue *events)
|
bool os_input_ready(MultiQueue *events)
|
||||||
{
|
{
|
||||||
return (typebuf_was_filled // API call filled typeahead
|
return (typebuf_was_filled // API call filled typeahead
|
||||||
|| rbuffer_size(input_buffer) // Input buffer filled
|
|| input_available() // Input buffer filled
|
||||||
|| pending_events(events)); // Events must be processed
|
|| pending_events(events)); // Events must be processed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user