1
0
forked from aniani/vim

patch 8.2.1909: number of status line items is limited to 80

Problem:    Number of status line items is limited to 80.
Solution:   Dynamically allocate the arrays. (Rom Grk, closes #7181)
This commit is contained in:
Bram Moolenaar 2020-10-26 21:05:27 +01:00
parent c8970b9464
commit 8133cc6bf4
10 changed files with 164 additions and 117 deletions

View File

@ -7225,7 +7225,7 @@ A jump table for the options with a short description can be found at |Q_op|.
normal text. Each status line item is of the form:
%-0{minwid}.{maxwid}{item}
All fields except the {item} are optional. A single percent sign can
be given as "%%". Up to 80 items can be specified. *E541*
be given as "%%".
When the option starts with "%!" then it is used as an expression,
evaluated and the result is used as the option value. Example: >

View File

@ -673,7 +673,7 @@ aucmd_abort:
buf->b_nwindows = nwindows;
buf_freeall(buf, (del_buf ? BFA_DEL : 0)
+ (wipe_buf ? BFA_WIPE : 0)
+ (wipe_buf ? BFA_WIPE : 0)
+ (ignore_abort ? BFA_IGNORE_ABORT : 0));
// Autocommands may have deleted the buffer.
@ -4017,6 +4017,32 @@ free_titles(void)
#endif // FEAT_TITLE
#if defined(FEAT_STL_OPT) || defined(FEAT_GUI_TABLINE) || defined(PROTO)
/*
* Used for building in the status line.
*/
typedef struct
{
char_u *stl_start;
int stl_minwid;
int stl_maxwid;
enum {
Normal,
Empty,
Group,
Middle,
Highlight,
TabPage,
Trunc
} stl_type;
} stl_item_T;
static size_t stl_items_len = 20; // Initial value, grows as needed.
static stl_item_T *stl_items = NULL;
static int *stl_groupitem = NULL;
static stl_hlrec_T *stl_hltab = NULL;
static stl_hlrec_T *stl_tabtab = NULL;
/*
* Build a string from the status line items in "fmt".
* Return length of string in screen cells.
@ -4040,8 +4066,8 @@ build_stl_str_hl(
int use_sandbox UNUSED, // "fmt" was set insecurely, use sandbox
int fillchar,
int maxwidth,
struct stl_hlrec *hltab, // return: HL attributes (can be NULL)
struct stl_hlrec *tabtab) // return: tab page nrs (can be NULL)
stl_hlrec_T **hltab, // return: HL attributes (can be NULL)
stl_hlrec_T **tabtab) // return: tab page nrs (can be NULL)
{
linenr_T lnum;
size_t len;
@ -4069,24 +4095,7 @@ build_stl_str_hl(
int curitem;
int group_end_userhl;
int group_start_userhl;
int groupitem[STL_MAX_ITEM];
int groupdepth;
struct stl_item
{
char_u *start;
int minwid;
int maxwid;
enum
{
Normal,
Empty,
Group,
Middle,
Highlight,
TabPage,
Trunc
} type;
} item[STL_MAX_ITEM];
int minwid;
int maxwid;
int zeropad;
@ -4096,10 +4105,18 @@ build_stl_str_hl(
char_u buf_tmp[TMPLEN];
char_u win_tmp[TMPLEN];
char_u *usefmt = fmt;
struct stl_hlrec *sp;
stl_hlrec_T *sp;
int save_must_redraw = must_redraw;
int save_redr_type = curwin->w_redr_type;
if (stl_items == NULL)
{
stl_items = ALLOC_MULT(stl_item_T, stl_items_len);
stl_groupitem = ALLOC_MULT(int, stl_items_len);
stl_hltab = ALLOC_MULT(stl_hlrec_T, stl_items_len);
stl_tabtab = ALLOC_MULT(stl_hlrec_T, stl_items_len);
}
#ifdef FEAT_EVAL
/*
* When the format starts with "%!" then evaluate it as an expression and
@ -4162,16 +4179,30 @@ build_stl_str_hl(
prevchar_isitem = FALSE;
for (s = usefmt; *s; )
{
if (curitem == STL_MAX_ITEM)
if (curitem == (int)stl_items_len)
{
// There are too many items. Add the error code to the statusline
// to give the user a hint about what went wrong.
if (p + 6 < out + outlen)
{
mch_memmove(p, " E541", (size_t)5);
p += 5;
}
break;
size_t new_len = stl_items_len * 3 / 2;
stl_item_T *new_items;
int *new_groupitem;
stl_hlrec_T *new_hlrec;
new_items = vim_realloc(stl_items, sizeof(stl_item_T) * new_len);
if (new_items == NULL)
break;
stl_items = new_items;
new_groupitem = vim_realloc(stl_groupitem, sizeof(int) * new_len);
if (new_groupitem == NULL)
break;
stl_groupitem = new_groupitem;
new_hlrec = vim_realloc(stl_hltab, sizeof(stl_hlrec_T) * new_len);
if (new_hlrec == NULL)
break;
stl_hltab = new_hlrec;
new_hlrec = vim_realloc(stl_tabtab, sizeof(stl_hlrec_T) * new_len);
if (new_hlrec == NULL)
break;
stl_tabtab = new_hlrec;
stl_items_len = new_len;
}
if (*s != NUL && *s != '%')
@ -4204,15 +4235,15 @@ build_stl_str_hl(
s++;
if (groupdepth > 0)
continue;
item[curitem].type = Middle;
item[curitem++].start = p;
stl_items[curitem].stl_type = Middle;
stl_items[curitem++].stl_start = p;
continue;
}
if (*s == STL_TRUNCMARK)
{
s++;
item[curitem].type = Trunc;
item[curitem++].start = p;
stl_items[curitem].stl_type = Trunc;
stl_items[curitem++].stl_start = p;
continue;
}
if (*s == ')')
@ -4222,83 +4253,85 @@ build_stl_str_hl(
continue;
groupdepth--;
t = item[groupitem[groupdepth]].start;
t = stl_items[stl_groupitem[groupdepth]].stl_start;
*p = NUL;
l = vim_strsize(t);
if (curitem > groupitem[groupdepth] + 1
&& item[groupitem[groupdepth]].minwid == 0)
if (curitem > stl_groupitem[groupdepth] + 1
&& stl_items[stl_groupitem[groupdepth]].stl_minwid == 0)
{
// remove group if all items are empty and highlight group
// doesn't change
group_start_userhl = group_end_userhl = 0;
for (n = groupitem[groupdepth] - 1; n >= 0; n--)
for (n = stl_groupitem[groupdepth] - 1; n >= 0; n--)
{
if (item[n].type == Highlight)
if (stl_items[n].stl_type == Highlight)
{
group_start_userhl = group_end_userhl = item[n].minwid;
group_start_userhl = group_end_userhl =
stl_items[n].stl_minwid;
break;
}
}
for (n = groupitem[groupdepth] + 1; n < curitem; n++)
for (n = stl_groupitem[groupdepth] + 1; n < curitem; n++)
{
if (item[n].type == Normal)
if (stl_items[n].stl_type == Normal)
break;
if (item[n].type == Highlight)
group_end_userhl = item[n].minwid;
if (stl_items[n].stl_type == Highlight)
group_end_userhl = stl_items[n].stl_minwid;
}
if (n == curitem && group_start_userhl == group_end_userhl)
{
// empty group
p = t;
l = 0;
for (n = groupitem[groupdepth] + 1; n < curitem; n++)
for (n = stl_groupitem[groupdepth] + 1; n < curitem; n++)
{
// do not use the highlighting from the removed group
if (item[n].type == Highlight)
item[n].type = Empty;
if (stl_items[n].stl_type == Highlight)
stl_items[n].stl_type = Empty;
// adjust the start position of TabPage to the next
// item position
if (item[n].type == TabPage)
item[n].start = p;
if (stl_items[n].stl_type == TabPage)
stl_items[n].stl_start = p;
}
}
}
if (l > item[groupitem[groupdepth]].maxwid)
if (l > stl_items[stl_groupitem[groupdepth]].stl_maxwid)
{
// truncate, remove n bytes of text at the start
if (has_mbyte)
{
// Find the first character that should be included.
n = 0;
while (l >= item[groupitem[groupdepth]].maxwid)
while (l >= stl_items[stl_groupitem[groupdepth]].stl_maxwid)
{
l -= ptr2cells(t + n);
n += (*mb_ptr2len)(t + n);
}
}
else
n = (long)(p - t) - item[groupitem[groupdepth]].maxwid + 1;
n = (long)(p - t) - stl_items[stl_groupitem[groupdepth]]
.stl_maxwid + 1;
*t = '<';
mch_memmove(t + 1, t + n, (size_t)(p - (t + n)));
p = p - n + 1;
// Fill up space left over by half a double-wide char.
while (++l < item[groupitem[groupdepth]].minwid)
while (++l < stl_items[stl_groupitem[groupdepth]].stl_minwid)
*p++ = fillchar;
// correct the start of the items for the truncation
for (l = groupitem[groupdepth] + 1; l < curitem; l++)
for (l = stl_groupitem[groupdepth] + 1; l < curitem; l++)
{
item[l].start -= n;
if (item[l].start < t)
item[l].start = t;
stl_items[l].stl_start -= n;
if (stl_items[l].stl_start < t)
stl_items[l].stl_start = t;
}
}
else if (abs(item[groupitem[groupdepth]].minwid) > l)
else if (abs(stl_items[stl_groupitem[groupdepth]].stl_minwid) > l)
{
// fill
n = item[groupitem[groupdepth]].minwid;
n = stl_items[stl_groupitem[groupdepth]].stl_minwid;
if (n < 0)
{
// fill by appending characters
@ -4314,8 +4347,8 @@ build_stl_str_hl(
if (p + l >= out + outlen)
l = (long)((out + outlen) - p - 1);
p += l;
for (n = groupitem[groupdepth] + 1; n < curitem; n++)
item[n].start += l;
for (n = stl_groupitem[groupdepth] + 1; n < curitem; n++)
stl_items[n].stl_start += l;
for ( ; l > 0; l--)
*t++ = fillchar;
}
@ -4344,9 +4377,9 @@ build_stl_str_hl(
}
if (*s == STL_USER_HL)
{
item[curitem].type = Highlight;
item[curitem].start = p;
item[curitem].minwid = minwid > 9 ? 1 : minwid;
stl_items[curitem].stl_type = Highlight;
stl_items[curitem].stl_start = p;
stl_items[curitem].stl_minwid = minwid > 9 ? 1 : minwid;
s++;
curitem++;
continue;
@ -4360,9 +4393,10 @@ build_stl_str_hl(
// %X ends the close label, go back to the previously
// define tab label nr.
for (n = curitem - 1; n >= 0; --n)
if (item[n].type == TabPage && item[n].minwid >= 0)
if (stl_items[n].stl_type == TabPage
&& stl_items[n].stl_minwid >= 0)
{
minwid = item[n].minwid;
minwid = stl_items[n].stl_minwid;
break;
}
}
@ -4370,9 +4404,9 @@ build_stl_str_hl(
// close nrs are stored as negative values
minwid = - minwid;
}
item[curitem].type = TabPage;
item[curitem].start = p;
item[curitem].minwid = minwid;
stl_items[curitem].stl_type = TabPage;
stl_items[curitem].stl_start = p;
stl_items[curitem].stl_minwid = minwid;
s++;
curitem++;
continue;
@ -4390,11 +4424,11 @@ build_stl_str_hl(
minwid = (minwid > 50 ? 50 : minwid) * l;
if (*s == '(')
{
groupitem[groupdepth++] = curitem;
item[curitem].type = Group;
item[curitem].start = p;
item[curitem].minwid = minwid;
item[curitem].maxwid = maxwid;
stl_groupitem[groupdepth++] = curitem;
stl_items[curitem].stl_type = Group;
stl_items[curitem].stl_start = p;
stl_items[curitem].stl_minwid = minwid;
stl_items[curitem].stl_maxwid = maxwid;
s++;
curitem++;
continue;
@ -4647,9 +4681,9 @@ build_stl_str_hl(
++s;
if (*s == '#')
{
item[curitem].type = Highlight;
item[curitem].start = p;
item[curitem].minwid = -syn_namen2id(t, (int)(s - t));
stl_items[curitem].stl_type = Highlight;
stl_items[curitem].stl_start = p;
stl_items[curitem].stl_minwid = -syn_namen2id(t, (int)(s - t));
curitem++;
}
if (*s != NUL)
@ -4657,8 +4691,8 @@ build_stl_str_hl(
continue;
}
item[curitem].start = p;
item[curitem].type = Normal;
stl_items[curitem].stl_start = p;
stl_items[curitem].stl_type = Normal;
if (str != NULL && *str)
{
t = str;
@ -4757,7 +4791,7 @@ build_stl_str_hl(
p += STRLEN(p);
}
else
item[curitem].type = Empty;
stl_items[curitem].stl_type = Empty;
if (opt == STL_VIM_EXPR)
vim_free(str);
@ -4784,16 +4818,16 @@ build_stl_str_hl(
else
{
for ( ; l < itemcnt; l++)
if (item[l].type == Trunc)
if (stl_items[l].stl_type == Trunc)
{
// Truncate at %< item.
s = item[l].start;
s = stl_items[l].stl_start;
break;
}
if (l == itemcnt)
{
// No %< item, truncate first item.
s = item[0].start;
s = stl_items[0].stl_start;
l = 0;
}
}
@ -4819,7 +4853,7 @@ build_stl_str_hl(
else
s = out + maxwidth - 1;
for (l = 0; l < itemcnt; l++)
if (item[l].start > s)
if (stl_items[l].stl_start > s)
break;
itemcnt = l;
*s++ = '>';
@ -4853,10 +4887,10 @@ build_stl_str_hl(
--n; // count the '<'
for (; l < itemcnt; l++)
{
if (item[l].start - n >= s)
item[l].start -= n;
if (stl_items[l].stl_start - n >= s)
stl_items[l].stl_start -= n;
else
item[l].start = s;
stl_items[l].stl_start = s;
}
}
width = maxwidth;
@ -4865,16 +4899,16 @@ build_stl_str_hl(
{
// Apply STL_MIDDLE if any
for (l = 0; l < itemcnt; l++)
if (item[l].type == Middle)
if (stl_items[l].stl_type == Middle)
break;
if (l < itemcnt)
{
p = item[l].start + maxwidth - width;
STRMOVE(p, item[l].start);
for (s = item[l].start; s < p; s++)
p = stl_items[l].stl_start + maxwidth - width;
STRMOVE(p, stl_items[l].stl_start);
for (s = stl_items[l].stl_start; s < p; s++)
*s = fillchar;
for (l++; l < itemcnt; l++)
item[l].start += maxwidth - width;
stl_items[l].stl_start += maxwidth - width;
width = maxwidth;
}
}
@ -4882,13 +4916,14 @@ build_stl_str_hl(
// Store the info about highlighting.
if (hltab != NULL)
{
sp = hltab;
*hltab = stl_hltab;
sp = stl_hltab;
for (l = 0; l < itemcnt; l++)
{
if (item[l].type == Highlight)
if (stl_items[l].stl_type == Highlight)
{
sp->start = item[l].start;
sp->userhl = item[l].minwid;
sp->start = stl_items[l].stl_start;
sp->userhl = stl_items[l].stl_minwid;
sp++;
}
}
@ -4899,13 +4934,14 @@ build_stl_str_hl(
// Store the info about tab pages labels.
if (tabtab != NULL)
{
sp = tabtab;
*tabtab = stl_tabtab;
sp = stl_tabtab;
for (l = 0; l < itemcnt; l++)
{
if (item[l].type == TabPage)
if (stl_items[l].stl_type == TabPage)
{
sp->start = item[l].start;
sp->userhl = item[l].minwid;
sp->start = stl_items[l].stl_start;
sp->userhl = stl_items[l].stl_minwid;
sp++;
}
}
@ -5534,8 +5570,8 @@ bt_nofile(buf_T *buf)
bt_dontwrite(buf_T *buf)
{
return buf != NULL && (buf->b_p_bt[0] == 'n'
|| buf->b_p_bt[0] == 't'
|| buf->b_p_bt[0] == 'p');
|| buf->b_p_bt[0] == 't'
|| buf->b_p_bt[0] == 'p');
}
#if defined(FEAT_QUICKFIX) || defined(PROTO)

View File

@ -571,11 +571,10 @@ valid_filetype(char_u *val)
static char *
check_stl_option(char_u *s)
{
int itemcnt = 0;
int groupdepth = 0;
static char errbuf[80];
while (*s && itemcnt < STL_MAX_ITEM)
while (*s)
{
// Check for valid keys after % sequences
while (*s && *s != '%')
@ -583,8 +582,6 @@ check_stl_option(char_u *s)
if (!*s)
break;
s++;
if (*s != '%' && *s != ')')
++itemcnt;
if (*s == '%' || *s == STL_TRUNCMARK || *s == STL_MIDDLEMARK)
{
s++;
@ -627,8 +624,6 @@ check_stl_option(char_u *s)
return N_("E540: Unclosed expression sequence");
}
}
if (itemcnt >= STL_MAX_ITEM)
return N_("E541: too many items");
if (groupdepth != 0)
return N_("E542: unbalanced groups");
return NULL;

View File

@ -48,7 +48,7 @@ void col_print(char_u *buf, size_t buflen, int col, int vcol);
void maketitle(void);
void resettitle(void);
void free_titles(void);
int build_stl_str_hl(win_T *wp, char_u *out, size_t outlen, char_u *fmt, int use_sandbox, int fillchar, int maxwidth, struct stl_hlrec *hltab, struct stl_hlrec *tabtab);
int build_stl_str_hl(win_T *wp, char_u *out, size_t outlen, char_u *fmt, int use_sandbox, int fillchar, int maxwidth, stl_hlrec_T **hltab, stl_hlrec_T **tabtab);
void get_rel_pos(win_T *wp, char_u *buf, int buflen);
char_u *fix_fname(char_u *fname);
void fname_expand(buf_T *buf, char_u **ffname, char_u **sfname);

View File

@ -1196,8 +1196,8 @@ win_redr_custom(
char_u buf[MAXPATHL];
char_u *stl;
char_u *p;
struct stl_hlrec hltab[STL_MAX_ITEM];
struct stl_hlrec tabtab[STL_MAX_ITEM];
stl_hlrec_T *hltab;
stl_hlrec_T *tabtab;
int use_sandbox = FALSE;
win_T *ewp;
int p_crb_save;
@ -1287,7 +1287,7 @@ win_redr_custom(
stl = vim_strsave(stl);
width = build_stl_str_hl(ewp, buf, sizeof(buf),
stl, use_sandbox,
fillchar, maxwidth, hltab, tabtab);
fillchar, maxwidth, &hltab, &tabtab);
vim_free(stl);
ewp->w_p_crb = p_crb_save;

View File

@ -1229,14 +1229,15 @@ struct mapblock
#endif
};
/*
* Used for highlighting in the status line.
*/
struct stl_hlrec
typedef struct
{
char_u *start;
int userhl; // 0: no HL, 1-9: User HL, < 0 for syn ID
};
} stl_hlrec_T;
/*

View File

@ -372,7 +372,6 @@ func Test_set_errors()
call assert_fails('set commentstring=x', 'E537:')
call assert_fails('set complete=x', 'E539:')
call assert_fails('set statusline=%{', 'E540:')
call assert_fails('set statusline=' . repeat("%p", 81), 'E541:')
call assert_fails('set statusline=%(', 'E542:')
if has('cursorshape')
" This invalid value for 'guicursor' used to cause Vim to crash.

View File

@ -376,6 +376,21 @@ func Test_statusline()
delfunc GetNested
delfunc GetStatusLine
" Test statusline works with 80+ items
function! StatusLabel()
redrawstatus
return '[label]'
endfunc
let statusline = '%{StatusLabel()}'
for i in range(150)
let statusline .= '%#TabLine' . (i % 2 == 0 ? 'Fill' : 'Sel') . '#' . string(i)[0]
endfor
let &statusline = statusline
redrawstatus
set statusline&
delfunc StatusLabel
" Check statusline in current and non-current window
" with the 'fillchars' option.
set fillchars=stl:^,stlnc:=,vert:\|,fold:-,diff:-

View File

@ -750,6 +750,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
1909,
/**/
1908,
/**/

View File

@ -1699,7 +1699,6 @@ typedef unsigned short disptick_T; // display tick type
#endif
#define SHOWCMD_COLS 10 // columns needed by shown command
#define STL_MAX_ITEM 80 // max nr of %<flag> in statusline
typedef void *vim_acl_T; // dummy to pass an ACL to a function