xref: /vim-8.2.3635/src/indent.c (revision 2ddb89f8)
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  * indent.c: Indentation related functions
12  */
13 
14 #include "vim.h"
15 
16 #if defined(FEAT_VARTABS) || defined(PROTO)
17 
18 /*
19  * Set the integer values corresponding to the string setting of 'vartabstop'.
20  * "array" will be set, caller must free it if needed.
21  * Return FAIL for an error.
22  */
23     int
tabstop_set(char_u * var,int ** array)24 tabstop_set(char_u *var, int **array)
25 {
26     int	    valcount = 1;
27     int	    t;
28     char_u  *cp;
29 
30     if (var[0] == NUL || (var[0] == '0' && var[1] == NUL))
31     {
32 	*array = NULL;
33 	return OK;
34     }
35 
36     for (cp = var; *cp != NUL; ++cp)
37     {
38 	if (cp == var || cp[-1] == ',')
39 	{
40 	    char_u *end;
41 
42 	    if (strtol((char *)cp, (char **)&end, 10) <= 0)
43 	    {
44 		if (cp != end)
45 		    emsg(_(e_positive));
46 		else
47 		    semsg(_(e_invarg2), cp);
48 		return FAIL;
49 	    }
50 	}
51 
52 	if (VIM_ISDIGIT(*cp))
53 	    continue;
54 	if (cp[0] == ',' && cp > var && cp[-1] != ',' && cp[1] != NUL)
55 	{
56 	    ++valcount;
57 	    continue;
58 	}
59 	semsg(_(e_invarg2), var);
60 	return FAIL;
61     }
62 
63     *array = ALLOC_MULT(int, valcount + 1);
64     if (*array == NULL)
65 	return FAIL;
66     (*array)[0] = valcount;
67 
68     t = 1;
69     for (cp = var; *cp != NUL;)
70     {
71 	int n = atoi((char *)cp);
72 
73 	// Catch negative values, overflow and ridiculous big values.
74 	if (n < 0 || n > 9999)
75 	{
76 	    semsg(_(e_invarg2), cp);
77 	    vim_free(*array);
78 	    *array = NULL;
79 	    return FAIL;
80 	}
81 	(*array)[t++] = n;
82 	while (*cp != NUL && *cp != ',')
83 	    ++cp;
84 	if (*cp != NUL)
85 	    ++cp;
86     }
87 
88     return OK;
89 }
90 
91 /*
92  * Calculate the number of screen spaces a tab will occupy.
93  * If "vts" is set then the tab widths are taken from that array,
94  * otherwise the value of ts is used.
95  */
96     int
tabstop_padding(colnr_T col,int ts_arg,int * vts)97 tabstop_padding(colnr_T col, int ts_arg, int *vts)
98 {
99     int		ts = ts_arg == 0 ? 8 : ts_arg;
100     int		tabcount;
101     colnr_T	tabcol = 0;
102     int		t;
103     int		padding = 0;
104 
105     if (vts == NULL || vts[0] == 0)
106 	return ts - (col % ts);
107 
108     tabcount = vts[0];
109 
110     for (t = 1; t <= tabcount; ++t)
111     {
112 	tabcol += vts[t];
113 	if (tabcol > col)
114 	{
115 	    padding = (int)(tabcol - col);
116 	    break;
117 	}
118     }
119     if (t > tabcount)
120 	padding = vts[tabcount] - (int)((col - tabcol) % vts[tabcount]);
121 
122     return padding;
123 }
124 
125 /*
126  * Find the size of the tab that covers a particular column.
127  */
128     int
tabstop_at(colnr_T col,int ts,int * vts)129 tabstop_at(colnr_T col, int ts, int *vts)
130 {
131     int		tabcount;
132     colnr_T	tabcol = 0;
133     int		t;
134     int		tab_size = 0;
135 
136     if (vts == 0 || vts[0] == 0)
137 	return ts;
138 
139     tabcount = vts[0];
140     for (t = 1; t <= tabcount; ++t)
141     {
142 	tabcol += vts[t];
143 	if (tabcol > col)
144 	{
145 	    tab_size = vts[t];
146 	    break;
147 	}
148     }
149     if (t > tabcount)
150 	tab_size = vts[tabcount];
151 
152     return tab_size;
153 }
154 
155 /*
156  * Find the column on which a tab starts.
157  */
158     colnr_T
tabstop_start(colnr_T col,int ts,int * vts)159 tabstop_start(colnr_T col, int ts, int *vts)
160 {
161     int		tabcount;
162     colnr_T	tabcol = 0;
163     int		t;
164     int         excess;
165 
166     if (vts == NULL || vts[0] == 0)
167 	return (col / ts) * ts;
168 
169     tabcount = vts[0];
170     for (t = 1; t <= tabcount; ++t)
171     {
172 	tabcol += vts[t];
173 	if (tabcol > col)
174 	    return tabcol - vts[t];
175     }
176 
177     excess = tabcol % vts[tabcount];
178     return excess + ((col - excess) / vts[tabcount]) * vts[tabcount];
179 }
180 
181 /*
182  * Find the number of tabs and spaces necessary to get from one column
183  * to another.
184  */
185     void
tabstop_fromto(colnr_T start_col,colnr_T end_col,int ts_arg,int * vts,int * ntabs,int * nspcs)186 tabstop_fromto(
187 	colnr_T start_col,
188 	colnr_T end_col,
189 	int	ts_arg,
190 	int	*vts,
191 	int	*ntabs,
192 	int	*nspcs)
193 {
194     int		spaces = end_col - start_col;
195     colnr_T	tabcol = 0;
196     int		padding = 0;
197     int		tabcount;
198     int		t;
199     int		ts = ts_arg == 0 ? curbuf->b_p_ts : ts_arg;
200 
201     if (vts == NULL || vts[0] == 0)
202     {
203 	int tabs = 0;
204 	int initspc = 0;
205 
206 	initspc = ts - (start_col % ts);
207 	if (spaces >= initspc)
208 	{
209 	    spaces -= initspc;
210 	    tabs++;
211 	}
212 	tabs += spaces / ts;
213 	spaces -= (spaces / ts) * ts;
214 
215 	*ntabs = tabs;
216 	*nspcs = spaces;
217 	return;
218     }
219 
220     // Find the padding needed to reach the next tabstop.
221     tabcount = vts[0];
222     for (t = 1; t <= tabcount; ++t)
223     {
224 	tabcol += vts[t];
225 	if (tabcol > start_col)
226 	{
227 	    padding = (int)(tabcol - start_col);
228 	    break;
229 	}
230     }
231     if (t > tabcount)
232 	padding = vts[tabcount] - (int)((start_col - tabcol) % vts[tabcount]);
233 
234     // If the space needed is less than the padding no tabs can be used.
235     if (spaces < padding)
236     {
237 	*ntabs = 0;
238 	*nspcs = spaces;
239 	return;
240     }
241 
242     *ntabs = 1;
243     spaces -= padding;
244 
245     // At least one tab has been used. See if any more will fit.
246     while (spaces != 0 && ++t <= tabcount)
247     {
248 	padding = vts[t];
249 	if (spaces < padding)
250 	{
251 	    *nspcs = spaces;
252 	    return;
253 	}
254 	++*ntabs;
255 	spaces -= padding;
256     }
257 
258     *ntabs += spaces / vts[tabcount];
259     *nspcs =  spaces % vts[tabcount];
260 }
261 
262 /*
263  * See if two tabstop arrays contain the same values.
264  */
265     static int
tabstop_eq(int * ts1,int * ts2)266 tabstop_eq(int *ts1, int *ts2)
267 {
268     int		t;
269 
270     if ((ts1 == 0 && ts2) || (ts1 && ts2 == 0))
271 	return FALSE;
272     if (ts1 == ts2)
273 	return TRUE;
274     if (ts1[0] != ts2[0])
275 	return FALSE;
276 
277     for (t = 1; t <= ts1[0]; ++t)
278 	if (ts1[t] != ts2[t])
279 	    return FALSE;
280 
281     return TRUE;
282 }
283 
284 # if defined(FEAT_BEVAL) || defined(PROTO)
285 /*
286  * Copy a tabstop array, allocating space for the new array.
287  */
288     int *
tabstop_copy(int * oldts)289 tabstop_copy(int *oldts)
290 {
291     int		*newts;
292     int		t;
293 
294     if (oldts == NULL)
295 	return NULL;
296     newts = ALLOC_MULT(int, oldts[0] + 1);
297     if (newts != NULL)
298 	for (t = 0; t <= oldts[0]; ++t)
299 	    newts[t] = oldts[t];
300     return newts;
301 }
302 # endif
303 
304 /*
305  * Return a count of the number of tabstops.
306  */
307     int
tabstop_count(int * ts)308 tabstop_count(int *ts)
309 {
310     return ts != NULL ? ts[0] : 0;
311 }
312 
313 /*
314  * Return the first tabstop, or 8 if there are no tabstops defined.
315  */
316     int
tabstop_first(int * ts)317 tabstop_first(int *ts)
318 {
319     return ts != NULL ? ts[1] : 8;
320 }
321 
322 #endif
323 
324 /*
325  * Return the effective shiftwidth value for current buffer, using the
326  * 'tabstop' value when 'shiftwidth' is zero.
327  */
328     long
get_sw_value(buf_T * buf)329 get_sw_value(buf_T *buf)
330 {
331     return get_sw_value_col(buf, 0);
332 }
333 
334 /*
335  * Idem, using "pos".
336  */
337     static long
get_sw_value_pos(buf_T * buf,pos_T * pos)338 get_sw_value_pos(buf_T *buf, pos_T *pos)
339 {
340     pos_T save_cursor = curwin->w_cursor;
341     long sw_value;
342 
343     curwin->w_cursor = *pos;
344     sw_value = get_sw_value_col(buf, get_nolist_virtcol());
345     curwin->w_cursor = save_cursor;
346     return sw_value;
347 }
348 
349 /*
350  * Idem, using the first non-black in the current line.
351  */
352     long
get_sw_value_indent(buf_T * buf)353 get_sw_value_indent(buf_T *buf)
354 {
355     pos_T pos = curwin->w_cursor;
356 
357     pos.col = getwhitecols_curline();
358     return get_sw_value_pos(buf, &pos);
359 }
360 
361 /*
362  * Idem, using virtual column "col".
363  */
364     long
get_sw_value_col(buf_T * buf,colnr_T col UNUSED)365 get_sw_value_col(buf_T *buf, colnr_T col UNUSED)
366 {
367     return buf->b_p_sw ? buf->b_p_sw :
368 #ifdef FEAT_VARTABS
369 	tabstop_at(col, buf->b_p_ts, buf->b_p_vts_array);
370 #else
371 	buf->b_p_ts;
372 #endif
373 }
374 
375 /*
376  * Return the effective softtabstop value for the current buffer, using the
377  * 'shiftwidth' value when 'softtabstop' is negative.
378  */
379     long
get_sts_value(void)380 get_sts_value(void)
381 {
382     return curbuf->b_p_sts < 0 ? get_sw_value(curbuf) : curbuf->b_p_sts;
383 }
384 
385 /*
386  * Count the size (in window cells) of the indent in the current line.
387  */
388     int
get_indent(void)389 get_indent(void)
390 {
391 #ifdef FEAT_VARTABS
392     return get_indent_str_vtab(ml_get_curline(), (int)curbuf->b_p_ts,
393 						 curbuf->b_p_vts_array, FALSE);
394 #else
395     return get_indent_str(ml_get_curline(), (int)curbuf->b_p_ts, FALSE);
396 #endif
397 }
398 
399 /*
400  * Count the size (in window cells) of the indent in line "lnum".
401  */
402     int
get_indent_lnum(linenr_T lnum)403 get_indent_lnum(linenr_T lnum)
404 {
405 #ifdef FEAT_VARTABS
406     return get_indent_str_vtab(ml_get(lnum), (int)curbuf->b_p_ts,
407 						 curbuf->b_p_vts_array, FALSE);
408 #else
409     return get_indent_str(ml_get(lnum), (int)curbuf->b_p_ts, FALSE);
410 #endif
411 }
412 
413 #if defined(FEAT_FOLDING) || defined(PROTO)
414 /*
415  * Count the size (in window cells) of the indent in line "lnum" of buffer
416  * "buf".
417  */
418     int
get_indent_buf(buf_T * buf,linenr_T lnum)419 get_indent_buf(buf_T *buf, linenr_T lnum)
420 {
421 # ifdef FEAT_VARTABS
422     return get_indent_str_vtab(ml_get_buf(buf, lnum, FALSE),
423 			       (int)curbuf->b_p_ts, buf->b_p_vts_array, FALSE);
424 # else
425     return get_indent_str(ml_get_buf(buf, lnum, FALSE), (int)buf->b_p_ts, FALSE);
426 # endif
427 }
428 #endif
429 
430 /*
431  * count the size (in window cells) of the indent in line "ptr", with
432  * 'tabstop' at "ts"
433  */
434     int
get_indent_str(char_u * ptr,int ts,int list)435 get_indent_str(
436     char_u	*ptr,
437     int		ts,
438     int		list) // if TRUE, count only screen size for tabs
439 {
440     int		count = 0;
441 
442     for ( ; *ptr; ++ptr)
443     {
444 	if (*ptr == TAB)
445 	{
446 	    if (!list || curwin->w_lcs_chars.tab1)
447 		// count a tab for what it is worth
448 		count += ts - (count % ts);
449 	    else
450 		// In list mode, when tab is not set, count screen char width
451 		// for Tab, displays: ^I
452 		count += ptr2cells(ptr);
453 	}
454 	else if (*ptr == ' ')
455 	    ++count;		// count a space for one
456 	else
457 	    break;
458     }
459     return count;
460 }
461 
462 #ifdef FEAT_VARTABS
463 /*
464  * Count the size (in window cells) of the indent in line "ptr", using
465  * variable tabstops.
466  * if "list" is TRUE, count only screen size for tabs.
467  */
468     int
get_indent_str_vtab(char_u * ptr,int ts,int * vts,int list)469 get_indent_str_vtab(char_u *ptr, int ts, int *vts, int list)
470 {
471     int		count = 0;
472 
473     for ( ; *ptr; ++ptr)
474     {
475 	if (*ptr == TAB)    // count a tab for what it is worth
476 	{
477 	    if (!list || curwin->w_lcs_chars.tab1)
478 		count += tabstop_padding(count, ts, vts);
479 	    else
480 		// In list mode, when tab is not set, count screen char width
481 		// for Tab, displays: ^I
482 		count += ptr2cells(ptr);
483 	}
484 	else if (*ptr == ' ')
485 	    ++count;		// count a space for one
486 	else
487 	    break;
488     }
489     return count;
490 }
491 #endif
492 
493 /*
494  * Set the indent of the current line.
495  * Leaves the cursor on the first non-blank in the line.
496  * Caller must take care of undo.
497  * "flags":
498  *	SIN_CHANGED:	call changed_bytes() if the line was changed.
499  *	SIN_INSERT:	insert the indent in front of the line.
500  *	SIN_UNDO:	save line for undo before changing it.
501  * Returns TRUE if the line was changed.
502  */
503     int
set_indent(int size,int flags)504 set_indent(
505     int		size,		    // measured in spaces
506     int		flags)
507 {
508     char_u	*p;
509     char_u	*newline;
510     char_u	*oldline;
511     char_u	*s;
512     int		todo;
513     int		ind_len;	    // measured in characters
514     int		line_len;
515     int		doit = FALSE;
516     int		ind_done = 0;	    // measured in spaces
517 #ifdef FEAT_VARTABS
518     int		ind_col = 0;
519 #endif
520     int		tab_pad;
521     int		retval = FALSE;
522     int		orig_char_len = -1; // number of initial whitespace chars when
523 				    // 'et' and 'pi' are both set
524 
525     // First check if there is anything to do and compute the number of
526     // characters needed for the indent.
527     todo = size;
528     ind_len = 0;
529     p = oldline = ml_get_curline();
530 
531     // Calculate the buffer size for the new indent, and check to see if it
532     // isn't already set
533 
534     // if 'expandtab' isn't set: use TABs; if both 'expandtab' and
535     // 'preserveindent' are set count the number of characters at the
536     // beginning of the line to be copied
537     if (!curbuf->b_p_et || (!(flags & SIN_INSERT) && curbuf->b_p_pi))
538     {
539 	// If 'preserveindent' is set then reuse as much as possible of
540 	// the existing indent structure for the new indent
541 	if (!(flags & SIN_INSERT) && curbuf->b_p_pi)
542 	{
543 	    ind_done = 0;
544 
545 	    // count as many characters as we can use
546 	    while (todo > 0 && VIM_ISWHITE(*p))
547 	    {
548 		if (*p == TAB)
549 		{
550 #ifdef FEAT_VARTABS
551 		    tab_pad = tabstop_padding(ind_done, curbuf->b_p_ts,
552 							curbuf->b_p_vts_array);
553 #else
554 		    tab_pad = (int)curbuf->b_p_ts
555 					   - (ind_done % (int)curbuf->b_p_ts);
556 #endif
557 		    // stop if this tab will overshoot the target
558 		    if (todo < tab_pad)
559 			break;
560 		    todo -= tab_pad;
561 		    ++ind_len;
562 		    ind_done += tab_pad;
563 		}
564 		else
565 		{
566 		    --todo;
567 		    ++ind_len;
568 		    ++ind_done;
569 		}
570 		++p;
571 	    }
572 
573 #ifdef FEAT_VARTABS
574 	    // These diverge from this point.
575 	    ind_col = ind_done;
576 #endif
577 	    // Set initial number of whitespace chars to copy if we are
578 	    // preserving indent but expandtab is set
579 	    if (curbuf->b_p_et)
580 		orig_char_len = ind_len;
581 
582 	    // Fill to next tabstop with a tab, if possible
583 #ifdef FEAT_VARTABS
584 	    tab_pad = tabstop_padding(ind_done, curbuf->b_p_ts,
585 						curbuf->b_p_vts_array);
586 #else
587 	    tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts);
588 #endif
589 	    if (todo >= tab_pad && orig_char_len == -1)
590 	    {
591 		doit = TRUE;
592 		todo -= tab_pad;
593 		++ind_len;
594 		// ind_done += tab_pad;
595 #ifdef FEAT_VARTABS
596 		ind_col += tab_pad;
597 #endif
598 	    }
599 	}
600 
601 	// count tabs required for indent
602 #ifdef FEAT_VARTABS
603 	for (;;)
604 	{
605 	    tab_pad = tabstop_padding(ind_col, curbuf->b_p_ts,
606 							curbuf->b_p_vts_array);
607 	    if (todo < tab_pad)
608 		break;
609 	    if (*p != TAB)
610 		doit = TRUE;
611 	    else
612 		++p;
613 	    todo -= tab_pad;
614 	    ++ind_len;
615 	    ind_col += tab_pad;
616 	}
617 #else
618 	while (todo >= (int)curbuf->b_p_ts)
619 	{
620 	    if (*p != TAB)
621 		doit = TRUE;
622 	    else
623 		++p;
624 	    todo -= (int)curbuf->b_p_ts;
625 	    ++ind_len;
626 	    // ind_done += (int)curbuf->b_p_ts;
627 	}
628 #endif
629     }
630     // count spaces required for indent
631     while (todo > 0)
632     {
633 	if (*p != ' ')
634 	    doit = TRUE;
635 	else
636 	    ++p;
637 	--todo;
638 	++ind_len;
639 	// ++ind_done;
640     }
641 
642     // Return if the indent is OK already.
643     if (!doit && !VIM_ISWHITE(*p) && !(flags & SIN_INSERT))
644 	return FALSE;
645 
646     // Allocate memory for the new line.
647     if (flags & SIN_INSERT)
648 	p = oldline;
649     else
650 	p = skipwhite(p);
651     line_len = (int)STRLEN(p) + 1;
652 
653     // If 'preserveindent' and 'expandtab' are both set keep the original
654     // characters and allocate accordingly.  We will fill the rest with spaces
655     // after the if (!curbuf->b_p_et) below.
656     if (orig_char_len != -1)
657     {
658 	newline = alloc(orig_char_len + size - ind_done + line_len);
659 	if (newline == NULL)
660 	    return FALSE;
661 	todo = size - ind_done;
662 	ind_len = orig_char_len + todo;    // Set total length of indent in
663 					   // characters, which may have been
664 					   // undercounted until now
665 	p = oldline;
666 	s = newline;
667 	while (orig_char_len > 0)
668 	{
669 	    *s++ = *p++;
670 	    orig_char_len--;
671 	}
672 
673 	// Skip over any additional white space (useful when newindent is less
674 	// than old)
675 	while (VIM_ISWHITE(*p))
676 	    ++p;
677 
678     }
679     else
680     {
681 	todo = size;
682 	newline = alloc(ind_len + line_len);
683 	if (newline == NULL)
684 	    return FALSE;
685 	s = newline;
686     }
687 
688     // Put the characters in the new line.
689     // if 'expandtab' isn't set: use TABs
690     if (!curbuf->b_p_et)
691     {
692 	// If 'preserveindent' is set then reuse as much as possible of
693 	// the existing indent structure for the new indent
694 	if (!(flags & SIN_INSERT) && curbuf->b_p_pi)
695 	{
696 	    p = oldline;
697 	    ind_done = 0;
698 
699 	    while (todo > 0 && VIM_ISWHITE(*p))
700 	    {
701 		if (*p == TAB)
702 		{
703 #ifdef FEAT_VARTABS
704 		    tab_pad = tabstop_padding(ind_done, curbuf->b_p_ts,
705 							curbuf->b_p_vts_array);
706 #else
707 		    tab_pad = (int)curbuf->b_p_ts
708 					   - (ind_done % (int)curbuf->b_p_ts);
709 #endif
710 		    // stop if this tab will overshoot the target
711 		    if (todo < tab_pad)
712 			break;
713 		    todo -= tab_pad;
714 		    ind_done += tab_pad;
715 		}
716 		else
717 		{
718 		    --todo;
719 		    ++ind_done;
720 		}
721 		*s++ = *p++;
722 	    }
723 
724 	    // Fill to next tabstop with a tab, if possible
725 #ifdef FEAT_VARTABS
726 	    tab_pad = tabstop_padding(ind_done, curbuf->b_p_ts,
727 						curbuf->b_p_vts_array);
728 #else
729 	    tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts);
730 #endif
731 	    if (todo >= tab_pad)
732 	    {
733 		*s++ = TAB;
734 		todo -= tab_pad;
735 #ifdef FEAT_VARTABS
736 		ind_done += tab_pad;
737 #endif
738 	    }
739 
740 	    p = skipwhite(p);
741 	}
742 
743 #ifdef FEAT_VARTABS
744 	for (;;)
745 	{
746 	    tab_pad = tabstop_padding(ind_done, curbuf->b_p_ts,
747 							curbuf->b_p_vts_array);
748 	    if (todo < tab_pad)
749 		break;
750 	    *s++ = TAB;
751 	    todo -= tab_pad;
752 	    ind_done += tab_pad;
753 	}
754 #else
755 	while (todo >= (int)curbuf->b_p_ts)
756 	{
757 	    *s++ = TAB;
758 	    todo -= (int)curbuf->b_p_ts;
759 	}
760 #endif
761     }
762     while (todo > 0)
763     {
764 	*s++ = ' ';
765 	--todo;
766     }
767     mch_memmove(s, p, (size_t)line_len);
768 
769     // Replace the line (unless undo fails).
770     if (!(flags & SIN_UNDO) || u_savesub(curwin->w_cursor.lnum) == OK)
771     {
772 	colnr_T old_offset = (colnr_T)(p - oldline);
773 	colnr_T new_offset = (colnr_T)(s - newline);
774 
775 	// this may free "newline"
776 	ml_replace(curwin->w_cursor.lnum, newline, FALSE);
777 	if (flags & SIN_CHANGED)
778 	    changed_bytes(curwin->w_cursor.lnum, 0);
779 
780 	// Correct saved cursor position if it is in this line.
781 	if (saved_cursor.lnum == curwin->w_cursor.lnum)
782 	{
783 	    if (saved_cursor.col >= old_offset)
784 		// cursor was after the indent, adjust for the number of
785 		// bytes added/removed
786 		saved_cursor.col += ind_len - old_offset;
787 	    else if (saved_cursor.col >= new_offset)
788 		// cursor was in the indent, and is now after it, put it back
789 		// at the start of the indent (replacing spaces with TAB)
790 		saved_cursor.col = new_offset;
791 	}
792 #ifdef FEAT_PROP_POPUP
793 	{
794 	    int added = ind_len - old_offset;
795 
796 	    // When increasing indent this behaves like spaces were inserted at
797 	    // the old indent, when decreasing indent it behaves like spaces
798 	    // were deleted at the new indent.
799 	    adjust_prop_columns(curwin->w_cursor.lnum,
800 			  added > 0 ? old_offset : (colnr_T)ind_len, added, 0);
801 	}
802 #endif
803 	retval = TRUE;
804     }
805     else
806 	vim_free(newline);
807 
808     curwin->w_cursor.col = ind_len;
809     return retval;
810 }
811 
812 /*
813  * Return the indent of the current line after a number.  Return -1 if no
814  * number was found.  Used for 'n' in 'formatoptions': numbered list.
815  * Since a pattern is used it can actually handle more than numbers.
816  */
817     int
get_number_indent(linenr_T lnum)818 get_number_indent(linenr_T lnum)
819 {
820     colnr_T	col;
821     pos_T	pos;
822 
823     regmatch_T	regmatch;
824     int		lead_len = 0;	// length of comment leader
825 
826     if (lnum > curbuf->b_ml.ml_line_count)
827 	return -1;
828     pos.lnum = 0;
829 
830     // In format_lines() (i.e. not insert mode), fo+=q is needed too...
831     if ((State & INSERT) || has_format_option(FO_Q_COMS))
832 	lead_len = get_leader_len(ml_get(lnum), NULL, FALSE, TRUE);
833 
834     regmatch.regprog = vim_regcomp(curbuf->b_p_flp, RE_MAGIC);
835     if (regmatch.regprog != NULL)
836     {
837 	regmatch.rm_ic = FALSE;
838 
839 	// vim_regexec() expects a pointer to a line.  This lets us
840 	// start matching for the flp beyond any comment leader...
841 	if (vim_regexec(&regmatch, ml_get(lnum) + lead_len, (colnr_T)0))
842 	{
843 	    pos.lnum = lnum;
844 	    pos.col = (colnr_T)(*regmatch.endp - ml_get(lnum));
845 	    pos.coladd = 0;
846 	}
847 	vim_regfree(regmatch.regprog);
848     }
849 
850     if (pos.lnum == 0 || *ml_get_pos(&pos) == NUL)
851 	return -1;
852     getvcol(curwin, &pos, &col, NULL, NULL);
853     return (int)col;
854 }
855 
856 #if defined(FEAT_LINEBREAK) || defined(PROTO)
857 /*
858  * This is called when 'breakindentopt' is changed and when a window is
859  * initialized.
860  */
861     int
briopt_check(win_T * wp)862 briopt_check(win_T *wp)
863 {
864     char_u	*p;
865     int		bri_shift = 0;
866     long	bri_min = 20;
867     int		bri_sbr = FALSE;
868     int		bri_list = 0;
869 
870     p = wp->w_p_briopt;
871     while (*p != NUL)
872     {
873 	if (STRNCMP(p, "shift:", 6) == 0
874 		 && ((p[6] == '-' && VIM_ISDIGIT(p[7])) || VIM_ISDIGIT(p[6])))
875 	{
876 	    p += 6;
877 	    bri_shift = getdigits(&p);
878 	}
879 	else if (STRNCMP(p, "min:", 4) == 0 && VIM_ISDIGIT(p[4]))
880 	{
881 	    p += 4;
882 	    bri_min = getdigits(&p);
883 	}
884 	else if (STRNCMP(p, "sbr", 3) == 0)
885 	{
886 	    p += 3;
887 	    bri_sbr = TRUE;
888 	}
889 	else if (STRNCMP(p, "list:", 5) == 0)
890 	{
891 	    p += 5;
892 	    bri_list = getdigits(&p);
893 	}
894 	if (*p != ',' && *p != NUL)
895 	    return FAIL;
896 	if (*p == ',')
897 	    ++p;
898     }
899 
900     wp->w_briopt_shift = bri_shift;
901     wp->w_briopt_min   = bri_min;
902     wp->w_briopt_sbr   = bri_sbr;
903     wp->w_briopt_list  = bri_list;
904 
905     return OK;
906 }
907 
908 /*
909  * Return appropriate space number for breakindent, taking influencing
910  * parameters into account. Window must be specified, since it is not
911  * necessarily always the current one.
912  */
913     int
get_breakindent_win(win_T * wp,char_u * line)914 get_breakindent_win(
915     win_T	*wp,
916     char_u	*line) // start of the line
917 {
918     static int	    prev_indent = 0;  // cached indent value
919     static long	    prev_ts     = 0L; // cached tabstop value
920     static char_u   *prev_line = NULL; // cached pointer to line
921     static varnumber_T prev_tick = 0;   // changedtick of cached value
922 # ifdef FEAT_VARTABS
923     static int      *prev_vts = NULL;    // cached vartabs values
924 # endif
925     int		    bri = 0;
926     // window width minus window margin space, i.e. what rests for text
927     const int	    eff_wwidth = wp->w_width
928 			    - ((wp->w_p_nu || wp->w_p_rnu)
929 				&& (vim_strchr(p_cpo, CPO_NUMCOL) == NULL)
930 						? number_width(wp) + 1 : 0);
931 
932     // used cached indent, unless pointer or 'tabstop' changed
933     if (prev_line != line || prev_ts != wp->w_buffer->b_p_ts
934 	    || prev_tick != CHANGEDTICK(wp->w_buffer)
935 # ifdef FEAT_VARTABS
936 	    || prev_vts != wp->w_buffer->b_p_vts_array
937 # endif
938 	)
939     {
940 	prev_line = line;
941 	prev_ts = wp->w_buffer->b_p_ts;
942 	prev_tick = CHANGEDTICK(wp->w_buffer);
943 # ifdef FEAT_VARTABS
944 	prev_vts = wp->w_buffer->b_p_vts_array;
945 	prev_indent = get_indent_str_vtab(line,
946 				     (int)wp->w_buffer->b_p_ts,
947 				    wp->w_buffer->b_p_vts_array, wp->w_p_list);
948 # else
949 	prev_indent = get_indent_str(line,
950 				     (int)wp->w_buffer->b_p_ts, wp->w_p_list);
951 # endif
952     }
953     bri = prev_indent + wp->w_briopt_shift;
954 
955     // Add offset for number column, if 'n' is in 'cpoptions'
956     bri += win_col_off2(wp);
957 
958     // add additional indent for numbered lists
959     if (wp->w_briopt_list != 0)
960     {
961 	regmatch_T	    regmatch;
962 
963 	regmatch.regprog = vim_regcomp(curbuf->b_p_flp,
964 				   RE_MAGIC + RE_STRING + RE_AUTO + RE_STRICT);
965 	if (regmatch.regprog != NULL)
966 	{
967 	    regmatch.rm_ic = FALSE;
968 	    if (vim_regexec(&regmatch, line, 0))
969 	    {
970 		if (wp->w_briopt_list > 0)
971 		    bri += wp->w_briopt_list;
972 		else
973 		    bri = (*regmatch.endp - *regmatch.startp);
974 	    }
975 	    vim_regfree(regmatch.regprog);
976 	}
977     }
978 
979     // indent minus the length of the showbreak string
980     if (wp->w_briopt_sbr)
981 	bri -= vim_strsize(get_showbreak_value(wp));
982 
983 
984     // never indent past left window margin
985     if (bri < 0)
986 	bri = 0;
987 
988     // always leave at least bri_min characters on the left,
989     // if text width is sufficient
990     else if (bri > eff_wwidth - wp->w_briopt_min)
991 	bri = (eff_wwidth - wp->w_briopt_min < 0)
992 					   ? 0 : eff_wwidth - wp->w_briopt_min;
993 
994     return bri;
995 }
996 #endif
997 
998 /*
999  * When extra == 0: Return TRUE if the cursor is before or on the first
1000  *		    non-blank in the line.
1001  * When extra == 1: Return TRUE if the cursor is before the first non-blank in
1002  *		    the line.
1003  */
1004     int
inindent(int extra)1005 inindent(int extra)
1006 {
1007     char_u	*ptr;
1008     colnr_T	col;
1009 
1010     for (col = 0, ptr = ml_get_curline(); VIM_ISWHITE(*ptr); ++col)
1011 	++ptr;
1012     if (col >= curwin->w_cursor.col + extra)
1013 	return TRUE;
1014     else
1015 	return FALSE;
1016 }
1017 
1018 #if defined(FEAT_LISP) || defined(FEAT_CINDENT) || defined(PROTO)
1019 /*
1020  * op_reindent - handle reindenting a block of lines.
1021  */
1022     void
op_reindent(oparg_T * oap,int (* how)(void))1023 op_reindent(oparg_T *oap, int (*how)(void))
1024 {
1025     long	i;
1026     char_u	*l;
1027     int		amount;
1028     linenr_T	first_changed = 0;
1029     linenr_T	last_changed = 0;
1030     linenr_T	start_lnum = curwin->w_cursor.lnum;
1031 
1032     // Don't even try when 'modifiable' is off.
1033     if (!curbuf->b_p_ma)
1034     {
1035 	emsg(_(e_cannot_make_changes_modifiable_is_off));
1036 	return;
1037     }
1038 
1039     for (i = oap->line_count; --i >= 0 && !got_int; )
1040     {
1041 	// it's a slow thing to do, so give feedback so there's no worry that
1042 	// the computer's just hung.
1043 
1044 	if (i > 1
1045 		&& (i % 50 == 0 || i == oap->line_count - 1)
1046 		&& oap->line_count > p_report)
1047 	    smsg(_("%ld lines to indent... "), i);
1048 
1049 	// Be vi-compatible: For lisp indenting the first line is not
1050 	// indented, unless there is only one line.
1051 # ifdef FEAT_LISP
1052 	if (i != oap->line_count - 1 || oap->line_count == 1
1053 						    || how != get_lisp_indent)
1054 # endif
1055 	{
1056 	    l = skipwhite(ml_get_curline());
1057 	    if (*l == NUL)		    // empty or blank line
1058 		amount = 0;
1059 	    else
1060 		amount = how();		    // get the indent for this line
1061 
1062 	    if (amount >= 0 && set_indent(amount, SIN_UNDO))
1063 	    {
1064 		// did change the indent, call changed_lines() later
1065 		if (first_changed == 0)
1066 		    first_changed = curwin->w_cursor.lnum;
1067 		last_changed = curwin->w_cursor.lnum;
1068 	    }
1069 	}
1070 	++curwin->w_cursor.lnum;
1071 	curwin->w_cursor.col = 0;  // make sure it's valid
1072     }
1073 
1074     // put cursor on first non-blank of indented line
1075     curwin->w_cursor.lnum = start_lnum;
1076     beginline(BL_SOL | BL_FIX);
1077 
1078     // Mark changed lines so that they will be redrawn.  When Visual
1079     // highlighting was present, need to continue until the last line.  When
1080     // there is no change still need to remove the Visual highlighting.
1081     if (last_changed != 0)
1082 	changed_lines(first_changed, 0,
1083 		oap->is_VIsual ? start_lnum + oap->line_count :
1084 		last_changed + 1, 0L);
1085     else if (oap->is_VIsual)
1086 	redraw_curbuf_later(INVERTED);
1087 
1088     if (oap->line_count > p_report)
1089     {
1090 	i = oap->line_count - (i + 1);
1091 	smsg(NGETTEXT("%ld line indented ",
1092 						 "%ld lines indented ", i), i);
1093     }
1094     if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0)
1095     {
1096 	// set '[ and '] marks
1097 	curbuf->b_op_start = oap->start;
1098 	curbuf->b_op_end = oap->end;
1099     }
1100 }
1101 #endif // defined(FEAT_LISP) || defined(FEAT_CINDENT)
1102 
1103 #if defined(FEAT_SMARTINDENT) || defined(FEAT_CINDENT) || defined(PROTO)
1104 /*
1105  * Return TRUE if lines starting with '#' should be left aligned.
1106  */
1107     int
preprocs_left(void)1108 preprocs_left(void)
1109 {
1110     return
1111 # ifdef FEAT_SMARTINDENT
1112 #  ifdef FEAT_CINDENT
1113 	(curbuf->b_p_si && !curbuf->b_p_cin) ||
1114 #  else
1115 	curbuf->b_p_si
1116 #  endif
1117 # endif
1118 # ifdef FEAT_CINDENT
1119 	(curbuf->b_p_cin && in_cinkeys('#', ' ', TRUE)
1120 					   && curbuf->b_ind_hash_comment == 0)
1121 # endif
1122 	;
1123 }
1124 #endif
1125 
1126 #ifdef FEAT_SMARTINDENT
1127 /*
1128  * Try to do some very smart auto-indenting.
1129  * Used when inserting a "normal" character.
1130  */
1131     void
ins_try_si(int c)1132 ins_try_si(int c)
1133 {
1134     pos_T	*pos, old_pos;
1135     char_u	*ptr;
1136     int		i;
1137     int		temp;
1138 
1139     // do some very smart indenting when entering '{' or '}'
1140     if (((did_si || can_si_back) && c == '{') || (can_si && c == '}'))
1141     {
1142 	// for '}' set indent equal to indent of line containing matching '{'
1143 	if (c == '}' && (pos = findmatch(NULL, '{')) != NULL)
1144 	{
1145 	    old_pos = curwin->w_cursor;
1146 	    // If the matching '{' has a ')' immediately before it (ignoring
1147 	    // white-space), then line up with the start of the line
1148 	    // containing the matching '(' if there is one.  This handles the
1149 	    // case where an "if (..\n..) {" statement continues over multiple
1150 	    // lines -- webb
1151 	    ptr = ml_get(pos->lnum);
1152 	    i = pos->col;
1153 	    if (i > 0)		// skip blanks before '{'
1154 		while (--i > 0 && VIM_ISWHITE(ptr[i]))
1155 		    ;
1156 	    curwin->w_cursor.lnum = pos->lnum;
1157 	    curwin->w_cursor.col = i;
1158 	    if (ptr[i] == ')' && (pos = findmatch(NULL, '(')) != NULL)
1159 		curwin->w_cursor = *pos;
1160 	    i = get_indent();
1161 	    curwin->w_cursor = old_pos;
1162 	    if (State & VREPLACE_FLAG)
1163 		change_indent(INDENT_SET, i, FALSE, NUL, TRUE);
1164 	    else
1165 		(void)set_indent(i, SIN_CHANGED);
1166 	}
1167 	else if (curwin->w_cursor.col > 0)
1168 	{
1169 	    // when inserting '{' after "O" reduce indent, but not
1170 	    // more than indent of previous line
1171 	    temp = TRUE;
1172 	    if (c == '{' && can_si_back && curwin->w_cursor.lnum > 1)
1173 	    {
1174 		old_pos = curwin->w_cursor;
1175 		i = get_indent();
1176 		while (curwin->w_cursor.lnum > 1)
1177 		{
1178 		    ptr = skipwhite(ml_get(--(curwin->w_cursor.lnum)));
1179 
1180 		    // ignore empty lines and lines starting with '#'.
1181 		    if (*ptr != '#' && *ptr != NUL)
1182 			break;
1183 		}
1184 		if (get_indent() >= i)
1185 		    temp = FALSE;
1186 		curwin->w_cursor = old_pos;
1187 	    }
1188 	    if (temp)
1189 		shift_line(TRUE, FALSE, 1, TRUE);
1190 	}
1191     }
1192 
1193     // set indent of '#' always to 0
1194     if (curwin->w_cursor.col > 0 && can_si && c == '#')
1195     {
1196 	// remember current indent for next line
1197 	old_indent = get_indent();
1198 	(void)set_indent(0, SIN_CHANGED);
1199     }
1200 
1201     // Adjust ai_col, the char at this position can be deleted.
1202     if (ai_col > curwin->w_cursor.col)
1203 	ai_col = curwin->w_cursor.col;
1204 }
1205 #endif
1206 
1207 /*
1208  * Insert an indent (for <Tab> or CTRL-T) or delete an indent (for CTRL-D).
1209  * Keep the cursor on the same character.
1210  * type == INDENT_INC	increase indent (for CTRL-T or <Tab>)
1211  * type == INDENT_DEC	decrease indent (for CTRL-D)
1212  * type == INDENT_SET	set indent to "amount"
1213  * if round is TRUE, round the indent to 'shiftwidth' (only with _INC and _Dec).
1214  */
1215     void
change_indent(int type,int amount,int round,int replaced,int call_changed_bytes)1216 change_indent(
1217     int		type,
1218     int		amount,
1219     int		round,
1220     int		replaced,	// replaced character, put on replace stack
1221     int		call_changed_bytes)	// call changed_bytes()
1222 {
1223     int		vcol;
1224     int		last_vcol;
1225     int		insstart_less;		// reduction for Insstart.col
1226     int		new_cursor_col;
1227     int		i;
1228     char_u	*ptr;
1229     int		save_p_list;
1230     int		start_col;
1231     colnr_T	vc;
1232     colnr_T	orig_col = 0;		// init for GCC
1233     char_u	*new_line, *orig_line = NULL;	// init for GCC
1234 
1235     // VREPLACE mode needs to know what the line was like before changing
1236     if (State & VREPLACE_FLAG)
1237     {
1238 	orig_line = vim_strsave(ml_get_curline());  // Deal with NULL below
1239 	orig_col = curwin->w_cursor.col;
1240     }
1241 
1242     // for the following tricks we don't want list mode
1243     save_p_list = curwin->w_p_list;
1244     curwin->w_p_list = FALSE;
1245     vc = getvcol_nolist(&curwin->w_cursor);
1246     vcol = vc;
1247 
1248     // For Replace mode we need to fix the replace stack later, which is only
1249     // possible when the cursor is in the indent.  Remember the number of
1250     // characters before the cursor if it's possible.
1251     start_col = curwin->w_cursor.col;
1252 
1253     // determine offset from first non-blank
1254     new_cursor_col = curwin->w_cursor.col;
1255     beginline(BL_WHITE);
1256     new_cursor_col -= curwin->w_cursor.col;
1257 
1258     insstart_less = curwin->w_cursor.col;
1259 
1260     // If the cursor is in the indent, compute how many screen columns the
1261     // cursor is to the left of the first non-blank.
1262     if (new_cursor_col < 0)
1263 	vcol = get_indent() - vcol;
1264 
1265     if (new_cursor_col > 0)	    // can't fix replace stack
1266 	start_col = -1;
1267 
1268     // Set the new indent.  The cursor will be put on the first non-blank.
1269     if (type == INDENT_SET)
1270 	(void)set_indent(amount, call_changed_bytes ? SIN_CHANGED : 0);
1271     else
1272     {
1273 	int	save_State = State;
1274 
1275 	// Avoid being called recursively.
1276 	if (State & VREPLACE_FLAG)
1277 	    State = INSERT;
1278 	shift_line(type == INDENT_DEC, round, 1, call_changed_bytes);
1279 	State = save_State;
1280     }
1281     insstart_less -= curwin->w_cursor.col;
1282 
1283     // Try to put cursor on same character.
1284     // If the cursor is at or after the first non-blank in the line,
1285     // compute the cursor column relative to the column of the first
1286     // non-blank character.
1287     // If we are not in insert mode, leave the cursor on the first non-blank.
1288     // If the cursor is before the first non-blank, position it relative
1289     // to the first non-blank, counted in screen columns.
1290     if (new_cursor_col >= 0)
1291     {
1292 	// When changing the indent while the cursor is touching it, reset
1293 	// Insstart_col to 0.
1294 	if (new_cursor_col == 0)
1295 	    insstart_less = MAXCOL;
1296 	new_cursor_col += curwin->w_cursor.col;
1297     }
1298     else if (!(State & INSERT))
1299 	new_cursor_col = curwin->w_cursor.col;
1300     else
1301     {
1302 	// Compute the screen column where the cursor should be.
1303 	vcol = get_indent() - vcol;
1304 	curwin->w_virtcol = (colnr_T)((vcol < 0) ? 0 : vcol);
1305 
1306 	// Advance the cursor until we reach the right screen column.
1307 	vcol = last_vcol = 0;
1308 	new_cursor_col = -1;
1309 	ptr = ml_get_curline();
1310 	while (vcol <= (int)curwin->w_virtcol)
1311 	{
1312 	    last_vcol = vcol;
1313 	    if (has_mbyte && new_cursor_col >= 0)
1314 		new_cursor_col += (*mb_ptr2len)(ptr + new_cursor_col);
1315 	    else
1316 		++new_cursor_col;
1317 	    vcol += lbr_chartabsize(ptr, ptr + new_cursor_col, (colnr_T)vcol);
1318 	}
1319 	vcol = last_vcol;
1320 
1321 	// May need to insert spaces to be able to position the cursor on
1322 	// the right screen column.
1323 	if (vcol != (int)curwin->w_virtcol)
1324 	{
1325 	    curwin->w_cursor.col = (colnr_T)new_cursor_col;
1326 	    i = (int)curwin->w_virtcol - vcol;
1327 	    ptr = alloc(i + 1);
1328 	    if (ptr != NULL)
1329 	    {
1330 		new_cursor_col += i;
1331 		ptr[i] = NUL;
1332 		while (--i >= 0)
1333 		    ptr[i] = ' ';
1334 		ins_str(ptr);
1335 		vim_free(ptr);
1336 	    }
1337 	}
1338 
1339 	// When changing the indent while the cursor is in it, reset
1340 	// Insstart_col to 0.
1341 	insstart_less = MAXCOL;
1342     }
1343 
1344     curwin->w_p_list = save_p_list;
1345 
1346     if (new_cursor_col <= 0)
1347 	curwin->w_cursor.col = 0;
1348     else
1349 	curwin->w_cursor.col = (colnr_T)new_cursor_col;
1350     curwin->w_set_curswant = TRUE;
1351     changed_cline_bef_curs();
1352 
1353     // May have to adjust the start of the insert.
1354     if (State & INSERT)
1355     {
1356 	if (curwin->w_cursor.lnum == Insstart.lnum && Insstart.col != 0)
1357 	{
1358 	    if ((int)Insstart.col <= insstart_less)
1359 		Insstart.col = 0;
1360 	    else
1361 		Insstart.col -= insstart_less;
1362 	}
1363 	if ((int)ai_col <= insstart_less)
1364 	    ai_col = 0;
1365 	else
1366 	    ai_col -= insstart_less;
1367     }
1368 
1369     // For REPLACE mode, may have to fix the replace stack, if it's possible.
1370     // If the number of characters before the cursor decreased, need to pop a
1371     // few characters from the replace stack.
1372     // If the number of characters before the cursor increased, need to push a
1373     // few NULs onto the replace stack.
1374     if (REPLACE_NORMAL(State) && start_col >= 0)
1375     {
1376 	while (start_col > (int)curwin->w_cursor.col)
1377 	{
1378 	    replace_join(0);	    // remove a NUL from the replace stack
1379 	    --start_col;
1380 	}
1381 	while (start_col < (int)curwin->w_cursor.col || replaced)
1382 	{
1383 	    replace_push(NUL);
1384 	    if (replaced)
1385 	    {
1386 		replace_push(replaced);
1387 		replaced = NUL;
1388 	    }
1389 	    ++start_col;
1390 	}
1391     }
1392 
1393     // For VREPLACE mode, we also have to fix the replace stack.  In this case
1394     // it is always possible because we backspace over the whole line and then
1395     // put it back again the way we wanted it.
1396     if (State & VREPLACE_FLAG)
1397     {
1398 	// If orig_line didn't allocate, just return.  At least we did the job,
1399 	// even if you can't backspace.
1400 	if (orig_line == NULL)
1401 	    return;
1402 
1403 	// Save new line
1404 	new_line = vim_strsave(ml_get_curline());
1405 	if (new_line == NULL)
1406 	    return;
1407 
1408 	// We only put back the new line up to the cursor
1409 	new_line[curwin->w_cursor.col] = NUL;
1410 
1411 	// Put back original line
1412 	ml_replace(curwin->w_cursor.lnum, orig_line, FALSE);
1413 	curwin->w_cursor.col = orig_col;
1414 
1415 	// Backspace from cursor to start of line
1416 	backspace_until_column(0);
1417 
1418 	// Insert new stuff into line again
1419 	ins_bytes(new_line);
1420 
1421 	vim_free(new_line);
1422     }
1423 }
1424 
1425 /*
1426  * Copy the indent from ptr to the current line (and fill to size)
1427  * Leaves the cursor on the first non-blank in the line.
1428  * Returns TRUE if the line was changed.
1429  */
1430     int
copy_indent(int size,char_u * src)1431 copy_indent(int size, char_u *src)
1432 {
1433     char_u	*p = NULL;
1434     char_u	*line = NULL;
1435     char_u	*s;
1436     int		todo;
1437     int		ind_len;
1438     int		line_len = 0;
1439     int		tab_pad;
1440     int		ind_done;
1441     int		round;
1442 #ifdef FEAT_VARTABS
1443     int		ind_col;
1444 #endif
1445 
1446     // Round 1: compute the number of characters needed for the indent
1447     // Round 2: copy the characters.
1448     for (round = 1; round <= 2; ++round)
1449     {
1450 	todo = size;
1451 	ind_len = 0;
1452 	ind_done = 0;
1453 #ifdef FEAT_VARTABS
1454 	ind_col = 0;
1455 #endif
1456 	s = src;
1457 
1458 	// Count/copy the usable portion of the source line
1459 	while (todo > 0 && VIM_ISWHITE(*s))
1460 	{
1461 	    if (*s == TAB)
1462 	    {
1463 #ifdef FEAT_VARTABS
1464 		tab_pad = tabstop_padding(ind_done, curbuf->b_p_ts,
1465 							curbuf->b_p_vts_array);
1466 #else
1467 		tab_pad = (int)curbuf->b_p_ts
1468 					   - (ind_done % (int)curbuf->b_p_ts);
1469 #endif
1470 		// Stop if this tab will overshoot the target
1471 		if (todo < tab_pad)
1472 		    break;
1473 		todo -= tab_pad;
1474 		ind_done += tab_pad;
1475 #ifdef FEAT_VARTABS
1476 		ind_col += tab_pad;
1477 #endif
1478 	    }
1479 	    else
1480 	    {
1481 		--todo;
1482 		++ind_done;
1483 #ifdef FEAT_VARTABS
1484 		++ind_col;
1485 #endif
1486 	    }
1487 	    ++ind_len;
1488 	    if (p != NULL)
1489 		*p++ = *s;
1490 	    ++s;
1491 	}
1492 
1493 	// Fill to next tabstop with a tab, if possible
1494 #ifdef FEAT_VARTABS
1495 	tab_pad = tabstop_padding(ind_done, curbuf->b_p_ts,
1496 							curbuf->b_p_vts_array);
1497 #else
1498 	tab_pad = (int)curbuf->b_p_ts - (ind_done % (int)curbuf->b_p_ts);
1499 #endif
1500 	if (todo >= tab_pad && !curbuf->b_p_et)
1501 	{
1502 	    todo -= tab_pad;
1503 	    ++ind_len;
1504 #ifdef FEAT_VARTABS
1505 	    ind_col += tab_pad;
1506 #endif
1507 	    if (p != NULL)
1508 		*p++ = TAB;
1509 	}
1510 
1511 	// Add tabs required for indent
1512 	if (!curbuf->b_p_et)
1513 	{
1514 #ifdef FEAT_VARTABS
1515 	    for (;;)
1516 	    {
1517 		tab_pad = tabstop_padding(ind_col, curbuf->b_p_ts,
1518 							curbuf->b_p_vts_array);
1519 		if (todo < tab_pad)
1520 		    break;
1521 		todo -= tab_pad;
1522 		++ind_len;
1523 		ind_col += tab_pad;
1524 		if (p != NULL)
1525 		    *p++ = TAB;
1526 	    }
1527 #else
1528 	    while (todo >= (int)curbuf->b_p_ts)
1529 	    {
1530 		todo -= (int)curbuf->b_p_ts;
1531 		++ind_len;
1532 		if (p != NULL)
1533 		    *p++ = TAB;
1534 	    }
1535 #endif
1536 	}
1537 
1538 	// Count/add spaces required for indent
1539 	while (todo > 0)
1540 	{
1541 	    --todo;
1542 	    ++ind_len;
1543 	    if (p != NULL)
1544 		*p++ = ' ';
1545 	}
1546 
1547 	if (p == NULL)
1548 	{
1549 	    // Allocate memory for the result: the copied indent, new indent
1550 	    // and the rest of the line.
1551 	    line_len = (int)STRLEN(ml_get_curline()) + 1;
1552 	    line = alloc(ind_len + line_len);
1553 	    if (line == NULL)
1554 		return FALSE;
1555 	    p = line;
1556 	}
1557     }
1558 
1559     // Append the original line
1560     mch_memmove(p, ml_get_curline(), (size_t)line_len);
1561 
1562     // Replace the line
1563     ml_replace(curwin->w_cursor.lnum, line, FALSE);
1564 
1565     // Put the cursor after the indent.
1566     curwin->w_cursor.col = ind_len;
1567     return TRUE;
1568 }
1569 
1570 /*
1571  * ":retab".
1572  */
1573     void
ex_retab(exarg_T * eap)1574 ex_retab(exarg_T *eap)
1575 {
1576     linenr_T	lnum;
1577     int		got_tab = FALSE;
1578     long	num_spaces = 0;
1579     long	num_tabs;
1580     long	len;
1581     long	col;
1582     long	vcol;
1583     long	start_col = 0;		// For start of white-space string
1584     long	start_vcol = 0;		// For start of white-space string
1585     long	old_len;
1586     char_u	*ptr;
1587     char_u	*new_line = (char_u *)1; // init to non-NULL
1588     int		did_undo;		// called u_save for current line
1589 #ifdef FEAT_VARTABS
1590     int		*new_vts_array = NULL;
1591     char_u	*new_ts_str;		// string value of tab argument
1592 #else
1593     int		temp;
1594     int		new_ts;
1595 #endif
1596     int		save_list;
1597     linenr_T	first_line = 0;		// first changed line
1598     linenr_T	last_line = 0;		// last changed line
1599 
1600     save_list = curwin->w_p_list;
1601     curwin->w_p_list = 0;	    // don't want list mode here
1602 
1603 #ifdef FEAT_VARTABS
1604     new_ts_str = eap->arg;
1605     if (tabstop_set(eap->arg, &new_vts_array) == FAIL)
1606 	return;
1607     while (vim_isdigit(*(eap->arg)) || *(eap->arg) == ',')
1608 	++(eap->arg);
1609 
1610     // This ensures that either new_vts_array and new_ts_str are freshly
1611     // allocated, or new_vts_array points to an existing array and new_ts_str
1612     // is null.
1613     if (new_vts_array == NULL)
1614     {
1615 	new_vts_array = curbuf->b_p_vts_array;
1616 	new_ts_str = NULL;
1617     }
1618     else
1619 	new_ts_str = vim_strnsave(new_ts_str, eap->arg - new_ts_str);
1620 #else
1621     ptr = eap->arg;
1622     new_ts = getdigits(&ptr);
1623     if (new_ts < 0 && *eap->arg == '-')
1624     {
1625 	emsg(_(e_positive));
1626 	return;
1627     }
1628     if (new_ts < 0 || new_ts > 9999)
1629     {
1630 	semsg(_(e_invarg2), eap->arg);
1631 	return;
1632     }
1633     if (new_ts == 0)
1634 	new_ts = curbuf->b_p_ts;
1635 #endif
1636     for (lnum = eap->line1; !got_int && lnum <= eap->line2; ++lnum)
1637     {
1638 	ptr = ml_get(lnum);
1639 	col = 0;
1640 	vcol = 0;
1641 	did_undo = FALSE;
1642 	for (;;)
1643 	{
1644 	    if (VIM_ISWHITE(ptr[col]))
1645 	    {
1646 		if (!got_tab && num_spaces == 0)
1647 		{
1648 		    // First consecutive white-space
1649 		    start_vcol = vcol;
1650 		    start_col = col;
1651 		}
1652 		if (ptr[col] == ' ')
1653 		    num_spaces++;
1654 		else
1655 		    got_tab = TRUE;
1656 	    }
1657 	    else
1658 	    {
1659 		if (got_tab || (eap->forceit && num_spaces > 1))
1660 		{
1661 		    // Retabulate this string of white-space
1662 
1663 		    // len is virtual length of white string
1664 		    len = num_spaces = vcol - start_vcol;
1665 		    num_tabs = 0;
1666 		    if (!curbuf->b_p_et)
1667 		    {
1668 #ifdef FEAT_VARTABS
1669 			int t, s;
1670 
1671 			tabstop_fromto(start_vcol, vcol,
1672 					curbuf->b_p_ts, new_vts_array, &t, &s);
1673 			num_tabs = t;
1674 			num_spaces = s;
1675 #else
1676 			temp = new_ts - (start_vcol % new_ts);
1677 			if (num_spaces >= temp)
1678 			{
1679 			    num_spaces -= temp;
1680 			    num_tabs++;
1681 			}
1682 			num_tabs += num_spaces / new_ts;
1683 			num_spaces -= (num_spaces / new_ts) * new_ts;
1684 #endif
1685 		    }
1686 		    if (curbuf->b_p_et || got_tab ||
1687 					(num_spaces + num_tabs < len))
1688 		    {
1689 			if (did_undo == FALSE)
1690 			{
1691 			    did_undo = TRUE;
1692 			    if (u_save((linenr_T)(lnum - 1),
1693 						(linenr_T)(lnum + 1)) == FAIL)
1694 			    {
1695 				new_line = NULL;	// flag out-of-memory
1696 				break;
1697 			    }
1698 			}
1699 
1700 			// len is actual number of white characters used
1701 			len = num_spaces + num_tabs;
1702 			old_len = (long)STRLEN(ptr);
1703 			new_line = alloc(old_len - col + start_col + len + 1);
1704 			if (new_line == NULL)
1705 			    break;
1706 			if (start_col > 0)
1707 			    mch_memmove(new_line, ptr, (size_t)start_col);
1708 			mch_memmove(new_line + start_col + len,
1709 				      ptr + col, (size_t)(old_len - col + 1));
1710 			ptr = new_line + start_col;
1711 			for (col = 0; col < len; col++)
1712 			    ptr[col] = (col < num_tabs) ? '\t' : ' ';
1713 			if (ml_replace(lnum, new_line, FALSE) == OK)
1714 			    // "new_line" may have been copied
1715 			    new_line = curbuf->b_ml.ml_line_ptr;
1716 			if (first_line == 0)
1717 			    first_line = lnum;
1718 			last_line = lnum;
1719 			ptr = new_line;
1720 			col = start_col + len;
1721 		    }
1722 		}
1723 		got_tab = FALSE;
1724 		num_spaces = 0;
1725 	    }
1726 	    if (ptr[col] == NUL)
1727 		break;
1728 	    vcol += chartabsize(ptr + col, (colnr_T)vcol);
1729 	    if (has_mbyte)
1730 		col += (*mb_ptr2len)(ptr + col);
1731 	    else
1732 		++col;
1733 	}
1734 	if (new_line == NULL)		    // out of memory
1735 	    break;
1736 	line_breakcheck();
1737     }
1738     if (got_int)
1739 	emsg(_(e_interr));
1740 
1741 #ifdef FEAT_VARTABS
1742     // If a single value was given then it can be considered equal to
1743     // either the value of 'tabstop' or the value of 'vartabstop'.
1744     if (tabstop_count(curbuf->b_p_vts_array) == 0
1745 	&& tabstop_count(new_vts_array) == 1
1746 	&& curbuf->b_p_ts == tabstop_first(new_vts_array))
1747 	; // not changed
1748     else if (tabstop_count(curbuf->b_p_vts_array) > 0
1749         && tabstop_eq(curbuf->b_p_vts_array, new_vts_array))
1750 	; // not changed
1751     else
1752 	redraw_curbuf_later(NOT_VALID);
1753 #else
1754     if (curbuf->b_p_ts != new_ts)
1755 	redraw_curbuf_later(NOT_VALID);
1756 #endif
1757     if (first_line != 0)
1758 	changed_lines(first_line, 0, last_line + 1, 0L);
1759 
1760     curwin->w_p_list = save_list;	// restore 'list'
1761 
1762 #ifdef FEAT_VARTABS
1763     if (new_ts_str != NULL)		// set the new tabstop
1764     {
1765 	// If 'vartabstop' is in use or if the value given to retab has more
1766 	// than one tabstop then update 'vartabstop'.
1767 	int *old_vts_ary = curbuf->b_p_vts_array;
1768 
1769 	if (tabstop_count(old_vts_ary) > 0 || tabstop_count(new_vts_array) > 1)
1770 	{
1771 	    set_string_option_direct((char_u *)"vts", -1, new_ts_str,
1772 							OPT_FREE|OPT_LOCAL, 0);
1773 	    curbuf->b_p_vts_array = new_vts_array;
1774 	    vim_free(old_vts_ary);
1775 	}
1776 	else
1777 	{
1778 	    // 'vartabstop' wasn't in use and a single value was given to
1779 	    // retab then update 'tabstop'.
1780 	    curbuf->b_p_ts = tabstop_first(new_vts_array);
1781 	    vim_free(new_vts_array);
1782 	}
1783 	vim_free(new_ts_str);
1784     }
1785 #else
1786     curbuf->b_p_ts = new_ts;
1787 #endif
1788     coladvance(curwin->w_curswant);
1789 
1790     u_clearline();
1791 }
1792 
1793 #if (defined(FEAT_CINDENT) && defined(FEAT_EVAL)) || defined(PROTO)
1794 /*
1795  * Get indent level from 'indentexpr'.
1796  */
1797     int
get_expr_indent(void)1798 get_expr_indent(void)
1799 {
1800     int		indent = -1;
1801     char_u	*inde_copy;
1802     pos_T	save_pos;
1803     colnr_T	save_curswant;
1804     int		save_set_curswant;
1805     int		save_State;
1806     int		use_sandbox = was_set_insecurely((char_u *)"indentexpr",
1807 								   OPT_LOCAL);
1808 
1809     // Save and restore cursor position and curswant, in case it was changed
1810     // via :normal commands
1811     save_pos = curwin->w_cursor;
1812     save_curswant = curwin->w_curswant;
1813     save_set_curswant = curwin->w_set_curswant;
1814     set_vim_var_nr(VV_LNUM, curwin->w_cursor.lnum);
1815     if (use_sandbox)
1816 	++sandbox;
1817     ++textwinlock;
1818 
1819     // Need to make a copy, the 'indentexpr' option could be changed while
1820     // evaluating it.
1821     inde_copy = vim_strsave(curbuf->b_p_inde);
1822     if (inde_copy != NULL)
1823     {
1824 	indent = (int)eval_to_number(inde_copy);
1825 	vim_free(inde_copy);
1826     }
1827 
1828     if (use_sandbox)
1829 	--sandbox;
1830     --textwinlock;
1831 
1832     // Restore the cursor position so that 'indentexpr' doesn't need to.
1833     // Pretend to be in Insert mode, allow cursor past end of line for "o"
1834     // command.
1835     save_State = State;
1836     State = INSERT;
1837     curwin->w_cursor = save_pos;
1838     curwin->w_curswant = save_curswant;
1839     curwin->w_set_curswant = save_set_curswant;
1840     check_cursor();
1841     State = save_State;
1842 
1843     // Reset did_throw, unless 'debug' has "throw" and inside a try/catch.
1844     if (did_throw && (vim_strchr(p_debug, 't') == NULL || trylevel == 0))
1845     {
1846 	handle_did_throw();
1847 	did_throw = FALSE;
1848     }
1849 
1850     // If there is an error, just keep the current indent.
1851     if (indent < 0)
1852 	indent = get_indent();
1853 
1854     return indent;
1855 }
1856 #endif
1857 
1858 #if defined(FEAT_LISP) || defined(PROTO)
1859 
1860     static int
lisp_match(char_u * p)1861 lisp_match(char_u *p)
1862 {
1863     char_u	buf[LSIZE];
1864     int		len;
1865     char_u	*word = *curbuf->b_p_lw != NUL ? curbuf->b_p_lw : p_lispwords;
1866 
1867     while (*word != NUL)
1868     {
1869 	(void)copy_option_part(&word, buf, LSIZE, ",");
1870 	len = (int)STRLEN(buf);
1871 	if (STRNCMP(buf, p, len) == 0 && p[len] == ' ')
1872 	    return TRUE;
1873     }
1874     return FALSE;
1875 }
1876 
1877 /*
1878  * When 'p' is present in 'cpoptions, a Vi compatible method is used.
1879  * The incompatible newer method is quite a bit better at indenting
1880  * code in lisp-like languages than the traditional one; it's still
1881  * mostly heuristics however -- Dirk van Deun, [email protected]
1882  *
1883  * TODO:
1884  * Findmatch() should be adapted for lisp, also to make showmatch
1885  * work correctly: now (v5.3) it seems all C/C++ oriented:
1886  * - it does not recognize the #\( and #\) notations as character literals
1887  * - it doesn't know about comments starting with a semicolon
1888  * - it incorrectly interprets '(' as a character literal
1889  * All this messes up get_lisp_indent in some rare cases.
1890  * Update from Sergey Khorev:
1891  * I tried to fix the first two issues.
1892  */
1893     int
get_lisp_indent(void)1894 get_lisp_indent(void)
1895 {
1896     pos_T	*pos, realpos, paren;
1897     int		amount;
1898     char_u	*that;
1899     colnr_T	col;
1900     colnr_T	firsttry;
1901     int		parencount, quotecount;
1902     int		vi_lisp;
1903 
1904     // Set vi_lisp to use the vi-compatible method
1905     vi_lisp = (vim_strchr(p_cpo, CPO_LISP) != NULL);
1906 
1907     realpos = curwin->w_cursor;
1908     curwin->w_cursor.col = 0;
1909 
1910     if ((pos = findmatch(NULL, '(')) == NULL)
1911 	pos = findmatch(NULL, '[');
1912     else
1913     {
1914 	paren = *pos;
1915 	pos = findmatch(NULL, '[');
1916 	if (pos == NULL || LT_POSP(pos, &paren))
1917 	    pos = &paren;
1918     }
1919     if (pos != NULL)
1920     {
1921 	// Extra trick: Take the indent of the first previous non-white
1922 	// line that is at the same () level.
1923 	amount = -1;
1924 	parencount = 0;
1925 
1926 	while (--curwin->w_cursor.lnum >= pos->lnum)
1927 	{
1928 	    if (linewhite(curwin->w_cursor.lnum))
1929 		continue;
1930 	    for (that = ml_get_curline(); *that != NUL; ++that)
1931 	    {
1932 		if (*that == ';')
1933 		{
1934 		    while (*(that + 1) != NUL)
1935 			++that;
1936 		    continue;
1937 		}
1938 		if (*that == '\\')
1939 		{
1940 		    if (*(that + 1) != NUL)
1941 			++that;
1942 		    continue;
1943 		}
1944 		if (*that == '"' && *(that + 1) != NUL)
1945 		{
1946 		    while (*++that && *that != '"')
1947 		    {
1948 			// skipping escaped characters in the string
1949 			if (*that == '\\')
1950 			{
1951 			    if (*++that == NUL)
1952 				break;
1953 			    if (that[1] == NUL)
1954 			    {
1955 				++that;
1956 				break;
1957 			    }
1958 			}
1959 		    }
1960 		}
1961 		if (*that == '(' || *that == '[')
1962 		    ++parencount;
1963 		else if (*that == ')' || *that == ']')
1964 		    --parencount;
1965 	    }
1966 	    if (parencount == 0)
1967 	    {
1968 		amount = get_indent();
1969 		break;
1970 	    }
1971 	}
1972 
1973 	if (amount == -1)
1974 	{
1975 	    curwin->w_cursor.lnum = pos->lnum;
1976 	    curwin->w_cursor.col = pos->col;
1977 	    col = pos->col;
1978 
1979 	    that = ml_get_curline();
1980 
1981 	    if (vi_lisp && get_indent() == 0)
1982 		amount = 2;
1983 	    else
1984 	    {
1985 		char_u *line = that;
1986 
1987 		amount = 0;
1988 		while (*that && col)
1989 		{
1990 		    amount += lbr_chartabsize_adv(line, &that, (colnr_T)amount);
1991 		    col--;
1992 		}
1993 
1994 		// Some keywords require "body" indenting rules (the
1995 		// non-standard-lisp ones are Scheme special forms):
1996 		//
1997 		// (let ((a 1))    instead    (let ((a 1))
1998 		//   (...))	      of	   (...))
1999 
2000 		if (!vi_lisp && (*that == '(' || *that == '[')
2001 						      && lisp_match(that + 1))
2002 		    amount += 2;
2003 		else
2004 		{
2005 		    that++;
2006 		    amount++;
2007 		    firsttry = amount;
2008 
2009 		    while (VIM_ISWHITE(*that))
2010 		    {
2011 			amount += lbr_chartabsize(line, that, (colnr_T)amount);
2012 			++that;
2013 		    }
2014 
2015 		    if (*that && *that != ';') // not a comment line
2016 		    {
2017 			// test *that != '(' to accommodate first let/do
2018 			// argument if it is more than one line
2019 			if (!vi_lisp && *that != '(' && *that != '[')
2020 			    firsttry++;
2021 
2022 			parencount = 0;
2023 			quotecount = 0;
2024 
2025 			if (vi_lisp
2026 				|| (*that != '"'
2027 				    && *that != '\''
2028 				    && *that != '#'
2029 				    && (*that < '0' || *that > '9')))
2030 			{
2031 			    while (*that
2032 				    && (!VIM_ISWHITE(*that)
2033 					|| quotecount
2034 					|| parencount)
2035 				    && (!((*that == '(' || *that == '[')
2036 					    && !quotecount
2037 					    && !parencount
2038 					    && vi_lisp)))
2039 			    {
2040 				if (*that == '"')
2041 				    quotecount = !quotecount;
2042 				if ((*that == '(' || *that == '[')
2043 							       && !quotecount)
2044 				    ++parencount;
2045 				if ((*that == ')' || *that == ']')
2046 							       && !quotecount)
2047 				    --parencount;
2048 				if (*that == '\\' && *(that+1) != NUL)
2049 				    amount += lbr_chartabsize_adv(
2050 						line, &that, (colnr_T)amount);
2051 				amount += lbr_chartabsize_adv(
2052 						line, &that, (colnr_T)amount);
2053 			    }
2054 			}
2055 			while (VIM_ISWHITE(*that))
2056 			{
2057 			    amount += lbr_chartabsize(
2058 						 line, that, (colnr_T)amount);
2059 			    that++;
2060 			}
2061 			if (!*that || *that == ';')
2062 			    amount = firsttry;
2063 		    }
2064 		}
2065 	    }
2066 	}
2067     }
2068     else
2069 	amount = 0;	// no matching '(' or '[' found, use zero indent
2070 
2071     curwin->w_cursor = realpos;
2072 
2073     return amount;
2074 }
2075 #endif // FEAT_LISP
2076 
2077 #if defined(FEAT_LISP) || defined(FEAT_CINDENT) || defined(PROTO)
2078 /*
2079  * Re-indent the current line, based on the current contents of it and the
2080  * surrounding lines. Fixing the cursor position seems really easy -- I'm very
2081  * confused what all the part that handles Control-T is doing that I'm not.
2082  * "get_the_indent" should be get_c_indent, get_expr_indent or get_lisp_indent.
2083  */
2084 
2085     void
fixthisline(int (* get_the_indent)(void))2086 fixthisline(int (*get_the_indent)(void))
2087 {
2088     int amount = get_the_indent();
2089 
2090     if (amount >= 0)
2091     {
2092 	change_indent(INDENT_SET, amount, FALSE, 0, TRUE);
2093 	if (linewhite(curwin->w_cursor.lnum))
2094 	    did_ai = TRUE;	// delete the indent if the line stays empty
2095     }
2096 }
2097 
2098     void
fix_indent(void)2099 fix_indent(void)
2100 {
2101     if (p_paste)
2102 	return;
2103 # ifdef FEAT_LISP
2104     if (curbuf->b_p_lisp && curbuf->b_p_ai)
2105 	fixthisline(get_lisp_indent);
2106 # endif
2107 # if defined(FEAT_LISP) && defined(FEAT_CINDENT)
2108     else
2109 # endif
2110 # ifdef FEAT_CINDENT
2111 	if (cindent_on())
2112 	    do_c_expr_indent();
2113 # endif
2114 }
2115 #endif
2116 
2117 #if defined(FEAT_EVAL) || defined(PROTO)
2118 /*
2119  * "indent()" function
2120  */
2121     void
f_indent(typval_T * argvars,typval_T * rettv)2122 f_indent(typval_T *argvars, typval_T *rettv)
2123 {
2124     linenr_T	lnum;
2125 
2126     if (in_vim9script() && check_for_lnum_arg(argvars, 0) == FAIL)
2127 	return;
2128 
2129     lnum = tv_get_lnum(argvars);
2130     if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2131 	rettv->vval.v_number = get_indent_lnum(lnum);
2132     else
2133 	rettv->vval.v_number = -1;
2134 }
2135 
2136 /*
2137  * "lispindent(lnum)" function
2138  */
2139     void
f_lispindent(typval_T * argvars UNUSED,typval_T * rettv)2140 f_lispindent(typval_T *argvars UNUSED, typval_T *rettv)
2141 {
2142 #ifdef FEAT_LISP
2143     pos_T	pos;
2144     linenr_T	lnum;
2145 
2146     if (in_vim9script() && check_for_lnum_arg(argvars, 0) == FAIL)
2147 	return;
2148 
2149     pos = curwin->w_cursor;
2150     lnum = tv_get_lnum(argvars);
2151     if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count)
2152     {
2153 	curwin->w_cursor.lnum = lnum;
2154 	rettv->vval.v_number = get_lisp_indent();
2155 	curwin->w_cursor = pos;
2156     }
2157     else
2158 #endif
2159 	rettv->vval.v_number = -1;
2160 }
2161 #endif
2162