From 7ce2d63fef6d377a41f1364c08a016d3997d9d28 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Fri, 23 May 2014 15:49:08 -0300 Subject: API: Cleanup: Remove unnecessary NULL checks --- src/nvim/api/buffer.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index e73823e5c3..f66d65b849 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -115,9 +115,7 @@ StringArray buffer_get_slice(Buffer buffer, end: if (err->set) { for (size_t i = 0; i < rv.size; i++) { - if (rv.items[i].data != NULL) { - free(rv.items[i].data); - } + free(rv.items[i].data); } free(rv.items); @@ -240,10 +238,8 @@ void buffer_set_slice(Buffer buffer, } end: - for (uint32_t i = 0; i < new_len; i++) { - if (lines[i] != NULL) { - free(lines[i]); - } + for (size_t i = 0; i < new_len; i++) { + free(lines[i]); } free(lines); -- cgit From 28eb3796b9d60e3c9e360b4cc7b2790c68a6db57 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Fri, 23 May 2014 15:49:12 -0300 Subject: API: Bugfix: Check that error isn't set in buffer_get_line --- src/nvim/api/buffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index f66d65b849..09528b016b 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -56,7 +56,7 @@ String buffer_get_line(Buffer buffer, Integer index, Error *err) String rv = {.size = 0}; StringArray slice = buffer_get_slice(buffer, index, index, true, true, err); - if (slice.size) { + if (!err->set && slice.size) { rv = slice.items[0]; } -- cgit From ee60683b9a5159e184c41f0dbd8121f082521019 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Fri, 23 May 2014 15:49:14 -0300 Subject: API: Bugfix: Remove wrong increment statement from buffer_set_slice --- src/nvim/api/buffer.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 09528b016b..fd3c76cc39 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -219,7 +219,6 @@ void buffer_set_slice(Buffer buffer, // Same as with replacing lines[i] = NULL; - i++; extra++; } -- cgit From c6483aa2fae07654f8a874a0c479916de33ec592 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Fri, 23 May 2014 15:49:17 -0300 Subject: API: Bugfix: Fix loop condition in vim_list_runtime_paths --- src/nvim/api/vim.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'src') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 505844e651..5796d7bc0e 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -94,14 +94,12 @@ StringArray vim_list_runtime_paths(void) rtp++; } - // index - uint32_t i = 0; // Allocate memory for the copies rv.items = xmalloc(sizeof(String) * rv.size); // reset the position rtp = p_rtp; // Start copying - while (*rtp != NUL) { + for (size_t i = 0; i < rv.size && *rtp != NUL; i++) { rv.items[i].data = xmalloc(MAXPATHL); // Copy the path from 'runtimepath' to rv.items[i] int length = copy_option_part(&rtp, @@ -110,7 +108,6 @@ StringArray vim_list_runtime_paths(void) ","); assert(length >= 0); rv.items[i].size = (size_t)length; - i++; } return rv; -- cgit From 677d30d7966dd2766bbf20665791c568dacc427a Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Fri, 23 May 2014 15:49:19 -0300 Subject: API: Bugfix: Use 0-terminated string in vim_strwidth While the mb_string2cells function accepts a length parameter, it only seems to work properly with 0-terminated strings, since valgrind reports a conditional jump that depends on uninitialized values(means it reads after the string boundaries which could result in overflows or wrong results) --- src/nvim/api/vim.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 5796d7bc0e..1f335cf5e0 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -73,7 +73,10 @@ Integer vim_strwidth(String str, Error *err) return 0; } - return mb_string2cells((char_u *)str.data, (int)str.size); + char *buf = xstrndup(str.data, str.size); + Integer rv = mb_string2cells((char_u *)buf, -1); + free(buf); + return rv; } StringArray vim_list_runtime_paths(void) -- cgit From 399a0e37405a0f68ef3373c8ad9bcfa94ee0f649 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Fri, 23 May 2014 15:49:21 -0300 Subject: API: Bugfix: Terminate directory string in vim_change_directory Also check that the string length is not equal or greater than MAXPATHL. --- src/nvim/api/vim.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 1f335cf5e0..8cf4fb04d7 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -118,8 +118,14 @@ StringArray vim_list_runtime_paths(void) void vim_change_directory(String dir, Error *err) { + if (dir.size >= MAXPATHL) { + set_api_error("directory string is too long", err); + return; + } + char string[MAXPATHL]; strncpy(string, dir.data, dir.size); + string[dir.size] = NUL; try_start(); -- cgit From 72e3125f452ae7224162da8e940e20b00680d41a Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Fri, 23 May 2014 15:49:25 -0300 Subject: API: Refactor: Move non-public files to private subdirectory --- src/nvim/CMakeLists.txt | 17 +- src/nvim/api/buffer.c | 4 +- src/nvim/api/buffer.h | 2 +- src/nvim/api/defs.h | 79 ------ src/nvim/api/helpers.c | 607 ----------------------------------------- src/nvim/api/helpers.h | 97 ------- src/nvim/api/private/defs.h | 79 ++++++ src/nvim/api/private/helpers.c | 607 +++++++++++++++++++++++++++++++++++++++++ src/nvim/api/private/helpers.h | 97 +++++++ src/nvim/api/tabpage.c | 4 +- src/nvim/api/tabpage.h | 2 +- src/nvim/api/vim.c | 4 +- src/nvim/api/vim.h | 2 +- src/nvim/api/window.c | 4 +- src/nvim/api/window.h | 2 +- src/nvim/os/msgpack_rpc.h | 2 +- 16 files changed, 800 insertions(+), 809 deletions(-) delete mode 100644 src/nvim/api/defs.h delete mode 100644 src/nvim/api/helpers.c delete mode 100644 src/nvim/api/helpers.h create mode 100644 src/nvim/api/private/defs.h create mode 100644 src/nvim/api/private/helpers.c create mode 100644 src/nvim/api/private/helpers.h (limited to 'src') diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index d9ec65af86..ad45f3ad3b 100644 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -6,17 +6,6 @@ file(GLOB API_HEADERS api/*.h) set(MSGPACK_RPC_HEADER ${PROJECT_SOURCE_DIR}/src/nvim/os/msgpack_rpc.h) set(MSGPACK_DISPATCH ${GENERATED_DIR}/msgpack_dispatch.c) -# Remove helpers.h from API_HEADERS since it doesn't contain public API -# functions -foreach(sfile ${API_HEADERS}) - get_filename_component(f ${sfile} NAME) - if(${f} MATCHES "^(helpers.h)$") - list(APPEND to_remove ${sfile}) - endif() -endforeach() -list(REMOVE_ITEM API_HEADERS ${to_remove}) -set(to_remove) - file(MAKE_DIRECTORY ${GENERATED_DIR}) add_custom_command(OUTPUT ${MSGPACK_DISPATCH} @@ -42,6 +31,7 @@ list(APPEND NEOVIM_SOURCES "${MSGPACK_DISPATCH}") file( GLOB OS_SOURCES os/*.c ) file( GLOB API_SOURCES api/*.c ) +file( GLOB API_PRIV_SOURCES api/private/*.c ) set(CONV_SRCS api.c @@ -110,13 +100,14 @@ list(APPEND NVIM_LINK_LIBRARIES ${CMAKE_THREAD_LIBS_INIT}) if(NOT DEFINED ENV{SKIP_EXEC}) - add_executable(nvim ${NEOVIM_SOURCES} ${OS_SOURCES} ${API_SOURCES}) + add_executable(nvim ${NEOVIM_SOURCES} ${OS_SOURCES} ${API_SOURCES} + ${API_PRIV_SOURCES}) target_link_libraries(nvim ${NVIM_LINK_LIBRARIES}) install(TARGETS nvim RUNTIME DESTINATION bin) endif() if(NOT DEFINED ENV{SKIP_UNITTEST}) add_library(nvim-test MODULE EXCLUDE_FROM_ALL ${NEOVIM_SOURCES} - ${OS_SOURCES} ${API_SOURCES}) + ${OS_SOURCES} ${API_SOURCES} ${API_PRIV_SOURCES}) target_link_libraries(nvim-test ${NVIM_LINK_LIBRARIES}) endif() diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index fd3c76cc39..9a4285d74c 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -4,8 +4,8 @@ #include #include "nvim/api/buffer.h" -#include "nvim/api/helpers.h" -#include "nvim/api/defs.h" +#include "nvim/api/private/helpers.h" +#include "nvim/api/private/defs.h" #include "nvim/vim.h" #include "nvim/buffer.h" #include "nvim/memline.h" diff --git a/src/nvim/api/buffer.h b/src/nvim/api/buffer.h index 5f39589679..2350f7f41d 100644 --- a/src/nvim/api/buffer.h +++ b/src/nvim/api/buffer.h @@ -4,7 +4,7 @@ #include #include -#include "nvim/api/defs.h" +#include "nvim/api/private/defs.h" /// Gets the buffer line count /// diff --git a/src/nvim/api/defs.h b/src/nvim/api/defs.h deleted file mode 100644 index 3ee50310fb..0000000000 --- a/src/nvim/api/defs.h +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef NVIM_API_DEFS_H -#define NVIM_API_DEFS_H - -#include -#include -#include - -// Basic types -typedef struct { - char msg[256]; - bool set; -} Error; - -typedef bool Boolean; -typedef int64_t Integer; -typedef double Float; - -typedef struct { - char *data; - size_t size; -} String; - -typedef Integer Buffer; -typedef Integer Window; -typedef Integer Tabpage; - -typedef struct object Object; - -typedef struct { - String *items; - size_t size; -} StringArray; - -typedef struct { - Integer row, col; -} Position; - -typedef struct { - Object *items; - size_t size; -} Array; - -typedef struct key_value_pair KeyValuePair; - -typedef struct { - KeyValuePair *items; - size_t size; -} Dictionary; - -typedef enum { - kObjectTypeNil, - kObjectTypeBoolean, - kObjectTypeInteger, - kObjectTypeFloat, - kObjectTypeString, - kObjectTypeArray, - kObjectTypeDictionary -} ObjectType; - -struct object { - ObjectType type; - union { - Boolean boolean; - Integer integer; - Float floating; - String string; - Array array; - Dictionary dictionary; - } data; -}; - -struct key_value_pair { - String key; - Object value; -}; - - -#endif // NVIM_API_DEFS_H - diff --git a/src/nvim/api/helpers.c b/src/nvim/api/helpers.c deleted file mode 100644 index a193c8721e..0000000000 --- a/src/nvim/api/helpers.c +++ /dev/null @@ -1,607 +0,0 @@ -#include -#include -#include - -#include "nvim/api/helpers.h" -#include "nvim/api/defs.h" -#include "nvim/vim.h" -#include "nvim/buffer.h" -#include "nvim/window.h" -#include "nvim/memory.h" -#include "nvim/eval.h" -#include "nvim/map_defs.h" -#include "nvim/map.h" -#include "nvim/option.h" -#include "nvim/option_defs.h" - -/// Recursion helper for the `vim_to_object`. This uses a pointer table -/// to avoid infinite recursion due to cyclic references -/// -/// @param obj The source object -/// @param lookup Lookup table containing pointers to all processed objects -/// @return The converted value -static Object vim_to_object_rec(typval_T *obj, Map(ptr_t) *lookup); - -static bool object_to_vim(Object obj, typval_T *tv, Error *err); - -static void set_option_value_for(char *key, - int numval, - char *stringval, - int opt_flags, - int opt_type, - void *from, - Error *err); - -static void set_option_value_err(char *key, - int numval, - char *stringval, - int opt_flags, - Error *err); - -void try_start() -{ - ++trylevel; -} - -bool try_end(Error *err) -{ - --trylevel; - - // Without this it stops processing all subsequent VimL commands and - // generates strange error messages if I e.g. try calling Test() in a - // cycle - did_emsg = false; - - if (got_int) { - if (did_throw) { - // If we got an interrupt, discard the current exception - discard_current_exception(); - } - - set_api_error("Keyboard interrupt", err); - got_int = false; - } else if (msg_list != NULL && *msg_list != NULL) { - int should_free; - char *msg = (char *)get_exception_string(*msg_list, - ET_ERROR, - NULL, - &should_free); - strncpy(err->msg, msg, sizeof(err->msg)); - err->set = true; - free_global_msglist(); - - if (should_free) { - free(msg); - } - } else if (did_throw) { - set_api_error((char *)current_exception->value, err); - } - - return err->set; -} - -Object dict_get_value(dict_T *dict, String key, Error *err) -{ - Object rv; - hashitem_T *hi; - dictitem_T *di; - char *k = xstrndup(key.data, key.size); - hi = hash_find(&dict->dv_hashtab, (uint8_t *)k); - free(k); - - if (HASHITEM_EMPTY(hi)) { - set_api_error("Key not found", err); - return rv; - } - - di = dict_lookup(hi); - rv = vim_to_object(&di->di_tv); - - return rv; -} - -Object dict_set_value(dict_T *dict, String key, Object value, Error *err) -{ - Object rv = {.type = kObjectTypeNil}; - - if (dict->dv_lock) { - set_api_error("Dictionary is locked", err); - return rv; - } - - if (key.size == 0) { - set_api_error("Empty dictionary keys aren't allowed", err); - return rv; - } - - if (key.size > INT_MAX) { - set_api_error("Key length is too high", err); - return rv; - } - - dictitem_T *di = dict_find(dict, (uint8_t *)key.data, (int)key.size); - - if (value.type == kObjectTypeNil) { - // Delete the key - if (di == NULL) { - // Doesn't exist, fail - set_api_error("Key doesn't exist", err); - } else { - // Return the old value - rv = vim_to_object(&di->di_tv); - // Delete the entry - hashitem_T *hi = hash_find(&dict->dv_hashtab, di->di_key); - hash_remove(&dict->dv_hashtab, hi); - dictitem_free(di); - } - } else { - // Update the key - typval_T tv; - - // Convert the object to a vimscript type in the temporary variable - if (!object_to_vim(value, &tv, err)) { - return rv; - } - - if (di == NULL) { - // Need to create an entry - char *k = xstrndup(key.data, key.size); - di = dictitem_alloc((uint8_t *)k); - free(k); - dict_add(dict, di); - } else { - // Return the old value - clear_tv(&di->di_tv); - } - - // Update the value - copy_tv(&tv, &di->di_tv); - // Clear the temporary variable - clear_tv(&tv); - } - - return rv; -} - -Object get_option_from(void *from, int type, String name, Error *err) -{ - Object rv = {.type = kObjectTypeNil}; - - if (name.size == 0) { - set_api_error("Empty option name", err); - return rv; - } - - // Return values - int64_t numval; - char *stringval = NULL; - // copy the option name into 0-delimited string - char *key = xstrndup(name.data, name.size); - int flags = get_option_value_strict(key, &numval, &stringval, type, from); - free(key); - - if (!flags) { - set_api_error("invalid option name", err); - return rv; - } - - if (flags & SOPT_BOOL) { - rv.type = kObjectTypeBoolean; - rv.data.boolean = numval ? true : false; - } else if (flags & SOPT_NUM) { - rv.type = kObjectTypeInteger; - rv.data.integer = numval; - } else if (flags & SOPT_STRING) { - if (stringval) { - rv.type = kObjectTypeString; - rv.data.string.data = stringval; - rv.data.string.size = strlen(stringval); - } else { - set_api_error(N_("Unable to get option value"), err); - } - } else { - set_api_error(N_("internal error: unknown option type"), err); - } - - return rv; -} - -void set_option_to(void *to, int type, String name, Object value, Error *err) -{ - if (name.size == 0) { - set_api_error("Empty option name", err); - return; - } - - char *key = xstrndup(name.data, name.size); - int flags = get_option_value_strict(key, NULL, NULL, type, to); - - if (flags == 0) { - set_api_error("invalid option name", err); - goto cleanup; - } - - if (value.type == kObjectTypeNil) { - if (type == SREQ_GLOBAL) { - set_api_error("unable to unset option", err); - goto cleanup; - } else if (!(flags & SOPT_GLOBAL)) { - set_api_error("cannot unset option that doesn't have a global value", - err); - goto cleanup; - } else { - unset_global_local_option(key, to); - goto cleanup; - } - } - - int opt_flags = (type ? OPT_LOCAL : OPT_GLOBAL); - - if (flags & SOPT_BOOL) { - if (value.type != kObjectTypeBoolean) { - set_api_error("option requires a boolean value", err); - goto cleanup; - } - bool val = value.data.boolean; - set_option_value_for(key, val, NULL, opt_flags, type, to, err); - - } else if (flags & SOPT_NUM) { - if (value.type != kObjectTypeInteger) { - set_api_error("option requires an integer value", err); - goto cleanup; - } - - if (value.data.integer > INT_MAX || value.data.integer < INT_MIN) { - set_api_error("Option value outside range", err); - return; - } - - int val = (int)value.data.integer; - set_option_value_for(key, val, NULL, opt_flags, type, to, err); - } else { - if (value.type != kObjectTypeString) { - set_api_error("option requires a string value", err); - goto cleanup; - } - - char *val = xstrndup(value.data.string.data, value.data.string.size); - set_option_value_for(key, 0, val, opt_flags, type, to, err); - } - -cleanup: - free(key); -} - -Object vim_to_object(typval_T *obj) -{ - Object rv; - // We use a lookup table to break out of cyclic references - Map(ptr_t) *lookup = map_new(ptr_t)(); - rv = vim_to_object_rec(obj, lookup); - // Free the table - map_free(ptr_t)(lookup); - return rv; -} - -buf_T *find_buffer(Buffer buffer, Error *err) -{ - if (buffer > INT_MAX || buffer < INT_MIN) { - set_api_error("Invalid buffer id", err); - return NULL; - } - - buf_T *buf = buflist_findnr((int)buffer); - - if (buf == NULL) { - set_api_error("Invalid buffer id", err); - } - - return buf; -} - -win_T * find_window(Window window, Error *err) -{ - tabpage_T *tp; - win_T *wp; - - FOR_ALL_TAB_WINDOWS(tp, wp) { - if (!--window) { - return wp; - } - } - - set_api_error("Invalid window id", err); - return NULL; -} - -tabpage_T * find_tab(Tabpage tabpage, Error *err) -{ - if (tabpage > INT_MAX || tabpage < INT_MIN) { - set_api_error("Invalid tabpage id", err); - return NULL; - } - - tabpage_T *rv = find_tabpage((int)tabpage); - - if (!rv) { - set_api_error("Invalid tabpage id", err); - } - - return rv; -} - -String cstr_to_string(const char *str) { - if (str == NULL) { - return (String) { .data = NULL, .size = 0 }; - } - - size_t len = strlen(str); - return (String) { - .data = xmemdup(str, len), - .size = len - }; -} - -static bool object_to_vim(Object obj, typval_T *tv, Error *err) -{ - tv->v_type = VAR_UNKNOWN; - tv->v_lock = 0; - - switch (obj.type) { - case kObjectTypeNil: - tv->v_type = VAR_NUMBER; - tv->vval.v_number = 0; - break; - - case kObjectTypeBoolean: - tv->v_type = VAR_NUMBER; - tv->vval.v_number = obj.data.boolean; - break; - - case kObjectTypeInteger: - if (obj.data.integer > INT_MAX || obj.data.integer < INT_MIN) { - set_api_error("Integer value outside range", err); - return false; - } - - tv->v_type = VAR_NUMBER; - tv->vval.v_number = (int)obj.data.integer; - break; - - case kObjectTypeFloat: - tv->v_type = VAR_FLOAT; - tv->vval.v_float = obj.data.floating; - break; - - case kObjectTypeString: - tv->v_type = VAR_STRING; - tv->vval.v_string = (uint8_t *)xstrndup(obj.data.string.data, - obj.data.string.size); - break; - - case kObjectTypeArray: - tv->v_type = VAR_LIST; - tv->vval.v_list = list_alloc(); - - for (uint32_t i = 0; i < obj.data.array.size; i++) { - Object item = obj.data.array.items[i]; - listitem_T *li = listitem_alloc(); - - if (!object_to_vim(item, &li->li_tv, err)) { - // cleanup - listitem_free(li); - list_free(tv->vval.v_list, true); - return false; - } - - list_append(tv->vval.v_list, li); - } - tv->vval.v_list->lv_refcount++; - break; - - case kObjectTypeDictionary: - tv->v_type = VAR_DICT; - tv->vval.v_dict = dict_alloc(); - - for (uint32_t i = 0; i < obj.data.dictionary.size; i++) { - KeyValuePair item = obj.data.dictionary.items[i]; - String key = item.key; - - if (key.size == 0) { - set_api_error("Empty dictionary keys aren't allowed", err); - // cleanup - dict_free(tv->vval.v_dict, true); - return false; - } - - char *k = xstrndup(key.data, key.size); - dictitem_T *di = dictitem_alloc((uint8_t *)k); - free(k); - - if (!object_to_vim(item.value, &di->di_tv, err)) { - // cleanup - dictitem_free(di); - dict_free(tv->vval.v_dict, true); - return false; - } - - dict_add(tv->vval.v_dict, di); - } - tv->vval.v_dict->dv_refcount++; - break; - } - - return true; -} - -static Object vim_to_object_rec(typval_T *obj, Map(ptr_t) *lookup) -{ - Object rv = {.type = kObjectTypeNil}; - - if (obj->v_type == VAR_LIST || obj->v_type == VAR_DICT) { - // Container object, add it to the lookup table - if (map_has(ptr_t)(lookup, obj)) { - // It's already present, meaning we alredy processed it so just return - // nil instead. - return rv; - } - map_put(ptr_t)(lookup, obj, NULL); - } - - switch (obj->v_type) { - case VAR_STRING: - if (obj->vval.v_string != NULL) { - rv.type = kObjectTypeString; - rv.data.string.data = xstrdup((char *)obj->vval.v_string); - rv.data.string.size = strlen(rv.data.string.data); - } - break; - - case VAR_NUMBER: - rv.type = kObjectTypeInteger; - rv.data.integer = obj->vval.v_number; - break; - - case VAR_FLOAT: - rv.type = kObjectTypeFloat; - rv.data.floating = obj->vval.v_float; - break; - - case VAR_LIST: - { - list_T *list = obj->vval.v_list; - listitem_T *item; - - if (list != NULL) { - rv.type = kObjectTypeArray; - assert(list->lv_len >= 0); - rv.data.array.size = (size_t)list->lv_len; - rv.data.array.items = xmalloc(rv.data.array.size * sizeof(Object)); - - uint32_t i = 0; - for (item = list->lv_first; item != NULL; item = item->li_next) { - rv.data.array.items[i] = vim_to_object_rec(&item->li_tv, lookup); - i++; - } - } - } - break; - - case VAR_DICT: - { - dict_T *dict = obj->vval.v_dict; - hashtab_T *ht; - uint64_t todo; - hashitem_T *hi; - dictitem_T *di; - - if (dict != NULL) { - ht = &obj->vval.v_dict->dv_hashtab; - todo = ht->ht_used; - rv.type = kObjectTypeDictionary; - - // Count items - rv.data.dictionary.size = 0; - for (hi = ht->ht_array; todo > 0; ++hi) { - if (!HASHITEM_EMPTY(hi)) { - todo--; - rv.data.dictionary.size++; - } - } - - rv.data.dictionary.items = - xmalloc(rv.data.dictionary.size * sizeof(KeyValuePair)); - todo = ht->ht_used; - uint32_t i = 0; - - // Convert all - for (hi = ht->ht_array; todo > 0; ++hi) { - if (!HASHITEM_EMPTY(hi)) { - di = dict_lookup(hi); - // Convert key - rv.data.dictionary.items[i].key.data = - xstrdup((char *)hi->hi_key); - rv.data.dictionary.items[i].key.size = - strlen((char *)hi->hi_key); - // Convert value - rv.data.dictionary.items[i].value = - vim_to_object_rec(&di->di_tv, lookup); - todo--; - i++; - } - } - } - } - break; - } - - return rv; -} - - -static void set_option_value_for(char *key, - int numval, - char *stringval, - int opt_flags, - int opt_type, - void *from, - Error *err) -{ - win_T *save_curwin = NULL; - tabpage_T *save_curtab = NULL; - buf_T *save_curbuf = NULL; - - try_start(); - switch (opt_type) - { - case SREQ_WIN: - if (switch_win(&save_curwin, &save_curtab, (win_T *)from, - win_find_tabpage((win_T *)from), false) == FAIL) - { - if (try_end(err)) { - return; - } - set_api_error("problem while switching windows", err); - return; - } - set_option_value_err(key, numval, stringval, opt_flags, err); - restore_win(save_curwin, save_curtab, true); - break; - case SREQ_BUF: - switch_buffer(&save_curbuf, (buf_T *)from); - set_option_value_err(key, numval, stringval, opt_flags, err); - restore_buffer(save_curbuf); - break; - case SREQ_GLOBAL: - set_option_value_err(key, numval, stringval, opt_flags, err); - break; - } - - if (err->set) { - return; - } - - try_end(err); -} - - -static void set_option_value_err(char *key, - int numval, - char *stringval, - int opt_flags, - Error *err) -{ - char *errmsg; - - if ((errmsg = (char *)set_option_value((uint8_t *)key, - numval, - (uint8_t *)stringval, - opt_flags))) - { - if (try_end(err)) { - return; - } - - set_api_error(errmsg, err); - } -} diff --git a/src/nvim/api/helpers.h b/src/nvim/api/helpers.h deleted file mode 100644 index f93487d62f..0000000000 --- a/src/nvim/api/helpers.h +++ /dev/null @@ -1,97 +0,0 @@ -#ifndef NVIM_API_HELPERS_H -#define NVIM_API_HELPERS_H - -#include - -#include "nvim/api/defs.h" -#include "nvim/vim.h" - -#define set_api_error(message, err) \ - do { \ - strncpy(err->msg, message, sizeof(err->msg)); \ - err->set = true; \ - } while (0) - -/// Start block that may cause vimscript exceptions -void try_start(void); - -/// End try block, set the error message if any and return true if an error -/// occurred. -/// -/// @param err Pointer to the stack-allocated error object -/// @return true if an error occurred -bool try_end(Error *err); - -/// Recursively expands a vimscript value in a dict -/// -/// @param dict The vimscript dict -/// @param key The key -/// @param[out] err Details of an error that may have occurred -Object dict_get_value(dict_T *dict, String key, Error *err); - -/// Set a value in a dict. Objects are recursively expanded into their -/// vimscript equivalents. Passing 'nil' as value deletes the key. -/// -/// @param dict The vimscript dict -/// @param key The key -/// @param value The new value -/// @param[out] err Details of an error that may have occurred -/// @return the old value, if any -Object dict_set_value(dict_T *dict, String key, Object value, Error *err); - -/// Gets the value of a global or local(buffer, window) option. -/// -/// @param from If `type` is `SREQ_WIN` or `SREQ_BUF`, this must be a pointer -/// to the window or buffer. -/// @param type One of `SREQ_GLOBAL`, `SREQ_WIN` or `SREQ_BUF` -/// @param name The option name -/// @param[out] err Details of an error that may have occurred -/// @return the option value -Object get_option_from(void *from, int type, String name, Error *err); - -/// Sets the value of a global or local(buffer, window) option. -/// -/// @param to If `type` is `SREQ_WIN` or `SREQ_BUF`, this must be a pointer -/// to the window or buffer. -/// @param type One of `SREQ_GLOBAL`, `SREQ_WIN` or `SREQ_BUF` -/// @param name The option name -/// @param[out] err Details of an error that may have occurred -void set_option_to(void *to, int type, String name, Object value, Error *err); - -/// Convert a vim object to an `Object` instance, recursively expanding -/// Arrays/Dictionaries. -/// -/// @param obj The source object -/// @return The converted value -Object vim_to_object(typval_T *obj); - -/// Finds the pointer for a window number -/// -/// @param window the window number -/// @param[out] err Details of an error that may have occurred -/// @return the window pointer -buf_T *find_buffer(Buffer buffer, Error *err); - -/// Finds the pointer for a window number -/// -/// @param window the window number -/// @param[out] err Details of an error that may have occurred -/// @return the window pointer -win_T * find_window(Window window, Error *err); - -/// Finds the pointer for a tabpage number -/// -/// @param tabpage the tabpage number -/// @param[out] err Details of an error that may have occurred -/// @return the tabpage pointer -tabpage_T * find_tab(Tabpage tabpage, Error *err); - -/// Copies a C string into a String (binary safe string, characters + length) -/// -/// @param str the C string to copy -/// @return the resulting String, if the input string was NULL, then an -/// empty String is returned -String cstr_to_string(const char *str); - -#endif // NVIM_API_HELPERS_H - diff --git a/src/nvim/api/private/defs.h b/src/nvim/api/private/defs.h new file mode 100644 index 0000000000..3ee50310fb --- /dev/null +++ b/src/nvim/api/private/defs.h @@ -0,0 +1,79 @@ +#ifndef NVIM_API_DEFS_H +#define NVIM_API_DEFS_H + +#include +#include +#include + +// Basic types +typedef struct { + char msg[256]; + bool set; +} Error; + +typedef bool Boolean; +typedef int64_t Integer; +typedef double Float; + +typedef struct { + char *data; + size_t size; +} String; + +typedef Integer Buffer; +typedef Integer Window; +typedef Integer Tabpage; + +typedef struct object Object; + +typedef struct { + String *items; + size_t size; +} StringArray; + +typedef struct { + Integer row, col; +} Position; + +typedef struct { + Object *items; + size_t size; +} Array; + +typedef struct key_value_pair KeyValuePair; + +typedef struct { + KeyValuePair *items; + size_t size; +} Dictionary; + +typedef enum { + kObjectTypeNil, + kObjectTypeBoolean, + kObjectTypeInteger, + kObjectTypeFloat, + kObjectTypeString, + kObjectTypeArray, + kObjectTypeDictionary +} ObjectType; + +struct object { + ObjectType type; + union { + Boolean boolean; + Integer integer; + Float floating; + String string; + Array array; + Dictionary dictionary; + } data; +}; + +struct key_value_pair { + String key; + Object value; +}; + + +#endif // NVIM_API_DEFS_H + diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c new file mode 100644 index 0000000000..a7d155382c --- /dev/null +++ b/src/nvim/api/private/helpers.c @@ -0,0 +1,607 @@ +#include +#include +#include + +#include "nvim/api/private/helpers.h" +#include "nvim/api/private/defs.h" +#include "nvim/vim.h" +#include "nvim/buffer.h" +#include "nvim/window.h" +#include "nvim/memory.h" +#include "nvim/eval.h" +#include "nvim/map_defs.h" +#include "nvim/map.h" +#include "nvim/option.h" +#include "nvim/option_defs.h" + +/// Recursion helper for the `vim_to_object`. This uses a pointer table +/// to avoid infinite recursion due to cyclic references +/// +/// @param obj The source object +/// @param lookup Lookup table containing pointers to all processed objects +/// @return The converted value +static Object vim_to_object_rec(typval_T *obj, Map(ptr_t) *lookup); + +static bool object_to_vim(Object obj, typval_T *tv, Error *err); + +static void set_option_value_for(char *key, + int numval, + char *stringval, + int opt_flags, + int opt_type, + void *from, + Error *err); + +static void set_option_value_err(char *key, + int numval, + char *stringval, + int opt_flags, + Error *err); + +void try_start() +{ + ++trylevel; +} + +bool try_end(Error *err) +{ + --trylevel; + + // Without this it stops processing all subsequent VimL commands and + // generates strange error messages if I e.g. try calling Test() in a + // cycle + did_emsg = false; + + if (got_int) { + if (did_throw) { + // If we got an interrupt, discard the current exception + discard_current_exception(); + } + + set_api_error("Keyboard interrupt", err); + got_int = false; + } else if (msg_list != NULL && *msg_list != NULL) { + int should_free; + char *msg = (char *)get_exception_string(*msg_list, + ET_ERROR, + NULL, + &should_free); + strncpy(err->msg, msg, sizeof(err->msg)); + err->set = true; + free_global_msglist(); + + if (should_free) { + free(msg); + } + } else if (did_throw) { + set_api_error((char *)current_exception->value, err); + } + + return err->set; +} + +Object dict_get_value(dict_T *dict, String key, Error *err) +{ + Object rv; + hashitem_T *hi; + dictitem_T *di; + char *k = xstrndup(key.data, key.size); + hi = hash_find(&dict->dv_hashtab, (uint8_t *)k); + free(k); + + if (HASHITEM_EMPTY(hi)) { + set_api_error("Key not found", err); + return rv; + } + + di = dict_lookup(hi); + rv = vim_to_object(&di->di_tv); + + return rv; +} + +Object dict_set_value(dict_T *dict, String key, Object value, Error *err) +{ + Object rv = {.type = kObjectTypeNil}; + + if (dict->dv_lock) { + set_api_error("Dictionary is locked", err); + return rv; + } + + if (key.size == 0) { + set_api_error("Empty dictionary keys aren't allowed", err); + return rv; + } + + if (key.size > INT_MAX) { + set_api_error("Key length is too high", err); + return rv; + } + + dictitem_T *di = dict_find(dict, (uint8_t *)key.data, (int)key.size); + + if (value.type == kObjectTypeNil) { + // Delete the key + if (di == NULL) { + // Doesn't exist, fail + set_api_error("Key doesn't exist", err); + } else { + // Return the old value + rv = vim_to_object(&di->di_tv); + // Delete the entry + hashitem_T *hi = hash_find(&dict->dv_hashtab, di->di_key); + hash_remove(&dict->dv_hashtab, hi); + dictitem_free(di); + } + } else { + // Update the key + typval_T tv; + + // Convert the object to a vimscript type in the temporary variable + if (!object_to_vim(value, &tv, err)) { + return rv; + } + + if (di == NULL) { + // Need to create an entry + char *k = xstrndup(key.data, key.size); + di = dictitem_alloc((uint8_t *)k); + free(k); + dict_add(dict, di); + } else { + // Return the old value + clear_tv(&di->di_tv); + } + + // Update the value + copy_tv(&tv, &di->di_tv); + // Clear the temporary variable + clear_tv(&tv); + } + + return rv; +} + +Object get_option_from(void *from, int type, String name, Error *err) +{ + Object rv = {.type = kObjectTypeNil}; + + if (name.size == 0) { + set_api_error("Empty option name", err); + return rv; + } + + // Return values + int64_t numval; + char *stringval = NULL; + // copy the option name into 0-delimited string + char *key = xstrndup(name.data, name.size); + int flags = get_option_value_strict(key, &numval, &stringval, type, from); + free(key); + + if (!flags) { + set_api_error("invalid option name", err); + return rv; + } + + if (flags & SOPT_BOOL) { + rv.type = kObjectTypeBoolean; + rv.data.boolean = numval ? true : false; + } else if (flags & SOPT_NUM) { + rv.type = kObjectTypeInteger; + rv.data.integer = numval; + } else if (flags & SOPT_STRING) { + if (stringval) { + rv.type = kObjectTypeString; + rv.data.string.data = stringval; + rv.data.string.size = strlen(stringval); + } else { + set_api_error(N_("Unable to get option value"), err); + } + } else { + set_api_error(N_("internal error: unknown option type"), err); + } + + return rv; +} + +void set_option_to(void *to, int type, String name, Object value, Error *err) +{ + if (name.size == 0) { + set_api_error("Empty option name", err); + return; + } + + char *key = xstrndup(name.data, name.size); + int flags = get_option_value_strict(key, NULL, NULL, type, to); + + if (flags == 0) { + set_api_error("invalid option name", err); + goto cleanup; + } + + if (value.type == kObjectTypeNil) { + if (type == SREQ_GLOBAL) { + set_api_error("unable to unset option", err); + goto cleanup; + } else if (!(flags & SOPT_GLOBAL)) { + set_api_error("cannot unset option that doesn't have a global value", + err); + goto cleanup; + } else { + unset_global_local_option(key, to); + goto cleanup; + } + } + + int opt_flags = (type ? OPT_LOCAL : OPT_GLOBAL); + + if (flags & SOPT_BOOL) { + if (value.type != kObjectTypeBoolean) { + set_api_error("option requires a boolean value", err); + goto cleanup; + } + bool val = value.data.boolean; + set_option_value_for(key, val, NULL, opt_flags, type, to, err); + + } else if (flags & SOPT_NUM) { + if (value.type != kObjectTypeInteger) { + set_api_error("option requires an integer value", err); + goto cleanup; + } + + if (value.data.integer > INT_MAX || value.data.integer < INT_MIN) { + set_api_error("Option value outside range", err); + return; + } + + int val = (int)value.data.integer; + set_option_value_for(key, val, NULL, opt_flags, type, to, err); + } else { + if (value.type != kObjectTypeString) { + set_api_error("option requires a string value", err); + goto cleanup; + } + + char *val = xstrndup(value.data.string.data, value.data.string.size); + set_option_value_for(key, 0, val, opt_flags, type, to, err); + } + +cleanup: + free(key); +} + +Object vim_to_object(typval_T *obj) +{ + Object rv; + // We use a lookup table to break out of cyclic references + Map(ptr_t) *lookup = map_new(ptr_t)(); + rv = vim_to_object_rec(obj, lookup); + // Free the table + map_free(ptr_t)(lookup); + return rv; +} + +buf_T *find_buffer(Buffer buffer, Error *err) +{ + if (buffer > INT_MAX || buffer < INT_MIN) { + set_api_error("Invalid buffer id", err); + return NULL; + } + + buf_T *buf = buflist_findnr((int)buffer); + + if (buf == NULL) { + set_api_error("Invalid buffer id", err); + } + + return buf; +} + +win_T * find_window(Window window, Error *err) +{ + tabpage_T *tp; + win_T *wp; + + FOR_ALL_TAB_WINDOWS(tp, wp) { + if (!--window) { + return wp; + } + } + + set_api_error("Invalid window id", err); + return NULL; +} + +tabpage_T * find_tab(Tabpage tabpage, Error *err) +{ + if (tabpage > INT_MAX || tabpage < INT_MIN) { + set_api_error("Invalid tabpage id", err); + return NULL; + } + + tabpage_T *rv = find_tabpage((int)tabpage); + + if (!rv) { + set_api_error("Invalid tabpage id", err); + } + + return rv; +} + +String cstr_to_string(const char *str) { + if (str == NULL) { + return (String) { .data = NULL, .size = 0 }; + } + + size_t len = strlen(str); + return (String) { + .data = xmemdup(str, len), + .size = len + }; +} + +static bool object_to_vim(Object obj, typval_T *tv, Error *err) +{ + tv->v_type = VAR_UNKNOWN; + tv->v_lock = 0; + + switch (obj.type) { + case kObjectTypeNil: + tv->v_type = VAR_NUMBER; + tv->vval.v_number = 0; + break; + + case kObjectTypeBoolean: + tv->v_type = VAR_NUMBER; + tv->vval.v_number = obj.data.boolean; + break; + + case kObjectTypeInteger: + if (obj.data.integer > INT_MAX || obj.data.integer < INT_MIN) { + set_api_error("Integer value outside range", err); + return false; + } + + tv->v_type = VAR_NUMBER; + tv->vval.v_number = (int)obj.data.integer; + break; + + case kObjectTypeFloat: + tv->v_type = VAR_FLOAT; + tv->vval.v_float = obj.data.floating; + break; + + case kObjectTypeString: + tv->v_type = VAR_STRING; + tv->vval.v_string = (uint8_t *)xstrndup(obj.data.string.data, + obj.data.string.size); + break; + + case kObjectTypeArray: + tv->v_type = VAR_LIST; + tv->vval.v_list = list_alloc(); + + for (uint32_t i = 0; i < obj.data.array.size; i++) { + Object item = obj.data.array.items[i]; + listitem_T *li = listitem_alloc(); + + if (!object_to_vim(item, &li->li_tv, err)) { + // cleanup + listitem_free(li); + list_free(tv->vval.v_list, true); + return false; + } + + list_append(tv->vval.v_list, li); + } + tv->vval.v_list->lv_refcount++; + break; + + case kObjectTypeDictionary: + tv->v_type = VAR_DICT; + tv->vval.v_dict = dict_alloc(); + + for (uint32_t i = 0; i < obj.data.dictionary.size; i++) { + KeyValuePair item = obj.data.dictionary.items[i]; + String key = item.key; + + if (key.size == 0) { + set_api_error("Empty dictionary keys aren't allowed", err); + // cleanup + dict_free(tv->vval.v_dict, true); + return false; + } + + char *k = xstrndup(key.data, key.size); + dictitem_T *di = dictitem_alloc((uint8_t *)k); + free(k); + + if (!object_to_vim(item.value, &di->di_tv, err)) { + // cleanup + dictitem_free(di); + dict_free(tv->vval.v_dict, true); + return false; + } + + dict_add(tv->vval.v_dict, di); + } + tv->vval.v_dict->dv_refcount++; + break; + } + + return true; +} + +static Object vim_to_object_rec(typval_T *obj, Map(ptr_t) *lookup) +{ + Object rv = {.type = kObjectTypeNil}; + + if (obj->v_type == VAR_LIST || obj->v_type == VAR_DICT) { + // Container object, add it to the lookup table + if (map_has(ptr_t)(lookup, obj)) { + // It's already present, meaning we alredy processed it so just return + // nil instead. + return rv; + } + map_put(ptr_t)(lookup, obj, NULL); + } + + switch (obj->v_type) { + case VAR_STRING: + if (obj->vval.v_string != NULL) { + rv.type = kObjectTypeString; + rv.data.string.data = xstrdup((char *)obj->vval.v_string); + rv.data.string.size = strlen(rv.data.string.data); + } + break; + + case VAR_NUMBER: + rv.type = kObjectTypeInteger; + rv.data.integer = obj->vval.v_number; + break; + + case VAR_FLOAT: + rv.type = kObjectTypeFloat; + rv.data.floating = obj->vval.v_float; + break; + + case VAR_LIST: + { + list_T *list = obj->vval.v_list; + listitem_T *item; + + if (list != NULL) { + rv.type = kObjectTypeArray; + assert(list->lv_len >= 0); + rv.data.array.size = (size_t)list->lv_len; + rv.data.array.items = xmalloc(rv.data.array.size * sizeof(Object)); + + uint32_t i = 0; + for (item = list->lv_first; item != NULL; item = item->li_next) { + rv.data.array.items[i] = vim_to_object_rec(&item->li_tv, lookup); + i++; + } + } + } + break; + + case VAR_DICT: + { + dict_T *dict = obj->vval.v_dict; + hashtab_T *ht; + uint64_t todo; + hashitem_T *hi; + dictitem_T *di; + + if (dict != NULL) { + ht = &obj->vval.v_dict->dv_hashtab; + todo = ht->ht_used; + rv.type = kObjectTypeDictionary; + + // Count items + rv.data.dictionary.size = 0; + for (hi = ht->ht_array; todo > 0; ++hi) { + if (!HASHITEM_EMPTY(hi)) { + todo--; + rv.data.dictionary.size++; + } + } + + rv.data.dictionary.items = + xmalloc(rv.data.dictionary.size * sizeof(KeyValuePair)); + todo = ht->ht_used; + uint32_t i = 0; + + // Convert all + for (hi = ht->ht_array; todo > 0; ++hi) { + if (!HASHITEM_EMPTY(hi)) { + di = dict_lookup(hi); + // Convert key + rv.data.dictionary.items[i].key.data = + xstrdup((char *)hi->hi_key); + rv.data.dictionary.items[i].key.size = + strlen((char *)hi->hi_key); + // Convert value + rv.data.dictionary.items[i].value = + vim_to_object_rec(&di->di_tv, lookup); + todo--; + i++; + } + } + } + } + break; + } + + return rv; +} + + +static void set_option_value_for(char *key, + int numval, + char *stringval, + int opt_flags, + int opt_type, + void *from, + Error *err) +{ + win_T *save_curwin = NULL; + tabpage_T *save_curtab = NULL; + buf_T *save_curbuf = NULL; + + try_start(); + switch (opt_type) + { + case SREQ_WIN: + if (switch_win(&save_curwin, &save_curtab, (win_T *)from, + win_find_tabpage((win_T *)from), false) == FAIL) + { + if (try_end(err)) { + return; + } + set_api_error("problem while switching windows", err); + return; + } + set_option_value_err(key, numval, stringval, opt_flags, err); + restore_win(save_curwin, save_curtab, true); + break; + case SREQ_BUF: + switch_buffer(&save_curbuf, (buf_T *)from); + set_option_value_err(key, numval, stringval, opt_flags, err); + restore_buffer(save_curbuf); + break; + case SREQ_GLOBAL: + set_option_value_err(key, numval, stringval, opt_flags, err); + break; + } + + if (err->set) { + return; + } + + try_end(err); +} + + +static void set_option_value_err(char *key, + int numval, + char *stringval, + int opt_flags, + Error *err) +{ + char *errmsg; + + if ((errmsg = (char *)set_option_value((uint8_t *)key, + numval, + (uint8_t *)stringval, + opt_flags))) + { + if (try_end(err)) { + return; + } + + set_api_error(errmsg, err); + } +} diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h new file mode 100644 index 0000000000..da7e357d04 --- /dev/null +++ b/src/nvim/api/private/helpers.h @@ -0,0 +1,97 @@ +#ifndef NVIM_API_HELPERS_H +#define NVIM_API_HELPERS_H + +#include + +#include "nvim/api/private/defs.h" +#include "nvim/vim.h" + +#define set_api_error(message, err) \ + do { \ + strncpy(err->msg, message, sizeof(err->msg)); \ + err->set = true; \ + } while (0) + +/// Start block that may cause vimscript exceptions +void try_start(void); + +/// End try block, set the error message if any and return true if an error +/// occurred. +/// +/// @param err Pointer to the stack-allocated error object +/// @return true if an error occurred +bool try_end(Error *err); + +/// Recursively expands a vimscript value in a dict +/// +/// @param dict The vimscript dict +/// @param key The key +/// @param[out] err Details of an error that may have occurred +Object dict_get_value(dict_T *dict, String key, Error *err); + +/// Set a value in a dict. Objects are recursively expanded into their +/// vimscript equivalents. Passing 'nil' as value deletes the key. +/// +/// @param dict The vimscript dict +/// @param key The key +/// @param value The new value +/// @param[out] err Details of an error that may have occurred +/// @return the old value, if any +Object dict_set_value(dict_T *dict, String key, Object value, Error *err); + +/// Gets the value of a global or local(buffer, window) option. +/// +/// @param from If `type` is `SREQ_WIN` or `SREQ_BUF`, this must be a pointer +/// to the window or buffer. +/// @param type One of `SREQ_GLOBAL`, `SREQ_WIN` or `SREQ_BUF` +/// @param name The option name +/// @param[out] err Details of an error that may have occurred +/// @return the option value +Object get_option_from(void *from, int type, String name, Error *err); + +/// Sets the value of a global or local(buffer, window) option. +/// +/// @param to If `type` is `SREQ_WIN` or `SREQ_BUF`, this must be a pointer +/// to the window or buffer. +/// @param type One of `SREQ_GLOBAL`, `SREQ_WIN` or `SREQ_BUF` +/// @param name The option name +/// @param[out] err Details of an error that may have occurred +void set_option_to(void *to, int type, String name, Object value, Error *err); + +/// Convert a vim object to an `Object` instance, recursively expanding +/// Arrays/Dictionaries. +/// +/// @param obj The source object +/// @return The converted value +Object vim_to_object(typval_T *obj); + +/// Finds the pointer for a window number +/// +/// @param window the window number +/// @param[out] err Details of an error that may have occurred +/// @return the window pointer +buf_T *find_buffer(Buffer buffer, Error *err); + +/// Finds the pointer for a window number +/// +/// @param window the window number +/// @param[out] err Details of an error that may have occurred +/// @return the window pointer +win_T * find_window(Window window, Error *err); + +/// Finds the pointer for a tabpage number +/// +/// @param tabpage the tabpage number +/// @param[out] err Details of an error that may have occurred +/// @return the tabpage pointer +tabpage_T * find_tab(Tabpage tabpage, Error *err); + +/// Copies a C string into a String (binary safe string, characters + length) +/// +/// @param str the C string to copy +/// @return the resulting String, if the input string was NULL, then an +/// empty String is returned +String cstr_to_string(const char *str); + +#endif // NVIM_API_HELPERS_H + diff --git a/src/nvim/api/tabpage.c b/src/nvim/api/tabpage.c index fc50723ba5..f4e5f2857a 100644 --- a/src/nvim/api/tabpage.c +++ b/src/nvim/api/tabpage.c @@ -4,8 +4,8 @@ #include "nvim/api/tabpage.h" #include "nvim/api/vim.h" -#include "nvim/api/defs.h" -#include "nvim/api/helpers.h" +#include "nvim/api/private/defs.h" +#include "nvim/api/private/helpers.h" Integer tabpage_get_window_count(Tabpage tabpage, Error *err) { diff --git a/src/nvim/api/tabpage.h b/src/nvim/api/tabpage.h index ef049fb644..abf4377ee4 100644 --- a/src/nvim/api/tabpage.h +++ b/src/nvim/api/tabpage.h @@ -4,7 +4,7 @@ #include #include -#include "nvim/api/defs.h" +#include "nvim/api/private/defs.h" /// Gets the number of windows in a tabpage /// diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 8cf4fb04d7..cfde53b0a8 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -4,8 +4,8 @@ #include #include "nvim/api/vim.h" -#include "nvim/api/helpers.h" -#include "nvim/api/defs.h" +#include "nvim/api/private/helpers.h" +#include "nvim/api/private/defs.h" #include "nvim/api/buffer.h" #include "nvim/vim.h" #include "nvim/buffer.h" diff --git a/src/nvim/api/vim.h b/src/nvim/api/vim.h index 4ecc9fc2d0..2a712c19a1 100644 --- a/src/nvim/api/vim.h +++ b/src/nvim/api/vim.h @@ -4,7 +4,7 @@ #include #include -#include "nvim/api/defs.h" +#include "nvim/api/private/defs.h" /// Send keys to vim input buffer, simulating user input. /// diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index 8e21034c40..73487d9c49 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -3,8 +3,8 @@ #include #include "nvim/api/window.h" -#include "nvim/api/defs.h" -#include "nvim/api/helpers.h" +#include "nvim/api/private/defs.h" +#include "nvim/api/private/helpers.h" #include "nvim/vim.h" #include "nvim/window.h" #include "nvim/screen.h" diff --git a/src/nvim/api/window.h b/src/nvim/api/window.h index 525b7f86c7..4c036ff5d7 100644 --- a/src/nvim/api/window.h +++ b/src/nvim/api/window.h @@ -4,7 +4,7 @@ #include #include -#include "nvim/api/defs.h" +#include "nvim/api/private/defs.h" /// Gets the current buffer in a window /// diff --git a/src/nvim/os/msgpack_rpc.h b/src/nvim/os/msgpack_rpc.h index 0e9d474d8d..0f644273cd 100644 --- a/src/nvim/os/msgpack_rpc.h +++ b/src/nvim/os/msgpack_rpc.h @@ -6,7 +6,7 @@ #include -#include "nvim/api/defs.h" +#include "nvim/api/private/defs.h" /// Validates the basic structure of the msgpack-rpc call and fills `res` /// with the basic response structure. -- cgit From 7dfc7bc2e17151dc545c3f2f339515c1b946e586 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Fri, 23 May 2014 15:49:28 -0300 Subject: API: Refactor: Implement api/handle module This module will be used to implement remote management of objects through the API. Object types to be registered must have a `uint64_t` field named 'handle'. --- src/nvim/api/private/handle.c | 31 +++++++++++++++++++++++++++++++ src/nvim/api/private/handle.h | 14 ++++++++++++++ src/nvim/map.c | 1 + src/nvim/map.h | 1 + src/nvim/os_unix.c | 2 ++ 5 files changed, 49 insertions(+) create mode 100644 src/nvim/api/private/handle.c create mode 100644 src/nvim/api/private/handle.h (limited to 'src') diff --git a/src/nvim/api/private/handle.c b/src/nvim/api/private/handle.c new file mode 100644 index 0000000000..3bf519bc58 --- /dev/null +++ b/src/nvim/api/private/handle.c @@ -0,0 +1,31 @@ +#include + +#include "nvim/vim.h" +#include "nvim/map.h" +#include "nvim/api/private/handle.h" + +#define HANDLE_INIT(name) name##_handles = map_new(uint64_t)() + +#define HANDLE_IMPL(type, name) \ + static Map(uint64_t) *name##_handles = NULL; \ + \ + type *handle_get_##name(uint64_t handle) \ + { \ + return map_get(uint64_t)(name##_handles, handle); \ + } \ + \ + void handle_register_##name(type *name) \ + { \ + assert(!name->handle); \ + name->handle = next_handle++; \ + map_put(uint64_t)(name##_handles, name->handle, name); \ + } \ + \ + void handle_unregister_##name(type *name) \ + { \ + map_del(uint64_t)(name##_handles, name->handle); \ + } + +void handle_init() +{ +} diff --git a/src/nvim/api/private/handle.h b/src/nvim/api/private/handle.h new file mode 100644 index 0000000000..b9ed507ce9 --- /dev/null +++ b/src/nvim/api/private/handle.h @@ -0,0 +1,14 @@ +#ifndef NVIM_API_HANDLE_H +#define NVIM_API_HANDLE_H + +#include "nvim/vim.h" + +#define HANDLE_DECLS(type, name) \ + type *handle_get_##name(uint64_t handle); \ + void handle_register_##name(type *name); \ + void handle_unregister_##name(type *name); + +void handle_init(void); + +#endif // NVIM_API_HANDLE_H + diff --git a/src/nvim/map.c b/src/nvim/map.c index 28fd0af61c..559a5f261a 100644 --- a/src/nvim/map.c +++ b/src/nvim/map.c @@ -85,3 +85,4 @@ MAP_IMPL(cstr_t) MAP_IMPL(ptr_t) +MAP_IMPL(uint64_t) diff --git a/src/nvim/map.h b/src/nvim/map.h index ae47561deb..dba56dc5aa 100644 --- a/src/nvim/map.h +++ b/src/nvim/map.h @@ -21,6 +21,7 @@ MAP_DECLS(cstr_t) MAP_DECLS(ptr_t) +MAP_DECLS(uint64_t) #define map_new(T) map_##T##_new #define map_free(T) map_##T##_free diff --git a/src/nvim/os_unix.c b/src/nvim/os_unix.c index 52627b6a8b..e0b838ed26 100644 --- a/src/nvim/os_unix.c +++ b/src/nvim/os_unix.c @@ -27,6 +27,7 @@ #include +#include "nvim/api/private/handle.h" #include "nvim/vim.h" #include "nvim/os_unix.h" #include "nvim/buffer.h" @@ -542,6 +543,7 @@ int mch_nodetype(char_u *name) void mch_early_init() { + handle_init(); time_init(); } -- cgit From ed99198ff1a3c2b6aad88b03e838a1337f83c4dc Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Fri, 23 May 2014 15:49:30 -0300 Subject: API: Refactor: Register/unregister created/destroyed buffers - Add the 'handle' field to `buf_T` - Add declare/implement functions for registering/unregistering/retrieving buffers - Register/unregister buffers when they are created/destroyed. --- src/nvim/api/private/handle.c | 5 +++++ src/nvim/api/private/handle.h | 4 ++++ src/nvim/buffer.c | 3 +++ src/nvim/buffer_defs.h | 1 + 4 files changed, 13 insertions(+) (limited to 'src') diff --git a/src/nvim/api/private/handle.c b/src/nvim/api/private/handle.c index 3bf519bc58..97f5cd88b5 100644 --- a/src/nvim/api/private/handle.c +++ b/src/nvim/api/private/handle.c @@ -26,6 +26,11 @@ map_del(uint64_t)(name##_handles, name->handle); \ } +static uint64_t next_handle = 1; + +HANDLE_IMPL(buf_T, buffer) + void handle_init() { + HANDLE_INIT(buffer); } diff --git a/src/nvim/api/private/handle.h b/src/nvim/api/private/handle.h index b9ed507ce9..846b20dff2 100644 --- a/src/nvim/api/private/handle.h +++ b/src/nvim/api/private/handle.h @@ -2,13 +2,17 @@ #define NVIM_API_HANDLE_H #include "nvim/vim.h" +#include "nvim/buffer_defs.h" #define HANDLE_DECLS(type, name) \ type *handle_get_##name(uint64_t handle); \ void handle_register_##name(type *name); \ void handle_unregister_##name(type *name); +HANDLE_DECLS(buf_T, buffer) + void handle_init(void); + #endif // NVIM_API_HANDLE_H diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index ffb62add3c..7c50b1721c 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -26,6 +26,7 @@ #include +#include "nvim/api/private/handle.h" #include "nvim/vim.h" #include "nvim/buffer.h" #include "nvim/charset.h" @@ -538,6 +539,7 @@ void buf_freeall(buf_T *buf, int flags) */ static void free_buffer(buf_T *buf) { + handle_unregister_buffer(buf); free_buffer_stuff(buf, TRUE); unref_var_dict(buf->b_vars); aubuflocal_remove(buf); @@ -1362,6 +1364,7 @@ buflist_new ( } if (buf != curbuf || curbuf == NULL) { buf = xcalloc(1, sizeof(buf_T)); + handle_register_buffer(buf); /* init b: variables */ buf->b_vars = dict_alloc(); init_var_dict(buf->b_vars, &buf->b_bufvar, VAR_SCOPE); diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index d658da9502..6634ba72a6 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -401,6 +401,7 @@ typedef struct { */ struct file_buffer { + uint64_t handle; // unique identifier for the buffer memline_T b_ml; /* associated memline (also contains line count) */ -- cgit From 20848c4064fc82c160d68770b2e64f5115f0bf60 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Fri, 23 May 2014 15:49:33 -0300 Subject: API: Refactor: Register/unregister created/destroyed windows - Add the 'handle' field to `win_T` - Add declare/implement functions for registering/unregistering/retrieving windows - Register/unregister windows when they are created/destroyed. --- src/nvim/api/private/handle.c | 2 ++ src/nvim/api/private/handle.h | 1 + src/nvim/buffer_defs.h | 1 + src/nvim/window.c | 4 ++++ 4 files changed, 8 insertions(+) (limited to 'src') diff --git a/src/nvim/api/private/handle.c b/src/nvim/api/private/handle.c index 97f5cd88b5..3dfe05d59f 100644 --- a/src/nvim/api/private/handle.c +++ b/src/nvim/api/private/handle.c @@ -29,8 +29,10 @@ static uint64_t next_handle = 1; HANDLE_IMPL(buf_T, buffer) +HANDLE_IMPL(win_T, window) void handle_init() { HANDLE_INIT(buffer); + HANDLE_INIT(window); } diff --git a/src/nvim/api/private/handle.h b/src/nvim/api/private/handle.h index 846b20dff2..29c80e10d4 100644 --- a/src/nvim/api/private/handle.h +++ b/src/nvim/api/private/handle.h @@ -10,6 +10,7 @@ void handle_unregister_##name(type *name); HANDLE_DECLS(buf_T, buffer) +HANDLE_DECLS(win_T, window) void handle_init(void); diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 6634ba72a6..68f70d7bf3 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -840,6 +840,7 @@ struct matchitem { * All row numbers are relative to the start of the window, except w_winrow. */ struct window_S { + uint64_t handle; buf_T *w_buffer; /* buffer we are a window into (used often, keep it the first item!) */ diff --git a/src/nvim/window.c b/src/nvim/window.c index 851e9cead7..a0a325f950 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -6,6 +6,7 @@ * See README.txt for an overview of the Vim source code. */ +#include "nvim/api/private/handle.h" #include "nvim/vim.h" #include "nvim/window.h" #include "nvim/buffer.h" @@ -3568,6 +3569,7 @@ static win_T *win_alloc(win_T *after, int hidden) * allocate window structure and linesizes arrays */ win_T *new_wp = xcalloc(1, sizeof(win_T)); + handle_register_window(new_wp); win_alloc_lines(new_wp); /* init w: variables */ @@ -3583,6 +3585,7 @@ static win_T *win_alloc(win_T *after, int hidden) */ if (!hidden) win_append(after, new_wp); + new_wp->w_wincol = 0; new_wp->w_width = Columns; @@ -3618,6 +3621,7 @@ win_free ( buf_T *buf; wininfo_T *wip; + handle_unregister_window(wp); clearFolding(wp); /* reduce the reference count to the argument list. */ -- cgit From 5fdf854f78eb1a87acb2d28b3d941d988bd1b74e Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Fri, 23 May 2014 15:49:35 -0300 Subject: API: Refactor: Register/unregister created/destroyed tabpages - Add the 'handle' field to `tabpage_T` - Add declare/implement functions for registering/unregistering/retrieving tabpages - Register/unregister tabpages when they are created/destroyed. --- src/nvim/api/private/handle.c | 2 ++ src/nvim/api/private/handle.h | 1 + src/nvim/buffer_defs.h | 1 + src/nvim/window.c | 2 ++ 4 files changed, 6 insertions(+) (limited to 'src') diff --git a/src/nvim/api/private/handle.c b/src/nvim/api/private/handle.c index 3dfe05d59f..88d176fccb 100644 --- a/src/nvim/api/private/handle.c +++ b/src/nvim/api/private/handle.c @@ -30,9 +30,11 @@ static uint64_t next_handle = 1; HANDLE_IMPL(buf_T, buffer) HANDLE_IMPL(win_T, window) +HANDLE_IMPL(tabpage_T, tabpage) void handle_init() { HANDLE_INIT(buffer); HANDLE_INIT(window); + HANDLE_INIT(tabpage); } diff --git a/src/nvim/api/private/handle.h b/src/nvim/api/private/handle.h index 29c80e10d4..27df453233 100644 --- a/src/nvim/api/private/handle.h +++ b/src/nvim/api/private/handle.h @@ -11,6 +11,7 @@ HANDLE_DECLS(buf_T, buffer) HANDLE_DECLS(win_T, window) +HANDLE_DECLS(tabpage_T, tabpage) void handle_init(void); diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 68f70d7bf3..0a24280b4a 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -738,6 +738,7 @@ struct diffblock_S { */ typedef struct tabpage_S tabpage_T; struct tabpage_S { + uint64_t handle; tabpage_T *tp_next; /* next tabpage or NULL */ frame_T *tp_topframe; /* topframe for the windows */ win_T *tp_curwin; /* current window in this Tab page */ diff --git a/src/nvim/window.c b/src/nvim/window.c index a0a325f950..534805b766 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -2845,6 +2845,7 @@ void win_init_size(void) static tabpage_T *alloc_tabpage(void) { tabpage_T *tp = xcalloc(1, sizeof(tabpage_T)); + handle_register_tabpage(tp); /* init t: variables */ tp->tp_vars = dict_alloc(); @@ -2859,6 +2860,7 @@ void free_tabpage(tabpage_T *tp) { int idx; + handle_unregister_tabpage(tp); diff_clear(tp); for (idx = 0; idx < SNAP_COUNT; ++idx) clear_snapshot(tp, idx); -- cgit From 92307201b51c399e8109c91cc131ff3602389db1 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Fri, 23 May 2014 15:49:38 -0300 Subject: API: Refactor: Generalize buffer, window and tabpage types/functions - Extract remote types definitions into a macro - Extract msgpack_rpc helper functions for remote types into a macro --- src/nvim/api/private/defs.h | 14 +++++++++++--- src/nvim/os/msgpack_rpc.c | 44 ++++++++++++++------------------------------ 2 files changed, 25 insertions(+), 33 deletions(-) (limited to 'src') diff --git a/src/nvim/api/private/defs.h b/src/nvim/api/private/defs.h index 3ee50310fb..9b0639067d 100644 --- a/src/nvim/api/private/defs.h +++ b/src/nvim/api/private/defs.h @@ -5,6 +5,14 @@ #include #include +#define REMOTE_TYPE(type) typedef Integer type + +#define TYPED_ARRAY_OF(type) \ + typedef struct { \ + type *items; \ + size_t size; \ + } type##Array + // Basic types typedef struct { char msg[256]; @@ -20,9 +28,9 @@ typedef struct { size_t size; } String; -typedef Integer Buffer; -typedef Integer Window; -typedef Integer Tabpage; +REMOTE_TYPE(Buffer); +REMOTE_TYPE(Window); +REMOTE_TYPE(Tabpage); typedef struct object Object; diff --git a/src/nvim/os/msgpack_rpc.c b/src/nvim/os/msgpack_rpc.c index 45832070b1..c1e749a000 100644 --- a/src/nvim/os/msgpack_rpc.c +++ b/src/nvim/os/msgpack_rpc.c @@ -4,6 +4,16 @@ #include "nvim/vim.h" #include "nvim/memory.h" +#define REMOTE_FUNCS_IMPL(t, lt) \ + bool msgpack_rpc_to_##lt(msgpack_object *obj, t *arg) \ + { \ + return msgpack_rpc_to_integer(obj, arg); \ + } \ + \ + void msgpack_rpc_from_##lt(t result, msgpack_packer *res) \ + { \ + msgpack_rpc_from_integer(result, res); \ + } void msgpack_rpc_call(msgpack_object *req, msgpack_packer *res) { // The initial response structure is the same no matter what happens, @@ -104,21 +114,6 @@ bool msgpack_rpc_to_string(msgpack_object *obj, String *arg) return obj->type == MSGPACK_OBJECT_RAW; } -bool msgpack_rpc_to_buffer(msgpack_object *obj, Buffer *arg) -{ - return msgpack_rpc_to_integer(obj, arg); -} - -bool msgpack_rpc_to_window(msgpack_object *obj, Window *arg) -{ - return msgpack_rpc_to_integer(obj, arg); -} - -bool msgpack_rpc_to_tabpage(msgpack_object *obj, Tabpage *arg) -{ - return msgpack_rpc_to_integer(obj, arg); -} - bool msgpack_rpc_to_object(msgpack_object *obj, Object *arg) { switch (obj->type) { @@ -251,21 +246,6 @@ void msgpack_rpc_from_string(String result, msgpack_packer *res) msgpack_pack_raw_body(res, result.data, result.size); } -void msgpack_rpc_from_buffer(Buffer result, msgpack_packer *res) -{ - msgpack_rpc_from_integer(result, res); -} - -void msgpack_rpc_from_window(Window result, msgpack_packer *res) -{ - msgpack_rpc_from_integer(result, res); -} - -void msgpack_rpc_from_tabpage(Tabpage result, msgpack_packer *res) -{ - msgpack_rpc_from_integer(result, res); -} - void msgpack_rpc_from_object(Object result, msgpack_packer *res) { switch (result.type) { @@ -390,3 +370,7 @@ void msgpack_rpc_free_dictionary(Dictionary value) free(value.items); } +REMOTE_FUNCS_IMPL(Buffer, buffer) +REMOTE_FUNCS_IMPL(Window, window) +REMOTE_FUNCS_IMPL(Tabpage, tabpage) + -- cgit From 1e67b13fdcb6ed7f2a951b9053f0a829b3a48906 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Fri, 23 May 2014 15:49:40 -0300 Subject: API: Refactor: Add macro infrastructure for typed arrays - Add macros supporting typed arrays in the remote API - Refactor StringArray-related functions on top of the new macros --- src/nvim/api/private/defs.h | 5 +-- src/nvim/os/msgpack_rpc.c | 74 ++++++++++++++++++++++++--------------------- src/nvim/os/msgpack_rpc.h | 9 +++--- 3 files changed, 45 insertions(+), 43 deletions(-) (limited to 'src') diff --git a/src/nvim/api/private/defs.h b/src/nvim/api/private/defs.h index 9b0639067d..a6c2eea8e5 100644 --- a/src/nvim/api/private/defs.h +++ b/src/nvim/api/private/defs.h @@ -34,10 +34,7 @@ REMOTE_TYPE(Tabpage); typedef struct object Object; -typedef struct { - String *items; - size_t size; -} StringArray; +TYPED_ARRAY_OF(String); typedef struct { Integer row, col; diff --git a/src/nvim/os/msgpack_rpc.c b/src/nvim/os/msgpack_rpc.c index c1e749a000..6c18c7310d 100644 --- a/src/nvim/os/msgpack_rpc.c +++ b/src/nvim/os/msgpack_rpc.c @@ -14,6 +14,43 @@ { \ msgpack_rpc_from_integer(result, res); \ } + +#define TYPED_ARRAY_IMPL(t, lt) \ + bool msgpack_rpc_to_##lt##array(msgpack_object *obj, t##Array *arg) \ + { \ + if (obj->type != MSGPACK_OBJECT_ARRAY) { \ + return false; \ + } \ + \ + arg->size = obj->via.array.size; \ + arg->items = xcalloc(obj->via.array.size, sizeof(t)); \ + \ + for (size_t i = 0; i < obj->via.array.size; i++) { \ + if (!msgpack_rpc_to_##lt(obj->via.array.ptr + i, &arg->items[i])) { \ + return false; \ + } \ + } \ + \ + return true; \ + } \ + \ + void msgpack_rpc_from_##lt##array(t##Array result, msgpack_packer *res) \ + { \ + msgpack_pack_array(res, result.size); \ + \ + for (size_t i = 0; i < result.size; i++) { \ + msgpack_rpc_from_##lt(result.items[i], res); \ + } \ + } \ + \ + void msgpack_rpc_free_##lt##array(t##Array value) { \ + for (size_t i = 0; i < value.size; i++) { \ + msgpack_rpc_free_##lt(value.items[i]); \ + } \ + \ + free(value.items); \ + } + void msgpack_rpc_call(msgpack_object *req, msgpack_packer *res) { // The initial response structure is the same no matter what happens, @@ -151,24 +188,6 @@ bool msgpack_rpc_to_object(msgpack_object *obj, Object *arg) } } -bool msgpack_rpc_to_stringarray(msgpack_object *obj, StringArray *arg) -{ - if (obj->type != MSGPACK_OBJECT_ARRAY) { - return false; - } - - arg->size = obj->via.array.size; - arg->items = xcalloc(obj->via.array.size, sizeof(String)); - - for (uint32_t i = 0; i < obj->via.array.size; i++) { - if (!msgpack_rpc_to_string(obj->via.array.ptr + i, &arg->items[i])) { - return false; - } - } - - return true; -} - bool msgpack_rpc_to_position(msgpack_object *obj, Position *arg) { return obj->type == MSGPACK_OBJECT_ARRAY @@ -282,15 +301,6 @@ void msgpack_rpc_from_object(Object result, msgpack_packer *res) } } -void msgpack_rpc_from_stringarray(StringArray result, msgpack_packer *res) -{ - msgpack_pack_array(res, result.size); - - for (size_t i = 0; i < result.size; i++) { - msgpack_rpc_from_string(result.items[i], res); - } -} - void msgpack_rpc_from_position(Position result, msgpack_packer *res) { msgpack_pack_array(res, 2);; @@ -343,14 +353,6 @@ void msgpack_rpc_free_object(Object value) } } -void msgpack_rpc_free_stringarray(StringArray value) { - for (uint32_t i = 0; i < value.size; i++) { - msgpack_rpc_free_string(value.items[i]); - } - - free(value.items); -} - void msgpack_rpc_free_array(Array value) { for (uint32_t i = 0; i < value.size; i++) { @@ -374,3 +376,5 @@ REMOTE_FUNCS_IMPL(Buffer, buffer) REMOTE_FUNCS_IMPL(Window, window) REMOTE_FUNCS_IMPL(Tabpage, tabpage) +TYPED_ARRAY_IMPL(String, string) + diff --git a/src/nvim/os/msgpack_rpc.h b/src/nvim/os/msgpack_rpc.h index 0f644273cd..45632c7389 100644 --- a/src/nvim/os/msgpack_rpc.h +++ b/src/nvim/os/msgpack_rpc.h @@ -8,6 +8,8 @@ #include "nvim/api/private/defs.h" +#define ARRAY_DICT_INIT {.size = 0, .items = NULL} + /// Validates the basic structure of the msgpack-rpc call and fills `res` /// with the basic response structure. /// @@ -80,9 +82,9 @@ void msgpack_rpc_from_dictionary(Dictionary result, msgpack_packer *res); #define msgpack_rpc_init_window #define msgpack_rpc_init_tabpage #define msgpack_rpc_init_object = {.type = kObjectTypeNil} -#define msgpack_rpc_init_stringarray = {.items = NULL, .size = 0} -#define msgpack_rpc_init_array = {.items = NULL, .size = 0} -#define msgpack_rpc_init_dictionary = {.items = NULL, .size = 0} +#define msgpack_rpc_init_stringarray = ARRAY_DICT_INIT +#define msgpack_rpc_init_array = ARRAY_DICT_INIT +#define msgpack_rpc_init_dictionary = ARRAY_DICT_INIT /// Helpers for freeing arguments/return value /// @@ -102,6 +104,5 @@ void msgpack_rpc_free_stringarray(StringArray value); void msgpack_rpc_free_array(Array value); void msgpack_rpc_free_dictionary(Dictionary value); - #endif // NVIM_OS_MSGPACK_RPC_H -- cgit From f70f9bfac1ae62828d222bc6ccb528e6e93be523 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Fri, 23 May 2014 15:49:42 -0300 Subject: API: Refactor: Change the integer type of remote objects to uint64_t --- src/nvim/api/private/defs.h | 2 +- src/nvim/api/private/helpers.c | 4 ++-- src/nvim/api/vim.c | 19 +++++++++++++++---- src/nvim/api/window.c | 3 ++- src/nvim/os/msgpack_rpc.c | 5 +++-- 5 files changed, 23 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/nvim/api/private/defs.h b/src/nvim/api/private/defs.h index a6c2eea8e5..770f43b20a 100644 --- a/src/nvim/api/private/defs.h +++ b/src/nvim/api/private/defs.h @@ -5,7 +5,7 @@ #include #include -#define REMOTE_TYPE(type) typedef Integer type +#define REMOTE_TYPE(type) typedef uint64_t type #define TYPED_ARRAY_OF(type) \ typedef struct { \ diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index a7d155382c..64aa0a2013 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -285,7 +285,7 @@ Object vim_to_object(typval_T *obj) buf_T *find_buffer(Buffer buffer, Error *err) { - if (buffer > INT_MAX || buffer < INT_MIN) { + if (buffer > INT_MAX) { set_api_error("Invalid buffer id", err); return NULL; } @@ -316,7 +316,7 @@ win_T * find_window(Window window, Error *err) tabpage_T * find_tab(Tabpage tabpage, Error *err) { - if (tabpage > INT_MAX || tabpage < INT_MIN) { + if (tabpage > INT_MAX) { set_api_error("Invalid tabpage id", err); return NULL; } diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index cfde53b0a8..6e8840a003 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -142,17 +142,27 @@ void vim_change_directory(String dir, Error *err) String vim_get_current_line(Error *err) { - return buffer_get_line(curbuf->b_fnum, curwin->w_cursor.lnum - 1, err); + assert(curbuf->b_fnum >= 0); + return buffer_get_line((uint64_t)curbuf->b_fnum, + curwin->w_cursor.lnum - 1, + err); } void vim_set_current_line(String line, Error *err) { - buffer_set_line(curbuf->b_fnum, curwin->w_cursor.lnum - 1, line, err); + assert(curbuf->b_fnum >= 0); + buffer_set_line((uint64_t)curbuf->b_fnum, + curwin->w_cursor.lnum - 1, + line, + err); } void vim_del_current_line(Error *err) { - buffer_del_line(curbuf->b_fnum, curwin->w_cursor.lnum - 1, err); + assert(curbuf->b_fnum >= 0); + buffer_del_line((uint64_t)curbuf->b_fnum, + curwin->w_cursor.lnum - 1, + err); } Object vim_get_var(String name, Error *err) @@ -205,7 +215,8 @@ Integer vim_get_buffer_count(void) Buffer vim_get_current_buffer(void) { - return curbuf->b_fnum; + assert(curbuf->b_fnum >= 0); + return (uint64_t)curbuf->b_fnum; } void vim_set_current_buffer(Buffer buffer, Error *err) diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index 73487d9c49..8b31d8e9fc 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -19,7 +19,8 @@ Buffer window_get_buffer(Window window, Error *err) return 0; } - return win->w_buffer->b_fnum; + assert(win->w_buffer->b_fnum >= 0); + return (uint64_t)win->w_buffer->b_fnum; } Position window_get_cursor(Window window, Error *err) diff --git a/src/nvim/os/msgpack_rpc.c b/src/nvim/os/msgpack_rpc.c index 6c18c7310d..5840d25375 100644 --- a/src/nvim/os/msgpack_rpc.c +++ b/src/nvim/os/msgpack_rpc.c @@ -7,12 +7,13 @@ #define REMOTE_FUNCS_IMPL(t, lt) \ bool msgpack_rpc_to_##lt(msgpack_object *obj, t *arg) \ { \ - return msgpack_rpc_to_integer(obj, arg); \ + *arg = obj->via.u64; \ + return obj->type == MSGPACK_OBJECT_POSITIVE_INTEGER; \ } \ \ void msgpack_rpc_from_##lt(t result, msgpack_packer *res) \ { \ - msgpack_rpc_from_integer(result, res); \ + msgpack_pack_uint64(res, result); \ } #define TYPED_ARRAY_IMPL(t, lt) \ -- cgit From a842fe4dc1e0624a6332ee0fef40517e7925dfb4 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Fri, 23 May 2014 15:49:44 -0300 Subject: API: Refactor: Return handles instead of indexes - Define specialized arrays for each remote object type - Implement msgpack_rpc functions for dealing with the new types - Refactor all functions dealing with buffers, windows and tabpages to return/accept handles instead of list indexes. --- src/nvim/api/private/defs.h | 3 ++ src/nvim/api/private/helpers.c | 31 ++++-------- src/nvim/api/tabpage.c | 21 ++++++--- src/nvim/api/tabpage.h | 2 +- src/nvim/api/vim.c | 104 ++++++++++++++++++++--------------------- src/nvim/api/vim.h | 12 ++--- src/nvim/api/window.c | 13 ++++-- src/nvim/os/msgpack_rpc.c | 3 ++ src/nvim/os/msgpack_rpc.h | 12 +++++ 9 files changed, 109 insertions(+), 92 deletions(-) (limited to 'src') diff --git a/src/nvim/api/private/defs.h b/src/nvim/api/private/defs.h index 770f43b20a..6be786b15a 100644 --- a/src/nvim/api/private/defs.h +++ b/src/nvim/api/private/defs.h @@ -34,6 +34,9 @@ REMOTE_TYPE(Tabpage); typedef struct object Object; +TYPED_ARRAY_OF(Buffer); +TYPED_ARRAY_OF(Window); +TYPED_ARRAY_OF(Tabpage); TYPED_ARRAY_OF(String); typedef struct { diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 64aa0a2013..c4340ddd89 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -4,6 +4,7 @@ #include "nvim/api/private/helpers.h" #include "nvim/api/private/defs.h" +#include "nvim/api/private/handle.h" #include "nvim/vim.h" #include "nvim/buffer.h" #include "nvim/window.h" @@ -285,43 +286,29 @@ Object vim_to_object(typval_T *obj) buf_T *find_buffer(Buffer buffer, Error *err) { - if (buffer > INT_MAX) { - set_api_error("Invalid buffer id", err); - return NULL; - } - - buf_T *buf = buflist_findnr((int)buffer); + buf_T *rv = handle_get_buffer(buffer); - if (buf == NULL) { + if (!rv) { set_api_error("Invalid buffer id", err); } - return buf; + return rv; } win_T * find_window(Window window, Error *err) { - tabpage_T *tp; - win_T *wp; + win_T *rv = handle_get_window(window); - FOR_ALL_TAB_WINDOWS(tp, wp) { - if (!--window) { - return wp; - } + if (!rv) { + set_api_error("Invalid window id", err); } - set_api_error("Invalid window id", err); - return NULL; + return rv; } tabpage_T * find_tab(Tabpage tabpage, Error *err) { - if (tabpage > INT_MAX) { - set_api_error("Invalid tabpage id", err); - return NULL; - } - - tabpage_T *rv = find_tabpage((int)tabpage); + tabpage_T *rv = handle_get_tabpage(tabpage); if (!rv) { set_api_error("Invalid tabpage id", err); diff --git a/src/nvim/api/tabpage.c b/src/nvim/api/tabpage.c index f4e5f2857a..58efc6a514 100644 --- a/src/nvim/api/tabpage.c +++ b/src/nvim/api/tabpage.c @@ -6,10 +6,11 @@ #include "nvim/api/vim.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" +#include "nvim/memory.h" -Integer tabpage_get_window_count(Tabpage tabpage, Error *err) +WindowArray tabpage_get_windows(Tabpage tabpage, Error *err) { - Integer rv = 0; + WindowArray rv = {.size = 0}; tabpage_T *tab = find_tab(tabpage, err); if (!tab) { @@ -23,7 +24,17 @@ Integer tabpage_get_window_count(Tabpage tabpage, Error *err) if (tp != tab) { break; } - rv++; + rv.size++; + } + + rv.items = xmalloc(sizeof(Window) * rv.size); + size_t i = 0; + + FOR_ALL_TAB_WINDOWS(tp, wp) { + if (tp != tab) { + break; + } + rv.items[i++] = wp->handle; } return rv; @@ -67,13 +78,11 @@ Window tabpage_get_window(Tabpage tabpage, Error *err) } else { tabpage_T *tp; win_T *wp; - rv = 1; FOR_ALL_TAB_WINDOWS(tp, wp) { if (tp == tab && wp == tab->tp_curwin) { - return rv; + return wp->handle; } - rv++; } // There should always be a current window for a tabpage abort(); diff --git a/src/nvim/api/tabpage.h b/src/nvim/api/tabpage.h index abf4377ee4..dddcecbdbd 100644 --- a/src/nvim/api/tabpage.h +++ b/src/nvim/api/tabpage.h @@ -11,7 +11,7 @@ /// @param tabpage The tabpage /// @param[out] err Details of an error that may have occurred /// @return The number of windows in `tabpage` -Integer tabpage_get_window_count(Tabpage tabpage, Error *err); +WindowArray tabpage_get_windows(Tabpage tabpage, Error *err); /// Gets a tabpage variable /// diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 6e8840a003..d9a5ce1db5 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -142,27 +142,17 @@ void vim_change_directory(String dir, Error *err) String vim_get_current_line(Error *err) { - assert(curbuf->b_fnum >= 0); - return buffer_get_line((uint64_t)curbuf->b_fnum, - curwin->w_cursor.lnum - 1, - err); + return buffer_get_line(curbuf->handle, curwin->w_cursor.lnum - 1, err); } void vim_set_current_line(String line, Error *err) { - assert(curbuf->b_fnum >= 0); - buffer_set_line((uint64_t)curbuf->b_fnum, - curwin->w_cursor.lnum - 1, - line, - err); + buffer_set_line(curbuf->handle, curwin->w_cursor.lnum - 1, line, err); } void vim_del_current_line(Error *err) { - assert(curbuf->b_fnum >= 0); - buffer_del_line((uint64_t)curbuf->b_fnum, - curwin->w_cursor.lnum - 1, - err); + buffer_del_line(curbuf->handle, curwin->w_cursor.lnum - 1, err); } Object vim_get_var(String name, Error *err) @@ -200,33 +190,43 @@ void vim_err_write(String str) write_msg(str, true); } -Integer vim_get_buffer_count(void) +BufferArray vim_get_buffers(void) { + BufferArray rv = {.size = 0}; buf_T *b = firstbuf; - Integer n = 0; while (b) { - n++; + rv.size++; b = b->b_next; } - return n; + rv.items = xmalloc(sizeof(Buffer) * rv.size); + size_t i = 0; + b = firstbuf; + + while (b) { + rv.items[i++] = b->handle; + b = b->b_next; + } + + return rv; } Buffer vim_get_current_buffer(void) { - assert(curbuf->b_fnum >= 0); - return (uint64_t)curbuf->b_fnum; + return curbuf->handle; } void vim_set_current_buffer(Buffer buffer, Error *err) { - if (!find_buffer(buffer, err)) { + buf_T *buf = find_buffer(buffer, err); + + if (!buf) { return; } try_start(); - if (do_buffer(DOBUF_GOTO, DOBUF_FIRST, FORWARD, (int)buffer, 0) == FAIL) { + if (do_buffer(DOBUF_GOTO, DOBUF_FIRST, FORWARD, buf->b_fnum, 0) == FAIL) { if (try_end(err)) { return; } @@ -240,14 +240,21 @@ void vim_set_current_buffer(Buffer buffer, Error *err) try_end(err); } -Integer vim_get_window_count(void) +WindowArray vim_get_windows(void) { + WindowArray rv = {.size = 0}; tabpage_T *tp; win_T *wp; - Integer rv = 0; FOR_ALL_TAB_WINDOWS(tp, wp) { - rv++; + rv.size++; + } + + rv.items = xmalloc(sizeof(Window) * rv.size); + size_t i = 0; + + FOR_ALL_TAB_WINDOWS(tp, wp) { + rv.items[i++] = wp->handle; } return rv; @@ -255,20 +262,7 @@ Integer vim_get_window_count(void) Window vim_get_current_window(void) { - tabpage_T *tp; - win_T *wp; - Window rv = 1; - - FOR_ALL_TAB_WINDOWS(tp, wp) { - if (wp == curwin) { - return rv; - } - - rv++; - } - - // There should always be a current window - abort(); + return curwin->handle; } void vim_set_current_window(Window window, Error *err) @@ -280,7 +274,7 @@ void vim_set_current_window(Window window, Error *err) } try_start(); - win_goto(win); + goto_tabpage_win(win_find_tabpage(win), win); if (win != curwin) { if (try_end(err)) { @@ -293,14 +287,23 @@ void vim_set_current_window(Window window, Error *err) try_end(err); } -Integer vim_get_tabpage_count(void) +TabpageArray vim_get_tabpages(void) { + TabpageArray rv = {.size = 0}; tabpage_T *tp = first_tabpage; - Integer rv = 0; - while (tp != NULL) { + while (tp) { + rv.size++; + tp = tp->tp_next; + } + + rv.items = xmalloc(sizeof(Tabpage) * rv.size); + size_t i = 0; + tp = first_tabpage; + + while (tp) { + rv.items[i++] = tp->handle; tp = tp->tp_next; - rv++; } return rv; @@ -308,24 +311,19 @@ Integer vim_get_tabpage_count(void) Tabpage vim_get_current_tabpage(void) { - Tabpage rv = 1; - tabpage_T *t; - - for (t = first_tabpage; t != NULL && t != curtab; t = t->tp_next) { - rv++; - } - - return rv; + return curtab->handle; } void vim_set_current_tabpage(Tabpage tabpage, Error *err) { - if (!find_tab(tabpage, err)) { + tabpage_T *tp = find_tab(tabpage, err); + + if (!tp) { return; } try_start(); - goto_tabpage((int)tabpage); + goto_tabpage_tp(tp, true, true); try_end(err); } diff --git a/src/nvim/api/vim.h b/src/nvim/api/vim.h index 2a712c19a1..acfab11cf7 100644 --- a/src/nvim/api/vim.h +++ b/src/nvim/api/vim.h @@ -108,10 +108,10 @@ void vim_out_write(String str); /// @param str The message void vim_err_write(String str); -/// Gets the number of buffers +/// Gets the current list of buffer handles /// /// @return The number of buffers -Integer vim_get_buffer_count(void); +BufferArray vim_get_buffers(void); /// Return the current buffer /// @@ -124,10 +124,10 @@ Buffer vim_get_current_buffer(void); /// @param[out] err Details of an error that may have occurred void vim_set_current_buffer(Buffer buffer, Error *err); -/// Gets the number of windows +/// Gets the current list of window handles /// /// @return The number of windows -Integer vim_get_window_count(void); +WindowArray vim_get_windows(void); /// Return the current window /// @@ -139,10 +139,10 @@ Window vim_get_current_window(void); /// @param handle The window handle void vim_set_current_window(Window window, Error *err); -/// Gets the number of tab pages +/// Gets the current list of tabpage handles /// /// @return The number of tab pages -Integer vim_get_tabpage_count(void); +TabpageArray vim_get_tabpages(void); /// Return the current tab page /// diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index 8b31d8e9fc..8bd8316477 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -19,8 +19,7 @@ Buffer window_get_buffer(Window window, Error *err) return 0; } - assert(win->w_buffer->b_fnum >= 0); - return (uint64_t)win->w_buffer->b_fnum; + return win->w_buffer->handle; } Position window_get_cursor(Window window, Error *err) @@ -193,8 +192,14 @@ Position window_get_position(Window window, Error *err) Tabpage window_get_tabpage(Window window, Error *err) { - set_api_error("Not implemented", err); - return 0; + Tabpage rv = 0; + win_T *win = find_window(window, err); + + if (win) { + rv = win_find_tabpage(win)->handle; + } + + return rv; } Boolean window_is_valid(Window window) diff --git a/src/nvim/os/msgpack_rpc.c b/src/nvim/os/msgpack_rpc.c index 5840d25375..d7ffa6f559 100644 --- a/src/nvim/os/msgpack_rpc.c +++ b/src/nvim/os/msgpack_rpc.c @@ -377,5 +377,8 @@ REMOTE_FUNCS_IMPL(Buffer, buffer) REMOTE_FUNCS_IMPL(Window, window) REMOTE_FUNCS_IMPL(Tabpage, tabpage) +TYPED_ARRAY_IMPL(Buffer, buffer) +TYPED_ARRAY_IMPL(Window, window) +TYPED_ARRAY_IMPL(Tabpage, tabpage) TYPED_ARRAY_IMPL(String, string) diff --git a/src/nvim/os/msgpack_rpc.h b/src/nvim/os/msgpack_rpc.h index 45632c7389..80c5a6914f 100644 --- a/src/nvim/os/msgpack_rpc.h +++ b/src/nvim/os/msgpack_rpc.h @@ -50,6 +50,9 @@ bool msgpack_rpc_to_window(msgpack_object *obj, Window *arg); bool msgpack_rpc_to_tabpage(msgpack_object *obj, Tabpage *arg); bool msgpack_rpc_to_object(msgpack_object *obj, Object *arg); bool msgpack_rpc_to_stringarray(msgpack_object *obj, StringArray *arg); +bool msgpack_rpc_to_bufferarray(msgpack_object *obj, BufferArray *arg); +bool msgpack_rpc_to_windowarray(msgpack_object *obj, WindowArray *arg); +bool msgpack_rpc_to_tabpagearray(msgpack_object *obj, TabpageArray *arg); bool msgpack_rpc_to_array(msgpack_object *obj, Array *arg); bool msgpack_rpc_to_dictionary(msgpack_object *obj, Dictionary *arg); @@ -69,6 +72,9 @@ void msgpack_rpc_from_window(Window result, msgpack_packer *res); void msgpack_rpc_from_tabpage(Tabpage result, msgpack_packer *res); void msgpack_rpc_from_object(Object result, msgpack_packer *res); void msgpack_rpc_from_stringarray(StringArray result, msgpack_packer *res); +void msgpack_rpc_from_bufferarray(BufferArray result, msgpack_packer *res); +void msgpack_rpc_from_windowarray(WindowArray result, msgpack_packer *res); +void msgpack_rpc_from_tabpagearray(TabpageArray result, msgpack_packer *res); void msgpack_rpc_from_array(Array result, msgpack_packer *res); void msgpack_rpc_from_dictionary(Dictionary result, msgpack_packer *res); @@ -83,6 +89,9 @@ void msgpack_rpc_from_dictionary(Dictionary result, msgpack_packer *res); #define msgpack_rpc_init_tabpage #define msgpack_rpc_init_object = {.type = kObjectTypeNil} #define msgpack_rpc_init_stringarray = ARRAY_DICT_INIT +#define msgpack_rpc_init_bufferarray = ARRAY_DICT_INIT +#define msgpack_rpc_init_windowarray = ARRAY_DICT_INIT +#define msgpack_rpc_init_tabpagearray = ARRAY_DICT_INIT #define msgpack_rpc_init_array = ARRAY_DICT_INIT #define msgpack_rpc_init_dictionary = ARRAY_DICT_INIT @@ -101,6 +110,9 @@ void msgpack_rpc_from_dictionary(Dictionary result, msgpack_packer *res); #define msgpack_rpc_free_tabpage(value) void msgpack_rpc_free_object(Object value); void msgpack_rpc_free_stringarray(StringArray value); +void msgpack_rpc_free_bufferarray(BufferArray value); +void msgpack_rpc_free_windowarray(WindowArray value); +void msgpack_rpc_free_tabpagearray(TabpageArray value); void msgpack_rpc_free_array(Array value); void msgpack_rpc_free_dictionary(Dictionary value); -- cgit From 1156360fe724fd3242186ededd8b3d4a42c990cd Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Fri, 23 May 2014 15:49:46 -0300 Subject: API: Refactor: Implement buffer_get_number --- src/nvim/api/buffer.c | 12 ++++++++++++ src/nvim/api/buffer.h | 7 +++++++ 2 files changed, 19 insertions(+) (limited to 'src') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 9a4285d74c..0796f5a324 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -293,6 +293,18 @@ void buffer_set_option(Buffer buffer, String name, Object value, Error *err) set_option_to(buf, SREQ_BUF, name, value, err); } +Integer buffer_get_number(Buffer buffer, Error *err) +{ + Integer rv = 0; + buf_T *buf = find_buffer(buffer, err); + + if (!buf) { + return rv; + } + + return buf->b_fnum; +} + String buffer_get_name(Buffer buffer, Error *err) { String rv = {.size = 0, .data = ""}; diff --git a/src/nvim/api/buffer.h b/src/nvim/api/buffer.h index 2350f7f41d..52a3b7cdb3 100644 --- a/src/nvim/api/buffer.h +++ b/src/nvim/api/buffer.h @@ -104,6 +104,13 @@ Object buffer_get_option(Buffer buffer, String name, Error *err); /// @param[out] err Details of an error that may have occurred void buffer_set_option(Buffer buffer, String name, Object value, Error *err); +/// Gets the buffer number +/// +/// @param buffer The buffer handle +/// @param[out] err Details of an error that may have occurred +/// @return The buffer number +Integer buffer_get_number(Buffer buffer, Error *err); + /// Gets the full file name for the buffer /// /// @param buffer The buffer handle -- cgit From 9815688fbdeb7bc1f1a28b9d827b31eea4fe8cfb Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Fri, 23 May 2014 15:49:48 -0300 Subject: API: Refactor: Use macro for initializing all arrays --- src/nvim/api/buffer.c | 4 ++-- src/nvim/api/private/defs.h | 1 + src/nvim/api/tabpage.c | 2 +- src/nvim/api/vim.c | 8 ++++---- src/nvim/os/msgpack_rpc.h | 2 -- 5 files changed, 8 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 0796f5a324..929735a6b9 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -71,7 +71,7 @@ void buffer_set_line(Buffer buffer, Integer index, String line, Error *err) void buffer_del_line(Buffer buffer, Integer index, Error *err) { - StringArray array = {.size = 0}; + StringArray array = ARRAY_DICT_INIT; buffer_set_slice(buffer, index, index, true, true, array, err); } @@ -82,7 +82,7 @@ StringArray buffer_get_slice(Buffer buffer, Boolean include_end, Error *err) { - StringArray rv = {.size = 0}; + StringArray rv = ARRAY_DICT_INIT; buf_T *buf = find_buffer(buffer, err); if (!buf) { diff --git a/src/nvim/api/private/defs.h b/src/nvim/api/private/defs.h index 6be786b15a..a91907f4f8 100644 --- a/src/nvim/api/private/defs.h +++ b/src/nvim/api/private/defs.h @@ -5,6 +5,7 @@ #include #include +#define ARRAY_DICT_INIT {.size = 0, .items = NULL} #define REMOTE_TYPE(type) typedef uint64_t type #define TYPED_ARRAY_OF(type) \ diff --git a/src/nvim/api/tabpage.c b/src/nvim/api/tabpage.c index 58efc6a514..b7243c68a8 100644 --- a/src/nvim/api/tabpage.c +++ b/src/nvim/api/tabpage.c @@ -10,7 +10,7 @@ WindowArray tabpage_get_windows(Tabpage tabpage, Error *err) { - WindowArray rv = {.size = 0}; + WindowArray rv = ARRAY_DICT_INIT; tabpage_T *tab = find_tab(tabpage, err); if (!tab) { diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index d9a5ce1db5..694781e0a3 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -81,7 +81,7 @@ Integer vim_strwidth(String str, Error *err) StringArray vim_list_runtime_paths(void) { - StringArray rv = {.size = 0}; + StringArray rv = ARRAY_DICT_INIT; uint8_t *rtp = p_rtp; if (*rtp == NUL) { @@ -192,7 +192,7 @@ void vim_err_write(String str) BufferArray vim_get_buffers(void) { - BufferArray rv = {.size = 0}; + BufferArray rv = ARRAY_DICT_INIT; buf_T *b = firstbuf; while (b) { @@ -242,7 +242,7 @@ void vim_set_current_buffer(Buffer buffer, Error *err) WindowArray vim_get_windows(void) { - WindowArray rv = {.size = 0}; + WindowArray rv = ARRAY_DICT_INIT; tabpage_T *tp; win_T *wp; @@ -289,7 +289,7 @@ void vim_set_current_window(Window window, Error *err) TabpageArray vim_get_tabpages(void) { - TabpageArray rv = {.size = 0}; + TabpageArray rv = ARRAY_DICT_INIT; tabpage_T *tp = first_tabpage; while (tp) { diff --git a/src/nvim/os/msgpack_rpc.h b/src/nvim/os/msgpack_rpc.h index 80c5a6914f..a6a909ac1f 100644 --- a/src/nvim/os/msgpack_rpc.h +++ b/src/nvim/os/msgpack_rpc.h @@ -8,8 +8,6 @@ #include "nvim/api/private/defs.h" -#define ARRAY_DICT_INIT {.size = 0, .items = NULL} - /// Validates the basic structure of the msgpack-rpc call and fills `res` /// with the basic response structure. /// -- cgit From f03a7672e18fe57b1e4de17abf2a193f8b343562 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Fri, 23 May 2014 15:49:49 -0300 Subject: API: Refactor: Fix buffer_get_mark --- src/nvim/api/buffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 929735a6b9..bf30ccf856 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -364,7 +364,7 @@ Position buffer_get_mark(Buffer buffer, String name, Error *err) return rv; } - if (name.size != 0) { + if (name.size != 1) { set_api_error("mark name must be a single character", err); return rv; } -- cgit