diff options
author | glacambre <code@lacamb.re> | 2021-10-03 16:19:25 +0200 |
---|---|---|
committer | glacambre <code@lacamb.re> | 2022-01-24 13:59:16 +0100 |
commit | a4069a3eed65f14b1149c6cda8638dcb49ab5027 (patch) | |
tree | dc0f0c1af6f8a9070340745c8f939b8a7d875d82 | |
parent | 326e74571be43823ded9fa805a3173bdabda6bec (diff) | |
download | rneovim-a4069a3eed65f14b1149c6cda8638dcb49ab5027.tar.gz rneovim-a4069a3eed65f14b1149c6cda8638dcb49ab5027.tar.bz2 rneovim-a4069a3eed65f14b1149c6cda8638dcb49ab5027.zip |
feat(--headless): add on_print callback to stdioopen
This commit adds an on_print callback to stdioopen's dictionary
argument which lets the caller specify a function called each time
neovim will try to output something to stdout (e.g. on "echo" or
"echoerr" in --headless mode).
-rw-r--r-- | src/nvim/channel.h | 2 | ||||
-rw-r--r-- | src/nvim/eval/funcs.c | 4 | ||||
-rw-r--r-- | src/nvim/eval/typval.h | 3 | ||||
-rw-r--r-- | src/nvim/message.c | 11 | ||||
-rw-r--r-- | test/functional/core/channels_spec.lua | 32 |
5 files changed, 51 insertions, 1 deletions
diff --git a/src/nvim/channel.h b/src/nvim/channel.h index 81b75e2d31..50d6b3600a 100644 --- a/src/nvim/channel.h +++ b/src/nvim/channel.h @@ -96,6 +96,8 @@ struct Channel { EXTERN PMap(uint64_t) channels INIT(= MAP_INIT); +EXTERN Callback on_print INIT(= CALLBACK_INIT); + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "channel.h.generated.h" #endif diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 5252c940f7..6d43097ddd 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -10213,6 +10213,10 @@ static void f_stdioopen(typval_T *argvars, typval_T *rettv, FunPtr fptr) if (!tv_dict_get_callback(opts, S_LEN("on_stdin"), &on_stdin.cb)) { return; } + if (!tv_dict_get_callback(opts, S_LEN("on_print"), &on_print)) { + return; + } + on_stdin.buffered = tv_dict_get_number(opts, "stdin_buffered"); if (on_stdin.buffered && on_stdin.cb.type == kCallbackNone) { on_stdin.self = opts; diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h index d1275d6512..ad01c01499 100644 --- a/src/nvim/eval/typval.h +++ b/src/nvim/eval/typval.h @@ -81,7 +81,8 @@ typedef struct { } data; CallbackType type; } Callback; -#define CALLBACK_NONE ((Callback){ .type = kCallbackNone }) +#define CALLBACK_INIT { .type = kCallbackNone } +#define CALLBACK_NONE ((Callback)CALLBACK_INIT) /// Structure holding dictionary watcher typedef struct dict_watcher { diff --git a/src/nvim/message.c b/src/nvim/message.c index befca8c76b..76aa863bde 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -2647,6 +2647,17 @@ static void msg_puts_printf(const char *str, const ptrdiff_t maxlen) char buf[7]; char *p; + if (on_print.type != kCallbackNone) { + typval_T argv[1]; + argv[0].v_type = VAR_STRING; + argv[0].v_lock = VAR_UNLOCKED; + argv[0].vval.v_string = (char_u *)str; + typval_T rettv = TV_INITIAL_VALUE; + callback_call(&on_print, 1, argv, &rettv); + tv_clear(&rettv); + return; + } + while ((maxlen < 0 || s - str < maxlen) && *s != NUL) { int len = utf_ptr2len((const char_u *)s); if (!(silent_mode && p_verbose == 0)) { diff --git a/test/functional/core/channels_spec.lua b/test/functional/core/channels_spec.lua index 93dec9fb35..c28300f0f4 100644 --- a/test/functional/core/channels_spec.lua +++ b/test/functional/core/channels_spec.lua @@ -100,6 +100,38 @@ describe('channels', function() eq({"notification", "exit", {3,0}}, next_msg()) end) + it('can use stdio channel and on_print callback', function() + source([[ + let g:job_opts = { + \ 'on_stdout': function('OnEvent'), + \ 'on_stderr': function('OnEvent'), + \ 'on_exit': function('OnEvent'), + \ } + ]]) + meths.set_var("nvim_prog", nvim_prog) + meths.set_var("code", [[ + function! OnStdin(id, data, event) dict + echo string([a:id, a:data, a:event]) + if a:data == [''] + quit + endif + endfunction + function! OnPrint(text) dict + call chansend(g:x, ['OnPrint:' .. a:text]) + endfunction + let g:x = stdioopen({'on_stdin': funcref('OnStdin'), 'on_print':'OnPrint'}) + call chansend(x, "hello") + ]]) + command("let g:id = jobstart([ g:nvim_prog, '-u', 'NONE', '-i', 'NONE', '--cmd', 'set noswapfile', '--headless', '--cmd', g:code], g:job_opts)") + local id = eval("g:id") + ok(id > 0) + + eq({ "notification", "stdout", {id, { "hello" } } }, next_msg()) + + command("call chansend(id, 'howdy')") + eq({"notification", "stdout", {id, {"OnPrint:[1, ['howdy'], 'stdin']"}}}, next_msg()) + end) + local function expect_twoline(id, stream, line1, line2, nobr) local msg = next_msg() local joined = nobr and {line1..line2} or {line1, line2} |