# HG changeset patch # User Bram Moolenaar # Date 1639319403 -3600 # Node ID 9596c652420b41ca6394522e4ec32417fdebe5ed # Parent 48000f73fe080c6fe9e94bf689376090c7a18c21 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 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. diff --git a/src/change.c b/src/change.c --- 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(); diff --git a/src/cindent.c b/src/cindent.c --- 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 diff --git a/src/edit.c b/src/edit.c --- 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; diff --git a/src/normal.c b/src/normal.c --- 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) diff --git a/src/proto/change.pro b/src/proto/change.pro --- 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 : */ diff --git a/src/proto/search.pro b/src/proto/search.pro --- 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); diff --git a/src/search.c b/src/search.c --- 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; diff --git a/src/testdir/test_cindent.vim b/src/testdir/test_cindent.vim --- 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, diff --git a/src/testdir/test_textformat.vim b/src/testdir/test_textformat.vim --- 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! diff --git a/src/textformat.c b/src/textformat.c --- 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) { diff --git a/src/version.c b/src/version.c --- 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,