aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustin M. Keyes <justinkz@gmail.com>2022-05-03 15:08:35 +0200
committerGitHub <noreply@github.com>2022-05-03 06:08:35 -0700
commit4fb48c5654d9ffbffbdcdd80d0498b1ea3c8e68b (patch)
tree8a1222f6ed9a170ca2d151afcd911dfd01affdaf
parentb5c15ba7e5266bdd742a835d82525d4625980d4d (diff)
downloadrneovim-4fb48c5654d9ffbffbdcdd80d0498b1ea3c8e68b.tar.gz
rneovim-4fb48c5654d9ffbffbdcdd80d0498b1ea3c8e68b.tar.bz2
rneovim-4fb48c5654d9ffbffbdcdd80d0498b1ea3c8e68b.zip
feat(server): set $NVIM, unset $NVIM_LISTEN_ADDRESS #11009
PROBLEM ------------------------------------------------------------------------ $NVIM_LISTEN_ADDRESS has conflicting purposes as both a parameter ("the current process should listen on this address") and a descriptor ("the current process is a child of this address"). This contradiction means the presence of NVIM_LISTEN_ADDRESS is ambiguous, so child Nvim always tries to listen on its _parent's_ socket. This is the cause of lots of "Failed to start server" spam in our test/CI logs: WARN 2022-04-30… server_start:154: Failed to start server: address already in use: \\.\pipe\nvim-4480-0 WARN 2022-04-30… server_start:154: Failed to start server: address already in use: \\.\pipe\nvim-2168-0 SOLUTION ------------------------------------------------------------------------ 1. Set $NVIM to the parent v:servername, *only* in child processes. - Now the correct way to detect a "parent" Nvim is to check for $NVIM. 2. Do NOT set $NVIM_LISTEN_ADDRESS in child processes. 3. On startup if $NVIM_LISTEN_ADDRESS exists, unset it immediately after server init. 4. Open a channel to parent automatically, expose it as v:parent. Fixes #3118 Fixes #6764 Fixes #9336 Ref https://github.com/neovim/neovim/pull/8247#issuecomment-380275696 Ref #8696
-rw-r--r--runtime/doc/api.txt2
-rw-r--r--runtime/doc/builtin.txt188
-rw-r--r--runtime/doc/deprecated.txt13
-rw-r--r--runtime/doc/eval.txt12
-rw-r--r--runtime/doc/nvim_terminal_emulator.txt18
-rw-r--r--src/nvim/eval.h2
-rw-r--r--src/nvim/eval/funcs.c10
-rw-r--r--src/nvim/eval/typval.c2
-rw-r--r--src/nvim/msgpack_rpc/server.c49
-rw-r--r--src/nvim/terminal.c12
-rw-r--r--src/nvim/terminal.h2
-rw-r--r--test/functional/core/job_spec.lua46
-rw-r--r--test/functional/helpers.lua2
-rw-r--r--test/functional/provider/nodejs_spec.lua4
-rw-r--r--test/functional/provider/perl_spec.lua4
-rw-r--r--test/functional/ui/screen.lua16
-rw-r--r--test/functional/vimscript/server_spec.lua20
17 files changed, 157 insertions, 245 deletions
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index ed3a838b6d..ed13d7f8c2 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -59,7 +59,7 @@ Nvim instance:
# trailing '&' which is required since Nvim won't process events while
# running a blocking command):
#
- # :!./hello.rb &
+ # :!./hello.rb &
#
# Or from another shell by setting NVIM_LISTEN_ADDRESS:
# $ NVIM_LISTEN_ADDRESS=[address] ./hello.rb
diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt
index 3e75914743..a909fd0d6b 100644
--- a/runtime/doc/builtin.txt
+++ b/runtime/doc/builtin.txt
@@ -158,7 +158,6 @@ foldclosedend({lnum}) Number last line of fold at {lnum} if closed
foldlevel({lnum}) Number fold level at {lnum}
foldtext() String line displayed for closed fold
foldtextresult({lnum}) String text for closed fold at {lnum}
-foreground() Number bring the Vim window to the foreground
fullcommand({name}) String get full command from {name}
funcref({name} [, {arglist}] [, {dict}])
Funcref reference to function {name}
@@ -352,16 +351,6 @@ reg_recording() String get the recording register name
reltime([{start} [, {end}]]) List get time value
reltimefloat({time}) Float turn the time value into a Float
reltimestr({time}) String turn time value into a String
-remote_expr({server}, {string} [, {idvar} [, {timeout}]])
- String send expression
-remote_foreground({server}) Number bring Vim server to the foreground
-remote_peek({serverid} [, {retvar}])
- Number check for reply string
-remote_read({serverid} [, {timeout}])
- String read reply string
-remote_send({server}, {string} [, {idvar}])
- String send key sequence
-remote_startserver({name}) none become server {name}
remove({list}, {idx} [, {end}]) any/List
remove items {idx}-{end} from {list}
remove({blob}, {idx} [, {end}]) Number/Blob
@@ -395,8 +384,6 @@ searchpairpos({start}, {middle}, {end} [, {flags} [, {skip} [...]]])
List search for other end of start/end pair
searchpos({pattern} [, {flags} [, {stopline} [, {timeout} [, {skip}]]]])
List search for {pattern}
-server2client({clientid}, {string})
- Number send reply string
serverlist() String get a list of available servers
setbufline({expr}, {lnum}, {text})
Number set line {lnum} to {text} in buffer
@@ -1974,7 +1961,7 @@ expand({string} [, {nosuf} [, {list}]]) *expand()*
<cword> word under the cursor
<cWORD> WORD under the cursor
<client> the {clientid} of the last received
- message |server2client()|
+ message
Modifiers:
:p expand to full path
:h head (last path component removed)
@@ -2409,14 +2396,6 @@ foldtextresult({lnum}) *foldtextresult()*
Can also be used as a |method|: >
GetLnum()->foldtextresult()
<
- *foreground()*
-foreground() Move the Vim window to the foreground. Useful when sent from
- a client to a Vim server. |remote_send()|
- On Win32 systems this might not work, the OS does not always
- allow a window to bring itself to the foreground. Use
- |remote_foreground()| instead.
- {only in the Win32 GUI and console version}
-
fullcommand({name}) *fullcommand()*
Get the full command name from a short abbreviated command
name; see |20.2| for details on command abbreviations.
@@ -4280,6 +4259,15 @@ jobstart({cmd} [, {opts}]) *jobstart()*
by CommandLineToArgvW https://msdn.microsoft.com/bb776391
unless cmd[0] is some form of "cmd.exe".
+ *jobstart-env*
+ The job environment is initialized as follows:
+ $NVIM is set to |v:servername| of the parent Nvim
+ $NVIM_LISTEN_ADDRESS is unset
+ $NVIM_LOG_FILE is unset
+ $VIM is unset
+ $VIMRUNTIME is unset
+ You can set these with the `env` option.
+
*jobstart-options*
{opts} is a dictionary with these keys:
clear_env: (boolean) `env` defines the job environment
@@ -4290,8 +4278,8 @@ jobstart({cmd} [, {opts}]) *jobstart()*
killed when Nvim exits. If the process exits
before Nvim, `on_exit` will be invoked.
env: (dict) Map of environment variable name:value
- pairs extending (or replacing if |clear_env|)
- the current environment.
+ pairs extending (or replacing with |clear_env|)
+ the current environment. |jobstart-env|
height: (number) Height of the `pty` terminal.
|on_exit|: (function) Callback invoked when the job exits.
|on_stdout|: (function) Callback invoked when the job emits
@@ -4305,8 +4293,8 @@ jobstart({cmd} [, {opts}]) *jobstart()*
platforms, this option is silently ignored.)
pty: (boolean) Connect the job to a new pseudo
terminal, and its streams to the master file
- descriptor. Then `on_stderr` is ignored,
- `on_stdout` receives all output.
+ descriptor. `on_stdout` receives all output,
+ `on_stderr` is ignored. |terminal-start|
rpc: (boolean) Use |msgpack-rpc| to communicate with
the job over stdio. Then `on_stdout` is ignored,
but `on_stderr` can still be used.
@@ -5242,9 +5230,8 @@ mode([expr]) Return a string that indicates the current mode.
! Shell or external command is executing
t Terminal mode: keys go to the job
- This is useful in the 'statusline' option or when used
- with |remote_expr()| In most other places it always returns
- "c" or "n".
+ This is useful in the 'statusline' option or RPC calls. In
+ most other places it always returns "c" or "n".
Note that in the future more modes and more specific modes may
be added. It's better not to compare the whole string but only
the leading character(s).
@@ -5964,107 +5951,6 @@ reltimestr({time}) *reltimestr()*
Can also be used as a |method|: >
reltime(start)->reltimestr()
<
- *remote_expr()* *E449*
-remote_expr({server}, {string} [, {idvar} [, {timeout}]])
- Send the {string} to {server}. The {server} argument is a
- string, also see |{server}|.
-
- The string is sent as an expression and the result is returned
- after evaluation. The result must be a String or a |List|. A
- |List| is turned into a String by joining the items with a
- line break in between (not at the end), like with join(expr,
- "\n").
-
- If {idvar} is present and not empty, it is taken as the name
- of a variable and a {serverid} for later use with
- |remote_read()| is stored there.
-
- If {timeout} is given the read times out after this many
- seconds. Otherwise a timeout of 600 seconds is used.
-
- See also |clientserver| |RemoteReply|.
- This function is not available in the |sandbox|.
- Note: Any errors will cause a local error message to be issued
- and the result will be the empty string.
-
- Variables will be evaluated in the global namespace,
- independent of a function currently being active. Except
- when in debug mode, then local function variables and
- arguments can be evaluated.
-
- Examples: >
- :echo remote_expr("gvim", "2+2")
- :echo remote_expr("gvim1", "b:current_syntax")
-<
-
-remote_foreground({server}) *remote_foreground()*
- Move the Vim server with the name {server} to the foreground.
- The {server} argument is a string, also see |{server}|.
- This works like: >
- remote_expr({server}, "foreground()")
-< Except that on Win32 systems the client does the work, to work
- around the problem that the OS doesn't always allow the server
- to bring itself to the foreground.
- Note: This does not restore the window if it was minimized,
- like foreground() does.
- This function is not available in the |sandbox|.
- {only in the Win32 GUI and the Win32 console version}
-
-
-remote_peek({serverid} [, {retvar}]) *remote_peek()*
- Returns a positive number if there are available strings
- from {serverid}. Copies any reply string into the variable
- {retvar} if specified. {retvar} must be a string with the
- name of a variable.
- Returns zero if none are available.
- Returns -1 if something is wrong.
- See also |clientserver|.
- This function is not available in the |sandbox|.
- Examples: >
- :let repl = ""
- :echo "PEEK: " .. remote_peek(id, "repl") .. ": " .. repl
-
-remote_read({serverid}, [{timeout}]) *remote_read()*
- Return the oldest available reply from {serverid} and consume
- it. Unless a {timeout} in seconds is given, it blocks until a
- reply is available.
- See also |clientserver|.
- This function is not available in the |sandbox|.
- Example: >
- :echo remote_read(id)
-<
- *remote_send()* *E241*
-remote_send({server}, {string} [, {idvar}])
- Send the {string} to {server}. The {server} argument is a
- string, also see |{server}|.
-
- The string is sent as input keys and the function returns
- immediately. At the Vim server the keys are not mapped
- |:map|.
-
- If {idvar} is present, it is taken as the name of a variable
- and a {serverid} for later use with remote_read() is stored
- there.
-
- See also |clientserver| |RemoteReply|.
- This function is not available in the |sandbox|.
-
- Note: Any errors will be reported in the server and may mess
- up the display.
- Examples: >
- :echo remote_send("gvim", ":DropAndReply " .. file, "serverid") ..
- \ remote_read(serverid)
-
- :autocmd NONE RemoteReply *
- \ echo remote_read(expand("<amatch>"))
- :echo remote_send("gvim", ":sleep 10 | echo " ..
- \ 'server2client(expand("<client>"), "HELLO")<CR>')
-<
- *remote_startserver()* *E941* *E942*
-remote_startserver({name})
- Become the server {name}. This fails if already running as a
- server, when |v:servername| is not empty.
-
remove({list}, {idx} [, {end}]) *remove()*
Without {end}: Remove the item at {idx} from |List| {list} and
return the item.
@@ -6648,21 +6534,6 @@ searchpos({pattern} [, {flags} [, {stopline} [, {timeout} [, {skip}]]]])
Can also be used as a |method|: >
GetPattern()->searchpos()
-server2client({clientid}, {string}) *server2client()*
- Send a reply string to {clientid}. The most recent {clientid}
- that sent a string can be retrieved with expand("<client>").
- Note:
- Returns zero for success, -1 for failure.
- This id has to be stored before the next command can be
- received. I.e. before returning from the received command and
- before calling any commands that waits for input.
- See also |clientserver|.
- Example: >
- :echo server2client(expand("<client>"), "HELLO")
-
-< Can also be used as a |method|: >
- GetClientId()->server2client(string)
-<
serverlist() *serverlist()*
Returns a list of server addresses, or empty if all servers
were stopped. |serverstart()| |serverstop()|
@@ -6672,7 +6543,9 @@ serverlist() *serverlist()*
serverstart([{address}]) *serverstart()*
Opens a socket or named pipe at {address} and listens for
|RPC| messages. Clients can send |API| commands to the address
- to control Nvim. Returns the address string.
+ to control Nvim.
+
+ Returns the address string.
If {address} does not contain a colon ":" it is interpreted as
a named pipe or Unix domain socket path.
@@ -6694,14 +6567,11 @@ serverstart([{address}]) *serverstart()*
If no address is given, it is equivalent to: >
:call serverstart(tempname())
-< |$NVIM_LISTEN_ADDRESS| is set to {address} if not already set.
-
serverstop({address}) *serverstop()*
Closes the pipe or socket at {address}.
Returns TRUE if {address} is valid, else FALSE.
- If |$NVIM_LISTEN_ADDRESS| is stopped it is unset.
If |v:servername| is stopped it is set to the next available
- address returned by |serverlist()|.
+ address in |serverlist()|.
setbufline({buf}, {lnum}, {text}) *setbufline()*
Set line {lnum} to {text} in buffer {buf}. This works like
@@ -8281,19 +8151,15 @@ tempname() *tempname()* *temp-file-name*
termopen({cmd} [, {opts}]) *termopen()*
Spawns {cmd} in a new pseudo-terminal session connected
- to the current buffer. {cmd} is the same as the one passed to
- |jobstart()|. This function fails if the current buffer is
- modified (all buffer contents are destroyed).
-
- The {opts} dict is similar to the one passed to |jobstart()|,
- but the `pty`, `width`, `height`, and `TERM` fields are
- ignored: `height`/`width` are taken from the current window
- and `$TERM` is set to "xterm-256color".
+ to the current (unmodified) buffer. Parameters and behavior
+ are the same as |jobstart()| except "pty", "width", "height",
+ and "TERM" are ignored: "height" and "width" are taken from
+ the current window.
Returns the same values as |jobstart()|.
- See |terminal| for more information.
-
-test_ functions are documented here: |test-functions-details|
+ Terminal environment is initialized as in ||jobstart-env|,
+ except $TERM is set to "xterm-256color". Full behavior is
+ described in |terminal|.
tan({expr}) *tan()*
Return the tangent of {expr}, measured in radians, as a |Float|
diff --git a/runtime/doc/deprecated.txt b/runtime/doc/deprecated.txt
index f24bf06feb..13644cf208 100644
--- a/runtime/doc/deprecated.txt
+++ b/runtime/doc/deprecated.txt
@@ -6,9 +6,8 @@
Nvim *deprecated*
-The items listed below are "deprecated". This means they will be removed in
-the future. They should not be used in new scripts, and old scripts should be
-updated.
+The items listed below are deprecated: they will be removed in the future.
+They should not be used in new scripts, and old scripts should be updated.
==============================================================================
@@ -25,8 +24,12 @@ Commands ~
*:wviminfo* Deprecated alias to |:wshada| command.
Environment Variables ~
-*$NVIM_LISTEN_ADDRESS* Deprecated in favor of |--listen|. If both are given,
- $NVIM_LISTEN_ADDRESS is ignored.
+*$NVIM_LISTEN_ADDRESS* $NVIM_LISTEN_ADDRESS is a deprecated way to set the
+ |--listen| address of Nvim, and also had a conflicting
+ purpose as a way to detect a parent Nvim (use |$NVIM|
+ for that). It is unset by |terminal| and |jobstart()|
+ (unless explicitly given by the "env" option).
+ Ignored if --listen is given.
Events ~
*BufCreate* Use |BufAdd| instead.
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index c6319c717a..3fd0d96f21 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -2138,9 +2138,19 @@ v:scrollstart String describing the script or function that caused the
*v:servername* *servername-variable*
v:servername Primary listen-address of the current Nvim instance, the first
item returned by |serverlist()|. Can be set by |--listen| or
- |$NVIM_LISTEN_ADDRESS| at startup. |serverstart()| |serverstop()|
+ |$NVIM_LISTEN_ADDRESS| (deprecated) at startup.
+ See also |serverstart()| |serverstop()|.
Read-only.
+ *$NVIM*
+ $NVIM is set by |terminal| and |jobstart()|, and is thus
+ a hint that the current environment is a subprocess of Nvim.
+ Example: >
+ if $NVIM
+ echo nvim_get_chan_info(v:parent)
+ endif
+
+< Note the contents of $NVIM may change in the future.
v:searchforward *v:searchforward* *searchforward-variable*
Search direction: 1 after a forward search, 0 after a
diff --git a/runtime/doc/nvim_terminal_emulator.txt b/runtime/doc/nvim_terminal_emulator.txt
index 0e2b048541..49e29111c6 100644
--- a/runtime/doc/nvim_terminal_emulator.txt
+++ b/runtime/doc/nvim_terminal_emulator.txt
@@ -25,23 +25,23 @@ Start *terminal-start*
There are several ways to create a terminal buffer:
-- Invoke the |:terminal| command.
-- Call the |termopen()| function.
-- Edit a file with a name matching `term://(.{-}//(\d+:)?)?\zs.*`.
- For example:
->
+- Run the |:terminal| command.
+- Call the |nvim_open_term()| or |termopen()| function.
+- Edit a "term://" buffer. Examples: >
:edit term://bash
:vsplit term://top
-<
- Note: The "term://" pattern is handled by a BufReadCmd handler, so the
- |autocmd-nested| modifier is required to use it in an autocmd. >
+
+< Note: To open a "term://" buffer from an autocmd, the |autocmd-nested|
+ modifier is required. >
autocmd VimEnter * ++nested split term://sh
-< This is only mentioned for reference; use |:terminal| instead.
+< (This is only mentioned for reference; use |:terminal| instead.)
When the terminal starts, the buffer contents are updated and the buffer is
named in the form of `term://{cwd}//{pid}:{cmd}`. This naming scheme is used
by |:mksession| to restore a terminal buffer (by restarting the {cmd}).
+The terminal environment is initialized as in |jobstart-env|.
+
==============================================================================
Input *terminal-input*
diff --git a/src/nvim/eval.h b/src/nvim/eval.h
index 53f19b8736..c81b31aba9 100644
--- a/src/nvim/eval.h
+++ b/src/nvim/eval.h
@@ -164,7 +164,7 @@ typedef enum {
VV_ARGV,
VV_COLLATE,
VV_EXITING,
- // Neovim
+ // Nvim
VV_STDERR,
VV_MSGPACK_TYPES,
VV__NULL_STRING, // String with NULL value. For test purposes only.
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 88059ff21e..0a71526246 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -5088,6 +5088,16 @@ static dict_T *create_environment(const dictitem_T *job_env, const bool clear_en
tv_dict_add_str(env, S_LEN("TERM"), pty_term_name);
}
+ // Set $NVIM (in the child process) to v:servername. #3118
+ char *nvim_addr = (char *)get_vim_var_str(VV_SEND_SERVER);
+ if (nvim_addr[0] != '\0') {
+ dictitem_T *dv = tv_dict_find(env, S_LEN("NVIM"));
+ if (dv) {
+ tv_dict_item_remove(env, dv);
+ }
+ tv_dict_add_str(env, S_LEN("NVIM"), nvim_addr);
+ }
+
if (job_env) {
#ifdef WIN32
TV_DICT_ITER(job_env->di_tv.vval.v_dict, var, {
diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c
index 2a432ecb47..ff52962913 100644
--- a/src/nvim/eval/typval.c
+++ b/src/nvim/eval/typval.c
@@ -1588,8 +1588,6 @@ varnumber_T tv_dict_get_number(const dict_T *const d, const char *const key)
}
/// Converts a dict to an environment
-///
-///
char **tv_dict_to_env(dict_T *denv)
{
size_t env_size = (size_t)tv_dict_len(denv);
diff --git a/src/nvim/msgpack_rpc/server.c b/src/nvim/msgpack_rpc/server.c
index e954e4b3a3..f15ce82917 100644
--- a/src/nvim/msgpack_rpc/server.c
+++ b/src/nvim/msgpack_rpc/server.c
@@ -22,7 +22,8 @@
#include "nvim/vim.h"
#define MAX_CONNECTIONS 32
-#define LISTEN_ADDRESS_ENV_VAR "NVIM_LISTEN_ADDRESS"
+#define ENV_LISTEN "NVIM_LISTEN_ADDRESS" // deprecated
+#define ENV_NVIM "NVIM"
static garray_T watchers = GA_EMPTY_INIT_VALUE;
@@ -35,20 +36,24 @@ bool server_init(const char *listen_addr)
{
ga_init(&watchers, sizeof(SocketWatcher *), 1);
- // $NVIM_LISTEN_ADDRESS
- const char *env_addr = os_getenv(LISTEN_ADDRESS_ENV_VAR);
- int rv = listen_addr == NULL ? 1 : server_start(listen_addr);
+ // $NVIM_LISTEN_ADDRESS (deprecated)
+ if (!listen_addr && os_env_exists(ENV_LISTEN)) {
+ listen_addr = os_getenv(ENV_LISTEN);
+ }
+ int rv = listen_addr ? server_start(listen_addr) : 1;
if (0 != rv) {
- rv = env_addr == NULL ? 1 : server_start(env_addr);
- if (0 != rv) {
- listen_addr = server_address_new();
- if (listen_addr == NULL) {
- return false;
- }
- rv = server_start(listen_addr);
- xfree((char *)listen_addr);
+ listen_addr = server_address_new();
+ if (!listen_addr) {
+ return false;
}
+ rv = server_start(listen_addr);
+ xfree((char *)listen_addr);
+ }
+
+ if (os_env_exists(ENV_LISTEN)) {
+ // Unset $NVIM_LISTEN_ADDRESS, it's a liability hereafter.
+ os_unsetenv(ENV_LISTEN);
}
return rv == 0;
@@ -60,8 +65,8 @@ static void close_socket_watcher(SocketWatcher **watcher)
socket_watcher_close(*watcher, free_server);
}
-/// Set v:servername to the first server in the server list, or unset it if no
-/// servers are known.
+/// Sets the "primary address" (v:servername and $NVIM) to the first server in
+/// the server list, or unsets if no servers are known.
static void set_vservername(garray_T *srvs)
{
char *default_server = (srvs->ga_len > 0)
@@ -156,12 +161,6 @@ int server_start(const char *endpoint)
return result;
}
- // Update $NVIM_LISTEN_ADDRESS, if not set.
- const char *listen_address = os_getenv(LISTEN_ADDRESS_ENV_VAR);
- if (listen_address == NULL) {
- os_setenv(LISTEN_ADDRESS_ENV_VAR, watcher->addr, 1);
- }
-
// Add the watcher to the list.
ga_grow(&watchers, 1);
((SocketWatcher **)watchers.ga_data)[watchers.ga_len++] = watcher;
@@ -200,12 +199,6 @@ bool server_stop(char *endpoint)
return false;
}
- // Unset $NVIM_LISTEN_ADDRESS if it is the stopped address.
- const char *listen_address = os_getenv(LISTEN_ADDRESS_ENV_VAR);
- if (listen_address && STRCMP(addr, listen_address) == 0) {
- os_unsetenv(LISTEN_ADDRESS_ENV_VAR);
- }
-
socket_watcher_close(watcher, free_server);
// Remove this server from the list by swapping it with the last item.
@@ -215,8 +208,8 @@ bool server_stop(char *endpoint)
}
watchers.ga_len--;
- // If v:servername is the stopped address, re-initialize it.
- if (STRCMP(addr, get_vim_var_str(VV_SEND_SERVER)) == 0) {
+ // Bump v:servername to the next available server, if any.
+ if (strequal(addr, (char *)get_vim_var_str(VV_SEND_SERVER))) {
set_vservername(&watchers);
}
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index b07c3786c3..225aa0100e 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -179,6 +179,13 @@ static void term_output_callback(const char *s, size_t len, void *user_data)
// public API {{{
+/// Initializes terminal properties, and triggers TermOpen.
+///
+/// The PTY process (TerminalOptions.data) was already started by termopen(),
+/// via ex_terminal() or the term:// BufReadCmd.
+///
+/// @param buf Buffer used for presentation of the terminal.
+/// @param opts PTY process channel, various terminal properties and callbacks.
Terminal *terminal_open(buf_T *buf, TerminalOptions opts)
{
// Create a new terminal instance and configure it
@@ -374,6 +381,7 @@ void terminal_check_size(Terminal *term)
invalidate_terminal(term, -1, -1);
}
+/// Implements TERM_FOCUS mode. :help Terminal-mode
void terminal_enter(void)
{
buf_T *buf = curbuf;
@@ -502,6 +510,7 @@ static int terminal_check(VimState *state)
return 1;
}
+/// Processes one char of terminal-mode input.
static int terminal_execute(VimState *state, int key)
{
TerminalState *s = (TerminalState *)state;
@@ -1448,7 +1457,8 @@ static void refresh_terminal(Terminal *term)
long ml_added = buf->b_ml.ml_line_count - ml_before;
adjust_topline(term, buf, ml_added);
}
-// Calls refresh_terminal() on all invalidated_terminals.
+
+/// Calls refresh_terminal() on all invalidated_terminals.
static void refresh_timer_cb(TimeWatcher *watcher, void *data)
{
refresh_pending = false;
diff --git a/src/nvim/terminal.h b/src/nvim/terminal.h
index 001adbadc3..a83929e224 100644
--- a/src/nvim/terminal.h
+++ b/src/nvim/terminal.h
@@ -13,7 +13,7 @@ typedef void (*terminal_close_cb)(void *data);
#include "nvim/buffer_defs.h"
typedef struct {
- void *data;
+ void *data; // PTY process channel
uint16_t width, height;
terminal_write_cb write_cb;
terminal_resize_cb resize_cb;
diff --git a/test/functional/core/job_spec.lua b/test/functional/core/job_spec.lua
index 94a50b9a41..cf24e570cb 100644
--- a/test/functional/core/job_spec.lua
+++ b/test/functional/core/job_spec.lua
@@ -16,6 +16,7 @@ local poke_eventloop = helpers.poke_eventloop
local iswin = helpers.iswin
local get_pathsep = helpers.get_pathsep
local pathroot = helpers.pathroot
+local exec_lua = helpers.exec_lua
local nvim_set = helpers.nvim_set
local expect_twostreams = helpers.expect_twostreams
local expect_msg_seq = helpers.expect_msg_seq
@@ -208,7 +209,7 @@ describe('jobs', function()
ok(string.find(err, "E475: Invalid argument: expected valid directory$") ~= nil)
end)
- it('produces error when using non-executable `cwd`', function()
+ it('error on non-executable `cwd`', function()
if iswin() then return end -- N/A for Windows
local dir = 'Xtest_not_executable_dir'
@@ -249,7 +250,7 @@ describe('jobs', function()
eq({'notification', 'exit', {0, 0}}, next_msg())
end)
- it('allows interactive commands', function()
+ it('interactive commands', function()
nvim('command', "let j = jobstart(['cat', '-'], g:job_opts)")
neq(0, eval('j'))
nvim('command', 'call jobsend(j, "abc\\n")')
@@ -295,7 +296,7 @@ describe('jobs', function()
nvim('command', "call jobstop(j)")
end)
- it("will not buffer data if it doesn't end in newlines", function()
+ it("emits partial lines (does NOT buffer data lacking newlines)", function()
nvim('command', "let j = jobstart(['cat', '-'], g:job_opts)")
nvim('command', 'call jobsend(j, "abc\\nxyz")')
eq({'notification', 'stdout', {0, {'abc', 'xyz'}}}, next_msg())
@@ -378,7 +379,7 @@ describe('jobs', function()
eq(NIL, meths.get_proc(pid))
end)
- it("do not survive the exit of nvim", function()
+ it("disposed on Nvim exit", function()
-- use sleep, which doesn't die on stdin close
nvim('command', "let g:j = jobstart(has('win32') ? ['ping', '-n', '1001', '127.0.0.1'] : ['sleep', '1000'], g:job_opts)")
local pid = eval('jobpid(g:j)')
@@ -646,6 +647,43 @@ describe('jobs', function()
)
end)
+ it('jobstart() environment: $NVIM, $NVIM_LISTEN_ADDRESS #11009', function()
+ local function get_env_in_child_job(envname, env)
+ return exec_lua([[
+ local envname, env = ...
+ local join = function(s) return vim.fn.join(s, '') end
+ local stdout = {}
+ local stderr = {}
+ local opt = {
+ env = env,
+ stdout_buffered = true,
+ stderr_buffered = true,
+ on_stderr = function(chan, data, name) stderr = data end,
+ on_stdout = function(chan, data, name) stdout = data end,
+ }
+ local j1 = vim.fn.jobstart({ vim.v.progpath, '-es', '-V1',( '+echo "%s="..getenv("%s")'):format(envname, envname), '+qa!' }, opt)
+ vim.fn.jobwait({ j1 }, 10000)
+ return join({ join(stdout), join(stderr) })
+ ]],
+ envname,
+ env)
+ end
+
+ local addr = eval('v:servername')
+ ok((addr):len() > 0)
+ -- $NVIM is _not_ defined in the top-level Nvim process.
+ eq('', eval('$NVIM'))
+ -- jobstart() shares its v:servername with the child via $NVIM.
+ eq('NVIM='..addr, get_env_in_child_job('NVIM'))
+ -- $NVIM_LISTEN_ADDRESS is unset by server_init in the child.
+ eq('NVIM_LISTEN_ADDRESS=null', get_env_in_child_job('NVIM_LISTEN_ADDRESS'))
+ eq('NVIM_LISTEN_ADDRESS=null', get_env_in_child_job('NVIM_LISTEN_ADDRESS',
+ { NVIM_LISTEN_ADDRESS='Xtest_jobstart_env' }))
+ -- User can explicitly set $NVIM_LOG_FILE, $VIM, $VIMRUNTIME.
+ eq('NVIM_LOG_FILE=Xtest_jobstart_env',
+ get_env_in_child_job('NVIM_LOG_FILE', { NVIM_LOG_FILE='Xtest_jobstart_env' }))
+ end)
+
describe('jobwait', function()
before_each(function()
if iswin() then
diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua
index b0b2dac9fd..e9c3d4bd92 100644
--- a/test/functional/helpers.lua
+++ b/test/functional/helpers.lua
@@ -782,7 +782,7 @@ function module.pathroot()
return iswin() and (module.nvim_dir:sub(1,2)..pathsep) or '/'
end
--- Returns a valid, platform-independent $NVIM_LISTEN_ADDRESS.
+-- Returns a valid, platform-independent Nvim listen address.
-- Useful for communicating with child instances.
function module.new_pipename()
-- HACK: Start a server temporarily, get the name, then stop it.
diff --git a/test/functional/provider/nodejs_spec.lua b/test/functional/provider/nodejs_spec.lua
index 661a6f4f94..187f1c0412 100644
--- a/test/functional/provider/nodejs_spec.lua
+++ b/test/functional/provider/nodejs_spec.lua
@@ -29,7 +29,7 @@ describe('nodejs host', function()
local fname = 'Xtest-nodejs-hello.js'
write_file(fname, [[
const neovim = require('neovim');
- const nvim = neovim.attach({socket: process.env.NVIM_LISTEN_ADDRESS});
+ const nvim = neovim.attach({socket: process.env.NVIM});
nvim.command('let g:job_out = "hello"');
]])
command('let g:job_id = jobstart(["node", "'..fname..'"])')
@@ -39,7 +39,7 @@ describe('nodejs host', function()
local fname = 'Xtest-nodejs-hello-plugin.js'
write_file(fname, [[
const neovim = require('neovim');
- const nvim = neovim.attach({socket: process.env.NVIM_LISTEN_ADDRESS});
+ const nvim = neovim.attach({socket: process.env.NVIM});
class TestPlugin {
hello() {
diff --git a/test/functional/provider/perl_spec.lua b/test/functional/provider/perl_spec.lua
index 125674660b..aff5e36e24 100644
--- a/test/functional/provider/perl_spec.lua
+++ b/test/functional/provider/perl_spec.lua
@@ -83,7 +83,7 @@ describe('perl provider', function()
use Neovim::Ext;
use Neovim::Ext::MsgPack::RPC;
- my $session = Neovim::Ext::MsgPack::RPC::socket_session($ENV{NVIM_LISTEN_ADDRESS});
+ my $session = Neovim::Ext::MsgPack::RPC::socket_session($ENV{NVIM});
my $nvim = Neovim::Ext::from_session($session);
$nvim->command('let g:job_out = "hello"');
1;
@@ -116,7 +116,7 @@ describe('perl provider', function()
use Neovim::Ext;
use Neovim::Ext::MsgPack::RPC;
- my $session = Neovim::Ext::MsgPack::RPC::socket_session($ENV{NVIM_LISTEN_ADDRESS});
+ my $session = Neovim::Ext::MsgPack::RPC::socket_session($ENV{NVIM});
my $nvim = Neovim::Ext::from_session($session);
my $plugin = TestPlugin->new($nvim);
$plugin->test_command();
diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua
index e8a39ab6f8..80dba70b33 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -75,7 +75,7 @@ local busted = require('busted')
local deepcopy = helpers.deepcopy
local shallowcopy = helpers.shallowcopy
local concat_tables = helpers.concat_tables
-local request, run_session = helpers.request, helpers.run_session
+local run_session = helpers.run_session
local eq = helpers.eq
local dedent = helpers.dedent
local get_session = helpers.get_session
@@ -90,8 +90,6 @@ end
local Screen = {}
Screen.__index = Screen
-local debug_screen
-
local default_timeout_factor = 1
if os.getenv('VALGRIND') then
default_timeout_factor = default_timeout_factor * 3
@@ -123,18 +121,6 @@ do
Screen.colornames = colornames
end
-function Screen.debug(command)
- if not command then
- command = 'pynvim -n -c '
- end
- command = command .. request('vim_eval', '$NVIM_LISTEN_ADDRESS')
- if debug_screen then
- debug_screen:close()
- end
- debug_screen = io.popen(command, 'r')
- debug_screen:read()
-end
-
function Screen.new(width, height)
if not width then
width = 53
diff --git a/test/functional/vimscript/server_spec.lua b/test/functional/vimscript/server_spec.lua
index 238d1aeb0f..de64a77b4d 100644
--- a/test/functional/vimscript/server_spec.lua
+++ b/test/functional/vimscript/server_spec.lua
@@ -1,6 +1,5 @@
local helpers = require('test.functional.helpers')(after_each)
local eq, neq, eval = helpers.eq, helpers.neq, helpers.eval
-local command = helpers.command
local clear, funcs, meths = helpers.clear, helpers.funcs, helpers.meths
local iswin = helpers.iswin
local ok = helpers.ok
@@ -16,27 +15,25 @@ end
describe('server', function()
before_each(clear)
- it('serverstart() sets $NVIM_LISTEN_ADDRESS on first invocation', function()
- -- Unset $NVIM_LISTEN_ADDRESS
- command('let $NVIM_LISTEN_ADDRESS = ""')
-
+ it('serverstart(), serverstop() does not set $NVIM', function()
local s = eval('serverstart()')
assert(s ~= nil and s:len() > 0, "serverstart() returned empty")
- eq(s, eval('$NVIM_LISTEN_ADDRESS'))
+ eq('', eval('$NVIM'))
+ eq('', eval('$NVIM_LISTEN_ADDRESS'))
eq(1, eval("serverstop('"..s.."')"))
eq('', eval('$NVIM_LISTEN_ADDRESS'))
end)
it('sets new v:servername if $NVIM_LISTEN_ADDRESS is invalid', function()
clear({env={NVIM_LISTEN_ADDRESS='.'}})
- eq('.', eval('$NVIM_LISTEN_ADDRESS'))
+ -- Cleared on startup.
+ eq('', eval('$NVIM_LISTEN_ADDRESS'))
local servers = funcs.serverlist()
eq(1, #servers)
ok(string.len(servers[1]) > 4) -- Like /tmp/nvim…/… or \\.\pipe\…
end)
- it('sets v:servername at startup or if all servers were stopped',
- function()
+ it('sets v:servername at startup or if all servers were stopped', function()
local initial_server = meths.get_vvar('servername')
assert(initial_server ~= nil and initial_server:len() > 0,
'v:servername was not initialized')
@@ -55,11 +52,13 @@ describe('server', function()
eq(1, funcs.serverstop(funcs.serverlist()[1]))
eq('', meths.get_vvar('servername'))
- -- v:servername will take the next available server.
+ -- v:servername and $NVIM take the next available server.
local servername = (iswin() and [[\\.\pipe\Xtest-functional-server-pipe]]
or 'Xtest-functional-server-socket')
funcs.serverstart(servername)
eq(servername, meths.get_vvar('servername'))
+ -- Not set in the current process, only in children.
+ eq('', eval('$NVIM'))
end)
it('serverstop() returns false for invalid input', function()
@@ -136,7 +135,6 @@ end)
describe('startup --listen', function()
it('validates', function()
clear()
-
local cmd = { unpack(helpers.nvim_argv) }
table.insert(cmd, '--listen')
matches('nvim.*: Argument missing after: "%-%-listen"', funcs.system(cmd))