[vim/vim] [WIP] add ch_listen to listen socket (#3639)

146 views
Skip to first unread message

mattn

unread,
Nov 26, 2018, 3:24:43 AM11/26/18
to vim/vim, Subscribed

This change add new function ch_listen() to listen socket channel. To know more description, please read my slide(P79-P81) of keynote speach on VimConf2018.


You can view, comment on, or merge this pull request online at:

  https://github.com/vim/vim/pull/3639

Commit Summary

  • support ch_listen
  • update doc
  • listen
  • Merge branch 'master' into listen

File Changes

Patch Links:


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub

Codecov

unread,
Nov 26, 2018, 3:55:57 AM11/26/18
to vim/vim, Subscribed

Codecov Report

Merging #3639 into master will increase coverage by <.01%.
The diff coverage is 63.02%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #3639      +/-   ##
==========================================
+ Coverage   77.37%   77.37%   +<.01%     
==========================================
  Files          99       99              
  Lines      139407   139526     +119     
==========================================
+ Hits       107862   107960      +98     
- Misses      31545    31566      +21
Impacted Files Coverage Δ
src/evalfunc.c 87.19% <100%> (+0.01%) ⬆️
src/channel.c 82.29% <61.4%> (-0.93%) ⬇️
src/os_unix.c 57.34% <0%> (-0.14%) ⬇️
src/term.c 60.36% <0%> (-0.06%) ⬇️
src/syntax.c 78.45% <0%> (+0.02%) ⬆️
src/screen.c 79.24% <0%> (+0.06%) ⬆️
src/window.c 83.55% <0%> (+0.06%) ⬆️
src/gui_gtk_x11.c 48.5% <0%> (+0.39%) ⬆️
src/gui.c 57.65% <0%> (+0.56%) ⬆️
... and 1 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 3067a4d...dda0b89. Read the comment docs.

mattn

unread,
Nov 26, 2018, 4:57:33 AM11/26/18
to vim/vim, Subscribed

IMO, This is useful to communicate to Vim(s) with some protocols. For example, we will be possible to implement something without +clientserver feature.

依云

unread,
Nov 26, 2018, 5:36:51 AM11/26/18
to vim/vim, Subscribed

Would you add UNIX domain socket support? With TCP sockets you'd need a way to authenicate clients or trust all users on the machine (including all the daemon users for services). This is why I don't use plugins like deoplete.

mattn

unread,
Nov 26, 2018, 7:59:29 PM11/26/18
to vim/vim, Subscribed

Okay, I'll add it that specifying file path to the socket file with unix: prefix.

mattn

unread,
Nov 28, 2018, 8:25:25 AM11/28/18
to vim/vim, Push

@mattn pushed 4 commits.

  • 5921d59 Merge branch 'master' into listen
  • cf021a3 Merge branch 'master' into listen
  • 936b61f Support AF_UNIX
  • 71dbae1 Merge branch 'listen' of github.com:mattn/vim into listen


You are receiving this because you are subscribed to this thread.

View it on GitHub

mattn

unread,
Nov 28, 2018, 8:25:40 AM11/28/18
to vim/vim, Subscribed

Now supported AF_UNIX. This should work on Windows 10 too.

mattn

unread,
Nov 28, 2018, 8:42:52 AM11/28/18
to vim/vim, Push

@mattn pushed 1 commit.


You are receiving this because you are subscribed to this thread.

View it on GitHub

mattn

unread,
Nov 28, 2018, 8:55:55 AM11/28/18
to vim/vim, Push

@mattn pushed 1 commit.


You are receiving this because you are subscribed to this thread.

View it on GitHub

mattn

unread,
Nov 28, 2018, 9:08:07 AM11/28/18
to vim/vim, Push

@mattn pushed 1 commit.


You are receiving this because you are subscribed to this thread.

View it on GitHub

mattn

unread,
Nov 28, 2018, 9:22:38 AM11/28/18
to vim/vim, Push

@mattn pushed 1 commit.


You are receiving this because you are subscribed to this thread.

View it on GitHub

mattn

unread,
Feb 1, 2019, 6:44:53 AM2/1/19
to vim/vim, Push

@mattn pushed 50 commits.


You are receiving this because you are subscribed to this thread.

View it on GitHub

mattn

unread,
Feb 17, 2019, 7:16:06 PM2/17/19
to vim/vim, Push

@mattn pushed 1 commit.

  • ca97414 Merge branch 'master' into listen


You are receiving this because you are subscribed to this thread.

View it on GitHub

mattn

unread,
Feb 17, 2019, 10:03:16 PM2/17/19
to vim/vim, Push

@mattn pushed 1 commit.


You are receiving this because you are subscribed to this thread.

View it on GitHub

mattn

unread,
Sep 9, 2019, 11:03:51 PM9/9/19
to vim/vim, Push

@mattn pushed 1 commit.

  • b098434 Merge branch 'master' into listen


You are receiving this because you are subscribed to this thread.

View it on GitHub

Bram Moolenaar

unread,
Sep 22, 2019, 4:00:46 PM9/22/19
to vim/vim, Subscribed

This requires more documentation. A practical example is preferred.

Bram Moolenaar

unread,
Jun 8, 2020, 2:53:56 PM6/8/20
to vim/vim, Subscribed

Still awaiting a practical example.


You are receiving this because you are subscribed to this thread.

Reply to this email directly, view it on GitHub, or unsubscribe.

Prabir Shrestha

unread,
Jun 10, 2020, 2:42:22 AM6/10/20
to vim/vim, Subscribed

Here is an example I can think of:

Vim is single threaded so even if we improve perf by vimscript9 or lua there will be certain heavy computation that will cause vim to pause for certain time. Being able to start a new vim process and communicate with sockets/pipes/stdin/stdout will help us. My previous ask on having remote lua plugins contains more details on a concrete example such as fuzzy matching. #2115.
natebosch/vim-lsc#291 Here was another example where dart language server was returning 27k items and vim was hanging while vscode had no issue.


You are receiving this because you are subscribed to this thread.

Reply to this email directly, view it on GitHub, or unsubscribe.

Yegappan Lakshmanan

unread,
Jun 13, 2020, 3:05:18 PM6/13/20
to vim/vim, Subscribed

Another example use case for ch_listen() function:
Implementing a debugger for Vim scripts. We can run the script under debug in a
separate Vim instance where a server is running (using ch_listen). From the outside
Vim instance, we can connect to this server and run various commands (using the
JSON interface) to get the state of the script. Currently we need to use an external
server (written in Python or some other language) for this. Using ch_listen(), we can
natively do this in Vim without any external dependencies.


You are receiving this because you are subscribed to this thread.

Reply to this email directly, view it on GitHub, or unsubscribe.

Ben Jackson

unread,
Jun 14, 2020, 6:30:21 AM6/14/20
to vim/vim, Subscribed

@yegappan did you see this? https://groups.google.com/forum/m/#!searchin/vim_dev/Vimspector$20/vim_dev/Xzb0a3bTg1U done without listen uses a debug adapter.


You are receiving this because you are subscribed to this thread.

Reply to this email directly, view it on GitHub, or unsubscribe.

Bram Moolenaar

unread,
Jun 14, 2020, 7:47:54 AM6/14/20
to vim/vim, Subscribed

I can guess ch_listen() can make some things work that were not possible before. But this pull request is still missing an example. When someone wants to use ch_listen(), it must be clear how it works. Also to understand that it cannot do. A working example that someone can play with works best.


You are receiving this because you are subscribed to this thread.

Reply to this email directly, view it on GitHub, or unsubscribe.

Yegappan Lakshmanan

unread,
Jun 14, 2020, 3:27:35 PM6/14/20
to vim_dev, reply+ACY5DGFC2NCC7P6OIP...@reply.github.com, vim/vim, Subscribed
Hi Ben,

On Sun, Jun 14, 2020 at 3:30 AM Ben Jackson <vim-dev...@256bit.org> wrote:

@yegappan did you see this? https://groups.google.com/forum/m/#!searchin/vim_dev/Vimspector$20/vim_dev/Xzb0a3bTg1U done without listen uses a debug adapter.


I went through the Vimspector documentation. It looks like it supports languages
with a debug adapter but doesn't support debugging Vimscript. I was referring to
creating a debugger for Vimscript. Even with ch_listen(), we will need support
for running the Vim debugger in the background while still being able to see
the Vim output screen. This will need some changes to the current Vim debugger.

Regards,
Yegappan
 

vim-dev ML

unread,
Jun 14, 2020, 3:27:50 PM6/14/20
to vim/vim, vim-dev ML, Your activity

Hi Ben,

On Sun, Jun 14, 2020 at 3:30 AM Ben Jackson <vim-dev...@256bit.org>
wrote:

> @yegappan <https://github.com/yegappan> did you see this?

> https://groups.google.com/forum/m/#!searchin/vim_dev/Vimspector$20/vim_dev/Xzb0a3bTg1U
> done without listen uses a debug adapter.
>
>
> I went through the Vimspector documentation. It looks like it supports
languages
with a debug adapter but doesn't support debugging Vimscript. I was
referring to
creating a debugger for Vimscript. Even with ch_listen(), we will need
support
for running the Vim debugger in the background while still being able to see
the Vim output screen. This will need some changes to the current Vim
debugger.

Regards,
Yegappan


You are receiving this because you are subscribed to this thread.

Reply to this email directly, view it on GitHub, or unsubscribe.

Ben Jackson

unread,
Jun 14, 2020, 3:33:22 PM6/14/20
to vim/vim, vim-dev ML, Comment

@yegappan

wasreferring to creating a debugger for Vimscript.

that's exactly what I've done, and what my RFC and demo are all about: https://github.com/puremourning/vim-debug-adapter and my vim debugger branch: https://github.com/puremourning/vim/tree/debugger

I think I might have copied a dud url - this is the RFC I sent: https://groups.google.com/d/msg/vim_dev/Xzb0a3bTg1U/m3WMcOu2BAAJ


You are receiving this because you commented.
Reply to this email directly, view it on GitHub, or unsubscribe.

Yegappan Lakshmanan

unread,
Jun 14, 2020, 3:39:12 PM6/14/20
to vim_dev, reply+ACY5DGFRHAWN4OYYQW...@reply.github.com, vim/vim, vim-dev ML, Comment
Hi,

On Sun, Jun 14, 2020 at 12:33 PM Ben Jackson <vim-dev...@256bit.org> wrote:

@yegappan

wasreferring to creating a debugger for Vimscript.

that's exactly what I've done, and what my RFC and demo are all about: https://github.com/puremourning/vim-debug-adapter and my vim debugger branch: https://github.com/puremourning/vim/tree/debugger

I think I might have copied a dud url - this is the RFC I sent: https://groups.google.com/d/msg/vim_dev/Xzb0a3bTg1U/m3WMcOu2BAAJ



This looks very interesting and useful. Hopefully this gets integrated into Vim at some point.

Regards,
Yegappan

vim-dev ML

unread,
Jun 14, 2020, 3:39:31 PM6/14/20
to vim/vim, vim-dev ML, Your activity

Hi,

On Sun, Jun 14, 2020 at 12:33 PM Ben Jackson <vim-dev...@256bit.org>
wrote:

> @yegappan <https://github.com/yegappan>

>
> wasreferring to creating a debugger for Vimscript.
>
> that's exactly what I've done, and what my RFC and demo are all about:
> https://github.com/puremourning/vim-debug-adapter and my vim debugger
> branch: https://github.com/puremourning/vim/tree/debugger
>
> I think I might have copied a dud url - this is the RFC I sent:
> https://groups.google.com/d/msg/vim_dev/Xzb0a3bTg1U/m3WMcOu2BAAJ
>
>
>
This looks very interesting and useful. Hopefully this gets integrated into
Vim at some point.

Regards,
Yegappan


You are receiving this because you are subscribed to this thread.

Reply to this email directly, view it on GitHub, or unsubscribe.

Ben Jackson

unread,
Jun 14, 2020, 3:41:09 PM6/14/20
to vim/vim, vim-dev ML, Comment

Thanks. My goal is to get it all to a shippable/professional level "in 2020". I expect the first PRs in Q3. It's likely to be a lot of smaller PRs and some discussion with Bram/etc. so I wouldn't expect it super soon, but you're more than welcome to try the branch out now. It does mostly work.


You are receiving this because you commented.

Alisue

unread,
Oct 8, 2020, 3:16:16 PM10/8/20
to vim/vim, vim-dev ML, Comment

Any news? I'd love to make a plugin which shows a prompt/buffer to input text for commands in jobstart() through some environment variable (e.g. EDITOR or SSH_ASKPASS).

I can make it for Neovim while it has RPC but Vim. If there is ch_listen(), I can use it to handle the Vim from a process executed in jobstart().

mattn

unread,
Oct 8, 2020, 9:21:33 PM10/8/20
to vim/vim, vim-dev ML, Push

@mattn pushed 1 commit.

  • 65b2664 Merge branch 'master' into listen


You are receiving this because you are subscribed to this thread.

View it on GitHub or unsubscribe.

Bram Moolenaar

unread,
Oct 9, 2020, 4:39:21 PM10/9/20
to vim/vim, vim-dev ML, Comment

This is still lacking an example.
The help is very brief. I guess "List to a channel" actually means "listen on a socket".
Does this work on all systems?
"sys/un.h" is a newly used include file, is this available everywhere or does it require a configure check?
The test lacks testing for the possible errors.

Ben Jackson

unread,
Oct 9, 2020, 6:15:37 PM10/9/20
to vim/vim, vim-dev ML, Comment

@puremourning commented on this pull request.

I was curious about how this would work, so I added some commentary. The API seems a little surprising to me, and it seems to introduce a new unix domain sockets support (which I think is welcome, but undocumented and untested).


In runtime/doc/channel.txt:

> @@ -584,6 +584,17 @@ ch_info({handle})						*ch_info()*
 		Can also be used as a |method|: >
 			GetChannel()->ch_info()
 
+ch_listen({address} [, {options}])				*ch_listen()*

This seems to imply that there may only be one attached client on this socket. I would have expected there to be a sort of accept callback which is passed the channel which is created by the client socket event, returning true/false (maybe) as to whether or not to accept the connection.

Perhaps supporting multiple clients on the same port is just something that a text editor shouldn't do, but it doens't seem much of a stretch from 1 to N.


In src/channel.c:

> +    {
+	is_unix = TRUE;
+	vim_memset((char *)&unixaddr, 0, sizeof(unixaddr));
+	unixaddr.sun_family = AF_UNIX;
+	STRNCPY(unixaddr.sun_path, channel->ch_hostname+5, sizeof(unixaddr.sun_path)-1);
+    }
+    else
+    {
+	/* Get the server internet address and put into addr structure */
+	/* fill in the socket address structure and connect to server */
+	vim_memset((char *)&server, 0, sizeof(server));
+	server.sin_family = AF_INET;
+	server.sin_port = htons(port);
+	if ((host = gethostbyname(channel->ch_hostname)) == NULL)
+	{
+	    ch_error(channel, "in gethostbyname() in channel_open()");

does this error include anything that can be used to work out what went wrong?

What happens if we use something like ch_listen( '0.0.0.0:1234' ) ? How about IPV6 addresses ?


In src/channel.c:

>  #endif
 
+    channel = add_channel();
+    if (channel == NULL)
+    {
+	ch_error(NULL, "Cannot allocate channel.");
+	return -1;
+    }
+
+    if (STRNCMP(channel->ch_hostname, "unix:", 5) == 0)

Is this unrelated to this PR? I mean, is this an undocumented way to use unix domain sockets?

I mean I'm all for supporting unix domain sockets for ch_open() and friends, but is that strictly part of this PR?


In runtime/doc/eval.txt:

> @@ -2448,6 +2448,8 @@ ch_evalraw({handle}, {string} [, {options}])
 ch_getbufnr({handle}, {what})	Number	get buffer number for {handle}/{what}
 ch_getjob({channel})		Job	get the Job of {channel}
 ch_info({handle})		String	info about channel {handle}
+ch_listen({address} [, {options}])
+				Channel	listen to a channel with {address}

I think this text could be improved, "Start listening for connections to {address}" perhaps.


In runtime/doc/channel.txt:

> @@ -584,6 +584,17 @@ ch_info({handle})						*ch_info()*
 		Can also be used as a |method|: >
 			GetChannel()->ch_info()
 
+ch_listen({address} [, {options}])				*ch_listen()*
+		Listen to a channel with {address}.  See |channel|.
+		Returns a Channel.  Use |ch_status()| to check for failure.
+
+		{address} has the form "hostname:port", e.g.,
+		"localhost:8765" or ":8765".
+
+		If {options} is given it must be a |Dictionary|.
+		See |channel-open-options|.

do all options apply?


In runtime/doc/channel.txt:

> @@ -584,6 +584,17 @@ ch_info({handle})						*ch_info()*
 		Can also be used as a |method|: >
 			GetChannel()->ch_info()
 
+ch_listen({address} [, {options}])				*ch_listen()*
+		Listen to a channel with {address}.  See |channel|.
+		Returns a Channel.  Use |ch_status()| to check for failure.

What happens if you write to or read from the channel before the client connects? For that matter, how is the user informed of the client connection?

Or is this API assuming that you'll wait synchronously for a client to connect to this port ? If so I think that's (probably) bad. I find it hard to imagine that all use cases for this would want to block until some client connects. I would have expected it to be more event driven, or at least.... that should be an option?

For simplicity sake, I can see that a synchronous version might be useful I suppose.


In runtime/doc/channel.txt:

> @@ -584,6 +584,17 @@ ch_info({handle})						*ch_info()*
 		Can also be used as a |method|: >
 			GetChannel()->ch_info()
 
+ch_listen({address} [, {options}])				*ch_listen()*
+		Listen to a channel with {address}.  See |channel|.

"Listening to a channel" isn't really what we're doing, we're listening on a port (ok, a socket), there result of which is a channel representing a connection to a client.


In src/channel.c:

> +
+    if (STRNCMP(channel->ch_hostname, "unix:", 5) == 0)
+    {
+	is_unix = TRUE;
+	vim_memset((char *)&unixaddr, 0, sizeof(unixaddr));
+	unixaddr.sun_family = AF_UNIX;
+	STRNCPY(unixaddr.sun_path, channel->ch_hostname+5, sizeof(unixaddr.sun_path)-1);
+    }
+    else
+    {
+	/* Get the server internet address and put into addr structure */
+	/* fill in the socket address structure and connect to server */
+	vim_memset((char *)&server, 0, sizeof(server));
+	server.sin_family = AF_INET;
+	server.sin_port = htons(port);
+	if ((host = gethostbyname(channel->ch_hostname)) == NULL)

at least on my system, man gethostbyname says

 The getaddrinfo(3) and getnameinfo(3) functions are preferred over the gethostbyname(), gethostbyname2(), and gethostbyaddr() functions.

In src/channel.c:

> @@ -3569,6 +3877,48 @@ channel_read(channel_T *channel, ch_part_T part, char *func)
     {
 	if (channel_wait(channel, fd, 0) != CW_READY)
 	    break;
+	if (channel->ch_listen)

so is this the only way to accept from the socket? I.e. the user has to do something like:

let ch = ch_listen( address, #{ callback: function( 'HandleDataOnSocket' ) } )
" see time later...
" this is a blocking call and we'll get data in the callback ? It will return after calling our callback ?
call ch_read( ch )

I think we really need an example of how to use this API in practice because it's really not obvious how to use it (as-is) for any of the proposed use cases. Use of ch_read() as a proxy for accept() when the channel happens to be listening seems surprising to me.


In src/testdir/test_channel.vim:

> @@ -1908,6 +1908,32 @@ func Test_close_lambda()
   call s:run_server('Ch_test_close_lambda')
 endfunc
 
+let g:server_received_addr = ''
+let g:server_received_msg = ''
+func s:test_listen_accept(ch, addr)
+  let g:server_received_addr = a:addr
+  let g:server_received_msg = ch_readraw(a:ch)
+endfunction
+
+func Test_listen()

tests seem... optimistic.

the code seems to include a completely new mechanism for using unix: to use a domain socket, but no tests for it.


In src/testdir/test_channel.vim:

> @@ -1908,6 +1908,32 @@ func Test_close_lambda()
   call s:run_server('Ch_test_close_lambda')
 endfunc
 
+let g:server_received_addr = ''
+let g:server_received_msg = ''
+func s:test_listen_accept(ch, addr)
+  let g:server_received_addr = a:addr
+  let g:server_received_msg = ch_readraw(a:ch)
+endfunction
+
+func Test_listen()
+  call ch_log('Test_listen()')
+  let server = ch_listen('127.0.0.1:' . 12345, {"callback": function("s:test_listen_accept")})
+  if ch_status(server) == "fail"
+    call assert_report("Can't listen channel")
+    return

so you set the channel callback to something which calls ch_read, which is what calls accept ?

how does it receive subsequent messages ? how to you write to the channel ?

skanehira

unread,
Oct 9, 2020, 8:38:20 PM10/9/20
to vim/vim, vim-dev ML, Comment

I want to make a markdown preview plugin using ch_listen.
I think ch_listen brings a good experience because If we can use ch_listen, we don't need any dependencies to make some plugins.

Bram Moolenaar

unread,
Jun 27, 2022, 12:54:08 PM6/27/22
to vim/vim, vim-dev ML, Comment

Closed #3639.


Reply to this email directly, view it on GitHub.
You are receiving this because you commented.Message ID: <vim/vim/pull/3639/issue_event/6886916464@github.com>

Bram Moolenaar

unread,
Jun 27, 2022, 1:00:14 PM6/27/22
to vim/vim, vim-dev ML, Comment

A lot of time has passed and there still is no example of how this wood be used.
Theoretically this would add a useful feature, but it's not clear if this is the right way to do this.
I'll close this now. Feel free to make a better version of this PR.


Reply to this email directly, view it on GitHub.

You are receiving this because you commented.Message ID: <vim/vim/pull/3639/c1167590976@github.com>

Christian Brabandt

unread,
Jan 21, 2026, 2:33:20 PMJan 21
to vim/vim, vim-dev ML, Comment
chrisbra left a comment (vim/vim#3639)

People who would like this, can you please see if #19231 is working for your use case?


Reply to this email directly, view it on GitHub.

You are receiving this because you commented.Message ID: <vim/vim/pull/3639/c3780780696@github.com>

Reply all
Reply to author
Forward
0 new messages