Skip to content

Commit 1c6fd1e

Browse files
committed
patch 8.1.1372: when evaluating 'statusline' the current window is unknown
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)
1 parent 99499b1 commit 1c6fd1e

File tree

4 files changed

+65
-23
lines changed

4 files changed

+65
-23
lines changed

runtime/doc/options.txt

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5082,6 +5082,8 @@ A jump table for the options with a short description can be found at |Q_op|.
50825082
When on allow some options that are an expression to be set in the
50835083
modeline. Check the option for whether it is affected by
50845084
'modelineexpr'. Also see |modeline|.
5085+
This option cannot be set from a |modeline| or in the |sandbox|, for
5086+
security reasons.
50855087

50865088
*'modelines'* *'mls'*
50875089
'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|.
70897091
When the option starts with "%!" then it is used as an expression,
70907092
evaluated and the result is used as the option value. Example: >
70917093
:set statusline=%!MyStatusLine()
7092-
< The result can contain %{} items that will be evaluated too.
7094+
< The *g:statusline_winid* variable will be set to the |window-ID| of the
7095+
window that the status line belongs to.
7096+
The result can contain %{} items that will be evaluated too.
70937097
Note that the "%!" expression is evaluated in the context of the
70947098
current window and buffer, while %{} items are evaluated in the
70957099
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|.
71927196
become empty. This will make a group like the following disappear
71937197
completely from the statusline when none of the flags are set. >
71947198
:set statusline=...%(\ [%M%R%H]%)...
7195-
< *g:actual_curbuf*
7196-
Beware that an expression is evaluated each and every time the status
7197-
line is displayed. The current buffer and current window will be set
7198-
temporarily to that of the window (and buffer) whose statusline is
7199-
currently being drawn. The expression will evaluate in this context.
7200-
The variable "g:actual_curbuf" is set to the `bufnr()` number of the
7201-
real current buffer.
7199+
< Beware that an expression is evaluated each and every time the status
7200+
line is displayed.
7201+
*g:actual_curbuf* *g:actual_curwin*
7202+
The current buffer and current window will be set temporarily to that
7203+
of the window (and buffer) whose statusline is currently being drawn.
7204+
The expression will evaluate in this context. The variable
7205+
"g:actual_curbuf" is set to the `bufnr()` number of the real current
7206+
buffer and "g:actual_curwin" to the |window-ID| of the real current
7207+
window. These values are strings.
72027208

72037209
The 'statusline' option will be evaluated in the |sandbox| if set from
72047210
a modeline, see |sandbox-option|.

src/buffer.c

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3893,7 +3893,8 @@ build_stl_str_hl(
38933893
char_u base;
38943894
char_u opt;
38953895
#define TMPLEN 70
3896-
char_u tmp[TMPLEN];
3896+
char_u buf_tmp[TMPLEN];
3897+
char_u win_tmp[TMPLEN];
38973898
char_u *usefmt = fmt;
38983899
struct stl_hlrec *sp;
38993900
int save_must_redraw = must_redraw;
@@ -3906,9 +3907,17 @@ build_stl_str_hl(
39063907
*/
39073908
if (fmt[0] == '%' && fmt[1] == '!')
39083909
{
3910+
typval_T tv;
3911+
3912+
tv.v_type = VAR_NUMBER;
3913+
tv.vval.v_number = wp->w_id;
3914+
set_var((char_u *)"g:statusline_winid", &tv, FALSE);
3915+
39093916
usefmt = eval_to_string_safe(fmt + 2, NULL, use_sandbox);
39103917
if (usefmt == NULL)
39113918
usefmt = fmt;
3919+
3920+
do_unlet((char_u *)"g:statusline_winid", TRUE);
39123921
}
39133922
#endif
39143923

@@ -4225,8 +4234,11 @@ build_stl_str_hl(
42254234
p = t;
42264235

42274236
#ifdef FEAT_EVAL
4228-
vim_snprintf((char *)tmp, sizeof(tmp), "%d", curbuf->b_fnum);
4229-
set_internal_string_var((char_u *)"g:actual_curbuf", tmp);
4237+
vim_snprintf((char *)buf_tmp, sizeof(buf_tmp),
4238+
"%d", curbuf->b_fnum);
4239+
set_internal_string_var((char_u *)"g:actual_curbuf", buf_tmp);
4240+
vim_snprintf((char *)win_tmp, sizeof(win_tmp), "%d", curwin->w_id);
4241+
set_internal_string_var((char_u *)"g:actual_curwin", win_tmp);
42304242

42314243
save_curbuf = curbuf;
42324244
save_curwin = curwin;
@@ -4238,6 +4250,7 @@ build_stl_str_hl(
42384250
curwin = save_curwin;
42394251
curbuf = save_curbuf;
42404252
do_unlet((char_u *)"g:actual_curbuf", TRUE);
4253+
do_unlet((char_u *)"g:actual_curwin", TRUE);
42414254

42424255
if (str != NULL && *str != 0)
42434256
{
@@ -4290,21 +4303,21 @@ build_stl_str_hl(
42904303
break;
42914304

42924305
case STL_ALTPERCENT:
4293-
str = tmp;
4306+
str = buf_tmp;
42944307
get_rel_pos(wp, str, TMPLEN);
42954308
break;
42964309

42974310
case STL_ARGLISTSTAT:
42984311
fillable = FALSE;
4299-
tmp[0] = 0;
4300-
if (append_arg_number(wp, tmp, (int)sizeof(tmp), FALSE))
4301-
str = tmp;
4312+
buf_tmp[0] = 0;
4313+
if (append_arg_number(wp, buf_tmp, (int)sizeof(buf_tmp), FALSE))
4314+
str = buf_tmp;
43024315
break;
43034316

43044317
case STL_KEYMAP:
43054318
fillable = FALSE;
4306-
if (get_keymap_str(wp, (char_u *)"<%s>", tmp, TMPLEN))
4307-
str = tmp;
4319+
if (get_keymap_str(wp, (char_u *)"<%s>", buf_tmp, TMPLEN))
4320+
str = buf_tmp;
43084321
break;
43094322
case STL_PAGENUM:
43104323
#if defined(FEAT_PRINTER) || defined(FEAT_GUI_TABLINE)
@@ -4360,9 +4373,9 @@ build_stl_str_hl(
43604373
if (*wp->w_buffer->b_p_ft != NUL
43614374
&& STRLEN(wp->w_buffer->b_p_ft) < TMPLEN - 3)
43624375
{
4363-
vim_snprintf((char *)tmp, sizeof(tmp), "[%s]",
4376+
vim_snprintf((char *)buf_tmp, sizeof(buf_tmp), "[%s]",
43644377
wp->w_buffer->b_p_ft);
4365-
str = tmp;
4378+
str = buf_tmp;
43664379
}
43674380
break;
43684381

@@ -4371,11 +4384,11 @@ build_stl_str_hl(
43714384
if (*wp->w_buffer->b_p_ft != NUL
43724385
&& STRLEN(wp->w_buffer->b_p_ft) < TMPLEN - 2)
43734386
{
4374-
vim_snprintf((char *)tmp, sizeof(tmp), ",%s",
4387+
vim_snprintf((char *)buf_tmp, sizeof(buf_tmp), ",%s",
43754388
wp->w_buffer->b_p_ft);
4376-
for (t = tmp; *t != 0; t++)
4389+
for (t = buf_tmp; *t != 0; t++)
43774390
*t = TOUPPER_LOC(*t);
4378-
str = tmp;
4391+
str = buf_tmp;
43794392
}
43804393
break;
43814394

src/testdir/test_statusline.vim

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ endfunc
2929

3030
" Function used to display syntax group.
3131
func SyntaxItem()
32-
return synIDattr(synID(line("."),col("."),1),"name")
32+
call assert_equal(s:expected_curbuf, g:actual_curbuf)
33+
call assert_equal(s:expected_curwin, g:actual_curwin)
34+
return synIDattr(synID(line("."), col("."),1), "name")
3335
endfunc
3436

3537
func Test_caught_error_in_statusline()
@@ -218,6 +220,8 @@ func Test_statusline()
218220

219221
"%{: Evaluate expression between '%{' and '}' and substitute result.
220222
syntax on
223+
let s:expected_curbuf = string(bufnr(''))
224+
let s:expected_curwin = string(win_getid())
221225
set statusline=%{SyntaxItem()}
222226
call assert_match('^vimNumber\s*$', s:get_statusline())
223227
s/^/"/
@@ -332,6 +336,23 @@ func Test_statusline()
332336
set statusline=%!2*3+1
333337
call assert_match('7\s*$', s:get_statusline())
334338

339+
func GetNested()
340+
call assert_equal(string(win_getid()), g:actual_curwin)
341+
call assert_equal(string(bufnr('')), g:actual_curbuf)
342+
return 'nested'
343+
endfunc
344+
func GetStatusLine()
345+
call assert_equal(win_getid(), g:statusline_winid)
346+
return 'the %{GetNested()} line'
347+
endfunc
348+
set statusline=%!GetStatusLine()
349+
call assert_match('the nested line', s:get_statusline())
350+
call assert_false(exists('g:actual_curwin'))
351+
call assert_false(exists('g:actual_curbuf'))
352+
call assert_false(exists('g:statusline_winid'))
353+
delfunc GetNested
354+
delfunc GetStatusLine
355+
335356
" Check statusline in current and non-current window
336357
" with the 'fillchars' option.
337358
set fillchars=stl:^,stlnc:=,vert:\|,fold:-,diff:-

src/version.c

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

768768
static int included_patches[] =
769769
{ /* Add new patch number below this line */
770+
/**/
771+
1372,
770772
/**/
771773
1371,
772774
/**/

0 commit comments

Comments
 (0)