blob: b7b6c0256cae0a3d1147ba30f7b85248e9f3ef2d [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 Moolenaare32c3c42022-01-15 18:26:04 +00002284 || c == K_MOUSELEFT || c == K_MOUSERIGHT
2285 || c == K_COMMAND || c == K_SCRIPT_COMMAND)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002286 return retval;
2287
Bram Moolenaar05ad5ff2019-11-30 22:48:27 +01002288#ifdef FEAT_PROP_POPUP
Bram Moolenaarf0bc15c2019-08-18 19:23:45 +02002289 // Ignore mouse events in a popup window
2290 if (is_mouse_key(c))
2291 {
2292 // Ignore drag and release events, the position does not need to be in
2293 // the popup and it may have just closed.
2294 if (c == K_LEFTRELEASE
2295 || c == K_LEFTRELEASE_NM
2296 || c == K_MIDDLERELEASE
2297 || c == K_RIGHTRELEASE
2298 || c == K_X1RELEASE
2299 || c == K_X2RELEASE
2300 || c == K_LEFTDRAG
2301 || c == K_MIDDLEDRAG
2302 || c == K_RIGHTDRAG
2303 || c == K_X1DRAG
2304 || c == K_X2DRAG)
2305 return retval;
2306 if (popup_visible)
2307 {
2308 int row = mouse_row;
2309 int col = mouse_col;
2310 win_T *wp = mouse_find_win(&row, &col, FIND_POPUP);
2311
2312 if (wp != NULL && WIN_IS_POPUP(wp))
2313 return retval;
2314 }
2315 }
2316#endif
2317
zeertzjqdca29d92021-08-31 19:12:51 +02002318 if (ctrl_x_mode == CTRL_X_CMDLINE_CTRL_X && c != Ctrl_X)
2319 {
2320 if (c == Ctrl_V || c == Ctrl_Q || c == Ctrl_Z || ins_compl_pum_key(c)
2321 || !vim_is_ctrl_x_key(c))
2322 {
2323 // Not starting another completion mode.
2324 ctrl_x_mode = CTRL_X_CMDLINE;
2325
2326 // CTRL-X CTRL-Z should stop completion without inserting anything
2327 if (c == Ctrl_Z)
2328 retval = TRUE;
2329 }
2330 else
2331 {
2332 ctrl_x_mode = CTRL_X_CMDLINE;
2333
2334 // Other CTRL-X keys first stop completion, then start another
2335 // completion mode.
2336 ins_compl_prep(' ');
2337 ctrl_x_mode = CTRL_X_NOT_DEFINED_YET;
2338 }
2339 }
2340
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002341 // Set "compl_get_longest" when finding the first matches.
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00002342 if (ctrl_x_mode_not_defined_yet()
2343 || (ctrl_x_mode_normal() && !compl_started))
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002344 {
2345 compl_get_longest = (strstr((char *)p_cot, "longest") != NULL);
2346 compl_used_match = TRUE;
2347
2348 }
2349
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00002350 if (ctrl_x_mode_not_defined_yet())
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002351 // We have just typed CTRL-X and aren't quite sure which CTRL-X mode
2352 // it will be yet. Now we decide.
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00002353 retval = set_ctrl_x_mode(c);
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00002354 else if (ctrl_x_mode_not_default())
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002355 {
2356 // We're already in CTRL-X mode, do we stay in it?
2357 if (!vim_is_ctrl_x_key(c))
2358 {
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00002359 if (ctrl_x_mode_scroll())
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002360 ctrl_x_mode = CTRL_X_NORMAL;
2361 else
2362 ctrl_x_mode = CTRL_X_FINISHED;
2363 edit_submode = NULL;
2364 }
2365 showmode();
2366 }
2367
2368 if (compl_started || ctrl_x_mode == CTRL_X_FINISHED)
2369 {
2370 // Show error message from attempted keyword completion (probably
2371 // 'Pattern not found') until another key is hit, then go back to
2372 // showing what mode we are in.
2373 showmode();
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00002374 if ((ctrl_x_mode_normal() && c != Ctrl_N && c != Ctrl_P
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002375 && c != Ctrl_R && !ins_compl_pum_key(c))
2376 || ctrl_x_mode == CTRL_X_FINISHED)
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00002377 retval = ins_compl_stop(c, prev_mode, retval);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002378 }
2379 else if (ctrl_x_mode == CTRL_X_LOCAL_MSG)
2380 // Trigger the CompleteDone event to give scripts a chance to act
2381 // upon the (possibly failed) completion.
2382 ins_apply_autocmds(EVENT_COMPLETEDONE);
2383
=?UTF-8?q?Magnus=20Gro=C3=9F?=25def2c2021-10-22 18:56:39 +01002384 trigger_modechanged();
2385
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002386 // reset continue_* if we left expansion-mode, if we stay they'll be
2387 // (re)set properly in ins_complete()
2388 if (!vim_is_ctrl_x_key(c))
2389 {
2390 compl_cont_status = 0;
2391 compl_cont_mode = 0;
2392 }
2393
2394 return retval;
2395}
2396
2397/*
2398 * Fix the redo buffer for the completion leader replacing some of the typed
2399 * text. This inserts backspaces and appends the changed text.
2400 * "ptr" is the known leader text or NUL.
2401 */
2402 static void
2403ins_compl_fixRedoBufForLeader(char_u *ptr_arg)
2404{
2405 int len;
2406 char_u *p;
2407 char_u *ptr = ptr_arg;
2408
2409 if (ptr == NULL)
2410 {
2411 if (compl_leader != NULL)
2412 ptr = compl_leader;
2413 else
2414 return; // nothing to do
2415 }
2416 if (compl_orig_text != NULL)
2417 {
2418 p = compl_orig_text;
2419 for (len = 0; p[len] != NUL && p[len] == ptr[len]; ++len)
2420 ;
2421 if (len > 0)
2422 len -= (*mb_head_off)(p, p + len);
2423 for (p += len; *p != NUL; MB_PTR_ADV(p))
2424 AppendCharToRedobuff(K_BS);
2425 }
2426 else
2427 len = 0;
2428 if (ptr != NULL)
2429 AppendToRedobuffLit(ptr + len, -1);
2430}
2431
2432/*
2433 * Loops through the list of windows, loaded-buffers or non-loaded-buffers
2434 * (depending on flag) starting from buf and looking for a non-scanned
2435 * buffer (other than curbuf). curbuf is special, if it is called with
2436 * buf=curbuf then it has to be the first call for a given flag/expansion.
2437 *
2438 * Returns the buffer to scan, if any, otherwise returns curbuf -- Acevedo
2439 */
2440 static buf_T *
2441ins_compl_next_buf(buf_T *buf, int flag)
2442{
2443 static win_T *wp = NULL;
2444
2445 if (flag == 'w') // just windows
2446 {
2447 if (buf == curbuf || wp == NULL) // first call for this flag/expansion
2448 wp = curwin;
2449 while ((wp = (wp->w_next != NULL ? wp->w_next : firstwin)) != curwin
2450 && wp->w_buffer->b_scanned)
2451 ;
2452 buf = wp->w_buffer;
2453 }
2454 else
2455 // 'b' (just loaded buffers), 'u' (just non-loaded buffers) or 'U'
2456 // (unlisted buffers)
2457 // When completing whole lines skip unloaded buffers.
2458 while ((buf = (buf->b_next != NULL ? buf->b_next : firstbuf)) != curbuf
2459 && ((flag == 'U'
2460 ? buf->b_p_bl
2461 : (!buf->b_p_bl
2462 || (buf->b_ml.ml_mfp == NULL) != (flag == 'u')))
2463 || buf->b_scanned))
2464 ;
2465 return buf;
2466}
2467
2468#ifdef FEAT_COMPL_FUNC
Yegappan Lakshmanan8658c752021-12-03 11:09:29 +00002469
2470# ifdef FEAT_EVAL
2471static callback_T cfu_cb; // 'completefunc' callback function
2472static callback_T ofu_cb; // 'omnifunc' callback function
2473static callback_T tsrfu_cb; // 'thesaurusfunc' callback function
2474# endif
2475
2476/*
2477 * Copy a global callback function to a buffer local callback.
2478 */
2479 static void
2480copy_global_to_buflocal_cb(callback_T *globcb, callback_T *bufcb)
2481{
2482 free_callback(bufcb);
2483 if (globcb->cb_name != NULL && *globcb->cb_name != NUL)
2484 copy_callback(bufcb, globcb);
2485}
2486
2487/*
2488 * Parse the 'completefunc' option value and set the callback function.
2489 * Invoked when the 'completefunc' option is set. The option value can be a
2490 * name of a function (string), or function(<name>) or funcref(<name>) or a
2491 * lambda expression.
2492 */
2493 int
2494set_completefunc_option(void)
2495{
2496 int retval;
2497
2498 retval = option_set_callback_func(curbuf->b_p_cfu, &cfu_cb);
2499 if (retval == OK)
2500 set_buflocal_cfu_callback(curbuf);
2501
2502 return retval;
2503}
2504
2505/*
2506 * Copy the global 'completefunc' callback function to the buffer-local
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00002507 * 'completefunc' callback for "buf".
Yegappan Lakshmanan8658c752021-12-03 11:09:29 +00002508 */
2509 void
2510set_buflocal_cfu_callback(buf_T *buf UNUSED)
2511{
2512# ifdef FEAT_EVAL
2513 copy_global_to_buflocal_cb(&cfu_cb, &buf->b_cfu_cb);
2514# endif
2515}
2516
2517/*
2518 * Parse the 'omnifunc' option value and set the callback function.
2519 * Invoked when the 'omnifunc' option is set. The option value can be a
2520 * name of a function (string), or function(<name>) or funcref(<name>) or a
2521 * lambda expression.
2522 */
2523 int
2524set_omnifunc_option(void)
2525{
2526 int retval;
2527
2528 retval = option_set_callback_func(curbuf->b_p_ofu, &ofu_cb);
2529 if (retval == OK)
2530 set_buflocal_ofu_callback(curbuf);
2531
2532 return retval;
2533}
2534
2535/*
2536 * Copy the global 'omnifunc' callback function to the buffer-local 'omnifunc'
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00002537 * callback for "buf".
Yegappan Lakshmanan8658c752021-12-03 11:09:29 +00002538 */
2539 void
2540set_buflocal_ofu_callback(buf_T *buf UNUSED)
2541{
2542# ifdef FEAT_EVAL
2543 copy_global_to_buflocal_cb(&ofu_cb, &buf->b_ofu_cb);
2544# endif
2545}
2546
2547/*
2548 * Parse the 'thesaurusfunc' option value and set the callback function.
2549 * Invoked when the 'thesaurusfunc' option is set. The option value can be a
2550 * name of a function (string), or function(<name>) or funcref(<name>) or a
2551 * lambda expression.
2552 */
2553 int
2554set_thesaurusfunc_option(void)
2555{
2556 int retval;
2557
2558 if (*curbuf->b_p_tsrfu != NUL)
2559 {
2560 // buffer-local option set
Yegappan Lakshmanan8658c752021-12-03 11:09:29 +00002561 retval = option_set_callback_func(curbuf->b_p_tsrfu,
2562 &curbuf->b_tsrfu_cb);
2563 }
2564 else
2565 {
2566 // global option set
Yegappan Lakshmanan8658c752021-12-03 11:09:29 +00002567 retval = option_set_callback_func(p_tsrfu, &tsrfu_cb);
2568 }
2569
2570 return retval;
2571}
2572
Yegappan Lakshmanan6ae8fae2021-12-12 16:26:44 +00002573/*
2574 * Mark the global 'completefunc' 'omnifunc' and 'thesaurusfunc' callbacks with
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00002575 * "copyID" so that they are not garbage collected.
Yegappan Lakshmanan6ae8fae2021-12-12 16:26:44 +00002576 */
2577 int
2578set_ref_in_insexpand_funcs(int copyID)
2579{
2580 int abort = FALSE;
2581
2582 abort = set_ref_in_callback(&cfu_cb, copyID);
2583 abort = abort || set_ref_in_callback(&ofu_cb, copyID);
2584 abort = abort || set_ref_in_callback(&tsrfu_cb, copyID);
2585
2586 return abort;
2587}
Yegappan Lakshmanan8658c752021-12-03 11:09:29 +00002588
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002589/*
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00002590 * Get the user-defined completion function name for completion "type"
Yegappan Lakshmanan160e9942021-10-16 15:41:29 +01002591 */
2592 static char_u *
2593get_complete_funcname(int type)
2594{
2595 switch (type)
2596 {
2597 case CTRL_X_FUNCTION:
2598 return curbuf->b_p_cfu;
2599 case CTRL_X_OMNI:
2600 return curbuf->b_p_ofu;
2601 case CTRL_X_THESAURUS:
Bram Moolenaarf4d8b762021-10-17 14:13:09 +01002602 return *curbuf->b_p_tsrfu == NUL ? p_tsrfu : curbuf->b_p_tsrfu;
Yegappan Lakshmanan160e9942021-10-16 15:41:29 +01002603 default:
2604 return (char_u *)"";
2605 }
2606}
2607
2608/*
Yegappan Lakshmanan8658c752021-12-03 11:09:29 +00002609 * Get the callback to use for insert mode completion.
2610 */
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00002611 static callback_T *
Yegappan Lakshmanan8658c752021-12-03 11:09:29 +00002612get_insert_callback(int type)
2613{
2614 if (type == CTRL_X_FUNCTION)
2615 return &curbuf->b_cfu_cb;
2616 if (type == CTRL_X_OMNI)
2617 return &curbuf->b_ofu_cb;
2618 // CTRL_X_THESAURUS
2619 return (*curbuf->b_p_tsrfu != NUL) ? &curbuf->b_tsrfu_cb : &tsrfu_cb;
2620}
2621
2622/*
Yegappan Lakshmanan05e59e32021-12-01 10:30:07 +00002623 * Execute user defined complete function 'completefunc', 'omnifunc' or
2624 * 'thesaurusfunc', and get matches in "matches".
2625 * "type" is either CTRL_X_OMNI or CTRL_X_FUNCTION or CTRL_X_THESAURUS.
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002626 */
2627 static void
Yegappan Lakshmanan05e59e32021-12-01 10:30:07 +00002628expand_by_function(int type, char_u *base)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002629{
2630 list_T *matchlist = NULL;
2631 dict_T *matchdict = NULL;
2632 typval_T args[3];
2633 char_u *funcname;
2634 pos_T pos;
Yegappan Lakshmanan8658c752021-12-03 11:09:29 +00002635 callback_T *cb;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002636 typval_T rettv;
2637 int save_State = State;
Yegappan Lakshmanan8658c752021-12-03 11:09:29 +00002638 int retval;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002639
Yegappan Lakshmanan160e9942021-10-16 15:41:29 +01002640 funcname = get_complete_funcname(type);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002641 if (*funcname == NUL)
2642 return;
2643
2644 // Call 'completefunc' to obtain the list of matches.
2645 args[0].v_type = VAR_NUMBER;
2646 args[0].vval.v_number = 0;
2647 args[1].v_type = VAR_STRING;
2648 args[1].vval.v_string = base != NULL ? base : (char_u *)"";
2649 args[2].v_type = VAR_UNKNOWN;
2650
2651 pos = curwin->w_cursor;
Bram Moolenaar28976e22021-01-29 21:07:07 +01002652 // Lock the text to avoid weird things from happening. Also disallow
2653 // switching to another window, it should not be needed and may end up in
2654 // Insert mode in another buffer.
2655 ++textwinlock;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002656
Yegappan Lakshmanan8658c752021-12-03 11:09:29 +00002657 cb = get_insert_callback(type);
2658 retval = call_callback(cb, 0, &rettv, 2, args);
2659
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002660 // Call a function, which returns a list or dict.
Yegappan Lakshmanan8658c752021-12-03 11:09:29 +00002661 if (retval == OK)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002662 {
2663 switch (rettv.v_type)
2664 {
2665 case VAR_LIST:
2666 matchlist = rettv.vval.v_list;
2667 break;
2668 case VAR_DICT:
2669 matchdict = rettv.vval.v_dict;
2670 break;
2671 case VAR_SPECIAL:
2672 if (rettv.vval.v_number == VVAL_NONE)
2673 compl_opt_suppress_empty = TRUE;
2674 // FALLTHROUGH
2675 default:
2676 // TODO: Give error message?
2677 clear_tv(&rettv);
2678 break;
2679 }
2680 }
Bram Moolenaar28976e22021-01-29 21:07:07 +01002681 --textwinlock;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002682
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002683 curwin->w_cursor = pos; // restore the cursor position
2684 validate_cursor();
2685 if (!EQUAL_POS(curwin->w_cursor, pos))
2686 {
Bram Moolenaar9d00e4a2022-01-05 17:49:15 +00002687 emsg(_(e_complete_function_deleted_text));
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002688 goto theend;
2689 }
2690
2691 if (matchlist != NULL)
2692 ins_compl_add_list(matchlist);
2693 else if (matchdict != NULL)
2694 ins_compl_add_dict(matchdict);
2695
2696theend:
2697 // Restore State, it might have been changed.
2698 State = save_State;
2699
2700 if (matchdict != NULL)
2701 dict_unref(matchdict);
2702 if (matchlist != NULL)
2703 list_unref(matchlist);
2704}
2705#endif // FEAT_COMPL_FUNC
2706
2707#if defined(FEAT_COMPL_FUNC) || defined(FEAT_EVAL) || defined(PROTO)
2708/*
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02002709 * Add a match to the list of matches from a typeval_T.
2710 * If the given string is already in the list of completions, then return
2711 * NOTDONE, otherwise add it to the list and return OK. If there is an error,
2712 * maybe because alloc() returns NULL, then FAIL is returned.
Bram Moolenaar440cf092021-04-03 20:13:30 +02002713 * When "fast" is TRUE use fast_breakcheck() instead of ui_breakcheck().
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02002714 */
2715 static int
Bram Moolenaar440cf092021-04-03 20:13:30 +02002716ins_compl_add_tv(typval_T *tv, int dir, int fast)
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02002717{
2718 char_u *word;
2719 int dup = FALSE;
2720 int empty = FALSE;
Bram Moolenaar440cf092021-04-03 20:13:30 +02002721 int flags = fast ? CP_FAST : 0;
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02002722 char_u *(cptext[CPT_COUNT]);
Bram Moolenaar08928322020-01-04 14:32:48 +01002723 typval_T user_data;
Yegappan Lakshmanan37079142022-01-08 10:38:48 +00002724 int status;
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02002725
Bram Moolenaar08928322020-01-04 14:32:48 +01002726 user_data.v_type = VAR_UNKNOWN;
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02002727 if (tv->v_type == VAR_DICT && tv->vval.v_dict != NULL)
2728 {
2729 word = dict_get_string(tv->vval.v_dict, (char_u *)"word", FALSE);
2730 cptext[CPT_ABBR] = dict_get_string(tv->vval.v_dict,
2731 (char_u *)"abbr", FALSE);
2732 cptext[CPT_MENU] = dict_get_string(tv->vval.v_dict,
2733 (char_u *)"menu", FALSE);
2734 cptext[CPT_KIND] = dict_get_string(tv->vval.v_dict,
2735 (char_u *)"kind", FALSE);
2736 cptext[CPT_INFO] = dict_get_string(tv->vval.v_dict,
2737 (char_u *)"info", FALSE);
Bram Moolenaar08928322020-01-04 14:32:48 +01002738 dict_get_tv(tv->vval.v_dict, (char_u *)"user_data", &user_data);
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02002739 if (dict_get_string(tv->vval.v_dict, (char_u *)"icase", FALSE) != NULL
2740 && dict_get_number(tv->vval.v_dict, (char_u *)"icase"))
2741 flags |= CP_ICASE;
2742 if (dict_get_string(tv->vval.v_dict, (char_u *)"dup", FALSE) != NULL)
2743 dup = dict_get_number(tv->vval.v_dict, (char_u *)"dup");
2744 if (dict_get_string(tv->vval.v_dict, (char_u *)"empty", FALSE) != NULL)
2745 empty = dict_get_number(tv->vval.v_dict, (char_u *)"empty");
2746 if (dict_get_string(tv->vval.v_dict, (char_u *)"equal", FALSE) != NULL
2747 && dict_get_number(tv->vval.v_dict, (char_u *)"equal"))
2748 flags |= CP_EQUAL;
2749 }
2750 else
2751 {
2752 word = tv_get_string_chk(tv);
Bram Moolenaara80faa82020-04-12 19:37:17 +02002753 CLEAR_FIELD(cptext);
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02002754 }
2755 if (word == NULL || (!empty && *word == NUL))
Yegappan Lakshmanan37079142022-01-08 10:38:48 +00002756 {
2757 clear_tv(&user_data);
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02002758 return FAIL;
Yegappan Lakshmanan37079142022-01-08 10:38:48 +00002759 }
2760 status = ins_compl_add(word, -1, NULL, cptext, &user_data, dir, flags, dup);
2761 if (status != OK)
2762 clear_tv(&user_data);
2763 return status;
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02002764}
2765
2766/*
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002767 * Add completions from a list.
2768 */
2769 static void
2770ins_compl_add_list(list_T *list)
2771{
2772 listitem_T *li;
2773 int dir = compl_direction;
2774
2775 // Go through the List with matches and add each of them.
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02002776 CHECK_LIST_MATERIALIZE(list);
Bram Moolenaaraeea7212020-04-02 18:50:46 +02002777 FOR_ALL_LIST_ITEMS(list, li)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002778 {
Bram Moolenaar440cf092021-04-03 20:13:30 +02002779 if (ins_compl_add_tv(&li->li_tv, dir, TRUE) == OK)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002780 // if dir was BACKWARD then honor it just once
2781 dir = FORWARD;
2782 else if (did_emsg)
2783 break;
2784 }
2785}
2786
2787/*
2788 * Add completions from a dict.
2789 */
2790 static void
2791ins_compl_add_dict(dict_T *dict)
2792{
2793 dictitem_T *di_refresh;
2794 dictitem_T *di_words;
2795
2796 // Check for optional "refresh" item.
2797 compl_opt_refresh_always = FALSE;
2798 di_refresh = dict_find(dict, (char_u *)"refresh", 7);
2799 if (di_refresh != NULL && di_refresh->di_tv.v_type == VAR_STRING)
2800 {
2801 char_u *v = di_refresh->di_tv.vval.v_string;
2802
2803 if (v != NULL && STRCMP(v, (char_u *)"always") == 0)
2804 compl_opt_refresh_always = TRUE;
2805 }
2806
2807 // Add completions from a "words" list.
2808 di_words = dict_find(dict, (char_u *)"words", 5);
2809 if (di_words != NULL && di_words->di_tv.v_type == VAR_LIST)
2810 ins_compl_add_list(di_words->di_tv.vval.v_list);
2811}
2812
2813/*
Bram Moolenaar9cb698d2019-08-21 15:30:45 +02002814 * Start completion for the complete() function.
2815 * "startcol" is where the matched text starts (1 is first column).
2816 * "list" is the list of matches.
2817 */
2818 static void
2819set_completion(colnr_T startcol, list_T *list)
2820{
2821 int save_w_wrow = curwin->w_wrow;
2822 int save_w_leftcol = curwin->w_leftcol;
2823 int flags = CP_ORIGINAL_TEXT;
2824
2825 // If already doing completions stop it.
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00002826 if (ctrl_x_mode_not_default())
Bram Moolenaar9cb698d2019-08-21 15:30:45 +02002827 ins_compl_prep(' ');
2828 ins_compl_clear();
2829 ins_compl_free();
2830
2831 compl_direction = FORWARD;
2832 if (startcol > curwin->w_cursor.col)
2833 startcol = curwin->w_cursor.col;
2834 compl_col = startcol;
2835 compl_length = (int)curwin->w_cursor.col - (int)startcol;
2836 // compl_pattern doesn't need to be set
2837 compl_orig_text = vim_strnsave(ml_get_curline() + compl_col, compl_length);
2838 if (p_ic)
2839 flags |= CP_ICASE;
2840 if (compl_orig_text == NULL || ins_compl_add(compl_orig_text,
Bram Moolenaar440cf092021-04-03 20:13:30 +02002841 -1, NULL, NULL, NULL, 0,
2842 flags | CP_FAST, FALSE) != OK)
Bram Moolenaar9cb698d2019-08-21 15:30:45 +02002843 return;
2844
2845 ctrl_x_mode = CTRL_X_EVAL;
2846
2847 ins_compl_add_list(list);
2848 compl_matches = ins_compl_make_cyclic();
2849 compl_started = TRUE;
2850 compl_used_match = TRUE;
2851 compl_cont_status = 0;
2852
2853 compl_curr_match = compl_first_match;
2854 if (compl_no_insert || compl_no_select)
2855 {
2856 ins_complete(K_DOWN, FALSE);
2857 if (compl_no_select)
2858 // Down/Up has no real effect.
2859 ins_complete(K_UP, FALSE);
2860 }
2861 else
2862 ins_complete(Ctrl_N, FALSE);
2863 compl_enter_selects = compl_no_insert;
2864
2865 // Lazily show the popup menu, unless we got interrupted.
2866 if (!compl_interrupted)
2867 show_pum(save_w_wrow, save_w_leftcol);
=?UTF-8?q?Magnus=20Gro=C3=9F?=25def2c2021-10-22 18:56:39 +01002868 trigger_modechanged();
Bram Moolenaar9cb698d2019-08-21 15:30:45 +02002869 out_flush();
2870}
2871
2872/*
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02002873 * "complete()" function
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002874 */
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02002875 void
2876f_complete(typval_T *argvars, typval_T *rettv UNUSED)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002877{
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02002878 int startcol;
Bram Moolenaarff06f282020-04-21 22:01:14 +02002879 int save_textlock = textlock;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002880
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +02002881 if (in_vim9script()
2882 && (check_for_number_arg(argvars, 0) == FAIL
2883 || check_for_list_arg(argvars, 1) == FAIL))
2884 return;
2885
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02002886 if ((State & INSERT) == 0)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002887 {
Bram Moolenaar677658a2022-01-05 16:09:06 +00002888 emsg(_(e_complete_can_only_be_used_in_insert_mode));
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02002889 return;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002890 }
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02002891
Bram Moolenaar6adb9ea2020-04-30 22:31:18 +02002892 // "textlock" is set when evaluating 'completefunc' but we can change
2893 // text here.
Bram Moolenaarff06f282020-04-21 22:01:14 +02002894 textlock = 0;
2895
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02002896 // Check for undo allowed here, because if something was already inserted
2897 // the line was already saved for undo and this check isn't done.
2898 if (!undo_allowed())
2899 return;
2900
2901 if (argvars[1].v_type != VAR_LIST || argvars[1].vval.v_list == NULL)
Bram Moolenaar436b5ad2021-12-31 22:49:24 +00002902 emsg(_(e_invalid_argument));
Bram Moolenaarff06f282020-04-21 22:01:14 +02002903 else
2904 {
2905 startcol = (int)tv_get_number_chk(&argvars[0], NULL);
2906 if (startcol > 0)
2907 set_completion(startcol - 1, argvars[1].vval.v_list);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01002908 }
Bram Moolenaarff06f282020-04-21 22:01:14 +02002909 textlock = save_textlock;
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02002910}
2911
2912/*
2913 * "complete_add()" function
2914 */
2915 void
2916f_complete_add(typval_T *argvars, typval_T *rettv)
2917{
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +02002918 if (in_vim9script() && check_for_string_or_dict_arg(argvars, 0) == FAIL)
Yegappan Lakshmanan83494b42021-07-20 17:51:51 +02002919 return;
2920
Bram Moolenaar440cf092021-04-03 20:13:30 +02002921 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0, FALSE);
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02002922}
2923
2924/*
2925 * "complete_check()" function
2926 */
2927 void
2928f_complete_check(typval_T *argvars UNUSED, typval_T *rettv)
2929{
2930 int saved = RedrawingDisabled;
2931
2932 RedrawingDisabled = 0;
2933 ins_compl_check_keys(0, TRUE);
2934 rettv->vval.v_number = ins_compl_interrupted();
2935 RedrawingDisabled = saved;
2936}
2937
2938/*
Bram Moolenaar9cb698d2019-08-21 15:30:45 +02002939 * Return Insert completion mode name string
2940 */
2941 static char_u *
2942ins_compl_mode(void)
2943{
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00002944 if (ctrl_x_mode_not_defined_yet() || ctrl_x_mode_scroll() || compl_started)
Bram Moolenaar9cb698d2019-08-21 15:30:45 +02002945 return (char_u *)ctrl_x_mode_names[ctrl_x_mode & ~CTRL_X_WANT_IDENT];
2946
2947 return (char_u *)"";
2948}
2949
Yegappan Lakshmanane9825862022-01-03 11:03:48 +00002950/*
2951 * Assign the sequence number to all the completion matches which don't have
2952 * one assigned yet.
2953 */
Bram Moolenaarf9d51352020-10-26 19:22:42 +01002954 static void
2955ins_compl_update_sequence_numbers()
2956{
2957 int number = 0;
2958 compl_T *match;
2959
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00002960 if (compl_dir_forward())
Bram Moolenaarf9d51352020-10-26 19:22:42 +01002961 {
2962 // search backwards for the first valid (!= -1) number.
2963 // This should normally succeed already at the first loop
2964 // cycle, so it's fast!
2965 for (match = compl_curr_match->cp_prev; match != NULL
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00002966 && !is_first_match(match); match = match->cp_prev)
Bram Moolenaarf9d51352020-10-26 19:22:42 +01002967 if (match->cp_number != -1)
2968 {
2969 number = match->cp_number;
2970 break;
2971 }
2972 if (match != NULL)
2973 // go up and assign all numbers which are not assigned
2974 // yet
2975 for (match = match->cp_next;
2976 match != NULL && match->cp_number == -1;
2977 match = match->cp_next)
2978 match->cp_number = ++number;
2979 }
2980 else // BACKWARD
2981 {
2982 // search forwards (upwards) for the first valid (!= -1)
2983 // number. This should normally succeed already at the
2984 // first loop cycle, so it's fast!
2985 for (match = compl_curr_match->cp_next; match != NULL
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00002986 && !is_first_match(match); match = match->cp_next)
Bram Moolenaarf9d51352020-10-26 19:22:42 +01002987 if (match->cp_number != -1)
2988 {
2989 number = match->cp_number;
2990 break;
2991 }
2992 if (match != NULL)
2993 // go down and assign all numbers which are not
2994 // assigned yet
2995 for (match = match->cp_prev; match
2996 && match->cp_number == -1;
2997 match = match->cp_prev)
2998 match->cp_number = ++number;
2999 }
3000}
3001
Bram Moolenaar9cb698d2019-08-21 15:30:45 +02003002/*
3003 * Get complete information
3004 */
3005 static void
3006get_complete_info(list_T *what_list, dict_T *retdict)
3007{
3008 int ret = OK;
3009 listitem_T *item;
3010#define CI_WHAT_MODE 0x01
3011#define CI_WHAT_PUM_VISIBLE 0x02
3012#define CI_WHAT_ITEMS 0x04
3013#define CI_WHAT_SELECTED 0x08
3014#define CI_WHAT_INSERTED 0x10
3015#define CI_WHAT_ALL 0xff
3016 int what_flag;
3017
3018 if (what_list == NULL)
3019 what_flag = CI_WHAT_ALL;
3020 else
3021 {
3022 what_flag = 0;
Bram Moolenaar7e9f3512020-05-13 22:44:22 +02003023 CHECK_LIST_MATERIALIZE(what_list);
Bram Moolenaaraeea7212020-04-02 18:50:46 +02003024 FOR_ALL_LIST_ITEMS(what_list, item)
Bram Moolenaar9cb698d2019-08-21 15:30:45 +02003025 {
3026 char_u *what = tv_get_string(&item->li_tv);
3027
3028 if (STRCMP(what, "mode") == 0)
3029 what_flag |= CI_WHAT_MODE;
3030 else if (STRCMP(what, "pum_visible") == 0)
3031 what_flag |= CI_WHAT_PUM_VISIBLE;
3032 else if (STRCMP(what, "items") == 0)
3033 what_flag |= CI_WHAT_ITEMS;
3034 else if (STRCMP(what, "selected") == 0)
3035 what_flag |= CI_WHAT_SELECTED;
3036 else if (STRCMP(what, "inserted") == 0)
3037 what_flag |= CI_WHAT_INSERTED;
3038 }
3039 }
3040
3041 if (ret == OK && (what_flag & CI_WHAT_MODE))
3042 ret = dict_add_string(retdict, "mode", ins_compl_mode());
3043
3044 if (ret == OK && (what_flag & CI_WHAT_PUM_VISIBLE))
3045 ret = dict_add_number(retdict, "pum_visible", pum_visible());
3046
3047 if (ret == OK && (what_flag & CI_WHAT_ITEMS))
3048 {
3049 list_T *li;
3050 dict_T *di;
3051 compl_T *match;
3052
3053 li = list_alloc();
3054 if (li == NULL)
3055 return;
3056 ret = dict_add_list(retdict, "items", li);
3057 if (ret == OK && compl_first_match != NULL)
3058 {
3059 match = compl_first_match;
3060 do
3061 {
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003062 if (!match_at_original_text(match))
Bram Moolenaar9cb698d2019-08-21 15:30:45 +02003063 {
3064 di = dict_alloc();
3065 if (di == NULL)
3066 return;
3067 ret = list_append_dict(li, di);
3068 if (ret != OK)
3069 return;
3070 dict_add_string(di, "word", match->cp_str);
3071 dict_add_string(di, "abbr", match->cp_text[CPT_ABBR]);
3072 dict_add_string(di, "menu", match->cp_text[CPT_MENU]);
3073 dict_add_string(di, "kind", match->cp_text[CPT_KIND]);
3074 dict_add_string(di, "info", match->cp_text[CPT_INFO]);
Bram Moolenaar08928322020-01-04 14:32:48 +01003075 if (match->cp_user_data.v_type == VAR_UNKNOWN)
3076 // Add an empty string for backwards compatibility
3077 dict_add_string(di, "user_data", (char_u *)"");
3078 else
3079 dict_add_tv(di, "user_data", &match->cp_user_data);
Bram Moolenaar9cb698d2019-08-21 15:30:45 +02003080 }
3081 match = match->cp_next;
3082 }
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003083 while (match != NULL && !is_first_match(match));
Bram Moolenaar9cb698d2019-08-21 15:30:45 +02003084 }
3085 }
3086
3087 if (ret == OK && (what_flag & CI_WHAT_SELECTED))
Bram Moolenaarf9d51352020-10-26 19:22:42 +01003088 {
3089 if (compl_curr_match != NULL && compl_curr_match->cp_number == -1)
3090 ins_compl_update_sequence_numbers();
3091 ret = dict_add_number(retdict, "selected", compl_curr_match != NULL
3092 ? compl_curr_match->cp_number - 1 : -1);
3093 }
Bram Moolenaar9cb698d2019-08-21 15:30:45 +02003094
3095 // TODO
3096 // if (ret == OK && (what_flag & CI_WHAT_INSERTED))
3097}
3098
3099/*
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02003100 * "complete_info()" function
3101 */
3102 void
3103f_complete_info(typval_T *argvars, typval_T *rettv)
3104{
3105 list_T *what_list = NULL;
3106
3107 if (rettv_dict_alloc(rettv) != OK)
3108 return;
3109
Yegappan Lakshmanan4490ec42021-07-27 22:00:44 +02003110 if (in_vim9script() && check_for_opt_list_arg(argvars, 0) == FAIL)
3111 return;
3112
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02003113 if (argvars[0].v_type != VAR_UNKNOWN)
3114 {
3115 if (argvars[0].v_type != VAR_LIST)
3116 {
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00003117 emsg(_(e_list_required));
Bram Moolenaar9bca58f2019-08-15 21:31:52 +02003118 return;
3119 }
3120 what_list = argvars[0].vval.v_list;
3121 }
3122 get_complete_info(what_list, rettv->vval.v_dict);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003123}
3124#endif
3125
3126/*
Yegappan Lakshmanan160e9942021-10-16 15:41:29 +01003127 * Returns TRUE when using a user-defined function for thesaurus completion.
3128 */
3129 static int
3130thesaurus_func_complete(int type UNUSED)
3131{
3132#ifdef FEAT_COMPL_FUNC
Bram Moolenaarf4d8b762021-10-17 14:13:09 +01003133 return type == CTRL_X_THESAURUS
3134 && (*curbuf->b_p_tsrfu != NUL || *p_tsrfu != NUL);
Yegappan Lakshmanan160e9942021-10-16 15:41:29 +01003135#else
3136 return FALSE;
3137#endif
3138}
3139
3140/*
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003141 * Return value of process_next_cpt_value()
3142 */
3143enum
3144{
3145 INS_COMPL_CPT_OK = 1,
3146 INS_COMPL_CPT_CONT,
3147 INS_COMPL_CPT_END
3148};
3149
3150/*
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003151 * state information used for getting the next set of insert completion
3152 * matches.
3153 */
3154typedef struct
3155{
3156 char_u *e_cpt; // current entry in 'complete'
3157 buf_T *ins_buf; // buffer being scanned
3158 pos_T *cur_match_pos; // current match position
3159 pos_T prev_match_pos; // previous match position
3160 int set_match_pos; // save first_match_pos/last_match_pos
3161 pos_T first_match_pos; // first match position
3162 pos_T last_match_pos; // last match position
3163 int found_all; // found all matches of a certain type.
3164 char_u *dict; // dictionary file to search
3165 int dict_f; // "dict" is an exact file name or not
3166} ins_compl_next_state_T;
3167
3168/*
3169 * Process the next 'complete' option value in st->e_cpt.
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003170 *
3171 * If successful, the arguments are set as below:
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003172 * st->cpt - pointer to the next option value in "st->cpt"
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003173 * compl_type_arg - type of insert mode completion to use
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003174 * st->found_all - all matches of this type are found
3175 * st->ins_buf - search for completions in this buffer
3176 * st->first_match_pos - position of the first completion match
3177 * st->last_match_pos - position of the last completion match
3178 * st->set_match_pos - TRUE if the first match position should be saved to
3179 * avoid loops after the search wraps around.
3180 * st->dict - name of the dictionary or thesaurus file to search
3181 * st->dict_f - flag specifying whether "dict" is an exact file name or not
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003182 *
3183 * Returns INS_COMPL_CPT_OK if the next value is processed successfully.
Yegappan Lakshmanan37079142022-01-08 10:38:48 +00003184 * Returns INS_COMPL_CPT_CONT to skip the current completion source matching
3185 * the "st->e_cpt" option value and process the next matching source.
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003186 * Returns INS_COMPL_CPT_END if all the values in "st->e_cpt" are processed.
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003187 */
3188 static int
3189process_next_cpt_value(
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003190 ins_compl_next_state_T *st,
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003191 int *compl_type_arg,
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003192 pos_T *start_match_pos)
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003193{
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003194 int compl_type = -1;
3195 int status = INS_COMPL_CPT_OK;
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003196
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003197 st->found_all = FALSE;
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003198
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003199 while (*st->e_cpt == ',' || *st->e_cpt == ' ')
3200 st->e_cpt++;
3201
3202 if (*st->e_cpt == '.' && !curbuf->b_scanned)
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003203 {
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003204 st->ins_buf = curbuf;
3205 st->first_match_pos = *start_match_pos;
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003206 // Move the cursor back one character so that ^N can match the
3207 // word immediately after the cursor.
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003208 if (ctrl_x_mode_normal() && dec(&st->first_match_pos) < 0)
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003209 {
3210 // Move the cursor to after the last character in the
3211 // buffer, so that word at start of buffer is found
3212 // correctly.
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003213 st->first_match_pos.lnum = st->ins_buf->b_ml.ml_line_count;
3214 st->first_match_pos.col =
3215 (colnr_T)STRLEN(ml_get(st->first_match_pos.lnum));
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003216 }
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003217 st->last_match_pos = st->first_match_pos;
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003218 compl_type = 0;
3219
3220 // Remember the first match so that the loop stops when we
3221 // wrap and come back there a second time.
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003222 st->set_match_pos = TRUE;
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003223 }
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003224 else if (vim_strchr((char_u *)"buwU", *st->e_cpt) != NULL
3225 && (st->ins_buf = ins_compl_next_buf(st->ins_buf, *st->e_cpt)) != curbuf)
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003226 {
3227 // Scan a buffer, but not the current one.
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003228 if (st->ins_buf->b_ml.ml_mfp != NULL) // loaded buffer
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003229 {
3230 compl_started = TRUE;
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003231 st->first_match_pos.col = st->last_match_pos.col = 0;
3232 st->first_match_pos.lnum = st->ins_buf->b_ml.ml_line_count + 1;
3233 st->last_match_pos.lnum = 0;
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003234 compl_type = 0;
3235 }
3236 else // unloaded buffer, scan like dictionary
3237 {
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003238 st->found_all = TRUE;
3239 if (st->ins_buf->b_fname == NULL)
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003240 {
3241 status = INS_COMPL_CPT_CONT;
3242 goto done;
3243 }
3244 compl_type = CTRL_X_DICTIONARY;
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003245 st->dict = st->ins_buf->b_fname;
3246 st->dict_f = DICT_EXACT;
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003247 }
3248 msg_hist_off = TRUE; // reset in msg_trunc_attr()
3249 vim_snprintf((char *)IObuff, IOSIZE, _("Scanning: %s"),
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003250 st->ins_buf->b_fname == NULL
3251 ? buf_spname(st->ins_buf)
3252 : st->ins_buf->b_sfname == NULL
3253 ? st->ins_buf->b_fname
3254 : st->ins_buf->b_sfname);
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003255 (void)msg_trunc_attr((char *)IObuff, TRUE, HL_ATTR(HLF_R));
3256 }
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003257 else if (*st->e_cpt == NUL)
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003258 status = INS_COMPL_CPT_END;
3259 else
3260 {
3261 if (ctrl_x_mode_line_or_eval())
3262 compl_type = -1;
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003263 else if (*st->e_cpt == 'k' || *st->e_cpt == 's')
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003264 {
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003265 if (*st->e_cpt == 'k')
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003266 compl_type = CTRL_X_DICTIONARY;
3267 else
3268 compl_type = CTRL_X_THESAURUS;
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003269 if (*++st->e_cpt != ',' && *st->e_cpt != NUL)
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003270 {
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003271 st->dict = st->e_cpt;
3272 st->dict_f = DICT_FIRST;
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003273 }
3274 }
3275#ifdef FEAT_FIND_ID
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003276 else if (*st->e_cpt == 'i')
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003277 compl_type = CTRL_X_PATH_PATTERNS;
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003278 else if (*st->e_cpt == 'd')
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003279 compl_type = CTRL_X_PATH_DEFINES;
3280#endif
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003281 else if (*st->e_cpt == ']' || *st->e_cpt == 't')
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003282 {
3283 msg_hist_off = TRUE; // reset in msg_trunc_attr()
3284 compl_type = CTRL_X_TAGS;
3285 vim_snprintf((char *)IObuff, IOSIZE, _("Scanning tags."));
3286 (void)msg_trunc_attr((char *)IObuff, TRUE, HL_ATTR(HLF_R));
3287 }
3288 else
3289 compl_type = -1;
3290
3291 // in any case e_cpt is advanced to the next entry
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003292 (void)copy_option_part(&st->e_cpt, IObuff, IOSIZE, ",");
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003293
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003294 st->found_all = TRUE;
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003295 if (compl_type == -1)
3296 status = INS_COMPL_CPT_CONT;
3297 }
3298
3299done:
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003300 *compl_type_arg = compl_type;
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003301 return status;
3302}
3303
3304#ifdef FEAT_FIND_ID
3305/*
3306 * Get the next set of identifiers or defines matching "compl_pattern" in
3307 * included files.
3308 */
3309 static void
3310get_next_include_file_completion(int compl_type)
3311{
3312 find_pattern_in_path(compl_pattern, compl_direction,
3313 (int)STRLEN(compl_pattern), FALSE, FALSE,
3314 (compl_type == CTRL_X_PATH_DEFINES
3315 && !(compl_cont_status & CONT_SOL))
3316 ? FIND_DEFINE : FIND_ANY, 1L, ACTION_EXPAND,
3317 (linenr_T)1, (linenr_T)MAXLNUM);
3318}
3319#endif
3320
3321/*
3322 * Get the next set of words matching "compl_pattern" in dictionary or
3323 * thesaurus files.
3324 */
3325 static void
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003326get_next_dict_tsr_completion(int compl_type, char_u *dict, int dict_f)
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003327{
3328#ifdef FEAT_COMPL_FUNC
3329 if (thesaurus_func_complete(compl_type))
3330 expand_by_function(compl_type, compl_pattern);
3331 else
3332#endif
3333 ins_compl_dictionaries(
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003334 dict != NULL ? dict
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003335 : (compl_type == CTRL_X_THESAURUS
3336 ? (*curbuf->b_p_tsr == NUL ? p_tsr : curbuf->b_p_tsr)
3337 : (*curbuf->b_p_dict == NUL ? p_dict : curbuf->b_p_dict)),
3338 compl_pattern,
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003339 dict != NULL ? dict_f : 0,
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003340 compl_type == CTRL_X_THESAURUS);
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003341}
3342
3343/*
3344 * Get the next set of tag names matching "compl_pattern".
3345 */
3346 static void
3347get_next_tag_completion(void)
3348{
3349 int save_p_ic;
3350 char_u **matches;
3351 int num_matches;
3352
3353 // set p_ic according to p_ic, p_scs and pat for find_tags().
3354 save_p_ic = p_ic;
3355 p_ic = ignorecase(compl_pattern);
3356
3357 // Find up to TAG_MANY matches. Avoids that an enormous number
3358 // of matches is found when compl_pattern is empty
3359 g_tag_at_cursor = TRUE;
3360 if (find_tags(compl_pattern, &num_matches, &matches,
3361 TAG_REGEXP | TAG_NAMES | TAG_NOIC | TAG_INS_COMP
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003362 | (ctrl_x_mode_not_default() ? TAG_VERBOSE : 0),
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003363 TAG_MANY, curbuf->b_ffname) == OK && num_matches > 0)
3364 ins_compl_add_matches(num_matches, matches, p_ic);
3365 g_tag_at_cursor = FALSE;
3366 p_ic = save_p_ic;
3367}
3368
3369/*
3370 * Get the next set of filename matching "compl_pattern".
3371 */
3372 static void
3373get_next_filename_completion(void)
3374{
3375 char_u **matches;
3376 int num_matches;
3377
3378 if (expand_wildcards(1, &compl_pattern, &num_matches, &matches,
3379 EW_FILE|EW_DIR|EW_ADDSLASH|EW_SILENT) != OK)
3380 return;
3381
3382 // May change home directory back to "~".
3383 tilde_replace(compl_pattern, num_matches, matches);
3384#ifdef BACKSLASH_IN_FILENAME
3385 if (curbuf->b_p_csl[0] != NUL)
3386 {
3387 int i;
3388
3389 for (i = 0; i < num_matches; ++i)
3390 {
3391 char_u *ptr = matches[i];
3392
3393 while (*ptr != NUL)
3394 {
3395 if (curbuf->b_p_csl[0] == 's' && *ptr == '\\')
3396 *ptr = '/';
3397 else if (curbuf->b_p_csl[0] == 'b' && *ptr == '/')
3398 *ptr = '\\';
3399 ptr += (*mb_ptr2len)(ptr);
3400 }
3401 }
3402 }
3403#endif
3404 ins_compl_add_matches(num_matches, matches, p_fic || p_wic);
3405}
3406
3407/*
3408 * Get the next set of command-line completions matching "compl_pattern".
3409 */
3410 static void
3411get_next_cmdline_completion()
3412{
3413 char_u **matches;
3414 int num_matches;
3415
3416 if (expand_cmdline(&compl_xp, compl_pattern,
3417 (int)STRLEN(compl_pattern),
3418 &num_matches, &matches) == EXPAND_OK)
3419 ins_compl_add_matches(num_matches, matches, FALSE);
3420}
3421
3422/*
3423 * Get the next set of spell suggestions matching "compl_pattern".
3424 */
3425 static void
3426get_next_spell_completion(linenr_T lnum UNUSED)
3427{
3428#ifdef FEAT_SPELL
3429 char_u **matches;
3430 int num_matches;
3431
3432 num_matches = expand_spelling(lnum, compl_pattern, &matches);
3433 if (num_matches > 0)
3434 ins_compl_add_matches(num_matches, matches, p_ic);
Bram Moolenaar8e7cc6b2021-12-30 10:32:25 +00003435 else
3436 vim_free(matches);
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003437#endif
3438}
3439
3440/*
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003441 * Return the next word or line from buffer "ins_buf" at position
3442 * "cur_match_pos" for completion. The length of the match is set in "len".
3443 */
3444 static char_u *
3445ins_comp_get_next_word_or_line(
3446 buf_T *ins_buf, // buffer being scanned
3447 pos_T *cur_match_pos, // current match position
3448 int *match_len,
3449 int *cont_s_ipos) // next ^X<> will set initial_pos
3450{
3451 char_u *ptr;
3452 int len;
3453
3454 *match_len = 0;
3455 ptr = ml_get_buf(ins_buf, cur_match_pos->lnum, FALSE) +
3456 cur_match_pos->col;
3457 if (ctrl_x_mode_line_or_eval())
3458 {
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003459 if (compl_status_adding())
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003460 {
3461 if (cur_match_pos->lnum >= ins_buf->b_ml.ml_line_count)
3462 return NULL;
3463 ptr = ml_get_buf(ins_buf, cur_match_pos->lnum + 1, FALSE);
3464 if (!p_paste)
3465 ptr = skipwhite(ptr);
3466 }
3467 len = (int)STRLEN(ptr);
3468 }
3469 else
3470 {
3471 char_u *tmp_ptr = ptr;
3472
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003473 if (compl_status_adding())
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003474 {
3475 tmp_ptr += compl_length;
3476 // Skip if already inside a word.
3477 if (vim_iswordp(tmp_ptr))
3478 return NULL;
3479 // Find start of next word.
3480 tmp_ptr = find_word_start(tmp_ptr);
3481 }
3482 // Find end of this word.
3483 tmp_ptr = find_word_end(tmp_ptr);
3484 len = (int)(tmp_ptr - ptr);
3485
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003486 if (compl_status_adding() && len == compl_length)
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003487 {
3488 if (cur_match_pos->lnum < ins_buf->b_ml.ml_line_count)
3489 {
3490 // Try next line, if any. the new word will be
3491 // "join" as if the normal command "J" was used.
3492 // IOSIZE is always greater than
3493 // compl_length, so the next STRNCPY always
3494 // works -- Acevedo
3495 STRNCPY(IObuff, ptr, len);
3496 ptr = ml_get_buf(ins_buf, cur_match_pos->lnum + 1, FALSE);
3497 tmp_ptr = ptr = skipwhite(ptr);
3498 // Find start of next word.
3499 tmp_ptr = find_word_start(tmp_ptr);
3500 // Find end of next word.
3501 tmp_ptr = find_word_end(tmp_ptr);
3502 if (tmp_ptr > ptr)
3503 {
3504 if (*ptr != ')' && IObuff[len - 1] != TAB)
3505 {
3506 if (IObuff[len - 1] != ' ')
3507 IObuff[len++] = ' ';
3508 // IObuf =~ "\k.* ", thus len >= 2
3509 if (p_js
3510 && (IObuff[len - 2] == '.'
3511 || (vim_strchr(p_cpo, CPO_JOINSP)
3512 == NULL
3513 && (IObuff[len - 2] == '?'
3514 || IObuff[len - 2] == '!'))))
3515 IObuff[len++] = ' ';
3516 }
3517 // copy as much as possible of the new word
3518 if (tmp_ptr - ptr >= IOSIZE - len)
3519 tmp_ptr = ptr + IOSIZE - len - 1;
3520 STRNCPY(IObuff + len, ptr, tmp_ptr - ptr);
3521 len += (int)(tmp_ptr - ptr);
3522 *cont_s_ipos = TRUE;
3523 }
3524 IObuff[len] = NUL;
3525 ptr = IObuff;
3526 }
3527 if (len == compl_length)
3528 return NULL;
3529 }
3530 }
3531
3532 *match_len = len;
3533 return ptr;
3534}
3535
3536/*
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003537 * Get the next set of words matching "compl_pattern" for default completion(s)
3538 * (normal ^P/^N and ^X^L).
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003539 * Search for "compl_pattern" in the buffer "st->ins_buf" starting from the
3540 * position "st->start_pos" in the "compl_direction" direction. If
3541 * "st->set_match_pos" is TRUE, then set the "st->first_match_pos" and
3542 * "st->last_match_pos".
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003543 * Returns OK if a new next match is found, otherwise returns FAIL.
3544 */
3545 static int
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003546get_next_default_completion(ins_compl_next_state_T *st, pos_T *start_pos)
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003547{
3548 int found_new_match = FAIL;
3549 int save_p_scs;
3550 int save_p_ws;
3551 int looped_around = FALSE;
3552 char_u *ptr;
3553 int len;
3554
3555 // If 'infercase' is set, don't use 'smartcase' here
3556 save_p_scs = p_scs;
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003557 if (st->ins_buf->b_p_inf)
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003558 p_scs = FALSE;
3559
3560 // Buffers other than curbuf are scanned from the beginning or the
3561 // end but never from the middle, thus setting nowrapscan in this
3562 // buffer is a good idea, on the other hand, we always set
3563 // wrapscan for curbuf to avoid missing matches -- Acevedo,Webb
3564 save_p_ws = p_ws;
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003565 if (st->ins_buf != curbuf)
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003566 p_ws = FALSE;
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003567 else if (*st->e_cpt == '.')
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003568 p_ws = TRUE;
3569 looped_around = FALSE;
3570 for (;;)
3571 {
3572 int cont_s_ipos = FALSE;
3573
3574 ++msg_silent; // Don't want messages for wrapscan.
3575
3576 // ctrl_x_mode_line_or_eval() || word-wise search that
3577 // has added a word that was at the beginning of the line
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003578 if (ctrl_x_mode_line_or_eval() || (compl_cont_status & CONT_SOL))
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003579 found_new_match = search_for_exact_line(st->ins_buf,
3580 st->cur_match_pos, compl_direction, compl_pattern);
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003581 else
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003582 found_new_match = searchit(NULL, st->ins_buf, st->cur_match_pos,
3583 NULL, compl_direction, compl_pattern, 1L,
3584 SEARCH_KEEP + SEARCH_NFMSG, RE_LAST, NULL);
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003585 --msg_silent;
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003586 if (!compl_started || st->set_match_pos)
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003587 {
3588 // set "compl_started" even on fail
3589 compl_started = TRUE;
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003590 st->first_match_pos = *st->cur_match_pos;
3591 st->last_match_pos = *st->cur_match_pos;
3592 st->set_match_pos = FALSE;
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003593 }
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003594 else if (st->first_match_pos.lnum == st->last_match_pos.lnum
3595 && st->first_match_pos.col == st->last_match_pos.col)
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003596 {
3597 found_new_match = FAIL;
3598 }
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003599 else if (compl_dir_forward()
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003600 && (st->prev_match_pos.lnum > st->cur_match_pos->lnum
3601 || (st->prev_match_pos.lnum == st->cur_match_pos->lnum
3602 && st->prev_match_pos.col >= st->cur_match_pos->col)))
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003603 {
3604 if (looped_around)
3605 found_new_match = FAIL;
3606 else
3607 looped_around = TRUE;
3608 }
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003609 else if (!compl_dir_forward()
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003610 && (st->prev_match_pos.lnum < st->cur_match_pos->lnum
3611 || (st->prev_match_pos.lnum == st->cur_match_pos->lnum
3612 && st->prev_match_pos.col <= st->cur_match_pos->col)))
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003613 {
3614 if (looped_around)
3615 found_new_match = FAIL;
3616 else
3617 looped_around = TRUE;
3618 }
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003619 st->prev_match_pos = *st->cur_match_pos;
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003620 if (found_new_match == FAIL)
3621 break;
3622
3623 // when ADDING, the text before the cursor matches, skip it
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003624 if (compl_status_adding() && st->ins_buf == curbuf
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003625 && start_pos->lnum == st->cur_match_pos->lnum
3626 && start_pos->col == st->cur_match_pos->col)
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003627 continue;
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003628
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003629 ptr = ins_comp_get_next_word_or_line(st->ins_buf, st->cur_match_pos,
3630 &len, &cont_s_ipos);
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003631 if (ptr == NULL)
3632 continue;
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003633
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003634 if (ins_compl_add_infercase(ptr, len, p_ic,
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003635 st->ins_buf == curbuf ? NULL : st->ins_buf->b_sfname,
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003636 0, cont_s_ipos) != NOTDONE)
3637 {
3638 found_new_match = OK;
3639 break;
3640 }
3641 }
3642 p_scs = save_p_scs;
3643 p_ws = save_p_ws;
3644
3645 return found_new_match;
3646}
3647
3648/*
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003649 * get the next set of completion matches for "type".
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003650 * Returns TRUE if a new match is found. Otherwise returns FALSE.
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003651 */
3652 static int
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003653get_next_completion_match(int type, ins_compl_next_state_T *st, pos_T *ini)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003654{
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003655 int found_new_match = FALSE;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003656
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003657 switch (type)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003658 {
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003659 case -1:
3660 break;
3661#ifdef FEAT_FIND_ID
3662 case CTRL_X_PATH_PATTERNS:
3663 case CTRL_X_PATH_DEFINES:
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003664 get_next_include_file_completion(type);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003665 break;
3666#endif
3667
3668 case CTRL_X_DICTIONARY:
3669 case CTRL_X_THESAURUS:
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003670 get_next_dict_tsr_completion(type, st->dict, st->dict_f);
3671 st->dict = NULL;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003672 break;
3673
3674 case CTRL_X_TAGS:
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003675 get_next_tag_completion();
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003676 break;
3677
3678 case CTRL_X_FILES:
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003679 get_next_filename_completion();
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003680 break;
3681
3682 case CTRL_X_CMDLINE:
zeertzjqdca29d92021-08-31 19:12:51 +02003683 case CTRL_X_CMDLINE_CTRL_X:
Yegappan Lakshmananedc6f102021-12-29 17:38:46 +00003684 get_next_cmdline_completion();
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003685 break;
3686
3687#ifdef FEAT_COMPL_FUNC
3688 case CTRL_X_FUNCTION:
3689 case CTRL_X_OMNI:
3690 expand_by_function(type, compl_pattern);
3691 break;
3692#endif
3693
3694 case CTRL_X_SPELL:
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003695 get_next_spell_completion(st->first_match_pos.lnum);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003696 break;
3697
3698 default: // normal ^P/^N and ^X^L
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003699 found_new_match = get_next_default_completion(st, ini);
3700 if (found_new_match == FAIL && st->ins_buf == curbuf)
3701 st->found_all = TRUE;
3702 }
3703
3704 // check if compl_curr_match has changed, (e.g. other type of
3705 // expansion added something)
3706 if (type != 0 && compl_curr_match != compl_old_match)
3707 found_new_match = OK;
3708
3709 return found_new_match;
3710}
3711
3712/*
3713 * Get the next expansion(s), using "compl_pattern".
3714 * The search starts at position "ini" in curbuf and in the direction
3715 * compl_direction.
3716 * When "compl_started" is FALSE start at that position, otherwise continue
3717 * where we stopped searching before.
3718 * This may return before finding all the matches.
3719 * Return the total number of matches or -1 if still unknown -- Acevedo
3720 */
3721 static int
3722ins_compl_get_exp(pos_T *ini)
3723{
3724 static ins_compl_next_state_T st;
3725 int i;
3726 int found_new_match;
3727 int type = ctrl_x_mode;
3728
3729 if (!compl_started)
3730 {
3731 FOR_ALL_BUFFERS(st.ins_buf)
3732 st.ins_buf->b_scanned = 0;
3733 st.found_all = FALSE;
3734 st.ins_buf = curbuf;
3735 st.e_cpt = (compl_cont_status & CONT_LOCAL)
3736 ? (char_u *)"." : curbuf->b_p_cpt;
3737 st.last_match_pos = st.first_match_pos = *ini;
3738 }
3739 else if (st.ins_buf != curbuf && !buf_valid(st.ins_buf))
3740 st.ins_buf = curbuf; // In case the buffer was wiped out.
3741
3742 compl_old_match = compl_curr_match; // remember the last current match
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003743 st.cur_match_pos = (compl_dir_forward())
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003744 ? &st.last_match_pos : &st.first_match_pos;
3745
3746 // For ^N/^P loop over all the flags/windows/buffers in 'complete'.
3747 for (;;)
3748 {
3749 found_new_match = FAIL;
3750 st.set_match_pos = FALSE;
3751
3752 // For ^N/^P pick a new entry from e_cpt if compl_started is off,
3753 // or if found_all says this entry is done. For ^X^L only use the
3754 // entries from 'complete' that look in loaded buffers.
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003755 if ((ctrl_x_mode_normal() || ctrl_x_mode_line_or_eval())
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003756 && (!compl_started || st.found_all))
3757 {
3758 int status = process_next_cpt_value(&st, &type, ini);
3759
3760 if (status == INS_COMPL_CPT_END)
3761 break;
3762 if (status == INS_COMPL_CPT_CONT)
3763 continue;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003764 }
3765
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003766 // If complete() was called then compl_pattern has been reset. The
3767 // following won't work then, bail out.
3768 if (compl_pattern == NULL)
3769 break;
3770
3771 // get the next set of completion matches
3772 found_new_match = get_next_completion_match(type, &st, ini);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003773
3774 // break the loop for specialized modes (use 'complete' just for the
3775 // generic ctrl_x_mode == CTRL_X_NORMAL) or when we've found a new
3776 // match
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003777 if ((ctrl_x_mode_not_default() && !ctrl_x_mode_line_or_eval())
3778 || found_new_match != FAIL)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003779 {
3780 if (got_int)
3781 break;
3782 // Fill the popup menu as soon as possible.
3783 if (type != -1)
3784 ins_compl_check_keys(0, FALSE);
3785
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003786 if ((ctrl_x_mode_not_default()
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003787 && !ctrl_x_mode_line_or_eval()) || compl_interrupted)
3788 break;
3789 compl_started = TRUE;
3790 }
3791 else
3792 {
3793 // Mark a buffer scanned when it has been scanned completely
3794 if (type == 0 || type == CTRL_X_PATH_PATTERNS)
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003795 st.ins_buf->b_scanned = TRUE;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003796
3797 compl_started = FALSE;
3798 }
3799 }
3800 compl_started = TRUE;
3801
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003802 if ((ctrl_x_mode_normal() || ctrl_x_mode_line_or_eval())
Yegappan Lakshmanan6ad84ab2021-12-31 12:59:53 +00003803 && *st.e_cpt == NUL) // Got to end of 'complete'
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003804 found_new_match = FAIL;
3805
3806 i = -1; // total of matches, unknown
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003807 if (found_new_match == FAIL || (ctrl_x_mode_not_default()
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003808 && !ctrl_x_mode_line_or_eval()))
3809 i = ins_compl_make_cyclic();
3810
3811 if (compl_old_match != NULL)
3812 {
3813 // If several matches were added (FORWARD) or the search failed and has
3814 // just been made cyclic then we have to move compl_curr_match to the
3815 // next or previous entry (if any) -- Acevedo
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003816 compl_curr_match = compl_dir_forward() ? compl_old_match->cp_next
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003817 : compl_old_match->cp_prev;
3818 if (compl_curr_match == NULL)
3819 compl_curr_match = compl_old_match;
3820 }
=?UTF-8?q?Magnus=20Gro=C3=9F?=25def2c2021-10-22 18:56:39 +01003821 trigger_modechanged();
3822
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003823 return i;
3824}
3825
3826/*
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003827 * Update "compl_shown_match" to the actually shown match, it may differ when
3828 * "compl_leader" is used to omit some of the matches.
3829 */
3830 static void
3831ins_compl_update_shown_match(void)
3832{
3833 while (!ins_compl_equal(compl_shown_match,
3834 compl_leader, (int)STRLEN(compl_leader))
3835 && compl_shown_match->cp_next != NULL
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003836 && !is_first_match(compl_shown_match->cp_next))
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003837 compl_shown_match = compl_shown_match->cp_next;
3838
3839 // If we didn't find it searching forward, and compl_shows_dir is
3840 // backward, find the last match.
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003841 if (compl_shows_dir_backward()
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003842 && !ins_compl_equal(compl_shown_match,
3843 compl_leader, (int)STRLEN(compl_leader))
3844 && (compl_shown_match->cp_next == NULL
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003845 || is_first_match(compl_shown_match->cp_next)))
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003846 {
3847 while (!ins_compl_equal(compl_shown_match,
3848 compl_leader, (int)STRLEN(compl_leader))
3849 && compl_shown_match->cp_prev != NULL
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003850 && !is_first_match(compl_shown_match->cp_prev))
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003851 compl_shown_match = compl_shown_match->cp_prev;
3852 }
3853}
3854
3855/*
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003856 * Delete the old text being completed.
3857 */
3858 void
3859ins_compl_delete(void)
3860{
3861 int col;
3862
3863 // In insert mode: Delete the typed part.
3864 // In replace mode: Put the old characters back, if any.
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003865 col = compl_col + (compl_status_adding() ? compl_length : 0);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003866 if ((int)curwin->w_cursor.col > col)
3867 {
3868 if (stop_arrow() == FAIL)
3869 return;
3870 backspace_until_column(col);
3871 }
3872
3873 // TODO: is this sufficient for redrawing? Redrawing everything causes
3874 // flicker, thus we can't do that.
3875 changed_cline_bef_curs();
Bram Moolenaar9cb698d2019-08-21 15:30:45 +02003876#ifdef FEAT_EVAL
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003877 // clear v:completed_item
3878 set_vim_var_dict(VV_COMPLETED_ITEM, dict_alloc_lock(VAR_FIXED));
Bram Moolenaar9cb698d2019-08-21 15:30:45 +02003879#endif
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003880}
3881
3882/*
3883 * Insert the new text being completed.
3884 * "in_compl_func" is TRUE when called from complete_check().
3885 */
3886 void
3887ins_compl_insert(int in_compl_func)
3888{
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003889 int compl_len = get_compl_len();
Bram Moolenaar4b28ba32021-12-27 19:28:37 +00003890
3891 // Make sure we don't go over the end of the string, this can happen with
3892 // illegal bytes.
3893 if (compl_len < (int)STRLEN(compl_shown_match->cp_str))
3894 ins_bytes(compl_shown_match->cp_str + compl_len);
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003895 if (match_at_original_text(compl_shown_match))
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003896 compl_used_match = FALSE;
3897 else
3898 compl_used_match = TRUE;
Bram Moolenaar9cb698d2019-08-21 15:30:45 +02003899#ifdef FEAT_EVAL
3900 {
3901 dict_T *dict = ins_compl_dict_alloc(compl_shown_match);
3902
3903 set_vim_var_dict(VV_COMPLETED_ITEM, dict);
3904 }
3905#endif
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003906 if (!in_compl_func)
3907 compl_curr_match = compl_shown_match;
3908}
3909
3910/*
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003911 * show the file name for the completion match (if any). Truncate the file
3912 * name to avoid a wait for return.
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003913 */
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003914 static void
3915ins_compl_show_filename(void)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003916{
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003917 char *lead = _("match in file");
3918 int space = sc_col - vim_strsize((char_u *)lead) - 2;
3919 char_u *s;
3920 char_u *e;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003921
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003922 if (space <= 0)
3923 return;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003924
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003925 // We need the tail that fits. With double-byte encoding going
3926 // back from the end is very slow, thus go from the start and keep
3927 // the text that fits in "space" between "s" and "e".
3928 for (s = e = compl_shown_match->cp_fname; *e != NUL; MB_PTR_ADV(e))
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003929 {
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003930 space -= ptr2cells(e);
3931 while (space < 0)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003932 {
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003933 space += ptr2cells(s);
3934 MB_PTR_ADV(s);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003935 }
3936 }
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003937 msg_hist_off = TRUE;
3938 vim_snprintf((char *)IObuff, IOSIZE, "%s %s%s", lead,
3939 s > compl_shown_match->cp_fname ? "<" : "", s);
3940 msg((char *)IObuff);
3941 msg_hist_off = FALSE;
3942 redraw_cmdline = FALSE; // don't overwrite!
3943}
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003944
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003945/*
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003946 * Find the next set of matches for completion. Repeat the completion "todo"
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003947 * times. The number of matches found is returned in 'num_matches'.
3948 *
3949 * If "allow_get_expansion" is TRUE, then ins_compl_get_exp() may be called to
3950 * get more completions. If it is FALSE, then do nothing when there are no more
3951 * completions in the given direction.
3952 *
3953 * If "advance" is TRUE, then completion will move to the first match.
3954 * Otherwise, the original text will be shown.
3955 *
3956 * Returns OK on success and -1 if the number of matches are unknown.
3957 */
3958 static int
3959find_next_completion_match(
3960 int allow_get_expansion,
3961 int todo, // repeat completion this many times
3962 int advance,
3963 int *num_matches)
3964{
3965 int found_end = FALSE;
3966 compl_T *found_compl = NULL;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003967
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003968 while (--todo >= 0)
3969 {
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003970 if (compl_shows_dir_forward() && compl_shown_match->cp_next != NULL)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003971 {
3972 compl_shown_match = compl_shown_match->cp_next;
3973 found_end = (compl_first_match != NULL
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003974 && (is_first_match(compl_shown_match->cp_next)
3975 || is_first_match(compl_shown_match)));
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003976 }
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003977 else if (compl_shows_dir_backward()
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00003978 && compl_shown_match->cp_prev != NULL)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003979 {
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003980 found_end = is_first_match(compl_shown_match);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003981 compl_shown_match = compl_shown_match->cp_prev;
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003982 found_end |= is_first_match(compl_shown_match);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003983 }
3984 else
3985 {
3986 if (!allow_get_expansion)
3987 {
3988 if (advance)
3989 {
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00003990 if (compl_shows_dir_backward())
Bram Moolenaar7591bb32019-03-30 13:53:47 +01003991 compl_pending -= todo + 1;
3992 else
3993 compl_pending += todo + 1;
3994 }
3995 return -1;
3996 }
3997
3998 if (!compl_no_select && advance)
3999 {
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004000 if (compl_shows_dir_backward())
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004001 --compl_pending;
4002 else
4003 ++compl_pending;
4004 }
4005
4006 // Find matches.
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004007 *num_matches = ins_compl_get_exp(&compl_startpos);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004008
4009 // handle any pending completions
4010 while (compl_pending != 0 && compl_direction == compl_shows_dir
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004011 && advance)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004012 {
4013 if (compl_pending > 0 && compl_shown_match->cp_next != NULL)
4014 {
4015 compl_shown_match = compl_shown_match->cp_next;
4016 --compl_pending;
4017 }
4018 if (compl_pending < 0 && compl_shown_match->cp_prev != NULL)
4019 {
4020 compl_shown_match = compl_shown_match->cp_prev;
4021 ++compl_pending;
4022 }
4023 else
4024 break;
4025 }
4026 found_end = FALSE;
4027 }
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004028 if (!match_at_original_text(compl_shown_match)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004029 && compl_leader != NULL
4030 && !ins_compl_equal(compl_shown_match,
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004031 compl_leader, (int)STRLEN(compl_leader)))
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004032 ++todo;
4033 else
4034 // Remember a matching item.
4035 found_compl = compl_shown_match;
4036
4037 // Stop at the end of the list when we found a usable match.
4038 if (found_end)
4039 {
4040 if (found_compl != NULL)
4041 {
4042 compl_shown_match = found_compl;
4043 break;
4044 }
4045 todo = 1; // use first usable match after wrapping around
4046 }
4047 }
4048
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004049 return OK;
4050}
4051
4052/*
4053 * Fill in the next completion in the current direction.
4054 * If "allow_get_expansion" is TRUE, then we may call ins_compl_get_exp() to
4055 * get more completions. If it is FALSE, then we just do nothing when there
4056 * are no more completions in a given direction. The latter case is used when
4057 * we are still in the middle of finding completions, to allow browsing
4058 * through the ones found so far.
4059 * Return the total number of matches, or -1 if still unknown -- webb.
4060 *
4061 * compl_curr_match is currently being used by ins_compl_get_exp(), so we use
4062 * compl_shown_match here.
4063 *
4064 * Note that this function may be called recursively once only. First with
4065 * "allow_get_expansion" TRUE, which calls ins_compl_get_exp(), which in turn
4066 * calls this function with "allow_get_expansion" FALSE.
4067 */
4068 static int
4069ins_compl_next(
4070 int allow_get_expansion,
4071 int count, // repeat completion this many times; should
4072 // be at least 1
4073 int insert_match, // Insert the newly selected match
4074 int in_compl_func) // called from complete_check()
4075{
4076 int num_matches = -1;
4077 int todo = count;
4078 int advance;
4079 int started = compl_started;
4080
4081 // When user complete function return -1 for findstart which is next
4082 // time of 'always', compl_shown_match become NULL.
4083 if (compl_shown_match == NULL)
4084 return -1;
4085
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004086 if (compl_leader != NULL && !match_at_original_text(compl_shown_match))
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004087 // Update "compl_shown_match" to the actually shown match
4088 ins_compl_update_shown_match();
4089
4090 if (allow_get_expansion && insert_match
4091 && (!(compl_get_longest || compl_restarting) || compl_used_match))
4092 // Delete old text to be replaced
4093 ins_compl_delete();
4094
4095 // When finding the longest common text we stick at the original text,
4096 // don't let CTRL-N or CTRL-P move to the first match.
4097 advance = count != 1 || !allow_get_expansion || !compl_get_longest;
4098
4099 // When restarting the search don't insert the first match either.
4100 if (compl_restarting)
4101 {
4102 advance = FALSE;
4103 compl_restarting = FALSE;
4104 }
4105
4106 // Repeat this for when <PageUp> or <PageDown> is typed. But don't wrap
4107 // around.
4108 if (find_next_completion_match(allow_get_expansion, todo, advance,
4109 &num_matches) == -1)
4110 return -1;
4111
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004112 // Insert the text of the new completion, or the compl_leader.
4113 if (compl_no_insert && !started)
4114 {
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004115 ins_bytes(compl_orig_text + get_compl_len());
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004116 compl_used_match = FALSE;
4117 }
4118 else if (insert_match)
4119 {
4120 if (!compl_get_longest || compl_used_match)
4121 ins_compl_insert(in_compl_func);
4122 else
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004123 ins_bytes(compl_leader + get_compl_len());
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004124 }
4125 else
4126 compl_used_match = FALSE;
4127
4128 if (!allow_get_expansion)
4129 {
4130 // may undisplay the popup menu first
4131 ins_compl_upd_pum();
4132
4133 if (pum_enough_matches())
4134 // Will display the popup menu, don't redraw yet to avoid flicker.
4135 pum_call_update_screen();
4136 else
4137 // Not showing the popup menu yet, redraw to show the user what was
4138 // inserted.
4139 update_screen(0);
4140
4141 // display the updated popup menu
4142 ins_compl_show_pum();
4143#ifdef FEAT_GUI
4144 if (gui.in_use)
4145 {
4146 // Show the cursor after the match, not after the redrawn text.
4147 setcursor();
4148 out_flush_cursor(FALSE, FALSE);
4149 }
4150#endif
4151
4152 // Delete old text to be replaced, since we're still searching and
4153 // don't want to match ourselves!
4154 ins_compl_delete();
4155 }
4156
4157 // Enter will select a match when the match wasn't inserted and the popup
4158 // menu is visible.
4159 if (compl_no_insert && !started)
4160 compl_enter_selects = TRUE;
4161 else
4162 compl_enter_selects = !insert_match && compl_match_array != NULL;
4163
4164 // Show the file name for the match (if any)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004165 if (compl_shown_match->cp_fname != NULL)
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004166 ins_compl_show_filename();
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004167
4168 return num_matches;
4169}
4170
4171/*
4172 * Call this while finding completions, to check whether the user has hit a key
4173 * that should change the currently displayed completion, or exit completion
4174 * mode. Also, when compl_pending is not zero, show a completion as soon as
4175 * possible. -- webb
4176 * "frequency" specifies out of how many calls we actually check.
4177 * "in_compl_func" is TRUE when called from complete_check(), don't set
4178 * compl_curr_match.
4179 */
4180 void
4181ins_compl_check_keys(int frequency, int in_compl_func)
4182{
4183 static int count = 0;
4184 int c;
4185
4186 // Don't check when reading keys from a script, :normal or feedkeys().
4187 // That would break the test scripts. But do check for keys when called
4188 // from complete_check().
4189 if (!in_compl_func && (using_script() || ex_normal_busy))
4190 return;
4191
4192 // Only do this at regular intervals
4193 if (++count < frequency)
4194 return;
4195 count = 0;
4196
4197 // Check for a typed key. Do use mappings, otherwise vim_is_ctrl_x_key()
4198 // can't do its work correctly.
4199 c = vpeekc_any();
4200 if (c != NUL)
4201 {
4202 if (vim_is_ctrl_x_key(c) && c != Ctrl_X && c != Ctrl_R)
4203 {
4204 c = safe_vgetc(); // Eat the character
4205 compl_shows_dir = ins_compl_key2dir(c);
4206 (void)ins_compl_next(FALSE, ins_compl_key2count(c),
4207 c != K_UP && c != K_DOWN, in_compl_func);
4208 }
4209 else
4210 {
4211 // Need to get the character to have KeyTyped set. We'll put it
4212 // back with vungetc() below. But skip K_IGNORE.
4213 c = safe_vgetc();
4214 if (c != K_IGNORE)
4215 {
4216 // Don't interrupt completion when the character wasn't typed,
4217 // e.g., when doing @q to replay keys.
4218 if (c != Ctrl_R && KeyTyped)
4219 compl_interrupted = TRUE;
4220
4221 vungetc(c);
4222 }
4223 }
4224 }
4225 if (compl_pending != 0 && !got_int && !compl_no_insert)
4226 {
4227 int todo = compl_pending > 0 ? compl_pending : -compl_pending;
4228
4229 compl_pending = 0;
4230 (void)ins_compl_next(FALSE, todo, TRUE, in_compl_func);
4231 }
4232}
4233
4234/*
4235 * Decide the direction of Insert mode complete from the key typed.
4236 * Returns BACKWARD or FORWARD.
4237 */
4238 static int
4239ins_compl_key2dir(int c)
4240{
4241 if (c == Ctrl_P || c == Ctrl_L
4242 || c == K_PAGEUP || c == K_KPAGEUP || c == K_S_UP || c == K_UP)
4243 return BACKWARD;
4244 return FORWARD;
4245}
4246
4247/*
4248 * Return TRUE for keys that are used for completion only when the popup menu
4249 * is visible.
4250 */
4251 static int
4252ins_compl_pum_key(int c)
4253{
4254 return pum_visible() && (c == K_PAGEUP || c == K_KPAGEUP || c == K_S_UP
4255 || c == K_PAGEDOWN || c == K_KPAGEDOWN || c == K_S_DOWN
4256 || c == K_UP || c == K_DOWN);
4257}
4258
4259/*
4260 * Decide the number of completions to move forward.
4261 * Returns 1 for most keys, height of the popup menu for page-up/down keys.
4262 */
4263 static int
4264ins_compl_key2count(int c)
4265{
4266 int h;
4267
4268 if (ins_compl_pum_key(c) && c != K_UP && c != K_DOWN)
4269 {
4270 h = pum_get_height();
4271 if (h > 3)
4272 h -= 2; // keep some context
4273 return h;
4274 }
4275 return 1;
4276}
4277
4278/*
4279 * Return TRUE if completion with "c" should insert the match, FALSE if only
4280 * to change the currently selected completion.
4281 */
4282 static int
4283ins_compl_use_match(int c)
4284{
4285 switch (c)
4286 {
4287 case K_UP:
4288 case K_DOWN:
4289 case K_PAGEDOWN:
4290 case K_KPAGEDOWN:
4291 case K_S_DOWN:
4292 case K_PAGEUP:
4293 case K_KPAGEUP:
4294 case K_S_UP:
4295 return FALSE;
4296 }
4297 return TRUE;
4298}
4299
4300/*
Bram Moolenaarbf7ff612021-12-27 12:52:07 +00004301 * Get the pattern, column and length for normal completion (CTRL-N CTRL-P
4302 * completion)
4303 * Sets the global variables: compl_col, compl_length and compl_pattern.
4304 * Uses the global variables: compl_cont_status and ctrl_x_mode
4305 */
4306 static int
4307get_normal_compl_info(char_u *line, int startcol, colnr_T curs_col)
4308{
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004309 if ((compl_cont_status & CONT_SOL) || ctrl_x_mode_path_defines())
Bram Moolenaarbf7ff612021-12-27 12:52:07 +00004310 {
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004311 if (!compl_status_adding())
Bram Moolenaarbf7ff612021-12-27 12:52:07 +00004312 {
4313 while (--startcol >= 0 && vim_isIDc(line[startcol]))
4314 ;
4315 compl_col += ++startcol;
4316 compl_length = curs_col - startcol;
4317 }
4318 if (p_ic)
4319 compl_pattern = str_foldcase(line + compl_col,
4320 compl_length, NULL, 0);
4321 else
4322 compl_pattern = vim_strnsave(line + compl_col, compl_length);
4323 if (compl_pattern == NULL)
4324 return FAIL;
4325 }
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004326 else if (compl_status_adding())
Bram Moolenaarbf7ff612021-12-27 12:52:07 +00004327 {
4328 char_u *prefix = (char_u *)"\\<";
4329
4330 // we need up to 2 extra chars for the prefix
4331 compl_pattern = alloc(quote_meta(NULL, line + compl_col,
4332 compl_length) + 2);
4333 if (compl_pattern == NULL)
4334 return FAIL;
4335 if (!vim_iswordp(line + compl_col)
4336 || (compl_col > 0
4337 && (vim_iswordp(mb_prevptr(line, line + compl_col)))))
4338 prefix = (char_u *)"";
4339 STRCPY((char *)compl_pattern, prefix);
4340 (void)quote_meta(compl_pattern + STRLEN(prefix),
4341 line + compl_col, compl_length);
4342 }
4343 else if (--startcol < 0
4344 || !vim_iswordp(mb_prevptr(line, line + startcol + 1)))
4345 {
4346 // Match any word of at least two chars
4347 compl_pattern = vim_strsave((char_u *)"\\<\\k\\k");
4348 if (compl_pattern == NULL)
4349 return FAIL;
4350 compl_col += curs_col;
4351 compl_length = 0;
4352 }
4353 else
4354 {
4355 // Search the point of change class of multibyte character
4356 // or not a word single byte character backward.
4357 if (has_mbyte)
4358 {
4359 int base_class;
4360 int head_off;
4361
4362 startcol -= (*mb_head_off)(line, line + startcol);
4363 base_class = mb_get_class(line + startcol);
4364 while (--startcol >= 0)
4365 {
4366 head_off = (*mb_head_off)(line, line + startcol);
4367 if (base_class != mb_get_class(line + startcol
4368 - head_off))
4369 break;
4370 startcol -= head_off;
4371 }
4372 }
4373 else
4374 while (--startcol >= 0 && vim_iswordc(line[startcol]))
4375 ;
4376 compl_col += ++startcol;
4377 compl_length = (int)curs_col - startcol;
4378 if (compl_length == 1)
4379 {
4380 // Only match word with at least two chars -- webb
4381 // there's no need to call quote_meta,
4382 // alloc(7) is enough -- Acevedo
4383 compl_pattern = alloc(7);
4384 if (compl_pattern == NULL)
4385 return FAIL;
4386 STRCPY((char *)compl_pattern, "\\<");
4387 (void)quote_meta(compl_pattern + 2, line + compl_col, 1);
4388 STRCAT((char *)compl_pattern, "\\k");
4389 }
4390 else
4391 {
4392 compl_pattern = alloc(quote_meta(NULL, line + compl_col,
4393 compl_length) + 2);
4394 if (compl_pattern == NULL)
4395 return FAIL;
4396 STRCPY((char *)compl_pattern, "\\<");
4397 (void)quote_meta(compl_pattern + 2, line + compl_col,
4398 compl_length);
4399 }
4400 }
4401
4402 return OK;
4403}
4404
4405/*
4406 * Get the pattern, column and length for whole line completion or for the
4407 * complete() function.
4408 * Sets the global variables: compl_col, compl_length and compl_pattern.
4409 */
4410 static int
4411get_wholeline_compl_info(char_u *line, colnr_T curs_col)
4412{
4413 compl_col = (colnr_T)getwhitecols(line);
4414 compl_length = (int)curs_col - (int)compl_col;
4415 if (compl_length < 0) // cursor in indent: empty pattern
4416 compl_length = 0;
4417 if (p_ic)
4418 compl_pattern = str_foldcase(line + compl_col, compl_length,
4419 NULL, 0);
4420 else
4421 compl_pattern = vim_strnsave(line + compl_col, compl_length);
4422 if (compl_pattern == NULL)
4423 return FAIL;
4424
4425 return OK;
4426}
4427
4428/*
4429 * Get the pattern, column and length for filename completion.
4430 * Sets the global variables: compl_col, compl_length and compl_pattern.
4431 */
4432 static int
4433get_filename_compl_info(char_u *line, int startcol, colnr_T curs_col)
4434{
4435 // Go back to just before the first filename character.
4436 if (startcol > 0)
4437 {
4438 char_u *p = line + startcol;
4439
4440 MB_PTR_BACK(line, p);
4441 while (p > line && vim_isfilec(PTR2CHAR(p)))
4442 MB_PTR_BACK(line, p);
4443 if (p == line && vim_isfilec(PTR2CHAR(p)))
4444 startcol = 0;
4445 else
4446 startcol = (int)(p - line) + 1;
4447 }
4448
4449 compl_col += startcol;
4450 compl_length = (int)curs_col - startcol;
4451 compl_pattern = addstar(line + compl_col, compl_length, EXPAND_FILES);
4452 if (compl_pattern == NULL)
4453 return FAIL;
4454
4455 return OK;
4456}
4457
4458/*
4459 * Get the pattern, column and length for command-line completion.
4460 * Sets the global variables: compl_col, compl_length and compl_pattern.
4461 */
4462 static int
4463get_cmdline_compl_info(char_u *line, colnr_T curs_col)
4464{
4465 compl_pattern = vim_strnsave(line, curs_col);
4466 if (compl_pattern == NULL)
4467 return FAIL;
4468 set_cmd_context(&compl_xp, compl_pattern,
4469 (int)STRLEN(compl_pattern), curs_col, FALSE);
4470 if (compl_xp.xp_context == EXPAND_UNSUCCESSFUL
4471 || compl_xp.xp_context == EXPAND_NOTHING)
4472 // No completion possible, use an empty pattern to get a
4473 // "pattern not found" message.
4474 compl_col = curs_col;
4475 else
4476 compl_col = (int)(compl_xp.xp_pattern - compl_pattern);
4477 compl_length = curs_col - compl_col;
4478
4479 return OK;
4480}
4481
4482/*
4483 * Get the pattern, column and length for user defined completion ('omnifunc',
4484 * 'completefunc' and 'thesaurusfunc')
4485 * Sets the global variables: compl_col, compl_length and compl_pattern.
4486 * Uses the global variable: spell_bad_len
4487 */
4488 static int
4489get_userdefined_compl_info(colnr_T curs_col UNUSED)
4490{
4491 int ret = FAIL;
4492
4493#ifdef FEAT_COMPL_FUNC
4494 // Call user defined function 'completefunc' with "a:findstart"
4495 // set to 1 to obtain the length of text to use for completion.
4496 char_u *line;
4497 typval_T args[3];
4498 int col;
4499 char_u *funcname;
4500 pos_T pos;
4501 int save_State = State;
4502 callback_T *cb;
4503
4504 // Call 'completefunc' or 'omnifunc' or 'thesaurusfunc' and get pattern
4505 // length as a string
4506 funcname = get_complete_funcname(ctrl_x_mode);
4507 if (*funcname == NUL)
4508 {
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004509 semsg(_(e_option_str_is_not_set), ctrl_x_mode_function()
Bram Moolenaarbf7ff612021-12-27 12:52:07 +00004510 ? "completefunc" : "omnifunc");
4511 return FAIL;
4512 }
4513
4514 args[0].v_type = VAR_NUMBER;
4515 args[0].vval.v_number = 1;
4516 args[1].v_type = VAR_STRING;
4517 args[1].vval.v_string = (char_u *)"";
4518 args[2].v_type = VAR_UNKNOWN;
4519 pos = curwin->w_cursor;
4520 ++textwinlock;
4521 cb = get_insert_callback(ctrl_x_mode);
4522 col = call_callback_retnr(cb, 2, args);
4523 --textwinlock;
4524
4525 State = save_State;
4526 curwin->w_cursor = pos; // restore the cursor position
4527 validate_cursor();
4528 if (!EQUAL_POS(curwin->w_cursor, pos))
4529 {
Bram Moolenaar9d00e4a2022-01-05 17:49:15 +00004530 emsg(_(e_complete_function_deleted_text));
Bram Moolenaarbf7ff612021-12-27 12:52:07 +00004531 return FAIL;
4532 }
4533
4534 // Return value -2 means the user complete function wants to
4535 // cancel the complete without an error.
4536 // Return value -3 does the same as -2 and leaves CTRL-X mode.
4537 if (col == -2)
4538 return FAIL;
4539 if (col == -3)
4540 {
4541 ctrl_x_mode = CTRL_X_NORMAL;
4542 edit_submode = NULL;
4543 if (!shortmess(SHM_COMPLETIONMENU))
4544 msg_clr_cmdline();
4545 return FAIL;
4546 }
4547
Yegappan Lakshmanan37079142022-01-08 10:38:48 +00004548 // Reset extended parameters of completion, when starting new
Bram Moolenaarbf7ff612021-12-27 12:52:07 +00004549 // completion.
4550 compl_opt_refresh_always = FALSE;
4551 compl_opt_suppress_empty = FALSE;
4552
4553 if (col < 0)
4554 col = curs_col;
4555 compl_col = col;
4556 if (compl_col > curs_col)
4557 compl_col = curs_col;
4558
4559 // Setup variables for completion. Need to obtain "line" again,
4560 // it may have become invalid.
4561 line = ml_get(curwin->w_cursor.lnum);
4562 compl_length = curs_col - compl_col;
4563 compl_pattern = vim_strnsave(line + compl_col, compl_length);
4564 if (compl_pattern == NULL)
4565 return FAIL;
4566
4567 ret = OK;
4568#endif
4569
4570 return ret;
4571}
4572
4573/*
4574 * Get the pattern, column and length for spell completion.
4575 * Sets the global variables: compl_col, compl_length and compl_pattern.
4576 * Uses the global variable: spell_bad_len
4577 */
4578 static int
4579get_spell_compl_info(int startcol UNUSED, colnr_T curs_col UNUSED)
4580{
4581 int ret = FAIL;
4582#ifdef FEAT_SPELL
4583 char_u *line;
4584
4585 if (spell_bad_len > 0)
4586 compl_col = curs_col - spell_bad_len;
4587 else
4588 compl_col = spell_word_start(startcol);
4589 if (compl_col >= (colnr_T)startcol)
4590 {
4591 compl_length = 0;
4592 compl_col = curs_col;
4593 }
4594 else
4595 {
4596 spell_expand_check_cap(compl_col);
4597 compl_length = (int)curs_col - compl_col;
4598 }
4599 // Need to obtain "line" again, it may have become invalid.
4600 line = ml_get(curwin->w_cursor.lnum);
4601 compl_pattern = vim_strnsave(line + compl_col, compl_length);
4602 if (compl_pattern == NULL)
4603 return FAIL;
4604
4605 ret = OK;
4606#endif
4607
4608 return ret;
4609}
4610
4611/*
4612 * Get the completion pattern, column and length.
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004613 * "startcol" - start column number of the completion pattern/text
4614 * "cur_col" - current cursor column
4615 * On return, "line_invalid" is set to TRUE, if the current line may have
4616 * become invalid and needs to be fetched again.
4617 * Returns OK on success.
Bram Moolenaarbf7ff612021-12-27 12:52:07 +00004618 */
4619 static int
4620compl_get_info(char_u *line, int startcol, colnr_T curs_col, int *line_invalid)
4621{
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004622 if (ctrl_x_mode_normal()
Bram Moolenaarbf7ff612021-12-27 12:52:07 +00004623 || (ctrl_x_mode & CTRL_X_WANT_IDENT
4624 && !thesaurus_func_complete(ctrl_x_mode)))
4625 {
4626 return get_normal_compl_info(line, startcol, curs_col);
4627 }
4628 else if (ctrl_x_mode_line_or_eval())
4629 {
4630 return get_wholeline_compl_info(line, curs_col);
4631 }
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004632 else if (ctrl_x_mode_files())
Bram Moolenaarbf7ff612021-12-27 12:52:07 +00004633 {
4634 return get_filename_compl_info(line, startcol, curs_col);
4635 }
4636 else if (ctrl_x_mode == CTRL_X_CMDLINE)
4637 {
4638 return get_cmdline_compl_info(line, curs_col);
4639 }
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004640 else if (ctrl_x_mode_function() || ctrl_x_mode_omni()
Bram Moolenaarbf7ff612021-12-27 12:52:07 +00004641 || thesaurus_func_complete(ctrl_x_mode))
4642 {
4643 if (get_userdefined_compl_info(curs_col) == FAIL)
4644 return FAIL;
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004645 *line_invalid = TRUE; // "line" may have become invalid
Bram Moolenaarbf7ff612021-12-27 12:52:07 +00004646 }
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004647 else if (ctrl_x_mode_spell())
Bram Moolenaarbf7ff612021-12-27 12:52:07 +00004648 {
4649 if (get_spell_compl_info(startcol, curs_col) == FAIL)
4650 return FAIL;
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004651 *line_invalid = TRUE; // "line" may have become invalid
Bram Moolenaarbf7ff612021-12-27 12:52:07 +00004652 }
4653 else
4654 {
4655 internal_error("ins_complete()");
4656 return FAIL;
4657 }
4658
4659 return OK;
4660}
4661
4662/*
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004663 * Continue an interrupted completion mode search in "line".
4664 *
4665 * If this same ctrl_x_mode has been interrupted use the text from
4666 * "compl_startpos" to the cursor as a pattern to add a new word instead of
4667 * expand the one before the cursor, in word-wise if "compl_startpos" is not in
4668 * the same line as the cursor then fix it (the line has been split because it
4669 * was longer than 'tw'). if SOL is set then skip the previous pattern, a word
4670 * at the beginning of the line has been inserted, we'll look for that.
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004671 */
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004672 static void
4673ins_compl_continue_search(char_u *line)
4674{
4675 // it is a continued search
4676 compl_cont_status &= ~CONT_INTRPT; // remove INTRPT
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004677 if (ctrl_x_mode_normal() || ctrl_x_mode_path_patterns()
4678 || ctrl_x_mode_path_defines())
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004679 {
4680 if (compl_startpos.lnum != curwin->w_cursor.lnum)
4681 {
4682 // line (probably) wrapped, set compl_startpos to the
4683 // first non_blank in the line, if it is not a wordchar
4684 // include it to get a better pattern, but then we don't
4685 // want the "\\<" prefix, check it below
4686 compl_col = (colnr_T)getwhitecols(line);
4687 compl_startpos.col = compl_col;
4688 compl_startpos.lnum = curwin->w_cursor.lnum;
4689 compl_cont_status &= ~CONT_SOL; // clear SOL if present
4690 }
4691 else
4692 {
4693 // S_IPOS was set when we inserted a word that was at the
4694 // beginning of the line, which means that we'll go to SOL
4695 // mode but first we need to redefine compl_startpos
4696 if (compl_cont_status & CONT_S_IPOS)
4697 {
4698 compl_cont_status |= CONT_SOL;
4699 compl_startpos.col = (colnr_T)(skipwhite(
4700 line + compl_length
4701 + compl_startpos.col) - line);
4702 }
4703 compl_col = compl_startpos.col;
4704 }
4705 compl_length = curwin->w_cursor.col - (int)compl_col;
4706 // IObuff is used to add a "word from the next line" would we
4707 // have enough space? just being paranoid
4708#define MIN_SPACE 75
4709 if (compl_length > (IOSIZE - MIN_SPACE))
4710 {
4711 compl_cont_status &= ~CONT_SOL;
4712 compl_length = (IOSIZE - MIN_SPACE);
4713 compl_col = curwin->w_cursor.col - compl_length;
4714 }
4715 compl_cont_status |= CONT_ADDING | CONT_N_ADDS;
4716 if (compl_length < 1)
4717 compl_cont_status &= CONT_LOCAL;
4718 }
4719 else if (ctrl_x_mode_line_or_eval())
4720 compl_cont_status = CONT_ADDING | CONT_N_ADDS;
4721 else
4722 compl_cont_status = 0;
4723}
4724
4725/*
4726 * start insert mode completion
4727 */
4728 static int
4729ins_compl_start(void)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004730{
4731 char_u *line;
4732 int startcol = 0; // column where searched text starts
4733 colnr_T curs_col; // cursor column
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004734 int line_invalid = FALSE;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004735 int save_did_ai = did_ai;
Bram Moolenaard9eefe32019-04-06 14:22:21 +02004736 int flags = CP_ORIGINAL_TEXT;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004737
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004738 // First time we hit ^N or ^P (in a row, I mean)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004739
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004740 did_ai = FALSE;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004741#ifdef FEAT_SMARTINDENT
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004742 did_si = FALSE;
4743 can_si = FALSE;
4744 can_si_back = FALSE;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004745#endif
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004746 if (stop_arrow() == FAIL)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004747 return FAIL;
4748
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004749 line = ml_get(curwin->w_cursor.lnum);
4750 curs_col = curwin->w_cursor.col;
4751 compl_pending = 0;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004752
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004753 if ((compl_cont_status & CONT_INTRPT) == CONT_INTRPT
4754 && compl_cont_mode == ctrl_x_mode)
4755 // this same ctrl-x_mode was interrupted previously. Continue the
4756 // completion.
4757 ins_compl_continue_search(line);
4758 else
4759 compl_cont_status &= CONT_LOCAL;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004760
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004761 if (!compl_status_adding()) // normal expansion
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004762 {
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004763 compl_cont_mode = ctrl_x_mode;
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004764 if (ctrl_x_mode_not_default())
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004765 // Remove LOCAL if ctrl_x_mode != CTRL_X_NORMAL
4766 compl_cont_status = 0;
4767 compl_cont_status |= CONT_N_ADDS;
4768 compl_startpos = curwin->w_cursor;
4769 startcol = (int)curs_col;
4770 compl_col = 0;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004771 }
4772
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004773 // Work out completion pattern and original text -- webb
4774 if (compl_get_info(line, startcol, curs_col, &line_invalid) == FAIL)
4775 {
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004776 if (ctrl_x_mode_function() || ctrl_x_mode_omni()
4777 || thesaurus_func_complete(ctrl_x_mode))
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004778 // restore did_ai, so that adding comment leader works
4779 did_ai = save_did_ai;
4780 return FAIL;
4781 }
4782 // If "line" was changed while getting completion info get it again.
4783 if (line_invalid)
4784 line = ml_get(curwin->w_cursor.lnum);
4785
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004786 if (compl_status_adding())
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004787 {
4788 edit_submode_pre = (char_u *)_(" Adding");
4789 if (ctrl_x_mode_line_or_eval())
4790 {
4791 // Insert a new line, keep indentation but ignore 'comments'.
4792 char_u *old = curbuf->b_p_com;
4793
4794 curbuf->b_p_com = (char_u *)"";
4795 compl_startpos.lnum = curwin->w_cursor.lnum;
4796 compl_startpos.col = compl_col;
4797 ins_eol('\r');
4798 curbuf->b_p_com = old;
4799 compl_length = 0;
4800 compl_col = curwin->w_cursor.col;
4801 }
4802 }
4803 else
4804 {
4805 edit_submode_pre = NULL;
4806 compl_startpos.col = compl_col;
4807 }
4808
4809 if (compl_cont_status & CONT_LOCAL)
4810 edit_submode = (char_u *)_(ctrl_x_msgs[CTRL_X_LOCAL_MSG]);
4811 else
4812 edit_submode = (char_u *)_(CTRL_X_MSG(ctrl_x_mode));
4813
4814 // If any of the original typed text has been changed we need to fix
4815 // the redo buffer.
4816 ins_compl_fixRedoBufForLeader(NULL);
4817
4818 // Always add completion for the original text.
4819 vim_free(compl_orig_text);
4820 compl_orig_text = vim_strnsave(line + compl_col, compl_length);
4821 if (p_ic)
4822 flags |= CP_ICASE;
4823 if (compl_orig_text == NULL || ins_compl_add(compl_orig_text,
4824 -1, NULL, NULL, NULL, 0, flags, FALSE) != OK)
4825 {
4826 VIM_CLEAR(compl_pattern);
4827 VIM_CLEAR(compl_orig_text);
4828 return FAIL;
4829 }
4830
4831 // showmode might reset the internal line pointers, so it must
4832 // be called before line = ml_get(), or when this address is no
4833 // longer needed. -- Acevedo.
4834 edit_submode_extra = (char_u *)_("-- Searching...");
4835 edit_submode_highl = HLF_COUNT;
4836 showmode();
4837 edit_submode_extra = NULL;
4838 out_flush();
4839
4840 return OK;
4841}
4842
4843/*
4844 * display the completion status message
4845 */
4846 static void
4847ins_compl_show_statusmsg(void)
4848{
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004849 // we found no match if the list has only the "compl_orig_text"-entry
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004850 if (is_first_match(compl_first_match->cp_next))
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004851 {
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004852 edit_submode_extra = compl_status_adding() && compl_length > 1
Bram Moolenaar460ae5d2022-01-01 14:19:49 +00004853 ? (char_u *)_(e_hitend)
4854 : (char_u *)_(e_pattern_not_found);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004855 edit_submode_highl = HLF_E;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004856 }
4857
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004858 if (edit_submode_extra == NULL)
4859 {
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004860 if (match_at_original_text(compl_curr_match))
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004861 {
4862 edit_submode_extra = (char_u *)_("Back at original");
4863 edit_submode_highl = HLF_W;
4864 }
4865 else if (compl_cont_status & CONT_S_IPOS)
4866 {
4867 edit_submode_extra = (char_u *)_("Word from other line");
4868 edit_submode_highl = HLF_COUNT;
4869 }
4870 else if (compl_curr_match->cp_next == compl_curr_match->cp_prev)
4871 {
4872 edit_submode_extra = (char_u *)_("The only match");
4873 edit_submode_highl = HLF_COUNT;
Bram Moolenaarf9d51352020-10-26 19:22:42 +01004874 compl_curr_match->cp_number = 1;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004875 }
4876 else
4877 {
Bram Moolenaar977fd0b2020-10-27 09:12:45 +01004878#if defined(FEAT_COMPL_FUNC) || defined(FEAT_EVAL)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004879 // Update completion sequence number when needed.
4880 if (compl_curr_match->cp_number == -1)
Bram Moolenaarf9d51352020-10-26 19:22:42 +01004881 ins_compl_update_sequence_numbers();
Bram Moolenaar977fd0b2020-10-27 09:12:45 +01004882#endif
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004883 // The match should always have a sequence number now, this is
4884 // just a safety check.
4885 if (compl_curr_match->cp_number != -1)
4886 {
4887 // Space for 10 text chars. + 2x10-digit no.s = 31.
4888 // Translations may need more than twice that.
4889 static char_u match_ref[81];
4890
4891 if (compl_matches > 0)
4892 vim_snprintf((char *)match_ref, sizeof(match_ref),
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004893 _("match %d of %d"),
4894 compl_curr_match->cp_number, compl_matches);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004895 else
4896 vim_snprintf((char *)match_ref, sizeof(match_ref),
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004897 _("match %d"),
4898 compl_curr_match->cp_number);
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004899 edit_submode_extra = match_ref;
4900 edit_submode_highl = HLF_R;
4901 if (dollar_vcol >= 0)
4902 curs_columns(FALSE);
4903 }
4904 }
4905 }
4906
4907 // Show a message about what (completion) mode we're in.
4908 if (!compl_opt_suppress_empty)
4909 {
4910 showmode();
4911 if (!shortmess(SHM_COMPLETIONMENU))
4912 {
4913 if (edit_submode_extra != NULL)
4914 {
4915 if (!p_smd)
Bram Moolenaarcc233582020-12-12 13:32:07 +01004916 {
4917 msg_hist_off = TRUE;
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004918 msg_attr((char *)edit_submode_extra,
4919 edit_submode_highl < HLF_COUNT
4920 ? HL_ATTR(edit_submode_highl) : 0);
Bram Moolenaarcc233582020-12-12 13:32:07 +01004921 msg_hist_off = FALSE;
4922 }
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004923 }
4924 else
4925 msg_clr_cmdline(); // necessary for "noshowmode"
4926 }
4927 }
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004928}
4929
4930/*
4931 * Do Insert mode completion.
4932 * Called when character "c" was typed, which has a meaning for completion.
4933 * Returns OK if completion was done, FAIL if something failed (out of mem).
4934 */
4935 int
4936ins_complete(int c, int enable_pum)
4937{
4938 int n;
4939 int save_w_wrow;
4940 int save_w_leftcol;
4941 int insert_match;
4942
4943 compl_direction = ins_compl_key2dir(c);
4944 insert_match = ins_compl_use_match(c);
4945
4946 if (!compl_started)
4947 {
4948 if (ins_compl_start() == FAIL)
4949 return FAIL;
4950 }
4951 else if (insert_match && stop_arrow() == FAIL)
4952 return FAIL;
4953
4954 compl_shown_match = compl_curr_match;
4955 compl_shows_dir = compl_direction;
4956
4957 // Find next match (and following matches).
4958 save_w_wrow = curwin->w_wrow;
4959 save_w_leftcol = curwin->w_leftcol;
4960 n = ins_compl_next(TRUE, ins_compl_key2count(c), insert_match, FALSE);
4961
4962 // may undisplay the popup menu
4963 ins_compl_upd_pum();
4964
4965 if (n > 1) // all matches have been found
4966 compl_matches = n;
4967 compl_curr_match = compl_shown_match;
4968 compl_direction = compl_shows_dir;
4969
4970 // Eat the ESC that vgetc() returns after a CTRL-C to avoid leaving Insert
4971 // mode.
4972 if (got_int && !global_busy)
4973 {
4974 (void)vgetc();
4975 got_int = FALSE;
4976 }
4977
4978 // we found no match if the list has only the "compl_orig_text"-entry
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004979 if (is_first_match(compl_first_match->cp_next))
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004980 {
4981 // remove N_ADDS flag, so next ^X<> won't try to go to ADDING mode,
4982 // because we couldn't expand anything at first place, but if we used
4983 // ^P, ^N, ^X^I or ^X^D we might want to add-expand a single-char-word
4984 // (such as M in M'exico) if not tried already. -- Acevedo
4985 if (compl_length > 1
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00004986 || compl_status_adding()
4987 || (ctrl_x_mode_not_default()
4988 && !ctrl_x_mode_path_patterns()
4989 && !ctrl_x_mode_path_defines()))
Yegappan Lakshmanan5d2e0072021-12-30 11:40:53 +00004990 compl_cont_status &= ~CONT_N_ADDS;
4991 }
4992
4993 if (compl_curr_match->cp_flags & CP_CONT_S_IPOS)
4994 compl_cont_status |= CONT_S_IPOS;
4995 else
4996 compl_cont_status &= ~CONT_S_IPOS;
4997
4998 ins_compl_show_statusmsg();
Bram Moolenaar7591bb32019-03-30 13:53:47 +01004999
5000 // Show the popup menu, unless we got interrupted.
5001 if (enable_pum && !compl_interrupted)
5002 show_pum(save_w_wrow, save_w_leftcol);
5003
5004 compl_was_interrupted = compl_interrupted;
5005 compl_interrupted = FALSE;
5006
5007 return OK;
5008}
5009
Yegappan Lakshmanane9825862022-01-03 11:03:48 +00005010/*
5011 * Remove (if needed) and show the popup menu
5012 */
Bram Moolenaar7591bb32019-03-30 13:53:47 +01005013 static void
5014show_pum(int prev_w_wrow, int prev_w_leftcol)
5015{
5016 // RedrawingDisabled may be set when invoked through complete().
5017 int n = RedrawingDisabled;
5018
5019 RedrawingDisabled = 0;
5020
5021 // If the cursor moved or the display scrolled we need to remove the pum
5022 // first.
5023 setcursor();
5024 if (prev_w_wrow != curwin->w_wrow || prev_w_leftcol != curwin->w_leftcol)
5025 ins_compl_del_pum();
5026
5027 ins_compl_show_pum();
5028 setcursor();
5029 RedrawingDisabled = n;
5030}
5031
5032/*
5033 * Looks in the first "len" chars. of "src" for search-metachars.
5034 * If dest is not NULL the chars. are copied there quoting (with
5035 * a backslash) the metachars, and dest would be NUL terminated.
5036 * Returns the length (needed) of dest
5037 */
5038 static unsigned
5039quote_meta(char_u *dest, char_u *src, int len)
5040{
5041 unsigned m = (unsigned)len + 1; // one extra for the NUL
5042
5043 for ( ; --len >= 0; src++)
5044 {
5045 switch (*src)
5046 {
5047 case '.':
5048 case '*':
5049 case '[':
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00005050 if (ctrl_x_mode_dictionary() || ctrl_x_mode_thesaurus())
Bram Moolenaar7591bb32019-03-30 13:53:47 +01005051 break;
5052 // FALLTHROUGH
5053 case '~':
Bram Moolenaarf4e20992020-12-21 19:59:08 +01005054 if (!magic_isset()) // quote these only if magic is set
Bram Moolenaar7591bb32019-03-30 13:53:47 +01005055 break;
5056 // FALLTHROUGH
5057 case '\\':
Yegappan Lakshmanand94fbfc2022-01-04 17:01:44 +00005058 if (ctrl_x_mode_dictionary() || ctrl_x_mode_thesaurus())
Bram Moolenaar7591bb32019-03-30 13:53:47 +01005059 break;
5060 // FALLTHROUGH
5061 case '^': // currently it's not needed.
5062 case '$':
5063 m++;
5064 if (dest != NULL)
5065 *dest++ = '\\';
5066 break;
5067 }
5068 if (dest != NULL)
5069 *dest++ = *src;
5070 // Copy remaining bytes of a multibyte character.
5071 if (has_mbyte)
5072 {
5073 int i, mb_len;
5074
5075 mb_len = (*mb_ptr2len)(src) - 1;
5076 if (mb_len > 0 && len >= mb_len)
5077 for (i = 0; i < mb_len; ++i)
5078 {
5079 --len;
5080 ++src;
5081 if (dest != NULL)
5082 *dest++ = *src;
5083 }
5084 }
5085 }
5086 if (dest != NULL)
5087 *dest = NUL;
5088
5089 return m;
5090}
5091
Bram Moolenaare2c453d2019-08-21 14:37:09 +02005092#if defined(EXITFREE) || defined(PROTO)
Bram Moolenaar7591bb32019-03-30 13:53:47 +01005093 void
5094free_insexpand_stuff(void)
5095{
5096 VIM_CLEAR(compl_orig_text);
Yegappan Lakshmanan8658c752021-12-03 11:09:29 +00005097# ifdef FEAT_EVAL
5098 free_callback(&cfu_cb);
5099 free_callback(&ofu_cb);
5100 free_callback(&tsrfu_cb);
5101# endif
Bram Moolenaar7591bb32019-03-30 13:53:47 +01005102}
Bram Moolenaare2c453d2019-08-21 14:37:09 +02005103#endif
Bram Moolenaar7591bb32019-03-30 13:53:47 +01005104
Bram Moolenaare2c453d2019-08-21 14:37:09 +02005105#ifdef FEAT_SPELL
Bram Moolenaar7591bb32019-03-30 13:53:47 +01005106/*
5107 * Called when starting CTRL_X_SPELL mode: Move backwards to a previous badly
5108 * spelled word, if there is one.
5109 */
5110 static void
5111spell_back_to_badword(void)
5112{
5113 pos_T tpos = curwin->w_cursor;
5114
5115 spell_bad_len = spell_move_to(curwin, BACKWARD, TRUE, TRUE, NULL);
5116 if (curwin->w_cursor.col != tpos.col)
5117 start_arrow(&tpos);
5118}
Bram Moolenaare2c453d2019-08-21 14:37:09 +02005119#endif