diff options
Diffstat (limited to 'src/nvim/api/private')
-rw-r--r-- | src/nvim/api/private/converter.c | 18 | ||||
-rw-r--r-- | src/nvim/api/private/defs.h | 6 | ||||
-rw-r--r-- | src/nvim/api/private/dispatch.c | 29 | ||||
-rw-r--r-- | src/nvim/api/private/dispatch.h | 17 | ||||
-rw-r--r-- | src/nvim/api/private/helpers.c | 150 | ||||
-rw-r--r-- | src/nvim/api/private/helpers.h | 9 |
6 files changed, 110 insertions, 119 deletions
diff --git a/src/nvim/api/private/converter.c b/src/nvim/api/private/converter.c index 8724ef4432..58ff552ab7 100644 --- a/src/nvim/api/private/converter.c +++ b/src/nvim/api/private/converter.c @@ -2,17 +2,24 @@ // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com #include <assert.h> +#include <stdbool.h> #include <stddef.h> +#include <stdint.h> #include <stdlib.h> +#include "klib/kvec.h" #include "nvim/api/private/converter.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" #include "nvim/assert.h" #include "nvim/eval/typval.h" +#include "nvim/eval/typval_defs.h" #include "nvim/eval/userfunc.h" -#include "nvim/lua/converter.h" +#include "nvim/garray.h" #include "nvim/lua/executor.h" +#include "nvim/memory.h" +#include "nvim/types.h" +#include "nvim/vim.h" /// Helper structure for vim_to_object typedef struct { @@ -65,8 +72,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 +358,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 = register_luafunc(api_new_luaref(obj.data.luaref)); tv->v_type = VAR_FUNC; tv->vval.v_string = xstrdup(name); break; diff --git a/src/nvim/api/private/defs.h b/src/nvim/api/private/defs.h index 9c7e59e4b3..8acbf0d9de 100644 --- a/src/nvim/api/private/defs.h +++ b/src/nvim/api/private/defs.h @@ -5,14 +5,14 @@ #include <stdint.h> #include <string.h> +#include "klib/kvec.h" #include "nvim/func_attr.h" -#include "nvim/lib/kvec.h" #include "nvim/types.h" #define ARRAY_DICT_INIT KV_INITIAL_VALUE #define STRING_INIT { .data = NULL, .size = 0 } #define OBJECT_INIT { .type = kObjectTypeNil } -#define ERROR_INIT { .type = kErrorTypeNone, .msg = NULL } +#define ERROR_INIT ((Error) { .type = kErrorTypeNone, .msg = NULL }) #define REMOTE_TYPE(type) typedef handle_T type #define ERROR_SET(e) ((e)->type != kErrorTypeNone) @@ -48,7 +48,7 @@ typedef enum { /// Internal call from lua code #define LUA_INTERNAL_CALL (VIML_INTERNAL_CALL + 1) -static inline bool is_internal_call(const uint64_t channel_id) +static inline bool is_internal_call(uint64_t channel_id) REAL_FATTR_ALWAYS_INLINE REAL_FATTR_CONST; /// Check whether call is internal diff --git a/src/nvim/api/private/dispatch.c b/src/nvim/api/private/dispatch.c index d6a6fc1219..f427bba00e 100644 --- a/src/nvim/api/private/dispatch.c +++ b/src/nvim/api/private/dispatch.c @@ -1,38 +1,11 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com -#include <assert.h> -#include <inttypes.h> -#include <msgpack.h> -#include <stdbool.h> +#include <stddef.h> -#include "nvim/api/deprecated.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/dispatch.h" #include "nvim/api/private/helpers.h" -#include "nvim/log.h" -#include "nvim/map.h" -#include "nvim/msgpack_rpc/helpers.h" -#include "nvim/vim.h" - -// =========================================================================== -// NEW API FILES MUST GO HERE. -// -// When creating a new API file, you must include it here, -// so that the dispatcher can find the C functions that you are creating! -// =========================================================================== -#include "nvim/api/autocmd.h" -#include "nvim/api/buffer.h" -#include "nvim/api/command.h" -#include "nvim/api/extmark.h" -#include "nvim/api/options.h" -#include "nvim/api/tabpage.h" -#include "nvim/api/ui.h" -#include "nvim/api/vim.h" -#include "nvim/api/vimscript.h" -#include "nvim/api/win_config.h" -#include "nvim/api/window.h" -#include "nvim/ui_client.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/private/dispatch_wrappers.generated.h" diff --git a/src/nvim/api/private/dispatch.h b/src/nvim/api/private/dispatch.h index 4b7c394944..4ae61b2bfb 100644 --- a/src/nvim/api/private/dispatch.h +++ b/src/nvim/api/private/dispatch.h @@ -1,22 +1,29 @@ #ifndef NVIM_API_PRIVATE_DISPATCH_H #define NVIM_API_PRIVATE_DISPATCH_H +#include <stdbool.h> +#include <stdint.h> + #include "nvim/api/private/defs.h" +#include "nvim/memory.h" +#include "nvim/types.h" -typedef Object (*ApiDispatchWrapper)(uint64_t channel_id, - Array args, - Error *error); +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 c466fc53e1..519f2cc5bf 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -3,37 +3,36 @@ #include <assert.h> #include <inttypes.h> +#include <limits.h> +#include <msgpack/unpack.h> +#include <stdarg.h> #include <stdbool.h> #include <stddef.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> +#include "klib/kvec.h" #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/lib/kvec.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" @@ -58,6 +57,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 +65,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 +86,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 +95,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 +130,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,8 +149,19 @@ bool try_end(Error *err) if (should_free) { xfree(msg); } - } else if (current_exception) { - api_set_error(err, kErrorTypeException, "%s", current_exception->value); + } else if (did_throw) { + 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(); } @@ -214,6 +228,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) { @@ -221,6 +237,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); @@ -237,11 +257,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); @@ -251,6 +276,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); } @@ -369,7 +401,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)); } /// Creates a String using the given C string. Unlike @@ -440,53 +478,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 = (char *)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; @@ -495,7 +495,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); + 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; @@ -515,12 +515,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(&bufstr[start_col], (size_t)(end_col - start_col)); } void api_free_string(String value) @@ -618,6 +613,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 +626,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 +711,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 +757,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 +844,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 4608554448..ec97ba9ec6 100644 --- a/src/nvim/api/private/helpers.h +++ b/src/nvim/api/private/helpers.h @@ -1,11 +1,17 @@ #ifndef NVIM_API_PRIVATE_HELPERS_H #define NVIM_API_PRIVATE_HELPERS_H +#include <stdbool.h> +#include <stddef.h> + +#include "klib/kvec.h" #include "nvim/api/private/defs.h" #include "nvim/decoration.h" #include "nvim/ex_eval_defs.h" #include "nvim/getchar.h" -#include "nvim/lib/kvec.h" +#include "nvim/globals.h" +#include "nvim/macros.h" +#include "nvim/map.h" #include "nvim/memory.h" #include "nvim/vim.h" @@ -134,6 +140,7 @@ typedef struct { const msglist_T *const *msg_list; int trylevel; int got_int; + bool did_throw; int need_rethrow; int did_emsg; } TryState; |