changeset 28684:6d55e6c9cdb5 v8.2.4866

patch 8.2.4866: duplicate code in "get" functions Commit: https://github.com/vim/vim/commit/47d4e317f85e4aeb3799d962f173bd0f1e7bc71c Author: LemonBoy <thatlemon@gmail.com> Date: Wed May 4 18:12:55 2022 +0100 patch 8.2.4866: duplicate code in "get" functions Problem: Duplicate code in "get" functions. Solution: Use get_var_from() for getwinvar(), gettabvar(), gettabwinvar() and getbufvar(). (closes #10335)
author Bram Moolenaar <Bram@vim.org>
date Wed, 04 May 2022 19:15:03 +0200
parents ce2bb6d9b763
children 9d93cac8b406
files src/evalvars.c src/version.c
diffstat 2 files changed, 87 insertions(+), 111 deletions(-) [+]
line wrap: on
line diff
--- a/src/evalvars.c
+++ b/src/evalvars.c
@@ -4036,48 +4036,53 @@ valid_varname(char_u *varname, int len, 
 }
 
 /*
- * getwinvar() and gettabwinvar()
+ * Implements the logic to retrieve local variable and option values.
+ * Used by "getwinvar()" "gettabvar()" "gettabwinvar()" "getbufvar()".
  */
     static void
-getwinvar(
-    typval_T	*argvars,
+get_var_from(
+    char_u	*varname,
     typval_T	*rettv,
-    int		off)	    // 1 for gettabwinvar()
+    typval_T	*deftv,	    // Default value if not found.
+    int		htname,	    // 't'ab, 'w'indow or 'b'uffer local.
+    tabpage_T	*tp,	    // can be NULL
+    win_T	*win,
+    buf_T	*buf)	    // Ignored if htname is not 'b'.
 {
-    win_T	*win;
-    char_u	*varname;
     dictitem_T	*v;
-    tabpage_T	*tp = NULL;
     int		done = FALSE;
     switchwin_T	switchwin;
     int		need_switch_win;
 
-    if (off == 1)
-	tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
-    else
-	tp = curtab;
-    win = find_win_by_nr(&argvars[off], tp);
-    varname = tv_get_string_chk(&argvars[off + 1]);
     ++emsg_off;
 
     rettv->v_type = VAR_STRING;
     rettv->vval.v_string = NULL;
 
-    if (win != NULL && varname != NULL)
+    if (varname != NULL && tp != NULL && win != NULL
+	    && (htname != 'b' || buf != NULL))
     {
 	// Set curwin to be our win, temporarily.  Also set the tabpage,
 	// otherwise the window is not valid. Only do this when needed,
 	// autocommands get blocked.
-	need_switch_win = !(tp == curtab && win == curwin);
-	if (!need_switch_win
-		  || switch_win(&switchwin, win, tp, TRUE) == OK)
+	// If we have a buffer reference avoid the switching, we're saving and
+	// restoring curbuf directly.
+	need_switch_win = !(tp == curtab && win == curwin) || (buf != NULL);
+	if (!need_switch_win || switch_win(&switchwin, win, tp, TRUE) == OK)
 	{
-	    if (*varname == '&')
+	    // Handle options. There are no tab-local options.
+	    if (*varname == '&' && htname != 't')
 	    {
+		buf_T	*save_curbuf = curbuf;
+
+		// Change curbuf so the option is read from the correct buffer.
+		if (buf != NULL && htname == 'b')
+		    curbuf = buf;
+
 		if (varname[1] == NUL)
 		{
 		    // get all window-local options in a dict
-		    dict_T	*opts = get_winbuf_options(FALSE);
+		    dict_T	*opts = get_winbuf_options(htname == 'b');
 
 		    if (opts != NULL)
 		    {
@@ -4085,16 +4090,37 @@ getwinvar(
 			done = TRUE;
 		    }
 		}
-		else if (eval_option(&varname, rettv, 1) == OK)
-		    // window-local-option
+		else if (eval_option(&varname, rettv, TRUE) == OK)
+		    // Local option
 		    done = TRUE;
+
+		curbuf = save_curbuf;
+	    }
+	    else if (*varname == NUL)
+	    {
+		// Empty string: return a dict with all the local variables.
+		if (htname == 'b')
+		    v = &buf->b_bufvar;
+		else if (htname == 'w')
+		    v = &win->w_winvar;
+		else
+		    v = &tp->tp_winvar;
+		copy_tv(&v->di_tv, rettv);
+		done = TRUE;
 	    }
 	    else
 	    {
+		hashtab_T	*ht;
+
+		if (htname == 'b')
+		    ht = &buf->b_vars->dv_hashtab;
+		else if (htname == 'w')
+		    ht = &win->w_vars->dv_hashtab;
+		else
+		    ht = &tp->tp_vars->dv_hashtab;
+
 		// Look up the variable.
-		// Let getwinvar({nr}, "") return the "w:" dictionary.
-		v = find_var_in_ht(&win->w_vars->dv_hashtab, 'w',
-							      varname, FALSE);
+		v = find_var_in_ht(ht, htname, varname, FALSE);
 		if (v != NULL)
 		{
 		    copy_tv(&v->di_tv, rettv);
@@ -4108,14 +4134,37 @@ getwinvar(
 	    restore_win(&switchwin, TRUE);
     }
 
-    if (!done && argvars[off + 2].v_type != VAR_UNKNOWN)
-	// use the default return value
-	copy_tv(&argvars[off + 2], rettv);
+    if (!done && deftv->v_type != VAR_UNKNOWN)
+	// use the default value
+	copy_tv(deftv, rettv);
 
     --emsg_off;
 }
 
 /*
+ * getwinvar() and gettabwinvar()
+ */
+    static void
+getwinvar(
+    typval_T	*argvars,
+    typval_T	*rettv,
+    int		off)	    // 1 for gettabwinvar()
+{
+    char_u	*varname;
+    tabpage_T	*tp;
+    win_T	*win;
+
+    if (off == 1)
+	tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
+    else
+	tp = curtab;
+    win = find_win_by_nr(&argvars[off], tp);
+    varname = tv_get_string_chk(&argvars[off + 1]);
+
+    get_var_from(varname, rettv, &argvars[off + 2], 'w', tp, win, NULL);
+}
+
+/*
  * Set option "varname" to the value of "varp" for the current buffer/window.
  */
     static void
@@ -4444,14 +4493,9 @@ get_clear_redir_ga(void)
     void
 f_gettabvar(typval_T *argvars, typval_T *rettv)
 {
-    switchwin_T	switchwin;
+    char_u	*varname;
     tabpage_T	*tp;
-    dictitem_T	*v;
-    char_u	*varname;
-    int		done = FALSE;
-
-    rettv->v_type = VAR_STRING;
-    rettv->vval.v_string = NULL;
+    win_T	*win = NULL;
 
     if (in_vim9script()
 	    && (check_for_number_arg(argvars, 0) == FAIL
@@ -4460,30 +4504,11 @@ f_gettabvar(typval_T *argvars, typval_T 
 
     varname = tv_get_string_chk(&argvars[1]);
     tp = find_tabpage((int)tv_get_number_chk(&argvars[0], NULL));
-    if (tp != NULL && varname != NULL)
-    {
-	// Set tp to be our tabpage, temporarily.  Also set the window to the
-	// first window in the tabpage, otherwise the window is not valid.
-	if (switch_win(&switchwin,
-		tp == curtab || tp->tp_firstwin == NULL ? firstwin
-					    : tp->tp_firstwin, tp, TRUE) == OK)
-	{
-	    // look up the variable
-	    // Let gettabvar({nr}, "") return the "t:" dictionary.
-	    v = find_var_in_ht(&tp->tp_vars->dv_hashtab, 't', varname, FALSE);
-	    if (v != NULL)
-	    {
-		copy_tv(&v->di_tv, rettv);
-		done = TRUE;
-	    }
-	}
-
-	// restore previous notion of curwin
-	restore_win(&switchwin, TRUE);
-    }
-
-    if (!done && argvars[2].v_type != VAR_UNKNOWN)
-	copy_tv(&argvars[2], rettv);
+    if (tp != NULL)
+	win = tp == curtab || tp->tp_firstwin == NULL ? firstwin
+		: tp->tp_firstwin;
+
+    get_var_from(varname, rettv, &argvars[2], 't', tp, win, NULL);
 }
 
 /*
@@ -4521,10 +4546,8 @@ f_getwinvar(typval_T *argvars, typval_T 
     void
 f_getbufvar(typval_T *argvars, typval_T *rettv)
 {
+    char_u	*varname;
     buf_T	*buf;
-    char_u	*varname;
-    dictitem_T	*v;
-    int		done = FALSE;
 
     if (in_vim9script()
 	    && (check_for_buffer_arg(argvars, 0) == FAIL
@@ -4534,56 +4557,7 @@ f_getbufvar(typval_T *argvars, typval_T 
     varname = tv_get_string_chk(&argvars[1]);
     buf = tv_get_buf_from_arg(&argvars[0]);
 
-    rettv->v_type = VAR_STRING;
-    rettv->vval.v_string = NULL;
-
-    if (buf != NULL && varname != NULL)
-    {
-	if (*varname == '&')
-	{
-	    buf_T	*save_curbuf = curbuf;
-
-	    // set curbuf to be our buf, temporarily
-	    curbuf = buf;
-
-	    if (varname[1] == NUL)
-	    {
-		// get all buffer-local options in a dict
-		dict_T	*opts = get_winbuf_options(TRUE);
-
-		if (opts != NULL)
-		{
-		    rettv_dict_set(rettv, opts);
-		    done = TRUE;
-		}
-	    }
-	    else if (eval_option(&varname, rettv, TRUE) == OK)
-		// buffer-local-option
-		done = TRUE;
-
-	    // restore previous notion of curbuf
-	    curbuf = save_curbuf;
-	}
-	else
-	{
-	    // Look up the variable.
-	    if (*varname == NUL)
-		// Let getbufvar({nr}, "") return the "b:" dictionary.
-		v = &buf->b_bufvar;
-	    else
-		v = find_var_in_ht(&buf->b_vars->dv_hashtab, 'b',
-							       varname, FALSE);
-	    if (v != NULL)
-	    {
-		copy_tv(&v->di_tv, rettv);
-		done = TRUE;
-	    }
-	}
-    }
-
-    if (!done && argvars[2].v_type != VAR_UNKNOWN)
-	// use the default value
-	copy_tv(&argvars[2], rettv);
+    get_var_from(varname, rettv, &argvars[2], 'b', curtab, curwin, buf);
 }
 
 /*
--- a/src/version.c
+++ b/src/version.c
@@ -747,6 +747,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    4866,
+/**/
     4865,
 /**/
     4864,