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/private/helpers.c | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) (limited to 'src/nvim/api/private/helpers.c') 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) { -- 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 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src/nvim/api/private/helpers.c') 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(); } -- 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/private/helpers.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/api/private/helpers.c') 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 91e912f8d40284c74d4a997c8c95961eebb35d91 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Sun, 25 Sep 2022 15:26:37 +0200 Subject: refactor: move klib out of src/nvim/ #20341 It's confusing to mix vendored dependencies with neovim source code. A clean separation is simpler to keep track of and simpler to document. --- src/nvim/api/private/helpers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api/private/helpers.c') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 22d2ffbaf1..b888d09343 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -8,6 +8,7 @@ #include #include +#include "klib/kvec.h" #include "nvim/api/private/converter.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" @@ -22,7 +23,6 @@ #include "nvim/ex_eval.h" #include "nvim/extmark.h" #include "nvim/highlight_group.h" -#include "nvim/lib/kvec.h" #include "nvim/lua/executor.h" #include "nvim/map.h" #include "nvim/map_defs.h" -- cgit From c7d30c152d1639523d05154e245ea60ed9a51a2b Mon Sep 17 00:00:00 2001 From: smolck <46855713+smolck@users.noreply.github.com> Date: Sat, 14 Aug 2021 12:19:05 -0500 Subject: fix(api): notify dict watchers on nvim_set_var and vim.g setter Co-authored-by: bfredl Co-authored-by: Christian Clason --- src/nvim/api/private/helpers.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'src/nvim/api/private/helpers.c') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index b888d09343..73b5489d5c 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -218,6 +218,8 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del, bool retva return rv; } + bool watched = tv_dict_is_watched(dict); + if (del) { // Delete the key if (di == NULL) { @@ -225,6 +227,10 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del, bool retva api_set_error(err, kErrorTypeValidation, "Key not found: %s", key.data); } else { + // Notify watchers + if (watched) { + tv_dict_watcher_notify(dict, key.data, NULL, &di->di_tv); + } // Return the old value if (retval) { rv = vim_to_object(&di->di_tv); @@ -241,11 +247,16 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del, bool retva return rv; } + typval_T oldtv = TV_INITIAL_VALUE; + if (di == NULL) { // Need to create an entry di = tv_dict_item_alloc_len(key.data, key.size); tv_dict_add(dict, di); } else { + if (watched) { + tv_copy(&di->di_tv, &oldtv); + } // Return the old value if (retval) { rv = vim_to_object(&di->di_tv); @@ -255,6 +266,13 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del, bool retva // Update the value tv_copy(&tv, &di->di_tv); + + // Notify watchers + if (watched) { + tv_dict_watcher_notify(dict, key.data, &tv, &oldtv); + tv_clear(&oldtv); + } + // Clear the temporary variable tv_clear(&tv); } -- cgit From f8c671827710c6e9cca3bfd60c32098b2be8239a Mon Sep 17 00:00:00 2001 From: Lewis Russell Date: Mon, 14 Nov 2022 18:04:36 +0000 Subject: feat(lua-api): avoid unnecessary allocations (#19877) Lua makes (or reuses) an internal copy of strings, so we can safely push buf pointers onto the stack. --- src/nvim/api/private/helpers.c | 55 +++++++----------------------------------- 1 file changed, 9 insertions(+), 46 deletions(-) (limited to 'src/nvim/api/private/helpers.c') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 73b5489d5c..d10d17c88d 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -394,6 +394,12 @@ String cstrn_to_string(const char *str, size_t maxsize) return cbuf_to_string(str, STRNLEN(str, maxsize)); } +String cstrn_as_string(char *str, size_t maxsize) + FUNC_ATTR_NONNULL_ALL +{ + return cbuf_as_string(str, STRNLEN(str, maxsize)); +} + /// Creates a String using the given C string. Unlike /// cstr_to_string this function DOES NOT copy the C string. /// @@ -462,53 +468,15 @@ Array string_to_array(const String input, bool crlf) return ret; } -/// Collects `n` buffer lines into array `l`, optionally replacing newlines -/// with NUL. -/// -/// @param buf Buffer to get lines from -/// @param n Number of lines to collect -/// @param replace_nl Replace newlines ("\n") with NUL -/// @param start Line number to start from -/// @param[out] l Lines are copied here -/// @param err[out] Error, if any -/// @return true unless `err` was set -bool buf_collect_lines(buf_T *buf, size_t n, int64_t start, bool replace_nl, Array *l, Error *err) -{ - for (size_t i = 0; i < n; i++) { - int64_t lnum = start + (int64_t)i; - - if (lnum >= MAXLNUM) { - if (err != NULL) { - api_set_error(err, kErrorTypeValidation, "Line index is too high"); - } - return false; - } - - const char *bufstr = ml_get_buf(buf, (linenr_T)lnum, false); - Object str = STRING_OBJ(cstr_to_string(bufstr)); - - if (replace_nl) { - // Vim represents NULs as NLs, but this may confuse clients. - strchrsub(str.data.string.data, '\n', '\0'); - } - - l->items[i] = str; - } - - return true; -} - /// Returns a substring of a buffer line /// /// @param buf Buffer handle /// @param lnum Line number (1-based) /// @param start_col Starting byte offset into line (0-based) /// @param end_col Ending byte offset into line (0-based, exclusive) -/// @param replace_nl Replace newlines ('\n') with null ('\0') /// @param err Error object /// @return The text between start_col and end_col on line lnum of buffer buf -String buf_get_text(buf_T *buf, int64_t lnum, int64_t start_col, int64_t end_col, bool replace_nl, - Error *err) +String buf_get_text(buf_T *buf, int64_t lnum, int64_t start_col, int64_t end_col, Error *err) { String rv = STRING_INIT; @@ -517,7 +485,7 @@ String buf_get_text(buf_T *buf, int64_t lnum, int64_t start_col, int64_t end_col return rv; } - const char *bufstr = ml_get_buf(buf, (linenr_T)lnum, false); + 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; @@ -537,12 +505,7 @@ String buf_get_text(buf_T *buf, int64_t lnum, int64_t start_col, int64_t end_col return rv; } - rv = cstrn_to_string(&bufstr[start_col], (size_t)(end_col - start_col)); - if (replace_nl) { - strchrsub(rv.data, '\n', '\0'); - } - - return rv; + return cstrn_as_string((char *)&bufstr[start_col], (size_t)(end_col - start_col)); } void api_free_string(String value) -- cgit From 66360675cf4d091b7460e4a8e1435c13216c1929 Mon Sep 17 00:00:00 2001 From: dundargoc Date: Sun, 11 Sep 2022 17:12:44 +0200 Subject: build: allow IWYU to fix includes for all .c files Allow Include What You Use to remove unnecessary includes and only include what is necessary. This helps with reducing compilation times and makes it easier to visualise which dependencies are actually required. Work on https://github.com/neovim/neovim/issues/549, but doesn't close it since this only works fully for .c files and not headers. --- src/nvim/api/private/helpers.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'src/nvim/api/private/helpers.c') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index d10d17c88d..b7cd0c82fb 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -3,8 +3,12 @@ #include #include +#include +#include +#include #include #include +#include #include #include @@ -12,28 +16,24 @@ #include "nvim/api/private/converter.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" -#include "nvim/api/vim.h" #include "nvim/ascii.h" -#include "nvim/assert.h" -#include "nvim/buffer.h" -#include "nvim/charset.h" -#include "nvim/eval.h" +#include "nvim/buffer_defs.h" #include "nvim/eval/typval.h" -#include "nvim/ex_cmds_defs.h" +#include "nvim/eval/typval_defs.h" #include "nvim/ex_eval.h" -#include "nvim/extmark.h" +#include "nvim/garray.h" #include "nvim/highlight_group.h" #include "nvim/lua/executor.h" #include "nvim/map.h" -#include "nvim/map_defs.h" #include "nvim/mark.h" #include "nvim/memline.h" #include "nvim/memory.h" +#include "nvim/message.h" #include "nvim/msgpack_rpc/helpers.h" +#include "nvim/pos.h" #include "nvim/ui.h" #include "nvim/version.h" #include "nvim/vim.h" -#include "nvim/window.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/private/funcs_metadata.generated.h" -- cgit From 40f3f75867bf03abfd90e0389a38197a00d37af1 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/private/helpers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api/private/helpers.c') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index b7cd0c82fb..ca8ad16cbf 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -505,7 +505,7 @@ String buf_get_text(buf_T *buf, int64_t lnum, int64_t start_col, int64_t end_col return rv; } - return cstrn_as_string((char *)&bufstr[start_col], (size_t)(end_col - start_col)); + return cstrn_as_string(&bufstr[start_col], (size_t)(end_col - start_col)); } void api_free_string(String value) -- cgit From 3b96ccf7d35be90e49029dec76344d3d92ad91dc Mon Sep 17 00:00:00 2001 From: dundargoc Date: Sat, 26 Nov 2022 18:57:46 +0100 Subject: refactor: replace char_u with char Work on https://github.com/neovim/neovim/issues/459 --- src/nvim/api/private/helpers.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/api/private/helpers.c') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index ca8ad16cbf..4ff600618d 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -391,13 +391,13 @@ String cbuf_to_string(const char *buf, size_t size) String cstrn_to_string(const char *str, size_t maxsize) FUNC_ATTR_NONNULL_ALL { - return cbuf_to_string(str, STRNLEN(str, maxsize)); + return cbuf_to_string(str, strnlen(str, maxsize)); } String cstrn_as_string(char *str, size_t maxsize) FUNC_ATTR_NONNULL_ALL { - return cbuf_as_string(str, STRNLEN(str, maxsize)); + return cbuf_as_string(str, strnlen(str, maxsize)); } /// Creates a String using the given C string. Unlike -- cgit From 3269902a13df3bccf8705db73488c0a47f495514 Mon Sep 17 00:00:00 2001 From: dundargoc <33953936+dundargoc@users.noreply.github.com> Date: Sun, 15 Jan 2023 14:16:33 +0100 Subject: refactor: fix IWYU mapping file and use IWYU (#21802) Also add the EXITFREE definition to main_lib rather than the nvim target, as the header generation needs the EXITFREE flag to work properly. --- src/nvim/api/private/helpers.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src/nvim/api/private/helpers.c') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 4ff600618d..bf19c8c395 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -33,7 +33,6 @@ #include "nvim/pos.h" #include "nvim/ui.h" #include "nvim/version.h" -#include "nvim/vim.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/private/funcs_metadata.generated.h" -- cgit From ce66f158b55287924b33451b272de847ab75b332 Mon Sep 17 00:00:00 2001 From: erw7 Date: Sat, 5 Nov 2022 19:40:02 +0900 Subject: feat(api): show more exception info --- src/nvim/api/private/helpers.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'src/nvim/api/private/helpers.c') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index bf19c8c395..519f2cc5bf 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -150,7 +150,18 @@ bool try_end(Error *err) xfree(msg); } } else if (did_throw) { - api_set_error(err, kErrorTypeException, "%s", current_exception->value); + if (*current_exception->throw_name != NUL) { + if (current_exception->throw_lnum != 0) { + api_set_error(err, kErrorTypeException, "%s, line %" PRIdLINENR ": %s", + current_exception->throw_name, current_exception->throw_lnum, + current_exception->value); + } else { + api_set_error(err, kErrorTypeException, "%s: %s", + current_exception->throw_name, current_exception->value); + } + } else { + api_set_error(err, kErrorTypeException, "%s", current_exception->value); + } discard_current_exception(); } -- cgit