summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYegappan Lakshmanan <yegappan@yahoo.com>2023-02-11 11:15:25 +0000
committerBram Moolenaar <Bram@vim.org>2023-02-11 11:15:25 +0000
commit3ec78f973fdaec2cea8e036ed38037b2fe40670b (patch)
tree1c2f85b5d0b762bbd0e8f943017e0a2e1c240aae
parent412e0e4ed903682f352d8ea58ded480930cc664f (diff)
patch 9.0.1300: 'statusline' only supports one "%=" itemv9.0.1300
Problem: 'statusline' only supports one "%=" item. Solution: Add support for multiple "%=" items. (TJ DeVries, Yegappan Lakshmanan, closes #11970, closes #11965)
-rw-r--r--runtime/doc/options.txt5
-rw-r--r--src/buffer.c80
-rw-r--r--src/option.h3
-rw-r--r--src/optionstr.c2
-rw-r--r--src/testdir/test_statusline.vim4
-rw-r--r--src/version.c2
6 files changed, 72 insertions, 24 deletions
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index eece6008ed..3d1f2ff8d2 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -7776,7 +7776,10 @@ A jump table for the options with a short description can be found at |Q_op|.
mark. This information is used for mouse clicks.
< - Where to truncate line if too long. Default is at the start.
No width fields allowed.
- = - Separation point between left and right aligned items.
+ = - Separation point between alignment sections. Each section will
+ be separated by an equal number of spaces. With one %= what
+ comes after it will be right-aligned. With two %= there is a
+ middle part, with white space left and right of it.
No width fields allowed.
# - Set highlight group. The name must follow and then a # again.
Thus use %#HLname# for highlight group HLname. The same
diff --git a/src/buffer.c b/src/buffer.c
index a3de68df29..0d523bd056 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -4179,7 +4179,7 @@ typedef struct
Normal,
Empty,
Group,
- Middle,
+ Separate,
Highlight,
TabPage,
Trunc
@@ -4191,6 +4191,7 @@ 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;
+static int *stl_separator_locations = NULL;
/*
* Build a string from the status line items in "fmt".
@@ -4200,7 +4201,7 @@ static stl_hlrec_T *stl_tabtab = NULL;
* is "curwin".
*
* Items are drawn interspersed with the text that surrounds it
- * Specials: %-<wid>(xxx%) => group, %= => middle marker, %< => truncation
+ * Specials: %-<wid>(xxx%) => group, %= => separation marker, %< => truncation
* Item: %-<minwid>.<maxwid><itemch> All but <itemch> are optional
*
* If maxwidth is not zero, the string will be filled at any middle marker
@@ -4282,6 +4283,8 @@ build_stl_str_hl(
// end of the list.
stl_hltab = ALLOC_MULT(stl_hlrec_T, stl_items_len + 1);
stl_tabtab = ALLOC_MULT(stl_hlrec_T, stl_items_len + 1);
+
+ stl_separator_locations = ALLOC_MULT(int, stl_items_len);
}
#ifdef FEAT_EVAL
@@ -4350,19 +4353,20 @@ build_stl_str_hl(
if (curitem == (int)stl_items_len)
{
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);
+ stl_item_T *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);
+
+ int *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,
+
+ stl_hlrec_T *new_hlrec = vim_realloc(stl_hltab,
sizeof(stl_hlrec_T) * (new_len + 1));
if (new_hlrec == NULL)
break;
@@ -4372,6 +4376,13 @@ build_stl_str_hl(
if (new_hlrec == NULL)
break;
stl_tabtab = new_hlrec;
+
+ int *new_separator_locs = vim_realloc(stl_separator_locations,
+ sizeof(int) * new_len);
+ if (new_separator_locs == NULL)
+ break;
+ stl_separator_locations = new_separator_locs;;
+
stl_items_len = new_len;
}
@@ -4400,12 +4411,13 @@ build_stl_str_hl(
prevchar_isflag = prevchar_isitem = FALSE;
continue;
}
- if (*s == STL_MIDDLEMARK)
+ // STL_SEPARATE: Separation between items, filled with white space.
+ if (*s == STL_SEPARATE)
{
s++;
if (groupdepth > 0)
continue;
- stl_items[curitem].stl_type = Middle;
+ stl_items[curitem].stl_type = Separate;
stl_items[curitem++].stl_start = p;
continue;
}
@@ -5121,19 +5133,45 @@ build_stl_str_hl(
}
else if (width < maxwidth && STRLEN(out) + maxwidth - width + 1 < outlen)
{
- // Apply STL_MIDDLE if any
+ // Find how many separators there are, which we will use when
+ // figuring out how many groups there are.
+ int num_separators = 0;
+
for (l = 0; l < itemcnt; l++)
- if (stl_items[l].stl_type == Middle)
- break;
- if (l < itemcnt)
{
- int middlelength = (maxwidth - width) * MB_CHAR2LEN(fillchar);
- p = stl_items[l].stl_start + middlelength;
- STRMOVE(p, stl_items[l].stl_start);
- for (s = stl_items[l].stl_start; s < p;)
- MB_CHAR2BYTES(fillchar, s);
- for (l++; l < itemcnt; l++)
- stl_items[l].stl_start += middlelength;
+ if (stl_items[l].stl_type == Separate)
+ {
+ // Create an array of the start location for each separator
+ // mark.
+ stl_separator_locations[num_separators] = l;
+ num_separators++;
+ }
+ }
+
+ // If we have separated groups, then we deal with it now
+ if (num_separators)
+ {
+ int standard_spaces;
+ int final_spaces;
+
+ standard_spaces = (maxwidth - width) / num_separators;
+ final_spaces = (maxwidth - width) -
+ standard_spaces * (num_separators - 1);
+ for (l = 0; l < num_separators; l++)
+ {
+ int dislocation = (l == (num_separators - 1)) ?
+ final_spaces : standard_spaces;
+ dislocation *= MB_CHAR2LEN(fillchar);
+ char_u *start = stl_items[stl_separator_locations[l]].stl_start;
+ char_u *seploc = start + dislocation;
+ STRMOVE(seploc, start);
+ for (s = start; s < seploc;)
+ MB_CHAR2BYTES(fillchar, s);
+
+ for (int i = stl_separator_locations[l] + 1; i < itemcnt; i++)
+ stl_items[i].stl_start += dislocation;
+ }
+
width = maxwidth;
}
}
diff --git a/src/option.h b/src/option.h
index aa55bfbac2..56b489b197 100644
--- a/src/option.h
+++ b/src/option.h
@@ -347,7 +347,8 @@ typedef enum {
#define STL_PAGENUM 'N' // page number (when printing)
#define STL_SHOWCMD 'S' // 'showcmd' buffer
#define STL_VIM_EXPR '{' // start of expression to substitute
-#define STL_MIDDLEMARK '=' // separation between left and right
+#define STL_SEPARATE '=' // separation between alignment
+ // sections
#define STL_TRUNCMARK '<' // truncation mark if line is too long
#define STL_USER_HL '*' // highlight from (User)1..9 or 0
#define STL_HIGHLIGHT '#' // highlight name
diff --git a/src/optionstr.c b/src/optionstr.c
index d218d5662b..7dfb7b7ff5 100644
--- a/src/optionstr.c
+++ b/src/optionstr.c
@@ -587,7 +587,7 @@ check_stl_option(char_u *s)
if (!*s)
break;
s++;
- if (*s == '%' || *s == STL_TRUNCMARK || *s == STL_MIDDLEMARK)
+ if (*s == '%' || *s == STL_TRUNCMARK || *s == STL_SEPARATE)
{
s++;
continue;
diff --git a/src/testdir/test_statusline.vim b/src/testdir/test_statusline.vim
index 8061d1507a..1239e4e4ee 100644
--- a/src/testdir/test_statusline.vim
+++ b/src/testdir/test_statusline.vim
@@ -231,6 +231,10 @@ func Test_statusline()
" %=: Separation point between left and right aligned items.
set statusline=foo%=bar
call assert_match('^foo\s\+bar\s*$', s:get_statusline())
+ set statusline=foo%=bar%=baz
+ call assert_match('^foo\s\+bar\s\+baz\s*$', s:get_statusline())
+ set statusline=foo%=bar%=baz%=qux
+ call assert_match('^foo\s\+bar\s\+baz\s\+qux\s*$', s:get_statusline())
" Test min/max width, leading zeroes, left/right justify.
set statusline=%04B
diff --git a/src/version.c b/src/version.c
index 9e8e975a96..f28cfd8e23 100644
--- a/src/version.c
+++ b/src/version.c
@@ -696,6 +696,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1300,
+/**/
1299,
/**/
1298,