patch 9.2.0447: cindent does not ignore comments

Commit: 
https://github.com/vim/vim/commit/c06002f3cb07c374bfc1a1310cf13ee1914e86da
Author: magnus-rattlehead <[email protected]>
Date:   Tue May 5 20:35:32 2026 +0000

    patch 9.2.0447: cindent does not ignore comments
    
    Problem:  When find_start_brace() scans backwards for the enclosing
              block, '{' and '}' inside // and /* */ comments are counted,
              producing wrong indent for code following such comments
              (rendcrx).
    Solution: Implement FM_SKIPCOMM in findmatchlimit() to track block-
              comment state and skip matches inside comments. Pass
              FM_SKIPCOMM from cindent's call sites
              (find_start_brace, find_match_char, cin_iswhileofdo,
              get_c_indent).
    
    fixes:  #4
    fixes:  #648
    fixes:  #19578
    closes: #19581
    closes: #20111
    
    Signed-off-by: magnus-rattlehead <[email protected]>
    Signed-off-by: Christian Brabandt <[email protected]>

diff --git a/runtime/doc/version9.txt b/runtime/doc/version9.txt
index 114bdf7da..a1b9afce7 100644
--- a/runtime/doc/version9.txt
+++ b/runtime/doc/version9.txt
@@ -1,4 +1,4 @@
-*version9.txt* For Vim version 9.2.  Last change: 2026 May 02
+*version9.txt* For Vim version 9.2.  Last change: 2026 May 05
 
 
                  VIM REFERENCE MANUAL    by Bram Moolenaar
@@ -52625,6 +52625,7 @@ Other ~
 - Added the "u" flag to 'shortmess' to silence undo/redo messages: |shm-u|
 - |:command-completion-customlist| can return a list of dictionaries with
   kind/menu/info/abbr for the popup menu.
+- |C-indenting| detects comments better.
 
 Platform specific ~
 -----------------
diff --git a/src/cindent.c b/src/cindent.c
index ddd268176..94c01db7e 100644
--- a/src/cindent.c
+++ b/src/cindent.c
@@ -1153,7 +1153,7 @@ find_match_char(int c, int ind_maxparen)  // XXX
     cursor_save = curwin->w_cursor;
     ind_maxp_wk = ind_maxparen;
 retry:
-    if ((trypos = findmatchlimit(NULL, c, 0, ind_maxp_wk)) != NULL)
+    if ((trypos = findmatchlimit(NULL, c, FM_SKIPCOMM, ind_maxp_wk)) != NULL)
     {
        // check if the ( is in a // comment
        if ((colnr_T)cin_skip2pos(trypos) > trypos->col)
@@ -1396,7 +1396,7 @@ cin_iswhileofdo (char_u *p, linenr_T lnum)        // XXX
            ++p;
            ++curwin->w_cursor.col;
        }
-       if ((trypos = findmatchlimit(NULL, 0, 0,
+       if ((trypos = findmatchlimit(NULL, 0, FM_SKIPCOMM,
                                              curbuf->b_ind_maxparen)) != NULL
                && *cin_skipcomment(ml_get_pos(trypos) + 1) == ';')
            retval = TRUE;
@@ -1732,7 +1732,7 @@ find_start_brace(void)        // XXX
     static pos_T    pos_copy;
 
     cursor_save = curwin->w_cursor;
-    while ((trypos = findmatchlimit(NULL, '{', FM_BLOCKSTOP, 0)) != NULL)
+    while ((trypos = findmatchlimit(NULL, '{', FM_BLOCKSTOP | FM_SKIPCOMM, 0)) 
!= NULL)
     {
        pos_copy = *trypos;     // copy pos_T, next findmatch will change it
        trypos = &pos_copy;
@@ -2547,7 +2547,7 @@ get_c_indent(void)
                line = ml_get_curline();
                look_col = (int)(look - line);
                curwin->w_cursor.col = look_col + 1;
-               if ((trypos = findmatchlimit(NULL, ')', 0,
+               if ((trypos = findmatchlimit(NULL, ')', FM_SKIPCOMM,
                                                      curbuf->b_ind_maxparen))
                                                                      != NULL
                          && trypos->lnum == our_paren_pos.lnum
diff --git a/src/search.c b/src/search.c
index bb85873dc..12977dc8f 100644
--- a/src/search.c
+++ b/src/search.c
@@ -2165,7 +2165,7 @@ find_mps_values(
  * flags: FM_BACKWARD  search backwards (when initc is '/', '*' or '#')
  *       FM_FORWARD    search forwards (when initc is '/', '*' or '#')
  *       FM_BLOCKSTOP  stop at start/end of block ({ or } in column 0)
- *       FM_SKIPCOMM   skip comments (not implemented yet!)
+ *       FM_SKIPCOMM   skip over comments (cursor must start outside a block 
comment)
  *
  * "oap" is only used to set oap->motion_type for a linewise motion, it can be
  * NULL
@@ -2201,6 +2201,8 @@ findmatchlimit(
     int                comment_col = MAXCOL;   // start of / / comment
     int                lispcomm = FALSE;       // inside of Lisp-style comment
     int                lisp = curbuf->b_p_lisp; // engage Lisp-specific hacks 
;)
+    int                skip_comments = (flags & FM_SKIPCOMM) != 0;
+    int                in_block_comment = FALSE; // inside /* */ block comment
 
     pos = curwin->w_cursor;
     pos.coladd = 0;
@@ -2429,10 +2431,14 @@ findmatchlimit(
     CLEAR_POS(&match_pos);
 
     // backward search: Check if this line contains a single-line comment
-    if ((backwards && comment_dir) || lisp)
+    if ((backwards && comment_dir) || lisp || skip_comments)
        comment_col = check_linecomment(linep);
     if (lisp && comment_col != MAXCOL && pos.col > (colnr_T)comment_col)
        lispcomm = TRUE;    // find match inside this comment
+    // skip // comment portion at starting position
+    if (skip_comments && !in_block_comment && comment_col != MAXCOL
+           && backwards && pos.col > (colnr_T)comment_col)
+       pos.col = comment_col;
 
     while (!got_int)
     {
@@ -2460,11 +2466,15 @@ findmatchlimit(
                line_breakcheck();
 
                // Check if this line contains a single-line comment
-               if (comment_dir || lisp)
+               if (comment_dir || lisp || skip_comments)
                    comment_col = check_linecomment(linep);
                // skip comment
                if (lisp && comment_col != MAXCOL)
                    pos.col = comment_col;
+               else if (skip_comments && !in_block_comment
+                       && comment_col != MAXCOL
+                       && pos.col > (colnr_T)comment_col)
+                   pos.col = comment_col;
            }
            else
            {
@@ -2495,7 +2505,7 @@ findmatchlimit(
                pos.col = 0;
                do_quotes = -1;
                line_breakcheck();
-               if (lisp)   // find comment pos in new line
+               if (lisp || skip_comments)   // find comment pos in new line
                    comment_col = check_linecomment(linep);
            }
            else
@@ -2507,6 +2517,37 @@ findmatchlimit(
            }
        }
 
+       // Track block comment state when FM_SKIPCOMM is set.
+       // Backward: '/' of end-marker enters comment; '*' of start-marker 
exits.
+       // Forward:  '/' of start-marker enters comment; '/' of end-marker 
exits.
+       if (skip_comments && !comment_dir)
+       {
+           if (backwards)
+           {
+               // Guard pos.col < comment_col: don't misread '*/' at the '//'
+               // position as a block-comment end-marker.
+               if (!in_block_comment && pos.col > 0
+                       && linep[pos.col - 1] == '*' && linep[pos.col] == '/'
+                       && (comment_col == MAXCOL || (int)pos.col < 
comment_col))
+                   in_block_comment = TRUE;
+               else if (in_block_comment && pos.col > 0
+                       && linep[pos.col - 1] == '/' && linep[pos.col] == '*')
+                   in_block_comment = FALSE;
+           }
+           else
+           {
+               // Guard pos.col < comment_col: don't treat '/*' inside a '//'
+               // comment as a block-comment start-marker.
+               if (!in_block_comment && linep[pos.col] == '/'
+                       && linep[pos.col + 1] == '*'
+                       && (comment_col == MAXCOL || (int)pos.col < 
comment_col))
+                   in_block_comment = TRUE;
+               else if (in_block_comment && pos.col > 0
+                       && linep[pos.col - 1] == '*' && linep[pos.col] == '/')
+                   in_block_comment = FALSE;
+           }
+       }
+
        /*
         * If FM_BLOCKSTOP given, stop at a '{' or '}' in column 0.
         */
@@ -2750,6 +2791,11 @@ findmatchlimit(
                    && check_prevcol(linep, pos.col - 1, '#', NULL))
                break;
 
+           // Skip matches inside comments when FM_SKIPCOMM is set.
+           if (skip_comments && (in_block_comment
+                   || (comment_col != MAXCOL && (int)pos.col >= comment_col)))
+               break;
+
            // Check for match outside of quotes, and inside of
            // quotes when the start is also inside of quotes.
            if ((!inquote || start_in_quotes == TRUE)
diff --git a/src/testdir/test_cindent.vim b/src/testdir/test_cindent.vim
index 4884dbb30..f050d82f8 100644
--- a/src/testdir/test_cindent.vim
+++ b/src/testdir/test_cindent.vim
@@ -5526,5 +5526,85 @@ def Test_find_brace_backwards()
   bwipe!
 enddef
 
+" Brackets inside comments must not affect C indent calculation (FM_SKIPCOMM)
+def Test_cindent_comment_brackets()
+  # stray } in inline block comment must not confuse enclosing-brace search
+  new
+  setl cindent sw=4
+  var code =<< trim [CODE]
+  int foo() {
+      /* } */
+      int bar;
+  }
+  [CODE]
+  setline(1, code)
+  cursor(3, 1)
+  normal ==
+  assert_equal('    int bar;', getline(3))
+  bwipe!
+
+  # stray } in // line comment: same
+  new
+  setl cindent sw=4
+  var code2 =<< trim [CODE]
+  int foo() {
+      // }
+      int bar;
+  }
+  [CODE]
+  setline(1, code2)
+  cursor(3, 1)
+  normal ==
+  assert_equal('    int bar;', getline(3))
+  bwipe!
+
+  # stray } on continuation line inside multi-line block comment
+  new
+  setl cindent sw=4
+  var code3 =<< trim [CODE]
+  int foo() {
+      /*
+         }
+      */
+      int bar;
+  }
+  [CODE]
+  setline(1, code3)
+  cursor(5, 1)
+  normal ==
+  assert_equal('    int bar;', getline(5))
+  bwipe!
+
+  # { in inline block comment must not be treated as enclosing brace
+  new
+  setl cindent sw=4
+  var code4 =<< trim [CODE]
+  int foo() {
+      /* { */
+      int bar;
+  }
+  [CODE]
+  setline(1, code4)
+  cursor(3, 1)
+  normal ==
+  assert_equal('    int bar;', getline(3))
+  bwipe!
+
+  # ) in inline block comment must not be treated as enclosing brace
+  new
+  setl cindent sw=4
+  var code5 =<< trim [CODE]
+  some_func(arg1,
+      /* ) */ arg2,
+      arg3);
+  [CODE]
+  setline(1, code5)
+  cursor(3, 1)
+  normal ==
+  assert_equal('    arg3);', getline(3))
+  bwipe!
+
+enddef
+
 
 " vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/version.c b/src/version.c
index 2f0af9ba1..78efc6c77 100644
--- a/src/version.c
+++ b/src/version.c
@@ -729,6 +729,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    447,
 /**/
     446,
 /**/
diff --git a/src/vim.h b/src/vim.h
index 37183f130..8949e867d 100644
--- a/src/vim.h
+++ b/src/vim.h
@@ -1095,7 +1095,7 @@ extern int (*dyn_libintl_wputenv)(const wchar_t 
*envstring);
 #define FM_BACKWARD    0x01    // search backwards
 #define FM_FORWARD     0x02    // search forwards
 #define FM_BLOCKSTOP   0x04    // stop at start/end of block
-#define FM_SKIPCOMM    0x08    // skip comments
+#define FM_SKIPCOMM    0x08    // skip comments (cursor must start outside)
 
 // Values for action argument for do_buffer() and close_buffer()
 #define DOBUF_GOTO     0       // go to specified buffer

-- 
-- 
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 visit 
https://groups.google.com/d/msgid/vim_dev/E1wKNLB-007foS-7Y%40256bit.org.

Raspunde prin e-mail lui