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