# HG changeset patch # User Bram Moolenaar # Date 1685031304 -7200 # Node ID 0632606a25306e327dcf8d4fb69c475d29b1f6ad # Parent 8064be0111ef538ae300e2a54a760c8145738185 patch 9.0.1578: SpellCap highlight not always updated when needed Commit: https://github.com/vim/vim/commit/2ac6497f0ef186f0e3ba67d7f0a485bfb612bb08 Author: Luuk van Baal Date: Thu May 25 17:14:42 2023 +0100 patch 9.0.1578: SpellCap highlight not always updated when needed 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 #12428, closes #12420) diff --git a/src/drawline.c b/src/drawline.c --- a/src/drawline.c +++ b/src/drawline.c @@ -1062,7 +1062,7 @@ win_line( linenr_T lnum, int startrow, int endrow, - int nochange UNUSED, // not updating for changed text + int mod_top UNUSED, // top line updated for changed text int number_only) // only update the number column { winlinevars_T wlv; // variables passed between functions @@ -1314,11 +1314,18 @@ win_line( // 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 - // the first word. - if (lnum != capcol_lnum) + // the first word. Also check for sentence end in the line above + // when updating the first row in a window, the top line with + // changed text in a window, or if the previous line is folded. + if (lnum == 1 + || ((startrow == 0 || mod_top == lnum +#ifdef FEAT_FOLDING + || hasFoldingWin(wp, lnum - 1, NULL, NULL, TRUE, NULL) +#endif + ) && check_need_cap(wp, lnum, 0))) + cap_col = 0; + else if (lnum != capcol_lnum) cap_col = -1; - if (lnum == 1) - cap_col = 0; capcol_lnum = 0; } #endif @@ -2787,7 +2794,7 @@ win_line( p = prev_ptr; cap_col -= (int)(prev_ptr - line); len = spell_check(wp, p, &spell_hlf, &cap_col, - nochange); + mod_top == 0); word_end = v + len; // In Insert mode only highlight a word that diff --git a/src/drawscreen.c b/src/drawscreen.c --- a/src/drawscreen.c +++ b/src/drawscreen.c @@ -2487,8 +2487,7 @@ win_update(win_T *wp) #endif // Display one line. - row = win_line(wp, lnum, srow, wp->w_height, - mod_top == 0, FALSE); + row = win_line(wp, lnum, srow, wp->w_height, mod_top, FALSE); #ifdef FEAT_FOLDING wp->w_lines[idx].wl_folded = FALSE; @@ -2535,7 +2534,7 @@ win_update(win_T *wp) fold_line(wp, fold_count, &win_foldinfo, lnum, row); else #endif - (void)win_line(wp, lnum, srow, wp->w_height, TRUE, TRUE); + (void)win_line(wp, lnum, srow, wp->w_height, mod_top, TRUE); } // This line does not need to be drawn, advance to the next one. diff --git a/src/proto/spell.pro b/src/proto/spell.pro --- a/src/proto/spell.pro +++ b/src/proto/spell.pro @@ -28,7 +28,7 @@ void init_spell_chartab(void); int spell_iswordp(char_u *p, win_T *wp); int spell_iswordp_nmw(char_u *p, win_T *wp); int spell_casefold(win_T *wp, char_u *str, int len, char_u *buf, int buflen); -int check_need_cap(linenr_T lnum, colnr_T col); +int check_need_cap(win_T *wp, linenr_T lnum, colnr_T col); void ex_spellrepall(exarg_T *eap); void onecap_copy(char_u *word, char_u *wcopy, int upper); void allcap_copy(char_u *word, char_u *wcopy); diff --git a/src/spell.c b/src/spell.c --- a/src/spell.c +++ b/src/spell.c @@ -1342,7 +1342,7 @@ spell_move_to( { // For spellbadword(): check if first word needs a capital. col = getwhitecols(line); - if (check_need_cap(lnum, col)) + if (check_need_cap(curwin, lnum, col)) capcol = col; // Need to get the line again, may have looked at the previous @@ -2815,24 +2815,20 @@ spell_casefold( /* * 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". */ int -check_need_cap(linenr_T lnum, colnr_T col) +check_need_cap(win_T *wp, linenr_T lnum, colnr_T col) { + if (wp->w_s->b_cap_prog == NULL) + return FALSE; + int need_cap = FALSE; - char_u *line; + char_u *line = col ? ml_get_buf(wp->w_buffer, lnum, FALSE) : NULL; char_u *line_copy = NULL; - char_u *p; - colnr_T endcol; - regmatch_T regmatch; - - if (curwin->w_s->b_cap_prog == NULL) - return FALSE; - - line = ml_get_curline(); - endcol = 0; - if (getwhitecols(line) >= (int)col) + colnr_T endcol = 0; + + if (col == 0 || getwhitecols(line) >= col) { // At start of line, check if previous line is empty or sentence // ends there. @@ -2840,13 +2836,16 @@ check_need_cap(linenr_T lnum, colnr_T co need_cap = TRUE; else { - line = ml_get(lnum - 1); + line = ml_get_buf(wp->w_buffer, lnum - 1, FALSE); if (*skipwhite(line) == NUL) need_cap = TRUE; else { // Append a space in place of the line break. line_copy = concat_str(line, (char_u *)" "); + if (line_copy == NULL) + return FALSE; + line = line_copy; endcol = (colnr_T)STRLEN(line); } @@ -2858,13 +2857,14 @@ check_need_cap(linenr_T lnum, colnr_T co if (endcol > 0) { // Check if sentence ends before the bad word. - regmatch.regprog = curwin->w_s->b_cap_prog; + regmatch_T regmatch; + regmatch.regprog = wp->w_s->b_cap_prog; regmatch.rm_ic = FALSE; - p = line + endcol; + char_u *p = line + endcol; for (;;) { MB_PTR_BACK(line, p); - if (p == line || spell_iswordp_nmw(p, curwin)) + if (p == line || spell_iswordp_nmw(p, wp)) break; if (vim_regexec(®match, p, 0) && regmatch.endp[0] == line + endcol) @@ -2873,7 +2873,7 @@ check_need_cap(linenr_T lnum, colnr_T co break; } } - curwin->w_s->b_cap_prog = regmatch.regprog; + wp->w_s->b_cap_prog = regmatch.regprog; } vim_free(line_copy); @@ -4340,7 +4340,7 @@ static int spell_expand_need_cap; 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); } /* diff --git a/src/spellsuggest.c b/src/spellsuggest.c --- a/src/spellsuggest.c +++ b/src/spellsuggest.c @@ -538,7 +538,8 @@ spell_suggest(int count) // Get the word and its length. // Figure out if the word should be capitalised. - need_cap = check_need_cap(curwin->w_cursor.lnum, curwin->w_cursor.col); + 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. line = vim_strsave(ml_get_curline()); diff --git a/src/testdir/dumps/Test_spell_6.dump b/src/testdir/dumps/Test_spell_6.dump new file mode 100644 --- /dev/null +++ b/src/testdir/dumps/Test_spell_6.dump @@ -0,0 +1,8 @@ +| +0&#ffffff0@2|T|h|i|s| |l|i|n|e| |h|a|s| |a| |s+0&#ffd7d7255|e|p|l@1| +0&#ffffff0|e|r@1|o|r|.| |a+0fd7ff255|n|d| +0&#ffffff0|m|i|s@1|i|n|g| |c|a|p|s| |a|n|d| |t|r|a|i|l|i|n|g| |s|p|a|c|e|s|.| @5 +|a+0fd7ff255|n|o|t|h|e|r| +0&#ffffff0|m|i|s@1|i|n|g| |c|a|p| |h|e|r|e|.| @49 +|N|o|t| @71 +>++0#0000e05#a8a8a8255|-@1| @1|2| |l|i|n|e|s|:| |a|n|d| |h|e|r|e|.|-@51 +|a+0#0000000#5fd7ff255|n|d| +0&#ffffff0|h|e|r|e|.| @65 +|~+0#4040ff13&| @73 +|~| @73 +| +0#0000000&@56|4|,|4|-|1| @8|A|l@1| diff --git a/src/testdir/dumps/Test_spell_7.dump b/src/testdir/dumps/Test_spell_7.dump new file mode 100644 --- /dev/null +++ b/src/testdir/dumps/Test_spell_7.dump @@ -0,0 +1,8 @@ +| +0&#ffffff0@2|T|h|i|s| |l|i|n|e| |h|a|s| |a| |s+0&#ffd7d7255|e|p|l@1| +0&#ffffff0|e|r@1|o|r|.| |a+0fd7ff255|n|d| +0&#ffffff0|m|i|s@1|i|n|g| |c|a|p|s| |a|n|d| |t|r|a|i|l|i|n|g| |s|p|a|c|e|s|.| @5 +|a+0fd7ff255|n|o|t|h|e|r| +0&#ffffff0|m|i|s@1|i|n|g| |c|a|p| |h|e|r>e| @50 +|++0#0000e05#a8a8a8255|-@1| @1|2| |l|i|n|e|s|:| |N|o|t|-@57 +|a+0#0000000#5fd7ff255|n|d| +0&#ffffff0|h|e|r|e|.| @65 +|~+0#4040ff13&| @73 +|~| @73 +|~| @73 +| +0#0000000&@56|2|,|2|4| @9|A|l@1| diff --git a/src/testdir/dumps/Test_spell_8.dump b/src/testdir/dumps/Test_spell_8.dump new file mode 100644 --- /dev/null +++ b/src/testdir/dumps/Test_spell_8.dump @@ -0,0 +1,8 @@ +|a+0fd7ff255|n|o|t|h|e|r| +0&#ffffff0|m|i|s@1|i|n|g| |c|a|p| |h|e|r|e| @50 +|++0#0000e05#a8a8a8255|-@1| @1|2| |l|i|n|e|s|:| |N|o|t|-@57 +|a+0#0000000#5fd7ff255|n|d| +0&#ffffff0|h|e|r|e>.| @65 +|~+0#4040ff13&| @73 +|~| @73 +|~| @73 +|~| @73 +| +0#0000000&@56|5|,|9| @10|B|o|t| diff --git a/src/testdir/test_spell.vim b/src/testdir/test_spell.vim --- a/src/testdir/test_spell.vim +++ b/src/testdir/test_spell.vim @@ -999,13 +999,26 @@ func Test_spell_screendump_spellcap() call VerifyScreenDump(buf, 'Test_spell_3', {}) " Deleting a full stop removes missing Cap in next line - call term_sendkeys(buf, "5Gddk$x") + call term_sendkeys(buf, "5Gdd\k$x") call VerifyScreenDump(buf, 'Test_spell_4', {}) " Undo also updates the next line (go to command line to remove message) call term_sendkeys(buf, "u:\") call VerifyScreenDump(buf, 'Test_spell_5', {}) + " Folding an empty line does not remove Cap in next line + call term_sendkeys(buf, "uzfk:\") + 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, "\\") + call VerifyScreenDump(buf, 'Test_spell_8', {}) + " clean up call StopVimInTerminal(buf) endfunc 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 */ /**/ + 1578, +/**/ 1577, /**/ 1576,