summaryrefslogtreecommitdiffstats
path: root/src/misc1.c
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2019-01-31 13:48:09 +0100
committerBram Moolenaar <Bram@vim.org>2019-01-31 13:48:09 +0100
commit4b47162ccede0b6d9cbb9473ad870220a24fbf54 (patch)
treece99699b4391edf919bc8a849653516f231d3ef7 /src/misc1.c
parentbbb5f8d4c2cbc5f48556008875f57cbe7fc4ac6c (diff)
patch 8.1.0857: indent functionality is not separatedv8.1.0857
Problem: Ignore functionality is not separated. Solution: Move indent functionality into a new file. (Yegappan Lakshmanan, closes #3886)
Diffstat (limited to 'src/misc1.c')
-rw-r--r--src/misc1.c4346
1 files changed, 0 insertions, 4346 deletions
diff --git a/src/misc1.c b/src/misc1.c
index 1db7496c07..26b570bcb0 100644
--- a/src/misc1.c
+++ b/src/misc1.c
@@ -702,41 +702,6 @@ get_breakindent_win(
#endif
-#if defined(FEAT_CINDENT) || defined(FEAT_SMARTINDENT)
-
-/*
- * Return TRUE if the string "line" starts with a word from 'cinwords'.
- */
- static int
-cin_is_cinword(char_u *line)
-{
- char_u *cinw;
- char_u *cinw_buf;
- int cinw_len;
- int retval = FALSE;
- int len;
-
- cinw_len = (int)STRLEN(curbuf->b_p_cinw) + 1;
- cinw_buf = alloc((unsigned)cinw_len);
- if (cinw_buf != NULL)
- {
- line = skipwhite(line);
- for (cinw = curbuf->b_p_cinw; *cinw; )
- {
- len = copy_option_part(&cinw, cinw_buf, cinw_len, ",");
- if (STRNCMP(line, cinw_buf, len) == 0
- && (!vim_iswordc(line[len]) || !vim_iswordc(line[len - 1])))
- {
- retval = TRUE;
- break;
- }
- }
- vim_free(cinw_buf);
- }
- return retval;
-}
-#endif
-
/*
* open_line: Add a new line below or above the current line.
*
@@ -5404,4317 +5369,6 @@ FullName_save(
return new_fname;
}
-#if defined(FEAT_CINDENT) || defined(FEAT_SYN_HL)
-
-static char_u *skip_string(char_u *p);
-static pos_T *find_start_rawstring(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(void) /* XXX */
-{
- return find_start_comment(curbuf->b_ind_maxcomment);
-}
-
- pos_T *
-find_start_comment(int ind_maxcomment) /* XXX */
-{
- pos_T *pos;
- char_u *line;
- char_u *p;
- int cur_maxcomment = ind_maxcomment;
-
- for (;;)
- {
- pos = findmatchlimit(NULL, '*', FM_BACKWARD, cur_maxcomment);
- if (pos == NULL)
- break;
-
- /*
- * 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)
- break;
- cur_maxcomment = curwin->w_cursor.lnum - pos->lnum - 1;
- if (cur_maxcomment <= 0)
- {
- pos = NULL;
- break;
- }
- }
- 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.
- * If is_raw is given and returns start of raw_string, sets it to true.
- * Return NULL when not inside a comment or raw string.
- * "CORS" -> Comment Or Raw String
- */
- static pos_T *
-ind_find_start_CORS(linenr_T *is_raw) /* XXX */
-{
- static pos_T comment_pos_copy;
- pos_T *comment_pos;
- pos_T *rs_pos;
-
- comment_pos = find_start_comment(curbuf->b_ind_maxcomment);
- if (comment_pos != NULL)
- {
- /* Need to make a copy of the static pos in findmatchlimit(),
- * calling find_start_rawstring() may change it. */
- comment_pos_copy = *comment_pos;
- comment_pos = &comment_pos_copy;
- }
- 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_POS(*rs_pos, *comment_pos)))
- {
- if (is_raw != NULL && rs_pos != NULL)
- *is_raw = rs_pos->lnum;
- 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.
- */
- static char_u *
-skip_string(char_u *p)
-{
- int i;
-
- /*
- * We loop, because strings may be concatenated: "date""time".
- */
- for ( ; ; ++p)
- {
- if (p[0] == '\'') /* 'c' or '\n' or '\000' */
- {
- if (!p[1]) /* ' at end of line */
- break;
- i = 2;
- if (p[1] == '\\') /* '\n' or '\000' */
- {
- ++i;
- while (vim_isdigit(p[i - 1])) /* '\000' */
- ++i;
- }
- if (p[i] == '\'') /* check for trailing ' */
- {
- p += i;
- continue;
- }
- }
- else if (p[0] == '"') /* start of string */
- {
- for (++p; p[0]; ++p)
- {
- if (p[0] == '\\' && p[1] != NUL)
- ++p;
- else if (p[0] == '"') /* end of string */
- 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 */
- }
- if (!*p)
- --p; /* backup from NUL */
- return p;
-}
-#endif /* FEAT_CINDENT || FEAT_SYN_HL */
-
-#if defined(FEAT_CINDENT) || defined(PROTO)
-
-/*
- * Do C or expression indenting on the current line.
- */
- void
-do_c_expr_indent(void)
-{
-# ifdef FEAT_EVAL
- if (*curbuf->b_p_inde != NUL)
- fixthisline(get_expr_indent);
- else
-# endif
- fixthisline(get_c_indent);
-}
-
-/* Find result cache for cpp_baseclass */
-typedef struct {
- int found;
- lpos_T lpos;
-} cpp_baseclass_cache_T;
-
-/*
- * Functions for C-indenting.
- * Most of this originally comes from Eric Fischer.
- */
-/*
- * Below "XXX" means that this function may unlock the current line.
- */
-
-static int cin_isdefault(char_u *);
-static int cin_ispreproc(char_u *);
-static int cin_iscomment(char_u *);
-static int cin_islinecomment(char_u *);
-static int cin_isterminated(char_u *, int, int);
-static int cin_iselse(char_u *);
-static int cin_ends_in(char_u *, char_u *, char_u *);
-static int cin_starts_with(char_u *s, char *word);
-static pos_T *find_match_paren(int);
-static pos_T *find_match_char(int c, int ind_maxparen);
-static int find_last_paren(char_u *l, int start, int end);
-static int find_match(int lookfor, linenr_T ourscope);
-
-/*
- * 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)
-{
- while (*s)
- {
- char_u *prev_s = s;
-
- s = skipwhite(s);
-
- /* Perl/shell # comment comment continues until eol. Require a space
- * before # to avoid recognizing $#array. */
- if (curbuf->b_ind_hash_comment != 0 && s != prev_s && *s == '#')
- {
- s += STRLEN(s);
- break;
- }
- if (*s != '/')
- break;
- ++s;
- if (*s == '/') /* slash-slash comment continues till eol */
- {
- s += STRLEN(s);
- break;
- }
- if (*s != '*')
- break;
- for (++s; *s; ++s) /* skip slash-star comment */
- if (s[0] == '*' && s[1] == '/')
- {
- s += 2;
- break;
- }
- }
- return 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)
-{
- return *cin_skipcomment(s) == NUL;
-}
-
-/*
- * Check previous lines for a "//" line comment, skipping over blank lines.
- */
- static pos_T *
-find_line_comment(void) /* XXX */
-{
- static pos_T pos;
- char_u *line;
- char_u *p;
-
- pos = curwin->w_cursor;
- while (--pos.lnum > 0)
- {
- line = ml_get(pos.lnum);
- p = skipwhite(line);
- if (cin_islinecomment(p))
- {
- pos.col = (int)(p - line);
- return &pos;
- }
- if (*p != NUL)
- break;
- }
- return NULL;
-}
-
-/*
- * Return TRUE if "text" starts with "key:".
- */
- static int
-cin_has_js_key(char_u *text)
-{
- char_u *s = skipwhite(text);
- int quote = -1;
-
- if (*s == '\'' || *s == '"')
- {
- /* can be 'key': or "key": */
- quote = *s;
- ++s;
- }
- if (!vim_isIDc(*s)) /* need at least one ID character */
- return FALSE;
-
- while (vim_isIDc(*s))
- ++s;
- if (*s == quote)
- ++s;
-
- s = cin_skipcomment(s);
-
- /* "::" is not a label, it's C++ */
- return (*s == ':' && s[1] != ':');
-}
-
-/*
- * Check if string matches "label:"; move to character after ':' if true.
- * "*s" must point to the start of the label, if there is one.
- */
- static int
-cin_islabel_skip(char_u **s)
-{
- if (!vim_isIDc(**s)) /* need at least one ID character */
- return FALSE;
-
- while (vim_isIDc(**s))
- (*s)++;
-
- *s = cin_skipcomment(*s);
-
- /* "::" is not a label, it's C++ */
- return (**s == ':' && *++*s != ':');
-}
-
-/*
- * Recognize a label: "label:".
- * Note: curwin->w_cursor must be where we are looking for the label.
- */
- int
-cin_islabel(void) /* XXX */
-{
- char_u *s;
-
- s = cin_skipcomment(ml_get_curline());
-
- /*
- * Exclude "default" from labels, since it should be indented
- * like a switch label. Same for C++ scope declarations.
- */
- if (cin_isdefault(s))
- return FALSE;
- if (cin_isscopedecl(s))
- return FALSE;
-
- if (cin_islabel_skip(&s))
- {
- /*
- * Only accept a label if the previous line is terminated or is a case
- * label.
- */
- pos_T cursor_save;
- pos_T *trypos;
- char_u *line;
-
- cursor_save = curwin->w_cursor;
- while (curwin->w_cursor.lnum > 1)
- {
- --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)) != NULL) /* XXX */
- curwin->w_cursor = *trypos;
-
- line = ml_get_curline();
- if (cin_ispreproc(line)) /* ignore #defines, #if, etc. */
- continue;
- if (*(line = cin_skipcomment(line)) == NUL)
- continue;
-
- curwin->w_cursor = cursor_save;
- if (cin_isterminated(line, TRUE, FALSE)
- || cin_isscopedecl(line)
- || cin_iscase(line, TRUE)
- || (cin_islabel_skip(&line) && cin_nocode(line)))
- return TRUE;
- return FALSE;
- }
- curwin->w_cursor = cursor_save;
- return TRUE; /* label at start of file??? */
- }
- return FALSE;
-}
-
-/*
- * Recognize structure initialization and enumerations:
- * "[typedef] [static|public|protected|private] enum"
- * "[typedef] [static|public|protected|private] = {"
- */
- static int
-cin_isinit(void)
-{
- char_u *s;
- static char *skip[] = {"static", "public", "protected", "private"};
-
- s = cin_skipcomment(ml_get_curline());
-
- if (cin_starts_with(s, "typedef"))
- s = cin_skipcomment(s + 7);
-
- for (;;)
- {
- int i, l;
-
- for (i = 0; i < (int)(sizeof(skip) / sizeof(char *)); ++i)
- {
- l = (int)strlen(skip[i]);
- if (cin_starts_with(s, skip[i]))
- {
- s = cin_skipcomment(s + l);
- l = 0;
- break;
- }
- }
- if (l != 0)
- break;
- }
-
- if (cin_starts_with(s, "enum"))
- return TRUE;
-
- if (cin_ends_in(s, (char_u *)"=", (char_u *)"{"))
- return TRUE;
-
- return FALSE;
-}
-
-/*
- * Recognize a switch label: "case .*:" or "default:".
- */
- int
-cin_iscase(
- char_u *s,
- int strict) /* Allow relaxed check of case statement for JS */
-{
- s = cin_skipcomment(s);
- if (cin_starts_with(s, "case"))
- {
- for (s += 4; *s; ++s)
- {
- s = cin_skipcomment(s);
- if (*s == ':')
- {
- if (s[1] == ':') /* skip over "::" for C++ */
- ++s;
- else
- return TRUE;
- }
- if (*s == '\'' && s[1] && s[2] == '\'')
- s += 2; /* skip over ':' */
- else if (*s == '/' && (s[1] == '*' || s[1] == '/'))
- return FALSE; /* stop at comment */
- else if (*s == '"')
- {
- /* JS etc. */
- if (strict)
- return FALSE; /* stop at string */
- else
- return TRUE;
- }
- }
- return FALSE;
- }
-
- if (cin_isdefault(s))
- return TRUE;
- return FALSE;
-}
-
-/*
- * Recognize a "default" switch label.
- */
- static int
-cin_isdefault(char_u *s)
-{
- return (STRNCMP(s, "default", 7) == 0
- && *(s = cin_skipcomment(s + 7)) == ':'
- && s[1] != ':');
-}
-
-/*
- * Recognize a "public/private/protected" scope declaration label.
- */
- int
-cin_isscopedecl(char_u *s)
-{
- int i;
-
- s = cin_skipcomment(s);
- if (STRNCMP(s, "public", 6) == 0)
- i = 6;
- else if (STRNCMP(s, "protected", 9) == 0)
- i = 9;
- else if (STRNCMP(s, "private", 7) == 0)
- i = 7;
- else
- return FALSE;
- return (*(s = cin_skipcomment(s + i)) == ':' && s[1] != ':');
-}
-
-/* Maximum number of lines to search back for a "namespace" line. */
-#define FIND_NAMESPACE_LIM 20
-
-/*
- * Recognize a "namespace" scope declaration.
- */
- static int
-cin_is_cpp_namespace(char_u *s)
-{
- char_u *p;
- int has_name = FALSE;
- int has_name_start = FALSE;
-
- s = cin_skipcomment(s);
- if (STRNCMP(s, "namespace", 9) == 0 && (s[9] == NUL || !vim_iswordc(s[9])))
- {
- p = cin_skipcomment(skipwhite(s + 9));
- while (*p != NUL)
- {
- if (VIM_ISWHITE(*p))
- {
- has_name = TRUE; /* found end of a name */
- p = cin_skipcomment(skipwhite(p));
- }
- else if (*p == '{')
- {
- break;
- }
- else if (vim_iswordc(*p))
- {
- has_name_start = TRUE;
- if (has_name)
- return FALSE; /* word character after skipping past name */
- ++p;
- }
- else if (p[0] == ':' && p[1] == ':' && vim_iswordc(p[2]))
- {
- if (!has_name_start || has_name)
- return FALSE;
- /* C++ 17 nested namespace */
- p += 3;
- }
- else
- {
- return FALSE;
- }
- }
- return TRUE;
- }
- return FALSE;
-}
-
-/*
- * Recognize a `extern "C"` or `extern "C++"` linkage specifications.
- */
- static int
-cin_is_cpp_extern_c(char_u *s)
-{
- 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])))
- {
- p = cin_skipcomment(skipwhite(s + 6));
- while (*p != NUL)
- {
- if (VIM_ISWHITE(*p))
- {
- p = cin_skipcomment(skipwhite(p));
- }
- else if (*p == '{')
- {
- break;
- }
- else if (p[0] == '"' && p[1] == 'C' && p[2] == '"')
- {
- if (has_string_literal)
- return FALSE;
- has_string_literal = TRUE;
- p += 3;
- }
- else if (p[0] == '"' && p[1] == 'C' && p[2] == '+' && p[3] == '+'
- && p[4] == '"')
- {
- if (has_string_literal)
- return FALSE;
- has_string_literal = TRUE;
- p += 5;
- }
- else
- {
- return FALSE;
- }
- }
- return has_string_literal ? TRUE : FALSE;
- }
- return FALSE;
-}
-
-/*
- * Return a pointer to the first non-empty non-comment character after a ':'.
- * Return NULL if not found.
- * case 234: a = b;
- * ^
- */
- static char_u *
-after_label(char_u *l)
-{
- for ( ; *l; ++l)
- {
- if (*l == ':')
- {
- if (l[1] == ':') /* skip over "::" for C++ */
- ++l;
- else if (!cin_iscase(l + 1, FALSE))
- break;
- }
- else if (*l == '\'' && l[1] && l[2] == '\'')
- l += 2; /* skip over 'x' */
- }
- if (*l == NUL)
- return NULL;
- l = cin_skipcomment(l + 1);
- if (*l == NUL)
- return NULL;
- return l;
-}
-
-/*
- * Get indent of line "lnum", skipping a label.
- * Return 0 if there is nothing after the label.
- */
- static int
-get_indent_nolabel (linenr_T lnum) /* XXX */
-{
- char_u *l;
- pos_T fp;
- colnr_T col;
- char_u *p;
-
- l = ml_get(lnum);
- p = after_label(l);
- if (p == NULL)
- return 0;
-
- fp.col = (colnr_T)(p - l);
- fp.lnum = lnum;
- getvcol(curwin, &fp, &col, NULL, NULL);
- return (int)col;
-}
-
-/*
- * Find indent for line "lnum", ignoring any case or jump label.
- * Also return a pointer to the text (after the label) in "pp".
- * label: if (asdf && asdfasdf)
- * ^
- */
- static int
-skip_label(linenr_T lnum, char_u **pp)
-{
- char_u *l;
- int amount;
- pos_T cursor_save;
-
- cursor_save = curwin->w_cursor;
- curwin->w_cursor.lnum = lnum;
- l = ml_get_curline();
- /* XXX */
- if (cin_iscase(l, FALSE) || cin_isscopedecl(l) || cin_islabel())
- {
- amount = get_indent_nolabel(lnum);
- l = after_label(ml_get_curline());
- if (l == NULL) /* just in case */
- l = ml_get_curline();
- }
- else
- {
- amount = get_indent();
- l = ml_get_curline();
- }
- *pp = l;
-
- curwin->w_cursor = cursor_save;
- return amount;
-}
-
-/*
- * Return the indent of the first variable name after a type in a declaration.
- * int a, indent of "a"
- * static struct foo b, indent of "b"
- * enum bla c, indent of "c"
- * Returns zero when it doesn't look like a declaration.
- */
- static int
-cin_first_id_amount(void)
-{
- char_u *line, *p, *s;
- int len;
- pos_T fp;
- colnr_T col;
-
- line = ml_get_curline();
- p = skipwhite(line);
- len = (int)(skiptowhite(p) - p);
- if (len == 6 && STRNCMP(p, "static", 6) == 0)
- {
- p = skipwhite(p + 6);
- len = (int)(skiptowhite(p) - p);
- }
- if (len == 6 && STRNCMP(p, "struct", 6) == 0)
- p = skipwhite(p + 6);
- else if (len == 4 && STRNCMP(p, "enum", 4) == 0)
- p = skipwhite(p + 4);
- else if ((len == 8 && STRNCMP(p, "unsigned", 8) == 0)
- || (len == 6 && STRNCMP(p, "signed", 6) == 0))
- {
- s = skipwhite(p + len);
- if ((STRNCMP(s, "int", 3) == 0 && VIM_ISWHITE(s[3]))
- || (STRNCMP(s, "long", 4) == 0 && VIM_ISWHITE(s[4]))
- || (STRNCMP(s, "short", 5) == 0 && VIM_ISWHITE(s[5]))
- || (STRNCMP(s, "char", 4) == 0 && VIM_ISWHITE(s[4])))
- p = s;
- }
- for (len = 0; vim_isIDc(p[len]); ++len)
- ;
- if (len == 0 || !VIM_ISWHITE(p[len]) || cin_nocode(p))
- return 0;
-
- p = skipwhite(p + len);
- fp.lnum = curwin->w_cursor.lnum;
- fp.col = (colnr_T)(p - line);
- getvcol(curwin, &fp, &col, NULL, NULL);
- return (int)col;
-}
-
-/*
- * Return the indent of the first non-blank after an equal sign.
- * char *foo = "here";
- * Return zero if no (useful) equal sign found.
- * Return -1 if the line above "lnum" ends in a backslash.
- * foo = "asdf\
- * asdf\
- * here";
- */
- static int
-cin_get_equal_amount(linenr_T lnum)
-{
- char_u *line;
- char_u *s;
- colnr_T col;
- pos_T fp;
-
- if (lnum > 1)
- {
- line = ml_get(lnum - 1);
- if (*line != NUL && line[STRLEN(line) - 1] == '\\')
- return -1;
- }
-
- line = s = ml_get(lnum);
- while (*s != NUL && vim_strchr((char_u *)"=;{}\"'", *s) == NULL)
- {
- if (cin_iscomment(s)) /* ignore comments */
- s = cin_skipcomment(s);
- else
- ++s;
- }
- if (*s != '=')
- return 0;
-
- s = skipwhite(s + 1);
- if (cin_nocode(s))
- return 0;
-
- if (*s == '"') /* nice alignment for continued strings */
- ++s;
-
- fp.lnum = lnum;
- fp.col = (colnr_T)(s - line);
- getvcol(curwin, &fp, &col, NULL, NULL);
- return (int)col;
-}
-
-/*
- * Recognize a preprocessor statement: Any line that starts with '#'.
- */
- static int
-cin_ispreproc(char_u *s)
-{
- if (*skipwhite(s) == '#')
- return TRUE;
- return FALSE;
-}
-
-/*
- * Return TRUE if line "*pp" at "*lnump" is a preprocessor statement or a
- * 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)
-{
- char_u *line = *pp;
- linenr_T lnum = *lnump;
- int retval = FALSE;
- int candidate_amount = *amount;
-
- if (*line != NUL && line[STRLEN(line) - 1] == '\\')
- candidate_amount = get_indent_lnum(lnum);
-
- for (;;)
- {
- if (cin_ispreproc(line))
- {
- retval = TRUE;
- *lnump = lnum;
- break;
- }
- if (lnum == 1)
- break;
- line = ml_get(--lnum);
- if (*line == NUL || line[STRLEN(line) - 1] != '\\')
- break;
- }
-
- if (lnum != *lnump)
- *pp = ml_get(*lnump);
- if (retval)
- *amount = candidate_amount;
- return retval;
-}
-
-/*
- * Recognize the start of a C or C++ comment.
- */
- static int
-cin_iscomment(char_u *p)
-{
- return (p[0] == '/' && (p[1] == '*' || p[1] == '/'));
-}
-
-/*
- * Recognize the start of a "//" comment.
- */
- static int
-cin_islinecomment(char_u *p)
-{
- return (p[0] == '/' && p[1] == '/');
-}
-
-/*
- * Recognize a line that starts with '{' or '}', or ends with ';', ',', '{' or
- * '}'.
- * Don't consider "} else" a terminated line.
- * If a line begins with an "else", only consider it terminated if no unmatched
- * opening braces follow (handle "else { foo();" correctly).
- * Return the character terminating the line (ending char's have precedence if
- * both apply in order to determine initializations).
- */
- static int
-cin_isterminated(
- char_u *s,
- int incl_open, /* include '{' at the end as terminator */
- int incl_comma) /* recognize a trailing comma */
-{
- char_u found_start = 0;
- unsigned n_open = 0;
- int is_else = FALSE;
-
- s = cin_skipcomment(s);
-
- if (*s == '{' || (*s == '}' && !cin_iselse(s)))
- found_start = *s;
-
- if (!found_start)
- is_else = cin_iselse(s);
-
- while (*s)
- {
- /* skip over comments, "" strings and 'c'haracters */
- s = skip_string(cin_skipcomment(s));
- if (*s == '}' && n_open > 0)
- --n_open;
- if ((!is_else || n_open == 0)
- && (*s == ';' || *s == '}' || (incl_comma && *s == ','))
- && cin_nocode(s + 1))
- return *s;
- else if (*s == '{')
- {
- if (incl_open && cin_nocode(s + 1))
- return *s;
- else
- ++n_open;
- }
-
- if (*s)
- s++;
- }
- return found_start;
-}
-
-/*
- * Recognize the basic picture of a function declaration -- it needs to
- * have an open paren somewhere and a close paren at the end of the line and
- * no semicolons anywhere.
- * When a line ends in a comma we continue looking in the next line.
- * "sp" points to a string with the line. When looking at other lines it must
- * be restored to the line. When it's NULL fetch lines here.
- * "first_lnum" is where we start looking.
- * "min_lnum" is the line before which we will not be looking.
- */
- static int
-cin_isfuncdecl(
- char_u **sp,
- linenr_T first_lnum,
- linenr_T min_lnum)
-{
- char_u *s;
- linenr_T lnum = first_lnum;
- linenr_T save_lnum = curwin->w_cursor.lnum;
- int retval = FALSE;
- pos_T *trypos;
- int just_started = TRUE;
-
- if (sp == NULL)
- s = ml_get(lnum);
- else
- s = *sp;
-
- curwin->w_cursor.lnum = lnum;
- if (find_last_paren(s, '(', ')')
- && (trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL)
- {
- lnum = trypos->lnum;
- if (lnum < min_lnum)
- {
- curwin->w_cursor.lnum = save_lnum;
- return FALSE;
- }
-
- s = ml_get(lnum);
- }
- curwin->w_cursor.lnum = save_lnum;
-
- /* Ignore line starting with #. */
- if (cin_ispreproc(s))
- return FALSE;
-
- while (*s && *s != '(' && *s != ';' && *s != '\'' && *s != '"')
- {
- if (cin_iscomment(s)) /* ignore comments */
- s = cin_skipcomment(s);
- else if (*s == ':')
- {
- if (*(s + 1) == ':')
- s += 2;
- else
- /* To avoid a mistake in the following situation:
- * A::A(int a, int b)
- * : a(0) // <--not a function decl
- * , b(0)
- * {...
- */
- return FALSE;
- }
- else
- ++s;
- }
- if (*s != '(')
- return FALSE; /* ';', ' or " before any () or no '(' */
-
- while (*s && *s != ';' && *s != '\'' && *s != '"')
- {
- if (*s == ')' && cin_nocode(s + 1))
- {
- /* ')' at the end: may have found a match
- * Check for he previous line not to end in a backslash:
- * #if defined(x) && \
- * defined(y)
- */
- lnum = first_lnum - 1;
- s = ml_get(lnum);
- if (*s == NUL || s[STRLEN(s) - 1] != '\\')
- retval = TRUE;
- goto done;
- }
- if ((*s == ',' && cin_nocode(s + 1)) || s[1] == NUL || cin_nocode(s))
- {
- int comma = (*s == ',');
-
- /* ',' at the end: continue looking in the next line.
- * At the end: check for ',' in the next line, for this style:
- * func(arg1
- * , arg2) */
- for (;;)
- {
- if (lnum >= curbuf->b_ml.ml_line_count)
- break;
- s = ml_get(++lnum);
- if (!cin_ispreproc(s))
- break;
- }
- if (lnum >= curbuf->b_ml.ml_line_count)
- break;
- /* Require a comma at end of the line or a comma or ')' at the
- * start of next line. */
- s = skipwhite(s);
- if (!just_started && (!comma && *s != ',' && *s != ')'))
- break;
- just_started = FALSE;
- }
- else if (cin_iscomment(s)) /* ignore comments */
- s = cin_skipcomment(s);
- else
- {
- ++s;
- just_started = FALSE;
- }
- }
-
-done:
- if (lnum != first_lnum && sp != NULL)
- *sp = ml_get(first_lnum);
-
- return retval;
-}
-
- static int
-cin_isif(char_u *p)
-{
- return (STRNCMP(p, "if", 2) == 0 && !vim_isIDc(p[2]));
-}
-
- static int
-cin_iselse(
- char_u *p)
-{
- if (*p == '}') /* accept "} else" */
- p = cin_skipcomment(p + 1);
- return (STRNCMP(p, "else", 4) == 0 && !vim_isIDc(p[4]));
-}
-
- static int
-cin_isdo(char_u *p)
-{
- return (STRNCMP(p, "do", 2) == 0 && !vim_isIDc(p[2]));
-}
-
-/*
- * Check if this is a "while" that should have a matching "do".
- * 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 */
-{
- pos_T cursor_save;
- pos_T *trypos;
- int retval = FALSE;
-
- p = cin_skipcomment(p);
- if (*p == '}') /* accept "} while (cond);" */
- p = cin_skipcomment(p + 1);
- if (cin_starts_with(p, "while"))
- {
- cursor_save = curwin->w_cursor;
- curwin->w_cursor.lnum = lnum;
- curwin->w_cursor.col = 0;
- p = ml_get_curline();
- while (*p && *p != 'w') /* skip any '}', until the 'w' of the "while" */
- {
- ++p;
- ++curwin->w_cursor.col;
- }
- if ((trypos = findmatchlimit(NULL, 0, 0,
- curbuf->b_ind_maxparen)) != NULL
- && *cin_skipcomment(ml_get_pos(trypos) + 1) == ';')
- retval = TRUE;
- curwin->w_cursor = cursor_save;
- }
- return retval;
-}
-
-/*
- * Check whether in "p" there is an "if", "for" or "while" before "*poffset".
- * Return 0 if there is none.
- * 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)
-{
- int offset = *poffset;
-
- if (offset-- < 2)
- return 0;
- while (offset > 2 && VIM_ISWHITE(line[offset]))
- --offset;
-
- offset -= 1;
- if (!STRNCMP(line + offset, "if", 2))
- goto probablyFound;
-
- if (offset >= 1)
- {
- offset -= 1;
- if (!STRNCMP(line + offset, "for", 3))
- goto probablyFound;
-
- if (offset >= 2)
- {
- offset -= 2;
- if (!STRNCMP(line + offset, "while", 5))
- goto probablyFound;
- }
- }
- return 0;
-
-probablyFound:
- if (!offset || !vim_isIDc(line[offset - 1]))
- {
- *poffset = offset;
- return 1;
- }
- return 0;
-}
-
-/*
- * Return TRUE if we are at the end of a do-while.
- * do
- * nothing;
- * while (foo
- * && bar); <-- here
- * Adjust the cursor to the line with "while".
- */
- static int
-cin_iswhileofdo_end(int terminated)
-{
- char_u *line;
- char_u *p;
- char_u *s;
- pos_T *trypos;
- int i;
-
- if (terminated != ';') /* there must be a ';' at the end */
- return FALSE;
-
- p = line = ml_get_curline();
- while (*p != NUL)
- {
- p = cin_skipcomment(p);
- if (*p == ')')
- {
- s = skipwhite(p + 1);
- if (*s == ';' && cin_nocode(s + 1))
- {
- /* Found ");" at end of the line, now check there is "while"
- * before the matching '('. XXX */
- i = (int)(p - line);
- curwin->w_cursor.col = i;
- trypos = find_match_paren(curbuf->b_ind_maxparen);
- if (trypos != NULL)
- {
- s = cin_skipcomment(ml_get(trypos->lnum));
- if (*s == '}') /* accept "} while (cond);" */
- s = cin_skipcomment(s + 1);
- if (cin_starts_with(s, "while"))
- {
- curwin->w_cursor.lnum = trypos->lnum;
- return TRUE;
- }
- }
-
- /* Searching may have made "line" invalid, get it again. */
- line = ml_get_curline();
- p = line + i;
- }
- }
- if (*p != NUL)
- ++p;
- }
- return FALSE;
-}
-
- static int
-cin_isbreak(char_u *p)
-{
- return (STRNCMP(p, "break", 5) == 0 && !vim_isIDc(p[5]));
-}
-
-/*