patch 9.1.1626: cindent: does not handle compound literals Commit: https://github.com/vim/vim/commit/5ba6e41d37ec29fc8360a4f06d4e95c63eb013ab Author: Anttoni Erkkilä <anttoni.erkk...@protonmail.com> Date: Tue Aug 12 21:59:06 2025 +0200
patch 9.1.1626: cindent: does not handle compound literals Problem: C-indent does not handle compound literals (@44100hertz, @Jorenar) Solution: Detect and handle compound literal and structure initialization (Anttoni Erkkilä) match '=' or "return" optionally followed by &, (typecast), { Fixes also initialization which begins with multiple opening braces. fixes: #2090 fixes: #12491 closes: #17865 Signed-off-by: Anttoni Erkkilä <anttoni.erkk...@protonmail.com> Signed-off-by: Christian Brabandt <c...@256bit.org> diff --git a/runtime/doc/version9.txt b/runtime/doc/version9.txt index 1052e7e51..fb278f0ab 100644 --- a/runtime/doc/version9.txt +++ b/runtime/doc/version9.txt @@ -1,4 +1,4 @@ -*version9.txt* For Vim version 9.1. Last change: 2025 Aug 08 +*version9.txt* For Vim version 9.1. Last change: 2025 Aug 12 VIM REFERENCE MANUAL by Bram Moolenaar @@ -41736,6 +41736,7 @@ Others: ~ - |gv| works in operator pending mode and does not abort - The close button shown in the non-GUI 'tabline' will only be visible if the 'mouse' option contains either "a" or any of the flags "n", "v", or "i". +- |C-indenting| handles compound literals. *added-9.2* Added ~ diff --git a/src/cindent.c b/src/cindent.c index e1f744676..3dea1079e 100644 --- a/src/cindent.c +++ b/src/cindent.c @@ -690,10 +690,9 @@ cin_islabel(void) // XXX /* * Return TRUE if string "s" ends with the string "find", possibly followed by * white space and comments. Skip strings and comments. - * Ignore "ignore" after "find" if it's not NULL. */ static int -cin_ends_in(char_u *s, char_u *find, char_u *ignore) +cin_ends_in(char_u *s, char_u *find) { char_u *p = s; char_u *r; @@ -705,8 +704,6 @@ cin_ends_in(char_u *s, char_u *find, char_u *ignore) if (STRNCMP(p, find, len) == 0) { r = skipwhite(p + len); - if (ignore != NULL && STRNCMP(r, ignore, STRLEN(ignore)) == 0) - r = skipwhite(r + STRLEN(ignore)); if (cin_nocode(r)) return TRUE; } @@ -717,9 +714,77 @@ cin_ends_in(char_u *s, char_u *find, char_u *ignore) } /* - * Recognize structure initialization and enumerations: + * Strings can be concatenated with comments between: + * "string0" |*comment*| "string1" + */ + static char_u * +cin_skip_comment_and_string(char_u *s) +{ + char_u *r = NULL, *p = s; + do + { + r = p; + p = cin_skipcomment(p); + if (*p) + p = skip_string(p); + } while (p != r); + return p; +} + +/* + * Recognize structure or compound literal initialization: + * =|return [&][(typecast)] [{] + * The number of opening braces is arbitrary. + */ + static int +cin_is_compound_init(char_u *s) +{ + char_u *p = s, *r = NULL; + + while (*p) + { + if (*p == '=') + p = r = cin_skipcomment(p + 1); + else if (!STRNCMP(p, "return", 6) && !vim_isIDc(p[6]) + && (p == s || (p > s && !vim_isIDc(p[-1])))) + p = r = cin_skipcomment(p + 6); + else + p = cin_skip_comment_and_string(p + 1); + } + if (!r) + return FALSE; + p = r; // p points now after '=' or "return" + + if (cin_nocode(p)) + return TRUE; + + if (*p == '&') + p = cin_skipcomment(p + 1); + + if (*p == '(') // skip a typecast + { + int open_count = 1; + do + { + p = cin_skip_comment_and_string(p + 1); + if (cin_nocode(p)) + return TRUE; + open_count += (*p == '(') - (*p == ')'); + } while (open_count); + p = cin_skipcomment(p + 1); + if (cin_nocode(p)) + return TRUE; + } + + while (*p == '{') + p = cin_skipcomment(p + 1); + return cin_nocode(p); +} + +/* + * Recognize enumerations: * "[typedef] [static|public|protected|private] enum" - * "[typedef] [static|public|protected|private] = {" + * Call another function to recognize structure initialization. */ static int cin_isinit(void) @@ -753,10 +818,7 @@ cin_isinit(void) if (cin_starts_with(s, "enum")) return TRUE; - if (cin_ends_in(s, (char_u *)"=", (char_u *)"{")) - return TRUE; - - return FALSE; + return cin_is_compound_init(s); } // Maximum number of lines to search back for a "namespace" line. @@ -1634,7 +1696,7 @@ get_baseclass_amount(int col) if (find_last_paren(ml_get_curline(), '(', ')') && (trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL) amount = get_indent_lnum(trypos->lnum); // XXX - if (!cin_ends_in(ml_get_curline(), (char_u *)",", NULL)) + if (!cin_ends_in(ml_get_curline(), (char_u *)",")) amount += curbuf->b_ind_cpp_baseclass; } else @@ -2505,7 +2567,7 @@ get_c_indent(void) cur_amount = MAXCOL; l = ml_get(our_paren_pos.lnum); if (curbuf->b_ind_unclosed_wrapped - && cin_ends_in(l, (char_u *)"(", NULL)) + && cin_ends_in(l, (char_u *)"(")) { // look for opening unmatched paren, indent one level // for each additional level @@ -3702,8 +3764,8 @@ term_again: && !cin_nocode(theline) && vim_strchr(theline, '{') == NULL && vim_strchr(theline, '}') == NULL - && !cin_ends_in(theline, (char_u *)":", NULL) - && !cin_ends_in(theline, (char_u *)",", NULL) + && !cin_ends_in(theline, (char_u *)":") + && !cin_ends_in(theline, (char_u *)",") && cin_isfuncdecl(NULL, cur_curpos.lnum + 1, cur_curpos.lnum + 1) && !cin_isterminated(theline, FALSE, TRUE)) @@ -3764,7 +3826,7 @@ term_again: // } foo, // bar; n = 0; - if (cin_ends_in(l, (char_u *)",", NULL) + if (cin_ends_in(l, (char_u *)",") || (*l != NUL && (n = l[STRLEN(l) - 1]) == '\')) { // take us back to opening paren @@ -3812,14 +3874,14 @@ term_again: // comments) align at column 0. For example: // char *string_array[] = { "foo", // / * x * / "b};ar" }; / * foobar * / - if (cin_ends_in(l, (char_u *)"};", NULL)) + if (cin_ends_in(l, (char_u *)"};")) break; // If the previous line ends on '[' we are probably in an // array constant: // something = [ // 234, <- extra indent - if (cin_ends_in(l, (char_u *)"[", NULL)) + if (cin_ends_in(l, (char_u *)"[")) { amount = get_indent() + ind_continuation; break; @@ -3840,7 +3902,7 @@ term_again: break; } if (curwin->w_cursor.lnum > 0 - && cin_ends_in(look, (char_u *)"}", NULL)) + && cin_ends_in(look, (char_u *)"}")) break; curwin->w_cursor = curpos_save; @@ -3860,10 +3922,10 @@ term_again: // int foo, // bar; // indent_to_0 here; - if (cin_ends_in(l, (char_u *)";", NULL)) + if (cin_ends_in(l, (char_u *)";")) { l = ml_get(curwin->w_cursor.lnum - 1); - if (cin_ends_in(l, (char_u *)",", NULL) + if (cin_ends_in(l, (char_u *)",") || (*l != NUL && l[STRLEN(l) - 1] == '\')) break; l = ml_get_curline(); diff --git a/src/testdir/test_indent.vim b/src/testdir/test_indent.vim index e20694792..52d7be139 100644 --- a/src/testdir/test_indent.vim +++ b/src/testdir/test_indent.vim @@ -119,6 +119,31 @@ func Test_userlabel_indent() close! endfunc +" Test that struct members are aligned +func Test_struct_indent() + new + call setline(1, ['struct a a = {', '1,', '1,']) + normal gg=G + call assert_equal(getline(2), getline(3)) + + call setline(1, 'a = (struct a) {') + normal gg=G + call assert_equal(getline(2), getline(3)) + + call setline(1, 'void *ptr = &(static struct a) {{') + normal gg=G + call assert_equal(getline(2), getline(3)) + + call setline(1, 'a = (macro(arg1, "str)))")) {') + normal gg=G + call assert_equal(getline(2), getline(3)) + + call setline(1, 'return (struct a) {') + normal gg=G + call assert_equal(getline(2), getline(3)) + close! +endfunc + " Test for 'copyindent' func Test_copyindent() new diff --git a/src/version.c b/src/version.c index d68e63d11..071eca3f0 100644 --- a/src/version.c +++ b/src/version.c @@ -719,6 +719,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1626, /**/ 1625, /**/ -- -- 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 vim_dev+unsubscr...@googlegroups.com. To view this discussion visit https://groups.google.com/d/msgid/vim_dev/E1ulvOh-00B50y-Mn%40256bit.org.