changeset 32507:2614026cd259 v9.0.1585

patch 9.0.1585: weird use of static variables for spell checking Commit: https://github.com/vim/vim/commit/30805a1aba0067cf0087f9a0e5c184562433e2e7 Author: Luuk van Baal <luukvbaal@gmail.com> 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)
author Bram Moolenaar <Bram@vim.org>
date Sat, 27 May 2023 23:30:03 +0200
parents fdcd3563571a
children eb8089e59bae
files src/drawline.c src/drawscreen.c src/proto/drawline.pro src/structs.h src/version.c
diffstat 5 files changed, 98 insertions(+), 87 deletions(-) [+]
line wrap: on
line diff
--- 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: "et<line-break>al.".
-	    // 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: "et<line-break>al.".
+	// 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);
--- 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.
--- 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 : */
--- 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;
--- 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,