xref: /vim-8.2.3635/src/change.c (revision 4b4b1b84)
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  * change.c: functions related to changing text
12  */
13 
14 #include "vim.h"
15 
16 /*
17  * If the file is readonly, give a warning message with the first change.
18  * Don't do this for autocommands.
19  * Doesn't use emsg(), because it flushes the macro buffer.
20  * If we have undone all changes b_changed will be FALSE, but "b_did_warn"
21  * will be TRUE.
22  * "col" is the column for the message; non-zero when in insert mode and
23  * 'showmode' is on.
24  * Careful: may trigger autocommands that reload the buffer.
25  */
26     void
change_warning(int col)27 change_warning(int col)
28 {
29     static char *w_readonly = N_("W10: Warning: Changing a readonly file");
30 
31     if (curbuf->b_did_warn == FALSE
32 	    && curbufIsChanged() == 0
33 	    && !autocmd_busy
34 	    && curbuf->b_p_ro)
35     {
36 	++curbuf_lock;
37 	apply_autocmds(EVENT_FILECHANGEDRO, NULL, NULL, FALSE, curbuf);
38 	--curbuf_lock;
39 	if (!curbuf->b_p_ro)
40 	    return;
41 
42 	// Do what msg() does, but with a column offset if the warning should
43 	// be after the mode message.
44 	msg_start();
45 	if (msg_row == Rows - 1)
46 	    msg_col = col;
47 	msg_source(HL_ATTR(HLF_W));
48 	msg_puts_attr(_(w_readonly), HL_ATTR(HLF_W) | MSG_HIST);
49 #ifdef FEAT_EVAL
50 	set_vim_var_string(VV_WARNINGMSG, (char_u *)_(w_readonly), -1);
51 #endif
52 	msg_clr_eos();
53 	(void)msg_end();
54 	if (msg_silent == 0 && !silent_mode
55 #ifdef FEAT_EVAL
56 		&& time_for_testing != 1
57 #endif
58 		)
59 	{
60 	    out_flush();
61 	    ui_delay(1002L, TRUE); // give the user time to think about it
62 	}
63 	curbuf->b_did_warn = TRUE;
64 	redraw_cmdline = FALSE;	// don't redraw and erase the message
65 	if (msg_row < Rows - 1)
66 	    showmode();
67     }
68 }
69 
70 /*
71  * Call this function when something in the current buffer is changed.
72  *
73  * Most often called through changed_bytes() and changed_lines(), which also
74  * mark the area of the display to be redrawn.
75  *
76  * Careful: may trigger autocommands that reload the buffer.
77  */
78     void
changed(void)79 changed(void)
80 {
81 #if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
82     if (p_imst == IM_ON_THE_SPOT)
83     {
84 	// The text of the preediting area is inserted, but this doesn't
85 	// mean a change of the buffer yet.  That is delayed until the
86 	// text is committed. (this means preedit becomes empty)
87 	if (im_is_preediting() && !xim_changed_while_preediting)
88 	    return;
89 	xim_changed_while_preediting = FALSE;
90     }
91 #endif
92 
93     if (!curbuf->b_changed)
94     {
95 	int	save_msg_scroll = msg_scroll;
96 
97 	// Give a warning about changing a read-only file.  This may also
98 	// check-out the file, thus change "curbuf"!
99 	change_warning(0);
100 
101 	// Create a swap file if that is wanted.
102 	// Don't do this for "nofile" and "nowrite" buffer types.
103 	if (curbuf->b_may_swap
104 #ifdef FEAT_QUICKFIX
105 		&& !bt_dontwrite(curbuf)
106 #endif
107 		)
108 	{
109 	    int save_need_wait_return = need_wait_return;
110 
111 	    need_wait_return = FALSE;
112 	    ml_open_file(curbuf);
113 
114 	    // The ml_open_file() can cause an ATTENTION message.
115 	    // Wait two seconds, to make sure the user reads this unexpected
116 	    // message.  Since we could be anywhere, call wait_return() now,
117 	    // and don't let the emsg() set msg_scroll.
118 	    if (need_wait_return && emsg_silent == 0 && !in_assert_fails)
119 	    {
120 		out_flush();
121 		ui_delay(2002L, TRUE);
122 		wait_return(TRUE);
123 		msg_scroll = save_msg_scroll;
124 	    }
125 	    else
126 		need_wait_return = save_need_wait_return;
127 	}
128 	changed_internal();
129     }
130     ++CHANGEDTICK(curbuf);
131 
132 #ifdef FEAT_SEARCH_EXTRA
133     // If a pattern is highlighted, the position may now be invalid.
134     highlight_match = FALSE;
135 #endif
136 }
137 
138 /*
139  * Internal part of changed(), no user interaction.
140  * Also used for recovery.
141  */
142     void
changed_internal(void)143 changed_internal(void)
144 {
145     curbuf->b_changed = TRUE;
146     ml_setflags(curbuf);
147     check_status(curbuf);
148     redraw_tabline = TRUE;
149 #ifdef FEAT_TITLE
150     need_maketitle = TRUE;	    // set window title later
151 #endif
152 }
153 
154 #ifdef FEAT_EVAL
155 static long next_listener_id = 0;
156 
157 /*
158  * Check if the change at "lnum" is above or overlaps with an existing
159  * change. If above then flush changes and invoke listeners.
160  * Returns TRUE if the change was merged.
161  */
162     static int
check_recorded_changes(buf_T * buf,linenr_T lnum,linenr_T lnume,long xtra)163 check_recorded_changes(
164 	buf_T		*buf,
165 	linenr_T	lnum,
166 	linenr_T	lnume,
167 	long		xtra)
168 {
169     if (buf->b_recorded_changes != NULL && xtra != 0)
170     {
171 	listitem_T *li;
172 	linenr_T    prev_lnum;
173 	linenr_T    prev_lnume;
174 
175 	FOR_ALL_LIST_ITEMS(buf->b_recorded_changes, li)
176 	{
177 	    prev_lnum = (linenr_T)dict_get_number(
178 				      li->li_tv.vval.v_dict, (char_u *)"lnum");
179 	    prev_lnume = (linenr_T)dict_get_number(
180 				       li->li_tv.vval.v_dict, (char_u *)"end");
181 	    if (prev_lnum >= lnum || prev_lnum > lnume || prev_lnume >= lnum)
182 	    {
183 		// the current change is going to make the line number in
184 		// the older change invalid, flush now
185 		invoke_listeners(curbuf);
186 		break;
187 	    }
188 	}
189     }
190     return FALSE;
191 }
192 
193 /*
194  * Record a change for listeners added with listener_add().
195  * Always for the current buffer.
196  */
197     static void
may_record_change(linenr_T lnum,colnr_T col,linenr_T lnume,long xtra)198 may_record_change(
199     linenr_T	lnum,
200     colnr_T	col,
201     linenr_T	lnume,
202     long	xtra)
203 {
204     dict_T	*dict;
205 
206     if (curbuf->b_listener == NULL)
207 	return;
208 
209     // If the new change is going to change the line numbers in already listed
210     // changes, then flush.
211     if (check_recorded_changes(curbuf, lnum, lnume, xtra))
212 	return;
213 
214     if (curbuf->b_recorded_changes == NULL)
215     {
216 	curbuf->b_recorded_changes = list_alloc();
217 	if (curbuf->b_recorded_changes == NULL)  // out of memory
218 	    return;
219 	++curbuf->b_recorded_changes->lv_refcount;
220 	curbuf->b_recorded_changes->lv_lock = VAR_FIXED;
221     }
222 
223     dict = dict_alloc();
224     if (dict == NULL)
225 	return;
226     dict_add_number(dict, "lnum", (varnumber_T)lnum);
227     dict_add_number(dict, "end", (varnumber_T)lnume);
228     dict_add_number(dict, "added", (varnumber_T)xtra);
229     dict_add_number(dict, "col", (varnumber_T)col + 1);
230 
231     list_append_dict(curbuf->b_recorded_changes, dict);
232 }
233 
234 /*
235  * listener_add() function
236  */
237     void
f_listener_add(typval_T * argvars,typval_T * rettv)238 f_listener_add(typval_T *argvars, typval_T *rettv)
239 {
240     callback_T	callback;
241     listener_T	*lnr;
242     buf_T	*buf = curbuf;
243 
244     if (in_vim9script() && check_for_opt_buffer_arg(argvars, 1) == FAIL)
245 	return;
246 
247     callback = get_callback(&argvars[0]);
248     if (callback.cb_name == NULL)
249 	return;
250 
251     if (argvars[1].v_type != VAR_UNKNOWN)
252     {
253 	buf = get_buf_arg(&argvars[1]);
254 	if (buf == NULL)
255 	{
256 	    free_callback(&callback);
257 	    return;
258 	}
259     }
260 
261     lnr = ALLOC_CLEAR_ONE(listener_T);
262     if (lnr == NULL)
263     {
264 	free_callback(&callback);
265 	return;
266     }
267     lnr->lr_next = buf->b_listener;
268     buf->b_listener = lnr;
269 
270     set_callback(&lnr->lr_callback, &callback);
271 
272     lnr->lr_id = ++next_listener_id;
273     rettv->vval.v_number = lnr->lr_id;
274 }
275 
276 /*
277  * listener_flush() function
278  */
279     void
f_listener_flush(typval_T * argvars,typval_T * rettv UNUSED)280 f_listener_flush(typval_T *argvars, typval_T *rettv UNUSED)
281 {
282     buf_T	*buf = curbuf;
283 
284     if (in_vim9script() && check_for_opt_buffer_arg(argvars, 0) == FAIL)
285 	return;
286 
287     if (argvars[0].v_type != VAR_UNKNOWN)
288     {
289 	buf = get_buf_arg(&argvars[0]);
290 	if (buf == NULL)
291 	    return;
292     }
293     invoke_listeners(buf);
294 }
295 
296 
297     static void
remove_listener(buf_T * buf,listener_T * lnr,listener_T * prev)298 remove_listener(buf_T *buf, listener_T *lnr, listener_T *prev)
299 {
300     if (prev != NULL)
301 	prev->lr_next = lnr->lr_next;
302     else
303 	buf->b_listener = lnr->lr_next;
304     free_callback(&lnr->lr_callback);
305     vim_free(lnr);
306 }
307 
308 /*
309  * listener_remove() function
310  */
311     void
f_listener_remove(typval_T * argvars,typval_T * rettv)312 f_listener_remove(typval_T *argvars, typval_T *rettv)
313 {
314     listener_T	*lnr;
315     listener_T	*next;
316     listener_T	*prev;
317     int		id;
318     buf_T	*buf;
319 
320     if (in_vim9script() && check_for_number_arg(argvars, 0) == FAIL)
321 	return;
322 
323     id = tv_get_number(argvars);
324     FOR_ALL_BUFFERS(buf)
325     {
326 	prev = NULL;
327 	for (lnr = buf->b_listener; lnr != NULL; lnr = next)
328 	{
329 	    next = lnr->lr_next;
330 	    if (lnr->lr_id == id)
331 	    {
332 		if (textwinlock > 0)
333 		{
334 		    // in invoke_listeners(), clear ID and delete later
335 		    lnr->lr_id = 0;
336 		    return;
337 		}
338 		remove_listener(buf, lnr, prev);
339 		rettv->vval.v_number = 1;
340 		return;
341 	    }
342 	    prev = lnr;
343 	}
344     }
345 }
346 
347 /*
348  * Called before inserting a line above "lnum"/"lnum3" or deleting line "lnum"
349  * to "lnume".
350  */
351     void
may_invoke_listeners(buf_T * buf,linenr_T lnum,linenr_T lnume,int added)352 may_invoke_listeners(buf_T *buf, linenr_T lnum, linenr_T lnume, int added)
353 {
354     check_recorded_changes(buf, lnum, lnume, added);
355 }
356 
357 /*
358  * Called when a sequence of changes is done: invoke listeners added with
359  * listener_add().
360  */
361     void
invoke_listeners(buf_T * buf)362 invoke_listeners(buf_T *buf)
363 {
364     listener_T	*lnr;
365     typval_T	rettv;
366     typval_T	argv[6];
367     listitem_T	*li;
368     linenr_T	start = MAXLNUM;
369     linenr_T	end = 0;
370     linenr_T	added = 0;
371     int		save_updating_screen = updating_screen;
372     static int	recursive = FALSE;
373     listener_T	*next;
374 
375     if (buf->b_recorded_changes == NULL  // nothing changed
376 	    || buf->b_listener == NULL   // no listeners
377 	    || recursive)		 // already busy
378 	return;
379     recursive = TRUE;
380 
381     // Block messages on channels from being handled, so that they don't make
382     // text changes here.
383     ++updating_screen;
384 
385     argv[0].v_type = VAR_NUMBER;
386     argv[0].vval.v_number = buf->b_fnum; // a:bufnr
387 
388     FOR_ALL_LIST_ITEMS(buf->b_recorded_changes, li)
389     {
390 	varnumber_T lnum;
391 
392 	lnum = dict_get_number(li->li_tv.vval.v_dict, (char_u *)"lnum");
393 	if (start > lnum)
394 	    start = lnum;
395 	lnum = dict_get_number(li->li_tv.vval.v_dict, (char_u *)"end");
396 	if (end < lnum)
397 	    end = lnum;
398 	added += dict_get_number(li->li_tv.vval.v_dict, (char_u *)"added");
399     }
400     argv[1].v_type = VAR_NUMBER;
401     argv[1].vval.v_number = start;
402     argv[2].v_type = VAR_NUMBER;
403     argv[2].vval.v_number = end;
404     argv[3].v_type = VAR_NUMBER;
405     argv[3].vval.v_number = added;
406 
407     argv[4].v_type = VAR_LIST;
408     argv[4].vval.v_list = buf->b_recorded_changes;
409     ++textwinlock;
410 
411     for (lnr = buf->b_listener; lnr != NULL; lnr = lnr->lr_next)
412     {
413 	call_callback(&lnr->lr_callback, -1, &rettv, 5, argv);
414 	clear_tv(&rettv);
415     }
416 
417     // If f_listener_remove() was called may have to remove a listener now.
418     for (lnr = buf->b_listener; lnr != NULL; lnr = next)
419     {
420 	listener_T	*prev = NULL;
421 
422 	next = lnr->lr_next;
423 	if (lnr->lr_id == 0)
424 	    remove_listener(buf, lnr, prev);
425 	else
426 	    prev = lnr;
427     }
428 
429     --textwinlock;
430     list_unref(buf->b_recorded_changes);
431     buf->b_recorded_changes = NULL;
432 
433     if (save_updating_screen)
434 	updating_screen = TRUE;
435     else
436 	after_updating_screen(TRUE);
437     recursive = FALSE;
438 }
439 
440 /*
441  * Remove all listeners associated with "buf".
442  */
443     void
remove_listeners(buf_T * buf)444 remove_listeners(buf_T *buf)
445 {
446     listener_T	*lnr;
447     listener_T	*next;
448 
449     for (lnr = buf->b_listener; lnr != NULL; lnr = next)
450     {
451 	next = lnr->lr_next;
452 	free_callback(&lnr->lr_callback);
453 	vim_free(lnr);
454     }
455     buf->b_listener = NULL;
456 }
457 #endif
458 
459 /*
460  * Common code for when a change was made.
461  * See changed_lines() for the arguments.
462  * Careful: may trigger autocommands that reload the buffer.
463  */
464     static void
changed_common(linenr_T lnum,colnr_T col,linenr_T lnume,long xtra)465 changed_common(
466     linenr_T	lnum,
467     colnr_T	col,
468     linenr_T	lnume,
469     long	xtra)
470 {
471     win_T	*wp;
472     tabpage_T	*tp;
473     int		i;
474 #ifdef FEAT_JUMPLIST
475     int		cols;
476     pos_T	*p;
477     int		add;
478 #endif
479 
480     // mark the buffer as modified
481     changed();
482 
483 #ifdef FEAT_EVAL
484     may_record_change(lnum, col, lnume, xtra);
485 #endif
486 #ifdef FEAT_DIFF
487     if (curwin->w_p_diff && diff_internal())
488 	curtab->tp_diff_update = TRUE;
489 #endif
490 
491     // set the '. mark
492     if ((cmdmod.cmod_flags & CMOD_KEEPJUMPS) == 0)
493     {
494 	curbuf->b_last_change.lnum = lnum;
495 	curbuf->b_last_change.col = col;
496 
497 #ifdef FEAT_JUMPLIST
498 	// Create a new entry if a new undo-able change was started or we
499 	// don't have an entry yet.
500 	if (curbuf->b_new_change || curbuf->b_changelistlen == 0)
501 	{
502 	    if (curbuf->b_changelistlen == 0)
503 		add = TRUE;
504 	    else
505 	    {
506 		// Don't create a new entry when the line number is the same
507 		// as the last one and the column is not too far away.  Avoids
508 		// creating many entries for typing "xxxxx".
509 		p = &curbuf->b_changelist[curbuf->b_changelistlen - 1];
510 		if (p->lnum != lnum)
511 		    add = TRUE;
512 		else
513 		{
514 		    cols = comp_textwidth(FALSE);
515 		    if (cols == 0)
516 			cols = 79;
517 		    add = (p->col + cols < col || col + cols < p->col);
518 		}
519 	    }
520 	    if (add)
521 	    {
522 		// This is the first of a new sequence of undo-able changes
523 		// and it's at some distance of the last change.  Use a new
524 		// position in the changelist.
525 		curbuf->b_new_change = FALSE;
526 
527 		if (curbuf->b_changelistlen == JUMPLISTSIZE)
528 		{
529 		    // changelist is full: remove oldest entry
530 		    curbuf->b_changelistlen = JUMPLISTSIZE - 1;
531 		    mch_memmove(curbuf->b_changelist, curbuf->b_changelist + 1,
532 					  sizeof(pos_T) * (JUMPLISTSIZE - 1));
533 		    FOR_ALL_TAB_WINDOWS(tp, wp)
534 		    {
535 			// Correct position in changelist for other windows on
536 			// this buffer.
537 			if (wp->w_buffer == curbuf && wp->w_changelistidx > 0)
538 			    --wp->w_changelistidx;
539 		    }
540 		}
541 		FOR_ALL_TAB_WINDOWS(tp, wp)
542 		{
543 		    // For other windows, if the position in the changelist is
544 		    // at the end it stays at the end.
545 		    if (wp->w_buffer == curbuf
546 			    && wp->w_changelistidx == curbuf->b_changelistlen)
547 			++wp->w_changelistidx;
548 		}
549 		++curbuf->b_changelistlen;
550 	    }
551 	}
552 	curbuf->b_changelist[curbuf->b_changelistlen - 1] =
553 							curbuf->b_last_change;
554 	// The current window is always after the last change, so that "g,"
555 	// takes you back to it.
556 	curwin->w_changelistidx = curbuf->b_changelistlen;
557 #endif
558     }
559 
560     FOR_ALL_TAB_WINDOWS(tp, wp)
561     {
562 	if (wp->w_buffer == curbuf)
563 	{
564 	    // Mark this window to be redrawn later.
565 	    if (wp->w_redr_type < VALID)
566 		wp->w_redr_type = VALID;
567 
568 	    // Check if a change in the buffer has invalidated the cached
569 	    // values for the cursor.
570 #ifdef FEAT_FOLDING
571 	    // Update the folds for this window.  Can't postpone this, because
572 	    // a following operator might work on the whole fold: ">>dd".
573 	    foldUpdate(wp, lnum, lnume + xtra - 1);
574 
575 	    // The change may cause lines above or below the change to become
576 	    // included in a fold.  Set lnum/lnume to the first/last line that
577 	    // might be displayed differently.
578 	    // Set w_cline_folded here as an efficient way to update it when
579 	    // inserting lines just above a closed fold.
580 	    i = hasFoldingWin(wp, lnum, &lnum, NULL, FALSE, NULL);
581 	    if (wp->w_cursor.lnum == lnum)
582 		wp->w_cline_folded = i;
583 	    i = hasFoldingWin(wp, lnume, NULL, &lnume, FALSE, NULL);
584 	    if (wp->w_cursor.lnum == lnume)
585 		wp->w_cline_folded = i;
586 
587 	    // If the changed line is in a range of previously folded lines,
588 	    // compare with the first line in that range.
589 	    if (wp->w_cursor.lnum <= lnum)
590 	    {
591 		i = find_wl_entry(wp, lnum);
592 		if (i >= 0 && wp->w_cursor.lnum > wp->w_lines[i].wl_lnum)
593 		    changed_line_abv_curs_win(wp);
594 	    }
595 #endif
596 	    if (wp->w_cursor.lnum > lnum)
597 		changed_line_abv_curs_win(wp);
598 	    else if (wp->w_cursor.lnum == lnum && wp->w_cursor.col >= col)
599 		changed_cline_bef_curs_win(wp);
600 	    if (wp->w_botline >= lnum)
601 	    {
602 		if (xtra < 0)
603 		    invalidate_botline_win(wp);
604 		else
605 		    // Assume that botline doesn't change (inserted lines make
606 		    // other lines scroll down below botline).
607 		    approximate_botline_win(wp);
608 	    }
609 
610 	    // Check if any w_lines[] entries have become invalid.
611 	    // For entries below the change: Correct the lnums for
612 	    // inserted/deleted lines.  Makes it possible to stop displaying
613 	    // after the change.
614 	    for (i = 0; i < wp->w_lines_valid; ++i)
615 		if (wp->w_lines[i].wl_valid)
616 		{
617 		    if (wp->w_lines[i].wl_lnum >= lnum)
618 		    {
619 			if (wp->w_lines[i].wl_lnum < lnume)
620 			{
621 			    // line included in change
622 			    wp->w_lines[i].wl_valid = FALSE;
623 			}
624 			else if (xtra != 0)
625 			{
626 			    // line below change
627 			    wp->w_lines[i].wl_lnum += xtra;
628 #ifdef FEAT_FOLDING
629 			    wp->w_lines[i].wl_lastlnum += xtra;
630 #endif
631 			}
632 		    }
633 #ifdef FEAT_FOLDING
634 		    else if (wp->w_lines[i].wl_lastlnum >= lnum)
635 		    {
636 			// change somewhere inside this range of folded lines,
637 			// may need to be redrawn
638 			wp->w_lines[i].wl_valid = FALSE;
639 		    }
640 #endif
641 		}
642 
643 #ifdef FEAT_FOLDING
644 	    // Take care of side effects for setting w_topline when folds have
645 	    // changed.  Esp. when the buffer was changed in another window.
646 	    if (hasAnyFolding(wp))
647 		set_topline(wp, wp->w_topline);
648 #endif
649 	    // Relative numbering may require updating more.
650 	    if (wp->w_p_rnu)
651 		redraw_win_later(wp, SOME_VALID);
652 #ifdef FEAT_SYN_HL
653 	    // Cursor line highlighting probably need to be updated with
654 	    // "VALID" if it's below the change.
655 	    // If the cursor line is inside the change we need to redraw more.
656 	    if (wp->w_p_cul)
657 	    {
658 		if (xtra == 0)
659 		    redraw_win_later(wp, VALID);
660 		else if (lnum <= wp->w_last_cursorline)
661 		    redraw_win_later(wp, SOME_VALID);
662 	    }
663 #endif
664 	}
665     }
666 
667     // Call update_screen() later, which checks out what needs to be redrawn,
668     // since it notices b_mod_set and then uses b_mod_*.
669     if (must_redraw < VALID)
670 	must_redraw = VALID;
671 
672     // when the cursor line is changed always trigger CursorMoved
673     if (lnum <= curwin->w_cursor.lnum
674 		 && lnume + (xtra < 0 ? -xtra : xtra) > curwin->w_cursor.lnum)
675 	last_cursormoved.lnum = 0;
676 }
677 
678     static void
changedOneline(buf_T * buf,linenr_T lnum)679 changedOneline(buf_T *buf, linenr_T lnum)
680 {
681     if (buf->b_mod_set)
682     {
683 	// find the maximum area that must be redisplayed
684 	if (lnum < buf->b_mod_top)
685 	    buf->b_mod_top = lnum;
686 	else if (lnum >= buf->b_mod_bot)
687 	    buf->b_mod_bot = lnum + 1;
688     }
689     else
690     {
691 	// set the area that must be redisplayed to one line
692 	buf->b_mod_set = TRUE;
693 	buf->b_mod_top = lnum;
694 	buf->b_mod_bot = lnum + 1;
695 	buf->b_mod_xlines = 0;
696     }
697 }
698 
699 /*
700  * Changed bytes within a single line for the current buffer.
701  * - marks the windows on this buffer to be redisplayed
702  * - marks the buffer changed by calling changed()
703  * - invalidates cached values
704  * Careful: may trigger autocommands that reload the buffer.
705  */
706     void
changed_bytes(linenr_T lnum,colnr_T col)707 changed_bytes(linenr_T lnum, colnr_T col)
708 {
709     changedOneline(curbuf, lnum);
710     changed_common(lnum, col, lnum + 1, 0L);
711 
712 #ifdef FEAT_DIFF
713     // Diff highlighting in other diff windows may need to be updated too.
714     if (curwin->w_p_diff)
715     {
716 	win_T	    *wp;
717 	linenr_T    wlnum;
718 
719 	FOR_ALL_WINDOWS(wp)
720 	    if (wp->w_p_diff && wp != curwin)
721 	    {
722 		redraw_win_later(wp, VALID);
723 		wlnum = diff_lnum_win(lnum, wp);
724 		if (wlnum > 0)
725 		    changedOneline(wp->w_buffer, wlnum);
726 	    }
727     }
728 #endif
729 }
730 
731 /*
732  * Like changed_bytes() but also adjust text properties for "added" bytes.
733  * When "added" is negative text was deleted.
734  */
735     void
inserted_bytes(linenr_T lnum,colnr_T col,int added UNUSED)736 inserted_bytes(linenr_T lnum, colnr_T col, int added UNUSED)
737 {
738 #ifdef FEAT_PROP_POPUP
739     if (curbuf->b_has_textprop && added != 0)
740 	adjust_prop_columns(lnum, col, added, 0);
741 #endif
742 
743     changed_bytes(lnum, col);
744 }
745 
746 /*
747  * Appended "count" lines below line "lnum" in the current buffer.
748  * Must be called AFTER the change and after mark_adjust().
749  * Takes care of marking the buffer to be redrawn and sets the changed flag.
750  */
751     void
appended_lines(linenr_T lnum,long count)752 appended_lines(linenr_T lnum, long count)
753 {
754     changed_lines(lnum + 1, 0, lnum + 1, count);
755 }
756 
757 /*
758  * Like appended_lines(), but adjust marks first.
759  */
760     void
appended_lines_mark(linenr_T lnum,long count)761 appended_lines_mark(linenr_T lnum, long count)
762 {
763     // Skip mark_adjust when adding a line after the last one, there can't
764     // be marks there. But it's still needed in diff mode.
765     if (lnum + count < curbuf->b_ml.ml_line_count
766 #ifdef FEAT_DIFF
767 	    || curwin->w_p_diff
768 #endif
769 	)
770 	mark_adjust(lnum + 1, (linenr_T)MAXLNUM, count, 0L);
771     changed_lines(lnum + 1, 0, lnum + 1, count);
772 }
773 
774 /*
775  * Deleted "count" lines at line "lnum" in the current buffer.
776  * Must be called AFTER the change and after mark_adjust().
777  * Takes care of marking the buffer to be redrawn and sets the changed flag.
778  */
779     void
deleted_lines(linenr_T lnum,long count)780 deleted_lines(linenr_T lnum, long count)
781 {
782     changed_lines(lnum, 0, lnum + count, -count);
783 }
784 
785 /*
786  * Like deleted_lines(), but adjust marks first.
787  * Make sure the cursor is on a valid line before calling, a GUI callback may
788  * be triggered to display the cursor.
789  */
790     void
deleted_lines_mark(linenr_T lnum,long count)791 deleted_lines_mark(linenr_T lnum, long count)
792 {
793     mark_adjust(lnum, (linenr_T)(lnum + count - 1), (long)MAXLNUM, -count);
794     changed_lines(lnum, 0, lnum + count, -count);
795 }
796 
797 /*
798  * Marks the area to be redrawn after a change.
799  */
800     void
changed_lines_buf(buf_T * buf,linenr_T lnum,linenr_T lnume,long xtra)801 changed_lines_buf(
802     buf_T	*buf,
803     linenr_T	lnum,	    // first line with change
804     linenr_T	lnume,	    // line below last changed line
805     long	xtra)	    // number of extra lines (negative when deleting)
806 {
807     if (buf->b_mod_set)
808     {
809 	// find the maximum area that must be redisplayed
810 	if (lnum < buf->b_mod_top)
811 	    buf->b_mod_top = lnum;
812 	if (lnum < buf->b_mod_bot)
813 	{
814 	    // adjust old bot position for xtra lines
815 	    buf->b_mod_bot += xtra;
816 	    if (buf->b_mod_bot < lnum)
817 		buf->b_mod_bot = lnum;
818 	}
819 	if (lnume + xtra > buf->b_mod_bot)
820 	    buf->b_mod_bot = lnume + xtra;
821 	buf->b_mod_xlines += xtra;
822     }
823     else
824     {
825 	// set the area that must be redisplayed
826 	buf->b_mod_set = TRUE;
827 	buf->b_mod_top = lnum;
828 	buf->b_mod_bot = lnume + xtra;
829 	buf->b_mod_xlines = xtra;
830     }
831 }
832 
833 /*
834  * Changed lines for the current buffer.
835  * Must be called AFTER the change and after mark_adjust().
836  * - mark the buffer changed by calling changed()
837  * - mark the windows on this buffer to be redisplayed
838  * - invalidate cached values
839  * "lnum" is the first line that needs displaying, "lnume" the first line
840  * below the changed lines (BEFORE the change).
841  * When only inserting lines, "lnum" and "lnume" are equal.
842  * Takes care of calling changed() and updating b_mod_*.
843  * Careful: may trigger autocommands that reload the buffer.
844  */
845     void
changed_lines(linenr_T lnum,colnr_T col,linenr_T lnume,long xtra)846 changed_lines(
847     linenr_T	lnum,	    // first line with change
848     colnr_T	col,	    // column in first line with change
849     linenr_T	lnume,	    // line below last changed line
850     long	xtra)	    // number of extra lines (negative when deleting)
851 {
852     changed_lines_buf(curbuf, lnum, lnume, xtra);
853 
854 #ifdef FEAT_DIFF
855     if (xtra == 0 && curwin->w_p_diff && !diff_internal())
856     {
857 	// When the number of lines doesn't change then mark_adjust() isn't
858 	// called and other diff buffers still need to be marked for
859 	// displaying.
860 	win_T	    *wp;
861 	linenr_T    wlnum;
862 
863 	FOR_ALL_WINDOWS(wp)
864 	    if (wp->w_p_diff && wp != curwin)
865 	    {
866 		redraw_win_later(wp, VALID);
867 		wlnum = diff_lnum_win(lnum, wp);
868 		if (wlnum > 0)
869 		    changed_lines_buf(wp->w_buffer, wlnum,
870 						    lnume - lnum + wlnum, 0L);
871 	    }
872     }
873 #endif
874 
875     changed_common(lnum, col, lnume, xtra);
876 }
877 
878 /*
879  * Called when the changed flag must be reset for buffer "buf".
880  * When "ff" is TRUE also reset 'fileformat'.
881  * When "always_inc_changedtick" is TRUE b:changedtick is incremented also when
882  * the changed flag was off.
883  */
884     void
unchanged(buf_T * buf,int ff,int always_inc_changedtick)885 unchanged(buf_T *buf, int ff, int always_inc_changedtick)
886 {
887     if (buf->b_changed || (ff && file_ff_differs(buf, FALSE)))
888     {
889 	buf->b_changed = 0;
890 	ml_setflags(buf);
891 	if (ff)
892 	    save_file_ff(buf);
893 	check_status(buf);
894 	redraw_tabline = TRUE;
895 #ifdef FEAT_TITLE
896 	need_maketitle = TRUE;	    // set window title later
897 #endif
898 	++CHANGEDTICK(buf);
899     }
900     else if (always_inc_changedtick)
901 	++CHANGEDTICK(buf);
902 #ifdef FEAT_NETBEANS_INTG
903     netbeans_unmodified(buf);
904 #endif
905 }
906 
907 /*
908  * Save the current values of 'fileformat' and 'fileencoding', so that we know
909  * the file must be considered changed when the value is different.
910  */
911     void
save_file_ff(buf_T * buf)912 save_file_ff(buf_T *buf)
913 {
914     buf->b_start_ffc = *buf->b_p_ff;
915     buf->b_start_eol = buf->b_p_eol;
916     buf->b_start_bomb = buf->b_p_bomb;
917 
918     // Only use free/alloc when necessary, they take time.
919     if (buf->b_start_fenc == NULL
920 			     || STRCMP(buf->b_start_fenc, buf->b_p_fenc) != 0)
921     {
922 	vim_free(buf->b_start_fenc);
923 	buf->b_start_fenc = vim_strsave(buf->b_p_fenc);
924     }
925 }
926 
927 /*
928  * Return TRUE if 'fileformat' and/or 'fileencoding' has a different value
929  * from when editing started (save_file_ff() called).
930  * Also when 'endofline' was changed and 'binary' is set, or when 'bomb' was
931  * changed and 'binary' is not set.
932  * Also when 'endofline' was changed and 'fixeol' is not set.
933  * When "ignore_empty" is true don't consider a new, empty buffer to be
934  * changed.
935  */
936     int
file_ff_differs(buf_T * buf,int ignore_empty)937 file_ff_differs(buf_T *buf, int ignore_empty)
938 {
939     // In a buffer that was never loaded the options are not valid.
940     if (buf->b_flags & BF_NEVERLOADED)
941 	return FALSE;
942     if (ignore_empty
943 	    && (buf->b_flags & BF_NEW)
944 	    && buf->b_ml.ml_line_count == 1
945 	    && *ml_get_buf(buf, (linenr_T)1, FALSE) == NUL)
946 	return FALSE;
947     if (buf->b_start_ffc != *buf->b_p_ff)
948 	return TRUE;
949     if ((buf->b_p_bin || !buf->b_p_fixeol) && buf->b_start_eol != buf->b_p_eol)
950 	return TRUE;
951     if (!buf->b_p_bin && buf->b_start_bomb != buf->b_p_bomb)
952 	return TRUE;
953     if (buf->b_start_fenc == NULL)
954 	return (*buf->b_p_fenc != NUL);
955     return (STRCMP(buf->b_start_fenc, buf->b_p_fenc) != 0);
956 }
957 
958 /*
959  * Insert string "p" at the cursor position.  Stops at a NUL byte.
960  * Handles Replace mode and multi-byte characters.
961  */
962     void
ins_bytes(char_u * p)963 ins_bytes(char_u *p)
964 {
965     ins_bytes_len(p, (int)STRLEN(p));
966 }
967 
968 /*
969  * Insert string "p" with length "len" at the cursor position.
970  * Handles Replace mode and multi-byte characters.
971  */
972     void
ins_bytes_len(char_u * p,int len)973 ins_bytes_len(char_u *p, int len)
974 {
975     int		i;
976     int		n;
977 
978     if (has_mbyte)
979 	for (i = 0; i < len; i += n)
980 	{
981 	    if (enc_utf8)
982 		// avoid reading past p[len]
983 		n = utfc_ptr2len_len(p + i, len - i);
984 	    else
985 		n = (*mb_ptr2len)(p + i);
986 	    ins_char_bytes(p + i, n);
987 	}
988     else
989 	for (i = 0; i < len; ++i)
990 	    ins_char(p[i]);
991 }
992 
993 /*
994  * Insert or replace a single character at the cursor position.
995  * When in REPLACE or VREPLACE mode, replace any existing character.
996  * Caller must have prepared for undo.
997  * For multi-byte characters we get the whole character, the caller must
998  * convert bytes to a character.
999  */
1000     void
ins_char(int c)1001 ins_char(int c)
1002 {
1003     char_u	buf[MB_MAXBYTES + 1];
1004     int		n = (*mb_char2bytes)(c, buf);
1005 
1006     // When "c" is 0x100, 0x200, etc. we don't want to insert a NUL byte.
1007     // Happens for CTRL-Vu9900.
1008     if (buf[0] == 0)
1009 	buf[0] = '\n';
1010 
1011     ins_char_bytes(buf, n);
1012 }
1013 
1014     void
ins_char_bytes(char_u * buf,int charlen)1015 ins_char_bytes(char_u *buf, int charlen)
1016 {
1017     int		c = buf[0];
1018     int		newlen;		// nr of bytes inserted
1019     int		oldlen;		// nr of bytes deleted (0 when not replacing)
1020     char_u	*p;
1021     char_u	*newp;
1022     char_u	*oldp;
1023     int		linelen;	// length of old line including NUL
1024     colnr_T	col;
1025     linenr_T	lnum = curwin->w_cursor.lnum;
1026     int		i;
1027 
1028     // Break tabs if needed.
1029     if (virtual_active() && curwin->w_cursor.coladd > 0)
1030 	coladvance_force(getviscol());
1031 
1032     col = curwin->w_cursor.col;
1033     oldp = ml_get(lnum);
1034     linelen = (int)STRLEN(oldp) + 1;
1035 
1036     // The lengths default to the values for when not replacing.
1037     oldlen = 0;
1038     newlen = charlen;
1039 
1040     if (State & REPLACE_FLAG)
1041     {
1042 	if (State & VREPLACE_FLAG)
1043 	{
1044 	    colnr_T	new_vcol = 0;   // init for GCC
1045 	    colnr_T	vcol;
1046 	    int		old_list;
1047 
1048 	    // Disable 'list' temporarily, unless 'cpo' contains the 'L' flag.
1049 	    // Returns the old value of list, so when finished,
1050 	    // curwin->w_p_list should be set back to this.
1051 	    old_list = curwin->w_p_list;
1052 	    if (old_list && vim_strchr(p_cpo, CPO_LISTWM) == NULL)
1053 		curwin->w_p_list = FALSE;
1054 
1055 	    // In virtual replace mode each character may replace one or more
1056 	    // characters (zero if it's a TAB).  Count the number of bytes to
1057 	    // be deleted to make room for the new character, counting screen
1058 	    // cells.  May result in adding spaces to fill a gap.
1059 	    getvcol(curwin, &curwin->w_cursor, NULL, &vcol, NULL);
1060 	    new_vcol = vcol + chartabsize(buf, vcol);
1061 	    while (oldp[col + oldlen] != NUL && vcol < new_vcol)
1062 	    {
1063 		vcol += chartabsize(oldp + col + oldlen, vcol);
1064 		// Don't need to remove a TAB that takes us to the right
1065 		// position.
1066 		if (vcol > new_vcol && oldp[col + oldlen] == TAB)
1067 		    break;
1068 		oldlen += (*mb_ptr2len)(oldp + col + oldlen);
1069 		// Deleted a bit too much, insert spaces.
1070 		if (vcol > new_vcol)
1071 		    newlen += vcol - new_vcol;
1072 	    }
1073 	    curwin->w_p_list = old_list;
1074 	}
1075 	else if (oldp[col] != NUL)
1076 	{
1077 	    // normal replace
1078 	    oldlen = (*mb_ptr2len)(oldp + col);
1079 	}
1080 
1081 
1082 	// Push the replaced bytes onto the replace stack, so that they can be
1083 	// put back when BS is used.  The bytes of a multi-byte character are
1084 	// done the other way around, so that the first byte is popped off
1085 	// first (it tells the byte length of the character).
1086 	replace_push(NUL);
1087 	for (i = 0; i < oldlen; ++i)
1088 	{
1089 	    if (has_mbyte)
1090 		i += replace_push_mb(oldp + col + i) - 1;
1091 	    else
1092 		replace_push(oldp[col + i]);
1093 	}
1094     }
1095 
1096     newp = alloc(linelen + newlen - oldlen);
1097     if (newp == NULL)
1098 	return;
1099 
1100     // Copy bytes before the cursor.
1101     if (col > 0)
1102 	mch_memmove(newp, oldp, (size_t)col);
1103 
1104     // Copy bytes after the changed character(s).
1105     p = newp + col;
1106     if (linelen > col + oldlen)
1107 	mch_memmove(p + newlen, oldp + col + oldlen,
1108 					    (size_t)(linelen - col - oldlen));
1109 
1110     // Insert or overwrite the new character.
1111     mch_memmove(p, buf, charlen);
1112     i = charlen;
1113 
1114     // Fill with spaces when necessary.
1115     while (i < newlen)
1116 	p[i++] = ' ';
1117 
1118     // Replace the line in the buffer.
1119     ml_replace(lnum, newp, FALSE);
1120 
1121     // mark the buffer as changed and prepare for displaying
1122     inserted_bytes(lnum, col, newlen - oldlen);
1123 
1124     // If we're in Insert or Replace mode and 'showmatch' is set, then briefly
1125     // show the match for right parens and braces.
1126     if (p_sm && (State & INSERT)
1127 	    && msg_silent == 0
1128 	    && !ins_compl_active())
1129     {
1130 	if (has_mbyte)
1131 	    showmatch(mb_ptr2char(buf));
1132 	else
1133 	    showmatch(c);
1134     }
1135 
1136 #ifdef FEAT_RIGHTLEFT
1137     if (!p_ri || (State & REPLACE_FLAG))
1138 #endif
1139     {
1140 	// Normal insert: move cursor right
1141 	curwin->w_cursor.col += charlen;
1142     }
1143 
1144     // TODO: should try to update w_row here, to avoid recomputing it later.
1145 }
1146 
1147 /*
1148  * Insert a string at the cursor position.
1149  * Note: Does NOT handle Replace mode.
1150  * Caller must have prepared for undo.
1151  */
1152     void
ins_str(char_u * s)1153 ins_str(char_u *s)
1154 {
1155     char_u	*oldp, *newp;
1156     int		newlen = (int)STRLEN(s);
1157     int		oldlen;
1158     colnr_T	col;
1159     linenr_T	lnum = curwin->w_cursor.lnum;
1160 
1161     if (virtual_active() && curwin->w_cursor.coladd > 0)
1162 	coladvance_force(getviscol());
1163 
1164     col = curwin->w_cursor.col;
1165     oldp = ml_get(lnum);
1166     oldlen = (int)STRLEN(oldp);
1167 
1168     newp = alloc(oldlen + newlen + 1);
1169     if (newp == NULL)
1170 	return;
1171     if (col > 0)
1172 	mch_memmove(newp, oldp, (size_t)col);
1173     mch_memmove(newp + col, s, (size_t)newlen);
1174     mch_memmove(newp + col + newlen, oldp + col, (size_t)(oldlen - col + 1));
1175     ml_replace(lnum, newp, FALSE);
1176     inserted_bytes(lnum, col, newlen);
1177     curwin->w_cursor.col += newlen;
1178 }
1179 
1180 /*
1181  * Delete one character under the cursor.
1182  * If "fixpos" is TRUE, don't leave the cursor on the NUL after the line.
1183  * Caller must have prepared for undo.
1184  *
1185  * return FAIL for failure, OK otherwise
1186  */
1187     int
del_char(int fixpos)1188 del_char(int fixpos)
1189 {
1190     if (has_mbyte)
1191     {
1192 	// Make sure the cursor is at the start of a character.
1193 	mb_adjust_cursor();
1194 	if (*ml_get_cursor() == NUL)
1195 	    return FAIL;
1196 	return del_chars(1L, fixpos);
1197     }
1198     return del_bytes(1L, fixpos, TRUE);
1199 }
1200 
1201 /*
1202  * Like del_bytes(), but delete characters instead of bytes.
1203  */
1204     int
del_chars(long count,int fixpos)1205 del_chars(long count, int fixpos)
1206 {
1207     long	bytes = 0;
1208     long	i;
1209     char_u	*p;
1210     int		l;
1211 
1212     p = ml_get_cursor();
1213     for (i = 0; i < count && *p != NUL; ++i)
1214     {
1215 	l = (*mb_ptr2len)(p);
1216 	bytes += l;
1217 	p += l;
1218     }
1219     return del_bytes(bytes, fixpos, TRUE);
1220 }
1221 
1222 /*
1223  * Delete "count" bytes under the cursor.
1224  * If "fixpos" is TRUE, don't leave the cursor on the NUL after the line.
1225  * Caller must have prepared for undo.
1226  *
1227  * Return FAIL for failure, OK otherwise.
1228  */
1229     int
del_bytes(long count,int fixpos_arg,int use_delcombine UNUSED)1230 del_bytes(
1231     long	count,
1232     int		fixpos_arg,
1233     int		use_delcombine UNUSED)	    // 'delcombine' option applies
1234 {
1235     char_u	*oldp, *newp;
1236     colnr_T	oldlen;
1237     colnr_T	newlen;
1238     linenr_T	lnum = curwin->w_cursor.lnum;
1239     colnr_T	col = curwin->w_cursor.col;
1240     int		alloc_newp;
1241     long	movelen;
1242     int		fixpos = fixpos_arg;
1243 
1244     oldp = ml_get(lnum);
1245     oldlen = (int)STRLEN(oldp);
1246 
1247     // Can't do anything when the cursor is on the NUL after the line.
1248     if (col >= oldlen)
1249 	return FAIL;
1250 
1251     // If "count" is zero there is nothing to do.
1252     if (count == 0)
1253 	return OK;
1254 
1255     // If "count" is negative the caller must be doing something wrong.
1256     if (count < 1)
1257     {
1258 	siemsg("E292: Invalid count for del_bytes(): %ld", count);
1259 	return FAIL;
1260     }
1261 
1262     // If 'delcombine' is set and deleting (less than) one character, only
1263     // delete the last combining character.
1264     if (p_deco && use_delcombine && enc_utf8
1265 					 && utfc_ptr2len(oldp + col) >= count)
1266     {
1267 	int	cc[MAX_MCO];
1268 	int	n;
1269 
1270 	(void)utfc_ptr2char(oldp + col, cc);
1271 	if (cc[0] != NUL)
1272 	{
1273 	    // Find the last composing char, there can be several.
1274 	    n = col;
1275 	    do
1276 	    {
1277 		col = n;
1278 		count = utf_ptr2len(oldp + n);
1279 		n += count;
1280 	    } while (UTF_COMPOSINGLIKE(oldp + col, oldp + n));
1281 	    fixpos = 0;
1282 	}
1283     }
1284 
1285     // When count is too big, reduce it.
1286     movelen = (long)oldlen - (long)col - count + 1; // includes trailing NUL
1287     if (movelen <= 1)
1288     {
1289 	// If we just took off the last character of a non-blank line, and
1290 	// fixpos is TRUE, we don't want to end up positioned at the NUL,
1291 	// unless "restart_edit" is set or 'virtualedit' contains "onemore".
1292 	if (col > 0 && fixpos && restart_edit == 0
1293 					      && (get_ve_flags() & VE_ONEMORE) == 0)
1294 	{
1295 	    --curwin->w_cursor.col;
1296 	    curwin->w_cursor.coladd = 0;
1297 	    if (has_mbyte)
1298 		curwin->w_cursor.col -=
1299 			    (*mb_head_off)(oldp, oldp + curwin->w_cursor.col);
1300 	}
1301 	count = oldlen - col;
1302 	movelen = 1;
1303     }
1304     newlen = oldlen - count;
1305 
1306     // If the old line has been allocated the deletion can be done in the
1307     // existing line. Otherwise a new line has to be allocated
1308     // Can't do this when using Netbeans, because we would need to invoke
1309     // netbeans_removed(), which deallocates the line.  Let ml_replace() take
1310     // care of notifying Netbeans.
1311 #ifdef FEAT_NETBEANS_INTG
1312     if (netbeans_active())
1313 	alloc_newp = TRUE;
1314     else
1315 #endif
1316 	alloc_newp = !ml_line_alloced();    // check if oldp was allocated
1317     if (!alloc_newp)
1318 	newp = oldp;			    // use same allocated memory
1319     else
1320     {					    // need to allocate a new line
1321 	newp = alloc(newlen + 1);
1322 	if (newp == NULL)
1323 	    return FAIL;
1324 	mch_memmove(newp, oldp, (size_t)col);
1325     }
1326     mch_memmove(newp + col, oldp + col + count, (size_t)movelen);
1327     if (alloc_newp)
1328 	ml_replace(lnum, newp, FALSE);
1329 #ifdef FEAT_PROP_POPUP
1330     else
1331     {
1332 	// Also move any following text properties.
1333 	if (oldlen + 1 < curbuf->b_ml.ml_line_len)
1334 	    mch_memmove(newp + newlen + 1, oldp + oldlen + 1,
1335 			       (size_t)curbuf->b_ml.ml_line_len - oldlen - 1);
1336 	curbuf->b_ml.ml_line_len -= count;
1337     }
1338 #endif
1339 
1340     // mark the buffer as changed and prepare for displaying
1341     inserted_bytes(lnum, col, -count);
1342 
1343     return OK;
1344 }
1345 
1346 /*
1347  * open_line: Add a new line below or above the current line.
1348  *
1349  * For VREPLACE mode, we only add a new line when we get to the end of the
1350  * file, otherwise we just start replacing the next line.
1351  *
1352  * Caller must take care of undo.  Since VREPLACE may affect any number of
1353  * lines however, it may call u_save_cursor() again when starting to change a
1354  * new line.
1355  * "flags": OPENLINE_DELSPACES	delete spaces after cursor
1356  *	    OPENLINE_DO_COM	format comments
1357  *	    OPENLINE_KEEPTRAIL	keep trailing spaces
1358  *	    OPENLINE_MARKFIX	adjust mark positions after the line break
1359  *	    OPENLINE_COM_LIST	format comments with list or 2nd line indent
1360  *
1361  * "second_line_indent": indent for after ^^D in Insert mode or if flag
1362  *			  OPENLINE_COM_LIST
1363  *
1364  * Return OK for success, FAIL for failure
1365  */
1366     int
open_line(int dir,int flags,int second_line_indent)1367 open_line(
1368     int		dir,		// FORWARD or BACKWARD
1369     int		flags,
1370     int		second_line_indent)
1371 {
1372     char_u	*saved_line;		// copy of the original line
1373     char_u	*next_line = NULL;	// copy of the next line
1374     char_u	*p_extra = NULL;	// what goes to next line
1375     int		less_cols = 0;		// less columns for mark in new line
1376     int		less_cols_off = 0;	// columns to skip for mark adjust
1377     pos_T	old_cursor;		// old cursor position
1378     int		newcol = 0;		// new cursor column
1379     int		newindent = 0;		// auto-indent of the new line
1380     int		n;
1381     int		trunc_line = FALSE;	// truncate current line afterwards
1382     int		retval = FAIL;		// return value
1383     int		extra_len = 0;		// length of p_extra string
1384     int		lead_len;		// length of comment leader
1385     char_u	*lead_flags;	// position in 'comments' for comment leader
1386     char_u	*leader = NULL;		// copy of comment leader
1387     char_u	*allocated = NULL;	// allocated memory
1388     char_u	*p;
1389     int		saved_char = NUL;	// init for GCC
1390     pos_T	*pos;
1391 #ifdef FEAT_SMARTINDENT
1392     int		do_si = (!p_paste && curbuf->b_p_si
1393 # ifdef FEAT_CINDENT
1394 					&& !curbuf->b_p_cin
1395 # endif
1396 # ifdef FEAT_EVAL
1397 					&& *curbuf->b_p_inde == NUL
1398 # endif
1399 			);
1400     int		no_si = FALSE;		// reset did_si afterwards
1401     int		first_char = NUL;	// init for GCC
1402 #endif
1403 #if defined(FEAT_LISP) || defined(FEAT_CINDENT)
1404     int		vreplace_mode;
1405 #endif
1406     int		did_append;		// appended a new line
1407     int		saved_pi = curbuf->b_p_pi; // copy of preserveindent setting
1408 
1409     // make a copy of the current line so we can mess with it
1410     saved_line = vim_strsave(ml_get_curline());
1411     if (saved_line == NULL)	    // out of memory!
1412 	return FALSE;
1413 
1414     if (State & VREPLACE_FLAG)
1415     {
1416 	// With VREPLACE we make a copy of the next line, which we will be
1417 	// starting to replace.  First make the new line empty and let vim play
1418 	// with the indenting and comment leader to its heart's content.  Then
1419 	// we grab what it ended up putting on the new line, put back the
1420 	// original line, and call ins_char() to put each new character onto
1421 	// the line, replacing what was there before and pushing the right
1422 	// stuff onto the replace stack.  -- webb.
1423 	if (curwin->w_cursor.lnum < orig_line_count)
1424 	    next_line = vim_strsave(ml_get(curwin->w_cursor.lnum + 1));
1425 	else
1426 	    next_line = vim_strsave((char_u *)"");
1427 	if (next_line == NULL)	    // out of memory!
1428 	    goto theend;
1429 
1430 	// In VREPLACE mode, a NL replaces the rest of the line, and starts
1431 	// replacing the next line, so push all of the characters left on the
1432 	// line onto the replace stack.  We'll push any other characters that
1433 	// might be replaced at the start of the next line (due to autoindent
1434 	// etc) a bit later.
1435 	replace_push(NUL);  // Call twice because BS over NL expects it
1436 	replace_push(NUL);
1437 	p = saved_line + curwin->w_cursor.col;
1438 	while (*p != NUL)
1439 	{
1440 	    if (has_mbyte)
1441 		p += replace_push_mb(p);
1442 	    else
1443 		replace_push(*p++);
1444 	}
1445 	saved_line[curwin->w_cursor.col] = NUL;
1446     }
1447 
1448     if ((State & INSERT) && !(State & VREPLACE_FLAG))
1449     {
1450 	p_extra = saved_line + curwin->w_cursor.col;
1451 #ifdef FEAT_SMARTINDENT
1452 	if (do_si)		// need first char after new line break
1453 	{
1454 	    p = skipwhite(p_extra);
1455 	    first_char = *p;
1456 	}
1457 #endif
1458 	extra_len = (int)STRLEN(p_extra);
1459 	saved_char = *p_extra;
1460 	*p_extra = NUL;
1461     }
1462 
1463     u_clearline();		// cannot do "U" command when adding lines
1464 #ifdef FEAT_SMARTINDENT
1465     did_si = FALSE;
1466 #endif
1467     ai_col = 0;
1468 
1469     // If we just did an auto-indent, then we didn't type anything on
1470     // the prior line, and it should be truncated.  Do this even if 'ai' is not
1471     // set because automatically inserting a comment leader also sets did_ai.
1472     if (dir == FORWARD && did_ai)
1473 	trunc_line = TRUE;
1474 
1475     // If 'autoindent' and/or 'smartindent' is set, try to figure out what
1476     // indent to use for the new line.
1477     if (curbuf->b_p_ai
1478 #ifdef FEAT_SMARTINDENT
1479 			|| do_si
1480 #endif
1481 					    )
1482     {
1483 	// count white space on current line
1484 #ifdef FEAT_VARTABS
1485 	newindent = get_indent_str_vtab(saved_line, curbuf->b_p_ts,
1486 						 curbuf->b_p_vts_array, FALSE);
1487 #else
1488 	newindent = get_indent_str(saved_line, (int)curbuf->b_p_ts, FALSE);
1489 #endif
1490 	if (newindent == 0 && !(flags & OPENLINE_COM_LIST))
1491 	    newindent = second_line_indent; // for ^^D command in insert mode
1492 
1493 #ifdef FEAT_SMARTINDENT
1494 	// Do smart indenting.
1495 	// In insert/replace mode (only when dir == FORWARD)
1496 	// we may move some text to the next line. If it starts with '{'
1497 	// don't add an indent. Fixes inserting a NL before '{' in line
1498 	//	"if (condition) {"
1499 	if (!trunc_line && do_si && *saved_line != NUL
1500 				    && (p_extra == NULL || first_char != '{'))
1501 	{
1502 	    char_u  *ptr;
1503 	    char_u  last_char;
1504 
1505 	    old_cursor = curwin->w_cursor;
1506 	    ptr = saved_line;
1507 	    if (flags & OPENLINE_DO_COM)
1508 		lead_len = get_leader_len(ptr, NULL, FALSE, TRUE);
1509 	    else
1510 		lead_len = 0;
1511 	    if (dir == FORWARD)
1512 	    {
1513 		// Skip preprocessor directives, unless they are
1514 		// recognised as comments.
1515 		if ( lead_len == 0 && ptr[0] == '#')
1516 		{
1517 		    while (ptr[0] == '#' && curwin->w_cursor.lnum > 1)
1518 			ptr = ml_get(--curwin->w_cursor.lnum);
1519 		    newindent = get_indent();
1520 		}
1521 		if (flags & OPENLINE_DO_COM)
1522 		    lead_len = get_leader_len(ptr, NULL, FALSE, TRUE);
1523 		else
1524 		    lead_len = 0;
1525 		if (lead_len > 0)
1526 		{
1527 		    // This case gets the following right:
1528 		    //	    /*
1529 		    //	     * A comment (read '\' as '/').
1530 		    //	     */
1531 		    // #define IN_THE_WAY
1532 		    //	    This should line up here;
1533 		    p = skipwhite(ptr);
1534 		    if (p[0] == '/' && p[1] == '*')
1535 			p++;
1536 		    if (p[0] == '*')
1537 		    {
1538 			for (p++; *p; p++)
1539 			{
1540 			    if (p[0] == '/' && p[-1] == '*')
1541 			    {
1542 				// End of C comment, indent should line up
1543 				// with the line containing the start of
1544 				// the comment
1545 				curwin->w_cursor.col = (colnr_T)(p - ptr);
1546 				if ((pos = findmatch(NULL, NUL)) != NULL)
1547 				{
1548 				    curwin->w_cursor.lnum = pos->lnum;
1549 				    newindent = get_indent();
1550 				}
1551 			    }
1552 			}
1553 		    }
1554 		}
1555 		else	// Not a comment line
1556 		{
1557 		    // Find last non-blank in line
1558 		    p = ptr + STRLEN(ptr) - 1;
1559 		    while (p > ptr && VIM_ISWHITE(*p))
1560 			--p;
1561 		    last_char = *p;
1562 
1563 		    // find the character just before the '{' or ';'
1564 		    if (last_char == '{' || last_char == ';')
1565 		    {
1566 			if (p > ptr)
1567 			    --p;
1568 			while (p > ptr && VIM_ISWHITE(*p))
1569 			    --p;
1570 		    }
1571 		    // Try to catch lines that are split over multiple
1572 		    // lines.  eg:
1573 		    //	    if (condition &&
1574 		    //			condition) {
1575 		    //		Should line up here!
1576 		    //	    }
1577 		    if (*p == ')')
1578 		    {
1579 			curwin->w_cursor.col = (colnr_T)(p - ptr);
1580 			if ((pos = findmatch(NULL, '(')) != NULL)
1581 			{
1582 			    curwin->w_cursor.lnum = pos->lnum;
1583 			    newindent = get_indent();
1584 			    ptr = ml_get_curline();
1585 			}
1586 		    }
1587 		    // If last character is '{' do indent, without
1588 		    // checking for "if" and the like.
1589 		    if (last_char == '{')
1590 		    {
1591 			did_si = TRUE;	// do indent
1592 			no_si = TRUE;	// don't delete it when '{' typed
1593 		    }
1594 		    // Look for "if" and the like, use 'cinwords'.
1595 		    // Don't do this if the previous line ended in ';' or
1596 		    // '}'.
1597 		    else if (last_char != ';' && last_char != '}'
1598 						       && cin_is_cinword(ptr))
1599 			did_si = TRUE;
1600 		}
1601 	    }
1602 	    else // dir == BACKWARD
1603 	    {
1604 		// Skip preprocessor directives, unless they are
1605 		// recognised as comments.
1606 		if (lead_len == 0 && ptr[0] == '#')
1607 		{
1608 		    int was_backslashed = FALSE;
1609 
1610 		    while ((ptr[0] == '#' || was_backslashed) &&
1611 			 curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
1612 		    {
1613 			if (*ptr && ptr[STRLEN(ptr) - 1] == '\\')
1614 			    was_backslashed = TRUE;
1615 			else
1616 			    was_backslashed = FALSE;
1617 			ptr = ml_get(++curwin->w_cursor.lnum);
1618 		    }
1619 		    if (was_backslashed)
1620 			newindent = 0;	    // Got to end of file
1621 		    else
1622 			newindent = get_indent();
1623 		}
1624 		p = skipwhite(ptr);
1625 		if (*p == '}')	    // if line starts with '}': do indent
1626 		    did_si = TRUE;
1627 		else		    // can delete indent when '{' typed
1628 		    can_si_back = TRUE;
1629 	    }
1630 	    curwin->w_cursor = old_cursor;
1631 	}
1632 	if (do_si)
1633 	    can_si = TRUE;
1634 #endif // FEAT_SMARTINDENT
1635 
1636 	did_ai = TRUE;
1637     }
1638 
1639     // Find out if the current line starts with a comment leader.
1640     // This may then be inserted in front of the new line.
1641     end_comment_pending = NUL;
1642     if (flags & OPENLINE_DO_COM)
1643 	lead_len = get_leader_len(saved_line, &lead_flags,
1644 							dir == BACKWARD, TRUE);
1645     else
1646 	lead_len = 0;
1647     if (lead_len > 0)
1648     {
1649 	char_u	*lead_repl = NULL;	    // replaces comment leader
1650 	int	lead_repl_len = 0;	    // length of *lead_repl
1651 	char_u	lead_middle[COM_MAX_LEN];   // middle-comment string
1652 	char_u	lead_end[COM_MAX_LEN];	    // end-comment string
1653 	char_u	*comment_end = NULL;	    // where lead_end has been found
1654 	int	extra_space = FALSE;	    // append extra space
1655 	int	current_flag;
1656 	int	require_blank = FALSE;	    // requires blank after middle
1657 	char_u	*p2;
1658 
1659 	// If the comment leader has the start, middle or end flag, it may not
1660 	// be used or may be replaced with the middle leader.
1661 	for (p = lead_flags; *p && *p != ':'; ++p)
1662 	{
1663 	    if (*p == COM_BLANK)
1664 	    {
1665 		require_blank = TRUE;
1666 		continue;
1667 	    }
1668 	    if (*p == COM_START || *p == COM_MIDDLE)
1669 	    {
1670 		current_flag = *p;
1671 		if (*p == COM_START)
1672 		{
1673 		    // Doing "O" on a start of comment does not insert leader.
1674 		    if (dir == BACKWARD)
1675 		    {
1676 			lead_len = 0;
1677 			break;
1678 		    }
1679 
1680 		    // find start of middle part
1681 		    (void)copy_option_part(&p, lead_middle, COM_MAX_LEN, ",");
1682 		    require_blank = FALSE;
1683 		}
1684 
1685 		// Isolate the strings of the middle and end leader.
1686 		while (*p && p[-1] != ':')	// find end of middle flags
1687 		{
1688 		    if (*p == COM_BLANK)
1689 			require_blank = TRUE;
1690 		    ++p;
1691 		}
1692 		(void)copy_option_part(&p, lead_middle, COM_MAX_LEN, ",");
1693 
1694 		while (*p && p[-1] != ':')	// find end of end flags
1695 		{
1696 		    // Check whether we allow automatic ending of comments
1697 		    if (*p == COM_AUTO_END)
1698 			end_comment_pending = -1; // means we want to set it
1699 		    ++p;
1700 		}
1701 		n = copy_option_part(&p, lead_end, COM_MAX_LEN, ",");
1702 
1703 		if (end_comment_pending == -1)	// we can set it now
1704 		    end_comment_pending = lead_end[n - 1];
1705 
1706 		// If the end of the comment is in the same line, don't use
1707 		// the comment leader.
1708 		if (dir == FORWARD)
1709 		{
1710 		    for (p = saved_line + lead_len; *p; ++p)
1711 			if (STRNCMP(p, lead_end, n) == 0)
1712 			{
1713 			    comment_end = p;
1714 			    lead_len = 0;
1715 			    break;
1716 			}
1717 		}
1718 
1719 		// Doing "o" on a start of comment inserts the middle leader.
1720 		if (lead_len > 0)
1721 		{
1722 		    if (current_flag == COM_START)
1723 		    {
1724 			lead_repl = lead_middle;
1725 			lead_repl_len = (int)STRLEN(lead_middle);
1726 		    }
1727 
1728 		    // If we have hit RETURN immediately after the start
1729 		    // comment leader, then put a space after the middle
1730 		    // comment leader on the next line.
1731 		    if (!VIM_ISWHITE(saved_line[lead_len - 1])
1732 			    && ((p_extra != NULL
1733 				    && (int)curwin->w_cursor.col == lead_len)
1734 				|| (p_extra == NULL
1735 				    && saved_line[lead_len] == NUL)
1736 				|| require_blank))
1737 			extra_space = TRUE;
1738 		}
1739 		break;
1740 	    }
1741 	    if (*p == COM_END)
1742 	    {
1743 		// Doing "o" on the end of a comment does not insert leader.
1744 		// Remember where the end is, might want to use it to find the
1745 		// start (for C-comments).
1746 		if (dir == FORWARD)
1747 		{
1748 		    comment_end = skipwhite(saved_line);
1749 		    lead_len = 0;
1750 		    break;
1751 		}
1752 
1753 		// Doing "O" on the end of a comment inserts the middle leader.
1754 		// Find the string for the middle leader, searching backwards.
1755 		while (p > curbuf->b_p_com && *p != ',')
1756 		    --p;
1757 		for (lead_repl = p; lead_repl > curbuf->b_p_com
1758 					 && lead_repl[-1] != ':'; --lead_repl)
1759 		    ;
1760 		lead_repl_len = (int)(p - lead_repl);
1761 
1762 		// We can probably always add an extra space when doing "O" on
1763 		// the comment-end
1764 		extra_space = TRUE;
1765 
1766 		// Check whether we allow automatic ending of comments
1767 		for (p2 = p; *p2 && *p2 != ':'; p2++)
1768 		{
1769 		    if (*p2 == COM_AUTO_END)
1770 			end_comment_pending = -1; // means we want to set it
1771 		}
1772 		if (end_comment_pending == -1)
1773 		{
1774 		    // Find last character in end-comment string
1775 		    while (*p2 && *p2 != ',')
1776 			p2++;
1777 		    end_comment_pending = p2[-1];
1778 		}
1779 		break;
1780 	    }
1781 	    if (*p == COM_FIRST)
1782 	    {
1783 		// Comment leader for first line only:	Don't repeat leader
1784 		// when using "O", blank out leader when using "o".
1785 		if (dir == BACKWARD)
1786 		    lead_len = 0;
1787 		else
1788 		{
1789 		    lead_repl = (char_u *)"";
1790 		    lead_repl_len = 0;
1791 		}
1792 		break;
1793 	    }
1794 	}
1795 	if (lead_len)
1796 	{
1797 	    // allocate buffer (may concatenate p_extra later)
1798 	    leader = alloc(lead_len + lead_repl_len + extra_space + extra_len
1799 		     + (second_line_indent > 0 ? second_line_indent : 0) + 1);
1800 	    allocated = leader;		    // remember to free it later
1801 
1802 	    if (leader == NULL)
1803 		lead_len = 0;
1804 	    else
1805 	    {
1806 		vim_strncpy(leader, saved_line, lead_len);
1807 
1808 		// Replace leader with lead_repl, right or left adjusted
1809 		if (lead_repl != NULL)
1810 		{
1811 		    int		c = 0;
1812 		    int		off = 0;
1813 
1814 		    for (p = lead_flags; *p != NUL && *p != ':'; )
1815 		    {
1816 			if (*p == COM_RIGHT || *p == COM_LEFT)
1817 			    c = *p++;
1818 			else if (VIM_ISDIGIT(*p) || *p == '-')
1819 			    off = getdigits(&p);
1820 			else
1821 			    ++p;
1822 		    }
1823 		    if (c == COM_RIGHT)    // right adjusted leader
1824 		    {
1825 			// find last non-white in the leader to line up with
1826 			for (p = leader + lead_len - 1; p > leader
1827 						      && VIM_ISWHITE(*p); --p)
1828 			    ;
1829 			++p;
1830 
1831 			// Compute the length of the replaced characters in
1832 			// screen characters, not bytes.
1833 			{
1834 			    int	    repl_size = vim_strnsize(lead_repl,
1835 							       lead_repl_len);
1836 			    int	    old_size = 0;
1837 			    char_u  *endp = p;
1838 			    int	    l;
1839 
1840 			    while (old_size < repl_size && p > leader)
1841 			    {
1842 				MB_PTR_BACK(leader, p);
1843 				old_size += ptr2cells(p);
1844 			    }
1845 			    l = lead_repl_len - (int)(endp - p);
1846 			    if (l != 0)
1847 				mch_memmove(endp + l, endp,
1848 					(size_t)((leader + lead_len) - endp));
1849 			    lead_len += l;
1850 			}
1851 			mch_memmove(p, lead_repl, (size_t)lead_repl_len);
1852 			if (p + lead_repl_len > leader + lead_len)
1853 			    p[lead_repl_len] = NUL;
1854 
1855 			// blank-out any other chars from the old leader.
1856 			while (--p >= leader)
1857 			{
1858 			    int l = mb_head_off(leader, p);
1859 
1860 			    if (l > 1)
1861 			    {
1862 				p -= l;
1863 				if (ptr2cells(p) > 1)
1864 				{
1865 				    p[1] = ' ';
1866 				    --l;
1867 				}
1868 				mch_memmove(p + 1, p + l + 1,
1869 				   (size_t)((leader + lead_len) - (p + l + 1)));
1870 				lead_len -= l;
1871 				*p = ' ';
1872 			    }
1873 			    else if (!VIM_ISWHITE(*p))
1874 				*p = ' ';
1875 			}
1876 		    }
1877 		    else	// left adjusted leader
1878 		    {
1879 			p = skipwhite(leader);
1880 
1881 			// Compute the length of the replaced characters in
1882 			// screen characters, not bytes. Move the part that is
1883 			// not to be overwritten.
1884 			{
1885 			    int	    repl_size = vim_strnsize(lead_repl,
1886 							       lead_repl_len);
1887 			    int	    i;
1888 			    int	    l;
1889 
1890 			    for (i = 0; i < lead_len && p[i] != NUL; i += l)
1891 			    {
1892 				l = (*mb_ptr2len)(p + i);
1893 				if (vim_strnsize(p, i + l) > repl_size)
1894 				    break;
1895 			    }
1896 			    if (i != lead_repl_len)
1897 			    {
1898 				mch_memmove(p + lead_repl_len, p + i,
1899 				       (size_t)(lead_len - i - (p - leader)));
1900 				lead_len += lead_repl_len - i;
1901 			    }
1902 			}
1903 			mch_memmove(p, lead_repl, (size_t)lead_repl_len);
1904 
1905 			// Replace any remaining non-white chars in the old
1906 			// leader by spaces.  Keep Tabs, the indent must
1907 			// remain the same.
1908 			for (p += lead_repl_len; p < leader + lead_len; ++p)
1909 			    if (!VIM_ISWHITE(*p))
1910 			    {
1911 				// Don't put a space before a TAB.
1912 				if (p + 1 < leader + lead_len && p[1] == TAB)
1913 				{
1914 				    --lead_len;
1915 				    mch_memmove(p, p + 1,
1916 						     (leader + lead_len) - p);
1917 				}
1918 				else
1919 				{
1920 				    int	    l = (*mb_ptr2len)(p);
1921 
1922 				    if (l > 1)
1923 				    {
1924 					if (ptr2cells(p) > 1)
1925 					{
1926 					    // Replace a double-wide char with
1927 					    // two spaces
1928 					    --l;
1929 					    *p++ = ' ';
1930 					}
1931 					mch_memmove(p + 1, p + l,
1932 						     (leader + lead_len) - p);
1933 					lead_len -= l - 1;
1934 				    }
1935 				    *p = ' ';
1936 				}
1937 			    }
1938 			*p = NUL;
1939 		    }
1940 
1941 		    // Recompute the indent, it may have changed.
1942 		    if (curbuf->b_p_ai
1943 #ifdef FEAT_SMARTINDENT
1944 					|| do_si
1945 #endif
1946 							   )
1947 #ifdef FEAT_VARTABS
1948 			newindent = get_indent_str_vtab(leader, curbuf->b_p_ts,
1949 						 curbuf->b_p_vts_array, FALSE);
1950 #else
1951 			newindent = get_indent_str(leader,
1952 						   (int)curbuf->b_p_ts, FALSE);
1953 #endif
1954 
1955 		    // Add the indent offset
1956 		    if (newindent + off < 0)
1957 		    {
1958 			off = -newindent;
1959 			newindent = 0;
1960 		    }
1961 		    else
1962 			newindent += off;
1963 
1964 		    // Correct trailing spaces for the shift, so that
1965 		    // alignment remains equal.
1966 		    while (off > 0 && lead_len > 0
1967 					       && leader[lead_len - 1] == ' ')
1968 		    {
1969 			// Don't do it when there is a tab before the space
1970 			if (vim_strchr(skipwhite(leader), '\t') != NULL)
1971 			    break;
1972 			--lead_len;
1973 			--off;
1974 		    }
1975 
1976 		    // If the leader ends in white space, don't add an
1977 		    // extra space
1978 		    if (lead_len > 0 && VIM_ISWHITE(leader[lead_len - 1]))
1979 			extra_space = FALSE;
1980 		    leader[lead_len] = NUL;
1981 		}
1982 
1983 		if (extra_space)
1984 		{
1985 		    leader[lead_len++] = ' ';
1986 		    leader[lead_len] = NUL;
1987 		}
1988 
1989 		newcol = lead_len;
1990 
1991 		// if a new indent will be set below, remove the indent that
1992 		// is in the comment leader
1993 		if (newindent
1994 #ifdef FEAT_SMARTINDENT
1995 				|| did_si
1996 #endif
1997 					   )
1998 		{
1999 		    while (lead_len && VIM_ISWHITE(*leader))
2000 		    {
2001 			--lead_len;
2002 			--newcol;
2003 			++leader;
2004 		    }
2005 		}
2006 
2007 	    }
2008 #ifdef FEAT_SMARTINDENT
2009 	    did_si = can_si = FALSE;
2010 #endif
2011 	}
2012 	else if (comment_end != NULL)
2013 	{
2014 	    // We have finished a comment, so we don't use the leader.
2015 	    // If this was a C-comment and 'ai' or 'si' is set do a normal
2016 	    // indent to align with the line containing the start of the
2017 	    // comment.
2018 	    if (comment_end[0] == '*' && comment_end[1] == '/' &&
2019 			(curbuf->b_p_ai
2020 #ifdef FEAT_SMARTINDENT
2021 					|| do_si
2022 #endif
2023 							   ))
2024 	    {
2025 		old_cursor = curwin->w_cursor;
2026 		curwin->w_cursor.col = (colnr_T)(comment_end - saved_line);
2027 		if ((pos = findmatch(NULL, NUL)) != NULL)
2028 		{
2029 		    curwin->w_cursor.lnum = pos->lnum;
2030 		    newindent = get_indent();
2031 		}
2032 		curwin->w_cursor = old_cursor;
2033 	    }
2034 	}
2035     }
2036 
2037     // (State == INSERT || State == REPLACE), only when dir == FORWARD
2038     if (p_extra != NULL)
2039     {
2040 	*p_extra = saved_char;		// restore char that NUL replaced
2041 
2042 	// When 'ai' set or "flags" has OPENLINE_DELSPACES, skip to the first
2043 	// non-blank.
2044 	//
2045 	// When in REPLACE mode, put the deleted blanks on the replace stack,
2046 	// preceded by a NUL, so they can be put back when a BS is entered.
2047 	if (REPLACE_NORMAL(State))
2048 	    replace_push(NUL);	    // end of extra blanks
2049 	if (curbuf->b_p_ai || (flags & OPENLINE_DELSPACES))
2050 	{
2051 	    while ((*p_extra == ' ' || *p_extra == '\t')
2052 		    && (!enc_utf8
2053 			       || !utf_iscomposing(utf_ptr2char(p_extra + 1))))
2054 	    {
2055 		if (REPLACE_NORMAL(State))
2056 		    replace_push(*p_extra);
2057 		++p_extra;
2058 		++less_cols_off;
2059 	    }
2060 	}
2061 
2062 	// columns for marks adjusted for removed columns
2063 	less_cols = (int)(p_extra - saved_line);
2064     }
2065 
2066     if (p_extra == NULL)
2067 	p_extra = (char_u *)"";		    // append empty line
2068 
2069     // concatenate leader and p_extra, if there is a leader
2070     if (lead_len)
2071     {
2072 	if (flags & OPENLINE_COM_LIST && second_line_indent > 0)
2073 	{
2074 	    int i;
2075 	    int padding = second_line_indent
2076 					  - (newindent + (int)STRLEN(leader));
2077 
2078 	    // Here whitespace is inserted after the comment char.
2079 	    // Below, set_indent(newindent, SIN_INSERT) will insert the
2080 	    // whitespace needed before the comment char.
2081 	    for (i = 0; i < padding; i++)
2082 	    {
2083 		STRCAT(leader, " ");
2084 		less_cols--;
2085 		newcol++;
2086 	    }
2087 	}
2088 	STRCAT(leader, p_extra);
2089 	p_extra = leader;
2090 	did_ai = TRUE;	    // So truncating blanks works with comments
2091 	less_cols -= lead_len;
2092     }
2093     else
2094 	end_comment_pending = NUL;  // turns out there was no leader
2095 
2096     old_cursor = curwin->w_cursor;
2097     if (dir == BACKWARD)
2098 	--curwin->w_cursor.lnum;
2099     if (!(State & VREPLACE_FLAG) || old_cursor.lnum >= orig_line_count)
2100     {
2101 	if (ml_append(curwin->w_cursor.lnum, p_extra, (colnr_T)0, FALSE)
2102 								      == FAIL)
2103 	    goto theend;
2104 	// Postpone calling changed_lines(), because it would mess up folding
2105 	// with markers.
2106 	// Skip mark_adjust when adding a line after the last one, there can't
2107 	// be marks there. But still needed in diff mode.
2108 	if (curwin->w_cursor.lnum + 1 < curbuf->b_ml.ml_line_count
2109 #ifdef FEAT_DIFF
2110 		|| curwin->w_p_diff
2111 #endif
2112 	    )
2113 	    mark_adjust(curwin->w_cursor.lnum + 1, (linenr_T)MAXLNUM, 1L, 0L);
2114 	did_append = TRUE;
2115 #ifdef FEAT_PROP_POPUP
2116 	if ((State & INSERT) && !(State & VREPLACE_FLAG))
2117 	    // properties after the split move to the next line
2118 	    adjust_props_for_split(curwin->w_cursor.lnum, curwin->w_cursor.lnum,
2119 						  curwin->w_cursor.col + 1, 0);
2120 #endif
2121     }
2122     else
2123     {
2124 	// In VREPLACE mode we are starting to replace the next line.
2125 	curwin->w_cursor.lnum++;
2126 	if (curwin->w_cursor.lnum >= Insstart.lnum + vr_lines_changed)
2127 	{
2128 	    // In case we NL to a new line, BS to the previous one, and NL
2129 	    // again, we don't want to save the new line for undo twice.
2130 	    (void)u_save_cursor();		    // errors are ignored!
2131 	    vr_lines_changed++;
2132 	}
2133 	ml_replace(curwin->w_cursor.lnum, p_extra, TRUE);
2134 	changed_bytes(curwin->w_cursor.lnum, 0);
2135 	curwin->w_cursor.lnum--;
2136 	did_append = FALSE;
2137     }
2138 
2139     if (newindent
2140 #ifdef FEAT_SMARTINDENT
2141 		    || did_si
2142 #endif
2143 				)
2144     {
2145 	++curwin->w_cursor.lnum;
2146 #ifdef FEAT_SMARTINDENT
2147 	if (did_si)
2148 	{
2149 	    int sw = (int)get_sw_value(curbuf);
2150 
2151 	    if (p_sr)
2152 		newindent -= newindent % sw;
2153 	    newindent += sw;
2154 	}
2155 #endif
2156 	// Copy the indent
2157 	if (curbuf->b_p_ci)
2158 	{
2159 	    (void)copy_indent(newindent, saved_line);
2160 
2161 	    // Set the 'preserveindent' option so that any further screwing
2162 	    // with the line doesn't entirely destroy our efforts to preserve
2163 	    // it.  It gets restored at the function end.
2164 	    curbuf->b_p_pi = TRUE;
2165 	}
2166 	else
2167 	    (void)set_indent(newindent, SIN_INSERT);
2168 	less_cols -= curwin->w_cursor.col;
2169 
2170 	ai_col = curwin->w_cursor.col;
2171 
2172 	// In REPLACE mode, for each character in the new indent, there must
2173 	// be a NUL on the replace stack, for when it is deleted with BS
2174 	if (REPLACE_NORMAL(State))
2175 	    for (n = 0; n < (int)curwin->w_cursor.col; ++n)
2176 		replace_push(NUL);
2177 	newcol += curwin->w_cursor.col;
2178 #ifdef FEAT_SMARTINDENT
2179 	if (no_si)
2180 	    did_si = FALSE;
2181 #endif
2182     }
2183 
2184     // In REPLACE mode, for each character in the extra leader, there must be
2185     // a NUL on the replace stack, for when it is deleted with BS.
2186     if (REPLACE_NORMAL(State))
2187 	while (lead_len-- > 0)
2188 	    replace_push(NUL);
2189 
2190     curwin->w_cursor = old_cursor;
2191 
2192     if (dir == FORWARD)
2193     {
2194 	if (trunc_line || (State & INSERT))
2195 	{
2196 	    // truncate current line at cursor
2197 	    saved_line[curwin->w_cursor.col] = NUL;
2198 	    // Remove trailing white space, unless OPENLINE_KEEPTRAIL used.
2199 	    if (trunc_line && !(flags & OPENLINE_KEEPTRAIL))
2200 		truncate_spaces(saved_line);
2201 	    ml_replace(curwin->w_cursor.lnum, saved_line, FALSE);
2202 	    saved_line = NULL;
2203 	    if (did_append)
2204 	    {
2205 		changed_lines(curwin->w_cursor.lnum, curwin->w_cursor.col,
2206 					       curwin->w_cursor.lnum + 1, 1L);
2207 		did_append = FALSE;
2208 
2209 		// Move marks after the line break to the new line.
2210 		if (flags & OPENLINE_MARKFIX)
2211 		    mark_col_adjust(curwin->w_cursor.lnum,
2212 					 curwin->w_cursor.col + less_cols_off,
2213 						      1L, (long)-less_cols, 0);
2214 	    }
2215 	    else
2216 		changed_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col);
2217 	}
2218 
2219 	// Put the cursor on the new line.  Careful: the scrollup() above may
2220 	// have moved w_cursor, we must use old_cursor.
2221 	curwin->w_cursor.lnum = old_cursor.lnum + 1;
2222     }
2223     if (did_append)
2224 	changed_lines(curwin->w_cursor.lnum, 0, curwin->w_cursor.lnum, 1L);
2225 
2226     curwin->w_cursor.col = newcol;
2227     curwin->w_cursor.coladd = 0;
2228 
2229 #if defined(FEAT_LISP) || defined(FEAT_CINDENT)
2230     // In VREPLACE mode, we are handling the replace stack ourselves, so stop
2231     // fixthisline() from doing it (via change_indent()) by telling it we're in
2232     // normal INSERT mode.
2233     if (State & VREPLACE_FLAG)
2234     {
2235 	vreplace_mode = State;	// So we know to put things right later
2236 	State = INSERT;
2237     }
2238     else
2239 	vreplace_mode = 0;
2240 #endif
2241 #ifdef FEAT_LISP
2242     // May do lisp indenting.
2243     if (!p_paste
2244 	    && leader == NULL
2245 	    && curbuf->b_p_lisp
2246 	    && curbuf->b_p_ai)
2247     {
2248 	fixthisline(get_lisp_indent);
2249 	ai_col = (colnr_T)getwhitecols_curline();
2250     }
2251 #endif
2252 #ifdef FEAT_CINDENT
2253     // May do indenting after opening a new line.
2254     if (!p_paste
2255 	    && (curbuf->b_p_cin
2256 #  ifdef FEAT_EVAL
2257 		    || *curbuf->b_p_inde != NUL
2258 #  endif
2259 		)
2260 	    && in_cinkeys(dir == FORWARD
2261 		? KEY_OPEN_FORW
2262 		: KEY_OPEN_BACK, ' ', linewhite(curwin->w_cursor.lnum)))
2263     {
2264 	do_c_expr_indent();
2265 	ai_col = (colnr_T)getwhitecols_curline();
2266     }
2267 #endif
2268 #if defined(FEAT_LISP) || defined(FEAT_CINDENT)
2269     if (vreplace_mode != 0)
2270 	State = vreplace_mode;
2271 #endif
2272 
2273     // Finally, VREPLACE gets the stuff on the new line, then puts back the
2274     // original line, and inserts the new stuff char by char, pushing old stuff
2275     // onto the replace stack (via ins_char()).
2276     if (State & VREPLACE_FLAG)
2277     {
2278 	// Put new line in p_extra
2279 	p_extra = vim_strsave(ml_get_curline());
2280 	if (p_extra == NULL)
2281 	    goto theend;
2282 
2283 	// Put back original line
2284 	ml_replace(curwin->w_cursor.lnum, next_line, FALSE);
2285 
2286 	// Insert new stuff into line again
2287 	curwin->w_cursor.col = 0;
2288 	curwin->w_cursor.coladd = 0;
2289 	ins_bytes(p_extra);	// will call changed_bytes()
2290 	vim_free(p_extra);
2291 	next_line = NULL;
2292     }
2293 
2294     retval = OK;		// success!
2295 theend:
2296     curbuf->b_p_pi = saved_pi;
2297     vim_free(saved_line);
2298     vim_free(next_line);
2299     vim_free(allocated);
2300     return retval;
2301 }
2302 
2303 /*
2304  * Delete from cursor to end of line.
2305  * Caller must have prepared for undo.
2306  * If "fixpos" is TRUE fix the cursor position when done.
2307  *
2308  * Return FAIL for failure, OK otherwise.
2309  */
2310     int
truncate_line(int fixpos)2311 truncate_line(int fixpos)
2312 {
2313     char_u	*newp;
2314     linenr_T	lnum = curwin->w_cursor.lnum;
2315     colnr_T	col = curwin->w_cursor.col;
2316 
2317     if (col == 0)
2318 	newp = vim_strsave((char_u *)"");
2319     else
2320 	newp = vim_strnsave(ml_get(lnum), col);
2321 
2322     if (newp == NULL)
2323 	return FAIL;
2324 
2325     ml_replace(lnum, newp, FALSE);
2326 
2327     // mark the buffer as changed and prepare for displaying
2328     changed_bytes(lnum, curwin->w_cursor.col);
2329 
2330     // If "fixpos" is TRUE we don't want to end up positioned at the NUL.
2331     if (fixpos && curwin->w_cursor.col > 0)
2332 	--curwin->w_cursor.col;
2333 
2334     return OK;
2335 }
2336 
2337 /*
2338  * Delete "nlines" lines at the cursor.
2339  * Saves the lines for undo first if "undo" is TRUE.
2340  */
2341     void
del_lines(long nlines,int undo)2342 del_lines(long nlines,	int undo)
2343 {
2344     long	n;
2345     linenr_T	first = curwin->w_cursor.lnum;
2346 
2347     if (nlines <= 0)
2348 	return;
2349 
2350     // save the deleted lines for undo
2351     if (undo && u_savedel(first, nlines) == FAIL)
2352 	return;
2353 
2354     for (n = 0; n < nlines; )
2355     {
2356 	if (curbuf->b_ml.ml_flags & ML_EMPTY)	    // nothing to delete
2357 	    break;
2358 
2359 	ml_delete_flags(first, ML_DEL_MESSAGE);
2360 	++n;
2361 
2362 	// If we delete the last line in the file, stop
2363 	if (first > curbuf->b_ml.ml_line_count)
2364 	    break;
2365     }
2366 
2367     // Correct the cursor position before calling deleted_lines_mark(), it may
2368     // trigger a callback to display the cursor.
2369     curwin->w_cursor.col = 0;
2370     check_cursor_lnum();
2371 
2372     // adjust marks, mark the buffer as changed and prepare for displaying
2373     deleted_lines_mark(first, n);
2374 }
2375