aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/shada.c
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2024-03-09 14:57:57 -0700
committerJosh Rahm <joshuarahm@gmail.com>2024-03-09 14:57:57 -0700
commitc324271b99eee4c621463f368914d57cd729bd9c (patch)
tree5d979d333a2d5f9c080991d5482fd5916f8579c6 /src/nvim/shada.c
parent931bffbda3668ddc609fc1da8f9eb576b170aa52 (diff)
parentade1b12f49c3b3914c74847d791eb90ea90b56b7 (diff)
downloadrneovim-c324271b99eee4c621463f368914d57cd729bd9c.tar.gz
rneovim-c324271b99eee4c621463f368914d57cd729bd9c.tar.bz2
rneovim-c324271b99eee4c621463f368914d57cd729bd9c.zip
Merge remote-tracking branch 'upstream/master' into userreg
Diffstat (limited to 'src/nvim/shada.c')
-rw-r--r--src/nvim/shada.c201
1 files changed, 103 insertions, 98 deletions
diff --git a/src/nvim/shada.c b/src/nvim/shada.c
index e9c23e742f..0b148993f8 100644
--- a/src/nvim/shada.c
+++ b/src/nvim/shada.c
@@ -17,40 +17,49 @@
#include "nvim/api/private/helpers.h"
#include "nvim/ascii_defs.h"
#include "nvim/buffer.h"
+#include "nvim/buffer_defs.h"
#include "nvim/cmdhist.h"
#include "nvim/eval.h"
#include "nvim/eval/decode.h"
#include "nvim/eval/encode.h"
#include "nvim/eval/typval.h"
+#include "nvim/eval/typval_defs.h"
#include "nvim/ex_cmds.h"
+#include "nvim/ex_cmds_defs.h"
#include "nvim/ex_docmd.h"
#include "nvim/fileio.h"
-#include "nvim/func_attr.h"
#include "nvim/garray.h"
-#include "nvim/gettext.h"
+#include "nvim/garray_defs.h"
+#include "nvim/gettext_defs.h"
#include "nvim/globals.h"
#include "nvim/hashtab.h"
+#include "nvim/hashtab_defs.h"
#include "nvim/macros_defs.h"
#include "nvim/map_defs.h"
#include "nvim/mark.h"
+#include "nvim/mark_defs.h"
#include "nvim/mbyte.h"
#include "nvim/memory.h"
#include "nvim/message.h"
-#include "nvim/msgpack_rpc/helpers.h"
-#include "nvim/normal.h"
+#include "nvim/normal_defs.h"
#include "nvim/ops.h"
#include "nvim/option.h"
#include "nvim/option_vars.h"
#include "nvim/os/fileio.h"
+#include "nvim/os/fileio_defs.h"
#include "nvim/os/fs.h"
+#include "nvim/os/fs_defs.h"
#include "nvim/os/os.h"
+#include "nvim/os/os_defs.h"
#include "nvim/os/time.h"
+#include "nvim/os/time_defs.h"
#include "nvim/path.h"
#include "nvim/pos_defs.h"
#include "nvim/regexp.h"
#include "nvim/search.h"
#include "nvim/shada.h"
#include "nvim/strings.h"
+#include "nvim/types_defs.h"
#include "nvim/version.h"
#include "nvim/vim_defs.h"
@@ -347,25 +356,25 @@ typedef struct {
PMap(cstr_t) file_marks; ///< All file marks.
} WriteMergerState;
-struct sd_read_def;
+typedef struct sd_read_def ShaDaReadDef;
/// Function used to close files defined by ShaDaReadDef
-typedef void (*ShaDaReadCloser)(struct sd_read_def *const sd_reader)
+typedef void (*ShaDaReadCloser)(ShaDaReadDef *const sd_reader)
REAL_FATTR_NONNULL_ALL;
/// Function used to read ShaDa files
-typedef ptrdiff_t (*ShaDaFileReader)(struct sd_read_def *const sd_reader,
+typedef ptrdiff_t (*ShaDaFileReader)(ShaDaReadDef *const sd_reader,
void *const dest,
const size_t size)
REAL_FATTR_NONNULL_ALL REAL_FATTR_WARN_UNUSED_RESULT;
/// Function used to skip in ShaDa files
-typedef int (*ShaDaFileSkipper)(struct sd_read_def *const sd_reader,
+typedef int (*ShaDaFileSkipper)(ShaDaReadDef *const sd_reader,
const size_t offset)
REAL_FATTR_NONNULL_ALL REAL_FATTR_WARN_UNUSED_RESULT;
/// Structure containing necessary pointers for reading ShaDa files
-typedef struct sd_read_def {
+struct sd_read_def {
ShaDaFileReader read; ///< Reader function.
ShaDaReadCloser close; ///< Close function.
ShaDaFileSkipper skip; ///< Function used to skip some bytes.
@@ -374,27 +383,7 @@ typedef struct sd_read_def {
const char *error; ///< Error message in case of error.
uintmax_t fpos; ///< Current position (amount of bytes read since
///< reader structure initialization). May overflow.
-} ShaDaReadDef;
-
-struct sd_write_def;
-
-/// Function used to close files defined by ShaDaWriteDef
-typedef void (*ShaDaWriteCloser)(struct sd_write_def *const sd_writer)
- REAL_FATTR_NONNULL_ALL;
-
-/// Function used to write ShaDa files
-typedef ptrdiff_t (*ShaDaFileWriter)(struct sd_write_def *const sd_writer,
- const void *const src,
- const size_t size)
- REAL_FATTR_NONNULL_ALL REAL_FATTR_WARN_UNUSED_RESULT;
-
-/// Structure containing necessary pointers for writing ShaDa files
-typedef struct sd_write_def {
- ShaDaFileWriter write; ///< Writer function.
- ShaDaWriteCloser close; ///< Close function.
- void *cookie; ///< Data describing object written to.
- const char *error; ///< Error message in case of error.
-} ShaDaWriteDef;
+};
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "shada.c.generated.h"
@@ -626,33 +615,12 @@ static int read_char(ShaDaReadDef *const sd_reader)
return (int)ret;
}
-/// Wrapper for writing to file descriptors
-///
-/// @return -1 or number of bytes written.
-static ptrdiff_t write_file(ShaDaWriteDef *const sd_writer, const void *const dest,
- const size_t size)
- FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
-{
- const ptrdiff_t ret = file_write(sd_writer->cookie, dest, size);
- if (ret < 0) {
- sd_writer->error = os_strerror((int)ret);
- return -1;
- }
- return ret;
-}
-
/// Wrapper for closing file descriptors opened for reading
static void close_sd_reader(ShaDaReadDef *const sd_reader)
FUNC_ATTR_NONNULL_ALL
{
close_file(sd_reader->cookie);
-}
-
-/// Wrapper for closing file descriptors opened for writing
-static void close_sd_writer(ShaDaWriteDef *const sd_writer)
- FUNC_ATTR_NONNULL_ALL
-{
- close_file(sd_writer->cookie);
+ xfree(sd_reader->cookie);
}
/// Wrapper for read that reads to IObuff and ignores bytes read
@@ -721,8 +689,6 @@ static ShaDaReadResult sd_reader_skip(ShaDaReadDef *const sd_reader, const size_
static int open_shada_file_for_reading(const char *const fname, ShaDaReadDef *sd_reader)
FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
{
- int error;
-
*sd_reader = (ShaDaReadDef) {
.read = &read_file,
.close = &close_sd_reader,
@@ -730,9 +696,11 @@ static int open_shada_file_for_reading(const char *const fname, ShaDaReadDef *sd
.error = NULL,
.eof = false,
.fpos = 0,
- .cookie = file_open_new(&error, fname, kFileReadOnly, 0),
+ .cookie = xmalloc(sizeof(FileDescriptor)),
};
- if (sd_reader->cookie == NULL) {
+ int error = file_open(sd_reader->cookie, fname, kFileReadOnly, 0);
+ if (error) {
+ XFREE_CLEAR(sd_reader->cookie);
return error;
}
@@ -742,25 +710,26 @@ static int open_shada_file_for_reading(const char *const fname, ShaDaReadDef *sd
}
/// Wrapper for closing file descriptors
-static void close_file(void *cookie)
+static void close_file(FileDescriptor *cookie)
{
- const int error = file_free(cookie, !!p_fs);
+ const int error = file_close(cookie, !!p_fs);
if (error != 0) {
semsg(_(SERR "System error while closing ShaDa file: %s"),
os_strerror(error));
}
}
-/// Msgpack callback for writing to ShaDaWriteDef*
+/// Msgpack callback for writing to FileDescriptor*
static int msgpack_sd_writer_write(void *data, const char *buf, size_t len)
{
- ShaDaWriteDef *const sd_writer = (ShaDaWriteDef *)data;
- ptrdiff_t written_bytes = sd_writer->write(sd_writer, buf, len);
- if (written_bytes == -1) {
+ FileDescriptor *const sd_writer = (FileDescriptor *)data;
+ const ptrdiff_t ret = file_write(sd_writer, buf, len);
+ if (ret < 0) {
semsg(_(SERR "System error while writing ShaDa file: %s"),
- sd_writer->error);
+ os_strerror((int)ret));
return -1;
}
+
return 0;
}
@@ -997,6 +966,48 @@ static inline void hms_dealloc(HistoryMergerState *const hms_p)
#define HMS_ITER(hms_p, cur_entry, code) \
HMLL_FORALL(&((hms_p)->hmll), cur_entry, code)
+/// Iterate over global variables
+///
+/// @warning No modifications to global variable dictionary must be performed
+/// while iteration is in progress.
+///
+/// @param[in] iter Iterator. Pass NULL to start iteration.
+/// @param[out] name Variable name.
+/// @param[out] rettv Variable value.
+///
+/// @return Pointer that needs to be passed to next `var_shada_iter` invocation
+/// or NULL to indicate that iteration is over.
+static const void *var_shada_iter(const void *const iter, const char **const name, typval_T *rettv,
+ var_flavour_T flavour)
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(2, 3)
+{
+ const hashitem_T *hi;
+ const hashitem_T *hifirst = globvarht.ht_array;
+ const size_t hinum = (size_t)globvarht.ht_mask + 1;
+ *name = NULL;
+ if (iter == NULL) {
+ hi = globvarht.ht_array;
+ while ((size_t)(hi - hifirst) < hinum
+ && (HASHITEM_EMPTY(hi)
+ || !(var_flavour(hi->hi_key) & flavour))) {
+ hi++;
+ }
+ if ((size_t)(hi - hifirst) == hinum) {
+ return NULL;
+ }
+ } else {
+ hi = (const hashitem_T *)iter;
+ }
+ *name = TV_DICT_HI2DI(hi)->di_key;
+ tv_copy(&TV_DICT_HI2DI(hi)->di_tv, rettv);
+ while ((size_t)(++hi - hifirst) < hinum) {
+ if (!HASHITEM_EMPTY(hi) && (var_flavour(hi->hi_key) & flavour)) {
+ return hi;
+ }
+ }
+ return NULL;
+}
+
/// Find buffer for given buffer name (cached)
///
/// @param[in,out] fname_bufs Cache containing fname to buffer mapping.
@@ -1118,7 +1129,7 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags)
}
HistoryMergerState hms[HIST_COUNT];
if (srni_flags & kSDReadHistory) {
- for (HistoryType i = 0; i < HIST_COUNT; i++) {
+ for (int i = 0; i < HIST_COUNT; i++) {
hms_init(&hms[i], (uint8_t)i, (size_t)p_hi, true, true);
}
}
@@ -1211,7 +1222,7 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags)
// string is close to useless: you can only use it with :& or :~ and
// that’s all because s//~ is not available until the first call to
// regtilde. Vim was not calling this for some reason.
- (void)regtilde(cur_entry.data.sub_string.sub, magic_isset(), false);
+ regtilde(cur_entry.data.sub_string.sub, magic_isset(), false);
// Do not free shada entry: its allocated memory was saved above.
break;
case kSDItemHistoryEntry:
@@ -1382,7 +1393,7 @@ shada_read_main_cycle_end:
// memory for the history string itself and separator character which
// may be assigned right away.
if (srni_flags & kSDReadHistory) {
- for (HistoryType i = 0; i < HIST_COUNT; i++) {
+ for (int i = 0; i < HIST_COUNT; i++) {
hms_insert_whole_neovim_history(&hms[i]);
clr_history(i);
int *new_hisidx;
@@ -1823,9 +1834,7 @@ static int compare_file_marks(const void *a, const void *b)
const FileMarks *const *const b_fms = b;
return ((*a_fms)->greatest_timestamp == (*b_fms)->greatest_timestamp
? 0
- : ((*a_fms)->greatest_timestamp > (*b_fms)->greatest_timestamp
- ? -1
- : 1));
+ : ((*a_fms)->greatest_timestamp > (*b_fms)->greatest_timestamp ? -1 : 1));
}
/// Parse msgpack object that has given length
@@ -2473,7 +2482,7 @@ static int hist_type2char(const int type)
/// @param[in] sd_reader Structure containing file reader definition. If it is
/// not NULL then contents of this file will be merged
/// with current Neovim runtime.
-static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, ShaDaReadDef *const sd_reader)
+static ShaDaWriteResult shada_write(FileDescriptor *const sd_writer, ShaDaReadDef *const sd_reader)
FUNC_ATTR_NONNULL_ARG(1)
{
ShaDaWriteResult ret = kSDWriteSuccessful;
@@ -2500,7 +2509,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, ShaDaReadDef
bool dump_history = false;
// Initialize history merger
- for (HistoryType i = 0; i < HIST_COUNT; i++) {
+ for (int i = 0; i < HIST_COUNT; i++) {
int num_saved = get_shada_parameter(hist_type2char(i));
if (num_saved == -1) {
num_saved = (int)p_hi;
@@ -2605,7 +2614,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, ShaDaReadDef
case VAR_LIST: {
list_T *l = vartv.vval.v_list;
int copyID = get_copyID();
- if (!set_ref_in_list(l, copyID, NULL)
+ if (!set_ref_in_list_items(l, copyID, NULL)
&& copyID == l->lv_copyID) {
tv_clear(&vartv);
continue;
@@ -2894,7 +2903,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, ShaDaReadDef
#undef PACK_WMS_ARRAY
if (dump_history) {
- for (size_t i = 0; i < HIST_COUNT; i++) {
+ for (int i = 0; i < HIST_COUNT; i++) {
if (dump_one_history[i]) {
hms_insert_whole_neovim_history(&wms->hms[i]);
HMS_ITER(&wms->hms[i], cur_entry, {
@@ -2914,7 +2923,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, ShaDaReadDef
}
shada_write_exit:
- for (size_t i = 0; i < HIST_COUNT; i++) {
+ for (int i = 0; i < HIST_COUNT; i++) {
if (dump_one_history[i]) {
hms_dealloc(&wms->hms[i]);
}
@@ -2947,12 +2956,9 @@ int shada_write_file(const char *const file, bool nomerge)
char *const fname = shada_filename(file);
char *tempname = NULL;
- ShaDaWriteDef sd_writer = {
- .write = &write_file,
- .close = &close_sd_writer,
- .error = NULL,
- };
+ FileDescriptor sd_writer;
ShaDaReadDef sd_reader = { .close = NULL };
+ bool did_open_writer = false;
if (!nomerge) {
int error;
@@ -2982,8 +2988,8 @@ int shada_write_file(const char *const file, bool nomerge)
// 3: If somebody happened to delete the file after it was opened for
// reading use u=rw permissions.
shada_write_file_open: {}
- sd_writer.cookie = file_open_new(&error, tempname, kFileCreateOnly|kFileNoSymlink, perm);
- if (sd_writer.cookie == NULL) {
+ error = file_open(&sd_writer, tempname, kFileCreateOnly|kFileNoSymlink, perm);
+ if (error) {
if (error == UV_EEXIST || error == UV_ELOOP) {
// File already exists, try another name
char *const wp = tempname + strlen(tempname) - 1;
@@ -3004,6 +3010,8 @@ shada_write_file_open: {}
semsg(_(SERR "System error while opening temporary ShaDa file %s "
"for writing: %s"), tempname, os_strerror(error));
}
+ } else {
+ did_open_writer = true;
}
}
if (nomerge) {
@@ -3026,16 +3034,16 @@ shada_write_file_nomerge: {}
}
*tail = tail_save;
}
- int error;
- sd_writer.cookie = file_open_new(&error, fname, kFileCreate|kFileTruncate,
- 0600);
- if (sd_writer.cookie == NULL) {
+ int error = file_open(&sd_writer, fname, kFileCreate|kFileTruncate, 0600);
+ if (error) {
semsg(_(SERR "System error while opening ShaDa file %s for writing: %s"),
fname, os_strerror(error));
+ } else {
+ did_open_writer = true;
}
}
- if (sd_writer.cookie == NULL) {
+ if (!did_open_writer) {
xfree(fname);
xfree(tempname);
if (sd_reader.cookie != NULL) {
@@ -3050,9 +3058,7 @@ shada_write_file_nomerge: {}
verbose_leave();
}
- const ShaDaWriteResult sw_ret = shada_write(&sd_writer, (nomerge
- ? NULL
- : &sd_reader));
+ const ShaDaWriteResult sw_ret = shada_write(&sd_writer, (nomerge ? NULL : &sd_reader));
assert(sw_ret != kSDWriteIgnError);
if (!nomerge) {
sd_reader.close(&sd_reader);
@@ -3082,7 +3088,7 @@ shada_write_file_nomerge: {}
|| old_info.stat.st_gid != getgid()) {
const uv_uid_t old_uid = (uv_uid_t)old_info.stat.st_uid;
const uv_gid_t old_gid = (uv_gid_t)old_info.stat.st_gid;
- const int fchown_ret = os_fchown(file_fd(sd_writer.cookie),
+ const int fchown_ret = os_fchown(file_fd(&sd_writer),
old_uid, old_gid);
if (fchown_ret != 0) {
semsg(_(RNERR "Failed setting uid and gid for file %s: %s"),
@@ -3115,7 +3121,7 @@ shada_write_file_did_not_remove:
}
xfree(tempname);
}
- sd_writer.close(&sd_writer);
+ close_file(&sd_writer);
xfree(fname);
return OK;
@@ -3358,7 +3364,7 @@ static ShaDaReadResult msgpack_read_uint64(ShaDaReadDef *const sd_reader, const
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)) /* NOLINT(readability/braces) */ \
+ else if (CHECK_KEY((un).data.via.map.ptr[i].key, name)) \
{ \
CHECKED_ENTRY(condition, \
"has " name " key value " error_desc, \
@@ -3389,7 +3395,7 @@ static ShaDaReadResult msgpack_read_uint64(ShaDaReadDef *const sd_reader, const
#define INTEGER_KEY(un, entry_name, name, tgt) \
INT_KEY(un, entry_name, name, tgt, TOINT)
#define ADDITIONAL_KEY(un) \
- else { /* NOLINT(readability/braces) */ \
+ else { \
ga_grow(&ad_ga, 1); \
memcpy(((char *)ad_ga.ga_data) + ((size_t)ad_ga.ga_len \
* sizeof(*(un).data.via.map.ptr)), \
@@ -3579,10 +3585,9 @@ shada_read_next_item_start:
entry->data = sd_default_values[type_u64].data;
switch ((ShadaEntryType)type_u64) {
case kSDItemHeader:
- if (!msgpack_rpc_to_dictionary(&(unpacked.data), &(entry->data.header))) {
- semsg(_(READERR("header", "is not a dictionary")), initial_fpos);
- goto shada_read_next_item_error;
- }
+ // TODO(bfredl): header is written to file and provides useful debugging
+ // info. It is never read by nvim (earlier we parsed it back to a
+ // Dictionary, but that value was never used)
break;
case kSDItemSearchPattern: {
if (unpacked.data.type != MSGPACK_OBJECT_MAP) {
@@ -3983,7 +3988,7 @@ static bool shada_removable(const char *name)
char *new_name = home_replace_save(NULL, name);
for (char *p = p_shada; *p;) {
- (void)copy_option_part(&p, part, ARRAY_SIZE(part), ", ");
+ copy_option_part(&p, part, ARRAY_SIZE(part), ", ");
if (part[0] == 'r') {
home_replace(NULL, part + 1, NameBuff, MAXPATHL, true);
size_t n = strlen(NameBuff);