patch 9.0.1933: Can change the type of a v: variable using if_lua

Commit: 
https://github.com/vim/vim/commit/edcba96c0088210927558b0e2583f3b689f457c4
Author: zeertzjq <zeert...@outlook.com>
Date:   Sun Sep 24 23:13:51 2023 +0200

    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 <c...@256bit.org>
    Co-authored-by: zeertzjq <zeert...@outlook.com>

diff --git a/src/errors.h b/src/errors.h
index 40e16f1c0..361a5761e 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 bd096dfd7..243899394 100644
--- a/src/evalvars.c
+++ b/src/evalvars.c
@@ -3672,6 +3672,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.
@@ -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 2041f5bcc..65d265f38 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 661cb5974..9879a401f 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 dd95e9fb5..7e7272828 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 6166111ac..31c172700 100644
--- a/src/version.c
+++ b/src/version.c
@@ -699,6 +699,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1933,
 /**/
     1932,
 /**/

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to vim_dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/E1qkWfz-00A2sa-9i%40256bit.org.

Raspunde prin e-mail lui