blob: 51177fb2c7e9198b62ac7421570c3a9b1429023c [file] [log] [blame]
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001/* vi:set ts=8 sts=4 sw=4 noet:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * insexpand.c: functions for Insert mode completion
12 */
13
14#include "vim.h"
15
Bram Moolenaar7591bb32019-03-30 13:53:47 +010016/*
17 * Definitions used for CTRL-X submode.
18 * Note: If you change CTRL-X submode, you must also maintain ctrl_x_msgs[] and
19 * ctrl_x_mode_names[] below.
20 */
21# define CTRL_X_WANT_IDENT 0x100
22
Bram Moolenaaraa2f0ee2019-12-21 18:47:26 +010023# define CTRL_X_NORMAL 0 // CTRL-N CTRL-P completion, default
Bram Moolenaar7591bb32019-03-30 13:53:47 +010024# define CTRL_X_NOT_DEFINED_YET 1
25# define CTRL_X_SCROLL 2
26# define CTRL_X_WHOLE_LINE 3
27# define CTRL_X_FILES 4
28# define CTRL_X_TAGS (5 + CTRL_X_WANT_IDENT)
29# define CTRL_X_PATH_PATTERNS (6 + CTRL_X_WANT_IDENT)
30# define CTRL_X_PATH_DEFINES (7 + CTRL_X_WANT_IDENT)
31# define CTRL_X_FINISHED 8
32# define CTRL_X_DICTIONARY (9 + CTRL_X_WANT_IDENT)
33# define CTRL_X_THESAURUS (10 + CTRL_X_WANT_IDENT)
34# define CTRL_X_CMDLINE 11
Bram Moolenaar9810cfb2019-12-11 21:23:00 +010035# define CTRL_X_FUNCTION 12
Bram Moolenaar7591bb32019-03-30 13:53:47 +010036# define CTRL_X_OMNI 13
37# define CTRL_X_SPELL 14
Bram Moolenaaraa2f0ee2019-12-21 18:47:26 +010038# define CTRL_X_LOCAL_MSG 15 // only used in "ctrl_x_msgs"
39# define CTRL_X_EVAL 16 // for builtin function complete()
zeertzjqdca29d92021-08-31 19:12:51 +020040# define CTRL_X_CMDLINE_CTRL_X 17 // CTRL-X typed in CTRL_X_CMDLINE
Bram Moolenaar7591bb32019-03-30 13:53:47 +010041
42# define CTRL_X_MSG(i) ctrl_x_msgs[(i) & ~CTRL_X_WANT_IDENT]
43
44// Message for CTRL-X mode, index is ctrl_x_mode.
45static char *ctrl_x_msgs[] =
46{
47 N_(" Keyword completion (^N^P)"), // CTRL_X_NORMAL, ^P/^N compl.
48 N_(" ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)"),
49 NULL, // CTRL_X_SCROLL: depends on state
50 N_(" Whole line completion (^L^N^P)"),
51 N_(" File name completion (^F^N^P)"),
52 N_(" Tag completion (^]^N^P)"),
53 N_(" Path pattern completion (^N^P)"),
54 N_(" Definition completion (^D^N^P)"),
55 NULL, // CTRL_X_FINISHED
56 N_(" Dictionary completion (^K^N^P)"),
57 N_(" Thesaurus completion (^T^N^P)"),
58 N_(" Command-line completion (^V^N^P)"),
59 N_(" User defined completion (^U^N^P)"),
60 N_(" Omni completion (^O^N^P)"),
61 N_(" Spelling suggestion (s^N^P)"),
62 N_(" Keyword Local completion (^N^P)"),
63 NULL, // CTRL_X_EVAL doesn't use msg.
zeertzjqdca29d92021-08-31 19:12:51 +020064 N_(" Command-line completion (^V^N^P)"),
Bram Moolenaar7591bb32019-03-30 13:53:47 +010065};
66
Bram Moolenaar9cb698d2019-08-21 15:30:45 +020067#if defined(FEAT_COMPL_FUNC) || defined(FEAT_EVAL)
Bram Moolenaar7591bb32019-03-30 13:53:47 +010068static char *ctrl_x_mode_names[] = {
69 "keyword",
70 "ctrl_x",
zeertzjq27fef592021-10-03 12:01:27 +010071 "scroll",
Bram Moolenaar7591bb32019-03-30 13:53:47 +010072 "whole_line",
73 "files",
74 "tags",
75 "path_patterns",
76 "path_defines",
77 "unknown", // CTRL_X_FINISHED
78 "dictionary",
79 "thesaurus",
80 "cmdline",
81 "function",
82 "omni",
83 "spell",
84 NULL, // CTRL_X_LOCAL_MSG only used in "ctrl_x_msgs"
zeertzjqdca29d92021-08-31 19:12:51 +020085 "eval",
86 "cmdline",
Bram Moolenaar7591bb32019-03-30 13:53:47 +010087};
Bram Moolenaar9cb698d2019-08-21 15:30:45 +020088#endif
Bram Moolenaar7591bb32019-03-30 13:53:47 +010089
90/*
91 * Array indexes used for cp_text[].
92 */
93#define CPT_ABBR 0 // "abbr"
94#define CPT_MENU 1 // "menu"
95#define CPT_KIND 2 // "kind"
96#define CPT_INFO 3 // "info"
Bram Moolenaar08928322020-01-04 14:32:48 +010097#define CPT_COUNT 4 // Number of entries
Bram Moolenaar7591bb32019-03-30 13:53:47 +010098
99/*
100 * Structure used to store one match for insert completion.
101 */
102typedef struct compl_S compl_T;
103struct compl_S
104{
105 compl_T *cp_next;
106 compl_T *cp_prev;
Bram Moolenaar73655cf2019-04-06 13:45:55 +0200107 char_u *cp_str; // matched text
Bram Moolenaar73655cf2019-04-06 13:45:55 +0200108 char_u *(cp_text[CPT_COUNT]); // text for the menu
Bram Moolenaarab782c52020-01-04 19:00:11 +0100109#ifdef FEAT_EVAL
Bram Moolenaar08928322020-01-04 14:32:48 +0100110 typval_T cp_user_data;
Bram Moolenaarab782c52020-01-04 19:00:11 +0100111#endif
Bram Moolenaar73655cf2019-04-06 13:45:55 +0200112 char_u *cp_fname; // file containing the match, allocated when
Bram Moolenaard9eefe32019-04-06 14:22:21 +0200113 // cp_flags has CP_FREE_FNAME
114 int cp_flags; // CP_ values
Bram Moolenaar73655cf2019-04-06 13:45:55 +0200115 int cp_number; // sequence number
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100116};
117
Bram Moolenaard9eefe32019-04-06 14:22:21 +0200118// values for cp_flags
119# define CP_ORIGINAL_TEXT 1 // the original text when the expansion begun
120# define CP_FREE_FNAME 2 // cp_fname is allocated
121# define CP_CONT_S_IPOS 4 // use CONT_S_IPOS for compl_cont_status
122# define CP_EQUAL 8 // ins_compl_equal() always returns TRUE
123# define CP_ICASE 16 // ins_compl_equal() ignores case
Bram Moolenaar440cf092021-04-03 20:13:30 +0200124# define CP_FAST 32 // use fast_breakcheck instead of ui_breakcheck
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100125
126static char e_hitend[] = N_("Hit end of paragraph");
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100127
128/*
129 * All the current matches are stored in a list.
130 * "compl_first_match" points to the start of the list.
131 * "compl_curr_match" points to the currently selected entry.
132 * "compl_shown_match" is different from compl_curr_match during
133 * ins_compl_get_exp().
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +0000134 * "compl_old_match" points to previous "compl_curr_match".
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100135 */
136static compl_T *compl_first_match = NULL;
137static compl_T *compl_curr_match = NULL;
138static compl_T *compl_shown_match = NULL;
139static compl_T *compl_old_match = NULL;
140
141// After using a cursor key <Enter> selects a match in the popup menu,
142// otherwise it inserts a line break.
143static int compl_enter_selects = FALSE;
144
145// When "compl_leader" is not NULL only matches that start with this string
146// are used.
147static char_u *compl_leader = NULL;
148
149static int compl_get_longest = FALSE; // put longest common string
150 // in compl_leader
151
152static int compl_no_insert = FALSE; // FALSE: select & insert
153 // TRUE: noinsert
154static int compl_no_select = FALSE; // FALSE: select & insert
155 // TRUE: noselect
156
157// Selected one of the matches. When FALSE the match was edited or using the
158// longest common string.
159static int compl_used_match;
160
161// didn't finish finding completions.
162static int compl_was_interrupted = FALSE;
163
164// Set when character typed while looking for matches and it means we should
165// stop looking for matches.
166static int compl_interrupted = FALSE;
167
168static int compl_restarting = FALSE; // don't insert match
169
170// When the first completion is done "compl_started" is set. When it's
171// FALSE the word to be completed must be located.
172static int compl_started = FALSE;
173
174// Which Ctrl-X mode are we in?
175static int ctrl_x_mode = CTRL_X_NORMAL;
176
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +0000177static int compl_matches = 0; // number of completion matches
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100178static char_u *compl_pattern = NULL;
179static int compl_direction = FORWARD;
180static int compl_shows_dir = FORWARD;
181static int compl_pending = 0; // > 1 for postponed CTRL-N
182static pos_T compl_startpos;
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +0000183// Length in bytes of the text being completed (this is deleted to be replaced
184// by the match.)
185static int compl_length = 0;
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100186static colnr_T compl_col = 0; // column where the text starts
187 // that is being completed
188static char_u *compl_orig_text = NULL; // text as it was before
189 // completion started
190static int compl_cont_mode = 0;
191static expand_T compl_xp;
192
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +0000193// List of flags for method of completion.
194static int compl_cont_status = 0;
195# define CONT_ADDING 1 // "normal" or "adding" expansion
196# define CONT_INTRPT (2 + 4) // a ^X interrupted the current expansion
197 // it's set only iff N_ADDS is set
198# define CONT_N_ADDS 4 // next ^X<> will add-new or expand-current
199# define CONT_S_IPOS 8 // next ^X<> will set initial_pos?
200 // if so, word-wise-expansion will set SOL
201# define CONT_SOL 16 // pattern includes start of line, just for
202 // word-wise expansion, not set for ^X^L
203# define CONT_LOCAL 32 // for ctrl_x_mode 0, ^X^P/^X^N do a local
204 // expansion, (eg use complete=.)
205
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100206static int compl_opt_refresh_always = FALSE;
207static int compl_opt_suppress_empty = FALSE;
208
Bram Moolenaar08928322020-01-04 14:32:48 +0100209static int ins_compl_add(char_u *str, int len, char_u *fname, char_u **cptext, typval_T *user_data, int cdir, int flags, int adup);
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100210static void ins_compl_longest_match(compl_T *match);
211static void ins_compl_del_pum(void);
212static void ins_compl_files(int count, char_u **files, int thesaurus, int flags, regmatch_T *regmatch, char_u *buf, int *dir);
213static char_u *find_line_end(char_u *ptr);
214static void ins_compl_free(void);
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100215static int ins_compl_need_restart(void);
216static void ins_compl_new_leader(void);
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +0000217static int get_compl_len(void);
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100218static void ins_compl_restart(void);
219static void ins_compl_set_original_text(char_u *str);
220static void ins_compl_fixRedoBufForLeader(char_u *ptr_arg);
221# if defined(FEAT_COMPL_FUNC) || defined(FEAT_EVAL)
222static void ins_compl_add_list(list_T *list);
223static void ins_compl_add_dict(dict_T *dict);
224# endif
225static int ins_compl_key2dir(int c);
226static int ins_compl_pum_key(int c);
227static int ins_compl_key2count(int c);
228static void show_pum(int prev_w_wrow, int prev_w_leftcol);
229static unsigned quote_meta(char_u *dest, char_u *str, int len);
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100230
231#ifdef FEAT_SPELL
232static void spell_back_to_badword(void);
233static int spell_bad_len = 0; // length of located bad word
234#endif
235
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100236/*
237 * CTRL-X pressed in Insert mode.
238 */
239 void
240ins_ctrl_x(void)
241{
zeertzjqdca29d92021-08-31 19:12:51 +0200242 if (!ctrl_x_mode_cmdline())
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100243 {
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +0000244 // if the next ^X<> won't ADD nothing, then reset compl_cont_status
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100245 if (compl_cont_status & CONT_N_ADDS)
246 compl_cont_status |= CONT_INTRPT;
247 else
248 compl_cont_status = 0;
249 // We're not sure which CTRL-X mode it will be yet
250 ctrl_x_mode = CTRL_X_NOT_DEFINED_YET;
251 edit_submode = (char_u *)_(CTRL_X_MSG(ctrl_x_mode));
252 edit_submode_pre = NULL;
253 showmode();
254 }
zeertzjqdca29d92021-08-31 19:12:51 +0200255 else
256 // CTRL-X in CTRL-X CTRL-V mode behaves differently to make CTRL-X
257 // CTRL-V look like CTRL-N
258 ctrl_x_mode = CTRL_X_CMDLINE_CTRL_X;
=?UTF-8?q?Magnus=20Gro=C3=9F?=25def2c2021-10-22 18:56:39 +0100259
260 trigger_modechanged();
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100261}
262
263/*
264 * Functions to check the current CTRL-X mode.
265 */
Dominique Pelle748b3082022-01-08 12:41:16 +0000266#ifdef FEAT_CINDENT
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100267int ctrl_x_mode_none(void) { return ctrl_x_mode == 0; }
Dominique Pelle748b3082022-01-08 12:41:16 +0000268#endif
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100269int ctrl_x_mode_normal(void) { return ctrl_x_mode == CTRL_X_NORMAL; }
270int ctrl_x_mode_scroll(void) { return ctrl_x_mode == CTRL_X_SCROLL; }
271int ctrl_x_mode_whole_line(void) { return ctrl_x_mode == CTRL_X_WHOLE_LINE; }
272int ctrl_x_mode_files(void) { return ctrl_x_mode == CTRL_X_FILES; }
273int ctrl_x_mode_tags(void) { return ctrl_x_mode == CTRL_X_TAGS; }
274int ctrl_x_mode_path_patterns(void) {
275 return ctrl_x_mode == CTRL_X_PATH_PATTERNS; }
276int ctrl_x_mode_path_defines(void) {
277 return ctrl_x_mode == CTRL_X_PATH_DEFINES; }
278int ctrl_x_mode_dictionary(void) { return ctrl_x_mode == CTRL_X_DICTIONARY; }
279int ctrl_x_mode_thesaurus(void) { return ctrl_x_mode == CTRL_X_THESAURUS; }
zeertzjqdca29d92021-08-31 19:12:51 +0200280int ctrl_x_mode_cmdline(void) {
281 return ctrl_x_mode == CTRL_X_CMDLINE
282 || ctrl_x_mode == CTRL_X_CMDLINE_CTRL_X; }
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100283int ctrl_x_mode_function(void) { return ctrl_x_mode == CTRL_X_FUNCTION; }
284int ctrl_x_mode_omni(void) { return ctrl_x_mode == CTRL_X_OMNI; }
285int ctrl_x_mode_spell(void) { return ctrl_x_mode == CTRL_X_SPELL; }
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +0000286static int ctrl_x_mode_eval(void) { return ctrl_x_mode == CTRL_X_EVAL; }
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100287int ctrl_x_mode_line_or_eval(void) {
288 return ctrl_x_mode == CTRL_X_WHOLE_LINE || ctrl_x_mode == CTRL_X_EVAL; }
289
290/*
291 * Whether other than default completion has been selected.
292 */
293 int
294ctrl_x_mode_not_default(void)
295{
296 return ctrl_x_mode != CTRL_X_NORMAL;
297}
298
299/*
zeertzjqdca29d92021-08-31 19:12:51 +0200300 * Whether CTRL-X was typed without a following character,
301 * not including when in CTRL-X CTRL-V mode.
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100302 */
303 int
304ctrl_x_mode_not_defined_yet(void)
305{
306 return ctrl_x_mode == CTRL_X_NOT_DEFINED_YET;
307}
308
309/*
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +0000310 * Return TRUE if currently in "normal" or "adding" insert completion matches
311 * state
312 */
313 int
314compl_status_adding(void)
315{
316 return compl_cont_status & CONT_ADDING;
317}
318
319/*
320 * Return TRUE if the completion pattern includes start of line, just for
321 * word-wise expansion.
322 */
323 int
324compl_status_sol(void)
325{
326 return compl_cont_status & CONT_SOL;
327}
328
329/*
330 * Return TRUE if ^X^P/^X^N will do a local completion (i.e. use complete=.)
331 */
332 int
333compl_status_local(void)
334{
335 return compl_cont_status & CONT_LOCAL;
336}
337
338/*
339 * Clear the completion status flags
340 */
341 void
342compl_status_clear(void)
343{
344 compl_cont_status = 0;
345}
346
347/*
348 * Return TRUE if completion is using the forward direction matches
349 */
350 static int
351compl_dir_forward(void)
352{
353 return compl_direction == FORWARD;
354}
355
356/*
357 * Return TRUE if currently showing forward completion matches
358 */
359 static int
360compl_shows_dir_forward(void)
361{
362 return compl_shows_dir == FORWARD;
363}
364
365/*
366 * Return TRUE if currently showing backward completion matches
367 */
368 static int
369compl_shows_dir_backward(void)
370{
371 return compl_shows_dir == BACKWARD;
372}
373
374/*
375 * Return TRUE if the 'dictionary' or 'thesaurus' option can be used.
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100376 */
377 int
378has_compl_option(int dict_opt)
379{
380 if (dict_opt ? (*curbuf->b_p_dict == NUL && *p_dict == NUL
Bram Moolenaare2c453d2019-08-21 14:37:09 +0200381#ifdef FEAT_SPELL
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100382 && !curwin->w_p_spell
Bram Moolenaare2c453d2019-08-21 14:37:09 +0200383#endif
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100384 )
Yegappan Lakshmanan160e9942021-10-16 15:41:29 +0100385 : (*curbuf->b_p_tsr == NUL && *p_tsr == NUL
386#ifdef FEAT_COMPL_FUNC
Bram Moolenaarf4d8b762021-10-17 14:13:09 +0100387 && *curbuf->b_p_tsrfu == NUL && *p_tsrfu == NUL
Yegappan Lakshmanan160e9942021-10-16 15:41:29 +0100388#endif
389 ))
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100390 {
391 ctrl_x_mode = CTRL_X_NORMAL;
392 edit_submode = NULL;
393 msg_attr(dict_opt ? _("'dictionary' option is empty")
394 : _("'thesaurus' option is empty"),
395 HL_ATTR(HLF_E));
Bram Moolenaar28ee8922020-10-28 20:20:00 +0100396 if (emsg_silent == 0 && !in_assert_fails)
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100397 {
398 vim_beep(BO_COMPL);
399 setcursor();
400 out_flush();
401#ifdef FEAT_EVAL
402 if (!get_vim_var_nr(VV_TESTING))
403#endif
Bram Moolenaareda1da02019-11-17 17:06:33 +0100404 ui_delay(2004L, FALSE);
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100405 }
406 return FALSE;
407 }
408 return TRUE;
409}
410
411/*
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +0000412 * Is the character "c" a valid key to go to or keep us in CTRL-X mode?
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100413 * This depends on the current mode.
414 */
415 int
416vim_is_ctrl_x_key(int c)
417{
418 // Always allow ^R - let its results then be checked
419 if (c == Ctrl_R)
420 return TRUE;
421
422 // Accept <PageUp> and <PageDown> if the popup menu is visible.
423 if (ins_compl_pum_key(c))
424 return TRUE;
425
426 switch (ctrl_x_mode)
427 {
428 case 0: // Not in any CTRL-X mode
429 return (c == Ctrl_N || c == Ctrl_P || c == Ctrl_X);
430 case CTRL_X_NOT_DEFINED_YET:
zeertzjqdca29d92021-08-31 19:12:51 +0200431 case CTRL_X_CMDLINE_CTRL_X:
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100432 return ( c == Ctrl_X || c == Ctrl_Y || c == Ctrl_E
433 || c == Ctrl_L || c == Ctrl_F || c == Ctrl_RSB
434 || c == Ctrl_I || c == Ctrl_D || c == Ctrl_P
435 || c == Ctrl_N || c == Ctrl_T || c == Ctrl_V
436 || c == Ctrl_Q || c == Ctrl_U || c == Ctrl_O
zeertzjqdca29d92021-08-31 19:12:51 +0200437 || c == Ctrl_S || c == Ctrl_K || c == 's'
438 || c == Ctrl_Z);
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100439 case CTRL_X_SCROLL:
440 return (c == Ctrl_Y || c == Ctrl_E);
441 case CTRL_X_WHOLE_LINE:
442 return (c == Ctrl_L || c == Ctrl_P || c == Ctrl_N);
443 case CTRL_X_FILES:
444 return (c == Ctrl_F || c == Ctrl_P || c == Ctrl_N);
445 case CTRL_X_DICTIONARY:
446 return (c == Ctrl_K || c == Ctrl_P || c == Ctrl_N);
447 case CTRL_X_THESAURUS:
448 return (c == Ctrl_T || c == Ctrl_P || c == Ctrl_N);
449 case CTRL_X_TAGS:
450 return (c == Ctrl_RSB || c == Ctrl_P || c == Ctrl_N);
451#ifdef FEAT_FIND_ID
452 case CTRL_X_PATH_PATTERNS:
453 return (c == Ctrl_P || c == Ctrl_N);
454 case CTRL_X_PATH_DEFINES:
455 return (c == Ctrl_D || c == Ctrl_P || c == Ctrl_N);
456#endif
457 case CTRL_X_CMDLINE:
458 return (c == Ctrl_V || c == Ctrl_Q || c == Ctrl_P || c == Ctrl_N
459 || c == Ctrl_X);
460#ifdef FEAT_COMPL_FUNC
461 case CTRL_X_FUNCTION:
462 return (c == Ctrl_U || c == Ctrl_P || c == Ctrl_N);
463 case CTRL_X_OMNI:
464 return (c == Ctrl_O || c == Ctrl_P || c == Ctrl_N);
465#endif
466 case CTRL_X_SPELL:
467 return (c == Ctrl_S || c == Ctrl_P || c == Ctrl_N);
468 case CTRL_X_EVAL:
469 return (c == Ctrl_P || c == Ctrl_N);
470 }
471 internal_error("vim_is_ctrl_x_key()");
472 return FALSE;
473}
474
475/*
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +0000476 * Return TRUE if "match" is the original text when the completion began.
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +0000477 */
478 static int
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +0000479match_at_original_text(compl_T *match)
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +0000480{
481 return match->cp_flags & CP_ORIGINAL_TEXT;
482}
483
484/*
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +0000485 * Returns TRUE if "match" is the first match in the completion list.
486 */
487 static int
488is_first_match(compl_T *match)
489{
490 return match == compl_first_match;
491}
492
493/*
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100494 * Return TRUE when character "c" is part of the item currently being
495 * completed. Used to decide whether to abandon complete mode when the menu
496 * is visible.
497 */
498 int
499ins_compl_accept_char(int c)
500{
501 if (ctrl_x_mode & CTRL_X_WANT_IDENT)
502 // When expanding an identifier only accept identifier chars.
503 return vim_isIDc(c);
504
505 switch (ctrl_x_mode)
506 {
507 case CTRL_X_FILES:
508 // When expanding file name only accept file name chars. But not
509 // path separators, so that "proto/<Tab>" expands files in
510 // "proto", not "proto/" as a whole
511 return vim_isfilec(c) && !vim_ispathsep(c);
512
513 case CTRL_X_CMDLINE:
zeertzjqdca29d92021-08-31 19:12:51 +0200514 case CTRL_X_CMDLINE_CTRL_X:
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100515 case CTRL_X_OMNI:
516 // Command line and Omni completion can work with just about any
517 // printable character, but do stop at white space.
518 return vim_isprintc(c) && !VIM_ISWHITE(c);
519
520 case CTRL_X_WHOLE_LINE:
521 // For while line completion a space can be part of the line.
522 return vim_isprintc(c);
523 }
524 return vim_iswordc(c);
525}
526
527/*
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +0000528 * Get the completed text by inferring the case of the originally typed text.
529 */
530 static char_u *
531ins_compl_infercase_gettext(
532 char_u *str,
533 int actual_len,
534 int actual_compl_length,
535 int min_len)
536{
537 int *wca; // Wide character array.
538 char_u *p;
539 int i, c;
540 int has_lower = FALSE;
541 int was_letter = FALSE;
542
543 IObuff[0] = NUL;
544
545 // Allocate wide character array for the completion and fill it.
546 wca = ALLOC_MULT(int, actual_len);
547 if (wca == NULL)
548 return IObuff;
549
550 p = str;
551 for (i = 0; i < actual_len; ++i)
552 if (has_mbyte)
553 wca[i] = mb_ptr2char_adv(&p);
554 else
555 wca[i] = *(p++);
556
557 // Rule 1: Were any chars converted to lower?
558 p = compl_orig_text;
559 for (i = 0; i < min_len; ++i)
560 {
561 if (has_mbyte)
562 c = mb_ptr2char_adv(&p);
563 else
564 c = *(p++);
565 if (MB_ISLOWER(c))
566 {
567 has_lower = TRUE;
568 if (MB_ISUPPER(wca[i]))
569 {
570 // Rule 1 is satisfied.
571 for (i = actual_compl_length; i < actual_len; ++i)
572 wca[i] = MB_TOLOWER(wca[i]);
573 break;
574 }
575 }
576 }
577
578 // Rule 2: No lower case, 2nd consecutive letter converted to
579 // upper case.
580 if (!has_lower)
581 {
582 p = compl_orig_text;
583 for (i = 0; i < min_len; ++i)
584 {
585 if (has_mbyte)
586 c = mb_ptr2char_adv(&p);
587 else
588 c = *(p++);
589 if (was_letter && MB_ISUPPER(c) && MB_ISLOWER(wca[i]))
590 {
591 // Rule 2 is satisfied.
592 for (i = actual_compl_length; i < actual_len; ++i)
593 wca[i] = MB_TOUPPER(wca[i]);
594 break;
595 }
596 was_letter = MB_ISLOWER(c) || MB_ISUPPER(c);
597 }
598 }
599
600 // Copy the original case of the part we typed.
601 p = compl_orig_text;
602 for (i = 0; i < min_len; ++i)
603 {
604 if (has_mbyte)
605 c = mb_ptr2char_adv(&p);
606 else
607 c = *(p++);
608 if (MB_ISLOWER(c))
609 wca[i] = MB_TOLOWER(wca[i]);
610 else if (MB_ISUPPER(c))
611 wca[i] = MB_TOUPPER(wca[i]);
612 }
613
614 // Generate encoding specific output from wide character array.
615 // Multi-byte characters can occupy up to five bytes more than
616 // ASCII characters, and we also need one byte for NUL, so stay
617 // six bytes away from the edge of IObuff.
618 p = IObuff;
619 i = 0;
620 while (i < actual_len && (p - IObuff + 6) < IOSIZE)
621 if (has_mbyte)
622 p += (*mb_char2bytes)(wca[i++], p);
623 else
624 *(p++) = wca[i++];
625 *p = NUL;
626
627 vim_free(wca);
628
629 return IObuff;
630}
631
632/*
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100633 * This is like ins_compl_add(), but if 'ic' and 'inf' are set, then the
634 * case of the originally typed text is used, and the case of the completed
635 * text is inferred, ie this tries to work out what case you probably wanted
636 * the rest of the word to be in -- webb
637 */
638 int
639ins_compl_add_infercase(
Bram Moolenaar73655cf2019-04-06 13:45:55 +0200640 char_u *str_arg,
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100641 int len,
642 int icase,
643 char_u *fname,
644 int dir,
Bram Moolenaard9eefe32019-04-06 14:22:21 +0200645 int cont_s_ipos) // next ^X<> will set initial_pos
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100646{
Bram Moolenaar73655cf2019-04-06 13:45:55 +0200647 char_u *str = str_arg;
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100648 char_u *p;
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100649 int actual_len; // Take multi-byte characters
650 int actual_compl_length; // into account.
651 int min_len;
Bram Moolenaard9eefe32019-04-06 14:22:21 +0200652 int flags = 0;
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100653
654 if (p_ic && curbuf->b_p_inf && len > 0)
655 {
656 // Infer case of completed part.
657
658 // Find actual length of completion.
659 if (has_mbyte)
660 {
661 p = str;
662 actual_len = 0;
663 while (*p != NUL)
664 {
665 MB_PTR_ADV(p);
666 ++actual_len;
667 }
668 }
669 else
670 actual_len = len;
671
672 // Find actual length of original text.
673 if (has_mbyte)
674 {
675 p = compl_orig_text;
676 actual_compl_length = 0;
677 while (*p != NUL)
678 {
679 MB_PTR_ADV(p);
680 ++actual_compl_length;
681 }
682 }
683 else
684 actual_compl_length = compl_length;
685
686 // "actual_len" may be smaller than "actual_compl_length" when using
687 // thesaurus, only use the minimum when comparing.
688 min_len = actual_len < actual_compl_length
689 ? actual_len : actual_compl_length;
690
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +0000691 str = ins_compl_infercase_gettext(str, actual_len, actual_compl_length,
692 min_len);
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100693 }
Bram Moolenaard9eefe32019-04-06 14:22:21 +0200694 if (cont_s_ipos)
695 flags |= CP_CONT_S_IPOS;
696 if (icase)
697 flags |= CP_ICASE;
Bram Moolenaar73655cf2019-04-06 13:45:55 +0200698
Bram Moolenaar08928322020-01-04 14:32:48 +0100699 return ins_compl_add(str, len, fname, NULL, NULL, dir, flags, FALSE);
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100700}
701
702/*
Yegappan Lakshmanan37079142022-01-08 10:38:48 +0000703 * Add a match to the list of matches. The arguments are:
704 * str - text of the match to add
705 * len - length of "str". If -1, then the length of "str" is
706 * computed.
707 * fname - file name to associate with this match.
708 * cptext - list of strings to use with this match (for abbr, menu, info
709 * and kind)
710 * user_data - user supplied data (any vim type) for this match
711 * cdir - match direction. If 0, use "compl_direction".
712 * flags_arg - match flags (cp_flags)
713 * adup - accept this match even if it is already present.
714 * If "cdir" is FORWARD, then the match is added after the current match.
715 * Otherwise, it is added before the current match.
716 *
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100717 * If the given string is already in the list of completions, then return
718 * NOTDONE, otherwise add it to the list and return OK. If there is an error,
719 * maybe because alloc() returns NULL, then FAIL is returned.
720 */
721 static int
722ins_compl_add(
723 char_u *str,
724 int len,
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100725 char_u *fname,
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100726 char_u **cptext, // extra text for popup menu or NULL
727 typval_T *user_data UNUSED, // "user_data" entry or NULL
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100728 int cdir,
Bram Moolenaard9eefe32019-04-06 14:22:21 +0200729 int flags_arg,
Bram Moolenaar08928322020-01-04 14:32:48 +0100730 int adup) // accept duplicate match
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100731{
732 compl_T *match;
733 int dir = (cdir == 0 ? compl_direction : cdir);
Bram Moolenaard9eefe32019-04-06 14:22:21 +0200734 int flags = flags_arg;
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100735
Bram Moolenaarceb06192021-04-04 15:05:22 +0200736 if (flags & CP_FAST)
737 fast_breakcheck();
738 else
739 ui_breakcheck();
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100740 if (got_int)
741 return FAIL;
742 if (len < 0)
743 len = (int)STRLEN(str);
744
745 // If the same match is already present, don't add it.
746 if (compl_first_match != NULL && !adup)
747 {
748 match = compl_first_match;
749 do
750 {
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +0000751 if (!match_at_original_text(match)
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100752 && STRNCMP(match->cp_str, str, len) == 0
753 && match->cp_str[len] == NUL)
754 return NOTDONE;
755 match = match->cp_next;
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +0000756 } while (match != NULL && !is_first_match(match));
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100757 }
758
759 // Remove any popup menu before changing the list of matches.
760 ins_compl_del_pum();
761
762 // Allocate a new match structure.
763 // Copy the values to the new match structure.
Bram Moolenaarc799fe22019-05-28 23:08:19 +0200764 match = ALLOC_CLEAR_ONE(compl_T);
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100765 if (match == NULL)
766 return FAIL;
767 match->cp_number = -1;
Bram Moolenaard9eefe32019-04-06 14:22:21 +0200768 if (flags & CP_ORIGINAL_TEXT)
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100769 match->cp_number = 0;
770 if ((match->cp_str = vim_strnsave(str, len)) == NULL)
771 {
772 vim_free(match);
773 return FAIL;
774 }
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100775
776 // match-fname is:
777 // - compl_curr_match->cp_fname if it is a string equal to fname.
Bram Moolenaard9eefe32019-04-06 14:22:21 +0200778 // - a copy of fname, CP_FREE_FNAME is set to free later THE allocated mem.
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100779 // - NULL otherwise. --Acevedo
780 if (fname != NULL
781 && compl_curr_match != NULL
782 && compl_curr_match->cp_fname != NULL
783 && STRCMP(fname, compl_curr_match->cp_fname) == 0)
784 match->cp_fname = compl_curr_match->cp_fname;
785 else if (fname != NULL)
786 {
787 match->cp_fname = vim_strsave(fname);
Bram Moolenaard9eefe32019-04-06 14:22:21 +0200788 flags |= CP_FREE_FNAME;
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100789 }
790 else
791 match->cp_fname = NULL;
792 match->cp_flags = flags;
793
794 if (cptext != NULL)
795 {
796 int i;
797
798 for (i = 0; i < CPT_COUNT; ++i)
799 if (cptext[i] != NULL && *cptext[i] != NUL)
800 match->cp_text[i] = vim_strsave(cptext[i]);
801 }
Bram Moolenaarab782c52020-01-04 19:00:11 +0100802#ifdef FEAT_EVAL
Bram Moolenaar08928322020-01-04 14:32:48 +0100803 if (user_data != NULL)
804 match->cp_user_data = *user_data;
Bram Moolenaarab782c52020-01-04 19:00:11 +0100805#endif
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100806
Yegappan Lakshmanan37079142022-01-08 10:38:48 +0000807 // Link the new match structure after (FORWARD) or before (BACKWARD) the
808 // current match in the list of matches .
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100809 if (compl_first_match == NULL)
810 match->cp_next = match->cp_prev = NULL;
811 else if (dir == FORWARD)
812 {
813 match->cp_next = compl_curr_match->cp_next;
814 match->cp_prev = compl_curr_match;
815 }
816 else // BACKWARD
817 {
818 match->cp_next = compl_curr_match;
819 match->cp_prev = compl_curr_match->cp_prev;
820 }
821 if (match->cp_next)
822 match->cp_next->cp_prev = match;
823 if (match->cp_prev)
824 match->cp_prev->cp_next = match;
825 else // if there's nothing before, it is the first match
826 compl_first_match = match;
827 compl_curr_match = match;
828
829 // Find the longest common string if still doing that.
Bram Moolenaard9eefe32019-04-06 14:22:21 +0200830 if (compl_get_longest && (flags & CP_ORIGINAL_TEXT) == 0)
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100831 ins_compl_longest_match(match);
832
833 return OK;
834}
835
836/*
837 * Return TRUE if "str[len]" matches with match->cp_str, considering
Bram Moolenaard9eefe32019-04-06 14:22:21 +0200838 * match->cp_flags.
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100839 */
840 static int
841ins_compl_equal(compl_T *match, char_u *str, int len)
842{
Bram Moolenaard9eefe32019-04-06 14:22:21 +0200843 if (match->cp_flags & CP_EQUAL)
Bram Moolenaar73655cf2019-04-06 13:45:55 +0200844 return TRUE;
Bram Moolenaard9eefe32019-04-06 14:22:21 +0200845 if (match->cp_flags & CP_ICASE)
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100846 return STRNICMP(match->cp_str, str, (size_t)len) == 0;
847 return STRNCMP(match->cp_str, str, (size_t)len) == 0;
848}
849
850/*
851 * Reduce the longest common string for match "match".
852 */
853 static void
854ins_compl_longest_match(compl_T *match)
855{
856 char_u *p, *s;
857 int c1, c2;
858 int had_match;
859
860 if (compl_leader == NULL)
861 {
862 // First match, use it as a whole.
863 compl_leader = vim_strsave(match->cp_str);
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +0000864 if (compl_leader == NULL)
865 return;
866
867 had_match = (curwin->w_cursor.col > compl_col);
868 ins_compl_delete();
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +0000869 ins_bytes(compl_leader + get_compl_len());
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +0000870 ins_redraw(FALSE);
871
872 // When the match isn't there (to avoid matching itself) remove it
873 // again after redrawing.
874 if (!had_match)
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100875 ins_compl_delete();
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100876 compl_used_match = FALSE;
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +0000877
878 return;
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100879 }
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +0000880
881 // Reduce the text if this match differs from compl_leader.
882 p = compl_leader;
883 s = match->cp_str;
884 while (*p != NUL)
885 {
886 if (has_mbyte)
887 {
888 c1 = mb_ptr2char(p);
889 c2 = mb_ptr2char(s);
890 }
891 else
892 {
893 c1 = *p;
894 c2 = *s;
895 }
896 if ((match->cp_flags & CP_ICASE)
897 ? (MB_TOLOWER(c1) != MB_TOLOWER(c2)) : (c1 != c2))
898 break;
899 if (has_mbyte)
900 {
901 MB_PTR_ADV(p);
902 MB_PTR_ADV(s);
903 }
904 else
905 {
906 ++p;
907 ++s;
908 }
909 }
910
911 if (*p != NUL)
912 {
913 // Leader was shortened, need to change the inserted text.
914 *p = NUL;
915 had_match = (curwin->w_cursor.col > compl_col);
916 ins_compl_delete();
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +0000917 ins_bytes(compl_leader + get_compl_len());
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +0000918 ins_redraw(FALSE);
919
920 // When the match isn't there (to avoid matching itself) remove it
921 // again after redrawing.
922 if (!had_match)
923 ins_compl_delete();
924 }
925
926 compl_used_match = FALSE;
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100927}
928
929/*
930 * Add an array of matches to the list of matches.
931 * Frees matches[].
932 */
933 static void
934ins_compl_add_matches(
935 int num_matches,
936 char_u **matches,
937 int icase)
938{
939 int i;
940 int add_r = OK;
941 int dir = compl_direction;
942
943 for (i = 0; i < num_matches && add_r != FAIL; i++)
Bram Moolenaar08928322020-01-04 14:32:48 +0100944 if ((add_r = ins_compl_add(matches[i], -1, NULL, NULL, NULL, dir,
Bram Moolenaar440cf092021-04-03 20:13:30 +0200945 CP_FAST | (icase ? CP_ICASE : 0), FALSE)) == OK)
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100946 // if dir was BACKWARD then honor it just once
947 dir = FORWARD;
948 FreeWild(num_matches, matches);
949}
950
951/*
952 * Make the completion list cyclic.
953 * Return the number of matches (excluding the original).
954 */
955 static int
956ins_compl_make_cyclic(void)
957{
958 compl_T *match;
959 int count = 0;
960
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +0000961 if (compl_first_match == NULL)
962 return 0;
963
964 // Find the end of the list.
965 match = compl_first_match;
966 // there's always an entry for the compl_orig_text, it doesn't count.
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +0000967 while (match->cp_next != NULL && !is_first_match(match->cp_next))
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100968 {
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +0000969 match = match->cp_next;
970 ++count;
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100971 }
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +0000972 match->cp_next = compl_first_match;
973 compl_first_match->cp_prev = match;
974
Bram Moolenaar7591bb32019-03-30 13:53:47 +0100975 return count;
976}
977
978/*
979 * Return whether there currently is a shown match.
980 */
981 int
982ins_compl_has_shown_match(void)
983{
984 return compl_shown_match == NULL
985 || compl_shown_match != compl_shown_match->cp_next;
986}
987
988/*
989 * Return whether the shown match is long enough.
990 */
991 int
992ins_compl_long_shown_match(void)
993{
994 return (int)STRLEN(compl_shown_match->cp_str)
995 > curwin->w_cursor.col - compl_col;
996}
997
998/*
999 * Set variables that store noselect and noinsert behavior from the
1000 * 'completeopt' value.
1001 */
1002 void
1003completeopt_was_set(void)
1004{
1005 compl_no_insert = FALSE;
1006 compl_no_select = FALSE;
1007 if (strstr((char *)p_cot, "noselect") != NULL)
1008 compl_no_select = TRUE;
1009 if (strstr((char *)p_cot, "noinsert") != NULL)
1010 compl_no_insert = TRUE;
1011}
1012
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001013
1014// "compl_match_array" points the currently displayed list of entries in the
1015// popup menu. It is NULL when there is no popup menu.
1016static pumitem_T *compl_match_array = NULL;
1017static int compl_match_arraysize;
1018
1019/*
1020 * Update the screen and when there is any scrolling remove the popup menu.
1021 */
1022 static void
1023ins_compl_upd_pum(void)
1024{
1025 int h;
1026
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00001027 if (compl_match_array == NULL)
1028 return;
1029
1030 h = curwin->w_cline_height;
1031 // Update the screen later, before drawing the popup menu over it.
1032 pum_call_update_screen();
1033 if (h != curwin->w_cline_height)
1034 ins_compl_del_pum();
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001035}
1036
1037/*
1038 * Remove any popup menu.
1039 */
1040 static void
1041ins_compl_del_pum(void)
1042{
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00001043 if (compl_match_array == NULL)
1044 return;
1045
1046 pum_undisplay();
1047 VIM_CLEAR(compl_match_array);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001048}
1049
1050/*
1051 * Return TRUE if the popup menu should be displayed.
1052 */
1053 int
1054pum_wanted(void)
1055{
1056 // 'completeopt' must contain "menu" or "menuone"
1057 if (vim_strchr(p_cot, 'm') == NULL)
1058 return FALSE;
1059
1060 // The display looks bad on a B&W display.
1061 if (t_colors < 8
1062#ifdef FEAT_GUI
1063 && !gui.in_use
1064#endif
1065 )
1066 return FALSE;
1067 return TRUE;
1068}
1069
1070/*
1071 * Return TRUE if there are two or more matches to be shown in the popup menu.
1072 * One if 'completopt' contains "menuone".
1073 */
1074 static int
1075pum_enough_matches(void)
1076{
1077 compl_T *compl;
1078 int i;
1079
1080 // Don't display the popup menu if there are no matches or there is only
1081 // one (ignoring the original text).
1082 compl = compl_first_match;
1083 i = 0;
1084 do
1085 {
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00001086 if (compl == NULL || (!match_at_original_text(compl) && ++i == 2))
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001087 break;
1088 compl = compl->cp_next;
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00001089 } while (!is_first_match(compl));
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001090
1091 if (strstr((char *)p_cot, "menuone") != NULL)
1092 return (i >= 1);
1093 return (i >= 2);
1094}
1095
Bram Moolenaar3075a452021-11-17 15:51:52 +00001096#if defined(FEAT_EVAL) || defined(PROTO)
Bram Moolenaar9cb698d2019-08-21 15:30:45 +02001097/*
1098 * Allocate Dict for the completed item.
1099 * { word, abbr, menu, kind, info }
1100 */
1101 static dict_T *
1102ins_compl_dict_alloc(compl_T *match)
1103{
1104 dict_T *dict = dict_alloc_lock(VAR_FIXED);
1105
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00001106 if (dict == NULL)
1107 return NULL;
1108
1109 dict_add_string(dict, "word", match->cp_str);
1110 dict_add_string(dict, "abbr", match->cp_text[CPT_ABBR]);
1111 dict_add_string(dict, "menu", match->cp_text[CPT_MENU]);
1112 dict_add_string(dict, "kind", match->cp_text[CPT_KIND]);
1113 dict_add_string(dict, "info", match->cp_text[CPT_INFO]);
1114 if (match->cp_user_data.v_type == VAR_UNKNOWN)
1115 dict_add_string(dict, "user_data", (char_u *)"");
1116 else
1117 dict_add_tv(dict, "user_data", &match->cp_user_data);
1118
Bram Moolenaar9cb698d2019-08-21 15:30:45 +02001119 return dict;
1120}
1121
Yegappan Lakshmanane9825862022-01-03 11:03:48 +00001122/*
1123 * Trigger the CompleteChanged autocmd event. Invoked each time the Insert mode
1124 * completion menu is changed.
1125 */
Bram Moolenaard7f246c2019-04-08 18:15:41 +02001126 static void
1127trigger_complete_changed_event(int cur)
1128{
1129 dict_T *v_event;
1130 dict_T *item;
1131 static int recursive = FALSE;
Bram Moolenaar3075a452021-11-17 15:51:52 +00001132 save_v_event_T save_v_event;
Bram Moolenaard7f246c2019-04-08 18:15:41 +02001133
1134 if (recursive)
1135 return;
1136
Bram Moolenaard7f246c2019-04-08 18:15:41 +02001137 if (cur < 0)
1138 item = dict_alloc();
1139 else
1140 item = ins_compl_dict_alloc(compl_curr_match);
1141 if (item == NULL)
1142 return;
Bram Moolenaar3075a452021-11-17 15:51:52 +00001143 v_event = get_v_event(&save_v_event);
Bram Moolenaard7f246c2019-04-08 18:15:41 +02001144 dict_add_dict(v_event, "completed_item", item);
1145 pum_set_event_info(v_event);
1146 dict_set_items_ro(v_event);
1147
1148 recursive = TRUE;
Bram Moolenaar6adb9ea2020-04-30 22:31:18 +02001149 textwinlock++;
Bram Moolenaard7f246c2019-04-08 18:15:41 +02001150 apply_autocmds(EVENT_COMPLETECHANGED, NULL, NULL, FALSE, curbuf);
Bram Moolenaar6adb9ea2020-04-30 22:31:18 +02001151 textwinlock--;
Bram Moolenaard7f246c2019-04-08 18:15:41 +02001152 recursive = FALSE;
1153
Bram Moolenaar3075a452021-11-17 15:51:52 +00001154 restore_v_event(v_event, &save_v_event);
Bram Moolenaard7f246c2019-04-08 18:15:41 +02001155}
Bram Moolenaar9cb698d2019-08-21 15:30:45 +02001156#endif
Bram Moolenaard7f246c2019-04-08 18:15:41 +02001157
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001158/*
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00001159 * Build a popup menu to show the completion matches.
1160 * Returns the popup menu entry that should be selected. Returns -1 if nothing
1161 * should be selected.
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001162 */
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00001163 static int
1164ins_compl_build_pum(void)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001165{
1166 compl_T *compl;
1167 compl_T *shown_compl = NULL;
1168 int did_find_shown_match = FALSE;
1169 int shown_match_ok = FALSE;
1170 int i;
1171 int cur = -1;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001172 int lead_len = 0;
1173
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00001174 // Need to build the popup menu list.
1175 compl_match_arraysize = 0;
1176 compl = compl_first_match;
1177 if (compl_leader != NULL)
1178 lead_len = (int)STRLEN(compl_leader);
1179
1180 do
1181 {
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00001182 if (!match_at_original_text(compl)
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00001183 && (compl_leader == NULL
1184 || ins_compl_equal(compl, compl_leader, lead_len)))
1185 ++compl_match_arraysize;
1186 compl = compl->cp_next;
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00001187 } while (compl != NULL && !is_first_match(compl));
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00001188
1189 if (compl_match_arraysize == 0)
1190 return -1;
1191
1192 compl_match_array = ALLOC_CLEAR_MULT(pumitem_T, compl_match_arraysize);
1193 if (compl_match_array == NULL)
1194 return -1;
1195
1196 // If the current match is the original text don't find the first
1197 // match after it, don't highlight anything.
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00001198 if (match_at_original_text(compl_shown_match))
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00001199 shown_match_ok = TRUE;
1200
1201 i = 0;
1202 compl = compl_first_match;
1203 do
1204 {
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00001205 if (!match_at_original_text(compl)
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00001206 && (compl_leader == NULL
1207 || ins_compl_equal(compl, compl_leader, lead_len)))
1208 {
1209 if (!shown_match_ok)
1210 {
1211 if (compl == compl_shown_match || did_find_shown_match)
1212 {
1213 // This item is the shown match or this is the
1214 // first displayed item after the shown match.
1215 compl_shown_match = compl;
1216 did_find_shown_match = TRUE;
1217 shown_match_ok = TRUE;
1218 }
1219 else
1220 // Remember this displayed match for when the
1221 // shown match is just below it.
1222 shown_compl = compl;
1223 cur = i;
1224 }
1225
1226 if (compl->cp_text[CPT_ABBR] != NULL)
1227 compl_match_array[i].pum_text =
1228 compl->cp_text[CPT_ABBR];
1229 else
1230 compl_match_array[i].pum_text = compl->cp_str;
1231 compl_match_array[i].pum_kind = compl->cp_text[CPT_KIND];
1232 compl_match_array[i].pum_info = compl->cp_text[CPT_INFO];
1233 if (compl->cp_text[CPT_MENU] != NULL)
1234 compl_match_array[i++].pum_extra =
1235 compl->cp_text[CPT_MENU];
1236 else
1237 compl_match_array[i++].pum_extra = compl->cp_fname;
1238 }
1239
1240 if (compl == compl_shown_match)
1241 {
1242 did_find_shown_match = TRUE;
1243
1244 // When the original text is the shown match don't set
1245 // compl_shown_match.
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00001246 if (match_at_original_text(compl))
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00001247 shown_match_ok = TRUE;
1248
1249 if (!shown_match_ok && shown_compl != NULL)
1250 {
1251 // The shown match isn't displayed, set it to the
1252 // previously displayed match.
1253 compl_shown_match = shown_compl;
1254 shown_match_ok = TRUE;
1255 }
1256 }
1257 compl = compl->cp_next;
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00001258 } while (compl != NULL && !is_first_match(compl));
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00001259
1260 if (!shown_match_ok) // no displayed match at all
1261 cur = -1;
1262
1263 return cur;
1264}
1265
1266/*
1267 * Show the popup menu for the list of matches.
1268 * Also adjusts "compl_shown_match" to an entry that is actually displayed.
1269 */
1270 void
1271ins_compl_show_pum(void)
1272{
1273 int i;
1274 int cur = -1;
1275 colnr_T col;
1276
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001277 if (!pum_wanted() || !pum_enough_matches())
1278 return;
1279
1280#if defined(FEAT_EVAL)
1281 // Dirty hard-coded hack: remove any matchparen highlighting.
Bram Moolenaar179eb562020-12-27 18:03:22 +01001282 do_cmdline_cmd((char_u *)"if exists('g:loaded_matchparen')|:3match none|endif");
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001283#endif
1284
1285 // Update the screen later, before drawing the popup menu over it.
1286 pum_call_update_screen();
1287
1288 if (compl_match_array == NULL)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001289 // Need to build the popup menu list.
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00001290 cur = ins_compl_build_pum();
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001291 else
1292 {
1293 // popup menu already exists, only need to find the current item.
1294 for (i = 0; i < compl_match_arraysize; ++i)
1295 if (compl_match_array[i].pum_text == compl_shown_match->cp_str
1296 || compl_match_array[i].pum_text
1297 == compl_shown_match->cp_text[CPT_ABBR])
1298 {
1299 cur = i;
1300 break;
1301 }
1302 }
1303
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00001304 if (compl_match_array == NULL)
1305 return;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001306
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00001307 // In Replace mode when a $ is displayed at the end of the line only
1308 // part of the screen would be updated. We do need to redraw here.
1309 dollar_vcol = -1;
1310
1311 // Compute the screen column of the start of the completed text.
1312 // Use the cursor to get all wrapping and other settings right.
1313 col = curwin->w_cursor.col;
1314 curwin->w_cursor.col = compl_col;
1315 pum_display(compl_match_array, compl_match_arraysize, cur);
1316 curwin->w_cursor.col = col;
Bram Moolenaard7f246c2019-04-08 18:15:41 +02001317
Bram Moolenaar9cb698d2019-08-21 15:30:45 +02001318#ifdef FEAT_EVAL
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00001319 if (has_completechanged())
1320 trigger_complete_changed_event(cur);
Bram Moolenaar9cb698d2019-08-21 15:30:45 +02001321#endif
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001322}
1323
1324#define DICT_FIRST (1) // use just first element in "dict"
1325#define DICT_EXACT (2) // "dict" is the exact name of a file
1326
1327/*
Yegappan Lakshmanane9825862022-01-03 11:03:48 +00001328 * Add any identifiers that match the given pattern "pat" in the list of
1329 * dictionary files "dict_start" to the list of completions.
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001330 */
1331 static void
1332ins_compl_dictionaries(
1333 char_u *dict_start,
1334 char_u *pat,
1335 int flags, // DICT_FIRST and/or DICT_EXACT
1336 int thesaurus) // Thesaurus completion
1337{
1338 char_u *dict = dict_start;
1339 char_u *ptr;
1340 char_u *buf;
1341 regmatch_T regmatch;
1342 char_u **files;
1343 int count;
1344 int save_p_scs;
1345 int dir = compl_direction;
1346
1347 if (*dict == NUL)
1348 {
1349#ifdef FEAT_SPELL
1350 // When 'dictionary' is empty and spell checking is enabled use
1351 // "spell".
1352 if (!thesaurus && curwin->w_p_spell)
1353 dict = (char_u *)"spell";
1354 else
1355#endif
1356 return;
1357 }
1358
1359 buf = alloc(LSIZE);
1360 if (buf == NULL)
1361 return;
1362 regmatch.regprog = NULL; // so that we can goto theend
1363
1364 // If 'infercase' is set, don't use 'smartcase' here
1365 save_p_scs = p_scs;
1366 if (curbuf->b_p_inf)
1367 p_scs = FALSE;
1368
1369 // When invoked to match whole lines for CTRL-X CTRL-L adjust the pattern
1370 // to only match at the start of a line. Otherwise just match the
1371 // pattern. Also need to double backslashes.
1372 if (ctrl_x_mode_line_or_eval())
1373 {
1374 char_u *pat_esc = vim_strsave_escaped(pat, (char_u *)"\\");
1375 size_t len;
1376
1377 if (pat_esc == NULL)
1378 goto theend;
1379 len = STRLEN(pat_esc) + 10;
Bram Moolenaar964b3742019-05-24 18:54:09 +02001380 ptr = alloc(len);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001381 if (ptr == NULL)
1382 {
1383 vim_free(pat_esc);
1384 goto theend;
1385 }
1386 vim_snprintf((char *)ptr, len, "^\\s*\\zs\\V%s", pat_esc);
1387 regmatch.regprog = vim_regcomp(ptr, RE_MAGIC);
1388 vim_free(pat_esc);
1389 vim_free(ptr);
1390 }
1391 else
1392 {
Bram Moolenaarf4e20992020-12-21 19:59:08 +01001393 regmatch.regprog = vim_regcomp(pat, magic_isset() ? RE_MAGIC : 0);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001394 if (regmatch.regprog == NULL)
1395 goto theend;
1396 }
1397
1398 // ignore case depends on 'ignorecase', 'smartcase' and "pat"
1399 regmatch.rm_ic = ignorecase(pat);
1400 while (*dict != NUL && !got_int && !compl_interrupted)
1401 {
1402 // copy one dictionary file name into buf
1403 if (flags == DICT_EXACT)
1404 {
1405 count = 1;
1406 files = &dict;
1407 }
1408 else
1409 {
1410 // Expand wildcards in the dictionary name, but do not allow
1411 // backticks (for security, the 'dict' option may have been set in
1412 // a modeline).
1413 copy_option_part(&dict, buf, LSIZE, ",");
1414# ifdef FEAT_SPELL
1415 if (!thesaurus && STRCMP(buf, "spell") == 0)
1416 count = -1;
1417 else
1418# endif
1419 if (vim_strchr(buf, '`') != NULL
1420 || expand_wildcards(1, &buf, &count, &files,
1421 EW_FILE|EW_SILENT) != OK)
1422 count = 0;
1423 }
1424
1425# ifdef FEAT_SPELL
1426 if (count == -1)
1427 {
1428 // Complete from active spelling. Skip "\<" in the pattern, we
1429 // don't use it as a RE.
1430 if (pat[0] == '\\' && pat[1] == '<')
1431 ptr = pat + 2;
1432 else
1433 ptr = pat;
1434 spell_dump_compl(ptr, regmatch.rm_ic, &dir, 0);
1435 }
1436 else
1437# endif
1438 if (count > 0) // avoid warning for using "files" uninit
1439 {
1440 ins_compl_files(count, files, thesaurus, flags,
1441 &regmatch, buf, &dir);
1442 if (flags != DICT_EXACT)
1443 FreeWild(count, files);
1444 }
1445 if (flags != 0)
1446 break;
1447 }
1448
1449theend:
1450 p_scs = save_p_scs;
1451 vim_regfree(regmatch.regprog);
1452 vim_free(buf);
1453}
1454
Yegappan Lakshmanane9825862022-01-03 11:03:48 +00001455/*
1456 * Add all the words in the line "*buf_arg" from the thesaurus file "fname"
1457 * skipping the word at 'skip_word'. Returns OK on success.
1458 */
1459 static int
1460thesarurs_add_words_in_line(
1461 char_u *fname,
1462 char_u **buf_arg,
1463 int dir,
1464 char_u *skip_word)
1465{
1466 int status = OK;
1467 char_u *ptr;
1468 char_u *wstart;
1469
1470 // Add the other matches on the line
1471 ptr = *buf_arg;
1472 while (!got_int)
1473 {
1474 // Find start of the next word. Skip white
1475 // space and punctuation.
1476 ptr = find_word_start(ptr);
1477 if (*ptr == NUL || *ptr == NL)
1478 break;
1479 wstart = ptr;
1480
1481 // Find end of the word.
1482 if (has_mbyte)
1483 // Japanese words may have characters in
1484 // different classes, only separate words
1485 // with single-byte non-word characters.
1486 while (*ptr != NUL)
1487 {
1488 int l = (*mb_ptr2len)(ptr);
1489
1490 if (l < 2 && !vim_iswordc(*ptr))
1491 break;
1492 ptr += l;
1493 }
1494 else
1495 ptr = find_word_end(ptr);
1496
1497 // Add the word. Skip the regexp match.
1498 if (wstart != skip_word)
1499 {
1500 status = ins_compl_add_infercase(wstart, (int)(ptr - wstart), p_ic,
1501 fname, dir, FALSE);
1502 if (status == FAIL)
1503 break;
1504 }
1505 }
1506
1507 *buf_arg = ptr;
1508 return status;
1509}
1510
1511/*
1512 * Process "count" dictionary/thesaurus "files" and add the text matching
1513 * "regmatch".
1514 */
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001515 static void
1516ins_compl_files(
1517 int count,
1518 char_u **files,
1519 int thesaurus,
1520 int flags,
1521 regmatch_T *regmatch,
1522 char_u *buf,
1523 int *dir)
1524{
1525 char_u *ptr;
1526 int i;
1527 FILE *fp;
1528 int add_r;
1529
1530 for (i = 0; i < count && !got_int && !compl_interrupted; i++)
1531 {
1532 fp = mch_fopen((char *)files[i], "r"); // open dictionary file
1533 if (flags != DICT_EXACT)
1534 {
Bram Moolenaarcc233582020-12-12 13:32:07 +01001535 msg_hist_off = TRUE; // reset in msg_trunc_attr()
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001536 vim_snprintf((char *)IObuff, IOSIZE,
1537 _("Scanning dictionary: %s"), (char *)files[i]);
1538 (void)msg_trunc_attr((char *)IObuff, TRUE, HL_ATTR(HLF_R));
1539 }
1540
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00001541 if (fp == NULL)
1542 continue;
1543
1544 // Read dictionary file line by line.
1545 // Check each line for a match.
1546 while (!got_int && !compl_interrupted && !vim_fgets(buf, LSIZE, fp))
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001547 {
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00001548 ptr = buf;
1549 while (vim_regexec(regmatch, buf, (colnr_T)(ptr - buf)))
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001550 {
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00001551 ptr = regmatch->startp[0];
1552 if (ctrl_x_mode_line_or_eval())
1553 ptr = find_line_end(ptr);
1554 else
1555 ptr = find_word_end(ptr);
1556 add_r = ins_compl_add_infercase(regmatch->startp[0],
1557 (int)(ptr - regmatch->startp[0]),
1558 p_ic, files[i], *dir, FALSE);
1559 if (thesaurus)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001560 {
Yegappan Lakshmanane9825862022-01-03 11:03:48 +00001561 // For a thesaurus, add all the words in the line
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00001562 ptr = buf;
Yegappan Lakshmanane9825862022-01-03 11:03:48 +00001563 add_r = thesarurs_add_words_in_line(files[i], &ptr, *dir,
1564 regmatch->startp[0]);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001565 }
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00001566 if (add_r == OK)
1567 // if dir was BACKWARD then honor it just once
1568 *dir = FORWARD;
1569 else if (add_r == FAIL)
1570 break;
1571 // avoid expensive call to vim_regexec() when at end
1572 // of line
1573 if (*ptr == '\n' || got_int)
1574 break;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001575 }
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00001576 line_breakcheck();
1577 ins_compl_check_keys(50, FALSE);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001578 }
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00001579 fclose(fp);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001580 }
1581}
1582
1583/*
1584 * Find the start of the next word.
1585 * Returns a pointer to the first char of the word. Also stops at a NUL.
1586 */
1587 char_u *
1588find_word_start(char_u *ptr)
1589{
1590 if (has_mbyte)
1591 while (*ptr != NUL && *ptr != '\n' && mb_get_class(ptr) <= 1)
1592 ptr += (*mb_ptr2len)(ptr);
1593 else
1594 while (*ptr != NUL && *ptr != '\n' && !vim_iswordc(*ptr))
1595 ++ptr;
1596 return ptr;
1597}
1598
1599/*
1600 * Find the end of the word. Assumes it starts inside a word.
1601 * Returns a pointer to just after the word.
1602 */
1603 char_u *
1604find_word_end(char_u *ptr)
1605{
1606 int start_class;
1607
1608 if (has_mbyte)
1609 {
1610 start_class = mb_get_class(ptr);
1611 if (start_class > 1)
1612 while (*ptr != NUL)
1613 {
1614 ptr += (*mb_ptr2len)(ptr);
1615 if (mb_get_class(ptr) != start_class)
1616 break;
1617 }
1618 }
1619 else
1620 while (vim_iswordc(*ptr))
1621 ++ptr;
1622 return ptr;
1623}
1624
1625/*
1626 * Find the end of the line, omitting CR and NL at the end.
1627 * Returns a pointer to just after the line.
1628 */
1629 static char_u *
1630find_line_end(char_u *ptr)
1631{
1632 char_u *s;
1633
1634 s = ptr + STRLEN(ptr);
1635 while (s > ptr && (s[-1] == CAR || s[-1] == NL))
1636 --s;
1637 return s;
1638}
1639
1640/*
1641 * Free the list of completions
1642 */
1643 static void
1644ins_compl_free(void)
1645{
1646 compl_T *match;
1647 int i;
1648
1649 VIM_CLEAR(compl_pattern);
1650 VIM_CLEAR(compl_leader);
1651
1652 if (compl_first_match == NULL)
1653 return;
1654
1655 ins_compl_del_pum();
1656 pum_clear();
1657
1658 compl_curr_match = compl_first_match;
1659 do
1660 {
1661 match = compl_curr_match;
1662 compl_curr_match = compl_curr_match->cp_next;
1663 vim_free(match->cp_str);
1664 // several entries may use the same fname, free it just once.
Bram Moolenaard9eefe32019-04-06 14:22:21 +02001665 if (match->cp_flags & CP_FREE_FNAME)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001666 vim_free(match->cp_fname);
1667 for (i = 0; i < CPT_COUNT; ++i)
1668 vim_free(match->cp_text[i]);
Bram Moolenaarab782c52020-01-04 19:00:11 +01001669#ifdef FEAT_EVAL
Bram Moolenaar08928322020-01-04 14:32:48 +01001670 clear_tv(&match->cp_user_data);
Bram Moolenaarab782c52020-01-04 19:00:11 +01001671#endif
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001672 vim_free(match);
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00001673 } while (compl_curr_match != NULL && !is_first_match(compl_curr_match));
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001674 compl_first_match = compl_curr_match = NULL;
1675 compl_shown_match = NULL;
1676 compl_old_match = NULL;
1677}
1678
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00001679/*
1680 * Reset/clear the completion state.
1681 */
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001682 void
1683ins_compl_clear(void)
1684{
1685 compl_cont_status = 0;
1686 compl_started = FALSE;
1687 compl_matches = 0;
1688 VIM_CLEAR(compl_pattern);
1689 VIM_CLEAR(compl_leader);
1690 edit_submode_extra = NULL;
1691 VIM_CLEAR(compl_orig_text);
1692 compl_enter_selects = FALSE;
Bram Moolenaar9cb698d2019-08-21 15:30:45 +02001693#ifdef FEAT_EVAL
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001694 // clear v:completed_item
1695 set_vim_var_dict(VV_COMPLETED_ITEM, dict_alloc_lock(VAR_FIXED));
Bram Moolenaar9cb698d2019-08-21 15:30:45 +02001696#endif
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001697}
1698
1699/*
1700 * Return TRUE when Insert completion is active.
1701 */
1702 int
1703ins_compl_active(void)
1704{
1705 return compl_started;
1706}
1707
1708/*
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001709 * Selected one of the matches. When FALSE the match was edited or using the
1710 * longest common string.
1711 */
1712 int
1713ins_compl_used_match(void)
1714{
1715 return compl_used_match;
1716}
1717
1718/*
1719 * Initialize get longest common string.
1720 */
1721 void
1722ins_compl_init_get_longest(void)
1723{
1724 compl_get_longest = FALSE;
1725}
1726
1727/*
1728 * Returns TRUE when insert completion is interrupted.
1729 */
1730 int
1731ins_compl_interrupted(void)
1732{
1733 return compl_interrupted;
1734}
1735
1736/*
1737 * Returns TRUE if the <Enter> key selects a match in the completion popup
1738 * menu.
1739 */
1740 int
1741ins_compl_enter_selects(void)
1742{
1743 return compl_enter_selects;
1744}
1745
1746/*
1747 * Return the column where the text starts that is being completed
1748 */
1749 colnr_T
1750ins_compl_col(void)
1751{
1752 return compl_col;
1753}
1754
1755/*
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00001756 * Return the length in bytes of the text being completed
1757 */
1758 int
1759ins_compl_len(void)
1760{
1761 return compl_length;
1762}
1763
1764/*
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001765 * Delete one character before the cursor and show the subset of the matches
1766 * that match the word that is now before the cursor.
1767 * Returns the character to be used, NUL if the work is done and another char
1768 * to be got from the user.
1769 */
1770 int
1771ins_compl_bs(void)
1772{
1773 char_u *line;
1774 char_u *p;
1775
1776 line = ml_get_curline();
1777 p = line + curwin->w_cursor.col;
1778 MB_PTR_BACK(line, p);
1779
1780 // Stop completion when the whole word was deleted. For Omni completion
1781 // allow the word to be deleted, we won't match everything.
1782 // Respect the 'backspace' option.
1783 if ((int)(p - line) - (int)compl_col < 0
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00001784 || ((int)(p - line) - (int)compl_col == 0 && !ctrl_x_mode_omni())
1785 || ctrl_x_mode_eval()
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001786 || (!can_bs(BS_START) && (int)(p - line) - (int)compl_col
1787 - compl_length < 0))
1788 return K_BS;
1789
1790 // Deleted more than what was used to find matches or didn't finish
1791 // finding all matches: need to look for matches all over again.
1792 if (curwin->w_cursor.col <= compl_col + compl_length
1793 || ins_compl_need_restart())
1794 ins_compl_restart();
1795
1796 vim_free(compl_leader);
Bram Moolenaar71ccd032020-06-12 22:59:11 +02001797 compl_leader = vim_strnsave(line + compl_col, (p - line) - compl_col);
Yegappan Lakshmanane9825862022-01-03 11:03:48 +00001798 if (compl_leader == NULL)
1799 return K_BS;
1800
1801 ins_compl_new_leader();
1802 if (compl_shown_match != NULL)
1803 // Make sure current match is not a hidden item.
1804 compl_curr_match = compl_shown_match;
1805 return NUL;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001806}
1807
1808/*
1809 * Return TRUE when we need to find matches again, ins_compl_restart() is to
1810 * be called.
1811 */
1812 static int
1813ins_compl_need_restart(void)
1814{
1815 // Return TRUE if we didn't complete finding matches or when the
1816 // 'completefunc' returned "always" in the "refresh" dictionary item.
1817 return compl_was_interrupted
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00001818 || ((ctrl_x_mode_function() || ctrl_x_mode_omni())
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001819 && compl_opt_refresh_always);
1820}
1821
1822/*
1823 * Called after changing "compl_leader".
1824 * Show the popup menu with a different set of matches.
1825 * May also search for matches again if the previous search was interrupted.
1826 */
1827 static void
1828ins_compl_new_leader(void)
1829{
1830 ins_compl_del_pum();
1831 ins_compl_delete();
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00001832 ins_bytes(compl_leader + get_compl_len());
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001833 compl_used_match = FALSE;
1834
1835 if (compl_started)
1836 ins_compl_set_original_text(compl_leader);
1837 else
1838 {
1839#ifdef FEAT_SPELL
1840 spell_bad_len = 0; // need to redetect bad word
1841#endif
Bram Moolenaar32aa1022019-11-02 22:54:41 +01001842 // Matches were cleared, need to search for them now. Before drawing
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001843 // the popup menu display the changed text before the cursor. Set
1844 // "compl_restarting" to avoid that the first match is inserted.
1845 pum_call_update_screen();
1846#ifdef FEAT_GUI
1847 if (gui.in_use)
1848 {
1849 // Show the cursor after the match, not after the redrawn text.
1850 setcursor();
1851 out_flush_cursor(FALSE, FALSE);
1852 }
1853#endif
1854 compl_restarting = TRUE;
1855 if (ins_complete(Ctrl_N, TRUE) == FAIL)
1856 compl_cont_status = 0;
1857 compl_restarting = FALSE;
1858 }
1859
1860 compl_enter_selects = !compl_used_match;
1861
1862 // Show the popup menu with a different set of matches.
1863 ins_compl_show_pum();
1864
1865 // Don't let Enter select the original text when there is no popup menu.
1866 if (compl_match_array == NULL)
1867 compl_enter_selects = FALSE;
1868}
1869
1870/*
1871 * Return the length of the completion, from the completion start column to
1872 * the cursor column. Making sure it never goes below zero.
1873 */
1874 static int
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00001875get_compl_len(void)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001876{
1877 int off = (int)curwin->w_cursor.col - (int)compl_col;
1878
1879 if (off < 0)
1880 return 0;
1881 return off;
1882}
1883
1884/*
1885 * Append one character to the match leader. May reduce the number of
1886 * matches.
1887 */
1888 void
1889ins_compl_addleader(int c)
1890{
1891 int cc;
1892
1893 if (stop_arrow() == FAIL)
1894 return;
1895 if (has_mbyte && (cc = (*mb_char2len)(c)) > 1)
1896 {
1897 char_u buf[MB_MAXBYTES + 1];
1898
1899 (*mb_char2bytes)(c, buf);
1900 buf[cc] = NUL;
1901 ins_char_bytes(buf, cc);
1902 if (compl_opt_refresh_always)
1903 AppendToRedobuff(buf);
1904 }
1905 else
1906 {
1907 ins_char(c);
1908 if (compl_opt_refresh_always)
1909 AppendCharToRedobuff(c);
1910 }
1911
1912 // If we didn't complete finding matches we must search again.
1913 if (ins_compl_need_restart())
1914 ins_compl_restart();
1915
1916 // When 'always' is set, don't reset compl_leader. While completing,
1917 // cursor doesn't point original position, changing compl_leader would
1918 // break redo.
1919 if (!compl_opt_refresh_always)
1920 {
1921 vim_free(compl_leader);
1922 compl_leader = vim_strnsave(ml_get_curline() + compl_col,
Bram Moolenaar71ccd032020-06-12 22:59:11 +02001923 curwin->w_cursor.col - compl_col);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001924 if (compl_leader != NULL)
1925 ins_compl_new_leader();
1926 }
1927}
1928
1929/*
1930 * Setup for finding completions again without leaving CTRL-X mode. Used when
1931 * BS or a key was typed while still searching for matches.
1932 */
1933 static void
1934ins_compl_restart(void)
1935{
1936 ins_compl_free();
1937 compl_started = FALSE;
1938 compl_matches = 0;
1939 compl_cont_status = 0;
1940 compl_cont_mode = 0;
1941}
1942
1943/*
1944 * Set the first match, the original text.
1945 */
1946 static void
1947ins_compl_set_original_text(char_u *str)
1948{
1949 char_u *p;
1950
1951 // Replace the original text entry.
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00001952 // The CP_ORIGINAL_TEXT flag is either at the first item or might possibly
1953 // be at the last item for backward completion
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00001954 if (match_at_original_text(compl_first_match)) // safety check
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001955 {
1956 p = vim_strsave(str);
1957 if (p != NULL)
1958 {
1959 vim_free(compl_first_match->cp_str);
1960 compl_first_match->cp_str = p;
1961 }
1962 }
1963 else if (compl_first_match->cp_prev != NULL
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00001964 && match_at_original_text(compl_first_match->cp_prev))
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001965 {
1966 p = vim_strsave(str);
1967 if (p != NULL)
1968 {
1969 vim_free(compl_first_match->cp_prev->cp_str);
1970 compl_first_match->cp_prev->cp_str = p;
1971 }
1972 }
1973}
1974
1975/*
1976 * Append one character to the match leader. May reduce the number of
1977 * matches.
1978 */
1979 void
1980ins_compl_addfrommatch(void)
1981{
1982 char_u *p;
1983 int len = (int)curwin->w_cursor.col - (int)compl_col;
1984 int c;
1985 compl_T *cp;
1986
1987 p = compl_shown_match->cp_str;
1988 if ((int)STRLEN(p) <= len) // the match is too short
1989 {
1990 // When still at the original match use the first entry that matches
1991 // the leader.
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00001992 if (!match_at_original_text(compl_shown_match))
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00001993 return;
1994
1995 p = NULL;
1996 for (cp = compl_shown_match->cp_next; cp != NULL
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00001997 && !is_first_match(cp); cp = cp->cp_next)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01001998 {
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00001999 if (compl_leader == NULL
2000 || ins_compl_equal(cp, compl_leader,
2001 (int)STRLEN(compl_leader)))
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002002 {
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00002003 p = cp->cp_str;
2004 break;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002005 }
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002006 }
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00002007 if (p == NULL || (int)STRLEN(p) <= len)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002008 return;
2009 }
2010 p += len;
2011 c = PTR2CHAR(p);
2012 ins_compl_addleader(c);
2013}
2014
2015/*
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00002016 * Set the CTRL-X completion mode based on the key "c" typed after a CTRL-X.
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00002017 * Uses the global variables: ctrl_x_mode, edit_submode, edit_submode_pre,
2018 * compl_cont_mode and compl_cont_status.
2019 * Returns TRUE when the character is not to be inserted.
2020 */
2021 static int
2022set_ctrl_x_mode(int c)
2023{
2024 int retval = FALSE;
2025
2026 switch (c)
2027 {
2028 case Ctrl_E:
2029 case Ctrl_Y:
2030 // scroll the window one line up or down
2031 ctrl_x_mode = CTRL_X_SCROLL;
2032 if (!(State & REPLACE_FLAG))
2033 edit_submode = (char_u *)_(" (insert) Scroll (^E/^Y)");
2034 else
2035 edit_submode = (char_u *)_(" (replace) Scroll (^E/^Y)");
2036 edit_submode_pre = NULL;
2037 showmode();
2038 break;
2039 case Ctrl_L:
2040 // complete whole line
2041 ctrl_x_mode = CTRL_X_WHOLE_LINE;
2042 break;
2043 case Ctrl_F:
2044 // complete filenames
2045 ctrl_x_mode = CTRL_X_FILES;
2046 break;
2047 case Ctrl_K:
2048 // complete words from a dictinoary
2049 ctrl_x_mode = CTRL_X_DICTIONARY;
2050 break;
2051 case Ctrl_R:
2052 // Register insertion without exiting CTRL-X mode
2053 // Simply allow ^R to happen without affecting ^X mode
2054 break;
2055 case Ctrl_T:
2056 // complete words from a thesaurus
2057 ctrl_x_mode = CTRL_X_THESAURUS;
2058 break;
2059#ifdef FEAT_COMPL_FUNC
2060 case Ctrl_U:
2061 // user defined completion
2062 ctrl_x_mode = CTRL_X_FUNCTION;
2063 break;
2064 case Ctrl_O:
2065 // omni completion
2066 ctrl_x_mode = CTRL_X_OMNI;
2067 break;
2068#endif
2069 case 's':
2070 case Ctrl_S:
2071 // complete spelling suggestions
2072 ctrl_x_mode = CTRL_X_SPELL;
2073#ifdef FEAT_SPELL
2074 ++emsg_off; // Avoid getting the E756 error twice.
2075 spell_back_to_badword();
2076 --emsg_off;
2077#endif
2078 break;
2079 case Ctrl_RSB:
2080 // complete tag names
2081 ctrl_x_mode = CTRL_X_TAGS;
2082 break;
2083#ifdef FEAT_FIND_ID
2084 case Ctrl_I:
2085 case K_S_TAB:
2086 // complete keywords from included files
2087 ctrl_x_mode = CTRL_X_PATH_PATTERNS;
2088 break;
2089 case Ctrl_D:
2090 // complete definitions from included files
2091 ctrl_x_mode = CTRL_X_PATH_DEFINES;
2092 break;
2093#endif
2094 case Ctrl_V:
2095 case Ctrl_Q:
2096 // complete vim commands
2097 ctrl_x_mode = CTRL_X_CMDLINE;
2098 break;
2099 case Ctrl_Z:
2100 // stop completion
2101 ctrl_x_mode = CTRL_X_NORMAL;
2102 edit_submode = NULL;
2103 showmode();
2104 retval = TRUE;
2105 break;
2106 case Ctrl_P:
2107 case Ctrl_N:
2108 // ^X^P means LOCAL expansion if nothing interrupted (eg we
2109 // just started ^X mode, or there were enough ^X's to cancel
2110 // the previous mode, say ^X^F^X^X^P or ^P^X^X^X^P, see below)
2111 // do normal expansion when interrupting a different mode (say
2112 // ^X^F^X^P or ^P^X^X^P, see below)
2113 // nothing changes if interrupting mode 0, (eg, the flag
2114 // doesn't change when going to ADDING mode -- Acevedo
2115 if (!(compl_cont_status & CONT_INTRPT))
2116 compl_cont_status |= CONT_LOCAL;
2117 else if (compl_cont_mode != 0)
2118 compl_cont_status &= ~CONT_LOCAL;
2119 // FALLTHROUGH
2120 default:
2121 // If we have typed at least 2 ^X's... for modes != 0, we set
2122 // compl_cont_status = 0 (eg, as if we had just started ^X
2123 // mode).
2124 // For mode 0, we set "compl_cont_mode" to an impossible
2125 // value, in both cases ^X^X can be used to restart the same
2126 // mode (avoiding ADDING mode).
2127 // Undocumented feature: In a mode != 0 ^X^P and ^X^X^P start
2128 // 'complete' and local ^P expansions respectively.
2129 // In mode 0 an extra ^X is needed since ^X^P goes to ADDING
2130 // mode -- Acevedo
2131 if (c == Ctrl_X)
2132 {
2133 if (compl_cont_mode != 0)
2134 compl_cont_status = 0;
2135 else
2136 compl_cont_mode = CTRL_X_NOT_DEFINED_YET;
2137 }
2138 ctrl_x_mode = CTRL_X_NORMAL;
2139 edit_submode = NULL;
2140 showmode();
2141 break;
2142 }
2143
2144 return retval;
2145}
2146
2147/*
2148 * Stop insert completion mode
2149 */
2150 static int
2151ins_compl_stop(int c, int prev_mode, int retval)
2152{
2153 char_u *ptr;
2154#ifdef FEAT_CINDENT
2155 int want_cindent;
2156#endif
2157
2158 // Get here when we have finished typing a sequence of ^N and
2159 // ^P or other completion characters in CTRL-X mode. Free up
2160 // memory that was used, and make sure we can redo the insert.
2161 if (compl_curr_match != NULL || compl_leader != NULL || c == Ctrl_E)
2162 {
2163 // If any of the original typed text has been changed, eg when
2164 // ignorecase is set, we must add back-spaces to the redo
2165 // buffer. We add as few as necessary to delete just the part
2166 // of the original text that has changed.
2167 // When using the longest match, edited the match or used
2168 // CTRL-E then don't use the current match.
2169 if (compl_curr_match != NULL && compl_used_match && c != Ctrl_E)
2170 ptr = compl_curr_match->cp_str;
2171 else
2172 ptr = NULL;
2173 ins_compl_fixRedoBufForLeader(ptr);
2174 }
2175
2176#ifdef FEAT_CINDENT
2177 want_cindent = (get_can_cindent() && cindent_on());
2178#endif
2179 // When completing whole lines: fix indent for 'cindent'.
2180 // Otherwise, break line if it's too long.
2181 if (compl_cont_mode == CTRL_X_WHOLE_LINE)
2182 {
2183#ifdef FEAT_CINDENT
2184 // re-indent the current line
2185 if (want_cindent)
2186 {
2187 do_c_expr_indent();
2188 want_cindent = FALSE; // don't do it again
2189 }
2190#endif
2191 }
2192 else
2193 {
2194 int prev_col = curwin->w_cursor.col;
2195
2196 // put the cursor on the last char, for 'tw' formatting
2197 if (prev_col > 0)
2198 dec_cursor();
2199 // only format when something was inserted
2200 if (!arrow_used && !ins_need_undo_get() && c != Ctrl_E)
2201 insertchar(NUL, 0, -1);
2202 if (prev_col > 0
2203 && ml_get_curline()[curwin->w_cursor.col] != NUL)
2204 inc_cursor();
2205 }
2206
2207 // If the popup menu is displayed pressing CTRL-Y means accepting
2208 // the selection without inserting anything. When
2209 // compl_enter_selects is set the Enter key does the same.
2210 if ((c == Ctrl_Y || (compl_enter_selects
2211 && (c == CAR || c == K_KENTER || c == NL)))
2212 && pum_visible())
2213 retval = TRUE;
2214
2215 // CTRL-E means completion is Ended, go back to the typed text.
2216 // but only do this, if the Popup is still visible
2217 if (c == Ctrl_E)
2218 {
2219 ins_compl_delete();
2220 if (compl_leader != NULL)
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00002221 ins_bytes(compl_leader + get_compl_len());
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00002222 else if (compl_first_match != NULL)
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00002223 ins_bytes(compl_orig_text + get_compl_len());
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00002224 retval = TRUE;
2225 }
2226
2227 auto_format(FALSE, TRUE);
2228
2229 // Trigger the CompleteDonePre event to give scripts a chance to
2230 // act upon the completion before clearing the info, and restore
2231 // ctrl_x_mode, so that complete_info() can be used.
2232 ctrl_x_mode = prev_mode;
2233 ins_apply_autocmds(EVENT_COMPLETEDONEPRE);
2234
2235 ins_compl_free();
2236 compl_started = FALSE;
2237 compl_matches = 0;
2238 if (!shortmess(SHM_COMPLETIONMENU))
2239 msg_clr_cmdline(); // necessary for "noshowmode"
2240 ctrl_x_mode = CTRL_X_NORMAL;
2241 compl_enter_selects = FALSE;
2242 if (edit_submode != NULL)
2243 {
2244 edit_submode = NULL;
2245 showmode();
2246 }
2247
2248#ifdef FEAT_CMDWIN
2249 if (c == Ctrl_C && cmdwin_type != 0)
2250 // Avoid the popup menu remains displayed when leaving the
2251 // command line window.
2252 update_screen(0);
2253#endif
2254#ifdef FEAT_CINDENT
2255 // Indent now if a key was typed that is in 'cinkeys'.
2256 if (want_cindent && in_cinkeys(KEY_COMPLETE, ' ', inindent(0)))
2257 do_c_expr_indent();
2258#endif
2259 // Trigger the CompleteDone event to give scripts a chance to act
2260 // upon the end of completion.
2261 ins_apply_autocmds(EVENT_COMPLETEDONE);
2262
2263 return retval;
2264}
2265
2266/*
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002267 * Prepare for Insert mode completion, or stop it.
2268 * Called just after typing a character in Insert mode.
2269 * Returns TRUE when the character is not to be inserted;
2270 */
2271 int
2272ins_compl_prep(int c)
2273{
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002274 int retval = FALSE;
Bram Moolenaar17e04782020-01-17 18:58:59 +01002275 int prev_mode = ctrl_x_mode;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002276
2277 // Forget any previous 'special' messages if this is actually
2278 // a ^X mode key - bar ^R, in which case we wait to see what it gives us.
2279 if (c != Ctrl_R && vim_is_ctrl_x_key(c))
2280 edit_submode_extra = NULL;
2281
2282 // Ignore end of Select mode mapping and mouse scroll buttons.
2283 if (c == K_SELECT || c == K_MOUSEDOWN || c == K_MOUSEUP
Bram Moolenaar957cf672020-11-12 14:21:06 +01002284 || c == K_MOUSELEFT || c == K_MOUSERIGHT || c == K_COMMAND)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002285 return retval;
2286
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01002287#ifdef FEAT_PROP_POPUP
Bram Moolenaarf0bc15c2019-08-18 19:23:45 +02002288 // Ignore mouse events in a popup window
2289 if (is_mouse_key(c))
2290 {
2291 // Ignore drag and release events, the position does not need to be in
2292 // the popup and it may have just closed.
2293 if (c == K_LEFTRELEASE
2294 || c == K_LEFTRELEASE_NM
2295 || c == K_MIDDLERELEASE
2296 || c == K_RIGHTRELEASE
2297 || c == K_X1RELEASE
2298 || c == K_X2RELEASE
2299 || c == K_LEFTDRAG
2300 || c == K_MIDDLEDRAG
2301 || c == K_RIGHTDRAG
2302 || c == K_X1DRAG
2303 || c == K_X2DRAG)
2304 return retval;
2305 if (popup_visible)
2306 {
2307 int row = mouse_row;
2308 int col = mouse_col;
2309 win_T *wp = mouse_find_win(&row, &col, FIND_POPUP);
2310
2311 if (wp != NULL && WIN_IS_POPUP(wp))
2312 return retval;
2313 }
2314 }
2315#endif
2316
zeertzjqdca29d92021-08-31 19:12:51 +02002317 if (ctrl_x_mode == CTRL_X_CMDLINE_CTRL_X && c != Ctrl_X)
2318 {
2319 if (c == Ctrl_V || c == Ctrl_Q || c == Ctrl_Z || ins_compl_pum_key(c)
2320 || !vim_is_ctrl_x_key(c))
2321 {
2322 // Not starting another completion mode.
2323 ctrl_x_mode = CTRL_X_CMDLINE;
2324
2325 // CTRL-X CTRL-Z should stop completion without inserting anything
2326 if (c == Ctrl_Z)
2327 retval = TRUE;
2328 }
2329 else
2330 {
2331 ctrl_x_mode = CTRL_X_CMDLINE;
2332
2333 // Other CTRL-X keys first stop completion, then start another
2334 // completion mode.
2335 ins_compl_prep(' ');
2336 ctrl_x_mode = CTRL_X_NOT_DEFINED_YET;
2337 }
2338 }
2339
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002340 // Set "compl_get_longest" when finding the first matches.
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00002341 if (ctrl_x_mode_not_defined_yet()
2342 || (ctrl_x_mode_normal() && !compl_started))
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002343 {
2344 compl_get_longest = (strstr((char *)p_cot, "longest") != NULL);
2345 compl_used_match = TRUE;
2346
2347 }
2348
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00002349 if (ctrl_x_mode_not_defined_yet())
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002350 // We have just typed CTRL-X and aren't quite sure which CTRL-X mode
2351 // it will be yet. Now we decide.
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00002352 retval = set_ctrl_x_mode(c);
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00002353 else if (ctrl_x_mode_not_default())
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002354 {
2355 // We're already in CTRL-X mode, do we stay in it?
2356 if (!vim_is_ctrl_x_key(c))
2357 {
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00002358 if (ctrl_x_mode_scroll())
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002359 ctrl_x_mode = CTRL_X_NORMAL;
2360 else
2361 ctrl_x_mode = CTRL_X_FINISHED;
2362 edit_submode = NULL;
2363 }
2364 showmode();
2365 }
2366
2367 if (compl_started || ctrl_x_mode == CTRL_X_FINISHED)
2368 {
2369 // Show error message from attempted keyword completion (probably
2370 // 'Pattern not found') until another key is hit, then go back to
2371 // showing what mode we are in.
2372 showmode();
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00002373 if ((ctrl_x_mode_normal() && c != Ctrl_N && c != Ctrl_P
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002374 && c != Ctrl_R && !ins_compl_pum_key(c))
2375 || ctrl_x_mode == CTRL_X_FINISHED)
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00002376 retval = ins_compl_stop(c, prev_mode, retval);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002377 }
2378 else if (ctrl_x_mode == CTRL_X_LOCAL_MSG)
2379 // Trigger the CompleteDone event to give scripts a chance to act
2380 // upon the (possibly failed) completion.
2381 ins_apply_autocmds(EVENT_COMPLETEDONE);
2382
=?UTF-8?q?Magnus=20Gro=C3=9F?=25def2c2021-10-22 18:56:39 +01002383 trigger_modechanged();
2384
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002385 // reset continue_* if we left expansion-mode, if we stay they'll be
2386 // (re)set properly in ins_complete()
2387 if (!vim_is_ctrl_x_key(c))
2388 {
2389 compl_cont_status = 0;
2390 compl_cont_mode = 0;
2391 }
2392
2393 return retval;
2394}
2395
2396/*
2397 * Fix the redo buffer for the completion leader replacing some of the typed
2398 * text. This inserts backspaces and appends the changed text.
2399 * "ptr" is the known leader text or NUL.
2400 */
2401 static void
2402ins_compl_fixRedoBufForLeader(char_u *ptr_arg)
2403{
2404 int len;
2405 char_u *p;
2406 char_u *ptr = ptr_arg;
2407
2408 if (ptr == NULL)
2409 {
2410 if (compl_leader != NULL)
2411 ptr = compl_leader;
2412 else
2413 return; // nothing to do
2414 }
2415 if (compl_orig_text != NULL)
2416 {
2417 p = compl_orig_text;
2418 for (len = 0; p[len] != NUL && p[len] == ptr[len]; ++len)
2419 ;
2420 if (len > 0)
2421 len -= (*mb_head_off)(p, p + len);
2422 for (p += len; *p != NUL; MB_PTR_ADV(p))
2423 AppendCharToRedobuff(K_BS);
2424 }
2425 else
2426 len = 0;
2427 if (ptr != NULL)
2428 AppendToRedobuffLit(ptr + len, -1);
2429}
2430
2431/*
2432 * Loops through the list of windows, loaded-buffers or non-loaded-buffers
2433 * (depending on flag) starting from buf and looking for a non-scanned
2434 * buffer (other than curbuf). curbuf is special, if it is called with
2435 * buf=curbuf then it has to be the first call for a given flag/expansion.
2436 *
2437 * Returns the buffer to scan, if any, otherwise returns curbuf -- Acevedo
2438 */
2439 static buf_T *
2440ins_compl_next_buf(buf_T *buf, int flag)
2441{
2442 static win_T *wp = NULL;
2443
2444 if (flag == 'w') // just windows
2445 {
2446 if (buf == curbuf || wp == NULL) // first call for this flag/expansion
2447 wp = curwin;
2448 while ((wp = (wp->w_next != NULL ? wp->w_next : firstwin)) != curwin
2449 && wp->w_buffer->b_scanned)
2450 ;
2451 buf = wp->w_buffer;
2452 }
2453 else
2454 // 'b' (just loaded buffers), 'u' (just non-loaded buffers) or 'U'
2455 // (unlisted buffers)
2456 // When completing whole lines skip unloaded buffers.
2457 while ((buf = (buf->b_next != NULL ? buf->b_next : firstbuf)) != curbuf
2458 && ((flag == 'U'
2459 ? buf->b_p_bl
2460 : (!buf->b_p_bl
2461 || (buf->b_ml.ml_mfp == NULL) != (flag == 'u')))
2462 || buf->b_scanned))
2463 ;
2464 return buf;
2465}
2466
2467#ifdef FEAT_COMPL_FUNC
Yegappan Lakshmanan8658c752021-12-03 11:09:29 +00002468
2469# ifdef FEAT_EVAL
2470static callback_T cfu_cb; // 'completefunc' callback function
2471static callback_T ofu_cb; // 'omnifunc' callback function
2472static callback_T tsrfu_cb; // 'thesaurusfunc' callback function
2473# endif
2474
2475/*
2476 * Copy a global callback function to a buffer local callback.
2477 */
2478 static void
2479copy_global_to_buflocal_cb(callback_T *globcb, callback_T *bufcb)
2480{
2481 free_callback(bufcb);
2482 if (globcb->cb_name != NULL && *globcb->cb_name != NUL)
2483 copy_callback(bufcb, globcb);
2484}
2485
2486/*
2487 * Parse the 'completefunc' option value and set the callback function.
2488 * Invoked when the 'completefunc' option is set. The option value can be a
2489 * name of a function (string), or function(<name>) or funcref(<name>) or a
2490 * lambda expression.
2491 */
2492 int
2493set_completefunc_option(void)
2494{
2495 int retval;
2496
2497 retval = option_set_callback_func(curbuf->b_p_cfu, &cfu_cb);
2498 if (retval == OK)
2499 set_buflocal_cfu_callback(curbuf);
2500
2501 return retval;
2502}
2503
2504/*
2505 * Copy the global 'completefunc' callback function to the buffer-local
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00002506 * 'completefunc' callback for "buf".
Yegappan Lakshmanan8658c752021-12-03 11:09:29 +00002507 */
2508 void
2509set_buflocal_cfu_callback(buf_T *buf UNUSED)
2510{
2511# ifdef FEAT_EVAL
2512 copy_global_to_buflocal_cb(&cfu_cb, &buf->b_cfu_cb);
2513# endif
2514}
2515
2516/*
2517 * Parse the 'omnifunc' option value and set the callback function.
2518 * Invoked when the 'omnifunc' option is set. The option value can be a
2519 * name of a function (string), or function(<name>) or funcref(<name>) or a
2520 * lambda expression.
2521 */
2522 int
2523set_omnifunc_option(void)
2524{
2525 int retval;
2526
2527 retval = option_set_callback_func(curbuf->b_p_ofu, &ofu_cb);
2528 if (retval == OK)
2529 set_buflocal_ofu_callback(curbuf);
2530
2531 return retval;
2532}
2533
2534/*
2535 * Copy the global 'omnifunc' callback function to the buffer-local 'omnifunc'
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00002536 * callback for "buf".
Yegappan Lakshmanan8658c752021-12-03 11:09:29 +00002537 */
2538 void
2539set_buflocal_ofu_callback(buf_T *buf UNUSED)
2540{
2541# ifdef FEAT_EVAL
2542 copy_global_to_buflocal_cb(&ofu_cb, &buf->b_ofu_cb);
2543# endif
2544}
2545
2546/*
2547 * Parse the 'thesaurusfunc' option value and set the callback function.
2548 * Invoked when the 'thesaurusfunc' option is set. The option value can be a
2549 * name of a function (string), or function(<name>) or funcref(<name>) or a
2550 * lambda expression.
2551 */
2552 int
2553set_thesaurusfunc_option(void)
2554{
2555 int retval;
2556
2557 if (*curbuf->b_p_tsrfu != NUL)
2558 {
2559 // buffer-local option set
Yegappan Lakshmanan8658c752021-12-03 11:09:29 +00002560 retval = option_set_callback_func(curbuf->b_p_tsrfu,
2561 &curbuf->b_tsrfu_cb);
2562 }
2563 else
2564 {
2565 // global option set
Yegappan Lakshmanan8658c752021-12-03 11:09:29 +00002566 retval = option_set_callback_func(p_tsrfu, &tsrfu_cb);
2567 }
2568
2569 return retval;
2570}
2571
Yegappan Lakshmanan6ae8fae2021-12-12 16:26:44 +00002572/*
2573 * Mark the global 'completefunc' 'omnifunc' and 'thesaurusfunc' callbacks with
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00002574 * "copyID" so that they are not garbage collected.
Yegappan Lakshmanan6ae8fae2021-12-12 16:26:44 +00002575 */
2576 int
2577set_ref_in_insexpand_funcs(int copyID)
2578{
2579 int abort = FALSE;
2580
2581 abort = set_ref_in_callback(&cfu_cb, copyID);
2582 abort = abort || set_ref_in_callback(&ofu_cb, copyID);
2583 abort = abort || set_ref_in_callback(&tsrfu_cb, copyID);
2584
2585 return abort;
2586}
Yegappan Lakshmanan8658c752021-12-03 11:09:29 +00002587
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002588/*
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00002589 * Get the user-defined completion function name for completion "type"
Yegappan Lakshmanan160e9942021-10-16 15:41:29 +01002590 */
2591 static char_u *
2592get_complete_funcname(int type)
2593{
2594 switch (type)
2595 {
2596 case CTRL_X_FUNCTION:
2597 return curbuf->b_p_cfu;
2598 case CTRL_X_OMNI:
2599 return curbuf->b_p_ofu;
2600 case CTRL_X_THESAURUS:
Bram Moolenaarf4d8b762021-10-17 14:13:09 +01002601 return *curbuf->b_p_tsrfu == NUL ? p_tsrfu : curbuf->b_p_tsrfu;
Yegappan Lakshmanan160e9942021-10-16 15:41:29 +01002602 default:
2603 return (char_u *)"";
2604 }
2605}
2606
2607/*
Yegappan Lakshmanan8658c752021-12-03 11:09:29 +00002608 * Get the callback to use for insert mode completion.
2609 */
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00002610 static callback_T *
Yegappan Lakshmanan8658c752021-12-03 11:09:29 +00002611get_insert_callback(int type)
2612{
2613 if (type == CTRL_X_FUNCTION)
2614 return &curbuf->b_cfu_cb;
2615 if (type == CTRL_X_OMNI)
2616 return &curbuf->b_ofu_cb;
2617 // CTRL_X_THESAURUS
2618 return (*curbuf->b_p_tsrfu != NUL) ? &curbuf->b_tsrfu_cb : &tsrfu_cb;
2619}
2620
2621/*
Yegappan Lakshmanan05e59e32021-12-01 10:30:07 +00002622 * Execute user defined complete function 'completefunc', 'omnifunc' or
2623 * 'thesaurusfunc', and get matches in "matches".
2624 * "type" is either CTRL_X_OMNI or CTRL_X_FUNCTION or CTRL_X_THESAURUS.
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002625 */
2626 static void
Yegappan Lakshmanan05e59e32021-12-01 10:30:07 +00002627expand_by_function(int type, char_u *base)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002628{
2629 list_T *matchlist = NULL;
2630 dict_T *matchdict = NULL;
2631 typval_T args[3];
2632 char_u *funcname;
2633 pos_T pos;
Yegappan Lakshmanan8658c752021-12-03 11:09:29 +00002634 callback_T *cb;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002635 typval_T rettv;
2636 int save_State = State;
Yegappan Lakshmanan8658c752021-12-03 11:09:29 +00002637 int retval;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002638
Yegappan Lakshmanan160e9942021-10-16 15:41:29 +01002639 funcname = get_complete_funcname(type);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002640 if (*funcname == NUL)
2641 return;
2642
2643 // Call 'completefunc' to obtain the list of matches.
2644 args[0].v_type = VAR_NUMBER;
2645 args[0].vval.v_number = 0;
2646 args[1].v_type = VAR_STRING;
2647 args[1].vval.v_string = base != NULL ? base : (char_u *)"";
2648 args[2].v_type = VAR_UNKNOWN;
2649
2650 pos = curwin->w_cursor;
Bram Moolenaar28976e22021-01-29 21:07:07 +01002651 // Lock the text to avoid weird things from happening. Also disallow
2652 // switching to another window, it should not be needed and may end up in
2653 // Insert mode in another buffer.
2654 ++textwinlock;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002655
Yegappan Lakshmanan8658c752021-12-03 11:09:29 +00002656 cb = get_insert_callback(type);
2657 retval = call_callback(cb, 0, &rettv, 2, args);
2658
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002659 // Call a function, which returns a list or dict.
Yegappan Lakshmanan8658c752021-12-03 11:09:29 +00002660 if (retval == OK)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002661 {
2662 switch (rettv.v_type)
2663 {
2664 case VAR_LIST:
2665 matchlist = rettv.vval.v_list;
2666 break;
2667 case VAR_DICT:
2668 matchdict = rettv.vval.v_dict;
2669 break;
2670 case VAR_SPECIAL:
2671 if (rettv.vval.v_number == VVAL_NONE)
2672 compl_opt_suppress_empty = TRUE;
2673 // FALLTHROUGH
2674 default:
2675 // TODO: Give error message?
2676 clear_tv(&rettv);
2677 break;
2678 }
2679 }
Bram Moolenaar28976e22021-01-29 21:07:07 +01002680 --textwinlock;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002681
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002682 curwin->w_cursor = pos; // restore the cursor position
2683 validate_cursor();
2684 if (!EQUAL_POS(curwin->w_cursor, pos))
2685 {
Bram Moolenaar9d00e4a2022-01-05 17:49:15 +00002686 emsg(_(e_complete_function_deleted_text));
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002687 goto theend;
2688 }
2689
2690 if (matchlist != NULL)
2691 ins_compl_add_list(matchlist);
2692 else if (matchdict != NULL)
2693 ins_compl_add_dict(matchdict);
2694
2695theend:
2696 // Restore State, it might have been changed.
2697 State = save_State;
2698
2699 if (matchdict != NULL)
2700 dict_unref(matchdict);
2701 if (matchlist != NULL)
2702 list_unref(matchlist);
2703}
2704#endif // FEAT_COMPL_FUNC
2705
2706#if defined(FEAT_COMPL_FUNC) || defined(FEAT_EVAL) || defined(PROTO)
2707/*
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02002708 * Add a match to the list of matches from a typeval_T.
2709 * If the given string is already in the list of completions, then return
2710 * NOTDONE, otherwise add it to the list and return OK. If there is an error,
2711 * maybe because alloc() returns NULL, then FAIL is returned.
Bram Moolenaar440cf092021-04-03 20:13:30 +02002712 * When "fast" is TRUE use fast_breakcheck() instead of ui_breakcheck().
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02002713 */
2714 static int
Bram Moolenaar440cf092021-04-03 20:13:30 +02002715ins_compl_add_tv(typval_T *tv, int dir, int fast)
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02002716{
2717 char_u *word;
2718 int dup = FALSE;
2719 int empty = FALSE;
Bram Moolenaar440cf092021-04-03 20:13:30 +02002720 int flags = fast ? CP_FAST : 0;
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02002721 char_u *(cptext[CPT_COUNT]);
Bram Moolenaar08928322020-01-04 14:32:48 +01002722 typval_T user_data;
Yegappan Lakshmanan37079142022-01-08 10:38:48 +00002723 int status;
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02002724
Bram Moolenaar08928322020-01-04 14:32:48 +01002725 user_data.v_type = VAR_UNKNOWN;
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02002726 if (tv->v_type == VAR_DICT && tv->vval.v_dict != NULL)
2727 {
2728 word = dict_get_string(tv->vval.v_dict, (char_u *)"word", FALSE);
2729 cptext[CPT_ABBR] = dict_get_string(tv->vval.v_dict,
2730 (char_u *)"abbr", FALSE);
2731 cptext[CPT_MENU] = dict_get_string(tv->vval.v_dict,
2732 (char_u *)"menu", FALSE);
2733 cptext[CPT_KIND] = dict_get_string(tv->vval.v_dict,
2734 (char_u *)"kind", FALSE);
2735 cptext[CPT_INFO] = dict_get_string(tv->vval.v_dict,
2736 (char_u *)"info", FALSE);
Bram Moolenaar08928322020-01-04 14:32:48 +01002737 dict_get_tv(tv->vval.v_dict, (char_u *)"user_data", &user_data);
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02002738 if (dict_get_string(tv->vval.v_dict, (char_u *)"icase", FALSE) != NULL
2739 && dict_get_number(tv->vval.v_dict, (char_u *)"icase"))
2740 flags |= CP_ICASE;
2741 if (dict_get_string(tv->vval.v_dict, (char_u *)"dup", FALSE) != NULL)
2742 dup = dict_get_number(tv->vval.v_dict, (char_u *)"dup");
2743 if (dict_get_string(tv->vval.v_dict, (char_u *)"empty", FALSE) != NULL)
2744 empty = dict_get_number(tv->vval.v_dict, (char_u *)"empty");
2745 if (dict_get_string(tv->vval.v_dict, (char_u *)"equal", FALSE) != NULL
2746 && dict_get_number(tv->vval.v_dict, (char_u *)"equal"))
2747 flags |= CP_EQUAL;
2748 }
2749 else
2750 {
2751 word = tv_get_string_chk(tv);
Bram Moolenaara80faa82020-04-12 19:37:17 +02002752 CLEAR_FIELD(cptext);
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02002753 }
2754 if (word == NULL || (!empty && *word == NUL))
Yegappan Lakshmanan37079142022-01-08 10:38:48 +00002755 {
2756 clear_tv(&user_data);
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02002757 return FAIL;
Yegappan Lakshmanan37079142022-01-08 10:38:48 +00002758 }
2759 status = ins_compl_add(word, -1, NULL, cptext, &user_data, dir, flags, dup);
2760 if (status != OK)
2761 clear_tv(&user_data);
2762 return status;
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02002763}
2764
2765/*
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002766 * Add completions from a list.
2767 */
2768 static void
2769ins_compl_add_list(list_T *list)
2770{
2771 listitem_T *li;
2772 int dir = compl_direction;
2773
2774 // Go through the List with matches and add each of them.
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02002775 CHECK_LIST_MATERIALIZE(list);
Bram Moolenaaraeea7212020-04-02 18:50:46 +02002776 FOR_ALL_LIST_ITEMS(list, li)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002777 {
Bram Moolenaar440cf092021-04-03 20:13:30 +02002778 if (ins_compl_add_tv(&li->li_tv, dir, TRUE) == OK)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002779 // if dir was BACKWARD then honor it just once
2780 dir = FORWARD;
2781 else if (did_emsg)
2782 break;
2783 }
2784}
2785
2786/*
2787 * Add completions from a dict.
2788 */
2789 static void
2790ins_compl_add_dict(dict_T *dict)
2791{
2792 dictitem_T *di_refresh;
2793 dictitem_T *di_words;
2794
2795 // Check for optional "refresh" item.
2796 compl_opt_refresh_always = FALSE;
2797 di_refresh = dict_find(dict, (char_u *)"refresh", 7);
2798 if (di_refresh != NULL && di_refresh->di_tv.v_type == VAR_STRING)
2799 {
2800 char_u *v = di_refresh->di_tv.vval.v_string;
2801
2802 if (v != NULL && STRCMP(v, (char_u *)"always") == 0)
2803 compl_opt_refresh_always = TRUE;
2804 }
2805
2806 // Add completions from a "words" list.
2807 di_words = dict_find(dict, (char_u *)"words", 5);
2808 if (di_words != NULL && di_words->di_tv.v_type == VAR_LIST)
2809 ins_compl_add_list(di_words->di_tv.vval.v_list);
2810}
2811
2812/*
Bram Moolenaar9cb698d2019-08-21 15:30:45 +02002813 * Start completion for the complete() function.
2814 * "startcol" is where the matched text starts (1 is first column).
2815 * "list" is the list of matches.
2816 */
2817 static void
2818set_completion(colnr_T startcol, list_T *list)
2819{
2820 int save_w_wrow = curwin->w_wrow;
2821 int save_w_leftcol = curwin->w_leftcol;
2822 int flags = CP_ORIGINAL_TEXT;
2823
2824 // If already doing completions stop it.
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00002825 if (ctrl_x_mode_not_default())
Bram Moolenaar9cb698d2019-08-21 15:30:45 +02002826 ins_compl_prep(' ');
2827 ins_compl_clear();
2828 ins_compl_free();
2829
2830 compl_direction = FORWARD;
2831 if (startcol > curwin->w_cursor.col)
2832 startcol = curwin->w_cursor.col;
2833 compl_col = startcol;
2834 compl_length = (int)curwin->w_cursor.col - (int)startcol;
2835 // compl_pattern doesn't need to be set
2836 compl_orig_text = vim_strnsave(ml_get_curline() + compl_col, compl_length);
2837 if (p_ic)
2838 flags |= CP_ICASE;
2839 if (compl_orig_text == NULL || ins_compl_add(compl_orig_text,
Bram Moolenaar440cf092021-04-03 20:13:30 +02002840 -1, NULL, NULL, NULL, 0,
2841 flags | CP_FAST, FALSE) != OK)
Bram Moolenaar9cb698d2019-08-21 15:30:45 +02002842 return;
2843
2844 ctrl_x_mode = CTRL_X_EVAL;
2845
2846 ins_compl_add_list(list);
2847 compl_matches = ins_compl_make_cyclic();
2848 compl_started = TRUE;
2849 compl_used_match = TRUE;
2850 compl_cont_status = 0;
2851
2852 compl_curr_match = compl_first_match;
2853 if (compl_no_insert || compl_no_select)
2854 {
2855 ins_complete(K_DOWN, FALSE);
2856 if (compl_no_select)
2857 // Down/Up has no real effect.
2858 ins_complete(K_UP, FALSE);
2859 }
2860 else
2861 ins_complete(Ctrl_N, FALSE);
2862 compl_enter_selects = compl_no_insert;
2863
2864 // Lazily show the popup menu, unless we got interrupted.
2865 if (!compl_interrupted)
2866 show_pum(save_w_wrow, save_w_leftcol);
=?UTF-8?q?Magnus=20Gro=C3=9F?=25def2c2021-10-22 18:56:39 +01002867 trigger_modechanged();
Bram Moolenaar9cb698d2019-08-21 15:30:45 +02002868 out_flush();
2869}
2870
2871/*
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02002872 * "complete()" function
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002873 */
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02002874 void
2875f_complete(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002876{
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02002877 int startcol;
Bram Moolenaarff06f282020-04-21 22:01:14 +02002878 int save_textlock = textlock;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002879
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +02002880 if (in_vim9script()
2881 && (check_for_number_arg(argvars, 0) == FAIL
2882 || check_for_list_arg(argvars, 1) == FAIL))
2883 return;
2884
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02002885 if ((State & INSERT) == 0)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002886 {
Bram Moolenaar677658a2022-01-05 16:09:06 +00002887 emsg(_(e_complete_can_only_be_used_in_insert_mode));
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02002888 return;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002889 }
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02002890
Bram Moolenaar6adb9ea2020-04-30 22:31:18 +02002891 // "textlock" is set when evaluating 'completefunc' but we can change
2892 // text here.
Bram Moolenaarff06f282020-04-21 22:01:14 +02002893 textlock = 0;
2894
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02002895 // Check for undo allowed here, because if something was already inserted
2896 // the line was already saved for undo and this check isn't done.
2897 if (!undo_allowed())
2898 return;
2899
2900 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00002901 emsg(_(e_invalid_argument));
Bram Moolenaarff06f282020-04-21 22:01:14 +02002902 else
2903 {
2904 startcol = (int)tv_get_number_chk(&argvars[0], NULL);
2905 if (startcol > 0)
2906 set_completion(startcol - 1, argvars[1].vval.v_list);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002907 }
Bram Moolenaarff06f282020-04-21 22:01:14 +02002908 textlock = save_textlock;
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02002909}
2910
2911/*
2912 * "complete_add()" function
2913 */
2914 void
2915f_complete_add(typval_T *argvars, typval_T *rettv)
2916{
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +02002917 if (in_vim9script() && check_for_string_or_dict_arg(argvars, 0) == FAIL)
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +02002918 return;
2919
Bram Moolenaar440cf092021-04-03 20:13:30 +02002920 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0, FALSE);
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02002921}
2922
2923/*
2924 * "complete_check()" function
2925 */
2926 void
2927f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2928{
2929 int saved = RedrawingDisabled;
2930
2931 RedrawingDisabled = 0;
2932 ins_compl_check_keys(0, TRUE);
2933 rettv->vval.v_number = ins_compl_interrupted();
2934 RedrawingDisabled = saved;
2935}
2936
2937/*
Bram Moolenaar9cb698d2019-08-21 15:30:45 +02002938 * Return Insert completion mode name string
2939 */
2940 static char_u *
2941ins_compl_mode(void)
2942{
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00002943 if (ctrl_x_mode_not_defined_yet() || ctrl_x_mode_scroll() || compl_started)
Bram Moolenaar9cb698d2019-08-21 15:30:45 +02002944 return (char_u *)ctrl_x_mode_names[ctrl_x_mode & ~CTRL_X_WANT_IDENT];
2945
2946 return (char_u *)"";
2947}
2948
Yegappan Lakshmanane9825862022-01-03 11:03:48 +00002949/*
2950 * Assign the sequence number to all the completion matches which don't have
2951 * one assigned yet.
2952 */
Bram Moolenaarf9d51352020-10-26 19:22:42 +01002953 static void
2954ins_compl_update_sequence_numbers()
2955{
2956 int number = 0;
2957 compl_T *match;
2958
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00002959 if (compl_dir_forward())
Bram Moolenaarf9d51352020-10-26 19:22:42 +01002960 {
2961 // search backwards for the first valid (!= -1) number.
2962 // This should normally succeed already at the first loop
2963 // cycle, so it's fast!
2964 for (match = compl_curr_match->cp_prev; match != NULL
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00002965 && !is_first_match(match); match = match->cp_prev)
Bram Moolenaarf9d51352020-10-26 19:22:42 +01002966 if (match->cp_number != -1)
2967 {
2968 number = match->cp_number;
2969 break;
2970 }
2971 if (match != NULL)
2972 // go up and assign all numbers which are not assigned
2973 // yet
2974 for (match = match->cp_next;
2975 match != NULL && match->cp_number == -1;
2976 match = match->cp_next)
2977 match->cp_number = ++number;
2978 }
2979 else // BACKWARD
2980 {
2981 // search forwards (upwards) for the first valid (!= -1)
2982 // number. This should normally succeed already at the
2983 // first loop cycle, so it's fast!
2984 for (match = compl_curr_match->cp_next; match != NULL
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00002985 && !is_first_match(match); match = match->cp_next)
Bram Moolenaarf9d51352020-10-26 19:22:42 +01002986 if (match->cp_number != -1)
2987 {
2988 number = match->cp_number;
2989 break;
2990 }
2991 if (match != NULL)
2992 // go down and assign all numbers which are not
2993 // assigned yet
2994 for (match = match->cp_prev; match
2995 && match->cp_number == -1;
2996 match = match->cp_prev)
2997 match->cp_number = ++number;
2998 }
2999}
3000
Bram Moolenaar9cb698d2019-08-21 15:30:45 +02003001/*
3002 * Get complete information
3003 */
3004 static void
3005get_complete_info(list_T *what_list, dict_T *retdict)
3006{
3007 int ret = OK;
3008 listitem_T *item;
3009#define CI_WHAT_MODE 0x01
3010#define CI_WHAT_PUM_VISIBLE 0x02
3011#define CI_WHAT_ITEMS 0x04
3012#define CI_WHAT_SELECTED 0x08
3013#define CI_WHAT_INSERTED 0x10
3014#define CI_WHAT_ALL 0xff
3015 int what_flag;
3016
3017 if (what_list == NULL)
3018 what_flag = CI_WHAT_ALL;
3019 else
3020 {
3021 what_flag = 0;
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02003022 CHECK_LIST_MATERIALIZE(what_list);
Bram Moolenaaraeea7212020-04-02 18:50:46 +02003023 FOR_ALL_LIST_ITEMS(what_list, item)
Bram Moolenaar9cb698d2019-08-21 15:30:45 +02003024 {
3025 char_u *what = tv_get_string(&item->li_tv);
3026
3027 if (STRCMP(what, "mode") == 0)
3028 what_flag |= CI_WHAT_MODE;
3029 else if (STRCMP(what, "pum_visible") == 0)
3030 what_flag |= CI_WHAT_PUM_VISIBLE;
3031 else if (STRCMP(what, "items") == 0)
3032 what_flag |= CI_WHAT_ITEMS;
3033 else if (STRCMP(what, "selected") == 0)
3034 what_flag |= CI_WHAT_SELECTED;
3035 else if (STRCMP(what, "inserted") == 0)
3036 what_flag |= CI_WHAT_INSERTED;
3037 }
3038 }
3039
3040 if (ret == OK && (what_flag & CI_WHAT_MODE))
3041 ret = dict_add_string(retdict, "mode", ins_compl_mode());
3042
3043 if (ret == OK && (what_flag & CI_WHAT_PUM_VISIBLE))
3044 ret = dict_add_number(retdict, "pum_visible", pum_visible());
3045
3046 if (ret == OK && (what_flag & CI_WHAT_ITEMS))
3047 {
3048 list_T *li;
3049 dict_T *di;
3050 compl_T *match;
3051
3052 li = list_alloc();
3053 if (li == NULL)
3054 return;
3055 ret = dict_add_list(retdict, "items", li);
3056 if (ret == OK && compl_first_match != NULL)
3057 {
3058 match = compl_first_match;
3059 do
3060 {
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003061 if (!match_at_original_text(match))
Bram Moolenaar9cb698d2019-08-21 15:30:45 +02003062 {
3063 di = dict_alloc();
3064 if (di == NULL)
3065 return;
3066 ret = list_append_dict(li, di);
3067 if (ret != OK)
3068 return;
3069 dict_add_string(di, "word", match->cp_str);
3070 dict_add_string(di, "abbr", match->cp_text[CPT_ABBR]);
3071 dict_add_string(di, "menu", match->cp_text[CPT_MENU]);
3072 dict_add_string(di, "kind", match->cp_text[CPT_KIND]);
3073 dict_add_string(di, "info", match->cp_text[CPT_INFO]);
Bram Moolenaar08928322020-01-04 14:32:48 +01003074 if (match->cp_user_data.v_type == VAR_UNKNOWN)
3075 // Add an empty string for backwards compatibility
3076 dict_add_string(di, "user_data", (char_u *)"");
3077 else
3078 dict_add_tv(di, "user_data", &match->cp_user_data);
Bram Moolenaar9cb698d2019-08-21 15:30:45 +02003079 }
3080 match = match->cp_next;
3081 }
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003082 while (match != NULL && !is_first_match(match));
Bram Moolenaar9cb698d2019-08-21 15:30:45 +02003083 }
3084 }
3085
3086 if (ret == OK && (what_flag & CI_WHAT_SELECTED))
Bram Moolenaarf9d51352020-10-26 19:22:42 +01003087 {
3088 if (compl_curr_match != NULL && compl_curr_match->cp_number == -1)
3089 ins_compl_update_sequence_numbers();
3090 ret = dict_add_number(retdict, "selected", compl_curr_match != NULL
3091 ? compl_curr_match->cp_number - 1 : -1);
3092 }
Bram Moolenaar9cb698d2019-08-21 15:30:45 +02003093
3094 // TODO
3095 // if (ret == OK && (what_flag & CI_WHAT_INSERTED))
3096}
3097
3098/*
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02003099 * "complete_info()" function
3100 */
3101 void
3102f_complete_info(typval_T *argvars, typval_T *rettv)
3103{
3104 list_T *what_list = NULL;
3105
3106 if (rettv_dict_alloc(rettv) != OK)
3107 return;
3108
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +02003109 if (in_vim9script() && check_for_opt_list_arg(argvars, 0) == FAIL)
3110 return;
3111
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02003112 if (argvars[0].v_type != VAR_UNKNOWN)
3113 {
3114 if (argvars[0].v_type != VAR_LIST)
3115 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00003116 emsg(_(e_list_required));
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02003117 return;
3118 }
3119 what_list = argvars[0].vval.v_list;
3120 }
3121 get_complete_info(what_list, rettv->vval.v_dict);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003122}
3123#endif
3124
3125/*
Yegappan Lakshmanan160e9942021-10-16 15:41:29 +01003126 * Returns TRUE when using a user-defined function for thesaurus completion.
3127 */
3128 static int
3129thesaurus_func_complete(int type UNUSED)
3130{
3131#ifdef FEAT_COMPL_FUNC
Bram Moolenaarf4d8b762021-10-17 14:13:09 +01003132 return type == CTRL_X_THESAURUS
3133 && (*curbuf->b_p_tsrfu != NUL || *p_tsrfu != NUL);
Yegappan Lakshmanan160e9942021-10-16 15:41:29 +01003134#else
3135 return FALSE;
3136#endif
3137}
3138
3139/*
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003140 * Return value of process_next_cpt_value()
3141 */
3142enum
3143{
3144 INS_COMPL_CPT_OK = 1,
3145 INS_COMPL_CPT_CONT,
3146 INS_COMPL_CPT_END
3147};
3148
3149/*
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003150 * state information used for getting the next set of insert completion
3151 * matches.
3152 */
3153typedef struct
3154{
3155 char_u *e_cpt; // current entry in 'complete'
3156 buf_T *ins_buf; // buffer being scanned
3157 pos_T *cur_match_pos; // current match position
3158 pos_T prev_match_pos; // previous match position
3159 int set_match_pos; // save first_match_pos/last_match_pos
3160 pos_T first_match_pos; // first match position
3161 pos_T last_match_pos; // last match position
3162 int found_all; // found all matches of a certain type.
3163 char_u *dict; // dictionary file to search
3164 int dict_f; // "dict" is an exact file name or not
3165} ins_compl_next_state_T;
3166
3167/*
3168 * Process the next 'complete' option value in st->e_cpt.
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003169 *
3170 * If successful, the arguments are set as below:
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003171 * st->cpt - pointer to the next option value in "st->cpt"
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003172 * compl_type_arg - type of insert mode completion to use
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003173 * st->found_all - all matches of this type are found
3174 * st->ins_buf - search for completions in this buffer
3175 * st->first_match_pos - position of the first completion match
3176 * st->last_match_pos - position of the last completion match
3177 * st->set_match_pos - TRUE if the first match position should be saved to
3178 * avoid loops after the search wraps around.
3179 * st->dict - name of the dictionary or thesaurus file to search
3180 * st->dict_f - flag specifying whether "dict" is an exact file name or not
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003181 *
3182 * Returns INS_COMPL_CPT_OK if the next value is processed successfully.
Yegappan Lakshmanan37079142022-01-08 10:38:48 +00003183 * Returns INS_COMPL_CPT_CONT to skip the current completion source matching
3184 * the "st->e_cpt" option value and process the next matching source.
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003185 * Returns INS_COMPL_CPT_END if all the values in "st->e_cpt" are processed.
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003186 */
3187 static int
3188process_next_cpt_value(
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003189 ins_compl_next_state_T *st,
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003190 int *compl_type_arg,
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003191 pos_T *start_match_pos)
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003192{
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003193 int compl_type = -1;
3194 int status = INS_COMPL_CPT_OK;
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003195
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003196 st->found_all = FALSE;
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003197
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003198 while (*st->e_cpt == ',' || *st->e_cpt == ' ')
3199 st->e_cpt++;
3200
3201 if (*st->e_cpt == '.' && !curbuf->b_scanned)
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003202 {
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003203 st->ins_buf = curbuf;
3204 st->first_match_pos = *start_match_pos;
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003205 // Move the cursor back one character so that ^N can match the
3206 // word immediately after the cursor.
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003207 if (ctrl_x_mode_normal() && dec(&st->first_match_pos) < 0)
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003208 {
3209 // Move the cursor to after the last character in the
3210 // buffer, so that word at start of buffer is found
3211 // correctly.
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003212 st->first_match_pos.lnum = st->ins_buf->b_ml.ml_line_count;
3213 st->first_match_pos.col =
3214 (colnr_T)STRLEN(ml_get(st->first_match_pos.lnum));
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003215 }
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003216 st->last_match_pos = st->first_match_pos;
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003217 compl_type = 0;
3218
3219 // Remember the first match so that the loop stops when we
3220 // wrap and come back there a second time.
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003221 st->set_match_pos = TRUE;
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003222 }
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003223 else if (vim_strchr((char_u *)"buwU", *st->e_cpt) != NULL
3224 && (st->ins_buf = ins_compl_next_buf(st->ins_buf, *st->e_cpt)) != curbuf)
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003225 {
3226 // Scan a buffer, but not the current one.
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003227 if (st->ins_buf->b_ml.ml_mfp != NULL) // loaded buffer
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003228 {
3229 compl_started = TRUE;
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003230 st->first_match_pos.col = st->last_match_pos.col = 0;
3231 st->first_match_pos.lnum = st->ins_buf->b_ml.ml_line_count + 1;
3232 st->last_match_pos.lnum = 0;
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003233 compl_type = 0;
3234 }
3235 else // unloaded buffer, scan like dictionary
3236 {
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003237 st->found_all = TRUE;
3238 if (st->ins_buf->b_fname == NULL)
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003239 {
3240 status = INS_COMPL_CPT_CONT;
3241 goto done;
3242 }
3243 compl_type = CTRL_X_DICTIONARY;
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003244 st->dict = st->ins_buf->b_fname;
3245 st->dict_f = DICT_EXACT;
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003246 }
3247 msg_hist_off = TRUE; // reset in msg_trunc_attr()
3248 vim_snprintf((char *)IObuff, IOSIZE, _("Scanning: %s"),
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003249 st->ins_buf->b_fname == NULL
3250 ? buf_spname(st->ins_buf)
3251 : st->ins_buf->b_sfname == NULL
3252 ? st->ins_buf->b_fname
3253 : st->ins_buf->b_sfname);
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003254 (void)msg_trunc_attr((char *)IObuff, TRUE, HL_ATTR(HLF_R));
3255 }
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003256 else if (*st->e_cpt == NUL)
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003257 status = INS_COMPL_CPT_END;
3258 else
3259 {
3260 if (ctrl_x_mode_line_or_eval())
3261 compl_type = -1;
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003262 else if (*st->e_cpt == 'k' || *st->e_cpt == 's')
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003263 {
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003264 if (*st->e_cpt == 'k')
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003265 compl_type = CTRL_X_DICTIONARY;
3266 else
3267 compl_type = CTRL_X_THESAURUS;
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003268 if (*++st->e_cpt != ',' && *st->e_cpt != NUL)
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003269 {
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003270 st->dict = st->e_cpt;
3271 st->dict_f = DICT_FIRST;
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003272 }
3273 }
3274#ifdef FEAT_FIND_ID
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003275 else if (*st->e_cpt == 'i')
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003276 compl_type = CTRL_X_PATH_PATTERNS;
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003277 else if (*st->e_cpt == 'd')
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003278 compl_type = CTRL_X_PATH_DEFINES;
3279#endif
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003280 else if (*st->e_cpt == ']' || *st->e_cpt == 't')
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003281 {
3282 msg_hist_off = TRUE; // reset in msg_trunc_attr()
3283 compl_type = CTRL_X_TAGS;
3284 vim_snprintf((char *)IObuff, IOSIZE, _("Scanning tags."));
3285 (void)msg_trunc_attr((char *)IObuff, TRUE, HL_ATTR(HLF_R));
3286 }
3287 else
3288 compl_type = -1;
3289
3290 // in any case e_cpt is advanced to the next entry
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003291 (void)copy_option_part(&st->e_cpt, IObuff, IOSIZE, ",");
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003292
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003293 st->found_all = TRUE;
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003294 if (compl_type == -1)
3295 status = INS_COMPL_CPT_CONT;
3296 }
3297
3298done:
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003299 *compl_type_arg = compl_type;
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003300 return status;
3301}
3302
3303#ifdef FEAT_FIND_ID
3304/*
3305 * Get the next set of identifiers or defines matching "compl_pattern" in
3306 * included files.
3307 */
3308 static void
3309get_next_include_file_completion(int compl_type)
3310{
3311 find_pattern_in_path(compl_pattern, compl_direction,
3312 (int)STRLEN(compl_pattern), FALSE, FALSE,
3313 (compl_type == CTRL_X_PATH_DEFINES
3314 && !(compl_cont_status & CONT_SOL))
3315 ? FIND_DEFINE : FIND_ANY, 1L, ACTION_EXPAND,
3316 (linenr_T)1, (linenr_T)MAXLNUM);
3317}
3318#endif
3319
3320/*
3321 * Get the next set of words matching "compl_pattern" in dictionary or
3322 * thesaurus files.
3323 */
3324 static void
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003325get_next_dict_tsr_completion(int compl_type, char_u *dict, int dict_f)
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003326{
3327#ifdef FEAT_COMPL_FUNC
3328 if (thesaurus_func_complete(compl_type))
3329 expand_by_function(compl_type, compl_pattern);
3330 else
3331#endif
3332 ins_compl_dictionaries(
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003333 dict != NULL ? dict
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003334 : (compl_type == CTRL_X_THESAURUS
3335 ? (*curbuf->b_p_tsr == NUL ? p_tsr : curbuf->b_p_tsr)
3336 : (*curbuf->b_p_dict == NUL ? p_dict : curbuf->b_p_dict)),
3337 compl_pattern,
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003338 dict != NULL ? dict_f : 0,
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003339 compl_type == CTRL_X_THESAURUS);
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003340}
3341
3342/*
3343 * Get the next set of tag names matching "compl_pattern".
3344 */
3345 static void
3346get_next_tag_completion(void)
3347{
3348 int save_p_ic;
3349 char_u **matches;
3350 int num_matches;
3351
3352 // set p_ic according to p_ic, p_scs and pat for find_tags().
3353 save_p_ic = p_ic;
3354 p_ic = ignorecase(compl_pattern);
3355
3356 // Find up to TAG_MANY matches. Avoids that an enormous number
3357 // of matches is found when compl_pattern is empty
3358 g_tag_at_cursor = TRUE;
3359 if (find_tags(compl_pattern, &num_matches, &matches,
3360 TAG_REGEXP | TAG_NAMES | TAG_NOIC | TAG_INS_COMP
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003361 | (ctrl_x_mode_not_default() ? TAG_VERBOSE : 0),
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003362 TAG_MANY, curbuf->b_ffname) == OK && num_matches > 0)
3363 ins_compl_add_matches(num_matches, matches, p_ic);
3364 g_tag_at_cursor = FALSE;
3365 p_ic = save_p_ic;
3366}
3367
3368/*
3369 * Get the next set of filename matching "compl_pattern".
3370 */
3371 static void
3372get_next_filename_completion(void)
3373{
3374 char_u **matches;
3375 int num_matches;
3376
3377 if (expand_wildcards(1, &compl_pattern, &num_matches, &matches,
3378 EW_FILE|EW_DIR|EW_ADDSLASH|EW_SILENT) != OK)
3379 return;
3380
3381 // May change home directory back to "~".
3382 tilde_replace(compl_pattern, num_matches, matches);
3383#ifdef BACKSLASH_IN_FILENAME
3384 if (curbuf->b_p_csl[0] != NUL)
3385 {
3386 int i;
3387
3388 for (i = 0; i < num_matches; ++i)
3389 {
3390 char_u *ptr = matches[i];
3391
3392 while (*ptr != NUL)
3393 {
3394 if (curbuf->b_p_csl[0] == 's' && *ptr == '\\')
3395 *ptr = '/';
3396 else if (curbuf->b_p_csl[0] == 'b' && *ptr == '/')
3397 *ptr = '\\';
3398 ptr += (*mb_ptr2len)(ptr);
3399 }
3400 }
3401 }
3402#endif
3403 ins_compl_add_matches(num_matches, matches, p_fic || p_wic);
3404}
3405
3406/*
3407 * Get the next set of command-line completions matching "compl_pattern".
3408 */
3409 static void
3410get_next_cmdline_completion()
3411{
3412 char_u **matches;
3413 int num_matches;
3414
3415 if (expand_cmdline(&compl_xp, compl_pattern,
3416 (int)STRLEN(compl_pattern),
3417 &num_matches, &matches) == EXPAND_OK)
3418 ins_compl_add_matches(num_matches, matches, FALSE);
3419}
3420
3421/*
3422 * Get the next set of spell suggestions matching "compl_pattern".
3423 */
3424 static void
3425get_next_spell_completion(linenr_T lnum UNUSED)
3426{
3427#ifdef FEAT_SPELL
3428 char_u **matches;
3429 int num_matches;
3430
3431 num_matches = expand_spelling(lnum, compl_pattern, &matches);
3432 if (num_matches > 0)
3433 ins_compl_add_matches(num_matches, matches, p_ic);
Bram Moolenaar8e7cc6b2021-12-30 10:32:25 +00003434 else
3435 vim_free(matches);
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003436#endif
3437}
3438
3439/*
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003440 * Return the next word or line from buffer "ins_buf" at position
3441 * "cur_match_pos" for completion. The length of the match is set in "len".
3442 */
3443 static char_u *
3444ins_comp_get_next_word_or_line(
3445 buf_T *ins_buf, // buffer being scanned
3446 pos_T *cur_match_pos, // current match position
3447 int *match_len,
3448 int *cont_s_ipos) // next ^X<> will set initial_pos
3449{
3450 char_u *ptr;
3451 int len;
3452
3453 *match_len = 0;
3454 ptr = ml_get_buf(ins_buf, cur_match_pos->lnum, FALSE) +
3455 cur_match_pos->col;
3456 if (ctrl_x_mode_line_or_eval())
3457 {
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003458 if (compl_status_adding())
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003459 {
3460 if (cur_match_pos->lnum >= ins_buf->b_ml.ml_line_count)
3461 return NULL;
3462 ptr = ml_get_buf(ins_buf, cur_match_pos->lnum + 1, FALSE);
3463 if (!p_paste)
3464 ptr = skipwhite(ptr);
3465 }
3466 len = (int)STRLEN(ptr);
3467 }
3468 else
3469 {
3470 char_u *tmp_ptr = ptr;
3471
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003472 if (compl_status_adding())
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003473 {
3474 tmp_ptr += compl_length;
3475 // Skip if already inside a word.
3476 if (vim_iswordp(tmp_ptr))
3477 return NULL;
3478 // Find start of next word.
3479 tmp_ptr = find_word_start(tmp_ptr);
3480 }
3481 // Find end of this word.
3482 tmp_ptr = find_word_end(tmp_ptr);
3483 len = (int)(tmp_ptr - ptr);
3484
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003485 if (compl_status_adding() && len == compl_length)
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003486 {
3487 if (cur_match_pos->lnum < ins_buf->b_ml.ml_line_count)
3488 {
3489 // Try next line, if any. the new word will be
3490 // "join" as if the normal command "J" was used.
3491 // IOSIZE is always greater than
3492 // compl_length, so the next STRNCPY always
3493 // works -- Acevedo
3494 STRNCPY(IObuff, ptr, len);
3495 ptr = ml_get_buf(ins_buf, cur_match_pos->lnum + 1, FALSE);
3496 tmp_ptr = ptr = skipwhite(ptr);
3497 // Find start of next word.
3498 tmp_ptr = find_word_start(tmp_ptr);
3499 // Find end of next word.
3500 tmp_ptr = find_word_end(tmp_ptr);
3501 if (tmp_ptr > ptr)
3502 {
3503 if (*ptr != ')' && IObuff[len - 1] != TAB)
3504 {
3505 if (IObuff[len - 1] != ' ')
3506 IObuff[len++] = ' ';
3507 // IObuf =~ "\k.* ", thus len >= 2
3508 if (p_js
3509 && (IObuff[len - 2] == '.'
3510 || (vim_strchr(p_cpo, CPO_JOINSP)
3511 == NULL
3512 && (IObuff[len - 2] == '?'
3513 || IObuff[len - 2] == '!'))))
3514 IObuff[len++] = ' ';
3515 }
3516 // copy as much as possible of the new word
3517 if (tmp_ptr - ptr >= IOSIZE - len)
3518 tmp_ptr = ptr + IOSIZE - len - 1;
3519 STRNCPY(IObuff + len, ptr, tmp_ptr - ptr);
3520 len += (int)(tmp_ptr - ptr);
3521 *cont_s_ipos = TRUE;
3522 }
3523 IObuff[len] = NUL;
3524 ptr = IObuff;
3525 }
3526 if (len == compl_length)
3527 return NULL;
3528 }
3529 }
3530
3531 *match_len = len;
3532 return ptr;
3533}
3534
3535/*
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003536 * Get the next set of words matching "compl_pattern" for default completion(s)
3537 * (normal ^P/^N and ^X^L).
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003538 * Search for "compl_pattern" in the buffer "st->ins_buf" starting from the
3539 * position "st->start_pos" in the "compl_direction" direction. If
3540 * "st->set_match_pos" is TRUE, then set the "st->first_match_pos" and
3541 * "st->last_match_pos".
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003542 * Returns OK if a new next match is found, otherwise returns FAIL.
3543 */
3544 static int
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003545get_next_default_completion(ins_compl_next_state_T *st, pos_T *start_pos)
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003546{
3547 int found_new_match = FAIL;
3548 int save_p_scs;
3549 int save_p_ws;
3550 int looped_around = FALSE;
3551 char_u *ptr;
3552 int len;
3553
3554 // If 'infercase' is set, don't use 'smartcase' here
3555 save_p_scs = p_scs;
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003556 if (st->ins_buf->b_p_inf)
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003557 p_scs = FALSE;
3558
3559 // Buffers other than curbuf are scanned from the beginning or the
3560 // end but never from the middle, thus setting nowrapscan in this
3561 // buffer is a good idea, on the other hand, we always set
3562 // wrapscan for curbuf to avoid missing matches -- Acevedo,Webb
3563 save_p_ws = p_ws;
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003564 if (st->ins_buf != curbuf)
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003565 p_ws = FALSE;
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003566 else if (*st->e_cpt == '.')
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003567 p_ws = TRUE;
3568 looped_around = FALSE;
3569 for (;;)
3570 {
3571 int cont_s_ipos = FALSE;
3572
3573 ++msg_silent; // Don't want messages for wrapscan.
3574
3575 // ctrl_x_mode_line_or_eval() || word-wise search that
3576 // has added a word that was at the beginning of the line
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003577 if (ctrl_x_mode_line_or_eval() || (compl_cont_status & CONT_SOL))
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003578 found_new_match = search_for_exact_line(st->ins_buf,
3579 st->cur_match_pos, compl_direction, compl_pattern);
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003580 else
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003581 found_new_match = searchit(NULL, st->ins_buf, st->cur_match_pos,
3582 NULL, compl_direction, compl_pattern, 1L,
3583 SEARCH_KEEP + SEARCH_NFMSG, RE_LAST, NULL);
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003584 --msg_silent;
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003585 if (!compl_started || st->set_match_pos)
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003586 {
3587 // set "compl_started" even on fail
3588 compl_started = TRUE;
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003589 st->first_match_pos = *st->cur_match_pos;
3590 st->last_match_pos = *st->cur_match_pos;
3591 st->set_match_pos = FALSE;
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003592 }
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003593 else if (st->first_match_pos.lnum == st->last_match_pos.lnum
3594 && st->first_match_pos.col == st->last_match_pos.col)
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003595 {
3596 found_new_match = FAIL;
3597 }
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003598 else if (compl_dir_forward()
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003599 && (st->prev_match_pos.lnum > st->cur_match_pos->lnum
3600 || (st->prev_match_pos.lnum == st->cur_match_pos->lnum
3601 && st->prev_match_pos.col >= st->cur_match_pos->col)))
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003602 {
3603 if (looped_around)
3604 found_new_match = FAIL;
3605 else
3606 looped_around = TRUE;
3607 }
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003608 else if (!compl_dir_forward()
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003609 && (st->prev_match_pos.lnum < st->cur_match_pos->lnum
3610 || (st->prev_match_pos.lnum == st->cur_match_pos->lnum
3611 && st->prev_match_pos.col <= st->cur_match_pos->col)))
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003612 {
3613 if (looped_around)
3614 found_new_match = FAIL;
3615 else
3616 looped_around = TRUE;
3617 }
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003618 st->prev_match_pos = *st->cur_match_pos;
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003619 if (found_new_match == FAIL)
3620 break;
3621
3622 // when ADDING, the text before the cursor matches, skip it
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003623 if (compl_status_adding() && st->ins_buf == curbuf
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003624 && start_pos->lnum == st->cur_match_pos->lnum
3625 && start_pos->col == st->cur_match_pos->col)
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003626 continue;
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003627
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003628 ptr = ins_comp_get_next_word_or_line(st->ins_buf, st->cur_match_pos,
3629 &len, &cont_s_ipos);
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003630 if (ptr == NULL)
3631 continue;
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003632
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003633 if (ins_compl_add_infercase(ptr, len, p_ic,
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003634 st->ins_buf == curbuf ? NULL : st->ins_buf->b_sfname,
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003635 0, cont_s_ipos) != NOTDONE)
3636 {
3637 found_new_match = OK;
3638 break;
3639 }
3640 }
3641 p_scs = save_p_scs;
3642 p_ws = save_p_ws;
3643
3644 return found_new_match;
3645}
3646
3647/*
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003648 * get the next set of completion matches for "type".
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003649 * Returns TRUE if a new match is found. Otherwise returns FALSE.
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003650 */
3651 static int
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003652get_next_completion_match(int type, ins_compl_next_state_T *st, pos_T *ini)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003653{
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003654 int found_new_match = FALSE;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003655
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003656 switch (type)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003657 {
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003658 case -1:
3659 break;
3660#ifdef FEAT_FIND_ID
3661 case CTRL_X_PATH_PATTERNS:
3662 case CTRL_X_PATH_DEFINES:
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003663 get_next_include_file_completion(type);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003664 break;
3665#endif
3666
3667 case CTRL_X_DICTIONARY:
3668 case CTRL_X_THESAURUS:
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003669 get_next_dict_tsr_completion(type, st->dict, st->dict_f);
3670 st->dict = NULL;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003671 break;
3672
3673 case CTRL_X_TAGS:
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003674 get_next_tag_completion();
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003675 break;
3676
3677 case CTRL_X_FILES:
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003678 get_next_filename_completion();
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003679 break;
3680
3681 case CTRL_X_CMDLINE:
zeertzjqdca29d92021-08-31 19:12:51 +02003682 case CTRL_X_CMDLINE_CTRL_X:
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003683 get_next_cmdline_completion();
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003684 break;
3685
3686#ifdef FEAT_COMPL_FUNC
3687 case CTRL_X_FUNCTION:
3688 case CTRL_X_OMNI:
3689 expand_by_function(type, compl_pattern);
3690 break;
3691#endif
3692
3693 case CTRL_X_SPELL:
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003694 get_next_spell_completion(st->first_match_pos.lnum);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003695 break;
3696
3697 default: // normal ^P/^N and ^X^L
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003698 found_new_match = get_next_default_completion(st, ini);
3699 if (found_new_match == FAIL && st->ins_buf == curbuf)
3700 st->found_all = TRUE;
3701 }
3702
3703 // check if compl_curr_match has changed, (e.g. other type of
3704 // expansion added something)
3705 if (type != 0 && compl_curr_match != compl_old_match)
3706 found_new_match = OK;
3707
3708 return found_new_match;
3709}
3710
3711/*
3712 * Get the next expansion(s), using "compl_pattern".
3713 * The search starts at position "ini" in curbuf and in the direction
3714 * compl_direction.
3715 * When "compl_started" is FALSE start at that position, otherwise continue
3716 * where we stopped searching before.
3717 * This may return before finding all the matches.
3718 * Return the total number of matches or -1 if still unknown -- Acevedo
3719 */
3720 static int
3721ins_compl_get_exp(pos_T *ini)
3722{
3723 static ins_compl_next_state_T st;
3724 int i;
3725 int found_new_match;
3726 int type = ctrl_x_mode;
3727
3728 if (!compl_started)
3729 {
3730 FOR_ALL_BUFFERS(st.ins_buf)
3731 st.ins_buf->b_scanned = 0;
3732 st.found_all = FALSE;
3733 st.ins_buf = curbuf;
3734 st.e_cpt = (compl_cont_status & CONT_LOCAL)
3735 ? (char_u *)"." : curbuf->b_p_cpt;
3736 st.last_match_pos = st.first_match_pos = *ini;
3737 }
3738 else if (st.ins_buf != curbuf && !buf_valid(st.ins_buf))
3739 st.ins_buf = curbuf; // In case the buffer was wiped out.
3740
3741 compl_old_match = compl_curr_match; // remember the last current match
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003742 st.cur_match_pos = (compl_dir_forward())
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003743 ? &st.last_match_pos : &st.first_match_pos;
3744
3745 // For ^N/^P loop over all the flags/windows/buffers in 'complete'.
3746 for (;;)
3747 {
3748 found_new_match = FAIL;
3749 st.set_match_pos = FALSE;
3750
3751 // For ^N/^P pick a new entry from e_cpt if compl_started is off,
3752 // or if found_all says this entry is done. For ^X^L only use the
3753 // entries from 'complete' that look in loaded buffers.
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003754 if ((ctrl_x_mode_normal() || ctrl_x_mode_line_or_eval())
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003755 && (!compl_started || st.found_all))
3756 {
3757 int status = process_next_cpt_value(&st, &type, ini);
3758
3759 if (status == INS_COMPL_CPT_END)
3760 break;
3761 if (status == INS_COMPL_CPT_CONT)
3762 continue;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003763 }
3764
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003765 // If complete() was called then compl_pattern has been reset. The
3766 // following won't work then, bail out.
3767 if (compl_pattern == NULL)
3768 break;
3769
3770 // get the next set of completion matches
3771 found_new_match = get_next_completion_match(type, &st, ini);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003772
3773 // break the loop for specialized modes (use 'complete' just for the
3774 // generic ctrl_x_mode == CTRL_X_NORMAL) or when we've found a new
3775 // match
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003776 if ((ctrl_x_mode_not_default() && !ctrl_x_mode_line_or_eval())
3777 || found_new_match != FAIL)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003778 {
3779 if (got_int)
3780 break;
3781 // Fill the popup menu as soon as possible.
3782 if (type != -1)
3783 ins_compl_check_keys(0, FALSE);
3784
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003785 if ((ctrl_x_mode_not_default()
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003786 && !ctrl_x_mode_line_or_eval()) || compl_interrupted)
3787 break;
3788 compl_started = TRUE;
3789 }
3790 else
3791 {
3792 // Mark a buffer scanned when it has been scanned completely
3793 if (type == 0 || type == CTRL_X_PATH_PATTERNS)
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003794 st.ins_buf->b_scanned = TRUE;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003795
3796 compl_started = FALSE;
3797 }
3798 }
3799 compl_started = TRUE;
3800
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003801 if ((ctrl_x_mode_normal() || ctrl_x_mode_line_or_eval())
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003802 && *st.e_cpt == NUL) // Got to end of 'complete'
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003803 found_new_match = FAIL;
3804
3805 i = -1; // total of matches, unknown
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003806 if (found_new_match == FAIL || (ctrl_x_mode_not_default()
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003807 && !ctrl_x_mode_line_or_eval()))
3808 i = ins_compl_make_cyclic();
3809
3810 if (compl_old_match != NULL)
3811 {
3812 // If several matches were added (FORWARD) or the search failed and has
3813 // just been made cyclic then we have to move compl_curr_match to the
3814 // next or previous entry (if any) -- Acevedo
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003815 compl_curr_match = compl_dir_forward() ? compl_old_match->cp_next
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003816 : compl_old_match->cp_prev;
3817 if (compl_curr_match == NULL)
3818 compl_curr_match = compl_old_match;
3819 }
=?UTF-8?q?Magnus=20Gro=C3=9F?=25def2c2021-10-22 18:56:39 +01003820 trigger_modechanged();
3821
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003822 return i;
3823}
3824
3825/*
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003826 * Update "compl_shown_match" to the actually shown match, it may differ when
3827 * "compl_leader" is used to omit some of the matches.
3828 */
3829 static void
3830ins_compl_update_shown_match(void)
3831{
3832 while (!ins_compl_equal(compl_shown_match,
3833 compl_leader, (int)STRLEN(compl_leader))
3834 && compl_shown_match->cp_next != NULL
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003835 && !is_first_match(compl_shown_match->cp_next))
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003836 compl_shown_match = compl_shown_match->cp_next;
3837
3838 // If we didn't find it searching forward, and compl_shows_dir is
3839 // backward, find the last match.
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003840 if (compl_shows_dir_backward()
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003841 && !ins_compl_equal(compl_shown_match,
3842 compl_leader, (int)STRLEN(compl_leader))
3843 && (compl_shown_match->cp_next == NULL
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003844 || is_first_match(compl_shown_match->cp_next)))
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003845 {
3846 while (!ins_compl_equal(compl_shown_match,
3847 compl_leader, (int)STRLEN(compl_leader))
3848 && compl_shown_match->cp_prev != NULL
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003849 && !is_first_match(compl_shown_match->cp_prev))
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003850 compl_shown_match = compl_shown_match->cp_prev;
3851 }
3852}
3853
3854/*
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003855 * Delete the old text being completed.
3856 */
3857 void
3858ins_compl_delete(void)
3859{
3860 int col;
3861
3862 // In insert mode: Delete the typed part.
3863 // In replace mode: Put the old characters back, if any.
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003864 col = compl_col + (compl_status_adding() ? compl_length : 0);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003865 if ((int)curwin->w_cursor.col > col)
3866 {
3867 if (stop_arrow() == FAIL)
3868 return;
3869 backspace_until_column(col);
3870 }
3871
3872 // TODO: is this sufficient for redrawing? Redrawing everything causes
3873 // flicker, thus we can't do that.
3874 changed_cline_bef_curs();
Bram Moolenaar9cb698d2019-08-21 15:30:45 +02003875#ifdef FEAT_EVAL
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003876 // clear v:completed_item
3877 set_vim_var_dict(VV_COMPLETED_ITEM, dict_alloc_lock(VAR_FIXED));
Bram Moolenaar9cb698d2019-08-21 15:30:45 +02003878#endif
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003879}
3880
3881/*
3882 * Insert the new text being completed.
3883 * "in_compl_func" is TRUE when called from complete_check().
3884 */
3885 void
3886ins_compl_insert(int in_compl_func)
3887{
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003888 int compl_len = get_compl_len();
Bram Moolenaar4b28ba32021-12-27 19:28:37 +00003889
3890 // Make sure we don't go over the end of the string, this can happen with
3891 // illegal bytes.
3892 if (compl_len < (int)STRLEN(compl_shown_match->cp_str))
3893 ins_bytes(compl_shown_match->cp_str + compl_len);
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003894 if (match_at_original_text(compl_shown_match))
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003895 compl_used_match = FALSE;
3896 else
3897 compl_used_match = TRUE;
Bram Moolenaar9cb698d2019-08-21 15:30:45 +02003898#ifdef FEAT_EVAL
3899 {
3900 dict_T *dict = ins_compl_dict_alloc(compl_shown_match);
3901
3902 set_vim_var_dict(VV_COMPLETED_ITEM, dict);
3903 }
3904#endif
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003905 if (!in_compl_func)
3906 compl_curr_match = compl_shown_match;
3907}
3908
3909/*
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003910 * show the file name for the completion match (if any). Truncate the file
3911 * name to avoid a wait for return.
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003912 */
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003913 static void
3914ins_compl_show_filename(void)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003915{
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003916 char *lead = _("match in file");
3917 int space = sc_col - vim_strsize((char_u *)lead) - 2;
3918 char_u *s;
3919 char_u *e;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003920
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003921 if (space <= 0)
3922 return;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003923
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003924 // We need the tail that fits. With double-byte encoding going
3925 // back from the end is very slow, thus go from the start and keep
3926 // the text that fits in "space" between "s" and "e".
3927 for (s = e = compl_shown_match->cp_fname; *e != NUL; MB_PTR_ADV(e))
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003928 {
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003929 space -= ptr2cells(e);
3930 while (space < 0)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003931 {
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003932 space += ptr2cells(s);
3933 MB_PTR_ADV(s);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003934 }
3935 }
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003936 msg_hist_off = TRUE;
3937 vim_snprintf((char *)IObuff, IOSIZE, "%s %s%s", lead,
3938 s > compl_shown_match->cp_fname ? "<" : "", s);
3939 msg((char *)IObuff);
3940 msg_hist_off = FALSE;
3941 redraw_cmdline = FALSE; // don't overwrite!
3942}
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003943
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003944/*
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003945 * Find the next set of matches for completion. Repeat the completion "todo"
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003946 * times. The number of matches found is returned in 'num_matches'.
3947 *
3948 * If "allow_get_expansion" is TRUE, then ins_compl_get_exp() may be called to
3949 * get more completions. If it is FALSE, then do nothing when there are no more
3950 * completions in the given direction.
3951 *
3952 * If "advance" is TRUE, then completion will move to the first match.
3953 * Otherwise, the original text will be shown.
3954 *
3955 * Returns OK on success and -1 if the number of matches are unknown.
3956 */
3957 static int
3958find_next_completion_match(
3959 int allow_get_expansion,
3960 int todo, // repeat completion this many times
3961 int advance,
3962 int *num_matches)
3963{
3964 int found_end = FALSE;
3965 compl_T *found_compl = NULL;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003966
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003967 while (--todo >= 0)
3968 {
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003969 if (compl_shows_dir_forward() && compl_shown_match->cp_next != NULL)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003970 {
3971 compl_shown_match = compl_shown_match->cp_next;
3972 found_end = (compl_first_match != NULL
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003973 && (is_first_match(compl_shown_match->cp_next)
3974 || is_first_match(compl_shown_match)));
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003975 }
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003976 else if (compl_shows_dir_backward()
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003977 && compl_shown_match->cp_prev != NULL)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003978 {
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003979 found_end = is_first_match(compl_shown_match);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003980 compl_shown_match = compl_shown_match->cp_prev;
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003981 found_end |= is_first_match(compl_shown_match);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003982 }
3983 else
3984 {
3985 if (!allow_get_expansion)
3986 {
3987 if (advance)
3988 {
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003989 if (compl_shows_dir_backward())
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003990 compl_pending -= todo + 1;
3991 else
3992 compl_pending += todo + 1;
3993 }
3994 return -1;
3995 }
3996
3997 if (!compl_no_select && advance)
3998 {
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003999 if (compl_shows_dir_backward())
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004000 --compl_pending;
4001 else
4002 ++compl_pending;
4003 }
4004
4005 // Find matches.
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004006 *num_matches = ins_compl_get_exp(&compl_startpos);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004007
4008 // handle any pending completions
4009 while (compl_pending != 0 && compl_direction == compl_shows_dir
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004010 && advance)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004011 {
4012 if (compl_pending > 0 && compl_shown_match->cp_next != NULL)
4013 {
4014 compl_shown_match = compl_shown_match->cp_next;
4015 --compl_pending;
4016 }
4017 if (compl_pending < 0 && compl_shown_match->cp_prev != NULL)
4018 {
4019 compl_shown_match = compl_shown_match->cp_prev;
4020 ++compl_pending;
4021 }
4022 else
4023 break;
4024 }
4025 found_end = FALSE;
4026 }
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004027 if (!match_at_original_text(compl_shown_match)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004028 && compl_leader != NULL
4029 && !ins_compl_equal(compl_shown_match,
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004030 compl_leader, (int)STRLEN(compl_leader)))
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004031 ++todo;
4032 else
4033 // Remember a matching item.
4034 found_compl = compl_shown_match;
4035
4036 // Stop at the end of the list when we found a usable match.
4037 if (found_end)
4038 {
4039 if (found_compl != NULL)
4040 {
4041 compl_shown_match = found_compl;
4042 break;
4043 }
4044 todo = 1; // use first usable match after wrapping around
4045 }
4046 }
4047
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004048 return OK;
4049}
4050
4051/*
4052 * Fill in the next completion in the current direction.
4053 * If "allow_get_expansion" is TRUE, then we may call ins_compl_get_exp() to
4054 * get more completions. If it is FALSE, then we just do nothing when there
4055 * are no more completions in a given direction. The latter case is used when
4056 * we are still in the middle of finding completions, to allow browsing
4057 * through the ones found so far.
4058 * Return the total number of matches, or -1 if still unknown -- webb.
4059 *
4060 * compl_curr_match is currently being used by ins_compl_get_exp(), so we use
4061 * compl_shown_match here.
4062 *
4063 * Note that this function may be called recursively once only. First with
4064 * "allow_get_expansion" TRUE, which calls ins_compl_get_exp(), which in turn
4065 * calls this function with "allow_get_expansion" FALSE.
4066 */
4067 static int
4068ins_compl_next(
4069 int allow_get_expansion,
4070 int count, // repeat completion this many times; should
4071 // be at least 1
4072 int insert_match, // Insert the newly selected match
4073 int in_compl_func) // called from complete_check()
4074{
4075 int num_matches = -1;
4076 int todo = count;
4077 int advance;
4078 int started = compl_started;
4079
4080 // When user complete function return -1 for findstart which is next
4081 // time of 'always', compl_shown_match become NULL.
4082 if (compl_shown_match == NULL)
4083 return -1;
4084
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004085 if (compl_leader != NULL && !match_at_original_text(compl_shown_match))
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004086 // Update "compl_shown_match" to the actually shown match
4087 ins_compl_update_shown_match();
4088
4089 if (allow_get_expansion && insert_match
4090 && (!(compl_get_longest || compl_restarting) || compl_used_match))
4091 // Delete old text to be replaced
4092 ins_compl_delete();
4093
4094 // When finding the longest common text we stick at the original text,
4095 // don't let CTRL-N or CTRL-P move to the first match.
4096 advance = count != 1 || !allow_get_expansion || !compl_get_longest;
4097
4098 // When restarting the search don't insert the first match either.
4099 if (compl_restarting)
4100 {
4101 advance = FALSE;
4102 compl_restarting = FALSE;
4103 }
4104
4105 // Repeat this for when <PageUp> or <PageDown> is typed. But don't wrap
4106 // around.
4107 if (find_next_completion_match(allow_get_expansion, todo, advance,
4108 &num_matches) == -1)
4109 return -1;
4110
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004111 // Insert the text of the new completion, or the compl_leader.
4112 if (compl_no_insert && !started)
4113 {
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004114 ins_bytes(compl_orig_text + get_compl_len());
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004115 compl_used_match = FALSE;
4116 }
4117 else if (insert_match)
4118 {
4119 if (!compl_get_longest || compl_used_match)
4120 ins_compl_insert(in_compl_func);
4121 else
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004122 ins_bytes(compl_leader + get_compl_len());
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004123 }
4124 else
4125 compl_used_match = FALSE;
4126
4127 if (!allow_get_expansion)
4128 {
4129 // may undisplay the popup menu first
4130 ins_compl_upd_pum();
4131
4132 if (pum_enough_matches())
4133 // Will display the popup menu, don't redraw yet to avoid flicker.
4134 pum_call_update_screen();
4135 else
4136 // Not showing the popup menu yet, redraw to show the user what was
4137 // inserted.
4138 update_screen(0);
4139
4140 // display the updated popup menu
4141 ins_compl_show_pum();
4142#ifdef FEAT_GUI
4143 if (gui.in_use)
4144 {
4145 // Show the cursor after the match, not after the redrawn text.
4146 setcursor();
4147 out_flush_cursor(FALSE, FALSE);
4148 }
4149#endif
4150
4151 // Delete old text to be replaced, since we're still searching and
4152 // don't want to match ourselves!
4153 ins_compl_delete();
4154 }
4155
4156 // Enter will select a match when the match wasn't inserted and the popup
4157 // menu is visible.
4158 if (compl_no_insert && !started)
4159 compl_enter_selects = TRUE;
4160 else
4161 compl_enter_selects = !insert_match && compl_match_array != NULL;
4162
4163 // Show the file name for the match (if any)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004164 if (compl_shown_match->cp_fname != NULL)
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004165 ins_compl_show_filename();
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004166
4167 return num_matches;
4168}
4169
4170/*
4171 * Call this while finding completions, to check whether the user has hit a key
4172 * that should change the currently displayed completion, or exit completion
4173 * mode. Also, when compl_pending is not zero, show a completion as soon as
4174 * possible. -- webb
4175 * "frequency" specifies out of how many calls we actually check.
4176 * "in_compl_func" is TRUE when called from complete_check(), don't set
4177 * compl_curr_match.
4178 */
4179 void
4180ins_compl_check_keys(int frequency, int in_compl_func)
4181{
4182 static int count = 0;
4183 int c;
4184
4185 // Don't check when reading keys from a script, :normal or feedkeys().
4186 // That would break the test scripts. But do check for keys when called
4187 // from complete_check().
4188 if (!in_compl_func && (using_script() || ex_normal_busy))
4189 return;
4190
4191 // Only do this at regular intervals
4192 if (++count < frequency)
4193 return;
4194 count = 0;
4195
4196 // Check for a typed key. Do use mappings, otherwise vim_is_ctrl_x_key()
4197 // can't do its work correctly.
4198 c = vpeekc_any();
4199 if (c != NUL)
4200 {
4201 if (vim_is_ctrl_x_key(c) && c != Ctrl_X && c != Ctrl_R)
4202 {
4203 c = safe_vgetc(); // Eat the character
4204 compl_shows_dir = ins_compl_key2dir(c);
4205 (void)ins_compl_next(FALSE, ins_compl_key2count(c),
4206 c != K_UP && c != K_DOWN, in_compl_func);
4207 }
4208 else
4209 {
4210 // Need to get the character to have KeyTyped set. We'll put it
4211 // back with vungetc() below. But skip K_IGNORE.
4212 c = safe_vgetc();
4213 if (c != K_IGNORE)
4214 {
4215 // Don't interrupt completion when the character wasn't typed,
4216 // e.g., when doing @q to replay keys.
4217 if (c != Ctrl_R && KeyTyped)
4218 compl_interrupted = TRUE;
4219
4220 vungetc(c);
4221 }
4222 }
4223 }
4224 if (compl_pending != 0 && !got_int && !compl_no_insert)
4225 {
4226 int todo = compl_pending > 0 ? compl_pending : -compl_pending;
4227
4228 compl_pending = 0;
4229 (void)ins_compl_next(FALSE, todo, TRUE, in_compl_func);
4230 }
4231}
4232
4233/*
4234 * Decide the direction of Insert mode complete from the key typed.
4235 * Returns BACKWARD or FORWARD.
4236 */
4237 static int
4238ins_compl_key2dir(int c)
4239{
4240 if (c == Ctrl_P || c == Ctrl_L
4241 || c == K_PAGEUP || c == K_KPAGEUP || c == K_S_UP || c == K_UP)
4242 return BACKWARD;
4243 return FORWARD;
4244}
4245
4246/*
4247 * Return TRUE for keys that are used for completion only when the popup menu
4248 * is visible.
4249 */
4250 static int
4251ins_compl_pum_key(int c)
4252{
4253 return pum_visible() && (c == K_PAGEUP || c == K_KPAGEUP || c == K_S_UP
4254 || c == K_PAGEDOWN || c == K_KPAGEDOWN || c == K_S_DOWN
4255 || c == K_UP || c == K_DOWN);
4256}
4257
4258/*
4259 * Decide the number of completions to move forward.
4260 * Returns 1 for most keys, height of the popup menu for page-up/down keys.
4261 */
4262 static int
4263ins_compl_key2count(int c)
4264{
4265 int h;
4266
4267 if (ins_compl_pum_key(c) && c != K_UP && c != K_DOWN)
4268 {
4269 h = pum_get_height();
4270 if (h > 3)
4271 h -= 2; // keep some context
4272 return h;
4273 }
4274 return 1;
4275}
4276
4277/*
4278 * Return TRUE if completion with "c" should insert the match, FALSE if only
4279 * to change the currently selected completion.
4280 */
4281 static int
4282ins_compl_use_match(int c)
4283{
4284 switch (c)
4285 {
4286 case K_UP:
4287 case K_DOWN:
4288 case K_PAGEDOWN:
4289 case K_KPAGEDOWN:
4290 case K_S_DOWN:
4291 case K_PAGEUP:
4292 case K_KPAGEUP:
4293 case K_S_UP:
4294 return FALSE;
4295 }
4296 return TRUE;
4297}
4298
4299/*
Bram Moolenaarbf7ff612021-12-27 12:52:07 +00004300 * Get the pattern, column and length for normal completion (CTRL-N CTRL-P
4301 * completion)
4302 * Sets the global variables: compl_col, compl_length and compl_pattern.
4303 * Uses the global variables: compl_cont_status and ctrl_x_mode
4304 */
4305 static int
4306get_normal_compl_info(char_u *line, int startcol, colnr_T curs_col)
4307{
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004308 if ((compl_cont_status & CONT_SOL) || ctrl_x_mode_path_defines())
Bram Moolenaarbf7ff612021-12-27 12:52:07 +00004309 {
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004310 if (!compl_status_adding())
Bram Moolenaarbf7ff612021-12-27 12:52:07 +00004311 {
4312 while (--startcol >= 0 && vim_isIDc(line[startcol]))
4313 ;
4314 compl_col += ++startcol;
4315 compl_length = curs_col - startcol;
4316 }
4317 if (p_ic)
4318 compl_pattern = str_foldcase(line + compl_col,
4319 compl_length, NULL, 0);
4320 else
4321 compl_pattern = vim_strnsave(line + compl_col, compl_length);
4322 if (compl_pattern == NULL)
4323 return FAIL;
4324 }
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004325 else if (compl_status_adding())
Bram Moolenaarbf7ff612021-12-27 12:52:07 +00004326 {
4327 char_u *prefix = (char_u *)"\\<";
4328
4329 // we need up to 2 extra chars for the prefix
4330 compl_pattern = alloc(quote_meta(NULL, line + compl_col,
4331 compl_length) + 2);
4332 if (compl_pattern == NULL)
4333 return FAIL;
4334 if (!vim_iswordp(line + compl_col)
4335 || (compl_col > 0
4336 && (vim_iswordp(mb_prevptr(line, line + compl_col)))))
4337 prefix = (char_u *)"";
4338 STRCPY((char *)compl_pattern, prefix);
4339 (void)quote_meta(compl_pattern + STRLEN(prefix),
4340 line + compl_col, compl_length);
4341 }
4342 else if (--startcol < 0
4343 || !vim_iswordp(mb_prevptr(line, line + startcol + 1)))
4344 {
4345 // Match any word of at least two chars
4346 compl_pattern = vim_strsave((char_u *)"\\<\\k\\k");
4347 if (compl_pattern == NULL)
4348 return FAIL;
4349 compl_col += curs_col;
4350 compl_length = 0;
4351 }
4352 else
4353 {
4354 // Search the point of change class of multibyte character
4355 // or not a word single byte character backward.
4356 if (has_mbyte)
4357 {
4358 int base_class;
4359 int head_off;
4360
4361 startcol -= (*mb_head_off)(line, line + startcol);
4362 base_class = mb_get_class(line + startcol);
4363 while (--startcol >= 0)
4364 {
4365 head_off = (*mb_head_off)(line, line + startcol);
4366 if (base_class != mb_get_class(line + startcol
4367 - head_off))
4368 break;
4369 startcol -= head_off;
4370 }
4371 }
4372 else
4373 while (--startcol >= 0 && vim_iswordc(line[startcol]))
4374 ;
4375 compl_col += ++startcol;
4376 compl_length = (int)curs_col - startcol;
4377 if (compl_length == 1)
4378 {
4379 // Only match word with at least two chars -- webb
4380 // there's no need to call quote_meta,
4381 // alloc(7) is enough -- Acevedo
4382 compl_pattern = alloc(7);
4383 if (compl_pattern == NULL)
4384 return FAIL;
4385 STRCPY((char *)compl_pattern, "\\<");
4386 (void)quote_meta(compl_pattern + 2, line + compl_col, 1);
4387 STRCAT((char *)compl_pattern, "\\k");
4388 }
4389 else
4390 {
4391 compl_pattern = alloc(quote_meta(NULL, line + compl_col,
4392 compl_length) + 2);
4393 if (compl_pattern == NULL)
4394 return FAIL;
4395 STRCPY((char *)compl_pattern, "\\<");
4396 (void)quote_meta(compl_pattern + 2, line + compl_col,
4397 compl_length);
4398 }
4399 }
4400
4401 return OK;
4402}
4403
4404/*
4405 * Get the pattern, column and length for whole line completion or for the
4406 * complete() function.
4407 * Sets the global variables: compl_col, compl_length and compl_pattern.
4408 */
4409 static int
4410get_wholeline_compl_info(char_u *line, colnr_T curs_col)
4411{
4412 compl_col = (colnr_T)getwhitecols(line);
4413 compl_length = (int)curs_col - (int)compl_col;
4414 if (compl_length < 0) // cursor in indent: empty pattern
4415 compl_length = 0;
4416 if (p_ic)
4417 compl_pattern = str_foldcase(line + compl_col, compl_length,
4418 NULL, 0);
4419 else
4420 compl_pattern = vim_strnsave(line + compl_col, compl_length);
4421 if (compl_pattern == NULL)
4422 return FAIL;
4423
4424 return OK;
4425}
4426
4427/*
4428 * Get the pattern, column and length for filename completion.
4429 * Sets the global variables: compl_col, compl_length and compl_pattern.
4430 */
4431 static int
4432get_filename_compl_info(char_u *line, int startcol, colnr_T curs_col)
4433{
4434 // Go back to just before the first filename character.
4435 if (startcol > 0)
4436 {
4437 char_u *p = line + startcol;
4438
4439 MB_PTR_BACK(line, p);
4440 while (p > line && vim_isfilec(PTR2CHAR(p)))
4441 MB_PTR_BACK(line, p);
4442 if (p == line && vim_isfilec(PTR2CHAR(p)))
4443 startcol = 0;
4444 else
4445 startcol = (int)(p - line) + 1;
4446 }
4447
4448 compl_col += startcol;
4449 compl_length = (int)curs_col - startcol;
4450 compl_pattern = addstar(line + compl_col, compl_length, EXPAND_FILES);
4451 if (compl_pattern == NULL)
4452 return FAIL;
4453
4454 return OK;
4455}
4456
4457/*
4458 * Get the pattern, column and length for command-line completion.
4459 * Sets the global variables: compl_col, compl_length and compl_pattern.
4460 */
4461 static int
4462get_cmdline_compl_info(char_u *line, colnr_T curs_col)
4463{
4464 compl_pattern = vim_strnsave(line, curs_col);
4465 if (compl_pattern == NULL)
4466 return FAIL;
4467 set_cmd_context(&compl_xp, compl_pattern,
4468 (int)STRLEN(compl_pattern), curs_col, FALSE);
4469 if (compl_xp.xp_context == EXPAND_UNSUCCESSFUL
4470 || compl_xp.xp_context == EXPAND_NOTHING)
4471 // No completion possible, use an empty pattern to get a
4472 // "pattern not found" message.
4473 compl_col = curs_col;
4474 else
4475 compl_col = (int)(compl_xp.xp_pattern - compl_pattern);
4476 compl_length = curs_col - compl_col;
4477
4478 return OK;
4479}
4480
4481/*
4482 * Get the pattern, column and length for user defined completion ('omnifunc',
4483 * 'completefunc' and 'thesaurusfunc')
4484 * Sets the global variables: compl_col, compl_length and compl_pattern.
4485 * Uses the global variable: spell_bad_len
4486 */
4487 static int
4488get_userdefined_compl_info(colnr_T curs_col UNUSED)
4489{
4490 int ret = FAIL;
4491
4492#ifdef FEAT_COMPL_FUNC
4493 // Call user defined function 'completefunc' with "a:findstart"
4494 // set to 1 to obtain the length of text to use for completion.
4495 char_u *line;
4496 typval_T args[3];
4497 int col;
4498 char_u *funcname;
4499 pos_T pos;
4500 int save_State = State;
4501 callback_T *cb;
4502
4503 // Call 'completefunc' or 'omnifunc' or 'thesaurusfunc' and get pattern
4504 // length as a string
4505 funcname = get_complete_funcname(ctrl_x_mode);
4506 if (*funcname == NUL)
4507 {
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004508 semsg(_(e_option_str_is_not_set), ctrl_x_mode_function()
Bram Moolenaarbf7ff612021-12-27 12:52:07 +00004509 ? "completefunc" : "omnifunc");
4510 return FAIL;
4511 }
4512
4513 args[0].v_type = VAR_NUMBER;
4514 args[0].vval.v_number = 1;
4515 args[1].v_type = VAR_STRING;
4516 args[1].vval.v_string = (char_u *)"";
4517 args[2].v_type = VAR_UNKNOWN;
4518 pos = curwin->w_cursor;
4519 ++textwinlock;
4520 cb = get_insert_callback(ctrl_x_mode);
4521 col = call_callback_retnr(cb, 2, args);
4522 --textwinlock;
4523
4524 State = save_State;
4525 curwin->w_cursor = pos; // restore the cursor position
4526 validate_cursor();
4527 if (!EQUAL_POS(curwin->w_cursor, pos))
4528 {
Bram Moolenaar9d00e4a2022-01-05 17:49:15 +00004529 emsg(_(e_complete_function_deleted_text));
Bram Moolenaarbf7ff612021-12-27 12:52:07 +00004530 return FAIL;
4531 }
4532
4533 // Return value -2 means the user complete function wants to
4534 // cancel the complete without an error.
4535 // Return value -3 does the same as -2 and leaves CTRL-X mode.
4536 if (col == -2)
4537 return FAIL;
4538 if (col == -3)
4539 {
4540 ctrl_x_mode = CTRL_X_NORMAL;
4541 edit_submode = NULL;
4542 if (!shortmess(SHM_COMPLETIONMENU))
4543 msg_clr_cmdline();
4544 return FAIL;
4545 }
4546
Yegappan Lakshmanan37079142022-01-08 10:38:48 +00004547 // Reset extended parameters of completion, when starting new
Bram Moolenaarbf7ff612021-12-27 12:52:07 +00004548 // completion.
4549 compl_opt_refresh_always = FALSE;
4550 compl_opt_suppress_empty = FALSE;
4551
4552 if (col < 0)
4553 col = curs_col;
4554 compl_col = col;
4555 if (compl_col > curs_col)
4556 compl_col = curs_col;
4557
4558 // Setup variables for completion. Need to obtain "line" again,
4559 // it may have become invalid.
4560 line = ml_get(curwin->w_cursor.lnum);
4561 compl_length = curs_col - compl_col;
4562 compl_pattern = vim_strnsave(line + compl_col, compl_length);
4563 if (compl_pattern == NULL)
4564 return FAIL;
4565
4566 ret = OK;
4567#endif
4568
4569 return ret;
4570}
4571
4572/*
4573 * Get the pattern, column and length for spell completion.
4574 * Sets the global variables: compl_col, compl_length and compl_pattern.
4575 * Uses the global variable: spell_bad_len
4576 */
4577 static int
4578get_spell_compl_info(int startcol UNUSED, colnr_T curs_col UNUSED)
4579{
4580 int ret = FAIL;
4581#ifdef FEAT_SPELL
4582 char_u *line;
4583
4584 if (spell_bad_len > 0)
4585 compl_col = curs_col - spell_bad_len;
4586 else
4587 compl_col = spell_word_start(startcol);
4588 if (compl_col >= (colnr_T)startcol)
4589 {
4590 compl_length = 0;
4591 compl_col = curs_col;
4592 }
4593 else
4594 {
4595 spell_expand_check_cap(compl_col);
4596 compl_length = (int)curs_col - compl_col;
4597 }
4598 // Need to obtain "line" again, it may have become invalid.
4599 line = ml_get(curwin->w_cursor.lnum);
4600 compl_pattern = vim_strnsave(line + compl_col, compl_length);
4601 if (compl_pattern == NULL)
4602 return FAIL;
4603
4604 ret = OK;
4605#endif
4606
4607 return ret;
4608}
4609
4610/*
4611 * Get the completion pattern, column and length.
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004612 * "startcol" - start column number of the completion pattern/text
4613 * "cur_col" - current cursor column
4614 * On return, "line_invalid" is set to TRUE, if the current line may have
4615 * become invalid and needs to be fetched again.
4616 * Returns OK on success.
Bram Moolenaarbf7ff612021-12-27 12:52:07 +00004617 */
4618 static int
4619compl_get_info(char_u *line, int startcol, colnr_T curs_col, int *line_invalid)
4620{
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004621 if (ctrl_x_mode_normal()
Bram Moolenaarbf7ff612021-12-27 12:52:07 +00004622 || (ctrl_x_mode & CTRL_X_WANT_IDENT
4623 && !thesaurus_func_complete(ctrl_x_mode)))
4624 {
4625 return get_normal_compl_info(line, startcol, curs_col);
4626 }
4627 else if (ctrl_x_mode_line_or_eval())
4628 {
4629 return get_wholeline_compl_info(line, curs_col);
4630 }
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004631 else if (ctrl_x_mode_files())
Bram Moolenaarbf7ff612021-12-27 12:52:07 +00004632 {
4633 return get_filename_compl_info(line, startcol, curs_col);
4634 }
4635 else if (ctrl_x_mode == CTRL_X_CMDLINE)
4636 {
4637 return get_cmdline_compl_info(line, curs_col);
4638 }
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004639 else if (ctrl_x_mode_function() || ctrl_x_mode_omni()
Bram Moolenaarbf7ff612021-12-27 12:52:07 +00004640 || thesaurus_func_complete(ctrl_x_mode))
4641 {
4642 if (get_userdefined_compl_info(curs_col) == FAIL)
4643 return FAIL;
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004644 *line_invalid = TRUE; // "line" may have become invalid
Bram Moolenaarbf7ff612021-12-27 12:52:07 +00004645 }
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004646 else if (ctrl_x_mode_spell())
Bram Moolenaarbf7ff612021-12-27 12:52:07 +00004647 {
4648 if (get_spell_compl_info(startcol, curs_col) == FAIL)
4649 return FAIL;
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004650 *line_invalid = TRUE; // "line" may have become invalid
Bram Moolenaarbf7ff612021-12-27 12:52:07 +00004651 }
4652 else
4653 {
4654 internal_error("ins_complete()");
4655 return FAIL;
4656 }
4657
4658 return OK;
4659}
4660
4661/*
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004662 * Continue an interrupted completion mode search in "line".
4663 *
4664 * If this same ctrl_x_mode has been interrupted use the text from
4665 * "compl_startpos" to the cursor as a pattern to add a new word instead of
4666 * expand the one before the cursor, in word-wise if "compl_startpos" is not in
4667 * the same line as the cursor then fix it (the line has been split because it
4668 * was longer than 'tw'). if SOL is set then skip the previous pattern, a word
4669 * at the beginning of the line has been inserted, we'll look for that.
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004670 */
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004671 static void
4672ins_compl_continue_search(char_u *line)
4673{
4674 // it is a continued search
4675 compl_cont_status &= ~CONT_INTRPT; // remove INTRPT
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004676 if (ctrl_x_mode_normal() || ctrl_x_mode_path_patterns()
4677 || ctrl_x_mode_path_defines())
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004678 {
4679 if (compl_startpos.lnum != curwin->w_cursor.lnum)
4680 {
4681 // line (probably) wrapped, set compl_startpos to the
4682 // first non_blank in the line, if it is not a wordchar
4683 // include it to get a better pattern, but then we don't
4684 // want the "\\<" prefix, check it below
4685 compl_col = (colnr_T)getwhitecols(line);
4686 compl_startpos.col = compl_col;
4687 compl_startpos.lnum = curwin->w_cursor.lnum;
4688 compl_cont_status &= ~CONT_SOL; // clear SOL if present
4689 }
4690 else
4691 {
4692 // S_IPOS was set when we inserted a word that was at the
4693 // beginning of the line, which means that we'll go to SOL
4694 // mode but first we need to redefine compl_startpos
4695 if (compl_cont_status & CONT_S_IPOS)
4696 {
4697 compl_cont_status |= CONT_SOL;
4698 compl_startpos.col = (colnr_T)(skipwhite(
4699 line + compl_length
4700 + compl_startpos.col) - line);
4701 }
4702 compl_col = compl_startpos.col;
4703 }
4704 compl_length = curwin->w_cursor.col - (int)compl_col;
4705 // IObuff is used to add a "word from the next line" would we
4706 // have enough space? just being paranoid
4707#define MIN_SPACE 75
4708 if (compl_length > (IOSIZE - MIN_SPACE))
4709 {
4710 compl_cont_status &= ~CONT_SOL;
4711 compl_length = (IOSIZE - MIN_SPACE);
4712 compl_col = curwin->w_cursor.col - compl_length;
4713 }
4714 compl_cont_status |= CONT_ADDING | CONT_N_ADDS;
4715 if (compl_length < 1)
4716 compl_cont_status &= CONT_LOCAL;
4717 }
4718 else if (ctrl_x_mode_line_or_eval())
4719 compl_cont_status = CONT_ADDING | CONT_N_ADDS;
4720 else
4721 compl_cont_status = 0;
4722}
4723
4724/*
4725 * start insert mode completion
4726 */
4727 static int
4728ins_compl_start(void)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004729{
4730 char_u *line;
4731 int startcol = 0; // column where searched text starts
4732 colnr_T curs_col; // cursor column
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004733 int line_invalid = FALSE;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004734 int save_did_ai = did_ai;
Bram Moolenaard9eefe32019-04-06 14:22:21 +02004735 int flags = CP_ORIGINAL_TEXT;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004736
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004737 // First time we hit ^N or ^P (in a row, I mean)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004738
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004739 did_ai = FALSE;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004740#ifdef FEAT_SMARTINDENT
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004741 did_si = FALSE;
4742 can_si = FALSE;
4743 can_si_back = FALSE;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004744#endif
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004745 if (stop_arrow() == FAIL)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004746 return FAIL;
4747
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004748 line = ml_get(curwin->w_cursor.lnum);
4749 curs_col = curwin->w_cursor.col;
4750 compl_pending = 0;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004751
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004752 if ((compl_cont_status & CONT_INTRPT) == CONT_INTRPT
4753 && compl_cont_mode == ctrl_x_mode)
4754 // this same ctrl-x_mode was interrupted previously. Continue the
4755 // completion.
4756 ins_compl_continue_search(line);
4757 else
4758 compl_cont_status &= CONT_LOCAL;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004759
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004760 if (!compl_status_adding()) // normal expansion
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004761 {
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004762 compl_cont_mode = ctrl_x_mode;
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004763 if (ctrl_x_mode_not_default())
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004764 // Remove LOCAL if ctrl_x_mode != CTRL_X_NORMAL
4765 compl_cont_status = 0;
4766 compl_cont_status |= CONT_N_ADDS;
4767 compl_startpos = curwin->w_cursor;
4768 startcol = (int)curs_col;
4769 compl_col = 0;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004770 }
4771
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004772 // Work out completion pattern and original text -- webb
4773 if (compl_get_info(line, startcol, curs_col, &line_invalid) == FAIL)
4774 {
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004775 if (ctrl_x_mode_function() || ctrl_x_mode_omni()
4776 || thesaurus_func_complete(ctrl_x_mode))
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004777 // restore did_ai, so that adding comment leader works
4778 did_ai = save_did_ai;
4779 return FAIL;
4780 }
4781 // If "line" was changed while getting completion info get it again.
4782 if (line_invalid)
4783 line = ml_get(curwin->w_cursor.lnum);
4784
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004785 if (compl_status_adding())
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004786 {
4787 edit_submode_pre = (char_u *)_(" Adding");
4788 if (ctrl_x_mode_line_or_eval())
4789 {
4790 // Insert a new line, keep indentation but ignore 'comments'.
4791 char_u *old = curbuf->b_p_com;
4792
4793 curbuf->b_p_com = (char_u *)"";
4794 compl_startpos.lnum = curwin->w_cursor.lnum;
4795 compl_startpos.col = compl_col;
4796 ins_eol('\r');
4797 curbuf->b_p_com = old;
4798 compl_length = 0;
4799 compl_col = curwin->w_cursor.col;
4800 }
4801 }
4802 else
4803 {
4804 edit_submode_pre = NULL;
4805 compl_startpos.col = compl_col;
4806 }
4807
4808 if (compl_cont_status & CONT_LOCAL)
4809 edit_submode = (char_u *)_(ctrl_x_msgs[CTRL_X_LOCAL_MSG]);
4810 else
4811 edit_submode = (char_u *)_(CTRL_X_MSG(ctrl_x_mode));
4812
4813 // If any of the original typed text has been changed we need to fix
4814 // the redo buffer.
4815 ins_compl_fixRedoBufForLeader(NULL);
4816
4817 // Always add completion for the original text.
4818 vim_free(compl_orig_text);
4819 compl_orig_text = vim_strnsave(line + compl_col, compl_length);
4820 if (p_ic)
4821 flags |= CP_ICASE;
4822 if (compl_orig_text == NULL || ins_compl_add(compl_orig_text,
4823 -1, NULL, NULL, NULL, 0, flags, FALSE) != OK)
4824 {
4825 VIM_CLEAR(compl_pattern);
4826 VIM_CLEAR(compl_orig_text);
4827 return FAIL;
4828 }
4829
4830 // showmode might reset the internal line pointers, so it must
4831 // be called before line = ml_get(), or when this address is no
4832 // longer needed. -- Acevedo.
4833 edit_submode_extra = (char_u *)_("-- Searching...");
4834 edit_submode_highl = HLF_COUNT;
4835 showmode();
4836 edit_submode_extra = NULL;
4837 out_flush();
4838
4839 return OK;
4840}
4841
4842/*
4843 * display the completion status message
4844 */
4845 static void
4846ins_compl_show_statusmsg(void)
4847{
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004848 // we found no match if the list has only the "compl_orig_text"-entry
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004849 if (is_first_match(compl_first_match->cp_next))
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004850 {
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004851 edit_submode_extra = compl_status_adding() && compl_length > 1
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00004852 ? (char_u *)_(e_hitend)
4853 : (char_u *)_(e_pattern_not_found);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004854 edit_submode_highl = HLF_E;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004855 }
4856
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004857 if (edit_submode_extra == NULL)
4858 {
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004859 if (match_at_original_text(compl_curr_match))
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004860 {
4861 edit_submode_extra = (char_u *)_("Back at original");
4862 edit_submode_highl = HLF_W;
4863 }
4864 else if (compl_cont_status & CONT_S_IPOS)
4865 {
4866 edit_submode_extra = (char_u *)_("Word from other line");
4867 edit_submode_highl = HLF_COUNT;
4868 }
4869 else if (compl_curr_match->cp_next == compl_curr_match->cp_prev)
4870 {
4871 edit_submode_extra = (char_u *)_("The only match");
4872 edit_submode_highl = HLF_COUNT;
Bram Moolenaarf9d51352020-10-26 19:22:42 +01004873 compl_curr_match->cp_number = 1;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004874 }
4875 else
4876 {
Bram Moolenaar977fd0b2020-10-27 09:12:45 +01004877#if defined(FEAT_COMPL_FUNC) || defined(FEAT_EVAL)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004878 // Update completion sequence number when needed.
4879 if (compl_curr_match->cp_number == -1)
Bram Moolenaarf9d51352020-10-26 19:22:42 +01004880 ins_compl_update_sequence_numbers();
Bram Moolenaar977fd0b2020-10-27 09:12:45 +01004881#endif
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004882 // The match should always have a sequence number now, this is
4883 // just a safety check.
4884 if (compl_curr_match->cp_number != -1)
4885 {
4886 // Space for 10 text chars. + 2x10-digit no.s = 31.
4887 // Translations may need more than twice that.
4888 static char_u match_ref[81];
4889
4890 if (compl_matches > 0)
4891 vim_snprintf((char *)match_ref, sizeof(match_ref),
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004892 _("match %d of %d"),
4893 compl_curr_match->cp_number, compl_matches);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004894 else
4895 vim_snprintf((char *)match_ref, sizeof(match_ref),
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004896 _("match %d"),
4897 compl_curr_match->cp_number);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004898 edit_submode_extra = match_ref;
4899 edit_submode_highl = HLF_R;
4900 if (dollar_vcol >= 0)
4901 curs_columns(FALSE);
4902 }
4903 }
4904 }
4905
4906 // Show a message about what (completion) mode we're in.
4907 if (!compl_opt_suppress_empty)
4908 {
4909 showmode();
4910 if (!shortmess(SHM_COMPLETIONMENU))
4911 {
4912 if (edit_submode_extra != NULL)
4913 {
4914 if (!p_smd)
Bram Moolenaarcc233582020-12-12 13:32:07 +01004915 {
4916 msg_hist_off = TRUE;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004917 msg_attr((char *)edit_submode_extra,
4918 edit_submode_highl < HLF_COUNT
4919 ? HL_ATTR(edit_submode_highl) : 0);
Bram Moolenaarcc233582020-12-12 13:32:07 +01004920 msg_hist_off = FALSE;
4921 }
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004922 }
4923 else
4924 msg_clr_cmdline(); // necessary for "noshowmode"
4925 }
4926 }
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004927}
4928
4929/*
4930 * Do Insert mode completion.
4931 * Called when character "c" was typed, which has a meaning for completion.
4932 * Returns OK if completion was done, FAIL if something failed (out of mem).
4933 */
4934 int
4935ins_complete(int c, int enable_pum)
4936{
4937 int n;
4938 int save_w_wrow;
4939 int save_w_leftcol;
4940 int insert_match;
4941
4942 compl_direction = ins_compl_key2dir(c);
4943 insert_match = ins_compl_use_match(c);
4944
4945 if (!compl_started)
4946 {
4947 if (ins_compl_start() == FAIL)
4948 return FAIL;
4949 }
4950 else if (insert_match && stop_arrow() == FAIL)
4951 return FAIL;
4952
4953 compl_shown_match = compl_curr_match;
4954 compl_shows_dir = compl_direction;
4955
4956 // Find next match (and following matches).
4957 save_w_wrow = curwin->w_wrow;
4958 save_w_leftcol = curwin->w_leftcol;
4959 n = ins_compl_next(TRUE, ins_compl_key2count(c), insert_match, FALSE);
4960
4961 // may undisplay the popup menu
4962 ins_compl_upd_pum();
4963
4964 if (n > 1) // all matches have been found
4965 compl_matches = n;
4966 compl_curr_match = compl_shown_match;
4967 compl_direction = compl_shows_dir;
4968
4969 // Eat the ESC that vgetc() returns after a CTRL-C to avoid leaving Insert
4970 // mode.
4971 if (got_int && !global_busy)
4972 {
4973 (void)vgetc();
4974 got_int = FALSE;
4975 }
4976
4977 // we found no match if the list has only the "compl_orig_text"-entry
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004978 if (is_first_match(compl_first_match->cp_next))
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004979 {
4980 // remove N_ADDS flag, so next ^X<> won't try to go to ADDING mode,
4981 // because we couldn't expand anything at first place, but if we used
4982 // ^P, ^N, ^X^I or ^X^D we might want to add-expand a single-char-word
4983 // (such as M in M'exico) if not tried already. -- Acevedo
4984 if (compl_length > 1
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004985 || compl_status_adding()
4986 || (ctrl_x_mode_not_default()
4987 && !ctrl_x_mode_path_patterns()
4988 && !ctrl_x_mode_path_defines()))
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004989 compl_cont_status &= ~CONT_N_ADDS;
4990 }
4991
4992 if (compl_curr_match->cp_flags & CP_CONT_S_IPOS)
4993 compl_cont_status |= CONT_S_IPOS;
4994 else
4995 compl_cont_status &= ~CONT_S_IPOS;
4996
4997 ins_compl_show_statusmsg();
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004998
4999 // Show the popup menu, unless we got interrupted.
5000 if (enable_pum && !compl_interrupted)
5001 show_pum(save_w_wrow, save_w_leftcol);
5002
5003 compl_was_interrupted = compl_interrupted;
5004 compl_interrupted = FALSE;
5005
5006 return OK;
5007}
5008
Yegappan Lakshmanane9825862022-01-03 11:03:48 +00005009/*
5010 * Remove (if needed) and show the popup menu
5011 */
Bram Moolenaar7591bb32019-03-30 13:53:47 +01005012 static void
5013show_pum(int prev_w_wrow, int prev_w_leftcol)
5014{
5015 // RedrawingDisabled may be set when invoked through complete().
5016 int n = RedrawingDisabled;
5017
5018 RedrawingDisabled = 0;
5019
5020 // If the cursor moved or the display scrolled we need to remove the pum
5021 // first.
5022 setcursor();
5023 if (prev_w_wrow != curwin->w_wrow || prev_w_leftcol != curwin->w_leftcol)
5024 ins_compl_del_pum();
5025
5026 ins_compl_show_pum();
5027 setcursor();
5028 RedrawingDisabled = n;
5029}
5030
5031/*
5032 * Looks in the first "len" chars. of "src" for search-metachars.
5033 * If dest is not NULL the chars. are copied there quoting (with
5034 * a backslash) the metachars, and dest would be NUL terminated.
5035 * Returns the length (needed) of dest
5036 */
5037 static unsigned
5038quote_meta(char_u *dest, char_u *src, int len)
5039{
5040 unsigned m = (unsigned)len + 1; // one extra for the NUL
5041
5042 for ( ; --len >= 0; src++)
5043 {
5044 switch (*src)
5045 {
5046 case '.':
5047 case '*':
5048 case '[':
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00005049 if (ctrl_x_mode_dictionary() || ctrl_x_mode_thesaurus())
Bram Moolenaar7591bb32019-03-30 13:53:47 +01005050 break;
5051 // FALLTHROUGH
5052 case '~':
Bram Moolenaarf4e20992020-12-21 19:59:08 +01005053 if (!magic_isset()) // quote these only if magic is set
Bram Moolenaar7591bb32019-03-30 13:53:47 +01005054 break;
5055 // FALLTHROUGH
5056 case '\\':
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00005057 if (ctrl_x_mode_dictionary() || ctrl_x_mode_thesaurus())
Bram Moolenaar7591bb32019-03-30 13:53:47 +01005058 break;
5059 // FALLTHROUGH
5060 case '^': // currently it's not needed.
5061 case '$':
5062 m++;
5063 if (dest != NULL)
5064 *dest++ = '\\';
5065 break;
5066 }
5067 if (dest != NULL)
5068 *dest++ = *src;
5069 // Copy remaining bytes of a multibyte character.
5070 if (has_mbyte)
5071 {
5072 int i, mb_len;
5073
5074 mb_len = (*mb_ptr2len)(src) - 1;
5075 if (mb_len > 0 && len >= mb_len)
5076 for (i = 0; i < mb_len; ++i)
5077 {
5078 --len;
5079 ++src;
5080 if (dest != NULL)
5081 *dest++ = *src;
5082 }
5083 }
5084 }
5085 if (dest != NULL)
5086 *dest = NUL;
5087
5088 return m;
5089}
5090
Bram Moolenaare2c453d2019-08-21 14:37:09 +02005091#if defined(EXITFREE) || defined(PROTO)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01005092 void
5093free_insexpand_stuff(void)
5094{
5095 VIM_CLEAR(compl_orig_text);
Yegappan Lakshmanan8658c752021-12-03 11:09:29 +00005096# ifdef FEAT_EVAL
5097 free_callback(&cfu_cb);
5098 free_callback(&ofu_cb);
5099 free_callback(&tsrfu_cb);
5100# endif
Bram Moolenaar7591bb32019-03-30 13:53:47 +01005101}
Bram Moolenaare2c453d2019-08-21 14:37:09 +02005102#endif
Bram Moolenaar7591bb32019-03-30 13:53:47 +01005103
Bram Moolenaare2c453d2019-08-21 14:37:09 +02005104#ifdef FEAT_SPELL
Bram Moolenaar7591bb32019-03-30 13:53:47 +01005105/*
5106 * Called when starting CTRL_X_SPELL mode: Move backwards to a previous badly
5107 * spelled word, if there is one.
5108 */
5109 static void
5110spell_back_to_badword(void)
5111{
5112 pos_T tpos = curwin->w_cursor;
5113
5114 spell_bad_len = spell_move_to(curwin, BACKWARD, TRUE, TRUE, NULL);
5115 if (curwin->w_cursor.col != tpos.col)
5116 start_arrow(&tpos);
5117}
Bram Moolenaare2c453d2019-08-21 14:37:09 +02005118#endif