Merge PR #1163 'Initial documentation of nvim features'

This commit is contained in:
Thiago de Arruda 2014-09-13 21:49:18 -03:00
commit 06390208f3
14 changed files with 749 additions and 225 deletions

View File

@ -303,6 +303,7 @@ Name triggered by ~
|InsertLeave| when leaving Insert mode |InsertLeave| when leaving Insert mode
|InsertCharPre| when a character was typed in Insert mode, before |InsertCharPre| when a character was typed in Insert mode, before
inserting it inserting it
|JobActivity| when something interesting happen with a job
|TextChanged| after a change was made to the text in Normal mode |TextChanged| after a change was made to the text in Normal mode
|TextChangedI| after a change was made to the text in Insert mode |TextChangedI| after a change was made to the text in Insert mode
@ -712,6 +713,10 @@ InsertEnter Just before starting Insert mode. Also for
*InsertLeave* *InsertLeave*
InsertLeave When leaving Insert mode. Also when using InsertLeave When leaving Insert mode. Also when using
CTRL-O |i_CTRL-O|. But not for |i_CTRL-C|. CTRL-O |i_CTRL-O|. But not for |i_CTRL-C|.
{Nvim} *JobActivity*
JobActivity When something interesting happens with a job
spawned by |jobstart()|. See |job-control| for
details.
*MenuPopup* *MenuPopup*
MenuPopup Just before showing the popup menu (under the MenuPopup Just before showing the popup menu (under the
right mouse button). Useful for adjusting the right mouse button). Useful for adjusting the
@ -1383,4 +1388,4 @@ This will write the file without triggering the autocommands defined by the
gzip plugin. gzip plugin.
vim:tw=78:ts=8:ft=help:norl: vim:tw=78:ts=8:noet:ft=help:norl:

View File

@ -1865,6 +1865,10 @@ invert( {expr}) Number bitwise invert
isdirectory( {directory}) Number TRUE if {directory} is a directory isdirectory( {directory}) Number TRUE if {directory} is a directory
islocked( {expr}) Number TRUE if {expr} is locked islocked( {expr}) Number TRUE if {expr} is locked
items( {dict}) List key-value pairs in {dict} items( {dict}) List key-value pairs in {dict}
job_close({job}) Closes a job with id {job}
job_send({job}, {data}) Writes {data} to {job}'s stdin
job_spawn({name}, {prog}[, {argv}])
Spawns {prog} as a job associated with {name}
join( {list} [, {sep}]) String join {list} items into one String join( {list} [, {sep}]) String join {list} items into one String
keys( {dict}) List keys in {dict} keys( {dict}) List keys in {dict}
len( {expr}) Number the length of {expr} len( {expr}) Number the length of {expr}
@ -1934,6 +1938,12 @@ repeat( {expr}, {count}) String repeat {expr} {count} times
resolve( {filename}) String get filename a shortcut points to resolve( {filename}) String get filename a shortcut points to
reverse( {list}) List reverse {list} in-place reverse( {list}) List reverse {list} in-place
round( {expr}) Float round off {expr} round( {expr}) Float round off {expr}
rpcnotify({channel}, {event}[, {args}...])
Sends a |msgpack-rpc| notification to {channel}
rpcrequest({channel}, {method}[, {args}...])
Sends a |msgpack-rpc| request to {channel}
rpcstart({prog}[, {argv}]) Spawns {prog} and opens a |msgpack-rpc| channel
rpcstop({channel}) Closes a |msgpack-rpc| {channel}
screenattr( {row}, {col}) Number attribute at screen position screenattr( {row}, {col}) Number attribute at screen position
screenchar( {row}, {col}) Number character at screen position screenchar( {row}, {col}) Number character at screen position
screencol() Number current cursor column screencol() Number current cursor column
@ -4002,6 +4012,22 @@ items({dict}) *items()*
entry and the value of this entry. The |List| is in arbitrary entry and the value of this entry. The |List| is in arbitrary
order. order.
jobsend({job}, {data}) {Nvim} *jobsend()*
Send data to {job} by writing it to the stdin of the process.
See |job-control| for more information.
jobstart({name}, {prog}[, {argv}]) {Nvim} *jobstart()*
Spawns {prog} as a job and associate it with the {name} string,
which will be used to match the "filename pattern" in
|JobActivity| events. See |job-control| for more information.
jobstop({job}) {Nvim} *jobstop()*
Stop a job created with |jobstart| by sending a `SIGTERM`
to the corresponding process. If the process doesn't exit
cleanly soon, a `SIGKILL` will be sent. When the job is
finally closed, a |JobActivity| event will trigger with
`v:job_data[0]` set to `exited`. See |job-control| for more
information.
join({list} [, {sep}]) *join()* join({list} [, {sep}]) *join()*
Join the items in {list} together into one String. Join the items in {list} together into one String.
@ -5043,6 +5069,32 @@ round({expr}) *round()*
< -5.0 < -5.0
{only available when compiled with the |+float| feature} {only available when compiled with the |+float| feature}
rpcnotify({channel}, {event}[, {args}...]) {Nvim} *rpcnotify()*
Sends {event} to {channel} via |msgpack-rpc| and returns
immediately. If {channel} is 0, the event is broadcast to all
channels. Example: >
:au VimLeave call rpcnotify(0, "leaving")
rpcrequest({channel}, {method}[, {args}...]) {Nvim} *rpcrequest()*
Sends a request to {channel} to invoke {method} via
|msgpack-rpc| and blocks until a response is received.
Example: >
:let result = rpcrequest(rpc_chan, "func", 1, 2, 3)
rpcstart({prog}[, {argv}]) {Nvim} *rpcstart()*
Spawns {prog} as a job(optionally passing the {argv} list),
and open a |msgpack-rpc| channel with the spawned process
stdin/stdout. Returns the channel id, which is used by
|rpcrequest()|, |rpcnotify()| and |rpcstop()|
It expects the rpc channel id as argument. Example: >
:let rpc_chan = rpcstart('prog', ['arg1', 'arg2'])
rpcstop({channel}) {Nvim} *rpcstop()*
Closes a |msgpack-rpc| channel, possibly created via
|rpcspawn()| (Though it will also close channels created by
connections to |NVIM_LISTEN_ADDRESS|). It accepts the rpc
channel id as only argument.
screenattr(row, col) *screenattr()* screenattr(row, col) *screenattr()*
Like screenchar(), but return the attribute. This is a rather Like screenchar(), but return the attribute. This is a rather
arbitrary number that can only be used to compare to the arbitrary number that can only be used to compare to the
@ -8874,4 +8926,4 @@ This is not allowed when the textlock is active:
- etc. - etc.
vim:tw=78:ts=8:ft=help:norl: vim:tw=78:ts=8:noet:ft=help:norl:

101
runtime/doc/job_control.txt Normal file
View File

@ -0,0 +1,101 @@
*job_control.txt* For Nvim. {Nvim}
NVIM REFERENCE MANUAL by Thiago de Arruda
Nvim's facilities for job control *job-control*
1. Introduction |job-control-intro|
2. Usage |job-control-usage|
==============================================================================
1. Introduction *job-control-intro*
Job control is a simple way to perform multitasking in vimscript. Wikipedia
contains a more generic/detailed description:
"Job control in computing refers to the control of multiple tasks or Jobs on a
computer system, ensuring that they each have access to adequate resources to
perform correctly, that competition for limited resources does not cause a
deadlock where two or more jobs are unable to complete, resolving such
situations where they do occur, and terminating jobs that, for any reason, are
not performing as expected."
In a few words: It allows a vimscript programmer to concurrently spawn and
control multiple processes without blocking the current Nvim instance.
Nvim's job control was designed to be simple and familiar to vimscript
programmers, instead of being very powerful but complex. Unlike Vim's
facilities for calling with external commands, job control does not depend
on installed shells, calling OS functions for process management directly.
Internally, Nvim job control is powered by libuv, which has a nice
cross-platform API for managing processes. See https://github.com/joyent/libuv
for details
==============================================================================
2. Usage *job-control-usage*
Job control is achieved by calling a combination of the |jobstart()|,
|jobsend()| and |jobstop()| functions, and by listening to the |JobActivity|
event. The best way to understand is with a complete example:
>
set nocp
let job1 = jobstart('shell1', 'bash')
let job2 = jobstart('shell2', 'bash', ['-c', 'for ((i = 0; i < 10; i++)); do echo -n hello $i!; sleep 2; done'])
function JobHandler()
if v:job_data[1] == 'stdout'
let str = 'shell '. v:job_data[0].' stdout: '.v:job_data[2]
elseif v:job_data[1] == 'stderr'
let str = 'shell '.v:job_data[0].' stderr: '.v:job_data[2]
else
let str = 'shell '.v:job_data[0].' exited'
endif
call append(line('$'), str)
endfunction
au JobActivity shell* call JobHandler()
<
To test the above, copy it to the ~/jobcontrol.vim file and start with a clean
nvim instance:
>
nvim -u NONE -S ~/jobcontrol.vim
<
Here's what is happening:
- Two bash instances are spawned |jobstart()| and their stdin/stdout/stderr
are connected to nvim.
- The first shell is idle, waiting to read commands from it's stdin
- The second shell is passed the -c option to execute a command and exit. In
our case, the command is a for loop that will print numbers and exit after
a while.
- The JobHandler function is called by the JobActivity autocommand(notice how
it the shell* pattern matches the `shell1` and `shell2` names passed to
|jobstart()|), and it takes care of displaying stdout/stderr received from
the shells.
- The v:job_data is an array set by the JobActivity event. It has the
following elements:
0: The job id
1: The kind of activity: one of "stdout", "stderr" or "exit"
2: When "activity" is "stdout" or "stderr", this will contain the data read
from stdout or stderr
To send data to the job's stdin, one can use the |jobsend()| function, like
this:
>
:call jobsend(job1, 'ls\n')<cr>
:call jobsend(job1, 'invalid-command\n')<cr>
:call jobsend(job1, 'exit\n')<cr>
<
A job may be killed at any time with the |jobstop()| function:
>
:call jobstop(job1)
<
When |jobstop()| is called, it will send `SIGTERM` to the job. If a job
doesn't exit after a while, `SIGKILL` will be sent.
==============================================================================
vim:tw=78:ts=8:noet:ft=help:norl:

245
runtime/doc/msgpack_rpc.txt Normal file
View File

@ -0,0 +1,245 @@
*msgpack_rpc.txt* For Nvim. {Nvim}
NVIM REFERENCE MANUAL by Thiago de Arruda
The Msgpack-RPC Interface to Nvim *msgpack-rpc*
1. Introduction |msgpack-rpc-intro|
2. API |msgpack-rpc-api|
3. Connecting |msgpack-rpc-connecting|
4. Clients |msgpack-rpc-clients|
5. Types |msgpack-rpc-types|
6. Wrapping methods |msgpack-rpc-wrap-methods|
7. Vimscript functions |msgpack-rpc-vim-functions|
==============================================================================
1. Introduction *msgpack-rpc-intro*
The primary means of controlling a running nvim instance is through
MessagePack-RPC, a messaging protocol that uses the MessagePack serialization
format: https://github.com/msgpack/msgpack/blob/7498cf3/spec.md.
From now on, we'll be referring to the protocol as msgpack-rpc.
At this point, only plugins use msgpack-rpc, but eventually even user
interaction will be achieved through the protocol, since user interfaces will
be separate programs that control a headless nvim instance.
This is what can be achieved by connecting to the msgpack-rpc interface:
- Call any nvim API function
- Listen for nvim events
- Receive remote calls from nvim
Nvim's msgpack-rpc interface can be seen as a more powerful version of Vim's
`clientserver` feature.
==============================================================================
2. API *msgpack-rpc-api*
Nvim C API is automatically exposed to the msgpack-rpc interface by the
build system, which parses headers at src/nvim/api from the project root. A
dispatch function is generated, and it will match msgpack-rpc method names
with non-static API functions, converting/validating arguments and return
values back to msgpack.
Client libraries will normally provide wrappers that hide msgpack-rpc details
from programmers, which can be automatically generated by reading bundled api
metadata from a compiled nvim instance.
There are two ways to obtain API metadata:
- By connecting to a running nvim instance and calling `vim_get_api_metadata`
via msgpack-rpc. This is the preferred way for clients written in
dynamically-typed languages, which can define functions at runtime.
- Through the `--api-info` command-line option, which makes nvim to dump a
msgpack blob containing the metadata to stdout and exit. This is preferred
when writing clients for statically-typed languages, which require a
separate compilation step.
Here's a simple way to get human-readable description of the API(requires
python and the pyyaml/msgpack-python pip packages):
>
nvim --api-info | python -c 'import msgpack, sys, yaml; print yaml.dump(msgpack.unpackb(sys.stdin.read()))' > api.yaml
==============================================================================
3. Connecting *msgpack-rpc-connecting*
There are four ways to open msgpack-rpc streams to nvim:
1. Through nvim's stdin/stdout when started with the `--embed` option. This
how other programs can embed nvim.
2. Through stdin/stdout of a program spawned by the |rpcstart()| function.
3. Through the socket automatically created with every instance. To find out
the socket location(which is random by default) from a running nvim
instance, one can inspect the *$NVIM_LISTEN_ADDRESS* environment variable
like this:
>
:echo $NVIM_LISTEN_ADDRESS
<
4. Through a tcp/ip socket. To make nvim listen on a tcp/ip socket, you need
to set the NVIM_LISTEN_ADDRESS environment variable before starting, like
this:
>
NVIM_LISTEN_ADDRESS=127.0.0.1:6666 nvim
<
Connecting to the socket is the easiest way a programmer can test the API,
which can be done through any msgpack-rpc client library or a fully-featured
Nvim client(which we'll see below). Here's a ruby script that will print the
string 'hello world!' on the current nvim instance:
>
#!/usr/bin/env ruby
# Requires msgpack-rpc: gem install msgpack-rpc
#
# To run this script, execute it from a running nvim instance(notice the
# trailing '&' which is required since nvim won't process events while
# running a blocking command):
#
# :!./hello.rb &
#
# Or from another shell by setting NVIM_LISTEN_ADDRESS:
# $ NVIM_LISTEN_ADDRESS=[address] ./hello.rb
require 'msgpack/rpc'
require 'msgpack/rpc/transport/unix'
vim = MessagePack::RPC::Client.new(MessagePack::RPC::UNIXTransport.new, ENV['NVIM_LISTEN_ADDRESS'])
result = vim.call(:vim_command, 'echo "hello world!"')
<
A better way is to use the python REPL with the `neovim` package, where API
functions can be called interactively:
>
>>> import neovim; vim = neovim.connect('[address]')
>>> vim.command('echo "hello world!"')
<
==============================================================================
4. Implementing new clients *msgpack-rpc-clients*
Nvim is still alpha and there's no in-depth documentation explaining how to
properly implement a client library. The python client(neovim pip package)
will be always up-to-date with the latest API changes, so it's source code is
best documentation currently available. There are some guidelines however:
- Separate the transport layer from the rest of the library(See
|msgpack-rpc-connecting| for details of how a client can connect to nvim).
- Use a msgpack library that implements the spec version 5, Nvim uses the
BIN/EXT types.
- Read api metadata in order to create client-side wrappers for all
msgpack-rpc methods.
- Use a single-threaded event loop library/pattern.
- Use a fiber/coroutine library for the language you are implementing a client
for. These greatly simplify concurrency and allow the library to expose a
blocking API on top of a non-blocking event loop without the complexity
that comes with preemptive multi-tasking.
- Don't assume anything about the order that responses to msgpack-rpc requests
will arrive.
- Clients should expect to receive msgpack-rpc requests, which need to be
handled immediately since Nvim is blocked while waiting for the client
response.
- Clients should expect to receive msgpack-rpc notifications, but these don't
need to be handled immediately because they won't block Nvim(Though you
probably want to handle them immediately anyway).
Most of the complexity could be handled by a msgpack-rpc library that supports
server->client requests and notifications, but it's not clear if this is part
of the msgpack-rpc spec. At least the ruby msgpack-rpc library does not seem
to support it:
https://github.com/msgpack-rpc/msgpack-rpc-ruby/blob/master/lib/msgpack/rpc/transport/tcp.rb#L150-L158
==============================================================================
5. Types *msgpack-rpc-types*
Nvim's C API uses custom types for all functions(some are just typedefs
around C99 standard types). The types can be split into two groups:
- Basic types that map natively to msgpack(and probably have a default
representation in msgpack-supported programming languages)
- Special Nvim types that map to msgpack ext with custom type codes.
Basic type mapping:
Nil -> msgpack nil
Boolean -> msgpack boolean
Integer (signed 64-bit integer) -> msgpack integer
Float (IEEE 754 double precision) -> msgpack float
String -> msgpack binary
Array -> msgpack array
Dictionary -> msgpack map
Special Nvim types that use msgpack ext:
Buffer -> enum value kObjectTypeBuffer
Window -> enum value kObjectTypeWindow
Tabpage -> enum value kObjectTypeTabpage
The most reliable way of determining the type codes for the special nvim types
is at runtime by inspecting the `types` key of metadata dictionary returned by
`vim_get_api_metadata` method. Here's an example json representation of the
`types` object:
>
"types": {
"Buffer": {
"id": 0
},
"Window": {
"id": 1
},
"Tabpage": {
"id": 2
}
}
<
Even for statically compiled clients, it's a good practice to avoid hardcoding
the type codes, because a client may build for a Nvim version and connect to
another that may have different type codes.
==============================================================================
6. Wrapping methods *msgpack-rpc-wrap-methods*
As mentioned before, clients should provide an API that hides msgpack-rpc
details from programmers, and the API metadata object contains information
that makes this task easier:
- The "functions" key contains a list of metadata objects for individual
functions.
- Each function metadata object has type information about the return value
and parameters. These can be used for generating strongly-typed APIs in
static languages.
- Container types may be decorated with type/size constraints, eg:
ArrayOf(Buffer) or ArrayOf(Integer, 2). This can be useful to generate even
more strongly-typed APIs.
- Methods that operate instances of Nvim's types are prefixed with the type
name in lower case. Eg: `buffer_get_line` represents the `get_line` method
of a Buffer instance.
- Global methods are prefixed with `vim`. Eg: `vim_list_buffers`
So, for a object-oriented language, a client library would have the classes
that represent Nvim's types, and the methods of each class could be defined
by inspecting the method name prefix. There could also be a singleton Vim
class with methods mapped to functions prefixed with `vim_`
==============================================================================
7. Vimscript functions *msgpack-rpc-vim-functions*
Four functions related to msgpack-rpc are available to vimscript:
- |rpcstart()|: Similarly to |jobstart()|, this will spawn a co-process with
it's standard handles connected to Nvim, the difference is that it's not
possible to process raw data to/from the process stdin/stdout/stderr(Since
the job's stdin/stdout combo are used as a msgpack channgel that is
processed directly by Nvim C code).
- |rpcstop()|: Same as |jobstop()|, but operates on handles returned by
|rpcstart().|
- |rpcrequest()|: Sends a msgpack-rpc request to the process.
- |rpcnotify()|: Sends a msgpack-rpc notification to the process.
The last two functions may also be used with channels created from
connections to |NVIM_LISTEN_ADDRESS|.
==============================================================================
vim:tw=78:ts=8:noet:ft=help:norl:

View File

@ -0,0 +1,47 @@
*nvim_clipboard.txt* For Nvim. {Nvim}
NVIM REFERENCE MANUAL by Thiago de Arruda
Clipboard integration for Nvim *nvim-clipboard*
By default, Nvim has no connection to the system clipboard. Eventually that
will be implemented by UI programs, which connect to Nvim via |msgpack-rpc|.
Even though externalized UIs are not available yet, there's a workaround that
enables clipboard usage through the python interface(which also uses
|msgpack-rpc| and consequently can implement the clipboard methods required
by Nvim):
- Make sure you follow the setup instructions in |nvim-python-quickstart|.
- Install the `xerox` python module:
>
$ pip install xerox
<
- Create a ~/.vim/pythonx/nvim_clipboard.py file with the following contents:
>
import xerox
class NvimClipboard(object):
def __init__(self, vim):
self.provides = ['clipboard']
def clipboard_get(self):
return xerox.paste().split('\n')
def clipboard_set(self, lines):
xerox.copy(u'\n'.join([line.decode('utf-8') for line in lines]))
<
This should enable the '+' and '*' registers. As an optional step, set the
'unnamedclip' option to transparently access clipboard using the unnamed
register. If you use the same |vimrc| for both Vim and Nvim, make sure you
only set the option when `has('neovim')` is true:
>
if has('neovim')
set unnamedclip
endif
<
==============================================================================
vim:tw=78:ts=8:noet:ft=help:norl:

View File

@ -0,0 +1,22 @@
*nvim_intro.txt* For Nvim. {Nvim}
NVIM REFERENCE MANUAL by Thiago de Arruda
Introduction to Nvim *nvim-intro*
This is an introduction new Nvim users. It is meant for experienced Vim users
that want to get started with Nvim. For a basic introduction to Vim, see
|help.txt|.
For now, it is just an index with the most relevant topics/features that
differentiate Nvim from Vim:
1. Msgpack-RPC |msgpack-rpc|
2. Job control |job-control|
3. Python plugins |nvim-python|
4. Clipboard integration |nvim-clipboard|
==============================================================================
vim:tw=78:ts=8:noet:ft=help:norl:

View File

@ -0,0 +1,40 @@
*nvim_python.txt* For Nvim. {Nvim}
NVIM REFERENCE MANUAL by Thiago de Arruda
Python plugins and scripting in Nvim *nvim-python*
1. Introduction |nvim-python-intro|
2. Quickstart |nvim-python-quickstart|
==============================================================================
1. Introduction *nvim-python-intro*
Through an external python interpreter connected via |msgpack-rpc|, Nvim
offers some support for the classic |python-vim| interface. For now only the
old Vim 7.3 API is supported.
==============================================================================
2. Quickstart *nvim-python-quickstart*
If you just want to start using python plugins with Nvim quickly, here's a
simple step-by-step:
- Make sure python 2.6 or 2.7 is available on your `$PATH`
- Install the `neovim` python package:
>
$ pip install neovim
<
- Add the following snippet to your `vimrc`, before any python plugins are
loaded:
>
if has('neovim')
runtime! plugin/python_setup.vim
endif
<
Most python plugins created for Vim 7.3 should work after these steps.
==============================================================================
vim:tw=78:ts=8:noet:ft=help:norl:

View File

@ -7647,6 +7647,13 @@ A jump table for the options with a short description can be found at |Q_op|.
Note that this causes the whole buffer to be stored in memory. Set Note that this causes the whole buffer to be stored in memory. Set
this option to a lower value if you run out of memory. this option to a lower value if you run out of memory.
{Nvim} *'unnamedclip'* *ucp'*
'unnamedclip' 'ucp' boolean (default off)
global
Use the unnamed register to access the clipboard(when available).
This option has the same effect of setting 'clipboard' to
'unnamed/unnamedplus' in Vim.
*'updatecount'* *'uc'* *'updatecount'* *'uc'*
'updatecount' 'uc' number (default: 200) 'updatecount' 'uc' number (default: 200)
global global
@ -8311,4 +8318,4 @@ A jump table for the options with a short description can be found at |Q_op|.
screen. When non-zero, characters are sent to the terminal one by screen. When non-zero, characters are sent to the terminal one by
one. For MS-DOS pcterm this does not work. For debugging purposes. one. For MS-DOS pcterm this does not work. For debugging purposes.
vim:tw=78:ts=8:ft=help:norl: vim:tw=78:ts=8:ft=help:noet:norl:

View File

@ -6,18 +6,21 @@ let did_python_setup = 1
let s:get_version = let s:get_version =
\ ' -c "import sys; sys.stdout.write(str(sys.version_info.major))"' \ ' -c "import sys; sys.stdout.write(str(sys.version_info.major) + '.
\ '\".\" + str(sys.version_info.minor))"'
let s:supported = ['2.6', '2.7']
" To load the python host a python 2 executable must be available " To load the python host a python 2 executable must be available
if exists('python_interpreter') if exists('python_interpreter')
\ && executable(g:python_interpreter) \ && executable(g:python_interpreter)
\ && system(g:python_interpreter.s:get_version) == "2" \ && index(s:supported, system(g:python_interpreter.s:get_version)) >= 0
let s:python_interpreter = g:python_interpreter let s:python_interpreter = g:python_interpreter
elseif executable('python') && elseif executable('python')
\ system('python'.s:get_version) == "2" \ && index(s:supported, system('python'.s:get_version)) >= 0
let s:python_interpreter = 'python' let s:python_interpreter = 'python'
elseif executable('python2') && elseif executable('python2')
\ system('python2'.s:get_version) == "2" \ && index(s:supported, system('python2'.s:get_version)) >= 0
" In some distros, python3 is the default python " In some distros, python3 is the default python
let s:python_interpreter = 'python2' let s:python_interpreter = 'python2'
else else
@ -33,12 +36,12 @@ if s:import_result != 'ok'
finish finish
endif endif
let s:pyhost_id = api_spawn(s:python_interpreter, let s:pyhost_id = rpcstart(s:python_interpreter,
\ ['-c', 'import neovim; neovim.start_host()']) \ ['-c', 'import neovim; neovim.start_host()'])
" Evaluate an expression in the script host as an additional sanity check, and " Evaluate an expression in the script host as an additional sanity check, and
" to block until all providers have been registered(or else some plugins loaded " to block until all providers have been registered(or else some plugins loaded
" by the user's vimrc would not get has('python') == 1 " by the user's vimrc would not get has('python') == 1
if send_call(s:pyhost_id, 'python_eval', '"o" + "k"') != 'ok' || !has('python') if rpcrequest(s:pyhost_id, 'python_eval', '"o"+"k"') != 'ok' || !has('python')
" Something went wrong " Something went wrong
api_close(s:pyhost_id) rpcstop(s:pyhost_id)
endif endif

View File

@ -42,6 +42,8 @@ syn match helpNormal "|||"
syn match helpNormal ":|vim:|" " for :help modeline syn match helpNormal ":|vim:|" " for :help modeline
syn match helpVim "\<Vim version [0-9][0-9.a-z]*" syn match helpVim "\<Vim version [0-9][0-9.a-z]*"
syn match helpVim "VIM REFERENCE.*" syn match helpVim "VIM REFERENCE.*"
syn match helpVim "\<Nvim\."
syn match helpVim "NVIM REFERENCE.*"
syn match helpOption "'[a-z]\{2,\}'" syn match helpOption "'[a-z]\{2,\}'"
syn match helpOption "'t_..'" syn match helpOption "'t_..'"
syn match helpCommand "`[^` \t]\+`"hs=s+1,he=e-1 contains=helpBacktick syn match helpCommand "`[^` \t]\+`"hs=s+1,he=e-1 contains=helpBacktick

View File

@ -33,7 +33,7 @@ syn keyword vimOption contained akm anti arshape awa backupskip bex bioskey brow
syn keyword vimOption contained al antialias autochdir background balloondelay bexpr bk bs casemap cf cink cmdheight colorcolumn completefunc copyindent cryptmethod cscopeverbose csverb debug dict dir eb enc errorbells expandtab fdl fenc fileencodings fkmap foldenable foldminlines formatprg gdefault gp guifontset helpfile hidden hl ignorecase imcmdline imsf indentexpr is isp keywordprg lazyredraw lispwords ls makeef maxmapdepth mfd mmd modified mousemodel msm numberwidth operatorfunc pastetoggle pexpr pmbfn printexpr pt re restorescreen rnu rulerformat scr sect sft shellredir shiftwidth showmatch siso smc spc spl ss statusline suffixesadd sws tabline tags tbs textmode timeoutlen to tsl ttyfast uc undoreload vdir viewoptions warn wfh wig wildmode winfixwidth wiw wrap writedelay syn keyword vimOption contained al antialias autochdir background balloondelay bexpr bk bs casemap cf cink cmdheight colorcolumn completefunc copyindent cryptmethod cscopeverbose csverb debug dict dir eb enc errorbells expandtab fdl fenc fileencodings fkmap foldenable foldminlines formatprg gdefault gp guifontset helpfile hidden hl ignorecase imcmdline imsf indentexpr is isp keywordprg lazyredraw lispwords ls makeef maxmapdepth mfd mmd modified mousemodel msm numberwidth operatorfunc pastetoggle pexpr pmbfn printexpr pt re restorescreen rnu rulerformat scr sect sft shellredir shiftwidth showmatch siso smc spc spl ss statusline suffixesadd sws tabline tags tbs textmode timeoutlen to tsl ttyfast uc undoreload vdir viewoptions warn wfh wig wildmode winfixwidth wiw wrap writedelay
syn keyword vimOption contained aleph ar autoindent backspace ballooneval bg bkc bsdir cb cfu cinkeys cmdwinheight columns completeopt cot cscopepathcomp cspc cuc deco dictionary directory ed encoding errorfile exrc fdls fencs fileformat flp foldexpr foldnestmax fp gfm grepformat guifontwide helpheight highlight hlg im imd imstatusfunc indentkeys isf isprint km lbr list lsp makeprg maxmem mh mmp more mouses mzq nuw opfunc patchexpr pfn popt printfont pumheight readonly revins ro runtimepath scroll sections sh shellslash shm showmode sj smd spell splitbelow ssl stl sw sxe tabpagemax tagstack tenc textwidth title toolbar tsr ttym udf updatecount ve viminfo wb wfw wildchar wildoptions winheight wm wrapmargin ws syn keyword vimOption contained aleph ar autoindent backspace ballooneval bg bkc bsdir cb cfu cinkeys cmdwinheight columns completeopt cot cscopepathcomp cspc cuc deco dictionary directory ed encoding errorfile exrc fdls fencs fileformat flp foldexpr foldnestmax fp gfm grepformat guifontwide helpheight highlight hlg im imd imstatusfunc indentkeys isf isprint km lbr list lsp makeprg maxmem mh mmp more mouses mzq nuw opfunc patchexpr pfn popt printfont pumheight readonly revins ro runtimepath scroll sections sh shellslash shm showmode sj smd spell splitbelow ssl stl sw sxe tabpagemax tagstack tenc textwidth title toolbar tsr ttym udf updatecount ve viminfo wb wfw wildchar wildoptions winheight wm wrapmargin ws
syn keyword vimOption contained allowrevins arab autoread backup balloonexpr bh bl bsk cc ch cino cmp com concealcursor cp cscopeprg csprg cul def diff display edcompatible endofline errorformat fcl fdm fex fileformats fml foldignore foldopen fs gfn grepprg guiheadroom helplang history hls imactivatefunc imdisable inc indk isfname joinspaces kmp lcs listchars lw mat maxmempattern mis mmt mouse mouseshape mzquantum odev osfiletype patchmode ph preserveindent printheader pvh redrawtime ri rs sb scrollbind secure shcf shelltemp shortmess showtabline slm sn spellcapcheck splitright ssop stmp swapfile sxq tabstop tal term tf titlelen toolbariconsize ttimeout ttymouse udir updatetime verbose virtualedit wc wh wildcharm wim winminheight wmh wrapscan ww syn keyword vimOption contained allowrevins arab autoread backup balloonexpr bh bl bsk cc ch cino cmp com concealcursor cp cscopeprg csprg cul def diff display edcompatible endofline errorformat fcl fdm fex fileformats fml foldignore foldopen fs gfn grepprg guiheadroom helplang history hls imactivatefunc imdisable inc indk isfname joinspaces kmp lcs listchars lw mat maxmempattern mis mmt mouse mouseshape mzquantum odev osfiletype patchmode ph preserveindent printheader pvh redrawtime ri rs sb scrollbind secure shcf shelltemp shortmess showtabline slm sn spellcapcheck splitright ssop stmp swapfile sxq tabstop tal term tf titlelen toolbariconsize ttimeout ttymouse udir updatetime verbose virtualedit wc wh wildcharm wim winminheight wmh wrapscan ww
syn keyword vimOption contained altkeymap arabic autowrite backupcopy bdir bin bomb bt ccv charconvert cinoptions cms comments conceallevel cpo cscopequickfix csqf cursorbind define diffexpr dy ef eol esckeys fcs fdn ff fileignorecase fmr foldlevel foldtext fsync gfs gtl guioptions hf hk hlsearch imactivatekey imi include inex isi js kp linebreak lm lz matchpairs maxmemtot mkspellmem mod mousef mouset nf oft pa path pheader previewheight printmbcharset pvw regexpengine rightleft rtp sbo scrolljump sel shell shelltype shortname shq sm so spellfile spr st sts swapsync syn tag tb termbidi tgst titleold top ttimeoutlen ttyscroll ul ur verbosefile visualbell syn keyword vimOption contained altkeymap arabic autowrite backupcopy bdir bin bomb bt ccv charconvert cinoptions cms comments conceallevel cpo cscopequickfix csqf cursorbind define diffexpr dy ef eol esckeys fcs fdn ff fileignorecase fmr foldlevel foldtext fsync gfs gtl guioptions hf hk hlsearch imactivatekey imi include inex isi js kp linebreak lm lz matchpairs maxmemtot mkspellmem mod mousef mouset nf oft pa path pheader previewheight printmbcharset pvw regexpengine rightleft rtp sbo scrolljump sel shell shelltype shortname shq sm so spellfile spr st sts swapsync syn tag tb termbidi tgst titleold top ttimeoutlen ttyscroll ul ur unnamedclip unc verbosefile visualbell
" vimOptions: These are the turn-off setting variants {{{2 " vimOptions: These are the turn-off setting variants {{{2
syn keyword vimOption contained noacd noallowrevins noantialias noarabic noarshape noautoread noaw noballooneval nobinary nobk nobuflisted nocin noconfirm nocopyindent nocscoperelative nocsre nocuc nocursorcolumn nodelcombine nodigraph noed noendofline noerrorbells noex nofen nofk nogd nohid nohkmap nohkp nohlsearch noicon noim noimcmdline noimdisable noinf noinsertmode nojoinspaces nolazyredraw nolinebreak nolist nolpl noma nomagic noml nomodeline nomodified nomousef nomousehide nonumber noopendevice nopi nopreviewwindow nopvw norelativenumber norestorescreen nori norl noro noru nosb noscb noscs nosft noshelltemp noshortname noshowfulltag noshowmode nosm nosmartindent nosmd nosol nosplitbelow nospr nossl nostartofline noswapfile nota notagrelative notbi notbs noterse notextmode notgst notimeout noto notr nottybuiltin notx noundofile novisualbell nowarn noweirdinvert nowfw nowildignorecase nowinfixheight nowiv nowrap nowrite nowritebackup syn keyword vimOption contained noacd noallowrevins noantialias noarabic noarshape noautoread noaw noballooneval nobinary nobk nobuflisted nocin noconfirm nocopyindent nocscoperelative nocsre nocuc nocursorcolumn nodelcombine nodigraph noed noendofline noerrorbells noex nofen nofk nogd nohid nohkmap nohkp nohlsearch noicon noim noimcmdline noimdisable noinf noinsertmode nojoinspaces nolazyredraw nolinebreak nolist nolpl noma nomagic noml nomodeline nomodified nomousef nomousehide nonumber noopendevice nopi nopreviewwindow nopvw norelativenumber norestorescreen nori norl noro noru nosb noscb noscs nosft noshelltemp noshortname noshowfulltag noshowmode nosm nosmartindent nosmd nosol nosplitbelow nospr nossl nostartofline noswapfile nota notagrelative notbi notbs noterse notextmode notgst notimeout noto notr nottybuiltin notx noundofile novisualbell nowarn noweirdinvert nowfw nowildignorecase nowinfixheight nowiv nowrap nowrite nowritebackup
@ -62,7 +62,7 @@ syn keyword vimErrSetting contained hardtabs ht w1200 w300 w9600
" AutoCmd Events {{{2 " AutoCmd Events {{{2
syn case ignore syn case ignore
syn keyword vimAutoEvent contained BufAdd BufCreate BufDelete BufEnter BufFilePost BufFilePre BufHidden BufLeave BufNew BufNewFile BufRead BufReadCmd BufReadPost BufReadPre BufUnload BufWinEnter BufWinLeave BufWipeout BufWrite BufWriteCmd BufWritePost BufWritePre Cmd-event CmdwinEnter CmdwinLeave ColorScheme CompleteDone CursorHold CursorHoldI CursorMoved CursorMovedI EncodingChanged FileAppendCmd FileAppendPost FileAppendPre FileChangedRO FileChangedShell FileChangedShellPost FileEncoding FileReadCmd FileReadPost FileReadPre FileType FileWriteCmd FileWritePost FileWritePre FilterReadPost FilterReadPre FilterWritePost FilterWritePre FocusGained FocusLost FuncUndefined GUIEnter GUIFailed InsertChange InsertCharPre InsertEnter InsertLeave MenuPopup QuickFixCmdPost QuickFixCmdPre QuitPre RemoteReply SessionLoadPost ShellCmdPost ShellFilterPost SourceCmd SourcePre SpellFileMissing StdinReadPost StdinReadPre SwapExists Syntax TabEnter TabLeave TermChanged TermResponse TextChanged TextChangedI User UserGettingBored VimEnter VimLeave VimLeavePre VimResized WinEnter WinLeave syn keyword vimAutoEvent contained BufAdd BufCreate BufDelete BufEnter BufFilePost BufFilePre BufHidden BufLeave BufNew BufNewFile BufRead BufReadCmd BufReadPost BufReadPre BufUnload BufWinEnter BufWinLeave BufWipeout BufWrite BufWriteCmd BufWritePost BufWritePre Cmd-event CmdwinEnter CmdwinLeave ColorScheme CompleteDone CursorHold CursorHoldI CursorMoved CursorMovedI EncodingChanged FileAppendCmd FileAppendPost FileAppendPre FileChangedRO FileChangedShell FileChangedShellPost FileEncoding FileReadCmd FileReadPost FileReadPre FileType FileWriteCmd FileWritePost FileWritePre FilterReadPost FilterReadPre FilterWritePost FilterWritePre FocusGained FocusLost FuncUndefined GUIEnter GUIFailed InsertChange InsertCharPre InsertEnter InsertLeave JobActivity MenuPopup QuickFixCmdPost QuickFixCmdPre QuitPre RemoteReply SessionLoadPost ShellCmdPost ShellFilterPost SourceCmd SourcePre SpellFileMissing StdinReadPost StdinReadPre SwapExists Syntax TabEnter TabLeave TermChanged TermResponse TextChanged TextChangedI User UserGettingBored VimEnter VimLeave VimLeavePre VimResized WinEnter WinLeave
" Highlight commonly used Groupnames {{{2 " Highlight commonly used Groupnames {{{2
syn keyword vimGroup contained Comment Constant String Character Number Boolean Float Identifier Function Statement Conditional Repeat Label Operator Keyword Exception PreProc Include Define Macro PreCondit Type StorageClass Structure Typedef Special SpecialChar Tag Delimiter SpecialComment Debug Underlined Ignore Error Todo syn keyword vimGroup contained Comment Constant String Character Number Boolean Float Identifier Function Statement Conditional Repeat Label Operator Keyword Exception PreProc Include Define Macro PreCondit Type StorageClass Structure Typedef Special SpecialChar Tag Delimiter SpecialComment Debug Underlined Ignore Error Todo
@ -75,7 +75,7 @@ syn case match
" Function Names {{{2 " Function Names {{{2
syn keyword vimFuncName contained abs and argidx atan browsedir bufloaded bufwinnr byteidxcomp changenr clearmatches complete_add copy count deepcopy diff_filler escape executable expand feedkeys filter float2nr fnameescape foldclosedend foldtextresult garbagecollect getbufvar getcmdline getcwd getfsize getline getpid getreg gettabwinvar getwinvar has hasmapto histget hlID indent inputdialog inputsave invert items len line localtime luaeval mapcheck matcharg matchlist min mzeval or prevnonblank py3eval readfile remote_expr remote_read rename reverse screenchar search searchpairpos serverlist setcmdpos setloclist setpos setreg settabwinvar sha256 shiftwidth sin sort spellbadword split str2float strchars strftime string strpart strtrans submatch synconcealed synIDattr synstack tabpagebuflist tabpagewinnr taglist tanh tolower tr type undotree virtcol wildmenumode wincol winline winrestcmd winsaveview writefile syn keyword vimFuncName contained abs and argidx atan browsedir bufloaded bufwinnr byteidxcomp changenr clearmatches complete_add copy count deepcopy diff_filler escape executable expand feedkeys filter float2nr fnameescape foldclosedend foldtextresult garbagecollect getbufvar getcmdline getcwd getfsize getline getpid getreg gettabwinvar getwinvar has hasmapto histget hlID indent inputdialog inputsave invert items len line localtime luaeval mapcheck matcharg matchlist min mzeval or prevnonblank py3eval readfile remote_expr remote_read rename reverse screenchar search searchpairpos serverlist setcmdpos setloclist setpos setreg settabwinvar sha256 shiftwidth sin sort spellbadword split str2float strchars strftime string strpart strtrans submatch synconcealed synIDattr synstack tabpagebuflist tabpagewinnr taglist tanh tolower tr type undotree virtcol wildmenumode wincol winline winrestcmd winsaveview writefile
syn keyword vimFuncName contained acos append argv atan2 bufexists bufname byte2line call char2nr col complete_check cos cscope_connection delete diff_hlID eval exists expr8 filereadable finddir floor fnamemodify foldlevel foreground get getchar getcmdpos getfontname getftime getloclist getpos getregtype getwinposx glob has_key histadd histnr hostname index inputlist inputsecret isdirectory join libcall line2byte log map match matchdelete matchstr mkdir nextnonblank pathshorten printf pyeval reltime remote_foreground remote_send repeat round screencol searchdecl searchpos setbufvar setline setmatches setqflist settabvar setwinvar shellescape simplify sinh soundfold spellsuggest sqrt str2nr strdisplaywidth stridx strlen strridx strwidth substitute synID synIDtrans system tabpagenr tagfiles tan tempname toupper trunc undofile values visualmode winbufnr winheight winnr winrestview winwidth xor syn keyword vimFuncName contained acos append argv atan2 bufexists bufname byte2line call char2nr col complete_check cos cscope_connection delete diff_hlID eval exists expr8 filereadable finddir floor fnamemodify foldlevel foreground get getchar getcmdpos getfontname getftime getloclist getpos getregtype getwinposx glob has_key histadd histnr hostname index inputlist inputsecret isdirectory join libcall line2byte log map match matchdelete matchstr mkdir nextnonblank pathshorten printf pyeval reltime remote_foreground remote_send repeat round screencol searchdecl searchpos setbufvar setline setmatches setqflist settabvar setwinvar shellescape simplify sinh soundfold spellsuggest sqrt str2nr strdisplaywidth stridx strlen strridx strwidth substitute synID synIDtrans system tabpagenr tagfiles tan tempname toupper trunc undofile values visualmode winbufnr winheight winnr winrestview winwidth xor
syn keyword vimFuncName contained add argc asin browse buflisted bufnr byteidx ceil cindent complete confirm cosh cursor did_filetype empty eventhandler exp extend filewritable findfile fmod foldclosed foldtext function getbufline getcharmod getcmdtype getfperm getftype getmatches getqflist gettabvar getwinposy globpath haslocaldir histdel hlexists iconv input inputrestore insert islocked keys libcallnr lispindent log10 maparg matchadd matchend max mode nr2char pow pumvisible range reltimestr remote_peek remove resolve screenattr screenrow searchpair server2client syn keyword vimFuncName contained add argc asin browse buflisted bufnr byteidx ceil cindent complete confirm cosh cursor did_filetype empty eventhandler exp extend filewritable findfile fmod foldclosed foldtext function getbufline getcharmod getcmdtype getfperm getftype getmatches getqflist gettabvar getwinposy globpath haslocaldir histdel hlexists iconv input inputrestore insert islocked keys libcallnr lispindent log10 maparg matchadd matchend max mode nr2char pow pumvisible range reltimestr remote_peek remove resolve screenattr screenrow searchpair server2client jobsend jobstart jobstop rpcnotify rpcrequest rpcstart rpcstop
"--- syntax here and above generated by mkvimvim --- "--- syntax here and above generated by mkvimvim ---
" Special Vim Highlighting (not automatic) {{{1 " Special Vim Highlighting (not automatic) {{{1

View File

@ -11,8 +11,8 @@ set run_nvim [split [lindex $argv 1] " "]
# don't echo to stdout # don't echo to stdout
log_user 0 log_user 0
# set NEOVIM_LISTEN_ADDRESS, so nvim will listen on a known socket # set NVIM_LISTEN_ADDRESS, so nvim will listen on a known socket
set env(NEOVIM_LISTEN_ADDRESS) "/tmp/nvim-[exec date +%s%N].sock" set env(NVIM_LISTEN_ADDRESS) "/tmp/nvim-[exec date +%s%N].sock"
# start nvim # start nvim
spawn {*}$run_nvim spawn {*}$run_nvim
# save the job descriptor # save the job descriptor

View File

@ -6306,8 +6306,6 @@ static struct fst {
{"acos", 1, 1, f_acos}, /* WJMc */ {"acos", 1, 1, f_acos}, /* WJMc */
{"add", 2, 2, f_add}, {"add", 2, 2, f_add},
{"and", 2, 2, f_and}, {"and", 2, 2, f_and},
{"api_close", 1, 1, f_api_close},
{"api_spawn", 1, 2, f_api_spawn},
{"append", 2, 2, f_append}, {"append", 2, 2, f_append},
{"argc", 0, 0, f_argc}, {"argc", 0, 0, f_argc},
{"argidx", 0, 0, f_argidx}, {"argidx", 0, 0, f_argidx},
@ -6436,9 +6434,9 @@ static struct fst {
{"isdirectory", 1, 1, f_isdirectory}, {"isdirectory", 1, 1, f_isdirectory},
{"islocked", 1, 1, f_islocked}, {"islocked", 1, 1, f_islocked},
{"items", 1, 1, f_items}, {"items", 1, 1, f_items},
{"jobstart", 2, 3, f_job_start}, {"jobsend", 2, 2, f_jobsend},
{"jobstop", 1, 1, f_job_stop}, {"jobstart", 2, 3, f_jobstart},
{"jobwrite", 2, 2, f_job_write}, {"jobstop", 1, 1, f_jobstop},
{"join", 1, 2, f_join}, {"join", 1, 2, f_join},
{"keys", 1, 1, f_keys}, {"keys", 1, 1, f_keys},
{"last_buffer_nr", 0, 0, f_last_buffer_nr}, /* obsolete */ {"last_buffer_nr", 0, 0, f_last_buffer_nr}, /* obsolete */
@ -6485,6 +6483,10 @@ static struct fst {
{"resolve", 1, 1, f_resolve}, {"resolve", 1, 1, f_resolve},
{"reverse", 1, 1, f_reverse}, {"reverse", 1, 1, f_reverse},
{"round", 1, 1, f_round}, {"round", 1, 1, f_round},
{"rpcnotify", 2, 64, f_rpcnotify},
{"rpcrequest", 2, 64, f_rpcrequest},
{"rpcstart", 1, 2, f_rpcstart},
{"rpcstop", 1, 1, f_rpcstop},
{"screenattr", 2, 2, f_screenattr}, {"screenattr", 2, 2, f_screenattr},
{"screenchar", 2, 2, f_screenchar}, {"screenchar", 2, 2, f_screenchar},
{"screencol", 0, 0, f_screencol}, {"screencol", 0, 0, f_screencol},
@ -6494,8 +6496,6 @@ static struct fst {
{"searchpair", 3, 7, f_searchpair}, {"searchpair", 3, 7, f_searchpair},
{"searchpairpos", 3, 7, f_searchpairpos}, {"searchpairpos", 3, 7, f_searchpairpos},
{"searchpos", 1, 4, f_searchpos}, {"searchpos", 1, 4, f_searchpos},
{"send_call", 2, 64, f_send_call},
{"send_event", 2, 64, f_send_event},
{"setbufvar", 3, 3, f_setbufvar}, {"setbufvar", 3, 3, f_setbufvar},
{"setcmdpos", 1, 1, f_setcmdpos}, {"setcmdpos", 1, 1, f_setcmdpos},
{"setline", 2, 2, f_setline}, {"setline", 2, 2, f_setline},
@ -7055,83 +7055,6 @@ static void f_and(typval_T *argvars, typval_T *rettv)
& get_tv_number_chk(&argvars[1], NULL); & get_tv_number_chk(&argvars[1], NULL);
} }
// "api_close(prog, argv)" function
static void f_api_close(typval_T *argvars, typval_T *rettv)
{
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = 0;
if (check_restricted() || check_secure()) {
return;
}
if (argvars[0].v_type != VAR_NUMBER) {
// Wrong argument types
EMSG(_(e_invarg));
return;
}
rettv->vval.v_number = channel_close(argvars[0].vval.v_number);
}
// "api_spawn(prog, argv)" function
static void f_api_spawn(typval_T *argvars, typval_T *rettv)
{
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = 0;
if (check_restricted() || check_secure()) {
return;
}
if (argvars[0].v_type != VAR_STRING
|| (argvars[1].v_type != VAR_LIST && argvars[1].v_type != VAR_UNKNOWN)) {
// Wrong argument types
EMSG(_(e_invarg));
return;
}
list_T *args = NULL;
int argsl = 0;
if (argvars[1].v_type == VAR_LIST) {
args = argvars[1].vval.v_list;
argsl = args->lv_len;
// Assert that all list items are strings
for (listitem_T *arg = args->lv_first; arg != NULL; arg = arg->li_next) {
if (arg->li_tv.v_type != VAR_STRING) {
EMSG(_(e_invarg));
return;
}
}
}
// Allocate extra memory for the argument vector and the NULL pointer
int argvl = argsl + 2;
char **argv = xmalloc(sizeof(char_u *) * argvl);
// Copy program name
argv[0] = xstrdup((char *)argvars[0].vval.v_string);
int i = 1;
// Copy arguments to the vector
if (argsl > 0) {
for (listitem_T *arg = args->lv_first; arg != NULL; arg = arg->li_next) {
argv[i++] = xstrdup((char *)arg->li_tv.vval.v_string);
}
}
// The last item of argv must be NULL
argv[i] = NULL;
uint64_t channel_id = channel_from_job(argv);
if (!channel_id) {
EMSG(_(e_api_spawn_failed));
}
rettv->vval.v_number = (varnumber_T)channel_id;
}
/* /*
* "append(lnum, string/list)" function * "append(lnum, string/list)" function
*/ */
@ -10558,8 +10481,40 @@ static void f_items(typval_T *argvars, typval_T *rettv)
dict_list(argvars, rettv, 2); dict_list(argvars, rettv, 2);
} }
// "jobsend()" function
static void f_jobsend(typval_T *argvars, typval_T *rettv)
{
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = 0;
if (check_restricted() || check_secure()) {
return;
}
if (argvars[0].v_type != VAR_NUMBER || argvars[1].v_type != VAR_STRING) {
// First argument is the job id and second is the string to write to
// the job's stdin
EMSG(_(e_invarg));
return;
}
Job *job = job_find(argvars[0].vval.v_number);
if (!job) {
// Invalid job id
EMSG(_(e_invjob));
return;
}
WBuffer *buf = wstream_new_buffer(xstrdup((char *)argvars[1].vval.v_string),
strlen((char *)argvars[1].vval.v_string),
1,
free);
rettv->vval.v_number = job_write(job, buf);
}
// "jobstart()" function // "jobstart()" function
static void f_job_start(typval_T *argvars, typval_T *rettv) static void f_jobstart(typval_T *argvars, typval_T *rettv)
{ {
list_T *args = NULL; list_T *args = NULL;
listitem_T *arg; listitem_T *arg;
@ -10637,7 +10592,7 @@ static void f_job_start(typval_T *argvars, typval_T *rettv)
} }
// "jobstop()" function // "jobstop()" function
static void f_job_stop(typval_T *argvars, typval_T *rettv) static void f_jobstop(typval_T *argvars, typval_T *rettv)
{ {
rettv->v_type = VAR_NUMBER; rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = 0; rettv->vval.v_number = 0;
@ -10664,38 +10619,6 @@ static void f_job_stop(typval_T *argvars, typval_T *rettv)
rettv->vval.v_number = 1; rettv->vval.v_number = 1;
} }
// "jobwrite()" function
static void f_job_write(typval_T *argvars, typval_T *rettv)
{
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = 0;
if (check_restricted() || check_secure()) {
return;
}
if (argvars[0].v_type != VAR_NUMBER || argvars[1].v_type != VAR_STRING) {
// First argument is the job id and second is the string to write to
// the job's stdin
EMSG(_(e_invarg));
return;
}
Job *job = job_find(argvars[0].vval.v_number);
if (!job) {
// Invalid job id
EMSG(_(e_invjob));
return;
}
WBuffer *buf = wstream_new_buffer(xstrdup((char *)argvars[1].vval.v_string),
strlen((char *)argvars[1].vval.v_string),
1,
free);
rettv->vval.v_number = job_write(job, buf);
}
/* /*
* "join()" function * "join()" function
*/ */
@ -12420,6 +12343,169 @@ static void f_round(typval_T *argvars, typval_T *rettv)
rettv->vval.v_float = 0.0; rettv->vval.v_float = 0.0;
} }
// "rpcnotify()" function
static void f_rpcnotify(typval_T *argvars, typval_T *rettv)
{
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = 0;
if (check_restricted() || check_secure()) {
return;
}
if (argvars[0].v_type != VAR_NUMBER || argvars[0].vval.v_number < 0) {
EMSG2(_(e_invarg2), "Channel id must be a positive integer");
return;
}
if (argvars[1].v_type != VAR_STRING) {
EMSG2(_(e_invarg2), "Event type must be a string");
return;
}
Array args = ARRAY_DICT_INIT;
for (typval_T *tv = argvars + 2; tv->v_type != VAR_UNKNOWN; tv++) {
ADD(args, vim_to_object(tv));
}
if (!channel_send_event((uint64_t)argvars[0].vval.v_number,
(char *)argvars[1].vval.v_string,
args)) {
EMSG2(_(e_invarg2), "Channel doesn't exist");
return;
}
rettv->vval.v_number = 1;
}
// "rpcrequest()" function
static void f_rpcrequest(typval_T *argvars, typval_T *rettv)
{
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = 0;
if (check_restricted() || check_secure()) {
return;
}
if (argvars[0].v_type != VAR_NUMBER || argvars[0].vval.v_number <= 0) {
EMSG2(_(e_invarg2), "Channel id must be a positive integer");
return;
}
if (argvars[1].v_type != VAR_STRING) {
EMSG2(_(e_invarg2), "Method name must be a string");
return;
}
Array args = ARRAY_DICT_INIT;
for (typval_T *tv = argvars + 2; tv->v_type != VAR_UNKNOWN; tv++) {
ADD(args, vim_to_object(tv));
}
bool errored;
Object result;
if (!channel_send_call((uint64_t)argvars[0].vval.v_number,
(char *)argvars[1].vval.v_string,
args,
&result,
&errored)) {
EMSG2(_(e_invarg2), "Channel doesn't exist");
return;
}
if (errored) {
vim_report_error(result.data.string);
goto end;
}
Error conversion_error = {.set = false};
if (!object_to_vim(result, rettv, &conversion_error)) {
EMSG(_("Error converting the call result"));
}
end:
api_free_object(result);
}
// "rpcstart()" function
static void f_rpcstart(typval_T *argvars, typval_T *rettv)
{
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = 0;
if (check_restricted() || check_secure()) {
return;
}
if (argvars[0].v_type != VAR_STRING
|| (argvars[1].v_type != VAR_LIST && argvars[1].v_type != VAR_UNKNOWN)) {
// Wrong argument types
EMSG(_(e_invarg));
return;
}
list_T *args = NULL;
int argsl = 0;
if (argvars[1].v_type == VAR_LIST) {
args = argvars[1].vval.v_list;
argsl = args->lv_len;
// Assert that all list items are strings
for (listitem_T *arg = args->lv_first; arg != NULL; arg = arg->li_next) {
if (arg->li_tv.v_type != VAR_STRING) {
EMSG(_(e_invarg));
return;
}
}
}
// Allocate extra memory for the argument vector and the NULL pointer
int argvl = argsl + 2;
char **argv = xmalloc(sizeof(char_u *) * argvl);
// Copy program name
argv[0] = xstrdup((char *)argvars[0].vval.v_string);
int i = 1;
// Copy arguments to the vector
if (argsl > 0) {
for (listitem_T *arg = args->lv_first; arg != NULL; arg = arg->li_next) {
argv[i++] = xstrdup((char *)arg->li_tv.vval.v_string);
}
}
// The last item of argv must be NULL
argv[i] = NULL;
uint64_t channel_id = channel_from_job(argv);
if (!channel_id) {
EMSG(_(e_api_spawn_failed));
}
rettv->vval.v_number = (varnumber_T)channel_id;
}
// "rpcstop()" function
static void f_rpcstop(typval_T *argvars, typval_T *rettv)
{
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = 0;
if (check_restricted() || check_secure()) {
return;
}
if (argvars[0].v_type != VAR_NUMBER) {
// Wrong argument types
EMSG(_(e_invarg));
return;
}
rettv->vval.v_number = channel_close(argvars[0].vval.v_number);
}
/* /*
* "screenattr()" function * "screenattr()" function
*/ */
@ -12759,93 +12845,6 @@ do_searchpair (
return retval; return retval;
} }
// "send_call()" function
static void f_send_call(typval_T *argvars, typval_T *rettv)
{
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = 0;
if (check_restricted() || check_secure()) {
return;
}
if (argvars[0].v_type != VAR_NUMBER || argvars[0].vval.v_number <= 0) {
EMSG2(_(e_invarg2), "Channel id must be a positive integer");
return;
}
if (argvars[1].v_type != VAR_STRING) {
EMSG2(_(e_invarg2), "Method name must be a string");
return;
}
Array args = ARRAY_DICT_INIT;
for (typval_T *tv = argvars + 2; tv->v_type != VAR_UNKNOWN; tv++) {
ADD(args, vim_to_object(tv));
}
bool errored;
Object result;
if (!channel_send_call((uint64_t)argvars[0].vval.v_number,
(char *)argvars[1].vval.v_string,
args,
&result,
&errored)) {
EMSG2(_(e_invarg2), "Channel doesn't exist");
return;
}
if (errored) {
vim_report_error(result.data.string);
goto end;
}
Error conversion_error = {.set = false};
if (!object_to_vim(result, rettv, &conversion_error)) {
EMSG(_("Error converting the call result"));
}
end:
api_free_object(result);
}
// "send_event()" function
static void f_send_event(typval_T *argvars, typval_T *rettv)
{
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = 0;
if (check_restricted() || check_secure()) {
return;
}
if (argvars[0].v_type != VAR_NUMBER || argvars[0].vval.v_number < 0) {
EMSG2(_(e_invarg2), "Channel id must be a positive integer");
return;
}
if (argvars[1].v_type != VAR_STRING) {
EMSG2(_(e_invarg2), "Event type must be a string");
return;
}
Array args = ARRAY_DICT_INIT;
for (typval_T *tv = argvars + 2; tv->v_type != VAR_UNKNOWN; tv++) {
ADD(args, vim_to_object(tv));
}
if (!channel_send_event((uint64_t)argvars[0].vval.v_number,
(char *)argvars[1].vval.v_string,
args)) {
EMSG2(_(e_invarg2), "Channel doesn't exist");
return;
}
rettv->vval.v_number = 1;
}
/* /*
* "searchpos()" function * "searchpos()" function
*/ */

View File

@ -17,6 +17,7 @@
#define MAX_CONNECTIONS 32 #define MAX_CONNECTIONS 32
#define ADDRESS_MAX_SIZE 256 #define ADDRESS_MAX_SIZE 256
#define NEOVIM_DEFAULT_TCP_PORT 7450 #define NEOVIM_DEFAULT_TCP_PORT 7450
#define LISTEN_ADDRESS_ENV_VAR "NVIM_LISTEN_ADDRESS"
typedef enum { typedef enum {
kServerTypeTcp, kServerTypeTcp,
@ -51,13 +52,13 @@ void server_init(void)
{ {
servers = pmap_new(cstr_t)(); servers = pmap_new(cstr_t)();
if (!os_getenv("NEOVIM_LISTEN_ADDRESS")) { if (!os_getenv(LISTEN_ADDRESS_ENV_VAR)) {
char *listen_address = (char *)vim_tempname(); char *listen_address = (char *)vim_tempname();
os_setenv("NEOVIM_LISTEN_ADDRESS", listen_address, 1); os_setenv(LISTEN_ADDRESS_ENV_VAR, listen_address, 1);
free(listen_address); free(listen_address);
} }
server_start((char *)os_getenv("NEOVIM_LISTEN_ADDRESS")); server_start((char *)os_getenv(LISTEN_ADDRESS_ENV_VAR));
} }
/// Teardown the server module /// Teardown the server module