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.