Merge pull request #4934 from bfredl/api

make the API callable from vimL, rename API functions to common nvim_ prefix
This commit is contained in:
Björn Linse 2016-09-01 18:32:37 +02:00 committed by GitHub
commit c6ac4f84b1
46 changed files with 1702 additions and 1318 deletions

View File

@ -17,7 +17,7 @@ set PATH=C:\Program Files (x86)\CMake\bin\cpack.exe;%PATH%
:: Build third-party dependencies
C:\msys64\usr\bin\bash -lc "pacman --verbose --noconfirm -Su" || goto :error
C:\msys64\usr\bin\bash -lc "pacman --verbose --noconfirm --needed -S mingw-w64-%ARCH%-cmake mingw-w64-%ARCH%-perl mingw-w64-%ARCH%-python2 mingw-w64-%ARCH%-diffutils" || goto :error
C:\msys64\usr\bin\bash -lc "pacman --verbose --noconfirm --needed -S mingw-w64-%ARCH%-cmake mingw-w64-%ARCH%-perl mingw-w64-%ARCH%-python2 mingw-w64-%ARCH%-diffutils gperf" || goto :error
mkdir .deps
cd .deps
@ -28,7 +28,7 @@ cd ..
:: Build Neovim
mkdir build
cd build
cmake -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release -DBUSTED_OUTPUT_TYPE=gtest .. || goto :error
cmake -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release -DBUSTED_OUTPUT_TYPE=gtest -DGPERF_PRG="C:\msys64\usr\bin\gperf.exe" .. || goto :error
mingw32-make VERBOSE=1 || goto :error
bin\nvim --version || goto :error

View File

@ -407,6 +407,8 @@ endif()
find_program(LUACHECK_PRG luacheck)
find_program(GPERF_PRG gperf)
include(InstallHelpers)
file(GLOB MANPAGES

View File

@ -3,6 +3,7 @@ set(GENERATED_RUNTIME_DIR ${PROJECT_BINARY_DIR}/runtime)
set(GENERATED_SYN_VIM ${GENERATED_RUNTIME_DIR}/syntax/vim/generated.vim)
set(GENERATED_HELP_TAGS ${GENERATED_RUNTIME_DIR}/doc/tags)
set(GENERATED_PACKAGE_DIR ${GENERATED_RUNTIME_DIR}/pack/dist/opt)
set(FUNCS_DATA ${PROJECT_BINARY_DIR}/funcs_data.mpack)
file(MAKE_DIRECTORY ${GENERATED_RUNTIME_DIR})
file(MAKE_DIRECTORY ${GENERATED_RUNTIME_DIR}/syntax)
@ -10,13 +11,14 @@ file(MAKE_DIRECTORY ${GENERATED_RUNTIME_DIR}/syntax/vim)
add_custom_command(OUTPUT ${GENERATED_SYN_VIM}
COMMAND ${LUA_PRG} ${SYN_VIM_GENERATOR}
${PROJECT_SOURCE_DIR}/src/nvim ${GENERATED_SYN_VIM}
${PROJECT_SOURCE_DIR}/src/nvim ${GENERATED_SYN_VIM} ${FUNCS_DATA}
DEPENDS
${SYN_VIM_GENERATOR}
${PROJECT_SOURCE_DIR}/src/nvim/ex_cmds.lua
${PROJECT_SOURCE_DIR}/src/nvim/auevents.lua
${PROJECT_SOURCE_DIR}/src/nvim/options.lua
${PROJECT_SOURCE_DIR}/src/nvim/eval.c
${FUNCS_DATA}
)
if(POLICY CMP0054)

View File

@ -14,13 +14,13 @@ C API for Nvim *API* *api*
==============================================================================
1. Introduction *api-intro*
Nvim exposes a public API for external code to interact with the Nvim core. In
the present version of Nvim the API is primarily used by external processes to
interact with Nvim using the msgpack-rpc protocol, see |msgpack-rpc|. The API
will also be used from vimscript to access new Nvim core features, but this is
not implemented yet. Later on, Nvim might be embeddable in C applications as
libnvim, and the application will then control the embedded instance by
calling the C API directly.
Nvim exposes a public API for external code to interact with the Nvim core.
The API is used by external processes to interact with Nvim using the
msgpack-rpc protocol, see |msgpack-rpc|. The API is used from vimscript to
access some new Nvim core features. See |eval-api| for how api functions are
called from vimscript. Later on, Nvim might be embeddable in C applications as
libnvim, and the application will then control the embedded instance by calling
the C API directly.
==============================================================================
2. API Types *api-types*
@ -73,10 +73,10 @@ Another use case are plugins that show output in an append-only buffer, and
want to add highlights to the outputs. Highlight data cannot be preserved
on writing and loading a buffer to file, nor in undo/redo cycles.
Highlights are registered using the |buffer_add_highlight| function, see the
Highlights are registered using the |nvim_buf_add_highlight| function, see the
generated API documentation for details. If an external highlighter plugin is
adding a large number of highlights in a batch, performance can be improved by
calling |buffer_add_highlight| as an asynchronous notification, after first
calling |nvim_buf_add_highlight| as an asynchronous notification, after first
(synchronously) reqesting a source id. Here is an example using wrapper
functions in the python client:
>
@ -91,10 +91,19 @@ functions in the python client:
buf.clear_highlight(src)
<
If the highlights don't need to be deleted or updated, just pass -1 as
src_id (this is the default in python). |buffer_clear_highlight| can be used
to clear highligts from a specific source, in a specific line range or the
entire buffer by passing in the line range 0, -1 (the later is the default
src_id (this is the default in python). |nvim_buf_clear_highlight| can be used
to clear highlights from a specific source, in a specific line range or the
entire buffer by passing in the line range 0, -1 (the latter is the default
in python as used above).
An example of calling the api from vimscript: >
call nvim_buf_set_lines(0, 0, 0, v:true, ["test text"])
let src = nvim_buf_add_highlight(0, 0, "String", 1, 0, 4)
call nvim_buf_add_highlight(0, src, "Identifier", 0, 5, -1)
" later
call nvim_buf_clear_highlight(0, src, 0, -1)
>
==============================================================================
vim:tw=78:ts=8:noet:ft=help:norl:

View File

@ -2009,6 +2009,7 @@ msgpackdump({list}) List dump a list of objects to msgpack
msgpackparse({list}) List parse msgpack to a list of objects
nextnonblank({lnum}) Number line nr of non-blank line >= {lnum}
nr2char({expr}[, {utf8}]) String single char with ASCII/UTF8 value {expr}
nvim_...({args}...) any call nvim |api| functions
or({expr}, {expr}) Number bitwise OR
pathshorten({expr}) String shorten directory names in a path
pow({x}, {y}) Float {x} to the power of {y}
@ -2208,11 +2209,9 @@ and({expr}, {expr}) *and()*
Example: >
:let flag = and(bits, 0x80)
api_info() *api_info()*
Returns Dictionary of |api-metadata|.
append({lnum}, {expr}) *append()*
When {expr} is a |List|: Append each item of the |List| as a
text line below line {lnum} in the current buffer.
@ -5172,6 +5171,17 @@ nr2char({expr}[, {utf8}]) *nr2char()*
characters. nr2char(0) is a real NUL and terminates the
string, thus results in an empty string.
nvim_...({...}) *nvim_...()* *eval-api*
Call nvim |api| functions. The type checking of arguments will
be stricter than for most other builtins. For instance,
if Integer is expected, a |Number| must be passed in, a
|String| will not be autoconverted.
Buffer numbers, as returned by |bufnr()| could be used as
first argument to nvim_buf_... functions. All functions
expecting an object (buffer, window or tabpage) can
also take the numerical value 0 to indicate the current
(focused) object.
or({expr}, {expr}) *or()*
Bitwise OR on the two arguments. The arguments are converted
to a number. A List, Dict or Float argument causes an error.

View File

@ -47,7 +47,7 @@ instance.
There are three ways to obtain API metadata:
1. Connect to a running Nvim instance and call `vim_get_api_info` via
1. Connect to a running Nvim instance and call `nvim_get_api_info` via
msgpack-rpc. This is best for clients written in dynamic languages which
can define functions at runtime.
@ -105,7 +105,7 @@ Nvim instance:
require 'msgpack/rpc/transport/unix'
nvim = MessagePack::RPC::Client.new(MessagePack::RPC::UNIXTransport.new, ENV['NVIM_LISTEN_ADDRESS'])
result = nvim.call(:vim_command, 'echo "hello world!"')
result = nvim.call(:nvim_command, 'echo "hello world!"')
<
A better way is to use the Python REPL with the `neovim` package, where API
functions can be called interactively:
@ -117,9 +117,9 @@ functions can be called interactively:
You can also embed an Nvim instance via |jobstart()|, and communicate using
|rpcrequest()| and |rpcnotify()|:
>
let vim = jobstart(['nvim', '--embed'], {'rpc': v:true})
echo rpcrequest(vim, 'vim_eval', '"Hello " . "world!"')
call jobstop(vim)
let nvim = jobstart(['nvim', '--embed'], {'rpc': v:true})
echo rpcrequest(nvim, 'nvim_eval', '"Hello " . "world!"')
call jobstop(nvim)
<
==============================================================================
4. Implementing API clients *rpc-api-client* *api-client*
@ -177,15 +177,20 @@ contains information that makes this task easier (see also |rpc-types|):
- Container types may be decorated with type/size constraints, e.g.
ArrayOf(Buffer) or ArrayOf(Integer, 2). This can be useful to generate
even more strongly-typed APIs.
- Methods that operate on instances of Nvim special types (msgpack EXT) are
prefixed with the type name in lower case, e.g. `buffer_get_line`
represents the `get_line` method of a Buffer instance.
- Global methods are prefixed with `vim`, e.g. `vim_get_buffers`.
- Functions that are considered to be methods that operate on instances of
Nvim special types (msgpack EXT) will have the `"method"` attribute set to
`true`. The reciever type is the type of the first argument. The method
names are prefixed with `nvim_` plus a shortened type name, e.g.
`nvim_buf_get_lines` represents the `get_lines` method of a Buffer instance.
- Global functions have `"method"` set to `false` and are prefixed with just
`nvim_`, e.g. `nvim_get_buffers`.
So for an object-oriented language, an API client contains the classes
representing Nvim special 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_`.
defined by stripping the prefix for the type as defined in the `types` metadata
(this will always be the first two "_"-separated parts of the function name).
There could also be a singleton Vim class with methods where the `nvim_`
prefix is stripped off.
==============================================================================
5. Types *rpc-types*
@ -219,18 +224,21 @@ an integer, but not a Window or Tabpage.
The most reliable way of determining the type codes for the special Nvim types
is to inspect the `types` key of metadata dictionary returned by the
`vim_get_api_info` method at runtime. Here's a sample JSON representation of
`nvim_get_api_info` method at runtime. Here's a sample JSON representation of
the `types` object:
>
"types": {
"Buffer": {
"id": 0
"id": 0,
"prefix": "nvim_buf_"
},
"Window": {
"id": 1
"id": 1,
"prefix": "nvim_win_"
},
"Tabpage": {
"id": 2
"id": 2,
"prefix": "nvim_tabpage_"
}
}
<

View File

@ -0,0 +1,77 @@
local deprecated_aliases = {
nvim_buf_line_count="buffer_line_count",
nvim_buf_get_lines="buffer_get_lines",
nvim_buf_set_lines="buffer_set_lines",
nvim_buf_get_var="buffer_get_var",
nvim_buf_set_var="buffer_set_var",
nvim_buf_del_var="buffer_del_var",
nvim_buf_get_option="buffer_get_option",
nvim_buf_set_option="buffer_set_option",
nvim_buf_get_number="buffer_get_number",
nvim_buf_get_name="buffer_get_name",
nvim_buf_set_name="buffer_set_name",
nvim_buf_is_valid="buffer_is_valid",
nvim_buf_get_mark="buffer_get_mark",
nvim_buf_add_highlight="buffer_add_highlight",
nvim_buf_clear_highlight="buffer_clear_highlight",
nvim_tabpage_get_windows="tabpage_get_windows",
nvim_tabpage_get_var="tabpage_get_var",
nvim_tabpage_set_var="tabpage_set_var",
nvim_tabpage_del_var="tabpage_del_var",
nvim_tabpage_get_window="tabpage_get_window",
nvim_tabpage_is_valid="tabpage_is_valid",
nvim_ui_detach="ui_detach",
nvim_ui_try_resize="ui_try_resize",
nvim_command="vim_command",
nvim_feedkeys="vim_feedkeys",
nvim_input="vim_input",
nvim_replace_termcodes="vim_replace_termcodes",
nvim_command_output="vim_command_output",
nvim_eval="vim_eval",
nvim_call_function="vim_call_function",
nvim_strwidth="vim_strwidth",
nvim_list_runtime_paths="vim_list_runtime_paths",
nvim_change_directory="vim_change_directory",
nvim_get_var="vim_get_var",
nvim_set_var="vim_set_var",
nvim_del_var="vim_del_var",
nvim_get_vvar="vim_get_vvar",
nvim_get_option="vim_get_option",
nvim_set_option="vim_set_option",
nvim_out_write="vim_out_write",
nvim_err_write="vim_err_write",
nvim_report_error="vim_report_error",
nvim_get_buffers="vim_get_buffers",
nvim_get_current_buffer="vim_get_current_buffer",
nvim_set_current_buffer="vim_set_current_buffer",
nvim_get_windows="vim_get_windows",
nvim_get_current_window="vim_get_current_window",
nvim_set_current_window="vim_set_current_window",
nvim_get_tabpages="vim_get_tabpages",
nvim_get_current_tabpage="vim_get_current_tabpage",
nvim_set_current_tabpage="vim_set_current_tabpage",
nvim_set_current_line="vim_set_current_line",
nvim_get_current_line="vim_get_current_line",
nvim_del_current_line="vim_del_current_line",
nvim_subscribe="vim_subscribe",
nvim_unsubscribe="vim_unsubscribe",
nvim_name_to_color="vim_name_to_color",
nvim_get_color_map="vim_get_color_map",
nvim_get_api_info="vim_get_api_info",
nvim_win_get_buffer="window_get_buffer",
nvim_win_get_cursor="window_get_cursor",
nvim_win_set_cursor="window_set_cursor",
nvim_win_get_height="window_get_height",
nvim_win_set_height="window_set_height",
nvim_win_get_width="window_get_width",
nvim_win_set_width="window_set_width",
nvim_win_get_var="window_get_var",
nvim_win_set_var="window_set_var",
nvim_win_del_var="window_del_var",
nvim_win_get_option="window_get_option",
nvim_win_set_option="window_set_option",
nvim_win_get_position="window_get_position",
nvim_win_get_tabpage="window_get_tabpage",
nvim_win_is_valid="window_is_valid"
}
return deprecated_aliases

View File

@ -37,22 +37,28 @@ c_proto = Ct(
Cg(Cc(false), 'async') *
(fill * Cg((P('FUNC_API_ASYNC') * Cc(true)), 'async') ^ -1) *
(fill * Cg((P('FUNC_API_NOEXPORT') * Cc(true)), 'noexport') ^ -1) *
(fill * Cg((P('FUNC_API_NOEVAL') * Cc(true)), 'noeval') ^ -1) *
fill * P(';')
)
grammar = Ct((c_proto + c_comment + c_preproc + ws) ^ 1)
-- we need at least 2 arguments since the last one is the output file
assert(#arg >= 1)
-- we need at least 4 arguments since the last two are output files
assert(#arg >= 3)
functions = {}
local scriptdir = arg[1]
package.path = scriptdir .. '/?.lua;' .. package.path
-- names of all headers relative to the source root (for inclusion in the
-- generated file)
headers = {}
-- output file(dispatch function + metadata serialized with msgpack)
outputf = arg[#arg]
-- output c file(dispatch function + metadata serialized with msgpack)
outputf = arg[#arg-1]
-- output mpack file (metadata)
mpack_outputf = arg[#arg]
-- read each input file, parse and append to the api metadata
for i = 1, #arg - 1 do
for i = 2, #arg - 2 do
local full_path = arg[i]
local parts = {}
for part in string.gmatch(full_path, '[^/]+') do
@ -84,6 +90,45 @@ for i = 1, #arg - 1 do
input:close()
end
local function shallowcopy(orig)
local copy = {}
for orig_key, orig_value in pairs(orig) do
copy[orig_key] = orig_value
end
return copy
end
local function startswith(String,Start)
return string.sub(String,1,string.len(Start))==Start
end
-- Export functions under older deprecated names.
-- These will be removed eventually.
local deprecated_aliases = require("dispatch_deprecated")
for i,f in ipairs(shallowcopy(functions)) do
local ismethod = false
if startswith(f.name, "nvim_buf_") then
ismethod = true
elseif startswith(f.name, "nvim_win_") then
ismethod = true
elseif startswith(f.name, "nvim_tabpage_") then
ismethod = true
elseif not startswith(f.name, "nvim_") then
f.noeval = true
f.deprecated_since = 1
end
f.method = ismethod
local newname = deprecated_aliases[f.name]
if newname ~= nil then
local newf = shallowcopy(f)
newf.name = newname
newf.impl_name = f.name
newf.noeval = true
newf.deprecated_since = 1
functions[#functions+1] = newf
end
end
-- start building the output
output = io.open(outputf, 'wb')
@ -99,7 +144,7 @@ output:write([[
#include "nvim/log.h"
#include "nvim/vim.h"
#include "nvim/msgpack_rpc/helpers.h"
#include "nvim/msgpack_rpc/defs.h"
#include "nvim/api/private/dispatch.h"
#include "nvim/api/private/helpers.h"
#include "nvim/api/private/defs.h"
]])
@ -163,99 +208,95 @@ end
-- the real API.
for i = 1, #functions do
local fn = functions[i]
local args = {}
if fn.impl_name == nil then
local args = {}
output:write('static Object handle_'..fn.name..'(uint64_t channel_id, uint64_t request_id, Array args, Error *error)')
output:write('\n{')
output:write('\n Object ret = NIL;')
-- Declare/initialize variables that will hold converted arguments
for j = 1, #fn.parameters do
local param = fn.parameters[j]
local converted = 'arg_'..j
output:write('\n '..param[1]..' '..converted..' api_init_'..string.lower(real_type(param[1]))..';')
end
output:write('\n')
output:write('\n if (args.size != '..#fn.parameters..') {')
output:write('\n snprintf(error->msg, sizeof(error->msg), "Wrong number of arguments: expecting '..#fn.parameters..' but got %zu", args.size);')
output:write('\n error->set = true;')
output:write('\n goto cleanup;')
output:write('\n }\n')
output:write('Object handle_'..fn.name..'(uint64_t channel_id, uint64_t request_id, Array args, Error *error)')
output:write('\n{')
output:write('\n Object ret = NIL;')
-- Declare/initialize variables that will hold converted arguments
for j = 1, #fn.parameters do
local param = fn.parameters[j]
local converted = 'arg_'..j
output:write('\n '..param[1]..' '..converted..' api_init_'..string.lower(real_type(param[1]))..';')
end
output:write('\n')
output:write('\n if (args.size != '..#fn.parameters..') {')
output:write('\n snprintf(error->msg, sizeof(error->msg), "Wrong number of arguments: expecting '..#fn.parameters..' but got %zu", args.size);')
output:write('\n error->set = true;')
output:write('\n goto cleanup;')
output:write('\n }\n')
-- Validation/conversion for each argument
for j = 1, #fn.parameters do
local converted, convert_arg, param, arg
param = fn.parameters[j]
converted = 'arg_'..j
local rt = real_type(param[1])
if rt ~= 'Object' then
output:write('\n if (args.items['..(j - 1)..'].type == kObjectType'..rt..') {')
output:write('\n '..converted..' = args.items['..(j - 1)..'].data.'..rt:lower()..';')
if rt:match('^Buffer$') or rt:match('^Window$') or rt:match('^Tabpage$') or rt:match('^Boolean$') then
-- accept positive integers for Buffers, Windows and Tabpages
output:write('\n } else if (args.items['..(j - 1)..'].type == kObjectTypeInteger && args.items['..(j - 1)..'].data.integer > 0) {')
output:write('\n '..converted..' = (unsigned)args.items['..(j - 1)..'].data.integer;')
-- Validation/conversion for each argument
for j = 1, #fn.parameters do
local converted, convert_arg, param, arg
param = fn.parameters[j]
converted = 'arg_'..j
local rt = real_type(param[1])
if rt ~= 'Object' then
output:write('\n if (args.items['..(j - 1)..'].type == kObjectType'..rt..') {')
output:write('\n '..converted..' = args.items['..(j - 1)..'].data.'..rt:lower()..';')
if rt:match('^Buffer$') or rt:match('^Window$') or rt:match('^Tabpage$') or rt:match('^Boolean$') then
-- accept nonnegative integers for Booleans, Buffers, Windows and Tabpages
output:write('\n } else if (args.items['..(j - 1)..'].type == kObjectTypeInteger && args.items['..(j - 1)..'].data.integer >= 0) {')
output:write('\n '..converted..' = (handle_T)args.items['..(j - 1)..'].data.integer;')
end
output:write('\n } else {')
output:write('\n snprintf(error->msg, sizeof(error->msg), "Wrong type for argument '..j..', expecting '..param[1]..'");')
output:write('\n error->set = true;')
output:write('\n goto cleanup;')
output:write('\n }\n')
else
output:write('\n '..converted..' = args.items['..(j - 1)..'];\n')
end
output:write('\n } else {')
output:write('\n snprintf(error->msg, sizeof(error->msg), "Wrong type for argument '..j..', expecting '..param[1]..'");')
output:write('\n error->set = true;')
args[#args + 1] = converted
end
-- function call
local call_args = table.concat(args, ', ')
output:write('\n ')
if fn.return_type ~= 'void' then
-- has a return value, prefix the call with a declaration
output:write(fn.return_type..' rv = ')
end
-- write the function name and the opening parenthesis
output:write(fn.name..'(')
if fn.receives_channel_id then
-- if the function receives the channel id, pass it as first argument
if #args > 0 or fn.can_fail then
output:write('channel_id, '..call_args)
else
output:write('channel_id')
end
else
output:write(call_args)
end
if fn.can_fail then
-- if the function can fail, also pass a pointer to the local error object
if #args > 0 then
output:write(', error);\n')
else
output:write('error);\n')
end
-- and check for the error
output:write('\n if (error->set) {')
output:write('\n goto cleanup;')
output:write('\n }\n')
else
output:write('\n '..converted..' = args.items['..(j - 1)..'];\n')
output:write(');\n')
end
args[#args + 1] = converted
end
-- function call
local call_args = table.concat(args, ', ')
output:write('\n ')
if fn.return_type ~= 'void' then
-- has a return value, prefix the call with a declaration
output:write(fn.return_type..' rv = ')
end
-- write the function name and the opening parenthesis
output:write(fn.name..'(')
if fn.receives_channel_id then
-- if the function receives the channel id, pass it as first argument
if #args > 0 or fn.can_fail then
output:write('channel_id, '..call_args)
else
output:write('channel_id')
if fn.return_type ~= 'void' then
output:write('\n ret = '..string.upper(real_type(fn.return_type))..'_OBJ(rv);')
end
else
output:write(call_args)
end
output:write('\n\ncleanup:');
if fn.can_fail then
-- if the function can fail, also pass a pointer to the local error object
if #args > 0 then
output:write(', error);\n')
else
output:write('error);\n')
end
-- and check for the error
output:write('\n if (error->set) {')
output:write('\n goto cleanup;')
output:write('\n }\n')
else
output:write(');\n')
output:write('\n return ret;\n}\n\n');
end
if fn.return_type ~= 'void' then
output:write('\n ret = '..string.upper(real_type(fn.return_type))..'_OBJ(rv);')
end
-- Now generate the cleanup label for freeing memory allocated for the
-- arguments
output:write('\n\ncleanup:');
for j = 1, #fn.parameters do
local param = fn.parameters[j]
output:write('\n api_free_'..string.lower(real_type(param[1]))..'(arg_'..j..');')
end
output:write('\n return ret;\n}\n\n');
end
-- Generate a function that initializes method names with handler functions
@ -281,7 +322,7 @@ for i = 1, #functions do
output:write(' msgpack_rpc_add_method_handler('..
'(String) {.data = "'..fn.name..'", '..
'.size = sizeof("'..fn.name..'") - 1}, '..
'(MsgpackRpcRequestHandler) {.fn = handle_'.. fn.name..
'(MsgpackRpcRequestHandler) {.fn = handle_'.. (fn.impl_name or fn.name)..
', .async = '..tostring(fn.async)..'});\n')
if #fn.name > max_fname_len then
@ -311,3 +352,7 @@ MsgpackRpcRequestHandler msgpack_rpc_get_handler_for(const char *name,
]])
output:close()
mpack_output = io.open(mpack_outputf, 'wb')
mpack_output:write(packed)
mpack_output:close()

66
scripts/geneval.lua Normal file
View File

@ -0,0 +1,66 @@
mpack = require('mpack')
local nvimsrcdir = arg[1]
local autodir = arg[2]
local metadata_file = arg[3]
local funcs_file = arg[4]
if nvimsrcdir == '--help' then
print([[
Usage:
lua geneval.lua src/nvim build/src/nvim/auto
Will generate build/src/nvim/auto/funcs.generated.h with definition of functions
static const array.
]])
os.exit(0)
end
package.path = nvimsrcdir .. '/?.lua;' .. package.path
local funcsfname = autodir .. '/funcs.generated.h'
local gperfpipe = io.open(funcsfname .. '.gperf', 'wb')
local funcs = require('eval').funcs
local metadata = mpack.unpack(io.open(arg[3], 'rb'):read("*all"))
for i,fun in ipairs(metadata) do
if not fun.noeval then
funcs[fun.name] = {
args=#fun.parameters,
func='api_wrapper',
data='&handle_'..fun.name,
}
end
end
local funcsdata = io.open(funcs_file, 'w')
funcsdata:write(mpack.pack(funcs))
funcsdata:close()
gperfpipe:write([[
%language=ANSI-C
%global-table
%define initializer-suffix ,0,0,NULL,NULL
%define word-array-name functions
%define hash-function-name hash_internal_func_gperf
%define lookup-function-name find_internal_func_gperf
%omit-struct-type
%struct-type
VimLFuncDef;
%%
]])
for name, def in pairs(funcs) do
args = def.args or 0
if type(args) == 'number' then
args = {args, args}
elseif #args == 1 then
args[2] = 'MAX_FUNC_ARGS'
end
func = def.func or ('f_' .. name)
data = def.data or "NULL"
gperfpipe:write(('%s, %s, %s, &%s, (FunPtr)%s\n')
:format(name, args[1], args[2], func, data))
end
gperfpipe:close()

View File

@ -1,3 +1,5 @@
mpack = require('mpack')
if arg[1] == '--help' then
print('Usage: lua genvimvim.lua src/nvim runtime/syntax/vim/generated.vim')
os.exit(0)
@ -5,6 +7,7 @@ end
local nvimsrcdir = arg[1]
local syntax_file = arg[2]
local funcs_file = arg[3]
package.path = nvimsrcdir .. '/?.lua;' .. package.path
@ -111,28 +114,16 @@ end
w('\n\nsyn case match')
local vimfun_start = 'syn keyword vimFuncName contained '
w('\n\n' .. vimfun_start)
eval_fd = io.open(nvimsrcdir .. '/eval.c', 'r')
funcs = mpack.unpack(io.open(funcs_file):read("*all"))
local started = 0
for line in eval_fd:lines() do
if line == '} functions[] =' then
started = 1
elseif started == 1 then
assert (line == '{')
started = 2
elseif started == 2 then
if line == '};' then
break
end
local func_name = line:match('^ { "([%w_]+)",')
if func_name then
if lld.line_length > 850 then
w('\n' .. vimfun_start)
end
w(' ' .. func_name)
for name, def in pairs(funcs) do
if name then
if lld.line_length > 850 then
w('\n' .. vimfun_start)
end
w(' ' .. name)
end
end
eval_fd:close()
w('\n')
syn_fd:close()

View File

@ -11,22 +11,28 @@ endif()
endif()
set(GENERATED_DIR ${PROJECT_BINARY_DIR}/src/nvim/auto)
set(DISPATCH_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/msgpack-gen.lua)
set(DISPATCH_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/gendispatch.lua)
file(GLOB API_HEADERS api/*.h)
file(GLOB MSGPACK_RPC_HEADERS msgpack_rpc/*.h)
set(MSGPACK_DISPATCH ${GENERATED_DIR}/msgpack_dispatch.c)
set(API_METADATA ${PROJECT_BINARY_DIR}/api_metadata.mpack)
set(FUNCS_DATA ${PROJECT_BINARY_DIR}/funcs_data.mpack)
set(HEADER_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/gendeclarations.lua)
set(GENERATED_INCLUDES_DIR ${PROJECT_BINARY_DIR}/include)
set(GENERATED_API_DISPATCH ${GENERATED_DIR}/api/private/dispatch.c)
set(GENERATED_EX_CMDS_ENUM ${GENERATED_INCLUDES_DIR}/ex_cmds_enum.generated.h)
set(GENERATED_EX_CMDS_DEFS ${GENERATED_DIR}/ex_cmds_defs.generated.h)
set(GENERATED_FUNCS_HASH_INPUT ${GENERATED_DIR}/funcs.generated.h.gperf)
set(GENERATED_FUNCS ${GENERATED_DIR}/funcs.generated.h)
set(GENERATED_EVENTS_ENUM ${GENERATED_INCLUDES_DIR}/auevents_enum.generated.h)
set(GENERATED_EVENTS_NAMES_MAP ${GENERATED_DIR}/auevents_name_map.generated.h)
set(GENERATED_OPTIONS ${GENERATED_DIR}/options.generated.h)
set(EX_CMDS_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/genex_cmds.lua)
set(FUNCS_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/geneval.lua)
set(EVENTS_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/gen_events.lua)
set(OPTIONS_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/genoptions.lua)
set(EVENTS_LIST_FILE ${PROJECT_SOURCE_DIR}/src/nvim/auevents.lua)
set(EX_CMDS_DEFS_FILE ${PROJECT_SOURCE_DIR}/src/nvim/ex_cmds.lua)
set(EVAL_DEFS_FILE ${PROJECT_SOURCE_DIR}/src/nvim/eval.lua)
set(OPTIONS_LIST_FILE ${PROJECT_SOURCE_DIR}/src/nvim/options.lua)
set(UNICODE_TABLES_GENERATOR ${PROJECT_SOURCE_DIR}/scripts/genunicodetables.lua)
set(UNICODE_DIR ${PROJECT_SOURCE_DIR}/unicode)
@ -36,6 +42,7 @@ set(EASTASIANWIDTH_FILE ${UNICODE_DIR}/EastAsianWidth.txt)
set(GENERATED_UNICODE_TABLES ${GENERATED_DIR}/unicode_tables.generated.h)
include_directories(${GENERATED_DIR})
include_directories(${CACHED_GENERATED_DIR})
include_directories(${GENERATED_INCLUDES_DIR})
file(MAKE_DIRECTORY ${GENERATED_DIR})
@ -112,6 +119,10 @@ endforeach()
if(NOT MSVC)
set_source_files_properties(
${CONV_SOURCES} PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-conversion")
# gperf generates ANSI-C with incorrect linkage, ignore it.
set_source_files_properties(
eval.c PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-static-in-inline -Wno-conversion")
endif()
if(DEFINED MIN_LOG_LEVEL)
@ -138,9 +149,13 @@ separate_arguments(C_FLAGS_${build_type}_ARRAY UNIX_COMMAND ${CMAKE_C_FLAGS_${bu
set(gen_cflags ${gen_cflags} ${C_FLAGS_${build_type}_ARRAY} ${C_FLAGS_ARRAY})
foreach(sfile ${NEOVIM_SOURCES}
"${PROJECT_SOURCE_DIR}/src/nvim/regexp_nfa.c")
"${PROJECT_SOURCE_DIR}/src/nvim/regexp_nfa.c"
${GENERATED_API_DISPATCH})
get_filename_component(full_d ${sfile} PATH)
file(RELATIVE_PATH d "${PROJECT_SOURCE_DIR}/src/nvim" "${full_d}")
if(${d} MATCHES "^[.][.]")
file(RELATIVE_PATH d "${GENERATED_DIR}" "${full_d}")
endif()
get_filename_component(f ${sfile} NAME)
get_filename_component(r ${sfile} NAME_WE)
if(NOT ${d} EQUAL ".")
@ -183,8 +198,8 @@ add_custom_command(OUTPUT ${GENERATED_UNICODE_TABLES}
${EASTASIANWIDTH_FILE}
)
add_custom_command(OUTPUT ${MSGPACK_DISPATCH}
COMMAND ${LUA_PRG} ${DISPATCH_GENERATOR} ${API_HEADERS} ${MSGPACK_DISPATCH}
add_custom_command(OUTPUT ${GENERATED_API_DISPATCH} ${API_METADATA}
COMMAND ${LUA_PRG} ${DISPATCH_GENERATOR} ${PROJECT_SOURCE_DIR}/scripts ${API_HEADERS} ${GENERATED_API_DISPATCH} ${API_METADATA}
DEPENDS
${API_HEADERS}
${MSGPACK_RPC_HEADERS}
@ -193,7 +208,7 @@ add_custom_command(OUTPUT ${MSGPACK_DISPATCH}
list(APPEND NEOVIM_GENERATED_SOURCES
"${PROJECT_BINARY_DIR}/config/auto/pathdef.c"
"${MSGPACK_DISPATCH}"
"${GENERATED_API_DISPATCH}"
"${GENERATED_EX_CMDS_ENUM}"
"${GENERATED_EX_CMDS_DEFS}"
"${GENERATED_EVENTS_ENUM}"
@ -208,6 +223,19 @@ add_custom_command(OUTPUT ${GENERATED_EX_CMDS_ENUM} ${GENERATED_EX_CMDS_DEFS}
DEPENDS ${EX_CMDS_GENERATOR} ${EX_CMDS_DEFS_FILE}
)
if(NOT GPERF_PRG)
message(FATAL_ERROR "gperf was not found.")
endif()
add_custom_command(OUTPUT ${GENERATED_FUNCS} ${FUNCS_DATA}
COMMAND ${LUA_PRG} ${FUNCS_GENERATOR}
${PROJECT_SOURCE_DIR}/src/nvim ${GENERATED_DIR} ${API_METADATA} ${FUNCS_DATA}
COMMAND ${GPERF_PRG}
${GENERATED_FUNCS_HASH_INPUT} --output-file=${GENERATED_FUNCS}
DEPENDS ${FUNCS_GENERATOR} ${EVAL_DEFS_FILE} ${API_METADATA}
)
list(APPEND NEOVIM_GENERATED_SOURCES
"${GENERATED_FUNCS}")
add_custom_command(OUTPUT ${GENERATED_EVENTS_ENUM} ${GENERATED_EVENTS_NAMES_MAP}
COMMAND ${LUA_PRG} ${EVENTS_GENERATOR}
${PROJECT_SOURCE_DIR}/src/nvim ${GENERATED_EVENTS_ENUM} ${GENERATED_EVENTS_NAMES_MAP}

View File

@ -32,7 +32,7 @@
/// @param buffer The buffer handle
/// @param[out] err Details of an error that may have occurred
/// @return The line count
Integer buffer_line_count(Buffer buffer, Error *err)
Integer nvim_buf_line_count(Buffer buffer, Error *err)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@ -45,11 +45,11 @@ Integer buffer_line_count(Buffer buffer, Error *err)
/// Gets a buffer line
///
/// @deprecated use buffer_get_lines instead.
/// @deprecated use nvim_buf_get_lines instead.
/// for positive indices (including 0) use
/// "buffer_get_lines(buffer, index, index+1, true)"
/// "nvim_buf_get_lines(buffer, index, index+1, true)"
/// for negative indices use
/// "buffer_get_lines(buffer, index-1, index, true)"
/// "nvim_buf_get_lines(buffer, index-1, index, true)"
///
/// @param buffer The buffer handle
/// @param index The line index
@ -60,7 +60,7 @@ String buffer_get_line(Buffer buffer, Integer index, Error *err)
String rv = { .size = 0 };
index = convert_index(index);
Array slice = buffer_get_lines(buffer, index, index+1, true, err);
Array slice = nvim_buf_get_lines(0, buffer, index, index+1, true, err);
if (!err->set && slice.size) {
rv = slice.items[0].data.string;
@ -73,11 +73,11 @@ String buffer_get_line(Buffer buffer, Integer index, Error *err)
/// Sets a buffer line
///
/// @deprecated use buffer_set_lines instead.
/// @deprecated use nvim_buf_set_lines instead.
/// for positive indices use
/// "buffer_set_lines(buffer, index, index+1, true, [line])"
/// "nvim_buf_set_lines(buffer, index, index+1, true, [line])"
/// for negative indices use
/// "buffer_set_lines(buffer, index-1, index, true, [line])"
/// "nvim_buf_set_lines(buffer, index-1, index, true, [line])"
///
/// @param buffer The buffer handle
/// @param index The line index
@ -88,16 +88,16 @@ void buffer_set_line(Buffer buffer, Integer index, String line, Error *err)
Object l = STRING_OBJ(line);
Array array = { .items = &l, .size = 1 };
index = convert_index(index);
buffer_set_lines(buffer, index, index+1, true, array, err);
nvim_buf_set_lines(0, buffer, index, index+1, true, array, err);
}
/// Deletes a buffer line
///
/// @deprecated use buffer_set_lines instead.
/// @deprecated use nvim_buf_set_lines instead.
/// for positive indices use
/// "buffer_set_lines(buffer, index, index+1, true, [])"
/// "nvim_buf_set_lines(buffer, index, index+1, true, [])"
/// for negative indices use
/// "buffer_set_lines(buffer, index-1, index, true, [])"
/// "nvim_buf_set_lines(buffer, index-1, index, true, [])"
/// @param buffer The buffer handle
/// @param index The line index
/// @param[out] err Details of an error that may have occurred
@ -105,12 +105,12 @@ void buffer_del_line(Buffer buffer, Integer index, Error *err)
{
Array array = ARRAY_DICT_INIT;
index = convert_index(index);
buffer_set_lines(buffer, index, index+1, true, array, err);
nvim_buf_set_lines(0, buffer, index, index+1, true, array, err);
}
/// Retrieves a line range from the buffer
///
/// @deprecated use buffer_get_lines(buffer, newstart, newend, false)
/// @deprecated use nvim_buf_get_lines(buffer, newstart, newend, false)
/// where newstart = start + int(not include_start) - int(start < 0)
/// newend = end + int(include_end) - int(end < 0)
/// int(bool) = 1 if bool is true else 0
@ -122,15 +122,15 @@ void buffer_del_line(Buffer buffer, Integer index, Error *err)
/// @param[out] err Details of an error that may have occurred
/// @return An array of lines
ArrayOf(String) buffer_get_line_slice(Buffer buffer,
Integer start,
Integer end,
Boolean include_start,
Boolean include_end,
Error *err)
Integer start,
Integer end,
Boolean include_start,
Boolean include_end,
Error *err)
{
start = convert_index(start) + !include_start;
end = convert_index(end) + include_end;
return buffer_get_lines(buffer, start , end, false, err);
return nvim_buf_get_lines(0, buffer, start , end, false, err);
}
@ -149,11 +149,12 @@ ArrayOf(String) buffer_get_line_slice(Buffer buffer,
/// @param strict_indexing whether out-of-bounds should be an error.
/// @param[out] err Details of an error that may have occurred
/// @return An array of lines
ArrayOf(String) buffer_get_lines(Buffer buffer,
Integer start,
Integer end,
Boolean strict_indexing,
Error *err)
ArrayOf(String) nvim_buf_get_lines(uint64_t channel_id,
Buffer buffer,
Integer start,
Integer end,
Boolean strict_indexing,
Error *err)
{
Array rv = ARRAY_DICT_INIT;
buf_T *buf = find_buffer_by_handle(buffer, err);
@ -191,7 +192,9 @@ ArrayOf(String) buffer_get_lines(Buffer buffer,
Object str = STRING_OBJ(cstr_to_string(bufstr));
// Vim represents NULs as NLs, but this may confuse clients.
strchrsub(str.data.string.data, '\n', '\0');
if (channel_id != INVALID_CHANNEL) {
strchrsub(str.data.string.data, '\n', '\0');
}
rv.items[i] = str;
}
@ -212,7 +215,7 @@ end:
/// Replaces a line range on the buffer
///
/// @deprecated use buffer_set_lines(buffer, newstart, newend, false, lines)
/// @deprecated use nvim_buf_set_lines(buffer, newstart, newend, false, lines)
/// where newstart = start + int(not include_start) + int(start < 0)
/// newend = end + int(include_end) + int(end < 0)
/// int(bool) = 1 if bool is true else 0
@ -226,16 +229,16 @@ end:
// array will simply delete the line range)
/// @param[out] err Details of an error that may have occurred
void buffer_set_line_slice(Buffer buffer,
Integer start,
Integer end,
Boolean include_start,
Boolean include_end,
ArrayOf(String) replacement,
Error *err)
Integer start,
Integer end,
Boolean include_start,
Boolean include_end,
ArrayOf(String) replacement, // NOLINT
Error *err)
{
start = convert_index(start) + !include_start;
end = convert_index(end) + include_end;
buffer_set_lines(buffer, start, end, false, replacement, err);
nvim_buf_set_lines(0, buffer, start, end, false, replacement, err);
}
@ -257,12 +260,13 @@ void buffer_set_line_slice(Buffer buffer,
/// @param strict_indexing whether out-of-bounds should be an error.
/// @param replacement An array of lines to use as replacement
/// @param[out] err Details of an error that may have occurred
void buffer_set_lines(Buffer buffer,
Integer start,
Integer end,
Boolean strict_indexing,
ArrayOf(String) replacement,
Error *err)
void nvim_buf_set_lines(uint64_t channel_id,
Buffer buffer,
Integer start,
Integer end,
Boolean strict_indexing,
ArrayOf(String) replacement, // NOLINT
Error *err)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@ -309,7 +313,7 @@ void buffer_set_lines(Buffer buffer,
// line and convert NULs to newlines to avoid truncation.
lines[i] = xmallocz(l.size);
for (size_t j = 0; j < l.size; j++) {
if (l.data[j] == '\n') {
if (l.data[j] == '\n' && channel_id != INVALID_CHANNEL) {
api_set_error(err, Exception, _("string cannot contain newlines"));
new_len = i + 1;
goto end;
@ -412,7 +416,7 @@ end:
/// @param name The variable name
/// @param[out] err Details of an error that may have occurred
/// @return The variable value
Object buffer_get_var(Buffer buffer, String name, Error *err)
Object nvim_buf_get_var(Buffer buffer, String name, Error *err)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@ -433,7 +437,7 @@ Object buffer_get_var(Buffer buffer, String name, Error *err)
///
/// @warning It may return nil if there was no previous value
/// or if previous value was `v:null`.
Object buffer_set_var(Buffer buffer, String name, Object value, Error *err)
Object nvim_buf_set_var(Buffer buffer, String name, Object value, Error *err)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@ -453,7 +457,7 @@ Object buffer_set_var(Buffer buffer, String name, Object value, Error *err)
///
/// @warning It may return nil if there was no previous value
/// or if previous value was `v:null`.
Object buffer_del_var(Buffer buffer, String name, Error *err)
Object nvim_buf_del_var(Buffer buffer, String name, Error *err)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@ -470,7 +474,7 @@ Object buffer_del_var(Buffer buffer, String name, Error *err)
/// @param name The option name
/// @param[out] err Details of an error that may have occurred
/// @return The option value
Object buffer_get_option(Buffer buffer, String name, Error *err)
Object nvim_buf_get_option(Buffer buffer, String name, Error *err)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@ -488,7 +492,7 @@ Object buffer_get_option(Buffer buffer, String name, Error *err)
/// @param name The option name
/// @param value The option value
/// @param[out] err Details of an error that may have occurred
void buffer_set_option(Buffer buffer, String name, Object value, Error *err)
void nvim_buf_set_option(Buffer buffer, String name, Object value, Error *err)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@ -504,7 +508,7 @@ void buffer_set_option(Buffer buffer, String name, Object value, Error *err)
/// @param buffer The buffer handle
/// @param[out] err Details of an error that may have occurred
/// @return The buffer number
Integer buffer_get_number(Buffer buffer, Error *err)
Integer nvim_buf_get_number(Buffer buffer, Error *err)
{
Integer rv = 0;
buf_T *buf = find_buffer_by_handle(buffer, err);
@ -521,7 +525,7 @@ Integer buffer_get_number(Buffer buffer, Error *err)
/// @param buffer The buffer handle
/// @param[out] err Details of an error that may have occurred
/// @return The buffer name
String buffer_get_name(Buffer buffer, Error *err)
String nvim_buf_get_name(Buffer buffer, Error *err)
{
String rv = STRING_INIT;
buf_T *buf = find_buffer_by_handle(buffer, err);
@ -538,7 +542,7 @@ String buffer_get_name(Buffer buffer, Error *err)
/// @param buffer The buffer handle
/// @param name The buffer name
/// @param[out] err Details of an error that may have occurred
void buffer_set_name(Buffer buffer, String name, Error *err)
void nvim_buf_set_name(Buffer buffer, String name, Error *err)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@ -567,7 +571,7 @@ void buffer_set_name(Buffer buffer, String name, Error *err)
///
/// @param buffer The buffer handle
/// @return true if the buffer is valid, false otherwise
Boolean buffer_is_valid(Buffer buffer)
Boolean nvim_buf_is_valid(Buffer buffer)
{
Error stub = ERROR_INIT;
return find_buffer_by_handle(buffer, &stub) != NULL;
@ -575,7 +579,7 @@ Boolean buffer_is_valid(Buffer buffer)
/// Inserts a sequence of lines to a buffer at a certain index
///
/// @deprecated use buffer_set_lines(buffer, lnum, lnum, true, lines)
/// @deprecated use nvim_buf_set_lines(buffer, lnum, lnum, true, lines)
///
/// @param buffer The buffer handle
/// @param lnum Insert the lines after `lnum`. If negative, it will append
@ -589,7 +593,7 @@ void buffer_insert(Buffer buffer,
{
// "lnum" will be the index of the line after inserting,
// no matter if it is negative or not
buffer_set_lines(buffer, lnum, lnum, true, lines, err);
nvim_buf_set_lines(0, buffer, lnum, lnum, true, lines, err);
}
/// Return a tuple (row,col) representing the position of the named mark
@ -598,7 +602,7 @@ void buffer_insert(Buffer buffer,
/// @param name The mark's name
/// @param[out] err Details of an error that may have occurred
/// @return The (row, col) tuple
ArrayOf(Integer, 2) buffer_get_mark(Buffer buffer, String name, Error *err)
ArrayOf(Integer, 2) nvim_buf_get_mark(Buffer buffer, String name, Error *err)
{
Array rv = ARRAY_DICT_INIT;
buf_T *buf = find_buffer_by_handle(buffer, err);
@ -648,7 +652,7 @@ ArrayOf(Integer, 2) buffer_get_mark(Buffer buffer, String name, Error *err)
/// called with src_id = 0, an unique source id is generated and returned.
/// Succesive calls can pass in it as "src_id" to add new highlights to the same
/// source group. All highlights in the same group can then be cleared with
/// buffer_clear_highlight. If the highlight never will be manually deleted
/// nvim_buf_clear_highlight. If the highlight never will be manually deleted
/// pass in -1 for "src_id".
///
/// If "hl_group" is the empty string no highlight is added, but a new src_id
@ -666,13 +670,13 @@ ArrayOf(Integer, 2) buffer_get_mark(Buffer buffer, String name, Error *err)
/// or -1 to highlight to end of line
/// @param[out] err Details of an error that may have occurred
/// @return The src_id that was used
Integer buffer_add_highlight(Buffer buffer,
Integer src_id,
String hl_group,
Integer line,
Integer col_start,
Integer col_end,
Error *err)
Integer nvim_buf_add_highlight(Buffer buffer,
Integer src_id,
String hl_group,
Integer line,
Integer col_start,
Integer col_end,
Error *err)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
if (!buf) {
@ -708,11 +712,11 @@ Integer buffer_add_highlight(Buffer buffer,
/// @param line_end End of range of lines to clear (exclusive)
/// or -1 to clear to end of file.
/// @param[out] err Details of an error that may have occurred
void buffer_clear_highlight(Buffer buffer,
Integer src_id,
Integer line_start,
Integer line_end,
Error *err)
void nvim_buf_clear_highlight(Buffer buffer,
Integer src_id,
Integer line_start,
Integer line_end,
Error *err)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
if (!buf) {

View File

@ -9,13 +9,15 @@
#define STRING_INIT {.data = NULL, .size = 0}
#define OBJECT_INIT { .type = kObjectTypeNil }
#define ERROR_INIT { .set = false }
#define REMOTE_TYPE(type) typedef uint64_t type
#define REMOTE_TYPE(type) typedef handle_T type
#ifdef INCLUDE_GENERATED_DECLARATIONS
# define ArrayOf(...) Array
# define DictionaryOf(...) Dictionary
#endif
typedef int handle_T;
// Basic types
typedef enum {
kErrorTypeException,
@ -31,6 +33,9 @@ typedef enum {
/// Used as the message ID of notifications.
#define NO_RESPONSE UINT64_MAX
/// Used as channel_id when the call is local
#define INVALID_CHANNEL UINT64_MAX
typedef struct {
ErrorType type;
char msg[1024];

View File

@ -0,0 +1,23 @@
#ifndef NVIM_API_PRIVATE_DISPATCH_H
#define NVIM_API_PRIVATE_DISPATCH_H
#include "nvim/api/private/defs.h"
typedef Object (*ApiDispatchWrapper)(uint64_t channel_id,
uint64_t request_id,
Array args,
Error *error);
/// The rpc_method_handlers table, used in msgpack_rpc_dispatch(), stores
/// functions of this type.
typedef struct {
ApiDispatchWrapper fn;
bool async; // function is always safe to run immediately instead of being
// put in a request queue for handling when nvim waits for input.
} MsgpackRpcRequestHandler;
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "api/private/dispatch.h.generated.h"
#endif
#endif // NVIM_API_PRIVATE_DISPATCH_H

View File

@ -5,30 +5,26 @@
#include "nvim/map.h"
#include "nvim/api/private/handle.h"
#define HANDLE_INIT(name) name##_handles = pmap_new(uint64_t)()
#define HANDLE_INIT(name) name##_handles = pmap_new(handle_T)()
#define HANDLE_IMPL(type, name) \
static PMap(uint64_t) *name##_handles = NULL; \
static PMap(handle_T) *name##_handles = NULL; /* NOLINT */ \
\
type *handle_get_##name(uint64_t handle) \
type *handle_get_##name(handle_T handle) \
{ \
return pmap_get(uint64_t)(name##_handles, handle); \
return pmap_get(handle_T)(name##_handles, handle); \
} \
\
void handle_register_##name(type *name) \
{ \
assert(!name->handle); \
name->handle = next_handle++; \
pmap_put(uint64_t)(name##_handles, name->handle, name); \
pmap_put(handle_T)(name##_handles, name->handle, name); \
} \
\
void handle_unregister_##name(type *name) \
{ \
pmap_del(uint64_t)(name##_handles, name->handle); \
pmap_del(handle_T)(name##_handles, name->handle); \
}
static uint64_t next_handle = 1;
HANDLE_IMPL(buf_T, buffer)
HANDLE_IMPL(win_T, window)
HANDLE_IMPL(tabpage_T, tabpage)

View File

@ -3,9 +3,10 @@
#include "nvim/vim.h"
#include "nvim/buffer_defs.h"
#include "nvim/api/private/defs.h"
#define HANDLE_DECLS(type, name) \
type *handle_get_##name(uint64_t handle); \
type *handle_get_##name(handle_T handle); \
void handle_register_##name(type *name); \
void handle_unregister_##name(type *name);

View File

@ -507,6 +507,10 @@ Object vim_to_object(typval_T *obj)
buf_T *find_buffer_by_handle(Buffer buffer, Error *err)
{
if (buffer == 0) {
return curbuf;
}
buf_T *rv = handle_get_buffer(buffer);
if (!rv) {
@ -518,6 +522,10 @@ buf_T *find_buffer_by_handle(Buffer buffer, Error *err)
win_T * find_window_by_handle(Window window, Error *err)
{
if (window == 0) {
return curwin;
}
win_T *rv = handle_get_window(window);
if (!rv) {
@ -529,6 +537,10 @@ win_T * find_window_by_handle(Window window, Error *err)
tabpage_T * find_tab_by_handle(Tabpage tabpage, Error *err)
{
if (tabpage == 0) {
return curtab;
}
tabpage_T *rv = handle_get_tabpage(tabpage);
if (!rv) {
@ -764,12 +776,15 @@ static void init_type_metadata(Dictionary *metadata)
Dictionary buffer_metadata = ARRAY_DICT_INIT;
PUT(buffer_metadata, "id", INTEGER_OBJ(kObjectTypeBuffer));
PUT(buffer_metadata, "prefix", STRING_OBJ(cstr_to_string("nvim_buf_")));
Dictionary window_metadata = ARRAY_DICT_INIT;
PUT(window_metadata, "id", INTEGER_OBJ(kObjectTypeWindow));
PUT(window_metadata, "prefix", STRING_OBJ(cstr_to_string("nvim_win_")));
Dictionary tabpage_metadata = ARRAY_DICT_INIT;
PUT(tabpage_metadata, "id", INTEGER_OBJ(kObjectTypeTabpage));
PUT(tabpage_metadata, "prefix", STRING_OBJ(cstr_to_string("nvim_tabpage_")));
PUT(types, "Buffer", DICTIONARY_OBJ(buffer_metadata));
PUT(types, "Window", DICTIONARY_OBJ(window_metadata));

View File

@ -14,7 +14,7 @@
/// @param tabpage The tabpage
/// @param[out] err Details of an error that may have occurred
/// @return The windows in `tabpage`
ArrayOf(Window) tabpage_get_windows(Tabpage tabpage, Error *err)
ArrayOf(Window) nvim_tabpage_get_windows(Tabpage tabpage, Error *err)
{
Array rv = ARRAY_DICT_INIT;
tabpage_T *tab = find_tab_by_handle(tabpage, err);
@ -43,7 +43,7 @@ ArrayOf(Window) tabpage_get_windows(Tabpage tabpage, Error *err)
/// @param name The variable name
/// @param[out] err Details of an error that may have occurred
/// @return The variable value
Object tabpage_get_var(Tabpage tabpage, String name, Error *err)
Object nvim_tabpage_get_var(Tabpage tabpage, String name, Error *err)
{
tabpage_T *tab = find_tab_by_handle(tabpage, err);
@ -64,7 +64,10 @@ Object tabpage_get_var(Tabpage tabpage, String name, Error *err)
///
/// @warning It may return nil if there was no previous value
/// or if previous value was `v:null`.
Object tabpage_set_var(Tabpage tabpage, String name, Object value, Error *err)
Object nvim_tabpage_set_var(Tabpage tabpage,
String name,
Object value,
Error *err)
{
tabpage_T *tab = find_tab_by_handle(tabpage, err);
@ -84,7 +87,7 @@ Object tabpage_set_var(Tabpage tabpage, String name, Object value, Error *err)
///
/// @warning It may return nil if there was no previous value
/// or if previous value was `v:null`.
Object tabpage_del_var(Tabpage tabpage, String name, Error *err)
Object nvim_tabpage_del_var(Tabpage tabpage, String name, Error *err)
{
tabpage_T *tab = find_tab_by_handle(tabpage, err);
@ -100,7 +103,7 @@ Object tabpage_del_var(Tabpage tabpage, String name, Error *err)
/// @param tabpage The tab page handle
/// @param[out] err Details of an error that may have occurred
/// @return The Window handle
Window tabpage_get_window(Tabpage tabpage, Error *err)
Window nvim_tabpage_get_window(Tabpage tabpage, Error *err)
{
Window rv = 0;
tabpage_T *tab = find_tab_by_handle(tabpage, err);
@ -110,7 +113,7 @@ Window tabpage_get_window(Tabpage tabpage, Error *err)
}
if (tab == curtab) {
return vim_get_current_window();
return nvim_get_current_window();
} else {
FOR_ALL_WINDOWS_IN_TAB(wp, tab) {
if (wp == tab->tp_curwin) {
@ -126,7 +129,7 @@ Window tabpage_get_window(Tabpage tabpage, Error *err)
///
/// @param tabpage The tab page handle
/// @return true if the tab page is valid, false otherwise
Boolean tabpage_is_valid(Tabpage tabpage)
Boolean nvim_tabpage_is_valid(Tabpage tabpage)
{
Error stub = ERROR_INIT;
return find_tab_by_handle(tabpage, &stub) != NULL;

View File

@ -48,6 +48,7 @@ void remote_ui_disconnect(uint64_t channel_id)
void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height,
Dictionary options, Error *err)
FUNC_API_NOEVAL
{
if (pmap_has(uint64_t)(connected_uis, channel_id)) {
api_set_error(err, Exception, _("UI already attached for channel"));
@ -117,6 +118,7 @@ void ui_attach(uint64_t channel_id, Integer width, Integer height,
}
void nvim_ui_detach(uint64_t channel_id, Error *err)
FUNC_API_NOEVAL
{
if (!pmap_has(uint64_t)(connected_uis, channel_id)) {
api_set_error(err, Exception, _("UI is not attached for channel"));
@ -125,14 +127,10 @@ void nvim_ui_detach(uint64_t channel_id, Error *err)
remote_ui_disconnect(channel_id);
}
/// @deprecated
void ui_detach(uint64_t channel_id, Error *err)
{
nvim_ui_detach(channel_id, err);
}
void nvim_ui_try_resize(uint64_t channel_id, Integer width,
Integer height, Error *err)
FUNC_API_NOEVAL
{
if (!pmap_has(uint64_t)(connected_uis, channel_id)) {
api_set_error(err, Exception, _("UI is not attached for channel"));
@ -151,15 +149,10 @@ void nvim_ui_try_resize(uint64_t channel_id, Integer width,
ui_refresh();
}
/// @deprecated
void ui_try_resize(uint64_t channel_id, Integer width,
Integer height, Error *err)
{
nvim_ui_try_resize(channel_id, width, height, err);
}
void nvim_ui_set_option(uint64_t channel_id, String name,
Object value, Error *error) {
Object value, Error *error)
FUNC_API_NOEVAL
{
if (!pmap_has(uint64_t)(connected_uis, channel_id)) {
api_set_error(error, Exception, _("UI is not attached for channel"));
return;

View File

@ -36,7 +36,7 @@
///
/// @param str The command str
/// @param[out] err Details of an error that may have occurred
void vim_command(String str, Error *err)
void nvim_command(String str, Error *err)
{
// Run the command
try_start();
@ -52,7 +52,7 @@ void vim_command(String str, Error *err)
/// @param escape_csi the string needs escaping for K_SPECIAL/CSI bytes
/// @see feedkeys()
/// @see vim_strsave_escape_csi
void vim_feedkeys(String keys, String mode, Boolean escape_csi)
void nvim_feedkeys(String keys, String mode, Boolean escape_csi)
{
bool remap = true;
bool insert = false;
@ -96,14 +96,14 @@ void vim_feedkeys(String keys, String mode, Boolean escape_csi)
}
}
/// Passes input keys to Neovim. Unlike `vim_feedkeys`, this will use a
/// Passes input keys to Neovim. Unlike `nvim_feedkeys`, this will use a
/// lower-level input buffer and the call is not deferred.
/// This is the most reliable way to emulate real user input.
///
/// @param keys to be typed
/// @return The number of bytes actually written, which can be lower than
/// requested if the buffer becomes full.
Integer vim_input(String keys)
Integer nvim_input(String keys)
FUNC_API_ASYNC
{
return (Integer)input_enqueue(keys);
@ -113,7 +113,7 @@ Integer vim_input(String keys)
///
/// @see replace_termcodes
/// @see cpoptions
String vim_replace_termcodes(String str, Boolean from_part, Boolean do_lt,
String nvim_replace_termcodes(String str, Boolean from_part, Boolean do_lt,
Boolean special)
{
if (str.size == 0) {
@ -133,10 +133,10 @@ String vim_replace_termcodes(String str, Boolean from_part, Boolean do_lt,
return cstr_as_string(ptr);
}
String vim_command_output(String str, Error *err)
String nvim_command_output(String str, Error *err)
{
do_cmdline_cmd("redir => v:command_output");
vim_command(str, err);
nvim_command(str, err);
do_cmdline_cmd("redir END");
if (err->set) {
@ -153,7 +153,7 @@ String vim_command_output(String str, Error *err)
/// @param str The expression str
/// @param[out] err Details of an error that may have occurred
/// @return The expanded object
Object vim_eval(String str, Error *err)
Object nvim_eval(String str, Error *err)
{
Object rv = OBJECT_INIT;
// Evaluate the expression
@ -180,7 +180,7 @@ Object vim_eval(String str, Error *err)
/// @param args Functions arguments packed in an Array
/// @param[out] err Details of an error that may have occurred
/// @return Result of the function call
Object vim_call_function(String fname, Array args, Error *err)
Object nvim_call_function(String fname, Array args, Error *err)
{
Object rv = OBJECT_INIT;
if (args.size > MAX_FUNC_ARGS) {
@ -229,7 +229,7 @@ free_vim_args:
/// @param str Some text
/// @param[out] err Details of an error that may have occurred
/// @return The number of cells
Integer vim_strwidth(String str, Error *err)
Integer nvim_strwidth(String str, Error *err)
{
if (str.size > INT_MAX) {
api_set_error(err, Validation, _("String length is too high"));
@ -242,7 +242,7 @@ Integer vim_strwidth(String str, Error *err)
/// Gets a list of paths contained in 'runtimepath'
///
/// @return The list of paths
ArrayOf(String) vim_list_runtime_paths(void)
ArrayOf(String) nvim_list_runtime_paths(void)
{
Array rv = ARRAY_DICT_INIT;
uint8_t *rtp = p_rtp;
@ -283,7 +283,7 @@ ArrayOf(String) vim_list_runtime_paths(void)
///
/// @param dir The new working directory
/// @param[out] err Details of an error that may have occurred
void vim_change_directory(String dir, Error *err)
void nvim_change_directory(String dir, Error *err)
{
if (dir.size >= MAXPATHL) {
api_set_error(err, Validation, _("Directory string is too long"));
@ -311,7 +311,7 @@ void vim_change_directory(String dir, Error *err)
///
/// @param[out] err Details of an error that may have occurred
/// @return The current line string
String vim_get_current_line(Error *err)
String nvim_get_current_line(Error *err)
{
return buffer_get_line(curbuf->handle, curwin->w_cursor.lnum - 1, err);
}
@ -320,7 +320,7 @@ String vim_get_current_line(Error *err)
///
/// @param line The line contents
/// @param[out] err Details of an error that may have occurred
void vim_set_current_line(String line, Error *err)
void nvim_set_current_line(String line, Error *err)
{
buffer_set_line(curbuf->handle, curwin->w_cursor.lnum - 1, line, err);
}
@ -328,7 +328,7 @@ void vim_set_current_line(String line, Error *err)
/// Deletes the current line
///
/// @param[out] err Details of an error that may have occurred
void vim_del_current_line(Error *err)
void nvim_del_current_line(Error *err)
{
buffer_del_line(curbuf->handle, curwin->w_cursor.lnum - 1, err);
}
@ -338,7 +338,7 @@ void vim_del_current_line(Error *err)
/// @param name The variable name
/// @param[out] err Details of an error that may have occurred
/// @return The variable value
Object vim_get_var(String name, Error *err)
Object nvim_get_var(String name, Error *err)
{
return dict_get_value(&globvardict, name, err);
}
@ -352,7 +352,7 @@ Object vim_get_var(String name, Error *err)
///
/// @warning It may return nil if there was no previous value
/// or if previous value was `v:null`.
Object vim_set_var(String name, Object value, Error *err)
Object nvim_set_var(String name, Object value, Error *err)
{
return dict_set_value(&globvardict, name, value, false, err);
}
@ -365,7 +365,7 @@ Object vim_set_var(String name, Object value, Error *err)
///
/// @warning It may return nil if there was no previous value
/// or if previous value was `v:null`.
Object vim_del_var(String name, Error *err)
Object nvim_del_var(String name, Error *err)
{
return dict_set_value(&globvardict, name, NIL, true, err);
}
@ -375,7 +375,7 @@ Object vim_del_var(String name, Error *err)
/// @param name The variable name
/// @param[out] err Details of an error that may have occurred
/// @return The variable value
Object vim_get_vvar(String name, Error *err)
Object nvim_get_vvar(String name, Error *err)
{
return dict_get_value(&vimvardict, name, err);
}
@ -385,7 +385,7 @@ Object vim_get_vvar(String name, Error *err)
/// @param name The option name
/// @param[out] err Details of an error that may have occurred
/// @return The option value
Object vim_get_option(String name, Error *err)
Object nvim_get_option(String name, Error *err)
{
return get_option_from(NULL, SREQ_GLOBAL, name, err);
}
@ -395,7 +395,7 @@ Object vim_get_option(String name, Error *err)
/// @param name The option name
/// @param value The new option value
/// @param[out] err Details of an error that may have occurred
void vim_set_option(String name, Object value, Error *err)
void nvim_set_option(String name, Object value, Error *err)
{
set_option_to(NULL, SREQ_GLOBAL, name, value, err);
}
@ -403,7 +403,7 @@ void vim_set_option(String name, Object value, Error *err)
/// Writes a message to vim output buffer
///
/// @param str The message
void vim_out_write(String str)
void nvim_out_write(String str)
{
write_msg(str, false);
}
@ -411,25 +411,25 @@ void vim_out_write(String str)
/// Writes a message to vim error buffer
///
/// @param str The message
void vim_err_write(String str)
void nvim_err_write(String str)
{
write_msg(str, true);
}
/// Higher level error reporting function that ensures all str contents
/// are written by sending a trailing linefeed to `vim_err_write`
/// are written by sending a trailing linefeed to `nvim_err_write`
///
/// @param str The message
void vim_report_error(String str)
void nvim_report_error(String str)
{
vim_err_write(str);
vim_err_write((String) {.data = "\n", .size = 1});
nvim_err_write(str);
nvim_err_write((String) { .data = "\n", .size = 1 });
}
/// Gets the current list of buffer handles
///
/// @return The number of buffers
ArrayOf(Buffer) vim_get_buffers(void)
ArrayOf(Buffer) nvim_get_buffers(void)
{
Array rv = ARRAY_DICT_INIT;
@ -450,7 +450,7 @@ ArrayOf(Buffer) vim_get_buffers(void)
/// Gets the current buffer
///
/// @reqturn The buffer handle
Buffer vim_get_current_buffer(void)
Buffer nvim_get_current_buffer(void)
{
return curbuf->handle;
}
@ -459,7 +459,7 @@ Buffer vim_get_current_buffer(void)
///
/// @param id The buffer handle
/// @param[out] err Details of an error that may have occurred
void vim_set_current_buffer(Buffer buffer, Error *err)
void nvim_set_current_buffer(Buffer buffer, Error *err)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@ -472,7 +472,7 @@ void vim_set_current_buffer(Buffer buffer, Error *err)
if (!try_end(err) && result == FAIL) {
api_set_error(err,
Exception,
_("Failed to switch to buffer %" PRIu64),
_("Failed to switch to buffer %d"),
buffer);
}
}
@ -480,7 +480,7 @@ void vim_set_current_buffer(Buffer buffer, Error *err)
/// Gets the current list of window handles
///
/// @return The number of windows
ArrayOf(Window) vim_get_windows(void)
ArrayOf(Window) nvim_get_windows(void)
{
Array rv = ARRAY_DICT_INIT;
@ -501,7 +501,7 @@ ArrayOf(Window) vim_get_windows(void)
/// Gets the current window
///
/// @return The window handle
Window vim_get_current_window(void)
Window nvim_get_current_window(void)
{
return curwin->handle;
}
@ -509,7 +509,7 @@ Window vim_get_current_window(void)
/// Sets the current window
///
/// @param handle The window handle
void vim_set_current_window(Window window, Error *err)
void nvim_set_current_window(Window window, Error *err)
{
win_T *win = find_window_by_handle(window, err);
@ -522,7 +522,7 @@ void vim_set_current_window(Window window, Error *err)
if (!try_end(err) && win != curwin) {
api_set_error(err,
Exception,
_("Failed to switch to window %" PRIu64),
_("Failed to switch to window %d"),
window);
}
}
@ -530,7 +530,7 @@ void vim_set_current_window(Window window, Error *err)
/// Gets the current list of tabpage handles
///
/// @return The number of tab pages
ArrayOf(Tabpage) vim_get_tabpages(void)
ArrayOf(Tabpage) nvim_get_tabpages(void)
{
Array rv = ARRAY_DICT_INIT;
@ -551,7 +551,7 @@ ArrayOf(Tabpage) vim_get_tabpages(void)
/// Gets the current tab page
///
/// @return The tab page handle
Tabpage vim_get_current_tabpage(void)
Tabpage nvim_get_current_tabpage(void)
{
return curtab->handle;
}
@ -560,7 +560,7 @@ Tabpage vim_get_current_tabpage(void)
///
/// @param handle The tab page handle
/// @param[out] err Details of an error that may have occurred
void vim_set_current_tabpage(Tabpage tabpage, Error *err)
void nvim_set_current_tabpage(Tabpage tabpage, Error *err)
{
tabpage_T *tp = find_tab_by_handle(tabpage, err);
@ -573,7 +573,7 @@ void vim_set_current_tabpage(Tabpage tabpage, Error *err)
if (!try_end(err) && tp != curtab) {
api_set_error(err,
Exception,
_("Failed to switch to tabpage %" PRIu64),
_("Failed to switch to tabpage %d"),
tabpage);
}
}
@ -582,7 +582,8 @@ void vim_set_current_tabpage(Tabpage tabpage, Error *err)
///
/// @param channel_id The channel id (passed automatically by the dispatcher)
/// @param event The event type string
void vim_subscribe(uint64_t channel_id, String event)
void nvim_subscribe(uint64_t channel_id, String event)
FUNC_API_NOEVAL
{
size_t length = (event.size < METHOD_MAXLEN ? event.size : METHOD_MAXLEN);
char e[METHOD_MAXLEN + 1];
@ -595,7 +596,8 @@ void vim_subscribe(uint64_t channel_id, String event)
///
/// @param channel_id The channel id (passed automatically by the dispatcher)
/// @param event The event type string
void vim_unsubscribe(uint64_t channel_id, String event)
void nvim_unsubscribe(uint64_t channel_id, String event)
FUNC_API_NOEVAL
{
size_t length = (event.size < METHOD_MAXLEN ?
event.size :
@ -606,12 +608,12 @@ void vim_unsubscribe(uint64_t channel_id, String event)
channel_unsubscribe(channel_id, e);
}
Integer vim_name_to_color(String name)
Integer nvim_name_to_color(String name)
{
return name_to_color((uint8_t *)name.data);
}
Dictionary vim_get_color_map(void)
Dictionary nvim_get_color_map(void)
{
Dictionary colors = ARRAY_DICT_INIT;
@ -623,8 +625,8 @@ Dictionary vim_get_color_map(void)
}
Array vim_get_api_info(uint64_t channel_id)
FUNC_API_ASYNC
Array nvim_get_api_info(uint64_t channel_id)
FUNC_API_ASYNC FUNC_API_NOEVAL
{
Array rv = ARRAY_DICT_INIT;

View File

@ -19,7 +19,7 @@
/// @param window The window handle
/// @param[out] err Details of an error that may have occurred
/// @return The buffer handle
Buffer window_get_buffer(Window window, Error *err)
Buffer nvim_win_get_buffer(Window window, Error *err)
{
win_T *win = find_window_by_handle(window, err);
@ -35,7 +35,7 @@ Buffer window_get_buffer(Window window, Error *err)
/// @param window The window handle
/// @param[out] err Details of an error that may have occurred
/// @return the (row, col) tuple
ArrayOf(Integer, 2) window_get_cursor(Window window, Error *err)
ArrayOf(Integer, 2) nvim_win_get_cursor(Window window, Error *err)
{
Array rv = ARRAY_DICT_INIT;
win_T *win = find_window_by_handle(window, err);
@ -53,7 +53,7 @@ ArrayOf(Integer, 2) window_get_cursor(Window window, Error *err)
/// @param window The window handle
/// @param pos the (row, col) tuple representing the new position
/// @param[out] err Details of an error that may have occurred
void window_set_cursor(Window window, ArrayOf(Integer, 2) pos, Error *err)
void nvim_win_set_cursor(Window window, ArrayOf(Integer, 2) pos, Error *err)
{
win_T *win = find_window_by_handle(window, err);
@ -99,7 +99,7 @@ void window_set_cursor(Window window, ArrayOf(Integer, 2) pos, Error *err)
/// @param window The window handle
/// @param[out] err Details of an error that may have occurred
/// @return the height in rows
Integer window_get_height(Window window, Error *err)
Integer nvim_win_get_height(Window window, Error *err)
{
win_T *win = find_window_by_handle(window, err);
@ -116,7 +116,7 @@ Integer window_get_height(Window window, Error *err)
/// @param window The window handle
/// @param height the new height in rows
/// @param[out] err Details of an error that may have occurred
void window_set_height(Window window, Integer height, Error *err)
void nvim_win_set_height(Window window, Integer height, Error *err)
{
win_T *win = find_window_by_handle(window, err);
@ -142,7 +142,7 @@ void window_set_height(Window window, Integer height, Error *err)
/// @param window The window handle
/// @param[out] err Details of an error that may have occurred
/// @return the width in columns
Integer window_get_width(Window window, Error *err)
Integer nvim_win_get_width(Window window, Error *err)
{
win_T *win = find_window_by_handle(window, err);
@ -159,7 +159,7 @@ Integer window_get_width(Window window, Error *err)
/// @param window The window handle
/// @param width the new width in columns
/// @param[out] err Details of an error that may have occurred
void window_set_width(Window window, Integer width, Error *err)
void nvim_win_set_width(Window window, Integer width, Error *err)
{
win_T *win = find_window_by_handle(window, err);
@ -186,7 +186,7 @@ void window_set_width(Window window, Integer width, Error *err)
/// @param name The variable name
/// @param[out] err Details of an error that may have occurred
/// @return The variable value
Object window_get_var(Window window, String name, Error *err)
Object nvim_win_get_var(Window window, String name, Error *err)
{
win_T *win = find_window_by_handle(window, err);
@ -207,7 +207,7 @@ Object window_get_var(Window window, String name, Error *err)
///
/// @warning It may return nil if there was no previous value
/// or if previous value was `v:null`.
Object window_set_var(Window window, String name, Object value, Error *err)
Object nvim_win_set_var(Window window, String name, Object value, Error *err)
{
win_T *win = find_window_by_handle(window, err);
@ -227,7 +227,7 @@ Object window_set_var(Window window, String name, Object value, Error *err)
///
/// @warning It may return nil if there was no previous value
/// or if previous value was `v:null`.
Object window_del_var(Window window, String name, Error *err)
Object nvim_win_del_var(Window window, String name, Error *err)
{
win_T *win = find_window_by_handle(window, err);
@ -244,7 +244,7 @@ Object window_del_var(Window window, String name, Error *err)
/// @param name The option name
/// @param[out] err Details of an error that may have occurred
/// @return The option value
Object window_get_option(Window window, String name, Error *err)
Object nvim_win_get_option(Window window, String name, Error *err)
{
win_T *win = find_window_by_handle(window, err);
@ -262,7 +262,7 @@ Object window_get_option(Window window, String name, Error *err)
/// @param name The option name
/// @param value The option value
/// @param[out] err Details of an error that may have occurred
void window_set_option(Window window, String name, Object value, Error *err)
void nvim_win_set_option(Window window, String name, Object value, Error *err)
{
win_T *win = find_window_by_handle(window, err);
@ -278,7 +278,7 @@ void window_set_option(Window window, String name, Object value, Error *err)
/// @param window The window handle
/// @param[out] err Details of an error that may have occurred
/// @return The (row, col) tuple with the window position
ArrayOf(Integer, 2) window_get_position(Window window, Error *err)
ArrayOf(Integer, 2) nvim_win_get_position(Window window, Error *err)
{
Array rv = ARRAY_DICT_INIT;
win_T *win = find_window_by_handle(window, err);
@ -296,7 +296,7 @@ ArrayOf(Integer, 2) window_get_position(Window window, Error *err)
/// @param window The window handle
/// @param[out] err Details of an error that may have occurred
/// @return The tab page that contains the window
Tabpage window_get_tabpage(Window window, Error *err)
Tabpage nvim_win_get_tabpage(Window window, Error *err)
{
Tabpage rv = 0;
win_T *win = find_window_by_handle(window, err);
@ -312,7 +312,7 @@ Tabpage window_get_tabpage(Window window, Error *err)
///
/// @param window The window handle
/// @return true if the window is valid, false otherwise
Boolean window_is_valid(Window window)
Boolean nvim_win_is_valid(Window window)
{
Error stub = ERROR_INIT;
return find_window_by_handle(window, &stub) != NULL;

View File

@ -1397,8 +1397,7 @@ buflist_new (
}
if (buf != curbuf || curbuf == NULL) {
buf = xcalloc(1, sizeof(buf_T));
handle_register_buffer(buf);
/* init b: variables */
// init b: variables
buf->b_vars = dict_alloc();
init_var_dict(buf->b_vars, &buf->b_bufvar, VAR_SCOPE);
}
@ -1451,11 +1450,12 @@ buflist_new (
lastbuf = buf;
buf->b_fnum = top_file_num++;
if (top_file_num < 0) { /* wrap around (may cause duplicates) */
handle_register_buffer(buf);
if (top_file_num < 0) { // wrap around (may cause duplicates)
EMSG(_("W14: Warning: List of file names overflow"));
if (emsg_silent == 0) {
ui_flush();
os_delay(3000L, true); /* make sure it is noticed */
os_delay(3000L, true); // make sure it is noticed
}
top_file_num = 1;
}
@ -5231,12 +5231,12 @@ wipe_buffer (
int aucmd /* When TRUE trigger autocommands. */
)
{
if (buf->b_fnum == top_file_num - 1)
--top_file_num;
if (!aucmd) /* Don't trigger BufDelete autocommands here. */
if (!aucmd) {
// Don't trigger BufDelete autocommands here.
block_autocmds();
close_buffer(NULL, buf, DOBUF_WIPE, FALSE);
if (!aucmd)
}
close_buffer(NULL, buf, DOBUF_WIPE, false);
if (!aucmd) {
unblock_autocmds();
}
}

View File

@ -461,9 +461,10 @@ typedef struct {
*/
struct file_buffer {
uint64_t handle; // unique identifier for the buffer
memline_T b_ml; /* associated memline (also contains line
count) */
handle_T handle; // unique id for the buffer (buffer number)
#define b_fnum handle
memline_T b_ml; // associated memline (also contains line count
buf_T *b_next; /* links in list of buffers */
buf_T *b_prev;
@ -487,8 +488,6 @@ struct file_buffer {
bool file_id_valid;
FileID file_id;
int b_fnum; /* buffer number for this file. */
bool b_changed; /* 'modified': Set to true if something in the
file has been changed and not written out. */
int b_changedtick; /* incremented for each change, also for undo */
@ -799,28 +798,27 @@ struct diffblock_S {
# define SNAP_AUCMD_IDX 1
# define SNAP_COUNT 2
/*
* Tab pages point to the top frame of each tab page.
* Note: Most values are NOT valid for the current tab page! Use "curwin",
* "firstwin", etc. for that. "tp_topframe" is always valid and can be
* compared against "topframe" to find the current tab page.
*/
/// Tab pages point to the top frame of each tab page.
/// Note: Most values are NOT valid for the current tab page! Use "curwin",
/// "firstwin", etc. for that. "tp_topframe" is always valid and can be
/// compared against "topframe" to find the current tab page.
typedef struct tabpage_S tabpage_T;
struct tabpage_S {
uint64_t handle;
tabpage_T *tp_next; /* next tabpage or NULL */
frame_T *tp_topframe; /* topframe for the windows */
win_T *tp_curwin; /* current window in this Tab page */
win_T *tp_prevwin; /* previous window in this Tab page */
win_T *tp_firstwin; /* first window in this Tab page */
win_T *tp_lastwin; /* last window in this Tab page */
long tp_old_Rows; /* Rows when Tab page was left */
long tp_old_Columns; /* Columns when Tab page was left */
long tp_ch_used; /* value of 'cmdheight' when frame size
was set */
handle_T handle;
tabpage_T *tp_next; ///< next tabpage or NULL
frame_T *tp_topframe; ///< topframe for the windows
win_T *tp_curwin; ///< current window in this Tab page
win_T *tp_prevwin; ///< previous window in this Tab page
win_T *tp_firstwin; ///< first window in this Tab page
win_T *tp_lastwin; ///< last window in this Tab page
long tp_old_Rows; ///< Rows when Tab page was left
long tp_old_Columns; ///< Columns when Tab page was left
long tp_ch_used; ///< value of 'cmdheight' when frame size
///< was set
diff_T *tp_first_diff;
buf_T *(tp_diffbuf[DB_COUNT]);
int tp_diff_invalid; ///< list of diffs is outdated */
int tp_diff_invalid; ///< list of diffs is outdated
frame_T *(tp_snapshot[SNAP_COUNT]); ///< window layout snapshots
dictitem_T tp_winvar; ///< variable for "t:" Dictionary
dict_T *tp_vars; ///< internal variables, local to tab page
@ -936,8 +934,8 @@ struct matchitem {
* All row numbers are relative to the start of the window, except w_winrow.
*/
struct window_S {
uint64_t handle;
int w_id; ///< unique window ID
handle_T handle; ///< unique identifier for the window
buf_T *w_buffer; ///< buffer we are a window into (used
///< often, keep it the first item!)

File diff suppressed because it is too large Load Diff

330
src/nvim/eval.lua Normal file
View File

@ -0,0 +1,330 @@
-- File containing table with all functions.
--
-- Keys:
--
-- args Number of arguments, list with maximum and minimum number of arguments
-- or list with a minimum number of arguments only. Defaults to zero
-- arguments.
-- func Name of the C function which implements the VimL function. Defaults to
-- `f_{funcname}`.
local varargs = function(nr)
return {nr}
end
return {
funcs={
abs={args=1},
acos={args=1, func="float_op_wrapper", data="&acos"}, -- WJMc
add={args=2},
['and']={args=2},
api_info={},
append={args=2},
argc={},
argidx={},
arglistid={args={0, 2}},
argv={args={0, 1}},
asin={args=1, func="float_op_wrapper", data="&asin"}, -- WJMc
assert_equal={args={2, 3}},
assert_exception={args={1, 2}},
assert_fails={args={1, 2}},
assert_false={args={1, 2}},
assert_match={args={2, 3}},
assert_notequal={args={2, 3}},
assert_notmatch={args={2, 3}},
assert_true={args={1, 2}},
atan={args=1, func="float_op_wrapper", data="&atan"},
atan2={args=2},
browse={args=4},
browsedir={args=2},
bufexists={args=1},
buffer_exists={args=1, func='f_bufexists'}, -- obsolete
buffer_name={args=1, func='f_bufname'}, -- obsolete
buffer_number={args=1, func='f_bufnr'}, -- obsolete
buflisted={args=1},
bufloaded={args=1},
bufname={args=1},
bufnr={args={1, 2}},
bufwinnr={args=1},
byte2line={args=1},
byteidx={args=2},
byteidxcomp={args=2},
call={args={2, 3}},
ceil={args=1, func="float_op_wrapper", data="&ceil"},
changenr={},
char2nr={args={1, 2}},
cindent={args=1},
clearmatches={},
col={args=1},
complete={args=2},
complete_add={args=1},
complete_check={},
confirm={args={1, 4}},
copy={args=1},
cos={args=1, func="float_op_wrapper", data="&cos"},
cosh={args=1, func="float_op_wrapper", data="&cosh"},
count={args={2, 4}},
cscope_connection={args={0, 3}},
cursor={args={1, 3}},
deepcopy={args={1, 2}},
delete={args={1,2}},
dictwatcheradd={args=3},
dictwatcherdel={args=3},
did_filetype={},
diff_filler={args=1},
diff_hlID={args=2},
empty={args=1},
escape={args=2},
eval={args=1},
eventhandler={},
executable={args=1},
execute={args=1},
exepath={args=1},
exists={args=1},
exp={args=1, func="float_op_wrapper", data="&exp"},
expand={args={1, 3}},
extend={args={2, 3}},
feedkeys={args={1, 2}},
file_readable={args=1, func='f_filereadable'}, -- obsolete
filereadable={args=1},
filewritable={args=1},
filter={args=2},
finddir={args={1, 3}},
findfile={args={1, 3}},
float2nr={args=1},
floor={args=1, func="float_op_wrapper", data="&floor"},
fmod={args=2},
fnameescape={args=1},
fnamemodify={args=2},
foldclosed={args=1},
foldclosedend={args=1},
foldlevel={args=1},
foldtext={},
foldtextresult={args=1},
foreground={},
['function']={args=1},
garbagecollect={args={0, 1}},
get={args={2, 3}},
getbufline={args={2, 3}},
getbufvar={args={2, 3}},
getchar={args={0, 1}},
getcharmod={},
getcharsearch={},
getcmdline={},
getcmdpos={},
getcmdtype={},
getcmdwintype={},
getcompletion={args=2},
getcurpos={},
getcwd={args={0,2}},
getfontname={args={0, 1}},
getfperm={args=1},
getfsize={args=1},
getftime={args=1},
getftype={args=1},
getline={args={1, 2}},
getloclist={args=1, func='f_getqflist'},
getmatches={},
getpid={},
getpos={args=1},
getqflist={},
getreg={args={0, 3}},
getregtype={args={0, 1}},
gettabvar={args={2, 3}},
gettabwinvar={args={3, 4}},
getwinposx={},
getwinposy={},
getwinvar={args={2, 3}},
glob={args={1, 4}},
glob2regpat={args=1},
globpath={args={2, 5}},
has={args=1},
has_key={args=2},
haslocaldir={args={0,2}},
hasmapto={args={1, 3}},
highlightID={args=1, func='f_hlID'}, -- obsolete
highlight_exists={args=1, func='f_hlexists'}, -- obsolete
histadd={args=2},
histdel={args={1, 2}},
histget={args={1, 2}},
histnr={args=1},
hlID={args=1},
hlexists={args=1},
hostname={},
iconv={args=3},
indent={args=1},
index={args={2, 4}},
input={args={1, 3}},
inputdialog={args={1, 3}},
inputlist={args=1},
inputrestore={},
inputsave={},
inputsecret={args={1, 2}},
insert={args={2, 3}},
invert={args=1},
isdirectory={args=1},
islocked={args=1},
items={args=1},
jobclose={args={1, 2}},
jobpid={args=1},
jobresize={args=3},
jobsend={args=2},
jobstart={args={1, 2}},
jobstop={args=1},
jobwait={args={1, 2}},
join={args={1, 2}},
json_decode={args=1},
json_encode={args=1},
keys={args=1},
last_buffer_nr={}, -- obsolete
len={args=1},
libcall={args=3},
libcallnr={args=3},
line={args=1},
line2byte={args=1},
lispindent={args=1},
localtime={},
log={args=1, func="float_op_wrapper", data="&log"},
log10={args=1, func="float_op_wrapper", data="&log10"},
map={args=2},
maparg={args={1, 4}},
mapcheck={args={1, 3}},
match={args={2, 4}},
matchadd={args={2, 5}},
matchaddpos={args={2, 5}},
matcharg={args=1},
matchdelete={args=1},
matchend={args={2, 4}},
matchlist={args={2, 4}},
matchstr={args={2, 4}},
max={args=1},
min={args=1},
mkdir={args={1, 3}},
mode={args={0, 1}},
msgpackdump={args=1},
msgpackparse={args=1},
nextnonblank={args=1},
nr2char={args={1, 2}},
['or']={args=2},
pathshorten={args=1},
pow={args=2},
prevnonblank={args=1},
printf={args=varargs(2)},
pumvisible={},
py3eval={args=1},
pyeval={args=1},
range={args={1, 3}},
readfile={args={1, 3}},
reltime={args={0, 2}},
reltimefloat={args=1},
reltimestr={args=1},
remove={args={2, 3}},
rename={args=2},
['repeat']={args=2},
resolve={args=1},
reverse={args=1},
round={args=1, func="float_op_wrapper", data="&round"},
rpcnotify={args=varargs(2)},
rpcrequest={args=varargs(2)},
rpcstart={args={1, 2}},
rpcstop={args=1},
screenattr={args=2},
screenchar={args=2},
screencol={},
screenrow={},
search={args={1, 4}},
searchdecl={args={1, 3}},
searchpair={args={3, 7}},
searchpairpos={args={3, 7}},
searchpos={args={1, 4}},
serverlist={},
serverstart={args={0, 1}},
serverstop={args=1},
setbufvar={args=3},
setcharsearch={args=1},
setcmdpos={args=1},
setfperm={args=2},
setline={args=2},
setloclist={args={2, 4}},
setmatches={args=1},
setpos={args=2},
setqflist={args={1, 3}},
setreg={args={2, 3}},
settabvar={args=3},
settabwinvar={args=4},
setwinvar={args=3},
sha256={args=1},
shellescape={args={1, 2}},
shiftwidth={},
simplify={args=1},
sin={args=1, func="float_op_wrapper", data="&sin"},
sinh={args=1, func="float_op_wrapper", data="&sinh"},
sort={args={1, 3}},
soundfold={args=1},
spellbadword={args={0, 1}},
spellsuggest={args={1, 3}},
split={args={1, 3}},
sqrt={args=1, func="float_op_wrapper", data="&sqrt"},
str2float={args=1},
str2nr={args={1, 2}},
strchars={args={1,2}},
strdisplaywidth={args={1, 2}},
strftime={args={1, 2}},
stridx={args={2, 3}},
string={args=1},
strlen={args=1},
strpart={args={2, 3}},
strridx={args={2, 3}},
strtrans={args=1},
strwidth={args=1},
submatch={args={1, 2}},
substitute={args=4},
synID={args=3},
synIDattr={args={2, 3}},
synIDtrans={args=1},
synconcealed={args=2},
synstack={args=2},
system={args={1, 2}},
systemlist={args={1, 3}},
tabpagebuflist={args={0, 1}},
tabpagenr={args={0, 1}},
tabpagewinnr={args={1, 2}},
tagfiles={},
taglist={args=1},
tan={args=1, func="float_op_wrapper", data="&tan"},
tanh={args=1, func="float_op_wrapper", data="&tanh"},
tempname={},
termopen={args={1, 2}},
test={args=1},
timer_start={args={2,3}},
timer_stop={args=1},
tolower={args=1},
toupper={args=1},
tr={args=3},
trunc={args=1, func="float_op_wrapper", data="&trunc"},
type={args=1},
undofile={args=1},
undotree={},
uniq={args={1, 3}},
values={args=1},
virtcol={args=1},
visualmode={args={0, 1}},
wildmenumode={},
win_getid={args={0,2}},
win_gotoid={args=1},
win_id2tabwin={args=1},
win_id2win={args=1},
winbufnr={args=1},
wincol={},
winheight={args=1},
winline={},
winnr={args={0, 1}},
winrestcmd={},
winrestview={args=1},
winsaveview={},
winwidth={args=1},
wordcount={},
writefile={args={2, 3}},
xor={args=2},
},
}

View File

@ -185,6 +185,7 @@
#ifdef DEFINE_FUNC_ATTRIBUTES
# define FUNC_API_ASYNC
# define FUNC_API_NOEXPORT
# define FUNC_API_NOEVAL
# define FUNC_ATTR_MALLOC REAL_FATTR_MALLOC
# define FUNC_ATTR_ALLOC_SIZE(x) REAL_FATTR_ALLOC_SIZE(x)
# define FUNC_ATTR_ALLOC_SIZE_PROD(x, y) REAL_FATTR_ALLOC_SIZE_PROD(x, y)

View File

@ -58,13 +58,13 @@
#include "nvim/event/loop.h"
#include "nvim/os/signal.h"
#include "nvim/event/process.h"
#include "nvim/msgpack_rpc/defs.h"
#include "nvim/msgpack_rpc/helpers.h"
#include "nvim/msgpack_rpc/server.h"
#include "nvim/msgpack_rpc/channel.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
#include "nvim/api/private/handle.h"
#include "nvim/api/private/dispatch.h"
/* Maximum number of commands from + or -c arguments. */
#define MAX_ARG_CMDS 10

View File

@ -6,7 +6,7 @@
#include "nvim/map_defs.h"
#include "nvim/vim.h"
#include "nvim/memory.h"
#include "nvim/msgpack_rpc/defs.h"
#include "nvim/api/private/dispatch.h"
#include "nvim/lib/khash.h"
@ -20,6 +20,8 @@
#define int_eq kh_int_hash_equal
#define linenr_T_hash kh_int_hash_func
#define linenr_T_eq kh_int_hash_equal
#define handle_T_hash kh_int_hash_func
#define handle_T_eq kh_int_hash_equal
#if defined(ARCH_64)
@ -141,7 +143,8 @@ MAP_IMPL(cstr_t, uint64_t, DEFAULT_INITIALIZER)
MAP_IMPL(cstr_t, ptr_t, DEFAULT_INITIALIZER)
MAP_IMPL(ptr_t, ptr_t, DEFAULT_INITIALIZER)
MAP_IMPL(uint64_t, ptr_t, DEFAULT_INITIALIZER)
#define MSGPACK_HANDLER_INITIALIZER {.fn = NULL, .async = false}
MAP_IMPL(handle_T, ptr_t, DEFAULT_INITIALIZER)
#define MSGPACK_HANDLER_INITIALIZER { .fn = NULL, .async = false }
MAP_IMPL(String, MsgpackRpcRequestHandler, MSGPACK_HANDLER_INITIALIZER)
#define KVEC_INITIALIZER { .size = 0, .capacity = 0, .items = NULL }
MAP_IMPL(linenr_T, bufhl_vec_T, KVEC_INITIALIZER)

View File

@ -5,7 +5,7 @@
#include "nvim/map_defs.h"
#include "nvim/api/private/defs.h"
#include "nvim/msgpack_rpc/defs.h"
#include "nvim/api/private/dispatch.h"
#include "nvim/bufhl_defs.h"
#define MAP_DECLS(T, U) \
@ -29,6 +29,7 @@ MAP_DECLS(cstr_t, uint64_t)
MAP_DECLS(cstr_t, ptr_t)
MAP_DECLS(ptr_t, ptr_t)
MAP_DECLS(uint64_t, ptr_t)
MAP_DECLS(handle_T, ptr_t)
MAP_DECLS(String, MsgpackRpcRequestHandler)
MAP_DECLS(linenr_T, bufhl_vec_T)

View File

@ -465,8 +465,7 @@ static void on_request_event(void **argv)
} else {
api_free_object(result);
}
// All arguments were freed already, but we still need to free the array
xfree(args.items);
api_free_array(args);
decref(channel);
xfree(e);
}

View File

@ -1,28 +0,0 @@
#ifndef NVIM_MSGPACK_RPC_DEFS_H
#define NVIM_MSGPACK_RPC_DEFS_H
/// The rpc_method_handlers table, used in msgpack_rpc_dispatch(), stores
/// functions of this type.
typedef struct {
Object (*fn)(uint64_t channel_id,
uint64_t request_id,
Array args,
Error *error);
bool async; // function is always safe to run immediately instead of being
// put in a request queue for handling when nvim waits for input.
} MsgpackRpcRequestHandler;
/// Initializes the msgpack-rpc method table
void msgpack_rpc_init_method_table(void);
// Add a handler to the method table
void msgpack_rpc_add_method_handler(String method,
MsgpackRpcRequestHandler handler);
void msgpack_rpc_init_function_metadata(Dictionary *metadata);
MsgpackRpcRequestHandler msgpack_rpc_get_handler_for(const char *name,
size_t name_len)
FUNC_ATTR_NONNULL_ARG(1);
#endif // NVIM_MSGPACK_RPC_DEFS_H

View File

@ -4,9 +4,9 @@
#include <msgpack.h>
#include "nvim/api/private/dispatch.h"
#include "nvim/api/private/helpers.h"
#include "nvim/msgpack_rpc/helpers.h"
#include "nvim/msgpack_rpc/defs.h"
#include "nvim/lib/kvec.h"
#include "nvim/vim.h"
#include "nvim/log.h"
@ -40,7 +40,7 @@ static msgpack_sbuffer sbuffer;
return false; \
} \
\
*arg = data.via.u64; \
*arg = (handle_T)data.via.i64; \
return true; \
} \
\
@ -49,7 +49,7 @@ static msgpack_sbuffer sbuffer;
{ \
msgpack_packer pac; \
msgpack_packer_init(&pac, &sbuffer, msgpack_sbuffer_write); \
msgpack_pack_uint64(&pac, o); \
msgpack_pack_int64(&pac, o); \
msgpack_pack_ext(res, sbuffer.size, kObjectType##t); \
msgpack_pack_ext_body(res, sbuffer.data, sbuffer.size); \
msgpack_sbuffer_clear(&sbuffer); \

View File

@ -127,7 +127,7 @@ struct terminal {
// we can't store a direct reference to the buffer because the
// refresh_timer_cb may be called after the buffer was freed, and there's
// no way to know if the memory was reused.
uint64_t buf_handle;
handle_T buf_handle;
// program exited
bool closed, destroy;
// some vterm properties

View File

@ -216,8 +216,8 @@ static int get_key_code_timeout(void)
// Check 'ttimeout' to determine if we should send ESC after 'ttimeoutlen'.
// See :help 'ttimeout' for more information
Error err = ERROR_INIT;
if (vim_get_option(cstr_as_string("ttimeout"), &err).data.boolean) {
ms = vim_get_option(cstr_as_string("ttimeoutlen"), &err).data.integer;
if (nvim_get_option(cstr_as_string("ttimeout"), &err).data.boolean) {
ms = nvim_get_option(cstr_as_string("ttimeoutlen"), &err).data.integer;
}
return (int)ms;

View File

@ -2926,7 +2926,9 @@ void win_init_size(void)
*/
static tabpage_T *alloc_tabpage(void)
{
static int last_tp_handle = 0;
tabpage_T *tp = xcalloc(1, sizeof(tabpage_T));
tp->handle = ++last_tp_handle;
handle_register_tabpage(tp);
/* init t: variables */
@ -3683,21 +3685,20 @@ win_T *buf_jump_open_tab(buf_T *buf)
return NULL;
}
static int last_win_id = 0;
/*
* Allocate a window structure and link it in the window list when "hidden" is
* FALSE.
*/
static win_T *win_alloc(win_T *after, int hidden)
{
/*
* allocate window structure and linesizes arrays
*/
static int last_win_id = 0;
// allocate window structure and linesizes arrays
win_T *new_wp = xcalloc(1, sizeof(win_T));
handle_register_window(new_wp);
win_alloc_lines(new_wp);
new_wp->w_id = ++last_win_id;
new_wp->handle = ++last_win_id;
handle_register_window(new_wp);
/* init w: variables */
new_wp->w_vars = dict_alloc();
@ -5681,7 +5682,7 @@ static bool frame_check_width(frame_T *topfrp, int width)
int win_getid(typval_T *argvars)
{
if (argvars[0].v_type == VAR_UNKNOWN) {
return curwin->w_id;
return curwin->handle;
}
int winnr = get_tv_number(&argvars[0]);
win_T *wp;
@ -5703,7 +5704,7 @@ int win_getid(typval_T *argvars)
}
for ( ; wp != NULL; wp = wp->w_next) {
if (--winnr == 0) {
return wp->w_id;
return wp->handle;
}
}
}
@ -5719,7 +5720,7 @@ int win_gotoid(typval_T *argvars)
for (tp = first_tabpage; tp != NULL; tp = tp->tp_next) {
for (wp = tp == curtab ? firstwin : tp->tp_firstwin;
wp != NULL; wp = wp->w_next) {
if (wp->w_id == id) {
if (wp->handle == id) {
goto_tabpage_win(tp, wp);
return 1;
}
@ -5739,7 +5740,7 @@ void win_id2tabwin(typval_T *argvars, list_T *list)
for (tp = first_tabpage; tp != NULL; tp = tp->tp_next) {
for (wp = tp == curtab ? firstwin : tp->tp_firstwin;
wp != NULL; wp = wp->w_next) {
if (wp->w_id == id) {
if (wp->handle == id) {
list_append_number(list, tabnr);
list_append_number(list, winnr);
return;
@ -5760,7 +5761,7 @@ int win_id2win(typval_T *argvars)
int id = get_tv_number(&argvars[0]);
for (wp = firstwin; wp != NULL; wp = wp->w_next) {
if (wp->w_id == id) {
if (wp->handle == id) {
return nr;
}
nr++;

View File

@ -3,105 +3,111 @@ local helpers = require('test.functional.helpers')(after_each)
local clear, nvim, buffer = helpers.clear, helpers.nvim, helpers.buffer
local curbuf, curwin, eq = helpers.curbuf, helpers.curwin, helpers.eq
local curbufmeths, ok = helpers.curbufmeths, helpers.ok
local funcs = helpers.funcs
local funcs, request = helpers.funcs, helpers.request
describe('buffer_* functions', function()
before_each(clear)
-- access deprecated functions
local function curbuf_depr(method, ...)
return request('buffer_'..method, 0, ...)
end
describe('line_count, insert and del_line', function()
it('works', function()
eq(1, curbuf('line_count'))
curbuf('insert', -1, {'line'})
eq(2, curbuf('line_count'))
curbuf('insert', -1, {'line'})
eq(3, curbuf('line_count'))
curbuf('del_line', -1)
eq(2, curbuf('line_count'))
curbuf('del_line', -1)
curbuf('del_line', -1)
eq(1, curbuf_depr('line_count'))
curbuf_depr('insert', -1, {'line'})
eq(2, curbuf_depr('line_count'))
curbuf_depr('insert', -1, {'line'})
eq(3, curbuf_depr('line_count'))
curbuf_depr('del_line', -1)
eq(2, curbuf_depr('line_count'))
curbuf_depr('del_line', -1)
curbuf_depr('del_line', -1)
-- There's always at least one line
eq(1, curbuf('line_count'))
eq(1, curbuf_depr('line_count'))
end)
end)
describe('{get,set,del}_line', function()
it('works', function()
eq('', curbuf('get_line', 0))
curbuf('set_line', 0, 'line1')
eq('line1', curbuf('get_line', 0))
curbuf('set_line', 0, 'line2')
eq('line2', curbuf('get_line', 0))
curbuf('del_line', 0)
eq('', curbuf('get_line', 0))
eq('', curbuf_depr('get_line', 0))
curbuf_depr('set_line', 0, 'line1')
eq('line1', curbuf_depr('get_line', 0))
curbuf_depr('set_line', 0, 'line2')
eq('line2', curbuf_depr('get_line', 0))
curbuf_depr('del_line', 0)
eq('', curbuf_depr('get_line', 0))
end)
it('get_line: out-of-bounds is an error', function()
curbuf('set_line', 0, 'line1.a')
eq(1, curbuf('line_count')) -- sanity
eq(false, pcall(curbuf, 'get_line', 1))
eq(false, pcall(curbuf, 'get_line', -2))
curbuf_depr('set_line', 0, 'line1.a')
eq(1, curbuf_depr('line_count')) -- sanity
eq(false, pcall(curbuf_depr, 'get_line', 1))
eq(false, pcall(curbuf_depr, 'get_line', -2))
end)
it('set_line, del_line: out-of-bounds is an error', function()
curbuf('set_line', 0, 'line1.a')
eq(false, pcall(curbuf, 'set_line', 1, 'line1.b'))
eq(false, pcall(curbuf, 'set_line', -2, 'line1.b'))
eq(false, pcall(curbuf, 'del_line', 2))
eq(false, pcall(curbuf, 'del_line', -3))
curbuf_depr('set_line', 0, 'line1.a')
eq(false, pcall(curbuf_depr, 'set_line', 1, 'line1.b'))
eq(false, pcall(curbuf_depr, 'set_line', -2, 'line1.b'))
eq(false, pcall(curbuf_depr, 'del_line', 2))
eq(false, pcall(curbuf_depr, 'del_line', -3))
end)
it('can handle NULs', function()
curbuf('set_line', 0, 'ab\0cd')
eq('ab\0cd', curbuf('get_line', 0))
curbuf_depr('set_line', 0, 'ab\0cd')
eq('ab\0cd', curbuf_depr('get_line', 0))
end)
end)
describe('{get,set}_line_slice', function()
it('get_line_slice: out-of-bounds returns empty array', function()
curbuf('set_line_slice', 0, 0, true, true, {'a', 'b', 'c'})
eq({'a', 'b', 'c'}, curbuf('get_line_slice', 0, 2, true, true)) --sanity
curbuf_depr('set_line_slice', 0, 0, true, true, {'a', 'b', 'c'})
eq({'a', 'b', 'c'}, curbuf_depr('get_line_slice', 0, 2, true, true)) --sanity
eq({}, curbuf('get_line_slice', 2, 3, false, true))
eq({}, curbuf('get_line_slice', 3, 9, true, true))
eq({}, curbuf('get_line_slice', 3, -1, true, true))
eq({}, curbuf('get_line_slice', -3, -4, false, true))
eq({}, curbuf('get_line_slice', -4, -5, true, true))
eq({}, curbuf_depr('get_line_slice', 2, 3, false, true))
eq({}, curbuf_depr('get_line_slice', 3, 9, true, true))
eq({}, curbuf_depr('get_line_slice', 3, -1, true, true))
eq({}, curbuf_depr('get_line_slice', -3, -4, false, true))
eq({}, curbuf_depr('get_line_slice', -4, -5, true, true))
end)
it('set_line_slice: out-of-bounds extends past end', function()
curbuf('set_line_slice', 0, 0, true, true, {'a', 'b', 'c'})
eq({'a', 'b', 'c'}, curbuf('get_line_slice', 0, 2, true, true)) --sanity
curbuf_depr('set_line_slice', 0, 0, true, true, {'a', 'b', 'c'})
eq({'a', 'b', 'c'}, curbuf_depr('get_line_slice', 0, 2, true, true)) --sanity
eq({'c'}, curbuf('get_line_slice', -1, 4, true, true))
eq({'a', 'b', 'c'}, curbuf('get_line_slice', 0, 5, true, true))
curbuf('set_line_slice', 4, 5, true, true, {'d'})
eq({'a', 'b', 'c', 'd'}, curbuf('get_line_slice', 0, 5, true, true))
curbuf('set_line_slice', -4, -5, true, true, {'e'})
eq({'e', 'a', 'b', 'c', 'd'}, curbuf('get_line_slice', 0, 5, true, true))
eq({'c'}, curbuf_depr('get_line_slice', -1, 4, true, true))
eq({'a', 'b', 'c'}, curbuf_depr('get_line_slice', 0, 5, true, true))
curbuf_depr('set_line_slice', 4, 5, true, true, {'d'})
eq({'a', 'b', 'c', 'd'}, curbuf_depr('get_line_slice', 0, 5, true, true))
curbuf_depr('set_line_slice', -4, -5, true, true, {'e'})
eq({'e', 'a', 'b', 'c', 'd'}, curbuf_depr('get_line_slice', 0, 5, true, true))
end)
it('works', function()
eq({''}, curbuf('get_line_slice', 0, -1, true, true))
eq({''}, curbuf_depr('get_line_slice', 0, -1, true, true))
-- Replace buffer
curbuf('set_line_slice', 0, -1, true, true, {'a', 'b', 'c'})
eq({'a', 'b', 'c'}, curbuf('get_line_slice', 0, -1, true, true))
eq({'b', 'c'}, curbuf('get_line_slice', 1, -1, true, true))
eq({'b'}, curbuf('get_line_slice', 1, 2, true, false))
eq({}, curbuf('get_line_slice', 1, 1, true, false))
eq({'a', 'b'}, curbuf('get_line_slice', 0, -1, true, false))
eq({'b'}, curbuf('get_line_slice', 1, -1, true, false))
eq({'b', 'c'}, curbuf('get_line_slice', -2, -1, true, true))
curbuf('set_line_slice', 1, 2, true, false, {'a', 'b', 'c'})
eq({'a', 'a', 'b', 'c', 'c'}, curbuf('get_line_slice', 0, -1, true, true))
curbuf('set_line_slice', -1, -1, true, true, {'a', 'b', 'c'})
curbuf_depr('set_line_slice', 0, -1, true, true, {'a', 'b', 'c'})
eq({'a', 'b', 'c'}, curbuf_depr('get_line_slice', 0, -1, true, true))
eq({'b', 'c'}, curbuf_depr('get_line_slice', 1, -1, true, true))
eq({'b'}, curbuf_depr('get_line_slice', 1, 2, true, false))
eq({}, curbuf_depr('get_line_slice', 1, 1, true, false))
eq({'a', 'b'}, curbuf_depr('get_line_slice', 0, -1, true, false))
eq({'b'}, curbuf_depr('get_line_slice', 1, -1, true, false))
eq({'b', 'c'}, curbuf_depr('get_line_slice', -2, -1, true, true))
curbuf_depr('set_line_slice', 1, 2, true, false, {'a', 'b', 'c'})
eq({'a', 'a', 'b', 'c', 'c'}, curbuf_depr('get_line_slice', 0, -1, true, true))
curbuf_depr('set_line_slice', -1, -1, true, true, {'a', 'b', 'c'})
eq({'a', 'a', 'b', 'c', 'a', 'b', 'c'},
curbuf('get_line_slice', 0, -1, true, true))
curbuf('set_line_slice', 0, -3, true, false, {})
eq({'a', 'b', 'c'}, curbuf('get_line_slice', 0, -1, true, true))
curbuf('set_line_slice', 0, -1, true, true, {})
eq({''}, curbuf('get_line_slice', 0, -1, true, true))
curbuf_depr('get_line_slice', 0, -1, true, true))
curbuf_depr('set_line_slice', 0, -3, true, false, {})
eq({'a', 'b', 'c'}, curbuf_depr('get_line_slice', 0, -1, true, true))
curbuf_depr('set_line_slice', 0, -1, true, true, {})
eq({''}, curbuf_depr('get_line_slice', 0, -1, true, true))
end)
end)
@ -286,7 +292,7 @@ describe('buffer_* functions', function()
describe('get_mark', function()
it('works', function()
curbuf('insert', -1, {'a', 'bit of', 'text'})
curbuf('set_lines', -1, -1, true, {'a', 'bit of', 'text'})
curwin('set_cursor', {3, 4})
nvim('command', 'mark V')
eq({3, 0}, curbuf('get_mark', 'V'))

View File

@ -163,11 +163,11 @@ describe('server -> client', function()
end)
it('can communicate buffers, tabpages, and windows', function()
eq({3}, eval("rpcrequest(vim, 'vim_get_tabpages')"))
eq({1}, eval("rpcrequest(vim, 'vim_get_tabpages')"))
eq({1}, eval("rpcrequest(vim, 'vim_get_windows')"))
local buf = eval("rpcrequest(vim, 'vim_get_buffers')")[1]
eq(2, buf)
eq(1, buf)
eval("rpcnotify(vim, 'buffer_set_line', "..buf..", 0, 'SOME TEXT')")
nvim('command', "call rpcrequest(vim, 'vim_eval', '0')") -- wait

View File

@ -7,6 +7,7 @@ local ok, nvim_async, feed = helpers.ok, helpers.nvim_async, helpers.feed
local os_name = helpers.os_name
local meths = helpers.meths
local funcs = helpers.funcs
local request = helpers.request
describe('vim_* functions', function()
before_each(clear)
@ -41,6 +42,10 @@ describe('vim_* functions', function()
eq(1, nvim('eval',"matcharg(1) == ['', '']"))
eq({'', ''}, nvim('eval','matcharg(1)'))
end)
it('works under deprecated name', function()
eq(2, request("vim_eval", "1+1"))
end)
end)
describe('call_function', function()
@ -298,4 +303,11 @@ describe('vim_* functions', function()
eq(false, status)
ok(err:match('Invalid option name') ~= nil)
end)
it("doesn't leak memory on incorrect argument types", function()
local status, err = pcall(nvim, 'change_directory',{'not', 'a', 'dir'})
eq(false, status)
ok(err:match(': Wrong type for argument 1, expecting String') ~= nil)
end)
end)

View File

@ -0,0 +1,148 @@
local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local lfs = require('lfs')
local neq, eq, execute = helpers.neq, helpers.eq, helpers.execute
local clear, curbufmeths = helpers.clear, helpers.curbufmeths
local exc_exec, expect, eval = helpers.exc_exec, helpers.expect, helpers.eval
local insert = helpers.insert
describe('api functions', function()
before_each(clear)
it("work", function()
execute("call nvim_command('let g:test = 1')")
eq(1, eval("nvim_get_var('test')"))
local buf = eval("nvim_get_current_buffer()")
execute("call nvim_buf_set_lines("..buf..", 0, -1, v:true, ['aa', 'bb'])")
expect([[
aa
bb]])
execute("call nvim_win_set_cursor(0, [1, 1])")
execute("call nvim_input('ax<esc>')")
expect([[
aax
bb]])
end)
it("throw errors for invalid arguments", function()
local err = exc_exec('call nvim_get_current_buffer("foo")')
eq('Vim(call):E118: Too many arguments for function: nvim_get_current_buffer', err)
err = exc_exec('call nvim_set_option("hlsearch")')
eq('Vim(call):E119: Not enough arguments for function: nvim_set_option', err)
err = exc_exec('call nvim_buf_set_lines(1, 0, -1, [], ["list"])')
eq('Vim(call):Wrong type for argument 4, expecting Boolean', err)
err = exc_exec('call nvim_buf_set_lines(0, 0, -1, v:true, "string")')
eq('Vim(call):Wrong type for argument 5, expecting ArrayOf(String)', err)
err = exc_exec('call nvim_buf_get_number("0")')
eq('Vim(call):Wrong type for argument 1, expecting Buffer', err)
err = exc_exec('call nvim_buf_line_count(17)')
eq('Vim(call):Invalid buffer id', err)
end)
it("use buffer numbers and windows ids as handles", function()
local screen = Screen.new(40, 8)
screen:attach()
local bnr = eval("bufnr('')")
local bhnd = eval("nvim_get_current_buffer()")
local wid = eval("win_getid()")
local whnd = eval("nvim_get_current_window()")
eq(bnr, bhnd)
eq(wid, whnd)
execute("new") -- creates new buffer and new window
local bnr2 = eval("bufnr('')")
local bhnd2 = eval("nvim_get_current_buffer()")
local wid2 = eval("win_getid()")
local whnd2 = eval("nvim_get_current_window()")
eq(bnr2, bhnd2)
eq(wid2, whnd2)
neq(bnr, bnr2)
neq(wid, wid2)
-- 0 is synonymous to the current buffer
eq(bnr2, eval("nvim_buf_get_number(0)"))
execute("bn") -- show old buffer in new window
eq(bnr, eval("nvim_get_current_buffer()"))
eq(bnr, eval("bufnr('')"))
eq(bnr, eval("nvim_buf_get_number(0)"))
eq(wid2, eval("win_getid()"))
eq(whnd2, eval("nvim_get_current_window()"))
end)
it("get_lines and set_lines use NL to represent NUL", function()
curbufmeths.set_lines(0, -1, true, {"aa\0", "b\0b"})
eq({'aa\n', 'b\nb'}, eval("nvim_buf_get_lines(0, 0, -1, 1)"))
execute('call nvim_buf_set_lines(0, 1, 2, v:true, ["xx", "\\nyy"])')
eq({'aa\0', 'xx', '\0yy'}, curbufmeths.get_lines(0, -1, 1))
end)
it("that are FUNC_ATTR_NOEVAL cannot be called", function()
-- Deprecated vim_ prefix is not exported.
local err = exc_exec('call vim_get_current_buffer("foo")')
eq('Vim(call):E117: Unknown function: vim_get_current_buffer', err)
-- Deprecated buffer_ prefix is not exported.
err = exc_exec('call buffer_line_count(0)')
eq('Vim(call):E117: Unknown function: buffer_line_count', err)
-- Functions deprecated before the api functions became available
-- in vimscript are not exported.
err = exc_exec('call buffer_get_line(0, 1)')
eq('Vim(call):E117: Unknown function: buffer_get_line', err)
-- some api functions are only useful from a msgpack-rpc channel
err = exc_exec('call nvim_subscribe("fancyevent")')
eq('Vim(call):E117: Unknown function: nvim_subscribe', err)
end)
it('have metadata accessible with api_info()', function()
local api_keys = eval("sort(keys(api_info()))")
eq({'error_types', 'functions', 'types'}, api_keys)
end)
it('are highlighted by vim.vim syntax file', function()
if lfs.attributes("build/runtime/syntax/vim/generated.vim",'uid') == nil then
pending("runtime was not built, skipping test")
return
end
local screen = Screen.new(40, 8)
screen:attach()
screen:set_default_attr_ids({
[1] = {bold = true, foreground = Screen.colors.Brown},
[2] = {foreground = Screen.colors.DarkCyan},
[3] = {foreground = Screen.colors.SlateBlue},
[4] = {foreground = Screen.colors.Fuchsia},
[5] = {bold = true, foreground = Screen.colors.Blue},
})
execute("set ft=vim")
execute("let &rtp='build/runtime/,'.&rtp")
execute("syntax on")
insert([[
call bufnr('%')
call nvim_input('typing...')
call not_a_function(42)]])
screen:expect([[
{1:call} {2:bufnr}{3:(}{4:'%'}{3:)} |
{1:call} {2:nvim_input}{3:(}{4:'typing...'}{3:)} |
{1:call} not_a_function{3:(}{4:42}{3:^)} |
{5:~ }|
{5:~ }|
{5:~ }|
{5:~ }|
|
]])
screen:detach()
end)
end)

View File

@ -133,11 +133,11 @@ local function stop()
end
local function nvim_command(cmd)
request('vim_command', cmd)
request('nvim_command', cmd)
end
local function nvim_eval(expr)
return request('vim_eval', expr)
return request('nvim_eval', expr)
end
local os_name = (function()
@ -157,12 +157,12 @@ local os_name = (function()
end)()
local function nvim_call(name, ...)
return request('vim_call_function', name, {...})
return request('nvim_call_function', name, {...})
end
local function nvim_feed(input)
while #input > 0 do
local written = request('vim_input', input)
local written = request('nvim_input', input)
input = input:sub(written + 1)
end
end
@ -339,7 +339,7 @@ local function source(code)
end
local function nvim(method, ...)
return request('vim_'..method, ...)
return request('nvim_'..method, ...)
end
local function ui(method, ...)
@ -347,27 +347,26 @@ local function ui(method, ...)
end
local function nvim_async(method, ...)
session:notify('vim_'..method, ...)
session:notify('nvim_'..method, ...)
end
local function buffer(method, ...)
return request('buffer_'..method, ...)
return request('nvim_buf_'..method, ...)
end
local function window(method, ...)
return request('window_'..method, ...)
return request('nvim_win_'..method, ...)
end
local function tabpage(method, ...)
return request('tabpage_'..method, ...)
return request('nvim_tabpage_'..method, ...)
end
local function curbuf(method, ...)
local buf = nvim('get_current_buffer')
if not method then
return buf
return nvim('get_current_buffer')
end
return buffer(method, buf, ...)
return buffer(method, 0, ...)
end
local function wait()
@ -387,19 +386,17 @@ local function curbuf_contents()
end
local function curwin(method, ...)
local win = nvim('get_current_window')
if not method then
return win
return nvim('get_current_window')
end
return window(method, win, ...)
return window(method, 0, ...)
end
local function curtab(method, ...)
local tab = nvim('get_current_tabpage')
if not method then
return tab
return nvim('get_current_tabpage')
end
return tabpage(method, tab, ...)
return tabpage(method, 0, ...)
end
local function expect(contents)

View File

@ -2463,17 +2463,17 @@ describe('ftplugin/shada.vim', function()
nvim_command('setlocal filetype=shada')
funcs.setline(1, ' Replacement with timestamp ' .. epoch)
nvim_feed('ggA:\027')
eq('Replacement with timestamp ' .. epoch .. ':', curbuf('get_line', 0))
eq('Replacement with timestamp ' .. epoch .. ':', curbuf('get_lines', 0, 1, true)[1])
nvim_feed('o-\027')
eq(' -', curbuf('get_line', 1))
eq({' -'}, curbuf('get_lines', 1, 2, true))
nvim_feed('ggO+\027')
eq('+', curbuf('get_line', 0))
eq({'+'}, curbuf('get_lines', 0, 1, true))
nvim_feed('GO*\027')
eq(' *', curbuf('get_line', 2))
eq({' *'}, curbuf('get_lines', 2, 3, true))
nvim_feed('ggO /\027')
eq(' /', curbuf('get_line', 0))
eq({' /'}, curbuf('get_lines', 0, 1, true))
nvim_feed('ggOx\027')
eq('x', curbuf('get_line', 0))
eq({'x'}, curbuf('get_lines', 0, 1, true))
end)
end)

View File

@ -80,9 +80,9 @@ describe('ShaDa support code', function()
it('does not dump unnamed buffers', function()
set_additional_cmd('set shada+=% hidden')
reset()
curbufmeths.set_line(0, 'foo')
curbufmeths.set_lines(0, 1, true, {'foo'})
nvim_command('enew')
curbufmeths.set_line(0, 'bar')
curbufmeths.set_lines(0, 1, true, {'bar'})
eq(2, funcs.bufnr('$'))
nvim_command('qall!')
reset()

View File

@ -2,7 +2,6 @@ local helpers = require('test.functional.helpers')(after_each)
local clear = helpers.clear
local eq = helpers.eq
local eval = helpers.eval
local exc_exec = helpers.exc_exec
describe('Up to MAX_FUNC_ARGS arguments are handled by', function()
@ -28,11 +27,3 @@ describe('Up to MAX_FUNC_ARGS arguments are handled by', function()
eq('Vim(call):E740: Too many arguments for function rpcnotify', ret)
end)
end)
describe('api_info()', function()
before_each(clear)
it('has the right keys', function()
local api_keys = eval("sort(keys(api_info()))")
eq({'error_types', 'functions', 'types'}, api_keys)
end)
end)

View File

@ -87,7 +87,7 @@ describe('buffer functions', function()
it('should find exact matches', function()
local buf = buflist_new(path1, buffer.BLN_LISTED)
eq(buf.b_fnum, buflist_findpat(path1, ONLY_LISTED))
eq(buf.handle, buflist_findpat(path1, ONLY_LISTED))
close_buffer(NULL, buf, buffer.DOBUF_WIPE, 0)
end)
@ -97,9 +97,9 @@ describe('buffer functions', function()
local buf2 = buflist_new(path2, buffer.BLN_LISTED)
local buf3 = buflist_new(path3, buffer.BLN_LISTED)
eq(buf1.b_fnum, buflist_findpat("test", ONLY_LISTED))
eq(buf2.b_fnum, buflist_findpat("file", ONLY_LISTED))
eq(buf3.b_fnum, buflist_findpat("path", ONLY_LISTED))
eq(buf1.handle, buflist_findpat("test", ONLY_LISTED))
eq(buf2.handle, buflist_findpat("file", ONLY_LISTED))
eq(buf3.handle, buflist_findpat("path", ONLY_LISTED))
close_buffer(NULL, buf1, buffer.DOBUF_WIPE, 0)
close_buffer(NULL, buf2, buffer.DOBUF_WIPE, 0)
@ -113,7 +113,7 @@ describe('buffer functions', function()
local buf3 = buflist_new(path3, buffer.BLN_LISTED)
-- Then: buf2 is the buffer that is found
eq(buf2.b_fnum, buflist_findpat("test", ONLY_LISTED))
eq(buf2.handle, buflist_findpat("test", ONLY_LISTED))
--}
--{ When: We close buf2
@ -123,7 +123,7 @@ describe('buffer functions', function()
local buf1 = buflist_new(path1, buffer.BLN_LISTED)
-- Then: buf3 is found since 'file' appears at the end of the name
eq(buf3.b_fnum, buflist_findpat("file", ONLY_LISTED))
eq(buf3.handle, buflist_findpat("file", ONLY_LISTED))
--}
close_buffer(NULL, buf1, buffer.DOBUF_WIPE, 0)
@ -135,7 +135,7 @@ describe('buffer functions', function()
local buf2 = buflist_new(path2, buffer.BLN_LISTED)
local buf3 = buflist_new(path3, buffer.BLN_LISTED)
eq(buf3.b_fnum, buflist_findpat("_test_", ONLY_LISTED))
eq(buf3.handle, buflist_findpat("_test_", ONLY_LISTED))
close_buffer(NULL, buf1, buffer.DOBUF_WIPE, 0)
close_buffer(NULL, buf2, buffer.DOBUF_WIPE, 0)
@ -147,7 +147,7 @@ describe('buffer functions', function()
local buf3 = buflist_new(path3, buffer.BLN_LISTED)
-- Then: We should find the buffer when it is given a unique pattern
eq(buf3.b_fnum, buflist_findpat("_test_", ONLY_LISTED))
eq(buf3.handle, buflist_findpat("_test_", ONLY_LISTED))
--}
--{ When: We unlist the buffer
@ -157,7 +157,7 @@ describe('buffer functions', function()
eq(-1, buflist_findpat("_test_", ONLY_LISTED))
-- And: It should find the buffer when including unlisted buffers
eq(buf3.b_fnum, buflist_findpat("_test_", ALLOW_UNLISTED))
eq(buf3.handle, buflist_findpat("_test_", ALLOW_UNLISTED))
--}
--{ When: We wipe the buffer
@ -175,7 +175,7 @@ describe('buffer functions', function()
local buf2 = buflist_new(path2, buffer.BLN_LISTED)
-- Then: The first buffer is preferred when both are listed
eq(buf1.b_fnum, buflist_findpat("test", ONLY_LISTED))
eq(buf1.handle, buflist_findpat("test", ONLY_LISTED))
--}
--{ When: The first buffer is unlisted
@ -183,13 +183,13 @@ describe('buffer functions', function()
-- Then: The second buffer is preferred because
-- unlisted buffers are not allowed
eq(buf2.b_fnum, buflist_findpat("test", ONLY_LISTED))
eq(buf2.handle, buflist_findpat("test", ONLY_LISTED))
--}
--{ When: We allow unlisted buffers
-- Then: The second buffer is still preferred
-- because listed buffers are preferred to unlisted
eq(buf2.b_fnum, buflist_findpat("test", ALLOW_UNLISTED))
eq(buf2.handle, buflist_findpat("test", ALLOW_UNLISTED))
--}
--{ When: We unlist the second buffer
@ -198,7 +198,7 @@ describe('buffer functions', function()
-- Then: The first buffer is preferred again
-- because buf1 matches better which takes precedence
-- when both buffers have the same listing status.
eq(buf1.b_fnum, buflist_findpat("test", ALLOW_UNLISTED))
eq(buf1.handle, buflist_findpat("test", ALLOW_UNLISTED))
-- And: Neither buffer is returned when ignoring unlisted
eq(-1, buflist_findpat("test", ONLY_LISTED))

View File

@ -32,6 +32,12 @@ option(USE_BUNDLED_LUV "Use the bundled version of luv." ${USE_BUNDLED})
# build it unless explicitly requested
option(USE_BUNDLED_LUA "Use the bundled version of lua." OFF)
if(USE_BUNDLED AND (NOT WIN32))
option(USE_BUNDLED_GPERF "Use the bundled version of gperf." ON)
else()
option(USE_BUNDLED_GPERF "Use the bundled version of gperf." OFF)
endif()
option(USE_EXISTING_SRC_DIR "Skip download of deps sources in case of existing source directory." OFF)
if(UNIX)
@ -111,6 +117,9 @@ set(JEMALLOC_SHA256 5630650d5c1caab95d2f0898de4fe5ab8519dc680b04963b38bb425ef6a4
set(LUV_URL https://github.com/luvit/luv/archive/146f1ce4c08c3b67f604c9ee1e124b1cf5c15cf3.tar.gz)
set(LUV_SHA256 3d537f8eb9fa5adb146a083eae22af886aee324ec268e2aa0fa75f2f1c52ca7a)
set(GPERF_URL http://ftp.gnu.org/pub/gnu/gperf/gperf-3.0.4.tar.gz)
set(GPERF_SHA256 767112a204407e62dbc3106647cf839ed544f3cf5d0f0523aaa2508623aad63e)
if(USE_BUNDLED_UNIBILIUM)
include(BuildUnibilium)
endif()
@ -151,6 +160,10 @@ if(USE_BUNDLED_LUV)
include(BuildLuv)
endif()
if(USE_BUNDLED_GPERF)
include(BuildGperf)
endif()
add_custom_target(clean-shared-libraries
COMMAND ${CMAKE_COMMAND}
-DREMOVE_FILE_GLOB=${DEPS_INSTALL_DIR}/lib/${CMAKE_SHARED_LIBRARY_PREFIX}*${CMAKE_SHARED_LIBRARY_SUFFIX}*

51
third-party/cmake/BuildGperf.cmake vendored Normal file
View File

@ -0,0 +1,51 @@
# Gperf recipe. Gperf is only required when building Neovim, when
# cross compiling we still want to build for the HOST system, whenever
# writing a recipe that is meant for cross-compile, use the HOSTDEPS_* variables
# instead of DEPS_* - check the main CMakeLists.txt for a list.
# BuildGperf(CONFIGURE_COMMAND ... BUILD_COMMAND ... INSTALL_COMMAND ...)
# Reusable function to build Gperf, wraps ExternalProject_Add.
# Failing to pass a command argument will result in no command being run
function(BuildGperf)
cmake_parse_arguments(_gperf
""
""
"CONFIGURE_COMMAND;BUILD_COMMAND;INSTALL_COMMAND"
${ARGN})
if(NOT _gperf_CONFIGURE_COMMAND AND NOT _gperf_BUILD_COMMAND
AND NOT _gperf_INSTALL_COMMAND)
message(FATAL_ERROR "Must pass at least one of CONFIGURE_COMMAND, BUILD_COMMAND, INSTALL_COMMAND")
endif()
ExternalProject_Add(gperf
PREFIX ${DEPS_BUILD_DIR}
URL ${GPERF_URL}
DOWNLOAD_DIR ${DEPS_DOWNLOAD_DIR}/gperf
DOWNLOAD_COMMAND ${CMAKE_COMMAND}
-DPREFIX=${DEPS_BUILD_DIR}
-DDOWNLOAD_DIR=${DEPS_DOWNLOAD_DIR}/gperf
-DURL=${GPERF_URL}
-DEXPECTED_SHA256=${GPERF_SHA256}
-DTARGET=gperf
-DUSE_EXISTING_SRC_DIR=${USE_EXISTING_SRC_DIR}
-P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/DownloadAndExtractFile.cmake
BUILD_IN_SOURCE 1
CONFIGURE_COMMAND "${_gperf_CONFIGURE_COMMAND}"
BUILD_COMMAND "${_gperf_BUILD_COMMAND}"
INSTALL_COMMAND "${_gperf_INSTALL_COMMAND}")
endfunction()
set(GPERF_BUILDARGS CC=${HOSTDEPS_C_COMPILER} LD=${HOSTDEPS_C_COMPILER})
if(UNIX OR (MINGW AND CMAKE_CROSSCOMPILING))
BuildGperf(
CONFIGURE_COMMAND ${DEPS_BUILD_DIR}/src/gperf/configure
--prefix=${HOSTDEPS_INSTALL_DIR}
INSTALL_COMMAND ${MAKE_PRG} install)
else()
message(FATAL_ERROR "Trying to build gperf in an unsupported system ${CMAKE_SYSTEM_NAME}/${CMAKE_C_COMPILER_ID}")
endif()