mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Refactor input module to use RStream class
This commit is contained in:
parent
6e4e40a0f7
commit
f276e97de9
153
src/os/input.c
153
src/os/input.c
@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
#include "os/input.h"
|
#include "os/input.h"
|
||||||
#include "os/event.h"
|
#include "os/event.h"
|
||||||
|
#include "os/rstream_defs.h"
|
||||||
|
#include "os/rstream.h"
|
||||||
#include "vim.h"
|
#include "vim.h"
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
@ -15,7 +17,7 @@
|
|||||||
#include "term.h"
|
#include "term.h"
|
||||||
#include "misc2.h"
|
#include "misc2.h"
|
||||||
|
|
||||||
#define READ_BUFFER_LENGTH 4096
|
#define READ_BUFFER_SIZE 256
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
kInputNone,
|
kInputNone,
|
||||||
@ -23,101 +25,41 @@ typedef enum {
|
|||||||
kInputEof
|
kInputEof
|
||||||
} InbufPollResult;
|
} InbufPollResult;
|
||||||
|
|
||||||
typedef struct {
|
static RStream *read_stream;
|
||||||
uv_buf_t uvbuf;
|
static bool eof = false, started_reading = false;
|
||||||
uint32_t rpos, wpos, fpos;
|
|
||||||
char_u data[READ_BUFFER_LENGTH];
|
|
||||||
bool reading;
|
|
||||||
} ReadBuffer;
|
|
||||||
|
|
||||||
static ReadBuffer rbuffer;
|
|
||||||
static uv_pipe_t read_stream;
|
|
||||||
// Use an idle handle to make reading from the fs look like a normal libuv
|
|
||||||
// event
|
|
||||||
static uv_idle_t fread_idle;
|
|
||||||
static uv_handle_type read_channel_type;
|
|
||||||
static bool eof = false;
|
|
||||||
|
|
||||||
static InbufPollResult inbuf_poll(int32_t ms);
|
static InbufPollResult inbuf_poll(int32_t ms);
|
||||||
static void stderr_switch(void);
|
static void stderr_switch(void);
|
||||||
static void alloc_cb(uv_handle_t *, size_t, uv_buf_t *);
|
static void read_cb(RStream *rstream, void *data, bool eof);
|
||||||
static void read_cb(uv_stream_t *, ssize_t, const uv_buf_t *);
|
|
||||||
static void fread_idle_cb(uv_idle_t *);
|
|
||||||
|
|
||||||
void input_init()
|
void input_init()
|
||||||
{
|
{
|
||||||
rbuffer.wpos = rbuffer.rpos = rbuffer.fpos = 0;
|
read_stream = rstream_new(read_cb, READ_BUFFER_SIZE, NULL);
|
||||||
#ifdef DEBUG
|
rstream_set_file(read_stream, read_cmd_fd);
|
||||||
memset(&rbuffer.data, 0, READ_BUFFER_LENGTH);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if ((read_channel_type = uv_guess_handle(read_cmd_fd)) == UV_FILE) {
|
|
||||||
uv_idle_init(uv_default_loop(), &fread_idle);
|
|
||||||
} else {
|
|
||||||
uv_pipe_init(uv_default_loop(), &read_stream, 0);
|
|
||||||
uv_pipe_open(&read_stream, read_cmd_fd);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if there's pending input
|
// Check if there's pending input
|
||||||
bool input_ready()
|
bool input_ready()
|
||||||
{
|
{
|
||||||
return rbuffer.rpos < rbuffer.wpos || eof;
|
return rstream_available(read_stream) > 0 || eof;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Listen for input
|
// Listen for input
|
||||||
void input_start()
|
void input_start()
|
||||||
{
|
{
|
||||||
// Pin the buffer used by libuv
|
rstream_start(read_stream);
|
||||||
rbuffer.uvbuf.len = READ_BUFFER_LENGTH - rbuffer.wpos;
|
|
||||||
rbuffer.uvbuf.base = (char *)(rbuffer.data + rbuffer.wpos);
|
|
||||||
|
|
||||||
if (read_channel_type == UV_FILE) {
|
|
||||||
// Just invoke the `fread_idle_cb` as soon as the loop starts
|
|
||||||
uv_idle_start(&fread_idle, fread_idle_cb);
|
|
||||||
} else {
|
|
||||||
// Start reading
|
|
||||||
rbuffer.reading = false;
|
|
||||||
uv_read_start((uv_stream_t *)&read_stream, alloc_cb, read_cb);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop listening for input
|
// Stop listening for input
|
||||||
void input_stop()
|
void input_stop()
|
||||||
{
|
{
|
||||||
if (read_channel_type == UV_FILE) {
|
rstream_stop(read_stream);
|
||||||
uv_idle_stop(&fread_idle);
|
|
||||||
} else {
|
|
||||||
uv_read_stop((uv_stream_t *)&read_stream);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copies (at most `count`) of was read from `read_cmd_fd` into `buf`
|
// Copies (at most `count`) of was read from `read_cmd_fd` into `buf`
|
||||||
uint32_t input_read(char *buf, uint32_t count)
|
uint32_t input_read(char *buf, uint32_t count)
|
||||||
{
|
{
|
||||||
uint32_t read_count = rbuffer.wpos - rbuffer.rpos;
|
return rstream_read(read_stream, buf, count);
|
||||||
|
|
||||||
if (count < read_count) {
|
|
||||||
read_count = count;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (read_count > 0) {
|
|
||||||
memcpy(buf, rbuffer.data + rbuffer.rpos, read_count);
|
|
||||||
rbuffer.rpos += read_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rbuffer.wpos == READ_BUFFER_LENGTH) {
|
|
||||||
// `wpos` is at the end of the buffer, so free some space by moving unread
|
|
||||||
// data...
|
|
||||||
memmove(
|
|
||||||
rbuffer.data, // ...To the beginning of the buffer(rpos 0)
|
|
||||||
rbuffer.data + rbuffer.rpos, // ...From the first unread position
|
|
||||||
rbuffer.wpos - rbuffer.rpos); // ...By the number of unread bytes
|
|
||||||
rbuffer.wpos -= rbuffer.rpos;
|
|
||||||
rbuffer.rpos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return read_count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -188,7 +130,9 @@ static InbufPollResult inbuf_poll(int32_t ms)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (event_poll(ms)) {
|
if (event_poll(ms)) {
|
||||||
return eof && rbuffer.rpos == rbuffer.wpos ? kInputEof : kInputAvail;
|
return eof && rstream_available(read_stream) == 0 ?
|
||||||
|
kInputEof :
|
||||||
|
kInputAvail;
|
||||||
}
|
}
|
||||||
|
|
||||||
return kInputNone;
|
return kInputNone;
|
||||||
@ -201,69 +145,22 @@ static void stderr_switch()
|
|||||||
// cooked mode
|
// cooked mode
|
||||||
settmode(TMODE_COOK);
|
settmode(TMODE_COOK);
|
||||||
// Stop the idle handle
|
// Stop the idle handle
|
||||||
uv_idle_stop(&fread_idle);
|
rstream_stop(read_stream);
|
||||||
// Use stderr for stdin, also works for shell commands.
|
// Use stderr for stdin, also works for shell commands.
|
||||||
read_cmd_fd = 2;
|
read_cmd_fd = 2;
|
||||||
// Initialize and start the input stream
|
// Initialize and start the input stream
|
||||||
uv_pipe_init(uv_default_loop(), &read_stream, 0);
|
rstream_set_file(read_stream, read_cmd_fd);
|
||||||
uv_pipe_open(&read_stream, read_cmd_fd);
|
rstream_start(read_stream);
|
||||||
uv_read_start((uv_stream_t *)&read_stream, alloc_cb, read_cb);
|
|
||||||
rbuffer.reading = false;
|
|
||||||
// Set the mode back to what it was
|
// Set the mode back to what it was
|
||||||
settmode(mode);
|
settmode(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called by libuv to allocate memory for reading.
|
static void read_cb(RStream *rstream, void *data, bool at_eof)
|
||||||
static void alloc_cb(uv_handle_t *handle, size_t suggested, uv_buf_t *buf)
|
|
||||||
{
|
{
|
||||||
if (rbuffer.reading) {
|
if (at_eof) {
|
||||||
buf->len = 0;
|
if (!started_reading
|
||||||
return;
|
&& rstream_is_regular_file(rstream)
|
||||||
}
|
&& uv_guess_handle(2) == UV_TTY) {
|
||||||
|
|
||||||
buf->base = rbuffer.uvbuf.base;
|
|
||||||
buf->len = rbuffer.uvbuf.len;
|
|
||||||
// Avoid `alloc_cb`, `alloc_cb` sequences on windows
|
|
||||||
rbuffer.reading = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Callback invoked by libuv after it copies the data into the buffer provided
|
|
||||||
// by `alloc_cb`. This is also called on EOF or when `alloc_cb` returns a
|
|
||||||
// 0-length buffer.
|
|
||||||
static void read_cb(uv_stream_t *stream, ssize_t cnt, const uv_buf_t *buf)
|
|
||||||
{
|
|
||||||
if (cnt <= 0) {
|
|
||||||
if (cnt != UV_ENOBUFS) {
|
|
||||||
// Read error or EOF, either way vim must exit
|
|
||||||
eof = true;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Data was already written, so all we need is to update 'wpos' to reflect
|
|
||||||
// the space actually used in the buffer.
|
|
||||||
rbuffer.wpos += cnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Called by the by the 'idle' handle to emulate a reading event
|
|
||||||
static void fread_idle_cb(uv_idle_t *handle)
|
|
||||||
{
|
|
||||||
uv_fs_t req;
|
|
||||||
|
|
||||||
// Synchronous read
|
|
||||||
uv_fs_read(
|
|
||||||
uv_default_loop(),
|
|
||||||
&req,
|
|
||||||
read_cmd_fd,
|
|
||||||
&rbuffer.uvbuf,
|
|
||||||
1,
|
|
||||||
rbuffer.fpos,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
uv_fs_req_cleanup(&req);
|
|
||||||
|
|
||||||
if (req.result <= 0) {
|
|
||||||
if (rbuffer.fpos == 0 && uv_guess_handle(2) == UV_TTY) {
|
|
||||||
// Read error. Since stderr is a tty we switch to reading from it. This
|
// 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
|
// is for handling for cases like "foo | xargs vim" because xargs
|
||||||
// redirects stdin from /dev/null. Previously, this was done in ui.c
|
// redirects stdin from /dev/null. Previously, this was done in ui.c
|
||||||
@ -271,9 +168,7 @@ static void fread_idle_cb(uv_idle_t *handle)
|
|||||||
} else {
|
} else {
|
||||||
eof = true;
|
eof = true;
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rbuffer.wpos += req.result;
|
started_reading = true;
|
||||||
rbuffer.fpos += req.result;
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user