diff --git a/src/nvim/statusline.c b/src/nvim/statusline.c index 1ac013f43b..017064c9e5 100644 --- a/src/nvim/statusline.c +++ b/src/nvim/statusline.c @@ -1119,16 +1119,19 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, OptIndex op } } + int minwid = stl_items[stl_groupitems[groupdepth]].minwid; + // If the group is longer than it is allowed to be truncate by removing // bytes from the start of the group text. Don't truncate when item is a // 'statuscolumn' fold item to ensure correctness of the mouse clicks. if (group_len > stl_items[stl_groupitems[groupdepth]].maxwid && stl_items[stl_groupitems[groupdepth]].type != HighlightFold) { // { Determine the number of bytes to remove + int maxwid = stl_items[stl_groupitems[groupdepth]].maxwid; // Find the first character that should be included. int n = 0; - while (group_len >= stl_items[stl_groupitems[groupdepth]].maxwid) { + while (group_len >= maxwid) { group_len -= ptr2cells(t + n); n += utfc_ptr2len(t + n); } @@ -1141,7 +1144,8 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, OptIndex op memmove(t + 1, t + n, (size_t)(out_p - (t + n))); out_p = out_p - n + 1; // Fill up space left over by half a double-wide char. - while (++group_len < stl_items[stl_groupitems[groupdepth]].minwid) { + minwid = MIN(minwid, maxwid); + while (++group_len < minwid) { schar_get_adv(&out_p, fillchar); } // } @@ -1157,33 +1161,36 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, OptIndex op stl_items[idx].start = MAX(stl_items[idx].start, t); } // If the group is shorter than the minimum width, add padding characters. - } else if (abs(stl_items[stl_groupitems[groupdepth]].minwid) > group_len) { - ptrdiff_t min_group_width = stl_items[stl_groupitems[groupdepth]].minwid; + } else if (abs(minwid) > group_len) { + ptrdiff_t fillchar_bytes = (ptrdiff_t)schar_len(fillchar); // If the group is left-aligned, add characters to the right. - if (min_group_width < 0) { - min_group_width = 0 - min_group_width; - while (group_len++ < min_group_width && out_p < out_end_p) { + if (minwid < 0) { + minwid = 0 - minwid; + while (group_len++ < minwid && out_p + fillchar_bytes <= out_end_p) { schar_get_adv(&out_p, fillchar); } // If the group is right-aligned, shift everything to the right and // prepend with filler characters. } else { - // { Move the group to the right - group_len = (min_group_width - group_len) * (int)schar_len(fillchar); - memmove(t + group_len, t, (size_t)(out_p - t)); - if (out_p + group_len >= (out_end_p + 1)) { - group_len = out_end_p - out_p; + ptrdiff_t added_cells = minwid - group_len; + ptrdiff_t added_bytes = added_cells * fillchar_bytes; + if (out_p + added_bytes > out_end_p) { + added_cells = (out_end_p - out_p) / fillchar_bytes; + added_bytes = added_cells * fillchar_bytes; } - out_p += group_len; + + // { Move the group to the right + memmove(t + added_bytes, t, (size_t)(out_p - t)); + out_p += added_bytes; // } // Adjust item start positions for (int n = stl_groupitems[groupdepth] + 1; n < curitem; n++) { - stl_items[n].start += group_len; + stl_items[n].start += added_bytes; } // Prepend the fill characters - for (; group_len > 0; group_len--) { + for (; added_cells > 0; added_cells--) { schar_get_adv(&t, fillchar); } } diff --git a/test/unit/statusline_spec.lua b/test/unit/statusline_spec.lua index 1388063a92..abf45474bb 100644 --- a/test/unit/statusline_spec.lua +++ b/test/unit/statusline_spec.lua @@ -429,6 +429,40 @@ describe('build_stl_str_hl', function() 'aaaa~~b~~c~~d~~e~~fg~~hi~~jk~~lmnop~~qrstuv~~~wxyz' ) + -- item group testing + + statusline_test_align( + 'should right align in right aligned groups', + 30, + '%5(%l%), %5.(%l%), %5.5(%l%), %5.10(%l%)', + '~~~~0, ~~~~0, ~~~~0, ~~~~0', + { expected_cell_count = 26 } + ) + + statusline_test_align( + 'should left align in left aligned groups', + 30, + '%-5(%l%), %-5.(%l%), %-5.5(%l%), %-5.10(%l%)', + '0~~~~, 0~~~~, 0~~~~, 0~~~~', + { expected_cell_count = 26 } + ) + + statusline_test( + 'Should truncate groups according to maxwid', + 30, + '%.5(1234567%), %2.5(1234567%), %5.5(1234567%)', + '<4567, <4567, <4567', + { expected_cell_count = 19 } + ) + + statusline_test_align( + 'Should compensate with fillchar after truncating item group at multicell character', + 20, + '%.5(12🙂345%), %5.5(12🙂345%), %50.5(12🙂345%)', + '<345, <345~, <345~', + { expected_cell_count = 18 } + ) + -- stl item testing local tabline = '' for i = 1, 1000 do