To: vim_dev@googlegroups.com Subject: Patch 7.4.803 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 7.4.803 Problem: C indent does not support C11 raw strings. (Mark Lodato) Solution: Do not change indent inside the raw string. Files: src/search.c, src/misc1.c, src/edit.c, src/ops.c, src/testdir/test3.in, src/testdir/test3.ok *** ../vim-7.4.802/src/search.c 2015-07-21 17:53:11.585527913 +0200 --- src/search.c 2015-07-28 21:14:08.968071627 +0200 *************** *** 1725,1744 **** return (col >= 0 && linep[col] == ch) ? TRUE : FALSE; } /* * 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. * * "initc" is the character to find a match for. NUL means to find the ! * character at or after the cursor. * * 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 * NULL */ --- 1725,1795 ---- 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 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. 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 can be * NULL */ *************** *** 1754,1759 **** --- 1805,1811 ---- 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,1809 **** * When '/' is used, we ignore running backwards into an star-slash, for * "[*" command, we just want to find any comment. */ ! if (initc == '/' || initc == '*') { comment_dir = dir; if (initc == '/') ignore_cend = TRUE; backwards = (dir == FORWARD) ? FALSE : TRUE; initc = NUL; } else if (initc != '#' && initc != NUL) --- 1850,1862 ---- * When '/' is used, we ignore running backwards into an star-slash, for * "[*" command, we just want to find any comment. */ ! 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,1823 **** if (findc == NUL) return NULL; } - /* - * Either initc is '#', or no initc was given and we need to look under the - * cursor. - */ else { if (initc == '#') { hash_dir = dir; --- 1865,1876 ---- if (findc == NUL) return NULL; } else { + /* + * Either initc is '#', or no initc was given and we need to look + * under the cursor. + */ if (initc == '#') { hash_dir = dir; *************** *** 2135,2140 **** --- 2188,2213 ---- */ 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) *** ../vim-7.4.802/src/misc1.c 2015-07-21 17:53:11.581527951 +0200 --- src/misc1.c 2015-07-28 21:06:38.908518760 +0200 *************** *** 5267,5276 **** --- 5267,5279 ---- 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,5318 **** --- 5316,5380 ---- } /* + * 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,5360 **** break; } if (p[0] == '"') ! continue; } break; /* no string found */ } --- 5416,5443 ---- break; } if (p[0] == '"') ! 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,5605 **** --curwin->w_cursor.lnum; /* ! * If we're in a comment now, skip to the start of the comment. */ curwin->w_cursor.col = 0; ! if ((trypos = ind_find_start_comment()) != NULL) /* XXX */ curwin->w_cursor = *trypos; line = ml_get_curline(); --- 5679,5689 ---- --curwin->w_cursor.lnum; /* ! * 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_CORS()) != NULL) /* XXX */ curwin->w_cursor = *trypos; line = ml_get_curline(); *************** *** 6454,6460 **** continue; } ! if (s[0] == '"') s = skip_string(s) + 1; else if (s[0] == ':') { --- 6538,6544 ---- continue; } ! if (s[0] == '"' || (s[0] == 'R' && s[1] == '"')) s = skip_string(s) + 1; else if (s[0] == ':') { *************** *** 6660,6666 **** 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 */ break; if (pos != NULL) curwin->w_cursor.lnum = pos->lnum; --- 6744,6750 ---- pos = NULL; /* ignore the { if it's in a // or / * * / comment */ if ((colnr_T)cin_skip2pos(trypos) == trypos->col ! && (pos = ind_find_start_CORS()) == NULL) /* XXX */ break; if (pos != NULL) curwin->w_cursor.lnum = pos->lnum; *************** *** 6714,6720 **** 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 */ { ind_maxp_wk = ind_maxparen - (int)(cursor_save.lnum - trypos_wk->lnum); --- 6798,6804 ---- pos_copy = *trypos; /* copy trypos, findmatch will change it */ trypos = &pos_copy; curwin->w_cursor = *trypos; ! if ((trypos_wk = ind_find_start_CORS()) != NULL) /* XXX */ { ind_maxp_wk = ind_maxparen - (int)(cursor_save.lnum - trypos_wk->lnum); *************** *** 7029,7034 **** --- 7113,7122 ---- } } + /* + * 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,7047 **** char_u *theline; char_u *linecopy; pos_T *trypos; pos_T *tryposBrace = NULL; ! pos_T tryposBraceCopy; pos_T our_paren_pos; char_u *start; int start_brace; --- 7128,7136 ---- char_u *theline; char_u *linecopy; pos_T *trypos; + pos_T *comment_pos; pos_T *tryposBrace = NULL; ! pos_T tryposCopy; pos_T our_paren_pos; char_u *start; int start_brace; *************** *** 7085,7091 **** /* remember where the cursor was when we started */ cur_curpos = curwin->w_cursor; ! /* if we are at line 1 0 is fine, right? */ if (cur_curpos.lnum == 1) return 0; --- 7174,7180 ---- /* remember where the cursor was when we started */ cur_curpos = curwin->w_cursor; ! /* if we are at line 1 zero indent is fine, right? */ if (cur_curpos.lnum == 1) return 0; *************** *** 7117,7157 **** original_line_islabel = cin_islabel(); /* XXX */ /* * #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; /* * 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 && curbuf->b_ind_jump_label < 0) { amount = 0; } /* * If we're inside a "//" comment and there is a "//" comment in a * previous line, lineup with that one. */ ! else 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; } /* * 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 */ { int lead_start_len = 2; int lead_middle_len = 1; --- 7206,7267 ---- 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. */ ! 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. */ ! 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. */ ! if (!cin_iscomment(theline) && comment_pos != NULL) /* XXX */ { int lead_start_len = 2; int lead_middle_len = 1; *************** *** 7164,7170 **** int done = FALSE; /* find how indented the line beginning the comment is */ ! getvcol(curwin, trypos, &col, NULL, NULL); amount = col; *lead_start = NUL; *lead_middle = NUL; --- 7274,7280 ---- int done = FALSE; /* find how indented the line beginning the comment is */ ! getvcol(curwin, comment_pos, &col, NULL, NULL); amount = col; *lead_start = NUL; *lead_middle = NUL; *************** *** 7228,7234 **** } /* 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, lead_start, lead_start_len) != 0) continue; } --- 7338,7344 ---- } /* If the start comment string doesn't match with the * start of the comment, skip this entry. XXX */ ! else if (STRNCMP(ml_get(comment_pos->lnum) + comment_pos->col, lead_start, lead_start_len) != 0) continue; } *************** *** 7276,7282 **** * otherwise, add the amount specified by "c" in 'cino' */ amount = -1; ! for (lnum = cur_curpos.lnum - 1; lnum > trypos->lnum; --lnum) { if (linewhite(lnum)) /* skip blank lines */ continue; --- 7386,7392 ---- * otherwise, add the amount specified by "c" in 'cino' */ amount = -1; ! for (lnum = cur_curpos.lnum - 1; lnum > comment_pos->lnum; --lnum) { if (linewhite(lnum)) /* skip blank lines */ continue; *************** *** 7287,7319 **** { if (!curbuf->b_ind_in_comment2) { ! start = ml_get(trypos->lnum); ! look = start + trypos->col + 2; /* skip / and * */ if (*look != NUL) /* if something after it */ ! trypos->col = (colnr_T)(skipwhite(look) - start); } ! getvcol(curwin, trypos, &col, NULL, NULL); amount = col; if (curbuf->b_ind_in_comment2 || *look == NUL) amount += curbuf->b_ind_in_comment; } } } /* * Are we looking at a ']' that has a match? */ ! else if (*skipwhite(theline) == ']' && (trypos = find_match_char('[', curbuf->b_ind_maxparen)) != NULL) { /* align with the line containing the '['. */ amount = get_indent_lnum(trypos->lnum); } /* * Are we inside parentheses or braces? */ /* XXX */ ! else if (((trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL && curbuf->b_ind_java == 0) || (tryposBrace = find_start_brace()) != NULL || trypos != NULL) --- 7397,7431 ---- { if (!curbuf->b_ind_in_comment2) { ! start = ml_get(comment_pos->lnum); ! look = start + comment_pos->col + 2; /* skip / and * */ if (*look != NUL) /* if something after it */ ! comment_pos->col = (colnr_T)(skipwhite(look) - start); } ! 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? */ ! 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 */ ! if (((trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL && curbuf->b_ind_java == 0) || (tryposBrace = find_start_brace()) != NULL || trypos != NULL) *************** *** 7354,7361 **** continue; /* ignore #define, #if, etc. */ curwin->w_cursor.lnum = lnum; ! /* Skip a comment. XXX */ ! if ((trypos = ind_find_start_comment()) != NULL) { lnum = trypos->lnum + 1; continue; --- 7466,7473 ---- continue; /* ignore #define, #if, etc. */ curwin->w_cursor.lnum = lnum; ! /* Skip a comment or raw string. XXX */ ! if ((trypos = ind_find_start_CORS()) != NULL) { lnum = trypos->lnum + 1; continue; *************** *** 7583,7590 **** * Make a copy of tryposBrace, it may point to pos_copy inside * find_start_brace(), which may be changed somewhere. */ ! tryposBraceCopy = *tryposBrace; ! tryposBrace = &tryposBraceCopy; trypos = tryposBrace; ourscope = trypos->lnum; start = ml_get(ourscope); --- 7695,7702 ---- * Make a copy of tryposBrace, it may point to pos_copy inside * find_start_brace(), which may be changed somewhere. */ ! tryposCopy = *tryposBrace; ! tryposBrace = &tryposCopy; trypos = tryposBrace; ourscope = trypos->lnum; start = ml_get(ourscope); *************** *** 7791,7800 **** l = ml_get_curline(); /* ! * If we're in a comment now, skip to the start of the ! * comment. */ ! trypos = ind_find_start_comment(); if (trypos != NULL) { curwin->w_cursor.lnum = trypos->lnum + 1; --- 7903,7912 ---- l = ml_get_curline(); /* ! * 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; *************** *** 7911,7919 **** l = ml_get_curline(); ! /* If we're in a comment now, skip to the start of ! * the comment. */ ! trypos = ind_find_start_comment(); if (trypos != NULL) { curwin->w_cursor.lnum = trypos->lnum + 1; --- 8023,8031 ---- l = ml_get_curline(); ! /* 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,7949 **** } /* ! * 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; --- 8053,8062 ---- } /* ! * If we're in a comment or raw string now, skip to the start ! * of it. */ /* XXX */ ! if ((trypos = ind_find_start_CORS()) != NULL) { curwin->w_cursor.lnum = trypos->lnum + 1; curwin->w_cursor.col = 0; *************** *** 8729,9004 **** /* subtract extra left-shift for jump labels */ if (curbuf->b_ind_jump_label > 0 && original_line_islabel) amount -= curbuf->b_ind_jump_label; } ! 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] == '{') { ! amount = curbuf->b_ind_first_open; } /* ! * 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; } ! else { ! amount = 0; ! curwin->w_cursor = cur_curpos; ! ! /* search backwards until we find something we recognize */ ! while (curwin->w_cursor.lnum > 1) ! { ! curwin->w_cursor.lnum--; ! curwin->w_cursor.col = 0; ! l = ml_get_curline(); ! /* ! * 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; ! } ! /* ! * 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); break; ! } ! ! /* ! * Skip preprocessor directives and blank lines. ! */ ! if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum)) ! continue; ! ! if (cin_nocode(l)) ! 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; ! /* 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; ! } ! amount = get_indent(); /* XXX */ ! if (amount == 0) ! amount = cin_first_id_amount(); ! if (amount == 0) ! amount = ind_continuation; ! 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(); ! /* ! * Finding the closing '}' of a previous function. Put ! * current line at the left margin. For when 'cino' has "fs". ! */ ! if (*skipwhite(l) == '}') ! 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; ! /* ! * 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; ! } ! ! /* ! * 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; ! 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 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, '(', ')'); ! 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 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: /* put the cursor back where it belongs */ curwin->w_cursor = cur_curpos; vim_free(linecopy); - if (amount < 0) - return 0; return amount; } --- 8842,9118 ---- /* 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; } ! ! /* ! * 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] == '{') { ! 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; ! ! 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) { ! curwin->w_cursor.lnum = trypos->lnum + 1; ! curwin->w_cursor.col = 0; ! continue; } /* ! * 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); ! break; ! } ! /* ! * Skip preprocessor directives and blank lines. ! */ ! if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum)) ! continue; ! if (cin_nocode(l)) ! 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; ! /* 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; ! } ! amount = get_indent(); /* XXX */ ! if (amount == 0) ! amount = cin_first_id_amount(); ! if (amount == 0) ! amount = ind_continuation; ! 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(); ! /* ! * Finding the closing '}' of a previous function. Put ! * current line at the left margin. For when 'cino' has "fs". ! */ ! if (*skipwhite(l) == '}') ! 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; ! /* ! * 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; ! } ! /* ! * 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; ! 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 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, '(', ')'); ! 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 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); return amount; } *** ../vim-7.4.802/src/edit.c 2015-07-21 17:53:11.577527989 +0200 --- src/edit.c 2015-07-28 19:40:27.771945786 +0200 *************** *** 7813,7821 **** 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 */ } void --- 7813,7826 ---- fixthisline(get_the_indent) int (*get_the_indent) __ARGS((void)); { ! 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 *** ../vim-7.4.802/src/ops.c 2015-07-22 22:46:08.127010101 +0200 --- src/ops.c 2015-07-28 19:45:37.060848436 +0200 *************** *** 686,692 **** { long i; char_u *l; ! int count; linenr_T first_changed = 0; linenr_T last_changed = 0; linenr_T start_lnum = curwin->w_cursor.lnum; --- 686,692 ---- { long i; char_u *l; ! int amount; linenr_T first_changed = 0; linenr_T last_changed = 0; linenr_T start_lnum = curwin->w_cursor.lnum; *************** *** 719,729 **** { l = skipwhite(ml_get_curline()); if (*l == NUL) /* empty or blank line */ ! count = 0; else ! count = how(); /* get the indent for this line */ ! if (set_indent(count, SIN_UNDO)) { /* did change the indent, call changed_lines() later */ if (first_changed == 0) --- 719,729 ---- { l = skipwhite(ml_get_curline()); if (*l == NUL) /* empty or blank line */ ! amount = 0; else ! amount = how(); /* get the indent for this line */ ! if (amount >= 0 && set_indent(amount, SIN_UNDO)) { /* did change the indent, call changed_lines() later */ if (first_changed == 0) *** ../vim-7.4.802/src/testdir/test3.in 2015-03-20 19:06:01.982429823 +0100 --- src/testdir/test3.in 2015-07-28 20:03:32.290099553 +0200 *************** *** 891,896 **** --- 891,915 ---- 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 *** ../vim-7.4.802/src/testdir/test3.ok 2015-03-20 19:06:01.986429778 +0100 --- src/testdir/test3.ok 2015-07-28 20:03:59.985823030 +0200 *************** *** 879,884 **** --- 879,903 ---- 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 */ *** ../vim-7.4.802/src/version.c 2015-07-28 17:16:28.302488118 +0200 --- src/version.c 2015-07-28 21:07:42.219893314 +0200 *************** *** 743,744 **** --- 743,746 ---- { /* Add new patch number below this line */ + /**/ + 803, /**/ -- Facepalm statement #4: "3000 year old graves? That's not possible, it's only 2014!" /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///