patch 9.2.0512: clientserver uses binary protocol

Problem:  clientserver feature uses binary protocol and is hard
          to understand
Solution: Rewrite the code based on channels and JSON messages
          (Foxe Chen).

closes: #19782

Signed-off-by: Foxe Chen <chen.foxe@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Foxe Chen
2026-05-22 18:30:52 +00:00
committed by Christian Brabandt
parent 1d727b6f74
commit e9c793bebc
40 changed files with 2128 additions and 2300 deletions
+2
View File
@@ -145,6 +145,7 @@ SRC_ALL = \
src/session.c \
src/sha256.c \
src/sign.c \
src/socketserver.c \
src/sound.c \
src/spell.c \
src/spell.h \
@@ -344,6 +345,7 @@ SRC_ALL = \
src/proto/session.pro \
src/proto/sha256.pro \
src/proto/sign.pro \
src/proto/socketserver.pro \
src/proto/sound.pro \
src/proto/spell.pro \
src/proto/spellfile.pro \
+47 -32
View File
@@ -79,9 +79,10 @@ The following command line arguments are available:
*--clientserver*
--clientserver {method} Use the specified method {method} as the
backend for clientserver functionality. Can
either be "socket" or "x11".
either be "socket", "x11", or "mswin".
{only available when compiled with both |+X11|
and |+socketserver| features}
and |+socketserver| features, or
|+socketserver| on MS-Windows}
Examples ~
@@ -220,12 +221,16 @@ When using gvim, the --remote-wait only works properly this way: >
<
==============================================================================
4. Socket server specific items *socketserver-clientserver*
*E1563* *E1564* *E1565* *E1566* *E1567*
*E1564* *E1565* *E1566*
The communication between client and server is done using Unix domain sockets.
These sockets are either placed in these directories in the following order of
NOTE: Vim version before patch 9.2.511 use a different socketserver backend
which is incompatible with the new one, which is based on channels and JSON.
The communication between client and server is done using channels internally.
When using the traditional/generic clientserver naming (only available on
Unix), sockets are placed in these directories in the following order of
availability:
1. "$XDG_RUTIME_DIR/vim" if $XDG_RUNTIME_DIR is set in the environment.
1. "$XDG_RUNTIME_DIR/vim" if $XDG_RUNTIME_DIR is set in the environment.
2. "$TMPDIR/vim-[uid]", where "[uid]" is the uid of the user. This
directory will have the access permissions set to 700 so only the user
can read or write from/to it. If $TMPDIR is not set, "/tmp" is used.
@@ -237,45 +242,55 @@ absolute or relative path. If the server id starts with either a "/"
Otherwise the server id will be the filename of the socket which will be
placed in the above common directories. Note that a server id/name can only
contain slashes "/" if it is taken as a path, so names such as "abc/dir" will
be invalid.
be invalid. This feature is only available on Unix.
Socket server functionality is available in both GTK GUI and terminal versions
of Vim. Unless Vim is compiled with |+autoservername| feature, the socket
server will have to started explicitly, just like X11, even in the GUI.
*socketserver-address*
In addition, the socketserver can also be created as a |channel-address|. To
do this, prefix the address with "channel:" (which will be ignored). This is
available on both Unix and MS-Windows, and is the only available naming for the
socketserver backend on Windows. However, note that |ch_listen()|
restrictions apply, meaning only port numbers can be used for TCP sockets.
If the name is prefixed with "name:", then the legacy servername behaviour is
used, so "name:VIM" is the same as "VIM".
Unless Vim is compiled with |+autoservername| feature, the socket server will
have to started explicitly, similar to X11. This is unless a X11 GUI Vim is
being used.
If Vim crashes or does not exit cleanly, the socket server will not remove the
socket file and it will be left around. This is generally not a problem,
because if a socket name is taken, Vim checks if the socket in its place is
dead (not attached to any process), and can replace it instead of finding a
new name.
To send commands to a Vim socket server from another application, read the
source file src/os_unix.c, there is detailed description of the protocol used.
new name. This is only relevant for Unix.
*socketserver-differences*
Most of the functionality is the same as X11, however unlike X11, where the
client does not need to be a server in order to communicate with another
server, the socket server requires the server to be running even as a client.
The exception is |serverlist()| or the |--serverlist| argument, which does not
require the server to be running.
Most of the functionality is the same as the other clientserver backends.
Additionally, the server id or client id will not be a number like X11 or
However, the server id or client id will not be a number like X11 or
MS-Windows (shown in hex representation), instead it is the absolute path to
the socket. This can be seen via the |v:servername| variable.
the socket. This can be seen via the |v:servername| variable. If the name is
a channel address, then it will be the address with the "a/" prefix as well.
The |--serverlist| argument will act just like X11, however it only checks the
given common directories above. If a custom path is used for a socket, it
will not be detected, such as a path either not in $XDG_RUNTIME_DIR or
<$TMPDIR or /tmp>/vim of the |--serverlist| Vim process.
Note when using |--remote-wait|, the client id will look like "t/<some
number>". This naming is specifically for this command, and attempting to use
it as an address will fail.
If you have both |+socketserver| and |+X11| compiled, you will need to add
|--clientserver| set to "socket" in combination with |--serverlist| to list
the available servers. You cannot list both types of backends in one command.
If on Unix, the |--serverlist| argument will act just like X11, however it
only checks the given common directories above. If a custom path is used for
a socket, it will not be detected, such as a path either not in
$XDG_RUNTIME_DIR or <$TMPDIR or /tmp>/vim of the |--serverlist| Vim process.
If on MS-Windows, then the |--serverlist| argument will output nothing.
The |+socketserver| feature is automatically enabled when on Unix or
MS-Windows, and the |+channel| feature is enabled
*socketserver-x11*
If Vim is compiled with both |+X11| and |+socketserver|, then deciding which
backend to use is done at startup time, via the |--clientserver| argument. By
default if it is not specified, then X11 will be used. A Vim instance using a
socket server cannot communicate with one using X11.
If Vim is compiled with |+socketserver| and another clientserver backend, then
deciding which backend to use is done at startup time, via the
|--clientserver| argument. By default if it is not specified, then the native
backend (X11 or MS-Window messages) will be used, if available. A Vim
instance using a socket server cannot communicate with one using another
clientserver backend.
vim:tw=78:sw=4:ts=8:noet:ft=help:norl:
+1 -2
View File
@@ -4762,11 +4762,9 @@ E156 sign.txt /*E156*
E1560 vim9.txt /*E1560*
E1561 vim9.txt /*E1561*
E1562 options.txt /*E1562*
E1563 remote.txt /*E1563*
E1564 remote.txt /*E1564*
E1565 remote.txt /*E1565*
E1566 remote.txt /*E1566*
E1567 remote.txt /*E1567*
E1568 options.txt /*E1568*
E1569 builtin.txt /*E1569*
E157 sign.txt /*E157*
@@ -10377,6 +10375,7 @@ slow-fast-terminal term.txt /*slow-fast-terminal*
slow-start starting.txt /*slow-start*
slow-terminal term.txt /*slow-terminal*
socket-interface channel.txt /*socket-interface*
socketserver-address remote.txt /*socketserver-address*
socketserver-clientserver remote.txt /*socketserver-clientserver*
socketserver-differences remote.txt /*socketserver-differences*
socketserver-name remote.txt /*socketserver-name*
+2 -1
View File
@@ -1,4 +1,4 @@
*version9.txt* For Vim version 9.2. Last change: 2026 May 19
*version9.txt* For Vim version 9.2. Last change: 2026 May 22
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -52665,6 +52665,7 @@ Changed ~
if needed, see |wayland-primary-selection| for an example.
- On Unix, filename completion for single-file Ex commands now treats embedded
whitespace as part of the filename, like on other platforms.
- Rewrite the clientserver socketserver backend to use channels and JSON.
*added-9.3*
+4 -3
View File
@@ -504,9 +504,10 @@ socketserver backend is being used, if the name starts with "/", "./", or "../",
it is taken as either an absolute, relative or relative path to the socket.
.TP
\-\-clientserver {backend}
Use {backend} as the backend for clientserver functionality, either "socket" or
"x11" respectively. Only available when compiled with both socketserver and X11
features present
Use {backend} as the backend for clientserver functionality, either "socket",
"x11", or "mswin" respectively. Only available when compiled with both
socketserver and X11 features present, or if compiled with socketserver on
MS-Windows.
.TP
\-\-socketid {id}
GTK GUI only: Use the GtkPlug mechanism to run gVim in another window.
+4 -3
View File
@@ -385,9 +385,10 @@ OPTIONS
--clientserver {backend}
Use {backend} as the backend for clientserver functional
ity, either "socket" or "x11" respectively. Only available
when compiled with both socketserver and X11 features
present
ity, either "socket", "x11", or "mswin" respectively. Only
available when compiled with both socketserver and X11 fea
tures present, or if compiled with socketserver on MS-Win
dows.
--socketid {id}
GTK GUI only: Use the GtkPlug mechanism to run gVim in an
+1
View File
@@ -877,6 +877,7 @@ OBJ = \
$(OUTDIR)/session.o \
$(OUTDIR)/sha256.o \
$(OUTDIR)/sign.o \
$(OUTDIR)/socketserver.o \
$(OUTDIR)/spell.o \
$(OUTDIR)/spellfile.o \
$(OUTDIR)/spellsuggest.o \
+4
View File
@@ -772,6 +772,7 @@ OBJ = \
$(OUTDIR)\session.obj \
$(OUTDIR)\sha256.obj \
$(OUTDIR)\sign.obj \
$(OUTDIR)\socketserver.obj \
$(OUTDIR)\spell.obj \
$(OUTDIR)\spellfile.obj \
$(OUTDIR)\spellsuggest.obj \
@@ -1767,6 +1768,8 @@ $(OUTDIR)/sha256.obj: $(OUTDIR) sha256.c $(INCL)
$(OUTDIR)/sign.obj: $(OUTDIR) sign.c $(INCL)
$(OUTDIR)/socketserver.obj: $(OUTDIR) socketserver.c $(INCL)
$(OUTDIR)/spell.obj: $(OUTDIR) spell.c $(INCL)
$(OUTDIR)/spellfile.obj: $(OUTDIR) spellfile.c $(INCL)
@@ -2017,6 +2020,7 @@ proto.h: \
proto/session.pro \
proto/sha256.pro \
proto/sign.pro \
proto/socketserver.pro \
proto/spell.pro \
proto/spellfile.pro \
proto/spellsuggest.pro \
+11
View File
@@ -1571,6 +1571,7 @@ BASIC_SRC = \
session.c \
sha256.c \
sign.c \
socketserver.c \
sound.c \
spell.c \
spellfile.c \
@@ -1749,6 +1750,7 @@ OBJ_COMMON = \
objects/session.o \
objects/sha256.o \
objects/sign.o \
objects/socketserver.o \
objects/sound.o \
objects/spell.o \
objects/spellfile.o \
@@ -3592,6 +3594,9 @@ objects/sha256.o: sha256.c
objects/sign.o: sign.c
$(CCC) -o $@ sign.c
objects/socketserver.o: socketserver.c
$(CCC) -o $@ socketserver.c
objects/sound.o: sound.c
$(CCC) -o $@ sound.c
@@ -4267,6 +4272,11 @@ objects/sign.o: auto/osdef.h sign.c vim.h protodef.h auto/config.h feature.h os_
structs.h regexp.h gui.h libvterm/include/vterm.h \
libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \
globals.h errors.h
objects/socketserver.o: socketserver.c vim.h protodef.h auto/config.h feature.h \
os_unix.h auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h \
beval.h structs.h regexp.h gui.h libvterm/include/vterm.h \
libvterm/include/vterm_keycodes.h xdiff/xdiff.h xdiff/../vim.h alloc.h \
ex_cmds.h spell.h proto.h globals.h errors.h
objects/sound.o: auto/osdef.h sound.c vim.h protodef.h auto/config.h feature.h os_unix.h \
ascii.h keymap.h termdefs.h macros.h option.h beval.h \
structs.h regexp.h gui.h libvterm/include/vterm.h \
@@ -4793,6 +4803,7 @@ proto/search.pro: search.c
proto/session.pro: session.c
proto/sha256.pro: sha256.c
proto/sign.pro: sign.c
proto/socketserver.pro: socketserver.c
proto/sound.pro: sound.c
proto/spell.pro: spell.c
proto/spellfile.pro: spellfile.c
-32
View File
@@ -850,7 +850,6 @@ enable_netbeans
enable_channel
enable_terminal
enable_autoservername
enable_socketserver
enable_multibyte
enable_rightleft
enable_arabic
@@ -1532,7 +1531,6 @@ Optional Features:
--disable-channel Disable process communication support.
--enable-terminal Enable terminal emulation support.
--enable-autoservername Automatically define servername at vim startup.
--enable-socketserver Use sockets for clientserver communication.
--enable-multibyte Include multibyte editing support.
--disable-rightleft Do not include Right-to-Left language support.
--disable-arabic Do not include Arabic language support.
@@ -9077,36 +9075,6 @@ if test "$enable_autoservername" = "yes"; then
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking --enable-socketserver argument" >&5
printf %s "checking --enable-socketserver argument... " >&6; }
# Check whether --enable-socketserver was given.
if test ${enable_socketserver+y}
then :
enableval=$enable_socketserver; enable_socketserver=$enableval
else case e in #(
e) if test "x$features" = xtiny
then :
enable_socketserver=no_msg
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: cannot use socketserver with tiny features" >&5
printf "%s\n" "cannot use socketserver with tiny features" >&6; }
else case e in #(
e) enable_socketserver=yes ;;
esac
fi ;;
esac
fi
if test "$enable_socketserver" = "yes"; then
printf "%s\n" "#define WANT_SOCKETSERVER 1" >>confdefs.h
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
printf "%s\n" "yes" >&6; }
elif test "$enable_socketserver" = "no"; then
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
printf "%s\n" "no" >&6; }
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking --enable-multibyte argument" >&5
printf %s "checking --enable-multibyte argument... " >&6; }
# Check whether --enable-multibyte was given.
+111 -21
View File
@@ -820,7 +820,7 @@ channel_connect(
* Returns the channel for success.
* Returns NULL for failure.
*/
static channel_T *
channel_T *
channel_open_unix(
const char *path,
void (*nb_close_cb)(void))
@@ -1290,6 +1290,46 @@ channel_set_options(channel_T *channel, jobopt_T *opt)
channel->ch_part[PART_IN].ch_io = opt->jo_io[PART_IN];
}
/*
* Parse the address for socketserver and store port in "port", or the path in
* "unix_path" if it is a unix domain socket. Returns OK on success and FAIL on
* failure.
*/
int
channel_parse_socketserver_address(
char_u *address,
int *port,
char_u **unix_path,
bool quiet)
{
char *rest;
long val;
if (*address == NUL)
goto fail;
if (!STRNCMP(address, "unix:", 5))
{
*unix_path = vim_strsave(address + 5);
return OK;
}
val = strtol((char *)(address), &rest, 10);
if (val < 0 || val >= 65536 || *rest != NUL)
{
if (!quiet)
semsg(_(e_invalid_argument_str), address);
return FAIL;
}
*port = (int)val;
return OK;
fail:
if (!quiet)
semsg(_(e_invalid_argument_str), address);
return FAIL;
}
/*
* Implements ch_open().
*/
@@ -1449,7 +1489,7 @@ channel_listen_func(typval_T *argvars)
}
if (is_unix)
channel = channel_listen_unix((char *)arg, NULL);
channel = channel_listen_unix((char *)arg, NULL, true);
else
channel = channel_listen(port, NULL);
if (channel != NULL)
@@ -1571,13 +1611,15 @@ channel_listen(
/*
* Listen to a Unix domain socket channel.
* If "replace" is true, then unlink the path first beforehand.
* Returns the channel for success.
* Returns NULL for failure.
*/
channel_T *
channel_listen_unix(
char *path,
void (*nb_close_cb)(void))
void (*nb_close_cb)(void),
bool replace)
{
int sd = -1;
struct sockaddr_un server;
@@ -1619,8 +1661,9 @@ channel_listen_unix(
return NULL;
}
// Unlink the socket in case it already exists
unlink(server.sun_path);
if (replace)
// Unlink the socket in case it already exists
unlink(server.sun_path);
// Bind the socket to the path
server_len = offsetof(struct sockaddr_un, sun_path) + path_len + 1;
@@ -1983,7 +2026,7 @@ channel_buffer_free(buf_T *buf)
/*
* Write any lines waiting to be written to "channel".
*/
static void
void
channel_write_input(channel_T *channel)
{
chanpart_T *in_part = &channel->ch_part[PART_IN];
@@ -2364,7 +2407,7 @@ channel_save(channel_T *channel, ch_part_T part, char_u *buf, int len,
* Try to fill the buffer of "reader".
* Returns FALSE when nothing was added.
*/
static int
int
channel_fill(js_read_T *reader)
{
channel_T *channel = (channel_T *)reader->js_cookie;
@@ -2484,11 +2527,12 @@ channel_process_lspdap_http_hdr(js_read_T *reader)
/*
* Use the read buffer of "channel"/"part" and parse a JSON message that is
* complete. The messages are added to the queue.
* complete. The messages are added to the queue. If "socketserver" is true,
* then ignore the channel mode.
* Return TRUE if there is more to read.
*/
static int
channel_parse_json(channel_T *channel, ch_part_T part)
int
channel_parse_json(channel_T *channel, ch_part_T part, bool socketserver)
{
js_read_T reader;
typval_T listtv;
@@ -2507,8 +2551,8 @@ channel_parse_json(channel_T *channel, ch_part_T part)
reader.js_cookie = channel;
reader.js_cookie_arg = part;
if (chanpart->ch_mode == CH_MODE_LSP
|| chanpart->ch_mode == CH_MODE_DAP)
if (!socketserver && (chanpart->ch_mode == CH_MODE_LSP
|| chanpart->ch_mode == CH_MODE_DAP))
status = channel_process_lspdap_http_hdr(&reader);
// When a message is incomplete we wait for a short while for more to
@@ -2526,14 +2570,16 @@ channel_parse_json(channel_T *channel, ch_part_T part)
{
// Only accept the response when it is a list with at least two
// items.
if ((chanpart->ch_mode == CH_MODE_LSP || chanpart->ch_mode == CH_MODE_DAP)
if (!socketserver && (chanpart->ch_mode == CH_MODE_LSP
|| chanpart->ch_mode == CH_MODE_DAP)
&& listtv.v_type != VAR_DICT)
{
ch_error(channel, "Did not receive a LSP dict, discarding");
clear_tv(&listtv);
}
else if (chanpart->ch_mode != CH_MODE_LSP && chanpart->ch_mode != CH_MODE_DAP
&& (listtv.v_type != VAR_LIST || listtv.vval.v_list->lv_len < 2))
else if (!socketserver && chanpart->ch_mode != CH_MODE_LSP
&& chanpart->ch_mode != CH_MODE_DAP
&& (listtv.v_type != VAR_LIST || listtv.vval.v_list->lv_len < 2))
{
if (listtv.v_type != VAR_LIST)
ch_error(channel, "Did not receive a list, discarding");
@@ -2668,7 +2714,7 @@ remove_cb_node(cbq_T *head, cbq_T *node)
* Remove "node" from the queue that it is in and free it.
* Caller should have freed or used node->jq_value.
*/
static void
void
remove_json_node(jsonq_T *head, jsonq_T *node)
{
if (node->jq_prev == NULL)
@@ -3227,8 +3273,12 @@ may_invoke_callback(channel_T *channel, ch_part_T part)
int called_otc; // one time callbackup
int raw_len = 0;
if (channel->ch_nb_close_cb != NULL)
// this channel is handled elsewhere (netbeans)
if (channel->ch_nb_close_cb != NULL
#ifdef FEAT_SOCKETSERVER
|| channel->ch_socketserver
#endif
)
// this channel is handled elsewhere (netbeans or socketserver)
return FALSE;
// Use a message-specific callback, part callback or channel callback
@@ -3267,7 +3317,7 @@ may_invoke_callback(channel_T *channel, ch_part_T part)
(void)channel_collapse(channel, part, FALSE);
// Parse readahead, return when there is still no message.
channel_parse_json(channel, part);
channel_parse_json(channel, part, false);
if (channel_get_json(channel, part, -1, FALSE, &listtv) == FAIL)
return FALSE;
}
@@ -3595,7 +3645,7 @@ channel_readahead_pointer(channel_T *channel, ch_part_T part)
if (head->jq_next == NULL)
// Parse json from readahead, there might be a complete message to
// process.
channel_parse_json(channel, part);
channel_parse_json(channel, part, false);
return head->jq_next;
}
@@ -3842,6 +3892,11 @@ channel_close(channel_T *channel, int invoke_close_cb)
}
channel->ch_nb_close_cb = NULL;
#ifdef FEAT_SOCKETSERVER
channel->ch_socketserver = false;
channel->ch_ss_accept_cb = NULL;
channel->ch_ss_close_cb = NULL;
#endif
#ifdef FEAT_TERMINAL
term_channel_closed(channel);
@@ -4181,6 +4236,10 @@ channel_close_now(channel_T *channel)
ch_log(channel, "Closing channel because all readable fds are closed");
if (channel->ch_nb_close_cb != NULL)
(*channel->ch_nb_close_cb)();
#ifdef FEAT_SOCKETSERVER
if (channel->ch_ss_close_cb != NULL)
channel->ch_ss_close_cb(channel);
#endif
channel_close(channel, TRUE);
}
@@ -4252,6 +4311,14 @@ channel_read(channel_T *channel, ch_part_T part, char *func)
channel_gui_register_one(newchannel, PART_SOCK);
#endif
#ifdef FEAT_SOCKETSERVER
if (channel->ch_ss_accept_cb != NULL)
{
channel->ch_ss_accept_cb(newchannel);
return;
}
#endif
if (client.ss_family == AF_INET)
{
#ifdef HAVE_INET_NTOP
@@ -4323,6 +4390,16 @@ channel_read(channel_T *channel, ch_part_T part, char *func)
#endif
}
#ifdef FEAT_SOCKETSERVER
void
channel_check(channel_T *channel, ch_part_T part)
{
channel_read(channel, part, "channel_check");
}
#endif
/*
* Read from RAW or NL "channel"/"part". Blocks until there is something to
* read or the timeout expires.
@@ -4465,7 +4542,7 @@ channel_read_json_block(
// received messages.
(void)channel_collapse(channel, part, FALSE);
more = channel_parse_json(channel, part);
more = channel_parse_json(channel, part, false);
// search for message "id"
if (channel_get_json(channel, part, id, TRUE, rettv) == OK)
@@ -5915,4 +5992,17 @@ channel_to_string_buf(typval_T *varp, char_u *buf)
return buf;
}
/*
* Return the channel with the given ID. Returns NULL if not found.
*/
channel_T *
channel_find(int ch_id)
{
channel_T *ch;
FOR_ALL_CHANNELS(ch)
if (ch->ch_id == ch_id)
return ch;
return NULL;
}
#endif // FEAT_JOB_CHANNEL
+179 -187
View File
@@ -15,11 +15,6 @@
#if defined(FEAT_CLIENTSERVER)
# ifdef FEAT_SOCKETSERVER
# include <sys/socket.h>
# include "sys/un.h"
# endif
static void cmdsrv_main(int *argc, char **argv, char_u *serverName_arg, char_u **serverStr);
static char_u *serverMakeName(char_u *arg, char *cmd);
@@ -206,23 +201,6 @@ exec_on_server(mparm_T *parmp)
serverInitMessaging();
# endif
# ifdef FEAT_SOCKETSERVER
// If servername is specified and we are using sockets, always init the
// sockt server. We may need to receive replies back to us. If --serverlist
// is passed, the socket server will be uninitialized before listing
// sockets then initialized after. This is so we don't add our own socket
// in the list. This does not happen in serverlist().
if ((parmp->serverArg || parmp->serverName_arg != NULL) &&
clientserver_method == CLIENTSERVER_METHOD_SOCKET)
{
parmp->servername = serverMakeName(parmp->serverName_arg,
parmp->argv[0]);
if (socket_server_init(parmp->servername) == OK)
TIME_MSG("initialize socket server");
made_name = TRUE;
}
# endif
/*
* When a command server argument was found, execute it. This may
* exit Vim when it was successful. Otherwise it's executed further
@@ -242,10 +220,12 @@ exec_on_server(mparm_T *parmp)
parmp->servername = serverMakeName(parmp->serverName_arg,
parmp->argv[0]);
# ifdef MSWIN
if (parmp->servername != NULL)
if (parmp->servername != NULL && clientserver_method == CLIENTSERVER_METHOD_MSWIN)
{
serverSetName(parmp->servername);
# ifndef FEAT_SOCKETSERVER
vim_free(parmp->servername);
# endif
}
# endif
}
@@ -262,16 +242,31 @@ prepare_server(mparm_T *parmp)
* Only register nongui-vim's with an explicit --servername argument,
* or when compiling with autoservername.
* When running as root --servername is also required.
*
* If we are Windows and socketserver is being used, then don't use
* autoservername, since traditional naming isn't supported.
*/
if (
# ifdef FEAT_X11
X_DISPLAY != NULL &&
# if defined(FEAT_X11) || (defined(FEAT_SOCKETSERVER) && !defined(MSWIN))
(
# ifdef FEAT_X11
X_DISPLAY != NULL
# endif
# if defined(FEAT_X11) && defined(FEAT_SOCKETSERVER) && !defined(MSWIN)
||
# endif
# if defined(FEAT_SOCKETSERVER) && !defined(MSWIN)
clientserver_method == CLIENTSERVER_METHOD_SOCKET
# endif
) &&
# endif
parmp->servername != NULL && (
# if defined(FEAT_AUTOSERVERNAME) || defined(FEAT_GUI)
(
# if defined(FEAT_SOCKETSERVER) && defined(MSWIN)
clientserver_method != CLIENTSERVER_METHOD_SOCKET &&
# endif
# if defined(FEAT_AUTOSERVERNAME)
1
# else
@@ -284,12 +279,10 @@ prepare_server(mparm_T *parmp)
# endif
parmp->serverName_arg != NULL))
{
# ifdef FEAT_SOCKETSERVER
if (clientserver_method == CLIENTSERVER_METHOD_SOCKET)
{
if (socket_server_init(parmp->servername) == OK)
TIME_MSG("initialize socket server");
}
socketserver_start(parmp->servername, false);
# endif
# ifdef FEAT_X11
if (clientserver_method == CLIENTSERVER_METHOD_X11)
@@ -300,10 +293,15 @@ prepare_server(mparm_T *parmp)
# endif
vim_free(parmp->servername);
}
# ifdef FEAT_X11
else
serverDelayedStartName = parmp->servername;
{
# ifdef FEAT_X11
if (clientserver_method == CLIENTSERVER_METHOD_X11)
serverDelayedStartName = parmp->servername;
else
# endif
vim_free(parmp->servername);
}
# endif
/*
@@ -343,9 +341,6 @@ cmdsrv_main(
# define ARGTYPE_SEND 3
int silent = FALSE;
int tabs = FALSE;
# ifdef FEAT_SOCKETSERVER
char_u *receiver;
# endif
# ifdef MSWIN
HWND srv;
# elif defined(FEAT_X11)
@@ -353,6 +348,9 @@ cmdsrv_main(
setup_term_clip();
# endif
# ifdef FEAT_SOCKETSERVER
channel_T *ch = NULL;
# endif
sname = serverMakeName(serverName_arg, argv[0]);
if (sname == NULL)
@@ -434,9 +432,8 @@ cmdsrv_main(
# ifdef FEAT_SOCKETSERVER
if (clientserver_method == CLIENTSERVER_METHOD_SOCKET)
ret = socket_server_send(
sname, *serverStr, NULL, &receiver,
0, -1, silent);
ret = socketserver_send(sname, *serverStr, NULL, false, -1,
silent, &ch);
# endif
# ifdef FEAT_X11
if (clientserver_method == CLIENTSERVER_METHOD_X11)
@@ -452,8 +449,10 @@ cmdsrv_main(
}
# endif
# ifdef MSWIN
// Win32 always works?
ret = serverSendToVim(sname, *serverStr, NULL, &srv, 0, 0, silent);
if (clientserver_method == CLIENTSERVER_METHOD_MSWIN)
// Win32 always works?
ret = serverSendToVim(sname, *serverStr, NULL, &srv, 0, 0,
silent);
# endif
if (ret < 0)
{
@@ -513,23 +512,23 @@ cmdsrv_main(
char_u *p = NULL;
int j;
# ifdef MSWIN
p = serverGetReply(srv, NULL, TRUE, TRUE, 0);
if (p == NULL)
break;
# else
# ifdef FEAT_SOCKETSERVER
if (clientserver_method == CLIENTSERVER_METHOD_MSWIN)
p = serverGetReply(srv, NULL, TRUE, TRUE, 0);
# endif
# ifdef FEAT_SOCKETSERVER
if (clientserver_method == CLIENTSERVER_METHOD_SOCKET
&& socket_server_read_reply(receiver, &p, -1) == FAIL)
&& (ch == NULL
|| socketserver_read_reply(sname, &p, -1, true)
== FAIL))
break;
# endif
# ifdef FEAT_X11
# endif
# ifdef FEAT_X11
if (clientserver_method == CLIENTSERVER_METHOD_X11
&& serverReadReply(xterm_dpy, srv, &p, TRUE, -1) < 0)
break;
# endif
# endif
if (p == NULL)
break;
# endif
j = atoi((char *)p);
vim_free(p);
if (j >= 0 && j < numFiles)
@@ -543,6 +542,13 @@ cmdsrv_main(
done[j] = 1;
}
}
# ifdef FEAT_SOCKETSERVER
if (ch != NULL)
{
channel_close(ch, false);
channel_clear(ch);
}
# endif
# ifdef FEAT_GUI_MSWIN
Shell_NotifyIcon(NIM_DELETE, &ni);
# endif
@@ -551,25 +557,24 @@ cmdsrv_main(
}
else if (STRICMP(argv[i], "--remote-expr") == 0)
{
int status = OK;
if (i == *argc - 1)
mainerr_arg_missing((char_u *)argv[i]);
# ifdef MSWIN
// Win32 always works?
if (serverSendToVim(sname, (char_u *)argv[i + 1],
if (clientserver_method == CLIENTSERVER_METHOD_MSWIN
&& serverSendToVim(sname, (char_u *)argv[i + 1],
&res, NULL, 1, 0, FALSE) < 0)
# else
# ifdef FEAT_SOCKETSERVER
if (clientserver_method == CLIENTSERVER_METHOD_SOCKET)
{
if (!socket_server_valid())
mch_errmsg(_("Socket server not online:"
"Send expression failed"));
else if (socket_server_send(sname, (char_u *)argv[i + 1],
&res, NULL, 1, 0, FALSE) < 0)
goto expr_fail;
}
# endif
# ifdef FEAT_X11
status = FAIL;
# endif
# ifdef FEAT_SOCKETSERVER
if (clientserver_method == CLIENTSERVER_METHOD_SOCKET
&& socketserver_send(sname, (char_u *)argv[i + 1],
&res, 1, 0, false, NULL) < 0)
status = FAIL;
# endif
# ifdef FEAT_X11
if (clientserver_method == CLIENTSERVER_METHOD_X11)
{
if (xterm_dpy == NULL)
@@ -577,15 +582,11 @@ cmdsrv_main(
else if (serverSendToVim(xterm_dpy, sname,
(char_u *)argv[i + 1], &res,
NULL, 1, 0, 1, FALSE) < 0)
goto expr_fail;
status = FAIL;
}
# endif
if (FALSE)
# endif
if (status == FAIL)
{
# if !defined(MSWIN)
expr_fail:
# endif
if (res != NULL && *res != NUL)
{
// Output error from remote
@@ -598,28 +599,22 @@ expr_fail:
else if (STRICMP(argv[i], "--serverlist") == 0)
{
# ifdef MSWIN
// Win32 always works?
res = serverGetVimNames();
# else
# ifdef FEAT_SOCKETSERVER
if (clientserver_method == CLIENTSERVER_METHOD_MSWIN)
// Win32 always works?
res = serverGetVimNames();
# endif
# ifdef FEAT_SOCKETSERVER
if (clientserver_method == CLIENTSERVER_METHOD_SOCKET)
{
int was_init = socket_server_valid();
// Don't want to add ourselves to the list. So shutdown the
// server before listing then startup back again.
socket_server_uninit();
res = socket_server_list_sockets();
if (was_init)
socket_server_init(NULL);
}
# ifdef MSWIN
res = vim_strsave((char_u *)"");
# else
res = socketserver_list();
# endif
# ifdef FEAT_X11
# endif
# ifdef FEAT_X11
if (clientserver_method == CLIENTSERVER_METHOD_X11 &&
xterm_dpy != NULL)
res = serverGetVimNames(xterm_dpy);
# endif
# endif
if (did_emsg)
mch_errmsg("\n");
@@ -648,9 +643,6 @@ expr_fail:
if (didone)
{
# ifdef FEAT_SOCKETSERVER
socket_server_uninit();
# endif
display_errors(); // display any collected messages
exit(exiterr); // Mission accomplished - get out
}
@@ -807,12 +799,12 @@ serverMakeName(char_u *arg, char *cmd)
if (arg != NULL && *arg != NUL)
{
# ifdef FEAT_SOCKETSERVER
// If we are using a socket server, we want to preserve the original
// name if it is a path, else uppercase it if its just a generic name.
// When using socketserver backend, do not change the name if path or
// channel address.
if (clientserver_method == CLIENTSERVER_METHOD_SOCKET)
{
if (arg[0] == '/' || STRNCMP(arg, "./", 2) == 0 ||
STRNCMP(arg, "../", 3) == 0)
if (STRNICMP(arg, "channel:", 8) == 0 || arg[0] == '/' ||
STRNCMP(arg, "./", 2) == 0 || STRNCMP(arg, "../", 3) == 0)
p = vim_strsave(arg);
else
p = vim_strsave_up(arg);
@@ -853,6 +845,8 @@ make_connection(void)
static int
check_connection(void)
{
if (clientserver_method != CLIENTSERVER_METHOD_X11)
return OK;
make_connection();
if (X_DISPLAY == NULL)
{
@@ -878,10 +872,8 @@ remote_common(typval_T *argvars, typval_T *rettv, int expr)
# ifdef FEAT_X11
Window w;
# endif
# ifdef FEAT_SOCKETSERVER
char_u *client = NULL;
# endif
# endif
int ret = OK;
if (check_restricted() || check_secure())
return;
@@ -899,35 +891,29 @@ remote_common(typval_T *argvars, typval_T *rettv, int expr)
return; // type error; errmsg already given
keys = tv_get_string_buf(&argvars[1], buf);
# ifdef MSWIN
if (serverSendToVim(server_name, keys, &r, &w, expr, timeout, TRUE) < 0)
# else
# ifdef FEAT_SOCKETSERVER
if (clientserver_method == CLIENTSERVER_METHOD_SOCKET)
if (socket_server_send(server_name, keys, &r, &client, expr,
timeout * 1000, TRUE) < 0)
goto fail;
# endif
# ifdef FEAT_X11
if (clientserver_method == CLIENTSERVER_METHOD_MSWIN
&& serverSendToVim(server_name, keys, &r, &w, expr,
timeout, TRUE) < 0)
ret = FAIL;
# endif
# ifdef FEAT_SOCKETSERVER
if (clientserver_method == CLIENTSERVER_METHOD_SOCKET
&& socketserver_send(server_name, keys, &r, expr,
timeout * 1000, true, NULL) < 0)
ret = FAIL;
# endif
# ifdef FEAT_X11
if (clientserver_method == CLIENTSERVER_METHOD_X11)
if (serverSendToVim(X_DISPLAY, server_name, keys, &r, &w, expr, timeout,
0, TRUE) < 0)
goto fail;
# endif
ret = FAIL;
# endif
# if !defined(MSWIN)
if (FALSE)
if (ret == FAIL)
{
fail:
# else
{
# endif
if (r != NULL)
{
emsg((char *)r); // sending worked but evaluation failed
vim_free(r);
# ifdef FEAT_SOCKETSERVER
vim_free(client);
# endif
}
else
semsg(_(e_unable_to_send_to_str), server_name);
@@ -939,40 +925,42 @@ fail:
if (argvars[2].v_type != VAR_UNKNOWN)
{
dictitem_T v;
# if defined(FEAT_SOCKETSERVER)
struct sockaddr_un addr;
char_u str[sizeof(addr.sun_path)];
# else
char_u str[30];
# if defined(MSWIN) || defined(FEAT_X11)
char_u sbuf[30];
# endif
char_u *str = NULL;
char_u *idvar;
idvar = tv_get_string_chk(&argvars[2]);
if (idvar != NULL && *idvar != NUL)
{
str[0] = NUL;
# ifdef MSWIN
sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
# else
# ifdef FEAT_X11
if (clientserver_method == CLIENTSERVER_METHOD_X11)
sprintf((char *)str, PRINTF_HEX_LONG_U, (long_u)w);
# endif
# ifdef FEAT_SOCKETSERVER
if (clientserver_method == CLIENTSERVER_METHOD_SOCKET)
vim_snprintf((char *)str, sizeof(addr.sun_path),
"%s", client);
# endif
if (clientserver_method == CLIENTSERVER_METHOD_MSWIN)
{
sprintf((char *)sbuf, PRINTF_HEX_LONG_U, (long_u)w);
str = sbuf;
}
# endif
# ifdef FEAT_X11
if (clientserver_method == CLIENTSERVER_METHOD_X11)
{
sprintf((char *)sbuf, PRINTF_HEX_LONG_U, (long_u)w);
str = sbuf;
}
# endif
# ifdef FEAT_SOCKETSERVER
if (clientserver_method == CLIENTSERVER_METHOD_SOCKET)
str = server_name;
# endif
if (str == NULL)
str = (char_u *)"";
v.di_tv.v_type = VAR_STRING;
v.di_tv.vval.v_string = vim_strsave(str);
set_var(idvar, &v.di_tv, FALSE);
vim_free(v.di_tv.vval.v_string);
}
}
# ifdef FEAT_SOCKETSERVER
vim_free(client);
# endif
}
#endif
@@ -1054,20 +1042,23 @@ f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
if (serverid == NULL)
return; // type error; errmsg already given
# ifdef MSWIN
sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
if (n == 0)
rettv->vval.v_number = -1;
else
if (clientserver_method == CLIENTSERVER_METHOD_MSWIN)
{
s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
rettv->vval.v_number = (s != NULL);
sscanf((const char *)serverid, SCANF_HEX_LONG_U, &n);
if (n == 0)
rettv->vval.v_number = -1;
else
{
s = serverGetReply((HWND)n, FALSE, FALSE, FALSE, 0);
rettv->vval.v_number = (s != NULL);
}
}
# else
# ifdef FEAT_SOCKETSERVER
# endif
# ifdef FEAT_SOCKETSERVER
if (clientserver_method == CLIENTSERVER_METHOD_SOCKET)
rettv->vval.v_number = socket_server_peek_reply(serverid, &s);
# endif
# ifdef FEAT_X11
rettv->vval.v_number = socketserver_peek_reply(serverid, &s);
# endif
# ifdef FEAT_X11
if (clientserver_method == CLIENTSERVER_METHOD_X11)
{
if (check_connection() == FAIL)
@@ -1076,7 +1067,6 @@ f_remote_peek(typval_T *argvars UNUSED, typval_T *rettv)
rettv->vval.v_number = serverPeekReply(X_DISPLAY,
serverStrToWin(serverid), &s);
}
# endif
# endif
if (argvars[1].v_type != VAR_UNKNOWN && rettv->vval.v_number > 0)
@@ -1121,24 +1111,27 @@ f_remote_read(typval_T *argvars UNUSED, typval_T *rettv)
timeout = tv_get_number(&argvars[1]);
# ifdef MSWIN
sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
if (n != 0)
r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
if (r == NULL)
emsg(_(e_unable_to_read_server_reply));
# else
# ifdef FEAT_SOCKETSERVER
if (clientserver_method == CLIENTSERVER_METHOD_MSWIN)
{
sscanf((char *)serverid, SCANF_HEX_LONG_U, &n);
if (n != 0)
r = serverGetReply((HWND)n, FALSE, TRUE, TRUE, timeout);
if (r == NULL)
emsg(_(e_unable_to_read_server_reply));
}
# endif
# ifdef FEAT_SOCKETSERVER
if (clientserver_method == CLIENTSERVER_METHOD_SOCKET &&
socket_server_read_reply(serverid, &r, timeout * 1000) == FAIL)
socketserver_read_reply(serverid, &r, timeout * 1000, false)
== FAIL)
emsg(_(e_unable_to_read_server_reply));
# endif
# ifdef FEAT_X11
# endif
# ifdef FEAT_X11
if (clientserver_method == CLIENTSERVER_METHOD_X11 &&
(check_connection() == FAIL
|| serverReadReply(X_DISPLAY, serverStrToWin(serverid),
&r, FALSE, timeout) < 0))
emsg(_(e_unable_to_read_server_reply));
# endif
# endif
}
# endif
@@ -1184,17 +1177,17 @@ f_remote_startserver(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
char_u *server = tv_get_string_chk(&argvars[0]);
# ifdef MSWIN
serverSetName(server);
# else
# ifdef FEAT_SOCKETSERVER
if (clientserver_method == CLIENTSERVER_METHOD_MSWIN)
serverSetName(server);
# endif
# ifdef FEAT_SOCKETSERVER
if (clientserver_method == CLIENTSERVER_METHOD_SOCKET)
socket_server_init(server);
# endif
# ifdef FEAT_X11
socketserver_start(server, true);
# endif
# ifdef FEAT_X11
if (clientserver_method == CLIENTSERVER_METHOD_X11 &&
check_connection() == OK)
serverRegisterName(X_DISPLAY, server);
# endif
# endif
# else
@@ -1209,6 +1202,7 @@ f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
char_u buf[NUMBUFLEN];
char_u *server;
char_u *reply;
int ret = OK;
rettv->vval.v_number = -1;
if (check_restricted() || check_secure())
@@ -1226,28 +1220,22 @@ f_server2client(typval_T *argvars UNUSED, typval_T *rettv)
# ifdef FEAT_SOCKETSERVER
if (clientserver_method == CLIENTSERVER_METHOD_SOCKET &&
socket_server_send_reply(server, reply) == FAIL)
goto fail;
socketserver_send_reply(server, reply) == FAIL)
ret = FAIL;
# endif
# ifdef FEAT_X11
if (clientserver_method == CLIENTSERVER_METHOD_X11 &&
check_connection() == FAIL)
return;
if (clientserver_method == CLIENTSERVER_METHOD_X11 &&
serverSendReply(server, reply) < 0)
ret = FAIL;
# endif
# ifdef MSWIN
if (serverSendReply(server, reply) < 0)
# endif
# if defined(FEAT_SOCKETSERVER) && !defined(FEAT_X11) && !defined(MSWIN)
if (FALSE)
if (clientserver_method == CLIENTSERVER_METHOD_MSWIN
&& serverSendReply(server, reply) < 0)
ret = FAIL;
# endif
if (ret == FAIL)
{
# ifdef FEAT_SOCKETSERVER
fail:
# endif
emsg(_(e_unable_to_send_to_client));
return;
}
@@ -1264,20 +1252,24 @@ f_serverlist(typval_T *argvars UNUSED, typval_T *rettv)
# ifdef FEAT_CLIENTSERVER
# ifdef MSWIN
r = serverGetVimNames();
# else
# ifdef FEAT_SOCKETSERVER
if (clientserver_method == CLIENTSERVER_METHOD_MSWIN)
r = serverGetVimNames();
# endif
# ifdef FEAT_SOCKETSERVER
if (clientserver_method == CLIENTSERVER_METHOD_SOCKET)
r = socket_server_list_sockets();
# ifdef MSWIN
r = vim_strsave((char_u *)"");
# else
r = socketserver_list();
# endif
# ifdef FEAT_X11
# endif
# ifdef FEAT_X11
if (clientserver_method == CLIENTSERVER_METHOD_X11)
{
make_connection();
if (X_DISPLAY != NULL)
r = serverGetVimNames(X_DISPLAY);
}
# endif
# endif
# endif
rettv->v_type = VAR_STRING;
-16
View File
@@ -2363,22 +2363,6 @@ if test "$enable_autoservername" = "yes"; then
AC_DEFINE(FEAT_AUTOSERVERNAME)
fi
AC_MSG_CHECKING(--enable-socketserver argument)
AC_ARG_ENABLE(socketserver,
[ --enable-socketserver Use sockets for clientserver communication.],
[enable_socketserver=$enableval],
AS_IF([test "x$features" = xtiny],
[enable_socketserver=no_msg
AC_MSG_RESULT([cannot use socketserver with tiny features])],
[enable_socketserver=yes]))
if test "$enable_socketserver" = "yes"; then
AC_DEFINE(WANT_SOCKETSERVER)
AC_MSG_RESULT([yes])
elif test "$enable_socketserver" = "no"; then
AC_MSG_RESULT([no])
fi
AC_MSG_CHECKING(--enable-multibyte argument)
AC_ARG_ENABLE(multibyte,
[ --enable-multibyte Include multibyte editing support.], ,
+5 -7
View File
@@ -1139,7 +1139,7 @@ EXTERN char e_cant_read_postscript_resource_file_str[]
INIT(= N_("E457: Can't read PostScript resource file \"%s\""));
#endif
// E458 unused
#if defined(UNIX) || defined(FEAT_SESSION)
#if defined(UNIX) || defined(FEAT_SESSION) || defined(FEAT_SOCKETSERVER)
EXTERN char e_cannot_go_back_to_previous_directory[]
INIT(= N_("E459: Cannot go back to previous directory"));
#endif
@@ -3777,16 +3777,14 @@ EXTERN char e_diff_anchors_with_hidden_windows[]
INIT(= N_("E1562: Diff anchors cannot be used with hidden diff windows"));
#endif
#ifdef FEAT_SOCKETSERVER
EXTERN char e_socket_path_too_big[]
INIT(= N_("E1563: Socket path is too big"));
EXTERN char e_socket_name_no_slashes[]
INIT(= N_("E1564: Socket name cannot have slashes in it without being a path"));
INIT(= N_("E1564: Socket name '%s' cannot have slashes in it without being a path"));
EXTERN char e_socket_server_not_online[]
INIT(= N_("E1565: Socket server is not online, call remote_startserver() first"));
EXTERN char e_socket_server_failed_connecting[]
INIT(= N_("E1566: Failed connecting to socket %s: %s"));
EXTERN char e_socket_server_unavailable[]
INIT(= N_("E1567: Cannot start socket server, socket path is unavailable"));
INIT(= N_("E1566: Failed connecting to socket '%s'"));
EXTERN char e_socket_server_version_mismatch[]
INIT(= N_("E1567: Socket server protocol version mismatch, check what Vim version you are using"));
#endif
EXTERN char e_osc_response_timed_out[]
INIT(= N_("E1568: OSC command response timed out: %.*s"));
+12 -10
View File
@@ -953,9 +953,16 @@
#endif
/*
* +socketserver Use UNIX domain sockets for clientserver communication
* The +channel feature requires +eval.
*/
#if defined(UNIX) && defined(WANT_SOCKETSERVER)
#if !defined(FEAT_EVAL) && defined(FEAT_JOB_CHANNEL)
# undef FEAT_JOB_CHANNEL
#endif
/*
* +socketserver Use channels for clientserver communication
*/
#if (defined(UNIX) || defined(MSWIN)) && defined(FEAT_JOB_CHANNEL)
# define FEAT_SOCKETSERVER
#endif
@@ -966,6 +973,9 @@
#if (defined(MSWIN) || defined(FEAT_XCLIPBOARD) || defined(FEAT_SOCKETSERVER)) \
&& defined(FEAT_EVAL)
# define FEAT_CLIENTSERVER
# if defined(FEAT_SOCKETSERVER) && (defined(FEAT_XCLIPBOARD) || defined(MSWIN))
# define FEAT_CLIENTSERVER_BACKENDS
# endif
#endif
/*
@@ -1053,14 +1063,6 @@
* +tgetent
*/
/*
* The +channel feature requires +eval.
*/
#if !defined(FEAT_EVAL) && defined(FEAT_JOB_CHANNEL)
# undef FEAT_JOB_CHANNEL
#endif
/*
* The Netbeans feature requires +eval and +job_channel
*/
+3
View File
@@ -208,6 +208,9 @@ garbage_collect(int testing)
#ifdef FEAT_NETBEANS_INTG
abort = abort || set_ref_in_nb_channel(copyID);
#endif
#ifdef FEAT_SOCKETSERVER
abort = abort || set_ref_in_socketserver_channel(copyID);
#endif
#ifdef FEAT_TIMERS
abort = abort || set_ref_in_timer(copyID);
+3
View File
@@ -2650,6 +2650,9 @@ parse_queued_messages(void)
// Process the queued netbeans messages.
netbeans_parse_messages();
# endif
# ifdef FEAT_SOCKETSERVER
socketserver_parse_messages();
# endif
# ifdef FEAT_JOB_CHANNEL
// Write any buffer lines still to be written.
channel_write_any_lines();
+11 -8
View File
@@ -2122,25 +2122,28 @@ EXTERN int wayland_no_connect INIT(= FALSE);
#endif
#if defined(FEAT_CLIENTSERVER) && !defined(MSWIN)
#if defined(FEAT_CLIENTSERVER)
// Backend for clientserver functionality
typedef enum {
CLIENTSERVER_METHOD_NONE,
# ifdef FEAT_X11
CLIENTSERVER_METHOD_X11,
# endif
# ifdef MSWIN
CLIENTSERVER_METHOD_MSWIN,
# endif
# ifdef FEAT_SOCKETSERVER
CLIENTSERVER_METHOD_SOCKET
# endif
} clientserver_method_T;
// Default to X11 if compiled with support for it, else use socket server.
# if defined(FEAT_X11) && defined(FEAT_SOCKETSERVER)
EXTERN clientserver_method_T clientserver_method
# else
// Since we aren't going to be changing clientserver_method, make it constant to
// allow compiler optimizations.
EXTERN const clientserver_method_T clientserver_method
# endif
# ifdef FEAT_X11
INIT(= CLIENTSERVER_METHOD_X11);
# elif defined(MSWIN)
INIT(= CLIENTSERVER_METHOD_MSWIN);
# elif defined(FEAT_SOCKETSERVER)
INIT(= CLIENTSERVER_METHOD_SOCKET);
# else
-6
View File
@@ -158,12 +158,6 @@ gui_start(char_u *arg UNUSED)
choose_clipmethod();
#endif
#if defined(FEAT_SOCKETSERVER) && defined(FEAT_GUI_GTK)
// Install socket server listening socket if we are running it
if (socket_server_valid())
gui_gtk_init_socket_server();
#endif
#ifdef FEAT_GUI_MSWIN
// Enable fullscreen mode
if (vim_strchr(p_go, GO_FULLSCREEN) != NULL)
-55
View File
@@ -80,13 +80,6 @@ extern void bonobo_dock_item_set_behavior(BonoboDockItem *dock_item, BonoboDockI
# include <X11/Sunkeysym.h>
#endif
#ifdef FEAT_SOCKETSERVER
# include <glib-unix.h>
// Used to track the source for the listening socket
static uint socket_server_source_id = 0;
#endif
/*
* Easy-to-use macro for multihead support.
*/
@@ -2690,54 +2683,6 @@ global_event_filter(GdkXEvent *xev,
}
#endif // !USE_GNOME_SESSION
#if defined(FEAT_SOCKETSERVER)
/*
* Callback for new events from the socket server listening socket
*/
static int
socket_server_poll_in(int fd UNUSED, GIOCondition cond, void *user_data UNUSED)
{
if (cond & G_IO_IN)
socket_server_accept_client();
else if (cond & (G_IO_ERR | G_IO_HUP))
{
socket_server_uninit();
return FALSE;
}
return TRUE;
}
/*
* Initialize socket server for use in the GUI (does not actually initialize the
* socket server, only attaches a source).
*/
void
gui_gtk_init_socket_server(void)
{
if (socket_server_source_id > 0)
return;
// Register source for file descriptor to global default context
socket_server_source_id = g_unix_fd_add(socket_server_get_fd(),
G_IO_IN | G_IO_ERR | G_IO_HUP, socket_server_poll_in, NULL);
}
/*
* Remove the source for the socket server listening socket.
*/
void
gui_gtk_uninit_socket_server(void)
{
if (socket_server_source_id > 0)
{
g_source_remove(socket_server_source_id);
socket_server_source_id = 0;
}
}
#endif
static GdkPixbuf *
pixbuf_new_from_png_data(const unsigned char *data, unsigned int len)
{
+2
View File
@@ -51,6 +51,8 @@ json_encode(typval_T *val, int options)
// Store bytes in the growarray.
ga_init2(&ga, 1, 4000);
json_encode_gap(&ga, val, options);
if (options & JSON_NL)
ga_append(&ga, NL);
ga_append(&ga, NUL);
return ga.ga_data;
}
+14 -5
View File
@@ -1844,6 +1844,9 @@ getout(int exitval)
#ifdef FEAT_NETBEANS_INTG
netbeans_end();
#endif
#ifdef FEAT_SOCKETSERVER
socketserver_stop();
#endif
#ifdef FEAT_CSCOPE
cs_end();
#endif
@@ -1910,7 +1913,7 @@ early_arg_scan(mparm_T *parmp UNUSED)
gui.dofork = false;
# endif
}
# if defined(FEAT_X11) && defined(FEAT_SOCKETSERVER)
# ifdef FEAT_CLIENTSERVER_BACKENDS
else if (STRNICMP(argv[i], "--clientserver", 14) == 0)
{
char_u *arg;
@@ -1920,8 +1923,14 @@ early_arg_scan(mparm_T *parmp UNUSED)
if (STRICMP(arg, "socket") == 0)
clientserver_method = CLIENTSERVER_METHOD_SOCKET;
# ifdef FEAT_X11
else if (STRICMP(arg, "x11") == 0)
clientserver_method = CLIENTSERVER_METHOD_X11;
# endif
# ifdef MSWIN
else if (STRICMP(arg, "mswin") == 0)
clientserver_method = CLIENTSERVER_METHOD_MSWIN;
# endif
else
mainerr(ME_UNKNOWN_OPTION, arg);
}
@@ -2247,9 +2256,9 @@ command_line_scan(mparm_T *parmp)
; // already processed -- no arg
else if (STRNICMP(argv[0] + argv_idx, "servername", 10) == 0
|| STRNICMP(argv[0] + argv_idx, "serversend", 10) == 0
# if defined(FEAT_X11) && defined(FEAT_SOCKETSERVER)
// Don't put this under FEAT_CLIENTSERVER_BACKENDS, just
// let it be ignored. Makes tests less complicated
|| STRNICMP(argv[0] + argv_idx, "clientserver", 12) == 0
# endif
)
{
// already processed -- snatch the following arg
@@ -3747,8 +3756,8 @@ usage(void)
main_msg(_("-Y\t\t\tDo not connect to Wayland compositor"));
# endif
# ifdef FEAT_CLIENTSERVER
# if defined(FEAT_X11) && defined(FEAT_SOCKETSERVER)
main_msg(_("--clientserver <socket|x11> Backend for clientserver communication"));
# ifdef FEAT_CLIENTSERVER_BACKENDS
main_msg(_("--clientserver <socket|x11|mswin> Backend for clientserver communication"));
# endif
main_msg(_("--remote <files>\tEdit <files> in a Vim server if possible"));
main_msg(_("--remote-silent <files> Same, don't complain if there is no server"));
+1 -1734
View File
File diff suppressed because it is too large Load Diff
+12 -14
View File
@@ -254,9 +254,6 @@ msgstr ""
msgid "%d of %d edited"
msgstr ""
msgid "Socket server not online:Send expression failed"
msgstr ""
msgid "No display: Send expression failed.\n"
msgstr ""
@@ -1722,7 +1719,8 @@ msgstr ""
msgid "-Y\t\t\tDo not connect to Wayland compositor"
msgstr ""
msgid "--clientserver <socket|x11> Backend for clientserver communication"
msgid ""
"--clientserver <socket|x11|mswin> Backend for clientserver communication"
msgstr ""
msgid "--remote <files>\tEdit <files> in a Vim server if possible"
@@ -2531,10 +2529,6 @@ msgstr ""
msgid "XSMP SmcOpenConnection failed: %s"
msgstr ""
#, c-format
msgid "Failed creating socket directory: %s"
msgstr ""
msgid "At line"
msgstr ""
@@ -2806,6 +2800,10 @@ msgstr ""
msgid " (not supported)"
msgstr ""
#, c-format
msgid "Failed creating socket directory: %s"
msgstr ""
#, c-format
msgid "Warning: Cannot find word list \"%s_%s.spl\" or \"%s_ascii.spl\""
msgstr ""
@@ -8834,20 +8832,20 @@ msgstr ""
msgid "E1562: Diff anchors cannot be used with hidden diff windows"
msgstr ""
msgid "E1563: Socket path is too big"
msgstr ""
msgid "E1564: Socket name cannot have slashes in it without being a path"
#, c-format
msgid "E1564: Socket name '%s' cannot have slashes in it without being a path"
msgstr ""
msgid "E1565: Socket server is not online, call remote_startserver() first"
msgstr ""
#, c-format
msgid "E1566: Failed connecting to socket %s: %s"
msgid "E1566: Failed connecting to socket '%s'"
msgstr ""
msgid "E1567: Cannot start socket server, socket path is unavailable"
msgid ""
"E1567: Socket server protocol version mismatch, check what Vim version you "
"are using"
msgstr ""
#, c-format
+3
View File
@@ -277,6 +277,9 @@ void mbyte_im_set_active(int active_arg);
# include "job.pro"
# include "channel.pro"
# endif
# ifdef FEAT_SOCKETSERVER
# include "socketserver.pro"
# endif
# ifdef FEAT_EVAL
// Not generated automatically so that we can add an extra attribute.
+9 -1
View File
@@ -7,15 +7,18 @@ int channel_unref(channel_T *channel);
int free_unused_channels_contents(int copyID, int mask);
void free_unused_channels(int copyID, int mask);
void channel_gui_register_all(void);
channel_T *channel_open_unix(const char *path, void (*nb_close_cb)(void));
channel_T *channel_open(const char *hostname, int port, int waittime, void (*nb_close_cb)(void));
int channel_parse_socketserver_address(char_u *address, int *port, char_u **unix_path, bool quiet);
channel_T *channel_listen_func(typval_T *argvars);
channel_T *channel_listen(int port_in, void (*nb_close_cb)(void));
channel_T *channel_listen_unix(char *path, void (*nb_close_cb)(void));
channel_T *channel_listen_unix(char *path, void (*nb_close_cb)(void), bool replace);
void ch_close_part(channel_T *channel, ch_part_T part);
void channel_set_pipes(channel_T *channel, sock_T in, sock_T out, sock_T err);
void channel_set_job(channel_T *channel, job_T *job, jobopt_T *options);
void channel_write_in(channel_T *channel);
void channel_buffer_free(buf_T *buf);
void channel_write_input(channel_T *channel);
void channel_write_any_lines(void);
void channel_write_new_lines(buf_T *buf);
readq_T *channel_peek(channel_T *channel, ch_part_T part);
@@ -23,11 +26,15 @@ char_u *channel_first_nl(readq_T *node);
char_u *channel_get(channel_T *channel, ch_part_T part, int *outlen);
void channel_consume(channel_T *channel, ch_part_T part, int len);
int channel_collapse(channel_T *channel, ch_part_T part, int want_nl);
int channel_fill(js_read_T *reader);
int channel_parse_json(channel_T *channel, ch_part_T part, bool socketserver);
void remove_json_node(jsonq_T *head, jsonq_T *node);
int channel_can_write_to(channel_T *channel);
int channel_is_open(channel_T *channel);
void channel_close(channel_T *channel, int invoke_close_cb);
void channel_clear(channel_T *channel);
void channel_free_all(void);
void channel_check(channel_T *channel, ch_part_T part);
int channel_in_blocking_wait(void);
channel_T *get_channel_arg(typval_T *tv, int check_open, int reading, ch_part_T part);
void channel_handle_events(int only_keep_open);
@@ -59,4 +66,5 @@ void f_ch_sendraw(typval_T *argvars, typval_T *rettv);
void f_ch_setoptions(typval_T *argvars, typval_T *rettv);
void f_ch_status(typval_T *argvars, typval_T *rettv);
char_u *channel_to_string_buf(typval_T *varp, char_u *buf);
channel_T *channel_find(int ch_id);
/* vim: set ft=c : */
-2
View File
@@ -8,8 +8,6 @@ void gui_mch_stop_blink(int may_call_gui_update_cursor);
void gui_mch_start_blink(void);
int gui_mch_early_init_check(int give_message);
int gui_mch_init_check(void);
void gui_gtk_init_socket_server(void);
void gui_gtk_uninit_socket_server(void);
void gui_mch_set_dark_theme(int dark);
void gui_mch_show_tabline(int showit);
int gui_mch_showing_tabline(void);
-11
View File
@@ -96,15 +96,4 @@ void stop_timeout(void);
volatile sig_atomic_t *start_timeout(long msec);
void delete_timer(void);
int mch_create_anon_file(void);
int socket_server_init(char_u *name);
void socket_server_uninit(void);
char_u *socket_server_list_sockets(void);
int socket_server_accept_client(void);
int socket_server_valid(void);
int socket_server_send(char_u *name, char_u *str, char_u **result, char_u **receiver, int is_expr, int timeout, int silent);
int socket_server_read_reply(char_u *client, char_u **str, int timeout);
int socket_server_peek_reply(char_u *sender, char_u **str);
int socket_server_send_reply(char_u *client, char_u *str);
int socket_server_get_fd(void);
int socket_server_waiting_accept(void);
/* vim: set ft=c : */
+11
View File
@@ -0,0 +1,11 @@
/* socketserver.c */
int socketserver_start(char_u *name, bool quiet);
void socketserver_stop(void);
char_u *socketserver_list(void);
int set_ref_in_socketserver_channel(int copyID);
void socketserver_parse_messages(void);
int socketserver_send(char_u *name, char_u *str, char_u **result, bool is_expr, int timeout, bool silent, channel_T **ch);
int socketserver_send_reply(char_u *client, char_u *str);
int socketserver_read_reply(char_u *client, char_u **str, int timeout, bool remotewait);
int socketserver_peek_reply(char_u *sender, char_u **str);
/* vim: set ft=c : */
+1404
View File
File diff suppressed because it is too large Load Diff
+7
View File
@@ -2795,6 +2795,13 @@ struct channel_S {
void (*ch_nb_close_cb)(void);
// callback for Netbeans when channel is
// closed
#ifdef FEAT_SOCKETSERVER
bool ch_socketserver; // If channel is used by socketserver
void (*ch_ss_close_cb)(channel_T *);
void (*ch_ss_accept_cb)(channel_T *);
channel_T *ch_ss_next;
channel_T *ch_ss_prev;
#endif
#ifdef MSWIN
int ch_named_pipe; // using named pipe instead of pty
+8
View File
@@ -0,0 +1,8 @@
|~+0#4040ff13#ffffff0| @73
|~| @73
|~| @73
|E+0#ffffff16#e000002|1|5|6|7|:| |S|o|c|k|e|t| |s|e|r|v|e|r| |p|r|o|t|o|c|o|l| |v|e|r|s|i|o|n| |m|i|s|m|a|t|c|h|,| |c|h|e|c|k| |w|h|a|t| |V|i|m| |v|e|r|s|i|o|n| |y|o|u|
|a|r|e| |u|s|i|n|g| +0#0000000#ffffff0@65
|E+0#ffffff16#e000002|2|4|1|:| |U|n|a|b|l|e| |t|o| |s|e|n|d| |t|o| |c|h|a|n@1|e|l|:|2|0@2| +0#0000000#ffffff0@38
@75
|P+0#00e0003&|r|e|s@1| |E|N|T|E|R| |o|r| |t|y|p|e| |c|o|m@1|a|n|d| |t|o| |c|o|n|t|i|n|u|e> +0#0000000&@35
+222 -85
View File
@@ -1,5 +1,6 @@
" Tests for the +clientserver feature.
source util/screendump.vim
CheckFeature job
if !has('clientserver')
@@ -10,10 +11,6 @@ CheckFeature clientserver
source util/shared.vim
" Unlike X11, we need the socket server running if we want to send commands to
" a server via sockets.
RunSocketServer
func Check_X11_Connection()
if has('x11')
CheckX11
@@ -192,9 +189,9 @@ func Test_client_server()
" When using socket server, server id is not a number, but the path to the
" socket.
if has('socketserver') && !has('X11')
call assert_fails("let x = remote_read('vim/10')", ['E573:.*vim/10'])
call assert_fails("call server2client('a/b/c', 'xyz')", ['E573:.*a/b/c'])
if (has('socketserver') && !has('X11') && !has('win32')) || index(v:argv, "socket") != -1
call assert_fails("let x = remote_read('vim/10')", ['E1564:'])
call assert_fails("call server2client('x/b/c', 'xyz')", ['E1564:'])
else
call assert_fails("let x = remote_read('vim10')",
\ has('unix') ? ['E573:.*vim10'] : 'E277:')
@@ -246,89 +243,65 @@ func Test_client_server_stopinsert()
endtry
endfunc
" Test if socket server and X11 backends can be chosen and work properly.
func Test_client_server_x11_and_socket_server()
CheckNotMSWindows
CheckFeature socketserver
CheckFeature x11
" Test if socket server, X11, and mswin backends can be chosen and work properly.
func Test_client_server_multiple_backends()
CheckFeature socketserver
let g:test_is_flaky = 1
let cmd = GetVimCommand()
let g:test_is_flaky = 1
let cmd = GetVimCommand()
if cmd == ''
throw 'GetVimCommand() failed'
endif
call Check_X11_Connection()
let types = ['socket', 'x11']
for type in types
let name = 'VIMTEST_' .. toupper(type)
let actual_cmd = cmd .. ' --clientserver ' .. type
let actual_cmd .= ' --servername ' .. name
let job = job_start(actual_cmd, {'stoponexit': 'kill', 'out_io': 'null'})
call WaitForAssert({-> assert_equal("run", job_status(job))})
call WaitForAssert({-> assert_match(name, system(cmd .. ' --clientserver ' .. type .. ' --serverlist'))})
call assert_match(name, system(actual_cmd .. ' --remote-expr "v:servername"'))
call system(actual_cmd .. " --remote-expr 'execute(\"qa!\")'")
try
call WaitForAssert({-> assert_equal("dead", job_status(job))})
finally
if job_status(job) != 'dead'
call assert_report('Server did not exit')
call job_stop(job, 'kill')
endif
endtry
endfor
endfunc
" Test if socket server works in the GUI
func Test_client_server_socket_server_gui()
CheckNotMSWindows
CheckFeature socketserver
CheckFeature gui_gtk
let g:test_is_flaky = 1
let cmd = GetVimCommand()
if cmd == ''
throw 'GetVimCommand() failed'
endif
call Check_X11_Connection()
let name = 'VIMTESTSOCKET'
let cmd .= ' --clientserver socket'
let cmd .= ' --servername ' .. name
let job = job_start(cmd, {'stoponexit': 'kill', 'out_io': 'null'})
call WaitForAssert({-> assert_equal("run", job_status(job))})
call WaitForAssert({-> assert_match(name, system(cmd .. ' --serverlist'))})
call system(cmd .. " --remote-expr 'execute(\"gui\")'")
call assert_match('1', system(cmd .. " --remote-expr 'has(\"gui_running\")'"))
call assert_match(name, system(cmd .. ' --remote-expr "v:servername"'))
call system(cmd .. " --remote-expr 'execute(\"qa!\")'")
try
call WaitForAssert({-> assert_equal("dead", job_status(job))})
finally
if job_status(job) != 'dead'
call assert_report('Server did not exit')
call job_stop(job, 'kill')
if cmd == ''
throw 'GetVimCommand() failed'
endif
endtry
endfunc
call Check_X11_Connection()
let types = [
\ ['socket', "channel:2000"],
\ ['x11', "TEST"],
\ ['mswin', "TEST"],
\ ]
for [type, expected] in types
if (type == 'x11' && (!has('x11') || !empty($WAYLAND_DISPLAY) || empty($DISPLAY))
\ || (type == 'mswin' && !has('win32')))
continue
endif
if has('win32') && has('gui_running')
" Windows gVim --remote-expr shows a dialog window, which blocks tests
" from running. Using --gui-dialog-file does not seem to work either.
continue
endif
let actual_cmd = cmd .. ' --clientserver ' .. type
let actual_cmd ..= ' --servername ' .. expected
let job = job_start(actual_cmd, {'stoponexit': 'kill', 'out_io': 'null'})
call WaitForAssert({-> assert_equal("run", job_status(job))})
call assert_match(expected, system(actual_cmd .. ' --remote-expr "v:servername"'))
" On Windows using --remote-expr causes E282, possibly due to some shell
" escaping quirk? When gtk gui is running, using system() seems to cause a
" deadlock when using the x11 backend only... don't use it for now...
if has('win32') || has('gui_running')
call job_stop(job, 'kill')
else
call system(actual_cmd .. " --remote-expr 'execute(\"qa!\")'")
endif
try
call WaitForAssert({-> assert_equal("dead", job_status(job))})
finally
if job_status(job) != 'dead'
call assert_report('Server did not exit')
call job_stop(job, 'kill')
endif
endtry
endfor
endfunc
" Test if custom paths work for socketserver
func Test_client_socket_server_custom_path()
CheckNotMSWindows
func Test_client_server_socketserver_custom_path()
CheckFeature socketserver
CheckNotFeature x11
CheckNotMSWindows
let g:test_is_flaky = 1
let cmd = GetVimCommand()
@@ -342,7 +315,7 @@ func Test_client_socket_server_custom_path()
let paths = ['./' .. name, '../testdir/' .. name, getcwd(-1) .. '/' .. name]
for path in paths
let actual = cmd .. ' --servername ' .. path
let actual = cmd .. ' --clientserver socket --servername ' .. path
let job = job_start(actual, {'stoponexit': 'kill', 'out_io': 'null'})
@@ -361,6 +334,170 @@ func Test_client_socket_server_custom_path()
endfor
endfunc
" Test if "channel:" prefix works correctly to use channel address for
" socketserver.
func Test_client_server_socketserver_address()
CheckFeature socketserver
let g:test_is_flaky = 1
let cmd = GetVimCommand()
if cmd == ''
throw 'GetVimCommand() failed'
endif
let actual = cmd .. ' --clientserver socket --servername channel:2000'
let job = job_start(actual, {'stoponexit': 'kill', 'out_io': 'null'})
call WaitForAssert({-> assert_equal("run", job_status(job))})
if !has('win32') || !has('gui_running')
" Does not work with gVim on Windows because it shows an OK dialog box which
" blocks tests from running
call assert_match('channel:2000', system(actual .. ' --remote-expr "v:servername"'))
endif
if has('win32')
call job_stop(job, 'kill')
else
call system(actual .. " --remote-expr 'execute(\"qa!\")'")
endif
try
call WaitForAssert({-> assert_equal("dead", job_status(job))})
finally
if job_status(job) != 'dead'
call assert_report('Server did not exit')
call job_stop(job, 'kill')
endif
endtry
endfunc
" Test if --remote-wait works properly with multiple files
func Test_client_server_multiple_remote_wait()
CheckRunVimInTerminal
call Check_X11_Connection()
let buf = RunVimInTerminal('--servername TEST', {'rows': 8})
call TermWait(buf)
call writefile(["1"], 'XRemoteOne', 'D')
call writefile(["2"], 'XRemoteTwo', 'D')
let cmd = GetVimCommand()
if cmd == ''
throw 'GetVimCommand() failed'
endif
let actual = cmd .. ' -n --servername TEST --remote-wait ./XRemoteOne ./XRemoteTwo'
let job = job_start(actual, {'stoponexit': 'kill', 'out_io': 'null'})
sleep 500m " Wait for server to receive request
call assert_equal("run", job_status(job))
call term_sendkeys(buf, "\<Esc>:next\<CR>")
call TermWait(buf)
call assert_equal("run", job_status(job))
call term_sendkeys(buf, "\<Esc>:q!\<CR>") " Don't use qa! because we only want to quit one file
call WaitForAssert({-> assert_equal("dead", job_status(job))})
endfunc
" Check if socket is removed even if Vim changes directory
func Test_client_server_socketserver_chdir()
CheckFeature socketserver
CheckRunVimInTerminal
CheckNotMSWindows
let buf = RunVimInTerminal('--clientserver socket --servername ./TEST',
\ {'rows': 8})
call TermWait(buf)
call term_sendkeys(buf, "\<Esc>:cd ../\<CR>")
call StopVimInTerminal(buf)
call assert_equal("", glob("./TEST"))
endfunc
func DummyServerCallback(ch, addr)
let msg = json_encode(#{type: "ver"}) .. "\n"
call ch_sendraw(a:ch, msg)
endfunc
" Test if commands with different version are ignored and handled properly.
func Test_client_server_socketserver_version_mismatch()
CheckFeature socketserver
CheckRunVimInTerminal
CheckScreendump
let cmd = GetVimCommand()
if cmd == ''
throw 'GetVimCommand() failed'
endif
let buf = RunVimInTerminal('--clientserver socket --servername
\ channel:2000', {'rows': 8})
call TermWait(buf)
let ch = ch_open('localhost:2000', #{mode: 'nl'})
let msg = json_encode(#{
\ type: "expr",
\ str: "v:servername",
\ version: 999999999
\ }) .. "\n"
call ch_sendraw(ch, msg)
let resp = ch_readraw(ch)
call assert_equal(#{type: "ver"}, json_decode(resp))
call StopVimInTerminal(buf)
let ch = ch_listen("2000", #{
\ mode: 'nl',
\ callback: function('DummyServerCallback')
\ })
let buf = RunVimInTerminal('--clientserver socket --servername channel:3000', {'rows': 8})
call TermWait(buf)
call term_sendkeys(buf, "\<Esc>:echo remote_expr('channel:2000', 'v:servername', '', 1)\<CR>")
call TermWait(buf)
call VerifyScreenDump(buf, 'Test_clientserver_1', #{wait: 3000})
call StopVimInTerminal(buf)
endfunc
" Test if invalid messages do not crash Vim socketserver.
func Test_clientserver_socketserver_invalid_msg()
CheckFeature socketserver
CheckRunVimInTerminal
let cmd = GetVimCommand()
if cmd == ''
throw 'GetVimCommand() failed'
endif
let buf = RunVimInTerminal('--clientserver socket --servername
\ channel:3000', {'rows': 8})
call TermWait(buf)
let ch = ch_open('localhost:3000', #{mode: 'nl'})
call ch_sendraw(ch, "wjdaljdsjalsj\n")
call ch_sendraw(ch, "{\"type\": \"unknown\"}\n")
call assert_match("channel:3000", system(cmd .. " --clientserver socket --servername channel:3000 --remote-expr 'v:servername'"))
call assert_equal("running", term_getstatus(buf))
call StopVimInTerminal(buf)
endfunc
" Uncomment this line to get a debugging log
" call ch_logfile('channellog', 'w')
+8 -12
View File
@@ -16,18 +16,6 @@ func Verify_remote_feature_works()
let buf = RunVimInTerminal('--servername XVIMTEST', {'rows': 8})
call TermWait(buf)
" For some reason when the socket server is being used, the terminal Vim never
" receives the `:w! XVimRemoteTest.txt` command from term_sendkeys.
if has('socketserver') && !has('X11')
if match(serverlist(), "XVIMTEST") == -1
call StopVimInTerminal(buf)
throw s:skip
endif
let s:remote = 1
return
endif
let cmd = GetVimCommandCleanTerm() .. '--serverlist'
call term_sendkeys(buf, ":r! " .. cmd .. "\<CR>")
call TermWait(buf)
@@ -71,6 +59,14 @@ func Test_remote_servername()
" open XTEST.txt, if wildignore setting is not ignored, the server
" will continue with the Xdummy.log file
let buf2 = RunVimInTerminal('--servername XVIMTEST --remote-silent XTEST.txt', {'rows': 5, 'wait_for_ruler': 0})
" It may take a while for the command to be sent to XVIMTEST and be executed.
" Do a blocking --remote-expr so that is assured the command was executed.
botright new
let buf3 = RunVimInTerminal('--servername XVIMTEST --remote-expr "v:servername"', {'rows': 5, 'wait_for_ruler': 0})
call WaitForAssert({-> assert_equal("finished", term_getstatus(buf3))})
exe buf3 .. 'bw!'
" job should be no-longer running, so we can just close it
exe buf2 .. 'bw!'
call term_sendkeys(buf, ":sil :3,$d\<CR>")
-1
View File
@@ -402,7 +402,6 @@ func Test_CmdCompletion()
exe 'delcommand ' .. cmd
endfor
delcommand MissingFeature
delcommand RunSocketServer
command! DoCmd1 :
command! DoCmd2 :
+21 -10
View File
@@ -1,7 +1,6 @@
" Test using builtin functions in the Vim9 script language.
source util/screendump.vim
source util/socketserver.vim
import './util/vim9.vim' as v9
" Test for passing too many or too few arguments to builtin functions
@@ -3525,11 +3524,12 @@ enddef
def Test_remote_expr()
CheckFeature clientserver
TrySocketServer
CheckNotMSWindows
if !g:socketserver_only
if has("x11")
CheckEnv DISPLAY
endif
v9.CheckSourceDefAndScriptFailure(['remote_expr(1, "b")'], ['E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1'])
v9.CheckSourceDefAndScriptFailure(['remote_expr("a", 2)'], ['E1013: Argument 2: type mismatch, expected string but got number', 'E1174: String required for argument 2'])
v9.CheckSourceDefAndScriptFailure(['remote_expr("a", "b", 3)'], ['E1013: Argument 3: type mismatch, expected string but got number', 'E1174: String required for argument 3'])
@@ -3551,10 +3551,12 @@ enddef
def Test_remote_peek()
CheckFeature clientserver
TrySocketServer
if !g:socketserver_only
CheckNotMSWindows
if has("x11")
CheckEnv DISPLAY
endif
v9.CheckSourceDefAndScriptFailure(['remote_peek(0z10)'], ['E1013: Argument 1: type mismatch, expected string but got blob', 'E1174: String required for argument 1'])
v9.CheckSourceDefAndScriptFailure(['remote_peek("a5b6c7", [1])'], ['E1013: Argument 2: type mismatch, expected string but got list<number>', 'E1174: String required for argument 2'])
v9.CheckSourceDefExecAndScriptFailure(['remote_peek("")'], 'E573: Invalid server id used')
@@ -3562,7 +3564,12 @@ enddef
def Test_remote_read()
CheckFeature clientserver
CheckEnv DISPLAY
CheckNotMSWindows
if has("x11")
CheckEnv DISPLAY
endif
v9.CheckSourceDefAndScriptFailure(['remote_read(1)'], ['E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1'])
v9.CheckSourceDefAndScriptFailure(['remote_read("a", "x")'], ['E1013: Argument 2: type mismatch, expected number but got string', 'E1210: Number required for argument 2'])
v9.CheckSourceDefExecAndScriptFailure(['remote_read("")'], 'E573: Invalid server id used')
@@ -3570,10 +3577,12 @@ enddef
def Test_remote_send()
CheckFeature clientserver
TrySocketServer
if !g:socketserver_only
CheckNotMSWindows
if has("x11")
CheckEnv DISPLAY
endif
v9.CheckSourceDefAndScriptFailure(['remote_send(1, "b")'], ['E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1'])
v9.CheckSourceDefAndScriptFailure(['remote_send("a", 2)'], ['E1013: Argument 2: type mismatch, expected string but got number', 'E1174: String required for argument 2'])
v9.CheckSourceDefAndScriptFailure(['remote_send("a", "b", 3)'], ['E1013: Argument 3: type mismatch, expected string but got number', 'E1174: String required for argument 3'])
@@ -3582,10 +3591,12 @@ enddef
def Test_remote_startserver()
CheckFeature clientserver
TrySocketServer
if !g:socketserver_only
CheckNotMSWindows
if has("x11")
CheckEnv DISPLAY
endif
v9.CheckSourceDefAndScriptFailure(['remote_startserver({})'], ['E1013: Argument 1: type mismatch, expected string but got dict<any>', 'E1174: String required for argument 1'])
enddef
-11
View File
@@ -348,17 +348,6 @@ func CheckGithubActions()
endif
endfunc
command RunSocketServer call RunSocketServer()
func RunSocketServer()
if has("socketserver") && v:servername == ""
try
call remote_startserver('VIMSOCKETSERVERTEST')
catch " not possible to start a remote server
throw 'Skipped: Cannot start remote server'
endtry
endif
endfunc
let &cpo = s:cpo_save
unlet s:cpo_save
" vim: shiftwidth=2 sts=2 expandtab
-17
View File
@@ -1,17 +0,0 @@
" Check if only the socketserver backend is available for clientserver (only on
" Unix), and set g:socketserver_only to v:true along with starting the
" socketserver.
command TrySocketServer call TrySocketServer()
func TrySocketServer()
if has("socketserver") && !has("x11")
let g:socketserver_only = v:true
if v:servername == ""
call remote_startserver('VIMSOCKETSERVERTEST')
endif
else
let g:socketserver_only = v:false
endif
endfunc
" vim: shiftwidth=2 sts=2 expandtab
+4 -14
View File
@@ -406,20 +406,10 @@ inchar_loop(
# endif
if ((resize_func != NULL && resize_func(TRUE))
# if defined(FEAT_CLIENTSERVER) && defined(UNIX)
|| (
# ifdef FEAT_X11
(clientserver_method == CLIENTSERVER_METHOD_X11 &&
server_waiting())
# endif
# if defined(FEAT_X11) && defined(FEAT_SOCKETSERVER)
||
# endif
# ifdef FEAT_SOCKETSERVER
(clientserver_method == CLIENTSERVER_METHOD_SOCKET &&
socket_server_waiting_accept())
# endif
)
# if defined(FEAT_CLIENTSERVER) && defined(FEAT_X11)
||
(clientserver_method == CLIENTSERVER_METHOD_X11 &&
server_waiting())
# endif
# ifdef MESSAGE_QUEUE
|| interrupted
+2
View File
@@ -729,6 +729,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
512,
/**/
511,
/**/