aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorThiago de Arruda <tpadilha84@gmail.com>2014-08-28 14:39:20 -0300
committerThiago de Arruda <tpadilha84@gmail.com>2014-08-28 14:39:20 -0300
commite0d812ab649c40b8cc0efbfbe5214fb5dd407e8f (patch)
treeed4bf469e4e2c71120d8bc2df60c0bd2f077bdf7 /src
parent7f9ec6c04f3949e6d666c1586efc20a4a79be257 (diff)
parentdd90dbeeba15af4ef401327ba3996caccd34f719 (diff)
downloadrneovim-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.c4
-rw-r--r--src/nvim/globals.h3
-rw-r--r--src/nvim/main.c44
-rw-r--r--src/nvim/os/channel.c42
-rw-r--r--src/nvim/os/input.c22
-rw-r--r--src/nvim/os/signal.c5
-rw-r--r--src/nvim/os/wstream.c43
-rw-r--r--src/nvim/os_unix.c12
-rw-r--r--src/nvim/term.c3
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(&params);
+ if (!embedded_mode) {
+ // Print a warning if stdout is not a terminal.
+ check_tty(&params);
+ }
/* 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) {
/*