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
index 3791ece..3811060 100644
--- a/src/drawline.c
+++ b/src/drawline.c
@@ -1050,8 +1050,11 @@
 #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 @@
     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 @@
     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 @@
 					// 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 @@
 	}
 #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 @@
     ptr = line;
 
 #ifdef FEAT_SPELL
-    if (has_spell && !number_only)
+    if (spv->spv_has_spell && !number_only)
     {
-	// For checking first word with a capital skip white space.
-	if (cap_col == 0)
-	    cap_col = getwhitecols(line);
+	// Prepare for spell checking.
+	extra_check = TRUE;
 
-	// 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].
+	// 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: "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 @@
 #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 @@
 # 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 @@
 		// @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 @@
 			    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 @@
 			{
 			    // 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 @@
 	}
 
     }	// 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);