diff options
author | Thiago de Arruda <tpadilha84@gmail.com> | 2014-08-28 14:39:20 -0300 |
---|---|---|
committer | Thiago de Arruda <tpadilha84@gmail.com> | 2014-08-28 14:39:20 -0300 |
commit | e0d812ab649c40b8cc0efbfbe5214fb5dd407e8f (patch) | |
tree | ed4bf469e4e2c71120d8bc2df60c0bd2f077bdf7 /src | |
parent | 7f9ec6c04f3949e6d666c1586efc20a4a79be257 (diff) | |
parent | dd90dbeeba15af4ef401327ba3996caccd34f719 (diff) | |
download | rneovim-e0d812ab649c40b8cc0efbfbe5214fb5dd407e8f.tar.gz rneovim-e0d812ab649c40b8cc0efbfbe5214fb5dd407e8f.tar.bz2 rneovim-e0d812ab649c40b8cc0efbfbe5214fb5dd407e8f.zip |
Merge PR #1060 'Implement --embedded-mode command-line option'
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/ex_getln.c | 4 | ||||
-rw-r--r-- | src/nvim/globals.h | 3 | ||||
-rw-r--r-- | src/nvim/main.c | 44 | ||||
-rw-r--r-- | src/nvim/os/channel.c | 42 | ||||
-rw-r--r-- | src/nvim/os/input.c | 22 | ||||
-rw-r--r-- | src/nvim/os/signal.c | 5 | ||||
-rw-r--r-- | src/nvim/os/wstream.c | 43 | ||||
-rw-r--r-- | src/nvim/os_unix.c | 12 | ||||
-rw-r--r-- | src/nvim/term.c | 3 |
9 files changed, 156 insertions, 22 deletions
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 74f3edc8d9..69fb1d344a 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -2011,6 +2011,10 @@ void free_cmdline_buf(void) */ static void draw_cmdline(int start, int len) { + if (embedded_mode) { + return; + } + int i; if (cmdline_star > 0) diff --git a/src/nvim/globals.h b/src/nvim/globals.h index ad65f7e6fd..1ff8887598 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -1233,6 +1233,9 @@ EXTERN char *ignoredp; * os_unix.c */ EXTERN int curr_tmode INIT(= TMODE_COOK); /* contains current terminal mode */ +// If a msgpack-rpc channel should be started over stdin/stdout +EXTERN bool embedded_mode INIT(= false); + /// Used to track the status of external functions. /// Currently only used for iconv(). typedef enum { diff --git a/src/nvim/main.c b/src/nvim/main.c index 1de4b04a07..2f06a2cbf2 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -256,10 +256,10 @@ int main(int argc, char **argv) TIME_MSG("shell init"); - /* - * Print a warning if stdout is not a terminal. - */ - check_tty(¶ms); + if (!embedded_mode) { + // Print a warning if stdout is not a terminal. + check_tty(¶ms); + } /* This message comes before term inits, but after setting "silent_mode" * when the input is not a tty. */ @@ -267,8 +267,16 @@ int main(int argc, char **argv) printf(_("%d files to edit\n"), GARGCOUNT); if (params.want_full_screen && !silent_mode) { - termcapinit(params.term); /* set terminal name and get terminal - capabilities (will set full_screen) */ + if (embedded_mode) { + // In embedded mode don't do terminal-related initializations, assume an + // initial screen size of 80x20 + full_screen = true; + set_shellsize(80, 20, false); + } else { + // set terminal name and get terminal capabilities (will set full_screen) + // Do some initialization of the screen + termcapinit(params.term); + } screen_start(); /* don't know where cursor is now */ TIME_MSG("Termcap init"); } @@ -405,14 +413,18 @@ int main(int argc, char **argv) TIME_MSG("waiting for return"); } - starttermcap(); /* start termcap if not done by wait_return() */ - TIME_MSG("start termcap"); - may_req_ambiguous_char_width(); + if (!embedded_mode) { + starttermcap(); // start termcap if not done by wait_return() + TIME_MSG("start termcap"); + may_req_ambiguous_char_width(); + setmouse(); // may start using the mouse - setmouse(); /* may start using the mouse */ - if (scroll_region) - scroll_region_reset(); /* In case Rows changed */ - scroll_start(); /* may scroll the screen to the right position */ + if (scroll_region) { + scroll_region_reset(); // In case Rows changed + } + + scroll_start(); // may scroll the screen to the right position + } /* * Don't clear the screen when starting in Ex mode, unless using the GUI. @@ -1015,11 +1027,13 @@ static void command_line_scan(mparm_T *parmp) msg_putchar('\n'); msg_didout = FALSE; mch_exit(0); - } else if (STRICMP(argv[0] + argv_idx, "api-msgpack-metadata") == 0) { + } else if (STRICMP(argv[0] + argv_idx, "api-msgpack-metadata") == 0) { for (unsigned int i = 0; i<msgpack_metadata_size; i++) { putchar(msgpack_metadata[i]); } mch_exit(0); + } else if (STRICMP(argv[0] + argv_idx, "embedded-mode") == 0) { + embedded_mode = true; } else if (STRNICMP(argv[0] + argv_idx, "literal", 7) == 0) { #if !defined(UNIX) parmp->literal = TRUE; @@ -2200,6 +2214,8 @@ static void usage(void) main_msg(_("--startuptime <file>\tWrite startup timing messages to <file>")); main_msg(_("-i <viminfo>\t\tUse <viminfo> instead of .viminfo")); main_msg(_("--api-msgpack-metadata\tDump API metadata information and exit")); + main_msg(_("--embedded-mode\tUse stdin/stdout as a msgpack-rpc channel. " + "This can be used for embedding Neovim into other programs")); main_msg(_("-h or --help\tPrint Help (this message) and exit")); main_msg(_("--version\t\tPrint version information and exit")); diff --git a/src/nvim/os/channel.c b/src/nvim/os/channel.c index 1a2efca513..2c1928f3b3 100644 --- a/src/nvim/os/channel.c +++ b/src/nvim/os/channel.c @@ -20,11 +20,14 @@ #include "nvim/vim.h" #include "nvim/ascii.h" #include "nvim/memory.h" +#include "nvim/os_unix.h" #include "nvim/message.h" #include "nvim/map.h" #include "nvim/log.h" #include "nvim/lib/kvec.h" +#define CHANNEL_BUFFER_SIZE 0xffff + typedef struct { uint64_t request_id; bool errored; @@ -64,6 +67,10 @@ void channel_init(void) channels = pmap_new(uint64_t)(); event_strings = pmap_new(cstr_t)(); msgpack_sbuffer_init(&out_buffer); + + if (embedded_mode) { + channel_from_stdio(); + } } /// Teardown the module @@ -117,7 +124,10 @@ void channel_from_stream(uv_stream_t *stream) stream->data = NULL; channel->is_job = false; // read stream - channel->data.streams.read = rstream_new(parse_msgpack, 1024, channel, NULL); + channel->data.streams.read = rstream_new(parse_msgpack, + CHANNEL_BUFFER_SIZE, + channel, + NULL); rstream_set_stream(channel->data.streams.read, stream); rstream_start(channel->data.streams.read); // write stream @@ -256,6 +266,25 @@ void channel_unsubscribe(uint64_t id, char *event) unsubscribe(channel, event); } +/// Creates an API channel from stdin/stdout. This is used when embedding +/// Neovim +static void channel_from_stdio(void) +{ + Channel *channel = register_channel(); + channel->is_job = false; + // read stream + channel->data.streams.read = rstream_new(parse_msgpack, + CHANNEL_BUFFER_SIZE, + channel, + NULL); + rstream_set_file(channel->data.streams.read, 0); + rstream_start(channel->data.streams.read); + // write stream + channel->data.streams.write = wstream_new(0); + wstream_set_file(channel->data.streams.write, 1); + channel->data.streams.uv = NULL; +} + static void job_out(RStream *rstream, void *data, bool eof) { Job *job = data; @@ -278,6 +307,7 @@ static void job_err(RStream *rstream, void *data, bool eof) static void parse_msgpack(RStream *rstream, void *data, bool eof) { Channel *channel = data; + channel->rpc_call_level++; if (eof) { char buf[256]; @@ -287,10 +317,9 @@ static void parse_msgpack(RStream *rstream, void *data, bool eof) "closed by the client", channel->id); call_set_error(channel, buf); - return; + goto end; } - channel->rpc_call_level++; uint32_t count = rstream_available(rstream); DLOG("Feeding the msgpack parser with %u bytes of data from RStream(%p)", count, @@ -469,7 +498,12 @@ static void close_channel(Channel *channel) } else { rstream_free(channel->data.streams.read); wstream_free(channel->data.streams.write); - uv_close((uv_handle_t *)channel->data.streams.uv, close_cb); + if (channel->data.streams.uv) { + uv_close((uv_handle_t *)channel->data.streams.uv, close_cb); + } else { + // When the stdin channel closes, it's time to go + mch_exit(0); + } } free(channel); diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index 15aebdbf3d..53024d1389 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -6,6 +6,7 @@ #include "nvim/os/input.h" #include "nvim/os/event.h" +#include "nvim/os/signal.h" #include "nvim/os/rstream_defs.h" #include "nvim/os/rstream.h" #include "nvim/ascii.h" @@ -34,6 +35,10 @@ static bool eof = false, started_reading = false; void input_init(void) { + if (embedded_mode) { + return; + } + read_stream = rstream_new(read_cb, READ_BUFFER_SIZE, NULL, NULL); rstream_set_file(read_stream, read_cmd_fd); } @@ -41,18 +46,30 @@ void input_init(void) // Listen for input void input_start(void) { + if (embedded_mode) { + return; + } + rstream_start(read_stream); } // Stop listening for input void input_stop(void) { + if (embedded_mode) { + return; + } + 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); } @@ -129,6 +146,11 @@ bool os_isatty(int fd) static bool input_poll(int32_t ms) { + if (embedded_mode) { + EventSource input_sources[] = { signal_event_source(), NULL }; + return event_poll(ms, input_sources); + } + EventSource input_sources[] = { rstream_event_source(read_stream), NULL diff --git a/src/nvim/os/signal.c b/src/nvim/os/signal.c index 17f270a5cc..2f93cfb08a 100644 --- a/src/nvim/os/signal.c +++ b/src/nvim/os/signal.c @@ -39,7 +39,10 @@ void signal_init(void) uv_signal_start(&shup, signal_cb, SIGHUP); uv_signal_start(&squit, signal_cb, SIGQUIT); uv_signal_start(&sterm, signal_cb, SIGTERM); - uv_signal_start(&swinch, signal_cb, SIGWINCH); + if (!embedded_mode) { + // TODO(tarruda): There must be an API function for resizing window + uv_signal_start(&swinch, signal_cb, SIGWINCH); + } #ifdef SIGPWR uv_signal_init(uv_default_loop(), &spwr); uv_signal_start(&spwr, signal_cb, SIGPWR); diff --git a/src/nvim/os/wstream.c b/src/nvim/os/wstream.c index 194bf757e4..44463c7c88 100644 --- a/src/nvim/os/wstream.c +++ b/src/nvim/os/wstream.c @@ -1,6 +1,7 @@ #include <assert.h> #include <stdint.h> #include <stdbool.h> +#include <stdlib.h> #include <uv.h> @@ -20,7 +21,7 @@ struct wstream { size_t maxmem; // Number of pending requests size_t pending_reqs; - bool freed; + bool freed, free_handle; // (optional) Write callback and data wstream_cb cb; void *data; @@ -60,6 +61,7 @@ WStream * wstream_new(size_t maxmem) rv->curmem = 0; rv->pending_reqs = 0; rv->freed = false; + rv->free_handle = false; rv->cb = NULL; return rv; @@ -68,9 +70,13 @@ WStream * wstream_new(size_t maxmem) /// Frees all memory allocated for a WStream instance /// /// @param wstream The `WStream` instance -void wstream_free(WStream *wstream) -{ +void wstream_free(WStream *wstream) { if (!wstream->pending_reqs) { + handle_set_wstream((uv_handle_t *)wstream->stream, NULL); + if (wstream->free_handle) { + uv_close((uv_handle_t *)wstream->stream, close_cb); + } + free(wstream); } else { wstream->freed = true; @@ -87,6 +93,24 @@ void wstream_set_stream(WStream *wstream, uv_stream_t *stream) wstream->stream = stream; } +/// Sets the underlying file descriptor that will be written to. Only pipes +/// are supported for now. +/// +/// @param wstream The `WStream` instance +/// @param file The file descriptor +void wstream_set_file(WStream *wstream, uv_file file) +{ + uv_handle_type type = uv_guess_handle(file); + + assert(type == UV_NAMED_PIPE || type == UV_TTY); + wstream->stream = xmalloc(sizeof(uv_pipe_t)); + uv_pipe_init(uv_default_loop(), (uv_pipe_t *)wstream->stream, 0); + uv_pipe_open((uv_pipe_t *)wstream->stream, file); + wstream->stream->data = NULL; + handle_set_wstream((uv_handle_t *)wstream->stream, wstream); + wstream->free_handle = true; +} + /// Sets a callback that will be called on completion of a write request, /// indicating failure/success. /// @@ -211,3 +235,16 @@ static void release_wbuffer(WBuffer *buffer) free(buffer); } } + +static void close_cb(uv_handle_t *handle) +{ + WStream *wstream = handle_get_wstream(handle); + + if (wstream) { + free(wstream); + } + + free(handle->data); + free(handle); +} + diff --git a/src/nvim/os_unix.c b/src/nvim/os_unix.c index af17676ebf..1b092c8261 100644 --- a/src/nvim/os_unix.c +++ b/src/nvim/os_unix.c @@ -88,6 +88,18 @@ static int did_set_icon = FALSE; */ void mch_write(char_u *s, int len) { + if (embedded_mode) { + // TODO(tarruda): This is a temporary hack to stop Neovim from writing + // messages to stdout in embedded mode. In the future, embedded mode will + // be the only possibility(GUIs will always start neovim with a msgpack-rpc + // over stdio) and this function won't exist. + // + // The reason for this is because before Neovim fully migrates to a + // msgpack-rpc-driven architecture, we must have a fully functional + // UI working + return; + } + ignored = (int)write(1, (char *)s, len); if (p_wd) /* Unix is too fast, slow down a bit more */ os_microdelay(p_wd, false); diff --git a/src/nvim/term.c b/src/nvim/term.c index 36e433d624..d2c524e2e8 100644 --- a/src/nvim/term.c +++ b/src/nvim/term.c @@ -2360,6 +2360,9 @@ void set_shellsize(int width, int height, int mustset) */ void settmode(int tmode) { + if (embedded_mode) { + return; + } if (full_screen) { /* |