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: "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)
        {
--- 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: "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,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 -- [email protected] -- http://www.Moolenaar.net   \\\
///                                                                      \\\
\\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/20230527212235.DF6FE1C140E%40moolenaar.net.

Raspunde prin e-mail lui