Skip to content

Commit edcba96

Browse files
zeertzjqchrisbra
authored andcommitted
patch 9.0.1933: Can change the type of a v: variable using if_lua
Problem: Can change the type of a v: variable using if_lua. Solution: Add additional handling of v: variables like :let. closes: #13161 Signed-off-by: Christian Brabandt <[email protected]> Co-authored-by: zeertzjq <[email protected]>
1 parent 7398f36 commit edcba96

6 files changed

Lines changed: 117 additions & 62 deletions

File tree

src/errors.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2520,8 +2520,8 @@ EXTERN char e_no_line_number_to_use_for_sflnum[]
25202520
INIT(= N_("E961: No line number to use for \"<sflnum>\""));
25212521
EXTERN char e_invalid_action_str_2[]
25222522
INIT(= N_("E962: Invalid action: '%s'"));
2523-
EXTERN char e_setting_str_to_value_with_wrong_type[]
2524-
INIT(= N_("E963: Setting %s to value with wrong type"));
2523+
EXTERN char e_setting_v_str_to_value_with_wrong_type[]
2524+
INIT(= N_("E963: Setting v:%s to value with wrong type"));
25252525
#endif
25262526
#ifdef FEAT_PROP_POPUP
25272527
EXTERN char_u e_invalid_column_number_nr[]

src/evalvars.c

Lines changed: 63 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -3672,6 +3672,62 @@ list_one_var_a(
36723672
}
36733673
}
36743674

3675+
/*
3676+
* Addition handling for setting a v: variable.
3677+
* Return TRUE if the variable should be set normally,
3678+
* FALSE if nothing else needs to be done.
3679+
*/
3680+
int
3681+
before_set_vvar(
3682+
char_u *varname,
3683+
dictitem_T *di,
3684+
typval_T *tv,
3685+
int copy,
3686+
int *type_error)
3687+
{
3688+
if (di->di_tv.v_type == VAR_STRING)
3689+
{
3690+
VIM_CLEAR(di->di_tv.vval.v_string);
3691+
if (copy || tv->v_type != VAR_STRING)
3692+
{
3693+
char_u *val = tv_get_string(tv);
3694+
3695+
// Careful: when assigning to v:errmsg and
3696+
// tv_get_string() causes an error message the variable
3697+
// will already be set.
3698+
if (di->di_tv.vval.v_string == NULL)
3699+
di->di_tv.vval.v_string = vim_strsave(val);
3700+
}
3701+
else
3702+
{
3703+
// Take over the string to avoid an extra alloc/free.
3704+
di->di_tv.vval.v_string = tv->vval.v_string;
3705+
tv->vval.v_string = NULL;
3706+
}
3707+
return FALSE;
3708+
}
3709+
else if (di->di_tv.v_type == VAR_NUMBER)
3710+
{
3711+
di->di_tv.vval.v_number = tv_get_number(tv);
3712+
if (STRCMP(varname, "searchforward") == 0)
3713+
set_search_direction(di->di_tv.vval.v_number ? '/' : '?');
3714+
#ifdef FEAT_SEARCH_EXTRA
3715+
else if (STRCMP(varname, "hlsearch") == 0)
3716+
{
3717+
no_hlsearch = !di->di_tv.vval.v_number;
3718+
redraw_all_later(UPD_SOME_VALID);
3719+
}
3720+
#endif
3721+
return FALSE;
3722+
}
3723+
else if (di->di_tv.v_type != tv->v_type)
3724+
{
3725+
*type_error = TRUE;
3726+
return FALSE;
3727+
}
3728+
return TRUE;
3729+
}
3730+
36753731
/*
36763732
* Set variable "name" to value in "tv".
36773733
* If the variable already exists, the value is updated.
@@ -3877,51 +3933,15 @@ set_var_const(
38773933

38783934
// existing variable, need to clear the value
38793935

3880-
// Handle setting internal di: variables separately where needed to
3936+
// Handle setting internal v: variables separately where needed to
38813937
// prevent changing the type.
3882-
if (ht == &vimvarht)
3938+
int type_error = FALSE;
3939+
if (ht == &vimvarht
3940+
&& !before_set_vvar(varname, di, tv, copy, &type_error))
38833941
{
3884-
if (di->di_tv.v_type == VAR_STRING)
3885-
{
3886-
VIM_CLEAR(di->di_tv.vval.v_string);
3887-
if (copy || tv->v_type != VAR_STRING)
3888-
{
3889-
char_u *val = tv_get_string(tv);
3890-
3891-
// Careful: when assigning to v:errmsg and
3892-
// tv_get_string() causes an error message the variable
3893-
// will already be set.
3894-
if (di->di_tv.vval.v_string == NULL)
3895-
di->di_tv.vval.v_string = vim_strsave(val);
3896-
}
3897-
else
3898-
{
3899-
// Take over the string to avoid an extra alloc/free.
3900-
di->di_tv.vval.v_string = tv->vval.v_string;
3901-
tv->vval.v_string = NULL;
3902-
}
3903-
goto failed;
3904-
}
3905-
else if (di->di_tv.v_type == VAR_NUMBER)
3906-
{
3907-
di->di_tv.vval.v_number = tv_get_number(tv);
3908-
if (STRCMP(varname, "searchforward") == 0)
3909-
set_search_direction(di->di_tv.vval.v_number
3910-
? '/' : '?');
3911-
#ifdef FEAT_SEARCH_EXTRA
3912-
else if (STRCMP(varname, "hlsearch") == 0)
3913-
{
3914-
no_hlsearch = !di->di_tv.vval.v_number;
3915-
redraw_all_later(UPD_SOME_VALID);
3916-
}
3917-
#endif
3918-
goto failed;
3919-
}
3920-
else if (di->di_tv.v_type != tv->v_type)
3921-
{
3922-
semsg(_(e_setting_str_to_value_with_wrong_type), name);
3923-
goto failed;
3924-
}
3942+
if (type_error)
3943+
semsg(_(e_setting_v_str_to_value_with_wrong_type), varname);
3944+
goto failed;
39253945
}
39263946

39273947
clear_tv(&di->di_tv);

src/if_lua.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1900,6 +1900,16 @@ luaV_setvar(lua_State *L)
19001900
}
19011901
else
19021902
{
1903+
int type_error = FALSE;
1904+
if (dict == get_vimvar_dict()
1905+
&& !before_set_vvar((char_u *)name, di, &tv, TRUE, &type_error))
1906+
{
1907+
clear_tv(&tv);
1908+
if (type_error)
1909+
return luaL_error(L,
1910+
"Setting v:%s to value with wrong type", name);
1911+
return 0;
1912+
}
19031913
// Clear the old value
19041914
clear_tv(&di->di_tv);
19051915
// Update the value

src/proto/evalvars.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ void unref_var_dict(dict_T *dict);
7575
void vars_clear(hashtab_T *ht);
7676
void vars_clear_ext(hashtab_T *ht, int free_val);
7777
void delete_var(hashtab_T *ht, hashitem_T *hi);
78+
int before_set_vvar(char_u *varname, dictitem_T *di, typval_T *tv, int copy, int *type_error);
7879
void set_var(char_u *name, typval_T *tv, int copy);
7980
void set_var_const(char_u *name, scid_T sid, type_T *type_arg, typval_T *tv_arg, int copy, int flags_arg, int var_idx);
8081
int var_check_permission(dictitem_T *di, char_u *name);

src/testdir/test_lua.vim

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -970,9 +970,9 @@ func Test_lua_global_var_table()
970970
let g:Var1 = [10, 20]
971971
let g:Var2 = #{one: 'mercury', two: 'mars'}
972972
lua << trim END
973-
vim.g.Var1[2] = Nil
973+
vim.g.Var1[2] = nil
974974
vim.g.Var1[3] = 15
975-
vim.g.Var2['two'] = Nil
975+
vim.g.Var2['two'] = nil
976976
vim.g.Var2['three'] = 'earth'
977977
END
978978
call assert_equal([10, 15], g:Var1)
@@ -985,11 +985,11 @@ func Test_lua_global_var_table()
985985
let g:Var4 = #{x: 'edit', y: 'run'}
986986
let g:Var5 = function('min')
987987
lua << trim END
988-
vim.g.Var1 = Nil
989-
vim.g.Var2 = Nil
990-
vim.g.Var3 = Nil
991-
vim.g.Var4 = Nil
992-
vim.g.Var5 = Nil
988+
vim.g.Var1 = nil
989+
vim.g.Var2 = nil
990+
vim.g.Var3 = nil
991+
vim.g.Var4 = nil
992+
vim.g.Var5 = nil
993993
END
994994
call assert_false(exists('g:Var1'))
995995
call assert_false(exists('g:Var2'))
@@ -1001,16 +1001,16 @@ func Test_lua_global_var_table()
10011001
let g:Var1 = 10
10021002
lockvar g:Var1
10031003
call assert_fails('lua vim.g.Var1 = 20', 'variable is locked')
1004-
call assert_fails('lua vim.g.Var1 = Nil', 'variable is locked')
1004+
call assert_fails('lua vim.g.Var1 = nil', 'variable is locked')
10051005
unlockvar g:Var1
10061006
let g:Var2 = [7, 14]
10071007
lockvar 0 g:Var2
1008-
lua vim.g.Var2[2] = Nil
1008+
lua vim.g.Var2[2] = nil
10091009
lua vim.g.Var2[3] = 21
1010-
call assert_fails('lua vim.g.Var2 = Nil', 'variable is locked')
1010+
call assert_fails('lua vim.g.Var2 = nil', 'variable is locked')
10111011
call assert_equal([7, 21], g:Var2)
10121012
lockvar 1 g:Var2
1013-
call assert_fails('lua vim.g.Var2[2] = Nil', 'list is locked')
1013+
call assert_fails('lua vim.g.Var2[2] = nil', 'list is locked')
10141014
call assert_fails('lua vim.g.Var2[3] = 21', 'list is locked')
10151015
unlockvar g:Var2
10161016

@@ -1020,7 +1020,7 @@ func Test_lua_global_var_table()
10201020

10211021
" Attempt to access a non-existing global variable
10221022
call assert_equal(v:null, luaeval('vim.g.NonExistingVar'))
1023-
lua vim.g.NonExisting = Nil
1023+
lua vim.g.NonExisting = nil
10241024

10251025
unlet! g:Var1 g:Var2 g:Var3 g:Var4 g:Var5
10261026
endfunc
@@ -1033,14 +1033,36 @@ func Test_lua_predefined_var_table()
10331033
call assert_equal('SomeError', luaeval('vim.v.errmsg'))
10341034
lua vim.v.errmsg = 'OtherError'
10351035
call assert_equal('OtherError', v:errmsg)
1036-
call assert_fails('lua vim.v.errmsg = Nil', 'variable is fixed')
1036+
lua vim.v.errmsg = 42
1037+
call assert_equal('42', v:errmsg)
1038+
call assert_fails('lua vim.v.errmsg = nil', 'variable is fixed')
10371039
let v:oldfiles = ['one', 'two']
10381040
call assert_equal(['one', 'two'], luaeval('vim.v.oldfiles'))
10391041
lua vim.v.oldfiles = vim.list({})
10401042
call assert_equal([], v:oldfiles)
1043+
call assert_fails('lua vim.v.oldfiles = "a"',
1044+
\ 'Setting v:oldfiles to value with wrong type')
1045+
call assert_equal([], v:oldfiles)
10411046
call assert_equal(v:null, luaeval('vim.v.null'))
1042-
call assert_fails('lua vim.v.argv[1] = Nil', 'list is locked')
1047+
call assert_fails('lua vim.v.argv[1] = nil', 'list is locked')
10431048
call assert_fails('lua vim.v.newvar = 1', 'Dictionary is locked')
1049+
1050+
new
1051+
call setline(1, ' foo foo foo')
1052+
/foo
1053+
call assert_equal([0, 1, 2, 0, 2], getcurpos())
1054+
call assert_equal(1, v:searchforward)
1055+
normal! n
1056+
call assert_equal([0, 1, 6, 0, 6], getcurpos())
1057+
lua vim.v.searchforward = 0
1058+
call assert_equal(0, v:searchforward)
1059+
normal! n
1060+
call assert_equal([0, 1, 2, 0, 2], getcurpos())
1061+
lua vim.v.searchforward = 1
1062+
call assert_equal(1, v:searchforward)
1063+
normal! n
1064+
call assert_equal([0, 1, 6, 0, 6], getcurpos())
1065+
bwipe!
10441066
endfunc
10451067

10461068
" Test for adding, accessing and modifying window-local variables using the
@@ -1076,7 +1098,7 @@ func Test_lua_window_var_table()
10761098
call assert_equal(#{a: [1, 2], b: 20}, w:wvar7)
10771099

10781100
" delete a window variable
1079-
lua vim.w.wvar2 = Nil
1101+
lua vim.w.wvar2 = nil
10801102
call assert_false(exists('w:wvar2'))
10811103

10821104
new
@@ -1117,7 +1139,7 @@ func Test_lua_buffer_var_table()
11171139
call assert_equal(#{a: [1, 2], b: 20}, b:bvar7)
11181140

11191141
" delete a buffer variable
1120-
lua vim.b.bvar2 = Nil
1142+
lua vim.b.bvar2 = nil
11211143
call assert_false(exists('b:bvar2'))
11221144

11231145
new
@@ -1158,7 +1180,7 @@ func Test_lua_tabpage_var_table()
11581180
call assert_equal(#{a: [1, 2], b: 20}, t:tvar7)
11591181

11601182
" delete a tabpage variable
1161-
lua vim.t.tvar2 = Nil
1183+
lua vim.t.tvar2 = nil
11621184
call assert_false(exists('t:tvar2'))
11631185

11641186
tabnew

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,8 @@ static char *(features[]) =
699699

700700
static int included_patches[] =
701701
{ /* Add new patch number below this line */
702+
/**/
703+
1933,
702704
/**/
703705
1932,
704706
/**/

0 commit comments

Comments
 (0)