mirror of
https://github.com/neovim/neovim.git
synced 2025-09-12 14:28:18 +00:00

As only a few API functions make use of explicit freeing of the return value, make it opt-in instead. The arena is always present under the hood, so `Arena *arena` arg now doesn't mean anything other than getting access to this arena. Also it is in principle possible to return an allocated value while still using the arena as scratch space for other stuff (unlikely, but there no reason to not allow it).
201 lines
6.1 KiB
C++
201 lines
6.1 KiB
C++
#pragma once
|
|
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
|
|
#include "klib/kvec.h"
|
|
#include "nvim/api/private/defs.h" // IWYU pragma: keep
|
|
#include "nvim/buffer_defs.h" // IWYU pragma: keep
|
|
#include "nvim/eval/typval_defs.h" // IWYU pragma: keep
|
|
#include "nvim/ex_eval_defs.h"
|
|
#include "nvim/macros_defs.h"
|
|
#include "nvim/map_defs.h"
|
|
#include "nvim/message_defs.h" // IWYU pragma: keep
|
|
|
|
#define OBJECT_OBJ(o) o
|
|
|
|
#define BOOLEAN_OBJ(b) ((Object) { \
|
|
.type = kObjectTypeBoolean, \
|
|
.data.boolean = b })
|
|
|
|
#define INTEGER_OBJ(i) ((Object) { \
|
|
.type = kObjectTypeInteger, \
|
|
.data.integer = i })
|
|
|
|
#define FLOAT_OBJ(f) ((Object) { \
|
|
.type = kObjectTypeFloat, \
|
|
.data.floating = f })
|
|
|
|
#define STRING_OBJ(s) ((Object) { \
|
|
.type = kObjectTypeString, \
|
|
.data.string = s })
|
|
|
|
#define CSTR_AS_OBJ(s) STRING_OBJ(cstr_as_string(s))
|
|
#define CSTR_TO_OBJ(s) STRING_OBJ(cstr_to_string(s))
|
|
#define CSTR_TO_ARENA_STR(arena, s) arena_string(arena, cstr_as_string(s))
|
|
#define CSTR_TO_ARENA_OBJ(arena, s) STRING_OBJ(CSTR_TO_ARENA_STR(arena, s))
|
|
#define CBUF_TO_ARENA_STR(arena, s, len) arena_string(arena, cbuf_as_string((char *)(s), len))
|
|
#define CBUF_TO_ARENA_OBJ(arena, s, len) STRING_OBJ(CBUF_TO_ARENA_STR(arena, s, len))
|
|
|
|
#define BUFFER_OBJ(s) ((Object) { \
|
|
.type = kObjectTypeBuffer, \
|
|
.data.integer = s })
|
|
|
|
#define WINDOW_OBJ(s) ((Object) { \
|
|
.type = kObjectTypeWindow, \
|
|
.data.integer = s })
|
|
|
|
#define TABPAGE_OBJ(s) ((Object) { \
|
|
.type = kObjectTypeTabpage, \
|
|
.data.integer = s })
|
|
|
|
#define ARRAY_OBJ(a) ((Object) { \
|
|
.type = kObjectTypeArray, \
|
|
.data.array = a })
|
|
|
|
#define DICTIONARY_OBJ(d) ((Object) { \
|
|
.type = kObjectTypeDictionary, \
|
|
.data.dictionary = d })
|
|
|
|
#define LUAREF_OBJ(r) ((Object) { \
|
|
.type = kObjectTypeLuaRef, \
|
|
.data.luaref = r })
|
|
|
|
#define NIL ((Object)OBJECT_INIT)
|
|
#define NULL_STRING ((String)STRING_INIT)
|
|
|
|
#define HAS_KEY(d, typ, key) (((d)->is_set__##typ##_ & (1 << KEYSET_OPTIDX_##typ##__##key)) != 0)
|
|
|
|
#define GET_BOOL_OR_TRUE(d, typ, key) (HAS_KEY(d, typ, key) ? (d)->key : true)
|
|
|
|
#define PUT(dict, k, v) \
|
|
kv_push(dict, ((KeyValuePair) { .key = cstr_to_string(k), .value = v }))
|
|
|
|
#define PUT_C(dict, k, v) \
|
|
kv_push_c(dict, ((KeyValuePair) { .key = cstr_as_string(k), .value = v }))
|
|
|
|
#define PUT_KEY(d, typ, key, v) \
|
|
do { (d).is_set__##typ##_ |= (1 << KEYSET_OPTIDX_##typ##__##key); (d).key = v; } while (0)
|
|
|
|
#define ADD(array, item) \
|
|
kv_push(array, item)
|
|
|
|
#define ADD_C(array, item) \
|
|
kv_push_c(array, item)
|
|
|
|
#define MAXSIZE_TEMP_ARRAY(name, maxsize) \
|
|
Array name = ARRAY_DICT_INIT; \
|
|
Object name##__items[maxsize]; \
|
|
name.capacity = maxsize; \
|
|
name.items = name##__items; \
|
|
|
|
#define MAXSIZE_TEMP_DICT(name, maxsize) \
|
|
Dictionary name = ARRAY_DICT_INIT; \
|
|
KeyValuePair name##__items[maxsize]; \
|
|
name.capacity = maxsize; \
|
|
name.items = name##__items; \
|
|
|
|
typedef kvec_withinit_t(Object, 16) ArrayBuilder;
|
|
|
|
#define cbuf_as_string(d, s) ((String) { .data = d, .size = s })
|
|
|
|
#define STATIC_CSTR_AS_STRING(s) ((String) { .data = s, .size = sizeof("" s) - 1 })
|
|
|
|
/// Create a new String instance, putting data in allocated memory
|
|
///
|
|
/// @param[in] s String to work with. Must be a string literal.
|
|
#define STATIC_CSTR_TO_STRING(s) ((String){ \
|
|
.data = xmemdupz(s, sizeof(s) - 1), \
|
|
.size = sizeof(s) - 1 })
|
|
|
|
#define STATIC_CSTR_AS_OBJ(s) STRING_OBJ(STATIC_CSTR_AS_STRING(s))
|
|
#define STATIC_CSTR_TO_OBJ(s) STRING_OBJ(STATIC_CSTR_TO_STRING(s))
|
|
|
|
// 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 KEYDICT_INIT { 0 }
|
|
|
|
EXTERN PMap(int) buffer_handles INIT( = MAP_INIT);
|
|
EXTERN PMap(int) window_handles INIT( = MAP_INIT);
|
|
EXTERN PMap(int) tabpage_handles INIT( = MAP_INIT);
|
|
|
|
#define handle_get_buffer(h) pmap_get(int)(&buffer_handles, (h))
|
|
#define handle_get_window(h) pmap_get(int)(&window_handles, (h))
|
|
#define handle_get_tabpage(h) pmap_get(int)(&tabpage_handles, (h))
|
|
|
|
/// Structure used for saving state for :try
|
|
///
|
|
/// Used when caller is supposed to be operating when other Vimscript code is being
|
|
/// processed and that “other Vimscript code” must not be affected.
|
|
typedef struct {
|
|
except_T *current_exception;
|
|
msglist_T *private_msg_list;
|
|
const msglist_T *const *msg_list;
|
|
int trylevel;
|
|
int got_int;
|
|
bool did_throw;
|
|
int need_rethrow;
|
|
int did_emsg;
|
|
} TryState;
|
|
|
|
// `msg_list` controls the collection of abort-causing non-exception errors,
|
|
// which would otherwise be ignored. This pattern is from do_cmdline().
|
|
//
|
|
// TODO(bfredl): prepare error-handling at "top level" (nv_event).
|
|
#define TRY_WRAP(err, code) \
|
|
do { \
|
|
msglist_T **saved_msg_list = msg_list; \
|
|
msglist_T *private_msg_list; \
|
|
msg_list = &private_msg_list; \
|
|
private_msg_list = NULL; \
|
|
try_start(); \
|
|
code; \
|
|
try_end(err); \
|
|
msg_list = saved_msg_list; /* Restore the exception context. */ \
|
|
} while (0)
|
|
|
|
// Execute code with cursor position saved and restored and textlock active.
|
|
#define TEXTLOCK_WRAP(code) \
|
|
do { \
|
|
const pos_T save_cursor = curwin->w_cursor; \
|
|
textlock++; \
|
|
code; \
|
|
textlock--; \
|
|
curwin->w_cursor = save_cursor; \
|
|
} while (0)
|
|
|
|
// Useful macro for executing some `code` for each item in an array.
|
|
#define FOREACH_ITEM(a, __foreach_item, code) \
|
|
for (size_t (__foreach_item##_index) = 0; (__foreach_item##_index) < (a).size; \
|
|
(__foreach_item##_index)++) { \
|
|
Object __foreach_item = (a).items[__foreach_item##_index]; \
|
|
code; \
|
|
}
|
|
|
|
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
|
# include "api/private/helpers.h.generated.h"
|
|
#endif
|
|
|
|
#define WITH_SCRIPT_CONTEXT(channel_id, code) \
|
|
do { \
|
|
const sctx_T save_current_sctx = current_sctx; \
|
|
const uint64_t save_channel_id = current_channel_id; \
|
|
current_sctx.sc_sid = \
|
|
(channel_id) == LUA_INTERNAL_CALL ? SID_LUA : SID_API_CLIENT; \
|
|
current_sctx.sc_lnum = 0; \
|
|
current_channel_id = channel_id; \
|
|
code; \
|
|
current_channel_id = save_channel_id; \
|
|
current_sctx = save_current_sctx; \
|
|
} while (0);
|