mirror of
https://github.com/vim/vim.git
synced 2025-07-26 11:04:33 -04:00
patch 8.2.2854: custom statusline cannot contain % items
Problem: Custom statusline cannot contain % items. Solution: Add "%{% expr %}". (closes #8190)
This commit is contained in:
parent
d832c3c56e
commit
30e3de21fc
@ -7339,6 +7339,18 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
Note that there is no '%' before the closing '}'. The
|
Note that there is no '%' before the closing '}'. The
|
||||||
expression cannot contain a '}' character, call a function to
|
expression cannot contain a '}' character, call a function to
|
||||||
work around that. See |stl-%{| below.
|
work around that. See |stl-%{| below.
|
||||||
|
{% - This is almost same as { except the result of the expression is
|
||||||
|
re-evaluated as a statusline format string. Thus if the
|
||||||
|
return value of expr contains % items they will get expanded.
|
||||||
|
The expression can contain the } character, the end of
|
||||||
|
expression is denoted by %}.
|
||||||
|
The For example: >
|
||||||
|
func! Stl_filename() abort
|
||||||
|
return "%t"
|
||||||
|
endfunc
|
||||||
|
< `stl=%{Stl_filename()}` results in `"%t"`
|
||||||
|
`stl=%{%Stl_filename()%}` results in `"Name of current file"`
|
||||||
|
} - End of `{%` expression
|
||||||
( - Start of item group. Can be used for setting the width and
|
( - Start of item group. Can be used for setting the width and
|
||||||
alignment of a section. Must be followed by %) somewhere.
|
alignment of a section. Must be followed by %) somewhere.
|
||||||
) - End of item group. No width fields allowed.
|
) - End of item group. No width fields allowed.
|
||||||
|
73
src/buffer.c
73
src/buffer.c
@ -27,6 +27,12 @@
|
|||||||
|
|
||||||
#include "vim.h"
|
#include "vim.h"
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef FEAT_EVAL
|
||||||
|
// Determines how deeply nested %{} blocks will be evaluated in statusline.
|
||||||
|
# define MAX_STL_EVAL_DEPTH 100
|
||||||
|
#endif
|
||||||
|
|
||||||
static void enter_buffer(buf_T *buf);
|
static void enter_buffer(buf_T *buf);
|
||||||
static void buflist_getfpos(void);
|
static void buflist_getfpos(void);
|
||||||
static char_u *buflist_match(regmatch_T *rmp, buf_T *buf, int ignore_case);
|
static char_u *buflist_match(regmatch_T *rmp, buf_T *buf, int ignore_case);
|
||||||
@ -4113,6 +4119,9 @@ build_stl_str_hl(
|
|||||||
int group_end_userhl;
|
int group_end_userhl;
|
||||||
int group_start_userhl;
|
int group_start_userhl;
|
||||||
int groupdepth;
|
int groupdepth;
|
||||||
|
#ifdef FEAT_EVAL
|
||||||
|
int evaldepth;
|
||||||
|
#endif
|
||||||
int minwid;
|
int minwid;
|
||||||
int maxwid;
|
int maxwid;
|
||||||
int zeropad;
|
int zeropad;
|
||||||
@ -4187,6 +4196,9 @@ build_stl_str_hl(
|
|||||||
byteval = (*mb_ptr2char)(p + wp->w_cursor.col);
|
byteval = (*mb_ptr2char)(p + wp->w_cursor.col);
|
||||||
|
|
||||||
groupdepth = 0;
|
groupdepth = 0;
|
||||||
|
#ifdef FEAT_EVAL
|
||||||
|
evaldepth = 0;
|
||||||
|
#endif
|
||||||
p = out;
|
p = out;
|
||||||
curitem = 0;
|
curitem = 0;
|
||||||
prevchar_isflag = TRUE;
|
prevchar_isflag = TRUE;
|
||||||
@ -4447,6 +4459,15 @@ build_stl_str_hl(
|
|||||||
curitem++;
|
curitem++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
#ifdef FEAT_EVAL
|
||||||
|
// Denotes end of expanded %{} block
|
||||||
|
if (*s == '}' && evaldepth > 0)
|
||||||
|
{
|
||||||
|
s++;
|
||||||
|
evaldepth--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (vim_strchr(STL_ALL, *s) == NULL)
|
if (vim_strchr(STL_ALL, *s) == NULL)
|
||||||
{
|
{
|
||||||
s++;
|
s++;
|
||||||
@ -4482,16 +4503,27 @@ build_stl_str_hl(
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case STL_VIM_EXPR: // '{'
|
case STL_VIM_EXPR: // '{'
|
||||||
|
{
|
||||||
|
#ifdef FEAT_EVAL
|
||||||
|
char_u *block_start = s - 1;
|
||||||
|
#endif
|
||||||
|
int reevaluate = (*s == '%');
|
||||||
|
|
||||||
|
if (reevaluate)
|
||||||
|
s++;
|
||||||
itemisflag = TRUE;
|
itemisflag = TRUE;
|
||||||
t = p;
|
t = p;
|
||||||
while (*s != '}' && *s != NUL && p + 1 < out + outlen)
|
while ((*s != '}' || (reevaluate && s[-1] != '%'))
|
||||||
|
&& *s != NUL && p + 1 < out + outlen)
|
||||||
*p++ = *s++;
|
*p++ = *s++;
|
||||||
if (*s != '}') // missing '}' or out of space
|
if (*s != '}') // missing '}' or out of space
|
||||||
break;
|
break;
|
||||||
s++;
|
s++;
|
||||||
*p = 0;
|
if (reevaluate)
|
||||||
|
p[-1] = 0; // remove the % at the end of %{% expr %}
|
||||||
|
else
|
||||||
|
*p = 0;
|
||||||
p = t;
|
p = t;
|
||||||
|
|
||||||
#ifdef FEAT_EVAL
|
#ifdef FEAT_EVAL
|
||||||
vim_snprintf((char *)buf_tmp, sizeof(buf_tmp),
|
vim_snprintf((char *)buf_tmp, sizeof(buf_tmp),
|
||||||
"%d", curbuf->b_fnum);
|
"%d", curbuf->b_fnum);
|
||||||
@ -4525,9 +4557,42 @@ build_stl_str_hl(
|
|||||||
itemisflag = FALSE;
|
itemisflag = FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the output of the expression needs to be evaluated
|
||||||
|
// replace the %{} block with the result of evaluation
|
||||||
|
if (reevaluate && str != NULL && *str != 0
|
||||||
|
&& strchr((const char *)str, '%') != NULL
|
||||||
|
&& evaldepth < MAX_STL_EVAL_DEPTH)
|
||||||
|
{
|
||||||
|
size_t parsed_usefmt = (size_t)(block_start - usefmt);
|
||||||
|
size_t str_length = strlen((const char *)str);
|
||||||
|
size_t fmt_length = strlen((const char *)s);
|
||||||
|
size_t new_fmt_len = parsed_usefmt
|
||||||
|
+ str_length + fmt_length + 3;
|
||||||
|
char_u *new_fmt = (char_u *)alloc(new_fmt_len * sizeof(char_u));
|
||||||
|
char_u *new_fmt_p = new_fmt;
|
||||||
|
|
||||||
|
new_fmt_p = (char_u *)memcpy(new_fmt_p, usefmt, parsed_usefmt)
|
||||||
|
+ parsed_usefmt;
|
||||||
|
new_fmt_p = (char_u *)memcpy(new_fmt_p , str, str_length)
|
||||||
|
+ str_length;
|
||||||
|
new_fmt_p = (char_u *)memcpy(new_fmt_p, "%}", 2) + 2;
|
||||||
|
new_fmt_p = (char_u *)memcpy(new_fmt_p , s, fmt_length)
|
||||||
|
+ fmt_length;
|
||||||
|
*new_fmt_p = 0;
|
||||||
|
new_fmt_p = NULL;
|
||||||
|
|
||||||
|
if (usefmt != fmt)
|
||||||
|
vim_free(usefmt);
|
||||||
|
VIM_CLEAR(str);
|
||||||
|
usefmt = new_fmt;
|
||||||
|
s = usefmt + parsed_usefmt;
|
||||||
|
evaldepth++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case STL_LINE:
|
case STL_LINE:
|
||||||
num = (wp->w_buffer->b_ml.ml_flags & ML_EMPTY)
|
num = (wp->w_buffer->b_ml.ml_flags & ML_EMPTY)
|
||||||
? 0L : (long)(wp->w_cursor.lnum);
|
? 0L : (long)(wp->w_cursor.lnum);
|
||||||
|
@ -618,8 +618,10 @@ check_stl_option(char_u *s)
|
|||||||
}
|
}
|
||||||
if (*s == '{')
|
if (*s == '{')
|
||||||
{
|
{
|
||||||
|
int reevaluate = (*s == '%');
|
||||||
|
|
||||||
s++;
|
s++;
|
||||||
while (*s != '}' && *s)
|
while ((*s != '}' || (reevaluate && s[-1] != '%')) && *s)
|
||||||
s++;
|
s++;
|
||||||
if (*s != '}')
|
if (*s != '}')
|
||||||
return N_("E540: Unclosed expression sequence");
|
return N_("E540: Unclosed expression sequence");
|
||||||
|
@ -251,6 +251,26 @@ func Test_statusline()
|
|||||||
call assert_match('^vimLineComment\s*$', s:get_statusline())
|
call assert_match('^vimLineComment\s*$', s:get_statusline())
|
||||||
syntax off
|
syntax off
|
||||||
|
|
||||||
|
"%{%expr%}: evaluates enxpressions present in result of expr
|
||||||
|
func! Inner_eval()
|
||||||
|
return '%n some other text'
|
||||||
|
endfunc
|
||||||
|
func! Outer_eval()
|
||||||
|
return 'some text %{%Inner_eval()%}'
|
||||||
|
endfunc
|
||||||
|
set statusline=%{%Outer_eval()%}
|
||||||
|
call assert_match('^some text ' . bufnr() . ' some other text\s*$', s:get_statusline())
|
||||||
|
delfunc Inner_eval
|
||||||
|
delfunc Outer_eval
|
||||||
|
|
||||||
|
"%{%expr%}: Doesn't get stuck in recursion
|
||||||
|
func! Recurse_eval()
|
||||||
|
return '%{%Recurse_eval()%}'
|
||||||
|
endfunc
|
||||||
|
set statusline=%{%Recurse_eval()%}
|
||||||
|
call assert_match('^%{%Recurse_eval()%}\s*$', s:get_statusline())
|
||||||
|
delfunc Recurse_eval
|
||||||
|
|
||||||
"%(: Start of item group.
|
"%(: Start of item group.
|
||||||
set statusline=ab%(cd%q%)de
|
set statusline=ab%(cd%q%)de
|
||||||
call assert_match('^abde\s*$', s:get_statusline())
|
call assert_match('^abde\s*$', s:get_statusline())
|
||||||
|
@ -750,6 +750,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
2854,
|
||||||
/**/
|
/**/
|
||||||
2853,
|
2853,
|
||||||
/**/
|
/**/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user