vim-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.
6e371ecb27
This commit is contained in:
zeertzjq 2022-01-31 15:44:54 +08:00
parent ef5cd99df0
commit eda957db10
7 changed files with 95 additions and 22 deletions

View File

@ -952,11 +952,13 @@ int copy_indent(int size, char_u *src)
///
/// "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.
///
/// @param dir FORWARD or BACKWARD
///
/// @return true on success, false on failure
int open_line(int dir, int flags, int second_line_indent)
int open_line(int dir, int flags, int second_line_indent, bool *did_do_comment)
{
char_u *next_line = NULL; // copy of the next line
char_u *p_extra = NULL; // what goes to next line
@ -969,6 +971,7 @@ int open_line(int dir, int flags, int second_line_indent)
bool retval = false; // 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
@ -977,6 +980,7 @@ int open_line(int dir, int flags, int second_line_indent)
pos_T *pos;
bool do_si = (!p_paste && curbuf->b_p_si && !curbuf->b_p_cin
&& *curbuf->b_p_inde == NUL);
bool do_cindent;
bool no_si = false; // reset did_si afterwards
int first_char = NUL; // init for GCC
int vreplace_mode;
@ -1189,11 +1193,29 @@ int open_line(int dir, int flags, int second_line_indent)
did_ai = true;
}
// May do indenting after opening a new line.
do_cindent = !p_paste && (curbuf->b_p_cin || *curbuf->b_p_inde != NUL)
&& in_cinkeys(dir == FORWARD ? KEY_OPEN_FORW : KEY_OPEN_BACK,
' ', linewhite(curwin->w_cursor.lnum));
// 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);
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;
}
}
}
}
} else {
lead_len = 0;
}
@ -1349,6 +1371,13 @@ int open_line(int dir, int flags, int second_line_indent)
STRLCPY(leader, saved_line, lead_len + 1);
// TODO(vim): handle multi-byte and double width chars
for (int li = 0; li < comment_start; li++) {
if (!ascii_iswhite(leader[li])) {
leader[li] = ' ';
}
}
// Replace leader with lead_repl, right or left adjusted
if (lead_repl != NULL) {
int c = 0;
@ -1758,13 +1787,7 @@ int open_line(int dir, int flags, int second_line_indent)
ai_col = (colnr_T)getwhitecols_curline();
}
// May do indenting after opening a new line.
if (!p_paste
&& (curbuf->b_p_cin
|| *curbuf->b_p_inde != NUL
)
&& 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();
}

View File

@ -6021,6 +6021,7 @@ static void internal_format(int textwidth, int second_indent, int flags, int for
char_u *saved_text = NULL;
colnr_T col;
colnr_T end_col;
bool did_do_comment = false;
virtcol = get_nolist_virtcol()
+ char2cells(c != NUL ? c : gchar_cursor());
@ -6294,11 +6295,18 @@ static void internal_format(int textwidth, int second_indent, int flags, int for
+ (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) {
if (!(flags & INSCHAR_COM_LIST)) {
@ -9183,7 +9191,7 @@ static bool ins_eol(int c)
AppendToRedobuff(NL_STR);
bool i = open_line(FORWARD,
has_format_option(FO_RET_COMS) ? OPENLINE_DO_COM : 0,
old_indent);
old_indent, NULL);
old_indent = 0;
can_cindent = true;
// When inserting a line the cursor line must never be in a closed fold.

View File

@ -1906,13 +1906,26 @@ int 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)) {
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
* comment, try using the 'comments' option.

View File

@ -6685,9 +6685,8 @@ static void n_opencmd(cmdarg_T *cap)
(cap->cmdchar == 'o' ? 1 : 0))
)
&& open_line(cap->cmdchar == 'O' ? BACKWARD : FORWARD,
has_format_option(FO_OPEN_COMS)
? OPENLINE_DO_COM : 0,
0)) {
has_format_option(FO_OPEN_COMS) ? OPENLINE_DO_COM : 0,
0, NULL)) {
if (win_cursorline_standout(curwin)) {
// force redraw of cursorline
curwin->w_valid &= ~VALID_CROW;

View File

@ -2318,7 +2318,7 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
* Return MAXCOL if not, otherwise return the column.
* TODO: skip strings.
*/
static int check_linecomment(const char_u *line)
int check_linecomment(const char_u *line)
{
const char_u *p = line; // scan from start
// skip Lispish one-line comments

View File

@ -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!