aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbfredl <bjorn.linse@gmail.com>2024-07-02 13:45:50 +0200
committerbfredl <bjorn.linse@gmail.com>2024-08-05 11:12:44 +0200
commitf926cc32c9262b6254e2843276b951cef9da1afe (patch)
tree56f13240abae6ec0f3b13022b011da84948788c0
parent0c2860d9e5ec5417a94db6e3edd237578b76d418 (diff)
downloadrneovim-f926cc32c9262b6254e2843276b951cef9da1afe.tar.gz
rneovim-f926cc32c9262b6254e2843276b951cef9da1afe.tar.bz2
rneovim-f926cc32c9262b6254e2843276b951cef9da1afe.zip
refactor(shada): rework msgpack decoding without msgpack-c
This also makes shada reading slightly faster due to avoiding some copying and allocation. Use keysets to drive decoding of msgpack maps for shada entries.
-rwxr-xr-xscripts/gen_eval_files.lua3
-rw-r--r--src/nvim/api/command.c6
-rw-r--r--src/nvim/api/keysets_defs.h42
-rw-r--r--src/nvim/api/private/defs.h10
-rw-r--r--src/nvim/api/private/helpers.c11
-rw-r--r--src/nvim/api/ui.c1
-rw-r--r--src/nvim/buffer.c2
-rw-r--r--src/nvim/buffer_defs.h2
-rw-r--r--src/nvim/cmdhist.c10
-rw-r--r--src/nvim/cmdhist.h2
-rw-r--r--src/nvim/context.h1
-rw-r--r--src/nvim/eval.c99
-rw-r--r--src/nvim/eval/decode.c307
-rw-r--r--src/nvim/eval/decode.h2
-rw-r--r--src/nvim/eval/encode.c5
-rw-r--r--src/nvim/eval/encode.h1
-rw-r--r--src/nvim/eval/funcs.c128
-rw-r--r--src/nvim/eval/typval.c5
-rw-r--r--src/nvim/ex_cmds.c6
-rw-r--r--src/nvim/ex_cmds_defs.h2
-rw-r--r--src/nvim/generators/c_grammar.lua6
-rw-r--r--src/nvim/generators/gen_api_dispatch.lua27
-rw-r--r--src/nvim/generators/hashy.lua22
-rw-r--r--src/nvim/main.c1
-rw-r--r--src/nvim/mark.c2
-rw-r--r--src/nvim/mark_defs.h8
-rw-r--r--src/nvim/msgpack_rpc/channel.c3
-rw-r--r--src/nvim/msgpack_rpc/channel_defs.h1
-rw-r--r--src/nvim/msgpack_rpc/unpacker.c196
-rw-r--r--src/nvim/msgpack_rpc/unpacker.h2
-rw-r--r--src/nvim/ops.c16
-rw-r--r--src/nvim/ops.h2
-rw-r--r--src/nvim/os/fileio.c16
-rw-r--r--src/nvim/search.c2
-rw-r--r--src/nvim/search.h2
-rw-r--r--src/nvim/shada.c1083
-rw-r--r--src/nvim/shada.h2
-rw-r--r--src/nvim/types_defs.h6
-rw-r--r--src/nvim/ui_client.c2
-rw-r--r--src/nvim/undo.c3
-rw-r--r--test/functional/shada/errors_spec.lua95
-rw-r--r--test/unit/eval/encode_spec.lua36
42 files changed, 1019 insertions, 1159 deletions
diff --git a/scripts/gen_eval_files.lua b/scripts/gen_eval_files.lua
index b490e7b480..fc2fadc440 100755
--- a/scripts/gen_eval_files.lua
+++ b/scripts/gen_eval_files.lua
@@ -376,6 +376,9 @@ end
--- @param fun vim.EvalFn
--- @param write fun(line: string)
local function render_api_keyset_meta(_f, fun, write)
+ if string.sub(fun.name, 1, 1) == '_' then
+ return -- not exported
+ end
write('')
write('--- @class vim.api.keyset.' .. fun.name)
for _, p in ipairs(fun.params) do
diff --git a/src/nvim/api/command.c b/src/nvim/api/command.c
index 5ad439af9c..78be0a2cf7 100644
--- a/src/nvim/api/command.c
+++ b/src/nvim/api/command.c
@@ -515,7 +515,7 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Arena
if (HAS_KEY(cmd, cmd, magic)) {
Dict(cmd_magic) magic[1] = KEYDICT_INIT;
- if (!api_dict_to_keydict(magic, KeyDict_cmd_magic_get_field, cmd->magic, err)) {
+ if (!api_dict_to_keydict(magic, DictHash(cmd_magic), cmd->magic, err)) {
goto end;
}
@@ -533,14 +533,14 @@ String nvim_cmd(uint64_t channel_id, Dict(cmd) *cmd, Dict(cmd_opts) *opts, Arena
if (HAS_KEY(cmd, cmd, mods)) {
Dict(cmd_mods) mods[1] = KEYDICT_INIT;
- if (!api_dict_to_keydict(mods, KeyDict_cmd_mods_get_field, cmd->mods, err)) {
+ if (!api_dict_to_keydict(mods, DictHash(cmd_mods), cmd->mods, err)) {
goto end;
}
if (HAS_KEY(mods, cmd_mods, filter)) {
Dict(cmd_mods_filter) filter[1] = KEYDICT_INIT;
- if (!api_dict_to_keydict(&filter, KeyDict_cmd_mods_filter_get_field,
+ if (!api_dict_to_keydict(&filter, DictHash(cmd_mods_filter),
mods->filter, err)) {
goto end;
}
diff --git a/src/nvim/api/keysets_defs.h b/src/nvim/api/keysets_defs.h
index cc2ef981b5..ce4e3d56e1 100644
--- a/src/nvim/api/keysets_defs.h
+++ b/src/nvim/api/keysets_defs.h
@@ -103,7 +103,7 @@ typedef struct {
Object nargs;
Object preview;
Object range;
- Boolean register_;
+ Boolean register_ DictKey(register);
} Dict(user_command);
typedef struct {
@@ -170,7 +170,7 @@ typedef struct {
Boolean reverse;
Boolean altfont;
Boolean nocombine;
- Boolean default_;
+ Boolean default_ DictKey(default);
Object cterm;
Object foreground;
Object fg;
@@ -392,3 +392,41 @@ typedef struct {
OptionalKeys is_set__ns_opts_;
Array wins;
} Dict(ns_opts);
+
+typedef struct {
+ OptionalKeys is_set___shada_search_pat_;
+ Boolean magic DictKey(sm);
+ Boolean smartcase DictKey(sc);
+ Boolean has_line_offset DictKey(sl);
+ Boolean place_cursor_at_end DictKey(se);
+ Boolean is_last_used DictKey(su);
+ Boolean is_substitute_pattern DictKey(ss);
+ Boolean highlighted DictKey(sh);
+ Boolean search_backward DictKey(sb);
+ Integer offset DictKey(so);
+ String pat DictKey(sp);
+} Dict(_shada_search_pat);
+
+typedef struct {
+ OptionalKeys is_set___shada_mark_;
+ Integer n;
+ Integer l;
+ Integer c;
+ String f;
+} Dict(_shada_mark);
+
+typedef struct {
+ OptionalKeys is_set___shada_register_;
+ StringArray rc;
+ Boolean ru;
+ Integer rt;
+ Integer n;
+ Integer rw;
+} Dict(_shada_register);
+
+typedef struct {
+ OptionalKeys is_set___shada_buflist_item_;
+ Integer l;
+ Integer c;
+ String f;
+} Dict(_shada_buflist_item);
diff --git a/src/nvim/api/private/defs.h b/src/nvim/api/private/defs.h
index 94e2d76cbe..ac3404cf86 100644
--- a/src/nvim/api/private/defs.h
+++ b/src/nvim/api/private/defs.h
@@ -19,6 +19,8 @@
# define ArrayOf(...) Array
# define DictionaryOf(...) Dictionary
# define Dict(name) KeyDict_##name
+# define DictHash(name) KeyDict_##name##_get_field
+# define DictKey(name)
# include "api/private/defs.h.inline.generated.h"
#endif
@@ -88,6 +90,8 @@ typedef kvec_t(Object) Array;
typedef struct key_value_pair KeyValuePair;
typedef kvec_t(KeyValuePair) Dictionary;
+typedef kvec_t(String) StringArray;
+
typedef enum {
kObjectTypeNil = 0,
kObjectTypeBoolean,
@@ -103,6 +107,10 @@ typedef enum {
kObjectTypeTabpage,
} ObjectType;
+typedef enum {
+ kUnpackTypeStringArray = -1,
+} UnpackType;
+
/// Value by which objects represented as EXT type are shifted
///
/// Subtracted when packing, added when unpacking. Used to allow moving
@@ -140,7 +148,7 @@ typedef struct {
typedef struct {
char *str;
size_t ptr_off;
- ObjectType type; // kObjectTypeNil == untyped
+ int type; // ObjectType or UnpackType. kObjectTypeNil == untyped
int opt_index;
bool is_hlgroup;
} KeySetLink;
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index ac621b1486..017265e0d3 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -1,6 +1,5 @@
#include <assert.h>
#include <limits.h>
-#include <msgpack/unpack.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
@@ -922,15 +921,17 @@ bool api_dict_to_keydict(void *retval, FieldHashfn hashy, Dictionary dict, Error
} else if (value->type == kObjectTypeDictionary) {
*val = value->data.dictionary;
} else {
- api_err_exp(err, field->str, api_typename(field->type), api_typename(value->type));
+ api_err_exp(err, field->str, api_typename((ObjectType)field->type),
+ api_typename(value->type));
return false;
}
} else if (field->type == kObjectTypeBuffer || field->type == kObjectTypeWindow
|| field->type == kObjectTypeTabpage) {
- if (value->type == kObjectTypeInteger || value->type == field->type) {
+ if (value->type == kObjectTypeInteger || value->type == (ObjectType)field->type) {
*(handle_T *)mem = (handle_T)value->data.integer;
} else {
- api_err_exp(err, field->str, api_typename(field->type), api_typename(value->type));
+ api_err_exp(err, field->str, api_typename((ObjectType)field->type),
+ api_typename(value->type));
return false;
}
} else if (field->type == kObjectTypeLuaRef) {
@@ -980,7 +981,7 @@ Dictionary api_keydict_to_dict(void *value, KeySetLink *table, size_t max_size,
} else if (field->type == kObjectTypeBuffer || field->type == kObjectTypeWindow
|| field->type == kObjectTypeTabpage) {
val.data.integer = *(handle_T *)mem;
- val.type = field->type;
+ val.type = (ObjectType)field->type;
} else if (field->type == kObjectTypeLuaRef) {
// do nothing
} else {
diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c
index 852b8b9b48..82a5ff5f8e 100644
--- a/src/nvim/api/ui.c
+++ b/src/nvim/api/ui.c
@@ -1,6 +1,5 @@
#include <assert.h>
#include <inttypes.h>
-#include <msgpack/pack.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index 2fc684b412..0c301bd5e2 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -868,7 +868,7 @@ static void free_buffer(buf_T *buf)
}
unref_var_dict(buf->b_vars);
aubuflocal_remove(buf);
- tv_dict_unref(buf->additional_data);
+ xfree(buf->additional_data);
xfree(buf->b_prompt_text);
callback_free(&buf->b_prompt_callback);
callback_free(&buf->b_prompt_interrupt);
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 221a86a907..8e076646c3 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -712,7 +712,7 @@ struct file_buffer {
Terminal *terminal; // Terminal instance associated with the buffer
- dict_T *additional_data; // Additional data from shada file if any.
+ AdditionalData *additional_data; // Additional data from shada file if any.
int b_mapped_ctrl_c; // modes where CTRL-C is mapped
diff --git a/src/nvim/cmdhist.c b/src/nvim/cmdhist.c
index ab05ae1cfc..47a4ffba9e 100644
--- a/src/nvim/cmdhist.c
+++ b/src/nvim/cmdhist.c
@@ -190,7 +190,7 @@ static inline void hist_free_entry(histentry_T *hisptr)
FUNC_ATTR_NONNULL_ALL
{
xfree(hisptr->hisstr);
- tv_list_unref(hisptr->additional_elements);
+ xfree(hisptr->additional_data);
clear_hist_entry(hisptr);
}
@@ -237,7 +237,7 @@ static int in_history(int type, const char *str, int move_to_front, int sep)
return false;
}
- list_T *const list = history[type][i].additional_elements;
+ AdditionalData *ad = history[type][i].additional_data;
char *const save_hisstr = history[type][i].hisstr;
while (i != hisidx[type]) {
if (++i >= hislen) {
@@ -246,11 +246,11 @@ static int in_history(int type, const char *str, int move_to_front, int sep)
history[type][last_i] = history[type][i];
last_i = i;
}
- tv_list_unref(list);
+ xfree(ad);
history[type][i].hisnum = ++hisnum[type];
history[type][i].hisstr = save_hisstr;
history[type][i].timestamp = os_time();
- history[type][i].additional_elements = NULL;
+ history[type][i].additional_data = NULL;
return true;
}
@@ -337,7 +337,7 @@ void add_to_history(int histype, const char *new_entry, size_t new_entrylen, boo
// Store the separator after the NUL of the string.
hisptr->hisstr = xstrnsave(new_entry, new_entrylen + 2);
hisptr->timestamp = os_time();
- hisptr->additional_elements = NULL;
+ hisptr->additional_data = NULL;
hisptr->hisstr[new_entrylen + 1] = (char)sep;
hisptr->hisnum = ++hisnum[histype];
diff --git a/src/nvim/cmdhist.h b/src/nvim/cmdhist.h
index 43be397cee..4df4b09e68 100644
--- a/src/nvim/cmdhist.h
+++ b/src/nvim/cmdhist.h
@@ -24,7 +24,7 @@ typedef struct {
int hisnum; ///< Entry identifier number.
char *hisstr; ///< Actual entry, separator char after the NUL.
Timestamp timestamp; ///< Time when entry was added.
- list_T *additional_elements; ///< Additional entries from ShaDa file.
+ AdditionalData *additional_data; ///< Additional entries from ShaDa file.
} histentry_T;
#ifdef INCLUDE_GENERATED_DECLARATIONS
diff --git a/src/nvim/context.h b/src/nvim/context.h
index 0bb7138b6c..4375030fbc 100644
--- a/src/nvim/context.h
+++ b/src/nvim/context.h
@@ -1,6 +1,5 @@
#pragma once
-#include <msgpack/sbuffer.h>
#include <stddef.h>
#include "klib/kvec.h"
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 0180d37ad8..31e4953a5c 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -4788,19 +4788,6 @@ bool garbage_collect(bool testing)
FOR_ALL_BUFFERS(buf) {
// buffer-local variables
ABORTING(set_ref_in_item)(&buf->b_bufvar.di_tv, copyID, NULL, NULL);
- // buffer marks (ShaDa additional data)
- ABORTING(set_ref_in_fmark)(buf->b_last_cursor, copyID);
- ABORTING(set_ref_in_fmark)(buf->b_last_insert, copyID);
- ABORTING(set_ref_in_fmark)(buf->b_last_change, copyID);
- for (size_t i = 0; i < NMARKS; i++) {
- ABORTING(set_ref_in_fmark)(buf->b_namedm[i], copyID);
- }
- // buffer change list (ShaDa additional data)
- for (int i = 0; i < buf->b_changelistlen; i++) {
- ABORTING(set_ref_in_fmark)(buf->b_changelist[i], copyID);
- }
- // buffer ShaDa additional data
- ABORTING(set_ref_dict)(buf->additional_data, copyID);
// buffer callback functions
ABORTING(set_ref_in_callback)(&buf->b_prompt_callback, copyID, NULL, NULL);
@@ -4823,10 +4810,6 @@ bool garbage_collect(bool testing)
FOR_ALL_TAB_WINDOWS(tp, wp) {
// window-local variables
ABORTING(set_ref_in_item)(&wp->w_winvar.di_tv, copyID, NULL, NULL);
- // window jump list (ShaDa additional data)
- for (int i = 0; i < wp->w_jumplistlen; i++) {
- ABORTING(set_ref_in_fmark)(wp->w_jumplist[i].fmark, copyID);
- }
}
// window-local variables in autocmd windows
for (int i = 0; i < AUCMD_WIN_COUNT; i++) {
@@ -4843,9 +4826,6 @@ bool garbage_collect(bool testing)
char name = NUL;
bool is_unnamed = false;
reg_iter = op_global_reg_iter(reg_iter, &name, &reg, &is_unnamed);
- if (name != NUL) {
- ABORTING(set_ref_dict)(reg.additional_data, copyID);
- }
} while (reg_iter != NULL);
}
@@ -4856,9 +4836,6 @@ bool garbage_collect(bool testing)
xfmark_T fm;
char name = NUL;
mark_iter = mark_global_iter(mark_iter, &name, &fm);
- if (name != NUL) {
- ABORTING(set_ref_dict)(fm.fmark.additional_data, copyID);
- }
} while (mark_iter != NULL);
}
@@ -4900,36 +4877,6 @@ bool garbage_collect(bool testing)
// v: vars
ABORTING(set_ref_in_ht)(&vimvarht, copyID, NULL);
- // history items (ShaDa additional elements)
- if (p_hi) {
- for (int i = 0; i < HIST_COUNT; i++) {
- const void *iter = NULL;
- do {
- histentry_T hist;
- iter = hist_iter(iter, (uint8_t)i, false, &hist);
- if (hist.hisstr != NULL) {
- ABORTING(set_ref_list)(hist.additional_elements, copyID);
- }
- } while (iter != NULL);
- }
- }
-
- // previously used search/substitute patterns (ShaDa additional data)
- {
- SearchPattern pat;
- get_search_pattern(&pat);
- ABORTING(set_ref_dict)(pat.additional_data, copyID);
- get_substitute_pattern(&pat);
- ABORTING(set_ref_dict)(pat.additional_data, copyID);
- }
-
- // previously used replacement string
- {
- SubReplacementString sub;
- sub_get_replacement(&sub);
- ABORTING(set_ref_list)(sub.additional_elements, copyID);
- }
-
ABORTING(set_ref_in_quickfix)(copyID);
bool did_free = false;
@@ -5211,52 +5158,6 @@ bool set_ref_in_item(typval_T *tv, int copyID, ht_stack_T **ht_stack, list_stack
return abort;
}
-/// Mark all lists and dicts referenced in given mark
-///
-/// @return true if setting references failed somehow.
-static inline bool set_ref_in_fmark(fmark_T fm, int copyID)
- FUNC_ATTR_WARN_UNUSED_RESULT
-{
- if (fm.additional_data != NULL
- && fm.additional_data->dv_copyID != copyID) {
- fm.additional_data->dv_copyID = copyID;
- return set_ref_in_ht(&fm.additional_data->dv_hashtab, copyID, NULL);
- }
- return false;
-}
-
-/// Mark all lists and dicts referenced in given list and the list itself
-///
-/// @return true if setting references failed somehow.
-static inline bool set_ref_list(list_T *list, int copyID)
- FUNC_ATTR_WARN_UNUSED_RESULT
-{
- if (list != NULL) {
- typval_T tv = (typval_T) {
- .v_type = VAR_LIST,
- .vval = { .v_list = list }
- };
- return set_ref_in_item(&tv, copyID, NULL, NULL);
- }
- return false;
-}
-
-/// Mark all lists and dicts referenced in given dict and the dict itself
-///
-/// @return true if setting references failed somehow.
-static inline bool set_ref_dict(dict_T *dict, int copyID)
- FUNC_ATTR_WARN_UNUSED_RESULT
-{
- if (dict != NULL) {
- typval_T tv = (typval_T) {
- .v_type = VAR_DICT,
- .vval = { .v_dict = dict }
- };
- return set_ref_in_item(&tv, copyID, NULL, NULL);
- }
- return false;
-}
-
/// Get the key for #{key: val} into "tv" and advance "arg".
///
/// @return FAIL when there is no valid key.
diff --git a/src/nvim/eval/decode.c b/src/nvim/eval/decode.c
index 13cd3274dd..1ff8716763 100644
--- a/src/nvim/eval/decode.c
+++ b/src/nvim/eval/decode.c
@@ -1,5 +1,4 @@
#include <assert.h>
-#include <msgpack/object.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
@@ -7,6 +6,7 @@
#include <string.h>
#include "klib/kvec.h"
+#include "mpack/object.h"
#include "nvim/ascii_defs.h"
#include "nvim/charset.h"
#include "nvim/eval.h"
@@ -885,173 +885,250 @@ json_decode_string_ret:
#undef DICT_LEN
-/// Convert msgpack object to a Vimscript one
-int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
- FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+static void positive_integer_to_special_typval(typval_T *rettv, uint64_t val)
{
- switch (mobj.type) {
- case MSGPACK_OBJECT_NIL:
+ if (val <= VARNUMBER_MAX) {
*rettv = (typval_T) {
+ .v_type = VAR_NUMBER,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_number = (varnumber_T)val },
+ };
+ } else {
+ list_T *const list = tv_list_alloc(4);
+ tv_list_ref(list);
+ create_special_dict(rettv, kMPInteger, ((typval_T) {
+ .v_type = VAR_LIST,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_list = list },
+ }));
+ tv_list_append_number(list, 1);
+ tv_list_append_number(list, (varnumber_T)((val >> 62) & 0x3));
+ tv_list_append_number(list, (varnumber_T)((val >> 31) & 0x7FFFFFFF));
+ tv_list_append_number(list, (varnumber_T)(val & 0x7FFFFFFF));
+ }
+}
+
+static void typval_parse_enter(mpack_parser_t *parser, mpack_node_t *node)
+{
+ typval_T *result = NULL;
+
+ mpack_node_t *parent = MPACK_PARENT_NODE(node);
+ if (parent) {
+ switch (parent->tok.type) {
+ case MPACK_TOKEN_ARRAY: {
+ list_T *list = parent->data[1].p;
+ result = tv_list_append_owned_tv(list, (typval_T) { .v_type = VAR_UNKNOWN });
+ break;
+ }
+ case MPACK_TOKEN_MAP: {
+ typval_T(*items)[2] = parent->data[1].p;
+ result = &items[parent->pos][parent->key_visited];
+ break;
+ }
+
+ case MPACK_TOKEN_STR:
+ case MPACK_TOKEN_BIN:
+ case MPACK_TOKEN_EXT:
+ assert(node->tok.type == MPACK_TOKEN_CHUNK);
+ break;
+
+ default:
+ abort();
+ }
+ } else {
+ result = parser->data.p;
+ }
+
+ // for types that are completed in typval_parse_exit
+ node->data[0].p = result;
+ node->data[1].p = NULL; // free on error if non-NULL
+
+ switch (node->tok.type) {
+ case MPACK_TOKEN_NIL:
+ *result = (typval_T) {
.v_type = VAR_SPECIAL,
.v_lock = VAR_UNLOCKED,
.vval = { .v_special = kSpecialVarNull },
};
break;
- case MSGPACK_OBJECT_BOOLEAN:
- *rettv = (typval_T) {
+ case MPACK_TOKEN_BOOLEAN:
+ *result = (typval_T) {
.v_type = VAR_BOOL,
.v_lock = VAR_UNLOCKED,
.vval = {
- .v_bool = mobj.via.boolean ? kBoolVarTrue : kBoolVarFalse
+ .v_bool = mpack_unpack_boolean(node->tok) ? kBoolVarTrue : kBoolVarFalse
},
};
break;
- case MSGPACK_OBJECT_POSITIVE_INTEGER:
- if (mobj.via.u64 <= VARNUMBER_MAX) {
- *rettv = (typval_T) {
- .v_type = VAR_NUMBER,
- .v_lock = VAR_UNLOCKED,
- .vval = { .v_number = (varnumber_T)mobj.via.u64 },
- };
- } else {
- list_T *const list = tv_list_alloc(4);
- tv_list_ref(list);
- create_special_dict(rettv, kMPInteger, ((typval_T) {
- .v_type = VAR_LIST,
- .v_lock = VAR_UNLOCKED,
- .vval = { .v_list = list },
- }));
- uint64_t n = mobj.via.u64;
- tv_list_append_number(list, 1);
- tv_list_append_number(list, (varnumber_T)((n >> 62) & 0x3));
- tv_list_append_number(list, (varnumber_T)((n >> 31) & 0x7FFFFFFF));
- tv_list_append_number(list, (varnumber_T)(n & 0x7FFFFFFF));
- }
+ case MPACK_TOKEN_SINT: {
+ *result = (typval_T) {
+ .v_type = VAR_NUMBER,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_number = mpack_unpack_sint(node->tok) },
+ };
break;
- case MSGPACK_OBJECT_NEGATIVE_INTEGER:
- if (mobj.via.i64 >= VARNUMBER_MIN) {
- *rettv = (typval_T) {
- .v_type = VAR_NUMBER,
- .v_lock = VAR_UNLOCKED,
- .vval = { .v_number = (varnumber_T)mobj.via.i64 },
- };
- } else {
- list_T *const list = tv_list_alloc(4);
- tv_list_ref(list);
- create_special_dict(rettv, kMPInteger, ((typval_T) {
- .v_type = VAR_LIST,
- .v_lock = VAR_UNLOCKED,
- .vval = { .v_list = list },
- }));
- uint64_t n = -((uint64_t)mobj.via.i64);
- tv_list_append_number(list, -1);
- tv_list_append_number(list, (varnumber_T)((n >> 62) & 0x3));
- tv_list_append_number(list, (varnumber_T)((n >> 31) & 0x7FFFFFFF));
- tv_list_append_number(list, (varnumber_T)(n & 0x7FFFFFFF));
- }
+ }
+ case MPACK_TOKEN_UINT:
+ positive_integer_to_special_typval(result, mpack_unpack_uint(node->tok));
break;
- case MSGPACK_OBJECT_FLOAT32:
- case MSGPACK_OBJECT_FLOAT64:
- *rettv = (typval_T) {
+ case MPACK_TOKEN_FLOAT:
+ *result = (typval_T) {
.v_type = VAR_FLOAT,
.v_lock = VAR_UNLOCKED,
- .vval = { .v_float = mobj.via.f64 },
+ .vval = { .v_float = mpack_unpack_float(node->tok) },
};
break;
- case MSGPACK_OBJECT_STR:
- case MSGPACK_OBJECT_BIN:
- *rettv = decode_string(mobj.via.bin.ptr, mobj.via.bin.size, false, false);
+
+ case MPACK_TOKEN_BIN:
+ case MPACK_TOKEN_STR:
+ case MPACK_TOKEN_EXT:
+ // actually converted in typval_parse_exit after the data chunks
+ node->data[1].p = xmallocz(node->tok.length);
break;
- case MSGPACK_OBJECT_ARRAY: {
- list_T *const list = tv_list_alloc((ptrdiff_t)mobj.via.array.size);
+ case MPACK_TOKEN_CHUNK: {
+ char *data = parent->data[1].p;
+ memcpy(data + parent->pos,
+ node->tok.data.chunk_ptr, node->tok.length);
+ break;
+ }
+
+ case MPACK_TOKEN_ARRAY: {
+ list_T *const list = tv_list_alloc((ptrdiff_t)node->tok.length);
tv_list_ref(list);
- *rettv = (typval_T) {
+ *result = (typval_T) {
.v_type = VAR_LIST,
.v_lock = VAR_UNLOCKED,
.vval = { .v_list = list },
};
- for (size_t i = 0; i < mobj.via.array.size; i++) {
- // Not populated yet, need to create list item to push.
- tv_list_append_owned_tv(list, (typval_T) { .v_type = VAR_UNKNOWN });
- if (msgpack_to_vim(mobj.via.array.ptr[i],
- TV_LIST_ITEM_TV(tv_list_last(list)))
- == FAIL) {
- return FAIL;
- }
+ node->data[1].p = list;
+ break;
+ }
+ case MPACK_TOKEN_MAP:
+ // we don't know if this will be safe to convert to a typval dict yet
+ node->data[1].p = xmallocz(node->tok.length * 2 * sizeof(typval_T));
+ break;
+ }
+}
+
+/// free node which was entered but never exited, due to a nested error
+///
+/// Don't bother with typvals as these will be GC:d eventually
+void typval_parser_error_free(mpack_parser_t *parser)
+{
+ for (uint32_t i = 0; i < parser->size; i++) {
+ mpack_node_t *node = &parser->items[i];
+ switch (node->tok.type) {
+ case MPACK_TOKEN_BIN:
+ case MPACK_TOKEN_STR:
+ case MPACK_TOKEN_EXT:
+ case MPACK_TOKEN_MAP:
+ XFREE_CLEAR(node->data[1].p);
+ break;
+ default:
+ break;
}
+ }
+}
+
+static void typval_parse_exit(mpack_parser_t *parser, mpack_node_t *node)
+{
+ typval_T *result = node->data[0].p;
+ switch (node->tok.type) {
+ case MPACK_TOKEN_BIN:
+ case MPACK_TOKEN_STR:
+ *result = decode_string(node->data[1].p, node->tok.length, false, true);
+ node->data[1].p = NULL;
break;
+
+ case MPACK_TOKEN_EXT: {
+ list_T *const list = tv_list_alloc(2);
+ tv_list_ref(list);
+ tv_list_append_number(list, node->tok.data.ext_type);
+ list_T *const ext_val_list = tv_list_alloc(kListLenMayKnow);
+ tv_list_append_list(list, ext_val_list);
+ create_special_dict(result, kMPExt, ((typval_T) { .v_type = VAR_LIST,
+ .v_lock = VAR_UNLOCKED,
+ .vval = { .v_list = list } }));
+ // TODO(bfredl): why not use BLOB?
+ encode_list_write((void *)ext_val_list, node->data[1].p, node->tok.length);
+ XFREE_CLEAR(node->data[1].p);
}
- case MSGPACK_OBJECT_MAP: {
- for (size_t i = 0; i < mobj.via.map.size; i++) {
- if ((mobj.via.map.ptr[i].key.type != MSGPACK_OBJECT_STR
- && mobj.via.map.ptr[i].key.type != MSGPACK_OBJECT_BIN)
- || mobj.via.map.ptr[i].key.via.str.size == 0
- || memchr(mobj.via.map.ptr[i].key.via.str.ptr, NUL,
- mobj.via.map.ptr[i].key.via.str.size) != NULL) {
+ break;
+
+ case MPACK_TOKEN_MAP: {
+ typval_T(*items)[2] = node->data[1].p;
+ for (size_t i = 0; i < node->tok.length; i++) {
+ typval_T *key = &items[i][0];
+ if (key->v_type != VAR_STRING
+ || key->vval.v_string == NULL
+ || key->vval.v_string[0] == NUL) {
goto msgpack_to_vim_generic_map;
}
}
dict_T *const dict = tv_dict_alloc();
dict->dv_refcount++;
- *rettv = (typval_T) {
+ *result = (typval_T) {
.v_type = VAR_DICT,
.v_lock = VAR_UNLOCKED,
.vval = { .v_dict = dict },
};
- for (size_t i = 0; i < mobj.via.map.size; i++) {
- dictitem_T *const di = xmallocz(offsetof(dictitem_T, di_key)
- + mobj.via.map.ptr[i].key.via.str.size);
- memcpy(&di->di_key[0], mobj.via.map.ptr[i].key.via.str.ptr,
- mobj.via.map.ptr[i].key.via.str.size);
+ for (size_t i = 0; i < node->tok.length; i++) {
+ char *key = items[i][0].vval.v_string;
+ size_t keylen = strlen(key);
+ dictitem_T *const di = xmallocz(offsetof(dictitem_T, di_key) + keylen);
+ memcpy(&di->di_key[0], key, keylen);
di->di_tv.v_type = VAR_UNKNOWN;
if (tv_dict_add(dict, di) == FAIL) {
// Duplicate key: fallback to generic map
- tv_clear(rettv);
+ TV_DICT_ITER(dict, d, {
+ d->di_tv.v_type = VAR_SPECIAL; // don't free values in tv_clear(), they will be reused
+ d->di_tv.vval.v_special = kSpecialVarNull;
+ });
+ tv_clear(result);
xfree(di);
goto msgpack_to_vim_generic_map;
}
- if (msgpack_to_vim(mobj.via.map.ptr[i].val, &di->di_tv) == FAIL) {
- return FAIL;
- }
+ di->di_tv = items[i][1];
+ }
+ for (size_t i = 0; i < node->tok.length; i++) {
+ xfree(items[i][0].vval.v_string);
}
+ XFREE_CLEAR(node->data[1].p);
break;
msgpack_to_vim_generic_map: {}
- list_T *const list = decode_create_map_special_dict(rettv, (ptrdiff_t)mobj.via.map.size);
- for (size_t i = 0; i < mobj.via.map.size; i++) {
+ list_T *const list = decode_create_map_special_dict(result, node->tok.length);
+ for (size_t i = 0; i < node->tok.length; i++) {
list_T *const kv_pair = tv_list_alloc(2);
tv_list_append_list(list, kv_pair);
- typval_T key_tv = { .v_type = VAR_UNKNOWN };
- if (msgpack_to_vim(mobj.via.map.ptr[i].key, &key_tv) == FAIL) {
- tv_clear(&key_tv);
- return FAIL;
- }
- tv_list_append_owned_tv(kv_pair, key_tv);
-
- typval_T val_tv = { .v_type = VAR_UNKNOWN };
- if (msgpack_to_vim(mobj.via.map.ptr[i].val, &val_tv) == FAIL) {
- tv_clear(&val_tv);
- return FAIL;
- }
- tv_list_append_owned_tv(kv_pair, val_tv);
+ tv_list_append_owned_tv(kv_pair, items[i][0]);
+ tv_list_append_owned_tv(kv_pair, items[i][1]);
}
+ XFREE_CLEAR(node->data[1].p);
break;
}
- case MSGPACK_OBJECT_EXT: {
- list_T *const list = tv_list_alloc(2);
- tv_list_ref(list);
- tv_list_append_number(list, mobj.via.ext.type);
- list_T *const ext_val_list = tv_list_alloc(kListLenMayKnow);
- tv_list_append_list(list, ext_val_list);
- create_special_dict(rettv, kMPExt, ((typval_T) { .v_type = VAR_LIST,
- .v_lock = VAR_UNLOCKED,
- .vval = { .v_list = list } }));
- if (encode_list_write((void *)ext_val_list, mobj.via.ext.ptr,
- mobj.via.ext.size) == -1) {
- return FAIL;
- }
+
+ default:
+ // other kinds are handled completely in typval_parse_enter,
break;
}
+}
+
+int mpack_parse_typval(mpack_parser_t *parser, const char **data, size_t *size)
+{
+ return mpack_parse(parser, data, size, typval_parse_enter, typval_parse_exit);
+}
+
+int unpack_typval(const char **data, size_t *size, typval_T *ret)
+{
+ ret->v_type = VAR_UNKNOWN;
+ mpack_parser_t parser;
+ mpack_parser_init(&parser, 0);
+ parser.data.p = ret;
+ int status = mpack_parse_typval(&parser, data, size);
+ if (status != MPACK_OK) {
+ typval_parser_error_free(&parser);
+ tv_clear(ret);
}
- return OK;
+ return status;
}
diff --git a/src/nvim/eval/decode.h b/src/nvim/eval/decode.h
index c0d10a469a..485cc65561 100644
--- a/src/nvim/eval/decode.h
+++ b/src/nvim/eval/decode.h
@@ -1,8 +1,8 @@
#pragma once
-#include <msgpack.h> // IWYU pragma: keep
#include <stddef.h> // IWYU pragma: keep
+#include "mpack/object.h"
#include "nvim/eval/typval_defs.h" // IWYU pragma: keep
#include "nvim/types_defs.h" // IWYU pragma: keep
diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c
index 92c5aaeffd..79f334601d 100644
--- a/src/nvim/eval/encode.c
+++ b/src/nvim/eval/encode.c
@@ -55,11 +55,11 @@ int encode_blob_write(void *const data, const char *const buf, const size_t len)
}
/// Msgpack callback for writing to readfile()-style list
-int encode_list_write(void *const data, const char *const buf, const size_t len)
+void encode_list_write(void *const data, const char *const buf, const size_t len)
FUNC_ATTR_NONNULL_ARG(1)
{
if (len == 0) {
- return 0;
+ return;
}
list_T *const list = (list_T *)data;
const char *const end = buf + len;
@@ -97,7 +97,6 @@ int encode_list_write(void *const data, const char *const buf, const size_t len)
if (line_end == end) {
tv_list_append_allocated_string(list, NULL);
}
- return 0;
}
/// Abort conversion to string after a recursion error.
diff --git a/src/nvim/eval/encode.h b/src/nvim/eval/encode.h
index efccfcb5a6..2bacc82b0d 100644
--- a/src/nvim/eval/encode.h
+++ b/src/nvim/eval/encode.h
@@ -1,6 +1,5 @@
#pragma once
-#include <msgpack/pack.h>
#include <string.h>
#include "nvim/eval/typval_defs.h"
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index d2f6af4d9e..2f51532ec4 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -4,9 +4,6 @@
#include <inttypes.h>
#include <limits.h>
#include <math.h>
-#include <msgpack/object.h>
-#include <msgpack/pack.h>
-#include <msgpack/unpack.h>
#include <signal.h>
#include <stdarg.h>
#include <stddef.h>
@@ -18,6 +15,7 @@
#include <uv.h>
#include "auto/config.h"
+#include "mpack/object.h"
#include "nvim/api/private/converter.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/dispatch.h"
@@ -5723,36 +5721,24 @@ static void f_msgpackdump(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
}
}
-static int msgpackparse_convert_item(const msgpack_object data, const msgpack_unpack_return result,
- list_T *const ret_list, const bool fail_if_incomplete)
- FUNC_ATTR_NONNULL_ALL
+static void emsg_mpack_error(int status)
{
- switch (result) {
- case MSGPACK_UNPACK_PARSE_ERROR:
+ switch (status) {
+ case MPACK_ERROR:
semsg(_(e_invarg2), "Failed to parse msgpack string");
- return FAIL;
- case MSGPACK_UNPACK_NOMEM_ERROR:
- emsg(_(e_outofmem));
- return FAIL;
- case MSGPACK_UNPACK_CONTINUE:
- if (fail_if_incomplete) {
- semsg(_(e_invarg2), "Incomplete msgpack string");
- return FAIL;
- }
- return NOTDONE;
- case MSGPACK_UNPACK_SUCCESS: {
- typval_T tv = { .v_type = VAR_UNKNOWN };
- if (msgpack_to_vim(data, &tv) == FAIL) {
- semsg(_(e_invarg2), "Failed to convert msgpack string");
- return FAIL;
- }
- tv_list_append_owned_tv(ret_list, tv);
- return OK;
- }
- case MSGPACK_UNPACK_EXTRA_BYTES:
- abort();
+ break;
+
+ case MPACK_EOF:
+ semsg(_(e_invarg2), "Incomplete msgpack string");
+ break;
+
+ case MPACK_NOMEM:
+ semsg(_(e_invarg2), "object was too deep to unpack");
+ break;
+
+ default:
+ break;
}
- UNREACHABLE;
}
static void msgpackparse_unpack_list(const list_T *const list, list_T *const ret_list)
@@ -5766,48 +5752,57 @@ static void msgpackparse_unpack_list(const list_T *const list, list_T *const ret
return;
}
ListReaderState lrstate = encode_init_lrstate(list);
- msgpack_unpacker *const unpacker = msgpack_unpacker_new(IOSIZE);
- if (unpacker == NULL) {
- emsg(_(e_outofmem));
- return;
- }
- msgpack_unpacked unpacked;
- msgpack_unpacked_init(&unpacked);
+ char *buf = alloc_block();
+ size_t buf_size = 0;
+
+ typval_T cur_item = { .v_type = VAR_UNKNOWN };
+ mpack_parser_t parser;
+ mpack_parser_init(&parser, 0);
+ parser.data.p = &cur_item;
+
+ int status = MPACK_OK;
while (true) {
- if (!msgpack_unpacker_reserve_buffer(unpacker, IOSIZE)) {
- emsg(_(e_outofmem));
- goto end;
- }
size_t read_bytes;
- const int rlret = encode_read_from_list(&lrstate, msgpack_unpacker_buffer(unpacker), IOSIZE,
+ const int rlret = encode_read_from_list(&lrstate, buf + buf_size, ARENA_BLOCK_SIZE - buf_size,
&read_bytes);
if (rlret == FAIL) {
semsg(_(e_invarg2), "List item is not a string");
goto end;
}
- msgpack_unpacker_buffer_consumed(unpacker, read_bytes);
- if (read_bytes == 0) {
- break;
- }
- while (unpacker->off < unpacker->used) {
- const msgpack_unpack_return result
- = msgpack_unpacker_next(unpacker, &unpacked);
- const int conv_result = msgpackparse_convert_item(unpacked.data, result,
- ret_list, rlret == OK);
- if (conv_result == NOTDONE) {
+ buf_size += read_bytes;
+
+ const char *ptr = buf;
+ while (buf_size) {
+ status = mpack_parse_typval(&parser, &ptr, &buf_size);
+ if (status == MPACK_OK) {
+ tv_list_append_owned_tv(ret_list, cur_item);
+ cur_item.v_type = VAR_UNKNOWN;
+ } else {
break;
- } else if (conv_result == FAIL) {
- goto end;
}
}
+
if (rlret == OK) {
break;
}
+
+ if (status == MPACK_EOF) {
+ // move remaining data to front of buffer
+ if (buf_size && ptr > buf) {
+ memmove(buf, ptr, buf_size);
+ }
+ } else if (status != MPACK_OK) {
+ break;
+ }
+ }
+
+ if (status != MPACK_OK) {
+ typval_parser_error_free(&parser);
+ emsg_mpack_error(status);
}
end:
- msgpack_unpacker_free(unpacker);
- msgpack_unpacked_destroy(&unpacked);
+ free_block(buf);
}
static void msgpackparse_unpack_blob(const blob_T *const blob, list_T *const ret_list)
@@ -5817,18 +5812,19 @@ static void msgpackparse_unpack_blob(const blob_T *const blob, list_T *const ret
if (len == 0) {
return;
}
- msgpack_unpacked unpacked;
- msgpack_unpacked_init(&unpacked);
- for (size_t offset = 0; offset < (size_t)len;) {
- const msgpack_unpack_return result
- = msgpack_unpack_next(&unpacked, blob->bv_ga.ga_data, (size_t)len, &offset);
- if (msgpackparse_convert_item(unpacked.data, result, ret_list, true)
- != OK) {
- break;
+
+ const char *data = blob->bv_ga.ga_data;
+ size_t remaining = (size_t)len;
+ while (remaining) {
+ typval_T tv;
+ int status = unpack_typval(&data, &remaining, &tv);
+ if (status != MPACK_OK) {
+ emsg_mpack_error(status);
+ return;
}
- }
- msgpack_unpacked_destroy(&unpacked);
+ tv_list_append_owned_tv(ret_list, tv);
+ }
}
/// "msgpackparse" function
diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c
index c00abe452c..e7b6a0feee 100644
--- a/src/nvim/eval/typval.c
+++ b/src/nvim/eval/typval.c
@@ -485,13 +485,14 @@ void tv_list_append_tv(list_T *const l, typval_T *const tv)
/// Like tv_list_append_tv(), but tv is moved to a list
///
/// This means that it is no longer valid to use contents of the typval_T after
-/// function exits.
-void tv_list_append_owned_tv(list_T *const l, typval_T tv)
+/// function exits. A pointer is returned to the allocated typval which can be used
+typval_T *tv_list_append_owned_tv(list_T *const l, typval_T tv)
FUNC_ATTR_NONNULL_ALL
{
listitem_T *const li = tv_list_item_alloc();
*TV_LIST_ITEM_TV(li) = tv;
tv_list_append(l, li);
+ return TV_LIST_ITEM_TV(li);
}
/// Append a list to a list as one item
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 1060650bf2..6a7a713d39 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -3068,8 +3068,8 @@ void sub_get_replacement(SubReplacementString *const ret_sub)
void sub_set_replacement(SubReplacementString sub)
{
xfree(old_sub.sub);
- if (sub.additional_elements != old_sub.additional_elements) {
- tv_list_unref(old_sub.additional_elements);
+ if (sub.additional_data != old_sub.additional_data) {
+ xfree(old_sub.additional_data);
}
old_sub = sub;
}
@@ -3395,7 +3395,7 @@ static int do_sub(exarg_T *eap, const proftime_T timeout, const int cmdpreview_n
sub_set_replacement((SubReplacementString) {
.sub = xstrdup(sub),
.timestamp = os_time(),
- .additional_elements = NULL,
+ .additional_data = NULL,
});
}
} else if (!eap->skip) { // use previous pattern and substitution
diff --git a/src/nvim/ex_cmds_defs.h b/src/nvim/ex_cmds_defs.h
index 07f92ca169..4924e86470 100644
--- a/src/nvim/ex_cmds_defs.h
+++ b/src/nvim/ex_cmds_defs.h
@@ -233,5 +233,5 @@ typedef struct {
typedef struct {
char *sub; ///< Previous replacement string.
Timestamp timestamp; ///< Time when it was last set.
- list_T *additional_elements; ///< Additional data left from ShaDa file.
+ AdditionalData *additional_data; ///< Additional data left from ShaDa file.
} SubReplacementString;
diff --git a/src/nvim/generators/c_grammar.lua b/src/nvim/generators/c_grammar.lua
index 9ce9f3d7a6..4e7de7adb4 100644
--- a/src/nvim/generators/c_grammar.lua
+++ b/src/nvim/generators/c_grammar.lua
@@ -91,7 +91,9 @@ local c_proto = Ct(
* (P(';') + (P('{') * nl + (impl_line ^ 0) * P('}')))
)
-local c_field = Ct(Cg(c_id, 'type') * ws * Cg(c_id, 'name') * fill * P(';') * fill)
+local dict_key = P('DictKey(') * Cg(rep1(any - P(')')), 'dict_key') * P(')')
+local keyset_field =
+ Ct(Cg(c_id, 'type') * ws * Cg(c_id, 'name') * fill * (dict_key ^ -1) * fill * P(';') * fill)
local c_keyset = Ct(
P('typedef')
* ws
@@ -99,7 +101,7 @@ local c_keyset = Ct(
* fill
* P('{')
* fill
- * Cg(Ct(c_field ^ 1), 'fields')
+ * Cg(Ct(keyset_field ^ 1), 'fields')
* P('}')
* fill
* P('Dict')
diff --git a/src/nvim/generators/gen_api_dispatch.lua b/src/nvim/generators/gen_api_dispatch.lua
index 61c80a3d2e..3567831c41 100644
--- a/src/nvim/generators/gen_api_dispatch.lua
+++ b/src/nvim/generators/gen_api_dispatch.lua
@@ -72,14 +72,19 @@ local keysets = {}
local function add_keyset(val)
local keys = {}
local types = {}
+ local c_names = {}
local is_set_name = 'is_set__' .. val.keyset_name .. '_'
local has_optional = false
for i, field in ipairs(val.fields) do
+ local dict_key = field.dict_key or field.name
if field.type ~= 'Object' then
- types[field.name] = field.type
+ types[dict_key] = field.type
end
if field.name ~= is_set_name and field.type ~= 'OptionalKeys' then
- table.insert(keys, field.name)
+ table.insert(keys, dict_key)
+ if dict_key ~= field.name then
+ c_names[dict_key] = field.name
+ end
else
if i > 1 then
error("'is_set__{type}_' must be first if present")
@@ -94,6 +99,7 @@ local function add_keyset(val)
table.insert(keysets, {
name = val.keyset_name,
keys = keys,
+ c_names = c_names,
types = types,
has_optional = has_optional,
})
@@ -332,19 +338,6 @@ output:write([[
keysets_defs:write('// IWYU pragma: private, include "nvim/api/private/dispatch.h"\n\n')
for _, k in ipairs(keysets) do
- local c_name = {}
-
- for i = 1, #k.keys do
- -- some keys, like "register" are c keywords and get
- -- escaped with a trailing _ in the struct.
- if vim.endswith(k.keys[i], '_') then
- local orig = k.keys[i]
- k.keys[i] = string.sub(k.keys[i], 1, #k.keys[i] - 1)
- c_name[k.keys[i]] = orig
- k.types[k.keys[i]] = k.types[orig]
- end
- end
-
local neworder, hashfun = hashy.hashy_hash(k.name, k.keys, function(idx)
return k.name .. '_table[' .. idx .. '].str'
end)
@@ -354,6 +347,8 @@ for _, k in ipairs(keysets) do
local function typename(type)
if type == 'HLGroupID' then
return 'kObjectTypeInteger'
+ elseif type == 'StringArray' then
+ return 'kUnpackTypeStringArray'
elseif type ~= nil then
return 'kObjectType' .. type
else
@@ -374,7 +369,7 @@ for _, k in ipairs(keysets) do
.. '", offsetof(KeyDict_'
.. k.name
.. ', '
- .. (c_name[key] or key)
+ .. (k.c_names[key] or key)
.. '), '
.. typename(k.types[key])
.. ', '
diff --git a/src/nvim/generators/hashy.lua b/src/nvim/generators/hashy.lua
index 711e695742..ea35064962 100644
--- a/src/nvim/generators/hashy.lua
+++ b/src/nvim/generators/hashy.lua
@@ -73,11 +73,15 @@ function M.switcher(put, tab, maxlen, worst_buck_size)
vim.list_extend(neworder, buck)
local endidx = #neworder
put(" case '" .. c .. "': ")
- put('low = ' .. startidx .. '; ')
- if bucky then
- put('high = ' .. endidx .. '; ')
+ if len == 1 then
+ put('return ' .. startidx .. ';\n')
+ else
+ put('low = ' .. startidx .. '; ')
+ if bucky then
+ put('high = ' .. endidx .. '; ')
+ end
+ put 'break;\n'
end
- put 'break;\n'
end
put ' default: break;\n'
put ' }\n '
@@ -105,13 +109,19 @@ function M.hashy_hash(name, strings, access)
end
local len_pos_buckets, maxlen, worst_buck_size = M.build_pos_hash(strings)
put('int ' .. name .. '_hash(const char *str, size_t len)\n{\n')
- if worst_buck_size > 1 then
+ if maxlen == 1 then
+ put('\n') -- nothing
+ elseif worst_buck_size > 1 then
put(' int low = 0, high = 0;\n')
else
put(' int low = -1;\n')
end
local neworder = M.switcher(put, len_pos_buckets, maxlen, worst_buck_size)
- if worst_buck_size > 1 then
+ if maxlen == 1 then
+ put([[
+ return -1;
+]])
+ elseif worst_buck_size > 1 then
put([[
for (int i = low; i < high; i++) {
if (!memcmp(str, ]] .. access('i') .. [[, len)) {
diff --git a/src/nvim/main.c b/src/nvim/main.c
index 72888757be..c507a201b0 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -6,7 +6,6 @@
#endif
#include <assert.h>
#include <limits.h>
-#include <msgpack/pack.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
diff --git a/src/nvim/mark.c b/src/nvim/mark.c
index fae28ef6e1..a09ade2b03 100644
--- a/src/nvim/mark.c
+++ b/src/nvim/mark.c
@@ -71,7 +71,7 @@ int setmark(int c)
/// Free fmark_T item
void free_fmark(fmark_T fm)
{
- tv_dict_unref(fm.additional_data);
+ xfree(fm.additional_data);
}
/// Free xfmark_T item
diff --git a/src/nvim/mark_defs.h b/src/nvim/mark_defs.h
index ad437e8ce1..f953e26e4e 100644
--- a/src/nvim/mark_defs.h
+++ b/src/nvim/mark_defs.h
@@ -1,7 +1,11 @@
#pragma once
-#include "nvim/eval/typval_defs.h"
+#include <stdbool.h>
+
+#include "nvim/func_attr.h"
#include "nvim/os/time_defs.h"
+#include "nvim/pos_defs.h"
+#include "nvim/types_defs.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "mark_defs.h.inline.generated.h"
@@ -75,7 +79,7 @@ typedef struct {
int fnum; ///< File number.
Timestamp timestamp; ///< Time when this mark was last set.
fmarkv_T view; ///< View the mark was created on
- dict_T *additional_data; ///< Additional data from ShaDa file.
+ AdditionalData *additional_data; ///< Additional data from ShaDa file.
} fmark_T;
#define INIT_FMARK { { 0, 0, 0 }, 0, 0, INIT_FMARKV, NULL }
diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c
index 0930f0c7b3..e4aef4063d 100644
--- a/src/nvim/msgpack_rpc/channel.c
+++ b/src/nvim/msgpack_rpc/channel.c
@@ -1,8 +1,5 @@
#include <assert.h>
#include <inttypes.h>
-#include <msgpack/object.h>
-#include <msgpack/sbuffer.h>
-#include <msgpack/unpack.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/src/nvim/msgpack_rpc/channel_defs.h b/src/nvim/msgpack_rpc/channel_defs.h
index 7dc1374964..6c8b05b8f3 100644
--- a/src/nvim/msgpack_rpc/channel_defs.h
+++ b/src/nvim/msgpack_rpc/channel_defs.h
@@ -1,6 +1,5 @@
#pragma once
-#include <msgpack.h>
#include <stdbool.h>
#include <uv.h>
diff --git a/src/nvim/msgpack_rpc/unpacker.c b/src/nvim/msgpack_rpc/unpacker.c
index 28d27e8268..9372754b01 100644
--- a/src/nvim/msgpack_rpc/unpacker.c
+++ b/src/nvim/msgpack_rpc/unpacker.c
@@ -11,6 +11,7 @@
#include "nvim/memory.h"
#include "nvim/msgpack_rpc/channel_defs.h"
#include "nvim/msgpack_rpc/unpacker.h"
+#include "nvim/strings.h"
#include "nvim/ui_client.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -206,6 +207,7 @@ bool unpacker_parse_header(Unpacker *p)
assert(!ERROR_SET(&p->unpack_error));
+ // TODO(bfredl): eliminate p->reader, we can use mpack_rtoken directly
#define NEXT(tok) \
result = mpack_read(&p->reader, &data, &size, &tok); \
if (result) { goto error; }
@@ -522,3 +524,197 @@ bool unpacker_parse_redraw(Unpacker *p)
abort();
}
}
+
+/// require complete string. safe to use e.g. in shada as we have loaded a complete shada item into
+/// a linear buffer.
+///
+/// data and size are preserved in cause of failure
+///
+/// @return "data" is NULL exact when failure (non-null data and size=0 for
+/// valid empty string)
+String unpack_string(const char **data, size_t *size)
+{
+ const char *data2 = *data;
+ size_t size2 = *size;
+ mpack_token_t tok;
+
+ // TODO(bfredl): this code is hot a f, specialize!
+ int result = mpack_rtoken(&data2, &size2, &tok);
+ if (result || (tok.type != MPACK_TOKEN_STR && tok.type != MPACK_TOKEN_BIN)) {
+ return (String)STRING_INIT;
+ }
+ if (*size < tok.length) {
+ // result = MPACK_EOF;
+ return (String)STRING_INIT;
+ }
+ (*data) = data2 + tok.length;
+ (*size) = size2 - tok.length;
+ return cbuf_as_string((char *)data2, tok.length);
+}
+
+/// @return -1 if not an array or EOF. otherwise size of valid array
+ssize_t unpack_array(const char **data, size_t *size)
+{
+ // TODO(bfredl): this code is hot, specialize!
+ mpack_token_t tok;
+ int result = mpack_rtoken(data, size, &tok);
+ if (result || tok.type != MPACK_TOKEN_ARRAY) {
+ return -1;
+ }
+ return tok.length;
+}
+
+/// does not keep "data" untouched on failure
+bool unpack_integer(const char **data, size_t *size, Integer *res)
+{
+ mpack_token_t tok;
+ int result = mpack_rtoken(data, size, &tok);
+ if (result) {
+ return false;
+ }
+ return unpack_uint_or_sint(tok, res);
+}
+
+bool unpack_uint_or_sint(mpack_token_t tok, Integer *res)
+{
+ if (tok.type == MPACK_TOKEN_UINT) {
+ *res = (Integer)mpack_unpack_uint(tok);
+ return true;
+ } else if (tok.type == MPACK_TOKEN_SINT) {
+ *res = (Integer)mpack_unpack_sint(tok);
+ return true;
+ }
+ return false;
+}
+
+static void parse_nop(mpack_parser_t *parser, mpack_node_t *node)
+{
+}
+
+int unpack_skip(const char **data, size_t *size)
+{
+ mpack_parser_t parser;
+ mpack_parser_init(&parser, 0);
+
+ return mpack_parse(&parser, data, size, parse_nop, parse_nop);
+}
+
+void push_additional_data(AdditionalDataBuilder *ad, const char *data, size_t size)
+{
+ if (kv_size(*ad) == 0) {
+ AdditionalData init = { 0 };
+ kv_concat_len(*ad, &init, sizeof(init));
+ }
+ AdditionalData *a = (AdditionalData *)ad->items;
+ a->nitems++;
+ a->nbytes += (uint32_t)size;
+ kv_concat_len(*ad, data, size);
+}
+
+// currently only used for shada, so not re-entrant like unpacker_parse_redraw
+bool unpack_keydict(void *retval, FieldHashfn hashy, AdditionalDataBuilder *ad, const char **data,
+ size_t *restrict size, char **error)
+{
+ OptKeySet *ks = (OptKeySet *)retval;
+ mpack_token_t tok;
+
+ int result = mpack_rtoken(data, size, &tok);
+ if (result || tok.type != MPACK_TOKEN_MAP) {
+ *error = xstrdup("is not a dictionary");
+ return false;
+ }
+
+ size_t map_size = tok.length;
+
+ for (size_t i = 0; i < map_size; i++) {
+ const char *item_start = *data;
+ // TODO(bfredl): we could specialize a hot path for FIXSTR here
+ String key = unpack_string(data, size);
+ if (!key.data) {
+ *error = arena_printf(NULL, "has key value which is not a string").data;
+ return false;
+ } else if (key.size == 0) {
+ *error = arena_printf(NULL, "has empty key").data;
+ return false;
+ }
+ KeySetLink *field = hashy(key.data, key.size);
+
+ if (!field) {
+ int status = unpack_skip(data, size);
+ if (status) {
+ return false;
+ }
+
+ if (ad) {
+ push_additional_data(ad, item_start, (size_t)(*data - item_start));
+ }
+ continue;
+ }
+
+ assert(field->opt_index >= 0);
+ uint64_t flag = (1ULL << field->opt_index);
+ if (ks->is_set_ & flag) {
+ *error = xstrdup("duplicate key");
+ return false;
+ }
+ ks->is_set_ |= flag;
+
+ char *mem = ((char *)retval + field->ptr_off);
+ switch (field->type) {
+ case kObjectTypeBoolean:
+ if (*size == 0 || (**data & 0xfe) != 0xc2) {
+ *error = arena_printf(NULL, "has %.*s key value which is not a boolean", (int)key.size,
+ key.data).data;
+ return false;
+ }
+ *(Boolean *)mem = **data & 0x01;
+ (*data)++; (*size)--;
+ break;
+
+ case kObjectTypeInteger:
+ if (!unpack_integer(data, size, (Integer *)mem)) {
+ *error = arena_printf(NULL, "has %.*s key value which is not an integer", (int)key.size,
+ key.data).data;
+ return false;
+ }
+ break;
+
+ case kObjectTypeString: {
+ String val = unpack_string(data, size);
+ if (!val.data) {
+ *error = arena_printf(NULL, "has %.*s key value which is not a binary", (int)key.size,
+ key.data).data;
+ return false;
+ }
+ *(String *)mem = val;
+ break;
+ }
+
+ case kUnpackTypeStringArray: {
+ ssize_t len = unpack_array(data, size);
+ if (len < 0) {
+ *error = arena_printf(NULL, "has %.*s key with non-array value", (int)key.size,
+ key.data).data;
+ return false;
+ }
+ StringArray *a = (StringArray *)mem;
+ kv_ensure_space(*a, (size_t)len);
+ for (size_t j = 0; j < (size_t)len; j++) {
+ String item = unpack_string(data, size);
+ if (!item.data) {
+ *error = arena_printf(NULL, "has %.*s array with non-binary value", (int)key.size,
+ key.data).data;
+ return false;
+ }
+ kv_push(*a, item);
+ }
+ break;
+ }
+
+ default:
+ abort(); // not supported
+ }
+ }
+
+ return true;
+}
diff --git a/src/nvim/msgpack_rpc/unpacker.h b/src/nvim/msgpack_rpc/unpacker.h
index ed55fdd4af..c29462292f 100644
--- a/src/nvim/msgpack_rpc/unpacker.h
+++ b/src/nvim/msgpack_rpc/unpacker.h
@@ -41,6 +41,8 @@ struct Unpacker {
bool has_grid_line_event;
};
+typedef kvec_t(char) AdditionalDataBuilder;
+
// unrecovareble error. unpack_error should be set!
#define unpacker_closed(p) ((p)->state < 0)
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index e418635d37..05b9db474e 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -930,16 +930,6 @@ int do_record(int c)
return retval;
}
-static void set_yreg_additional_data(yankreg_T *reg, dict_T *additional_data)
- FUNC_ATTR_NONNULL_ARG(1)
-{
- if (reg->additional_data == additional_data) {
- return;
- }
- tv_dict_unref(reg->additional_data);
- reg->additional_data = additional_data;
-}
-
/// Stuff string "p" into yank register "regname" as a single line (append if
/// uppercase). "p" must have been allocated.
///
@@ -969,7 +959,7 @@ static int stuff_yank(int regname, char *p)
*pp = lp;
} else {
free_register(reg);
- set_yreg_additional_data(reg, NULL);
+ reg->additional_data = NULL;
reg->y_array = xmalloc(sizeof(char *));
reg->y_array[0] = p;
reg->y_size = 1;
@@ -2507,7 +2497,7 @@ void clear_registers(void)
void free_register(yankreg_T *reg)
FUNC_ATTR_NONNULL_ALL
{
- set_yreg_additional_data(reg, NULL);
+ XFREE_CLEAR(reg->additional_data);
if (reg->y_array == NULL) {
return;
}
@@ -5144,7 +5134,7 @@ static void str_to_reg(yankreg_T *y_ptr, MotionType yank_type, const char *str,
}
y_ptr->y_type = yank_type;
y_ptr->y_size = lnum;
- set_yreg_additional_data(y_ptr, NULL);
+ XFREE_CLEAR(y_ptr->additional_data);
y_ptr->timestamp = os_time();
if (yank_type == kMTBlockWise) {
y_ptr->y_width = (blocklen == -1 ? (colnr_T)maxlen - 1 : blocklen);
diff --git a/src/nvim/ops.h b/src/nvim/ops.h
index f2b38e5faf..dfa2d4b112 100644
--- a/src/nvim/ops.h
+++ b/src/nvim/ops.h
@@ -110,7 +110,7 @@ typedef struct {
MotionType y_type; ///< Register type
colnr_T y_width; ///< Register width (only valid for y_type == kBlockWise).
Timestamp timestamp; ///< Time when register was last modified.
- dict_T *additional_data; ///< Additional data from ShaDa file.
+ AdditionalData *additional_data; ///< Additional data from ShaDa file.
} yankreg_T;
/// Modes for get_yank_register()
diff --git a/src/nvim/os/fileio.c b/src/nvim/os/fileio.c
index 89834bed80..1981d0dfd4 100644
--- a/src/nvim/os/fileio.c
+++ b/src/nvim/os/fileio.c
@@ -309,6 +309,22 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf, const size_t
return (ptrdiff_t)(size - read_remaining);
}
+/// try to read already buffered data in place
+///
+/// @return NULL if enough data is not available
+/// valid pointer to chunk of "size". pointer becomes invalid in the next "file_read" call!
+char *file_try_read_buffered(FileDescriptor *const fp, const size_t size)
+ FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ if ((size_t)(fp->write_pos - fp->read_pos) >= size) {
+ char *ret = fp->read_pos;
+ fp->read_pos += size;
+ fp->bytes_read += size;
+ return ret;
+ }
+ return NULL;
+}
+
/// Write to a file
///
/// @param[in] fd File descriptor to write to.
diff --git a/src/nvim/search.c b/src/nvim/search.c
index 57d151cf75..d1cb336905 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -290,7 +290,7 @@ void restore_search_patterns(void)
static inline void free_spat(SearchPattern *const spat)
{
xfree(spat->pat);
- tv_dict_unref(spat->additional_data);
+ xfree(spat->additional_data);
}
#if defined(EXITFREE)
diff --git a/src/nvim/search.h b/src/nvim/search.h
index 92ee5d6854..1b6c1a6375 100644
--- a/src/nvim/search.h
+++ b/src/nvim/search.h
@@ -89,7 +89,7 @@ typedef struct {
bool no_scs; ///< No smartcase for this pattern.
Timestamp timestamp; ///< Time of the last change.
SearchOffset off; ///< Pattern offset.
- dict_T *additional_data; ///< Additional data from ShaDa file.
+ AdditionalData *additional_data; ///< Additional data from ShaDa file.
} SearchPattern;
/// Optional extra arguments for searchit().
diff --git a/src/nvim/shada.c b/src/nvim/shada.c
index 7dcc6025eb..e5479a7d40 100644
--- a/src/nvim/shada.c
+++ b/src/nvim/shada.c
@@ -1,9 +1,5 @@
#include <assert.h>
#include <inttypes.h>
-#include <msgpack/object.h>
-#include <msgpack/pack.h>
-#include <msgpack/sbuffer.h>
-#include <msgpack/unpack.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
@@ -13,6 +9,7 @@
#include <uv.h>
#include "auto/config.h"
+#include "nvim/api/keysets_defs.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
#include "nvim/ascii_defs.h"
@@ -43,6 +40,7 @@
#include "nvim/memory.h"
#include "nvim/message.h"
#include "nvim/msgpack_rpc/packer.h"
+#include "nvim/msgpack_rpc/unpacker.h"
#include "nvim/normal_defs.h"
#include "nvim/ops.h"
#include "nvim/option.h"
@@ -71,26 +69,26 @@
# include ENDIAN_INCLUDE_FILE
#endif
-#define SEARCH_KEY_MAGIC "sm"
-#define SEARCH_KEY_SMARTCASE "sc"
-#define SEARCH_KEY_HAS_LINE_OFFSET "sl"
-#define SEARCH_KEY_PLACE_CURSOR_AT_END "se"
-#define SEARCH_KEY_IS_LAST_USED "su"
-#define SEARCH_KEY_IS_SUBSTITUTE_PATTERN "ss"
-#define SEARCH_KEY_HIGHLIGHTED "sh"
-#define SEARCH_KEY_OFFSET "so"
-#define SEARCH_KEY_PAT "sp"
-#define SEARCH_KEY_BACKWARD "sb"
-
-#define REG_KEY_TYPE "rt"
-#define REG_KEY_WIDTH "rw"
-#define REG_KEY_CONTENTS "rc"
-#define REG_KEY_UNNAMED "ru"
-
-#define KEY_LNUM "l"
-#define KEY_COL "c"
-#define KEY_FILE "f"
-#define KEY_NAME_CHAR "n"
+#define SEARCH_KEY_MAGIC sm
+#define SEARCH_KEY_SMARTCASE sc
+#define SEARCH_KEY_HAS_LINE_OFFSET sl
+#define SEARCH_KEY_PLACE_CURSOR_AT_END se
+#define SEARCH_KEY_IS_LAST_USED su
+#define SEARCH_KEY_IS_SUBSTITUTE_PATTERN ss
+#define SEARCH_KEY_HIGHLIGHTED sh
+#define SEARCH_KEY_OFFSET so
+#define SEARCH_KEY_PAT sp
+#define SEARCH_KEY_BACKWARD sb
+
+#define REG_KEY_TYPE rt
+#define REG_KEY_WIDTH rw
+#define REG_KEY_CONTENTS rc
+#define REG_KEY_UNNAMED ru
+
+#define KEY_LNUM l
+#define KEY_COL c
+#define KEY_FILE f
+#define KEY_NAME_CHAR n
// Error messages formerly used by viminfo code:
// E136: viminfo: Too many errors, skipping rest of file
@@ -238,26 +236,12 @@ typedef struct {
char name;
pos_T mark;
char *fname;
- dict_T *additional_data;
} filemark;
- struct search_pattern {
- bool magic;
- bool smartcase;
- bool has_line_offset;
- bool place_cursor_at_end;
- int64_t offset;
- bool is_last_used;
- bool is_substitute_pattern;
- bool highlighted;
- bool search_backward;
- char *pat;
- dict_T *additional_data;
- } search_pattern;
+ Dict(_shada_search_pat) search_pattern;
struct history_item {
uint8_t histtype;
char *string;
char sep;
- list_T *additional_elements;
} history_item;
struct reg { // yankreg_T
char name;
@@ -266,12 +250,10 @@ typedef struct {
bool is_unnamed;
size_t contents_size;
size_t width;
- dict_T *additional_data;
} reg;
struct global_var {
char *name;
typval_T value;
- list_T *additional_elements;
} global_var;
struct {
uint64_t type;
@@ -280,17 +262,17 @@ typedef struct {
} unknown_item;
struct sub_string {
char *sub;
- list_T *additional_elements;
} sub_string;
struct buffer_list {
size_t size;
struct buffer_list_buffer {
pos_T pos;
char *fname;
- dict_T *additional_data;
+ AdditionalData *additional_data;
} *buffers;
} buffer_list;
} data;
+ AdditionalData *additional_data;
} ShadaEntry;
/// One entry in sized linked list
@@ -366,6 +348,7 @@ typedef struct {
[kSDItem##name] = { \
.timestamp = 0, \
.type = kSDItem##name, \
+ .additional_data = NULL, \
.data = { \
.attr = { __VA_ARGS__ } \
} \
@@ -385,49 +368,41 @@ static const ShadaEntry sd_default_values[] = {
.is_substitute_pattern = false,
.highlighted = false,
.search_backward = false,
- .pat = NULL,
- .additional_data = NULL),
- DEF_SDE(SubString, sub_string, .sub = NULL, .additional_elements = NULL),
+ .pat = STRING_INIT),
+ DEF_SDE(SubString, sub_string, .sub = NULL),
DEF_SDE(HistoryEntry, history_item,
.histtype = HIST_CMD,
.string = NULL,
- .sep = NUL,
- .additional_elements = NULL),
+ .sep = NUL),
DEF_SDE(Register, reg,
.name = NUL,
.type = kMTCharWise,
.contents = NULL,
.contents_size = 0,
.is_unnamed = false,
- .width = 0,
- .additional_data = NULL),
+ .width = 0),
DEF_SDE(Variable, global_var,
.name = NULL,
- .value = { .v_type = VAR_UNKNOWN, .vval = { .v_string = NULL } },
- .additional_elements = NULL),
+ .value = { .v_type = VAR_UNKNOWN, .vval = { .v_string = NULL } }),
DEF_SDE(GlobalMark, filemark,
.name = '"',
.mark = DEFAULT_POS,
- .fname = NULL,
- .additional_data = NULL),
+ .fname = NULL),
DEF_SDE(Jump, filemark,
.name = NUL,
.mark = DEFAULT_POS,
- .fname = NULL,
- .additional_data = NULL),
+ .fname = NULL),
DEF_SDE(BufferList, buffer_list,
.size = 0,
.buffers = NULL),
DEF_SDE(LocalMark, filemark,
.name = '"',
.mark = DEFAULT_POS,
- .fname = NULL,
- .additional_data = NULL),
+ .fname = NULL),
DEF_SDE(Change, filemark,
.name = NUL,
.mark = DEFAULT_POS,
- .fname = NULL,
- .additional_data = NULL),
+ .fname = NULL),
};
#undef DEFAULT_POS
#undef DEF_SDE
@@ -685,9 +660,9 @@ static const void *shada_hist_iter(const void *const iter, const uint8_t history
.sep = (char)(history_type == HIST_SEARCH
? hist_he.hisstr[strlen(hist_he.hisstr) + 1]
: 0),
- .additional_elements = hist_he.additional_elements,
}
- }
+ },
+ .additional_data = hist_he.additional_data,
};
}
return ret;
@@ -809,8 +784,7 @@ static inline void hms_to_he_array(const HistoryMergerState *const hms_p,
hist->timestamp = cur_entry->data.timestamp;
hist->hisnum = (int)(hist - hist_array) + 1;
hist->hisstr = cur_entry->data.data.history_item.string;
- hist->additional_elements =
- cur_entry->data.data.history_item.additional_elements;
+ hist->additional_data = cur_entry->data.additional_data;
hist++;
})
*new_hisnum = (int)(hist - hist_array);
@@ -1057,9 +1031,9 @@ static void shada_read(FileDescriptor *const sd_reader, const int flags)
.end = cur_entry.data.search_pattern.place_cursor_at_end,
.off = cur_entry.data.search_pattern.offset,
},
- .pat = cur_entry.data.search_pattern.pat,
- .patlen = strlen(cur_entry.data.search_pattern.pat),
- .additional_data = cur_entry.data.search_pattern.additional_data,
+ .pat = cur_entry.data.search_pattern.pat.data,
+ .patlen = cur_entry.data.search_pattern.pat.size,
+ .additional_data = cur_entry.additional_data,
.timestamp = cur_entry.timestamp,
};
@@ -1087,7 +1061,7 @@ static void shada_read(FileDescriptor *const sd_reader, const int flags)
sub_set_replacement((SubReplacementString) {
.sub = cur_entry.data.sub_string.sub,
.timestamp = cur_entry.timestamp,
- .additional_elements = cur_entry.data.sub_string.additional_elements,
+ .additional_data = cur_entry.additional_data,
});
// Without using regtilde and without / &cpo flag previous substitute
// string is close to useless: you can only use it with :& or :~ and
@@ -1125,7 +1099,7 @@ static void shada_read(FileDescriptor *const sd_reader, const int flags)
.y_type = cur_entry.data.reg.type,
.y_width = (colnr_T)cur_entry.data.reg.width,
.timestamp = cur_entry.timestamp,
- .additional_data = cur_entry.data.reg.additional_data,
+ .additional_data = cur_entry.additional_data,
}, cur_entry.data.reg.is_unnamed)) {
shada_free_shada_entry(&cur_entry);
}
@@ -1150,7 +1124,7 @@ static void shada_read(FileDescriptor *const sd_reader, const int flags)
.fnum = (buf == NULL ? 0 : buf->b_fnum),
.timestamp = cur_entry.timestamp,
.view = INIT_FMARKV,
- .additional_data = cur_entry.data.filemark.additional_data,
+ .additional_data = cur_entry.additional_data,
},
};
if (cur_entry.type == kSDItemGlobalMark) {
@@ -1192,8 +1166,9 @@ static void shada_read(FileDescriptor *const sd_reader, const int flags)
cur_entry.data.buffer_list.buffers[i].pos, 0, view);
buflist_setfpos(buf, curwin, buf->b_last_cursor.mark.lnum,
buf->b_last_cursor.mark.col, false);
- buf->additional_data =
- cur_entry.data.buffer_list.buffers[i].additional_data;
+
+ xfree(buf->additional_data);
+ buf->additional_data = cur_entry.data.buffer_list.buffers[i].additional_data;
cur_entry.data.buffer_list.buffers[i].additional_data = NULL;
}
}
@@ -1230,7 +1205,7 @@ static void shada_read(FileDescriptor *const sd_reader, const int flags)
.fnum = 0,
.timestamp = cur_entry.timestamp,
.view = INIT_FMARKV,
- .additional_data = cur_entry.data.filemark.additional_data,
+ .additional_data = cur_entry.additional_data,
};
if (cur_entry.type == kSDItemLocalMark) {
if (!mark_set_local(cur_entry.data.filemark.name, buf, fm, !force)) {
@@ -1338,7 +1313,9 @@ static char *shada_filename(const char *file)
return xstrdup(file);
}
-#define PACK_STATIC_STR(s) mpack_str(STATIC_CSTR_AS_STRING(s), &sbuf);
+#define PACK_KEY(s) mpack_str(STATIC_CSTR_AS_STRING(KEY_NAME(s)), &sbuf);
+#define KEY_NAME(s) #s
+#define KEY_NAME2(s) KEY_NAME(s)
#define SHADA_MPACK_FREE_SPACE (4 * MPACK_ITEM_SIZE)
@@ -1349,6 +1326,18 @@ static void shada_check_buffer(PackerBuffer *packer)
}
}
+static uint32_t additional_data_len(AdditionalData *src)
+{
+ return src ? src->nitems : 0;
+}
+
+static void dump_additional_data(AdditionalData *src, PackerBuffer *sbuf)
+{
+ if (src != NULL) {
+ mpack_raw(src->data, src->nbytes, sbuf);
+ }
+}
+
/// Write single ShaDa entry
///
/// @param[in] packer Packer used to write entry.
@@ -1363,37 +1352,7 @@ static ShaDaWriteResult shada_pack_entry(PackerBuffer *const packer, ShadaEntry
{
ShaDaWriteResult ret = kSDWriteFailed;
PackerBuffer sbuf = packer_string_buffer();
-#define DUMP_ADDITIONAL_ELEMENTS(src, what) \
- do { \
- if ((src) != NULL) { \
- TV_LIST_ITER((src), li, { \
- if (encode_vim_to_msgpack(&sbuf, TV_LIST_ITEM_TV(li), \
- _("additional elements of ShaDa " what)) \
- == FAIL) { \
- goto shada_pack_entry_error; \
- } \
- }); \
- } \
- } while (0)
-#define DUMP_ADDITIONAL_DATA(src, what) \
- do { \
- dict_T *const d = (src); \
- if (d != NULL) { \
- size_t todo = d->dv_hashtab.ht_used; \
- for (const hashitem_T *hi = d->dv_hashtab.ht_array; todo; hi++) { \
- if (!HASHITEM_EMPTY(hi)) { \
- todo--; \
- dictitem_T *const di = TV_DICT_HI2DI(hi); \
- mpack_str(cstr_as_string(hi->hi_key), &sbuf); \
- if (encode_vim_to_msgpack(&sbuf, &di->di_tv, \
- _("additional data of ShaDa " what)) \
- == FAIL) { \
- goto shada_pack_entry_error; \
- } \
- } \
- } \
- } \
- } while (0)
+
#define CHECK_DEFAULT(entry, attr) \
(sd_default_values[(entry).type].data.attr == (entry).data.attr)
#define ONE_IF_NOT_DEFAULT(entry, attr) \
@@ -1402,7 +1361,7 @@ static ShaDaWriteResult shada_pack_entry(PackerBuffer *const packer, ShadaEntry
#define PACK_BOOL(entry, name, attr) \
do { \
if (!CHECK_DEFAULT(entry, search_pattern.attr)) { \
- PACK_STATIC_STR(name); \
+ PACK_KEY(name); \
mpack_bool(&sbuf.ptr, !sd_default_values[(entry).type].data.search_pattern.attr); \
} \
} while (0)
@@ -1418,26 +1377,19 @@ static ShaDaWriteResult shada_pack_entry(PackerBuffer *const packer, ShadaEntry
const bool is_hist_search =
entry.data.history_item.histtype == HIST_SEARCH;
uint32_t arr_size = (2 + (uint32_t)is_hist_search
- + (uint32_t)(tv_list_len(entry.data.history_item.additional_elements)));
+ + additional_data_len(entry.additional_data));
mpack_array(&sbuf.ptr, arr_size);
mpack_uint(&sbuf.ptr, entry.data.history_item.histtype);
mpack_bin(cstr_as_string(entry.data.history_item.string), &sbuf);
if (is_hist_search) {
mpack_uint(&sbuf.ptr, (uint8_t)entry.data.history_item.sep);
}
- DUMP_ADDITIONAL_ELEMENTS(entry.data.history_item.additional_elements,
- "history entry item");
+ dump_additional_data(entry.additional_data, &sbuf);
break;
}
case kSDItemVariable: {
- if (entry.data.global_var.value.v_type == VAR_BLOB) {
- // Strings and Blobs both pack as msgpack BINs; differentiate them by
- // storing an additional VAR_TYPE_BLOB element alongside Blobs
- list_T *const list = tv_list_alloc(1);
- tv_list_append_number(list, VAR_TYPE_BLOB);
- entry.data.global_var.additional_elements = list;
- }
- uint32_t arr_size = 2 + (uint32_t)(tv_list_len(entry.data.global_var.additional_elements));
+ bool is_blob = (entry.data.global_var.value.v_type == VAR_BLOB);
+ uint32_t arr_size = 2 + (is_blob ? 1 : 0) + additional_data_len(entry.additional_data);
mpack_array(&sbuf.ptr, arr_size);
const String varname = cstr_as_string(entry.data.global_var.name);
mpack_bin(varname, &sbuf);
@@ -1451,16 +1403,18 @@ static ShaDaWriteResult shada_pack_entry(PackerBuffer *const packer, ShadaEntry
entry.data.global_var.name);
goto shada_pack_entry_error;
}
- DUMP_ADDITIONAL_ELEMENTS(entry.data.global_var.additional_elements,
- "variable item");
+ if (is_blob) {
+ mpack_check_buffer(&sbuf);
+ mpack_integer(&sbuf.ptr, VAR_TYPE_BLOB);
+ }
+ dump_additional_data(entry.additional_data, &sbuf);
break;
}
case kSDItemSubString: {
- uint32_t arr_size = 1 + (uint32_t)(tv_list_len(entry.data.sub_string.additional_elements));
+ uint32_t arr_size = 1 + additional_data_len(entry.additional_data);
mpack_array(&sbuf.ptr, arr_size);
mpack_bin(cstr_as_string(entry.data.sub_string.sub), &sbuf);
- DUMP_ADDITIONAL_ELEMENTS(entry.data.sub_string.additional_elements,
- "sub string item");
+ dump_additional_data(entry.additional_data, &sbuf);
break;
}
case kSDItemSearchPattern: {
@@ -1475,14 +1429,10 @@ static ShaDaWriteResult shada_pack_entry(PackerBuffer *const packer, ShadaEntry
+ ONE_IF_NOT_DEFAULT(entry, search_pattern.highlighted)
+ ONE_IF_NOT_DEFAULT(entry, search_pattern.offset)
+ ONE_IF_NOT_DEFAULT(entry, search_pattern.search_backward)
- // finally, additional data:
- + (entry.data.search_pattern.additional_data
- ? (uint32_t)entry.data.search_pattern.additional_data->dv_hashtab.
- ht_used
- : 0));
+ + additional_data_len(entry.additional_data));
mpack_map(&sbuf.ptr, entry_map_size);
- PACK_STATIC_STR(SEARCH_KEY_PAT);
- mpack_bin(cstr_as_string(entry.data.search_pattern.pat), &sbuf);
+ PACK_KEY(SEARCH_KEY_PAT);
+ mpack_bin(entry.data.search_pattern.pat, &sbuf);
PACK_BOOL(entry, SEARCH_KEY_MAGIC, magic);
PACK_BOOL(entry, SEARCH_KEY_IS_LAST_USED, is_last_used);
PACK_BOOL(entry, SEARCH_KEY_SMARTCASE, smartcase);
@@ -1492,12 +1442,11 @@ static ShaDaWriteResult shada_pack_entry(PackerBuffer *const packer, ShadaEntry
PACK_BOOL(entry, SEARCH_KEY_HIGHLIGHTED, highlighted);
PACK_BOOL(entry, SEARCH_KEY_BACKWARD, search_backward);
if (!CHECK_DEFAULT(entry, search_pattern.offset)) {
- PACK_STATIC_STR(SEARCH_KEY_OFFSET);
+ PACK_KEY(SEARCH_KEY_OFFSET);
mpack_integer(&sbuf.ptr, entry.data.search_pattern.offset);
}
#undef PACK_BOOL
- DUMP_ADDITIONAL_DATA(entry.data.search_pattern.additional_data,
- "search pattern item");
+ dump_additional_data(entry.additional_data, &sbuf);
break;
}
case kSDItemChange:
@@ -1508,31 +1457,26 @@ static ShaDaWriteResult shada_pack_entry(PackerBuffer *const packer, ShadaEntry
+ ONE_IF_NOT_DEFAULT(entry, filemark.mark.lnum)
+ ONE_IF_NOT_DEFAULT(entry, filemark.mark.col)
+ ONE_IF_NOT_DEFAULT(entry, filemark.name)
- // Additional entries, if any:
- + (
- entry.data.filemark.additional_data == NULL
- ? 0
- : entry.data.filemark.additional_data->dv_hashtab.ht_used));
+ + additional_data_len(entry.additional_data));
mpack_map(&sbuf.ptr, (uint32_t)entry_map_size);
- PACK_STATIC_STR(KEY_FILE);
+ PACK_KEY(KEY_FILE);
mpack_bin(cstr_as_string(entry.data.filemark.fname), &sbuf);
if (!CHECK_DEFAULT(entry, filemark.mark.lnum)) {
- PACK_STATIC_STR(KEY_LNUM);
+ PACK_KEY(KEY_LNUM);
mpack_integer(&sbuf.ptr, entry.data.filemark.mark.lnum);
}
if (!CHECK_DEFAULT(entry, filemark.mark.col)) {
- PACK_STATIC_STR(KEY_COL);
+ PACK_KEY(KEY_COL);
mpack_integer(&sbuf.ptr, entry.data.filemark.mark.col);
}
assert(entry.type == kSDItemJump || entry.type == kSDItemChange
? CHECK_DEFAULT(entry, filemark.name)
: true);
if (!CHECK_DEFAULT(entry, filemark.name)) {
- PACK_STATIC_STR(KEY_NAME_CHAR);
+ PACK_KEY(KEY_NAME_CHAR);
mpack_uint(&sbuf.ptr, (uint8_t)entry.data.filemark.name);
}
- DUMP_ADDITIONAL_DATA(entry.data.filemark.additional_data,
- "mark (change, jump, global or local) item");
+ dump_additional_data(entry.additional_data, &sbuf);
break;
}
case kSDItemRegister: {
@@ -1540,31 +1484,29 @@ static ShaDaWriteResult shada_pack_entry(PackerBuffer *const packer, ShadaEntry
+ ONE_IF_NOT_DEFAULT(entry, reg.type)
+ ONE_IF_NOT_DEFAULT(entry, reg.width)
+ ONE_IF_NOT_DEFAULT(entry, reg.is_unnamed)
- // Additional entries, if any:
- + (entry.data.reg.additional_data == NULL
- ? 0
- : (uint32_t)entry.data.reg.additional_data->dv_hashtab.ht_used));
+ + additional_data_len(entry.additional_data));
+
mpack_map(&sbuf.ptr, entry_map_size);
- PACK_STATIC_STR(REG_KEY_CONTENTS);
+ PACK_KEY(REG_KEY_CONTENTS);
mpack_array(&sbuf.ptr, (uint32_t)entry.data.reg.contents_size);
for (size_t i = 0; i < entry.data.reg.contents_size; i++) {
mpack_bin(cstr_as_string(entry.data.reg.contents[i]), &sbuf);
}
- PACK_STATIC_STR(KEY_NAME_CHAR);
+ PACK_KEY(KEY_NAME_CHAR);
mpack_uint(&sbuf.ptr, (uint8_t)entry.data.reg.name);
if (!CHECK_DEFAULT(entry, reg.type)) {
- PACK_STATIC_STR(REG_KEY_TYPE);
+ PACK_KEY(REG_KEY_TYPE);
mpack_uint(&sbuf.ptr, (uint8_t)entry.data.reg.type);
}
if (!CHECK_DEFAULT(entry, reg.width)) {
- PACK_STATIC_STR(REG_KEY_WIDTH);
+ PACK_KEY(REG_KEY_WIDTH);
mpack_uint64(&sbuf.ptr, (uint64_t)entry.data.reg.width);
}
if (!CHECK_DEFAULT(entry, reg.is_unnamed)) {
- PACK_STATIC_STR(REG_KEY_UNNAMED);
+ PACK_KEY(REG_KEY_UNNAMED);
mpack_bool(&sbuf.ptr, entry.data.reg.is_unnamed);
}
- DUMP_ADDITIONAL_DATA(entry.data.reg.additional_data, "register item");
+ dump_additional_data(entry.additional_data, &sbuf);
break;
}
case kSDItemBufferList:
@@ -1575,24 +1517,20 @@ static ShaDaWriteResult shada_pack_entry(PackerBuffer *const packer, ShadaEntry
!= default_pos.lnum)
+ (size_t)(entry.data.buffer_list.buffers[i].pos.col
!= default_pos.col)
- // Additional entries, if any:
- + (entry.data.buffer_list.buffers[i].additional_data == NULL
- ? 0
- : (entry.data.buffer_list.buffers[i].additional_data
- ->dv_hashtab.ht_used)));
+ + additional_data_len(entry.data.buffer_list.buffers[i].
+ additional_data));
mpack_map(&sbuf.ptr, (uint32_t)entry_map_size);
- PACK_STATIC_STR(KEY_FILE);
+ PACK_KEY(KEY_FILE);
mpack_bin(cstr_as_string(entry.data.buffer_list.buffers[i].fname), &sbuf);
if (entry.data.buffer_list.buffers[i].pos.lnum != 1) {
- PACK_STATIC_STR(KEY_LNUM);
+ PACK_KEY(KEY_LNUM);
mpack_uint64(&sbuf.ptr, (uint64_t)entry.data.buffer_list.buffers[i].pos.lnum);
}
if (entry.data.buffer_list.buffers[i].pos.col != 0) {
- PACK_STATIC_STR(KEY_COL);
+ PACK_KEY(KEY_COL);
mpack_uint64(&sbuf.ptr, (uint64_t)entry.data.buffer_list.buffers[i].pos.col);
}
- DUMP_ADDITIONAL_DATA(entry.data.buffer_list.buffers[i].additional_data,
- "buffer list subitem");
+ dump_additional_data(entry.data.buffer_list.buffers[i].additional_data, &sbuf);
}
break;
case kSDItemHeader:
@@ -1686,76 +1624,29 @@ static int compare_file_marks(const void *a, const void *b)
///
/// @return kSDReadStatusNotShaDa, kSDReadStatusReadError or
/// kSDReadStatusSuccess.
-static inline ShaDaReadResult shada_parse_msgpack(FileDescriptor *const sd_reader,
- const size_t length,
- msgpack_unpacked *ret_unpacked,
- char **const ret_buf)
- FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1)
+static ShaDaReadResult shada_check_status(uintmax_t initial_fpos, int status, size_t remaining)
+ FUNC_ATTR_WARN_UNUSED_RESULT
{
- const uintmax_t initial_fpos = sd_reader->bytes_read;
- char *const buf = xmalloc(length);
-
- const ShaDaReadResult fl_ret = fread_len(sd_reader, buf, length);
- if (fl_ret != kSDReadStatusSuccess) {
- xfree(buf);
- return fl_ret;
- }
- bool did_try_to_free = false;
-shada_parse_msgpack_read_next: {}
- size_t off = 0;
- msgpack_unpacked unpacked;
- msgpack_unpacked_init(&unpacked);
- const msgpack_unpack_return result =
- msgpack_unpack_next(&unpacked, buf, length, &off);
- ShaDaReadResult ret = kSDReadStatusSuccess;
- switch (result) {
- case MSGPACK_UNPACK_SUCCESS:
- if (off < length) {
- goto shada_parse_msgpack_extra_bytes;
+ switch (status) {
+ case MPACK_OK:
+ if (remaining) {
+ semsg(_(RCERR "Failed to parse ShaDa file: extra bytes in msgpack string "
+ "at position %" PRIu64),
+ (uint64_t)initial_fpos);
+ return kSDReadStatusNotShaDa;
}
- break;
- case MSGPACK_UNPACK_PARSE_ERROR:
- semsg(_(RCERR "Failed to parse ShaDa file due to a msgpack parser error "
- "at position %" PRIu64),
- (uint64_t)initial_fpos);
- ret = kSDReadStatusNotShaDa;
- break;
- case MSGPACK_UNPACK_NOMEM_ERROR:
- if (!did_try_to_free) {
- did_try_to_free = true;
- try_to_free_memory();
- goto shada_parse_msgpack_read_next;
- }
- emsg(_(e_outofmem));
- ret = kSDReadStatusReadError;
- break;
- case MSGPACK_UNPACK_CONTINUE:
+ return kSDReadStatusSuccess;
+ case MPACK_EOF:
semsg(_(RCERR "Failed to parse ShaDa file: incomplete msgpack string "
"at position %" PRIu64),
(uint64_t)initial_fpos);
- ret = kSDReadStatusNotShaDa;
- break;
- case MSGPACK_UNPACK_EXTRA_BYTES:
-shada_parse_msgpack_extra_bytes:
- semsg(_(RCERR "Failed to parse ShaDa file: extra bytes in msgpack string "
+ return kSDReadStatusNotShaDa;
+ default:
+ semsg(_(RCERR "Failed to parse ShaDa file due to a msgpack parser error "
"at position %" PRIu64),
(uint64_t)initial_fpos);
- ret = kSDReadStatusNotShaDa;
- break;
- }
- if (ret_buf != NULL && ret == kSDReadStatusSuccess) {
- if (ret_unpacked == NULL) {
- msgpack_unpacked_destroy(&unpacked);
- } else {
- *ret_unpacked = unpacked;
- }
- *ret_buf = buf;
- } else {
- assert(ret_buf == NULL || ret != kSDReadStatusSuccess);
- msgpack_unpacked_destroy(&unpacked);
- xfree(buf);
+ return kSDReadStatusNotShaDa;
}
- return ret;
}
/// Format shada entry for debugging purposes
@@ -1772,25 +1663,16 @@ static const char *shada_format_entry(const ShadaEntry entry)
// ^ Space for `can_free_entry`
#define FORMAT_MARK_ENTRY(entry_name, name_fmt, name_fmt_arg) \
do { \
- typval_T ad_tv = { \
- .v_type = VAR_DICT, \
- .vval.v_dict = entry.data.filemark.additional_data \
- }; \
- size_t ad_len; \
- char *const ad = encode_tv2string(&ad_tv, &ad_len); \
vim_snprintf_add(S_LEN(ret), \
entry_name " {" name_fmt " file=[%zu]\"%.512s\", " \
"pos={l=%" PRIdLINENR ",c=%" PRIdCOLNR ",a=%" PRIdCOLNR "}, " \
- "ad={%p:[%zu]%.64s} }", \
+ "}", \
name_fmt_arg, \
strlen(entry.data.filemark.fname), \
entry.data.filemark.fname, \
entry.data.filemark.mark.lnum, \
entry.data.filemark.mark.col, \
- entry.data.filemark.mark.coladd, \
- (void *)entry.data.filemark.additional_data, \
- ad_len, \
- ad); \
+ entry.data.filemark.mark.coladd); \
} while (0)
switch (entry.type) {
case kSDItemMissing:
@@ -1974,8 +1856,8 @@ static inline ShaDaWriteResult shada_read_when_writing(FileDescriptor *const sd_
}
// Ignore duplicates.
if (wms_entry.timestamp == entry.timestamp
- && (wms_entry.data.filemark.additional_data == NULL
- && entry.data.filemark.additional_data == NULL)
+ && (wms_entry.additional_data == NULL
+ && entry.additional_data == NULL)
&& marks_equal(wms_entry.data.filemark.mark,
entry.data.filemark.mark)
&& strcmp(wms_entry.data.filemark.fname,
@@ -2203,11 +2085,11 @@ static inline void add_search_pattern(PossiblyFreedShadaEntry *const ret_pse,
.is_substitute_pattern = is_substitute_pattern,
.highlighted = ((is_substitute_pattern ^ search_last_used)
&& search_highlighted),
- .pat = pat.pat,
- .additional_data = pat.additional_data,
+ .pat = cstr_as_string(pat.pat),
.search_backward = (!is_substitute_pattern && pat.off.dir == '?'),
}
- }
+ },
+ .additional_data = pat.additional_data,
}
};
}
@@ -2244,11 +2126,11 @@ static inline void shada_initialize_registers(WriteMergerState *const wms, int m
.contents_size = reg.y_size,
.type = reg.y_type,
.width = (size_t)(reg.y_type == kMTBlockWise ? reg.y_width : 0),
- .additional_data = reg.additional_data,
.name = name,
.is_unnamed = is_unnamed,
}
- }
+ },
+ .additional_data = reg.additional_data,
}
};
} while (reg_iter != NULL);
@@ -2494,9 +2376,9 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer,
.global_var = {
.name = (char *)name,
.value = tgttv,
- .additional_elements = NULL,
}
- }
+ },
+ .additional_data = NULL,
}, max_kbyte)) == kSDWriteFailed) {
tv_clear(&vartv);
tv_clear(&tgttv);
@@ -2538,9 +2420,9 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer,
.data = {
.sub_string = {
.sub = sub.sub,
- .additional_elements = sub.additional_elements,
}
- }
+ },
+ .additional_data = sub.additional_data,
}
};
}
@@ -2580,10 +2462,10 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer,
.filemark = {
.mark = fm.fmark.mark,
.name = name,
- .additional_data = fm.fmark.additional_data,
.fname = (char *)fname,
}
- }
+ },
+ .additional_data = fm.fmark.additional_data,
},
};
if (ascii_isdigit(name)) {
@@ -2629,9 +2511,9 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer,
.mark = fm.mark,
.name = name,
.fname = (char *)fname,
- .additional_data = fm.additional_data,
}
- }
+ },
+ .additional_data = fm.additional_data,
}
};
if (fm.timestamp > filemarks->greatest_timestamp) {
@@ -2649,9 +2531,9 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer,
.filemark = {
.mark = fm.mark,
.fname = (char *)fname,
- .additional_data = fm.additional_data,
}
- }
+ },
+ .additional_data = fm.additional_data,
}
};
if (fm.timestamp > filemarks->greatest_timestamp) {
@@ -2682,10 +2564,10 @@ static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer,
.filemark = {
.mark = curwin->w_cursor,
.name = '0',
- .additional_data = NULL,
.fname = curbuf->b_ffname,
}
- }
+ },
+ .additional_data = NULL,
},
});
}
@@ -2799,7 +2681,7 @@ shada_write_exit:
return ret;
}
-#undef PACK_STATIC_STR
+#undef PACK_KEY
/// Write ShaDa file to a given location
///
@@ -3035,41 +2917,36 @@ static void shada_free_shada_entry(ShadaEntry *const entry)
case kSDItemJump:
case kSDItemGlobalMark:
case kSDItemLocalMark:
- tv_dict_unref(entry->data.filemark.additional_data);
xfree(entry->data.filemark.fname);
break;
case kSDItemSearchPattern:
- tv_dict_unref(entry->data.search_pattern.additional_data);
- xfree(entry->data.search_pattern.pat);
+ api_free_string(entry->data.search_pattern.pat);
break;
case kSDItemRegister:
- tv_dict_unref(entry->data.reg.additional_data);
for (size_t i = 0; i < entry->data.reg.contents_size; i++) {
xfree(entry->data.reg.contents[i]);
}
xfree(entry->data.reg.contents);
break;
case kSDItemHistoryEntry:
- tv_list_unref(entry->data.history_item.additional_elements);
xfree(entry->data.history_item.string);
break;
case kSDItemVariable:
- tv_list_unref(entry->data.global_var.additional_elements);
xfree(entry->data.global_var.name);
tv_clear(&entry->data.global_var.value);
break;
case kSDItemSubString:
- tv_list_unref(entry->data.sub_string.additional_elements);
xfree(entry->data.sub_string.sub);
break;
case kSDItemBufferList:
for (size_t i = 0; i < entry->data.buffer_list.size; i++) {
xfree(entry->data.buffer_list.buffers[i].fname);
- tv_dict_unref(entry->data.buffer_list.buffers[i].additional_data);
+ xfree(entry->data.buffer_list.buffers[i].additional_data);
}
xfree(entry->data.buffer_list.buffers);
break;
}
+ XFREE_CLEAR(entry->additional_data);
}
#ifndef HAVE_BE64TOH
@@ -3203,128 +3080,6 @@ static ShaDaReadResult msgpack_read_uint64(FileDescriptor *const sd_reader, bool
RERR "Error while reading ShaDa file: " \
entry_name " entry at position %" PRIu64 " " \
error_desc
-#define CHECK_KEY(key, \
- expected) ((key).via.str.size == (sizeof(expected) - 1) \
- && strncmp((key).via.str.ptr, expected, (sizeof(expected) - 1)) == 0)
-#define CLEAR_GA_AND_ERROR_OUT(ga) \
- do { \
- ga_clear(&(ga)); \
- goto shada_read_next_item_error; \
- } while (0)
-#define ID(s) s
-#define BINDUP(b) xmemdupz((b).ptr, (b).size)
-#define TOINT(s) ((int)(s))
-#define TOCHAR(s) ((char)(s))
-#define TOU8(s) ((uint8_t)(s))
-#define TOSIZE(s) ((size_t)(s))
-#define CHECKED_ENTRY(condition, error_desc, entry_name, obj, tgt, attr, \
- proc) \
- do { \
- if (!(condition)) { \
- semsg(_(READERR(entry_name, error_desc)), initial_fpos); \
- CLEAR_GA_AND_ERROR_OUT(ad_ga); \
- } \
- (tgt) = proc((obj).via.attr); \
- } while (0)
-#define CHECK_KEY_IS_STR(un, entry_name) \
- if ((un).data.via.map.ptr[i].key.type != MSGPACK_OBJECT_STR) { \
- semsg(_(READERR(entry_name, "has key which is not a string")), \
- initial_fpos); \
- CLEAR_GA_AND_ERROR_OUT(ad_ga); \
- } else if ((un).data.via.map.ptr[i].key.via.str.size == 0) { \
- semsg(_(READERR(entry_name, "has empty key")), initial_fpos); \
- CLEAR_GA_AND_ERROR_OUT(ad_ga); \
- }
-#define CHECKED_KEY(un, entry_name, name, error_desc, tgt, condition, attr, proc) \
- else if (CHECK_KEY((un).data.via.map.ptr[i].key, name)) \
- { \
- CHECKED_ENTRY(condition, \
- "has " name " key value " error_desc, \
- entry_name, \
- (un).data.via.map.ptr[i].val, \
- tgt, \
- attr, \
- proc); \
- }
-#define TYPED_KEY(un, entry_name, name, type_name, tgt, objtype, attr, proc) \
- CHECKED_KEY(un, entry_name, name, "which is not " type_name, tgt, \
- (un).data.via.map.ptr[i].val.type == MSGPACK_OBJECT_##objtype, \
- attr, proc)
-#define BOOLEAN_KEY(un, entry_name, name, tgt) \
- TYPED_KEY(un, entry_name, name, "a boolean", tgt, BOOLEAN, boolean, ID)
-#define STRING_KEY(un, entry_name, name, tgt) \
- TYPED_KEY(un, entry_name, name, "a binary", tgt, BIN, bin, BINDUP)
-#define CONVERTED_STRING_KEY(un, entry_name, name, tgt) \
- TYPED_KEY(un, entry_name, name, "a binary", tgt, BIN, bin, \
- BIN_CONVERTED)
-#define INT_KEY(un, entry_name, name, tgt, proc) \
- CHECKED_KEY(un, entry_name, name, "which is not an integer", tgt, \
- (((un).data.via.map.ptr[i].val.type \
- == MSGPACK_OBJECT_POSITIVE_INTEGER) \
- || ((un).data.via.map.ptr[i].val.type \
- == MSGPACK_OBJECT_NEGATIVE_INTEGER)), \
- i64, proc)
-#define INTEGER_KEY(un, entry_name, name, tgt) \
- INT_KEY(un, entry_name, name, tgt, TOINT)
-#define ADDITIONAL_KEY(un) \
- else { \
- ga_grow(&ad_ga, 1); \
- memcpy(((char *)ad_ga.ga_data) + ((size_t)ad_ga.ga_len \
- * sizeof(*(un).data.via.map.ptr)), \
- (un).data.via.map.ptr + i, \
- sizeof(*(un).data.via.map.ptr)); \
- ad_ga.ga_len++; \
- }
-#define BIN_CONVERTED(b) (xmemdupz(((b).ptr), ((b).size)))
-#define SET_ADDITIONAL_DATA(tgt, name) \
- do { \
- if (ad_ga.ga_len) { \
- msgpack_object obj = { \
- .type = MSGPACK_OBJECT_MAP, \
- .via = { \
- .map = { \
- .size = (uint32_t)ad_ga.ga_len, \
- .ptr = ad_ga.ga_data, \
- } \
- } \
- }; \
- typval_T adtv; \
- if (msgpack_to_vim(obj, &adtv) == FAIL \
- || adtv.v_type != VAR_DICT) { \
- semsg(_(READERR(name, \
- "cannot be converted to a Vimscript dictionary")), \
- initial_fpos); \
- ga_clear(&ad_ga); \
- tv_clear(&adtv); \
- goto shada_read_next_item_error; \
- } \
- (tgt) = adtv.vval.v_dict; \
- } \
- ga_clear(&ad_ga); \
- } while (0)
-#define SET_ADDITIONAL_ELEMENTS(src, src_maxsize, tgt, name) \
- do { \
- if ((src).size > (size_t)(src_maxsize)) { \
- msgpack_object obj = { \
- .type = MSGPACK_OBJECT_ARRAY, \
- .via = { \
- .array = { \
- .size = ((src).size - (uint32_t)(src_maxsize)), \
- .ptr = (src).ptr + (src_maxsize), \
- } \
- } \
- }; \
- typval_T aetv; \
- if (msgpack_to_vim(obj, &aetv) == FAIL) { \
- semsg(_(READERR(name, "cannot be converted to a Vimscript list")), \
- initial_fpos); \
- tv_clear(&aetv); \
- goto shada_read_next_item_error; \
- } \
- assert(aetv.v_type == VAR_LIST); \
- (tgt) = aetv.vval.v_list; \
- } \
- } while (0)
/// Iterate over shada file contents
///
@@ -3352,6 +3107,8 @@ shada_read_next_item_start:
return kSDReadStatusFinished;
}
+ bool verify_but_ignore = false;
+
// First: manually unpack type, timestamp and length.
// This is needed to avoid both seeking and having to maintain a buffer.
uint64_t type_u64 = (uint64_t)kSDItemMissing;
@@ -3359,6 +3116,9 @@ shada_read_next_item_start:
uint64_t length_u64;
const uint64_t initial_fpos = sd_reader->bytes_read;
+ AdditionalDataBuilder ad = KV_INITIAL_VALUE;
+ uint32_t read_additional_array_elements = 0;
+ char *error_alloc = NULL;
ShaDaReadResult mru_ret;
if (((mru_ret = msgpack_read_uint64(sd_reader, true, &type_u64))
@@ -3406,16 +3166,42 @@ shada_read_next_item_start:
// in incomplete MessagePack string.
if (initial_fpos == 0
&& (type_u64 == '\n' || type_u64 > SHADA_LAST_ENTRY)) {
- const ShaDaReadResult spm_ret = shada_parse_msgpack(sd_reader, length,
- NULL, NULL);
- if (spm_ret != kSDReadStatusSuccess) {
- return spm_ret;
- }
+ verify_but_ignore = true;
} else {
const ShaDaReadResult srs_ret = sd_reader_skip(sd_reader, length);
if (srs_ret != kSDReadStatusSuccess) {
return srs_ret;
}
+ goto shada_read_next_item_start;
+ }
+ }
+
+ const uint64_t parse_pos = sd_reader->bytes_read;
+ bool buf_allocated = false;
+ // try to avoid allocation for small items which fits entirely
+ // in the internal buffer of sd_reader
+ char *buf = file_try_read_buffered(sd_reader, length);
+ if (!buf) {
+ buf_allocated = true;
+ buf = xmalloc(length);
+ const ShaDaReadResult fl_ret = fread_len(sd_reader, buf, length);
+ if (fl_ret != kSDReadStatusSuccess) {
+ ret = fl_ret;
+ goto shada_read_next_item_error;
+ }
+ }
+
+ const char *read_ptr = buf;
+ size_t read_size = length;
+
+ if (verify_but_ignore) {
+ int status = unpack_skip(&read_ptr, &read_size);
+ ShaDaReadResult spm_ret = shada_check_status(parse_pos, status, read_size);
+ if (buf_allocated) {
+ xfree(buf);
+ }
+ if (spm_ret != kSDReadStatusSuccess) {
+ return spm_ret;
}
goto shada_read_next_item_start;
}
@@ -3425,32 +3211,20 @@ shada_read_next_item_start:
entry->data.unknown_item.size = length;
entry->data.unknown_item.type = type_u64;
if (initial_fpos == 0) {
- const ShaDaReadResult spm_ret = shada_parse_msgpack(sd_reader, length, NULL,
- &entry->data.unknown_item.contents);
+ int status = unpack_skip(&read_ptr, &read_size);
+ ShaDaReadResult spm_ret = shada_check_status(parse_pos, status, read_size);
if (spm_ret != kSDReadStatusSuccess) {
+ if (buf_allocated) {
+ xfree(buf);
+ }
entry->type = kSDItemMissing;
+ return spm_ret;
}
- return spm_ret;
- }
- entry->data.unknown_item.contents = xmalloc(length);
- const ShaDaReadResult fl_ret =
- fread_len(sd_reader, entry->data.unknown_item.contents, length);
- if (fl_ret != kSDReadStatusSuccess) {
- shada_free_shada_entry(entry);
- entry->type = kSDItemMissing;
}
- return fl_ret;
+ entry->data.unknown_item.contents = buf_allocated ? buf : xmemdup(buf, length);
+ return kSDReadStatusSuccess;
}
- msgpack_unpacked unpacked;
- char *buf = NULL;
-
- const ShaDaReadResult spm_ret = shada_parse_msgpack(sd_reader, length,
- &unpacked, &buf);
- if (spm_ret != kSDReadStatusSuccess) {
- ret = spm_ret;
- goto shada_read_next_item_error;
- }
entry->data = sd_default_values[type_u64].data;
switch ((ShadaEntryType)type_u64) {
case kSDItemHeader:
@@ -3459,363 +3233,286 @@ shada_read_next_item_start:
// Dictionary, but that value was never used)
break;
case kSDItemSearchPattern: {
- if (unpacked.data.type != MSGPACK_OBJECT_MAP) {
- semsg(_(READERR("search pattern", "is not a dictionary")),
- initial_fpos);
+ Dict(_shada_search_pat) *it = &entry->data.search_pattern;
+ if (!unpack_keydict(it, DictHash(_shada_search_pat), &ad, &read_ptr, &read_size,
+ &error_alloc)) {
+ semsg(_(READERR("search pattern", "%s")), initial_fpos, error_alloc);
+ it->pat = NULL_STRING;
goto shada_read_next_item_error;
}
- garray_T ad_ga;
- ga_init(&ad_ga, sizeof(*(unpacked.data.via.map.ptr)), 1);
- for (size_t i = 0; i < unpacked.data.via.map.size; i++) {
- CHECK_KEY_IS_STR(unpacked, "search pattern")
- BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_MAGIC,
- entry->data.search_pattern.magic)
- BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_SMARTCASE,
- entry->data.search_pattern.smartcase)
- BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_HAS_LINE_OFFSET,
- entry->data.search_pattern.has_line_offset)
- BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_PLACE_CURSOR_AT_END,
- entry->data.search_pattern.place_cursor_at_end)
- BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_IS_LAST_USED,
- entry->data.search_pattern.is_last_used)
- BOOLEAN_KEY(unpacked, "search pattern",
- SEARCH_KEY_IS_SUBSTITUTE_PATTERN,
- entry->data.search_pattern.is_substitute_pattern)
- BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_HIGHLIGHTED,
- entry->data.search_pattern.highlighted)
- BOOLEAN_KEY(unpacked, "search pattern", SEARCH_KEY_BACKWARD,
- entry->data.search_pattern.search_backward)
- INTEGER_KEY(unpacked, "search pattern", SEARCH_KEY_OFFSET,
- entry->data.search_pattern.offset)
- CONVERTED_STRING_KEY(unpacked, "search pattern", SEARCH_KEY_PAT,
- entry->data.search_pattern.pat)
- ADDITIONAL_KEY(unpacked)
- }
- if (entry->data.search_pattern.pat == NULL) {
+
+ if (!HAS_KEY(it, _shada_search_pat, sp)) { // SEARCH_KEY_PAT
semsg(_(READERR("search pattern", "has no pattern")), initial_fpos);
- CLEAR_GA_AND_ERROR_OUT(ad_ga);
+ goto shada_read_next_item_error;
}
- SET_ADDITIONAL_DATA(entry->data.search_pattern.additional_data,
- "search pattern");
+ entry->data.search_pattern.pat = copy_string(entry->data.search_pattern.pat, NULL);
+
break;
}
case kSDItemChange:
case kSDItemJump:
case kSDItemGlobalMark:
case kSDItemLocalMark: {
- if (unpacked.data.type != MSGPACK_OBJECT_MAP) {
- semsg(_(READERR("mark", "is not a dictionary")), initial_fpos);
+ Dict(_shada_mark) it = { 0 };
+ if (!unpack_keydict(&it, DictHash(_shada_mark), &ad, &read_ptr, &read_size, &error_alloc)) {
+ semsg(_(READERR("mark", "%s")), initial_fpos, error_alloc);
goto shada_read_next_item_error;
}
- garray_T ad_ga;
- ga_init(&ad_ga, sizeof(*(unpacked.data.via.map.ptr)), 1);
- for (size_t i = 0; i < unpacked.data.via.map.size; i++) {
- CHECK_KEY_IS_STR(unpacked, "mark")
- if (CHECK_KEY(unpacked.data.via.map.ptr[i].key, KEY_NAME_CHAR)) {
- if (type_u64 == kSDItemJump || type_u64 == kSDItemChange) {
- semsg(_(READERR("mark", "has n key which is only valid for "
- "local and global mark entries")), initial_fpos);
- CLEAR_GA_AND_ERROR_OUT(ad_ga);
- }
- CHECKED_ENTRY((unpacked.data.via.map.ptr[i].val.type
- == MSGPACK_OBJECT_POSITIVE_INTEGER),
- "has n key value which is not an unsigned integer",
- "mark", unpacked.data.via.map.ptr[i].val,
- entry->data.filemark.name, u64, TOCHAR);
+
+ if (HAS_KEY(&it, _shada_mark, n)) {
+ if (type_u64 == kSDItemJump || type_u64 == kSDItemChange) {
+ semsg(_(READERR("mark", "has n key which is only valid for "
+ "local and global mark entries")), initial_fpos);
+ goto shada_read_next_item_error;
}
- INTEGER_KEY(unpacked, "mark", KEY_LNUM, entry->data.filemark.mark.lnum)
- INTEGER_KEY(unpacked, "mark", KEY_COL, entry->data.filemark.mark.col)
- STRING_KEY(unpacked, "mark", KEY_FILE, entry->data.filemark.fname)
- ADDITIONAL_KEY(unpacked)
+ entry->data.filemark.name = (char)it.n;
+ }
+
+ if (HAS_KEY(&it, _shada_mark, l)) {
+ entry->data.filemark.mark.lnum = (linenr_T)it.l;
}
+ if (HAS_KEY(&it, _shada_mark, c)) {
+ entry->data.filemark.mark.col = (colnr_T)it.c;
+ }
+ if (HAS_KEY(&it, _shada_mark, f)) {
+ entry->data.filemark.fname = xmemdupz(it.f.data, it.f.size);
+ }
+
if (entry->data.filemark.fname == NULL) {
semsg(_(READERR("mark", "is missing file name")), initial_fpos);
- CLEAR_GA_AND_ERROR_OUT(ad_ga);
+ goto shada_read_next_item_error;
}
if (entry->data.filemark.mark.lnum <= 0) {
semsg(_(READERR("mark", "has invalid line number")), initial_fpos);
- CLEAR_GA_AND_ERROR_OUT(ad_ga);
+ goto shada_read_next_item_error;
}
if (entry->data.filemark.mark.col < 0) {
semsg(_(READERR("mark", "has invalid column number")), initial_fpos);
- CLEAR_GA_AND_ERROR_OUT(ad_ga);
+ goto shada_read_next_item_error;
}
- SET_ADDITIONAL_DATA(entry->data.filemark.additional_data, "mark");
break;
}
case kSDItemRegister: {
- if (unpacked.data.type != MSGPACK_OBJECT_MAP) {
- semsg(_(READERR("register", "is not a dictionary")), initial_fpos);
+ Dict(_shada_register) it = { 0 };
+ if (!unpack_keydict(&it, DictHash(_shada_register), &ad, &read_ptr, &read_size, &error_alloc)) {
+ semsg(_(READERR("register", "%s")), initial_fpos, error_alloc);
+ kv_destroy(it.rc);
goto shada_read_next_item_error;
}
- garray_T ad_ga;
- ga_init(&ad_ga, sizeof(*(unpacked.data.via.map.ptr)), 1);
- for (size_t i = 0; i < unpacked.data.via.map.size; i++) {
- CHECK_KEY_IS_STR(unpacked, "register")
- if (CHECK_KEY(unpacked.data.via.map.ptr[i].key,
- REG_KEY_CONTENTS)) {
- if (unpacked.data.via.map.ptr[i].val.type != MSGPACK_OBJECT_ARRAY) {
- semsg(_(READERR("register",
- "has " REG_KEY_CONTENTS
- " key with non-array value")),
- initial_fpos);
- CLEAR_GA_AND_ERROR_OUT(ad_ga);
- }
- if (unpacked.data.via.map.ptr[i].val.via.array.size == 0) {
- semsg(_(READERR("register",
- "has " REG_KEY_CONTENTS " key with empty array")),
- initial_fpos);
- CLEAR_GA_AND_ERROR_OUT(ad_ga);
- }
- const msgpack_object_array arr =
- unpacked.data.via.map.ptr[i].val.via.array;
- for (size_t j = 0; j < arr.size; j++) {
- if (arr.ptr[j].type != MSGPACK_OBJECT_BIN) {
- semsg(_(READERR("register", "has " REG_KEY_CONTENTS " array "
- "with non-binary value")), initial_fpos);
- CLEAR_GA_AND_ERROR_OUT(ad_ga);
- }
- }
- entry->data.reg.contents_size = arr.size;
- entry->data.reg.contents = xmalloc(arr.size * sizeof(char *));
- for (size_t j = 0; j < arr.size; j++) {
- entry->data.reg.contents[j] = BIN_CONVERTED(arr.ptr[j].via.bin);
- }
- }
- BOOLEAN_KEY(unpacked, "register", REG_KEY_UNNAMED,
- entry->data.reg.is_unnamed)
- TYPED_KEY(unpacked, "register", REG_KEY_TYPE, "an unsigned integer",
- entry->data.reg.type, POSITIVE_INTEGER, u64, TOU8)
- TYPED_KEY(unpacked, "register", KEY_NAME_CHAR, "an unsigned integer",
- entry->data.reg.name, POSITIVE_INTEGER, u64, TOCHAR)
- TYPED_KEY(unpacked, "register", REG_KEY_WIDTH, "an unsigned integer",
- entry->data.reg.width, POSITIVE_INTEGER, u64, TOSIZE)
- ADDITIONAL_KEY(unpacked)
- }
- if (entry->data.reg.contents == NULL) {
- semsg(_(READERR("register", "has missing " REG_KEY_CONTENTS " array")),
+ if (it.rc.size == 0) {
+ semsg(_(READERR("register",
+ "has " KEY_NAME2(REG_KEY_CONTENTS) " key with missing or empty array")),
initial_fpos);
- CLEAR_GA_AND_ERROR_OUT(ad_ga);
+ goto shada_read_next_item_error;
}
- SET_ADDITIONAL_DATA(entry->data.reg.additional_data, "register");
+ entry->data.reg.contents_size = it.rc.size;
+ entry->data.reg.contents = xmalloc(it.rc.size * sizeof(char *));
+ for (size_t j = 0; j < it.rc.size; j++) {
+ entry->data.reg.contents[j] = xmemdupz(it.rc.items[j].data, it.rc.items[j].size);
+ }
+ kv_destroy(it.rc);
+
+#define REGISTER_VAL(name, loc, type) \
+ if (HAS_KEY(&it, _shada_register, name)) { \
+ loc = (type)it.name; \
+ }
+ REGISTER_VAL(REG_KEY_UNNAMED, entry->data.reg.is_unnamed, bool)
+ REGISTER_VAL(REG_KEY_TYPE, entry->data.reg.type, uint8_t)
+ REGISTER_VAL(KEY_NAME_CHAR, entry->data.reg.name, char)
+ REGISTER_VAL(REG_KEY_WIDTH, entry->data.reg.width, size_t)
break;
}
case kSDItemHistoryEntry: {
- if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) {
- semsg(_(READERR("history", "is not an array")), initial_fpos);
- goto shada_read_next_item_error;
- }
- if (unpacked.data.via.array.size < 2) {
- semsg(_(READERR("history", "does not have enough elements")),
- initial_fpos);
+ ssize_t len = unpack_array(&read_ptr, &read_size);
+
+ if (len < 2) {
+ semsg(_(READERR("history", "is not an array with enough elements")), initial_fpos);
goto shada_read_next_item_error;
}
- if (unpacked.data.via.array.ptr[0].type
- != MSGPACK_OBJECT_POSITIVE_INTEGER) {
- semsg(_(READERR("history", "has wrong history type type")),
- initial_fpos);
+ Integer hist_type;
+ if (!unpack_integer(&read_ptr, &read_size, &hist_type)) {
+ semsg(_(READERR("history", "has wrong history type type")), initial_fpos);
goto shada_read_next_item_error;
}
- if (unpacked.data.via.array.ptr[1].type
- != MSGPACK_OBJECT_BIN) {
- semsg(_(READERR("history", "has wrong history string type")),
- initial_fpos);
+ const String item = unpack_string(&read_ptr, &read_size);
+ if (!item.data) {
+ semsg(_(READERR("history", "has wrong history string type")), initial_fpos);
goto shada_read_next_item_error;
}
- if (memchr(unpacked.data.via.array.ptr[1].via.bin.ptr, 0,
- unpacked.data.via.array.ptr[1].via.bin.size) != NULL) {
- semsg(_(READERR("history", "contains string with zero byte inside")),
- initial_fpos);
+ if (memchr(item.data, 0, item.size) != NULL) {
+ semsg(_(READERR("history", "contains string with zero byte inside")), initial_fpos);
goto shada_read_next_item_error;
}
- entry->data.history_item.histtype =
- (uint8_t)unpacked.data.via.array.ptr[0].via.u64;
- const bool is_hist_search =
- entry->data.history_item.histtype == HIST_SEARCH;
+ entry->data.history_item.histtype = (uint8_t)hist_type;
+ const bool is_hist_search = entry->data.history_item.histtype == HIST_SEARCH;
if (is_hist_search) {
- if (unpacked.data.via.array.size < 3) {
+ if (len < 3) {
semsg(_(READERR("search history",
"does not have separator character")), initial_fpos);
goto shada_read_next_item_error;
}
- if (unpacked.data.via.array.ptr[2].type
- != MSGPACK_OBJECT_POSITIVE_INTEGER) {
- semsg(_(READERR("search history",
- "has wrong history separator type")), initial_fpos);
+ Integer sep_type;
+ if (!unpack_integer(&read_ptr, &read_size, &sep_type)) {
+ semsg(_(READERR("search history", "has wrong history separator type")), initial_fpos);
goto shada_read_next_item_error;
}
- entry->data.history_item.sep =
- (char)unpacked.data.via.array.ptr[2].via.u64;
+ entry->data.history_item.sep = (char)sep_type;
}
- size_t strsize;
- strsize = (
- unpacked.data.via.array.ptr[1].via.bin.size
- + 1 // Zero byte
- + 1); // Separator character
+ size_t strsize = (item.size
+ + 1 // Zero byte
+ + 1); // Separator character
entry->data.history_item.string = xmalloc(strsize);
- memcpy(entry->data.history_item.string,
- unpacked.data.via.array.ptr[1].via.bin.ptr,
- unpacked.data.via.array.ptr[1].via.bin.size);
+ memcpy(entry->data.history_item.string, item.data, item.size);
entry->data.history_item.string[strsize - 2] = 0;
- entry->data.history_item.string[strsize - 1] =
- entry->data.history_item.sep;
- SET_ADDITIONAL_ELEMENTS(unpacked.data.via.array, (2 + is_hist_search),
- entry->data.history_item.additional_elements,
- "history");
+ entry->data.history_item.string[strsize - 1] = entry->data.history_item.sep;
+ read_additional_array_elements = (uint32_t)(len - (2 + is_hist_search));
break;
}
case kSDItemVariable: {
- if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) {
- semsg(_(READERR("variable", "is not an array")), initial_fpos);
- goto shada_read_next_item_error;
- }
- if (unpacked.data.via.array.size < 2) {
- semsg(_(READERR("variable", "does not have enough elements")),
- initial_fpos);
+ ssize_t len = unpack_array(&read_ptr, &read_size);
+
+ if (len < 2) {
+ semsg(_(READERR("variable", "is not an array with enough elements")), initial_fpos);
goto shada_read_next_item_error;
}
- if (unpacked.data.via.array.ptr[0].type != MSGPACK_OBJECT_BIN) {
- semsg(_(READERR("variable", "has wrong variable name type")),
- initial_fpos);
+
+ String name = unpack_string(&read_ptr, &read_size);
+
+ if (!name.data) {
+ semsg(_(READERR("variable", "has wrong variable name type")), initial_fpos);
goto shada_read_next_item_error;
}
- entry->data.global_var.name =
- xmemdupz(unpacked.data.via.array.ptr[0].via.bin.ptr,
- unpacked.data.via.array.ptr[0].via.bin.size);
- SET_ADDITIONAL_ELEMENTS(unpacked.data.via.array, 2,
- entry->data.global_var.additional_elements,
- "variable");
+ entry->data.global_var.name = xmemdupz(name.data, name.size);
+
+ String binval = unpack_string(&read_ptr, &read_size);
+
bool is_blob = false;
- // A msgpack BIN could be a String or Blob; an additional VAR_TYPE_BLOB
- // element is stored with Blobs which can be used to differentiate them
- if (unpacked.data.via.array.ptr[1].type == MSGPACK_OBJECT_BIN) {
- const listitem_T *type_item
- = tv_list_first(entry->data.global_var.additional_elements);
- if (type_item != NULL) {
- const typval_T *type_tv = TV_LIST_ITEM_TV(type_item);
- if (type_tv->v_type != VAR_NUMBER
- || type_tv->vval.v_number != VAR_TYPE_BLOB) {
+ if (binval.data) {
+ if (len > 2) {
+ // A msgpack BIN could be a String or Blob; an additional VAR_TYPE_BLOB
+ // element is stored with Blobs which can be used to differentiate them
+ Integer type;
+ if (!unpack_integer(&read_ptr, &read_size, &type) || type != VAR_TYPE_BLOB) {
semsg(_(READERR("variable", "has wrong variable type")),
initial_fpos);
goto shada_read_next_item_error;
}
is_blob = true;
}
+ entry->data.global_var.value = decode_string(binval.data, binval.size, is_blob, false);
+ } else {
+ int status = unpack_typval(&read_ptr, &read_size, &entry->data.global_var.value);
+ if (status != MPACK_OK) {
+ semsg(_(READERR("variable", "has value that cannot "
+ "be converted to the Vimscript value")), initial_fpos);
+ goto shada_read_next_item_error;
+ }
}
- if (is_blob) {
- const msgpack_object_bin *const bin
- = &unpacked.data.via.array.ptr[1].via.bin;
- blob_T *const blob = tv_blob_alloc();
- ga_concat_len(&blob->bv_ga, bin->ptr, (size_t)bin->size);
- tv_blob_set_ret(&entry->data.global_var.value, blob);
- } else if (msgpack_to_vim(unpacked.data.via.array.ptr[1],
- &(entry->data.global_var.value)) == FAIL) {
- semsg(_(READERR("variable", "has value that cannot "
- "be converted to the Vimscript value")), initial_fpos);
- goto shada_read_next_item_error;
- }
+ read_additional_array_elements = (uint32_t)(len - 2 - (is_blob ? 1 : 0));
break;
}
- case kSDItemSubString:
- if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) {
- semsg(_(READERR("sub string", "is not an array")), initial_fpos);
- goto shada_read_next_item_error;
- }
- if (unpacked.data.via.array.size < 1) {
- semsg(_(READERR("sub string", "does not have enough elements")),
- initial_fpos);
+ case kSDItemSubString: {
+ ssize_t len = unpack_array(&read_ptr, &read_size);
+
+ if (len < 1) {
+ semsg(_(READERR("sub string", "is not an array with enough elements")), initial_fpos);
goto shada_read_next_item_error;
}
- if (unpacked.data.via.array.ptr[0].type != MSGPACK_OBJECT_BIN) {
- semsg(_(READERR("sub string", "has wrong sub string type")),
- initial_fpos);
+
+ String sub = unpack_string(&read_ptr, &read_size);
+ if (!sub.data) {
+ semsg(_(READERR("sub string", "has wrong sub string type")), initial_fpos);
goto shada_read_next_item_error;
}
- entry->data.sub_string.sub =
- BIN_CONVERTED(unpacked.data.via.array.ptr[0].via.bin);
- SET_ADDITIONAL_ELEMENTS(unpacked.data.via.array, 1,
- entry->data.sub_string.additional_elements,
- "sub string");
+ entry->data.sub_string.sub = xmemdupz(sub.data, sub.size);
+ read_additional_array_elements = (uint32_t)(len - 1);
break;
- case kSDItemBufferList:
- if (unpacked.data.type != MSGPACK_OBJECT_ARRAY) {
+ }
+ case kSDItemBufferList: {
+ ssize_t len = unpack_array(&read_ptr, &read_size);
+ if (len < 0) {
semsg(_(READERR("buffer list", "is not an array")), initial_fpos);
goto shada_read_next_item_error;
}
- if (unpacked.data.via.array.size == 0) {
+ if (len == 0) {
break;
}
- entry->data.buffer_list.buffers =
- xcalloc(unpacked.data.via.array.size,
- sizeof(*entry->data.buffer_list.buffers));
- for (size_t i = 0; i < unpacked.data.via.array.size; i++) {
+ entry->data.buffer_list.buffers = xcalloc((size_t)len,
+ sizeof(*entry->data.buffer_list.buffers));
+ for (size_t i = 0; i < (size_t)len; i++) {
entry->data.buffer_list.size++;
- msgpack_unpacked unpacked_2 = (msgpack_unpacked) {
- .data = unpacked.data.via.array.ptr[i],
- };
- {
- if (unpacked_2.data.type != MSGPACK_OBJECT_MAP) {
- semsg(_(RERR "Error while reading ShaDa file: "
- "buffer list at position %" PRIu64 " "
- "contains entry that is not a dictionary"),
- initial_fpos);
- goto shada_read_next_item_error;
- }
- entry->data.buffer_list.buffers[i].pos = default_pos;
- garray_T ad_ga;
- ga_init(&ad_ga, sizeof(*(unpacked_2.data.via.map.ptr)), 1);
- {
- // XXX: Temporarily reassign `i` because the macros depend on it.
- const size_t j = i;
- {
- for (i = 0; i < unpacked_2.data.via.map.size; i++) {
- CHECK_KEY_IS_STR(unpacked_2, "buffer list entry")
- INTEGER_KEY(unpacked_2, "buffer list entry", KEY_LNUM,
- entry->data.buffer_list.buffers[j].pos.lnum)
- INTEGER_KEY(unpacked_2, "buffer list entry", KEY_COL,
- entry->data.buffer_list.buffers[j].pos.col)
- STRING_KEY(unpacked_2, "buffer list entry", KEY_FILE,
- entry->data.buffer_list.buffers[j].fname)
- ADDITIONAL_KEY(unpacked_2)
- }
- }
- i = j; // XXX: Restore `i`.
- }
- if (entry->data.buffer_list.buffers[i].pos.lnum <= 0) {
- semsg(_(RERR "Error while reading ShaDa file: "
- "buffer list at position %" PRIu64 " "
- "contains entry with invalid line number"),
- initial_fpos);
- CLEAR_GA_AND_ERROR_OUT(ad_ga);
- }
- if (entry->data.buffer_list.buffers[i].pos.col < 0) {
- semsg(_(RERR "Error while reading ShaDa file: "
- "buffer list at position %" PRIu64 " "
- "contains entry with invalid column number"),
- initial_fpos);
- CLEAR_GA_AND_ERROR_OUT(ad_ga);
- }
- if (entry->data.buffer_list.buffers[i].fname == NULL) {
- semsg(_(RERR "Error while reading ShaDa file: "
- "buffer list at position %" PRIu64 " "
- "contains entry that does not have a file name"),
- initial_fpos);
- CLEAR_GA_AND_ERROR_OUT(ad_ga);
- }
- SET_ADDITIONAL_DATA(entry->data.buffer_list.buffers[i].additional_data,
- "buffer list entry");
+ Dict(_shada_buflist_item) it = { 0 };
+ AdditionalDataBuilder it_ad = KV_INITIAL_VALUE;
+ if (!unpack_keydict(&it, DictHash(_shada_buflist_item), &it_ad, &read_ptr, &read_size,
+ &error_alloc)) {
+ semsg(_(RERR "Error while reading ShaDa file: "
+ "buffer list at position %" PRIu64 " contains entry that %s"),
+ initial_fpos, error_alloc);
+ kv_destroy(it_ad);
+ goto shada_read_next_item_error;
+ }
+ struct buffer_list_buffer *e = &entry->data.buffer_list.buffers[i];
+ e->additional_data = (AdditionalData *)it_ad.items;
+ e->pos = default_pos;
+ if (HAS_KEY(&it, _shada_buflist_item, l)) {
+ e->pos.lnum = (linenr_T)it.l;
+ }
+ if (HAS_KEY(&it, _shada_buflist_item, c)) {
+ e->pos.col = (colnr_T)it.c;
+ }
+ if (HAS_KEY(&it, _shada_buflist_item, f)) {
+ e->fname = xmemdupz(it.f.data, it.f.size);
+ }
+
+ if (e->pos.lnum <= 0) {
+ semsg(_(RERR "Error while reading ShaDa file: "
+ "buffer list at position %" PRIu64 " "
+ "contains entry with invalid line number"),
+ initial_fpos);
+ goto shada_read_next_item_error;
+ }
+ if (e->pos.col < 0) {
+ semsg(_(RERR "Error while reading ShaDa file: "
+ "buffer list at position %" PRIu64 " "
+ "contains entry with invalid column number"),
+ initial_fpos);
+ goto shada_read_next_item_error;
+ }
+ if (e->fname == NULL) {
+ semsg(_(RERR "Error while reading ShaDa file: "
+ "buffer list at position %" PRIu64 " "
+ "contains entry that does not have a file name"),
+ initial_fpos);
+ goto shada_read_next_item_error;
}
}
break;
+ }
case kSDItemMissing:
case kSDItemUnknown:
abort();
}
+
+ for (uint32_t i = 0; i < read_additional_array_elements; i++) {
+ const char *item_start = read_ptr;
+ int status = unpack_skip(&read_ptr, &read_size);
+ if (status) {
+ goto shada_read_next_item_error;
+ }
+
+ push_additional_data(&ad, item_start, (size_t)(read_ptr - item_start));
+ }
+
+ if (read_size) {
+ semsg(_(READERR("item", "additional bytes")), initial_fpos);
+ goto shada_read_next_item_error;
+ }
+
entry->type = (ShadaEntryType)type_u64;
+ entry->additional_data = (AdditionalData *)ad.items;
ret = kSDReadStatusSuccess;
shada_read_next_item_end:
- if (buf != NULL) {
- msgpack_unpacked_destroy(&unpacked);
+ if (buf_allocated) {
xfree(buf);
}
return ret;
@@ -3823,26 +3520,10 @@ shada_read_next_item_error:
entry->type = (ShadaEntryType)type_u64;
shada_free_shada_entry(entry);
entry->type = kSDItemMissing;
+ xfree(error_alloc);
+ kv_destroy(ad);
goto shada_read_next_item_end;
}
-#undef BIN_CONVERTED
-#undef CHECK_KEY
-#undef BOOLEAN_KEY
-#undef CONVERTED_STRING_KEY
-#undef STRING_KEY
-#undef ADDITIONAL_KEY
-#undef ID
-#undef BINDUP
-#undef TOCHAR
-#undef TOINT
-#undef TYPED_KEY
-#undef INT_KEY
-#undef INTEGER_KEY
-#undef TOU8
-#undef TOSIZE
-#undef SET_ADDITIONAL_DATA
-#undef SET_ADDITIONAL_ELEMENTS
-#undef CLEAR_GA_AND_ERROR_OUT
/// Check whether "name" is on removable media (according to 'shada')
///
@@ -3919,9 +3600,9 @@ static inline size_t shada_init_jumps(PossiblyFreedShadaEntry *jumps,
.name = NUL,
.mark = fm.fmark.mark,
.fname = (char *)fname,
- .additional_data = fm.fmark.additional_data,
}
- }
+ },
+ .additional_data = fm.fmark.additional_data,
}
};
} while (jump_iter != NULL);
@@ -4013,9 +3694,9 @@ String shada_encode_gvars(void)
.global_var = {
.name = (char *)name,
.value = tgttv,
- .additional_elements = NULL,
}
- }
+ },
+ .additional_data = NULL,
}, 0);
if (kSDWriteFailed == r) {
abort();
diff --git a/src/nvim/shada.h b/src/nvim/shada.h
index 58689a5bd7..7d736dadc7 100644
--- a/src/nvim/shada.h
+++ b/src/nvim/shada.h
@@ -1,7 +1,5 @@
#pragma once
-#include <msgpack.h> // IWYU pragma: keep
-
#include "nvim/api/private/defs.h"
/// Flags for shada_read_file and children
diff --git a/src/nvim/types_defs.h b/src/nvim/types_defs.h
index 934159b9d9..2dd2b01adf 100644
--- a/src/nvim/types_defs.h
+++ b/src/nvim/types_defs.h
@@ -56,3 +56,9 @@ typedef struct regprog regprog_T;
typedef struct syn_state synstate_T;
typedef struct terminal Terminal;
typedef struct window_S win_T;
+
+typedef struct {
+ uint32_t nitems;
+ uint32_t nbytes;
+ char data[];
+} AdditionalData;
diff --git a/src/nvim/ui_client.c b/src/nvim/ui_client.c
index 4f36cae4b2..839cf965b0 100644
--- a/src/nvim/ui_client.c
+++ b/src/nvim/ui_client.c
@@ -174,7 +174,7 @@ static HlAttrs ui_client_dict2hlattrs(Dictionary d, bool rgb)
{
Error err = ERROR_INIT;
Dict(highlight) dict = KEYDICT_INIT;
- if (!api_dict_to_keydict(&dict, KeyDict_highlight_get_field, d, &err)) {
+ if (!api_dict_to_keydict(&dict, DictHash(highlight), d, &err)) {
// TODO(bfredl): log "err"
return HLATTRS_INIT;
}
diff --git a/src/nvim/undo.c b/src/nvim/undo.c
index c403e94184..15c8e0b283 100644
--- a/src/nvim/undo.c
+++ b/src/nvim/undo.c
@@ -343,8 +343,7 @@ static OptInt get_undolevel(buf_T *buf)
static inline void zero_fmark_additional_data(fmark_T *fmarks)
{
for (size_t i = 0; i < NMARKS; i++) {
- tv_dict_unref(fmarks[i].additional_data);
- fmarks[i].additional_data = NULL;
+ XFREE_CLEAR(fmarks[i].additional_data);
}
}
diff --git a/test/functional/shada/errors_spec.lua b/test/functional/shada/errors_spec.lua
index e000d0988b..321744f7dd 100644
--- a/test/functional/shada/errors_spec.lua
+++ b/test/functional/shada/errors_spec.lua
@@ -58,7 +58,7 @@ describe('ShaDa error handling', function()
it('fails on search pattern item with zero length', function()
wshada('\002\000\000')
eq(
- 'Vim(rshada):E576: Failed to parse ShaDa file: incomplete msgpack string at position 3',
+ 'Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 is not a dictionary',
exc_exec(sdrcmd())
)
end)
@@ -89,18 +89,10 @@ describe('ShaDa error handling', function()
it('fails on search pattern item with invalid byte', function()
-- 195 (== 0xC1) cannot start any valid messagepack entry (the only byte
- -- that cannot do this). Specifically unpack_template.h contains
- --
- -- //case 0xc1: // string
- -- // again_terminal_trail(NEXT_CS(p), p+1);
- --
- -- (literally: commented out code) which means that in place of this code
- -- `goto _failed` is used from default: case. I do not know any other way to
- -- get MSGPACK_UNPACK_PARSE_ERROR and not MSGPACK_UNPACK_CONTINUE or
- -- MSGPACK_UNPACK_EXTRA_BYTES.
+ -- that cannot do this)
wshada('\002\000\001\193')
eq(
- 'Vim(rshada):E576: Failed to parse ShaDa file due to a msgpack parser error at position 3',
+ 'Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 is not a dictionary',
exc_exec(sdrcmd())
)
end)
@@ -108,7 +100,7 @@ describe('ShaDa error handling', function()
it('fails on search pattern item with incomplete map', function()
wshada('\002\000\001\129')
eq(
- 'Vim(rshada):E576: Failed to parse ShaDa file: incomplete msgpack string at position 3',
+ 'Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 has key value which is not a string',
exc_exec(sdrcmd())
)
end)
@@ -124,7 +116,7 @@ describe('ShaDa error handling', function()
it('fails on search pattern with extra bytes', function()
wshada('\002\000\002\128\000')
eq(
- 'Vim(rshada):E576: Failed to parse ShaDa file: extra bytes in msgpack string at position 3',
+ 'Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 has no pattern',
exc_exec(sdrcmd())
)
end)
@@ -138,15 +130,6 @@ describe('ShaDa error handling', function()
end)
-- sp entry is here because it causes an allocation.
- it('fails on search pattern item with BIN key', function()
- wshada('\002\000\014\131\162sp\196\001a\162sX\192\196\000\000')
- eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 has key which is not a string',
- exc_exec(sdrcmd())
- )
- end)
-
- -- sp entry is here because it causes an allocation.
it('fails on search pattern item with empty key', function()
wshada('\002\000\013\131\162sp\196\001a\162sX\192\160\000')
eq(
@@ -235,22 +218,12 @@ describe('ShaDa error handling', function()
)
end)
- it('fails on search pattern item with STR pat key value', function()
- wshada('\002\000\011\130\162sX\192\162sp\162sp')
- eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: search pattern entry at position 0 has sp key value which is not a binary',
- exc_exec(sdrcmd())
- )
- end)
-
for _, v in ipairs({
{ name = 'global mark', mpack = '\007' },
{ name = 'jump', mpack = '\008' },
{ name = 'local mark', mpack = '\010' },
{ name = 'change', mpack = '\011' },
}) do
- local is_mark_test = ({ ['global mark'] = true, ['local mark'] = true })[v.name]
-
it('fails on ' .. v.name .. ' item with NIL value', function()
wshada(v.mpack .. '\000\001\192')
eq(
@@ -260,15 +233,6 @@ describe('ShaDa error handling', function()
end)
-- f entry is here because it causes an allocation.
- it('fails on ' .. v.name .. ' item with BIN key', function()
- wshada(v.mpack .. '\000\013\131\161f\196\001/\162mX\192\196\000\000')
- eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: mark entry at position 0 has key which is not a string',
- exc_exec(sdrcmd())
- )
- end)
-
- -- f entry is here because it causes an allocation.
it('fails on ' .. v.name .. ' item with empty key', function()
wshada(v.mpack .. '\000\012\131\161f\196\001/\162mX\192\160\000')
eq(
@@ -312,9 +276,7 @@ describe('ShaDa error handling', function()
it('fails on ' .. v.name .. ' item with STR n key value', function()
wshada(v.mpack .. '\000\011\130\162mX\192\161n\163spa')
eq(
- is_mark_test
- and 'Vim(rshada):E575: Error while reading ShaDa file: mark entry at position 0 has n key value which is not an unsigned integer'
- or 'Vim(rshada):E575: Error while reading ShaDa file: mark entry at position 0 has n key which is only valid for local and global mark entries',
+ 'Vim(rshada):E575: Error while reading ShaDa file: mark entry at position 0 has n key value which is not an integer',
exc_exec(sdrcmd())
)
end)
@@ -334,14 +296,6 @@ describe('ShaDa error handling', function()
exc_exec(sdrcmd())
)
end)
-
- it('fails on ' .. v.name .. ' item with STR f key value', function()
- wshada(v.mpack .. '\000\010\130\162mX\192\161f\162sp')
- eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: mark entry at position 0 has f key value which is not a binary',
- exc_exec(sdrcmd())
- )
- end)
end
it('fails on register item with NIL value', function()
@@ -354,15 +308,6 @@ describe('ShaDa error handling', function()
-- rc entry is here because it causes an allocation
it('fails on register item with BIN key', function()
- wshada('\005\000\015\131\162rc\145\196\001a\162rX\192\196\000\000')
- eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has key which is not a string',
- exc_exec(sdrcmd())
- )
- end)
-
- -- rc entry is here because it causes an allocation
- it('fails on register item with BIN key', function()
wshada('\005\000\014\131\162rc\145\196\001a\162rX\192\160\000')
eq(
'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has empty key',
@@ -373,7 +318,7 @@ describe('ShaDa error handling', function()
it('fails on register item with NIL rt key value', function()
wshada('\005\000\009\130\162rX\192\162rt\192')
eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has rt key value which is not an unsigned integer',
+ 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has rt key value which is not an integer',
exc_exec(sdrcmd())
)
end)
@@ -381,7 +326,7 @@ describe('ShaDa error handling', function()
it('fails on register item with NIL rw key value', function()
wshada('\005\000\009\130\162rX\192\162rw\192')
eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has rw key value which is not an unsigned integer',
+ 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has rw key value which is not an integer',
exc_exec(sdrcmd())
)
end)
@@ -397,7 +342,7 @@ describe('ShaDa error handling', function()
it('fails on register item with empty rc key value', function()
wshada('\005\000\009\130\162rX\192\162rc\144')
eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has rc key with empty array',
+ 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has rc key with missing or empty array',
exc_exec(sdrcmd())
)
end)
@@ -413,7 +358,7 @@ describe('ShaDa error handling', function()
it('fails on register item without rc array', function()
wshada('\005\000\009\129\162rX\146\196\001a\192')
eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has missing rc array',
+ 'Vim(rshada):E575: Error while reading ShaDa file: register entry at position 0 has rc key with missing or empty array',
exc_exec(sdrcmd())
)
end)
@@ -421,7 +366,7 @@ describe('ShaDa error handling', function()
it('fails on history item with NIL value', function()
wshada('\004\000\001\192')
eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: history entry at position 0 is not an array',
+ 'Vim(rshada):E575: Error while reading ShaDa file: history entry at position 0 is not an array with enough elements',
exc_exec(sdrcmd())
)
end)
@@ -429,7 +374,7 @@ describe('ShaDa error handling', function()
it('fails on history item with empty value', function()
wshada('\004\000\001\144')
eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: history entry at position 0 does not have enough elements',
+ 'Vim(rshada):E575: Error while reading ShaDa file: history entry at position 0 is not an array with enough elements',
exc_exec(sdrcmd())
)
end)
@@ -437,7 +382,7 @@ describe('ShaDa error handling', function()
it('fails on history item with single element value', function()
wshada('\004\000\002\145\000')
eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: history entry at position 0 does not have enough elements',
+ 'Vim(rshada):E575: Error while reading ShaDa file: history entry at position 0 is not an array with enough elements',
exc_exec(sdrcmd())
)
end)
@@ -485,7 +430,7 @@ describe('ShaDa error handling', function()
it('fails on variable item with NIL value', function()
wshada('\006\000\001\192')
eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: variable entry at position 0 is not an array',
+ 'Vim(rshada):E575: Error while reading ShaDa file: variable entry at position 0 is not an array with enough elements',
exc_exec(sdrcmd())
)
end)
@@ -493,7 +438,7 @@ describe('ShaDa error handling', function()
it('fails on variable item with empty value', function()
wshada('\006\000\001\144')
eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: variable entry at position 0 does not have enough elements',
+ 'Vim(rshada):E575: Error while reading ShaDa file: variable entry at position 0 is not an array with enough elements',
exc_exec(sdrcmd())
)
end)
@@ -501,7 +446,7 @@ describe('ShaDa error handling', function()
it('fails on variable item with single element value', function()
wshada('\006\000\002\145\000')
eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: variable entry at position 0 does not have enough elements',
+ 'Vim(rshada):E575: Error while reading ShaDa file: variable entry at position 0 is not an array with enough elements',
exc_exec(sdrcmd())
)
end)
@@ -525,7 +470,7 @@ describe('ShaDa error handling', function()
it('fails on replacement item with NIL value', function()
wshada('\003\000\001\192')
eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: sub string entry at position 0 is not an array',
+ 'Vim(rshada):E575: Error while reading ShaDa file: sub string entry at position 0 is not an array with enough elements',
exc_exec(sdrcmd())
)
end)
@@ -533,7 +478,7 @@ describe('ShaDa error handling', function()
it('fails on replacement item with empty value', function()
wshada('\003\000\001\144')
eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: sub string entry at position 0 does not have enough elements',
+ 'Vim(rshada):E575: Error while reading ShaDa file: sub string entry at position 0 is not an array with enough elements',
exc_exec(sdrcmd())
)
end)
@@ -577,7 +522,7 @@ describe('ShaDa error handling', function()
nvim_command('set shada+=%')
wshada('\009\000\017\146\129\161f\196\001/\130\161f\196\002/a\161l\192')
eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: buffer list entry entry at position 0 has l key value which is not an integer',
+ 'Vim(rshada):E575: Error while reading ShaDa file: buffer list at position 0 contains entry that has l key value which is not an integer',
exc_exec(sdrcmd())
)
end)
@@ -613,7 +558,7 @@ describe('ShaDa error handling', function()
nvim_command('set shada+=%')
wshada('\009\000\017\146\129\161f\196\001/\130\161f\196\002/a\161c\192')
eq(
- 'Vim(rshada):E575: Error while reading ShaDa file: buffer list entry entry at position 0 has c key value which is not an integer',
+ 'Vim(rshada):E575: Error while reading ShaDa file: buffer list at position 0 contains entry that has c key value which is not an integer',
exc_exec(sdrcmd())
)
end)
diff --git a/test/unit/eval/encode_spec.lua b/test/unit/eval/encode_spec.lua
index 5b9188163e..9f193bc2f9 100644
--- a/test/unit/eval/encode_spec.lua
+++ b/test/unit/eval/encode_spec.lua
@@ -21,81 +21,81 @@ describe('encode_list_write()', function()
itp('writes empty string', function()
local l = list()
- eq(0, encode_list_write(l, ''))
+ encode_list_write(l, '')
eq({ [type_key] = list_type }, lst2tbl(l))
end)
itp('writes ASCII string literal with printable characters', function()
local l = list()
- eq(0, encode_list_write(l, 'abc'))
+ encode_list_write(l, 'abc')
eq({ 'abc' }, lst2tbl(l))
end)
itp('writes string starting with NL', function()
local l = list()
- eq(0, encode_list_write(l, '\nabc'))
+ encode_list_write(l, '\nabc')
eq({ null_string, 'abc' }, lst2tbl(l))
end)
itp('writes string starting with NL twice', function()
local l = list()
- eq(0, encode_list_write(l, '\nabc'))
+ encode_list_write(l, '\nabc')
eq({ null_string, 'abc' }, lst2tbl(l))
- eq(0, encode_list_write(l, '\nabc'))
+ encode_list_write(l, '\nabc')
eq({ null_string, 'abc', 'abc' }, lst2tbl(l))
end)
itp('writes string ending with NL', function()
local l = list()
- eq(0, encode_list_write(l, 'abc\n'))
+ encode_list_write(l, 'abc\n')
eq({ 'abc', null_string }, lst2tbl(l))
end)
itp('writes string ending with NL twice', function()
local l = list()
- eq(0, encode_list_write(l, 'abc\n'))
+ encode_list_write(l, 'abc\n')
eq({ 'abc', null_string }, lst2tbl(l))
- eq(0, encode_list_write(l, 'abc\n'))
+ encode_list_write(l, 'abc\n')
eq({ 'abc', 'abc', null_string }, lst2tbl(l))
end)
itp('writes string starting, ending and containing NL twice', function()
local l = list()
- eq(0, encode_list_write(l, '\na\nb\n'))
+ encode_list_write(l, '\na\nb\n')
eq({ null_string, 'a', 'b', null_string }, lst2tbl(l))
- eq(0, encode_list_write(l, '\na\nb\n'))
+ encode_list_write(l, '\na\nb\n')
eq({ null_string, 'a', 'b', null_string, 'a', 'b', null_string }, lst2tbl(l))
end)
itp('writes string starting, ending and containing NUL with NL between twice', function()
local l = list()
- eq(0, encode_list_write(l, '\0\n\0\n\0'))
+ encode_list_write(l, '\0\n\0\n\0')
eq({ '\n', '\n', '\n' }, lst2tbl(l))
- eq(0, encode_list_write(l, '\0\n\0\n\0'))
+ encode_list_write(l, '\0\n\0\n\0')
eq({ '\n', '\n', '\n\n', '\n', '\n' }, lst2tbl(l))
end)
itp('writes string starting, ending and containing NL with NUL between twice', function()
local l = list()
- eq(0, encode_list_write(l, '\n\0\n\0\n'))
+ encode_list_write(l, '\n\0\n\0\n')
eq({ null_string, '\n', '\n', null_string }, lst2tbl(l))
- eq(0, encode_list_write(l, '\n\0\n\0\n'))
+ encode_list_write(l, '\n\0\n\0\n')
eq({ null_string, '\n', '\n', null_string, '\n', '\n', null_string }, lst2tbl(l))
end)
itp('writes string containing a single NL twice', function()
local l = list()
- eq(0, encode_list_write(l, '\n'))
+ encode_list_write(l, '\n')
eq({ null_string, null_string }, lst2tbl(l))
- eq(0, encode_list_write(l, '\n'))
+ encode_list_write(l, '\n')
eq({ null_string, null_string, null_string }, lst2tbl(l))
end)
itp('writes string containing a few NLs twice', function()
local l = list()
- eq(0, encode_list_write(l, '\n\n\n'))
+ encode_list_write(l, '\n\n\n')
eq({ null_string, null_string, null_string, null_string }, lst2tbl(l))
- eq(0, encode_list_write(l, '\n\n\n'))
+ encode_list_write(l, '\n\n\n')
eq(
{ null_string, null_string, null_string, null_string, null_string, null_string, null_string },
lst2tbl(l)