mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Merge pull request #27511 from bfredl/maparena
refactor(api): use arena for mappings, autocmd, channel info
This commit is contained in:
commit
93c911e52f
@ -23,6 +23,7 @@
|
|||||||
#include "nvim/globals.h"
|
#include "nvim/globals.h"
|
||||||
#include "nvim/lua/executor.h"
|
#include "nvim/lua/executor.h"
|
||||||
#include "nvim/memory.h"
|
#include "nvim/memory.h"
|
||||||
|
#include "nvim/strings.h"
|
||||||
#include "nvim/types_defs.h"
|
#include "nvim/types_defs.h"
|
||||||
#include "nvim/vim_defs.h"
|
#include "nvim/vim_defs.h"
|
||||||
|
|
||||||
@ -33,12 +34,12 @@
|
|||||||
#define AUCMD_MAX_PATTERNS 256
|
#define AUCMD_MAX_PATTERNS 256
|
||||||
|
|
||||||
// Copy string or array of strings into an empty array.
|
// Copy string or array of strings into an empty array.
|
||||||
// Get the event number, unless it is an error. Then goto `goto_name`.
|
// Get the event number, unless it is an error. Then do `or_else`.
|
||||||
#define GET_ONE_EVENT(event_nr, event_str, goto_name) \
|
#define GET_ONE_EVENT(event_nr, event_str, or_else) \
|
||||||
event_T event_nr = \
|
event_T event_nr = \
|
||||||
event_name2nr_str(event_str.data.string); \
|
event_name2nr_str(event_str.data.string); \
|
||||||
VALIDATE_S((event_nr < NUM_EVENTS), "event", event_str.data.string.data, { \
|
VALIDATE_S((event_nr < NUM_EVENTS), "event", event_str.data.string.data, { \
|
||||||
goto goto_name; \
|
or_else; \
|
||||||
});
|
});
|
||||||
|
|
||||||
// ID for associating autocmds created via nvim_create_autocmd
|
// ID for associating autocmds created via nvim_create_autocmd
|
||||||
@ -88,14 +89,14 @@ static int64_t next_autocmd_id = 1;
|
|||||||
/// If the autocommand is buffer local |autocmd-buffer-local|:
|
/// If the autocommand is buffer local |autocmd-buffer-local|:
|
||||||
/// - buflocal (boolean): true if the autocommand is buffer local.
|
/// - buflocal (boolean): true if the autocommand is buffer local.
|
||||||
/// - buffer (number): the buffer number.
|
/// - buffer (number): the buffer number.
|
||||||
Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err)
|
Array nvim_get_autocmds(Dict(get_autocmds) *opts, Arena *arena, Error *err)
|
||||||
FUNC_API_SINCE(9)
|
FUNC_API_SINCE(9)
|
||||||
{
|
{
|
||||||
// TODO(tjdevries): Would be cool to add nvim_get_autocmds({ id = ... })
|
// TODO(tjdevries): Would be cool to add nvim_get_autocmds({ id = ... })
|
||||||
|
|
||||||
Array autocmd_list = ARRAY_DICT_INIT;
|
ArrayBuilder autocmd_list = KV_INITIAL_VALUE;
|
||||||
|
kvi_init(autocmd_list);
|
||||||
char *pattern_filters[AUCMD_MAX_PATTERNS];
|
char *pattern_filters[AUCMD_MAX_PATTERNS];
|
||||||
char pattern_buflocal[BUFLOCAL_PAT_LEN];
|
|
||||||
|
|
||||||
Array buffers = ARRAY_DICT_INIT;
|
Array buffers = ARRAY_DICT_INIT;
|
||||||
|
|
||||||
@ -131,7 +132,7 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err)
|
|||||||
|
|
||||||
Object v = opts->event;
|
Object v = opts->event;
|
||||||
if (v.type == kObjectTypeString) {
|
if (v.type == kObjectTypeString) {
|
||||||
GET_ONE_EVENT(event_nr, v, cleanup);
|
GET_ONE_EVENT(event_nr, v, goto cleanup);
|
||||||
event_set[event_nr] = true;
|
event_set[event_nr] = true;
|
||||||
} else if (v.type == kObjectTypeArray) {
|
} else if (v.type == kObjectTypeArray) {
|
||||||
FOREACH_ITEM(v.data.array, event_v, {
|
FOREACH_ITEM(v.data.array, event_v, {
|
||||||
@ -139,7 +140,7 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err)
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
});
|
});
|
||||||
|
|
||||||
GET_ONE_EVENT(event_nr, event_v, cleanup);
|
GET_ONE_EVENT(event_nr, event_v, goto cleanup);
|
||||||
event_set[event_nr] = true;
|
event_set[event_nr] = true;
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
@ -187,8 +188,9 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err)
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(pattern_buflocal, BUFLOCAL_PAT_LEN, "<buffer=%d>", (int)buf->handle);
|
String pat = arena_printf(arena, "<buffer=%d>", (int)buf->handle);
|
||||||
ADD(buffers, CSTR_TO_OBJ(pattern_buflocal));
|
buffers = arena_array(arena, 1);
|
||||||
|
ADD_C(buffers, STRING_OBJ(pat));
|
||||||
} else if (opts->buffer.type == kObjectTypeArray) {
|
} else if (opts->buffer.type == kObjectTypeArray) {
|
||||||
if (opts->buffer.data.array.size > AUCMD_MAX_PATTERNS) {
|
if (opts->buffer.data.array.size > AUCMD_MAX_PATTERNS) {
|
||||||
api_set_error(err, kErrorTypeValidation, "Too many buffers (maximum of %d)",
|
api_set_error(err, kErrorTypeValidation, "Too many buffers (maximum of %d)",
|
||||||
@ -196,6 +198,7 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err)
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buffers = arena_array(arena, kv_size(opts->buffer.data.array));
|
||||||
FOREACH_ITEM(opts->buffer.data.array, bufnr, {
|
FOREACH_ITEM(opts->buffer.data.array, bufnr, {
|
||||||
VALIDATE_EXP((bufnr.type == kObjectTypeInteger || bufnr.type == kObjectTypeBuffer),
|
VALIDATE_EXP((bufnr.type == kObjectTypeInteger || bufnr.type == kObjectTypeBuffer),
|
||||||
"buffer", "Integer", api_typename(bufnr.type), {
|
"buffer", "Integer", api_typename(bufnr.type), {
|
||||||
@ -207,8 +210,7 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err)
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(pattern_buflocal, BUFLOCAL_PAT_LEN, "<buffer=%d>", (int)buf->handle);
|
ADD_C(buffers, STRING_OBJ(arena_printf(arena, "<buffer=%d>", (int)buf->handle)));
|
||||||
ADD(buffers, CSTR_TO_OBJ(pattern_buflocal));
|
|
||||||
});
|
});
|
||||||
} else if (HAS_KEY(opts, get_autocmds, buffer)) {
|
} else if (HAS_KEY(opts, get_autocmds, buffer)) {
|
||||||
VALIDATE_EXP(false, "buffer", "Integer or Array", api_typename(opts->buffer.type), {
|
VALIDATE_EXP(false, "buffer", "Integer or Array", api_typename(opts->buffer.type), {
|
||||||
@ -250,6 +252,7 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err)
|
|||||||
char *pat = pattern_filters[j];
|
char *pat = pattern_filters[j];
|
||||||
int patlen = (int)strlen(pat);
|
int patlen = (int)strlen(pat);
|
||||||
|
|
||||||
|
char pattern_buflocal[BUFLOCAL_PAT_LEN];
|
||||||
if (aupat_is_buflocal(pat, patlen)) {
|
if (aupat_is_buflocal(pat, patlen)) {
|
||||||
aupat_normalize_buflocal_pat(pattern_buflocal, pat, patlen,
|
aupat_normalize_buflocal_pat(pattern_buflocal, pat, patlen,
|
||||||
aupat_get_buflocal_nr(pat, patlen));
|
aupat_get_buflocal_nr(pat, patlen));
|
||||||
@ -267,51 +270,51 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Dictionary autocmd_info = ARRAY_DICT_INIT;
|
Dictionary autocmd_info = arena_dict(arena, 11);
|
||||||
|
|
||||||
if (ap->group != AUGROUP_DEFAULT) {
|
if (ap->group != AUGROUP_DEFAULT) {
|
||||||
PUT(autocmd_info, "group", INTEGER_OBJ(ap->group));
|
PUT_C(autocmd_info, "group", INTEGER_OBJ(ap->group));
|
||||||
PUT(autocmd_info, "group_name", CSTR_TO_OBJ(augroup_name(ap->group)));
|
PUT_C(autocmd_info, "group_name", CSTR_AS_OBJ(augroup_name(ap->group)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ac->id > 0) {
|
if (ac->id > 0) {
|
||||||
PUT(autocmd_info, "id", INTEGER_OBJ(ac->id));
|
PUT_C(autocmd_info, "id", INTEGER_OBJ(ac->id));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ac->desc != NULL) {
|
if (ac->desc != NULL) {
|
||||||
PUT(autocmd_info, "desc", CSTR_TO_OBJ(ac->desc));
|
PUT_C(autocmd_info, "desc", CSTR_AS_OBJ(ac->desc));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ac->exec.type == CALLABLE_CB) {
|
if (ac->exec.type == CALLABLE_CB) {
|
||||||
PUT(autocmd_info, "command", STRING_OBJ(STRING_INIT));
|
PUT_C(autocmd_info, "command", STRING_OBJ(STRING_INIT));
|
||||||
|
|
||||||
Callback *cb = &ac->exec.callable.cb;
|
Callback *cb = &ac->exec.callable.cb;
|
||||||
switch (cb->type) {
|
switch (cb->type) {
|
||||||
case kCallbackLua:
|
case kCallbackLua:
|
||||||
if (nlua_ref_is_function(cb->data.luaref)) {
|
if (nlua_ref_is_function(cb->data.luaref)) {
|
||||||
PUT(autocmd_info, "callback", LUAREF_OBJ(api_new_luaref(cb->data.luaref)));
|
PUT_C(autocmd_info, "callback", LUAREF_OBJ(api_new_luaref(cb->data.luaref)));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case kCallbackFuncref:
|
case kCallbackFuncref:
|
||||||
case kCallbackPartial:
|
case kCallbackPartial:
|
||||||
PUT(autocmd_info, "callback", CSTR_AS_OBJ(callback_to_string(cb)));
|
PUT_C(autocmd_info, "callback", CSTR_AS_OBJ(callback_to_string(cb, arena)));
|
||||||
break;
|
break;
|
||||||
case kCallbackNone:
|
case kCallbackNone:
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
PUT(autocmd_info, "command", CSTR_TO_OBJ(ac->exec.callable.cmd));
|
PUT_C(autocmd_info, "command", CSTR_AS_OBJ(ac->exec.callable.cmd));
|
||||||
}
|
}
|
||||||
|
|
||||||
PUT(autocmd_info, "pattern", CSTR_TO_OBJ(ap->pat));
|
PUT_C(autocmd_info, "pattern", CSTR_AS_OBJ(ap->pat));
|
||||||
PUT(autocmd_info, "event", CSTR_TO_OBJ(event_nr2name(event)));
|
PUT_C(autocmd_info, "event", CSTR_AS_OBJ(event_nr2name(event)));
|
||||||
PUT(autocmd_info, "once", BOOLEAN_OBJ(ac->once));
|
PUT_C(autocmd_info, "once", BOOLEAN_OBJ(ac->once));
|
||||||
|
|
||||||
if (ap->buflocal_nr) {
|
if (ap->buflocal_nr) {
|
||||||
PUT(autocmd_info, "buflocal", BOOLEAN_OBJ(true));
|
PUT_C(autocmd_info, "buflocal", BOOLEAN_OBJ(true));
|
||||||
PUT(autocmd_info, "buffer", INTEGER_OBJ(ap->buflocal_nr));
|
PUT_C(autocmd_info, "buffer", INTEGER_OBJ(ap->buflocal_nr));
|
||||||
} else {
|
} else {
|
||||||
PUT(autocmd_info, "buflocal", BOOLEAN_OBJ(false));
|
PUT_C(autocmd_info, "buflocal", BOOLEAN_OBJ(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(sctx): It would be good to unify script_ctx to actually work with lua
|
// TODO(sctx): It would be good to unify script_ctx to actually work with lua
|
||||||
@ -328,16 +331,15 @@ Array nvim_get_autocmds(Dict(get_autocmds) *opts, Error *err)
|
|||||||
// Once we do that, we can put these into the autocmd_info, but I don't think it's
|
// Once we do that, we can put these into the autocmd_info, but I don't think it's
|
||||||
// useful to do that at this time.
|
// useful to do that at this time.
|
||||||
//
|
//
|
||||||
// PUT(autocmd_info, "sid", INTEGER_OBJ(ac->script_ctx.sc_sid));
|
// PUT_C(autocmd_info, "sid", INTEGER_OBJ(ac->script_ctx.sc_sid));
|
||||||
// PUT(autocmd_info, "lnum", INTEGER_OBJ(ac->script_ctx.sc_lnum));
|
// PUT_C(autocmd_info, "lnum", INTEGER_OBJ(ac->script_ctx.sc_lnum));
|
||||||
|
|
||||||
ADD(autocmd_list, DICTIONARY_OBJ(autocmd_info));
|
kvi_push(autocmd_list, DICTIONARY_OBJ(autocmd_info));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
api_free_array(buffers);
|
return arena_take_arraybuilder(arena, &autocmd_list);
|
||||||
return autocmd_list;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an |autocommand| event handler, defined by `callback` (Lua function or Vimscript
|
/// Creates an |autocommand| event handler, defined by `callback` (Lua function or Vimscript
|
||||||
@ -399,17 +401,16 @@ cleanup:
|
|||||||
/// @see |autocommand|
|
/// @see |autocommand|
|
||||||
/// @see |nvim_del_autocmd()|
|
/// @see |nvim_del_autocmd()|
|
||||||
Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autocmd) *opts,
|
Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autocmd) *opts,
|
||||||
Error *err)
|
Arena *arena, Error *err)
|
||||||
FUNC_API_SINCE(9)
|
FUNC_API_SINCE(9)
|
||||||
{
|
{
|
||||||
int64_t autocmd_id = -1;
|
int64_t autocmd_id = -1;
|
||||||
char *desc = NULL;
|
char *desc = NULL;
|
||||||
Array patterns = ARRAY_DICT_INIT;
|
|
||||||
Array event_array = ARRAY_DICT_INIT;
|
|
||||||
AucmdExecutable aucmd = AUCMD_EXECUTABLE_INIT;
|
AucmdExecutable aucmd = AUCMD_EXECUTABLE_INIT;
|
||||||
Callback cb = CALLBACK_NONE;
|
Callback cb = CALLBACK_NONE;
|
||||||
|
|
||||||
if (!unpack_string_or_array(&event_array, &event, "event", true, err)) {
|
Array event_array = unpack_string_or_array(event, "event", true, arena, err);
|
||||||
|
if (ERROR_SET(err)) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -469,7 +470,9 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!get_patterns_from_pattern_or_buf(&patterns, opts->pattern, has_buffer, opts->buffer, err)) {
|
Array patterns = get_patterns_from_pattern_or_buf(opts->pattern, has_buffer, opts->buffer, "*",
|
||||||
|
arena, err);
|
||||||
|
if (ERROR_SET(err)) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -477,17 +480,13 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc
|
|||||||
desc = opts->desc.data;
|
desc = opts->desc.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (patterns.size == 0) {
|
|
||||||
ADD(patterns, STATIC_CSTR_TO_OBJ("*"));
|
|
||||||
}
|
|
||||||
|
|
||||||
VALIDATE_R((event_array.size > 0), "event", {
|
VALIDATE_R((event_array.size > 0), "event", {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
});
|
});
|
||||||
|
|
||||||
autocmd_id = next_autocmd_id++;
|
autocmd_id = next_autocmd_id++;
|
||||||
FOREACH_ITEM(event_array, event_str, {
|
FOREACH_ITEM(event_array, event_str, {
|
||||||
GET_ONE_EVENT(event_nr, event_str, cleanup);
|
GET_ONE_EVENT(event_nr, event_str, goto cleanup);
|
||||||
|
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
@ -514,8 +513,6 @@ Integer nvim_create_autocmd(uint64_t channel_id, Object event, Dict(create_autoc
|
|||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
aucmd_exec_free(&aucmd);
|
aucmd_exec_free(&aucmd);
|
||||||
api_free_array(event_array);
|
|
||||||
api_free_array(patterns);
|
|
||||||
|
|
||||||
return autocmd_id;
|
return autocmd_id;
|
||||||
}
|
}
|
||||||
@ -555,7 +552,7 @@ void nvim_del_autocmd(Integer id, Error *err)
|
|||||||
/// - group: (string|int) The augroup name or id.
|
/// - group: (string|int) The augroup name or id.
|
||||||
/// - NOTE: If not passed, will only delete autocmds *not* in any group.
|
/// - NOTE: If not passed, will only delete autocmds *not* in any group.
|
||||||
///
|
///
|
||||||
void nvim_clear_autocmds(Dict(clear_autocmds) *opts, Error *err)
|
void nvim_clear_autocmds(Dict(clear_autocmds) *opts, Arena *arena, Error *err)
|
||||||
FUNC_API_SINCE(9)
|
FUNC_API_SINCE(9)
|
||||||
{
|
{
|
||||||
// TODO(tjdevries): Future improvements:
|
// TODO(tjdevries): Future improvements:
|
||||||
@ -564,33 +561,29 @@ void nvim_clear_autocmds(Dict(clear_autocmds) *opts, Error *err)
|
|||||||
// - group: Allow passing "*" or true or something like that to force doing all
|
// - group: Allow passing "*" or true or something like that to force doing all
|
||||||
// autocmds, regardless of their group.
|
// autocmds, regardless of their group.
|
||||||
|
|
||||||
Array patterns = ARRAY_DICT_INIT;
|
Array event_array = unpack_string_or_array(opts->event, "event", false, arena, err);
|
||||||
Array event_array = ARRAY_DICT_INIT;
|
if (ERROR_SET(err)) {
|
||||||
|
return;
|
||||||
if (!unpack_string_or_array(&event_array, &opts->event, "event", false, err)) {
|
|
||||||
goto cleanup;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_buffer = HAS_KEY(opts, clear_autocmds, buffer);
|
bool has_buffer = HAS_KEY(opts, clear_autocmds, buffer);
|
||||||
|
|
||||||
VALIDATE((!HAS_KEY(opts, clear_autocmds, pattern) || !has_buffer),
|
VALIDATE((!HAS_KEY(opts, clear_autocmds, pattern) || !has_buffer),
|
||||||
"%s", "Cannot use both 'pattern' and 'buffer'", {
|
"%s", "Cannot use both 'pattern' and 'buffer'", {
|
||||||
goto cleanup;
|
return;
|
||||||
});
|
});
|
||||||
|
|
||||||
int au_group = get_augroup_from_object(opts->group, err);
|
int au_group = get_augroup_from_object(opts->group, err);
|
||||||
if (au_group == AUGROUP_ERROR) {
|
if (au_group == AUGROUP_ERROR) {
|
||||||
goto cleanup;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if (!get_patterns_from_pattern_or_buf(&patterns, opts->pattern, has_buffer, opts->buffer, err)) {
|
|
||||||
goto cleanup;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// When we create the autocmds, we want to say that they are all matched, so that's *
|
// When we create the autocmds, we want to say that they are all matched, so that's *
|
||||||
// but when we clear them, we want to say that we didn't pass a pattern, so that's NUL
|
// but when we clear them, we want to say that we didn't pass a pattern, so that's NUL
|
||||||
if (patterns.size == 0) {
|
Array patterns = get_patterns_from_pattern_or_buf(opts->pattern, has_buffer, opts->buffer, "",
|
||||||
ADD(patterns, STATIC_CSTR_TO_OBJ(""));
|
arena, err);
|
||||||
|
if (ERROR_SET(err)) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we didn't pass any events, that means clear all events.
|
// If we didn't pass any events, that means clear all events.
|
||||||
@ -599,26 +592,22 @@ void nvim_clear_autocmds(Dict(clear_autocmds) *opts, Error *err)
|
|||||||
FOREACH_ITEM(patterns, pat_object, {
|
FOREACH_ITEM(patterns, pat_object, {
|
||||||
char *pat = pat_object.data.string.data;
|
char *pat = pat_object.data.string.data;
|
||||||
if (!clear_autocmd(event, pat, au_group, err)) {
|
if (!clear_autocmd(event, pat, au_group, err)) {
|
||||||
goto cleanup;
|
return;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
FOREACH_ITEM(event_array, event_str, {
|
FOREACH_ITEM(event_array, event_str, {
|
||||||
GET_ONE_EVENT(event_nr, event_str, cleanup);
|
GET_ONE_EVENT(event_nr, event_str, return );
|
||||||
|
|
||||||
FOREACH_ITEM(patterns, pat_object, {
|
FOREACH_ITEM(patterns, pat_object, {
|
||||||
char *pat = pat_object.data.string.data;
|
char *pat = pat_object.data.string.data;
|
||||||
if (!clear_autocmd(event_nr, pat, au_group, err)) {
|
if (!clear_autocmd(event_nr, pat, au_group, err)) {
|
||||||
goto cleanup;
|
return;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup:
|
|
||||||
api_free_array(event_array);
|
|
||||||
api_free_array(patterns);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create or get an autocommand group |autocmd-groups|.
|
/// Create or get an autocommand group |autocmd-groups|.
|
||||||
@ -709,7 +698,7 @@ void nvim_del_augroup_by_name(String name, Error *err)
|
|||||||
/// - data (any): arbitrary data to send to the autocommand callback. See
|
/// - data (any): arbitrary data to send to the autocommand callback. See
|
||||||
/// |nvim_create_autocmd()| for details.
|
/// |nvim_create_autocmd()| for details.
|
||||||
/// @see |:doautocmd|
|
/// @see |:doautocmd|
|
||||||
void nvim_exec_autocmds(Object event, Dict(exec_autocmds) *opts, Error *err)
|
void nvim_exec_autocmds(Object event, Dict(exec_autocmds) *opts, Arena *arena, Error *err)
|
||||||
FUNC_API_SINCE(9)
|
FUNC_API_SINCE(9)
|
||||||
{
|
{
|
||||||
int au_group = AUGROUP_ALL;
|
int au_group = AUGROUP_ALL;
|
||||||
@ -717,13 +706,11 @@ void nvim_exec_autocmds(Object event, Dict(exec_autocmds) *opts, Error *err)
|
|||||||
|
|
||||||
buf_T *buf = curbuf;
|
buf_T *buf = curbuf;
|
||||||
|
|
||||||
Array patterns = ARRAY_DICT_INIT;
|
|
||||||
Array event_array = ARRAY_DICT_INIT;
|
|
||||||
|
|
||||||
Object *data = NULL;
|
Object *data = NULL;
|
||||||
|
|
||||||
if (!unpack_string_or_array(&event_array, &event, "event", true, err)) {
|
Array event_array = unpack_string_or_array(event, "event", true, arena, err);
|
||||||
goto cleanup;
|
if (ERROR_SET(err)) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (opts->group.type) {
|
switch (opts->group.type) {
|
||||||
@ -732,19 +719,19 @@ void nvim_exec_autocmds(Object event, Dict(exec_autocmds) *opts, Error *err)
|
|||||||
case kObjectTypeString:
|
case kObjectTypeString:
|
||||||
au_group = augroup_find(opts->group.data.string.data);
|
au_group = augroup_find(opts->group.data.string.data);
|
||||||
VALIDATE_S((au_group != AUGROUP_ERROR), "group", opts->group.data.string.data, {
|
VALIDATE_S((au_group != AUGROUP_ERROR), "group", opts->group.data.string.data, {
|
||||||
goto cleanup;
|
return;
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case kObjectTypeInteger:
|
case kObjectTypeInteger:
|
||||||
au_group = (int)opts->group.data.integer;
|
au_group = (int)opts->group.data.integer;
|
||||||
char *name = au_group == 0 ? NULL : augroup_name(au_group);
|
char *name = au_group == 0 ? NULL : augroup_name(au_group);
|
||||||
VALIDATE_INT(augroup_exists(name), "group", (int64_t)au_group, {
|
VALIDATE_INT(augroup_exists(name), "group", (int64_t)au_group, {
|
||||||
goto cleanup;
|
return;
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
VALIDATE_EXP(false, "group", "String or Integer", api_typename(opts->group.type), {
|
VALIDATE_EXP(false, "group", "String or Integer", api_typename(opts->group.type), {
|
||||||
goto cleanup;
|
return;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -752,23 +739,21 @@ void nvim_exec_autocmds(Object event, Dict(exec_autocmds) *opts, Error *err)
|
|||||||
if (HAS_KEY(opts, exec_autocmds, buffer)) {
|
if (HAS_KEY(opts, exec_autocmds, buffer)) {
|
||||||
VALIDATE((!HAS_KEY(opts, exec_autocmds, pattern)),
|
VALIDATE((!HAS_KEY(opts, exec_autocmds, pattern)),
|
||||||
"%s", "Cannot use both 'pattern' and 'buffer' for the same autocmd", {
|
"%s", "Cannot use both 'pattern' and 'buffer' for the same autocmd", {
|
||||||
goto cleanup;
|
return;
|
||||||
});
|
});
|
||||||
|
|
||||||
has_buffer = true;
|
has_buffer = true;
|
||||||
buf = find_buffer_by_handle(opts->buffer, err);
|
buf = find_buffer_by_handle(opts->buffer, err);
|
||||||
|
|
||||||
if (ERROR_SET(err)) {
|
if (ERROR_SET(err)) {
|
||||||
goto cleanup;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!get_patterns_from_pattern_or_buf(&patterns, opts->pattern, has_buffer, opts->buffer, err)) {
|
Array patterns = get_patterns_from_pattern_or_buf(opts->pattern, has_buffer, opts->buffer, "",
|
||||||
goto cleanup;
|
arena, err);
|
||||||
}
|
if (ERROR_SET(err)) {
|
||||||
|
return;
|
||||||
if (patterns.size == 0) {
|
|
||||||
ADD(patterns, STATIC_CSTR_TO_OBJ(""));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HAS_KEY(opts, exec_autocmds, data)) {
|
if (HAS_KEY(opts, exec_autocmds, data)) {
|
||||||
@ -779,7 +764,7 @@ void nvim_exec_autocmds(Object event, Dict(exec_autocmds) *opts, Error *err)
|
|||||||
|
|
||||||
bool did_aucmd = false;
|
bool did_aucmd = false;
|
||||||
FOREACH_ITEM(event_array, event_str, {
|
FOREACH_ITEM(event_array, event_str, {
|
||||||
GET_ONE_EVENT(event_nr, event_str, cleanup)
|
GET_ONE_EVENT(event_nr, event_str, return )
|
||||||
|
|
||||||
FOREACH_ITEM(patterns, pat, {
|
FOREACH_ITEM(patterns, pat, {
|
||||||
char *fname = !has_buffer ? pat.data.string.data : NULL;
|
char *fname = !has_buffer ? pat.data.string.data : NULL;
|
||||||
@ -790,28 +775,26 @@ void nvim_exec_autocmds(Object event, Dict(exec_autocmds) *opts, Error *err)
|
|||||||
if (did_aucmd && modeline) {
|
if (did_aucmd && modeline) {
|
||||||
do_modelines(0);
|
do_modelines(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup:
|
|
||||||
api_free_array(event_array);
|
|
||||||
api_free_array(patterns);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool unpack_string_or_array(Array *array, Object *v, char *k, bool required, Error *err)
|
static Array unpack_string_or_array(Object v, char *k, bool required, Arena *arena, Error *err)
|
||||||
{
|
{
|
||||||
if (v->type == kObjectTypeString) {
|
if (v.type == kObjectTypeString) {
|
||||||
ADD(*array, copy_object(*v, NULL));
|
Array arr = arena_array(arena, 1);
|
||||||
} else if (v->type == kObjectTypeArray) {
|
ADD_C(arr, v);
|
||||||
if (!check_string_array(v->data.array, k, true, err)) {
|
return arr;
|
||||||
return false;
|
} else if (v.type == kObjectTypeArray) {
|
||||||
|
if (!check_string_array(v.data.array, k, true, err)) {
|
||||||
|
return (Array)ARRAY_DICT_INIT;
|
||||||
}
|
}
|
||||||
*array = copy_array(v->data.array, NULL);
|
return v.data.array;
|
||||||
} else {
|
} else {
|
||||||
VALIDATE_EXP(!required, k, "Array or String", api_typename(v->type), {
|
VALIDATE_EXP(!required, k, "Array or String", api_typename(v.type), {
|
||||||
return false;
|
return (Array)ARRAY_DICT_INIT;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return (Array)ARRAY_DICT_INIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns AUGROUP_ERROR if there was a problem with {group}
|
// Returns AUGROUP_ERROR if there was a problem with {group}
|
||||||
@ -843,55 +826,57 @@ static int get_augroup_from_object(Object group, Error *err)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool get_patterns_from_pattern_or_buf(Array *patterns, Object pattern, bool has_buffer,
|
static Array get_patterns_from_pattern_or_buf(Object pattern, bool has_buffer, Buffer buffer,
|
||||||
Buffer buffer, Error *err)
|
char *fallback, Arena *arena, Error *err)
|
||||||
{
|
{
|
||||||
const char pattern_buflocal[BUFLOCAL_PAT_LEN];
|
ArrayBuilder patterns = ARRAY_DICT_INIT;
|
||||||
|
kvi_init(patterns);
|
||||||
|
|
||||||
if (pattern.type != kObjectTypeNil) {
|
if (pattern.type != kObjectTypeNil) {
|
||||||
Object *v = &pattern;
|
if (pattern.type == kObjectTypeString) {
|
||||||
|
const char *pat = pattern.data.string.data;
|
||||||
if (v->type == kObjectTypeString) {
|
|
||||||
const char *pat = v->data.string.data;
|
|
||||||
size_t patlen = aucmd_pattern_length(pat);
|
size_t patlen = aucmd_pattern_length(pat);
|
||||||
while (patlen) {
|
while (patlen) {
|
||||||
ADD(*patterns, STRING_OBJ(cbuf_to_string(pat, patlen)));
|
kvi_push(patterns, CBUF_TO_ARENA_OBJ(arena, pat, patlen));
|
||||||
|
|
||||||
pat = aucmd_next_pattern(pat, patlen);
|
pat = aucmd_next_pattern(pat, patlen);
|
||||||
patlen = aucmd_pattern_length(pat);
|
patlen = aucmd_pattern_length(pat);
|
||||||
}
|
}
|
||||||
} else if (v->type == kObjectTypeArray) {
|
} else if (pattern.type == kObjectTypeArray) {
|
||||||
if (!check_string_array(v->data.array, "pattern", true, err)) {
|
if (!check_string_array(pattern.data.array, "pattern", true, err)) {
|
||||||
return false;
|
return (Array)ARRAY_DICT_INIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
Array array = v->data.array;
|
Array array = pattern.data.array;
|
||||||
FOREACH_ITEM(array, entry, {
|
FOREACH_ITEM(array, entry, {
|
||||||
const char *pat = entry.data.string.data;
|
const char *pat = entry.data.string.data;
|
||||||
size_t patlen = aucmd_pattern_length(pat);
|
size_t patlen = aucmd_pattern_length(pat);
|
||||||
while (patlen) {
|
while (patlen) {
|
||||||
ADD(*patterns, STRING_OBJ(cbuf_to_string(pat, patlen)));
|
kvi_push(patterns, CBUF_TO_ARENA_OBJ(arena, pat, patlen));
|
||||||
|
|
||||||
pat = aucmd_next_pattern(pat, patlen);
|
pat = aucmd_next_pattern(pat, patlen);
|
||||||
patlen = aucmd_pattern_length(pat);
|
patlen = aucmd_pattern_length(pat);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
VALIDATE_EXP(false, "pattern", "String or Table", api_typename(v->type), {
|
VALIDATE_EXP(false, "pattern", "String or Table", api_typename(pattern.type), {
|
||||||
return false;
|
return (Array)ARRAY_DICT_INIT;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (has_buffer) {
|
} else if (has_buffer) {
|
||||||
buf_T *buf = find_buffer_by_handle(buffer, err);
|
buf_T *buf = find_buffer_by_handle(buffer, err);
|
||||||
if (ERROR_SET(err)) {
|
if (ERROR_SET(err)) {
|
||||||
return false;
|
return (Array)ARRAY_DICT_INIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf((char *)pattern_buflocal, BUFLOCAL_PAT_LEN, "<buffer=%d>", (int)buf->handle);
|
kvi_push(patterns, STRING_OBJ(arena_printf(arena, "<buffer=%d>", (int)buf->handle)));
|
||||||
ADD(*patterns, CSTR_TO_OBJ(pattern_buflocal));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
if (kv_size(patterns) == 0 && fallback) {
|
||||||
|
kvi_push(patterns, CSTR_AS_OBJ(fallback));
|
||||||
|
}
|
||||||
|
|
||||||
|
return arena_take_arraybuilder(arena, &patterns);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool clear_autocmd(event_T event, char *pat, int au_group, Error *err)
|
static bool clear_autocmd(event_T event, char *pat, int au_group, Error *err)
|
||||||
|
@ -905,7 +905,7 @@ Integer nvim_buf_get_changedtick(Buffer buffer, Error *err)
|
|||||||
/// @param[out] err Error details, if any
|
/// @param[out] err Error details, if any
|
||||||
/// @returns Array of |maparg()|-like dictionaries describing mappings.
|
/// @returns Array of |maparg()|-like dictionaries describing mappings.
|
||||||
/// The "buffer" key holds the associated buffer handle.
|
/// The "buffer" key holds the associated buffer handle.
|
||||||
ArrayOf(Dictionary) nvim_buf_get_keymap(Buffer buffer, String mode, Error *err)
|
ArrayOf(Dictionary) nvim_buf_get_keymap(Buffer buffer, String mode, Arena *arena, Error *err)
|
||||||
FUNC_API_SINCE(3)
|
FUNC_API_SINCE(3)
|
||||||
{
|
{
|
||||||
buf_T *buf = find_buffer_by_handle(buffer, err);
|
buf_T *buf = find_buffer_by_handle(buffer, err);
|
||||||
@ -914,7 +914,7 @@ ArrayOf(Dictionary) nvim_buf_get_keymap(Buffer buffer, String mode, Error *err)
|
|||||||
return (Array)ARRAY_DICT_INIT;
|
return (Array)ARRAY_DICT_INIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
return keymap_array(mode, buf);
|
return keymap_array(mode, buf, arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets a buffer-local |mapping| for the given mode.
|
/// Sets a buffer-local |mapping| for the given mode.
|
||||||
|
@ -346,7 +346,7 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e
|
|||||||
|
|
||||||
rv = arena_array(arena, kv_size(marks));
|
rv = arena_array(arena, kv_size(marks));
|
||||||
for (size_t i = 0; i < kv_size(marks); i++) {
|
for (size_t i = 0; i < kv_size(marks); i++) {
|
||||||
ADD(rv, ARRAY_OBJ(extmark_to_array(kv_A(marks, i), true, details, hl_name, arena)));
|
ADD_C(rv, ARRAY_OBJ(extmark_to_array(kv_A(marks, i), true, details, hl_name, arena)));
|
||||||
}
|
}
|
||||||
|
|
||||||
kv_destroy(marks);
|
kv_destroy(marks);
|
||||||
|
@ -581,6 +581,15 @@ String arena_string(Arena *arena, String str)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Array arena_take_arraybuilder(Arena *arena, ArrayBuilder *arr)
|
||||||
|
{
|
||||||
|
Array ret = arena_array(arena, kv_size(*arr));
|
||||||
|
ret.size = kv_size(*arr);
|
||||||
|
memcpy(ret.items, arr->items, sizeof(ret.items[0]) * ret.size);
|
||||||
|
kvi_destroy(*arr);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
void api_free_object(Object value)
|
void api_free_object(Object value)
|
||||||
{
|
{
|
||||||
switch (value.type) {
|
switch (value.type) {
|
||||||
|
@ -95,6 +95,8 @@
|
|||||||
name.capacity = maxsize; \
|
name.capacity = maxsize; \
|
||||||
name.items = name##__items; \
|
name.items = name##__items; \
|
||||||
|
|
||||||
|
typedef kvec_withinit_t(Object, 16) ArrayBuilder;
|
||||||
|
|
||||||
#define cbuf_as_string(d, s) ((String) { .data = d, .size = s })
|
#define cbuf_as_string(d, s) ((String) { .data = d, .size = s })
|
||||||
|
|
||||||
#define STATIC_CSTR_AS_STRING(s) ((String) { .data = s, .size = sizeof("" s) - 1 })
|
#define STATIC_CSTR_AS_STRING(s) ((String) { .data = s, .size = sizeof("" s) - 1 })
|
||||||
|
@ -1046,7 +1046,7 @@ static Array translate_firstarg(UI *ui, Array args, Arena *arena)
|
|||||||
|
|
||||||
ADD_C(new_args, ARRAY_OBJ(translate_contents(ui, contents, arena)));
|
ADD_C(new_args, ARRAY_OBJ(translate_contents(ui, contents, arena)));
|
||||||
for (size_t i = 1; i < args.size; i++) {
|
for (size_t i = 1; i < args.size; i++) {
|
||||||
ADD(new_args, args.items[i]);
|
ADD_C(new_args, args.items[i]);
|
||||||
}
|
}
|
||||||
return new_args;
|
return new_args;
|
||||||
}
|
}
|
||||||
|
@ -1456,10 +1456,10 @@ Dictionary nvim_get_mode(Arena *arena)
|
|||||||
/// @param mode Mode short-name ("n", "i", "v", ...)
|
/// @param mode Mode short-name ("n", "i", "v", ...)
|
||||||
/// @returns Array of |maparg()|-like dictionaries describing mappings.
|
/// @returns Array of |maparg()|-like dictionaries describing mappings.
|
||||||
/// The "buffer" key is always zero.
|
/// The "buffer" key is always zero.
|
||||||
ArrayOf(Dictionary) nvim_get_keymap(String mode)
|
ArrayOf(Dictionary) nvim_get_keymap(String mode, Arena *arena)
|
||||||
FUNC_API_SINCE(3)
|
FUNC_API_SINCE(3)
|
||||||
{
|
{
|
||||||
return keymap_array(mode, NULL);
|
return keymap_array(mode, NULL, arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets a global |mapping| for the given mode.
|
/// Sets a global |mapping| for the given mode.
|
||||||
@ -1633,7 +1633,7 @@ void nvim_set_client_info(uint64_t channel_id, String name, Dictionary version,
|
|||||||
/// the RPC channel), if provided by it via
|
/// the RPC channel), if provided by it via
|
||||||
/// |nvim_set_client_info()|.
|
/// |nvim_set_client_info()|.
|
||||||
///
|
///
|
||||||
Dictionary nvim_get_chan_info(uint64_t channel_id, Integer chan, Error *err)
|
Dictionary nvim_get_chan_info(uint64_t channel_id, Integer chan, Arena *arena, Error *err)
|
||||||
FUNC_API_SINCE(4)
|
FUNC_API_SINCE(4)
|
||||||
{
|
{
|
||||||
if (chan < 0) {
|
if (chan < 0) {
|
||||||
@ -1644,17 +1644,17 @@ Dictionary nvim_get_chan_info(uint64_t channel_id, Integer chan, Error *err)
|
|||||||
assert(channel_id <= INT64_MAX);
|
assert(channel_id <= INT64_MAX);
|
||||||
chan = (Integer)channel_id;
|
chan = (Integer)channel_id;
|
||||||
}
|
}
|
||||||
return channel_info((uint64_t)chan);
|
return channel_info((uint64_t)chan, arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get information about all open channels.
|
/// Get information about all open channels.
|
||||||
///
|
///
|
||||||
/// @returns Array of Dictionaries, each describing a channel with
|
/// @returns Array of Dictionaries, each describing a channel with
|
||||||
/// the format specified at |nvim_get_chan_info()|.
|
/// the format specified at |nvim_get_chan_info()|.
|
||||||
Array nvim_list_chans(void)
|
Array nvim_list_chans(Arena *arena)
|
||||||
FUNC_API_SINCE(4)
|
FUNC_API_SINCE(4)
|
||||||
{
|
{
|
||||||
return channel_all_info();
|
return channel_all_info(arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calls many API methods atomically.
|
/// Calls many API methods atomically.
|
||||||
@ -1891,7 +1891,7 @@ Array nvim_get_proc_children(Integer pid, Arena *arena, Error *err)
|
|||||||
// syscall failed (possibly because of kernel options), try shelling out.
|
// syscall failed (possibly because of kernel options), try shelling out.
|
||||||
DLOG("fallback to vim._os_proc_children()");
|
DLOG("fallback to vim._os_proc_children()");
|
||||||
MAXSIZE_TEMP_ARRAY(a, 1);
|
MAXSIZE_TEMP_ARRAY(a, 1);
|
||||||
ADD(a, INTEGER_OBJ(pid));
|
ADD_C(a, INTEGER_OBJ(pid));
|
||||||
Object o = NLUA_EXEC_STATIC("return vim._os_proc_children(...)", a, kRetObject, arena, err);
|
Object o = NLUA_EXEC_STATIC("return vim._os_proc_children(...)", a, kRetObject, arena, err);
|
||||||
if (o.type == kObjectTypeArray) {
|
if (o.type == kObjectTypeArray) {
|
||||||
rvobj = o.data.array;
|
rvobj = o.data.array;
|
||||||
@ -1903,7 +1903,7 @@ Array nvim_get_proc_children(Integer pid, Arena *arena, Error *err)
|
|||||||
} else {
|
} else {
|
||||||
rvobj = arena_array(arena, proc_count);
|
rvobj = arena_array(arena, proc_count);
|
||||||
for (size_t i = 0; i < proc_count; i++) {
|
for (size_t i = 0; i < proc_count; i++) {
|
||||||
ADD(rvobj, INTEGER_OBJ(proc_list[i]));
|
ADD_C(rvobj, INTEGER_OBJ(proc_list[i]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1925,7 +1925,7 @@ Object nvim_get_proc(Integer pid, Arena *arena, Error *err)
|
|||||||
});
|
});
|
||||||
|
|
||||||
#ifdef MSWIN
|
#ifdef MSWIN
|
||||||
rvobj = DICTIONARY_OBJ(os_proc_info((int)pid));
|
rvobj = DICTIONARY_OBJ(os_proc_info((int)pid, arena));
|
||||||
if (rvobj.data.dictionary.size == 0) { // Process not found.
|
if (rvobj.data.dictionary.size == 0) { // Process not found.
|
||||||
return NIL;
|
return NIL;
|
||||||
}
|
}
|
||||||
|
@ -77,15 +77,16 @@ void nvim_win_set_buf(Window window, Buffer buffer, Error *err)
|
|||||||
/// @param window Window handle, or 0 for current window
|
/// @param window Window handle, or 0 for current window
|
||||||
/// @param[out] err Error details, if any
|
/// @param[out] err Error details, if any
|
||||||
/// @return (row, col) tuple
|
/// @return (row, col) tuple
|
||||||
ArrayOf(Integer, 2) nvim_win_get_cursor(Window window, Error *err)
|
ArrayOf(Integer, 2) nvim_win_get_cursor(Window window, Arena *arena, Error *err)
|
||||||
FUNC_API_SINCE(1)
|
FUNC_API_SINCE(1)
|
||||||
{
|
{
|
||||||
Array rv = ARRAY_DICT_INIT;
|
Array rv = ARRAY_DICT_INIT;
|
||||||
win_T *win = find_window_by_handle(window, err);
|
win_T *win = find_window_by_handle(window, err);
|
||||||
|
|
||||||
if (win) {
|
if (win) {
|
||||||
ADD(rv, INTEGER_OBJ(win->w_cursor.lnum));
|
rv = arena_array(arena, 2);
|
||||||
ADD(rv, INTEGER_OBJ(win->w_cursor.col));
|
ADD_C(rv, INTEGER_OBJ(win->w_cursor.lnum));
|
||||||
|
ADD_C(rv, INTEGER_OBJ(win->w_cursor.col));
|
||||||
}
|
}
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
|
@ -2429,7 +2429,7 @@ char *aucmd_exec_to_string(AutoCmd *ac, AucmdExecutable acc)
|
|||||||
case CALLABLE_EX:
|
case CALLABLE_EX:
|
||||||
return xstrdup(acc.callable.cmd);
|
return xstrdup(acc.callable.cmd);
|
||||||
case CALLABLE_CB:
|
case CALLABLE_CB:
|
||||||
return callback_to_string(&acc.callable.cb);
|
return callback_to_string(&acc.callable.cb, NULL);
|
||||||
case CALLABLE_NONE:
|
case CALLABLE_NONE:
|
||||||
return "This is not possible";
|
return "This is not possible";
|
||||||
}
|
}
|
||||||
|
@ -238,7 +238,8 @@ void channel_create_event(Channel *chan, const char *ext_source)
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert(chan->id <= VARNUMBER_MAX);
|
assert(chan->id <= VARNUMBER_MAX);
|
||||||
Dictionary info = channel_info(chan->id);
|
Arena arena = ARENA_EMPTY;
|
||||||
|
Dictionary info = channel_info(chan->id, &arena);
|
||||||
typval_T tv = TV_INITIAL_VALUE;
|
typval_T tv = TV_INITIAL_VALUE;
|
||||||
// TODO(bfredl): do the conversion in one step. Also would be nice
|
// TODO(bfredl): do the conversion in one step. Also would be nice
|
||||||
// to pretty print top level dict in defined order
|
// to pretty print top level dict in defined order
|
||||||
@ -247,7 +248,7 @@ void channel_create_event(Channel *chan, const char *ext_source)
|
|||||||
char *str = encode_tv2json(&tv, NULL);
|
char *str = encode_tv2json(&tv, NULL);
|
||||||
ILOG("new channel %" PRIu64 " (%s) : %s", chan->id, source, str);
|
ILOG("new channel %" PRIu64 " (%s) : %s", chan->id, source, str);
|
||||||
xfree(str);
|
xfree(str);
|
||||||
api_free_dictionary(info);
|
arena_mem_free(arena_finish(&arena));
|
||||||
|
|
||||||
#else
|
#else
|
||||||
(void)ext_source;
|
(void)ext_source;
|
||||||
@ -876,7 +877,8 @@ static void set_info_event(void **argv)
|
|||||||
|
|
||||||
save_v_event_T save_v_event;
|
save_v_event_T save_v_event;
|
||||||
dict_T *dict = get_v_event(&save_v_event);
|
dict_T *dict = get_v_event(&save_v_event);
|
||||||
Dictionary info = channel_info(chan->id);
|
Arena arena = ARENA_EMPTY;
|
||||||
|
Dictionary info = channel_info(chan->id, &arena);
|
||||||
typval_T retval;
|
typval_T retval;
|
||||||
object_to_vim(DICTIONARY_OBJ(info), &retval, NULL);
|
object_to_vim(DICTIONARY_OBJ(info), &retval, NULL);
|
||||||
assert(retval.v_type == VAR_DICT);
|
assert(retval.v_type == VAR_DICT);
|
||||||
@ -886,7 +888,7 @@ static void set_info_event(void **argv)
|
|||||||
apply_autocmds(event, NULL, NULL, false, curbuf);
|
apply_autocmds(event, NULL, NULL, false, curbuf);
|
||||||
|
|
||||||
restore_v_event(dict, &save_v_event);
|
restore_v_event(dict, &save_v_event);
|
||||||
api_free_dictionary(info);
|
arena_mem_free(arena_finish(&arena));
|
||||||
channel_decref(chan);
|
channel_decref(chan);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -898,15 +900,15 @@ bool channel_job_running(uint64_t id)
|
|||||||
&& !process_is_stopped(&chan->stream.proc));
|
&& !process_is_stopped(&chan->stream.proc));
|
||||||
}
|
}
|
||||||
|
|
||||||
Dictionary channel_info(uint64_t id)
|
Dictionary channel_info(uint64_t id, Arena *arena)
|
||||||
{
|
{
|
||||||
Channel *chan = find_channel(id);
|
Channel *chan = find_channel(id);
|
||||||
if (!chan) {
|
if (!chan) {
|
||||||
return (Dictionary)ARRAY_DICT_INIT;
|
return (Dictionary)ARRAY_DICT_INIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
Dictionary info = ARRAY_DICT_INIT;
|
Dictionary info = arena_dict(arena, 8);
|
||||||
PUT(info, "id", INTEGER_OBJ((Integer)chan->id));
|
PUT_C(info, "id", INTEGER_OBJ((Integer)chan->id));
|
||||||
|
|
||||||
const char *stream_desc, *mode_desc;
|
const char *stream_desc, *mode_desc;
|
||||||
switch (chan->streamtype) {
|
switch (chan->streamtype) {
|
||||||
@ -914,18 +916,20 @@ Dictionary channel_info(uint64_t id)
|
|||||||
stream_desc = "job";
|
stream_desc = "job";
|
||||||
if (chan->stream.proc.type == kProcessTypePty) {
|
if (chan->stream.proc.type == kProcessTypePty) {
|
||||||
const char *name = pty_process_tty_name(&chan->stream.pty);
|
const char *name = pty_process_tty_name(&chan->stream.pty);
|
||||||
PUT(info, "pty", CSTR_TO_OBJ(name));
|
PUT_C(info, "pty", CSTR_TO_ARENA_OBJ(arena, name));
|
||||||
}
|
}
|
||||||
|
|
||||||
char **p = chan->stream.proc.argv;
|
char **args = chan->stream.proc.argv;
|
||||||
Array argv = ARRAY_DICT_INIT;
|
Array argv = ARRAY_DICT_INIT;
|
||||||
if (p != NULL) {
|
if (args != NULL) {
|
||||||
while (*p != NULL) {
|
size_t n;
|
||||||
ADD(argv, CSTR_TO_OBJ(*p));
|
for (n = 0; args[n] != NULL; n++) {}
|
||||||
p++;
|
argv = arena_array(arena, n);
|
||||||
|
for (size_t i = 0; i < n; i++) {
|
||||||
|
ADD_C(argv, CSTR_AS_OBJ(args[i]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PUT(info, "argv", ARRAY_OBJ(argv));
|
PUT_C(info, "argv", ARRAY_OBJ(argv));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -938,25 +942,25 @@ Dictionary channel_info(uint64_t id)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case kChannelStreamInternal:
|
case kChannelStreamInternal:
|
||||||
PUT(info, "internal", BOOLEAN_OBJ(true));
|
PUT_C(info, "internal", BOOLEAN_OBJ(true));
|
||||||
FALLTHROUGH;
|
FALLTHROUGH;
|
||||||
|
|
||||||
case kChannelStreamSocket:
|
case kChannelStreamSocket:
|
||||||
stream_desc = "socket";
|
stream_desc = "socket";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
PUT(info, "stream", CSTR_TO_OBJ(stream_desc));
|
PUT_C(info, "stream", CSTR_AS_OBJ(stream_desc));
|
||||||
|
|
||||||
if (chan->is_rpc) {
|
if (chan->is_rpc) {
|
||||||
mode_desc = "rpc";
|
mode_desc = "rpc";
|
||||||
PUT(info, "client", DICTIONARY_OBJ(rpc_client_info(chan)));
|
PUT_C(info, "client", DICTIONARY_OBJ(chan->rpc.info));
|
||||||
} else if (chan->term) {
|
} else if (chan->term) {
|
||||||
mode_desc = "terminal";
|
mode_desc = "terminal";
|
||||||
PUT(info, "buffer", BUFFER_OBJ(terminal_buf(chan->term)));
|
PUT_C(info, "buffer", BUFFER_OBJ(terminal_buf(chan->term)));
|
||||||
} else {
|
} else {
|
||||||
mode_desc = "bytes";
|
mode_desc = "bytes";
|
||||||
}
|
}
|
||||||
PUT(info, "mode", CSTR_TO_OBJ(mode_desc));
|
PUT_C(info, "mode", CSTR_AS_OBJ(mode_desc));
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
@ -969,21 +973,20 @@ static int int64_t_cmp(const void *pa, const void *pb)
|
|||||||
return a == b ? 0 : a > b ? 1 : -1;
|
return a == b ? 0 : a > b ? 1 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Array channel_all_info(void)
|
Array channel_all_info(Arena *arena)
|
||||||
{
|
{
|
||||||
// order the items in the array by channel number, for Determinism™
|
// order the items in the array by channel number, for Determinism™
|
||||||
kvec_t(int64_t) ids = KV_INITIAL_VALUE;
|
kvec_t(int64_t) ids = KV_INITIAL_VALUE;
|
||||||
kv_resize(ids, map_size(&channels));
|
kv_fixsize_arena(arena, ids, map_size(&channels));
|
||||||
uint64_t id;
|
uint64_t id;
|
||||||
map_foreach_key(&channels, id, {
|
map_foreach_key(&channels, id, {
|
||||||
kv_push(ids, (int64_t)id);
|
kv_push(ids, (int64_t)id);
|
||||||
});
|
});
|
||||||
qsort(ids.items, ids.size, sizeof ids.items[0], int64_t_cmp);
|
qsort(ids.items, ids.size, sizeof ids.items[0], int64_t_cmp);
|
||||||
|
|
||||||
Array ret = ARRAY_DICT_INIT;
|
Array ret = arena_array(arena, ids.size);
|
||||||
for (size_t i = 0; i < ids.size; i++) {
|
for (size_t i = 0; i < ids.size; i++) {
|
||||||
ADD(ret, DICTIONARY_OBJ(channel_info((uint64_t)ids.items[i])));
|
ADD_C(ret, DICTIONARY_OBJ(channel_info((uint64_t)ids.items[i], arena)));
|
||||||
}
|
}
|
||||||
kv_destroy(ids);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -374,7 +374,7 @@ static void api_wrapper(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
|||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
object_to_vim(result, rettv, &err);
|
object_to_vim_take_luaref(&result, rettv, true, &err);
|
||||||
|
|
||||||
end:
|
end:
|
||||||
if (!handler.arena_return) {
|
if (!handler.arena_return) {
|
||||||
|
@ -1805,10 +1805,10 @@ void callback_copy(Callback *dest, Callback *src)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Generate a string description of a callback
|
/// Generate a string description of a callback
|
||||||
char *callback_to_string(Callback *cb)
|
char *callback_to_string(Callback *cb, Arena *arena)
|
||||||
{
|
{
|
||||||
if (cb->type == kCallbackLua) {
|
if (cb->type == kCallbackLua) {
|
||||||
return nlua_funcref_str(cb->data.luaref);
|
return nlua_funcref_str(cb->data.luaref, arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
const size_t msglen = 100;
|
const size_t msglen = 100;
|
||||||
|
@ -2327,11 +2327,9 @@ int nlua_do_ucmd(ucmd_T *cmd, exarg_T *eap, bool preview)
|
|||||||
/// String representation of a Lua function reference
|
/// String representation of a Lua function reference
|
||||||
///
|
///
|
||||||
/// @return Allocated string
|
/// @return Allocated string
|
||||||
char *nlua_funcref_str(LuaRef ref)
|
char *nlua_funcref_str(LuaRef ref, Arena *arena)
|
||||||
{
|
{
|
||||||
lua_State *const lstate = global_lstate;
|
lua_State *const lstate = global_lstate;
|
||||||
StringBuilder str = KV_INITIAL_VALUE;
|
|
||||||
kv_resize(str, 16);
|
|
||||||
|
|
||||||
if (!lua_checkstack(lstate, 1)) {
|
if (!lua_checkstack(lstate, 1)) {
|
||||||
goto plain;
|
goto plain;
|
||||||
@ -2345,14 +2343,13 @@ char *nlua_funcref_str(LuaRef ref)
|
|||||||
lua_Debug ar;
|
lua_Debug ar;
|
||||||
if (lua_getinfo(lstate, ">S", &ar) && *ar.source == '@' && ar.linedefined >= 0) {
|
if (lua_getinfo(lstate, ">S", &ar) && *ar.source == '@' && ar.linedefined >= 0) {
|
||||||
char *src = home_replace_save(NULL, ar.source + 1);
|
char *src = home_replace_save(NULL, ar.source + 1);
|
||||||
kv_printf(str, "<Lua %d: %s:%d>", ref, src, ar.linedefined);
|
String str = arena_printf(arena, "<Lua %d: %s:%d>", ref, src, ar.linedefined);
|
||||||
xfree(src);
|
xfree(src);
|
||||||
return str.items;
|
return str.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
plain:
|
plain: {}
|
||||||
kv_printf(str, "<Lua %d>", ref);
|
return arena_printf(arena, "<Lua %d>", ref).data;
|
||||||
return str.items;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Execute the vim._defaults module to set up default mappings and autocommands
|
/// Execute the vim._defaults module to set up default mappings and autocommands
|
||||||
|
@ -947,10 +947,10 @@ static void remote_request(mparm_T *params, int remote_args, char *server_addr,
|
|||||||
|
|
||||||
Error err = ERROR_INIT;
|
Error err = ERROR_INIT;
|
||||||
MAXSIZE_TEMP_ARRAY(a, 4);
|
MAXSIZE_TEMP_ARRAY(a, 4);
|
||||||
ADD(a, INTEGER_OBJ((int)chan));
|
ADD_C(a, INTEGER_OBJ((int)chan));
|
||||||
ADD(a, CSTR_AS_OBJ(server_addr));
|
ADD_C(a, CSTR_AS_OBJ(server_addr));
|
||||||
ADD(a, CSTR_AS_OBJ(connect_error));
|
ADD_C(a, CSTR_AS_OBJ(connect_error));
|
||||||
ADD(a, ARRAY_OBJ(args));
|
ADD_C(a, ARRAY_OBJ(args));
|
||||||
String s = STATIC_CSTR_AS_STRING("return vim._cs_remote(...)");
|
String s = STATIC_CSTR_AS_STRING("return vim._cs_remote(...)");
|
||||||
Object o = nlua_exec(s, a, kRetObject, NULL, &err);
|
Object o = nlua_exec(s, a, kRetObject, NULL, &err);
|
||||||
kv_destroy(args);
|
kv_destroy(args);
|
||||||
|
@ -160,51 +160,47 @@ static void mapblock_free(mapblock_T **mpp)
|
|||||||
xfree(mp);
|
xfree(mp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return characters to represent the map mode in an allocated string
|
/// put characters to represent the map mode in a string buffer
|
||||||
///
|
///
|
||||||
/// @return [allocated] NUL-terminated string with characters.
|
/// @param[out] buf must be at least 7 bytes (including NUL)
|
||||||
static char *map_mode_to_chars(int mode)
|
void map_mode_to_chars(int mode, char *buf)
|
||||||
FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_RET
|
FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
garray_T mapmode;
|
char *p = buf;
|
||||||
|
|
||||||
ga_init(&mapmode, 1, 7);
|
|
||||||
|
|
||||||
if ((mode & (MODE_INSERT | MODE_CMDLINE)) == (MODE_INSERT | MODE_CMDLINE)) {
|
if ((mode & (MODE_INSERT | MODE_CMDLINE)) == (MODE_INSERT | MODE_CMDLINE)) {
|
||||||
ga_append(&mapmode, '!'); // :map!
|
*p++ = '!'; // :map!
|
||||||
} else if (mode & MODE_INSERT) {
|
} else if (mode & MODE_INSERT) {
|
||||||
ga_append(&mapmode, 'i'); // :imap
|
*p++ = 'i'; // :imap
|
||||||
} else if (mode & MODE_LANGMAP) {
|
} else if (mode & MODE_LANGMAP) {
|
||||||
ga_append(&mapmode, 'l'); // :lmap
|
*p++ = 'l'; // :lmap
|
||||||
} else if (mode & MODE_CMDLINE) {
|
} else if (mode & MODE_CMDLINE) {
|
||||||
ga_append(&mapmode, 'c'); // :cmap
|
*p++ = 'c'; // :cmap
|
||||||
} else if ((mode & (MODE_NORMAL | MODE_VISUAL | MODE_SELECT | MODE_OP_PENDING))
|
} else if ((mode & (MODE_NORMAL | MODE_VISUAL | MODE_SELECT | MODE_OP_PENDING))
|
||||||
== (MODE_NORMAL | MODE_VISUAL | MODE_SELECT | MODE_OP_PENDING)) {
|
== (MODE_NORMAL | MODE_VISUAL | MODE_SELECT | MODE_OP_PENDING)) {
|
||||||
ga_append(&mapmode, ' '); // :map
|
*p++ = ' '; // :map
|
||||||
} else {
|
} else {
|
||||||
if (mode & MODE_NORMAL) {
|
if (mode & MODE_NORMAL) {
|
||||||
ga_append(&mapmode, 'n'); // :nmap
|
*p++ = 'n'; // :nmap
|
||||||
}
|
}
|
||||||
if (mode & MODE_OP_PENDING) {
|
if (mode & MODE_OP_PENDING) {
|
||||||
ga_append(&mapmode, 'o'); // :omap
|
*p++ = 'o'; // :omap
|
||||||
}
|
}
|
||||||
if (mode & MODE_TERMINAL) {
|
if (mode & MODE_TERMINAL) {
|
||||||
ga_append(&mapmode, 't'); // :tmap
|
*p++ = 't'; // :tmap
|
||||||
}
|
}
|
||||||
if ((mode & (MODE_VISUAL | MODE_SELECT)) == (MODE_VISUAL | MODE_SELECT)) {
|
if ((mode & (MODE_VISUAL | MODE_SELECT)) == (MODE_VISUAL | MODE_SELECT)) {
|
||||||
ga_append(&mapmode, 'v'); // :vmap
|
*p++ = 'v'; // :vmap
|
||||||
} else {
|
} else {
|
||||||
if (mode & MODE_VISUAL) {
|
if (mode & MODE_VISUAL) {
|
||||||
ga_append(&mapmode, 'x'); // :xmap
|
*p++ = 'x'; // :xmap
|
||||||
}
|
}
|
||||||
if (mode & MODE_SELECT) {
|
if (mode & MODE_SELECT) {
|
||||||
ga_append(&mapmode, 's'); // :smap
|
*p++ = 's'; // :smap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ga_append(&mapmode, NUL);
|
*p = NUL;
|
||||||
return (char *)mapmode.ga_data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @param local true for buffer-local map
|
/// @param local true for buffer-local map
|
||||||
@ -223,10 +219,10 @@ static void showmap(mapblock_T *mp, bool local)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char *const mapchars = map_mode_to_chars(mp->m_mode);
|
char mapchars[7];
|
||||||
|
map_mode_to_chars(mp->m_mode, mapchars);
|
||||||
msg_puts(mapchars);
|
msg_puts(mapchars);
|
||||||
size_t len = strlen(mapchars);
|
size_t len = strlen(mapchars);
|
||||||
xfree(mapchars);
|
|
||||||
|
|
||||||
while (++len <= 3) {
|
while (++len <= 3) {
|
||||||
msg_putchar(' ');
|
msg_putchar(' ');
|
||||||
@ -256,7 +252,7 @@ static void showmap(mapblock_T *mp, bool local)
|
|||||||
// Use false below if we only want things like <Up> to show up as such on
|
// Use false below if we only want things like <Up> to show up as such on
|
||||||
// the rhs, and not M-x etc, true gets both -- webb
|
// the rhs, and not M-x etc, true gets both -- webb
|
||||||
if (mp->m_luaref != LUA_NOREF) {
|
if (mp->m_luaref != LUA_NOREF) {
|
||||||
char *str = nlua_funcref_str(mp->m_luaref);
|
char *str = nlua_funcref_str(mp->m_luaref, NULL);
|
||||||
msg_puts_attr(str, HL_ATTR(HLF_8));
|
msg_puts_attr(str, HL_ATTR(HLF_8));
|
||||||
xfree(str);
|
xfree(str);
|
||||||
} else if (mp->m_str[0] == NUL) {
|
} else if (mp->m_str[0] == NUL) {
|
||||||
@ -2070,12 +2066,14 @@ void f_hasmapto(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
|||||||
///
|
///
|
||||||
/// @return A Dictionary.
|
/// @return A Dictionary.
|
||||||
static Dictionary mapblock_fill_dict(const mapblock_T *const mp, const char *lhsrawalt,
|
static Dictionary mapblock_fill_dict(const mapblock_T *const mp, const char *lhsrawalt,
|
||||||
const int buffer_value, const bool abbr, const bool compatible)
|
const int buffer_value, const bool abbr, const bool compatible,
|
||||||
|
Arena *arena)
|
||||||
FUNC_ATTR_NONNULL_ARG(1)
|
FUNC_ATTR_NONNULL_ARG(1)
|
||||||
{
|
{
|
||||||
Dictionary dict = ARRAY_DICT_INIT;
|
Dictionary dict = arena_dict(arena, 19);
|
||||||
char *const lhs = str2special_save(mp->m_keys, compatible, !compatible);
|
char *const lhs = str2special_arena(mp->m_keys, compatible, !compatible, arena);
|
||||||
char *const mapmode = map_mode_to_chars(mp->m_mode);
|
char *mapmode = arena_alloc(arena, 7, false);
|
||||||
|
map_mode_to_chars(mp->m_mode, mapmode);
|
||||||
int noremap_value;
|
int noremap_value;
|
||||||
|
|
||||||
if (compatible) {
|
if (compatible) {
|
||||||
@ -2089,36 +2087,37 @@ static Dictionary mapblock_fill_dict(const mapblock_T *const mp, const char *lhs
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mp->m_luaref != LUA_NOREF) {
|
if (mp->m_luaref != LUA_NOREF) {
|
||||||
PUT(dict, "callback", LUAREF_OBJ(api_new_luaref(mp->m_luaref)));
|
PUT_C(dict, "callback", LUAREF_OBJ(api_new_luaref(mp->m_luaref)));
|
||||||
} else {
|
} else {
|
||||||
PUT(dict, "rhs", STRING_OBJ(compatible
|
String rhs = cstr_as_string(compatible
|
||||||
? cstr_to_string(mp->m_orig_str)
|
? mp->m_orig_str
|
||||||
: cstr_as_string(str2special_save(mp->m_str, false, true))));
|
: str2special_arena(mp->m_str, false, true, arena));
|
||||||
|
PUT_C(dict, "rhs", STRING_OBJ(rhs));
|
||||||
}
|
}
|
||||||
if (mp->m_desc != NULL) {
|
if (mp->m_desc != NULL) {
|
||||||
PUT(dict, "desc", CSTR_TO_OBJ(mp->m_desc));
|
PUT_C(dict, "desc", CSTR_AS_OBJ(mp->m_desc));
|
||||||
}
|
}
|
||||||
PUT(dict, "lhs", CSTR_AS_OBJ(lhs));
|
PUT_C(dict, "lhs", CSTR_AS_OBJ(lhs));
|
||||||
PUT(dict, "lhsraw", CSTR_TO_OBJ(mp->m_keys));
|
PUT_C(dict, "lhsraw", CSTR_AS_OBJ(mp->m_keys));
|
||||||
if (lhsrawalt != NULL) {
|
if (lhsrawalt != NULL) {
|
||||||
// Also add the value for the simplified entry.
|
// Also add the value for the simplified entry.
|
||||||
PUT(dict, "lhsrawalt", CSTR_TO_OBJ(lhsrawalt));
|
PUT_C(dict, "lhsrawalt", CSTR_AS_OBJ(lhsrawalt));
|
||||||
}
|
}
|
||||||
PUT(dict, "noremap", INTEGER_OBJ(noremap_value));
|
PUT_C(dict, "noremap", INTEGER_OBJ(noremap_value));
|
||||||
PUT(dict, "script", INTEGER_OBJ(mp->m_noremap == REMAP_SCRIPT ? 1 : 0));
|
PUT_C(dict, "script", INTEGER_OBJ(mp->m_noremap == REMAP_SCRIPT ? 1 : 0));
|
||||||
PUT(dict, "expr", INTEGER_OBJ(mp->m_expr ? 1 : 0));
|
PUT_C(dict, "expr", INTEGER_OBJ(mp->m_expr ? 1 : 0));
|
||||||
PUT(dict, "silent", INTEGER_OBJ(mp->m_silent ? 1 : 0));
|
PUT_C(dict, "silent", INTEGER_OBJ(mp->m_silent ? 1 : 0));
|
||||||
PUT(dict, "sid", INTEGER_OBJ(mp->m_script_ctx.sc_sid));
|
PUT_C(dict, "sid", INTEGER_OBJ(mp->m_script_ctx.sc_sid));
|
||||||
PUT(dict, "scriptversion", INTEGER_OBJ(1));
|
PUT_C(dict, "scriptversion", INTEGER_OBJ(1));
|
||||||
PUT(dict, "lnum", INTEGER_OBJ(mp->m_script_ctx.sc_lnum));
|
PUT_C(dict, "lnum", INTEGER_OBJ(mp->m_script_ctx.sc_lnum));
|
||||||
PUT(dict, "buffer", INTEGER_OBJ(buffer_value));
|
PUT_C(dict, "buffer", INTEGER_OBJ(buffer_value));
|
||||||
PUT(dict, "nowait", INTEGER_OBJ(mp->m_nowait ? 1 : 0));
|
PUT_C(dict, "nowait", INTEGER_OBJ(mp->m_nowait ? 1 : 0));
|
||||||
if (mp->m_replace_keycodes) {
|
if (mp->m_replace_keycodes) {
|
||||||
PUT(dict, "replace_keycodes", INTEGER_OBJ(1));
|
PUT_C(dict, "replace_keycodes", INTEGER_OBJ(1));
|
||||||
}
|
}
|
||||||
PUT(dict, "mode", CSTR_AS_OBJ(mapmode));
|
PUT_C(dict, "mode", CSTR_AS_OBJ(mapmode));
|
||||||
PUT(dict, "abbr", INTEGER_OBJ(abbr ? 1 : 0));
|
PUT_C(dict, "abbr", INTEGER_OBJ(abbr ? 1 : 0));
|
||||||
PUT(dict, "mode_bits", INTEGER_OBJ(mp->m_mode));
|
PUT_C(dict, "mode_bits", INTEGER_OBJ(mp->m_mode));
|
||||||
|
|
||||||
return dict;
|
return dict;
|
||||||
}
|
}
|
||||||
@ -2184,16 +2183,16 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact)
|
|||||||
rettv->vval.v_string = str2special_save(rhs, false, false);
|
rettv->vval.v_string = str2special_save(rhs, false, false);
|
||||||
}
|
}
|
||||||
} else if (rhs_lua != LUA_NOREF) {
|
} else if (rhs_lua != LUA_NOREF) {
|
||||||
rettv->vval.v_string = nlua_funcref_str(mp->m_luaref);
|
rettv->vval.v_string = nlua_funcref_str(mp->m_luaref, NULL);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Return a dictionary.
|
// Return a dictionary.
|
||||||
if (mp != NULL && (rhs != NULL || rhs_lua != LUA_NOREF)) {
|
if (mp != NULL && (rhs != NULL || rhs_lua != LUA_NOREF)) {
|
||||||
Dictionary dict = mapblock_fill_dict(mp,
|
Arena arena = ARENA_EMPTY;
|
||||||
did_simplify ? keys_simplified : NULL,
|
Dictionary dict = mapblock_fill_dict(mp, did_simplify ? keys_simplified : NULL,
|
||||||
buffer_local, abbr, true);
|
buffer_local, abbr, true, &arena);
|
||||||
object_to_vim(DICTIONARY_OBJ(dict), rettv, NULL);
|
object_to_vim_take_luaref(&DICTIONARY_OBJ(dict), rettv, true, NULL);
|
||||||
api_free_dictionary(dict);
|
arena_mem_free(arena_finish(&arena));
|
||||||
} else {
|
} else {
|
||||||
// Return an empty dictionary.
|
// Return an empty dictionary.
|
||||||
tv_dict_alloc_ret(rettv);
|
tv_dict_alloc_ret(rettv);
|
||||||
@ -2391,19 +2390,18 @@ void f_maplist(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
|
|||||||
char *keys_buf = NULL;
|
char *keys_buf = NULL;
|
||||||
bool did_simplify = false;
|
bool did_simplify = false;
|
||||||
|
|
||||||
char *lhs = str2special_save(mp->m_keys, true, false);
|
Arena arena = ARENA_EMPTY;
|
||||||
|
char *lhs = str2special_arena(mp->m_keys, true, false, &arena);
|
||||||
replace_termcodes(lhs, strlen(lhs), &keys_buf, 0, flags, &did_simplify,
|
replace_termcodes(lhs, strlen(lhs), &keys_buf, 0, flags, &did_simplify,
|
||||||
p_cpo);
|
p_cpo);
|
||||||
xfree(lhs);
|
|
||||||
|
|
||||||
Dictionary dict = mapblock_fill_dict(mp,
|
Dictionary dict = mapblock_fill_dict(mp, did_simplify ? keys_buf : NULL,
|
||||||
did_simplify ? keys_buf : NULL,
|
buffer_local, abbr, true, &arena);
|
||||||
buffer_local, abbr, true);
|
|
||||||
typval_T d = TV_INITIAL_VALUE;
|
typval_T d = TV_INITIAL_VALUE;
|
||||||
object_to_vim(DICTIONARY_OBJ(dict), &d, NULL);
|
object_to_vim_take_luaref(&DICTIONARY_OBJ(dict), &d, true, NULL);
|
||||||
assert(d.v_type == VAR_DICT);
|
assert(d.v_type == VAR_DICT);
|
||||||
tv_list_append_dict(rettv->vval.v_list, d.vval.v_dict);
|
tv_list_append_dict(rettv->vval.v_list, d.vval.v_dict);
|
||||||
api_free_dictionary(dict);
|
arena_mem_free(arena_finish(&arena));
|
||||||
xfree(keys_buf);
|
xfree(keys_buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2805,9 +2803,10 @@ fail_and_free:
|
|||||||
/// @param mode The abbreviation for the mode
|
/// @param mode The abbreviation for the mode
|
||||||
/// @param buf The buffer to get the mapping array. NULL for global
|
/// @param buf The buffer to get the mapping array. NULL for global
|
||||||
/// @returns Array of maparg()-like dictionaries describing mappings
|
/// @returns Array of maparg()-like dictionaries describing mappings
|
||||||
ArrayOf(Dictionary) keymap_array(String mode, buf_T *buf)
|
ArrayOf(Dictionary) keymap_array(String mode, buf_T *buf, Arena *arena)
|
||||||
{
|
{
|
||||||
Array mappings = ARRAY_DICT_INIT;
|
ArrayBuilder mappings = KV_INITIAL_VALUE;
|
||||||
|
kvi_init(mappings);
|
||||||
|
|
||||||
char *p = mode.size > 0 ? mode.data : "m";
|
char *p = mode.size > 0 ? mode.data : "m";
|
||||||
bool forceit = *p == '!';
|
bool forceit = *p == '!';
|
||||||
@ -2833,12 +2832,11 @@ ArrayOf(Dictionary) keymap_array(String mode, buf_T *buf)
|
|||||||
}
|
}
|
||||||
// Check for correct mode
|
// Check for correct mode
|
||||||
if (int_mode & current_maphash->m_mode) {
|
if (int_mode & current_maphash->m_mode) {
|
||||||
ADD(mappings,
|
kvi_push(mappings, DICTIONARY_OBJ(mapblock_fill_dict(current_maphash, NULL, buffer_value,
|
||||||
DICTIONARY_OBJ(mapblock_fill_dict(current_maphash, NULL,
|
is_abbrev, false, arena)));
|
||||||
buffer_value, is_abbrev, false)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return mappings;
|
return arena_take_arraybuilder(arena, &mappings);
|
||||||
}
|
}
|
||||||
|
@ -1713,6 +1713,39 @@ char *str2special_save(const char *const str, const bool replace_spaces, const b
|
|||||||
return (char *)ga.ga_data;
|
return (char *)ga.ga_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert string, replacing key codes with printables
|
||||||
|
///
|
||||||
|
/// Used for lhs or rhs of mappings.
|
||||||
|
///
|
||||||
|
/// @param[in] str String to convert.
|
||||||
|
/// @param[in] replace_spaces Convert spaces into `<Space>`, normally used for
|
||||||
|
/// lhs of mapping and keytrans(), but not rhs.
|
||||||
|
/// @param[in] replace_lt Convert `<` into `<lt>`.
|
||||||
|
///
|
||||||
|
/// @return [allocated] Converted string.
|
||||||
|
char *str2special_arena(const char *str, bool replace_spaces, bool replace_lt, Arena *arena)
|
||||||
|
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_MALLOC
|
||||||
|
FUNC_ATTR_NONNULL_RET
|
||||||
|
{
|
||||||
|
const char *p = str;
|
||||||
|
size_t len = 0;
|
||||||
|
while (*p) {
|
||||||
|
len += strlen(str2special(&p, replace_spaces, replace_lt));
|
||||||
|
}
|
||||||
|
|
||||||
|
char *buf = arena_alloc(arena, len + 1, false);
|
||||||
|
size_t pos = 0;
|
||||||
|
p = str;
|
||||||
|
while (*p) {
|
||||||
|
const char *s = str2special(&p, replace_spaces, replace_lt);
|
||||||
|
size_t s_len = strlen(s);
|
||||||
|
memcpy(buf + pos, s, s_len);
|
||||||
|
pos += s_len;
|
||||||
|
}
|
||||||
|
buf[pos] = NUL;
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
/// Convert character, replacing key with printable representation.
|
/// Convert character, replacing key with printable representation.
|
||||||
///
|
///
|
||||||
/// @param[in,out] sp String to convert. Is advanced to the next key code.
|
/// @param[in,out] sp String to convert. Is advanced to the next key code.
|
||||||
|
@ -682,12 +682,11 @@ static WBuffer *serialize_response(uint64_t channel_id, MsgpackRpcRequestHandler
|
|||||||
semsg("paste: %s", err->msg);
|
semsg("paste: %s", err->msg);
|
||||||
api_clear_error(err);
|
api_clear_error(err);
|
||||||
} else {
|
} else {
|
||||||
Array args = ARRAY_DICT_INIT;
|
MAXSIZE_TEMP_ARRAY(args, 2);
|
||||||
ADD(args, INTEGER_OBJ(err->type));
|
ADD_C(args, INTEGER_OBJ(err->type));
|
||||||
ADD(args, CSTR_TO_OBJ(err->msg));
|
ADD_C(args, CSTR_AS_OBJ(err->msg));
|
||||||
msgpack_rpc_serialize_request(0, cstr_as_string("nvim_error_event"),
|
msgpack_rpc_serialize_request(0, cstr_as_string("nvim_error_event"),
|
||||||
args, &pac);
|
args, &pac);
|
||||||
api_free_array(args);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
msgpack_rpc_serialize_response(response_id, err, arg, &pac);
|
msgpack_rpc_serialize_response(response_id, err, arg, &pac);
|
||||||
|
@ -230,7 +230,7 @@ int os_proc_children(int ppid, int **proc_list, size_t *proc_count)
|
|||||||
///
|
///
|
||||||
/// @param pid Process to inspect.
|
/// @param pid Process to inspect.
|
||||||
/// @return Map of process properties, empty on error.
|
/// @return Map of process properties, empty on error.
|
||||||
Dictionary os_proc_info(int pid)
|
Dictionary os_proc_info(int pid, Arena *arena)
|
||||||
{
|
{
|
||||||
Dictionary pinfo = ARRAY_DICT_INIT;
|
Dictionary pinfo = ARRAY_DICT_INIT;
|
||||||
PROCESSENTRY32 pe;
|
PROCESSENTRY32 pe;
|
||||||
@ -258,9 +258,10 @@ Dictionary os_proc_info(int pid)
|
|||||||
CloseHandle(h);
|
CloseHandle(h);
|
||||||
|
|
||||||
if (pe.th32ProcessID == (DWORD)pid) {
|
if (pe.th32ProcessID == (DWORD)pid) {
|
||||||
PUT(pinfo, "pid", INTEGER_OBJ(pid));
|
pinfo = arena_dict(arena, 3);
|
||||||
PUT(pinfo, "ppid", INTEGER_OBJ((int)pe.th32ParentProcessID));
|
PUT_C(pinfo, "pid", INTEGER_OBJ(pid));
|
||||||
PUT(pinfo, "name", CSTR_TO_OBJ(pe.szExeFile));
|
PUT_C(pinfo, "ppid", INTEGER_OBJ((int)pe.th32ParentProcessID));
|
||||||
|
PUT_C(pinfo, "name", CSTR_TO_ARENA_OBJ(arena, pe.szExeFile));
|
||||||
}
|
}
|
||||||
|
|
||||||
return pinfo;
|
return pinfo;
|
||||||
|
@ -2166,6 +2166,47 @@ int kv_do_printf(StringBuilder *str, const char *fmt, ...)
|
|||||||
return printed;
|
return printed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String arena_printf(Arena *arena, const char *fmt, ...)
|
||||||
|
FUNC_ATTR_PRINTF(2, 3)
|
||||||
|
{
|
||||||
|
size_t remaining = 0;
|
||||||
|
char *buf = NULL;
|
||||||
|
if (arena) {
|
||||||
|
if (!arena->cur_blk) {
|
||||||
|
alloc_block(arena);
|
||||||
|
}
|
||||||
|
|
||||||
|
// happy case, we can fit the printed string in the rest of the current
|
||||||
|
// block (one pass):
|
||||||
|
remaining = arena->size - arena->pos;
|
||||||
|
buf = arena->cur_blk + arena->pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
int printed = vsnprintf(buf, remaining, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
if (printed < 0) {
|
||||||
|
return (String)STRING_INIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// printed string didn't fit, allocate and try again
|
||||||
|
if ((size_t)printed >= remaining) {
|
||||||
|
buf = arena_alloc(arena, (size_t)printed + 1, false);
|
||||||
|
va_start(ap, fmt);
|
||||||
|
printed = vsnprintf(buf, (size_t)printed + 1, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
if (printed < 0) {
|
||||||
|
return (String)STRING_INIT;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
arena->pos += (size_t)printed + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cbuf_as_string(buf, (size_t)printed);
|
||||||
|
}
|
||||||
|
|
||||||
/// Reverse text into allocated memory.
|
/// Reverse text into allocated memory.
|
||||||
///
|
///
|
||||||
/// @return the allocated string.
|
/// @return the allocated string.
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include "auto/config.h"
|
#include "auto/config.h"
|
||||||
#include "klib/kvec.h"
|
#include "klib/kvec.h"
|
||||||
|
#include "nvim/api/private/defs.h"
|
||||||
#include "nvim/eval/typval_defs.h" // IWYU pragma: keep
|
#include "nvim/eval/typval_defs.h" // IWYU pragma: keep
|
||||||
#include "nvim/func_attr.h"
|
#include "nvim/func_attr.h"
|
||||||
#include "nvim/os/os_defs.h"
|
#include "nvim/os/os_defs.h"
|
||||||
|
@ -1434,28 +1434,28 @@ static void show_verbose_terminfo(TUIData *tui)
|
|||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
Array chunks = ARRAY_DICT_INIT;
|
MAXSIZE_TEMP_ARRAY(chunks, 3);
|
||||||
Array title = ARRAY_DICT_INIT;
|
MAXSIZE_TEMP_ARRAY(title, 2);
|
||||||
ADD(title, CSTR_TO_OBJ("\n\n--- Terminal info --- {{{\n"));
|
ADD_C(title, CSTR_AS_OBJ("\n\n--- Terminal info --- {{{\n"));
|
||||||
ADD(title, CSTR_TO_OBJ("Title"));
|
ADD_C(title, CSTR_AS_OBJ("Title"));
|
||||||
ADD(chunks, ARRAY_OBJ(title));
|
ADD_C(chunks, ARRAY_OBJ(title));
|
||||||
Array info = ARRAY_DICT_INIT;
|
MAXSIZE_TEMP_ARRAY(info, 2);
|
||||||
String str = terminfo_info_msg(ut, tui->term);
|
String str = terminfo_info_msg(ut, tui->term);
|
||||||
ADD(info, STRING_OBJ(str));
|
ADD_C(info, STRING_OBJ(str));
|
||||||
ADD(chunks, ARRAY_OBJ(info));
|
ADD_C(chunks, ARRAY_OBJ(info));
|
||||||
Array end_fold = ARRAY_DICT_INIT;
|
MAXSIZE_TEMP_ARRAY(end_fold, 2);
|
||||||
ADD(end_fold, CSTR_TO_OBJ("}}}\n"));
|
ADD_C(end_fold, CSTR_AS_OBJ("}}}\n"));
|
||||||
ADD(end_fold, CSTR_TO_OBJ("Title"));
|
ADD_C(end_fold, CSTR_AS_OBJ("Title"));
|
||||||
ADD(chunks, ARRAY_OBJ(end_fold));
|
ADD_C(chunks, ARRAY_OBJ(end_fold));
|
||||||
|
|
||||||
Array args = ARRAY_DICT_INIT;
|
MAXSIZE_TEMP_ARRAY(args, 3);
|
||||||
ADD(args, ARRAY_OBJ(chunks));
|
ADD_C(args, ARRAY_OBJ(chunks));
|
||||||
ADD(args, BOOLEAN_OBJ(true)); // history
|
ADD_C(args, BOOLEAN_OBJ(true)); // history
|
||||||
Dictionary opts = ARRAY_DICT_INIT;
|
MAXSIZE_TEMP_DICT(opts, 1);
|
||||||
PUT(opts, "verbose", BOOLEAN_OBJ(true));
|
PUT_C(opts, "verbose", BOOLEAN_OBJ(true));
|
||||||
ADD(args, DICTIONARY_OBJ(opts));
|
ADD_C(args, DICTIONARY_OBJ(opts));
|
||||||
rpc_send_event(ui_client_channel_id, "nvim_echo", args);
|
rpc_send_event(ui_client_channel_id, "nvim_echo", args);
|
||||||
api_free_array(args);
|
xfree(str.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tui_suspend(TUIData *tui)
|
void tui_suspend(TUIData *tui)
|
||||||
|
@ -584,7 +584,7 @@ static void uc_list(char *name, size_t name_len)
|
|||||||
msg_outtrans(IObuff, 0);
|
msg_outtrans(IObuff, 0);
|
||||||
|
|
||||||
if (cmd->uc_luaref != LUA_NOREF) {
|
if (cmd->uc_luaref != LUA_NOREF) {
|
||||||
char *fn = nlua_funcref_str(cmd->uc_luaref);
|
char *fn = nlua_funcref_str(cmd->uc_luaref, NULL);
|
||||||
msg_puts_attr(fn, HL_ATTR(HLF_8));
|
msg_puts_attr(fn, HL_ATTR(HLF_8));
|
||||||
xfree(fn);
|
xfree(fn);
|
||||||
// put the description on a new line
|
// put the description on a new line
|
||||||
|
Loading…
Reference in New Issue
Block a user