diff options
author | Thiago de Arruda <tpadilha84@gmail.com> | 2014-10-18 08:38:15 -0300 |
---|---|---|
committer | Thiago de Arruda <tpadilha84@gmail.com> | 2014-10-18 12:51:35 -0300 |
commit | 42112e04a999c0f289939fce3142ef2c2517110a (patch) | |
tree | 5f2a1dd7395461be1bc6df7aa259fa8dd63008d3 | |
parent | 68de5d79a243fecc9ef256d9d0356f8541aa3821 (diff) | |
download | rneovim-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.h | 6 | ||||
-rw-r--r-- | src/nvim/getchar.c | 24 | ||||
-rw-r--r-- | src/nvim/mbyte.c | 44 | ||||
-rw-r--r-- | src/nvim/os/input.c | 108 | ||||
-rw-r--r-- | src/nvim/os/input.h | 2 | ||||
-rw-r--r-- | src/nvim/ui.c | 242 | ||||
-rw-r--r-- | src/nvim/vim.h | 4 |
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)) |