blob: 4de17aa180139f5816efb459da75b2b18557f3a1 [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002 *
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 * edit.c: functions for Insert mode
12 */
13
14#include "vim.h"
15
Bram Moolenaar071d4272004-06-13 20:20:40 +000016#define BACKSPACE_CHAR 1
17#define BACKSPACE_WORD 2
18#define BACKSPACE_WORD_NOT_SPACE 3
19#define BACKSPACE_LINE 4
20
Bram Moolenaar7591bb32019-03-30 13:53:47 +010021#ifdef FEAT_INS_EXPAND
22/* Set when doing something for completion that may call edit() recursively,
23 * which is not allowed. */
24static int compl_busy = FALSE;
25#endif /* FEAT_INS_EXPAND */
26
27
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010028static void ins_ctrl_v(void);
Bram Moolenaarf2732452018-06-03 14:47:35 +020029#ifdef FEAT_JOB_CHANNEL
30static void init_prompt(int cmdchar_todo);
31#endif
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010032static void undisplay_dollar(void);
33static void insert_special(int, int, int);
34static void internal_format(int textwidth, int second_indent, int flags, int format_only, int c);
35static void check_auto_format(int);
36static void redo_literal(int c);
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010037static void start_arrow_common(pos_T *end_insert_pos, int change);
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +000038#ifdef FEAT_SPELL
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010039static void check_spell_redraw(void);
Bram Moolenaar217ad922005-03-20 22:37:15 +000040#endif
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010041static void stop_insert(pos_T *end_insert_pos, int esc, int nomove);
42static int echeck_abbr(int);
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010043static void replace_join(int off);
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010044static void mb_replace_pop_ins(int cc);
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010045static void replace_flush(void);
46static void replace_do_bs(int limit_col);
47static int del_char_after_col(int limit_col);
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010048static void ins_reg(void);
49static void ins_ctrl_g(void);
50static void ins_ctrl_hat(void);
51static int ins_esc(long *count, int cmdchar, int nomove);
Bram Moolenaar071d4272004-06-13 20:20:40 +000052#ifdef FEAT_RIGHTLEFT
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010053static void ins_ctrl_(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +000054#endif
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010055static int ins_start_select(int c);
56static void ins_insert(int replaceState);
57static void ins_ctrl_o(void);
58static void ins_shift(int c, int lastc);
59static void ins_del(void);
60static int ins_bs(int c, int mode, int *inserted_space_p);
Bram Moolenaar071d4272004-06-13 20:20:40 +000061#ifdef FEAT_MOUSE
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010062static void ins_mouse(int c);
63static void ins_mousescroll(int dir);
Bram Moolenaar071d4272004-06-13 20:20:40 +000064#endif
Bram Moolenaara23ccb82006-02-27 00:08:02 +000065#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010066static void ins_tabline(int c);
Bram Moolenaara23ccb82006-02-27 00:08:02 +000067#endif
Bram Moolenaar75bf3d22019-03-26 22:46:05 +010068static void ins_left(void);
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010069static void ins_home(int c);
70static void ins_end(int c);
71static void ins_s_left(void);
Bram Moolenaar75bf3d22019-03-26 22:46:05 +010072static void ins_right(void);
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010073static void ins_s_right(void);
74static void ins_up(int startcol);
75static void ins_pageup(void);
76static void ins_down(int startcol);
77static void ins_pagedown(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +000078#ifdef FEAT_DND
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010079static void ins_drop(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +000080#endif
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010081static int ins_tab(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +000082#ifdef FEAT_DIGRAPHS
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010083static int ins_digraph(void);
Bram Moolenaar071d4272004-06-13 20:20:40 +000084#endif
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010085static int ins_ctrl_ey(int tc);
Bram Moolenaar071d4272004-06-13 20:20:40 +000086#ifdef FEAT_SMARTINDENT
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010087static void ins_try_si(int c);
Bram Moolenaar071d4272004-06-13 20:20:40 +000088#endif
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +010089#if defined(FEAT_EVAL)
Bram Moolenaarf28dbce2016-01-29 22:03:47 +010090static char_u *do_insert_char_pre(int c);
Bram Moolenaarf5876f12012-02-29 18:22:08 +010091#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +000092
93static colnr_T Insstart_textlen; /* length of line when insert started */
94static colnr_T Insstart_blank_vcol; /* vcol for first inserted blank */
Bram Moolenaarb1d90a32014-02-22 23:03:55 +010095static int update_Insstart_orig = TRUE; /* set Insstart_orig to Insstart */
Bram Moolenaar071d4272004-06-13 20:20:40 +000096
97static char_u *last_insert = NULL; /* the text of the previous insert,
98 K_SPECIAL and CSI are escaped */
99static int last_insert_skip; /* nr of chars in front of previous insert */
100static int new_insert_skip; /* nr of chars in front of current insert */
Bram Moolenaar83c465c2005-12-16 21:53:56 +0000101static int did_restart_edit; /* "restart_edit" when calling edit() */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000102
103#ifdef FEAT_CINDENT
104static int can_cindent; /* may do cindenting on this line */
105#endif
106
107static int old_indent = 0; /* for ^^D command in insert mode */
108
109#ifdef FEAT_RIGHTLEFT
Bram Moolenaar6c0b44b2005-06-01 21:56:33 +0000110static int revins_on; /* reverse insert mode on */
111static int revins_chars; /* how much to skip after edit */
112static int revins_legal; /* was the last char 'legal'? */
113static int revins_scol; /* start column of revins session */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000114#endif
115
Bram Moolenaar071d4272004-06-13 20:20:40 +0000116static int ins_need_undo; /* call u_save() before inserting a
117 char. Set when edit() is called.
118 after that arrow_used is used. */
119
Bram Moolenaar75bf3d22019-03-26 22:46:05 +0100120static int did_add_space = FALSE; // auto_format() added an extra space
121 // under the cursor
122static int dont_sync_undo = FALSE; // CTRL-G U prevents syncing undo for
123 // the next left/right cursor key
Bram Moolenaar071d4272004-06-13 20:20:40 +0000124
125/*
126 * edit(): Start inserting text.
127 *
128 * "cmdchar" can be:
129 * 'i' normal insert command
130 * 'a' normal append command
Bram Moolenaarec2da362017-01-21 20:04:22 +0100131 * K_PS bracketed paste
Bram Moolenaar071d4272004-06-13 20:20:40 +0000132 * 'R' replace command
133 * 'r' "r<CR>" command: insert one <CR>. Note: count can be > 1, for redo,
134 * but still only one <CR> is inserted. The <Esc> is not used for redo.
135 * 'g' "gI" command.
136 * 'V' "gR" command for Virtual Replace mode.
137 * 'v' "gr" command for single character Virtual Replace mode.
138 *
139 * This function is not called recursively. For CTRL-O commands, it returns
140 * and lets the caller handle the Normal-mode command.
141 *
142 * Return TRUE if a CTRL-O command caused the return (insert mode pending).
143 */
144 int
Bram Moolenaar7454a062016-01-30 15:14:10 +0100145edit(
146 int cmdchar,
147 int startln, /* if set, insert at start of line */
148 long count)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000149{
150 int c = 0;
151 char_u *ptr;
Bram Moolenaar418f81b2016-02-16 20:12:02 +0100152 int lastc = 0;
Bram Moolenaar0ab2a882009-05-13 10:51:08 +0000153 int mincol;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000154 static linenr_T o_lnum = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000155 int i;
156 int did_backspace = TRUE; /* previous char was backspace */
157#ifdef FEAT_CINDENT
158 int line_is_white = FALSE; /* line is empty before insert */
159#endif
160 linenr_T old_topline = 0; /* topline before insertion */
161#ifdef FEAT_DIFF
162 int old_topfill = -1;
163#endif
164 int inserted_space = FALSE; /* just inserted a space */
165 int replaceState = REPLACE;
Bram Moolenaar488c6512005-08-11 20:09:58 +0000166 int nomove = FALSE; /* don't move cursor on return */
Bram Moolenaarf2732452018-06-03 14:47:35 +0200167#ifdef FEAT_JOB_CHANNEL
168 int cmdchar_todo = cmdchar;
169#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000170
Bram Moolenaar83c465c2005-12-16 21:53:56 +0000171 /* Remember whether editing was restarted after CTRL-O. */
172 did_restart_edit = restart_edit;
173
Bram Moolenaar071d4272004-06-13 20:20:40 +0000174 /* sleep before redrawing, needed for "CTRL-O :" that results in an
175 * error message */
176 check_for_delay(TRUE);
177
Bram Moolenaarb1d90a32014-02-22 23:03:55 +0100178 /* set Insstart_orig to Insstart */
179 update_Insstart_orig = TRUE;
180
Bram Moolenaar071d4272004-06-13 20:20:40 +0000181#ifdef HAVE_SANDBOX
182 /* Don't allow inserting in the sandbox. */
183 if (sandbox != 0)
184 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100185 emsg(_(e_sandbox));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000186 return FALSE;
187 }
188#endif
Bram Moolenaar8ada17c2006-01-19 22:16:24 +0000189 /* Don't allow changes in the buffer while editing the cmdline. The
190 * caller of getcmdline() may get confused. */
Bram Moolenaarb71eaae2006-01-20 23:10:18 +0000191 if (textlock != 0)
Bram Moolenaar8ada17c2006-01-19 22:16:24 +0000192 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100193 emsg(_(e_secure));
Bram Moolenaar8ada17c2006-01-19 22:16:24 +0000194 return FALSE;
195 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000196
197#ifdef FEAT_INS_EXPAND
Bram Moolenaarf193fff2006-04-27 00:02:13 +0000198 /* Don't allow recursive insert mode when busy with completion. */
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100199 if (ins_compl_active() || compl_busy || pum_visible())
Bram Moolenaarf193fff2006-04-27 00:02:13 +0000200 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +0100201 emsg(_(e_secure));
Bram Moolenaarf193fff2006-04-27 00:02:13 +0000202 return FALSE;
203 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000204 ins_compl_clear(); /* clear stuff for CTRL-X mode */
205#endif
206
Bram Moolenaar843ee412004-06-30 16:16:41 +0000207 /*
208 * Trigger InsertEnter autocommands. Do not do this for "r<CR>" or "grx".
209 */
210 if (cmdchar != 'r' && cmdchar != 'v')
211 {
Bram Moolenaar3e37fd02013-01-17 15:37:01 +0100212 pos_T save_cursor = curwin->w_cursor;
213
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100214#ifdef FEAT_EVAL
Bram Moolenaar843ee412004-06-30 16:16:41 +0000215 if (cmdchar == 'R')
216 ptr = (char_u *)"r";
217 else if (cmdchar == 'V')
218 ptr = (char_u *)"v";
219 else
220 ptr = (char_u *)"i";
221 set_vim_var_string(VV_INSERTMODE, ptr, 1);
Bram Moolenaar097c9922013-05-19 21:15:15 +0200222 set_vim_var_string(VV_CHAR, NULL, -1); /* clear v:char */
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100223#endif
Bram Moolenaar9fa95062018-08-08 22:08:32 +0200224 ins_apply_autocmds(EVENT_INSERTENTER);
Bram Moolenaar3e37fd02013-01-17 15:37:01 +0100225
Bram Moolenaar097c9922013-05-19 21:15:15 +0200226 /* Make sure the cursor didn't move. Do call check_cursor_col() in
227 * case the text was modified. Since Insert mode was not started yet
228 * a call to check_cursor_col() may move the cursor, especially with
229 * the "A" command, thus set State to avoid that. Also check that the
230 * line number is still valid (lines may have been deleted).
231 * Do not restore if v:char was set to a non-empty string. */
Bram Moolenaarb5aedf32017-03-12 18:23:53 +0100232 if (!EQUAL_POS(curwin->w_cursor, save_cursor)
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100233#ifdef FEAT_EVAL
Bram Moolenaar097c9922013-05-19 21:15:15 +0200234 && *get_vim_var_str(VV_CHAR) == NUL
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100235#endif
Bram Moolenaar097c9922013-05-19 21:15:15 +0200236 && save_cursor.lnum <= curbuf->b_ml.ml_line_count)
Bram Moolenaar3e37fd02013-01-17 15:37:01 +0100237 {
238 int save_state = State;
239
240 curwin->w_cursor = save_cursor;
241 State = INSERT;
242 check_cursor_col();
243 State = save_state;
244 }
Bram Moolenaar843ee412004-06-30 16:16:41 +0000245 }
Bram Moolenaar843ee412004-06-30 16:16:41 +0000246
Bram Moolenaarf5963f72010-07-23 22:10:27 +0200247#ifdef FEAT_CONCEAL
248 /* Check if the cursor line needs redrawing before changing State. If
249 * 'concealcursor' is "n" it needs to be redrawn without concealing. */
Bram Moolenaarb9464822018-05-10 15:09:49 +0200250 conceal_check_cursor_line();
Bram Moolenaarf5963f72010-07-23 22:10:27 +0200251#endif
252
Bram Moolenaar071d4272004-06-13 20:20:40 +0000253#ifdef FEAT_MOUSE
254 /*
255 * When doing a paste with the middle mouse button, Insstart is set to
256 * where the paste started.
257 */
258 if (where_paste_started.lnum != 0)
259 Insstart = where_paste_started;
260 else
261#endif
262 {
263 Insstart = curwin->w_cursor;
264 if (startln)
265 Insstart.col = 0;
266 }
Bram Moolenaar0ab2a882009-05-13 10:51:08 +0000267 Insstart_textlen = (colnr_T)linetabsize(ml_get_curline());
Bram Moolenaar071d4272004-06-13 20:20:40 +0000268 Insstart_blank_vcol = MAXCOL;
269 if (!did_ai)
270 ai_col = 0;
271
272 if (cmdchar != NUL && restart_edit == 0)
273 {
274 ResetRedobuff();
275 AppendNumberToRedobuff(count);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000276 if (cmdchar == 'V' || cmdchar == 'v')
277 {
278 /* "gR" or "gr" command */
279 AppendCharToRedobuff('g');
280 AppendCharToRedobuff((cmdchar == 'v') ? 'r' : 'R');
281 }
282 else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000283 {
Bram Moolenaar076e5022017-01-24 18:58:30 +0100284 if (cmdchar == K_PS)
285 AppendCharToRedobuff('a');
286 else
287 AppendCharToRedobuff(cmdchar);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000288 if (cmdchar == 'g') /* "gI" command */
289 AppendCharToRedobuff('I');
290 else if (cmdchar == 'r') /* "r<CR>" command */
291 count = 1; /* insert only one <CR> */
292 }
293 }
294
295 if (cmdchar == 'R')
296 {
Bram Moolenaar071d4272004-06-13 20:20:40 +0000297 State = REPLACE;
298 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000299 else if (cmdchar == 'V' || cmdchar == 'v')
300 {
301 State = VREPLACE;
302 replaceState = VREPLACE;
303 orig_line_count = curbuf->b_ml.ml_line_count;
304 vr_lines_changed = 1;
305 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000306 else
307 State = INSERT;
308
309 stop_insert_mode = FALSE;
310
311 /*
312 * Need to recompute the cursor position, it might move when the cursor is
313 * on a TAB or special character.
314 */
315 curs_columns(TRUE);
316
317 /*
318 * Enable langmap or IME, indicated by 'iminsert'.
319 * Note that IME may enabled/disabled without us noticing here, thus the
320 * 'iminsert' value may not reflect what is actually used. It is updated
321 * when hitting <Esc>.
322 */
323 if (curbuf->b_p_iminsert == B_IMODE_LMAP)
324 State |= LANGMAP;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100325#ifdef HAVE_INPUT_METHOD
Bram Moolenaar071d4272004-06-13 20:20:40 +0000326 im_set_active(curbuf->b_p_iminsert == B_IMODE_IM);
327#endif
328
Bram Moolenaar071d4272004-06-13 20:20:40 +0000329#ifdef FEAT_MOUSE
330 setmouse();
331#endif
332#ifdef FEAT_CMDL_INFO
333 clear_showcmd();
334#endif
335#ifdef FEAT_RIGHTLEFT
336 /* there is no reverse replace mode */
337 revins_on = (State == INSERT && p_ri);
338 if (revins_on)
339 undisplay_dollar();
340 revins_chars = 0;
341 revins_legal = 0;
342 revins_scol = -1;
343#endif
Bram Moolenaar48c9f3b2017-01-24 19:08:15 +0100344 if (!p_ek)
345 /* Disable bracketed paste mode, we won't recognize the escape
346 * sequences. */
347 out_str(T_BD);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000348
349 /*
350 * Handle restarting Insert mode.
Bram Moolenaara6c07602017-03-05 21:18:27 +0100351 * Don't do this for "CTRL-O ." (repeat an insert): In that case we get
352 * here with something in the stuff buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000353 */
354 if (restart_edit != 0 && stuff_empty())
355 {
356#ifdef FEAT_MOUSE
357 /*
358 * After a paste we consider text typed to be part of the insert for
359 * the pasted text. You can backspace over the pasted text too.
360 */
361 if (where_paste_started.lnum)
362 arrow_used = FALSE;
363 else
364#endif
365 arrow_used = TRUE;
366 restart_edit = 0;
367
368 /*
369 * If the cursor was after the end-of-line before the CTRL-O and it is
370 * now at the end-of-line, put it after the end-of-line (this is not
371 * correct in very rare cases).
372 * Also do this if curswant is greater than the current virtual
373 * column. Eg after "^O$" or "^O80|".
374 */
375 validate_virtcol();
376 update_curswant();
Bram Moolenaar68b76a62005-03-25 21:53:48 +0000377 if (((ins_at_eol && curwin->w_cursor.lnum == o_lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000378 || curwin->w_curswant > curwin->w_virtcol)
379 && *(ptr = ml_get_curline() + curwin->w_cursor.col) != NUL)
380 {
381 if (ptr[1] == NUL)
382 ++curwin->w_cursor.col;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000383 else if (has_mbyte)
384 {
Bram Moolenaar0fa313a2005-08-10 21:07:57 +0000385 i = (*mb_ptr2len)(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000386 if (ptr[i] == NUL)
387 curwin->w_cursor.col += i;
388 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000389 }
Bram Moolenaar68b76a62005-03-25 21:53:48 +0000390 ins_at_eol = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000391 }
392 else
393 arrow_used = FALSE;
394
395 /* we are in insert mode now, don't need to start it anymore */
396 need_start_insertmode = FALSE;
397
398 /* Need to save the line for undo before inserting the first char. */
399 ins_need_undo = TRUE;
400
401#ifdef FEAT_MOUSE
402 where_paste_started.lnum = 0;
403#endif
404#ifdef FEAT_CINDENT
405 can_cindent = TRUE;
406#endif
407#ifdef FEAT_FOLDING
408 /* The cursor line is not in a closed fold, unless 'insertmode' is set or
409 * restarting. */
410 if (!p_im && did_restart_edit == 0)
411 foldOpenCursor();
412#endif
413
414 /*
415 * If 'showmode' is set, show the current (insert/replace/..) mode.
416 * A warning message for changing a readonly file is given here, before
417 * actually changing anything. It's put after the mode, if any.
418 */
419 i = 0;
Bram Moolenaard12f5c12006-01-25 22:10:52 +0000420 if (p_smd && msg_silent == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000421 i = showmode();
422
423 if (!p_im && did_restart_edit == 0)
Bram Moolenaar21af89e2008-01-02 21:09:33 +0000424 change_warning(i == 0 ? 0 : i + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000425
426#ifdef CURSOR_SHAPE
427 ui_cursor_shape(); /* may show different cursor shape */
428#endif
429#ifdef FEAT_DIGRAPHS
430 do_digraph(-1); /* clear digraphs */
431#endif
432
Bram Moolenaar83c465c2005-12-16 21:53:56 +0000433 /*
434 * Get the current length of the redo buffer, those characters have to be
435 * skipped if we want to get to the inserted characters.
436 */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000437 ptr = get_inserted();
438 if (ptr == NULL)
439 new_insert_skip = 0;
440 else
441 {
442 new_insert_skip = (int)STRLEN(ptr);
443 vim_free(ptr);
444 }
445
446 old_indent = 0;
447
448 /*
449 * Main loop in Insert mode: repeat until Insert mode is left.
450 */
451 for (;;)
452 {
453#ifdef FEAT_RIGHTLEFT
454 if (!revins_legal)
455 revins_scol = -1; /* reset on illegal motions */
456 else
457 revins_legal = 0;
458#endif
459 if (arrow_used) /* don't repeat insert when arrow key used */
460 count = 0;
461
Bram Moolenaarb1d90a32014-02-22 23:03:55 +0100462 if (update_Insstart_orig)
463 Insstart_orig = Insstart;
464
Bram Moolenaar00672e12016-06-26 18:38:13 +0200465 if (stop_insert_mode
466#ifdef FEAT_INS_EXPAND
467 && !pum_visible()
468#endif
469 )
Bram Moolenaar071d4272004-06-13 20:20:40 +0000470 {
471 /* ":stopinsert" used or 'insertmode' reset */
472 count = 0;
473 goto doESCkey;
474 }
475
476 /* set curwin->w_curswant for next K_DOWN or K_UP */
477 if (!arrow_used)
478 curwin->w_set_curswant = TRUE;
479
480 /* If there is no typeahead may check for timestamps (e.g., for when a
481 * menu invoked a shell command). */
482 if (stuff_empty())
483 {
484 did_check_timestamps = FALSE;
485 if (need_check_timestamps)
486 check_timestamps(FALSE);
487 }
488
489 /*
490 * When emsg() was called msg_scroll will have been set.
491 */
492 msg_scroll = FALSE;
493
494#ifdef FEAT_GUI
495 /* When 'mousefocus' is set a mouse movement may have taken us to
496 * another window. "need_mouse_correct" may then be set because of an
497 * autocommand. */
498 if (need_mouse_correct)
499 gui_mouse_correct();
500#endif
501
502#ifdef FEAT_FOLDING
503 /* Open fold at the cursor line, according to 'foldopen'. */
504 if (fdo_flags & FDO_INSERT)
505 foldOpenCursor();
506 /* Close folds where the cursor isn't, according to 'foldclose' */
507 if (!char_avail())
508 foldCheckClose();
509#endif
510
Bram Moolenaarf2732452018-06-03 14:47:35 +0200511#ifdef FEAT_JOB_CHANNEL
512 if (bt_prompt(curbuf))
513 {
514 init_prompt(cmdchar_todo);
515 cmdchar_todo = NUL;
516 }
517#endif
518
Bram Moolenaar071d4272004-06-13 20:20:40 +0000519 /*
520 * If we inserted a character at the last position of the last line in
521 * the window, scroll the window one line up. This avoids an extra
522 * redraw.
523 * This is detected when the cursor column is smaller after inserting
524 * something.
525 * Don't do this when the topline changed already, it has
526 * already been adjusted (by insertchar() calling open_line())).
527 */
528 if (curbuf->b_mod_set
529 && curwin->w_p_wrap
530 && !did_backspace
531 && curwin->w_topline == old_topline
532#ifdef FEAT_DIFF
533 && curwin->w_topfill == old_topfill
534#endif
535 )
536 {
537 mincol = curwin->w_wcol;
538 validate_cursor_col();
539
Bram Moolenaar04958cb2018-06-23 19:23:02 +0200540 if (
541#ifdef FEAT_VARTABS
542 (int)curwin->w_wcol < mincol - tabstop_at(
543 get_nolist_virtcol(), curbuf->b_p_ts,
544 curbuf->b_p_vts_array)
545#else
546 (int)curwin->w_wcol < mincol - curbuf->b_p_ts
547#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000548 && curwin->w_wrow == W_WINROW(curwin)
Bram Moolenaar375e3392019-01-31 18:26:10 +0100549 + curwin->w_height - 1 - get_scrolloff_value()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000550 && (curwin->w_cursor.lnum != curwin->w_topline
551#ifdef FEAT_DIFF
552 || curwin->w_topfill > 0
553#endif
554 ))
555 {
556#ifdef FEAT_DIFF
557 if (curwin->w_topfill > 0)
558 --curwin->w_topfill;
559 else
560#endif
561#ifdef FEAT_FOLDING
562 if (hasFolding(curwin->w_topline, NULL, &old_topline))
563 set_topline(curwin, old_topline + 1);
564 else
565#endif
566 set_topline(curwin, curwin->w_topline + 1);
567 }
568 }
569
570 /* May need to adjust w_topline to show the cursor. */
571 update_topline();
572
573 did_backspace = FALSE;
574
575 validate_cursor(); /* may set must_redraw */
576
577 /*
578 * Redraw the display when no characters are waiting.
579 * Also shows mode, ruler and positions cursor.
580 */
Bram Moolenaar754b5602006-02-09 23:53:20 +0000581 ins_redraw(TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000582
Bram Moolenaar071d4272004-06-13 20:20:40 +0000583 if (curwin->w_p_scb)
584 do_check_scrollbind(TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000585
Bram Moolenaar860cae12010-06-05 23:22:07 +0200586 if (curwin->w_p_crb)
587 do_check_cursorbind();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000588 update_curswant();
589 old_topline = curwin->w_topline;
590#ifdef FEAT_DIFF
591 old_topfill = curwin->w_topfill;
592#endif
593
594#ifdef USE_ON_FLY_SCROLL
595 dont_scroll = FALSE; /* allow scrolling here */
596#endif
597
598 /*
Bram Moolenaarc5aa55d2017-11-28 20:47:40 +0100599 * Get a character for Insert mode. Ignore K_IGNORE and K_NOP.
Bram Moolenaar071d4272004-06-13 20:20:40 +0000600 */
Bram Moolenaar6c5bdb72015-03-13 13:24:23 +0100601 if (c != K_CURSORHOLD)
602 lastc = c; /* remember the previous char for CTRL-D */
Bram Moolenaar8b5f65a2015-09-01 19:26:12 +0200603
604 /* After using CTRL-G U the next cursor key will not break undo. */
605 if (dont_sync_undo == MAYBE)
606 dont_sync_undo = TRUE;
607 else
608 dont_sync_undo = FALSE;
Bram Moolenaarec2da362017-01-21 20:04:22 +0100609 if (cmdchar == K_PS)
610 /* Got here from normal mode when bracketed paste started. */
611 c = K_PS;
612 else
613 do
614 {
615 c = safe_vgetc();
Bram Moolenaar6d41c782018-06-06 09:11:12 +0200616
617 if (stop_insert_mode)
618 {
619 // Insert mode ended, possibly from a callback.
620 count = 0;
621 nomove = TRUE;
622 goto doESCkey;
623 }
Bram Moolenaarc5aa55d2017-11-28 20:47:40 +0100624 } while (c == K_IGNORE || c == K_NOP);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000625
Bram Moolenaard29a9ee2006-09-14 09:07:34 +0000626 /* Don't want K_CURSORHOLD for the second key, e.g., after CTRL-V. */
627 did_cursorhold = TRUE;
Bram Moolenaard29a9ee2006-09-14 09:07:34 +0000628
Bram Moolenaar071d4272004-06-13 20:20:40 +0000629#ifdef FEAT_RIGHTLEFT
630 if (p_hkmap && KeyTyped)
631 c = hkmap(c); /* Hebrew mode mapping */
632#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000633
634#ifdef FEAT_INS_EXPAND
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000635 /*
636 * Special handling of keys while the popup menu is visible or wanted
Bram Moolenaarbe46a1e2006-06-22 15:13:21 +0000637 * and the cursor is still in the completed word. Only when there is
638 * a match, skip this when no matches were found.
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000639 */
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100640 if (ins_compl_active()
Bram Moolenaarbe46a1e2006-06-22 15:13:21 +0000641 && pum_wanted()
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100642 && curwin->w_cursor.col >= ins_compl_col()
643 && ins_compl_has_shown_match())
Bram Moolenaara6557602006-02-04 22:43:20 +0000644 {
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000645 /* BS: Delete one character from "compl_leader". */
646 if ((c == K_BS || c == Ctrl_H)
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100647 && curwin->w_cursor.col > ins_compl_col()
Bram Moolenaarc1e37902006-04-18 21:55:01 +0000648 && (c = ins_compl_bs()) == NUL)
Bram Moolenaara6557602006-02-04 22:43:20 +0000649 continue;
650
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000651 /* When no match was selected or it was edited. */
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100652 if (!ins_compl_used_match())
Bram Moolenaara6557602006-02-04 22:43:20 +0000653 {
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000654 /* CTRL-L: Add one character from the current match to
Bram Moolenaarc1e37902006-04-18 21:55:01 +0000655 * "compl_leader". Except when at the original match and
656 * there is nothing to add, CTRL-L works like CTRL-P then. */
657 if (c == Ctrl_L
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100658 && (!ctrl_x_mode_line_or_eval()
659 || ins_compl_long_shown_match()))
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000660 {
661 ins_compl_addfrommatch();
662 continue;
663 }
664
Bram Moolenaar711d5b52007-10-19 18:40:51 +0000665 /* A non-white character that fits in with the current
666 * completion: Add to "compl_leader". */
667 if (ins_compl_accept_char(c))
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000668 {
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +0100669#if defined(FEAT_EVAL)
Bram Moolenaarf5876f12012-02-29 18:22:08 +0100670 /* Trigger InsertCharPre. */
671 char_u *str = do_insert_char_pre(c);
672 char_u *p;
673
674 if (str != NULL)
675 {
Bram Moolenaar91acfff2017-03-12 19:22:36 +0100676 for (p = str; *p != NUL; MB_PTR_ADV(p))
Bram Moolenaarf5876f12012-02-29 18:22:08 +0100677 ins_compl_addleader(PTR2CHAR(p));
678 vim_free(str);
679 }
680 else
681#endif
682 ins_compl_addleader(c);
Bram Moolenaar8b6144b2006-02-08 09:20:24 +0000683 continue;
684 }
Bram Moolenaarc7453f52006-02-10 23:20:28 +0000685
Bram Moolenaar0440ca32006-05-13 13:24:33 +0000686 /* Pressing CTRL-Y selects the current match. When
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100687 * ins_compl_enter_selects() is set the Enter key does the
688 * same. */
689 if ((c == Ctrl_Y || (ins_compl_enter_selects()
Bram Moolenaarcbd3bd62016-10-17 20:47:02 +0200690 && (c == CAR || c == K_KENTER || c == NL)))
691 && stop_arrow() == OK)
Bram Moolenaarc7453f52006-02-10 23:20:28 +0000692 {
693 ins_compl_delete();
Bram Moolenaar472e8592016-10-15 17:06:47 +0200694 ins_compl_insert(FALSE);
Bram Moolenaarc7453f52006-02-10 23:20:28 +0000695 }
Bram Moolenaara6557602006-02-04 22:43:20 +0000696 }
697 }
698
Bram Moolenaar071d4272004-06-13 20:20:40 +0000699 /* Prepare for or stop CTRL-X mode. This doesn't do completion, but
700 * it does fix up the text when finishing completion. */
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100701 ins_compl_init_get_longest();
Bram Moolenaard4e20a72008-01-22 16:50:03 +0000702 if (ins_compl_prep(c))
Bram Moolenaara6557602006-02-04 22:43:20 +0000703 continue;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000704#endif
705
Bram Moolenaar488c6512005-08-11 20:09:58 +0000706 /* CTRL-\ CTRL-N goes to Normal mode,
707 * CTRL-\ CTRL-G goes to mode selected with 'insertmode',
708 * CTRL-\ CTRL-O is like CTRL-O but without moving the cursor. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000709 if (c == Ctrl_BSL)
710 {
711 /* may need to redraw when no more chars available now */
Bram Moolenaar754b5602006-02-09 23:53:20 +0000712 ins_redraw(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000713 ++no_mapping;
714 ++allow_keys;
Bram Moolenaar61abfd12007-09-13 16:26:47 +0000715 c = plain_vgetc();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000716 --no_mapping;
717 --allow_keys;
Bram Moolenaar488c6512005-08-11 20:09:58 +0000718 if (c != Ctrl_N && c != Ctrl_G && c != Ctrl_O)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000719 {
Bram Moolenaar488c6512005-08-11 20:09:58 +0000720 /* it's something else */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000721 vungetc(c);
722 c = Ctrl_BSL;
723 }
724 else if (c == Ctrl_G && p_im)
725 continue;
726 else
727 {
Bram Moolenaar488c6512005-08-11 20:09:58 +0000728 if (c == Ctrl_O)
729 {
730 ins_ctrl_o();
731 ins_at_eol = FALSE; /* cursor keeps its column */
732 nomove = TRUE;
733 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000734 count = 0;
735 goto doESCkey;
736 }
737 }
738
739#ifdef FEAT_DIGRAPHS
740 c = do_digraph(c);
741#endif
742
743#ifdef FEAT_INS_EXPAND
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100744 if ((c == Ctrl_V || c == Ctrl_Q) && ctrl_x_mode_cmdline())
Bram Moolenaar071d4272004-06-13 20:20:40 +0000745 goto docomplete;
746#endif
747 if (c == Ctrl_V || c == Ctrl_Q)
748 {
749 ins_ctrl_v();
750 c = Ctrl_V; /* pretend CTRL-V is last typed character */
751 continue;
752 }
753
754#ifdef FEAT_CINDENT
755 if (cindent_on()
756# ifdef FEAT_INS_EXPAND
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100757 && ctrl_x_mode_none()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000758# endif
759 )
760 {
761 /* A key name preceded by a bang means this key is not to be
762 * inserted. Skip ahead to the re-indenting below.
763 * A key name preceded by a star means that indenting has to be
764 * done before inserting the key. */
765 line_is_white = inindent(0);
766 if (in_cinkeys(c, '!', line_is_white))
767 goto force_cindent;
768 if (can_cindent && in_cinkeys(c, '*', line_is_white)
769 && stop_arrow() == OK)
770 do_c_expr_indent();
771 }
772#endif
773
774#ifdef FEAT_RIGHTLEFT
775 if (curwin->w_p_rl)
776 switch (c)
777 {
778 case K_LEFT: c = K_RIGHT; break;
779 case K_S_LEFT: c = K_S_RIGHT; break;
780 case K_C_LEFT: c = K_C_RIGHT; break;
781 case K_RIGHT: c = K_LEFT; break;
782 case K_S_RIGHT: c = K_S_LEFT; break;
783 case K_C_RIGHT: c = K_C_LEFT; break;
784 }
785#endif
786
Bram Moolenaar071d4272004-06-13 20:20:40 +0000787 /*
788 * If 'keymodel' contains "startsel", may start selection. If it
789 * does, a CTRL-O and c will be stuffed, we need to get these
790 * characters.
791 */
792 if (ins_start_select(c))
793 continue;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000794
795 /*
796 * The big switch to handle a character in insert mode.
797 */
798 switch (c)
799 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000800 case ESC: /* End input mode */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000801 if (echeck_abbr(ESC + ABBR_OFF))
802 break;
Bram Moolenaar2f40d122017-10-24 21:49:36 +0200803 /* FALLTHROUGH */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000804
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000805 case Ctrl_C: /* End input mode */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000806#ifdef FEAT_CMDWIN
807 if (c == Ctrl_C && cmdwin_type != 0)
808 {
809 /* Close the cmdline window. */
810 cmdwin_result = K_IGNORE;
811 got_int = FALSE; /* don't stop executing autocommands et al. */
Bram Moolenaar5495cc92006-08-16 14:23:04 +0000812 nomove = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000813 goto doESCkey;
814 }
815#endif
Bram Moolenaar0e5979a2018-06-17 19:36:33 +0200816#ifdef FEAT_JOB_CHANNEL
817 if (c == Ctrl_C && bt_prompt(curbuf))
818 {
819 if (invoke_prompt_interrupt())
820 {
821 if (!bt_prompt(curbuf))
822 // buffer changed to a non-prompt buffer, get out of
823 // Insert mode
824 goto doESCkey;
825 break;
826 }
827 }
828#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000829
830#ifdef UNIX
831do_intr:
832#endif
833 /* when 'insertmode' set, and not halfway a mapping, don't leave
834 * Insert mode */
835 if (goto_im())
836 {
837 if (got_int)
838 {
839 (void)vgetc(); /* flush all buffers */
840 got_int = FALSE;
841 }
842 else
Bram Moolenaar165bc692015-07-21 17:53:25 +0200843 vim_beep(BO_IM);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000844 break;
845 }
846doESCkey:
847 /*
848 * This is the ONLY return from edit()!
849 */
850 /* Always update o_lnum, so that a "CTRL-O ." that adds a line
851 * still puts the cursor back after the inserted text. */
Bram Moolenaar68b76a62005-03-25 21:53:48 +0000852 if (ins_at_eol && gchar_cursor() == NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000853 o_lnum = curwin->w_cursor.lnum;
854
Bram Moolenaar488c6512005-08-11 20:09:58 +0000855 if (ins_esc(&count, cmdchar, nomove))
Bram Moolenaar843ee412004-06-30 16:16:41 +0000856 {
Bram Moolenaar4dbc2622018-11-02 11:59:15 +0100857 // When CTRL-C was typed got_int will be set, with the result
858 // that the autocommands won't be executed. When mapped got_int
859 // is not set, but let's keep the behavior the same.
860 if (cmdchar != 'r' && cmdchar != 'v' && c != Ctrl_C)
Bram Moolenaar9fa95062018-08-08 22:08:32 +0200861 ins_apply_autocmds(EVENT_INSERTLEAVE);
Bram Moolenaarc0a0ab52006-10-06 18:39:58 +0000862 did_cursorhold = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000863 return (c == Ctrl_O);
Bram Moolenaar843ee412004-06-30 16:16:41 +0000864 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000865 continue;
866
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000867 case Ctrl_Z: /* suspend when 'insertmode' set */
868 if (!p_im)
869 goto normalchar; /* insert CTRL-Z as normal char */
Bram Moolenaar25b0e6b2017-01-20 21:51:53 +0100870 do_cmdline_cmd((char_u *)"stop");
Bram Moolenaar74a47162017-02-26 19:09:05 +0100871#ifdef CURSOR_SHAPE
872 ui_cursor_shape(); /* may need to update cursor shape */
873#endif
874 continue;
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000875
876 case Ctrl_O: /* execute one command */
Bram Moolenaare344bea2005-09-01 20:46:49 +0000877#ifdef FEAT_COMPL_FUNC
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100878 if (ctrl_x_mode_omni())
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000879 goto docomplete;
880#endif
881 if (echeck_abbr(Ctrl_O + ABBR_OFF))
882 break;
883 ins_ctrl_o();
Bram Moolenaar06a89a52006-04-29 22:01:03 +0000884
Bram Moolenaar06a89a52006-04-29 22:01:03 +0000885 /* don't move the cursor left when 'virtualedit' has "onemore". */
886 if (ve_flags & VE_ONEMORE)
887 {
888 ins_at_eol = FALSE;
889 nomove = TRUE;
890 }
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000891 count = 0;
892 goto doESCkey;
893
Bram Moolenaar572cb562005-08-05 21:35:02 +0000894 case K_INS: /* toggle insert/replace mode */
895 case K_KINS:
896 ins_insert(replaceState);
897 break;
898
899 case K_SELECT: /* end of Select mode mapping - ignore */
900 break;
901
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000902 case K_HELP: /* Help key works like <ESC> <Help> */
903 case K_F1:
904 case K_XF1:
905 stuffcharReadbuff(K_HELP);
906 if (p_im)
907 need_start_insertmode = TRUE;
908 goto doESCkey;
909
910#ifdef FEAT_NETBEANS_INTG
911 case K_F21: /* NetBeans command */
912 ++no_mapping; /* don't map the next key hits */
Bram Moolenaar61abfd12007-09-13 16:26:47 +0000913 i = plain_vgetc();
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000914 --no_mapping;
915 netbeans_keycommand(i);
916 break;
917#endif
918
919 case K_ZERO: /* Insert the previously inserted text. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000920 case NUL:
921 case Ctrl_A:
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000922 /* For ^@ the trailing ESC will end the insert, unless there is an
923 * error. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000924 if (stuff_inserted(NUL, 1L, (c == Ctrl_A)) == FAIL
925 && c != Ctrl_A && !p_im)
926 goto doESCkey; /* quit insert mode */
927 inserted_space = FALSE;
928 break;
929
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000930 case Ctrl_R: /* insert the contents of a register */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000931 ins_reg();
932 auto_format(FALSE, TRUE);
933 inserted_space = FALSE;
934 break;
935
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000936 case Ctrl_G: /* commands starting with CTRL-G */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000937 ins_ctrl_g();
938 break;
939
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000940 case Ctrl_HAT: /* switch input mode and/or langmap */
941 ins_ctrl_hat();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000942 break;
943
944#ifdef FEAT_RIGHTLEFT
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000945 case Ctrl__: /* switch between languages */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000946 if (!p_ari)
947 goto normalchar;
948 ins_ctrl_();
949 break;
950#endif
951
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000952 case Ctrl_D: /* Make indent one shiftwidth smaller. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000953#if defined(FEAT_INS_EXPAND) && defined(FEAT_FIND_ID)
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100954 if (ctrl_x_mode_path_defines())
Bram Moolenaar071d4272004-06-13 20:20:40 +0000955 goto docomplete;
956#endif
957 /* FALLTHROUGH */
958
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000959 case Ctrl_T: /* Make indent one shiftwidth greater. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000960# ifdef FEAT_INS_EXPAND
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100961 if (c == Ctrl_T && ctrl_x_mode_thesaurus())
Bram Moolenaar071d4272004-06-13 20:20:40 +0000962 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000963 if (has_compl_option(FALSE))
964 goto docomplete;
965 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000966 }
967# endif
968 ins_shift(c, lastc);
969 auto_format(FALSE, TRUE);
970 inserted_space = FALSE;
971 break;
972
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000973 case K_DEL: /* delete character under the cursor */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000974 case K_KDEL:
975 ins_del();
976 auto_format(FALSE, TRUE);
977 break;
978
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000979 case K_BS: /* delete character before the cursor */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000980 case Ctrl_H:
981 did_backspace = ins_bs(c, BACKSPACE_CHAR, &inserted_space);
982 auto_format(FALSE, TRUE);
983 break;
984
Bram Moolenaar4be06f92005-07-29 22:36:03 +0000985 case Ctrl_W: /* delete word before the cursor */
Bram Moolenaar6d41c782018-06-06 09:11:12 +0200986#ifdef FEAT_JOB_CHANNEL
987 if (bt_prompt(curbuf) && (mod_mask & MOD_MASK_SHIFT) == 0)
988 {
989 // In a prompt window CTRL-W is used for window commands.
990 // Use Shift-CTRL-W to delete a word.
991 stuffcharReadbuff(Ctrl_W);
Bram Moolenaar942b4542018-06-17 16:23:34 +0200992 restart_edit = 'A';
Bram Moolenaar6d41c782018-06-06 09:11:12 +0200993 nomove = TRUE;
994 count = 0;
995 goto doESCkey;
996 }
997#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000998 did_backspace = ins_bs(c, BACKSPACE_WORD, &inserted_space);
999 auto_format(FALSE, TRUE);
1000 break;
1001
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001002 case Ctrl_U: /* delete all inserted text in current line */
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00001003# ifdef FEAT_COMPL_FUNC
1004 /* CTRL-X CTRL-U completes with 'completefunc'. */
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001005 if (ctrl_x_mode_function())
Bram Moolenaarcfbc5ee2004-07-02 15:38:35 +00001006 goto docomplete;
1007# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001008 did_backspace = ins_bs(c, BACKSPACE_LINE, &inserted_space);
1009 auto_format(FALSE, TRUE);
1010 inserted_space = FALSE;
1011 break;
1012
1013#ifdef FEAT_MOUSE
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001014 case K_LEFTMOUSE: /* mouse keys */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001015 case K_LEFTMOUSE_NM:
1016 case K_LEFTDRAG:
1017 case K_LEFTRELEASE:
1018 case K_LEFTRELEASE_NM:
Bram Moolenaar51b0f372017-11-18 18:52:04 +01001019 case K_MOUSEMOVE:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001020 case K_MIDDLEMOUSE:
1021 case K_MIDDLEDRAG:
1022 case K_MIDDLERELEASE:
1023 case K_RIGHTMOUSE:
1024 case K_RIGHTDRAG:
1025 case K_RIGHTRELEASE:
1026 case K_X1MOUSE:
1027 case K_X1DRAG:
1028 case K_X1RELEASE:
1029 case K_X2MOUSE:
1030 case K_X2DRAG:
1031 case K_X2RELEASE:
1032 ins_mouse(c);
1033 break;
1034
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001035 case K_MOUSEDOWN: /* Default action for scroll wheel up: scroll up */
Bram Moolenaar8d9b40e2010-07-25 15:49:07 +02001036 ins_mousescroll(MSCR_DOWN);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001037 break;
1038
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001039 case K_MOUSEUP: /* Default action for scroll wheel down: scroll down */
Bram Moolenaar8d9b40e2010-07-25 15:49:07 +02001040 ins_mousescroll(MSCR_UP);
1041 break;
1042
1043 case K_MOUSELEFT: /* Scroll wheel left */
1044 ins_mousescroll(MSCR_LEFT);
1045 break;
1046
1047 case K_MOUSERIGHT: /* Scroll wheel right */
1048 ins_mousescroll(MSCR_RIGHT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001049 break;
1050#endif
Bram Moolenaarec2da362017-01-21 20:04:22 +01001051 case K_PS:
1052 bracketed_paste(PASTE_INSERT, FALSE, NULL);
1053 if (cmdchar == K_PS)
1054 /* invoked from normal mode, bail out */
1055 goto doESCkey;
1056 break;
1057 case K_PE:
1058 /* Got K_PE without K_PS, ignore. */
1059 break;
1060
Bram Moolenaara23ccb82006-02-27 00:08:02 +00001061#ifdef FEAT_GUI_TABLINE
1062 case K_TABLINE:
1063 case K_TABMENU:
1064 ins_tabline(c);
1065 break;
1066#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001067
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001068 case K_IGNORE: /* Something mapped to nothing */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001069 break;
1070
Bram Moolenaar754b5602006-02-09 23:53:20 +00001071 case K_CURSORHOLD: /* Didn't type something for a while. */
Bram Moolenaar9fa95062018-08-08 22:08:32 +02001072 ins_apply_autocmds(EVENT_CURSORHOLDI);
Bram Moolenaar754b5602006-02-09 23:53:20 +00001073 did_cursorhold = TRUE;
1074 break;
Bram Moolenaar754b5602006-02-09 23:53:20 +00001075
Bram Moolenaar4f974752019-02-17 17:44:42 +01001076#ifdef FEAT_GUI_MSWIN
1077 /* On MS-Windows ignore <M-F4>, we get it when closing the window
1078 * was cancelled. */
Bram Moolenaar4770d092006-01-12 23:22:24 +00001079 case K_F4:
1080 if (mod_mask != MOD_MASK_ALT)
1081 goto normalchar;
1082 break;
1083#endif
1084
Bram Moolenaar071d4272004-06-13 20:20:40 +00001085#ifdef FEAT_GUI
1086 case K_VER_SCROLLBAR:
1087 ins_scroll();
1088 break;
1089
1090 case K_HOR_SCROLLBAR:
1091 ins_horscroll();
1092 break;
1093#endif
1094
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001095 case K_HOME: /* <Home> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001096 case K_KHOME:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001097 case K_S_HOME:
1098 case K_C_HOME:
1099 ins_home(c);
1100 break;
1101
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001102 case K_END: /* <End> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001103 case K_KEND:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001104 case K_S_END:
1105 case K_C_END:
1106 ins_end(c);
1107 break;
1108
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001109 case K_LEFT: /* <Left> */
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001110 if (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL))
1111 ins_s_left();
1112 else
Bram Moolenaar75bf3d22019-03-26 22:46:05 +01001113 ins_left();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001114 break;
1115
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001116 case K_S_LEFT: /* <S-Left> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001117 case K_C_LEFT:
1118 ins_s_left();
1119 break;
1120
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001121 case K_RIGHT: /* <Right> */
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001122 if (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL))
1123 ins_s_right();
1124 else
Bram Moolenaar75bf3d22019-03-26 22:46:05 +01001125 ins_right();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001126 break;
1127
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001128 case K_S_RIGHT: /* <S-Right> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001129 case K_C_RIGHT:
1130 ins_s_right();
1131 break;
1132
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001133 case K_UP: /* <Up> */
Bram Moolenaarc7453f52006-02-10 23:20:28 +00001134#ifdef FEAT_INS_EXPAND
1135 if (pum_visible())
1136 goto docomplete;
1137#endif
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001138 if (mod_mask & MOD_MASK_SHIFT)
1139 ins_pageup();
1140 else
1141 ins_up(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001142 break;
1143
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001144 case K_S_UP: /* <S-Up> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001145 case K_PAGEUP:
1146 case K_KPAGEUP:
Bram Moolenaara9b1e742005-12-19 22:14:58 +00001147#ifdef FEAT_INS_EXPAND
Bram Moolenaare3226be2005-12-18 22:10:00 +00001148 if (pum_visible())
1149 goto docomplete;
Bram Moolenaara9b1e742005-12-19 22:14:58 +00001150#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001151 ins_pageup();
1152 break;
1153
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001154 case K_DOWN: /* <Down> */
Bram Moolenaarc7453f52006-02-10 23:20:28 +00001155#ifdef FEAT_INS_EXPAND
1156 if (pum_visible())
1157 goto docomplete;
1158#endif
Bram Moolenaarbc7aa852005-03-06 23:38:09 +00001159 if (mod_mask & MOD_MASK_SHIFT)
1160 ins_pagedown();
1161 else
1162 ins_down(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001163 break;
1164
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001165 case K_S_DOWN: /* <S-Down> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001166 case K_PAGEDOWN:
1167 case K_KPAGEDOWN:
Bram Moolenaara9b1e742005-12-19 22:14:58 +00001168#ifdef FEAT_INS_EXPAND
Bram Moolenaare3226be2005-12-18 22:10:00 +00001169 if (pum_visible())
1170 goto docomplete;
Bram Moolenaara9b1e742005-12-19 22:14:58 +00001171#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001172 ins_pagedown();
1173 break;
1174
1175#ifdef FEAT_DND
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001176 case K_DROP: /* drag-n-drop event */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001177 ins_drop();
1178 break;
1179#endif
1180
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001181 case K_S_TAB: /* When not mapped, use like a normal TAB */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001182 c = TAB;
1183 /* FALLTHROUGH */
1184
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001185 case TAB: /* TAB or Complete patterns along path */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001186#if defined(FEAT_INS_EXPAND) && defined(FEAT_FIND_ID)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001187 if (ctrl_x_mode_path_patterns())
Bram Moolenaar071d4272004-06-13 20:20:40 +00001188 goto docomplete;
1189#endif
1190 inserted_space = FALSE;
1191 if (ins_tab())
1192 goto normalchar; /* insert TAB as a normal char */
1193 auto_format(FALSE, TRUE);
1194 break;
1195
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001196 case K_KENTER: /* <Enter> */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001197 c = CAR;
1198 /* FALLTHROUGH */
1199 case CAR:
1200 case NL:
Bram Moolenaar4033c552017-09-16 20:54:51 +02001201#if defined(FEAT_QUICKFIX)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001202 /* In a quickfix window a <CR> jumps to the error under the
1203 * cursor. */
1204 if (bt_quickfix(curbuf) && c == CAR)
1205 {
Bram Moolenaard12f5c12006-01-25 22:10:52 +00001206 if (curwin->w_llist_ref == NULL) /* quickfix window */
1207 do_cmdline_cmd((char_u *)".cc");
1208 else /* location list window */
1209 do_cmdline_cmd((char_u *)".ll");
Bram Moolenaar071d4272004-06-13 20:20:40 +00001210 break;
1211 }
1212#endif
1213#ifdef FEAT_CMDWIN
1214 if (cmdwin_type != 0)
1215 {
1216 /* Execute the command in the cmdline window. */
1217 cmdwin_result = CAR;
1218 goto doESCkey;
1219 }
1220#endif
Bram Moolenaarf2732452018-06-03 14:47:35 +02001221#ifdef FEAT_JOB_CHANNEL
1222 if (bt_prompt(curbuf))
1223 {
Bram Moolenaarf2732452018-06-03 14:47:35 +02001224 invoke_prompt_callback();
Bram Moolenaar891e1fd2018-06-06 18:02:39 +02001225 if (!bt_prompt(curbuf))
1226 // buffer changed to a non-prompt buffer, get out of
1227 // Insert mode
Bram Moolenaarf2732452018-06-03 14:47:35 +02001228 goto doESCkey;
1229 break;
1230 }
1231#endif
Bram Moolenaar24a2d722018-04-24 19:36:43 +02001232 if (ins_eol(c) == FAIL && !p_im)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001233 goto doESCkey; /* out of memory */
1234 auto_format(FALSE, FALSE);
1235 inserted_space = FALSE;
1236 break;
1237
Bram Moolenaar860cae12010-06-05 23:22:07 +02001238#if defined(FEAT_DIGRAPHS) || defined(FEAT_INS_EXPAND)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001239 case Ctrl_K: /* digraph or keyword completion */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001240# ifdef FEAT_INS_EXPAND
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001241 if (ctrl_x_mode_dictionary())
Bram Moolenaar071d4272004-06-13 20:20:40 +00001242 {
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001243 if (has_compl_option(TRUE))
1244 goto docomplete;
1245 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001246 }
1247# endif
1248# ifdef FEAT_DIGRAPHS
1249 c = ins_digraph();
1250 if (c == NUL)
1251 break;
1252# endif
1253 goto normalchar;
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001254#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001255
1256#ifdef FEAT_INS_EXPAND
Bram Moolenaar572cb562005-08-05 21:35:02 +00001257 case Ctrl_X: /* Enter CTRL-X mode */
1258 ins_ctrl_x();
1259 break;
1260
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001261 case Ctrl_RSB: /* Tag name completion after ^X */
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001262 if (!ctrl_x_mode_tags())
Bram Moolenaar071d4272004-06-13 20:20:40 +00001263 goto normalchar;
1264 goto docomplete;
1265
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001266 case Ctrl_F: /* File name completion after ^X */
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001267 if (!ctrl_x_mode_files())
Bram Moolenaar071d4272004-06-13 20:20:40 +00001268 goto normalchar;
1269 goto docomplete;
Bram Moolenaar488c6512005-08-11 20:09:58 +00001270
1271 case 's': /* Spelling completion after ^X */
1272 case Ctrl_S:
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001273 if (!ctrl_x_mode_spell())
Bram Moolenaar488c6512005-08-11 20:09:58 +00001274 goto normalchar;
1275 goto docomplete;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001276#endif
1277
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001278 case Ctrl_L: /* Whole line completion after ^X */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001279#ifdef FEAT_INS_EXPAND
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001280 if (!ctrl_x_mode_whole_line())
Bram Moolenaar071d4272004-06-13 20:20:40 +00001281#endif
1282 {
1283 /* CTRL-L with 'insertmode' set: Leave Insert mode */
1284 if (p_im)
1285 {
1286 if (echeck_abbr(Ctrl_L + ABBR_OFF))
1287 break;
1288 goto doESCkey;
1289 }
1290 goto normalchar;
1291 }
1292#ifdef FEAT_INS_EXPAND
1293 /* FALLTHROUGH */
1294
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001295 case Ctrl_P: /* Do previous/next pattern completion */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001296 case Ctrl_N:
1297 /* if 'complete' is empty then plain ^P is no longer special,
1298 * but it is under other ^X modes */
1299 if (*curbuf->b_p_cpt == NUL
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001300 && (ctrl_x_mode_normal() || ctrl_x_mode_whole_line())
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001301 && !(compl_cont_status & CONT_LOCAL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001302 goto normalchar;
1303
1304docomplete:
Bram Moolenaar031e0dd2009-07-09 16:15:16 +00001305 compl_busy = TRUE;
Bram Moolenaara6c07602017-03-05 21:18:27 +01001306#ifdef FEAT_FOLDING
Bram Moolenaar429fcfb2016-04-14 16:22:04 +02001307 disable_fold_update++; /* don't redraw folds here */
Bram Moolenaara6c07602017-03-05 21:18:27 +01001308#endif
Bram Moolenaar8aefbe02016-02-23 20:13:16 +01001309 if (ins_complete(c, TRUE) == FAIL)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001310 compl_cont_status = 0;
Bram Moolenaara6c07602017-03-05 21:18:27 +01001311#ifdef FEAT_FOLDING
Bram Moolenaar429fcfb2016-04-14 16:22:04 +02001312 disable_fold_update--;
Bram Moolenaara6c07602017-03-05 21:18:27 +01001313#endif
Bram Moolenaar031e0dd2009-07-09 16:15:16 +00001314 compl_busy = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001315 break;
1316#endif /* FEAT_INS_EXPAND */
1317
Bram Moolenaar4be06f92005-07-29 22:36:03 +00001318 case Ctrl_Y: /* copy from previous line or scroll down */
1319 case Ctrl_E: /* copy from next line or scroll up */
1320 c = ins_ctrl_ey(c);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001321 break;
1322
1323 default:
1324#ifdef UNIX
1325 if (c == intr_char) /* special interrupt char */
1326 goto do_intr;
1327#endif
1328
Bram Moolenaare659c952011-05-19 17:25:41 +02001329normalchar:
Bram Moolenaar071d4272004-06-13 20:20:40 +00001330 /*
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02001331 * Insert a normal character.
Bram Moolenaar071d4272004-06-13 20:20:40 +00001332 */
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001333#if defined(FEAT_EVAL)
Bram Moolenaare659c952011-05-19 17:25:41 +02001334 if (!p_paste)
1335 {
Bram Moolenaarf5876f12012-02-29 18:22:08 +01001336 /* Trigger InsertCharPre. */
1337 char_u *str = do_insert_char_pre(c);
1338 char_u *p;
1339
1340 if (str != NULL)
Bram Moolenaare659c952011-05-19 17:25:41 +02001341 {
Bram Moolenaarf5876f12012-02-29 18:22:08 +01001342 if (*str != NUL && stop_arrow() != FAIL)
Bram Moolenaare659c952011-05-19 17:25:41 +02001343 {
Bram Moolenaarf5876f12012-02-29 18:22:08 +01001344 /* Insert the new value of v:char literally. */
Bram Moolenaar91acfff2017-03-12 19:22:36 +01001345 for (p = str; *p != NUL; MB_PTR_ADV(p))
Bram Moolenaare659c952011-05-19 17:25:41 +02001346 {
Bram Moolenaarf5876f12012-02-29 18:22:08 +01001347 c = PTR2CHAR(p);
1348 if (c == CAR || c == K_KENTER || c == NL)
1349 ins_eol(c);
1350 else
1351 ins_char(c);
Bram Moolenaare659c952011-05-19 17:25:41 +02001352 }
Bram Moolenaarf5876f12012-02-29 18:22:08 +01001353 AppendToRedobuffLit(str, -1);
Bram Moolenaare659c952011-05-19 17:25:41 +02001354 }
Bram Moolenaarf5876f12012-02-29 18:22:08 +01001355 vim_free(str);
1356 c = NUL;
Bram Moolenaare659c952011-05-19 17:25:41 +02001357 }
1358
Bram Moolenaarf5876f12012-02-29 18:22:08 +01001359 /* If the new value is already inserted or an empty string
1360 * then don't insert any character. */
Bram Moolenaare659c952011-05-19 17:25:41 +02001361 if (c == NUL)
1362 break;
1363 }
1364#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001365#ifdef FEAT_SMARTINDENT
1366 /* Try to perform smart-indenting. */
1367 ins_try_si(c);
1368#endif
1369
1370 if (c == ' ')
1371 {
1372 inserted_space = TRUE;
1373#ifdef FEAT_CINDENT
1374 if (inindent(0))
1375 can_cindent = FALSE;
1376#endif
1377 if (Insstart_blank_vcol == MAXCOL
1378 && curwin->w_cursor.lnum == Insstart.lnum)
1379 Insstart_blank_vcol = get_nolist_virtcol();
1380 }
1381
Bram Moolenaare0ebfd72012-04-05 16:07:06 +02001382 /* Insert a normal character and check for abbreviations on a
1383 * special character. Let CTRL-] expand abbreviations without
1384 * inserting it. */
1385 if (vim_iswordc(c) || (!echeck_abbr(
Bram Moolenaar13505972019-01-24 15:04:48 +01001386 // Add ABBR_OFF for characters above 0x100, this is
1387 // what check_abbr() expects.
1388 (has_mbyte && c >= 0x100) ? (c + ABBR_OFF) : c)
1389 && c != Ctrl_RSB))
Bram Moolenaar071d4272004-06-13 20:20:40 +00001390 {
1391 insert_special(c, FALSE, FALSE);
1392#ifdef FEAT_RIGHTLEFT
1393 revins_legal++;
1394 revins_chars++;
1395#endif
1396 }
1397
1398 auto_format(FALSE, TRUE);
1399
1400#ifdef FEAT_FOLDING
1401 /* When inserting a character the cursor line must never be in a
1402 * closed fold. */
1403 foldOpenCursor();
1404#endif
1405 break;
1406 } /* end of switch (c) */
1407
Bram Moolenaard29a9ee2006-09-14 09:07:34 +00001408 /* If typed something may trigger CursorHoldI again. */
Bram Moolenaar245c4102016-04-20 17:37:41 +02001409 if (c != K_CURSORHOLD
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001410#ifdef FEAT_COMPL_FUNC
Bram Moolenaar02ae9b42018-02-09 15:06:02 +01001411 /* but not in CTRL-X mode, a script can't restore the state */
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001412 && ctrl_x_mode_normal()
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001413#endif
Bram Moolenaar245c4102016-04-20 17:37:41 +02001414 )
Bram Moolenaard29a9ee2006-09-14 09:07:34 +00001415 did_cursorhold = FALSE;
Bram Moolenaard29a9ee2006-09-14 09:07:34 +00001416
Bram Moolenaar071d4272004-06-13 20:20:40 +00001417 /* If the cursor was moved we didn't just insert a space */
1418 if (arrow_used)
1419 inserted_space = FALSE;
1420
1421#ifdef FEAT_CINDENT
1422 if (can_cindent && cindent_on()
1423# ifdef FEAT_INS_EXPAND
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001424 && ctrl_x_mode_normal()
Bram Moolenaar071d4272004-06-13 20:20:40 +00001425# endif
1426 )
1427 {
1428force_cindent:
1429 /*
1430 * Indent now if a key was typed that is in 'cinkeys'.
1431 */
1432 if (in_cinkeys(c, ' ', line_is_white))
1433 {
1434 if (stop_arrow() == OK)
1435 /* re-indent the current line */
1436 do_c_expr_indent();
1437 }
1438 }
1439#endif /* FEAT_CINDENT */
1440
1441 } /* for (;;) */
1442 /* NOTREACHED */
1443}
1444
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001445 int
1446ins_need_undo_get(void)
1447{
1448 return ins_need_undo;
1449}
1450
Bram Moolenaar071d4272004-06-13 20:20:40 +00001451/*
1452 * Redraw for Insert mode.
1453 * This is postponed until getting the next character to make '$' in the 'cpo'
1454 * option work correctly.
1455 * Only redraw when there are no characters available. This speeds up
1456 * inserting sequences of characters (e.g., for CTRL-R).
1457 */
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001458 void
Bram Moolenaar3397f742019-06-02 18:40:06 +02001459ins_redraw(int ready) // not busy with something
Bram Moolenaar071d4272004-06-13 20:20:40 +00001460{
Bram Moolenaarb2c03502010-07-02 20:20:09 +02001461#ifdef FEAT_CONCEAL
1462 linenr_T conceal_old_cursor_line = 0;
1463 linenr_T conceal_new_cursor_line = 0;
1464 int conceal_update_lines = FALSE;
1465#endif
1466
Bram Moolenaare21b6b22014-01-14 12:17:02 +01001467 if (char_avail())
1468 return;
1469
Bram Moolenaare21b6b22014-01-14 12:17:02 +01001470 /* Trigger CursorMoved if the cursor moved. Not when the popup menu is
1471 * visible, the command might delete it. */
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001472 if (ready && (has_cursormovedI()
Bram Moolenaar3397f742019-06-02 18:40:06 +02001473# ifdef FEAT_TEXT_PROP
1474 || popup_visible
1475# endif
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001476# if defined(FEAT_CONCEAL)
1477 || curwin->w_p_cole > 0
Bram Moolenaarb2c03502010-07-02 20:20:09 +02001478# endif
Bram Moolenaare21b6b22014-01-14 12:17:02 +01001479 )
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001480 && !EQUAL_POS(last_cursormoved, curwin->w_cursor)
Bram Moolenaare21b6b22014-01-14 12:17:02 +01001481# ifdef FEAT_INS_EXPAND
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001482 && !pum_visible()
Bram Moolenaare21b6b22014-01-14 12:17:02 +01001483# endif
1484 )
1485 {
1486# ifdef FEAT_SYN_HL
1487 /* Need to update the screen first, to make sure syntax
1488 * highlighting is correct after making a change (e.g., inserting
1489 * a "(". The autocommand may also require a redraw, so it's done
1490 * again below, unfortunately. */
1491 if (syntax_present(curwin) && must_redraw)
1492 update_screen(0);
1493# endif
Bram Moolenaare21b6b22014-01-14 12:17:02 +01001494 if (has_cursormovedI())
Bram Moolenaarf068dca2016-02-09 21:24:46 +01001495 {
1496 /* Make sure curswant is correct, an autocommand may call
1497 * getcurpos(). */
1498 update_curswant();
Bram Moolenaar9fa95062018-08-08 22:08:32 +02001499 ins_apply_autocmds(EVENT_CURSORMOVEDI);
Bram Moolenaarf068dca2016-02-09 21:24:46 +01001500 }
Bram Moolenaar3397f742019-06-02 18:40:06 +02001501#ifdef FEAT_TEXT_PROP
1502 if (popup_visible)
1503 popup_check_cursor_pos();
1504#endif
Bram Moolenaare21b6b22014-01-14 12:17:02 +01001505# ifdef FEAT_CONCEAL
1506 if (curwin->w_p_cole > 0)
1507 {
1508 conceal_old_cursor_line = last_cursormoved.lnum;
1509 conceal_new_cursor_line = curwin->w_cursor.lnum;
1510 conceal_update_lines = TRUE;
1511 }
1512# endif
1513 last_cursormoved = curwin->w_cursor;
1514 }
Bram Moolenaare21b6b22014-01-14 12:17:02 +01001515
Bram Moolenaare21b6b22014-01-14 12:17:02 +01001516 /* Trigger TextChangedI if b_changedtick differs. */
1517 if (ready && has_textchangedI()
Bram Moolenaar5a093432018-02-10 18:15:19 +01001518 && curbuf->b_last_changedtick != CHANGEDTICK(curbuf)
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001519#ifdef FEAT_INS_EXPAND
Bram Moolenaarb2c03502010-07-02 20:20:09 +02001520 && !pum_visible()
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001521#endif
Bram Moolenaare21b6b22014-01-14 12:17:02 +01001522 )
1523 {
Bram Moolenaar6ba3ec12018-06-16 15:32:38 +02001524 aco_save_T aco;
Bram Moolenaar9fa95062018-08-08 22:08:32 +02001525 varnumber_T tick = CHANGEDTICK(curbuf);
Bram Moolenaar91d2e782018-08-07 19:05:01 +02001526
Bram Moolenaar6ba3ec12018-06-16 15:32:38 +02001527 // save and restore curwin and curbuf, in case the autocmd changes them
1528 aucmd_prepbuf(&aco, curbuf);
Bram Moolenaar5a093432018-02-10 18:15:19 +01001529 apply_autocmds(EVENT_TEXTCHANGEDI, NULL, NULL, FALSE, curbuf);
Bram Moolenaar6ba3ec12018-06-16 15:32:38 +02001530 aucmd_restbuf(&aco);
Bram Moolenaar5a093432018-02-10 18:15:19 +01001531 curbuf->b_last_changedtick = CHANGEDTICK(curbuf);
Bram Moolenaar9fa95062018-08-08 22:08:32 +02001532 if (tick != CHANGEDTICK(curbuf)) // see ins_apply_autocmds()
1533 u_save(curwin->w_cursor.lnum,
1534 (linenr_T)(curwin->w_cursor.lnum + 1));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001535 }
Bram Moolenaar5a093432018-02-10 18:15:19 +01001536
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01001537#ifdef FEAT_INS_EXPAND
Bram Moolenaar5a093432018-02-10 18:15:19 +01001538 /* Trigger TextChangedP if b_changedtick differs. When the popupmenu closes
1539 * TextChangedI will need to trigger for backwards compatibility, thus use
1540 * different b_last_changedtick* variables. */
1541 if (ready && has_textchangedP()
1542 && curbuf->b_last_changedtick_pum != CHANGEDTICK(curbuf)
1543 && pum_visible())
1544 {
Bram Moolenaar6ba3ec12018-06-16 15:32:38 +02001545 aco_save_T aco;
Bram Moolenaar9fa95062018-08-08 22:08:32 +02001546 varnumber_T tick = CHANGEDTICK(curbuf);
Bram Moolenaar6ba3ec12018-06-16 15:32:38 +02001547
1548 // save and restore curwin and curbuf, in case the autocmd changes them
1549 aucmd_prepbuf(&aco, curbuf);
Bram Moolenaar5a093432018-02-10 18:15:19 +01001550 apply_autocmds(EVENT_TEXTCHANGEDP, NULL, NULL, FALSE, curbuf);
Bram Moolenaar6ba3ec12018-06-16 15:32:38 +02001551 aucmd_restbuf(&aco);
Bram Moolenaar5a093432018-02-10 18:15:19 +01001552 curbuf->b_last_changedtick_pum = CHANGEDTICK(curbuf);
Bram Moolenaar9fa95062018-08-08 22:08:32 +02001553 if (tick != CHANGEDTICK(curbuf)) // see ins_apply_autocmds()
1554 u_save(curwin->w_cursor.lnum,
1555 (linenr_T)(curwin->w_cursor.lnum + 1));
Bram Moolenaar5a093432018-02-10 18:15:19 +01001556 }
Bram Moolenaare21b6b22014-01-14 12:17:02 +01001557#endif
1558
Bram Moolenaar535d5b62019-01-11 20:45:36 +01001559#if defined(FEAT_CONCEAL)
Bram Moolenaare21b6b22014-01-14 12:17:02 +01001560 if ((conceal_update_lines
1561 && (conceal_old_cursor_line != conceal_new_cursor_line
1562 || conceal_cursor_line(curwin)))
1563 || need_cursor_line_redraw)
1564 {
1565 if (conceal_old_cursor_line != conceal_new_cursor_line)
Bram Moolenaar535d5b62019-01-11 20:45:36 +01001566 redrawWinline(curwin, conceal_old_cursor_line);
1567 redrawWinline(curwin, conceal_new_cursor_line == 0
1568 ? curwin->w_cursor.lnum : conceal_new_cursor_line);
Bram Moolenaare21b6b22014-01-14 12:17:02 +01001569 curwin->w_valid &= ~VALID_CROW;
Bram Moolenaar535d5b62019-01-11 20:45:36 +01001570 need_cursor_line_redraw = FALSE;
Bram Moolenaare21b6b22014-01-14 12:17:02 +01001571 }
Bram Moolenaar535d5b62019-01-11 20:45:36 +01001572#endif
1573 if (must_redraw)
1574 update_screen(0);
1575 else if (clear_cmdline || redraw_cmdline)
1576 showmode(); /* clear cmdline and show mode */
Bram Moolenaare21b6b22014-01-14 12:17:02 +01001577 showruler(FALSE);
1578 setcursor();
1579 emsg_on_display = FALSE; /* may remove error message now */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001580}
1581
1582/*
1583 * Handle a CTRL-V or CTRL-Q typed in Insert mode.
1584 */
1585 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +01001586ins_ctrl_v(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001587{
1588 int c;
Bram Moolenaar9c520cb2011-05-10 14:22:16 +02001589 int did_putchar = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001590
1591 /* may need to redraw when no more chars available now */
Bram Moolenaar754b5602006-02-09 23:53:20 +00001592 ins_redraw(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001593
1594 if (redrawing() && !char_avail())
Bram Moolenaar9c520cb2011-05-10 14:22:16 +02001595 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001596 edit_putchar('^', TRUE);
Bram Moolenaar9c520cb2011-05-10 14:22:16 +02001597 did_putchar = TRUE;
1598 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001599 AppendToRedobuff((char_u *)CTRL_V_STR); /* CTRL-V */
1600
1601#ifdef FEAT_CMDL_INFO
1602 add_to_showcmd_c(Ctrl_V);
1603#endif
1604
1605 c = get_literal();
Bram Moolenaar9c520cb2011-05-10 14:22:16 +02001606 if (did_putchar)
1607 /* when the line fits in 'columns' the '^' is at the start of the next
1608 * line and will not removed by the redraw */
1609 edit_unputchar();
Bram Moolenaar071d4272004-06-13 20:20:40 +00001610#ifdef FEAT_CMDL_INFO
1611 clear_showcmd();
1612#endif
1613 insert_special(c, FALSE, TRUE);
1614#ifdef FEAT_RIGHTLEFT
1615 revins_chars++;
1616 revins_legal++;
1617#endif
1618}
1619
1620/*
1621 * Put a character directly onto the screen. It's not stored in a buffer.
1622 * Used while handling CTRL-K, CTRL-V, etc. in Insert mode.
1623 */
1624static int pc_status;
1625#define PC_STATUS_UNSET 0 /* pc_bytes was not set */
1626#define PC_STATUS_RIGHT 1 /* right halve of double-wide char */
1627#define PC_STATUS_LEFT 2 /* left halve of double-wide char */
1628#define PC_STATUS_SET 3 /* pc_bytes was filled */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001629static char_u pc_bytes[MB_MAXBYTES + 1]; /* saved bytes */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001630static int pc_attr;
1631static int pc_row;
1632static int pc_col;
1633
1634 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01001635edit_putchar(int c, int highlight)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001636{
1637 int attr;
1638
1639 if (ScreenLines != NULL)
1640 {
1641 update_topline(); /* just in case w_topline isn't valid */
1642 validate_cursor();
1643 if (highlight)
Bram Moolenaar8820b482017-03-16 17:23:31 +01001644 attr = HL_ATTR(HLF_8);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001645 else
1646 attr = 0;
1647 pc_row = W_WINROW(curwin) + curwin->w_wrow;
Bram Moolenaar53f81742017-09-22 14:35:51 +02001648 pc_col = curwin->w_wincol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001649 pc_status = PC_STATUS_UNSET;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001650#ifdef FEAT_RIGHTLEFT
1651 if (curwin->w_p_rl)
1652 {
Bram Moolenaar02631462017-09-22 15:20:32 +02001653 pc_col += curwin->w_width - 1 - curwin->w_wcol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001654 if (has_mbyte)
1655 {
1656 int fix_col = mb_fix_col(pc_col, pc_row);
1657
1658 if (fix_col != pc_col)
1659 {
1660 screen_putchar(' ', pc_row, fix_col, attr);
1661 --curwin->w_wcol;
1662 pc_status = PC_STATUS_RIGHT;
1663 }
1664 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001665 }
1666 else
1667#endif
1668 {
1669 pc_col += curwin->w_wcol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001670 if (mb_lefthalve(pc_row, pc_col))
1671 pc_status = PC_STATUS_LEFT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001672 }
1673
1674 /* save the character to be able to put it back */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001675 if (pc_status == PC_STATUS_UNSET)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001676 {
1677 screen_getbytes(pc_row, pc_col, pc_bytes, &pc_attr);
1678 pc_status = PC_STATUS_SET;
1679 }
1680 screen_putchar(c, pc_row, pc_col, attr);
1681 }
1682}
1683
Bram Moolenaarf2732452018-06-03 14:47:35 +02001684#if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
1685/*
1686 * Return the effective prompt for the current buffer.
1687 */
1688 char_u *
1689prompt_text(void)
1690{
1691 if (curbuf->b_prompt_text == NULL)
1692 return (char_u *)"% ";
1693 return curbuf->b_prompt_text;
1694}
1695
1696/*
1697 * Prepare for prompt mode: Make sure the last line has the prompt text.
1698 * Move the cursor to this line.
1699 */
1700 static void
1701init_prompt(int cmdchar_todo)
1702{
1703 char_u *prompt = prompt_text();
1704 char_u *text;
1705
1706 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
1707 text = ml_get_curline();
1708 if (STRNCMP(text, prompt, STRLEN(prompt)) != 0)
1709 {
1710 // prompt is missing, insert it or append a line with it
1711 if (*text == NUL)
1712 ml_replace(curbuf->b_ml.ml_line_count, prompt, TRUE);
1713 else
1714 ml_append(curbuf->b_ml.ml_line_count, prompt, 0, FALSE);
1715 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
1716 coladvance((colnr_T)MAXCOL);
1717 changed_bytes(curbuf->b_ml.ml_line_count, 0);
1718 }
Bram Moolenaar6d41c782018-06-06 09:11:12 +02001719
1720 // Insert always starts after the prompt, allow editing text after it.
1721 if (Insstart_orig.lnum != curwin->w_cursor.lnum
1722 || Insstart_orig.col != (int)STRLEN(prompt))
1723 {
1724 Insstart.lnum = curwin->w_cursor.lnum;
Bram Moolenaare31e2562018-06-10 13:12:55 +02001725 Insstart.col = (int)STRLEN(prompt);
Bram Moolenaar6d41c782018-06-06 09:11:12 +02001726 Insstart_orig = Insstart;
1727 Insstart_textlen = Insstart.col;
1728 Insstart_blank_vcol = MAXCOL;
1729 arrow_used = FALSE;
1730 }
1731
Bram Moolenaarf2732452018-06-03 14:47:35 +02001732 if (cmdchar_todo == 'A')
1733 coladvance((colnr_T)MAXCOL);
1734 if (cmdchar_todo == 'I' || curwin->w_cursor.col <= (int)STRLEN(prompt))
Bram Moolenaare31e2562018-06-10 13:12:55 +02001735 curwin->w_cursor.col = (int)STRLEN(prompt);
Bram Moolenaar891e1fd2018-06-06 18:02:39 +02001736 /* Make sure the cursor is in a valid position. */
1737 check_cursor();
Bram Moolenaarf2732452018-06-03 14:47:35 +02001738}
1739
1740/*
1741 * Return TRUE if the cursor is in the editable position of the prompt line.
1742 */
1743 int
1744prompt_curpos_editable()
1745{
1746 return curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count
1747 && curwin->w_cursor.col >= (int)STRLEN(prompt_text());
1748}
1749#endif
1750
Bram Moolenaar071d4272004-06-13 20:20:40 +00001751/*
1752 * Undo the previous edit_putchar().
1753 */
1754 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01001755edit_unputchar(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001756{
1757 if (pc_status != PC_STATUS_UNSET && pc_row >= msg_scrolled)
1758 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001759 if (pc_status == PC_STATUS_RIGHT)
1760 ++curwin->w_wcol;
1761 if (pc_status == PC_STATUS_RIGHT || pc_status == PC_STATUS_LEFT)
Bram Moolenaarae12f4b2019-01-09 20:51:04 +01001762 redrawWinline(curwin, curwin->w_cursor.lnum);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001763 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001764 screen_puts(pc_bytes, pc_row - msg_scrolled, pc_col, pc_attr);
1765 }
1766}
1767
1768/*
1769 * Called when p_dollar is set: display a '$' at the end of the changed text
1770 * Only works when cursor is in the line that changes.
1771 */
1772 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01001773display_dollar(colnr_T col)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001774{
1775 colnr_T save_col;
1776
1777 if (!redrawing())
1778 return;
1779
1780 cursor_off();
1781 save_col = curwin->w_cursor.col;
1782 curwin->w_cursor.col = col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001783 if (has_mbyte)
1784 {
1785 char_u *p;
1786
1787 /* If on the last byte of a multi-byte move to the first byte. */
1788 p = ml_get_curline();
1789 curwin->w_cursor.col -= (*mb_head_off)(p, p + col);
1790 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001791 curs_columns(FALSE); /* recompute w_wrow and w_wcol */
Bram Moolenaar02631462017-09-22 15:20:32 +02001792 if (curwin->w_wcol < curwin->w_width)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001793 {
1794 edit_putchar('$', FALSE);
1795 dollar_vcol = curwin->w_virtcol;
1796 }
1797 curwin->w_cursor.col = save_col;
1798}
1799
1800/*
1801 * Call this function before moving the cursor from the normal insert position
1802 * in insert mode.
1803 */
1804 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +01001805undisplay_dollar(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001806{
Bram Moolenaar76b9b362012-02-04 23:35:00 +01001807 if (dollar_vcol >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001808 {
Bram Moolenaar76b9b362012-02-04 23:35:00 +01001809 dollar_vcol = -1;
Bram Moolenaarae12f4b2019-01-09 20:51:04 +01001810 redrawWinline(curwin, curwin->w_cursor.lnum);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001811 }
1812}
1813
1814/*
1815 * Insert an indent (for <Tab> or CTRL-T) or delete an indent (for CTRL-D).
1816 * Keep the cursor on the same character.
1817 * type == INDENT_INC increase indent (for CTRL-T or <Tab>)
1818 * type == INDENT_DEC decrease indent (for CTRL-D)
1819 * type == INDENT_SET set indent to "amount"
1820 * if round is TRUE, round the indent to 'shiftwidth' (only with _INC and _Dec).
1821 */
1822 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01001823change_indent(
1824 int type,
1825 int amount,
1826 int round,
1827 int replaced, /* replaced character, put on replace stack */
1828 int call_changed_bytes) /* call changed_bytes() */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001829{
1830 int vcol;
1831 int last_vcol;
1832 int insstart_less; /* reduction for Insstart.col */
1833 int new_cursor_col;
1834 int i;
1835 char_u *ptr;
1836 int save_p_list;
1837 int start_col;
1838 colnr_T vc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001839 colnr_T orig_col = 0; /* init for GCC */
1840 char_u *new_line, *orig_line = NULL; /* init for GCC */
1841
1842 /* VREPLACE mode needs to know what the line was like before changing */
1843 if (State & VREPLACE_FLAG)
1844 {
1845 orig_line = vim_strsave(ml_get_curline()); /* Deal with NULL below */
1846 orig_col = curwin->w_cursor.col;
1847 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001848
1849 /* for the following tricks we don't want list mode */
1850 save_p_list = curwin->w_p_list;
1851 curwin->w_p_list = FALSE;
1852 vc = getvcol_nolist(&curwin->w_cursor);
1853 vcol = vc;
1854
1855 /*
1856 * For Replace mode we need to fix the replace stack later, which is only
1857 * possible when the cursor is in the indent. Remember the number of
1858 * characters before the cursor if it's possible.
1859 */
1860 start_col = curwin->w_cursor.col;
1861
1862 /* determine offset from first non-blank */
1863 new_cursor_col = curwin->w_cursor.col;
1864 beginline(BL_WHITE);
1865 new_cursor_col -= curwin->w_cursor.col;
1866
1867 insstart_less = curwin->w_cursor.col;
1868
1869 /*
1870 * If the cursor is in the indent, compute how many screen columns the
1871 * cursor is to the left of the first non-blank.
1872 */
1873 if (new_cursor_col < 0)
1874 vcol = get_indent() - vcol;
1875
1876 if (new_cursor_col > 0) /* can't fix replace stack */
1877 start_col = -1;
1878
1879 /*
1880 * Set the new indent. The cursor will be put on the first non-blank.
1881 */
1882 if (type == INDENT_SET)
Bram Moolenaar21b17e72008-01-16 19:03:13 +00001883 (void)set_indent(amount, call_changed_bytes ? SIN_CHANGED : 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001884 else
1885 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001886 int save_State = State;
1887
1888 /* Avoid being called recursively. */
1889 if (State & VREPLACE_FLAG)
1890 State = INSERT;
Bram Moolenaar21b17e72008-01-16 19:03:13 +00001891 shift_line(type == INDENT_DEC, round, 1, call_changed_bytes);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001892 State = save_State;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001893 }
1894 insstart_less -= curwin->w_cursor.col;
1895
1896 /*
1897 * Try to put cursor on same character.
1898 * If the cursor is at or after the first non-blank in the line,
1899 * compute the cursor column relative to the column of the first
1900 * non-blank character.
1901 * If we are not in insert mode, leave the cursor on the first non-blank.
1902 * If the cursor is before the first non-blank, position it relative
1903 * to the first non-blank, counted in screen columns.
1904 */
1905 if (new_cursor_col >= 0)
1906 {
1907 /*
1908 * When changing the indent while the cursor is touching it, reset
1909 * Insstart_col to 0.
1910 */
1911 if (new_cursor_col == 0)
1912 insstart_less = MAXCOL;
1913 new_cursor_col += curwin->w_cursor.col;
1914 }
1915 else if (!(State & INSERT))
1916 new_cursor_col = curwin->w_cursor.col;
1917 else
1918 {
1919 /*
1920 * Compute the screen column where the cursor should be.
1921 */
1922 vcol = get_indent() - vcol;
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00001923 curwin->w_virtcol = (colnr_T)((vcol < 0) ? 0 : vcol);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001924
1925 /*
1926 * Advance the cursor until we reach the right screen column.
1927 */
1928 vcol = last_vcol = 0;
1929 new_cursor_col = -1;
1930 ptr = ml_get_curline();
1931 while (vcol <= (int)curwin->w_virtcol)
1932 {
1933 last_vcol = vcol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001934 if (has_mbyte && new_cursor_col >= 0)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00001935 new_cursor_col += (*mb_ptr2len)(ptr + new_cursor_col);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001936 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00001937 ++new_cursor_col;
Bram Moolenaar597a4222014-06-25 14:39:50 +02001938 vcol += lbr_chartabsize(ptr, ptr + new_cursor_col, (colnr_T)vcol);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001939 }
1940 vcol = last_vcol;
1941
1942 /*
1943 * May need to insert spaces to be able to position the cursor on
1944 * the right screen column.
1945 */
1946 if (vcol != (int)curwin->w_virtcol)
1947 {
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00001948 curwin->w_cursor.col = (colnr_T)new_cursor_col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001949 i = (int)curwin->w_virtcol - vcol;
Bram Moolenaar964b3742019-05-24 18:54:09 +02001950 ptr = alloc(i + 1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001951 if (ptr != NULL)
1952 {
1953 new_cursor_col += i;
1954 ptr[i] = NUL;
1955 while (--i >= 0)
1956 ptr[i] = ' ';
1957 ins_str(ptr);
1958 vim_free(ptr);
1959 }
1960 }
1961
1962 /*
1963 * When changing the indent while the cursor is in it, reset
1964 * Insstart_col to 0.
1965 */
1966 insstart_less = MAXCOL;
1967 }
1968
1969 curwin->w_p_list = save_p_list;
1970
1971 if (new_cursor_col <= 0)
1972 curwin->w_cursor.col = 0;
1973 else
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00001974 curwin->w_cursor.col = (colnr_T)new_cursor_col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001975 curwin->w_set_curswant = TRUE;
1976 changed_cline_bef_curs();
1977
1978 /*
1979 * May have to adjust the start of the insert.
1980 */
1981 if (State & INSERT)
1982 {
1983 if (curwin->w_cursor.lnum == Insstart.lnum && Insstart.col != 0)
1984 {
1985 if ((int)Insstart.col <= insstart_less)
1986 Insstart.col = 0;
1987 else
1988 Insstart.col -= insstart_less;
1989 }
1990 if ((int)ai_col <= insstart_less)
1991 ai_col = 0;
1992 else
1993 ai_col -= insstart_less;
1994 }
1995
1996 /*
1997 * For REPLACE mode, may have to fix the replace stack, if it's possible.
1998 * If the number of characters before the cursor decreased, need to pop a
1999 * few characters from the replace stack.
2000 * If the number of characters before the cursor increased, need to push a
2001 * few NULs onto the replace stack.
2002 */
2003 if (REPLACE_NORMAL(State) && start_col >= 0)
2004 {
2005 while (start_col > (int)curwin->w_cursor.col)
2006 {
2007 replace_join(0); /* remove a NUL from the replace stack */
2008 --start_col;
2009 }
2010 while (start_col < (int)curwin->w_cursor.col || replaced)
2011 {
2012 replace_push(NUL);
2013 if (replaced)
2014 {
2015 replace_push(replaced);
2016 replaced = NUL;
2017 }
2018 ++start_col;
2019 }
2020 }
2021
Bram Moolenaar071d4272004-06-13 20:20:40 +00002022 /*
2023 * For VREPLACE mode, we also have to fix the replace stack. In this case
2024 * it is always possible because we backspace over the whole line and then
2025 * put it back again the way we wanted it.
2026 */
2027 if (State & VREPLACE_FLAG)
2028 {
2029 /* If orig_line didn't allocate, just return. At least we did the job,
2030 * even if you can't backspace. */
2031 if (orig_line == NULL)
2032 return;
2033
2034 /* Save new line */
2035 new_line = vim_strsave(ml_get_curline());
2036 if (new_line == NULL)
2037 return;
2038
2039 /* We only put back the new line up to the cursor */
2040 new_line[curwin->w_cursor.col] = NUL;
2041
2042 /* Put back original line */
2043 ml_replace(curwin->w_cursor.lnum, orig_line, FALSE);
2044 curwin->w_cursor.col = orig_col;
2045
2046 /* Backspace from cursor to start of line */
2047 backspace_until_column(0);
2048
2049 /* Insert new stuff into line again */
2050 ins_bytes(new_line);
2051
2052 vim_free(new_line);
2053 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002054}
2055
2056/*
2057 * Truncate the space at the end of a line. This is to be used only in an
2058 * insert mode. It handles fixing the replace stack for REPLACE and VREPLACE
2059 * modes.
2060 */
2061 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01002062truncate_spaces(char_u *line)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002063{
2064 int i;
2065
2066 /* find start of trailing white space */
Bram Moolenaar1c465442017-03-12 20:10:05 +01002067 for (i = (int)STRLEN(line) - 1; i >= 0 && VIM_ISWHITE(line[i]); i--)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002068 {
2069 if (State & REPLACE_FLAG)
2070 replace_join(0); /* remove a NUL from the replace stack */
2071 }
2072 line[i + 1] = NUL;
2073}
2074
Bram Moolenaar071d4272004-06-13 20:20:40 +00002075/*
2076 * Backspace the cursor until the given column. Handles REPLACE and VREPLACE
2077 * modes correctly. May also be used when not in insert mode at all.
Bram Moolenaar0f6c9482009-01-13 11:29:48 +00002078 * Will attempt not to go before "col" even when there is a composing
2079 * character.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002080 */
2081 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01002082backspace_until_column(int col)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002083{
2084 while ((int)curwin->w_cursor.col > col)
2085 {
2086 curwin->w_cursor.col--;
2087 if (State & REPLACE_FLAG)
Bram Moolenaar0f6c9482009-01-13 11:29:48 +00002088 replace_do_bs(col);
2089 else if (!del_char_after_col(col))
2090 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002091 }
2092}
Bram Moolenaar071d4272004-06-13 20:20:40 +00002093
Bram Moolenaar0f6c9482009-01-13 11:29:48 +00002094/*
2095 * Like del_char(), but make sure not to go before column "limit_col".
2096 * Only matters when there are composing characters.
2097 * Return TRUE when something was deleted.
2098 */
2099 static int
Bram Moolenaar7454a062016-01-30 15:14:10 +01002100del_char_after_col(int limit_col UNUSED)
Bram Moolenaar0f6c9482009-01-13 11:29:48 +00002101{
Bram Moolenaar0f6c9482009-01-13 11:29:48 +00002102 if (enc_utf8 && limit_col >= 0)
2103 {
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00002104 colnr_T ecol = curwin->w_cursor.col + 1;
Bram Moolenaar0f6c9482009-01-13 11:29:48 +00002105
2106 /* Make sure the cursor is at the start of a character, but
2107 * skip forward again when going too far back because of a
2108 * composing character. */
2109 mb_adjust_cursor();
Bram Moolenaar5b3e4602009-02-04 10:20:58 +00002110 while (curwin->w_cursor.col < (colnr_T)limit_col)
Bram Moolenaar0f6c9482009-01-13 11:29:48 +00002111 {
2112 int l = utf_ptr2len(ml_get_cursor());
2113
2114 if (l == 0) /* end of line */
2115 break;
2116 curwin->w_cursor.col += l;
2117 }
2118 if (*ml_get_cursor() == NUL || curwin->w_cursor.col == ecol)
2119 return FALSE;
Bram Moolenaar0ab2a882009-05-13 10:51:08 +00002120 del_bytes((long)((int)ecol - curwin->w_cursor.col), FALSE, TRUE);
Bram Moolenaar0f6c9482009-01-13 11:29:48 +00002121 }
2122 else
Bram Moolenaar0f6c9482009-01-13 11:29:48 +00002123 (void)del_char(FALSE);
2124 return TRUE;
2125}
2126
Bram Moolenaar071d4272004-06-13 20:20:40 +00002127/*
2128 * Next character is interpreted literally.
2129 * A one, two or three digit decimal number is interpreted as its byte value.
2130 * If one or two digits are entered, the next character is given to vungetc().
2131 * For Unicode a character > 255 may be returned.
2132 */
2133 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01002134get_literal(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002135{
2136 int cc;
2137 int nc;
2138 int i;
2139 int hex = FALSE;
2140 int octal = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002141 int unicode = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002142
2143 if (got_int)
2144 return Ctrl_C;
2145
2146#ifdef FEAT_GUI
2147 /*
2148 * In GUI there is no point inserting the internal code for a special key.
2149 * It is more useful to insert the string "<KEY>" instead. This would
2150 * probably be useful in a text window too, but it would not be
2151 * vi-compatible (maybe there should be an option for it?) -- webb
2152 */
2153 if (gui.in_use)
2154 ++allow_keys;
2155#endif
2156#ifdef USE_ON_FLY_SCROLL
2157 dont_scroll = TRUE; /* disallow scrolling here */
2158#endif
2159 ++no_mapping; /* don't map the next key hits */
2160 cc = 0;
2161 i = 0;
2162 for (;;)
2163 {
Bram Moolenaar61abfd12007-09-13 16:26:47 +00002164 nc = plain_vgetc();
Bram Moolenaar071d4272004-06-13 20:20:40 +00002165#ifdef FEAT_CMDL_INFO
Bram Moolenaar13505972019-01-24 15:04:48 +01002166 if (!(State & CMDLINE) && MB_BYTE2LEN_CHECK(nc) == 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002167 add_to_showcmd(nc);
2168#endif
2169 if (nc == 'x' || nc == 'X')
2170 hex = TRUE;
2171 else if (nc == 'o' || nc == 'O')
2172 octal = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002173 else if (nc == 'u' || nc == 'U')
2174 unicode = nc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002175 else
2176 {
Bram Moolenaar13505972019-01-24 15:04:48 +01002177 if (hex || unicode != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002178 {
2179 if (!vim_isxdigit(nc))
2180 break;
2181 cc = cc * 16 + hex2nr(nc);
2182 }
2183 else if (octal)
2184 {
2185 if (nc < '0' || nc > '7')
2186 break;
2187 cc = cc * 8 + nc - '0';
2188 }
2189 else
2190 {
2191 if (!VIM_ISDIGIT(nc))
2192 break;
2193 cc = cc * 10 + nc - '0';
2194 }
2195
2196 ++i;
2197 }
2198
Bram Moolenaar13505972019-01-24 15:04:48 +01002199 if (cc > 255 && unicode == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002200 cc = 255; /* limit range to 0-255 */
2201 nc = 0;
2202
2203 if (hex) /* hex: up to two chars */
2204 {
2205 if (i >= 2)
2206 break;
2207 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002208 else if (unicode) /* Unicode: up to four or eight chars */
2209 {
2210 if ((unicode == 'u' && i >= 4) || (unicode == 'U' && i >= 8))
2211 break;
2212 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002213 else if (i >= 3) /* decimal or octal: up to three chars */
2214 break;
2215 }
2216 if (i == 0) /* no number entered */
2217 {
2218 if (nc == K_ZERO) /* NUL is stored as NL */
2219 {
2220 cc = '\n';
2221 nc = 0;
2222 }
2223 else
2224 {
2225 cc = nc;
2226 nc = 0;
2227 }
2228 }
2229
2230 if (cc == 0) /* NUL is stored as NL */
2231 cc = '\n';
Bram Moolenaar217ad922005-03-20 22:37:15 +00002232 if (enc_dbcs && (cc & 0xff) == 0)
2233 cc = '?'; /* don't accept an illegal DBCS char, the NUL in the
2234 second byte will cause trouble! */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002235
2236 --no_mapping;
2237#ifdef FEAT_GUI
2238 if (gui.in_use)
2239 --allow_keys;
2240#endif
2241 if (nc)
2242 vungetc(nc);
2243 got_int = FALSE; /* CTRL-C typed after CTRL-V is not an interrupt */
2244 return cc;
2245}
2246
2247/*
2248 * Insert character, taking care of special keys and mod_mask
2249 */
2250 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +01002251insert_special(
2252 int c,
2253 int allow_modmask,
2254 int ctrlv) /* c was typed after CTRL-V */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002255{
2256 char_u *p;
2257 int len;
2258
2259 /*
2260 * Special function key, translate into "<Key>". Up to the last '>' is
2261 * inserted with ins_str(), so as not to replace characters in replace
2262 * mode.
2263 * Only use mod_mask for special keys, to avoid things like <S-Space>,
2264 * unless 'allow_modmask' is TRUE.
2265 */
Bram Moolenaard0573012017-10-28 21:11:06 +02002266#ifdef MACOS_X
Bram Moolenaar071d4272004-06-13 20:20:40 +00002267 /* Command-key never produces a normal key */
2268 if (mod_mask & MOD_MASK_CMD)
2269 allow_modmask = TRUE;
2270#endif
2271 if (IS_SPECIAL(c) || (mod_mask && allow_modmask))
2272 {
2273 p = get_special_key_name(c, mod_mask);
2274 len = (int)STRLEN(p);
2275 c = p[len - 1];
2276 if (len > 2)
2277 {
2278 if (stop_arrow() == FAIL)
2279 return;
2280 p[len - 1] = NUL;
2281 ins_str(p);
Bram Moolenaarebefac62005-12-28 22:39:57 +00002282 AppendToRedobuffLit(p, -1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002283 ctrlv = FALSE;
2284 }
2285 }
2286 if (stop_arrow() == OK)
2287 insertchar(c, ctrlv ? INSCHAR_CTRLV : 0, -1);
2288}
2289
2290/*
2291 * Special characters in this context are those that need processing other
2292 * than the simple insertion that can be performed here. This includes ESC
2293 * which terminates the insert, and CR/NL which need special processing to
2294 * open up a new line. This routine tries to optimize insertions performed by
2295 * the "redo", "undo" or "put" commands, so it needs to know when it should
2296 * stop and defer processing to the "normal" mechanism.
2297 * '0' and '^' are special, because they can be followed by CTRL-D.
2298 */
2299#ifdef EBCDIC
2300# define ISSPECIAL(c) ((c) < ' ' || (c) == '0' || (c) == '^')
2301#else
2302# define ISSPECIAL(c) ((c) < ' ' || (c) >= DEL || (c) == '0' || (c) == '^')
2303#endif
2304
Bram Moolenaar13505972019-01-24 15:04:48 +01002305#define WHITECHAR(cc) (VIM_ISWHITE(cc) && (!enc_utf8 || !utf_iscomposing(utf_ptr2char(ml_get_cursor() + 1))))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002306
Bram Moolenaarbfe3bf82012-06-13 17:28:55 +02002307/*
2308 * "flags": INSCHAR_FORMAT - force formatting
2309 * INSCHAR_CTRLV - char typed just after CTRL-V
2310 * INSCHAR_NO_FEX - don't use 'formatexpr'
2311 *
2312 * NOTE: passes the flags value straight through to internal_format() which,
2313 * beside INSCHAR_FORMAT (above), is also looking for these:
2314 * INSCHAR_DO_COM - format comments
2315 * INSCHAR_COM_LIST - format comments with num list or 2nd line indent
2316 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002317 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01002318insertchar(
2319 int c, /* character to insert or NUL */
2320 int flags, /* INSCHAR_FORMAT, etc. */
2321 int second_indent) /* indent for second line if >= 0 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002322{
Bram Moolenaar071d4272004-06-13 20:20:40 +00002323 int textwidth;
2324#ifdef FEAT_COMMENTS
Bram Moolenaar071d4272004-06-13 20:20:40 +00002325 char_u *p;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002326#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002327 int fo_ins_blank;
Bram Moolenaar0f8dd842015-03-08 14:48:49 +01002328 int force_format = flags & INSCHAR_FORMAT;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002329
Bram Moolenaar0f8dd842015-03-08 14:48:49 +01002330 textwidth = comp_textwidth(force_format);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002331 fo_ins_blank = has_format_option(FO_INS_BLANK);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002332
2333 /*
2334 * Try to break the line in two or more pieces when:
2335 * - Always do this if we have been called to do formatting only.
2336 * - Always do this when 'formatoptions' has the 'a' flag and the line
2337 * ends in white space.
2338 * - Otherwise:
2339 * - Don't do this if inserting a blank
2340 * - Don't do this if an existing character is being replaced, unless
2341 * we're in VREPLACE mode.
2342 * - Do this if the cursor is not on the line where insert started
2343 * or - 'formatoptions' doesn't have 'l' or the line was not too long
2344 * before the insert.
2345 * - 'formatoptions' doesn't have 'b' or a blank was inserted at or
2346 * before 'textwidth'
2347 */
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002348 if (textwidth > 0
Bram Moolenaar0f8dd842015-03-08 14:48:49 +01002349 && (force_format
Bram Moolenaar1c465442017-03-12 20:10:05 +01002350 || (!VIM_ISWHITE(c)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002351 && !((State & REPLACE_FLAG)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002352 && !(State & VREPLACE_FLAG)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002353 && *ml_get_cursor() != NUL)
2354 && (curwin->w_cursor.lnum != Insstart.lnum
2355 || ((!has_format_option(FO_INS_LONG)
2356 || Insstart_textlen <= (colnr_T)textwidth)
2357 && (!fo_ins_blank
2358 || Insstart_blank_vcol <= (colnr_T)textwidth
2359 ))))))
2360 {
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002361 /* Format with 'formatexpr' when it's set. Use internal formatting
2362 * when 'formatexpr' isn't set or it returns non-zero. */
2363#if defined(FEAT_EVAL)
Bram Moolenaar0f8dd842015-03-08 14:48:49 +01002364 int do_internal = TRUE;
2365 colnr_T virtcol = get_nolist_virtcol()
2366 + char2cells(c != NUL ? c : gchar_cursor());
Bram Moolenaarf3442e72006-10-10 13:49:10 +00002367
Bram Moolenaar0f8dd842015-03-08 14:48:49 +01002368 if (*curbuf->b_p_fex != NUL && (flags & INSCHAR_NO_FEX) == 0
2369 && (force_format || virtcol > (colnr_T)textwidth))
Bram Moolenaarf3442e72006-10-10 13:49:10 +00002370 {
2371 do_internal = (fex_format(curwin->w_cursor.lnum, 1L, c) != 0);
2372 /* It may be required to save for undo again, e.g. when setline()
2373 * was called. */
2374 ins_need_undo = TRUE;
2375 }
2376 if (do_internal)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002377#endif
Bram Moolenaar97b98102009-11-17 16:41:01 +00002378 internal_format(textwidth, second_indent, flags, c == NUL, c);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002379 }
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002380
Bram Moolenaar071d4272004-06-13 20:20:40 +00002381 if (c == NUL) /* only formatting was wanted */
2382 return;
2383
2384#ifdef FEAT_COMMENTS
2385 /* Check whether this character should end a comment. */
2386 if (did_ai && (int)c == end_comment_pending)
2387 {
2388 char_u *line;
2389 char_u lead_end[COM_MAX_LEN]; /* end-comment string */
2390 int middle_len, end_len;
2391 int i;
2392
2393 /*
2394 * Need to remove existing (middle) comment leader and insert end
2395 * comment leader. First, check what comment leader we can find.
2396 */
Bram Moolenaar81340392012-06-06 16:12:59 +02002397 i = get_leader_len(line = ml_get_curline(), &p, FALSE, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002398 if (i > 0 && vim_strchr(p, COM_MIDDLE) != NULL) /* Just checking */
2399 {
2400 /* Skip middle-comment string */
2401 while (*p && p[-1] != ':') /* find end of middle flags */
2402 ++p;
2403 middle_len = copy_option_part(&p, lead_end, COM_MAX_LEN, ",");
2404 /* Don't count trailing white space for middle_len */
Bram Moolenaar1c465442017-03-12 20:10:05 +01002405 while (middle_len > 0 && VIM_ISWHITE(lead_end[middle_len - 1]))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002406 --middle_len;
2407
2408 /* Find the end-comment string */
2409 while (*p && p[-1] != ':') /* find end of end flags */
2410 ++p;
2411 end_len = copy_option_part(&p, lead_end, COM_MAX_LEN, ",");
2412
2413 /* Skip white space before the cursor */
2414 i = curwin->w_cursor.col;
Bram Moolenaar1c465442017-03-12 20:10:05 +01002415 while (--i >= 0 && VIM_ISWHITE(line[i]))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002416 ;
2417 i++;
2418
2419 /* Skip to before the middle leader */
2420 i -= middle_len;
2421
2422 /* Check some expected things before we go on */
2423 if (i >= 0 && lead_end[end_len - 1] == end_comment_pending)
2424 {
2425 /* Backspace over all the stuff we want to replace */
2426 backspace_until_column(i);
2427
2428 /*
2429 * Insert the end-comment string, except for the last
2430 * character, which will get inserted as normal later.
2431 */
2432 ins_bytes_len(lead_end, end_len - 1);
2433 }
2434 }
2435 }
2436 end_comment_pending = NUL;
2437#endif
2438
2439 did_ai = FALSE;
2440#ifdef FEAT_SMARTINDENT
2441 did_si = FALSE;
2442 can_si = FALSE;
2443 can_si_back = FALSE;
2444#endif
2445
2446 /*
2447 * If there's any pending input, grab up to INPUT_BUFLEN at once.
2448 * This speeds up normal text input considerably.
2449 * Don't do this when 'cindent' or 'indentexpr' is set, because we might
2450 * need to re-indent at a ':', or any other character (but not what
2451 * 'paste' is set)..
Bram Moolenaarf5876f12012-02-29 18:22:08 +01002452 * Don't do this when there an InsertCharPre autocommand is defined,
2453 * because we need to fire the event for every character.
Bram Moolenaar39de9522018-05-08 22:48:00 +02002454 * Do the check for InsertCharPre before the call to vpeekc() because the
2455 * InsertCharPre autocommand could change the input buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00002456 */
2457#ifdef USE_ON_FLY_SCROLL
2458 dont_scroll = FALSE; /* allow scrolling here */
2459#endif
2460
2461 if ( !ISSPECIAL(c)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002462 && (!has_mbyte || (*mb_char2len)(c) == 1)
Bram Moolenaar39de9522018-05-08 22:48:00 +02002463 && !has_insertcharpre()
Bram Moolenaar071d4272004-06-13 20:20:40 +00002464 && vpeekc() != NUL
2465 && !(State & REPLACE_FLAG)
2466#ifdef FEAT_CINDENT
2467 && !cindent_on()
2468#endif
2469#ifdef FEAT_RIGHTLEFT
2470 && !p_ri
2471#endif
Bram Moolenaar39de9522018-05-08 22:48:00 +02002472 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00002473 {
2474#define INPUT_BUFLEN 100
2475 char_u buf[INPUT_BUFLEN + 1];
2476 int i;
2477 colnr_T virtcol = 0;
2478
2479 buf[0] = c;
2480 i = 1;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002481 if (textwidth > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002482 virtcol = get_nolist_virtcol();
2483 /*
2484 * Stop the string when:
2485 * - no more chars available
2486 * - finding a special character (command key)
2487 * - buffer is full
2488 * - running into the 'textwidth' boundary
2489 * - need to check for abbreviation: A non-word char after a word-char
2490 */
2491 while ( (c = vpeekc()) != NUL
2492 && !ISSPECIAL(c)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002493 && (!has_mbyte || MB_BYTE2LEN_CHECK(c) == 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002494 && i < INPUT_BUFLEN
2495 && (textwidth == 0
2496 || (virtcol += byte2cells(buf[i - 1])) < (colnr_T)textwidth)
2497 && !(!no_abbr && !vim_iswordc(c) && vim_iswordc(buf[i - 1])))
2498 {
2499#ifdef FEAT_RIGHTLEFT
2500 c = vgetc();
2501 if (p_hkmap && KeyTyped)
2502 c = hkmap(c); /* Hebrew mode mapping */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002503 buf[i++] = c;
2504#else
2505 buf[i++] = vgetc();
2506#endif
2507 }
2508
2509#ifdef FEAT_DIGRAPHS
2510 do_digraph(-1); /* clear digraphs */
2511 do_digraph(buf[i-1]); /* may be the start of a digraph */
2512#endif
2513 buf[i] = NUL;
2514 ins_str(buf);
2515 if (flags & INSCHAR_CTRLV)
2516 {
2517 redo_literal(*buf);
2518 i = 1;
2519 }
2520 else
2521 i = 0;
2522 if (buf[i] != NUL)
Bram Moolenaarebefac62005-12-28 22:39:57 +00002523 AppendToRedobuffLit(buf + i, -1);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002524 }
2525 else
2526 {
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002527 int cc;
2528
Bram Moolenaar071d4272004-06-13 20:20:40 +00002529 if (has_mbyte && (cc = (*mb_char2len)(c)) > 1)
2530 {
2531 char_u buf[MB_MAXBYTES + 1];
2532
2533 (*mb_char2bytes)(c, buf);
2534 buf[cc] = NUL;
2535 ins_char_bytes(buf, cc);
2536 AppendCharToRedobuff(c);
2537 }
2538 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00002539 {
2540 ins_char(c);
2541 if (flags & INSCHAR_CTRLV)
2542 redo_literal(c);
2543 else
2544 AppendCharToRedobuff(c);
2545 }
2546 }
2547}
2548
2549/*
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002550 * Format text at the current insert position.
Bram Moolenaarbfe3bf82012-06-13 17:28:55 +02002551 *
2552 * If the INSCHAR_COM_LIST flag is present, then the value of second_indent
2553 * will be the comment leader length sent to open_line().
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002554 */
2555 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +01002556internal_format(
2557 int textwidth,
2558 int second_indent,
2559 int flags,
2560 int format_only,
2561 int c) /* character to be inserted (can be NUL) */
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002562{
2563 int cc;
2564 int save_char = NUL;
2565 int haveto_redraw = FALSE;
2566 int fo_ins_blank = has_format_option(FO_INS_BLANK);
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002567 int fo_multibyte = has_format_option(FO_MBYTE_BREAK);
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002568 int fo_white_par = has_format_option(FO_WHITE_PAR);
2569 int first_line = TRUE;
2570#ifdef FEAT_COMMENTS
2571 colnr_T leader_len;
2572 int no_leader = FALSE;
2573 int do_comments = (flags & INSCHAR_DO_COM);
2574#endif
Bram Moolenaar0026d472014-09-09 16:32:39 +02002575#ifdef FEAT_LINEBREAK
2576 int has_lbr = curwin->w_p_lbr;
2577
2578 /* make sure win_lbr_chartabsize() counts correctly */
2579 curwin->w_p_lbr = FALSE;
2580#endif
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002581
2582 /*
2583 * When 'ai' is off we don't want a space under the cursor to be
2584 * deleted. Replace it with an 'x' temporarily.
2585 */
Bram Moolenaar1f0bfe52018-07-29 16:09:22 +02002586 if (!curbuf->b_p_ai && !(State & VREPLACE_FLAG))
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002587 {
2588 cc = gchar_cursor();
Bram Moolenaar1c465442017-03-12 20:10:05 +01002589 if (VIM_ISWHITE(cc))
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002590 {
2591 save_char = cc;
2592 pchar_cursor('x');
2593 }
2594 }
2595
2596 /*
2597 * Repeat breaking lines, until the current line is not too long.
2598 */
2599 while (!got_int)
2600 {
2601 int startcol; /* Cursor column at entry */
2602 int wantcol; /* column at textwidth border */
2603 int foundcol; /* column for start of spaces */
2604 int end_foundcol = 0; /* column for start of word */
2605 colnr_T len;
2606 colnr_T virtcol;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002607 int orig_col = 0;
2608 char_u *saved_text = NULL;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002609 colnr_T col;
Bram Moolenaar97b98102009-11-17 16:41:01 +00002610 colnr_T end_col;
Bram Moolenaarc3c31582019-01-11 22:15:05 +01002611 int wcc; // counter for whitespace chars
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002612
Bram Moolenaar97b98102009-11-17 16:41:01 +00002613 virtcol = get_nolist_virtcol()
2614 + char2cells(c != NUL ? c : gchar_cursor());
2615 if (virtcol <= (colnr_T)textwidth)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002616 break;
2617
2618#ifdef FEAT_COMMENTS
2619 if (no_leader)
2620 do_comments = FALSE;
2621 else if (!(flags & INSCHAR_FORMAT)
2622 && has_format_option(FO_WRAP_COMS))
2623 do_comments = TRUE;
2624
2625 /* Don't break until after the comment leader */
2626 if (do_comments)
Bram Moolenaar81340392012-06-06 16:12:59 +02002627 leader_len = get_leader_len(ml_get_curline(), NULL, FALSE, TRUE);
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002628 else
2629 leader_len = 0;
2630
2631 /* If the line doesn't start with a comment leader, then don't
2632 * start one in a following broken line. Avoids that a %word
2633 * moved to the start of the next line causes all following lines
2634 * to start with %. */
2635 if (leader_len == 0)
2636 no_leader = TRUE;
2637#endif
2638 if (!(flags & INSCHAR_FORMAT)
2639#ifdef FEAT_COMMENTS
2640 && leader_len == 0
2641#endif
2642 && !has_format_option(FO_WRAP))
2643
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002644 break;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002645 if ((startcol = curwin->w_cursor.col) == 0)
2646 break;
2647
2648 /* find column of textwidth border */
2649 coladvance((colnr_T)textwidth);
2650 wantcol = curwin->w_cursor.col;
2651
Bram Moolenaar97b98102009-11-17 16:41:01 +00002652 curwin->w_cursor.col = startcol;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002653 foundcol = 0;
2654
2655 /*
2656 * Find position to break at.
2657 * Stop at first entered white when 'formatoptions' has 'v'
2658 */
2659 while ((!fo_ins_blank && !has_format_option(FO_INS_VI))
Bram Moolenaara27ad5a2011-10-26 17:04:29 +02002660 || (flags & INSCHAR_FORMAT)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002661 || curwin->w_cursor.lnum != Insstart.lnum
2662 || curwin->w_cursor.col >= Insstart.col)
2663 {
Bram Moolenaar97b98102009-11-17 16:41:01 +00002664 if (curwin->w_cursor.col == startcol && c != NUL)
2665 cc = c;
2666 else
2667 cc = gchar_cursor();
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002668 if (WHITECHAR(cc))
2669 {
2670 /* remember position of blank just before text */
Bram Moolenaar97b98102009-11-17 16:41:01 +00002671 end_col = curwin->w_cursor.col;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002672
Bram Moolenaarc3c31582019-01-11 22:15:05 +01002673 // find start of sequence of blanks
2674 wcc = 0;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002675 while (curwin->w_cursor.col > 0 && WHITECHAR(cc))
2676 {
2677 dec_cursor();
2678 cc = gchar_cursor();
Bram Moolenaarc3c31582019-01-11 22:15:05 +01002679
2680 // Increment count of how many whitespace chars in this
2681 // group; we only need to know if it's more than one.
2682 if (wcc < 2)
2683 wcc++;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002684 }
2685 if (curwin->w_cursor.col == 0 && WHITECHAR(cc))
2686 break; /* only spaces in front of text */
Bram Moolenaarc3c31582019-01-11 22:15:05 +01002687
2688 // Don't break after a period when 'formatoptions' has 'p' and
2689 // there are less than two spaces.
2690 if (has_format_option(FO_PERIOD_ABBR) && cc == '.' && wcc < 2)
2691 continue;
2692
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002693#ifdef FEAT_COMMENTS
2694 /* Don't break until after the comment leader */
2695 if (curwin->w_cursor.col < leader_len)
2696 break;
2697#endif
2698 if (has_format_option(FO_ONE_LETTER))
2699 {
2700 /* do not break after one-letter words */
2701 if (curwin->w_cursor.col == 0)
2702 break; /* one-letter word at begin */
Bram Moolenaar97b98102009-11-17 16:41:01 +00002703#ifdef FEAT_COMMENTS
2704 /* do not break "#a b" when 'tw' is 2 */
2705 if (curwin->w_cursor.col <= leader_len)
2706 break;
2707#endif
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002708 col = curwin->w_cursor.col;
2709 dec_cursor();
2710 cc = gchar_cursor();
2711
2712 if (WHITECHAR(cc))
2713 continue; /* one-letter, continue */
2714 curwin->w_cursor.col = col;
2715 }
Bram Moolenaar97b98102009-11-17 16:41:01 +00002716
2717 inc_cursor();
2718
2719 end_foundcol = end_col + 1;
2720 foundcol = curwin->w_cursor.col;
2721 if (curwin->w_cursor.col <= (colnr_T)wantcol)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002722 break;
2723 }
Bram Moolenaar97b98102009-11-17 16:41:01 +00002724 else if (cc >= 0x100 && fo_multibyte)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002725 {
2726 /* Break after or before a multi-byte character. */
Bram Moolenaar97b98102009-11-17 16:41:01 +00002727 if (curwin->w_cursor.col != startcol)
2728 {
2729#ifdef FEAT_COMMENTS
2730 /* Don't break until after the comment leader */
2731 if (curwin->w_cursor.col < leader_len)
2732 break;
2733#endif
2734 col = curwin->w_cursor.col;
2735 inc_cursor();
2736 /* Don't change end_foundcol if already set. */
2737 if (foundcol != curwin->w_cursor.col)
2738 {
2739 foundcol = curwin->w_cursor.col;
2740 end_foundcol = foundcol;
2741 if (curwin->w_cursor.col <= (colnr_T)wantcol)
2742 break;
2743 }
2744 curwin->w_cursor.col = col;
2745 }
2746
2747 if (curwin->w_cursor.col == 0)
2748 break;
2749
2750 col = curwin->w_cursor.col;
2751
2752 dec_cursor();
2753 cc = gchar_cursor();
2754
2755 if (WHITECHAR(cc))
2756 continue; /* break with space */
2757#ifdef FEAT_COMMENTS
2758 /* Don't break until after the comment leader */
2759 if (curwin->w_cursor.col < leader_len)
2760 break;
2761#endif
2762
2763 curwin->w_cursor.col = col;
2764
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002765 foundcol = curwin->w_cursor.col;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002766 end_foundcol = foundcol;
Bram Moolenaar97b98102009-11-17 16:41:01 +00002767 if (curwin->w_cursor.col <= (colnr_T)wantcol)
2768 break;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002769 }
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002770 if (curwin->w_cursor.col == 0)
2771 break;
2772 dec_cursor();
2773 }
2774
2775 if (foundcol == 0) /* no spaces, cannot break line */
2776 {
2777 curwin->w_cursor.col = startcol;
2778 break;
2779 }
2780
2781 /* Going to break the line, remove any "$" now. */
2782 undisplay_dollar();
2783
2784 /*
2785 * Offset between cursor position and line break is used by replace
2786 * stack functions. VREPLACE does not use this, and backspaces
2787 * over the text instead.
2788 */
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002789 if (State & VREPLACE_FLAG)
2790 orig_col = startcol; /* Will start backspacing from here */
2791 else
Bram Moolenaar97b98102009-11-17 16:41:01 +00002792 replace_offset = startcol - end_foundcol;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002793
2794 /*
2795 * adjust startcol for spaces that will be deleted and
2796 * characters that will remain on top line
2797 */
2798 curwin->w_cursor.col = foundcol;
Bram Moolenaar97b98102009-11-17 16:41:01 +00002799 while ((cc = gchar_cursor(), WHITECHAR(cc))
2800 && (!fo_white_par || curwin->w_cursor.col < startcol))
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002801 inc_cursor();
2802 startcol -= curwin->w_cursor.col;
2803 if (startcol < 0)
2804 startcol = 0;
2805
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002806 if (State & VREPLACE_FLAG)
2807 {
2808 /*
2809 * In VREPLACE mode, we will backspace over the text to be
2810 * wrapped, so save a copy now to put on the next line.
2811 */
2812 saved_text = vim_strsave(ml_get_cursor());
2813 curwin->w_cursor.col = orig_col;
2814 if (saved_text == NULL)
2815 break; /* Can't do it, out of memory */
2816 saved_text[startcol] = NUL;
2817
2818 /* Backspace over characters that will move to the next line */
2819 if (!fo_white_par)
2820 backspace_until_column(foundcol);
2821 }
2822 else
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002823 {
2824 /* put cursor after pos. to break line */
2825 if (!fo_white_par)
2826 curwin->w_cursor.col = foundcol;
2827 }
2828
2829 /*
2830 * Split the line just before the margin.
2831 * Only insert/delete lines, but don't really redraw the window.
2832 */
2833 open_line(FORWARD, OPENLINE_DELSPACES + OPENLINE_MARKFIX
2834 + (fo_white_par ? OPENLINE_KEEPTRAIL : 0)
2835#ifdef FEAT_COMMENTS
2836 + (do_comments ? OPENLINE_DO_COM : 0)
Bram Moolenaarbfe3bf82012-06-13 17:28:55 +02002837 + ((flags & INSCHAR_COM_LIST) ? OPENLINE_COM_LIST : 0)
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002838#endif
Bram Moolenaarbfe3bf82012-06-13 17:28:55 +02002839 , ((flags & INSCHAR_COM_LIST) ? second_indent : old_indent));
2840 if (!(flags & INSCHAR_COM_LIST))
2841 old_indent = 0;
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002842
2843 replace_offset = 0;
2844 if (first_line)
2845 {
Bram Moolenaarbfe3bf82012-06-13 17:28:55 +02002846 if (!(flags & INSCHAR_COM_LIST))
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002847 {
Bram Moolenaarbfe3bf82012-06-13 17:28:55 +02002848 /*
Bram Moolenaar96b7ca52012-06-29 15:04:49 +02002849 * This section is for auto-wrap of numeric lists. When not
2850 * in insert mode (i.e. format_lines()), the INSCHAR_COM_LIST
2851 * flag will be set and open_line() will handle it (as seen
2852 * above). The code here (and in get_number_indent()) will
2853 * recognize comments if needed...
Bram Moolenaarbfe3bf82012-06-13 17:28:55 +02002854 */
2855 if (second_indent < 0 && has_format_option(FO_Q_NUMBER))
Bram Moolenaar96b7ca52012-06-29 15:04:49 +02002856 second_indent =
2857 get_number_indent(curwin->w_cursor.lnum - 1);
Bram Moolenaarbfe3bf82012-06-13 17:28:55 +02002858 if (second_indent >= 0)
2859 {
Bram Moolenaarbfe3bf82012-06-13 17:28:55 +02002860 if (State & VREPLACE_FLAG)
2861 change_indent(INDENT_SET, second_indent,
2862 FALSE, NUL, TRUE);
2863 else
Bram Moolenaar96b7ca52012-06-29 15:04:49 +02002864#ifdef FEAT_COMMENTS
2865 if (leader_len > 0 && second_indent - leader_len > 0)
2866 {
2867 int i;
2868 int padding = second_indent - leader_len;
2869
2870 /* We started at the first_line of a numbered list
2871 * that has a comment. the open_line() function has
2872 * inserted the proper comment leader and positioned
2873 * the cursor at the end of the split line. Now we
2874 * add the additional whitespace needed after the
2875 * comment leader for the numbered list. */
2876 for (i = 0; i < padding; i++)
Bram Moolenaar96b7ca52012-06-29 15:04:49 +02002877 ins_str((char_u *)" ");
Bram Moolenaar96b7ca52012-06-29 15:04:49 +02002878 }
2879 else
2880 {
2881#endif
Bram Moolenaarbfe3bf82012-06-13 17:28:55 +02002882 (void)set_indent(second_indent, SIN_CHANGED);
Bram Moolenaar96b7ca52012-06-29 15:04:49 +02002883#ifdef FEAT_COMMENTS
2884 }
2885#endif
Bram Moolenaarbfe3bf82012-06-13 17:28:55 +02002886 }
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002887 }
2888 first_line = FALSE;
2889 }
2890
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002891 if (State & VREPLACE_FLAG)
2892 {
2893 /*
2894 * In VREPLACE mode we have backspaced over the text to be
2895 * moved, now we re-insert it into the new line.
2896 */
2897 ins_bytes(saved_text);
2898 vim_free(saved_text);
2899 }
2900 else
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002901 {
2902 /*
2903 * Check if cursor is not past the NUL off the line, cindent
2904 * may have added or removed indent.
2905 */
2906 curwin->w_cursor.col += startcol;
2907 len = (colnr_T)STRLEN(ml_get_curline());
2908 if (curwin->w_cursor.col > len)
2909 curwin->w_cursor.col = len;
2910 }
2911
2912 haveto_redraw = TRUE;
2913#ifdef FEAT_CINDENT
2914 can_cindent = TRUE;
2915#endif
2916 /* moved the cursor, don't autoindent or cindent now */
2917 did_ai = FALSE;
2918#ifdef FEAT_SMARTINDENT
2919 did_si = FALSE;
2920 can_si = FALSE;
2921 can_si_back = FALSE;
2922#endif
2923 line_breakcheck();
2924 }
2925
2926 if (save_char != NUL) /* put back space after cursor */
2927 pchar_cursor(save_char);
2928
Bram Moolenaar0026d472014-09-09 16:32:39 +02002929#ifdef FEAT_LINEBREAK
2930 curwin->w_p_lbr = has_lbr;
2931#endif
Bram Moolenaar1d2ba7f2006-02-14 22:29:30 +00002932 if (!format_only && haveto_redraw)
2933 {
2934 update_topline();
2935 redraw_curbuf_later(VALID);
2936 }
2937}
2938
2939/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00002940 * Called after inserting or deleting text: When 'formatoptions' includes the
2941 * 'a' flag format from the current line until the end of the paragraph.
2942 * Keep the cursor at the same position relative to the text.
2943 * The caller must have saved the cursor line for undo, following ones will be
2944 * saved here.
2945 */
2946 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01002947auto_format(
2948 int trailblank, /* when TRUE also format with trailing blank */
2949 int prev_line) /* may start in previous line */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002950{
2951 pos_T pos;
2952 colnr_T len;
2953 char_u *old;
2954 char_u *new, *pnew;
2955 int wasatend;
Bram Moolenaar75c50c42005-06-04 22:06:24 +00002956 int cc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002957
2958 if (!has_format_option(FO_AUTO))
2959 return;
2960
2961 pos = curwin->w_cursor;
2962 old = ml_get_curline();
2963
2964 /* may remove added space */
2965 check_auto_format(FALSE);
2966
2967 /* Don't format in Insert mode when the cursor is on a trailing blank, the
2968 * user might insert normal text next. Also skip formatting when "1" is
2969 * in 'formatoptions' and there is a single character before the cursor.
2970 * Otherwise the line would be broken and when typing another non-white
2971 * next they are not joined back together. */
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00002972 wasatend = (pos.col == (colnr_T)STRLEN(old));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002973 if (*old != NUL && !trailblank && wasatend)
2974 {
2975 dec_cursor();
Bram Moolenaar75c50c42005-06-04 22:06:24 +00002976 cc = gchar_cursor();
2977 if (!WHITECHAR(cc) && curwin->w_cursor.col > 0
2978 && has_format_option(FO_ONE_LETTER))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002979 dec_cursor();
Bram Moolenaar75c50c42005-06-04 22:06:24 +00002980 cc = gchar_cursor();
2981 if (WHITECHAR(cc))
Bram Moolenaar071d4272004-06-13 20:20:40 +00002982 {
2983 curwin->w_cursor = pos;
2984 return;
2985 }
2986 curwin->w_cursor = pos;
2987 }
2988
2989#ifdef FEAT_COMMENTS
2990 /* With the 'c' flag in 'formatoptions' and 't' missing: only format
2991 * comments. */
2992 if (has_format_option(FO_WRAP_COMS) && !has_format_option(FO_WRAP)
Bram Moolenaar81340392012-06-06 16:12:59 +02002993 && get_leader_len(old, NULL, FALSE, TRUE) == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002994 return;
2995#endif
2996
2997 /*
2998 * May start formatting in a previous line, so that after "x" a word is
2999 * moved to the previous line if it fits there now. Only when this is not
3000 * the start of a paragraph.
3001 */
3002 if (prev_line && !paragraph_start(curwin->w_cursor.lnum))
3003 {
3004 --curwin->w_cursor.lnum;
3005 if (u_save_cursor() == FAIL)
3006 return;
3007 }
3008
3009 /*
3010 * Do the formatting and restore the cursor position. "saved_cursor" will
3011 * be adjusted for the text formatting.
3012 */
3013 saved_cursor = pos;
Bram Moolenaar81a82092008-03-12 16:27:00 +00003014 format_lines((linenr_T)-1, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003015 curwin->w_cursor = saved_cursor;
3016 saved_cursor.lnum = 0;
3017
3018 if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
3019 {
3020 /* "cannot happen" */
3021 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
3022 coladvance((colnr_T)MAXCOL);
3023 }
3024 else
3025 check_cursor_col();
3026
3027 /* Insert mode: If the cursor is now after the end of the line while it
3028 * previously wasn't, the line was broken. Because of the rule above we
3029 * need to add a space when 'w' is in 'formatoptions' to keep a paragraph
3030 * formatted. */
3031 if (!wasatend && has_format_option(FO_WHITE_PAR))
3032 {
3033 new = ml_get_curline();
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00003034 len = (colnr_T)STRLEN(new);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003035 if (curwin->w_cursor.col == len)
3036 {
3037 pnew = vim_strnsave(new, len + 2);
3038 pnew[len] = ' ';
3039 pnew[len + 1] = NUL;
3040 ml_replace(curwin->w_cursor.lnum, pnew, FALSE);
3041 /* remove the space later */
3042 did_add_space = TRUE;
3043 }
3044 else
3045 /* may remove added space */
3046 check_auto_format(FALSE);
3047 }
3048
3049 check_cursor();
3050}
3051
3052/*
3053 * When an extra space was added to continue a paragraph for auto-formatting,
3054 * delete it now. The space must be under the cursor, just after the insert
3055 * position.
3056 */
3057 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +01003058check_auto_format(
3059 int end_insert) /* TRUE when ending Insert mode */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003060{
3061 int c = ' ';
Bram Moolenaar75c50c42005-06-04 22:06:24 +00003062 int cc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003063
3064 if (did_add_space)
3065 {
Bram Moolenaar75c50c42005-06-04 22:06:24 +00003066 cc = gchar_cursor();
3067 if (!WHITECHAR(cc))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003068 /* Somehow the space was removed already. */
3069 did_add_space = FALSE;
3070 else
3071 {
3072 if (!end_insert)
3073 {
3074 inc_cursor();
3075 c = gchar_cursor();
3076 dec_cursor();
3077 }
3078 if (c != NUL)
3079 {
3080 /* The space is no longer at the end of the line, delete it. */
3081 del_char(FALSE);
3082 did_add_space = FALSE;
3083 }
3084 }
3085 }
3086}
3087
3088/*
3089 * Find out textwidth to be used for formatting:
3090 * if 'textwidth' option is set, use it
Bram Moolenaar02631462017-09-22 15:20:32 +02003091 * else if 'wrapmargin' option is set, use curwin->w_width - 'wrapmargin'
Bram Moolenaar071d4272004-06-13 20:20:40 +00003092 * if invalid value, use 0.
3093 * Set default to window width (maximum 79) for "gq" operator.
3094 */
3095 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01003096comp_textwidth(
3097 int ff) /* force formatting (for "gq" command) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003098{
3099 int textwidth;
3100
3101 textwidth = curbuf->b_p_tw;
3102 if (textwidth == 0 && curbuf->b_p_wm)
3103 {
3104 /* The width is the window width minus 'wrapmargin' minus all the
3105 * things that add to the margin. */
Bram Moolenaar02631462017-09-22 15:20:32 +02003106 textwidth = curwin->w_width - curbuf->b_p_wm;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003107#ifdef FEAT_CMDWIN
3108 if (cmdwin_type != 0)
3109 textwidth -= 1;
3110#endif
3111#ifdef FEAT_FOLDING
3112 textwidth -= curwin->w_p_fdc;
3113#endif
3114#ifdef FEAT_SIGNS
Bram Moolenaar95ec9d62016-08-12 18:29:59 +02003115 if (signcolumn_on(curwin))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003116 textwidth -= 1;
3117#endif
Bram Moolenaar64486672010-05-16 15:46:46 +02003118 if (curwin->w_p_nu || curwin->w_p_rnu)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003119 textwidth -= 8;
3120 }
3121 if (textwidth < 0)
3122 textwidth = 0;
3123 if (ff && textwidth == 0)
3124 {
Bram Moolenaar02631462017-09-22 15:20:32 +02003125 textwidth = curwin->w_width - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003126 if (textwidth > 79)
3127 textwidth = 79;
3128 }
3129 return textwidth;
3130}
3131
3132/*
3133 * Put a character in the redo buffer, for when just after a CTRL-V.
3134 */
3135 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +01003136redo_literal(int c)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003137{
3138 char_u buf[10];
3139
3140 /* Only digits need special treatment. Translate them into a string of
3141 * three digits. */
3142 if (VIM_ISDIGIT(c))
3143 {
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00003144 vim_snprintf((char *)buf, sizeof(buf), "%03d", c);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003145 AppendToRedobuff(buf);
3146 }
3147 else
3148 AppendCharToRedobuff(c);
3149}
3150
3151/*
3152 * start_arrow() is called when an arrow key is used in insert mode.
Bram Moolenaar8aff23a2005-08-19 20:40:30 +00003153 * For undo/redo it resembles hitting the <ESC> key.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003154 */
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003155 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01003156start_arrow(
3157 pos_T *end_insert_pos) /* can be NULL */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003158{
Bram Moolenaar8b5f65a2015-09-01 19:26:12 +02003159 start_arrow_common(end_insert_pos, TRUE);
3160}
3161
3162/*
3163 * Like start_arrow() but with end_change argument.
3164 * Will prepare for redo of CTRL-G U if "end_change" is FALSE.
3165 */
3166 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +01003167start_arrow_with_change(
3168 pos_T *end_insert_pos, /* can be NULL */
3169 int end_change) /* end undoable change */
Bram Moolenaar8b5f65a2015-09-01 19:26:12 +02003170{
3171 start_arrow_common(end_insert_pos, end_change);
3172 if (!end_change)
3173 {
3174 AppendCharToRedobuff(Ctrl_G);
3175 AppendCharToRedobuff('U');
3176 }
3177}
3178
3179 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +01003180start_arrow_common(
3181 pos_T *end_insert_pos, /* can be NULL */
3182 int end_change) /* end undoable change */
Bram Moolenaar8b5f65a2015-09-01 19:26:12 +02003183{
3184 if (!arrow_used && end_change) /* something has been inserted */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003185 {
3186 AppendToRedobuff(ESC_STR);
Bram Moolenaarf332a652013-11-04 04:20:33 +01003187 stop_insert(end_insert_pos, FALSE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003188 arrow_used = TRUE; /* this means we stopped the current insert */
3189 }
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00003190#ifdef FEAT_SPELL
Bram Moolenaar217ad922005-03-20 22:37:15 +00003191 check_spell_redraw();
3192#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003193}
3194
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00003195#ifdef FEAT_SPELL
Bram Moolenaar217ad922005-03-20 22:37:15 +00003196/*
3197 * If we skipped highlighting word at cursor, do it now.
3198 * It may be skipped again, thus reset spell_redraw_lnum first.
3199 */
3200 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +01003201check_spell_redraw(void)
Bram Moolenaar217ad922005-03-20 22:37:15 +00003202{
3203 if (spell_redraw_lnum != 0)
3204 {
3205 linenr_T lnum = spell_redraw_lnum;
3206
3207 spell_redraw_lnum = 0;
Bram Moolenaarae12f4b2019-01-09 20:51:04 +01003208 redrawWinline(curwin, lnum);
Bram Moolenaar217ad922005-03-20 22:37:15 +00003209 }
3210}
Bram Moolenaar8aff23a2005-08-19 20:40:30 +00003211
Bram Moolenaar217ad922005-03-20 22:37:15 +00003212#endif
3213
Bram Moolenaar071d4272004-06-13 20:20:40 +00003214/*
3215 * stop_arrow() is called before a change is made in insert mode.
3216 * If an arrow key has been used, start a new insertion.
3217 * Returns FAIL if undo is impossible, shouldn't insert then.
3218 */
3219 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01003220stop_arrow(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003221{
3222 if (arrow_used)
3223 {
Bram Moolenaar1fc7e972014-08-16 18:13:03 +02003224 Insstart = curwin->w_cursor; /* new insertion starts here */
3225 if (Insstart.col > Insstart_orig.col && !ins_need_undo)
3226 /* Don't update the original insert position when moved to the
3227 * right, except when nothing was inserted yet. */
3228 update_Insstart_orig = FALSE;
3229 Insstart_textlen = (colnr_T)linetabsize(ml_get_curline());
3230
Bram Moolenaar071d4272004-06-13 20:20:40 +00003231 if (u_save_cursor() == OK)
3232 {
3233 arrow_used = FALSE;
3234 ins_need_undo = FALSE;
3235 }
Bram Moolenaar1fc7e972014-08-16 18:13:03 +02003236
Bram Moolenaar071d4272004-06-13 20:20:40 +00003237 ai_col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003238 if (State & VREPLACE_FLAG)
3239 {
3240 orig_line_count = curbuf->b_ml.ml_line_count;
3241 vr_lines_changed = 1;
3242 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003243 ResetRedobuff();
3244 AppendToRedobuff((char_u *)"1i"); /* pretend we start an insertion */
Bram Moolenaara9b1e742005-12-19 22:14:58 +00003245 new_insert_skip = 2;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003246 }
3247 else if (ins_need_undo)
3248 {
3249 if (u_save_cursor() == OK)
3250 ins_need_undo = FALSE;
3251 }
3252
3253#ifdef FEAT_FOLDING
3254 /* Always open fold at the cursor line when inserting something. */
3255 foldOpenCursor();
3256#endif
3257
3258 return (arrow_used || ins_need_undo ? FAIL : OK);
3259}
3260
3261/*
Bram Moolenaareb3593b2006-04-22 22:33:57 +00003262 * Do a few things to stop inserting.
3263 * "end_insert_pos" is where insert ended. It is NULL when we already jumped
3264 * to another window/buffer.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003265 */
3266 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +01003267stop_insert(
3268 pos_T *end_insert_pos,
3269 int esc, /* called by ins_esc() */
3270 int nomove) /* <c-\><c-o>, don't move cursor */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003271{
Bram Moolenaar83c465c2005-12-16 21:53:56 +00003272 int cc;
3273 char_u *ptr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003274
3275 stop_redo_ins();
3276 replace_flush(); /* abandon replace stack */
3277
3278 /*
Bram Moolenaar83c465c2005-12-16 21:53:56 +00003279 * Save the inserted text for later redo with ^@ and CTRL-A.
3280 * Don't do it when "restart_edit" was set and nothing was inserted,
3281 * otherwise CTRL-O w and then <Left> will clear "last_insert".
Bram Moolenaar071d4272004-06-13 20:20:40 +00003282 */
Bram Moolenaar83c465c2005-12-16 21:53:56 +00003283 ptr = get_inserted();
Bram Moolenaarf4cd3e82005-12-22 22:47:02 +00003284 if (did_restart_edit == 0 || (ptr != NULL
3285 && (int)STRLEN(ptr) > new_insert_skip))
Bram Moolenaar83c465c2005-12-16 21:53:56 +00003286 {
3287 vim_free(last_insert);
3288 last_insert = ptr;
3289 last_insert_skip = new_insert_skip;
3290 }
3291 else
3292 vim_free(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003293
Bram Moolenaareb3593b2006-04-22 22:33:57 +00003294 if (!arrow_used && end_insert_pos != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003295 {
3296 /* Auto-format now. It may seem strange to do this when stopping an
3297 * insertion (or moving the cursor), but it's required when appending
3298 * a line and having it end in a space. But only do it when something
3299 * was actually inserted, otherwise undo won't work. */
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00003300 if (!ins_need_undo && has_format_option(FO_AUTO))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003301 {
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00003302 pos_T tpos = curwin->w_cursor;
3303
Bram Moolenaar071d4272004-06-13 20:20:40 +00003304 /* When the cursor is at the end of the line after a space the
3305 * formatting will move it to the following word. Avoid that by
3306 * moving the cursor onto the space. */
3307 cc = 'x';
3308 if (curwin->w_cursor.col > 0 && gchar_cursor() == NUL)
3309 {
3310 dec_cursor();
3311 cc = gchar_cursor();
Bram Moolenaar1c465442017-03-12 20:10:05 +01003312 if (!VIM_ISWHITE(cc))
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00003313 curwin->w_cursor = tpos;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003314 }
3315
3316 auto_format(TRUE, FALSE);
3317
Bram Moolenaar1c465442017-03-12 20:10:05 +01003318 if (VIM_ISWHITE(cc))
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00003319 {
3320 if (gchar_cursor() != NUL)
3321 inc_cursor();
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003322 // If the cursor is still at the same character, also keep
3323 // the "coladd".
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00003324 if (gchar_cursor() == NUL
3325 && curwin->w_cursor.lnum == tpos.lnum
3326 && curwin->w_cursor.col == tpos.col)
3327 curwin->w_cursor.coladd = tpos.coladd;
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00003328 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003329 }
3330
3331 /* If a space was inserted for auto-formatting, remove it now. */
3332 check_auto_format(TRUE);
3333
3334 /* If we just did an auto-indent, remove the white space from the end
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00003335 * of the line, and put the cursor back.
Bram Moolenaar4be50682009-05-26 09:02:10 +00003336 * Do this when ESC was used or moving the cursor up/down.
3337 * Check for the old position still being valid, just in case the text
3338 * got changed unexpectedly. */
Bram Moolenaarf332a652013-11-04 04:20:33 +01003339 if (!nomove && did_ai && (esc || (vim_strchr(p_cpo, CPO_INDENT) == NULL
Bram Moolenaar4be50682009-05-26 09:02:10 +00003340 && curwin->w_cursor.lnum != end_insert_pos->lnum))
3341 && end_insert_pos->lnum <= curbuf->b_ml.ml_line_count)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003342 {
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00003343 pos_T tpos = curwin->w_cursor;
3344
3345 curwin->w_cursor = *end_insert_pos;
Bram Moolenaar4be50682009-05-26 09:02:10 +00003346 check_cursor_col(); /* make sure it is not past the line */
Bram Moolenaar39f05632006-03-19 22:15:26 +00003347 for (;;)
3348 {
3349 if (gchar_cursor() == NUL && curwin->w_cursor.col > 0)
3350 --curwin->w_cursor.col;
3351 cc = gchar_cursor();
Bram Moolenaar1c465442017-03-12 20:10:05 +01003352 if (!VIM_ISWHITE(cc))
Bram Moolenaar39f05632006-03-19 22:15:26 +00003353 break;
Bram Moolenaar4be50682009-05-26 09:02:10 +00003354 if (del_char(TRUE) == FAIL)
3355 break; /* should not happen */
Bram Moolenaar39f05632006-03-19 22:15:26 +00003356 }
Bram Moolenaarf4b8e572004-06-24 15:53:16 +00003357 if (curwin->w_cursor.lnum != tpos.lnum)
3358 curwin->w_cursor = tpos;
Bram Moolenaar2f31e392014-10-31 19:20:36 +01003359 else
3360 {
Bram Moolenaaref6875b2014-11-12 18:59:25 +01003361 /* reset tpos, could have been invalidated in the loop above */
3362 tpos = curwin->w_cursor;
Bram Moolenaar2f31e392014-10-31 19:20:36 +01003363 tpos.col++;
3364 if (cc != NUL && gchar_pos(&tpos) == NUL)
3365 ++curwin->w_cursor.col; /* put cursor back on the NUL */
3366 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003367
Bram Moolenaar071d4272004-06-13 20:20:40 +00003368 /* <C-S-Right> may have started Visual mode, adjust the position for
3369 * deleted characters. */
3370 if (VIsual_active && VIsual.lnum == curwin->w_cursor.lnum)
3371 {
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00003372 int len = (int)STRLEN(ml_get_curline());
3373
3374 if (VIsual.col > len)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003375 {
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00003376 VIsual.col = len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003377 VIsual.coladd = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003378 }
3379 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003380 }
3381 }
3382 did_ai = FALSE;
3383#ifdef FEAT_SMARTINDENT
3384 did_si = FALSE;
3385 can_si = FALSE;
3386 can_si_back = FALSE;
3387#endif
3388
Bram Moolenaareb3593b2006-04-22 22:33:57 +00003389 /* Set '[ and '] to the inserted text. When end_insert_pos is NULL we are
3390 * now in a different buffer. */
3391 if (end_insert_pos != NULL)
3392 {
3393 curbuf->b_op_start = Insstart;
Bram Moolenaarb1d90a32014-02-22 23:03:55 +01003394 curbuf->b_op_start_orig = Insstart_orig;
Bram Moolenaareb3593b2006-04-22 22:33:57 +00003395 curbuf->b_op_end = *end_insert_pos;
3396 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003397}
3398
3399/*
3400 * Set the last inserted text to a single character.
3401 * Used for the replace command.
3402 */
3403 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01003404set_last_insert(int c)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003405{
3406 char_u *s;
3407
3408 vim_free(last_insert);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003409 last_insert = alloc(MB_MAXBYTES * 3 + 5);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003410 if (last_insert != NULL)
3411 {
3412 s = last_insert;
3413 /* Use the CTRL-V only when entering a special char */
3414 if (c < ' ' || c == DEL)
3415 *s++ = Ctrl_V;
3416 s = add_char2buf(c, s);
3417 *s++ = ESC;
3418 *s++ = NUL;
3419 last_insert_skip = 0;
3420 }
3421}
3422
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003423#if defined(EXITFREE) || defined(PROTO)
3424 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01003425free_last_insert(void)
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003426{
Bram Moolenaard23a8232018-02-10 18:45:26 +01003427 VIM_CLEAR(last_insert);
Bram Moolenaarf461c8e2005-06-25 23:04:51 +00003428}
3429#endif
3430
Bram Moolenaar071d4272004-06-13 20:20:40 +00003431/*
3432 * Add character "c" to buffer "s". Escape the special meaning of K_SPECIAL
3433 * and CSI. Handle multi-byte characters.
3434 * Returns a pointer to after the added bytes.
3435 */
3436 char_u *
Bram Moolenaar7454a062016-01-30 15:14:10 +01003437add_char2buf(int c, char_u *s)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003438{
Bram Moolenaar9a920d82012-06-01 15:21:02 +02003439 char_u temp[MB_MAXBYTES + 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003440 int i;
3441 int len;
3442
3443 len = (*mb_char2bytes)(c, temp);
3444 for (i = 0; i < len; ++i)
3445 {
3446 c = temp[i];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003447 /* Need to escape K_SPECIAL and CSI like in the typeahead buffer. */
3448 if (c == K_SPECIAL)
3449 {
3450 *s++ = K_SPECIAL;
3451 *s++ = KS_SPECIAL;
3452 *s++ = KE_FILLER;
3453 }
3454#ifdef FEAT_GUI
3455 else if (c == CSI)
3456 {
3457 *s++ = CSI;
3458 *s++ = KS_EXTRA;
3459 *s++ = (int)KE_CSI;
3460 }
3461#endif
3462 else
3463 *s++ = c;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003464 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003465 return s;
3466}
3467
3468/*
3469 * move cursor to start of line
3470 * if flags & BL_WHITE move to first non-white
3471 * if flags & BL_SOL move to first non-white if startofline is set,
3472 * otherwise keep "curswant" column
3473 * if flags & BL_FIX don't leave the cursor on a NUL.
3474 */
3475 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01003476beginline(int flags)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003477{
3478 if ((flags & BL_SOL) && !p_sol)
3479 coladvance(curwin->w_curswant);
3480 else
3481 {
3482 curwin->w_cursor.col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003483 curwin->w_cursor.coladd = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003484
3485 if (flags & (BL_WHITE | BL_SOL))
3486 {
3487 char_u *ptr;
3488
Bram Moolenaar1c465442017-03-12 20:10:05 +01003489 for (ptr = ml_get_curline(); VIM_ISWHITE(*ptr)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003490 && !((flags & BL_FIX) && ptr[1] == NUL); ++ptr)
3491 ++curwin->w_cursor.col;
3492 }
3493 curwin->w_set_curswant = TRUE;
3494 }
3495}
3496
3497/*
3498 * oneright oneleft cursor_down cursor_up
3499 *
3500 * Move one char {right,left,down,up}.
Bram Moolenaar2eb25da2006-03-16 21:43:34 +00003501 * Doesn't move onto the NUL past the end of the line, unless it is allowed.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003502 * Return OK when successful, FAIL when we hit a line of file boundary.
3503 */
3504
3505 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01003506oneright(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003507{
3508 char_u *ptr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003509 int l;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003510
Bram Moolenaar071d4272004-06-13 20:20:40 +00003511 if (virtual_active())
3512 {
3513 pos_T prevpos = curwin->w_cursor;
3514
3515 /* Adjust for multi-wide char (excluding TAB) */
3516 ptr = ml_get_cursor();
Bram Moolenaar13505972019-01-24 15:04:48 +01003517 coladvance(getviscol() + ((*ptr != TAB
3518 && vim_isprintc((*mb_ptr2char)(ptr)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003519 ? ptr2cells(ptr) : 1));
3520 curwin->w_set_curswant = TRUE;
3521 /* Return OK if the cursor moved, FAIL otherwise (at window edge). */
3522 return (prevpos.col != curwin->w_cursor.col
3523 || prevpos.coladd != curwin->w_cursor.coladd) ? OK : FAIL;
3524 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003525
3526 ptr = ml_get_cursor();
Bram Moolenaar2eb25da2006-03-16 21:43:34 +00003527 if (*ptr == NUL)
3528 return FAIL; /* already at the very end */
3529
Bram Moolenaar2eb25da2006-03-16 21:43:34 +00003530 if (has_mbyte)
3531 l = (*mb_ptr2len)(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003532 else
Bram Moolenaar2eb25da2006-03-16 21:43:34 +00003533 l = 1;
3534
3535 /* move "l" bytes right, but don't end up on the NUL, unless 'virtualedit'
3536 * contains "onemore". */
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003537 if (ptr[l] == NUL && (ve_flags & VE_ONEMORE) == 0)
Bram Moolenaar2eb25da2006-03-16 21:43:34 +00003538 return FAIL;
3539 curwin->w_cursor.col += l;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003540
3541 curwin->w_set_curswant = TRUE;
3542 return OK;
3543}
3544
3545 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01003546oneleft(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003547{
Bram Moolenaar071d4272004-06-13 20:20:40 +00003548 if (virtual_active())
3549 {
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003550#ifdef FEAT_LINEBREAK
Bram Moolenaar071d4272004-06-13 20:20:40 +00003551 int width;
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003552#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003553 int v = getviscol();
3554
3555 if (v == 0)
3556 return FAIL;
3557
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003558#ifdef FEAT_LINEBREAK
Bram Moolenaar071d4272004-06-13 20:20:40 +00003559 /* We might get stuck on 'showbreak', skip over it. */
3560 width = 1;
3561 for (;;)
3562 {
3563 coladvance(v - width);
Bram Moolenaar597a4222014-06-25 14:39:50 +02003564 /* getviscol() is slow, skip it when 'showbreak' is empty,
3565 * 'breakindent' is not set and there are no multi-byte
3566 * characters */
3567 if ((*p_sbr == NUL && !curwin->w_p_bri
Bram Moolenaar13505972019-01-24 15:04:48 +01003568 && !has_mbyte) || getviscol() < v)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003569 break;
3570 ++width;
3571 }
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003572#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00003573 coladvance(v - 1);
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01003574#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003575
3576 if (curwin->w_cursor.coladd == 1)
3577 {
3578 char_u *ptr;
3579
3580 /* Adjust for multi-wide char (not a TAB) */
3581 ptr = ml_get_cursor();
Bram Moolenaar13505972019-01-24 15:04:48 +01003582 if (*ptr != TAB && vim_isprintc((*mb_ptr2char)(ptr))
3583 && ptr2cells(ptr) > 1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003584 curwin->w_cursor.coladd = 0;
3585 }
3586
3587 curwin->w_set_curswant = TRUE;
3588 return OK;
3589 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003590
3591 if (curwin->w_cursor.col == 0)
3592 return FAIL;
3593
3594 curwin->w_set_curswant = TRUE;
3595 --curwin->w_cursor.col;
3596
Bram Moolenaar071d4272004-06-13 20:20:40 +00003597 /* if the character on the left of the current cursor is a multi-byte
3598 * character, move to its first byte */
3599 if (has_mbyte)
3600 mb_adjust_cursor();
Bram Moolenaar071d4272004-06-13 20:20:40 +00003601 return OK;
3602}
3603
3604 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01003605cursor_up(
3606 long n,
3607 int upd_topline) /* When TRUE: update topline */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003608{
3609 linenr_T lnum;
3610
3611 if (n > 0)
3612 {
3613 lnum = curwin->w_cursor.lnum;
Bram Moolenaar7c626922005-02-07 22:01:03 +00003614 /* This fails if the cursor is already in the first line or the count
3615 * is larger than the line number and '-' is in 'cpoptions' */
3616 if (lnum <= 1 || (n >= lnum && vim_strchr(p_cpo, CPO_MINUS) != NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003617 return FAIL;
3618 if (n >= lnum)
3619 lnum = 1;
3620 else
3621#ifdef FEAT_FOLDING
3622 if (hasAnyFolding(curwin))
3623 {
3624 /*
3625 * Count each sequence of folded lines as one logical line.
3626 */
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003627 /* go to the start of the current fold */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003628 (void)hasFolding(lnum, &lnum, NULL);
3629
3630 while (n--)
3631 {
3632 /* move up one line */
3633 --lnum;
3634 if (lnum <= 1)
3635 break;
3636 /* If we entered a fold, move to the beginning, unless in
3637 * Insert mode or when 'foldopen' contains "all": it will open
3638 * in a moment. */
3639 if (n > 0 || !((State & INSERT) || (fdo_flags & FDO_ALL)))
3640 (void)hasFolding(lnum, &lnum, NULL);
3641 }
3642 if (lnum < 1)
3643 lnum = 1;
3644 }
3645 else
3646#endif
3647 lnum -= n;
3648 curwin->w_cursor.lnum = lnum;
3649 }
3650
3651 /* try to advance to the column we want to be at */
3652 coladvance(curwin->w_curswant);
3653
3654 if (upd_topline)
3655 update_topline(); /* make sure curwin->w_topline is valid */
3656
3657 return OK;
3658}
3659
3660/*
3661 * Cursor down a number of logical lines.
3662 */
3663 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01003664cursor_down(
3665 long n,
3666 int upd_topline) /* When TRUE: update topline */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003667{
3668 linenr_T lnum;
3669
3670 if (n > 0)
3671 {
3672 lnum = curwin->w_cursor.lnum;
3673#ifdef FEAT_FOLDING
3674 /* Move to last line of fold, will fail if it's the end-of-file. */
3675 (void)hasFolding(lnum, NULL, &lnum);
3676#endif
Bram Moolenaar7c626922005-02-07 22:01:03 +00003677 /* This fails if the cursor is already in the last line or would move
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02003678 * beyond the last line and '-' is in 'cpoptions' */
Bram Moolenaar7c626922005-02-07 22:01:03 +00003679 if (lnum >= curbuf->b_ml.ml_line_count
3680 || (lnum + n > curbuf->b_ml.ml_line_count
3681 && vim_strchr(p_cpo, CPO_MINUS) != NULL))
Bram Moolenaar071d4272004-06-13 20:20:40 +00003682 return FAIL;
3683 if (lnum + n >= curbuf->b_ml.ml_line_count)
3684 lnum = curbuf->b_ml.ml_line_count;
3685 else
3686#ifdef FEAT_FOLDING
3687 if (hasAnyFolding(curwin))
3688 {
3689 linenr_T last;
3690
3691 /* count each sequence of folded lines as one logical line */
3692 while (n--)
3693 {
3694 if (hasFolding(lnum, NULL, &last))
3695 lnum = last + 1;
3696 else
3697 ++lnum;
3698 if (lnum >= curbuf->b_ml.ml_line_count)
3699 break;
3700 }
3701 if (lnum > curbuf->b_ml.ml_line_count)
3702 lnum = curbuf->b_ml.ml_line_count;
3703 }
3704 else
3705#endif
3706 lnum += n;
3707 curwin->w_cursor.lnum = lnum;
3708 }
3709
3710 /* try to advance to the column we want to be at */
3711 coladvance(curwin->w_curswant);
3712
3713 if (upd_topline)
3714 update_topline(); /* make sure curwin->w_topline is valid */
3715
3716 return OK;
3717}
3718
3719/*
3720 * Stuff the last inserted text in the read buffer.
3721 * Last_insert actually is a copy of the redo buffer, so we
3722 * first have to remove the command.
3723 */
3724 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01003725stuff_inserted(
3726 int c, /* Command character to be inserted */
3727 long count, /* Repeat this many times */
3728 int no_esc) /* Don't add an ESC at the end */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003729{
3730 char_u *esc_ptr;
3731 char_u *ptr;
3732 char_u *last_ptr;
3733 char_u last = NUL;
3734
3735 ptr = get_last_insert();
3736 if (ptr == NULL)
3737 {
Bram Moolenaarf9e3e092019-01-13 23:38:42 +01003738 emsg(_(e_noinstext));
Bram Moolenaar071d4272004-06-13 20:20:40 +00003739 return FAIL;
3740 }
3741
3742 /* may want to stuff the command character, to start Insert mode */
3743 if (c != NUL)
3744 stuffcharReadbuff(c);
3745 if ((esc_ptr = (char_u *)vim_strrchr(ptr, ESC)) != NULL)
3746 *esc_ptr = NUL; /* remove the ESC */
3747
3748 /* when the last char is either "0" or "^" it will be quoted if no ESC
3749 * comes after it OR if it will inserted more than once and "ptr"
3750 * starts with ^D. -- Acevedo
3751 */
3752 last_ptr = (esc_ptr ? esc_ptr : ptr + STRLEN(ptr)) - 1;
3753 if (last_ptr >= ptr && (*last_ptr == '0' || *last_ptr == '^')
3754 && (no_esc || (*ptr == Ctrl_D && count > 1)))
3755 {
3756 last = *last_ptr;
3757 *last_ptr = NUL;
3758 }
3759
3760 do
3761 {
3762 stuffReadbuff(ptr);
3763 /* a trailing "0" is inserted as "<C-V>048", "^" as "<C-V>^" */
3764 if (last)
3765 stuffReadbuff((char_u *)(last == '0'
3766 ? IF_EB("\026\060\064\070", CTRL_V_STR "xf0")
3767 : IF_EB("\026^", CTRL_V_STR "^")));
3768 }
3769 while (--count > 0);
3770
3771 if (last)
3772 *last_ptr = last;
3773
3774 if (esc_ptr != NULL)
3775 *esc_ptr = ESC; /* put the ESC back */
3776
3777 /* may want to stuff a trailing ESC, to get out of Insert mode */
3778 if (!no_esc)
3779 stuffcharReadbuff(ESC);
3780
3781 return OK;
3782}
3783
3784 char_u *
Bram Moolenaar7454a062016-01-30 15:14:10 +01003785get_last_insert(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003786{
3787 if (last_insert == NULL)
3788 return NULL;
3789 return last_insert + last_insert_skip;
3790}
3791
3792/*
3793 * Get last inserted string, and remove trailing <Esc>.
3794 * Returns pointer to allocated memory (must be freed) or NULL.
3795 */
3796 char_u *
Bram Moolenaar7454a062016-01-30 15:14:10 +01003797get_last_insert_save(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003798{
3799 char_u *s;
3800 int len;
3801
3802 if (last_insert == NULL)
3803 return NULL;
3804 s = vim_strsave(last_insert + last_insert_skip);
3805 if (s != NULL)
3806 {
3807 len = (int)STRLEN(s);
3808 if (len > 0 && s[len - 1] == ESC) /* remove trailing ESC */
3809 s[len - 1] = NUL;
3810 }
3811 return s;
3812}
3813
3814/*
3815 * Check the word in front of the cursor for an abbreviation.
3816 * Called when the non-id character "c" has been entered.
3817 * When an abbreviation is recognized it is removed from the text and
3818 * the replacement string is inserted in typebuf.tb_buf[], followed by "c".
3819 */
3820 static int
Bram Moolenaar7454a062016-01-30 15:14:10 +01003821echeck_abbr(int c)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003822{
3823 /* Don't check for abbreviation in paste mode, when disabled and just
3824 * after moving around with cursor keys. */
3825 if (p_paste || no_abbr || arrow_used)
3826 return FALSE;
3827
3828 return check_abbr(c, ml_get_curline(), curwin->w_cursor.col,
3829 curwin->w_cursor.lnum == Insstart.lnum ? Insstart.col : 0);
3830}
3831
3832/*
3833 * replace-stack functions
3834 *
3835 * When replacing characters, the replaced characters are remembered for each
3836 * new character. This is used to re-insert the old text when backspacing.
3837 *
3838 * There is a NUL headed list of characters for each character that is
3839 * currently in the file after the insertion point. When BS is used, one NUL
3840 * headed list is put back for the deleted character.
3841 *
3842 * For a newline, there are two NUL headed lists. One contains the characters
3843 * that the NL replaced. The extra one stores the characters after the cursor
3844 * that were deleted (always white space).
3845 *
3846 * Replace_offset is normally 0, in which case replace_push will add a new
3847 * character at the end of the stack. If replace_offset is not 0, that many
3848 * characters will be left on the stack above the newly inserted character.
3849 */
3850
Bram Moolenaar6c0b44b2005-06-01 21:56:33 +00003851static char_u *replace_stack = NULL;
3852static long replace_stack_nr = 0; /* next entry in replace stack */
3853static long replace_stack_len = 0; /* max. number of entries */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003854
3855 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01003856replace_push(
3857 int c) /* character that is replaced (NUL is none) */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003858{
3859 char_u *p;
3860
3861 if (replace_stack_nr < replace_offset) /* nothing to do */
3862 return;
3863 if (replace_stack_len <= replace_stack_nr)
3864 {
3865 replace_stack_len += 50;
Bram Moolenaar3397f742019-06-02 18:40:06 +02003866 p = ALLOC_MULT(char_u, replace_stack_len);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003867 if (p == NULL) /* out of memory */
3868 {
3869 replace_stack_len -= 50;
3870 return;
3871 }
3872 if (replace_stack != NULL)
3873 {
3874 mch_memmove(p, replace_stack,
3875 (size_t)(replace_stack_nr * sizeof(char_u)));
3876 vim_free(replace_stack);
3877 }
3878 replace_stack = p;
3879 }
3880 p = replace_stack + replace_stack_nr - replace_offset;
3881 if (replace_offset)
3882 mch_memmove(p + 1, p, (size_t)(replace_offset * sizeof(char_u)));
3883 *p = c;
3884 ++replace_stack_nr;
3885}
3886
Bram Moolenaar2c994e82008-01-02 16:49:36 +00003887/*
3888 * Push a character onto the replace stack. Handles a multi-byte character in
3889 * reverse byte order, so that the first byte is popped off first.
3890 * Return the number of bytes done (includes composing characters).
3891 */
3892 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01003893replace_push_mb(char_u *p)
Bram Moolenaar2c994e82008-01-02 16:49:36 +00003894{
3895 int l = (*mb_ptr2len)(p);
3896 int j;
3897
3898 for (j = l - 1; j >= 0; --j)
3899 replace_push(p[j]);
3900 return l;
3901}
Bram Moolenaar2c994e82008-01-02 16:49:36 +00003902
Bram Moolenaar071d4272004-06-13 20:20:40 +00003903/*
3904 * Pop one item from the replace stack.
3905 * return -1 if stack empty
3906 * return replaced character or NUL otherwise
3907 */
3908 static int
Bram Moolenaar7454a062016-01-30 15:14:10 +01003909replace_pop(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003910{
3911 if (replace_stack_nr == 0)
3912 return -1;
3913 return (int)replace_stack[--replace_stack_nr];
3914}
3915
3916/*
3917 * Join the top two items on the replace stack. This removes to "off"'th NUL
3918 * encountered.
3919 */
3920 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +01003921replace_join(
3922 int off) /* offset for which NUL to remove */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003923{
3924 int i;
3925
3926 for (i = replace_stack_nr; --i >= 0; )
3927 if (replace_stack[i] == NUL && off-- <= 0)
3928 {
3929 --replace_stack_nr;
3930 mch_memmove(replace_stack + i, replace_stack + i + 1,
3931 (size_t)(replace_stack_nr - i));
3932 return;
3933 }
3934}
3935
3936/*
3937 * Pop bytes from the replace stack until a NUL is found, and insert them
3938 * before the cursor. Can only be used in REPLACE or VREPLACE mode.
3939 */
3940 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +01003941replace_pop_ins(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003942{
3943 int cc;
3944 int oldState = State;
3945
3946 State = NORMAL; /* don't want REPLACE here */
3947 while ((cc = replace_pop()) > 0)
3948 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00003949 mb_replace_pop_ins(cc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003950 dec_cursor();
3951 }
3952 State = oldState;
3953}
3954
Bram Moolenaar071d4272004-06-13 20:20:40 +00003955/*
3956 * Insert bytes popped from the replace stack. "cc" is the first byte. If it
3957 * indicates a multi-byte char, pop the other bytes too.
3958 */
3959 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +01003960mb_replace_pop_ins(int cc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003961{
3962 int n;
Bram Moolenaar9a920d82012-06-01 15:21:02 +02003963 char_u buf[MB_MAXBYTES + 1];
Bram Moolenaar071d4272004-06-13 20:20:40 +00003964 int i;
3965 int c;
3966
3967 if (has_mbyte && (n = MB_BYTE2LEN(cc)) > 1)
3968 {
3969 buf[0] = cc;
3970 for (i = 1; i < n; ++i)
3971 buf[i] = replace_pop();
3972 ins_bytes_len(buf, n);
3973 }
3974 else
3975 ins_char(cc);
3976
3977 if (enc_utf8)
3978 /* Handle composing chars. */
3979 for (;;)
3980 {
3981 c = replace_pop();
3982 if (c == -1) /* stack empty */
3983 break;
3984 if ((n = MB_BYTE2LEN(c)) == 1)
3985 {
3986 /* Not a multi-byte char, put it back. */
3987 replace_push(c);
3988 break;
3989 }
3990 else
3991 {
3992 buf[0] = c;
3993 for (i = 1; i < n; ++i)
3994 buf[i] = replace_pop();
3995 if (utf_iscomposing(utf_ptr2char(buf)))
3996 ins_bytes_len(buf, n);
3997 else
3998 {
3999 /* Not a composing char, put it back. */
4000 for (i = n - 1; i >= 0; --i)
4001 replace_push(buf[i]);
4002 break;
4003 }
4004 }
4005 }
4006}
Bram Moolenaar071d4272004-06-13 20:20:40 +00004007
4008/*
4009 * make the replace stack empty
4010 * (called when exiting replace mode)
4011 */
4012 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +01004013replace_flush(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004014{
Bram Moolenaard23a8232018-02-10 18:45:26 +01004015 VIM_CLEAR(replace_stack);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004016 replace_stack_len = 0;
4017 replace_stack_nr = 0;
4018}
4019
4020/*
4021 * Handle doing a BS for one character.
4022 * cc < 0: replace stack empty, just move cursor
4023 * cc == 0: character was inserted, delete it
4024 * cc > 0: character was replaced, put cc (first byte of original char) back
4025 * and check for more characters to be put back
Bram Moolenaar0f6c9482009-01-13 11:29:48 +00004026 * When "limit_col" is >= 0, don't delete before this column. Matters when
4027 * using composing characters, use del_char_after_col() instead of del_char().
Bram Moolenaar071d4272004-06-13 20:20:40 +00004028 */
4029 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +01004030replace_do_bs(int limit_col)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004031{
4032 int cc;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004033 int orig_len = 0;
4034 int ins_len;
4035 int orig_vcols = 0;
4036 colnr_T start_vcol;
4037 char_u *p;
4038 int i;
4039 int vcol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004040
4041 cc = replace_pop();
4042 if (cc > 0)
4043 {
Bram Moolenaar196d1572019-01-02 23:47:18 +01004044#ifdef FEAT_TEXT_PROP
Bram Moolenaar6d11f3b2019-01-06 17:44:38 +01004045 size_t len_before = 0; // init to shut up GCC
Bram Moolenaar196d1572019-01-02 23:47:18 +01004046
4047 if (curbuf->b_has_textprop)
4048 {
4049 // Do not adjust text properties for individual delete and insert
4050 // operations, do it afterwards on the resulting text.
4051 len_before = STRLEN(ml_get_curline());
4052 ++text_prop_frozen;
4053 }
4054#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004055 if (State & VREPLACE_FLAG)
4056 {
4057 /* Get the number of screen cells used by the character we are
4058 * going to delete. */
4059 getvcol(curwin, &curwin->w_cursor, NULL, &start_vcol, NULL);
4060 orig_vcols = chartabsize(ml_get_cursor(), start_vcol);
4061 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004062 if (has_mbyte)
4063 {
Bram Moolenaar0f6c9482009-01-13 11:29:48 +00004064 (void)del_char_after_col(limit_col);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004065 if (State & VREPLACE_FLAG)
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004066 orig_len = (int)STRLEN(ml_get_cursor());
Bram Moolenaar071d4272004-06-13 20:20:40 +00004067 replace_push(cc);
4068 }
4069 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004070 {
4071 pchar_cursor(cc);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004072 if (State & VREPLACE_FLAG)
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004073 orig_len = (int)STRLEN(ml_get_cursor()) - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004074 }
4075 replace_pop_ins();
4076
Bram Moolenaar071d4272004-06-13 20:20:40 +00004077 if (State & VREPLACE_FLAG)
4078 {
4079 /* Get the number of screen cells used by the inserted characters */
4080 p = ml_get_cursor();
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004081 ins_len = (int)STRLEN(p) - orig_len;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004082 vcol = start_vcol;
4083 for (i = 0; i < ins_len; ++i)
4084 {
4085 vcol += chartabsize(p + i, vcol);
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00004086 i += (*mb_ptr2len)(p) - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004087 }
4088 vcol -= start_vcol;
4089
4090 /* Delete spaces that were inserted after the cursor to keep the
4091 * text aligned. */
4092 curwin->w_cursor.col += ins_len;
4093 while (vcol > orig_vcols && gchar_cursor() == ' ')
4094 {
4095 del_char(FALSE);
4096 ++orig_vcols;
4097 }
4098 curwin->w_cursor.col -= ins_len;
4099 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004100
Bram Moolenaar196d1572019-01-02 23:47:18 +01004101 // mark the buffer as changed and prepare for displaying
Bram Moolenaar071d4272004-06-13 20:20:40 +00004102 changed_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col);
Bram Moolenaar196d1572019-01-02 23:47:18 +01004103
4104#ifdef FEAT_TEXT_PROP
4105 if (curbuf->b_has_textprop)
4106 {
4107 size_t len_now = STRLEN(ml_get_curline());
4108
4109 --text_prop_frozen;
4110 adjust_prop_columns(curwin->w_cursor.lnum, curwin->w_cursor.col,
Bram Moolenaarf3333b02019-05-19 22:53:40 +02004111 (int)(len_now - len_before), 0);
Bram Moolenaar196d1572019-01-02 23:47:18 +01004112 }
4113#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004114 }
4115 else if (cc == 0)
Bram Moolenaar0f6c9482009-01-13 11:29:48 +00004116 (void)del_char_after_col(limit_col);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004117}
4118
Bram Moolenaar071d4272004-06-13 20:20:40 +00004119#if defined(FEAT_RIGHTLEFT) || defined(PROTO)
4120/*
4121 * Map Hebrew keyboard when in hkmap mode.
4122 */
4123 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01004124hkmap(int c)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004125{
4126 if (p_hkmapp) /* phonetic mapping, by Ilya Dogolazky */
4127 {
4128 enum {hALEF=0, BET, GIMEL, DALET, HEI, VAV, ZAIN, HET, TET, IUD,
4129 KAFsofit, hKAF, LAMED, MEMsofit, MEM, NUNsofit, NUN, SAMEH, AIN,
4130 PEIsofit, PEI, ZADIsofit, ZADI, KOF, RESH, hSHIN, TAV};
4131 static char_u map[26] =
4132 {(char_u)hALEF/*a*/, (char_u)BET /*b*/, (char_u)hKAF /*c*/,
4133 (char_u)DALET/*d*/, (char_u)-1 /*e*/, (char_u)PEIsofit/*f*/,
4134 (char_u)GIMEL/*g*/, (char_u)HEI /*h*/, (char_u)IUD /*i*/,
4135 (char_u)HET /*j*/, (char_u)KOF /*k*/, (char_u)LAMED /*l*/,
4136 (char_u)MEM /*m*/, (char_u)NUN /*n*/, (char_u)SAMEH /*o*/,
4137 (char_u)PEI /*p*/, (char_u)-1 /*q*/, (char_u)RESH /*r*/,
4138 (char_u)ZAIN /*s*/, (char_u)TAV /*t*/, (char_u)TET /*u*/,
4139 (char_u)VAV /*v*/, (char_u)hSHIN/*w*/, (char_u)-1 /*x*/,
4140 (char_u)AIN /*y*/, (char_u)ZADI /*z*/};
4141
4142 if (c == 'N' || c == 'M' || c == 'P' || c == 'C' || c == 'Z')
4143 return (int)(map[CharOrd(c)] - 1 + p_aleph);
4144 /* '-1'='sofit' */
4145 else if (c == 'x')
4146 return 'X';
4147 else if (c == 'q')
4148 return '\''; /* {geresh}={'} */
4149 else if (c == 246)
4150 return ' '; /* \"o --> ' ' for a german keyboard */
4151 else if (c == 228)
4152 return ' '; /* \"a --> ' ' -- / -- */
4153 else if (c == 252)
4154 return ' '; /* \"u --> ' ' -- / -- */
4155#ifdef EBCDIC
4156 else if (islower(c))
4157#else
4158 /* NOTE: islower() does not do the right thing for us on Linux so we
4159 * do this the same was as 5.7 and previous, so it works correctly on
4160 * all systems. Specifically, the e.g. Delete and Arrow keys are
4161 * munged and won't work if e.g. searching for Hebrew text.
4162 */
4163 else if (c >= 'a' && c <= 'z')
4164#endif
4165 return (int)(map[CharOrdLow(c)] + p_aleph);
4166 else
4167 return c;
4168 }
4169 else
4170 {
4171 switch (c)
4172 {
4173 case '`': return ';';
4174 case '/': return '.';
4175 case '\'': return ',';
4176 case 'q': return '/';
4177 case 'w': return '\'';
4178
4179 /* Hebrew letters - set offset from 'a' */
4180 case ',': c = '{'; break;
4181 case '.': c = 'v'; break;
4182 case ';': c = 't'; break;
4183 default: {
4184 static char str[] = "zqbcxlsjphmkwonu ydafe rig";
4185
4186#ifdef EBCDIC
4187 /* see note about islower() above */
4188 if (!islower(c))
4189#else
4190 if (c < 'a' || c > 'z')
4191#endif
4192 return c;
4193 c = str[CharOrdLow(c)];
4194 break;
4195 }
4196 }
4197
4198 return (int)(CharOrdLow(c) + p_aleph);
4199 }
4200}
4201#endif
4202
4203 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +01004204ins_reg(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004205{
4206 int need_redraw = FALSE;
4207 int regname;
4208 int literally = 0;
Bram Moolenaarf193fff2006-04-27 00:02:13 +00004209 int vis_active = VIsual_active;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004210
4211 /*
4212 * If we are going to wait for a character, show a '"'.
4213 */
4214 pc_status = PC_STATUS_UNSET;
4215 if (redrawing() && !char_avail())
4216 {
4217 /* may need to redraw when no more chars available now */
Bram Moolenaar754b5602006-02-09 23:53:20 +00004218 ins_redraw(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004219
4220 edit_putchar('"', TRUE);
4221#ifdef FEAT_CMDL_INFO
4222 add_to_showcmd_c(Ctrl_R);
4223#endif
4224 }
4225
4226#ifdef USE_ON_FLY_SCROLL
4227 dont_scroll = TRUE; /* disallow scrolling here */
4228#endif
4229
4230 /*
4231 * Don't map the register name. This also prevents the mode message to be
4232 * deleted when ESC is hit.
4233 */
4234 ++no_mapping;
Bram Moolenaar61abfd12007-09-13 16:26:47 +00004235 regname = plain_vgetc();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004236 LANGMAP_ADJUST(regname, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004237 if (regname == Ctrl_R || regname == Ctrl_O || regname == Ctrl_P)
4238 {
4239 /* Get a third key for literal register insertion */
4240 literally = regname;
4241#ifdef FEAT_CMDL_INFO
4242 add_to_showcmd_c(literally);
4243#endif
Bram Moolenaar61abfd12007-09-13 16:26:47 +00004244 regname = plain_vgetc();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004245 LANGMAP_ADJUST(regname, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004246 }
4247 --no_mapping;
4248
4249#ifdef FEAT_EVAL
Bram Moolenaardf9259a2013-06-15 17:54:43 +02004250 /* Don't call u_sync() while typing the expression or giving an error
4251 * message for it. Only call it explicitly. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004252 ++no_u_sync;
4253 if (regname == '=')
4254 {
Bram Moolenaar9e26f7d2019-01-22 22:08:09 +01004255 pos_T curpos = curwin->w_cursor;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01004256# ifdef HAVE_INPUT_METHOD
Bram Moolenaar071d4272004-06-13 20:20:40 +00004257 int im_on = im_get_status();
Bram Moolenaar8f999f12005-01-25 22:12:55 +00004258# endif
Bram Moolenaar3c1e9c22013-07-04 20:25:41 +02004259 /* Sync undo when evaluating the expression calls setline() or
4260 * append(), so that it can be undone separately. */
4261 u_sync_once = 2;
Bram Moolenaar5737ca22013-06-27 22:21:24 +02004262
Bram Moolenaar071d4272004-06-13 20:20:40 +00004263 regname = get_expr_register();
Bram Moolenaar9e26f7d2019-01-22 22:08:09 +01004264
4265 // Cursor may be moved back a column.
4266 curwin->w_cursor = curpos;
4267 check_cursor();
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01004268# ifdef HAVE_INPUT_METHOD
Bram Moolenaar9e26f7d2019-01-22 22:08:09 +01004269 // Restore the Input Method.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004270 if (im_on)
4271 im_set_active(TRUE);
Bram Moolenaar8f999f12005-01-25 22:12:55 +00004272# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004273 }
Bram Moolenaar677ee682005-01-27 14:41:15 +00004274 if (regname == NUL || !valid_yank_reg(regname, FALSE))
4275 {
Bram Moolenaar165bc692015-07-21 17:53:25 +02004276 vim_beep(BO_REG);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004277 need_redraw = TRUE; /* remove the '"' */
Bram Moolenaar677ee682005-01-27 14:41:15 +00004278 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004279 else
4280 {
4281#endif
4282 if (literally == Ctrl_O || literally == Ctrl_P)
4283 {
4284 /* Append the command to the redo buffer. */
4285 AppendCharToRedobuff(Ctrl_R);
4286 AppendCharToRedobuff(literally);
4287 AppendCharToRedobuff(regname);
4288
4289 do_put(regname, BACKWARD, 1L,
4290 (literally == Ctrl_P ? PUT_FIXINDENT : 0) | PUT_CURSEND);
4291 }
4292 else if (insert_reg(regname, literally) == FAIL)
4293 {
Bram Moolenaar165bc692015-07-21 17:53:25 +02004294 vim_beep(BO_REG);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004295 need_redraw = TRUE; /* remove the '"' */
4296 }
Bram Moolenaar8f999f12005-01-25 22:12:55 +00004297 else if (stop_insert_mode)
4298 /* When the '=' register was used and a function was invoked that
4299 * did ":stopinsert" then stuff_empty() returns FALSE but we won't
4300 * insert anything, need to remove the '"' */
4301 need_redraw = TRUE;
4302
Bram Moolenaar071d4272004-06-13 20:20:40 +00004303#ifdef FEAT_EVAL
4304 }
4305 --no_u_sync;
Bram Moolenaar3c1e9c22013-07-04 20:25:41 +02004306 if (u_sync_once == 1)
4307 ins_need_undo = TRUE;
4308 u_sync_once = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004309#endif
4310#ifdef FEAT_CMDL_INFO
4311 clear_showcmd();
4312#endif
4313
4314 /* If the inserted register is empty, we need to remove the '"' */
4315 if (need_redraw || stuff_empty())
4316 edit_unputchar();
Bram Moolenaarf193fff2006-04-27 00:02:13 +00004317
Bram Moolenaarf193fff2006-04-27 00:02:13 +00004318 /* Disallow starting Visual mode here, would get a weird mode. */
4319 if (!vis_active && VIsual_active)
4320 end_visual_mode();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004321}
4322
4323/*
4324 * CTRL-G commands in Insert mode.
4325 */
4326 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +01004327ins_ctrl_g(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004328{
4329 int c;
4330
4331#ifdef FEAT_INS_EXPAND
4332 /* Right after CTRL-X the cursor will be after the ruler. */
4333 setcursor();
4334#endif
4335
4336 /*
4337 * Don't map the second key. This also prevents the mode message to be
4338 * deleted when ESC is hit.
4339 */
4340 ++no_mapping;
Bram Moolenaar61abfd12007-09-13 16:26:47 +00004341 c = plain_vgetc();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004342 --no_mapping;
4343 switch (c)
4344 {
4345 /* CTRL-G k and CTRL-G <Up>: cursor up to Insstart.col */
4346 case K_UP:
4347 case Ctrl_K:
4348 case 'k': ins_up(TRUE);
4349 break;
4350
4351 /* CTRL-G j and CTRL-G <Down>: cursor down to Insstart.col */
4352 case K_DOWN:
4353 case Ctrl_J:
4354 case 'j': ins_down(TRUE);
4355 break;
4356
4357 /* CTRL-G u: start new undoable edit */
Bram Moolenaar779b74b2006-04-10 14:55:34 +00004358 case 'u': u_sync(TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004359 ins_need_undo = TRUE;
Bram Moolenaara40ceaf2006-01-13 22:35:40 +00004360
4361 /* Need to reset Insstart, esp. because a BS that joins
Bram Moolenaar34e0bfa2007-05-10 18:44:18 +00004362 * a line to the previous one must save for undo. */
Bram Moolenaarb1d90a32014-02-22 23:03:55 +01004363 update_Insstart_orig = FALSE;
Bram Moolenaara40ceaf2006-01-13 22:35:40 +00004364 Insstart = curwin->w_cursor;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004365 break;
4366
Bram Moolenaar8b5f65a2015-09-01 19:26:12 +02004367 /* CTRL-G U: do not break undo with the next char */
4368 case 'U':
4369 /* Allow one left/right cursor movement with the next char,
4370 * without breaking undo. */
4371 dont_sync_undo = MAYBE;
4372 break;
4373
Bram Moolenaar071d4272004-06-13 20:20:40 +00004374 /* Unknown CTRL-G command, reserved for future expansion. */
Bram Moolenaar165bc692015-07-21 17:53:25 +02004375 default: vim_beep(BO_CTRLG);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004376 }
4377}
4378
4379/*
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004380 * CTRL-^ in Insert mode.
4381 */
4382 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +01004383ins_ctrl_hat(void)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004384{
Bram Moolenaar97b2ad32006-03-18 21:40:56 +00004385 if (map_to_exists_mode((char_u *)"", LANGMAP, FALSE))
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004386 {
4387 /* ":lmap" mappings exists, Toggle use of ":lmap" mappings. */
4388 if (State & LANGMAP)
4389 {
4390 curbuf->b_p_iminsert = B_IMODE_NONE;
4391 State &= ~LANGMAP;
4392 }
4393 else
4394 {
4395 curbuf->b_p_iminsert = B_IMODE_LMAP;
4396 State |= LANGMAP;
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01004397#ifdef HAVE_INPUT_METHOD
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004398 im_set_active(FALSE);
4399#endif
4400 }
4401 }
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01004402#ifdef HAVE_INPUT_METHOD
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004403 else
4404 {
4405 /* There are no ":lmap" mappings, toggle IM */
4406 if (im_get_status())
4407 {
4408 curbuf->b_p_iminsert = B_IMODE_NONE;
4409 im_set_active(FALSE);
4410 }
4411 else
4412 {
4413 curbuf->b_p_iminsert = B_IMODE_IM;
4414 State &= ~LANGMAP;
4415 im_set_active(TRUE);
4416 }
4417 }
4418#endif
4419 set_iminsert_global();
4420 showmode();
4421#ifdef FEAT_GUI
4422 /* may show different cursor shape or color */
4423 if (gui.in_use)
4424 gui_update_cursor(TRUE, FALSE);
4425#endif
Bram Moolenaar4033c552017-09-16 20:54:51 +02004426#if defined(FEAT_KEYMAP)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004427 /* Show/unshow value of 'keymap' in status lines. */
4428 status_redraw_curbuf();
4429#endif
4430}
4431
4432/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00004433 * Handle ESC in insert mode.
4434 * Returns TRUE when leaving insert mode, FALSE when going to repeat the
4435 * insert.
4436 */
4437 static int
Bram Moolenaar7454a062016-01-30 15:14:10 +01004438ins_esc(
4439 long *count,
4440 int cmdchar,
4441 int nomove) /* don't move cursor */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004442{
4443 int temp;
4444 static int disabled_redraw = FALSE;
4445
Bram Moolenaarb9a02fc2006-03-12 22:08:12 +00004446#ifdef FEAT_SPELL
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004447 check_spell_redraw();
4448#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004449#if defined(FEAT_HANGULIN)
4450# if defined(ESC_CHG_TO_ENG_MODE)
4451 hangul_input_state_set(0);
4452# endif
4453 if (composing_hangul)
4454 {
4455 push_raw_key(composing_hangul_buffer, 2);
4456 composing_hangul = 0;
4457 }
4458#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004459
4460 temp = curwin->w_cursor.col;
4461 if (disabled_redraw)
4462 {
4463 --RedrawingDisabled;
4464 disabled_redraw = FALSE;
4465 }
4466 if (!arrow_used)
4467 {
4468 /*
4469 * Don't append the ESC for "r<CR>" and "grx".
Bram Moolenaar12805862005-01-05 22:16:17 +00004470 * When 'insertmode' is set only CTRL-L stops Insert mode. Needed for
4471 * when "count" is non-zero.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004472 */
4473 if (cmdchar != 'r' && cmdchar != 'v')
Bram Moolenaar12805862005-01-05 22:16:17 +00004474 AppendToRedobuff(p_im ? (char_u *)"\014" : ESC_STR);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004475
4476 /*
4477 * Repeating insert may take a long time. Check for
4478 * interrupt now and then.
4479 */
4480 if (*count > 0)
4481 {
4482 line_breakcheck();
4483 if (got_int)
4484 *count = 0;
4485 }
4486
4487 if (--*count > 0) /* repeat what was typed */
4488 {
Bram Moolenaar4399ef42005-02-12 14:29:27 +00004489 /* Vi repeats the insert without replacing characters. */
4490 if (vim_strchr(p_cpo, CPO_REPLCNT) != NULL)
4491 State &= ~REPLACE_FLAG;
4492
Bram Moolenaar071d4272004-06-13 20:20:40 +00004493 (void)start_redo_ins();
4494 if (cmdchar == 'r' || cmdchar == 'v')
Bram Moolenaar4f5ce332014-07-30 16:00:58 +02004495 stuffRedoReadbuff(ESC_STR); /* no ESC in redo buffer */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004496 ++RedrawingDisabled;
4497 disabled_redraw = TRUE;
4498 return FALSE; /* repeat the insert */
4499 }
Bram Moolenaarf332a652013-11-04 04:20:33 +01004500 stop_insert(&curwin->w_cursor, TRUE, nomove);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004501 undisplay_dollar();
4502 }
4503
4504 /* When an autoindent was removed, curswant stays after the
4505 * indent */
4506 if (restart_edit == NUL && (colnr_T)temp == curwin->w_cursor.col)
4507 curwin->w_set_curswant = TRUE;
4508
4509 /* Remember the last Insert position in the '^ mark. */
4510 if (!cmdmod.keepjumps)
4511 curbuf->b_last_insert = curwin->w_cursor;
4512
4513 /*
4514 * The cursor should end up on the last inserted character.
Bram Moolenaar488c6512005-08-11 20:09:58 +00004515 * Don't do it for CTRL-O, unless past the end of the line.
Bram Moolenaar071d4272004-06-13 20:20:40 +00004516 */
Bram Moolenaar488c6512005-08-11 20:09:58 +00004517 if (!nomove
4518 && (curwin->w_cursor.col != 0
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01004519 || curwin->w_cursor.coladd > 0)
Bram Moolenaar488c6512005-08-11 20:09:58 +00004520 && (restart_edit == NUL
Bram Moolenaarf7ff6e82014-03-23 15:13:05 +01004521 || (gchar_cursor() == NUL && !VIsual_active))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004522#ifdef FEAT_RIGHTLEFT
4523 && !revins_on
4524#endif
4525 )
4526 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004527 if (curwin->w_cursor.coladd > 0 || ve_flags == VE_ALL)
4528 {
4529 oneleft();
4530 if (restart_edit != NUL)
4531 ++curwin->w_cursor.coladd;
4532 }
4533 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00004534 {
4535 --curwin->w_cursor.col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004536 /* Correct cursor for multi-byte character. */
4537 if (has_mbyte)
4538 mb_adjust_cursor();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004539 }
4540 }
4541
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01004542#ifdef HAVE_INPUT_METHOD
Bram Moolenaar071d4272004-06-13 20:20:40 +00004543 /* Disable IM to allow typing English directly for Normal mode commands.
4544 * When ":lmap" is enabled don't change 'iminsert' (IM can be enabled as
4545 * well). */
4546 if (!(State & LANGMAP))
4547 im_save_status(&curbuf->b_p_iminsert);
4548 im_set_active(FALSE);
4549#endif
4550
4551 State = NORMAL;
4552 /* need to position cursor again (e.g. when on a TAB ) */
4553 changed_cline_bef_curs();
4554
4555#ifdef FEAT_MOUSE
4556 setmouse();
4557#endif
4558#ifdef CURSOR_SHAPE
4559 ui_cursor_shape(); /* may show different cursor shape */
4560#endif
Bram Moolenaar48c9f3b2017-01-24 19:08:15 +01004561 if (!p_ek)
4562 /* Re-enable bracketed paste mode. */
4563 out_str(T_BE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004564
Bram Moolenaarad3ec762019-04-21 00:00:13 +02004565 // When recording or for CTRL-O, need to display the new mode.
4566 // Otherwise remove the mode message.
Bram Moolenaar0b6d9112018-05-22 20:35:17 +02004567 if (reg_recording != 0 || restart_edit != NUL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004568 showmode();
Bram Moolenaarabc7c7f2019-04-20 15:10:13 +02004569 else if (p_smd && (got_int || !skip_showmode()))
Bram Moolenaar32526b32019-01-19 17:43:09 +01004570 msg("");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004571
4572 return TRUE; /* exit Insert mode */
4573}
4574
4575#ifdef FEAT_RIGHTLEFT
4576/*
4577 * Toggle language: hkmap and revins_on.
4578 * Move to end of reverse inserted text.
4579 */
4580 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +01004581ins_ctrl_(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004582{
4583 if (revins_on && revins_chars && revins_scol >= 0)
4584 {
4585 while (gchar_cursor() != NUL && revins_chars--)
4586 ++curwin->w_cursor.col;
4587 }
4588 p_ri = !p_ri;
4589 revins_on = (State == INSERT && p_ri);
4590 if (revins_on)
4591 {
4592 revins_scol = curwin->w_cursor.col;
4593 revins_legal++;
4594 revins_chars = 0;
4595 undisplay_dollar();
4596 }
4597 else
4598 revins_scol = -1;
Bram Moolenaar14184a32019-02-16 15:10:30 +01004599 p_hkmap = curwin->w_p_rl ^ p_ri; // be consistent!
Bram Moolenaar071d4272004-06-13 20:20:40 +00004600 showmode();
4601}
4602#endif
4603
Bram Moolenaar071d4272004-06-13 20:20:40 +00004604/*
4605 * If 'keymodel' contains "startsel", may start selection.
4606 * Returns TRUE when a CTRL-O and other keys stuffed.
4607 */
4608 static int
Bram Moolenaar7454a062016-01-30 15:14:10 +01004609ins_start_select(int c)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004610{
4611 if (km_startsel)
4612 switch (c)
4613 {
4614 case K_KHOME:
Bram Moolenaar071d4272004-06-13 20:20:40 +00004615 case K_KEND:
Bram Moolenaar071d4272004-06-13 20:20:40 +00004616 case K_PAGEUP:
4617 case K_KPAGEUP:
4618 case K_PAGEDOWN:
4619 case K_KPAGEDOWN:
Bram Moolenaard0573012017-10-28 21:11:06 +02004620# ifdef MACOS_X
Bram Moolenaar071d4272004-06-13 20:20:40 +00004621 case K_LEFT:
4622 case K_RIGHT:
4623 case K_UP:
4624 case K_DOWN:
4625 case K_END:
4626 case K_HOME:
4627# endif
4628 if (!(mod_mask & MOD_MASK_SHIFT))
4629 break;
4630 /* FALLTHROUGH */
4631 case K_S_LEFT:
4632 case K_S_RIGHT:
4633 case K_S_UP:
4634 case K_S_DOWN:
4635 case K_S_END:
4636 case K_S_HOME:
4637 /* Start selection right away, the cursor can move with
4638 * CTRL-O when beyond the end of the line. */
4639 start_selection();
4640
4641 /* Execute the key in (insert) Select mode. */
4642 stuffcharReadbuff(Ctrl_O);
4643 if (mod_mask)
4644 {
4645 char_u buf[4];
4646
4647 buf[0] = K_SPECIAL;
4648 buf[1] = KS_MODIFIER;
4649 buf[2] = mod_mask;
4650 buf[3] = NUL;
4651 stuffReadbuff(buf);
4652 }
4653 stuffcharReadbuff(c);
4654 return TRUE;
4655 }
4656 return FALSE;
4657}
Bram Moolenaar071d4272004-06-13 20:20:40 +00004658
4659/*
Bram Moolenaar84a05ac2013-05-06 04:24:17 +02004660 * <Insert> key in Insert mode: toggle insert/replace mode.
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004661 */
4662 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +01004663ins_insert(int replaceState)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004664{
Bram Moolenaar14184a32019-02-16 15:10:30 +01004665#ifdef FEAT_EVAL
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004666 set_vim_var_string(VV_INSERTMODE,
Bram Moolenaar1f0bfe52018-07-29 16:09:22 +02004667 (char_u *)((State & REPLACE_FLAG) ? "i"
4668 : replaceState == VREPLACE ? "v"
4669 : "r"), 1);
Bram Moolenaar14184a32019-02-16 15:10:30 +01004670#endif
Bram Moolenaar9fa95062018-08-08 22:08:32 +02004671 ins_apply_autocmds(EVENT_INSERTCHANGE);
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004672 if (State & REPLACE_FLAG)
4673 State = INSERT | (State & LANGMAP);
4674 else
4675 State = replaceState | (State & LANGMAP);
4676 AppendCharToRedobuff(K_INS);
4677 showmode();
4678#ifdef CURSOR_SHAPE
4679 ui_cursor_shape(); /* may show different cursor shape */
4680#endif
4681}
4682
4683/*
4684 * Pressed CTRL-O in Insert mode.
4685 */
4686 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +01004687ins_ctrl_o(void)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004688{
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004689 if (State & VREPLACE_FLAG)
4690 restart_edit = 'V';
4691 else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004692 if (State & REPLACE_FLAG)
4693 restart_edit = 'R';
4694 else
4695 restart_edit = 'I';
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004696 if (virtual_active())
4697 ins_at_eol = FALSE; /* cursor always keeps its column */
4698 else
Bram Moolenaar4be06f92005-07-29 22:36:03 +00004699 ins_at_eol = (gchar_cursor() == NUL);
4700}
4701
4702/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00004703 * If the cursor is on an indent, ^T/^D insert/delete one
4704 * shiftwidth. Otherwise ^T/^D behave like a "<<" or ">>".
Bram Moolenaar5b3e4602009-02-04 10:20:58 +00004705 * Always round the indent to 'shiftwidth', this is compatible
Bram Moolenaar071d4272004-06-13 20:20:40 +00004706 * with vi. But vi only supports ^T and ^D after an
4707 * autoindent, we support it everywhere.
4708 */
4709 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +01004710ins_shift(int c, int lastc)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004711{
4712 if (stop_arrow() == FAIL)
4713 return;
4714 AppendCharToRedobuff(c);
4715
4716 /*
4717 * 0^D and ^^D: remove all indent.
4718 */
Bram Moolenaar0cbac5b2007-07-29 13:03:35 +00004719 if (c == Ctrl_D && (lastc == '0' || lastc == '^')
4720 && curwin->w_cursor.col > 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004721 {
4722 --curwin->w_cursor.col;
4723 (void)del_char(FALSE); /* delete the '^' or '0' */
4724 /* In Replace mode, restore the characters that '^' or '0' replaced. */
4725 if (State & REPLACE_FLAG)
4726 replace_pop_ins();
4727 if (lastc == '^')
4728 old_indent = get_indent(); /* remember curr. indent */
Bram Moolenaar21b17e72008-01-16 19:03:13 +00004729 change_indent(INDENT_SET, 0, TRUE, 0, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004730 }
4731 else
Bram Moolenaar21b17e72008-01-16 19:03:13 +00004732 change_indent(c == Ctrl_D ? INDENT_DEC : INDENT_INC, 0, TRUE, 0, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004733
4734 if (did_ai && *skipwhite(ml_get_curline()) != NUL)
4735 did_ai = FALSE;
4736#ifdef FEAT_SMARTINDENT
4737 did_si = FALSE;
4738 can_si = FALSE;
4739 can_si_back = FALSE;
4740#endif
4741#ifdef FEAT_CINDENT
4742 can_cindent = FALSE; /* no cindenting after ^D or ^T */
4743#endif
4744}
4745
4746 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +01004747ins_del(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004748{
4749 int temp;
4750
4751 if (stop_arrow() == FAIL)
4752 return;
4753 if (gchar_cursor() == NUL) /* delete newline */
4754 {
4755 temp = curwin->w_cursor.col;
4756 if (!can_bs(BS_EOL) /* only if "eol" included */
Bram Moolenaard69bd9a2014-04-29 12:15:40 +02004757 || do_join(2, FALSE, TRUE, FALSE, FALSE) == FAIL)
Bram Moolenaar165bc692015-07-21 17:53:25 +02004758 vim_beep(BO_BS);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004759 else
Bram Moolenaar63e82db2018-03-06 12:10:48 +01004760 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004761 curwin->w_cursor.col = temp;
Bram Moolenaar63e82db2018-03-06 12:10:48 +01004762 /* Adjust orig_line_count in case more lines have been deleted than
4763 * have been added. That makes sure, that open_line() later
4764 * can access all buffer lines correctly */
4765 if (State & VREPLACE_FLAG &&
4766 orig_line_count > curbuf->b_ml.ml_line_count)
4767 orig_line_count = curbuf->b_ml.ml_line_count;
Bram Moolenaar63e82db2018-03-06 12:10:48 +01004768 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004769 }
Bram Moolenaar165bc692015-07-21 17:53:25 +02004770 else if (del_char(FALSE) == FAIL) /* delete char under cursor */
4771 vim_beep(BO_BS);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004772 did_ai = FALSE;
4773#ifdef FEAT_SMARTINDENT
4774 did_si = FALSE;
4775 can_si = FALSE;
4776 can_si_back = FALSE;
4777#endif
4778 AppendCharToRedobuff(K_DEL);
4779}
4780
Bram Moolenaarf5dcf7c2007-12-09 19:26:44 +00004781/*
4782 * Delete one character for ins_bs().
4783 */
4784 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +01004785ins_bs_one(colnr_T *vcolp)
Bram Moolenaarf5dcf7c2007-12-09 19:26:44 +00004786{
4787 dec_cursor();
4788 getvcol(curwin, &curwin->w_cursor, vcolp, NULL, NULL);
4789 if (State & REPLACE_FLAG)
4790 {
4791 /* Don't delete characters before the insert point when in
4792 * Replace mode */
4793 if (curwin->w_cursor.lnum != Insstart.lnum
4794 || curwin->w_cursor.col >= Insstart.col)
Bram Moolenaar0f6c9482009-01-13 11:29:48 +00004795 replace_do_bs(-1);
Bram Moolenaarf5dcf7c2007-12-09 19:26:44 +00004796 }
4797 else
4798 (void)del_char(FALSE);
4799}
4800
Bram Moolenaar071d4272004-06-13 20:20:40 +00004801/*
4802 * Handle Backspace, delete-word and delete-line in Insert mode.
4803 * Return TRUE when backspace was actually used.
4804 */
4805 static int
Bram Moolenaar7454a062016-01-30 15:14:10 +01004806ins_bs(
4807 int c,
4808 int mode,
4809 int *inserted_space_p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004810{
4811 linenr_T lnum;
4812 int cc;
4813 int temp = 0; /* init for GCC */
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00004814 colnr_T save_col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004815 colnr_T mincol;
4816 int did_backspace = FALSE;
4817 int in_indent;
4818 int oldState;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00004819 int cpc[MAX_MCO]; /* composing characters */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004820
4821 /*
4822 * can't delete anything in an empty file
4823 * can't backup past first character in buffer
4824 * can't backup past starting point unless 'backspace' > 1
4825 * can backup to a previous line if 'backspace' == 0
4826 */
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01004827 if ( BUFEMPTY()
Bram Moolenaar071d4272004-06-13 20:20:40 +00004828 || (
4829#ifdef FEAT_RIGHTLEFT
4830 !revins_on &&
4831#endif
4832 ((curwin->w_cursor.lnum == 1 && curwin->w_cursor.col == 0)
4833 || (!can_bs(BS_START)
4834 && (arrow_used
Bram Moolenaar3d1956b2014-04-29 14:44:35 +02004835 || (curwin->w_cursor.lnum == Insstart_orig.lnum
4836 && curwin->w_cursor.col <= Insstart_orig.col)))
Bram Moolenaar071d4272004-06-13 20:20:40 +00004837 || (!can_bs(BS_INDENT) && !arrow_used && ai_col > 0
4838 && curwin->w_cursor.col <= ai_col)
4839 || (!can_bs(BS_EOL) && curwin->w_cursor.col == 0))))
4840 {
Bram Moolenaar165bc692015-07-21 17:53:25 +02004841 vim_beep(BO_BS);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004842 return FALSE;
4843 }
4844
4845 if (stop_arrow() == FAIL)
4846 return FALSE;
4847 in_indent = inindent(0);
4848#ifdef FEAT_CINDENT
4849 if (in_indent)
4850 can_cindent = FALSE;
4851#endif
4852#ifdef FEAT_COMMENTS
4853 end_comment_pending = NUL; /* After BS, don't auto-end comment */
4854#endif
4855#ifdef FEAT_RIGHTLEFT
4856 if (revins_on) /* put cursor after last inserted char */
4857 inc_cursor();
4858#endif
4859
Bram Moolenaar071d4272004-06-13 20:20:40 +00004860 /* Virtualedit:
4861 * BACKSPACE_CHAR eats a virtual space
4862 * BACKSPACE_WORD eats all coladd
4863 * BACKSPACE_LINE eats all coladd and keeps going
4864 */
4865 if (curwin->w_cursor.coladd > 0)
4866 {
4867 if (mode == BACKSPACE_CHAR)
4868 {
4869 --curwin->w_cursor.coladd;
4870 return TRUE;
4871 }
4872 if (mode == BACKSPACE_WORD)
4873 {
4874 curwin->w_cursor.coladd = 0;
4875 return TRUE;
4876 }
4877 curwin->w_cursor.coladd = 0;
4878 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004879
4880 /*
Bram Moolenaar878c2632017-04-01 15:15:52 +02004881 * Delete newline!
Bram Moolenaar071d4272004-06-13 20:20:40 +00004882 */
4883 if (curwin->w_cursor.col == 0)
4884 {
Bram Moolenaarc3bbad02015-02-17 17:50:26 +01004885 lnum = Insstart.lnum;
Bram Moolenaar3d1956b2014-04-29 14:44:35 +02004886 if (curwin->w_cursor.lnum == lnum
Bram Moolenaar071d4272004-06-13 20:20:40 +00004887#ifdef FEAT_RIGHTLEFT
4888 || revins_on
4889#endif
4890 )
4891 {
4892 if (u_save((linenr_T)(curwin->w_cursor.lnum - 2),
4893 (linenr_T)(curwin->w_cursor.lnum + 1)) == FAIL)
4894 return FALSE;
Bram Moolenaarc3bbad02015-02-17 17:50:26 +01004895 --Insstart.lnum;
Bram Moolenaar04000562017-04-03 21:35:42 +02004896 Insstart.col = (colnr_T)STRLEN(ml_get(Insstart.lnum));
Bram Moolenaar071d4272004-06-13 20:20:40 +00004897 }
4898 /*
4899 * In replace mode:
4900 * cc < 0: NL was inserted, delete it
4901 * cc >= 0: NL was replaced, put original characters back
4902 */
4903 cc = -1;
4904 if (State & REPLACE_FLAG)
4905 cc = replace_pop(); /* returns -1 if NL was inserted */
4906 /*
4907 * In replace mode, in the line we started replacing, we only move the
4908 * cursor.
4909 */
4910 if ((State & REPLACE_FLAG) && curwin->w_cursor.lnum <= lnum)
4911 {
4912 dec_cursor();
4913 }
4914 else
4915 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00004916 if (!(State & VREPLACE_FLAG)
4917 || curwin->w_cursor.lnum > orig_line_count)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004918 {
4919 temp = gchar_cursor(); /* remember current char */
4920 --curwin->w_cursor.lnum;
Bram Moolenaarc930a3c2005-05-20 21:27:20 +00004921
4922 /* When "aw" is in 'formatoptions' we must delete the space at
4923 * the end of the line, otherwise the line will be broken
4924 * again when auto-formatting. */
4925 if (has_format_option(FO_AUTO)
4926 && has_format_option(FO_WHITE_PAR))
4927 {
4928 char_u *ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum,
4929 TRUE);
4930 int len;
4931
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00004932 len = (int)STRLEN(ptr);
Bram Moolenaarc930a3c2005-05-20 21:27:20 +00004933 if (len > 0 && ptr[len - 1] == ' ')
4934 ptr[len - 1] = NUL;
4935 }
4936
Bram Moolenaard69bd9a2014-04-29 12:15:40 +02004937 (void)do_join(2, FALSE, FALSE, FALSE, FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004938 if (temp == NUL && gchar_cursor() != NUL)
4939 inc_cursor();
4940 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00004941 else
4942 dec_cursor();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004943
4944 /*
4945 * In REPLACE mode we have to put back the text that was replaced
4946 * by the NL. On the replace stack is first a NUL-terminated
4947 * sequence of characters that were deleted and then the
4948 * characters that NL replaced.
4949 */
4950 if (State & REPLACE_FLAG)
4951 {
4952 /*
4953 * Do the next ins_char() in NORMAL state, to
4954 * prevent ins_char() from replacing characters and
4955 * avoiding showmatch().
4956 */
4957 oldState = State;
4958 State = NORMAL;
4959 /*
4960 * restore characters (blanks) deleted after cursor
4961 */
4962 while (cc > 0)
4963 {
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00004964 save_col = curwin->w_cursor.col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004965 mb_replace_pop_ins(cc);
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00004966 curwin->w_cursor.col = save_col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004967 cc = replace_pop();
4968 }
4969 /* restore the characters that NL replaced */
4970 replace_pop_ins();
4971 State = oldState;
4972 }
4973 }
4974 did_ai = FALSE;
4975 }
4976 else
4977 {
4978 /*
4979 * Delete character(s) before the cursor.
4980 */
4981#ifdef FEAT_RIGHTLEFT
4982 if (revins_on) /* put cursor on last inserted char */
4983 dec_cursor();
4984#endif
4985 mincol = 0;
4986 /* keep indent */
Bram Moolenaar9248e6e2007-03-08 12:10:13 +00004987 if (mode == BACKSPACE_LINE
4988 && (curbuf->b_p_ai
4989#ifdef FEAT_CINDENT
Bram Moolenaar97b98102009-11-17 16:41:01 +00004990 || cindent_on()
Bram Moolenaar9248e6e2007-03-08 12:10:13 +00004991#endif
4992 )
Bram Moolenaar071d4272004-06-13 20:20:40 +00004993#ifdef FEAT_RIGHTLEFT
4994 && !revins_on
4995#endif
4996 )
4997 {
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00004998 save_col = curwin->w_cursor.col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004999 beginline(BL_WHITE);
Bram Moolenaar76675562009-11-11 12:22:32 +00005000 if (curwin->w_cursor.col < save_col)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005001 mincol = curwin->w_cursor.col;
Bram Moolenaar5fd0ca72009-05-13 16:56:33 +00005002 curwin->w_cursor.col = save_col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005003 }
5004
5005 /*
5006 * Handle deleting one 'shiftwidth' or 'softtabstop'.
5007 */
5008 if ( mode == BACKSPACE_CHAR
5009 && ((p_sta && in_indent)
Bram Moolenaar04958cb2018-06-23 19:23:02 +02005010 || ((get_sts_value() != 0
5011#ifdef FEAT_VARTABS
5012 || tabstop_count(curbuf->b_p_vsts_array)
5013#endif
5014 )
Bram Moolenaar7b88a0e2008-01-09 09:14:13 +00005015 && curwin->w_cursor.col > 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00005016 && (*(ml_get_cursor() - 1) == TAB
5017 || (*(ml_get_cursor() - 1) == ' '
5018 && (!*inserted_space_p
5019 || arrow_used))))))
5020 {
5021 int ts;
5022 colnr_T vcol;
5023 colnr_T want_vcol;
Bram Moolenaarf5dcf7c2007-12-09 19:26:44 +00005024 colnr_T start_vcol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005025
5026 *inserted_space_p = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005027 /* Compute the virtual column where we want to be. Since
5028 * 'showbreak' may get in the way, need to get the last column of
5029 * the previous character. */
5030 getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL);
Bram Moolenaarf5dcf7c2007-12-09 19:26:44 +00005031 start_vcol = vcol;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005032 dec_cursor();
5033 getvcol(curwin, &curwin->w_cursor, NULL, NULL, &want_vcol);
5034 inc_cursor();
Bram Moolenaar04958cb2018-06-23 19:23:02 +02005035#ifdef FEAT_VARTABS
5036 if (p_sta && in_indent)
Bram Moolenaarc9fe5ab2018-07-05 22:27:08 +02005037 {
5038 ts = (int)get_sw_value(curbuf);
5039 want_vcol = (want_vcol / ts) * ts;
5040 }
Bram Moolenaar04958cb2018-06-23 19:23:02 +02005041 else
Bram Moolenaar33d5ab32018-07-02 20:51:24 +02005042 want_vcol = tabstop_start(want_vcol, get_sts_value(),
Bram Moolenaar04958cb2018-06-23 19:23:02 +02005043 curbuf->b_p_vsts_array);
5044#else
Bram Moolenaarc9fe5ab2018-07-05 22:27:08 +02005045 if (p_sta && in_indent)
5046 ts = (int)get_sw_value(curbuf);
5047 else
5048 ts = (int)get_sts_value();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005049 want_vcol = (want_vcol / ts) * ts;
Bram Moolenaar04958cb2018-06-23 19:23:02 +02005050#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005051
5052 /* delete characters until we are at or before want_vcol */
5053 while (vcol > want_vcol
Bram Moolenaar1c465442017-03-12 20:10:05 +01005054 && (cc = *(ml_get_cursor() - 1), VIM_ISWHITE(cc)))
Bram Moolenaarf5dcf7c2007-12-09 19:26:44 +00005055 ins_bs_one(&vcol);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005056
5057 /* insert extra spaces until we are at want_vcol */
5058 while (vcol < want_vcol)
5059 {
5060 /* Remember the first char we inserted */
Bram Moolenaar3d1956b2014-04-29 14:44:35 +02005061 if (curwin->w_cursor.lnum == Insstart_orig.lnum
5062 && curwin->w_cursor.col < Insstart_orig.col)
5063 Insstart_orig.col = curwin->w_cursor.col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005064
Bram Moolenaar071d4272004-06-13 20:20:40 +00005065 if (State & VREPLACE_FLAG)
5066 ins_char(' ');
5067 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005068 {
5069 ins_str((char_u *)" ");
Bram Moolenaarf5dcf7c2007-12-09 19:26:44 +00005070 if ((State & REPLACE_FLAG))
5071 replace_push(NUL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005072 }
5073 getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL);
5074 }
Bram Moolenaarf5dcf7c2007-12-09 19:26:44 +00005075
5076 /* If we are now back where we started delete one character. Can
5077 * happen when using 'sts' and 'linebreak'. */
5078 if (vcol >= start_vcol)
5079 ins_bs_one(&vcol);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005080 }
5081
5082 /*
5083 * Delete upto starting point, start of line or previous word.
5084 */
Bram Moolenaar310f2d52015-03-24 17:49:51 +01005085 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005086 {
Bram Moolenaar310f2d52015-03-24 17:49:51 +01005087 int cclass = 0, prev_cclass = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005088
Bram Moolenaar310f2d52015-03-24 17:49:51 +01005089 if (has_mbyte)
5090 cclass = mb_get_class(ml_get_cursor());
Bram Moolenaar310f2d52015-03-24 17:49:51 +01005091 do
5092 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005093#ifdef FEAT_RIGHTLEFT
Bram Moolenaar310f2d52015-03-24 17:49:51 +01005094 if (!revins_on) /* put cursor on char to be deleted */
5095#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005096 dec_cursor();
Bram Moolenaar310f2d52015-03-24 17:49:51 +01005097
5098 cc = gchar_cursor();
Bram Moolenaar310f2d52015-03-24 17:49:51 +01005099 /* look multi-byte character class */
5100 if (has_mbyte)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005101 {
Bram Moolenaar310f2d52015-03-24 17:49:51 +01005102 prev_cclass = cclass;
5103 cclass = mb_get_class(ml_get_cursor());
Bram Moolenaar071d4272004-06-13 20:20:40 +00005104 }
Bram Moolenaar310f2d52015-03-24 17:49:51 +01005105
5106 /* start of word? */
5107 if (mode == BACKSPACE_WORD && !vim_isspace(cc))
5108 {
5109 mode = BACKSPACE_WORD_NOT_SPACE;
5110 temp = vim_iswordc(cc);
5111 }
5112 /* end of word? */
5113 else if (mode == BACKSPACE_WORD_NOT_SPACE
5114 && ((vim_isspace(cc) || vim_iswordc(cc) != temp)
Bram Moolenaar13505972019-01-24 15:04:48 +01005115 || prev_cclass != cclass))
Bram Moolenaar310f2d52015-03-24 17:49:51 +01005116 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005117#ifdef FEAT_RIGHTLEFT
Bram Moolenaar310f2d52015-03-24 17:49:51 +01005118 if (!revins_on)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005119#endif
Bram Moolenaar310f2d52015-03-24 17:49:51 +01005120 inc_cursor();
5121#ifdef FEAT_RIGHTLEFT
5122 else if (State & REPLACE_FLAG)
5123 dec_cursor();
5124#endif
5125 break;
5126 }
5127 if (State & REPLACE_FLAG)
5128 replace_do_bs(-1);
5129 else
5130 {
Bram Moolenaar310f2d52015-03-24 17:49:51 +01005131 if (enc_utf8 && p_deco)
5132 (void)utfc_ptr2char(ml_get_cursor(), cpc);
Bram Moolenaar310f2d52015-03-24 17:49:51 +01005133 (void)del_char(FALSE);
Bram Moolenaar310f2d52015-03-24 17:49:51 +01005134 /*
5135 * If there are combining characters and 'delcombine' is set
5136 * move the cursor back. Don't back up before the base
5137 * character.
5138 */
5139 if (enc_utf8 && p_deco && cpc[0] != NUL)
5140 inc_cursor();
Bram Moolenaar310f2d52015-03-24 17:49:51 +01005141#ifdef FEAT_RIGHTLEFT
5142 if (revins_chars)
5143 {
5144 revins_chars--;
5145 revins_legal++;
5146 }
5147 if (revins_on && gchar_cursor() == NUL)
5148 break;
5149#endif
5150 }
5151 /* Just a single backspace?: */
5152 if (mode == BACKSPACE_CHAR)
5153 break;
5154 } while (
5155#ifdef FEAT_RIGHTLEFT
5156 revins_on ||
5157#endif
5158 (curwin->w_cursor.col > mincol
5159 && (curwin->w_cursor.lnum != Insstart_orig.lnum
5160 || curwin->w_cursor.col != Insstart_orig.col)));
5161 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005162 did_backspace = TRUE;
5163 }
5164#ifdef FEAT_SMARTINDENT
5165 did_si = FALSE;
5166 can_si = FALSE;
5167 can_si_back = FALSE;
5168#endif
5169 if (curwin->w_cursor.col <= 1)
5170 did_ai = FALSE;
5171 /*
5172 * It's a little strange to put backspaces into the redo
5173 * buffer, but it makes auto-indent a lot easier to deal
5174 * with.
5175 */
5176 AppendCharToRedobuff(c);
5177
5178 /* If deleted before the insertion point, adjust it */
Bram Moolenaar3d1956b2014-04-29 14:44:35 +02005179 if (curwin->w_cursor.lnum == Insstart_orig.lnum
Bram Moolenaar891e1fd2018-06-06 18:02:39 +02005180 && curwin->w_cursor.col < Insstart_orig.col)
Bram Moolenaar3d1956b2014-04-29 14:44:35 +02005181 Insstart_orig.col = curwin->w_cursor.col;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005182
5183 /* vi behaviour: the cursor moves backward but the character that
5184 * was there remains visible
5185 * Vim behaviour: the cursor moves backward and the character that
5186 * was there is erased from the screen.
5187 * We can emulate the vi behaviour by pretending there is a dollar
5188 * displayed even when there isn't.
5189 * --pkv Sun Jan 19 01:56:40 EST 2003 */
Bram Moolenaar76b9b362012-02-04 23:35:00 +01005190 if (vim_strchr(p_cpo, CPO_BACKSPACE) != NULL && dollar_vcol == -1)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005191 dollar_vcol = curwin->w_virtcol;
5192
Bram Moolenaarce3be472008-01-14 19:12:28 +00005193#ifdef FEAT_FOLDING
5194 /* When deleting a char the cursor line must never be in a closed fold.
5195 * E.g., when 'foldmethod' is indent and deleting the first non-white
5196 * char before a Tab. */
5197 if (did_backspace)
5198 foldOpenCursor();
5199#endif
5200
Bram Moolenaar071d4272004-06-13 20:20:40 +00005201 return did_backspace;
5202}
5203
5204#ifdef FEAT_MOUSE
5205 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +01005206ins_mouse(int c)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005207{
5208 pos_T tpos;
Bram Moolenaareb3593b2006-04-22 22:33:57 +00005209 win_T *old_curwin = curwin;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005210
5211# ifdef FEAT_GUI
5212 /* When GUI is active, also move/paste when 'mouse' is empty */
5213 if (!gui.in_use)
5214# endif
5215 if (!mouse_has(MOUSE_INSERT))
5216 return;
5217
5218 undisplay_dollar();
5219 tpos = curwin->w_cursor;
5220 if (do_mouse(NULL, c, BACKWARD, 1L, 0))
5221 {
Bram Moolenaareb3593b2006-04-22 22:33:57 +00005222 win_T *new_curwin = curwin;
5223
5224 if (curwin != old_curwin && win_valid(old_curwin))
5225 {
5226 /* Mouse took us to another window. We need to go back to the
5227 * previous one to stop insert there properly. */
5228 curwin = old_curwin;
5229 curbuf = curwin->w_buffer;
Bram Moolenaar891e1fd2018-06-06 18:02:39 +02005230#ifdef FEAT_JOB_CHANNEL
5231 if (bt_prompt(curbuf))
5232 // Restart Insert mode when re-entering the prompt buffer.
5233 curbuf->b_prompt_insert = 'A';
5234#endif
Bram Moolenaareb3593b2006-04-22 22:33:57 +00005235 }
Bram Moolenaareb3593b2006-04-22 22:33:57 +00005236 start_arrow(curwin == old_curwin ? &tpos : NULL);
Bram Moolenaareb3593b2006-04-22 22:33:57 +00005237 if (curwin != new_curwin && win_valid(new_curwin))
5238 {
5239 curwin = new_curwin;
5240 curbuf = curwin->w_buffer;
5241 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005242# ifdef FEAT_CINDENT
5243 can_cindent = TRUE;
5244# endif
5245 }
5246
Bram Moolenaar071d4272004-06-13 20:20:40 +00005247 /* redraw status lines (in case another window became active) */
5248 redraw_statuslines();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005249}
5250
5251 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +01005252ins_mousescroll(int dir)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005253{
5254 pos_T tpos;
Bram Moolenaar989a70c2017-08-16 22:46:01 +02005255 win_T *old_curwin = curwin, *wp;
Bram Moolenaar9b25ffb2007-11-06 21:27:31 +00005256# ifdef FEAT_INS_EXPAND
5257 int did_scroll = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005258# endif
5259
5260 tpos = curwin->w_cursor;
5261
Bram Moolenaar40cf4b42013-02-26 13:30:32 +01005262 if (mouse_row >= 0 && mouse_col >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005263 {
5264 int row, col;
5265
5266 row = mouse_row;
5267 col = mouse_col;
5268
5269 /* find the window at the pointer coordinates */
Bram Moolenaar451d4b52019-06-12 20:22:27 +02005270 wp = mouse_find_win(&row, &col, FAIL_POPUP);
Bram Moolenaar989a70c2017-08-16 22:46:01 +02005271 if (wp == NULL)
5272 return;
5273 curwin = wp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005274 curbuf = curwin->w_buffer;
5275 }
5276 if (curwin == old_curwin)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005277 undisplay_dollar();
5278
Bram Moolenaar9b25ffb2007-11-06 21:27:31 +00005279# ifdef FEAT_INS_EXPAND
5280 /* Don't scroll the window in which completion is being done. */
Bram Moolenaar4033c552017-09-16 20:54:51 +02005281 if (!pum_visible() || curwin != old_curwin)
Bram Moolenaar9b25ffb2007-11-06 21:27:31 +00005282# endif
5283 {
Bram Moolenaar8d9b40e2010-07-25 15:49:07 +02005284 if (dir == MSCR_DOWN || dir == MSCR_UP)
5285 {
5286 if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
5287 scroll_redraw(dir,
5288 (long)(curwin->w_botline - curwin->w_topline));
5289 else
5290 scroll_redraw(dir, 3L);
5291 }
5292#ifdef FEAT_GUI
Bram Moolenaar9b25ffb2007-11-06 21:27:31 +00005293 else
Bram Moolenaar8d9b40e2010-07-25 15:49:07 +02005294 {
5295 int val, step = 6;
5296
5297 if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
Bram Moolenaar02631462017-09-22 15:20:32 +02005298 step = curwin->w_width;
Bram Moolenaar8d9b40e2010-07-25 15:49:07 +02005299 val = curwin->w_leftcol + (dir == MSCR_RIGHT ? -step : step);
5300 if (val < 0)
5301 val = 0;
5302 gui_do_horiz_scroll(val, TRUE);
5303 }
5304#endif
Bram Moolenaar9b25ffb2007-11-06 21:27:31 +00005305# ifdef FEAT_INS_EXPAND
5306 did_scroll = TRUE;
5307# endif
5308 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005309
Bram Moolenaar071d4272004-06-13 20:20:40 +00005310 curwin->w_redr_status = TRUE;
5311
5312 curwin = old_curwin;
5313 curbuf = curwin->w_buffer;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005314
Bram Moolenaar9b25ffb2007-11-06 21:27:31 +00005315# ifdef FEAT_INS_EXPAND
5316 /* The popup menu may overlay the window, need to redraw it.
5317 * TODO: Would be more efficient to only redraw the windows that are
5318 * overlapped by the popup menu. */
5319 if (pum_visible() && did_scroll)
5320 {
5321 redraw_all_later(NOT_VALID);
5322 ins_compl_show_pum();
5323 }
5324# endif
5325
Bram Moolenaarb5aedf32017-03-12 18:23:53 +01005326 if (!EQUAL_POS(curwin->w_cursor, tpos))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005327 {
5328 start_arrow(&tpos);
5329# ifdef FEAT_CINDENT
5330 can_cindent = TRUE;
5331# endif
5332 }
5333}
5334#endif
5335
Bram Moolenaarec2da362017-01-21 20:04:22 +01005336/*
5337 * Handle receiving P_PS: start paste mode. Inserts the following text up to
5338 * P_PE literally.
5339 * When "drop" is TRUE then consume the text and drop it.
5340 */
5341 int
5342bracketed_paste(paste_mode_T mode, int drop, garray_T *gap)
5343{
5344 int c;
5345 char_u buf[NUMBUFLEN + MB_MAXBYTES];
5346 int idx = 0;
5347 char_u *end = find_termcode((char_u *)"PE");
5348 int ret_char = -1;
5349 int save_allow_keys = allow_keys;
Bram Moolenaar9e817c82017-01-25 21:36:17 +01005350 int save_paste = p_paste;
Bram Moolenaarec2da362017-01-21 20:04:22 +01005351
5352 /* If the end code is too long we can't detect it, read everything. */
5353 if (STRLEN(end) >= NUMBUFLEN)
5354 end = NULL;
5355 ++no_mapping;
5356 allow_keys = 0;
Bram Moolenaarfdd71552018-07-28 23:12:05 +02005357 if (!p_paste)
5358 // Also have the side effects of setting 'paste' to make it work much
5359 // faster.
5360 set_option_value((char_u *)"paste", TRUE, NULL, 0);
Bram Moolenaar9e817c82017-01-25 21:36:17 +01005361
Bram Moolenaarec2da362017-01-21 20:04:22 +01005362 for (;;)
5363 {
Bram Moolenaarfdd71552018-07-28 23:12:05 +02005364 // When the end is not defined read everything there is.
Bram Moolenaarec2da362017-01-21 20:04:22 +01005365 if (end == NULL && vpeekc() == NUL)
5366 break;
Bram Moolenaarfdd71552018-07-28 23:12:05 +02005367 do
Bram Moolenaarfdd71552018-07-28 23:12:05 +02005368 c = vgetc();
Bram Moolenaarabab0b02019-03-30 18:47:01 +01005369 while (c == K_IGNORE || c == K_VER_SCROLLBAR || c == K_HOR_SCROLLBAR);
Bram Moolenaarfdd71552018-07-28 23:12:05 +02005370 if (c == NUL || got_int)
5371 // When CTRL-C was encountered the typeahead will be flushed and we
5372 // won't get the end sequence.
5373 break;
5374
Bram Moolenaarec2da362017-01-21 20:04:22 +01005375 if (has_mbyte)
5376 idx += (*mb_char2bytes)(c, buf + idx);
5377 else
Bram Moolenaarec2da362017-01-21 20:04:22 +01005378 buf[idx++] = c;
5379 buf[idx] = NUL;
Bram Moolenaar866c6882017-04-07 14:02:01 +02005380 if (end != NULL && STRNCMP(buf, end, idx) == 0)
Bram Moolenaarec2da362017-01-21 20:04:22 +01005381 {
5382 if (end[idx] == NUL)
5383 break; /* Found the end of paste code. */
5384 continue;
5385 }
5386 if (!drop)
5387 {
5388 switch (mode)
5389 {
5390 case PASTE_CMDLINE:
5391 put_on_cmdline(buf, idx, TRUE);
5392 break;
5393
5394 case PASTE_EX:
5395 if (gap != NULL && ga_grow(gap, idx) == OK)
5396 {
5397 mch_memmove((char *)gap->ga_data + gap->ga_len,
5398 buf, (size_t)idx);
5399 gap->ga_len += idx;
5400 }
5401 break;
5402
5403 case PASTE_INSERT:
5404 if (stop_arrow() == OK)
5405 {
Bram Moolenaar915350e2017-01-24 17:50:52 +01005406 c = buf[0];
5407 if (idx == 1 && (c == CAR || c == K_KENTER || c == NL))
5408 ins_eol(c);
5409 else
Bram Moolenaar076e5022017-01-24 18:58:30 +01005410 {
Bram Moolenaar915350e2017-01-24 17:50:52 +01005411 ins_char_bytes(buf, idx);
Bram Moolenaar076e5022017-01-24 18:58:30 +01005412 AppendToRedobuffLit(buf, idx);
5413 }
Bram Moolenaarec2da362017-01-21 20:04:22 +01005414 }
5415 break;
5416
5417 case PASTE_ONE_CHAR:
5418 if (ret_char == -1)
5419 {
Bram Moolenaarec2da362017-01-21 20:04:22 +01005420 if (has_mbyte)
5421 ret_char = (*mb_ptr2char)(buf);
5422 else
Bram Moolenaarec2da362017-01-21 20:04:22 +01005423 ret_char = buf[0];
5424 }
5425 break;
5426 }
5427 }
5428 idx = 0;
5429 }
Bram Moolenaar9e817c82017-01-25 21:36:17 +01005430
Bram Moolenaarec2da362017-01-21 20:04:22 +01005431 --no_mapping;
5432 allow_keys = save_allow_keys;
Bram Moolenaarfdd71552018-07-28 23:12:05 +02005433 if (!save_paste)
5434 set_option_value((char_u *)"paste", FALSE, NULL, 0);
Bram Moolenaarec2da362017-01-21 20:04:22 +01005435
5436 return ret_char;
5437}
5438
Bram Moolenaara23ccb82006-02-27 00:08:02 +00005439#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
Bram Moolenaara94bc432006-03-10 21:42:59 +00005440 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +01005441ins_tabline(int c)
Bram Moolenaara23ccb82006-02-27 00:08:02 +00005442{
5443 /* We will be leaving the current window, unless closing another tab. */
5444 if (c != K_TABMENU || current_tabmenu != TABLINE_MENU_CLOSE
5445 || (current_tab != 0 && current_tab != tabpage_index(curtab)))
5446 {
5447 undisplay_dollar();
5448 start_arrow(&curwin->w_cursor);
5449# ifdef FEAT_CINDENT
5450 can_cindent = TRUE;
5451# endif
5452 }
5453
5454 if (c == K_TABLINE)
5455 goto_tabpage(current_tab);
5456 else
Bram Moolenaar437df8f2006-04-27 21:47:44 +00005457 {
Bram Moolenaara23ccb82006-02-27 00:08:02 +00005458 handle_tabmenu();
Bram Moolenaar437df8f2006-04-27 21:47:44 +00005459 redraw_statuslines(); /* will redraw the tabline when needed */
5460 }
Bram Moolenaara23ccb82006-02-27 00:08:02 +00005461}
5462#endif
5463
5464#if defined(FEAT_GUI) || defined(PROTO)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005465 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01005466ins_scroll(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005467{
5468 pos_T tpos;
5469
5470 undisplay_dollar();
5471 tpos = curwin->w_cursor;
5472 if (gui_do_scroll())
5473 {
5474 start_arrow(&tpos);
5475# ifdef FEAT_CINDENT
5476 can_cindent = TRUE;
5477# endif
5478 }
5479}
5480
5481 void
Bram Moolenaar7454a062016-01-30 15:14:10 +01005482ins_horscroll(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005483{
5484 pos_T tpos;
5485
5486 undisplay_dollar();
5487 tpos = curwin->w_cursor;
Bram Moolenaar8d9b40e2010-07-25 15:49:07 +02005488 if (gui_do_horiz_scroll(scrollbar_value, FALSE))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005489 {
5490 start_arrow(&tpos);
5491# ifdef FEAT_CINDENT
5492 can_cindent = TRUE;
5493# endif
5494 }
5495}
5496#endif
5497
5498 static void
Bram Moolenaar75bf3d22019-03-26 22:46:05 +01005499ins_left(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005500{
5501 pos_T tpos;
Bram Moolenaar75bf3d22019-03-26 22:46:05 +01005502 int end_change = dont_sync_undo == FALSE; // end undoable change
Bram Moolenaar071d4272004-06-13 20:20:40 +00005503
5504#ifdef FEAT_FOLDING
5505 if ((fdo_flags & FDO_HOR) && KeyTyped)
5506 foldOpenCursor();
5507#endif
5508 undisplay_dollar();
5509 tpos = curwin->w_cursor;
5510 if (oneleft() == OK)
5511 {
Bram Moolenaar39fecab2006-08-29 14:07:36 +00005512#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
5513 /* Only call start_arrow() when not busy with preediting, it will
5514 * break undo. K_LEFT is inserted in im_correct_cursor(). */
Bram Moolenaar5c6dbcb2017-08-30 22:00:20 +02005515 if (p_imst == IM_OVER_THE_SPOT || !im_is_preediting())
Bram Moolenaar39fecab2006-08-29 14:07:36 +00005516#endif
Bram Moolenaar8b5f65a2015-09-01 19:26:12 +02005517 {
5518 start_arrow_with_change(&tpos, end_change);
5519 if (!end_change)
5520 AppendCharToRedobuff(K_LEFT);
5521 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00005522#ifdef FEAT_RIGHTLEFT
5523 /* If exit reversed string, position is fixed */
5524 if (revins_scol != -1 && (int)curwin->w_cursor.col >= revins_scol)
5525 revins_legal++;
5526 revins_chars++;
5527#endif
5528 }
5529
5530 /*
5531 * if 'whichwrap' set for cursor in insert mode may go to
5532 * previous line
5533 */
5534 else if (vim_strchr(p_ww, '[') != NULL && curwin->w_cursor.lnum > 1)
5535 {
Bram Moolenaar8b5f65a2015-09-01 19:26:12 +02005536 /* always break undo when moving upwards/downwards, else undo may break */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005537 start_arrow(&tpos);
5538 --(curwin->w_cursor.lnum);
5539 coladvance((colnr_T)MAXCOL);
5540 curwin->w_set_curswant = TRUE; /* so we stay at the end */
5541 }
5542 else
Bram Moolenaar165bc692015-07-21 17:53:25 +02005543 vim_beep(BO_CRSR);
Bram Moolenaar8b5f65a2015-09-01 19:26:12 +02005544 dont_sync_undo = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005545}
5546
5547 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +01005548ins_home(int c)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005549{
5550 pos_T tpos;
5551
5552#ifdef FEAT_FOLDING
5553 if ((fdo_flags & FDO_HOR) && KeyTyped)
5554 foldOpenCursor();
5555#endif
5556 undisplay_dollar();
5557 tpos = curwin->w_cursor;
5558 if (c == K_C_HOME)
5559 curwin->w_cursor.lnum = 1;
5560 curwin->w_cursor.col = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005561 curwin->w_cursor.coladd = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005562 curwin->w_curswant = 0;
5563 start_arrow(&tpos);
5564}
5565
5566 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +01005567ins_end(int c)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005568{
5569 pos_T tpos;
5570
5571#ifdef FEAT_FOLDING
5572 if ((fdo_flags & FDO_HOR) && KeyTyped)
5573 foldOpenCursor();
5574#endif
5575 undisplay_dollar();
5576 tpos = curwin->w_cursor;
5577 if (c == K_C_END)
5578 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
5579 coladvance((colnr_T)MAXCOL);
5580 curwin->w_curswant = MAXCOL;
5581
5582 start_arrow(&tpos);
5583}
5584
5585 static void
Bram Moolenaar75bf3d22019-03-26 22:46:05 +01005586ins_s_left()
Bram Moolenaar071d4272004-06-13 20:20:40 +00005587{
Bram Moolenaar75bf3d22019-03-26 22:46:05 +01005588 int end_change = dont_sync_undo == FALSE; // end undoable change
Bram Moolenaar071d4272004-06-13 20:20:40 +00005589#ifdef FEAT_FOLDING
5590 if ((fdo_flags & FDO_HOR) && KeyTyped)
5591 foldOpenCursor();
5592#endif
5593 undisplay_dollar();
5594 if (curwin->w_cursor.lnum > 1 || curwin->w_cursor.col > 0)
5595 {
Bram Moolenaar75bf3d22019-03-26 22:46:05 +01005596 start_arrow_with_change(&curwin->w_cursor, end_change);
5597 if (!end_change)
5598 AppendCharToRedobuff(K_S_LEFT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005599 (void)bck_word(1L, FALSE, FALSE);
5600 curwin->w_set_curswant = TRUE;
5601 }
5602 else
Bram Moolenaar165bc692015-07-21 17:53:25 +02005603 vim_beep(BO_CRSR);
Bram Moolenaar75bf3d22019-03-26 22:46:05 +01005604 dont_sync_undo = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005605}
5606
5607 static void
Bram Moolenaar75bf3d22019-03-26 22:46:05 +01005608ins_right(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005609{
Bram Moolenaar75bf3d22019-03-26 22:46:05 +01005610 int end_change = dont_sync_undo == FALSE; // end undoable change
5611
Bram Moolenaar071d4272004-06-13 20:20:40 +00005612#ifdef FEAT_FOLDING
5613 if ((fdo_flags & FDO_HOR) && KeyTyped)
5614 foldOpenCursor();
5615#endif
5616 undisplay_dollar();
Bram Moolenaar29ddebe2019-01-26 17:28:26 +01005617 if (gchar_cursor() != NUL || virtual_active())
Bram Moolenaar071d4272004-06-13 20:20:40 +00005618 {
Bram Moolenaar8b5f65a2015-09-01 19:26:12 +02005619 start_arrow_with_change(&curwin->w_cursor, end_change);
5620 if (!end_change)
5621 AppendCharToRedobuff(K_RIGHT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005622 curwin->w_set_curswant = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005623 if (virtual_active())
5624 oneright();
5625 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005626 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005627 if (has_mbyte)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00005628 curwin->w_cursor.col += (*mb_ptr2len)(ml_get_cursor());
Bram Moolenaar071d4272004-06-13 20:20:40 +00005629 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005630 ++curwin->w_cursor.col;
5631 }
5632
5633#ifdef FEAT_RIGHTLEFT
5634 revins_legal++;
5635 if (revins_chars)
5636 revins_chars--;
5637#endif
5638 }
5639 /* if 'whichwrap' set for cursor in insert mode, may move the
5640 * cursor to the next line */
5641 else if (vim_strchr(p_ww, ']') != NULL
5642 && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
5643 {
5644 start_arrow(&curwin->w_cursor);
5645 curwin->w_set_curswant = TRUE;
5646 ++curwin->w_cursor.lnum;
5647 curwin->w_cursor.col = 0;
5648 }
5649 else
Bram Moolenaar165bc692015-07-21 17:53:25 +02005650 vim_beep(BO_CRSR);
Bram Moolenaar8b5f65a2015-09-01 19:26:12 +02005651 dont_sync_undo = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005652}
5653
5654 static void
Bram Moolenaar75bf3d22019-03-26 22:46:05 +01005655ins_s_right()
Bram Moolenaar071d4272004-06-13 20:20:40 +00005656{
Bram Moolenaar75bf3d22019-03-26 22:46:05 +01005657 int end_change = dont_sync_undo == FALSE; // end undoable change
Bram Moolenaar071d4272004-06-13 20:20:40 +00005658#ifdef FEAT_FOLDING
5659 if ((fdo_flags & FDO_HOR) && KeyTyped)
5660 foldOpenCursor();
5661#endif
5662 undisplay_dollar();
5663 if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count
5664 || gchar_cursor() != NUL)
5665 {
Bram Moolenaar75bf3d22019-03-26 22:46:05 +01005666 start_arrow_with_change(&curwin->w_cursor, end_change);
5667 if (!end_change)
5668 AppendCharToRedobuff(K_S_RIGHT);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005669 (void)fwd_word(1L, FALSE, 0);
5670 curwin->w_set_curswant = TRUE;
5671 }
5672 else
Bram Moolenaar165bc692015-07-21 17:53:25 +02005673 vim_beep(BO_CRSR);
Bram Moolenaar75bf3d22019-03-26 22:46:05 +01005674 dont_sync_undo = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005675}
5676
5677 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +01005678ins_up(
5679 int startcol) /* when TRUE move to Insstart.col */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005680{
5681 pos_T tpos;
5682 linenr_T old_topline = curwin->w_topline;
5683#ifdef FEAT_DIFF
5684 int old_topfill = curwin->w_topfill;
5685#endif
5686
5687 undisplay_dollar();
5688 tpos = curwin->w_cursor;
5689 if (cursor_up(1L, TRUE) == OK)
5690 {
5691 if (startcol)
5692 coladvance(getvcol_nolist(&Insstart));
5693 if (old_topline != curwin->w_topline
5694#ifdef FEAT_DIFF
5695 || old_topfill != curwin->w_topfill
5696#endif
5697 )
5698 redraw_later(VALID);
5699 start_arrow(&tpos);
5700#ifdef FEAT_CINDENT
5701 can_cindent = TRUE;
5702#endif
5703 }
5704 else
Bram Moolenaar165bc692015-07-21 17:53:25 +02005705 vim_beep(BO_CRSR);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005706}
5707
5708 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +01005709ins_pageup(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005710{
5711 pos_T tpos;
5712
5713 undisplay_dollar();
Bram Moolenaar7fc904b2006-04-13 20:37:35 +00005714
Bram Moolenaar7fc904b2006-04-13 20:37:35 +00005715 if (mod_mask & MOD_MASK_CTRL)
5716 {
5717 /* <C-PageUp>: tab page back */
Bram Moolenaarbc444822006-10-17 11:37:50 +00005718 if (first_tabpage->tp_next != NULL)
5719 {
5720 start_arrow(&curwin->w_cursor);
5721 goto_tabpage(-1);
5722 }
Bram Moolenaar7fc904b2006-04-13 20:37:35 +00005723 return;
5724 }
Bram Moolenaar7fc904b2006-04-13 20:37:35 +00005725
Bram Moolenaar071d4272004-06-13 20:20:40 +00005726 tpos = curwin->w_cursor;
5727 if (onepage(BACKWARD, 1L) == OK)
5728 {
5729 start_arrow(&tpos);
5730#ifdef FEAT_CINDENT
5731 can_cindent = TRUE;
5732#endif
5733 }
5734 else
Bram Moolenaar165bc692015-07-21 17:53:25 +02005735 vim_beep(BO_CRSR);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005736}
5737
5738 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +01005739ins_down(
5740 int startcol) /* when TRUE move to Insstart.col */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005741{
5742 pos_T tpos;
5743 linenr_T old_topline = curwin->w_topline;
5744#ifdef FEAT_DIFF
5745 int old_topfill = curwin->w_topfill;
5746#endif
5747
5748 undisplay_dollar();
5749 tpos = curwin->w_cursor;
5750 if (cursor_down(1L, TRUE) == OK)
5751 {
5752 if (startcol)
5753 coladvance(getvcol_nolist(&Insstart));
5754 if (old_topline != curwin->w_topline
5755#ifdef FEAT_DIFF
5756 || old_topfill != curwin->w_topfill
5757#endif
5758 )
5759 redraw_later(VALID);
5760 start_arrow(&tpos);
5761#ifdef FEAT_CINDENT
5762 can_cindent = TRUE;
5763#endif
5764 }
5765 else
Bram Moolenaar165bc692015-07-21 17:53:25 +02005766 vim_beep(BO_CRSR);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005767}
5768
5769 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +01005770ins_pagedown(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005771{
5772 pos_T tpos;
5773
5774 undisplay_dollar();
Bram Moolenaar7fc904b2006-04-13 20:37:35 +00005775
Bram Moolenaar7fc904b2006-04-13 20:37:35 +00005776 if (mod_mask & MOD_MASK_CTRL)
5777 {
5778 /* <C-PageDown>: tab page forward */
Bram Moolenaarbc444822006-10-17 11:37:50 +00005779 if (first_tabpage->tp_next != NULL)
5780 {
5781 start_arrow(&curwin->w_cursor);
5782 goto_tabpage(0);
5783 }
Bram Moolenaar7fc904b2006-04-13 20:37:35 +00005784 return;
5785 }
Bram Moolenaar7fc904b2006-04-13 20:37:35 +00005786
Bram Moolenaar071d4272004-06-13 20:20:40 +00005787 tpos = curwin->w_cursor;
5788 if (onepage(FORWARD, 1L) == OK)
5789 {
5790 start_arrow(&tpos);
5791#ifdef FEAT_CINDENT
5792 can_cindent = TRUE;
5793#endif
5794 }
5795 else
Bram Moolenaar165bc692015-07-21 17:53:25 +02005796 vim_beep(BO_CRSR);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005797}
5798
5799#ifdef FEAT_DND
5800 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +01005801ins_drop(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005802{
5803 do_put('~', BACKWARD, 1L, PUT_CURSEND);
5804}
5805#endif
5806
5807/*
5808 * Handle TAB in Insert or Replace mode.
5809 * Return TRUE when the TAB needs to be inserted like a normal character.
5810 */
5811 static int
Bram Moolenaar7454a062016-01-30 15:14:10 +01005812ins_tab(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005813{
5814 int ind;
5815 int i;
5816 int temp;
5817
5818 if (Insstart_blank_vcol == MAXCOL && curwin->w_cursor.lnum == Insstart.lnum)
5819 Insstart_blank_vcol = get_nolist_virtcol();
5820 if (echeck_abbr(TAB + ABBR_OFF))
5821 return FALSE;
5822
5823 ind = inindent(0);
5824#ifdef FEAT_CINDENT
5825 if (ind)
5826 can_cindent = FALSE;
5827#endif
5828
5829 /*
Bram Moolenaar04958cb2018-06-23 19:23:02 +02005830 * When nothing special, insert TAB like a normal character.
Bram Moolenaar071d4272004-06-13 20:20:40 +00005831 */
5832 if (!curbuf->b_p_et
Bram Moolenaar04958cb2018-06-23 19:23:02 +02005833#ifdef FEAT_VARTABS
5834 && !(p_sta && ind
5835 /* These five lines mean 'tabstop' != 'shiftwidth' */
5836 && ((tabstop_count(curbuf->b_p_vts_array) > 1)
5837 || (tabstop_count(curbuf->b_p_vts_array) == 1
5838 && tabstop_first(curbuf->b_p_vts_array)
5839 != get_sw_value(curbuf))
5840 || (tabstop_count(curbuf->b_p_vts_array) == 0
5841 && curbuf->b_p_ts != get_sw_value(curbuf))))
5842 && tabstop_count(curbuf->b_p_vsts_array) == 0
5843#else
Bram Moolenaar6bcbcc52013-11-05 07:13:41 +01005844 && !(p_sta && ind && curbuf->b_p_ts != get_sw_value(curbuf))
Bram Moolenaar04958cb2018-06-23 19:23:02 +02005845#endif
Bram Moolenaar9f340fa2012-10-21 00:10:39 +02005846 && get_sts_value() == 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00005847 return TRUE;
5848
5849 if (stop_arrow() == FAIL)
5850 return TRUE;
5851
5852 did_ai = FALSE;
5853#ifdef FEAT_SMARTINDENT
5854 did_si = FALSE;
5855 can_si = FALSE;
5856 can_si_back = FALSE;
5857#endif
5858 AppendToRedobuff((char_u *)"\t");
5859
Bram Moolenaar04958cb2018-06-23 19:23:02 +02005860#ifdef FEAT_VARTABS
5861 if (p_sta && ind) /* insert tab in indent, use 'shiftwidth' */
5862 {
Bram Moolenaarc9fe5ab2018-07-05 22:27:08 +02005863 temp = (int)get_sw_value(curbuf);
Bram Moolenaar04958cb2018-06-23 19:23:02 +02005864 temp -= get_nolist_virtcol() % temp;
5865 }
Bram Moolenaar33d5ab32018-07-02 20:51:24 +02005866 else if (tabstop_count(curbuf->b_p_vsts_array) > 0 || curbuf->b_p_sts != 0)
Bram Moolenaar04958cb2018-06-23 19:23:02 +02005867 /* use 'softtabstop' when set */
Bram Moolenaar33d5ab32018-07-02 20:51:24 +02005868 temp = tabstop_padding(get_nolist_virtcol(), get_sts_value(),
Bram Moolenaar04958cb2018-06-23 19:23:02 +02005869 curbuf->b_p_vsts_array);
5870 else /* otherwise use 'tabstop' */
5871 temp = tabstop_padding(get_nolist_virtcol(), curbuf->b_p_ts,
5872 curbuf->b_p_vts_array);
5873#else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005874 if (p_sta && ind) /* insert tab in indent, use 'shiftwidth' */
Bram Moolenaar6bcbcc52013-11-05 07:13:41 +01005875 temp = (int)get_sw_value(curbuf);
Bram Moolenaar9f340fa2012-10-21 00:10:39 +02005876 else if (curbuf->b_p_sts != 0) /* use 'softtabstop' when set */
5877 temp = (int)get_sts_value();
Bram Moolenaar071d4272004-06-13 20:20:40 +00005878 else /* otherwise use 'tabstop' */
5879 temp = (int)curbuf->b_p_ts;
5880 temp -= get_nolist_virtcol() % temp;
Bram Moolenaar04958cb2018-06-23 19:23:02 +02005881#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005882
5883 /*
5884 * Insert the first space with ins_char(). It will delete one char in
5885 * replace mode. Insert the rest with ins_str(); it will not delete any
5886 * chars. For VREPLACE mode, we use ins_char() for all characters.
5887 */
5888 ins_char(' ');
5889 while (--temp > 0)
5890 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00005891 if (State & VREPLACE_FLAG)
5892 ins_char(' ');
5893 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005894 {
5895 ins_str((char_u *)" ");
5896 if (State & REPLACE_FLAG) /* no char replaced */
5897 replace_push(NUL);
5898 }
5899 }
5900
5901 /*
5902 * When 'expandtab' not set: Replace spaces by TABs where possible.
5903 */
Bram Moolenaar04958cb2018-06-23 19:23:02 +02005904#ifdef FEAT_VARTABS
5905 if (!curbuf->b_p_et && (tabstop_count(curbuf->b_p_vsts_array) > 0
5906 || get_sts_value() > 0
5907 || (p_sta && ind)))
5908#else
Bram Moolenaar9f340fa2012-10-21 00:10:39 +02005909 if (!curbuf->b_p_et && (get_sts_value() || (p_sta && ind)))
Bram Moolenaar04958cb2018-06-23 19:23:02 +02005910#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00005911 {
5912 char_u *ptr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005913 char_u *saved_line = NULL; /* init for GCC */
5914 pos_T pos;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005915 pos_T fpos;
5916 pos_T *cursor;
5917 colnr_T want_vcol, vcol;
5918 int change_col = -1;
5919 int save_list = curwin->w_p_list;
5920
5921 /*
5922 * Get the current line. For VREPLACE mode, don't make real changes
5923 * yet, just work on a copy of the line.
5924 */
Bram Moolenaar071d4272004-06-13 20:20:40 +00005925 if (State & VREPLACE_FLAG)
5926 {
5927 pos = curwin->w_cursor;
5928 cursor = &pos;
5929 saved_line = vim_strsave(ml_get_curline());
5930 if (saved_line == NULL)
5931 return FALSE;
5932 ptr = saved_line + pos.col;
5933 }
5934 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00005935 {
5936 ptr = ml_get_cursor();
5937 cursor = &curwin->w_cursor;
5938 }
5939
5940 /* When 'L' is not in 'cpoptions' a tab always takes up 'ts' spaces. */
5941 if (vim_strchr(p_cpo, CPO_LISTWM) == NULL)
5942 curwin->w_p_list = FALSE;
5943
5944 /* Find first white before the cursor */
5945 fpos = curwin->w_cursor;
Bram Moolenaar1c465442017-03-12 20:10:05 +01005946 while (fpos.col > 0 && VIM_ISWHITE(ptr[-1]))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005947 {
5948 --fpos.col;
5949 --ptr;
5950 }
5951
5952 /* In Replace mode, don't change characters before the insert point. */
5953 if ((State & REPLACE_FLAG)
5954 && fpos.lnum == Insstart.lnum
5955 && fpos.col < Insstart.col)
5956 {
5957 ptr += Insstart.col - fpos.col;
5958 fpos.col = Insstart.col;
5959 }
5960
5961 /* compute virtual column numbers of first white and cursor */
5962 getvcol(curwin, &fpos, &vcol, NULL, NULL);
5963 getvcol(curwin, cursor, &want_vcol, NULL, NULL);
5964
Bram Moolenaar597a4222014-06-25 14:39:50 +02005965 /* Use as many TABs as possible. Beware of 'breakindent', 'showbreak'
5966 * and 'linebreak' adding extra virtual columns. */
Bram Moolenaar1c465442017-03-12 20:10:05 +01005967 while (VIM_ISWHITE(*ptr))
Bram Moolenaar071d4272004-06-13 20:20:40 +00005968 {
Bram Moolenaar597a4222014-06-25 14:39:50 +02005969 i = lbr_chartabsize(NULL, (char_u *)"\t", vcol);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005970 if (vcol + i > want_vcol)
5971 break;
5972 if (*ptr != TAB)
5973 {
5974 *ptr = TAB;
5975 if (change_col < 0)
5976 {
5977 change_col = fpos.col; /* Column of first change */
5978 /* May have to adjust Insstart */
5979 if (fpos.lnum == Insstart.lnum && fpos.col < Insstart.col)
5980 Insstart.col = fpos.col;
5981 }
5982 }
5983 ++fpos.col;
5984 ++ptr;
5985 vcol += i;
5986 }
5987
5988 if (change_col >= 0)
5989 {
5990 int repl_off = 0;
Bram Moolenaar597a4222014-06-25 14:39:50 +02005991 char_u *line = ptr;
Bram Moolenaar071d4272004-06-13 20:20:40 +00005992
5993 /* Skip over the spaces we need. */
5994 while (vcol < want_vcol && *ptr == ' ')
5995 {
Bram Moolenaar597a4222014-06-25 14:39:50 +02005996 vcol += lbr_chartabsize(line, ptr, vcol);
Bram Moolenaar071d4272004-06-13 20:20:40 +00005997 ++ptr;
5998 ++repl_off;
5999 }
6000 if (vcol > want_vcol)
6001 {
6002 /* Must have a char with 'showbreak' just before it. */
6003 --ptr;
6004 --repl_off;
6005 }
6006 fpos.col += repl_off;
6007
6008 /* Delete following spaces. */
6009 i = cursor->col - fpos.col;
6010 if (i > 0)
6011 {
Bram Moolenaarc1a11ed2008-06-24 22:09:24 +00006012 STRMOVE(ptr, ptr + i);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006013 /* correct replace stack. */
Bram Moolenaar1f0bfe52018-07-29 16:09:22 +02006014 if ((State & REPLACE_FLAG) && !(State & VREPLACE_FLAG))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006015 for (temp = i; --temp >= 0; )
6016 replace_join(repl_off);
Bram Moolenaar98aefe72018-12-13 22:20:09 +01006017#ifdef FEAT_TEXT_PROP
6018 curbuf->b_ml.ml_line_len -= i;
6019#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006020 }
Bram Moolenaar009b2592004-10-24 19:18:58 +00006021#ifdef FEAT_NETBEANS_INTG
Bram Moolenaarb26e6322010-05-22 21:34:09 +02006022 if (netbeans_active())
Bram Moolenaar009b2592004-10-24 19:18:58 +00006023 {
Bram Moolenaar67c53842010-05-22 18:28:27 +02006024 netbeans_removed(curbuf, fpos.lnum, cursor->col, (long)(i + 1));
Bram Moolenaar009b2592004-10-24 19:18:58 +00006025 netbeans_inserted(curbuf, fpos.lnum, cursor->col,
6026 (char_u *)"\t", 1);
6027 }
6028#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006029 cursor->col -= i;
6030
Bram Moolenaar071d4272004-06-13 20:20:40 +00006031 /*
6032 * In VREPLACE mode, we haven't changed anything yet. Do it now by
6033 * backspacing over the changed spacing and then inserting the new
6034 * spacing.
6035 */
6036 if (State & VREPLACE_FLAG)
6037 {
6038 /* Backspace from real cursor to change_col */
6039 backspace_until_column(change_col);
6040
6041 /* Insert each char in saved_line from changed_col to
6042 * ptr-cursor */
6043 ins_bytes_len(saved_line + change_col,
6044 cursor->col - change_col);
6045 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006046 }
6047
Bram Moolenaar071d4272004-06-13 20:20:40 +00006048 if (State & VREPLACE_FLAG)
6049 vim_free(saved_line);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006050 curwin->w_p_list = save_list;
6051 }
6052
6053 return FALSE;
6054}
6055
6056/*
6057 * Handle CR or NL in insert mode.
Bram Moolenaar24a2d722018-04-24 19:36:43 +02006058 * Return FAIL when out of memory or can't undo.
Bram Moolenaar071d4272004-06-13 20:20:40 +00006059 */
Bram Moolenaar7591bb32019-03-30 13:53:47 +01006060 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01006061ins_eol(int c)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006062{
6063 int i;
6064
6065 if (echeck_abbr(c + ABBR_OFF))
Bram Moolenaarc3c3e692018-04-26 22:30:33 +02006066 return OK;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006067 if (stop_arrow() == FAIL)
Bram Moolenaarc3c3e692018-04-26 22:30:33 +02006068 return FAIL;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006069 undisplay_dollar();
6070
6071 /*
6072 * Strange Vi behaviour: In Replace mode, typing a NL will not delete the
6073 * character under the cursor. Only push a NUL on the replace stack,
6074 * nothing to put back when the NL is deleted.
6075 */
Bram Moolenaar1f0bfe52018-07-29 16:09:22 +02006076 if ((State & REPLACE_FLAG) && !(State & VREPLACE_FLAG))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006077 replace_push(NUL);
6078
6079 /*
6080 * In VREPLACE mode, a NL replaces the rest of the line, and starts
6081 * replacing the next line, so we push all of the characters left on the
6082 * line onto the replace stack. This is not done here though, it is done
6083 * in open_line().
6084 */
6085
Bram Moolenaarf193fff2006-04-27 00:02:13 +00006086 /* Put cursor on NUL if on the last char and coladd is 1 (happens after
6087 * CTRL-O). */
6088 if (virtual_active() && curwin->w_cursor.coladd > 0)
6089 coladvance(getviscol());
Bram Moolenaarf193fff2006-04-27 00:02:13 +00006090
Bram Moolenaar071d4272004-06-13 20:20:40 +00006091#ifdef FEAT_RIGHTLEFT
Bram Moolenaar071d4272004-06-13 20:20:40 +00006092 /* NL in reverse insert will always start in the end of
6093 * current line. */
6094 if (revins_on)
6095 curwin->w_cursor.col += (colnr_T)STRLEN(ml_get_cursor());
6096#endif
6097
6098 AppendToRedobuff(NL_STR);
6099 i = open_line(FORWARD,
6100#ifdef FEAT_COMMENTS
6101 has_format_option(FO_RET_COMS) ? OPENLINE_DO_COM :
6102#endif
6103 0, old_indent);
6104 old_indent = 0;
6105#ifdef FEAT_CINDENT
6106 can_cindent = TRUE;
6107#endif
Bram Moolenaar6ae133b2006-11-01 20:25:45 +00006108#ifdef FEAT_FOLDING
6109 /* When inserting a line the cursor line must never be in a closed fold. */
6110 foldOpenCursor();
6111#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00006112
Bram Moolenaar24a2d722018-04-24 19:36:43 +02006113 return i;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006114}
6115
6116#ifdef FEAT_DIGRAPHS
6117/*
6118 * Handle digraph in insert mode.
6119 * Returns character still to be inserted, or NUL when nothing remaining to be
6120 * done.
6121 */
6122 static int
Bram Moolenaar7454a062016-01-30 15:14:10 +01006123ins_digraph(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006124{
6125 int c;
6126 int cc;
Bram Moolenaar9c520cb2011-05-10 14:22:16 +02006127 int did_putchar = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006128
6129 pc_status = PC_STATUS_UNSET;
6130 if (redrawing() && !char_avail())
6131 {
6132 /* may need to redraw when no more chars available now */
Bram Moolenaar754b5602006-02-09 23:53:20 +00006133 ins_redraw(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006134
6135 edit_putchar('?', TRUE);
Bram Moolenaar9c520cb2011-05-10 14:22:16 +02006136 did_putchar = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006137#ifdef FEAT_CMDL_INFO
6138 add_to_showcmd_c(Ctrl_K);
6139#endif
6140 }
6141
6142#ifdef USE_ON_FLY_SCROLL
6143 dont_scroll = TRUE; /* disallow scrolling here */
6144#endif
6145
6146 /* don't map the digraph chars. This also prevents the
6147 * mode message to be deleted when ESC is hit */
6148 ++no_mapping;
6149 ++allow_keys;
Bram Moolenaar61abfd12007-09-13 16:26:47 +00006150 c = plain_vgetc();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006151 --no_mapping;
6152 --allow_keys;
Bram Moolenaar9c520cb2011-05-10 14:22:16 +02006153 if (did_putchar)
6154 /* when the line fits in 'columns' the '?' is at the start of the next
6155 * line and will not be removed by the redraw */
6156 edit_unputchar();
Bram Moolenaar26dcc7e2010-07-14 22:35:55 +02006157
Bram Moolenaar071d4272004-06-13 20:20:40 +00006158 if (IS_SPECIAL(c) || mod_mask) /* special key */
6159 {
6160#ifdef FEAT_CMDL_INFO
6161 clear_showcmd();
6162#endif
6163 insert_special(c, TRUE, FALSE);
6164 return NUL;
6165 }
6166 if (c != ESC)
6167 {
Bram Moolenaar9c520cb2011-05-10 14:22:16 +02006168 did_putchar = FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006169 if (redrawing() && !char_avail())
6170 {
6171 /* may need to redraw when no more chars available now */
Bram Moolenaar754b5602006-02-09 23:53:20 +00006172 ins_redraw(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006173
6174 if (char2cells(c) == 1)
6175 {
Bram Moolenaar754b5602006-02-09 23:53:20 +00006176 ins_redraw(FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006177 edit_putchar(c, TRUE);
Bram Moolenaar9c520cb2011-05-10 14:22:16 +02006178 did_putchar = TRUE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006179 }
6180#ifdef FEAT_CMDL_INFO
6181 add_to_showcmd_c(c);
6182#endif
6183 }
6184 ++no_mapping;
6185 ++allow_keys;
Bram Moolenaar61abfd12007-09-13 16:26:47 +00006186 cc = plain_vgetc();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006187 --no_mapping;
6188 --allow_keys;
Bram Moolenaar9c520cb2011-05-10 14:22:16 +02006189 if (did_putchar)
6190 /* when the line fits in 'columns' the '?' is at the start of the
6191 * next line and will not be removed by a redraw */
6192 edit_unputchar();
Bram Moolenaar071d4272004-06-13 20:20:40 +00006193 if (cc != ESC)
6194 {
6195 AppendToRedobuff((char_u *)CTRL_V_STR);
6196 c = getdigraph(c, cc, TRUE);
6197#ifdef FEAT_CMDL_INFO
6198 clear_showcmd();
6199#endif
6200 return c;
6201 }
6202 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00006203#ifdef FEAT_CMDL_INFO
6204 clear_showcmd();
6205#endif
6206 return NUL;
6207}
6208#endif
6209
6210/*
6211 * Handle CTRL-E and CTRL-Y in Insert mode: copy char from other line.
6212 * Returns the char to be inserted, or NUL if none found.
6213 */
Bram Moolenaar8320da42012-04-30 18:18:47 +02006214 int
Bram Moolenaar7454a062016-01-30 15:14:10 +01006215ins_copychar(linenr_T lnum)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006216{
6217 int c;
6218 int temp;
6219 char_u *ptr, *prev_ptr;
Bram Moolenaar597a4222014-06-25 14:39:50 +02006220 char_u *line;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006221
6222 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
6223 {
Bram Moolenaar165bc692015-07-21 17:53:25 +02006224 vim_beep(BO_COPY);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006225 return NUL;
6226 }
6227
6228 /* try to advance to the cursor column */
6229 temp = 0;
Bram Moolenaar597a4222014-06-25 14:39:50 +02006230 line = ptr = ml_get(lnum);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006231 prev_ptr = ptr;
6232 validate_virtcol();
6233 while ((colnr_T)temp < curwin->w_virtcol && *ptr != NUL)
6234 {
6235 prev_ptr = ptr;
Bram Moolenaar597a4222014-06-25 14:39:50 +02006236 temp += lbr_chartabsize_adv(line, &ptr, (colnr_T)temp);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006237 }
6238 if ((colnr_T)temp > curwin->w_virtcol)
6239 ptr = prev_ptr;
6240
Bram Moolenaar071d4272004-06-13 20:20:40 +00006241 c = (*mb_ptr2char)(ptr);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006242 if (c == NUL)
Bram Moolenaar165bc692015-07-21 17:53:25 +02006243 vim_beep(BO_COPY);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006244 return c;
6245}
6246
Bram Moolenaar4be06f92005-07-29 22:36:03 +00006247/*
6248 * CTRL-Y or CTRL-E typed in Insert mode.
6249 */
6250 static int
Bram Moolenaar7454a062016-01-30 15:14:10 +01006251ins_ctrl_ey(int tc)
Bram Moolenaar4be06f92005-07-29 22:36:03 +00006252{
6253 int c = tc;
6254
6255#ifdef FEAT_INS_EXPAND
Bram Moolenaar7591bb32019-03-30 13:53:47 +01006256 if (ctrl_x_mode_scroll())
Bram Moolenaar4be06f92005-07-29 22:36:03 +00006257 {
6258 if (c == Ctrl_Y)
6259 scrolldown_clamp();
6260 else
6261 scrollup_clamp();
6262 redraw_later(VALID);
6263 }
6264 else
6265#endif
6266 {
6267 c = ins_copychar(curwin->w_cursor.lnum + (c == Ctrl_Y ? -1 : 1));
6268 if (c != NUL)
6269 {
6270 long tw_save;
6271
6272 /* The character must be taken literally, insert like it
6273 * was typed after a CTRL-V, and pretend 'textwidth'
6274 * wasn't set. Digits, 'o' and 'x' are special after a
6275 * CTRL-V, don't use it for these. */
6276 if (c < 256 && !isalnum(c))
6277 AppendToRedobuff((char_u *)CTRL_V_STR); /* CTRL-V */
6278 tw_save = curbuf->b_p_tw;
6279 curbuf->b_p_tw = -1;
6280 insert_special(c, TRUE, FALSE);
6281 curbuf->b_p_tw = tw_save;
6282#ifdef FEAT_RIGHTLEFT
6283 revins_chars++;
6284 revins_legal++;
6285#endif
6286 c = Ctrl_V; /* pretend CTRL-V is last character */
6287 auto_format(FALSE, TRUE);
6288 }
6289 }
6290 return c;
6291}
6292
Bram Moolenaar071d4272004-06-13 20:20:40 +00006293#ifdef FEAT_SMARTINDENT
6294/*
6295 * Try to do some very smart auto-indenting.
6296 * Used when inserting a "normal" character.
6297 */
6298 static void
Bram Moolenaar7454a062016-01-30 15:14:10 +01006299ins_try_si(int c)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006300{
6301 pos_T *pos, old_pos;
6302 char_u *ptr;
6303 int i;
6304 int temp;
6305
6306 /*
6307 * do some very smart indenting when entering '{' or '}'
6308 */
6309 if (((did_si || can_si_back) && c == '{') || (can_si && c == '}'))
6310 {
6311 /*
6312 * for '}' set indent equal to indent of line containing matching '{'
6313 */
6314 if (c == '}' && (pos = findmatch(NULL, '{')) != NULL)
6315 {
6316 old_pos = curwin->w_cursor;
6317 /*
6318 * If the matching '{' has a ')' immediately before it (ignoring
6319 * white-space), then line up with the start of the line
6320 * containing the matching '(' if there is one. This handles the
6321 * case where an "if (..\n..) {" statement continues over multiple
6322 * lines -- webb
6323 */
6324 ptr = ml_get(pos->lnum);
6325 i = pos->col;
6326 if (i > 0) /* skip blanks before '{' */
Bram Moolenaar1c465442017-03-12 20:10:05 +01006327 while (--i > 0 && VIM_ISWHITE(ptr[i]))
Bram Moolenaar071d4272004-06-13 20:20:40 +00006328 ;
6329 curwin->w_cursor.lnum = pos->lnum;
6330 curwin->w_cursor.col = i;
6331 if (ptr[i] == ')' && (pos = findmatch(NULL, '(')) != NULL)
6332 curwin->w_cursor = *pos;
6333 i = get_indent();
6334 curwin->w_cursor = old_pos;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006335 if (State & VREPLACE_FLAG)
Bram Moolenaar21b17e72008-01-16 19:03:13 +00006336 change_indent(INDENT_SET, i, FALSE, NUL, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006337 else
Bram Moolenaar071d4272004-06-13 20:20:40 +00006338 (void)set_indent(i, SIN_CHANGED);
6339 }
6340 else if (curwin->w_cursor.col > 0)
6341 {
6342 /*
6343 * when inserting '{' after "O" reduce indent, but not
6344 * more than indent of previous line
6345 */
6346 temp = TRUE;
6347 if (c == '{' && can_si_back && curwin->w_cursor.lnum > 1)
6348 {
6349 old_pos = curwin->w_cursor;
6350 i = get_indent();
6351 while (curwin->w_cursor.lnum > 1)
6352 {
6353 ptr = skipwhite(ml_get(--(curwin->w_cursor.lnum)));
6354
6355 /* ignore empty lines and lines starting with '#'. */
6356 if (*ptr != '#' && *ptr != NUL)
6357 break;
6358 }
6359 if (get_indent() >= i)
6360 temp = FALSE;
6361 curwin->w_cursor = old_pos;
6362 }
6363 if (temp)
Bram Moolenaar21b17e72008-01-16 19:03:13 +00006364 shift_line(TRUE, FALSE, 1, TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00006365 }
6366 }
6367
6368 /*
6369 * set indent of '#' always to 0
6370 */
6371 if (curwin->w_cursor.col > 0 && can_si && c == '#')
6372 {
6373 /* remember current indent for next line */
6374 old_indent = get_indent();
6375 (void)set_indent(0, SIN_CHANGED);
6376 }
6377
6378 /* Adjust ai_col, the char at this position can be deleted. */
6379 if (ai_col > curwin->w_cursor.col)
6380 ai_col = curwin->w_cursor.col;
6381}
6382#endif
6383
6384/*
6385 * Get the value that w_virtcol would have when 'list' is off.
6386 * Unless 'cpo' contains the 'L' flag.
6387 */
Bram Moolenaarf9514162018-11-22 03:08:29 +01006388 colnr_T
Bram Moolenaar7454a062016-01-30 15:14:10 +01006389get_nolist_virtcol(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +00006390{
Bram Moolenaarf9514162018-11-22 03:08:29 +01006391 // check validity of cursor in current buffer
6392 if (curwin->w_buffer == NULL
6393 || curwin->w_buffer->b_ml.ml_mfp == NULL
6394 || curwin->w_cursor.lnum > curwin->w_buffer->b_ml.ml_line_count)
6395 return 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00006396 if (curwin->w_p_list && vim_strchr(p_cpo, CPO_LISTWM) == NULL)
6397 return getvcol_nolist(&curwin->w_cursor);
6398 validate_virtcol();
6399 return curwin->w_virtcol;
6400}
Bram Moolenaarf5876f12012-02-29 18:22:08 +01006401
Bram Moolenaarf2bd8ef2018-03-04 18:08:14 +01006402#if defined(FEAT_EVAL)
Bram Moolenaarf5876f12012-02-29 18:22:08 +01006403/*
6404 * Handle the InsertCharPre autocommand.
6405 * "c" is the character that was typed.
6406 * Return a pointer to allocated memory with the replacement string.
6407 * Return NULL to continue inserting "c".
6408 */
6409 static char_u *
Bram Moolenaar7454a062016-01-30 15:14:10 +01006410do_insert_char_pre(int c)
Bram Moolenaarf5876f12012-02-29 18:22:08 +01006411{
Bram Moolenaar704984a2012-06-01 14:57:51 +02006412 char_u *res;
Bram Moolenaar704984a2012-06-01 14:57:51 +02006413 char_u buf[MB_MAXBYTES + 1];
Bram Moolenaar8ad16da2019-01-06 15:29:57 +01006414 int save_State = State;
Bram Moolenaarf5876f12012-02-29 18:22:08 +01006415
6416 /* Return quickly when there is nothing to do. */
6417 if (!has_insertcharpre())
6418 return NULL;
6419
Bram Moolenaar704984a2012-06-01 14:57:51 +02006420 if (has_mbyte)
6421 buf[(*mb_char2bytes)(c, buf)] = NUL;
6422 else
Bram Moolenaar704984a2012-06-01 14:57:51 +02006423 {
6424 buf[0] = c;
6425 buf[1] = NUL;
6426 }
6427
Bram Moolenaarf5876f12012-02-29 18:22:08 +01006428 /* Lock the text to avoid weird things from happening. */
6429 ++textlock;
Bram Moolenaar704984a2012-06-01 14:57:51 +02006430 set_vim_var_string(VV_CHAR, buf, -1); /* set v:char */
Bram Moolenaarf5876f12012-02-29 18:22:08 +01006431
Bram Moolenaar704984a2012-06-01 14:57:51 +02006432 res = NULL;
Bram Moolenaar9fa95062018-08-08 22:08:32 +02006433 if (ins_apply_autocmds(EVENT_INSERTCHARPRE))
Bram Moolenaar704984a2012-06-01 14:57:51 +02006434 {
6435 /* Get the value of v:char. It may be empty or more than one
6436 * character. Only use it when changed, otherwise continue with the
6437 * original character to avoid breaking autoindent. */
6438 if (STRCMP(buf, get_vim_var_str(VV_CHAR)) != 0)
6439 res = vim_strsave(get_vim_var_str(VV_CHAR));
6440 }
Bram Moolenaarf5876f12012-02-29 18:22:08 +01006441
6442 set_vim_var_string(VV_CHAR, NULL, -1); /* clear v:char */
6443 --textlock;
6444
Bram Moolenaar8ad16da2019-01-06 15:29:57 +01006445 // Restore the State, it may have been changed.
6446 State = save_State;
6447
Bram Moolenaarf5876f12012-02-29 18:22:08 +01006448 return res;
6449}
6450#endif
Bram Moolenaar9fa95062018-08-08 22:08:32 +02006451
Bram Moolenaar7591bb32019-03-30 13:53:47 +01006452#if defined(FEAT_CINDENT) || defined(PROTO)
6453 int
6454can_cindent_get(void)
6455{
6456 return can_cindent;
6457}
6458#endif
6459
Bram Moolenaar9fa95062018-08-08 22:08:32 +02006460/*
6461 * Trigger "event" and take care of fixing undo.
6462 */
Bram Moolenaar7591bb32019-03-30 13:53:47 +01006463 int
Bram Moolenaar9fa95062018-08-08 22:08:32 +02006464ins_apply_autocmds(event_T event)
6465{
6466 varnumber_T tick = CHANGEDTICK(curbuf);
6467 int r;
6468
6469 r = apply_autocmds(event, NULL, NULL, FALSE, curbuf);
6470
6471 // If u_savesub() was called then we are not prepared to start
6472 // a new line. Call u_save() with no contents to fix that.
6473 if (tick != CHANGEDTICK(curbuf))
6474 u_save(curwin->w_cursor.lnum, (linenr_T)(curwin->w_cursor.lnum + 1));
6475
6476 return r;
6477}