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;
|
||||
}
|
||||
if (lowlevel) {
|
||||
input_enqueue_raw(cstr_as_string(keys_esc));
|
||||
input_enqueue_raw(keys_esc, strlen(keys_esc));
|
||||
} else {
|
||||
ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE),
|
||||
insert ? 0 : typebuf.tb_len, !typed, false);
|
||||
|
@ -154,7 +154,6 @@ void event_init(void)
|
||||
loop_init(&main_loop, NULL);
|
||||
resize_events = multiqueue_new_child(main_loop.events);
|
||||
|
||||
input_init();
|
||||
signal_init();
|
||||
// mspgack-rpc initialization
|
||||
channel_init();
|
||||
|
@ -882,7 +882,6 @@ void free_all_mem(void)
|
||||
|
||||
decor_free_all_mem();
|
||||
drawline_free_all_mem();
|
||||
input_free_all_mem();
|
||||
|
||||
if (ui_client_channel_id) {
|
||||
ui_client_free_all_mem();
|
||||
|
@ -33,7 +33,7 @@
|
||||
#include "nvim/state_defs.h"
|
||||
|
||||
#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 {
|
||||
kInputNone,
|
||||
@ -42,7 +42,10 @@ typedef enum {
|
||||
} InbufPollResult;
|
||||
|
||||
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 blocking = false;
|
||||
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"
|
||||
#endif
|
||||
|
||||
void input_init(void)
|
||||
{
|
||||
input_buffer = rbuffer_new(INPUT_BUFFER_SIZE + MAX_KEY_CODE_LEN);
|
||||
}
|
||||
|
||||
void input_start(void)
|
||||
{
|
||||
if (!read_stream.s.closed) {
|
||||
@ -78,13 +76,6 @@ void input_stop(void)
|
||||
rstream_may_close(&read_stream);
|
||||
}
|
||||
|
||||
#ifdef EXITFREE
|
||||
void input_free_all_mem(void)
|
||||
{
|
||||
rbuffer_free(input_buffer);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void cursorhold_event(void **argv)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
if (maxlen && rbuffer_size(input_buffer)) {
|
||||
if (maxlen && input_available()) {
|
||||
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.
|
||||
@ -161,11 +155,14 @@ int os_inchar(uint8_t *buf, int maxlen, int ms, int tb_change_cnt, MultiQueue *e
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (maxlen && rbuffer_size(input_buffer)) {
|
||||
if (maxlen && input_available()) {
|
||||
restart_cursorhold_wait(tb_change_cnt);
|
||||
// Safe to convert rbuffer_read to int, it will never overflow since we use
|
||||
// relatively small buffers.
|
||||
return (int)rbuffer_read(input_buffer, (char *)buf, (size_t)maxlen);
|
||||
// Safe to convert rbuffer_read to int, it will never overflow since
|
||||
// INPUT_BUFFER_SIZE fits in an int
|
||||
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
|
||||
@ -247,11 +244,28 @@ bool os_isatty(int fd)
|
||||
return uv_guess_handle(fd) == UV_TTY;
|
||||
}
|
||||
|
||||
void input_enqueue_raw(String keys)
|
||||
size_t input_available(void)
|
||||
{
|
||||
if (keys.size > 0) {
|
||||
rbuffer_write(input_buffer, keys.data, keys.size);
|
||||
return (size_t)(input_write_pos - input_read_pos);
|
||||
}
|
||||
|
||||
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)
|
||||
@ -259,7 +273,7 @@ size_t input_enqueue(String keys)
|
||||
const char *ptr = keys.data;
|
||||
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
|
||||
// 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,
|
||||
@ -272,7 +286,7 @@ size_t input_enqueue(String keys)
|
||||
|
||||
if (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;
|
||||
}
|
||||
|
||||
@ -293,11 +307,11 @@ size_t input_enqueue(String keys)
|
||||
|
||||
// copy the character, escaping K_SPECIAL
|
||||
if ((uint8_t)(*ptr) == K_SPECIAL) {
|
||||
rbuffer_write(input_buffer, (char *)&(uint8_t){ K_SPECIAL }, 1);
|
||||
rbuffer_write(input_buffer, (char *)&(uint8_t){ KS_SPECIAL }, 1);
|
||||
rbuffer_write(input_buffer, (char *)&(uint8_t){ KE_FILLER }, 1);
|
||||
input_enqueue_raw((char *)&(uint8_t){ K_SPECIAL }, 1);
|
||||
input_enqueue_raw((char *)&(uint8_t){ KS_SPECIAL }, 1);
|
||||
input_enqueue_raw((char *)&(uint8_t){ KE_FILLER }, 1);
|
||||
} else {
|
||||
rbuffer_write(input_buffer, ptr, 1);
|
||||
input_enqueue_raw(ptr, 1);
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
@ -422,7 +436,7 @@ static unsigned handle_mouse_event(const char **ptr, uint8_t *buf, unsigned bufs
|
||||
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);
|
||||
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;
|
||||
|
||||
size_t written = 3 + (size_t)(p - buf);
|
||||
rbuffer_write(input_buffer, (char *)buf, written);
|
||||
return written;
|
||||
input_enqueue_raw((char *)buf, written);
|
||||
}
|
||||
|
||||
/// @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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (at_eof) {
|
||||
input_eof = true;
|
||||
}
|
||||
|
||||
assert(rbuffer_space(input_buffer) >= rbuffer_size(buf));
|
||||
assert(input_space() >= rbuffer_size(buf));
|
||||
RBUFFER_UNTIL_EMPTY(buf, ptr, len) {
|
||||
(void)rbuffer_write(input_buffer, ptr, len);
|
||||
input_enqueue_raw(ptr, len);
|
||||
rbuffer_consumed(buf, len);
|
||||
}
|
||||
}
|
||||
@ -508,23 +516,24 @@ static void process_ctrl_c(void)
|
||||
return;
|
||||
}
|
||||
|
||||
size_t consume_count = 0;
|
||||
RBUFFER_EACH_REVERSE(input_buffer, c, i) {
|
||||
if ((uint8_t)c == Ctrl_C
|
||||
|| ((uint8_t)c == 'C' && i >= 3
|
||||
&& (uint8_t)(*rbuffer_get(input_buffer, i - 3)) == K_SPECIAL
|
||||
&& (uint8_t)(*rbuffer_get(input_buffer, i - 2)) == KS_MODIFIER
|
||||
&& (uint8_t)(*rbuffer_get(input_buffer, i - 1)) == MOD_MASK_CTRL)) {
|
||||
*rbuffer_get(input_buffer, i) = Ctrl_C;
|
||||
size_t available = input_available();
|
||||
ssize_t i;
|
||||
for (i = (ssize_t)available - 1; i >= 0; i--) {
|
||||
uint8_t c = (uint8_t)input_read_pos[i];
|
||||
if (c == Ctrl_C
|
||||
|| (c == 'C' && i >= 3
|
||||
&& (uint8_t)input_read_pos[i - 3] == K_SPECIAL
|
||||
&& (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;
|
||||
consume_count = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (got_int && consume_count) {
|
||||
if (got_int && i > 0) {
|
||||
// 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)
|
||||
{
|
||||
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
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user