aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/change.c42
-rw-r--r--src/nvim/edit.c23
-rw-r--r--src/nvim/indent_c.c213
-rw-r--r--src/nvim/normal.c5
-rw-r--r--src/nvim/ops.c11
-rw-r--r--src/nvim/search.c21
-rw-r--r--src/nvim/testdir/test_cindent.vim4
-rw-r--r--src/nvim/testdir/test_textformat.vim98
8 files changed, 288 insertions, 129 deletions
diff --git a/src/nvim/change.c b/src/nvim/change.c
index 0c16b204e3..54c4ba5319 100644
--- a/src/nvim/change.c
+++ b/src/nvim/change.c
@@ -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,30 @@ 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) {
+ if (flags & OPENLINE_DO_COM && dir == FORWARD) {
+ // Check for a line comment after code.
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, false, true);
+ if (lead_len != 0) {
+ lead_len += comment_start;
+ if (did_do_comment != NULL) {
+ *did_do_comment = true;
+ }
+ }
+ }
+ }
} else {
lead_len = 0;
}
@@ -1349,6 +1372,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 +1788,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();
}
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 095fa14752..f96e7261ca 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -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());
@@ -6136,8 +6137,7 @@ static void internal_format(int textwidth, int second_indent, int flags, int for
if (curwin->w_cursor.col <= (colnr_T)wantcol) {
break;
}
- } else if ((cc >= 0x100 || !utf_allow_break_before(cc))
- && fo_multibyte) {
+ } else if ((cc >= 0x100 || !utf_allow_break_before(cc)) && fo_multibyte) {
int ncc;
bool allow_break;
@@ -6294,11 +6294,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)) {
@@ -8292,6 +8299,7 @@ static bool ins_bs(int c, int mode, int *inserted_space_p)
int in_indent;
int oldState;
int cpc[MAX_MCO]; // composing characters
+ bool call_fix_indent = false;
// can't delete anything in an empty file
// can't backup past first character in buffer
@@ -8435,6 +8443,8 @@ static bool ins_bs(int c, int mode, int *inserted_space_p)
beginline(BL_WHITE);
if (curwin->w_cursor.col < save_col) {
mincol = curwin->w_cursor.col;
+ // should now fix the indent to match with the previous line
+ call_fix_indent = true;
}
curwin->w_cursor.col = save_col;
}
@@ -8569,6 +8579,11 @@ static bool ins_bs(int c, int mode, int *inserted_space_p)
if (curwin->w_cursor.col <= 1) {
did_ai = false;
}
+
+ if (call_fix_indent) {
+ fix_indent();
+ }
+
// It's a little strange to put backspaces into the redo
// buffer, but it makes auto-indent a lot easier to deal
// with.
@@ -9183,7 +9198,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.
diff --git a/src/nvim/indent_c.c b/src/nvim/indent_c.c
index eb24e13d24..7f483d02ab 100644
--- a/src/nvim/indent_c.c
+++ b/src/nvim/indent_c.c
@@ -41,9 +41,7 @@ static pos_T *ind_find_start_comment(void) // XXX
pos_T *find_start_comment(int ind_maxcomment) // XXX
{
- pos_T *pos;
- char_u *line;
- char_u *p;
+ pos_T *pos;
int64_t cur_maxcomment = ind_maxcomment;
for (;; ) {
@@ -55,11 +53,9 @@ pos_T *find_start_comment(int ind_maxcomment) // XXX
* Check if the comment start we found is inside a string.
* If it is then restrict the search to below this line and try again.
*/
- line = ml_get(pos->lnum);
- for (p = line; *p && (colnr_T)(p - line) < pos->col; ++p)
- p = skip_string(p);
- if ((colnr_T)(p - line) <= pos->col)
+ if (!is_pos_in_string(ml_get(pos->lnum), pos->col)) {
break;
+ }
cur_maxcomment = curwin->w_cursor.lnum - pos->lnum - 1;
if (cur_maxcomment <= 0) {
pos = NULL;
@@ -110,8 +106,6 @@ static pos_T *ind_find_start_CORS(linenr_T *is_raw)
static pos_T *find_start_rawstring(int ind_maxcomment) // XXX
{
pos_T *pos;
- char_u *line;
- char_u *p;
long cur_maxcomment = ind_maxcomment;
for (;;)
@@ -124,11 +118,9 @@ static pos_T *find_start_rawstring(int ind_maxcomment) // XXX
* Check if the raw string start we found is inside a string.
* If it is then restrict the search to below this line and try again.
*/
- line = ml_get(pos->lnum);
- for (p = line; *p && (colnr_T)(p - line) < pos->col; ++p)
- p = skip_string(p);
- if ((colnr_T)(p - line) <= pos->col)
- break;
+ if (!is_pos_in_string(ml_get(pos->lnum), pos->col)) {
+ break;
+ }
cur_maxcomment = curwin->w_cursor.lnum - pos->lnum - 1;
if (cur_maxcomment <= 0)
{
@@ -143,7 +135,7 @@ static pos_T *find_start_rawstring(int ind_maxcomment) // XXX
* Skip to the end of a "string" and a 'c' character.
* If there is no string or character, return argument unmodified.
*/
-static char_u *skip_string(char_u *p)
+static const char_u *skip_string(const char_u *p)
{
int i;
@@ -178,24 +170,24 @@ static char_u *skip_string(char_u *p)
continue; // continue for another string
}
} else if (p[0] == 'R' && p[1] == '"') {
- // Raw string: R"[delim](...)[delim]"
- char_u *delim = p + 2;
- char_u *paren = vim_strchr(delim, '(');
-
- if (paren != NULL) {
- const ptrdiff_t delim_len = paren - delim;
-
- for (p += 3; *p; ++p)
- if (p[0] == ')' && STRNCMP(p + 1, delim, delim_len) == 0
- && p[delim_len + 1] == '"')
- {
- p += delim_len + 1;
- break;
- }
- if (p[0] == '"') {
- continue; // continue for another string
- }
+ // Raw string: R"[delim](...)[delim]"
+ const char_u *delim = p + 2;
+ const char_u *paren = vim_strchr(delim, '(');
+
+ if (paren != NULL) {
+ const ptrdiff_t delim_len = paren - delim;
+
+ for (p += 3; *p; p++) {
+ if (p[0] == ')' && STRNCMP(p + 1, delim, delim_len) == 0
+ && p[delim_len + 1] == '"') {
+ p += delim_len + 1;
+ break;
+ }
+ }
+ if (p[0] == '"') {
+ continue; // continue for another string
}
+ }
}
break; // no string found
}
@@ -205,6 +197,16 @@ static char_u *skip_string(char_u *p)
return p;
}
+/// @returns true if "line[col]" is inside a C string.
+int is_pos_in_string(const char_u *line, colnr_T col)
+{
+ const char_u *p;
+
+ for (p = line; *p && (colnr_T)(p - line) < col; p++) {
+ p = skip_string(p);
+ }
+ return !((colnr_T)(p - line) <= col);
+}
/*
* Functions for C-indenting.
@@ -218,7 +220,7 @@ static char_u *skip_string(char_u *p)
/*
* Return true if the string "line" starts with a word from 'cinwords'.
*/
-bool cin_is_cinword(char_u *line)
+bool cin_is_cinword(const char_u *line)
{
bool retval = false;
@@ -246,10 +248,10 @@ bool cin_is_cinword(char_u *line)
* Skip over white space and C comments within the line.
* Also skip over Perl/shell comments if desired.
*/
-static char_u *cin_skipcomment(char_u *s)
+static const char_u *cin_skipcomment(const char_u *s)
{
while (*s) {
- char_u *prev_s = s;
+ const char_u *prev_s = s;
s = skipwhite(s);
@@ -283,7 +285,7 @@ static char_u *cin_skipcomment(char_u *s)
* Return TRUE if there is no code at *s. White space and comments are
* not considered code.
*/
-static int cin_nocode(char_u *s)
+static int cin_nocode(const char_u *s)
{
return *cin_skipcomment(s) == NUL;
}
@@ -312,9 +314,9 @@ static pos_T *find_line_comment(void) // XXX
}
/// Checks if `text` starts with "key:".
-static bool cin_has_js_key(char_u *text)
+static bool cin_has_js_key(const char_u *text)
{
- char_u *s = skipwhite(text);
+ const char_u *s = skipwhite(text);
char_u quote = 0;
if (*s == '\'' || *s == '"') {
@@ -341,7 +343,7 @@ static bool cin_has_js_key(char_u *text)
/// Checks if string matches "label:"; move to character after ':' if true.
/// "*s" must point to the start of the label, if there is one.
-static bool cin_islabel_skip(char_u **s)
+static bool cin_islabel_skip(const char_u **s)
FUNC_ATTR_NONNULL_ALL
{
if (!vim_isIDc(**s)) { // need at least one ID character
@@ -361,7 +363,7 @@ static bool cin_islabel_skip(char_u **s)
// Note: curwin->w_cursor must be where we are looking for the label.
bool cin_islabel(void) // XXX
{
- char_u *s = cin_skipcomment(get_cursor_line_ptr());
+ const char_u *s = cin_skipcomment(get_cursor_line_ptr());
// Exclude "default" from labels, since it should be indented
// like a switch label. Same for C++ scope declarations.
@@ -380,8 +382,8 @@ bool cin_islabel(void) // XXX
* label.
*/
pos_T cursor_save;
- pos_T *trypos;
- char_u *line;
+ pos_T *trypos;
+ const char_u *line;
cursor_save = curwin->w_cursor;
while (curwin->w_cursor.lnum > 1) {
@@ -424,8 +426,8 @@ bool cin_islabel(void) // XXX
*/
static int cin_isinit(void)
{
- char_u *s;
- static char *skip[] = {"static", "public", "protected", "private"};
+ const char_u *s;
+ static char *skip[] = { "static", "public", "protected", "private" };
s = cin_skipcomment(get_cursor_line_ptr());
@@ -460,7 +462,7 @@ static int cin_isinit(void)
* Recognize a switch label: "case .*:" or "default:".
*/
bool cin_iscase(
- char_u *s,
+ const char_u *s,
bool strict // Allow relaxed check of case statement for JS
)
{
@@ -503,7 +505,7 @@ bool cin_iscase(
/*
* Recognize a "default" switch label.
*/
-static int cin_isdefault(char_u *s)
+static int cin_isdefault(const char_u *s)
{
return STRNCMP(s, "default", 7) == 0
&& *(s = cin_skipcomment(s + 7)) == ':'
@@ -513,7 +515,7 @@ static int cin_isdefault(char_u *s)
/*
* Recognize a "public/private/protected" scope declaration label.
*/
-bool cin_isscopedecl(char_u *s)
+bool cin_isscopedecl(const char_u *s)
{
int i;
@@ -534,9 +536,9 @@ bool cin_isscopedecl(char_u *s)
#define FIND_NAMESPACE_LIM 20
// Recognize a "namespace" scope declaration.
-static bool cin_is_cpp_namespace(char_u *s)
+static bool cin_is_cpp_namespace(const char_u *s)
{
- char_u *p;
+ const char_u *p;
bool has_name = false;
bool has_name_start = false;
@@ -581,7 +583,7 @@ static bool cin_is_cpp_namespace(char_u *s)
* case 234: a = b;
* ^
*/
-static char_u *after_label(char_u *l)
+static const char_u *after_label(const char_u *l)
{
for (; *l; ++l) {
if (*l == ':') {
@@ -608,10 +610,10 @@ static char_u *after_label(char_u *l)
*/
static int get_indent_nolabel(linenr_T lnum) // XXX
{
- char_u *l;
+ const char_u *l;
pos_T fp;
colnr_T col;
- char_u *p;
+ const char_u *p;
l = ml_get(lnum);
p = after_label(l);
@@ -630,9 +632,9 @@ static int get_indent_nolabel(linenr_T lnum) // XXX
* label: if (asdf && asdfasdf)
* ^
*/
-static int skip_label(linenr_T lnum, char_u **pp)
+static int skip_label(linenr_T lnum, const char_u **pp)
{
- char_u *l;
+ const char_u *l;
int amount;
pos_T cursor_save;
@@ -713,8 +715,8 @@ static int cin_first_id_amount(void)
*/
static int cin_get_equal_amount(linenr_T lnum)
{
- char_u *line;
- char_u *s;
+ const char_u *line;
+ const char_u *s;
colnr_T col;
pos_T fp;
@@ -752,7 +754,7 @@ static int cin_get_equal_amount(linenr_T lnum)
/*
* Recognize a preprocessor statement: Any line that starts with '#'.
*/
-static int cin_ispreproc(char_u *s)
+static int cin_ispreproc(const char_u *s)
{
if (*skipwhite(s) == '#')
return TRUE;
@@ -763,9 +765,9 @@ static int cin_ispreproc(char_u *s)
/// continuation line of a preprocessor statement. Decrease "*lnump" to the
/// start and return the line in "*pp".
/// Put the amount of indent in "*amount".
-static int cin_ispreproc_cont(char_u **pp, linenr_T *lnump, int *amount)
+static int cin_ispreproc_cont(const char_u **pp, linenr_T *lnump, int *amount)
{
- char_u *line = *pp;
+ const char_u *line = *pp;
linenr_T lnum = *lnump;
int retval = false;
int candidate_amount = *amount;
@@ -799,7 +801,7 @@ static int cin_ispreproc_cont(char_u **pp, linenr_T *lnump, int *amount)
/*
* Recognize the start of a C or C++ comment.
*/
-static int cin_iscomment(char_u *p)
+static int cin_iscomment(const char_u *p)
{
return p[0] == '/' && (p[1] == '*' || p[1] == '/');
}
@@ -807,7 +809,7 @@ static int cin_iscomment(char_u *p)
/*
* Recognize the start of a "//" comment.
*/
-static int cin_islinecomment(char_u *p)
+static int cin_islinecomment(const char_u *p)
{
return p[0] == '/' && p[1] == '/';
}
@@ -822,8 +824,8 @@ static int cin_islinecomment(char_u *p)
* both apply in order to determine initializations).
*/
static char_u
-cin_isterminated (
- char_u *s,
+cin_isterminated(
+ const char_u *s,
int incl_open, // include '{' at the end as terminator
int incl_comma // recognize a trailing comma
)
@@ -872,9 +874,9 @@ cin_isterminated (
/// lines here.
/// @param[in] first_lnum Where to start looking.
/// @param[in] min_lnum The line before which we will not be looking.
-static int cin_isfuncdecl(char_u **sp, linenr_T first_lnum, linenr_T min_lnum)
+static int cin_isfuncdecl(const char_u **sp, linenr_T first_lnum, linenr_T min_lnum)
{
- char_u *s;
+ const char_u *s;
linenr_T lnum = first_lnum;
linenr_T save_lnum = curwin->w_cursor.lnum;
int retval = false;
@@ -975,12 +977,12 @@ done:
return retval;
}
-static int cin_isif(char_u *p)
+static int cin_isif(const char_u *p)
{
return STRNCMP(p, "if", 2) == 0 && !vim_isIDc(p[2]);
}
-static int cin_iselse(char_u *p)
+static int cin_iselse(const char_u *p)
{
if (*p == '}') { // accept "} else"
p = cin_skipcomment(p + 1);
@@ -988,7 +990,7 @@ static int cin_iselse(char_u *p)
return STRNCMP(p, "else", 4) == 0 && !vim_isIDc(p[4]);
}
-static int cin_isdo(char_u *p)
+static int cin_isdo(const char_u *p)
{
return STRNCMP(p, "do", 2) == 0 && !vim_isIDc(p[2]);
}
@@ -998,7 +1000,7 @@ static int cin_isdo(char_u *p)
* We only accept a "while (condition) ;", with only white space between the
* ')' and ';'. The condition may be spread over several lines.
*/
-static int cin_iswhileofdo(char_u *p, linenr_T lnum) // XXX
+static int cin_iswhileofdo(const char_u *p, linenr_T lnum) // XXX
{
pos_T cursor_save;
pos_T *trypos;
@@ -1032,7 +1034,7 @@ static int cin_iswhileofdo(char_u *p, linenr_T lnum) // XXX
* Otherwise return !0 and update "*poffset" to point to the place where the
* string was found.
*/
-static int cin_is_if_for_while_before_offset(char_u *line, int *poffset)
+static int cin_is_if_for_while_before_offset(const char_u *line, int *poffset)
{
int offset = *poffset;
@@ -1076,10 +1078,10 @@ probablyFound:
*/
static int cin_iswhileofdo_end(int terminated)
{
- char_u *line;
- char_u *p;
- char_u *s;
- pos_T *trypos;
+ const char_u *line;
+ const char_u *p;
+ const char_u *s;
+ pos_T *trypos;
int i;
if (terminated != ';') { // there must be a ';' at the end
@@ -1119,7 +1121,7 @@ static int cin_iswhileofdo_end(int terminated)
return FALSE;
}
-static int cin_isbreak(char_u *p)
+static int cin_isbreak(const char_u *p)
{
return STRNCMP(p, "break", 5) == 0 && !vim_isIDc(p[5]);
}
@@ -1139,10 +1141,10 @@ static int cin_isbreak(char_u *p)
*/
static int cin_is_cpp_baseclass(cpp_baseclass_cache_T *cached) {
lpos_T *pos = &cached->lpos; // find position
- char_u *s;
+ const char_u *s;
int class_or_struct, lookfor_ctor_init, cpp_base_class;
linenr_T lnum = curwin->w_cursor.lnum;
- char_u *line = get_cursor_line_ptr();
+ const char_u *line = get_cursor_line_ptr();
if (pos->lnum <= lnum) {
return cached->found; // Use the cached result
@@ -1310,10 +1312,10 @@ static int get_baseclass_amount(int col)
* 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)
+static int cin_ends_in(const char_u *s, const char_u *find, const char_u *ignore)
{
- char_u *p = s;
- char_u *r;
+ const char_u *p = s;
+ const char_u *r;
int len = (int)STRLEN(find);
while (*p != NUL) {
@@ -1334,7 +1336,7 @@ static int cin_ends_in(char_u *s, char_u *find, char_u *ignore)
/*
* Return TRUE when "s" starts with "word" and then a non-ID character.
*/
-static int cin_starts_with(char_u *s, char *word)
+static int cin_starts_with(const char_u *s, const char *word)
{
int l = (int)STRLEN(word);
@@ -1342,10 +1344,10 @@ static int cin_starts_with(char_u *s, char *word)
}
/// Recognize a `extern "C"` or `extern "C++"` linkage specifications.
-static int cin_is_cpp_extern_c(char_u *s)
+static int cin_is_cpp_extern_c(const char_u *s)
{
- char_u *p;
- int has_string_literal = false;
+ const char_u *p;
+ int has_string_literal = false;
s = cin_skipcomment(s);
if (STRNCMP(s, "extern", 6) == 0 && (s[6] == NUL || !vim_iswordc(s[6]))) {
@@ -1384,9 +1386,9 @@ static int cin_is_cpp_extern_c(char_u *s)
*/
static int cin_skip2pos(pos_T *trypos)
{
- char_u *line;
- char_u *p;
- char_u *new_p;
+ const char_u *line;
+ const char_u *p;
+ const char_u *new_p;
p = line = ml_get(trypos->lnum);
while (*p && (colnr_T)(p - line) < trypos->col) {
@@ -1529,7 +1531,7 @@ static int corr_ind_maxparen(pos_T *startpos)
* Set w_cursor.col to the column number of the last unmatched ')' or '{' in
* line "l". "l" must point to the start of the line.
*/
-static int find_last_paren(char_u *l, int start, int end)
+static int find_last_paren(const char_u *l, int start, int end)
{
int i;
int retval = FALSE;
@@ -1801,8 +1803,8 @@ int get_c_indent(void)
#define BRACE_AT_START 2 // '{' is at start of line
#define BRACE_AT_END 3 // '{' is at end of line
linenr_T ourscope;
- char_u *l;
- char_u *look;
+ const char_u *l;
+ const char_u *look;
char_u terminated;
int lookfor;
#define LOOKFOR_INITIAL 0
@@ -1906,12 +1908,25 @@ 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
- // find how indented the line beginning the comment is
- getvcol(curwin, trypos, &col, NULL, NULL);
- amount = col;
- goto theend;
+ 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
@@ -3602,9 +3617,9 @@ laterend:
static int find_match(int lookfor, linenr_T ourscope)
{
- char_u *look;
- pos_T *theirscope;
- char_u *mightbeif;
+ const char_u *look;
+ pos_T *theirscope;
+ const char_u *mightbeif;
int elselevel;
int whilelevel;
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index 28e5d47dbc..6e36226914 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -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;
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index 83a7c31991..11484eee57 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -4350,7 +4350,7 @@ void format_lines(linenr_T line_count, int avoid_fex)
int leader_len = 0; // leader len of current line
int next_leader_len; // leader len of next line
char_u *leader_flags = NULL; // flags for leader of current line
- char_u *next_leader_flags; // flags for leader of next line
+ char_u *next_leader_flags = NULL; // flags for leader of next line
bool advance = true;
int second_indent = -1; // indent for second line (comment aware)
bool first_par_line = true;
@@ -4467,7 +4467,14 @@ void format_lines(linenr_T line_count, int avoid_fex)
leader_len, leader_flags,
next_leader_len,
next_leader_flags)) {
- is_end_par = true;
+ // Special case: If the next line starts with a line comment
+ // and this line has a line comment after some text, the
+ // paragraph doesn't really end.
+ if (next_leader_flags == NULL
+ || STRNCMP(next_leader_flags, "://", 3) != 0
+ || check_linecomment(get_cursor_line_ptr()) == MAXCOL) {
+ is_end_par = true;
+ }
}
/*
diff --git a/src/nvim/search.c b/src/nvim/search.c
index 906c9a6f47..93180f97fe 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -26,6 +26,7 @@
#include "nvim/func_attr.h"
#include "nvim/getchar.h"
#include "nvim/indent.h"
+#include "nvim/indent_c.h"
#include "nvim/main.h"
#include "nvim/mark.h"
#include "nvim/mbyte.h"
@@ -2313,12 +2314,9 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
return (pos_T *)NULL; // never found it
}
-/*
- * Check if line[] contains a / / comment.
- * Return MAXCOL if not, otherwise return the column.
- * TODO: skip strings.
- */
-static int check_linecomment(const char_u *line)
+/// Check if line[] contains a / / comment.
+/// @returns MAXCOL if not, otherwise return the column.
+int check_linecomment(const char_u *line)
{
const char_u *p = line; // scan from start
// skip Lispish one-line comments
@@ -2338,7 +2336,8 @@ static int check_linecomment(const char_u *line)
in_str = true;
}
} else if (!in_str && ((p - line) < 2
- || (*(p - 1) != '\\' && *(p - 2) != '#'))) {
+ || (*(p - 1) != '\\' && *(p - 2) != '#'))
+ && !is_pos_in_string(line, (colnr_T)(p - line))) {
break; // found!
}
p++;
@@ -2348,9 +2347,11 @@ static int check_linecomment(const char_u *line)
}
} else {
while ((p = vim_strchr(p, '/')) != NULL) {
- // accept a double /, unless it's preceded with * and followed by *,
- // because * / / * is an end and start of a C comment
- if (p[1] == '/' && (p == line || p[-1] != '*' || p[2] != '*')) {
+ // Accept a double /, unless it's preceded with * and followed by *,
+ // because * / / * is an end and start of a C comment.
+ // Only accept the position if it is not inside a string.
+ if (p[1] == '/' && (p == line || p[-1] != '*' || p[2] != '*')
+ && !is_pos_in_string(line, (colnr_T)(p - line))) {
break;
}
++p;
diff --git a/src/nvim/testdir/test_cindent.vim b/src/nvim/testdir/test_cindent.vim
index 6554d034d3..5dc54111e7 100644
--- a/src/nvim/testdir/test_cindent.vim
+++ b/src/nvim/testdir/test_cindent.vim
@@ -1707,9 +1707,9 @@ func Test_cindent_1()
#endif
int y; // comment
- // comment
+ // comment
- // comment
+ // comment
{
Constructor(int a,
diff --git a/src/nvim/testdir/test_textformat.vim b/src/nvim/testdir/test_textformat.vim
index bf0706a0c2..052c32214d 100644
--- a/src/nvim/testdir/test_textformat.vim
+++ b/src/nvim/testdir/test_textformat.vim
@@ -196,6 +196,104 @@ 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, '$'))
+
+ %del
+ let text =<< trim END
+ #if 0 // This is another long end of
+ // line comment that
+ // wraps.
+ END
+ call setline(1, text)
+ normal gq2j
+ let expected =<< trim END
+ #if 0 // This is another long
+ // end of line comment
+ // that wraps.
+ END
+ call assert_equal(expected, getline(1, '$'))
+
+ " Using "o" repeats the line comment, "O" does not.
+ %del
+ let text =<< trim END
+ nop;
+ val = val; // This is a comment
+ END
+ call setline(1, text)
+ normal 2Go
+ let expected =<< trim END
+ nop;
+ val = val; // This is a comment
+ //
+ END
+ call assert_equal(expected, getline(1, '$'))
+ normal 2GO
+ let expected =<< trim END
+ nop;
+
+ val = val; // This is a comment
+ //
+ END
+ call assert_equal(expected, getline(1, '$'))
+
+ " Using "o" does not repeat a comment in a string
+ %del
+ let text =<< trim END
+ nop;
+ val = " // This is not a comment";
+ END
+ call setline(1, text)
+ normal 2Gox
+ let expected =<< trim END
+ nop;
+ val = " // This is not a comment";
+ x
+ END
+ call assert_equal(expected, getline(1, '$'))
+
+ " Using CTRL-U after "o" fixes the indent
+ %del
+ let text =<< trim END
+ {
+ val = val; // This is a comment
+ END
+ call setline(1, text)
+ exe "normal! 2Go\<C-U>x\<Esc>"
+ let expected =<< trim END
+ {
+ val = val; // This is a comment
+ x
+ 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!