mirror of
				https://github.com/vim/vim.git
				synced 2025-10-30 09:47:20 -04:00 
			
		
		
		
	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
						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 | ||||
| @@ -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 ~ | ||||
|   | ||||
							
								
								
									
										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 | ||||
|  * 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(); | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -719,6 +719,8 @@ static char *(features[]) = | ||||
|  | ||||
| static int included_patches[] = | ||||
| {   /* Add new patch number below this line */ | ||||
| /**/ | ||||
|     1626, | ||||
| /**/ | ||||
|     1625, | ||||
| /**/ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user