summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2023-09-24 23:13:51 +0200
committerChristian Brabandt <cb@256bit.org>2023-09-24 23:13:51 +0200
commitedcba96c0088210927558b0e2583f3b689f457c4 (patch)
tree615328c8c06bfd48a79098e7045c3998856b2d7f
parent7398f367d5125eedfb4058c63a5d167fe8601e3d (diff)
patch 9.0.1933: Can change the type of a v: variable using if_luav9.0.1933
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 <cb@256bit.org> Co-authored-by: zeertzjq <zeertzjq@outlook.com>
-rw-r--r--src/errors.h4
-rw-r--r--src/evalvars.c106
-rw-r--r--src/if_lua.c10
-rw-r--r--src/proto/evalvars.pro1
-rw-r--r--src/testdir/test_lua.vim56
-rw-r--r--src/version.c2
6 files changed, 117 insertions, 62 deletions
diff --git a/src/errors.h b/src/errors.h
index 40e16f1c0d..361a5761eb 100644
--- a/src/errors.h
+++ b/src/errors.h
@@ -2520,8 +2520,8 @@ EXTERN char e_no_line_number_to_use_for_sflnum[]
INIT(= N_("E961: No line number to use for \"<sflnum>\""));
EXTERN char e_invalid_action_str_2[]
INIT(= N_("E962: Invalid action: '%s'"));
-EXTERN char e_setting_str_to_value_with_wrong_type[]
- INIT(= N_("E963: Setting %s to value with wrong type"));
+EXTERN char e_setting_v_str_to_value_with_wrong_type[]
+ INIT(= N_("E963: Setting v:%s to value with wrong type"));
#endif
#ifdef FEAT_PROP_POPUP
EXTERN char_u e_invalid_column_number_nr[]
diff --git a/src/evalvars.c b/src/evalvars.c
index bd096dfd7b..2438993942 100644
--- a/src/evalvars.c
+++ b/src/evalvars.c
@@ -3673,6 +3673,62 @@ list_one_var_a(
}
/*
+ * Addition handling for setting a v: variable.
+ * Return TRUE if the variable should be set normally,
+ * FALSE if nothing else needs to be done.
+ */
+ int
+before_set_vvar(
+ char_u *varname,
+ dictitem_T *di,
+ typval_T *tv,
+ int copy,
+ int *type_error)
+{
+ if (di->di_tv.v_type == VAR_STRING)
+ {
+ VIM_CLEAR(di->di_tv.vval.v_string);
+ if (copy || tv->v_type != VAR_STRING)
+ {
+ char_u *val = tv_get_string(tv);
+
+ // Careful: when assigning to v:errmsg and
+ // tv_get_string() causes an error message the variable
+ // will already be set.
+ if (di->di_tv.vval.v_string == NULL)
+ di->di_tv.vval.v_string = vim_strsave(val);
+ }
+ else
+ {
+ // Take over the string to avoid an extra alloc/free.
+ di->di_tv.vval.v_string = tv->vval.v_string;
+ tv->vval.v_string = NULL;
+ }
+ return FALSE;
+ }
+ else if (di->di_tv.v_type == VAR_NUMBER)
+ {
+ di->di_tv.vval.v_number = tv_get_number(tv);
+ if (STRCMP(varname, "searchforward") == 0)
+ set_search_direction(di->di_tv.vval.v_number ? '/' : '?');
+#ifdef FEAT_SEARCH_EXTRA
+ else if (STRCMP(varname, "hlsearch") == 0)
+ {
+ no_hlsearch = !di->di_tv.vval.v_number;
+ redraw_all_later(UPD_SOME_VALID);
+ }
+#endif
+ return FALSE;
+ }
+ else if (di->di_tv.v_type != tv->v_type)
+ {
+ *type_error = TRUE;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*
* Set variable "name" to value in "tv".
* If the variable already exists, the value is updated.
* Otherwise the variable is created.
@@ -3877,51 +3933,15 @@ set_var_const(
// existing variable, need to clear the value
- // Handle setting internal di: variables separately where needed to
+ // Handle setting internal v: variables separately where needed to
// prevent changing the type.
- if (ht == &vimvarht)
+ int type_error = FALSE;
+ if (ht == &vimvarht
+ && !before_set_vvar(varname, di, tv, copy, &type_error))
{
- if (di->di_tv.v_type == VAR_STRING)
- {
- VIM_CLEAR(di->di_tv.vval.v_string);
- if (copy || tv->v_type != VAR_STRING)
- {
- char_u *val = tv_get_string(tv);
-
- // Careful: when assigning to v:errmsg and
- // tv_get_string() causes an error message the variable
- // will already be set.
- if (di->di_tv.vval.v_string == NULL)
- di->di_tv.vval.v_string = vim_strsave(val);
- }
- else
- {
- // Take over the string to avoid an extra alloc/free.
- di->di_tv.vval.v_string = tv->vval.v_string;
- tv->vval.v_string = NULL;
- }
- goto failed;
- }
- else if (di->di_tv.v_type == VAR_NUMBER)
- {
- di->di_tv.vval.v_number = tv_get_number(tv);
- if (STRCMP(varname, "searchforward") == 0)
- set_search_direction(di->di_tv.vval.v_number
- ? '/' : '?');
-#ifdef FEAT_SEARCH_EXTRA
- else if (STRCMP(varname, "hlsearch") == 0)
- {
- no_hlsearch = !di->di_tv.vval.v_number;
- redraw_all_later(UPD_SOME_VALID);
- }
-#endif
- goto failed;
- }
- else if (di->di_tv.v_type != tv->v_type)
- {
- semsg(_(e_setting_str_to_value_with_wrong_type), name);
- goto failed;
- }
+ if (type_error)
+ semsg(_(e_setting_v_str_to_value_with_wrong_type), varname);
+ goto failed;
}
clear_tv(&di->di_tv);
diff --git a/src/if_lua.c b/src/if_lua.c
index 2041f5bccc..65d265f388 100644
--- a/src/if_lua.c
+++ b/src/if_lua.c
@@ -1900,6 +1900,16 @@ luaV_setvar(lua_State *L)
}
else
{
+ int type_error = FALSE;
+ if (dict == get_vimvar_dict()
+ && !before_set_vvar((char_u *)name, di, &tv, TRUE, &type_error))
+ {
+ clear_tv(&tv);
+ if (type_error)
+ return luaL_error(L,
+ "Setting v:%s to value with wrong type", name);
+ return 0;
+ }
// Clear the old value
clear_tv(&di->di_tv);
// Update the value
diff --git a/src/proto/evalvars.pro b/src/proto/evalvars.pro
index 661cb5974d..9879a401f2 100644
--- a/src/proto/evalvars.pro
+++ b/src/proto/evalvars.pro
@@ -75,6 +75,7 @@ void unref_var_dict(dict_T *dict);
void vars_clear(hashtab_T *ht);
void vars_clear_ext(hashtab_T *ht, int free_val);
void delete_var(hashtab_T *ht, hashitem_T *hi);
+int before_set_vvar(char_u *varname, dictitem_T *di, typval_T *tv, int copy, int *type_error);
void set_var(char_u *name, typval_T *tv, int copy);
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);
int var_check_permission(dictitem_T *di, char_u *name);
diff --git a/src/testdir/test_lua.vim b/src/testdir/test_lua.vim
index dd95e9fb52..7e72728289 100644
--- a/src/testdir/test_lua.vim
+++ b/src/testdir/test_lua.vim
@@ -970,9 +970,9 @@ func Test_lua_global_var_table()
let g:Var1 = [10, 20]
let g:Var2 = #{one: 'mercury', two: 'mars'}
lua << trim END
- vim.g.Var1[2] = Nil
+ vim.g.Var1[2] = nil
vim.g.Var1[3] = 15
- vim.g.Var2['two'] = Nil
+ vim.g.Var2['two'] = nil
vim.g.Var2['three'] = 'earth'
END
call assert_equal([10, 15], g:Var1)
@@ -985,11 +985,11 @@ func Test_lua_global_var_table()
let g:Var4 = #{x: 'edit', y: 'run'}
let g:Var5 = function('min')
lua << trim END
- vim.g.Var1 = Nil
- vim.g.Var2 = Nil
- vim.g.Var3 = Nil
- vim.g.Var4 = Nil
- vim.g.Var5 = Nil
+ vim.g.Var1 = nil
+ vim.g.Var2 = nil
+ vim.g.Var3 = nil
+ vim.g.Var4 = nil
+ vim.g.Var5 = nil
END
call assert_false(exists('g:Var1'))
call assert_false(exists('g:Var2'))
@@ -1001,16 +1001,16 @@ func Test_lua_global_var_table()
let g:Var1 = 10
lockvar g:Var1
call assert_fails('lua vim.g.Var1 = 20', 'variable is locked')
- call assert_fails('lua vim.g.Var1 = Nil', 'variable is locked')
+ call assert_fails('lua vim.g.Var1 = nil', 'variable is locked')
unlockvar g:Var1
let g:Var2 = [7, 14]
lockvar 0 g:Var2
- lua vim.g.Var2[2] = Nil
+ lua vim.g.Var2[2] = nil
lua vim.g.Var2[3] = 21
- call assert_fails('lua vim.g.Var2 = Nil', 'variable is locked')
+ call assert_fails('lua vim.g.Var2 = nil', 'variable is locked')
call assert_equal([7, 21], g:Var2)
lockvar 1 g:Var2
- call assert_fails('lua vim.g.Var2[2] = Nil', 'list is locked')
+ call assert_fails('lua vim.g.Var2[2] = nil', 'list is locked')
call assert_fails('lua vim.g.Var2[3] = 21', 'list is locked')
unlockvar g:Var2
@@ -1020,7 +1020,7 @@ func Test_lua_global_var_table()
" Attempt to access a non-existing global variable
call assert_equal(v:null, luaeval('vim.g.NonExistingVar'))
- lua vim.g.NonExisting = Nil
+ lua vim.g.NonExisting = nil
unlet! g:Var1 g:Var2 g:Var3 g:Var4 g:Var5
endfunc
@@ -1033,14 +1033,36 @@ func Test_lua_predefined_var_table()
call assert_equal('SomeError', luaeval('vim.v.errmsg'))
lua vim.v.errmsg = 'OtherError'
call assert_equal('OtherError', v:errmsg)
- call assert_fails('lua vim.v.errmsg = Nil', 'variable is fixed')
+ lua vim.v.errmsg = 42
+ call assert_equal('42', v:errmsg)
+ call assert_fails('lua vim.v.errmsg = nil', 'variable is fixed')
let v:oldfiles = ['one', 'two']
call assert_equal(['one', 'two'], luaeval('vim.v.oldfiles'))
lua vim.v.oldfiles = vim.list({})
call assert_equal([], v:oldfiles)
+ call assert_fails('lua vim.v.oldfiles = "a"',
+ \ 'Setting v:oldfiles to value with wrong type')
+ call assert_equal([], v:oldfiles)
call assert_equal(v:null, luaeval('vim.v.null'))
- call assert_fails('lua vim.v.argv[1] = Nil', 'list is locked')
+ call assert_fails('lua vim.v.argv[1] = nil', 'list is locked')
call assert_fails('lua vim.v.newvar = 1', 'Dictionary is locked')
+
+ new
+ call setline(1, ' foo foo foo')
+ /foo
+ call assert_equal([0, 1, 2, 0, 2], getcurpos())
+ call assert_equal(1, v:searchforward)
+ normal! n
+ call assert_equal([0, 1, 6, 0, 6], getcurpos())
+ lua vim.v.searchforward = 0
+ call assert_equal(0, v:searchforward)
+ normal! n
+ call assert_equal([0, 1, 2, 0, 2], getcurpos())
+ lua vim.v.searchforward = 1
+ call assert_equal(1, v:searchforward)
+ normal! n
+ call assert_equal([0, 1, 6, 0, 6], getcurpos())
+ bwipe!
endfunc
" Test for adding, accessing and modifying window-local variables using the
@@ -1076,7 +1098,7 @@ func Test_lua_window_var_table()
call assert_equal(#{a: [1, 2], b: 20}, w:wvar7)
" delete a window variable
- lua vim.w.wvar2 = Nil
+ lua vim.w.wvar2 = nil
call assert_false(exists('w:wvar2'))
new
@@ -1117,7 +1139,7 @@ func Test_lua_buffer_var_table()
call assert_equal(#{a: [1, 2], b: 20}, b:bvar7)
" delete a buffer variable
- lua vim.b.bvar2 = Nil
+ lua vim.b.bvar2 = nil
call assert_false(exists('b:bvar2'))
new
@@ -1158,7 +1180,7 @@ func Test_lua_tabpage_var_table()
call assert_equal(#{a: [1, 2], b: 20}, t:tvar7)
" delete a tabpage variable
- lua vim.t.tvar2 = Nil
+ lua vim.t.tvar2 = nil
call assert_false(exists('t:tvar2'))
tabnew
diff --git a/src/version.c b/src/version.c
index 6166111ac7..31c1727007 100644
--- a/src/version.c
+++ b/src/version.c
@@ -700,6 +700,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1933,
+/**/
1932,
/**/
1931,