aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/api
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/api')
-rw-r--r--src/nvim/api/autocmd.c6
-rw-r--r--src/nvim/api/buffer.c5
-rw-r--r--src/nvim/api/command.c16
-rw-r--r--src/nvim/api/extmark.c13
-rw-r--r--src/nvim/api/keysets.lua3
-rw-r--r--src/nvim/api/private/dispatch.h9
-rw-r--r--src/nvim/api/private/helpers.c47
-rw-r--r--src/nvim/api/private/helpers.h11
-rw-r--r--src/nvim/api/ui.c12
-rw-r--r--src/nvim/api/vim.c147
-rw-r--r--src/nvim/api/vimscript.c11
-rw-r--r--src/nvim/api/win_config.c8
-rw-r--r--src/nvim/api/window.c29
13 files changed, 189 insertions, 128 deletions
diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c
index bf6402f938..1cf0211f43 100644
--- a/src/nvim/api/autocmd.c
+++ b/src/nvim/api/autocmd.c
@@ -9,9 +9,9 @@
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
#include "nvim/ascii.h"
+#include "nvim/autocmd.h"
#include "nvim/buffer.h"
#include "nvim/eval/typval.h"
-#include "nvim/fileio.h"
#include "nvim/lua/executor.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -887,12 +887,12 @@ static bool check_autocmd_string_array(Array arr, char *k, Error *err)
static bool unpack_string_or_array(Array *array, Object *v, char *k, bool required, Error *err)
{
if (v->type == kObjectTypeString) {
- ADD(*array, copy_object(*v));
+ ADD(*array, copy_object(*v, NULL));
} else if (v->type == kObjectTypeArray) {
if (!check_autocmd_string_array(v->data.array, k, err)) {
return false;
}
- *array = copy_array(v->data.array);
+ *array = copy_array(v->data.array, NULL);
} else {
if (required) {
api_set_error(err,
diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c
index d3895d31cf..199650fc55 100644
--- a/src/nvim/api/buffer.c
+++ b/src/nvim/api/buffer.c
@@ -18,6 +18,7 @@
#include "nvim/change.h"
#include "nvim/cursor.h"
#include "nvim/decoration.h"
+#include "nvim/drawscreen.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_docmd.h"
#include "nvim/extmark.h"
@@ -1020,7 +1021,7 @@ void nvim_buf_del_var(Buffer buffer, String name, Error *err)
/// @param buffer Buffer handle, or 0 for current buffer
/// @param[out] err Error details, if any
/// @return Buffer name
-String nvim_buf_get_name(Buffer buffer, Error *err)
+String nvim_buf_get_name(Buffer buffer, Arena *arena, Error *err)
FUNC_API_SINCE(1)
{
String rv = STRING_INIT;
@@ -1030,7 +1031,7 @@ String nvim_buf_get_name(Buffer buffer, Error *err)
return rv;
}
- return cstr_to_string((char *)buf->b_ffname);
+ return cstr_as_string(buf->b_ffname);
}
/// Sets the full file name for a buffer
diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c
index bc766ff39c..1323fc347b 100644
--- a/src/nvim/api/command.c
+++ b/src/nvim/api/command.c
@@ -11,6 +11,7 @@
#include "nvim/api/private/helpers.h"
#include "nvim/autocmd.h"
#include "nvim/ex_docmd.h"
+#include "nvim/ex_eval.h"
#include "nvim/lua/executor.h"
#include "nvim/ops.h"
#include "nvim/regexp.h"
@@ -300,10 +301,10 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error
FUNC_API_SINCE(10)
{
exarg_T ea;
- memset(&ea, 0, sizeof(ea));
+ CLEAR_FIELD(ea);
CmdParseInfo cmdinfo;
- memset(&cmdinfo, 0, sizeof(cmdinfo));
+ CLEAR_FIELD(cmdinfo);
char *cmdline = NULL;
char *cmdname = NULL;
@@ -625,6 +626,7 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error
garray_T capture_local;
const int save_msg_silent = msg_silent;
garray_T * const save_capture_ga = capture_ga;
+ const int save_msg_col = msg_col;
if (output) {
ga_init(&capture_local, 1, 80);
@@ -635,6 +637,7 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error
try_start();
if (output) {
msg_silent++;
+ msg_col = 0; // prevent leading spaces
}
WITH_SCRIPT_CONTEXT(channel_id, {
@@ -644,6 +647,8 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error
if (output) {
capture_ga = save_capture_ga;
msg_silent = save_msg_silent;
+ // Put msg_col back where it was, since nothing should have been written.
+ msg_col = save_msg_col;
}
try_end(err);
@@ -819,9 +824,12 @@ static void build_cmdline_str(char **cmdlinep, exarg_T *eap, CmdParseInfo *cmdin
char *p = replace_makeprg(eap, eap->arg, cmdlinep);
if (p != eap->arg) {
// If replace_makeprg modified the cmdline string, correct the argument pointers.
- assert(argc == 1);
eap->arg = p;
- eap->args[0] = p;
+ // We can only know the position of the first argument because the argument list can be used
+ // multiple times in makeprg / grepprg.
+ if (argc >= 1) {
+ eap->args[0] = p;
+ }
}
}
diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c
index da1b6beeda..09b004637f 100644
--- a/src/nvim/api/extmark.c
+++ b/src/nvim/api/extmark.c
@@ -10,11 +10,11 @@
#include "nvim/api/private/helpers.h"
#include "nvim/charset.h"
#include "nvim/decoration_provider.h"
+#include "nvim/drawscreen.h"
#include "nvim/extmark.h"
#include "nvim/highlight_group.h"
#include "nvim/lua/executor.h"
#include "nvim/memline.h"
-#include "nvim/screen.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "api/extmark.c.generated.h"
@@ -51,7 +51,7 @@ Integer nvim_create_namespace(String name)
}
id = next_namespace_id++;
if (name.size > 0) {
- String name_alloc = copy_string(name);
+ String name_alloc = copy_string(name, NULL);
map_put(String, handle_T)(&namespace_ids, name_alloc, id);
}
return (Integer)id;
@@ -441,8 +441,9 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e
/// the extmark end position (if it exists) will be shifted
/// in when new text is inserted (true for right, false
/// for left). Defaults to false.
-/// - priority: a priority value for the highlight group. For
-/// example treesitter highlighting uses a value of 100.
+/// - priority: a priority value for the highlight group or sign
+/// attribute. For example treesitter highlighting uses a
+/// value of 100.
/// - strict: boolean that indicates extmark should not be placed
/// if the line or column value is past the end of the
/// buffer or end of the line respectively. Defaults to true.
@@ -992,7 +993,7 @@ void nvim_set_decoration_provider(Integer ns_id, DictionaryOf(LuaRef) opts, Erro
decor_provider_clear(p);
// regardless of what happens, it seems good idea to redraw
- redraw_all_later(NOT_VALID); // TODO(bfredl): too soon?
+ redraw_all_later(UPD_NOT_VALID); // TODO(bfredl): too soon?
struct {
const char *name;
@@ -1030,6 +1031,8 @@ void nvim_set_decoration_provider(Integer ns_id, DictionaryOf(LuaRef) opts, Erro
}
p->active = true;
+ p->hl_valid++;
+ p->hl_cached = false;
return;
error:
decor_provider_clear(p);
diff --git a/src/nvim/api/keysets.lua b/src/nvim/api/keysets.lua
index 4f4ac40ce9..6fad52ba75 100644
--- a/src/nvim/api/keysets.lua
+++ b/src/nvim/api/keysets.lua
@@ -104,7 +104,6 @@ return {
"reverse";
"nocombine";
"default";
- "global";
"cterm";
"foreground"; "fg";
"background"; "bg";
@@ -112,9 +111,9 @@ return {
"ctermbg";
"special"; "sp";
"link";
+ "global_link";
"fallback";
"blend";
- "temp";
};
highlight_cterm = {
"bold";
diff --git a/src/nvim/api/private/dispatch.h b/src/nvim/api/private/dispatch.h
index 4b7c394944..f92b205531 100644
--- a/src/nvim/api/private/dispatch.h
+++ b/src/nvim/api/private/dispatch.h
@@ -5,18 +5,23 @@
typedef Object (*ApiDispatchWrapper)(uint64_t channel_id,
Array args,
+ Arena *arena,
Error *error);
/// The rpc_method_handlers table, used in msgpack_rpc_dispatch(), stores
/// functions of this type.
-typedef struct {
+struct MsgpackRpcRequestHandler {
const char *name;
ApiDispatchWrapper fn;
bool fast; // Function is safe to be executed immediately while running the
// uv loop (the loop is run very frequently due to breakcheck).
// If "fast" is false, the function is deferred, i e the call will
// be put in the event queue, for safe handling later.
-} MsgpackRpcRequestHandler;
+ bool arena_return; // return value is allocated in the arena (or statically)
+ // and should not be freed as such.
+};
+
+extern const MsgpackRpcRequestHandler method_handlers[];
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "api/private/dispatch.h.generated.h"
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index fad75d55be..ebcf6cca6d 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -19,8 +19,8 @@
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/ex_cmds_defs.h"
+#include "nvim/ex_eval.h"
#include "nvim/extmark.h"
-#include "nvim/fileio.h"
#include "nvim/highlight_group.h"
#include "nvim/lib/kvec.h"
#include "nvim/lua/executor.h"
@@ -54,10 +54,11 @@ void try_enter(TryState *const tstate)
// save_dbg_stuff()/restore_dbg_stuff().
*tstate = (TryState) {
.current_exception = current_exception,
- .msg_list = (const struct msglist *const *)msg_list,
+ .msg_list = (const msglist_T *const *)msg_list,
.private_msg_list = NULL,
.trylevel = trylevel,
.got_int = got_int,
+ .did_throw = did_throw,
.need_rethrow = need_rethrow,
.did_emsg = did_emsg,
};
@@ -65,6 +66,7 @@ void try_enter(TryState *const tstate)
current_exception = NULL;
trylevel = 1;
got_int = false;
+ did_throw = false;
need_rethrow = false;
did_emsg = false;
}
@@ -85,14 +87,16 @@ bool try_leave(const TryState *const tstate, Error *const err)
assert(trylevel == 0);
assert(!need_rethrow);
assert(!got_int);
+ assert(!did_throw);
assert(!did_emsg);
assert(msg_list == &tstate->private_msg_list);
assert(*msg_list == NULL);
assert(current_exception == NULL);
- msg_list = (struct msglist **)tstate->msg_list;
+ msg_list = (msglist_T **)tstate->msg_list;
current_exception = tstate->current_exception;
trylevel = tstate->trylevel;
got_int = tstate->got_int;
+ did_throw = tstate->did_throw;
need_rethrow = tstate->need_rethrow;
did_emsg = tstate->did_emsg;
return ret;
@@ -127,7 +131,7 @@ bool try_end(Error *err)
force_abort = false;
if (got_int) {
- if (current_exception) {
+ if (did_throw) {
// If we got an interrupt, discard the current exception
discard_current_exception();
}
@@ -146,7 +150,7 @@ bool try_end(Error *err)
if (should_free) {
xfree(msg);
}
- } else if (current_exception) {
+ } else if (did_throw) {
api_set_error(err, kErrorTypeException, "%s", current_exception->value);
discard_current_exception();
}
@@ -618,6 +622,7 @@ void api_clear_error(Error *value)
value->type = kErrorTypeNone;
}
+/// @returns a shared value. caller must not modify it!
Dictionary api_metadata(void)
{
static Dictionary metadata = ARRAY_DICT_INIT;
@@ -630,7 +635,7 @@ Dictionary api_metadata(void)
init_type_metadata(&metadata);
}
- return copy_object(DICTIONARY_OBJ(metadata)).data.dictionary;
+ return metadata;
}
static void init_function_metadata(Dictionary *metadata)
@@ -715,36 +720,40 @@ static void init_type_metadata(Dictionary *metadata)
PUT(*metadata, "types", DICTIONARY_OBJ(types));
}
-String copy_string(String str)
+// all the copy_[object] functions allow arena=NULL,
+// then global allocations are used, and the resulting object
+// should be freed with an api_free_[object] function
+
+String copy_string(String str, Arena *arena)
{
if (str.data != NULL) {
- return (String){ .data = xmemdupz(str.data, str.size), .size = str.size };
+ return (String){ .data = arena_memdupz(arena, str.data, str.size), .size = str.size };
} else {
return (String)STRING_INIT;
}
}
-Array copy_array(Array array)
+Array copy_array(Array array, Arena *arena)
{
- Array rv = ARRAY_DICT_INIT;
+ Array rv = arena_array(arena, array.size);
for (size_t i = 0; i < array.size; i++) {
- ADD(rv, copy_object(array.items[i]));
+ ADD(rv, copy_object(array.items[i], arena));
}
return rv;
}
-Dictionary copy_dictionary(Dictionary dict)
+Dictionary copy_dictionary(Dictionary dict, Arena *arena)
{
- Dictionary rv = ARRAY_DICT_INIT;
+ Dictionary rv = arena_dict(arena, dict.size);
for (size_t i = 0; i < dict.size; i++) {
KeyValuePair item = dict.items[i];
- PUT(rv, item.key.data, copy_object(item.value));
+ PUT_C(rv, copy_string(item.key, arena).data, copy_object(item.value, arena));
}
return rv;
}
/// Creates a deep clone of an object
-Object copy_object(Object obj)
+Object copy_object(Object obj, Arena *arena)
{
switch (obj.type) {
case kObjectTypeBuffer:
@@ -757,13 +766,13 @@ Object copy_object(Object obj)
return obj;
case kObjectTypeString:
- return STRING_OBJ(copy_string(obj.data.string));
+ return STRING_OBJ(copy_string(obj.data.string, arena));
case kObjectTypeArray:
- return ARRAY_OBJ(copy_array(obj.data.array));
+ return ARRAY_OBJ(copy_array(obj.data.array, arena));
case kObjectTypeDictionary:
- return DICTIONARY_OBJ(copy_dictionary(obj.data.dictionary));
+ return DICTIONARY_OBJ(copy_dictionary(obj.data.dictionary, arena));
case kObjectTypeLuaRef:
return LUAREF_OBJ(api_new_luaref(obj.data.luaref));
@@ -844,7 +853,7 @@ HlMessage parse_hl_msg(Array chunks, Error *err)
goto free_exit;
}
- String str = copy_string(chunk.items[0].data.string);
+ String str = copy_string(chunk.items[0].data.string, NULL);
int attr = 0;
if (chunk.size == 2) {
diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h
index 1441da853c..2157ad0ec2 100644
--- a/src/nvim/api/private/helpers.h
+++ b/src/nvim/api/private/helpers.h
@@ -3,7 +3,7 @@
#include "nvim/api/private/defs.h"
#include "nvim/decoration.h"
-#include "nvim/ex_eval.h"
+#include "nvim/ex_eval_defs.h"
#include "nvim/getchar.h"
#include "nvim/lib/kvec.h"
#include "nvim/memory.h"
@@ -130,10 +130,11 @@ EXTERN PMap(handle_T) tabpage_handles INIT(= MAP_INIT);
/// processed and that “other VimL code” must not be affected.
typedef struct {
except_T *current_exception;
- struct msglist *private_msg_list;
- const struct msglist *const *msg_list;
+ msglist_T *private_msg_list;
+ const msglist_T *const *msg_list;
int trylevel;
int got_int;
+ bool did_throw;
int need_rethrow;
int did_emsg;
} TryState;
@@ -144,8 +145,8 @@ typedef struct {
// TODO(bfredl): prepare error-handling at "top level" (nv_event).
#define TRY_WRAP(code) \
do { \
- struct msglist **saved_msg_list = msg_list; \
- struct msglist *private_msg_list; \
+ msglist_T **saved_msg_list = msg_list; \
+ msglist_T *private_msg_list; \
msg_list = &private_msg_list; \
private_msg_list = NULL; \
code \
diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c
index 6239e414a7..e34dcbdb46 100644
--- a/src/nvim/api/ui.c
+++ b/src/nvim/api/ui.c
@@ -11,14 +11,14 @@
#include "nvim/api/ui.h"
#include "nvim/channel.h"
#include "nvim/cursor_shape.h"
+#include "nvim/grid.h"
#include "nvim/highlight.h"
#include "nvim/map.h"
#include "nvim/memory.h"
#include "nvim/msgpack_rpc/channel.h"
#include "nvim/msgpack_rpc/helpers.h"
#include "nvim/option.h"
-#include "nvim/popupmnu.h"
-#include "nvim/screen.h"
+#include "nvim/popupmenu.h"
#include "nvim/ui.h"
#include "nvim/vim.h"
#include "nvim/window.h"
@@ -224,7 +224,7 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, Dictiona
ui->event = remote_ui_event;
ui->inspect = remote_ui_inspect;
- memset(ui->ui_ext, 0, sizeof(ui->ui_ext));
+ CLEAR_FIELD(ui->ui_ext);
for (size_t i = 0; i < options.size; i++) {
ui_set_option(ui, true, options.items[i].key, options.items[i].value, err);
@@ -965,7 +965,7 @@ static Array translate_contents(UI *ui, Array contents)
} else {
ADD(new_item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT));
}
- ADD(new_item, copy_object(item.items[1]));
+ ADD(new_item, copy_object(item.items[1], NULL));
ADD(new_contents, ARRAY_OBJ(new_item));
}
return new_contents;
@@ -978,7 +978,7 @@ static Array translate_firstarg(UI *ui, Array args)
ADD(new_args, ARRAY_OBJ(translate_contents(ui, contents)));
for (size_t i = 1; i < args.size; i++) {
- ADD(new_args, copy_object(args.items[i]));
+ ADD(new_args, copy_object(args.items[i], NULL));
}
return new_args;
}
@@ -1024,7 +1024,7 @@ static void remote_ui_event(UI *ui, char *name, Array args)
Array items = args.items[0].data.array;
Array new_items = ARRAY_DICT_INIT;
for (size_t i = 0; i < items.size; i++) {
- ADD(new_items, copy_object(items.items[i].data.array.items[0]));
+ ADD(new_items, copy_object(items.items[i].data.array.items[0], NULL));
}
ADD_C(new_args, ARRAY_OBJ(new_items));
push_call(ui, "wildmenu_show", new_args);
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index e2f58dba62..b164106cef 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -23,17 +23,19 @@
#include "nvim/context.h"
#include "nvim/decoration.h"
#include "nvim/decoration_provider.h"
+#include "nvim/drawscreen.h"
#include "nvim/edit.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/userfunc.h"
-#include "nvim/ex_cmds2.h"
#include "nvim/ex_cmds_defs.h"
#include "nvim/ex_docmd.h"
+#include "nvim/ex_eval.h"
#include "nvim/file_search.h"
#include "nvim/fileio.h"
#include "nvim/getchar.h"
#include "nvim/globals.h"
+#include "nvim/grid.h"
#include "nvim/highlight.h"
#include "nvim/highlight_defs.h"
#include "nvim/highlight_group.h"
@@ -50,11 +52,13 @@
#include "nvim/msgpack_rpc/unpacker.h"
#include "nvim/ops.h"
#include "nvim/option.h"
+#include "nvim/optionstr.h"
#include "nvim/os/input.h"
#include "nvim/os/process.h"
-#include "nvim/popupmnu.h"
-#include "nvim/screen.h"
+#include "nvim/popupmenu.h"
+#include "nvim/runtime.h"
#include "nvim/state.h"
+#include "nvim/statusline.h"
#include "nvim/types.h"
#include "nvim/ui.h"
#include "nvim/vim.h"
@@ -91,7 +95,6 @@ Dictionary nvim_get_hl_by_name(String name, Boolean rgb, Error *err)
}
/// Gets a highlight definition by id. |hlID()|
-///
/// @param hl_id Highlight id as returned by |hlID()|
/// @param rgb Export RGB colors
/// @param[out] err Error details, if any
@@ -180,35 +183,38 @@ void nvim_set_hl(Integer ns_id, String name, Dict(highlight) *val, Error *err)
}
}
-/// Set active namespace for highlights.
-///
-/// NB: this function can be called from async contexts, but the
-/// semantics are not yet well-defined. To start with
-/// |nvim_set_decoration_provider| on_win and on_line callbacks
-/// are explicitly allowed to change the namespace during a redraw cycle.
+/// Set active namespace for highlights. This can be set for a single window,
+/// see |nvim_win_set_hl_ns|.
///
-/// @param ns_id the namespace to activate
+/// @param ns_id the namespace to use
/// @param[out] err Error details, if any
-void nvim__set_hl_ns(Integer ns_id, Error *err)
- FUNC_API_FAST
+void nvim_set_hl_ns(Integer ns_id, Error *err)
+ FUNC_API_SINCE(10)
{
- if (ns_id >= 0) {
- ns_hl_active = (NS)ns_id;
+ if (ns_id < 0) {
+ api_set_error(err, kErrorTypeValidation, "no such namespace");
+ return;
}
- // TODO(bfredl): this is a little bit hackish. Eventually we want a standard
- // event path for redraws caused by "fast" events. This could tie in with
- // better throttling of async events causing redraws, such as non-batched
- // nvim_buf_set_extmark calls from async contexts.
- if (!provider_active && !ns_hl_changed && must_redraw < NOT_VALID) {
- multiqueue_put(main_loop.events, on_redraw_event, 0);
- }
- ns_hl_changed = true;
+ ns_hl_global = (NS)ns_id;
+ hl_check_ns();
+ redraw_all_later(UPD_NOT_VALID);
}
-static void on_redraw_event(void **argv)
+/// 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
+/// are allowed to change the namespace during a redraw cycle.
+///
+/// @param ns_id the namespace to activate
+/// @param[out] err Error details, if any
+void nvim_set_hl_ns_fast(Integer ns_id, Error *err)
+ FUNC_API_SINCE(10)
+ FUNC_API_FAST
{
- redraw_all_later(NOT_VALID);
+ ns_hl_fast = (NS)ns_id;
+ hl_check_ns();
}
/// Sends input-keys to Nvim, subject to various quirks controlled by `mode`
@@ -478,7 +484,7 @@ Object nvim_notify(String msg, Integer log_level, Dictionary opts, Error *err)
ADD_C(args, INTEGER_OBJ(log_level));
ADD_C(args, DICTIONARY_OBJ(opts));
- return nlua_exec(STATIC_CSTR_AS_STRING("return vim.notify(...)"), args, err);
+ return NLUA_EXEC_STATIC("return vim.notify(...)", args, err);
}
/// Calculates the number of display cells occupied by `text`.
@@ -1473,14 +1479,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;
}
@@ -1539,9 +1545,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")) {
@@ -1554,9 +1560,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);
}
@@ -1623,11 +1629,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
@@ -1636,21 +1642,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;
@@ -1658,7 +1664,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;
@@ -1670,29 +1676,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;
@@ -1745,7 +1754,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.
@@ -1758,7 +1767,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.
@@ -1771,7 +1780,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.
@@ -1797,6 +1806,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;
}
@@ -1833,11 +1843,9 @@ Array nvim_get_proc_children(Integer pid, Error *err)
if (rv == 2) {
// syscall failed (possibly because of kernel options), try shelling out.
DLOG("fallback to vim._os_proc_children()");
- Array a = ARRAY_DICT_INIT;
+ MAXSIZE_TEMP_ARRAY(a, 1);
ADD(a, INTEGER_OBJ(pid));
- String s = STATIC_CSTR_AS_STRING("return vim._os_proc_children(...)");
- Object o = nlua_exec(s, a, err);
- api_free_array(a);
+ Object o = NLUA_EXEC_STATIC("return vim._os_proc_children(...)", a, err);
if (o.type == kObjectTypeArray) {
rvobj = o.data.array;
} else if (!ERROR_SET(err)) {
@@ -1878,12 +1886,9 @@ Object nvim_get_proc(Integer pid, Error *err)
}
#else
// Cross-platform process info APIs are miserable, so use `ps` instead.
- Array a = ARRAY_DICT_INIT;
+ MAXSIZE_TEMP_ARRAY(a, 1);
ADD(a, INTEGER_OBJ(pid));
- String s = cstr_to_string("return vim._os_proc_info(select(1, ...))");
- Object o = nlua_exec(s, a, err);
- api_free_string(s);
- api_free_array(a);
+ Object o = NLUA_EXEC_STATIC("return vim._os_proc_info(...)", a, err);
if (o.type == kObjectTypeArray && o.data.array.size == 0) {
return NIL; // Process not found.
} else if (o.type == kObjectTypeDictionary) {
@@ -2039,7 +2044,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 {
@@ -2087,7 +2092,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.
@@ -2095,7 +2100,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.
@@ -2227,7 +2232,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);
diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c
index 478e146781..f6d0e39327 100644
--- a/src/nvim/api/vimscript.c
+++ b/src/nvim/api/vimscript.c
@@ -14,8 +14,9 @@
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
#include "nvim/eval/userfunc.h"
-#include "nvim/ex_cmds2.h"
+#include "nvim/ex_docmd.h"
#include "nvim/ops.h"
+#include "nvim/runtime.h"
#include "nvim/strings.h"
#include "nvim/vim.h"
#include "nvim/viml/parser/expressions.h"
@@ -48,6 +49,7 @@ String nvim_exec(uint64_t channel_id, String src, Boolean output, Error *err)
{
const int save_msg_silent = msg_silent;
garray_T *const save_capture_ga = capture_ga;
+ const int save_msg_col = msg_col;
garray_T capture_local;
if (output) {
ga_init(&capture_local, 1, 80);
@@ -57,6 +59,7 @@ String nvim_exec(uint64_t channel_id, String src, Boolean output, Error *err)
try_start();
if (output) {
msg_silent++;
+ msg_col = 0; // prevent leading spaces
}
const sctx_T save_current_sctx = api_set_sctx(channel_id);
@@ -65,6 +68,8 @@ String nvim_exec(uint64_t channel_id, String src, Boolean output, Error *err)
if (output) {
capture_ga = save_capture_ga;
msg_silent = save_msg_silent;
+ // Put msg_col back where it was, since nothing should have been written.
+ msg_col = save_msg_col;
}
current_sctx = save_current_sctx;
@@ -132,7 +137,7 @@ Object nvim_eval(String expr, Error *err)
if (!recursive) {
force_abort = false;
suppress_errthrow = false;
- current_exception = NULL;
+ did_throw = false;
// `did_emsg` is set by emsg(), which cancels execution.
did_emsg = false;
}
@@ -191,7 +196,7 @@ static Object _call_function(String fn, Array args, dict_T *self, Error *err)
if (!recursive) {
force_abort = false;
suppress_errthrow = false;
- current_exception = NULL;
+ did_throw = false;
// `did_emsg` is set by emsg(), which cancels execution.
did_emsg = false;
}
diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c
index 969643eeef..96c560efa1 100644
--- a/src/nvim/api/win_config.c
+++ b/src/nvim/api/win_config.c
@@ -10,9 +10,9 @@
#include "nvim/api/private/helpers.h"
#include "nvim/api/win_config.h"
#include "nvim/ascii.h"
+#include "nvim/drawscreen.h"
#include "nvim/highlight_group.h"
#include "nvim/option.h"
-#include "nvim/screen.h"
#include "nvim/strings.h"
#include "nvim/syntax.h"
#include "nvim/ui.h"
@@ -167,7 +167,7 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dict(float_config) *config, E
if (fconfig.style == kWinStyleMinimal) {
win_set_minimal_style(wp);
- didset_window_options(wp);
+ didset_window_options(wp, true);
}
return wp->handle;
}
@@ -202,14 +202,14 @@ void nvim_win_set_config(Window window, Dict(float_config) *config, Error *err)
if (!win_new_float(win, false, fconfig, err)) {
return;
}
- redraw_later(win, NOT_VALID);
+ redraw_later(win, UPD_NOT_VALID);
} else {
win_config_float(win, fconfig);
win->w_pos_changed = true;
}
if (fconfig.style == kWinStyleMinimal) {
win_set_minimal_style(win);
- didset_window_options(win);
+ didset_window_options(win, true);
}
}
diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c
index 5a4ff70257..5203003369 100644
--- a/src/nvim/api/window.c
+++ b/src/nvim/api/window.c
@@ -12,12 +12,12 @@
#include "nvim/ascii.h"
#include "nvim/buffer.h"
#include "nvim/cursor.h"
+#include "nvim/drawscreen.h"
#include "nvim/ex_docmd.h"
#include "nvim/globals.h"
#include "nvim/lua/executor.h"
#include "nvim/move.h"
#include "nvim/option.h"
-#include "nvim/screen.h"
#include "nvim/syntax.h"
#include "nvim/vim.h"
#include "nvim/window.h"
@@ -118,7 +118,7 @@ void nvim_win_set_cursor(Window window, ArrayOf(Integer, 2) pos, Error *err)
// make sure cursor is in visible range even if win != curwin
update_topline_win(win);
- redraw_later(win, VALID);
+ redraw_later(win, UPD_VALID);
win->w_redr_status = true;
}
@@ -426,3 +426,28 @@ Object nvim_win_call(Window window, LuaRef fun, Error *err)
try_end(err);
return res;
}
+
+/// Set highlight namespace for a window. This will use highlights defined in
+/// this namespace, but fall back to global highlights (ns=0) when missing.
+///
+/// This takes predecence over the 'winhighlight' option.
+///
+/// @param ns_id the namespace to use
+/// @param[out] err Error details, if any
+void nvim_win_set_hl_ns(Window window, Integer ns_id, Error *err)
+ FUNC_API_SINCE(10)
+{
+ win_T *win = find_window_by_handle(window, err);
+ if (!win) {
+ return;
+ }
+
+ // -1 is allowed as inherit global namespace
+ if (ns_id < -1) {
+ api_set_error(err, kErrorTypeValidation, "no such namespace");
+ }
+
+ win->w_ns_hl = (NS)ns_id;
+ win->w_hl_needs_update = true;
+ redraw_later(win, UPD_NOT_VALID);
+}