mirror of
https://github.com/neovim/neovim.git
synced 2025-10-26 12:27:24 +00:00
Merge pull request #15630 from zeertzjq/vim-8.2.3424
vim-patch:8.1.{1071,1078,1079,1110},8.2.{2640,3424,3425,3437}
This commit is contained in:
@@ -2596,9 +2596,11 @@ rpcrequest({channel}, {method}[, {args}...])
|
|||||||
Sends an |RPC| request to {channel}
|
Sends an |RPC| request to {channel}
|
||||||
screenattr({row}, {col}) Number attribute at screen position
|
screenattr({row}, {col}) Number attribute at screen position
|
||||||
screenchar({row}, {col}) Number character at screen position
|
screenchar({row}, {col}) Number character at screen position
|
||||||
|
screenchars({row}, {col}) List List of characters at screen position
|
||||||
screencol() Number current cursor column
|
screencol() Number current cursor column
|
||||||
screenpos({winid}, {lnum}, {col}) Dict screen row and col of a text character
|
screenpos({winid}, {lnum}, {col}) Dict screen row and col of a text character
|
||||||
screenrow() Number current cursor row
|
screenrow() Number current cursor row
|
||||||
|
screenstring({row}, {col}) String characters at screen position
|
||||||
search({pattern} [, {flags} [, {stopline} [, {timeout}]]])
|
search({pattern} [, {flags} [, {stopline} [, {timeout}]]])
|
||||||
Number search for {pattern}
|
Number search for {pattern}
|
||||||
searchcount([{options}]) Dict Get or update the last search count
|
searchcount([{options}]) Dict Get or update the last search count
|
||||||
@@ -7669,6 +7671,13 @@ screenchar({row}, {col}) *screenchar()*
|
|||||||
This is mainly to be used for testing.
|
This is mainly to be used for testing.
|
||||||
Returns -1 when row or col is out of range.
|
Returns -1 when row or col is out of range.
|
||||||
|
|
||||||
|
screenchars({row}, {col}) *screenchars()*
|
||||||
|
The result is a List of Numbers. The first number is the same
|
||||||
|
as what |screenchar()| returns. Further numbers are
|
||||||
|
composing characters on top of the base character.
|
||||||
|
This is mainly to be used for testing.
|
||||||
|
Returns an empty List when row or col is out of range.
|
||||||
|
|
||||||
screencol() *screencol()*
|
screencol() *screencol()*
|
||||||
The result is a Number, which is the current screen column of
|
The result is a Number, which is the current screen column of
|
||||||
the cursor. The leftmost column has number 1.
|
the cursor. The leftmost column has number 1.
|
||||||
@@ -7712,6 +7721,14 @@ screenrow() *screenrow()*
|
|||||||
|
|
||||||
Note: Same restrictions as with |screencol()|.
|
Note: Same restrictions as with |screencol()|.
|
||||||
|
|
||||||
|
screenstring({row}, {col}) *screenstring()*
|
||||||
|
The result is a String that contains the base character and
|
||||||
|
any composing characters at position [row, col] on the screen.
|
||||||
|
This is like |screenchars()| but returning a String with the
|
||||||
|
characters.
|
||||||
|
This is mainly to be used for testing.
|
||||||
|
Returns an empty String when row or col is out of range.
|
||||||
|
|
||||||
search({pattern} [, {flags} [, {stopline} [, {timeout}]]]) *search()*
|
search({pattern} [, {flags} [, {stopline} [, {timeout}]]]) *search()*
|
||||||
Search for regexp pattern {pattern}. The search starts at the
|
Search for regexp pattern {pattern}. The search starts at the
|
||||||
cursor position (you can use |cursor()| to set it).
|
cursor position (you can use |cursor()| to set it).
|
||||||
|
|||||||
@@ -3751,16 +3751,25 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
*lcs-space*
|
*lcs-space*
|
||||||
space:c Character to show for a space. When omitted, spaces
|
space:c Character to show for a space. When omitted, spaces
|
||||||
are left blank.
|
are left blank.
|
||||||
|
*lcs-multispace*
|
||||||
|
multispace:c...
|
||||||
|
One or more characters to use cyclically to show for
|
||||||
|
multiple consecutive spaces. Overrides the "space"
|
||||||
|
setting, except for single spaces. When omitted, the
|
||||||
|
"space" setting is used. For example,
|
||||||
|
`:set listchars=multispace:---+` shows ten consecutive
|
||||||
|
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"
|
leading spaces are blank. Overrides the "space" and
|
||||||
setting for leading spaces. You can combine it with
|
"multispace" settings for leading spaces. You can
|
||||||
"tab:", for example: >
|
combine it with "tab:", for example: >
|
||||||
:set listchars+=tab:>-,lead:.
|
:set listchars+=tab:>-,lead:.
|
||||||
< *lcs-trail*
|
< *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"
|
trailing spaces are blank. Overrides the "space" and
|
||||||
setting for trailing spaces.
|
"multispace" settings for trailing spaces.
|
||||||
*lcs-extends*
|
*lcs-extends*
|
||||||
extends:c Character to show in the last column, when 'wrap' is
|
extends:c Character to show in the last column, when 'wrap' is
|
||||||
off and the line continues beyond the right of the
|
off and the line continues beyond the right of the
|
||||||
@@ -3785,7 +3794,8 @@ A jump table for the options with a short description can be found at |Q_op|.
|
|||||||
:set lcs=tab:>-,eol:<,nbsp:%
|
:set lcs=tab:>-,eol:<,nbsp:%
|
||||||
:set lcs=extends:>,precedes:<
|
:set lcs=extends:>,precedes:<
|
||||||
< |hl-NonText| highlighting will be used for "eol", "extends" and
|
< |hl-NonText| highlighting will be used for "eol", "extends" and
|
||||||
"precedes". |hl-Whitespace| for "nbsp", "space", "tab" and "trail".
|
"precedes". |hl-Whitespace| for "nbsp", "space", "tab", "multispace",
|
||||||
|
"lead" and "trail".
|
||||||
|
|
||||||
*'lpl'* *'nolpl'* *'loadplugins'* *'noloadplugins'*
|
*'lpl'* *'nolpl'* *'loadplugins'* *'noloadplugins'*
|
||||||
'loadplugins' 'lpl' boolean (default on)
|
'loadplugins' 'lpl' boolean (default on)
|
||||||
|
|||||||
@@ -744,6 +744,8 @@ Cursor and mark position: *cursor-functions* *mark-functions*
|
|||||||
diff_filler() get the number of filler lines above a line
|
diff_filler() get the number of filler lines above a line
|
||||||
screenattr() get attribute at a screen line/row
|
screenattr() get attribute at a screen line/row
|
||||||
screenchar() get character code at a screen line/row
|
screenchar() get character code at a screen line/row
|
||||||
|
screenchars() get character codes at a screen line/row
|
||||||
|
screenstring() get string of characters at a screen line/row
|
||||||
|
|
||||||
Working with text in the current buffer: *text-functions*
|
Working with text in the current buffer: *text-functions*
|
||||||
getline() get a line or list of lines from the buffer
|
getline() get a line or list of lines from the buffer
|
||||||
|
|||||||
@@ -1214,6 +1214,7 @@ struct window_S {
|
|||||||
int tab3; ///< third tab character
|
int tab3; ///< third tab character
|
||||||
int lead;
|
int lead;
|
||||||
int trail;
|
int trail;
|
||||||
|
int *multispace;
|
||||||
int conceal;
|
int conceal;
|
||||||
} w_p_lcs_chars;
|
} w_p_lcs_chars;
|
||||||
|
|
||||||
|
|||||||
@@ -290,9 +290,11 @@ return {
|
|||||||
rubyeval={args=1},
|
rubyeval={args=1},
|
||||||
screenattr={args=2},
|
screenattr={args=2},
|
||||||
screenchar={args=2},
|
screenchar={args=2},
|
||||||
|
screenchars={args=2},
|
||||||
screencol={},
|
screencol={},
|
||||||
screenpos={args=3},
|
screenpos={args=3},
|
||||||
screenrow={},
|
screenrow={},
|
||||||
|
screenstring={args=2},
|
||||||
search={args={1, 4}},
|
search={args={1, 4}},
|
||||||
searchcount={args={0,1}},
|
searchcount={args={0,1}},
|
||||||
searchdecl={args={1, 3}},
|
searchdecl={args={1, 3}},
|
||||||
|
|||||||
@@ -8108,9 +8108,7 @@ static void f_rpcstop(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// "screenattr()" function
|
||||||
* "screenattr()" function
|
|
||||||
*/
|
|
||||||
static void f_screenattr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
static void f_screenattr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
@@ -8128,9 +8126,7 @@ static void f_screenattr(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||||||
rettv->vval.v_number = c;
|
rettv->vval.v_number = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// "screenchar()" function
|
||||||
* "screenchar()" function
|
|
||||||
*/
|
|
||||||
static void f_screenchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
static void f_screenchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
@@ -8148,11 +8144,34 @@ static void f_screenchar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||||||
rettv->vval.v_number = c;
|
rettv->vval.v_number = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// "screenchars()" function
|
||||||
* "screencol()" function
|
static void f_screenchars(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||||
*
|
{
|
||||||
* First column is 1 to be consistent with virtcol().
|
int row = tv_get_number_chk(&argvars[0], NULL) - 1;
|
||||||
*/
|
int col = tv_get_number_chk(&argvars[1], NULL) - 1;
|
||||||
|
if (row < 0 || row >= default_grid.Rows
|
||||||
|
|| col < 0 || col >= default_grid.Columns) {
|
||||||
|
tv_list_alloc_ret(rettv, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ScreenGrid *grid = &default_grid;
|
||||||
|
screenchar_adjust_grid(&grid, &row, &col);
|
||||||
|
int pcc[MAX_MCO];
|
||||||
|
int c = utfc_ptr2char(grid->chars[grid->line_offset[row] + col], pcc);
|
||||||
|
int composing_len = 0;
|
||||||
|
while (pcc[composing_len] != 0) {
|
||||||
|
composing_len++;
|
||||||
|
}
|
||||||
|
tv_list_alloc_ret(rettv, composing_len + 1);
|
||||||
|
tv_list_append_number(rettv->vval.v_list, c);
|
||||||
|
for (int i = 0; i < composing_len; i++) {
|
||||||
|
tv_list_append_number(rettv->vval.v_list, pcc[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// "screencol()" function
|
||||||
|
//
|
||||||
|
// First column is 1 to be consistent with virtcol().
|
||||||
static void f_screencol(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
static void f_screencol(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||||
{
|
{
|
||||||
rettv->vval.v_number = ui_current_col() + 1;
|
rettv->vval.v_number = ui_current_col() + 1;
|
||||||
@@ -8184,17 +8203,29 @@ static void f_screenpos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||||||
tv_dict_add_nr(dict, S_LEN("endcol"), ecol);
|
tv_dict_add_nr(dict, S_LEN("endcol"), ecol);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// "screenrow()" function
|
||||||
* "screenrow()" function
|
|
||||||
*/
|
|
||||||
static void f_screenrow(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
static void f_screenrow(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||||
{
|
{
|
||||||
rettv->vval.v_number = ui_current_row() + 1;
|
rettv->vval.v_number = ui_current_row() + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// "screenstring()" function
|
||||||
* "search()" function
|
static void f_screenstring(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||||
*/
|
{
|
||||||
|
rettv->vval.v_string = NULL;
|
||||||
|
rettv->v_type = VAR_STRING;
|
||||||
|
int row = tv_get_number_chk(&argvars[0], NULL) - 1;
|
||||||
|
int col = tv_get_number_chk(&argvars[1], NULL) - 1;
|
||||||
|
if (row < 0 || row >= default_grid.Rows
|
||||||
|
|| col < 0 || col >= default_grid.Columns) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ScreenGrid *grid = &default_grid;
|
||||||
|
screenchar_adjust_grid(&grid, &row, &col);
|
||||||
|
rettv->vval.v_string = vim_strsave(grid->chars[grid->line_offset[row] + col]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// "search()" function
|
||||||
static void f_search(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
static void f_search(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||||
{
|
{
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
|
|||||||
@@ -1707,6 +1707,8 @@ void msg_prt_line(char_u *s, int list)
|
|||||||
int n;
|
int n;
|
||||||
int attr = 0;
|
int attr = 0;
|
||||||
char_u *lead = NULL;
|
char_u *lead = NULL;
|
||||||
|
bool in_multispace = false;
|
||||||
|
int multispace_pos = 0;
|
||||||
char_u *trail = NULL;
|
char_u *trail = NULL;
|
||||||
int l;
|
int l;
|
||||||
|
|
||||||
@@ -1771,6 +1773,10 @@ void msg_prt_line(char_u *s, int list)
|
|||||||
} else {
|
} else {
|
||||||
attr = 0;
|
attr = 0;
|
||||||
c = *s++;
|
c = *s++;
|
||||||
|
in_multispace = c == ' ' && ((col > 0 && s[-2] == ' ') || *s == ' ');
|
||||||
|
if (!in_multispace) {
|
||||||
|
multispace_pos = 0;
|
||||||
|
}
|
||||||
if (c == TAB && (!list || curwin->w_p_lcs_chars.tab1)) {
|
if (c == TAB && (!list || curwin->w_p_lcs_chars.tab1)) {
|
||||||
// tab amount depends on current column
|
// tab amount depends on current column
|
||||||
n_extra = tabstop_padding(col,
|
n_extra = tabstop_padding(col,
|
||||||
@@ -1786,11 +1792,11 @@ void msg_prt_line(char_u *s, int list)
|
|||||||
: curwin->w_p_lcs_chars.tab1;
|
: curwin->w_p_lcs_chars.tab1;
|
||||||
c_extra = curwin->w_p_lcs_chars.tab2;
|
c_extra = curwin->w_p_lcs_chars.tab2;
|
||||||
c_final = curwin->w_p_lcs_chars.tab3;
|
c_final = curwin->w_p_lcs_chars.tab3;
|
||||||
attr = HL_ATTR(HLF_8);
|
attr = HL_ATTR(HLF_0);
|
||||||
}
|
}
|
||||||
} else if (c == 160 && list && curwin->w_p_lcs_chars.nbsp != NUL) {
|
} else if (c == 160 && list && curwin->w_p_lcs_chars.nbsp != NUL) {
|
||||||
c = curwin->w_p_lcs_chars.nbsp;
|
c = curwin->w_p_lcs_chars.nbsp;
|
||||||
attr = HL_ATTR(HLF_8);
|
attr = HL_ATTR(HLF_0);
|
||||||
} else if (c == NUL && list && curwin->w_p_lcs_chars.eol != NUL) {
|
} else if (c == NUL && list && curwin->w_p_lcs_chars.eol != NUL) {
|
||||||
p_extra = (char_u *)"";
|
p_extra = (char_u *)"";
|
||||||
c_extra = NUL;
|
c_extra = NUL;
|
||||||
@@ -1807,16 +1813,24 @@ void msg_prt_line(char_u *s, int list)
|
|||||||
c = *p_extra++;
|
c = *p_extra++;
|
||||||
/* Use special coloring to be able to distinguish <hex> from
|
/* Use special coloring to be able to distinguish <hex> from
|
||||||
* the same in plain text. */
|
* the same in plain text. */
|
||||||
attr = HL_ATTR(HLF_8);
|
attr = HL_ATTR(HLF_0);
|
||||||
} else if (c == ' ' && lead != NULL && s <= lead) {
|
} else if (c == ' ') {
|
||||||
c = curwin->w_p_lcs_chars.lead;
|
if (lead != NULL && s <= lead) {
|
||||||
attr = HL_ATTR(HLF_8);
|
c = curwin->w_p_lcs_chars.lead;
|
||||||
} else if (c == ' ' && trail != NULL && s > trail) {
|
attr = HL_ATTR(HLF_0);
|
||||||
c = curwin->w_p_lcs_chars.trail;
|
} else if (trail != NULL && s > trail) {
|
||||||
attr = HL_ATTR(HLF_8);
|
c = curwin->w_p_lcs_chars.trail;
|
||||||
} else if (c == ' ' && list && curwin->w_p_lcs_chars.space != NUL) {
|
attr = HL_ATTR(HLF_0);
|
||||||
c = curwin->w_p_lcs_chars.space;
|
} else if (list && in_multispace && curwin->w_p_lcs_chars.multispace != NULL) {
|
||||||
attr = HL_ATTR(HLF_8);
|
c = curwin->w_p_lcs_chars.multispace[multispace_pos++];
|
||||||
|
if (curwin->w_p_lcs_chars.multispace[multispace_pos] == NUL) {
|
||||||
|
multispace_pos = 0;
|
||||||
|
}
|
||||||
|
attr = HL_ATTR(HLF_0);
|
||||||
|
} else if (list && curwin->w_p_lcs_chars.space != NUL) {
|
||||||
|
c = curwin->w_p_lcs_chars.space;
|
||||||
|
attr = HL_ATTR(HLF_0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3442,6 +3442,8 @@ static char_u *set_chars_option(win_T *wp, char_u **varp, bool set)
|
|||||||
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:"
|
||||||
|
int multispace_len = 0; // Length of lcs-multispace string
|
||||||
|
|
||||||
struct chars_tab {
|
struct chars_tab {
|
||||||
int *cp; ///< char value
|
int *cp; ///< char value
|
||||||
@@ -3511,6 +3513,15 @@ static char_u *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);
|
||||||
|
}
|
||||||
|
if (multispace_len > 0) {
|
||||||
|
wp->w_p_lcs_chars.multispace = xmalloc((size_t)(multispace_len + 1) * sizeof(int));
|
||||||
|
wp->w_p_lcs_chars.multispace[multispace_len] = NUL;
|
||||||
|
} else {
|
||||||
|
wp->w_p_lcs_chars.multispace = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p = *varp;
|
p = *varp;
|
||||||
@@ -3527,27 +3538,27 @@ static char_u *set_chars_option(win_T *wp, char_u **varp, bool set)
|
|||||||
int c1len = utf_ptr2len(s);
|
int c1len = utf_ptr2len(s);
|
||||||
c1 = mb_cptr2char_adv((const char_u **)&s);
|
c1 = mb_cptr2char_adv((const char_u **)&s);
|
||||||
if (mb_char2cells(c1) > 1 || (c1len == 1 && c1 > 127)) {
|
if (mb_char2cells(c1) > 1 || (c1len == 1 && c1 > 127)) {
|
||||||
continue;
|
return e_invarg;
|
||||||
}
|
}
|
||||||
if (tab[i].cp == &wp->w_p_lcs_chars.tab2) {
|
if (tab[i].cp == &wp->w_p_lcs_chars.tab2) {
|
||||||
if (*s == NUL) {
|
if (*s == NUL) {
|
||||||
continue;
|
return e_invarg;
|
||||||
}
|
}
|
||||||
int c2len = utf_ptr2len(s);
|
int c2len = utf_ptr2len(s);
|
||||||
c2 = mb_cptr2char_adv((const char_u **)&s);
|
c2 = mb_cptr2char_adv((const char_u **)&s);
|
||||||
if (mb_char2cells(c2) > 1 || (c2len == 1 && c2 > 127)) {
|
if (mb_char2cells(c2) > 1 || (c2len == 1 && c2 > 127)) {
|
||||||
continue;
|
return e_invarg;
|
||||||
}
|
}
|
||||||
if (!(*s == ',' || *s == NUL)) {
|
if (!(*s == ',' || *s == NUL)) {
|
||||||
int c3len = utf_ptr2len(s);
|
int c3len = utf_ptr2len(s);
|
||||||
c3 = mb_cptr2char_adv((const char_u **)&s);
|
c3 = mb_cptr2char_adv((const char_u **)&s);
|
||||||
if (mb_char2cells(c3) > 1 || (c3len == 1 && c3 > 127)) {
|
if (mb_char2cells(c3) > 1 || (c3len == 1 && c3 > 127)) {
|
||||||
continue;
|
return e_invarg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (*s == ',' || *s == NUL) {
|
if (*s == ',' || *s == NUL) {
|
||||||
if (round) {
|
if (round > 0) {
|
||||||
if (tab[i].cp == &wp->w_p_lcs_chars.tab2) {
|
if (tab[i].cp == &wp->w_p_lcs_chars.tab2) {
|
||||||
wp->w_p_lcs_chars.tab1 = c1;
|
wp->w_p_lcs_chars.tab1 = c1;
|
||||||
wp->w_p_lcs_chars.tab2 = c2;
|
wp->w_p_lcs_chars.tab2 = c2;
|
||||||
@@ -3563,7 +3574,42 @@ static char_u *set_chars_option(win_T *wp, char_u **varp, bool set)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (i == entries) {
|
if (i == entries) {
|
||||||
return e_invarg;
|
len = (int)STRLEN("multispace");
|
||||||
|
if ((varp == &p_lcs || varp == &wp->w_p_lcs)
|
||||||
|
&& STRNCMP(p, "multispace", len) == 0
|
||||||
|
&& p[len] == ':'
|
||||||
|
&& p[len + 1] != NUL) {
|
||||||
|
s = p + len + 1;
|
||||||
|
if (round == 0) {
|
||||||
|
// Get length of lcs-multispace string in the first round
|
||||||
|
last_multispace = p;
|
||||||
|
multispace_len = 0;
|
||||||
|
while (*s != NUL && *s != ',') {
|
||||||
|
int c1len = utf_ptr2len(s);
|
||||||
|
c1 = mb_cptr2char_adv((const char_u **)&s);
|
||||||
|
if (mb_char2cells(c1) > 1 || (c1len == 1 && c1 > 127)) {
|
||||||
|
return e_invarg;
|
||||||
|
}
|
||||||
|
multispace_len++;
|
||||||
|
}
|
||||||
|
if (multispace_len == 0) {
|
||||||
|
// lcs-multispace cannot be an empty string
|
||||||
|
return e_invarg;
|
||||||
|
}
|
||||||
|
p = s;
|
||||||
|
} else {
|
||||||
|
int multispace_pos = 0;
|
||||||
|
while (*s != NUL && *s != ',') {
|
||||||
|
c1 = mb_cptr2char_adv((const char_u **)&s);
|
||||||
|
if (p == last_multispace) {
|
||||||
|
wp->w_p_lcs_chars.multispace[multispace_pos++] = c1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p = s;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return e_invarg;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (*p == ',') {
|
if (*p == ',') {
|
||||||
p++;
|
p++;
|
||||||
|
|||||||
@@ -2081,6 +2081,8 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
|
|||||||
int change_end = -1; // last col of changed area
|
int change_end = -1; // last col of changed area
|
||||||
colnr_T trailcol = MAXCOL; // start of trailing spaces
|
colnr_T trailcol = MAXCOL; // start of trailing spaces
|
||||||
colnr_T leadcol = 0; // start of leading spaces
|
colnr_T leadcol = 0; // start of leading spaces
|
||||||
|
bool in_multispace = false; // in multiple consecutive spaces
|
||||||
|
int multispace_pos = 0; // position in lcs-multispace string
|
||||||
bool need_showbreak = false; // overlong line, skip first x chars
|
bool need_showbreak = false; // overlong line, skip first x chars
|
||||||
sign_attrs_T sattrs[SIGN_SHOW_MAX]; // attributes for signs
|
sign_attrs_T sattrs[SIGN_SHOW_MAX]; // attributes for signs
|
||||||
int num_signs; // number of signs for line
|
int num_signs; // number of signs for line
|
||||||
@@ -2462,6 +2464,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.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) {
|
||||||
@@ -3580,15 +3583,34 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 'list': change char 160 to 'nbsp' and space to 'space'.
|
in_multispace = c == ' ' && ((ptr > line + 1 && ptr[-2] == ' ') || *ptr == ' ');
|
||||||
|
if (!in_multispace) {
|
||||||
|
multispace_pos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 'list': Change char 160 to 'nbsp' and space to 'space'.
|
||||||
|
// But not when the character is followed by a composing
|
||||||
|
// character (use mb_l to check that).
|
||||||
if (wp->w_p_list
|
if (wp->w_p_list
|
||||||
&& (((c == 160
|
&& ((((c == 160 && mb_l == 1)
|
||||||
|| (mb_utf8 && (mb_c == 160 || mb_c == 0x202f)))
|
|| (mb_utf8
|
||||||
&& curwin->w_p_lcs_chars.nbsp)
|
&& ((mb_c == 160 && mb_l == 2)
|
||||||
|| (c == ' ' && curwin->w_p_lcs_chars.space
|
|| (mb_c == 0x202f && mb_l == 3))))
|
||||||
|
&& wp->w_p_lcs_chars.nbsp)
|
||||||
|
|| (c == ' '
|
||||||
|
&& mb_l == 1
|
||||||
|
&& (wp->w_p_lcs_chars.space
|
||||||
|
|| (in_multispace && wp->w_p_lcs_chars.multispace != NULL))
|
||||||
&& ptr - line >= leadcol
|
&& ptr - line >= leadcol
|
||||||
&& ptr - line <= trailcol))) {
|
&& ptr - line <= trailcol))) {
|
||||||
c = (c == ' ') ? wp->w_p_lcs_chars.space : wp->w_p_lcs_chars.nbsp;
|
if (in_multispace && wp->w_p_lcs_chars.multispace != NULL) {
|
||||||
|
c = wp->w_p_lcs_chars.multispace[multispace_pos++];
|
||||||
|
if (wp->w_p_lcs_chars.multispace[multispace_pos] == NUL) {
|
||||||
|
multispace_pos = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
c = (c == ' ') ? wp->w_p_lcs_chars.space : wp->w_p_lcs_chars.nbsp;
|
||||||
|
}
|
||||||
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
|
||||||
|
|||||||
@@ -140,13 +140,100 @@ func Test_listchars()
|
|||||||
|
|
||||||
call assert_equal(expected, split(execute("%list"), "\n"))
|
call assert_equal(expected, split(execute("%list"), "\n"))
|
||||||
|
|
||||||
|
" Test multispace
|
||||||
|
normal ggdG
|
||||||
|
set listchars=eol:$
|
||||||
|
set listchars+=multispace:yYzZ
|
||||||
|
set list
|
||||||
|
|
||||||
|
call append(0, [
|
||||||
|
\ ' ffff ',
|
||||||
|
\ ' i i gg',
|
||||||
|
\ ' h ',
|
||||||
|
\ ' j ',
|
||||||
|
\ ' 0 0 ',
|
||||||
|
\ ])
|
||||||
|
|
||||||
|
let expected = [
|
||||||
|
\ 'yYzZffffyYzZ$',
|
||||||
|
\ 'yYi iyYzZygg$',
|
||||||
|
\ ' hyYzZyYzZyY$',
|
||||||
|
\ 'yYzZyYzZyYj $',
|
||||||
|
\ 'yYzZ0yY0yYzZ$',
|
||||||
|
\ '$'
|
||||||
|
\ ]
|
||||||
|
redraw!
|
||||||
|
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
|
||||||
|
set listchars+=space:x,multispace:XyY
|
||||||
|
|
||||||
|
let expected = [
|
||||||
|
\ 'XyYXffffXyYX$',
|
||||||
|
\ 'XyixiXyYXygg$',
|
||||||
|
\ 'xhXyYXyYXyYX$',
|
||||||
|
\ 'XyYXyYXyYXjx$',
|
||||||
|
\ 'XyYX0Xy0XyYX$',
|
||||||
|
\ '$'
|
||||||
|
\ ]
|
||||||
|
redraw!
|
||||||
|
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"))
|
||||||
|
|
||||||
|
set listchars+=lead:>,trail:<
|
||||||
|
|
||||||
|
let expected = [
|
||||||
|
\ '>>>>ffff<<<<$',
|
||||||
|
\ '>>ixiXyYXygg$',
|
||||||
|
\ '>h<<<<<<<<<<$',
|
||||||
|
\ '>>>>>>>>>>j<$',
|
||||||
|
\ '>>>>0Xy0<<<<$',
|
||||||
|
\ '$'
|
||||||
|
\ ]
|
||||||
|
redraw!
|
||||||
|
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"))
|
||||||
|
|
||||||
|
" removing 'multispace:'
|
||||||
|
set listchars-=multispace:XyY
|
||||||
|
set listchars-=multispace:yYzZ
|
||||||
|
|
||||||
|
let expected = [
|
||||||
|
\ '>>>>ffff<<<<$',
|
||||||
|
\ '>>ixixxxxxgg$',
|
||||||
|
\ '>h<<<<<<<<<<$',
|
||||||
|
\ '>>>>>>>>>>j<$',
|
||||||
|
\ '>>>>0xx0<<<<$',
|
||||||
|
\ '$'
|
||||||
|
\ ]
|
||||||
|
redraw!
|
||||||
|
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 nbsp
|
" test nbsp
|
||||||
normal ggdG
|
normal ggdG
|
||||||
set listchars=nbsp:X,trail:Y
|
set listchars=nbsp:X,trail:Y
|
||||||
set list
|
set list
|
||||||
" Non-breaking space
|
" Non-breaking space
|
||||||
let nbsp = nr2char(0xa0)
|
let nbsp = nr2char(0xa0)
|
||||||
call append(0, [ ">".nbsp."<" ])
|
call append(0, [ ">" .. nbsp .. "<" ])
|
||||||
|
|
||||||
let expected = '>X< '
|
let expected = '>X< '
|
||||||
|
|
||||||
@@ -181,3 +268,100 @@ func Test_listchars()
|
|||||||
enew!
|
enew!
|
||||||
set listchars& ff&
|
set listchars& ff&
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
" Test that unicode listchars characters get properly inserted
|
||||||
|
func Test_listchars_unicode()
|
||||||
|
enew!
|
||||||
|
let oldencoding=&encoding
|
||||||
|
set encoding=utf-8
|
||||||
|
set ff=unix
|
||||||
|
|
||||||
|
set listchars=eol:⇔,space:␣,multispace:≡≢≣,nbsp:≠,tab:←↔→
|
||||||
|
set list
|
||||||
|
|
||||||
|
let nbsp = nr2char(0xa0)
|
||||||
|
call append(0, [" a\tb c" .. nbsp .. "d "])
|
||||||
|
let expected = ['≡≢≣≡≢≣≡≢a←↔↔↔↔↔→b␣c≠d≡≢⇔']
|
||||||
|
redraw!
|
||||||
|
call cursor(1, 1)
|
||||||
|
call assert_equal(expected, ScreenLines(1, virtcol('$')))
|
||||||
|
|
||||||
|
set listchars+=lead:⇨,trail:⇦
|
||||||
|
let expected = ['⇨⇨⇨⇨⇨⇨⇨⇨a←↔↔↔↔↔→b␣c≠d⇦⇦⇔']
|
||||||
|
redraw!
|
||||||
|
call cursor(1, 1)
|
||||||
|
call assert_equal(expected, ScreenLines(1, virtcol('$')))
|
||||||
|
|
||||||
|
let &encoding=oldencoding
|
||||||
|
enew!
|
||||||
|
set listchars& ff&
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
func Test_listchars_invalid()
|
||||||
|
enew!
|
||||||
|
set ff=unix
|
||||||
|
|
||||||
|
set listchars=eol:$
|
||||||
|
set list
|
||||||
|
set ambiwidth=double
|
||||||
|
|
||||||
|
" No colon
|
||||||
|
call assert_fails('set listchars=x', 'E474:')
|
||||||
|
call assert_fails('set listchars=x', 'E474:')
|
||||||
|
call assert_fails('set listchars=multispace', 'E474:')
|
||||||
|
|
||||||
|
" Too short
|
||||||
|
call assert_fails('set listchars=space:', 'E474:')
|
||||||
|
call assert_fails('set listchars=tab:x', 'E474:')
|
||||||
|
call assert_fails('set listchars=multispace:', 'E474:')
|
||||||
|
|
||||||
|
" One occurrence too short
|
||||||
|
call assert_fails('set listchars=space:,space:x', 'E474:')
|
||||||
|
call assert_fails('set listchars=space:x,space:', 'E474:')
|
||||||
|
call assert_fails('set listchars=tab:x,tab:xx', '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:x,multispace:', 'E474:')
|
||||||
|
|
||||||
|
" Too long
|
||||||
|
call assert_fails('set listchars=space:xx', 'E474:')
|
||||||
|
call assert_fails('set listchars=tab:xxxx', 'E474:')
|
||||||
|
|
||||||
|
" Has non-single width character
|
||||||
|
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=tab:xx·', 'E474:')
|
||||||
|
call assert_fails('set listchars=multispace:·', 'E474:')
|
||||||
|
call assert_fails('set listchars=multispace:xxx·', 'E474:')
|
||||||
|
|
||||||
|
enew!
|
||||||
|
set ambiwidth& listchars& ff&
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
" Tests that space characters following composing character won't get replaced
|
||||||
|
" by listchars.
|
||||||
|
func Test_listchars_composing()
|
||||||
|
enew!
|
||||||
|
let oldencoding=&encoding
|
||||||
|
set encoding=utf-8
|
||||||
|
set ff=unix
|
||||||
|
set list
|
||||||
|
|
||||||
|
set listchars=eol:$,space:_,nbsp:=
|
||||||
|
|
||||||
|
let nbsp1 = nr2char(0xa0)
|
||||||
|
let nbsp2 = nr2char(0x202f)
|
||||||
|
call append(0, [
|
||||||
|
\ " \u3099\t \u309A" .. nbsp1 .. nbsp1 .. "\u0302" .. nbsp2 .. nbsp2 .. "\u0302",
|
||||||
|
\ ])
|
||||||
|
let expected = [
|
||||||
|
\ "_ \u3099^I \u309A=" .. nbsp1 .. "\u0302=" .. nbsp2 .. "\u0302$"
|
||||||
|
\ ]
|
||||||
|
redraw!
|
||||||
|
call cursor(1, 1)
|
||||||
|
call assert_equal(expected, ScreenLines(1, virtcol('$')))
|
||||||
|
let &encoding=oldencoding
|
||||||
|
enew!
|
||||||
|
set listchars& ff&
|
||||||
|
endfunction
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
" Tests for Unicode manipulations
|
" Tests for Unicode manipulations
|
||||||
|
|
||||||
|
source view_util.vim
|
||||||
|
|
||||||
" Visual block Insert adjusts for multi-byte char
|
" Visual block Insert adjusts for multi-byte char
|
||||||
func Test_visual_block_insert()
|
func Test_visual_block_insert()
|
||||||
@@ -61,6 +62,40 @@ func Test_getvcol()
|
|||||||
call assert_equal(2, virtcol("']"))
|
call assert_equal(2, virtcol("']"))
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func Test_screenchar_utf8()
|
||||||
|
new
|
||||||
|
|
||||||
|
" 1-cell, with composing characters
|
||||||
|
call setline(1, ["ABC\u0308"])
|
||||||
|
redraw
|
||||||
|
call assert_equal([0x0041], screenchars(1, 1))
|
||||||
|
call assert_equal([0x0042], screenchars(1, 2))
|
||||||
|
call assert_equal([0x0043, 0x0308], screenchars(1, 3))
|
||||||
|
call assert_equal("A", screenstring(1, 1))
|
||||||
|
call assert_equal("B", screenstring(1, 2))
|
||||||
|
call assert_equal("C\u0308", screenstring(1, 3))
|
||||||
|
|
||||||
|
" 2-cells, with composing characters
|
||||||
|
let text = "\u3042\u3044\u3046\u3099"
|
||||||
|
call setline(1, text)
|
||||||
|
redraw
|
||||||
|
call assert_equal([0x3042], screenchars(1, 1))
|
||||||
|
call assert_equal([0], screenchars(1, 2))
|
||||||
|
call assert_equal([0x3044], screenchars(1, 3))
|
||||||
|
call assert_equal([0], screenchars(1, 4))
|
||||||
|
call assert_equal([0x3046, 0x3099], screenchars(1, 5))
|
||||||
|
|
||||||
|
call assert_equal("\u3042", screenstring(1, 1))
|
||||||
|
call assert_equal("", screenstring(1, 2))
|
||||||
|
call assert_equal("\u3044", screenstring(1, 3))
|
||||||
|
call assert_equal("", screenstring(1, 4))
|
||||||
|
call assert_equal("\u3046\u3099", screenstring(1, 5))
|
||||||
|
|
||||||
|
call assert_equal([text . ' '], ScreenLines(1, 8))
|
||||||
|
|
||||||
|
bwipe!
|
||||||
|
endfunc
|
||||||
|
|
||||||
func Test_list2str_str2list_utf8()
|
func Test_list2str_str2list_utf8()
|
||||||
" One Unicode codepoint
|
" One Unicode codepoint
|
||||||
let s = "\u3042\u3044"
|
let s = "\u3042\u3044"
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ func Screenline(lnum)
|
|||||||
return matchstr(line, '^.\{-}\ze\s*$')
|
return matchstr(line, '^.\{-}\ze\s*$')
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
" Get text on the screen, including composing characters.
|
||||||
" ScreenLines(lnum, width) or
|
" ScreenLines(lnum, width) or
|
||||||
" ScreenLines([start, end], width)
|
" ScreenLines([start, end], width)
|
||||||
function! ScreenLines(lnum, width) abort
|
function! ScreenLines(lnum, width) abort
|
||||||
@@ -29,7 +30,7 @@ function! ScreenLines(lnum, width) abort
|
|||||||
endif
|
endif
|
||||||
let lines = []
|
let lines = []
|
||||||
for l in range(start, end)
|
for l in range(start, end)
|
||||||
let lines += [join(map(range(1, a:width), 'nr2char(screenchar(l, v:val))'), '')]
|
let lines += [join(map(range(1, a:width), 'screenstring(l, v:val)'), '')]
|
||||||
endfor
|
endfor
|
||||||
return lines
|
return lines
|
||||||
endfunction
|
endfunction
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ static long xdl_get_rec(xdfile_t *xdf, long ri, char const **rec) {
|
|||||||
|
|
||||||
|
|
||||||
static int xdl_emit_record(xdfile_t *xdf, long ri, char const *pre, xdemitcb_t *ecb) {
|
static int xdl_emit_record(xdfile_t *xdf, long ri, char const *pre, xdemitcb_t *ecb) {
|
||||||
long size, psize = strlen(pre);
|
long size, psize = (long)strlen(pre);
|
||||||
char const *rec;
|
char const *rec;
|
||||||
|
|
||||||
size = xdl_get_rec(xdf, ri, &rec);
|
size = xdl_get_rec(xdf, ri, &rec);
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ int xdl_emit_diffrec(char const *rec, long size, char const *pre, long psize,
|
|||||||
mb[1].size = size;
|
mb[1].size = size;
|
||||||
if (size > 0 && rec[size - 1] != '\n') {
|
if (size > 0 && rec[size - 1] != '\n') {
|
||||||
mb[2].ptr = (char *) "\n\\ No newline at end of file\n";
|
mb[2].ptr = (char *) "\n\\ No newline at end of file\n";
|
||||||
mb[2].size = strlen(mb[2].ptr);
|
mb[2].size = (long)strlen(mb[2].ptr);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
if (ecb->out_line(ecb->priv, mb, i) < 0) {
|
if (ecb->out_line(ecb->priv, mb, i) < 0) {
|
||||||
|
|||||||
Reference in New Issue
Block a user