Merge pull request #18908 from zeertzjq/vim-8.2.5066

vim-patch:8.2.{5066,5070}: lcs-leadmultispace
This commit is contained in:
zeertzjq 2022-06-09 22:01:32 +08:00 committed by GitHub
commit d189bfaeb2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 230 additions and 19 deletions

View File

@ -3782,14 +3782,23 @@ A jump table for the options with a short description can be found at |Q_op|.
"space" setting is used. For example, "space" setting is used. For example,
`:set listchars=multispace:---+` shows ten consecutive `:set listchars=multispace:---+` shows ten consecutive
spaces as: spaces as:
---+---+-- ---+---+-- ~
*lcs-lead* *lcs-lead*
lead:c Character to show for leading spaces. When omitted, lead:c Character to show for leading spaces. When omitted,
leading spaces are blank. Overrides the "space" and leading spaces are blank. Overrides the "space" and
"multispace" settings for leading spaces. You can "multispace" settings for leading spaces. You can
combine it with "tab:", for example: > combine it with "tab:", for example: >
:set listchars+=tab:>-,lead:. :set listchars+=tab:>-,lead:.
< *lcs-trail* < *lcs-leadmultispace*
leadmultispace:c...
Like multispace value, but only for leading whitespace
Overrides |lcs-lead| for leading multiple spaces.
`:set listchars=leadmultispace:---+` shows ten consecutive
leading spaces as:
---+---+--XXX ~
Where "XXX" denotes the first non-blank characters in
the line.
*lcs-trail*
trail:c Character to show for trailing spaces. When omitted, trail:c Character to show for trailing spaces. When omitted,
trailing spaces are blank. Overrides the "space" and trailing spaces are blank. Overrides the "space" and
"multispace" settings for trailing spaces. "multispace" settings for trailing spaces.

View File

@ -1232,6 +1232,7 @@ struct window_S {
int lead; int lead;
int trail; int trail;
int *multispace; int *multispace;
int *leadmultispace;
int conceal; int conceal;
} w_p_lcs_chars; } w_p_lcs_chars;

View File

@ -1783,7 +1783,7 @@ void msg_prt_line(char_u *s, int list)
} }
} }
// find end of leading whitespace // find end of leading whitespace
if (curwin->w_p_lcs_chars.lead) { if (curwin->w_p_lcs_chars.lead || curwin->w_p_lcs_chars.leadmultispace != NULL) {
lead = s; lead = s;
while (ascii_iswhite(lead[0])) { while (ascii_iswhite(lead[0])) {
lead++; lead++;
@ -1873,13 +1873,21 @@ void msg_prt_line(char_u *s, int list)
// the same in plain text. // the same in plain text.
attr = HL_ATTR(HLF_0); attr = HL_ATTR(HLF_0);
} else if (c == ' ') { } else if (c == ' ') {
if (lead != NULL && s <= lead) { if (list && lead != NULL && s <= lead && in_multispace
&& curwin->w_p_lcs_chars.leadmultispace != NULL) {
c = curwin->w_p_lcs_chars.leadmultispace[multispace_pos++];
if (curwin->w_p_lcs_chars.leadmultispace[multispace_pos] == NUL) {
multispace_pos = 0;
}
attr = HL_ATTR(HLF_0);
} else if (lead != NULL && s <= lead && curwin->w_p_lcs_chars.lead != NUL) {
c = curwin->w_p_lcs_chars.lead; c = curwin->w_p_lcs_chars.lead;
attr = HL_ATTR(HLF_0); attr = HL_ATTR(HLF_0);
} else if (trail != NULL && s > trail) { } else if (trail != NULL && s > trail) {
c = curwin->w_p_lcs_chars.trail; c = curwin->w_p_lcs_chars.trail;
attr = HL_ATTR(HLF_0); attr = HL_ATTR(HLF_0);
} else if (list && in_multispace && curwin->w_p_lcs_chars.multispace != NULL) { } else if (list && in_multispace
&& curwin->w_p_lcs_chars.multispace != NULL) {
c = curwin->w_p_lcs_chars.multispace[multispace_pos++]; c = curwin->w_p_lcs_chars.multispace[multispace_pos++];
if (curwin->w_p_lcs_chars.multispace[multispace_pos] == NUL) { if (curwin->w_p_lcs_chars.multispace[multispace_pos] == NUL) {
multispace_pos = 0; multispace_pos = 0;

View File

@ -3552,13 +3552,15 @@ static int get_encoded_char_adv(char_u **p)
/// @return error message, NULL if it's OK. /// @return error message, NULL if it's OK.
static char *set_chars_option(win_T *wp, char_u **varp, bool set) static char *set_chars_option(win_T *wp, char_u **varp, bool set)
{ {
int round, i, len, entries; int round, i, len, len2, entries;
char_u *p, *s; char_u *p, *s;
int c1; int c1;
int c2 = 0; int c2 = 0;
int c3 = 0; int c3 = 0;
char_u *last_multispace = NULL; // Last occurrence of "multispace:" char_u *last_multispace = NULL; // Last occurrence of "multispace:"
int multispace_len = 0; // Length of lcs-multispace string char_u *last_lmultispace = NULL; // Last occurrence of "leadmultispace:"
int multispace_len = 0; // Length of lcs-multispace string
int lead_multispace_len = 0; // Length of lcs-leadmultispace string
struct chars_tab { struct chars_tab {
int *cp; ///< char value int *cp; ///< char value
@ -3637,15 +3639,23 @@ static char *set_chars_option(win_T *wp, char_u **varp, bool set)
if (varp == &p_lcs || varp == &wp->w_p_lcs) { if (varp == &p_lcs || varp == &wp->w_p_lcs) {
wp->w_p_lcs_chars.tab1 = NUL; wp->w_p_lcs_chars.tab1 = NUL;
wp->w_p_lcs_chars.tab3 = NUL; wp->w_p_lcs_chars.tab3 = NUL;
if (wp->w_p_lcs_chars.multispace != NULL) {
xfree(wp->w_p_lcs_chars.multispace); xfree(wp->w_p_lcs_chars.multispace);
}
if (multispace_len > 0) { if (multispace_len > 0) {
wp->w_p_lcs_chars.multispace = xmalloc(((size_t)multispace_len + 1) * sizeof(int)); wp->w_p_lcs_chars.multispace = xmalloc(((size_t)multispace_len + 1) * sizeof(int));
wp->w_p_lcs_chars.multispace[multispace_len] = NUL; wp->w_p_lcs_chars.multispace[multispace_len] = NUL;
} else { } else {
wp->w_p_lcs_chars.multispace = NULL; wp->w_p_lcs_chars.multispace = NULL;
} }
xfree(wp->w_p_lcs_chars.leadmultispace);
if (lead_multispace_len > 0) {
wp->w_p_lcs_chars.leadmultispace
= xmalloc(((size_t)lead_multispace_len + 1) * sizeof(int));
wp->w_p_lcs_chars.leadmultispace[lead_multispace_len] = NUL;
} else {
wp->w_p_lcs_chars.leadmultispace = NULL;
}
} }
} }
p = *varp; p = *varp;
@ -3694,6 +3704,7 @@ static char *set_chars_option(win_T *wp, char_u **varp, bool set)
if (i == entries) { if (i == entries) {
len = (int)STRLEN("multispace"); len = (int)STRLEN("multispace");
len2 = (int)STRLEN("leadmultispace");
if ((varp == &p_lcs || varp == &wp->w_p_lcs) if ((varp == &p_lcs || varp == &wp->w_p_lcs)
&& STRNCMP(p, "multispace", len) == 0 && STRNCMP(p, "multispace", len) == 0
&& p[len] == ':' && p[len] == ':'
@ -3725,6 +3736,37 @@ static char *set_chars_option(win_T *wp, char_u **varp, bool set)
} }
p = s; p = s;
} }
} else if ((varp == &p_lcs || varp == &wp->w_p_lcs)
&& STRNCMP(p, "leadmultispace", len2) == 0
&& p[len2] == ':'
&& p[len2 + 1] != NUL) {
s = p + len2 + 1;
if (round == 0) {
// get length of lcs-leadmultispace string in first round
last_lmultispace = p;
lead_multispace_len = 0;
while (*s != NUL && *s != ',') {
c1 = get_encoded_char_adv(&s);
if (c1 == 0 || char2cells(c1) > 1) {
return e_invarg;
}
lead_multispace_len++;
}
if (lead_multispace_len == 0) {
// lcs-leadmultispace cannot be an empty string
return e_invarg;
}
p = s;
} else {
int multispace_pos = 0;
while (*s != NUL && *s != ',') {
c1 = get_encoded_char_adv(&s);
if (p == last_lmultispace) {
wp->w_p_lcs_chars.leadmultispace[multispace_pos++] = c1;
}
}
p = s;
}
} else { } else {
return e_invarg; return e_invarg;
} }

View File

@ -2453,6 +2453,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
if (wp->w_p_list && !has_fold && !end_fill) { if (wp->w_p_list && !has_fold && !end_fill) {
if (wp->w_p_lcs_chars.space if (wp->w_p_lcs_chars.space
|| wp->w_p_lcs_chars.multispace != NULL || wp->w_p_lcs_chars.multispace != NULL
|| wp->w_p_lcs_chars.leadmultispace != NULL
|| wp->w_p_lcs_chars.trail || wp->w_p_lcs_chars.trail
|| wp->w_p_lcs_chars.lead || wp->w_p_lcs_chars.lead
|| wp->w_p_lcs_chars.nbsp) { || wp->w_p_lcs_chars.nbsp) {
@ -2467,7 +2468,7 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
trailcol += (colnr_T)(ptr - line); trailcol += (colnr_T)(ptr - line);
} }
// find end of leading whitespace // find end of leading whitespace
if (wp->w_p_lcs_chars.lead) { if (wp->w_p_lcs_chars.lead || wp->w_p_lcs_chars.leadmultispace != NULL) {
leadcol = 0; leadcol = 0;
while (ascii_iswhite(ptr[leadcol])) { while (ascii_iswhite(ptr[leadcol])) {
leadcol++; leadcol++;
@ -3441,8 +3442,20 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
if ((trailcol != MAXCOL && ptr > line + trailcol && c == ' ') if ((trailcol != MAXCOL && ptr > line + trailcol && c == ' ')
|| (leadcol != 0 && ptr < line + leadcol && c == ' ')) { || (leadcol != 0 && ptr < line + leadcol && c == ' ')) {
c = (ptr > line + trailcol) ? wp->w_p_lcs_chars.trail if (leadcol != 0 && in_multispace && ptr < line + leadcol
: wp->w_p_lcs_chars.lead; && wp->w_p_lcs_chars.leadmultispace != NULL) {
c = wp->w_p_lcs_chars.leadmultispace[multispace_pos++];
if (wp->w_p_lcs_chars.leadmultispace[multispace_pos] == NUL) {
multispace_pos = 0;
}
} else if (ptr > line + trailcol && wp->w_p_lcs_chars.trail) {
c = wp->w_p_lcs_chars.trail;
} else if (ptr < line + leadcol && wp->w_p_lcs_chars.lead) {
c = wp->w_p_lcs_chars.lead;
} else if (leadcol != 0 && c == ' ' && wp->w_p_lcs_chars.space) {
c = wp->w_p_lcs_chars.space;
}
n_attr = 1; n_attr = 1;
extra_attr = win_hl_attr(wp, HLF_0); extra_attr = win_hl_attr(wp, HLF_0);
saved_attr2 = char_attr; // save current attr saved_attr2 = char_attr; // save current attr

View File

@ -132,7 +132,7 @@ func Test_listchars()
\ 'h<<<<<<<<<<<$', \ 'h<<<<<<<<<<<$',
\ '<<<<<<<<<<<<$', \ '<<<<<<<<<<<<$',
\ '>>>>0xx0<<<<$', \ '>>>>0xx0<<<<$',
\ '$' \ '$'
\ ] \ ]
redraw! redraw!
for i in range(1, 5) for i in range(1, 5)
@ -162,7 +162,7 @@ func Test_listchars()
\ ' hyYzZyYzZyY$', \ ' hyYzZyYzZyY$',
\ 'yYzZyYzZyYj $', \ 'yYzZyYzZyYj $',
\ 'yYzZ0yY0yYzZ$', \ 'yYzZ0yY0yYzZ$',
\ '$' \ '$'
\ ] \ ]
redraw! redraw!
for i in range(1, 5) for i in range(1, 5)
@ -172,7 +172,133 @@ func Test_listchars()
call assert_equal(expected, split(execute("%list"), "\n")) call assert_equal(expected, split(execute("%list"), "\n"))
" Test leadmultispace + multispace
normal ggdG
set listchars=eol:$,multispace:yYzZ,nbsp:S
set listchars+=leadmultispace:.-+*
set list
call append(0, [
\ ' ffff ',
\ ' i i  gg',
\ ' h ',
\ ' j ',
\ ' 0 0 ',
\ ])
let expected = [
\ '.-+*ffffyYzZ$',
\ '.-i iSyYzZgg$',
\ ' hyYzZyYzZyY$',
\ '.-+*.-+*.-j $',
\ '.-+*0yY0yYzZ$',
\ '$'
\ ]
redraw!
call assert_equal('eol:$,multispace:yYzZ,nbsp:S,leadmultispace:.-+*', &listchars)
for i in range(1, 5)
call cursor(i, 1)
call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$')))
endfor
call assert_equal(expected, split(execute("%list"), "\n"))
" Test leadmultispace without multispace
normal ggdG
set listchars-=multispace:yYzZ
set listchars+=space:+,trail:>,eol:$
set list
call append(0, [
\ ' ffff ',
\ ' i i gg',
\ ' h ',
\ ' j ',
\ ' 0 0 ',
\ ])
let expected = [
\ '.-+*ffff>>>>$',
\ '.-i+i+++++gg$',
\ '+h>>>>>>>>>>$',
\ '.-+*.-+*.-j>$',
\ '.-+*0++0>>>>$',
\ '$',
\ ]
redraw!
call assert_equal('eol:$,nbsp:S,leadmultispace:.-+*,space:+,trail:>,eol:$', &listchars)
for i in range(1, 5)
call cursor(i, 1)
call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$')))
endfor
call assert_equal(expected, split(execute("%list"), "\n"))
" Test leadmultispace only
normal ggdG
set listchars=eol:$ " Accommodate Nvim default
set listchars=leadmultispace:.-+*
set list
call append(0, [
\ ' ffff ',
\ ' i i gg',
\ ' h ',
\ ' j ',
\ ' 0 0 ',
\ ])
let expected = [
\ '.-+*ffff ',
\ '.-i i gg',
\ ' h ',
\ '.-+*.-+*.-j ',
\ '.-+*0 0 ',
\ ' ',
\ ]
redraw!
call assert_equal('leadmultispace:.-+*', &listchars)
for i in range(1, 5)
call cursor(i, 1)
call assert_equal([expected[i - 1]], ScreenLines(i, 12))
endfor
call assert_equal(expected, split(execute("%list"), "\n"))
" Test leadmultispace and lead and space
normal ggdG
set listchars=eol:$ " Accommodate Nvim default
set listchars+=lead:<,space:-
set listchars+=leadmultispace:.-+*
set list
call append(0, [
\ ' ffff ',
\ ' i i gg',
\ ' h ',
\ ' j ',
\ ' 0 0 ',
\ ])
let expected = [
\ '.-+*ffff----$',
\ '.-i-i-----gg$',
\ '<h----------$',
\ '.-+*.-+*.-j-$',
\ '.-+*0--0----$',
\ '$',
\ ]
redraw!
call assert_equal('eol:$,lead:<,space:-,leadmultispace:.-+*', &listchars)
for i in range(1, 5)
call cursor(i, 1)
call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$')))
endfor
call assert_equal(expected, split(execute("%list"), "\n"))
" the last occurrence of 'multispace:' is used " the last occurrence of 'multispace:' is used
set listchars=eol:$ " Accommodate Nvim default
set listchars+=multispace:yYzZ
set listchars+=space:x,multispace:XyY set listchars+=space:x,multispace:XyY
let expected = [ let expected = [
@ -181,9 +307,10 @@ func Test_listchars()
\ 'xhXyYXyYXyYX$', \ 'xhXyYXyYXyYX$',
\ 'XyYXyYXyYXjx$', \ 'XyYXyYXyYXjx$',
\ 'XyYX0Xy0XyYX$', \ 'XyYX0Xy0XyYX$',
\ '$' \ '$'
\ ] \ ]
redraw! redraw!
call assert_equal('eol:$,multispace:yYzZ,space:x,multispace:XyY', &listchars)
for i in range(1, 5) for i in range(1, 5)
call cursor(i, 1) call cursor(i, 1)
call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$'))) call assert_equal([expected[i - 1]], ScreenLines(i, virtcol('$')))
@ -199,7 +326,7 @@ func Test_listchars()
\ '>h<<<<<<<<<<$', \ '>h<<<<<<<<<<$',
\ '>>>>>>>>>>j<$', \ '>>>>>>>>>>j<$',
\ '>>>>0Xy0<<<<$', \ '>>>>0Xy0<<<<$',
\ '$' \ '$'
\ ] \ ]
redraw! redraw!
for i in range(1, 5) for i in range(1, 5)
@ -219,7 +346,7 @@ func Test_listchars()
\ '>h<<<<<<<<<<$', \ '>h<<<<<<<<<<$',
\ '>>>>>>>>>>j<$', \ '>>>>>>>>>>j<$',
\ '>>>>0xx0<<<<$', \ '>>>>0xx0<<<<$',
\ '$' \ '$'
\ ] \ ]
redraw! redraw!
for i in range(1, 5) for i in range(1, 5)
@ -315,11 +442,13 @@ func Test_listchars_invalid()
call assert_fails('set listchars=x', 'E474:') call assert_fails('set listchars=x', 'E474:')
call assert_fails('set listchars=x', 'E474:') call assert_fails('set listchars=x', 'E474:')
call assert_fails('set listchars=multispace', 'E474:') call assert_fails('set listchars=multispace', 'E474:')
call assert_fails('set listchars=leadmultispace', 'E474:')
" Too short " Too short
call assert_fails('set listchars=space:', 'E474:') call assert_fails('set listchars=space:', 'E474:')
call assert_fails('set listchars=tab:x', 'E474:') call assert_fails('set listchars=tab:x', 'E474:')
call assert_fails('set listchars=multispace:', 'E474:') call assert_fails('set listchars=multispace:', 'E474:')
call assert_fails('set listchars=leadmultispace:', 'E474:')
" One occurrence too short " One occurrence too short
call assert_fails('set listchars=space:,space:x', 'E474:') call assert_fails('set listchars=space:,space:x', 'E474:')
@ -328,6 +457,8 @@ func Test_listchars_invalid()
call assert_fails('set listchars=tab:xx,tab:x', 'E474:') call assert_fails('set listchars=tab:xx,tab:x', 'E474:')
call assert_fails('set listchars=multispace:,multispace:x', 'E474:') call assert_fails('set listchars=multispace:,multispace:x', 'E474:')
call assert_fails('set listchars=multispace:x,multispace:', 'E474:') call assert_fails('set listchars=multispace:x,multispace:', 'E474:')
call assert_fails('set listchars=leadmultispace:,leadmultispace:x', 'E474:')
call assert_fails('set listchars=leadmultispace:x,leadmultispace:', 'E474:')
" Too long " Too long
call assert_fails('set listchars=space:xx', 'E474:') call assert_fails('set listchars=space:xx', 'E474:')
@ -340,6 +471,8 @@ func Test_listchars_invalid()
call assert_fails('set listchars=tab:xx·', 'E474:') call assert_fails('set listchars=tab:xx·', 'E474:')
call assert_fails('set listchars=multispace:·', 'E474:') call assert_fails('set listchars=multispace:·', 'E474:')
call assert_fails('set listchars=multispace:xxx·', 'E474:') call assert_fails('set listchars=multispace:xxx·', 'E474:')
call assert_fails('set listchars=leadmultispace:·', 'E474:')
call assert_fails('set listchars=leadmultispace:xxx·', 'E474:')
" Has control character " Has control character
call assert_fails("set listchars=space:\x01", 'E474:') call assert_fails("set listchars=space:\x01", 'E474:')
@ -354,6 +487,10 @@ func Test_listchars_invalid()
call assert_fails('set listchars=tab:xx\\x01', 'E474:') call assert_fails('set listchars=tab:xx\\x01', 'E474:')
call assert_fails('set listchars=multispace:\\x01', 'E474:') call assert_fails('set listchars=multispace:\\x01', 'E474:')
call assert_fails('set listchars=multispace:xxx\\x01', 'E474:') call assert_fails('set listchars=multispace:xxx\\x01', 'E474:')
call assert_fails("set listchars=leadmultispace:\x01", 'E474:')
call assert_fails('set listchars=leadmultispace:\\x01', 'E474:')
call assert_fails("set listchars=leadmultispace:xxx\x01", 'E474:')
call assert_fails('set listchars=leadmultispace:xxx\\x01', 'E474:')
enew! enew!
set ambiwidth& listchars& ff& set ambiwidth& listchars& ff&

View File

@ -5085,6 +5085,7 @@ static void win_free(win_T *wp, tabpage_T *tp)
clear_winopt(&wp->w_allbuf_opt); clear_winopt(&wp->w_allbuf_opt);
xfree(wp->w_p_lcs_chars.multispace); xfree(wp->w_p_lcs_chars.multispace);
xfree(wp->w_p_lcs_chars.leadmultispace);
vars_clear(&wp->w_vars->dv_hashtab); // free all w: variables vars_clear(&wp->w_vars->dv_hashtab); // free all w: variables
hash_init(&wp->w_vars->dv_hashtab); hash_init(&wp->w_vars->dv_hashtab);