changeset 26516:9596c652420b v8.2.3787

patch 8.2.3787: no proper formatting of a C line comment after a statement Commit: https://github.com/vim/vim/commit/6e371ecb27227ff8fedd8561d0f3880a17576848 Author: Bram Moolenaar <Bram@vim.org> Date: Sun Dec 12 14:16:39 2021 +0000 patch 8.2.3787: no proper formatting of a C line comment after a statement Problem: No proper formatting of a C line comment after a statement. Solution: Find the start of the line comment, insert the comment leader and indent the comment properly.
author Bram Moolenaar <Bram@vim.org>
date Sun, 12 Dec 2021 15:30:03 +0100
parents 48000f73fe08
children 7dfc4c45f698
files src/change.c src/cindent.c src/edit.c src/normal.c src/proto/change.pro src/proto/search.pro src/search.c src/testdir/test_cindent.vim src/testdir/test_textformat.vim src/textformat.c src/version.c
diffstat 11 files changed, 119 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- a/src/change.c
+++ b/src/change.c
@@ -1356,6 +1356,8 @@ del_bytes(
  *
  * "second_line_indent": indent for after ^^D in Insert mode or if flag
  *			  OPENLINE_COM_LIST
+ * "did_do_comment" is set to TRUE when intentionally putting the comment
+ * leader in fromt of the new line.
  *
  * Return OK for success, FAIL for failure
  */
@@ -1363,7 +1365,8 @@ del_bytes(
 open_line(
     int		dir,		// FORWARD or BACKWARD
     int		flags,
-    int		second_line_indent)
+    int		second_line_indent,
+    int		*did_do_comment UNUSED)
 {
     char_u	*saved_line;		// copy of the original line
     char_u	*next_line = NULL;	// copy of the next line
@@ -1378,6 +1381,7 @@ open_line(
     int		retval = FAIL;		// return value
     int		extra_len = 0;		// length of p_extra string
     int		lead_len;		// length of comment leader
+    int		comment_start = 0;	// start index of the comment leader
     char_u	*lead_flags;	// position in 'comments' for comment leader
     char_u	*leader = NULL;		// copy of comment leader
     char_u	*allocated = NULL;	// allocated memory
@@ -1393,6 +1397,9 @@ open_line(
 					&& *curbuf->b_p_inde == NUL
 # endif
 			);
+#ifdef FEAT_CINDENT
+    int		do_cindent;
+#endif
     int		no_si = FALSE;		// reset did_si afterwards
     int		first_char = NUL;	// init for GCC
 #endif
@@ -1632,12 +1639,43 @@ open_line(
 	did_ai = TRUE;
     }
 
+#ifdef FEAT_CINDENT
+    // May do indenting after opening a new line.
+    do_cindent = !p_paste && (curbuf->b_p_cin
+#  ifdef FEAT_EVAL
+		    || *curbuf->b_p_inde != NUL
+#  endif
+		)
+	    && in_cinkeys(dir == FORWARD
+		? KEY_OPEN_FORW
+		: KEY_OPEN_BACK, ' ', linewhite(curwin->w_cursor.lnum));
+#endif
+
     // Find out if the current line starts with a comment leader.
     // This may then be inserted in front of the new line.
     end_comment_pending = NUL;
     if (flags & OPENLINE_DO_COM)
+    {
 	lead_len = get_leader_len(saved_line, &lead_flags,
 							dir == BACKWARD, TRUE);
+#ifdef FEAT_CINDENT
+	if (lead_len == 0 && do_cindent)
+	{
+	    comment_start = check_linecomment(saved_line);
+	    if (comment_start != MAXCOL)
+	    {
+		lead_len = get_leader_len(saved_line + comment_start,
+					   &lead_flags, dir == BACKWARD, TRUE);
+		if (lead_len != 0)
+		{
+		    lead_len += comment_start;
+		    if (did_do_comment != NULL)
+			*did_do_comment = TRUE;
+		}
+	    }
+	}
+#endif
+    }
     else
 	lead_len = 0;
     if (lead_len > 0)
@@ -1799,8 +1837,15 @@ open_line(
 		lead_len = 0;
 	    else
 	    {
+		int li;
+
 		vim_strncpy(leader, saved_line, lead_len);
 
+		// TODO: handle multi-byte and double width chars
+		for (li = 0; li < comment_start; ++li)
+		    if (!VIM_ISWHITE(leader[li]))
+			leader[li] = ' ';
+
 		// Replace leader with lead_repl, right or left adjusted
 		if (lead_repl != NULL)
 		{
@@ -2247,15 +2292,7 @@ open_line(
 #endif
 #ifdef FEAT_CINDENT
     // May do indenting after opening a new line.
-    if (!p_paste
-	    && (curbuf->b_p_cin
-#  ifdef FEAT_EVAL
-		    || *curbuf->b_p_inde != NUL
-#  endif
-		)
-	    && in_cinkeys(dir == FORWARD
-		? KEY_OPEN_FORW
-		: KEY_OPEN_BACK, ' ', linewhite(curwin->w_cursor.lnum)))
+    if (do_cindent)
     {
 	do_c_expr_indent();
 	ai_col = (colnr_T)getwhitecols_curline();
--- a/src/cindent.c
+++ b/src/cindent.c
@@ -2144,13 +2144,30 @@ get_c_indent(void)
 
     // If we're inside a "//" comment and there is a "//" comment in a
     // previous line, lineup with that one.
-    if (cin_islinecomment(theline)
-	    && (trypos = find_line_comment()) != NULL) // XXX
+    if (cin_islinecomment(theline))
     {
-	// find how indented the line beginning the comment is
-	getvcol(curwin, trypos, &col, NULL, NULL);
-	amount = col;
-	goto theend;
+	pos_T	linecomment_pos;
+
+	trypos = find_line_comment(); // XXX
+	if (trypos == NULL && curwin->w_cursor.lnum > 1)
+	{
+	    // There may be a statement before the comment, search from the end
+	    // of the line for a comment start.
+	    linecomment_pos.col =
+			  check_linecomment(ml_get(curwin->w_cursor.lnum - 1));
+	    if (linecomment_pos.col != MAXCOL)
+	    {
+	        trypos = &linecomment_pos;
+	        trypos->lnum = curwin->w_cursor.lnum - 1;
+	    }
+	}
+	if (trypos  != NULL)
+	{
+	    // find how indented the line beginning the comment is
+	    getvcol(curwin, trypos, &col, NULL, NULL);
+	    amount = col;
+	    goto theend;
+	}
     }
 
     // If we're inside a comment and not looking at the start of the
--- a/src/edit.c
+++ b/src/edit.c
@@ -5147,7 +5147,8 @@ ins_eol(int c)
 
     AppendToRedobuff(NL_STR);
     i = open_line(FORWARD,
-	    has_format_option(FO_RET_COMS) ? OPENLINE_DO_COM : 0, old_indent);
+	    has_format_option(FO_RET_COMS) ? OPENLINE_DO_COM : 0, old_indent,
+	    NULL);
     old_indent = 0;
 #ifdef FEAT_CINDENT
     can_cindent = TRUE;
--- a/src/normal.c
+++ b/src/normal.c
@@ -6511,7 +6511,7 @@ n_opencmd(cmdarg_T *cap)
 		       ) == OK
 		&& open_line(cap->cmdchar == 'O' ? BACKWARD : FORWARD,
 			 has_format_option(FO_OPEN_COMS) ? OPENLINE_DO_COM : 0,
-								      0) == OK)
+								0, NULL) == OK)
 	{
 #ifdef FEAT_CONCEAL
 	    if (curwin->w_p_cole > 0 && oldline != curwin->w_cursor.lnum)
--- a/src/proto/change.pro
+++ b/src/proto/change.pro
@@ -27,7 +27,7 @@ void ins_str(char_u *s);
 int del_char(int fixpos);
 int del_chars(long count, int fixpos);
 int del_bytes(long count, int fixpos_arg, int use_delcombine);
-int open_line(int dir, int flags, int second_line_indent);
+int open_line(int dir, int flags, int second_line_indent, int *did_do_comment);
 int truncate_line(int fixpos);
 void del_lines(long nlines, int undo);
 /* vim: set ft=c : */
--- a/src/proto/search.pro
+++ b/src/proto/search.pro
@@ -29,6 +29,7 @@ int search_for_exact_line(buf_T *buf, po
 int searchc(cmdarg_T *cap, int t_cmd);
 pos_T *findmatch(oparg_T *oap, int initc);
 pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int maxtravel);
+int check_linecomment(char_u *line);
 void showmatch(int c);
 int current_search(long count, int forward);
 int linewhite(linenr_T lnum);
--- a/src/search.c
+++ b/src/search.c
@@ -16,7 +16,6 @@
 static void set_vv_searchforward(void);
 static int first_submatch(regmmatch_T *rp);
 #endif
-static int check_linecomment(char_u *line);
 #ifdef FEAT_FIND_ID
 static void show_pat_in_path(char_u *, int,
 					 int, int, FILE *, linenr_T *, long);
@@ -2717,7 +2716,7 @@ findmatchlimit(
  * Return MAXCOL if not, otherwise return the column.
  * TODO: skip strings.
  */
-    static int
+    int
 check_linecomment(char_u *line)
 {
     char_u  *p;
--- a/src/testdir/test_cindent.vim
+++ b/src/testdir/test_cindent.vim
@@ -1694,9 +1694,9 @@ func Test_cindent_1()
   #endif
 
   int y;		// comment
-  // comment
-
-  // comment
+			// comment
+
+			// comment
 
   {
   	Constructor(int a,
--- a/src/testdir/test_textformat.vim
+++ b/src/testdir/test_textformat.vim
@@ -196,6 +196,36 @@ func Test_text_format()
   enew!
 endfunc
 
+func Test_format_c_comment()
+  new
+  setl ai cindent tw=40 et fo=croql
+  let text =<< trim END
+      var = 2345;  // asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf
+  END
+  call setline(1, text)
+  normal gql
+  let expected =<< trim END
+      var = 2345;  // asdf asdf asdf asdf asdf
+                   // asdf asdf asdf asdf asdf
+  END
+  call assert_equal(expected, getline(1, '$'))
+
+  %del
+  let text =<< trim END
+      var = 2345;  // asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf asdf
+  END
+  call setline(1, text)
+  normal gql
+  let expected =<< trim END
+      var = 2345;  // asdf asdf asdf asdf asdf
+                   // asdf asdf asdf asdf asdf
+                   // asdf asdf
+  END
+  call assert_equal(expected, getline(1, '$'))
+
+  bwipe!
+endfunc
+
 " Tests for :right, :center and :left on text with embedded TAB.
 func Test_format_align()
   enew!
--- a/src/textformat.c
+++ b/src/textformat.c
@@ -89,6 +89,7 @@ internal_format(
 	colnr_T	col;
 	colnr_T	end_col;
 	int	wcc;			// counter for whitespace chars
+	int	did_do_comment = FALSE;
 
 	virtcol = get_nolist_virtcol()
 		+ char2cells(c != NUL ? c : gchar_cursor());
@@ -352,10 +353,16 @@ internal_format(
 		+ (fo_white_par ? OPENLINE_KEEPTRAIL : 0)
 		+ (do_comments ? OPENLINE_DO_COM : 0)
 		+ ((flags & INSCHAR_COM_LIST) ? OPENLINE_COM_LIST : 0)
-		, ((flags & INSCHAR_COM_LIST) ? second_indent : old_indent));
+		, ((flags & INSCHAR_COM_LIST) ? second_indent : old_indent),
+		&did_do_comment);
 	if (!(flags & INSCHAR_COM_LIST))
 	    old_indent = 0;
 
+	// If a comment leader was inserted, may also do this on a following
+	// line.
+	if (did_do_comment)
+	    no_leader = FALSE;
+
 	replace_offset = 0;
 	if (first_line)
 	{
--- a/src/version.c
+++ b/src/version.c
@@ -754,6 +754,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    3787,
+/**/
     3786,
 /**/
     3785,