-
-
Notifications
You must be signed in to change notification settings - Fork 6.3k
[RFC] channels: support buffered output and bytes sockets/stdio #6844
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Also change I would make, but in a separate PR: move almost all job/channel code from eval.c to channel.c, also expose functionality natively in lua, so lua functions/callbacks can use lua binary strings instead of linelists, also rpc functions can do directly lua<->msgpack (primarily for semantics/convenience, only secondarily for performance). lua callbacks could even be run more asynchronously than vimL callbacks (i e in situations where vimL is forbidden) and must use |
Lua is no more thread-safe then VimL is, except that you can asynchronously use different |
I'm not thinking of threads, just event handling in the main thread. There are many circumstances where the uv event loop is being run, but most events (that can execute arbitrary vimscript, most API functions) are blocked. We could be more liberal with executing lua callbacks if this behavior is introduced from start. Alternatively they can by default behave like vimL callbacks, and this behavior behind a flag. |
Now allows byte based sockets:
should see something like
|
Also implement |
src/nvim/channel.c
Outdated
uint64_t channel_from_stdio(bool rpc, CallbackReader on_output, const char **error) | ||
{ | ||
if (!headless_mode) { | ||
error = _("Stdio channel can only be opened in headless mode"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
*error
instead of error
src/nvim/channel.c
Outdated
} | ||
|
||
if (did_stdio) { | ||
error = _("Stdio channel was already open"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
*error
instead of error
@@ -23,13 +23,15 @@ struct process { | |||
uint64_t stopped_time; | |||
const char *cwd; | |||
char **argv; | |||
Stream *in, *out, *err; | |||
Stream in, out, err; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
process_init()
still initializes these members with NULL
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That explains gcc:s strange warning message (it complains of missing braces for all of Process, not the Stream members).
4d60817
to
e272633
Compare
Rather than allowing a separate close callback Another solution is to rename the |
Implemented option |
Now Functions that return channels
Functions that take jobs
Functions that take any channel
(ignoring deprecated functions that can be done using any above) |
src/nvim/eval.c
Outdated
TerminalJobData *data; | ||
map_foreach_value(jobs, data, { | ||
Channel *data; | ||
map_foreach_value(channels, data, { | ||
set_ref_in_callback(&data->on_stdout, copyID, NULL, NULL); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing cast (Callback *)
to hide -Wincompatible_pointer_types
warning for first argument.
Perhaps also add somewhere a static_assert
to make sure that the Callback
object is the first member in CallbackReader
:
#include "nvim/assert.h"
#include <stddef.h>
STATIC_ASSERT(offsetof(CallbackReader,cb)== 0,"...");
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do get a warning already, I have just not fixed it as it is still WIP
src/nvim/eval.c
Outdated
TerminalJobData *data; | ||
map_foreach_value(jobs, data, { | ||
Channel *data; | ||
map_foreach_value(channels, data, { | ||
set_ref_in_callback(&data->on_stdout, copyID, NULL, NULL); | ||
set_ref_in_callback(&data->on_stderr, copyID, NULL, NULL); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing cast
src/nvim/event/process.h
Outdated
.in = NULL, | ||
.out = NULL, | ||
.err = NULL, | ||
.in = {0}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clang complains here about a missing initializer (field uv
). If we remove .in = ...
, .out =...
and .err = ...
the compiler should set the fields to zero.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer being explicit in such cases rather then rely on compiler zeroing things out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Strange that clang complains, {0}
is a standard pattern and it's used elsewhere without complaints.
What is also missing is able to write to nvim's own stderr. It should probably not be mixed into the stdio channel as |
src/nvim/channel.c
Outdated
} | ||
|
||
/// @param data will be consumed | ||
size_t channel_send(uint64_t id, char* data, size_t len, const char **error) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why use size_t
as return type? It looks like this function only returns 0
or 1
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it should return the number of bytes written, as is standard for write function. But it looks like wstream_write
doesn't do this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fwrite()
only returns the number of items written (here 1
). That number is also not equal the number of bytes written if len != 1
.
src/nvim/channel.c
Outdated
Channel *channel = channel_alloc(kChannelTypeSocket); | ||
if (!socket_connect(&main_loop, &channel->stream.socket, | ||
tcp, address, timeout, error)) { | ||
// TODO: early detroy that doesn't consume a channel id? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo: detroy
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A TODO without (name)
is something I will fix before merging the PR.
src/nvim/channel.c
Outdated
// TODO: test mixed mode (server RPC, client bytes) | ||
if (!tcp && rpc) { | ||
char *path = fix_fname(address); | ||
if (rpc && server_owns_pipe_address(path)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rpc
is here always true.
@@ -117,8 +117,8 @@ variables: | |||
- *b:term_title* The settable title of the terminal, typically displayed in | |||
the window title or tab title of a graphical terminal emulator. Programs | |||
running in the terminal can set this title via an escape sequence. | |||
- *b:terminal_job_id* The nvim job ID of the job running in the terminal. See | |||
|job-control| for more information. | |||
- *b:terminal_job_id* The nvim channel ID or the PTY of the terminal emulateor. See |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo: emulateor -> emulator
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Second half of the sentence not clear to me. What is the PTY of the terminal emulator
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should be channel ID of the PTY of the emulator
, but I guess it could be clearer; the channelrepresents specifically the master end of the PTY, not the PTY itself.
runtime/doc/channels.txt
Outdated
There are several ways to open a channel: | ||
|
||
1. Through stdin/stdout when `nvim` is started with `--headless`, and a startup | ||
script or --cmd commad opens the stdio channel using |stdioopen()|. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo: commad -> command
runtime/doc/channels.txt
Outdated
|
||
4. By connecting to a TCP/IP socket or named pipe with |sockconnect()|. | ||
|
||
5. By another process connecting to a socket listened by nvim. This only |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
socket listened by => socket listened to by
runtime/doc/channels.txt
Outdated
5. By another process connecting to a socket listened by nvim. This only | ||
supports RPC channels, see |rpc-connecting|. | ||
|
||
Channels can operate in two different modes, a mode using the |rpc| protocol, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would re-organize to:
Channels can operate in two modes: one via the |rpc| protocol (msgpack-rpc
based) and the other in "bytes" mode where scripts read and write raw bytes
over the channel. As a caveat even if a job's channel is in |rpc| mode, bytes can still
be read over its' stderr. Additionally only bytes can be written to nvim's stderr.
(Honestly it doesn't make a big difference either way, feel completely free to reject
this suggestion).
Edit: Is it possible to link to the next section after mentioning "bytes" mode?
Or is that too much?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
almost, but I prefer to think of stderr as an asset, not as a "caveat"
merged. The "channels can connect to socket" (bytes mode) test was a bit flaky the other day, but has been fine the latest retries. If it causes trouble again I will mark it as pending (and eventually fix it by adding a proper bytes server shim, instead of abusing msgpackdump for this purpose). |
This seems breaking old behavior... An extra newline seems to be added. I'll investigate deeply later. https://travis-ci.org/lambdalisue/gina.vim/jobs/308500736#L2077 |
Hmm, I first though it was issue of the extra EOF event that is added. But |
https://travis-ci.org/lambdalisue/gina.vim/builds/308500727 Only the neovim HEAD shows fail so I think test is correct. |
Do you have detail? I would like to investigate that.
Possible. I'll check thanks 👍 |
https://github.com/lambdalisue/gina.vim/blob/master/test/gina/process.vimspec#L31 You were correct. The test has its own inplementation which just add the data to a list. So is this behavior change intentional? And is there any documentation about behavior change? |
@lambdalisue See "Note 2" in |
@justinmk The behavior did change so that EOF is identifiable, but it should be purely an information gain change. 90 % of plugins that uses the recommended pattern should notice no breaking change, 9% was broken already but extremely unlikely seen because flushing behavior is kind of deterministic even if no guarantees actually was made.1% is the "spacebar heating" cases we need to give recommendations individually. |
so what is the recommanded pattern ? if a
then the a:data of stdout func is and any document show the differences, or any job example show the differences? |
In my case, I was using a low-level implementation (only in one test, other parts I was using a recommended pattern) so the test had failed. Prob "Note 2" in |
@lambdalisue Thanks, I got it. |
@bfredl is there a check flag for this change? just to make sure my config is compatibility to old version of neovim, for example " some new func added in this pr
if exist('*new_func_name')
" old stdout handle func
else
" new fixed stdout handle func
endif |
The point is that a function that parses lines correctly, shouldn't need to change behavior depending on version. But you can of course check for |
jobsend/jobclose has renamed to chansend/chanclose in Neovim 0.2.3 and the old names became obsolute. PR: neovim/neovim#6844
// We want to deal with stream events as fast a possible while queueing | ||
// process events, so reset everything to NULL. It prevents closing the | ||
// Note: unlike process events, stream events are not queued, as we want to | ||
// deal with stream events as fast a possible. It prevents closing the | ||
// streams while there's still data in the OS buffer (due to the process |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does "It prevents" still make sense here? What prevents the streams from closing?
Are there any plans to extend |
@boxofrox This is already implemented, but only on master. |
FEATURES: 3cc7ebf #7234 built-in VimL expression parser 6a7c904 #4419 implement <Cmd> key to invoke command in any mode b836328 #7679 'startup: treat stdin as text instead of commands' 58b210e :digraphs : highlight with hl-SpecialKey #2690 7a13611 #8276 'startup: Let `-s -` read from stdin' 1e71978 events: VimSuspend, VimResume #8280 1e7d5e8 #6272 'stdpath()' f96d99a #8247 server: introduce --listen e8c39f7 #8226 insert-mode: interpret unmapped META as ESC 98e7112 msg: do not scroll entire screen (#8088) f72630b #8055 let negative 'writedelay' show all redraws 5d2dd2e win: has("wsl") on Windows Subsystem for Linux #7330 a4f6cec cmdline: CmdlineEnter and CmdlineLeave autocommands (#7422) 207b7ca #6844 channels: support buffered output and bytes sockets/stdio API: f85cbea #7917 API: buffer updates 418abfc #6743 API: list information about all channels/jobs. 36b2e3f #8375 API: nvim_get_commands 273d2cd #8329 API: Make nvim_set_option() update `:verbose set …` 8d40b36 #8371 API: more reliable/descriptive VimL errors ebb1acb #8353 API: nvim_call_dict_function 9f994bb #8004 API: nvim_list_uis 3405704 #7520 API/UI: forward option updates to UIs 911b1e4 #7821 API: improve nvim_command_output WINDOWS OS: 9cefd83 #8084, #8516 build/win: support MSVC ee4e1fd win: Fix reading content from stdin (#8267) TUI: ffb8904 #8309 TUI: add support for mouse release events in urxvt 8d5a46e #8081 TUI: implement "standout" attribute 6071637 TUI: support TERM=konsole-256color 67848c0 #7653 TUI: report TUI info with -V3 ('verbose' >= 3) 3d0ee17 TUI/rxvt: enable focus-reporting d109f56 #7640 TUI: 'term' option: reflect effective terminal behavior FIXES: ed6a113 #8273 'job-control: avoid kill-timer race' 4e02f1a #8107 'jobs: separate process-group' 451c48a terminal: flush vterm output buffer on pty output #8486 5d6732f :checkhealth fixes #8335 53f11dc #8218 'Fix errors reported by PVS' d05712f inccommand: pause :terminal redraws (#8307) 51af911 inccommand: do not execute trailing commands #8256 84359a4 terminal: resize to the max dimensions (#8249) d49c1dd #8228 Make vim_fgets() return the same values as in Vim 60e96a4 screen: winhl=Normal:Background should not override syntax (#8093) 0c59ac1 #5908 'shada: Also save numbered marks' ba87a2c cscope: ignore EINTR while reading the prompt (#8079) b1412dc #7971 ':terminal Enter/Leave should not increment jumplist' 3a5721e TUI: libtermkey: force CSI driver for mouse input #7948 6ff13d7 #7720 TUI: faster startup 1c6e956 #7862 TUI: fix resize-related segfaults a58c909 #7676 TUI: always hide cursor when flushing, never flush buffers during unibilium output 303e1df #7624 TUI: disable BCE almost always 249bdb0 #7761 mark: Make sure that jumplist item will not have zero lnum 6f41ce0 #7704 macOS: Set $LANG based on the system locale a043899 #7633 'Retry fgets on EINTR' CHANGES: ad60927 #8304 default to 'nofsync' f3f1970 #8035 defaults: 'fillchars' a6052c7 #7984 defaults: sidescroll=1 b69fa86 #7888 defaults: enable cscopeverbose 7c4bb23 defaults: do :filetype stuff unless explicitly "off" 2aa308c #5658 'Apply :lmap in macros' 8ce6393 terminal: Leave 'relativenumber' alone (#8360) e46534b #4486 refactor: Remove maxmem, maxmemtot options 131aad9 win: defaults: 'shellcmdflag', 'shellxquote' #7343 c57d315 #8031 jobwait(): return -2 on interrupt also with timeout 6452831 clipboard: macOS: fallback to tmux if pbcopy is broken #7940 300d365 #7919 Make 'langnoremap' apply directly after a map ada1956 #7880 'lua/executor: Remove lightuserdata' INTERNAL: de0a954 #7806 internal statistics for list impl dee78a4 #7708 rewrite internal list impl
Adds the following:
introspection of all channels and jobs(do it in [RPC] Add methods to enumerate channels and clients to identify themselves #6743)