vim-patch:7.4.803

Problem:    C indent does not support C11 raw strings. (Mark Lodato)
Solution:   Do not change indent inside the raw string.

f7bb86dc59
This commit is contained in:
Johan Klokkhammer Helsing 2015-11-03 22:04:15 +01:00
parent b079622716
commit 3b472e55b3
6 changed files with 500 additions and 280 deletions

View File

@ -6584,9 +6584,14 @@ static int cindent_on(void) {
*/
void fixthisline(IndentGetter get_the_indent)
{
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 fix_indent(void) {

View File

@ -29,6 +29,7 @@ typedef struct {
/*
* 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(void)
{ /* XXX */
@ -68,6 +69,62 @@ find_start_comment ( /* XXX */
return pos;
}
/*
* 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(void)
{ /* 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(int ind_maxcomment)
{ /* XXX */
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.
@ -101,7 +158,28 @@ static char_u *skip_string(char_u *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 */
}
@ -292,10 +370,11 @@ int cin_islabel(void)
--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 = get_cursor_line_ptr();
@ -1057,7 +1136,7 @@ static int cin_is_cpp_baseclass(cpp_baseclass_cache_T *cached) {
continue;
}
if (s[0] == '"')
if (s[0] == '"' || (s[0] == 'R' && s[1] == '"'))
s = skip_string(s) + 1;
else if (s[0] == ':') {
if (s[1] == ':') {
@ -1228,7 +1307,7 @@ static pos_T *find_start_brace(void)
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;
@ -1270,7 +1349,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);
if (ind_maxp_wk > 0) {
@ -1562,6 +1641,10 @@ void parse_cino(buf_T *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(void)
{
pos_T cur_curpos;
@ -1572,8 +1655,9 @@ int get_c_indent(void)
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;
@ -1616,7 +1700,7 @@ int get_c_indent(void)
/* 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;
@ -1645,38 +1729,56 @@ int get_c_indent(void)
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)))
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;
char_u lead_start[COM_MAX_LEN]; /* start-comment string */
@ -1688,7 +1790,7 @@ int get_c_indent(void)
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;
@ -1743,7 +1845,7 @@ int get_c_indent(void)
}
/* 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;
}
@ -1789,7 +1891,7 @@ int get_c_indent(void)
* 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;
amount = get_indent_lnum(lnum); /* XXX */
@ -1797,28 +1899,30 @@ int get_c_indent(void)
}
if (amount == -1) { /* use the comment opener */
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) {
@ -1852,8 +1956,8 @@ int get_c_indent(void)
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;
}
@ -2054,8 +2158,8 @@ int get_c_indent(void)
// stored in tryposBrace.
// 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);
@ -2232,10 +2336,10 @@ int get_c_indent(void)
l = get_cursor_line_ptr();
/*
* 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;
curwin->w_cursor.col = 0;
@ -2341,9 +2445,9 @@ int get_c_indent(void)
l = get_cursor_line_ptr();
/* 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;
curwin->w_cursor.col = 0;
@ -2369,9 +2473,10 @@ int get_c_indent(void)
}
/*
* 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;
continue;
@ -3086,8 +3191,10 @@ 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
@ -3098,8 +3205,10 @@ term_again:
// 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] == '{') {
amount = curbuf->b_ind_first_open;
goto theend;
}
/*
* If the NEXT line is a function declaration, the current
@ -3108,7 +3217,7 @@ term_again:
* 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
if (cur_curpos.lnum < curbuf->b_ml.ml_line_count
&& !cin_nocode(theline)
&& vim_strchr(theline, '{') == NULL
&& vim_strchr(theline, '}') == NULL
@ -3118,12 +3227,12 @@ term_again:
cur_curpos.lnum + 1)
&& !cin_isterminated(theline, FALSE, TRUE)) {
amount = curbuf->b_ind_func_type;
} else {
amount = 0;
curwin->w_cursor = cur_curpos;
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;
@ -3131,9 +3240,10 @@ term_again:
l = get_cursor_line_ptr();
/*
* 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;
continue;
@ -3321,17 +3431,17 @@ term_again:
amount += ind_continuation;
}
}
}
}
theend:
if (amount < 0)
amount = 0;
laterend:
/* put the cursor back where it belongs */
curwin->w_cursor = cur_curpos;
xfree(linecopy);
if (amount < 0)
return 0;
return amount;
}

View File

@ -554,7 +554,7 @@ void op_reindent(oparg_T *oap, Indenter 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;
@ -582,11 +582,11 @@ void op_reindent(oparg_T *oap, Indenter how)
|| how != get_lisp_indent) {
l = skipwhite(get_cursor_line_ptr());
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)
first_changed = curwin->w_cursor.lnum;

View File

@ -1442,20 +1442,69 @@ static int check_prevcol(char_u *linep, int col, int ch, int *prevcol)
return (col >= 0 && linep[col] == ch) ? TRUE : FALSE;
}
/*
* 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;
}
xfree(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
*/
@ -1466,6 +1515,7 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t 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;
@ -1506,22 +1556,23 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel)
* When '/' is used, we ignore running backwards into a 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) {
find_mps_values(&initc, &findc, &backwards, TRUE);
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;
} else {
@ -1766,6 +1817,26 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t 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) {

View File

@ -190,7 +190,7 @@ static int included_patches[] = {
// 806,
// 805,
// 804,
// 803,
803,
802,
// 801,
// 800,

View File

@ -901,6 +901,23 @@ describe('cindent', function()
{
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 */
]=])
@ -1790,6 +1807,23 @@ describe('cindent', function()
{
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 */
]=])
@ -4214,7 +4248,7 @@ describe('cindent', function()
]=])
end)
it('54 is working', function()
it('javascript indent / vim-patch 7.4.670', function()
insert_([=[
JSSTART