]> granicus.if.org Git - vim/commitdiff
patch 8.1.1372: when evaluating 'statusline' the current window is unknown v8.1.1372
authorBram Moolenaar <Bram@vim.org>
Thu, 23 May 2019 20:11:59 +0000 (22:11 +0200)
committerBram Moolenaar <Bram@vim.org>
Thu, 23 May 2019 20:11:59 +0000 (22:11 +0200)
Problem:    When evaluating 'statusline' the current window is unknown.
            (Daniel Hahler)
Solution:   Set "g:actual_curwin" for %{} items.  Set "g:statusline_winid"
            when evaluationg %!. (closes #4406, closes #3299)

runtime/doc/options.txt
src/buffer.c
src/testdir/test_statusline.vim
src/version.c

index 53d72b38c174457c34cab1d68a1cdad543bcffb3..2c2afa17c2031df35cb031d3139317874e5f70a6 100644 (file)
@@ -5082,6 +5082,8 @@ A jump table for the options with a short description can be found at |Q_op|.
        When on allow some options that are an expression to be set in the
        modeline.  Check the option for whether it is affected by
        'modelineexpr'.  Also see |modeline|.
+       This option cannot be set from a |modeline| or in the |sandbox|, for
+       security reasons.
 
                                                *'modelines'* *'mls'*
 'modelines' 'mls'      number  (default 5)
@@ -7089,7 +7091,9 @@ A jump table for the options with a short description can be found at |Q_op|.
        When the option starts with "%!" then it is used as an expression,
        evaluated and the result is used as the option value.  Example: >
                :set statusline=%!MyStatusLine()
-<      The result can contain %{} items that will be evaluated too.
+<      The *g:statusline_winid* variable will be set to the |window-ID| of the
+       window that the status line belongs to.
+       The result can contain %{} items that will be evaluated too.
        Note that the "%!" expression is evaluated in the context of the
        current window and buffer, while %{} items are evaluated in the
        context of the window that the statusline belongs to.
@@ -7192,13 +7196,15 @@ A jump table for the options with a short description can be found at |Q_op|.
        become empty.  This will make a group like the following disappear
        completely from the statusline when none of the flags are set. >
                :set statusline=...%(\ [%M%R%H]%)...
-<                                                      *g:actual_curbuf*
-       Beware that an expression is evaluated each and every time the status
-       line is displayed.  The current buffer and current window will be set
-       temporarily to that of the window (and buffer) whose statusline is
-       currently being drawn.  The expression will evaluate in this context.
-       The variable "g:actual_curbuf" is set to the `bufnr()` number of the
-       real current buffer.
+<      Beware that an expression is evaluated each and every time the status
+       line is displayed.
+                                       *g:actual_curbuf* *g:actual_curwin*
+       The current buffer and current window will be set temporarily to that
+       of the window (and buffer) whose statusline is currently being drawn.
+       The expression will evaluate in this context.  The variable
+       "g:actual_curbuf" is set to the `bufnr()` number of the real current
+       buffer and "g:actual_curwin" to the |window-ID| of the real current
+       window.  These values are strings.
 
        The 'statusline' option will be evaluated in the |sandbox| if set from
        a modeline, see |sandbox-option|.
index 0e45f0e66c95a14b03cbef26179a2784688c9d3e..425c9143a121195e43ab459e3a4536b1cd913365 100644 (file)
@@ -3893,7 +3893,8 @@ build_stl_str_hl(
     char_u     base;
     char_u     opt;
 #define TMPLEN 70
-    char_u     tmp[TMPLEN];
+    char_u     buf_tmp[TMPLEN];
+    char_u     win_tmp[TMPLEN];
     char_u     *usefmt = fmt;
     struct stl_hlrec *sp;
     int                save_must_redraw = must_redraw;
@@ -3906,9 +3907,17 @@ build_stl_str_hl(
      */
     if (fmt[0] == '%' && fmt[1] == '!')
     {
+       typval_T        tv;
+
+       tv.v_type = VAR_NUMBER;
+       tv.vval.v_number = wp->w_id;
+       set_var((char_u *)"g:statusline_winid", &tv, FALSE);
+
        usefmt = eval_to_string_safe(fmt + 2, NULL, use_sandbox);
        if (usefmt == NULL)
            usefmt = fmt;
+
+       do_unlet((char_u *)"g:statusline_winid", TRUE);
     }
 #endif
 
@@ -4225,8 +4234,11 @@ build_stl_str_hl(
            p = t;
 
 #ifdef FEAT_EVAL
-           vim_snprintf((char *)tmp, sizeof(tmp), "%d", curbuf->b_fnum);
-           set_internal_string_var((char_u *)"g:actual_curbuf", tmp);
+           vim_snprintf((char *)buf_tmp, sizeof(buf_tmp),
+                                                        "%d", curbuf->b_fnum);
+           set_internal_string_var((char_u *)"g:actual_curbuf", buf_tmp);
+           vim_snprintf((char *)win_tmp, sizeof(win_tmp), "%d", curwin->w_id);
+           set_internal_string_var((char_u *)"g:actual_curwin", win_tmp);
 
            save_curbuf = curbuf;
            save_curwin = curwin;
@@ -4238,6 +4250,7 @@ build_stl_str_hl(
            curwin = save_curwin;
            curbuf = save_curbuf;
            do_unlet((char_u *)"g:actual_curbuf", TRUE);
+           do_unlet((char_u *)"g:actual_curwin", TRUE);
 
            if (str != NULL && *str != 0)
            {
@@ -4290,21 +4303,21 @@ build_stl_str_hl(
            break;
 
        case STL_ALTPERCENT:
-           str = tmp;
+           str = buf_tmp;
            get_rel_pos(wp, str, TMPLEN);
            break;
 
        case STL_ARGLISTSTAT:
            fillable = FALSE;
-           tmp[0] = 0;
-           if (append_arg_number(wp, tmp, (int)sizeof(tmp), FALSE))
-               str = tmp;
+           buf_tmp[0] = 0;
+           if (append_arg_number(wp, buf_tmp, (int)sizeof(buf_tmp), FALSE))
+               str = buf_tmp;
            break;
 
        case STL_KEYMAP:
            fillable = FALSE;
-           if (get_keymap_str(wp, (char_u *)"<%s>", tmp, TMPLEN))
-               str = tmp;
+           if (get_keymap_str(wp, (char_u *)"<%s>", buf_tmp, TMPLEN))
+               str = buf_tmp;
            break;
        case STL_PAGENUM:
 #if defined(FEAT_PRINTER) || defined(FEAT_GUI_TABLINE)
@@ -4360,9 +4373,9 @@ build_stl_str_hl(
            if (*wp->w_buffer->b_p_ft != NUL
                    && STRLEN(wp->w_buffer->b_p_ft) < TMPLEN - 3)
            {
-               vim_snprintf((char *)tmp, sizeof(tmp), "[%s]",
+               vim_snprintf((char *)buf_tmp, sizeof(buf_tmp), "[%s]",
                                                        wp->w_buffer->b_p_ft);
-               str = tmp;
+               str = buf_tmp;
            }
            break;
 
@@ -4371,11 +4384,11 @@ build_stl_str_hl(
            if (*wp->w_buffer->b_p_ft != NUL
                    && STRLEN(wp->w_buffer->b_p_ft) < TMPLEN - 2)
            {
-               vim_snprintf((char *)tmp, sizeof(tmp), ",%s",
+               vim_snprintf((char *)buf_tmp, sizeof(buf_tmp), ",%s",
                                                        wp->w_buffer->b_p_ft);
-               for (t = tmp; *t != 0; t++)
+               for (t = buf_tmp; *t != 0; t++)
                    *t = TOUPPER_LOC(*t);
-               str = tmp;
+               str = buf_tmp;
            }
            break;
 
index b86340a23abfb0dcfc4413560703e16df391f0ed..e1830d08baf60125dd9a386a980389f01f8db566 100644 (file)
@@ -29,7 +29,9 @@ endfunc
 
 " Function used to display syntax group.
 func SyntaxItem()
-  return synIDattr(synID(line("."),col("."),1),"name")
+  call assert_equal(s:expected_curbuf, g:actual_curbuf)
+  call assert_equal(s:expected_curwin, g:actual_curwin)
+  return synIDattr(synID(line("."), col("."),1), "name")
 endfunc
 
 func Test_caught_error_in_statusline()
@@ -218,6 +220,8 @@ func Test_statusline()
 
   "%{: Evaluate expression between '%{' and '}' and substitute result.
   syntax on
+  let s:expected_curbuf = string(bufnr(''))
+  let s:expected_curwin = string(win_getid())
   set statusline=%{SyntaxItem()}
   call assert_match('^vimNumber\s*$', s:get_statusline())
   s/^/"/
@@ -332,6 +336,23 @@ func Test_statusline()
   set statusline=%!2*3+1
   call assert_match('7\s*$', s:get_statusline())
 
+  func GetNested()
+    call assert_equal(string(win_getid()), g:actual_curwin)
+    call assert_equal(string(bufnr('')), g:actual_curbuf)
+    return 'nested'
+  endfunc
+  func GetStatusLine()
+    call assert_equal(win_getid(), g:statusline_winid)
+    return 'the %{GetNested()} line'
+  endfunc
+  set statusline=%!GetStatusLine()
+  call assert_match('the nested line', s:get_statusline())
+  call assert_false(exists('g:actual_curwin'))
+  call assert_false(exists('g:actual_curbuf'))
+  call assert_false(exists('g:statusline_winid'))
+  delfunc GetNested
+  delfunc GetStatusLine
+
   " Check statusline in current and non-current window
   " with the 'fillchars' option.
   set fillchars=stl:^,stlnc:=,vert:\|,fold:-,diff:-
index c2ee827a8c5fac6077463329ad2fa5469581e794..7bac657e597aa1c4db90ffd9076e9e3dc74801ea 100644 (file)
@@ -767,6 +767,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1372,
 /**/
     1371,
 /**/