Skip to content

Commit 5ba6e41

Browse files
aerkkilachrisbra
authored andcommitted
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]>
1 parent 59e1d7f commit 5ba6e41

4 files changed

Lines changed: 111 additions & 21 deletions

File tree

runtime/doc/version9.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
*version9.txt* For Vim version 9.1. Last change: 2025 Aug 08
1+
*version9.txt* For Vim version 9.1. Last change: 2025 Aug 12
22

33

44
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -41736,6 +41736,7 @@ Others: ~
4173641736
- |gv| works in operator pending mode and does not abort
4173741737
- The close button shown in the non-GUI 'tabline' will only be visible if the
4173841738
'mouse' option contains either "a" or any of the flags "n", "v", or "i".
41739+
- |C-indenting| handles compound literals.
4173941740

4174041741
*added-9.2*
4174141742
Added ~

src/cindent.c

Lines changed: 82 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -690,10 +690,9 @@ cin_islabel(void) // XXX
690690
/*
691691
* Return TRUE if string "s" ends with the string "find", possibly followed by
692692
* white space and comments. Skip strings and comments.
693-
* Ignore "ignore" after "find" if it's not NULL.
694693
*/
695694
static int
696-
cin_ends_in(char_u *s, char_u *find, char_u *ignore)
695+
cin_ends_in(char_u *s, char_u *find)
697696
{
698697
char_u *p = s;
699698
char_u *r;
@@ -705,8 +704,6 @@ cin_ends_in(char_u *s, char_u *find, char_u *ignore)
705704
if (STRNCMP(p, find, len) == 0)
706705
{
707706
r = skipwhite(p + len);
708-
if (ignore != NULL && STRNCMP(r, ignore, STRLEN(ignore)) == 0)
709-
r = skipwhite(r + STRLEN(ignore));
710707
if (cin_nocode(r))
711708
return TRUE;
712709
}
@@ -717,9 +714,77 @@ cin_ends_in(char_u *s, char_u *find, char_u *ignore)
717714
}
718715

719716
/*
720-
* Recognize structure initialization and enumerations:
717+
* Strings can be concatenated with comments between:
718+
* "string0" |*comment*| "string1"
719+
*/
720+
static char_u *
721+
cin_skip_comment_and_string(char_u *s)
722+
{
723+
char_u *r = NULL, *p = s;
724+
do
725+
{
726+
r = p;
727+
p = cin_skipcomment(p);
728+
if (*p)
729+
p = skip_string(p);
730+
} while (p != r);
731+
return p;
732+
}
733+
734+
/*
735+
* Recognize structure or compound literal initialization:
736+
* =|return [&][(typecast)] [{]
737+
* The number of opening braces is arbitrary.
738+
*/
739+
static int
740+
cin_is_compound_init(char_u *s)
741+
{
742+
char_u *p = s, *r = NULL;
743+
744+
while (*p)
745+
{
746+
if (*p == '=')
747+
p = r = cin_skipcomment(p + 1);
748+
else if (!STRNCMP(p, "return", 6) && !vim_isIDc(p[6])
749+
&& (p == s || (p > s && !vim_isIDc(p[-1]))))
750+
p = r = cin_skipcomment(p + 6);
751+
else
752+
p = cin_skip_comment_and_string(p + 1);
753+
}
754+
if (!r)
755+
return FALSE;
756+
p = r; // p points now after '=' or "return"
757+
758+
if (cin_nocode(p))
759+
return TRUE;
760+
761+
if (*p == '&')
762+
p = cin_skipcomment(p + 1);
763+
764+
if (*p == '(') // skip a typecast
765+
{
766+
int open_count = 1;
767+
do
768+
{
769+
p = cin_skip_comment_and_string(p + 1);
770+
if (cin_nocode(p))
771+
return TRUE;
772+
open_count += (*p == '(') - (*p == ')');
773+
} while (open_count);
774+
p = cin_skipcomment(p + 1);
775+
if (cin_nocode(p))
776+
return TRUE;
777+
}
778+
779+
while (*p == '{')
780+
p = cin_skipcomment(p + 1);
781+
return cin_nocode(p);
782+
}
783+
784+
/*
785+
* Recognize enumerations:
721786
* "[typedef] [static|public|protected|private] enum"
722-
* "[typedef] [static|public|protected|private] = {"
787+
* Call another function to recognize structure initialization.
723788
*/
724789
static int
725790
cin_isinit(void)
@@ -753,10 +818,7 @@ cin_isinit(void)
753818
if (cin_starts_with(s, "enum"))
754819
return TRUE;
755820

756-
if (cin_ends_in(s, (char_u *)"=", (char_u *)"{"))
757-
return TRUE;
758-
759-
return FALSE;
821+
return cin_is_compound_init(s);
760822
}
761823

762824
// Maximum number of lines to search back for a "namespace" line.
@@ -1634,7 +1696,7 @@ get_baseclass_amount(int col)
16341696
if (find_last_paren(ml_get_curline(), '(', ')')
16351697
&& (trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL)
16361698
amount = get_indent_lnum(trypos->lnum); // XXX
1637-
if (!cin_ends_in(ml_get_curline(), (char_u *)",", NULL))
1699+
if (!cin_ends_in(ml_get_curline(), (char_u *)","))
16381700
amount += curbuf->b_ind_cpp_baseclass;
16391701
}
16401702
else
@@ -2505,7 +2567,7 @@ get_c_indent(void)
25052567
cur_amount = MAXCOL;
25062568
l = ml_get(our_paren_pos.lnum);
25072569
if (curbuf->b_ind_unclosed_wrapped
2508-
&& cin_ends_in(l, (char_u *)"(", NULL))
2570+
&& cin_ends_in(l, (char_u *)"("))
25092571
{
25102572
// look for opening unmatched paren, indent one level
25112573
// for each additional level
@@ -3702,8 +3764,8 @@ get_c_indent(void)
37023764
&& !cin_nocode(theline)
37033765
&& vim_strchr(theline, '{') == NULL
37043766
&& vim_strchr(theline, '}') == NULL
3705-
&& !cin_ends_in(theline, (char_u *)":", NULL)
3706-
&& !cin_ends_in(theline, (char_u *)",", NULL)
3767+
&& !cin_ends_in(theline, (char_u *)":")
3768+
&& !cin_ends_in(theline, (char_u *)",")
37073769
&& cin_isfuncdecl(NULL, cur_curpos.lnum + 1,
37083770
cur_curpos.lnum + 1)
37093771
&& !cin_isterminated(theline, FALSE, TRUE))
@@ -3764,7 +3826,7 @@ get_c_indent(void)
37643826
// } foo,
37653827
// bar;
37663828
n = 0;
3767-
if (cin_ends_in(l, (char_u *)",", NULL)
3829+
if (cin_ends_in(l, (char_u *)",")
37683830
|| (*l != NUL && (n = l[STRLEN(l) - 1]) == '\\'))
37693831
{
37703832
// take us back to opening paren
@@ -3812,14 +3874,14 @@ get_c_indent(void)
38123874
// comments) align at column 0. For example:
38133875
// char *string_array[] = { "foo",
38143876
// / * x * / "b};ar" }; / * foobar * /
3815-
if (cin_ends_in(l, (char_u *)"};", NULL))
3877+
if (cin_ends_in(l, (char_u *)"};"))
38163878
break;
38173879

38183880
// If the previous line ends on '[' we are probably in an
38193881
// array constant:
38203882
// something = [
38213883
// 234, <- extra indent
3822-
if (cin_ends_in(l, (char_u *)"[", NULL))
3884+
if (cin_ends_in(l, (char_u *)"["))
38233885
{
38243886
amount = get_indent() + ind_continuation;
38253887
break;
@@ -3840,7 +3902,7 @@ get_c_indent(void)
38403902
break;
38413903
}
38423904
if (curwin->w_cursor.lnum > 0
3843-
&& cin_ends_in(look, (char_u *)"}", NULL))
3905+
&& cin_ends_in(look, (char_u *)"}"))
38443906
break;
38453907

38463908
curwin->w_cursor = curpos_save;
@@ -3860,10 +3922,10 @@ get_c_indent(void)
38603922
// int foo,
38613923
// bar;
38623924
// indent_to_0 here;
3863-
if (cin_ends_in(l, (char_u *)";", NULL))
3925+
if (cin_ends_in(l, (char_u *)";"))
38643926
{
38653927
l = ml_get(curwin->w_cursor.lnum - 1);
3866-
if (cin_ends_in(l, (char_u *)",", NULL)
3928+
if (cin_ends_in(l, (char_u *)",")
38673929
|| (*l != NUL && l[STRLEN(l) - 1] == '\\'))
38683930
break;
38693931
l = ml_get_curline();

src/testdir/test_indent.vim

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,31 @@ func Test_userlabel_indent()
119119
close!
120120
endfunc
121121

122+
" Test that struct members are aligned
123+
func Test_struct_indent()
124+
new
125+
call setline(1, ['struct a a = {', '1,', '1,'])
126+
normal gg=G
127+
call assert_equal(getline(2), getline(3))
128+
129+
call setline(1, 'a = (struct a) {')
130+
normal gg=G
131+
call assert_equal(getline(2), getline(3))
132+
133+
call setline(1, 'void *ptr = &(static struct a) {{')
134+
normal gg=G
135+
call assert_equal(getline(2), getline(3))
136+
137+
call setline(1, 'a = (macro(arg1, "str)))")) {')
138+
normal gg=G
139+
call assert_equal(getline(2), getline(3))
140+
141+
call setline(1, 'return (struct a) {')
142+
normal gg=G
143+
call assert_equal(getline(2), getline(3))
144+
close!
145+
endfunc
146+
122147
" Test for 'copyindent'
123148
func Test_copyindent()
124149
new

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,8 @@ static char *(features[]) =
719719

720720
static int included_patches[] =
721721
{ /* Add new patch number below this line */
722+
/**/
723+
1626,
722724
/**/
723725
1625,
724726
/**/

0 commit comments

Comments
 (0)