mirror of
https://github.com/neovim/neovim.git
synced 2025-09-18 09:18:19 +00:00
API: Move vim_to_object to helpers.c
This commit is contained in:
@@ -5,6 +5,20 @@
|
|||||||
#include "api/helpers.h"
|
#include "api/helpers.h"
|
||||||
#include "api/defs.h"
|
#include "api/defs.h"
|
||||||
#include "../vim.h"
|
#include "../vim.h"
|
||||||
|
#include "memory.h"
|
||||||
|
#include "eval.h"
|
||||||
|
|
||||||
|
#include "lib/khash.h"
|
||||||
|
|
||||||
|
KHASH_SET_INIT_INT64(Lookup)
|
||||||
|
|
||||||
|
/// 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, khash_t(Lookup) *lookup);
|
||||||
|
|
||||||
void try_start()
|
void try_start()
|
||||||
{
|
{
|
||||||
@@ -48,3 +62,117 @@ bool try_end(Error *err)
|
|||||||
return err->set;
|
return err->set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Object vim_to_object(typval_T *obj)
|
||||||
|
{
|
||||||
|
Object rv;
|
||||||
|
// We use a lookup table to break out of cyclic references
|
||||||
|
khash_t(Lookup) *lookup = kh_init(Lookup);
|
||||||
|
rv = vim_to_object_rec(obj, lookup);
|
||||||
|
// Free the table
|
||||||
|
kh_destroy(Lookup, lookup);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Object vim_to_object_rec(typval_T *obj, khash_t(Lookup) *lookup)
|
||||||
|
{
|
||||||
|
Object rv = {.type = kObjectTypeNil};
|
||||||
|
|
||||||
|
if (obj->v_type == VAR_LIST || obj->v_type == VAR_DICT) {
|
||||||
|
int ret;
|
||||||
|
// Container object, add it to the lookup table
|
||||||
|
kh_put(Lookup, lookup, (uint64_t)obj, &ret);
|
||||||
|
if (!ret) {
|
||||||
|
// It's already present, meaning we alredy processed it so just return
|
||||||
|
// nil instead.
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = kObjectTypeInt;
|
||||||
|
rv.data.integer = obj->vval.v_number;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VAR_FLOAT:
|
||||||
|
rv.type = kObjectTypeFloat;
|
||||||
|
rv.data.floating_point = obj->vval.v_float;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VAR_LIST:
|
||||||
|
{
|
||||||
|
list_T *list = obj->vval.v_list;
|
||||||
|
listitem_T *item;
|
||||||
|
|
||||||
|
if (list != NULL) {
|
||||||
|
rv.type = kObjectTypeArray;
|
||||||
|
rv.data.array.size = list->lv_len;
|
||||||
|
rv.data.array.items = xmalloc(list->lv_len * 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;
|
||||||
|
}
|
||||||
|
@@ -4,6 +4,7 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include "api/defs.h"
|
#include "api/defs.h"
|
||||||
|
#include "../vim.h"
|
||||||
|
|
||||||
#define set_api_error(message, err) \
|
#define set_api_error(message, err) \
|
||||||
do { \
|
do { \
|
||||||
@@ -21,5 +22,12 @@ void try_start(void);
|
|||||||
/// @return true if an error occurred
|
/// @return true if an error occurred
|
||||||
bool try_end(Error *err);
|
bool try_end(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);
|
||||||
|
|
||||||
#endif /* NEOVIM_API_HELPERS_H */
|
#endif /* NEOVIM_API_HELPERS_H */
|
||||||
|
|
||||||
|
136
src/api/vim.c
136
src/api/vim.c
@@ -12,28 +12,9 @@
|
|||||||
#include "ascii.h"
|
#include "ascii.h"
|
||||||
#include "ex_docmd.h"
|
#include "ex_docmd.h"
|
||||||
#include "screen.h"
|
#include "screen.h"
|
||||||
|
#include "memory.h"
|
||||||
#include "eval.h"
|
#include "eval.h"
|
||||||
#include "misc2.h"
|
#include "misc2.h"
|
||||||
#include "memory.h"
|
|
||||||
|
|
||||||
#include "lib/khash.h"
|
|
||||||
|
|
||||||
KHASH_SET_INIT_INT64(Lookup)
|
|
||||||
|
|
||||||
/// Convert a vim object to an `Object` instance, recursively expanding
|
|
||||||
/// Arrays/Dictionaries.
|
|
||||||
///
|
|
||||||
/// @param obj The source object
|
|
||||||
/// @return The converted value
|
|
||||||
static Object vim_to_object(typval_T *vim_obj);
|
|
||||||
|
|
||||||
/// 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, khash_t(Lookup) *lookup);
|
|
||||||
|
|
||||||
void vim_push_keys(String str)
|
void vim_push_keys(String str)
|
||||||
{
|
{
|
||||||
@@ -240,118 +221,3 @@ void vim_set_current_tabpage(Tabpage tabpage)
|
|||||||
{
|
{
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
static Object vim_to_object(typval_T *obj)
|
|
||||||
{
|
|
||||||
Object rv;
|
|
||||||
// We use a lookup table to break out of cyclic references
|
|
||||||
khash_t(Lookup) *lookup = kh_init(Lookup);
|
|
||||||
rv = vim_to_object_rec(obj, lookup);
|
|
||||||
// Free the table
|
|
||||||
kh_destroy(Lookup, lookup);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Object vim_to_object_rec(typval_T *obj, khash_t(Lookup) *lookup)
|
|
||||||
{
|
|
||||||
Object rv = {.type = kObjectTypeNil};
|
|
||||||
|
|
||||||
if (obj->v_type == VAR_LIST || obj->v_type == VAR_DICT) {
|
|
||||||
int ret;
|
|
||||||
// Container object, add it to the lookup table
|
|
||||||
kh_put(Lookup, lookup, (uint64_t)obj, &ret);
|
|
||||||
if (!ret) {
|
|
||||||
// It's already present, meaning we alredy processed it so just return
|
|
||||||
// nil instead.
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 = kObjectTypeInt;
|
|
||||||
rv.data.integer = obj->vval.v_number;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VAR_FLOAT:
|
|
||||||
rv.type = kObjectTypeFloat;
|
|
||||||
rv.data.floating_point = obj->vval.v_float;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VAR_LIST:
|
|
||||||
{
|
|
||||||
list_T *list = obj->vval.v_list;
|
|
||||||
listitem_T *item;
|
|
||||||
|
|
||||||
if (list != NULL) {
|
|
||||||
rv.type = kObjectTypeArray;
|
|
||||||
rv.data.array.size = list->lv_len;
|
|
||||||
rv.data.array.items = xmalloc(list->lv_len * 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;
|
|
||||||
}
|
|
||||||
|
Reference in New Issue
Block a user