To: vim_dev@googlegroups.com Subject: Patch 9.0.1585 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 9.0.1585 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) Files: src/drawline.c, src/proto/drawline.pro, src/drawscreen.c, src/structs.h *** ../vim-9.0.1584/src/drawline.c 2023-05-25 17:14:18.219481255 +0100 --- src/drawline.c 2023-05-27 21:40:36.834631232 +0100 *************** *** 1050,1057 **** #endif /* ! * Display line "lnum" of window 'wp' on the screen. * Start at row "startrow", stop when "endrow" is reached. * wp->w_virtcol needs to be valid. * * Return the number of last row the line occupies. --- 1050,1060 ---- #endif /* ! * 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,1069 **** 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 { winlinevars_T wlv; // variables passed between functions --- 1065,1072 ---- linenr_T lnum, int startrow, int endrow, ! int number_only, ! spellvars_T *spv UNUSED) { winlinevars_T wlv; // variables passed between functions *************** *** 1139,1145 **** 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 --- 1142,1147 ---- *************** *** 1148,1158 **** // 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 --- 1150,1155 ---- *************** *** 1289,1335 **** } #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) { --- 1286,1291 ---- *************** *** 1497,1511 **** ptr = line; #ifdef FEAT_SPELL ! if (has_spell && !number_only) { // 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 (nextline[SPWORDLEN] == NUL) { // No next line or it is empty. --- 1453,1490 ---- ptr = line; #ifdef FEAT_SPELL ! 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 (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,1729 **** #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) { int len; colnr_T linecol = (colnr_T)(ptr - line); --- 1702,1708 ---- #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 (spv->spv_has_spell) { int len; colnr_T linecol = (colnr_T)(ptr - line); *************** *** 2327,2335 **** # endif syntax_attr = get_syntax_attr((colnr_T)v, # ifdef FEAT_SPELL ! has_spell ? &can_spell : # endif ! NULL, FALSE); prev_syntax_col = v; prev_syntax_attr = syntax_attr; } --- 2306,2314 ---- # endif syntax_attr = get_syntax_attr((colnr_T)v, # ifdef FEAT_SPELL ! spv->spv_has_spell ? &can_spell : # endif ! NULL, FALSE); prev_syntax_col = v; prev_syntax_attr = syntax_attr; } *************** *** 2768,2774 **** // @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) { spell_attr = 0; // do not calculate cap_col at the end of the line or when --- 2747,2753 ---- // @Spell cluster is not used or the current syntax item // contains the @Spell cluster. v = (long)(ptr - line); ! 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,2800 **** 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); word_end = v + len; // In Insert mode only highlight a word that --- 2771,2779 ---- p = nextline + (prev_ptr - line) - nextlinecol; else p = prev_ptr; ! 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,2843 **** { // 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); } // Turn index into actual attributes. if (spell_hlf != HLF_COUNT) spell_attr = highlight_attr[spell_hlf]; ! if (cap_col > 0) { if (p != prev_ptr ! && (p - nextline) + 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); } else // Compute the actual column. ! cap_col += (int)(prev_ptr - line); } } } --- 2794,2823 ---- { // Remember that the good word continues at the // start of the next line. ! 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 (spv->spv_cap_col > 0) { if (p != prev_ptr ! && (p - nextline) + spv->spv_cap_col ! >= nextline_idx) { // Remember that the word in the next line // must start with a capital. ! spv->spv_capcol_lnum = lnum + 1; ! spv->spv_cap_col = ((p - nextline) ! + spv->spv_cap_col - nextline_idx); } else // Compute the actual column. ! spv->spv_cap_col += (prev_ptr - line); } } } *************** *** 4119,4133 **** } } // 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); --- 4099,4104 ---- *** ../vim-9.0.1584/src/proto/drawline.pro 2022-12-06 14:17:32.178527467 +0000 --- src/proto/drawline.pro 2023-05-27 21:26:47.825527350 +0100 *************** *** 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); /* vim: set ft=c : */ --- 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 number_only, spellvars_T *spv); /* vim: set ft=c : */ *** ../vim-9.0.1584/src/drawscreen.c 2023-05-25 17:14:18.219481255 +0100 --- src/drawscreen.c 2023-05-27 22:16:56.662425321 +0100 *************** *** 2191,2201 **** redraw_win_toolbar(wp); #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_ --- 2191,2215 ---- 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; for (;;) { // stop updating when reached the end of the window (check for _past_ *************** *** 2450,2460 **** fold_line(wp, fold_count, &win_foldinfo, lnum, row); ++row; --fold_count; wp->w_lines[idx].wl_folded = TRUE; ! wp->w_lines[idx].wl_lastlnum = lnum + fold_count; # ifdef FEAT_SYN_HL did_update = DID_FOLD; # endif } else #endif --- 2464,2483 ---- 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 = 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,2493 **** #endif // Display one line. ! row = win_line(wp, lnum, srow, wp->w_height, mod_top, FALSE); #ifdef FEAT_FOLDING wp->w_lines[idx].wl_folded = FALSE; --- 2510,2516 ---- #endif // Display one line. ! row = win_line(wp, lnum, srow, wp->w_height, FALSE, &spv); #ifdef FEAT_FOLDING wp->w_lines[idx].wl_folded = FALSE; *************** *** 2534,2540 **** fold_line(wp, fold_count, &win_foldinfo, lnum, row); else #endif ! (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. --- 2557,2563 ---- fold_line(wp, fold_count, &win_foldinfo, lnum, row); else #endif ! (void)win_line(wp, lnum, srow, wp->w_height, TRUE, &spv); } // This line does not need to be drawn, advance to the next one. *** ../vim-9.0.1584/src/structs.h 2023-05-27 18:02:50.188062442 +0100 --- src/structs.h 2023-05-27 21:20:27.502104826 +0100 *************** *** 4870,4872 **** --- 4870,4887 ---- // 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; *** ../vim-9.0.1584/src/version.c 2023-05-27 19:01:48.395230967 +0100 --- src/version.c 2023-05-27 21:21:56.521970607 +0100 *************** *** 697,698 **** --- 697,700 ---- { /* Add new patch number below this line */ + /**/ + 1585, /**/ -- From "know your smileys": :-H Is missing teeth /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///