Skip to content

Commit 8a1a256

Browse files
authored
Merge pull request neovim#14326 from janlazo/vim-8.2.0623
vim-patch:8.2.{623,1822,2738}
2 parents 82ac44d + b35daa9 commit 8a1a256

File tree

7 files changed

+109
-9
lines changed

7 files changed

+109
-9
lines changed

runtime/doc/eval.txt

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5563,13 +5563,14 @@ id({expr}) *id()*
55635563
Returns a |String| which is a unique identifier of the
55645564
container type (|List|, |Dict| and |Partial|). It is
55655565
guaranteed that for the mentioned types `id(v1) ==# id(v2)`
5566-
returns true iff `type(v1) == type(v2) && v1 is v2` (note:
5567-
|v:_null_list| and |v:_null_dict| have the same `id()` with
5568-
different types because they are internally represented as
5569-
a NULL pointers). Currently `id()` returns a hexadecimal
5570-
representanion of the pointers to the containers (i.e. like
5571-
`0x994a40`), same as `printf("%p", {expr})`, but it is advised
5572-
against counting on exact format of return value.
5566+
returns true iff `type(v1) == type(v2) && v1 is v2`.
5567+
Note that |v:_null_string|, |v:_null_list|, and |v:_null_dict|
5568+
have the same `id()` with different types because they are
5569+
internally represented as a NULL pointers. `id()` returns a
5570+
hexadecimal representanion of the pointers to the containers
5571+
(i.e. like `0x994a40`), same as `printf("%p", {expr})`,
5572+
but it is advised against counting on the exact format of
5573+
return value.
55735574

55745575
It is not guaranteed that `id(no_longer_existing_container)`
55755576
will not be equal to some other `id()`: new containers may

src/nvim/eval.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ static struct vimvar {
229229
// Neovim
230230
VV(VV_STDERR, "stderr", VAR_NUMBER, VV_RO),
231231
VV(VV_MSGPACK_TYPES, "msgpack_types", VAR_DICT, VV_RO),
232+
VV(VV__NULL_STRING, "_null_string", VAR_STRING, VV_RO),
232233
VV(VV__NULL_LIST, "_null_list", VAR_LIST, VV_RO),
233234
VV(VV__NULL_DICT, "_null_dict", VAR_DICT, VV_RO),
234235
VV(VV_LUA, "lua", VAR_PARTIAL, VV_RO),

src/nvim/eval.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ typedef enum {
158158
// Neovim
159159
VV_STDERR,
160160
VV_MSGPACK_TYPES,
161+
VV__NULL_STRING, // String with NULL value. For test purposes only.
161162
VV__NULL_LIST, // List with NULL value. For test purposes only.
162163
VV__NULL_DICT, // Dictionary with NULL value. For test purposes only.
163164
VV_LUA,

src/nvim/testdir/test_listdict.vim

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,15 @@ func Test_dict_lock_extend()
506506
call assert_equal({'a': 99, 'b': 100}, d)
507507
endfunc
508508

509+
" Cannot use += with a locked dict
510+
func Test_dict_lock_operator()
511+
unlet! d
512+
let d = {}
513+
lockvar d
514+
call assert_fails("let d += {'k' : 10}", 'E741:')
515+
unlockvar d
516+
endfunc
517+
509518
" No remove() of write-protected scope-level variable
510519
func! Tfunc(this_is_a_long_parameter_name)
511520
call assert_fails("call remove(a:, 'this_is_a_long_parameter_name')", 'E742')
@@ -709,6 +718,23 @@ func Test_listdict_extend()
709718

710719
call assert_fails("call extend([1, 2], 1)", 'E712:')
711720
call assert_fails("call extend([1, 2], {})", 'E712:')
721+
722+
" Extend g: dictionary with an invalid variable name
723+
call assert_fails("call extend(g:, {'-!' : 10})", 'E461:')
724+
725+
" Extend a list with itself.
726+
let l = [1, 5, 7]
727+
call extend(l, l, 0)
728+
call assert_equal([1, 5, 7, 1, 5, 7], l)
729+
let l = [1, 5, 7]
730+
call extend(l, l, 1)
731+
call assert_equal([1, 1, 5, 7, 5, 7], l)
732+
let l = [1, 5, 7]
733+
call extend(l, l, 2)
734+
call assert_equal([1, 5, 1, 5, 7, 7], l)
735+
let l = [1, 5, 7]
736+
call extend(l, l, 3)
737+
call assert_equal([1, 5, 7, 1, 5, 7], l)
712738
endfunc
713739

714740
func s:check_scope_dict(x, fixed)
@@ -782,3 +808,40 @@ func Test_scope_dict()
782808
" Test for v:
783809
call s:check_scope_dict('v', v:true)
784810
endfunc
811+
812+
" Test for a null list
813+
func Test_null_list()
814+
let l = v:_null_list
815+
call assert_equal('', join(l))
816+
call assert_equal(0, len(l))
817+
call assert_equal(1, empty(l))
818+
call assert_fails('let s = join([1, 2], [])', 'E730:')
819+
call assert_equal([], split(v:_null_string))
820+
call assert_equal([], l[:2])
821+
call assert_true([] == l)
822+
call assert_equal('[]', string(l))
823+
" call assert_equal(0, sort(l))
824+
" call assert_equal(0, sort(l))
825+
" call assert_equal(0, uniq(l))
826+
let k = [] + l
827+
call assert_equal([], k)
828+
let k = l + []
829+
call assert_equal([], k)
830+
call assert_equal(0, len(copy(l)))
831+
call assert_equal(0, count(l, 5))
832+
call assert_equal([], deepcopy(l))
833+
call assert_equal(5, get(l, 2, 5))
834+
call assert_equal(-1, index(l, 2, 5))
835+
" call assert_equal(0, insert(l, 2, -1))
836+
call assert_equal(0, min(l))
837+
call assert_equal(0, max(l))
838+
" call assert_equal(0, remove(l, 0, 2))
839+
call assert_equal([], repeat(l, 2))
840+
" call assert_equal(0, reverse(l))
841+
" call assert_equal(0, sort(l))
842+
call assert_equal('[]', string(l))
843+
" call assert_equal(0, extend(l, l, 0))
844+
lockvar l
845+
call assert_equal(1, islocked('l'))
846+
unlockvar l
847+
endfunc

src/nvim/testdir/test_utf8.vim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ func Test_list2str_str2list_utf8()
8484

8585
" Null list is the same as an empty list
8686
call assert_equal('', list2str([]))
87-
" call assert_equal('', list2str(test_null_list()))
87+
call assert_equal('', list2str(v:_null_list))
8888
endfunc
8989

9090
func Test_list2str_str2list_latin1()

test/functional/eval/null_spec.lua

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ describe('NULL', function()
1414
clear()
1515
command('let L = v:_null_list')
1616
command('let D = v:_null_dict')
17-
command('let S = $XXX_NONEXISTENT_VAR_XXX')
17+
command('let S = v:_null_string')
18+
command('let V = $XXX_NONEXISTENT_VAR_XXX')
1819
end)
1920
local tmpfname = 'Xtest-functional-viml-null'
2021
after_each(function()
@@ -129,6 +130,7 @@ describe('NULL', function()
129130
null_expr_test('is accepted by setloclist()', 'setloclist(1, L)', 0, 0)
130131
null_test('is accepted by :cexpr', 'cexpr L', 0)
131132
null_test('is accepted by :lexpr', 'lexpr L', 0)
133+
null_expr_test('does not crash execute()', 'execute(L)', 0, '')
132134
end)
133135
describe('dict', function()
134136
it('does not crash when indexing NULL dict', function()
@@ -142,4 +144,26 @@ describe('NULL', function()
142144
null_expr_test('makes map() return v:_null_dict', 'map(D, "v:val") is# D', 0, 1)
143145
null_expr_test('makes filter() return v:_null_dict', 'filter(D, "1") is# D', 0, 1)
144146
end)
147+
describe('string', function()
148+
null_test('does not crash :echomsg', 'echomsg S', 0)
149+
null_test('does not crash :execute', 'execute S', 0)
150+
null_expr_test('does not crash execute()', 'execute(S)', 0, '')
151+
null_expr_test('makes executable() error out', 'executable(S)', 'E928: String required', 0)
152+
null_expr_test('does not crash filereadable()', 'filereadable(S)', 0, 0)
153+
null_expr_test('does not crash filewritable()', 'filewritable(S)', 0, 0)
154+
null_expr_test('does not crash fnamemodify()', 'fnamemodify(S, S)', 0, '')
155+
null_expr_test('does not crash getfperm()', 'getfperm(S)', 0, '')
156+
null_expr_test('does not crash getfsize()', 'getfsize(S)', 0, -1)
157+
null_expr_test('does not crash getftime()', 'getftime(S)', 0, -1)
158+
null_expr_test('does not crash getftype()', 'getftype(S)', 0, '')
159+
null_expr_test('does not crash glob()', 'glob(S)', 0, '')
160+
null_expr_test('does not crash globpath()', 'globpath(S, S)', 0, '')
161+
null_expr_test('does not crash mkdir()', 'mkdir(S)', 0, 0)
162+
null_expr_test('does not crash sort()', 'sort(["b", S, "a"])', 0, {'', 'a', 'b'})
163+
null_expr_test('does not crash split()', 'split(S)', 0, {})
164+
165+
null_test('can be used to set an option', 'let &grepprg = S', 0)
166+
167+
null_expr_test('is equal to non-existent variable', 'S == V', 0, 1)
168+
end)
145169
end)

test/functional/eval/writefile_spec.lua

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,16 @@ describe('writefile()', function()
5959
eq('\n', read_file(fname))
6060
end)
6161

62+
it('writes list with a null string to a file', function()
63+
eq(0, exc_exec(
64+
('call writefile([v:_null_string], "%s", "b")'):format(
65+
fname)))
66+
eq('', read_file(fname))
67+
eq(0, exc_exec(('call writefile([v:_null_string], "%s")'):format(
68+
fname)))
69+
eq('\n', read_file(fname))
70+
end)
71+
6272
it('appends to a file', function()
6373
eq(nil, read_file(fname))
6474
eq(0, funcs.writefile({'abc', 'def', 'ghi'}, fname))

0 commit comments

Comments
 (0)