From d5a60d17fbca33ca96124288e69937a276d3abda Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Sun, 7 Sep 2014 18:48:10 -0300 Subject: api/msgpack-rpc: Remove specialized array types Specialized array types(BufferArray, WindowArray, etc) were added to the API for two main reasons: - msgpack used to lack a way of serializing appliaction-specific types and there was no obvious way of making an API function accept/return arrays of custom objects such as buffers(which are represented as integers, so clients didn't have a way to distinguish from normal numbers) - Let clients in statically-typed languages that support generics have a better typed API With msgpack 2.0 EXT type the first item is no longer a factor and this commit starts by removing the specialized array types. The second item will be addressed in the future by making the API metadata return extra useful information for statically-typed languages. --- src/nvim/api/buffer.c | 46 +++++++++++++++++++++++++-------------------- src/nvim/api/private/defs.h | 19 ------------------- src/nvim/api/tabpage.c | 8 ++++---- src/nvim/api/vim.c | 37 ++++++++++++++++++------------------ 4 files changed, 49 insertions(+), 61 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index a268e04559..380de12c89 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -51,10 +51,10 @@ Integer buffer_get_length(Buffer buffer, Error *err) 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); + Array slice = buffer_get_slice(buffer, index, index, true, true, err); if (!err->set && slice.size) { - rv = slice.items[0]; + rv = slice.items[0].data.string; } free(slice.items); @@ -70,7 +70,8 @@ String buffer_get_line(Buffer buffer, Integer index, Error *err) /// @param[out] err Details of an error that may have occurred void buffer_set_line(Buffer buffer, Integer index, String line, Error *err) { - StringArray array = {.items = &line, .size = 1}; + Object l = STRING_OBJ(line); + Array array = {.items = &l, .size = 1}; buffer_set_slice(buffer, index, index, true, true, array, err); } @@ -81,7 +82,7 @@ void buffer_set_line(Buffer buffer, Integer index, String line, Error *err) /// @param[out] err Details of an error that may have occurred void buffer_del_line(Buffer buffer, Integer index, Error *err) { - StringArray array = ARRAY_DICT_INIT; + Array array = ARRAY_DICT_INIT; buffer_set_slice(buffer, index, index, true, true, array, err); } @@ -94,14 +95,14 @@ void buffer_del_line(Buffer buffer, Integer index, Error *err) /// @param include_end True if the slice includes the `end` parameter /// @param[out] err Details of an error that may have occurred /// @return An array of lines -StringArray buffer_get_slice(Buffer buffer, - Integer start, - Integer end, - Boolean include_start, - Boolean include_end, - Error *err) +Array buffer_get_slice(Buffer buffer, + Integer start, + Integer end, + Boolean include_start, + Boolean include_end, + Error *err) { - StringArray rv = ARRAY_DICT_INIT; + Array rv = ARRAY_DICT_INIT; buf_T *buf = find_buffer_by_handle(buffer, err); if (!buf) { @@ -118,7 +119,7 @@ StringArray buffer_get_slice(Buffer buffer, } rv.size = (size_t)(end - start); - rv.items = xcalloc(sizeof(String), rv.size); + rv.items = xcalloc(sizeof(Object), rv.size); for (size_t i = 0; i < rv.size; i++) { int64_t lnum = start + (int64_t)i; @@ -129,13 +130,13 @@ StringArray buffer_get_slice(Buffer buffer, } const char *bufstr = (char *) ml_get_buf(buf, (linenr_T) lnum, false); - rv.items[i] = cstr_to_string(bufstr); + rv.items[i] = STRING_OBJ(cstr_to_string(bufstr)); } end: if (err->set) { for (size_t i = 0; i < rv.size; i++) { - free(rv.items[i].data); + free(rv.items[i].data.string.data); } free(rv.items); @@ -152,15 +153,15 @@ end: /// @param end The last line index /// @param include_start True if the slice includes the `start` parameter /// @param include_end True if the slice includes the `end` parameter -/// @param lines An array of lines to use as replacement(A 0-length array -/// will simply delete the line range) +/// @param replacement An array of lines to use as replacement(A 0-length +// array will simply delete the line range) /// @param[out] err Details of an error that may have occurred void buffer_set_slice(Buffer buffer, Integer start, Integer end, Boolean include_start, Boolean include_end, - StringArray replacement, + Array replacement, Error *err) { buf_T *buf = find_buffer_by_handle(buffer, err); @@ -184,10 +185,15 @@ void buffer_set_slice(Buffer buffer, size_t new_len = replacement.size; size_t old_len = (size_t)(end - start); ssize_t extra = 0; // lines added to text, can be negative - char **lines = (new_len != 0) ? xmalloc(new_len * sizeof(char *)) : NULL; + char **lines = (new_len != 0) ? xcalloc(new_len, sizeof(char *)) : NULL; for (size_t i = 0; i < new_len; i++) { - String l = replacement.items[i]; + if (replacement.items[i].type != kObjectTypeString) { + set_api_error("all items in the replacement array must be strings", err); + goto end; + } + + String l = replacement.items[i].data.string; lines[i] = xmemdupz(l.data, l.size); } @@ -430,7 +436,7 @@ Boolean buffer_is_valid(Buffer buffer) /// to the end of the buffer. /// @param lines An array of lines /// @param[out] err Details of an error that may have occurred -void buffer_insert(Buffer buffer, Integer lnum, StringArray lines, Error *err) +void buffer_insert(Buffer buffer, Integer lnum, Array lines, Error *err) { buffer_set_slice(buffer, lnum, lnum, false, true, lines, err); } diff --git a/src/nvim/api/private/defs.h b/src/nvim/api/private/defs.h index b049412014..071563a628 100644 --- a/src/nvim/api/private/defs.h +++ b/src/nvim/api/private/defs.h @@ -11,12 +11,6 @@ #define POSITION_INIT { .row = 0, .col = 0 } #define REMOTE_TYPE(type) typedef uint64_t type -#define TYPED_ARRAY_OF(type) \ - typedef struct { \ - type *items; \ - size_t size; \ - } type##Array - // Basic types typedef struct { char msg[256]; @@ -38,11 +32,6 @@ 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 { Integer row, col; } Position; @@ -71,10 +60,6 @@ typedef enum { kObjectTypeArray, kObjectTypeDictionary, kObjectTypePosition, - kObjectTypeStringArray, - kObjectTypeBufferArray, - kObjectTypeWindowArray, - kObjectTypeTabpageArray, } ObjectType; struct object { @@ -90,10 +75,6 @@ struct object { Array array; Dictionary dictionary; Position position; - StringArray stringarray; - BufferArray bufferarray; - WindowArray windowarray; - TabpageArray tabpagearray; } data; }; diff --git a/src/nvim/api/tabpage.c b/src/nvim/api/tabpage.c index 535722c087..901f9a6c1a 100644 --- a/src/nvim/api/tabpage.c +++ b/src/nvim/api/tabpage.c @@ -13,9 +13,9 @@ /// @param tabpage The tabpage /// @param[out] err Details of an error that may have occurred /// @return The number of windows in `tabpage` -WindowArray tabpage_get_windows(Tabpage tabpage, Error *err) +Array tabpage_get_windows(Tabpage tabpage, Error *err) { - WindowArray rv = ARRAY_DICT_INIT; + Array rv = ARRAY_DICT_INIT; tabpage_T *tab = find_tab_by_handle(tabpage, err); if (!tab) { @@ -32,14 +32,14 @@ WindowArray tabpage_get_windows(Tabpage tabpage, Error *err) rv.size++; } - rv.items = xmalloc(sizeof(Window) * rv.size); + rv.items = xmalloc(sizeof(Object) * rv.size); size_t i = 0; FOR_ALL_TAB_WINDOWS(tp, wp) { if (tp != tab) { break; } - rv.items[i++] = wp->handle; + rv.items[i++] = WINDOW_OBJ(wp->handle); } return rv; diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index a2c50b4c81..b1d5a067b4 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -149,9 +149,9 @@ Integer vim_strwidth(String str, Error *err) /// Returns a list of paths contained in 'runtimepath' /// /// @return The list of paths -StringArray vim_list_runtime_paths(void) +Array vim_list_runtime_paths(void) { - StringArray rv = ARRAY_DICT_INIT; + Array rv = ARRAY_DICT_INIT; uint8_t *rtp = p_rtp; if (*rtp == NUL) { @@ -168,19 +168,20 @@ StringArray vim_list_runtime_paths(void) } // Allocate memory for the copies - rv.items = xmalloc(sizeof(String) * rv.size); + rv.items = xmalloc(sizeof(Object) * rv.size); // reset the position rtp = p_rtp; // Start copying for (size_t i = 0; i < rv.size && *rtp != NUL; i++) { - rv.items[i].data = xmalloc(MAXPATHL); + rv.items[i].type = kObjectTypeString; + rv.items[i].data.string.data = xmalloc(MAXPATHL); // Copy the path from 'runtimepath' to rv.items[i] int length = copy_option_part(&rtp, - (char_u *)rv.items[i].data, + (char_u *)rv.items[i].data.string.data, MAXPATHL, ","); assert(length >= 0); - rv.items[i].size = (size_t)length; + rv.items[i].data.string.size = (size_t)length; } return rv; @@ -310,9 +311,9 @@ void vim_err_write(String str) /// Gets the current list of buffer handles /// /// @return The number of buffers -BufferArray vim_get_buffers(void) +Array vim_get_buffers(void) { - BufferArray rv = ARRAY_DICT_INIT; + Array rv = ARRAY_DICT_INIT; buf_T *b = firstbuf; while (b) { @@ -320,12 +321,12 @@ BufferArray vim_get_buffers(void) b = b->b_next; } - rv.items = xmalloc(sizeof(Buffer) * rv.size); + rv.items = xmalloc(sizeof(Object) * rv.size); size_t i = 0; b = firstbuf; while (b) { - rv.items[i++] = b->handle; + rv.items[i++] = BUFFER_OBJ(b->handle); b = b->b_next; } @@ -370,9 +371,9 @@ void vim_set_current_buffer(Buffer buffer, Error *err) /// Gets the current list of window handles /// /// @return The number of windows -WindowArray vim_get_windows(void) +Array vim_get_windows(void) { - WindowArray rv = ARRAY_DICT_INIT; + Array rv = ARRAY_DICT_INIT; tabpage_T *tp; win_T *wp; @@ -380,11 +381,11 @@ WindowArray vim_get_windows(void) rv.size++; } - rv.items = xmalloc(sizeof(Window) * rv.size); + rv.items = xmalloc(sizeof(Object) * rv.size); size_t i = 0; FOR_ALL_TAB_WINDOWS(tp, wp) { - rv.items[i++] = wp->handle; + rv.items[i++] = WINDOW_OBJ(wp->handle); } return rv; @@ -426,9 +427,9 @@ void vim_set_current_window(Window window, Error *err) /// Gets the current list of tabpage handles /// /// @return The number of tab pages -TabpageArray vim_get_tabpages(void) +Array vim_get_tabpages(void) { - TabpageArray rv = ARRAY_DICT_INIT; + Array rv = ARRAY_DICT_INIT; tabpage_T *tp = first_tabpage; while (tp) { @@ -436,12 +437,12 @@ TabpageArray vim_get_tabpages(void) tp = tp->tp_next; } - rv.items = xmalloc(sizeof(Tabpage) * rv.size); + rv.items = xmalloc(sizeof(Object) * rv.size); size_t i = 0; tp = first_tabpage; while (tp) { - rv.items[i++] = tp->handle; + rv.items[i++] = TABPAGE_OBJ(tp->handle); tp = tp->tp_next; } -- cgit From 2f566c83d9eee4a8097c9a18eb58dcef6adf894e Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Sun, 7 Sep 2014 20:40:07 -0300 Subject: api/msgpack-rpc: Parse type information from api/private/defs.h Enhance msgpack-gen.lua to extract custom api type codes from the ObjectType enum in api/private/defs.h. The type information is made available from the api metadata and clients can use to correctly serialize/deserialize these types using msgpack EXT type. --- src/nvim/api/private/defs.h | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/private/defs.h b/src/nvim/api/private/defs.h index 071563a628..689594f231 100644 --- a/src/nvim/api/private/defs.h +++ b/src/nvim/api/private/defs.h @@ -49,32 +49,36 @@ typedef struct { } Dictionary; typedef enum { +// The following comments are markers that msgpack-gen.lua uses to extract +// types, don't remove! +// start custom types + kObjectTypePosition, + kObjectTypeBuffer, + kObjectTypeWindow, + kObjectTypeTabpage, +// end custom types kObjectTypeNil, kObjectTypeBoolean, kObjectTypeInteger, kObjectTypeFloat, kObjectTypeString, - kObjectTypeBuffer, - kObjectTypeWindow, - kObjectTypeTabpage, kObjectTypeArray, kObjectTypeDictionary, - kObjectTypePosition, } ObjectType; struct object { ObjectType type; union { + Position position; + Buffer buffer; + Window window; + Tabpage tabpage; Boolean boolean; Integer integer; Float floating; String string; - Buffer buffer; - Window window; - Tabpage tabpage; Array array; Dictionary dictionary; - Position position; } data; }; -- cgit From 2792a0e33c0845fdd5b1b752d99ee573f6534256 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Tue, 9 Sep 2014 08:59:48 -0300 Subject: api/msgpack-rpc: Remove Position type, using arrays instead. --- src/nvim/api/buffer.c | 9 +++++---- src/nvim/api/private/defs.h | 7 ------- src/nvim/api/window.c | 38 +++++++++++++++++++++----------------- 3 files changed, 26 insertions(+), 28 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 380de12c89..383e13fd92 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -447,9 +447,9 @@ void buffer_insert(Buffer buffer, Integer lnum, Array lines, Error *err) /// @param name The mark's name /// @param[out] err Details of an error that may have occurred /// @return The (row, col) tuple -Position buffer_get_mark(Buffer buffer, String name, Error *err) +Array buffer_get_mark(Buffer buffer, String name, Error *err) { - Position rv = POSITION_INIT; + Array rv = ARRAY_DICT_INIT; buf_T *buf = find_buffer_by_handle(buffer, err); if (!buf) { @@ -479,8 +479,9 @@ Position buffer_get_mark(Buffer buffer, String name, Error *err) return rv; } - rv.row = posp->lnum; - rv.col = posp->col; + ADD(rv, INTEGER_OBJ(posp->lnum)); + ADD(rv, INTEGER_OBJ(posp->col)); + return rv; } diff --git a/src/nvim/api/private/defs.h b/src/nvim/api/private/defs.h index 689594f231..11800ed786 100644 --- a/src/nvim/api/private/defs.h +++ b/src/nvim/api/private/defs.h @@ -8,7 +8,6 @@ #define ARRAY_DICT_INIT {.size = 0, .items = NULL} #define STRING_INIT {.data = NULL, .size = 0} #define OBJECT_INIT { .type = kObjectTypeNil } -#define POSITION_INIT { .row = 0, .col = 0 } #define REMOTE_TYPE(type) typedef uint64_t type // Basic types @@ -32,10 +31,6 @@ REMOTE_TYPE(Tabpage); typedef struct object Object; -typedef struct { - Integer row, col; -} Position; - typedef struct { Object *items; size_t size, capacity; @@ -52,7 +47,6 @@ typedef enum { // The following comments are markers that msgpack-gen.lua uses to extract // types, don't remove! // start custom types - kObjectTypePosition, kObjectTypeBuffer, kObjectTypeWindow, kObjectTypeTabpage, @@ -69,7 +63,6 @@ typedef enum { struct object { ObjectType type; union { - Position position; Buffer buffer; Window window; Tabpage tabpage; diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index 1ab441bed3..967d8acda4 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -33,14 +33,14 @@ Buffer window_get_buffer(Window window, Error *err) /// @param window The window handle /// @param[out] err Details of an error that may have occurred /// @return the (row, col) tuple -Position window_get_cursor(Window window, Error *err) +Array window_get_cursor(Window window, Error *err) { - Position rv = POSITION_INIT; + Array rv = ARRAY_DICT_INIT; win_T *win = find_window_by_handle(window, err); if (win) { - rv.row = win->w_cursor.lnum; - rv.col = win->w_cursor.col; + ADD(rv, INTEGER_OBJ(win->w_cursor.lnum)); + ADD(rv, INTEGER_OBJ(win->w_cursor.col)); } return rv; @@ -51,31 +51,35 @@ Position window_get_cursor(Window window, Error *err) /// @param window The window handle /// @param pos the (row, col) tuple representing the new position /// @param[out] err Details of an error that may have occurred -void window_set_cursor(Window window, Position pos, Error *err) +void window_set_cursor(Window window, Array pos, Error *err) { win_T *win = find_window_by_handle(window, err); - if (!win) { + if (pos.size != 2 || pos.items[0].type != kObjectTypeInteger || + pos.items[1].type != kObjectTypeInteger) { + set_api_error("\"pos\" argument must be a [row, col] array", err); return; } - if (pos.row <= 0 || pos.row > win->w_buffer->b_ml.ml_line_count) { - set_api_error("cursor position outside buffer", err); + if (!win) { return; } - if (pos.row > LONG_MAX || pos.row < LONG_MIN) { - set_api_error("Row value outside range", err); + int64_t row = pos.items[0].data.integer; + int64_t col = pos.items[1].data.integer; + + if (row <= 0 || row > win->w_buffer->b_ml.ml_line_count) { + set_api_error("cursor position outside buffer", err); return; } - if (pos.col > INT_MAX || pos.col < INT_MIN) { + if (col > MAXCOL || col < 0) { set_api_error("Column value outside range", err); return; } - win->w_cursor.lnum = (linenr_T)pos.row; - win->w_cursor.col = (colnr_T)pos.col; + win->w_cursor.lnum = (linenr_T)row; + win->w_cursor.col = (colnr_T)col; win->w_cursor.coladd = 0; // When column is out of range silently correct it. check_cursor_col_win(win); @@ -243,14 +247,14 @@ void window_set_option(Window window, String name, Object value, Error *err) /// @param window The window handle /// @param[out] err Details of an error that may have occurred /// @return The (row, col) tuple with the window position -Position window_get_position(Window window, Error *err) +Array window_get_position(Window window, Error *err) { - Position rv = POSITION_INIT; + Array rv = ARRAY_DICT_INIT; win_T *win = find_window_by_handle(window, err); if (win) { - rv.col = win->w_wincol; - rv.row = win->w_winrow; + ADD(rv, INTEGER_OBJ(win->w_winrow)); + ADD(rv, INTEGER_OBJ(win->w_wincol)); } return rv; -- cgit From cac24cb06ddcad0cfb3a9379c3bdd0e8706602f9 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Tue, 9 Sep 2014 09:36:14 -0300 Subject: api/msgpack-rpc: Refactor msgpack_rpc_helpers.{c,h} - Move helpers that are specific to API types to api/private/helpers.{c,h} - Include headers with generated declarations - Delete unused macros --- src/nvim/api/private/helpers.c | 58 ++++++++++++++++++++++++++++++++++++++++++ src/nvim/api/private/helpers.h | 44 ++++++++++++++------------------ 2 files changed, 77 insertions(+), 25 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index f6fb46e1d1..de23481813 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -449,6 +449,64 @@ bool object_to_vim(Object obj, typval_T *tv, Error *err) return true; } +void api_free_string(String value) +{ + if (!value.data) { + return; + } + + free(value.data); +} + +void api_free_object(Object value) +{ + switch (value.type) { + case kObjectTypeNil: + case kObjectTypeBoolean: + case kObjectTypeInteger: + case kObjectTypeFloat: + case kObjectTypeBuffer: + case kObjectTypeWindow: + case kObjectTypeTabpage: + break; + + case kObjectTypeString: + api_free_string(value.data.string); + break; + + case kObjectTypeArray: + api_free_array(value.data.array); + break; + + case kObjectTypeDictionary: + api_free_dictionary(value.data.dictionary); + break; + + default: + abort(); + } +} + +void api_free_array(Array value) +{ + for (size_t i = 0; i < value.size; i++) { + api_free_object(value.items[i]); + } + + free(value.items); +} + +void api_free_dictionary(Dictionary value) +{ + for (size_t i = 0; i < value.size; i++) { + api_free_string(value.items[i].key); + api_free_object(value.items[i].value); + } + + free(value.items); +} + + /// Recursion helper for the `vim_to_object`. This uses a pointer table /// to avoid infinite recursion due to cyclic references /// diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h index f1b9dc3bc8..f3ecdaacc4 100644 --- a/src/nvim/api/private/helpers.h +++ b/src/nvim/api/private/helpers.h @@ -51,36 +51,11 @@ .data.array = a \ }) -#define STRINGARRAY_OBJ(a) ((Object) { \ - .type = kObjectTypeStringArray, \ - .data.stringarray = a \ - }) - -#define BUFFERARRAY_OBJ(a) ((Object) { \ - .type = kObjectTypeBufferArray, \ - .data.bufferarray = a \ - }) - -#define WINDOWARRAY_OBJ(a) ((Object) { \ - .type = kObjectTypeWindowArray, \ - .data.windowarray = a \ - }) - -#define TABPAGEARRAY_OBJ(a) ((Object) { \ - .type = kObjectTypeTabpageArray, \ - .data.tabpagearray = a \ - }) - #define DICTIONARY_OBJ(d) ((Object) { \ .type = kObjectTypeDictionary, \ .data.dictionary = d \ }) -#define POSITION_OBJ(p) ((Object) { \ - .type = kObjectTypePosition, \ - .data.position = p \ - }) - #define NIL ((Object) {.type = kObjectTypeNil}) #define PUT(dict, k, v) \ @@ -91,6 +66,25 @@ #define ADD(array, item) \ kv_push(Object, array, item) +// Helpers used by the generated msgpack-rpc api wrappers +#define api_init_boolean +#define api_init_integer +#define api_init_float +#define api_init_string = STRING_INIT +#define api_init_buffer +#define api_init_window +#define api_init_tabpage +#define api_init_object = NIL +#define api_init_array = ARRAY_DICT_INIT +#define api_init_dictionary = ARRAY_DICT_INIT + +#define api_free_boolean(value) +#define api_free_integer(value) +#define api_free_float(value) +#define api_free_buffer(value) +#define api_free_window(value) +#define api_free_tabpage(value) + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "api/private/helpers.h.generated.h" #endif -- cgit From a1ce3a3acc9f5e617e9d7e9542d58953d2e9546f Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Wed, 10 Sep 2014 10:11:45 -0300 Subject: provider: Major refactor - Providers for features are now registered as a unit. For example, instead of calling `register_provider("clipboard_get")` and `register_provider("clipboard_set")`, clients call `register_provider("clipboard")` and nvim will assume it implements all methods of the "clipboard" feature - Bootstrapping code was removed. With the `api_spawn` function exposed to vimscript, it's no longer necessary and will be handled by plugins distributed with nvim. - Now the `has` function will return true if there's a live channel that has registered as a provider for the feature. - 'initpython'/'initclipboard' options were removed - A new API function was exposed: `vim_discover_features` which returns an object with information about pluggable features such as 'python' or 'clipboard' --- src/nvim/api/vim.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index b1d5a067b4..e14c427dc1 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -502,22 +502,28 @@ void vim_unsubscribe(uint64_t channel_id, String event) channel_unsubscribe(channel_id, e); } -/// Registers the channel as the provider for `method`. This fails if -/// a provider for `method` is already registered. +/// Registers the channel as the provider for `feature`. This fails if +/// a provider for `feature` is already provided by another channel. /// /// @param channel_id The channel id -/// @param method The method name +/// @param feature The feature name /// @param[out] err Details of an error that may have occurred -void vim_register_provider(uint64_t channel_id, String method, Error *err) +void vim_register_provider(uint64_t channel_id, String feature, Error *err) { char buf[METHOD_MAXLEN]; - xstrlcpy(buf, method.data, sizeof(buf)); + xstrlcpy(buf, feature.data, sizeof(buf)); if (!provider_register(buf, channel_id)) { - set_api_error("Provider already registered", err); + set_api_error("Feature doesn't exist", err); } } +/// Returns a feature->method list dictionary for all pluggable features +Dictionary vim_discover_features(void) +{ + return provider_get_all(); +} + /// Writes a message to vim output or error buffer. The string is split /// and flushed after each newline. Incomplete lines are kept for writing /// later. -- cgit From d29b62daabd88e3c7ee9a979f4feae5612e3fbaf Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Thu, 11 Sep 2014 10:34:51 -0300 Subject: api: initialize capacity in the array_dict_macro --- src/nvim/api/private/defs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/private/defs.h b/src/nvim/api/private/defs.h index 11800ed786..bae1819172 100644 --- a/src/nvim/api/private/defs.h +++ b/src/nvim/api/private/defs.h @@ -5,7 +5,7 @@ #include #include -#define ARRAY_DICT_INIT {.size = 0, .items = NULL} +#define ARRAY_DICT_INIT {.size = 0, .capacity = 0, .items = NULL} #define STRING_INIT {.data = NULL, .size = 0} #define OBJECT_INIT { .type = kObjectTypeNil } #define REMOTE_TYPE(type) typedef uint64_t type -- cgit From 15ca58d79f8cc8565c1a2b2581029cf7901b5fbd Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Thu, 11 Sep 2014 10:35:52 -0300 Subject: api: Implement `vim_report_error` function This function is used to report errors caused by remote functions called by channel_send_call --- src/nvim/api/vim.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src/nvim/api') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index e14c427dc1..25454761ea 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -308,6 +308,16 @@ void vim_err_write(String str) write_msg(str, true); } +/// Higher level error reporting function that ensures all str contents +/// are written by sending a trailing linefeed to `vim_wrr_write` +/// +/// @param str The message +void vim_report_error(String str) +{ + vim_err_write(str); + vim_err_write((String) {.data = "\n", .size = 1}); +} + /// Gets the current list of buffer handles /// /// @return The number of buffers -- cgit From cd2e46c0785d40b9ea15f6d722a3fad54c007b9b Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Thu, 11 Sep 2014 21:56:52 -0300 Subject: api/msgpack-rpc: Refactor metadata object construction Instead of building all metadata from msgpack-gen.lua, we now merge the generated part with manual information(such as types and features). The metadata is accessible through the api method `vim_get_api_info`. This was done to simplify the generator while also increasing flexibility(by being able to add more metadata) --- src/nvim/api/private/defs.h | 4 --- src/nvim/api/private/helpers.c | 67 ++++++++++++++++++++++++++++++++++++++++++ src/nvim/api/vim.c | 11 +++++-- 3 files changed, 75 insertions(+), 7 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/private/defs.h b/src/nvim/api/private/defs.h index bae1819172..cf559a372e 100644 --- a/src/nvim/api/private/defs.h +++ b/src/nvim/api/private/defs.h @@ -44,13 +44,9 @@ typedef struct { } Dictionary; typedef enum { -// The following comments are markers that msgpack-gen.lua uses to extract -// types, don't remove! -// start custom types kObjectTypeBuffer, kObjectTypeWindow, kObjectTypeTabpage, -// end custom types kObjectTypeNil, kObjectTypeBoolean, kObjectTypeInteger, diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index de23481813..14a820aa1b 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -6,6 +6,7 @@ #include "nvim/api/private/helpers.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/handle.h" +#include "nvim/os/provider.h" #include "nvim/ascii.h" #include "nvim/vim.h" #include "nvim/buffer.h" @@ -506,6 +507,72 @@ void api_free_dictionary(Dictionary value) free(value.items); } +Dictionary api_metadata(void) +{ + static Dictionary metadata = ARRAY_DICT_INIT; + + if (!metadata.size) { + msgpack_rpc_init_function_metadata(&metadata); + init_type_metadata(&metadata); + provider_init_feature_metadata(&metadata); + } + + return copy_object(DICTIONARY_OBJ(metadata)).data.dictionary; +} + +static void init_type_metadata(Dictionary *metadata) +{ + Dictionary types = ARRAY_DICT_INIT; + + Dictionary buffer_metadata = ARRAY_DICT_INIT; + PUT(buffer_metadata, "id", INTEGER_OBJ(kObjectTypeBuffer)); + + Dictionary window_metadata = ARRAY_DICT_INIT; + PUT(window_metadata, "id", INTEGER_OBJ(kObjectTypeWindow)); + + Dictionary tabpage_metadata = ARRAY_DICT_INIT; + PUT(tabpage_metadata, "id", INTEGER_OBJ(kObjectTypeTabpage)); + + PUT(types, "Buffer", DICTIONARY_OBJ(buffer_metadata)); + PUT(types, "Window", DICTIONARY_OBJ(window_metadata)); + PUT(types, "Tabpage", DICTIONARY_OBJ(tabpage_metadata)); + + PUT(*metadata, "types", DICTIONARY_OBJ(types)); +} + +/// Creates a deep clone of an object +static Object copy_object(Object obj) +{ + switch (obj.type) { + case kObjectTypeNil: + case kObjectTypeBoolean: + case kObjectTypeInteger: + case kObjectTypeFloat: + return obj; + + case kObjectTypeString: + return STRING_OBJ(cstr_to_string(obj.data.string.data)); + + case kObjectTypeArray: { + Array rv = ARRAY_DICT_INIT; + for (size_t i = 0; i < obj.data.array.size; i++) { + ADD(rv, copy_object(obj.data.array.items[i])); + } + return ARRAY_OBJ(rv); + } + + case kObjectTypeDictionary: { + Dictionary rv = ARRAY_DICT_INIT; + for (size_t i = 0; i < obj.data.dictionary.size; i++) { + KeyValuePair item = obj.data.dictionary.items[i]; + PUT(rv, item.key.data, copy_object(item.value)); + } + return DICTIONARY_OBJ(rv); + } + default: + abort(); + } +} /// Recursion helper for the `vim_to_object`. This uses a pointer table /// to avoid infinite recursion due to cyclic references diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 25454761ea..c0a9fe3410 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -528,10 +528,15 @@ void vim_register_provider(uint64_t channel_id, String feature, Error *err) } } -/// Returns a feature->method list dictionary for all pluggable features -Dictionary vim_discover_features(void) +Array vim_get_api_info(uint64_t channel_id) { - return provider_get_all(); + Array rv = ARRAY_DICT_INIT; + + assert(channel_id <= INT64_MAX); + ADD(rv, INTEGER_OBJ((int64_t)channel_id)); + ADD(rv, DICTIONARY_OBJ(api_metadata())); + + return rv; } /// Writes a message to vim output or error buffer. The string is split -- cgit From 545acf2024ea2653ae6937d570a37aa0340caa5e Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Fri, 12 Sep 2014 11:24:01 -0300 Subject: api metadata: Allow typed container information in api functions Adapt gendeclarations.lua/msgpack-gen.lua to allow the `ArrayOf(...)` and `DictionaryOf(...)` types in function headers. These are simple macros that expand to Array and Dictionary respectively, but the information is kept in the metadata object, which is useful for building clients in statically typed languages. --- src/nvim/api/buffer.c | 21 ++++++++++++--------- src/nvim/api/private/defs.h | 5 +++++ src/nvim/api/tabpage.c | 2 +- src/nvim/api/vim.c | 8 ++++---- src/nvim/api/window.c | 6 +++--- 5 files changed, 25 insertions(+), 17 deletions(-) (limited to 'src/nvim/api') diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 383e13fd92..8355bfe868 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -95,12 +95,12 @@ void buffer_del_line(Buffer buffer, Integer index, Error *err) /// @param include_end True if the slice includes the `end` parameter /// @param[out] err Details of an error that may have occurred /// @return An array of lines -Array buffer_get_slice(Buffer buffer, - Integer start, - Integer end, - Boolean include_start, - Boolean include_end, - Error *err) +ArrayOf(String) buffer_get_slice(Buffer buffer, + Integer start, + Integer end, + Boolean include_start, + Boolean include_end, + Error *err) { Array rv = ARRAY_DICT_INIT; buf_T *buf = find_buffer_by_handle(buffer, err); @@ -161,7 +161,7 @@ void buffer_set_slice(Buffer buffer, Integer end, Boolean include_start, Boolean include_end, - Array replacement, + ArrayOf(String) replacement, Error *err) { buf_T *buf = find_buffer_by_handle(buffer, err); @@ -436,7 +436,10 @@ Boolean buffer_is_valid(Buffer buffer) /// to the end of the buffer. /// @param lines An array of lines /// @param[out] err Details of an error that may have occurred -void buffer_insert(Buffer buffer, Integer lnum, Array lines, Error *err) +void buffer_insert(Buffer buffer, + Integer lnum, + ArrayOf(String) lines, + Error *err) { buffer_set_slice(buffer, lnum, lnum, false, true, lines, err); } @@ -447,7 +450,7 @@ void buffer_insert(Buffer buffer, Integer lnum, Array lines, Error *err) /// @param name The mark's name /// @param[out] err Details of an error that may have occurred /// @return The (row, col) tuple -Array buffer_get_mark(Buffer buffer, String name, Error *err) +ArrayOf(Integer, 2) buffer_get_mark(Buffer buffer, String name, Error *err) { Array rv = ARRAY_DICT_INIT; buf_T *buf = find_buffer_by_handle(buffer, err); diff --git a/src/nvim/api/private/defs.h b/src/nvim/api/private/defs.h index cf559a372e..2dd229ec5f 100644 --- a/src/nvim/api/private/defs.h +++ b/src/nvim/api/private/defs.h @@ -10,6 +10,11 @@ #define OBJECT_INIT { .type = kObjectTypeNil } #define REMOTE_TYPE(type) typedef uint64_t type +#ifdef INCLUDE_GENERATED_DECLARATIONS + #define ArrayOf(...) Array + #define DictionaryOf(...) Dictionary +#endif + // Basic types typedef struct { char msg[256]; diff --git a/src/nvim/api/tabpage.c b/src/nvim/api/tabpage.c index 901f9a6c1a..91020d6850 100644 --- a/src/nvim/api/tabpage.c +++ b/src/nvim/api/tabpage.c @@ -13,7 +13,7 @@ /// @param tabpage The tabpage /// @param[out] err Details of an error that may have occurred /// @return The number of windows in `tabpage` -Array tabpage_get_windows(Tabpage tabpage, Error *err) +ArrayOf(Window) tabpage_get_windows(Tabpage tabpage, Error *err) { Array rv = ARRAY_DICT_INIT; tabpage_T *tab = find_tab_by_handle(tabpage, err); diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index c0a9fe3410..43f2aafdc8 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -149,7 +149,7 @@ Integer vim_strwidth(String str, Error *err) /// Returns a list of paths contained in 'runtimepath' /// /// @return The list of paths -Array vim_list_runtime_paths(void) +ArrayOf(String) vim_list_runtime_paths(void) { Array rv = ARRAY_DICT_INIT; uint8_t *rtp = p_rtp; @@ -321,7 +321,7 @@ void vim_report_error(String str) /// Gets the current list of buffer handles /// /// @return The number of buffers -Array vim_get_buffers(void) +ArrayOf(Buffer) vim_get_buffers(void) { Array rv = ARRAY_DICT_INIT; buf_T *b = firstbuf; @@ -381,7 +381,7 @@ void vim_set_current_buffer(Buffer buffer, Error *err) /// Gets the current list of window handles /// /// @return The number of windows -Array vim_get_windows(void) +ArrayOf(Window) vim_get_windows(void) { Array rv = ARRAY_DICT_INIT; tabpage_T *tp; @@ -437,7 +437,7 @@ void vim_set_current_window(Window window, Error *err) /// Gets the current list of tabpage handles /// /// @return The number of tab pages -Array vim_get_tabpages(void) +ArrayOf(Tabpage) vim_get_tabpages(void) { Array rv = ARRAY_DICT_INIT; tabpage_T *tp = first_tabpage; diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index 967d8acda4..dd256f2b6d 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -33,7 +33,7 @@ Buffer window_get_buffer(Window window, Error *err) /// @param window The window handle /// @param[out] err Details of an error that may have occurred /// @return the (row, col) tuple -Array window_get_cursor(Window window, Error *err) +ArrayOf(Integer, 2) window_get_cursor(Window window, Error *err) { Array rv = ARRAY_DICT_INIT; win_T *win = find_window_by_handle(window, err); @@ -51,7 +51,7 @@ Array window_get_cursor(Window window, Error *err) /// @param window The window handle /// @param pos the (row, col) tuple representing the new position /// @param[out] err Details of an error that may have occurred -void window_set_cursor(Window window, Array pos, Error *err) +void window_set_cursor(Window window, ArrayOf(Integer, 2) pos, Error *err) { win_T *win = find_window_by_handle(window, err); @@ -247,7 +247,7 @@ void window_set_option(Window window, String name, Object value, Error *err) /// @param window The window handle /// @param[out] err Details of an error that may have occurred /// @return The (row, col) tuple with the window position -Array window_get_position(Window window, Error *err) +ArrayOf(Integer, 2) window_get_position(Window window, Error *err) { Array rv = ARRAY_DICT_INIT; win_T *win = find_window_by_handle(window, err); -- cgit