#include <assert.h>
#include <lauxlib.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "klib/kvec.h"
#include "nvim/api/extmark.h"
#include "nvim/api/keysets_defs.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/dispatch.h"
#include "nvim/api/private/helpers.h"
#include "nvim/api/private/validate.h"
#include "nvim/buffer_defs.h"
#include "nvim/charset.h"
#include "nvim/decoration.h"
#include "nvim/decoration_provider.h"
#include "nvim/drawscreen.h"
#include "nvim/extmark.h"
#include "nvim/func_attr.h"
#include "nvim/grid.h"
#include "nvim/highlight_group.h"
#include "nvim/marktree.h"
#include "nvim/mbyte.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/pos_defs.h"
#include "nvim/sign.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "api/extmark.c.generated.h"
#endif
void api_extmark_free_all_mem(void)
{
String name;
map_foreach_key(&namespace_ids, name, {
xfree(name.data);
})
map_destroy(String, &namespace_ids);
}
/// Creates a new namespace or gets an existing one. \*namespace\*
///
/// Namespaces are used for buffer highlights and virtual text, see
/// |nvim_buf_add_highlight()| and |nvim_buf_set_extmark()|.
///
/// Namespaces can be named or anonymous. If `name` matches an existing
/// namespace, the associated id is returned. If `name` is an empty string
/// a new, anonymous namespace is created.
///
/// @param name Namespace name or empty string
/// @return Namespace id
Integer nvim_create_namespace(String name)
FUNC_API_SINCE(5)
{
handle_T id = map_get(String, int)(&namespace_ids, name);
if (id > 0) {
return id;
}
id = next_namespace_id++;
if (name.size > 0) {
String name_alloc = copy_string(name, NULL);
map_put(String, int)(&namespace_ids, name_alloc, id);
}
return (Integer)id;
}
/// Gets existing, non-anonymous |namespace|s.
///
/// @return dict that maps from names to namespace ids.
Dictionary nvim_get_namespaces(void)
FUNC_API_SINCE(5)
{
Dictionary retval = ARRAY_DICT_INIT;
String name;
handle_T id;
map_foreach(&namespace_ids, name, id, {
PUT(retval, name.data, INTEGER_OBJ(id));
})
return retval;
}
const char *describe_ns(NS ns_id, const char *unknown)
{
String name;
handle_T id;
map_foreach(&namespace_ids, name, id, {
if ((NS)id == ns_id && name.size) {
return name.data;
}
})
return unknown;
}
// Is the Namespace in use?
bool ns_initialized(uint32_t ns)
{
if (ns < 1) {
return false;
}
return ns < (uint32_t)next_namespace_id;
}
Array virt_text_to_array(VirtText vt, bool hl_name)
{
Array chunks = ARRAY_DICT_INIT;
Array hl_array = ARRAY_DICT_INIT;
for (size_t i = 0; i < kv_size(vt); i++) {
char *text = kv_A(vt, i).text;
int hl_id = kv_A(vt, i).hl_id;
if (text == NULL) {
if (hl_id > 0) {
ADD(hl_array, hl_group_name(hl_id, hl_name));
}
continue;
}
Array chunk = ARRAY_DICT_INIT;
ADD(chunk, CSTR_TO_OBJ(text));
if (hl_array.size > 0) {
if (hl_id > 0) {
ADD(hl_array, hl_group_name(hl_id, hl_name));
}
ADD(chunk, ARRAY_OBJ(hl_array));
hl_array = (Array)ARRAY_DICT_INIT;
} else if (hl_id > 0) {
ADD(chunk, hl_group_name(hl_id, hl_name));
}
ADD(chunks, ARRAY_OBJ(chunk));
}
assert(hl_array.size == 0);
return chunks;
}
static Array extmark_to_array(MTPair extmark, bool id, bool add_dict, bool hl_name)
{
MTKey start = extmark.start;
Array rv = ARRAY_DICT_INIT;
if (id) {
ADD(rv, INTEGER_OBJ((Integer)start.id));
}
ADD(rv, INTEGER_OBJ(start.pos.row));
ADD(rv, INTEGER_OBJ(start.pos.col));
if (add_dict) {
Dictionary dict = ARRAY_DICT_INIT;
PUT(dict, "ns_id", INTEGER_OBJ((Integer)start.ns));
PUT(dict, "right_gravity", BOOLEAN_OBJ(mt_right(start)));
if (extmark.end_pos.row >= 0) {
PUT(dict, "end_row", INTEGER_OBJ(extmark.end_pos.row));
PUT(dict, "end_col", INTEGER_OBJ(extmark.end_pos.col));
PUT(dict, "end_right_gravity", BOOLEAN_OBJ(extmark.end_right_gravity));
}
if (mt_no_undo(start)) {
PUT(dict, "undo_restore", BOOLEAN_OBJ(false));
}
if (mt_invalidate(start)) {
PUT(dict, "invalidate", BOOLEAN_OBJ(true));
}
if (mt_invalid(start)) {
PUT(dict, "invalid", BOOLEAN_OBJ(true));
}
decor_to_dict_legacy(&dict, mt_decor(start), hl_name);
ADD(rv, DICTIONARY_OBJ(dict));
}
return rv;
}
/// Gets the position (0-indexed) of an |extmark|.
///
/// @param buffer Buffer handle, or 0 for current buffer
/// @param ns_id Namespace id from |nvim_create_namespace()|
/// @param id Extmark id
/// @param opts Optional parameters. Keys:
/// - details: Whether t
|