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 <guranjakustivi@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
magnus-rattlehead
2026-05-05 20:35:32 +00:00
committed by Christian Brabandt
parent 7ccc273a4c
commit c06002f3cb
6 changed files with 139 additions and 10 deletions
+2 -1
View File
@@ -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 ~
-----------------
+4 -4
View File
@@ -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
+50 -4
View File
@@ -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)
+80
View File
@@ -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
+2
View File
@@ -729,6 +729,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
447,
/**/
446,
/**/
+1 -1
View File
@@ -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