# HG changeset patch # User Bram Moolenaar # Date 1676115003 -3600 # Node ID 82da100c0e4589da60059a8d9d2f4cb31564ce79 # Parent 46f369a1f0cb5036c98943b6f49f157192c6e757 patch 9.0.1300: 'statusline' only supports one "%=" item Commit: https://github.com/vim/vim/commit/3ec78f973fdaec2cea8e036ed38037b2fe40670b Author: Yegappan Lakshmanan Date: Sat Feb 11 11:15:25 2023 +0000 patch 9.0.1300: 'statusline' only supports one "%=" item Problem: 'statusline' only supports one "%=" item. Solution: Add support for multiple "%=" items. (TJ DeVries, Yegappan Lakshmanan, closes #11970, closes #11965) diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -7776,7 +7776,10 @@ A jump table for the options with a shor 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 --- 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 = NUL * is "curwin". * * Items are drawn interspersed with the text that surrounds it - * Specials: %-(xxx%) => group, %= => middle marker, %< => truncation + * Specials: %-(xxx%) => group, %= => separation marker, %< => truncation * Item: %-. All but 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) + { + 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 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; + 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 --- 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 --- 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 --- 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 --- 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,