From 6cc6e11929ad76a2dc5204aed95cb9ed1dafde23 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Tue, 23 Aug 2022 22:00:19 +0800 Subject: vim-patch:9.0.0206: redraw flags are not named specifically (#19913) Problem: Redraw flags are not named specifically. Solution: Prefix "UPD_" to the flags, for UPDate_screen(). https://github.com/vim/vim/commit/a4d158b3c839e96ed98ff87c7b7124ff4518c4ff --- src/nvim/api/extmark.c | 2 +- src/nvim/api/vim.c | 2 +- src/nvim/api/win_config.c | 2 +- src/nvim/api/window.c | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 933aa85530..3ac373283c 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -993,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; diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index ce91c1b4af..7fccacdb23 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -198,7 +198,7 @@ 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. diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index 6c37df6af8..96c560efa1 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -202,7 +202,7 @@ 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; diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index 580dfd8639..5203003369 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -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; } @@ -449,5 +449,5 @@ void nvim_win_set_hl_ns(Window window, Integer ns_id, Error *err) win->w_ns_hl = (NS)ns_id; win->w_hl_needs_update = true; - redraw_later(win, NOT_VALID); + redraw_later(win, UPD_NOT_VALID); } -- cgit From c0d60526541a3cf977ae623471ae4a347b492af1 Mon Sep 17 00:00:00 2001 From: bfredl Date: Tue, 23 Aug 2022 09:33:08 +0200 Subject: perf(api): allow to use an arena for return values --- src/nvim/api/buffer.c | 4 ++-- src/nvim/api/private/dispatch.h | 9 +++++++-- src/nvim/api/vim.c | 30 +++++++++++++++++------------- 3 files changed, 26 insertions(+), 17 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 5e90e40dd3..43027473a0 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -1021,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; @@ -1031,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((char *)buf->b_ffname); } /// Sets the full file name for a buffer 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/vim.c b/src/nvim/api/vim.c index ce91c1b4af..c333db1b37 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1629,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 @@ -1676,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; } + if (!handler.arena_return && result.type != kObjectTypeNil) { + // TODO: fix to not leak memory as fuck + } - ADD(results, result); + ADD_C(results, 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(cstr_to_string(nested_error.msg))); // TODO + 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; @@ -1803,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; } -- cgit From 7784dc9e0d90284b0d9c9cf0833c27d4de22b7f4 Mon Sep 17 00:00:00 2001 From: bfredl Date: Tue, 23 Aug 2022 13:52:09 +0200 Subject: refactor(api): provide a temporary copy solution for nvim_call_atomic Make the copy_object() family accept an optional arena. More than half of the callsites should be refactored to use an arena later anyway. --- src/nvim/api/autocmd.c | 4 ++-- src/nvim/api/extmark.c | 2 +- src/nvim/api/private/helpers.c | 33 +++++++++++++++++------------- src/nvim/api/ui.c | 6 +++--- src/nvim/api/vim.c | 46 +++++++++++++++++++++--------------------- 5 files changed, 48 insertions(+), 43 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c index 79ae7994f7..1cf0211f43 100644 --- a/src/nvim/api/autocmd.c +++ b/src/nvim/api/autocmd.c @@ -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/extmark.c b/src/nvim/api/extmark.c index 933aa85530..1d6eaa42b0 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -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; diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index c466fc53e1..e35c58bf1b 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -618,6 +618,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 +631,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 +716,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 +762,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 +849,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/ui.c b/src/nvim/api/ui.c index 6f7bfa244a..e34dcbdb46 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -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 c333db1b37..7b70de7b12 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1479,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; } @@ -1545,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")) { @@ -1560,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); } @@ -1642,21 +1642,21 @@ Array nvim_call_atomic(uint64_t channel_id, Array calls, Arena *arena, Error *er 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 +1664,7 @@ Array nvim_call_atomic(uint64_t channel_id, Array calls, Arena *arena, Error *er api_set_error(err, kErrorTypeValidation, "Args must be Array"); - goto validation_error; + goto theend; } Array args = call.items[1].data.array; @@ -1682,11 +1682,13 @@ Array nvim_call_atomic(uint64_t channel_id, Array calls, Arena *arena, Error *er // error handled after loop break; } - if (!handler.arena_return && result.type != kObjectTypeNil) { - // TODO: fix to not leak memory as fuck + // 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_C(results, result); } ADD_C(rv, ARRAY_OBJ(results)); @@ -1694,14 +1696,12 @@ Array nvim_call_atomic(uint64_t channel_id, Array calls, Arena *arena, Error *er 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(cstr_to_string(nested_error.msg))); // TODO + ADD_C(errval, STRING_OBJ(copy_string(cstr_as_string(nested_error.msg), arena))); ADD_C(rv, ARRAY_OBJ(errval)); } else { ADD_C(rv, NIL); } - goto theend; -validation_error: theend: api_clear_error(&nested_error); return rv; @@ -1754,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. @@ -1767,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. @@ -1780,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. -- cgit From 40855b0143a864739a6037921e15699445dcf8a7 Mon Sep 17 00:00:00 2001 From: Dundar Goc Date: Sun, 31 Jul 2022 16:20:57 +0200 Subject: refactor: replace char_u with char Work on https://github.com/neovim/neovim/issues/459 --- src/nvim/api/buffer.c | 2 +- src/nvim/api/vim.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 43027473a0..199650fc55 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -1031,7 +1031,7 @@ String nvim_buf_get_name(Buffer buffer, Arena *arena, Error *err) return rv; } - return cstr_as_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/vim.c b/src/nvim/api/vim.c index 2fa0277df7..ca98aeb34a 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -2044,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 { @@ -2232,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); -- cgit From 2498e9feb025361576603a0101c86393d211e31e Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Thu, 25 Aug 2022 14:41:02 +0100 Subject: refactor: change FALSE/TRUE to false/true Co-authored-by: zeertzjq --- src/nvim/api/vim.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index ca98aeb34a..b164106cef 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -2092,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. @@ -2100,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. -- cgit From 813476bf7291dfaf9fc0ef77c9f53a07258a3801 Mon Sep 17 00:00:00 2001 From: Sean Dewar Date: Tue, 30 Aug 2022 23:13:52 +0100 Subject: fix(exceptions): restore `did_throw` (#20000) `!did_throw` doesn't exactly imply `!current_exception`, as `did_throw = false` is sometimes used to defer exception handling for later (without forgetting the exception). E.g: uncaught exception handling in `do_cmdline()` may be deferred to a different call (e.g: when `try_level > 0`). In #7881, `current_exception = NULL` in `do_cmdline()` is used as an analogue of `did_throw = false`, but also causes the pending exception to be lost, which also leaks as `discard_exception()` wasn't used. It may be possible to fix this by saving/restoring `current_exception`, but handling all of `did_throw`'s edge cases seems messier. Maybe not worth diverging over. This fix also uncovers a `man_spec.lua` bug on Windows: exceptions are thrown due to Windows missing `man`, but they're lost; skip these tests if `man` isn't executable. --- src/nvim/api/private/helpers.c | 8 ++++++-- src/nvim/api/private/helpers.h | 1 + src/nvim/api/vimscript.c | 4 ++-- 3 files changed, 9 insertions(+), 4 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index e35c58bf1b..ebcf6cca6d 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -58,6 +58,7 @@ void try_enter(TryState *const tstate) .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,6 +87,7 @@ 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); @@ -93,6 +96,7 @@ bool try_leave(const TryState *const tstate, Error *const err) 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(); } diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h index 4608554448..2157ad0ec2 100644 --- a/src/nvim/api/private/helpers.h +++ b/src/nvim/api/private/helpers.h @@ -134,6 +134,7 @@ typedef struct { const msglist_T *const *msg_list; int trylevel; int got_int; + bool did_throw; int need_rethrow; int did_emsg; } TryState; diff --git a/src/nvim/api/vimscript.c b/src/nvim/api/vimscript.c index a28bfd2ab9..f6d0e39327 100644 --- a/src/nvim/api/vimscript.c +++ b/src/nvim/api/vimscript.c @@ -137,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; } @@ -196,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; } -- cgit From fa747d004a1e91b30066020f2f592e4dc5d94084 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 31 Aug 2022 19:47:10 +0800 Subject: fix(api): nvim_set_hl bail out on invalid group name (#20021) --- src/nvim/api/vim.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index b164106cef..a1721d433f 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -86,8 +86,7 @@ Dictionary nvim_get_hl_by_name(String name, Boolean rgb, Error *err) 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); @@ -105,8 +104,7 @@ Dictionary nvim_get_hl_by_id(Integer hl_id, Boolean rgb, Error *err) { 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); @@ -175,6 +173,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); -- cgit From 933c80e8f9d7ff4ab634c14d370440702c7c8ed7 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Wed, 31 Aug 2022 21:14:14 +0800 Subject: refactor(mappings)!: mapblock_fill_dict() use API Dictionary (#20020) This introduces the following breaking changes: - nvim_get_keymap now always returns a LuaRef object as "callback" for a Lua mapping regardless of how it is called. The LuaRef object can be called from Lua and Vim script, but is lost over RPC. - maparg() now returns a Funcref instead of a ref number as "callback" for a Lua mapping. The Funcref can be called from Lua and Vim script, but is lost over RPC. This may also make nvim_get_keymap faster, but make maparg() slower. --- src/nvim/api/buffer.c | 4 ++-- src/nvim/api/vim.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 199650fc55..16f574f46d 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -945,7 +945,7 @@ Integer nvim_buf_get_changedtick(Buffer buffer, Error *err) /// @param[out] err Error details, if any /// @returns Array of |maparg()|-like dictionaries describing mappings. /// The "buffer" key holds the associated buffer handle. -ArrayOf(Dictionary) nvim_buf_get_keymap(uint64_t channel_id, Buffer buffer, String mode, Error *err) +ArrayOf(Dictionary) nvim_buf_get_keymap(Buffer buffer, String mode, Error *err) FUNC_API_SINCE(3) { buf_T *buf = find_buffer_by_handle(buffer, err); @@ -954,7 +954,7 @@ ArrayOf(Dictionary) nvim_buf_get_keymap(uint64_t channel_id, Buffer buffer, Stri return (Array)ARRAY_DICT_INIT; } - return keymap_array(mode, buf, channel_id == LUA_INTERNAL_CALL); + return keymap_array(mode, buf); } /// Sets a buffer-local |mapping| for the given mode. diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index a1721d433f..9e1f2dd631 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -1421,10 +1421,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. -- cgit From f31db30975479cb6b57247f124a65f4362f80bfe Mon Sep 17 00:00:00 2001 From: bfredl Date: Thu, 30 Jun 2022 13:26:31 +0600 Subject: feat(lua): vim.ui_attach to get ui events from lua Co-authored-by: Famiu Haque --- src/nvim/api/extmark.c | 2 +- src/nvim/api/ui.c | 1 + src/nvim/api/ui_events.in.h | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 09b004637f..6ff0a2ed21 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -87,7 +87,7 @@ const char *describe_ns(NS ns_id) } // Is the Namespace in use? -static bool ns_initialized(uint32_t ns) +bool ns_initialized(uint32_t ns) { if (ns < 1) { return false; diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index e34dcbdb46..654eb19bec 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -223,6 +223,7 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, Dictiona ui->msg_set_pos = remote_ui_msg_set_pos; ui->event = remote_ui_event; ui->inspect = remote_ui_inspect; + ui->win_viewport = remote_ui_win_viewport; CLEAR_FIELD(ui->ui_ext); diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h index 8b7e01e1c3..17930dca85 100644 --- a/src/nvim/api/ui_events.in.h +++ b/src/nvim/api/ui_events.in.h @@ -100,7 +100,7 @@ void raw_line(Integer grid, Integer row, Integer startcol, FUNC_API_NOEXPORT FUNC_API_COMPOSITOR_IMPL; void event(char *name, Array args) - FUNC_API_NOEXPORT; + FUNC_API_NOEXPORT FUNC_API_COMPOSITOR_IMPL; void win_pos(Integer grid, Window win, Integer startrow, Integer startcol, Integer width, Integer height) @@ -121,7 +121,7 @@ void msg_set_pos(Integer grid, Integer row, Boolean scrolled, String sep_char) void win_viewport(Integer grid, Window win, Integer topline, Integer botline, Integer curline, Integer curcol, Integer line_count) - FUNC_API_SINCE(7) FUNC_API_REMOTE_ONLY; + FUNC_API_SINCE(7) FUNC_API_BRIDGE_IMPL; void win_extmark(Integer grid, Window win, Integer ns_id, Integer mark_id, Integer row, Integer col) -- cgit From ba8be7446d440053b24358046e8e4033e3447633 Mon Sep 17 00:00:00 2001 From: bfredl Date: Wed, 31 Aug 2022 14:49:15 +0200 Subject: refactor(highlight): make hlattrs2dict always use pre-allocated dict hlattrs2dict used to work with both allocated and unallocated dicts which was quite messy. Now always delegate allocation to caller. --- src/nvim/api/ui.c | 64 +++++++++++++++++++++++++++++------------------------- src/nvim/api/vim.c | 22 +++++++++---------- 2 files changed, 45 insertions(+), 41 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index e34dcbdb46..110bd6920e 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -748,10 +748,12 @@ static void remote_ui_hl_attr_define(UI *ui, Integer id, HlAttrs rgb_attrs, HlAt UIData *data = ui->data; Array args = data->call_buf; ADD_C(args, INTEGER_OBJ(id)); - MAXSIZE_TEMP_DICT(rgb, 16); - MAXSIZE_TEMP_DICT(cterm, 16); - ADD_C(args, DICTIONARY_OBJ(hlattrs2dict(&rgb, rgb_attrs, true))); - ADD_C(args, DICTIONARY_OBJ(hlattrs2dict(&cterm, cterm_attrs, false))); + MAXSIZE_TEMP_DICT(rgb, HLATTRS_DICT_SIZE); + MAXSIZE_TEMP_DICT(cterm, HLATTRS_DICT_SIZE); + hlattrs2dict(&rgb, rgb_attrs, true); + hlattrs2dict(&cterm, rgb_attrs, false); + ADD_C(args, DICTIONARY_OBJ(rgb)); + ADD_C(args, DICTIONARY_OBJ(cterm)); if (ui->ui_ext[kUIHlState]) { ADD_C(args, ARRAY_OBJ(info)); @@ -771,8 +773,9 @@ static void remote_ui_highlight_set(UI *ui, int id) return; } data->hl_id = id; - MAXSIZE_TEMP_DICT(dict, 16); - ADD_C(args, DICTIONARY_OBJ(hlattrs2dict(&dict, syn_attr2entry(id), ui->rgb))); + MAXSIZE_TEMP_DICT(dict, HLATTRS_DICT_SIZE); + hlattrs2dict(&dict, syn_attr2entry(id), ui->rgb); + ADD_C(args, DICTIONARY_OBJ(dict)); push_call(ui, "highlight_set", args); } @@ -952,65 +955,63 @@ static void remote_ui_flush(UI *ui) } } -static Array translate_contents(UI *ui, Array contents) +static Array translate_contents(UI *ui, Array contents, Arena *arena) { - Array new_contents = ARRAY_DICT_INIT; + Array new_contents = arena_array(arena, contents.size); for (size_t i = 0; i < contents.size; i++) { Array item = contents.items[i].data.array; - Array new_item = ARRAY_DICT_INIT; + Array new_item = arena_array(arena, 2); int attr = (int)item.items[0].data.integer; if (attr) { - Dictionary rgb_attrs = hlattrs2dict(NULL, syn_attr2entry(attr), ui->rgb); + Dictionary rgb_attrs = arena_dict(arena, HLATTRS_DICT_SIZE); + hlattrs2dict(&rgb_attrs, syn_attr2entry(attr), ui->rgb); ADD(new_item, DICTIONARY_OBJ(rgb_attrs)); } else { ADD(new_item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT)); } - ADD(new_item, copy_object(item.items[1], NULL)); + ADD(new_item, item.items[1]); ADD(new_contents, ARRAY_OBJ(new_item)); } return new_contents; } -static Array translate_firstarg(UI *ui, Array args) +static Array translate_firstarg(UI *ui, Array args, Arena *arena) { - Array new_args = ARRAY_DICT_INIT; + Array new_args = arena_array(arena, args.size); Array contents = args.items[0].data.array; - ADD(new_args, ARRAY_OBJ(translate_contents(ui, contents))); + ADD_C(new_args, ARRAY_OBJ(translate_contents(ui, contents, arena))); for (size_t i = 1; i < args.size; i++) { - ADD(new_args, copy_object(args.items[i], NULL)); + ADD(new_args, args.items[i]); } return new_args; } static void remote_ui_event(UI *ui, char *name, Array args) { + Arena arena = ARENA_EMPTY; UIData *data = ui->data; if (!ui->ui_ext[kUILinegrid]) { // the representation of highlights in cmdline changed, translate back // never consumes args if (strequal(name, "cmdline_show")) { - Array new_args = translate_firstarg(ui, args); + Array new_args = translate_firstarg(ui, args, &arena); push_call(ui, name, new_args); - api_free_array(new_args); - return; + goto free_ret; } else if (strequal(name, "cmdline_block_show")) { Array new_args = data->call_buf; Array block = args.items[0].data.array; - Array new_block = ARRAY_DICT_INIT; + Array new_block = arena_array(&arena, block.size); for (size_t i = 0; i < block.size; i++) { - ADD(new_block, - ARRAY_OBJ(translate_contents(ui, block.items[i].data.array))); + ADD_C(new_block, ARRAY_OBJ(translate_contents(ui, block.items[i].data.array, &arena))); } ADD_C(new_args, ARRAY_OBJ(new_block)); push_call(ui, name, new_args); - api_free_array(new_block); - return; + goto free_ret; } else if (strequal(name, "cmdline_block_append")) { - Array new_args = translate_firstarg(ui, args); + Array new_args = translate_firstarg(ui, args, &arena); push_call(ui, name, new_args); - api_free_array(new_args); - return; + goto free_ret; } } @@ -1022,19 +1023,18 @@ static void remote_ui_event(UI *ui, char *name, Array args) if (data->wildmenu_active) { Array new_args = data->call_buf; Array items = args.items[0].data.array; - Array new_items = ARRAY_DICT_INIT; + Array new_items = arena_array(&arena, items.size); for (size_t i = 0; i < items.size; i++) { - ADD(new_items, copy_object(items.items[i].data.array.items[0], NULL)); + ADD_C(new_items, items.items[i].data.array.items[0]); } ADD_C(new_args, ARRAY_OBJ(new_items)); push_call(ui, "wildmenu_show", new_args); - api_free_array(new_items); if (args.items[1].data.integer != -1) { Array new_args2 = data->call_buf; ADD_C(new_args2, args.items[1]); push_call(ui, "wildmenu_select", new_args2); } - return; + goto free_ret; } } else if (strequal(name, "popupmenu_select")) { if (data->wildmenu_active) { @@ -1048,6 +1048,10 @@ static void remote_ui_event(UI *ui, char *name, Array args) } push_call(ui, name, args); + return; + +free_ret: + arena_mem_free(arena_finish(&arena)); } static void remote_ui_inspect(UI *ui, Dictionary *info) diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 9e1f2dd631..83d6ba8dc7 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -79,7 +79,7 @@ /// @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; @@ -89,8 +89,7 @@ Dictionary nvim_get_hl_by_name(String name, Boolean rgb, Error *err) 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()| @@ -99,7 +98,7 @@ 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; @@ -108,7 +107,7 @@ Dictionary nvim_get_hl_by_id(Integer hl_id, Boolean rgb, Error *err) 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 @@ -120,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(); } @@ -1934,7 +1933,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; @@ -1958,13 +1957,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; } -- cgit From 689f5d604e59eba1ddab6f91b458a8163dc6629d Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 1 Sep 2022 20:32:59 +0800 Subject: feat(api): add support for :horizontal modifier --- src/nvim/api/command.c | 7 +++++++ src/nvim/api/keysets.lua | 1 + 2 files changed, 8 insertions(+) (limited to 'src/nvim/api') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 1323fc347b..b821e07d60 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -62,6 +62,7 @@ /// - browse: (boolean) |:browse|. /// - confirm: (boolean) |:confirm|. /// - hide: (boolean) |:hide|. +/// - horizontal: (boolean) |:horizontal|. /// - keepalt: (boolean) |:keepalt|. /// - keepjumps: (boolean) |:keepjumps|. /// - keepmarks: (boolean) |:keepmarks|. @@ -250,6 +251,7 @@ Dictionary nvim_parse_cmd(String str, Dictionary opts, Error *err) PUT(mods, "lockmarks", BOOLEAN_OBJ(cmdinfo.cmdmod.cmod_flags & CMOD_LOCKMARKS)); PUT(mods, "noswapfile", BOOLEAN_OBJ(cmdinfo.cmdmod.cmod_flags & CMOD_NOSWAPFILE)); PUT(mods, "vertical", BOOLEAN_OBJ(cmdinfo.cmdmod.cmod_split & WSP_VERT)); + PUT(mods, "horizontal", BOOLEAN_OBJ(cmdinfo.cmdmod.cmod_split & WSP_HOR)); const char *split; if (cmdinfo.cmdmod.cmod_split & WSP_BOT) { @@ -576,6 +578,10 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error OBJ_TO_BOOL(vertical, mods.vertical, false, "'mods.vertical'"); cmdinfo.cmdmod.cmod_split |= (vertical ? WSP_VERT : 0); + bool horizontal; + OBJ_TO_BOOL(horizontal, mods.horizontal, false, "'mods.horizontal'"); + cmdinfo.cmdmod.cmod_split |= (horizontal ? WSP_HOR : 0); + if (HAS_KEY(mods.split)) { if (mods.split.type != kObjectTypeString) { VALIDATION_ERROR("'mods.split' must be a String"); @@ -753,6 +759,7 @@ static void build_cmdline_str(char **cmdlinep, exarg_T *eap, CmdParseInfo *cmdin } while (0) CMDLINE_APPEND_IF(cmdinfo->cmdmod.cmod_split & WSP_VERT, "vertical "); + CMDLINE_APPEND_IF(cmdinfo->cmdmod.cmod_split & WSP_HOR, "horizontal "); CMDLINE_APPEND_IF(cmdinfo->cmdmod.cmod_flags & CMOD_SANDBOX, "sandbox "); CMDLINE_APPEND_IF(cmdinfo->cmdmod.cmod_flags & CMOD_NOAUTOCMD, "noautocmd "); CMDLINE_APPEND_IF(cmdinfo->cmdmod.cmod_flags & CMOD_BROWSE, "browse "); diff --git a/src/nvim/api/keysets.lua b/src/nvim/api/keysets.lua index 6fad52ba75..af3dc24f51 100644 --- a/src/nvim/api/keysets.lua +++ b/src/nvim/api/keysets.lua @@ -188,6 +188,7 @@ return { "browse"; "confirm"; "hide"; + "horizontal"; "keepalt"; "keepjumps"; "keepmarks"; -- cgit From 1ef7720567b08caec0c077605fb2a01a9d6eafbc Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Thu, 1 Sep 2022 18:46:34 +0800 Subject: fix(api)!: correctly deal with number before :tab Now nvim_parse_cmd and nvim_create_user_command use a "tab" value which is the same as the number passed before :tab modifier instead of the number plus 1, and "tab" value is -1 if :tab modifier is not used. --- src/nvim/api/command.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index b821e07d60..11715a49dc 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -69,7 +69,7 @@ /// - keeppatterns: (boolean) |:keeppatterns|. /// - lockmarks: (boolean) |:lockmarks|. /// - noswapfile: (boolean) |:noswapfile|. -/// - tab: (integer) |:tab|. +/// - tab: (integer) |:tab|. -1 when omitted. /// - verbose: (integer) |:verbose|. -1 when omitted. /// - vertical: (boolean) |:vertical|. /// - split: (string) Split modifier string, is an empty string when there's no split @@ -239,7 +239,7 @@ Dictionary nvim_parse_cmd(String str, Dictionary opts, Error *err) PUT(mods, "unsilent", BOOLEAN_OBJ(cmdinfo.cmdmod.cmod_flags & CMOD_UNSILENT)); PUT(mods, "sandbox", BOOLEAN_OBJ(cmdinfo.cmdmod.cmod_flags & CMOD_SANDBOX)); PUT(mods, "noautocmd", BOOLEAN_OBJ(cmdinfo.cmdmod.cmod_flags & CMOD_NOAUTOCMD)); - PUT(mods, "tab", INTEGER_OBJ(cmdinfo.cmdmod.cmod_tab)); + PUT(mods, "tab", INTEGER_OBJ(cmdinfo.cmdmod.cmod_tab - 1)); PUT(mods, "verbose", INTEGER_OBJ(cmdinfo.cmdmod.cmod_verbose - 1)); PUT(mods, "browse", BOOLEAN_OBJ(cmdinfo.cmdmod.cmod_flags & CMOD_BROWSE)); PUT(mods, "confirm", BOOLEAN_OBJ(cmdinfo.cmdmod.cmod_flags & CMOD_CONFIRM)); @@ -559,15 +559,17 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error } if (HAS_KEY(mods.tab)) { - if (mods.tab.type != kObjectTypeInteger || mods.tab.data.integer < 0) { - VALIDATION_ERROR("'mods.tab' must be a non-negative Integer"); + if (mods.tab.type != kObjectTypeInteger) { + VALIDATION_ERROR("'mods.tab' must be an Integer"); + } else if ((int)mods.tab.data.integer >= 0) { + // Silently ignore negative integers to allow mods.tab to be set to -1. + cmdinfo.cmdmod.cmod_tab = (int)mods.tab.data.integer + 1; } - cmdinfo.cmdmod.cmod_tab = (int)mods.tab.data.integer + 1; } if (HAS_KEY(mods.verbose)) { if (mods.verbose.type != kObjectTypeInteger) { - VALIDATION_ERROR("'mods.verbose' must be a Integer"); + VALIDATION_ERROR("'mods.verbose' must be an Integer"); } else if ((int)mods.verbose.data.integer >= 0) { // Silently ignore negative integers to allow mods.verbose to be set to -1. cmdinfo.cmdmod.cmod_verbose = (int)mods.verbose.data.integer + 1; -- cgit From ceb09701f29dcabcf219f458fffbb64f5adced9b Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 24 Jul 2022 13:58:29 +0800 Subject: feat(api): add "move" to nvim_input_mouse --- src/nvim/api/vim.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 83d6ba8dc7..95c9919522 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -336,9 +336,9 @@ Integer nvim_input(String keys) /// mouse input in a GUI. The deprecated pseudokey form /// ("") 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" @@ -365,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; } @@ -381,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")) { -- cgit From 75adfefc85bcf0d62d2c0f51a951e6003b595cea Mon Sep 17 00:00:00 2001 From: Thomas Vigouroux Date: Mon, 18 Jul 2022 14:21:40 +0200 Subject: feat(extmarks,ts,spell): full support for spelling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added 'spell' option to extmarks: Extmarks with this set will have the region spellchecked. - Added 'noplainbuffer' option to 'spelloptions': This is used to tell Neovim not to spellcheck the buffer. The old behaviour was to spell check the whole buffer unless :syntax was set. - Added spelling support to the treesitter highlighter: @spell captures in highlights.scm are used to define regions which should be spell checked. - Added support for navigating spell errors for extmarks: Works for both ephemeral and static extmarks - Added '_on_spell_nav' callback for decoration providers: Since ephemeral callbacks are only drawn for the visible screen, providers must implement this callback to instruct Neovim which regions in the buffer need can be spell checked. The callback takes a start position and an end position. Note: this callback is subject to change hence the _ prefix. - Added spell captures for built-in support languages Co-authored-by: Lewis Russell Co-authored-by: Björn Linse --- src/nvim/api/extmark.c | 65 +++++++++++++++++++++++++----------------------- src/nvim/api/keysets.lua | 10 ++++++++ 2 files changed, 44 insertions(+), 31 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 6ff0a2ed21..ae051d8cab 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -473,6 +473,8 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e /// When a character is supplied it is used as |:syn-cchar|. /// "hl_group" is used as highlight for the cchar if provided, /// otherwise it defaults to |hl-Conceal|. +/// - spell: boolean indicating that spell checking should be +/// performed within this extmark /// - ui_watched: boolean that indicates the mark should be drawn /// by a UI. When set, the UI will receive win_extmark events. /// Note: the mark is positioned by virt_text attributes. Can be @@ -719,6 +721,11 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer bool ephemeral = false; OPTION_TO_BOOL(ephemeral, ephemeral, false); + OPTION_TO_BOOL(decor.spell, spell, false); + if (decor.spell) { + has_decor = true; + } + OPTION_TO_BOOL(decor.ui_watched, ui_watched, false); if (decor.ui_watched) { has_decor = true; @@ -972,20 +979,21 @@ void nvim_buf_clear_namespace(Buffer buffer, Integer ns_id, Integer line_start, /// for the moment. /// /// @param ns_id Namespace id from |nvim_create_namespace()| -/// @param opts Callbacks invoked during redraw: +/// @param opts Table of callbacks: /// - on_start: called first on each screen redraw /// ["start", tick] -/// - on_buf: called for each buffer being redrawn (before window -/// callbacks) +/// - on_buf: called for each buffer being redrawn (before +/// window callbacks) /// ["buf", bufnr, tick] -/// - on_win: called when starting to redraw a specific window. +/// - on_win: called when starting to redraw a +/// specific window. /// ["win", winid, bufnr, topline, botline_guess] -/// - on_line: called for each buffer line being redrawn. (The -/// interaction with fold lines is subject to change) +/// - on_line: called for each buffer line being redrawn. +/// (The interaction with fold lines is subject to change) /// ["win", winid, bufnr, row] /// - on_end: called at the end of a redraw cycle /// ["end", tick] -void nvim_set_decoration_provider(Integer ns_id, DictionaryOf(LuaRef) opts, Error *err) +void nvim_set_decoration_provider(Integer ns_id, Dict(set_decoration_provider) *opts, Error *err) FUNC_API_SINCE(7) FUNC_API_LUA_ONLY { DecorProvider *p = get_decor_provider((NS)ns_id, true); @@ -997,37 +1005,32 @@ void nvim_set_decoration_provider(Integer ns_id, DictionaryOf(LuaRef) opts, Erro struct { const char *name; + Object *source; LuaRef *dest; } cbs[] = { - { "on_start", &p->redraw_start }, - { "on_buf", &p->redraw_buf }, - { "on_win", &p->redraw_win }, - { "on_line", &p->redraw_line }, - { "on_end", &p->redraw_end }, - { "_on_hl_def", &p->hl_def }, - { NULL, NULL }, + { "on_start", &opts->on_start, &p->redraw_start }, + { "on_buf", &opts->on_buf, &p->redraw_buf }, + { "on_win", &opts->on_win, &p->redraw_win }, + { "on_line", &opts->on_line, &p->redraw_line }, + { "on_end", &opts->on_end, &p->redraw_end }, + { "_on_hl_def", &opts->_on_hl_def, &p->hl_def }, + { "_on_spell_nav", &opts->_on_spell_nav, &p->spell_nav }, + { NULL, NULL, NULL }, }; - for (size_t i = 0; i < opts.size; i++) { - String k = opts.items[i].key; - Object *v = &opts.items[i].value; - size_t j; - for (j = 0; cbs[j].name && cbs[j].dest; j++) { - if (strequal(cbs[j].name, k.data)) { - if (v->type != kObjectTypeLuaRef) { - api_set_error(err, kErrorTypeValidation, - "%s is not a function", cbs[j].name); - goto error; - } - *(cbs[j].dest) = v->data.luaref; - v->data.luaref = LUA_NOREF; - break; - } + for (size_t i = 0; cbs[i].source && cbs[i].dest && cbs[i].name; i++) { + Object *v = cbs[i].source; + if (v->type == kObjectTypeNil) { + continue; } - if (!cbs[j].name) { - api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data); + + if (v->type != kObjectTypeLuaRef) { + api_set_error(err, kErrorTypeValidation, + "%s is not a function", cbs[i].name); goto error; } + *(cbs[i].dest) = v->data.luaref; + v->data.luaref = LUA_NOREF; } p->active = true; diff --git a/src/nvim/api/keysets.lua b/src/nvim/api/keysets.lua index af3dc24f51..ea8949bd2c 100644 --- a/src/nvim/api/keysets.lua +++ b/src/nvim/api/keysets.lua @@ -2,6 +2,15 @@ return { context = { "types"; }; + set_decoration_provider = { + "on_start"; + "on_buf"; + "on_win"; + "on_line"; + "on_end"; + "_on_hl_def"; + "_on_spell_nav"; + }; set_extmark = { "id"; "end_line"; @@ -28,6 +37,7 @@ return { "line_hl_group"; "cursorline_hl_group"; "conceal"; + "spell"; "ui_watched"; }; keymap = { -- cgit From 73207cae611a1efb8cd17139e8228772daeb9866 Mon Sep 17 00:00:00 2001 From: Dundar Göc Date: Fri, 26 Aug 2022 23:11:25 +0200 Subject: refactor: replace char_u with char Work on https://github.com/neovim/neovim/issues/459 --- src/nvim/api/buffer.c | 6 +++--- src/nvim/api/private/helpers.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 16f574f46d..6f8cad3e33 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -570,7 +570,7 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In char *str_at_end = NULL; // Another call to ml_get_buf() may free the line, so make a copy. - str_at_start = xstrdup((char *)ml_get_buf(buf, (linenr_T)start_row, false)); + str_at_start = xstrdup(ml_get_buf(buf, (linenr_T)start_row, false)); size_t len_at_start = strlen(str_at_start); if (start_col < 0 || (size_t)start_col > len_at_start) { api_set_error(err, kErrorTypeValidation, "start_col out of bounds"); @@ -578,7 +578,7 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In } // Another call to ml_get_buf() may free the line, so make a copy. - str_at_end = xstrdup((char *)ml_get_buf(buf, (linenr_T)end_row, false)); + str_at_end = xstrdup(ml_get_buf(buf, (linenr_T)end_row, false)); size_t len_at_end = strlen(str_at_end); if (end_col < 0 || (size_t)end_col > len_at_end) { api_set_error(err, kErrorTypeValidation, "end_col out of bounds"); @@ -608,7 +608,7 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In for (int64_t i = 1; i < end_row - start_row; i++) { int64_t lnum = start_row + i; - const char *bufline = (char *)ml_get_buf(buf, (linenr_T)lnum, false); + const char *bufline = ml_get_buf(buf, (linenr_T)lnum, false); old_byte += (bcount_t)(strlen(bufline)) + 1; } old_byte += (bcount_t)end_col + 1; diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index ebcf6cca6d..22d2ffbaf1 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -466,7 +466,7 @@ bool buf_collect_lines(buf_T *buf, size_t n, int64_t start, bool replace_nl, Arr return false; } - const char *bufstr = (char *)ml_get_buf(buf, (linenr_T)lnum, false); + const char *bufstr = ml_get_buf(buf, (linenr_T)lnum, false); Object str = STRING_OBJ(cstr_to_string(bufstr)); if (replace_nl) { @@ -499,7 +499,7 @@ String buf_get_text(buf_T *buf, int64_t lnum, int64_t start_col, int64_t end_col return rv; } - const char *bufstr = (char *)ml_get_buf(buf, (linenr_T)lnum, false); + const char *bufstr = ml_get_buf(buf, (linenr_T)lnum, false); size_t line_length = strlen(bufstr); start_col = start_col < 0 ? (int64_t)line_length + start_col + 1 : start_col; -- cgit From db9b8b08e74ae8cfb08960eca0a7273538ebcdf1 Mon Sep 17 00:00:00 2001 From: bfredl Date: Tue, 6 Sep 2022 22:23:54 +0200 Subject: refactor(typval): change FC_CFUNC abstraction into FC_LUAREF "cfuncs" was only ever used to wrap luarefs. As vim8script is finished and will not be developed further, support for "cfuncs" for other usecases are not planned. This abstraction was immediately broken anyway in order to get luarefs out of userfuncs again. Even if a new kind of userfunc needs to be invented in the future, likely just extending the FC_... flag union directy, instead of invoking unnecessary heap object and c function pointer indirection, will be a more straightforward design pattern. --- src/nvim/api/private/converter.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/private/converter.c b/src/nvim/api/private/converter.c index 8724ef4432..b6b3c83f3c 100644 --- a/src/nvim/api/private/converter.c +++ b/src/nvim/api/private/converter.c @@ -65,8 +65,8 @@ typedef struct { #define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \ do { \ ufunc_T *fp = find_func(fun); \ - if (fp != NULL && fp->uf_cb == nlua_CFunction_func_call) { \ - LuaRef ref = api_new_luaref(((LuaCFunctionState *)fp->uf_cb_state)->lua_callable.func_ref); \ + if (fp != NULL && (fp->uf_flags & FC_LUAREF)) { \ + LuaRef ref = api_new_luaref(fp->uf_luaref); \ kvi_push(edata->stack, LUAREF_OBJ(ref)); \ } else { \ TYPVAL_ENCODE_CONV_NIL(tv); \ @@ -351,10 +351,7 @@ bool object_to_vim(Object obj, typval_T *tv, Error *err) } case kObjectTypeLuaRef: { - LuaCFunctionState *state = xmalloc(sizeof(LuaCFunctionState)); - state->lua_callable.func_ref = api_new_luaref(obj.data.luaref); - char *name = - (char *)register_cfunc(&nlua_CFunction_func_call, &nlua_CFunction_func_free, state); + char *name = (char *)register_luafunc(api_new_luaref(obj.data.luaref)); tv->v_type = VAR_FUNC; tv->vval.v_string = xstrdup(name); break; -- cgit From c5322e752e9e568de907f7a1ef733bbfe342140c Mon Sep 17 00:00:00 2001 From: Dundar Göc Date: Fri, 26 Aug 2022 23:11:25 +0200 Subject: refactor: replace char_u with char Work on https://github.com/neovim/neovim/issues/459 --- src/nvim/api/command.c | 14 +++++++------- src/nvim/api/ui.c | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c index 11715a49dc..b3518f1b0f 100644 --- a/src/nvim/api/command.c +++ b/src/nvim/api/command.c @@ -591,15 +591,15 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Error if (*mods.split.data.string.data == NUL) { // Empty string, do nothing. - } else if (STRCMP(mods.split.data.string.data, "aboveleft") == 0 - || STRCMP(mods.split.data.string.data, "leftabove") == 0) { + } else if (strcmp(mods.split.data.string.data, "aboveleft") == 0 + || strcmp(mods.split.data.string.data, "leftabove") == 0) { cmdinfo.cmdmod.cmod_split |= WSP_ABOVE; - } else if (STRCMP(mods.split.data.string.data, "belowright") == 0 - || STRCMP(mods.split.data.string.data, "rightbelow") == 0) { + } else if (strcmp(mods.split.data.string.data, "belowright") == 0 + || strcmp(mods.split.data.string.data, "rightbelow") == 0) { cmdinfo.cmdmod.cmod_split |= WSP_BELOW; - } else if (STRCMP(mods.split.data.string.data, "topleft") == 0) { + } else if (strcmp(mods.split.data.string.data, "topleft") == 0) { cmdinfo.cmdmod.cmod_split |= WSP_TOP; - } else if (STRCMP(mods.split.data.string.data, "botright") == 0) { + } else if (strcmp(mods.split.data.string.data, "botright") == 0) { cmdinfo.cmdmod.cmod_split |= WSP_BOT; } else { VALIDATION_ERROR("Invalid value for 'mods.split'"); @@ -938,7 +938,7 @@ void nvim_buf_del_user_command(Buffer buffer, String name, Error *err) for (int i = 0; i < gap->ga_len; i++) { ucmd_T *cmd = USER_CMD_GA(gap, i); - if (!STRCMP(name.data, cmd->uc_name)) { + if (!strcmp(name.data, cmd->uc_name)) { free_ucmd(cmd); gap->ga_len -= 1; diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index 1534e547b0..27fb4b8e16 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -845,7 +845,7 @@ static void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startc for (size_t i = 0; i < ncells; i++) { repeat++; if (i == ncells - 1 || attrs[i] != attrs[i + 1] - || STRCMP(chunk[i], chunk[i + 1])) { + || strcmp(chunk[i], chunk[i + 1])) { if (UI_BUF_SIZE - BUF_POS(data) < 2 * (1 + 2 + sizeof(schar_T) + 5 + 5)) { // close to overflowing the redraw buffer. finish this event, // flush, and start a new "grid_line" event at the current position. -- cgit