From 2dc27a8a78512269e4672bffcb11ede1c26fbd47 Mon Sep 17 00:00:00 2001 From: James McCoy Date: Tue, 26 Apr 2016 14:16:09 -0400 Subject: [PATCH 1/9] shada: Remember whether "0 or "1 was the unnamed register Ref #4645 --- test/functional/shada/registers_spec.lua | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/functional/shada/registers_spec.lua b/test/functional/shada/registers_spec.lua index fc812f799c..d8e9892c76 100644 --- a/test/functional/shada/registers_spec.lua +++ b/test/functional/shada/registers_spec.lua @@ -148,4 +148,14 @@ describe('ShaDa support code', function() eq({{'\171«'}, 'v'}, getreg('e')) end) + it('remembers which register was the unnamed register when loading', + function() + setreg('0', {'zero'}, 'c') + setreg('1', {'one'}, 'c') + nvim_command('qall') + reset() + eq({{'zero'}, 'v'}, getreg('0')) + eq({{'one'}, 'v'}, getreg('1')) + eq({{'one'}, 'v'}, getreg('"')) + end) end) From a00b03d03f1c8e3aced87c54da7223672bce720d Mon Sep 17 00:00:00 2001 From: AdnoC Date: Wed, 4 May 2016 14:12:50 -0400 Subject: [PATCH 2/9] shada: Set the unnamed register to the previous unnamed register on startup --- runtime/autoload/shada.vim | 3 ++- runtime/doc/starting.txt | 49 ++++++++++++++++++++------------------ src/nvim/ops.c | 14 +++++++---- src/nvim/shada.c | 18 ++++++++++++-- 4 files changed, 54 insertions(+), 30 deletions(-) diff --git a/runtime/autoload/shada.vim b/runtime/autoload/shada.vim index cf27ee608a..87acc515ee 100644 --- a/runtime/autoload/shada.vim +++ b/runtime/autoload/shada.vim @@ -45,7 +45,7 @@ call map(copy(s:SHADA_ENTRY_NAMES), let s:SHADA_MAP_ENTRIES = { \'search_pattern': ['sp', 'sh', 'ss', 'sb', 'sm', 'sc', 'sl', 'se', 'so', \ 'su'], - \'register': ['n', 'rc', 'rw', 'rt'], + \'register': ['n', 'rc', 'rw', 'rt', 'ru'], \'global_mark': ['n', 'f', 'l', 'c'], \'local_mark': ['f', 'n', 'l', 'c'], \'jump': ['f', 'l', 'c'], @@ -139,6 +139,7 @@ let s:SHADA_STANDARD_KEYS = { \'rt': ['type', 'regtype', s:SHADA_ENUMS.regtype.CHARACTERWISE], \'rw': ['block width', 'uint', 0], \'rc': ['contents', 'binarray', s:SHADA_REQUIRED], + \'ru': ['is_unnamed', 'boolean', g:msgpack#false], \'n': ['name', 'intchar', char2nr('"')], \'l': ['line number', 'uint', 1], \'c': ['column', 'uint', 0], diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt index 477d927a12..4b3f894cf7 100644 --- a/runtime/doc/starting.txt +++ b/runtime/doc/starting.txt @@ -1281,29 +1281,32 @@ exactly four MessagePack objects: 5 (Register) Map describing one register (|registers|). If key value is equal to default then it is normally not present. Keys: - Key Type Def Description ~ - rt UInteger 0 Register type: - No Description ~ - 0 |characterwise-register| - 1 |linewise-register| - 2 |blockwise-register| - rw UInteger 0 Register width. Only valid - for |blockwise-register|s. - rc Array of binary N/A Register contents. Each - entry in the array - represents its own line. - NUL characters inside the - line should be represented - as NL according to - |NL-used-for-Nul|. - n UInteger N/A Register name: character - code in range [1, 255]. - Example: |quote0| register - has name 48 (ASCII code for - zero character). - * any none Other keys are allowed - for compatibility reasons, - see |shada-compatibility|. + Key Type Def Description ~ + rt UInteger 0 Register type: + No Description ~ + 0 |characterwise-register| + 1 |linewise-register| + 2 |blockwise-register| + rw UInteger 0 Register width. Only valid + for |blockwise-register|s. + rc Array of binary N/A Register contents. Each + entry in the array + represents its own line. + NUL characters inside the + line should be represented + as NL according to + |NL-used-for-Nul|. + ru Boolean false Unnamed register. Whether + the unnamed register had + pointed to this register. + n UInteger N/A Register name: character + code in range [1, 255]. + Example: |quote0| register + has name 48 (ASCII code for + zero character). + * any none Other keys are allowed + for compatibility reasons, + see |shada-compatibility|. 6 (Variable) Array containing two items: variable name (binary) and variable value (any object). Values are converted using the same code |msgpackparse()| uses when reading, diff --git a/src/nvim/ops.c b/src/nvim/ops.c index c77781b1d1..9e5121b3fe 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -5780,7 +5780,7 @@ static inline bool reg_empty(const yankreg_T *const reg) /// @return Pointer that needs to be passed to next `op_register_iter` call or /// NULL if iteration is over. const void *op_register_iter(const void *const iter, char *const name, - yankreg_T *const reg) + yankreg_T *const reg, bool *is_unnamed) FUNC_ATTR_NONNULL_ARG(2, 3) FUNC_ATTR_WARN_UNUSED_RESULT { *name = NUL; @@ -5796,6 +5796,7 @@ const void *op_register_iter(const void *const iter, char *const name, int iter_off = (int)(iter_reg - &(y_regs[0])); *name = (char)get_register_name(iter_off); *reg = *iter_reg; + *is_unnamed = (iter_reg == y_previous); while (++iter_reg - &(y_regs[0]) < NUM_SAVED_REGISTERS) { if (!reg_empty(iter_reg)) { return (void *) iter_reg; @@ -5819,11 +5820,12 @@ size_t op_register_amount(void) /// Set register to a given value /// -/// @param[in] name Register name. -/// @param[in] reg Register value. +/// @param[in] name Register name. +/// @param[in] reg Register value. +/// @param[in] is_unnamed Whether to set the unnamed regiseter to reg /// /// @return true on success, false on failure. -bool op_register_set(const char name, const yankreg_T reg) +bool op_register_set(const char name, const yankreg_T reg, bool is_unnamed) { int i = op_reg_index(name); if (i == -1) { @@ -5831,6 +5833,10 @@ bool op_register_set(const char name, const yankreg_T reg) } free_register(&y_regs[i]); y_regs[i] = reg; + + if (is_unnamed) { + y_previous = &y_regs[i]; + } return true; } diff --git a/src/nvim/shada.c b/src/nvim/shada.c index 87b4617099..c23fd398a5 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -98,6 +98,7 @@ KHASH_SET_INIT_STR(strset) #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" @@ -286,6 +287,7 @@ typedef struct { char **contents; size_t contents_size; size_t width; + bool is_unnamed; dict_T *additional_data; } reg; struct global_var { @@ -1335,7 +1337,7 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags) .y_width = (colnr_T) cur_entry.data.reg.width, .timestamp = cur_entry.timestamp, .additional_data = cur_entry.data.reg.additional_data, - })) { + }, cur_entry.data.reg.is_unnamed)) { shada_free_shada_entry(&cur_entry); } // Do not free shada entry: its allocated memory was saved above. @@ -1780,6 +1782,7 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer, 2 // Register contents and name + 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: + (size_t) (entry.data.reg.additional_data == NULL ? 0 @@ -1800,6 +1803,14 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer, PACK_STATIC_STR(REG_KEY_WIDTH); msgpack_pack_uint64(spacker, (uint64_t) entry.data.reg.width); } + if (!CHECK_DEFAULT(entry, reg.is_unnamed)) { + PACK_STATIC_STR(REG_KEY_UNNAMED); + if (entry.data.reg.is_unnamed) { + msgpack_pack_true(spacker); + } else { + msgpack_pack_false(spacker); + } + } DUMP_ADDITIONAL_DATA(entry.data.reg.additional_data, "register item"); break; } @@ -2591,7 +2602,8 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, do { yankreg_T reg; char name = NUL; - reg_iter = op_register_iter(reg_iter, &name, ®); + bool is_unnamed = false; + reg_iter = op_register_iter(reg_iter, &name, ®, &is_unnamed); if (name == NUL) { break; } @@ -2611,6 +2623,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, .width = (size_t) (reg.y_type == kMTBlockWise ? reg.y_width : 0), .additional_data = reg.additional_data, .name = name, + .is_unnamed = is_unnamed, } } } @@ -3594,6 +3607,7 @@ shada_read_next_item_start: entry->data.reg.contents[i] = BIN_CONVERTED(arr.ptr[i].via.bin); } } + BOOLEAN_KEY("register", REG_KEY_UNNAMED, entry->data.reg.is_unnamed) TYPED_KEY("register", REG_KEY_TYPE, "an unsigned integer", entry->data.reg.type, POSITIVE_INTEGER, u64, TOU8) TYPED_KEY("register", KEY_NAME_CHAR, "an unsigned integer", From 9a91ce4fa6a7504644e10a6761eae5cc5699159a Mon Sep 17 00:00:00 2001 From: AdnoC Date: Wed, 4 May 2016 14:16:19 -0400 Subject: [PATCH 3/9] eval: Add ability to set the unnamed register with setreg --- runtime/doc/eval.txt | 2 ++ src/nvim/eval.c | 12 +++++++++++- src/nvim/ops.c | 16 ++++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index f076458fed..f73599ebd9 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -6710,6 +6710,8 @@ setreg({regname}, {value} [, {options}]) used as the width of the selection - if it is not specified then the width of the block is set to the number of characters in the longest line (counting a as 1 character). + If {options} contains "u" or '"', then the unnamed register is + set to point to register {regname}. If {options} contains no register settings, then the default is to use character mode unless {value} ends in a for diff --git a/src/nvim/eval.c b/src/nvim/eval.c index e4b3128930..473de02ab6 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -5100,7 +5100,8 @@ bool garbage_collect(bool testing) do { yankreg_T reg; char name = NUL; - reg_iter = op_register_iter(reg_iter, &name, ®); + bool is_unnamed = false; + reg_iter = op_register_iter(reg_iter, &name, ®, &is_unnamed); if (name != NUL) { ABORTING(set_ref_dict)(reg.additional_data, copyID); } @@ -14792,6 +14793,7 @@ static void f_setreg(typval_T *argvars, typval_T *rettv, FunPtr fptr) regname = '"'; } + bool set_unnamed = false; if (argvars[2].v_type != VAR_UNKNOWN) { const char *stropt = tv_get_string_chk(&argvars[2]); if (stropt == NULL) { @@ -14820,6 +14822,10 @@ static void f_setreg(typval_T *argvars, typval_T *rettv, FunPtr fptr) } break; } + case 'u': case '"': { // unnamed register + set_unnamed = true; + break; + } } } } @@ -14872,6 +14878,10 @@ free_lstval: append, yank_type, block_len); } rettv->vval.v_number = 0; + + if (set_unnamed) { + op_register_set_previous(regname); + } } /* diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 9e5121b3fe..90d9d41a2a 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -5853,3 +5853,19 @@ const yankreg_T *op_register_get(const char name) } return &y_regs[i]; } + +/// Set the previous yank register +/// +/// @param[in] name Register name. +/// +/// @return true on success, false on failure. +bool op_register_set_previous(const char name) +{ + int i = op_reg_index(name); + if (i == -1) { + return false; + } + + y_previous = &y_regs[i]; + return true; +} From beca4dc16c0cc45b97bb04891b19350308026f1f Mon Sep 17 00:00:00 2001 From: AdnoC Date: Wed, 4 May 2016 14:17:09 -0400 Subject: [PATCH 4/9] eval/shada: Add testing for unnamed register with setreg and startup --- test/functional/legacy/eval_spec.lua | 9 ++++++++ test/functional/plugin/shada_spec.lua | 28 ++++++++++++++++++++++++ test/functional/shada/registers_spec.lua | 15 ++++++++++++- 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/test/functional/legacy/eval_spec.lua b/test/functional/legacy/eval_spec.lua index d7ef508194..1b6f834019 100644 --- a/test/functional/legacy/eval_spec.lua +++ b/test/functional/legacy/eval_spec.lua @@ -516,6 +516,15 @@ describe('eval', function() eq({'item'}, eval("y")) end) + it('sets the unnamed register when the "u" option is passed to setreg', function() + execute("call setreg('a','a reg', 'cu')") + eq("a reg", eval('@"')) + execute("call setreg('b','b reg', 'cu')") + eq("b reg", eval('@"')) + execute("call setreg('c','c reg', 'c')") + eq("b reg", eval('@"')) + end) + it('search and expressions', function() command('so test_eval_setup.vim') command([=[call SetReg('/', ['abc/'])]=]) diff --git a/test/functional/plugin/shada_spec.lua b/test/functional/plugin/shada_spec.lua index b543037ae2..bf37fbabc5 100644 --- a/test/functional/plugin/shada_spec.lua +++ b/test/functional/plugin/shada_spec.lua @@ -636,6 +636,7 @@ describe('In autoload/shada.vim', function() ' # Required key missing: rc', ' + rw block width 0', ' + rt type CHARACTERWISE', + ' + ru is_unnamed FALSE', }, ([[ [{'type': 5, 'timestamp': 0, 'data': { }}] ]]):gsub('\n', '')) sd2strings_eq({ @@ -645,6 +646,7 @@ describe('In autoload/shada.vim', function() ' # Required key missing: rc', ' + rw block width 0', ' + rt type CHARACTERWISE', + ' + ru is_unnamed FALSE', }, ([[ [{'type': 5, 'timestamp': 0, 'data': { 'n': 0x20, }}] ]]):gsub('\n', '')) @@ -655,9 +657,11 @@ describe('In autoload/shada.vim', function() ' + rc contents ["abc", "def"]', ' + rw block width 0', ' + rt type CHARACTERWISE', + ' + ru is_unnamed FALSE', }, ([[ [{'type': 5, 'timestamp': 0, 'data': { 'n': 0x20, 'rc': ["abc", "def"], + 'ru': {'_TYPE': v:msgpack_types.boolean, '_VAL': 0}, }}] ]]):gsub('\n', '')) sd2strings_eq({ 'Register with timestamp ' .. epoch .. ':', @@ -668,9 +672,11 @@ describe('In autoload/shada.vim', function() ' | - "abcdefghijklmnopqrstuvwxyz"', ' + rw block width 0', ' + rt type CHARACTERWISE', + ' + ru is_unnamed TRUE', }, ([[ [{'type': 5, 'timestamp': 0, 'data': { 'n': 0x20, 'rc': ['abcdefghijklmnopqrstuvwxyz', 'abcdefghijklmnopqrstuvwxyz'], + 'ru': {'_TYPE': v:msgpack_types.boolean, '_VAL': 1}, }}] ]]):gsub('\n', '')) sd2strings_eq({ 'Register with timestamp ' .. epoch .. ':', @@ -681,6 +687,7 @@ describe('In autoload/shada.vim', function() ' | - "abcdefghijklmnopqrstuvwxyz"', ' + rw block width 0', ' + rt type CHARACTERWISE', + ' + ru is_unnamed FALSE', }, ([[ [{'type': 5, 'timestamp': 0, 'data': { 'n': 0x20, 'rc': ['abcdefghijklmnopqrstuvwxyz', 'abcdefghijklmnopqrstuvwxyz'], @@ -696,6 +703,7 @@ describe('In autoload/shada.vim', function() ' | - "abcdefghijklmnopqrstuvwxyz"', ' + rw block width 5', ' + rt type LINEWISE', + ' + ru is_unnamed FALSE', }, ([[ [{'type': 5, 'timestamp': 0, 'data': { 'n': 0x20, 'rc': ['abcdefghijklmnopqrstuvwxyz', 'abcdefghijklmnopqrstuvwxyz'], @@ -712,6 +720,7 @@ describe('In autoload/shada.vim', function() ' # Expected integer', ' + rw block width ""', ' + rt type BLOCKWISE', + ' + ru is_unnamed FALSE', }, ([[ [{'type': 5, 'timestamp': 0, 'data': { 'n': 0x20, 'rc': ['abcdefghijklmnopqrstuvwxyz', 'abcdefghijklmnopqrstuvwxyz'], @@ -729,12 +738,31 @@ describe('In autoload/shada.vim', function() ' # Unexpected enum value: expected one of 0 (CHARACTERWISE), ' .. '1 (LINEWISE), 2 (BLOCKWISE)', ' + rt type 10', + ' + ru is_unnamed FALSE', }, ([[ [{'type': 5, 'timestamp': 0, 'data': { 'n': 0x20, 'rc': 0, 'rw': -1, 'rt': 10, }}] ]]):gsub('\n', '')) + sd2strings_eq({ + 'Register with timestamp ' .. epoch .. ':', + ' % Key Description Value', + ' + n name \' \'', + ' + rc contents @', + ' | - "abcdefghijklmnopqrstuvwxyz"', + ' | - "abcdefghijklmnopqrstuvwxyz"', + ' + rw block width 5', + ' + rt type LINEWISE', + ' # Expected boolean', + ' + ru is_unnamed 0', + }, ([[ [{'type': 5, 'timestamp': 0, 'data': { + 'n': 0x20, + 'rc': ['abcdefghijklmnopqrstuvwxyz', 'abcdefghijklmnopqrstuvwxyz'], + 'rw': 5, + 'rt': 1, + 'ru': 0, + }}] ]]):gsub('\n', '')) end) it('works with variable items', function() diff --git a/test/functional/shada/registers_spec.lua b/test/functional/shada/registers_spec.lua index d8e9892c76..256242cbf6 100644 --- a/test/functional/shada/registers_spec.lua +++ b/test/functional/shada/registers_spec.lua @@ -148,10 +148,23 @@ describe('ShaDa support code', function() eq({{'\171«'}, 'v'}, getreg('e')) end) - it('remembers which register was the unnamed register when loading', + it('defaults the unnamed register to register 0 if it wasn\'t set', function() setreg('0', {'zero'}, 'c') setreg('1', {'one'}, 'c') + setreg('2', {'two'}, 'c') + nvim_command('qall') + reset() + eq({{'zero'}, 'v'}, getreg('0')) + eq({{'one'}, 'v'}, getreg('1')) + eq({{'zero'}, 'v'}, getreg('"')) + end) + + it('remembers which register was the unnamed register when loading', + function() + setreg('0', {'zero'}, 'c') + setreg('1', {'one'}, 'cu') + setreg('2', {'two'}, 'c') nvim_command('qall') reset() eq({{'zero'}, 'v'}, getreg('0')) From 336412e1db84c3cd8f0287b95820f903e084dd3d Mon Sep 17 00:00:00 2001 From: AdnoC Date: Fri, 6 May 2016 16:36:15 -0400 Subject: [PATCH 5/9] shada/linting: Moved some code out of shada_write. shada_write was too long (over 500 lines) and caused a linting error. Register initialization was moved to its own function in order to save lines. --- src/nvim/shada.c | 73 +++++++++++++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 32 deletions(-) diff --git a/src/nvim/shada.c b/src/nvim/shada.c index c23fd398a5..a29d34d037 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -2329,6 +2329,46 @@ static inline void add_search_pattern(PossiblyFreedShadaEntry *const ret_pse, } } +/// Initializes registers for writing to the ShaDa file +/// +/// @param[in] wms The WriteMergerState used when writing. +/// @param[in] max_reg_lines The maximum number of register lines. +static void shada_initialize_registers(WriteMergerState *const wms, + int max_reg_lines) { + const void *reg_iter = NULL; + const bool limit_reg_lines = max_reg_lines >= 0; + do { + yankreg_T reg; + char name = NUL; + bool is_unnamed = false; + reg_iter = op_register_iter(reg_iter, &name, ®, &is_unnamed); + if (name == NUL) { + break; + } + if (limit_reg_lines && reg.y_size > max_reg_lines) { + continue; + } + wms->registers[op_reg_index(name)] = (PossiblyFreedShadaEntry) { + .can_free_entry = false, + .data = { + .type = kSDItemRegister, + .timestamp = reg.timestamp, + .data = { + .reg = { + .contents = (char **) reg.y_array, + .contents_size = (size_t) 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, + } + } + } + }; + } while (reg_iter != NULL); +} + /// Write ShaDa file /// /// @param[in] sd_writer Structure containing file writer definition. @@ -2355,7 +2395,6 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, if (max_reg_lines < 0) { max_reg_lines = get_shada_parameter('"'); } - const bool limit_reg_lines = max_reg_lines >= 0; const bool dump_registers = (max_reg_lines != 0); khash_t(bufset) removable_bufs = KHASH_EMPTY_TABLE(bufset); const size_t max_kbyte = (size_t) max_kbyte_i; @@ -2598,37 +2637,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, // Initialize registers if (dump_registers) { - const void *reg_iter = NULL; - do { - yankreg_T reg; - char name = NUL; - bool is_unnamed = false; - reg_iter = op_register_iter(reg_iter, &name, ®, &is_unnamed); - if (name == NUL) { - break; - } - if (limit_reg_lines && reg.y_size > (size_t)max_reg_lines) { - continue; - } - wms->registers[op_reg_index(name)] = (PossiblyFreedShadaEntry) { - .can_free_entry = false, - .data = { - .type = kSDItemRegister, - .timestamp = reg.timestamp, - .data = { - .reg = { - .contents = (char **) reg.y_array, - .contents_size = (size_t) 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, - } - } - } - }; - } while (reg_iter != NULL); + shada_initialize_registers(wms, max_reg_lines); } // Initialize buffers From 0c3dea5c4d86a8ef61363034877bde04a0e99463 Mon Sep 17 00:00:00 2001 From: AdnoC Date: Mon, 29 May 2017 11:31:06 -0400 Subject: [PATCH 6/9] style/lint --- src/nvim/eval.c | 2 +- src/nvim/ops.c | 5 +++-- src/nvim/shada.c | 20 +++++++++++--------- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 473de02ab6..398d8bb699 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -14822,7 +14822,7 @@ static void f_setreg(typval_T *argvars, typval_T *rettv, FunPtr fptr) } break; } - case 'u': case '"': { // unnamed register + case 'u': case '"': { // unnamed register set_unnamed = true; break; } diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 90d9d41a2a..e374686286 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -5820,8 +5820,8 @@ size_t op_register_amount(void) /// Set register to a given value /// -/// @param[in] name Register name. -/// @param[in] reg Register value. +/// @param[in] name Register name. +/// @param[in] reg Register value. /// @param[in] is_unnamed Whether to set the unnamed regiseter to reg /// /// @return true on success, false on failure. @@ -5860,6 +5860,7 @@ const yankreg_T *op_register_get(const char name) /// /// @return true on success, false on failure. bool op_register_set_previous(const char name) + FUNC_ATTR_WARN_UNUSED_RESULT { int i = op_reg_index(name); if (i == -1) { diff --git a/src/nvim/shada.c b/src/nvim/shada.c index a29d34d037..8dccb24ebe 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -285,9 +285,9 @@ typedef struct { char name; MotionType type; char **contents; + bool is_unnamed; size_t contents_size; size_t width; - bool is_unnamed; dict_T *additional_data; } reg; struct global_var { @@ -2329,12 +2329,14 @@ static inline void add_search_pattern(PossiblyFreedShadaEntry *const ret_pse, } } -/// Initializes registers for writing to the ShaDa file +/// Initialize registers for writing to the ShaDa file /// /// @param[in] wms The WriteMergerState used when writing. -/// @param[in] max_reg_lines The maximum number of register lines. -static void shada_initialize_registers(WriteMergerState *const wms, - int max_reg_lines) { +/// @param[in] max_reg_lines The maximum number of register lines. +static inline void shada_initialize_registers(WriteMergerState *const wms, + int max_reg_lines) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_ALWAYS_INLINE +{ const void *reg_iter = NULL; const bool limit_reg_lines = max_reg_lines >= 0; do { @@ -2345,7 +2347,7 @@ static void shada_initialize_registers(WriteMergerState *const wms, if (name == NUL) { break; } - if (limit_reg_lines && reg.y_size > max_reg_lines) { + if (limit_reg_lines && reg.y_size > (size_t)max_reg_lines) { continue; } wms->registers[op_reg_index(name)] = (PossiblyFreedShadaEntry) { @@ -2355,10 +2357,10 @@ static void shada_initialize_registers(WriteMergerState *const wms, .timestamp = reg.timestamp, .data = { .reg = { - .contents = (char **) reg.y_array, - .contents_size = (size_t) reg.y_size, + .contents = (char **)reg.y_array, + .contents_size = (size_t)reg.y_size, .type = reg.y_type, - .width = (size_t) (reg.y_type == kMTBlockWise ? reg.y_width : 0), + .width = (size_t)(reg.y_type == kMTBlockWise ? reg.y_width : 0), .additional_data = reg.additional_data, .name = name, .is_unnamed = is_unnamed, From 5908f562dfe9dfcbf1218b2820addff117ee4847 Mon Sep 17 00:00:00 2001 From: AdnoC Date: Mon, 29 May 2017 11:34:08 -0400 Subject: [PATCH 7/9] test: Fix and add cases for unnamed register Also: Add ru to shada tests with all keys Add test for unset unnamed and register 0 --- test/functional/legacy/eval_spec.lua | 6 +++--- test/functional/plugin/shada_spec.lua | 13 +++++++++++-- test/functional/shada/registers_spec.lua | 13 +++++++++++++ 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/test/functional/legacy/eval_spec.lua b/test/functional/legacy/eval_spec.lua index 1b6f834019..c5d38d6d05 100644 --- a/test/functional/legacy/eval_spec.lua +++ b/test/functional/legacy/eval_spec.lua @@ -517,11 +517,11 @@ describe('eval', function() end) it('sets the unnamed register when the "u" option is passed to setreg', function() - execute("call setreg('a','a reg', 'cu')") + command("call setreg('a','a reg', 'cu')") eq("a reg", eval('@"')) - execute("call setreg('b','b reg', 'cu')") + command("call setreg('b','b reg', 'cu')") eq("b reg", eval('@"')) - execute("call setreg('c','c reg', 'c')") + command("call setreg('c','c reg', 'c')") eq("b reg", eval('@"')) end) diff --git a/test/functional/plugin/shada_spec.lua b/test/functional/plugin/shada_spec.lua index bf37fbabc5..639833071b 100644 --- a/test/functional/plugin/shada_spec.lua +++ b/test/functional/plugin/shada_spec.lua @@ -179,6 +179,7 @@ describe('In autoload/shada.vim', function() ' + n name \'@\'', ' + rc contents ["abc", "def"]', ' + rt type CHARACTERWISE', + ' + ru is_unnamed FALSE', ' + rw block width 10', ' + sb search backward TRUE', ' + sc smartcase value FALSE', @@ -204,6 +205,7 @@ describe('In autoload/shada.vim', function() 'rt': 0, 'rw': 10, 'rc': ['abc', 'def'], + 'ru': {'_TYPE': v:msgpack_types.boolean, '_VAL': 0}, 'n': 0x40, 'l': 10, 'c': 0, @@ -226,6 +228,8 @@ describe('In autoload/shada.vim', function() .. '0 (CHARACTERWISE), 1 (LINEWISE), 2 (BLOCKWISE)', ' + rt type 10', ' # Expected boolean', + ' + ru is_unnamed 10', + ' # Expected boolean', ' + sc smartcase value NIL', ' # Expected boolean', ' + sm magic value "TRUE"', @@ -240,6 +244,7 @@ describe('In autoload/shada.vim', function() 'sp': {'_TYPE': v:msgpack_types.string, '_VAL': ["abc"]}, 'rt': 10, 'rc': '10', + 'ru': 10, 'n': -0x40, 'l': -10, 'c': 'abc', @@ -720,12 +725,14 @@ describe('In autoload/shada.vim', function() ' # Expected integer', ' + rw block width ""', ' + rt type BLOCKWISE', - ' + ru is_unnamed FALSE', + ' # Expected boolean', + ' + ru is_unnamed ""', }, ([[ [{'type': 5, 'timestamp': 0, 'data': { 'n': 0x20, 'rc': ['abcdefghijklmnopqrstuvwxyz', 'abcdefghijklmnopqrstuvwxyz'], 'rw': "", 'rt': 2, + 'ru': "" }}] ]]):gsub('\n', '')) sd2strings_eq({ 'Register with timestamp ' .. epoch .. ':', @@ -738,12 +745,14 @@ describe('In autoload/shada.vim', function() ' # Unexpected enum value: expected one of 0 (CHARACTERWISE), ' .. '1 (LINEWISE), 2 (BLOCKWISE)', ' + rt type 10', - ' + ru is_unnamed FALSE', + ' # Expected boolean', + ' + ru is_unnamed ["abc", "def"]', }, ([[ [{'type': 5, 'timestamp': 0, 'data': { 'n': 0x20, 'rc': 0, 'rw': -1, 'rt': 10, + 'ru': ['abc', 'def'], }}] ]]):gsub('\n', '')) sd2strings_eq({ 'Register with timestamp ' .. epoch .. ':', diff --git a/test/functional/shada/registers_spec.lua b/test/functional/shada/registers_spec.lua index 256242cbf6..71af14aba8 100644 --- a/test/functional/shada/registers_spec.lua +++ b/test/functional/shada/registers_spec.lua @@ -148,6 +148,19 @@ describe('ShaDa support code', function() eq({{'\171«'}, 'v'}, getreg('e')) end) + it('has a blank unnamed register if it wasn\'t set and register 0 is empty', + function() + setreg('1', {'one'}, 'c') + setreg('2', {'two'}, 'c') + setreg('a', {'a'}, 'c') + nvim_command('qall') + reset() + eq({{}, ''}, getreg('0')) + eq({{'one'}, 'v'}, getreg('1')) + eq({{}, ''}, getreg('"')) + eq({{'a'}, 'v'}, getreg('a')) + end) + it('defaults the unnamed register to register 0 if it wasn\'t set', function() setreg('0', {'zero'}, 'c') From 745bac562d84cda1e3e150e482f673fa5bd23638 Mon Sep 17 00:00:00 2001 From: AdnoC Date: Mon, 29 May 2017 12:04:19 -0400 Subject: [PATCH 8/9] eval.c: Ignore unnamed register error in f_setreg The error case is already handled and an appropriate error message is already printed. --- src/nvim/eval.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 398d8bb699..35ca236831 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -14880,7 +14880,8 @@ free_lstval: rettv->vval.v_number = 0; if (set_unnamed) { - op_register_set_previous(regname); + // Discard the result. We already handle the error case. + if (op_register_set_previous(regname)) { } } } From 2f2eeb19ba7ba6f8b7789d7d10c9e821d4ea3351 Mon Sep 17 00:00:00 2001 From: AdnoC Date: Mon, 29 May 2017 13:46:31 -0400 Subject: [PATCH 9/9] shada: Add default value for is_unnamed --- src/nvim/shada.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/nvim/shada.c b/src/nvim/shada.c index 8dccb24ebe..4788b1e7d0 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -475,6 +475,7 @@ static const ShadaEntry sd_default_values[] = { .type = kMTCharWise, .contents = NULL, .contents_size = 0, + .is_unnamed = false, .width = 0, .additional_data = NULL), DEF_SDE(Variable, global_var,