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.erkkila@protonmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
committed by
Christian Brabandt
parent
59e1d7f353
commit
5ba6e41d37
@ -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
|
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||||
@ -41736,6 +41736,7 @@ Others: ~
|
|||||||
- |gv| works in operator pending mode and does not abort
|
- |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
|
- 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".
|
'mouse' option contains either "a" or any of the flags "n", "v", or "i".
|
||||||
|
- |C-indenting| handles compound literals.
|
||||||
|
|
||||||
*added-9.2*
|
*added-9.2*
|
||||||
Added ~
|
Added ~
|
||||||
|
|||||||
102
src/cindent.c
102
src/cindent.c
@ -690,10 +690,9 @@ cin_islabel(void) // XXX
|
|||||||
/*
|
/*
|
||||||
* Return TRUE if string "s" ends with the string "find", possibly followed by
|
* Return TRUE if string "s" ends with the string "find", possibly followed by
|
||||||
* white space and comments. Skip strings and comments.
|
* white space and comments. Skip strings and comments.
|
||||||
* Ignore "ignore" after "find" if it's not NULL.
|
|
||||||
*/
|
*/
|
||||||
static int
|
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 *p = s;
|
||||||
char_u *r;
|
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)
|
if (STRNCMP(p, find, len) == 0)
|
||||||
{
|
{
|
||||||
r = skipwhite(p + len);
|
r = skipwhite(p + len);
|
||||||
if (ignore != NULL && STRNCMP(r, ignore, STRLEN(ignore)) == 0)
|
|
||||||
r = skipwhite(r + STRLEN(ignore));
|
|
||||||
if (cin_nocode(r))
|
if (cin_nocode(r))
|
||||||
return TRUE;
|
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] enum"
|
||||||
* "[typedef] [static|public|protected|private] = {"
|
* Call another function to recognize structure initialization.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
cin_isinit(void)
|
cin_isinit(void)
|
||||||
@ -753,10 +818,7 @@ cin_isinit(void)
|
|||||||
if (cin_starts_with(s, "enum"))
|
if (cin_starts_with(s, "enum"))
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
if (cin_ends_in(s, (char_u *)"=", (char_u *)"{"))
|
return cin_is_compound_init(s);
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Maximum number of lines to search back for a "namespace" line.
|
// 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(), '(', ')')
|
if (find_last_paren(ml_get_curline(), '(', ')')
|
||||||
&& (trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL)
|
&& (trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL)
|
||||||
amount = get_indent_lnum(trypos->lnum); // XXX
|
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;
|
amount += curbuf->b_ind_cpp_baseclass;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -2505,7 +2567,7 @@ get_c_indent(void)
|
|||||||
cur_amount = MAXCOL;
|
cur_amount = MAXCOL;
|
||||||
l = ml_get(our_paren_pos.lnum);
|
l = ml_get(our_paren_pos.lnum);
|
||||||
if (curbuf->b_ind_unclosed_wrapped
|
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
|
// look for opening unmatched paren, indent one level
|
||||||
// for each additional level
|
// for each additional level
|
||||||
@ -3702,8 +3764,8 @@ term_again:
|
|||||||
&& !cin_nocode(theline)
|
&& !cin_nocode(theline)
|
||||||
&& vim_strchr(theline, '{') == NULL
|
&& vim_strchr(theline, '{') == NULL
|
||||||
&& vim_strchr(theline, '}') == NULL
|
&& vim_strchr(theline, '}') == NULL
|
||||||
&& !cin_ends_in(theline, (char_u *)":", NULL)
|
&& !cin_ends_in(theline, (char_u *)":")
|
||||||
&& !cin_ends_in(theline, (char_u *)",", NULL)
|
&& !cin_ends_in(theline, (char_u *)",")
|
||||||
&& cin_isfuncdecl(NULL, cur_curpos.lnum + 1,
|
&& cin_isfuncdecl(NULL, cur_curpos.lnum + 1,
|
||||||
cur_curpos.lnum + 1)
|
cur_curpos.lnum + 1)
|
||||||
&& !cin_isterminated(theline, FALSE, TRUE))
|
&& !cin_isterminated(theline, FALSE, TRUE))
|
||||||
@ -3764,7 +3826,7 @@ term_again:
|
|||||||
// } foo,
|
// } foo,
|
||||||
// bar;
|
// bar;
|
||||||
n = 0;
|
n = 0;
|
||||||
if (cin_ends_in(l, (char_u *)",", NULL)
|
if (cin_ends_in(l, (char_u *)",")
|
||||||
|| (*l != NUL && (n = l[STRLEN(l) - 1]) == '\\'))
|
|| (*l != NUL && (n = l[STRLEN(l) - 1]) == '\\'))
|
||||||
{
|
{
|
||||||
// take us back to opening paren
|
// take us back to opening paren
|
||||||
@ -3812,14 +3874,14 @@ term_again:
|
|||||||
// comments) align at column 0. For example:
|
// comments) align at column 0. For example:
|
||||||
// char *string_array[] = { "foo",
|
// char *string_array[] = { "foo",
|
||||||
// / * x * / "b};ar" }; / * foobar * /
|
// / * x * / "b};ar" }; / * foobar * /
|
||||||
if (cin_ends_in(l, (char_u *)"};", NULL))
|
if (cin_ends_in(l, (char_u *)"};"))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// If the previous line ends on '[' we are probably in an
|
// If the previous line ends on '[' we are probably in an
|
||||||
// array constant:
|
// array constant:
|
||||||
// something = [
|
// something = [
|
||||||
// 234, <- extra indent
|
// 234, <- extra indent
|
||||||
if (cin_ends_in(l, (char_u *)"[", NULL))
|
if (cin_ends_in(l, (char_u *)"["))
|
||||||
{
|
{
|
||||||
amount = get_indent() + ind_continuation;
|
amount = get_indent() + ind_continuation;
|
||||||
break;
|
break;
|
||||||
@ -3840,7 +3902,7 @@ term_again:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (curwin->w_cursor.lnum > 0
|
if (curwin->w_cursor.lnum > 0
|
||||||
&& cin_ends_in(look, (char_u *)"}", NULL))
|
&& cin_ends_in(look, (char_u *)"}"))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
curwin->w_cursor = curpos_save;
|
curwin->w_cursor = curpos_save;
|
||||||
@ -3860,10 +3922,10 @@ term_again:
|
|||||||
// int foo,
|
// int foo,
|
||||||
// bar;
|
// bar;
|
||||||
// indent_to_0 here;
|
// 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);
|
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] == '\\'))
|
|| (*l != NUL && l[STRLEN(l) - 1] == '\\'))
|
||||||
break;
|
break;
|
||||||
l = ml_get_curline();
|
l = ml_get_curline();
|
||||||
|
|||||||
@ -119,6 +119,31 @@ func Test_userlabel_indent()
|
|||||||
close!
|
close!
|
||||||
endfunc
|
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'
|
" Test for 'copyindent'
|
||||||
func Test_copyindent()
|
func Test_copyindent()
|
||||||
new
|
new
|
||||||
|
|||||||
@ -719,6 +719,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
1626,
|
||||||
/**/
|
/**/
|
||||||
1625,
|
1625,
|
||||||
/**/
|
/**/
|
||||||
|
|||||||
Reference in New Issue
Block a user