aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThiago de Arruda <tpadilha84@gmail.com>2014-10-18 08:38:15 -0300
committerThiago de Arruda <tpadilha84@gmail.com>2014-10-18 12:51:35 -0300
commit42112e04a999c0f289939fce3142ef2c2517110a (patch)
tree5f2a1dd7395461be1bc6df7aa259fa8dd63008d3
parent68de5d79a243fecc9ef256d9d0356f8541aa3821 (diff)
downloadrneovim-42112e04a999c0f289939fce3142ef2c2517110a.tar.gz
rneovim-42112e04a999c0f289939fce3142ef2c2517110a.tar.bz2
rneovim-42112e04a999c0f289939fce3142ef2c2517110a.zip
ui: Refactor input buffer handling
All input buffer code was moved to os/input.c, and `inbuf` is now a `RBuffer` instance(which abstracts static buffer manipulation).
-rw-r--r--src/nvim/buffer_defs.h6
-rw-r--r--src/nvim/getchar.c24
-rw-r--r--src/nvim/mbyte.c44
-rw-r--r--src/nvim/os/input.c108
-rw-r--r--src/nvim/os/input.h2
-rw-r--r--src/nvim/ui.c242
-rw-r--r--src/nvim/vim.h4
7 files changed, 100 insertions, 330 deletions
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 84d55fb730..6d097010ac 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -21,6 +21,8 @@
#include "nvim/eval_defs.h"
// for proftime_T
#include "nvim/profile.h"
+// for String
+#include "nvim/api/private/defs.h"
/*
* Flags for w_valid.
@@ -311,9 +313,7 @@ typedef struct {
int old_mod_mask;
buffheader_T save_readbuf1;
buffheader_T save_readbuf2;
-#ifdef USE_INPUT_BUF
- char_u *save_inputbuf;
-#endif
+ String save_inputbuf;
} tasave_T;
/*
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index c3f6e2c2b6..fd60664b7b 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -50,6 +50,7 @@
#include "nvim/ui.h"
#include "nvim/undo.h"
#include "nvim/os/event.h"
+#include "nvim/os/input.h"
/*
* These buffers are used for storing:
@@ -1201,9 +1202,7 @@ void save_typeahead(tasave_T *tp)
readbuf1.bh_first.b_next = NULL;
tp->save_readbuf2 = readbuf2;
readbuf2.bh_first.b_next = NULL;
-# ifdef USE_INPUT_BUF
- tp->save_inputbuf = get_input_buf();
-# endif
+ tp->save_inputbuf = input_buffer_save();
}
/*
@@ -1224,9 +1223,7 @@ void restore_typeahead(tasave_T *tp)
readbuf1 = tp->save_readbuf1;
free_buff(&readbuf2);
readbuf2 = tp->save_readbuf2;
-# ifdef USE_INPUT_BUF
- set_input_buf(tp->save_inputbuf);
-# endif
+ input_buffer_restore(tp->save_inputbuf);
}
/*
@@ -2551,21 +2548,6 @@ fix_input_buffer (
return len;
}
-#if defined(USE_INPUT_BUF) || defined(PROTO)
-/*
- * Return TRUE when bytes are in the input buffer or in the typeahead buffer.
- * Normally the input buffer would be sufficient, but feedkeys() may insert
- * characters in the typeahead buffer while we are waiting for input to arrive.
- */
-int input_available(void)
-{
- return !vim_is_input_buf_empty()
- || typebuf_was_filled
- ;
-}
-
-#endif
-
/*
* map[!] : show all key mappings
* map[!] {lhs} : show key mapping for {lhs}
diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c
index 7ba4409180..cb33c2e666 100644
--- a/src/nvim/mbyte.c
+++ b/src/nvim/mbyte.c
@@ -3803,50 +3803,6 @@ int convert_setup_ext(vimconv_T *vcp, char_u *from, bool from_unicode_is_utf8,
return OK;
}
-#if defined(FEAT_GUI) || defined(WIN3264) || defined(PROTO)
-/*
- * Do conversion on typed input characters in-place.
- * The input and output are not NUL terminated!
- * Returns the length after conversion.
- */
-int convert_input(char_u *ptr, int len, int maxlen)
-{
- return convert_input_safe(ptr, len, maxlen, NULL, NULL);
-}
-#endif
-
-/*
- * Like convert_input(), but when there is an incomplete byte sequence at the
- * end return that as an allocated string in "restp" and set "*restlenp" to
- * the length. If "restp" is NULL it is not used.
- */
-int convert_input_safe(char_u *ptr, int len, int maxlen, char_u **restp,
- int *restlenp)
-{
- char_u *d;
- int dlen = len;
- int unconvertlen = 0;
-
- d = string_convert_ext(&input_conv, ptr, &dlen,
- restp == NULL ? NULL : &unconvertlen);
- if (d != NULL) {
- if (dlen <= maxlen) {
- if (unconvertlen > 0) {
- /* Move the unconverted characters to allocated memory. */
- *restp = xmalloc(unconvertlen);
- memmove(*restp, ptr + len - unconvertlen, unconvertlen);
- *restlenp = unconvertlen;
- }
- memmove(ptr, d, dlen);
- } else
- /* result is too long, keep the unconverted text (the caller must
- * have done something wrong!) */
- dlen = len;
- free(d);
- }
- return dlen;
-}
-
/*
* Convert text "ptr[*lenp]" according to "vcp".
* Returns the result in allocated memory and sets "*lenp".
diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c
index 511dfd7b07..71b590ceaa 100644
--- a/src/nvim/os/input.c
+++ b/src/nvim/os/input.c
@@ -4,6 +4,7 @@
#include <uv.h>
+#include "nvim/api/private/defs.h"
#include "nvim/os/input.h"
#include "nvim/os/event.h"
#include "nvim/os/signal.h"
@@ -12,11 +13,15 @@
#include "nvim/ascii.h"
#include "nvim/vim.h"
#include "nvim/ui.h"
+#include "nvim/memory.h"
+#include "nvim/keymap.h"
+#include "nvim/mbyte.h"
#include "nvim/fileio.h"
#include "nvim/getchar.h"
#include "nvim/term.h"
-#define READ_BUFFER_SIZE 256
+#define READ_BUFFER_SIZE 0xffff
+#define INPUT_BUFFER_SIZE 4096
typedef enum {
kInputNone,
@@ -25,6 +30,7 @@ typedef enum {
} InbufPollResult;
static RStream *read_stream;
+static RBuffer *read_buffer, *input_buffer;
static bool eof = false, started_reading = false;
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -35,12 +41,15 @@ static bool eof = false, started_reading = false;
void input_init(void)
{
+ input_buffer = rbuffer_new(INPUT_BUFFER_SIZE + MAX_KEY_CODE_LEN);
+
if (embedded_mode) {
return;
}
+ read_buffer = rbuffer_new(READ_BUFFER_SIZE);
read_stream = rstream_new(read_cb,
- rbuffer_new(READ_BUFFER_SIZE),
+ read_buffer,
NULL,
NULL);
rstream_set_file(read_stream, read_cmd_fd);
@@ -66,17 +75,6 @@ void input_stop(void)
rstream_stop(read_stream);
}
-// Copies (at most `count`) of was read from `read_cmd_fd` into `buf`
-uint32_t input_read(char *buf, uint32_t count)
-{
- if (embedded_mode) {
- return 0;
- }
-
- return rstream_read(read_stream, buf, count);
-}
-
-
// Low level input function.
int os_inchar(uint8_t *buf, int maxlen, int32_t ms, int tb_change_cnt)
{
@@ -121,7 +119,8 @@ int os_inchar(uint8_t *buf, int maxlen, int32_t ms, int tb_change_cnt)
return 0;
}
- return read_from_input_buf(buf, (int64_t)maxlen);
+ convert_input();
+ return rbuffer_read(input_buffer, (char *)buf, maxlen);
}
// Check if a character is available for reading
@@ -135,7 +134,7 @@ bool os_char_avail(void)
void os_breakcheck(void)
{
if (curr_tmode == TMODE_RAW && input_poll(0))
- fill_input_buf(false);
+ convert_input();
}
/// Test whether a file descriptor refers to a terminal.
@@ -147,6 +146,27 @@ bool os_isatty(int fd)
return uv_guess_handle(fd) == UV_TTY;
}
+/// Return the contents of the input buffer and make it empty. The returned
+/// pointer must be passed to `input_buffer_restore()` later.
+String input_buffer_save(void)
+{
+ size_t inbuf_size = rbuffer_pending(input_buffer);
+ String rv = {
+ .data = xmemdup(rbuffer_data(input_buffer), inbuf_size),
+ .size = inbuf_size
+ };
+ rbuffer_consumed(input_buffer, inbuf_size);
+ return rv;
+}
+
+/// Restore the contents of the input buffer and free `str`
+void input_buffer_restore(String str)
+{
+ rbuffer_consumed(input_buffer, rbuffer_pending(input_buffer));
+ rbuffer_write(input_buffer, str.data, str.size);
+ free(str.data);
+}
+
static bool input_poll(int32_t ms)
{
if (embedded_mode) {
@@ -165,7 +185,7 @@ static bool input_poll(int32_t ms)
// This is a replacement for the old `WaitForChar` function in os_unix.c
static InbufPollResult inbuf_poll(int32_t ms)
{
- if (input_available()) {
+ if (typebuf_was_filled || rbuffer_pending(input_buffer)) {
return kInputAvail;
}
@@ -213,6 +233,60 @@ static void read_cb(RStream *rstream, void *data, bool at_eof)
started_reading = true;
}
+static void convert_input(void)
+{
+ if (!rbuffer_available(input_buffer)) {
+ // No input buffer space
+ return;
+ }
+
+ bool convert = input_conv.vc_type != CONV_NONE;
+ // Set unconverted data/length
+ char *data = rbuffer_data(read_buffer);
+ size_t data_length = rbuffer_pending(read_buffer);
+ size_t converted_length = data_length;
+
+ if (convert) {
+ // Perform input conversion according to `input_conv`
+ size_t unconverted_length;
+ data = (char *)string_convert_ext(&input_conv,
+ (uint8_t *)data,
+ (int *)&converted_length,
+ (int *)&unconverted_length);
+ data_length = rbuffer_pending(read_buffer) - unconverted_length;
+ }
+
+ // Write processed data to input buffer
+ size_t consumed = rbuffer_write(input_buffer, data, data_length);
+ // Adjust raw buffer pointers
+ rbuffer_consumed(read_buffer, consumed);
+
+ if (convert) {
+ // data points to memory allocated by `string_convert_ext`, free it.
+ free(data);
+ }
+
+ if (!ctrl_c_interrupts) {
+ return;
+ }
+
+ char *inbuf = rbuffer_data(input_buffer);
+ size_t count = rbuffer_pending(input_buffer), consume_count = 0;
+
+ for (int i = count - 1; i >= 0; i--) {
+ if (inbuf[i] == 3) {
+ consume_count = i + 1;
+ break;
+ }
+ }
+
+ if (consume_count) {
+ // Remove everything typed before the CTRL-C
+ rbuffer_consumed(input_buffer, consume_count);
+ got_int = true;
+ }
+}
+
static int push_event_key(uint8_t *buf, int maxlen)
{
static const uint8_t key[3] = { K_SPECIAL, KS_EXTRA, KE_EVENT };
@@ -228,7 +302,7 @@ static int push_event_key(uint8_t *buf, int maxlen)
}
// Check if there's pending input
-bool input_ready(void)
+static bool input_ready(void)
{
return rstream_pending(read_stream) > 0 || eof;
}
diff --git a/src/nvim/os/input.h b/src/nvim/os/input.h
index 7543950b4f..5902677a35 100644
--- a/src/nvim/os/input.h
+++ b/src/nvim/os/input.h
@@ -4,6 +4,8 @@
#include <stdint.h>
#include <stdbool.h>
+#include "nvim/api/private/defs.h"
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "os/input.h.generated.h"
#endif
diff --git a/src/nvim/ui.c b/src/nvim/ui.c
index d51fbd162b..2c5f7158f6 100644
--- a/src/nvim/ui.c
+++ b/src/nvim/ui.c
@@ -228,247 +228,6 @@ void ui_breakcheck(void)
* for them.
*/
-
-/*****************************************************************************
- * Functions that handle the input buffer.
- * This is used for any GUI version, and the unix terminal version.
- *
- * For Unix, the input characters are buffered to be able to check for a
- * CTRL-C. This should be done with signals, but I don't know how to do that
- * in a portable way for a tty in RAW mode.
- *
- * For the client-server code in the console the received keys are put in the
- * input buffer.
- */
-
-#if defined(USE_INPUT_BUF) || defined(PROTO)
-
-/*
- * Internal typeahead buffer. Includes extra space for long key code
- * descriptions which would otherwise overflow. The buffer is considered full
- * when only this extra space (or part of it) remains.
- */
-# define INBUFLEN 4096
-
-static char_u inbuf[INBUFLEN + MAX_KEY_CODE_LEN];
-static int inbufcount = 0; /* number of chars in inbuf[] */
-
-/*
- * vim_is_input_buf_full(), vim_is_input_buf_empty(), add_to_input_buf(), and
- * trash_input_buf() are functions for manipulating the input buffer. These
- * are used by the gui_* calls when a GUI is used to handle keyboard input.
- */
-
-int vim_is_input_buf_full(void)
-{
- return inbufcount >= INBUFLEN;
-}
-
-int vim_is_input_buf_empty(void)
-{
- return inbufcount == 0;
-}
-
-/*
- * Return the current contents of the input buffer and make it empty.
- * The returned pointer must be passed to set_input_buf() later.
- */
-char_u *get_input_buf(void)
-{
- /* We use a growarray to store the data pointer and the length. */
- garray_T *gap = xmalloc(sizeof(garray_T));
- /* Add one to avoid a zero size. */
- gap->ga_data = xmalloc(inbufcount + 1);
- if (gap->ga_data != NULL)
- memmove(gap->ga_data, inbuf, (size_t)inbufcount);
- gap->ga_len = inbufcount;
-
- trash_input_buf();
- return (char_u *)gap;
-}
-
-/*
- * Restore the input buffer with a pointer returned from get_input_buf().
- * The allocated memory is freed, this only works once!
- */
-void set_input_buf(char_u *p)
-{
- garray_T *gap = (garray_T *)p;
-
- if (gap != NULL) {
- if (gap->ga_data != NULL) {
- memmove(inbuf, gap->ga_data, gap->ga_len);
- inbufcount = gap->ga_len;
- free(gap->ga_data);
- }
- free(gap);
- }
-}
-
-#if defined(FEAT_GUI) \
- || defined(FEAT_MOUSE_GPM) || defined(FEAT_SYSMOUSE) \
- || defined(FEAT_XCLIPBOARD) || defined(PROTO)
-/*
- * Add the given bytes to the input buffer
- * Special keys start with CSI. A real CSI must have been translated to
- * CSI KS_EXTRA KE_CSI. K_SPECIAL doesn't require translation.
- */
-void add_to_input_buf(char_u *s, int len)
-{
- if (inbufcount + len > INBUFLEN + MAX_KEY_CODE_LEN)
- return; /* Shouldn't ever happen! */
-
- if ((State & (INSERT|CMDLINE)) && hangul_input_state_get())
- if ((len = hangul_input_process(s, len)) == 0)
- return;
-
- while (len--)
- inbuf[inbufcount++] = *s++;
-}
-#endif
-
-#if ((defined(FEAT_XIM) || defined(FEAT_DND)) && defined(FEAT_GUI_GTK)) \
- || defined(FEAT_GUI_MSWIN) \
- || defined(FEAT_GUI_MAC) \
- || defined(FEAT_MBYTE_IME) \
- || defined(FEAT_GUI) \
- || defined(PROTO)
-/*
- * Add "str[len]" to the input buffer while escaping CSI bytes.
- */
-void add_to_input_buf_csi(char_u *str, int len) {
- int i;
- char_u buf[2];
-
- for (i = 0; i < len; ++i) {
- add_to_input_buf(str + i, 1);
- if (str[i] == CSI) {
- /* Turn CSI into K_CSI. */
- buf[0] = KS_EXTRA;
- buf[1] = (int)KE_CSI;
- add_to_input_buf(buf, 2);
- }
- }
-}
-
-#endif
-
-/* Remove everything from the input buffer. Called when ^C is found */
-void trash_input_buf(void)
-{
- inbufcount = 0;
-}
-
-/*
- * Read as much data from the input buffer as possible up to maxlen, and store
- * it in buf.
- * Note: this function used to be Read() in unix.c
- */
-int read_from_input_buf(char_u *buf, long maxlen)
-{
- if (inbufcount == 0) /* if the buffer is empty, fill it */
- fill_input_buf(true);
- if (maxlen > inbufcount)
- maxlen = inbufcount;
- memmove(buf, inbuf, (size_t)maxlen);
- inbufcount -= maxlen;
- if (inbufcount)
- memmove(inbuf, inbuf + maxlen, (size_t)inbufcount);
- return (int)maxlen;
-}
-
-void fill_input_buf(bool exit_on_error)
-{
-#if defined(UNIX) || defined(MACOS_X_UNIX)
- int len;
- int try;
- static char_u *rest = NULL; /* unconverted rest of previous read */
- static int restlen = 0;
- int unconverted;
-#endif
-
-#if defined(UNIX) || defined(MACOS_X_UNIX)
- if (vim_is_input_buf_full())
- return;
- /*
- * Fill_input_buf() is only called when we really need a character.
- * If we can't get any, but there is some in the buffer, just return.
- * If we can't get any, and there isn't any in the buffer, we give up and
- * exit Vim.
- */
-
-
- if (rest != NULL) {
- /* Use remainder of previous call, starts with an invalid character
- * that may become valid when reading more. */
- if (restlen > INBUFLEN - inbufcount)
- unconverted = INBUFLEN - inbufcount;
- else
- unconverted = restlen;
- memmove(inbuf + inbufcount, rest, unconverted);
- if (unconverted == restlen) {
- free(rest);
- rest = NULL;
- } else {
- restlen -= unconverted;
- memmove(rest, rest + unconverted, restlen);
- }
- inbufcount += unconverted;
- } else
- unconverted = 0;
-
- len = 0; /* to avoid gcc warning */
- for (try = 0; try < 100; ++try) {
- len = input_read(
- (char *)inbuf + inbufcount,
- (size_t)((INBUFLEN - inbufcount) / input_conv.vc_factor));
-
- if (len > 0 || got_int)
- break;
-
- if (!exit_on_error)
- return;
- }
-
- if (len <= 0 && !got_int)
- read_error_exit();
-
- if (got_int) {
- /* Interrupted, pretend a CTRL-C was typed. */
- inbuf[0] = 3;
- inbufcount = 1;
- } else {
- /*
- * May perform conversion on the input characters.
- * Include the unconverted rest of the previous call.
- * If there is an incomplete char at the end it is kept for the next
- * time, reading more bytes should make conversion possible.
- * Don't do this in the unlikely event that the input buffer is too
- * small ("rest" still contains more bytes).
- */
- if (input_conv.vc_type != CONV_NONE) {
- inbufcount -= unconverted;
- len = convert_input_safe(inbuf + inbufcount,
- len + unconverted, INBUFLEN - inbufcount,
- rest == NULL ? &rest : NULL, &restlen);
- }
- while (len-- > 0) {
- /*
- * if a CTRL-C was typed, remove it from the buffer and set got_int
- */
- if (inbuf[inbufcount] == 3 && ctrl_c_interrupts) {
- /* remove everything typed before the CTRL-C */
- memmove(inbuf, inbuf + inbufcount, (size_t)(len + 1));
- inbufcount = 0;
- got_int = TRUE;
- }
- ++inbufcount;
- }
- }
-#endif /* UNIX */
-}
-#endif /* defined(UNIX) || defined(FEAT_GUI) */
-
/*
* Exit because of an input read error.
*/
@@ -954,3 +713,4 @@ void im_save_status(long *psave)
}
}
#endif
+
diff --git a/src/nvim/vim.h b/src/nvim/vim.h
index 3ef291ef7c..47ed223e81 100644
--- a/src/nvim/vim.h
+++ b/src/nvim/vim.h
@@ -339,10 +339,6 @@ enum {
#define fnamencmp(x, y, n) vim_fnamencmp((char_u *)(x), (char_u *)(y), \
(size_t)(n))
-#if defined(UNIX) || defined(FEAT_GUI)
-# define USE_INPUT_BUF
-#endif
-
#ifndef EINTR
# define read_eintr(fd, buf, count) vim_read((fd), (buf), (count))
# define write_eintr(fd, buf, count) vim_write((fd), (buf), (count))