mirror of
https://github.com/neovim/neovim.git
synced 2025-09-05 19:08:15 +00:00
vim-patch:9.1.1626: cindent: does not handle compound literals (#35319)
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: vim/vim#2090
fixes: vim/vim#12491
closes: vim/vim#17865
5ba6e41d37
Co-authored-by: Anttoni Erkkilä <anttoni.erkkila@protonmail.com>
This commit is contained in:
@@ -262,6 +262,10 @@ preprocess_patch() {
|
|||||||
LC_ALL=C sed -Ee 's/( [ab]\/src\/nvim)\/evalwindow\.c/\1\/eval\/window.c/g' \
|
LC_ALL=C sed -Ee 's/( [ab]\/src\/nvim)\/evalwindow\.c/\1\/eval\/window.c/g' \
|
||||||
"$file" > "$file".tmp && mv "$file".tmp "$file"
|
"$file" > "$file".tmp && mv "$file".tmp "$file"
|
||||||
|
|
||||||
|
# Rename cindent.c to indent_c.c
|
||||||
|
LC_ALL=C sed -Ee 's/( [ab]\/src\/nvim)\/cindent\.c/\1\/indent_c.c/g' \
|
||||||
|
"$file" > "$file".tmp && mv "$file".tmp "$file"
|
||||||
|
|
||||||
# Rename map.c to mapping.c
|
# Rename map.c to mapping.c
|
||||||
LC_ALL=C sed -Ee 's/( [ab]\/src\/nvim)\/map\.c/\1\/mapping.c/g' \
|
LC_ALL=C sed -Ee 's/( [ab]\/src\/nvim)\/map\.c/\1\/mapping.c/g' \
|
||||||
"$file" > "$file".tmp && mv "$file".tmp "$file"
|
"$file" > "$file".tmp && mv "$file".tmp "$file"
|
||||||
|
@@ -410,10 +410,76 @@ static bool cin_islabel(void) // XXX
|
|||||||
return true; // label at start of file???
|
return true; // label at start of file???
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recognize structure initialization and enumerations:
|
/// Strings can be concatenated with comments between:
|
||||||
// "[typedef] [static|public|protected|private] enum"
|
/// "string0" |*comment*| "string1"
|
||||||
// "[typedef] [static|public|protected|private] = {"
|
static const char *cin_skip_comment_and_string(const char *s)
|
||||||
static int cin_isinit(void)
|
{
|
||||||
|
const char *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 bool cin_is_compound_init(const char *s)
|
||||||
|
{
|
||||||
|
const char *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"
|
||||||
|
/// Calls another function to recognize structure initialization.
|
||||||
|
static bool cin_isinit(void)
|
||||||
{
|
{
|
||||||
const char *s;
|
const char *s;
|
||||||
static char *skip[] = { "static", "public", "protected", "private" };
|
static char *skip[] = { "static", "public", "protected", "private" };
|
||||||
@@ -444,11 +510,7 @@ static int cin_isinit(void)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cin_ends_in(s, "=", "{")) {
|
return cin_is_compound_init(s);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Recognize a switch label: "case .*:" or "default:".
|
/// Recognize a switch label: "case .*:" or "default:".
|
||||||
@@ -1299,7 +1361,7 @@ static int get_baseclass_amount(int col)
|
|||||||
&& (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(get_cursor_line_ptr(), ",", NULL)) {
|
if (!cin_ends_in(get_cursor_line_ptr(), ",")) {
|
||||||
amount += curbuf->b_ind_cpp_baseclass;
|
amount += curbuf->b_ind_cpp_baseclass;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -1315,8 +1377,7 @@ static int get_baseclass_amount(int col)
|
|||||||
|
|
||||||
/// 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 cin_ends_in(const char *s, const char *find)
|
||||||
static int cin_ends_in(const char *s, const char *find, const char *ignore)
|
|
||||||
{
|
{
|
||||||
const char *p = s;
|
const char *p = s;
|
||||||
const char *r;
|
const char *r;
|
||||||
@@ -1326,9 +1387,6 @@ static int cin_ends_in(const char *s, const char *find, const char *ignore)
|
|||||||
p = cin_skipcomment(p);
|
p = cin_skipcomment(p);
|
||||||
if (strncmp(p, find, (size_t)len) == 0) {
|
if (strncmp(p, find, (size_t)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;
|
||||||
}
|
}
|
||||||
@@ -2264,8 +2322,7 @@ int get_c_indent(void)
|
|||||||
if (theline[0] != ')') {
|
if (theline[0] != ')') {
|
||||||
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, "(")) {
|
||||||
&& cin_ends_in(l, "(", NULL)) {
|
|
||||||
// look for opening unmatched paren, indent one level
|
// look for opening unmatched paren, indent one level
|
||||||
// for each additional level
|
// for each additional level
|
||||||
n = 1;
|
n = 1;
|
||||||
@@ -3393,8 +3450,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, ":", NULL)
|
&& !cin_ends_in(theline, ":")
|
||||||
&& !cin_ends_in(theline, ",", NULL)
|
&& !cin_ends_in(theline, ",")
|
||||||
&& cin_isfuncdecl(NULL, cur_curpos.lnum + 1, cur_curpos.lnum + 1)
|
&& cin_isfuncdecl(NULL, cur_curpos.lnum + 1, cur_curpos.lnum + 1)
|
||||||
&& !cin_isterminated(theline, false, true)) {
|
&& !cin_isterminated(theline, false, true)) {
|
||||||
amount = curbuf->b_ind_func_type;
|
amount = curbuf->b_ind_func_type;
|
||||||
@@ -3451,7 +3508,7 @@ term_again:
|
|||||||
// ...
|
// ...
|
||||||
// } foo,
|
// } foo,
|
||||||
// bar;
|
// bar;
|
||||||
if (cin_ends_in(l, ",", NULL)
|
if (cin_ends_in(l, ",")
|
||||||
|| (*l != NUL && (n = (uint8_t)l[strlen(l) - 1]) == '\\')) {
|
|| (*l != NUL && (n = (uint8_t)l[strlen(l) - 1]) == '\\')) {
|
||||||
// take us back to opening paren
|
// take us back to opening paren
|
||||||
if (find_last_paren(l, '(', ')')
|
if (find_last_paren(l, '(', ')')
|
||||||
@@ -3502,7 +3559,7 @@ 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, "};", NULL)) {
|
if (cin_ends_in(l, "};")) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3510,7 +3567,7 @@ term_again:
|
|||||||
// array constant:
|
// array constant:
|
||||||
// something = [
|
// something = [
|
||||||
// 234, <- extra indent
|
// 234, <- extra indent
|
||||||
if (cin_ends_in(l, "[", NULL)) {
|
if (cin_ends_in(l, "[")) {
|
||||||
amount = get_indent() + ind_continuation;
|
amount = get_indent() + ind_continuation;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -3528,8 +3585,7 @@ term_again:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (curwin->w_cursor.lnum > 0
|
if (curwin->w_cursor.lnum > 0 && cin_ends_in(look, "}")) {
|
||||||
&& cin_ends_in(look, "}", NULL)) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3549,9 +3605,9 @@ term_again:
|
|||||||
// int foo,
|
// int foo,
|
||||||
// bar;
|
// bar;
|
||||||
// indent_to_0 here;
|
// indent_to_0 here;
|
||||||
if (cin_ends_in(l, ";", NULL)) {
|
if (cin_ends_in(l, ";")) {
|
||||||
l = ml_get(curwin->w_cursor.lnum - 1);
|
l = ml_get(curwin->w_cursor.lnum - 1);
|
||||||
if (cin_ends_in(l, ",", NULL)
|
if (cin_ends_in(l, ",")
|
||||||
|| (*l != NUL && l[strlen(l) - 1] == '\\')) {
|
|| (*l != NUL && l[strlen(l) - 1] == '\\')) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@@ -122,6 +122,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
|
||||||
|
Reference in New Issue
Block a user