Merge pull request #27534 from bfredl/userarena

refactor(api): next PR to make use of the arena
This commit is contained in:
bfredl 2024-02-19 21:21:05 +01:00 committed by GitHub
commit 8952a89db5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 107 additions and 109 deletions

View File

@ -1166,10 +1166,10 @@ err:
/// @param[out] err Error details, if any.
///
/// @returns Map of maps describing commands.
Dictionary nvim_get_commands(Dict(get_commands) *opts, Error *err)
Dictionary nvim_get_commands(Dict(get_commands) *opts, Arena *arena, Error *err)
FUNC_API_SINCE(4)
{
return nvim_buf_get_commands(-1, opts, err);
return nvim_buf_get_commands(-1, opts, arena, err);
}
/// Gets a map of buffer-local |user-commands|.
@ -1179,7 +1179,7 @@ Dictionary nvim_get_commands(Dict(get_commands) *opts, Error *err)
/// @param[out] err Error details, if any.
///
/// @returns Map of maps describing commands.
Dictionary nvim_buf_get_commands(Buffer buffer, Dict(get_commands) *opts, Error *err)
Dictionary nvim_buf_get_commands(Buffer buffer, Dict(get_commands) *opts, Arena *arena, Error *err)
FUNC_API_SINCE(4)
{
bool global = (buffer == -1);
@ -1192,12 +1192,12 @@ Dictionary nvim_buf_get_commands(Buffer buffer, Dict(get_commands) *opts, Error
api_set_error(err, kErrorTypeValidation, "builtin=true not implemented");
return (Dictionary)ARRAY_DICT_INIT;
}
return commands_array(NULL);
return commands_array(NULL, arena);
}
buf_T *buf = find_buffer_by_handle(buffer, err);
if (opts->builtin || !buf) {
return (Dictionary)ARRAY_DICT_INIT;
}
return commands_array(buf);
return commands_array(buf, arena);
}

View File

@ -456,9 +456,10 @@ String ga_take_string(garray_T *ga)
/// @param input Binary string
/// @param crlf Also break lines at CR and CRLF.
/// @return [allocated] String array
Array string_to_array(const String input, bool crlf)
Array string_to_array(const String input, bool crlf, Arena *arena)
{
Array ret = ARRAY_DICT_INIT;
ArrayBuilder ret = ARRAY_DICT_INIT;
kvi_init(ret);
for (size_t i = 0; i < input.size; i++) {
const char *start = input.data + i;
const char *end = start;
@ -473,20 +474,17 @@ Array string_to_array(const String input, bool crlf)
if (crlf && *end == CAR && i + 1 < input.size && *(end + 1) == NL) {
i += 1; // Advance past CRLF.
}
String s = {
.size = line_len,
.data = xmemdupz(start, line_len),
};
String s = CBUF_TO_ARENA_STR(arena, start, line_len);
memchrsub(s.data, NUL, NL, line_len);
ADD(ret, STRING_OBJ(s));
kvi_push(ret, STRING_OBJ(s));
// If line ends at end-of-buffer, add empty final item.
// This is "readfile()-style", see also ":help channel-lines".
if (i + 1 == input.size && (*end == NL || (crlf && *end == CAR))) {
ADD(ret, STRING_OBJ(STRING_INIT));
kvi_push(ret, STRING_OBJ(STRING_INIT));
}
}
return ret;
return arena_take_arraybuilder(arena, &ret);
}
/// Normalizes 0-based indexes to buffer line numbers.

View File

@ -19,7 +19,7 @@
/// @param tabpage Tabpage handle, or 0 for current tabpage
/// @param[out] err Error details, if any
/// @return List of windows in `tabpage`
ArrayOf(Window) nvim_tabpage_list_wins(Tabpage tabpage, Error *err)
ArrayOf(Window) nvim_tabpage_list_wins(Tabpage tabpage, Arena *arena, Error *err)
FUNC_API_SINCE(1)
{
Array rv = ARRAY_DICT_INIT;
@ -29,15 +29,15 @@ ArrayOf(Window) nvim_tabpage_list_wins(Tabpage tabpage, Error *err)
return rv;
}
size_t n = 0;
FOR_ALL_WINDOWS_IN_TAB(wp, tab) {
rv.size++;
n++;
}
rv.items = xmalloc(sizeof(Object) * rv.size);
size_t i = 0;
rv = arena_array(arena, n);
FOR_ALL_WINDOWS_IN_TAB(wp, tab) {
rv.items[i++] = WINDOW_OBJ(wp->handle);
ADD_C(rv, WINDOW_OBJ(wp->handle));
}
return rv;

View File

@ -543,17 +543,22 @@ Integer nvim_strwidth(String text, Error *err)
/// Gets the paths contained in |runtime-search-path|.
///
/// @return List of paths
ArrayOf(String) nvim_list_runtime_paths(Error *err)
ArrayOf(String) nvim_list_runtime_paths(Arena *arena, Error *err)
FUNC_API_SINCE(1)
{
return nvim_get_runtime_file(NULL_STRING, true, err);
return nvim_get_runtime_file(NULL_STRING, true, arena, err);
}
Array nvim__runtime_inspect(void)
Array nvim__runtime_inspect(Arena *arena)
{
return runtime_inspect();
return runtime_inspect(arena);
}
typedef struct {
ArrayBuilder rv;
Arena *arena;
} RuntimeCookie;
/// Find files in runtime directories
///
/// "name" can contain wildcards. For example
@ -566,25 +571,27 @@ Array nvim__runtime_inspect(void)
/// @param name pattern of files to search for
/// @param all whether to return all matches or only the first
/// @return list of absolute paths to the found files
ArrayOf(String) nvim_get_runtime_file(String name, Boolean all, Error *err)
ArrayOf(String) nvim_get_runtime_file(String name, Boolean all, Arena *arena, Error *err)
FUNC_API_SINCE(7)
FUNC_API_FAST
{
Array rv = ARRAY_DICT_INIT;
RuntimeCookie cookie = { .rv = ARRAY_DICT_INIT, .arena = arena, };
kvi_init(cookie.rv);
int flags = DIP_DIRFILE | (all ? DIP_ALL : 0);
TRY_WRAP(err, {
do_in_runtimepath((name.size ? name.data : ""), flags, find_runtime_cb, &rv);
do_in_runtimepath((name.size ? name.data : ""), flags, find_runtime_cb, &cookie);
});
return rv;
return arena_take_arraybuilder(arena, &cookie.rv);
}
static bool find_runtime_cb(int num_fnames, char **fnames, bool all, void *cookie)
static bool find_runtime_cb(int num_fnames, char **fnames, bool all, void *c)
{
Array *rv = (Array *)cookie;
RuntimeCookie *cookie = (RuntimeCookie *)c;
for (int i = 0; i < num_fnames; i++) {
ADD(*rv, CSTR_TO_OBJ(fnames[i]));
// TODO(bfredl): consider memory management of gen_expand_wildcards() itself
kvi_push(cookie->rv, CSTR_TO_ARENA_OBJ(cookie->arena, fnames[i]));
if (!all) {
return true;
}
@ -825,20 +832,19 @@ void nvim_err_writeln(String str)
/// Use |nvim_buf_is_loaded()| to check if a buffer is loaded.
///
/// @return List of buffer handles
ArrayOf(Buffer) nvim_list_bufs(void)
ArrayOf(Buffer) nvim_list_bufs(Arena *arena)
FUNC_API_SINCE(1)
{
Array rv = ARRAY_DICT_INIT;
size_t n = 0;
FOR_ALL_BUFFERS(b) {
rv.size++;
n++;
}
rv.items = xmalloc(sizeof(Object) * rv.size);
size_t i = 0;
Array rv = arena_array(arena, n);
FOR_ALL_BUFFERS(b) {
rv.items[i++] = BUFFER_OBJ(b->handle);
ADD_C(rv, BUFFER_OBJ(b->handle));
}
return rv;
@ -880,20 +886,19 @@ void nvim_set_current_buf(Buffer buffer, Error *err)
/// Gets the current list of window handles.
///
/// @return List of window handles
ArrayOf(Window) nvim_list_wins(void)
ArrayOf(Window) nvim_list_wins(Arena *arena)
FUNC_API_SINCE(1)
{
Array rv = ARRAY_DICT_INIT;
size_t n = 0;
FOR_ALL_TAB_WINDOWS(tp, wp) {
rv.size++;
n++;
}
rv.items = xmalloc(sizeof(Object) * rv.size);
size_t i = 0;
Array rv = arena_array(arena, n);
FOR_ALL_TAB_WINDOWS(tp, wp) {
rv.items[i++] = WINDOW_OBJ(wp->handle);
ADD_C(rv, WINDOW_OBJ(wp->handle));
}
return rv;
@ -1117,20 +1122,19 @@ void nvim_chan_send(Integer chan, String data, Error *err)
/// Gets the current list of tabpage handles.
///
/// @return List of tabpage handles
ArrayOf(Tabpage) nvim_list_tabpages(void)
ArrayOf(Tabpage) nvim_list_tabpages(Arena *arena)
FUNC_API_SINCE(1)
{
Array rv = ARRAY_DICT_INIT;
size_t n = 0;
FOR_ALL_TABS(tp) {
rv.size++;
n++;
}
rv.items = xmalloc(sizeof(Object) * rv.size);
size_t i = 0;
Array rv = arena_array(arena, n);
FOR_ALL_TABS(tp) {
rv.items[i++] = TABPAGE_OBJ(tp->handle);
ADD_C(rv, TABPAGE_OBJ(tp->handle));
}
return rv;
@ -1201,14 +1205,13 @@ Boolean nvim_paste(String data, Boolean crlf, Integer phase, Arena *arena, Error
VALIDATE_INT((phase >= -1 && phase <= 3), "phase", phase, {
return false;
});
Array lines = ARRAY_DICT_INIT;
if (phase == -1 || phase == 1) { // Start of paste-stream.
draining = false;
} else if (draining) {
// Skip remaining chunks. Report error only once per "stream".
goto theend;
}
lines = string_to_array(data, crlf);
Array lines = string_to_array(data, crlf, arena);
MAXSIZE_TEMP_ARRAY(args, 2);
ADD_C(args, ARRAY_OBJ(lines));
ADD_C(args, INTEGER_OBJ(phase));
@ -1239,7 +1242,6 @@ Boolean nvim_paste(String data, Boolean crlf, Integer phase, Arena *arena, Error
AppendCharToRedobuff(ESC); // Dot-repeat.
}
theend:
api_free_array(lines);
if (cancel || phase == -1 || phase == 3) { // End of paste-stream.
draining = false;
}
@ -1260,24 +1262,27 @@ theend:
/// @param after If true insert after cursor (like |p|), or before (like |P|).
/// @param follow If true place cursor at end of inserted text.
/// @param[out] err Error details, if any
void nvim_put(ArrayOf(String) lines, String type, Boolean after, Boolean follow, Error *err)
void nvim_put(ArrayOf(String) lines, String type, Boolean after, Boolean follow, Arena *arena,
Error *err)
FUNC_API_SINCE(6)
FUNC_API_TEXTLOCK_ALLOW_CMDWIN
{
yankreg_T *reg = xcalloc(1, sizeof(yankreg_T));
yankreg_T reg[1] = { 0 };
VALIDATE_S((prepare_yankreg_from_object(reg, type, lines.size)), "type", type.data, {
goto cleanup;
return;
});
if (lines.size == 0) {
goto cleanup; // Nothing to do.
return; // Nothing to do.
}
reg->y_array = arena_alloc(arena, lines.size * sizeof(uint8_t *), true);
reg->y_size = lines.size;
for (size_t i = 0; i < lines.size; i++) {
VALIDATE_T("line", kObjectTypeString, lines.items[i].type, {
goto cleanup;
return;
});
String line = lines.items[i].data.string;
reg->y_array[i] = xmemdupz(line.data, line.size);
reg->y_array[i] = arena_memdupz(arena, line.data, line.size);
memchrsub(reg->y_array[i], NUL, NL, line.size);
}
@ -1290,10 +1295,6 @@ void nvim_put(ArrayOf(String) lines, String type, Boolean after, Boolean follow,
msg_silent--;
VIsual_active = VIsual_was_active;
});
cleanup:
free_register(reg);
xfree(reg);
}
/// Subscribes to event broadcasts.
@ -1583,13 +1584,12 @@ Array nvim_get_api_info(uint64_t channel_id, Arena *arena)
///
/// @param[out] err Error details, if any
void nvim_set_client_info(uint64_t channel_id, String name, Dictionary version, String type,
Dictionary methods, Dictionary attributes, Error *err)
Dictionary methods, Dictionary attributes, Arena *arena, Error *err)
FUNC_API_SINCE(4) FUNC_API_REMOTE_ONLY
{
Dictionary info = ARRAY_DICT_INIT;
PUT(info, "name", copy_object(STRING_OBJ(name), NULL));
MAXSIZE_TEMP_DICT(info, 5);
PUT_C(info, "name", STRING_OBJ(name));
version = copy_dictionary(version, NULL);
bool has_major = false;
for (size_t i = 0; i < version.size; i++) {
if (strequal(version.items[i].key.data, "major")) {
@ -1598,15 +1598,21 @@ void nvim_set_client_info(uint64_t channel_id, String name, Dictionary version,
}
}
if (!has_major) {
PUT(version, "major", INTEGER_OBJ(0));
Dictionary v = arena_dict(arena, version.size + 1);
if (version.size) {
memcpy(v.items, version.items, version.size * sizeof(v.items[0]));
v.size = version.size;
}
PUT_C(v, "major", INTEGER_OBJ(0));
version = v;
}
PUT(info, "version", DICTIONARY_OBJ(version));
PUT_C(info, "version", DICTIONARY_OBJ(version));
PUT(info, "type", copy_object(STRING_OBJ(type), NULL));
PUT(info, "methods", DICTIONARY_OBJ(copy_dictionary(methods, NULL)));
PUT(info, "attributes", DICTIONARY_OBJ(copy_dictionary(attributes, NULL)));
PUT_C(info, "type", STRING_OBJ(type));
PUT_C(info, "methods", DICTIONARY_OBJ(methods));
PUT_C(info, "attributes", DICTIONARY_OBJ(attributes));
rpc_set_client_info(channel_id, info);
rpc_set_client_info(channel_id, copy_dictionary(info, NULL));
}
/// Gets information about a channel.

View File

@ -6499,8 +6499,6 @@ bool prepare_yankreg_from_object(yankreg_T *reg, String regtype, size_t lines)
}
}
reg->y_array = xcalloc(lines, sizeof(uint8_t *));
reg->y_size = lines;
reg->additional_data = NULL;
reg->timestamp = 0;
return true;
@ -6513,7 +6511,6 @@ void finish_yankreg_from_object(yankreg_T *reg, bool clipboard_adjust)
// but otherwise there is no line after the final newline
if (reg->y_type != kMTCharWise) {
if (reg->y_type == kMTUnknown || clipboard_adjust) {
xfree(reg->y_array[reg->y_size - 1]);
reg->y_size--;
}
if (reg->y_type == kMTUnknown) {

View File

@ -574,20 +574,20 @@ static int do_in_cached_path(char *name, int flags, DoInRuntimepathCB callback,
return did_one ? OK : FAIL;
}
Array runtime_inspect(void)
Array runtime_inspect(Arena *arena)
{
RuntimeSearchPath path = runtime_search_path;
Array rv = ARRAY_DICT_INIT;
Array rv = arena_array(arena, kv_size(path));
for (size_t i = 0; i < kv_size(path); i++) {
SearchPathItem *item = &kv_A(path, i);
Array entry = ARRAY_DICT_INIT;
ADD(entry, CSTR_TO_OBJ(item->path));
ADD(entry, BOOLEAN_OBJ(item->after));
ADD_C(entry, CSTR_AS_OBJ(item->path));
ADD_C(entry, BOOLEAN_OBJ(item->after));
if (item->has_lua != kNone) {
ADD(entry, BOOLEAN_OBJ(item->has_lua == kTrue));
ADD_C(entry, BOOLEAN_OBJ(item->has_lua == kTrue));
}
ADD(rv, ARRAY_OBJ(entry));
ADD_C(rv, ARRAY_OBJ(entry));
}
return rv;
}

View File

@ -1744,25 +1744,24 @@ int do_ucmd(exarg_T *eap, bool preview)
/// @param buf Buffer to inspect, or NULL to get global commands.
///
/// @return Map of maps describing commands
Dictionary commands_array(buf_T *buf)
Dictionary commands_array(buf_T *buf, Arena *arena)
{
Dictionary rv = ARRAY_DICT_INIT;
char str[20];
garray_T *gap = (buf == NULL) ? &ucmds : &buf->b_ucmds;
Dictionary rv = arena_dict(arena, (size_t)gap->ga_len);
for (int i = 0; i < gap->ga_len; i++) {
char arg[2] = { 0, 0 };
Dictionary d = ARRAY_DICT_INIT;
Dictionary d = arena_dict(arena, 14);
ucmd_T *cmd = USER_CMD_GA(gap, i);
PUT(d, "name", CSTR_TO_OBJ(cmd->uc_name));
PUT(d, "definition", CSTR_TO_OBJ(cmd->uc_rep));
PUT(d, "script_id", INTEGER_OBJ(cmd->uc_script_ctx.sc_sid));
PUT(d, "bang", BOOLEAN_OBJ(!!(cmd->uc_argt & EX_BANG)));
PUT(d, "bar", BOOLEAN_OBJ(!!(cmd->uc_argt & EX_TRLBAR)));
PUT(d, "register", BOOLEAN_OBJ(!!(cmd->uc_argt & EX_REGSTR)));
PUT(d, "keepscript", BOOLEAN_OBJ(!!(cmd->uc_argt & EX_KEEPSCRIPT)));
PUT(d, "preview", BOOLEAN_OBJ(!!(cmd->uc_argt & EX_PREVIEW)));
PUT_C(d, "name", CSTR_AS_OBJ(cmd->uc_name));
PUT_C(d, "definition", CSTR_AS_OBJ(cmd->uc_rep));
PUT_C(d, "script_id", INTEGER_OBJ(cmd->uc_script_ctx.sc_sid));
PUT_C(d, "bang", BOOLEAN_OBJ(!!(cmd->uc_argt & EX_BANG)));
PUT_C(d, "bar", BOOLEAN_OBJ(!!(cmd->uc_argt & EX_TRLBAR)));
PUT_C(d, "register", BOOLEAN_OBJ(!!(cmd->uc_argt & EX_REGSTR)));
PUT_C(d, "keepscript", BOOLEAN_OBJ(!!(cmd->uc_argt & EX_KEEPSCRIPT)));
PUT_C(d, "preview", BOOLEAN_OBJ(!!(cmd->uc_argt & EX_PREVIEW)));
switch (cmd->uc_argt & (EX_EXTRA | EX_NOSPC | EX_NEEDARG)) {
case 0:
@ -1776,49 +1775,47 @@ Dictionary commands_array(buf_T *buf)
case (EX_EXTRA | EX_NOSPC | EX_NEEDARG):
arg[0] = '1'; break;
}
PUT(d, "nargs", CSTR_TO_OBJ(arg));
PUT_C(d, "nargs", CSTR_TO_ARENA_OBJ(arena, arg));
char *cmd_compl = get_command_complete(cmd->uc_compl);
PUT(d, "complete", (cmd_compl == NULL
? NIL : CSTR_TO_OBJ(cmd_compl)));
PUT(d, "complete_arg", cmd->uc_compl_arg == NULL
? NIL : CSTR_TO_OBJ(cmd->uc_compl_arg));
PUT_C(d, "complete", (cmd_compl == NULL
? NIL : CSTR_AS_OBJ(cmd_compl)));
PUT_C(d, "complete_arg", cmd->uc_compl_arg == NULL
? NIL : CSTR_AS_OBJ(cmd->uc_compl_arg));
Object obj = NIL;
if (cmd->uc_argt & EX_COUNT) {
if (cmd->uc_def >= 0) {
snprintf(str, sizeof(str), "%" PRId64, cmd->uc_def);
obj = CSTR_TO_OBJ(str); // -count=N
obj = STRING_OBJ(arena_printf(arena, "%" PRId64, cmd->uc_def)); // -count=N
} else {
obj = CSTR_TO_OBJ("0"); // -count
obj = CSTR_AS_OBJ("0"); // -count
}
}
PUT(d, "count", obj);
PUT_C(d, "count", obj);
obj = NIL;
if (cmd->uc_argt & EX_RANGE) {
if (cmd->uc_argt & EX_DFLALL) {
obj = CSTR_TO_OBJ("%"); // -range=%
obj = STATIC_CSTR_AS_OBJ("%"); // -range=%
} else if (cmd->uc_def >= 0) {
snprintf(str, sizeof(str), "%" PRId64, cmd->uc_def);
obj = CSTR_TO_OBJ(str); // -range=N
obj = STRING_OBJ(arena_printf(arena, "%" PRId64, cmd->uc_def)); // -range=N
} else {
obj = CSTR_TO_OBJ("."); // -range
obj = STATIC_CSTR_AS_OBJ("."); // -range
}
}
PUT(d, "range", obj);
PUT_C(d, "range", obj);
obj = NIL;
for (int j = 0; addr_type_complete[j].expand != ADDR_NONE; j++) {
if (addr_type_complete[j].expand != ADDR_LINES
&& addr_type_complete[j].expand == cmd->uc_addr_type) {
obj = CSTR_TO_OBJ(addr_type_complete[j].name);
obj = CSTR_AS_OBJ(addr_type_complete[j].name);
break;
}
}
PUT(d, "addr", obj);
PUT_C(d, "addr", obj);
PUT(rv, cmd->uc_name, DICTIONARY_OBJ(d));
PUT_C(rv, cmd->uc_name, DICTIONARY_OBJ(d));
}
return rv;
}