mirror of
https://github.com/neovim/neovim.git
synced 2024-12-31 17:13:26 -07:00
vim-patch:9.0.1578: SpellCap highlight not always updated when needed (#23755)
Problem: SpellCap highlight not always updated when needed.
Solution: Handle updating line below closed fold and other situations where
only part of the window is redrawn. (Luuk van Baal, closes vim/vim#12428,
closes vim/vim#12420)
2ac6497f0e
This commit is contained in:
parent
ee986ee044
commit
f733595e79
@ -1028,7 +1028,7 @@ static void win_line_continue(winlinevars_T *wlv)
|
|||||||
/// @param lnum line to display
|
/// @param lnum line to display
|
||||||
/// @param startrow first row relative to window grid
|
/// @param startrow first row relative to window grid
|
||||||
/// @param endrow last grid row to be redrawn
|
/// @param endrow last grid row to be redrawn
|
||||||
/// @param nochange not updating for changed text
|
/// @param mod_top top line updated for changed text
|
||||||
/// @param number_only only update the number column
|
/// @param number_only only update the number column
|
||||||
/// @param foldinfo fold info for this line
|
/// @param foldinfo fold info for this line
|
||||||
/// @param[in, out] providers decoration providers active this line
|
/// @param[in, out] providers decoration providers active this line
|
||||||
@ -1036,7 +1036,7 @@ static void win_line_continue(winlinevars_T *wlv)
|
|||||||
/// or explicitly return `false`.
|
/// or explicitly return `false`.
|
||||||
///
|
///
|
||||||
/// @return the number of last row the line occupies.
|
/// @return the number of last row the line occupies.
|
||||||
int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange, bool number_only,
|
int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int mod_top, bool number_only,
|
||||||
foldinfo_T foldinfo, DecorProviders *providers, char **provider_err)
|
foldinfo_T foldinfo, DecorProviders *providers, char **provider_err)
|
||||||
{
|
{
|
||||||
winlinevars_T wlv; // variables passed between functions
|
winlinevars_T wlv; // variables passed between functions
|
||||||
@ -1227,12 +1227,16 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
|
|||||||
|
|
||||||
// When there was a sentence end in the previous line may require a
|
// When there was a sentence end in the previous line may require a
|
||||||
// word starting with capital in this line. In line 1 always check
|
// word starting with capital in this line. In line 1 always check
|
||||||
// the first word.
|
// the first word. Also check for sentence end in the line above
|
||||||
if (lnum != capcol_lnum) {
|
// when updating the first row in a window, the top line with
|
||||||
cap_col = -1;
|
// changed text in a window, or if the previous line is folded.
|
||||||
}
|
if (lnum == 1
|
||||||
if (lnum == 1) {
|
|| ((startrow == 0 || mod_top == lnum
|
||||||
|
|| hasFoldingWin(wp, lnum - 1, NULL, NULL, true, NULL))
|
||||||
|
&& check_need_cap(wp, lnum, 0))) {
|
||||||
cap_col = 0;
|
cap_col = 0;
|
||||||
|
} else if (lnum != capcol_lnum) {
|
||||||
|
cap_col = -1;
|
||||||
}
|
}
|
||||||
capcol_lnum = 0;
|
capcol_lnum = 0;
|
||||||
}
|
}
|
||||||
@ -2207,7 +2211,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool nochange,
|
|||||||
p = prev_ptr;
|
p = prev_ptr;
|
||||||
}
|
}
|
||||||
cap_col -= (int)(prev_ptr - line);
|
cap_col -= (int)(prev_ptr - line);
|
||||||
size_t tmplen = spell_check(wp, p, &spell_hlf, &cap_col, nochange);
|
size_t tmplen = spell_check(wp, p, &spell_hlf, &cap_col, mod_top == 0);
|
||||||
assert(tmplen <= INT_MAX);
|
assert(tmplen <= INT_MAX);
|
||||||
int len = (int)tmplen;
|
int len = (int)tmplen;
|
||||||
word_end = (int)v + len;
|
word_end = (int)v + len;
|
||||||
|
@ -2222,9 +2222,8 @@ static void win_update(win_T *wp, DecorProviders *providers)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Display one line
|
// Display one line
|
||||||
row = win_line(wp, lnum, srow,
|
row = win_line(wp, lnum, srow, foldinfo.fi_lines ? srow : wp->w_grid.rows,
|
||||||
foldinfo.fi_lines ? srow : wp->w_grid.rows,
|
mod_top, false, foldinfo, &line_providers, &provider_err);
|
||||||
mod_top == 0, false, foldinfo, &line_providers, &provider_err);
|
|
||||||
|
|
||||||
if (foldinfo.fi_lines == 0) {
|
if (foldinfo.fi_lines == 0) {
|
||||||
wp->w_lines[idx].wl_folded = false;
|
wp->w_lines[idx].wl_folded = false;
|
||||||
@ -2261,7 +2260,7 @@ static void win_update(win_T *wp, DecorProviders *providers)
|
|||||||
// text doesn't need to be drawn, but the number column does.
|
// text doesn't need to be drawn, but the number column does.
|
||||||
foldinfo_T info = wp->w_p_cul && lnum == wp->w_cursor.lnum ?
|
foldinfo_T info = wp->w_p_cul && lnum == wp->w_cursor.lnum ?
|
||||||
cursorline_fi : fold_info(wp, lnum);
|
cursorline_fi : fold_info(wp, lnum);
|
||||||
(void)win_line(wp, lnum, srow, wp->w_grid.rows, true, true,
|
(void)win_line(wp, lnum, srow, wp->w_grid.rows, mod_top, true,
|
||||||
info, &line_providers, &provider_err);
|
info, &line_providers, &provider_err);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2359,7 +2358,7 @@ static void win_update(win_T *wp, DecorProviders *providers)
|
|||||||
// for ml_line_count+1 and only draw filler lines
|
// for ml_line_count+1 and only draw filler lines
|
||||||
foldinfo_T info = { 0 };
|
foldinfo_T info = { 0 };
|
||||||
row = win_line(wp, wp->w_botline, row, wp->w_grid.rows,
|
row = win_line(wp, wp->w_botline, row, wp->w_grid.rows,
|
||||||
false, false, info, &line_providers, &provider_err);
|
mod_top, false, info, &line_providers, &provider_err);
|
||||||
}
|
}
|
||||||
} else if (dollar_vcol == -1) {
|
} else if (dollar_vcol == -1) {
|
||||||
wp->w_botline = lnum;
|
wp->w_botline = lnum;
|
||||||
|
@ -1312,7 +1312,7 @@ size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *att
|
|||||||
} else if (curline && wp == curwin) {
|
} else if (curline && wp == curwin) {
|
||||||
// For spellbadword(): check if first word needs a capital.
|
// For spellbadword(): check if first word needs a capital.
|
||||||
col = (colnr_T)getwhitecols(line);
|
col = (colnr_T)getwhitecols(line);
|
||||||
if (check_need_cap(lnum, col)) {
|
if (check_need_cap(curwin, lnum, col)) {
|
||||||
capcol = col;
|
capcol = col;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2536,25 +2536,24 @@ int spell_casefold(const win_T *wp, char *str, int len, char *buf, int buflen)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if the word at line "lnum" column "col" is required to start with a
|
// Check if the word at line "lnum" column "col" is required to start with a
|
||||||
// capital. This uses 'spellcapcheck' of the current buffer.
|
// capital. This uses 'spellcapcheck' of the buffer in window "wp".
|
||||||
bool check_need_cap(linenr_T lnum, colnr_T col)
|
bool check_need_cap(win_T *wp, linenr_T lnum, colnr_T col)
|
||||||
{
|
{
|
||||||
bool need_cap = false;
|
if (wp->w_s->b_cap_prog == NULL) {
|
||||||
|
|
||||||
if (curwin->w_s->b_cap_prog == NULL) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *line = get_cursor_line_ptr();
|
bool need_cap = false;
|
||||||
|
char *line = col ? ml_get_buf(wp->w_buffer, lnum, false) : NULL;
|
||||||
char *line_copy = NULL;
|
char *line_copy = NULL;
|
||||||
colnr_T endcol = 0;
|
colnr_T endcol = 0;
|
||||||
if (getwhitecols(line) >= (int)col) {
|
if (col == 0 || getwhitecols(line) >= col) {
|
||||||
// At start of line, check if previous line is empty or sentence
|
// At start of line, check if previous line is empty or sentence
|
||||||
// ends there.
|
// ends there.
|
||||||
if (lnum == 1) {
|
if (lnum == 1) {
|
||||||
need_cap = true;
|
need_cap = true;
|
||||||
} else {
|
} else {
|
||||||
line = ml_get(lnum - 1);
|
line = ml_get_buf(wp->w_buffer, lnum - 1, false);
|
||||||
if (*skipwhite(line) == NUL) {
|
if (*skipwhite(line) == NUL) {
|
||||||
need_cap = true;
|
need_cap = true;
|
||||||
} else {
|
} else {
|
||||||
@ -2571,13 +2570,13 @@ bool check_need_cap(linenr_T lnum, colnr_T col)
|
|||||||
if (endcol > 0) {
|
if (endcol > 0) {
|
||||||
// Check if sentence ends before the bad word.
|
// Check if sentence ends before the bad word.
|
||||||
regmatch_T regmatch = {
|
regmatch_T regmatch = {
|
||||||
.regprog = curwin->w_s->b_cap_prog,
|
.regprog = wp->w_s->b_cap_prog,
|
||||||
.rm_ic = false
|
.rm_ic = false
|
||||||
};
|
};
|
||||||
char *p = line + endcol;
|
char *p = line + endcol;
|
||||||
while (true) {
|
while (true) {
|
||||||
MB_PTR_BACK(line, p);
|
MB_PTR_BACK(line, p);
|
||||||
if (p == line || spell_iswordp_nmw(p, curwin)) {
|
if (p == line || spell_iswordp_nmw(p, wp)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (vim_regexec(®match, p, 0)
|
if (vim_regexec(®match, p, 0)
|
||||||
@ -2586,7 +2585,7 @@ bool check_need_cap(linenr_T lnum, colnr_T col)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
curwin->w_s->b_cap_prog = regmatch.regprog;
|
wp->w_s->b_cap_prog = regmatch.regprog;
|
||||||
}
|
}
|
||||||
|
|
||||||
xfree(line_copy);
|
xfree(line_copy);
|
||||||
@ -3601,7 +3600,7 @@ static bool spell_expand_need_cap;
|
|||||||
|
|
||||||
void spell_expand_check_cap(colnr_T col)
|
void spell_expand_check_cap(colnr_T col)
|
||||||
{
|
{
|
||||||
spell_expand_need_cap = check_need_cap(curwin->w_cursor.lnum, col);
|
spell_expand_need_cap = check_need_cap(curwin, curwin->w_cursor.lnum, col);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get list of spelling suggestions.
|
// Get list of spelling suggestions.
|
||||||
|
@ -509,7 +509,7 @@ void spell_suggest(int count)
|
|||||||
// Get the word and its length.
|
// Get the word and its length.
|
||||||
|
|
||||||
// Figure out if the word should be capitalised.
|
// Figure out if the word should be capitalised.
|
||||||
int need_cap = check_need_cap(curwin->w_cursor.lnum, curwin->w_cursor.col);
|
int need_cap = check_need_cap(curwin, curwin->w_cursor.lnum, curwin->w_cursor.col);
|
||||||
|
|
||||||
// Make a copy of current line since autocommands may free the line.
|
// Make a copy of current line since autocommands may free the line.
|
||||||
line = xstrdup(get_cursor_line_ptr());
|
line = xstrdup(get_cursor_line_ptr());
|
||||||
|
@ -28,6 +28,7 @@ describe("'spell'", function()
|
|||||||
[7] = {foreground = Screen.colors.Blue},
|
[7] = {foreground = Screen.colors.Blue},
|
||||||
[8] = {foreground = Screen.colors.Blue, special = Screen.colors.Red, undercurl = true},
|
[8] = {foreground = Screen.colors.Blue, special = Screen.colors.Red, undercurl = true},
|
||||||
[9] = {bold = true},
|
[9] = {bold = true},
|
||||||
|
[10] = {background = Screen.colors.LightGrey, foreground = Screen.colors.DarkBlue},
|
||||||
})
|
})
|
||||||
end)
|
end)
|
||||||
|
|
||||||
@ -82,7 +83,7 @@ describe("'spell'", function()
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
-- oldtest: Test_spell_screendump_spellcap()
|
-- oldtest: Test_spell_screendump_spellcap()
|
||||||
it('has correct highlight at start of line with trailing space', function()
|
it('SpellCap highlight at start of line', function()
|
||||||
exec([=[
|
exec([=[
|
||||||
call setline(1, [
|
call setline(1, [
|
||||||
\" This line has a sepll error. and missing caps and trailing spaces. ",
|
\" This line has a sepll error. and missing caps and trailing spaces. ",
|
||||||
@ -117,7 +118,7 @@ describe("'spell'", function()
|
|||||||
|
|
|
|
||||||
]])
|
]])
|
||||||
-- Deleting a full stop removes missing Cap in next line
|
-- Deleting a full stop removes missing Cap in next line
|
||||||
feed('5Gddk$x')
|
feed('5Gdd<C-L>k$x')
|
||||||
screen:expect([[
|
screen:expect([[
|
||||||
This line has a {1:sepll} error. {2:and} missing caps and trailing spaces. |
|
This line has a {1:sepll} error. {2:and} missing caps and trailing spaces. |
|
||||||
{2:another} missing cap here. |
|
{2:another} missing cap here. |
|
||||||
@ -140,6 +141,43 @@ describe("'spell'", function()
|
|||||||
{0:~ }|
|
{0:~ }|
|
||||||
|
|
|
|
||||||
]])
|
]])
|
||||||
|
-- Folding an empty line does not remove Cap in next line
|
||||||
|
feed('uzfk:<Esc>')
|
||||||
|
screen:expect([[
|
||||||
|
This line has a {1:sepll} error. {2:and} missing caps and trailing spaces. |
|
||||||
|
{2:another} missing cap here. |
|
||||||
|
Not |
|
||||||
|
{10:^+-- 2 lines: and here.·························································}|
|
||||||
|
{2:and} here. |
|
||||||
|
{0:~ }|
|
||||||
|
{0:~ }|
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
-- Folding the end of a sentence does not remove Cap in next line
|
||||||
|
-- and editing a line does not remove Cap in current line
|
||||||
|
feed('Jzfkk$x')
|
||||||
|
screen:expect([[
|
||||||
|
This line has a {1:sepll} error. {2:and} missing caps and trailing spaces. |
|
||||||
|
{2:another} missing cap her^e |
|
||||||
|
{10:+-- 2 lines: Not·······························································}|
|
||||||
|
{2:and} here. |
|
||||||
|
{0:~ }|
|
||||||
|
{0:~ }|
|
||||||
|
{0:~ }|
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
-- Cap is correctly applied in the first row of a window
|
||||||
|
feed('<C-E><C-L>')
|
||||||
|
screen:expect([[
|
||||||
|
{2:another} missing cap her^e |
|
||||||
|
{10:+-- 2 lines: Not·······························································}|
|
||||||
|
{2:and} here. |
|
||||||
|
{0:~ }|
|
||||||
|
{0:~ }|
|
||||||
|
{0:~ }|
|
||||||
|
{0:~ }|
|
||||||
|
|
|
||||||
|
]])
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- oldtest: Test_spell_compatible()
|
-- oldtest: Test_spell_compatible()
|
||||||
|
@ -1003,13 +1003,26 @@ func Test_spell_screendump_spellcap()
|
|||||||
call VerifyScreenDump(buf, 'Test_spell_3', {})
|
call VerifyScreenDump(buf, 'Test_spell_3', {})
|
||||||
|
|
||||||
" Deleting a full stop removes missing Cap in next line
|
" Deleting a full stop removes missing Cap in next line
|
||||||
call term_sendkeys(buf, "5Gddk$x")
|
call term_sendkeys(buf, "5Gdd\<C-L>k$x")
|
||||||
call VerifyScreenDump(buf, 'Test_spell_4', {})
|
call VerifyScreenDump(buf, 'Test_spell_4', {})
|
||||||
|
|
||||||
" Undo also updates the next line (go to command line to remove message)
|
" Undo also updates the next line (go to command line to remove message)
|
||||||
call term_sendkeys(buf, "u:\<Esc>")
|
call term_sendkeys(buf, "u:\<Esc>")
|
||||||
call VerifyScreenDump(buf, 'Test_spell_5', {})
|
call VerifyScreenDump(buf, 'Test_spell_5', {})
|
||||||
|
|
||||||
|
" Folding an empty line does not remove Cap in next line
|
||||||
|
call term_sendkeys(buf, "uzfk:\<Esc>")
|
||||||
|
call VerifyScreenDump(buf, 'Test_spell_6', {})
|
||||||
|
|
||||||
|
" Folding the end of a sentence does not remove Cap in next line
|
||||||
|
" and editing a line does not remove Cap in current line
|
||||||
|
call term_sendkeys(buf, "Jzfkk$x")
|
||||||
|
call VerifyScreenDump(buf, 'Test_spell_7', {})
|
||||||
|
|
||||||
|
" Cap is correctly applied in the first row of a window
|
||||||
|
call term_sendkeys(buf, "\<C-E>\<C-L>")
|
||||||
|
call VerifyScreenDump(buf, 'Test_spell_8', {})
|
||||||
|
|
||||||
" clean up
|
" clean up
|
||||||
call StopVimInTerminal(buf)
|
call StopVimInTerminal(buf)
|
||||||
endfunc
|
endfunc
|
||||||
|
Loading…
Reference in New Issue
Block a user