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/api/private/defs.h | 79 ++++++ src/nvim/api/private/helpers.c | 607 +++++++++++++++++++++++++++++++++++++++++ src/nvim/api/private/helpers.h | 97 +++++++ 3 files changed, 783 insertions(+) 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/nvim/api/private') 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 + -- 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 ++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 src/nvim/api/private/handle.c create mode 100644 src/nvim/api/private/handle.h (limited to 'src/nvim/api/private') 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 + -- 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 ++++ 2 files changed, 9 insertions(+) (limited to 'src/nvim/api/private') 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 -- 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 + 2 files changed, 3 insertions(+) (limited to 'src/nvim/api/private') 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); -- 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 + 2 files changed, 3 insertions(+) (limited to 'src/nvim/api/private') 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); -- 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 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'src/nvim/api/private') 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; -- 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 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'src/nvim/api/private') 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; -- 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 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/nvim/api/private') 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; } -- 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 +++++++++---------------------- 2 files changed, 12 insertions(+), 22 deletions(-) (limited to 'src/nvim/api/private') 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); -- 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/private/defs.h | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/api/private') 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) \ -- cgit