summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2020-10-26 21:05:27 +0100
committerBram Moolenaar <Bram@vim.org>2020-10-26 21:05:27 +0100
commit8133cc6bf454eb90bb0868f7cf806fce5c0c9fe6 (patch)
treebfb32937e3b811412be16b24058e03840e94cc78
parentc8970b94645d0730f4a7cc42388ff32665398e8b (diff)
patch 8.2.1909: number of status line items is limited to 80v8.2.1909
Problem: Number of status line items is limited to 80. Solution: Dynamically allocate the arrays. (Rom Grk, closes #7181)
-rw-r--r--runtime/doc/options.txt2
-rw-r--r--src/buffer.c240
-rw-r--r--src/optionstr.c7
-rw-r--r--src/proto/buffer.pro2
-rw-r--r--src/screen.c6
-rw-r--r--src/structs.h5
-rw-r--r--src/testdir/test_options.vim1
-rw-r--r--src/testdir/test_statusline.vim15
-rw-r--r--src/version.c2
-rw-r--r--src/vim.h1
10 files changed, 164 insertions, 117 deletions
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index 88b3d2b237..239ecb2e10 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -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: >
diff --git a/src/buffer.c b/src/buffer.c
index 5a5eb9f416..5cbaaac9cc 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -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)
diff --git a/src/optionstr.c b/src/optionstr.c
index 430e3c34cd..8f3f0c5edc 100644
--- a/src/optionstr.c
+++ b/src/optionstr.c
@@ -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;
diff --git a/src/proto/buffer.pro b/src/proto/buffer.pro
index 4d890ce45c..3fdcc69497 100644
--- a/src/proto/buffer.pro
+++ b/src/proto/buffer.pro
@@ -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);
diff --git a/src/screen.c b/src/screen.c
index 233d6a5852..0b117cd849 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -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;
diff --git a/src/structs.h b/src/structs.h
index 86912c17ac..007aa9d27f 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -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;
/*
diff --git a/src/testdir/test_options.vim b/src/testdir/test_options.vim
index 22e0809ad0..d11d34b000 100644
--- a/src/testdir/test_options.vim
+++ b/src/testdir/test_options.vim
@@ -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.
diff --git a/src/testdir/test_statusline.vim b/src/testdir/test_statusline.vim
index d8e921f555..b28dbb9539 100644
--- a/src/testdir/test_statusline.vim
+++ b/src/testdir/test_statusline.vim
@@ -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:-
diff --git a/src/version.c b/src/version.c
index 91736ec0ad..ac8155a13b 100644
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1909,
+/**/
1908,
/**/
1907,
diff --git a/src/vim.h b/src/vim.h
index 4e40c81384..289ef3cc8a 100644
--- a/src/vim.h
+++ b/src/vim.h
@@ -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