From: magnus-rattlehead Date: Tue, 5 May 2026 20:35:32 +0000 (+0000) Subject: patch 9.2.0447: cindent does not ignore comments X-Git-Tag: v9.2.0447^0 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=c06002f3cb07c374bfc1a1310cf13ee1914e86da;p=thirdparty%2Fvim.git 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 Signed-off-by: Christian Brabandt --- diff --git a/runtime/doc/version9.txt b/runtime/doc/version9.txt index 114bdf7dac..a1b9afce71 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 ddd268176b..94c01db7e8 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 bb85873dc0..12977dc8fa 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 4884dbb304..f050d82f8c 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 2f0af9ba11..78efc6c777 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 37183f130a..8949e867de 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