helpers.h (5737B)
1 #pragma once 2 3 #include <stdbool.h> 4 #include <stddef.h> // IWYU pragma: keep 5 6 #include "klib/kvec.h" 7 #include "nvim/api/private/defs.h" // IWYU pragma: keep 8 #include "nvim/buffer_defs.h" // IWYU pragma: keep 9 #include "nvim/eval/typval_defs.h" // IWYU pragma: keep 10 #include "nvim/ex_eval_defs.h" 11 #include "nvim/macros_defs.h" 12 #include "nvim/map_defs.h" 13 #include "nvim/message_defs.h" // IWYU pragma: keep 14 15 #define OBJECT_OBJ(o) o 16 17 #define BOOLEAN_OBJ(b) ((Object) { \ 18 .type = kObjectTypeBoolean, \ 19 .data.boolean = b }) 20 21 #define INTEGER_OBJ(i) ((Object) { \ 22 .type = kObjectTypeInteger, \ 23 .data.integer = i }) 24 25 #define FLOAT_OBJ(f) ((Object) { \ 26 .type = kObjectTypeFloat, \ 27 .data.floating = f }) 28 29 #define STRING_OBJ(s) ((Object) { \ 30 .type = kObjectTypeString, \ 31 .data.string = s }) 32 33 #define CSTR_AS_OBJ(s) STRING_OBJ(cstr_as_string(s)) 34 #define CSTR_TO_OBJ(s) STRING_OBJ(cstr_to_string(s)) 35 #define CSTR_TO_ARENA_STR(arena, s) arena_string(arena, cstr_as_string(s)) 36 #define CSTR_TO_ARENA_OBJ(arena, s) STRING_OBJ(CSTR_TO_ARENA_STR(arena, s)) 37 #define CBUF_TO_ARENA_STR(arena, s, len) arena_string(arena, cbuf_as_string((char *)(s), len)) 38 #define CBUF_TO_ARENA_OBJ(arena, s, len) STRING_OBJ(CBUF_TO_ARENA_STR(arena, s, len)) 39 40 #define BUFFER_OBJ(s) ((Object) { \ 41 .type = kObjectTypeBuffer, \ 42 .data.integer = s }) 43 44 #define WINDOW_OBJ(s) ((Object) { \ 45 .type = kObjectTypeWindow, \ 46 .data.integer = s }) 47 48 #define TABPAGE_OBJ(s) ((Object) { \ 49 .type = kObjectTypeTabpage, \ 50 .data.integer = s }) 51 52 #define ARRAY_OBJ(a) ((Object) { \ 53 .type = kObjectTypeArray, \ 54 .data.array = a }) 55 56 #define DICT_OBJ(d) ((Object) { \ 57 .type = kObjectTypeDict, \ 58 .data.dict = d }) 59 60 #define LUAREF_OBJ(r) ((Object) { \ 61 .type = kObjectTypeLuaRef, \ 62 .data.luaref = r }) 63 64 #define NIL ((Object)OBJECT_INIT) 65 #define NULL_STRING ((String)STRING_INIT) 66 67 #define HAS_KEY(d, typ, key) (((d)->is_set__##typ##_ & (1ULL << KEYSET_OPTIDX_##typ##__##key)) != 0) 68 69 #define GET_BOOL_OR_TRUE(d, typ, key) (HAS_KEY(d, typ, key) ? (d)->key : true) 70 71 #define PUT(dict, k, v) \ 72 kv_push(dict, ((KeyValuePair) { .key = cstr_to_string(k), .value = v })) 73 74 #define PUT_C(dict, k, v) \ 75 kv_push_c(dict, ((KeyValuePair) { .key = cstr_as_string(k), .value = v })) 76 77 #define PUT_KEY(d, typ, key, v) \ 78 do { (d).is_set__##typ##_ |= (1ULL << KEYSET_OPTIDX_##typ##__##key); (d).key = v; } while (0) 79 80 #define ADD(array, item) \ 81 kv_push(array, item) 82 83 #define ADD_C(array, item) \ 84 kv_push_c(array, item) 85 86 #define MAXSIZE_TEMP_ARRAY(name, maxsize) \ 87 Array name = ARRAY_DICT_INIT; \ 88 Object name##__items[maxsize]; \ 89 name.capacity = maxsize; \ 90 name.items = name##__items; \ 91 92 #define MAXSIZE_TEMP_DICT(name, maxsize) \ 93 Dict name = ARRAY_DICT_INIT; \ 94 KeyValuePair name##__items[maxsize]; \ 95 name.capacity = maxsize; \ 96 name.items = name##__items; \ 97 98 typedef kvec_withinit_t(Object, 16) ArrayBuilder; 99 100 #define cbuf_as_string(d, s) ((String) { .data = d, .size = s }) 101 102 #define STATIC_CSTR_AS_STRING(s) ((String) { .data = s, .size = sizeof("" s) - 1 }) 103 104 /// Create a new String instance, putting data in allocated memory 105 /// 106 /// @param[in] s String to work with. Must be a string literal. 107 #define STATIC_CSTR_TO_STRING(s) ((String){ \ 108 .data = xmemdupz(s, sizeof(s) - 1), \ 109 .size = sizeof(s) - 1 }) 110 111 #define STATIC_CSTR_AS_OBJ(s) STRING_OBJ(STATIC_CSTR_AS_STRING(s)) 112 #define STATIC_CSTR_TO_OBJ(s) STRING_OBJ(STATIC_CSTR_TO_STRING(s)) 113 114 #define API_CLEAR_STRING(s) \ 115 do { \ 116 XFREE_CLEAR(s.data); \ 117 s.size = 0; \ 118 } while (0) 119 120 // Helpers used by the generated msgpack-rpc api wrappers 121 #define api_init_boolean 122 #define api_init_integer 123 #define api_init_float 124 #define api_init_string = STRING_INIT 125 #define api_init_buffer 126 #define api_init_window 127 #define api_init_tabpage 128 #define api_init_object = NIL 129 #define api_init_array = ARRAY_DICT_INIT 130 #define api_init_dict = ARRAY_DICT_INIT 131 132 #define KEYDICT_INIT { 0 } 133 134 EXTERN PMap(int) buffer_handles INIT( = MAP_INIT); 135 EXTERN PMap(int) window_handles INIT( = MAP_INIT); 136 EXTERN PMap(int) tabpage_handles INIT( = MAP_INIT); 137 138 #define handle_get_buffer(h) pmap_get(int)(&buffer_handles, (h)) 139 #define handle_get_window(h) pmap_get(int)(&window_handles, (h)) 140 #define handle_get_tabpage(h) pmap_get(int)(&tabpage_handles, (h)) 141 142 /// Structure used for saving state for :try 143 /// 144 /// Used when caller is supposed to be operating when other Vimscript code is being 145 /// processed and that “other Vimscript code” must not be affected. 146 typedef struct { 147 except_T *current_exception; 148 msglist_T *private_msg_list; 149 const msglist_T *const *msg_list; 150 int got_int; 151 bool did_throw; 152 int need_rethrow; 153 int did_emsg; 154 } TryState; 155 156 // TODO(bfredl): prepare error-handling at "top level" (nv_event). 157 #define TRY_WRAP(err, code) \ 158 do { \ 159 TryState tstate; \ 160 try_enter(&tstate); \ 161 code; \ 162 try_leave(&tstate, err); \ 163 } while (0) 164 165 // Execute code with cursor position saved and restored and textlock active. 166 #define TEXTLOCK_WRAP(code) \ 167 do { \ 168 const pos_T save_cursor = curwin->w_cursor; \ 169 textlock++; \ 170 code; \ 171 textlock--; \ 172 curwin->w_cursor = save_cursor; \ 173 } while (0) 174 175 // Useful macro for executing some `code` for each item in an array. 176 #define FOREACH_ITEM(a, __foreach_item, code) \ 177 for (size_t (__foreach_item##_index) = 0; (__foreach_item##_index) < (a).size; \ 178 (__foreach_item##_index)++) { \ 179 Object __foreach_item = (a).items[__foreach_item##_index]; \ 180 code; \ 181 } 182 183 #include "api/private/helpers.h.generated.h" 184 185 #define WITH_SCRIPT_CONTEXT(channel_id, code) \ 186 do { \ 187 const sctx_T save_current_sctx = api_set_sctx(channel_id); \ 188 code; \ 189 current_sctx = save_current_sctx; \ 190 } while (0);