summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <bram@vim.org>2015-07-28 21:17:36 +0200
committerBram Moolenaar <bram@vim.org>2015-07-28 21:17:36 +0200
commitf4103840ca6ab7ed3889626ed21a0a3f52302f40 (patch)
tree34b0ad14c7d386251622b0e2beeedfaad4140a28
parenta405a9d10712b0566eb52cb2384ee37b8a5040a7 (diff)
downloadvim-f4103840ca6ab7ed3889626ed21a0a3f52302f40.tar.gz
patch 7.4.803v7.4.803v7-4-803
Problem: C indent does not support C11 raw strings. (Mark Lodato) Solution: Do not change indent inside the raw string.
-rw-r--r--src/edit.c11
-rw-r--r--src/misc1.c644
-rw-r--r--src/ops.c8
-rw-r--r--src/search.c91
-rw-r--r--src/testdir/test3.in19
-rw-r--r--src/testdir/test3.ok19
-rw-r--r--src/version.c2
7 files changed, 513 insertions, 281 deletions
diff --git a/src/edit.c b/src/edit.c
index 5d3bd827..b48a2176 100644
--- a/src/edit.c
+++ b/src/edit.c
@@ -7813,9 +7813,14 @@ cindent_on()
fixthisline(get_the_indent)
int (*get_the_indent) __ARGS((void));
{
- change_indent(INDENT_SET, get_the_indent(), FALSE, 0, TRUE);
- if (linewhite(curwin->w_cursor.lnum))
- did_ai = TRUE; /* delete the indent if the line stays empty */
+ int amount = get_the_indent();
+
+ if (amount >= 0)
+ {
+ change_indent(INDENT_SET, amount, FALSE, 0, TRUE);
+ if (linewhite(curwin->w_cursor.lnum))
+ did_ai = TRUE; /* delete the indent if the line stays empty */
+ }
}
void
diff --git a/src/misc1.c b/src/misc1.c
index 3c68f8de..cb31e201 100644
--- a/src/misc1.c
+++ b/src/misc1.c
@@ -5267,10 +5267,13 @@ FullName_save(fname, force)
static char_u *skip_string __ARGS((char_u *p));
static pos_T *ind_find_start_comment __ARGS((void));
+static pos_T *ind_find_start_CORS __ARGS((void));
+static pos_T *find_start_rawstring __ARGS((int ind_maxcomment));
/*
* Find the start of a comment, not knowing if we are in a comment right now.
* Search starts at w_cursor.lnum and goes backwards.
+ * Return NULL when not inside a comment.
*/
static pos_T *
ind_find_start_comment() /* XXX */
@@ -5313,6 +5316,65 @@ find_start_comment(ind_maxcomment) /* XXX */
}
/*
+ * Find the start of a comment or raw string, not knowing if we are in a
+ * comment or raw string right now.
+ * Search starts at w_cursor.lnum and goes backwards.
+ * Return NULL when not inside a comment or raw string.
+ * "CORS" -> Comment Or Raw String
+ */
+ static pos_T *
+ind_find_start_CORS() /* XXX */
+{
+ pos_T *comment_pos = find_start_comment(curbuf->b_ind_maxcomment);
+ pos_T *rs_pos = find_start_rawstring(curbuf->b_ind_maxcomment);
+
+ /* If comment_pos is before rs_pos the raw string is inside the comment.
+ * If rs_pos is before comment_pos the comment is inside the raw string. */
+ if (comment_pos == NULL || (rs_pos != NULL && lt(*rs_pos, *comment_pos)))
+ return rs_pos;
+ return comment_pos;
+}
+
+/*
+ * Find the start of a raw string, not knowing if we are in one right now.
+ * Search starts at w_cursor.lnum and goes backwards.
+ * Return NULL when not inside a raw string.
+ */
+ static pos_T *
+find_start_rawstring(ind_maxcomment) /* XXX */
+ int ind_maxcomment;
+{
+ pos_T *pos;
+ char_u *line;
+ char_u *p;
+ int cur_maxcomment = ind_maxcomment;
+
+ for (;;)
+ {
+ pos = findmatchlimit(NULL, 'R', FM_BACKWARD, cur_maxcomment);
+ if (pos == NULL)
+ break;
+
+ /*
+ * 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;
+ cur_maxcomment = curwin->w_cursor.lnum - pos->lnum - 1;
+ if (cur_maxcomment <= 0)
+ {
+ pos = NULL;
+ break;
+ }
+ }
+ return pos;
+}
+
+/*
* Skip to the end of a "string" and a 'c' character.
* If there is no string or character, return argument unmodified.
*/
@@ -5354,7 +5416,28 @@ skip_string(p)
break;
}
if (p[0] == '"')
- continue;
+ 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)
+ {
+ size_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 */
}
@@ -5596,10 +5679,11 @@ cin_islabel() /* XXX */
--curwin->w_cursor.lnum;
/*
- * If we're in a comment now, skip to the start of the comment.
+ * If we're in a comment or raw string now, skip to the start of
+ * it.
*/
curwin->w_cursor.col = 0;
- if ((trypos = ind_find_start_comment()) != NULL) /* XXX */
+ if ((trypos = ind_find_start_CORS()) != NULL) /* XXX */
curwin->w_cursor = *trypos;
line = ml_get_curline();
@@ -6454,7 +6538,7 @@ cin_is_cpp_baseclass(cached)
continue;
}
- if (s[0] == '"')
+ if (s[0] == '"' || (s[0] == 'R' && s[1] == '"'))
s = skip_string(s) + 1;
else if (s[0] == ':')
{
@@ -6660,7 +6744,7 @@ find_start_brace() /* XXX */
pos = NULL;
/* ignore the { if it's in a // or / * * / comment */
if ((colnr_T)cin_skip2pos(trypos) == trypos->col
- && (pos = ind_find_start_comment()) == NULL) /* XXX */
+ && (pos = ind_find_start_CORS()) == NULL) /* XXX */
break;
if (pos != NULL)
curwin->w_cursor.lnum = pos->lnum;
@@ -6714,7 +6798,7 @@ retry:
pos_copy = *trypos; /* copy trypos, findmatch will change it */
trypos = &pos_copy;
curwin->w_cursor = *trypos;
- if ((trypos_wk = ind_find_start_comment()) != NULL) /* XXX */
+ if ((trypos_wk = ind_find_start_CORS()) != NULL) /* XXX */
{
ind_maxp_wk = ind_maxparen - (int)(cursor_save.lnum
- trypos_wk->lnum);
@@ -7029,6 +7113,10 @@ parse_cino(buf)
}
}
+/*
+ * Return the desired indent for C code.
+ * Return -1 if the indent should be left alone (inside a raw string).
+ */
int
get_c_indent()
{
@@ -7040,8 +7128,9 @@ get_c_indent()
char_u *theline;
char_u *linecopy;
pos_T *trypos;
+ pos_T *comment_pos;
pos_T *tryposBrace = NULL;
- pos_T tryposBraceCopy;
+ pos_T tryposCopy;
pos_T our_paren_pos;
char_u *start;
int start_brace;
@@ -7085,7 +7174,7 @@ get_c_indent()
/* remember where the cursor was when we started */
cur_curpos = curwin->w_cursor;
- /* if we are at line 1 0 is fine, right? */
+ /* if we are at line 1 zero indent is fine, right? */
if (cur_curpos.lnum == 1)
return 0;
@@ -7117,41 +7206,62 @@ get_c_indent()
original_line_islabel = cin_islabel(); /* XXX */
/*
+ * If we are inside a raw string don't change the indent.
+ * Ignore a raw string inside a comment.
+ */
+ comment_pos = ind_find_start_comment();
+ if (comment_pos != NULL)
+ {
+ /* findmatchlimit() static pos is overwritten, make a copy */
+ tryposCopy = *comment_pos;
+ comment_pos = &tryposCopy;
+ }
+ trypos = find_start_rawstring(curbuf->b_ind_maxcomment);
+ if (trypos != NULL && (comment_pos == NULL || lt(*trypos, *comment_pos)))
+ {
+ amount = -1;
+ goto laterend;
+ }
+
+ /*
* #defines and so on always go at the left when included in 'cinkeys'.
*/
if (*theline == '#' && (*linecopy == '#' || in_cinkeys('#', ' ', TRUE)))
+ {
amount = curbuf->b_ind_hash_comment;
+ goto theend;
+ }
/*
* Is it a non-case label? Then that goes at the left margin too unless:
* - JS flag is set.
* - 'L' item has a positive value.
*/
- else if (original_line_islabel && !curbuf->b_ind_js
+ if (original_line_islabel && !curbuf->b_ind_js
&& curbuf->b_ind_jump_label < 0)
{
amount = 0;
+ goto theend;
}
/*
* If we're inside a "//" comment and there is a "//" comment in a
* previous line, lineup with that one.
*/
- else if (cin_islinecomment(theline)
+ 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 we're inside a comment and not looking at the start of the
* comment, try using the 'comments' option.
*/
- else if (!cin_iscomment(theline)
- && (trypos = ind_find_start_comment()) != NULL)
- /* XXX */
+ if (!cin_iscomment(theline) && comment_pos != NULL) /* XXX */
{
int lead_start_len = 2;
int lead_middle_len = 1;
@@ -7164,7 +7274,7 @@ get_c_indent()
int done = FALSE;
/* find how indented the line beginning the comment is */
- getvcol(curwin, trypos, &col, NULL, NULL);
+ getvcol(curwin, comment_pos, &col, NULL, NULL);
amount = col;
*lead_start = NUL;
*lead_middle = NUL;
@@ -7228,7 +7338,7 @@ get_c_indent()
}
/* If the start comment string doesn't match with the
* start of the comment, skip this entry. XXX */
- else if (STRNCMP(ml_get(trypos->lnum) + trypos->col,
+ else if (STRNCMP(ml_get(comment_pos->lnum) + comment_pos->col,
lead_start, lead_start_len) != 0)
continue;
}
@@ -7276,7 +7386,7 @@ get_c_indent()
* otherwise, add the amount specified by "c" in 'cino'
*/
amount = -1;
- for (lnum = cur_curpos.lnum - 1; lnum > trypos->lnum; --lnum)
+ for (lnum = cur_curpos.lnum - 1; lnum > comment_pos->lnum; --lnum)
{
if (linewhite(lnum)) /* skip blank lines */
continue;
@@ -7287,33 +7397,35 @@ get_c_indent()
{
if (!curbuf->b_ind_in_comment2)
{
- start = ml_get(trypos->lnum);
- look = start + trypos->col + 2; /* skip / and * */
+ start = ml_get(comment_pos->lnum);
+ look = start + comment_pos->col + 2; /* skip / and * */
if (*look != NUL) /* if something after it */
- trypos->col = (colnr_T)(skipwhite(look) - start);
+ comment_pos->col = (colnr_T)(skipwhite(look) - start);
}
- getvcol(curwin, trypos, &col, NULL, NULL);
+ getvcol(curwin, comment_pos, &col, NULL, NULL);
amount = col;
if (curbuf->b_ind_in_comment2 || *look == NUL)
amount += curbuf->b_ind_in_comment;
}
}
+ goto theend;
}
/*
* Are we looking at a ']' that has a match?
*/
- else if (*skipwhite(theline) == ']'
+ if (*skipwhite(theline) == ']'
&& (trypos = find_match_char('[', curbuf->b_ind_maxparen)) != NULL)
{
/* align with the line containing the '['. */
amount = get_indent_lnum(trypos->lnum);
+ goto theend;
}
/*
* Are we inside parentheses or braces?
*/ /* XXX */
- else if (((trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL
+ if (((trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL
&& curbuf->b_ind_java == 0)
|| (tryposBrace = find_start_brace()) != NULL
|| trypos != NULL)
@@ -7354,8 +7466,8 @@ get_c_indent()
continue; /* ignore #define, #if, etc. */
curwin->w_cursor.lnum = lnum;
- /* Skip a comment. XXX */
- if ((trypos = ind_find_start_comment()) != NULL)
+ /* Skip a comment or raw string. XXX */
+ if ((trypos = ind_find_start_CORS()) != NULL)
{
lnum = trypos->lnum + 1;
continue;
@@ -7583,8 +7695,8 @@ get_c_indent()
* Make a copy of tryposBrace, it may point to pos_copy inside
* find_start_brace(), which may be changed somewhere.
*/
- tryposBraceCopy = *tryposBrace;
- tryposBrace = &tryposBraceCopy;
+ tryposCopy = *tryposBrace;
+ tryposBrace = &tryposCopy;
trypos = tryposBrace;
ourscope = trypos->lnum;
start = ml_get(ourscope);
@@ -7791,10 +7903,10 @@ get_c_indent()
l = ml_get_curline();
/*
- * If we're in a comment now, skip to the start of the
- * comment.
+ * If we're in a comment or raw string now, skip to
+ * the start of it.
*/
- trypos = ind_find_start_comment();
+ trypos = ind_find_start_CORS();
if (trypos != NULL)
{
curwin->w_cursor.lnum = trypos->lnum + 1;
@@ -7911,9 +8023,9 @@ get_c_indent()
l = ml_get_curline();
- /* If we're in a comment now, skip to the start of
- * the comment. */
- trypos = ind_find_start_comment();
+ /* If we're in a comment or raw string now, skip
+ * to the start of it. */
+ trypos = ind_find_start_CORS();
if (trypos != NULL)
{
curwin->w_cursor.lnum = trypos->lnum + 1;
@@ -7941,9 +8053,10 @@ get_c_indent()
}
/*
- * If we're in a comment now, skip to the start of the comment.
+ * If we're in a comment or raw string now, skip to the start
+ * of it.
*/ /* XXX */
- if ((trypos = ind_find_start_comment()) != NULL)
+ if ((trypos = ind_find_start_CORS()) != NULL)
{
curwin->w_cursor.lnum = trypos->lnum + 1;
curwin->w_cursor.col = 0;
@@ -8729,276 +8842,277 @@ term_again:
/* subtract extra left-shift for jump labels */
if (curbuf->b_ind_jump_label > 0 && original_line_islabel)
amount -= curbuf->b_ind_jump_label;
+
+ goto theend;
}
- else
+
+ /*
+ * ok -- we're not inside any sort of structure at all!
+ *
+ * This means we're at the top level, and everything should
+ * basically just match where the previous line is, except
+ * for the lines immediately following a function declaration,
+ * which are K&R-style parameters and need to be indented.
+ *
+ * if our line starts with an open brace, forget about any
+ * prevailing indent and make sure it looks like the start
+ * of a function
+ */
+
+ if (theline[0] == '{')
{
- /*
- * ok -- we're not inside any sort of structure at all!
- *
- * This means we're at the top level, and everything should
- * basically just match where the previous line is, except
- * for the lines immediately following a function declaration,
- * which are K&R-style parameters and need to be indented.
- *
- * if our line starts with an open brace, forget about any
- * prevailing indent and make sure it looks like the start
- * of a function
- */
+ amount = curbuf->b_ind_first_open;
+ goto theend;
+ }
+
+ /*
+ * If the NEXT line is a function declaration, the current
+ * line needs to be indented as a function type spec.
+ * Don't do this if the current line looks like a comment or if the
+ * current line is terminated, ie. ends in ';', or if the current line
+ * contains { or }: "void f() {\n if (1)"
+ */
+ if (cur_curpos.lnum < curbuf->b_ml.ml_line_count
+ && !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_isfuncdecl(NULL, cur_curpos.lnum + 1,
+ cur_curpos.lnum + 1)
+ && !cin_isterminated(theline, FALSE, TRUE))
+ {
+ amount = curbuf->b_ind_func_type;
+ goto theend;
+ }
+
+ /* search backwards until we find something we recognize */
+ amount = 0;
+ curwin->w_cursor = cur_curpos;
+ while (curwin->w_cursor.lnum > 1)
+ {
+ curwin->w_cursor.lnum--;
+ curwin->w_cursor.col = 0;
- if (theline[0] == '{')
+ l = ml_get_curline();
+
+ /*
+ * If we're in a comment or raw string now, skip to the start
+ * of it.
+ */ /* XXX */
+ if ((trypos = ind_find_start_CORS()) != NULL)
{
- amount = curbuf->b_ind_first_open;
+ curwin->w_cursor.lnum = trypos->lnum + 1;
+ curwin->w_cursor.col = 0;
+ continue;
}
/*
- * If the NEXT line is a function declaration, the current
- * line needs to be indented as a function type spec.
- * Don't do this if the current line looks like a comment or if the
- * current line is terminated, ie. ends in ';', or if the current line
- * contains { or }: "void f() {\n if (1)"
- */
- else if (cur_curpos.lnum < curbuf->b_ml.ml_line_count
- && !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_isfuncdecl(NULL, cur_curpos.lnum + 1,
- cur_curpos.lnum + 1)
- && !cin_isterminated(theline, FALSE, TRUE))
- {
- amount = curbuf->b_ind_func_type;
+ * Are we at the start of a cpp base class declaration or
+ * constructor initialization?
+ */ /* XXX */
+ n = FALSE;
+ if (curbuf->b_ind_cpp_baseclass != 0 && theline[0] != '{')
+ {
+ n = cin_is_cpp_baseclass(&cache_cpp_baseclass);
+ l = ml_get_curline();
}
- else
+ if (n)
{
- amount = 0;
- curwin->w_cursor = cur_curpos;
-
- /* search backwards until we find something we recognize */
+ /* XXX */
+ amount = get_baseclass_amount(cache_cpp_baseclass.lpos.col);
+ break;
+ }
- while (curwin->w_cursor.lnum > 1)
- {
- curwin->w_cursor.lnum--;
- curwin->w_cursor.col = 0;
+ /*
+ * Skip preprocessor directives and blank lines.
+ */
+ if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum))
+ continue;
- l = ml_get_curline();
+ if (cin_nocode(l))
+ continue;
- /*
- * If we're in a comment now, skip to the start of the comment.
- */ /* XXX */
- if ((trypos = ind_find_start_comment()) != NULL)
- {
- curwin->w_cursor.lnum = trypos->lnum + 1;
- curwin->w_cursor.col = 0;
- continue;
- }
+ /*
+ * If the previous line ends in ',', use one level of
+ * indentation:
+ * int foo,
+ * bar;
+ * do this before checking for '}' in case of eg.
+ * enum foobar
+ * {
+ * ...
+ * } foo,
+ * bar;
+ */
+ n = 0;
+ if (cin_ends_in(l, (char_u *)",", NULL)
+ || (*l != NUL && (n = l[STRLEN(l) - 1]) == '\\'))
+ {
+ /* take us back to opening paren */
+ if (find_last_paren(l, '(', ')')
+ && (trypos = find_match_paren(
+ curbuf->b_ind_maxparen)) != NULL)
+ curwin->w_cursor = *trypos;
- /*
- * Are we at the start of a cpp base class declaration or
- * constructor initialization?
- */ /* XXX */
- n = FALSE;
- if (curbuf->b_ind_cpp_baseclass != 0 && theline[0] != '{')
- {
- n = cin_is_cpp_baseclass(&cache_cpp_baseclass);
- l = ml_get_curline();
- }
- if (n)
- {
- /* XXX */
- amount = get_baseclass_amount(cache_cpp_baseclass.lpos.col);
+ /* For a line ending in ',' that is a continuation line go
+ * back to the first line with a backslash:
+ * char *foo = "bla\
+ * bla",
+ * here;
+ */
+ while (n == 0 && curwin->w_cursor.lnum > 1)
+ {
+ l = ml_get(curwin->w_cursor.lnum - 1);
+ if (*l == NUL || l[STRLEN(l) - 1] != '\\')
break;
- }
-
- /*
- * Skip preprocessor directives and blank lines.
- */
- if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum))
- continue;
-
- if (cin_nocode(l))
- continue;
+ --curwin->w_cursor.lnum;
+ curwin->w_cursor.col = 0;
+ }
- /*
- * If the previous line ends in ',', use one level of
- * indentation:
- * int foo,
- * bar;
- * do this before checking for '}' in case of eg.
- * enum foobar
- * {
- * ...
- * } foo,
- * bar;
- */
- n = 0;
- if (cin_ends_in(l, (char_u *)",", NULL)
- || (*l != NUL && (n = l[STRLEN(l) - 1]) == '\\'))
- {
- /* take us back to opening paren */
- if (find_last_paren(l, '(', ')')
- && (trypos = find_match_paren(
- curbuf->b_ind_maxparen)) != NULL)
- curwin->w_cursor = *trypos;
+ amount = get_indent(); /* XXX */
- /* For a line ending in ',' that is a continuation line go
- * back to the first line with a backslash:
- * char *foo = "bla\
- * bla",
- * here;
- */
- while (n == 0 && curwin->w_cursor.lnum > 1)
- {
- l = ml_get(curwin->w_cursor.lnum - 1);
- if (*l == NUL || l[STRLEN(l) - 1] != '\\')
- break;
- --curwin->w_cursor.lnum;
- curwin->w_cursor.col = 0;
- }
+ if (amount == 0)
+ amount = cin_first_id_amount();
+ if (amount == 0)
+ amount = ind_continuation;
+ break;
+ }
- amount = get_indent(); /* XXX */
+ /*
+ * If the line looks like a function declaration, and we're
+ * not in a comment, put it the left margin.
+ */
+ if (cin_isfuncdecl(NULL, cur_curpos.lnum, 0)) /* XXX */
+ break;
+ l = ml_get_curline();
- if (amount == 0)
- amount = cin_first_id_amount();
- if (amount == 0)
- amount = ind_continuation;
- break;
- }
+ /*
+ * Finding the closing '}' of a previous function. Put
+ * current line at the left margin. For when 'cino' has "fs".
+ */
+ if (*skipwhite(l) == '}')
+ break;
- /*
- * If the line looks like a function declaration, and we're
- * not in a comment, put it the left margin.
- */
- if (cin_isfuncdecl(NULL, cur_curpos.lnum, 0)) /* XXX */
- break;
- l = ml_get_curline();
+ /* (matching {)
+ * If the previous line ends on '};' (maybe followed by
+ * comments) align at column 0. For example:
+ * char *string_array[] = { "foo",
+ * / * x * / "b};ar" }; / * foobar * /
+ */
+ if (cin_ends_in(l, (char_u *)"};", NULL))
+ break;
- /*
- * Finding the closing '}' of a previous function. Put
- * current line at the left margin. For when 'cino' has "fs".
- */
- if (*skipwhite(l) == '}')
- 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))
+ {
+ amount = get_indent() + ind_continuation;
+ break;
+ }
- /* (matching {)
- * If the previous line ends on '};' (maybe followed by
- * comments) align at column 0. For example:
- * char *string_array[] = { "foo",
- * / * x * / "b};ar" }; / * foobar * /
- */
- if (cin_ends_in(l, (char_u *)"};", NULL))
- break;
+ /*
+ * Find a line only has a semicolon that belongs to a previous
+ * line ending in '}', e.g. before an #endif. Don't increase
+ * indent then.
+ */
+ if (*(look = skipwhite(l)) == ';' && cin_nocode(look + 1))
+ {
+ pos_T curpos_save = curwin->w_cursor;
- /*
- * 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))
- {
- amount = get_indent() + ind_continuation;
+ while (curwin->w_cursor.lnum > 1)
+ {
+ look = ml_get(--curwin->w_cursor.lnum);
+ if (!(cin_nocode(look) || cin_ispreproc_cont(
+ &look, &curwin->w_cursor.lnum)))
break;
- }
-
- /*
- * Find a line only has a semicolon that belongs to a previous
- * line ending in '}', e.g. before an #endif. Don't increase
- * indent then.
- */
- if (*(look = skipwhite(l)) == ';' && cin_nocode(look + 1))
- {
- pos_T curpos_save = curwin->w_cursor;
-
- while (curwin->w_cursor.lnum > 1)
- {
- look = ml_get(--curwin->w_cursor.lnum);
- if (!(cin_nocode(look) || cin_ispreproc_cont(
- &look, &curwin->w_cursor.lnum)))
- break;
- }
- if (curwin->w_cursor.lnum > 0
- && cin_ends_in(look, (char_u *)"}", NULL))
- break;
+ }
+ if (curwin->w_cursor.lnum > 0
+ && cin_ends_in(look, (char_u *)"}", NULL))
+ break;
- curwin->w_cursor = curpos_save;
- }
+ curwin->w_cursor = curpos_save;
+ }
- /*
- * If the PREVIOUS line is a function declaration, the current
- * line (and the ones that follow) needs to be indented as
- * parameters.
- */
- if (cin_isfuncdecl(&l, curwin->w_cursor.lnum, 0))
- {
- amount = curbuf->b_ind_param;
- break;
- }
+ /*
+ * If the PREVIOUS line is a function declaration, the current
+ * line (and the ones that follow) needs to be indented as
+ * parameters.
+ */
+ if (cin_isfuncdecl(&l, curwin->w_cursor.lnum, 0))
+ {
+ amount = curbuf->b_ind_param;
+ break;
+ }
- /*
- * If the previous line ends in ';' and the line before the
- * previous line ends in ',' or '\', ident to column zero:
- * int foo,
- * bar;
- * indent_to_0 here;
- */
- if (cin_ends_in(l, (char_u *)";", NULL))
- {
- l = ml_get(curwin->w_cursor.lnum - 1);
- if (cin_ends_in(l, (char_u *)",", NULL)
- || (*l != NUL && l[STRLEN(l) - 1] == '\\'))
- break;
- l = ml_get_curline();
- }
+ /*
+ * If the previous line ends in ';' and the line before the
+ * previous line ends in ',' or '\', ident to column zero:
+ * int foo,
+ * bar;
+ * indent_to_0 here;
+ */
+ if (cin_ends_in(l, (char_u *)";", NULL))
+ {
+ l = ml_get(curwin->w_cursor.lnum - 1);
+ if (cin_ends_in(l, (char_u *)",", NULL)
+ || (*l != NUL && l[STRLEN(l) - 1] == '\\'))
+ break;
+ l = ml_get_curline();
+ }
- /*
- * Doesn't look like anything interesting -- so just
- * use the indent of this line.
- *
- * Position the cursor over the rightmost paren, so that
- * matching it will take us back to the start of the line.
- */
- find_last_paren(l, '(', ')');
+ /*
+ * Doesn't look like anything interesting -- so just
+ * use the indent of this line.
+ *
+ * Position the cursor over the rightmost paren, so that
+ * matching it will take us back to the start of the line.
+ */
+ find_last_paren(l, '(', ')');
- if ((trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL)
- curwin->w_cursor = *trypos;
- amount = get_indent(); /* XXX */
- break;
- }
+ if ((trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL)
+ curwin->w_cursor = *trypos;
+ amount = get_indent(); /* XXX */
+ break;
+ }
- /* add extra indent for a comment */
- if (cin_iscomment(theline))
- amount += curbuf->b_ind_comment;
+ /* add extra indent for a comment */
+ if (cin_iscomment(theline))
+ amount += curbuf->b_ind_comment;
- /* add extra indent if the previous line ended in a backslash:
- * "asdfasdf\
- * here";
- * char *foo = "asdf\
- * here";
- */
- if (cur_curpos.lnum > 1)
- {
- l = ml_get(cur_curpos.lnum - 1);
- if (*l != NUL && l[STRLEN(l) - 1] == '\\')
- {
- cur_amount = cin_get_equal_amount(cur_curpos.lnum - 1);
- if (cur_amount > 0)
- amount = cur_amount;
- else if (cur_amount == 0)
- amount += ind_continuation;
- }
- }
+ /* add extra indent if the previous line ended in a backslash:
+ * "asdfasdf\
+ * here";
+ * char *foo = "asdf\
+ * here";
+ */
+ if (cur_curpos.lnum > 1)
+ {
+ l = ml_get(cur_curpos.lnum - 1);
+ if (*l != NUL && l[STRLEN(l) - 1] == '\\')
+ {
+ cur_amount = cin_get_equal_amount(cur_curpos.lnum - 1);
+ if (cur_amount > 0)
+ amount = cur_amount;
+ else if (cur_amount == 0)
+ amount += ind_continuation;
}
}
theend:
+ if (amount < 0)
+ amount = 0;
+
+laterend:
/* put the cursor back where it belongs */
curwin->w_cursor = cur_curpos;
vim_free(linecopy);
- if (amount < 0)
- return 0;
return amount;
}
diff --git a/src/ops.c b/src/ops.c
index a9eec34d..ff722589 100644
--- a/src/ops.c
+++ b/src/ops.c
@@ -686,7 +686,7 @@ op_reindent(oap, how)
{
long i;
char_u *l;
- int count;
+ int amount;
linenr_T first_changed = 0;
linenr_T last_changed = 0;
linenr_T start_lnum = curwin->w_cursor.lnum;
@@ -719,11 +719,11 @@ op_reindent(oap, how)
{
l = skipwhite(ml_get_curline());
if (*l == NUL) /* empty or blank line */
- count = 0;
+ amount = 0;
else
- count = how(); /* get the indent for this line */
+ amount = how(); /* get the indent for this line */
- if (set_indent(count, SIN_UNDO))
+ if (amount >= 0 && set_indent(amount, SIN_UNDO))
{
/* did change the indent, call changed_lines() later */
if (first_changed == 0)
diff --git a/src/search.c b/src/search.c
index 4905a49d..238fc816 100644
--- a/src/search.c
+++ b/src/search.c
@@ -1725,20 +1725,71 @@ check_prevcol(linep, col, ch, prevcol)
return (col >= 0 && linep[col] == ch) ? TRUE : FALSE;
}
+static int find_rawstring_end __ARGS((char_u *linep, pos_T *startpos, pos_T *endpos));
+
+/*
+ * Raw string start is found at linep[startpos.col - 1].
+ * Return TRUE if the matching end can be found between startpos and endpos.
+ */
+ static int
+find_rawstring_end(linep, startpos, endpos)
+ char_u *linep;
+ pos_T *startpos;
+ pos_T *endpos;
+{
+ char_u *p;
+ char_u *delim_copy;
+ size_t delim_len;
+ linenr_T lnum;
+ int found = FALSE;
+
+ for (p = linep + startpos->col + 1; *p && *p != '('; ++p)
+ ;
+ delim_len = (p - linep) - startpos->col - 1;
+ delim_copy = vim_strnsave(linep + startpos->col + 1, delim_len);
+ if (delim_copy == NULL)
+ return FALSE;
+ for (lnum = startpos->lnum; lnum <= endpos->lnum; ++lnum)
+ {
+ char_u *line = ml_get(lnum);
+
+ for (p = line + (lnum == startpos->lnum
+ ? startpos->col + 1 : 0); *p; ++p)
+ {
+ if (lnum == endpos->lnum && (colnr_T)(p - line) >= endpos->col)
+ break;
+ if (*p == ')' && p[delim_len + 1] == '"'
+ && STRNCMP(delim_copy, p + 1, delim_len) == 0)
+ {
+ found = TRUE;
+ break;
+ }
+ }
+ if (found)
+ break;
+ }
+ vim_free(delim_copy);
+ return found;
+}
+
/*
* findmatchlimit -- find the matching paren or brace, if it exists within
- * maxtravel lines of here. A maxtravel of 0 means search until falling off
- * the edge of the file.
+ * maxtravel lines of the cursor. A maxtravel of 0 means search until falling
+ * off the edge of the file.
*
* "initc" is the character to find a match for. NUL means to find the
- * character at or after the cursor.
+ * character at or after the cursor. Special values:
+ * '*' look for C-style comment / *
+ * '/' look for C-style comment / *, ignoring comment-end
+ * '#' look for preprocessor directives
+ * 'R' look for raw string start: R"delim(text)delim" (only backwards)
*
* flags: FM_BACKWARD search backwards (when initc is '/', '*' or '#')
* FM_FORWARD search forwards (when initc is '/', '*' or '#')
* FM_BLOCKSTOP stop at start/end of block ({ or } in column 0)
* FM_SKIPCOMM skip comments (not implemented yet!)
*
- * "oap" is only used to set oap->motion_type for a linewise motion, it be
+ * "oap" is only used to set oap->motion_type for a linewise motion, it can be
* NULL
*/
@@ -1754,6 +1805,7 @@ findmatchlimit(oap, initc, flags, maxtravel)
int c;
int count = 0; /* cumulative number of braces */
int backwards = FALSE; /* init for gcc */
+ int raw_string = FALSE; /* search for raw string */
int inquote = FALSE; /* TRUE when inside quotes */
char_u *linep; /* pointer to current line */
char_u *ptr;
@@ -1798,12 +1850,13 @@ findmatchlimit(oap, initc, flags, maxtravel)
* When '/' is used, we ignore running backwards into an star-slash, for
* "[*" command, we just want to find any comment.
*/
- if (initc == '/' || initc == '*')
+ if (initc == '/' || initc == '*' || initc == 'R')
{
comment_dir = dir;
if (initc == '/')
ignore_cend = TRUE;
backwards = (dir == FORWARD) ? FALSE : TRUE;
+ raw_string = (initc == 'R');
initc = NUL;
}
else if (initc != '#' && initc != NUL)
@@ -1812,12 +1865,12 @@ findmatchlimit(oap, initc, flags, maxtravel)
if (findc == NUL)
return NULL;
}
- /*
- * Either initc is '#', or no initc was given and we need to look under the
- * cursor.
- */
else
{
+ /*
+ * Either initc is '#', or no initc was given and we need to look
+ * under the cursor.
+ */
if (initc == '#')
{
hash_dir = dir;
@@ -2135,6 +2188,26 @@ findmatchlimit(oap, initc, flags, maxtravel)
*/
if (pos.col == 0)
continue;
+ else if (raw_string)
+ {
+ if (linep[pos.col - 1] == 'R'
+ && linep[pos.col] == '"'
+ && vim_strchr(linep + pos.col + 1, '(') != NULL)
+ {
+ /* Possible start of raw string. Now that we have the
+ * delimiter we can check if it ends before where we
+ * started searching, or before the previously found
+ * raw string start. */
+ if (!find_rawstring_end(linep, &pos,
+ count > 0 ? &match_pos : &curwin->w_cursor))
+ {
+ count++;
+ match_pos = pos;
+ match_pos.col--;
+ }
+ linep = ml_get(pos.lnum); /* may have been released */
+ }
+ }
else if ( linep[pos.col - 1] == '/'
&& linep[pos.col] == '*'
&& (int)pos.col < comment_col)
diff --git a/src/testdir/test3.in b/src/testdir/test3.in
index a321bb88..4f5331e5 100644
--- a/src/testdir/test3.in
+++ b/src/testdir/test3.in
@@ -891,6 +891,25 @@ namespace111111111
111111111111111111;
}
+void getstring() {
+/* Raw strings */
+const char* s = R"(
+ test {
+ # comment
+ field: 123
+ }
+ )";
+ }
+
+void getstring() {
+const char* s = R"foo(
+ test {
+ # comment
+ field: 123
+ }
+ )foo";
+ }
+
/* end of AUTO */
STARTTEST
diff --git a/src/testdir/test3.ok b/src/testdir/test3.ok
index b1c8b708..e87e7fdc 100644
--- a/src/testdir/test3.ok
+++ b/src/testdir/test3.ok
@@ -879,6 +879,25 @@ namespace111111111
111111111111111111;
}
+void getstring() {
+ /* Raw strings */
+ const char* s = R"(
+ test {
+ # comment
+ field: 123
+ }
+ )";
+}
+
+void getstring() {
+ const char* s = R"foo(
+ test {
+ # comment
+ field: 123
+ }
+ )foo";
+}
+
/* end of AUTO */
diff --git a/src/version.c b/src/version.c
index 7de9d82e..13dab4d4 100644
--- a/src/version.c
+++ b/src/version.c
@@ -742,6 +742,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 803,
+/**/
802,
/**/
801,