1// This is an open source non-commercial project. Dear PVS-Studio, please check
2// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
3
4/*
5 * edit.c: functions for Insert mode
6 */
7
8#include <assert.h>
9#include <string.h>
10#include <inttypes.h>
11#include <stdbool.h>
12
13#include "nvim/vim.h"
14#include "nvim/ascii.h"
15#include "nvim/edit.h"
16#include "nvim/buffer.h"
17#include "nvim/change.h"
18#include "nvim/charset.h"
19#include "nvim/cursor.h"
20#include "nvim/digraph.h"
21#include "nvim/eval.h"
22#include "nvim/eval/typval.h"
23#include "nvim/ex_docmd.h"
24#include "nvim/ex_getln.h"
25#include "nvim/fileio.h"
26#include "nvim/fold.h"
27#include "nvim/getchar.h"
28#include "nvim/indent.h"
29#include "nvim/indent_c.h"
30#include "nvim/main.h"
31#include "nvim/mbyte.h"
32#include "nvim/memline.h"
33#include "nvim/memory.h"
34#include "nvim/message.h"
35#include "nvim/misc1.h"
36#include "nvim/keymap.h"
37#include "nvim/move.h"
38#include "nvim/normal.h"
39#include "nvim/ops.h"
40#include "nvim/option.h"
41#include "nvim/path.h"
42#include "nvim/popupmnu.h"
43#include "nvim/quickfix.h"
44#include "nvim/regexp.h"
45#include "nvim/screen.h"
46#include "nvim/search.h"
47#include "nvim/spell.h"
48#include "nvim/strings.h"
49#include "nvim/state.h"
50#include "nvim/syntax.h"
51#include "nvim/tag.h"
52#include "nvim/ui.h"
53#include "nvim/mouse.h"
54#include "nvim/terminal.h"
55#include "nvim/undo.h"
56#include "nvim/window.h"
57#include "nvim/event/loop.h"
58#include "nvim/mark.h"
59#include "nvim/os/input.h"
60#include "nvim/os/time.h"
61
62// Definitions used for CTRL-X submode.
63// Note: If you change CTRL-X submode, you must also maintain ctrl_x_msgs[]
64// and ctrl_x_mode_names[].
65
66#define CTRL_X_WANT_IDENT 0x100
67
68#define CTRL_X_NORMAL 0 ///< CTRL-N CTRL-P completion, default
69#define CTRL_X_NOT_DEFINED_YET 1
70#define CTRL_X_SCROLL 2
71#define CTRL_X_WHOLE_LINE 3
72#define CTRL_X_FILES 4
73#define CTRL_X_TAGS (5 + CTRL_X_WANT_IDENT)
74#define CTRL_X_PATH_PATTERNS (6 + CTRL_X_WANT_IDENT)
75#define CTRL_X_PATH_DEFINES (7 + CTRL_X_WANT_IDENT)
76#define CTRL_X_FINISHED 8
77#define CTRL_X_DICTIONARY (9 + CTRL_X_WANT_IDENT)
78#define CTRL_X_THESAURUS (10 + CTRL_X_WANT_IDENT)
79#define CTRL_X_CMDLINE 11
80#define CTRL_X_FUNCTION 12
81#define CTRL_X_OMNI 13
82#define CTRL_X_SPELL 14
83#define CTRL_X_LOCAL_MSG 15 ///< only used in "ctrl_x_msgs"
84#define CTRL_X_EVAL 16 ///< for builtin function complete()
85
86#define CTRL_X_MSG(i) ctrl_x_msgs[(i) & ~CTRL_X_WANT_IDENT]
87#define CTRL_X_MODE_LINE_OR_EVAL(m) \
88 ((m) == CTRL_X_WHOLE_LINE || (m) == CTRL_X_EVAL)
89
90// Message for CTRL-X mode, index is ctrl_x_mode.
91static char *ctrl_x_msgs[] =
92{
93 N_(" Keyword completion (^N^P)"), // CTRL_X_NORMAL, ^P/^N compl.
94 N_(" ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"),
95 NULL, // CTRL_X_SCROLL: depends on state
96 N_(" Whole line completion (^L^N^P)"),
97 N_(" File name completion (^F^N^P)"),
98 N_(" Tag completion (^]^N^P)"),
99 N_(" Path pattern completion (^N^P)"),
100 N_(" Definition completion (^D^N^P)"),
101 NULL, // CTRL_X_FINISHED
102 N_(" Dictionary completion (^K^N^P)"),
103 N_(" Thesaurus completion (^T^N^P)"),
104 N_(" Command-line completion (^V^N^P)"),
105 N_(" User defined completion (^U^N^P)"),
106 N_(" Omni completion (^O^N^P)"),
107 N_(" Spelling suggestion (s^N^P)"),
108 N_(" Keyword Local completion (^N^P)"),
109 NULL, // CTRL_X_EVAL doesn't use msg.
110};
111
112static char *ctrl_x_mode_names[] = {
113 "keyword",
114 "ctrl_x",
115 "unknown", // CTRL_X_SCROLL
116 "whole_line",
117 "files",
118 "tags",
119 "path_patterns",
120 "path_defines",
121 "unknown", // CTRL_X_FINISHED
122 "dictionary",
123 "thesaurus",
124 "cmdline",
125 "function",
126 "omni",
127 "spell",
128 NULL, // CTRL_X_LOCAL_MSG only used in "ctrl_x_msgs"
129 "eval"
130};
131
132static char e_hitend[] = N_("Hit end of paragraph");
133static char e_complwin[] = N_("E839: Completion function changed window");
134static char e_compldel[] = N_("E840: Completion function deleted text");
135
136/*
137 * Structure used to store one match for insert completion.
138 */
139typedef struct compl_S compl_T;
140struct compl_S {
141 compl_T *cp_next;
142 compl_T *cp_prev;
143 char_u *cp_str; // matched text
144 char_u *(cp_text[CPT_COUNT]); // text for the menu
145 char_u *cp_fname; // file containing the match, allocated when
146 // cp_flags has CP_FREE_FNAME
147 int cp_flags; // CP_ values
148 int cp_number; // sequence number
149};
150
151/*
152 * All the current matches are stored in a list.
153 * "compl_first_match" points to the start of the list.
154 * "compl_curr_match" points to the currently selected entry.
155 * "compl_shown_match" is different from compl_curr_match during
156 * ins_compl_get_exp().
157 */
158static compl_T *compl_first_match = NULL;
159static compl_T *compl_curr_match = NULL;
160static compl_T *compl_shown_match = NULL;
161static compl_T *compl_old_match = NULL;
162
163/* After using a cursor key <Enter> selects a match in the popup menu,
164 * otherwise it inserts a line break. */
165static int compl_enter_selects = FALSE;
166
167/* When "compl_leader" is not NULL only matches that start with this string
168 * are used. */
169static char_u *compl_leader = NULL;
170
171static int compl_get_longest = FALSE; /* put longest common string
172 in compl_leader */
173
174static int compl_no_insert = FALSE; /* FALSE: select & insert
175 TRUE: noinsert */
176static int compl_no_select = FALSE; /* FALSE: select & insert
177 TRUE: noselect */
178
179static bool compl_used_match; // Selected one of the matches.
180 // When false the match was edited or using
181 // the longest common string.
182
183static int compl_was_interrupted = FALSE; /* didn't finish finding
184 completions. */
185
186static int compl_restarting = FALSE; /* don't insert match */
187
188// When the first completion is done "compl_started" is set. When it's
189// false the word to be completed must be located.
190static bool compl_started = false;
191
192// Which Ctrl-X mode are we in?
193static int ctrl_x_mode = CTRL_X_NORMAL;
194
195static int compl_matches = 0;
196static char_u *compl_pattern = NULL;
197static int compl_direction = FORWARD;
198static int compl_shows_dir = FORWARD;
199static int compl_pending = 0; /* > 1 for postponed CTRL-N */
200static pos_T compl_startpos;
201static colnr_T compl_col = 0; /* column where the text starts
202 * that is being completed */
203static char_u *compl_orig_text = NULL; /* text as it was before
204 * completion started */
205static int compl_cont_mode = 0;
206static expand_T compl_xp;
207
208static int compl_opt_refresh_always = FALSE;
209
210static int pum_selected_item = -1;
211
212/// state for pum_ext_select_item.
213struct {
214 bool active;
215 int item;
216 bool insert;
217 bool finish;
218} pum_want;
219
220typedef struct insert_state {
221 VimState state;
222 cmdarg_T *ca;
223 int mincol;
224 int cmdchar;
225 int startln;
226 long count;
227 int c;
228 int lastc;
229 int i;
230 bool did_backspace; // previous char was backspace
231 bool line_is_white; // line is empty before insert
232 linenr_T old_topline; // topline before insertion
233 int old_topfill;
234 int inserted_space; // just inserted a space
235 int replaceState;
236 int did_restart_edit; // remember if insert mode was restarted
237 // after a ctrl+o
238 bool nomove;
239 char_u *ptr;
240} InsertState;
241
242
243#ifdef INCLUDE_GENERATED_DECLARATIONS
244# include "edit.c.generated.h"
245#endif
246#define BACKSPACE_CHAR 1
247#define BACKSPACE_WORD 2
248#define BACKSPACE_WORD_NOT_SPACE 3
249#define BACKSPACE_LINE 4
250
251static size_t spell_bad_len = 0; /* length of located bad word */
252
253static colnr_T Insstart_textlen; /* length of line when insert started */
254static colnr_T Insstart_blank_vcol; /* vcol for first inserted blank */
255static bool update_Insstart_orig = true; /* set Insstart_orig to Insstart */
256
257static char_u *last_insert = NULL; /* the text of the previous insert,
258 K_SPECIAL and CSI are escaped */
259static int last_insert_skip; /* nr of chars in front of previous insert */
260static int new_insert_skip; /* nr of chars in front of current insert */
261static int did_restart_edit; /* "restart_edit" when calling edit() */
262
263static bool can_cindent; // may do cindenting on this line
264
265static int old_indent = 0; /* for ^^D command in insert mode */
266
267static int revins_on; /* reverse insert mode on */
268static int revins_chars; /* how much to skip after edit */
269static int revins_legal; /* was the last char 'legal'? */
270static int revins_scol; /* start column of revins session */
271
272static int ins_need_undo; /* call u_save() before inserting a
273 char. Set when edit() is called.
274 after that arrow_used is used. */
275
276static bool did_add_space = false; // auto_format() added an extra space
277 // under the cursor
278static TriState dont_sync_undo = kFalse; // CTRL-G U prevents syncing undo
279 // for the next left/right cursor key
280
281static linenr_T o_lnum = 0;
282
283static void insert_enter(InsertState *s)
284{
285 s->did_backspace = true;
286 s->old_topfill = -1;
287 s->replaceState = REPLACE;
288 // Remember whether editing was restarted after CTRL-O
289 did_restart_edit = restart_edit;
290 // sleep before redrawing, needed for "CTRL-O :" that results in an
291 // error message
292 check_for_delay(true);
293 // set Insstart_orig to Insstart
294 update_Insstart_orig = true;
295
296 ins_compl_clear(); // clear stuff for CTRL-X mode
297
298 // Trigger InsertEnter autocommands. Do not do this for "r<CR>" or "grx".
299 if (s->cmdchar != 'r' && s->cmdchar != 'v') {
300 pos_T save_cursor = curwin->w_cursor;
301
302 if (s->cmdchar == 'R') {
303 s->ptr = (char_u *)"r";
304 } else if (s->cmdchar == 'V') {
305 s->ptr = (char_u *)"v";
306 } else {
307 s->ptr = (char_u *)"i";
308 }
309
310 set_vim_var_string(VV_INSERTMODE, (char *) s->ptr, 1);
311 set_vim_var_string(VV_CHAR, NULL, -1);
312 ins_apply_autocmds(EVENT_INSERTENTER);
313
314 // Make sure the cursor didn't move. Do call check_cursor_col() in
315 // case the text was modified. Since Insert mode was not started yet
316 // a call to check_cursor_col() may move the cursor, especially with
317 // the "A" command, thus set State to avoid that. Also check that the
318 // line number is still valid (lines may have been deleted).
319 // Do not restore if v:char was set to a non-empty string.
320 if (!equalpos(curwin->w_cursor, save_cursor)
321 && *get_vim_var_str(VV_CHAR) == NUL
322 && save_cursor.lnum <= curbuf->b_ml.ml_line_count) {
323 int save_state = State;
324
325 curwin->w_cursor = save_cursor;
326 State = INSERT;
327 check_cursor_col();
328 State = save_state;
329 }
330 }
331
332 // When doing a paste with the middle mouse button, Insstart is set to
333 // where the paste started.
334 if (where_paste_started.lnum != 0) {
335 Insstart = where_paste_started;
336 } else {
337 Insstart = curwin->w_cursor;
338 if (s->startln) {
339 Insstart.col = 0;
340 }
341 }
342
343 Insstart_textlen = (colnr_T)linetabsize(get_cursor_line_ptr());
344 Insstart_blank_vcol = MAXCOL;
345
346 if (!did_ai) {
347 ai_col = 0;
348 }
349
350 if (s->cmdchar != NUL && restart_edit == 0) {
351 ResetRedobuff();
352 AppendNumberToRedobuff(s->count);
353 if (s->cmdchar == 'V' || s->cmdchar == 'v') {
354 // "gR" or "gr" command
355 AppendCharToRedobuff('g');
356 AppendCharToRedobuff((s->cmdchar == 'v') ? 'r' : 'R');
357 } else {
358 AppendCharToRedobuff(s->cmdchar);
359 if (s->cmdchar == 'g') { // "gI" command
360 AppendCharToRedobuff('I');
361 } else if (s->cmdchar == 'r') { // "r<CR>" command
362 s->count = 1; // insert only one <CR>
363 }
364 }
365 }
366
367 if (s->cmdchar == 'R') {
368 State = REPLACE;
369 } else if (s->cmdchar == 'V' || s->cmdchar == 'v') {
370 State = VREPLACE;
371 s->replaceState = VREPLACE;
372 orig_line_count = curbuf->b_ml.ml_line_count;
373 vr_lines_changed = 1;
374 } else {
375 State = INSERT;
376 }
377
378 stop_insert_mode = false;
379
380 // Need to recompute the cursor position, it might move when the cursor is
381 // on a TAB or special character.
382 curs_columns(true);
383
384 // Enable langmap or IME, indicated by 'iminsert'.
385 // Note that IME may enabled/disabled without us noticing here, thus the
386 // 'iminsert' value may not reflect what is actually used. It is updated
387 // when hitting <Esc>.
388 if (curbuf->b_p_iminsert == B_IMODE_LMAP) {
389 State |= LANGMAP;
390 }
391
392 setmouse();
393 clear_showcmd();
394 // there is no reverse replace mode
395 revins_on = (State == INSERT && p_ri);
396 if (revins_on) {
397 undisplay_dollar();
398 }
399 revins_chars = 0;
400 revins_legal = 0;
401 revins_scol = -1;
402
403 // Handle restarting Insert mode.
404 // Don't do this for "CTRL-O ." (repeat an insert): we get here with
405 // restart_edit non-zero, and something in the stuff buffer.
406 if (restart_edit != 0 && stuff_empty()) {
407 // After a paste we consider text typed to be part of the insert for
408 // the pasted text. You can backspace over the pasted text too.
409 if (where_paste_started.lnum) {
410 arrow_used = false;
411 } else {
412 arrow_used = true;
413 }
414 restart_edit = 0;
415
416 // If the cursor was after the end-of-line before the CTRL-O and it is
417 // now at the end-of-line, put it after the end-of-line (this is not
418 // correct in very rare cases).
419 // Also do this if curswant is greater than the current virtual
420 // column. Eg after "^O$" or "^O80|".
421 validate_virtcol();
422 update_curswant();
423 if (((ins_at_eol && curwin->w_cursor.lnum == o_lnum)
424 || curwin->w_curswant > curwin->w_virtcol)
425 && *(s->ptr = get_cursor_line_ptr() + curwin->w_cursor.col) != NUL) {
426 if (s->ptr[1] == NUL) {
427 ++curwin->w_cursor.col;
428 } else if (has_mbyte) {
429 s->i = (*mb_ptr2len)(s->ptr);
430 if (s->ptr[s->i] == NUL) {
431 curwin->w_cursor.col += s->i;
432 }
433 }
434 }
435 ins_at_eol = false;
436 } else {
437 arrow_used = false;
438 }
439
440 // we are in insert mode now, don't need to start it anymore
441 need_start_insertmode = false;
442
443 // Need to save the line for undo before inserting the first char.
444 ins_need_undo = true;
445
446 where_paste_started.lnum = 0;
447 can_cindent = true;
448 // The cursor line is not in a closed fold, unless 'insertmode' is set or
449 // restarting.
450 if (!p_im && did_restart_edit == 0) {
451 foldOpenCursor();
452 }
453
454 // If 'showmode' is set, show the current (insert/replace/..) mode.
455 // A warning message for changing a readonly file is given here, before
456 // actually changing anything. It's put after the mode, if any.
457 s->i = 0;
458 if (p_smd && msg_silent == 0) {
459 s->i = showmode();
460 }
461
462 if (!p_im && did_restart_edit == 0) {
463 change_warning(s->i == 0 ? 0 : s->i + 1);
464 }
465
466 ui_cursor_shape(); /* may show different cursor shape */
467 do_digraph(-1); /* clear digraphs */
468
469 // Get the current length of the redo buffer, those characters have to be
470 // skipped if we want to get to the inserted characters.
471 s->ptr = get_inserted();
472 if (s->ptr == NULL) {
473 new_insert_skip = 0;
474 } else {
475 new_insert_skip = (int)STRLEN(s->ptr);
476 xfree(s->ptr);
477 }
478
479 old_indent = 0;
480
481 do {
482 state_enter(&s->state);
483 // If s->count != 0, `ins_esc` will prepare the redo buffer for reprocessing
484 // and return false, causing `state_enter` to be called again.
485 } while (!ins_esc(&s->count, s->cmdchar, s->nomove));
486
487 // Always update o_lnum, so that a "CTRL-O ." that adds a line
488 // still puts the cursor back after the inserted text.
489 if (ins_at_eol) {
490 o_lnum = curwin->w_cursor.lnum;
491 }
492
493 pum_check_clear();
494
495 foldUpdateAfterInsert();
496 // When CTRL-C was typed got_int will be set, with the result
497 // that the autocommands won't be executed. When mapped got_int
498 // is not set, but let's keep the behavior the same.
499 if (s->cmdchar != 'r' && s->cmdchar != 'v' && s->c != Ctrl_C) {
500 ins_apply_autocmds(EVENT_INSERTLEAVE);
501 }
502 did_cursorhold = false;
503}
504
505static int insert_check(VimState *state)
506{
507 InsertState *s = (InsertState *)state;
508
509 // If typed something may trigger CursorHoldI again.
510 if (s->c != K_EVENT
511 // but not in CTRL-X mode, a script can't restore the state
512 && ctrl_x_mode == CTRL_X_NORMAL) {
513 did_cursorhold = false;
514 }
515
516 // If the cursor was moved we didn't just insert a space */
517 if (arrow_used) {
518 s->inserted_space = false;
519 }
520
521 if (can_cindent
522 && cindent_on()
523 && ctrl_x_mode == CTRL_X_NORMAL
524 && !compl_started) {
525 insert_do_cindent(s);
526 }
527
528 if (!revins_legal) {
529 revins_scol = -1; // reset on illegal motions
530 } else {
531 revins_legal = 0;
532 }
533
534 if (arrow_used) { // don't repeat insert when arrow key used
535 s->count = 0;
536 }
537
538 if (update_Insstart_orig) {
539 Insstart_orig = Insstart;
540 }
541
542 if (stop_insert_mode && !pum_visible()) {
543 // ":stopinsert" used or 'insertmode' reset
544 s->count = 0;
545 return 0; // exit insert mode
546 }
547
548 // set curwin->w_curswant for next K_DOWN or K_UP
549 if (!arrow_used) {
550 curwin->w_set_curswant = true;
551 }
552
553 // If there is no typeahead may check for timestamps (e.g., for when a
554 // menu invoked a shell command).
555 if (stuff_empty()) {
556 did_check_timestamps = false;
557 if (need_check_timestamps) {
558 check_timestamps(false);
559 }
560 }
561
562 // When emsg() was called msg_scroll will have been set.
563 msg_scroll = false;
564
565
566 // Open fold at the cursor line, according to 'foldopen'.
567 if (fdo_flags & FDO_INSERT) {
568 foldOpenCursor();
569 }
570
571 // Close folds where the cursor isn't, according to 'foldclose'
572 if (!char_avail()) {
573 foldCheckClose();
574 }
575
576 // If we inserted a character at the last position of the last line in the
577 // window, scroll the window one line up. This avoids an extra redraw. This
578 // is detected when the cursor column is smaller after inserting something.
579 // Don't do this when the topline changed already, it has already been
580 // adjusted (by insertchar() calling open_line())).
581 if (curbuf->b_mod_set
582 && curwin->w_p_wrap
583 && !s->did_backspace
584 && curwin->w_topline == s->old_topline
585 && curwin->w_topfill == s->old_topfill) {
586 s->mincol = curwin->w_wcol;
587 validate_cursor_col();
588
589 if (curwin->w_wcol < s->mincol - curbuf->b_p_ts
590 && curwin->w_wrow == curwin->w_winrow
591 + curwin->w_height_inner - 1 - p_so
592 && (curwin->w_cursor.lnum != curwin->w_topline
593 || curwin->w_topfill > 0)) {
594 if (curwin->w_topfill > 0) {
595 --curwin->w_topfill;
596 } else if (hasFolding(curwin->w_topline, NULL, &s->old_topline)) {
597 set_topline(curwin, s->old_topline + 1);
598 } else {
599 set_topline(curwin, curwin->w_topline + 1);
600 }
601 }
602 }
603
604 // May need to adjust w_topline to show the cursor.
605 update_topline();
606
607 s->did_backspace = false;
608
609 validate_cursor(); // may set must_redraw
610
611 // Redraw the display when no characters are waiting.
612 // Also shows mode, ruler and positions cursor.
613 ins_redraw(true);
614
615 if (curwin->w_p_scb) {
616 do_check_scrollbind(true);
617 }
618
619 if (curwin->w_p_crb) {
620 do_check_cursorbind();
621 }
622
623 update_curswant();
624 s->old_topline = curwin->w_topline;
625 s->old_topfill = curwin->w_topfill;
626 s->lastc = s->c; // remember previous char for CTRL-D
627
628 // After using CTRL-G U the next cursor key will not break undo.
629 if (dont_sync_undo == kNone) {
630 dont_sync_undo = kTrue;
631 } else {
632 dont_sync_undo = kFalse;
633 }
634
635 return 1;
636}
637
638static int insert_execute(VimState *state, int key)
639{
640 if (key == K_IGNORE) {
641 return -1; // get another key
642 }
643 InsertState *s = (InsertState *)state;
644 s->c = key;
645
646 // Don't want K_EVENT with cursorhold for the second key, e.g., after CTRL-V.
647 if (key != K_EVENT) {
648 did_cursorhold = true;
649 }
650
651 if (p_hkmap && KeyTyped) {
652 s->c = hkmap(s->c); // Hebrew mode mapping
653 }
654
655 // Special handling of keys while the popup menu is visible or wanted
656 // and the cursor is still in the completed word. Only when there is
657 // a match, skip this when no matches were found.
658 if (compl_started
659 && pum_wanted()
660 && curwin->w_cursor.col >= compl_col
661 && (compl_shown_match == NULL
662 || compl_shown_match != compl_shown_match->cp_next)) {
663 // BS: Delete one character from "compl_leader".
664 if ((s->c == K_BS || s->c == Ctrl_H)
665 && curwin->w_cursor.col > compl_col
666 && (s->c = ins_compl_bs()) == NUL) {
667 return 1; // continue
668 }
669
670 // When no match was selected or it was edited.
671 if (!compl_used_match) {
672 // CTRL-L: Add one character from the current match to
673 // "compl_leader". Except when at the original match and
674 // there is nothing to add, CTRL-L works like CTRL-P then.
675 if (s->c == Ctrl_L
676 && (!CTRL_X_MODE_LINE_OR_EVAL(ctrl_x_mode)
677 || (compl_shown_match != NULL
678 && compl_shown_match->cp_str != NULL
679 && (int)STRLEN(compl_shown_match->cp_str)
680 > curwin->w_cursor.col - compl_col))) {
681 ins_compl_addfrommatch();
682 return 1; // continue
683 }
684
685 // A non-white character that fits in with the current
686 // completion: Add to "compl_leader".
687 if (ins_compl_accept_char(s->c)) {
688 // Trigger InsertCharPre.
689 char_u *str = do_insert_char_pre(s->c);
690 char_u *p;
691
692 if (str != NULL) {
693 for (p = str; *p != NUL; MB_PTR_ADV(p)) {
694 ins_compl_addleader(PTR2CHAR(p));
695 }
696 xfree(str);
697 } else {
698 ins_compl_addleader(s->c);
699 }
700 return 1; // continue
701 }
702
703 // Pressing CTRL-Y selects the current match. When
704 // compl_enter_selects is set the Enter key does the same.
705 if ((s->c == Ctrl_Y
706 || (compl_enter_selects
707 && (s->c == CAR || s->c == K_KENTER || s->c == NL)))
708 && stop_arrow() == OK) {
709 ins_compl_delete();
710 ins_compl_insert(false);
711 }
712 }
713 }
714
715 // Prepare for or stop CTRL-X mode. This doesn't do completion, but it does
716 // fix up the text when finishing completion.
717 compl_get_longest = false;
718 if (ins_compl_prep(s->c)) {
719 return 1; // continue
720 }
721
722 // CTRL-\ CTRL-N goes to Normal mode,
723 // CTRL-\ CTRL-G goes to mode selected with 'insertmode',
724 // CTRL-\ CTRL-O is like CTRL-O but without moving the cursor
725 if (s->c == Ctrl_BSL) {
726 // may need to redraw when no more chars available now
727 ins_redraw(false);
728 no_mapping++;
729 s->c = plain_vgetc();
730 no_mapping--;
731 if (s->c != Ctrl_N && s->c != Ctrl_G && s->c != Ctrl_O) {
732 // it's something else
733 vungetc(s->c);
734 s->c = Ctrl_BSL;
735 } else if (s->c == Ctrl_G && p_im) {
736 return 1; // continue
737 } else {
738 if (s->c == Ctrl_O) {
739 ins_ctrl_o();
740 ins_at_eol = false; // cursor keeps its column
741 s->nomove = true;
742 }
743 s->count = 0;
744 return 0;
745 }
746 }
747
748 s->c = do_digraph(s->c);
749
750 if ((s->c == Ctrl_V || s->c == Ctrl_Q) && ctrl_x_mode == CTRL_X_CMDLINE) {
751 insert_do_complete(s);
752 return 1;
753 }
754
755 if (s->c == Ctrl_V || s->c == Ctrl_Q) {
756 ins_ctrl_v();
757 s->c = Ctrl_V; // pretend CTRL-V is last typed character
758 return 1; // continue
759 }
760
761 if (cindent_on()
762 && ctrl_x_mode == 0) {
763 // A key name preceded by a bang means this key is not to be
764 // inserted. Skip ahead to the re-indenting below.
765 // A key name preceded by a star means that indenting has to be
766 // done before inserting the key.
767 s->line_is_white = inindent(0);
768 if (in_cinkeys(s->c, '!', s->line_is_white)) {
769 insert_do_cindent(s);
770 return 1; // continue
771 }
772
773 if (can_cindent && in_cinkeys(s->c, '*', s->line_is_white)
774 && stop_arrow() == OK) {
775 do_c_expr_indent();
776 }
777 }
778
779 if (curwin->w_p_rl)
780 switch (s->c) {
781 case K_LEFT: s->c = K_RIGHT; break;
782 case K_S_LEFT: s->c = K_S_RIGHT; break;
783 case K_C_LEFT: s->c = K_C_RIGHT; break;
784 case K_RIGHT: s->c = K_LEFT; break;
785 case K_S_RIGHT: s->c = K_S_LEFT; break;
786 case K_C_RIGHT: s->c = K_C_LEFT; break;
787 }
788
789 // If 'keymodel' contains "startsel", may start selection. If it
790 // does, a CTRL-O and c will be stuffed, we need to get these
791 // characters.
792 if (ins_start_select(s->c)) {
793 return 1; // continue
794 }
795
796 return insert_handle_key(s);
797}
798
799static int insert_handle_key(InsertState *s)
800{
801 // The big switch to handle a character in insert mode.
802 // TODO(tarruda): This could look better if a lookup table is used.
803 // (similar to normal mode `nv_cmds[]`)
804 switch (s->c) {
805 case ESC: // End input mode
806 if (echeck_abbr(ESC + ABBR_OFF)) {
807 break;
808 }
809 FALLTHROUGH;
810
811 case Ctrl_C: // End input mode
812 if (s->c == Ctrl_C && cmdwin_type != 0) {
813 // Close the cmdline window. */
814 cmdwin_result = K_IGNORE;
815 got_int = false; // don't stop executing autocommands et al
816 s->nomove = true;
817 return 0; // exit insert mode
818 }
819
820 // when 'insertmode' set, and not halfway through a mapping, don't leave
821 // Insert mode
822 if (goto_im()) {
823 if (got_int) {
824 (void)vgetc(); // flush all buffers
825 got_int = false;
826 } else {
827 vim_beep(BO_IM);
828 }
829 break;
830 }
831 return 0; // exit insert mode
832
833 case Ctrl_Z: // suspend when 'insertmode' set
834 if (!p_im) {
835 goto normalchar; // insert CTRL-Z as normal char
836 }
837 do_cmdline_cmd("stop");
838 ui_cursor_shape(); // may need to update cursor shape
839 break;
840
841 case Ctrl_O: // execute one command
842 if (ctrl_x_mode == CTRL_X_OMNI) {
843 insert_do_complete(s);
844 break;
845 }
846
847 if (echeck_abbr(Ctrl_O + ABBR_OFF)) {
848 break;
849 }
850
851 ins_ctrl_o();
852
853 // don't move the cursor left when 'virtualedit' has "onemore".
854 if (ve_flags & VE_ONEMORE) {
855 ins_at_eol = false;
856 s->nomove = true;
857 }
858
859 s->count = 0;
860 return 0; // exit insert mode
861
862 case K_INS: // toggle insert/replace mode
863 case K_KINS:
864 ins_insert(s->replaceState);
865 break;
866
867 case K_SELECT: // end of Select mode mapping - ignore
868 break;
869
870
871 case K_HELP: // Help key works like <ESC> <Help>
872 case K_F1:
873 case K_XF1:
874 stuffcharReadbuff(K_HELP);
875 if (p_im) {
876 need_start_insertmode = true;
877 }
878 return 0; // exit insert mode
879
880
881 case ' ':
882 if (mod_mask != MOD_MASK_CTRL) {
883 goto normalchar;
884 }
885 FALLTHROUGH;
886 case K_ZERO: // Insert the previously inserted text.
887 case NUL:
888 case Ctrl_A:
889 // For ^@ the trailing ESC will end the insert, unless there is an
890 // error.
891 if (stuff_inserted(NUL, 1L, (s->c == Ctrl_A)) == FAIL
892 && s->c != Ctrl_A && !p_im) {
893 return 0; // exit insert mode
894 }
895 s->inserted_space = false;
896 break;
897
898 case Ctrl_R: // insert the contents of a register
899 ins_reg();
900 auto_format(false, true);
901 s->inserted_space = false;
902 break;
903
904 case Ctrl_G: // commands starting with CTRL-G
905 ins_ctrl_g();
906 break;
907
908 case Ctrl_HAT: // switch input mode and/or langmap
909 ins_ctrl_hat();
910 break;
911
912 case Ctrl__: // switch between languages
913 if (!p_ari) {
914 goto normalchar;
915 }
916 ins_ctrl_();
917 break;
918
919 case Ctrl_D: // Make indent one shiftwidth smaller.
920 if (ctrl_x_mode == CTRL_X_PATH_DEFINES) {
921 insert_do_complete(s);
922 break;
923 }
924 FALLTHROUGH;
925
926 case Ctrl_T: // Make indent one shiftwidth greater.
927 if (s->c == Ctrl_T && ctrl_x_mode == CTRL_X_THESAURUS) {
928 if (check_compl_option(false)) {
929 insert_do_complete(s);
930 }
931 break;
932 }
933 ins_shift(s->c, s->lastc);
934 auto_format(false, true);
935 s->inserted_space = false;
936 break;
937
938 case K_DEL: // delete character under the cursor
939 case K_KDEL:
940 ins_del();
941 auto_format(false, true);
942 break;
943
944 case K_BS: // delete character before the cursor
945 case Ctrl_H:
946 s->did_backspace = ins_bs(s->c, BACKSPACE_CHAR, &s->inserted_space);
947 auto_format(false, true);
948 break;
949
950 case Ctrl_W: // delete word before the cursor
951 s->did_backspace = ins_bs(s->c, BACKSPACE_WORD, &s->inserted_space);
952 auto_format(false, true);
953 break;
954
955 case Ctrl_U: // delete all inserted text in current line
956 // CTRL-X CTRL-U completes with 'completefunc'.
957 if (ctrl_x_mode == CTRL_X_FUNCTION) {
958 insert_do_complete(s);
959 } else {
960 s->did_backspace = ins_bs(s->c, BACKSPACE_LINE, &s->inserted_space);
961 auto_format(false, true);
962 s->inserted_space = false;
963 }
964 break;
965
966 case K_LEFTMOUSE: // mouse keys
967 case K_LEFTMOUSE_NM:
968 case K_LEFTDRAG:
969 case K_LEFTRELEASE:
970 case K_LEFTRELEASE_NM:
971 case K_MIDDLEMOUSE:
972 case K_MIDDLEDRAG:
973 case K_MIDDLERELEASE:
974 case K_RIGHTMOUSE:
975 case K_RIGHTDRAG:
976 case K_RIGHTRELEASE:
977 case K_X1MOUSE:
978 case K_X1DRAG:
979 case K_X1RELEASE:
980 case K_X2MOUSE:
981 case K_X2DRAG:
982 case K_X2RELEASE:
983 ins_mouse(s->c);
984 break;
985
986 case K_MOUSEDOWN: // Default action for scroll wheel up: scroll up
987 ins_mousescroll(MSCR_DOWN);
988 break;
989
990 case K_MOUSEUP: // Default action for scroll wheel down: scroll down
991 ins_mousescroll(MSCR_UP);
992 break;
993
994 case K_MOUSELEFT: // Scroll wheel left
995 ins_mousescroll(MSCR_LEFT);
996 break;
997
998 case K_MOUSERIGHT: // Scroll wheel right
999 ins_mousescroll(MSCR_RIGHT);
1000 break;
1001
1002 case K_IGNORE: // Something mapped to nothing
1003 break;
1004
1005 case K_EVENT: // some event
1006 multiqueue_process_events(main_loop.events);
1007 goto check_pum;
1008
1009 case K_COMMAND: // some command
1010 do_cmdline(NULL, getcmdkeycmd, NULL, 0);
1011
1012check_pum:
1013 // TODO(bfredl): Not entirely sure this indirection is necessary
1014 // but doing like this ensures using nvim_select_popupmenu_item is
1015 // equivalent to selecting the item with a typed key.
1016 if (pum_want.active) {
1017 if (pum_visible()) {
1018 insert_do_complete(s);
1019 if (pum_want.finish) {
1020 // accept the item and stop completion
1021 ins_compl_prep(Ctrl_Y);
1022 }
1023 }
1024 pum_want.active = false;
1025 }
1026 break;
1027
1028 case K_HOME: // <Home>
1029 case K_KHOME:
1030 case K_S_HOME:
1031 case K_C_HOME:
1032 ins_home(s->c);
1033 break;
1034
1035 case K_END: // <End>
1036 case K_KEND:
1037 case K_S_END:
1038 case K_C_END:
1039 ins_end(s->c);
1040 break;
1041
1042 case K_LEFT: // <Left>
1043 if (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL)) {
1044 ins_s_left();
1045 } else {
1046 ins_left();
1047 }
1048 break;
1049
1050 case K_S_LEFT: // <S-Left>
1051 case K_C_LEFT:
1052 ins_s_left();
1053 break;
1054
1055 case K_RIGHT: // <Right>
1056 if (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL)) {
1057 ins_s_right();
1058 } else {
1059 ins_right();
1060 }
1061 break;
1062
1063 case K_S_RIGHT: // <S-Right>
1064 case K_C_RIGHT:
1065 ins_s_right();
1066 break;
1067
1068 case K_UP: // <Up>
1069 if (pum_visible()) {
1070 insert_do_complete(s);
1071 } else if (mod_mask & MOD_MASK_SHIFT) {
1072 ins_pageup();
1073 } else {
1074 ins_up(false);
1075 }
1076 break;
1077
1078 case K_S_UP: // <S-Up>
1079 case K_PAGEUP:
1080 case K_KPAGEUP:
1081 if (pum_visible()) {
1082 insert_do_complete(s);
1083 } else {
1084 ins_pageup();
1085 }
1086 break;
1087
1088 case K_DOWN: // <Down>
1089 if (pum_visible()) {
1090 insert_do_complete(s);
1091 } else if (mod_mask & MOD_MASK_SHIFT) {
1092 ins_pagedown();
1093 } else {
1094 ins_down(false);
1095 }
1096 break;
1097
1098 case K_S_DOWN: // <S-Down>
1099 case K_PAGEDOWN:
1100 case K_KPAGEDOWN:
1101 if (pum_visible()) {
1102 insert_do_complete(s);
1103 } else {
1104 ins_pagedown();
1105 }
1106 break;
1107
1108
1109 case K_S_TAB: // When not mapped, use like a normal TAB
1110 s->c = TAB;
1111 FALLTHROUGH;
1112
1113 case TAB: // TAB or Complete patterns along path
1114 if (ctrl_x_mode == CTRL_X_PATH_PATTERNS) {
1115 insert_do_complete(s);
1116 break;
1117 }
1118 s->inserted_space = false;
1119 if (ins_tab()) {
1120 goto normalchar; // insert TAB as a normal char
1121 }
1122 auto_format(false, true);
1123 break;
1124
1125 case K_KENTER: // <Enter>
1126 s->c = CAR;
1127 FALLTHROUGH;
1128 case CAR:
1129 case NL:
1130 // In a quickfix window a <CR> jumps to the error under the
1131 // cursor.
1132 if (bt_quickfix(curbuf) && s->c == CAR) {
1133 if (curwin->w_llist_ref == NULL) { // quickfix window
1134 do_cmdline_cmd(".cc");
1135 } else { // location list window
1136 do_cmdline_cmd(".ll");
1137 }
1138 break;
1139 }
1140 if (cmdwin_type != 0) {
1141 // Execute the command in the cmdline window.
1142 cmdwin_result = CAR;
1143 return 0;
1144 }
1145 if (!ins_eol(s->c) && !p_im) {
1146 return 0; // out of memory
1147 }
1148 auto_format(false, false);
1149 s->inserted_space = false;
1150 break;
1151
1152 case Ctrl_K: // digraph or keyword completion
1153 if (ctrl_x_mode == CTRL_X_DICTIONARY) {
1154 if (check_compl_option(true)) {
1155 insert_do_complete(s);
1156 }
1157 break;
1158 }
1159
1160 s->c = ins_digraph();
1161 if (s->c == NUL) {
1162 break;
1163 }
1164 goto normalchar;
1165
1166 case Ctrl_X: // Enter CTRL-X mode
1167 ins_ctrl_x();
1168 break;
1169
1170 case Ctrl_RSB: // Tag name completion after ^X
1171 if (ctrl_x_mode != CTRL_X_TAGS) {
1172 goto normalchar;
1173 } else {
1174 insert_do_complete(s);
1175 }
1176 break;
1177
1178 case Ctrl_F: // File name completion after ^X
1179 if (ctrl_x_mode != CTRL_X_FILES) {
1180 goto normalchar;
1181 } else {
1182 insert_do_complete(s);
1183 }
1184 break;
1185
1186 case 's': // Spelling completion after ^X
1187 case Ctrl_S:
1188 if (ctrl_x_mode != CTRL_X_SPELL) {
1189 goto normalchar;
1190 } else {
1191 insert_do_complete(s);
1192 }
1193 break;
1194
1195 case Ctrl_L: // Whole line completion after ^X
1196 if (ctrl_x_mode != CTRL_X_WHOLE_LINE) {
1197 // CTRL-L with 'insertmode' set: Leave Insert mode
1198 if (p_im) {
1199 if (echeck_abbr(Ctrl_L + ABBR_OFF)) {
1200 break;
1201 }
1202 return 0; // exit insert mode
1203 }
1204 goto normalchar;
1205 }
1206 FALLTHROUGH;
1207
1208 case Ctrl_P: // Do previous/next pattern completion
1209 case Ctrl_N:
1210 // if 'complete' is empty then plain ^P is no longer special,
1211 // but it is under other ^X modes
1212 if (*curbuf->b_p_cpt == NUL
1213 && (ctrl_x_mode == CTRL_X_NORMAL
1214 || ctrl_x_mode == CTRL_X_WHOLE_LINE)
1215 && !(compl_cont_status & CONT_LOCAL)) {
1216 goto normalchar;
1217 }
1218
1219 insert_do_complete(s);
1220 break;
1221
1222 case Ctrl_Y: // copy from previous line or scroll down
1223 case Ctrl_E: // copy from next line or scroll up
1224 s->c = ins_ctrl_ey(s->c);
1225 break;
1226
1227 default:
1228
1229normalchar:
1230 // Insert a normal character.
1231
1232 if (mod_mask == MOD_MASK_ALT || mod_mask == MOD_MASK_META) {
1233 // Unmapped ALT/META chord behaves like ESC+c. #8213
1234 stuffcharReadbuff(ESC);
1235 stuffcharReadbuff(s->c);
1236 break;
1237 }
1238
1239 if (!p_paste) {
1240 // Trigger InsertCharPre.
1241 char_u *str = do_insert_char_pre(s->c);
1242 char_u *p;
1243
1244 if (str != NULL) {
1245 if (*str != NUL && stop_arrow() != FAIL) {
1246 // Insert the new value of v:char literally.
1247 for (p = str; *p != NUL; MB_PTR_ADV(p)) {
1248 s->c = PTR2CHAR(p);
1249 if (s->c == CAR || s->c == K_KENTER || s->c == NL) {
1250 ins_eol(s->c);
1251 } else {
1252 ins_char(s->c);
1253 }
1254 }
1255 AppendToRedobuffLit(str, -1);
1256 }
1257 xfree(str);
1258 s->c = NUL;
1259 }
1260
1261 // If the new value is already inserted or an empty string
1262 // then don't insert any character.
1263 if (s->c == NUL)
1264 break;
1265 }
1266 // Try to perform smart-indenting.
1267 ins_try_si(s->c);
1268
1269 if (s->c == ' ') {
1270 s->inserted_space = true;
1271 if (inindent(0)) {
1272 can_cindent = false;
1273 }
1274 if (Insstart_blank_vcol == MAXCOL
1275 && curwin->w_cursor.lnum == Insstart.lnum) {
1276 Insstart_blank_vcol = get_nolist_virtcol();
1277 }
1278 }
1279
1280 // Insert a normal character and check for abbreviations on a
1281 // special character. Let CTRL-] expand abbreviations without
1282 // inserting it.
1283 if (vim_iswordc(s->c)
1284 || (!echeck_abbr(
1285 // Add ABBR_OFF for characters above 0x100, this is
1286 // what check_abbr() expects.
1287 (has_mbyte && s->c >= 0x100) ? (s->c + ABBR_OFF) : s->c)
1288 && s->c != Ctrl_RSB)) {
1289 insert_special(s->c, false, false);
1290 revins_legal++;
1291 revins_chars++;
1292 }
1293
1294 auto_format(false, true);
1295
1296 // When inserting a character the cursor line must never be in a
1297 // closed fold.
1298 foldOpenCursor();
1299 break;
1300 } // end of switch (s->c)
1301
1302 return 1; // continue
1303}
1304
1305static void insert_do_complete(InsertState *s)
1306{
1307 compl_busy = true;
1308 if (ins_complete(s->c, true) == FAIL) {
1309 compl_cont_status = 0;
1310 }
1311 compl_busy = false;
1312}
1313
1314static void insert_do_cindent(InsertState *s)
1315{
1316 // Indent now if a key was typed that is in 'cinkeys'.
1317 if (in_cinkeys(s->c, ' ', s->line_is_white)) {
1318 if (stop_arrow() == OK) {
1319 // re-indent the current line
1320 do_c_expr_indent();
1321 }
1322 }
1323}
1324
1325/// edit(): Start inserting text.
1326///
1327/// "cmdchar" can be:
1328/// 'i' normal insert command
1329/// 'a' normal append command
1330/// 'R' replace command
1331/// 'r' "r<CR>" command: insert one <CR>.
1332/// Note: count can be > 1, for redo, but still only one <CR> is inserted.
1333/// <Esc> is not used for redo.
1334/// 'g' "gI" command.
1335/// 'V' "gR" command for Virtual Replace mode.
1336/// 'v' "gr" command for single character Virtual Replace mode.
1337///
1338/// This function is not called recursively. For CTRL-O commands, it returns
1339/// and lets the caller handle the Normal-mode command.
1340///
1341/// @param cmdchar command that started the insert
1342/// @param startln if true, insert at start of line
1343/// @param count repeat count for the command
1344///
1345/// @return true if a CTRL-O command caused the return (insert mode pending).
1346bool edit(int cmdchar, bool startln, long count)
1347{
1348 if (curbuf->terminal) {
1349 if (ex_normal_busy) {
1350 // Do not enter terminal mode from ex_normal(), which would cause havoc
1351 // (such as terminal-mode recursiveness). Instead set a flag to force-set
1352 // the value of `restart_edit` before `ex_normal` returns.
1353 restart_edit = 'i';
1354 force_restart_edit = true;
1355 } else {
1356 terminal_enter();
1357 }
1358 return false;
1359 }
1360
1361 // Don't allow inserting in the sandbox.
1362 if (sandbox != 0) {
1363 EMSG(_(e_sandbox));
1364 return false;
1365 }
1366
1367 // Don't allow changes in the buffer while editing the cmdline. The
1368 // caller of getcmdline() may get confused.
1369 if (textlock != 0) {
1370 EMSG(_(e_secure));
1371 return false;
1372 }
1373
1374 // Don't allow recursive insert mode when busy with completion.
1375 if (compl_started || compl_busy || pum_visible()) {
1376 EMSG(_(e_secure));
1377 return false;
1378 }
1379
1380 InsertState state, *s = &state;
1381 memset(s, 0, sizeof(InsertState));
1382 s->state.execute = insert_execute;
1383 s->state.check = insert_check;
1384 s->cmdchar = cmdchar;
1385 s->startln = startln;
1386 s->count = count;
1387 insert_enter(s);
1388 return s->c == Ctrl_O;
1389}
1390
1391/*
1392 * Redraw for Insert mode.
1393 * This is postponed until getting the next character to make '$' in the 'cpo'
1394 * option work correctly.
1395 * Only redraw when there are no characters available. This speeds up
1396 * inserting sequences of characters (e.g., for CTRL-R).
1397 */
1398static void
1399ins_redraw (
1400 int ready /* not busy with something */
1401)
1402{
1403 bool conceal_cursor_moved = false;
1404
1405 if (char_avail())
1406 return;
1407
1408 // Trigger CursorMoved if the cursor moved. Not when the popup menu is
1409 // visible, the command might delete it.
1410 if (ready && (has_event(EVENT_CURSORMOVEDI) || curwin->w_p_cole > 0)
1411 && !equalpos(curwin->w_last_cursormoved, curwin->w_cursor)
1412 && !pum_visible()) {
1413 // Need to update the screen first, to make sure syntax
1414 // highlighting is correct after making a change (e.g., inserting
1415 // a "(". The autocommand may also require a redraw, so it's done
1416 // again below, unfortunately.
1417 if (syntax_present(curwin) && must_redraw) {
1418 update_screen(0);
1419 }
1420 if (has_event(EVENT_CURSORMOVEDI)) {
1421 // Make sure curswant is correct, an autocommand may call
1422 // getcurpos()
1423 update_curswant();
1424 ins_apply_autocmds(EVENT_CURSORMOVEDI);
1425 }
1426 conceal_cursor_moved = true;
1427 curwin->w_last_cursormoved = curwin->w_cursor;
1428 }
1429
1430 // Trigger TextChangedI if changedtick differs.
1431 if (ready && has_event(EVENT_TEXTCHANGEDI)
1432 && curbuf->b_last_changedtick != buf_get_changedtick(curbuf)
1433 && !pum_visible()) {
1434 aco_save_T aco;
1435 varnumber_T tick = buf_get_changedtick(curbuf);
1436
1437 // save and restore curwin and curbuf, in case the autocmd changes them
1438 aucmd_prepbuf(&aco, curbuf);
1439 apply_autocmds(EVENT_TEXTCHANGEDI, NULL, NULL, false, curbuf);
1440 aucmd_restbuf(&aco);
1441 curbuf->b_last_changedtick = buf_get_changedtick(curbuf);
1442 if (tick != buf_get_changedtick(curbuf)) { // see ins_apply_autocmds()
1443 u_save(curwin->w_cursor.lnum,
1444 (linenr_T)(curwin->w_cursor.lnum + 1));
1445 }
1446 }
1447
1448 // Trigger TextChangedP if changedtick differs. When the popupmenu closes
1449 // TextChangedI will need to trigger for backwards compatibility, thus use
1450 // different b_last_changedtick* variables.
1451 if (ready && has_event(EVENT_TEXTCHANGEDP)
1452 && curbuf->b_last_changedtick_pum != buf_get_changedtick(curbuf)
1453 && pum_visible()) {
1454 aco_save_T aco;
1455 varnumber_T tick = buf_get_changedtick(curbuf);
1456
1457 // save and restore curwin and curbuf, in case the autocmd changes them
1458 aucmd_prepbuf(&aco, curbuf);
1459 apply_autocmds(EVENT_TEXTCHANGEDP, NULL, NULL, false, curbuf);
1460 aucmd_restbuf(&aco);
1461 curbuf->b_last_changedtick_pum = buf_get_changedtick(curbuf);
1462 if (tick != buf_get_changedtick(curbuf)) { // see ins_apply_autocmds()
1463 u_save(curwin->w_cursor.lnum,
1464 (linenr_T)(curwin->w_cursor.lnum + 1));
1465 }
1466 }
1467
1468 if (curwin->w_p_cole > 0 && conceal_cursor_line(curwin)
1469 && conceal_cursor_moved) {
1470 redrawWinline(curwin, curwin->w_cursor.lnum);
1471 }
1472
1473 pum_check_clear();
1474 if (must_redraw) {
1475 update_screen(0);
1476 } else if (clear_cmdline || redraw_cmdline) {
1477 showmode(); // clear cmdline and show mode
1478 }
1479 showruler(false);
1480 setcursor();
1481 emsg_on_display = FALSE; /* may remove error message now */
1482}
1483
1484/*
1485 * Handle a CTRL-V or CTRL-Q typed in Insert mode.
1486 */
1487static void ins_ctrl_v(void)
1488{
1489 int c;
1490 int did_putchar = FALSE;
1491
1492 /* may need to redraw when no more chars available now */
1493 ins_redraw(FALSE);
1494
1495 if (redrawing() && !char_avail()) {
1496 edit_putchar('^', TRUE);
1497 did_putchar = TRUE;
1498 }
1499 AppendToRedobuff(CTRL_V_STR);
1500
1501 add_to_showcmd_c(Ctrl_V);
1502
1503 c = get_literal();
1504 if (did_putchar)
1505 /* when the line fits in 'columns' the '^' is at the start of the next
1506 * line and will not removed by the redraw */
1507 edit_unputchar();
1508 clear_showcmd();
1509 insert_special(c, true, true);
1510 revins_chars++;
1511 revins_legal++;
1512}
1513
1514/*
1515 * Put a character directly onto the screen. It's not stored in a buffer.
1516 * Used while handling CTRL-K, CTRL-V, etc. in Insert mode.
1517 */
1518static int pc_status;
1519#define PC_STATUS_UNSET 0 /* pc_bytes was not set */
1520#define PC_STATUS_RIGHT 1 /* right halve of double-wide char */
1521#define PC_STATUS_LEFT 2 /* left halve of double-wide char */
1522#define PC_STATUS_SET 3 /* pc_bytes was filled */
1523static char_u pc_bytes[MB_MAXBYTES + 1]; /* saved bytes */
1524static int pc_attr;
1525static int pc_row;
1526static int pc_col;
1527
1528void edit_putchar(int c, int highlight)
1529{
1530 int attr;
1531
1532 if (curwin->w_grid.chars != NULL || default_grid.chars != NULL) {
1533 update_topline(); // just in case w_topline isn't valid
1534 validate_cursor();
1535 if (highlight) {
1536 attr = HL_ATTR(HLF_8);
1537 } else {
1538 attr = 0;
1539 }
1540 pc_row = curwin->w_wrow;
1541 pc_col = 0;
1542 pc_status = PC_STATUS_UNSET;
1543 if (curwin->w_p_rl) {
1544 pc_col += curwin->w_grid.Columns - 1 - curwin->w_wcol;
1545 if (has_mbyte) {
1546 int fix_col = grid_fix_col(&curwin->w_grid, pc_col, pc_row);
1547
1548 if (fix_col != pc_col) {
1549 grid_putchar(&curwin->w_grid, ' ', pc_row, fix_col, attr);
1550 curwin->w_wcol--;
1551 pc_status = PC_STATUS_RIGHT;
1552 }
1553 }
1554 } else {
1555 pc_col += curwin->w_wcol;
1556 if (grid_lefthalve(&curwin->w_grid, pc_row, pc_col)) {
1557 pc_status = PC_STATUS_LEFT;
1558 }
1559 }
1560
1561 /* save the character to be able to put it back */
1562 if (pc_status == PC_STATUS_UNSET) {
1563 grid_getbytes(&curwin->w_grid, pc_row, pc_col, pc_bytes, &pc_attr);
1564 pc_status = PC_STATUS_SET;
1565 }
1566 grid_putchar(&curwin->w_grid, c, pc_row, pc_col, attr);
1567 }
1568}
1569
1570/*
1571 * Undo the previous edit_putchar().
1572 */
1573void edit_unputchar(void)
1574{
1575 if (pc_status != PC_STATUS_UNSET && pc_row >= msg_scrolled) {
1576 if (pc_status == PC_STATUS_RIGHT) {
1577 curwin->w_wcol++;
1578 }
1579 if (pc_status == PC_STATUS_RIGHT || pc_status == PC_STATUS_LEFT) {
1580 redrawWinline(curwin, curwin->w_cursor.lnum);
1581 } else {
1582 grid_puts(&curwin->w_grid, pc_bytes, pc_row - msg_scrolled, pc_col,
1583 pc_attr);
1584 }
1585 }
1586}
1587
1588/*
1589 * Called when p_dollar is set: display a '$' at the end of the changed text
1590 * Only works when cursor is in the line that changes.
1591 */
1592void display_dollar(colnr_T col)
1593{
1594 colnr_T save_col;
1595
1596 if (!redrawing())
1597 return;
1598
1599 save_col = curwin->w_cursor.col;
1600 curwin->w_cursor.col = col;
1601
1602 // If on the last byte of a multi-byte move to the first byte.
1603 char_u *p = get_cursor_line_ptr();
1604 curwin->w_cursor.col -= utf_head_off(p, p + col);
1605 curs_columns(false); // Recompute w_wrow and w_wcol
1606 if (curwin->w_wcol < curwin->w_grid.Columns) {
1607 edit_putchar('$', false);
1608 dollar_vcol = curwin->w_virtcol;
1609 }
1610 curwin->w_cursor.col = save_col;
1611}
1612
1613/*
1614 * Call this function before moving the cursor from the normal insert position
1615 * in insert mode.
1616 */
1617static void undisplay_dollar(void)
1618{
1619 if (dollar_vcol >= 0) {
1620 dollar_vcol = -1;
1621 redrawWinline(curwin, curwin->w_cursor.lnum);
1622 }
1623}
1624
1625/*
1626 * Insert an indent (for <Tab> or CTRL-T) or delete an indent (for CTRL-D).
1627 * Keep the cursor on the same character.
1628 * type == INDENT_INC increase indent (for CTRL-T or <Tab>)
1629 * type == INDENT_DEC decrease indent (for CTRL-D)
1630 * type == INDENT_SET set indent to "amount"
1631 * if round is TRUE, round the indent to 'shiftwidth' (only with _INC and _Dec).
1632 */
1633void
1634change_indent (
1635 int type,
1636 int amount,
1637 int round,
1638 int replaced, /* replaced character, put on replace stack */
1639 int call_changed_bytes /* call changed_bytes() */
1640)
1641{
1642 int vcol;
1643 int last_vcol;
1644 int insstart_less; /* reduction for Insstart.col */
1645 int new_cursor_col;
1646 int i;
1647 char_u *ptr;
1648 int save_p_list;
1649 int start_col;
1650 colnr_T vc;
1651 colnr_T orig_col = 0; /* init for GCC */
1652 char_u *new_line, *orig_line = NULL; /* init for GCC */
1653
1654 /* VREPLACE mode needs to know what the line was like before changing */
1655 if (State & VREPLACE_FLAG) {
1656 orig_line = vim_strsave(get_cursor_line_ptr()); /* Deal with NULL below */
1657 orig_col = curwin->w_cursor.col;
1658 }
1659
1660 /* for the following tricks we don't want list mode */
1661 save_p_list = curwin->w_p_list;
1662 curwin->w_p_list = FALSE;
1663 vc = getvcol_nolist(&curwin->w_cursor);
1664 vcol = vc;
1665
1666 /*
1667 * For Replace mode we need to fix the replace stack later, which is only
1668 * possible when the cursor is in the indent. Remember the number of
1669 * characters before the cursor if it's possible.
1670 */
1671 start_col = curwin->w_cursor.col;
1672
1673 /* determine offset from first non-blank */
1674 new_cursor_col = curwin->w_cursor.col;
1675 beginline(BL_WHITE);
1676 new_cursor_col -= curwin->w_cursor.col;
1677
1678 insstart_less = curwin->w_cursor.col;
1679
1680 /*
1681 * If the cursor is in the indent, compute how many screen columns the
1682 * cursor is to the left of the first non-blank.
1683 */
1684 if (new_cursor_col < 0)
1685 vcol = get_indent() - vcol;
1686
1687 if (new_cursor_col > 0) /* can't fix replace stack */
1688 start_col = -1;
1689
1690 /*
1691 * Set the new indent. The cursor will be put on the first non-blank.
1692 */
1693 if (type == INDENT_SET)
1694 (void)set_indent(amount, call_changed_bytes ? SIN_CHANGED : 0);
1695 else {
1696 int save_State = State;
1697
1698 /* Avoid being called recursively. */
1699 if (State & VREPLACE_FLAG)
1700 State = INSERT;
1701 shift_line(type == INDENT_DEC, round, 1, call_changed_bytes);
1702 State = save_State;
1703 }
1704 insstart_less -= curwin->w_cursor.col;
1705
1706 /*
1707 * Try to put cursor on same character.
1708 * If the cursor is at or after the first non-blank in the line,
1709 * compute the cursor column relative to the column of the first
1710 * non-blank character.
1711 * If we are not in insert mode, leave the cursor on the first non-blank.
1712 * If the cursor is before the first non-blank, position it relative
1713 * to the first non-blank, counted in screen columns.
1714 */
1715 if (new_cursor_col >= 0) {
1716 /*
1717 * When changing the indent while the cursor is touching it, reset
1718 * Insstart_col to 0.
1719 */
1720 if (new_cursor_col == 0)
1721 insstart_less = MAXCOL;
1722 new_cursor_col += curwin->w_cursor.col;
1723 } else if (!(State & INSERT))
1724 new_cursor_col = curwin->w_cursor.col;
1725 else {
1726 /*
1727 * Compute the screen column where the cursor should be.
1728 */
1729 vcol = get_indent() - vcol;
1730 curwin->w_virtcol = (colnr_T)((vcol < 0) ? 0 : vcol);
1731
1732 /*
1733 * Advance the cursor until we reach the right screen column.
1734 */
1735 vcol = last_vcol = 0;
1736 new_cursor_col = -1;
1737 ptr = get_cursor_line_ptr();
1738 while (vcol <= (int)curwin->w_virtcol) {
1739 last_vcol = vcol;
1740 if (has_mbyte && new_cursor_col >= 0)
1741 new_cursor_col += (*mb_ptr2len)(ptr + new_cursor_col);
1742 else
1743 ++new_cursor_col;
1744 vcol += lbr_chartabsize(ptr, ptr + new_cursor_col, (colnr_T)vcol);
1745 }
1746 vcol = last_vcol;
1747
1748 /*
1749 * May need to insert spaces to be able to position the cursor on
1750 * the right screen column.
1751 */
1752 if (vcol != (int)curwin->w_virtcol) {
1753 curwin->w_cursor.col = (colnr_T)new_cursor_col;
1754 i = (int)curwin->w_virtcol - vcol;
1755 ptr = xmallocz(i);
1756 memset(ptr, ' ', i);
1757 new_cursor_col += i;
1758 ins_str(ptr);
1759 xfree(ptr);
1760 }
1761
1762 /*
1763 * When changing the indent while the cursor is in it, reset
1764 * Insstart_col to 0.
1765 */
1766 insstart_less = MAXCOL;
1767 }
1768
1769 curwin->w_p_list = save_p_list;
1770
1771 if (new_cursor_col <= 0)
1772 curwin->w_cursor.col = 0;
1773 else
1774 curwin->w_cursor.col = (colnr_T)new_cursor_col;
1775 curwin->w_set_curswant = TRUE;
1776 changed_cline_bef_curs();
1777
1778 /*
1779 * May have to adjust the start of the insert.
1780 */
1781 if (State & INSERT) {
1782 if (curwin->w_cursor.lnum == Insstart.lnum && Insstart.col != 0) {
1783 if ((int)Insstart.col <= insstart_less)
1784 Insstart.col = 0;
1785 else
1786 Insstart.col -= insstart_less;
1787 }
1788 if ((int)ai_col <= insstart_less)
1789 ai_col = 0;
1790 else
1791 ai_col -= insstart_less;
1792 }
1793
1794 /*
1795 * For REPLACE mode, may have to fix the replace stack, if it's possible.
1796 * If the number of characters before the cursor decreased, need to pop a
1797 * few characters from the replace stack.
1798 * If the number of characters before the cursor increased, need to push a
1799 * few NULs onto the replace stack.
1800 */
1801 if (REPLACE_NORMAL(State) && start_col >= 0) {
1802 while (start_col > (int)curwin->w_cursor.col) {
1803 replace_join(0); /* remove a NUL from the replace stack */
1804 --start_col;
1805 }
1806 while (start_col < (int)curwin->w_cursor.col || replaced) {
1807 replace_push(NUL);
1808 if (replaced) {
1809 replace_push(replaced);
1810 replaced = NUL;
1811 }
1812 ++start_col;
1813 }
1814 }
1815
1816 /*
1817 * For VREPLACE mode, we also have to fix the replace stack. In this case
1818 * it is always possible because we backspace over the whole line and then
1819 * put it back again the way we wanted it.
1820 */
1821 if (State & VREPLACE_FLAG) {
1822 /* Save new line */
1823 new_line = vim_strsave(get_cursor_line_ptr());
1824
1825 /* We only put back the new line up to the cursor */
1826 new_line[curwin->w_cursor.col] = NUL;
1827
1828 // Put back original line
1829 ml_replace(curwin->w_cursor.lnum, orig_line, false);
1830 curwin->w_cursor.col = orig_col;
1831
1832 /* Backspace from cursor to start of line */
1833 backspace_until_column(0);
1834
1835 /* Insert new stuff into line again */
1836 ins_bytes(new_line);
1837
1838 xfree(new_line);
1839 }
1840}
1841
1842/*
1843 * Truncate the space at the end of a line. This is to be used only in an
1844 * insert mode. It handles fixing the replace stack for REPLACE and VREPLACE
1845 * modes.
1846 */
1847void truncate_spaces(char_u *line)
1848{
1849 int i;
1850
1851 /* find start of trailing white space */
1852 for (i = (int)STRLEN(line) - 1; i >= 0 && ascii_iswhite(line[i]); i--) {
1853 if (State & REPLACE_FLAG)
1854 replace_join(0); /* remove a NUL from the replace stack */
1855 }
1856 line[i + 1] = NUL;
1857}
1858
1859/*
1860 * Backspace the cursor until the given column. Handles REPLACE and VREPLACE
1861 * modes correctly. May also be used when not in insert mode at all.
1862 * Will attempt not to go before "col" even when there is a composing
1863 * character.
1864 */
1865void backspace_until_column(int col)
1866{
1867 while ((int)curwin->w_cursor.col > col) {
1868 curwin->w_cursor.col--;
1869 if (State & REPLACE_FLAG)
1870 replace_do_bs(col);
1871 else if (!del_char_after_col(col))
1872 break;
1873 }
1874}
1875
1876/// Like del_char(), but make sure not to go before column "limit_col".
1877/// Only matters when there are composing characters.
1878///
1879/// @param limit_col only delete the character if it is after this column
1880//
1881/// @return true when something was deleted.
1882static bool del_char_after_col(int limit_col)
1883{
1884 if (enc_utf8 && limit_col >= 0) {
1885 colnr_T ecol = curwin->w_cursor.col + 1;
1886
1887 // Make sure the cursor is at the start of a character, but
1888 // skip forward again when going too far back because of a
1889 // composing character.
1890 mb_adjust_cursor();
1891 while (curwin->w_cursor.col < (colnr_T)limit_col) {
1892 int l = utf_ptr2len(get_cursor_pos_ptr());
1893
1894 if (l == 0) { // end of line
1895 break;
1896 }
1897 curwin->w_cursor.col += l;
1898 }
1899 if (*get_cursor_pos_ptr() == NUL || curwin->w_cursor.col == ecol) {
1900 return false;
1901 }
1902 del_bytes(ecol - curwin->w_cursor.col, false, true);
1903 } else {
1904 del_char(false);
1905 }
1906 return true;
1907}
1908
1909/*
1910 * CTRL-X pressed in Insert mode.
1911 */
1912static void ins_ctrl_x(void)
1913{
1914 /* CTRL-X after CTRL-X CTRL-V doesn't do anything, so that CTRL-X
1915 * CTRL-V works like CTRL-N */
1916 if (ctrl_x_mode != CTRL_X_CMDLINE) {
1917 /* if the next ^X<> won't ADD nothing, then reset
1918 * compl_cont_status */
1919 if (compl_cont_status & CONT_N_ADDS)
1920 compl_cont_status |= CONT_INTRPT;
1921 else
1922 compl_cont_status = 0;
1923 /* We're not sure which CTRL-X mode it will be yet */
1924 ctrl_x_mode = CTRL_X_NOT_DEFINED_YET;
1925 edit_submode = (char_u *)_(CTRL_X_MSG(ctrl_x_mode));
1926 edit_submode_pre = NULL;
1927 showmode();
1928 }
1929}
1930
1931// Whether other than default completion has been selected.
1932bool ctrl_x_mode_not_default(void)
1933{
1934 return ctrl_x_mode != CTRL_X_NORMAL;
1935}
1936
1937// Whether CTRL-X was typed without a following character.
1938bool ctrl_x_mode_not_defined_yet(void)
1939{
1940 return ctrl_x_mode == CTRL_X_NOT_DEFINED_YET;
1941}
1942
1943
1944/// Check that the "dict" or "tsr" option can be used.
1945///
1946/// @param dict_opt check "dict" when true, "tsr" when false.
1947static bool check_compl_option(bool dict_opt)
1948{
1949 if (dict_opt
1950 ? (*curbuf->b_p_dict == NUL && *p_dict == NUL && !curwin->w_p_spell)
1951 : (*curbuf->b_p_tsr == NUL && *p_tsr == NUL)) {
1952 ctrl_x_mode = CTRL_X_NORMAL;
1953 edit_submode = NULL;
1954 msg_attr((dict_opt
1955 ? _("'dictionary' option is empty")
1956 : _("'thesaurus' option is empty")), HL_ATTR(HLF_E));
1957 if (emsg_silent == 0) {
1958 vim_beep(BO_COMPL);
1959 setcursor();
1960 ui_flush();
1961 os_delay(2000L, false);
1962 }
1963 return false;
1964 }
1965 return true;
1966}
1967
1968/// Check that the character "c" a valid key to go to or keep us in CTRL-X mode?
1969/// This depends on the current mode.
1970///
1971/// @param c character to check
1972bool vim_is_ctrl_x_key(int c)
1973 FUNC_ATTR_WARN_UNUSED_RESULT
1974{
1975 // Always allow ^R - let its results then be checked
1976 if (c == Ctrl_R) {
1977 return true;
1978 }
1979
1980 // Accept <PageUp> and <PageDown> if the popup menu is visible.
1981 if (ins_compl_pum_key(c)) {
1982 return true;
1983 }
1984
1985 switch (ctrl_x_mode) {
1986 case 0: // Not in any CTRL-X mode
1987 return c == Ctrl_N || c == Ctrl_P || c == Ctrl_X;
1988 case CTRL_X_NOT_DEFINED_YET:
1989 return c == Ctrl_X || c == Ctrl_Y || c == Ctrl_E
1990 || c == Ctrl_L || c == Ctrl_F || c == Ctrl_RSB
1991 || c == Ctrl_I || c == Ctrl_D || c == Ctrl_P
1992 || c == Ctrl_N || c == Ctrl_T || c == Ctrl_V
1993 || c == Ctrl_Q || c == Ctrl_U || c == Ctrl_O
1994 || c == Ctrl_S || c == Ctrl_K || c == 's';
1995 case CTRL_X_SCROLL:
1996 return c == Ctrl_Y || c == Ctrl_E;
1997 case CTRL_X_WHOLE_LINE:
1998 return c == Ctrl_L || c == Ctrl_P || c == Ctrl_N;
1999 case CTRL_X_FILES:
2000 return c == Ctrl_F || c == Ctrl_P || c == Ctrl_N;
2001 case CTRL_X_DICTIONARY:
2002 return c == Ctrl_K || c == Ctrl_P || c == Ctrl_N;
2003 case CTRL_X_THESAURUS:
2004 return c == Ctrl_T || c == Ctrl_P || c == Ctrl_N;
2005 case CTRL_X_TAGS:
2006 return c == Ctrl_RSB || c == Ctrl_P || c == Ctrl_N;
2007 case CTRL_X_PATH_PATTERNS:
2008 return c == Ctrl_P || c == Ctrl_N;
2009 case CTRL_X_PATH_DEFINES:
2010 return c == Ctrl_D || c == Ctrl_P || c == Ctrl_N;
2011 case CTRL_X_CMDLINE:
2012 return c == Ctrl_V || c == Ctrl_Q || c == Ctrl_P || c == Ctrl_N
2013 || c == Ctrl_X;
2014 case CTRL_X_FUNCTION:
2015 return c == Ctrl_U || c == Ctrl_P || c == Ctrl_N;
2016 case CTRL_X_OMNI:
2017 return c == Ctrl_O || c == Ctrl_P || c == Ctrl_N;
2018 case CTRL_X_SPELL:
2019 return c == Ctrl_S || c == Ctrl_P || c == Ctrl_N;
2020 case CTRL_X_EVAL:
2021 return (c == Ctrl_P || c == Ctrl_N);
2022 }
2023 internal_error("vim_is_ctrl_x_key()");
2024 return false;
2025}
2026
2027/// Check that character "c" is part of the item currently being
2028/// completed. Used to decide whether to abandon complete mode when the menu
2029/// is visible.
2030///
2031/// @param c character to check
2032static bool ins_compl_accept_char(int c)
2033 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
2034{
2035 if (ctrl_x_mode & CTRL_X_WANT_IDENT) {
2036 // When expanding an identifier only accept identifier chars.
2037 return vim_isIDc(c);
2038 }
2039
2040 switch (ctrl_x_mode) {
2041 case CTRL_X_FILES:
2042 // When expanding file name only accept file name chars. But not
2043 // path separators, so that "proto/<Tab>" expands files in
2044 // "proto", not "proto/" as a whole
2045 return vim_isfilec(c) && !vim_ispathsep(c);
2046
2047 case CTRL_X_CMDLINE:
2048 case CTRL_X_OMNI:
2049 // Command line and Omni completion can work with just about any
2050 // printable character, but do stop at white space.
2051 return vim_isprintc(c) && !ascii_iswhite(c);
2052
2053 case CTRL_X_WHOLE_LINE:
2054 // For while line completion a space can be part of the line.
2055 return vim_isprintc(c);
2056 }
2057 return vim_iswordc(c);
2058}
2059
2060/// This is like ins_compl_add(), but if 'ic' and 'inf' are set, then the
2061/// case of the originally typed text is used, and the case of the completed
2062/// text is inferred, ie this tries to work out what case you probably wanted
2063/// the rest of the word to be in -- webb
2064///
2065/// @param[in] cont_s_ipos next ^X<> will set initial_pos
2066int ins_compl_add_infercase(char_u *str_arg, int len, bool icase, char_u *fname,
2067 int dir, bool cont_s_ipos)
2068 FUNC_ATTR_NONNULL_ARG(1)
2069{
2070 char_u *str = str_arg;
2071 int i, c;
2072 int actual_len; /* Take multi-byte characters */
2073 int actual_compl_length; /* into account. */
2074 int min_len;
2075 bool has_lower = false;
2076 bool was_letter = false;
2077 int flags = 0;
2078
2079 if (p_ic && curbuf->b_p_inf && len > 0) {
2080 // Infer case of completed part.
2081
2082 // Find actual length of completion.
2083 if (has_mbyte) {
2084 const char_u *p = str;
2085 actual_len = 0;
2086 while (*p != NUL) {
2087 MB_PTR_ADV(p);
2088 actual_len++;
2089 }
2090 } else
2091 actual_len = len;
2092
2093 /* Find actual length of original text. */
2094 if (has_mbyte) {
2095 const char_u *p = compl_orig_text;
2096 actual_compl_length = 0;
2097 while (*p != NUL) {
2098 MB_PTR_ADV(p);
2099 actual_compl_length++;
2100 }
2101 } else
2102 actual_compl_length = compl_length;
2103
2104 /* "actual_len" may be smaller than "actual_compl_length" when using
2105 * thesaurus, only use the minimum when comparing. */
2106 min_len = actual_len < actual_compl_length
2107 ? actual_len : actual_compl_length;
2108
2109 // Allocate wide character array for the completion and fill it.
2110 int *const wca = xmalloc(actual_len * sizeof(*wca));
2111 {
2112 const char_u *p = str;
2113 for (i = 0; i < actual_len; i++) {
2114 if (has_mbyte) {
2115 wca[i] = mb_ptr2char_adv(&p);
2116 } else {
2117 wca[i] = *(p++);
2118 }
2119 }
2120 }
2121
2122 // Rule 1: Were any chars converted to lower?
2123 {
2124 const char_u *p = compl_orig_text;
2125 for (i = 0; i < min_len; i++) {
2126 if (has_mbyte) {
2127 c = mb_ptr2char_adv(&p);
2128 } else {
2129 c = *(p++);
2130 }
2131 if (mb_islower(c)) {
2132 has_lower = true;
2133 if (mb_isupper(wca[i])) {
2134 // Rule 1 is satisfied.
2135 for (i = actual_compl_length; i < actual_len; i++) {
2136 wca[i] = mb_tolower(wca[i]);
2137 }
2138 break;
2139 }
2140 }
2141 }
2142 }
2143
2144 /*
2145 * Rule 2: No lower case, 2nd consecutive letter converted to
2146 * upper case.
2147 */
2148 if (!has_lower) {
2149 const char_u *p = compl_orig_text;
2150 for (i = 0; i < min_len; i++) {
2151 if (has_mbyte) {
2152 c = mb_ptr2char_adv(&p);
2153 } else {
2154 c = *(p++);
2155 }
2156 if (was_letter && mb_isupper(c) && mb_islower(wca[i])) {
2157 // Rule 2 is satisfied.
2158 for (i = actual_compl_length; i < actual_len; i++) {
2159 wca[i] = mb_toupper(wca[i]);
2160 }
2161 break;
2162 }
2163 was_letter = mb_islower(c) || mb_isupper(c);
2164 }
2165 }
2166
2167 // Copy the original case of the part we typed.
2168 {
2169 const char_u *p = compl_orig_text;
2170 for (i = 0; i < min_len; i++) {
2171 if (has_mbyte) {
2172 c = mb_ptr2char_adv(&p);
2173 } else {
2174 c = *(p++);
2175 }
2176 if (mb_islower(c)) {
2177 wca[i] = mb_tolower(wca[i]);
2178 } else if (mb_isupper(c)) {
2179 wca[i] = mb_toupper(wca[i]);
2180 }
2181 }
2182 }
2183
2184 // Generate encoding specific output from wide character array.
2185 // Multi-byte characters can occupy up to five bytes more than
2186 // ASCII characters, and we also need one byte for NUL, so stay
2187 // six bytes away from the edge of IObuff.
2188 {
2189 char_u *p = IObuff;
2190 i = 0;
2191 while (i < actual_len && (p - IObuff + 6) < IOSIZE) {
2192 p += utf_char2bytes(wca[i++], p);
2193 }
2194 *p = NUL;
2195 }
2196
2197 xfree(wca);
2198
2199 str = IObuff;
2200 }
2201 if (cont_s_ipos) {
2202 flags |= CP_CONT_S_IPOS;
2203 }
2204 if (icase) {
2205 flags |= CP_ICASE;
2206 }
2207
2208 return ins_compl_add(str, len, fname, NULL, false, dir, flags, false);
2209}
2210
2211/// Add a match to the list of matches
2212///
2213/// @param[in] str Match to add.
2214/// @param[in] len Match length, -1 to use #STRLEN.
2215/// @param[in] fname File name match comes from. May be NULL.
2216/// @param[in] cptext Extra text for popup menu. May be NULL. If not NULL,
2217/// must have exactly #CPT_COUNT items.
2218/// @param[in] cptext_allocated If true, will not copy cptext strings.
2219///
2220/// @note Will free strings in case of error.
2221/// cptext itself will not be freed.
2222/// @param[in] cdir Completion direction.
2223/// @param[in] adup True if duplicate matches are to be accepted.
2224///
2225/// @return NOTDONE if the given string is already in the list of completions,
2226/// otherwise it is added to the list and OK is returned. FAIL will be
2227/// returned in case of error.
2228static int ins_compl_add(char_u *const str, int len,
2229 char_u *const fname,
2230 char_u *const *const cptext,
2231 const bool cptext_allocated,
2232 const Direction cdir, int flags_arg, const bool adup)
2233 FUNC_ATTR_NONNULL_ARG(1)
2234{
2235 compl_T *match;
2236 int dir = (cdir == kDirectionNotSet ? compl_direction : cdir);
2237 int flags = flags_arg;
2238
2239 os_breakcheck();
2240#define FREE_CPTEXT(cptext, cptext_allocated) \
2241 do { \
2242 if (cptext != NULL && cptext_allocated) { \
2243 for (size_t i = 0; i < CPT_COUNT; i++) { \
2244 xfree(cptext[i]); \
2245 } \
2246 } \
2247 } while (0)
2248 if (got_int) {
2249 FREE_CPTEXT(cptext, cptext_allocated);
2250 return FAIL;
2251 }
2252 if (len < 0) {
2253 len = (int)STRLEN(str);
2254 }
2255
2256 /*
2257 * If the same match is already present, don't add it.
2258 */
2259 if (compl_first_match != NULL && !adup) {
2260 match = compl_first_match;
2261 do {
2262 if (!(match->cp_flags & CP_ORIGINAL_TEXT)
2263 && STRNCMP(match->cp_str, str, len) == 0
2264 && match->cp_str[len] == NUL) {
2265 FREE_CPTEXT(cptext, cptext_allocated);
2266 return NOTDONE;
2267 }
2268 match = match->cp_next;
2269 } while (match != NULL && match != compl_first_match);
2270 }
2271
2272 /* Remove any popup menu before changing the list of matches. */
2273 ins_compl_del_pum();
2274
2275 /*
2276 * Allocate a new match structure.
2277 * Copy the values to the new match structure.
2278 */
2279 match = xcalloc(1, sizeof(compl_T));
2280 match->cp_number = -1;
2281 if (flags & CP_ORIGINAL_TEXT) {
2282 match->cp_number = 0;
2283 }
2284 match->cp_str = vim_strnsave(str, len);
2285
2286 // match-fname is:
2287 // - compl_curr_match->cp_fname if it is a string equal to fname.
2288 // - a copy of fname, CP_FREE_FNAME is set to free later THE allocated mem.
2289 // - NULL otherwise. --Acevedo
2290 if (fname != NULL
2291 && compl_curr_match != NULL
2292 && compl_curr_match->cp_fname != NULL
2293 && STRCMP(fname, compl_curr_match->cp_fname) == 0) {
2294 match->cp_fname = compl_curr_match->cp_fname;
2295 } else if (fname != NULL) {
2296 match->cp_fname = vim_strsave(fname);
2297 flags |= CP_FREE_FNAME;
2298 } else {
2299 match->cp_fname = NULL;
2300 }
2301 match->cp_flags = flags;
2302
2303 if (cptext != NULL) {
2304 int i;
2305
2306 for (i = 0; i < CPT_COUNT; i++) {
2307 if (cptext[i] == NULL) {
2308 continue;
2309 }
2310 if (*cptext[i] != NUL) {
2311 match->cp_text[i] = (cptext_allocated
2312 ? cptext[i]
2313 : (char_u *)xstrdup((char *)cptext[i]));
2314 } else if (cptext_allocated) {
2315 xfree(cptext[i]);
2316 }
2317 }
2318 }
2319
2320 /*
2321 * Link the new match structure in the list of matches.
2322 */
2323 if (compl_first_match == NULL)
2324 match->cp_next = match->cp_prev = NULL;
2325 else if (dir == FORWARD) {
2326 match->cp_next = compl_curr_match->cp_next;
2327 match->cp_prev = compl_curr_match;
2328 } else { /* BACKWARD */
2329 match->cp_next = compl_curr_match;
2330 match->cp_prev = compl_curr_match->cp_prev;
2331 }
2332 if (match->cp_next)
2333 match->cp_next->cp_prev = match;
2334 if (match->cp_prev)
2335 match->cp_prev->cp_next = match;
2336 else /* if there's nothing before, it is the first match */
2337 compl_first_match = match;
2338 compl_curr_match = match;
2339
2340 /*
2341 * Find the longest common string if still doing that.
2342 */
2343 if (compl_get_longest && (flags & CP_ORIGINAL_TEXT) == 0) {
2344 ins_compl_longest_match(match);
2345 }
2346
2347 return OK;
2348}
2349
2350/// Check that "str[len]" matches with "match->cp_str", considering
2351/// "match->cp_flags".
2352///
2353/// @param match completion match
2354/// @param str character string to check
2355/// @param len lenth of "str"
2356static bool ins_compl_equal(compl_T *match, char_u *str, size_t len)
2357 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
2358{
2359 if (match->cp_flags & CP_EQUAL) {
2360 return true;
2361 }
2362 if (match->cp_flags & CP_ICASE) {
2363 return STRNICMP(match->cp_str, str, len) == 0;
2364 }
2365 return STRNCMP(match->cp_str, str, len) == 0;
2366}
2367
2368/*
2369 * Reduce the longest common string for match "match".
2370 */
2371static void ins_compl_longest_match(compl_T *match)
2372{
2373 char_u *p, *s;
2374 int c1, c2;
2375 int had_match;
2376
2377 if (compl_leader == NULL) {
2378 /* First match, use it as a whole. */
2379 compl_leader = vim_strsave(match->cp_str);
2380 had_match = (curwin->w_cursor.col > compl_col);
2381 ins_compl_delete();
2382 ins_bytes(compl_leader + ins_compl_len());
2383 ins_redraw(FALSE);
2384
2385 /* When the match isn't there (to avoid matching itself) remove it
2386 * again after redrawing. */
2387 if (!had_match)
2388 ins_compl_delete();
2389 compl_used_match = false;
2390 } else {
2391 /* Reduce the text if this match differs from compl_leader. */
2392 p = compl_leader;
2393 s = match->cp_str;
2394 while (*p != NUL) {
2395 c1 = utf_ptr2char(p);
2396 c2 = utf_ptr2char(s);
2397
2398 if ((match->cp_flags & CP_ICASE)
2399 ? (mb_tolower(c1) != mb_tolower(c2))
2400 : (c1 != c2)) {
2401 break;
2402 }
2403 MB_PTR_ADV(p);
2404 MB_PTR_ADV(s);
2405 }
2406
2407 if (*p != NUL) {
2408 /* Leader was shortened, need to change the inserted text. */
2409 *p = NUL;
2410 had_match = (curwin->w_cursor.col > compl_col);
2411 ins_compl_delete();
2412 ins_bytes(compl_leader + ins_compl_len());
2413 ins_redraw(FALSE);
2414
2415 /* When the match isn't there (to avoid matching itself) remove it
2416 * again after redrawing. */
2417 if (!had_match)
2418 ins_compl_delete();
2419 }
2420
2421 compl_used_match = false;
2422 }
2423}
2424
2425/*
2426 * Add an array of matches to the list of matches.
2427 * Frees matches[].
2428 */
2429static void ins_compl_add_matches(int num_matches, char_u **matches, int icase)
2430 FUNC_ATTR_NONNULL_ALL
2431{
2432 int add_r = OK;
2433 int dir = compl_direction;
2434
2435 for (int i = 0; i < num_matches && add_r != FAIL; i++) {
2436 if ((add_r = ins_compl_add(matches[i], -1, NULL, NULL, false, dir,
2437 icase ? CP_ICASE : 0, false)) == OK) {
2438 // If dir was BACKWARD then honor it just once.
2439 dir = FORWARD;
2440 }
2441 }
2442 FreeWild(num_matches, matches);
2443}
2444
2445/* Make the completion list cyclic.
2446 * Return the number of matches (excluding the original).
2447 */
2448static int ins_compl_make_cyclic(void)
2449{
2450 compl_T *match;
2451 int count = 0;
2452
2453 if (compl_first_match != NULL) {
2454 /*
2455 * Find the end of the list.
2456 */
2457 match = compl_first_match;
2458 /* there's always an entry for the compl_orig_text, it doesn't count. */
2459 while (match->cp_next != NULL && match->cp_next != compl_first_match) {
2460 match = match->cp_next;
2461 ++count;
2462 }
2463 match->cp_next = compl_first_match;
2464 compl_first_match->cp_prev = match;
2465 }
2466 return count;
2467}
2468
2469// Set variables that store noselect and noinsert behavior from the
2470// 'completeopt' value.
2471void completeopt_was_set(void)
2472{
2473 compl_no_insert = false;
2474 compl_no_select = false;
2475 if (strstr((char *)p_cot, "noselect") != NULL) {
2476 compl_no_select = true;
2477 }
2478 if (strstr((char *)p_cot, "noinsert") != NULL) {
2479 compl_no_insert = true;
2480 }
2481}
2482
2483
2484/*
2485 * Start completion for the complete() function.
2486 * "startcol" is where the matched text starts (1 is first column).
2487 * "list" is the list of matches.
2488 */
2489void set_completion(colnr_T startcol, list_T *list)
2490{
2491 int flags = CP_ORIGINAL_TEXT;
2492
2493 // If already doing completions stop it.
2494 if (ctrl_x_mode != CTRL_X_NORMAL) {
2495 ins_compl_prep(' ');
2496 }
2497 ins_compl_clear();
2498 ins_compl_free();
2499
2500 compl_direction = FORWARD;
2501 if (startcol > curwin->w_cursor.col)
2502 startcol = curwin->w_cursor.col;
2503 compl_col = startcol;
2504 compl_length = (int)curwin->w_cursor.col - (int)startcol;
2505 /* compl_pattern doesn't need to be set */
2506 compl_orig_text = vim_strnsave(get_cursor_line_ptr() + compl_col,
2507 compl_length);
2508 if (p_ic) {
2509 flags |= CP_ICASE;
2510 }
2511 if (ins_compl_add(compl_orig_text, -1, NULL, NULL, false, 0,
2512 flags, false) != OK) {
2513 return;
2514 }
2515
2516 ctrl_x_mode = CTRL_X_EVAL;
2517
2518 ins_compl_add_list(list);
2519 compl_matches = ins_compl_make_cyclic();
2520 compl_started = true;
2521 compl_used_match = true;
2522 compl_cont_status = 0;
2523 int save_w_wrow = curwin->w_wrow;
2524 int save_w_leftcol = curwin->w_leftcol;
2525
2526 compl_curr_match = compl_first_match;
2527 if (compl_no_insert || compl_no_select) {
2528 ins_complete(K_DOWN, false);
2529 if (compl_no_select) {
2530 ins_complete(K_UP, false);
2531 }
2532 } else {
2533 ins_complete(Ctrl_N, false);
2534 }
2535 compl_enter_selects = compl_no_insert;
2536
2537 // Lazily show the popup menu, unless we got interrupted.
2538 if (!compl_interrupted) {
2539 show_pum(save_w_wrow, save_w_leftcol);
2540 }
2541
2542 ui_flush();
2543}
2544
2545
2546/* "compl_match_array" points the currently displayed list of entries in the
2547 * popup menu. It is NULL when there is no popup menu. */
2548static pumitem_T *compl_match_array = NULL;
2549static int compl_match_arraysize;
2550
2551
2552/*
2553 * Remove any popup menu.
2554 */
2555static void ins_compl_del_pum(void)
2556{
2557 if (compl_match_array != NULL) {
2558 pum_undisplay(false);
2559 XFREE_CLEAR(compl_match_array);
2560 }
2561}
2562
2563/// Check if the popup menu should be displayed.
2564static bool pum_wanted(void)
2565 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
2566{
2567 // "completeopt" must contain "menu" or "menuone"
2568 return vim_strchr(p_cot, 'm') != NULL;
2569}
2570
2571/// Check that there are two or more matches to be shown in the popup menu.
2572/// One if "completopt" contains "menuone".
2573static bool pum_enough_matches(void)
2574 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
2575{
2576 // Don't display the popup menu if there are no matches or there is only
2577 // one (ignoring the original text).
2578 compl_T *comp = compl_first_match;
2579 int i = 0;
2580 do {
2581 if (comp == NULL
2582 || ((comp->cp_flags & CP_ORIGINAL_TEXT) == 0 && ++i == 2)) {
2583 break;
2584 }
2585 comp = comp->cp_next;
2586 } while (comp != compl_first_match);
2587
2588 if (strstr((char *)p_cot, "menuone") != NULL) {
2589 return i >= 1;
2590 }
2591 return i >= 2;
2592}
2593
2594static void trigger_complete_changed_event(int cur)
2595{
2596 static bool recursive = false;
2597
2598 if (recursive) {
2599 return;
2600 }
2601
2602 dict_T *v_event = get_vim_var_dict(VV_EVENT);
2603 if (cur < 0) {
2604 tv_dict_add_dict(v_event, S_LEN("completed_item"), tv_dict_alloc());
2605 } else {
2606 dict_T *item = ins_compl_dict_alloc(compl_curr_match);
2607 tv_dict_add_dict(v_event, S_LEN("completed_item"), item);
2608 }
2609 pum_set_event_info(v_event);
2610 tv_dict_set_keys_readonly(v_event);
2611
2612 recursive = true;
2613 textlock++;
2614 apply_autocmds(EVENT_COMPLETECHANGED, NULL, NULL, false, curbuf);
2615 textlock--;
2616 recursive = false;
2617
2618 tv_dict_clear(v_event);
2619}
2620
2621/// Show the popup menu for the list of matches.
2622/// Also adjusts "compl_shown_match" to an entry that is actually displayed.
2623void ins_compl_show_pum(void)
2624{
2625 compl_T *compl;
2626 compl_T *shown_compl = NULL;
2627 bool did_find_shown_match = false;
2628 bool shown_match_ok = false;
2629 int i;
2630 int cur = -1;
2631 colnr_T col;
2632 int lead_len = 0;
2633 bool array_changed = false;
2634
2635 if (!pum_wanted() || !pum_enough_matches())
2636 return;
2637
2638 /* Dirty hard-coded hack: remove any matchparen highlighting. */
2639 do_cmdline_cmd("if exists('g:loaded_matchparen')|3match none|endif");
2640
2641 /* Update the screen before drawing the popup menu over it. */
2642 update_screen(0);
2643
2644 if (compl_match_array == NULL) {
2645 array_changed = true;
2646 // Need to build the popup menu list.
2647 compl_match_arraysize = 0;
2648 compl = compl_first_match;
2649 //
2650 // If it's user complete function and refresh_always,
2651 // do not use "compl_leader" as prefix filter.
2652 //
2653 if (ins_compl_need_restart()) {
2654 XFREE_CLEAR(compl_leader);
2655 }
2656 if (compl_leader != NULL) {
2657 lead_len = (int)STRLEN(compl_leader);
2658 }
2659 do {
2660 if ((compl->cp_flags & CP_ORIGINAL_TEXT) == 0
2661 && (compl_leader == NULL
2662 || ins_compl_equal(compl, compl_leader, lead_len))) {
2663 compl_match_arraysize++;
2664 }
2665 compl = compl->cp_next;
2666 } while (compl != NULL && compl != compl_first_match);
2667 if (compl_match_arraysize == 0)
2668 return;
2669
2670 assert(compl_match_arraysize >= 0);
2671 compl_match_array = xcalloc(compl_match_arraysize, sizeof(pumitem_T));
2672 /* If the current match is the original text don't find the first
2673 * match after it, don't highlight anything. */
2674 if (compl_shown_match->cp_flags & CP_ORIGINAL_TEXT) {
2675 shown_match_ok = true;
2676 }
2677
2678 i = 0;
2679 compl = compl_first_match;
2680 do {
2681 if ((compl->cp_flags & CP_ORIGINAL_TEXT) == 0
2682 && (compl_leader == NULL
2683 || ins_compl_equal(compl, compl_leader, lead_len))) {
2684 if (!shown_match_ok) {
2685 if (compl == compl_shown_match || did_find_shown_match) {
2686 /* This item is the shown match or this is the
2687 * first displayed item after the shown match. */
2688 compl_shown_match = compl;
2689 did_find_shown_match = true;
2690 shown_match_ok = true;
2691 } else {
2692 // Remember this displayed match for when the
2693 // shown match is just below it.
2694 shown_compl = compl;
2695 }
2696 cur = i;
2697 }
2698
2699 if (compl->cp_text[CPT_ABBR] != NULL)
2700 compl_match_array[i].pum_text =
2701 compl->cp_text[CPT_ABBR];
2702 else
2703 compl_match_array[i].pum_text = compl->cp_str;
2704 compl_match_array[i].pum_kind = compl->cp_text[CPT_KIND];
2705 compl_match_array[i].pum_info = compl->cp_text[CPT_INFO];
2706 if (compl->cp_text[CPT_MENU] != NULL)
2707 compl_match_array[i++].pum_extra =
2708 compl->cp_text[CPT_MENU];
2709 else
2710 compl_match_array[i++].pum_extra = compl->cp_fname;
2711 }
2712
2713 if (compl == compl_shown_match) {
2714 did_find_shown_match = true;
2715
2716 /* When the original text is the shown match don't set
2717 * compl_shown_match. */
2718 if (compl->cp_flags & CP_ORIGINAL_TEXT) {
2719 shown_match_ok = true;
2720 }
2721
2722 if (!shown_match_ok && shown_compl != NULL) {
2723 /* The shown match isn't displayed, set it to the
2724 * previously displayed match. */
2725 compl_shown_match = shown_compl;
2726 shown_match_ok = true;
2727 }
2728 }
2729 compl = compl->cp_next;
2730 } while (compl != NULL && compl != compl_first_match);
2731
2732 if (!shown_match_ok) /* no displayed match at all */
2733 cur = -1;
2734 } else {
2735 /* popup menu already exists, only need to find the current item.*/
2736 for (i = 0; i < compl_match_arraysize; ++i)
2737 if (compl_match_array[i].pum_text == compl_shown_match->cp_str
2738 || compl_match_array[i].pum_text
2739 == compl_shown_match->cp_text[CPT_ABBR]) {
2740 cur = i;
2741 break;
2742 }
2743 }
2744
2745 // In Replace mode when a $ is displayed at the end of the line only
2746 // part of the screen would be updated. We do need to redraw here.
2747 dollar_vcol = -1;
2748
2749 // Compute the screen column of the start of the completed text.
2750 // Use the cursor to get all wrapping and other settings right.
2751 col = curwin->w_cursor.col;
2752 curwin->w_cursor.col = compl_col;
2753 pum_selected_item = cur;
2754 pum_display(compl_match_array, compl_match_arraysize, cur, array_changed, 0);
2755 curwin->w_cursor.col = col;
2756
2757 if (has_event(EVENT_COMPLETECHANGED)) {
2758 trigger_complete_changed_event(cur);
2759 }
2760}
2761
2762#define DICT_FIRST (1) /* use just first element in "dict" */
2763#define DICT_EXACT (2) /* "dict" is the exact name of a file */
2764
2765/*
2766 * Add any identifiers that match the given pattern in the list of dictionary
2767 * files "dict_start" to the list of completions.
2768 */
2769static void
2770ins_compl_dictionaries (
2771 char_u *dict_start,
2772 char_u *pat,
2773 int flags, /* DICT_FIRST and/or DICT_EXACT */
2774 int thesaurus /* Thesaurus completion */
2775)
2776{
2777 char_u *dict = dict_start;
2778 char_u *ptr;
2779 char_u *buf;
2780 regmatch_T regmatch;
2781 char_u **files;
2782 int count;
2783 int save_p_scs;
2784 int dir = compl_direction;
2785
2786 if (*dict == NUL) {
2787 /* When 'dictionary' is empty and spell checking is enabled use
2788 * "spell". */
2789 if (!thesaurus && curwin->w_p_spell)
2790 dict = (char_u *)"spell";
2791 else
2792 return;
2793 }
2794
2795 buf = xmalloc(LSIZE);
2796 regmatch.regprog = NULL; /* so that we can goto theend */
2797
2798 /* If 'infercase' is set, don't use 'smartcase' here */
2799 save_p_scs = p_scs;
2800 if (curbuf->b_p_inf)
2801 p_scs = FALSE;
2802
2803 /* When invoked to match whole lines for CTRL-X CTRL-L adjust the pattern
2804 * to only match at the start of a line. Otherwise just match the
2805 * pattern. Also need to double backslashes. */
2806 if (CTRL_X_MODE_LINE_OR_EVAL(ctrl_x_mode)) {
2807 char_u *pat_esc = vim_strsave_escaped(pat, (char_u *)"\\");
2808
2809 size_t len = STRLEN(pat_esc) + 10;
2810 ptr = xmalloc(len);
2811 vim_snprintf((char *)ptr, len, "^\\s*\\zs\\V%s", pat_esc);
2812 regmatch.regprog = vim_regcomp(ptr, RE_MAGIC);
2813 xfree(pat_esc);
2814 xfree(ptr);
2815 } else {
2816 regmatch.regprog = vim_regcomp(pat, p_magic ? RE_MAGIC : 0);
2817 if (regmatch.regprog == NULL)
2818 goto theend;
2819 }
2820
2821 /* ignore case depends on 'ignorecase', 'smartcase' and "pat" */
2822 regmatch.rm_ic = ignorecase(pat);
2823 while (*dict != NUL && !got_int && !compl_interrupted) {
2824 /* copy one dictionary file name into buf */
2825 if (flags == DICT_EXACT) {
2826 count = 1;
2827 files = &dict;
2828 } else {
2829 /* Expand wildcards in the dictionary name, but do not allow
2830 * backticks (for security, the 'dict' option may have been set in
2831 * a modeline). */
2832 copy_option_part(&dict, buf, LSIZE, ",");
2833 if (!thesaurus && STRCMP(buf, "spell") == 0)
2834 count = -1;
2835 else if (vim_strchr(buf, '`') != NULL
2836 || expand_wildcards(1, &buf, &count, &files,
2837 EW_FILE|EW_SILENT) != OK)
2838 count = 0;
2839 }
2840
2841 if (count == -1) {
2842 /* Complete from active spelling. Skip "\<" in the pattern, we
2843 * don't use it as a RE. */
2844 if (pat[0] == '\\' && pat[1] == '<')
2845 ptr = pat + 2;
2846 else
2847 ptr = pat;
2848 spell_dump_compl(ptr, regmatch.rm_ic, &dir, 0);
2849 } else if (count > 0) { /* avoid warning for using "files" uninit */
2850 ins_compl_files(count, files, thesaurus, flags,
2851 &regmatch, buf, &dir);
2852 if (flags != DICT_EXACT)
2853 FreeWild(count, files);
2854 }
2855 if (flags != 0)
2856 break;
2857 }
2858
2859theend:
2860 p_scs = save_p_scs;
2861 vim_regfree(regmatch.regprog);
2862 xfree(buf);
2863}
2864
2865static void ins_compl_files(int count, char_u **files, int thesaurus, int flags, regmatch_T *regmatch, char_u *buf, int *dir)
2866{
2867 char_u *ptr;
2868 int i;
2869 FILE *fp;
2870 int add_r;
2871
2872 for (i = 0; i < count && !got_int && !compl_interrupted; i++) {
2873 fp = os_fopen((char *)files[i], "r"); // open dictionary file
2874 if (flags != DICT_EXACT) {
2875 vim_snprintf((char *)IObuff, IOSIZE,
2876 _("Scanning dictionary: %s"), (char *)files[i]);
2877 (void)msg_trunc_attr(IObuff, true, HL_ATTR(HLF_R));
2878 }
2879
2880 if (fp == NULL) {
2881 continue;
2882 }
2883 /*
2884 * Read dictionary file line by line.
2885 * Check each line for a match.
2886 */
2887 while (!got_int && !compl_interrupted
2888 && !vim_fgets(buf, LSIZE, fp)) {
2889 ptr = buf;
2890 while (vim_regexec(regmatch, buf, (colnr_T)(ptr - buf))) {
2891 ptr = regmatch->startp[0];
2892 if (CTRL_X_MODE_LINE_OR_EVAL(ctrl_x_mode)) {
2893 ptr = find_line_end(ptr);
2894 } else {
2895 ptr = find_word_end(ptr);
2896 }
2897 add_r = ins_compl_add_infercase(regmatch->startp[0],
2898 (int)(ptr - regmatch->startp[0]),
2899 p_ic, files[i], *dir, false);
2900 if (thesaurus) {
2901 char_u *wstart;
2902
2903 /*
2904 * Add the other matches on the line
2905 */
2906 ptr = buf;
2907 while (!got_int) {
2908 /* Find start of the next word. Skip white
2909 * space and punctuation. */
2910 ptr = find_word_start(ptr);
2911 if (*ptr == NUL || *ptr == NL)
2912 break;
2913 wstart = ptr;
2914
2915 /* Find end of the word. */
2916 if (has_mbyte)
2917 /* Japanese words may have characters in
2918 * different classes, only separate words
2919 * with single-byte non-word characters. */
2920 while (*ptr != NUL) {
2921 int l = (*mb_ptr2len)(ptr);
2922
2923 if (l < 2 && !vim_iswordc(*ptr))
2924 break;
2925 ptr += l;
2926 }
2927 else
2928 ptr = find_word_end(ptr);
2929
2930 // Add the word. Skip the regexp match.
2931 if (wstart != regmatch->startp[0]) {
2932 add_r = ins_compl_add_infercase(wstart, (int)(ptr - wstart),
2933 p_ic, files[i], *dir, false);
2934 }
2935 }
2936 }
2937 if (add_r == OK)
2938 /* if dir was BACKWARD then honor it just once */
2939 *dir = FORWARD;
2940 else if (add_r == FAIL)
2941 break;
2942 /* avoid expensive call to vim_regexec() when at end
2943 * of line */
2944 if (*ptr == '\n' || got_int)
2945 break;
2946 }
2947 line_breakcheck();
2948 ins_compl_check_keys(50, false);
2949 }
2950 fclose(fp);
2951 }
2952}
2953
2954/*
2955 * Find the start of the next word.
2956 * Returns a pointer to the first char of the word. Also stops at a NUL.
2957 */
2958char_u *find_word_start(char_u *ptr)
2959{
2960 if (has_mbyte)
2961 while (*ptr != NUL && *ptr != '\n' && mb_get_class(ptr) <= 1)
2962 ptr += (*mb_ptr2len)(ptr);
2963 else
2964 while (*ptr != NUL && *ptr != '\n' && !vim_iswordc(*ptr))
2965 ++ptr;
2966 return ptr;
2967}
2968
2969/*
2970 * Find the end of the word. Assumes it starts inside a word.
2971 * Returns a pointer to just after the word.
2972 */
2973char_u *find_word_end(char_u *ptr)
2974{
2975 int start_class;
2976
2977 if (has_mbyte) {
2978 start_class = mb_get_class(ptr);
2979 if (start_class > 1)
2980 while (*ptr != NUL) {
2981 ptr += (*mb_ptr2len)(ptr);
2982 if (mb_get_class(ptr) != start_class)
2983 break;
2984 }
2985 } else
2986 while (vim_iswordc(*ptr))
2987 ++ptr;
2988 return ptr;
2989}
2990
2991/*
2992 * Find the end of the line, omitting CR and NL at the end.
2993 * Returns a pointer to just after the line.
2994 */
2995static char_u *find_line_end(char_u *ptr)
2996{
2997 char_u *s;
2998
2999 s = ptr + STRLEN(ptr);
3000 while (s > ptr && (s[-1] == CAR || s[-1] == NL))
3001 --s;
3002 return s;
3003}
3004
3005/*
3006 * Free the list of completions
3007 */
3008static void ins_compl_free(void)
3009{
3010 compl_T *match;
3011
3012 XFREE_CLEAR(compl_pattern);
3013 XFREE_CLEAR(compl_leader);
3014
3015 if (compl_first_match == NULL)
3016 return;
3017
3018 ins_compl_del_pum();
3019 pum_clear();
3020
3021 compl_curr_match = compl_first_match;
3022 do {
3023 match = compl_curr_match;
3024 compl_curr_match = compl_curr_match->cp_next;
3025 xfree(match->cp_str);
3026 // several entries may use the same fname, free it just once.
3027 if (match->cp_flags & CP_FREE_FNAME) {
3028 xfree(match->cp_fname);
3029 }
3030 for (int i = 0; i < CPT_COUNT; i++) {
3031 xfree(match->cp_text[i]);
3032 }
3033 xfree(match);
3034 } while (compl_curr_match != NULL && compl_curr_match != compl_first_match);
3035 compl_first_match = compl_curr_match = NULL;
3036 compl_shown_match = NULL;
3037 compl_old_match = NULL;
3038}
3039
3040static void ins_compl_clear(void)
3041{
3042 compl_cont_status = 0;
3043 compl_started = false;
3044 compl_matches = 0;
3045 XFREE_CLEAR(compl_pattern);
3046 XFREE_CLEAR(compl_leader);
3047 edit_submode_extra = NULL;
3048 XFREE_CLEAR(compl_orig_text);
3049 compl_enter_selects = false;
3050 // clear v:completed_item
3051 set_vim_var_dict(VV_COMPLETED_ITEM, tv_dict_alloc());
3052}
3053
3054/// Check that Insert completion is active.
3055bool ins_compl_active(void)
3056 FUNC_ATTR_PURE
3057{
3058 return compl_started;
3059}
3060
3061// Get complete information
3062void get_complete_info(list_T *what_list, dict_T *retdict)
3063{
3064#define CI_WHAT_MODE 0x01
3065#define CI_WHAT_PUM_VISIBLE 0x02
3066#define CI_WHAT_ITEMS 0x04
3067#define CI_WHAT_SELECTED 0x08
3068#define CI_WHAT_INSERTED 0x10
3069#define CI_WHAT_ALL 0xff
3070 int what_flag;
3071
3072 if (what_list == NULL) {
3073 what_flag = CI_WHAT_ALL;
3074 } else {
3075 what_flag = 0;
3076 for (listitem_T *item = tv_list_first(what_list)
3077 ; item != NULL
3078 ; item = TV_LIST_ITEM_NEXT(what_list, item)) {
3079 const char *what = tv_get_string(TV_LIST_ITEM_TV(item));
3080
3081 if (STRCMP(what, "mode") == 0) {
3082 what_flag |= CI_WHAT_MODE;
3083 } else if (STRCMP(what, "pum_visible") == 0) {
3084 what_flag |= CI_WHAT_PUM_VISIBLE;
3085 } else if (STRCMP(what, "items") == 0) {
3086 what_flag |= CI_WHAT_ITEMS;
3087 } else if (STRCMP(what, "selected") == 0) {
3088 what_flag |= CI_WHAT_SELECTED;
3089 } else if (STRCMP(what, "inserted") == 0) {
3090 what_flag |= CI_WHAT_INSERTED;
3091 }
3092 }
3093 }
3094
3095 int ret = OK;
3096 if (what_flag & CI_WHAT_MODE) {
3097 ret = tv_dict_add_str(retdict, S_LEN("mode"),
3098 (char *)ins_compl_mode());
3099 }
3100
3101 if (ret == OK && (what_flag & CI_WHAT_PUM_VISIBLE)) {
3102 ret = tv_dict_add_nr(retdict, S_LEN("pum_visible"), pum_visible());
3103 }
3104
3105 if (ret == OK && (what_flag & CI_WHAT_ITEMS)) {
3106 list_T *li = tv_list_alloc(ins_compl_len());
3107
3108 ret = tv_dict_add_list(retdict, S_LEN("items"), li);
3109 if (ret == OK && compl_first_match != NULL) {
3110 compl_T *match = compl_first_match;
3111 do {
3112 if (!(match->cp_flags & CP_ORIGINAL_TEXT)) {
3113 dict_T *di = tv_dict_alloc();
3114
3115 tv_list_append_dict(li, di);
3116 tv_dict_add_str(di, S_LEN("word"),
3117 (char *)EMPTY_IF_NULL(match->cp_str));
3118 tv_dict_add_str(di, S_LEN("abbr"),
3119 (char *)EMPTY_IF_NULL(match->cp_text[CPT_ABBR]));
3120 tv_dict_add_str(di, S_LEN("menu"),
3121 (char *)EMPTY_IF_NULL(match->cp_text[CPT_MENU]));
3122 tv_dict_add_str(di, S_LEN("kind"),
3123 (char *)EMPTY_IF_NULL(match->cp_text[CPT_KIND]));
3124 tv_dict_add_str(di, S_LEN("info"),
3125 (char *)EMPTY_IF_NULL(match->cp_text[CPT_INFO]));
3126 tv_dict_add_str(di, S_LEN("user_data"),
3127 (char *)EMPTY_IF_NULL(match->cp_text[CPT_USER_DATA]));
3128 }
3129 match = match->cp_next;
3130 } while (match != NULL && match != compl_first_match);
3131 }
3132 }
3133
3134 if (ret == OK && (what_flag & CI_WHAT_SELECTED)) {
3135 ret = tv_dict_add_nr(retdict, S_LEN("selected"),
3136 (compl_curr_match != NULL)
3137 ? compl_curr_match->cp_number - 1 : -1);
3138 }
3139
3140 (void)ret;
3141 // TODO(vim):
3142 // if (ret == OK && (what_flag & CI_WHAT_INSERTED))
3143}
3144
3145// Return Insert completion mode name string
3146static char_u * ins_compl_mode(void)
3147{
3148 if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET || compl_started) {
3149 return (char_u *)ctrl_x_mode_names[ctrl_x_mode & ~CTRL_X_WANT_IDENT];
3150 }
3151 return (char_u *)"";
3152}
3153
3154
3155/*
3156 * Delete one character before the cursor and show the subset of the matches
3157 * that match the word that is now before the cursor.
3158 * Returns the character to be used, NUL if the work is done and another char
3159 * to be got from the user.
3160 */
3161static int ins_compl_bs(void)
3162{
3163 char_u *line;
3164 char_u *p;
3165
3166 line = get_cursor_line_ptr();
3167 p = line + curwin->w_cursor.col;
3168 MB_PTR_BACK(line, p);
3169
3170 // Stop completion when the whole word was deleted. For Omni completion
3171 // allow the word to be deleted, we won't match everything.
3172 // Respect the 'backspace' option.
3173 if ((int)(p - line) - (int)compl_col < 0
3174 || ((int)(p - line) - (int)compl_col == 0
3175 && ctrl_x_mode != CTRL_X_OMNI) || ctrl_x_mode == CTRL_X_EVAL
3176 || (!can_bs(BS_START) && (int)(p - line) - (int)compl_col
3177 - compl_length < 0)) {
3178 return K_BS;
3179 }
3180
3181 /* Deleted more than what was used to find matches or didn't finish
3182 * finding all matches: need to look for matches all over again. */
3183 if (curwin->w_cursor.col <= compl_col + compl_length
3184 || ins_compl_need_restart())
3185 ins_compl_restart();
3186
3187 xfree(compl_leader);
3188 compl_leader = vim_strnsave(line + compl_col, (int)(p - line) - compl_col);
3189 ins_compl_new_leader();
3190 if (compl_shown_match != NULL)
3191 /* Make sure current match is not a hidden item. */
3192 compl_curr_match = compl_shown_match;
3193
3194 return NUL;
3195}
3196
3197/// Check that we need to find matches again, ins_compl_restart() is to
3198/// be called.
3199static bool ins_compl_need_restart(void)
3200 FUNC_ATTR_PURE
3201{
3202 // Return true if we didn't complete finding matches or when the
3203 // "completefunc" returned "always" in the "refresh" dictionary item.
3204 return compl_was_interrupted
3205 || ((ctrl_x_mode == CTRL_X_FUNCTION || ctrl_x_mode == CTRL_X_OMNI)
3206 && compl_opt_refresh_always);
3207}
3208
3209/*
3210 * Called after changing "compl_leader".
3211 * Show the popup menu with a different set of matches.
3212 * May also search for matches again if the previous search was interrupted.
3213 */
3214static void ins_compl_new_leader(void)
3215{
3216 ins_compl_del_pum();
3217 ins_compl_delete();
3218 ins_bytes(compl_leader + ins_compl_len());
3219 compl_used_match = false;
3220
3221 if (compl_started) {
3222 ins_compl_set_original_text(compl_leader);
3223 } else {
3224 spell_bad_len = 0; // need to redetect bad word
3225 // Matches were cleared, need to search for them now.
3226 // Set "compl_restarting" to avoid that the first match is inserted.
3227 compl_restarting = true;
3228 if (ins_complete(Ctrl_N, true) == FAIL) {
3229 compl_cont_status = 0;
3230 }
3231 compl_restarting = false;
3232 }
3233
3234 compl_enter_selects = !compl_used_match;
3235
3236 /* Show the popup menu with a different set of matches. */
3237 ins_compl_show_pum();
3238
3239 /* Don't let Enter select the original text when there is no popup menu.
3240 * Don't let Enter select when use user function and refresh_always is set */
3241 if (compl_match_array == NULL || ins_compl_need_restart())
3242 compl_enter_selects = FALSE;
3243}
3244
3245/*
3246 * Return the length of the completion, from the completion start column to
3247 * the cursor column. Making sure it never goes below zero.
3248 */
3249static int ins_compl_len(void)
3250{
3251 int off = (int)curwin->w_cursor.col - (int)compl_col;
3252
3253 if (off < 0)
3254 return 0;
3255 return off;
3256}
3257
3258/*
3259 * Append one character to the match leader. May reduce the number of
3260 * matches.
3261 */
3262static void ins_compl_addleader(int c)
3263{
3264 int cc;
3265
3266 if (stop_arrow() == FAIL) {
3267 return;
3268 }
3269 if ((cc = utf_char2len(c)) > 1) {
3270 char_u buf[MB_MAXBYTES + 1];
3271
3272 utf_char2bytes(c, buf);
3273 buf[cc] = NUL;
3274 ins_char_bytes(buf, cc);
3275 } else {
3276 ins_char(c);
3277 }
3278
3279 /* If we didn't complete finding matches we must search again. */
3280 if (ins_compl_need_restart())
3281 ins_compl_restart();
3282
3283 xfree(compl_leader);
3284 compl_leader = vim_strnsave(get_cursor_line_ptr() + compl_col,
3285 (int)(curwin->w_cursor.col - compl_col));
3286 ins_compl_new_leader();
3287}
3288
3289/*
3290 * Setup for finding completions again without leaving CTRL-X mode. Used when
3291 * BS or a key was typed while still searching for matches.
3292 */
3293static void ins_compl_restart(void)
3294{
3295 /* update screen before restart.
3296 * so if complete is blocked,
3297 * will stay to the last popup menu and reduce flicker */
3298 update_screen(0);
3299 ins_compl_free();
3300 compl_started = false;
3301 compl_matches = 0;
3302 compl_cont_status = 0;
3303 compl_cont_mode = 0;
3304}
3305
3306/*
3307 * Set the first match, the original text.
3308 */
3309static void ins_compl_set_original_text(char_u *str)
3310 FUNC_ATTR_NONNULL_ALL
3311{
3312 // Replace the original text entry.
3313 // The CP_ORIGINAL_TEXT flag is either at the first item or might possibly be
3314 // at the last item for backward completion
3315 if (compl_first_match->cp_flags & CP_ORIGINAL_TEXT) { // safety check
3316 xfree(compl_first_match->cp_str);
3317 compl_first_match->cp_str = vim_strsave(str);
3318 } else if (compl_first_match->cp_prev != NULL
3319 && (compl_first_match->cp_prev->cp_flags & CP_ORIGINAL_TEXT)) {
3320 xfree(compl_first_match->cp_prev->cp_str);
3321 compl_first_match->cp_prev->cp_str = vim_strsave(str);
3322 }
3323}
3324
3325/*
3326 * Append one character to the match leader. May reduce the number of
3327 * matches.
3328 */
3329static void ins_compl_addfrommatch(void)
3330{
3331 char_u *p;
3332 int len = (int)curwin->w_cursor.col - (int)compl_col;
3333 int c;
3334 compl_T *cp;
3335 assert(compl_shown_match != NULL);
3336 p = compl_shown_match->cp_str;
3337 if ((int)STRLEN(p) <= len) { /* the match is too short */
3338 /* When still at the original match use the first entry that matches
3339 * the leader. */
3340 if (compl_shown_match->cp_flags & CP_ORIGINAL_TEXT) {
3341 p = NULL;
3342 for (cp = compl_shown_match->cp_next; cp != NULL
3343 && cp != compl_first_match; cp = cp->cp_next) {
3344 if (compl_leader == NULL
3345 || ins_compl_equal(cp, compl_leader,
3346 (int)STRLEN(compl_leader))) {
3347 p = cp->cp_str;
3348 break;
3349 }
3350 }
3351 if (p == NULL || (int)STRLEN(p) <= len)
3352 return;
3353 } else
3354 return;
3355 }
3356 p += len;
3357 c = PTR2CHAR(p);
3358 ins_compl_addleader(c);
3359}
3360
3361/// Prepare for Insert mode completion, or stop it.
3362/// Called just after typing a character in Insert mode.
3363///
3364/// @param c character that was typed
3365///
3366/// @return true when the character is not to be inserted;
3367static bool ins_compl_prep(int c)
3368{
3369 char_u *ptr;
3370 bool retval = false;
3371
3372 /* Forget any previous 'special' messages if this is actually
3373 * a ^X mode key - bar ^R, in which case we wait to see what it gives us.
3374 */
3375 if (c != Ctrl_R && vim_is_ctrl_x_key(c))
3376 edit_submode_extra = NULL;
3377
3378 /* Ignore end of Select mode mapping and mouse scroll buttons. */
3379 if (c == K_SELECT || c == K_MOUSEDOWN || c == K_MOUSEUP
3380 || c == K_MOUSELEFT || c == K_MOUSERIGHT || c == K_EVENT
3381 || c == K_COMMAND) {
3382 return retval;
3383 }
3384
3385 /* Set "compl_get_longest" when finding the first matches. */
3386 if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET
3387 || (ctrl_x_mode == CTRL_X_NORMAL && !compl_started)) {
3388 compl_get_longest = (strstr((char *)p_cot, "longest") != NULL);
3389 compl_used_match = true;
3390 }
3391
3392 if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET) {
3393 /*
3394 * We have just typed CTRL-X and aren't quite sure which CTRL-X mode
3395 * it will be yet. Now we decide.
3396 */
3397 switch (c) {
3398 case Ctrl_E:
3399 case Ctrl_Y:
3400 ctrl_x_mode = CTRL_X_SCROLL;
3401 if (!(State & REPLACE_FLAG))
3402 edit_submode = (char_u *)_(" (insert) Scroll (^E/^Y)");
3403 else
3404 edit_submode = (char_u *)_(" (replace) Scroll (^E/^Y)");
3405 edit_submode_pre = NULL;
3406 showmode();
3407 break;
3408 case Ctrl_L:
3409 ctrl_x_mode = CTRL_X_WHOLE_LINE;
3410 break;
3411 case Ctrl_F:
3412 ctrl_x_mode = CTRL_X_FILES;
3413 break;
3414 case Ctrl_K:
3415 ctrl_x_mode = CTRL_X_DICTIONARY;
3416 break;
3417 case Ctrl_R:
3418 /* Simply allow ^R to happen without affecting ^X mode */
3419 break;
3420 case Ctrl_T:
3421 ctrl_x_mode = CTRL_X_THESAURUS;
3422 break;
3423 case Ctrl_U:
3424 ctrl_x_mode = CTRL_X_FUNCTION;
3425 break;
3426 case Ctrl_O:
3427 ctrl_x_mode = CTRL_X_OMNI;
3428 break;
3429 case 's':
3430 case Ctrl_S:
3431 ctrl_x_mode = CTRL_X_SPELL;
3432 ++emsg_off; /* Avoid getting the E756 error twice. */
3433 spell_back_to_badword();
3434 --emsg_off;
3435 break;
3436 case Ctrl_RSB:
3437 ctrl_x_mode = CTRL_X_TAGS;
3438 break;
3439 case Ctrl_I:
3440 case K_S_TAB:
3441 ctrl_x_mode = CTRL_X_PATH_PATTERNS;
3442 break;
3443 case Ctrl_D:
3444 ctrl_x_mode = CTRL_X_PATH_DEFINES;
3445 break;
3446 case Ctrl_V:
3447 case Ctrl_Q:
3448 ctrl_x_mode = CTRL_X_CMDLINE;
3449 break;
3450 case Ctrl_P:
3451 case Ctrl_N:
3452 /* ^X^P means LOCAL expansion if nothing interrupted (eg we
3453 * just started ^X mode, or there were enough ^X's to cancel
3454 * the previous mode, say ^X^F^X^X^P or ^P^X^X^X^P, see below)
3455 * do normal expansion when interrupting a different mode (say
3456 * ^X^F^X^P or ^P^X^X^P, see below)
3457 * nothing changes if interrupting mode 0, (eg, the flag
3458 * doesn't change when going to ADDING mode -- Acevedo */
3459 if (!(compl_cont_status & CONT_INTRPT))
3460 compl_cont_status |= CONT_LOCAL;
3461 else if (compl_cont_mode != 0)
3462 compl_cont_status &= ~CONT_LOCAL;
3463 FALLTHROUGH;
3464 default:
3465 /* If we have typed at least 2 ^X's... for modes != 0, we set
3466 * compl_cont_status = 0 (eg, as if we had just started ^X
3467 * mode).
3468 * For mode 0, we set "compl_cont_mode" to an impossible
3469 * value, in both cases ^X^X can be used to restart the same
3470 * mode (avoiding ADDING mode).
3471 * Undocumented feature: In a mode != 0 ^X^P and ^X^X^P start
3472 * 'complete' and local ^P expansions respectively.
3473 * In mode 0 an extra ^X is needed since ^X^P goes to ADDING
3474 * mode -- Acevedo */
3475 if (c == Ctrl_X) {
3476 if (compl_cont_mode != 0)
3477 compl_cont_status = 0;
3478 else
3479 compl_cont_mode = CTRL_X_NOT_DEFINED_YET;
3480 }
3481 ctrl_x_mode = CTRL_X_NORMAL;
3482 edit_submode = NULL;
3483 showmode();
3484 break;
3485 }
3486 } else if (ctrl_x_mode != CTRL_X_NORMAL) {
3487 // We're already in CTRL-X mode, do we stay in it?
3488 if (!vim_is_ctrl_x_key(c)) {
3489 if (ctrl_x_mode == CTRL_X_SCROLL) {
3490 ctrl_x_mode = CTRL_X_NORMAL;
3491 } else {
3492 ctrl_x_mode = CTRL_X_FINISHED;
3493 }
3494 edit_submode = NULL;
3495 }
3496 showmode();
3497 }
3498
3499 if (compl_started || ctrl_x_mode == CTRL_X_FINISHED) {
3500 /* Show error message from attempted keyword completion (probably
3501 * 'Pattern not found') until another key is hit, then go back to
3502 * showing what mode we are in. */
3503 showmode();
3504 if ((ctrl_x_mode == CTRL_X_NORMAL
3505 && c != Ctrl_N
3506 && c != Ctrl_P
3507 && c != Ctrl_R
3508 && !ins_compl_pum_key(c))
3509 || ctrl_x_mode == CTRL_X_FINISHED) {
3510 /* Get here when we have finished typing a sequence of ^N and
3511 * ^P or other completion characters in CTRL-X mode. Free up
3512 * memory that was used, and make sure we can redo the insert. */
3513 if (compl_curr_match != NULL || compl_leader != NULL || c == Ctrl_E) {
3514 /*
3515 * If any of the original typed text has been changed, eg when
3516 * ignorecase is set, we must add back-spaces to the redo
3517 * buffer. We add as few as necessary to delete just the part
3518 * of the original text that has changed.
3519 * When using the longest match, edited the match or used
3520 * CTRL-E then don't use the current match.
3521 */
3522 if (compl_curr_match != NULL && compl_used_match && c != Ctrl_E)
3523 ptr = compl_curr_match->cp_str;
3524 else
3525 ptr = NULL;
3526 ins_compl_fixRedoBufForLeader(ptr);
3527 }
3528
3529 bool want_cindent = (can_cindent && cindent_on());
3530 // When completing whole lines: fix indent for 'cindent'.
3531 // Otherwise, break line if it's too long.
3532 if (compl_cont_mode == CTRL_X_WHOLE_LINE) {
3533 /* re-indent the current line */
3534 if (want_cindent) {
3535 do_c_expr_indent();
3536 want_cindent = FALSE; /* don't do it again */
3537 }
3538 } else {
3539 int prev_col = curwin->w_cursor.col;
3540
3541 // put the cursor on the last char, for 'tw' formatting
3542 if (prev_col > 0) {
3543 dec_cursor();
3544 }
3545
3546 if (!arrow_used && !ins_need_undo && c != Ctrl_E) {
3547 insertchar(NUL, 0, -1);
3548 }
3549
3550 if (prev_col > 0
3551 && get_cursor_line_ptr()[curwin->w_cursor.col] != NUL) {
3552 inc_cursor();
3553 }
3554 }
3555
3556 // If the popup menu is displayed pressing CTRL-Y means accepting
3557 // the selection without inserting anything. When
3558 // compl_enter_selects is set the Enter key does the same.
3559 if ((c == Ctrl_Y || (compl_enter_selects
3560 && (c == CAR || c == K_KENTER || c == NL)))
3561 && pum_visible()) {
3562 retval = true;
3563 }
3564
3565 // CTRL-E means completion is Ended, go back to the typed text.
3566 // but only do this, if the Popup is still visible
3567 if (c == Ctrl_E) {
3568 ins_compl_delete();
3569 if (compl_leader != NULL) {
3570 ins_bytes(compl_leader + ins_compl_len());
3571 } else if (compl_first_match != NULL) {
3572 ins_bytes(compl_orig_text + ins_compl_len());
3573 }
3574 retval = true;
3575 }
3576
3577 auto_format(FALSE, TRUE);
3578
3579 ins_compl_free();
3580 compl_started = false;
3581 compl_matches = 0;
3582 if (!shortmess(SHM_COMPLETIONMENU)) {
3583 msg_clr_cmdline(); // necessary for "noshowmode"
3584 }
3585 ctrl_x_mode = CTRL_X_NORMAL;
3586 compl_enter_selects = false;
3587 if (edit_submode != NULL) {
3588 edit_submode = NULL;
3589 showmode();
3590 }
3591
3592 // Avoid the popup menu remains displayed when leaving the
3593 // command line window.
3594 if (c == Ctrl_C && cmdwin_type != 0) {
3595 update_screen(0);
3596 }
3597
3598 /*
3599 * Indent now if a key was typed that is in 'cinkeys'.
3600 */
3601 if (want_cindent && in_cinkeys(KEY_COMPLETE, ' ', inindent(0)))
3602 do_c_expr_indent();
3603 /* Trigger the CompleteDone event to give scripts a chance to act
3604 * upon the completion. */
3605 ins_apply_autocmds(EVENT_COMPLETEDONE);
3606 }
3607 } else if (ctrl_x_mode == CTRL_X_LOCAL_MSG)
3608 /* Trigger the CompleteDone event to give scripts a chance to act
3609 * upon the (possibly failed) completion. */
3610 ins_apply_autocmds(EVENT_COMPLETEDONE);
3611
3612 /* reset continue_* if we left expansion-mode, if we stay they'll be
3613 * (re)set properly in ins_complete() */
3614 if (!vim_is_ctrl_x_key(c)) {
3615 compl_cont_status = 0;
3616 compl_cont_mode = 0;
3617 }
3618
3619 return retval;
3620}
3621
3622/*
3623 * Fix the redo buffer for the completion leader replacing some of the typed
3624 * text. This inserts backspaces and appends the changed text.
3625 * "ptr" is the known leader text or NUL.
3626 */
3627static void ins_compl_fixRedoBufForLeader(char_u *ptr_arg)
3628{
3629 int len;
3630 char_u *p;
3631 char_u *ptr = ptr_arg;
3632
3633 if (ptr == NULL) {
3634 if (compl_leader != NULL)
3635 ptr = compl_leader;
3636 else
3637 return; /* nothing to do */
3638 }
3639 if (compl_orig_text != NULL) {
3640 p = compl_orig_text;
3641 for (len = 0; p[len] != NUL && p[len] == ptr[len]; len++) {}
3642 if (len > 0) {
3643 len -= utf_head_off(p, p + len);
3644 }
3645 for (p += len; *p != NUL; MB_PTR_ADV(p)) {
3646 AppendCharToRedobuff(K_BS);
3647 }
3648 } else {
3649 len = 0;
3650 }
3651 AppendToRedobuffLit(ptr + len, -1);
3652}
3653
3654/*
3655 * Loops through the list of windows, loaded-buffers or non-loaded-buffers
3656 * (depending on flag) starting from buf and looking for a non-scanned
3657 * buffer (other than curbuf). curbuf is special, if it is called with
3658 * buf=curbuf then it has to be the first call for a given flag/expansion.
3659 *
3660 * Returns the buffer to scan, if any, otherwise returns curbuf -- Acevedo
3661 */
3662static buf_T *ins_compl_next_buf(buf_T *buf, int flag)
3663{
3664 static win_T *wp;
3665
3666 if (flag == 'w') { /* just windows */
3667 if (buf == curbuf) /* first call for this flag/expansion */
3668 wp = curwin;
3669 assert(wp);
3670 while ((wp = (wp->w_next != NULL ? wp->w_next : firstwin)) != curwin
3671 && wp->w_buffer->b_scanned)
3672 ;
3673 buf = wp->w_buffer;
3674 } else
3675 /* 'b' (just loaded buffers), 'u' (just non-loaded buffers) or 'U'
3676 * (unlisted buffers)
3677 * When completing whole lines skip unloaded buffers. */
3678 while ((buf = (buf->b_next != NULL ? buf->b_next : firstbuf)) != curbuf
3679 && ((flag == 'U'
3680 ? buf->b_p_bl
3681 : (!buf->b_p_bl
3682 || (buf->b_ml.ml_mfp == NULL) != (flag == 'u')))
3683 || buf->b_scanned))
3684 ;
3685 return buf;
3686}
3687
3688
3689// Execute user defined complete function 'completefunc' or 'omnifunc', and
3690// get matches in "matches".
3691static void
3692expand_by_function(
3693 int type, // CTRL_X_OMNI or CTRL_X_FUNCTION
3694 char_u *base
3695)
3696{
3697 list_T *matchlist = NULL;
3698 dict_T *matchdict = NULL;
3699 char_u *funcname;
3700 pos_T pos;
3701 win_T *curwin_save;
3702 buf_T *curbuf_save;
3703 typval_T rettv;
3704 const int save_State = State;
3705
3706 assert(curbuf != NULL);
3707 funcname = (type == CTRL_X_FUNCTION) ? curbuf->b_p_cfu : curbuf->b_p_ofu;
3708 if (*funcname == NUL) {
3709 return;
3710 }
3711
3712 // Call 'completefunc' to obtain the list of matches.
3713 typval_T args[3];
3714 args[0].v_type = VAR_NUMBER;
3715 args[1].v_type = VAR_STRING;
3716 args[2].v_type = VAR_UNKNOWN;
3717 args[0].vval.v_number = 0;
3718 args[1].vval.v_string = base != NULL ? base : (char_u *)"";
3719
3720 pos = curwin->w_cursor;
3721 curwin_save = curwin;
3722 curbuf_save = curbuf;
3723
3724 // Call a function, which returns a list or dict.
3725 if (call_vim_function(funcname, 2, args, &rettv) == OK) {
3726 switch (rettv.v_type) {
3727 case VAR_LIST:
3728 matchlist = rettv.vval.v_list;
3729 break;
3730 case VAR_DICT:
3731 matchdict = rettv.vval.v_dict;
3732 break;
3733 default:
3734 // TODO(brammool): Give error message?
3735 tv_clear(&rettv);
3736 break;
3737 }
3738 }
3739
3740 if (curwin_save != curwin || curbuf_save != curbuf) {
3741 EMSG(_(e_complwin));
3742 goto theend;
3743 }
3744 curwin->w_cursor = pos; /* restore the cursor position */
3745 validate_cursor();
3746 if (!equalpos(curwin->w_cursor, pos)) {
3747 EMSG(_(e_compldel));
3748 goto theend;
3749 }
3750
3751 if (matchlist != NULL)
3752 ins_compl_add_list(matchlist);
3753 else if (matchdict != NULL)
3754 ins_compl_add_dict(matchdict);
3755
3756theend:
3757 // Restore State, it might have been changed.
3758 State = save_State;
3759
3760 if (matchdict != NULL) {
3761 tv_dict_unref(matchdict);
3762 }
3763 if (matchlist != NULL) {
3764 tv_list_unref(matchlist);
3765 }
3766}
3767
3768/*
3769 * Add completions from a list.
3770 */
3771static void ins_compl_add_list(list_T *const list)
3772{
3773 int dir = compl_direction;
3774
3775 // Go through the List with matches and add each of them.
3776 TV_LIST_ITER(list, li, {
3777 if (ins_compl_add_tv(TV_LIST_ITEM_TV(li), dir) == OK) {
3778 // If dir was BACKWARD then honor it just once.
3779 dir = FORWARD;
3780 } else if (did_emsg) {
3781 break;
3782 }
3783 });
3784}
3785
3786/*
3787 * Add completions from a dict.
3788 */
3789static void ins_compl_add_dict(dict_T *dict)
3790{
3791 dictitem_T *di_refresh;
3792 dictitem_T *di_words;
3793
3794 // Check for optional "refresh" item.
3795 compl_opt_refresh_always = false;
3796 di_refresh = tv_dict_find(dict, S_LEN("refresh"));
3797 if (di_refresh != NULL && di_refresh->di_tv.v_type == VAR_STRING) {
3798 const char *v = (const char *)di_refresh->di_tv.vval.v_string;
3799
3800 if (v != NULL && strcmp(v, "always") == 0) {
3801 compl_opt_refresh_always = true;
3802 }
3803 }
3804
3805 // Add completions from a "words" list.
3806 di_words = tv_dict_find(dict, S_LEN("words"));
3807 if (di_words != NULL && di_words->di_tv.v_type == VAR_LIST) {
3808 ins_compl_add_list(di_words->di_tv.vval.v_list);
3809 }
3810}
3811
3812/// Add a match to the list of matches from VimL object
3813///
3814/// @param[in] tv Object to get matches from.
3815/// @param[in] dir Completion direction.
3816///
3817/// @return NOTDONE if the given string is already in the list of completions,
3818/// otherwise it is added to the list and OK is returned. FAIL will be
3819/// returned in case of error.
3820int ins_compl_add_tv(typval_T *const tv, const Direction dir)
3821 FUNC_ATTR_NONNULL_ALL
3822{
3823 const char *word;
3824 bool dup = false;
3825 bool empty = false;
3826 int flags = 0;
3827 char *(cptext[CPT_COUNT]);
3828
3829 if (tv->v_type == VAR_DICT && tv->vval.v_dict != NULL) {
3830 word = tv_dict_get_string(tv->vval.v_dict, "word", false);
3831 cptext[CPT_ABBR] = tv_dict_get_string(tv->vval.v_dict, "abbr", true);
3832 cptext[CPT_MENU] = tv_dict_get_string(tv->vval.v_dict, "menu", true);
3833 cptext[CPT_KIND] = tv_dict_get_string(tv->vval.v_dict, "kind", true);
3834 cptext[CPT_INFO] = tv_dict_get_string(tv->vval.v_dict, "info", true);
3835 cptext[CPT_USER_DATA] = tv_dict_get_string(tv->vval.v_dict,
3836 "user_data", true);
3837
3838 if (tv_dict_get_number(tv->vval.v_dict, "icase")) {
3839 flags |= CP_ICASE;
3840 }
3841 dup = (bool)tv_dict_get_number(tv->vval.v_dict, "dup");
3842 empty = (bool)tv_dict_get_number(tv->vval.v_dict, "empty");
3843 if (tv_dict_get_string(tv->vval.v_dict, "equal", false) != NULL
3844 && tv_dict_get_number(tv->vval.v_dict, "equal")) {
3845 flags |= CP_EQUAL;
3846 }
3847 } else {
3848 word = (const char *)tv_get_string_chk(tv);
3849 memset(cptext, 0, sizeof(cptext));
3850 }
3851 if (word == NULL || (!empty && *word == NUL)) {
3852 for (size_t i = 0; i < CPT_COUNT; i++) {
3853 xfree(cptext[i]);
3854 }
3855 return FAIL;
3856 }
3857 return ins_compl_add((char_u *)word, -1, NULL,
3858 (char_u **)cptext, true, dir, flags, dup);
3859}
3860
3861// Get the next expansion(s), using "compl_pattern".
3862// The search starts at position "ini" in curbuf and in the direction
3863// compl_direction.
3864// When "compl_started" is false start at that position, otherwise continue
3865// where we stopped searching before.
3866// This may return before finding all the matches.
3867// Return the total number of matches or -1 if still unknown -- Acevedo
3868static int ins_compl_get_exp(pos_T *ini)
3869{
3870 static pos_T first_match_pos;
3871 static pos_T last_match_pos;
3872 static char_u *e_cpt = (char_u *)""; // curr. entry in 'complete'
3873 static int found_all = false; // Found all matches of a
3874 // certain type.
3875 static buf_T *ins_buf = NULL; // buffer being scanned
3876
3877 pos_T *pos;
3878 char_u **matches;
3879 int save_p_scs;
3880 bool save_p_ws;
3881 int save_p_ic;
3882 int i;
3883 int num_matches;
3884 int len;
3885 int found_new_match;
3886 int type = ctrl_x_mode;
3887 char_u *ptr;
3888 char_u *dict = NULL;
3889 int dict_f = 0;
3890 int set_match_pos;
3891 int l_ctrl_x_mode = ctrl_x_mode;
3892
3893 assert(curbuf != NULL);
3894
3895 if (!compl_started) {
3896 FOR_ALL_BUFFERS(buf) {
3897 buf->b_scanned = false;
3898 }
3899 found_all = FALSE;
3900 ins_buf = curbuf;
3901 e_cpt = (compl_cont_status & CONT_LOCAL)
3902 ? (char_u *)"." : curbuf->b_p_cpt;
3903 last_match_pos = first_match_pos = *ini;
3904 } else if (ins_buf != curbuf && !buf_valid(ins_buf)) {
3905 ins_buf = curbuf; // In case the buffer was wiped out.
3906 }
3907
3908 compl_old_match = compl_curr_match; // remember the last current match
3909 pos = (compl_direction == FORWARD) ? &last_match_pos : &first_match_pos;
3910
3911 // For ^N/^P loop over all the flags/windows/buffers in 'complete'
3912 for (;; ) {
3913 found_new_match = FAIL;
3914 set_match_pos = FALSE;
3915
3916 assert(l_ctrl_x_mode == ctrl_x_mode);
3917
3918 // For ^N/^P pick a new entry from e_cpt if compl_started is off,
3919 // or if found_all says this entry is done. For ^X^L only use the
3920 // entries from 'complete' that look in loaded buffers.
3921 if ((l_ctrl_x_mode == CTRL_X_NORMAL
3922 || CTRL_X_MODE_LINE_OR_EVAL(l_ctrl_x_mode))
3923 && (!compl_started || found_all)) {
3924 found_all = FALSE;
3925 while (*e_cpt == ',' || *e_cpt == ' ')
3926 e_cpt++;
3927 if (*e_cpt == '.' && !curbuf->b_scanned) {
3928 ins_buf = curbuf;
3929 first_match_pos = *ini;
3930 // Move the cursor back one character so that ^N can match the
3931 // word immediately after the cursor.
3932 if (ctrl_x_mode == CTRL_X_NORMAL && dec(&first_match_pos) < 0) {
3933 // Move the cursor to after the last character in the
3934 // buffer, so that word at start of buffer is found
3935 // correctly.
3936 first_match_pos.lnum = ins_buf->b_ml.ml_line_count;
3937 first_match_pos.col = (colnr_T)STRLEN(ml_get(first_match_pos.lnum));
3938 }
3939 last_match_pos = first_match_pos;
3940 type = 0;
3941
3942 // Remember the first match so that the loop stops when we
3943 // wrap and come back there a second time.
3944 set_match_pos = true;
3945 } else if (vim_strchr((char_u *)"buwU", *e_cpt) != NULL
3946 && (ins_buf =
3947 ins_compl_next_buf(ins_buf, *e_cpt)) != curbuf) {
3948 // Scan a buffer, but not the current one.
3949 if (ins_buf->b_ml.ml_mfp != NULL) { // loaded buffer
3950 compl_started = true;
3951 first_match_pos.col = last_match_pos.col = 0;
3952 first_match_pos.lnum = ins_buf->b_ml.ml_line_count + 1;
3953 last_match_pos.lnum = 0;
3954 type = 0;
3955 } else { // unloaded buffer, scan like dictionary
3956 found_all = true;
3957 if (ins_buf->b_fname == NULL) {
3958 continue;
3959 }
3960 type = CTRL_X_DICTIONARY;
3961 dict = ins_buf->b_fname;
3962 dict_f = DICT_EXACT;
3963 }
3964 vim_snprintf((char *)IObuff, IOSIZE, _("Scanning: %s"),
3965 ins_buf->b_fname == NULL
3966 ? buf_spname(ins_buf)
3967 : ins_buf->b_sfname == NULL
3968 ? ins_buf->b_fname
3969 : ins_buf->b_sfname);
3970 (void)msg_trunc_attr(IObuff, true, HL_ATTR(HLF_R));
3971 } else if (*e_cpt == NUL) {
3972 break;
3973 } else {
3974 if (CTRL_X_MODE_LINE_OR_EVAL(l_ctrl_x_mode)) {
3975 type = -1;
3976 } else if (*e_cpt == 'k' || *e_cpt == 's') {
3977 if (*e_cpt == 'k')
3978 type = CTRL_X_DICTIONARY;
3979 else
3980 type = CTRL_X_THESAURUS;
3981 if (*++e_cpt != ',' && *e_cpt != NUL) {
3982 dict = e_cpt;
3983 dict_f = DICT_FIRST;
3984 }
3985 } else if (*e_cpt == 'i')
3986 type = CTRL_X_PATH_PATTERNS;
3987 else if (*e_cpt == 'd')
3988 type = CTRL_X_PATH_DEFINES;
3989 else if (*e_cpt == ']' || *e_cpt == 't') {
3990 type = CTRL_X_TAGS;
3991 vim_snprintf((char *)IObuff, IOSIZE, _("Scanning tags."));
3992 (void)msg_trunc_attr(IObuff, true, HL_ATTR(HLF_R));
3993 } else {
3994 type = -1;
3995 }
3996
3997 // in any case e_cpt is advanced to the next entry
3998 (void)copy_option_part(&e_cpt, IObuff, IOSIZE, ",");
3999
4000 found_all = TRUE;
4001 if (type == -1)
4002 continue;
4003 }
4004 }
4005
4006 // If complete() was called then compl_pattern has been reset.
4007 // The following won't work then, bail out.
4008 if (compl_pattern == NULL) {
4009 break;
4010 }
4011
4012 switch (type) {
4013 case -1:
4014 break;
4015 case CTRL_X_PATH_PATTERNS:
4016 case CTRL_X_PATH_DEFINES:
4017 find_pattern_in_path(compl_pattern, compl_direction,
4018 STRLEN(compl_pattern), FALSE, FALSE,
4019 ((type == CTRL_X_PATH_DEFINES
4020 && !(compl_cont_status & CONT_SOL))
4021 ? FIND_DEFINE
4022 : FIND_ANY),
4023 1L, ACTION_EXPAND, 1, MAXLNUM);
4024 break;
4025
4026 case CTRL_X_DICTIONARY:
4027 case CTRL_X_THESAURUS:
4028 ins_compl_dictionaries(
4029 dict != NULL ? dict
4030 : (type == CTRL_X_THESAURUS
4031 ? (*curbuf->b_p_tsr == NUL
4032 ? p_tsr
4033 : curbuf->b_p_tsr)
4034 : (*curbuf->b_p_dict == NUL
4035 ? p_dict
4036 : curbuf->b_p_dict)),
4037 compl_pattern,
4038 dict != NULL ? dict_f
4039 : 0, type == CTRL_X_THESAURUS);
4040 dict = NULL;
4041 break;
4042
4043 case CTRL_X_TAGS:
4044 // set p_ic according to p_ic, p_scs and pat for find_tags().
4045 save_p_ic = p_ic;
4046 p_ic = ignorecase(compl_pattern);
4047
4048 // Find up to TAG_MANY matches. Avoids that an enormous number
4049 // of matches is found when compl_pattern is empty
4050 if (find_tags(compl_pattern, &num_matches, &matches,
4051 TAG_REGEXP | TAG_NAMES | TAG_NOIC | TAG_INS_COMP
4052 | (l_ctrl_x_mode != CTRL_X_NORMAL ? TAG_VERBOSE : 0),
4053 TAG_MANY, curbuf->b_ffname) == OK && num_matches > 0) {
4054 ins_compl_add_matches(num_matches, matches, p_ic);
4055 }
4056 p_ic = save_p_ic;
4057 break;
4058
4059 case CTRL_X_FILES:
4060 if (expand_wildcards(1, &compl_pattern, &num_matches, &matches,
4061 EW_FILE|EW_DIR|EW_ADDSLASH|EW_SILENT) == OK) {
4062 // May change home directory back to "~".
4063 tilde_replace(compl_pattern, num_matches, matches);
4064 ins_compl_add_matches(num_matches, matches, p_fic || p_wic);
4065 }
4066 break;
4067
4068 case CTRL_X_CMDLINE:
4069 if (expand_cmdline(&compl_xp, compl_pattern,
4070 (int)STRLEN(compl_pattern),
4071 &num_matches, &matches) == EXPAND_OK)
4072 ins_compl_add_matches(num_matches, matches, FALSE);
4073 break;
4074
4075 case CTRL_X_FUNCTION:
4076 case CTRL_X_OMNI:
4077 expand_by_function(type, compl_pattern);
4078 break;
4079
4080 case CTRL_X_SPELL:
4081 num_matches = expand_spelling(first_match_pos.lnum,
4082 compl_pattern, &matches);
4083 if (num_matches > 0)
4084 ins_compl_add_matches(num_matches, matches, p_ic);
4085 break;
4086
4087 default: // normal ^P/^N and ^X^L
4088 // If 'infercase' is set, don't use 'smartcase' here
4089 save_p_scs = p_scs;
4090 assert(ins_buf);
4091 if (ins_buf->b_p_inf)
4092 p_scs = FALSE;
4093
4094 // Buffers other than curbuf are scanned from the beginning or the
4095 // end but never from the middle, thus setting nowrapscan in this
4096 // buffers is a good idea, on the other hand, we always set
4097 // wrapscan for curbuf to avoid missing matches -- Acevedo,Webb
4098 save_p_ws = p_ws;
4099 if (ins_buf != curbuf)
4100 p_ws = false;
4101 else if (*e_cpt == '.')
4102 p_ws = true;
4103 for (;; ) {
4104 bool cont_s_ipos = false;
4105
4106 msg_silent++; // Don't want messages for wrapscan.
4107 // CTRL_X_MODE_LINE_OR_EVAL(l_ctrl_x_mode) || word-wise search that
4108 // has added a word that was at the beginning of the line.
4109 if (CTRL_X_MODE_LINE_OR_EVAL(l_ctrl_x_mode)
4110 || (compl_cont_status & CONT_SOL)) {
4111 found_new_match = search_for_exact_line(ins_buf, pos,
4112 compl_direction,
4113 compl_pattern);
4114 } else {
4115 found_new_match = searchit(NULL, ins_buf, pos, NULL,
4116 compl_direction,
4117 compl_pattern, 1L,
4118 SEARCH_KEEP + SEARCH_NFMSG,
4119 RE_LAST, (linenr_T)0, NULL, NULL);
4120 }
4121 msg_silent--;
4122 if (!compl_started || set_match_pos) {
4123 // set "compl_started" even on fail
4124 compl_started = true;
4125 first_match_pos = *pos;
4126 last_match_pos = *pos;
4127 set_match_pos = false;
4128 } else if (first_match_pos.lnum == last_match_pos.lnum
4129 && first_match_pos.col == last_match_pos.col) {
4130 found_new_match = FAIL;
4131 }
4132 if (found_new_match == FAIL) {
4133 if (ins_buf == curbuf)
4134 found_all = TRUE;
4135 break;
4136 }
4137
4138 // when ADDING, the text before the cursor matches, skip it
4139 if ((compl_cont_status & CONT_ADDING) && ins_buf == curbuf
4140 && ini->lnum == pos->lnum
4141 && ini->col == pos->col) {
4142 continue;
4143 }
4144 ptr = ml_get_buf(ins_buf, pos->lnum, false) + pos->col;
4145 if (CTRL_X_MODE_LINE_OR_EVAL(l_ctrl_x_mode)) {
4146 if (compl_cont_status & CONT_ADDING) {
4147 if (pos->lnum >= ins_buf->b_ml.ml_line_count) {
4148 continue;
4149 }
4150 ptr = ml_get_buf(ins_buf, pos->lnum + 1, false);
4151 if (!p_paste) {
4152 ptr = skipwhite(ptr);
4153 }
4154 }
4155 len = (int)STRLEN(ptr);
4156 } else {
4157 char_u *tmp_ptr = ptr;
4158
4159 if (compl_cont_status & CONT_ADDING) {
4160 tmp_ptr += compl_length;
4161 // Skip if already inside a word.
4162 if (vim_iswordp(tmp_ptr)) {
4163 continue;
4164 }
4165 // Find start of next word.
4166 tmp_ptr = find_word_start(tmp_ptr);
4167 }
4168 // Find end of this word.
4169 tmp_ptr = find_word_end(tmp_ptr);
4170 len = (int)(tmp_ptr - ptr);
4171
4172 if ((compl_cont_status & CONT_ADDING)
4173 && len == compl_length) {
4174 if (pos->lnum < ins_buf->b_ml.ml_line_count) {
4175 // Try next line, if any. the new word will be "join" as if the
4176 // normal command "J" was used. IOSIZE is always greater than
4177 // compl_length, so the next STRNCPY always works -- Acevedo
4178 STRNCPY(IObuff, ptr, len);
4179 ptr = ml_get_buf(ins_buf, pos->lnum + 1, false);
4180 tmp_ptr = ptr = skipwhite(ptr);
4181 // Find start of next word.
4182 tmp_ptr = find_word_start(tmp_ptr);
4183 // Find end of next word.
4184 tmp_ptr = find_word_end(tmp_ptr);
4185 if (tmp_ptr > ptr) {
4186 if (*ptr != ')' && IObuff[len - 1] != TAB) {
4187 if (IObuff[len - 1] != ' ') {
4188 IObuff[len++] = ' ';
4189 }
4190 // IObuf =~ "\k.* ", thus len >= 2
4191 if (p_js
4192 && (IObuff[len - 2] == '.'
4193 || IObuff[len - 2] == '?'
4194 || IObuff[len - 2] == '!')) {
4195 IObuff[len++] = ' ';
4196 }
4197 }
4198 // copy as much as possible of the new word
4199 if (tmp_ptr - ptr >= IOSIZE - len) {
4200 tmp_ptr = ptr + IOSIZE - len - 1;
4201 }
4202 STRLCPY(IObuff + len, ptr, IOSIZE - len);
4203 len += (int)(tmp_ptr - ptr);
4204 cont_s_ipos = true;
4205 }
4206 IObuff[len] = NUL;
4207 ptr = IObuff;
4208 }
4209 if (len == compl_length)
4210 continue;
4211 }
4212 }
4213 if (ins_compl_add_infercase(
4214 ptr, len, p_ic, ins_buf == curbuf ? NULL : ins_buf->b_sfname,
4215 0, cont_s_ipos) != NOTDONE) {
4216 found_new_match = OK;
4217 break;
4218 }
4219 }
4220 p_scs = save_p_scs;
4221 p_ws = save_p_ws;
4222 }
4223
4224 // check if compl_curr_match has changed, (e.g. other type of
4225 // expansion added something)
4226 if (type != 0 && compl_curr_match != compl_old_match) {
4227 found_new_match = OK;
4228 }
4229
4230 // break the loop for specialized modes (use 'complete' just for the
4231 // generic l_ctrl_x_mode == CTRL_X_NORMAL) or when we've found a new match
4232 if ((l_ctrl_x_mode != CTRL_X_NORMAL
4233 && !CTRL_X_MODE_LINE_OR_EVAL(l_ctrl_x_mode))
4234 || found_new_match != FAIL) {
4235 if (got_int)
4236 break;
4237 // Fill the popup menu as soon as possible.
4238 if (type != -1) {
4239 ins_compl_check_keys(0, false);
4240 }
4241
4242 if ((l_ctrl_x_mode != CTRL_X_NORMAL
4243 && !CTRL_X_MODE_LINE_OR_EVAL(l_ctrl_x_mode))
4244 || compl_interrupted) {
4245 break;
4246 }
4247 compl_started = true;
4248 } else {
4249 // Mark a buffer scanned when it has been scanned completely
4250 if (type == 0 || type == CTRL_X_PATH_PATTERNS) {
4251 assert(ins_buf);
4252 ins_buf->b_scanned = true;
4253 }
4254
4255 compl_started = false;
4256 }
4257 }
4258 compl_started = true;
4259
4260 if ((l_ctrl_x_mode == CTRL_X_NORMAL
4261 || CTRL_X_MODE_LINE_OR_EVAL(l_ctrl_x_mode))
4262 && *e_cpt == NUL) { // Got to end of 'complete'
4263 found_new_match = FAIL;
4264 }
4265
4266 i = -1; // total of matches, unknown
4267 if (found_new_match == FAIL
4268 || (l_ctrl_x_mode != CTRL_X_NORMAL
4269 && !CTRL_X_MODE_LINE_OR_EVAL(l_ctrl_x_mode))) {
4270 i = ins_compl_make_cyclic();
4271 }
4272
4273 if (compl_old_match != NULL) {
4274 // If several matches were added (FORWARD) or the search failed and has
4275 // just been made cyclic then we have to move compl_curr_match to the
4276 // next or previous entry (if any) -- Acevedo
4277 compl_curr_match = compl_direction == FORWARD
4278 ? compl_old_match->cp_next
4279 : compl_old_match->cp_prev;
4280 if (compl_curr_match == NULL) {
4281 compl_curr_match = compl_old_match;
4282 }
4283 }
4284 return i;
4285}
4286
4287// Delete the old text being completed.
4288static void ins_compl_delete(void)
4289{
4290 int col;
4291
4292 // In insert mode: Delete the typed part.
4293 // In replace mode: Put the old characters back, if any.
4294 col = compl_col + (compl_cont_status & CONT_ADDING ? compl_length : 0);
4295 if ((int)curwin->w_cursor.col > col) {
4296 if (stop_arrow() == FAIL) {
4297 return;
4298 }
4299 backspace_until_column(col);
4300 }
4301
4302 // TODO(vim): is this sufficient for redrawing? Redrawing everything
4303 // causes flicker, thus we can't do that.
4304 changed_cline_bef_curs();
4305 // clear v:completed_item
4306 set_vim_var_dict(VV_COMPLETED_ITEM, tv_dict_alloc());
4307}
4308
4309// Insert the new text being completed.
4310// "in_compl_func" is TRUE when called from complete_check().
4311static void ins_compl_insert(int in_compl_func)
4312{
4313 ins_bytes(compl_shown_match->cp_str + ins_compl_len());
4314 compl_used_match = !(compl_shown_match->cp_flags & CP_ORIGINAL_TEXT);
4315
4316 dict_T *dict = ins_compl_dict_alloc(compl_shown_match);
4317 set_vim_var_dict(VV_COMPLETED_ITEM, dict);
4318 if (!in_compl_func) {
4319 compl_curr_match = compl_shown_match;
4320 }
4321}
4322
4323// Convert to complete item dict
4324static dict_T *ins_compl_dict_alloc(compl_T *match)
4325{
4326 // { word, abbr, menu, kind, info }
4327 dict_T *dict = tv_dict_alloc();
4328 tv_dict_add_str(
4329 dict, S_LEN("word"),
4330 (const char *)EMPTY_IF_NULL(match->cp_str));
4331 tv_dict_add_str(
4332 dict, S_LEN("abbr"),
4333 (const char *)EMPTY_IF_NULL(match->cp_text[CPT_ABBR]));
4334 tv_dict_add_str(
4335 dict, S_LEN("menu"),
4336 (const char *)EMPTY_IF_NULL(match->cp_text[CPT_MENU]));
4337 tv_dict_add_str(
4338 dict, S_LEN("kind"),
4339 (const char *)EMPTY_IF_NULL(match->cp_text[CPT_KIND]));
4340 tv_dict_add_str(
4341 dict, S_LEN("info"),
4342 (const char *)EMPTY_IF_NULL(match->cp_text[CPT_INFO]));
4343 tv_dict_add_str(
4344 dict, S_LEN("user_data"),
4345 (const char *)EMPTY_IF_NULL(match->cp_text[CPT_USER_DATA]));
4346 return dict;
4347}
4348
4349/*
4350 * Fill in the next completion in the current direction.
4351 * If "allow_get_expansion" is TRUE, then we may call ins_compl_get_exp() to
4352 * get more completions. If it is FALSE, then we just do nothing when there
4353 * are no more completions in a given direction. The latter case is used when
4354 * we are still in the middle of finding completions, to allow browsing
4355 * through the ones found so far.
4356 * Return the total number of matches, or -1 if still unknown -- webb.
4357 *
4358 * compl_curr_match is currently being used by ins_compl_get_exp(), so we use
4359 * compl_shown_match here.
4360 *
4361 * Note that this function may be called recursively once only. First with
4362 * "allow_get_expansion" TRUE, which calls ins_compl_get_exp(), which in turn
4363 * calls this function with "allow_get_expansion" FALSE.
4364 */
4365static int
4366ins_compl_next (
4367 int allow_get_expansion,
4368 int count, // Repeat completion this many times; should
4369 // be at least 1
4370 int insert_match, // Insert the newly selected match
4371 int in_compl_func // Called from complete_check()
4372)
4373{
4374 int num_matches = -1;
4375 int todo = count;
4376 compl_T *found_compl = NULL;
4377 int found_end = FALSE;
4378 int advance;
4379 const bool started = compl_started;
4380
4381 /* When user complete function return -1 for findstart which is next
4382 * time of 'always', compl_shown_match become NULL. */
4383 if (compl_shown_match == NULL)
4384 return -1;
4385
4386 if (compl_leader != NULL
4387 && (compl_shown_match->cp_flags & CP_ORIGINAL_TEXT) == 0) {
4388 // Set "compl_shown_match" to the actually shown match, it may differ
4389 // when "compl_leader" is used to omit some of the matches.
4390 while (!ins_compl_equal(compl_shown_match,
4391 compl_leader, STRLEN(compl_leader))
4392 && compl_shown_match->cp_next != NULL
4393 && compl_shown_match->cp_next != compl_first_match) {
4394 compl_shown_match = compl_shown_match->cp_next;
4395 }
4396
4397 /* If we didn't find it searching forward, and compl_shows_dir is
4398 * backward, find the last match. */
4399 if (compl_shows_dir == BACKWARD
4400 && !ins_compl_equal(compl_shown_match,
4401 compl_leader, (int)STRLEN(compl_leader))
4402 && (compl_shown_match->cp_next == NULL
4403 || compl_shown_match->cp_next == compl_first_match)) {
4404 while (!ins_compl_equal(compl_shown_match,
4405 compl_leader, (int)STRLEN(compl_leader))
4406 && compl_shown_match->cp_prev != NULL
4407 && compl_shown_match->cp_prev != compl_first_match)
4408 compl_shown_match = compl_shown_match->cp_prev;
4409 }
4410 }
4411
4412 if (allow_get_expansion && insert_match
4413 && (!(compl_get_longest || compl_restarting) || compl_used_match))
4414 /* Delete old text to be replaced */
4415 ins_compl_delete();
4416
4417 /* When finding the longest common text we stick at the original text,
4418 * don't let CTRL-N or CTRL-P move to the first match. */
4419 advance = count != 1 || !allow_get_expansion || !compl_get_longest;
4420
4421 /* When restarting the search don't insert the first match either. */
4422 if (compl_restarting) {
4423 advance = FALSE;
4424 compl_restarting = FALSE;
4425 }
4426
4427 /* Repeat this for when <PageUp> or <PageDown> is typed. But don't wrap
4428 * around. */
4429 while (--todo >= 0) {
4430 if (compl_shows_dir == FORWARD && compl_shown_match->cp_next != NULL) {
4431 compl_shown_match = compl_shown_match->cp_next;
4432 found_end = (compl_first_match != NULL
4433 && (compl_shown_match->cp_next == compl_first_match
4434 || compl_shown_match == compl_first_match));
4435 } else if (compl_shows_dir == BACKWARD
4436 && compl_shown_match->cp_prev != NULL) {
4437 found_end = (compl_shown_match == compl_first_match);
4438 compl_shown_match = compl_shown_match->cp_prev;
4439 found_end |= (compl_shown_match == compl_first_match);
4440 } else {
4441 if (!allow_get_expansion) {
4442 if (advance) {
4443 if (compl_shows_dir == BACKWARD)
4444 compl_pending -= todo + 1;
4445 else
4446 compl_pending += todo + 1;
4447 }
4448 return -1;
4449 }
4450
4451 if (!compl_no_select && advance) {
4452 if (compl_shows_dir == BACKWARD)
4453 --compl_pending;
4454 else
4455 ++compl_pending;
4456 }
4457
4458 /* Find matches. */
4459 num_matches = ins_compl_get_exp(&compl_startpos);
4460
4461 /* handle any pending completions */
4462 while (compl_pending != 0 && compl_direction == compl_shows_dir
4463 && advance) {
4464 if (compl_pending > 0 && compl_shown_match->cp_next != NULL) {
4465 compl_shown_match = compl_shown_match->cp_next;
4466 --compl_pending;
4467 }
4468 if (compl_pending < 0 && compl_shown_match->cp_prev != NULL) {
4469 compl_shown_match = compl_shown_match->cp_prev;
4470 ++compl_pending;
4471 } else
4472 break;
4473 }
4474 found_end = FALSE;
4475 }
4476 if ((compl_shown_match->cp_flags & CP_ORIGINAL_TEXT) == 0
4477 && compl_leader != NULL
4478 && !ins_compl_equal(compl_shown_match,
4479 compl_leader, STRLEN(compl_leader))) {
4480 todo++;
4481 } else {
4482 // Remember a matching item.
4483 found_compl = compl_shown_match;
4484 }
4485
4486 /* Stop at the end of the list when we found a usable match. */
4487 if (found_end) {
4488 if (found_compl != NULL) {
4489 compl_shown_match = found_compl;
4490 break;
4491 }
4492 todo = 1; /* use first usable match after wrapping around */
4493 }
4494 }
4495
4496 /* Insert the text of the new completion, or the compl_leader. */
4497 if (compl_no_insert && !started) {
4498 ins_bytes(compl_orig_text + ins_compl_len());
4499 compl_used_match = false;
4500 } else if (insert_match) {
4501 if (!compl_get_longest || compl_used_match) {
4502 ins_compl_insert(in_compl_func);
4503 } else {
4504 ins_bytes(compl_leader + ins_compl_len());
4505 }
4506 } else {
4507 compl_used_match = false;
4508 }
4509
4510 if (!allow_get_expansion) {
4511 // redraw to show the user what was inserted
4512 update_screen(0);
4513
4514 // display the updated popup menu
4515 ins_compl_show_pum();
4516
4517 // Delete old text to be replaced, since we're still searching and
4518 // don't want to match ourselves!
4519 ins_compl_delete();
4520 }
4521
4522 /* Enter will select a match when the match wasn't inserted and the popup
4523 * menu is visible. */
4524 if (compl_no_insert && !started) {
4525 compl_enter_selects = TRUE;
4526 } else {
4527 compl_enter_selects = !insert_match && compl_match_array != NULL;
4528 }
4529
4530 /*
4531 * Show the file name for the match (if any)
4532 * Truncate the file name to avoid a wait for return.
4533 */
4534 if (compl_shown_match->cp_fname != NULL) {
4535 char *lead = _("match in file");
4536 int space = sc_col - vim_strsize((char_u *)lead) - 2;
4537 char_u *s;
4538 char_u *e;
4539
4540 if (space > 0) {
4541 // We need the tail that fits. With double-byte encoding going
4542 // back from the end is very slow, thus go from the start and keep
4543 // the text that fits in "space" between "s" and "e".
4544 for (s = e = compl_shown_match->cp_fname; *e != NUL; MB_PTR_ADV(e)) {
4545 space -= ptr2cells(e);
4546 while (space < 0) {
4547 space += ptr2cells(s);
4548 MB_PTR_ADV(s);
4549 }
4550 }
4551 vim_snprintf((char *)IObuff, IOSIZE, "%s %s%s", lead,
4552 s > compl_shown_match->cp_fname ? "<" : "", s);
4553 msg(IObuff);
4554 redraw_cmdline = false; // don't overwrite!
4555 }
4556 }
4557
4558 return num_matches;
4559}
4560
4561void pum_ext_select_item(int item, bool insert, bool finish)
4562{
4563 if (!pum_visible() || item < -1 || item >= compl_match_arraysize) {
4564 return;
4565 }
4566 pum_want.active = true;
4567 pum_want.item = item;
4568 pum_want.insert = insert;
4569 pum_want.finish = finish;
4570}
4571
4572// Call this while finding completions, to check whether the user has hit a key
4573// that should change the currently displayed completion, or exit completion
4574// mode. Also, when compl_pending is not zero, show a completion as soon as
4575// possible. -- webb
4576// "frequency" specifies out of how many calls we actually check.
4577// "in_compl_func" is TRUE when called from complete_check(), don't set
4578// compl_curr_match.
4579void ins_compl_check_keys(int frequency, int in_compl_func)
4580{
4581 static int count = 0;
4582
4583 // Don't check when reading keys from a script, :normal or feedkeys().
4584 // That would break the test scripts. But do check for keys when called
4585 // from complete_check().
4586 if (!in_compl_func && (using_script() || ex_normal_busy)) {
4587 return;
4588 }
4589
4590 /* Only do this at regular intervals */
4591 if (++count < frequency)
4592 return;
4593 count = 0;
4594
4595 /* Check for a typed key. Do use mappings, otherwise vim_is_ctrl_x_key()
4596 * can't do its work correctly. */
4597 int c = vpeekc_any();
4598 if (c != NUL) {
4599 if (vim_is_ctrl_x_key(c) && c != Ctrl_X && c != Ctrl_R) {
4600 c = safe_vgetc(); /* Eat the character */
4601 compl_shows_dir = ins_compl_key2dir(c);
4602 (void)ins_compl_next(false, ins_compl_key2count(c),
4603 c != K_UP && c != K_DOWN, in_compl_func);
4604 } else {
4605 /* Need to get the character to have KeyTyped set. We'll put it
4606 * back with vungetc() below. But skip K_IGNORE. */
4607 c = safe_vgetc();
4608 if (c != K_IGNORE) {
4609 /* Don't interrupt completion when the character wasn't typed,
4610 * e.g., when doing @q to replay keys. */
4611 if (c != Ctrl_R && KeyTyped)
4612 compl_interrupted = TRUE;
4613
4614 vungetc(c);
4615 }
4616 }
4617 }
4618 if (compl_pending != 0 && !got_int && !compl_no_insert) {
4619 int todo = compl_pending > 0 ? compl_pending : -compl_pending;
4620
4621 compl_pending = 0;
4622 (void)ins_compl_next(false, todo, true, in_compl_func);
4623 }
4624}
4625
4626/*
4627 * Decide the direction of Insert mode complete from the key typed.
4628 * Returns BACKWARD or FORWARD.
4629 */
4630static int ins_compl_key2dir(int c)
4631{
4632 if (c == K_EVENT || c == K_COMMAND) {
4633 return pum_want.item < pum_selected_item ? BACKWARD : FORWARD;
4634 }
4635 if (c == Ctrl_P || c == Ctrl_L
4636 || c == K_PAGEUP || c == K_KPAGEUP
4637 || c == K_S_UP || c == K_UP) {
4638 return BACKWARD;
4639 }
4640 return FORWARD;
4641}
4642
4643/// Check that "c" is a valid completion key only while the popup menu is shown
4644///
4645/// @param c character to check
4646static bool ins_compl_pum_key(int c)
4647 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
4648{
4649 return pum_visible() && (c == K_PAGEUP || c == K_KPAGEUP || c == K_S_UP
4650 || c == K_PAGEDOWN || c == K_KPAGEDOWN
4651 || c == K_S_DOWN || c == K_UP || c == K_DOWN);
4652}
4653
4654/*
4655 * Decide the number of completions to move forward.
4656 * Returns 1 for most keys, height of the popup menu for page-up/down keys.
4657 */
4658static int ins_compl_key2count(int c)
4659{
4660 int h;
4661
4662 if (c == K_EVENT || c == K_COMMAND) {
4663 int offset = pum_want.item - pum_selected_item;
4664 return abs(offset);
4665 }
4666
4667 if (ins_compl_pum_key(c) && c != K_UP && c != K_DOWN) {
4668 h = pum_get_height();
4669 if (h > 3)
4670 h -= 2; /* keep some context */
4671 return h;
4672 }
4673 return 1;
4674}
4675
4676/// Check that completion with "c" should insert the match, false if only
4677/// to change the currently selected completion.
4678///
4679/// @param c character to check
4680static bool ins_compl_use_match(int c)
4681 FUNC_ATTR_CONST FUNC_ATTR_WARN_UNUSED_RESULT
4682{
4683 switch (c) {
4684 case K_UP:
4685 case K_DOWN:
4686 case K_PAGEDOWN:
4687 case K_KPAGEDOWN:
4688 case K_S_DOWN:
4689 case K_PAGEUP:
4690 case K_KPAGEUP:
4691 case K_S_UP:
4692 return false;
4693 case K_EVENT:
4694 case K_COMMAND:
4695 return pum_want.active && pum_want.insert;
4696 }
4697 return true;
4698}
4699
4700/*
4701 * Do Insert mode completion.
4702 * Called when character "c" was typed, which has a meaning for completion.
4703 * Returns OK if completion was done, FAIL if something failed.
4704 */
4705static int ins_complete(int c, bool enable_pum)
4706{
4707 char_u *line;
4708 int startcol = 0; /* column where searched text starts */
4709 colnr_T curs_col; /* cursor column */
4710 int n;
4711 int save_w_wrow;
4712 int save_w_leftcol;
4713 int insert_match;
4714 const bool save_did_ai = did_ai;
4715 int flags = CP_ORIGINAL_TEXT;
4716
4717 compl_direction = ins_compl_key2dir(c);
4718 insert_match = ins_compl_use_match(c);
4719
4720 if (!compl_started) {
4721 /* First time we hit ^N or ^P (in a row, I mean) */
4722
4723 did_ai = false;
4724 did_si = false;
4725 can_si = false;
4726 can_si_back = false;
4727 if (stop_arrow() == FAIL) {
4728 return FAIL;
4729 }
4730
4731 line = ml_get(curwin->w_cursor.lnum);
4732 curs_col = curwin->w_cursor.col;
4733 compl_pending = 0;
4734
4735 /* If this same ctrl_x_mode has been interrupted use the text from
4736 * "compl_startpos" to the cursor as a pattern to add a new word
4737 * instead of expand the one before the cursor, in word-wise if
4738 * "compl_startpos" is not in the same line as the cursor then fix it
4739 * (the line has been split because it was longer than 'tw'). if SOL
4740 * is set then skip the previous pattern, a word at the beginning of
4741 * the line has been inserted, we'll look for that -- Acevedo. */
4742 if ((compl_cont_status & CONT_INTRPT) == CONT_INTRPT
4743 && compl_cont_mode == ctrl_x_mode) {
4744 /*
4745 * it is a continued search
4746 */
4747 compl_cont_status &= ~CONT_INTRPT; // remove INTRPT
4748 if (ctrl_x_mode == CTRL_X_NORMAL
4749 || ctrl_x_mode == CTRL_X_PATH_PATTERNS
4750 || ctrl_x_mode == CTRL_X_PATH_DEFINES) {
4751 if (compl_startpos.lnum != curwin->w_cursor.lnum) {
4752 /* line (probably) wrapped, set compl_startpos to the
4753 * first non_blank in the line, if it is not a wordchar
4754 * include it to get a better pattern, but then we don't
4755 * want the "\\<" prefix, check it bellow */
4756 compl_col = (colnr_T)getwhitecols(line);
4757 compl_startpos.col = compl_col;
4758 compl_startpos.lnum = curwin->w_cursor.lnum;
4759 compl_cont_status &= ~CONT_SOL; /* clear SOL if present */
4760 } else {
4761 /* S_IPOS was set when we inserted a word that was at the
4762 * beginning of the line, which means that we'll go to SOL
4763 * mode but first we need to redefine compl_startpos */
4764 if (compl_cont_status & CONT_S_IPOS) {
4765 compl_cont_status |= CONT_SOL;
4766 compl_startpos.col = (colnr_T)(skipwhite(
4767 line + compl_length
4768 + compl_startpos.col) - line);
4769 }
4770 compl_col = compl_startpos.col;
4771 }
4772 compl_length = curwin->w_cursor.col - (int)compl_col;
4773 /* IObuff is used to add a "word from the next line" would we
4774 * have enough space? just being paranoid */
4775#define MIN_SPACE 75
4776 if (compl_length > (IOSIZE - MIN_SPACE)) {
4777 compl_cont_status &= ~CONT_SOL;
4778 compl_length = (IOSIZE - MIN_SPACE);
4779 compl_col = curwin->w_cursor.col - compl_length;
4780 }
4781 compl_cont_status |= CONT_ADDING | CONT_N_ADDS;
4782 if (compl_length < 1)
4783 compl_cont_status &= CONT_LOCAL;
4784 } else if (CTRL_X_MODE_LINE_OR_EVAL(ctrl_x_mode)) {
4785 compl_cont_status = CONT_ADDING | CONT_N_ADDS;
4786 } else
4787 compl_cont_status = 0;
4788 } else
4789 compl_cont_status &= CONT_LOCAL;
4790
4791 if (!(compl_cont_status & CONT_ADDING)) { /* normal expansion */
4792 compl_cont_mode = ctrl_x_mode;
4793 if (ctrl_x_mode != CTRL_X_NORMAL) {
4794 // Remove LOCAL if ctrl_x_mode != CTRL_X_NORMAL
4795 compl_cont_status = 0;
4796 }
4797 compl_cont_status |= CONT_N_ADDS;
4798 compl_startpos = curwin->w_cursor;
4799 startcol = (int)curs_col;
4800 compl_col = 0;
4801 }
4802
4803 // Work out completion pattern and original text -- webb
4804 if (ctrl_x_mode == CTRL_X_NORMAL || (ctrl_x_mode & CTRL_X_WANT_IDENT)) {
4805 if ((compl_cont_status & CONT_SOL)
4806 || ctrl_x_mode == CTRL_X_PATH_DEFINES) {
4807 if (!(compl_cont_status & CONT_ADDING)) {
4808 while (--startcol >= 0 && vim_isIDc(line[startcol]))
4809 ;
4810 compl_col += ++startcol;
4811 compl_length = curs_col - startcol;
4812 }
4813 if (p_ic)
4814 compl_pattern = str_foldcase(line + compl_col, compl_length, NULL, 0);
4815 else
4816 compl_pattern = vim_strnsave(line + compl_col, compl_length);
4817 } else if (compl_cont_status & CONT_ADDING) {
4818 char_u *prefix = (char_u *)"\\<";
4819
4820 /* we need up to 2 extra chars for the prefix */
4821 compl_pattern = xmalloc(quote_meta(NULL, line + compl_col,
4822 compl_length) + 2);
4823 if (!vim_iswordp(line + compl_col)
4824 || (compl_col > 0
4825 && (
4826 vim_iswordp(mb_prevptr(line, line + compl_col))
4827 )))
4828 prefix = (char_u *)"";
4829 STRCPY((char *)compl_pattern, prefix);
4830 (void)quote_meta(compl_pattern + STRLEN(prefix),
4831 line + compl_col, compl_length);
4832 } else if (--startcol < 0
4833 || !vim_iswordp(mb_prevptr(line, line + startcol + 1))) {
4834 // Match any word of at least two chars
4835 compl_pattern = vim_strsave((char_u *)"\\<\\k\\k");
4836 compl_col += curs_col;
4837 compl_length = 0;
4838 } else {
4839 // Search the point of change class of multibyte character
4840 // or not a word single byte character backward.
4841 startcol -= utf_head_off(line, line + startcol);
4842 int base_class = mb_get_class(line + startcol);
4843 while (--startcol >= 0) {
4844 int head_off = utf_head_off(line, line + startcol);
4845 if (base_class != mb_get_class(line + startcol - head_off)) {
4846 break;
4847 }
4848 startcol -= head_off;
4849 }
4850 compl_col += ++startcol;
4851 compl_length = (int)curs_col - startcol;
4852 if (compl_length == 1) {
4853 /* Only match word with at least two chars -- webb
4854 * there's no need to call quote_meta,
4855 * xmalloc(7) is enough -- Acevedo
4856 */
4857 compl_pattern = xmalloc(7);
4858 STRCPY((char *)compl_pattern, "\\<");
4859 (void)quote_meta(compl_pattern + 2, line + compl_col, 1);
4860 STRCAT((char *)compl_pattern, "\\k");
4861 } else {
4862 compl_pattern = xmalloc(quote_meta(NULL, line + compl_col,
4863 compl_length) + 2);
4864 STRCPY((char *)compl_pattern, "\\<");
4865 (void)quote_meta(compl_pattern + 2, line + compl_col,
4866 compl_length);
4867 }
4868 }
4869 } else if (CTRL_X_MODE_LINE_OR_EVAL(ctrl_x_mode)) {
4870 compl_col = (colnr_T)getwhitecols(line);
4871 compl_length = (int)curs_col - (int)compl_col;
4872 if (compl_length < 0) /* cursor in indent: empty pattern */
4873 compl_length = 0;
4874 if (p_ic)
4875 compl_pattern = str_foldcase(line + compl_col, compl_length, NULL, 0);
4876 else
4877 compl_pattern = vim_strnsave(line + compl_col, compl_length);
4878 } else if (ctrl_x_mode == CTRL_X_FILES) {
4879 /* Go back to just before the first filename character. */
4880 if (startcol > 0) {
4881 char_u *p = line + startcol;
4882
4883 MB_PTR_BACK(line, p);
4884 while (p > line && vim_isfilec(PTR2CHAR(p))) {
4885 MB_PTR_BACK(line, p);
4886 }
4887 if (p == line && vim_isfilec(PTR2CHAR(p))) {
4888 startcol = 0;
4889 } else {
4890 startcol = (int)(p - line) + 1;
4891 }
4892 }
4893
4894 compl_col += startcol;
4895 compl_length = (int)curs_col - startcol;
4896 compl_pattern = addstar(line + compl_col, compl_length, EXPAND_FILES);
4897 } else if (ctrl_x_mode == CTRL_X_CMDLINE) {
4898 compl_pattern = vim_strnsave(line, curs_col);
4899 set_cmd_context(&compl_xp, compl_pattern,
4900 (int)STRLEN(compl_pattern), curs_col, false);
4901 if (compl_xp.xp_context == EXPAND_UNSUCCESSFUL
4902 || compl_xp.xp_context == EXPAND_NOTHING) {
4903 // No completion possible, use an empty pattern to get a
4904 // "pattern not found" message.
4905 compl_col = curs_col;
4906 } else {
4907 compl_col = (int)(compl_xp.xp_pattern - compl_pattern);
4908 }
4909 compl_length = curs_col - compl_col;
4910 } else if (ctrl_x_mode == CTRL_X_FUNCTION || ctrl_x_mode ==
4911 CTRL_X_OMNI) {
4912 /*
4913 * Call user defined function 'completefunc' with "a:findstart"
4914 * set to 1 to obtain the length of text to use for completion.
4915 */
4916 char_u *funcname;
4917 pos_T pos;
4918 win_T *curwin_save;
4919 buf_T *curbuf_save;
4920 const int save_State = State;
4921
4922 /* Call 'completefunc' or 'omnifunc' and get pattern length as a
4923 * string */
4924 funcname = ctrl_x_mode == CTRL_X_FUNCTION
4925 ? curbuf->b_p_cfu : curbuf->b_p_ofu;
4926 if (*funcname == NUL) {
4927 EMSG2(_(e_notset), ctrl_x_mode == CTRL_X_FUNCTION
4928 ? "completefunc" : "omnifunc");
4929 // restore did_ai, so that adding comment leader works
4930 did_ai = save_did_ai;
4931 return FAIL;
4932 }
4933
4934 typval_T args[3];
4935 args[0].v_type = VAR_NUMBER;
4936 args[1].v_type = VAR_STRING;
4937 args[2].v_type = VAR_UNKNOWN;
4938 args[0].vval.v_number = 1;
4939 args[1].vval.v_string = (char_u *)"";
4940
4941 pos = curwin->w_cursor;
4942 curwin_save = curwin;
4943 curbuf_save = curbuf;
4944 int col = call_func_retnr(funcname, 2, args);
4945
4946 State = save_State;
4947 if (curwin_save != curwin || curbuf_save != curbuf) {
4948 EMSG(_(e_complwin));
4949 return FAIL;
4950 }
4951 curwin->w_cursor = pos; /* restore the cursor position */
4952 validate_cursor();
4953 if (!equalpos(curwin->w_cursor, pos)) {
4954 EMSG(_(e_compldel));
4955 return FAIL;
4956 }
4957
4958 /* Return value -2 means the user complete function wants to
4959 * cancel the complete without an error.
4960 * Return value -3 does the same as -2 and leaves CTRL-X mode.*/
4961 if (col == -2)
4962 return FAIL;
4963 if (col == -3) {
4964 ctrl_x_mode = CTRL_X_NORMAL;
4965 edit_submode = NULL;
4966 if (!shortmess(SHM_COMPLETIONMENU)) {
4967 msg_clr_cmdline();
4968 }
4969 return FAIL;
4970 }
4971
4972 /*
4973 * Reset extended parameters of completion, when start new
4974 * completion.
4975 */
4976 compl_opt_refresh_always = FALSE;
4977
4978 if (col < 0)
4979 col = curs_col;
4980 compl_col = col;
4981 if (compl_col > curs_col)
4982 compl_col = curs_col;
4983
4984 /* Setup variables for completion. Need to obtain "line" again,
4985 * it may have become invalid. */
4986 line = ml_get(curwin->w_cursor.lnum);
4987 compl_length = curs_col - compl_col;
4988 compl_pattern = vim_strnsave(line + compl_col, compl_length);
4989 } else if (ctrl_x_mode == CTRL_X_SPELL) {
4990 if (spell_bad_len > 0) {
4991 assert(spell_bad_len <= INT_MAX);
4992 compl_col = curs_col - (int)spell_bad_len;
4993 }
4994 else
4995 compl_col = spell_word_start(startcol);
4996 if (compl_col >= (colnr_T)startcol) {
4997 compl_length = 0;
4998 compl_col = curs_col;
4999 } else {
5000 spell_expand_check_cap(compl_col);
5001 compl_length = (int)curs_col - compl_col;
5002 }
5003 /* Need to obtain "line" again, it may have become invalid. */
5004 line = ml_get(curwin->w_cursor.lnum);
5005 compl_pattern = vim_strnsave(line + compl_col, compl_length);
5006 } else {
5007 internal_error("ins_complete()");
5008 return FAIL;
5009 }
5010
5011 if (compl_cont_status & CONT_ADDING) {
5012 edit_submode_pre = (char_u *)_(" Adding");
5013 if (CTRL_X_MODE_LINE_OR_EVAL(ctrl_x_mode)) {
5014 /* Insert a new line, keep indentation but ignore 'comments' */
5015 char_u *old = curbuf->b_p_com;
5016
5017 curbuf->b_p_com = (char_u *)"";
5018 compl_startpos.lnum = curwin->w_cursor.lnum;
5019 compl_startpos.col = compl_col;
5020 ins_eol('\r');
5021 curbuf->b_p_com = old;
5022 compl_length = 0;
5023 compl_col = curwin->w_cursor.col;
5024 }
5025 } else {
5026 edit_submode_pre = NULL;
5027 compl_startpos.col = compl_col;
5028 }
5029
5030 if (compl_cont_status & CONT_LOCAL)
5031 edit_submode = (char_u *)_(ctrl_x_msgs[CTRL_X_LOCAL_MSG]);
5032 else
5033 edit_submode = (char_u *)_(CTRL_X_MSG(ctrl_x_mode));
5034
5035 /* If any of the original typed text has been changed we need to fix
5036 * the redo buffer. */
5037 ins_compl_fixRedoBufForLeader(NULL);
5038
5039 /* Always add completion for the original text. */
5040 xfree(compl_orig_text);
5041 compl_orig_text = vim_strnsave(line + compl_col, compl_length);
5042 if (p_ic) {
5043 flags |= CP_ICASE;
5044 }
5045 if (ins_compl_add(compl_orig_text, -1, NULL, NULL, false, 0,
5046 flags, false) != OK) {
5047 XFREE_CLEAR(compl_pattern);
5048 XFREE_CLEAR(compl_orig_text);
5049 return FAIL;
5050 }
5051
5052 /* showmode might reset the internal line pointers, so it must
5053 * be called before line = ml_get(), or when this address is no
5054 * longer needed. -- Acevedo.
5055 */
5056 edit_submode_extra = (char_u *)_("-- Searching...");
5057 edit_submode_highl = HLF_COUNT;
5058 showmode();
5059 edit_submode_extra = NULL;
5060 ui_flush();
5061 } else if (insert_match && stop_arrow() == FAIL) {
5062 return FAIL;
5063 }
5064
5065 compl_shown_match = compl_curr_match;
5066 compl_shows_dir = compl_direction;
5067
5068 /*
5069 * Find next match (and following matches).
5070 */
5071 save_w_wrow = curwin->w_wrow;
5072 save_w_leftcol = curwin->w_leftcol;
5073 n = ins_compl_next(true, ins_compl_key2count(c), insert_match, false);
5074
5075
5076 if (n > 1) /* all matches have been found */
5077 compl_matches = n;
5078 compl_curr_match = compl_shown_match;
5079 compl_direction = compl_shows_dir;
5080
5081 /* Eat the ESC that vgetc() returns after a CTRL-C to avoid leaving Insert
5082 * mode. */
5083 if (got_int && !global_busy) {
5084 (void)vgetc();
5085 got_int = FALSE;
5086 }
5087
5088 /* we found no match if the list has only the "compl_orig_text"-entry */
5089 if (compl_first_match == compl_first_match->cp_next) {
5090 edit_submode_extra = (compl_cont_status & CONT_ADDING)
5091 && compl_length > 1
5092 ? (char_u *)_(e_hitend) : (char_u *)_(e_patnotf);
5093 edit_submode_highl = HLF_E;
5094 /* remove N_ADDS flag, so next ^X<> won't try to go to ADDING mode,
5095 * because we couldn't expand anything at first place, but if we used
5096 * ^P, ^N, ^X^I or ^X^D we might want to add-expand a single-char-word
5097 * (such as M in M'exico) if not tried already. -- Acevedo */
5098 if (compl_length > 1
5099 || (compl_cont_status & CONT_ADDING)
5100 || (ctrl_x_mode != CTRL_X_NORMAL
5101 && ctrl_x_mode != CTRL_X_PATH_PATTERNS
5102 && ctrl_x_mode != CTRL_X_PATH_DEFINES)) {
5103 compl_cont_status &= ~CONT_N_ADDS;
5104 }
5105 }
5106
5107 if (compl_curr_match->cp_flags & CP_CONT_S_IPOS) {
5108 compl_cont_status |= CONT_S_IPOS;
5109 } else {
5110 compl_cont_status &= ~CONT_S_IPOS;
5111 }
5112
5113 if (edit_submode_extra == NULL) {
5114 if (compl_curr_match->cp_flags & CP_ORIGINAL_TEXT) {
5115 edit_submode_extra = (char_u *)_("Back at original");
5116 edit_submode_highl = HLF_W;
5117 } else if (compl_cont_status & CONT_S_IPOS) {
5118 edit_submode_extra = (char_u *)_("Word from other line");
5119 edit_submode_highl = HLF_COUNT;
5120 } else if (compl_curr_match->cp_next == compl_curr_match->cp_prev) {
5121 edit_submode_extra = (char_u *)_("The only match");
5122 edit_submode_highl = HLF_COUNT;
5123 } else {
5124 /* Update completion sequence number when needed. */
5125 if (compl_curr_match->cp_number == -1) {
5126 int number = 0;
5127 compl_T *match;
5128
5129 if (compl_direction == FORWARD) {
5130 /* search backwards for the first valid (!= -1) number.
5131 * This should normally succeed already at the first loop
5132 * cycle, so it's fast! */
5133 for (match = compl_curr_match->cp_prev; match != NULL
5134 && match != compl_first_match;
5135 match = match->cp_prev)
5136 if (match->cp_number != -1) {
5137 number = match->cp_number;
5138 break;
5139 }
5140 if (match != NULL)
5141 /* go up and assign all numbers which are not assigned
5142 * yet */
5143 for (match = match->cp_next;
5144 match != NULL && match->cp_number == -1;
5145 match = match->cp_next)
5146 match->cp_number = ++number;
5147 } else { /* BACKWARD */
5148 /* search forwards (upwards) for the first valid (!= -1)
5149 * number. This should normally succeed already at the
5150 * first loop cycle, so it's fast! */
5151 for (match = compl_curr_match->cp_next; match != NULL
5152 && match != compl_first_match;
5153 match = match->cp_next)
5154 if (match->cp_number != -1) {
5155 number = match->cp_number;
5156 break;
5157 }
5158 if (match != NULL)
5159 /* go down and assign all numbers which are not
5160 * assigned yet */
5161 for (match = match->cp_prev; match
5162 && match->cp_number == -1;
5163 match = match->cp_prev)
5164 match->cp_number = ++number;
5165 }
5166 }
5167
5168 /* The match should always have a sequence number now, this is
5169 * just a safety check. */
5170 if (compl_curr_match->cp_number != -1) {
5171 /* Space for 10 text chars. + 2x10-digit no.s = 31.
5172 * Translations may need more than twice that. */
5173 static char_u match_ref[81];
5174
5175 if (compl_matches > 0)
5176 vim_snprintf((char *)match_ref, sizeof(match_ref),
5177 _("match %d of %d"),
5178 compl_curr_match->cp_number, compl_matches);
5179 else
5180 vim_snprintf((char *)match_ref, sizeof(match_ref),
5181 _("match %d"),
5182 compl_curr_match->cp_number);
5183 edit_submode_extra = match_ref;
5184 edit_submode_highl = HLF_R;
5185 if (dollar_vcol >= 0)
5186 curs_columns(FALSE);
5187 }
5188 }
5189 }
5190
5191 /* Show a message about what (completion) mode we're in. */
5192 showmode();
5193 if (!shortmess(SHM_COMPLETIONMENU)) {
5194 if (edit_submode_extra != NULL) {
5195 if (!p_smd) {
5196 msg_attr((const char *)edit_submode_extra,
5197 (edit_submode_highl < HLF_COUNT
5198 ? HL_ATTR(edit_submode_highl) : 0));
5199 }
5200 } else {
5201 msg_clr_cmdline(); // necessary for "noshowmode"
5202 }
5203 }
5204
5205 // Show the popup menu, unless we got interrupted.
5206 if (enable_pum && !compl_interrupted) {
5207 show_pum(save_w_wrow, save_w_leftcol);
5208 }
5209 compl_was_interrupted = compl_interrupted;
5210 compl_interrupted = FALSE;
5211
5212 return OK;
5213}
5214
5215/*
5216 * Looks in the first "len" chars. of "src" for search-metachars.
5217 * If dest is not NULL the chars. are copied there quoting (with
5218 * a backslash) the metachars, and dest would be NUL terminated.
5219 * Returns the length (needed) of dest
5220 */
5221static unsigned quote_meta(char_u *dest, char_u *src, int len)
5222{
5223 unsigned m = (unsigned)len + 1; /* one extra for the NUL */
5224
5225 for (; --len >= 0; src++) {
5226 switch (*src) {
5227 case '.':
5228 case '*':
5229 case '[':
5230 if (ctrl_x_mode == CTRL_X_DICTIONARY
5231 || ctrl_x_mode == CTRL_X_THESAURUS)
5232 break;
5233 FALLTHROUGH;
5234 case '~':
5235 if (!p_magic) /* quote these only if magic is set */
5236 break;
5237 FALLTHROUGH;
5238 case '\\':
5239 if (ctrl_x_mode == CTRL_X_DICTIONARY
5240 || ctrl_x_mode == CTRL_X_THESAURUS)
5241 break;
5242 FALLTHROUGH;
5243 case '^': // currently it's not needed.
5244 case '$':
5245 m++;
5246 if (dest != NULL)
5247 *dest++ = '\\';
5248 break;
5249 }
5250 if (dest != NULL)
5251 *dest++ = *src;
5252 /* Copy remaining bytes of a multibyte character. */
5253 if (has_mbyte) {
5254 int i, mb_len;
5255
5256 mb_len = (*mb_ptr2len)(src) - 1;
5257 if (mb_len > 0 && len >= mb_len)
5258 for (i = 0; i < mb_len; ++i) {
5259 --len;
5260 ++src;
5261 if (dest != NULL)
5262 *dest++ = *src;
5263 }
5264 }
5265 }
5266 if (dest != NULL)
5267 *dest = NUL;
5268
5269 return m;
5270}
5271
5272/*
5273 * Next character is interpreted literally.
5274 * A one, two or three digit decimal number is interpreted as its byte value.
5275 * If one or two digits are entered, the next character is given to vungetc().
5276 * For Unicode a character > 255 may be returned.
5277 */
5278int get_literal(void)
5279{
5280 int cc;
5281 int nc;
5282 int i;
5283 int hex = FALSE;
5284 int octal = FALSE;
5285 int unicode = 0;
5286
5287 if (got_int)
5288 return Ctrl_C;
5289
5290 ++no_mapping; /* don't map the next key hits */
5291 cc = 0;
5292 i = 0;
5293 for (;; ) {
5294 nc = plain_vgetc();
5295 if (!(State & CMDLINE)
5296 && MB_BYTE2LEN_CHECK(nc) == 1
5297 )
5298 add_to_showcmd(nc);
5299 if (nc == 'x' || nc == 'X')
5300 hex = TRUE;
5301 else if (nc == 'o' || nc == 'O')
5302 octal = TRUE;
5303 else if (nc == 'u' || nc == 'U')
5304 unicode = nc;
5305 else {
5306 if (hex
5307 || unicode != 0
5308 ) {
5309 if (!ascii_isxdigit(nc))
5310 break;
5311 cc = cc * 16 + hex2nr(nc);
5312 } else if (octal) {
5313 if (nc < '0' || nc > '7')
5314 break;
5315 cc = cc * 8 + nc - '0';
5316 } else {
5317 if (!ascii_isdigit(nc))
5318 break;
5319 cc = cc * 10 + nc - '0';
5320 }
5321
5322 ++i;
5323 }
5324
5325 if (cc > 255
5326 && unicode == 0
5327 )
5328 cc = 255; /* limit range to 0-255 */
5329 nc = 0;
5330
5331 if (hex) { /* hex: up to two chars */
5332 if (i >= 2)
5333 break;
5334 } else if (unicode) { /* Unicode: up to four or eight chars */
5335 if ((unicode == 'u' && i >= 4) || (unicode == 'U' && i >= 8))
5336 break;
5337 } else if (i >= 3) /* decimal or octal: up to three chars */
5338 break;
5339 }
5340 if (i == 0) { /* no number entered */
5341 if (nc == K_ZERO) { /* NUL is stored as NL */
5342 cc = '\n';
5343 nc = 0;
5344 } else {
5345 cc = nc;
5346 nc = 0;
5347 }
5348 }
5349
5350 if (cc == 0) { // NUL is stored as NL
5351 cc = '\n';
5352 }
5353
5354 --no_mapping;
5355 if (nc)
5356 vungetc(nc);
5357 got_int = FALSE; /* CTRL-C typed after CTRL-V is not an interrupt */
5358 return cc;
5359}
5360
5361/// Insert character, taking care of special keys and mod_mask
5362///
5363/// @param ctrlv `c` was typed after CTRL-V
5364static void insert_special(int c, int allow_modmask, int ctrlv)
5365{
5366 char_u *p;
5367 int len;
5368
5369 // Special function key, translate into "<Key>". Up to the last '>' is
5370 // inserted with ins_str(), so as not to replace characters in replace
5371 // mode.
5372 // Only use mod_mask for special keys, to avoid things like <S-Space>,
5373 // unless 'allow_modmask' is TRUE.
5374 if (mod_mask & MOD_MASK_CMD) { // Command-key never produces a normal key.
5375 allow_modmask = true;
5376 }
5377 if (IS_SPECIAL(c) || (mod_mask && allow_modmask)) {
5378 p = get_special_key_name(c, mod_mask);
5379 len = (int)STRLEN(p);
5380 c = p[len - 1];
5381 if (len > 2) {
5382 if (stop_arrow() == FAIL)
5383 return;
5384 p[len - 1] = NUL;
5385 ins_str(p);
5386 AppendToRedobuffLit(p, -1);
5387 ctrlv = FALSE;
5388 }
5389 }
5390 if (stop_arrow() == OK)
5391 insertchar(c, ctrlv ? INSCHAR_CTRLV : 0, -1);
5392}
5393
5394/*
5395 * Special characters in this context are those that need processing other
5396 * than the simple insertion that can be performed here. This includes ESC
5397 * which terminates the insert, and CR/NL which need special processing to
5398 * open up a new line. This routine tries to optimize insertions performed by
5399 * the "redo", "undo" or "put" commands, so it needs to know when it should
5400 * stop and defer processing to the "normal" mechanism.
5401 * '0' and '^' are special, because they can be followed by CTRL-D.
5402 */
5403# define ISSPECIAL(c) ((c) < ' ' || (c) >= DEL || (c) == '0' || (c) == '^')
5404
5405# define WHITECHAR(cc) (ascii_iswhite(cc) && \
5406 (!enc_utf8 || \
5407 !utf_iscomposing( \
5408 utf_ptr2char(get_cursor_pos_ptr() + 1))))
5409
5410/*
5411 * "flags": INSCHAR_FORMAT - force formatting
5412 * INSCHAR_CTRLV - char typed just after CTRL-V
5413 * INSCHAR_NO_FEX - don't use 'formatexpr'
5414 *
5415 * NOTE: passes the flags value straight through to internal_format() which,
5416 * beside INSCHAR_FORMAT (above), is also looking for these:
5417 * INSCHAR_DO_COM - format comments
5418 * INSCHAR_COM_LIST - format comments with num list or 2nd line indent
5419 */
5420void
5421insertchar (
5422 int c, /* character to insert or NUL */
5423 int flags, /* INSCHAR_FORMAT, etc. */
5424 int second_indent /* indent for second line if >= 0 */
5425)
5426{
5427 int textwidth;
5428 char_u *p;
5429 int fo_ins_blank;
5430 int force_format = flags & INSCHAR_FORMAT;
5431
5432 textwidth = comp_textwidth(force_format);
5433 fo_ins_blank = has_format_option(FO_INS_BLANK);
5434
5435 /*
5436 * Try to break the line in two or more pieces when:
5437 * - Always do this if we have been called to do formatting only.
5438 * - Always do this when 'formatoptions' has the 'a' flag and the line
5439 * ends in white space.
5440 * - Otherwise:
5441 * - Don't do this if inserting a blank
5442 * - Don't do this if an existing character is being replaced, unless
5443 * we're in VREPLACE mode.
5444 * - Do this if the cursor is not on the line where insert started
5445 * or - 'formatoptions' doesn't have 'l' or the line was not too long
5446 * before the insert.
5447 * - 'formatoptions' doesn't have 'b' or a blank was inserted at or
5448 * before 'textwidth'
5449 */
5450 if (textwidth > 0
5451 && (force_format
5452 || (!ascii_iswhite(c)
5453 && !((State & REPLACE_FLAG)
5454 && !(State & VREPLACE_FLAG)
5455 && *get_cursor_pos_ptr() != NUL)
5456 && (curwin->w_cursor.lnum != Insstart.lnum
5457 || ((!has_format_option(FO_INS_LONG)
5458 || Insstart_textlen <= (colnr_T)textwidth)
5459 && (!fo_ins_blank
5460 || Insstart_blank_vcol <= (colnr_T)textwidth
5461 )))))) {
5462 /* Format with 'formatexpr' when it's set. Use internal formatting
5463 * when 'formatexpr' isn't set or it returns non-zero. */
5464 int do_internal = TRUE;
5465 colnr_T virtcol = get_nolist_virtcol()
5466 + char2cells(c != NUL ? c : gchar_cursor());
5467
5468 if (*curbuf->b_p_fex != NUL && (flags & INSCHAR_NO_FEX) == 0
5469 && (force_format || virtcol > (colnr_T)textwidth)) {
5470 do_internal = (fex_format(curwin->w_cursor.lnum, 1L, c) != 0);
5471 /* It may be required to save for undo again, e.g. when setline()
5472 * was called. */
5473 ins_need_undo = TRUE;
5474 }
5475 if (do_internal)
5476 internal_format(textwidth, second_indent, flags, c == NUL, c);
5477 }
5478
5479 if (c == NUL) /* only formatting was wanted */
5480 return;
5481
5482 /* Check whether this character should end a comment. */
5483 if (did_ai && c == end_comment_pending) {
5484 char_u *line;
5485 char_u lead_end[COM_MAX_LEN]; /* end-comment string */
5486 int middle_len, end_len;
5487 int i;
5488
5489 /*
5490 * Need to remove existing (middle) comment leader and insert end
5491 * comment leader. First, check what comment leader we can find.
5492 */
5493 i = get_leader_len(line = get_cursor_line_ptr(), &p, FALSE, TRUE);
5494 if (i > 0 && vim_strchr(p, COM_MIDDLE) != NULL) { /* Just checking */
5495 /* Skip middle-comment string */
5496 while (*p && p[-1] != ':') /* find end of middle flags */
5497 ++p;
5498 middle_len = copy_option_part(&p, lead_end, COM_MAX_LEN, ",");
5499 /* Don't count trailing white space for middle_len */
5500 while (middle_len > 0 && ascii_iswhite(lead_end[middle_len - 1]))
5501 --middle_len;
5502
5503 /* Find the end-comment string */
5504 while (*p && p[-1] != ':') /* find end of end flags */
5505 ++p;
5506 end_len = copy_option_part(&p, lead_end, COM_MAX_LEN, ",");
5507
5508 /* Skip white space before the cursor */
5509 i = curwin->w_cursor.col;
5510 while (--i >= 0 && ascii_iswhite(line[i]))
5511 ;
5512 i++;
5513
5514 /* Skip to before the middle leader */
5515 i -= middle_len;
5516
5517 /* Check some expected things before we go on */
5518 if (i >= 0 && lead_end[end_len - 1] == end_comment_pending) {
5519 /* Backspace over all the stuff we want to replace */
5520 backspace_until_column(i);
5521
5522 /*
5523 * Insert the end-comment string, except for the last
5524 * character, which will get inserted as normal later.
5525 */
5526 ins_bytes_len(lead_end, end_len - 1);
5527 }
5528 }
5529 }
5530 end_comment_pending = NUL;
5531
5532 did_ai = false;
5533 did_si = false;
5534 can_si = false;
5535 can_si_back = false;
5536
5537 // If there's any pending input, grab up to INPUT_BUFLEN at once.
5538 // This speeds up normal text input considerably.
5539 // Don't do this when 'cindent' or 'indentexpr' is set, because we might
5540 // need to re-indent at a ':', or any other character (but not what
5541 // 'paste' is set)..
5542 // Don't do this when there an InsertCharPre autocommand is defined,
5543 // because we need to fire the event for every character.
5544 // Do the check for InsertCharPre before the call to vpeekc() because the
5545 // InsertCharPre autocommand could change the input buffer.
5546 if (!ISSPECIAL(c)
5547 && (!has_mbyte || (*mb_char2len)(c) == 1)
5548 && !has_event(EVENT_INSERTCHARPRE)
5549 && vpeekc() != NUL
5550 && !(State & REPLACE_FLAG)
5551 && !cindent_on()
5552 && !p_ri) {
5553#define INPUT_BUFLEN 100
5554 char_u buf[INPUT_BUFLEN + 1];
5555 int i;
5556 colnr_T virtcol = 0;
5557
5558 buf[0] = c;
5559 i = 1;
5560 if (textwidth > 0) {
5561 virtcol = get_nolist_virtcol();
5562 }
5563 // Stop the string when:
5564 // - no more chars available
5565 // - finding a special character (command key)
5566 // - buffer is full
5567 // - running into the 'textwidth' boundary
5568 // - need to check for abbreviation: A non-word char after a word-char
5569 while ((c = vpeekc()) != NUL
5570 && !ISSPECIAL(c)
5571 && MB_BYTE2LEN(c) == 1
5572 && i < INPUT_BUFLEN
5573 && (textwidth == 0
5574 || (virtcol += byte2cells(buf[i - 1])) < (colnr_T)textwidth)
5575 && !(!no_abbr && !vim_iswordc(c) && vim_iswordc(buf[i - 1]))) {
5576 c = vgetc();
5577 if (p_hkmap && KeyTyped) {
5578 c = hkmap(c); // Hebrew mode mapping
5579 }
5580 buf[i++] = c;
5581 }
5582
5583 do_digraph(-1); /* clear digraphs */
5584 do_digraph(buf[i-1]); /* may be the start of a digraph */
5585 buf[i] = NUL;
5586 ins_str(buf);
5587 if (flags & INSCHAR_CTRLV) {
5588 redo_literal(*buf);
5589 i = 1;
5590 } else
5591 i = 0;
5592 if (buf[i] != NUL)
5593 AppendToRedobuffLit(buf + i, -1);
5594 } else {
5595 int cc;
5596
5597 if ((cc = utf_char2len(c)) > 1) {
5598 char_u buf[MB_MAXBYTES + 1];
5599
5600 utf_char2bytes(c, buf);
5601 buf[cc] = NUL;
5602 ins_char_bytes(buf, cc);
5603 AppendCharToRedobuff(c);
5604 } else {
5605 ins_char(c);
5606 if (flags & INSCHAR_CTRLV)
5607 redo_literal(c);
5608 else
5609 AppendCharToRedobuff(c);
5610 }
5611 }
5612}
5613
5614/*
5615 * Format text at the current insert position.
5616 *
5617 * If the INSCHAR_COM_LIST flag is present, then the value of second_indent
5618 * will be the comment leader length sent to open_line().
5619 */
5620static void
5621internal_format (
5622 int textwidth,
5623 int second_indent,
5624 int flags,
5625 int format_only,
5626 int c /* character to be inserted (can be NUL) */
5627)
5628{
5629 int cc;
5630 int save_char = NUL;
5631 bool haveto_redraw = false;
5632 int fo_ins_blank = has_format_option(FO_INS_BLANK);
5633 int fo_multibyte = has_format_option(FO_MBYTE_BREAK);
5634 int fo_white_par = has_format_option(FO_WHITE_PAR);
5635 int first_line = TRUE;
5636 colnr_T leader_len;
5637 int no_leader = FALSE;
5638 int do_comments = (flags & INSCHAR_DO_COM);
5639 int has_lbr = curwin->w_p_lbr;
5640
5641 // make sure win_lbr_chartabsize() counts correctly
5642 curwin->w_p_lbr = false;
5643
5644 /*
5645 * When 'ai' is off we don't want a space under the cursor to be
5646 * deleted. Replace it with an 'x' temporarily.
5647 */
5648 if (!curbuf->b_p_ai
5649 && !(State & VREPLACE_FLAG)
5650 ) {
5651 cc = gchar_cursor();
5652 if (ascii_iswhite(cc)) {
5653 save_char = cc;
5654 pchar_cursor('x');
5655 }
5656 }
5657
5658 /*
5659 * Repeat breaking lines, until the current line is not too long.
5660 */
5661 while (!got_int) {
5662 int startcol; /* Cursor column at entry */
5663 int wantcol; /* column at textwidth border */
5664 int foundcol; /* column for start of spaces */
5665 int end_foundcol = 0; /* column for start of word */
5666 colnr_T len;
5667 colnr_T virtcol;
5668 int orig_col = 0;
5669 char_u *saved_text = NULL;
5670 colnr_T col;
5671 colnr_T end_col;
5672
5673 virtcol = get_nolist_virtcol()
5674 + char2cells(c != NUL ? c : gchar_cursor());
5675 if (virtcol <= (colnr_T)textwidth)
5676 break;
5677
5678 if (no_leader)
5679 do_comments = FALSE;
5680 else if (!(flags & INSCHAR_FORMAT)
5681 && has_format_option(FO_WRAP_COMS))
5682 do_comments = TRUE;
5683
5684 /* Don't break until after the comment leader */
5685 if (do_comments)
5686 leader_len = get_leader_len(get_cursor_line_ptr(), NULL, FALSE, TRUE);
5687 else
5688 leader_len = 0;
5689
5690 /* If the line doesn't start with a comment leader, then don't
5691 * start one in a following broken line. Avoids that a %word
5692 * moved to the start of the next line causes all following lines
5693 * to start with %. */
5694 if (leader_len == 0)
5695 no_leader = TRUE;
5696 if (!(flags & INSCHAR_FORMAT)
5697 && leader_len == 0
5698 && !has_format_option(FO_WRAP))
5699
5700 break;
5701 if ((startcol = curwin->w_cursor.col) == 0)
5702 break;
5703
5704 /* find column of textwidth border */
5705 coladvance((colnr_T)textwidth);
5706 wantcol = curwin->w_cursor.col;
5707
5708 curwin->w_cursor.col = startcol;
5709 foundcol = 0;
5710
5711 /*
5712 * Find position to break at.
5713 * Stop at first entered white when 'formatoptions' has 'v'
5714 */
5715 while ((!fo_ins_blank && !has_format_option(FO_INS_VI))
5716 || (flags & INSCHAR_FORMAT)
5717 || curwin->w_cursor.lnum != Insstart.lnum
5718 || curwin->w_cursor.col >= Insstart.col) {
5719 if (curwin->w_cursor.col == startcol && c != NUL)
5720 cc = c;
5721 else
5722 cc = gchar_cursor();
5723 if (WHITECHAR(cc)) {
5724 /* remember position of blank just before text */
5725 end_col = curwin->w_cursor.col;
5726
5727 // find start of sequence of blanks
5728 int wcc = 0; // counter for whitespace chars
5729 while (curwin->w_cursor.col > 0 && WHITECHAR(cc)) {
5730 dec_cursor();
5731 cc = gchar_cursor();
5732
5733 // Increment count of how many whitespace chars in this
5734 // group; we only need to know if it's more than one.
5735 if (wcc < 2) {
5736 wcc++;
5737 }
5738 }
5739 if (curwin->w_cursor.col == 0 && WHITECHAR(cc)) {
5740 break; // only spaces in front of text
5741 }
5742
5743 // Don't break after a period when 'formatoptions' has 'p' and
5744 // there are less than two spaces.
5745 if (has_format_option(FO_PERIOD_ABBR) && cc == '.' && wcc < 2) {
5746 continue;
5747 }
5748
5749 // Don't break until after the comment leader
5750 if (curwin->w_cursor.col < leader_len) {
5751 break;
5752 }
5753
5754 if (has_format_option(FO_ONE_LETTER)) {
5755 /* do not break after one-letter words */
5756 if (curwin->w_cursor.col == 0)
5757 break; /* one-letter word at begin */
5758 /* do not break "#a b" when 'tw' is 2 */
5759 if (curwin->w_cursor.col <= leader_len)
5760 break;
5761 col = curwin->w_cursor.col;
5762 dec_cursor();
5763 cc = gchar_cursor();
5764
5765 if (WHITECHAR(cc))
5766 continue; /* one-letter, continue */
5767 curwin->w_cursor.col = col;
5768 }
5769
5770 inc_cursor();
5771
5772 end_foundcol = end_col + 1;
5773 foundcol = curwin->w_cursor.col;
5774 if (curwin->w_cursor.col <= (colnr_T)wantcol)
5775 break;
5776 } else if (cc >= 0x100 && fo_multibyte) {
5777 /* Break after or before a multi-byte character. */
5778 if (curwin->w_cursor.col != startcol) {
5779 /* Don't break until after the comment leader */
5780 if (curwin->w_cursor.col < leader_len)
5781 break;
5782 col = curwin->w_cursor.col;
5783 inc_cursor();
5784 /* Don't change end_foundcol if already set. */
5785 if (foundcol != curwin->w_cursor.col) {
5786 foundcol = curwin->w_cursor.col;
5787 end_foundcol = foundcol;
5788 if (curwin->w_cursor.col <= (colnr_T)wantcol)
5789 break;
5790 }
5791 curwin->w_cursor.col = col;
5792 }
5793
5794 if (curwin->w_cursor.col == 0)
5795 break;
5796
5797 col = curwin->w_cursor.col;
5798
5799 dec_cursor();
5800 cc = gchar_cursor();
5801
5802 if (WHITECHAR(cc))
5803 continue; /* break with space */
5804 /* Don't break until after the comment leader */
5805 if (curwin->w_cursor.col < leader_len)
5806 break;
5807
5808 curwin->w_cursor.col = col;
5809
5810 foundcol = curwin->w_cursor.col;
5811 end_foundcol = foundcol;
5812 if (curwin->w_cursor.col <= (colnr_T)wantcol)
5813 break;
5814 }
5815 if (curwin->w_cursor.col == 0)
5816 break;
5817 dec_cursor();
5818 }
5819
5820 if (foundcol == 0) { /* no spaces, cannot break line */
5821 curwin->w_cursor.col = startcol;
5822 break;
5823 }
5824
5825 /* Going to break the line, remove any "$" now. */
5826 undisplay_dollar();
5827
5828 /*
5829 * Offset between cursor position and line break is used by replace
5830 * stack functions. VREPLACE does not use this, and backspaces
5831 * over the text instead.
5832 */
5833 if (State & VREPLACE_FLAG)
5834 orig_col = startcol; /* Will start backspacing from here */
5835 else
5836 replace_offset = startcol - end_foundcol;
5837
5838 /*
5839 * adjust startcol for spaces that will be deleted and
5840 * characters that will remain on top line
5841 */
5842 curwin->w_cursor.col = foundcol;
5843 while ((cc = gchar_cursor(), WHITECHAR(cc))
5844 && (!fo_white_par || curwin->w_cursor.col < startcol))
5845 inc_cursor();
5846 startcol -= curwin->w_cursor.col;
5847 if (startcol < 0)
5848 startcol = 0;
5849
5850 if (State & VREPLACE_FLAG) {
5851 /*
5852 * In VREPLACE mode, we will backspace over the text to be
5853 * wrapped, so save a copy now to put on the next line.
5854 */
5855 saved_text = vim_strsave(get_cursor_pos_ptr());
5856 curwin->w_cursor.col = orig_col;
5857 saved_text[startcol] = NUL;
5858
5859 /* Backspace over characters that will move to the next line */
5860 if (!fo_white_par)
5861 backspace_until_column(foundcol);
5862 } else {
5863 /* put cursor after pos. to break line */
5864 if (!fo_white_par)
5865 curwin->w_cursor.col = foundcol;
5866 }
5867
5868 /*
5869 * Split the line just before the margin.
5870 * Only insert/delete lines, but don't really redraw the window.
5871 */
5872 open_line(FORWARD, OPENLINE_DELSPACES + OPENLINE_MARKFIX
5873 + (fo_white_par ? OPENLINE_KEEPTRAIL : 0)
5874 + (do_comments ? OPENLINE_DO_COM : 0)
5875 + ((flags & INSCHAR_COM_LIST) ? OPENLINE_COM_LIST : 0)
5876 , ((flags & INSCHAR_COM_LIST) ? second_indent : old_indent));
5877 if (!(flags & INSCHAR_COM_LIST))
5878 old_indent = 0;
5879
5880 replace_offset = 0;
5881 if (first_line) {
5882 if (!(flags & INSCHAR_COM_LIST)) {
5883 /*
5884 * This section is for auto-wrap of numeric lists. When not
5885 * in insert mode (i.e. format_lines()), the INSCHAR_COM_LIST
5886 * flag will be set and open_line() will handle it (as seen
5887 * above). The code here (and in get_number_indent()) will
5888 * recognize comments if needed...
5889 */
5890 if (second_indent < 0 && has_format_option(FO_Q_NUMBER))
5891 second_indent =
5892 get_number_indent(curwin->w_cursor.lnum - 1);
5893 if (second_indent >= 0) {
5894 if (State & VREPLACE_FLAG)
5895 change_indent(INDENT_SET, second_indent,
5896 FALSE, NUL, TRUE);
5897 else if (leader_len > 0 && second_indent - leader_len > 0) {
5898 int i;
5899 int padding = second_indent - leader_len;
5900
5901 /* We started at the first_line of a numbered list
5902 * that has a comment. the open_line() function has
5903 * inserted the proper comment leader and positioned
5904 * the cursor at the end of the split line. Now we
5905 * add the additional whitespace needed after the
5906 * comment leader for the numbered list. */
5907 for (i = 0; i < padding; i++)
5908 ins_str((char_u *)" ");
5909 changed_bytes(curwin->w_cursor.lnum, leader_len);
5910 } else {
5911 (void)set_indent(second_indent, SIN_CHANGED);
5912 }
5913 }
5914 }
5915 first_line = FALSE;
5916 }
5917
5918 if (State & VREPLACE_FLAG) {
5919 /*
5920 * In VREPLACE mode we have backspaced over the text to be
5921 * moved, now we re-insert it into the new line.
5922 */
5923 ins_bytes(saved_text);
5924 xfree(saved_text);
5925 } else {
5926 /*
5927 * Check if cursor is not past the NUL off the line, cindent
5928 * may have added or removed indent.
5929 */
5930 curwin->w_cursor.col += startcol;
5931 len = (colnr_T)STRLEN(get_cursor_line_ptr());
5932 if (curwin->w_cursor.col > len)
5933 curwin->w_cursor.col = len;
5934 }
5935
5936 haveto_redraw = true;
5937 can_cindent = true;
5938 // moved the cursor, don't autoindent or cindent now
5939 did_ai = false;
5940 did_si = false;
5941 can_si = false;
5942 can_si_back = false;
5943 line_breakcheck();
5944 }
5945
5946 if (save_char != NUL) /* put back space after cursor */
5947 pchar_cursor(save_char);
5948
5949 curwin->w_p_lbr = has_lbr;
5950
5951 if (!format_only && haveto_redraw) {
5952 update_topline();
5953 redraw_curbuf_later(VALID);
5954 }
5955}
5956
5957/*
5958 * Called after inserting or deleting text: When 'formatoptions' includes the
5959 * 'a' flag format from the current line until the end of the paragraph.
5960 * Keep the cursor at the same position relative to the text.
5961 * The caller must have saved the cursor line for undo, following ones will be
5962 * saved here.
5963 */
5964void
5965auto_format (
5966 int trailblank, /* when TRUE also format with trailing blank */
5967 int prev_line /* may start in previous line */
5968)
5969{
5970 pos_T pos;
5971 colnr_T len;
5972 char_u *old;
5973 char_u *new, *pnew;
5974 int wasatend;
5975 int cc;
5976
5977 if (!has_format_option(FO_AUTO))
5978 return;
5979
5980 pos = curwin->w_cursor;
5981 old = get_cursor_line_ptr();
5982
5983 // may remove added space
5984 check_auto_format(false);
5985
5986 /* Don't format in Insert mode when the cursor is on a trailing blank, the
5987 * user might insert normal text next. Also skip formatting when "1" is
5988 * in 'formatoptions' and there is a single character before the cursor.
5989 * Otherwise the line would be broken and when typing another non-white
5990 * next they are not joined back together. */
5991 wasatend = (pos.col == (colnr_T)STRLEN(old));
5992 if (*old != NUL && !trailblank && wasatend) {
5993 dec_cursor();
5994 cc = gchar_cursor();
5995 if (!WHITECHAR(cc) && curwin->w_cursor.col > 0
5996 && has_format_option(FO_ONE_LETTER))
5997 dec_cursor();
5998 cc = gchar_cursor();
5999 if (WHITECHAR(cc)) {
6000 curwin->w_cursor = pos;
6001 return;
6002 }
6003 curwin->w_cursor = pos;
6004 }
6005
6006 /* With the 'c' flag in 'formatoptions' and 't' missing: only format
6007 * comments. */
6008 if (has_format_option(FO_WRAP_COMS) && !has_format_option(FO_WRAP)
6009 && get_leader_len(old, NULL, FALSE, TRUE) == 0)
6010 return;
6011
6012 /*
6013 * May start formatting in a previous line, so that after "x" a word is
6014 * moved to the previous line if it fits there now. Only when this is not
6015 * the start of a paragraph.
6016 */
6017 if (prev_line && !paragraph_start(curwin->w_cursor.lnum)) {
6018 --curwin->w_cursor.lnum;
6019 if (u_save_cursor() == FAIL)
6020 return;
6021 }
6022
6023 /*
6024 * Do the formatting and restore the cursor position. "saved_cursor" will
6025 * be adjusted for the text formatting.
6026 */
6027 saved_cursor = pos;
6028 format_lines((linenr_T)-1, FALSE);
6029 curwin->w_cursor = saved_cursor;
6030 saved_cursor.lnum = 0;
6031
6032 if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) {
6033 /* "cannot happen" */
6034 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
6035 coladvance((colnr_T)MAXCOL);
6036 } else
6037 check_cursor_col();
6038
6039 /* Insert mode: If the cursor is now after the end of the line while it
6040 * previously wasn't, the line was broken. Because of the rule above we
6041 * need to add a space when 'w' is in 'formatoptions' to keep a paragraph
6042 * formatted. */
6043 if (!wasatend && has_format_option(FO_WHITE_PAR)) {
6044 new = get_cursor_line_ptr();
6045 len = (colnr_T)STRLEN(new);
6046 if (curwin->w_cursor.col == len) {
6047 pnew = vim_strnsave(new, len + 2);
6048 pnew[len] = ' ';
6049 pnew[len + 1] = NUL;
6050 ml_replace(curwin->w_cursor.lnum, pnew, false);
6051 // remove the space later
6052 did_add_space = true;
6053 } else {
6054 // may remove added space
6055 check_auto_format(false);
6056 }
6057 }
6058
6059 check_cursor();
6060}
6061
6062/*
6063 * When an extra space was added to continue a paragraph for auto-formatting,
6064 * delete it now. The space must be under the cursor, just after the insert
6065 * position.
6066 */
6067static void check_auto_format(
6068 bool end_insert // true when ending Insert mode
6069)
6070{
6071 int c = ' ';
6072 int cc;
6073
6074 if (did_add_space) {
6075 cc = gchar_cursor();
6076 if (!WHITECHAR(cc)) {
6077 // Somehow the space was removed already.
6078 did_add_space = false;
6079 } else {
6080 if (!end_insert) {
6081 inc_cursor();
6082 c = gchar_cursor();
6083 dec_cursor();
6084 }
6085 if (c != NUL) {
6086 // The space is no longer at the end of the line, delete it.
6087 del_char(false);
6088 did_add_space = false;
6089 }
6090 }
6091 }
6092}
6093
6094/*
6095 * Find out textwidth to be used for formatting:
6096 * if 'textwidth' option is set, use it
6097 * else if 'wrapmargin' option is set, use curwin->w_width_inner-'wrapmargin'
6098 * if invalid value, use 0.
6099 * Set default to window width (maximum 79) for "gq" operator.
6100 */
6101int
6102comp_textwidth (
6103 int ff /* force formatting (for "gq" command) */
6104)
6105{
6106 int textwidth;
6107
6108 textwidth = curbuf->b_p_tw;
6109 if (textwidth == 0 && curbuf->b_p_wm) {
6110 /* The width is the window width minus 'wrapmargin' minus all the
6111 * things that add to the margin. */
6112 textwidth = curwin->w_width_inner - curbuf->b_p_wm;
6113 if (cmdwin_type != 0) {
6114 textwidth -= 1;
6115 }
6116 textwidth -= curwin->w_p_fdc;
6117 textwidth -= win_signcol_count(curwin);
6118
6119 if (curwin->w_p_nu || curwin->w_p_rnu)
6120 textwidth -= 8;
6121 }
6122 if (textwidth < 0)
6123 textwidth = 0;
6124 if (ff && textwidth == 0) {
6125 textwidth = curwin->w_width_inner - 1;
6126 if (textwidth > 79) {
6127 textwidth = 79;
6128 }
6129 }
6130 return textwidth;
6131}
6132
6133/*
6134 * Put a character in the redo buffer, for when just after a CTRL-V.
6135 */
6136static void redo_literal(int c)
6137{
6138 char buf[10];
6139
6140 // Only digits need special treatment. Translate them into a string of
6141 // three digits.
6142 if (ascii_isdigit(c)) {
6143 vim_snprintf(buf, sizeof(buf), "%03d", c);
6144 AppendToRedobuff(buf);
6145 } else {
6146 AppendCharToRedobuff(c);
6147 }
6148}
6149
6150// start_arrow() is called when an arrow key is used in insert mode.
6151// For undo/redo it resembles hitting the <ESC> key.
6152static void start_arrow(pos_T *end_insert_pos /* can be NULL */)
6153{
6154 start_arrow_common(end_insert_pos, true);
6155}
6156
6157/// Like start_arrow() but with end_change argument.
6158/// Will prepare for redo of CTRL-G U if "end_change" is FALSE.
6159/// @param end_insert_pos can be NULL
6160/// @param end_change end undoable change
6161static void start_arrow_with_change(pos_T *end_insert_pos, bool end_change)
6162{
6163 start_arrow_common(end_insert_pos, end_change);
6164 if (!end_change) {
6165 AppendCharToRedobuff(Ctrl_G);
6166 AppendCharToRedobuff('U');
6167 }
6168}
6169
6170/// @param end_insert_pos can be NULL
6171/// @param end_change end undoable change
6172static void start_arrow_common(pos_T *end_insert_pos, bool end_change)
6173{
6174 if (!arrow_used && end_change) { // something has been inserted
6175 AppendToRedobuff(ESC_STR);
6176 stop_insert(end_insert_pos, false, false);
6177 arrow_used = true; // This means we stopped the current insert.
6178 }
6179 check_spell_redraw();
6180}
6181
6182/*
6183 * If we skipped highlighting word at cursor, do it now.
6184 * It may be skipped again, thus reset spell_redraw_lnum first.
6185 */
6186static void check_spell_redraw(void)
6187{
6188 if (spell_redraw_lnum != 0) {
6189 linenr_T lnum = spell_redraw_lnum;
6190
6191 spell_redraw_lnum = 0;
6192 redrawWinline(curwin, lnum);
6193 }
6194}
6195
6196/*
6197 * Called when starting CTRL_X_SPELL mode: Move backwards to a previous badly
6198 * spelled word, if there is one.
6199 */
6200static void spell_back_to_badword(void)
6201{
6202 pos_T tpos = curwin->w_cursor;
6203 spell_bad_len = spell_move_to(curwin, BACKWARD, TRUE, TRUE, NULL);
6204 if (curwin->w_cursor.col != tpos.col)
6205 start_arrow(&tpos);
6206}
6207
6208/*
6209 * stop_arrow() is called before a change is made in insert mode.
6210 * If an arrow key has been used, start a new insertion.
6211 * Returns FAIL if undo is impossible, shouldn't insert then.
6212 */
6213int stop_arrow(void)
6214{
6215 if (arrow_used) {
6216 Insstart = curwin->w_cursor; //new insertion starts here
6217 if (Insstart.col > Insstart_orig.col && !ins_need_undo) {
6218 // Don't update the original insert position when moved to the
6219 // right, except when nothing was inserted yet.
6220 update_Insstart_orig = FALSE;
6221 }
6222 Insstart_textlen = (colnr_T)linetabsize(get_cursor_line_ptr());
6223
6224 if (u_save_cursor() == OK) {
6225 arrow_used = FALSE;
6226 ins_need_undo = FALSE;
6227 }
6228 ai_col = 0;
6229 if (State & VREPLACE_FLAG) {
6230 orig_line_count = curbuf->b_ml.ml_line_count;
6231 vr_lines_changed = 1;
6232 }
6233 ResetRedobuff();
6234 AppendToRedobuff("1i"); // Pretend we start an insertion.
6235 new_insert_skip = 2;
6236 } else if (ins_need_undo) {
6237 if (u_save_cursor() == OK)
6238 ins_need_undo = FALSE;
6239 }
6240
6241 /* Always open fold at the cursor line when inserting something. */
6242 foldOpenCursor();
6243
6244 return arrow_used || ins_need_undo ? FAIL : OK;
6245}
6246
6247/*
6248 * Do a few things to stop inserting.
6249 * "end_insert_pos" is where insert ended. It is NULL when we already jumped
6250 * to another window/buffer.
6251 */
6252static void
6253stop_insert (
6254 pos_T *end_insert_pos,
6255 int esc, /* called by ins_esc() */
6256 int nomove /* <c-\><c-o>, don't move cursor */
6257)
6258{
6259 int cc;
6260 char_u *ptr;
6261
6262 stop_redo_ins();
6263 replace_flush(); /* abandon replace stack */
6264
6265 /*
6266 * Save the inserted text for later redo with ^@ and CTRL-A.
6267 * Don't do it when "restart_edit" was set and nothing was inserted,
6268 * otherwise CTRL-O w and then <Left> will clear "last_insert".
6269 */
6270 ptr = get_inserted();
6271 if (did_restart_edit == 0 || (ptr != NULL
6272 && (int)STRLEN(ptr) > new_insert_skip)) {
6273 xfree(last_insert);
6274 last_insert = ptr;
6275 last_insert_skip = new_insert_skip;
6276 } else
6277 xfree(ptr);
6278
6279 if (!arrow_used && end_insert_pos != NULL) {
6280 /* Auto-format now. It may seem strange to do this when stopping an
6281 * insertion (or moving the cursor), but it's required when appending
6282 * a line and having it end in a space. But only do it when something
6283 * was actually inserted, otherwise undo won't work. */
6284 if (!ins_need_undo && has_format_option(FO_AUTO)) {
6285 pos_T tpos = curwin->w_cursor;
6286
6287 /* When the cursor is at the end of the line after a space the
6288 * formatting will move it to the following word. Avoid that by
6289 * moving the cursor onto the space. */
6290 cc = 'x';
6291 if (curwin->w_cursor.col > 0 && gchar_cursor() == NUL) {
6292 dec_cursor();
6293 cc = gchar_cursor();
6294 if (!ascii_iswhite(cc))
6295 curwin->w_cursor = tpos;
6296 }
6297
6298 auto_format(TRUE, FALSE);
6299
6300 if (ascii_iswhite(cc)) {
6301 if (gchar_cursor() != NUL)
6302 inc_cursor();
6303 /* If the cursor is still at the same character, also keep
6304 * the "coladd". */
6305 if (gchar_cursor() == NUL
6306 && curwin->w_cursor.lnum == tpos.lnum
6307 && curwin->w_cursor.col == tpos.col)
6308 curwin->w_cursor.coladd = tpos.coladd;
6309 }
6310 }
6311
6312 // If a space was inserted for auto-formatting, remove it now.
6313 check_auto_format(true);
6314
6315 /* If we just did an auto-indent, remove the white space from the end
6316 * of the line, and put the cursor back.
6317 * Do this when ESC was used or moving the cursor up/down.
6318 * Check for the old position still being valid, just in case the text
6319 * got changed unexpectedly. */
6320 if (!nomove && did_ai && (esc || (vim_strchr(p_cpo, CPO_INDENT) == NULL
6321 && curwin->w_cursor.lnum !=
6322 end_insert_pos->lnum))
6323 && end_insert_pos->lnum <= curbuf->b_ml.ml_line_count) {
6324 pos_T tpos = curwin->w_cursor;
6325
6326 curwin->w_cursor = *end_insert_pos;
6327 check_cursor_col(); /* make sure it is not past the line */
6328 for (;; ) {
6329 if (gchar_cursor() == NUL && curwin->w_cursor.col > 0)
6330 --curwin->w_cursor.col;
6331 cc = gchar_cursor();
6332 if (!ascii_iswhite(cc)) {
6333 break;
6334 }
6335 if (del_char(true) == FAIL) {
6336 break; // should not happen
6337 }
6338 }
6339 if (curwin->w_cursor.lnum != tpos.lnum)
6340 curwin->w_cursor = tpos;
6341 else {
6342 /* reset tpos, could have been invalidated in the loop above */
6343 tpos = curwin->w_cursor;
6344 tpos.col++;
6345 if (cc != NUL && gchar_pos(&tpos) == NUL) {
6346 ++curwin->w_cursor.col; // put cursor back on the NUL
6347 }
6348 }
6349
6350 /* <C-S-Right> may have started Visual mode, adjust the position for
6351 * deleted characters. */
6352 if (VIsual_active && VIsual.lnum == curwin->w_cursor.lnum) {
6353 int len = (int)STRLEN(get_cursor_line_ptr());
6354
6355 if (VIsual.col > len) {
6356 VIsual.col = len;
6357 VIsual.coladd = 0;
6358 }
6359 }
6360 }
6361 }
6362 did_ai = false;
6363 did_si = false;
6364 can_si = false;
6365 can_si_back = false;
6366
6367 /* Set '[ and '] to the inserted text. When end_insert_pos is NULL we are
6368 * now in a different buffer. */
6369 if (end_insert_pos != NULL) {
6370 curbuf->b_op_start = Insstart;
6371 curbuf->b_op_start_orig = Insstart_orig;
6372 curbuf->b_op_end = *end_insert_pos;
6373 }
6374}
6375
6376/*
6377 * Set the last inserted text to a single character.
6378 * Used for the replace command.
6379 */
6380void set_last_insert(int c)
6381{
6382 char_u *s;
6383
6384 xfree(last_insert);
6385 last_insert = xmalloc(MB_MAXBYTES * 3 + 5);
6386 s = last_insert;
6387 /* Use the CTRL-V only when entering a special char */
6388 if (c < ' ' || c == DEL)
6389 *s++ = Ctrl_V;
6390 s = add_char2buf(c, s);
6391 *s++ = ESC;
6392 *s++ = NUL;
6393 last_insert_skip = 0;
6394}
6395
6396#if defined(EXITFREE)
6397void free_last_insert(void)
6398{
6399 XFREE_CLEAR(last_insert);
6400 XFREE_CLEAR(compl_orig_text);
6401}
6402
6403#endif
6404
6405/// Add character "c" to buffer "s"
6406///
6407/// Escapes the special meaning of K_SPECIAL and CSI, handles multi-byte
6408/// characters.
6409///
6410/// @param[in] c Character to add.
6411/// @param[out] s Buffer to add to. Must have at least MB_MAXBYTES + 1 bytes.
6412///
6413/// @return Pointer to after the added bytes.
6414char_u *add_char2buf(int c, char_u *s)
6415 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
6416{
6417 char_u temp[MB_MAXBYTES + 1];
6418 const int len = utf_char2bytes(c, temp);
6419 for (int i = 0; i < len; i++) {
6420 c = temp[i];
6421 // Need to escape K_SPECIAL and CSI like in the typeahead buffer.
6422 if (c == K_SPECIAL) {
6423 *s++ = K_SPECIAL;
6424 *s++ = KS_SPECIAL;
6425 *s++ = KE_FILLER;
6426 } else {
6427 *s++ = c;
6428 }
6429 }
6430 return s;
6431}
6432
6433/*
6434 * move cursor to start of line
6435 * if flags & BL_WHITE move to first non-white
6436 * if flags & BL_SOL move to first non-white if startofline is set,
6437 * otherwise keep "curswant" column
6438 * if flags & BL_FIX don't leave the cursor on a NUL.
6439 */
6440void beginline(int flags)
6441{
6442 if ((flags & BL_SOL) && !p_sol)
6443 coladvance(curwin->w_curswant);
6444 else {
6445 curwin->w_cursor.col = 0;
6446 curwin->w_cursor.coladd = 0;
6447
6448 if (flags & (BL_WHITE | BL_SOL)) {
6449 char_u *ptr;
6450
6451 for (ptr = get_cursor_line_ptr(); ascii_iswhite(*ptr)
6452 && !((flags & BL_FIX) && ptr[1] == NUL); ++ptr)
6453 ++curwin->w_cursor.col;
6454 }
6455 curwin->w_set_curswant = TRUE;
6456 }
6457}
6458
6459/*
6460 * oneright oneleft cursor_down cursor_up
6461 *
6462 * Move one char {right,left,down,up}.
6463 * Doesn't move onto the NUL past the end of the line, unless it is allowed.
6464 * Return OK when successful, FAIL when we hit a line of file boundary.
6465 */
6466
6467int oneright(void)
6468{
6469 char_u *ptr;
6470 int l;
6471
6472 if (virtual_active()) {
6473 pos_T prevpos = curwin->w_cursor;
6474
6475 /* Adjust for multi-wide char (excluding TAB) */
6476 ptr = get_cursor_pos_ptr();
6477 coladvance(getviscol() + ((*ptr != TAB && vim_isprintc(utf_ptr2char(ptr))) ?
6478 ptr2cells(ptr) : 1));
6479 curwin->w_set_curswant = true;
6480 // Return OK if the cursor moved, FAIL otherwise (at window edge).
6481 return (prevpos.col != curwin->w_cursor.col
6482 || prevpos.coladd != curwin->w_cursor.coladd) ? OK : FAIL;
6483 }
6484
6485 ptr = get_cursor_pos_ptr();
6486 if (*ptr == NUL)
6487 return FAIL; /* already at the very end */
6488
6489 if (has_mbyte)
6490 l = (*mb_ptr2len)(ptr);
6491 else
6492 l = 1;
6493
6494 /* move "l" bytes right, but don't end up on the NUL, unless 'virtualedit'
6495 * contains "onemore". */
6496 if (ptr[l] == NUL
6497 && (ve_flags & VE_ONEMORE) == 0
6498 )
6499 return FAIL;
6500 curwin->w_cursor.col += l;
6501
6502 curwin->w_set_curswant = TRUE;
6503 return OK;
6504}
6505
6506int oneleft(void)
6507{
6508 if (virtual_active()) {
6509 int width;
6510 int v = getviscol();
6511
6512 if (v == 0)
6513 return FAIL;
6514
6515 /* We might get stuck on 'showbreak', skip over it. */
6516 width = 1;
6517 for (;; ) {
6518 coladvance(v - width);
6519 /* getviscol() is slow, skip it when 'showbreak' is empty,
6520 'breakindent' is not set and there are no multi-byte
6521 characters */
6522 if ((*p_sbr == NUL
6523 && !curwin->w_p_bri
6524 && !has_mbyte
6525 ) || getviscol() < v)
6526 break;
6527 ++width;
6528 }
6529
6530 if (curwin->w_cursor.coladd == 1) {
6531 char_u *ptr;
6532
6533 /* Adjust for multi-wide char (not a TAB) */
6534 ptr = get_cursor_pos_ptr();
6535 if (*ptr != TAB && vim_isprintc(utf_ptr2char(ptr))
6536 && ptr2cells(ptr) > 1) {
6537 curwin->w_cursor.coladd = 0;
6538 }
6539 }
6540
6541 curwin->w_set_curswant = TRUE;
6542 return OK;
6543 }
6544
6545 if (curwin->w_cursor.col == 0)
6546 return FAIL;
6547
6548 curwin->w_set_curswant = TRUE;
6549 --curwin->w_cursor.col;
6550
6551 /* if the character on the left of the current cursor is a multi-byte
6552 * character, move to its first byte */
6553 if (has_mbyte)
6554 mb_adjust_cursor();
6555 return OK;
6556}
6557
6558int
6559cursor_up (
6560 long n,
6561 int upd_topline /* When TRUE: update topline */
6562)
6563{
6564 linenr_T lnum;
6565
6566 if (n > 0) {
6567 lnum = curwin->w_cursor.lnum;
6568
6569 // This fails if the cursor is already in the first line.
6570 if (lnum <= 1) {
6571 return FAIL;
6572 }
6573 if (n >= lnum)
6574 lnum = 1;
6575 else if (hasAnyFolding(curwin)) {
6576 /*
6577 * Count each sequence of folded lines as one logical line.
6578 */
6579 /* go to the start of the current fold */
6580 (void)hasFolding(lnum, &lnum, NULL);
6581
6582 while (n--) {
6583 /* move up one line */
6584 --lnum;
6585 if (lnum <= 1)
6586 break;
6587 /* If we entered a fold, move to the beginning, unless in
6588 * Insert mode or when 'foldopen' contains "all": it will open
6589 * in a moment. */
6590 if (n > 0 || !((State & INSERT) || (fdo_flags & FDO_ALL)))
6591 (void)hasFolding(lnum, &lnum, NULL);
6592 }
6593 if (lnum < 1)
6594 lnum = 1;
6595 } else
6596 lnum -= n;
6597 curwin->w_cursor.lnum = lnum;
6598 }
6599
6600 /* try to advance to the column we want to be at */
6601 coladvance(curwin->w_curswant);
6602
6603 if (upd_topline)
6604 update_topline(); /* make sure curwin->w_topline is valid */
6605
6606 return OK;
6607}
6608
6609/*
6610 * Cursor down a number of logical lines.
6611 */
6612int
6613cursor_down (
6614 long n,
6615 int upd_topline /* When TRUE: update topline */
6616)
6617{
6618 linenr_T lnum;
6619
6620 if (n > 0) {
6621 lnum = curwin->w_cursor.lnum;
6622 /* Move to last line of fold, will fail if it's the end-of-file. */
6623 (void)hasFolding(lnum, NULL, &lnum);
6624
6625 // This fails if the cursor is already in the last line.
6626 if (lnum >= curbuf->b_ml.ml_line_count) {
6627 return FAIL;
6628 }
6629 if (lnum + n >= curbuf->b_ml.ml_line_count)
6630 lnum = curbuf->b_ml.ml_line_count;
6631 else if (hasAnyFolding(curwin)) {
6632 linenr_T last;
6633
6634 /* count each sequence of folded lines as one logical line */
6635 while (n--) {
6636 if (hasFolding(lnum, NULL, &last))
6637 lnum = last + 1;
6638 else
6639 ++lnum;
6640 if (lnum >= curbuf->b_ml.ml_line_count)
6641 break;
6642 }
6643 if (lnum > curbuf->b_ml.ml_line_count)
6644 lnum = curbuf->b_ml.ml_line_count;
6645 } else
6646 lnum += n;
6647 curwin->w_cursor.lnum = lnum;
6648 }
6649
6650 /* try to advance to the column we want to be at */
6651 coladvance(curwin->w_curswant);
6652
6653 if (upd_topline)
6654 update_topline(); /* make sure curwin->w_topline is valid */
6655
6656 return OK;
6657}
6658
6659/*
6660 * Stuff the last inserted text in the read buffer.
6661 * Last_insert actually is a copy of the redo buffer, so we
6662 * first have to remove the command.
6663 */
6664int
6665stuff_inserted (
6666 int c, /* Command character to be inserted */
6667 long count, /* Repeat this many times */
6668 int no_esc /* Don't add an ESC at the end */
6669)
6670{
6671 char_u *esc_ptr;
6672 char_u *ptr;
6673 char_u *last_ptr;
6674 char_u last = NUL;
6675
6676 ptr = get_last_insert();
6677 if (ptr == NULL) {
6678 EMSG(_(e_noinstext));
6679 return FAIL;
6680 }
6681
6682 /* may want to stuff the command character, to start Insert mode */
6683 if (c != NUL)
6684 stuffcharReadbuff(c);
6685 if ((esc_ptr = STRRCHR(ptr, ESC)) != NULL) {
6686 // remove the ESC.
6687 *esc_ptr = NUL;
6688 }
6689
6690 /* when the last char is either "0" or "^" it will be quoted if no ESC
6691 * comes after it OR if it will inserted more than once and "ptr"
6692 * starts with ^D. -- Acevedo
6693 */
6694 last_ptr = (esc_ptr ? esc_ptr : ptr + STRLEN(ptr)) - 1;
6695 if (last_ptr >= ptr && (*last_ptr == '0' || *last_ptr == '^')
6696 && (no_esc || (*ptr == Ctrl_D && count > 1))) {
6697 last = *last_ptr;
6698 *last_ptr = NUL;
6699 }
6700
6701 do {
6702 stuffReadbuff((const char *)ptr);
6703 // A trailing "0" is inserted as "<C-V>048", "^" as "<C-V>^".
6704 if (last) {
6705 stuffReadbuff((last == '0'
6706 ? "\026\060\064\070"
6707 : "\026^"));
6708 }
6709 } while (--count > 0);
6710
6711 if (last)
6712 *last_ptr = last;
6713
6714 if (esc_ptr != NULL)
6715 *esc_ptr = ESC; /* put the ESC back */
6716
6717 /* may want to stuff a trailing ESC, to get out of Insert mode */
6718 if (!no_esc)
6719 stuffcharReadbuff(ESC);
6720
6721 return OK;
6722}
6723
6724char_u *get_last_insert(void)
6725{
6726 if (last_insert == NULL)
6727 return NULL;
6728 return last_insert + last_insert_skip;
6729}
6730
6731/*
6732 * Get last inserted string, and remove trailing <Esc>.
6733 * Returns pointer to allocated memory (must be freed) or NULL.
6734 */
6735char_u *get_last_insert_save(void)
6736{
6737 char_u *s;
6738 int len;
6739
6740 if (last_insert == NULL)
6741 return NULL;
6742 s = vim_strsave(last_insert + last_insert_skip);
6743 len = (int)STRLEN(s);
6744 if (len > 0 && s[len - 1] == ESC) /* remove trailing ESC */
6745 s[len - 1] = NUL;
6746
6747 return s;
6748}
6749
6750/// Check the word in front of the cursor for an abbreviation.
6751/// Called when the non-id character "c" has been entered.
6752/// When an abbreviation is recognized it is removed from the text and
6753/// the replacement string is inserted in typebuf.tb_buf[], followed by "c".
6754///
6755/// @param c character
6756///
6757/// @return true if the word is a known abbreviation.
6758static bool echeck_abbr(int c)
6759 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
6760{
6761 // Don't check for abbreviation in paste mode, when disabled and just
6762 // after moving around with cursor keys.
6763 if (p_paste || no_abbr || arrow_used) {
6764 return false;
6765 }
6766
6767 return check_abbr(c, get_cursor_line_ptr(), curwin->w_cursor.col,
6768 curwin->w_cursor.lnum == Insstart.lnum ? Insstart.col : 0);
6769}
6770
6771/*
6772 * replace-stack functions
6773 *
6774 * When replacing characters, the replaced characters are remembered for each
6775 * new character. This is used to re-insert the old text when backspacing.
6776 *
6777 * There is a NUL headed list of characters for each character that is
6778 * currently in the file after the insertion point. When BS is used, one NUL
6779 * headed list is put back for the deleted character.
6780 *
6781 * For a newline, there are two NUL headed lists. One contains the characters
6782 * that the NL replaced. The extra one stores the characters after the cursor
6783 * that were deleted (always white space).
6784 */
6785
6786static char_u *replace_stack = NULL;
6787static ssize_t replace_stack_nr = 0; /* next entry in replace stack */
6788static ssize_t replace_stack_len = 0; /* max. number of entries */
6789
6790/// Push character that is replaced onto the the replace stack.
6791///
6792/// replace_offset is normally 0, in which case replace_push will add a new
6793/// character at the end of the stack. If replace_offset is not 0, that many
6794/// characters will be left on the stack above the newly inserted character.
6795///
6796/// @param c character that is replaced (NUL is none)
6797void replace_push(int c)
6798{
6799 if (replace_stack_nr < replace_offset) { // nothing to do
6800 return;
6801 }
6802
6803 if (replace_stack_len <= replace_stack_nr) {
6804 replace_stack_len += 50;
6805 replace_stack = xrealloc(replace_stack, replace_stack_len);
6806 }
6807 char_u *p = replace_stack + replace_stack_nr - replace_offset;
6808 if (replace_offset) {
6809 memmove(p + 1, p, replace_offset);
6810 }
6811 *p = (char_u)c;
6812 ++replace_stack_nr;
6813}
6814
6815/*
6816 * Push a character onto the replace stack. Handles a multi-byte character in
6817 * reverse byte order, so that the first byte is popped off first.
6818 * Return the number of bytes done (includes composing characters).
6819 */
6820int replace_push_mb(char_u *p)
6821{
6822 int l = (*mb_ptr2len)(p);
6823 int j;
6824
6825 for (j = l - 1; j >= 0; --j)
6826 replace_push(p[j]);
6827 return l;
6828}
6829
6830/// Pop one item from the replace stack.
6831///
6832/// @return -1 if stack is empty, replaced character or NUL otherwise
6833static int replace_pop(void)
6834{
6835 return (replace_stack_nr == 0) ? -1 : (int)replace_stack[--replace_stack_nr];
6836}
6837
6838/*
6839 * Join the top two items on the replace stack. This removes to "off"'th NUL
6840 * encountered.
6841 */
6842static void
6843replace_join (
6844 int off /* offset for which NUL to remove */
6845)
6846{
6847 int i;
6848
6849 for (i = replace_stack_nr; --i >= 0; )
6850 if (replace_stack[i] == NUL && off-- <= 0) {
6851 --replace_stack_nr;
6852 memmove(replace_stack + i, replace_stack + i + 1,
6853 (size_t)(replace_stack_nr - i));
6854 return;
6855 }
6856}
6857
6858/*
6859 * Pop bytes from the replace stack until a NUL is found, and insert them
6860 * before the cursor. Can only be used in REPLACE or VREPLACE mode.
6861 */
6862static void replace_pop_ins(void)
6863{
6864 int cc;
6865 int oldState = State;
6866
6867 State = NORMAL; /* don't want REPLACE here */
6868 while ((cc = replace_pop()) > 0) {
6869 mb_replace_pop_ins(cc);
6870 dec_cursor();
6871 }
6872 State = oldState;
6873}
6874
6875/*
6876 * Insert bytes popped from the replace stack. "cc" is the first byte. If it
6877 * indicates a multi-byte char, pop the other bytes too.
6878 */
6879static void mb_replace_pop_ins(int cc)
6880{
6881 int n;
6882 char_u buf[MB_MAXBYTES + 1];
6883 int i;
6884 int c;
6885
6886 if (has_mbyte && (n = MB_BYTE2LEN(cc)) > 1) {
6887 buf[0] = cc;
6888 for (i = 1; i < n; ++i)
6889 buf[i] = replace_pop();
6890 ins_bytes_len(buf, n);
6891 } else
6892 ins_char(cc);
6893
6894 if (enc_utf8)
6895 /* Handle composing chars. */
6896 for (;; ) {
6897 c = replace_pop();
6898 if (c == -1) /* stack empty */
6899 break;
6900 if ((n = MB_BYTE2LEN(c)) == 1) {
6901 /* Not a multi-byte char, put it back. */
6902 replace_push(c);
6903 break;
6904 } else {
6905 buf[0] = c;
6906 assert(n > 1);
6907 for (i = 1; i < n; ++i)
6908 buf[i] = replace_pop();
6909 if (utf_iscomposing(utf_ptr2char(buf)))
6910 ins_bytes_len(buf, n);
6911 else {
6912 /* Not a composing char, put it back. */
6913 for (i = n - 1; i >= 0; --i)
6914 replace_push(buf[i]);
6915 break;
6916 }
6917 }
6918 }
6919}
6920
6921/*
6922 * make the replace stack empty
6923 * (called when exiting replace mode)
6924 */
6925static void replace_flush(void)
6926{
6927 XFREE_CLEAR(replace_stack);
6928 replace_stack_len = 0;
6929 replace_stack_nr = 0;
6930}
6931
6932/*
6933 * Handle doing a BS for one character.
6934 * cc < 0: replace stack empty, just move cursor
6935 * cc == 0: character was inserted, delete it
6936 * cc > 0: character was replaced, put cc (first byte of original char) back
6937 * and check for more characters to be put back
6938 * When "limit_col" is >= 0, don't delete before this column. Matters when
6939 * using composing characters, use del_char_after_col() instead of del_char().
6940 */
6941static void replace_do_bs(int limit_col)
6942{
6943 int cc;
6944 int orig_len = 0;
6945 int ins_len;
6946 int orig_vcols = 0;
6947 colnr_T start_vcol;
6948 char_u *p;
6949 int i;
6950 int vcol;
6951 const int l_State = State;
6952
6953 cc = replace_pop();
6954 if (cc > 0) {
6955 if (l_State & VREPLACE_FLAG) {
6956 /* Get the number of screen cells used by the character we are
6957 * going to delete. */
6958 getvcol(curwin, &curwin->w_cursor, NULL, &start_vcol, NULL);
6959 orig_vcols = chartabsize(get_cursor_pos_ptr(), start_vcol);
6960 }
6961 if (has_mbyte) {
6962 (void)del_char_after_col(limit_col);
6963 if (l_State & VREPLACE_FLAG)
6964 orig_len = (int)STRLEN(get_cursor_pos_ptr());
6965 replace_push(cc);
6966 } else {
6967 pchar_cursor(cc);
6968 if (l_State & VREPLACE_FLAG)
6969 orig_len = (int)STRLEN(get_cursor_pos_ptr()) - 1;
6970 }
6971 replace_pop_ins();
6972
6973 if (l_State & VREPLACE_FLAG) {
6974 /* Get the number of screen cells used by the inserted characters */
6975 p = get_cursor_pos_ptr();
6976 ins_len = (int)STRLEN(p) - orig_len;
6977 vcol = start_vcol;
6978 for (i = 0; i < ins_len; ++i) {
6979 vcol += chartabsize(p + i, vcol);
6980 i += (*mb_ptr2len)(p) - 1;
6981 }
6982 vcol -= start_vcol;
6983
6984 /* Delete spaces that were inserted after the cursor to keep the
6985 * text aligned. */
6986 curwin->w_cursor.col += ins_len;
6987 while (vcol > orig_vcols && gchar_cursor() == ' ') {
6988 del_char(false);
6989 orig_vcols++;
6990 }
6991 curwin->w_cursor.col -= ins_len;
6992 }
6993
6994 /* mark the buffer as changed and prepare for displaying */
6995 changed_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col);
6996 } else if (cc == 0)
6997 (void)del_char_after_col(limit_col);
6998}
6999
7000/// Check that C-indenting is on.
7001static bool cindent_on(void)
7002 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
7003{
7004 return !p_paste && (curbuf->b_p_cin || *curbuf->b_p_inde != NUL);
7005}
7006
7007/*
7008 * Re-indent the current line, based on the current contents of it and the
7009 * surrounding lines. Fixing the cursor position seems really easy -- I'm very
7010 * confused what all the part that handles Control-T is doing that I'm not.
7011 * "get_the_indent" should be get_c_indent, get_expr_indent or get_lisp_indent.
7012 */
7013void fixthisline(IndentGetter get_the_indent)
7014{
7015 int amount = get_the_indent();
7016
7017 if (amount >= 0) {
7018 change_indent(INDENT_SET, amount, false, 0, true);
7019 if (linewhite(curwin->w_cursor.lnum)) {
7020 did_ai = true; // delete the indent if the line stays empty
7021 }
7022 }
7023}
7024
7025void fix_indent(void) {
7026 if (p_paste)
7027 return;
7028 if (curbuf->b_p_lisp && curbuf->b_p_ai)
7029 fixthisline(get_lisp_indent);
7030 else if (cindent_on())
7031 do_c_expr_indent();
7032}
7033
7034/// Check that "cinkeys" contains the key "keytyped",
7035/// when == '*': Only if key is preceded with '*' (indent before insert)
7036/// when == '!': Only if key is preceded with '!' (don't insert)
7037/// when == ' ': Only if key is not preceded with '*' (indent afterwards)
7038///
7039/// "keytyped" can have a few special values:
7040/// KEY_OPEN_FORW :
7041/// KEY_OPEN_BACK :
7042/// KEY_COMPLETE : Just finished completion.
7043///
7044/// @param keytyped key that was typed
7045/// @param when condition on when to perform the check
7046/// @param line_is_empty when true, accept keys with '0' before them.
7047bool in_cinkeys(int keytyped, int when, bool line_is_empty)
7048{
7049 char_u *look;
7050 int try_match;
7051 int try_match_word;
7052 char_u *p;
7053 char_u *line;
7054 int icase;
7055 int i;
7056
7057 if (keytyped == NUL) {
7058 // Can happen with CTRL-Y and CTRL-E on a short line.
7059 return false;
7060 }
7061
7062 if (*curbuf->b_p_inde != NUL)
7063 look = curbuf->b_p_indk; /* 'indentexpr' set: use 'indentkeys' */
7064 else
7065 look = curbuf->b_p_cink; /* 'indentexpr' empty: use 'cinkeys' */
7066 while (*look) {
7067 /*
7068 * Find out if we want to try a match with this key, depending on
7069 * 'when' and a '*' or '!' before the key.
7070 */
7071 switch (when) {
7072 case '*': try_match = (*look == '*'); break;
7073 case '!': try_match = (*look == '!'); break;
7074 default: try_match = (*look != '*'); break;
7075 }
7076 if (*look == '*' || *look == '!') {
7077 look++;
7078 }
7079
7080 // If there is a '0', only accept a match if the line is empty.
7081 // But may still match when typing last char of a word.
7082 if (*look == '0') {
7083 try_match_word = try_match;
7084 if (!line_is_empty) {
7085 try_match = false;
7086 }
7087 look++;
7088 } else {
7089 try_match_word = false;
7090 }
7091
7092 // Does it look like a control character?
7093 if (*look == '^' && look[1] >= '?' && look[1] <= '_') {
7094 if (try_match && keytyped == Ctrl_chr(look[1])) {
7095 return true;
7096 }
7097 look += 2;
7098
7099 // 'o' means "o" command, open forward.
7100 // 'O' means "O" command, open backward.
7101 } else if (*look == 'o') {
7102 if (try_match && keytyped == KEY_OPEN_FORW) {
7103 return true;
7104 }
7105 look++;
7106 } else if (*look == 'O') {
7107 if (try_match && keytyped == KEY_OPEN_BACK) {
7108 return true;
7109 }
7110 look++;
7111
7112 // 'e' means to check for "else" at start of line and just before the
7113 // cursor.
7114 } else if (*look == 'e') {
7115 if (try_match && keytyped == 'e' && curwin->w_cursor.col >= 4) {
7116 p = get_cursor_line_ptr();
7117 if (skipwhite(p) == p + curwin->w_cursor.col - 4
7118 && STRNCMP(p + curwin->w_cursor.col - 4, "else", 4) == 0) {
7119 return true;
7120 }
7121 }
7122 look++;
7123
7124 // ':' only causes an indent if it is at the end of a label or case
7125 // statement, or when it was before typing the ':' (to fix
7126 // class::method for C++).
7127 } else if (*look == ':') {
7128 if (try_match && keytyped == ':') {
7129 p = get_cursor_line_ptr();
7130 if (cin_iscase(p, false) || cin_isscopedecl(p) || cin_islabel()) {
7131 return true;
7132 }
7133 // Need to get the line again after cin_islabel().
7134 p = get_cursor_line_ptr();
7135 if (curwin->w_cursor.col > 2
7136 && p[curwin->w_cursor.col - 1] == ':'
7137 && p[curwin->w_cursor.col - 2] == ':') {
7138 p[curwin->w_cursor.col - 1] = ' ';
7139 i = (cin_iscase(p, FALSE) || cin_isscopedecl(p)
7140 || cin_islabel());
7141 p = get_cursor_line_ptr();
7142 p[curwin->w_cursor.col - 1] = ':';
7143 if (i) {
7144 return true;
7145 }
7146 }
7147 }
7148 look++;
7149
7150 // Is it a key in <>, maybe?
7151 } else if (*look == '<') {
7152 if (try_match) {
7153 // make up some named keys <o>, <O>, <e>, <0>, <>>, <<>, <*>,
7154 // <:> and <!> so that people can re-indent on o, O, e, 0, <,
7155 // >, *, : and ! keys if they really really want to.
7156 if (vim_strchr((char_u *)"<>!*oOe0:", look[1]) != NULL
7157 && keytyped == look[1]) {
7158 return true;
7159 }
7160
7161 if (keytyped == get_special_key_code(look + 1)) {
7162 return true;
7163 }
7164 }
7165 while (*look && *look != '>')
7166 look++;
7167 while (*look == '>')
7168 look++;
7169 }
7170 /*
7171 * Is it a word: "=word"?
7172 */
7173 else if (*look == '=' && look[1] != ',' && look[1] != NUL) {
7174 ++look;
7175 if (*look == '~') {
7176 icase = TRUE;
7177 ++look;
7178 } else
7179 icase = FALSE;
7180 p = vim_strchr(look, ',');
7181 if (p == NULL)
7182 p = look + STRLEN(look);
7183 if ((try_match || try_match_word)
7184 && curwin->w_cursor.col >= (colnr_T)(p - look)) {
7185 bool match = false;
7186
7187 if (keytyped == KEY_COMPLETE) {
7188 char_u *s;
7189
7190 /* Just completed a word, check if it starts with "look".
7191 * search back for the start of a word. */
7192 line = get_cursor_line_ptr();
7193 if (has_mbyte) {
7194 char_u *n;
7195
7196 for (s = line + curwin->w_cursor.col; s > line; s = n) {
7197 n = mb_prevptr(line, s);
7198 if (!vim_iswordp(n))
7199 break;
7200 }
7201 } else
7202 for (s = line + curwin->w_cursor.col; s > line; --s)
7203 if (!vim_iswordc(s[-1]))
7204 break;
7205 assert(p >= look && (uintmax_t)(p - look) <= SIZE_MAX);
7206 if (s + (p - look) <= line + curwin->w_cursor.col
7207 && (icase
7208 ? mb_strnicmp(s, look, (size_t)(p - look))
7209 : STRNCMP(s, look, p - look)) == 0)
7210 match = true;
7211 } else {
7212 // TODO(@brammool): multi-byte
7213 if (keytyped == (int)p[-1]
7214 || (icase && keytyped < 256
7215 && TOLOWER_LOC(keytyped) == TOLOWER_LOC((int)p[-1]))) {
7216 line = get_cursor_pos_ptr();
7217 assert(p >= look && (uintmax_t)(p - look) <= SIZE_MAX);
7218 if ((curwin->w_cursor.col == (colnr_T)(p - look)
7219 || !vim_iswordc(line[-(p - look) - 1]))
7220 && (icase
7221 ? mb_strnicmp(line - (p - look), look, (size_t)(p - look))
7222 : STRNCMP(line - (p - look), look, p - look)) == 0) {
7223 match = true;
7224 }
7225 }
7226 }
7227 if (match && try_match_word && !try_match) {
7228 /* "0=word": Check if there are only blanks before the
7229 * word. */
7230 if (getwhitecols_curline() !=
7231 (int)(curwin->w_cursor.col - (p - look))) {
7232 match = false;
7233 }
7234 }
7235 if (match) {
7236 return true;
7237 }
7238 }
7239 look = p;
7240
7241 // Ok, it's a boring generic character.
7242 } else {
7243 if (try_match && *look == keytyped) {
7244 return true;
7245 }
7246 if (*look != NUL) {
7247 look++;
7248 }
7249 }
7250
7251 /*
7252 * Skip over ", ".
7253 */
7254 look = skip_to_option_part(look);
7255 }
7256 return false;
7257}
7258
7259/*
7260 * Map Hebrew keyboard when in hkmap mode.
7261 */
7262int hkmap(int c)
7263{
7264 if (p_hkmapp) { /* phonetic mapping, by Ilya Dogolazky */
7265 enum {hALEF=0, BET, GIMEL, DALET, HEI, VAV, ZAIN, HET, TET, IUD,
7266 KAFsofit, hKAF, LAMED, MEMsofit, MEM, NUNsofit, NUN, SAMEH, AIN,
7267 PEIsofit, PEI, ZADIsofit, ZADI, KOF, RESH, hSHIN, TAV};
7268 static char_u map[26] =
7269 {(char_u)hALEF /*a*/, (char_u)BET /*b*/, (char_u)hKAF /*c*/,
7270 (char_u)DALET /*d*/, (char_u)-1 /*e*/, (char_u)PEIsofit /*f*/,
7271 (char_u)GIMEL /*g*/, (char_u)HEI /*h*/, (char_u)IUD /*i*/,
7272 (char_u)HET /*j*/, (char_u)KOF /*k*/, (char_u)LAMED /*l*/,
7273 (char_u)MEM /*m*/, (char_u)NUN /*n*/, (char_u)SAMEH /*o*/,
7274 (char_u)PEI /*p*/, (char_u)-1 /*q*/, (char_u)RESH /*r*/,
7275 (char_u)ZAIN /*s*/, (char_u)TAV /*t*/, (char_u)TET /*u*/,
7276 (char_u)VAV /*v*/, (char_u)hSHIN /*w*/, (char_u)-1 /*x*/,
7277 (char_u)AIN /*y*/, (char_u)ZADI /*z*/};
7278
7279 if (c == 'N' || c == 'M' || c == 'P' || c == 'C' || c == 'Z')
7280 return (int)(map[CharOrd(c)] - 1 + p_aleph);
7281 /* '-1'='sofit' */
7282 else if (c == 'x')
7283 return 'X';
7284 else if (c == 'q')
7285 return '\''; /* {geresh}={'} */
7286 else if (c == 246)
7287 return ' '; /* \"o --> ' ' for a german keyboard */
7288 else if (c == 228)
7289 return ' '; /* \"a --> ' ' -- / -- */
7290 else if (c == 252)
7291 return ' '; /* \"u --> ' ' -- / -- */
7292 /* NOTE: islower() does not do the right thing for us on Linux so we
7293 * do this the same was as 5.7 and previous, so it works correctly on
7294 * all systems. Specifically, the e.g. Delete and Arrow keys are
7295 * munged and won't work if e.g. searching for Hebrew text.
7296 */
7297 else if (c >= 'a' && c <= 'z')
7298 return (int)(map[CharOrdLow(c)] + p_aleph);
7299 else
7300 return c;
7301 } else {
7302 switch (c) {
7303 case '`': return ';';
7304 case '/': return '.';
7305 case '\'': return ',';
7306 case 'q': return '/';
7307 case 'w': return '\'';
7308
7309 /* Hebrew letters - set offset from 'a' */
7310 case ',': c = '{'; break;
7311 case '.': c = 'v'; break;
7312 case ';': c = 't'; break;
7313 default: {
7314 static char str[] = "zqbcxlsjphmkwonu ydafe rig";
7315
7316 if (c < 'a' || c > 'z')
7317 return c;
7318 c = str[CharOrdLow(c)];
7319 break;
7320 }
7321 }
7322
7323 return (int)(CharOrdLow(c) + p_aleph);
7324 }
7325}
7326
7327static void ins_reg(void)
7328{
7329 int need_redraw = FALSE;
7330 int regname;
7331 int literally = 0;
7332 int vis_active = VIsual_active;
7333
7334 /*
7335 * If we are going to wait for a character, show a '"'.
7336 */
7337 pc_status = PC_STATUS_UNSET;
7338 if (redrawing() && !char_avail()) {
7339 /* may need to redraw when no more chars available now */
7340 ins_redraw(FALSE);
7341
7342 edit_putchar('"', TRUE);
7343 add_to_showcmd_c(Ctrl_R);
7344 }
7345
7346
7347 /*
7348 * Don't map the register name. This also prevents the mode message to be
7349 * deleted when ESC is hit.
7350 */
7351 ++no_mapping;
7352 regname = plain_vgetc();
7353 LANGMAP_ADJUST(regname, TRUE);
7354 if (regname == Ctrl_R || regname == Ctrl_O || regname == Ctrl_P) {
7355 /* Get a third key for literal register insertion */
7356 literally = regname;
7357 add_to_showcmd_c(literally);
7358 regname = plain_vgetc();
7359 LANGMAP_ADJUST(regname, TRUE);
7360 }
7361 --no_mapping;
7362
7363 /* Don't call u_sync() while typing the expression or giving an error
7364 * message for it. Only call it explicitly. */
7365 ++no_u_sync;
7366 if (regname == '=') {
7367 pos_T curpos = curwin->w_cursor;
7368
7369 // Sync undo when evaluating the expression calls setline() or
7370 // append(), so that it can be undone separately.
7371 u_sync_once = 2;
7372
7373 regname = get_expr_register();
7374
7375 // Cursor may be moved back a column.
7376 curwin->w_cursor = curpos;
7377 check_cursor();
7378 }
7379 if (regname == NUL || !valid_yank_reg(regname, false)) {
7380 vim_beep(BO_REG);
7381 need_redraw = true; // remove the '"'
7382 } else {
7383 if (literally == Ctrl_O || literally == Ctrl_P) {
7384 /* Append the command to the redo buffer. */
7385 AppendCharToRedobuff(Ctrl_R);
7386 AppendCharToRedobuff(literally);
7387 AppendCharToRedobuff(regname);
7388
7389 do_put(regname, NULL, BACKWARD, 1,
7390 (literally == Ctrl_P ? PUT_FIXINDENT : 0) | PUT_CURSEND);
7391 } else if (insert_reg(regname, literally) == FAIL) {
7392 vim_beep(BO_REG);
7393 need_redraw = true; // remove the '"'
7394 } else if (stop_insert_mode) {
7395 // When the '=' register was used and a function was invoked that
7396 // did ":stopinsert" then stuff_empty() returns FALSE but we won't
7397 // insert anything, need to remove the '"'
7398 need_redraw = true;
7399 }
7400 }
7401 --no_u_sync;
7402 if (u_sync_once == 1)
7403 ins_need_undo = TRUE;
7404 u_sync_once = 0;
7405 clear_showcmd();
7406
7407 /* If the inserted register is empty, we need to remove the '"' */
7408 if (need_redraw || stuff_empty())
7409 edit_unputchar();
7410
7411 /* Disallow starting Visual mode here, would get a weird mode. */
7412 if (!vis_active && VIsual_active)
7413 end_visual_mode();
7414}
7415
7416/*
7417 * CTRL-G commands in Insert mode.
7418 */
7419static void ins_ctrl_g(void)
7420{
7421 int c;
7422
7423 /* Right after CTRL-X the cursor will be after the ruler. */
7424 setcursor();
7425
7426 /*
7427 * Don't map the second key. This also prevents the mode message to be
7428 * deleted when ESC is hit.
7429 */
7430 ++no_mapping;
7431 c = plain_vgetc();
7432 --no_mapping;
7433 switch (c) {
7434 /* CTRL-G k and CTRL-G <Up>: cursor up to Insstart.col */
7435 case K_UP:
7436 case Ctrl_K:
7437 case 'k': ins_up(TRUE);
7438 break;
7439
7440 /* CTRL-G j and CTRL-G <Down>: cursor down to Insstart.col */
7441 case K_DOWN:
7442 case Ctrl_J:
7443 case 'j': ins_down(TRUE);
7444 break;
7445
7446 /* CTRL-G u: start new undoable edit */
7447 case 'u': u_sync(TRUE);
7448 ins_need_undo = TRUE;
7449
7450 /* Need to reset Insstart, esp. because a BS that joins
7451 * a line to the previous one must save for undo. */
7452 update_Insstart_orig = false;
7453 Insstart = curwin->w_cursor;
7454 break;
7455
7456 // CTRL-G U: do not break undo with the next char.
7457 case 'U':
7458 // Allow one left/right cursor movement with the next char,
7459 // without breaking undo.
7460 dont_sync_undo = kNone;
7461 break;
7462
7463 /* Unknown CTRL-G command, reserved for future expansion. */
7464 default: vim_beep(BO_CTRLG);
7465 }
7466}
7467
7468/*
7469 * CTRL-^ in Insert mode.
7470 */
7471static void ins_ctrl_hat(void)
7472{
7473 if (map_to_exists_mode("", LANGMAP, false)) {
7474 // ":lmap" mappings exists, Toggle use of ":lmap" mappings.
7475 if (State & LANGMAP) {
7476 curbuf->b_p_iminsert = B_IMODE_NONE;
7477 State &= ~LANGMAP;
7478 } else {
7479 curbuf->b_p_iminsert = B_IMODE_LMAP;
7480 State |= LANGMAP;
7481 }
7482 }
7483 set_iminsert_global();
7484 showmode();
7485 /* Show/unshow value of 'keymap' in status lines. */
7486 status_redraw_curbuf();
7487}
7488
7489/// Handle ESC in insert mode.
7490///
7491/// @param[in,out] count repeat count of the insert command
7492/// @param cmdchar command that started the insert
7493/// @param nomove when true, don't move the cursor
7494///
7495/// @return true when leaving insert mode, false when repeating the insert.
7496static bool ins_esc(long *count, int cmdchar, bool nomove)
7497 FUNC_ATTR_NONNULL_ARG(1)
7498{
7499 static bool disabled_redraw = false;
7500
7501 check_spell_redraw();
7502
7503 int temp = curwin->w_cursor.col;
7504 if (disabled_redraw) {
7505 RedrawingDisabled--;
7506 disabled_redraw = false;
7507 }
7508 if (!arrow_used) {
7509 // Don't append the ESC for "r<CR>" and "grx".
7510 // When 'insertmode' is set only CTRL-L stops Insert mode. Needed for
7511 // when "count" is non-zero.
7512 if (cmdchar != 'r' && cmdchar != 'v') {
7513 AppendToRedobuff(p_im ? "\014" : ESC_STR);
7514 }
7515
7516 /*
7517 * Repeating insert may take a long time. Check for
7518 * interrupt now and then.
7519 */
7520 if (*count > 0) {
7521 line_breakcheck();
7522 if (got_int)
7523 *count = 0;
7524 }
7525
7526 if (--*count > 0) { /* repeat what was typed */
7527 /* Vi repeats the insert without replacing characters. */
7528 if (vim_strchr(p_cpo, CPO_REPLCNT) != NULL)
7529 State &= ~REPLACE_FLAG;
7530
7531 (void)start_redo_ins();
7532 if (cmdchar == 'r' || cmdchar == 'v') {
7533 stuffRedoReadbuff(ESC_STR); // No ESC in redo buffer
7534 }
7535 RedrawingDisabled++;
7536 disabled_redraw = true;
7537 // Repeat the insert
7538 return false;
7539 }
7540 stop_insert(&curwin->w_cursor, TRUE, nomove);
7541 undisplay_dollar();
7542 }
7543
7544 /* When an autoindent was removed, curswant stays after the
7545 * indent */
7546 if (restart_edit == NUL && (colnr_T)temp == curwin->w_cursor.col)
7547 curwin->w_set_curswant = TRUE;
7548
7549 /* Remember the last Insert position in the '^ mark. */
7550 if (!cmdmod.keepjumps) {
7551 RESET_FMARK(&curbuf->b_last_insert, curwin->w_cursor, curbuf->b_fnum);
7552 }
7553
7554 /*
7555 * The cursor should end up on the last inserted character.
7556 * Don't do it for CTRL-O, unless past the end of the line.
7557 */
7558 if (!nomove
7559 && (curwin->w_cursor.col != 0
7560 || curwin->w_cursor.coladd > 0
7561 )
7562 && (restart_edit == NUL
7563 || (gchar_cursor() == NUL
7564 && !VIsual_active
7565 ))
7566 && !revins_on
7567 ) {
7568 if (curwin->w_cursor.coladd > 0 || ve_flags == VE_ALL) {
7569 oneleft();
7570 if (restart_edit != NUL)
7571 ++curwin->w_cursor.coladd;
7572 } else {
7573 --curwin->w_cursor.col;
7574 /* Correct cursor for multi-byte character. */
7575 if (has_mbyte)
7576 mb_adjust_cursor();
7577 }
7578 }
7579
7580
7581 State = NORMAL;
7582 /* need to position cursor again (e.g. when on a TAB ) */
7583 changed_cline_bef_curs();
7584
7585 setmouse();
7586 ui_cursor_shape(); /* may show different cursor shape */
7587
7588 // When recording or for CTRL-O, need to display the new mode.
7589 // Otherwise remove the mode message.
7590 if (reg_recording != 0 || restart_edit != NUL) {
7591 showmode();
7592 } else if (p_smd) {
7593 MSG("");
7594 }
7595 // Exit Insert mode
7596 return true;
7597}
7598
7599/*
7600 * Toggle language: hkmap and revins_on.
7601 * Move to end of reverse inserted text.
7602 */
7603static void ins_ctrl_(void)
7604{
7605 if (revins_on && revins_chars && revins_scol >= 0) {
7606 while (gchar_cursor() != NUL && revins_chars--)
7607 ++curwin->w_cursor.col;
7608 }
7609 p_ri = !p_ri;
7610 revins_on = (State == INSERT && p_ri);
7611 if (revins_on) {
7612 revins_scol = curwin->w_cursor.col;
7613 revins_legal++;
7614 revins_chars = 0;
7615 undisplay_dollar();
7616 } else
7617 revins_scol = -1;
7618 p_hkmap = curwin->w_p_rl ^ p_ri; // be consistent!
7619 showmode();
7620}
7621
7622/// If 'keymodel' contains "startsel", may start selection.
7623///
7624/// @param c character to check
7625//
7626/// @return true when a CTRL-O and other keys stuffed.
7627static bool ins_start_select(int c)
7628 FUNC_ATTR_WARN_UNUSED_RESULT
7629{
7630 if (!km_startsel) {
7631 return false;
7632 }
7633 switch (c) {
7634 case K_KHOME:
7635 case K_KEND:
7636 case K_PAGEUP:
7637 case K_KPAGEUP:
7638 case K_PAGEDOWN:
7639 case K_KPAGEDOWN:
7640 if (!(mod_mask & MOD_MASK_SHIFT))
7641 break;
7642 FALLTHROUGH;
7643 case K_S_LEFT:
7644 case K_S_RIGHT:
7645 case K_S_UP:
7646 case K_S_DOWN:
7647 case K_S_END:
7648 case K_S_HOME:
7649 // Start selection right away, the cursor can move with
7650 // CTRL-O when beyond the end of the line.
7651 start_selection();
7652
7653 // Execute the key in (insert) Select mode.
7654 stuffcharReadbuff(Ctrl_O);
7655 if (mod_mask) {
7656 const char buf[] = { (char)K_SPECIAL, (char)KS_MODIFIER,
7657 (char)(uint8_t)mod_mask, NUL };
7658 stuffReadbuff(buf);
7659 }
7660 stuffcharReadbuff(c);
7661 return true;
7662 }
7663 return false;
7664}
7665
7666/*
7667 * <Insert> key in Insert mode: toggle insert/replace mode.
7668 */
7669static void ins_insert(int replaceState)
7670{
7671 set_vim_var_string(VV_INSERTMODE, ((State & REPLACE_FLAG) ? "i" :
7672 replaceState == VREPLACE ? "v" :
7673 "r"), 1);
7674 ins_apply_autocmds(EVENT_INSERTCHANGE);
7675 if (State & REPLACE_FLAG) {
7676 State = INSERT | (State & LANGMAP);
7677 } else {
7678 State = replaceState | (State & LANGMAP);
7679 }
7680 AppendCharToRedobuff(K_INS);
7681 showmode();
7682 ui_cursor_shape(); /* may show different cursor shape */
7683}
7684
7685/*
7686 * Pressed CTRL-O in Insert mode.
7687 */
7688static void ins_ctrl_o(void)
7689{
7690 if (State & VREPLACE_FLAG)
7691 restart_edit = 'V';
7692 else if (State & REPLACE_FLAG)
7693 restart_edit = 'R';
7694 else
7695 restart_edit = 'I';
7696 if (virtual_active())
7697 ins_at_eol = FALSE; /* cursor always keeps its column */
7698 else
7699 ins_at_eol = (gchar_cursor() == NUL);
7700}
7701
7702/*
7703 * If the cursor is on an indent, ^T/^D insert/delete one
7704 * shiftwidth. Otherwise ^T/^D behave like a "<<" or ">>".
7705 * Always round the indent to 'shiftwidth', this is compatible
7706 * with vi. But vi only supports ^T and ^D after an
7707 * autoindent, we support it everywhere.
7708 */
7709static void ins_shift(int c, int lastc)
7710{
7711 if (stop_arrow() == FAIL)
7712 return;
7713 AppendCharToRedobuff(c);
7714
7715 /*
7716 * 0^D and ^^D: remove all indent.
7717 */
7718 if (c == Ctrl_D && (lastc == '0' || lastc == '^')
7719 && curwin->w_cursor.col > 0) {
7720 curwin->w_cursor.col--;
7721 (void)del_char(false); // delete the '^' or '0'
7722 // In Replace mode, restore the characters that '^' or '0' replaced.
7723 if (State & REPLACE_FLAG) {
7724 replace_pop_ins();
7725 }
7726 if (lastc == '^') {
7727 old_indent = get_indent(); // remember curr. indent
7728 }
7729 change_indent(INDENT_SET, 0, TRUE, 0, TRUE);
7730 } else
7731 change_indent(c == Ctrl_D ? INDENT_DEC : INDENT_INC, 0, TRUE, 0, TRUE);
7732
7733 if (did_ai && *skipwhite(get_cursor_line_ptr()) != NUL) {
7734 did_ai = false;
7735 }
7736 did_si = false;
7737 can_si = false;
7738 can_si_back = false;
7739 can_cindent = false; // no cindenting after ^D or ^T
7740}
7741
7742static void ins_del(void)
7743{
7744 if (stop_arrow() == FAIL) {
7745 return;
7746 }
7747 if (gchar_cursor() == NUL) { // delete newline
7748 const int temp = curwin->w_cursor.col;
7749 if (!can_bs(BS_EOL) // only if "eol" included
7750 || do_join(2, false, true, false, false) == FAIL) {
7751 vim_beep(BO_BS);
7752 } else {
7753 curwin->w_cursor.col = temp;
7754 // Adjust orig_line_count in case more lines have been deleted than
7755 // have been added. That makes sure, that open_line() later
7756 // can access all buffer lines correctly
7757 if (State & VREPLACE_FLAG
7758 && orig_line_count > curbuf->b_ml.ml_line_count) {
7759 orig_line_count = curbuf->b_ml.ml_line_count;
7760 }
7761 }
7762 } else if (del_char(false) == FAIL) { // delete char under cursor
7763 vim_beep(BO_BS);
7764 }
7765 did_ai = false;
7766 did_si = false;
7767 can_si = false;
7768 can_si_back = false;
7769 AppendCharToRedobuff(K_DEL);
7770}
7771
7772
7773/*
7774 * Delete one character for ins_bs().
7775 */
7776static void ins_bs_one(colnr_T *vcolp)
7777{
7778 dec_cursor();
7779 getvcol(curwin, &curwin->w_cursor, vcolp, NULL, NULL);
7780 if (State & REPLACE_FLAG) {
7781 /* Don't delete characters before the insert point when in
7782 * Replace mode */
7783 if (curwin->w_cursor.lnum != Insstart.lnum
7784 || curwin->w_cursor.col >= Insstart.col)
7785 replace_do_bs(-1);
7786 } else {
7787 (void)del_char(false);
7788 }
7789}
7790
7791/// Handle Backspace, delete-word and delete-line in Insert mode.
7792///
7793/// @param c charcter that was typed
7794/// @param mode backspace mode to use
7795/// @param[in,out] inserted_space_p whether a space was the last
7796// character inserted
7797///
7798/// @return true when backspace was actually used.
7799static bool ins_bs(int c, int mode, int *inserted_space_p)
7800 FUNC_ATTR_NONNULL_ARG(3)
7801{
7802 linenr_T lnum;
7803 int cc;
7804 int temp = 0; /* init for GCC */
7805 colnr_T save_col;
7806 colnr_T mincol;
7807 bool did_backspace = false;
7808 int in_indent;
7809 int oldState;
7810 int cpc[MAX_MCO]; /* composing characters */
7811
7812 // can't delete anything in an empty file
7813 // can't backup past first character in buffer
7814 // can't backup past starting point unless 'backspace' > 1
7815 // can backup to a previous line if 'backspace' == 0
7816 if (BUFEMPTY()
7817 || (!revins_on
7818 && ((curwin->w_cursor.lnum == 1 && curwin->w_cursor.col == 0)
7819 || (!can_bs(BS_START)
7820 && (arrow_used
7821 || (curwin->w_cursor.lnum == Insstart_orig.lnum
7822 && curwin->w_cursor.col <= Insstart_orig.col)))
7823 || (!can_bs(BS_INDENT) && !arrow_used && ai_col > 0
7824 && curwin->w_cursor.col <= ai_col)
7825 || (!can_bs(BS_EOL) && curwin->w_cursor.col == 0)))) {
7826 vim_beep(BO_BS);
7827 return false;
7828 }
7829
7830 if (stop_arrow() == FAIL) {
7831 return false;
7832 }
7833 in_indent = inindent(0);
7834 if (in_indent) {
7835 can_cindent = false;
7836 }
7837 end_comment_pending = NUL; // After BS, don't auto-end comment
7838 if (revins_on) { // put cursor after last inserted char
7839 inc_cursor();
7840 }
7841 // Virtualedit:
7842 // BACKSPACE_CHAR eats a virtual space
7843 // BACKSPACE_WORD eats all coladd
7844 // BACKSPACE_LINE eats all coladd and keeps going
7845 if (curwin->w_cursor.coladd > 0) {
7846 if (mode == BACKSPACE_CHAR) {
7847 curwin->w_cursor.coladd--;
7848 return true;
7849 }
7850 if (mode == BACKSPACE_WORD) {
7851 curwin->w_cursor.coladd = 0;
7852 return true;
7853 }
7854 curwin->w_cursor.coladd = 0;
7855 }
7856
7857 // Delete newline!
7858 if (curwin->w_cursor.col == 0) {
7859 lnum = Insstart.lnum;
7860 if (curwin->w_cursor.lnum == lnum || revins_on) {
7861 if (u_save((linenr_T)(curwin->w_cursor.lnum - 2),
7862 (linenr_T)(curwin->w_cursor.lnum + 1)) == FAIL) {
7863 return false;
7864 }
7865 Insstart.lnum--;
7866 Insstart.col = (colnr_T)STRLEN(ml_get(Insstart.lnum));
7867 }
7868 /*
7869 * In replace mode:
7870 * cc < 0: NL was inserted, delete it
7871 * cc >= 0: NL was replaced, put original characters back
7872 */
7873 cc = -1;
7874 if (State & REPLACE_FLAG)
7875 cc = replace_pop(); /* returns -1 if NL was inserted */
7876 /*
7877 * In replace mode, in the line we started replacing, we only move the
7878 * cursor.
7879 */
7880 if ((State & REPLACE_FLAG) && curwin->w_cursor.lnum <= lnum) {
7881 dec_cursor();
7882 } else {
7883 if (!(State & VREPLACE_FLAG)
7884 || curwin->w_cursor.lnum > orig_line_count) {
7885 temp = gchar_cursor(); /* remember current char */
7886 --curwin->w_cursor.lnum;
7887
7888 /* When "aw" is in 'formatoptions' we must delete the space at
7889 * the end of the line, otherwise the line will be broken
7890 * again when auto-formatting. */
7891 if (has_format_option(FO_AUTO)
7892 && has_format_option(FO_WHITE_PAR)) {
7893 char_u *ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum,
7894 TRUE);
7895 int len;
7896
7897 len = (int)STRLEN(ptr);
7898 if (len > 0 && ptr[len - 1] == ' ')
7899 ptr[len - 1] = NUL;
7900 }
7901
7902 do_join(2, FALSE, FALSE, FALSE, false);
7903 if (temp == NUL && gchar_cursor() != NUL)
7904 inc_cursor();
7905 } else
7906 dec_cursor();
7907
7908 /*
7909 * In REPLACE mode we have to put back the text that was replaced
7910 * by the NL. On the replace stack is first a NUL-terminated
7911 * sequence of characters that were deleted and then the
7912 * characters that NL replaced.
7913 */
7914 if (State & REPLACE_FLAG) {
7915 /*
7916 * Do the next ins_char() in NORMAL state, to
7917 * prevent ins_char() from replacing characters and
7918 * avoiding showmatch().
7919 */
7920 oldState = State;
7921 State = NORMAL;
7922 /*
7923 * restore characters (blanks) deleted after cursor
7924 */
7925 while (cc > 0) {
7926 save_col = curwin->w_cursor.col;
7927 mb_replace_pop_ins(cc);
7928 curwin->w_cursor.col = save_col;
7929 cc = replace_pop();
7930 }
7931 /* restore the characters that NL replaced */
7932 replace_pop_ins();
7933 State = oldState;
7934 }
7935 }
7936 did_ai = false;
7937 } else {
7938 /*
7939 * Delete character(s) before the cursor.
7940 */
7941 if (revins_on) /* put cursor on last inserted char */
7942 dec_cursor();
7943 mincol = 0;
7944 /* keep indent */
7945 if (mode == BACKSPACE_LINE
7946 && (curbuf->b_p_ai
7947 || cindent_on()
7948 )
7949 && !revins_on
7950 ) {
7951 save_col = curwin->w_cursor.col;
7952 beginline(BL_WHITE);
7953 if (curwin->w_cursor.col < save_col)
7954 mincol = curwin->w_cursor.col;
7955 curwin->w_cursor.col = save_col;
7956 }
7957
7958 /*
7959 * Handle deleting one 'shiftwidth' or 'softtabstop'.
7960 */
7961 if ( mode == BACKSPACE_CHAR
7962 && ((p_sta && in_indent)
7963 || (get_sts_value() != 0
7964 && curwin->w_cursor.col > 0
7965 && (*(get_cursor_pos_ptr() - 1) == TAB
7966 || (*(get_cursor_pos_ptr() - 1) == ' '
7967 && (!*inserted_space_p
7968 || arrow_used)))))) {
7969 int ts;
7970 colnr_T vcol;
7971 colnr_T want_vcol;
7972 colnr_T start_vcol;
7973
7974 *inserted_space_p = FALSE;
7975 if (p_sta && in_indent)
7976 ts = get_sw_value(curbuf);
7977 else
7978 ts = get_sts_value();
7979 /* Compute the virtual column where we want to be. Since
7980 * 'showbreak' may get in the way, need to get the last column of
7981 * the previous character. */
7982 getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL);
7983 start_vcol = vcol;
7984 dec_cursor();
7985 getvcol(curwin, &curwin->w_cursor, NULL, NULL, &want_vcol);
7986 inc_cursor();
7987 want_vcol = (want_vcol / ts) * ts;
7988
7989 /* delete characters until we are at or before want_vcol */
7990 while (vcol > want_vcol
7991 && (cc = *(get_cursor_pos_ptr() - 1), ascii_iswhite(cc)))
7992 ins_bs_one(&vcol);
7993
7994 /* insert extra spaces until we are at want_vcol */
7995 while (vcol < want_vcol) {
7996 /* Remember the first char we inserted */
7997 if (curwin->w_cursor.lnum == Insstart_orig.lnum
7998 && curwin->w_cursor.col < Insstart_orig.col) {
7999 Insstart_orig.col = curwin->w_cursor.col;
8000 }
8001
8002 if (State & VREPLACE_FLAG)
8003 ins_char(' ');
8004 else {
8005 ins_str((char_u *)" ");
8006 if ((State & REPLACE_FLAG))
8007 replace_push(NUL);
8008 }
8009 getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL);
8010 }
8011
8012 /* If we are now back where we started delete one character. Can
8013 * happen when using 'sts' and 'linebreak'. */
8014 if (vcol >= start_vcol)
8015 ins_bs_one(&vcol);
8016
8017 // Delete upto starting point, start of line or previous word.
8018 } else {
8019 int cclass = 0, prev_cclass = 0;
8020
8021 if (has_mbyte) {
8022 cclass = mb_get_class(get_cursor_pos_ptr());
8023 }
8024 do {
8025 if (!revins_on) { // put cursor on char to be deleted
8026 dec_cursor();
8027 }
8028 cc = gchar_cursor();
8029 // look multi-byte character class
8030 if (has_mbyte) {
8031 prev_cclass = cclass;
8032 cclass = mb_get_class(get_cursor_pos_ptr());
8033 }
8034 if (mode == BACKSPACE_WORD && !ascii_isspace(cc)) { // start of word?
8035 mode = BACKSPACE_WORD_NOT_SPACE;
8036 temp = vim_iswordc(cc);
8037 } else if (mode == BACKSPACE_WORD_NOT_SPACE
8038 && ((ascii_isspace(cc) || vim_iswordc(cc) != temp)
8039 || prev_cclass != cclass)) { // end of word?
8040 if (!revins_on) {
8041 inc_cursor();
8042 } else if (State & REPLACE_FLAG) {
8043 dec_cursor();
8044 }
8045 break;
8046 }
8047 if (State & REPLACE_FLAG)
8048 replace_do_bs(-1);
8049 else {
8050 const bool l_enc_utf8 = enc_utf8;
8051 const int l_p_deco = p_deco;
8052 if (l_enc_utf8 && l_p_deco) {
8053 (void)utfc_ptr2char(get_cursor_pos_ptr(), cpc);
8054 }
8055 (void)del_char(false);
8056 // If there are combining characters and 'delcombine' is set
8057 // move the cursor back. Don't back up before the base
8058 // character.
8059 if (l_enc_utf8 && l_p_deco && cpc[0] != NUL) {
8060 inc_cursor();
8061 }
8062 if (revins_chars) {
8063 revins_chars--;
8064 revins_legal++;
8065 }
8066 if (revins_on && gchar_cursor() == NUL)
8067 break;
8068 }
8069 // Just a single backspace?:
8070 if (mode == BACKSPACE_CHAR) {
8071 break;
8072 }
8073 } while (revins_on
8074 || (curwin->w_cursor.col > mincol
8075 && (curwin->w_cursor.lnum != Insstart_orig.lnum
8076 || curwin->w_cursor.col != Insstart_orig.col)));
8077 }
8078 did_backspace = true;
8079 }
8080 did_si = false;
8081 can_si = false;
8082 can_si_back = false;
8083 if (curwin->w_cursor.col <= 1) {
8084 did_ai = false;
8085 }
8086 // It's a little strange to put backspaces into the redo
8087 // buffer, but it makes auto-indent a lot easier to deal
8088 // with.
8089 AppendCharToRedobuff(c);
8090
8091 /* If deleted before the insertion point, adjust it */
8092 if (curwin->w_cursor.lnum == Insstart_orig.lnum
8093 && curwin->w_cursor.col < Insstart_orig.col) {
8094 Insstart_orig.col = curwin->w_cursor.col;
8095 }
8096
8097 /* vi behaviour: the cursor moves backward but the character that
8098 * was there remains visible
8099 * Vim behaviour: the cursor moves backward and the character that
8100 * was there is erased from the screen.
8101 * We can emulate the vi behaviour by pretending there is a dollar
8102 * displayed even when there isn't.
8103 * --pkv Sun Jan 19 01:56:40 EST 2003 */
8104 if (vim_strchr(p_cpo, CPO_BACKSPACE) != NULL && dollar_vcol == -1)
8105 dollar_vcol = curwin->w_virtcol;
8106
8107 // When deleting a char the cursor line must never be in a closed fold.
8108 // E.g., when 'foldmethod' is indent and deleting the first non-white
8109 // char before a Tab.
8110 if (did_backspace) {
8111 foldOpenCursor();
8112 }
8113 return did_backspace;
8114}
8115
8116static void ins_mouse(int c)
8117{
8118 pos_T tpos;
8119 win_T *old_curwin = curwin;
8120
8121 if (!mouse_has(MOUSE_INSERT))
8122 return;
8123
8124 undisplay_dollar();
8125 tpos = curwin->w_cursor;
8126 if (do_mouse(NULL, c, BACKWARD, 1, 0)) {
8127 win_T *new_curwin = curwin;
8128
8129 if (curwin != old_curwin && win_valid(old_curwin)) {
8130 /* Mouse took us to another window. We need to go back to the
8131 * previous one to stop insert there properly. */
8132 curwin = old_curwin;
8133 curbuf = curwin->w_buffer;
8134 }
8135 start_arrow(curwin == old_curwin ? &tpos : NULL);
8136 if (curwin != new_curwin && win_valid(new_curwin)) {
8137 curwin = new_curwin;
8138 curbuf = curwin->w_buffer;
8139 }
8140 can_cindent = true;
8141 }
8142
8143 /* redraw status lines (in case another window became active) */
8144 redraw_statuslines();
8145}
8146
8147static void ins_mousescroll(int dir)
8148{
8149 win_T *const old_curwin = curwin;
8150 pos_T tpos = curwin->w_cursor;
8151
8152 if (mouse_row >= 0 && mouse_col >= 0) {
8153 int row = mouse_row, col = mouse_col, grid = mouse_grid;
8154
8155 // find the window at the pointer coordinates
8156 win_T *wp = mouse_find_win(&grid, &row, &col);
8157 if (wp == NULL) {
8158 return;
8159 }
8160 curwin = wp;
8161 curbuf = curwin->w_buffer;
8162 }
8163 if (curwin == old_curwin)
8164 undisplay_dollar();
8165
8166 /* Don't scroll the window in which completion is being done. */
8167 if (!pum_visible()
8168 || curwin != old_curwin
8169 ) {
8170 if (dir == MSCR_DOWN || dir == MSCR_UP) {
8171 if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL))
8172 scroll_redraw(dir,
8173 (long)(curwin->w_botline - curwin->w_topline));
8174 else
8175 scroll_redraw(dir, 3L);
8176 } else {
8177 mouse_scroll_horiz(dir);
8178 }
8179 }
8180
8181 curwin->w_redr_status = TRUE;
8182
8183 curwin = old_curwin;
8184 curbuf = curwin->w_buffer;
8185
8186 if (!equalpos(curwin->w_cursor, tpos)) {
8187 start_arrow(&tpos);
8188 can_cindent = true;
8189 }
8190}
8191
8192
8193
8194static void ins_left(void)
8195{
8196 pos_T tpos;
8197 const bool end_change = dont_sync_undo == kFalse; // end undoable change
8198
8199 if ((fdo_flags & FDO_HOR) && KeyTyped)
8200 foldOpenCursor();
8201 undisplay_dollar();
8202 tpos = curwin->w_cursor;
8203 if (oneleft() == OK) {
8204 start_arrow_with_change(&tpos, end_change);
8205 if (!end_change) {
8206 AppendCharToRedobuff(K_LEFT);
8207 }
8208 /* If exit reversed string, position is fixed */
8209 if (revins_scol != -1 && (int)curwin->w_cursor.col >= revins_scol)
8210 revins_legal++;
8211 revins_chars++;
8212 } else if (vim_strchr(p_ww, '[') != NULL && curwin->w_cursor.lnum > 1) {
8213 // if 'whichwrap' set for cursor in insert mode may go to previous line.
8214 // always break undo when moving upwards/downwards, else undo may break
8215 start_arrow(&tpos);
8216 --(curwin->w_cursor.lnum);
8217 coladvance((colnr_T)MAXCOL);
8218 curwin->w_set_curswant = true; // so we stay at the end
8219 } else {
8220 vim_beep(BO_CRSR);
8221 }
8222 dont_sync_undo = kFalse;
8223}
8224
8225static void ins_home(int c)
8226{
8227 pos_T tpos;
8228
8229 if ((fdo_flags & FDO_HOR) && KeyTyped)
8230 foldOpenCursor();
8231 undisplay_dollar();
8232 tpos = curwin->w_cursor;
8233 if (c == K_C_HOME)
8234 curwin->w_cursor.lnum = 1;
8235 curwin->w_cursor.col = 0;
8236 curwin->w_cursor.coladd = 0;
8237 curwin->w_curswant = 0;
8238 start_arrow(&tpos);
8239}
8240
8241static void ins_end(int c)
8242{
8243 pos_T tpos;
8244
8245 if ((fdo_flags & FDO_HOR) && KeyTyped)
8246 foldOpenCursor();
8247 undisplay_dollar();
8248 tpos = curwin->w_cursor;
8249 if (c == K_C_END)
8250 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
8251 coladvance((colnr_T)MAXCOL);
8252 curwin->w_curswant = MAXCOL;
8253
8254 start_arrow(&tpos);
8255}
8256
8257static void ins_s_left(void)
8258{
8259 const bool end_change = dont_sync_undo == kFalse; // end undoable change
8260 if ((fdo_flags & FDO_HOR) && KeyTyped) {
8261 foldOpenCursor();
8262 }
8263 undisplay_dollar();
8264 if (curwin->w_cursor.lnum > 1 || curwin->w_cursor.col > 0) {
8265 start_arrow_with_change(&curwin->w_cursor, end_change);
8266 if (!end_change) {
8267 AppendCharToRedobuff(K_S_LEFT);
8268 }
8269 (void)bck_word(1L, false, false);
8270 curwin->w_set_curswant = true;
8271 } else {
8272 vim_beep(BO_CRSR);
8273 }
8274 dont_sync_undo = kFalse;
8275}
8276
8277/// @param end_change end undoable change
8278static void ins_right(void)
8279{
8280 const bool end_change = dont_sync_undo == kFalse; // end undoable change
8281 if ((fdo_flags & FDO_HOR) && KeyTyped) {
8282 foldOpenCursor();
8283 }
8284 undisplay_dollar();
8285 if (gchar_cursor() != NUL || virtual_active()) {
8286 start_arrow_with_change(&curwin->w_cursor, end_change);
8287 if (!end_change) {
8288 AppendCharToRedobuff(K_RIGHT);
8289 }
8290 curwin->w_set_curswant = true;
8291 if (virtual_active())
8292 oneright();
8293 else {
8294 if (has_mbyte)
8295 curwin->w_cursor.col += (*mb_ptr2len)(get_cursor_pos_ptr());
8296 else
8297 ++curwin->w_cursor.col;
8298 }
8299
8300 revins_legal++;
8301 if (revins_chars)
8302 revins_chars--;
8303 }
8304 /* if 'whichwrap' set for cursor in insert mode, may move the
8305 * cursor to the next line */
8306 else if (vim_strchr(p_ww, ']') != NULL
8307 && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) {
8308 start_arrow(&curwin->w_cursor);
8309 curwin->w_set_curswant = TRUE;
8310 ++curwin->w_cursor.lnum;
8311 curwin->w_cursor.col = 0;
8312 } else {
8313 vim_beep(BO_CRSR);
8314 }
8315 dont_sync_undo = kFalse;
8316}
8317
8318static void ins_s_right(void)
8319{
8320 const bool end_change = dont_sync_undo == kFalse; // end undoable change
8321 if ((fdo_flags & FDO_HOR) && KeyTyped) {
8322 foldOpenCursor();
8323 }
8324 undisplay_dollar();
8325 if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count
8326 || gchar_cursor() != NUL) {
8327 start_arrow_with_change(&curwin->w_cursor, end_change);
8328 if (!end_change) {
8329 AppendCharToRedobuff(K_S_RIGHT);
8330 }
8331 (void)fwd_word(1L, false, 0);
8332 curwin->w_set_curswant = true;
8333 } else {
8334 vim_beep(BO_CRSR);
8335 }
8336 dont_sync_undo = kFalse;
8337}
8338
8339static void
8340ins_up (
8341 int startcol /* when TRUE move to Insstart.col */
8342)
8343{
8344 pos_T tpos;
8345 linenr_T old_topline = curwin->w_topline;
8346 int old_topfill = curwin->w_topfill;
8347
8348 undisplay_dollar();
8349 tpos = curwin->w_cursor;
8350 if (cursor_up(1L, TRUE) == OK) {
8351 if (startcol)
8352 coladvance(getvcol_nolist(&Insstart));
8353 if (old_topline != curwin->w_topline
8354 || old_topfill != curwin->w_topfill
8355 )
8356 redraw_later(VALID);
8357 start_arrow(&tpos);
8358 can_cindent = true;
8359 } else {
8360 vim_beep(BO_CRSR);
8361 }
8362}
8363
8364static void ins_pageup(void)
8365{
8366 pos_T tpos;
8367
8368 undisplay_dollar();
8369
8370 if (mod_mask & MOD_MASK_CTRL) {
8371 /* <C-PageUp>: tab page back */
8372 if (first_tabpage->tp_next != NULL) {
8373 start_arrow(&curwin->w_cursor);
8374 goto_tabpage(-1);
8375 }
8376 return;
8377 }
8378
8379 tpos = curwin->w_cursor;
8380 if (onepage(BACKWARD, 1L) == OK) {
8381 start_arrow(&tpos);
8382 can_cindent = true;
8383 } else {
8384 vim_beep(BO_CRSR);
8385 }
8386}
8387
8388static void
8389ins_down (
8390 int startcol /* when TRUE move to Insstart.col */
8391)
8392{
8393 pos_T tpos;
8394 linenr_T old_topline = curwin->w_topline;
8395 int old_topfill = curwin->w_topfill;
8396
8397 undisplay_dollar();
8398 tpos = curwin->w_cursor;
8399 if (cursor_down(1L, TRUE) == OK) {
8400 if (startcol)
8401 coladvance(getvcol_nolist(&Insstart));
8402 if (old_topline != curwin->w_topline
8403 || old_topfill != curwin->w_topfill
8404 )
8405 redraw_later(VALID);
8406 start_arrow(&tpos);
8407 can_cindent = true;
8408 } else {
8409 vim_beep(BO_CRSR);
8410 }
8411}
8412
8413static void ins_pagedown(void)
8414{
8415 pos_T tpos;
8416
8417 undisplay_dollar();
8418
8419 if (mod_mask & MOD_MASK_CTRL) {
8420 /* <C-PageDown>: tab page forward */
8421 if (first_tabpage->tp_next != NULL) {
8422 start_arrow(&curwin->w_cursor);
8423 goto_tabpage(0);
8424 }
8425 return;
8426 }
8427
8428 tpos = curwin->w_cursor;
8429 if (onepage(FORWARD, 1L) == OK) {
8430 start_arrow(&tpos);
8431 can_cindent = true;
8432 } else {
8433 vim_beep(BO_CRSR);
8434 }
8435}
8436
8437/// Handle TAB in Insert or Replace mode.
8438///
8439/// @return true when the TAB needs to be inserted like a normal character.
8440static bool ins_tab(void)
8441 FUNC_ATTR_WARN_UNUSED_RESULT
8442{
8443 int i;
8444 int temp;
8445
8446 if (Insstart_blank_vcol == MAXCOL && curwin->w_cursor.lnum == Insstart.lnum) {
8447 Insstart_blank_vcol = get_nolist_virtcol();
8448 }
8449 if (echeck_abbr(TAB + ABBR_OFF)) {
8450 return false;
8451 }
8452
8453 int ind = inindent(0);
8454 if (ind) {
8455 can_cindent = false;
8456 }
8457
8458 // When nothing special, insert TAB like a normal character
8459 if (!curbuf->b_p_et
8460 && !(p_sta && ind && curbuf->b_p_ts != get_sw_value(curbuf))
8461 && get_sts_value() == 0) {
8462 return true;
8463 }
8464
8465 if (stop_arrow() == FAIL) {
8466 return true;
8467 }
8468
8469 did_ai = false;
8470 did_si = false;
8471 can_si = false;
8472 can_si_back = false;
8473 AppendToRedobuff("\t");
8474
8475 if (p_sta && ind) { // insert tab in indent, use "shiftwidth"
8476 temp = get_sw_value(curbuf);
8477 } else if (curbuf->b_p_sts != 0) { // use "softtabstop" when set
8478 temp = get_sts_value();
8479 } else { // otherwise use "tabstop"
8480 temp = (int)curbuf->b_p_ts;
8481 }
8482 temp -= get_nolist_virtcol() % temp;
8483
8484 /*
8485 * Insert the first space with ins_char(). It will delete one char in
8486 * replace mode. Insert the rest with ins_str(); it will not delete any
8487 * chars. For VREPLACE mode, we use ins_char() for all characters.
8488 */
8489 ins_char(' ');
8490 while (--temp > 0) {
8491 if (State & VREPLACE_FLAG)
8492 ins_char(' ');
8493 else {
8494 ins_str((char_u *)" ");
8495 if (State & REPLACE_FLAG) /* no char replaced */
8496 replace_push(NUL);
8497 }
8498 }
8499
8500 /*
8501 * When 'expandtab' not set: Replace spaces by TABs where possible.
8502 */
8503 if (!curbuf->b_p_et && (get_sts_value() || (p_sta && ind))) {
8504 char_u *ptr;
8505 char_u *saved_line = NULL; /* init for GCC */
8506 pos_T pos;
8507 pos_T fpos;
8508 pos_T *cursor;
8509 colnr_T want_vcol, vcol;
8510 int change_col = -1;
8511 int save_list = curwin->w_p_list;
8512
8513 /*
8514 * Get the current line. For VREPLACE mode, don't make real changes
8515 * yet, just work on a copy of the line.
8516 */
8517 if (State & VREPLACE_FLAG) {
8518 pos = curwin->w_cursor;
8519 cursor = &pos;
8520 saved_line = vim_strsave(get_cursor_line_ptr());
8521 ptr = saved_line + pos.col;
8522 } else {
8523 ptr = get_cursor_pos_ptr();
8524 cursor = &curwin->w_cursor;
8525 }
8526
8527 /* When 'L' is not in 'cpoptions' a tab always takes up 'ts' spaces. */
8528 if (vim_strchr(p_cpo, CPO_LISTWM) == NULL)
8529 curwin->w_p_list = FALSE;
8530
8531 /* Find first white before the cursor */
8532 fpos = curwin->w_cursor;
8533 while (fpos.col > 0 && ascii_iswhite(ptr[-1])) {
8534 --fpos.col;
8535 --ptr;
8536 }
8537
8538 /* In Replace mode, don't change characters before the insert point. */
8539 if ((State & REPLACE_FLAG)
8540 && fpos.lnum == Insstart.lnum
8541 && fpos.col < Insstart.col) {
8542 ptr += Insstart.col - fpos.col;
8543 fpos.col = Insstart.col;
8544 }
8545
8546 /* compute virtual column numbers of first white and cursor */
8547 getvcol(curwin, &fpos, &vcol, NULL, NULL);
8548 getvcol(curwin, cursor, &want_vcol, NULL, NULL);
8549
8550 /* Use as many TABs as possible. Beware of 'breakindent', 'showbreak'
8551 and 'linebreak' adding extra virtual columns. */
8552 while (ascii_iswhite(*ptr)) {
8553 i = lbr_chartabsize(NULL, (char_u *)"\t", vcol);
8554 if (vcol + i > want_vcol)
8555 break;
8556 if (*ptr != TAB) {
8557 *ptr = TAB;
8558 if (change_col < 0) {
8559 change_col = fpos.col; /* Column of first change */
8560 /* May have to adjust Insstart */
8561 if (fpos.lnum == Insstart.lnum && fpos.col < Insstart.col)
8562 Insstart.col = fpos.col;
8563 }
8564 }
8565 ++fpos.col;
8566 ++ptr;
8567 vcol += i;
8568 }
8569
8570 if (change_col >= 0) {
8571 int repl_off = 0;
8572 char_u *line = ptr;
8573
8574 /* Skip over the spaces we need. */
8575 while (vcol < want_vcol && *ptr == ' ') {
8576 vcol += lbr_chartabsize(line, ptr, vcol);
8577 ++ptr;
8578 ++repl_off;
8579 }
8580 if (vcol > want_vcol) {
8581 /* Must have a char with 'showbreak' just before it. */
8582 --ptr;
8583 --repl_off;
8584 }
8585 fpos.col += repl_off;
8586
8587 /* Delete following spaces. */
8588 i = cursor->col - fpos.col;
8589 if (i > 0) {
8590 STRMOVE(ptr, ptr + i);
8591 /* correct replace stack. */
8592 if ((State & REPLACE_FLAG)
8593 && !(State & VREPLACE_FLAG)
8594 )
8595 for (temp = i; --temp >= 0; )
8596 replace_join(repl_off);
8597 }
8598 cursor->col -= i;
8599
8600 /*
8601 * In VREPLACE mode, we haven't changed anything yet. Do it now by
8602 * backspacing over the changed spacing and then inserting the new
8603 * spacing.
8604 */
8605 if (State & VREPLACE_FLAG) {
8606 /* Backspace from real cursor to change_col */
8607 backspace_until_column(change_col);
8608
8609 /* Insert each char in saved_line from changed_col to
8610 * ptr-cursor */
8611 ins_bytes_len(saved_line + change_col,
8612 cursor->col - change_col);
8613 }
8614 }
8615
8616 if (State & VREPLACE_FLAG)
8617 xfree(saved_line);
8618 curwin->w_p_list = save_list;
8619 }
8620
8621 return false;
8622}
8623
8624/// Handle CR or NL in insert mode.
8625///
8626/// @return false when it can't undo.
8627static bool ins_eol(int c)
8628{
8629 if (echeck_abbr(c + ABBR_OFF)) {
8630 return true;
8631 }
8632 if (stop_arrow() == FAIL) {
8633 return false;
8634 }
8635 undisplay_dollar();
8636
8637 /*
8638 * Strange Vi behaviour: In Replace mode, typing a NL will not delete the
8639 * character under the cursor. Only push a NUL on the replace stack,
8640 * nothing to put back when the NL is deleted.
8641 */
8642 if ((State & REPLACE_FLAG)
8643 && !(State & VREPLACE_FLAG)
8644 )
8645 replace_push(NUL);
8646
8647 /*
8648 * In VREPLACE mode, a NL replaces the rest of the line, and starts
8649 * replacing the next line, so we push all of the characters left on the
8650 * line onto the replace stack. This is not done here though, it is done
8651 * in open_line().
8652 */
8653
8654 /* Put cursor on NUL if on the last char and coladd is 1 (happens after
8655 * CTRL-O). */
8656 if (virtual_active() && curwin->w_cursor.coladd > 0)
8657 coladvance(getviscol());
8658
8659 // NL in reverse insert will always start in the end of current line.
8660 if (revins_on) {
8661 curwin->w_cursor.col += (colnr_T)STRLEN(get_cursor_pos_ptr());
8662 }
8663
8664 AppendToRedobuff(NL_STR);
8665 bool i = open_line(FORWARD,
8666 has_format_option(FO_RET_COMS) ? OPENLINE_DO_COM : 0,
8667 old_indent);
8668 old_indent = 0;
8669 can_cindent = true;
8670 // When inserting a line the cursor line must never be in a closed fold.
8671 foldOpenCursor();
8672
8673 return i;
8674}
8675
8676/*
8677 * Handle digraph in insert mode.
8678 * Returns character still to be inserted, or NUL when nothing remaining to be
8679 * done.
8680 */
8681static int ins_digraph(void)
8682{
8683 int c;
8684 int cc;
8685 int did_putchar = FALSE;
8686
8687 pc_status = PC_STATUS_UNSET;
8688 if (redrawing() && !char_avail()) {
8689 /* may need to redraw when no more chars available now */
8690 ins_redraw(FALSE);
8691
8692 edit_putchar('?', TRUE);
8693 did_putchar = TRUE;
8694 add_to_showcmd_c(Ctrl_K);
8695 }
8696
8697
8698 // don't map the digraph chars. This also prevents the
8699 // mode message to be deleted when ESC is hit
8700 no_mapping++;
8701 c = plain_vgetc();
8702 no_mapping--;
8703 if (did_putchar) {
8704 // when the line fits in 'columns' the '?' is at the start of the next
8705 // line and will not be removed by the redraw
8706 edit_unputchar();
8707 }
8708
8709 if (IS_SPECIAL(c) || mod_mask) { /* special key */
8710 clear_showcmd();
8711 insert_special(c, TRUE, FALSE);
8712 return NUL;
8713 }
8714 if (c != ESC) {
8715 did_putchar = FALSE;
8716 if (redrawing() && !char_avail()) {
8717 /* may need to redraw when no more chars available now */
8718 ins_redraw(FALSE);
8719
8720 if (char2cells(c) == 1) {
8721 ins_redraw(FALSE);
8722 edit_putchar(c, TRUE);
8723 did_putchar = TRUE;
8724 }
8725 add_to_showcmd_c(c);
8726 }
8727 no_mapping++;
8728 cc = plain_vgetc();
8729 no_mapping--;
8730 if (did_putchar) {
8731 // when the line fits in 'columns' the '?' is at the start of the
8732 // next line and will not be removed by a redraw
8733 edit_unputchar();
8734 }
8735 if (cc != ESC) {
8736 AppendToRedobuff(CTRL_V_STR);
8737 c = getdigraph(c, cc, true);
8738 clear_showcmd();
8739 return c;
8740 }
8741 }
8742 clear_showcmd();
8743 return NUL;
8744}
8745
8746/*
8747 * Handle CTRL-E and CTRL-Y in Insert mode: copy char from other line.
8748 * Returns the char to be inserted, or NUL if none found.
8749 */
8750int ins_copychar(linenr_T lnum)
8751{
8752 int c;
8753 int temp;
8754 char_u *ptr, *prev_ptr;
8755 char_u *line;
8756
8757 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count) {
8758 vim_beep(BO_COPY);
8759 return NUL;
8760 }
8761
8762 /* try to advance to the cursor column */
8763 temp = 0;
8764 line = ptr = ml_get(lnum);
8765 prev_ptr = ptr;
8766 validate_virtcol();
8767 while ((colnr_T)temp < curwin->w_virtcol && *ptr != NUL) {
8768 prev_ptr = ptr;
8769 temp += lbr_chartabsize_adv(line, &ptr, (colnr_T)temp);
8770 }
8771 if ((colnr_T)temp > curwin->w_virtcol)
8772 ptr = prev_ptr;
8773
8774 c = utf_ptr2char(ptr);
8775 if (c == NUL) {
8776 vim_beep(BO_COPY);
8777 }
8778 return c;
8779}
8780
8781/*
8782 * CTRL-Y or CTRL-E typed in Insert mode.
8783 */
8784static int ins_ctrl_ey(int tc)
8785{
8786 int c = tc;
8787
8788 if (ctrl_x_mode == CTRL_X_SCROLL) {
8789 if (c == Ctrl_Y)
8790 scrolldown_clamp();
8791 else
8792 scrollup_clamp();
8793 redraw_later(VALID);
8794 } else {
8795 c = ins_copychar(curwin->w_cursor.lnum + (c == Ctrl_Y ? -1 : 1));
8796 if (c != NUL) {
8797 long tw_save;
8798
8799 // The character must be taken literally, insert like it
8800 // was typed after a CTRL-V, and pretend 'textwidth'
8801 // wasn't set. Digits, 'o' and 'x' are special after a
8802 // CTRL-V, don't use it for these.
8803 if (c < 256 && !isalnum(c)) {
8804 AppendToRedobuff(CTRL_V_STR);
8805 }
8806 tw_save = curbuf->b_p_tw;
8807 curbuf->b_p_tw = -1;
8808 insert_special(c, TRUE, FALSE);
8809 curbuf->b_p_tw = tw_save;
8810 revins_chars++;
8811 revins_legal++;
8812 c = Ctrl_V; /* pretend CTRL-V is last character */
8813 auto_format(FALSE, TRUE);
8814 }
8815 }
8816 return c;
8817}
8818
8819/*
8820 * Try to do some very smart auto-indenting.
8821 * Used when inserting a "normal" character.
8822 */
8823static void ins_try_si(int c)
8824{
8825 pos_T *pos, old_pos;
8826 char_u *ptr;
8827 int i;
8828 int temp;
8829
8830 /*
8831 * do some very smart indenting when entering '{' or '}'
8832 */
8833 if (((did_si || can_si_back) && c == '{') || (can_si && c == '}')) {
8834 /*
8835 * for '}' set indent equal to indent of line containing matching '{'
8836 */
8837 if (c == '}' && (pos = findmatch(NULL, '{')) != NULL) {
8838 old_pos = curwin->w_cursor;
8839 /*
8840 * If the matching '{' has a ')' immediately before it (ignoring
8841 * white-space), then line up with the start of the line
8842 * containing the matching '(' if there is one. This handles the
8843 * case where an "if (..\n..) {" statement continues over multiple
8844 * lines -- webb
8845 */
8846 ptr = ml_get(pos->lnum);
8847 i = pos->col;
8848 if (i > 0) /* skip blanks before '{' */
8849 while (--i > 0 && ascii_iswhite(ptr[i]))
8850 ;
8851 curwin->w_cursor.lnum = pos->lnum;
8852 curwin->w_cursor.col = i;
8853 if (ptr[i] == ')' && (pos = findmatch(NULL, '(')) != NULL)
8854 curwin->w_cursor = *pos;
8855 i = get_indent();
8856 curwin->w_cursor = old_pos;
8857 if (State & VREPLACE_FLAG)
8858 change_indent(INDENT_SET, i, FALSE, NUL, TRUE);
8859 else
8860 (void)set_indent(i, SIN_CHANGED);
8861 } else if (curwin->w_cursor.col > 0) {
8862 /*
8863 * when inserting '{' after "O" reduce indent, but not
8864 * more than indent of previous line
8865 */
8866 temp = TRUE;
8867 if (c == '{' && can_si_back && curwin->w_cursor.lnum > 1) {
8868 old_pos = curwin->w_cursor;
8869 i = get_indent();
8870 while (curwin->w_cursor.lnum > 1) {
8871 ptr = skipwhite(ml_get(--(curwin->w_cursor.lnum)));
8872
8873 /* ignore empty lines and lines starting with '#'. */
8874 if (*ptr != '#' && *ptr != NUL)
8875 break;
8876 }
8877 if (get_indent() >= i)
8878 temp = FALSE;
8879 curwin->w_cursor = old_pos;
8880 }
8881 if (temp)
8882 shift_line(TRUE, FALSE, 1, TRUE);
8883 }
8884 }
8885
8886 /*
8887 * set indent of '#' always to 0
8888 */
8889 if (curwin->w_cursor.col > 0 && can_si && c == '#') {
8890 /* remember current indent for next line */
8891 old_indent = get_indent();
8892 (void)set_indent(0, SIN_CHANGED);
8893 }
8894
8895 /* Adjust ai_col, the char at this position can be deleted. */
8896 if (ai_col > curwin->w_cursor.col)
8897 ai_col = curwin->w_cursor.col;
8898}
8899
8900/*
8901 * Get the value that w_virtcol would have when 'list' is off.
8902 * Unless 'cpo' contains the 'L' flag.
8903 */
8904static colnr_T get_nolist_virtcol(void)
8905{
8906 if (curwin->w_p_list && vim_strchr(p_cpo, CPO_LISTWM) == NULL)
8907 return getvcol_nolist(&curwin->w_cursor);
8908 validate_virtcol();
8909 return curwin->w_virtcol;
8910}
8911
8912/*
8913 * Handle the InsertCharPre autocommand.
8914 * "c" is the character that was typed.
8915 * Return a pointer to allocated memory with the replacement string.
8916 * Return NULL to continue inserting "c".
8917 */
8918static char_u *do_insert_char_pre(int c)
8919{
8920 char buf[MB_MAXBYTES + 1];
8921 const int save_State = State;
8922
8923 // Return quickly when there is nothing to do.
8924 if (!has_event(EVENT_INSERTCHARPRE)) {
8925 return NULL;
8926 }
8927 buf[utf_char2bytes(c, (char_u *)buf)] = NUL;
8928
8929 // Lock the text to avoid weird things from happening.
8930 textlock++;
8931 set_vim_var_string(VV_CHAR, buf, -1);
8932
8933 char_u *res = NULL;
8934 if (ins_apply_autocmds(EVENT_INSERTCHARPRE)) {
8935 // Get the value of v:char. It may be empty or more than one
8936 // character. Only use it when changed, otherwise continue with the
8937 // original character to avoid breaking autoindent.
8938 if (STRCMP(buf, get_vim_var_str(VV_CHAR)) != 0) {
8939 res = vim_strsave(get_vim_var_str(VV_CHAR));
8940 }
8941 }
8942
8943 set_vim_var_string(VV_CHAR, NULL, -1);
8944 textlock--;
8945
8946 // Restore the State, it may have been changed.
8947 State = save_State;
8948
8949 return res;
8950}
8951
8952/// Trigger "event" and take care of fixing undo.
8953static int ins_apply_autocmds(event_T event)
8954{
8955 varnumber_T tick = buf_get_changedtick(curbuf);
8956 int r;
8957
8958 r = apply_autocmds(event, NULL, NULL, false, curbuf);
8959
8960 // If u_savesub() was called then we are not prepared to start
8961 // a new line. Call u_save() with no contents to fix that.
8962 if (tick != buf_get_changedtick(curbuf)) {
8963 u_save(curwin->w_cursor.lnum, (linenr_T)(curwin->w_cursor.lnum + 1));
8964 }
8965
8966 return r;
8967}
8968
8969static void show_pum(int prev_w_wrow, int prev_w_leftcol)
8970{
8971 // RedrawingDisabled may be set when invoked through complete().
8972 int n = RedrawingDisabled;
8973 RedrawingDisabled = 0;
8974
8975 // If the cursor moved or the display scrolled we need to remove the pum
8976 // first.
8977 setcursor();
8978 if (prev_w_wrow != curwin->w_wrow || prev_w_leftcol != curwin->w_leftcol) {
8979 ins_compl_del_pum();
8980 }
8981
8982 ins_compl_show_pum();
8983 setcursor();
8984 RedrawingDisabled = n;
8985}
8986