diff options
Diffstat (limited to 'data/vim/patches/8.1.0857')
-rw-r--r-- | data/vim/patches/8.1.0857 | 9872 |
1 files changed, 9872 insertions, 0 deletions
diff --git a/data/vim/patches/8.1.0857 b/data/vim/patches/8.1.0857 new file mode 100644 index 000000000..06d20502e --- /dev/null +++ b/data/vim/patches/8.1.0857 @@ -0,0 +1,9872 @@ +To: vim_dev@googlegroups.com +Subject: Patch 8.1.0857 +Fcc: outbox +From: Bram Moolenaar <Bram@moolenaar.net> +Mime-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit +------------ + +Patch 8.1.0857 +Problem: Indent functionality is not separated. +Solution: Move indent functionality into a new file. (Yegappan Lakshmanan, + closes #3886) +Files: Filelist, src/Make_bc5.mak, src/Make_cyg_ming.mak, + src/Make_dice.mak, src/Make_ivc.mak, src/Make_manx.mak, + src/Make_morph.mak, src/Make_mvc.mak, src/Make_sas.mak, + src/Make_vms.mms, src/Makefile, src/edit.c, src/indent.c, + src/misc1.c, src/proto.h, src/proto/edit.pro, + src/proto/indent.pro, src/proto/misc1.pro + + +*** ../vim-8.1.0856/Filelist 2019-01-26 16:20:44.256683619 +0100 +--- Filelist 2019-01-31 13:43:23.348467289 +0100 +*************** +*** 49,54 **** +--- 49,55 ---- + src/gui_beval.c \ + src/hardcopy.c \ + src/hashtab.c \ ++ src/indent.c \ + src/json.c \ + src/json_test.c \ + src/kword_test.c \ +*************** +*** 175,180 **** +--- 176,182 ---- + src/proto/gui_beval.pro \ + src/proto/hardcopy.pro \ + src/proto/hashtab.pro \ ++ src/proto/indent.pro \ + src/proto/json.pro \ + src/proto/list.pro \ + src/proto/main.pro \ +*** ../vim-8.1.0856/src/Make_bc5.mak 2019-01-26 16:20:44.256683619 +0100 +--- src/Make_bc5.mak 2019-01-31 13:43:23.348467289 +0100 +*************** +*** 548,553 **** +--- 548,554 ---- + $(OBJDIR)\getchar.obj \ + $(OBJDIR)\hardcopy.obj \ + $(OBJDIR)\hashtab.obj \ ++ $(OBJDIR)\indent.obj \ + $(OBJDIR)\json.obj \ + $(OBJDIR)\list.obj \ + $(OBJDIR)\main.obj \ +*** ../vim-8.1.0856/src/Make_cyg_ming.mak 2019-01-26 16:20:44.256683619 +0100 +--- src/Make_cyg_ming.mak 2019-01-31 13:43:23.348467289 +0100 +*************** +*** 720,725 **** +--- 720,726 ---- + $(OUTDIR)/getchar.o \ + $(OUTDIR)/hardcopy.o \ + $(OUTDIR)/hashtab.o \ ++ $(OUTDIR)/indent.o \ + $(OUTDIR)/json.o \ + $(OUTDIR)/list.o \ + $(OUTDIR)/main.o \ +*** ../vim-8.1.0856/src/Make_dice.mak 2019-01-26 16:20:44.256683619 +0100 +--- src/Make_dice.mak 2019-01-31 13:43:23.348467289 +0100 +*************** +*** 50,55 **** +--- 50,56 ---- + getchar.c \ + hardcopy.c \ + hashtab.c \ ++ indent.c \ + json.c \ + list.c \ + main.c \ +*************** +*** 108,113 **** +--- 109,115 ---- + o/getchar.o \ + o/hardcopy.o \ + o/hashtab.o \ ++ o/indent.o \ + o/json.o \ + o/list.o \ + o/main.o \ +*************** +*** 209,214 **** +--- 211,218 ---- + + o/hashtab.o: hashtab.c $(SYMS) + ++ o/indent.o: indent.c $(SYMS) ++ + o/json.o: json.c $(SYMS) + + o/list.o: list.c $(SYMS) +*** ../vim-8.1.0856/src/Make_ivc.mak 2019-01-26 16:20:44.256683619 +0100 +--- src/Make_ivc.mak 2019-01-31 13:43:23.348467289 +0100 +*************** +*** 234,239 **** +--- 234,240 ---- + "$(INTDIR)/getchar.obj" \ + "$(INTDIR)/hardcopy.obj" \ + "$(INTDIR)/hashtab.obj" \ ++ "$(INTDIR)/indent.obj" \ + "$(INTDIR)/json.obj" \ + "$(INTDIR)/list.obj" \ + "$(INTDIR)/main.obj" \ +*************** +*** 434,439 **** +--- 435,444 ---- + SOURCE=.\hashtab.c + # End Source File + # Begin Source File ++ # ++ SOURCE=.\indent.c ++ # End Source File ++ # Begin Source File + + SOURCE=.\gui.c + +*** ../vim-8.1.0856/src/Make_manx.mak 2019-01-26 16:20:44.260683581 +0100 +--- src/Make_manx.mak 2019-01-31 13:43:23.348467289 +0100 +*************** +*** 60,65 **** +--- 60,66 ---- + getchar.c \ + hardcopy.c \ + hashtab.c \ ++ indent.c \ + json.c \ + list.c \ + main.c \ +*************** +*** 120,125 **** +--- 121,127 ---- + obj/getchar.o \ + obj/hardcopy.o \ + obj/hashtab.o \ ++ obj/indent.o \ + obj/json.o \ + obj/list.o \ + obj/main.o \ +*************** +*** 178,183 **** +--- 180,186 ---- + proto/getchar.pro \ + proto/hardcopy.pro \ + proto/hashtab.pro \ ++ proto/indent.pro \ + proto/json.pro \ + proto/list.pro \ + proto/main.pro \ +*************** +*** 329,334 **** +--- 332,340 ---- + obj/hashtab.o: hashtab.c + $(CCSYM) $@ hashtab.c + ++ obj/indent.o: indent.c ++ $(CCSYM) $@ indent.c ++ + obj/json.o: json.c + $(CCSYM) $@ json.c + +*** ../vim-8.1.0856/src/Make_morph.mak 2019-01-26 16:20:44.260683581 +0100 +--- src/Make_morph.mak 2019-01-31 13:43:23.348467289 +0100 +*************** +*** 48,53 **** +--- 48,54 ---- + getchar.c \ + hardcopy.c \ + hashtab.c \ ++ indent.c \ + json.c \ + list.c \ + main.c \ +*** ../vim-8.1.0856/src/Make_mvc.mak 2019-01-26 16:20:44.260683581 +0100 +--- src/Make_mvc.mak 2019-01-31 13:43:23.348467289 +0100 +*************** +*** 725,730 **** +--- 725,731 ---- + $(OUTDIR)\getchar.obj \ + $(OUTDIR)\hardcopy.obj \ + $(OUTDIR)\hashtab.obj \ ++ $(OUTDIR)\indent.obj \ + $(OUTDIR)\json.obj \ + $(OUTDIR)\list.obj \ + $(OUTDIR)\main.obj \ +*************** +*** 1414,1419 **** +--- 1415,1422 ---- + + $(OUTDIR)/hashtab.obj: $(OUTDIR) hashtab.c $(INCL) + ++ $(OUTDIR)/indent.obj: $(OUTDIR) indent.c $(INCL) ++ + $(OUTDIR)/gui.obj: $(OUTDIR) gui.c $(INCL) $(GUI_INCL) + + $(OUTDIR)/gui_beval.obj: $(OUTDIR) gui_beval.c $(INCL) $(GUI_INCL) +*************** +*** 1645,1650 **** +--- 1648,1654 ---- + proto/getchar.pro \ + proto/hardcopy.pro \ + proto/hashtab.pro \ ++ proto/indent.pro \ + proto/json.pro \ + proto/list.pro \ + proto/main.pro \ +*** ../vim-8.1.0856/src/Make_sas.mak 2019-01-26 16:20:44.260683581 +0100 +--- src/Make_sas.mak 2019-01-31 13:43:23.348467289 +0100 +*************** +*** 113,118 **** +--- 113,119 ---- + getchar.c \ + hardcopy.c \ + hashtab.c \ ++ indent.c \ + json.c \ + list.c \ + main.c \ +*************** +*** 172,177 **** +--- 173,179 ---- + getchar.o \ + hardcopy.o \ + hashtab.o \ ++ indent.o \ + json.o \ + list.o \ + main.o \ +*************** +*** 231,236 **** +--- 233,239 ---- + proto/getchar.pro \ + proto/hardcopy.pro \ + proto/hashtab.pro \ ++ proto/indent.pro \ + proto/json.pro \ + proto/list.pro \ + proto/main.pro \ +*************** +*** 368,373 **** +--- 371,378 ---- + proto/hardcopy.pro: hardcopy.c + hashtab.o: hashtab.c + proto/hashtab.pro: hashtab.c ++ indent.o: indent.c ++ proto/indent.pro: indent.c + json.o: json.c + proto/json.pro: json.c + list.o: list.c +*** ../vim-8.1.0856/src/Make_vms.mms 2019-01-26 16:20:44.260683581 +0100 +--- src/Make_vms.mms 2019-01-31 13:43:23.352467260 +0100 +*************** +*** 314,320 **** + + SRC = arabic.c autocmd.c beval.c blob.c blowfish.c buffer.c charset.c crypt.c crypt_zip.c dict.c diff.c digraph.c edit.c eval.c \ + evalfunc.c ex_cmds.c ex_cmds2.c ex_docmd.c ex_eval.c ex_getln.c if_cscope.c if_xcmdsrv.c farsi.c fileio.c fold.c \ +! getchar.c hardcopy.c hashtab.c json.c list.c main.c mark.c menu.c mbyte.c memfile.c memline.c message.c misc1.c \ + misc2.c move.c normal.c ops.c option.c popupmnu.c quickfix.c regexp.c search.c sha256.c sign.c \ + spell.c spellfile.c syntax.c tag.c term.c termlib.c textprop.c ui.c undo.c userfunc.c version.c screen.c \ + window.c os_unix.c os_vms.c pathdef.c \ +--- 314,320 ---- + + SRC = arabic.c autocmd.c beval.c blob.c blowfish.c buffer.c charset.c crypt.c crypt_zip.c dict.c diff.c digraph.c edit.c eval.c \ + evalfunc.c ex_cmds.c ex_cmds2.c ex_docmd.c ex_eval.c ex_getln.c if_cscope.c if_xcmdsrv.c farsi.c fileio.c fold.c \ +! getchar.c hardcopy.c hashtab.c indent.c json.c list.c main.c mark.c menu.c mbyte.c memfile.c memline.c message.c misc1.c \ + misc2.c move.c normal.c ops.c option.c popupmnu.c quickfix.c regexp.c search.c sha256.c sign.c \ + spell.c spellfile.c syntax.c tag.c term.c termlib.c textprop.c ui.c undo.c userfunc.c version.c screen.c \ + window.c os_unix.c os_vms.c pathdef.c \ +*************** +*** 323,329 **** + + OBJ = arabic.obj autocmd.obj beval.obj blob.obj blowfish.obj buffer.obj charset.obj crypt.obj crypt_zip.obj dict.obj diff.obj digraph.obj \ + edit.obj eval.obj evalfunc.obj ex_cmds.obj ex_cmds2.obj ex_docmd.obj ex_eval.obj ex_getln.obj if_cscope.obj \ +! if_xcmdsrv.obj farsi.obj fileio.obj fold.obj getchar.obj hardcopy.obj hashtab.obj json.obj list.obj main.obj mark.obj \ + menu.obj memfile.obj memline.obj message.obj misc1.obj misc2.obj \ + move.obj mbyte.obj normal.obj ops.obj option.obj popupmnu.obj quickfix.obj \ + regexp.obj search.obj sha256.obj sign.obj spell.obj spellfile.obj syntax.obj tag.obj term.obj termlib.obj textprop.obj \ +--- 323,329 ---- + + OBJ = arabic.obj autocmd.obj beval.obj blob.obj blowfish.obj buffer.obj charset.obj crypt.obj crypt_zip.obj dict.obj diff.obj digraph.obj \ + edit.obj eval.obj evalfunc.obj ex_cmds.obj ex_cmds2.obj ex_docmd.obj ex_eval.obj ex_getln.obj if_cscope.obj \ +! if_xcmdsrv.obj farsi.obj fileio.obj fold.obj getchar.obj hardcopy.obj hashtab.obj indent.obj json.obj list.obj main.obj mark.obj \ + menu.obj memfile.obj memline.obj message.obj misc1.obj misc2.obj \ + move.obj mbyte.obj normal.obj ops.obj option.obj popupmnu.obj quickfix.obj \ + regexp.obj search.obj sha256.obj sign.obj spell.obj spellfile.obj syntax.obj tag.obj term.obj termlib.obj textprop.obj \ +*************** +*** 596,601 **** +--- 596,602 ---- + ascii.h keymap.h term.h macros.h option.h structs.h \ + regexp.h gui.h beval.h [.proto]gui_beval.pro ex_cmds.h proto.h \ + globals.h farsi.h arabic.h if_mzsch.h ++ indent.obj : indent.c vim.h [.auto]config.h feature.h os_unix.h + json.obj : json.c vim.h [.auto]config.h feature.h os_unix.h \ + ascii.h keymap.h term.h macros.h structs.h regexp.h gui.h beval.h \ + [.proto]gui_beval.pro option.h ex_cmds.h proto.h globals.h farsi.h \ +*** ../vim-8.1.0856/src/Makefile 2019-01-26 17:36:46.997192946 +0100 +--- src/Makefile 2019-01-31 13:43:23.352467260 +0100 +*************** +*** 1599,1604 **** +--- 1598,1604 ---- + hashtab.c \ + if_cscope.c \ + if_xcmdsrv.c \ ++ indent.c \ + json.c \ + list.c \ + main.c \ +*************** +*** 1712,1717 **** +--- 1712,1718 ---- + $(HANGULIN_OBJ) \ + objects/if_cscope.o \ + objects/if_xcmdsrv.o \ ++ objects/indent.o \ + objects/list.o \ + objects/mark.o \ + objects/memline.o \ +*************** +*** 1842,1847 **** +--- 1843,1849 ---- + if_python3.pro \ + if_ruby.pro \ + if_xcmdsrv.pro \ ++ indent.pro \ + json.pro \ + list.pro \ + main.pro \ +*************** +*** 3093,3098 **** +--- 3095,3103 ---- + objects/if_tcl.o: if_tcl.c + $(CCC_NF) $(TCL_CFLAGS) $(ALL_CFLAGS) -o $@ if_tcl.c + ++ objects/indent.o: indent.c ++ $(CCC) -o $@ indent.c ++ + objects/json.o: json.c + $(CCC) -o $@ json.c + +*************** +*** 3490,3495 **** +--- 3495,3504 ---- + os_unix.h auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \ + proto.h globals.h farsi.h arabic.h version.h ++ objects/indent.o: indent.c vim.h protodef.h auto/config.h feature.h os_unix.h \ ++ os_mac.h ascii.h keymap.h term.h macros.h option.h beval.h structs.h \ ++ regexp.h gui.h alloc.h ex_cmds.h spell.h proto.h globals.h farsi.h \ ++ arabic.h + objects/json.o: json.c vim.h protodef.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \ + proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \ +*** ../vim-8.1.0856/src/edit.c 2019-01-26 17:28:22.220599167 +0100 +--- src/edit.c 2019-01-31 13:43:23.352467260 +0100 +*************** +*** 216,224 **** + static void replace_flush(void); + static void replace_do_bs(int limit_col); + static int del_char_after_col(int limit_col); +- #ifdef FEAT_CINDENT +- static int cindent_on(void); +- #endif + static void ins_reg(void); + static void ins_ctrl_g(void); + static void ins_ctrl_hat(void); +--- 216,221 ---- +*************** +*** 380,385 **** +--- 377,383 ---- + ins_compl_clear(); /* clear stuff for CTRL-X mode */ + #endif + ++ ch_log(NULL, "ENTERING Insert mode"); + /* + * Trigger InsertEnter autocommands. Do not do this for "r<CR>" or "grx". + */ +*************** +*** 1050,1055 **** +--- 1048,1054 ---- + if (cmdchar != 'r' && cmdchar != 'v' && c != Ctrl_C) + ins_apply_autocmds(EVENT_INSERTLEAVE); + did_cursorhold = FALSE; ++ ch_log(NULL, "LEAVING Insert mode"); + return (c == Ctrl_O); + } + continue; +*************** +*** 7923,8254 **** + (void)del_char_after_col(limit_col); + } + +- #ifdef FEAT_CINDENT +- /* +- * Return TRUE if C-indenting is on. +- */ +- static int +- cindent_on(void) +- { +- return (!p_paste && (curbuf->b_p_cin +- # ifdef FEAT_EVAL +- || *curbuf->b_p_inde != NUL +- # endif +- )); +- } +- #endif +- +- #if defined(FEAT_LISP) || defined(FEAT_CINDENT) || defined(PROTO) +- /* +- * Re-indent the current line, based on the current contents of it and the +- * surrounding lines. Fixing the cursor position seems really easy -- I'm very +- * confused what all the part that handles Control-T is doing that I'm not. +- * "get_the_indent" should be get_c_indent, get_expr_indent or get_lisp_indent. +- */ +- +- void +- fixthisline(int (*get_the_indent)(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 +- fix_indent(void) +- { +- if (p_paste) +- return; +- # ifdef FEAT_LISP +- if (curbuf->b_p_lisp && curbuf->b_p_ai) +- fixthisline(get_lisp_indent); +- # endif +- # if defined(FEAT_LISP) && defined(FEAT_CINDENT) +- else +- # endif +- # ifdef FEAT_CINDENT +- if (cindent_on()) +- do_c_expr_indent(); +- # endif +- } +- +- #endif +- +- #ifdef FEAT_CINDENT +- /* +- * return TRUE if 'cinkeys' contains the key "keytyped", +- * when == '*': Only if key is preceded with '*' (indent before insert) +- * when == '!': Only if key is preceded with '!' (don't insert) +- * when == ' ': Only if key is not preceded with '*'(indent afterwards) +- * +- * "keytyped" can have a few special values: +- * KEY_OPEN_FORW +- * KEY_OPEN_BACK +- * KEY_COMPLETE just finished completion. +- * +- * If line_is_empty is TRUE accept keys with '0' before them. +- */ +- int +- in_cinkeys( +- int keytyped, +- int when, +- int line_is_empty) +- { +- char_u *look; +- int try_match; +- int try_match_word; +- char_u *p; +- char_u *line; +- int icase; +- int i; +- +- if (keytyped == NUL) +- /* Can happen with CTRL-Y and CTRL-E on a short line. */ +- return FALSE; +- +- #ifdef FEAT_EVAL +- if (*curbuf->b_p_inde != NUL) +- look = curbuf->b_p_indk; /* 'indentexpr' set: use 'indentkeys' */ +- else +- #endif +- look = curbuf->b_p_cink; /* 'indentexpr' empty: use 'cinkeys' */ +- while (*look) +- { +- /* +- * Find out if we want to try a match with this key, depending on +- * 'when' and a '*' or '!' before the key. +- */ +- switch (when) +- { +- case '*': try_match = (*look == '*'); break; +- case '!': try_match = (*look == '!'); break; +- default: try_match = (*look != '*'); break; +- } +- if (*look == '*' || *look == '!') +- ++look; +- +- /* +- * If there is a '0', only accept a match if the line is empty. +- * But may still match when typing last char of a word. +- */ +- if (*look == '0') +- { +- try_match_word = try_match; +- if (!line_is_empty) +- try_match = FALSE; +- ++look; +- } +- else +- try_match_word = FALSE; +- +- /* +- * does it look like a control character? +- */ +- if (*look == '^' +- #ifdef EBCDIC +- && (Ctrl_chr(look[1]) != 0) +- #else +- && look[1] >= '?' && look[1] <= '_' +- #endif +- ) +- { +- if (try_match && keytyped == Ctrl_chr(look[1])) +- return TRUE; +- look += 2; +- } +- /* +- * 'o' means "o" command, open forward. +- * 'O' means "O" command, open backward. +- */ +- else if (*look == 'o') +- { +- if (try_match && keytyped == KEY_OPEN_FORW) +- return TRUE; +- ++look; +- } +- else if (*look == 'O') +- { +- if (try_match && keytyped == KEY_OPEN_BACK) +- return TRUE; +- ++look; +- } +- +- /* +- * 'e' means to check for "else" at start of line and just before the +- * cursor. +- */ +- else if (*look == 'e') +- { +- if (try_match && keytyped == 'e' && curwin->w_cursor.col >= 4) +- { +- p = ml_get_curline(); +- if (skipwhite(p) == p + curwin->w_cursor.col - 4 && +- STRNCMP(p + curwin->w_cursor.col - 4, "else", 4) == 0) +- return TRUE; +- } +- ++look; +- } +- +- /* +- * ':' only causes an indent if it is at the end of a label or case +- * statement, or when it was before typing the ':' (to fix +- * class::method for C++). +- */ +- else if (*look == ':') +- { +- if (try_match && keytyped == ':') +- { +- p = ml_get_curline(); +- if (cin_iscase(p, FALSE) || cin_isscopedecl(p) || cin_islabel()) +- return TRUE; +- /* Need to get the line again after cin_islabel(). */ +- p = ml_get_curline(); +- if (curwin->w_cursor.col > 2 +- && p[curwin->w_cursor.col - 1] == ':' +- && p[curwin->w_cursor.col - 2] == ':') +- { +- p[curwin->w_cursor.col - 1] = ' '; +- i = (cin_iscase(p, FALSE) || cin_isscopedecl(p) +- || cin_islabel()); +- p = ml_get_curline(); +- p[curwin->w_cursor.col - 1] = ':'; +- if (i) +- return TRUE; +- } +- } +- ++look; +- } +- +- +- /* +- * Is it a key in <>, maybe? +- */ +- else if (*look == '<') +- { +- if (try_match) +- { +- /* +- * make up some named keys <o>, <O>, <e>, <0>, <>>, <<>, <*>, +- * <:> and <!> so that people can re-indent on o, O, e, 0, <, +- * >, *, : and ! keys if they really really want to. +- */ +- if (vim_strchr((char_u *)"<>!*oOe0:", look[1]) != NULL +- && keytyped == look[1]) +- return TRUE; +- +- if (keytyped == get_special_key_code(look + 1)) +- return TRUE; +- } +- while (*look && *look != '>') +- look++; +- while (*look == '>') +- look++; +- } +- +- /* +- * Is it a word: "=word"? +- */ +- else if (*look == '=' && look[1] != ',' && look[1] != NUL) +- { +- ++look; +- if (*look == '~') +- { +- icase = TRUE; +- ++look; +- } +- else +- icase = FALSE; +- p = vim_strchr(look, ','); +- if (p == NULL) +- p = look + STRLEN(look); +- if ((try_match || try_match_word) +- && curwin->w_cursor.col >= (colnr_T)(p - look)) +- { +- int match = FALSE; +- +- #ifdef FEAT_INS_EXPAND +- if (keytyped == KEY_COMPLETE) +- { +- char_u *s; +- +- /* Just completed a word, check if it starts with "look". +- * search back for the start of a word. */ +- line = ml_get_curline(); +- if (has_mbyte) +- { +- char_u *n; +- +- for (s = line + curwin->w_cursor.col; s > line; s = n) +- { +- n = mb_prevptr(line, s); +- if (!vim_iswordp(n)) +- break; +- } +- } +- else +- for (s = line + curwin->w_cursor.col; s > line; --s) +- if (!vim_iswordc(s[-1])) +- break; +- if (s + (p - look) <= line + curwin->w_cursor.col +- && (icase +- ? MB_STRNICMP(s, look, p - look) +- : STRNCMP(s, look, p - look)) == 0) +- match = TRUE; +- } +- else +- #endif +- /* TODO: multi-byte */ +- if (keytyped == (int)p[-1] || (icase && keytyped < 256 +- && TOLOWER_LOC(keytyped) == TOLOWER_LOC((int)p[-1]))) +- { +- line = ml_get_cursor(); +- if ((curwin->w_cursor.col == (colnr_T)(p - look) +- || !vim_iswordc(line[-(p - look) - 1])) +- && (icase +- ? MB_STRNICMP(line - (p - look), look, p - look) +- : STRNCMP(line - (p - look), look, p - look)) +- == 0) +- match = TRUE; +- } +- if (match && try_match_word && !try_match) +- { +- /* "0=word": Check if there are only blanks before the +- * word. */ +- if (getwhitecols_curline() != +- (int)(curwin->w_cursor.col - (p - look))) +- match = FALSE; +- } +- if (match) +- return TRUE; +- } +- look = p; +- } +- +- /* +- * ok, it's a boring generic character. +- */ +- else +- { +- if (try_match && *look == keytyped) +- return TRUE; +- if (*look != NUL) +- ++look; +- } +- +- /* +- * Skip over ", ". +- */ +- look = skip_to_option_part(look); +- } +- return FALSE; +- } +- #endif /* FEAT_CINDENT */ +- + #if defined(FEAT_RIGHTLEFT) || defined(PROTO) + /* + * Map Hebrew keyboard when in hkmap mode. +--- 7922,7927 ---- +*** ../vim-8.1.0856/src/indent.c 2019-01-31 13:47:08.550925126 +0100 +--- src/indent.c 2019-01-31 13:43:23.352467260 +0100 +*************** +*** 0 **** +--- 1,4683 ---- ++ /* vi:set ts=8 sts=4 sw=4 noet: ++ * ++ * VIM - Vi IMproved by Bram Moolenaar ++ * ++ * Do ":help uganda" in Vim to read copying and usage conditions. ++ * Do ":help credits" in Vim to see a list of people who contributed. ++ * See README.txt for an overview of the Vim source code. ++ */ ++ ++ /* ++ * indent.c: Indentation related functions ++ */ ++ ++ #include "vim.h" ++ ++ #if defined(FEAT_CINDENT) || defined(FEAT_SMARTINDENT) ++ ++ /* ++ * Return TRUE if the string "line" starts with a word from 'cinwords'. ++ */ ++ 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 ++ ++ #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) ++ ++ /* ++ * Return TRUE if C-indenting is on. ++ */ ++ int ++ cindent_on(void) ++ { ++ return (!p_paste && (curbuf->b_p_cin ++ # ifdef FEAT_EVAL ++ || *curbuf->b_p_inde != NUL ++ # endif ++ )); ++ } ++ ++ /* 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])); ++ } ++ ++ /* ++ * Find the position of a C++ base-class declaration or ++ * constructor-initialization. eg: ++ * ++ * class MyClass : ++ * baseClass <-- here ++ * class MyClass : public baseClass, ++ * anotherBaseClass <-- here (should probably lineup ??) ++ * MyClass::MyClass(...) : ++ * baseClass(...) <-- here (constructor-initialization) ++ * ++ * This is a lot of guessing. Watch out for "cond ? func() : foo". ++ */ ++ static int ++ cin_is_cpp_baseclass( ++ cpp_baseclass_cache_T *cached) /* input and output */ ++ { ++ lpos_T *pos = &cached->lpos; /* find position */ ++ char_u *s; ++ int class_or_struct, lookfor_ctor_init, cpp_base_class; ++ linenr_T lnum = curwin->w_cursor.lnum; ++ char_u *line = ml_get_curline(); ++ ++ if (pos->lnum <= lnum) ++ return cached->found; /* Use the cached result */ ++ ++ pos->col = 0; ++ ++ s = skipwhite(line); ++ if (*s == '#') /* skip #define FOO x ? (x) : x */ ++ return FALSE; ++ s = cin_skipcomment(s); ++ if (*s == NUL) ++ return FALSE; ++ ++ cpp_base_class = lookfor_ctor_init = class_or_struct = FALSE; ++ ++ /* Search for a line starting with '#', empty, ending in ';' or containing ++ * '{' or '}' and start below it. This handles the following situations: ++ * a = cond ? ++ * func() : ++ * asdf; ++ * func::foo() ++ * : something ++ * {} ++ * Foo::Foo (int one, int two) ++ * : something(4), ++ * somethingelse(3) ++ * {} ++ */ ++ while (lnum > 1) ++ { ++ line = ml_get(lnum - 1); ++ s = skipwhite(line); ++ if (*s == '#' || *s == NUL) ++ break; ++ while (*s != NUL) ++ { ++ s = cin_skipcomment(s); ++ if (*s == '{' || *s == '}' ++ || (*s == ';' && cin_nocode(s + 1))) ++ break; ++ if (*s != NUL) ++ ++s; ++ } ++ if (*s != NUL) ++ break; ++ --lnum; ++ } ++ ++ pos->lnum = lnum; ++ line = ml_get(lnum); ++ s = line; ++ for (;;) ++ { ++ if (*s == NUL) ++ { ++ if (lnum == curwin->w_cursor.lnum) ++ break; ++ /* Continue in the cursor line. */ ++ line = ml_get(++lnum); ++ s = line; ++ } ++ if (s == line) ++ { ++ /* don't recognize "case (foo):" as a baseclass */ ++ if (cin_iscase(s, FALSE)) ++ break; ++ s = cin_skipcomment(line); ++ if (*s == NUL) ++ continue; ++ } ++ ++ if (s[0] == '"' || (s[0] == 'R' && s[1] == '"')) ++ s = skip_string(s) + 1; ++ else if (s[0] == ':') ++ { ++ if (s[1] == ':') ++ { ++ /* skip double colon. It can't be a constructor ++ * initialization any more */ ++ lookfor_ctor_init = FALSE; ++ s = cin_skipcomment(s + 2); ++ } ++ else if (lookfor_ctor_init || class_or_struct) ++ { ++ /* we have something found, that looks like the start of ++ * cpp-base-class-declaration or constructor-initialization */ ++ cpp_base_class = TRUE; ++ lookfor_ctor_init = class_or_struct = FALSE; ++ pos->col = 0; ++ s = cin_skipcomment(s + 1); ++ } ++ else ++ s = cin_skipcomment(s + 1); ++ } ++ else if ((STRNCMP(s, "class", 5) == 0 && !vim_isIDc(s[5])) ++ || (STRNCMP(s, "struct", 6) == 0 && !vim_isIDc(s[6]))) ++ { ++ class_or_struct = TRUE; ++ lookfor_ctor_init = FALSE; ++ ++ if (*s == 'c') ++ s = cin_skipcomment(s + 5); ++ else ++ s = cin_skipcomment(s + 6); ++ } ++ else ++ { ++ if (s[0] == '{' || s[0] == '}' || s[0] == ';') ++ { ++ cpp_base_class = lookfor_ctor_init = class_or_struct = FALSE; ++ } ++ else if (s[0] == ')') ++ { ++ /* Constructor-initialization is assumed if we come across ++ * something like "):" */ ++ class_or_struct = FALSE; ++ lookfor_ctor_init = TRUE; ++ } ++ else if (s[0] == '?') ++ { ++ /* Avoid seeing '() :' after '?' as constructor init. */ ++ return FALSE; ++ } ++ else if (!vim_isIDc(s[0])) ++ { ++ /* if it is not an identifier, we are wrong */ ++ class_or_struct = FALSE; ++ lookfor_ctor_init = FALSE; ++ } ++ else if (pos->col == 0) ++ { ++ /* it can't be a constructor-initialization any more */ ++ lookfor_ctor_init = FALSE; ++ ++ /* the first statement starts here: lineup with this one... */ ++ if (cpp_base_class) ++ pos->col = (colnr_T)(s - line); ++ } ++ ++ /* When the line ends in a comma don't align with it. */ ++ if (lnum == curwin->w_cursor.lnum && *s == ',' && cin_nocode(s + 1)) ++ pos->col = 0; ++ ++ s = cin_skipcomment(s + 1); ++ } ++ } ++ ++ cached->found = cpp_base_class; ++ if (cpp_base_class) ++ pos->lnum = lnum; ++ return cpp_base_class; ++ } ++ ++ static int ++ get_baseclass_amount(int col) ++ { ++ int amount; ++ colnr_T vcol; ++ pos_T *trypos; ++ ++ if (col == 0) ++ { ++ amount = get_indent(); ++ if (find_last_paren(ml_get_curline(), '(', ')') ++ && (trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL) ++ amount = get_indent_lnum(trypos->lnum); /* XXX */ ++ if (!cin_ends_in(ml_get_curline(), (char_u *)",", NULL)) ++ amount += curbuf->b_ind_cpp_baseclass; ++ } ++ else ++ { ++ curwin->w_cursor.col = col; ++ getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL); ++ amount = (int)vcol; ++ } ++ if (amount < curbuf->b_ind_cpp_baseclass) ++ amount = curbuf->b_ind_cpp_baseclass; ++ return amount; ++ } ++ ++ /* ++ * Return TRUE if string "s" ends with the string "find", possibly followed by ++ * white space and comments. Skip strings and comments. ++ * Ignore "ignore" after "find" if it's not NULL. ++ */ ++ static int ++ cin_ends_in(char_u *s, char_u *find, char_u *ignore) ++ { ++ char_u *p = s; ++ char_u *r; ++ int len = (int)STRLEN(find); ++ ++ while (*p != NUL) ++ { ++ p = cin_skipcomment(p); ++ if (STRNCMP(p, find, len) == 0) ++ { ++ r = skipwhite(p + len); ++ if (ignore != NULL && STRNCMP(r, ignore, STRLEN(ignore)) == 0) ++ r = skipwhite(r + STRLEN(ignore)); ++ if (cin_nocode(r)) ++ return TRUE; ++ } ++ if (*p != NUL) ++ ++p; ++ } ++ return FALSE; ++ } ++ ++ /* ++ * Return TRUE when "s" starts with "word" and then a non-ID character. ++ */ ++ static int ++ cin_starts_with(char_u *s, char *word) ++ { ++ int l = (int)STRLEN(word); ++ ++ return (STRNCMP(s, word, l) == 0 && !vim_isIDc(s[l])); ++ } ++ ++ /* ++ * Skip strings, chars and comments until at or past "trypos". ++ * Return the column found. ++ */ ++ static int ++ cin_skip2pos(pos_T *trypos) ++ { ++ char_u *line; ++ char_u *p; ++ char_u *new_p; ++ ++ p = line = ml_get(trypos->lnum); ++ while (*p && (colnr_T)(p - line) < trypos->col) ++ { ++ if (cin_iscomment(p)) ++ p = cin_skipcomment(p); ++ else ++ { ++ new_p = skip_string(p); ++ if (new_p == p) ++ ++p; ++ else ++ p = new_p; ++ } ++ } ++ return (int)(p - line); ++ } ++ ++ /* ++ * Find the '{' at the start of the block we are in. ++ * Return NULL if no match found. ++ * Ignore a '{' that is in a comment, makes indenting the next three lines ++ * work. */ ++ /* foo() */ ++ /* { */ ++ /* } */ ++ ++ static pos_T * ++ find_start_brace(void) /* XXX */ ++ { ++ pos_T cursor_save; ++ pos_T *trypos; ++ pos_T *pos; ++ static pos_T pos_copy; ++ ++ cursor_save = curwin->w_cursor; ++ while ((trypos = findmatchlimit(NULL, '{', FM_BLOCKSTOP, 0)) != NULL) ++ { ++ pos_copy = *trypos; /* copy pos_T, next findmatch will change it */ ++ trypos = &pos_copy; ++ curwin->w_cursor = *trypos; ++ 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)) == NULL) /* XXX */ ++ break; ++ if (pos != NULL) ++ curwin->w_cursor.lnum = pos->lnum; ++ } ++ curwin->w_cursor = cursor_save; ++ return trypos; ++ } ++ ++ /* ++ * Find the matching '(', ignoring it if it is in a comment. ++ * Return NULL if no match found. ++ */ ++ static pos_T * ++ find_match_paren(int ind_maxparen) /* XXX */ ++ { ++ return find_match_char('(', ind_maxparen); ++ } ++ ++ static pos_T * ++ find_match_char(int c, int ind_maxparen) /* XXX */ ++ { ++ pos_T cursor_save; ++ pos_T *trypos; ++ static pos_T pos_copy; ++ int ind_maxp_wk; ++ ++ cursor_save = curwin->w_cursor; ++ ind_maxp_wk = ind_maxparen; ++ retry: ++ if ((trypos = findmatchlimit(NULL, c, 0, ind_maxp_wk)) != NULL) ++ { ++ /* check if the ( is in a // comment */ ++ if ((colnr_T)cin_skip2pos(trypos) > trypos->col) ++ { ++ ind_maxp_wk = ind_maxparen - (int)(cursor_save.lnum - trypos->lnum); ++ if (ind_maxp_wk > 0) ++ { ++ curwin->w_cursor = *trypos; ++ curwin->w_cursor.col = 0; /* XXX */ ++ goto retry; ++ } ++ trypos = NULL; ++ } ++ else ++ { ++ pos_T *trypos_wk; ++ ++ pos_copy = *trypos; /* copy trypos, findmatch will change it */ ++ trypos = &pos_copy; ++ curwin->w_cursor = *trypos; ++ if ((trypos_wk = ind_find_start_CORS(NULL)) != NULL) /* XXX */ ++ { ++ ind_maxp_wk = ind_maxparen - (int)(cursor_save.lnum ++ - trypos_wk->lnum); ++ if (ind_maxp_wk > 0) ++ { ++ curwin->w_cursor = *trypos_wk; ++ goto retry; ++ } ++ trypos = NULL; ++ } ++ } ++ } ++ curwin->w_cursor = cursor_save; ++ return trypos; ++ } ++ ++ /* ++ * Find the matching '(', ignoring it if it is in a comment or before an ++ * unmatched {. ++ * Return NULL if no match found. ++ */ ++ static pos_T * ++ find_match_paren_after_brace (int ind_maxparen) /* XXX */ ++ { ++ pos_T *trypos = find_match_paren(ind_maxparen); ++ ++ if (trypos != NULL) ++ { ++ pos_T *tryposBrace = find_start_brace(); ++ ++ /* If both an unmatched '(' and '{' is found. Ignore the '(' ++ * position if the '{' is further down. */ ++ if (tryposBrace != NULL ++ && (trypos->lnum != tryposBrace->lnum ++ ? trypos->lnum < tryposBrace->lnum ++ : trypos->col < tryposBrace->col)) ++ trypos = NULL; ++ } ++ return trypos; ++ } ++ ++ /* ++ * Return ind_maxparen corrected for the difference in line number between the ++ * cursor position and "startpos". This makes sure that searching for a ++ * matching paren above the cursor line doesn't find a match because of ++ * looking a few lines further. ++ */ ++ static int ++ corr_ind_maxparen(pos_T *startpos) ++ { ++ long n = (long)startpos->lnum - (long)curwin->w_cursor.lnum; ++ ++ if (n > 0 && n < curbuf->b_ind_maxparen / 2) ++ return curbuf->b_ind_maxparen - (int)n; ++ return curbuf->b_ind_maxparen; ++ } ++ ++ /* ++ * Set w_cursor.col to the column number of the last unmatched ')' or '{' in ++ * line "l". "l" must point to the start of the line. ++ */ ++ static int ++ find_last_paren(char_u *l, int start, int end) ++ { ++ int i; ++ int retval = FALSE; ++ int open_count = 0; ++ ++ curwin->w_cursor.col = 0; /* default is start of line */ ++ ++ for (i = 0; l[i] != NUL; i++) ++ { ++ i = (int)(cin_skipcomment(l + i) - l); /* ignore parens in comments */ ++ i = (int)(skip_string(l + i) - l); /* ignore parens in quotes */ ++ if (l[i] == start) ++ ++open_count; ++ else if (l[i] == end) ++ { ++ if (open_count > 0) ++ --open_count; ++ else ++ { ++ curwin->w_cursor.col = i; ++ retval = TRUE; ++ } ++ } ++ } ++ return retval; ++ } ++ ++ /* ++ * Parse 'cinoptions' and set the values in "curbuf". ++ * Must be called when 'cinoptions', 'shiftwidth' and/or 'tabstop' changes. ++ */ ++ void ++ parse_cino(buf_T *buf) ++ { ++ char_u *p; ++ char_u *l; ++ char_u *digits; ++ int n; ++ int divider; ++ int fraction = 0; ++ int sw = (int)get_sw_value(buf); ++ ++ /* ++ * Set the default values. ++ */ ++ /* Spaces from a block's opening brace the prevailing indent for that ++ * block should be. */ ++ buf->b_ind_level = sw; ++ ++ /* Spaces from the edge of the line an open brace that's at the end of a ++ * line is imagined to be. */ ++ buf->b_ind_open_imag = 0; ++ ++ /* Spaces from the prevailing indent for a line that is not preceded by ++ * an opening brace. */ ++ buf->b_ind_no_brace = 0; ++ ++ /* Column where the first { of a function should be located }. */ ++ buf->b_ind_first_open = 0; ++ ++ /* Spaces from the prevailing indent a leftmost open brace should be ++ * located. */ ++ buf->b_ind_open_extra = 0; ++ ++ /* Spaces from the matching open brace (real location for one at the left ++ * edge; imaginary location from one that ends a line) the matching close ++ * brace should be located. */ ++ buf->b_ind_close_extra = 0; ++ ++ /* Spaces from the edge of the line an open brace sitting in the leftmost ++ * column is imagined to be. */ ++ buf->b_ind_open_left_imag = 0; ++ ++ /* Spaces jump labels should be shifted to the left if N is non-negative, ++ * otherwise the jump label will be put to column 1. */ ++ buf->b_ind_jump_label = -1; ++ ++ /* Spaces from the switch() indent a "case xx" label should be located. */ ++ buf->b_ind_case = sw; ++ ++ /* Spaces from the "case xx:" code after a switch() should be located. */ ++ buf->b_ind_case_code = sw; ++ ++ /* Lineup break at end of case in switch() with case label. */ ++ buf->b_ind_case_break = 0; ++ ++ /* Spaces from the class declaration indent a scope declaration label ++ * should be located. */ ++ buf->b_ind_scopedecl = sw; ++ ++ /* Spaces from the scope declaration label code should be located. */ ++ buf->b_ind_scopedecl_code = sw; ++ ++ /* Amount K&R-style parameters should be indented. */ ++ buf->b_ind_param = sw; ++ ++ /* Amount a function type spec should be indented. */ ++ buf->b_ind_func_type = sw; ++ ++ /* Amount a cpp base class declaration or constructor initialization ++ * should be indented. */ ++ buf->b_ind_cpp_baseclass = sw; ++ ++ /* additional spaces beyond the prevailing indent a continuation line ++ * should be located. */ ++ buf->b_ind_continuation = sw; ++ ++ /* Spaces from the indent of the line with an unclosed parentheses. */ ++ buf->b_ind_unclosed = sw * 2; ++ ++ /* Spaces from the indent of the line with an unclosed parentheses, which ++ * itself is also unclosed. */ ++ buf->b_ind_unclosed2 = sw; ++ ++ /* Suppress ignoring spaces from the indent of a line starting with an ++ * unclosed parentheses. */ ++ buf->b_ind_unclosed_noignore = 0; ++ ++ /* If the opening paren is the last nonwhite character on the line, and ++ * b_ind_unclosed_wrapped is nonzero, use this indent relative to the outer ++ * context (for very long lines). */ ++ buf->b_ind_unclosed_wrapped = 0; ++ ++ /* Suppress ignoring white space when lining up with the character after ++ * an unclosed parentheses. */ ++ buf->b_ind_unclosed_whiteok = 0; ++ ++ /* Indent a closing parentheses under the line start of the matching ++ * opening parentheses. */ ++ buf->b_ind_matching_paren = 0; ++ ++ /* Indent a closing parentheses under the previous line. */ ++ buf->b_ind_paren_prev = 0; ++ ++ /* Extra indent for comments. */ ++ buf->b_ind_comment = 0; ++ ++ /* Spaces from the comment opener when there is nothing after it. */ ++ buf->b_ind_in_comment = 3; ++ ++ /* Boolean: if non-zero, use b_ind_in_comment even if there is something ++ * after the comment opener. */ ++ buf->b_ind_in_comment2 = 0; ++ ++ /* Max lines to search for an open paren. */ ++ buf->b_ind_maxparen = 20; ++ ++ /* Max lines to search for an open comment. */ ++ buf->b_ind_maxcomment = 70; ++ ++ /* Handle braces for java code. */ ++ buf->b_ind_java = 0; ++ ++ /* Not to confuse JS object properties with labels. */ ++ buf->b_ind_js = 0; ++ ++ /* Handle blocked cases correctly. */ ++ buf->b_ind_keep_case_label = 0; ++ ++ /* Handle C++ namespace. */ ++ buf->b_ind_cpp_namespace = 0; ++ ++ /* Handle continuation lines containing conditions of if(), for() and ++ * while(). */ ++ buf->b_ind_if_for_while = 0; ++ ++ /* indentation for # comments */ ++ buf->b_ind_hash_comment = 0; ++ ++ /* Handle C++ extern "C" or "C++" */ ++ buf->b_ind_cpp_extern_c = 0; ++ ++ for (p = buf->b_p_cino; *p; ) ++ { ++ l = p++; ++ if (*p == '-') ++ ++p; ++ digits = p; /* remember where the digits start */ ++ n = getdigits(&p); ++ divider = 0; ++ if (*p == '.') /* ".5s" means a fraction */ ++ { ++ fraction = atol((char *)++p); ++ while (VIM_ISDIGIT(*p)) ++ { ++ ++p; ++ if (divider) ++ divider *= 10; ++ else ++ divider = 10; ++ } ++ } ++ if (*p == 's') /* "2s" means two times 'shiftwidth' */ ++ { ++ if (p == digits) ++ n = sw; /* just "s" is one 'shiftwidth' */ ++ else ++ { ++ n *= sw; ++ if (divider) ++ n += (sw * fraction + divider / 2) / divider; ++ } ++ ++p; ++ } ++ if (l[1] == '-') ++ n = -n; ++ ++ /* When adding an entry here, also update the default 'cinoptions' in ++ * doc/indent.txt, and add explanation for it! */ ++ switch (*l) ++ { ++ case '>': buf->b_ind_level = n; break; ++ case 'e': buf->b_ind_open_imag = n; break; ++ case 'n': buf->b_ind_no_brace = n; break; ++ case 'f': buf->b_ind_first_open = n; break; ++ case '{': buf->b_ind_open_extra = n; break; ++ case '}': buf->b_ind_close_extra = n; break; ++ case '^': buf->b_ind_open_left_imag = n; break; ++ case 'L': buf->b_ind_jump_label = n; break; ++ case ':': buf->b_ind_case = n; break; ++ case '=': buf->b_ind_case_code = n; break; ++ case 'b': buf->b_ind_case_break = n; break; ++ case 'p': buf->b_ind_param = n; break; ++ case 't': buf->b_ind_func_type = n; break; ++ case '/': buf->b_ind_comment = n; break; ++ case 'c': buf->b_ind_in_comment = n; break; ++ case 'C': buf->b_ind_in_comment2 = n; break; ++ case 'i': buf->b_ind_cpp_baseclass = n; break; ++ case '+': buf->b_ind_continuation = n; break; ++ case '(': buf->b_ind_unclosed = n; break; ++ case 'u': buf->b_ind_unclosed2 = n; break; ++ case 'U': buf->b_ind_unclosed_noignore = n; break; ++ case 'W': buf->b_ind_unclosed_wrapped = n; break; ++ case 'w': buf->b_ind_unclosed_whiteok = n; break; ++ case 'm': buf->b_ind_matching_paren = n; break; ++ case 'M': buf->b_ind_paren_prev = n; break; ++ case ')': buf->b_ind_maxparen = n; break; ++ case '*': buf->b_ind_maxcomment = n; break; ++ case 'g': buf->b_ind_scopedecl = n; break; ++ case 'h': buf->b_ind_scopedecl_code = n; break; ++ case 'j': buf->b_ind_java = n; break; ++ case 'J': buf->b_ind_js = n; break; ++ case 'l': buf->b_ind_keep_case_label = n; break; ++ case '#': buf->b_ind_hash_comment = n; break; ++ case 'N': buf->b_ind_cpp_namespace = n; break; ++ case 'k': buf->b_ind_if_for_while = n; break; ++ case 'E': buf->b_ind_cpp_extern_c = n; break; ++ } ++ if (*p == ',') ++ ++p; ++ } ++ } ++ ++ /* ++ * 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; ++ int amount; ++ int scope_amount; ++ int cur_amount = MAXCOL; ++ colnr_T col; ++ 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; ++ #define BRACE_IN_COL0 1 /* '{' is in column 0 */ ++ #define BRACE_AT_START 2 /* '{' is at start of line */ ++ #define BRACE_AT_END 3 /* '{' is at end of line */ ++ linenr_T ourscope; ++ char_u *l; ++ char_u *look; ++ char_u terminated; ++ int lookfor; ++ #define LOOKFOR_INITIAL 0 ++ #define LOOKFOR_IF 1 ++ #define LOOKFOR_DO 2 ++ #define LOOKFOR_CASE 3 ++ #define LOOKFOR_ANY 4 ++ #define LOOKFOR_TERM 5 ++ #define LOOKFOR_UNTERM 6 ++ #define LOOKFOR_SCOPEDECL 7 ++ #define LOOKFOR_NOBREAK 8 ++ #define LOOKFOR_CPP_BASECLASS 9 ++ #define LOOKFOR_ENUM_OR_INIT 10 ++ #define LOOKFOR_JS_KEY 11 ++ #define LOOKFOR_COMMA 12 ++ ++ int whilelevel; ++ linenr_T lnum; ++ int n; ++ int iscase; ++ int lookfor_break; ++ int lookfor_cpp_namespace = FALSE; ++ int cont_amount = 0; /* amount for continuation line */ ++ int original_line_islabel; ++ int added_to_amount = 0; ++ int js_cur_has_key = 0; ++ linenr_T raw_string_start = 0; ++ cpp_baseclass_cache_T cache_cpp_baseclass = { FALSE, { MAXLNUM, 0 } }; ++ ++ /* make a copy, value is changed below */ ++ int ind_continuation = curbuf->b_ind_continuation; ++ ++ /* 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; ++ ++ /* Get a copy of the current contents of the line. ++ * This is required, because only the most recent line obtained with ++ * ml_get is valid! */ ++ linecopy = vim_strsave(ml_get(cur_curpos.lnum)); ++ if (linecopy == NULL) ++ return 0; ++ ++ /* ++ * In insert mode and the cursor is on a ')' truncate the line at the ++ * cursor position. We don't want to line up with the matching '(' when ++ * inserting new stuff. ++ * For unknown reasons the cursor might be past the end of the line, thus ++ * check for that. ++ */ ++ if ((State & INSERT) ++ && curwin->w_cursor.col < (colnr_T)STRLEN(linecopy) ++ && linecopy[curwin->w_cursor.col] == ')') ++ linecopy[curwin->w_cursor.col] = NUL; ++ ++ theline = skipwhite(linecopy); ++ ++ /* move the cursor to the start of the line */ ++ ++ curwin->w_cursor.col = 0; ++ ++ 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_POS(*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; ++ char_u lead_start[COM_MAX_LEN]; /* start-comment string */ ++ char_u lead_middle[COM_MAX_LEN]; /* middle-comment string */ ++ char_u lead_end[COM_MAX_LEN]; /* end-comment string */ ++ char_u *p; ++ int start_align = 0; ++ int start_off = 0; ++ 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; ++ ++ p = curbuf->b_p_com; ++ while (*p != NUL) ++ { ++ int align = 0; ++ int off = 0; ++ int what = 0; ++ ++ while (*p != NUL && *p != ':') ++ { ++ if (*p == COM_START || *p == COM_END || *p == COM_MIDDLE) ++ what = *p++; ++ else if (*p == COM_LEFT || *p == COM_RIGHT) ++ align = *p++; ++ else if (VIM_ISDIGIT(*p) || *p == '-') ++ off = getdigits(&p); ++ else ++ ++p; ++ } ++ ++ if (*p == ':') ++ ++p; ++ (void)copy_option_part(&p, lead_end, COM_MAX_LEN, ","); ++ if (what == COM_START) ++ { ++ STRCPY(lead_start, lead_end); ++ lead_start_len = (int)STRLEN(lead_start); ++ start_off = off; ++ start_align = align; ++ } ++ else if (what == COM_MIDDLE) ++ { ++ STRCPY(lead_middle, lead_end); ++ lead_middle_len = (int)STRLEN(lead_middle); ++ } ++ else if (what == COM_END) ++ { ++ /* If our line starts with the middle comment string, line it ++ * up with the comment opener per the 'comments' option. */ ++ if (STRNCMP(theline, lead_middle, lead_middle_len) == 0 ++ && STRNCMP(theline, lead_end, STRLEN(lead_end)) != 0) ++ { ++ done = TRUE; ++ if (curwin->w_cursor.lnum > 1) ++ { ++ /* If the start comment string matches in the previous ++ * line, use the indent of that line plus offset. If ++ * the middle comment string matches in the previous ++ * line, use the indent of that line. XXX */ ++ look = skipwhite(ml_get(curwin->w_cursor.lnum - 1)); ++ if (STRNCMP(look, lead_start, lead_start_len) == 0) ++ amount = get_indent_lnum(curwin->w_cursor.lnum - 1); ++ else if (STRNCMP(look, lead_middle, ++ lead_middle_len) == 0) ++ { ++ amount = get_indent_lnum(curwin->w_cursor.lnum - 1); ++ break; ++ } ++ /* 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; ++ } ++ if (start_off != 0) ++ amount += start_off; ++ else if (start_align == COM_RIGHT) ++ amount += vim_strsize(lead_start) ++ - vim_strsize(lead_middle); ++ break; ++ } ++ ++ /* If our line starts with the end comment string, line it up ++ * with the middle comment */ ++ if (STRNCMP(theline, lead_middle, lead_middle_len) != 0 ++ && STRNCMP(theline, lead_end, STRLEN(lead_end)) == 0) ++ { ++ amount = get_indent_lnum(curwin->w_cursor.lnum - 1); ++ /* XXX */ ++ if (off != 0) ++ amount += off; ++ else if (align == COM_RIGHT) ++ amount += vim_strsize(lead_start) ++ - vim_strsize(lead_middle); ++ done = TRUE; ++ break; ++ } ++ } ++ } ++ ++ /* If our line starts with an asterisk, line up with the ++ * asterisk in the comment opener; otherwise, line up ++ * with the first character of the comment text. ++ */ ++ if (done) ++ ; ++ else if (theline[0] == '*') ++ amount += 1; ++ else ++ { ++ /* ++ * If we are more than one line away from the comment opener, take ++ * the indent of the previous non-empty line. If 'cino' has "CO" ++ * and we are just below the comment opener and there are any ++ * white characters after it line up with the text after it; ++ * 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; ++ amount = get_indent_lnum(lnum); /* XXX */ ++ break; ++ } ++ if (amount == -1) /* use the comment opener */ ++ { ++ 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) ++ { ++ if (trypos != NULL && tryposBrace != NULL) ++ { ++ /* Both an unmatched '(' and '{' is found. Use the one which is ++ * closer to the current cursor position, set the other to NULL. */ ++ if (trypos->lnum != tryposBrace->lnum ++ ? trypos->lnum < tryposBrace->lnum ++ : trypos->col < tryposBrace->col) ++ trypos = NULL; ++ else ++ tryposBrace = NULL; ++ } ++ ++ if (trypos != NULL) ++ { ++ /* ++ * If the matching paren is more than one line away, use the indent of ++ * a previous non-empty line that matches the same paren. ++ */ ++ if (theline[0] == ')' && curbuf->b_ind_paren_prev) ++ { ++ /* Line up with the start of the matching paren line. */ ++ amount = get_indent_lnum(curwin->w_cursor.lnum - 1); /* XXX */ ++ } ++ else ++ { ++ amount = -1; ++ our_paren_pos = *trypos; ++ for (lnum = cur_curpos.lnum - 1; lnum > our_paren_pos.lnum; --lnum) ++ { ++ l = skipwhite(ml_get(lnum)); ++ if (cin_nocode(l)) /* skip comment lines */ ++ continue; ++ if (cin_ispreproc_cont(&l, &lnum, &amount)) ++ continue; /* ignore #define, #if, etc. */ ++ curwin->w_cursor.lnum = lnum; ++ ++ /* Skip a comment or raw string. XXX */ ++ if ((trypos = ind_find_start_CORS(NULL)) != NULL) ++ { ++ lnum = trypos->lnum + 1; ++ continue; ++ } ++ ++ /* XXX */ ++ if ((trypos = find_match_paren( ++ corr_ind_maxparen(&cur_curpos))) != NULL ++ && trypos->lnum == our_paren_pos.lnum ++ && trypos->col == our_paren_pos.col) ++ { ++ amount = get_indent_lnum(lnum); /* XXX */ ++ ++ if (theline[0] == ')') ++ { ++ if (our_paren_pos.lnum != lnum ++ && cur_amount > amount) ++ cur_amount = amount; ++ amount = -1; ++ } ++ break; ++ } ++ } ++ } ++ ++ /* ++ * Line up with line where the matching paren is. XXX ++ * If the line starts with a '(' or the indent for unclosed ++ * parentheses is zero, line up with the unclosed parentheses. ++ */ ++ if (amount == -1) ++ { ++ int ignore_paren_col = 0; ++ int is_if_for_while = 0; ++ ++ if (curbuf->b_ind_if_for_while) ++ { ++ /* Look for the outermost opening parenthesis on this line ++ * and check whether it belongs to an "if", "for" or "while". */ ++ ++ pos_T cursor_save = curwin->w_cursor; ++ pos_T outermost; ++ char_u *line; ++ ++ trypos = &our_paren_pos; ++ do { ++ outermost = *trypos; ++ curwin->w_cursor.lnum = outermost.lnum; ++ curwin->w_cursor.col = outermost.col; ++ ++ trypos = find_match_paren(curbuf->b_ind_maxparen); ++ } while (trypos && trypos->lnum == outermost.lnum); ++ ++ curwin->w_cursor = cursor_save; ++ ++ line = ml_get(outermost.lnum); ++ ++ is_if_for_while = ++ cin_is_if_for_while_before_offset(line, &outermost.col); ++ } ++ ++ amount = skip_label(our_paren_pos.lnum, &look); ++ look = skipwhite(look); ++ if (*look == '(') ++ { ++ linenr_T save_lnum = curwin->w_cursor.lnum; ++ char_u *line; ++ int look_col; ++ ++ /* Ignore a '(' in front of the line that has a match before ++ * our matching '('. */ ++ curwin->w_cursor.lnum = our_paren_pos.lnum; ++ line = ml_get_curline(); ++ look_col = (int)(look - line); ++ curwin->w_cursor.col = look_col + 1; ++ if ((trypos = findmatchlimit(NULL, ')', 0, ++ curbuf->b_ind_maxparen)) ++ != NULL ++ && trypos->lnum == our_paren_pos.lnum ++ && trypos->col < our_paren_pos.col) ++ ignore_paren_col = trypos->col + 1; ++ ++ curwin->w_cursor.lnum = save_lnum; ++ look = ml_get(our_paren_pos.lnum) + look_col; ++ } ++ if (theline[0] == ')' || (curbuf->b_ind_unclosed == 0 ++ && is_if_for_while == 0) ++ || (!curbuf->b_ind_unclosed_noignore && *look == '(' ++ && ignore_paren_col == 0)) ++ { ++ /* ++ * If we're looking at a close paren, line up right there; ++ * otherwise, line up with the next (non-white) character. ++ * When b_ind_unclosed_wrapped is set and the matching paren is ++ * the last nonwhite character of the line, use either the ++ * indent of the current line or the indentation of the next ++ * outer paren and add b_ind_unclosed_wrapped (for very long ++ * lines). ++ */ ++ if (theline[0] != ')') ++ { ++ cur_amount = MAXCOL; ++ l = ml_get(our_paren_pos.lnum); ++ if (curbuf->b_ind_unclosed_wrapped ++ && cin_ends_in(l, (char_u *)"(", NULL)) ++ { ++ /* look for opening unmatched paren, indent one level ++ * for each additional level */ ++ n = 1; ++ for (col = 0; col < our_paren_pos.col; ++col) ++ { ++ switch (l[col]) ++ { ++ case '(': ++ case '{': ++n; ++ break; ++ ++ case ')': ++ case '}': if (n > 1) ++ --n; ++ break; ++ } ++ } ++ ++ our_paren_pos.col = 0; ++ amount += n * curbuf->b_ind_unclosed_wrapped; ++ } ++ else if (curbuf->b_ind_unclosed_whiteok) ++ our_paren_pos.col++; ++ else ++ { ++ col = our_paren_pos.col + 1; ++ while (VIM_ISWHITE(l[col])) ++ col++; ++ if (l[col] != NUL) /* In case of trailing space */ ++ our_paren_pos.col = col; ++ else ++ our_paren_pos.col++; ++ } ++ } ++ ++ /* ++ * Find how indented the paren is, or the character after it ++ * if we did the above "if". ++ */ ++ if (our_paren_pos.col > 0) ++ { ++ getvcol(curwin, &our_paren_pos, &col, NULL, NULL); ++ if (cur_amount > (int)col) ++ cur_amount = col; ++ } ++ } ++ ++ if (theline[0] == ')' && curbuf->b_ind_matching_paren) ++ { ++ /* Line up with the start of the matching paren line. */ ++ } ++ else if ((curbuf->b_ind_unclosed == 0 && is_if_for_while == 0) ++ || (!curbuf->b_ind_unclosed_noignore ++ && *look == '(' && ignore_paren_col == 0)) ++ { ++ if (cur_amount != MAXCOL) ++ amount = cur_amount; ++ } ++ else ++ { ++ /* Add b_ind_unclosed2 for each '(' before our matching one, ++ * but ignore (void) before the line (ignore_paren_col). */ ++ col = our_paren_pos.col; ++ while ((int)our_paren_pos.col > ignore_paren_col) ++ { ++ --our_paren_pos.col; ++ switch (*ml_get_pos(&our_paren_pos)) ++ { ++ case '(': amount += curbuf->b_ind_unclosed2; ++ col = our_paren_pos.col; ++ break; ++ case ')': amount -= curbuf->b_ind_unclosed2; ++ col = MAXCOL; ++ break; ++ } ++ } ++ ++ /* Use b_ind_unclosed once, when the first '(' is not inside ++ * braces */ ++ if (col == MAXCOL) ++ amount += curbuf->b_ind_unclosed; ++ else ++ { ++ curwin->w_cursor.lnum = our_paren_pos.lnum; ++ curwin->w_cursor.col = col; ++ if (find_match_paren_after_brace(curbuf->b_ind_maxparen) ++ != NULL) ++ amount += curbuf->b_ind_unclosed2; ++ else ++ { ++ if (is_if_for_while) ++ amount += curbuf->b_ind_if_for_while; ++ else ++ amount += curbuf->b_ind_unclosed; ++ } ++ } ++ /* ++ * For a line starting with ')' use the minimum of the two ++ * positions, to avoid giving it more indent than the previous ++ * lines: ++ * func_long_name( if (x ++ * arg && yy ++ * ) ^ not here ) ^ not here ++ */ ++ if (cur_amount < amount) ++ amount = cur_amount; ++ } ++ } ++ ++ /* add extra indent for a comment */ ++ if (cin_iscomment(theline)) ++ amount += curbuf->b_ind_comment; ++ } ++ else ++ { ++ /* ++ * We are inside braces, there is a { before this line at the position ++ * stored in tryposBrace. ++ * 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); ++ ++ /* ++ * Now figure out how indented the line is in general. ++ * If the brace was at the start of the line, we use that; ++ * otherwise, check out the indentation of the line as ++ * a whole and then add the "imaginary indent" to that. ++ */ ++ look = skipwhite(start); ++ if (*look == '{') ++ { ++ getvcol(curwin, trypos, &col, NULL, NULL); ++ amount = col; ++ if (*start == '{') ++ start_brace = BRACE_IN_COL0; ++ else ++ start_brace = BRACE_AT_START; ++ } ++ else ++ { ++ /* That opening brace might have been on a continuation ++ * line. if so, find the start of the line. */ ++ curwin->w_cursor.lnum = ourscope; ++ ++ /* Position the cursor over the rightmost paren, so that ++ * matching it will take us back to the start of the line. */ ++ lnum = ourscope; ++ if (find_last_paren(start, '(', ')') ++ && (trypos = find_match_paren(curbuf->b_ind_maxparen)) ++ != NULL) ++ lnum = trypos->lnum; ++ ++ /* It could have been something like ++ * case 1: if (asdf && ++ * ldfd) { ++ * } ++ */ ++ if ((curbuf->b_ind_js || curbuf->b_ind_keep_case_label) ++ && cin_iscase(skipwhite(ml_get_curline()), FALSE)) ++ amount = get_indent(); ++ else if (curbuf->b_ind_js) ++ amount = get_indent_lnum(lnum); ++ else ++ amount = skip_label(lnum, &l); ++ ++ start_brace = BRACE_AT_END; ++ } ++ ++ /* For Javascript check if the line starts with "key:". */ ++ if (curbuf->b_ind_js) ++ js_cur_has_key = cin_has_js_key(theline); ++ ++ /* ++ * If we're looking at a closing brace, that's where ++ * we want to be. otherwise, add the amount of room ++ * that an indent is supposed to be. ++ */ ++ if (theline[0] == '}') ++ { ++ /* ++ * they may want closing braces to line up with something ++ * other than the open brace. indulge them, if so. ++ */ ++ amount += curbuf->b_ind_close_extra; ++ } ++ else ++ { ++ /* ++ * If we're looking at an "else", try to find an "if" ++ * to match it with. ++ * If we're looking at a "while", try to find a "do" ++ * to match it with. ++ */ ++ lookfor = LOOKFOR_INITIAL; ++ if (cin_iselse(theline)) ++ lookfor = LOOKFOR_IF; ++ else if (cin_iswhileofdo(theline, cur_curpos.lnum)) /* XXX */ ++ lookfor = LOOKFOR_DO; ++ if (lookfor != LOOKFOR_INITIAL) ++ { ++ curwin->w_cursor.lnum = cur_curpos.lnum; ++ if (find_match(lookfor, ourscope) == OK) ++ { ++ amount = get_indent(); /* XXX */ ++ goto theend; ++ } ++ } ++ ++ /* ++ * We get here if we are not on an "while-of-do" or "else" (or ++ * failed to find a matching "if"). ++ * Search backwards for something to line up with. ++ * First set amount for when we don't find anything. ++ */ ++ ++ /* ++ * if the '{' is _really_ at the left margin, use the imaginary ++ * location of a left-margin brace. Otherwise, correct the ++ * location for b_ind_open_extra. ++ */ ++ ++ if (start_brace == BRACE_IN_COL0) /* '{' is in column 0 */ ++ { ++ amount = curbuf->b_ind_open_left_imag; ++ lookfor_cpp_namespace = TRUE; ++ } ++ else if (start_brace == BRACE_AT_START && ++ lookfor_cpp_namespace) /* '{' is at start */ ++ { ++ ++ lookfor_cpp_namespace = TRUE; ++ } ++ else ++ { ++ if (start_brace == BRACE_AT_END) /* '{' is at end of line */ ++ { ++ amount += curbuf->b_ind_open_imag; ++ ++ l = skipwhite(ml_get_curline()); ++ if (cin_is_cpp_namespace(l)) ++ amount += curbuf->b_ind_cpp_namespace; ++ else if (cin_is_cpp_extern_c(l)) ++ amount += curbuf->b_ind_cpp_extern_c; ++ } ++ else ++ { ++ /* Compensate for adding b_ind_open_extra later. */ ++ amount -= curbuf->b_ind_open_extra; ++ if (amount < 0) ++ amount = 0; ++ } ++ } ++ ++ lookfor_break = FALSE; ++ ++ if (cin_iscase(theline, FALSE)) /* it's a switch() label */ ++ { ++ lookfor = LOOKFOR_CASE; /* find a previous switch() label */ ++ amount += curbuf->b_ind_case; ++ } ++ else if (cin_isscopedecl(theline)) /* private:, ... */ ++ { ++ lookfor = LOOKFOR_SCOPEDECL; /* class decl is this block */ ++ amount += curbuf->b_ind_scopedecl; ++ } ++ else ++ { ++ if (curbuf->b_ind_case_break && cin_isbreak(theline)) ++ /* break; ... */ ++ lookfor_break = TRUE; ++ ++ lookfor = LOOKFOR_INITIAL; ++ /* b_ind_level from start of block */ ++ amount += curbuf->b_ind_level; ++ } ++ scope_amount = amount; ++ whilelevel = 0; ++ ++ /* ++ * Search backwards. If we find something we recognize, line up ++ * with that. ++ * ++ * If we're looking at an open brace, indent ++ * the usual amount relative to the conditional ++ * that opens the block. ++ */ ++ curwin->w_cursor = cur_curpos; ++ for (;;) ++ { ++ curwin->w_cursor.lnum--; ++ curwin->w_cursor.col = 0; ++ ++ /* ++ * If we went all the way back to the start of our scope, line ++ * up with it. ++ */ ++ if (curwin->w_cursor.lnum <= ourscope) ++ { ++ /* We reached end of scope: ++ * If looking for a enum or structure initialization ++ * go further back: ++ * If it is an initializer (enum xxx or xxx =), then ++ * don't add ind_continuation, otherwise it is a variable ++ * declaration: ++ * int x, ++ * here; <-- add ind_continuation ++ */ ++ if (lookfor == LOOKFOR_ENUM_OR_INIT) ++ { ++ if (curwin->w_cursor.lnum == 0 ++ || curwin->w_cursor.lnum ++ < ourscope - curbuf->b_ind_maxparen) ++ { ++ /* nothing found (abuse curbuf->b_ind_maxparen as ++ * limit) assume terminated line (i.e. a variable ++ * initialization) */ ++ if (cont_amount > 0) ++ amount = cont_amount; ++ else if (!curbuf->b_ind_js) ++ amount += ind_continuation; ++ break; ++ } ++ ++ 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(NULL); ++ if (trypos != NULL) ++ { ++ curwin->w_cursor.lnum = trypos->lnum + 1; ++ curwin->w_cursor.col = 0; ++ continue; ++ } ++ ++ /* ++ * Skip preprocessor directives and blank lines. ++ */ ++ if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum, ++ &amount)) ++ continue; ++ ++ if (cin_nocode(l)) ++ continue; ++ ++ terminated = cin_isterminated(l, FALSE, TRUE); ++ ++ /* ++ * If we are at top level and the line looks like a ++ * function declaration, we are done ++ * (it's a variable declaration). ++ */ ++ if (start_brace != BRACE_IN_COL0 ++ || !cin_isfuncdecl(&l, curwin->w_cursor.lnum, 0)) ++ { ++ /* if the line is terminated with another ',' ++ * it is a continued variable initialization. ++ * don't add extra indent. ++ * TODO: does not work, if a function ++ * declaration is split over multiple lines: ++ * cin_isfuncdecl returns FALSE then. ++ */ ++ if (terminated == ',') ++ break; ++ ++ /* if it es a enum declaration or an assignment, ++ * we are done. ++ */ ++ if (terminated != ';' && cin_isinit()) ++ break; ++ ++ /* nothing useful found */ ++ if (terminated == 0 || terminated == '{') ++ continue; ++ } ++ ++ if (terminated != ';') ++ { ++ /* Skip parens and braces. Position the cursor ++ * over the rightmost paren, so that matching it ++ * will take us back to the start of the line. ++ */ /* XXX */ ++ trypos = NULL; ++ if (find_last_paren(l, '(', ')')) ++ trypos = find_match_paren( ++ curbuf->b_ind_maxparen); ++ ++ if (trypos == NULL && find_last_paren(l, '{', '}')) ++ trypos = find_start_brace(); ++ ++ if (trypos != NULL) ++ { ++ curwin->w_cursor.lnum = trypos->lnum + 1; ++ curwin->w_cursor.col = 0; ++ continue; ++ } ++ } ++ ++ /* it's a variable declaration, add indentation ++ * like in ++ * int a, ++ * b; ++ */ ++ if (cont_amount > 0) ++ amount = cont_amount; ++ else ++ amount += ind_continuation; ++ } ++ else if (lookfor == LOOKFOR_UNTERM) ++ { ++ if (cont_amount > 0) ++ amount = cont_amount; ++ else ++ amount += ind_continuation; ++ } ++ else ++ { ++ if (lookfor != LOOKFOR_TERM ++ && lookfor != LOOKFOR_CPP_BASECLASS ++ && lookfor != LOOKFOR_COMMA) ++ { ++ amount = scope_amount; ++ if (theline[0] == '{') ++ { ++ amount += curbuf->b_ind_open_extra; ++ added_to_amount = curbuf->b_ind_open_extra; ++ } ++ } ++ ++ if (lookfor_cpp_namespace) ++ { ++ /* ++ * Looking for C++ namespace, need to look further ++ * back. ++ */ ++ if (curwin->w_cursor.lnum == ourscope) ++ continue; ++ ++ if (curwin->w_cursor.lnum == 0 ++ || curwin->w_cursor.lnum ++ < ourscope - FIND_NAMESPACE_LIM) ++ break; ++ ++ 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(NULL); ++ if (trypos != NULL) ++ { ++ curwin->w_cursor.lnum = trypos->lnum + 1; ++ curwin->w_cursor.col = 0; ++ continue; ++ } ++ ++ /* Skip preprocessor directives and blank lines. */ ++ if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum, ++ &amount)) ++ continue; ++ ++ /* Finally the actual check for "namespace". */ ++ if (cin_is_cpp_namespace(l)) ++ { ++ amount += curbuf->b_ind_cpp_namespace ++ - added_to_amount; ++ break; ++ } ++ else if (cin_is_cpp_extern_c(l)) ++ { ++ amount += curbuf->b_ind_cpp_extern_c ++ - added_to_amount; ++ break; ++ } ++ ++ if (cin_nocode(l)) ++ continue; ++ } ++ } ++ break; ++ } ++ ++ /* ++ * If we're in a comment or raw string now, skip to the start ++ * of it. ++ */ /* XXX */ ++ if ((trypos = ind_find_start_CORS(&raw_string_start)) != NULL) ++ { ++ curwin->w_cursor.lnum = trypos->lnum + 1; ++ curwin->w_cursor.col = 0; ++ continue; ++ } ++ ++ l = ml_get_curline(); ++ ++ /* ++ * If this is a switch() label, may line up relative to that. ++ * If this is a C++ scope declaration, do the same. ++ */ ++ iscase = cin_iscase(l, FALSE); ++ if (iscase || cin_isscopedecl(l)) ++ { ++ /* we are only looking for cpp base class ++ * declaration/initialization any longer */ ++ if (lookfor == LOOKFOR_CPP_BASECLASS) ++ break; ++ ++ /* When looking for a "do" we are not interested in ++ * labels. */ ++ if (whilelevel > 0) ++ continue; ++ ++ /* ++ * case xx: ++ * c = 99 + <- this indent plus continuation ++ *-> here; ++ */ ++ if (lookfor == LOOKFOR_UNTERM ++ || lookfor == LOOKFOR_ENUM_OR_INIT) ++ { ++ if (cont_amount > 0) ++ amount = cont_amount; ++ else ++ amount += ind_continuation; ++ break; ++ } ++ ++ /* ++ * case xx: <- line up with this case ++ * x = 333; ++ * case yy: ++ */ ++ if ( (iscase && lookfor == LOOKFOR_CASE) ++ || (iscase && lookfor_break) ++ || (!iscase && lookfor == LOOKFOR_SCOPEDECL)) ++ { ++ /* ++ * Check that this case label is not for another ++ * switch() ++ */ /* XXX */ ++ if ((trypos = find_start_brace()) == NULL ++ || trypos->lnum == ourscope) ++ { ++ amount = get_indent(); /* XXX */ ++ break; ++ } ++ continue; ++ } ++ ++ n = get_indent_nolabel(curwin->w_cursor.lnum); /* XXX */ ++ ++ /* ++ * case xx: if (cond) <- line up with this if ++ * y = y + 1; ++ * -> s = 99; ++ * ++ * case xx: ++ * if (cond) <- line up with this line ++ * y = y + 1; ++ * -> s = 99; ++ */ ++ if (lookfor == LOOKFOR_TERM) ++ { ++ if (n) ++ amount = n; ++ ++ if (!lookfor_break) ++ break; ++ } ++ ++ /* ++ * case xx: x = x + 1; <- line up with this x ++ * -> y = y + 1; ++ * ++ * case xx: if (cond) <- line up with this if ++ * -> y = y + 1; ++ */ ++ if (n) ++ { ++ amount = n; ++ l = after_label(ml_get_curline()); ++ if (l != NULL && cin_is_cinword(l)) ++ { ++ if (theline[0] == '{') ++ amount += curbuf->b_ind_open_extra; ++ else ++ amount += curbuf->b_ind_level ++ + curbuf->b_ind_no_brace; ++ } ++ break; ++ } ++ ++ /* ++ * Try to get the indent of a statement before the switch ++ * label. If nothing is found, line up relative to the ++ * switch label. ++ * break; <- may line up with this line ++ * case xx: ++ * -> y = 1; ++ */ ++ scope_amount = get_indent() + (iscase /* XXX */ ++ ? curbuf->b_ind_case_code ++ : curbuf->b_ind_scopedecl_code); ++ lookfor = curbuf->b_ind_case_break ++ ? LOOKFOR_NOBREAK : LOOKFOR_ANY; ++ continue; ++ } ++ ++ /* ++ * Looking for a switch() label or C++ scope declaration, ++ * ignore other lines, skip {}-blocks. ++ */ ++ if (lookfor == LOOKFOR_CASE || lookfor == LOOKFOR_SCOPEDECL) ++ { ++ if (find_last_paren(l, '{', '}') ++ && (trypos = find_start_brace()) != NULL) ++ { ++ curwin->w_cursor.lnum = trypos->lnum + 1; ++ curwin->w_cursor.col = 0; ++ } ++ continue; ++ } ++ ++ /* ++ * Ignore jump labels with nothing after them. ++ */ ++ if (!curbuf->b_ind_js && cin_islabel()) ++ { ++ l = after_label(ml_get_curline()); ++ if (l == NULL || cin_nocode(l)) ++ continue; ++ } ++ ++ /* ++ * Ignore #defines, #if, etc. ++ * Ignore comment and empty lines. ++ * (need to get the line again, cin_islabel() may have ++ * unlocked it) ++ */ ++ l = ml_get_curline(); ++ if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum, &amount) ++ || cin_nocode(l)) ++ continue; ++ ++ /* ++ * Are we at the start of a cpp base class declaration or ++ * constructor initialization? ++ */ /* XXX */ ++ n = FALSE; ++ if (lookfor != LOOKFOR_TERM && curbuf->b_ind_cpp_baseclass > 0) ++ { ++ n = cin_is_cpp_baseclass(&cache_cpp_baseclass); ++ l = ml_get_curline(); ++ } ++ if (n) ++ { ++ if (lookfor == LOOKFOR_UNTERM) ++ { ++ if (cont_amount > 0) ++ amount = cont_amount; ++ else ++ amount += ind_continuation; ++ } ++ else if (theline[0] == '{') ++ { ++ /* Need to find start of the declaration. */ ++ lookfor = LOOKFOR_UNTERM; ++ ind_continuation = 0; ++ continue; ++ } ++ else ++ /* XXX */ ++ amount = get_baseclass_amount( ++ cache_cpp_baseclass.lpos.col); ++ break; ++ } ++ else if (lookfor == LOOKFOR_CPP_BASECLASS) ++ { ++ /* only look, whether there is a cpp base class ++ * declaration or initialization before the opening brace. ++ */ ++ if (cin_isterminated(l, TRUE, FALSE)) ++ break; ++ else ++ continue; ++ } ++ ++ /* ++ * What happens next depends on the line being terminated. ++ * If terminated with a ',' only consider it terminating if ++ * there is another unterminated statement behind, eg: ++ * 123, ++ * sizeof ++ * here ++ * Otherwise check whether it is a enumeration or structure ++ * initialisation (not indented) or a variable declaration ++ * (indented). ++ */ ++ terminated = cin_isterminated(l, FALSE, TRUE); ++ ++ if (js_cur_has_key) ++ { ++ js_cur_has_key = 0; /* only check the first line */ ++ if (curbuf->b_ind_js && terminated == ',') ++ { ++ /* For Javascript we might be inside an object: ++ * key: something, <- align with this ++ * key: something ++ * or: ++ * key: something + <- align with this ++ * something, ++ * key: something ++ */ ++ lookfor = LOOKFOR_JS_KEY; ++ } ++ } ++ if (lookfor == LOOKFOR_JS_KEY && cin_has_js_key(l)) ++ { ++ amount = get_indent(); ++ break; ++ } ++ if (lookfor == LOOKFOR_COMMA) ++ { ++ if (tryposBrace != NULL && tryposBrace->lnum ++ >= curwin->w_cursor.lnum) ++ break; ++ if (terminated == ',') ++ /* line below current line is the one that starts a ++ * (possibly broken) line ending in a comma. */ ++ break; ++ else ++ { ++ amount = get_indent(); ++ if (curwin->w_cursor.lnum - 1 == ourscope) ++ /* line above is start of the scope, thus current ++ * line is the one that stars a (possibly broken) ++ * line ending in a comma. */ ++ break; ++ } ++ } ++ ++ if (terminated == 0 || (lookfor != LOOKFOR_UNTERM ++ && terminated == ',')) ++ { ++ if (lookfor != LOOKFOR_ENUM_OR_INIT && ++ (*skipwhite(l) == '[' || l[STRLEN(l) - 1] == '[')) ++ amount += ind_continuation; ++ /* ++ * if we're in the middle of a paren thing, ++ * go back to the line that starts it so ++ * we can get the right prevailing indent ++ * if ( foo && ++ * bar ) ++ */ ++ /* ++ * Position the cursor over the rightmost paren, so that ++ * matching it will take us back to the start of the line. ++ * Ignore a match before the start of the block. ++ */ ++ (void)find_last_paren(l, '(', ')'); ++ trypos = find_match_paren(corr_ind_maxparen(&cur_curpos)); ++ if (trypos != NULL && (trypos->lnum < tryposBrace->lnum ++ || (trypos->lnum == tryposBrace->lnum ++ && trypos->col < tryposBrace->col))) ++ trypos = NULL; ++ ++ /* ++ * If we are looking for ',', we also look for matching ++ * braces. ++ */ ++ if (trypos == NULL && terminated == ',' ++ && find_last_paren(l, '{', '}')) ++ trypos = find_start_brace(); ++ ++ if (trypos != NULL) ++ { ++ /* ++ * Check if we are on a case label now. This is ++ * handled above. ++ * case xx: if ( asdf && ++ * asdf) ++ */ ++ curwin->w_cursor = *trypos; ++ l = ml_get_curline(); ++ if (cin_iscase(l, FALSE) || cin_isscopedecl(l)) ++ { ++ ++curwin->w_cursor.lnum; ++ curwin->w_cursor.col = 0; ++ continue; ++ } ++ } ++ ++ /* ++ * Skip over continuation lines to find the one to get the ++ * indent from ++ * char *usethis = "bla\ ++ * bla", ++ * here; ++ */ ++ if (terminated == ',') ++ { ++ while (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; ++ } ++ } ++ ++ /* ++ * Get indent and pointer to text for current line, ++ * ignoring any jump label. XXX ++ */ ++ if (curbuf->b_ind_js) ++ cur_amount = get_indent(); ++ else ++ cur_amount = skip_label(curwin->w_cursor.lnum, &l); ++ /* ++ * If this is just above the line we are indenting, and it ++ * starts with a '{', line it up with this line. ++ * while (not) ++ * -> { ++ * } ++ */ ++ if (terminated != ',' && lookfor != LOOKFOR_TERM ++ && theline[0] == '{') ++ { ++ amount = cur_amount; ++ /* ++ * Only add b_ind_open_extra when the current line ++ * doesn't start with a '{', which must have a match ++ * in the same line (scope is the same). Probably: ++ * { 1, 2 }, ++ * -> { 3, 4 } ++ */ ++ if (*skipwhite(l) != '{') ++ amount += curbuf->b_ind_open_extra; ++ ++ if (curbuf->b_ind_cpp_baseclass && !curbuf->b_ind_js) ++ { ++ /* have to look back, whether it is a cpp base ++ * class declaration or initialization */ ++ lookfor = LOOKFOR_CPP_BASECLASS; ++ continue; ++ } ++ break; ++ } ++ ++ /* ++ * Check if we are after an "if", "while", etc. ++ * Also allow " } else". ++ */ ++ if (cin_is_cinword(l) || cin_iselse(skipwhite(l))) ++ { ++ /* ++ * Found an unterminated line after an if (), line up ++ * with the last one. ++ * if (cond) ++ * 100 + ++ * -> here; ++ */ ++ if (lookfor == LOOKFOR_UNTERM ++ || lookfor == LOOKFOR_ENUM_OR_INIT) ++ { ++ if (cont_amount > 0) ++ amount = cont_amount; ++ else ++ amount += ind_continuation; ++ break; ++ } ++ ++ /* ++ * If this is just above the line we are indenting, we ++ * are finished. ++ * while (not) ++ * -> here; ++ * Otherwise this indent can be used when the line ++ * before this is terminated. ++ * yyy; ++ * if (stat) ++ * while (not) ++ * xxx; ++ * -> here; ++ */ ++ amount = cur_amount; ++ if (theline[0] == '{') ++ amount += curbuf->b_ind_open_extra; ++ if (lookfor != LOOKFOR_TERM) ++ { ++ amount += curbuf->b_ind_level ++ + curbuf->b_ind_no_brace; ++ break; ++ } ++ ++ /* ++ * Special trick: when expecting the while () after a ++ * do, line up with the while() ++ * do ++ * x = 1; ++ * -> here ++ */ ++ l = skipwhite(ml_get_curline()); ++ if (cin_isdo(l)) ++ { ++ if (whilelevel == 0) ++ break; ++ --whilelevel; ++ } ++ ++ /* ++ * When searching for a terminated line, don't use the ++ * one between the "if" and the matching "else". ++ * Need to use the scope of this "else". XXX ++ * If whilelevel != 0 continue looking for a "do {". ++ */ ++ if (cin_iselse(l) && whilelevel == 0) ++ { ++ /* If we're looking at "} else", let's make sure we ++ * find the opening brace of the enclosing scope, ++ * not the one from "if () {". */ ++ if (*l == '}') ++ curwin->w_cursor.col = ++ (colnr_T)(l - ml_get_curline()) + 1; ++ ++ if ((trypos = find_start_brace()) == NULL ++ || find_match(LOOKFOR_IF, trypos->lnum) ++ == FAIL) ++ break; ++ } ++ } ++ ++ /* ++ * If we're below an unterminated line that is not an ++ * "if" or something, we may line up with this line or ++ * add something for a continuation line, depending on ++ * the line before this one. ++ */ ++ else ++ { ++ /* ++ * Found two unterminated lines on a row, line up with ++ * the last one. ++ * c = 99 + ++ * 100 + ++ * -> here; ++ */ ++ if (lookfor == LOOKFOR_UNTERM) ++ { ++ /* When line ends in a comma add extra indent */ ++ if (terminated == ',') ++ amount += ind_continuation; ++ break; ++ } ++ ++ if (lookfor == LOOKFOR_ENUM_OR_INIT) ++ { ++ /* Found two lines ending in ',', lineup with the ++ * lowest one, but check for cpp base class ++ * declaration/initialization, if it is an ++ * opening brace or we are looking just for ++ * enumerations/initializations. */ ++ if (terminated == ',') ++ { ++ if (curbuf->b_ind_cpp_baseclass == 0) ++ break; ++ ++ lookfor = LOOKFOR_CPP_BASECLASS; ++ continue; ++ } ++ ++ /* Ignore unterminated lines in between, but ++ * reduce indent. */ ++ if (amount > cur_amount) ++ amount = cur_amount; ++ } ++ else ++ { ++ /* ++ * Found first unterminated line on a row, may ++ * line up with this line, remember its indent ++ * 100 + ++ * -> here; ++ */ ++ l = ml_get_curline(); ++ amount = cur_amount; ++ ++ n = (int)STRLEN(l); ++ if (terminated == ',' && (*skipwhite(l) == ']' ++ || (n >=2 && l[n - 2] == ']'))) ++ break; ++ ++ /* ++ * If previous line ends in ',', check whether we ++ * are in an initialization or enum ++ * struct xxx = ++ * { ++ * sizeof a, ++ * 124 }; ++ * or a normal possible continuation line. ++ * but only, of no other statement has been found ++ * yet. ++ */ ++ if (lookfor == LOOKFOR_INITIAL && terminated == ',') ++ { ++ if (curbuf->b_ind_js) ++ { ++ /* Search for a line ending in a comma ++ * and line up with the line below it ++ * (could be the current line). ++ * some = [ ++ * 1, <- line up here ++ * 2, ++ * some = [ ++ * 3 + <- line up here ++ * 4 * ++ * 5, ++ * 6, ++ */ ++ if (cin_iscomment(skipwhite(l))) ++ break; ++ lookfor = LOOKFOR_COMMA; ++ trypos = find_match_char('[', ++ curbuf->b_ind_maxparen); ++ if (trypos != NULL) ++ { ++ if (trypos->lnum ++ == curwin->w_cursor.lnum - 1) ++ { ++ /* Current line is first inside ++ * [], line up with it. */ ++ break; ++ } ++ ourscope = trypos->lnum; ++ } ++ } ++ else ++ { ++ lookfor = LOOKFOR_ENUM_OR_INIT; ++ cont_amount = cin_first_id_amount(); ++ } ++ } ++ else ++ { ++ if (lookfor == LOOKFOR_INITIAL ++ && *l != NUL ++ && l[STRLEN(l) - 1] == '\\') ++ /* XXX */ ++ cont_amount = cin_get_equal_amount( ++ curwin->w_cursor.lnum); ++ if (lookfor != LOOKFOR_TERM ++ && lookfor != LOOKFOR_JS_KEY ++ && lookfor != LOOKFOR_COMMA ++ && raw_string_start != curwin->w_cursor.lnum) ++ lookfor = LOOKFOR_UNTERM; ++ } ++ } ++ } ++ } ++ ++ /* ++ * Check if we are after a while (cond); ++ * If so: Ignore until the matching "do". ++ */ ++ else if (cin_iswhileofdo_end(terminated)) /* XXX */ ++ { ++ /* ++ * Found an unterminated line after a while ();, line up ++ * with the last one. ++ * while (cond); ++ * 100 + <- line up with this one ++ * -> here; ++ */ ++ if (lookfor == LOOKFOR_UNTERM ++ || lookfor == LOOKFOR_ENUM_OR_INIT) ++ { ++ if (cont_amount > 0) ++ amount = cont_amount; ++ else ++ amount += ind_continuation; ++ break; ++ } ++ ++ if (whilelevel == 0) ++ { ++ lookfor = LOOKFOR_TERM; ++ amount = get_indent(); /* XXX */ ++ if (theline[0] == '{') ++ amount += curbuf->b_ind_open_extra; ++ } ++ ++whilelevel; ++ } ++ ++ /* ++ * We are after a "normal" statement. ++ * If we had another statement we can stop now and use the ++ * indent of that other statement. ++ * Otherwise the indent of the current statement may be used, ++ * search backwards for the next "normal" statement. ++ */ ++ else ++ { ++ /* ++ * Skip single break line, if before a switch label. It ++ * may be lined up with the case label. ++ */ ++ if (lookfor == LOOKFOR_NOBREAK ++ && cin_isbreak(skipwhite(ml_get_curline()))) ++ { ++ lookfor = LOOKFOR_ANY; ++ continue; ++ } ++ ++ /* ++ * Handle "do {" line. ++ */ ++ if (whilelevel > 0) ++ { ++ l = cin_skipcomment(ml_get_curline()); ++ if (cin_isdo(l)) ++ { ++ amount = get_indent(); /* XXX */ ++ --whilelevel; ++ continue; ++ } ++ } ++ ++ /* ++ * Found a terminated line above an unterminated line. Add ++ * the amount for a continuation line. ++ * x = 1; ++ * y = foo + ++ * -> here; ++ * or ++ * int x = 1; ++ * int foo, ++ * -> here; ++ */ ++ if (lookfor == LOOKFOR_UNTERM ++ || lookfor == LOOKFOR_ENUM_OR_INIT) ++ { ++ if (cont_amount > 0) ++ amount = cont_amount; ++ else ++ amount += ind_continuation; ++ break; ++ } ++ ++ /* ++ * Found a terminated line above a terminated line or "if" ++ * etc. line. Use the amount of the line below us. ++ * x = 1; x = 1; ++ * if (asdf) y = 2; ++ * while (asdf) ->here; ++ * here; ++ * ->foo; ++ */ ++ if (lookfor == LOOKFOR_TERM) ++ { ++ if (!lookfor_break && whilelevel == 0) ++ break; ++ } ++ ++ /* ++ * First line above the one we're indenting is terminated. ++ * To know what needs to be done look further backward for ++ * a terminated line. ++ */ ++ else ++ { ++ /* ++ * position the cursor over the rightmost paren, so ++ * that matching it will take us back to the start of ++ * the line. Helps for: ++ * func(asdr, ++ * asdfasdf); ++ * here; ++ */ ++ term_again: ++ l = ml_get_curline(); ++ if (find_last_paren(l, '(', ')') ++ && (trypos = find_match_paren( ++ curbuf->b_ind_maxparen)) != NULL) ++ { ++ /* ++ * Check if we are on a case label now. This is ++ * handled above. ++ * case xx: if ( asdf && ++ * asdf) ++ */ ++ curwin->w_cursor = *trypos; ++ l = ml_get_curline(); ++ if (cin_iscase(l, FALSE) || cin_isscopedecl(l)) ++ { ++ ++curwin->w_cursor.lnum; ++ curwin->w_cursor.col = 0; ++ continue; ++ } ++ } ++ ++ /* When aligning with the case statement, don't align ++ * with a statement after it. ++ * case 1: { <-- don't use this { position ++ * stat; ++ * } ++ * case 2: ++ * stat; ++ * } ++ */ ++ iscase = (curbuf->b_ind_keep_case_label ++ && cin_iscase(l, FALSE)); ++ ++ /* ++ * Get indent and pointer to text for current line, ++ * ignoring any jump label. ++ */ ++ amount = skip_label(curwin->w_cursor.lnum, &l); ++ ++ if (theline[0] == '{') ++ amount += curbuf->b_ind_open_extra; ++ /* See remark above: "Only add b_ind_open_extra.." */ ++ l = skipwhite(l); ++ if (*l == '{') ++ amount -= curbuf->b_ind_open_extra; ++ lookfor = iscase ? LOOKFOR_ANY : LOOKFOR_TERM; ++ ++ /* ++ * When a terminated line starts with "else" skip to ++ * the matching "if": ++ * else 3; ++ * indent this; ++ * Need to use the scope of this "else". XXX ++ * If whilelevel != 0 continue looking for a "do {". ++ */ ++ if (lookfor == LOOKFOR_TERM ++ && *l != '}' ++ && cin_iselse(l) ++ && whilelevel == 0) ++ { ++ if ((trypos = find_start_brace()) == NULL ++ || find_match(LOOKFOR_IF, trypos->lnum) ++ == FAIL) ++ break; ++ continue; ++ } ++ ++ /* ++ * If we're at the end of a block, skip to the start of ++ * that block. ++ */ ++ l = ml_get_curline(); ++ if (find_last_paren(l, '{', '}') /* XXX */ ++ && (trypos = find_start_brace()) != NULL) ++ { ++ curwin->w_cursor = *trypos; ++ /* if not "else {" check for terminated again */ ++ /* but skip block for "} else {" */ ++ l = cin_skipcomment(ml_get_curline()); ++ if (*l == '}' || !cin_iselse(l)) ++ goto term_again; ++ ++curwin->w_cursor.lnum; ++ curwin->w_cursor.col = 0; ++ } ++ } ++ } ++ } ++ } ++ } ++ ++ /* add extra indent for a comment */ ++ if (cin_iscomment(theline)) ++ amount += curbuf->b_ind_comment; ++ ++ /* 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)) != 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, &amount)) ++ 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, &amount))) ++ 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; ++ } ++ ++ static int ++ find_match(int lookfor, linenr_T ourscope) ++ { ++ char_u *look; ++ pos_T *theirscope; ++ char_u *mightbeif; ++ int elselevel; ++ int whilelevel; ++ ++ if (lookfor == LOOKFOR_IF) ++ { ++ elselevel = 1; ++ whilelevel = 0; ++ } ++ else ++ { ++ elselevel = 0; ++ whilelevel = 1; ++ } ++ ++ curwin->w_cursor.col = 0; ++ ++ while (curwin->w_cursor.lnum > ourscope + 1) ++ { ++ curwin->w_cursor.lnum--; ++ curwin->w_cursor.col = 0; ++ ++ look = cin_skipcomment(ml_get_curline()); ++ if (cin_iselse(look) ++ || cin_isif(look) ++ || cin_isdo(look) /* XXX */ ++ || cin_iswhileofdo(look, curwin->w_cursor.lnum)) ++ { ++ /* ++ * if we've gone outside the braces entirely, ++ * we must be out of scope... ++ */ ++ theirscope = find_start_brace(); /* XXX */ ++ if (theirscope == NULL) ++ break; ++ ++ /* ++ * and if the brace enclosing this is further ++ * back than the one enclosing the else, we're ++ * out of luck too. ++ */ ++ if (theirscope->lnum < ourscope) ++ break; ++ ++ /* ++ * and if they're enclosed in a *deeper* brace, ++ * then we can ignore it because it's in a ++ * different scope... ++ */ ++ if (theirscope->lnum > ourscope) ++ continue; ++ ++ /* ++ * if it was an "else" (that's not an "else if") ++ * then we need to go back to another if, so ++ * increment elselevel ++ */ ++ look = cin_skipcomment(ml_get_curline()); ++ if (cin_iselse(look)) ++ { ++ mightbeif = cin_skipcomment(look + 4); ++ if (!cin_isif(mightbeif)) ++ ++elselevel; ++ continue; ++ } ++ ++ /* ++ * if it was a "while" then we need to go back to ++ * another "do", so increment whilelevel. XXX ++ */ ++ if (cin_iswhileofdo(look, curwin->w_cursor.lnum)) ++ { ++ ++whilelevel; ++ continue; ++ } ++ ++ /* If it's an "if" decrement elselevel */ ++ look = cin_skipcomment(ml_get_curline()); ++ if (cin_isif(look)) ++ { ++ elselevel--; ++ /* ++ * When looking for an "if" ignore "while"s that ++ * get in the way. ++ */ ++ if (elselevel == 0 && lookfor == LOOKFOR_IF) ++ whilelevel = 0; ++ } ++ ++ /* If it's a "do" decrement whilelevel */ ++ if (cin_isdo(look)) ++ whilelevel--; ++ ++ /* ++ * if we've used up all the elses, then ++ * this must be the if that we want! ++ * match the indent level of that if. ++ */ ++ if (elselevel <= 0 && whilelevel <= 0) ++ { ++ return OK; ++ } ++ } ++ } ++ return FAIL; ++ } ++ ++ # if defined(FEAT_EVAL) || defined(PROTO) ++ /* ++ * Get indent level from 'indentexpr'. ++ */ ++ int ++ get_expr_indent(void) ++ { ++ int indent = -1; ++ char_u *inde_copy; ++ pos_T save_pos; ++ colnr_T save_curswant; ++ int save_set_curswant; ++ int save_State; ++ int use_sandbox = was_set_insecurely((char_u *)"indentexpr", ++ OPT_LOCAL); ++ ++ /* Save and restore cursor position and curswant, in case it was changed ++ * via :normal commands */ ++ save_pos = curwin->w_cursor; ++ save_curswant = curwin->w_curswant; ++ save_set_curswant = curwin->w_set_curswant; ++ set_vim_var_nr(VV_LNUM, curwin->w_cursor.lnum); ++ if (use_sandbox) ++ ++sandbox; ++ ++textlock; ++ ++ /* Need to make a copy, the 'indentexpr' option could be changed while ++ * evaluating it. */ ++ inde_copy = vim_strsave(curbuf->b_p_inde); ++ if (inde_copy != NULL) ++ { ++ indent = (int)eval_to_number(inde_copy); ++ vim_free(inde_copy); ++ } ++ ++ if (use_sandbox) ++ --sandbox; ++ --textlock; ++ ++ /* Restore the cursor position so that 'indentexpr' doesn't need to. ++ * Pretend to be in Insert mode, allow cursor past end of line for "o" ++ * command. */ ++ save_State = State; ++ State = INSERT; ++ curwin->w_cursor = save_pos; ++ curwin->w_curswant = save_curswant; ++ curwin->w_set_curswant = save_set_curswant; ++ check_cursor(); ++ State = save_State; ++ ++ /* If there is an error, just keep the current indent. */ ++ if (indent < 0) ++ indent = get_indent(); ++ ++ return indent; ++ } ++ # endif ++ ++ /* ++ * return TRUE if 'cinkeys' contains the key "keytyped", ++ * when == '*': Only if key is preceded with '*' (indent before insert) ++ * when == '!': Only if key is preceded with '!' (don't insert) ++ * when == ' ': Only if key is not preceded with '*'(indent afterwards) ++ * ++ * "keytyped" can have a few special values: ++ * KEY_OPEN_FORW ++ * KEY_OPEN_BACK ++ * KEY_COMPLETE just finished completion. ++ * ++ * If line_is_empty is TRUE accept keys with '0' before them. ++ */ ++ int ++ in_cinkeys( ++ int keytyped, ++ int when, ++ int line_is_empty) ++ { ++ char_u *look; ++ int try_match; ++ int try_match_word; ++ char_u *p; ++ char_u *line; ++ int icase; ++ int i; ++ ++ if (keytyped == NUL) ++ /* Can happen with CTRL-Y and CTRL-E on a short line. */ ++ return FALSE; ++ ++ #ifdef FEAT_EVAL ++ if (*curbuf->b_p_inde != NUL) ++ look = curbuf->b_p_indk; /* 'indentexpr' set: use 'indentkeys' */ ++ else ++ #endif ++ look = curbuf->b_p_cink; /* 'indentexpr' empty: use 'cinkeys' */ ++ while (*look) ++ { ++ /* ++ * Find out if we want to try a match with this key, depending on ++ * 'when' and a '*' or '!' before the key. ++ */ ++ switch (when) ++ { ++ case '*': try_match = (*look == '*'); break; ++ case '!': try_match = (*look == '!'); break; ++ default: try_match = (*look != '*'); break; ++ } ++ if (*look == '*' || *look == '!') ++ ++look; ++ ++ /* ++ * If there is a '0', only accept a match if the line is empty. ++ * But may still match when typing last char of a word. ++ */ ++ if (*look == '0') ++ { ++ try_match_word = try_match; ++ if (!line_is_empty) ++ try_match = FALSE; ++ ++look; ++ } ++ else ++ try_match_word = FALSE; ++ ++ /* ++ * does it look like a control character? ++ */ ++ if (*look == '^' ++ #ifdef EBCDIC ++ && (Ctrl_chr(look[1]) != 0) ++ #else ++ && look[1] >= '?' && look[1] <= '_' ++ #endif ++ ) ++ { ++ if (try_match && keytyped == Ctrl_chr(look[1])) ++ return TRUE; ++ look += 2; ++ } ++ /* ++ * 'o' means "o" command, open forward. ++ * 'O' means "O" command, open backward. ++ */ ++ else if (*look == 'o') ++ { ++ if (try_match && keytyped == KEY_OPEN_FORW) ++ return TRUE; ++ ++look; ++ } ++ else if (*look == 'O') ++ { ++ if (try_match && keytyped == KEY_OPEN_BACK) ++ return TRUE; ++ ++look; ++ } ++ ++ /* ++ * 'e' means to check for "else" at start of line and just before the ++ * cursor. ++ */ ++ else if (*look == 'e') ++ { ++ if (try_match && keytyped == 'e' && curwin->w_cursor.col >= 4) ++ { ++ p = ml_get_curline(); ++ if (skipwhite(p) == p + curwin->w_cursor.col - 4 && ++ STRNCMP(p + curwin->w_cursor.col - 4, "else", 4) == 0) ++ return TRUE; ++ } ++ ++look; ++ } ++ ++ /* ++ * ':' only causes an indent if it is at the end of a label or case ++ * statement, or when it was before typing the ':' (to fix ++ * class::method for C++). ++ */ ++ else if (*look == ':') ++ { ++ if (try_match && keytyped == ':') ++ { ++ p = ml_get_curline(); ++ if (cin_iscase(p, FALSE) || cin_isscopedecl(p) || cin_islabel()) ++ return TRUE; ++ /* Need to get the line again after cin_islabel(). */ ++ p = ml_get_curline(); ++ if (curwin->w_cursor.col > 2 ++ && p[curwin->w_cursor.col - 1] == ':' ++ && p[curwin->w_cursor.col - 2] == ':') ++ { ++ p[curwin->w_cursor.col - 1] = ' '; ++ i = (cin_iscase(p, FALSE) || cin_isscopedecl(p) ++ || cin_islabel()); ++ p = ml_get_curline(); ++ p[curwin->w_cursor.col - 1] = ':'; ++ if (i) ++ return TRUE; ++ } ++ } ++ ++look; ++ } ++ ++ ++ /* ++ * Is it a key in <>, maybe? ++ */ ++ else if (*look == '<') ++ { ++ if (try_match) ++ { ++ /* ++ * make up some named keys <o>, <O>, <e>, <0>, <>>, <<>, <*>, ++ * <:> and <!> so that people can re-indent on o, O, e, 0, <, ++ * >, *, : and ! keys if they really really want to. ++ */ ++ if (vim_strchr((char_u *)"<>!*oOe0:", look[1]) != NULL ++ && keytyped == look[1]) ++ return TRUE; ++ ++ if (keytyped == get_special_key_code(look + 1)) ++ return TRUE; ++ } ++ while (*look && *look != '>') ++ look++; ++ while (*look == '>') ++ look++; ++ } ++ ++ /* ++ * Is it a word: "=word"? ++ */ ++ else if (*look == '=' && look[1] != ',' && look[1] != NUL) ++ { ++ ++look; ++ if (*look == '~') ++ { ++ icase = TRUE; ++ ++look; ++ } ++ else ++ icase = FALSE; ++ p = vim_strchr(look, ','); ++ if (p == NULL) ++ p = look + STRLEN(look); ++ if ((try_match || try_match_word) ++ && curwin->w_cursor.col >= (colnr_T)(p - look)) ++ { ++ int match = FALSE; ++ ++ #ifdef FEAT_INS_EXPAND ++ if (keytyped == KEY_COMPLETE) ++ { ++ char_u *s; ++ ++ /* Just completed a word, check if it starts with "look". ++ * search back for the start of a word. */ ++ line = ml_get_curline(); ++ if (has_mbyte) ++ { ++ char_u *n; ++ ++ for (s = line + curwin->w_cursor.col; s > line; s = n) ++ { ++ n = mb_prevptr(line, s); ++ if (!vim_iswordp(n)) ++ break; ++ } ++ } ++ else ++ for (s = line + curwin->w_cursor.col; s > line; --s) ++ if (!vim_iswordc(s[-1])) ++ break; ++ if (s + (p - look) <= line + curwin->w_cursor.col ++ && (icase ++ ? MB_STRNICMP(s, look, p - look) ++ : STRNCMP(s, look, p - look)) == 0) ++ match = TRUE; ++ } ++ else ++ #endif ++ /* TODO: multi-byte */ ++ if (keytyped == (int)p[-1] || (icase && keytyped < 256 ++ && TOLOWER_LOC(keytyped) == TOLOWER_LOC((int)p[-1]))) ++ { ++ line = ml_get_cursor(); ++ if ((curwin->w_cursor.col == (colnr_T)(p - look) ++ || !vim_iswordc(line[-(p - look) - 1])) ++ && (icase ++ ? MB_STRNICMP(line - (p - look), look, p - look) ++ : STRNCMP(line - (p - look), look, p - look)) ++ == 0) ++ match = TRUE; ++ } ++ if (match && try_match_word && !try_match) ++ { ++ /* "0=word": Check if there are only blanks before the ++ * word. */ ++ if (getwhitecols_curline() != ++ (int)(curwin->w_cursor.col - (p - look))) ++ match = FALSE; ++ } ++ if (match) ++ return TRUE; ++ } ++ look = p; ++ } ++ ++ /* ++ * ok, it's a boring generic character. ++ */ ++ else ++ { ++ if (try_match && *look == keytyped) ++ return TRUE; ++ if (*look != NUL) ++ ++look; ++ } ++ ++ /* ++ * Skip over ", ". ++ */ ++ look = skip_to_option_part(look); ++ } ++ return FALSE; ++ } ++ #endif /* FEAT_CINDENT */ ++ ++ #if defined(FEAT_LISP) || defined(PROTO) ++ ++ static int ++ lisp_match(char_u *p) ++ { ++ char_u buf[LSIZE]; ++ int len; ++ char_u *word = *curbuf->b_p_lw != NUL ? curbuf->b_p_lw : p_lispwords; ++ ++ while (*word != NUL) ++ { ++ (void)copy_option_part(&word, buf, LSIZE, ","); ++ len = (int)STRLEN(buf); ++ if (STRNCMP(buf, p, len) == 0 && p[len] == ' ') ++ return TRUE; ++ } ++ return FALSE; ++ } ++ ++ /* ++ * When 'p' is present in 'cpoptions, a Vi compatible method is used. ++ * The incompatible newer method is quite a bit better at indenting ++ * code in lisp-like languages than the traditional one; it's still ++ * mostly heuristics however -- Dirk van Deun, dirk@rave.org ++ * ++ * TODO: ++ * Findmatch() should be adapted for lisp, also to make showmatch ++ * work correctly: now (v5.3) it seems all C/C++ oriented: ++ * - it does not recognize the #\( and #\) notations as character literals ++ * - it doesn't know about comments starting with a semicolon ++ * - it incorrectly interprets '(' as a character literal ++ * All this messes up get_lisp_indent in some rare cases. ++ * Update from Sergey Khorev: ++ * I tried to fix the first two issues. ++ */ ++ int ++ get_lisp_indent(void) ++ { ++ pos_T *pos, realpos, paren; ++ int amount; ++ char_u *that; ++ colnr_T col; ++ colnr_T firsttry; ++ int parencount, quotecount; ++ int vi_lisp; ++ ++ /* Set vi_lisp to use the vi-compatible method */ ++ vi_lisp = (vim_strchr(p_cpo, CPO_LISP) != NULL); ++ ++ realpos = curwin->w_cursor; ++ curwin->w_cursor.col = 0; ++ ++ if ((pos = findmatch(NULL, '(')) == NULL) ++ pos = findmatch(NULL, '['); ++ else ++ { ++ paren = *pos; ++ pos = findmatch(NULL, '['); ++ if (pos == NULL || LT_POSP(pos, &paren)) ++ pos = &paren; ++ } ++ if (pos != NULL) ++ { ++ /* Extra trick: Take the indent of the first previous non-white ++ * line that is at the same () level. */ ++ amount = -1; ++ parencount = 0; ++ ++ while (--curwin->w_cursor.lnum >= pos->lnum) ++ { ++ if (linewhite(curwin->w_cursor.lnum)) ++ continue; ++ for (that = ml_get_curline(); *that != NUL; ++that) ++ { ++ if (*that == ';') ++ { ++ while (*(that + 1) != NUL) ++ ++that; ++ continue; ++ } ++ if (*that == '\\') ++ { ++ if (*(that + 1) != NUL) ++ ++that; ++ continue; ++ } ++ if (*that == '"' && *(that + 1) != NUL) ++ { ++ while (*++that && *that != '"') ++ { ++ /* skipping escaped characters in the string */ ++ if (*that == '\\') ++ { ++ if (*++that == NUL) ++ break; ++ if (that[1] == NUL) ++ { ++ ++that; ++ break; ++ } ++ } ++ } ++ } ++ if (*that == '(' || *that == '[') ++ ++parencount; ++ else if (*that == ')' || *that == ']') ++ --parencount; ++ } ++ if (parencount == 0) ++ { ++ amount = get_indent(); ++ break; ++ } ++ } ++ ++ if (amount == -1) ++ { ++ curwin->w_cursor.lnum = pos->lnum; ++ curwin->w_cursor.col = pos->col; ++ col = pos->col; ++ ++ that = ml_get_curline(); ++ ++ if (vi_lisp && get_indent() == 0) ++ amount = 2; ++ else ++ { ++ char_u *line = that; ++ ++ amount = 0; ++ while (*that && col) ++ { ++ amount += lbr_chartabsize_adv(line, &that, (colnr_T)amount); ++ col--; ++ } ++ ++ /* ++ * Some keywords require "body" indenting rules (the ++ * non-standard-lisp ones are Scheme special forms): ++ * ++ * (let ((a 1)) instead (let ((a 1)) ++ * (...)) of (...)) ++ */ ++ ++ if (!vi_lisp && (*that == '(' || *that == '[') ++ && lisp_match(that + 1)) ++ amount += 2; ++ else ++ { ++ that++; ++ amount++; ++ firsttry = amount; ++ ++ while (VIM_ISWHITE(*that)) ++ { ++ amount += lbr_chartabsize(line, that, (colnr_T)amount); ++ ++that; ++ } ++ ++ if (*that && *that != ';') /* not a comment line */ ++ { ++ /* test *that != '(' to accommodate first let/do ++ * argument if it is more than one line */ ++ if (!vi_lisp && *that != '(' && *that != '[') ++ firsttry++; ++ ++ parencount = 0; ++ quotecount = 0; ++ ++ if (vi_lisp ++ || (*that != '"' ++ && *that != '\'' ++ && *that != '#' ++ && (*that < '0' || *that > '9'))) ++ { ++ while (*that ++ && (!VIM_ISWHITE(*that) ++ || quotecount ++ || parencount) ++ && (!((*that == '(' || *that == '[') ++ && !quotecount ++ && !parencount ++ && vi_lisp))) ++ { ++ if (*that == '"') ++ quotecount = !quotecount; ++ if ((*that == '(' || *that == '[') ++ && !quotecount) ++ ++parencount; ++ if ((*that == ')' || *that == ']') ++ && !quotecount) ++ --parencount; ++ if (*that == '\\' && *(that+1) != NUL) ++ amount += lbr_chartabsize_adv( ++ line, &that, (colnr_T)amount); ++ amount += lbr_chartabsize_adv( ++ line, &that, (colnr_T)amount); ++ } ++ } ++ while (VIM_ISWHITE(*that)) ++ { ++ amount += lbr_chartabsize( ++ line, that, (colnr_T)amount); ++ that++; ++ } ++ if (!*that || *that == ';') ++ amount = firsttry; ++ } ++ } ++ } ++ } ++ } ++ else ++ amount = 0; /* no matching '(' or '[' found, use zero indent */ ++ ++ curwin->w_cursor = realpos; ++ ++ return amount; ++ } ++ #endif /* FEAT_LISP */ ++ ++ #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); ++ } ++ #endif ++ ++ #if defined(FEAT_LISP) || defined(FEAT_CINDENT) || defined(PROTO) ++ /* ++ * Re-indent the current line, based on the current contents of it and the ++ * surrounding lines. Fixing the cursor position seems really easy -- I'm very ++ * confused what all the part that handles Control-T is doing that I'm not. ++ * "get_the_indent" should be get_c_indent, get_expr_indent or get_lisp_indent. ++ */ ++ ++ void ++ fixthisline(int (*get_the_indent)(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 ++ fix_indent(void) ++ { ++ if (p_paste) ++ return; ++ # ifdef FEAT_LISP ++ if (curbuf->b_p_lisp && curbuf->b_p_ai) ++ fixthisline(get_lisp_indent); ++ # endif ++ # if defined(FEAT_LISP) && defined(FEAT_CINDENT) ++ else ++ # endif ++ # ifdef FEAT_CINDENT ++ if (cindent_on()) ++ do_c_expr_indent(); ++ # endif ++ } ++ ++ #endif +*** ../vim-8.1.0856/src/misc1.c 2019-01-26 17:28:22.228599112 +0100 +--- src/misc1.c 2019-01-31 13:43:23.356467234 +0100 +*************** +*** 702,742 **** + #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. + * +--- 702,707 ---- +*************** +*** 5404,9720 **** + 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])); +- } +- +- /* +- * Find the position of a C++ base-class declaration or +- * constructor-initialization. eg: +- * +- * class MyClass : +- * baseClass <-- here +- * class MyClass : public baseClass, +- * anotherBaseClass <-- here (should probably lineup ??) +- * MyClass::MyClass(...) : +- * baseClass(...) <-- here (constructor-initialization) +- * +- * This is a lot of guessing. Watch out for "cond ? func() : foo". +- */ +- static int +- cin_is_cpp_baseclass( +- cpp_baseclass_cache_T *cached) /* input and output */ +- { +- lpos_T *pos = &cached->lpos; /* find position */ +- char_u *s; +- int class_or_struct, lookfor_ctor_init, cpp_base_class; +- linenr_T lnum = curwin->w_cursor.lnum; +- char_u *line = ml_get_curline(); +- +- if (pos->lnum <= lnum) +- return cached->found; /* Use the cached result */ +- +- pos->col = 0; +- +- s = skipwhite(line); +- if (*s == '#') /* skip #define FOO x ? (x) : x */ +- return FALSE; +- s = cin_skipcomment(s); +- if (*s == NUL) +- return FALSE; +- +- cpp_base_class = lookfor_ctor_init = class_or_struct = FALSE; +- +- /* Search for a line starting with '#', empty, ending in ';' or containing +- * '{' or '}' and start below it. This handles the following situations: +- * a = cond ? +- * func() : +- * asdf; +- * func::foo() +- * : something +- * {} +- * Foo::Foo (int one, int two) +- * : something(4), +- * somethingelse(3) +- * {} +- */ +- while (lnum > 1) +- { +- line = ml_get(lnum - 1); +- s = skipwhite(line); +- if (*s == '#' || *s == NUL) +- break; +- while (*s != NUL) +- { +- s = cin_skipcomment(s); +- if (*s == '{' || *s == '}' +- || (*s == ';' && cin_nocode(s + 1))) +- break; +- if (*s != NUL) +- ++s; +- } +- if (*s != NUL) +- break; +- --lnum; +- } +- +- pos->lnum = lnum; +- line = ml_get(lnum); +- s = line; +- for (;;) +- { +- if (*s == NUL) +- { +- if (lnum == curwin->w_cursor.lnum) +- break; +- /* Continue in the cursor line. */ +- line = ml_get(++lnum); +- s = line; +- } +- if (s == line) +- { +- /* don't recognize "case (foo):" as a baseclass */ +- if (cin_iscase(s, FALSE)) +- break; +- s = cin_skipcomment(line); +- if (*s == NUL) +- continue; +- } +- +- if (s[0] == '"' || (s[0] == 'R' && s[1] == '"')) +- s = skip_string(s) + 1; +- else if (s[0] == ':') +- { +- if (s[1] == ':') +- { +- /* skip double colon. It can't be a constructor +- * initialization any more */ +- lookfor_ctor_init = FALSE; +- s = cin_skipcomment(s + 2); +- } +- else if (lookfor_ctor_init || class_or_struct) +- { +- /* we have something found, that looks like the start of +- * cpp-base-class-declaration or constructor-initialization */ +- cpp_base_class = TRUE; +- lookfor_ctor_init = class_or_struct = FALSE; +- pos->col = 0; +- s = cin_skipcomment(s + 1); +- } +- else +- s = cin_skipcomment(s + 1); +- } +- else if ((STRNCMP(s, "class", 5) == 0 && !vim_isIDc(s[5])) +- || (STRNCMP(s, "struct", 6) == 0 && !vim_isIDc(s[6]))) +- { +- class_or_struct = TRUE; +- lookfor_ctor_init = FALSE; +- +- if (*s == 'c') +- s = cin_skipcomment(s + 5); +- else +- s = cin_skipcomment(s + 6); +- } +- else +- { +- if (s[0] == '{' || s[0] == '}' || s[0] == ';') +- { +- cpp_base_class = lookfor_ctor_init = class_or_struct = FALSE; +- } +- else if (s[0] == ')') +- { +- /* Constructor-initialization is assumed if we come across +- * something like "):" */ +- class_or_struct = FALSE; +- lookfor_ctor_init = TRUE; +- } +- else if (s[0] == '?') +- { +- /* Avoid seeing '() :' after '?' as constructor init. */ +- return FALSE; +- } +- else if (!vim_isIDc(s[0])) +- { +- /* if it is not an identifier, we are wrong */ +- class_or_struct = FALSE; +- lookfor_ctor_init = FALSE; +- } +- else if (pos->col == 0) +- { +- /* it can't be a constructor-initialization any more */ +- lookfor_ctor_init = FALSE; +- +- /* the first statement starts here: lineup with this one... */ +- if (cpp_base_class) +- pos->col = (colnr_T)(s - line); +- } +- +- /* When the line ends in a comma don't align with it. */ +- if (lnum == curwin->w_cursor.lnum && *s == ',' && cin_nocode(s + 1)) +- pos->col = 0; +- +- s = cin_skipcomment(s + 1); +- } +- } +- +- cached->found = cpp_base_class; +- if (cpp_base_class) +- pos->lnum = lnum; +- return cpp_base_class; +- } +- +- static int +- get_baseclass_amount(int col) +- { +- int amount; +- colnr_T vcol; +- pos_T *trypos; +- +- if (col == 0) +- { +- amount = get_indent(); +- if (find_last_paren(ml_get_curline(), '(', ')') +- && (trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL) +- amount = get_indent_lnum(trypos->lnum); /* XXX */ +- if (!cin_ends_in(ml_get_curline(), (char_u *)",", NULL)) +- amount += curbuf->b_ind_cpp_baseclass; +- } +- else +- { +- curwin->w_cursor.col = col; +- getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL); +- amount = (int)vcol; +- } +- if (amount < curbuf->b_ind_cpp_baseclass) +- amount = curbuf->b_ind_cpp_baseclass; +- return amount; +- } +- +- /* +- * Return TRUE if string "s" ends with the string "find", possibly followed by +- * white space and comments. Skip strings and comments. +- * Ignore "ignore" after "find" if it's not NULL. +- */ +- static int +- cin_ends_in(char_u *s, char_u *find, char_u *ignore) +- { +- char_u *p = s; +- char_u *r; +- int len = (int)STRLEN(find); +- +- while (*p != NUL) +- { +- p = cin_skipcomment(p); +- if (STRNCMP(p, find, len) == 0) +- { +- r = skipwhite(p + len); +- if (ignore != NULL && STRNCMP(r, ignore, STRLEN(ignore)) == 0) +- r = skipwhite(r + STRLEN(ignore)); +- if (cin_nocode(r)) +- return TRUE; +- } +- if (*p != NUL) +- ++p; +- } +- return FALSE; +- } +- +- /* +- * Return TRUE when "s" starts with "word" and then a non-ID character. +- */ +- static int +- cin_starts_with(char_u *s, char *word) +- { +- int l = (int)STRLEN(word); +- +- return (STRNCMP(s, word, l) == 0 && !vim_isIDc(s[l])); +- } +- +- /* +- * Skip strings, chars and comments until at or past "trypos". +- * Return the column found. +- */ +- static int +- cin_skip2pos(pos_T *trypos) +- { +- char_u *line; +- char_u *p; +- char_u *new_p; +- +- p = line = ml_get(trypos->lnum); +- while (*p && (colnr_T)(p - line) < trypos->col) +- { +- if (cin_iscomment(p)) +- p = cin_skipcomment(p); +- else +- { +- new_p = skip_string(p); +- if (new_p == p) +- ++p; +- else +- p = new_p; +- } +- } +- return (int)(p - line); +- } +- +- /* +- * Find the '{' at the start of the block we are in. +- * Return NULL if no match found. +- * Ignore a '{' that is in a comment, makes indenting the next three lines +- * work. */ +- /* foo() */ +- /* { */ +- /* } */ +- +- static pos_T * +- find_start_brace(void) /* XXX */ +- { +- pos_T cursor_save; +- pos_T *trypos; +- pos_T *pos; +- static pos_T pos_copy; +- +- cursor_save = curwin->w_cursor; +- while ((trypos = findmatchlimit(NULL, '{', FM_BLOCKSTOP, 0)) != NULL) +- { +- pos_copy = *trypos; /* copy pos_T, next findmatch will change it */ +- trypos = &pos_copy; +- curwin->w_cursor = *trypos; +- 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)) == NULL) /* XXX */ +- break; +- if (pos != NULL) +- curwin->w_cursor.lnum = pos->lnum; +- } +- curwin->w_cursor = cursor_save; +- return trypos; +- } +- +- /* +- * Find the matching '(', ignoring it if it is in a comment. +- * Return NULL if no match found. +- */ +- static pos_T * +- find_match_paren(int ind_maxparen) /* XXX */ +- { +- return find_match_char('(', ind_maxparen); +- } +- +- static pos_T * +- find_match_char(int c, int ind_maxparen) /* XXX */ +- { +- pos_T cursor_save; +- pos_T *trypos; +- static pos_T pos_copy; +- int ind_maxp_wk; +- +- cursor_save = curwin->w_cursor; +- ind_maxp_wk = ind_maxparen; +- retry: +- if ((trypos = findmatchlimit(NULL, c, 0, ind_maxp_wk)) != NULL) +- { +- /* check if the ( is in a // comment */ +- if ((colnr_T)cin_skip2pos(trypos) > trypos->col) +- { +- ind_maxp_wk = ind_maxparen - (int)(cursor_save.lnum - trypos->lnum); +- if (ind_maxp_wk > 0) +- { +- curwin->w_cursor = *trypos; +- curwin->w_cursor.col = 0; /* XXX */ +- goto retry; +- } +- trypos = NULL; +- } +- else +- { +- pos_T *trypos_wk; +- +- pos_copy = *trypos; /* copy trypos, findmatch will change it */ +- trypos = &pos_copy; +- curwin->w_cursor = *trypos; +- if ((trypos_wk = ind_find_start_CORS(NULL)) != NULL) /* XXX */ +- { +- ind_maxp_wk = ind_maxparen - (int)(cursor_save.lnum +- - trypos_wk->lnum); +- if (ind_maxp_wk > 0) +- { +- curwin->w_cursor = *trypos_wk; +- goto retry; +- } +- trypos = NULL; +- } +- } +- } +- curwin->w_cursor = cursor_save; +- return trypos; +- } +- +- /* +- * Find the matching '(', ignoring it if it is in a comment or before an +- * unmatched {. +- * Return NULL if no match found. +- */ +- static pos_T * +- find_match_paren_after_brace (int ind_maxparen) /* XXX */ +- { +- pos_T *trypos = find_match_paren(ind_maxparen); +- +- if (trypos != NULL) +- { +- pos_T *tryposBrace = find_start_brace(); +- +- /* If both an unmatched '(' and '{' is found. Ignore the '(' +- * position if the '{' is further down. */ +- if (tryposBrace != NULL +- && (trypos->lnum != tryposBrace->lnum +- ? trypos->lnum < tryposBrace->lnum +- : trypos->col < tryposBrace->col)) +- trypos = NULL; +- } +- return trypos; +- } +- +- /* +- * Return ind_maxparen corrected for the difference in line number between the +- * cursor position and "startpos". This makes sure that searching for a +- * matching paren above the cursor line doesn't find a match because of +- * looking a few lines further. +- */ +- static int +- corr_ind_maxparen(pos_T *startpos) +- { +- long n = (long)startpos->lnum - (long)curwin->w_cursor.lnum; +- +- if (n > 0 && n < curbuf->b_ind_maxparen / 2) +- return curbuf->b_ind_maxparen - (int)n; +- return curbuf->b_ind_maxparen; +- } +- +- /* +- * Set w_cursor.col to the column number of the last unmatched ')' or '{' in +- * line "l". "l" must point to the start of the line. +- */ +- static int +- find_last_paren(char_u *l, int start, int end) +- { +- int i; +- int retval = FALSE; +- int open_count = 0; +- +- curwin->w_cursor.col = 0; /* default is start of line */ +- +- for (i = 0; l[i] != NUL; i++) +- { +- i = (int)(cin_skipcomment(l + i) - l); /* ignore parens in comments */ +- i = (int)(skip_string(l + i) - l); /* ignore parens in quotes */ +- if (l[i] == start) +- ++open_count; +- else if (l[i] == end) +- { +- if (open_count > 0) +- --open_count; +- else +- { +- curwin->w_cursor.col = i; +- retval = TRUE; +- } +- } +- } +- return retval; +- } +- +- /* +- * Parse 'cinoptions' and set the values in "curbuf". +- * Must be called when 'cinoptions', 'shiftwidth' and/or 'tabstop' changes. +- */ +- void +- parse_cino(buf_T *buf) +- { +- char_u *p; +- char_u *l; +- char_u *digits; +- int n; +- int divider; +- int fraction = 0; +- int sw = (int)get_sw_value(buf); +- +- /* +- * Set the default values. +- */ +- /* Spaces from a block's opening brace the prevailing indent for that +- * block should be. */ +- buf->b_ind_level = sw; +- +- /* Spaces from the edge of the line an open brace that's at the end of a +- * line is imagined to be. */ +- buf->b_ind_open_imag = 0; +- +- /* Spaces from the prevailing indent for a line that is not preceded by +- * an opening brace. */ +- buf->b_ind_no_brace = 0; +- +- /* Column where the first { of a function should be located }. */ +- buf->b_ind_first_open = 0; +- +- /* Spaces from the prevailing indent a leftmost open brace should be +- * located. */ +- buf->b_ind_open_extra = 0; +- +- /* Spaces from the matching open brace (real location for one at the left +- * edge; imaginary location from one that ends a line) the matching close +- * brace should be located. */ +- buf->b_ind_close_extra = 0; +- +- /* Spaces from the edge of the line an open brace sitting in the leftmost +- * column is imagined to be. */ +- buf->b_ind_open_left_imag = 0; +- +- /* Spaces jump labels should be shifted to the left if N is non-negative, +- * otherwise the jump label will be put to column 1. */ +- buf->b_ind_jump_label = -1; +- +- /* Spaces from the switch() indent a "case xx" label should be located. */ +- buf->b_ind_case = sw; +- +- /* Spaces from the "case xx:" code after a switch() should be located. */ +- buf->b_ind_case_code = sw; +- +- /* Lineup break at end of case in switch() with case label. */ +- buf->b_ind_case_break = 0; +- +- /* Spaces from the class declaration indent a scope declaration label +- * should be located. */ +- buf->b_ind_scopedecl = sw; +- +- /* Spaces from the scope declaration label code should be located. */ +- buf->b_ind_scopedecl_code = sw; +- +- /* Amount K&R-style parameters should be indented. */ +- buf->b_ind_param = sw; +- +- /* Amount a function type spec should be indented. */ +- buf->b_ind_func_type = sw; +- +- /* Amount a cpp base class declaration or constructor initialization +- * should be indented. */ +- buf->b_ind_cpp_baseclass = sw; +- +- /* additional spaces beyond the prevailing indent a continuation line +- * should be located. */ +- buf->b_ind_continuation = sw; +- +- /* Spaces from the indent of the line with an unclosed parentheses. */ +- buf->b_ind_unclosed = sw * 2; +- +- /* Spaces from the indent of the line with an unclosed parentheses, which +- * itself is also unclosed. */ +- buf->b_ind_unclosed2 = sw; +- +- /* Suppress ignoring spaces from the indent of a line starting with an +- * unclosed parentheses. */ +- buf->b_ind_unclosed_noignore = 0; +- +- /* If the opening paren is the last nonwhite character on the line, and +- * b_ind_unclosed_wrapped is nonzero, use this indent relative to the outer +- * context (for very long lines). */ +- buf->b_ind_unclosed_wrapped = 0; +- +- /* Suppress ignoring white space when lining up with the character after +- * an unclosed parentheses. */ +- buf->b_ind_unclosed_whiteok = 0; +- +- /* Indent a closing parentheses under the line start of the matching +- * opening parentheses. */ +- buf->b_ind_matching_paren = 0; +- +- /* Indent a closing parentheses under the previous line. */ +- buf->b_ind_paren_prev = 0; +- +- /* Extra indent for comments. */ +- buf->b_ind_comment = 0; +- +- /* Spaces from the comment opener when there is nothing after it. */ +- buf->b_ind_in_comment = 3; +- +- /* Boolean: if non-zero, use b_ind_in_comment even if there is something +- * after the comment opener. */ +- buf->b_ind_in_comment2 = 0; +- +- /* Max lines to search for an open paren. */ +- buf->b_ind_maxparen = 20; +- +- /* Max lines to search for an open comment. */ +- buf->b_ind_maxcomment = 70; +- +- /* Handle braces for java code. */ +- buf->b_ind_java = 0; +- +- /* Not to confuse JS object properties with labels. */ +- buf->b_ind_js = 0; +- +- /* Handle blocked cases correctly. */ +- buf->b_ind_keep_case_label = 0; +- +- /* Handle C++ namespace. */ +- buf->b_ind_cpp_namespace = 0; +- +- /* Handle continuation lines containing conditions of if(), for() and +- * while(). */ +- buf->b_ind_if_for_while = 0; +- +- /* indentation for # comments */ +- buf->b_ind_hash_comment = 0; +- +- /* Handle C++ extern "C" or "C++" */ +- buf->b_ind_cpp_extern_c = 0; +- +- for (p = buf->b_p_cino; *p; ) +- { +- l = p++; +- if (*p == '-') +- ++p; +- digits = p; /* remember where the digits start */ +- n = getdigits(&p); +- divider = 0; +- if (*p == '.') /* ".5s" means a fraction */ +- { +- fraction = atol((char *)++p); +- while (VIM_ISDIGIT(*p)) +- { +- ++p; +- if (divider) +- divider *= 10; +- else +- divider = 10; +- } +- } +- if (*p == 's') /* "2s" means two times 'shiftwidth' */ +- { +- if (p == digits) +- n = sw; /* just "s" is one 'shiftwidth' */ +- else +- { +- n *= sw; +- if (divider) +- n += (sw * fraction + divider / 2) / divider; +- } +- ++p; +- } +- if (l[1] == '-') +- n = -n; +- +- /* When adding an entry here, also update the default 'cinoptions' in +- * doc/indent.txt, and add explanation for it! */ +- switch (*l) +- { +- case '>': buf->b_ind_level = n; break; +- case 'e': buf->b_ind_open_imag = n; break; +- case 'n': buf->b_ind_no_brace = n; break; +- case 'f': buf->b_ind_first_open = n; break; +- case '{': buf->b_ind_open_extra = n; break; +- case '}': buf->b_ind_close_extra = n; break; +- case '^': buf->b_ind_open_left_imag = n; break; +- case 'L': buf->b_ind_jump_label = n; break; +- case ':': buf->b_ind_case = n; break; +- case '=': buf->b_ind_case_code = n; break; +- case 'b': buf->b_ind_case_break = n; break; +- case 'p': buf->b_ind_param = n; break; +- case 't': buf->b_ind_func_type = n; break; +- case '/': buf->b_ind_comment = n; break; +- case 'c': buf->b_ind_in_comment = n; break; +- case 'C': buf->b_ind_in_comment2 = n; break; +- case 'i': buf->b_ind_cpp_baseclass = n; break; +- case '+': buf->b_ind_continuation = n; break; +- case '(': buf->b_ind_unclosed = n; break; +- case 'u': buf->b_ind_unclosed2 = n; break; +- case 'U': buf->b_ind_unclosed_noignore = n; break; +- case 'W': buf->b_ind_unclosed_wrapped = n; break; +- case 'w': buf->b_ind_unclosed_whiteok = n; break; +- case 'm': buf->b_ind_matching_paren = n; break; +- case 'M': buf->b_ind_paren_prev = n; break; +- case ')': buf->b_ind_maxparen = n; break; +- case '*': buf->b_ind_maxcomment = n; break; +- case 'g': buf->b_ind_scopedecl = n; break; +- case 'h': buf->b_ind_scopedecl_code = n; break; +- case 'j': buf->b_ind_java = n; break; +- case 'J': buf->b_ind_js = n; break; +- case 'l': buf->b_ind_keep_case_label = n; break; +- case '#': buf->b_ind_hash_comment = n; break; +- case 'N': buf->b_ind_cpp_namespace = n; break; +- case 'k': buf->b_ind_if_for_while = n; break; +- case 'E': buf->b_ind_cpp_extern_c = n; break; +- } +- if (*p == ',') +- ++p; +- } +- } +- +- /* +- * 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; +- int amount; +- int scope_amount; +- int cur_amount = MAXCOL; +- colnr_T col; +- 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; +- #define BRACE_IN_COL0 1 /* '{' is in column 0 */ +- #define BRACE_AT_START 2 /* '{' is at start of line */ +- #define BRACE_AT_END 3 /* '{' is at end of line */ +- linenr_T ourscope; +- char_u *l; +- char_u *look; +- char_u terminated; +- int lookfor; +- #define LOOKFOR_INITIAL 0 +- #define LOOKFOR_IF 1 +- #define LOOKFOR_DO 2 +- #define LOOKFOR_CASE 3 +- #define LOOKFOR_ANY 4 +- #define LOOKFOR_TERM 5 +- #define LOOKFOR_UNTERM 6 +- #define LOOKFOR_SCOPEDECL 7 +- #define LOOKFOR_NOBREAK 8 +- #define LOOKFOR_CPP_BASECLASS 9 +- #define LOOKFOR_ENUM_OR_INIT 10 +- #define LOOKFOR_JS_KEY 11 +- #define LOOKFOR_COMMA 12 +- +- int whilelevel; +- linenr_T lnum; +- int n; +- int iscase; +- int lookfor_break; +- int lookfor_cpp_namespace = FALSE; +- int cont_amount = 0; /* amount for continuation line */ +- int original_line_islabel; +- int added_to_amount = 0; +- int js_cur_has_key = 0; +- linenr_T raw_string_start = 0; +- cpp_baseclass_cache_T cache_cpp_baseclass = { FALSE, { MAXLNUM, 0 } }; +- +- /* make a copy, value is changed below */ +- int ind_continuation = curbuf->b_ind_continuation; +- +- /* 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; +- +- /* Get a copy of the current contents of the line. +- * This is required, because only the most recent line obtained with +- * ml_get is valid! */ +- linecopy = vim_strsave(ml_get(cur_curpos.lnum)); +- if (linecopy == NULL) +- return 0; +- +- /* +- * In insert mode and the cursor is on a ')' truncate the line at the +- * cursor position. We don't want to line up with the matching '(' when +- * inserting new stuff. +- * For unknown reasons the cursor might be past the end of the line, thus +- * check for that. +- */ +- if ((State & INSERT) +- && curwin->w_cursor.col < (colnr_T)STRLEN(linecopy) +- && linecopy[curwin->w_cursor.col] == ')') +- linecopy[curwin->w_cursor.col] = NUL; +- +- theline = skipwhite(linecopy); +- +- /* move the cursor to the start of the line */ +- +- curwin->w_cursor.col = 0; +- +- 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_POS(*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; +- char_u lead_start[COM_MAX_LEN]; /* start-comment string */ +- char_u lead_middle[COM_MAX_LEN]; /* middle-comment string */ +- char_u lead_end[COM_MAX_LEN]; /* end-comment string */ +- char_u *p; +- int start_align = 0; +- int start_off = 0; +- 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; +- +- p = curbuf->b_p_com; +- while (*p != NUL) +- { +- int align = 0; +- int off = 0; +- int what = 0; +- +- while (*p != NUL && *p != ':') +- { +- if (*p == COM_START || *p == COM_END || *p == COM_MIDDLE) +- what = *p++; +- else if (*p == COM_LEFT || *p == COM_RIGHT) +- align = *p++; +- else if (VIM_ISDIGIT(*p) || *p == '-') +- off = getdigits(&p); +- else +- ++p; +- } +- +- if (*p == ':') +- ++p; +- (void)copy_option_part(&p, lead_end, COM_MAX_LEN, ","); +- if (what == COM_START) +- { +- STRCPY(lead_start, lead_end); +- lead_start_len = (int)STRLEN(lead_start); +- start_off = off; +- start_align = align; +- } +- else if (what == COM_MIDDLE) +- { +- STRCPY(lead_middle, lead_end); +- lead_middle_len = (int)STRLEN(lead_middle); +- } +- else if (what == COM_END) +- { +- /* If our line starts with the middle comment string, line it +- * up with the comment opener per the 'comments' option. */ +- if (STRNCMP(theline, lead_middle, lead_middle_len) == 0 +- && STRNCMP(theline, lead_end, STRLEN(lead_end)) != 0) +- { +- done = TRUE; +- if (curwin->w_cursor.lnum > 1) +- { +- /* If the start comment string matches in the previous +- * line, use the indent of that line plus offset. If +- * the middle comment string matches in the previous +- * line, use the indent of that line. XXX */ +- look = skipwhite(ml_get(curwin->w_cursor.lnum - 1)); +- if (STRNCMP(look, lead_start, lead_start_len) == 0) +- amount = get_indent_lnum(curwin->w_cursor.lnum - 1); +- else if (STRNCMP(look, lead_middle, +- lead_middle_len) == 0) +- { +- amount = get_indent_lnum(curwin->w_cursor.lnum - 1); +- break; +- } +- /* 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; +- } +- if (start_off != 0) +- amount += start_off; +- else if (start_align == COM_RIGHT) +- amount += vim_strsize(lead_start) +- - vim_strsize(lead_middle); +- break; +- } +- +- /* If our line starts with the end comment string, line it up +- * with the middle comment */ +- if (STRNCMP(theline, lead_middle, lead_middle_len) != 0 +- && STRNCMP(theline, lead_end, STRLEN(lead_end)) == 0) +- { +- amount = get_indent_lnum(curwin->w_cursor.lnum - 1); +- /* XXX */ +- if (off != 0) +- amount += off; +- else if (align == COM_RIGHT) +- amount += vim_strsize(lead_start) +- - vim_strsize(lead_middle); +- done = TRUE; +- break; +- } +- } +- } +- +- /* If our line starts with an asterisk, line up with the +- * asterisk in the comment opener; otherwise, line up +- * with the first character of the comment text. +- */ +- if (done) +- ; +- else if (theline[0] == '*') +- amount += 1; +- else +- { +- /* +- * If we are more than one line away from the comment opener, take +- * the indent of the previous non-empty line. If 'cino' has "CO" +- * and we are just below the comment opener and there are any +- * white characters after it line up with the text after it; +- * 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; +- amount = get_indent_lnum(lnum); /* XXX */ +- break; +- } +- if (amount == -1) /* use the comment opener */ +- { +- 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) +- { +- if (trypos != NULL && tryposBrace != NULL) +- { +- /* Both an unmatched '(' and '{' is found. Use the one which is +- * closer to the current cursor position, set the other to NULL. */ +- if (trypos->lnum != tryposBrace->lnum +- ? trypos->lnum < tryposBrace->lnum +- : trypos->col < tryposBrace->col) +- trypos = NULL; +- else +- tryposBrace = NULL; +- } +- +- if (trypos != NULL) +- { +- /* +- * If the matching paren is more than one line away, use the indent of +- * a previous non-empty line that matches the same paren. +- */ +- if (theline[0] == ')' && curbuf->b_ind_paren_prev) +- { +- /* Line up with the start of the matching paren line. */ +- amount = get_indent_lnum(curwin->w_cursor.lnum - 1); /* XXX */ +- } +- else +- { +- amount = -1; +- our_paren_pos = *trypos; +- for (lnum = cur_curpos.lnum - 1; lnum > our_paren_pos.lnum; --lnum) +- { +- l = skipwhite(ml_get(lnum)); +- if (cin_nocode(l)) /* skip comment lines */ +- continue; +- if (cin_ispreproc_cont(&l, &lnum, &amount)) +- continue; /* ignore #define, #if, etc. */ +- curwin->w_cursor.lnum = lnum; +- +- /* Skip a comment or raw string. XXX */ +- if ((trypos = ind_find_start_CORS(NULL)) != NULL) +- { +- lnum = trypos->lnum + 1; +- continue; +- } +- +- /* XXX */ +- if ((trypos = find_match_paren( +- corr_ind_maxparen(&cur_curpos))) != NULL +- && trypos->lnum == our_paren_pos.lnum +- && trypos->col == our_paren_pos.col) +- { +- amount = get_indent_lnum(lnum); /* XXX */ +- +- if (theline[0] == ')') +- { +- if (our_paren_pos.lnum != lnum +- && cur_amount > amount) +- cur_amount = amount; +- amount = -1; +- } +- break; +- } +- } +- } +- +- /* +- * Line up with line where the matching paren is. XXX +- * If the line starts with a '(' or the indent for unclosed +- * parentheses is zero, line up with the unclosed parentheses. +- */ +- if (amount == -1) +- { +- int ignore_paren_col = 0; +- int is_if_for_while = 0; +- +- if (curbuf->b_ind_if_for_while) +- { +- /* Look for the outermost opening parenthesis on this line +- * and check whether it belongs to an "if", "for" or "while". */ +- +- pos_T cursor_save = curwin->w_cursor; +- pos_T outermost; +- char_u *line; +- +- trypos = &our_paren_pos; +- do { +- outermost = *trypos; +- curwin->w_cursor.lnum = outermost.lnum; +- curwin->w_cursor.col = outermost.col; +- +- trypos = find_match_paren(curbuf->b_ind_maxparen); +- } while (trypos && trypos->lnum == outermost.lnum); +- +- curwin->w_cursor = cursor_save; +- +- line = ml_get(outermost.lnum); +- +- is_if_for_while = +- cin_is_if_for_while_before_offset(line, &outermost.col); +- } +- +- amount = skip_label(our_paren_pos.lnum, &look); +- look = skipwhite(look); +- if (*look == '(') +- { +- linenr_T save_lnum = curwin->w_cursor.lnum; +- char_u *line; +- int look_col; +- +- /* Ignore a '(' in front of the line that has a match before +- * our matching '('. */ +- curwin->w_cursor.lnum = our_paren_pos.lnum; +- line = ml_get_curline(); +- look_col = (int)(look - line); +- curwin->w_cursor.col = look_col + 1; +- if ((trypos = findmatchlimit(NULL, ')', 0, +- curbuf->b_ind_maxparen)) +- != NULL +- && trypos->lnum == our_paren_pos.lnum +- && trypos->col < our_paren_pos.col) +- ignore_paren_col = trypos->col + 1; +- +- curwin->w_cursor.lnum = save_lnum; +- look = ml_get(our_paren_pos.lnum) + look_col; +- } +- if (theline[0] == ')' || (curbuf->b_ind_unclosed == 0 +- && is_if_for_while == 0) +- || (!curbuf->b_ind_unclosed_noignore && *look == '(' +- && ignore_paren_col == 0)) +- { +- /* +- * If we're looking at a close paren, line up right there; +- * otherwise, line up with the next (non-white) character. +- * When b_ind_unclosed_wrapped is set and the matching paren is +- * the last nonwhite character of the line, use either the +- * indent of the current line or the indentation of the next +- * outer paren and add b_ind_unclosed_wrapped (for very long +- * lines). +- */ +- if (theline[0] != ')') +- { +- cur_amount = MAXCOL; +- l = ml_get(our_paren_pos.lnum); +- if (curbuf->b_ind_unclosed_wrapped +- && cin_ends_in(l, (char_u *)"(", NULL)) +- { +- /* look for opening unmatched paren, indent one level +- * for each additional level */ +- n = 1; +- for (col = 0; col < our_paren_pos.col; ++col) +- { +- switch (l[col]) +- { +- case '(': +- case '{': ++n; +- break; +- +- case ')': +- case '}': if (n > 1) +- --n; +- break; +- } +- } +- +- our_paren_pos.col = 0; +- amount += n * curbuf->b_ind_unclosed_wrapped; +- } +- else if (curbuf->b_ind_unclosed_whiteok) +- our_paren_pos.col++; +- else +- { +- col = our_paren_pos.col + 1; +- while (VIM_ISWHITE(l[col])) +- col++; +- if (l[col] != NUL) /* In case of trailing space */ +- our_paren_pos.col = col; +- else +- our_paren_pos.col++; +- } +- } +- +- /* +- * Find how indented the paren is, or the character after it +- * if we did the above "if". +- */ +- if (our_paren_pos.col > 0) +- { +- getvcol(curwin, &our_paren_pos, &col, NULL, NULL); +- if (cur_amount > (int)col) +- cur_amount = col; +- } +- } +- +- if (theline[0] == ')' && curbuf->b_ind_matching_paren) +- { +- /* Line up with the start of the matching paren line. */ +- } +- else if ((curbuf->b_ind_unclosed == 0 && is_if_for_while == 0) +- || (!curbuf->b_ind_unclosed_noignore +- && *look == '(' && ignore_paren_col == 0)) +- { +- if (cur_amount != MAXCOL) +- amount = cur_amount; +- } +- else +- { +- /* Add b_ind_unclosed2 for each '(' before our matching one, +- * but ignore (void) before the line (ignore_paren_col). */ +- col = our_paren_pos.col; +- while ((int)our_paren_pos.col > ignore_paren_col) +- { +- --our_paren_pos.col; +- switch (*ml_get_pos(&our_paren_pos)) +- { +- case '(': amount += curbuf->b_ind_unclosed2; +- col = our_paren_pos.col; +- break; +- case ')': amount -= curbuf->b_ind_unclosed2; +- col = MAXCOL; +- break; +- } +- } +- +- /* Use b_ind_unclosed once, when the first '(' is not inside +- * braces */ +- if (col == MAXCOL) +- amount += curbuf->b_ind_unclosed; +- else +- { +- curwin->w_cursor.lnum = our_paren_pos.lnum; +- curwin->w_cursor.col = col; +- if (find_match_paren_after_brace(curbuf->b_ind_maxparen) +- != NULL) +- amount += curbuf->b_ind_unclosed2; +- else +- { +- if (is_if_for_while) +- amount += curbuf->b_ind_if_for_while; +- else +- amount += curbuf->b_ind_unclosed; +- } +- } +- /* +- * For a line starting with ')' use the minimum of the two +- * positions, to avoid giving it more indent than the previous +- * lines: +- * func_long_name( if (x +- * arg && yy +- * ) ^ not here ) ^ not here +- */ +- if (cur_amount < amount) +- amount = cur_amount; +- } +- } +- +- /* add extra indent for a comment */ +- if (cin_iscomment(theline)) +- amount += curbuf->b_ind_comment; +- } +- else +- { +- /* +- * We are inside braces, there is a { before this line at the position +- * stored in tryposBrace. +- * 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); +- +- /* +- * Now figure out how indented the line is in general. +- * If the brace was at the start of the line, we use that; +- * otherwise, check out the indentation of the line as +- * a whole and then add the "imaginary indent" to that. +- */ +- look = skipwhite(start); +- if (*look == '{') +- { +- getvcol(curwin, trypos, &col, NULL, NULL); +- amount = col; +- if (*start == '{') +- start_brace = BRACE_IN_COL0; +- else +- start_brace = BRACE_AT_START; +- } +- else +- { +- /* That opening brace might have been on a continuation +- * line. if so, find the start of the line. */ +- curwin->w_cursor.lnum = ourscope; +- +- /* Position the cursor over the rightmost paren, so that +- * matching it will take us back to the start of the line. */ +- lnum = ourscope; +- if (find_last_paren(start, '(', ')') +- && (trypos = find_match_paren(curbuf->b_ind_maxparen)) +- != NULL) +- lnum = trypos->lnum; +- +- /* It could have been something like +- * case 1: if (asdf && +- * ldfd) { +- * } +- */ +- if ((curbuf->b_ind_js || curbuf->b_ind_keep_case_label) +- && cin_iscase(skipwhite(ml_get_curline()), FALSE)) +- amount = get_indent(); +- else if (curbuf->b_ind_js) +- amount = get_indent_lnum(lnum); +- else +- amount = skip_label(lnum, &l); +- +- start_brace = BRACE_AT_END; +- } +- +- /* For Javascript check if the line starts with "key:". */ +- if (curbuf->b_ind_js) +- js_cur_has_key = cin_has_js_key(theline); +- +- /* +- * If we're looking at a closing brace, that's where +- * we want to be. otherwise, add the amount of room +- * that an indent is supposed to be. +- */ +- if (theline[0] == '}') +- { +- /* +- * they may want closing braces to line up with something +- * other than the open brace. indulge them, if so. +- */ +- amount += curbuf->b_ind_close_extra; +- } +- else +- { +- /* +- * If we're looking at an "else", try to find an "if" +- * to match it with. +- * If we're looking at a "while", try to find a "do" +- * to match it with. +- */ +- lookfor = LOOKFOR_INITIAL; +- if (cin_iselse(theline)) +- lookfor = LOOKFOR_IF; +- else if (cin_iswhileofdo(theline, cur_curpos.lnum)) /* XXX */ +- lookfor = LOOKFOR_DO; +- if (lookfor != LOOKFOR_INITIAL) +- { +- curwin->w_cursor.lnum = cur_curpos.lnum; +- if (find_match(lookfor, ourscope) == OK) +- { +- amount = get_indent(); /* XXX */ +- goto theend; +- } +- } +- +- /* +- * We get here if we are not on an "while-of-do" or "else" (or +- * failed to find a matching "if"). +- * Search backwards for something to line up with. +- * First set amount for when we don't find anything. +- */ +- +- /* +- * if the '{' is _really_ at the left margin, use the imaginary +- * location of a left-margin brace. Otherwise, correct the +- * location for b_ind_open_extra. +- */ +- +- if (start_brace == BRACE_IN_COL0) /* '{' is in column 0 */ +- { +- amount = curbuf->b_ind_open_left_imag; +- lookfor_cpp_namespace = TRUE; +- } +- else if (start_brace == BRACE_AT_START && +- lookfor_cpp_namespace) /* '{' is at start */ +- { +- +- lookfor_cpp_namespace = TRUE; +- } +- else +- { +- if (start_brace == BRACE_AT_END) /* '{' is at end of line */ +- { +- amount += curbuf->b_ind_open_imag; +- +- l = skipwhite(ml_get_curline()); +- if (cin_is_cpp_namespace(l)) +- amount += curbuf->b_ind_cpp_namespace; +- else if (cin_is_cpp_extern_c(l)) +- amount += curbuf->b_ind_cpp_extern_c; +- } +- else +- { +- /* Compensate for adding b_ind_open_extra later. */ +- amount -= curbuf->b_ind_open_extra; +- if (amount < 0) +- amount = 0; +- } +- } +- +- lookfor_break = FALSE; +- +- if (cin_iscase(theline, FALSE)) /* it's a switch() label */ +- { +- lookfor = LOOKFOR_CASE; /* find a previous switch() label */ +- amount += curbuf->b_ind_case; +- } +- else if (cin_isscopedecl(theline)) /* private:, ... */ +- { +- lookfor = LOOKFOR_SCOPEDECL; /* class decl is this block */ +- amount += curbuf->b_ind_scopedecl; +- } +- else +- { +- if (curbuf->b_ind_case_break && cin_isbreak(theline)) +- /* break; ... */ +- lookfor_break = TRUE; +- +- lookfor = LOOKFOR_INITIAL; +- /* b_ind_level from start of block */ +- amount += curbuf->b_ind_level; +- } +- scope_amount = amount; +- whilelevel = 0; +- +- /* +- * Search backwards. If we find something we recognize, line up +- * with that. +- * +- * If we're looking at an open brace, indent +- * the usual amount relative to the conditional +- * that opens the block. +- */ +- curwin->w_cursor = cur_curpos; +- for (;;) +- { +- curwin->w_cursor.lnum--; +- curwin->w_cursor.col = 0; +- +- /* +- * If we went all the way back to the start of our scope, line +- * up with it. +- */ +- if (curwin->w_cursor.lnum <= ourscope) +- { +- /* We reached end of scope: +- * If looking for a enum or structure initialization +- * go further back: +- * If it is an initializer (enum xxx or xxx =), then +- * don't add ind_continuation, otherwise it is a variable +- * declaration: +- * int x, +- * here; <-- add ind_continuation +- */ +- if (lookfor == LOOKFOR_ENUM_OR_INIT) +- { +- if (curwin->w_cursor.lnum == 0 +- || curwin->w_cursor.lnum +- < ourscope - curbuf->b_ind_maxparen) +- { +- /* nothing found (abuse curbuf->b_ind_maxparen as +- * limit) assume terminated line (i.e. a variable +- * initialization) */ +- if (cont_amount > 0) +- amount = cont_amount; +- else if (!curbuf->b_ind_js) +- amount += ind_continuation; +- break; +- } +- +- 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(NULL); +- if (trypos != NULL) +- { +- curwin->w_cursor.lnum = trypos->lnum + 1; +- curwin->w_cursor.col = 0; +- continue; +- } +- +- /* +- * Skip preprocessor directives and blank lines. +- */ +- if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum, +- &amount)) +- continue; +- +- if (cin_nocode(l)) +- continue; +- +- terminated = cin_isterminated(l, FALSE, TRUE); +- +- /* +- * If we are at top level and the line looks like a +- * function declaration, we are done +- * (it's a variable declaration). +- */ +- if (start_brace != BRACE_IN_COL0 +- || !cin_isfuncdecl(&l, curwin->w_cursor.lnum, 0)) +- { +- /* if the line is terminated with another ',' +- * it is a continued variable initialization. +- * don't add extra indent. +- * TODO: does not work, if a function +- * declaration is split over multiple lines: +- * cin_isfuncdecl returns FALSE then. +- */ +- if (terminated == ',') +- break; +- +- /* if it es a enum declaration or an assignment, +- * we are done. +- */ +- if (terminated != ';' && cin_isinit()) +- break; +- +- /* nothing useful found */ +- if (terminated == 0 || terminated == '{') +- continue; +- } +- +- if (terminated != ';') +- { +- /* Skip parens and braces. Position the cursor +- * over the rightmost paren, so that matching it +- * will take us back to the start of the line. +- */ /* XXX */ +- trypos = NULL; +- if (find_last_paren(l, '(', ')')) +- trypos = find_match_paren( +- curbuf->b_ind_maxparen); +- +- if (trypos == NULL && find_last_paren(l, '{', '}')) +- trypos = find_start_brace(); +- +- if (trypos != NULL) +- { +- curwin->w_cursor.lnum = trypos->lnum + 1; +- curwin->w_cursor.col = 0; +- continue; +- } +- } +- +- /* it's a variable declaration, add indentation +- * like in +- * int a, +- * b; +- */ +- if (cont_amount > 0) +- amount = cont_amount; +- else +- amount += ind_continuation; +- } +- else if (lookfor == LOOKFOR_UNTERM) +- { +- if (cont_amount > 0) +- amount = cont_amount; +- else +- amount += ind_continuation; +- } +- else +- { +- if (lookfor != LOOKFOR_TERM +- && lookfor != LOOKFOR_CPP_BASECLASS +- && lookfor != LOOKFOR_COMMA) +- { +- amount = scope_amount; +- if (theline[0] == '{') +- { +- amount += curbuf->b_ind_open_extra; +- added_to_amount = curbuf->b_ind_open_extra; +- } +- } +- +- if (lookfor_cpp_namespace) +- { +- /* +- * Looking for C++ namespace, need to look further +- * back. +- */ +- if (curwin->w_cursor.lnum == ourscope) +- continue; +- +- if (curwin->w_cursor.lnum == 0 +- || curwin->w_cursor.lnum +- < ourscope - FIND_NAMESPACE_LIM) +- break; +- +- 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(NULL); +- if (trypos != NULL) +- { +- curwin->w_cursor.lnum = trypos->lnum + 1; +- curwin->w_cursor.col = 0; +- continue; +- } +- +- /* Skip preprocessor directives and blank lines. */ +- if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum, +- &amount)) +- continue; +- +- /* Finally the actual check for "namespace". */ +- if (cin_is_cpp_namespace(l)) +- { +- amount += curbuf->b_ind_cpp_namespace +- - added_to_amount; +- break; +- } +- else if (cin_is_cpp_extern_c(l)) +- { +- amount += curbuf->b_ind_cpp_extern_c +- - added_to_amount; +- break; +- } +- +- if (cin_nocode(l)) +- continue; +- } +- } +- break; +- } +- +- /* +- * If we're in a comment or raw string now, skip to the start +- * of it. +- */ /* XXX */ +- if ((trypos = ind_find_start_CORS(&raw_string_start)) != NULL) +- { +- curwin->w_cursor.lnum = trypos->lnum + 1; +- curwin->w_cursor.col = 0; +- continue; +- } +- +- l = ml_get_curline(); +- +- /* +- * If this is a switch() label, may line up relative to that. +- * If this is a C++ scope declaration, do the same. +- */ +- iscase = cin_iscase(l, FALSE); +- if (iscase || cin_isscopedecl(l)) +- { +- /* we are only looking for cpp base class +- * declaration/initialization any longer */ +- if (lookfor == LOOKFOR_CPP_BASECLASS) +- break; +- +- /* When looking for a "do" we are not interested in +- * labels. */ +- if (whilelevel > 0) +- continue; +- +- /* +- * case xx: +- * c = 99 + <- this indent plus continuation +- *-> here; +- */ +- if (lookfor == LOOKFOR_UNTERM +- || lookfor == LOOKFOR_ENUM_OR_INIT) +- { +- if (cont_amount > 0) +- amount = cont_amount; +- else +- amount += ind_continuation; +- break; +- } +- +- /* +- * case xx: <- line up with this case +- * x = 333; +- * case yy: +- */ +- if ( (iscase && lookfor == LOOKFOR_CASE) +- || (iscase && lookfor_break) +- || (!iscase && lookfor == LOOKFOR_SCOPEDECL)) +- { +- /* +- * Check that this case label is not for another +- * switch() +- */ /* XXX */ +- if ((trypos = find_start_brace()) == NULL +- || trypos->lnum == ourscope) +- { +- amount = get_indent(); /* XXX */ +- break; +- } +- continue; +- } +- +- n = get_indent_nolabel(curwin->w_cursor.lnum); /* XXX */ +- +- /* +- * case xx: if (cond) <- line up with this if +- * y = y + 1; +- * -> s = 99; +- * +- * case xx: +- * if (cond) <- line up with this line +- * y = y + 1; +- * -> s = 99; +- */ +- if (lookfor == LOOKFOR_TERM) +- { +- if (n) +- amount = n; +- +- if (!lookfor_break) +- break; +- } +- +- /* +- * case xx: x = x + 1; <- line up with this x +- * -> y = y + 1; +- * +- * case xx: if (cond) <- line up with this if +- * -> y = y + 1; +- */ +- if (n) +- { +- amount = n; +- l = after_label(ml_get_curline()); +- if (l != NULL && cin_is_cinword(l)) +- { +- if (theline[0] == '{') +- amount += curbuf->b_ind_open_extra; +- else +- amount += curbuf->b_ind_level +- + curbuf->b_ind_no_brace; +- } +- break; +- } +- +- /* +- * Try to get the indent of a statement before the switch +- * label. If nothing is found, line up relative to the +- * switch label. +- * break; <- may line up with this line +- * case xx: +- * -> y = 1; +- */ +- scope_amount = get_indent() + (iscase /* XXX */ +- ? curbuf->b_ind_case_code +- : curbuf->b_ind_scopedecl_code); +- lookfor = curbuf->b_ind_case_break +- ? LOOKFOR_NOBREAK : LOOKFOR_ANY; +- continue; +- } +- +- /* +- * Looking for a switch() label or C++ scope declaration, +- * ignore other lines, skip {}-blocks. +- */ +- if (lookfor == LOOKFOR_CASE || lookfor == LOOKFOR_SCOPEDECL) +- { +- if (find_last_paren(l, '{', '}') +- && (trypos = find_start_brace()) != NULL) +- { +- curwin->w_cursor.lnum = trypos->lnum + 1; +- curwin->w_cursor.col = 0; +- } +- continue; +- } +- +- /* +- * Ignore jump labels with nothing after them. +- */ +- if (!curbuf->b_ind_js && cin_islabel()) +- { +- l = after_label(ml_get_curline()); +- if (l == NULL || cin_nocode(l)) +- continue; +- } +- +- /* +- * Ignore #defines, #if, etc. +- * Ignore comment and empty lines. +- * (need to get the line again, cin_islabel() may have +- * unlocked it) +- */ +- l = ml_get_curline(); +- if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum, &amount) +- || cin_nocode(l)) +- continue; +- +- /* +- * Are we at the start of a cpp base class declaration or +- * constructor initialization? +- */ /* XXX */ +- n = FALSE; +- if (lookfor != LOOKFOR_TERM && curbuf->b_ind_cpp_baseclass > 0) +- { +- n = cin_is_cpp_baseclass(&cache_cpp_baseclass); +- l = ml_get_curline(); +- } +- if (n) +- { +- if (lookfor == LOOKFOR_UNTERM) +- { +- if (cont_amount > 0) +- amount = cont_amount; +- else +- amount += ind_continuation; +- } +- else if (theline[0] == '{') +- { +- /* Need to find start of the declaration. */ +- lookfor = LOOKFOR_UNTERM; +- ind_continuation = 0; +- continue; +- } +- else +- /* XXX */ +- amount = get_baseclass_amount( +- cache_cpp_baseclass.lpos.col); +- break; +- } +- else if (lookfor == LOOKFOR_CPP_BASECLASS) +- { +- /* only look, whether there is a cpp base class +- * declaration or initialization before the opening brace. +- */ +- if (cin_isterminated(l, TRUE, FALSE)) +- break; +- else +- continue; +- } +- +- /* +- * What happens next depends on the line being terminated. +- * If terminated with a ',' only consider it terminating if +- * there is another unterminated statement behind, eg: +- * 123, +- * sizeof +- * here +- * Otherwise check whether it is a enumeration or structure +- * initialisation (not indented) or a variable declaration +- * (indented). +- */ +- terminated = cin_isterminated(l, FALSE, TRUE); +- +- if (js_cur_has_key) +- { +- js_cur_has_key = 0; /* only check the first line */ +- if (curbuf->b_ind_js && terminated == ',') +- { +- /* For Javascript we might be inside an object: +- * key: something, <- align with this +- * key: something +- * or: +- * key: something + <- align with this +- * something, +- * key: something +- */ +- lookfor = LOOKFOR_JS_KEY; +- } +- } +- if (lookfor == LOOKFOR_JS_KEY && cin_has_js_key(l)) +- { +- amount = get_indent(); +- break; +- } +- if (lookfor == LOOKFOR_COMMA) +- { +- if (tryposBrace != NULL && tryposBrace->lnum +- >= curwin->w_cursor.lnum) +- break; +- if (terminated == ',') +- /* line below current line is the one that starts a +- * (possibly broken) line ending in a comma. */ +- break; +- else +- { +- amount = get_indent(); +- if (curwin->w_cursor.lnum - 1 == ourscope) +- /* line above is start of the scope, thus current +- * line is the one that stars a (possibly broken) +- * line ending in a comma. */ +- break; +- } +- } +- +- if (terminated == 0 || (lookfor != LOOKFOR_UNTERM +- && terminated == ',')) +- { +- if (lookfor != LOOKFOR_ENUM_OR_INIT && +- (*skipwhite(l) == '[' || l[STRLEN(l) - 1] == '[')) +- amount += ind_continuation; +- /* +- * if we're in the middle of a paren thing, +- * go back to the line that starts it so +- * we can get the right prevailing indent +- * if ( foo && +- * bar ) +- */ +- /* +- * Position the cursor over the rightmost paren, so that +- * matching it will take us back to the start of the line. +- * Ignore a match before the start of the block. +- */ +- (void)find_last_paren(l, '(', ')'); +- trypos = find_match_paren(corr_ind_maxparen(&cur_curpos)); +- if (trypos != NULL && (trypos->lnum < tryposBrace->lnum +- || (trypos->lnum == tryposBrace->lnum +- && trypos->col < tryposBrace->col))) +- trypos = NULL; +- +- /* +- * If we are looking for ',', we also look for matching +- * braces. +- */ +- if (trypos == NULL && terminated == ',' +- && find_last_paren(l, '{', '}')) +- trypos = find_start_brace(); +- +- if (trypos != NULL) +- { +- /* +- * Check if we are on a case label now. This is +- * handled above. +- * case xx: if ( asdf && +- * asdf) +- */ +- curwin->w_cursor = *trypos; +- l = ml_get_curline(); +- if (cin_iscase(l, FALSE) || cin_isscopedecl(l)) +- { +- ++curwin->w_cursor.lnum; +- curwin->w_cursor.col = 0; +- continue; +- } +- } +- +- /* +- * Skip over continuation lines to find the one to get the +- * indent from +- * char *usethis = "bla\ +- * bla", +- * here; +- */ +- if (terminated == ',') +- { +- while (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; +- } +- } +- +- /* +- * Get indent and pointer to text for current line, +- * ignoring any jump label. XXX +- */ +- if (curbuf->b_ind_js) +- cur_amount = get_indent(); +- else +- cur_amount = skip_label(curwin->w_cursor.lnum, &l); +- /* +- * If this is just above the line we are indenting, and it +- * starts with a '{', line it up with this line. +- * while (not) +- * -> { +- * } +- */ +- if (terminated != ',' && lookfor != LOOKFOR_TERM +- && theline[0] == '{') +- { +- amount = cur_amount; +- /* +- * Only add b_ind_open_extra when the current line +- * doesn't start with a '{', which must have a match +- * in the same line (scope is the same). Probably: +- * { 1, 2 }, +- * -> { 3, 4 } +- */ +- if (*skipwhite(l) != '{') +- amount += curbuf->b_ind_open_extra; +- +- if (curbuf->b_ind_cpp_baseclass && !curbuf->b_ind_js) +- { +- /* have to look back, whether it is a cpp base +- * class declaration or initialization */ +- lookfor = LOOKFOR_CPP_BASECLASS; +- continue; +- } +- break; +- } +- +- /* +- * Check if we are after an "if", "while", etc. +- * Also allow " } else". +- */ +- if (cin_is_cinword(l) || cin_iselse(skipwhite(l))) +- { +- /* +- * Found an unterminated line after an if (), line up +- * with the last one. +- * if (cond) +- * 100 + +- * -> here; +- */ +- if (lookfor == LOOKFOR_UNTERM +- || lookfor == LOOKFOR_ENUM_OR_INIT) +- { +- if (cont_amount > 0) +- amount = cont_amount; +- else +- amount += ind_continuation; +- break; +- } +- +- /* +- * If this is just above the line we are indenting, we +- * are finished. +- * while (not) +- * -> here; +- * Otherwise this indent can be used when the line +- * before this is terminated. +- * yyy; +- * if (stat) +- * while (not) +- * xxx; +- * -> here; +- */ +- amount = cur_amount; +- if (theline[0] == '{') +- amount += curbuf->b_ind_open_extra; +- if (lookfor != LOOKFOR_TERM) +- { +- amount += curbuf->b_ind_level +- + curbuf->b_ind_no_brace; +- break; +- } +- +- /* +- * Special trick: when expecting the while () after a +- * do, line up with the while() +- * do +- * x = 1; +- * -> here +- */ +- l = skipwhite(ml_get_curline()); +- if (cin_isdo(l)) +- { +- if (whilelevel == 0) +- break; +- --whilelevel; +- } +- +- /* +- * When searching for a terminated line, don't use the +- * one between the "if" and the matching "else". +- * Need to use the scope of this "else". XXX +- * If whilelevel != 0 continue looking for a "do {". +- */ +- if (cin_iselse(l) && whilelevel == 0) +- { +- /* If we're looking at "} else", let's make sure we +- * find the opening brace of the enclosing scope, +- * not the one from "if () {". */ +- if (*l == '}') +- curwin->w_cursor.col = +- (colnr_T)(l - ml_get_curline()) + 1; +- +- if ((trypos = find_start_brace()) == NULL +- || find_match(LOOKFOR_IF, trypos->lnum) +- == FAIL) +- break; +- } +- } +- +- /* +- * If we're below an unterminated line that is not an +- * "if" or something, we may line up with this line or +- * add something for a continuation line, depending on +- * the line before this one. +- */ +- else +- { +- /* +- * Found two unterminated lines on a row, line up with +- * the last one. +- * c = 99 + +- * 100 + +- * -> here; +- */ +- if (lookfor == LOOKFOR_UNTERM) +- { +- /* When line ends in a comma add extra indent */ +- if (terminated == ',') +- amount += ind_continuation; +- break; +- } +- +- if (lookfor == LOOKFOR_ENUM_OR_INIT) +- { +- /* Found two lines ending in ',', lineup with the +- * lowest one, but check for cpp base class +- * declaration/initialization, if it is an +- * opening brace or we are looking just for +- * enumerations/initializations. */ +- if (terminated == ',') +- { +- if (curbuf->b_ind_cpp_baseclass == 0) +- break; +- +- lookfor = LOOKFOR_CPP_BASECLASS; +- continue; +- } +- +- /* Ignore unterminated lines in between, but +- * reduce indent. */ +- if (amount > cur_amount) +- amount = cur_amount; +- } +- else +- { +- /* +- * Found first unterminated line on a row, may +- * line up with this line, remember its indent +- * 100 + +- * -> here; +- */ +- l = ml_get_curline(); +- amount = cur_amount; +- +- n = (int)STRLEN(l); +- if (terminated == ',' && (*skipwhite(l) == ']' +- || (n >=2 && l[n - 2] == ']'))) +- break; +- +- /* +- * If previous line ends in ',', check whether we +- * are in an initialization or enum +- * struct xxx = +- * { +- * sizeof a, +- * 124 }; +- * or a normal possible continuation line. +- * but only, of no other statement has been found +- * yet. +- */ +- if (lookfor == LOOKFOR_INITIAL && terminated == ',') +- { +- if (curbuf->b_ind_js) +- { +- /* Search for a line ending in a comma +- * and line up with the line below it +- * (could be the current line). +- * some = [ +- * 1, <- line up here +- * 2, +- * some = [ +- * 3 + <- line up here +- * 4 * +- * 5, +- * 6, +- */ +- if (cin_iscomment(skipwhite(l))) +- break; +- lookfor = LOOKFOR_COMMA; +- trypos = find_match_char('[', +- curbuf->b_ind_maxparen); +- if (trypos != NULL) +- { +- if (trypos->lnum +- == curwin->w_cursor.lnum - 1) +- { +- /* Current line is first inside +- * [], line up with it. */ +- break; +- } +- ourscope = trypos->lnum; +- } +- } +- else +- { +- lookfor = LOOKFOR_ENUM_OR_INIT; +- cont_amount = cin_first_id_amount(); +- } +- } +- else +- { +- if (lookfor == LOOKFOR_INITIAL +- && *l != NUL +- && l[STRLEN(l) - 1] == '\\') +- /* XXX */ +- cont_amount = cin_get_equal_amount( +- curwin->w_cursor.lnum); +- if (lookfor != LOOKFOR_TERM +- && lookfor != LOOKFOR_JS_KEY +- && lookfor != LOOKFOR_COMMA +- && raw_string_start != curwin->w_cursor.lnum) +- lookfor = LOOKFOR_UNTERM; +- } +- } +- } +- } +- +- /* +- * Check if we are after a while (cond); +- * If so: Ignore until the matching "do". +- */ +- else if (cin_iswhileofdo_end(terminated)) /* XXX */ +- { +- /* +- * Found an unterminated line after a while ();, line up +- * with the last one. +- * while (cond); +- * 100 + <- line up with this one +- * -> here; +- */ +- if (lookfor == LOOKFOR_UNTERM +- || lookfor == LOOKFOR_ENUM_OR_INIT) +- { +- if (cont_amount > 0) +- amount = cont_amount; +- else +- amount += ind_continuation; +- break; +- } +- +- if (whilelevel == 0) +- { +- lookfor = LOOKFOR_TERM; +- amount = get_indent(); /* XXX */ +- if (theline[0] == '{') +- amount += curbuf->b_ind_open_extra; +- } +- ++whilelevel; +- } +- +- /* +- * We are after a "normal" statement. +- * If we had another statement we can stop now and use the +- * indent of that other statement. +- * Otherwise the indent of the current statement may be used, +- * search backwards for the next "normal" statement. +- */ +- else +- { +- /* +- * Skip single break line, if before a switch label. It +- * may be lined up with the case label. +- */ +- if (lookfor == LOOKFOR_NOBREAK +- && cin_isbreak(skipwhite(ml_get_curline()))) +- { +- lookfor = LOOKFOR_ANY; +- continue; +- } +- +- /* +- * Handle "do {" line. +- */ +- if (whilelevel > 0) +- { +- l = cin_skipcomment(ml_get_curline()); +- if (cin_isdo(l)) +- { +- amount = get_indent(); /* XXX */ +- --whilelevel; +- continue; +- } +- } +- +- /* +- * Found a terminated line above an unterminated line. Add +- * the amount for a continuation line. +- * x = 1; +- * y = foo + +- * -> here; +- * or +- * int x = 1; +- * int foo, +- * -> here; +- */ +- if (lookfor == LOOKFOR_UNTERM +- || lookfor == LOOKFOR_ENUM_OR_INIT) +- { +- if (cont_amount > 0) +- amount = cont_amount; +- else +- amount += ind_continuation; +- break; +- } +- +- /* +- * Found a terminated line above a terminated line or "if" +- * etc. line. Use the amount of the line below us. +- * x = 1; x = 1; +- * if (asdf) y = 2; +- * while (asdf) ->here; +- * here; +- * ->foo; +- */ +- if (lookfor == LOOKFOR_TERM) +- { +- if (!lookfor_break && whilelevel == 0) +- break; +- } +- +- /* +- * First line above the one we're indenting is terminated. +- * To know what needs to be done look further backward for +- * a terminated line. +- */ +- else +- { +- /* +- * position the cursor over the rightmost paren, so +- * that matching it will take us back to the start of +- * the line. Helps for: +- * func(asdr, +- * asdfasdf); +- * here; +- */ +- term_again: +- l = ml_get_curline(); +- if (find_last_paren(l, '(', ')') +- && (trypos = find_match_paren( +- curbuf->b_ind_maxparen)) != NULL) +- { +- /* +- * Check if we are on a case label now. This is +- * handled above. +- * case xx: if ( asdf && +- * asdf) +- */ +- curwin->w_cursor = *trypos; +- l = ml_get_curline(); +- if (cin_iscase(l, FALSE) || cin_isscopedecl(l)) +- { +- ++curwin->w_cursor.lnum; +- curwin->w_cursor.col = 0; +- continue; +- } +- } +- +- /* When aligning with the case statement, don't align +- * with a statement after it. +- * case 1: { <-- don't use this { position +- * stat; +- * } +- * case 2: +- * stat; +- * } +- */ +- iscase = (curbuf->b_ind_keep_case_label +- && cin_iscase(l, FALSE)); +- +- /* +- * Get indent and pointer to text for current line, +- * ignoring any jump label. +- */ +- amount = skip_label(curwin->w_cursor.lnum, &l); +- +- if (theline[0] == '{') +- amount += curbuf->b_ind_open_extra; +- /* See remark above: "Only add b_ind_open_extra.." */ +- l = skipwhite(l); +- if (*l == '{') +- amount -= curbuf->b_ind_open_extra; +- lookfor = iscase ? LOOKFOR_ANY : LOOKFOR_TERM; +- +- /* +- * When a terminated line starts with "else" skip to +- * the matching "if": +- * else 3; +- * indent this; +- * Need to use the scope of this "else". XXX +- * If whilelevel != 0 continue looking for a "do {". +- */ +- if (lookfor == LOOKFOR_TERM +- && *l != '}' +- && cin_iselse(l) +- && whilelevel == 0) +- { +- if ((trypos = find_start_brace()) == NULL +- || find_match(LOOKFOR_IF, trypos->lnum) +- == FAIL) +- break; +- continue; +- } +- +- /* +- * If we're at the end of a block, skip to the start of +- * that block. +- */ +- l = ml_get_curline(); +- if (find_last_paren(l, '{', '}') /* XXX */ +- && (trypos = find_start_brace()) != NULL) +- { +- curwin->w_cursor = *trypos; +- /* if not "else {" check for terminated again */ +- /* but skip block for "} else {" */ +- l = cin_skipcomment(ml_get_curline()); +- if (*l == '}' || !cin_iselse(l)) +- goto term_again; +- ++curwin->w_cursor.lnum; +- curwin->w_cursor.col = 0; +- } +- } +- } +- } +- } +- } +- +- /* add extra indent for a comment */ +- if (cin_iscomment(theline)) +- amount += curbuf->b_ind_comment; +- +- /* 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)) != 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, &amount)) +- 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, &amount))) +- 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; +- } +- +- static int +- find_match(int lookfor, linenr_T ourscope) +- { +- char_u *look; +- pos_T *theirscope; +- char_u *mightbeif; +- int elselevel; +- int whilelevel; +- +- if (lookfor == LOOKFOR_IF) +- { +- elselevel = 1; +- whilelevel = 0; +- } +- else +- { +- elselevel = 0; +- whilelevel = 1; +- } +- +- curwin->w_cursor.col = 0; +- +- while (curwin->w_cursor.lnum > ourscope + 1) +- { +- curwin->w_cursor.lnum--; +- curwin->w_cursor.col = 0; +- +- look = cin_skipcomment(ml_get_curline()); +- if (cin_iselse(look) +- || cin_isif(look) +- || cin_isdo(look) /* XXX */ +- || cin_iswhileofdo(look, curwin->w_cursor.lnum)) +- { +- /* +- * if we've gone outside the braces entirely, +- * we must be out of scope... +- */ +- theirscope = find_start_brace(); /* XXX */ +- if (theirscope == NULL) +- break; +- +- /* +- * and if the brace enclosing this is further +- * back than the one enclosing the else, we're +- * out of luck too. +- */ +- if (theirscope->lnum < ourscope) +- break; +- +- /* +- * and if they're enclosed in a *deeper* brace, +- * then we can ignore it because it's in a +- * different scope... +- */ +- if (theirscope->lnum > ourscope) +- continue; +- +- /* +- * if it was an "else" (that's not an "else if") +- * then we need to go back to another if, so +- * increment elselevel +- */ +- look = cin_skipcomment(ml_get_curline()); +- if (cin_iselse(look)) +- { +- mightbeif = cin_skipcomment(look + 4); +- if (!cin_isif(mightbeif)) +- ++elselevel; +- continue; +- } +- +- /* +- * if it was a "while" then we need to go back to +- * another "do", so increment whilelevel. XXX +- */ +- if (cin_iswhileofdo(look, curwin->w_cursor.lnum)) +- { +- ++whilelevel; +- continue; +- } +- +- /* If it's an "if" decrement elselevel */ +- look = cin_skipcomment(ml_get_curline()); +- if (cin_isif(look)) +- { +- elselevel--; +- /* +- * When looking for an "if" ignore "while"s that +- * get in the way. +- */ +- if (elselevel == 0 && lookfor == LOOKFOR_IF) +- whilelevel = 0; +- } +- +- /* If it's a "do" decrement whilelevel */ +- if (cin_isdo(look)) +- whilelevel--; +- +- /* +- * if we've used up all the elses, then +- * this must be the if that we want! +- * match the indent level of that if. +- */ +- if (elselevel <= 0 && whilelevel <= 0) +- { +- return OK; +- } +- } +- } +- return FAIL; +- } +- +- # if defined(FEAT_EVAL) || defined(PROTO) +- /* +- * Get indent level from 'indentexpr'. +- */ +- int +- get_expr_indent(void) +- { +- int indent = -1; +- char_u *inde_copy; +- pos_T save_pos; +- colnr_T save_curswant; +- int save_set_curswant; +- int save_State; +- int use_sandbox = was_set_insecurely((char_u *)"indentexpr", +- OPT_LOCAL); +- +- /* Save and restore cursor position and curswant, in case it was changed +- * via :normal commands */ +- save_pos = curwin->w_cursor; +- save_curswant = curwin->w_curswant; +- save_set_curswant = curwin->w_set_curswant; +- set_vim_var_nr(VV_LNUM, curwin->w_cursor.lnum); +- if (use_sandbox) +- ++sandbox; +- ++textlock; +- +- /* Need to make a copy, the 'indentexpr' option could be changed while +- * evaluating it. */ +- inde_copy = vim_strsave(curbuf->b_p_inde); +- if (inde_copy != NULL) +- { +- indent = (int)eval_to_number(inde_copy); +- vim_free(inde_copy); +- } +- +- if (use_sandbox) +- --sandbox; +- --textlock; +- +- /* Restore the cursor position so that 'indentexpr' doesn't need to. +- * Pretend to be in Insert mode, allow cursor past end of line for "o" +- * command. */ +- save_State = State; +- State = INSERT; +- curwin->w_cursor = save_pos; +- curwin->w_curswant = save_curswant; +- curwin->w_set_curswant = save_set_curswant; +- check_cursor(); +- State = save_State; +- +- /* If there is an error, just keep the current indent. */ +- if (indent < 0) +- indent = get_indent(); +- +- return indent; +- } +- # endif +- +- #endif /* FEAT_CINDENT */ +- +- #if defined(FEAT_LISP) || defined(PROTO) +- +- static int +- lisp_match(char_u *p) +- { +- char_u buf[LSIZE]; +- int len; +- char_u *word = *curbuf->b_p_lw != NUL ? curbuf->b_p_lw : p_lispwords; +- +- while (*word != NUL) +- { +- (void)copy_option_part(&word, buf, LSIZE, ","); +- len = (int)STRLEN(buf); +- if (STRNCMP(buf, p, len) == 0 && p[len] == ' ') +- return TRUE; +- } +- return FALSE; +- } +- +- /* +- * When 'p' is present in 'cpoptions, a Vi compatible method is used. +- * The incompatible newer method is quite a bit better at indenting +- * code in lisp-like languages than the traditional one; it's still +- * mostly heuristics however -- Dirk van Deun, dirk@rave.org +- * +- * TODO: +- * Findmatch() should be adapted for lisp, also to make showmatch +- * work correctly: now (v5.3) it seems all C/C++ oriented: +- * - it does not recognize the #\( and #\) notations as character literals +- * - it doesn't know about comments starting with a semicolon +- * - it incorrectly interprets '(' as a character literal +- * All this messes up get_lisp_indent in some rare cases. +- * Update from Sergey Khorev: +- * I tried to fix the first two issues. +- */ +- int +- get_lisp_indent(void) +- { +- pos_T *pos, realpos, paren; +- int amount; +- char_u *that; +- colnr_T col; +- colnr_T firsttry; +- int parencount, quotecount; +- int vi_lisp; +- +- /* Set vi_lisp to use the vi-compatible method */ +- vi_lisp = (vim_strchr(p_cpo, CPO_LISP) != NULL); +- +- realpos = curwin->w_cursor; +- curwin->w_cursor.col = 0; +- +- if ((pos = findmatch(NULL, '(')) == NULL) +- pos = findmatch(NULL, '['); +- else +- { +- paren = *pos; +- pos = findmatch(NULL, '['); +- if (pos == NULL || LT_POSP(pos, &paren)) +- pos = &paren; +- } +- if (pos != NULL) +- { +- /* Extra trick: Take the indent of the first previous non-white +- * line that is at the same () level. */ +- amount = -1; +- parencount = 0; +- +- while (--curwin->w_cursor.lnum >= pos->lnum) +- { +- if (linewhite(curwin->w_cursor.lnum)) +- continue; +- for (that = ml_get_curline(); *that != NUL; ++that) +- { +- if (*that == ';') +- { +- while (*(that + 1) != NUL) +- ++that; +- continue; +- } +- if (*that == '\\') +- { +- if (*(that + 1) != NUL) +- ++that; +- continue; +- } +- if (*that == '"' && *(that + 1) != NUL) +- { +- while (*++that && *that != '"') +- { +- /* skipping escaped characters in the string */ +- if (*that == '\\') +- { +- if (*++that == NUL) +- break; +- if (that[1] == NUL) +- { +- ++that; +- break; +- } +- } +- } +- } +- if (*that == '(' || *that == '[') +- ++parencount; +- else if (*that == ')' || *that == ']') +- --parencount; +- } +- if (parencount == 0) +- { +- amount = get_indent(); +- break; +- } +- } +- +- if (amount == -1) +- { +- curwin->w_cursor.lnum = pos->lnum; +- curwin->w_cursor.col = pos->col; +- col = pos->col; +- +- that = ml_get_curline(); +- +- if (vi_lisp && get_indent() == 0) +- amount = 2; +- else +- { +- char_u *line = that; +- +- amount = 0; +- while (*that && col) +- { +- amount += lbr_chartabsize_adv(line, &that, (colnr_T)amount); +- col--; +- } +- +- /* +- * Some keywords require "body" indenting rules (the +- * non-standard-lisp ones are Scheme special forms): +- * +- * (let ((a 1)) instead (let ((a 1)) +- * (...)) of (...)) +- */ +- +- if (!vi_lisp && (*that == '(' || *that == '[') +- && lisp_match(that + 1)) +- amount += 2; +- else +- { +- that++; +- amount++; +- firsttry = amount; +- +- while (VIM_ISWHITE(*that)) +- { +- amount += lbr_chartabsize(line, that, (colnr_T)amount); +- ++that; +- } +- +- if (*that && *that != ';') /* not a comment line */ +- { +- /* test *that != '(' to accommodate first let/do +- * argument if it is more than one line */ +- if (!vi_lisp && *that != '(' && *that != '[') +- firsttry++; +- +- parencount = 0; +- quotecount = 0; +- +- if (vi_lisp +- || (*that != '"' +- && *that != '\'' +- && *that != '#' +- && (*that < '0' || *that > '9'))) +- { +- while (*that +- && (!VIM_ISWHITE(*that) +- || quotecount +- || parencount) +- && (!((*that == '(' || *that == '[') +- && !quotecount +- && !parencount +- && vi_lisp))) +- { +- if (*that == '"') +- quotecount = !quotecount; +- if ((*that == '(' || *that == '[') +- && !quotecount) +- ++parencount; +- if ((*that == ')' || *that == ']') +- && !quotecount) +- --parencount; +- if (*that == '\\' && *(that+1) != NUL) +- amount += lbr_chartabsize_adv( +- line, &that, (colnr_T)amount); +- amount += lbr_chartabsize_adv( +- line, &that, (colnr_T)amount); +- } +- } +- while (VIM_ISWHITE(*that)) +- { +- amount += lbr_chartabsize( +- line, that, (colnr_T)amount); +- that++; +- } +- if (!*that || *that == ';') +- amount = firsttry; +- } +- } +- } +- } +- } +- else +- amount = 0; /* no matching '(' or '[' found, use zero indent */ +- +- curwin->w_cursor = realpos; +- +- return amount; +- } +- #endif /* FEAT_LISP */ +- + void + prepare_to_exit(void) + { +--- 5369,5374 ---- +*** ../vim-8.1.0856/src/proto.h 2019-01-26 16:20:44.264683546 +0100 +--- src/proto.h 2019-01-31 13:43:23.356467234 +0100 +*************** +*** 87,92 **** +--- 87,93 ---- + # endif + # include "hardcopy.pro" + # include "hashtab.pro" ++ # include "indent.pro" + # include "json.pro" + # include "list.pro" + # include "blob.pro" +*** ../vim-8.1.0856/src/proto/edit.pro 2018-11-22 03:07:30.948596188 +0100 +--- src/proto/edit.pro 2019-01-31 13:45:12.275722540 +0100 +*************** +*** 38,46 **** + char_u *get_last_insert_save(void); + void replace_push(int c); + int replace_push_mb(char_u *p); +- void fixthisline(int (*get_the_indent)(void)); +- void fix_indent(void); +- int in_cinkeys(int keytyped, int when, int line_is_empty); + int hkmap(int c); + int bracketed_paste(paste_mode_T mode, int drop, garray_T *gap); + void ins_scroll(void); +--- 38,43 ---- +*** ../vim-8.1.0856/src/proto/indent.pro 2019-01-31 13:47:08.570924989 +0100 +--- src/proto/indent.pro 2019-01-31 13:45:17.403687423 +0100 +*************** +*** 0 **** +--- 1,16 ---- ++ /* indent.c */ ++ int cin_is_cinword(char_u *line); ++ pos_T *find_start_comment(int ind_maxcomment); ++ int cindent_on(void); ++ int cin_islabel(void); ++ int cin_iscase(char_u *s, int strict); ++ int cin_isscopedecl(char_u *s); ++ void parse_cino(buf_T *buf); ++ int get_c_indent(void); ++ int get_expr_indent(void); ++ int in_cinkeys(int keytyped, int when, int line_is_empty); ++ int get_lisp_indent(void); ++ void do_c_expr_indent(void); ++ void fixthisline(int (*get_the_indent)(void)); ++ void fix_indent(void); ++ /* vim: set ft=c : */ +*** ../vim-8.1.0856/src/proto/misc1.pro 2019-01-02 00:02:07.607556145 +0100 +--- src/proto/misc1.pro 2019-01-31 13:45:20.359667178 +0100 +*************** +*** 83,97 **** + char_u *concat_str(char_u *str1, char_u *str2); + void add_pathsep(char_u *p); + char_u *FullName_save(char_u *fname, int force); +- pos_T *find_start_comment(int ind_maxcomment); +- void do_c_expr_indent(void); +- int cin_islabel(void); +- int cin_iscase(char_u *s, int strict); +- int cin_isscopedecl(char_u *s); +- void parse_cino(buf_T *buf); +- int get_c_indent(void); +- int get_expr_indent(void); +- int get_lisp_indent(void); + void prepare_to_exit(void); + void preserve_exit(void); + int vim_fexists(char_u *fname); +--- 83,88 ---- +*** ../vim-8.1.0856/src/version.c 2019-01-31 13:22:28.068543628 +0100 +--- src/version.c 2019-01-31 13:45:27.287619720 +0100 +*************** +*** 785,786 **** +--- 785,788 ---- + { /* Add new patch number below this line */ ++ /**/ ++ 857, + /**/ + +-- + [SIR LAUNCELOT runs back up the stairs, grabs a rope + of the wall and swings out over the heads of the CROWD in a + swashbuckling manner towards a large window. He stops just short + of the window and is left swing pathetically back and forth.] +LAUNCELOT: Excuse me ... could somebody give me a push ... + "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD + + /// 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 /// |