mirror of
https://github.com/neovim/neovim.git
synced 2026-04-29 10:44:08 +00:00
job control: reuse common job code for rpc jobs
This makes stderr and exit callbacks work for rpc jobs
This commit is contained in:
@@ -5,11 +5,24 @@ endif
|
||||
|
||||
let s:loaded_pythonx_provider = 1
|
||||
|
||||
let s:stderr = {}
|
||||
let s:job_opts = {'rpc': v:true}
|
||||
|
||||
" TODO(bfredl): this logic is common and should be builtin
|
||||
function! s:job_opts.on_stderr(chan_id, data, event)
|
||||
let stderr = get(s:stderr, a:chan_id, [''])
|
||||
let last = remove(stderr, -1)
|
||||
let a:data[0] = last.a:data[0]
|
||||
call extend(stderr, a:data)
|
||||
let s:stderr[a:chan_id] = stderr
|
||||
endfunction
|
||||
|
||||
function! provider#pythonx#Require(host) abort
|
||||
let ver = (a:host.orig_name ==# 'python') ? 2 : 3
|
||||
|
||||
" Python host arguments
|
||||
let args = ['-c', 'import sys; sys.path.remove(""); import neovim; neovim.start_host()']
|
||||
let prog = (ver == '2' ? provider#python#Prog() : provider#python3#Prog())
|
||||
let args = [prog, '-c', 'import sys; sys.path.remove(""); import neovim; neovim.start_host()']
|
||||
|
||||
" Collect registered Python plugins into args
|
||||
let python_plugins = remote#host#PluginsForHost(a:host.name)
|
||||
@@ -18,14 +31,16 @@ function! provider#pythonx#Require(host) abort
|
||||
endfor
|
||||
|
||||
try
|
||||
let channel_id = rpcstart((ver ==# '2' ?
|
||||
\ provider#python#Prog() : provider#python3#Prog()), args)
|
||||
let channel_id = jobstart(args, s:job_opts)
|
||||
if rpcrequest(channel_id, 'poll') ==# 'ok'
|
||||
return channel_id
|
||||
endif
|
||||
catch
|
||||
echomsg v:throwpoint
|
||||
echomsg v:exception
|
||||
for row in get(s:stderr, channel_id, [])
|
||||
echomsg row
|
||||
endfor
|
||||
endtry
|
||||
throw remote#host#LoadErrorForHost(a:host.orig_name,
|
||||
\ '$NVIM_PYTHON_LOG_FILE')
|
||||
|
||||
@@ -4,6 +4,17 @@ if exists('g:loaded_ruby_provider')
|
||||
endif
|
||||
let g:loaded_ruby_provider = 1
|
||||
|
||||
let s:stderr = {}
|
||||
let s:job_opts = {'rpc': v:true}
|
||||
|
||||
function! s:job_opts.on_stderr(chan_id, data, event)
|
||||
let stderr = get(s:stderr, a:chan_id, [''])
|
||||
let last = remove(stderr, -1)
|
||||
let a:data[0] = last.a:data[0]
|
||||
call extend(stderr, a:data)
|
||||
let s:stderr[a:chan_id] = stderr
|
||||
endfunction
|
||||
|
||||
function! provider#ruby#Detect() abort
|
||||
return exepath('neovim-ruby-host')
|
||||
endfunction
|
||||
@@ -13,7 +24,7 @@ function! provider#ruby#Prog()
|
||||
endfunction
|
||||
|
||||
function! provider#ruby#Require(host) abort
|
||||
let args = []
|
||||
let args = [provider#ruby#Prog()]
|
||||
let ruby_plugins = remote#host#PluginsForHost(a:host.name)
|
||||
|
||||
for plugin in ruby_plugins
|
||||
@@ -21,13 +32,16 @@ function! provider#ruby#Require(host) abort
|
||||
endfor
|
||||
|
||||
try
|
||||
let channel_id = rpcstart(provider#ruby#Prog(), args)
|
||||
let channel_id = jobstart(args, s:job_opts)
|
||||
if rpcrequest(channel_id, 'poll') ==# 'ok'
|
||||
return channel_id
|
||||
endif
|
||||
catch
|
||||
echomsg v:throwpoint
|
||||
echomsg v:exception
|
||||
for row in get(s:stderr, channel_id, [])
|
||||
echomsg row
|
||||
endfor
|
||||
endtry
|
||||
throw remote#host#LoadErrorForHost(a:host.orig_name, '$NVIM_RUBY_LOG_FILE')
|
||||
endfunction
|
||||
|
||||
@@ -261,9 +261,8 @@ function! remote#host#LoadErrorForHost(host, log) abort
|
||||
\ 'You can try to see what happened '.
|
||||
\ 'by starting Neovim with the environment variable '.
|
||||
\ a:log . ' set to a file and opening the generated '.
|
||||
\ 'log file. Also, the host stderr will be available '.
|
||||
\ 'in Neovim log, so it may contain useful information. '.
|
||||
\ 'See also ~/.nvimlog.'
|
||||
\ 'log file. Also, the host stderr is available '.
|
||||
\ 'in messages.'
|
||||
endfunction
|
||||
|
||||
|
||||
|
||||
@@ -2043,7 +2043,6 @@ rpcnotify({channel}, {event}[, {args}...])
|
||||
Sends an |RPC| notification to {channel}
|
||||
rpcrequest({channel}, {method}[, {args}...])
|
||||
Sends an |RPC| request to {channel}
|
||||
rpcstart({prog}[, {argv}]) Spawns {prog} and opens an |RPC| channel
|
||||
rpcstop({channel}) Closes an |RPC| {channel}
|
||||
screenattr({row}, {col}) Number attribute at screen position
|
||||
screenchar({row}, {col}) Number character at screen position
|
||||
@@ -4395,8 +4394,10 @@ items({dict}) *items()*
|
||||
order.
|
||||
|
||||
jobclose({job}[, {stream}]) {Nvim} *jobclose()*
|
||||
Close {job}'s {stream}, which can be one "stdin", "stdout" or
|
||||
"stderr". If {stream} is omitted, all streams are closed.
|
||||
Close {job}'s {stream}, which can be one of "stdin", "stdout",
|
||||
"stderr" or "rpc" (closes the rpc channel for a job started
|
||||
with the "rpc" option.) If {stream} is omitted, all streams
|
||||
are closed.
|
||||
|
||||
jobpid({job}) {Nvim} *jobpid()*
|
||||
Return the pid (process id) of {job}.
|
||||
@@ -4418,6 +4419,10 @@ jobsend({job}, {data}) {Nvim} *jobsend()*
|
||||
:call jobsend(j, ["abc", "123\n456", ""])
|
||||
< will send "abc<NL>123<NUL>456<NL>".
|
||||
|
||||
If the job was started with the rpc option this function
|
||||
cannot be used, instead use |rpcnotify()| and |rpcrequest()|
|
||||
to communicate with the job.
|
||||
|
||||
jobstart({cmd}[, {opts}]) {Nvim} *jobstart()*
|
||||
Spawns {cmd} as a job. If {cmd} is a |List| it is run
|
||||
directly. If {cmd} is a |String| it is processed like this: >
|
||||
@@ -4433,9 +4438,14 @@ jobstart({cmd}[, {opts}]) {Nvim} *jobstart()*
|
||||
on_exit : exit event handler (function name or |Funcref|)
|
||||
cwd : Working directory of the job; defaults to
|
||||
|current-directory|.
|
||||
rpc : If set, |msgpack-rpc| will be used to communicate
|
||||
with the job over stdin and stdout. "on_stdout" is
|
||||
then ignored, but "on_stderr" can still be used.
|
||||
pty : If set, the job will be connected to a new pseudo
|
||||
terminal, and the job streams are connected to
|
||||
the master file descriptor.
|
||||
terminal, and the job streams are connected to
|
||||
the master file descriptor. "on_stderr" is ignored
|
||||
as all output will be received on stdout.
|
||||
|
||||
width : (pty only) Width of the terminal screen
|
||||
height : (pty only) Height of the terminal screen
|
||||
TERM : (pty only) $TERM environment variable
|
||||
@@ -4447,10 +4457,12 @@ jobstart({cmd}[, {opts}]) {Nvim} *jobstart()*
|
||||
{opts} is passed as |self| to the callback; the caller may
|
||||
pass arbitrary data by setting other keys.
|
||||
Returns:
|
||||
- job ID on success, used by |jobsend()| and |jobstop()|
|
||||
- The job ID on success, which is used by |jobsend()| (or
|
||||
|rpcnotify()| and |rpcrequest()| if "rpc" option was used)
|
||||
and |jobstop()|
|
||||
- 0 on invalid arguments or if the job table is full
|
||||
- -1 if {cmd}[0] is not executable.
|
||||
See |job-control| for more information.
|
||||
See |job-control| and |msgpack-rpc| for more information.
|
||||
|
||||
jobstop({job}) {Nvim} *jobstop()*
|
||||
Stop a job created with |jobstart()| by sending a `SIGTERM`
|
||||
@@ -5649,19 +5661,20 @@ rpcrequest({channel}, {method}[, {args}...]) {Nvim} *rpcrequest()*
|
||||
:let result = rpcrequest(rpc_chan, "func", 1, 2, 3)
|
||||
|
||||
rpcstart({prog}[, {argv}]) {Nvim} *rpcstart()*
|
||||
Spawns {prog} as a job (optionally passing the list {argv}),
|
||||
and opens an |RPC| channel with the spawned process's
|
||||
stdin/stdout. Returns:
|
||||
- channel id on success, which is used by |rpcrequest()|,
|
||||
|rpcnotify()| and |rpcstop()|
|
||||
- 0 on failure
|
||||
Example: >
|
||||
:let rpc_chan = rpcstart('prog', ['arg1', 'arg2'])
|
||||
Deprecated. Replace >
|
||||
:let id = rpcstart('prog', ['arg1', 'arg2'])
|
||||
< with >
|
||||
:let id = jobstart(['prog', 'arg1', 'arg2'],
|
||||
{'rpc': v:true})
|
||||
|
||||
rpcstop({channel}) {Nvim} *rpcstop()*
|
||||
Closes an |RPC| {channel}, possibly created via
|
||||
|rpcstart()|. Also closes channels created by connections to
|
||||
|v:servername|.
|
||||
Closes an |RPC| {channel}. If the channel is a job
|
||||
started with |jobstart()| the job is killed.
|
||||
It is better to use |jobstop()| in this case, or use
|
||||
|jobclose|(id, "rpc") to only close the channel without
|
||||
killing the job.
|
||||
Closes the socket connection if the channel was opened by
|
||||
connecting to |v:servername|.
|
||||
|
||||
screenattr(row, col) *screenattr()*
|
||||
Like screenchar(), but return the attribute. This is a rather
|
||||
|
||||
@@ -11,7 +11,6 @@ RPC API for Nvim *RPC* *rpc* *msgpack-rpc*
|
||||
3. Connecting |rpc-connecting|
|
||||
4. Clients |rpc-api-client|
|
||||
5. Types |rpc-types|
|
||||
6. Vimscript functions |rpc-vim-functions|
|
||||
|
||||
==============================================================================
|
||||
1. Introduction *rpc-intro*
|
||||
@@ -66,12 +65,16 @@ To get a formatted dump of the API using python (requires the `pyyaml` and
|
||||
==============================================================================
|
||||
3. Connecting *rpc-connecting*
|
||||
|
||||
There are several ways to open a msgpack-rpc stream to an Nvim server:
|
||||
There are several ways to open a msgpack-rpc channel to an Nvim instance:
|
||||
|
||||
1. Through stdin/stdout when `nvim` is started with `--embed`. This is how
|
||||
applications can embed Nvim.
|
||||
|
||||
2. Through stdin/stdout of some other process spawned by |rpcstart()|.
|
||||
2. Through stdin/stdout of some other process spawned by |jobstart()|.
|
||||
Set the "rpc" key to |v:true| in the options dict to use the job's stdin
|
||||
and stdout as a single msgpack channel that is processed directly by
|
||||
Nvim. Then it is not possible to process raw data to or from the
|
||||
process's stdin and stdout. stderr can still be used, though.
|
||||
|
||||
3. Through the socket automatically created with each instance. The socket
|
||||
location is stored in |v:servername|.
|
||||
@@ -110,11 +113,12 @@ functions can be called interactively:
|
||||
>>> nvim = attach('socket', path='[address]')
|
||||
>>> nvim.command('echo "hello world!"')
|
||||
<
|
||||
You can also embed an Nvim instance via |rpcstart()|
|
||||
You can also embed an Nvim instance via |jobstart()|, and communicate using
|
||||
|rpcrequest()| and |rpcnotify()|:
|
||||
>
|
||||
let vim = rpcstart('nvim', ['--embed'])
|
||||
let vim = jobstart(['nvim', '--embed'], {'rpc': v:true})
|
||||
echo rpcrequest(vim, 'vim_eval', '"Hello " . "world!"')
|
||||
call rpcstop(vim)
|
||||
call jobstop(vim)
|
||||
<
|
||||
==============================================================================
|
||||
4. Implementing API clients *rpc-api-client* *api-client*
|
||||
@@ -233,23 +237,5 @@ Even for statically compiled clients it is good practice to avoid hardcoding
|
||||
the type codes, because a client may be built against one Nvim version but
|
||||
connect to another with different type codes.
|
||||
|
||||
==============================================================================
|
||||
6. Vimscript functions *rpc-vim-functions*
|
||||
|
||||
RPC functions are available in Vimscript:
|
||||
|
||||
1. |rpcstart()|: Similarly to |jobstart()|, this will spawn a co-process
|
||||
with its standard handles connected to Nvim. The difference is that it's
|
||||
not possible to process raw data to or from the process's stdin, stdout,
|
||||
or stderr. This is because the job's stdin and stdout are used as
|
||||
a single msgpack channel that is processed directly by Nvim.
|
||||
2. |rpcstop()|: Same as |jobstop()|, but operates on handles returned by
|
||||
|rpcstart()|.
|
||||
3. |rpcrequest()|: Sends a msgpack-rpc request to the process.
|
||||
4. |rpcnotify()|: Sends a msgpack-rpc notification to the process.
|
||||
|
||||
|rpcrequest()| and |rpcnotify()| can also be used with channels connected to
|
||||
a nvim server. |v:servername|
|
||||
|
||||
==============================================================================
|
||||
vim:tw=78:ts=8:noet:ft=help:norl:
|
||||
|
||||
Reference in New Issue
Block a user