aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/os/input.c
diff options
context:
space:
mode:
authorEliseo Martínez <eliseomarmol@gmail.com>2014-05-12 02:25:17 +0200
committerEliseo Martínez <eliseomarmol@gmail.com>2014-05-15 20:46:01 +0200
commitda51dc9cf202772f60bd2da975dbef257bd9237c (patch)
tree5c16b93238a153f55634e9323077f30c8133970c /src/nvim/os/input.c
parentffe61e5ba1721340ca51d56bae3ddaca415fb5bc (diff)
downloadrneovim-da51dc9cf202772f60bd2da975dbef257bd9237c.tar.gz
rneovim-da51dc9cf202772f60bd2da975dbef257bd9237c.tar.bz2
rneovim-da51dc9cf202772f60bd2da975dbef257bd9237c.zip
Introduce nvim namespace: Move files.
Move files from src/ to src/nvim/. - src/nvim/ becomes the new root dir for nvim executable sources. - src/libnvim/ is planned to become root dir of the neovim library.
Diffstat (limited to 'src/nvim/os/input.c')
-rw-r--r--src/nvim/os/input.c195
1 files changed, 195 insertions, 0 deletions
diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c
new file mode 100644
index 0000000000..4310edd514
--- /dev/null
+++ b/src/nvim/os/input.c
@@ -0,0 +1,195 @@
+#include <string.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <uv.h>
+
+#include "os/input.h"
+#include "os/event.h"
+#include "os/rstream_defs.h"
+#include "os/rstream.h"
+#include "vim.h"
+#include "ui.h"
+#include "fileio.h"
+#include "getchar.h"
+#include "term.h"
+
+#define READ_BUFFER_SIZE 256
+
+typedef enum {
+ kInputNone,
+ kInputAvail,
+ kInputEof
+} InbufPollResult;
+
+static RStream *read_stream;
+static bool eof = false, started_reading = false;
+
+static InbufPollResult inbuf_poll(int32_t ms);
+static void stderr_switch(void);
+static void read_cb(RStream *rstream, void *data, bool eof);
+// Helper function used to push bytes from the 'event' key sequence partially
+// between calls to os_inchar when maxlen < 3
+static int push_event_key(uint8_t *buf, int maxlen);
+
+void input_init()
+{
+ read_stream = rstream_new(read_cb, READ_BUFFER_SIZE, NULL, false);
+ rstream_set_file(read_stream, read_cmd_fd);
+}
+
+// Check if there's pending input
+bool input_ready()
+{
+ return rstream_available(read_stream) > 0 || eof;
+}
+
+// Listen for input
+void input_start()
+{
+ rstream_start(read_stream);
+}
+
+// Stop listening for input
+void input_stop()
+{
+ 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)
+{
+ 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)
+{
+ InbufPollResult result;
+
+ if (event_is_pending()) {
+ // Return pending event bytes
+ return push_event_key(buf, maxlen);
+ }
+
+ if (ms >= 0) {
+ if ((result = inbuf_poll(ms)) == kInputNone) {
+ return 0;
+ }
+ } else {
+ if ((result = inbuf_poll(p_ut)) == kInputNone) {
+ if (trigger_cursorhold() && maxlen >= 3
+ && !typebuf_changed(tb_change_cnt)) {
+ buf[0] = K_SPECIAL;
+ buf[1] = KS_EXTRA;
+ buf[2] = KE_CURSORHOLD;
+ return 3;
+ }
+
+ before_blocking();
+ result = inbuf_poll(-1);
+ }
+ }
+
+ // If there are pending events, return the keys directly
+ if (event_is_pending()) {
+ return push_event_key(buf, maxlen);
+ }
+
+ // If input was put directly in typeahead buffer bail out here.
+ if (typebuf_changed(tb_change_cnt)) {
+ return 0;
+ }
+
+ if (result == kInputEof) {
+ read_error_exit();
+ return 0;
+ }
+
+ return read_from_input_buf(buf, (int64_t)maxlen);
+}
+
+// Check if a character is available for reading
+bool os_char_avail()
+{
+ return inbuf_poll(0) == kInputAvail;
+}
+
+// Check for CTRL-C typed by reading all available characters.
+// In cooked mode we should get SIGINT, no need to check.
+void os_breakcheck()
+{
+ if (curr_tmode == TMODE_RAW && event_poll(0))
+ fill_input_buf(false);
+}
+
+bool os_isatty(int fd)
+{
+ return uv_guess_handle(fd) == UV_TTY;
+}
+
+// This is a replacement for the old `WaitForChar` function in os_unix.c
+static InbufPollResult inbuf_poll(int32_t ms)
+{
+ if (input_available()) {
+ return kInputAvail;
+ }
+
+ if (event_poll(ms)) {
+ return eof && rstream_available(read_stream) == 0 ?
+ kInputEof :
+ kInputAvail;
+ }
+
+ return kInputNone;
+}
+
+static void stderr_switch()
+{
+ int mode = cur_tmode;
+ // We probably set the wrong file descriptor to raw mode. Switch back to
+ // cooked mode
+ settmode(TMODE_COOK);
+ // Stop the idle handle
+ rstream_stop(read_stream);
+ // Use stderr for stdin, also works for shell commands.
+ read_cmd_fd = 2;
+ // Initialize and start the input stream
+ rstream_set_file(read_stream, read_cmd_fd);
+ rstream_start(read_stream);
+ // Set the mode back to what it was
+ settmode(mode);
+}
+
+static void read_cb(RStream *rstream, void *data, bool at_eof)
+{
+ if (at_eof) {
+ if (!started_reading
+ && rstream_is_regular_file(rstream)
+ && os_isatty(STDERR_FILENO)) {
+ // Read error. Since stderr is a tty we switch to reading from it. This
+ // is for handling for cases like "foo | xargs vim" because xargs
+ // redirects stdin from /dev/null. Previously, this was done in ui.c
+ stderr_switch();
+ } else {
+ eof = true;
+ }
+ }
+
+ started_reading = true;
+}
+
+static int push_event_key(uint8_t *buf, int maxlen)
+{
+ static const uint8_t key[3] = { K_SPECIAL, KS_EXTRA, KE_EVENT };
+ static int key_idx = 0;
+ int buf_idx = 0;
+
+ do {
+ buf[buf_idx++] = key[key_idx++];
+ key_idx %= 3;
+ } while (key_idx > 0 && buf_idx < maxlen);
+
+ return buf_idx;
+}