# HG changeset patch # User Bram Moolenaar # Date 1685223003 -7200 # Node ID 2614026cd259120017b1133d2ab0298b819c0c87 # Parent fdcd3563571ad24ebbac2fc51eb70f66956205c9 patch 9.0.1585: weird use of static variables for spell checking Commit: https://github.com/vim/vim/commit/30805a1aba0067cf0087f9a0e5c184562433e2e7 Author: Luuk van Baal Date: Sat May 27 22:22:10 2023 +0100 patch 9.0.1585: weird use of static variables for spell checking Problem: Weird use of static variables for spell checking. Solution: Move the variables to a structure and pass them from win_update() to win_line(). (Luuk van Baal, closes #12448) diff --git a/src/drawline.c b/src/drawline.c --- a/src/drawline.c +++ b/src/drawline.c @@ -1050,8 +1050,11 @@ apply_cursorline_highlight( #endif /* - * Display line "lnum" of window 'wp' on the screen. + * Display line "lnum" of window "wp" on the screen. * Start at row "startrow", stop when "endrow" is reached. + * When "number_only" is TRUE only update the number column. + * "spv" is used to store information for spell checking, kept between + * sequential calls for the same window. * wp->w_virtcol needs to be valid. * * Return the number of last row the line occupies. @@ -1062,8 +1065,8 @@ win_line( linenr_T lnum, int startrow, int endrow, - int mod_top UNUSED, // top line updated for changed text - int number_only) // only update the number column + int number_only, + spellvars_T *spv UNUSED) { winlinevars_T wlv; // variables passed between functions @@ -1139,7 +1142,6 @@ win_line( int reset_extra_attr = FALSE; #endif #ifdef FEAT_SPELL - int has_spell = FALSE; // this buffer has spell checking int can_spell = FALSE; # define SPWORDLEN 150 char_u nextline[SPWORDLEN * 2];// text with start of the next line @@ -1148,11 +1150,6 @@ win_line( // starts int spell_attr = 0; // attributes desired by spelling int word_end = 0; // last byte with same spell_attr - static linenr_T checked_lnum = 0; // line number for "checked_col" - static int checked_col = 0; // column in "checked_lnum" up to which - // there are no spell errors - static int cap_col = -1; // column to check for Cap word - static linenr_T capcol_lnum = 0; // line number where "cap_col" used int cur_checked_col = 0; // checked column for current line #endif int extra_check = 0; // has extra highlighting @@ -1289,47 +1286,6 @@ win_line( } #endif -#ifdef FEAT_SPELL - if (spell_check_window(wp)) - { - // Prepare for spell checking. - has_spell = TRUE; - extra_check = TRUE; - - // Get the start of the next line, so that words that wrap to the - // next line are found too: "etal.". - // Trick: skip a few chars for C/shell/Vim comments - nextline[SPWORDLEN] = NUL; - if (lnum < wp->w_buffer->b_ml.ml_line_count) - { - line = ml_get_buf(wp->w_buffer, lnum + 1, FALSE); - spell_cat_line(nextline + SPWORDLEN, line, SPWORDLEN); - } - - // When a word wrapped from the previous line the start of the - // current line is valid. - if (lnum == checked_lnum) - cur_checked_col = checked_col; - checked_lnum = 0; - - // 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. 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; - capcol_lnum = 0; - } -#endif - // handle Visual active in this window if (VIsual_active && wp->w_buffer == curwin->w_buffer) { @@ -1497,15 +1453,38 @@ win_line( ptr = line; #ifdef FEAT_SPELL - if (has_spell && !number_only) + if (spv->spv_has_spell && !number_only) { + // Prepare for spell checking. + extra_check = TRUE; + + // When a word wrapped from the previous line the start of the + // current line is valid. + if (lnum == spv->spv_checked_lnum) + cur_checked_col = spv->spv_checked_col; + if (lnum != spv->spv_capcol_lnum) + spv->spv_cap_col = -1; + spv->spv_checked_lnum = 0; + // For checking first word with a capital skip white space. - if (cap_col == 0) - cap_col = getwhitecols(line); - - // To be able to spell-check over line boundaries copy the end of the - // current line into nextline[]. Above the start of the next line was - // copied to nextline[SPWORDLEN]. + if (spv->spv_cap_col == 0) + spv->spv_cap_col = getwhitecols(line); + // If current line is empty, check first word in next line for capital. + else if (*skipwhite(line) == NUL) + { + spv->spv_cap_col = 0; + spv->spv_capcol_lnum = lnum + 1; + } + + + // Get the start of the next line, so that words that wrap to the + // next line are found too: "etal.". + // Trick: skip a few chars for C/shell/Vim comments + nextline[SPWORDLEN] = NUL; + if (lnum < wp->w_buffer->b_ml.ml_line_count) + spell_cat_line(nextline + SPWORDLEN, + ml_get_buf(wp->w_buffer, lnum + 1, FALSE), SPWORDLEN); + // Copy the end of the current line into nextline[]. if (nextline[SPWORDLEN] == NUL) { // No next line or it is empty. @@ -1723,7 +1702,7 @@ win_line( #ifdef FEAT_SPELL // When spell checking a word we need to figure out the start of the // word and if it's badly spelled or not. - if (has_spell) + if (spv->spv_has_spell) { int len; colnr_T linecol = (colnr_T)(ptr - line); @@ -2327,9 +2306,9 @@ win_line( # endif syntax_attr = get_syntax_attr((colnr_T)v, # ifdef FEAT_SPELL - has_spell ? &can_spell : + spv->spv_has_spell ? &can_spell : # endif - NULL, FALSE); + NULL, FALSE); prev_syntax_col = v; prev_syntax_attr = syntax_attr; } @@ -2768,7 +2747,7 @@ win_line( // @Spell cluster is not used or the current syntax item // contains the @Spell cluster. v = (long)(ptr - line); - if (has_spell && v >= word_end && v > cur_checked_col) + if (spv->spv_has_spell && v >= word_end && v > cur_checked_col) { spell_attr = 0; // do not calculate cap_col at the end of the line or when @@ -2792,9 +2771,9 @@ win_line( p = nextline + (prev_ptr - line) - nextlinecol; else p = prev_ptr; - cap_col -= (int)(prev_ptr - line); - len = spell_check(wp, p, &spell_hlf, &cap_col, - mod_top == 0); + spv->spv_cap_col -= (int)(prev_ptr - line); + len = spell_check(wp, p, &spell_hlf, &spv->spv_cap_col, + spv->spv_unchanged); word_end = v + len; // In Insert mode only highlight a word that @@ -2815,29 +2794,30 @@ win_line( { // Remember that the good word continues at the // start of the next line. - checked_lnum = lnum + 1; - checked_col = (int)((p - nextline) - + len - nextline_idx); + spv->spv_checked_lnum = lnum + 1; + spv->spv_checked_col = (p - nextline) + len + - nextline_idx; } // Turn index into actual attributes. if (spell_hlf != HLF_COUNT) spell_attr = highlight_attr[spell_hlf]; - if (cap_col > 0) + if (spv->spv_cap_col > 0) { if (p != prev_ptr - && (p - nextline) + cap_col >= nextline_idx) + && (p - nextline) + spv->spv_cap_col + >= nextline_idx) { // Remember that the word in the next line // must start with a capital. - capcol_lnum = lnum + 1; - cap_col = (int)((p - nextline) + cap_col - - nextline_idx); + spv->spv_capcol_lnum = lnum + 1; + spv->spv_cap_col = ((p - nextline) + + spv->spv_cap_col - nextline_idx); } else // Compute the actual column. - cap_col += (int)(prev_ptr - line); + spv->spv_cap_col += (prev_ptr - line); } } } @@ -4119,15 +4099,6 @@ win_line( } } // for every character in the line - -#ifdef FEAT_SPELL - // After an empty line check first word for capital. - if (*skipwhite(line) == NUL) - { - capcol_lnum = lnum + 1; - cap_col = 0; - } -#endif #ifdef FEAT_PROP_POPUP vim_free(text_props); vim_free(text_prop_idxs); diff --git a/src/drawscreen.c b/src/drawscreen.c --- a/src/drawscreen.c +++ b/src/drawscreen.c @@ -2191,11 +2191,25 @@ win_update(win_T *wp) redraw_win_toolbar(wp); #endif + lnum = wp->w_topline; // first line shown in window + + spellvars_T spv; +#ifdef FEAT_SPELL + // Initialize spell related variables for the first drawn line. + CLEAR_FIELD(spv); + spv.spv_has_spell = spell_check_window(wp); + if (spv.spv_has_spell) + { + spv.spv_unchanged = mod_top == 0; + spv.spv_capcol_lnum = mod_top ? mod_top : lnum; + spv.spv_cap_col = check_need_cap(wp, spv.spv_capcol_lnum, 0) ? 0 : - 1; + } +#endif + // Update all the window rows. idx = 0; // first entry in w_lines[].wl_size row = 0; srow = 0; - lnum = wp->w_topline; // first line shown in window for (;;) { // stop updating when reached the end of the window (check for _past_ @@ -2450,11 +2464,20 @@ win_update(win_T *wp) fold_line(wp, fold_count, &win_foldinfo, lnum, row); ++row; --fold_count; + linenr_T lnume = lnum + fold_count; wp->w_lines[idx].wl_folded = TRUE; - wp->w_lines[idx].wl_lastlnum = lnum + fold_count; + wp->w_lines[idx].wl_lastlnum = lnume; # ifdef FEAT_SYN_HL did_update = DID_FOLD; # endif +# ifdef FEAT_SPELL + // Check if the line after this fold requires a capital. + if (spv.spv_has_spell && check_need_cap(wp, lnume + 1, 0)) + { + spv.spv_cap_col = 0; + spv.spv_capcol_lnum = lnume + 1; + } +# endif } else #endif @@ -2487,7 +2510,7 @@ win_update(win_T *wp) #endif // Display one line. - row = win_line(wp, lnum, srow, wp->w_height, mod_top, FALSE); + row = win_line(wp, lnum, srow, wp->w_height, FALSE, &spv); #ifdef FEAT_FOLDING wp->w_lines[idx].wl_folded = FALSE; @@ -2534,7 +2557,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, mod_top, TRUE); + (void)win_line(wp, lnum, srow, wp->w_height, TRUE, &spv); } // This line does not need to be drawn, advance to the next one. diff --git a/src/proto/drawline.pro b/src/proto/drawline.pro --- a/src/proto/drawline.pro +++ b/src/proto/drawline.pro @@ -1,4 +1,4 @@ /* drawline.c */ int text_prop_position(win_T *wp, textprop_T *tp, int vcol, int scr_col, int *n_extra, char_u **p_extra, int *n_attr, int *n_attr_skip, int do_skip); -int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int nochange, int number_only); +int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int number_only, spellvars_T *spv); /* vim: set ft=c : */ diff --git a/src/structs.h b/src/structs.h --- a/src/structs.h +++ b/src/structs.h @@ -4870,3 +4870,18 @@ typedef struct // message (when it is not NULL). char *os_errbuf; } optset_T; + +/* + * Spell checking variables passed from win_update() to win_line(). + */ +typedef struct { + int spv_has_spell; // drawn window has spell checking +#ifdef FEAT_SPELL + int spv_unchanged; // not updating for changed text + int spv_checked_col; // column in "checked_lnum" up to + // which there are no spell errors + linenr_T spv_checked_lnum; // line number for "checked_col" + int spv_cap_col; // column to check for Cap word + linenr_T spv_capcol_lnum; // line number for "cap_col" +#endif +} spellvars_T; 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 */ /**/ + 1585, +/**/ 1584, /**/ 1583,