• R/O
  • SSH

vim: Commit

Mirror of the Vim source from https://github.com/vim/vim


Commit MetaInfo

Revisionfe5afdc03bd2a06cacccf67b7cf93d33906e97eb (tree)
Time2019-10-10 06:00:04
AuthorBram Moolenaar <Bram@vim....>
CommiterBram Moolenaar

Log Message

patch 8.1.2127: the indent.c file is a bit big

Commit: https://github.com/vim/vim/commit/14c01f83487d5c53192297a710eda2b8a4ab17c9
Author: Bram Moolenaar <Bram@vim.org>
Date: Wed Oct 9 22:53:08 2019 +0200

patch 8.1.2127: the indent.c file is a bit big
Problem: The indent.c file is a bit big.
Solution: Move C-indent code a a new cindent.c file. Move other
indent-related code to indent.c. (Yegappan Lakshmanan,
closes #5031)

Change Summary

Incremental Difference

diff -r 5202d9b99bee -r fe5afdc03bd2 Filelist
--- a/Filelist Wed Oct 09 22:15:04 2019 +0200
+++ b/Filelist Wed Oct 09 23:00:04 2019 +0200
@@ -25,6 +25,7 @@
2525 src/change.c \
2626 src/channel.c \
2727 src/charset.c \
28+ src/cindent.c \
2829 src/cmdexpand.c \
2930 src/cmdhist.c \
3031 src/crypt.c \
@@ -191,6 +192,7 @@
191192 src/proto/change.pro \
192193 src/proto/channel.pro \
193194 src/proto/charset.pro \
195+ src/proto/cindent.pro \
194196 src/proto/cmdexpand.pro \
195197 src/proto/cmdhist.pro \
196198 src/proto/crypt.pro \
diff -r 5202d9b99bee -r fe5afdc03bd2 src/Make_cyg_ming.mak
--- a/src/Make_cyg_ming.mak Wed Oct 09 22:15:04 2019 +0200
+++ b/src/Make_cyg_ming.mak Wed Oct 09 23:00:04 2019 +0200
@@ -712,6 +712,7 @@
712712 $(OUTDIR)/bufwrite.o \
713713 $(OUTDIR)/change.o \
714714 $(OUTDIR)/charset.o \
715+ $(OUTDIR)/cindent.o \
715716 $(OUTDIR)/cmdexpand.o \
716717 $(OUTDIR)/cmdhist.o \
717718 $(OUTDIR)/crypt.o \
diff -r 5202d9b99bee -r fe5afdc03bd2 src/Make_morph.mak
--- a/src/Make_morph.mak Wed Oct 09 22:15:04 2019 +0200
+++ b/src/Make_morph.mak Wed Oct 09 23:00:04 2019 +0200
@@ -32,6 +32,7 @@
3232 bufwrite.c \
3333 change.c \
3434 charset.c \
35+ cindent.c \
3536 cmdexpand.c \
3637 cmdhist.c \
3738 crypt.c \
diff -r 5202d9b99bee -r fe5afdc03bd2 src/Make_mvc.mak
--- a/src/Make_mvc.mak Wed Oct 09 22:15:04 2019 +0200
+++ b/src/Make_mvc.mak Wed Oct 09 23:00:04 2019 +0200
@@ -719,6 +719,7 @@
719719 $(OUTDIR)\bufwrite.obj \
720720 $(OUTDIR)\change.obj \
721721 $(OUTDIR)\charset.obj \
722+ $(OUTDIR)\cindent.obj \
722723 $(OUTDIR)\cmdexpand.obj \
723724 $(OUTDIR)\cmdhist.obj \
724725 $(OUTDIR)\crypt.obj \
@@ -1464,6 +1465,8 @@
14641465
14651466 $(OUTDIR)/charset.obj: $(OUTDIR) charset.c $(INCL)
14661467
1468+$(OUTDIR)/cindent.obj: $(OUTDIR) cindent.c $(INCL)
1469+
14671470 $(OUTDIR)/cmdexpand.obj: $(OUTDIR) cmdexpand.c $(INCL)
14681471
14691472 $(OUTDIR)/cmdhist.obj: $(OUTDIR) cmdhist.c $(INCL)
@@ -1794,6 +1797,7 @@
17941797 proto/bufwrite.pro \
17951798 proto/change.pro \
17961799 proto/charset.pro \
1800+ proto/cindent.pro \
17971801 proto/cmdexpand.pro \
17981802 proto/cmdhist.pro \
17991803 proto/crypt.pro \
diff -r 5202d9b99bee -r fe5afdc03bd2 src/Make_vms.mms
--- a/src/Make_vms.mms Wed Oct 09 22:15:04 2019 +0200
+++ b/src/Make_vms.mms Wed Oct 09 23:00:04 2019 +0200
@@ -318,6 +318,7 @@
318318 bufwrite.c \
319319 change.c \
320320 charset.c \
321+ cindent.c \
321322 cmdexpand.c \
322323 cmdhist.c \
323324 crypt.c \
@@ -420,6 +421,7 @@
420421 bufwrite.obj \
421422 change.obj \
422423 charset.obj \
424+ cindent.obj \
423425 cmdexpand.obj \
424426 cmdhist.obj \
425427 crypt.obj \
@@ -700,6 +702,10 @@
700702 ascii.h keymap.h term.h macros.h structs.h regexp.h \
701703 gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
702704 globals.h
705+cindent.obj : cindent.c vim.h [.auto]config.h feature.h os_unix.h \
706+ ascii.h keymap.h term.h macros.h structs.h regexp.h \
707+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
708+ globals.h
703709 cmdexpand.obj : cmdexpand.c vim.h [.auto]config.h feature.h os_unix.h \
704710 ascii.h keymap.h term.h macros.h structs.h regexp.h \
705711 gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
diff -r 5202d9b99bee -r fe5afdc03bd2 src/Makefile
--- a/src/Makefile Wed Oct 09 22:15:04 2019 +0200
+++ b/src/Makefile Wed Oct 09 23:00:04 2019 +0200
@@ -1585,6 +1585,7 @@
15851585 buffer.c \
15861586 change.c \
15871587 charset.c \
1588+ cindent.c \
15881589 cmdexpand.c \
15891590 cmdhist.c \
15901591 crypt.c \
@@ -1725,6 +1726,7 @@
17251726 objects/change.o \
17261727 objects/blob.o \
17271728 objects/blowfish.o \
1729+ objects/cindent.o \
17281730 objects/cmdexpand.o \
17291731 objects/cmdhist.o \
17301732 objects/crypt.o \
@@ -1878,6 +1880,7 @@
18781880 buffer.pro \
18791881 change.pro \
18801882 charset.pro \
1883+ cindent.pro \
18811884 cmdexpand.pro \
18821885 cmdhist.pro \
18831886 crypt.pro \
@@ -3081,6 +3084,9 @@
30813084 objects/charset.o: charset.c
30823085 $(CCC) -o $@ charset.c
30833086
3087+objects/cindent.o: cindent.c
3088+ $(CCC) -o $@ cindent.c
3089+
30843090 objects/cmdexpand.o: cmdexpand.c
30853091 $(CCC) -o $@ cmdexpand.c
30863092
@@ -3621,6 +3627,10 @@
36213627 auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
36223628 proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
36233629 proto.h globals.h
3630+objects/cindent.o: cindent.c vim.h protodef.h auto/config.h feature.h os_unix.h \
3631+ auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
3632+ proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
3633+ proto.h globals.h
36243634 objects/cmdexpand.o: cmdexpand.c vim.h protodef.h auto/config.h feature.h os_unix.h \
36253635 auto/osdef.h ascii.h keymap.h term.h macros.h option.h beval.h \
36263636 proto/gui_beval.pro structs.h regexp.h gui.h alloc.h ex_cmds.h spell.h \
diff -r 5202d9b99bee -r fe5afdc03bd2 src/README.md
--- a/src/README.md Wed Oct 09 22:15:04 2019 +0200
+++ b/src/README.md Wed Oct 09 23:00:04 2019 +0200
@@ -29,6 +29,7 @@
2929 buffer.c | manipulating buffers (loaded files)
3030 bufwrite.c | writing a buffer to file
3131 change.c | handling changes to text
32+cindent.c | C and Lisp indentation
3233 cmdexpand.c | command-line completion
3334 cmdhist.c | command-line history
3435 debugger.c | vim script debugger
@@ -46,7 +47,7 @@
4647 fold.c | folding
4748 getchar.c | getting characters and key mapping
4849 highlight.c | syntax highlighting
49-indent.c | C and Lisp indentation
50+indent.c | text indentation
5051 insexpand.c | Insert mode completion
5152 mark.c | marks
5253 map.c | mapping and abbreviations
diff -r 5202d9b99bee -r fe5afdc03bd2 src/change.c
--- a/src/change.c Wed Oct 09 22:15:04 2019 +0200
+++ b/src/change.c Wed Oct 09 23:00:04 2019 +0200
@@ -1251,151 +1251,6 @@
12511251 }
12521252
12531253 /*
1254- * Copy the indent from ptr to the current line (and fill to size)
1255- * Leaves the cursor on the first non-blank in the line.
1256- * Returns TRUE if the line was changed.
1257- */
1258- static int
1259-copy_indent(int size, char_u *src)
1260-{
1261- char_u *p = NULL;
1262- char_u *line = NULL;
1263- char_u *s;
1264- int todo;
1265- int ind_len;
1266- int line_len = 0;
1267- int tab_pad;
1268- int ind_done;
1269- int round;
1270-#ifdef FEAT_VARTABS
1271- int ind_col;
1272-#endif
1273-
1274- // Round 1: compute the number of characters needed for the indent
1275- // Round 2: copy the characters.
1276- for (round = 1; round <= 2; ++round)
1277- {
1278- todo = size;
1279- ind_len = 0;
1280- ind_done = 0;
1281-#ifdef FEAT_VARTABS
1282- ind_col = 0;
1283-#endif
1284- s = src;
1285-
1286- // Count/copy the usable portion of the source line
1287- while (todo > 0 && VIM_ISWHITE(*s))
1288- {
1289- if (*s == TAB)
1290- {
1291-#ifdef FEAT_VARTABS
1292- tab_pad = tabstop_padding(ind_done, curbuf->b_p_ts,
1293- curbuf->b_p_vts_array);
1294-#else
1295- tab_pad = (int)curbuf->b_p_ts
1296- - (ind_done % (int)curbuf->b_p_ts);
1297-#endif
1298- // Stop if this tab will overshoot the target
1299- if (todo < tab_pad)
1300- break;
1301- todo -= tab_pad;
1302- ind_done += tab_pad;
1303-#ifdef FEAT_VARTABS
1304- ind_col += tab_pad;
1305-#endif
1306- }
1307- else
1308- {
1309- --todo;
1310- ++ind_done;
1311-#ifdef FEAT_VARTABS
1312- ++ind_col;
1313-#endif
1314- }
1315- ++ind_len;
1316- if (p != NULL)
1317- *p++ = *s;
1318- ++s;
1319- }
1320-
1321- // Fill to next tabstop with a tab, if possible
1322-#ifdef FEAT_VARTABS
1323- tab_pad = tabstop_padding(ind_done, curbuf->b_p_ts,
1324- curbuf->b_p_vts_array);
1325-#else
1326- tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts);
1327-#endif
1328- if (todo >= tab_pad && !curbuf->b_p_et)
1329- {
1330- todo -= tab_pad;
1331- ++ind_len;
1332-#ifdef FEAT_VARTABS
1333- ind_col += tab_pad;
1334-#endif
1335- if (p != NULL)
1336- *p++ = TAB;
1337- }
1338-
1339- // Add tabs required for indent
1340- if (!curbuf->b_p_et)
1341- {
1342-#ifdef FEAT_VARTABS
1343- for (;;)
1344- {
1345- tab_pad = tabstop_padding(ind_col, curbuf->b_p_ts,
1346- curbuf->b_p_vts_array);
1347- if (todo < tab_pad)
1348- break;
1349- todo -= tab_pad;
1350- ++ind_len;
1351- ind_col += tab_pad;
1352- if (p != NULL)
1353- *p++ = TAB;
1354- }
1355-#else
1356- while (todo >= (int)curbuf->b_p_ts)
1357- {
1358- todo -= (int)curbuf->b_p_ts;
1359- ++ind_len;
1360- if (p != NULL)
1361- *p++ = TAB;
1362- }
1363-#endif
1364- }
1365-
1366- // Count/add spaces required for indent
1367- while (todo > 0)
1368- {
1369- --todo;
1370- ++ind_len;
1371- if (p != NULL)
1372- *p++ = ' ';
1373- }
1374-
1375- if (p == NULL)
1376- {
1377- // Allocate memory for the result: the copied indent, new indent
1378- // and the rest of the line.
1379- line_len = (int)STRLEN(ml_get_curline()) + 1;
1380- line = alloc(ind_len + line_len);
1381- if (line == NULL)
1382- return FALSE;
1383- p = line;
1384- }
1385- }
1386-
1387- // Append the original line
1388- mch_memmove(p, ml_get_curline(), (size_t)line_len);
1389-
1390- // Replace the line
1391- ml_replace(curwin->w_cursor.lnum, line, FALSE);
1392-
1393- // Put the cursor after the indent.
1394- curwin->w_cursor.col = ind_len;
1395- return TRUE;
1396-}
1397-
1398-/*
13991254 * open_line: Add a new line below or above the current line.
14001255 *
14011256 * For VREPLACE mode, we only add a new line when we get to the end of the
diff -r 5202d9b99bee -r fe5afdc03bd2 src/cindent.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cindent.c Wed Oct 09 23:00:04 2019 +0200
@@ -0,0 +1,4133 @@
1+/* vi:set ts=8 sts=4 sw=4 noet:
2+ *
3+ * VIM - Vi IMproved by Bram Moolenaar
4+ *
5+ * Do ":help uganda" in Vim to read copying and usage conditions.
6+ * Do ":help credits" in Vim to see a list of people who contributed.
7+ * See README.txt for an overview of the Vim source code.
8+ */
9+
10+/*
11+ * cindent.c: C indentation related functions
12+ *
13+ * Many of C-indenting functions originally come from Eric Fischer.
14+ *
15+ * Below "XXX" means that this function may unlock the current line.
16+ */
17+
18+#include "vim.h"
19+
20+// values for the "lookfor" state
21+#define LOOKFOR_INITIAL 0
22+#define LOOKFOR_IF 1
23+#define LOOKFOR_DO 2
24+#define LOOKFOR_CASE 3
25+#define LOOKFOR_ANY 4
26+#define LOOKFOR_TERM 5
27+#define LOOKFOR_UNTERM 6
28+#define LOOKFOR_SCOPEDECL 7
29+#define LOOKFOR_NOBREAK 8
30+#define LOOKFOR_CPP_BASECLASS 9
31+#define LOOKFOR_ENUM_OR_INIT 10
32+#define LOOKFOR_JS_KEY 11
33+#define LOOKFOR_COMMA 12
34+
35+#if defined(FEAT_CINDENT) || defined(FEAT_SMARTINDENT)
36+/*
37+ * Return TRUE if the string "line" starts with a word from 'cinwords'.
38+ */
39+ int
40+cin_is_cinword(char_u *line)
41+{
42+ char_u *cinw;
43+ char_u *cinw_buf;
44+ int cinw_len;
45+ int retval = FALSE;
46+ int len;
47+
48+ cinw_len = (int)STRLEN(curbuf->b_p_cinw) + 1;
49+ cinw_buf = alloc(cinw_len);
50+ if (cinw_buf != NULL)
51+ {
52+ line = skipwhite(line);
53+ for (cinw = curbuf->b_p_cinw; *cinw; )
54+ {
55+ len = copy_option_part(&cinw, cinw_buf, cinw_len, ",");
56+ if (STRNCMP(line, cinw_buf, len) == 0
57+ && (!vim_iswordc(line[len]) || !vim_iswordc(line[len - 1])))
58+ {
59+ retval = TRUE;
60+ break;
61+ }
62+ }
63+ vim_free(cinw_buf);
64+ }
65+ return retval;
66+}
67+#endif
68+
69+#if defined(FEAT_CINDENT) || defined(FEAT_SYN_HL)
70+
71+/*
72+ * Skip to the end of a "string" and a 'c' character.
73+ * If there is no string or character, return argument unmodified.
74+ */
75+ static char_u *
76+skip_string(char_u *p)
77+{
78+ int i;
79+
80+ // We loop, because strings may be concatenated: "date""time".
81+ for ( ; ; ++p)
82+ {
83+ if (p[0] == '\'') // 'c' or '\n' or '\000'
84+ {
85+ if (!p[1]) // ' at end of line
86+ break;
87+ i = 2;
88+ if (p[1] == '\\') // '\n' or '\000'
89+ {
90+ ++i;
91+ while (vim_isdigit(p[i - 1])) // '\000'
92+ ++i;
93+ }
94+ if (p[i] == '\'') // check for trailing '
95+ {
96+ p += i;
97+ continue;
98+ }
99+ }
100+ else if (p[0] == '"') // start of string
101+ {
102+ for (++p; p[0]; ++p)
103+ {
104+ if (p[0] == '\\' && p[1] != NUL)
105+ ++p;
106+ else if (p[0] == '"') // end of string
107+ break;
108+ }
109+ if (p[0] == '"')
110+ continue; // continue for another string
111+ }
112+ else if (p[0] == 'R' && p[1] == '"')
113+ {
114+ // Raw string: R"[delim](...)[delim]"
115+ char_u *delim = p + 2;
116+ char_u *paren = vim_strchr(delim, '(');
117+
118+ if (paren != NULL)
119+ {
120+ size_t delim_len = paren - delim;
121+
122+ for (p += 3; *p; ++p)
123+ if (p[0] == ')' && STRNCMP(p + 1, delim, delim_len) == 0
124+ && p[delim_len + 1] == '"')
125+ {
126+ p += delim_len + 1;
127+ break;
128+ }
129+ if (p[0] == '"')
130+ continue; // continue for another string
131+ }
132+ }
133+ break; // no string found
134+ }
135+ if (!*p)
136+ --p; // backup from NUL
137+ return p;
138+}
139+
140+/*
141+ * Find the start of a comment, not knowing if we are in a comment right now.
142+ * Search starts at w_cursor.lnum and goes backwards.
143+ * Return NULL when not inside a comment.
144+ */
145+ static pos_T *
146+ind_find_start_comment(void) // XXX
147+{
148+ return find_start_comment(curbuf->b_ind_maxcomment);
149+}
150+
151+ pos_T *
152+find_start_comment(int ind_maxcomment) // XXX
153+{
154+ pos_T *pos;
155+ char_u *line;
156+ char_u *p;
157+ int cur_maxcomment = ind_maxcomment;
158+
159+ for (;;)
160+ {
161+ pos = findmatchlimit(NULL, '*', FM_BACKWARD, cur_maxcomment);
162+ if (pos == NULL)
163+ break;
164+
165+ // Check if the comment start we found is inside a string.
166+ // If it is then restrict the search to below this line and try again.
167+ line = ml_get(pos->lnum);
168+ for (p = line; *p && (colnr_T)(p - line) < pos->col; ++p)
169+ p = skip_string(p);
170+ if ((colnr_T)(p - line) <= pos->col)
171+ break;
172+ cur_maxcomment = curwin->w_cursor.lnum - pos->lnum - 1;
173+ if (cur_maxcomment <= 0)
174+ {
175+ pos = NULL;
176+ break;
177+ }
178+ }
179+ return pos;
180+}
181+
182+/*
183+ * Find the start of a raw string, not knowing if we are in one right now.
184+ * Search starts at w_cursor.lnum and goes backwards.
185+ * Return NULL when not inside a raw string.
186+ */
187+ static pos_T *
188+find_start_rawstring(int ind_maxcomment) // XXX
189+{
190+ pos_T *pos;
191+ char_u *line;
192+ char_u *p;
193+ int cur_maxcomment = ind_maxcomment;
194+
195+ for (;;)
196+ {
197+ pos = findmatchlimit(NULL, 'R', FM_BACKWARD, cur_maxcomment);
198+ if (pos == NULL)
199+ break;
200+
201+ // Check if the raw string start we found is inside a string.
202+ // If it is then restrict the search to below this line and try again.
203+ line = ml_get(pos->lnum);
204+ for (p = line; *p && (colnr_T)(p - line) < pos->col; ++p)
205+ p = skip_string(p);
206+ if ((colnr_T)(p - line) <= pos->col)
207+ break;
208+ cur_maxcomment = curwin->w_cursor.lnum - pos->lnum - 1;
209+ if (cur_maxcomment <= 0)
210+ {
211+ pos = NULL;
212+ break;
213+ }
214+ }
215+ return pos;
216+}
217+
218+/*
219+ * Find the start of a comment or raw string, not knowing if we are in a
220+ * comment or raw string right now.
221+ * Search starts at w_cursor.lnum and goes backwards.
222+ * If is_raw is given and returns start of raw_string, sets it to true.
223+ * Return NULL when not inside a comment or raw string.
224+ * "CORS" -> Comment Or Raw String
225+ */
226+ static pos_T *
227+ind_find_start_CORS(linenr_T *is_raw) // XXX
228+{
229+ static pos_T comment_pos_copy;
230+ pos_T *comment_pos;
231+ pos_T *rs_pos;
232+
233+ comment_pos = find_start_comment(curbuf->b_ind_maxcomment);
234+ if (comment_pos != NULL)
235+ {
236+ // Need to make a copy of the static pos in findmatchlimit(),
237+ // calling find_start_rawstring() may change it.
238+ comment_pos_copy = *comment_pos;
239+ comment_pos = &comment_pos_copy;
240+ }
241+ rs_pos = find_start_rawstring(curbuf->b_ind_maxcomment);
242+
243+ // If comment_pos is before rs_pos the raw string is inside the comment.
244+ // If rs_pos is before comment_pos the comment is inside the raw string.
245+ if (comment_pos == NULL || (rs_pos != NULL
246+ && LT_POS(*rs_pos, *comment_pos)))
247+ {
248+ if (is_raw != NULL && rs_pos != NULL)
249+ *is_raw = rs_pos->lnum;
250+ return rs_pos;
251+ }
252+ return comment_pos;
253+}
254+#endif // FEAT_CINDENT || FEAT_SYN_HL
255+
256+#if defined(FEAT_CINDENT) || defined(PROTO)
257+
258+/*
259+ * Return TRUE if C-indenting is on.
260+ */
261+ int
262+cindent_on(void)
263+{
264+ return (!p_paste && (curbuf->b_p_cin
265+# ifdef FEAT_EVAL
266+ || *curbuf->b_p_inde != NUL
267+# endif
268+ ));
269+}
270+
271+// Find result cache for cpp_baseclass
272+typedef struct {
273+ int found;
274+ lpos_T lpos;
275+} cpp_baseclass_cache_T;
276+
277+/*
278+ * Skip over white space and C comments within the line.
279+ * Also skip over Perl/shell comments if desired.
280+ */
281+ static char_u *
282+cin_skipcomment(char_u *s)
283+{
284+ while (*s)
285+ {
286+ char_u *prev_s = s;
287+
288+ s = skipwhite(s);
289+
290+ // Perl/shell # comment comment continues until eol. Require a space
291+ // before # to avoid recognizing $#array.
292+ if (curbuf->b_ind_hash_comment != 0 && s != prev_s && *s == '#')
293+ {
294+ s += STRLEN(s);
295+ break;
296+ }
297+ if (*s != '/')
298+ break;
299+ ++s;
300+ if (*s == '/') // slash-slash comment continues till eol
301+ {
302+ s += STRLEN(s);
303+ break;
304+ }
305+ if (*s != '*')
306+ break;
307+ for (++s; *s; ++s) // skip slash-star comment
308+ if (s[0] == '*' && s[1] == '/')
309+ {
310+ s += 2;
311+ break;
312+ }
313+ }
314+ return s;
315+}
316+
317+/*
318+ * Return TRUE if there is no code at *s. White space and comments are
319+ * not considered code.
320+ */
321+ static int
322+cin_nocode(char_u *s)
323+{
324+ return *cin_skipcomment(s) == NUL;
325+}
326+
327+/*
328+ * Recognize the start of a C or C++ comment.
329+ */
330+ static int
331+cin_iscomment(char_u *p)
332+{
333+ return (p[0] == '/' && (p[1] == '*' || p[1] == '/'));
334+}
335+
336+/*
337+ * Recognize the start of a "//" comment.
338+ */
339+ static int
340+cin_islinecomment(char_u *p)
341+{
342+ return (p[0] == '/' && p[1] == '/');
343+}
344+
345+/*
346+ * Check previous lines for a "//" line comment, skipping over blank lines.
347+ */
348+ static pos_T *
349+find_line_comment(void) // XXX
350+{
351+ static pos_T pos;
352+ char_u *line;
353+ char_u *p;
354+
355+ pos = curwin->w_cursor;
356+ while (--pos.lnum > 0)
357+ {
358+ line = ml_get(pos.lnum);
359+ p = skipwhite(line);
360+ if (cin_islinecomment(p))
361+ {
362+ pos.col = (int)(p - line);
363+ return &pos;
364+ }
365+ if (*p != NUL)
366+ break;
367+ }
368+ return NULL;
369+}
370+
371+/*
372+ * Return TRUE if "text" starts with "key:".
373+ */
374+ static int
375+cin_has_js_key(char_u *text)
376+{
377+ char_u *s = skipwhite(text);
378+ int quote = -1;
379+
380+ if (*s == '\'' || *s == '"')
381+ {
382+ // can be 'key': or "key":
383+ quote = *s;
384+ ++s;
385+ }
386+ if (!vim_isIDc(*s)) // need at least one ID character
387+ return FALSE;
388+
389+ while (vim_isIDc(*s))
390+ ++s;
391+ if (*s == quote)
392+ ++s;
393+
394+ s = cin_skipcomment(s);
395+
396+ // "::" is not a label, it's C++
397+ return (*s == ':' && s[1] != ':');
398+}
399+
400+/*
401+ * Check if string matches "label:"; move to character after ':' if true.
402+ * "*s" must point to the start of the label, if there is one.
403+ */
404+ static int
405+cin_islabel_skip(char_u **s)
406+{
407+ if (!vim_isIDc(**s)) // need at least one ID character
408+ return FALSE;
409+
410+ while (vim_isIDc(**s))
411+ (*s)++;
412+
413+ *s = cin_skipcomment(*s);
414+
415+ // "::" is not a label, it's C++
416+ return (**s == ':' && *++*s != ':');
417+}
418+
419+/*
420+ * Recognize a "public/private/protected" scope declaration label.
421+ */
422+ static int
423+cin_isscopedecl(char_u *s)
424+{
425+ int i;
426+
427+ s = cin_skipcomment(s);
428+ if (STRNCMP(s, "public", 6) == 0)
429+ i = 6;
430+ else if (STRNCMP(s, "protected", 9) == 0)
431+ i = 9;
432+ else if (STRNCMP(s, "private", 7) == 0)
433+ i = 7;
434+ else
435+ return FALSE;
436+ return (*(s = cin_skipcomment(s + i)) == ':' && s[1] != ':');
437+}
438+
439+/*
440+ * Recognize a preprocessor statement: Any line that starts with '#'.
441+ */
442+ static int
443+cin_ispreproc(char_u *s)
444+{
445+ if (*skipwhite(s) == '#')
446+ return TRUE;
447+ return FALSE;
448+}
449+
450+/*
451+ * Return TRUE if line "*pp" at "*lnump" is a preprocessor statement or a
452+ * continuation line of a preprocessor statement. Decrease "*lnump" to the
453+ * start and return the line in "*pp".
454+ * Put the amount of indent in "*amount".
455+ */
456+ static int
457+cin_ispreproc_cont(char_u **pp, linenr_T *lnump, int *amount)
458+{
459+ char_u *line = *pp;
460+ linenr_T lnum = *lnump;
461+ int retval = FALSE;
462+ int candidate_amount = *amount;
463+
464+ if (*line != NUL && line[STRLEN(line) - 1] == '\\')
465+ candidate_amount = get_indent_lnum(lnum);
466+
467+ for (;;)
468+ {
469+ if (cin_ispreproc(line))
470+ {
471+ retval = TRUE;
472+ *lnump = lnum;
473+ break;
474+ }
475+ if (lnum == 1)
476+ break;
477+ line = ml_get(--lnum);
478+ if (*line == NUL || line[STRLEN(line) - 1] != '\\')
479+ break;
480+ }
481+
482+ if (lnum != *lnump)
483+ *pp = ml_get(*lnump);
484+ if (retval)
485+ *amount = candidate_amount;
486+ return retval;
487+}
488+
489+ static int
490+cin_iselse(
491+ char_u *p)
492+{
493+ if (*p == '}') // accept "} else"
494+ p = cin_skipcomment(p + 1);
495+ return (STRNCMP(p, "else", 4) == 0 && !vim_isIDc(p[4]));
496+}
497+
498+/*
499+ * Recognize a line that starts with '{' or '}', or ends with ';', ',', '{' or
500+ * '}'.
501+ * Don't consider "} else" a terminated line.
502+ * If a line begins with an "else", only consider it terminated if no unmatched
503+ * opening braces follow (handle "else { foo();" correctly).
504+ * Return the character terminating the line (ending char's have precedence if
505+ * both apply in order to determine initializations).
506+ */
507+ static int
508+cin_isterminated(
509+ char_u *s,
510+ int incl_open, // include '{' at the end as terminator
511+ int incl_comma) // recognize a trailing comma
512+{
513+ char_u found_start = 0;
514+ unsigned n_open = 0;
515+ int is_else = FALSE;
516+
517+ s = cin_skipcomment(s);
518+
519+ if (*s == '{' || (*s == '}' && !cin_iselse(s)))
520+ found_start = *s;
521+
522+ if (!found_start)
523+ is_else = cin_iselse(s);
524+
525+ while (*s)
526+ {
527+ // skip over comments, "" strings and 'c'haracters
528+ s = skip_string(cin_skipcomment(s));
529+ if (*s == '}' && n_open > 0)
530+ --n_open;
531+ if ((!is_else || n_open == 0)
532+ && (*s == ';' || *s == '}' || (incl_comma && *s == ','))
533+ && cin_nocode(s + 1))
534+ return *s;
535+ else if (*s == '{')
536+ {
537+ if (incl_open && cin_nocode(s + 1))
538+ return *s;
539+ else
540+ ++n_open;
541+ }
542+
543+ if (*s)
544+ s++;
545+ }
546+ return found_start;
547+}
548+
549+/*
550+ * Return TRUE when "s" starts with "word" and then a non-ID character.
551+ */
552+ static int
553+cin_starts_with(char_u *s, char *word)
554+{
555+ int l = (int)STRLEN(word);
556+
557+ return (STRNCMP(s, word, l) == 0 && !vim_isIDc(s[l]));
558+}
559+
560+/*
561+ * Recognize a "default" switch label.
562+ */
563+ static int
564+cin_isdefault(char_u *s)
565+{
566+ return (STRNCMP(s, "default", 7) == 0
567+ && *(s = cin_skipcomment(s + 7)) == ':'
568+ && s[1] != ':');
569+}
570+
571+/*
572+ * Recognize a switch label: "case .*:" or "default:".
573+ */
574+ static int
575+cin_iscase(
576+ char_u *s,
577+ int strict) // Allow relaxed check of case statement for JS
578+{
579+ s = cin_skipcomment(s);
580+ if (cin_starts_with(s, "case"))
581+ {
582+ for (s += 4; *s; ++s)
583+ {
584+ s = cin_skipcomment(s);
585+ if (*s == ':')
586+ {
587+ if (s[1] == ':') // skip over "::" for C++
588+ ++s;
589+ else
590+ return TRUE;
591+ }
592+ if (*s == '\'' && s[1] && s[2] == '\'')
593+ s += 2; // skip over ':'
594+ else if (*s == '/' && (s[1] == '*' || s[1] == '/'))
595+ return FALSE; // stop at comment
596+ else if (*s == '"')
597+ {
598+ // JS etc.
599+ if (strict)
600+ return FALSE; // stop at string
601+ else
602+ return TRUE;
603+ }
604+ }
605+ return FALSE;
606+ }
607+
608+ if (cin_isdefault(s))
609+ return TRUE;
610+ return FALSE;
611+}
612+
613+/*
614+ * Recognize a label: "label:".
615+ * Note: curwin->w_cursor must be where we are looking for the label.
616+ */
617+ static int
618+cin_islabel(void) // XXX
619+{
620+ char_u *s;
621+
622+ s = cin_skipcomment(ml_get_curline());
623+
624+ // Exclude "default" from labels, since it should be indented
625+ // like a switch label. Same for C++ scope declarations.
626+ if (cin_isdefault(s))
627+ return FALSE;
628+ if (cin_isscopedecl(s))
629+ return FALSE;
630+
631+ if (cin_islabel_skip(&s))
632+ {
633+ // Only accept a label if the previous line is terminated or is a case
634+ // label.
635+ pos_T cursor_save;
636+ pos_T *trypos;
637+ char_u *line;
638+
639+ cursor_save = curwin->w_cursor;
640+ while (curwin->w_cursor.lnum > 1)
641+ {
642+ --curwin->w_cursor.lnum;
643+
644+ // If we're in a comment or raw string now, skip to the start of
645+ // it.
646+ curwin->w_cursor.col = 0;
647+ if ((trypos = ind_find_start_CORS(NULL)) != NULL) // XXX
648+ curwin->w_cursor = *trypos;
649+
650+ line = ml_get_curline();
651+ if (cin_ispreproc(line)) // ignore #defines, #if, etc.
652+ continue;
653+ if (*(line = cin_skipcomment(line)) == NUL)
654+ continue;
655+
656+ curwin->w_cursor = cursor_save;
657+ if (cin_isterminated(line, TRUE, FALSE)
658+ || cin_isscopedecl(line)
659+ || cin_iscase(line, TRUE)
660+ || (cin_islabel_skip(&line) && cin_nocode(line)))
661+ return TRUE;
662+ return FALSE;
663+ }
664+ curwin->w_cursor = cursor_save;
665+ return TRUE; // label at start of file???
666+ }
667+ return FALSE;
668+}
669+
670+/*
671+ * Return TRUE if string "s" ends with the string "find", possibly followed by
672+ * white space and comments. Skip strings and comments.
673+ * Ignore "ignore" after "find" if it's not NULL.
674+ */
675+ static int
676+cin_ends_in(char_u *s, char_u *find, char_u *ignore)
677+{
678+ char_u *p = s;
679+ char_u *r;
680+ int len = (int)STRLEN(find);
681+
682+ while (*p != NUL)
683+ {
684+ p = cin_skipcomment(p);
685+ if (STRNCMP(p, find, len) == 0)
686+ {
687+ r = skipwhite(p + len);
688+ if (ignore != NULL && STRNCMP(r, ignore, STRLEN(ignore)) == 0)
689+ r = skipwhite(r + STRLEN(ignore));
690+ if (cin_nocode(r))
691+ return TRUE;
692+ }
693+ if (*p != NUL)
694+ ++p;
695+ }
696+ return FALSE;
697+}
698+
699+/*
700+ * Recognize structure initialization and enumerations:
701+ * "[typedef] [static|public|protected|private] enum"
702+ * "[typedef] [static|public|protected|private] = {"
703+ */
704+ static int
705+cin_isinit(void)
706+{
707+ char_u *s;
708+ static char *skip[] = {"static", "public", "protected", "private"};
709+
710+ s = cin_skipcomment(ml_get_curline());
711+
712+ if (cin_starts_with(s, "typedef"))
713+ s = cin_skipcomment(s + 7);
714+
715+ for (;;)
716+ {
717+ int i, l;
718+
719+ for (i = 0; i < (int)(sizeof(skip) / sizeof(char *)); ++i)
720+ {
721+ l = (int)strlen(skip[i]);
722+ if (cin_starts_with(s, skip[i]))
723+ {
724+ s = cin_skipcomment(s + l);
725+ l = 0;
726+ break;
727+ }
728+ }
729+ if (l != 0)
730+ break;
731+ }
732+
733+ if (cin_starts_with(s, "enum"))
734+ return TRUE;
735+
736+ if (cin_ends_in(s, (char_u *)"=", (char_u *)"{"))
737+ return TRUE;
738+
739+ return FALSE;
740+}
741+
742+// Maximum number of lines to search back for a "namespace" line.
743+#define FIND_NAMESPACE_LIM 20
744+
745+/*
746+ * Recognize a "namespace" scope declaration.
747+ */
748+ static int
749+cin_is_cpp_namespace(char_u *s)
750+{
751+ char_u *p;
752+ int has_name = FALSE;
753+ int has_name_start = FALSE;
754+
755+ s = cin_skipcomment(s);
756+ if (STRNCMP(s, "namespace", 9) == 0 && (s[9] == NUL || !vim_iswordc(s[9])))
757+ {
758+ p = cin_skipcomment(skipwhite(s + 9));
759+ while (*p != NUL)
760+ {
761+ if (VIM_ISWHITE(*p))
762+ {
763+ has_name = TRUE; // found end of a name
764+ p = cin_skipcomment(skipwhite(p));
765+ }
766+ else if (*p == '{')
767+ {
768+ break;
769+ }
770+ else if (vim_iswordc(*p))
771+ {
772+ has_name_start = TRUE;
773+ if (has_name)
774+ return FALSE; // word character after skipping past name
775+ ++p;
776+ }
777+ else if (p[0] == ':' && p[1] == ':' && vim_iswordc(p[2]))
778+ {
779+ if (!has_name_start || has_name)
780+ return FALSE;
781+ // C++ 17 nested namespace
782+ p += 3;
783+ }
784+ else
785+ {
786+ return FALSE;
787+ }
788+ }
789+ return TRUE;
790+ }
791+ return FALSE;
792+}
793+
794+/*
795+ * Recognize a `extern "C"` or `extern "C++"` linkage specifications.
796+ */
797+ static int
798+cin_is_cpp_extern_c(char_u *s)
799+{
800+ char_u *p;
801+ int has_string_literal = FALSE;
802+
803+ s = cin_skipcomment(s);
804+ if (STRNCMP(s, "extern", 6) == 0 && (s[6] == NUL || !vim_iswordc(s[6])))
805+ {
806+ p = cin_skipcomment(skipwhite(s + 6));
807+ while (*p != NUL)
808+ {
809+ if (VIM_ISWHITE(*p))
810+ {
811+ p = cin_skipcomment(skipwhite(p));
812+ }
813+ else if (*p == '{')
814+ {
815+ break;
816+ }
817+ else if (p[0] == '"' && p[1] == 'C' && p[2] == '"')
818+ {
819+ if (has_string_literal)
820+ return FALSE;
821+ has_string_literal = TRUE;
822+ p += 3;
823+ }
824+ else if (p[0] == '"' && p[1] == 'C' && p[2] == '+' && p[3] == '+'
825+ && p[4] == '"')
826+ {
827+ if (has_string_literal)
828+ return FALSE;
829+ has_string_literal = TRUE;
830+ p += 5;
831+ }
832+ else
833+ {
834+ return FALSE;
835+ }
836+ }
837+ return has_string_literal ? TRUE : FALSE;
838+ }
839+ return FALSE;
840+}
841+
842+/*
843+ * Return a pointer to the first non-empty non-comment character after a ':'.
844+ * Return NULL if not found.
845+ * case 234: a = b;
846+ * ^
847+ */
848+ static char_u *
849+after_label(char_u *l)
850+{
851+ for ( ; *l; ++l)
852+ {
853+ if (*l == ':')
854+ {
855+ if (l[1] == ':') // skip over "::" for C++
856+ ++l;
857+ else if (!cin_iscase(l + 1, FALSE))
858+ break;
859+ }
860+ else if (*l == '\'' && l[1] && l[2] == '\'')
861+ l += 2; // skip over 'x'
862+ }
863+ if (*l == NUL)
864+ return NULL;
865+ l = cin_skipcomment(l + 1);
866+ if (*l == NUL)
867+ return NULL;
868+ return l;
869+}
870+
871+/*
872+ * Get indent of line "lnum", skipping a label.
873+ * Return 0 if there is nothing after the label.
874+ */
875+ static int
876+get_indent_nolabel (linenr_T lnum) // XXX
877+{
878+ char_u *l;
879+ pos_T fp;
880+ colnr_T col;
881+ char_u *p;
882+
883+ l = ml_get(lnum);
884+ p = after_label(l);
885+ if (p == NULL)
886+ return 0;
887+
888+ fp.col = (colnr_T)(p - l);
889+ fp.lnum = lnum;
890+ getvcol(curwin, &fp, &col, NULL, NULL);
891+ return (int)col;
892+}
893+
894+/*
895+ * Find indent for line "lnum", ignoring any case or jump label.
896+ * Also return a pointer to the text (after the label) in "pp".
897+ * label: if (asdf && asdfasdf)
898+ * ^
899+ */
900+ static int
901+skip_label(linenr_T lnum, char_u **pp)
902+{
903+ char_u *l;
904+ int amount;
905+ pos_T cursor_save;
906+
907+ cursor_save = curwin->w_cursor;
908+ curwin->w_cursor.lnum = lnum;
909+ l = ml_get_curline();
910+ // XXX
911+ if (cin_iscase(l, FALSE) || cin_isscopedecl(l) || cin_islabel())
912+ {
913+ amount = get_indent_nolabel(lnum);
914+ l = after_label(ml_get_curline());
915+ if (l == NULL) // just in case
916+ l = ml_get_curline();
917+ }
918+ else
919+ {
920+ amount = get_indent();
921+ l = ml_get_curline();
922+ }
923+ *pp = l;
924+
925+ curwin->w_cursor = cursor_save;
926+ return amount;
927+}
928+
929+/*
930+ * Return the indent of the first variable name after a type in a declaration.
931+ * int a, indent of "a"
932+ * static struct foo b, indent of "b"
933+ * enum bla c, indent of "c"
934+ * Returns zero when it doesn't look like a declaration.
935+ */
936+ static int
937+cin_first_id_amount(void)
938+{
939+ char_u *line, *p, *s;
940+ int len;
941+ pos_T fp;
942+ colnr_T col;
943+
944+ line = ml_get_curline();
945+ p = skipwhite(line);
946+ len = (int)(skiptowhite(p) - p);
947+ if (len == 6 && STRNCMP(p, "static", 6) == 0)
948+ {
949+ p = skipwhite(p + 6);
950+ len = (int)(skiptowhite(p) - p);
951+ }
952+ if (len == 6 && STRNCMP(p, "struct", 6) == 0)
953+ p = skipwhite(p + 6);
954+ else if (len == 4 && STRNCMP(p, "enum", 4) == 0)
955+ p = skipwhite(p + 4);
956+ else if ((len == 8 && STRNCMP(p, "unsigned", 8) == 0)
957+ || (len == 6 && STRNCMP(p, "signed", 6) == 0))
958+ {
959+ s = skipwhite(p + len);
960+ if ((STRNCMP(s, "int", 3) == 0 && VIM_ISWHITE(s[3]))
961+ || (STRNCMP(s, "long", 4) == 0 && VIM_ISWHITE(s[4]))
962+ || (STRNCMP(s, "short", 5) == 0 && VIM_ISWHITE(s[5]))
963+ || (STRNCMP(s, "char", 4) == 0 && VIM_ISWHITE(s[4])))
964+ p = s;
965+ }
966+ for (len = 0; vim_isIDc(p[len]); ++len)
967+ ;
968+ if (len == 0 || !VIM_ISWHITE(p[len]) || cin_nocode(p))
969+ return 0;
970+
971+ p = skipwhite(p + len);
972+ fp.lnum = curwin->w_cursor.lnum;
973+ fp.col = (colnr_T)(p - line);
974+ getvcol(curwin, &fp, &col, NULL, NULL);
975+ return (int)col;
976+}
977+
978+/*
979+ * Return the indent of the first non-blank after an equal sign.
980+ * char *foo = "here";
981+ * Return zero if no (useful) equal sign found.
982+ * Return -1 if the line above "lnum" ends in a backslash.
983+ * foo = "asdf\
984+ * asdf\
985+ * here";
986+ */
987+ static int
988+cin_get_equal_amount(linenr_T lnum)
989+{
990+ char_u *line;
991+ char_u *s;
992+ colnr_T col;
993+ pos_T fp;
994+
995+ if (lnum > 1)
996+ {
997+ line = ml_get(lnum - 1);
998+ if (*line != NUL && line[STRLEN(line) - 1] == '\\')
999+ return -1;
1000+ }
1001+
1002+ line = s = ml_get(lnum);
1003+ while (*s != NUL && vim_strchr((char_u *)"=;{}\"'", *s) == NULL)
1004+ {
1005+ if (cin_iscomment(s)) // ignore comments
1006+ s = cin_skipcomment(s);
1007+ else
1008+ ++s;
1009+ }
1010+ if (*s != '=')
1011+ return 0;
1012+
1013+ s = skipwhite(s + 1);
1014+ if (cin_nocode(s))
1015+ return 0;
1016+
1017+ if (*s == '"') // nice alignment for continued strings
1018+ ++s;
1019+
1020+ fp.lnum = lnum;
1021+ fp.col = (colnr_T)(s - line);
1022+ getvcol(curwin, &fp, &col, NULL, NULL);
1023+ return (int)col;
1024+}
1025+
1026+/*
1027+ * Skip strings, chars and comments until at or past "trypos".
1028+ * Return the column found.
1029+ */
1030+ static int
1031+cin_skip2pos(pos_T *trypos)
1032+{
1033+ char_u *line;
1034+ char_u *p;
1035+ char_u *new_p;
1036+
1037+ p = line = ml_get(trypos->lnum);
1038+ while (*p && (colnr_T)(p - line) < trypos->col)
1039+ {
1040+ if (cin_iscomment(p))
1041+ p = cin_skipcomment(p);
1042+ else
1043+ {
1044+ new_p = skip_string(p);
1045+ if (new_p == p)
1046+ ++p;
1047+ else
1048+ p = new_p;
1049+ }
1050+ }
1051+ return (int)(p - line);
1052+}
1053+
1054+ static pos_T *
1055+find_match_char(int c, int ind_maxparen) // XXX
1056+{
1057+ pos_T cursor_save;
1058+ pos_T *trypos;
1059+ static pos_T pos_copy;
1060+ int ind_maxp_wk;
1061+
1062+ cursor_save = curwin->w_cursor;
1063+ ind_maxp_wk = ind_maxparen;
1064+retry:
1065+ if ((trypos = findmatchlimit(NULL, c, 0, ind_maxp_wk)) != NULL)
1066+ {
1067+ // check if the ( is in a // comment
1068+ if ((colnr_T)cin_skip2pos(trypos) > trypos->col)
1069+ {
1070+ ind_maxp_wk = ind_maxparen - (int)(cursor_save.lnum - trypos->lnum);
1071+ if (ind_maxp_wk > 0)
1072+ {
1073+ curwin->w_cursor = *trypos;
1074+ curwin->w_cursor.col = 0; // XXX
1075+ goto retry;
1076+ }
1077+ trypos = NULL;
1078+ }
1079+ else
1080+ {
1081+ pos_T *trypos_wk;
1082+
1083+ pos_copy = *trypos; // copy trypos, findmatch will change it
1084+ trypos = &pos_copy;
1085+ curwin->w_cursor = *trypos;
1086+ if ((trypos_wk = ind_find_start_CORS(NULL)) != NULL) // XXX
1087+ {
1088+ ind_maxp_wk = ind_maxparen - (int)(cursor_save.lnum
1089+ - trypos_wk->lnum);
1090+ if (ind_maxp_wk > 0)
1091+ {
1092+ curwin->w_cursor = *trypos_wk;
1093+ goto retry;
1094+ }
1095+ trypos = NULL;
1096+ }
1097+ }
1098+ }
1099+ curwin->w_cursor = cursor_save;
1100+ return trypos;
1101+}
1102+
1103+/*
1104+ * Find the matching '(', ignoring it if it is in a comment.
1105+ * Return NULL if no match found.
1106+ */
1107+ static pos_T *
1108+find_match_paren(int ind_maxparen) // XXX
1109+{
1110+ return find_match_char('(', ind_maxparen);
1111+}
1112+
1113+/*
1114+ * Set w_cursor.col to the column number of the last unmatched ')' or '{' in
1115+ * line "l". "l" must point to the start of the line.
1116+ */
1117+ static int
1118+find_last_paren(char_u *l, int start, int end)
1119+{
1120+ int i;
1121+ int retval = FALSE;
1122+ int open_count = 0;
1123+
1124+ curwin->w_cursor.col = 0; // default is start of line
1125+
1126+ for (i = 0; l[i] != NUL; i++)
1127+ {
1128+ i = (int)(cin_skipcomment(l + i) - l); // ignore parens in comments
1129+ i = (int)(skip_string(l + i) - l); // ignore parens in quotes
1130+ if (l[i] == start)
1131+ ++open_count;
1132+ else if (l[i] == end)
1133+ {
1134+ if (open_count > 0)
1135+ --open_count;
1136+ else
1137+ {
1138+ curwin->w_cursor.col = i;
1139+ retval = TRUE;
1140+ }
1141+ }
1142+ }
1143+ return retval;
1144+}
1145+
1146+/*
1147+ * Recognize the basic picture of a function declaration -- it needs to
1148+ * have an open paren somewhere and a close paren at the end of the line and
1149+ * no semicolons anywhere.
1150+ * When a line ends in a comma we continue looking in the next line.
1151+ * "sp" points to a string with the line. When looking at other lines it must
1152+ * be restored to the line. When it's NULL fetch lines here.
1153+ * "first_lnum" is where we start looking.
1154+ * "min_lnum" is the line before which we will not be looking.
1155+ */
1156+ static int
1157+cin_isfuncdecl(
1158+ char_u **sp,
1159+ linenr_T first_lnum,
1160+ linenr_T min_lnum)
1161+{
1162+ char_u *s;
1163+ linenr_T lnum = first_lnum;
1164+ linenr_T save_lnum = curwin->w_cursor.lnum;
1165+ int retval = FALSE;
1166+ pos_T *trypos;
1167+ int just_started = TRUE;
1168+
1169+ if (sp == NULL)
1170+ s = ml_get(lnum);
1171+ else
1172+ s = *sp;
1173+
1174+ curwin->w_cursor.lnum = lnum;
1175+ if (find_last_paren(s, '(', ')')
1176+ && (trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL)
1177+ {
1178+ lnum = trypos->lnum;
1179+ if (lnum < min_lnum)
1180+ {
1181+ curwin->w_cursor.lnum = save_lnum;
1182+ return FALSE;
1183+ }
1184+
1185+ s = ml_get(lnum);
1186+ }
1187+ curwin->w_cursor.lnum = save_lnum;
1188+
1189+ // Ignore line starting with #.
1190+ if (cin_ispreproc(s))
1191+ return FALSE;
1192+
1193+ while (*s && *s != '(' && *s != ';' && *s != '\'' && *s != '"')
1194+ {
1195+ if (cin_iscomment(s)) // ignore comments
1196+ s = cin_skipcomment(s);
1197+ else if (*s == ':')
1198+ {
1199+ if (*(s + 1) == ':')
1200+ s += 2;
1201+ else
1202+ // To avoid a mistake in the following situation:
1203+ // A::A(int a, int b)
1204+ // : a(0) // <--not a function decl
1205+ // , b(0)
1206+ // {...
1207+ return FALSE;
1208+ }
1209+ else
1210+ ++s;
1211+ }
1212+ if (*s != '(')
1213+ return FALSE; // ';', ' or " before any () or no '('
1214+
1215+ while (*s && *s != ';' && *s != '\'' && *s != '"')
1216+ {
1217+ if (*s == ')' && cin_nocode(s + 1))
1218+ {
1219+ // ')' at the end: may have found a match
1220+ // Check for he previous line not to end in a backslash:
1221+ // #if defined(x) && {backslash}
1222+ // defined(y)
1223+ lnum = first_lnum - 1;
1224+ s = ml_get(lnum);
1225+ if (*s == NUL || s[STRLEN(s) - 1] != '\\')
1226+ retval = TRUE;
1227+ goto done;
1228+ }
1229+ if ((*s == ',' && cin_nocode(s + 1)) || s[1] == NUL || cin_nocode(s))
1230+ {
1231+ int comma = (*s == ',');
1232+
1233+ // ',' at the end: continue looking in the next line.
1234+ // At the end: check for ',' in the next line, for this style:
1235+ // func(arg1
1236+ // , arg2)
1237+ for (;;)
1238+ {
1239+ if (lnum >= curbuf->b_ml.ml_line_count)
1240+ break;
1241+ s = ml_get(++lnum);
1242+ if (!cin_ispreproc(s))
1243+ break;
1244+ }
1245+ if (lnum >= curbuf->b_ml.ml_line_count)
1246+ break;
1247+ // Require a comma at end of the line or a comma or ')' at the
1248+ // start of next line.
1249+ s = skipwhite(s);
1250+ if (!just_started && (!comma && *s != ',' && *s != ')'))
1251+ break;
1252+ just_started = FALSE;
1253+ }
1254+ else if (cin_iscomment(s)) // ignore comments
1255+ s = cin_skipcomment(s);
1256+ else
1257+ {
1258+ ++s;
1259+ just_started = FALSE;
1260+ }
1261+ }
1262+
1263+done:
1264+ if (lnum != first_lnum && sp != NULL)
1265+ *sp = ml_get(first_lnum);
1266+
1267+ return retval;
1268+}
1269+
1270+ static int
1271+cin_isif(char_u *p)
1272+{
1273+ return (STRNCMP(p, "if", 2) == 0 && !vim_isIDc(p[2]));
1274+}
1275+
1276+ static int
1277+cin_isdo(char_u *p)
1278+{
1279+ return (STRNCMP(p, "do", 2) == 0 && !vim_isIDc(p[2]));
1280+}
1281+
1282+/*
1283+ * Check if this is a "while" that should have a matching "do".
1284+ * We only accept a "while (condition) ;", with only white space between the
1285+ * ')' and ';'. The condition may be spread over several lines.
1286+ */
1287+ static int
1288+cin_iswhileofdo (char_u *p, linenr_T lnum) // XXX
1289+{
1290+ pos_T cursor_save;
1291+ pos_T *trypos;
1292+ int retval = FALSE;
1293+
1294+ p = cin_skipcomment(p);
1295+ if (*p == '}') // accept "} while (cond);"
1296+ p = cin_skipcomment(p + 1);
1297+ if (cin_starts_with(p, "while"))
1298+ {
1299+ cursor_save = curwin->w_cursor;
1300+ curwin->w_cursor.lnum = lnum;
1301+ curwin->w_cursor.col = 0;
1302+ p = ml_get_curline();
1303+ while (*p && *p != 'w') // skip any '}', until the 'w' of the "while"
1304+ {
1305+ ++p;
1306+ ++curwin->w_cursor.col;
1307+ }
1308+ if ((trypos = findmatchlimit(NULL, 0, 0,
1309+ curbuf->b_ind_maxparen)) != NULL
1310+ && *cin_skipcomment(ml_get_pos(trypos) + 1) == ';')
1311+ retval = TRUE;
1312+ curwin->w_cursor = cursor_save;
1313+ }
1314+ return retval;
1315+}
1316+
1317+/*
1318+ * Check whether in "p" there is an "if", "for" or "while" before "*poffset".
1319+ * Return 0 if there is none.
1320+ * Otherwise return !0 and update "*poffset" to point to the place where the
1321+ * string was found.
1322+ */
1323+ static int
1324+cin_is_if_for_while_before_offset(char_u *line, int *poffset)
1325+{
1326+ int offset = *poffset;
1327+
1328+ if (offset-- < 2)
1329+ return 0;
1330+ while (offset > 2 && VIM_ISWHITE(line[offset]))
1331+ --offset;
1332+
1333+ offset -= 1;
1334+ if (!STRNCMP(line + offset, "if", 2))
1335+ goto probablyFound;
1336+
1337+ if (offset >= 1)
1338+ {
1339+ offset -= 1;
1340+ if (!STRNCMP(line + offset, "for", 3))
1341+ goto probablyFound;
1342+
1343+ if (offset >= 2)
1344+ {
1345+ offset -= 2;
1346+ if (!STRNCMP(line + offset, "while", 5))
1347+ goto probablyFound;
1348+ }
1349+ }
1350+ return 0;
1351+
1352+probablyFound:
1353+ if (!offset || !vim_isIDc(line[offset - 1]))
1354+ {
1355+ *poffset = offset;
1356+ return 1;
1357+ }
1358+ return 0;
1359+}
1360+
1361+/*
1362+ * Return TRUE if we are at the end of a do-while.
1363+ * do
1364+ * nothing;
1365+ * while (foo
1366+ * && bar); <-- here
1367+ * Adjust the cursor to the line with "while".
1368+ */
1369+ static int
1370+cin_iswhileofdo_end(int terminated)
1371+{
1372+ char_u *line;
1373+ char_u *p;
1374+ char_u *s;
1375+ pos_T *trypos;
1376+ int i;
1377+
1378+ if (terminated != ';') // there must be a ';' at the end
1379+ return FALSE;
1380+
1381+ p = line = ml_get_curline();
1382+ while (*p != NUL)
1383+ {
1384+ p = cin_skipcomment(p);
1385+ if (*p == ')')
1386+ {
1387+ s = skipwhite(p + 1);
1388+ if (*s == ';' && cin_nocode(s + 1))
1389+ {
1390+ // Found ");" at end of the line, now check there is "while"
1391+ // before the matching '('. XXX
1392+ i = (int)(p - line);
1393+ curwin->w_cursor.col = i;
1394+ trypos = find_match_paren(curbuf->b_ind_maxparen);
1395+ if (trypos != NULL)
1396+ {
1397+ s = cin_skipcomment(ml_get(trypos->lnum));
1398+ if (*s == '}') // accept "} while (cond);"
1399+ s = cin_skipcomment(s + 1);
1400+ if (cin_starts_with(s, "while"))
1401+ {
1402+ curwin->w_cursor.lnum = trypos->lnum;
1403+ return TRUE;
1404+ }
1405+ }
1406+
1407+ // Searching may have made "line" invalid, get it again.
1408+ line = ml_get_curline();
1409+ p = line + i;
1410+ }
1411+ }
1412+ if (*p != NUL)
1413+ ++p;
1414+ }
1415+ return FALSE;
1416+}
1417+
1418+ static int
1419+cin_isbreak(char_u *p)
1420+{
1421+ return (STRNCMP(p, "break", 5) == 0 && !vim_isIDc(p[5]));
1422+}
1423+
1424+/*
1425+ * Find the position of a C++ base-class declaration or
1426+ * constructor-initialization. eg:
1427+ *
1428+ * class MyClass :
1429+ * baseClass <-- here
1430+ * class MyClass : public baseClass,
1431+ * anotherBaseClass <-- here (should probably lineup ??)
1432+ * MyClass::MyClass(...) :
1433+ * baseClass(...) <-- here (constructor-initialization)
1434+ *
1435+ * This is a lot of guessing. Watch out for "cond ? func() : foo".
1436+ */
1437+ static int
1438+cin_is_cpp_baseclass(
1439+ cpp_baseclass_cache_T *cached) // input and output
1440+{
1441+ lpos_T *pos = &cached->lpos; // find position
1442+ char_u *s;
1443+ int class_or_struct, lookfor_ctor_init, cpp_base_class;
1444+ linenr_T lnum = curwin->w_cursor.lnum;
1445+ char_u *line = ml_get_curline();
1446+
1447+ if (pos->lnum <= lnum)
1448+ return cached->found; // Use the cached result
1449+
1450+ pos->col = 0;
1451+
1452+ s = skipwhite(line);
1453+ if (*s == '#') // skip #define FOO x ? (x) : x
1454+ return FALSE;
1455+ s = cin_skipcomment(s);
1456+ if (*s == NUL)
1457+ return FALSE;
1458+
1459+ cpp_base_class = lookfor_ctor_init = class_or_struct = FALSE;
1460+
1461+ // Search for a line starting with '#', empty, ending in ';' or containing
1462+ // '{' or '}' and start below it. This handles the following situations:
1463+ // a = cond ?
1464+ // func() :
1465+ // asdf;
1466+ // func::foo()
1467+ // : something
1468+ // {}
1469+ // Foo::Foo (int one, int two)
1470+ // : something(4),
1471+ // somethingelse(3)
1472+ // {}
1473+ while (lnum > 1)
1474+ {
1475+ line = ml_get(lnum - 1);
1476+ s = skipwhite(line);
1477+ if (*s == '#' || *s == NUL)
1478+ break;
1479+ while (*s != NUL)
1480+ {
1481+ s = cin_skipcomment(s);
1482+ if (*s == '{' || *s == '}'
1483+ || (*s == ';' && cin_nocode(s + 1)))
1484+ break;
1485+ if (*s != NUL)
1486+ ++s;
1487+ }
1488+ if (*s != NUL)
1489+ break;
1490+ --lnum;
1491+ }
1492+
1493+ pos->lnum = lnum;
1494+ line = ml_get(lnum);
1495+ s = line;
1496+ for (;;)
1497+ {
1498+ if (*s == NUL)
1499+ {
1500+ if (lnum == curwin->w_cursor.lnum)
1501+ break;
1502+ // Continue in the cursor line.
1503+ line = ml_get(++lnum);
1504+ s = line;
1505+ }
1506+ if (s == line)
1507+ {
1508+ // don't recognize "case (foo):" as a baseclass
1509+ if (cin_iscase(s, FALSE))
1510+ break;
1511+ s = cin_skipcomment(line);
1512+ if (*s == NUL)
1513+ continue;
1514+ }
1515+
1516+ if (s[0] == '"' || (s[0] == 'R' && s[1] == '"'))
1517+ s = skip_string(s) + 1;
1518+ else if (s[0] == ':')
1519+ {
1520+ if (s[1] == ':')
1521+ {
1522+ // skip double colon. It can't be a constructor
1523+ // initialization any more
1524+ lookfor_ctor_init = FALSE;
1525+ s = cin_skipcomment(s + 2);
1526+ }
1527+ else if (lookfor_ctor_init || class_or_struct)
1528+ {
1529+ // we have something found, that looks like the start of
1530+ // cpp-base-class-declaration or constructor-initialization
1531+ cpp_base_class = TRUE;
1532+ lookfor_ctor_init = class_or_struct = FALSE;
1533+ pos->col = 0;
1534+ s = cin_skipcomment(s + 1);
1535+ }
1536+ else
1537+ s = cin_skipcomment(s + 1);
1538+ }
1539+ else if ((STRNCMP(s, "class", 5) == 0 && !vim_isIDc(s[5]))
1540+ || (STRNCMP(s, "struct", 6) == 0 && !vim_isIDc(s[6])))
1541+ {
1542+ class_or_struct = TRUE;
1543+ lookfor_ctor_init = FALSE;
1544+
1545+ if (*s == 'c')
1546+ s = cin_skipcomment(s + 5);
1547+ else
1548+ s = cin_skipcomment(s + 6);
1549+ }
1550+ else
1551+ {
1552+ if (s[0] == '{' || s[0] == '}' || s[0] == ';')
1553+ {
1554+ cpp_base_class = lookfor_ctor_init = class_or_struct = FALSE;
1555+ }
1556+ else if (s[0] == ')')
1557+ {
1558+ // Constructor-initialization is assumed if we come across
1559+ // something like "):"
1560+ class_or_struct = FALSE;
1561+ lookfor_ctor_init = TRUE;
1562+ }
1563+ else if (s[0] == '?')
1564+ {
1565+ // Avoid seeing '() :' after '?' as constructor init.
1566+ return FALSE;
1567+ }
1568+ else if (!vim_isIDc(s[0]))
1569+ {
1570+ // if it is not an identifier, we are wrong
1571+ class_or_struct = FALSE;
1572+ lookfor_ctor_init = FALSE;
1573+ }
1574+ else if (pos->col == 0)
1575+ {
1576+ // it can't be a constructor-initialization any more
1577+ lookfor_ctor_init = FALSE;
1578+
1579+ // the first statement starts here: lineup with this one...
1580+ if (cpp_base_class)
1581+ pos->col = (colnr_T)(s - line);
1582+ }
1583+
1584+ // When the line ends in a comma don't align with it.
1585+ if (lnum == curwin->w_cursor.lnum && *s == ',' && cin_nocode(s + 1))
1586+ pos->col = 0;
1587+
1588+ s = cin_skipcomment(s + 1);
1589+ }
1590+ }
1591+
1592+ cached->found = cpp_base_class;
1593+ if (cpp_base_class)
1594+ pos->lnum = lnum;
1595+ return cpp_base_class;
1596+}
1597+
1598+ static int
1599+get_baseclass_amount(int col)
1600+{
1601+ int amount;
1602+ colnr_T vcol;
1603+ pos_T *trypos;
1604+
1605+ if (col == 0)
1606+ {
1607+ amount = get_indent();
1608+ if (find_last_paren(ml_get_curline(), '(', ')')
1609+ && (trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL)
1610+ amount = get_indent_lnum(trypos->lnum); // XXX
1611+ if (!cin_ends_in(ml_get_curline(), (char_u *)",", NULL))
1612+ amount += curbuf->b_ind_cpp_baseclass;
1613+ }
1614+ else
1615+ {
1616+ curwin->w_cursor.col = col;
1617+ getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL);
1618+ amount = (int)vcol;
1619+ }
1620+ if (amount < curbuf->b_ind_cpp_baseclass)
1621+ amount = curbuf->b_ind_cpp_baseclass;
1622+ return amount;
1623+}
1624+
1625+/*
1626+ * Find the '{' at the start of the block we are in.
1627+ * Return NULL if no match found.
1628+ * Ignore a '{' that is in a comment, makes indenting the next three lines
1629+ * work.
1630+ */
1631+/* foo() */
1632+/* { */
1633+/* } */
1634+
1635+ static pos_T *
1636+find_start_brace(void) // XXX
1637+{
1638+ pos_T cursor_save;
1639+ pos_T *trypos;
1640+ pos_T *pos;
1641+ static pos_T pos_copy;
1642+
1643+ cursor_save = curwin->w_cursor;
1644+ while ((trypos = findmatchlimit(NULL, '{', FM_BLOCKSTOP, 0)) != NULL)
1645+ {
1646+ pos_copy = *trypos; // copy pos_T, next findmatch will change it
1647+ trypos = &pos_copy;
1648+ curwin->w_cursor = *trypos;
1649+ pos = NULL;
1650+ // ignore the { if it's in a // or / * * / comment
1651+ if ((colnr_T)cin_skip2pos(trypos) == trypos->col
1652+ && (pos = ind_find_start_CORS(NULL)) == NULL) // XXX
1653+ break;
1654+ if (pos != NULL)
1655+ curwin->w_cursor.lnum = pos->lnum;
1656+ }
1657+ curwin->w_cursor = cursor_save;
1658+ return trypos;
1659+}
1660+
1661+/*
1662+ * Find the matching '(', ignoring it if it is in a comment or before an
1663+ * unmatched {.
1664+ * Return NULL if no match found.
1665+ */
1666+ static pos_T *
1667+find_match_paren_after_brace (int ind_maxparen) // XXX
1668+{
1669+ pos_T *trypos = find_match_paren(ind_maxparen);
1670+
1671+ if (trypos != NULL)
1672+ {
1673+ pos_T *tryposBrace = find_start_brace();
1674+
1675+ // If both an unmatched '(' and '{' is found. Ignore the '('
1676+ // position if the '{' is further down.
1677+ if (tryposBrace != NULL
1678+ && (trypos->lnum != tryposBrace->lnum
1679+ ? trypos->lnum < tryposBrace->lnum
1680+ : trypos->col < tryposBrace->col))
1681+ trypos = NULL;
1682+ }
1683+ return trypos;
1684+}
1685+
1686+/*
1687+ * Return ind_maxparen corrected for the difference in line number between the
1688+ * cursor position and "startpos". This makes sure that searching for a
1689+ * matching paren above the cursor line doesn't find a match because of
1690+ * looking a few lines further.
1691+ */
1692+ static int
1693+corr_ind_maxparen(pos_T *startpos)
1694+{
1695+ long n = (long)startpos->lnum - (long)curwin->w_cursor.lnum;
1696+
1697+ if (n > 0 && n < curbuf->b_ind_maxparen / 2)
1698+ return curbuf->b_ind_maxparen - (int)n;
1699+ return curbuf->b_ind_maxparen;
1700+}
1701+
1702+/*
1703+ * Parse 'cinoptions' and set the values in "curbuf".
1704+ * Must be called when 'cinoptions', 'shiftwidth' and/or 'tabstop' changes.
1705+ */
1706+ void
1707+parse_cino(buf_T *buf)
1708+{
1709+ char_u *p;
1710+ char_u *l;
1711+ char_u *digits;
1712+ int n;
1713+ int divider;
1714+ int fraction = 0;
1715+ int sw = (int)get_sw_value(buf);
1716+
1717+ // Set the default values.
1718+
1719+ // Spaces from a block's opening brace the prevailing indent for that
1720+ // block should be.
1721+ buf->b_ind_level = sw;
1722+
1723+ // Spaces from the edge of the line an open brace that's at the end of a
1724+ // line is imagined to be.
1725+ buf->b_ind_open_imag = 0;
1726+
1727+ // Spaces from the prevailing indent for a line that is not preceded by
1728+ // an opening brace.
1729+ buf->b_ind_no_brace = 0;
1730+
1731+ // Column where the first { of a function should be located }.
1732+ buf->b_ind_first_open = 0;
1733+
1734+ // Spaces from the prevailing indent a leftmost open brace should be
1735+ // located.
1736+ buf->b_ind_open_extra = 0;
1737+
1738+ // Spaces from the matching open brace (real location for one at the left
1739+ // edge; imaginary location from one that ends a line) the matching close
1740+ // brace should be located.
1741+ buf->b_ind_close_extra = 0;
1742+
1743+ // Spaces from the edge of the line an open brace sitting in the leftmost
1744+ // column is imagined to be.
1745+ buf->b_ind_open_left_imag = 0;
1746+
1747+ // Spaces jump labels should be shifted to the left if N is non-negative,
1748+ // otherwise the jump label will be put to column 1.
1749+ buf->b_ind_jump_label = -1;
1750+
1751+ // Spaces from the switch() indent a "case xx" label should be located.
1752+ buf->b_ind_case = sw;
1753+
1754+ // Spaces from the "case xx:" code after a switch() should be located.
1755+ buf->b_ind_case_code = sw;
1756+
1757+ // Lineup break at end of case in switch() with case label.
1758+ buf->b_ind_case_break = 0;
1759+
1760+ // Spaces from the class declaration indent a scope declaration label
1761+ // should be located.
1762+ buf->b_ind_scopedecl = sw;
1763+
1764+ // Spaces from the scope declaration label code should be located.
1765+ buf->b_ind_scopedecl_code = sw;
1766+
1767+ // Amount K&R-style parameters should be indented.
1768+ buf->b_ind_param = sw;
1769+
1770+ // Amount a function type spec should be indented.
1771+ buf->b_ind_func_type = sw;
1772+
1773+ // Amount a cpp base class declaration or constructor initialization
1774+ // should be indented.
1775+ buf->b_ind_cpp_baseclass = sw;
1776+
1777+ // additional spaces beyond the prevailing indent a continuation line
1778+ // should be located.
1779+ buf->b_ind_continuation = sw;
1780+
1781+ // Spaces from the indent of the line with an unclosed parentheses.
1782+ buf->b_ind_unclosed = sw * 2;
1783+
1784+ // Spaces from the indent of the line with an unclosed parentheses, which
1785+ // itself is also unclosed.
1786+ buf->b_ind_unclosed2 = sw;
1787+
1788+ // Suppress ignoring spaces from the indent of a line starting with an
1789+ // unclosed parentheses.
1790+ buf->b_ind_unclosed_noignore = 0;
1791+
1792+ // If the opening paren is the last nonwhite character on the line, and
1793+ // b_ind_unclosed_wrapped is nonzero, use this indent relative to the outer
1794+ // context (for very long lines).
1795+ buf->b_ind_unclosed_wrapped = 0;
1796+
1797+ // Suppress ignoring white space when lining up with the character after
1798+ // an unclosed parentheses.
1799+ buf->b_ind_unclosed_whiteok = 0;
1800+
1801+ // Indent a closing parentheses under the line start of the matching
1802+ // opening parentheses.
1803+ buf->b_ind_matching_paren = 0;
1804+
1805+ // Indent a closing parentheses under the previous line.
1806+ buf->b_ind_paren_prev = 0;
1807+
1808+ // Extra indent for comments.
1809+ buf->b_ind_comment = 0;
1810+
1811+ // Spaces from the comment opener when there is nothing after it.
1812+ buf->b_ind_in_comment = 3;
1813+
1814+ // Boolean: if non-zero, use b_ind_in_comment even if there is something
1815+ // after the comment opener.
1816+ buf->b_ind_in_comment2 = 0;
1817+
1818+ // Max lines to search for an open paren.
1819+ buf->b_ind_maxparen = 20;
1820+
1821+ // Max lines to search for an open comment.
1822+ buf->b_ind_maxcomment = 70;
1823+
1824+ // Handle braces for java code.
1825+ buf->b_ind_java = 0;
1826+
1827+ // Not to confuse JS object properties with labels.
1828+ buf->b_ind_js = 0;
1829+
1830+ // Handle blocked cases correctly.
1831+ buf->b_ind_keep_case_label = 0;
1832+
1833+ // Handle C++ namespace.
1834+ buf->b_ind_cpp_namespace = 0;
1835+
1836+ // Handle continuation lines containing conditions of if(), for() and
1837+ // while().
1838+ buf->b_ind_if_for_while = 0;
1839+
1840+ // indentation for # comments
1841+ buf->b_ind_hash_comment = 0;
1842+
1843+ // Handle C++ extern "C" or "C++"
1844+ buf->b_ind_cpp_extern_c = 0;
1845+
1846+ for (p = buf->b_p_cino; *p; )
1847+ {
1848+ l = p++;
1849+ if (*p == '-')
1850+ ++p;
1851+ digits = p; // remember where the digits start
1852+ n = getdigits(&p);
1853+ divider = 0;
1854+ if (*p == '.') // ".5s" means a fraction
1855+ {
1856+ fraction = atol((char *)++p);
1857+ while (VIM_ISDIGIT(*p))
1858+ {
1859+ ++p;
1860+ if (divider)
1861+ divider *= 10;
1862+ else
1863+ divider = 10;
1864+ }
1865+ }
1866+ if (*p == 's') // "2s" means two times 'shiftwidth'
1867+ {
1868+ if (p == digits)
1869+ n = sw; // just "s" is one 'shiftwidth'
1870+ else
1871+ {
1872+ n *= sw;
1873+ if (divider)
1874+ n += (sw * fraction + divider / 2) / divider;
1875+ }
1876+ ++p;
1877+ }
1878+ if (l[1] == '-')
1879+ n = -n;
1880+
1881+ // When adding an entry here, also update the default 'cinoptions' in
1882+ // doc/indent.txt, and add explanation for it!
1883+ switch (*l)
1884+ {
1885+ case '>': buf->b_ind_level = n; break;
1886+ case 'e': buf->b_ind_open_imag = n; break;
1887+ case 'n': buf->b_ind_no_brace = n; break;
1888+ case 'f': buf->b_ind_first_open = n; break;
1889+ case '{': buf->b_ind_open_extra = n; break;
1890+ case '}': buf->b_ind_close_extra = n; break;
1891+ case '^': buf->b_ind_open_left_imag = n; break;
1892+ case 'L': buf->b_ind_jump_label = n; break;
1893+ case ':': buf->b_ind_case = n; break;
1894+ case '=': buf->b_ind_case_code = n; break;
1895+ case 'b': buf->b_ind_case_break = n; break;
1896+ case 'p': buf->b_ind_param = n; break;
1897+ case 't': buf->b_ind_func_type = n; break;
1898+ case '/': buf->b_ind_comment = n; break;
1899+ case 'c': buf->b_ind_in_comment = n; break;
1900+ case 'C': buf->b_ind_in_comment2 = n; break;
1901+ case 'i': buf->b_ind_cpp_baseclass = n; break;
1902+ case '+': buf->b_ind_continuation = n; break;
1903+ case '(': buf->b_ind_unclosed = n; break;
1904+ case 'u': buf->b_ind_unclosed2 = n; break;
1905+ case 'U': buf->b_ind_unclosed_noignore = n; break;
1906+ case 'W': buf->b_ind_unclosed_wrapped = n; break;
1907+ case 'w': buf->b_ind_unclosed_whiteok = n; break;
1908+ case 'm': buf->b_ind_matching_paren = n; break;
1909+ case 'M': buf->b_ind_paren_prev = n; break;
1910+ case ')': buf->b_ind_maxparen = n; break;
1911+ case '*': buf->b_ind_maxcomment = n; break;
1912+ case 'g': buf->b_ind_scopedecl = n; break;
1913+ case 'h': buf->b_ind_scopedecl_code = n; break;
1914+ case 'j': buf->b_ind_java = n; break;
1915+ case 'J': buf->b_ind_js = n; break;
1916+ case 'l': buf->b_ind_keep_case_label = n; break;
1917+ case '#': buf->b_ind_hash_comment = n; break;
1918+ case 'N': buf->b_ind_cpp_namespace = n; break;
1919+ case 'k': buf->b_ind_if_for_while = n; break;
1920+ case 'E': buf->b_ind_cpp_extern_c = n; break;
1921+ }
1922+ if (*p == ',')
1923+ ++p;
1924+ }
1925+}
1926+
1927+ static int
1928+find_match(int lookfor, linenr_T ourscope)
1929+{
1930+ char_u *look;
1931+ pos_T *theirscope;
1932+ char_u *mightbeif;
1933+ int elselevel;
1934+ int whilelevel;
1935+
1936+ if (lookfor == LOOKFOR_IF)
1937+ {
1938+ elselevel = 1;
1939+ whilelevel = 0;
1940+ }
1941+ else
1942+ {
1943+ elselevel = 0;
1944+ whilelevel = 1;
1945+ }
1946+
1947+ curwin->w_cursor.col = 0;
1948+
1949+ while (curwin->w_cursor.lnum > ourscope + 1)
1950+ {
1951+ curwin->w_cursor.lnum--;
1952+ curwin->w_cursor.col = 0;
1953+
1954+ look = cin_skipcomment(ml_get_curline());
1955+ if (cin_iselse(look)
1956+ || cin_isif(look)
1957+ || cin_isdo(look) // XXX
1958+ || cin_iswhileofdo(look, curwin->w_cursor.lnum))
1959+ {
1960+ // if we've gone outside the braces entirely,
1961+ // we must be out of scope...
1962+ theirscope = find_start_brace(); // XXX
1963+ if (theirscope == NULL)
1964+ break;
1965+
1966+ // and if the brace enclosing this is further
1967+ // back than the one enclosing the else, we're
1968+ // out of luck too.
1969+ if (theirscope->lnum < ourscope)
1970+ break;
1971+
1972+ // and if they're enclosed in a *deeper* brace,
1973+ // then we can ignore it because it's in a
1974+ // different scope...
1975+ if (theirscope->lnum > ourscope)
1976+ continue;
1977+
1978+ // if it was an "else" (that's not an "else if")
1979+ // then we need to go back to another if, so
1980+ // increment elselevel
1981+ look = cin_skipcomment(ml_get_curline());
1982+ if (cin_iselse(look))
1983+ {
1984+ mightbeif = cin_skipcomment(look + 4);
1985+ if (!cin_isif(mightbeif))
1986+ ++elselevel;
1987+ continue;
1988+ }
1989+
1990+ // if it was a "while" then we need to go back to
1991+ // another "do", so increment whilelevel. XXX
1992+ if (cin_iswhileofdo(look, curwin->w_cursor.lnum))
1993+ {
1994+ ++whilelevel;
1995+ continue;
1996+ }
1997+
1998+ // If it's an "if" decrement elselevel
1999+ look = cin_skipcomment(ml_get_curline());
2000+ if (cin_isif(look))
2001+ {
2002+ elselevel--;
2003+ // When looking for an "if" ignore "while"s that
2004+ // get in the way.
2005+ if (elselevel == 0 && lookfor == LOOKFOR_IF)
2006+ whilelevel = 0;
2007+ }
2008+
2009+ // If it's a "do" decrement whilelevel
2010+ if (cin_isdo(look))
2011+ whilelevel--;
2012+
2013+ // if we've used up all the elses, then
2014+ // this must be the if that we want!
2015+ // match the indent level of that if.
2016+ if (elselevel <= 0 && whilelevel <= 0)
2017+ return OK;
2018+ }
2019+ }
2020+ return FAIL;
2021+}
2022+
2023+/*
2024+ * Return the desired indent for C code.
2025+ * Return -1 if the indent should be left alone (inside a raw string).
2026+ */
2027+ int
2028+get_c_indent(void)
2029+{
2030+ pos_T cur_curpos;
2031+ int amount;
2032+ int scope_amount;
2033+ int cur_amount = MAXCOL;
2034+ colnr_T col;
2035+ char_u *theline;
2036+ char_u *linecopy;
2037+ pos_T *trypos;
2038+ pos_T *comment_pos;
2039+ pos_T *tryposBrace = NULL;
2040+ pos_T tryposCopy;
2041+ pos_T our_paren_pos;
2042+ char_u *start;
2043+ int start_brace;
2044+#define BRACE_IN_COL0 1 // '{' is in column 0
2045+#define BRACE_AT_START 2 // '{' is at start of line
2046+#define BRACE_AT_END 3 // '{' is at end of line
2047+ linenr_T ourscope;
2048+ char_u *l;
2049+ char_u *look;
2050+ char_u terminated;
2051+ int lookfor;
2052+ int whilelevel;
2053+ linenr_T lnum;
2054+ int n;
2055+ int iscase;
2056+ int lookfor_break;
2057+ int lookfor_cpp_namespace = FALSE;
2058+ int cont_amount = 0; // amount for continuation line
2059+ int original_line_islabel;
2060+ int added_to_amount = 0;
2061+ int js_cur_has_key = 0;
2062+ linenr_T raw_string_start = 0;
2063+ cpp_baseclass_cache_T cache_cpp_baseclass = { FALSE, { MAXLNUM, 0 } };
2064+
2065+ // make a copy, value is changed below
2066+ int ind_continuation = curbuf->b_ind_continuation;
2067+
2068+ // remember where the cursor was when we started
2069+ cur_curpos = curwin->w_cursor;
2070+
2071+ // if we are at line 1 zero indent is fine, right?
2072+ if (cur_curpos.lnum == 1)
2073+ return 0;
2074+
2075+ // Get a copy of the current contents of the line.
2076+ // This is required, because only the most recent line obtained with
2077+ // ml_get is valid!
2078+ linecopy = vim_strsave(ml_get(cur_curpos.lnum));
2079+ if (linecopy == NULL)
2080+ return 0;
2081+
2082+ // In insert mode and the cursor is on a ')' truncate the line at the
2083+ // cursor position. We don't want to line up with the matching '(' when
2084+ // inserting new stuff.
2085+ // For unknown reasons the cursor might be past the end of the line, thus
2086+ // check for that.
2087+ if ((State & INSERT)
2088+ && curwin->w_cursor.col < (colnr_T)STRLEN(linecopy)
2089+ && linecopy[curwin->w_cursor.col] == ')')
2090+ linecopy[curwin->w_cursor.col] = NUL;
2091+
2092+ theline = skipwhite(linecopy);
2093+
2094+ // move the cursor to the start of the line
2095+
2096+ curwin->w_cursor.col = 0;
2097+
2098+ original_line_islabel = cin_islabel(); // XXX
2099+
2100+ // If we are inside a raw string don't change the indent.
2101+ // Ignore a raw string inside a comment.
2102+ comment_pos = ind_find_start_comment();
2103+ if (comment_pos != NULL)
2104+ {
2105+ // findmatchlimit() static pos is overwritten, make a copy
2106+ tryposCopy = *comment_pos;
2107+ comment_pos = &tryposCopy;
2108+ }
2109+ trypos = find_start_rawstring(curbuf->b_ind_maxcomment);
2110+ if (trypos != NULL && (comment_pos == NULL
2111+ || LT_POS(*trypos, *comment_pos)))
2112+ {
2113+ amount = -1;
2114+ goto laterend;
2115+ }
2116+
2117+ // #defines and so on always go at the left when included in 'cinkeys'.
2118+ if (*theline == '#' && (*linecopy == '#' || in_cinkeys('#', ' ', TRUE)))
2119+ {
2120+ amount = curbuf->b_ind_hash_comment;
2121+ goto theend;
2122+ }
2123+
2124+ // Is it a non-case label? Then that goes at the left margin too unless:
2125+ // - JS flag is set.
2126+ // - 'L' item has a positive value.
2127+ if (original_line_islabel && !curbuf->b_ind_js
2128+ && curbuf->b_ind_jump_label < 0)
2129+ {
2130+ amount = 0;
2131+ goto theend;
2132+ }
2133+
2134+ // If we're inside a "//" comment and there is a "//" comment in a
2135+ // previous line, lineup with that one.
2136+ if (cin_islinecomment(theline)
2137+ && (trypos = find_line_comment()) != NULL) // XXX
2138+ {
2139+ // find how indented the line beginning the comment is
2140+ getvcol(curwin, trypos, &col, NULL, NULL);
2141+ amount = col;
2142+ goto theend;
2143+ }
2144+
2145+ // If we're inside a comment and not looking at the start of the
2146+ // comment, try using the 'comments' option.
2147+ if (!cin_iscomment(theline) && comment_pos != NULL) // XXX
2148+ {
2149+ int lead_start_len = 2;
2150+ int lead_middle_len = 1;
2151+ char_u lead_start[COM_MAX_LEN]; // start-comment string
2152+ char_u lead_middle[COM_MAX_LEN]; // middle-comment string
2153+ char_u lead_end[COM_MAX_LEN]; // end-comment string
2154+ char_u *p;
2155+ int start_align = 0;
2156+ int start_off = 0;
2157+ int done = FALSE;
2158+
2159+ // find how indented the line beginning the comment is
2160+ getvcol(curwin, comment_pos, &col, NULL, NULL);
2161+ amount = col;
2162+ *lead_start = NUL;
2163+ *lead_middle = NUL;
2164+
2165+ p = curbuf->b_p_com;
2166+ while (*p != NUL)
2167+ {
2168+ int align = 0;
2169+ int off = 0;
2170+ int what = 0;
2171+
2172+ while (*p != NUL && *p != ':')
2173+ {
2174+ if (*p == COM_START || *p == COM_END || *p == COM_MIDDLE)
2175+ what = *p++;
2176+ else if (*p == COM_LEFT || *p == COM_RIGHT)
2177+ align = *p++;
2178+ else if (VIM_ISDIGIT(*p) || *p == '-')
2179+ off = getdigits(&p);
2180+ else
2181+ ++p;
2182+ }
2183+
2184+ if (*p == ':')
2185+ ++p;
2186+ (void)copy_option_part(&p, lead_end, COM_MAX_LEN, ",");
2187+ if (what == COM_START)
2188+ {
2189+ STRCPY(lead_start, lead_end);
2190+ lead_start_len = (int)STRLEN(lead_start);
2191+ start_off = off;
2192+ start_align = align;
2193+ }
2194+ else if (what == COM_MIDDLE)
2195+ {
2196+ STRCPY(lead_middle, lead_end);
2197+ lead_middle_len = (int)STRLEN(lead_middle);
2198+ }
2199+ else if (what == COM_END)
2200+ {
2201+ // If our line starts with the middle comment string, line it
2202+ // up with the comment opener per the 'comments' option.
2203+ if (STRNCMP(theline, lead_middle, lead_middle_len) == 0
2204+ && STRNCMP(theline, lead_end, STRLEN(lead_end)) != 0)
2205+ {
2206+ done = TRUE;
2207+ if (curwin->w_cursor.lnum > 1)
2208+ {
2209+ // If the start comment string matches in the previous
2210+ // line, use the indent of that line plus offset. If
2211+ // the middle comment string matches in the previous
2212+ // line, use the indent of that line. XXX
2213+ look = skipwhite(ml_get(curwin->w_cursor.lnum - 1));
2214+ if (STRNCMP(look, lead_start, lead_start_len) == 0)
2215+ amount = get_indent_lnum(curwin->w_cursor.lnum - 1);
2216+ else if (STRNCMP(look, lead_middle,
2217+ lead_middle_len) == 0)
2218+ {
2219+ amount = get_indent_lnum(curwin->w_cursor.lnum - 1);
2220+ break;
2221+ }
2222+ // If the start comment string doesn't match with the
2223+ // start of the comment, skip this entry. XXX
2224+ else if (STRNCMP(ml_get(comment_pos->lnum) + comment_pos->col,
2225+ lead_start, lead_start_len) != 0)
2226+ continue;
2227+ }
2228+ if (start_off != 0)
2229+ amount += start_off;
2230+ else if (start_align == COM_RIGHT)
2231+ amount += vim_strsize(lead_start)
2232+ - vim_strsize(lead_middle);
2233+ break;
2234+ }
2235+
2236+ // If our line starts with the end comment string, line it up
2237+ // with the middle comment
2238+ if (STRNCMP(theline, lead_middle, lead_middle_len) != 0
2239+ && STRNCMP(theline, lead_end, STRLEN(lead_end)) == 0)
2240+ {
2241+ amount = get_indent_lnum(curwin->w_cursor.lnum - 1);
2242+ // XXX
2243+ if (off != 0)
2244+ amount += off;
2245+ else if (align == COM_RIGHT)
2246+ amount += vim_strsize(lead_start)
2247+ - vim_strsize(lead_middle);
2248+ done = TRUE;
2249+ break;
2250+ }
2251+ }
2252+ }
2253+
2254+ // If our line starts with an asterisk, line up with the
2255+ // asterisk in the comment opener; otherwise, line up
2256+ // with the first character of the comment text.
2257+ if (done)
2258+ ;
2259+ else if (theline[0] == '*')
2260+ amount += 1;
2261+ else
2262+ {
2263+ // If we are more than one line away from the comment opener, take
2264+ // the indent of the previous non-empty line. If 'cino' has "CO"
2265+ // and we are just below the comment opener and there are any
2266+ // white characters after it line up with the text after it;
2267+ // otherwise, add the amount specified by "c" in 'cino'
2268+ amount = -1;
2269+ for (lnum = cur_curpos.lnum - 1; lnum > comment_pos->lnum; --lnum)
2270+ {
2271+ if (linewhite(lnum)) // skip blank lines
2272+ continue;
2273+ amount = get_indent_lnum(lnum); // XXX
2274+ break;
2275+ }
2276+ if (amount == -1) // use the comment opener
2277+ {
2278+ if (!curbuf->b_ind_in_comment2)
2279+ {
2280+ start = ml_get(comment_pos->lnum);
2281+ look = start + comment_pos->col + 2; // skip / and *
2282+ if (*look != NUL) // if something after it
2283+ comment_pos->col = (colnr_T)(skipwhite(look) - start);
2284+ }
2285+ getvcol(curwin, comment_pos, &col, NULL, NULL);
2286+ amount = col;
2287+ if (curbuf->b_ind_in_comment2 || *look == NUL)
2288+ amount += curbuf->b_ind_in_comment;
2289+ }
2290+ }
2291+ goto theend;
2292+ }
2293+
2294+ // Are we looking at a ']' that has a match?
2295+ if (*skipwhite(theline) == ']'
2296+ && (trypos = find_match_char('[', curbuf->b_ind_maxparen)) != NULL)
2297+ {
2298+ // align with the line containing the '['.
2299+ amount = get_indent_lnum(trypos->lnum);
2300+ goto theend;
2301+ }
2302+
2303+ // Are we inside parentheses or braces? XXX
2304+ if (((trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL
2305+ && curbuf->b_ind_java == 0)
2306+ || (tryposBrace = find_start_brace()) != NULL
2307+ || trypos != NULL)
2308+ {
2309+ if (trypos != NULL && tryposBrace != NULL)
2310+ {
2311+ // Both an unmatched '(' and '{' is found. Use the one which is
2312+ // closer to the current cursor position, set the other to NULL.
2313+ if (trypos->lnum != tryposBrace->lnum
2314+ ? trypos->lnum < tryposBrace->lnum
2315+ : trypos->col < tryposBrace->col)
2316+ trypos = NULL;
2317+ else
2318+ tryposBrace = NULL;
2319+ }
2320+
2321+ if (trypos != NULL)
2322+ {
2323+ // If the matching paren is more than one line away, use the indent of
2324+ // a previous non-empty line that matches the same paren.
2325+ if (theline[0] == ')' && curbuf->b_ind_paren_prev)
2326+ {
2327+ // Line up with the start of the matching paren line.
2328+ amount = get_indent_lnum(curwin->w_cursor.lnum - 1); // XXX
2329+ }
2330+ else
2331+ {
2332+ amount = -1;
2333+ our_paren_pos = *trypos;
2334+ for (lnum = cur_curpos.lnum - 1; lnum > our_paren_pos.lnum; --lnum)
2335+ {
2336+ l = skipwhite(ml_get(lnum));
2337+ if (cin_nocode(l)) // skip comment lines
2338+ continue;
2339+ if (cin_ispreproc_cont(&l, &lnum, &amount))
2340+ continue; // ignore #define, #if, etc.
2341+ curwin->w_cursor.lnum = lnum;
2342+
2343+ // Skip a comment or raw string. XXX
2344+ if ((trypos = ind_find_start_CORS(NULL)) != NULL)
2345+ {
2346+ lnum = trypos->lnum + 1;
2347+ continue;
2348+ }
2349+
2350+ // XXX
2351+ if ((trypos = find_match_paren(
2352+ corr_ind_maxparen(&cur_curpos))) != NULL
2353+ && trypos->lnum == our_paren_pos.lnum
2354+ && trypos->col == our_paren_pos.col)
2355+ {
2356+ amount = get_indent_lnum(lnum); // XXX
2357+
2358+ if (theline[0] == ')')
2359+ {
2360+ if (our_paren_pos.lnum != lnum
2361+ && cur_amount > amount)
2362+ cur_amount = amount;
2363+ amount = -1;
2364+ }
2365+ break;
2366+ }
2367+ }
2368+ }
2369+
2370+ // Line up with line where the matching paren is. XXX
2371+ // If the line starts with a '(' or the indent for unclosed
2372+ // parentheses is zero, line up with the unclosed parentheses.
2373+ if (amount == -1)
2374+ {
2375+ int ignore_paren_col = 0;
2376+ int is_if_for_while = 0;
2377+
2378+ if (curbuf->b_ind_if_for_while)
2379+ {
2380+ // Look for the outermost opening parenthesis on this line
2381+ // and check whether it belongs to an "if", "for" or "while".
2382+
2383+ pos_T cursor_save = curwin->w_cursor;
2384+ pos_T outermost;
2385+ char_u *line;
2386+
2387+ trypos = &our_paren_pos;
2388+ do {
2389+ outermost = *trypos;
2390+ curwin->w_cursor.lnum = outermost.lnum;
2391+ curwin->w_cursor.col = outermost.col;
2392+
2393+ trypos = find_match_paren(curbuf->b_ind_maxparen);
2394+ } while (trypos && trypos->lnum == outermost.lnum);
2395+
2396+ curwin->w_cursor = cursor_save;
2397+
2398+ line = ml_get(outermost.lnum);
2399+
2400+ is_if_for_while =
2401+ cin_is_if_for_while_before_offset(line, &outermost.col);
2402+ }
2403+
2404+ amount = skip_label(our_paren_pos.lnum, &look);
2405+ look = skipwhite(look);
2406+ if (*look == '(')
2407+ {
2408+ linenr_T save_lnum = curwin->w_cursor.lnum;
2409+ char_u *line;
2410+ int look_col;
2411+
2412+ // Ignore a '(' in front of the line that has a match before
2413+ // our matching '('.
2414+ curwin->w_cursor.lnum = our_paren_pos.lnum;
2415+ line = ml_get_curline();
2416+ look_col = (int)(look - line);
2417+ curwin->w_cursor.col = look_col + 1;
2418+ if ((trypos = findmatchlimit(NULL, ')', 0,
2419+ curbuf->b_ind_maxparen))
2420+ != NULL
2421+ && trypos->lnum == our_paren_pos.lnum
2422+ && trypos->col < our_paren_pos.col)
2423+ ignore_paren_col = trypos->col + 1;
2424+
2425+ curwin->w_cursor.lnum = save_lnum;
2426+ look = ml_get(our_paren_pos.lnum) + look_col;
2427+ }
2428+ if (theline[0] == ')' || (curbuf->b_ind_unclosed == 0
2429+ && is_if_for_while == 0)
2430+ || (!curbuf->b_ind_unclosed_noignore && *look == '('
2431+ && ignore_paren_col == 0))
2432+ {
2433+ // If we're looking at a close paren, line up right there;
2434+ // otherwise, line up with the next (non-white) character.
2435+ // When b_ind_unclosed_wrapped is set and the matching paren is
2436+ // the last nonwhite character of the line, use either the
2437+ // indent of the current line or the indentation of the next
2438+ // outer paren and add b_ind_unclosed_wrapped (for very long
2439+ // lines).
2440+ if (theline[0] != ')')
2441+ {
2442+ cur_amount = MAXCOL;
2443+ l = ml_get(our_paren_pos.lnum);
2444+ if (curbuf->b_ind_unclosed_wrapped
2445+ && cin_ends_in(l, (char_u *)"(", NULL))
2446+ {
2447+ // look for opening unmatched paren, indent one level
2448+ // for each additional level
2449+ n = 1;
2450+ for (col = 0; col < our_paren_pos.col; ++col)
2451+ {
2452+ switch (l[col])
2453+ {
2454+ case '(':
2455+ case '{': ++n;
2456+ break;
2457+
2458+ case ')':
2459+ case '}': if (n > 1)
2460+ --n;
2461+ break;
2462+ }
2463+ }
2464+
2465+ our_paren_pos.col = 0;
2466+ amount += n * curbuf->b_ind_unclosed_wrapped;
2467+ }
2468+ else if (curbuf->b_ind_unclosed_whiteok)
2469+ our_paren_pos.col++;
2470+ else
2471+ {
2472+ col = our_paren_pos.col + 1;
2473+ while (VIM_ISWHITE(l[col]))
2474+ col++;
2475+ if (l[col] != NUL) // In case of trailing space
2476+ our_paren_pos.col = col;
2477+ else
2478+ our_paren_pos.col++;
2479+ }
2480+ }
2481+
2482+ // Find how indented the paren is, or the character after it
2483+ // if we did the above "if".
2484+ if (our_paren_pos.col > 0)
2485+ {
2486+ getvcol(curwin, &our_paren_pos, &col, NULL, NULL);
2487+ if (cur_amount > (int)col)
2488+ cur_amount = col;
2489+ }
2490+ }
2491+
2492+ if (theline[0] == ')' && curbuf->b_ind_matching_paren)
2493+ {
2494+ // Line up with the start of the matching paren line.
2495+ }
2496+ else if ((curbuf->b_ind_unclosed == 0 && is_if_for_while == 0)
2497+ || (!curbuf->b_ind_unclosed_noignore
2498+ && *look == '(' && ignore_paren_col == 0))
2499+ {
2500+ if (cur_amount != MAXCOL)
2501+ amount = cur_amount;
2502+ }
2503+ else
2504+ {
2505+ // Add b_ind_unclosed2 for each '(' before our matching one,
2506+ // but ignore (void) before the line (ignore_paren_col).
2507+ col = our_paren_pos.col;
2508+ while ((int)our_paren_pos.col > ignore_paren_col)
2509+ {
2510+ --our_paren_pos.col;
2511+ switch (*ml_get_pos(&our_paren_pos))
2512+ {
2513+ case '(': amount += curbuf->b_ind_unclosed2;
2514+ col = our_paren_pos.col;
2515+ break;
2516+ case ')': amount -= curbuf->b_ind_unclosed2;
2517+ col = MAXCOL;
2518+ break;
2519+ }
2520+ }
2521+
2522+ // Use b_ind_unclosed once, when the first '(' is not inside
2523+ // braces
2524+ if (col == MAXCOL)
2525+ amount += curbuf->b_ind_unclosed;
2526+ else
2527+ {
2528+ curwin->w_cursor.lnum = our_paren_pos.lnum;
2529+ curwin->w_cursor.col = col;
2530+ if (find_match_paren_after_brace(curbuf->b_ind_maxparen)
2531+ != NULL)
2532+ amount += curbuf->b_ind_unclosed2;
2533+ else
2534+ {
2535+ if (is_if_for_while)
2536+ amount += curbuf->b_ind_if_for_while;
2537+ else
2538+ amount += curbuf->b_ind_unclosed;
2539+ }
2540+ }
2541+ // For a line starting with ')' use the minimum of the two
2542+ // positions, to avoid giving it more indent than the previous
2543+ // lines:
2544+ // func_long_name( if (x
2545+ // arg && yy
2546+ // ) ^ not here ) ^ not here
2547+ if (cur_amount < amount)
2548+ amount = cur_amount;
2549+ }
2550+ }
2551+
2552+ // add extra indent for a comment
2553+ if (cin_iscomment(theline))
2554+ amount += curbuf->b_ind_comment;
2555+ }
2556+ else
2557+ {
2558+ // We are inside braces, there is a { before this line at the position
2559+ // stored in tryposBrace.
2560+ // Make a copy of tryposBrace, it may point to pos_copy inside
2561+ // find_start_brace(), which may be changed somewhere.
2562+ tryposCopy = *tryposBrace;
2563+ tryposBrace = &tryposCopy;
2564+ trypos = tryposBrace;
2565+ ourscope = trypos->lnum;
2566+ start = ml_get(ourscope);
2567+
2568+ // Now figure out how indented the line is in general.
2569+ // If the brace was at the start of the line, we use that;
2570+ // otherwise, check out the indentation of the line as
2571+ // a whole and then add the "imaginary indent" to that.
2572+ look = skipwhite(start);
2573+ if (*look == '{')
2574+ {
2575+ getvcol(curwin, trypos, &col, NULL, NULL);
2576+ amount = col;
2577+ if (*start == '{')
2578+ start_brace = BRACE_IN_COL0;
2579+ else
2580+ start_brace = BRACE_AT_START;
2581+ }
2582+ else
2583+ {
2584+ // That opening brace might have been on a continuation
2585+ // line. if so, find the start of the line.
2586+ curwin->w_cursor.lnum = ourscope;
2587+
2588+ // Position the cursor over the rightmost paren, so that
2589+ // matching it will take us back to the start of the line.
2590+ lnum = ourscope;
2591+ if (find_last_paren(start, '(', ')')
2592+ && (trypos = find_match_paren(curbuf->b_ind_maxparen))
2593+ != NULL)
2594+ lnum = trypos->lnum;
2595+
2596+ // It could have been something like
2597+ // case 1: if (asdf &&
2598+ // ldfd) {
2599+ // }
2600+ if ((curbuf->b_ind_js || curbuf->b_ind_keep_case_label)
2601+ && cin_iscase(skipwhite(ml_get_curline()), FALSE))
2602+ amount = get_indent();
2603+ else if (curbuf->b_ind_js)
2604+ amount = get_indent_lnum(lnum);
2605+ else
2606+ amount = skip_label(lnum, &l);
2607+
2608+ start_brace = BRACE_AT_END;
2609+ }
2610+
2611+ // For Javascript check if the line starts with "key:".
2612+ if (curbuf->b_ind_js)
2613+ js_cur_has_key = cin_has_js_key(theline);
2614+
2615+ // If we're looking at a closing brace, that's where
2616+ // we want to be. otherwise, add the amount of room
2617+ // that an indent is supposed to be.
2618+ if (theline[0] == '}')
2619+ {
2620+ // they may want closing braces to line up with something
2621+ // other than the open brace. indulge them, if so.
2622+ amount += curbuf->b_ind_close_extra;
2623+ }
2624+ else
2625+ {
2626+ // If we're looking at an "else", try to find an "if"
2627+ // to match it with.
2628+ // If we're looking at a "while", try to find a "do"
2629+ // to match it with.
2630+ lookfor = LOOKFOR_INITIAL;
2631+ if (cin_iselse(theline))
2632+ lookfor = LOOKFOR_IF;
2633+ else if (cin_iswhileofdo(theline, cur_curpos.lnum)) // XXX
2634+ lookfor = LOOKFOR_DO;
2635+ if (lookfor != LOOKFOR_INITIAL)
2636+ {
2637+ curwin->w_cursor.lnum = cur_curpos.lnum;
2638+ if (find_match(lookfor, ourscope) == OK)
2639+ {
2640+ amount = get_indent(); // XXX
2641+ goto theend;
2642+ }
2643+ }
2644+
2645+ // We get here if we are not on an "while-of-do" or "else" (or
2646+ // failed to find a matching "if").
2647+ // Search backwards for something to line up with.
2648+ // First set amount for when we don't find anything.
2649+
2650+ // if the '{' is _really_ at the left margin, use the imaginary
2651+ // location of a left-margin brace. Otherwise, correct the
2652+ // location for b_ind_open_extra.
2653+
2654+ if (start_brace == BRACE_IN_COL0) // '{' is in column 0
2655+ {
2656+ amount = curbuf->b_ind_open_left_imag;
2657+ lookfor_cpp_namespace = TRUE;
2658+ }
2659+ else if (start_brace == BRACE_AT_START &&
2660+ lookfor_cpp_namespace) // '{' is at start
2661+ {
2662+
2663+ lookfor_cpp_namespace = TRUE;
2664+ }
2665+ else
2666+ {
2667+ if (start_brace == BRACE_AT_END) // '{' is at end of line
2668+ {
2669+ amount += curbuf->b_ind_open_imag;
2670+
2671+ l = skipwhite(ml_get_curline());
2672+ if (cin_is_cpp_namespace(l))
2673+ amount += curbuf->b_ind_cpp_namespace;
2674+ else if (cin_is_cpp_extern_c(l))
2675+ amount += curbuf->b_ind_cpp_extern_c;
2676+ }
2677+ else
2678+ {
2679+ // Compensate for adding b_ind_open_extra later.
2680+ amount -= curbuf->b_ind_open_extra;
2681+ if (amount < 0)
2682+ amount = 0;
2683+ }
2684+ }
2685+
2686+ lookfor_break = FALSE;
2687+
2688+ if (cin_iscase(theline, FALSE)) // it's a switch() label
2689+ {
2690+ lookfor = LOOKFOR_CASE; // find a previous switch() label
2691+ amount += curbuf->b_ind_case;
2692+ }
2693+ else if (cin_isscopedecl(theline)) // private:, ...
2694+ {
2695+ lookfor = LOOKFOR_SCOPEDECL; // class decl is this block
2696+ amount += curbuf->b_ind_scopedecl;
2697+ }
2698+ else
2699+ {
2700+ if (curbuf->b_ind_case_break && cin_isbreak(theline))
2701+ // break; ...
2702+ lookfor_break = TRUE;
2703+
2704+ lookfor = LOOKFOR_INITIAL;
2705+ // b_ind_level from start of block
2706+ amount += curbuf->b_ind_level;
2707+ }
2708+ scope_amount = amount;
2709+ whilelevel = 0;
2710+
2711+ // Search backwards. If we find something we recognize, line up
2712+ // with that.
2713+ //
2714+ // If we're looking at an open brace, indent
2715+ // the usual amount relative to the conditional
2716+ // that opens the block.
2717+ curwin->w_cursor = cur_curpos;
2718+ for (;;)
2719+ {
2720+ curwin->w_cursor.lnum--;
2721+ curwin->w_cursor.col = 0;
2722+
2723+ // If we went all the way back to the start of our scope, line
2724+ // up with it.
2725+ if (curwin->w_cursor.lnum <= ourscope)
2726+ {
2727+ // We reached end of scope:
2728+ // If looking for a enum or structure initialization
2729+ // go further back:
2730+ // If it is an initializer (enum xxx or xxx =), then
2731+ // don't add ind_continuation, otherwise it is a variable
2732+ // declaration:
2733+ // int x,
2734+ // here; <-- add ind_continuation
2735+ if (lookfor == LOOKFOR_ENUM_OR_INIT)
2736+ {
2737+ if (curwin->w_cursor.lnum == 0
2738+ || curwin->w_cursor.lnum
2739+ < ourscope - curbuf->b_ind_maxparen)
2740+ {
2741+ // nothing found (abuse curbuf->b_ind_maxparen as
2742+ // limit) assume terminated line (i.e. a variable
2743+ // initialization)
2744+ if (cont_amount > 0)
2745+ amount = cont_amount;
2746+ else if (!curbuf->b_ind_js)
2747+ amount += ind_continuation;
2748+ break;
2749+ }
2750+
2751+ l = ml_get_curline();
2752+
2753+ // If we're in a comment or raw string now, skip to
2754+ // the start of it.
2755+ trypos = ind_find_start_CORS(NULL);
2756+ if (trypos != NULL)
2757+ {
2758+ curwin->w_cursor.lnum = trypos->lnum + 1;
2759+ curwin->w_cursor.col = 0;
2760+ continue;
2761+ }
2762+
2763+ // Skip preprocessor directives and blank lines.
2764+ if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum,
2765+ &amount))
2766+ continue;
2767+
2768+ if (cin_nocode(l))
2769+ continue;
2770+
2771+ terminated = cin_isterminated(l, FALSE, TRUE);
2772+
2773+ // If we are at top level and the line looks like a
2774+ // function declaration, we are done
2775+ // (it's a variable declaration).
2776+ if (start_brace != BRACE_IN_COL0
2777+ || !cin_isfuncdecl(&l, curwin->w_cursor.lnum, 0))
2778+ {
2779+ // if the line is terminated with another ','
2780+ // it is a continued variable initialization.
2781+ // don't add extra indent.
2782+ // TODO: does not work, if a function
2783+ // declaration is split over multiple lines:
2784+ // cin_isfuncdecl returns FALSE then.
2785+ if (terminated == ',')
2786+ break;
2787+
2788+ // if it es a enum declaration or an assignment,
2789+ // we are done.
2790+ if (terminated != ';' && cin_isinit())
2791+ break;
2792+
2793+ // nothing useful found
2794+ if (terminated == 0 || terminated == '{')
2795+ continue;
2796+ }
2797+
2798+ if (terminated != ';')
2799+ {
2800+ // Skip parens and braces. Position the cursor
2801+ // over the rightmost paren, so that matching it
2802+ // will take us back to the start of the line.
2803+ // XXX
2804+ trypos = NULL;
2805+ if (find_last_paren(l, '(', ')'))
2806+ trypos = find_match_paren(
2807+ curbuf->b_ind_maxparen);
2808+
2809+ if (trypos == NULL && find_last_paren(l, '{', '}'))
2810+ trypos = find_start_brace();
2811+
2812+ if (trypos != NULL)
2813+ {
2814+ curwin->w_cursor.lnum = trypos->lnum + 1;
2815+ curwin->w_cursor.col = 0;
2816+ continue;
2817+ }
2818+ }
2819+
2820+ // it's a variable declaration, add indentation
2821+ // like in
2822+ // int a,
2823+ // b;
2824+ if (cont_amount > 0)
2825+ amount = cont_amount;
2826+ else
2827+ amount += ind_continuation;
2828+ }
2829+ else if (lookfor == LOOKFOR_UNTERM)
2830+ {
2831+ if (cont_amount > 0)
2832+ amount = cont_amount;
2833+ else
2834+ amount += ind_continuation;
2835+ }
2836+ else
2837+ {
2838+ if (lookfor != LOOKFOR_TERM
2839+ && lookfor != LOOKFOR_CPP_BASECLASS
2840+ && lookfor != LOOKFOR_COMMA)
2841+ {
2842+ amount = scope_amount;
2843+ if (theline[0] == '{')
2844+ {
2845+ amount += curbuf->b_ind_open_extra;
2846+ added_to_amount = curbuf->b_ind_open_extra;
2847+ }
2848+ }
2849+
2850+ if (lookfor_cpp_namespace)
2851+ {
2852+ // Looking for C++ namespace, need to look further
2853+ // back.
2854+ if (curwin->w_cursor.lnum == ourscope)
2855+ continue;
2856+
2857+ if (curwin->w_cursor.lnum == 0
2858+ || curwin->w_cursor.lnum
2859+ < ourscope - FIND_NAMESPACE_LIM)
2860+ break;
2861+
2862+ l = ml_get_curline();
2863+
2864+ // If we're in a comment or raw string now, skip
2865+ // to the start of it.
2866+ trypos = ind_find_start_CORS(NULL);
2867+ if (trypos != NULL)
2868+ {
2869+ curwin->w_cursor.lnum = trypos->lnum + 1;
2870+ curwin->w_cursor.col = 0;
2871+ continue;
2872+ }
2873+
2874+ // Skip preprocessor directives and blank lines.
2875+ if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum,
2876+ &amount))
2877+ continue;
2878+
2879+ // Finally the actual check for "namespace".
2880+ if (cin_is_cpp_namespace(l))
2881+ {
2882+ amount += curbuf->b_ind_cpp_namespace
2883+ - added_to_amount;
2884+ break;
2885+ }
2886+ else if (cin_is_cpp_extern_c(l))
2887+ {
2888+ amount += curbuf->b_ind_cpp_extern_c
2889+ - added_to_amount;
2890+ break;
2891+ }
2892+
2893+ if (cin_nocode(l))
2894+ continue;
2895+ }
2896+ }
2897+ break;
2898+ }
2899+
2900+ // If we're in a comment or raw string now, skip to the start
2901+ // of it. XXX
2902+ if ((trypos = ind_find_start_CORS(&raw_string_start)) != NULL)
2903+ {
2904+ curwin->w_cursor.lnum = trypos->lnum + 1;
2905+ curwin->w_cursor.col = 0;
2906+ continue;
2907+ }
2908+
2909+ l = ml_get_curline();
2910+
2911+ // If this is a switch() label, may line up relative to that.
2912+ // If this is a C++ scope declaration, do the same.
2913+ iscase = cin_iscase(l, FALSE);
2914+ if (iscase || cin_isscopedecl(l))
2915+ {
2916+ // we are only looking for cpp base class
2917+ // declaration/initialization any longer
2918+ if (lookfor == LOOKFOR_CPP_BASECLASS)
2919+ break;
2920+
2921+ // When looking for a "do" we are not interested in
2922+ // labels.
2923+ if (whilelevel > 0)
2924+ continue;
2925+
2926+ // case xx:
2927+ // c = 99 + <- this indent plus continuation
2928+ //-> here;
2929+ if (lookfor == LOOKFOR_UNTERM
2930+ || lookfor == LOOKFOR_ENUM_OR_INIT)
2931+ {
2932+ if (cont_amount > 0)
2933+ amount = cont_amount;
2934+ else
2935+ amount += ind_continuation;
2936+ break;
2937+ }
2938+
2939+ // case xx: <- line up with this case
2940+ // x = 333;
2941+ // case yy:
2942+ if ( (iscase && lookfor == LOOKFOR_CASE)
2943+ || (iscase && lookfor_break)
2944+ || (!iscase && lookfor == LOOKFOR_SCOPEDECL))
2945+ {
2946+ // Check that this case label is not for another
2947+ // switch() XXX
2948+ if ((trypos = find_start_brace()) == NULL
2949+ || trypos->lnum == ourscope)
2950+ {
2951+ amount = get_indent(); // XXX
2952+ break;
2953+ }
2954+ continue;
2955+ }
2956+
2957+ n = get_indent_nolabel(curwin->w_cursor.lnum); // XXX
2958+
2959+ // case xx: if (cond) <- line up with this if
2960+ // y = y + 1;
2961+ // -> s = 99;
2962+ //
2963+ // case xx:
2964+ // if (cond) <- line up with this line
2965+ // y = y + 1;
2966+ // -> s = 99;
2967+ if (lookfor == LOOKFOR_TERM)
2968+ {
2969+ if (n)
2970+ amount = n;
2971+
2972+ if (!lookfor_break)
2973+ break;
2974+ }
2975+
2976+ // case xx: x = x + 1; <- line up with this x
2977+ // -> y = y + 1;
2978+ //
2979+ // case xx: if (cond) <- line up with this if
2980+ // -> y = y + 1;
2981+ if (n)
2982+ {
2983+ amount = n;
2984+ l = after_label(ml_get_curline());
2985+ if (l != NULL && cin_is_cinword(l))
2986+ {
2987+ if (theline[0] == '{')
2988+ amount += curbuf->b_ind_open_extra;
2989+ else
2990+ amount += curbuf->b_ind_level
2991+ + curbuf->b_ind_no_brace;
2992+ }
2993+ break;
2994+ }
2995+
2996+ // Try to get the indent of a statement before the switch
2997+ // label. If nothing is found, line up relative to the
2998+ // switch label.
2999+ // break; <- may line up with this line
3000+ // case xx:
3001+ // -> y = 1;
3002+ scope_amount = get_indent() + (iscase // XXX
3003+ ? curbuf->b_ind_case_code
3004+ : curbuf->b_ind_scopedecl_code);
3005+ lookfor = curbuf->b_ind_case_break
3006+ ? LOOKFOR_NOBREAK : LOOKFOR_ANY;
3007+ continue;
3008+ }
3009+
3010+ // Looking for a switch() label or C++ scope declaration,
3011+ // ignore other lines, skip {}-blocks.
3012+ if (lookfor == LOOKFOR_CASE || lookfor == LOOKFOR_SCOPEDECL)
3013+ {
3014+ if (find_last_paren(l, '{', '}')
3015+ && (trypos = find_start_brace()) != NULL)
3016+ {
3017+ curwin->w_cursor.lnum = trypos->lnum + 1;
3018+ curwin->w_cursor.col = 0;
3019+ }
3020+ continue;
3021+ }
3022+
3023+ // Ignore jump labels with nothing after them.
3024+ if (!curbuf->b_ind_js && cin_islabel())
3025+ {
3026+ l = after_label(ml_get_curline());
3027+ if (l == NULL || cin_nocode(l))
3028+ continue;
3029+ }
3030+
3031+ // Ignore #defines, #if, etc.
3032+ // Ignore comment and empty lines.
3033+ // (need to get the line again, cin_islabel() may have
3034+ // unlocked it)
3035+ l = ml_get_curline();
3036+ if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum, &amount)
3037+ || cin_nocode(l))
3038+ continue;
3039+
3040+ // Are we at the start of a cpp base class declaration or
3041+ // constructor initialization? XXX
3042+ n = FALSE;
3043+ if (lookfor != LOOKFOR_TERM && curbuf->b_ind_cpp_baseclass > 0)
3044+ {
3045+ n = cin_is_cpp_baseclass(&cache_cpp_baseclass);
3046+ l = ml_get_curline();
3047+ }
3048+ if (n)
3049+ {
3050+ if (lookfor == LOOKFOR_UNTERM)
3051+ {
3052+ if (cont_amount > 0)
3053+ amount = cont_amount;
3054+ else
3055+ amount += ind_continuation;
3056+ }
3057+ else if (theline[0] == '{')
3058+ {
3059+ // Need to find start of the declaration.
3060+ lookfor = LOOKFOR_UNTERM;
3061+ ind_continuation = 0;
3062+ continue;
3063+ }
3064+ else
3065+ // XXX
3066+ amount = get_baseclass_amount(
3067+ cache_cpp_baseclass.lpos.col);
3068+ break;
3069+ }
3070+ else if (lookfor == LOOKFOR_CPP_BASECLASS)
3071+ {
3072+ // only look, whether there is a cpp base class
3073+ // declaration or initialization before the opening brace.
3074+ if (cin_isterminated(l, TRUE, FALSE))
3075+ break;
3076+ else
3077+ continue;
3078+ }
3079+
3080+ // What happens next depends on the line being terminated.
3081+ // If terminated with a ',' only consider it terminating if
3082+ // there is another unterminated statement behind, eg:
3083+ // 123,
3084+ // sizeof
3085+ // here
3086+ // Otherwise check whether it is a enumeration or structure
3087+ // initialisation (not indented) or a variable declaration
3088+ // (indented).
3089+ terminated = cin_isterminated(l, FALSE, TRUE);
3090+
3091+ if (js_cur_has_key)
3092+ {
3093+ js_cur_has_key = 0; // only check the first line
3094+ if (curbuf->b_ind_js && terminated == ',')
3095+ {
3096+ // For Javascript we might be inside an object:
3097+ // key: something, <- align with this
3098+ // key: something
3099+ // or:
3100+ // key: something + <- align with this
3101+ // something,
3102+ // key: something
3103+ lookfor = LOOKFOR_JS_KEY;
3104+ }
3105+ }
3106+ if (lookfor == LOOKFOR_JS_KEY && cin_has_js_key(l))
3107+ {
3108+ amount = get_indent();
3109+ break;
3110+ }
3111+ if (lookfor == LOOKFOR_COMMA)
3112+ {
3113+ if (tryposBrace != NULL && tryposBrace->lnum
3114+ >= curwin->w_cursor.lnum)
3115+ break;
3116+ if (terminated == ',')
3117+ // line below current line is the one that starts a
3118+ // (possibly broken) line ending in a comma.
3119+ break;
3120+ else
3121+ {
3122+ amount = get_indent();
3123+ if (curwin->w_cursor.lnum - 1 == ourscope)
3124+ // line above is start of the scope, thus current
3125+ // line is the one that stars a (possibly broken)
3126+ // line ending in a comma.
3127+ break;
3128+ }
3129+ }
3130+
3131+ if (terminated == 0 || (lookfor != LOOKFOR_UNTERM
3132+ && terminated == ','))
3133+ {
3134+ if (lookfor != LOOKFOR_ENUM_OR_INIT &&
3135+ (*skipwhite(l) == '[' || l[STRLEN(l) - 1] == '['))
3136+ amount += ind_continuation;
3137+ // if we're in the middle of a paren thing,
3138+ // go back to the line that starts it so
3139+ // we can get the right prevailing indent
3140+ // if ( foo &&
3141+ // bar )
3142+
3143+ // Position the cursor over the rightmost paren, so that
3144+ // matching it will take us back to the start of the line.
3145+ // Ignore a match before the start of the block.
3146+ (void)find_last_paren(l, '(', ')');
3147+ trypos = find_match_paren(corr_ind_maxparen(&cur_curpos));
3148+ if (trypos != NULL && (trypos->lnum < tryposBrace->lnum
3149+ || (trypos->lnum == tryposBrace->lnum
3150+ && trypos->col < tryposBrace->col)))
3151+ trypos = NULL;
3152+
3153+ // If we are looking for ',', we also look for matching
3154+ // braces.
3155+ if (trypos == NULL && terminated == ','
3156+ && find_last_paren(l, '{', '}'))
3157+ trypos = find_start_brace();
3158+
3159+ if (trypos != NULL)
3160+ {
3161+ // Check if we are on a case label now. This is
3162+ // handled above.
3163+ // case xx: if ( asdf &&
3164+ // asdf)
3165+ curwin->w_cursor = *trypos;
3166+ l = ml_get_curline();
3167+ if (cin_iscase(l, FALSE) || cin_isscopedecl(l))
3168+ {
3169+ ++curwin->w_cursor.lnum;
3170+ curwin->w_cursor.col = 0;
3171+ continue;
3172+ }
3173+ }
3174+
3175+ // Skip over continuation lines to find the one to get the
3176+ // indent from
3177+ // char *usethis = "bla{backslash}
3178+ // bla",
3179+ // here;
3180+ if (terminated == ',')
3181+ {
3182+ while (curwin->w_cursor.lnum > 1)
3183+ {
3184+ l = ml_get(curwin->w_cursor.lnum - 1);
3185+ if (*l == NUL || l[STRLEN(l) - 1] != '\\')
3186+ break;
3187+ --curwin->w_cursor.lnum;
3188+ curwin->w_cursor.col = 0;
3189+ }
3190+ }
3191+
3192+ // Get indent and pointer to text for current line,
3193+ // ignoring any jump label. XXX
3194+ if (curbuf->b_ind_js)
3195+ cur_amount = get_indent();
3196+ else
3197+ cur_amount = skip_label(curwin->w_cursor.lnum, &l);
3198+ // If this is just above the line we are indenting, and it
3199+ // starts with a '{', line it up with this line.
3200+ // while (not)
3201+ // -> {
3202+ // }
3203+ if (terminated != ',' && lookfor != LOOKFOR_TERM
3204+ && theline[0] == '{')
3205+ {
3206+ amount = cur_amount;
3207+ // Only add b_ind_open_extra when the current line
3208+ // doesn't start with a '{', which must have a match
3209+ // in the same line (scope is the same). Probably:
3210+ // { 1, 2 },
3211+ // -> { 3, 4 }
3212+ if (*skipwhite(l) != '{')
3213+ amount += curbuf->b_ind_open_extra;
3214+
3215+ if (curbuf->b_ind_cpp_baseclass && !curbuf->b_ind_js)
3216+ {
3217+ // have to look back, whether it is a cpp base
3218+ // class declaration or initialization
3219+ lookfor = LOOKFOR_CPP_BASECLASS;
3220+ continue;
3221+ }
3222+ break;
3223+ }
3224+
3225+ // Check if we are after an "if", "while", etc.
3226+ // Also allow " } else".
3227+ if (cin_is_cinword(l) || cin_iselse(skipwhite(l)))
3228+ {
3229+ // Found an unterminated line after an if (), line up
3230+ // with the last one.
3231+ // if (cond)
3232+ // 100 +
3233+ // -> here;
3234+ if (lookfor == LOOKFOR_UNTERM
3235+ || lookfor == LOOKFOR_ENUM_OR_INIT)
3236+ {
3237+ if (cont_amount > 0)
3238+ amount = cont_amount;
3239+ else
3240+ amount += ind_continuation;
3241+ break;
3242+ }
3243+
3244+ // If this is just above the line we are indenting, we
3245+ // are finished.
3246+ // while (not)
3247+ // -> here;
3248+ // Otherwise this indent can be used when the line
3249+ // before this is terminated.
3250+ // yyy;
3251+ // if (stat)
3252+ // while (not)
3253+ // xxx;
3254+ // -> here;
3255+ amount = cur_amount;
3256+ if (theline[0] == '{')
3257+ amount += curbuf->b_ind_open_extra;
3258+ if (lookfor != LOOKFOR_TERM)
3259+ {
3260+ amount += curbuf->b_ind_level
3261+ + curbuf->b_ind_no_brace;
3262+ break;
3263+ }
3264+
3265+ // Special trick: when expecting the while () after a
3266+ // do, line up with the while()
3267+ // do
3268+ // x = 1;
3269+ // -> here
3270+ l = skipwhite(ml_get_curline());
3271+ if (cin_isdo(l))
3272+ {
3273+ if (whilelevel == 0)
3274+ break;
3275+ --whilelevel;
3276+ }
3277+
3278+ // When searching for a terminated line, don't use the
3279+ // one between the "if" and the matching "else".
3280+ // Need to use the scope of this "else". XXX
3281+ // If whilelevel != 0 continue looking for a "do {".
3282+ if (cin_iselse(l) && whilelevel == 0)
3283+ {
3284+ // If we're looking at "} else", let's make sure we
3285+ // find the opening brace of the enclosing scope,
3286+ // not the one from "if () {".
3287+ if (*l == '}')
3288+ curwin->w_cursor.col =
3289+ (colnr_T)(l - ml_get_curline()) + 1;
3290+
3291+ if ((trypos = find_start_brace()) == NULL
3292+ || find_match(LOOKFOR_IF, trypos->lnum)
3293+ == FAIL)
3294+ break;
3295+ }
3296+ }
3297+
3298+ // If we're below an unterminated line that is not an
3299+ // "if" or something, we may line up with this line or
3300+ // add something for a continuation line, depending on
3301+ // the line before this one.
3302+ else
3303+ {
3304+ // Found two unterminated lines on a row, line up with
3305+ // the last one.
3306+ // c = 99 +
3307+ // 100 +
3308+ // -> here;
3309+ if (lookfor == LOOKFOR_UNTERM)
3310+ {
3311+ // When line ends in a comma add extra indent
3312+ if (terminated == ',')
3313+ amount += ind_continuation;
3314+ break;
3315+ }
3316+
3317+ if (lookfor == LOOKFOR_ENUM_OR_INIT)
3318+ {
3319+ // Found two lines ending in ',', lineup with the
3320+ // lowest one, but check for cpp base class
3321+ // declaration/initialization, if it is an
3322+ // opening brace or we are looking just for
3323+ // enumerations/initializations.
3324+ if (terminated == ',')
3325+ {
3326+ if (curbuf->b_ind_cpp_baseclass == 0)
3327+ break;
3328+
3329+ lookfor = LOOKFOR_CPP_BASECLASS;
3330+ continue;
3331+ }
3332+
3333+ // Ignore unterminated lines in between, but
3334+ // reduce indent.
3335+ if (amount > cur_amount)
3336+ amount = cur_amount;
3337+ }
3338+ else
3339+ {
3340+ // Found first unterminated line on a row, may
3341+ // line up with this line, remember its indent
3342+ // 100 +
3343+ // -> here;
3344+ l = ml_get_curline();
3345+ amount = cur_amount;
3346+
3347+ n = (int)STRLEN(l);
3348+ if (terminated == ',' && (*skipwhite(l) == ']'
3349+ || (n >=2 && l[n - 2] == ']')))
3350+ break;
3351+
3352+ // If previous line ends in ',', check whether we
3353+ // are in an initialization or enum
3354+ // struct xxx =
3355+ // {
3356+ // sizeof a,
3357+ // 124 };
3358+ // or a normal possible continuation line.
3359+ // but only, of no other statement has been found
3360+ // yet.
3361+ if (lookfor == LOOKFOR_INITIAL && terminated == ',')
3362+ {
3363+ if (curbuf->b_ind_js)
3364+ {
3365+ // Search for a line ending in a comma
3366+ // and line up with the line below it
3367+ // (could be the current line).
3368+ // some = [
3369+ // 1, <- line up here
3370+ // 2,
3371+ // some = [
3372+ // 3 + <- line up here
3373+ // 4 *
3374+ // 5,
3375+ // 6,
3376+ if (cin_iscomment(skipwhite(l)))
3377+ break;
3378+ lookfor = LOOKFOR_COMMA;
3379+ trypos = find_match_char('[',
3380+ curbuf->b_ind_maxparen);
3381+ if (trypos != NULL)
3382+ {
3383+ if (trypos->lnum
3384+ == curwin->w_cursor.lnum - 1)
3385+ {
3386+ // Current line is first inside
3387+ // [], line up with it.
3388+ break;
3389+ }
3390+ ourscope = trypos->lnum;
3391+ }
3392+ }
3393+ else
3394+ {
3395+ lookfor = LOOKFOR_ENUM_OR_INIT;
3396+ cont_amount = cin_first_id_amount();
3397+ }
3398+ }
3399+ else
3400+ {
3401+ if (lookfor == LOOKFOR_INITIAL
3402+ && *l != NUL
3403+ && l[STRLEN(l) - 1] == '\\')
3404+ // XXX
3405+ cont_amount = cin_get_equal_amount(
3406+ curwin->w_cursor.lnum);
3407+ if (lookfor != LOOKFOR_TERM
3408+ && lookfor != LOOKFOR_JS_KEY
3409+ && lookfor != LOOKFOR_COMMA
3410+ && raw_string_start != curwin->w_cursor.lnum)
3411+ lookfor = LOOKFOR_UNTERM;
3412+ }
3413+ }
3414+ }
3415+ }
3416+
3417+ // Check if we are after a while (cond);
3418+ // If so: Ignore until the matching "do".
3419+ else if (cin_iswhileofdo_end(terminated)) // XXX
3420+ {
3421+ // Found an unterminated line after a while ();, line up
3422+ // with the last one.
3423+ // while (cond);
3424+ // 100 + <- line up with this one
3425+ // -> here;
3426+ if (lookfor == LOOKFOR_UNTERM
3427+ || lookfor == LOOKFOR_ENUM_OR_INIT)
3428+ {
3429+ if (cont_amount > 0)
3430+ amount = cont_amount;
3431+ else
3432+ amount += ind_continuation;
3433+ break;
3434+ }
3435+
3436+ if (whilelevel == 0)
3437+ {
3438+ lookfor = LOOKFOR_TERM;
3439+ amount = get_indent(); // XXX
3440+ if (theline[0] == '{')
3441+ amount += curbuf->b_ind_open_extra;
3442+ }
3443+ ++whilelevel;
3444+ }
3445+
3446+ // We are after a "normal" statement.
3447+ // If we had another statement we can stop now and use the
3448+ // indent of that other statement.
3449+ // Otherwise the indent of the current statement may be used,
3450+ // search backwards for the next "normal" statement.
3451+ else
3452+ {
3453+ // Skip single break line, if before a switch label. It
3454+ // may be lined up with the case label.
3455+ if (lookfor == LOOKFOR_NOBREAK
3456+ && cin_isbreak(skipwhite(ml_get_curline())))
3457+ {
3458+ lookfor = LOOKFOR_ANY;
3459+ continue;
3460+ }
3461+
3462+ // Handle "do {" line.
3463+ if (whilelevel > 0)
3464+ {
3465+ l = cin_skipcomment(ml_get_curline());
3466+ if (cin_isdo(l))
3467+ {
3468+ amount = get_indent(); // XXX
3469+ --whilelevel;
3470+ continue;
3471+ }
3472+ }
3473+
3474+ // Found a terminated line above an unterminated line. Add
3475+ // the amount for a continuation line.
3476+ // x = 1;
3477+ // y = foo +
3478+ // -> here;
3479+ // or
3480+ // int x = 1;
3481+ // int foo,
3482+ // -> here;
3483+ if (lookfor == LOOKFOR_UNTERM
3484+ || lookfor == LOOKFOR_ENUM_OR_INIT)
3485+ {
3486+ if (cont_amount > 0)
3487+ amount = cont_amount;
3488+ else
3489+ amount += ind_continuation;
3490+ break;
3491+ }
3492+
3493+ // Found a terminated line above a terminated line or "if"
3494+ // etc. line. Use the amount of the line below us.
3495+ // x = 1; x = 1;
3496+ // if (asdf) y = 2;
3497+ // while (asdf) ->here;
3498+ // here;
3499+ // ->foo;
3500+ if (lookfor == LOOKFOR_TERM)
3501+ {
3502+ if (!lookfor_break && whilelevel == 0)
3503+ break;
3504+ }
3505+
3506+ // First line above the one we're indenting is terminated.
3507+ // To know what needs to be done look further backward for
3508+ // a terminated line.
3509+ else
3510+ {
3511+ // position the cursor over the rightmost paren, so
3512+ // that matching it will take us back to the start of
3513+ // the line. Helps for:
3514+ // func(asdr,
3515+ // asdfasdf);
3516+ // here;
3517+term_again:
3518+ l = ml_get_curline();
3519+ if (find_last_paren(l, '(', ')')
3520+ && (trypos = find_match_paren(
3521+ curbuf->b_ind_maxparen)) != NULL)
3522+ {
3523+ // Check if we are on a case label now. This is
3524+ // handled above.
3525+ // case xx: if ( asdf &&
3526+ // asdf)
3527+ curwin->w_cursor = *trypos;
3528+ l = ml_get_curline();
3529+ if (cin_iscase(l, FALSE) || cin_isscopedecl(l))
3530+ {
3531+ ++curwin->w_cursor.lnum;
3532+ curwin->w_cursor.col = 0;
3533+ continue;
3534+ }
3535+ }
3536+
3537+ // When aligning with the case statement, don't align
3538+ // with a statement after it.
3539+ // case 1: { <-- don't use this { position
3540+ // stat;
3541+ // }
3542+ // case 2:
3543+ // stat;
3544+ // }
3545+ iscase = (curbuf->b_ind_keep_case_label
3546+ && cin_iscase(l, FALSE));
3547+
3548+ // Get indent and pointer to text for current line,
3549+ // ignoring any jump label.
3550+ amount = skip_label(curwin->w_cursor.lnum, &l);
3551+
3552+ if (theline[0] == '{')
3553+ amount += curbuf->b_ind_open_extra;
3554+ // See remark above: "Only add b_ind_open_extra.."
3555+ l = skipwhite(l);
3556+ if (*l == '{')
3557+ amount -= curbuf->b_ind_open_extra;
3558+ lookfor = iscase ? LOOKFOR_ANY : LOOKFOR_TERM;
3559+
3560+ // When a terminated line starts with "else" skip to
3561+ // the matching "if":
3562+ // else 3;
3563+ // indent this;
3564+ // Need to use the scope of this "else". XXX
3565+ // If whilelevel != 0 continue looking for a "do {".
3566+ if (lookfor == LOOKFOR_TERM
3567+ && *l != '}'
3568+ && cin_iselse(l)
3569+ && whilelevel == 0)
3570+ {
3571+ if ((trypos = find_start_brace()) == NULL
3572+ || find_match(LOOKFOR_IF, trypos->lnum)
3573+ == FAIL)
3574+ break;
3575+ continue;
3576+ }
3577+
3578+ // If we're at the end of a block, skip to the start of
3579+ // that block.
3580+ l = ml_get_curline();
3581+ if (find_last_paren(l, '{', '}') // XXX
3582+ && (trypos = find_start_brace()) != NULL)
3583+ {
3584+ curwin->w_cursor = *trypos;
3585+ // if not "else {" check for terminated again
3586+ // but skip block for "} else {"
3587+ l = cin_skipcomment(ml_get_curline());
3588+ if (*l == '}' || !cin_iselse(l))
3589+ goto term_again;
3590+ ++curwin->w_cursor.lnum;
3591+ curwin->w_cursor.col = 0;
3592+ }
3593+ }
3594+ }
3595+ }
3596+ }
3597+ }
3598+
3599+ // add extra indent for a comment
3600+ if (cin_iscomment(theline))
3601+ amount += curbuf->b_ind_comment;
3602+
3603+ // subtract extra left-shift for jump labels
3604+ if (curbuf->b_ind_jump_label > 0 && original_line_islabel)
3605+ amount -= curbuf->b_ind_jump_label;
3606+
3607+ goto theend;
3608+ }
3609+
3610+ // ok -- we're not inside any sort of structure at all!
3611+ //
3612+ // This means we're at the top level, and everything should
3613+ // basically just match where the previous line is, except
3614+ // for the lines immediately following a function declaration,
3615+ // which are K&R-style parameters and need to be indented.
3616+ //
3617+ // if our line starts with an open brace, forget about any
3618+ // prevailing indent and make sure it looks like the start
3619+ // of a function
3620+
3621+ if (theline[0] == '{')
3622+ {
3623+ amount = curbuf->b_ind_first_open;
3624+ goto theend;
3625+ }
3626+
3627+ // If the NEXT line is a function declaration, the current
3628+ // line needs to be indented as a function type spec.
3629+ // Don't do this if the current line looks like a comment or if the
3630+ // current line is terminated, ie. ends in ';', or if the current line
3631+ // contains { or }: "void f() {\n if (1)"
3632+ if (cur_curpos.lnum < curbuf->b_ml.ml_line_count
3633+ && !cin_nocode(theline)
3634+ && vim_strchr(theline, '{') == NULL
3635+ && vim_strchr(theline, '}') == NULL
3636+ && !cin_ends_in(theline, (char_u *)":", NULL)
3637+ && !cin_ends_in(theline, (char_u *)",", NULL)
3638+ && cin_isfuncdecl(NULL, cur_curpos.lnum + 1,
3639+ cur_curpos.lnum + 1)
3640+ && !cin_isterminated(theline, FALSE, TRUE))
3641+ {
3642+ amount = curbuf->b_ind_func_type;
3643+ goto theend;
3644+ }
3645+
3646+ // search backwards until we find something we recognize
3647+ amount = 0;
3648+ curwin->w_cursor = cur_curpos;
3649+ while (curwin->w_cursor.lnum > 1)
3650+ {
3651+ curwin->w_cursor.lnum--;
3652+ curwin->w_cursor.col = 0;
3653+
3654+ l = ml_get_curline();
3655+
3656+ // If we're in a comment or raw string now, skip to the start
3657+ // of it. XXX
3658+ if ((trypos = ind_find_start_CORS(NULL)) != NULL)
3659+ {
3660+ curwin->w_cursor.lnum = trypos->lnum + 1;
3661+ curwin->w_cursor.col = 0;
3662+ continue;
3663+ }
3664+
3665+ // Are we at the start of a cpp base class declaration or
3666+ // constructor initialization? XXX
3667+ n = FALSE;
3668+ if (curbuf->b_ind_cpp_baseclass != 0 && theline[0] != '{')
3669+ {
3670+ n = cin_is_cpp_baseclass(&cache_cpp_baseclass);
3671+ l = ml_get_curline();
3672+ }
3673+ if (n)
3674+ {
3675+ // XXX
3676+ amount = get_baseclass_amount(cache_cpp_baseclass.lpos.col);
3677+ break;
3678+ }
3679+
3680+ // Skip preprocessor directives and blank lines.
3681+ if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum, &amount))
3682+ continue;
3683+
3684+ if (cin_nocode(l))
3685+ continue;
3686+
3687+ // If the previous line ends in ',', use one level of
3688+ // indentation:
3689+ // int foo,
3690+ // bar;
3691+ // do this before checking for '}' in case of eg.
3692+ // enum foobar
3693+ // {
3694+ // ...
3695+ // } foo,
3696+ // bar;
3697+ n = 0;
3698+ if (cin_ends_in(l, (char_u *)",", NULL)
3699+ || (*l != NUL && (n = l[STRLEN(l) - 1]) == '\\'))
3700+ {
3701+ // take us back to opening paren
3702+ if (find_last_paren(l, '(', ')')
3703+ && (trypos = find_match_paren(
3704+ curbuf->b_ind_maxparen)) != NULL)
3705+ curwin->w_cursor = *trypos;
3706+
3707+ // For a line ending in ',' that is a continuation line go
3708+ // back to the first line with a backslash:
3709+ // char *foo = "bla{backslash}
3710+ // bla",
3711+ // here;
3712+ while (n == 0 && curwin->w_cursor.lnum > 1)
3713+ {
3714+ l = ml_get(curwin->w_cursor.lnum - 1);
3715+ if (*l == NUL || l[STRLEN(l) - 1] != '\\')
3716+ break;
3717+ --curwin->w_cursor.lnum;
3718+ curwin->w_cursor.col = 0;
3719+ }
3720+
3721+ amount = get_indent(); // XXX
3722+
3723+ if (amount == 0)
3724+ amount = cin_first_id_amount();
3725+ if (amount == 0)
3726+ amount = ind_continuation;
3727+ break;
3728+ }
3729+
3730+ // If the line looks like a function declaration, and we're
3731+ // not in a comment, put it the left margin.
3732+ if (cin_isfuncdecl(NULL, cur_curpos.lnum, 0)) // XXX
3733+ break;
3734+ l = ml_get_curline();
3735+
3736+ // Finding the closing '}' of a previous function. Put
3737+ // current line at the left margin. For when 'cino' has "fs".
3738+ if (*skipwhite(l) == '}')
3739+ break;
3740+
3741+ // (matching {)
3742+ // If the previous line ends on '};' (maybe followed by
3743+ // comments) align at column 0. For example:
3744+ // char *string_array[] = { "foo",
3745+ // / * x * / "b};ar" }; / * foobar * /
3746+ if (cin_ends_in(l, (char_u *)"};", NULL))
3747+ break;
3748+
3749+ // If the previous line ends on '[' we are probably in an
3750+ // array constant:
3751+ // something = [
3752+ // 234, <- extra indent
3753+ if (cin_ends_in(l, (char_u *)"[", NULL))
3754+ {
3755+ amount = get_indent() + ind_continuation;
3756+ break;
3757+ }
3758+
3759+ // Find a line only has a semicolon that belongs to a previous
3760+ // line ending in '}', e.g. before an #endif. Don't increase
3761+ // indent then.
3762+ if (*(look = skipwhite(l)) == ';' && cin_nocode(look + 1))
3763+ {
3764+ pos_T curpos_save = curwin->w_cursor;
3765+
3766+ while (curwin->w_cursor.lnum > 1)
3767+ {
3768+ look = ml_get(--curwin->w_cursor.lnum);
3769+ if (!(cin_nocode(look) || cin_ispreproc_cont(
3770+ &look, &curwin->w_cursor.lnum, &amount)))
3771+ break;
3772+ }
3773+ if (curwin->w_cursor.lnum > 0
3774+ && cin_ends_in(look, (char_u *)"}", NULL))
3775+ break;
3776+
3777+ curwin->w_cursor = curpos_save;
3778+ }
3779+
3780+ // If the PREVIOUS line is a function declaration, the current
3781+ // line (and the ones that follow) needs to be indented as
3782+ // parameters.
3783+ if (cin_isfuncdecl(&l, curwin->w_cursor.lnum, 0))
3784+ {
3785+ amount = curbuf->b_ind_param;
3786+ break;
3787+ }
3788+
3789+ // If the previous line ends in ';' and the line before the
3790+ // previous line ends in ',' or '\', ident to column zero:
3791+ // int foo,
3792+ // bar;
3793+ // indent_to_0 here;
3794+ if (cin_ends_in(l, (char_u *)";", NULL))
3795+ {
3796+ l = ml_get(curwin->w_cursor.lnum - 1);
3797+ if (cin_ends_in(l, (char_u *)",", NULL)
3798+ || (*l != NUL && l[STRLEN(l) - 1] == '\\'))
3799+ break;
3800+ l = ml_get_curline();
3801+ }
3802+
3803+ // Doesn't look like anything interesting -- so just
3804+ // use the indent of this line.
3805+ //
3806+ // Position the cursor over the rightmost paren, so that
3807+ // matching it will take us back to the start of the line.
3808+ find_last_paren(l, '(', ')');
3809+
3810+ if ((trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL)
3811+ curwin->w_cursor = *trypos;
3812+ amount = get_indent(); // XXX
3813+ break;
3814+ }
3815+
3816+ // add extra indent for a comment
3817+ if (cin_iscomment(theline))
3818+ amount += curbuf->b_ind_comment;
3819+
3820+ // add extra indent if the previous line ended in a backslash:
3821+ // "asdfasdf{backslash}
3822+ // here";
3823+ // char *foo = "asdf{backslash}
3824+ // here";
3825+ if (cur_curpos.lnum > 1)
3826+ {
3827+ l = ml_get(cur_curpos.lnum - 1);
3828+ if (*l != NUL && l[STRLEN(l) - 1] == '\\')
3829+ {
3830+ cur_amount = cin_get_equal_amount(cur_curpos.lnum - 1);
3831+ if (cur_amount > 0)
3832+ amount = cur_amount;
3833+ else if (cur_amount == 0)
3834+ amount += ind_continuation;
3835+ }
3836+ }
3837+
3838+theend:
3839+ if (amount < 0)
3840+ amount = 0;
3841+
3842+laterend:
3843+ // put the cursor back where it belongs
3844+ curwin->w_cursor = cur_curpos;
3845+
3846+ vim_free(linecopy);
3847+
3848+ return amount;
3849+}
3850+
3851+/*
3852+ * return TRUE if 'cinkeys' contains the key "keytyped",
3853+ * when == '*': Only if key is preceded with '*' (indent before insert)
3854+ * when == '!': Only if key is preceded with '!' (don't insert)
3855+ * when == ' ': Only if key is not preceded with '*'(indent afterwards)
3856+ *
3857+ * "keytyped" can have a few special values:
3858+ * KEY_OPEN_FORW
3859+ * KEY_OPEN_BACK
3860+ * KEY_COMPLETE just finished completion.
3861+ *
3862+ * If line_is_empty is TRUE accept keys with '0' before them.
3863+ */
3864+ int
3865+in_cinkeys(
3866+ int keytyped,
3867+ int when,
3868+ int line_is_empty)
3869+{
3870+ char_u *look;
3871+ int try_match;
3872+ int try_match_word;
3873+ char_u *p;
3874+ char_u *line;
3875+ int icase;
3876+ int i;
3877+
3878+ if (keytyped == NUL)
3879+ // Can happen with CTRL-Y and CTRL-E on a short line.
3880+ return FALSE;
3881+
3882+#ifdef FEAT_EVAL
3883+ if (*curbuf->b_p_inde != NUL)
3884+ look = curbuf->b_p_indk; // 'indentexpr' set: use 'indentkeys'
3885+ else
3886+#endif
3887+ look = curbuf->b_p_cink; // 'indentexpr' empty: use 'cinkeys'
3888+ while (*look)
3889+ {
3890+ // Find out if we want to try a match with this key, depending on
3891+ // 'when' and a '*' or '!' before the key.
3892+ switch (when)
3893+ {
3894+ case '*': try_match = (*look == '*'); break;
3895+ case '!': try_match = (*look == '!'); break;
3896+ default: try_match = (*look != '*'); break;
3897+ }
3898+ if (*look == '*' || *look == '!')
3899+ ++look;
3900+
3901+ // If there is a '0', only accept a match if the line is empty.
3902+ // But may still match when typing last char of a word.
3903+ if (*look == '0')
3904+ {
3905+ try_match_word = try_match;
3906+ if (!line_is_empty)
3907+ try_match = FALSE;
3908+ ++look;
3909+ }
3910+ else
3911+ try_match_word = FALSE;
3912+
3913+ // does it look like a control character?
3914+ if (*look == '^'
3915+#ifdef EBCDIC
3916+ && (Ctrl_chr(look[1]) != 0)
3917+#else
3918+ && look[1] >= '?' && look[1] <= '_'
3919+#endif
3920+ )
3921+ {
3922+ if (try_match && keytyped == Ctrl_chr(look[1]))
3923+ return TRUE;
3924+ look += 2;
3925+ }
3926+ // 'o' means "o" command, open forward.
3927+ // 'O' means "O" command, open backward.
3928+ else if (*look == 'o')
3929+ {
3930+ if (try_match && keytyped == KEY_OPEN_FORW)
3931+ return TRUE;
3932+ ++look;
3933+ }
3934+ else if (*look == 'O')
3935+ {
3936+ if (try_match && keytyped == KEY_OPEN_BACK)
3937+ return TRUE;
3938+ ++look;
3939+ }
3940+
3941+ // 'e' means to check for "else" at start of line and just before the
3942+ // cursor.
3943+ else if (*look == 'e')
3944+ {
3945+ if (try_match && keytyped == 'e' && curwin->w_cursor.col >= 4)
3946+ {
3947+ p = ml_get_curline();
3948+ if (skipwhite(p) == p + curwin->w_cursor.col - 4 &&
3949+ STRNCMP(p + curwin->w_cursor.col - 4, "else", 4) == 0)
3950+ return TRUE;
3951+ }
3952+ ++look;
3953+ }
3954+
3955+ // ':' only causes an indent if it is at the end of a label or case
3956+ // statement, or when it was before typing the ':' (to fix
3957+ // class::method for C++).
3958+ else if (*look == ':')
3959+ {
3960+ if (try_match && keytyped == ':')
3961+ {
3962+ p = ml_get_curline();
3963+ if (cin_iscase(p, FALSE) || cin_isscopedecl(p) || cin_islabel())
3964+ return TRUE;
3965+ // Need to get the line again after cin_islabel().
3966+ p = ml_get_curline();
3967+ if (curwin->w_cursor.col > 2
3968+ && p[curwin->w_cursor.col - 1] == ':'
3969+ && p[curwin->w_cursor.col - 2] == ':')
3970+ {
3971+ p[curwin->w_cursor.col - 1] = ' ';
3972+ i = (cin_iscase(p, FALSE) || cin_isscopedecl(p)
3973+ || cin_islabel());
3974+ p = ml_get_curline();
3975+ p[curwin->w_cursor.col - 1] = ':';
3976+ if (i)
3977+ return TRUE;
3978+ }
3979+ }
3980+ ++look;
3981+ }
3982+
3983+
3984+ // Is it a key in <>, maybe?
3985+ else if (*look == '<')
3986+ {
3987+ if (try_match)
3988+ {
3989+ // make up some named keys <o>, <O>, <e>, <0>, <>>, <<>, <*>,
3990+ // <:> and <!> so that people can re-indent on o, O, e, 0, <,
3991+ // >, *, : and ! keys if they really really want to.
3992+ if (vim_strchr((char_u *)"<>!*oOe0:", look[1]) != NULL
3993+ && keytyped == look[1])
3994+ return TRUE;
3995+
3996+ if (keytyped == get_special_key_code(look + 1))
3997+ return TRUE;
3998+ }
3999+ while (*look && *look != '>')
4000+ look++;
4001+ while (*look == '>')
4002+ look++;
4003+ }
4004+
4005+ // Is it a word: "=word"?
4006+ else if (*look == '=' && look[1] != ',' && look[1] != NUL)
4007+ {
4008+ ++look;
4009+ if (*look == '~')
4010+ {
4011+ icase = TRUE;
4012+ ++look;
4013+ }
4014+ else
4015+ icase = FALSE;
4016+ p = vim_strchr(look, ',');
4017+ if (p == NULL)
4018+ p = look + STRLEN(look);
4019+ if ((try_match || try_match_word)
4020+ && curwin->w_cursor.col >= (colnr_T)(p - look))
4021+ {
4022+ int match = FALSE;
4023+
4024+ if (keytyped == KEY_COMPLETE)
4025+ {
4026+ char_u *s;
4027+
4028+ // Just completed a word, check if it starts with "look".
4029+ // search back for the start of a word.
4030+ line = ml_get_curline();
4031+ if (has_mbyte)
4032+ {
4033+ char_u *n;
4034+
4035+ for (s = line + curwin->w_cursor.col; s > line; s = n)
4036+ {
4037+ n = mb_prevptr(line, s);
4038+ if (!vim_iswordp(n))
4039+ break;
4040+ }
4041+ }
4042+ else
4043+ for (s = line + curwin->w_cursor.col; s > line; --s)
4044+ if (!vim_iswordc(s[-1]))
4045+ break;
4046+ if (s + (p - look) <= line + curwin->w_cursor.col
4047+ && (icase
4048+ ? MB_STRNICMP(s, look, p - look)
4049+ : STRNCMP(s, look, p - look)) == 0)
4050+ match = TRUE;
4051+ }
4052+ else
4053+ // TODO: multi-byte
4054+ if (keytyped == (int)p[-1] || (icase && keytyped < 256
4055+ && TOLOWER_LOC(keytyped) == TOLOWER_LOC((int)p[-1])))
4056+ {
4057+ line = ml_get_cursor();
4058+ if ((curwin->w_cursor.col == (colnr_T)(p - look)
4059+ || !vim_iswordc(line[-(p - look) - 1]))
4060+ && (icase
4061+ ? MB_STRNICMP(line - (p - look), look, p - look)
4062+ : STRNCMP(line - (p - look), look, p - look))
4063+ == 0)
4064+ match = TRUE;
4065+ }
4066+ if (match && try_match_word && !try_match)
4067+ {
4068+ // "0=word": Check if there are only blanks before the
4069+ // word.
4070+ if (getwhitecols_curline() !=
4071+ (int)(curwin->w_cursor.col - (p - look)))
4072+ match = FALSE;
4073+ }
4074+ if (match)
4075+ return TRUE;
4076+ }
4077+ look = p;
4078+ }
4079+
4080+ // ok, it's a boring generic character.
4081+ else
4082+ {
4083+ if (try_match && *look == keytyped)
4084+ return TRUE;
4085+ if (*look != NUL)
4086+ ++look;
4087+ }
4088+
4089+ // Skip over ", ".
4090+ look = skip_to_option_part(look);
4091+ }
4092+ return FALSE;
4093+}
4094+
4095+/*
4096+ * Do C or expression indenting on the current line.
4097+ */
4098+ void
4099+do_c_expr_indent(void)
4100+{
4101+# ifdef FEAT_EVAL
4102+ if (*curbuf->b_p_inde != NUL)
4103+ fixthisline(get_expr_indent);
4104+ else
4105+# endif
4106+ fixthisline(get_c_indent);
4107+}
4108+#endif
4109+
4110+#if defined(FEAT_EVAL) || defined(PROTO)
4111+/*
4112+ * "cindent(lnum)" function
4113+ */
4114+ void
4115+f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
4116+{
4117+# ifdef FEAT_CINDENT
4118+ pos_T pos;
4119+ linenr_T lnum;
4120+
4121+ pos = curwin->w_cursor;
4122+ lnum = tv_get_lnum(argvars);
4123+ if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
4124+ {
4125+ curwin->w_cursor.lnum = lnum;
4126+ rettv->vval.v_number = get_c_indent();
4127+ curwin->w_cursor = pos;
4128+ }
4129+ else
4130+# endif
4131+ rettv->vval.v_number = -1;
4132+}
4133+#endif
diff -r 5202d9b99bee -r fe5afdc03bd2 src/edit.c
--- a/src/edit.c Wed Oct 09 22:15:04 2019 +0200
+++ b/src/edit.c Wed Oct 09 23:00:04 2019 +0200
@@ -37,7 +37,6 @@
3737 #endif
3838 static void stop_insert(pos_T *end_insert_pos, int esc, int nomove);
3939 static int echeck_abbr(int);
40-static void replace_join(int off);
4140 static void mb_replace_pop_ins(int cc);
4241 static void replace_flush(void);
4342 static void replace_do_bs(int limit_col);
@@ -76,9 +75,6 @@
7675 static int ins_digraph(void);
7776 #endif
7877 static int ins_ctrl_ey(int tc);
79-#ifdef FEAT_SMARTINDENT
80-static void ins_try_si(int c);
81-#endif
8278 #if defined(FEAT_EVAL)
8379 static char_u *do_insert_char_pre(int c);
8480 #endif
@@ -97,8 +93,6 @@
9793 static int can_cindent; /* may do cindenting on this line */
9894 #endif
9995
100-static int old_indent = 0; /* for ^^D command in insert mode */
101-
10296 #ifdef FEAT_RIGHTLEFT
10397 static int revins_on; /* reverse insert mode on */
10498 static int revins_chars; /* how much to skip after edit */
@@ -1763,248 +1757,6 @@
17631757 }
17641758
17651759 /*
1766- * Insert an indent (for <Tab> or CTRL-T) or delete an indent (for CTRL-D).
1767- * Keep the cursor on the same character.
1768- * type == INDENT_INC increase indent (for CTRL-T or <Tab>)
1769- * type == INDENT_DEC decrease indent (for CTRL-D)
1770- * type == INDENT_SET set indent to "amount"
1771- * if round is TRUE, round the indent to 'shiftwidth' (only with _INC and _Dec).
1772- */
1773- void
1774-change_indent(
1775- int type,
1776- int amount,
1777- int round,
1778- int replaced, /* replaced character, put on replace stack */
1779- int call_changed_bytes) /* call changed_bytes() */
1780-{
1781- int vcol;
1782- int last_vcol;
1783- int insstart_less; /* reduction for Insstart.col */
1784- int new_cursor_col;
1785- int i;
1786- char_u *ptr;
1787- int save_p_list;
1788- int start_col;
1789- colnr_T vc;
1790- colnr_T orig_col = 0; /* init for GCC */
1791- char_u *new_line, *orig_line = NULL; /* init for GCC */
1792-
1793- /* VREPLACE mode needs to know what the line was like before changing */
1794- if (State & VREPLACE_FLAG)
1795- {
1796- orig_line = vim_strsave(ml_get_curline()); /* Deal with NULL below */
1797- orig_col = curwin->w_cursor.col;
1798- }
1799-
1800- /* for the following tricks we don't want list mode */
1801- save_p_list = curwin->w_p_list;
1802- curwin->w_p_list = FALSE;
1803- vc = getvcol_nolist(&curwin->w_cursor);
1804- vcol = vc;
1805-
1806- /*
1807- * For Replace mode we need to fix the replace stack later, which is only
1808- * possible when the cursor is in the indent. Remember the number of
1809- * characters before the cursor if it's possible.
1810- */
1811- start_col = curwin->w_cursor.col;
1812-
1813- /* determine offset from first non-blank */
1814- new_cursor_col = curwin->w_cursor.col;
1815- beginline(BL_WHITE);
1816- new_cursor_col -= curwin->w_cursor.col;
1817-
1818- insstart_less = curwin->w_cursor.col;
1819-
1820- /*
1821- * If the cursor is in the indent, compute how many screen columns the
1822- * cursor is to the left of the first non-blank.
1823- */
1824- if (new_cursor_col < 0)
1825- vcol = get_indent() - vcol;
1826-
1827- if (new_cursor_col > 0) /* can't fix replace stack */
1828- start_col = -1;
1829-
1830- /*
1831- * Set the new indent. The cursor will be put on the first non-blank.
1832- */
1833- if (type == INDENT_SET)
1834- (void)set_indent(amount, call_changed_bytes ? SIN_CHANGED : 0);
1835- else
1836- {
1837- int save_State = State;
1838-
1839- /* Avoid being called recursively. */
1840- if (State & VREPLACE_FLAG)
1841- State = INSERT;
1842- shift_line(type == INDENT_DEC, round, 1, call_changed_bytes);
1843- State = save_State;
1844- }
1845- insstart_less -= curwin->w_cursor.col;
1846-
1847- /*
1848- * Try to put cursor on same character.
1849- * If the cursor is at or after the first non-blank in the line,
1850- * compute the cursor column relative to the column of the first
1851- * non-blank character.
1852- * If we are not in insert mode, leave the cursor on the first non-blank.
1853- * If the cursor is before the first non-blank, position it relative
1854- * to the first non-blank, counted in screen columns.
1855- */
1856- if (new_cursor_col >= 0)
1857- {
1858- /*
1859- * When changing the indent while the cursor is touching it, reset
1860- * Insstart_col to 0.
1861- */
1862- if (new_cursor_col == 0)
1863- insstart_less = MAXCOL;
1864- new_cursor_col += curwin->w_cursor.col;
1865- }
1866- else if (!(State & INSERT))
1867- new_cursor_col = curwin->w_cursor.col;
1868- else
1869- {
1870- /*
1871- * Compute the screen column where the cursor should be.
1872- */
1873- vcol = get_indent() - vcol;
1874- curwin->w_virtcol = (colnr_T)((vcol < 0) ? 0 : vcol);
1875-
1876- /*
1877- * Advance the cursor until we reach the right screen column.
1878- */
1879- vcol = last_vcol = 0;
1880- new_cursor_col = -1;
1881- ptr = ml_get_curline();
1882- while (vcol <= (int)curwin->w_virtcol)
1883- {
1884- last_vcol = vcol;
1885- if (has_mbyte && new_cursor_col >= 0)
1886- new_cursor_col += (*mb_ptr2len)(ptr + new_cursor_col);
1887- else
1888- ++new_cursor_col;
1889- vcol += lbr_chartabsize(ptr, ptr + new_cursor_col, (colnr_T)vcol);
1890- }
1891- vcol = last_vcol;
1892-
1893- /*
1894- * May need to insert spaces to be able to position the cursor on
1895- * the right screen column.
1896- */
1897- if (vcol != (int)curwin->w_virtcol)
1898- {
1899- curwin->w_cursor.col = (colnr_T)new_cursor_col;
1900- i = (int)curwin->w_virtcol - vcol;
1901- ptr = alloc(i + 1);
1902- if (ptr != NULL)
1903- {
1904- new_cursor_col += i;
1905- ptr[i] = NUL;
1906- while (--i >= 0)
1907- ptr[i] = ' ';
1908- ins_str(ptr);
1909- vim_free(ptr);
1910- }
1911- }
1912-
1913- /*
1914- * When changing the indent while the cursor is in it, reset
1915- * Insstart_col to 0.
1916- */
1917- insstart_less = MAXCOL;
1918- }
1919-
1920- curwin->w_p_list = save_p_list;
1921-
1922- if (new_cursor_col <= 0)
1923- curwin->w_cursor.col = 0;
1924- else
1925- curwin->w_cursor.col = (colnr_T)new_cursor_col;
1926- curwin->w_set_curswant = TRUE;
1927- changed_cline_bef_curs();
1928-
1929- /*
1930- * May have to adjust the start of the insert.
1931- */
1932- if (State & INSERT)
1933- {
1934- if (curwin->w_cursor.lnum == Insstart.lnum && Insstart.col != 0)
1935- {
1936- if ((int)Insstart.col <= insstart_less)
1937- Insstart.col = 0;
1938- else
1939- Insstart.col -= insstart_less;
1940- }
1941- if ((int)ai_col <= insstart_less)
1942- ai_col = 0;
1943- else
1944- ai_col -= insstart_less;
1945- }
1946-
1947- /*
1948- * For REPLACE mode, may have to fix the replace stack, if it's possible.
1949- * If the number of characters before the cursor decreased, need to pop a
1950- * few characters from the replace stack.
1951- * If the number of characters before the cursor increased, need to push a
1952- * few NULs onto the replace stack.
1953- */
1954- if (REPLACE_NORMAL(State) && start_col >= 0)
1955- {
1956- while (start_col > (int)curwin->w_cursor.col)
1957- {
1958- replace_join(0); /* remove a NUL from the replace stack */
1959- --start_col;
1960- }
1961- while (start_col < (int)curwin->w_cursor.col || replaced)
1962- {
1963- replace_push(NUL);
1964- if (replaced)
1965- {
1966- replace_push(replaced);
1967- replaced = NUL;
1968- }
1969- ++start_col;
1970- }
1971- }
1972-
1973- /*
1974- * For VREPLACE mode, we also have to fix the replace stack. In this case
1975- * it is always possible because we backspace over the whole line and then
1976- * put it back again the way we wanted it.
1977- */
1978- if (State & VREPLACE_FLAG)
1979- {
1980- /* If orig_line didn't allocate, just return. At least we did the job,
1981- * even if you can't backspace. */
1982- if (orig_line == NULL)
1983- return;
1984-
1985- /* Save new line */
1986- new_line = vim_strsave(ml_get_curline());
1987- if (new_line == NULL)
1988- return;
1989-
1990- /* We only put back the new line up to the cursor */
1991- new_line[curwin->w_cursor.col] = NUL;
1992-
1993- /* Put back original line */
1994- ml_replace(curwin->w_cursor.lnum, orig_line, FALSE);
1995- curwin->w_cursor.col = orig_col;
1996-
1997- /* Backspace from cursor to start of line */
1998- backspace_until_column(0);
1999-
2000- /* Insert new stuff into line again */
2001- ins_bytes(new_line);
2002-
2003- vim_free(new_line);
2004- }
2005-}
2006-
2007-/*
20081760 * Truncate the space at the end of a line. This is to be used only in an
20091761 * insert mode. It handles fixing the replace stack for REPLACE and VREPLACE
20101762 * modes.
@@ -3840,7 +3592,7 @@
38403592 * Join the top two items on the replace stack. This removes to "off"'th NUL
38413593 * encountered.
38423594 */
3843- static void
3595+ void
38443596 replace_join(
38453597 int off) /* offset for which NUL to remove */
38463598 {
@@ -6070,97 +5822,6 @@
60705822 return c;
60715823 }
60725824
6073-#ifdef FEAT_SMARTINDENT
6074-/*
6075- * Try to do some very smart auto-indenting.
6076- * Used when inserting a "normal" character.
6077- */
6078- static void
6079-ins_try_si(int c)
6080-{
6081- pos_T *pos, old_pos;
6082- char_u *ptr;
6083- int i;
6084- int temp;
6085-
6086- /*
6087- * do some very smart indenting when entering '{' or '}'
6088- */
6089- if (((did_si || can_si_back) && c == '{') || (can_si && c == '}'))
6090- {
6091- /*
6092- * for '}' set indent equal to indent of line containing matching '{'
6093- */
6094- if (c == '}' && (pos = findmatch(NULL, '{')) != NULL)
6095- {
6096- old_pos = curwin->w_cursor;
6097- /*
6098- * If the matching '{' has a ')' immediately before it (ignoring
6099- * white-space), then line up with the start of the line
6100- * containing the matching '(' if there is one. This handles the
6101- * case where an "if (..\n..) {" statement continues over multiple
6102- * lines -- webb
6103- */
6104- ptr = ml_get(pos->lnum);
6105- i = pos->col;
6106- if (i > 0) /* skip blanks before '{' */
6107- while (--i > 0 && VIM_ISWHITE(ptr[i]))
6108- ;
6109- curwin->w_cursor.lnum = pos->lnum;
6110- curwin->w_cursor.col = i;
6111- if (ptr[i] == ')' && (pos = findmatch(NULL, '(')) != NULL)
6112- curwin->w_cursor = *pos;
6113- i = get_indent();
6114- curwin->w_cursor = old_pos;
6115- if (State & VREPLACE_FLAG)
6116- change_indent(INDENT_SET, i, FALSE, NUL, TRUE);
6117- else
6118- (void)set_indent(i, SIN_CHANGED);
6119- }
6120- else if (curwin->w_cursor.col > 0)
6121- {
6122- /*
6123- * when inserting '{' after "O" reduce indent, but not
6124- * more than indent of previous line
6125- */
6126- temp = TRUE;
6127- if (c == '{' && can_si_back && curwin->w_cursor.lnum > 1)
6128- {
6129- old_pos = curwin->w_cursor;
6130- i = get_indent();
6131- while (curwin->w_cursor.lnum > 1)
6132- {
6133- ptr = skipwhite(ml_get(--(curwin->w_cursor.lnum)));
6134-
6135- /* ignore empty lines and lines starting with '#'. */
6136- if (*ptr != '#' && *ptr != NUL)
6137- break;
6138- }
6139- if (get_indent() >= i)
6140- temp = FALSE;
6141- curwin->w_cursor = old_pos;
6142- }
6143- if (temp)
6144- shift_line(TRUE, FALSE, 1, TRUE);
6145- }
6146- }
6147-
6148- /*
6149- * set indent of '#' always to 0
6150- */
6151- if (curwin->w_cursor.col > 0 && can_si && c == '#')
6152- {
6153- /* remember current indent for next line */
6154- old_indent = get_indent();
6155- (void)set_indent(0, SIN_CHANGED);
6156- }
6157-
6158- /* Adjust ai_col, the char at this position can be deleted. */
6159- if (ai_col > curwin->w_cursor.col)
6160- ai_col = curwin->w_cursor.col;
6161-}
6162-#endif
6163-
61645825 /*
61655826 * Get the value that w_virtcol would have when 'list' is off.
61665827 * Unless 'cpo' contains the 'L' flag.
diff -r 5202d9b99bee -r fe5afdc03bd2 src/evalfunc.c
--- a/src/evalfunc.c Wed Oct 09 22:15:04 2019 +0200
+++ b/src/evalfunc.c Wed Oct 09 23:00:04 2019 +0200
@@ -51,7 +51,6 @@
5151 #endif
5252 static void f_changenr(typval_T *argvars, typval_T *rettv);
5353 static void f_char2nr(typval_T *argvars, typval_T *rettv);
54-static void f_cindent(typval_T *argvars, typval_T *rettv);
5554 static void f_col(typval_T *argvars, typval_T *rettv);
5655 static void f_confirm(typval_T *argvars, typval_T *rettv);
5756 static void f_copy(typval_T *argvars, typval_T *rettv);
@@ -108,7 +107,6 @@
108107 static void f_hlexists(typval_T *argvars, typval_T *rettv);
109108 static void f_hostname(typval_T *argvars, typval_T *rettv);
110109 static void f_iconv(typval_T *argvars, typval_T *rettv);
111-static void f_indent(typval_T *argvars, typval_T *rettv);
112110 static void f_index(typval_T *argvars, typval_T *rettv);
113111 static void f_input(typval_T *argvars, typval_T *rettv);
114112 static void f_inputdialog(typval_T *argvars, typval_T *rettv);
@@ -128,7 +126,6 @@
128126 static void f_libcallnr(typval_T *argvars, typval_T *rettv);
129127 static void f_line(typval_T *argvars, typval_T *rettv);
130128 static void f_line2byte(typval_T *argvars, typval_T *rettv);
131-static void f_lispindent(typval_T *argvars, typval_T *rettv);
132129 static void f_localtime(typval_T *argvars, typval_T *rettv);
133130 #ifdef FEAT_FLOAT
134131 static void f_log(typval_T *argvars, typval_T *rettv);
@@ -1491,29 +1488,6 @@
14911488 rettv->vval.v_number = tv_get_string(&argvars[0])[0];
14921489 }
14931490
1494-/*
1495- * "cindent(lnum)" function
1496- */
1497- static void
1498-f_cindent(typval_T *argvars UNUSED, typval_T *rettv)
1499-{
1500-#ifdef FEAT_CINDENT
1501- pos_T pos;
1502- linenr_T lnum;
1503-
1504- pos = curwin->w_cursor;
1505- lnum = tv_get_lnum(argvars);
1506- if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
1507- {
1508- curwin->w_cursor.lnum = lnum;
1509- rettv->vval.v_number = get_c_indent();
1510- curwin->w_cursor = pos;
1511- }
1512- else
1513-#endif
1514- rettv->vval.v_number = -1;
1515-}
1516-
15171491 win_T *
15181492 get_optional_window(typval_T *argvars, int idx)
15191493 {
@@ -3946,21 +3920,6 @@
39463920 }
39473921
39483922 /*
3949- * "indent()" function
3950- */
3951- static void
3952-f_indent(typval_T *argvars, typval_T *rettv)
3953-{
3954- linenr_T lnum;
3955-
3956- lnum = tv_get_lnum(argvars);
3957- if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
3958- rettv->vval.v_number = get_indent_lnum(lnum);
3959- else
3960- rettv->vval.v_number = -1;
3961-}
3962-
3963-/*
39643923 * "index()" function
39653924 */
39663925 static void
@@ -4451,29 +4410,6 @@
44514410 }
44524411
44534412 /*
4454- * "lispindent(lnum)" function
4455- */
4456- static void
4457-f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
4458-{
4459-#ifdef FEAT_LISP
4460- pos_T pos;
4461- linenr_T lnum;
4462-
4463- pos = curwin->w_cursor;
4464- lnum = tv_get_lnum(argvars);
4465- if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
4466- {
4467- curwin->w_cursor.lnum = lnum;
4468- rettv->vval.v_number = get_lisp_indent();
4469- curwin->w_cursor = pos;
4470- }
4471- else
4472-#endif
4473- rettv->vval.v_number = -1;
4474-}
4475-
4476-/*
44774413 * "localtime()" function
44784414 */
44794415 static void
diff -r 5202d9b99bee -r fe5afdc03bd2 src/ex_cmds.c
--- a/src/ex_cmds.c Wed Oct 09 22:15:04 2019 +0200
+++ b/src/ex_cmds.c Wed Oct 09 23:00:04 2019 +0200
@@ -661,221 +661,6 @@
661661 }
662662
663663 /*
664- * ":retab".
665- */
666- void
667-ex_retab(exarg_T *eap)
668-{
669- linenr_T lnum;
670- int got_tab = FALSE;
671- long num_spaces = 0;
672- long num_tabs;
673- long len;
674- long col;
675- long vcol;
676- long start_col = 0; /* For start of white-space string */
677- long start_vcol = 0; /* For start of white-space string */
678- long old_len;
679- char_u *ptr;
680- char_u *new_line = (char_u *)1; /* init to non-NULL */
681- int did_undo; /* called u_save for current line */
682-#ifdef FEAT_VARTABS
683- int *new_vts_array = NULL;
684- char_u *new_ts_str; /* string value of tab argument */
685-#else
686- int temp;
687- int new_ts;
688-#endif
689- int save_list;
690- linenr_T first_line = 0; /* first changed line */
691- linenr_T last_line = 0; /* last changed line */
692-
693- save_list = curwin->w_p_list;
694- curwin->w_p_list = 0; /* don't want list mode here */
695-
696-#ifdef FEAT_VARTABS
697- new_ts_str = eap->arg;
698- if (!tabstop_set(eap->arg, &new_vts_array))
699- return;
700- while (vim_isdigit(*(eap->arg)) || *(eap->arg) == ',')
701- ++(eap->arg);
702-
703- // This ensures that either new_vts_array and new_ts_str are freshly
704- // allocated, or new_vts_array points to an existing array and new_ts_str
705- // is null.
706- if (new_vts_array == NULL)
707- {
708- new_vts_array = curbuf->b_p_vts_array;
709- new_ts_str = NULL;
710- }
711- else
712- new_ts_str = vim_strnsave(new_ts_str, eap->arg - new_ts_str);
713-#else
714- new_ts = getdigits(&(eap->arg));
715- if (new_ts < 0)
716- {
717- emsg(_(e_positive));
718- return;
719- }
720- if (new_ts == 0)
721- new_ts = curbuf->b_p_ts;
722-#endif
723- for (lnum = eap->line1; !got_int && lnum <= eap->line2; ++lnum)
724- {
725- ptr = ml_get(lnum);
726- col = 0;
727- vcol = 0;
728- did_undo = FALSE;
729- for (;;)
730- {
731- if (VIM_ISWHITE(ptr[col]))
732- {
733- if (!got_tab && num_spaces == 0)
734- {
735- /* First consecutive white-space */
736- start_vcol = vcol;
737- start_col = col;
738- }
739- if (ptr[col] == ' ')
740- num_spaces++;
741- else
742- got_tab = TRUE;
743- }
744- else
745- {
746- if (got_tab || (eap->forceit && num_spaces > 1))
747- {
748- /* Retabulate this string of white-space */
749-
750- /* len is virtual length of white string */
751- len = num_spaces = vcol - start_vcol;
752- num_tabs = 0;
753- if (!curbuf->b_p_et)
754- {
755-#ifdef FEAT_VARTABS
756- int t, s;
757-
758- tabstop_fromto(start_vcol, vcol,
759- curbuf->b_p_ts, new_vts_array, &t, &s);
760- num_tabs = t;
761- num_spaces = s;
762-#else
763- temp = new_ts - (start_vcol % new_ts);
764- if (num_spaces >= temp)
765- {
766- num_spaces -= temp;
767- num_tabs++;
768- }
769- num_tabs += num_spaces / new_ts;
770- num_spaces -= (num_spaces / new_ts) * new_ts;
771-#endif
772- }
773- if (curbuf->b_p_et || got_tab ||
774- (num_spaces + num_tabs < len))
775- {
776- if (did_undo == FALSE)
777- {
778- did_undo = TRUE;
779- if (u_save((linenr_T)(lnum - 1),
780- (linenr_T)(lnum + 1)) == FAIL)
781- {
782- new_line = NULL; /* flag out-of-memory */
783- break;
784- }
785- }
786-
787- /* len is actual number of white characters used */
788- len = num_spaces + num_tabs;
789- old_len = (long)STRLEN(ptr);
790- new_line = alloc(old_len - col + start_col + len + 1);
791- if (new_line == NULL)
792- break;
793- if (start_col > 0)
794- mch_memmove(new_line, ptr, (size_t)start_col);
795- mch_memmove(new_line + start_col + len,
796- ptr + col, (size_t)(old_len - col + 1));
797- ptr = new_line + start_col;
798- for (col = 0; col < len; col++)
799- ptr[col] = (col < num_tabs) ? '\t' : ' ';
800- ml_replace(lnum, new_line, FALSE);
801- if (first_line == 0)
802- first_line = lnum;
803- last_line = lnum;
804- ptr = new_line;
805- col = start_col + len;
806- }
807- }
808- got_tab = FALSE;
809- num_spaces = 0;
810- }
811- if (ptr[col] == NUL)
812- break;
813- vcol += chartabsize(ptr + col, (colnr_T)vcol);
814- if (has_mbyte)
815- col += (*mb_ptr2len)(ptr + col);
816- else
817- ++col;
818- }
819- if (new_line == NULL) /* out of memory */
820- break;
821- line_breakcheck();
822- }
823- if (got_int)
824- emsg(_(e_interr));
825-
826-#ifdef FEAT_VARTABS
827- // If a single value was given then it can be considered equal to
828- // either the value of 'tabstop' or the value of 'vartabstop'.
829- if (tabstop_count(curbuf->b_p_vts_array) == 0
830- && tabstop_count(new_vts_array) == 1
831- && curbuf->b_p_ts == tabstop_first(new_vts_array))
832- ; /* not changed */
833- else if (tabstop_count(curbuf->b_p_vts_array) > 0
834- && tabstop_eq(curbuf->b_p_vts_array, new_vts_array))
835- ; /* not changed */
836- else
837- redraw_curbuf_later(NOT_VALID);
838-#else
839- if (curbuf->b_p_ts != new_ts)
840- redraw_curbuf_later(NOT_VALID);
841-#endif
842- if (first_line != 0)
843- changed_lines(first_line, 0, last_line + 1, 0L);
844-
845- curwin->w_p_list = save_list; /* restore 'list' */
846-
847-#ifdef FEAT_VARTABS
848- if (new_ts_str != NULL) /* set the new tabstop */
849- {
850- // If 'vartabstop' is in use or if the value given to retab has more
851- // than one tabstop then update 'vartabstop'.
852- int *old_vts_ary = curbuf->b_p_vts_array;
853-
854- if (tabstop_count(old_vts_ary) > 0 || tabstop_count(new_vts_array) > 1)
855- {
856- set_string_option_direct((char_u *)"vts", -1, new_ts_str,
857- OPT_FREE|OPT_LOCAL, 0);
858- curbuf->b_p_vts_array = new_vts_array;
859- vim_free(old_vts_ary);
860- }
861- else
862- {
863- // 'vartabstop' wasn't in use and a single value was given to
864- // retab then update 'tabstop'.
865- curbuf->b_p_ts = tabstop_first(new_vts_array);
866- vim_free(new_vts_array);
867- }
868- vim_free(new_ts_str);
869- }
870-#else
871- curbuf->b_p_ts = new_ts;
872-#endif
873- coladvance(curwin->w_curswant);
874-
875- u_clearline();
876-}
877-
878-/*
879664 * :move command - move lines line1-line2 to line dest
880665 *
881666 * return FAIL for failure, OK otherwise
diff -r 5202d9b99bee -r fe5afdc03bd2 src/globals.h
--- a/src/globals.h Wed Oct 09 22:15:04 2019 +0200
+++ b/src/globals.h Wed Oct 09 23:00:04 2019 +0200
@@ -843,6 +843,8 @@
843843 EXTERN int can_si_back INIT(= FALSE);
844844 #endif
845845
846+EXTERN int old_indent INIT(= 0); // for ^^D command in insert mode
847+
846848 EXTERN pos_T saved_cursor // w_cursor before formatting text.
847849 #ifdef DO_INIT
848850 = {0, 0, 0}
diff -r 5202d9b99bee -r fe5afdc03bd2 src/indent.c
--- a/src/indent.c Wed Oct 09 22:15:04 2019 +0200
+++ b/src/indent.c Wed Oct 09 23:00:04 2019 +0200
@@ -13,4451 +13,6 @@
1313
1414 #include "vim.h"
1515
16-#if defined(FEAT_CINDENT) || defined(FEAT_SMARTINDENT)
17-
18-static int cin_iscase(char_u *s, int strict);
19-static int cin_isscopedecl(char_u *s);
20-
21-/*
22- * Return TRUE if the string "line" starts with a word from 'cinwords'.
23- */
24- int
25-cin_is_cinword(char_u *line)
26-{
27- char_u *cinw;
28- char_u *cinw_buf;
29- int cinw_len;
30- int retval = FALSE;
31- int len;
32-
33- cinw_len = (int)STRLEN(curbuf->b_p_cinw) + 1;
34- cinw_buf = alloc(cinw_len);
35- if (cinw_buf != NULL)
36- {
37- line = skipwhite(line);
38- for (cinw = curbuf->b_p_cinw; *cinw; )
39- {
40- len = copy_option_part(&cinw, cinw_buf, cinw_len, ",");
41- if (STRNCMP(line, cinw_buf, len) == 0
42- && (!vim_iswordc(line[len]) || !vim_iswordc(line[len - 1])))
43- {
44- retval = TRUE;
45- break;
46- }
47- }
48- vim_free(cinw_buf);
49- }
50- return retval;
51-}
52-#endif
53-
54-#if defined(FEAT_CINDENT) || defined(FEAT_SYN_HL)
55-
56-static char_u *skip_string(char_u *p);
57-static pos_T *find_start_rawstring(int ind_maxcomment);
58-
59-/*
60- * Find the start of a comment, not knowing if we are in a comment right now.
61- * Search starts at w_cursor.lnum and goes backwards.
62- * Return NULL when not inside a comment.
63- */
64- static pos_T *
65-ind_find_start_comment(void) // XXX
66-{
67- return find_start_comment(curbuf->b_ind_maxcomment);
68-}
69-
70- pos_T *
71-find_start_comment(int ind_maxcomment) // XXX
72-{
73- pos_T *pos;
74- char_u *line;
75- char_u *p;
76- int cur_maxcomment = ind_maxcomment;
77-
78- for (;;)
79- {
80- pos = findmatchlimit(NULL, '*', FM_BACKWARD, cur_maxcomment);
81- if (pos == NULL)
82- break;
83-
84- // Check if the comment start we found is inside a string.
85- // If it is then restrict the search to below this line and try again.
86- line = ml_get(pos->lnum);
87- for (p = line; *p && (colnr_T)(p - line) < pos->col; ++p)
88- p = skip_string(p);
89- if ((colnr_T)(p - line) <= pos->col)
90- break;
91- cur_maxcomment = curwin->w_cursor.lnum - pos->lnum - 1;
92- if (cur_maxcomment <= 0)
93- {
94- pos = NULL;
95- break;
96- }
97- }
98- return pos;
99-}
100-
101-/*
102- * Find the start of a comment or raw string, not knowing if we are in a
103- * comment or raw string right now.
104- * Search starts at w_cursor.lnum and goes backwards.
105- * If is_raw is given and returns start of raw_string, sets it to true.
106- * Return NULL when not inside a comment or raw string.
107- * "CORS" -> Comment Or Raw String
108- */
109- static pos_T *
110-ind_find_start_CORS(linenr_T *is_raw) // XXX
111-{
112- static pos_T comment_pos_copy;
113- pos_T *comment_pos;
114- pos_T *rs_pos;
115-
116- comment_pos = find_start_comment(curbuf->b_ind_maxcomment);
117- if (comment_pos != NULL)
118- {
119- // Need to make a copy of the static pos in findmatchlimit(),
120- // calling find_start_rawstring() may change it.
121- comment_pos_copy = *comment_pos;
122- comment_pos = &comment_pos_copy;
123- }
124- rs_pos = find_start_rawstring(curbuf->b_ind_maxcomment);
125-
126- // If comment_pos is before rs_pos the raw string is inside the comment.
127- // If rs_pos is before comment_pos the comment is inside the raw string.
128- if (comment_pos == NULL || (rs_pos != NULL
129- && LT_POS(*rs_pos, *comment_pos)))
130- {
131- if (is_raw != NULL && rs_pos != NULL)
132- *is_raw = rs_pos->lnum;
133- return rs_pos;
134- }
135- return comment_pos;
136-}
137-
138-/*
139- * Find the start of a raw string, not knowing if we are in one right now.
140- * Search starts at w_cursor.lnum and goes backwards.
141- * Return NULL when not inside a raw string.
142- */
143- static pos_T *
144-find_start_rawstring(int ind_maxcomment) // XXX
145-{
146- pos_T *pos;
147- char_u *line;
148- char_u *p;
149- int cur_maxcomment = ind_maxcomment;
150-
151- for (;;)
152- {
153- pos = findmatchlimit(NULL, 'R', FM_BACKWARD, cur_maxcomment);
154- if (pos == NULL)
155- break;
156-
157- // Check if the raw string start we found is inside a string.
158- // If it is then restrict the search to below this line and try again.
159- line = ml_get(pos->lnum);
160- for (p = line; *p && (colnr_T)(p - line) < pos->col; ++p)
161- p = skip_string(p);
162- if ((colnr_T)(p - line) <= pos->col)
163- break;
164- cur_maxcomment = curwin->w_cursor.lnum - pos->lnum - 1;
165- if (cur_maxcomment <= 0)
166- {
167- pos = NULL;
168- break;
169- }
170- }
171- return pos;
172-}
173-
174-/*
175- * Skip to the end of a "string" and a 'c' character.
176- * If there is no string or character, return argument unmodified.
177- */
178- static char_u *
179-skip_string(char_u *p)
180-{
181- int i;
182-
183- // We loop, because strings may be concatenated: "date""time".
184- for ( ; ; ++p)
185- {
186- if (p[0] == '\'') // 'c' or '\n' or '\000'
187- {
188- if (!p[1]) // ' at end of line
189- break;
190- i = 2;
191- if (p[1] == '\\') // '\n' or '\000'
192- {
193- ++i;
194- while (vim_isdigit(p[i - 1])) // '\000'
195- ++i;
196- }
197- if (p[i] == '\'') // check for trailing '
198- {
199- p += i;
200- continue;
201- }
202- }
203- else if (p[0] == '"') // start of string
204- {
205- for (++p; p[0]; ++p)
206- {
207- if (p[0] == '\\' && p[1] != NUL)
208- ++p;
209- else if (p[0] == '"') // end of string
210- break;
211- }
212- if (p[0] == '"')
213- continue; // continue for another string
214- }
215- else if (p[0] == 'R' && p[1] == '"')
216- {
217- // Raw string: R"[delim](...)[delim]"
218- char_u *delim = p + 2;
219- char_u *paren = vim_strchr(delim, '(');
220-
221- if (paren != NULL)
222- {
223- size_t delim_len = paren - delim;
224-
225- for (p += 3; *p; ++p)
226- if (p[0] == ')' && STRNCMP(p + 1, delim, delim_len) == 0
227- && p[delim_len + 1] == '"')
228- {
229- p += delim_len + 1;
230- break;
231- }
232- if (p[0] == '"')
233- continue; // continue for another string
234- }
235- }
236- break; // no string found
237- }
238- if (!*p)
239- --p; // backup from NUL
240- return p;
241-}
242-#endif // FEAT_CINDENT || FEAT_SYN_HL
243-
244-#if defined(FEAT_CINDENT) || defined(PROTO)
245-
246-/*
247- * Return TRUE if C-indenting is on.
248- */
249- int
250-cindent_on(void)
251-{
252- return (!p_paste && (curbuf->b_p_cin
253-# ifdef FEAT_EVAL
254- || *curbuf->b_p_inde != NUL
255-# endif
256- ));
257-}
258-
259-// Find result cache for cpp_baseclass
260-typedef struct {
261- int found;
262- lpos_T lpos;
263-} cpp_baseclass_cache_T;
264-
265-/*
266- * Functions for C-indenting.
267- * Most of this originally comes from Eric Fischer.
268- */
269-/*
270- * Below "XXX" means that this function may unlock the current line.
271- */
272-
273-static int cin_isdefault(char_u *);
274-static int cin_ispreproc(char_u *);
275-static int cin_iscomment(char_u *);
276-static int cin_islinecomment(char_u *);
277-static int cin_isterminated(char_u *, int, int);
278-static int cin_iselse(char_u *);
279-static int cin_ends_in(char_u *, char_u *, char_u *);
280-static int cin_starts_with(char_u *s, char *word);
281-static pos_T *find_match_paren(int);
282-static pos_T *find_match_char(int c, int ind_maxparen);
283-static int find_last_paren(char_u *l, int start, int end);
284-static int find_match(int lookfor, linenr_T ourscope);
285-
286-/*
287- * Skip over white space and C comments within the line.
288- * Also skip over Perl/shell comments if desired.
289- */
290- static char_u *
291-cin_skipcomment(char_u *s)
292-{
293- while (*s)
294- {
295- char_u *prev_s = s;
296-
297- s = skipwhite(s);
298-
299- // Perl/shell # comment comment continues until eol. Require a space
300- // before # to avoid recognizing $#array.
301- if (curbuf->b_ind_hash_comment != 0 && s != prev_s && *s == '#')
302- {
303- s += STRLEN(s);
304- break;
305- }
306- if (*s != '/')
307- break;
308- ++s;
309- if (*s == '/') // slash-slash comment continues till eol
310- {
311- s += STRLEN(s);
312- break;
313- }
314- if (*s != '*')
315- break;
316- for (++s; *s; ++s) // skip slash-star comment
317- if (s[0] == '*' && s[1] == '/')
318- {
319- s += 2;
320- break;
321- }
322- }
323- return s;
324-}
325-
326-/*
327- * Return TRUE if there is no code at *s. White space and comments are
328- * not considered code.
329- */
330- static int
331-cin_nocode(char_u *s)
332-{
333- return *cin_skipcomment(s) == NUL;
334-}
335-
336-/*
337- * Check previous lines for a "//" line comment, skipping over blank lines.
338- */
339- static pos_T *
340-find_line_comment(void) // XXX
341-{
342- static pos_T pos;
343- char_u *line;
344- char_u *p;
345-
346- pos = curwin->w_cursor;
347- while (--pos.lnum > 0)
348- {
349- line = ml_get(pos.lnum);
350- p = skipwhite(line);
351- if (cin_islinecomment(p))
352- {
353- pos.col = (int)(p - line);
354- return &pos;
355- }
356- if (*p != NUL)
357- break;
358- }
359- return NULL;
360-}
361-
362-/*
363- * Return TRUE if "text" starts with "key:".
364- */
365- static int
366-cin_has_js_key(char_u *text)
367-{
368- char_u *s = skipwhite(text);
369- int quote = -1;
370-
371- if (*s == '\'' || *s == '"')
372- {
373- // can be 'key': or "key":
374- quote = *s;
375- ++s;
376- }
377- if (!vim_isIDc(*s)) // need at least one ID character
378- return FALSE;
379-
380- while (vim_isIDc(*s))
381- ++s;
382- if (*s == quote)
383- ++s;
384-
385- s = cin_skipcomment(s);
386-
387- // "::" is not a label, it's C++
388- return (*s == ':' && s[1] != ':');
389-}
390-
391-/*
392- * Check if string matches "label:"; move to character after ':' if true.
393- * "*s" must point to the start of the label, if there is one.
394- */
395- static int
396-cin_islabel_skip(char_u **s)
397-{
398- if (!vim_isIDc(**s)) // need at least one ID character
399- return FALSE;
400-
401- while (vim_isIDc(**s))
402- (*s)++;
403-
404- *s = cin_skipcomment(*s);
405-
406- // "::" is not a label, it's C++
407- return (**s == ':' && *++*s != ':');
408-}
409-
410-/*
411- * Recognize a label: "label:".
412- * Note: curwin->w_cursor must be where we are looking for the label.
413- */
414- static int
415-cin_islabel(void) // XXX
416-{
417- char_u *s;
418-
419- s = cin_skipcomment(ml_get_curline());
420-
421- // Exclude "default" from labels, since it should be indented
422- // like a switch label. Same for C++ scope declarations.
423- if (cin_isdefault(s))
424- return FALSE;
425- if (cin_isscopedecl(s))
426- return FALSE;
427-
428- if (cin_islabel_skip(&s))
429- {
430- // Only accept a label if the previous line is terminated or is a case
431- // label.
432- pos_T cursor_save;
433- pos_T *trypos;
434- char_u *line;
435-
436- cursor_save = curwin->w_cursor;
437- while (curwin->w_cursor.lnum > 1)
438- {
439- --curwin->w_cursor.lnum;
440-
441- // If we're in a comment or raw string now, skip to the start of
442- // it.
443- curwin->w_cursor.col = 0;
444- if ((trypos = ind_find_start_CORS(NULL)) != NULL) // XXX
445- curwin->w_cursor = *trypos;
446-
447- line = ml_get_curline();
448- if (cin_ispreproc(line)) // ignore #defines, #if, etc.
449- continue;
450- if (*(line = cin_skipcomment(line)) == NUL)
451- continue;
452-
453- curwin->w_cursor = cursor_save;
454- if (cin_isterminated(line, TRUE, FALSE)
455- || cin_isscopedecl(line)
456- || cin_iscase(line, TRUE)
457- || (cin_islabel_skip(&line) && cin_nocode(line)))
458- return TRUE;
459- return FALSE;
460- }
461- curwin->w_cursor = cursor_save;
462- return TRUE; // label at start of file???
463- }
464- return FALSE;
465-}
466-
467-/*
468- * Recognize structure initialization and enumerations:
469- * "[typedef] [static|public|protected|private] enum"
470- * "[typedef] [static|public|protected|private] = {"
471- */
472- static int
473-cin_isinit(void)
474-{
475- char_u *s;
476- static char *skip[] = {"static", "public", "protected", "private"};
477-
478- s = cin_skipcomment(ml_get_curline());
479-
480- if (cin_starts_with(s, "typedef"))
481- s = cin_skipcomment(s + 7);
482-
483- for (;;)
484- {
485- int i, l;
486-
487- for (i = 0; i < (int)(sizeof(skip) / sizeof(char *)); ++i)
488- {
489- l = (int)strlen(skip[i]);
490- if (cin_starts_with(s, skip[i]))
491- {
492- s = cin_skipcomment(s + l);
493- l = 0;
494- break;
495- }
496- }
497- if (l != 0)
498- break;
499- }
500-
501- if (cin_starts_with(s, "enum"))
502- return TRUE;
503-
504- if (cin_ends_in(s, (char_u *)"=", (char_u *)"{"))
505- return TRUE;
506-
507- return FALSE;
508-}
509-
510-/*
511- * Recognize a switch label: "case .*:" or "default:".
512- */
513- static int
514-cin_iscase(
515- char_u *s,
516- int strict) // Allow relaxed check of case statement for JS
517-{
518- s = cin_skipcomment(s);
519- if (cin_starts_with(s, "case"))
520- {
521- for (s += 4; *s; ++s)
522- {
523- s = cin_skipcomment(s);
524- if (*s == ':')
525- {
526- if (s[1] == ':') // skip over "::" for C++
527- ++s;
528- else
529- return TRUE;
530- }
531- if (*s == '\'' && s[1] && s[2] == '\'')
532- s += 2; // skip over ':'
533- else if (*s == '/' && (s[1] == '*' || s[1] == '/'))
534- return FALSE; // stop at comment
535- else if (*s == '"')
536- {
537- // JS etc.
538- if (strict)
539- return FALSE; // stop at string
540- else
541- return TRUE;
542- }
543- }
544- return FALSE;
545- }
546-
547- if (cin_isdefault(s))
548- return TRUE;
549- return FALSE;
550-}
551-
552-/*
553- * Recognize a "default" switch label.
554- */
555- static int
556-cin_isdefault(char_u *s)
557-{
558- return (STRNCMP(s, "default", 7) == 0
559- && *(s = cin_skipcomment(s + 7)) == ':'
560- && s[1] != ':');
561-}
562-
563-/*
564- * Recognize a "public/private/protected" scope declaration label.
565- */
566- static int
567-cin_isscopedecl(char_u *s)
568-{
569- int i;
570-
571- s = cin_skipcomment(s);
572- if (STRNCMP(s, "public", 6) == 0)
573- i = 6;
574- else if (STRNCMP(s, "protected", 9) == 0)
575- i = 9;
576- else if (STRNCMP(s, "private", 7) == 0)
577- i = 7;
578- else
579- return FALSE;
580- return (*(s = cin_skipcomment(s + i)) == ':' && s[1] != ':');
581-}
582-
583-// Maximum number of lines to search back for a "namespace" line.
584-#define FIND_NAMESPACE_LIM 20
585-
586-/*
587- * Recognize a "namespace" scope declaration.
588- */
589- static int
590-cin_is_cpp_namespace(char_u *s)
591-{
592- char_u *p;
593- int has_name = FALSE;
594- int has_name_start = FALSE;
595-
596- s = cin_skipcomment(s);
597- if (STRNCMP(s, "namespace", 9) == 0 && (s[9] == NUL || !vim_iswordc(s[9])))
598- {
599- p = cin_skipcomment(skipwhite(s + 9));
600- while (*p != NUL)
601- {
602- if (VIM_ISWHITE(*p))
603- {
604- has_name = TRUE; // found end of a name
605- p = cin_skipcomment(skipwhite(p));
606- }
607- else if (*p == '{')
608- {
609- break;
610- }
611- else if (vim_iswordc(*p))
612- {
613- has_name_start = TRUE;
614- if (has_name)
615- return FALSE; // word character after skipping past name
616- ++p;
617- }
618- else if (p[0] == ':' && p[1] == ':' && vim_iswordc(p[2]))
619- {
620- if (!has_name_start || has_name)
621- return FALSE;
622- // C++ 17 nested namespace
623- p += 3;
624- }
625- else
626- {
627- return FALSE;
628- }
629- }
630- return TRUE;
631- }
632- return FALSE;
633-}
634-
635-/*
636- * Recognize a `extern "C"` or `extern "C++"` linkage specifications.
637- */
638- static int
639-cin_is_cpp_extern_c(char_u *s)
640-{
641- char_u *p;
642- int has_string_literal = FALSE;
643-
644- s = cin_skipcomment(s);
645- if (STRNCMP(s, "extern", 6) == 0 && (s[6] == NUL || !vim_iswordc(s[6])))
646- {
647- p = cin_skipcomment(skipwhite(s + 6));
648- while (*p != NUL)
649- {
650- if (VIM_ISWHITE(*p))
651- {
652- p = cin_skipcomment(skipwhite(p));
653- }
654- else if (*p == '{')
655- {
656- break;
657- }
658- else if (p[0] == '"' && p[1] == 'C' && p[2] == '"')
659- {
660- if (has_string_literal)
661- return FALSE;
662- has_string_literal = TRUE;
663- p += 3;
664- }
665- else if (p[0] == '"' && p[1] == 'C' && p[2] == '+' && p[3] == '+'
666- && p[4] == '"')
667- {
668- if (has_string_literal)
669- return FALSE;
670- has_string_literal = TRUE;
671- p += 5;
672- }
673- else
674- {
675- return FALSE;
676- }
677- }
678- return has_string_literal ? TRUE : FALSE;
679- }
680- return FALSE;
681-}
682-
683-/*
684- * Return a pointer to the first non-empty non-comment character after a ':'.
685- * Return NULL if not found.
686- * case 234: a = b;
687- * ^
688- */
689- static char_u *
690-after_label(char_u *l)
691-{
692- for ( ; *l; ++l)
693- {
694- if (*l == ':')
695- {
696- if (l[1] == ':') // skip over "::" for C++
697- ++l;
698- else if (!cin_iscase(l + 1, FALSE))
699- break;
700- }
701- else if (*l == '\'' && l[1] && l[2] == '\'')
702- l += 2; // skip over 'x'
703- }
704- if (*l == NUL)
705- return NULL;
706- l = cin_skipcomment(l + 1);
707- if (*l == NUL)
708- return NULL;
709- return l;
710-}
711-
712-/*
713- * Get indent of line "lnum", skipping a label.
714- * Return 0 if there is nothing after the label.
715- */
716- static int
717-get_indent_nolabel (linenr_T lnum) // XXX
718-{
719- char_u *l;
720- pos_T fp;
721- colnr_T col;
722- char_u *p;
723-
724- l = ml_get(lnum);
725- p = after_label(l);
726- if (p == NULL)
727- return 0;
728-
729- fp.col = (colnr_T)(p - l);
730- fp.lnum = lnum;
731- getvcol(curwin, &fp, &col, NULL, NULL);
732- return (int)col;
733-}
734-
735-/*
736- * Find indent for line "lnum", ignoring any case or jump label.
737- * Also return a pointer to the text (after the label) in "pp".
738- * label: if (asdf && asdfasdf)
739- * ^
740- */
741- static int
742-skip_label(linenr_T lnum, char_u **pp)
743-{
744- char_u *l;
745- int amount;
746- pos_T cursor_save;
747-
748- cursor_save = curwin->w_cursor;
749- curwin->w_cursor.lnum = lnum;
750- l = ml_get_curline();
751- // XXX
752- if (cin_iscase(l, FALSE) || cin_isscopedecl(l) || cin_islabel())
753- {
754- amount = get_indent_nolabel(lnum);
755- l = after_label(ml_get_curline());
756- if (l == NULL) // just in case
757- l = ml_get_curline();
758- }
759- else
760- {
761- amount = get_indent();
762- l = ml_get_curline();
763- }
764- *pp = l;
765-
766- curwin->w_cursor = cursor_save;
767- return amount;
768-}
769-
770-/*
771- * Return the indent of the first variable name after a type in a declaration.
772- * int a, indent of "a"
773- * static struct foo b, indent of "b"
774- * enum bla c, indent of "c"
775- * Returns zero when it doesn't look like a declaration.
776- */
777- static int
778-cin_first_id_amount(void)
779-{
780- char_u *line, *p, *s;
781- int len;
782- pos_T fp;
783- colnr_T col;
784-
785- line = ml_get_curline();
786- p = skipwhite(line);
787- len = (int)(skiptowhite(p) - p);
788- if (len == 6 && STRNCMP(p, "static", 6) == 0)
789- {
790- p = skipwhite(p + 6);
791- len = (int)(skiptowhite(p) - p);
792- }
793- if (len == 6 && STRNCMP(p, "struct", 6) == 0)
794- p = skipwhite(p + 6);
795- else if (len == 4 && STRNCMP(p, "enum", 4) == 0)
796- p = skipwhite(p + 4);
797- else if ((len == 8 && STRNCMP(p, "unsigned", 8) == 0)
798- || (len == 6 && STRNCMP(p, "signed", 6) == 0))
799- {
800- s = skipwhite(p + len);
801- if ((STRNCMP(s, "int", 3) == 0 && VIM_ISWHITE(s[3]))
802- || (STRNCMP(s, "long", 4) == 0 && VIM_ISWHITE(s[4]))
803- || (STRNCMP(s, "short", 5) == 0 && VIM_ISWHITE(s[5]))
804- || (STRNCMP(s, "char", 4) == 0 && VIM_ISWHITE(s[4])))
805- p = s;
806- }
807- for (len = 0; vim_isIDc(p[len]); ++len)
808- ;
809- if (len == 0 || !VIM_ISWHITE(p[len]) || cin_nocode(p))
810- return 0;
811-
812- p = skipwhite(p + len);
813- fp.lnum = curwin->w_cursor.lnum;
814- fp.col = (colnr_T)(p - line);
815- getvcol(curwin, &fp, &col, NULL, NULL);
816- return (int)col;
817-}
818-
819-/*
820- * Return the indent of the first non-blank after an equal sign.
821- * char *foo = "here";
822- * Return zero if no (useful) equal sign found.
823- * Return -1 if the line above "lnum" ends in a backslash.
824- * foo = "asdf\
825- * asdf\
826- * here";
827- */
828- static int
829-cin_get_equal_amount(linenr_T lnum)
830-{
831- char_u *line;
832- char_u *s;
833- colnr_T col;
834- pos_T fp;
835-
836- if (lnum > 1)
837- {
838- line = ml_get(lnum - 1);
839- if (*line != NUL && line[STRLEN(line) - 1] == '\\')
840- return -1;
841- }
842-
843- line = s = ml_get(lnum);
844- while (*s != NUL && vim_strchr((char_u *)"=;{}\"'", *s) == NULL)
845- {
846- if (cin_iscomment(s)) // ignore comments
847- s = cin_skipcomment(s);
848- else
849- ++s;
850- }
851- if (*s != '=')
852- return 0;
853-
854- s = skipwhite(s + 1);
855- if (cin_nocode(s))
856- return 0;
857-
858- if (*s == '"') // nice alignment for continued strings
859- ++s;
860-
861- fp.lnum = lnum;
862- fp.col = (colnr_T)(s - line);
863- getvcol(curwin, &fp, &col, NULL, NULL);
864- return (int)col;
865-}
866-
867-/*
868- * Recognize a preprocessor statement: Any line that starts with '#'.
869- */
870- static int
871-cin_ispreproc(char_u *s)
872-{
873- if (*skipwhite(s) == '#')
874- return TRUE;
875- return FALSE;
876-}
877-
878-/*
879- * Return TRUE if line "*pp" at "*lnump" is a preprocessor statement or a
880- * continuation line of a preprocessor statement. Decrease "*lnump" to the
881- * start and return the line in "*pp".
882- * Put the amount of indent in "*amount".
883- */
884- static int
885-cin_ispreproc_cont(char_u **pp, linenr_T *lnump, int *amount)
886-{
887- char_u *line = *pp;
888- linenr_T lnum = *lnump;
889- int retval = FALSE;
890- int candidate_amount = *amount;
891-
892- if (*line != NUL && line[STRLEN(line) - 1] == '\\')
893- candidate_amount = get_indent_lnum(lnum);
894-
895- for (;;)
896- {
897- if (cin_ispreproc(line))
898- {
899- retval = TRUE;
900- *lnump = lnum;
901- break;
902- }
903- if (lnum == 1)
904- break;
905- line = ml_get(--lnum);
906- if (*line == NUL || line[STRLEN(line) - 1] != '\\')
907- break;
908- }
909-
910- if (lnum != *lnump)
911- *pp = ml_get(*lnump);
912- if (retval)
913- *amount = candidate_amount;
914- return retval;
915-}
916-
917-/*
918- * Recognize the start of a C or C++ comment.
919- */
920- static int
921-cin_iscomment(char_u *p)
922-{
923- return (p[0] == '/' && (p[1] == '*' || p[1] == '/'));
924-}
925-
926-/*
927- * Recognize the start of a "//" comment.
928- */
929- static int
930-cin_islinecomment(char_u *p)
931-{
932- return (p[0] == '/' && p[1] == '/');
933-}
934-
935-/*
936- * Recognize a line that starts with '{' or '}', or ends with ';', ',', '{' or
937- * '}'.
938- * Don't consider "} else" a terminated line.
939- * If a line begins with an "else", only consider it terminated if no unmatched
940- * opening braces follow (handle "else { foo();" correctly).
941- * Return the character terminating the line (ending char's have precedence if
942- * both apply in order to determine initializations).
943- */
944- static int
945-cin_isterminated(
946- char_u *s,
947- int incl_open, // include '{' at the end as terminator
948- int incl_comma) // recognize a trailing comma
949-{
950- char_u found_start = 0;
951- unsigned n_open = 0;
952- int is_else = FALSE;
953-
954- s = cin_skipcomment(s);
955-
956- if (*s == '{' || (*s == '}' && !cin_iselse(s)))
957- found_start = *s;
958-
959- if (!found_start)
960- is_else = cin_iselse(s);
961-
962- while (*s)
963- {
964- // skip over comments, "" strings and 'c'haracters
965- s = skip_string(cin_skipcomment(s));
966- if (*s == '}' && n_open > 0)
967- --n_open;
968- if ((!is_else || n_open == 0)
969- && (*s == ';' || *s == '}' || (incl_comma && *s == ','))
970- && cin_nocode(s + 1))
971- return *s;
972- else if (*s == '{')
973- {
974- if (incl_open && cin_nocode(s + 1))
975- return *s;
976- else
977- ++n_open;
978- }
979-
980- if (*s)
981- s++;
982- }
983- return found_start;
984-}
985-
986-/*
987- * Recognize the basic picture of a function declaration -- it needs to
988- * have an open paren somewhere and a close paren at the end of the line and
989- * no semicolons anywhere.
990- * When a line ends in a comma we continue looking in the next line.
991- * "sp" points to a string with the line. When looking at other lines it must
992- * be restored to the line. When it's NULL fetch lines here.
993- * "first_lnum" is where we start looking.
994- * "min_lnum" is the line before which we will not be looking.
995- */
996- static int
997-cin_isfuncdecl(
998- char_u **sp,
999- linenr_T first_lnum,
1000- linenr_T min_lnum)
1001-{
1002- char_u *s;
1003- linenr_T lnum = first_lnum;
1004- linenr_T save_lnum = curwin->w_cursor.lnum;
1005- int retval = FALSE;
1006- pos_T *trypos;
1007- int just_started = TRUE;
1008-
1009- if (sp == NULL)
1010- s = ml_get(lnum);
1011- else
1012- s = *sp;
1013-
1014- curwin->w_cursor.lnum = lnum;
1015- if (find_last_paren(s, '(', ')')
1016- && (trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL)
1017- {
1018- lnum = trypos->lnum;
1019- if (lnum < min_lnum)
1020- {
1021- curwin->w_cursor.lnum = save_lnum;
1022- return FALSE;
1023- }
1024-
1025- s = ml_get(lnum);
1026- }
1027- curwin->w_cursor.lnum = save_lnum;
1028-
1029- // Ignore line starting with #.
1030- if (cin_ispreproc(s))
1031- return FALSE;
1032-
1033- while (*s && *s != '(' && *s != ';' && *s != '\'' && *s != '"')
1034- {
1035- if (cin_iscomment(s)) // ignore comments
1036- s = cin_skipcomment(s);
1037- else if (*s == ':')
1038- {
1039- if (*(s + 1) == ':')
1040- s += 2;
1041- else
1042- // To avoid a mistake in the following situation:
1043- // A::A(int a, int b)
1044- // : a(0) // <--not a function decl
1045- // , b(0)
1046- // {...
1047- return FALSE;
1048- }
1049- else
1050- ++s;
1051- }
1052- if (*s != '(')
1053- return FALSE; // ';', ' or " before any () or no '('
1054-
1055- while (*s && *s != ';' && *s != '\'' && *s != '"')
1056- {
1057- if (*s == ')' && cin_nocode(s + 1))
1058- {
1059- /*
1060- * ')' at the end: may have found a match
1061- * Check for he previous line not to end in a backslash:
1062- * #if defined(x) && \
1063- * defined(y)
1064- */
1065- lnum = first_lnum - 1;
1066- s = ml_get(lnum);
1067- if (*s == NUL || s[STRLEN(s) - 1] != '\\')
1068- retval = TRUE;
1069- goto done;
1070- }
1071- if ((*s == ',' && cin_nocode(s + 1)) || s[1] == NUL || cin_nocode(s))
1072- {
1073- int comma = (*s == ',');
1074-
1075- // ',' at the end: continue looking in the next line.
1076- // At the end: check for ',' in the next line, for this style:
1077- // func(arg1
1078- // , arg2)
1079- for (;;)
1080- {
1081- if (lnum >= curbuf->b_ml.ml_line_count)
1082- break;
1083- s = ml_get(++lnum);
1084- if (!cin_ispreproc(s))
1085- break;
1086- }
1087- if (lnum >= curbuf->b_ml.ml_line_count)
1088- break;
1089- // Require a comma at end of the line or a comma or ')' at the
1090- // start of next line.
1091- s = skipwhite(s);
1092- if (!just_started && (!comma && *s != ',' && *s != ')'))
1093- break;
1094- just_started = FALSE;
1095- }
1096- else if (cin_iscomment(s)) // ignore comments
1097- s = cin_skipcomment(s);
1098- else
1099- {
1100- ++s;
1101- just_started = FALSE;
1102- }
1103- }
1104-
1105-done:
1106- if (lnum != first_lnum && sp != NULL)
1107- *sp = ml_get(first_lnum);
1108-
1109- return retval;
1110-}
1111-
1112- static int
1113-cin_isif(char_u *p)
1114-{
1115- return (STRNCMP(p, "if", 2) == 0 && !vim_isIDc(p[2]));
1116-}
1117-
1118- static int
1119-cin_iselse(
1120- char_u *p)
1121-{
1122- if (*p == '}') // accept "} else"
1123- p = cin_skipcomment(p + 1);
1124- return (STRNCMP(p, "else", 4) == 0 && !vim_isIDc(p[4]));
1125-}
1126-
1127- static int
1128-cin_isdo(char_u *p)
1129-{
1130- return (STRNCMP(p, "do", 2) == 0 && !vim_isIDc(p[2]));
1131-}
1132-
1133-/*
1134- * Check if this is a "while" that should have a matching "do".
1135- * We only accept a "while (condition) ;", with only white space between the
1136- * ')' and ';'. The condition may be spread over several lines.
1137- */
1138- static int
1139-cin_iswhileofdo (char_u *p, linenr_T lnum) // XXX
1140-{
1141- pos_T cursor_save;
1142- pos_T *trypos;
1143- int retval = FALSE;
1144-
1145- p = cin_skipcomment(p);
1146- if (*p == '}') // accept "} while (cond);"
1147- p = cin_skipcomment(p + 1);
1148- if (cin_starts_with(p, "while"))
1149- {
1150- cursor_save = curwin->w_cursor;
1151- curwin->w_cursor.lnum = lnum;
1152- curwin->w_cursor.col = 0;
1153- p = ml_get_curline();
1154- while (*p && *p != 'w') // skip any '}', until the 'w' of the "while"
1155- {
1156- ++p;
1157- ++curwin->w_cursor.col;
1158- }
1159- if ((trypos = findmatchlimit(NULL, 0, 0,
1160- curbuf->b_ind_maxparen)) != NULL
1161- && *cin_skipcomment(ml_get_pos(trypos) + 1) == ';')
1162- retval = TRUE;
1163- curwin->w_cursor = cursor_save;
1164- }
1165- return retval;
1166-}
1167-
1168-/*
1169- * Check whether in "p" there is an "if", "for" or "while" before "*poffset".
1170- * Return 0 if there is none.
1171- * Otherwise return !0 and update "*poffset" to point to the place where the
1172- * string was found.
1173- */
1174- static int
1175-cin_is_if_for_while_before_offset(char_u *line, int *poffset)
1176-{
1177- int offset = *poffset;
1178-
1179- if (offset-- < 2)
1180- return 0;
1181- while (offset > 2 && VIM_ISWHITE(line[offset]))
1182- --offset;
1183-
1184- offset -= 1;
1185- if (!STRNCMP(line + offset, "if", 2))
1186- goto probablyFound;
1187-
1188- if (offset >= 1)
1189- {
1190- offset -= 1;
1191- if (!STRNCMP(line + offset, "for", 3))
1192- goto probablyFound;
1193-
1194- if (offset >= 2)
1195- {
1196- offset -= 2;
1197- if (!STRNCMP(line + offset, "while", 5))
1198- goto probablyFound;
1199- }
1200- }
1201- return 0;
1202-
1203-probablyFound:
1204- if (!offset || !vim_isIDc(line[offset - 1]))
1205- {
1206- *poffset = offset;
1207- return 1;
1208- }
1209- return 0;
1210-}
1211-
1212-/*
1213- * Return TRUE if we are at the end of a do-while.
1214- * do
1215- * nothing;
1216- * while (foo
1217- * && bar); <-- here
1218- * Adjust the cursor to the line with "while".
1219- */
1220- static int
1221-cin_iswhileofdo_end(int terminated)
1222-{
1223- char_u *line;
1224- char_u *p;
1225- char_u *s;
1226- pos_T *trypos;
1227- int i;
1228-
1229- if (terminated != ';') // there must be a ';' at the end
1230- return FALSE;
1231-
1232- p = line = ml_get_curline();
1233- while (*p != NUL)
1234- {
1235- p = cin_skipcomment(p);
1236- if (*p == ')')
1237- {
1238- s = skipwhite(p + 1);
1239- if (*s == ';' && cin_nocode(s + 1))
1240- {
1241- // Found ");" at end of the line, now check there is "while"
1242- // before the matching '('. XXX
1243- i = (int)(p - line);
1244- curwin->w_cursor.col = i;
1245- trypos = find_match_paren(curbuf->b_ind_maxparen);
1246- if (trypos != NULL)
1247- {
1248- s = cin_skipcomment(ml_get(trypos->lnum));
1249- if (*s == '}') // accept "} while (cond);"
1250- s = cin_skipcomment(s + 1);
1251- if (cin_starts_with(s, "while"))
1252- {
1253- curwin->w_cursor.lnum = trypos->lnum;
1254- return TRUE;
1255- }
1256- }
1257-
1258- // Searching may have made "line" invalid, get it again.
1259- line = ml_get_curline();
1260- p = line + i;
1261- }
1262- }
1263- if (*p != NUL)
1264- ++p;
1265- }
1266- return FALSE;
1267-}
1268-
1269- static int
1270-cin_isbreak(char_u *p)
1271-{
1272- return (STRNCMP(p, "break", 5) == 0 && !vim_isIDc(p[5]));
1273-}
1274-
1275-/*
1276- * Find the position of a C++ base-class declaration or
1277- * constructor-initialization. eg:
1278- *
1279- * class MyClass :
1280- * baseClass <-- here
1281- * class MyClass : public baseClass,
1282- * anotherBaseClass <-- here (should probably lineup ??)
1283- * MyClass::MyClass(...) :
1284- * baseClass(...) <-- here (constructor-initialization)
1285- *
1286- * This is a lot of guessing. Watch out for "cond ? func() : foo".
1287- */
1288- static int
1289-cin_is_cpp_baseclass(
1290- cpp_baseclass_cache_T *cached) // input and output
1291-{
1292- lpos_T *pos = &cached->lpos; // find position
1293- char_u *s;
1294- int class_or_struct, lookfor_ctor_init, cpp_base_class;
1295- linenr_T lnum = curwin->w_cursor.lnum;
1296- char_u *line = ml_get_curline();
1297-
1298- if (pos->lnum <= lnum)
1299- return cached->found; // Use the cached result
1300-
1301- pos->col = 0;
1302-
1303- s = skipwhite(line);
1304- if (*s == '#') // skip #define FOO x ? (x) : x
1305- return FALSE;
1306- s = cin_skipcomment(s);
1307- if (*s == NUL)
1308- return FALSE;
1309-
1310- cpp_base_class = lookfor_ctor_init = class_or_struct = FALSE;
1311-
1312- // Search for a line starting with '#', empty, ending in ';' or containing
1313- // '{' or '}' and start below it. This handles the following situations:
1314- // a = cond ?
1315- // func() :
1316- // asdf;
1317- // func::foo()
1318- // : something
1319- // {}
1320- // Foo::Foo (int one, int two)
1321- // : something(4),
1322- // somethingelse(3)
1323- // {}
1324- while (lnum > 1)
1325- {
1326- line = ml_get(lnum - 1);
1327- s = skipwhite(line);
1328- if (*s == '#' || *s == NUL)
1329- break;
1330- while (*s != NUL)
1331- {
1332- s = cin_skipcomment(s);
1333- if (*s == '{' || *s == '}'
1334- || (*s == ';' && cin_nocode(s + 1)))
1335- break;
1336- if (*s != NUL)
1337- ++s;
1338- }
1339- if (*s != NUL)
1340- break;
1341- --lnum;
1342- }
1343-
1344- pos->lnum = lnum;
1345- line = ml_get(lnum);
1346- s = line;
1347- for (;;)
1348- {
1349- if (*s == NUL)
1350- {
1351- if (lnum == curwin->w_cursor.lnum)
1352- break;
1353- // Continue in the cursor line.
1354- line = ml_get(++lnum);
1355- s = line;
1356- }
1357- if (s == line)
1358- {
1359- // don't recognize "case (foo):" as a baseclass
1360- if (cin_iscase(s, FALSE))
1361- break;
1362- s = cin_skipcomment(line);
1363- if (*s == NUL)
1364- continue;
1365- }
1366-
1367- if (s[0] == '"' || (s[0] == 'R' && s[1] == '"'))
1368- s = skip_string(s) + 1;
1369- else if (s[0] == ':')
1370- {
1371- if (s[1] == ':')
1372- {
1373- // skip double colon. It can't be a constructor
1374- // initialization any more
1375- lookfor_ctor_init = FALSE;
1376- s = cin_skipcomment(s + 2);
1377- }
1378- else if (lookfor_ctor_init || class_or_struct)
1379- {
1380- // we have something found, that looks like the start of
1381- // cpp-base-class-declaration or constructor-initialization
1382- cpp_base_class = TRUE;
1383- lookfor_ctor_init = class_or_struct = FALSE;
1384- pos->col = 0;
1385- s = cin_skipcomment(s + 1);
1386- }
1387- else
1388- s = cin_skipcomment(s + 1);
1389- }
1390- else if ((STRNCMP(s, "class", 5) == 0 && !vim_isIDc(s[5]))
1391- || (STRNCMP(s, "struct", 6) == 0 && !vim_isIDc(s[6])))
1392- {
1393- class_or_struct = TRUE;
1394- lookfor_ctor_init = FALSE;
1395-
1396- if (*s == 'c')
1397- s = cin_skipcomment(s + 5);
1398- else
1399- s = cin_skipcomment(s + 6);
1400- }
1401- else
1402- {
1403- if (s[0] == '{' || s[0] == '}' || s[0] == ';')
1404- {
1405- cpp_base_class = lookfor_ctor_init = class_or_struct = FALSE;
1406- }
1407- else if (s[0] == ')')
1408- {
1409- // Constructor-initialization is assumed if we come across
1410- // something like "):"
1411- class_or_struct = FALSE;
1412- lookfor_ctor_init = TRUE;
1413- }
1414- else if (s[0] == '?')
1415- {
1416- // Avoid seeing '() :' after '?' as constructor init.
1417- return FALSE;
1418- }
1419- else if (!vim_isIDc(s[0]))
1420- {
1421- // if it is not an identifier, we are wrong
1422- class_or_struct = FALSE;
1423- lookfor_ctor_init = FALSE;
1424- }
1425- else if (pos->col == 0)
1426- {
1427- // it can't be a constructor-initialization any more
1428- lookfor_ctor_init = FALSE;
1429-
1430- // the first statement starts here: lineup with this one...
1431- if (cpp_base_class)
1432- pos->col = (colnr_T)(s - line);
1433- }
1434-
1435- // When the line ends in a comma don't align with it.
1436- if (lnum == curwin->w_cursor.lnum && *s == ',' && cin_nocode(s + 1))
1437- pos->col = 0;
1438-
1439- s = cin_skipcomment(s + 1);
1440- }
1441- }
1442-
1443- cached->found = cpp_base_class;
1444- if (cpp_base_class)
1445- pos->lnum = lnum;
1446- return cpp_base_class;
1447-}
1448-
1449- static int
1450-get_baseclass_amount(int col)
1451-{
1452- int amount;
1453- colnr_T vcol;
1454- pos_T *trypos;
1455-
1456- if (col == 0)
1457- {
1458- amount = get_indent();
1459- if (find_last_paren(ml_get_curline(), '(', ')')
1460- && (trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL)
1461- amount = get_indent_lnum(trypos->lnum); // XXX
1462- if (!cin_ends_in(ml_get_curline(), (char_u *)",", NULL))
1463- amount += curbuf->b_ind_cpp_baseclass;
1464- }
1465- else
1466- {
1467- curwin->w_cursor.col = col;
1468- getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL);
1469- amount = (int)vcol;
1470- }
1471- if (amount < curbuf->b_ind_cpp_baseclass)
1472- amount = curbuf->b_ind_cpp_baseclass;
1473- return amount;
1474-}
1475-
1476-/*
1477- * Return TRUE if string "s" ends with the string "find", possibly followed by
1478- * white space and comments. Skip strings and comments.
1479- * Ignore "ignore" after "find" if it's not NULL.
1480- */
1481- static int
1482-cin_ends_in(char_u *s, char_u *find, char_u *ignore)
1483-{
1484- char_u *p = s;
1485- char_u *r;
1486- int len = (int)STRLEN(find);
1487-
1488- while (*p != NUL)
1489- {
1490- p = cin_skipcomment(p);
1491- if (STRNCMP(p, find, len) == 0)
1492- {
1493- r = skipwhite(p + len);
1494- if (ignore != NULL && STRNCMP(r, ignore, STRLEN(ignore)) == 0)
1495- r = skipwhite(r + STRLEN(ignore));
1496- if (cin_nocode(r))
1497- return TRUE;
1498- }
1499- if (*p != NUL)
1500- ++p;
1501- }
1502- return FALSE;
1503-}
1504-
1505-/*
1506- * Return TRUE when "s" starts with "word" and then a non-ID character.
1507- */
1508- static int
1509-cin_starts_with(char_u *s, char *word)
1510-{
1511- int l = (int)STRLEN(word);
1512-
1513- return (STRNCMP(s, word, l) == 0 && !vim_isIDc(s[l]));
1514-}
1515-
1516-/*
1517- * Skip strings, chars and comments until at or past "trypos".
1518- * Return the column found.
1519- */
1520- static int
1521-cin_skip2pos(pos_T *trypos)
1522-{
1523- char_u *line;
1524- char_u *p;
1525- char_u *new_p;
1526-
1527- p = line = ml_get(trypos->lnum);
1528- while (*p && (colnr_T)(p - line) < trypos->col)
1529- {
1530- if (cin_iscomment(p))
1531- p = cin_skipcomment(p);
1532- else
1533- {
1534- new_p = skip_string(p);
1535- if (new_p == p)
1536- ++p;
1537- else
1538- p = new_p;
1539- }
1540- }
1541- return (int)(p - line);
1542-}
1543-
1544-/*
1545- * Find the '{' at the start of the block we are in.
1546- * Return NULL if no match found.
1547- * Ignore a '{' that is in a comment, makes indenting the next three lines
1548- * work.
1549- */
1550-/* foo() */
1551-/* { */
1552-/* } */
1553-
1554- static pos_T *
1555-find_start_brace(void) // XXX
1556-{
1557- pos_T cursor_save;
1558- pos_T *trypos;
1559- pos_T *pos;
1560- static pos_T pos_copy;
1561-
1562- cursor_save = curwin->w_cursor;
1563- while ((trypos = findmatchlimit(NULL, '{', FM_BLOCKSTOP, 0)) != NULL)
1564- {
1565- pos_copy = *trypos; // copy pos_T, next findmatch will change it
1566- trypos = &pos_copy;
1567- curwin->w_cursor = *trypos;
1568- pos = NULL;
1569- // ignore the { if it's in a // or / * * / comment
1570- if ((colnr_T)cin_skip2pos(trypos) == trypos->col
1571- && (pos = ind_find_start_CORS(NULL)) == NULL) // XXX
1572- break;
1573- if (pos != NULL)
1574- curwin->w_cursor.lnum = pos->lnum;
1575- }
1576- curwin->w_cursor = cursor_save;
1577- return trypos;
1578-}
1579-
1580-/*
1581- * Find the matching '(', ignoring it if it is in a comment.
1582- * Return NULL if no match found.
1583- */
1584- static pos_T *
1585-find_match_paren(int ind_maxparen) // XXX
1586-{
1587- return find_match_char('(', ind_maxparen);
1588-}
1589-
1590- static pos_T *
1591-find_match_char(int c, int ind_maxparen) // XXX
1592-{
1593- pos_T cursor_save;
1594- pos_T *trypos;
1595- static pos_T pos_copy;
1596- int ind_maxp_wk;
1597-
1598- cursor_save = curwin->w_cursor;
1599- ind_maxp_wk = ind_maxparen;
1600-retry:
1601- if ((trypos = findmatchlimit(NULL, c, 0, ind_maxp_wk)) != NULL)
1602- {
1603- // check if the ( is in a // comment
1604- if ((colnr_T)cin_skip2pos(trypos) > trypos->col)
1605- {
1606- ind_maxp_wk = ind_maxparen - (int)(cursor_save.lnum - trypos->lnum);
1607- if (ind_maxp_wk > 0)
1608- {
1609- curwin->w_cursor = *trypos;
1610- curwin->w_cursor.col = 0; // XXX
1611- goto retry;
1612- }
1613- trypos = NULL;
1614- }
1615- else
1616- {
1617- pos_T *trypos_wk;
1618-
1619- pos_copy = *trypos; // copy trypos, findmatch will change it
1620- trypos = &pos_copy;
1621- curwin->w_cursor = *trypos;
1622- if ((trypos_wk = ind_find_start_CORS(NULL)) != NULL) // XXX
1623- {
1624- ind_maxp_wk = ind_maxparen - (int)(cursor_save.lnum
1625- - trypos_wk->lnum);
1626- if (ind_maxp_wk > 0)
1627- {
1628- curwin->w_cursor = *trypos_wk;
1629- goto retry;
1630- }
1631- trypos = NULL;
1632- }
1633- }
1634- }
1635- curwin->w_cursor = cursor_save;
1636- return trypos;
1637-}
1638-
1639-/*
1640- * Find the matching '(', ignoring it if it is in a comment or before an
1641- * unmatched {.
1642- * Return NULL if no match found.
1643- */
1644- static pos_T *
1645-find_match_paren_after_brace (int ind_maxparen) // XXX
1646-{
1647- pos_T *trypos = find_match_paren(ind_maxparen);
1648-
1649- if (trypos != NULL)
1650- {
1651- pos_T *tryposBrace = find_start_brace();
1652-
1653- // If both an unmatched '(' and '{' is found. Ignore the '('
1654- // position if the '{' is further down.
1655- if (tryposBrace != NULL
1656- && (trypos->lnum != tryposBrace->lnum
1657- ? trypos->lnum < tryposBrace->lnum
1658- : trypos->col < tryposBrace->col))
1659- trypos = NULL;
1660- }
1661- return trypos;
1662-}
1663-
1664-/*
1665- * Return ind_maxparen corrected for the difference in line number between the
1666- * cursor position and "startpos". This makes sure that searching for a
1667- * matching paren above the cursor line doesn't find a match because of
1668- * looking a few lines further.
1669- */
1670- static int
1671-corr_ind_maxparen(pos_T *startpos)
1672-{
1673- long n = (long)startpos->lnum - (long)curwin->w_cursor.lnum;
1674-
1675- if (n > 0 && n < curbuf->b_ind_maxparen / 2)
1676- return curbuf->b_ind_maxparen - (int)n;
1677- return curbuf->b_ind_maxparen;
1678-}
1679-
1680-/*
1681- * Set w_cursor.col to the column number of the last unmatched ')' or '{' in
1682- * line "l". "l" must point to the start of the line.
1683- */
1684- static int
1685-find_last_paren(char_u *l, int start, int end)
1686-{
1687- int i;
1688- int retval = FALSE;
1689- int open_count = 0;
1690-
1691- curwin->w_cursor.col = 0; // default is start of line
1692-
1693- for (i = 0; l[i] != NUL; i++)
1694- {
1695- i = (int)(cin_skipcomment(l + i) - l); // ignore parens in comments
1696- i = (int)(skip_string(l + i) - l); // ignore parens in quotes
1697- if (l[i] == start)
1698- ++open_count;
1699- else if (l[i] == end)
1700- {
1701- if (open_count > 0)
1702- --open_count;
1703- else
1704- {
1705- curwin->w_cursor.col = i;
1706- retval = TRUE;
1707- }
1708- }
1709- }
1710- return retval;
1711-}
1712-
1713-/*
1714- * Parse 'cinoptions' and set the values in "curbuf".
1715- * Must be called when 'cinoptions', 'shiftwidth' and/or 'tabstop' changes.
1716- */
1717- void
1718-parse_cino(buf_T *buf)
1719-{
1720- char_u *p;
1721- char_u *l;
1722- char_u *digits;
1723- int n;
1724- int divider;
1725- int fraction = 0;
1726- int sw = (int)get_sw_value(buf);
1727-
1728- // Set the default values.
1729-
1730- // Spaces from a block's opening brace the prevailing indent for that
1731- // block should be.
1732- buf->b_ind_level = sw;
1733-
1734- // Spaces from the edge of the line an open brace that's at the end of a
1735- // line is imagined to be.
1736- buf->b_ind_open_imag = 0;
1737-
1738- // Spaces from the prevailing indent for a line that is not preceded by
1739- // an opening brace.
1740- buf->b_ind_no_brace = 0;
1741-
1742- // Column where the first { of a function should be located }.
1743- buf->b_ind_first_open = 0;
1744-
1745- // Spaces from the prevailing indent a leftmost open brace should be
1746- // located.
1747- buf->b_ind_open_extra = 0;
1748-
1749- // Spaces from the matching open brace (real location for one at the left
1750- // edge; imaginary location from one that ends a line) the matching close
1751- // brace should be located.
1752- buf->b_ind_close_extra = 0;
1753-
1754- // Spaces from the edge of the line an open brace sitting in the leftmost
1755- // column is imagined to be.
1756- buf->b_ind_open_left_imag = 0;
1757-
1758- // Spaces jump labels should be shifted to the left if N is non-negative,
1759- // otherwise the jump label will be put to column 1.
1760- buf->b_ind_jump_label = -1;
1761-
1762- // Spaces from the switch() indent a "case xx" label should be located.
1763- buf->b_ind_case = sw;
1764-
1765- // Spaces from the "case xx:" code after a switch() should be located.
1766- buf->b_ind_case_code = sw;
1767-
1768- // Lineup break at end of case in switch() with case label.
1769- buf->b_ind_case_break = 0;
1770-
1771- // Spaces from the class declaration indent a scope declaration label
1772- // should be located.
1773- buf->b_ind_scopedecl = sw;
1774-
1775- // Spaces from the scope declaration label code should be located.
1776- buf->b_ind_scopedecl_code = sw;
1777-
1778- // Amount K&R-style parameters should be indented.
1779- buf->b_ind_param = sw;
1780-
1781- // Amount a function type spec should be indented.
1782- buf->b_ind_func_type = sw;
1783-
1784- // Amount a cpp base class declaration or constructor initialization
1785- // should be indented.
1786- buf->b_ind_cpp_baseclass = sw;
1787-
1788- // additional spaces beyond the prevailing indent a continuation line
1789- // should be located.
1790- buf->b_ind_continuation = sw;
1791-
1792- // Spaces from the indent of the line with an unclosed parentheses.
1793- buf->b_ind_unclosed = sw * 2;
1794-
1795- // Spaces from the indent of the line with an unclosed parentheses, which
1796- // itself is also unclosed.
1797- buf->b_ind_unclosed2 = sw;
1798-
1799- // Suppress ignoring spaces from the indent of a line starting with an
1800- // unclosed parentheses.
1801- buf->b_ind_unclosed_noignore = 0;
1802-
1803- // If the opening paren is the last nonwhite character on the line, and
1804- // b_ind_unclosed_wrapped is nonzero, use this indent relative to the outer
1805- // context (for very long lines).
1806- buf->b_ind_unclosed_wrapped = 0;
1807-
1808- // Suppress ignoring white space when lining up with the character after
1809- // an unclosed parentheses.
1810- buf->b_ind_unclosed_whiteok = 0;
1811-
1812- // Indent a closing parentheses under the line start of the matching
1813- // opening parentheses.
1814- buf->b_ind_matching_paren = 0;
1815-
1816- // Indent a closing parentheses under the previous line.
1817- buf->b_ind_paren_prev = 0;
1818-
1819- // Extra indent for comments.
1820- buf->b_ind_comment = 0;
1821-
1822- // Spaces from the comment opener when there is nothing after it.
1823- buf->b_ind_in_comment = 3;
1824-
1825- // Boolean: if non-zero, use b_ind_in_comment even if there is something
1826- // after the comment opener.
1827- buf->b_ind_in_comment2 = 0;
1828-
1829- // Max lines to search for an open paren.
1830- buf->b_ind_maxparen = 20;
1831-
1832- // Max lines to search for an open comment.
1833- buf->b_ind_maxcomment = 70;
1834-
1835- // Handle braces for java code.
1836- buf->b_ind_java = 0;
1837-
1838- // Not to confuse JS object properties with labels.
1839- buf->b_ind_js = 0;
1840-
1841- // Handle blocked cases correctly.
1842- buf->b_ind_keep_case_label = 0;
1843-
1844- // Handle C++ namespace.
1845- buf->b_ind_cpp_namespace = 0;
1846-
1847- // Handle continuation lines containing conditions of if(), for() and
1848- // while().
1849- buf->b_ind_if_for_while = 0;
1850-
1851- // indentation for # comments
1852- buf->b_ind_hash_comment = 0;
1853-
1854- // Handle C++ extern "C" or "C++"
1855- buf->b_ind_cpp_extern_c = 0;
1856-
1857- for (p = buf->b_p_cino; *p; )
1858- {
1859- l = p++;
1860- if (*p == '-')
1861- ++p;
1862- digits = p; // remember where the digits start
1863- n = getdigits(&p);
1864- divider = 0;
1865- if (*p == '.') // ".5s" means a fraction
1866- {
1867- fraction = atol((char *)++p);
1868- while (VIM_ISDIGIT(*p))
1869- {
1870- ++p;
1871- if (divider)
1872- divider *= 10;
1873- else
1874- divider = 10;
1875- }
1876- }
1877- if (*p == 's') // "2s" means two times 'shiftwidth'
1878- {
1879- if (p == digits)
1880- n = sw; // just "s" is one 'shiftwidth'
1881- else
1882- {
1883- n *= sw;
1884- if (divider)
1885- n += (sw * fraction + divider / 2) / divider;
1886- }
1887- ++p;
1888- }
1889- if (l[1] == '-')
1890- n = -n;
1891-
1892- // When adding an entry here, also update the default 'cinoptions' in
1893- // doc/indent.txt, and add explanation for it!
1894- switch (*l)
1895- {
1896- case '>': buf->b_ind_level = n; break;
1897- case 'e': buf->b_ind_open_imag = n; break;
1898- case 'n': buf->b_ind_no_brace = n; break;
1899- case 'f': buf->b_ind_first_open = n; break;
1900- case '{': buf->b_ind_open_extra = n; break;
1901- case '}': buf->b_ind_close_extra = n; break;
1902- case '^': buf->b_ind_open_left_imag = n; break;
1903- case 'L': buf->b_ind_jump_label = n; break;
1904- case ':': buf->b_ind_case = n; break;
1905- case '=': buf->b_ind_case_code = n; break;
1906- case 'b': buf->b_ind_case_break = n; break;
1907- case 'p': buf->b_ind_param = n; break;
1908- case 't': buf->b_ind_func_type = n; break;
1909- case '/': buf->b_ind_comment = n; break;
1910- case 'c': buf->b_ind_in_comment = n; break;
1911- case 'C': buf->b_ind_in_comment2 = n; break;
1912- case 'i': buf->b_ind_cpp_baseclass = n; break;
1913- case '+': buf->b_ind_continuation = n; break;
1914- case '(': buf->b_ind_unclosed = n; break;
1915- case 'u': buf->b_ind_unclosed2 = n; break;
1916- case 'U': buf->b_ind_unclosed_noignore = n; break;
1917- case 'W': buf->b_ind_unclosed_wrapped = n; break;
1918- case 'w': buf->b_ind_unclosed_whiteok = n; break;
1919- case 'm': buf->b_ind_matching_paren = n; break;
1920- case 'M': buf->b_ind_paren_prev = n; break;
1921- case ')': buf->b_ind_maxparen = n; break;
1922- case '*': buf->b_ind_maxcomment = n; break;
1923- case 'g': buf->b_ind_scopedecl = n; break;
1924- case 'h': buf->b_ind_scopedecl_code = n; break;
1925- case 'j': buf->b_ind_java = n; break;
1926- case 'J': buf->b_ind_js = n; break;
1927- case 'l': buf->b_ind_keep_case_label = n; break;
1928- case '#': buf->b_ind_hash_comment = n; break;
1929- case 'N': buf->b_ind_cpp_namespace = n; break;
1930- case 'k': buf->b_ind_if_for_while = n; break;
1931- case 'E': buf->b_ind_cpp_extern_c = n; break;
1932- }
1933- if (*p == ',')
1934- ++p;
1935- }
1936-}
1937-
1938-/*
1939- * Return the desired indent for C code.
1940- * Return -1 if the indent should be left alone (inside a raw string).
1941- */
1942- int
1943-get_c_indent(void)
1944-{
1945- pos_T cur_curpos;
1946- int amount;
1947- int scope_amount;
1948- int cur_amount = MAXCOL;
1949- colnr_T col;
1950- char_u *theline;
1951- char_u *linecopy;
1952- pos_T *trypos;
1953- pos_T *comment_pos;
1954- pos_T *tryposBrace = NULL;
1955- pos_T tryposCopy;
1956- pos_T our_paren_pos;
1957- char_u *start;
1958- int start_brace;
1959-#define BRACE_IN_COL0 1 // '{' is in column 0
1960-#define BRACE_AT_START 2 // '{' is at start of line
1961-#define BRACE_AT_END 3 // '{' is at end of line
1962- linenr_T ourscope;
1963- char_u *l;
1964- char_u *look;
1965- char_u terminated;
1966- int lookfor;
1967-#define LOOKFOR_INITIAL 0
1968-#define LOOKFOR_IF 1
1969-#define LOOKFOR_DO 2
1970-#define LOOKFOR_CASE 3
1971-#define LOOKFOR_ANY 4
1972-#define LOOKFOR_TERM 5
1973-#define LOOKFOR_UNTERM 6
1974-#define LOOKFOR_SCOPEDECL 7
1975-#define LOOKFOR_NOBREAK 8
1976-#define LOOKFOR_CPP_BASECLASS 9
1977-#define LOOKFOR_ENUM_OR_INIT 10
1978-#define LOOKFOR_JS_KEY 11
1979-#define LOOKFOR_COMMA 12
1980-
1981- int whilelevel;
1982- linenr_T lnum;
1983- int n;
1984- int iscase;
1985- int lookfor_break;
1986- int lookfor_cpp_namespace = FALSE;
1987- int cont_amount = 0; // amount for continuation line
1988- int original_line_islabel;
1989- int added_to_amount = 0;
1990- int js_cur_has_key = 0;
1991- linenr_T raw_string_start = 0;
1992- cpp_baseclass_cache_T cache_cpp_baseclass = { FALSE, { MAXLNUM, 0 } };
1993-
1994- // make a copy, value is changed below
1995- int ind_continuation = curbuf->b_ind_continuation;
1996-
1997- // remember where the cursor was when we started
1998- cur_curpos = curwin->w_cursor;
1999-
2000- // if we are at line 1 zero indent is fine, right?
2001- if (cur_curpos.lnum == 1)
2002- return 0;
2003-
2004- // Get a copy of the current contents of the line.
2005- // This is required, because only the most recent line obtained with
2006- // ml_get is valid!
2007- linecopy = vim_strsave(ml_get(cur_curpos.lnum));
2008- if (linecopy == NULL)
2009- return 0;
2010-
2011- // In insert mode and the cursor is on a ')' truncate the line at the
2012- // cursor position. We don't want to line up with the matching '(' when
2013- // inserting new stuff.
2014- // For unknown reasons the cursor might be past the end of the line, thus
2015- // check for that.
2016- if ((State & INSERT)
2017- && curwin->w_cursor.col < (colnr_T)STRLEN(linecopy)
2018- && linecopy[curwin->w_cursor.col] == ')')
2019- linecopy[curwin->w_cursor.col] = NUL;
2020-
2021- theline = skipwhite(linecopy);
2022-
2023- // move the cursor to the start of the line
2024-
2025- curwin->w_cursor.col = 0;
2026-
2027- original_line_islabel = cin_islabel(); // XXX
2028-
2029- // If we are inside a raw string don't change the indent.
2030- // Ignore a raw string inside a comment.
2031- comment_pos = ind_find_start_comment();
2032- if (comment_pos != NULL)
2033- {
2034- // findmatchlimit() static pos is overwritten, make a copy
2035- tryposCopy = *comment_pos;
2036- comment_pos = &tryposCopy;
2037- }
2038- trypos = find_start_rawstring(curbuf->b_ind_maxcomment);
2039- if (trypos != NULL && (comment_pos == NULL
2040- || LT_POS(*trypos, *comment_pos)))
2041- {
2042- amount = -1;
2043- goto laterend;
2044- }
2045-
2046- // #defines and so on always go at the left when included in 'cinkeys'.
2047- if (*theline == '#' && (*linecopy == '#' || in_cinkeys('#', ' ', TRUE)))
2048- {
2049- amount = curbuf->b_ind_hash_comment;
2050- goto theend;
2051- }
2052-
2053- // Is it a non-case label? Then that goes at the left margin too unless:
2054- // - JS flag is set.
2055- // - 'L' item has a positive value.
2056- if (original_line_islabel && !curbuf->b_ind_js
2057- && curbuf->b_ind_jump_label < 0)
2058- {
2059- amount = 0;
2060- goto theend;
2061- }
2062-
2063- // If we're inside a "//" comment and there is a "//" comment in a
2064- // previous line, lineup with that one.
2065- if (cin_islinecomment(theline)
2066- && (trypos = find_line_comment()) != NULL) // XXX
2067- {
2068- // find how indented the line beginning the comment is
2069- getvcol(curwin, trypos, &col, NULL, NULL);
2070- amount = col;
2071- goto theend;
2072- }
2073-
2074- // If we're inside a comment and not looking at the start of the
2075- // comment, try using the 'comments' option.
2076- if (!cin_iscomment(theline) && comment_pos != NULL) // XXX
2077- {
2078- int lead_start_len = 2;
2079- int lead_middle_len = 1;
2080- char_u lead_start[COM_MAX_LEN]; // start-comment string
2081- char_u lead_middle[COM_MAX_LEN]; // middle-comment string
2082- char_u lead_end[COM_MAX_LEN]; // end-comment string
2083- char_u *p;
2084- int start_align = 0;
2085- int start_off = 0;
2086- int done = FALSE;
2087-
2088- // find how indented the line beginning the comment is
2089- getvcol(curwin, comment_pos, &col, NULL, NULL);
2090- amount = col;
2091- *lead_start = NUL;
2092- *lead_middle = NUL;
2093-
2094- p = curbuf->b_p_com;
2095- while (*p != NUL)
2096- {
2097- int align = 0;
2098- int off = 0;
2099- int what = 0;
2100-
2101- while (*p != NUL && *p != ':')
2102- {
2103- if (*p == COM_START || *p == COM_END || *p == COM_MIDDLE)
2104- what = *p++;
2105- else if (*p == COM_LEFT || *p == COM_RIGHT)
2106- align = *p++;
2107- else if (VIM_ISDIGIT(*p) || *p == '-')
2108- off = getdigits(&p);
2109- else
2110- ++p;
2111- }
2112-
2113- if (*p == ':')
2114- ++p;
2115- (void)copy_option_part(&p, lead_end, COM_MAX_LEN, ",");
2116- if (what == COM_START)
2117- {
2118- STRCPY(lead_start, lead_end);
2119- lead_start_len = (int)STRLEN(lead_start);
2120- start_off = off;
2121- start_align = align;
2122- }
2123- else if (what == COM_MIDDLE)
2124- {
2125- STRCPY(lead_middle, lead_end);
2126- lead_middle_len = (int)STRLEN(lead_middle);
2127- }
2128- else if (what == COM_END)
2129- {
2130- // If our line starts with the middle comment string, line it
2131- // up with the comment opener per the 'comments' option.
2132- if (STRNCMP(theline, lead_middle, lead_middle_len) == 0
2133- && STRNCMP(theline, lead_end, STRLEN(lead_end)) != 0)
2134- {
2135- done = TRUE;
2136- if (curwin->w_cursor.lnum > 1)
2137- {
2138- // If the start comment string matches in the previous
2139- // line, use the indent of that line plus offset. If
2140- // the middle comment string matches in the previous
2141- // line, use the indent of that line. XXX
2142- look = skipwhite(ml_get(curwin->w_cursor.lnum - 1));
2143- if (STRNCMP(look, lead_start, lead_start_len) == 0)
2144- amount = get_indent_lnum(curwin->w_cursor.lnum - 1);
2145- else if (STRNCMP(look, lead_middle,
2146- lead_middle_len) == 0)
2147- {
2148- amount = get_indent_lnum(curwin->w_cursor.lnum - 1);
2149- break;
2150- }
2151- // If the start comment string doesn't match with the
2152- // start of the comment, skip this entry. XXX
2153- else if (STRNCMP(ml_get(comment_pos->lnum) + comment_pos->col,
2154- lead_start, lead_start_len) != 0)
2155- continue;
2156- }
2157- if (start_off != 0)
2158- amount += start_off;
2159- else if (start_align == COM_RIGHT)
2160- amount += vim_strsize(lead_start)
2161- - vim_strsize(lead_middle);
2162- break;
2163- }
2164-
2165- // If our line starts with the end comment string, line it up
2166- // with the middle comment
2167- if (STRNCMP(theline, lead_middle, lead_middle_len) != 0
2168- && STRNCMP(theline, lead_end, STRLEN(lead_end)) == 0)
2169- {
2170- amount = get_indent_lnum(curwin->w_cursor.lnum - 1);
2171- // XXX
2172- if (off != 0)
2173- amount += off;
2174- else if (align == COM_RIGHT)
2175- amount += vim_strsize(lead_start)
2176- - vim_strsize(lead_middle);
2177- done = TRUE;
2178- break;
2179- }
2180- }
2181- }
2182-
2183- // If our line starts with an asterisk, line up with the
2184- // asterisk in the comment opener; otherwise, line up
2185- // with the first character of the comment text.
2186- if (done)
2187- ;
2188- else if (theline[0] == '*')
2189- amount += 1;
2190- else
2191- {
2192- // If we are more than one line away from the comment opener, take
2193- // the indent of the previous non-empty line. If 'cino' has "CO"
2194- // and we are just below the comment opener and there are any
2195- // white characters after it line up with the text after it;
2196- // otherwise, add the amount specified by "c" in 'cino'
2197- amount = -1;
2198- for (lnum = cur_curpos.lnum - 1; lnum > comment_pos->lnum; --lnum)
2199- {
2200- if (linewhite(lnum)) // skip blank lines
2201- continue;
2202- amount = get_indent_lnum(lnum); // XXX
2203- break;
2204- }
2205- if (amount == -1) // use the comment opener
2206- {
2207- if (!curbuf->b_ind_in_comment2)
2208- {
2209- start = ml_get(comment_pos->lnum);
2210- look = start + comment_pos->col + 2; // skip / and *
2211- if (*look != NUL) // if something after it
2212- comment_pos->col = (colnr_T)(skipwhite(look) - start);
2213- }
2214- getvcol(curwin, comment_pos, &col, NULL, NULL);
2215- amount = col;
2216- if (curbuf->b_ind_in_comment2 || *look == NUL)
2217- amount += curbuf->b_ind_in_comment;
2218- }
2219- }
2220- goto theend;
2221- }
2222-
2223- // Are we looking at a ']' that has a match?
2224- if (*skipwhite(theline) == ']'
2225- && (trypos = find_match_char('[', curbuf->b_ind_maxparen)) != NULL)
2226- {
2227- // align with the line containing the '['.
2228- amount = get_indent_lnum(trypos->lnum);
2229- goto theend;
2230- }
2231-
2232- // Are we inside parentheses or braces? XXX
2233- if (((trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL
2234- && curbuf->b_ind_java == 0)
2235- || (tryposBrace = find_start_brace()) != NULL
2236- || trypos != NULL)
2237- {
2238- if (trypos != NULL && tryposBrace != NULL)
2239- {
2240- // Both an unmatched '(' and '{' is found. Use the one which is
2241- // closer to the current cursor position, set the other to NULL.
2242- if (trypos->lnum != tryposBrace->lnum
2243- ? trypos->lnum < tryposBrace->lnum
2244- : trypos->col < tryposBrace->col)
2245- trypos = NULL;
2246- else
2247- tryposBrace = NULL;
2248- }
2249-
2250- if (trypos != NULL)
2251- {
2252- // If the matching paren is more than one line away, use the indent of
2253- // a previous non-empty line that matches the same paren.
2254- if (theline[0] == ')' && curbuf->b_ind_paren_prev)
2255- {
2256- // Line up with the start of the matching paren line.
2257- amount = get_indent_lnum(curwin->w_cursor.lnum - 1); // XXX
2258- }
2259- else
2260- {
2261- amount = -1;
2262- our_paren_pos = *trypos;
2263- for (lnum = cur_curpos.lnum - 1; lnum > our_paren_pos.lnum; --lnum)
2264- {
2265- l = skipwhite(ml_get(lnum));
2266- if (cin_nocode(l)) // skip comment lines
2267- continue;
2268- if (cin_ispreproc_cont(&l, &lnum, &amount))
2269- continue; // ignore #define, #if, etc.
2270- curwin->w_cursor.lnum = lnum;
2271-
2272- // Skip a comment or raw string. XXX
2273- if ((trypos = ind_find_start_CORS(NULL)) != NULL)
2274- {
2275- lnum = trypos->lnum + 1;
2276- continue;
2277- }
2278-
2279- // XXX
2280- if ((trypos = find_match_paren(
2281- corr_ind_maxparen(&cur_curpos))) != NULL
2282- && trypos->lnum == our_paren_pos.lnum
2283- && trypos->col == our_paren_pos.col)
2284- {
2285- amount = get_indent_lnum(lnum); // XXX
2286-
2287- if (theline[0] == ')')
2288- {
2289- if (our_paren_pos.lnum != lnum
2290- && cur_amount > amount)
2291- cur_amount = amount;
2292- amount = -1;
2293- }
2294- break;
2295- }
2296- }
2297- }
2298-
2299- // Line up with line where the matching paren is. XXX
2300- // If the line starts with a '(' or the indent for unclosed
2301- // parentheses is zero, line up with the unclosed parentheses.
2302- if (amount == -1)
2303- {
2304- int ignore_paren_col = 0;
2305- int is_if_for_while = 0;
2306-
2307- if (curbuf->b_ind_if_for_while)
2308- {
2309- // Look for the outermost opening parenthesis on this line
2310- // and check whether it belongs to an "if", "for" or "while".
2311-
2312- pos_T cursor_save = curwin->w_cursor;
2313- pos_T outermost;
2314- char_u *line;
2315-
2316- trypos = &our_paren_pos;
2317- do {
2318- outermost = *trypos;
2319- curwin->w_cursor.lnum = outermost.lnum;
2320- curwin->w_cursor.col = outermost.col;
2321-
2322- trypos = find_match_paren(curbuf->b_ind_maxparen);
2323- } while (trypos && trypos->lnum == outermost.lnum);
2324-
2325- curwin->w_cursor = cursor_save;
2326-
2327- line = ml_get(outermost.lnum);
2328-
2329- is_if_for_while =
2330- cin_is_if_for_while_before_offset(line, &outermost.col);
2331- }
2332-
2333- amount = skip_label(our_paren_pos.lnum, &look);
2334- look = skipwhite(look);
2335- if (*look == '(')
2336- {
2337- linenr_T save_lnum = curwin->w_cursor.lnum;
2338- char_u *line;
2339- int look_col;
2340-
2341- // Ignore a '(' in front of the line that has a match before
2342- // our matching '('.
2343- curwin->w_cursor.lnum = our_paren_pos.lnum;
2344- line = ml_get_curline();
2345- look_col = (int)(look - line);
2346- curwin->w_cursor.col = look_col + 1;
2347- if ((trypos = findmatchlimit(NULL, ')', 0,
2348- curbuf->b_ind_maxparen))
2349- != NULL
2350- && trypos->lnum == our_paren_pos.lnum
2351- && trypos->col < our_paren_pos.col)
2352- ignore_paren_col = trypos->col + 1;
2353-
2354- curwin->w_cursor.lnum = save_lnum;
2355- look = ml_get(our_paren_pos.lnum) + look_col;
2356- }
2357- if (theline[0] == ')' || (curbuf->b_ind_unclosed == 0
2358- && is_if_for_while == 0)
2359- || (!curbuf->b_ind_unclosed_noignore && *look == '('
2360- && ignore_paren_col == 0))
2361- {
2362- // If we're looking at a close paren, line up right there;
2363- // otherwise, line up with the next (non-white) character.
2364- // When b_ind_unclosed_wrapped is set and the matching paren is
2365- // the last nonwhite character of the line, use either the
2366- // indent of the current line or the indentation of the next
2367- // outer paren and add b_ind_unclosed_wrapped (for very long
2368- // lines).
2369- if (theline[0] != ')')
2370- {
2371- cur_amount = MAXCOL;
2372- l = ml_get(our_paren_pos.lnum);
2373- if (curbuf->b_ind_unclosed_wrapped
2374- && cin_ends_in(l, (char_u *)"(", NULL))
2375- {
2376- // look for opening unmatched paren, indent one level
2377- // for each additional level
2378- n = 1;
2379- for (col = 0; col < our_paren_pos.col; ++col)
2380- {
2381- switch (l[col])
2382- {
2383- case '(':
2384- case '{': ++n;
2385- break;
2386-
2387- case ')':
2388- case '}': if (n > 1)
2389- --n;
2390- break;
2391- }
2392- }
2393-
2394- our_paren_pos.col = 0;
2395- amount += n * curbuf->b_ind_unclosed_wrapped;
2396- }
2397- else if (curbuf->b_ind_unclosed_whiteok)
2398- our_paren_pos.col++;
2399- else
2400- {
2401- col = our_paren_pos.col + 1;
2402- while (VIM_ISWHITE(l[col]))
2403- col++;
2404- if (l[col] != NUL) // In case of trailing space
2405- our_paren_pos.col = col;
2406- else
2407- our_paren_pos.col++;
2408- }
2409- }
2410-
2411- // Find how indented the paren is, or the character after it
2412- // if we did the above "if".
2413- if (our_paren_pos.col > 0)
2414- {
2415- getvcol(curwin, &our_paren_pos, &col, NULL, NULL);
2416- if (cur_amount > (int)col)
2417- cur_amount = col;
2418- }
2419- }
2420-
2421- if (theline[0] == ')' && curbuf->b_ind_matching_paren)
2422- {
2423- // Line up with the start of the matching paren line.
2424- }
2425- else if ((curbuf->b_ind_unclosed == 0 && is_if_for_while == 0)
2426- || (!curbuf->b_ind_unclosed_noignore
2427- && *look == '(' && ignore_paren_col == 0))
2428- {
2429- if (cur_amount != MAXCOL)
2430- amount = cur_amount;
2431- }
2432- else
2433- {
2434- // Add b_ind_unclosed2 for each '(' before our matching one,
2435- // but ignore (void) before the line (ignore_paren_col).
2436- col = our_paren_pos.col;
2437- while ((int)our_paren_pos.col > ignore_paren_col)
2438- {
2439- --our_paren_pos.col;
2440- switch (*ml_get_pos(&our_paren_pos))
2441- {
2442- case '(': amount += curbuf->b_ind_unclosed2;
2443- col = our_paren_pos.col;
2444- break;
2445- case ')': amount -= curbuf->b_ind_unclosed2;
2446- col = MAXCOL;
2447- break;
2448- }
2449- }
2450-
2451- // Use b_ind_unclosed once, when the first '(' is not inside
2452- // braces
2453- if (col == MAXCOL)
2454- amount += curbuf->b_ind_unclosed;
2455- else
2456- {
2457- curwin->w_cursor.lnum = our_paren_pos.lnum;
2458- curwin->w_cursor.col = col;
2459- if (find_match_paren_after_brace(curbuf->b_ind_maxparen)
2460- != NULL)
2461- amount += curbuf->b_ind_unclosed2;
2462- else
2463- {
2464- if (is_if_for_while)
2465- amount += curbuf->b_ind_if_for_while;
2466- else
2467- amount += curbuf->b_ind_unclosed;
2468- }
2469- }
2470- // For a line starting with ')' use the minimum of the two
2471- // positions, to avoid giving it more indent than the previous
2472- // lines:
2473- // func_long_name( if (x
2474- // arg && yy
2475- // ) ^ not here ) ^ not here
2476- if (cur_amount < amount)
2477- amount = cur_amount;
2478- }
2479- }
2480-
2481- // add extra indent for a comment
2482- if (cin_iscomment(theline))
2483- amount += curbuf->b_ind_comment;
2484- }
2485- else
2486- {
2487- // We are inside braces, there is a { before this line at the position
2488- // stored in tryposBrace.
2489- // Make a copy of tryposBrace, it may point to pos_copy inside
2490- // find_start_brace(), which may be changed somewhere.
2491- tryposCopy = *tryposBrace;
2492- tryposBrace = &tryposCopy;
2493- trypos = tryposBrace;
2494- ourscope = trypos->lnum;
2495- start = ml_get(ourscope);
2496-
2497- // Now figure out how indented the line is in general.
2498- // If the brace was at the start of the line, we use that;
2499- // otherwise, check out the indentation of the line as
2500- // a whole and then add the "imaginary indent" to that.
2501- look = skipwhite(start);
2502- if (*look == '{')
2503- {
2504- getvcol(curwin, trypos, &col, NULL, NULL);
2505- amount = col;
2506- if (*start == '{')
2507- start_brace = BRACE_IN_COL0;
2508- else
2509- start_brace = BRACE_AT_START;
2510- }
2511- else
2512- {
2513- // That opening brace might have been on a continuation
2514- // line. if so, find the start of the line.
2515- curwin->w_cursor.lnum = ourscope;
2516-
2517- // Position the cursor over the rightmost paren, so that
2518- // matching it will take us back to the start of the line.
2519- lnum = ourscope;
2520- if (find_last_paren(start, '(', ')')
2521- && (trypos = find_match_paren(curbuf->b_ind_maxparen))
2522- != NULL)
2523- lnum = trypos->lnum;
2524-
2525- // It could have been something like
2526- // case 1: if (asdf &&
2527- // ldfd) {
2528- // }
2529- if ((curbuf->b_ind_js || curbuf->b_ind_keep_case_label)
2530- && cin_iscase(skipwhite(ml_get_curline()), FALSE))
2531- amount = get_indent();
2532- else if (curbuf->b_ind_js)
2533- amount = get_indent_lnum(lnum);
2534- else
2535- amount = skip_label(lnum, &l);
2536-
2537- start_brace = BRACE_AT_END;
2538- }
2539-
2540- // For Javascript check if the line starts with "key:".
2541- if (curbuf->b_ind_js)
2542- js_cur_has_key = cin_has_js_key(theline);
2543-
2544- // If we're looking at a closing brace, that's where
2545- // we want to be. otherwise, add the amount of room
2546- // that an indent is supposed to be.
2547- if (theline[0] == '}')
2548- {
2549- // they may want closing braces to line up with something
2550- // other than the open brace. indulge them, if so.
2551- amount += curbuf->b_ind_close_extra;
2552- }
2553- else
2554- {
2555- // If we're looking at an "else", try to find an "if"
2556- // to match it with.
2557- // If we're looking at a "while", try to find a "do"
2558- // to match it with.
2559- lookfor = LOOKFOR_INITIAL;
2560- if (cin_iselse(theline))
2561- lookfor = LOOKFOR_IF;
2562- else if (cin_iswhileofdo(theline, cur_curpos.lnum)) // XXX
2563- lookfor = LOOKFOR_DO;
2564- if (lookfor != LOOKFOR_INITIAL)
2565- {
2566- curwin->w_cursor.lnum = cur_curpos.lnum;
2567- if (find_match(lookfor, ourscope) == OK)
2568- {
2569- amount = get_indent(); // XXX
2570- goto theend;
2571- }
2572- }
2573-
2574- // We get here if we are not on an "while-of-do" or "else" (or
2575- // failed to find a matching "if").
2576- // Search backwards for something to line up with.
2577- // First set amount for when we don't find anything.
2578-
2579- // if the '{' is _really_ at the left margin, use the imaginary
2580- // location of a left-margin brace. Otherwise, correct the
2581- // location for b_ind_open_extra.
2582-
2583- if (start_brace == BRACE_IN_COL0) // '{' is in column 0
2584- {
2585- amount = curbuf->b_ind_open_left_imag;
2586- lookfor_cpp_namespace = TRUE;
2587- }
2588- else if (start_brace == BRACE_AT_START &&
2589- lookfor_cpp_namespace) // '{' is at start
2590- {
2591-
2592- lookfor_cpp_namespace = TRUE;
2593- }
2594- else
2595- {
2596- if (start_brace == BRACE_AT_END) // '{' is at end of line
2597- {
2598- amount += curbuf->b_ind_open_imag;
2599-
2600- l = skipwhite(ml_get_curline());
2601- if (cin_is_cpp_namespace(l))
2602- amount += curbuf->b_ind_cpp_namespace;
2603- else if (cin_is_cpp_extern_c(l))
2604- amount += curbuf->b_ind_cpp_extern_c;
2605- }
2606- else
2607- {
2608- // Compensate for adding b_ind_open_extra later.
2609- amount -= curbuf->b_ind_open_extra;
2610- if (amount < 0)
2611- amount = 0;
2612- }
2613- }
2614-
2615- lookfor_break = FALSE;
2616-
2617- if (cin_iscase(theline, FALSE)) // it's a switch() label
2618- {
2619- lookfor = LOOKFOR_CASE; // find a previous switch() label
2620- amount += curbuf->b_ind_case;
2621- }
2622- else if (cin_isscopedecl(theline)) // private:, ...
2623- {
2624- lookfor = LOOKFOR_SCOPEDECL; // class decl is this block
2625- amount += curbuf->b_ind_scopedecl;
2626- }
2627- else
2628- {
2629- if (curbuf->b_ind_case_break && cin_isbreak(theline))
2630- // break; ...
2631- lookfor_break = TRUE;
2632-
2633- lookfor = LOOKFOR_INITIAL;
2634- // b_ind_level from start of block
2635- amount += curbuf->b_ind_level;
2636- }
2637- scope_amount = amount;
2638- whilelevel = 0;
2639-
2640- // Search backwards. If we find something we recognize, line up
2641- // with that.
2642- //
2643- // If we're looking at an open brace, indent
2644- // the usual amount relative to the conditional
2645- // that opens the block.
2646- curwin->w_cursor = cur_curpos;
2647- for (;;)
2648- {
2649- curwin->w_cursor.lnum--;
2650- curwin->w_cursor.col = 0;
2651-
2652- // If we went all the way back to the start of our scope, line
2653- // up with it.
2654- if (curwin->w_cursor.lnum <= ourscope)
2655- {
2656- // We reached end of scope:
2657- // If looking for a enum or structure initialization
2658- // go further back:
2659- // If it is an initializer (enum xxx or xxx =), then
2660- // don't add ind_continuation, otherwise it is a variable
2661- // declaration:
2662- // int x,
2663- // here; <-- add ind_continuation
2664- if (lookfor == LOOKFOR_ENUM_OR_INIT)
2665- {
2666- if (curwin->w_cursor.lnum == 0
2667- || curwin->w_cursor.lnum
2668- < ourscope - curbuf->b_ind_maxparen)
2669- {
2670- // nothing found (abuse curbuf->b_ind_maxparen as
2671- // limit) assume terminated line (i.e. a variable
2672- // initialization)
2673- if (cont_amount > 0)
2674- amount = cont_amount;
2675- else if (!curbuf->b_ind_js)
2676- amount += ind_continuation;
2677- break;
2678- }
2679-
2680- l = ml_get_curline();
2681-
2682- // If we're in a comment or raw string now, skip to
2683- // the start of it.
2684- trypos = ind_find_start_CORS(NULL);
2685- if (trypos != NULL)
2686- {
2687- curwin->w_cursor.lnum = trypos->lnum + 1;
2688- curwin->w_cursor.col = 0;
2689- continue;
2690- }
2691-
2692- // Skip preprocessor directives and blank lines.
2693- if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum,
2694- &amount))
2695- continue;
2696-
2697- if (cin_nocode(l))
2698- continue;
2699-
2700- terminated = cin_isterminated(l, FALSE, TRUE);
2701-
2702- // If we are at top level and the line looks like a
2703- // function declaration, we are done
2704- // (it's a variable declaration).
2705- if (start_brace != BRACE_IN_COL0
2706- || !cin_isfuncdecl(&l, curwin->w_cursor.lnum, 0))
2707- {
2708- // if the line is terminated with another ','
2709- // it is a continued variable initialization.
2710- // don't add extra indent.
2711- // TODO: does not work, if a function
2712- // declaration is split over multiple lines:
2713- // cin_isfuncdecl returns FALSE then.
2714- if (terminated == ',')
2715- break;
2716-
2717- // if it es a enum declaration or an assignment,
2718- // we are done.
2719- if (terminated != ';' && cin_isinit())
2720- break;
2721-
2722- // nothing useful found
2723- if (terminated == 0 || terminated == '{')
2724- continue;
2725- }
2726-
2727- if (terminated != ';')
2728- {
2729- // Skip parens and braces. Position the cursor
2730- // over the rightmost paren, so that matching it
2731- // will take us back to the start of the line.
2732- // XXX
2733- trypos = NULL;
2734- if (find_last_paren(l, '(', ')'))
2735- trypos = find_match_paren(
2736- curbuf->b_ind_maxparen);
2737-
2738- if (trypos == NULL && find_last_paren(l, '{', '}'))
2739- trypos = find_start_brace();
2740-
2741- if (trypos != NULL)
2742- {
2743- curwin->w_cursor.lnum = trypos->lnum + 1;
2744- curwin->w_cursor.col = 0;
2745- continue;
2746- }
2747- }
2748-
2749- // it's a variable declaration, add indentation
2750- // like in
2751- // int a,
2752- // b;
2753- if (cont_amount > 0)
2754- amount = cont_amount;
2755- else
2756- amount += ind_continuation;
2757- }
2758- else if (lookfor == LOOKFOR_UNTERM)
2759- {
2760- if (cont_amount > 0)
2761- amount = cont_amount;
2762- else
2763- amount += ind_continuation;
2764- }
2765- else
2766- {
2767- if (lookfor != LOOKFOR_TERM
2768- && lookfor != LOOKFOR_CPP_BASECLASS
2769- && lookfor != LOOKFOR_COMMA)
2770- {
2771- amount = scope_amount;
2772- if (theline[0] == '{')
2773- {
2774- amount += curbuf->b_ind_open_extra;
2775- added_to_amount = curbuf->b_ind_open_extra;
2776- }
2777- }
2778-
2779- if (lookfor_cpp_namespace)
2780- {
2781- // Looking for C++ namespace, need to look further
2782- // back.
2783- if (curwin->w_cursor.lnum == ourscope)
2784- continue;
2785-
2786- if (curwin->w_cursor.lnum == 0
2787- || curwin->w_cursor.lnum
2788- < ourscope - FIND_NAMESPACE_LIM)
2789- break;
2790-
2791- l = ml_get_curline();
2792-
2793- // If we're in a comment or raw string now, skip
2794- // to the start of it.
2795- trypos = ind_find_start_CORS(NULL);
2796- if (trypos != NULL)
2797- {
2798- curwin->w_cursor.lnum = trypos->lnum + 1;
2799- curwin->w_cursor.col = 0;
2800- continue;
2801- }
2802-
2803- // Skip preprocessor directives and blank lines.
2804- if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum,
2805- &amount))
2806- continue;
2807-
2808- // Finally the actual check for "namespace".
2809- if (cin_is_cpp_namespace(l))
2810- {
2811- amount += curbuf->b_ind_cpp_namespace
2812- - added_to_amount;
2813- break;
2814- }
2815- else if (cin_is_cpp_extern_c(l))
2816- {
2817- amount += curbuf->b_ind_cpp_extern_c
2818- - added_to_amount;
2819- break;
2820- }
2821-
2822- if (cin_nocode(l))
2823- continue;
2824- }
2825- }
2826- break;
2827- }
2828-
2829- // If we're in a comment or raw string now, skip to the start
2830- // of it. XXX
2831- if ((trypos = ind_find_start_CORS(&raw_string_start)) != NULL)
2832- {
2833- curwin->w_cursor.lnum = trypos->lnum + 1;
2834- curwin->w_cursor.col = 0;
2835- continue;
2836- }
2837-
2838- l = ml_get_curline();
2839-
2840- // If this is a switch() label, may line up relative to that.
2841- // If this is a C++ scope declaration, do the same.
2842- iscase = cin_iscase(l, FALSE);
2843- if (iscase || cin_isscopedecl(l))
2844- {
2845- // we are only looking for cpp base class
2846- // declaration/initialization any longer
2847- if (lookfor == LOOKFOR_CPP_BASECLASS)
2848- break;
2849-
2850- // When looking for a "do" we are not interested in
2851- // labels.
2852- if (whilelevel > 0)
2853- continue;
2854-
2855- // case xx:
2856- // c = 99 + <- this indent plus continuation
2857- //-> here;
2858- if (lookfor == LOOKFOR_UNTERM
2859- || lookfor == LOOKFOR_ENUM_OR_INIT)
2860- {
2861- if (cont_amount > 0)
2862- amount = cont_amount;
2863- else
2864- amount += ind_continuation;
2865- break;
2866- }
2867-
2868- // case xx: <- line up with this case
2869- // x = 333;
2870- // case yy:
2871- if ( (iscase && lookfor == LOOKFOR_CASE)
2872- || (iscase && lookfor_break)
2873- || (!iscase && lookfor == LOOKFOR_SCOPEDECL))
2874- {
2875- // Check that this case label is not for another
2876- // switch() XXX
2877- if ((trypos = find_start_brace()) == NULL
2878- || trypos->lnum == ourscope)
2879- {
2880- amount = get_indent(); // XXX
2881- break;
2882- }
2883- continue;
2884- }
2885-
2886- n = get_indent_nolabel(curwin->w_cursor.lnum); // XXX
2887-
2888- // case xx: if (cond) <- line up with this if
2889- // y = y + 1;
2890- // -> s = 99;
2891- //
2892- // case xx:
2893- // if (cond) <- line up with this line
2894- // y = y + 1;
2895- // -> s = 99;
2896- if (lookfor == LOOKFOR_TERM)
2897- {
2898- if (n)
2899- amount = n;
2900-
2901- if (!lookfor_break)
2902- break;
2903- }
2904-
2905- // case xx: x = x + 1; <- line up with this x
2906- // -> y = y + 1;
2907- //
2908- // case xx: if (cond) <- line up with this if
2909- // -> y = y + 1;
2910- if (n)
2911- {
2912- amount = n;
2913- l = after_label(ml_get_curline());
2914- if (l != NULL && cin_is_cinword(l))
2915- {
2916- if (theline[0] == '{')
2917- amount += curbuf->b_ind_open_extra;
2918- else
2919- amount += curbuf->b_ind_level
2920- + curbuf->b_ind_no_brace;
2921- }
2922- break;
2923- }
2924-
2925- // Try to get the indent of a statement before the switch
2926- // label. If nothing is found, line up relative to the
2927- // switch label.
2928- // break; <- may line up with this line
2929- // case xx:
2930- // -> y = 1;
2931- scope_amount = get_indent() + (iscase // XXX
2932- ? curbuf->b_ind_case_code
2933- : curbuf->b_ind_scopedecl_code);
2934- lookfor = curbuf->b_ind_case_break
2935- ? LOOKFOR_NOBREAK : LOOKFOR_ANY;
2936- continue;
2937- }
2938-
2939- // Looking for a switch() label or C++ scope declaration,
2940- // ignore other lines, skip {}-blocks.
2941- if (lookfor == LOOKFOR_CASE || lookfor == LOOKFOR_SCOPEDECL)
2942- {
2943- if (find_last_paren(l, '{', '}')
2944- && (trypos = find_start_brace()) != NULL)
2945- {
2946- curwin->w_cursor.lnum = trypos->lnum + 1;
2947- curwin->w_cursor.col = 0;
2948- }
2949- continue;
2950- }
2951-
2952- // Ignore jump labels with nothing after them.
2953- if (!curbuf->b_ind_js && cin_islabel())
2954- {
2955- l = after_label(ml_get_curline());
2956- if (l == NULL || cin_nocode(l))
2957- continue;
2958- }
2959-
2960- // Ignore #defines, #if, etc.
2961- // Ignore comment and empty lines.
2962- // (need to get the line again, cin_islabel() may have
2963- // unlocked it)
2964- l = ml_get_curline();
2965- if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum, &amount)
2966- || cin_nocode(l))
2967- continue;
2968-
2969- // Are we at the start of a cpp base class declaration or
2970- // constructor initialization? XXX
2971- n = FALSE;
2972- if (lookfor != LOOKFOR_TERM && curbuf->b_ind_cpp_baseclass > 0)
2973- {
2974- n = cin_is_cpp_baseclass(&cache_cpp_baseclass);
2975- l = ml_get_curline();
2976- }
2977- if (n)
2978- {
2979- if (lookfor == LOOKFOR_UNTERM)
2980- {
2981- if (cont_amount > 0)
2982- amount = cont_amount;
2983- else
2984- amount += ind_continuation;
2985- }
2986- else if (theline[0] == '{')
2987- {
2988- // Need to find start of the declaration.
2989- lookfor = LOOKFOR_UNTERM;
2990- ind_continuation = 0;
2991- continue;
2992- }
2993- else
2994- // XXX
2995- amount = get_baseclass_amount(
2996- cache_cpp_baseclass.lpos.col);
2997- break;
2998- }
2999- else if (lookfor == LOOKFOR_CPP_BASECLASS)
3000- {
3001- // only look, whether there is a cpp base class
3002- // declaration or initialization before the opening brace.
3003- if (cin_isterminated(l, TRUE, FALSE))
3004- break;
3005- else
3006- continue;
3007- }
3008-
3009- // What happens next depends on the line being terminated.
3010- // If terminated with a ',' only consider it terminating if
3011- // there is another unterminated statement behind, eg:
3012- // 123,
3013- // sizeof
3014- // here
3015- // Otherwise check whether it is a enumeration or structure
3016- // initialisation (not indented) or a variable declaration
3017- // (indented).
3018- terminated = cin_isterminated(l, FALSE, TRUE);
3019-
3020- if (js_cur_has_key)
3021- {
3022- js_cur_has_key = 0; // only check the first line
3023- if (curbuf->b_ind_js && terminated == ',')
3024- {
3025- // For Javascript we might be inside an object:
3026- // key: something, <- align with this
3027- // key: something
3028- // or:
3029- // key: something + <- align with this
3030- // something,
3031- // key: something
3032- lookfor = LOOKFOR_JS_KEY;
3033- }
3034- }
3035- if (lookfor == LOOKFOR_JS_KEY && cin_has_js_key(l))
3036- {
3037- amount = get_indent();
3038- break;
3039- }
3040- if (lookfor == LOOKFOR_COMMA)
3041- {
3042- if (tryposBrace != NULL && tryposBrace->lnum
3043- >= curwin->w_cursor.lnum)
3044- break;
3045- if (terminated == ',')
3046- // line below current line is the one that starts a
3047- // (possibly broken) line ending in a comma.
3048- break;
3049- else
3050- {
3051- amount = get_indent();
3052- if (curwin->w_cursor.lnum - 1 == ourscope)
3053- // line above is start of the scope, thus current
3054- // line is the one that stars a (possibly broken)
3055- // line ending in a comma.
3056- break;
3057- }
3058- }
3059-
3060- if (terminated == 0 || (lookfor != LOOKFOR_UNTERM
3061- && terminated == ','))
3062- {
3063- if (lookfor != LOOKFOR_ENUM_OR_INIT &&
3064- (*skipwhite(l) == '[' || l[STRLEN(l) - 1] == '['))
3065- amount += ind_continuation;
3066- // if we're in the middle of a paren thing,
3067- // go back to the line that starts it so
3068- // we can get the right prevailing indent
3069- // if ( foo &&
3070- // bar )
3071-
3072- // Position the cursor over the rightmost paren, so that
3073- // matching it will take us back to the start of the line.
3074- // Ignore a match before the start of the block.
3075- (void)find_last_paren(l, '(', ')');
3076- trypos = find_match_paren(corr_ind_maxparen(&cur_curpos));
3077- if (trypos != NULL && (trypos->lnum < tryposBrace->lnum
3078- || (trypos->lnum == tryposBrace->lnum
3079- && trypos->col < tryposBrace->col)))
3080- trypos = NULL;
3081-
3082- // If we are looking for ',', we also look for matching
3083- // braces.
3084- if (trypos == NULL && terminated == ','
3085- && find_last_paren(l, '{', '}'))
3086- trypos = find_start_brace();
3087-
3088- if (trypos != NULL)
3089- {
3090- // Check if we are on a case label now. This is
3091- // handled above.
3092- // case xx: if ( asdf &&
3093- // asdf)
3094- curwin->w_cursor = *trypos;
3095- l = ml_get_curline();
3096- if (cin_iscase(l, FALSE) || cin_isscopedecl(l))
3097- {
3098- ++curwin->w_cursor.lnum;
3099- curwin->w_cursor.col = 0;
3100- continue;
3101- }
3102- }
3103-
3104- /*
3105- * Skip over continuation lines to find the one to get the
3106- * indent from
3107- * char *usethis = "bla\
3108- * bla",
3109- * here;
3110- */
3111- if (terminated == ',')
3112- {
3113- while (curwin->w_cursor.lnum > 1)
3114- {
3115- l = ml_get(curwin->w_cursor.lnum - 1);
3116- if (*l == NUL || l[STRLEN(l) - 1] != '\\')
3117- break;
3118- --curwin->w_cursor.lnum;
3119- curwin->w_cursor.col = 0;
3120- }
3121- }
3122-
3123- // Get indent and pointer to text for current line,
3124- // ignoring any jump label. XXX
3125- if (curbuf->b_ind_js)
3126- cur_amount = get_indent();
3127- else
3128- cur_amount = skip_label(curwin->w_cursor.lnum, &l);
3129- // If this is just above the line we are indenting, and it
3130- // starts with a '{', line it up with this line.
3131- // while (not)
3132- // -> {
3133- // }
3134- if (terminated != ',' && lookfor != LOOKFOR_TERM
3135- && theline[0] == '{')
3136- {
3137- amount = cur_amount;
3138- // Only add b_ind_open_extra when the current line
3139- // doesn't start with a '{', which must have a match
3140- // in the same line (scope is the same). Probably:
3141- // { 1, 2 },
3142- // -> { 3, 4 }
3143- if (*skipwhite(l) != '{')
3144- amount += curbuf->b_ind_open_extra;
3145-
3146- if (curbuf->b_ind_cpp_baseclass && !curbuf->b_ind_js)
3147- {
3148- // have to look back, whether it is a cpp base
3149- // class declaration or initialization
3150- lookfor = LOOKFOR_CPP_BASECLASS;
3151- continue;
3152- }
3153- break;
3154- }
3155-
3156- // Check if we are after an "if", "while", etc.
3157- // Also allow " } else".
3158- if (cin_is_cinword(l) || cin_iselse(skipwhite(l)))
3159- {
3160- // Found an unterminated line after an if (), line up
3161- // with the last one.
3162- // if (cond)
3163- // 100 +
3164- // -> here;
3165- if (lookfor == LOOKFOR_UNTERM
3166- || lookfor == LOOKFOR_ENUM_OR_INIT)
3167- {
3168- if (cont_amount > 0)
3169- amount = cont_amount;
3170- else
3171- amount += ind_continuation;
3172- break;
3173- }
3174-
3175- // If this is just above the line we are indenting, we
3176- // are finished.
3177- // while (not)
3178- // -> here;
3179- // Otherwise this indent can be used when the line
3180- // before this is terminated.
3181- // yyy;
3182- // if (stat)
3183- // while (not)
3184- // xxx;
3185- // -> here;
3186- amount = cur_amount;
3187- if (theline[0] == '{')
3188- amount += curbuf->b_ind_open_extra;
3189- if (lookfor != LOOKFOR_TERM)
3190- {
3191- amount += curbuf->b_ind_level
3192- + curbuf->b_ind_no_brace;
3193- break;
3194- }
3195-
3196- // Special trick: when expecting the while () after a
3197- // do, line up with the while()
3198- // do
3199- // x = 1;
3200- // -> here
3201- l = skipwhite(ml_get_curline());
3202- if (cin_isdo(l))
3203- {
3204- if (whilelevel == 0)
3205- break;
3206- --whilelevel;
3207- }
3208-
3209- // When searching for a terminated line, don't use the
3210- // one between the "if" and the matching "else".
3211- // Need to use the scope of this "else". XXX
3212- // If whilelevel != 0 continue looking for a "do {".
3213- if (cin_iselse(l) && whilelevel == 0)
3214- {
3215- // If we're looking at "} else", let's make sure we
3216- // find the opening brace of the enclosing scope,
3217- // not the one from "if () {".
3218- if (*l == '}')
3219- curwin->w_cursor.col =
3220- (colnr_T)(l - ml_get_curline()) + 1;
3221-
3222- if ((trypos = find_start_brace()) == NULL
3223- || find_match(LOOKFOR_IF, trypos->lnum)
3224- == FAIL)
3225- break;
3226- }
3227- }
3228-
3229- // If we're below an unterminated line that is not an
3230- // "if" or something, we may line up with this line or
3231- // add something for a continuation line, depending on
3232- // the line before this one.
3233- else
3234- {
3235- // Found two unterminated lines on a row, line up with
3236- // the last one.
3237- // c = 99 +
3238- // 100 +
3239- // -> here;
3240- if (lookfor == LOOKFOR_UNTERM)
3241- {
3242- // When line ends in a comma add extra indent
3243- if (terminated == ',')
3244- amount += ind_continuation;
3245- break;
3246- }
3247-
3248- if (lookfor == LOOKFOR_ENUM_OR_INIT)
3249- {
3250- // Found two lines ending in ',', lineup with the
3251- // lowest one, but check for cpp base class
3252- // declaration/initialization, if it is an
3253- // opening brace or we are looking just for
3254- // enumerations/initializations.
3255- if (terminated == ',')
3256- {
3257- if (curbuf->b_ind_cpp_baseclass == 0)
3258- break;
3259-
3260- lookfor = LOOKFOR_CPP_BASECLASS;
3261- continue;
3262- }
3263-
3264- // Ignore unterminated lines in between, but
3265- // reduce indent.
3266- if (amount > cur_amount)
3267- amount = cur_amount;
3268- }
3269- else
3270- {
3271- // Found first unterminated line on a row, may
3272- // line up with this line, remember its indent
3273- // 100 +
3274- // -> here;
3275- l = ml_get_curline();
3276- amount = cur_amount;
3277-
3278- n = (int)STRLEN(l);
3279- if (terminated == ',' && (*skipwhite(l) == ']'
3280- || (n >=2 && l[n - 2] == ']')))
3281- break;
3282-
3283- // If previous line ends in ',', check whether we
3284- // are in an initialization or enum
3285- // struct xxx =
3286- // {
3287- // sizeof a,
3288- // 124 };
3289- // or a normal possible continuation line.
3290- // but only, of no other statement has been found
3291- // yet.
3292- if (lookfor == LOOKFOR_INITIAL && terminated == ',')
3293- {
3294- if (curbuf->b_ind_js)
3295- {
3296- // Search for a line ending in a comma
3297- // and line up with the line below it
3298- // (could be the current line).
3299- // some = [
3300- // 1, <- line up here
3301- // 2,
3302- // some = [
3303- // 3 + <- line up here
3304- // 4 *
3305- // 5,
3306- // 6,
3307- if (cin_iscomment(skipwhite(l)))
3308- break;
3309- lookfor = LOOKFOR_COMMA;
3310- trypos = find_match_char('[',
3311- curbuf->b_ind_maxparen);
3312- if (trypos != NULL)
3313- {
3314- if (trypos->lnum
3315- == curwin->w_cursor.lnum - 1)
3316- {
3317- // Current line is first inside
3318- // [], line up with it.
3319- break;
3320- }
3321- ourscope = trypos->lnum;
3322- }
3323- }
3324- else
3325- {
3326- lookfor = LOOKFOR_ENUM_OR_INIT;
3327- cont_amount = cin_first_id_amount();
3328- }
3329- }
3330- else
3331- {
3332- if (lookfor == LOOKFOR_INITIAL
3333- && *l != NUL
3334- && l[STRLEN(l) - 1] == '\\')
3335- // XXX
3336- cont_amount = cin_get_equal_amount(
3337- curwin->w_cursor.lnum);
3338- if (lookfor != LOOKFOR_TERM
3339- && lookfor != LOOKFOR_JS_KEY
3340- && lookfor != LOOKFOR_COMMA
3341- && raw_string_start != curwin->w_cursor.lnum)
3342- lookfor = LOOKFOR_UNTERM;
3343- }
3344- }
3345- }
3346- }
3347-
3348- // Check if we are after a while (cond);
3349- // If so: Ignore until the matching "do".
3350- else if (cin_iswhileofdo_end(terminated)) // XXX
3351- {
3352- // Found an unterminated line after a while ();, line up
3353- // with the last one.
3354- // while (cond);
3355- // 100 + <- line up with this one
3356- // -> here;
3357- if (lookfor == LOOKFOR_UNTERM
3358- || lookfor == LOOKFOR_ENUM_OR_INIT)
3359- {
3360- if (cont_amount > 0)
3361- amount = cont_amount;
3362- else
3363- amount += ind_continuation;
3364- break;
3365- }
3366-
3367- if (whilelevel == 0)
3368- {
3369- lookfor = LOOKFOR_TERM;
3370- amount = get_indent(); // XXX
3371- if (theline[0] == '{')
3372- amount += curbuf->b_ind_open_extra;
3373- }
3374- ++whilelevel;
3375- }
3376-
3377- // We are after a "normal" statement.
3378- // If we had another statement we can stop now and use the
3379- // indent of that other statement.
3380- // Otherwise the indent of the current statement may be used,
3381- // search backwards for the next "normal" statement.
3382- else
3383- {
3384- // Skip single break line, if before a switch label. It
3385- // may be lined up with the case label.
3386- if (lookfor == LOOKFOR_NOBREAK
3387- && cin_isbreak(skipwhite(ml_get_curline())))
3388- {
3389- lookfor = LOOKFOR_ANY;
3390- continue;
3391- }
3392-
3393- // Handle "do {" line.
3394- if (whilelevel > 0)
3395- {
3396- l = cin_skipcomment(ml_get_curline());
3397- if (cin_isdo(l))
3398- {
3399- amount = get_indent(); // XXX
3400- --whilelevel;
3401- continue;
3402- }
3403- }
3404-
3405- // Found a terminated line above an unterminated line. Add
3406- // the amount for a continuation line.
3407- // x = 1;
3408- // y = foo +
3409- // -> here;
3410- // or
3411- // int x = 1;
3412- // int foo,
3413- // -> here;
3414- if (lookfor == LOOKFOR_UNTERM
3415- || lookfor == LOOKFOR_ENUM_OR_INIT)
3416- {
3417- if (cont_amount > 0)
3418- amount = cont_amount;
3419- else
3420- amount += ind_continuation;
3421- break;
3422- }
3423-
3424- // Found a terminated line above a terminated line or "if"
3425- // etc. line. Use the amount of the line below us.
3426- // x = 1; x = 1;
3427- // if (asdf) y = 2;
3428- // while (asdf) ->here;
3429- // here;
3430- // ->foo;
3431- if (lookfor == LOOKFOR_TERM)
3432- {
3433- if (!lookfor_break && whilelevel == 0)
3434- break;
3435- }
3436-
3437- // First line above the one we're indenting is terminated.
3438- // To know what needs to be done look further backward for
3439- // a terminated line.
3440- else
3441- {
3442- // position the cursor over the rightmost paren, so
3443- // that matching it will take us back to the start of
3444- // the line. Helps for:
3445- // func(asdr,
3446- // asdfasdf);
3447- // here;
3448-term_again:
3449- l = ml_get_curline();
3450- if (find_last_paren(l, '(', ')')
3451- && (trypos = find_match_paren(
3452- curbuf->b_ind_maxparen)) != NULL)
3453- {
3454- // Check if we are on a case label now. This is
3455- // handled above.
3456- // case xx: if ( asdf &&
3457- // asdf)
3458- curwin->w_cursor = *trypos;
3459- l = ml_get_curline();
3460- if (cin_iscase(l, FALSE) || cin_isscopedecl(l))
3461- {
3462- ++curwin->w_cursor.lnum;
3463- curwin->w_cursor.col = 0;
3464- continue;
3465- }
3466- }
3467-
3468- // When aligning with the case statement, don't align
3469- // with a statement after it.
3470- // case 1: { <-- don't use this { position
3471- // stat;
3472- // }
3473- // case 2:
3474- // stat;
3475- // }
3476- iscase = (curbuf->b_ind_keep_case_label
3477- && cin_iscase(l, FALSE));
3478-
3479- // Get indent and pointer to text for current line,
3480- // ignoring any jump label.
3481- amount = skip_label(curwin->w_cursor.lnum, &l);
3482-
3483- if (theline[0] == '{')
3484- amount += curbuf->b_ind_open_extra;
3485- // See remark above: "Only add b_ind_open_extra.."
3486- l = skipwhite(l);
3487- if (*l == '{')
3488- amount -= curbuf->b_ind_open_extra;
3489- lookfor = iscase ? LOOKFOR_ANY : LOOKFOR_TERM;
3490-
3491- // When a terminated line starts with "else" skip to
3492- // the matching "if":
3493- // else 3;
3494- // indent this;
3495- // Need to use the scope of this "else". XXX
3496- // If whilelevel != 0 continue looking for a "do {".
3497- if (lookfor == LOOKFOR_TERM
3498- && *l != '}'
3499- && cin_iselse(l)
3500- && whilelevel == 0)
3501- {
3502- if ((trypos = find_start_brace()) == NULL
3503- || find_match(LOOKFOR_IF, trypos->lnum)
3504- == FAIL)
3505- break;
3506- continue;
3507- }
3508-
3509- // If we're at the end of a block, skip to the start of
3510- // that block.
3511- l = ml_get_curline();
3512- if (find_last_paren(l, '{', '}') // XXX
3513- && (trypos = find_start_brace()) != NULL)
3514- {
3515- curwin->w_cursor = *trypos;
3516- // if not "else {" check for terminated again
3517- // but skip block for "} else {"
3518- l = cin_skipcomment(ml_get_curline());
3519- if (*l == '}' || !cin_iselse(l))
3520- goto term_again;
3521- ++curwin->w_cursor.lnum;
3522- curwin->w_cursor.col = 0;
3523- }
3524- }
3525- }
3526- }
3527- }
3528- }
3529-
3530- // add extra indent for a comment
3531- if (cin_iscomment(theline))
3532- amount += curbuf->b_ind_comment;
3533-
3534- // subtract extra left-shift for jump labels
3535- if (curbuf->b_ind_jump_label > 0 && original_line_islabel)
3536- amount -= curbuf->b_ind_jump_label;
3537-
3538- goto theend;
3539- }
3540-
3541- // ok -- we're not inside any sort of structure at all!
3542- //
3543- // This means we're at the top level, and everything should
3544- // basically just match where the previous line is, except
3545- // for the lines immediately following a function declaration,
3546- // which are K&R-style parameters and need to be indented.
3547- //
3548- // if our line starts with an open brace, forget about any
3549- // prevailing indent and make sure it looks like the start
3550- // of a function
3551-
3552- if (theline[0] == '{')
3553- {
3554- amount = curbuf->b_ind_first_open;
3555- goto theend;
3556- }
3557-
3558- // If the NEXT line is a function declaration, the current
3559- // line needs to be indented as a function type spec.
3560- // Don't do this if the current line looks like a comment or if the
3561- // current line is terminated, ie. ends in ';', or if the current line
3562- // contains { or }: "void f() {\n if (1)"
3563- if (cur_curpos.lnum < curbuf->b_ml.ml_line_count
3564- && !cin_nocode(theline)
3565- && vim_strchr(theline, '{') == NULL
3566- && vim_strchr(theline, '}') == NULL
3567- && !cin_ends_in(theline, (char_u *)":", NULL)
3568- && !cin_ends_in(theline, (char_u *)",", NULL)
3569- && cin_isfuncdecl(NULL, cur_curpos.lnum + 1,
3570- cur_curpos.lnum + 1)
3571- && !cin_isterminated(theline, FALSE, TRUE))
3572- {
3573- amount = curbuf->b_ind_func_type;
3574- goto theend;
3575- }
3576-
3577- // search backwards until we find something we recognize
3578- amount = 0;
3579- curwin->w_cursor = cur_curpos;
3580- while (curwin->w_cursor.lnum > 1)
3581- {
3582- curwin->w_cursor.lnum--;
3583- curwin->w_cursor.col = 0;
3584-
3585- l = ml_get_curline();
3586-
3587- // If we're in a comment or raw string now, skip to the start
3588- // of it. XXX
3589- if ((trypos = ind_find_start_CORS(NULL)) != NULL)
3590- {
3591- curwin->w_cursor.lnum = trypos->lnum + 1;
3592- curwin->w_cursor.col = 0;
3593- continue;
3594- }
3595-
3596- // Are we at the start of a cpp base class declaration or
3597- // constructor initialization? XXX
3598- n = FALSE;
3599- if (curbuf->b_ind_cpp_baseclass != 0 && theline[0] != '{')
3600- {
3601- n = cin_is_cpp_baseclass(&cache_cpp_baseclass);
3602- l = ml_get_curline();
3603- }
3604- if (n)
3605- {
3606- // XXX
3607- amount = get_baseclass_amount(cache_cpp_baseclass.lpos.col);
3608- break;
3609- }
3610-
3611- // Skip preprocessor directives and blank lines.
3612- if (cin_ispreproc_cont(&l, &curwin->w_cursor.lnum, &amount))
3613- continue;
3614-
3615- if (cin_nocode(l))
3616- continue;
3617-
3618- // If the previous line ends in ',', use one level of
3619- // indentation:
3620- // int foo,
3621- // bar;
3622- // do this before checking for '}' in case of eg.
3623- // enum foobar
3624- // {
3625- // ...
3626- // } foo,
3627- // bar;
3628- n = 0;
3629- if (cin_ends_in(l, (char_u *)",", NULL)
3630- || (*l != NUL && (n = l[STRLEN(l) - 1]) == '\\'))
3631- {
3632- // take us back to opening paren
3633- if (find_last_paren(l, '(', ')')
3634- && (trypos = find_match_paren(
3635- curbuf->b_ind_maxparen)) != NULL)
3636- curwin->w_cursor = *trypos;
3637-
3638- /*
3639- * For a line ending in ',' that is a continuation line go
3640- * back to the first line with a backslash:
3641- * char *foo = "bla\
3642- * bla",
3643- * here;
3644- */
3645- while (n == 0 && curwin->w_cursor.lnum > 1)
3646- {
3647- l = ml_get(curwin->w_cursor.lnum - 1);
3648- if (*l == NUL || l[STRLEN(l) - 1] != '\\')
3649- break;
3650- --curwin->w_cursor.lnum;
3651- curwin->w_cursor.col = 0;
3652- }
3653-
3654- amount = get_indent(); // XXX
3655-
3656- if (amount == 0)
3657- amount = cin_first_id_amount();
3658- if (amount == 0)
3659- amount = ind_continuation;
3660- break;
3661- }
3662-
3663- // If the line looks like a function declaration, and we're
3664- // not in a comment, put it the left margin.
3665- if (cin_isfuncdecl(NULL, cur_curpos.lnum, 0)) // XXX
3666- break;
3667- l = ml_get_curline();
3668-
3669- // Finding the closing '}' of a previous function. Put
3670- // current line at the left margin. For when 'cino' has "fs".
3671- if (*skipwhite(l) == '}')
3672- break;
3673-
3674- // (matching {)
3675- // If the previous line ends on '};' (maybe followed by
3676- // comments) align at column 0. For example:
3677- // char *string_array[] = { "foo",
3678- // / * x * / "b};ar" }; / * foobar * /
3679- if (cin_ends_in(l, (char_u *)"};", NULL))
3680- break;
3681-
3682- // If the previous line ends on '[' we are probably in an
3683- // array constant:
3684- // something = [
3685- // 234, <- extra indent
3686- if (cin_ends_in(l, (char_u *)"[", NULL))
3687- {
3688- amount = get_indent() + ind_continuation;
3689- break;
3690- }
3691-
3692- // Find a line only has a semicolon that belongs to a previous
3693- // line ending in '}', e.g. before an #endif. Don't increase
3694- // indent then.
3695- if (*(look = skipwhite(l)) == ';' && cin_nocode(look + 1))
3696- {
3697- pos_T curpos_save = curwin->w_cursor;
3698-
3699- while (curwin->w_cursor.lnum > 1)
3700- {
3701- look = ml_get(--curwin->w_cursor.lnum);
3702- if (!(cin_nocode(look) || cin_ispreproc_cont(
3703- &look, &curwin->w_cursor.lnum, &amount)))
3704- break;
3705- }
3706- if (curwin->w_cursor.lnum > 0
3707- && cin_ends_in(look, (char_u *)"}", NULL))
3708- break;
3709-
3710- curwin->w_cursor = curpos_save;
3711- }
3712-
3713- // If the PREVIOUS line is a function declaration, the current
3714- // line (and the ones that follow) needs to be indented as
3715- // parameters.
3716- if (cin_isfuncdecl(&l, curwin->w_cursor.lnum, 0))
3717- {
3718- amount = curbuf->b_ind_param;
3719- break;
3720- }
3721-
3722- // If the previous line ends in ';' and the line before the
3723- // previous line ends in ',' or '\', ident to column zero:
3724- // int foo,
3725- // bar;
3726- // indent_to_0 here;
3727- if (cin_ends_in(l, (char_u *)";", NULL))
3728- {
3729- l = ml_get(curwin->w_cursor.lnum - 1);
3730- if (cin_ends_in(l, (char_u *)",", NULL)
3731- || (*l != NUL && l[STRLEN(l) - 1] == '\\'))
3732- break;
3733- l = ml_get_curline();
3734- }
3735-
3736- // Doesn't look like anything interesting -- so just
3737- // use the indent of this line.
3738- //
3739- // Position the cursor over the rightmost paren, so that
3740- // matching it will take us back to the start of the line.
3741- find_last_paren(l, '(', ')');
3742-
3743- if ((trypos = find_match_paren(curbuf->b_ind_maxparen)) != NULL)
3744- curwin->w_cursor = *trypos;
3745- amount = get_indent(); // XXX
3746- break;
3747- }
3748-
3749- // add extra indent for a comment
3750- if (cin_iscomment(theline))
3751- amount += curbuf->b_ind_comment;
3752-
3753- /*
3754- * add extra indent if the previous line ended in a backslash:
3755- * "asdfasdf\
3756- * here";
3757- * char *foo = "asdf\
3758- * here";
3759- */
3760- if (cur_curpos.lnum > 1)
3761- {
3762- l = ml_get(cur_curpos.lnum - 1);
3763- if (*l != NUL && l[STRLEN(l) - 1] == '\\')
3764- {
3765- cur_amount = cin_get_equal_amount(cur_curpos.lnum - 1);
3766- if (cur_amount > 0)
3767- amount = cur_amount;
3768- else if (cur_amount == 0)
3769- amount += ind_continuation;
3770- }
3771- }
3772-
3773-theend:
3774- if (amount < 0)
3775- amount = 0;
3776-
3777-laterend:
3778- // put the cursor back where it belongs
3779- curwin->w_cursor = cur_curpos;
3780-
3781- vim_free(linecopy);
3782-
3783- return amount;
3784-}
3785-
3786- static int
3787-find_match(int lookfor, linenr_T ourscope)
3788-{
3789- char_u *look;
3790- pos_T *theirscope;
3791- char_u *mightbeif;
3792- int elselevel;
3793- int whilelevel;
3794-
3795- if (lookfor == LOOKFOR_IF)
3796- {
3797- elselevel = 1;
3798- whilelevel = 0;
3799- }
3800- else
3801- {
3802- elselevel = 0;
3803- whilelevel = 1;
3804- }
3805-
3