diff options
Diffstat (limited to 'src/nvim/shada.c')
-rw-r--r-- | src/nvim/shada.c | 316 |
1 files changed, 253 insertions, 63 deletions
diff --git a/src/nvim/shada.c b/src/nvim/shada.c index 4aafc669dc..3ebe75b980 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -151,15 +151,6 @@ KHASH_SET_INIT_STR(strset) /// Callback function for add_search_pattern typedef void (*SearchPatternGetter)(SearchPattern *); -/// Flags for shada_read_file and children -typedef enum { - kShaDaWantInfo = 1, ///< Load non-mark information - kShaDaWantMarks = 2, ///< Load local file marks and change list - kShaDaForceit = 4, ///< Overwrite info already read - kShaDaGetOldfiles = 8, ///< Load v:oldfiles. - kShaDaMissingError = 16, ///< Error out when os_open returns -ENOENT. -} ShaDaReadFileFlags; - /// Possible ShaDa entry types /// /// @warning Enum values are part of the API and must not be altered. @@ -283,7 +274,7 @@ typedef struct { char sep; list_T *additional_elements; } history_item; - struct reg { + struct reg { // yankreg_T char name; MotionType type; char **contents; @@ -1328,13 +1319,13 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags) break; } if (!force) { - const yankreg_T *const reg = op_register_get(cur_entry.data.reg.name); + const yankreg_T *const reg = op_reg_get(cur_entry.data.reg.name); if (reg == NULL || reg->timestamp >= cur_entry.timestamp) { shada_free_shada_entry(&cur_entry); break; } } - if (!op_register_set(cur_entry.data.reg.name, (yankreg_T) { + if (!op_reg_set(cur_entry.data.reg.name, (yankreg_T) { .y_array = (char_u **)cur_entry.data.reg.contents, .y_size = cur_entry.data.reg.contents_size, .y_type = cur_entry.data.reg.type, @@ -2496,7 +2487,7 @@ static inline void shada_initialize_registers(WriteMergerState *const wms, yankreg_T reg; char name = NUL; bool is_unnamed = false; - reg_iter = op_register_iter(reg_iter, &name, ®, &is_unnamed); + reg_iter = op_global_reg_iter(reg_iter, &name, ®, &is_unnamed); if (name == NUL) { break; } @@ -2552,6 +2543,19 @@ static inline void replace_numbered_mark(WriteMergerState *const wms, wms->numbered_marks[idx].data.data.filemark.name = (char)('0' + (int)idx); } +/// Find buffers ignored due to their location. +/// +/// @param[out] removable_bufs Cache of buffers ignored due to their location. +static inline void find_removable_bufs(khash_t(bufset) *removable_bufs) +{ + FOR_ALL_BUFFERS(buf) { + if (buf->b_ffname != NULL && shada_removable((char *)buf->b_ffname)) { + int kh_ret; + (void)kh_put(bufset, removable_bufs, (uintptr_t)buf, &kh_ret); + } + } +} + /// Write ShaDa file /// /// @param[in] sd_writer Structure containing file writer definition. @@ -2621,12 +2625,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, set_last_cursor(wp); } - FOR_ALL_BUFFERS(buf) { - if (buf->b_ffname != NULL && shada_removable((char *) buf->b_ffname)) { - int kh_ret; - (void) kh_put(bufset, &removable_bufs, (uintptr_t) buf, &kh_ret); - } - } + find_removable_bufs(&removable_bufs); // Write header if (shada_pack_entry(packer, (ShadaEntry) { @@ -2673,7 +2672,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, do { typval_T vartv; const char *name = NULL; - var_iter = var_shada_iter(var_iter, &name, &vartv); + var_iter = var_shada_iter(var_iter, &name, &vartv, VAR_FLAVOUR_SHADA); if (name == NULL) { break; } @@ -2737,49 +2736,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, } // Initialize jump list - const void *jump_iter = NULL; - cleanup_jumplist(curwin, false); - setpcmark(); - do { - xfmark_T fm; - jump_iter = mark_jumplist_iter(jump_iter, curwin, &fm); - - if (fm.fmark.mark.lnum == 0) { - iemsgf("ShaDa: mark lnum zero (ji:%p, js:%p, len:%i)", - (void *)jump_iter, (void *)&curwin->w_jumplist[0], - curwin->w_jumplistlen); - continue; - } - const buf_T *const buf = (fm.fmark.fnum == 0 - ? NULL - : buflist_findnr(fm.fmark.fnum)); - if (buf != NULL - ? in_bufset(&removable_bufs, buf) - : fm.fmark.fnum != 0) { - continue; - } - const char *const fname = (char *) (fm.fmark.fnum == 0 - ? (fm.fname == NULL ? NULL : fm.fname) - : buf->b_ffname); - if (fname == NULL) { - continue; - } - wms->jumps[wms->jumps_size++] = (PossiblyFreedShadaEntry) { - .can_free_entry = false, - .data = { - .type = kSDItemJump, - .timestamp = fm.fmark.timestamp, - .data = { - .filemark = { - .name = NUL, - .mark = fm.fmark.mark, - .fname = (char *) fname, - .additional_data = fm.fmark.additional_data, - } - } - } - }; - } while (jump_iter != NULL); + wms->jumps_size = shada_init_jumps(wms->jumps, &removable_bufs); // Initialize global marks if (dump_global_marks) { @@ -4117,3 +4074,236 @@ static bool shada_removable(const char *name) xfree(new_name); return retval; } + +/// Initialize ShaDa jumplist entries. +/// +/// @param[in,out] jumps Array of ShaDa entries to set. +/// @param[in] removable_bufs Cache of buffers ignored due to their +/// location. +/// +/// @return number of jumplist entries +static inline size_t shada_init_jumps( + PossiblyFreedShadaEntry *jumps, khash_t(bufset) *const removable_bufs) +{ + // Initialize jump list + size_t jumps_size = 0; + const void *jump_iter = NULL; + setpcmark(); + cleanup_jumplist(curwin, false); + do { + xfmark_T fm; + jump_iter = mark_jumplist_iter(jump_iter, curwin, &fm); + + if (fm.fmark.mark.lnum == 0) { + iemsgf("ShaDa: mark lnum zero (ji:%p, js:%p, len:%i)", + (void *)jump_iter, (void *)&curwin->w_jumplist[0], + curwin->w_jumplistlen); + continue; + } + const buf_T *const buf = (fm.fmark.fnum == 0 + ? NULL + : buflist_findnr(fm.fmark.fnum)); + if (buf != NULL + ? in_bufset(removable_bufs, buf) + : fm.fmark.fnum != 0) { + continue; + } + const char *const fname = (char *) (fm.fmark.fnum == 0 + ? (fm.fname == NULL ? NULL : fm.fname) + : buf->b_ffname); + if (fname == NULL) { + continue; + } + jumps[jumps_size++] = (PossiblyFreedShadaEntry) { + .can_free_entry = false, + .data = { + .type = kSDItemJump, + .timestamp = fm.fmark.timestamp, + .data = { + .filemark = { + .name = NUL, + .mark = fm.fmark.mark, + .fname = (char *) fname, + .additional_data = fm.fmark.additional_data, + } + } + } + }; + } while (jump_iter != NULL); + return jumps_size; +} + +/// Write registers ShaDa entries in given msgpack_sbuffer. +/// +/// @param[in] sbuf target msgpack_sbuffer to write to. +void shada_encode_regs(msgpack_sbuffer *const sbuf) + FUNC_ATTR_NONNULL_ALL +{ + WriteMergerState *const wms = xcalloc(1, sizeof(*wms)); + shada_initialize_registers(wms, -1); + msgpack_packer packer; + msgpack_packer_init(&packer, sbuf, msgpack_sbuffer_write); + for (size_t i = 0; i < ARRAY_SIZE(wms->registers); i++) { + if (wms->registers[i].data.type == kSDItemRegister) { + if (kSDWriteFailed + == shada_pack_pfreed_entry(&packer, wms->registers[i], 0)) { + abort(); + } + } + } + xfree(wms); +} + +/// Write jumplist ShaDa entries in given msgpack_sbuffer. +/// +/// @param[in] sbuf target msgpack_sbuffer to write to. +void shada_encode_jumps(msgpack_sbuffer *const sbuf) + FUNC_ATTR_NONNULL_ALL +{ + khash_t(bufset) removable_bufs = KHASH_EMPTY_TABLE(bufset); + find_removable_bufs(&removable_bufs); + PossiblyFreedShadaEntry jumps[JUMPLISTSIZE]; + size_t jumps_size = shada_init_jumps(jumps, &removable_bufs); + msgpack_packer packer; + msgpack_packer_init(&packer, sbuf, msgpack_sbuffer_write); + for (size_t i = 0; i < jumps_size; i++) { + if (kSDWriteFailed == shada_pack_pfreed_entry(&packer, jumps[i], 0)) { + abort(); + } + } +} + +/// Write buffer list ShaDa entry in given msgpack_sbuffer. +/// +/// @param[in] sbuf target msgpack_sbuffer to write to. +void shada_encode_buflist(msgpack_sbuffer *const sbuf) + FUNC_ATTR_NONNULL_ALL +{ + khash_t(bufset) removable_bufs = KHASH_EMPTY_TABLE(bufset); + find_removable_bufs(&removable_bufs); + ShadaEntry buflist_entry = shada_get_buflist(&removable_bufs); + msgpack_packer packer; + msgpack_packer_init(&packer, sbuf, msgpack_sbuffer_write); + if (kSDWriteFailed == shada_pack_entry(&packer, buflist_entry, 0)) { + abort(); + } + xfree(buflist_entry.data.buffer_list.buffers); +} + +/// Write global variables ShaDa entries in given msgpack_sbuffer. +/// +/// @param[in] sbuf target msgpack_sbuffer to write to. +void shada_encode_gvars(msgpack_sbuffer *const sbuf) + FUNC_ATTR_NONNULL_ALL +{ + msgpack_packer packer; + msgpack_packer_init(&packer, sbuf, msgpack_sbuffer_write); + const void *var_iter = NULL; + const Timestamp cur_timestamp = os_time(); + do { + typval_T vartv; + const char *name = NULL; + var_iter = var_shada_iter( + var_iter, &name, &vartv, + VAR_FLAVOUR_DEFAULT | VAR_FLAVOUR_SESSION | VAR_FLAVOUR_SHADA); + if (name == NULL) { + break; + } + if (vartv.v_type != VAR_FUNC && vartv.v_type != VAR_PARTIAL) { + typval_T tgttv; + tv_copy(&vartv, &tgttv); + ShaDaWriteResult r = shada_pack_entry(&packer, (ShadaEntry) { + .type = kSDItemVariable, + .timestamp = cur_timestamp, + .data = { + .global_var = { + .name = (char *)name, + .value = tgttv, + .additional_elements = NULL, + } + } + }, 0); + if (kSDWriteFailed == r) { + abort(); + } + tv_clear(&tgttv); + } + tv_clear(&vartv); + } while (var_iter != NULL); +} + +/// Wrapper for reading from msgpack_sbuffer. +/// +/// @return number of bytes read. +static ptrdiff_t read_sbuf(ShaDaReadDef *const sd_reader, void *const dest, + const size_t size) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT +{ + msgpack_sbuffer *sbuf = (msgpack_sbuffer *)sd_reader->cookie; + const uintmax_t bytes_read = MIN(size, sbuf->size - sd_reader->fpos); + if (bytes_read < size) { + sd_reader->eof = true; + } + memcpy(dest, sbuf->data + sd_reader->fpos, (size_t)bytes_read); + sd_reader->fpos += bytes_read; + return (ptrdiff_t)bytes_read; +} + +/// Wrapper for read that ignores bytes read from msgpack_sbuffer. +/// +/// Used for skipping. +/// +/// @param[in,out] sd_reader ShaDaReadDef with msgpack_sbuffer. +/// @param[in] offset Amount of bytes to skip. +/// +/// @return FAIL in case of failure, OK in case of success. May set +/// sd_reader->eof. +static int sd_sbuf_reader_skip_read(ShaDaReadDef *const sd_reader, + const size_t offset) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT +{ + msgpack_sbuffer *sbuf = (msgpack_sbuffer *)sd_reader->cookie; + assert(sbuf->size >= sd_reader->fpos); + const uintmax_t skip_bytes = MIN(offset, sbuf->size - sd_reader->fpos); + if (skip_bytes < offset) { + sd_reader->eof = true; + return FAIL; + } + sd_reader->fpos += offset; + return OK; +} + +/// Prepare ShaDaReadDef with msgpack_sbuffer for reading. +/// +/// @param[in] sbuf msgpack_sbuffer to read from. +/// @param[out] sd_reader Location where reader structure will be saved. +static void open_shada_sbuf_for_reading(const msgpack_sbuffer *const sbuf, + ShaDaReadDef *sd_reader) + FUNC_ATTR_NONNULL_ALL +{ + *sd_reader = (ShaDaReadDef) { + .read = &read_sbuf, + .close = NULL, + .skip = &sd_sbuf_reader_skip_read, + .error = NULL, + .eof = false, + .fpos = 0, + .cookie = (void *)sbuf, + }; +} + +/// Read ShaDa from msgpack_sbuffer. +/// +/// @param[in] file msgpack_sbuffer to read from. +/// @param[in] flags Flags, see ShaDaReadFileFlags enum. +void shada_read_sbuf(msgpack_sbuffer *const sbuf, const int flags) + FUNC_ATTR_NONNULL_ALL +{ + assert(sbuf != NULL); + if (sbuf->data == NULL) { + return; + } + ShaDaReadDef sd_reader; + open_shada_sbuf_for_reading(sbuf, &sd_reader); + shada_read(&sd_reader, flags); +} |