patch 9.1.1626: cindent: does not handle compound literals
Commit:
https://github.com/vim/vim/commit/5ba6e41d37ec29fc8360a4f06d4e95c63eb013ab
Author: Anttoni Erkkilä <[email protected]>
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ä <[email protected]>
Signed-off-by: Christian Brabandt <[email protected]>
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 [email protected].
To view this discussion visit
https://groups.google.com/d/msgid/vim_dev/E1ulvOh-00B50y-Mn%40256bit.org.