aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/api/vim.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/api/vim.c')
-rw-r--r--src/nvim/api/vim.c164
1 files changed, 88 insertions, 76 deletions
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index ce91c1b4af..fa8d26914a 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -66,7 +66,7 @@
#include "nvim/viml/parser/parser.h"
#include "nvim/window.h"
-#define LINE_BUFFER_SIZE 4096
+#define LINE_BUFFER_MIN_SIZE 4096
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "api/vim.c.generated.h"
@@ -79,19 +79,17 @@
/// @param[out] err Error details, if any
/// @return Highlight definition map
/// @see nvim_get_hl_by_id
-Dictionary nvim_get_hl_by_name(String name, Boolean rgb, Error *err)
+Dictionary nvim_get_hl_by_name(String name, Boolean rgb, Arena *arena, Error *err)
FUNC_API_SINCE(3)
{
Dictionary result = ARRAY_DICT_INIT;
int id = syn_name2id(name.data);
if (id == 0) {
- api_set_error(err, kErrorTypeException, "Invalid highlight name: %s",
- name.data);
+ api_set_error(err, kErrorTypeException, "Invalid highlight name: %s", name.data);
return result;
}
- result = nvim_get_hl_by_id(id, rgb, err);
- return result;
+ return nvim_get_hl_by_id(id, rgb, arena, err);
}
/// Gets a highlight definition by id. |hlID()|
@@ -100,17 +98,16 @@ Dictionary nvim_get_hl_by_name(String name, Boolean rgb, Error *err)
/// @param[out] err Error details, if any
/// @return Highlight definition map
/// @see nvim_get_hl_by_name
-Dictionary nvim_get_hl_by_id(Integer hl_id, Boolean rgb, Error *err)
+Dictionary nvim_get_hl_by_id(Integer hl_id, Boolean rgb, Arena *arena, Error *err)
FUNC_API_SINCE(3)
{
Dictionary dic = ARRAY_DICT_INIT;
if (syn_get_final_id((int)hl_id) == 0) {
- api_set_error(err, kErrorTypeException,
- "Invalid highlight id: %" PRId64, hl_id);
+ api_set_error(err, kErrorTypeException, "Invalid highlight id: %" PRId64, hl_id);
return dic;
}
int attrcode = syn_id2attr((int)hl_id);
- return hl_get_attr_by_id(attrcode, rgb, err);
+ return hl_get_attr_by_id(attrcode, rgb, arena, err);
}
/// Gets a highlight group by name
@@ -122,10 +119,10 @@ Integer nvim_get_hl_id_by_name(String name)
return syn_check_group(name.data, name.size);
}
-Dictionary nvim__get_hl_defs(Integer ns_id, Error *err)
+Dictionary nvim__get_hl_defs(Integer ns_id, Arena *arena, Error *err)
{
if (ns_id == 0) {
- return get_global_hl_defs();
+ return get_global_hl_defs(arena);
}
abort();
}
@@ -163,8 +160,8 @@ Dictionary nvim__get_hl_defs(Integer ns_id, Error *err)
/// - nocombine: boolean
/// - link: name of another highlight group to link to, see |:hi-link|.
/// - default: Don't override existing definition |:hi-default|
-/// - ctermfg: Sets foreground of cterm color |highlight-ctermfg|
-/// - ctermbg: Sets background of cterm color |highlight-ctermbg|
+/// - ctermfg: Sets foreground of cterm color |ctermfg|
+/// - ctermbg: Sets background of cterm color |ctermbg|
/// - cterm: cterm attribute map, like |highlight-args|. If not set,
/// cterm attributes will match those from the attribute map
/// documented above.
@@ -175,6 +172,10 @@ void nvim_set_hl(Integer ns_id, String name, Dict(highlight) *val, Error *err)
FUNC_API_SINCE(7)
{
int hl_id = syn_check_group(name.data, name.size);
+ if (hl_id == 0) {
+ api_set_error(err, kErrorTypeException, "Invalid highlight name: %s", name.data);
+ return;
+ }
int link_id = -1;
HlAttrs attrs = dict2hlattrs(val, true, &link_id, err);
@@ -184,7 +185,7 @@ void nvim_set_hl(Integer ns_id, String name, Dict(highlight) *val, Error *err)
}
/// Set active namespace for highlights. This can be set for a single window,
-/// see |nvim_win_set_hl_ns|.
+/// see |nvim_win_set_hl_ns()|.
///
/// @param ns_id the namespace to use
/// @param[out] err Error details, if any
@@ -198,13 +199,13 @@ void nvim_set_hl_ns(Integer ns_id, Error *err)
ns_hl_global = (NS)ns_id;
hl_check_ns();
- redraw_all_later(NOT_VALID);
+ redraw_all_later(UPD_NOT_VALID);
}
/// Set active namespace for highlights while redrawing.
///
/// This function meant to be called while redrawing, primarily from
-/// |nvim_set_decoration_provider| on_win and on_line callbacks, which
+/// |nvim_set_decoration_provider()| on_win and on_line callbacks, which
/// are allowed to change the namespace during a redraw cycle.
///
/// @param ns_id the namespace to activate
@@ -335,9 +336,9 @@ Integer nvim_input(String keys)
/// mouse input in a GUI. The deprecated pseudokey form
/// ("<LeftMouse><col,row>") of |nvim_input()| has the same limitation.
///
-/// @param button Mouse button: one of "left", "right", "middle", "wheel".
+/// @param button Mouse button: one of "left", "right", "middle", "wheel", "move".
/// @param action For ordinary buttons, one of "press", "drag", "release".
-/// For the wheel, one of "up", "down", "left", "right".
+/// For the wheel, one of "up", "down", "left", "right". Ignored for "move".
/// @param modifier String of modifiers each represented by a single char.
/// The same specifiers are used as for a key press, except
/// that the "-" separator is optional, so "C-A-", "c-a"
@@ -364,6 +365,8 @@ void nvim_input_mouse(String button, String action, String modifier, Integer gri
code = KE_RIGHTMOUSE;
} else if (strequal(button.data, "wheel")) {
code = KE_MOUSEDOWN;
+ } else if (strequal(button.data, "move")) {
+ code = KE_MOUSEMOVE;
} else {
goto error;
}
@@ -380,7 +383,7 @@ void nvim_input_mouse(String button, String action, String modifier, Integer gri
} else {
goto error;
}
- } else {
+ } else if (code != KE_MOUSEMOVE) {
if (strequal(action.data, "press")) {
// pass
} else if (strequal(action.data, "drag")) {
@@ -520,7 +523,7 @@ Array nvim__runtime_inspect(void)
/// Find files in runtime directories
///
-/// 'name' can contain wildcards. For example
+/// "name" can contain wildcards. For example
/// nvim_get_runtime_file("colors/*.vim", true) will return all color
/// scheme files. Always use forward slashes (/) in the search pattern for
/// subdirectories regardless of platform.
@@ -961,7 +964,7 @@ fail:
/// mode. Note: keypresses are sent raw as they would be to the pty
/// master end. For instance, a carriage return is sent
/// as a "\r", not as a "\n". |textlock| applies. It is possible
-/// to call |nvim_chan_send| directly in the callback however.
+/// to call |nvim_chan_send()| directly in the callback however.
/// ["input", term, bufnr, data]
/// @param[out] err Error details, if any
/// @return Channel id, or 0 on error
@@ -1419,10 +1422,10 @@ Dictionary nvim_get_mode(void)
/// @param mode Mode short-name ("n", "i", "v", ...)
/// @returns Array of |maparg()|-like dictionaries describing mappings.
/// The "buffer" key is always zero.
-ArrayOf(Dictionary) nvim_get_keymap(uint64_t channel_id, String mode)
+ArrayOf(Dictionary) nvim_get_keymap(String mode)
FUNC_API_SINCE(3)
{
- return keymap_array(mode, NULL, channel_id == LUA_INTERNAL_CALL);
+ return keymap_array(mode, NULL);
}
/// Sets a global |mapping| for the given mode.
@@ -1449,7 +1452,7 @@ ArrayOf(Dictionary) nvim_get_keymap(uint64_t channel_id, String mode)
/// @param rhs Right-hand-side |{rhs}| of the mapping.
/// @param opts Optional parameters map: keys are |:map-arguments|, values are booleans (default
/// false). Accepts all |:map-arguments| as keys excluding |<buffer>| but including
-/// |noremap| and "desc". Unknown key is an error.
+/// |:noremap| and "desc". Unknown key is an error.
/// "desc" can be used to give a description to the mapping.
/// When called from Lua, also accepts a "callback" key that takes a Lua function to
/// call when the mapping is executed.
@@ -1479,14 +1482,14 @@ void nvim_del_keymap(uint64_t channel_id, String mode, String lhs, Error *err)
/// 1 is the |api-metadata| map (Dictionary).
///
/// @returns 2-tuple [{channel-id}, {api-metadata}]
-Array nvim_get_api_info(uint64_t channel_id)
+Array nvim_get_api_info(uint64_t channel_id, Arena *arena)
FUNC_API_SINCE(1) FUNC_API_FAST FUNC_API_REMOTE_ONLY
{
- Array rv = ARRAY_DICT_INIT;
+ Array rv = arena_array(arena, 2);
assert(channel_id <= INT64_MAX);
- ADD(rv, INTEGER_OBJ((int64_t)channel_id));
- ADD(rv, DICTIONARY_OBJ(api_metadata()));
+ ADD_C(rv, INTEGER_OBJ((int64_t)channel_id));
+ ADD_C(rv, DICTIONARY_OBJ(api_metadata()));
return rv;
}
@@ -1545,9 +1548,9 @@ void nvim_set_client_info(uint64_t channel_id, String name, Dictionary version,
FUNC_API_SINCE(4) FUNC_API_REMOTE_ONLY
{
Dictionary info = ARRAY_DICT_INIT;
- PUT(info, "name", copy_object(STRING_OBJ(name)));
+ PUT(info, "name", copy_object(STRING_OBJ(name), NULL));
- version = copy_dictionary(version);
+ version = copy_dictionary(version, NULL);
bool has_major = false;
for (size_t i = 0; i < version.size; i++) {
if (strequal(version.items[i].key.data, "major")) {
@@ -1560,9 +1563,9 @@ void nvim_set_client_info(uint64_t channel_id, String name, Dictionary version,
}
PUT(info, "version", DICTIONARY_OBJ(version));
- PUT(info, "type", copy_object(STRING_OBJ(type)));
- PUT(info, "methods", DICTIONARY_OBJ(copy_dictionary(methods)));
- PUT(info, "attributes", DICTIONARY_OBJ(copy_dictionary(attributes)));
+ PUT(info, "type", copy_object(STRING_OBJ(type), NULL));
+ PUT(info, "methods", DICTIONARY_OBJ(copy_dictionary(methods, NULL)));
+ PUT(info, "attributes", DICTIONARY_OBJ(copy_dictionary(attributes, NULL)));
rpc_set_client_info(channel_id, info);
}
@@ -1629,11 +1632,11 @@ Array nvim_list_chans(void)
/// an error, it is a three-element array with the zero-based index of the call
/// which resulted in an error, the error type and the error message. If an
/// error occurred, the values from all preceding calls will still be returned.
-Array nvim_call_atomic(uint64_t channel_id, Array calls, Error *err)
+Array nvim_call_atomic(uint64_t channel_id, Array calls, Arena *arena, Error *err)
FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY
{
- Array rv = ARRAY_DICT_INIT;
- Array results = ARRAY_DICT_INIT;
+ Array rv = arena_array(arena, 2);
+ Array results = arena_array(arena, calls.size);
Error nested_error = ERROR_INIT;
size_t i; // also used for freeing the variables
@@ -1642,21 +1645,21 @@ Array nvim_call_atomic(uint64_t channel_id, Array calls, Error *err)
api_set_error(err,
kErrorTypeValidation,
"Items in calls array must be arrays");
- goto validation_error;
+ goto theend;
}
Array call = calls.items[i].data.array;
if (call.size != 2) {
api_set_error(err,
kErrorTypeValidation,
"Items in calls array must be arrays of size 2");
- goto validation_error;
+ goto theend;
}
if (call.items[0].type != kObjectTypeString) {
api_set_error(err,
kErrorTypeValidation,
"Name must be String");
- goto validation_error;
+ goto theend;
}
String name = call.items[0].data.string;
@@ -1664,7 +1667,7 @@ Array nvim_call_atomic(uint64_t channel_id, Array calls, Error *err)
api_set_error(err,
kErrorTypeValidation,
"Args must be Array");
- goto validation_error;
+ goto theend;
}
Array args = call.items[1].data.array;
@@ -1676,29 +1679,32 @@ Array nvim_call_atomic(uint64_t channel_id, Array calls, Error *err)
if (ERROR_SET(&nested_error)) {
break;
}
- Object result = handler.fn(channel_id, args, &nested_error);
+
+ Object result = handler.fn(channel_id, args, arena, &nested_error);
if (ERROR_SET(&nested_error)) {
// error handled after loop
break;
}
-
- ADD(results, result);
+ // TODO(bfredl): wastefull copy. It could be avoided to encoding to msgpack
+ // directly here. But `result` might become invalid when next api function
+ // is called in the loop.
+ ADD_C(results, copy_object(result, arena));
+ if (!handler.arena_return) {
+ api_free_object(result);
+ }
}
- ADD(rv, ARRAY_OBJ(results));
+ ADD_C(rv, ARRAY_OBJ(results));
if (ERROR_SET(&nested_error)) {
- Array errval = ARRAY_DICT_INIT;
- ADD(errval, INTEGER_OBJ((Integer)i));
- ADD(errval, INTEGER_OBJ(nested_error.type));
- ADD(errval, STRING_OBJ(cstr_to_string(nested_error.msg)));
- ADD(rv, ARRAY_OBJ(errval));
+ Array errval = arena_array(arena, 3);
+ ADD_C(errval, INTEGER_OBJ((Integer)i));
+ ADD_C(errval, INTEGER_OBJ(nested_error.type));
+ ADD_C(errval, STRING_OBJ(copy_string(cstr_as_string(nested_error.msg), arena)));
+ ADD_C(rv, ARRAY_OBJ(errval));
} else {
- ADD(rv, NIL);
+ ADD_C(rv, NIL);
}
- goto theend;
-validation_error:
- api_free_array(results);
theend:
api_clear_error(&nested_error);
return rv;
@@ -1712,17 +1718,21 @@ theend:
/// @param to_err true: message is an error (uses `emsg` instead of `msg`)
static void write_msg(String message, bool to_err)
{
- static size_t out_pos = 0, err_pos = 0;
- static char out_line_buf[LINE_BUFFER_SIZE], err_line_buf[LINE_BUFFER_SIZE];
+ static StringBuilder out_line_buf = KV_INITIAL_VALUE;
+ static StringBuilder err_line_buf = KV_INITIAL_VALUE;
-#define PUSH_CHAR(i, pos, line_buf, msg) \
- if (message.data[i] == NL || (pos) == LINE_BUFFER_SIZE - 1) { \
- (line_buf)[pos] = NUL; \
- msg(line_buf); \
- (pos) = 0; \
+#define PUSH_CHAR(i, line_buf, msg) \
+ if (kv_max(line_buf) == 0) { \
+ kv_resize(line_buf, LINE_BUFFER_MIN_SIZE); \
+ } \
+ if (message.data[i] == NL) { \
+ kv_push(line_buf, NUL); \
+ msg(line_buf.items); \
+ kv_drop(line_buf, kv_size(line_buf)); \
+ kv_resize(line_buf, LINE_BUFFER_MIN_SIZE); \
continue; \
} \
- (line_buf)[(pos)++] = message.data[i];
+ kv_push(line_buf, message.data[i]);
no_wait_return++;
for (uint32_t i = 0; i < message.size; i++) {
@@ -1730,9 +1740,9 @@ static void write_msg(String message, bool to_err)
break;
}
if (to_err) {
- PUSH_CHAR(i, err_pos, err_line_buf, emsg);
+ PUSH_CHAR(i, err_line_buf, emsg);
} else {
- PUSH_CHAR(i, out_pos, out_line_buf, msg);
+ PUSH_CHAR(i, out_line_buf, msg);
}
}
no_wait_return--;
@@ -1751,7 +1761,7 @@ static void write_msg(String message, bool to_err)
/// @return its argument.
Object nvim__id(Object obj)
{
- return copy_object(obj);
+ return copy_object(obj, NULL);
}
/// Returns array given as argument.
@@ -1764,7 +1774,7 @@ Object nvim__id(Object obj)
/// @return its argument.
Array nvim__id_array(Array arr)
{
- return copy_object(ARRAY_OBJ(arr)).data.array;
+ return copy_array(arr, NULL);
}
/// Returns dictionary given as argument.
@@ -1777,7 +1787,7 @@ Array nvim__id_array(Array arr)
/// @return its argument.
Dictionary nvim__id_dictionary(Dictionary dct)
{
- return copy_object(DICTIONARY_OBJ(dct)).data.dictionary;
+ return copy_dictionary(dct, NULL);
}
/// Returns floating-point value given as argument.
@@ -1803,6 +1813,7 @@ Dictionary nvim__stats(void)
PUT(rv, "log_skip", INTEGER_OBJ(g_stats.log_skip));
PUT(rv, "lua_refcount", INTEGER_OBJ(nlua_get_global_ref_count()));
PUT(rv, "redraw", INTEGER_OBJ(g_stats.redraw));
+ PUT(rv, "arena_alloc_count", INTEGER_OBJ((Integer)arena_alloc_count));
return rv;
}
@@ -1875,7 +1886,7 @@ Object nvim_get_proc(Integer pid, Error *err)
api_set_error(err, kErrorTypeException, "Invalid pid: %" PRId64, pid);
return NIL;
}
-#ifdef WIN32
+#ifdef MSWIN
rvobj.data.dictionary = os_proc_info((int)pid);
if (rvobj.data.dictionary.size == 0) { // Process not found.
return NIL;
@@ -1928,7 +1939,7 @@ void nvim_select_popupmenu_item(Integer item, Boolean insert, Boolean finish, Di
}
/// NB: if your UI doesn't use hlstate, this will not return hlstate first time
-Array nvim__inspect_cell(Integer grid, Integer row, Integer col, Error *err)
+Array nvim__inspect_cell(Integer grid, Integer row, Integer col, Arena *arena, Error *err)
{
Array ret = ARRAY_DICT_INIT;
@@ -1952,13 +1963,14 @@ Array nvim__inspect_cell(Integer grid, Integer row, Integer col, Error *err)
|| col < 0 || col >= g->cols) {
return ret;
}
+ ret = arena_array(arena, 3);
size_t off = g->line_offset[(size_t)row] + (size_t)col;
- ADD(ret, STRING_OBJ(cstr_to_string((char *)g->chars[off])));
+ ADD_C(ret, STRING_OBJ(cstr_as_string((char *)g->chars[off])));
int attr = g->attrs[off];
- ADD(ret, DICTIONARY_OBJ(hl_get_attr_by_id(attr, true, err)));
+ ADD_C(ret, DICTIONARY_OBJ(hl_get_attr_by_id(attr, true, arena, err)));
// will not work first time
if (!highlight_use_hlstate()) {
- ADD(ret, ARRAY_OBJ(hl_inspect(attr)));
+ ADD_C(ret, ARRAY_OBJ(hl_inspect(attr)));
}
return ret;
}
@@ -2040,7 +2052,7 @@ Array nvim_get_mark(String name, Dictionary opts, Error *err)
// Marks are from an open buffer it fnum is non zero
if (mark->fmark.fnum != 0) {
bufnr = mark->fmark.fnum;
- filename = (char *)buflist_nr2name(bufnr, true, true);
+ filename = buflist_nr2name(bufnr, true, true);
allocated = true;
// Marks comes from shada
} else {
@@ -2088,7 +2100,7 @@ Array nvim_get_mark(String name, Dictionary opts, Error *err)
/// 'fillchars'). Treated as single-width even if it isn't.
/// - highlights: (boolean) Return highlight information.
/// - use_winbar: (boolean) Evaluate winbar instead of statusline.
-/// - use_tabline: (boolean) Evaluate tabline instead of statusline. When |TRUE|, {winid}
+/// - use_tabline: (boolean) Evaluate tabline instead of statusline. When true, {winid}
/// is ignored. Mutually exclusive with {use_winbar}.
///
/// @param[out] err Error details, if any.
@@ -2096,7 +2108,7 @@ Array nvim_get_mark(String name, Dictionary opts, Error *err)
/// - str: (string) Characters that will be displayed on the statusline.
/// - width: (number) Display width of the statusline.
/// - highlights: Array containing highlight information of the statusline. Only included when
-/// the "highlights" key in {opts} is |TRUE|. Each element of the array is a
+/// the "highlights" key in {opts} is true. Each element of the array is a
/// |Dictionary| with these keys:
/// - start: (number) Byte index (0-based) of first character that uses the highlight.
/// - group: (string) Name of highlight group.
@@ -2228,7 +2240,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
// If first character doesn't have a defined highlight,
// add the default highlight at the beginning of the highlight list
- if (hltab->start == NULL || ((char *)hltab->start - buf) != 0) {
+ if (hltab->start == NULL || (hltab->start - buf) != 0) {
Dictionary hl_info = ARRAY_DICT_INIT;
grpname = get_default_stl_hl(wp, use_winbar);