aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThiago de Arruda <tpadilha84@gmail.com>2014-05-08 18:48:40 -0300
committerThiago de Arruda <tpadilha84@gmail.com>2014-05-13 09:33:41 -0300
commit7c01d5ff9286d262097484c680e3a4eab49e2911 (patch)
tree17c4402f90638019525612720216cdc444ced5ef
parent5f5e39323ee799def35adde7cfee06698c2dfcc8 (diff)
downloadrneovim-7c01d5ff9286d262097484c680e3a4eab49e2911.tar.gz
rneovim-7c01d5ff9286d262097484c680e3a4eab49e2911.tar.bz2
rneovim-7c01d5ff9286d262097484c680e3a4eab49e2911.zip
API: Implement vim_{get,set}_var
-rw-r--r--src/api/helpers.c160
-rw-r--r--src/api/helpers.h18
-rw-r--r--src/api/vim.c10
-rw-r--r--src/api/vim.h8
4 files changed, 188 insertions, 8 deletions
diff --git a/src/api/helpers.c b/src/api/helpers.c
index 2e189861a5..584249fcc6 100644
--- a/src/api/helpers.c
+++ b/src/api/helpers.c
@@ -20,6 +20,8 @@ KHASH_SET_INIT_INT64(Lookup)
/// @return The converted value
static Object vim_to_object_rec(typval_T *obj, khash_t(Lookup) *lookup);
+static bool object_to_vim(Object obj, typval_T *tv, Error *err);
+
void try_start()
{
++trylevel;
@@ -62,6 +64,76 @@ bool try_end(Error *err)
return err->set;
}
+Object dict_get_value(dict_T *dict, String key, bool pop, Error *err)
+{
+ Object rv;
+ hashitem_T *hi;
+ dictitem_T *di;
+ char k[key.size + 1];
+ // Convert the key
+ memcpy(k, key.data, key.size);
+ k[key.size] = NUL;
+ hi = hash_find(&dict->dv_hashtab, (uint8_t *)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);
+
+ if (pop) {
+ if (dict->dv_lock) {
+ set_api_error("Dictionary is locked", err);
+ return rv;
+ }
+
+ hash_remove(&dict->dv_hashtab, hi);
+ dictitem_free(di);
+ }
+
+ 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;
+ }
+
+ dictitem_T *di = dict_find(dict, (uint8_t *)key.data, key.size);
+ typval_T tv;
+
+ if (!object_to_vim(value, &tv, err)) {
+ return rv;
+ }
+
+ if (di == NULL) {
+ uint8_t k[key.size + 1];
+ memcpy(k, key.data, key.size);
+ k[key.size] = NUL;
+ di = dictitem_alloc(k);
+ dict_add(dict, di);
+ } else {
+ rv = vim_to_object(&di->di_tv);
+ clear_tv(&di->di_tv);
+ }
+
+ copy_tv(&tv, &di->di_tv);
+ clear_tv(&tv);
+
+ return rv;
+}
+
Object vim_to_object(typval_T *obj)
{
Object rv;
@@ -73,6 +145,94 @@ Object vim_to_object(typval_T *obj)
return rv;
}
+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 kObjectTypeBool:
+ tv->v_type = VAR_NUMBER;
+ tv->vval.v_number = obj.data.boolean;
+ break;
+
+ case kObjectTypeInt:
+ tv->v_type = VAR_NUMBER;
+ tv->vval.v_number = obj.data.integer;
+ break;
+
+ case kObjectTypeFloat:
+ tv->v_type = VAR_FLOAT;
+ tv->vval.v_float = obj.data.floating_point;
+ 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[key.size + 1];
+ memcpy(k, key.data, key.size);
+ k[key.size] = NUL;
+ dictitem_T *di = dictitem_alloc((uint8_t *)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, khash_t(Lookup) *lookup)
{
Object rv = {.type = kObjectTypeNil};
diff --git a/src/api/helpers.h b/src/api/helpers.h
index ddb46eaad4..d839fe30e7 100644
--- a/src/api/helpers.h
+++ b/src/api/helpers.h
@@ -22,6 +22,24 @@ void try_start(void);
/// @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 bool If true it will pop the value from the dict
+/// @param[out] err Details of an error that may have occurred
+Object dict_get_value(dict_T *dict, String key, bool pop, Error *err);
+
+/// Set a value in a dict. Objects are recursively expanded into their
+/// vimscript equivalents.
+///
+/// @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);
+
/// Convert a vim object to an `Object` instance, recursively expanding
/// Arrays/Dictionaries.
///
diff --git a/src/api/vim.c b/src/api/vim.c
index efe37d9e9a..93654da91f 100644
--- a/src/api/vim.c
+++ b/src/api/vim.c
@@ -127,14 +127,16 @@ void vim_set_current_line(Object line, Error *err)
buffer_set_line(curbuf->b_fnum, curwin->w_cursor.lnum - 1, line, err);
}
-Object vim_get_var(bool special, String name, Error *err)
+Object vim_get_var(bool special, String name, bool pop, Error *err)
{
- abort();
+ return dict_get_value(special ? &vimvardict : &globvardict, name,
+ special ? false : pop,
+ err);
}
-void vim_set_var(bool special, String name, Object value, Error *err)
+Object vim_set_var(String name, Object value, Error *err)
{
- abort();
+ return dict_set_value(&globvardict, name, value, err);
}
String vim_get_option(String name, Error *err)
diff --git a/src/api/vim.h b/src/api/vim.h
index 8335081de7..a18f9c69e9 100644
--- a/src/api/vim.h
+++ b/src/api/vim.h
@@ -62,15 +62,15 @@ void vim_set_current_line(Object line, Error *err);
/// @param name The variable name
/// @param[out] err Details of an error that may have occurred
/// @return The variable value
-Object vim_get_var(bool special, String name, Error *err);
+Object vim_get_var(bool special, String name, bool pop, Error *err);
-/// Sets a global or special variable
+/// Sets a global variable
///
-/// @param special If it's a special(:v) variable
/// @param name The variable name
/// @param value The variable value
/// @param[out] err Details of an error that may have occurred
-void vim_set_var(bool special, String name, Object value, Error *err);
+/// @return the old value if any
+Object vim_set_var(String name, Object value, Error *err);
/// Get an option value string
///