mirror of
https://github.com/neovim/neovim
synced 2025-07-16 09:11:51 +00:00
[Backport release-0.7] introduce $NVIM, unset $NVIM_LISTEN_ADDRESS (#18986)
feat(server): introduce $NVIM
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
(cherry picked from commit b9d97f5951
)
Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
This commit is contained in:
committed by
GitHub
parent
ed9e6d19ab
commit
fdd5178581
@ -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
|
||||
|
@ -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.
|
||||
@ -5237,9 +5225,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).
|
||||
@ -5959,107 +5946,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.
|
||||
@ -6643,21 +6529,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()|
|
||||
@ -6667,7 +6538,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.
|
||||
@ -6689,14 +6562,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
|
||||
@ -8276,19 +8146,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|
|
||||
|
@ -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.
|
||||
|
@ -2135,9 +2135,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
|
||||
|
@ -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*
|
||||
|
||||
|
@ -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.
|
||||
|
@ -5090,6 +5090,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, {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -779,7 +779,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.
|
||||
|
@ -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() {
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
Reference in New Issue
Block a user