Browse Source

Merge pull request #14326 from janlazo/vim-8.2.0623

vim-patch:8.2.{623,1822,2738}
pull/14334/head
Jan Edmund Lazo 4 weeks ago
committed by GitHub
parent
commit
8a1a256b44
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 15
      runtime/doc/eval.txt
  2. 1
      src/nvim/eval.c
  3. 1
      src/nvim/eval.h
  4. 63
      src/nvim/testdir/test_listdict.vim
  5. 2
      src/nvim/testdir/test_utf8.vim
  6. 26
      test/functional/eval/null_spec.lua
  7. 10
      test/functional/eval/writefile_spec.lua

15
runtime/doc/eval.txt

@ -5563,13 +5563,14 @@ id({expr}) *id()*
Returns a |String| which is a unique identifier of the
container type (|List|, |Dict| and |Partial|). It is
guaranteed that for the mentioned types `id(v1) ==# id(v2)`
returns true iff `type(v1) == type(v2) && v1 is v2` (note:
|v:_null_list| and |v:_null_dict| have the same `id()` with
different types because they are internally represented as
a NULL pointers). Currently `id()` returns a hexadecimal
representanion of the pointers to the containers (i.e. like
`0x994a40`), same as `printf("%p", {expr})`, but it is advised
against counting on exact format of return value.
returns true iff `type(v1) == type(v2) && v1 is v2`.
Note that |v:_null_string|, |v:_null_list|, and |v:_null_dict|
have the same `id()` with different types because they are
internally represented as a NULL pointers. `id()` returns a
hexadecimal representanion of the pointers to the containers
(i.e. like `0x994a40`), same as `printf("%p", {expr})`,
but it is advised against counting on the exact format of
return value.
It is not guaranteed that `id(no_longer_existing_container)`
will not be equal to some other `id()`: new containers may

1
src/nvim/eval.c

@ -229,6 +229,7 @@ static struct vimvar {
// Neovim
VV(VV_STDERR, "stderr", VAR_NUMBER, VV_RO),
VV(VV_MSGPACK_TYPES, "msgpack_types", VAR_DICT, VV_RO),
VV(VV__NULL_STRING, "_null_string", VAR_STRING, VV_RO),
VV(VV__NULL_LIST, "_null_list", VAR_LIST, VV_RO),
VV(VV__NULL_DICT, "_null_dict", VAR_DICT, VV_RO),
VV(VV_LUA, "lua", VAR_PARTIAL, VV_RO),

1
src/nvim/eval.h

@ -158,6 +158,7 @@ typedef enum {
// Neovim
VV_STDERR,
VV_MSGPACK_TYPES,
VV__NULL_STRING, // String with NULL value. For test purposes only.
VV__NULL_LIST, // List with NULL value. For test purposes only.
VV__NULL_DICT, // Dictionary with NULL value. For test purposes only.
VV_LUA,

63
src/nvim/testdir/test_listdict.vim

@ -506,6 +506,15 @@ func Test_dict_lock_extend()
call assert_equal({'a': 99, 'b': 100}, d)
endfunc
" Cannot use += with a locked dict
func Test_dict_lock_operator()
unlet! d
let d = {}
lockvar d
call assert_fails("let d += {'k' : 10}", 'E741:')
unlockvar d
endfunc
" No remove() of write-protected scope-level variable
func! Tfunc(this_is_a_long_parameter_name)
call assert_fails("call remove(a:, 'this_is_a_long_parameter_name')", 'E742')
@ -709,6 +718,23 @@ func Test_listdict_extend()
call assert_fails("call extend([1, 2], 1)", 'E712:')
call assert_fails("call extend([1, 2], {})", 'E712:')
" Extend g: dictionary with an invalid variable name
call assert_fails("call extend(g:, {'-!' : 10})", 'E461:')
" Extend a list with itself.
let l = [1, 5, 7]
call extend(l, l, 0)
call assert_equal([1, 5, 7, 1, 5, 7], l)
let l = [1, 5, 7]
call extend(l, l, 1)
call assert_equal([1, 1, 5, 7, 5, 7], l)
let l = [1, 5, 7]
call extend(l, l, 2)
call assert_equal([1, 5, 1, 5, 7, 7], l)
let l = [1, 5, 7]
call extend(l, l, 3)
call assert_equal([1, 5, 7, 1, 5, 7], l)
endfunc
func s:check_scope_dict(x, fixed)
@ -782,3 +808,40 @@ func Test_scope_dict()
" Test for v:
call s:check_scope_dict('v', v:true)
endfunc
" Test for a null list
func Test_null_list()
let l = v:_null_list
call assert_equal('', join(l))
call assert_equal(0, len(l))
call assert_equal(1, empty(l))
call assert_fails('let s = join([1, 2], [])', 'E730:')
call assert_equal([], split(v:_null_string))
call assert_equal([], l[:2])
call assert_true([] == l)
call assert_equal('[]', string(l))
" call assert_equal(0, sort(l))
" call assert_equal(0, sort(l))
" call assert_equal(0, uniq(l))
let k = [] + l
call assert_equal([], k)
let k = l + []
call assert_equal([], k)
call assert_equal(0, len(copy(l)))
call assert_equal(0, count(l, 5))
call assert_equal([], deepcopy(l))
call assert_equal(5, get(l, 2, 5))
call assert_equal(-1, index(l, 2, 5))
" call assert_equal(0, insert(l, 2, -1))
call assert_equal(0, min(l))
call assert_equal(0, max(l))
" call assert_equal(0, remove(l, 0, 2))
call assert_equal([], repeat(l, 2))
" call assert_equal(0, reverse(l))
" call assert_equal(0, sort(l))
call assert_equal('[]', string(l))
" call assert_equal(0, extend(l, l, 0))
lockvar l
call assert_equal(1, islocked('l'))
unlockvar l
endfunc

2
src/nvim/testdir/test_utf8.vim

@ -84,7 +84,7 @@ func Test_list2str_str2list_utf8()
" Null list is the same as an empty list
call assert_equal('', list2str([]))
" call assert_equal('', list2str(test_null_list()))
call assert_equal('', list2str(v:_null_list))
endfunc
func Test_list2str_str2list_latin1()

26
test/functional/eval/null_spec.lua

@ -14,7 +14,8 @@ describe('NULL', function()
clear()
command('let L = v:_null_list')
command('let D = v:_null_dict')
command('let S = $XXX_NONEXISTENT_VAR_XXX')
command('let S = v:_null_string')
command('let V = $XXX_NONEXISTENT_VAR_XXX')
end)
local tmpfname = 'Xtest-functional-viml-null'
after_each(function()
@ -129,6 +130,7 @@ describe('NULL', function()
null_expr_test('is accepted by setloclist()', 'setloclist(1, L)', 0, 0)
null_test('is accepted by :cexpr', 'cexpr L', 0)
null_test('is accepted by :lexpr', 'lexpr L', 0)
null_expr_test('does not crash execute()', 'execute(L)', 0, '')
end)
describe('dict', function()
it('does not crash when indexing NULL dict', function()
@ -142,4 +144,26 @@ describe('NULL', function()
null_expr_test('makes map() return v:_null_dict', 'map(D, "v:val") is# D', 0, 1)
null_expr_test('makes filter() return v:_null_dict', 'filter(D, "1") is# D', 0, 1)
end)
describe('string', function()
null_test('does not crash :echomsg', 'echomsg S', 0)
null_test('does not crash :execute', 'execute S', 0)
null_expr_test('does not crash execute()', 'execute(S)', 0, '')
null_expr_test('makes executable() error out', 'executable(S)', 'E928: String required', 0)
null_expr_test('does not crash filereadable()', 'filereadable(S)', 0, 0)
null_expr_test('does not crash filewritable()', 'filewritable(S)', 0, 0)
null_expr_test('does not crash fnamemodify()', 'fnamemodify(S, S)', 0, '')
null_expr_test('does not crash getfperm()', 'getfperm(S)', 0, '')
null_expr_test('does not crash getfsize()', 'getfsize(S)', 0, -1)
null_expr_test('does not crash getftime()', 'getftime(S)', 0, -1)
null_expr_test('does not crash getftype()', 'getftype(S)', 0, '')
null_expr_test('does not crash glob()', 'glob(S)', 0, '')
null_expr_test('does not crash globpath()', 'globpath(S, S)', 0, '')
null_expr_test('does not crash mkdir()', 'mkdir(S)', 0, 0)
null_expr_test('does not crash sort()', 'sort(["b", S, "a"])', 0, {'', 'a', 'b'})
null_expr_test('does not crash split()', 'split(S)', 0, {})
null_test('can be used to set an option', 'let &grepprg = S', 0)
null_expr_test('is equal to non-existent variable', 'S == V', 0, 1)
end)
end)

10
test/functional/eval/writefile_spec.lua

@ -59,6 +59,16 @@ describe('writefile()', function()
eq('\n', read_file(fname))
end)
it('writes list with a null string to a file', function()
eq(0, exc_exec(
('call writefile([v:_null_string], "%s", "b")'):format(
fname)))
eq('', read_file(fname))
eq(0, exc_exec(('call writefile([v:_null_string], "%s")'):format(
fname)))
eq('\n', read_file(fname))
end)
it('appends to a file', function()
eq(nil, read_file(fname))
eq(0, funcs.writefile({'abc', 'def', 'ghi'}, fname))

Loading…
Cancel
Save