insexpand.c (209189B)
1 // insexpand.c: functions for Insert mode completion 2 3 #include <assert.h> 4 #include <limits.h> 5 #include <stdbool.h> 6 #include <stddef.h> 7 #include <stdint.h> 8 #include <stdio.h> 9 #include <stdlib.h> 10 #include <string.h> 11 12 #include "klib/kvec.h" 13 #include "nvim/api/private/helpers.h" 14 #include "nvim/ascii_defs.h" 15 #include "nvim/autocmd.h" 16 #include "nvim/autocmd_defs.h" 17 #include "nvim/buffer.h" 18 #include "nvim/buffer_defs.h" 19 #include "nvim/change.h" 20 #include "nvim/charset.h" 21 #include "nvim/cmdexpand.h" 22 #include "nvim/cmdexpand_defs.h" 23 #include "nvim/cursor.h" 24 #include "nvim/drawscreen.h" 25 #include "nvim/edit.h" 26 #include "nvim/errors.h" 27 #include "nvim/eval.h" 28 #include "nvim/eval/executor.h" 29 #include "nvim/eval/typval.h" 30 #include "nvim/eval/typval_defs.h" 31 #include "nvim/eval/userfunc.h" 32 #include "nvim/eval/vars.h" 33 #include "nvim/ex_eval.h" 34 #include "nvim/ex_getln.h" 35 #include "nvim/extmark.h" 36 #include "nvim/extmark_defs.h" 37 #include "nvim/fileio.h" 38 #include "nvim/fuzzy.h" 39 #include "nvim/garray.h" 40 #include "nvim/garray_defs.h" 41 #include "nvim/getchar.h" 42 #include "nvim/gettext_defs.h" 43 #include "nvim/globals.h" 44 #include "nvim/highlight_defs.h" 45 #include "nvim/highlight_group.h" 46 #include "nvim/indent.h" 47 #include "nvim/indent_c.h" 48 #include "nvim/insexpand.h" 49 #include "nvim/keycodes.h" 50 #include "nvim/lua/executor.h" 51 #include "nvim/macros_defs.h" 52 #include "nvim/mark_defs.h" 53 #include "nvim/mbyte.h" 54 #include "nvim/mbyte_defs.h" 55 #include "nvim/memline.h" 56 #include "nvim/memory.h" 57 #include "nvim/message.h" 58 #include "nvim/move.h" 59 #include "nvim/option.h" 60 #include "nvim/option_defs.h" 61 #include "nvim/option_vars.h" 62 #include "nvim/os/fs.h" 63 #include "nvim/os/input.h" 64 #include "nvim/os/time.h" 65 #include "nvim/path.h" 66 #include "nvim/popupmenu.h" 67 #include "nvim/pos_defs.h" 68 #include "nvim/regexp.h" 69 #include "nvim/regexp_defs.h" 70 #include "nvim/register.h" 71 #include "nvim/search.h" 72 #include "nvim/spell.h" 73 #include "nvim/state.h" 74 #include "nvim/state_defs.h" 75 #include "nvim/strings.h" 76 #include "nvim/tag.h" 77 #include "nvim/textformat.h" 78 #include "nvim/types_defs.h" 79 #include "nvim/ui.h" 80 #include "nvim/undo.h" 81 #include "nvim/vim_defs.h" 82 #include "nvim/window.h" 83 #include "nvim/winfloat.h" 84 85 // Definitions used for CTRL-X submode. 86 // Note: If you change CTRL-X submode, you must also maintain ctrl_x_msgs[] 87 // and ctrl_x_mode_names[]. 88 89 #define CTRL_X_WANT_IDENT 0x100 90 91 enum { 92 CTRL_X_NORMAL = 0, ///< CTRL-N CTRL-P completion, default 93 CTRL_X_NOT_DEFINED_YET = 1, 94 CTRL_X_SCROLL = 2, 95 CTRL_X_WHOLE_LINE = 3, 96 CTRL_X_FILES = 4, 97 CTRL_X_TAGS = (5 + CTRL_X_WANT_IDENT), 98 CTRL_X_PATH_PATTERNS = (6 + CTRL_X_WANT_IDENT), 99 CTRL_X_PATH_DEFINES = (7 + CTRL_X_WANT_IDENT), 100 CTRL_X_FINISHED = 8, 101 CTRL_X_DICTIONARY = (9 + CTRL_X_WANT_IDENT), 102 CTRL_X_THESAURUS = (10 + CTRL_X_WANT_IDENT), 103 CTRL_X_CMDLINE = 11, 104 CTRL_X_FUNCTION = 12, 105 CTRL_X_OMNI = 13, 106 CTRL_X_SPELL = 14, 107 CTRL_X_LOCAL_MSG = 15, ///< only used in "ctrl_x_msgs" 108 CTRL_X_EVAL = 16, ///< for builtin function complete() 109 CTRL_X_CMDLINE_CTRL_X = 17, ///< CTRL-X typed in CTRL_X_CMDLINE 110 CTRL_X_BUFNAMES = 18, 111 CTRL_X_REGISTER = 19, ///< complete words from registers 112 }; 113 114 #define CTRL_X_MSG(i) ctrl_x_msgs[(i) & ~CTRL_X_WANT_IDENT] 115 116 /// Message for CTRL-X mode, index is ctrl_x_mode. 117 static char *ctrl_x_msgs[] = { 118 N_(" Keyword completion (^N^P)"), // CTRL_X_NORMAL, ^P/^N compl. 119 N_(" ^X mode (^]^D^E^F^I^K^L^N^O^P^Rs^U^V^Y)"), 120 NULL, // CTRL_X_SCROLL: depends on state 121 N_(" Whole line completion (^L^N^P)"), 122 N_(" File name completion (^F^N^P)"), 123 N_(" Tag completion (^]^N^P)"), 124 N_(" Path pattern completion (^N^P)"), 125 N_(" Definition completion (^D^N^P)"), 126 NULL, // CTRL_X_FINISHED 127 N_(" Dictionary completion (^K^N^P)"), 128 N_(" Thesaurus completion (^T^N^P)"), 129 N_(" Command-line completion (^V^N^P)"), 130 N_(" User defined completion (^U^N^P)"), 131 N_(" Omni completion (^O^N^P)"), 132 N_(" Spelling suggestion (^S^N^P)"), 133 N_(" Keyword Local completion (^N^P)"), 134 NULL, // CTRL_X_EVAL doesn't use msg. 135 N_(" Command-line completion (^V^N^P)"), 136 NULL, 137 N_(" Register completion (^N^P)"), 138 }; 139 140 static char *ctrl_x_mode_names[] = { 141 "keyword", 142 "ctrl_x", 143 "scroll", 144 "whole_line", 145 "files", 146 "tags", 147 "path_patterns", 148 "path_defines", 149 "unknown", // CTRL_X_FINISHED 150 "dictionary", 151 "thesaurus", 152 "cmdline", 153 "function", 154 "omni", 155 "spell", 156 NULL, // CTRL_X_LOCAL_MSG only used in "ctrl_x_msgs" 157 "eval", 158 "cmdline", 159 NULL, // CTRL_X_BUFNAME 160 "register", 161 }; 162 163 /// Structure used to store one match for insert completion. 164 typedef struct compl_S compl_T; 165 struct compl_S { 166 compl_T *cp_next; 167 compl_T *cp_prev; 168 compl_T *cp_match_next; ///< matched next compl_T 169 String cp_str; ///< matched text 170 char *(cp_text[CPT_COUNT]); ///< text for the menu 171 typval_T cp_user_data; 172 char *cp_fname; ///< file containing the match, allocated when 173 ///< cp_flags has CP_FREE_FNAME 174 int cp_flags; ///< CP_ values 175 int cp_number; ///< sequence number 176 int cp_score; ///< fuzzy match score or proximity score 177 bool cp_in_match_array; ///< collected by compl_match_array 178 int cp_user_abbr_hlattr; ///< highlight attribute for abbr 179 int cp_user_kind_hlattr; ///< highlight attribute for kind 180 int cp_cpt_source_idx; ///< index of this match's source in 'cpt' option 181 }; 182 183 /// state information used for getting the next set of insert completion 184 /// matches. 185 typedef struct { 186 char *e_cpt_copy; ///< copy of 'complete' 187 char *e_cpt; ///< current entry in "e_cpt_copy" 188 buf_T *ins_buf; ///< buffer being scanned 189 pos_T *cur_match_pos; ///< current match position 190 pos_T prev_match_pos; ///< previous match position 191 bool set_match_pos; ///< save first_match_pos/last_match_pos 192 pos_T first_match_pos; ///< first match position 193 pos_T last_match_pos; ///< last match position 194 bool found_all; ///< found all matches of a certain type. 195 char *dict; ///< dictionary file to search 196 int dict_f; ///< "dict" is an exact file name or not 197 Callback *func_cb; ///< callback of function in 'cpt' option 198 } ins_compl_next_state_T; 199 200 #include "insexpand.c.generated.h" 201 202 /// values for cp_flags 203 typedef enum { 204 CP_ORIGINAL_TEXT = 1, ///< the original text when the expansion begun 205 CP_FREE_FNAME = 2, ///< cp_fname is allocated 206 CP_CONT_S_IPOS = 4, ///< use CONT_S_IPOS for compl_cont_status 207 CP_EQUAL = 8, ///< ins_compl_equal() always returns true 208 CP_ICASE = 16, ///< ins_compl_equal ignores case 209 CP_FAST = 32, ///< use fast_breakcheck instead of os_breakcheck 210 } cp_flags_T; 211 212 static const char e_hitend[] = N_("Hit end of paragraph"); 213 static const char e_compldel[] = N_("E840: Completion function deleted text"); 214 215 // All the current matches are stored in a list. 216 // "compl_first_match" points to the start of the list. 217 // "compl_curr_match" points to the currently selected entry. 218 // "compl_shown_match" is different from compl_curr_match during 219 // ins_compl_get_exp(), when new matches are added to the list. 220 // "compl_old_match" points to previous "compl_curr_match". 221 222 static compl_T *compl_first_match = NULL; 223 static compl_T *compl_curr_match = NULL; 224 static compl_T *compl_shown_match = NULL; 225 static compl_T *compl_old_match = NULL; 226 227 /// list used to store the compl_T which have the max score 228 static compl_T **compl_best_matches = NULL; 229 static int compl_num_bests = 0; 230 231 /// After using a cursor key <Enter> selects a match in the popup menu, 232 /// otherwise it inserts a line break. 233 static bool compl_enter_selects = false; 234 235 /// When "compl_leader" is not NULL only matches that start with this string 236 /// are used. 237 static String compl_leader = STRING_INIT; 238 239 static bool compl_get_longest = false; ///< put longest common string in compl_leader 240 241 /// This flag is false when no match is selected (by ^N/^P) or the match was 242 /// edited or using the longest common string. 243 static bool compl_used_match; 244 245 /// didn't finish finding completions. 246 static bool compl_was_interrupted = false; 247 248 // Set when character typed while looking for matches and it means we should 249 // stop looking for matches. 250 static bool compl_interrupted = false; 251 252 static bool compl_restarting = false; ///< don't insert match 253 254 /// When the first completion is done "compl_started" is set. When it's 255 /// false the word to be completed must be located. 256 static bool compl_started = false; 257 258 /// Which Ctrl-X mode are we in? 259 static int ctrl_x_mode = CTRL_X_NORMAL; 260 261 static int compl_matches = 0; ///< number of completion matches 262 static String compl_pattern = STRING_INIT; ///< search pattern for matching items 263 static String cpt_compl_pattern = STRING_INIT; ///< pattern returned by func in 'cpt' 264 static Direction compl_direction = FORWARD; 265 static Direction compl_shows_dir = FORWARD; 266 static int compl_pending = 0; ///< > 1 for postponed CTRL-N 267 static pos_T compl_startpos; 268 /// Length in bytes of the text being completed (this is deleted to be replaced 269 /// by the match.) 270 static int compl_length = 0; 271 static linenr_T compl_lnum = 0; ///< lnum where the completion start 272 static colnr_T compl_col = 0; ///< column where the text starts 273 ///< that is being completed 274 static colnr_T compl_ins_end_col = 0; 275 static String compl_orig_text = STRING_INIT; ///< text as it was before 276 ///< completion started 277 /// Undo information to restore extmarks for original text. 278 static extmark_undo_vec_t compl_orig_extmarks; 279 static int compl_cont_mode = 0; 280 static expand_T compl_xp; 281 282 static win_T *compl_curr_win = NULL; ///< win where completion is active 283 static buf_T *compl_curr_buf = NULL; ///< buf where completion is active 284 285 #define COMPL_INITIAL_TIMEOUT_MS 80 286 // Autocomplete uses a decaying timeout: starting from COMPL_INITIAL_TIMEOUT_MS, 287 // if the current source exceeds its timeout, it is interrupted and the next 288 // begins with half the time. A small minimum timeout ensures every source 289 // gets at least a brief chance. 290 // Special case: when 'complete' contains "F" or "o" (function sources), a 291 // longer fixed timeout is used (COMPL_FUNC_TIMEOUT_MS or 292 // COMPL_FUNC_TIMEOUT_NON_KW_MS). - girish 293 static bool compl_autocomplete = false; ///< whether autocompletion is active 294 static uint64_t compl_timeout_ms = COMPL_INITIAL_TIMEOUT_MS; 295 static bool compl_time_slice_expired = false; ///< time budget exceeded for current source 296 static bool compl_from_nonkeyword = false; ///< completion started from non-keyword 297 static bool compl_hi_on_autocompl_longest = false; ///< apply "PreInsert" highlight 298 299 // Halve the current completion timeout, simulating exponential decay. 300 #define COMPL_MIN_TIMEOUT_MS 5 301 #define DECAY_COMPL_TIMEOUT() \ 302 do { \ 303 if (compl_timeout_ms > COMPL_MIN_TIMEOUT_MS) { \ 304 compl_timeout_ms /= 2; \ 305 } \ 306 } while (0) 307 308 // Timeout values for F{func}, F and o values in 'complete' 309 #define COMPL_FUNC_TIMEOUT_MS 300 310 #define COMPL_FUNC_TIMEOUT_NON_KW_MS 1000 311 312 // List of flags for method of completion. 313 static int compl_cont_status = 0; 314 #define CONT_ADDING 1 ///< "normal" or "adding" expansion 315 #define CONT_INTRPT (2 + 4) ///< a ^X interrupted the current expansion 316 ///< it's set only iff N_ADDS is set 317 #define CONT_N_ADDS 4 ///< next ^X<> will add-new or expand-current 318 #define CONT_S_IPOS 8 ///< next ^X<> will set initial_pos? 319 ///< if so, word-wise-expansion will set SOL 320 #define CONT_SOL 16 ///< pattern includes start of line, just for 321 ///< word-wise expansion, not set for ^X^L 322 #define CONT_LOCAL 32 ///< for ctrl_x_mode 0, ^X^P/^X^N do a local 323 ///< expansion, (eg use complete=.) 324 325 static bool compl_opt_refresh_always = false; 326 327 static size_t spell_bad_len = 0; // length of located bad word 328 329 static int compl_selected_item = -1; 330 331 static int *compl_fuzzy_scores; 332 333 /// Define the structure for completion source (in 'cpt' option) information 334 typedef struct cpt_source_T { 335 bool cs_refresh_always; ///< Whether 'refresh:always' is set for func 336 int cs_startcol; ///< Start column returned by func 337 int cs_max_matches; ///< Max items to display from this source 338 uint64_t compl_start_tv; ///< Timestamp when match collection starts 339 char cs_flag; ///< Flag indicating the type of source 340 } cpt_source_T; 341 342 /// Pointer to the array of completion sources 343 static cpt_source_T *cpt_sources_array; 344 /// Total number of completion sources specified in the 'cpt' option 345 static int cpt_sources_count; 346 /// Index of the current completion source being expanded 347 static int cpt_sources_index = -1; 348 349 // "compl_match_array" points the currently displayed list of entries in the 350 // popup menu. It is NULL when there is no popup menu. 351 static pumitem_T *compl_match_array = NULL; 352 static int compl_match_arraysize; 353 354 /// CTRL-X pressed in Insert mode. 355 void ins_ctrl_x(void) 356 { 357 if (!ctrl_x_mode_cmdline()) { 358 // if the next ^X<> won't ADD nothing, then reset compl_cont_status 359 if (compl_cont_status & CONT_N_ADDS) { 360 compl_cont_status |= CONT_INTRPT; 361 } else { 362 compl_cont_status = 0; 363 } 364 // We're not sure which CTRL-X mode it will be yet 365 ctrl_x_mode = CTRL_X_NOT_DEFINED_YET; 366 edit_submode = _(CTRL_X_MSG(ctrl_x_mode)); 367 edit_submode_pre = NULL; 368 redraw_mode = true; 369 } else { 370 // CTRL-X in CTRL-X CTRL-V mode behaves differently to make CTRL-X 371 // CTRL-V look like CTRL-N 372 ctrl_x_mode = CTRL_X_CMDLINE_CTRL_X; 373 } 374 375 may_trigger_modechanged(); 376 } 377 378 // Functions to check the current CTRL-X mode. 379 380 bool ctrl_x_mode_none(void) 381 FUNC_ATTR_PURE 382 { 383 return ctrl_x_mode == 0; 384 } 385 386 bool ctrl_x_mode_normal(void) 387 FUNC_ATTR_PURE 388 { 389 return ctrl_x_mode == CTRL_X_NORMAL; 390 } 391 392 bool ctrl_x_mode_scroll(void) 393 FUNC_ATTR_PURE 394 { 395 return ctrl_x_mode == CTRL_X_SCROLL; 396 } 397 398 bool ctrl_x_mode_whole_line(void) 399 FUNC_ATTR_PURE 400 { 401 return ctrl_x_mode == CTRL_X_WHOLE_LINE; 402 } 403 404 bool ctrl_x_mode_files(void) 405 FUNC_ATTR_PURE 406 { 407 return ctrl_x_mode == CTRL_X_FILES; 408 } 409 410 bool ctrl_x_mode_tags(void) 411 FUNC_ATTR_PURE 412 { 413 return ctrl_x_mode == CTRL_X_TAGS; 414 } 415 416 bool ctrl_x_mode_path_patterns(void) 417 FUNC_ATTR_PURE 418 { 419 return ctrl_x_mode == CTRL_X_PATH_PATTERNS; 420 } 421 422 bool ctrl_x_mode_path_defines(void) 423 FUNC_ATTR_PURE 424 { 425 return ctrl_x_mode == CTRL_X_PATH_DEFINES; 426 } 427 428 bool ctrl_x_mode_dictionary(void) 429 FUNC_ATTR_PURE 430 { 431 return ctrl_x_mode == CTRL_X_DICTIONARY; 432 } 433 434 bool ctrl_x_mode_thesaurus(void) 435 FUNC_ATTR_PURE 436 { 437 return ctrl_x_mode == CTRL_X_THESAURUS; 438 } 439 440 bool ctrl_x_mode_cmdline(void) 441 FUNC_ATTR_PURE 442 { 443 return ctrl_x_mode == CTRL_X_CMDLINE || ctrl_x_mode == CTRL_X_CMDLINE_CTRL_X; 444 } 445 446 bool ctrl_x_mode_function(void) 447 FUNC_ATTR_PURE 448 { 449 return ctrl_x_mode == CTRL_X_FUNCTION; 450 } 451 452 bool ctrl_x_mode_omni(void) 453 FUNC_ATTR_PURE 454 { 455 return ctrl_x_mode == CTRL_X_OMNI; 456 } 457 458 bool ctrl_x_mode_spell(void) 459 FUNC_ATTR_PURE 460 { 461 return ctrl_x_mode == CTRL_X_SPELL; 462 } 463 464 static bool ctrl_x_mode_eval(void) 465 FUNC_ATTR_PURE 466 { 467 return ctrl_x_mode == CTRL_X_EVAL; 468 } 469 470 bool ctrl_x_mode_line_or_eval(void) 471 FUNC_ATTR_PURE 472 { 473 return ctrl_x_mode == CTRL_X_WHOLE_LINE || ctrl_x_mode == CTRL_X_EVAL; 474 } 475 476 bool ctrl_x_mode_register(void) 477 FUNC_ATTR_PURE 478 { 479 return ctrl_x_mode == CTRL_X_REGISTER; 480 } 481 482 /// Whether other than default completion has been selected. 483 bool ctrl_x_mode_not_default(void) 484 FUNC_ATTR_PURE 485 { 486 return ctrl_x_mode != CTRL_X_NORMAL; 487 } 488 489 /// Whether CTRL-X was typed without a following character, 490 /// not including when in CTRL-X CTRL-V mode. 491 bool ctrl_x_mode_not_defined_yet(void) 492 FUNC_ATTR_PURE 493 { 494 return ctrl_x_mode == CTRL_X_NOT_DEFINED_YET; 495 } 496 497 /// @return true if currently in "normal" or "adding" insert completion matches state 498 bool compl_status_adding(void) 499 { 500 return compl_cont_status & CONT_ADDING; 501 } 502 503 /// @return true if the completion pattern includes start of line, just for 504 /// word-wise expansion. 505 bool compl_status_sol(void) 506 { 507 return compl_cont_status & CONT_SOL; 508 } 509 510 /// @return true if ^X^P/^X^N will do a local completion (i.e. use complete=.) 511 bool compl_status_local(void) 512 { 513 return compl_cont_status & CONT_LOCAL; 514 } 515 516 /// Clear the completion status flags 517 void compl_status_clear(void) 518 { 519 compl_cont_status = 0; 520 } 521 522 /// @return true if completion is using the forward direction matches 523 static bool compl_dir_forward(void) 524 { 525 return compl_direction == FORWARD; 526 } 527 528 /// @return true if currently showing forward completion matches 529 static bool compl_shows_dir_forward(void) 530 { 531 return compl_shows_dir == FORWARD; 532 } 533 534 /// @return true if currently showing backward completion matches 535 static bool compl_shows_dir_backward(void) 536 { 537 return compl_shows_dir == BACKWARD; 538 } 539 540 /// Check that the 'dictionary' or 'thesaurus' option can be used. 541 /// 542 /// @param dict_opt check 'dictionary' when true, 'thesaurus' when false. 543 bool check_compl_option(bool dict_opt) 544 { 545 if (dict_opt 546 ? (*curbuf->b_p_dict == NUL && *p_dict == NUL && !curwin->w_p_spell) 547 : (*curbuf->b_p_tsr == NUL && *p_tsr == NUL 548 && *curbuf->b_p_tsrfu == NUL && *p_tsrfu == NUL)) { 549 ctrl_x_mode = CTRL_X_NORMAL; 550 edit_submode = NULL; 551 emsg(dict_opt ? _("'dictionary' option is empty") : _("'thesaurus' option is empty")); 552 if (emsg_silent == 0 && !in_assert_fails) { 553 vim_beep(kOptBoFlagComplete); 554 setcursor(); 555 msg_delay(2004, false); 556 } 557 return false; 558 } 559 return true; 560 } 561 562 /// Check that the character "c" a valid key to go to or keep us in CTRL-X mode? 563 /// This depends on the current mode. 564 /// 565 /// @param c character to check 566 bool vim_is_ctrl_x_key(int c) 567 FUNC_ATTR_WARN_UNUSED_RESULT 568 { 569 // Always allow ^R - let its results then be checked 570 if (c == Ctrl_R && ctrl_x_mode != CTRL_X_REGISTER) { 571 return true; 572 } 573 574 // Accept <PageUp> and <PageDown> if the popup menu is visible. 575 if (ins_compl_pum_key(c)) { 576 return true; 577 } 578 579 switch (ctrl_x_mode) { 580 case 0: // Not in any CTRL-X mode 581 return c == Ctrl_N || c == Ctrl_P || c == Ctrl_X; 582 case CTRL_X_NOT_DEFINED_YET: 583 case CTRL_X_CMDLINE_CTRL_X: 584 return c == Ctrl_X || c == Ctrl_Y || c == Ctrl_E 585 || c == Ctrl_L || c == Ctrl_F || c == Ctrl_RSB 586 || c == Ctrl_I || c == Ctrl_D || c == Ctrl_P 587 || c == Ctrl_N || c == Ctrl_T || c == Ctrl_V 588 || c == Ctrl_Q || c == Ctrl_U || c == Ctrl_O 589 || c == Ctrl_S || c == Ctrl_K || c == 's' 590 || c == Ctrl_Z || c == Ctrl_R; 591 case CTRL_X_SCROLL: 592 return c == Ctrl_Y || c == Ctrl_E; 593 case CTRL_X_WHOLE_LINE: 594 return c == Ctrl_L || c == Ctrl_P || c == Ctrl_N; 595 case CTRL_X_FILES: 596 return c == Ctrl_F || c == Ctrl_P || c == Ctrl_N; 597 case CTRL_X_DICTIONARY: 598 return c == Ctrl_K || c == Ctrl_P || c == Ctrl_N; 599 case CTRL_X_THESAURUS: 600 return c == Ctrl_T || c == Ctrl_P || c == Ctrl_N; 601 case CTRL_X_TAGS: 602 return c == Ctrl_RSB || c == Ctrl_P || c == Ctrl_N; 603 case CTRL_X_PATH_PATTERNS: 604 return c == Ctrl_P || c == Ctrl_N; 605 case CTRL_X_PATH_DEFINES: 606 return c == Ctrl_D || c == Ctrl_P || c == Ctrl_N; 607 case CTRL_X_CMDLINE: 608 return c == Ctrl_V || c == Ctrl_Q || c == Ctrl_P || c == Ctrl_N 609 || c == Ctrl_X; 610 case CTRL_X_FUNCTION: 611 return c == Ctrl_U || c == Ctrl_P || c == Ctrl_N; 612 case CTRL_X_OMNI: 613 return c == Ctrl_O || c == Ctrl_P || c == Ctrl_N; 614 case CTRL_X_SPELL: 615 return c == Ctrl_S || c == Ctrl_P || c == Ctrl_N; 616 case CTRL_X_EVAL: 617 return (c == Ctrl_P || c == Ctrl_N); 618 case CTRL_X_BUFNAMES: 619 return (c == Ctrl_P || c == Ctrl_N); 620 case CTRL_X_REGISTER: 621 return (c == Ctrl_R || c == Ctrl_P || c == Ctrl_N); 622 } 623 internal_error("vim_is_ctrl_x_key()"); 624 return false; 625 } 626 627 /// @return true if "match" is the original text when the completion began. 628 static bool match_at_original_text(const compl_T *const match) 629 { 630 return match->cp_flags & CP_ORIGINAL_TEXT; 631 } 632 633 /// @return true if "match" is the first match in the completion list. 634 static bool is_first_match(const compl_T *const match) 635 { 636 return match == compl_first_match; 637 } 638 639 static void do_autocmd_completedone(int c, int mode, char *word) 640 { 641 save_v_event_T save_v_event; 642 dict_T *v_event = get_v_event(&save_v_event); 643 644 mode = mode & ~CTRL_X_WANT_IDENT; 645 char *mode_str = NULL; 646 if (ctrl_x_mode_names[mode]) { 647 mode_str = ctrl_x_mode_names[mode]; 648 } 649 tv_dict_add_str(v_event, S_LEN("complete_word"), word != NULL ? word : ""); 650 tv_dict_add_str(v_event, S_LEN("complete_type"), mode_str != NULL ? mode_str : ""); 651 652 tv_dict_add_str(v_event, S_LEN("reason"), 653 (c == Ctrl_Y ? "accept" : (c == Ctrl_E ? "cancel" : "discard"))); 654 tv_dict_set_keys_readonly(v_event); 655 656 ins_apply_autocmds(EVENT_COMPLETEDONE); 657 restore_v_event(v_event, &save_v_event); 658 } 659 660 /// Check that character "c" is part of the item currently being 661 /// completed. Used to decide whether to abandon complete mode when the menu 662 /// is visible. 663 /// 664 /// @param c character to check 665 bool ins_compl_accept_char(int c) 666 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT 667 { 668 if (compl_autocomplete && compl_from_nonkeyword) { 669 return false; 670 } 671 672 if (ctrl_x_mode & CTRL_X_WANT_IDENT) { 673 // When expanding an identifier only accept identifier chars. 674 return vim_isIDc(c); 675 } 676 677 switch (ctrl_x_mode) { 678 case CTRL_X_FILES: 679 // When expanding file name only accept file name chars. But not 680 // path separators, so that "proto/<Tab>" expands files in 681 // "proto", not "proto/" as a whole 682 return vim_isfilec(c) && !vim_ispathsep(c); 683 684 case CTRL_X_CMDLINE: 685 case CTRL_X_CMDLINE_CTRL_X: 686 case CTRL_X_OMNI: 687 // Command line and Omni completion can work with just about any 688 // printable character, but do stop at white space. 689 return vim_isprintc(c) && !ascii_iswhite(c); 690 691 case CTRL_X_WHOLE_LINE: 692 // For while line completion a space can be part of the line. 693 return vim_isprintc(c); 694 } 695 return vim_iswordc(c); 696 } 697 698 /// Get the completed text by inferring the case of the originally typed text. 699 /// If the result is in allocated memory "tofree" is set to it. 700 static char *ins_compl_infercase_gettext(const char *str, int char_len, int compl_char_len, 701 int min_len, char **tofree) 702 { 703 bool has_lower = false; 704 705 // Allocate wide character array for the completion and fill it. 706 int *const wca = xmalloc((size_t)char_len * sizeof(*wca)); 707 { 708 const char *p = str; 709 for (int i = 0; i < char_len; i++) { 710 wca[i] = mb_ptr2char_adv(&p); 711 } 712 } 713 714 // Rule 1: Were any chars converted to lower? 715 { 716 const char *p = compl_orig_text.data; 717 for (int i = 0; i < min_len; i++) { 718 const int c = mb_ptr2char_adv(&p); 719 if (mb_islower(c)) { 720 has_lower = true; 721 if (mb_isupper(wca[i])) { 722 // Rule 1 is satisfied. 723 for (i = compl_char_len; i < char_len; i++) { 724 wca[i] = mb_tolower(wca[i]); 725 } 726 break; 727 } 728 } 729 } 730 } 731 732 // Rule 2: No lower case, 2nd consecutive letter converted to 733 // upper case. 734 if (!has_lower) { 735 bool was_letter = false; 736 const char *p = compl_orig_text.data; 737 for (int i = 0; i < min_len; i++) { 738 const int c = mb_ptr2char_adv(&p); 739 if (was_letter && mb_isupper(c) && mb_islower(wca[i])) { 740 // Rule 2 is satisfied. 741 for (i = compl_char_len; i < char_len; i++) { 742 wca[i] = mb_toupper(wca[i]); 743 } 744 break; 745 } 746 was_letter = mb_islower(c) || mb_isupper(c); 747 } 748 } 749 750 // Copy the original case of the part we typed. 751 { 752 const char *p = compl_orig_text.data; 753 for (int i = 0; i < min_len; i++) { 754 const int c = mb_ptr2char_adv(&p); 755 if (mb_islower(c)) { 756 wca[i] = mb_tolower(wca[i]); 757 } else if (mb_isupper(c)) { 758 wca[i] = mb_toupper(wca[i]); 759 } 760 } 761 } 762 763 // Generate encoding specific output from wide character array. 764 garray_T gap; 765 char *p = IObuff; 766 int i = 0; 767 ga_init(&gap, 1, 500); 768 while (i < char_len) { 769 if (gap.ga_data != NULL) { 770 ga_grow(&gap, 10); 771 assert(gap.ga_data != NULL); // suppress clang "Dereference of NULL pointer" 772 p = (char *)gap.ga_data + gap.ga_len; 773 gap.ga_len += utf_char2bytes(wca[i++], p); 774 } else if ((p - IObuff) + 6 >= IOSIZE) { 775 // Multi-byte characters can occupy up to five bytes more than 776 // ASCII characters, and we also need one byte for NUL, so when 777 // getting to six bytes from the edge of IObuff switch to using a 778 // growarray. Add the character in the next round. 779 ga_grow(&gap, IOSIZE); 780 *p = NUL; 781 STRCPY(gap.ga_data, IObuff); 782 gap.ga_len = (int)(p - IObuff); 783 } else { 784 p += utf_char2bytes(wca[i++], p); 785 } 786 } 787 xfree(wca); 788 789 if (gap.ga_data != NULL) { 790 *tofree = gap.ga_data; 791 return gap.ga_data; 792 } 793 794 *p = NUL; 795 return IObuff; 796 } 797 798 /// This is like ins_compl_add(), but if 'ic' and 'inf' are set, then the 799 /// case of the originally typed text is used, and the case of the completed 800 /// text is inferred, ie this tries to work out what case you probably wanted 801 /// the rest of the word to be in -- webb 802 /// 803 /// @param[in] cont_s_ipos next ^X<> will set initial_pos 804 int ins_compl_add_infercase(char *str_arg, int len, bool icase, char *fname, Direction dir, 805 bool cont_s_ipos, int score) 806 FUNC_ATTR_NONNULL_ARG(1) 807 { 808 char *str = str_arg; 809 int char_len; // count multi-byte characters 810 int compl_char_len; 811 int flags = 0; 812 char *tofree = NULL; 813 814 if (p_ic && curbuf->b_p_inf && len > 0) { 815 // Infer case of completed part. 816 817 // Find actual length of completion. 818 { 819 const char *p = str; 820 char_len = 0; 821 while (*p != NUL) { 822 MB_PTR_ADV(p); 823 char_len++; 824 } 825 } 826 827 // Find actual length of original text. 828 { 829 const char *p = compl_orig_text.data; 830 compl_char_len = 0; 831 while (*p != NUL) { 832 MB_PTR_ADV(p); 833 compl_char_len++; 834 } 835 } 836 837 // "char_len" may be smaller than "compl_char_len" when using 838 // thesaurus, only use the minimum when comparing. 839 int min_len = MIN(char_len, compl_char_len); 840 841 str = ins_compl_infercase_gettext(str, char_len, compl_char_len, min_len, &tofree); 842 } 843 if (cont_s_ipos) { 844 flags |= CP_CONT_S_IPOS; 845 } 846 if (icase) { 847 flags |= CP_ICASE; 848 } 849 850 int res = ins_compl_add(str, len, fname, NULL, false, NULL, dir, flags, false, NULL, score); 851 xfree(tofree); 852 return res; 853 } 854 855 /// free cptext 856 static inline void free_cptext(char *const *const cptext) 857 { 858 if (cptext != NULL) { 859 for (size_t i = 0; i < CPT_COUNT; i++) { 860 xfree(cptext[i]); 861 } 862 } 863 } 864 865 /// Check if fuzzy matching is enabled 866 static bool cot_fuzzy(void) 867 { 868 return (get_cot_flags() & kOptCotFlagFuzzy) != 0 && !ctrl_x_mode_thesaurus(); 869 } 870 871 /// Returns true if matches should be sorted based on proximity to the cursor. 872 static bool is_nearest_active(void) 873 { 874 return (compl_autocomplete || (get_cot_flags() & kOptCotFlagNearest)) 875 && !cot_fuzzy(); 876 } 877 878 /// True if a match is selected (even if it is not inserted). 879 bool ins_compl_is_match_selected(void) 880 { 881 return compl_shown_match != NULL && !is_first_match(compl_shown_match); 882 } 883 884 /// Returns true if autocomplete is active and the pre-insert effect targets the 885 /// longest prefix. 886 bool ins_compl_preinsert_longest(void) 887 { 888 return compl_autocomplete 889 && (get_cot_flags() & (kOptCotFlagLongest | kOptCotFlagPreinsert | kOptCotFlagFuzzy)) 890 == kOptCotFlagLongest; 891 } 892 893 /// Add a match to the list of matches 894 /// 895 /// @param[in] str text of the match to add 896 /// @param[in] len length of "str". If -1, then the length of "str" is computed. 897 /// @param[in] fname file name to associate with this match. May be NULL. 898 /// @param[in] cptext list of strings to use with this match (for abbr, menu, info 899 /// and kind). May be NULL. 900 /// If not NULL, must have exactly #CPT_COUNT items. 901 /// @param[in] cptext_allocated If true, will not copy cptext strings. 902 /// 903 /// @note Will free strings in case of error. 904 /// cptext itself will not be freed. 905 /// @param[in] user_data user supplied data (any vim type) for this match 906 /// @param[in] cdir match direction. If 0, use "compl_direction". 907 /// @param[in] flags_arg match flags (cp_flags) 908 /// @param[in] adup accept this match even if it is already present. 909 /// @param[in] user_hl list of extra highlight attributes for abbr kind. 910 /// 911 /// If "cdir" is FORWARD, then the match is added after the current match. 912 /// Otherwise, it is added before the current match. 913 /// 914 /// @return NOTDONE if the given string is already in the list of completions, 915 /// otherwise it is added to the list and OK is returned. FAIL will be 916 /// returned in case of error. 917 static int ins_compl_add(char *const str, int len, char *const fname, char *const *const cptext, 918 const bool cptext_allocated, typval_T *user_data, const Direction cdir, 919 int flags_arg, const bool adup, const int *user_hl, const int score) 920 FUNC_ATTR_NONNULL_ARG(1) 921 { 922 compl_T *match; 923 const Direction dir = (cdir == kDirectionNotSet ? compl_direction : cdir); 924 int flags = flags_arg; 925 bool inserted = false; 926 927 if (flags & CP_FAST) { 928 fast_breakcheck(); 929 } else { 930 os_breakcheck(); 931 } 932 if (got_int) { 933 if (cptext_allocated) { 934 free_cptext(cptext); 935 } 936 return FAIL; 937 } 938 if (len < 0) { 939 len = (int)strlen(str); 940 } 941 942 // If the same match is already present, don't add it. 943 if (compl_first_match != NULL && !adup) { 944 match = compl_first_match; 945 do { 946 if (!match_at_original_text(match) 947 && strncmp(match->cp_str.data, str, (size_t)len) == 0 948 && ((int)match->cp_str.size <= len || match->cp_str.data[len] == NUL)) { 949 if (is_nearest_active() && score > 0 && score < match->cp_score) { 950 match->cp_score = score; 951 } 952 if (cptext_allocated) { 953 free_cptext(cptext); 954 } 955 return NOTDONE; 956 } 957 match = match->cp_next; 958 } while (match != NULL && !is_first_match(match)); 959 } 960 961 // Remove any popup menu before changing the list of matches. 962 ins_compl_del_pum(); 963 964 // Allocate a new match structure. 965 // Copy the values to the new match structure. 966 match = xcalloc(1, sizeof(compl_T)); 967 match->cp_number = flags & CP_ORIGINAL_TEXT ? 0 : -1; 968 match->cp_str = cbuf_to_string(str, (size_t)len); 969 970 // match-fname is: 971 // - compl_curr_match->cp_fname if it is a string equal to fname. 972 // - a copy of fname, CP_FREE_FNAME is set to free later THE allocated mem. 973 // - NULL otherwise. --Acevedo 974 if (fname != NULL 975 && compl_curr_match != NULL 976 && compl_curr_match->cp_fname != NULL 977 && strcmp(fname, compl_curr_match->cp_fname) == 0) { 978 match->cp_fname = compl_curr_match->cp_fname; 979 } else if (fname != NULL) { 980 match->cp_fname = xstrdup(fname); 981 flags |= CP_FREE_FNAME; 982 } else { 983 match->cp_fname = NULL; 984 } 985 match->cp_flags = flags; 986 match->cp_user_abbr_hlattr = user_hl ? user_hl[0] : -1; 987 match->cp_user_kind_hlattr = user_hl ? user_hl[1] : -1; 988 match->cp_score = score; 989 match->cp_cpt_source_idx = cpt_sources_index; 990 991 if (cptext != NULL) { 992 for (int i = 0; i < CPT_COUNT; i++) { 993 if (cptext[i] == NULL) { 994 continue; 995 } 996 if (*cptext[i] != NUL) { 997 match->cp_text[i] = (cptext_allocated ? cptext[i] : xstrdup(cptext[i])); 998 } else if (cptext_allocated) { 999 xfree(cptext[i]); 1000 } 1001 } 1002 } 1003 1004 if (user_data != NULL) { 1005 match->cp_user_data = *user_data; 1006 } 1007 1008 // Link the new match structure after (FORWARD) or before (BACKWARD) the 1009 // current match in the list of matches . 1010 if (compl_first_match == NULL) { 1011 match->cp_next = match->cp_prev = NULL; 1012 } else if (cot_fuzzy() && score != FUZZY_SCORE_NONE && compl_get_longest) { 1013 compl_T *current = compl_first_match->cp_next; 1014 compl_T *prev = compl_first_match; 1015 inserted = false; 1016 // The direction is ignored when using longest and fuzzy match, because 1017 // matches are inserted and sorted by score. 1018 while (current != NULL && current != compl_first_match) { 1019 if (current->cp_score < score) { 1020 match->cp_next = current; 1021 match->cp_prev = current->cp_prev; 1022 if (current->cp_prev) { 1023 current->cp_prev->cp_next = match; 1024 } 1025 current->cp_prev = match; 1026 inserted = true; 1027 break; 1028 } 1029 prev = current; 1030 current = current->cp_next; 1031 } 1032 if (!inserted) { 1033 prev->cp_next = match; 1034 match->cp_prev = prev; 1035 match->cp_next = compl_first_match; 1036 compl_first_match->cp_prev = match; 1037 } 1038 } else if (dir == FORWARD) { 1039 match->cp_next = compl_curr_match->cp_next; 1040 match->cp_prev = compl_curr_match; 1041 } else { // BACKWARD 1042 match->cp_next = compl_curr_match; 1043 match->cp_prev = compl_curr_match->cp_prev; 1044 } 1045 if (match->cp_next) { 1046 match->cp_next->cp_prev = match; 1047 } 1048 if (match->cp_prev) { 1049 match->cp_prev->cp_next = match; 1050 } else { // if there's nothing before, it is the first match 1051 compl_first_match = match; 1052 } 1053 compl_curr_match = match; 1054 1055 // Find the longest common string if still doing that. 1056 if (compl_get_longest && (flags & CP_ORIGINAL_TEXT) == 0 && !cot_fuzzy() 1057 && !ins_compl_preinsert_longest() && !ctrl_x_mode_thesaurus()) { 1058 ins_compl_longest_match(match); 1059 } 1060 1061 return OK; 1062 } 1063 1064 /// Check that "str[len]" matches with "match->cp_str", considering 1065 /// "match->cp_flags". 1066 /// 1067 /// @param match completion match 1068 /// @param str character string to check 1069 /// @param len length of "str" 1070 static bool ins_compl_equal(compl_T *match, char *str, size_t len) 1071 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL 1072 { 1073 if (match->cp_flags & CP_EQUAL) { 1074 return true; 1075 } 1076 if (match->cp_flags & CP_ICASE) { 1077 return STRNICMP(match->cp_str.data, str, len) == 0; 1078 } 1079 return strncmp(match->cp_str.data, str, len) == 0; 1080 } 1081 1082 /// when len is -1 mean use whole length of p otherwise part of p 1083 static void ins_compl_insert_bytes(char *p, int len) 1084 FUNC_ATTR_NONNULL_ALL 1085 { 1086 if (len == -1) { 1087 len = (int)strlen(p); 1088 } 1089 assert(len >= 0); 1090 ins_bytes_len(p, (size_t)len); 1091 compl_ins_end_col = curwin->w_cursor.col; 1092 } 1093 1094 /// Get current completion leader 1095 char *ins_compl_leader(void) 1096 { 1097 return compl_leader.data != NULL ? compl_leader.data : compl_orig_text.data; 1098 } 1099 1100 /// Get current completion leader length 1101 static size_t ins_compl_leader_len(void) 1102 { 1103 return compl_leader.data != NULL ? compl_leader.size : compl_orig_text.size; 1104 } 1105 1106 /// Checks if the column is within the currently inserted completion text 1107 /// column range. If it is, it returns a special highlight attribute. 1108 /// -1 means normal item. 1109 int ins_compl_col_range_attr(linenr_T lnum, int col) 1110 { 1111 const bool has_preinsert = ins_compl_has_preinsert() || ins_compl_preinsert_longest(); 1112 1113 int attr; 1114 if (cot_fuzzy() 1115 || (!compl_hi_on_autocompl_longest && ins_compl_preinsert_longest()) 1116 || (attr = syn_name2attr(has_preinsert ? "PreInsert" : "ComplMatchIns")) == 0) { 1117 return -1; 1118 } 1119 1120 int start_col = compl_col + (int)ins_compl_leader_len(); 1121 if (!ins_compl_has_multiple()) { 1122 return (col >= start_col && col < compl_ins_end_col) ? attr : -1; 1123 } 1124 1125 // Multiple lines 1126 if ((lnum == compl_lnum && col >= start_col && col < MAXCOL) 1127 || (lnum > compl_lnum && lnum < curwin->w_cursor.lnum) 1128 || (lnum == curwin->w_cursor.lnum && col <= compl_ins_end_col)) { 1129 return attr; 1130 } 1131 1132 return -1; 1133 } 1134 1135 /// Returns true if the current completion string contains newline characters, 1136 /// indicating it's a multi-line completion. 1137 static bool ins_compl_has_multiple(void) 1138 { 1139 return vim_strchr(compl_shown_match->cp_str.data, '\n') != NULL; 1140 } 1141 1142 /// Returns true if the given line number falls within the range of a multi-line 1143 /// completion, i.e. between the starting line (compl_lnum) and current cursor 1144 /// line. Always returns false for single-line completions. 1145 bool ins_compl_lnum_in_range(linenr_T lnum) 1146 { 1147 if (!ins_compl_has_multiple()) { 1148 return false; 1149 } 1150 return lnum >= compl_lnum && lnum <= curwin->w_cursor.lnum; 1151 } 1152 1153 /// Reduce the longest common string for match "match". 1154 static void ins_compl_longest_match(compl_T *match) 1155 { 1156 if (compl_leader.data == NULL) { 1157 // First match, use it as a whole. 1158 compl_leader = copy_string(match->cp_str, NULL); 1159 1160 bool had_match = (curwin->w_cursor.col > compl_col); 1161 ins_compl_longest_insert(compl_leader.data); 1162 1163 // When the match isn't there (to avoid matching itself) remove it 1164 // again after redrawing. 1165 if (!had_match) { 1166 ins_compl_delete(false); 1167 } 1168 compl_used_match = false; 1169 1170 return; 1171 } 1172 1173 // Reduce the text if this match differs from compl_leader. 1174 char *p = compl_leader.data; 1175 char *s = match->cp_str.data; 1176 while (*p != NUL) { 1177 int c1 = utf_ptr2char(p); 1178 int c2 = utf_ptr2char(s); 1179 1180 if ((match->cp_flags & CP_ICASE) 1181 ? (mb_tolower(c1) != mb_tolower(c2)) 1182 : (c1 != c2)) { 1183 break; 1184 } 1185 MB_PTR_ADV(p); 1186 MB_PTR_ADV(s); 1187 } 1188 1189 if (*p != NUL) { 1190 // Leader was shortened, need to change the inserted text. 1191 *p = NUL; 1192 compl_leader.size = (size_t)(p - compl_leader.data); 1193 1194 bool had_match = (curwin->w_cursor.col > compl_col); 1195 ins_compl_longest_insert(compl_leader.data); 1196 1197 // When the match isn't there (to avoid matching itself) remove it 1198 // again after redrawing. 1199 if (!had_match) { 1200 ins_compl_delete(false); 1201 } 1202 } 1203 1204 compl_used_match = false; 1205 } 1206 1207 /// Add an array of matches to the list of matches. 1208 /// Frees matches[]. 1209 static void ins_compl_add_matches(int num_matches, char **matches, int icase) 1210 { 1211 int add_r = OK; 1212 Direction dir = compl_direction; 1213 1214 for (int i = 0; i < num_matches && add_r != FAIL; i++) { 1215 add_r = ins_compl_add(matches[i], -1, NULL, NULL, false, NULL, dir, 1216 CP_FAST | (icase ? CP_ICASE : 0), false, NULL, 1217 FUZZY_SCORE_NONE); 1218 if (add_r == OK) { 1219 // If dir was BACKWARD then honor it just once. 1220 dir = FORWARD; 1221 } 1222 } 1223 FreeWild(num_matches, matches); 1224 } 1225 1226 /// Make the completion list cyclic. 1227 /// Return the number of matches (excluding the original). 1228 static int ins_compl_make_cyclic(void) 1229 { 1230 if (compl_first_match == NULL) { 1231 return 0; 1232 } 1233 1234 // Find the end of the list. 1235 compl_T *match = compl_first_match; 1236 int count = 0; 1237 // there's always an entry for the compl_orig_text, it doesn't count. 1238 while (match->cp_next != NULL && !is_first_match(match->cp_next)) { 1239 match = match->cp_next; 1240 count++; 1241 } 1242 match->cp_next = compl_first_match; 1243 compl_first_match->cp_prev = match; 1244 1245 return count; 1246 } 1247 1248 /// Return whether there currently is a shown match. 1249 bool ins_compl_has_shown_match(void) 1250 { 1251 return compl_shown_match == NULL || compl_shown_match != compl_shown_match->cp_next; 1252 } 1253 1254 /// Return whether the shown match is long enough. 1255 bool ins_compl_long_shown_match(void) 1256 { 1257 return compl_shown_match != NULL && compl_shown_match->cp_str.data != NULL 1258 && (colnr_T)compl_shown_match->cp_str.size > curwin->w_cursor.col - compl_col; 1259 } 1260 1261 /// Get the local or global value of 'completeopt' flags. 1262 unsigned get_cot_flags(void) 1263 { 1264 return curbuf->b_cot_flags != 0 ? curbuf->b_cot_flags : cot_flags; 1265 } 1266 1267 /// Remove any popup menu. 1268 static void ins_compl_del_pum(void) 1269 { 1270 if (compl_match_array == NULL) { 1271 return; 1272 } 1273 1274 pum_undisplay(false); 1275 XFREE_CLEAR(compl_match_array); 1276 } 1277 1278 /// Check if the popup menu should be displayed. 1279 bool pum_wanted(void) 1280 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT 1281 { 1282 // "completeopt" must contain "menu" or "menuone" 1283 return (get_cot_flags() & (kOptCotFlagMenu | kOptCotFlagMenuone)) != 0 || compl_autocomplete; 1284 } 1285 1286 /// Check that there are two or more matches to be shown in the popup menu. 1287 /// One if "completopt" contains "menuone". 1288 static bool pum_enough_matches(void) 1289 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT 1290 { 1291 // Don't display the popup menu if there are no matches or there is only 1292 // one (ignoring the original text). 1293 compl_T *comp = compl_first_match; 1294 int i = 0; 1295 do { 1296 if (comp == NULL || (!match_at_original_text(comp) && ++i == 2)) { 1297 break; 1298 } 1299 comp = comp->cp_next; 1300 } while (!is_first_match(comp)); 1301 1302 if ((get_cot_flags() & kOptCotFlagMenuone) || compl_autocomplete) { 1303 return i >= 1; 1304 } 1305 return i >= 2; 1306 } 1307 1308 /// Convert to complete item dict 1309 static dict_T *ins_compl_dict_alloc(compl_T *match) 1310 { 1311 // { word, abbr, menu, kind, info } 1312 dict_T *dict = tv_dict_alloc_lock(VAR_FIXED); 1313 tv_dict_add_str(dict, S_LEN("word"), match->cp_str.data); 1314 tv_dict_add_str(dict, S_LEN("abbr"), match->cp_text[CPT_ABBR]); 1315 tv_dict_add_str(dict, S_LEN("menu"), match->cp_text[CPT_MENU]); 1316 tv_dict_add_str(dict, S_LEN("kind"), match->cp_text[CPT_KIND]); 1317 tv_dict_add_str(dict, S_LEN("info"), match->cp_text[CPT_INFO]); 1318 if (match->cp_user_data.v_type == VAR_UNKNOWN) { 1319 tv_dict_add_str(dict, S_LEN("user_data"), ""); 1320 } else { 1321 tv_dict_add_tv(dict, S_LEN("user_data"), &match->cp_user_data); 1322 } 1323 return dict; 1324 } 1325 1326 /// Trigger the CompleteChanged autocmd event. Invoked each time the Insert mode 1327 /// completion menu is changed. 1328 static void trigger_complete_changed_event(int cur) 1329 { 1330 static bool recursive = false; 1331 save_v_event_T save_v_event; 1332 1333 if (recursive) { 1334 return; 1335 } 1336 1337 dict_T *item = cur < 0 ? tv_dict_alloc() : ins_compl_dict_alloc(compl_curr_match); 1338 dict_T *v_event = get_v_event(&save_v_event); 1339 tv_dict_add_dict(v_event, S_LEN("completed_item"), item); 1340 pum_set_event_info(v_event); 1341 tv_dict_set_keys_readonly(v_event); 1342 1343 recursive = true; 1344 textlock++; 1345 apply_autocmds(EVENT_COMPLETECHANGED, NULL, NULL, false, curbuf); 1346 textlock--; 1347 recursive = false; 1348 1349 restore_v_event(v_event, &save_v_event); 1350 } 1351 1352 // Helper functions for mergesort_list(). 1353 1354 static void *cp_get_next(void *node) 1355 { 1356 return ((compl_T *)node)->cp_next; 1357 } 1358 1359 static void cp_set_next(void *node, void *next) 1360 { 1361 ((compl_T *)node)->cp_next = (compl_T *)next; 1362 } 1363 1364 static void *cp_get_prev(void *node) 1365 { 1366 return ((compl_T *)node)->cp_prev; 1367 } 1368 1369 static void cp_set_prev(void *node, void *prev) 1370 { 1371 ((compl_T *)node)->cp_prev = (compl_T *)prev; 1372 } 1373 1374 static int cp_compare_fuzzy(const void *a, const void *b) 1375 { 1376 int score_a = ((compl_T *)a)->cp_score; 1377 int score_b = ((compl_T *)b)->cp_score; 1378 return (score_b > score_a) ? 1 : (score_b < score_a) ? -1 : 0; 1379 } 1380 1381 static int cp_compare_nearest(const void *a, const void *b) 1382 { 1383 int score_a = ((compl_T *)a)->cp_score; 1384 int score_b = ((compl_T *)b)->cp_score; 1385 if (score_a == FUZZY_SCORE_NONE || score_b == FUZZY_SCORE_NONE) { 1386 return 0; 1387 } 1388 return (score_a > score_b) ? 1 : (score_a < score_b) ? -1 : 0; 1389 } 1390 1391 /// Constructs a new string by prepending text from the current line (from 1392 /// startcol to compl_col) to the given source string. Stores the result in 1393 /// dest. 1394 static void prepend_startcol_text(String *dest, String *src, int startcol) 1395 { 1396 int prepend_len = compl_col - startcol; 1397 int new_length = prepend_len + (int)src->size; 1398 1399 dest->size = (size_t)new_length; 1400 dest->data = xmalloc((size_t)new_length + 1); // +1 for NUL 1401 1402 char *line = ml_get(curwin->w_cursor.lnum); 1403 1404 memmove(dest->data, line + startcol, (size_t)prepend_len); 1405 memmove(dest->data + prepend_len, src->data, src->size); 1406 dest->data[new_length] = NUL; 1407 } 1408 1409 /// Returns the completion leader string adjusted for a specific source's 1410 /// startcol. If the source's startcol is before compl_col, prepends text from 1411 /// the buffer line to the original compl_leader. 1412 static String *get_leader_for_startcol(compl_T *match, bool cached) 1413 { 1414 static String adjusted_leader = STRING_INIT; 1415 1416 if (match == NULL) { 1417 API_CLEAR_STRING(adjusted_leader); 1418 return NULL; 1419 } 1420 1421 if (cpt_sources_array == NULL) { 1422 goto theend; 1423 } 1424 1425 int cpt_idx = match->cp_cpt_source_idx; 1426 if (cpt_idx < 0) { 1427 goto theend; 1428 } 1429 int startcol = cpt_sources_array[cpt_idx].cs_startcol; 1430 1431 if (compl_leader.data == NULL) { 1432 // When leader is not set (e.g. 'autocomplete' first fires before 1433 // compl_leader is initialised), fall back to compl_orig_text for 1434 // matches starting at or after compl_col. Matches starting before 1435 // compl_col carry pre-compl_col text and must not be compared with 1436 // compl_orig_text, so return &compl_leader (NULL string) to signal 1437 // "pass through" (no prefix filter). 1438 if (startcol < 0 || startcol >= compl_col) { 1439 return &compl_orig_text; 1440 } 1441 return &compl_leader; // pass through (startcol < compl_col) 1442 } 1443 1444 if (compl_col <= 0) { 1445 goto theend; 1446 } 1447 1448 if (startcol >= 0 && startcol < compl_col) { 1449 int prepend_len = compl_col - startcol; 1450 int new_length = prepend_len + (int)compl_leader.size; 1451 if (cached && (size_t)new_length == adjusted_leader.size 1452 && adjusted_leader.data != NULL) { 1453 return &adjusted_leader; 1454 } 1455 1456 API_CLEAR_STRING(adjusted_leader); 1457 prepend_startcol_text(&adjusted_leader, &compl_leader, startcol); 1458 return &adjusted_leader; 1459 } 1460 theend: 1461 return &compl_leader; 1462 } 1463 1464 /// Set fuzzy score for completion matches. 1465 static void set_fuzzy_score(void) 1466 { 1467 if (compl_first_match == NULL) { 1468 return; 1469 } 1470 1471 // Determine the pattern to match against 1472 bool use_leader = (compl_leader.data != NULL && compl_leader.size > 0); 1473 char *pattern; 1474 if (!use_leader) { 1475 if (compl_orig_text.data == NULL || compl_orig_text.size == 0) { 1476 return; 1477 } 1478 pattern = compl_orig_text.data; 1479 } else { 1480 // Clear the leader cache once before the loop 1481 (void)get_leader_for_startcol(NULL, true); 1482 pattern = NULL; // Will be computed per-completion 1483 } 1484 1485 // Score all completion matches 1486 compl_T *comp = compl_first_match; 1487 do { 1488 if (use_leader) { 1489 pattern = get_leader_for_startcol(comp, true)->data; 1490 } 1491 1492 comp->cp_score = fuzzy_match_str(comp->cp_str.data, pattern); 1493 comp = comp->cp_next; 1494 } while (comp != NULL && !is_first_match(comp)); 1495 } 1496 1497 /// Sort completion matches, excluding the node that contains the leader. 1498 static void sort_compl_match_list(MergeSortCompareFunc compare) 1499 { 1500 if (!compl_first_match || is_first_match(compl_first_match->cp_next)) { 1501 return; 1502 } 1503 1504 compl_T *comp = compl_first_match->cp_prev; 1505 ins_compl_make_linear(); 1506 if (compl_shows_dir_forward()) { 1507 compl_first_match->cp_next->cp_prev = NULL; 1508 compl_first_match->cp_next = mergesort_list(compl_first_match->cp_next, 1509 cp_get_next, cp_set_next, 1510 cp_get_prev, cp_set_prev, 1511 compare); 1512 compl_first_match->cp_next->cp_prev = compl_first_match; 1513 } else { 1514 comp->cp_prev->cp_next = NULL; 1515 compl_first_match = mergesort_list(compl_first_match, cp_get_next, cp_set_next, 1516 cp_get_prev, cp_set_prev, compare); 1517 compl_T *tail = compl_first_match; 1518 while (tail->cp_next != NULL) { 1519 tail = tail->cp_next; 1520 } 1521 tail->cp_next = comp; 1522 comp->cp_prev = tail; 1523 } 1524 (void)ins_compl_make_cyclic(); 1525 } 1526 1527 /// Build a popup menu to show the completion matches. 1528 /// 1529 /// @return the popup menu entry that should be selected, 1530 /// -1 if nothing should be selected. 1531 static int ins_compl_build_pum(void) 1532 { 1533 // Need to build the popup menu list. 1534 compl_match_arraysize = 0; 1535 1536 // If it's user complete function and refresh_always, 1537 // do not use "compl_leader" as prefix filter. 1538 if (ins_compl_need_restart()) { 1539 XFREE_CLEAR(compl_leader); 1540 } 1541 1542 bool compl_no_select = (get_cot_flags() & kOptCotFlagNoselect) != 0 1543 || (compl_autocomplete && !ins_compl_has_preinsert()); 1544 1545 compl_T *match_head = NULL, *match_tail = NULL; 1546 int *match_count = NULL; 1547 bool is_forward = compl_shows_dir_forward(); 1548 bool is_cpt_completion = (cpt_sources_array != NULL); 1549 1550 // If the current match is the original text don't find the first 1551 // match after it, don't highlight anything. 1552 bool shown_match_ok = match_at_original_text(compl_shown_match); 1553 1554 if (strequal(compl_leader.data, compl_orig_text.data) && !shown_match_ok) { 1555 compl_shown_match = compl_no_select ? compl_first_match : compl_first_match->cp_next; 1556 } 1557 1558 bool did_find_shown_match = false; 1559 compl_T *comp; 1560 compl_T *shown_compl = NULL; 1561 int i = 0; 1562 int cur = -1; 1563 1564 if (is_cpt_completion) { 1565 match_count = xcalloc((size_t)cpt_sources_count, sizeof(int)); 1566 } 1567 1568 (void)get_leader_for_startcol(NULL, true); // Clear the cache 1569 1570 comp = compl_first_match; 1571 do { 1572 comp->cp_in_match_array = false; 1573 1574 String *leader = get_leader_for_startcol(comp, true); 1575 1576 // Apply 'smartcase' behavior during normal mode 1577 if (ctrl_x_mode_normal() && !p_inf && leader->data 1578 && !ignorecase(leader->data) && !cot_fuzzy()) { 1579 comp->cp_flags &= ~CP_ICASE; 1580 } 1581 1582 if (!match_at_original_text(comp) 1583 && (leader->data == NULL 1584 || ins_compl_equal(comp, leader->data, leader->size) 1585 || (cot_fuzzy() && comp->cp_score != FUZZY_SCORE_NONE))) { 1586 // Limit number of items from each source if max_items is set. 1587 bool match_limit_exceeded = false; 1588 int cur_source = comp->cp_cpt_source_idx; 1589 if (is_forward && cur_source != -1 && is_cpt_completion) { 1590 match_count[cur_source]++; 1591 int max_matches = cpt_sources_array[cur_source].cs_max_matches; 1592 if (max_matches > 0 && match_count[cur_source] > max_matches) { 1593 match_limit_exceeded = true; 1594 } 1595 } 1596 1597 if (!match_limit_exceeded) { 1598 compl_match_arraysize++; 1599 comp->cp_in_match_array = true; 1600 if (match_head == NULL) { 1601 match_head = comp; 1602 } else { 1603 match_tail->cp_match_next = comp; 1604 } 1605 match_tail = comp; 1606 1607 if (!shown_match_ok && !cot_fuzzy()) { 1608 if (comp == compl_shown_match || did_find_shown_match) { 1609 // This item is the shown match or this is the 1610 // first displayed item after the shown match. 1611 compl_shown_match = comp; 1612 did_find_shown_match = true; 1613 shown_match_ok = true; 1614 } else { 1615 // Remember this displayed match for when the 1616 // shown match is just below it. 1617 shown_compl = comp; 1618 } 1619 cur = i; 1620 } else if (cot_fuzzy()) { 1621 if (i == 0) { 1622 shown_compl = comp; 1623 } 1624 1625 if (!shown_match_ok && comp == compl_shown_match) { 1626 cur = i; 1627 shown_match_ok = true; 1628 } 1629 } 1630 i++; 1631 } 1632 } 1633 1634 if (comp == compl_shown_match && !cot_fuzzy()) { 1635 did_find_shown_match = true; 1636 // When the original text is the shown match don't set 1637 // compl_shown_match. 1638 if (match_at_original_text(comp)) { 1639 shown_match_ok = true; 1640 } 1641 if (!shown_match_ok && shown_compl != NULL) { 1642 // The shown match isn't displayed, set it to the 1643 // previously displayed match. 1644 compl_shown_match = shown_compl; 1645 shown_match_ok = true; 1646 } 1647 } 1648 comp = comp->cp_next; 1649 } while (comp != NULL && !is_first_match(comp)); 1650 1651 xfree(match_count); 1652 1653 if (compl_match_arraysize == 0) { 1654 return -1; 1655 } 1656 1657 if (cot_fuzzy() && !compl_no_select && !shown_match_ok) { 1658 compl_shown_match = shown_compl; 1659 shown_match_ok = true; 1660 cur = 0; 1661 } 1662 1663 assert(compl_match_arraysize >= 0); 1664 compl_match_array = xcalloc((size_t)compl_match_arraysize, sizeof(pumitem_T)); 1665 1666 i = 0; 1667 comp = match_head; 1668 while (comp != NULL) { 1669 compl_match_array[i].pum_text = comp->cp_text[CPT_ABBR] != NULL 1670 ? comp->cp_text[CPT_ABBR] : comp->cp_str.data; 1671 compl_match_array[i].pum_kind = comp->cp_text[CPT_KIND]; 1672 compl_match_array[i].pum_info = comp->cp_text[CPT_INFO]; 1673 compl_match_array[i].pum_cpt_source_idx = comp->cp_cpt_source_idx; 1674 compl_match_array[i].pum_user_abbr_hlattr = comp->cp_user_abbr_hlattr; 1675 compl_match_array[i].pum_user_kind_hlattr = comp->cp_user_kind_hlattr; 1676 compl_match_array[i++].pum_extra = comp->cp_text[CPT_MENU] != NULL 1677 ? comp->cp_text[CPT_MENU] : comp->cp_fname; 1678 compl_T *match_next = comp->cp_match_next; 1679 comp->cp_match_next = NULL; 1680 comp = match_next; 1681 } 1682 1683 if (!shown_match_ok) { // no displayed match at all 1684 cur = -1; 1685 } 1686 1687 return cur; 1688 } 1689 1690 /// Show the popup menu for the list of matches. 1691 /// Also adjusts "compl_shown_match" to an entry that is actually displayed. 1692 void ins_compl_show_pum(void) 1693 { 1694 if (!pum_wanted() || !pum_enough_matches()) { 1695 return; 1696 } 1697 1698 // Update the screen before drawing the popup menu over it. 1699 update_screen(); 1700 1701 int cur = -1; 1702 bool array_changed = false; 1703 1704 if (compl_match_array == NULL) { 1705 array_changed = true; 1706 // Need to build the popup menu list. 1707 cur = ins_compl_build_pum(); 1708 } else { 1709 // popup menu already exists, only need to find the current item. 1710 for (int i = 0; i < compl_match_arraysize; i++) { 1711 if (compl_match_array[i].pum_text == compl_shown_match->cp_str.data 1712 || compl_match_array[i].pum_text == compl_shown_match->cp_text[CPT_ABBR]) { 1713 cur = i; 1714 break; 1715 } 1716 } 1717 } 1718 1719 if (compl_match_array == NULL) { 1720 if (compl_started && has_event(EVENT_COMPLETECHANGED)) { 1721 trigger_complete_changed_event(cur); 1722 } 1723 return; 1724 } 1725 1726 // In Replace mode when a $ is displayed at the end of the line only 1727 // part of the screen would be updated. We do need to redraw here. 1728 dollar_vcol = -1; 1729 1730 // Compute the screen column of the start of the completed text. 1731 // Use the cursor to get all wrapping and other settings right. 1732 const colnr_T col = curwin->w_cursor.col; 1733 curwin->w_cursor.col = compl_col; 1734 compl_selected_item = cur; 1735 pum_display(compl_match_array, compl_match_arraysize, cur, array_changed, 0); 1736 curwin->w_cursor.col = col; 1737 1738 // After adding leader, set the current match to shown match. 1739 if (compl_started && compl_curr_match != compl_shown_match) { 1740 compl_curr_match = compl_shown_match; 1741 } 1742 1743 if (has_event(EVENT_COMPLETECHANGED)) { 1744 trigger_complete_changed_event(cur); 1745 } 1746 } 1747 1748 /// check selected is current match. 1749 /// 1750 /// @param selected the item which is selected. 1751 /// @return bool return true when is current match otherwise is false. 1752 bool compl_match_curr_select(int selected) 1753 { 1754 if (selected < 0) { 1755 return false; 1756 } 1757 compl_T *match = compl_first_match; 1758 int selected_idx = -1, list_idx = 0; 1759 do { 1760 if (!match_at_original_text(match)) { 1761 if (compl_curr_match != NULL 1762 && compl_curr_match->cp_number == match->cp_number) { 1763 selected_idx = list_idx; 1764 break; 1765 } 1766 list_idx += 1; 1767 } 1768 match = match->cp_next; 1769 } while (match != NULL && !is_first_match(match)); 1770 1771 return selected == selected_idx; 1772 } 1773 1774 #define DICT_FIRST (1) ///< use just first element in "dict" 1775 #define DICT_EXACT (2) ///< "dict" is the exact name of a file 1776 1777 /// Add any identifiers that match the given pattern "pat" in the list of 1778 /// dictionary files "dict_start" to the list of completions. 1779 /// 1780 /// @param flags DICT_FIRST and/or DICT_EXACT 1781 /// @param thesaurus Thesaurus completion 1782 static void ins_compl_dictionaries(char *dict_start, char *pat, int flags, bool thesaurus) 1783 { 1784 char *dict = dict_start; 1785 char *ptr; 1786 regmatch_T regmatch; 1787 char **files; 1788 int count; 1789 Direction dir = compl_direction; 1790 1791 if (*dict == NUL) { 1792 // When 'dictionary' is empty and spell checking is enabled use 1793 // "spell". 1794 if (!thesaurus && curwin->w_p_spell) { 1795 dict = "spell"; 1796 } else { 1797 return; 1798 } 1799 } 1800 1801 char *buf = xmalloc(LSIZE); 1802 regmatch.regprog = NULL; // so that we can goto theend 1803 1804 // If 'infercase' is set, don't use 'smartcase' here 1805 int save_p_scs = p_scs; 1806 if (curbuf->b_p_inf) { 1807 p_scs = false; 1808 } 1809 1810 // When invoked to match whole lines for CTRL-X CTRL-L adjust the pattern 1811 // to only match at the start of a line. Otherwise just match the 1812 // pattern. Also need to double backslashes. 1813 if (ctrl_x_mode_line_or_eval()) { 1814 char *pat_esc = vim_strsave_escaped(pat, "\\"); 1815 1816 size_t len = strlen(pat_esc) + 10; 1817 ptr = xmalloc(len); 1818 vim_snprintf(ptr, len, "^\\s*\\zs\\V%s", pat_esc); 1819 regmatch.regprog = vim_regcomp(ptr, RE_MAGIC); 1820 xfree(pat_esc); 1821 xfree(ptr); 1822 } else { 1823 regmatch.regprog = vim_regcomp(pat, magic_isset() ? RE_MAGIC : 0); 1824 if (regmatch.regprog == NULL) { 1825 goto theend; 1826 } 1827 } 1828 1829 // ignore case depends on 'ignorecase', 'smartcase' and "pat" 1830 regmatch.rm_ic = ignorecase(pat); 1831 while (*dict != NUL && !got_int && !compl_interrupted) { 1832 // copy one dictionary file name into buf 1833 if (flags == DICT_EXACT) { 1834 count = 1; 1835 files = &dict; 1836 } else { 1837 // Expand wildcards in the dictionary name, but do not allow 1838 // backticks (for security, the 'dict' option may have been set in 1839 // a modeline). 1840 copy_option_part(&dict, buf, LSIZE, ","); 1841 if (!thesaurus && strcmp(buf, "spell") == 0) { 1842 count = -1; 1843 } else if (vim_strchr(buf, '`') != NULL 1844 || expand_wildcards(1, &buf, &count, &files, 1845 EW_FILE|EW_SILENT) != OK) { 1846 count = 0; 1847 } 1848 } 1849 1850 if (count == -1) { 1851 // Complete from active spelling. Skip "\<" in the pattern, we 1852 // don't use it as a RE. 1853 if (pat[0] == '\\' && pat[1] == '<') { 1854 ptr = pat + 2; 1855 } else { 1856 ptr = pat; 1857 } 1858 spell_dump_compl(ptr, regmatch.rm_ic, &dir, 0); 1859 } else if (count > 0) { // avoid warning for using "files" uninit 1860 ins_compl_files(count, files, thesaurus, flags, ®match, buf, &dir); 1861 if (flags != DICT_EXACT) { 1862 FreeWild(count, files); 1863 } 1864 } 1865 if (flags != 0) { 1866 break; 1867 } 1868 } 1869 1870 theend: 1871 p_scs = save_p_scs; 1872 vim_regfree(regmatch.regprog); 1873 xfree(buf); 1874 } 1875 1876 /// Add all the words in the line "*buf_arg" from the thesaurus file "fname" 1877 /// skipping the word at 'skip_word'. 1878 /// 1879 /// @return OK on success. 1880 static int thesaurus_add_words_in_line(char *fname, char **buf_arg, int dir, const char *skip_word) 1881 { 1882 int status = OK; 1883 1884 // Add the other matches on the line 1885 char *ptr = *buf_arg; 1886 while (!got_int) { 1887 // Find start of the next word. Skip white 1888 // space and punctuation. 1889 ptr = find_word_start(ptr); 1890 if (*ptr == NUL || *ptr == NL) { 1891 break; 1892 } 1893 char *wstart = ptr; 1894 1895 // Find end of the word. 1896 // Japanese words may have characters in 1897 // different classes, only separate words 1898 // with single-byte non-word characters. 1899 while (*ptr != NUL) { 1900 const int l = utfc_ptr2len(ptr); 1901 1902 if (l < 2 && !vim_iswordc((uint8_t)(*ptr))) { 1903 break; 1904 } 1905 ptr += l; 1906 } 1907 1908 // Add the word. Skip the regexp match. 1909 if (wstart != skip_word) { 1910 status = ins_compl_add_infercase(wstart, (int)(ptr - wstart), p_ic, 1911 fname, dir, false, FUZZY_SCORE_NONE); 1912 if (status == FAIL) { 1913 break; 1914 } 1915 } 1916 } 1917 1918 *buf_arg = ptr; 1919 return status; 1920 } 1921 1922 /// Process "count" dictionary/thesaurus "files" and add the text matching 1923 /// "regmatch". 1924 static void ins_compl_files(int count, char **files, bool thesaurus, int flags, 1925 regmatch_T *regmatch, char *buf, Direction *dir) 1926 FUNC_ATTR_NONNULL_ARG(2, 7) 1927 { 1928 char *leader = cot_fuzzy() ? ins_compl_leader() : NULL; 1929 int leader_len = cot_fuzzy() ? (int)ins_compl_leader_len() : 0; 1930 1931 for (int i = 0; i < count && !got_int && !ins_compl_interrupted(); i++) { 1932 FILE *fp = os_fopen(files[i], "r"); // open dictionary file 1933 if (flags != DICT_EXACT && !shortmess(SHM_COMPLETIONSCAN) && !compl_autocomplete) { 1934 msg_hist_off = true; // reset in msg_trunc() 1935 msg_ext_set_kind("completion"); 1936 vim_snprintf(IObuff, IOSIZE, 1937 _("Scanning dictionary: %s"), files[i]); 1938 msg_trunc(IObuff, true, HLF_R); 1939 } 1940 1941 if (fp == NULL) { 1942 continue; 1943 } 1944 1945 // Read dictionary file line by line. 1946 // Check each line for a match. 1947 while (!got_int && !ins_compl_interrupted() && !vim_fgets(buf, LSIZE, fp)) { 1948 char *ptr = buf; 1949 if (cot_fuzzy() && leader_len > 0) { 1950 char *line_end = find_line_end(ptr); 1951 while (ptr < line_end) { 1952 int score = 0; 1953 int len = 0; 1954 if (fuzzy_match_str_in_line(&ptr, leader, &len, NULL, &score)) { 1955 char *end_ptr = ctrl_x_mode_line_or_eval() 1956 ? find_line_end(ptr) : find_word_end(ptr); 1957 int add_r = ins_compl_add_infercase(ptr, (int)(end_ptr - ptr), 1958 p_ic, files[i], *dir, false, score); 1959 if (add_r == FAIL) { 1960 break; 1961 } 1962 ptr = end_ptr; // start from next word 1963 if (compl_get_longest && ctrl_x_mode_normal() 1964 && compl_first_match->cp_next 1965 && score == compl_first_match->cp_next->cp_score) { 1966 compl_num_bests++; 1967 } 1968 } 1969 } 1970 } else if (regmatch != NULL) { 1971 while (vim_regexec(regmatch, buf, (colnr_T)(ptr - buf))) { 1972 ptr = regmatch->startp[0]; 1973 ptr = ctrl_x_mode_line_or_eval() ? find_line_end(ptr) : find_word_end(ptr); 1974 int add_r = ins_compl_add_infercase(regmatch->startp[0], 1975 (int)(ptr - regmatch->startp[0]), 1976 p_ic, files[i], *dir, false, 1977 FUZZY_SCORE_NONE); 1978 if (thesaurus) { 1979 // For a thesaurus, add all the words in the line 1980 ptr = buf; 1981 add_r = thesaurus_add_words_in_line(files[i], &ptr, *dir, regmatch->startp[0]); 1982 } 1983 if (add_r == OK) { 1984 // if dir was BACKWARD then honor it just once 1985 *dir = FORWARD; 1986 } else if (add_r == FAIL) { 1987 break; 1988 } 1989 // avoid expensive call to vim_regexec() when at end 1990 // of line 1991 if (*ptr == '\n' || got_int) { 1992 break; 1993 } 1994 } 1995 } 1996 line_breakcheck(); 1997 ins_compl_check_keys(50, false); 1998 } 1999 fclose(fp); 2000 } 2001 } 2002 2003 /// Find the start of the next word. 2004 /// Returns a pointer to the first char of the word. Also stops at a NUL. 2005 char *find_word_start(char *ptr) 2006 FUNC_ATTR_PURE 2007 { 2008 while (*ptr != NUL && *ptr != '\n' && mb_get_class(ptr) <= 1) { 2009 ptr += utfc_ptr2len(ptr); 2010 } 2011 return ptr; 2012 } 2013 2014 /// Find the end of the word. Assumes it starts inside a word. 2015 /// Returns a pointer to just after the word. 2016 char *find_word_end(char *ptr) 2017 FUNC_ATTR_PURE 2018 { 2019 const int start_class = mb_get_class(ptr); 2020 if (start_class > 1) { 2021 while (*ptr != NUL) { 2022 ptr += utfc_ptr2len(ptr); 2023 if (mb_get_class(ptr) != start_class) { 2024 break; 2025 } 2026 } 2027 } 2028 return ptr; 2029 } 2030 2031 /// Find the end of the line, omitting CR and NL at the end. 2032 /// 2033 /// @return a pointer to just after the line. 2034 char *find_line_end(char *ptr) 2035 { 2036 char *s = ptr + strlen(ptr); 2037 while (s > ptr && (s[-1] == CAR || s[-1] == NL)) { 2038 s--; 2039 } 2040 return s; 2041 } 2042 2043 /// Free a completion item in the list 2044 static void ins_compl_item_free(compl_T *match) 2045 { 2046 API_CLEAR_STRING(match->cp_str); 2047 // several entries may use the same fname, free it just once. 2048 if (match->cp_flags & CP_FREE_FNAME) { 2049 xfree(match->cp_fname); 2050 } 2051 free_cptext(match->cp_text); 2052 tv_clear(&match->cp_user_data); 2053 xfree(match); 2054 } 2055 2056 /// Free the list of completions 2057 static void ins_compl_free(void) 2058 { 2059 API_CLEAR_STRING(compl_pattern); 2060 API_CLEAR_STRING(compl_leader); 2061 2062 if (compl_first_match == NULL) { 2063 return; 2064 } 2065 2066 ins_compl_del_pum(); 2067 pum_clear(); 2068 2069 compl_curr_match = compl_first_match; 2070 do { 2071 compl_T *match = compl_curr_match; 2072 compl_curr_match = compl_curr_match->cp_next; 2073 ins_compl_item_free(match); 2074 } while (compl_curr_match != NULL && !is_first_match(compl_curr_match)); 2075 compl_first_match = compl_curr_match = NULL; 2076 compl_shown_match = NULL; 2077 compl_old_match = NULL; 2078 } 2079 2080 /// Reset/clear the completion state. 2081 void ins_compl_clear(void) 2082 { 2083 compl_cont_status = 0; 2084 compl_started = false; 2085 compl_matches = 0; 2086 compl_selected_item = -1; 2087 compl_ins_end_col = 0; 2088 compl_curr_win = NULL; 2089 compl_curr_buf = NULL; 2090 API_CLEAR_STRING(compl_pattern); 2091 API_CLEAR_STRING(compl_leader); 2092 edit_submode_extra = NULL; 2093 kv_destroy(compl_orig_extmarks); 2094 API_CLEAR_STRING(compl_orig_text); 2095 compl_enter_selects = false; 2096 cpt_sources_clear(); 2097 compl_autocomplete = false; 2098 compl_from_nonkeyword = false; 2099 compl_num_bests = 0; 2100 // clear v:completed_item 2101 set_vim_var_dict(VV_COMPLETED_ITEM, tv_dict_alloc_lock(VAR_FIXED)); 2102 } 2103 2104 /// Check that Insert completion is active. 2105 bool ins_compl_active(void) 2106 FUNC_ATTR_PURE 2107 { 2108 return compl_started; 2109 } 2110 2111 /// Return true when wp is the actual completion window 2112 bool ins_compl_win_active(win_T *wp) 2113 { 2114 return ins_compl_active() && wp == compl_curr_win && wp->w_buffer == compl_curr_buf; 2115 } 2116 2117 /// Selected one of the matches. When false, the match was edited or 2118 /// using the longest common string. 2119 bool ins_compl_used_match(void) 2120 { 2121 return compl_used_match; 2122 } 2123 2124 /// Initialize get longest common string. 2125 void ins_compl_init_get_longest(void) 2126 { 2127 compl_get_longest = false; 2128 } 2129 2130 /// Returns true when insert completion is interrupted. 2131 bool ins_compl_interrupted(void) 2132 { 2133 return compl_interrupted || compl_time_slice_expired; 2134 } 2135 2136 /// Returns true if the <Enter> key selects a match in the completion popup 2137 /// menu. 2138 bool ins_compl_enter_selects(void) 2139 { 2140 return compl_enter_selects; 2141 } 2142 2143 /// Return the column where the text starts that is being completed 2144 colnr_T ins_compl_col(void) 2145 { 2146 return compl_col; 2147 } 2148 2149 /// Return the length in bytes of the text being completed 2150 int ins_compl_len(void) 2151 { 2152 return compl_length; 2153 } 2154 2155 /// Return true when the 'completeopt' "preinsert" flag is in effect, 2156 /// otherwise return false. 2157 bool ins_compl_has_preinsert(void) 2158 { 2159 unsigned cur_cot_flags = get_cot_flags(); 2160 if (compl_autocomplete && p_ic && !p_inf) { 2161 return false; 2162 } 2163 return (!compl_autocomplete 2164 ? (cur_cot_flags & (kOptCotFlagPreinsert|kOptCotFlagFuzzy|kOptCotFlagMenuone)) 2165 == (kOptCotFlagPreinsert|kOptCotFlagMenuone) 2166 : (cur_cot_flags & (kOptCotFlagPreinsert|kOptCotFlagFuzzy)) 2167 == kOptCotFlagPreinsert); 2168 } 2169 2170 /// Returns true if the pre-insert effect is valid and the cursor is within 2171 /// the `compl_ins_end_col` range. 2172 bool ins_compl_preinsert_effect(void) 2173 { 2174 if (!ins_compl_has_preinsert() && !ins_compl_preinsert_longest()) { 2175 return false; 2176 } 2177 2178 return curwin->w_cursor.col < compl_ins_end_col; 2179 } 2180 2181 /// Delete one character before the cursor and show the subset of the matches 2182 /// that match the word that is now before the cursor. 2183 /// Returns the character to be used, NUL if the work is done and another char 2184 /// to be got from the user. 2185 int ins_compl_bs(void) 2186 { 2187 if (ins_compl_preinsert_effect()) { 2188 ins_compl_delete(false); 2189 } 2190 2191 char *line = get_cursor_line_ptr(); 2192 char *p = line + curwin->w_cursor.col; 2193 MB_PTR_BACK(line, p); 2194 ptrdiff_t p_off = p - line; 2195 2196 // Stop completion when the whole word was deleted. For Omni completion 2197 // allow the word to be deleted, we won't match everything. 2198 // Respect the 'backspace' option. 2199 if ((int)(p - line) - (int)compl_col < 0 2200 || ((int)(p - line) - (int)compl_col == 0 && !ctrl_x_mode_omni()) 2201 || ctrl_x_mode_eval() 2202 || (!can_bs(BS_START) && (int)(p - line) - (int)compl_col 2203 - compl_length < 0)) { 2204 return K_BS; 2205 } 2206 2207 // Deleted more than what was used to find matches or didn't finish 2208 // finding all matches: need to look for matches all over again. 2209 if (curwin->w_cursor.col <= compl_col + compl_length 2210 || ins_compl_need_restart()) { 2211 ins_compl_restart(); 2212 } 2213 2214 // ins_compl_restart() calls update_screen() which may invalidate the pointer 2215 // TODO(bfredl): get rid of random update_screen() calls deep inside completion logic 2216 line = get_cursor_line_ptr(); 2217 2218 API_CLEAR_STRING(compl_leader); 2219 compl_leader = cbuf_to_string(line + compl_col, 2220 (size_t)(p_off - (ptrdiff_t)compl_col)); 2221 2222 // Clear selection if a menu item is currently selected in autocompletion 2223 if (compl_autocomplete && compl_first_match && !ins_compl_has_preinsert()) { 2224 compl_shown_match = compl_first_match; 2225 } 2226 2227 ins_compl_new_leader(); 2228 if (compl_shown_match != NULL) { 2229 // Make sure current match is not a hidden item. 2230 compl_curr_match = compl_shown_match; 2231 } 2232 return NUL; 2233 } 2234 2235 /// Check if the complete function returned "always" in the "refresh" dictionary item. 2236 static bool ins_compl_refresh_always(void) 2237 FUNC_ATTR_PURE 2238 { 2239 return (ctrl_x_mode_function() || ctrl_x_mode_omni()) && compl_opt_refresh_always; 2240 } 2241 2242 /// Check that we need to find matches again, ins_compl_restart() is to 2243 /// be called. 2244 static bool ins_compl_need_restart(void) 2245 FUNC_ATTR_PURE 2246 { 2247 // Return true if we didn't complete finding matches or when the 2248 // "completefunc" returned "always" in the "refresh" dictionary item. 2249 return compl_was_interrupted || ins_compl_refresh_always(); 2250 } 2251 2252 /// Return true if 'autocomplete' option is set 2253 bool ins_compl_has_autocomplete(void) 2254 { 2255 // Use buffer-local setting if defined (>= 0), otherwise use global 2256 return curbuf->b_p_ac >= 0 ? curbuf->b_p_ac : p_ac; 2257 } 2258 2259 /// Calculate fuzzy score and sort completion matches unless sorting is disabled. 2260 static void ins_compl_fuzzy_sort(void) 2261 { 2262 unsigned cur_cot_flags = get_cot_flags(); 2263 2264 // Set the fuzzy score in cp_score and sort 2265 set_fuzzy_score(); 2266 if (!(cur_cot_flags & kOptCotFlagNosort)) { 2267 sort_compl_match_list(cp_compare_fuzzy); 2268 // Reset the shown item since sorting reorders items 2269 if ((cur_cot_flags & (kOptCotFlagNoinsert|kOptCotFlagNoselect)) == kOptCotFlagNoinsert) { 2270 bool none_selected = compl_shown_match == (compl_shows_dir_forward() 2271 ? compl_first_match : compl_first_match->cp_prev); 2272 if (!none_selected) { 2273 compl_shown_match = (!compl_autocomplete && compl_shows_dir_forward()) 2274 ? compl_first_match->cp_next : compl_first_match; 2275 } 2276 } 2277 } 2278 } 2279 2280 /// Called after changing "compl_leader". 2281 /// Show the popup menu with a different set of matches. 2282 /// May also search for matches again if the previous search was interrupted. 2283 static void ins_compl_new_leader(void) 2284 { 2285 ins_compl_del_pum(); 2286 ins_compl_delete(true); 2287 ins_compl_insert_bytes(compl_leader.data + get_compl_len(), -1); 2288 compl_used_match = false; 2289 2290 if (p_acl > 0) { 2291 pum_undisplay(true); 2292 redraw_later(curwin, UPD_VALID); 2293 update_screen(); // Show char (deletion) immediately 2294 ui_flush(); 2295 } 2296 2297 if (compl_started) { 2298 ins_compl_set_original_text(compl_leader.data, compl_leader.size); 2299 if (is_cpt_func_refresh_always()) { 2300 cpt_compl_refresh(); 2301 } 2302 if (cot_fuzzy()) { 2303 ins_compl_fuzzy_sort(); 2304 } 2305 } else { 2306 spell_bad_len = 0; // need to redetect bad word 2307 // Matches were cleared, need to search for them now. 2308 // Set "compl_restarting" to avoid that the first match is inserted. 2309 compl_restarting = true; 2310 if (ins_compl_has_autocomplete()) { 2311 ins_compl_enable_autocomplete(); 2312 } else { 2313 compl_autocomplete = false; 2314 } 2315 if (ins_complete(Ctrl_N, true) == FAIL) { 2316 compl_cont_status = 0; 2317 } 2318 compl_restarting = false; 2319 } 2320 2321 compl_enter_selects = !compl_used_match && compl_selected_item != -1; 2322 2323 // Show the popup menu with a different set of matches. 2324 ins_compl_show_pum(); 2325 2326 // Don't let Enter select the original text when there is no popup menu. 2327 if (compl_match_array == NULL) { 2328 compl_enter_selects = false; 2329 } else if (ins_compl_has_preinsert() && compl_leader.size > 0) { 2330 ins_compl_insert(true, false); 2331 } else if (compl_started && ins_compl_preinsert_longest() 2332 && compl_leader.size > 0 && !ins_compl_preinsert_effect()) { 2333 ins_compl_insert(true, true); 2334 } 2335 // Don't let Enter select when use user function and refresh_always is set 2336 if (ins_compl_refresh_always()) { 2337 compl_enter_selects = false; 2338 } 2339 } 2340 2341 /// Return the length of the completion, from the completion start column to 2342 /// the cursor column. Making sure it never goes below zero. 2343 static int get_compl_len(void) 2344 { 2345 int off = (int)curwin->w_cursor.col - (int)compl_col; 2346 return MAX(0, off); 2347 } 2348 2349 /// Append one character to the match leader. May reduce the number of 2350 /// matches. 2351 void ins_compl_addleader(int c) 2352 { 2353 int cc; 2354 2355 if (ins_compl_preinsert_effect()) { 2356 ins_compl_delete(false); 2357 } 2358 2359 if (stop_arrow() == FAIL) { 2360 return; 2361 } 2362 if ((cc = utf_char2len(c)) > 1) { 2363 char buf[MB_MAXCHAR + 1]; 2364 2365 utf_char2bytes(c, buf); 2366 buf[cc] = NUL; 2367 ins_char_bytes(buf, (size_t)cc); 2368 } else { 2369 ins_char(c); 2370 } 2371 2372 // If we didn't complete finding matches we must search again. 2373 if (ins_compl_need_restart()) { 2374 ins_compl_restart(); 2375 } 2376 2377 API_CLEAR_STRING(compl_leader); 2378 compl_leader = cbuf_to_string(get_cursor_line_ptr() + compl_col, 2379 (size_t)(curwin->w_cursor.col - compl_col)); 2380 ins_compl_new_leader(); 2381 } 2382 2383 /// Setup for finding completions again without leaving CTRL-X mode. Used when 2384 /// BS or a key was typed while still searching for matches. 2385 static void ins_compl_restart(void) 2386 { 2387 // update screen before restart. 2388 // so if complete is blocked, 2389 // will stay to the last popup menu and reduce flicker 2390 update_screen(); // TODO(bfredl): no. 2391 ins_compl_free(); 2392 compl_started = false; 2393 compl_matches = 0; 2394 compl_cont_status = 0; 2395 compl_cont_mode = 0; 2396 cpt_sources_clear(); 2397 compl_autocomplete = false; 2398 compl_from_nonkeyword = false; 2399 compl_num_bests = 0; 2400 } 2401 2402 /// Set the first match, the original text. 2403 static void ins_compl_set_original_text(char *str, size_t len) 2404 FUNC_ATTR_NONNULL_ALL 2405 { 2406 // Replace the original text entry. 2407 // The CP_ORIGINAL_TEXT flag is either at the first item or might possibly 2408 // be at the last item for backward completion 2409 if (match_at_original_text(compl_first_match)) { // safety check 2410 API_CLEAR_STRING(compl_first_match->cp_str); 2411 compl_first_match->cp_str = cbuf_to_string(str, len); 2412 } else if (compl_first_match->cp_prev != NULL 2413 && match_at_original_text(compl_first_match->cp_prev)) { 2414 API_CLEAR_STRING(compl_first_match->cp_prev->cp_str); 2415 compl_first_match->cp_prev->cp_str = cbuf_to_string(str, len); 2416 } 2417 } 2418 2419 /// Append one character to the match leader. May reduce the number of 2420 /// matches. 2421 void ins_compl_addfrommatch(void) 2422 { 2423 int len = (int)curwin->w_cursor.col - (int)compl_col; 2424 assert(compl_shown_match != NULL); 2425 char *p = compl_shown_match->cp_str.data; 2426 if ((int)compl_shown_match->cp_str.size <= len) { // the match is too short 2427 // When still at the original match use the first entry that matches 2428 // the leader. 2429 if (!match_at_original_text(compl_shown_match)) { 2430 return; 2431 } 2432 2433 p = NULL; 2434 size_t plen = 0; 2435 for (compl_T *cp = compl_shown_match->cp_next; cp != NULL 2436 && !is_first_match(cp); cp = cp->cp_next) { 2437 if (compl_leader.data == NULL 2438 || ins_compl_equal(cp, compl_leader.data, compl_leader.size)) { 2439 p = cp->cp_str.data; 2440 plen = cp->cp_str.size; 2441 break; 2442 } 2443 } 2444 if (p == NULL || (int)plen <= len) { 2445 return; 2446 } 2447 } 2448 p += len; 2449 int c = utf_ptr2char(p); 2450 ins_compl_addleader(c); 2451 } 2452 2453 /// Set the CTRL-X completion mode based on the key "c" typed after a CTRL-X. 2454 /// Uses the global variables: ctrl_x_mode, edit_submode, edit_submode_pre, 2455 /// compl_cont_mode and compl_cont_status. 2456 /// 2457 /// @return true when the character is not to be inserted. 2458 static bool set_ctrl_x_mode(const int c) 2459 { 2460 bool retval = false; 2461 2462 switch (c) { 2463 case Ctrl_E: 2464 case Ctrl_Y: 2465 // scroll the window one line up or down 2466 ctrl_x_mode = CTRL_X_SCROLL; 2467 if (!(State & REPLACE_FLAG)) { 2468 edit_submode = _(" (insert) Scroll (^E/^Y)"); 2469 } else { 2470 edit_submode = _(" (replace) Scroll (^E/^Y)"); 2471 } 2472 edit_submode_pre = NULL; 2473 redraw_mode = true; 2474 break; 2475 case Ctrl_L: 2476 // complete whole line 2477 ctrl_x_mode = CTRL_X_WHOLE_LINE; 2478 break; 2479 case Ctrl_F: 2480 // complete filenames 2481 ctrl_x_mode = CTRL_X_FILES; 2482 break; 2483 case Ctrl_K: 2484 // complete words from a dictionary 2485 ctrl_x_mode = CTRL_X_DICTIONARY; 2486 break; 2487 case Ctrl_R: 2488 // When CTRL-R is followed by '=', don't trigger register completion 2489 // This allows expressions like <C-R>=func()<CR> to work normally 2490 if (vpeekc() == '=') { 2491 break; 2492 } 2493 ctrl_x_mode = CTRL_X_REGISTER; 2494 break; 2495 case Ctrl_T: 2496 // complete words from a thesaurus 2497 ctrl_x_mode = CTRL_X_THESAURUS; 2498 break; 2499 case Ctrl_U: 2500 // user defined completion 2501 ctrl_x_mode = CTRL_X_FUNCTION; 2502 break; 2503 case Ctrl_O: 2504 // omni completion 2505 ctrl_x_mode = CTRL_X_OMNI; 2506 break; 2507 case 's': 2508 case Ctrl_S: 2509 // complete spelling suggestions 2510 ctrl_x_mode = CTRL_X_SPELL; 2511 emsg_off++; // Avoid getting the E756 error twice. 2512 spell_back_to_badword(); 2513 emsg_off--; 2514 break; 2515 case Ctrl_RSB: 2516 // complete tag names 2517 ctrl_x_mode = CTRL_X_TAGS; 2518 break; 2519 case Ctrl_I: 2520 case K_S_TAB: 2521 // complete keywords from included files 2522 ctrl_x_mode = CTRL_X_PATH_PATTERNS; 2523 break; 2524 case Ctrl_D: 2525 // complete definitions from included files 2526 ctrl_x_mode = CTRL_X_PATH_DEFINES; 2527 break; 2528 case Ctrl_V: 2529 case Ctrl_Q: 2530 // complete vim commands 2531 ctrl_x_mode = CTRL_X_CMDLINE; 2532 break; 2533 case Ctrl_Z: 2534 // stop completion 2535 ctrl_x_mode = CTRL_X_NORMAL; 2536 edit_submode = NULL; 2537 redraw_mode = true; 2538 retval = true; 2539 break; 2540 case Ctrl_P: 2541 case Ctrl_N: 2542 // ^X^P means LOCAL expansion if nothing interrupted (eg we 2543 // just started ^X mode, or there were enough ^X's to cancel 2544 // the previous mode, say ^X^F^X^X^P or ^P^X^X^X^P, see below) 2545 // do normal expansion when interrupting a different mode (say 2546 // ^X^F^X^P or ^P^X^X^P, see below) 2547 // nothing changes if interrupting mode 0, (eg, the flag 2548 // doesn't change when going to ADDING mode -- Acevedo 2549 if (!(compl_cont_status & CONT_INTRPT)) { 2550 compl_cont_status |= CONT_LOCAL; 2551 } else if (compl_cont_mode != 0) { 2552 compl_cont_status &= ~CONT_LOCAL; 2553 } 2554 FALLTHROUGH; 2555 default: 2556 // If we have typed at least 2 ^X's... for modes != 0, we set 2557 // compl_cont_status = 0 (eg, as if we had just started ^X 2558 // mode). 2559 // For mode 0, we set "compl_cont_mode" to an impossible 2560 // value, in both cases ^X^X can be used to restart the same 2561 // mode (avoiding ADDING mode). 2562 // Undocumented feature: In a mode != 0 ^X^P and ^X^X^P start 2563 // 'complete' and local ^P expansions respectively. 2564 // In mode 0 an extra ^X is needed since ^X^P goes to ADDING 2565 // mode -- Acevedo 2566 if (c == Ctrl_X) { 2567 if (compl_cont_mode != 0) { 2568 compl_cont_status = 0; 2569 } else { 2570 compl_cont_mode = CTRL_X_NOT_DEFINED_YET; 2571 } 2572 } 2573 ctrl_x_mode = CTRL_X_NORMAL; 2574 edit_submode = NULL; 2575 redraw_mode = true; 2576 break; 2577 } 2578 2579 return retval; 2580 } 2581 2582 /// Stop insert completion mode 2583 static bool ins_compl_stop(const int c, const int prev_mode, bool retval) 2584 { 2585 // Remove pre-inserted text when present. 2586 if (ins_compl_preinsert_effect() && ins_compl_win_active(curwin)) { 2587 ins_compl_delete(false); 2588 } 2589 2590 // Get here when we have finished typing a sequence of ^N and 2591 // ^P or other completion characters in CTRL-X mode. Free up 2592 // memory that was used, and make sure we can redo the insert. 2593 if (compl_curr_match != NULL || compl_leader.data != NULL || c == Ctrl_E) { 2594 // If any of the original typed text has been changed, eg when 2595 // ignorecase is set, we must add back-spaces to the redo 2596 // buffer. We add as few as necessary to delete just the part 2597 // of the original text that has changed. 2598 // When using the longest match, edited the match or used 2599 // CTRL-E then don't use the current match. 2600 char *ptr = NULL; 2601 if (compl_curr_match != NULL && compl_used_match && c != Ctrl_E) { 2602 ptr = compl_curr_match->cp_str.data; 2603 } 2604 ins_compl_fixRedoBufForLeader(ptr); 2605 } 2606 2607 bool want_cindent = (get_can_cindent() && cindent_on()); 2608 2609 // When completing whole lines: fix indent for 'cindent'. 2610 // Otherwise, break line if it's too long. 2611 if (compl_cont_mode == CTRL_X_WHOLE_LINE) { 2612 // re-indent the current line 2613 if (want_cindent) { 2614 do_c_expr_indent(); 2615 want_cindent = false; // don't do it again 2616 } 2617 } else { 2618 const int prev_col = curwin->w_cursor.col; 2619 2620 // put the cursor on the last char, for 'tw' formatting 2621 if (prev_col > 0) { 2622 dec_cursor(); 2623 } 2624 2625 // only format when something was inserted 2626 if (!arrow_used && !ins_need_undo_get() && c != Ctrl_E) { 2627 insertchar(NUL, 0, -1); 2628 } 2629 2630 if (prev_col > 0 2631 && get_cursor_line_ptr()[curwin->w_cursor.col] != NUL) { 2632 inc_cursor(); 2633 } 2634 } 2635 2636 char *word = NULL; 2637 // If the popup menu is displayed pressing CTRL-Y means accepting 2638 // the selection without inserting anything. When 2639 // compl_enter_selects is set the Enter key does the same. 2640 if ((c == Ctrl_Y || (compl_enter_selects 2641 && (c == CAR || c == K_KENTER || c == NL))) 2642 && pum_visible()) { 2643 word = xstrdup(compl_shown_match->cp_str.data); 2644 retval = true; 2645 // May need to remove ComplMatchIns highlight. 2646 redrawWinline(curwin, curwin->w_cursor.lnum); 2647 } 2648 2649 // CTRL-E means completion is Ended, go back to the typed text. 2650 // but only do this, if the Popup is still visible 2651 if (c == Ctrl_E) { 2652 ins_compl_delete(false); 2653 char *p = NULL; 2654 size_t plen = 0; 2655 if (compl_leader.data != NULL) { 2656 p = compl_leader.data; 2657 plen = compl_leader.size; 2658 } else if (compl_first_match != NULL) { 2659 p = compl_orig_text.data; 2660 plen = compl_orig_text.size; 2661 } 2662 if (p != NULL) { 2663 const int compl_len = get_compl_len(); 2664 if ((int)plen > compl_len) { 2665 ins_compl_insert_bytes(p + compl_len, (int)plen - compl_len); 2666 } 2667 } 2668 restore_orig_extmarks(); 2669 retval = true; 2670 } 2671 2672 auto_format(false, true); 2673 2674 // Trigger the CompleteDonePre event to give scripts a chance to 2675 // act upon the completion before clearing the info, and restore 2676 // ctrl_x_mode, so that complete_info() can be used. 2677 ctrl_x_mode = prev_mode; 2678 ins_apply_autocmds(EVENT_COMPLETEDONEPRE); 2679 2680 ins_compl_free(); 2681 compl_started = false; 2682 compl_matches = 0; 2683 if (!shortmess(SHM_COMPLETIONMENU)) { 2684 msg_clr_cmdline(); // necessary for "noshowmode" 2685 } 2686 ctrl_x_mode = CTRL_X_NORMAL; 2687 compl_enter_selects = false; 2688 if (edit_submode != NULL) { 2689 edit_submode = NULL; 2690 redraw_mode = true; 2691 } 2692 compl_autocomplete = false; 2693 compl_from_nonkeyword = false; 2694 compl_best_matches = 0; 2695 compl_ins_end_col = 0; 2696 2697 if (c == Ctrl_C && cmdwin_type != 0) { 2698 // Avoid the popup menu remains displayed when leaving the 2699 // command line window. 2700 update_screen(); 2701 } 2702 2703 // Indent now if a key was typed that is in 'cinkeys'. 2704 if (want_cindent && in_cinkeys(KEY_COMPLETE, ' ', inindent(0))) { 2705 do_c_expr_indent(); 2706 } 2707 // Trigger the CompleteDone event to give scripts a chance to act 2708 // upon the end of completion. 2709 do_autocmd_completedone(c, prev_mode, word); 2710 xfree(word); 2711 2712 return retval; 2713 } 2714 2715 /// Cancel completion. 2716 bool ins_compl_cancel(void) 2717 { 2718 return ins_compl_stop(' ', ctrl_x_mode, true); 2719 } 2720 2721 /// Prepare for Insert mode completion, or stop it. 2722 /// Called just after typing a character in Insert mode. 2723 /// 2724 /// @param c character that was typed 2725 /// 2726 /// @return true when the character is not to be inserted; 2727 bool ins_compl_prep(int c) 2728 { 2729 bool retval = false; 2730 const int prev_mode = ctrl_x_mode; 2731 2732 // Forget any previous 'special' messages if this is actually 2733 // a ^X mode key - bar ^R, in which case we wait to see what it gives us. 2734 if (c != Ctrl_R && vim_is_ctrl_x_key(c)) { 2735 edit_submode_extra = NULL; 2736 } 2737 2738 // Ignore end of Select mode mapping and mouse scroll/movement. 2739 if (c == K_SELECT || c == K_MOUSEDOWN || c == K_MOUSEUP 2740 || c == K_MOUSELEFT || c == K_MOUSERIGHT || c == K_MOUSEMOVE 2741 || c == K_EVENT || c == K_COMMAND || c == K_LUA) { 2742 return retval; 2743 } 2744 2745 if (ctrl_x_mode == CTRL_X_CMDLINE_CTRL_X && c != Ctrl_X) { 2746 if (c == Ctrl_V || c == Ctrl_Q || c == Ctrl_Z || ins_compl_pum_key(c) 2747 || !vim_is_ctrl_x_key(c)) { 2748 // Not starting another completion mode. 2749 ctrl_x_mode = CTRL_X_CMDLINE; 2750 2751 // CTRL-X CTRL-Z should stop completion without inserting anything 2752 if (c == Ctrl_Z) { 2753 retval = true; 2754 } 2755 } else { 2756 ctrl_x_mode = CTRL_X_CMDLINE; 2757 2758 // Other CTRL-X keys first stop completion, then start another 2759 // completion mode. 2760 ins_compl_prep(' '); 2761 ctrl_x_mode = CTRL_X_NOT_DEFINED_YET; 2762 } 2763 } 2764 2765 // Set "compl_get_longest" when finding the first matches. 2766 if (ctrl_x_mode_not_defined_yet() 2767 || (ctrl_x_mode_normal() && !compl_started)) { 2768 compl_get_longest = (get_cot_flags() & kOptCotFlagLongest) != 0; 2769 compl_used_match = true; 2770 } 2771 2772 if (ctrl_x_mode_not_defined_yet()) { 2773 // We have just typed CTRL-X and aren't quite sure which CTRL-X mode 2774 // it will be yet. Now we decide. 2775 retval = set_ctrl_x_mode(c); 2776 } else if (ctrl_x_mode_not_default()) { 2777 // We're already in CTRL-X mode, do we stay in it? 2778 if (!vim_is_ctrl_x_key(c)) { 2779 ctrl_x_mode = ctrl_x_mode_scroll() ? CTRL_X_NORMAL : CTRL_X_FINISHED; 2780 edit_submode = NULL; 2781 } 2782 redraw_mode = true; 2783 } 2784 2785 if (compl_started || ctrl_x_mode == CTRL_X_FINISHED) { 2786 // Show error message from attempted keyword completion (probably 2787 // 'Pattern not found') until another key is hit, then go back to 2788 // showing what mode we are in. 2789 redraw_mode = true; 2790 if ((ctrl_x_mode_normal() 2791 && c != Ctrl_N 2792 && c != Ctrl_P 2793 && c != Ctrl_R 2794 && !ins_compl_pum_key(c)) 2795 || ctrl_x_mode == CTRL_X_FINISHED) { 2796 retval = ins_compl_stop(c, prev_mode, retval); 2797 } 2798 } else if (ctrl_x_mode == CTRL_X_LOCAL_MSG) { 2799 // Trigger the CompleteDone event to give scripts a chance to act 2800 // upon the (possibly failed) completion. 2801 do_autocmd_completedone(c, ctrl_x_mode, NULL); 2802 } 2803 2804 may_trigger_modechanged(); 2805 2806 // reset continue_* if we left expansion-mode, if we stay they'll be 2807 // (re)set properly in ins_complete() 2808 if (!vim_is_ctrl_x_key(c)) { 2809 compl_cont_status = 0; 2810 compl_cont_mode = 0; 2811 } 2812 2813 return retval; 2814 } 2815 2816 /// Fix the redo buffer for the completion leader replacing some of the typed 2817 /// text. This inserts backspaces and appends the changed text. 2818 /// "ptr" is the known leader text or NUL. 2819 static void ins_compl_fixRedoBufForLeader(char *ptr_arg) 2820 { 2821 int len = 0; 2822 char *ptr = ptr_arg; 2823 2824 if (ptr == NULL) { 2825 if (compl_leader.data != NULL) { 2826 ptr = compl_leader.data; 2827 } else { 2828 return; // nothing to do 2829 } 2830 } 2831 if (compl_orig_text.data != NULL) { 2832 char *p = compl_orig_text.data; 2833 // Find length of common prefix between original text and new completion 2834 while (p[len] != NUL && p[len] == ptr[len]) { 2835 len++; 2836 } 2837 // Adjust length to not break inside a multi-byte character 2838 if (len > 0) { 2839 len -= utf_head_off(p, p + len); 2840 } 2841 // Add backspace characters for each remaining character in original text 2842 for (p += len; *p != NUL; MB_PTR_ADV(p)) { 2843 AppendCharToRedobuff(K_BS); 2844 } 2845 } 2846 AppendToRedobuffLit(ptr + len, -1); 2847 } 2848 2849 /// Loops through the list of windows, loaded-buffers or non-loaded-buffers 2850 /// (depending on flag) starting from buf and looking for a non-scanned 2851 /// buffer (other than curbuf). curbuf is special, if it is called with 2852 /// buf=curbuf then it has to be the first call for a given flag/expansion. 2853 /// 2854 /// Returns the buffer to scan, if any, otherwise returns curbuf -- Acevedo 2855 static buf_T *ins_compl_next_buf(buf_T *buf, int flag) 2856 { 2857 static win_T *wp = NULL; 2858 2859 if (flag == 'w') { // just windows 2860 if (buf == curbuf || !win_valid(wp)) { 2861 // first call for this flag/expansion or window was closed 2862 wp = curwin; 2863 } 2864 2865 assert(wp); 2866 while (true) { 2867 // Move to next window (wrap to first window if at the end) 2868 wp = (wp->w_next != NULL) ? wp->w_next : firstwin; 2869 // Break if we're back at start or found an unscanned buffer (in a focusable window) 2870 if (wp == curwin || (!wp->w_buffer->b_scanned && wp->w_config.focusable)) { 2871 break; 2872 } 2873 } 2874 buf = wp->w_buffer; 2875 } else { 2876 // 'b' (just loaded buffers), 'u' (just non-loaded buffers) or 'U' 2877 // (unlisted buffers) 2878 // When completing whole lines skip unloaded buffers. 2879 while (true) { 2880 // Move to next buffer (wrap to first buffer if at the end) 2881 buf = (buf->b_next != NULL) ? buf->b_next : firstbuf; 2882 // Break if we're back at start buffer 2883 if (buf == curbuf) { 2884 break; 2885 } 2886 2887 bool skip_buffer; 2888 // Check buffer conditions based on flag 2889 if (flag == 'U') { 2890 skip_buffer = buf->b_p_bl; 2891 } else { 2892 skip_buffer = !buf->b_p_bl || (buf->b_ml.ml_mfp == NULL) != (flag == 'u'); 2893 } 2894 2895 // Break if we found a buffer that matches our criteria 2896 if (!skip_buffer && !buf->b_scanned) { 2897 break; 2898 } 2899 } 2900 } 2901 return buf; 2902 } 2903 2904 /// Count the number of entries in the 'complete' option (curbuf->b_p_cpt). 2905 /// Each non-empty, comma-separated segment is counted as one entry. 2906 static int get_cpt_sources_count(void) 2907 { 2908 char dummy[LSIZE]; 2909 int count = 0; 2910 2911 for (char *p = curbuf->b_p_cpt; *p != NUL;) { 2912 while (*p == ',' || *p == ' ') { 2913 p++; // Skip delimiters 2914 } 2915 if (*p != NUL) { 2916 (void)copy_option_part(&p, dummy, LSIZE, ","); // Advance p 2917 count++; 2918 } 2919 } 2920 2921 return count; 2922 } 2923 2924 static Callback cfu_cb; ///< 'completefunc' callback function 2925 static Callback ofu_cb; ///< 'omnifunc' callback function 2926 static Callback tsrfu_cb; ///< 'thesaurusfunc' callback function 2927 static Callback *cpt_cb; ///< Callback functions associated with F{func} 2928 static int cpt_cb_count; ///< Number of cpt callbacks 2929 2930 /// Copy a global callback function to a buffer local callback. 2931 static void copy_global_to_buflocal_cb(Callback *globcb, Callback *bufcb) 2932 { 2933 callback_free(bufcb); 2934 if (globcb->type != kCallbackNone) { 2935 callback_copy(bufcb, globcb); 2936 } 2937 } 2938 2939 /// Parse the 'completefunc' option value and set the callback function. 2940 /// Invoked when the 'completefunc' option is set. The option value can be a 2941 /// name of a function (string), or function(<name>) or funcref(<name>) or a 2942 /// lambda expression. 2943 const char *did_set_completefunc(optset_T *args) 2944 { 2945 buf_T *buf = (buf_T *)args->os_buf; 2946 int retval; 2947 2948 if (args->os_flags & OPT_LOCAL) { 2949 retval = option_set_callback_func(args->os_newval.string.data, &buf->b_cfu_cb); 2950 } else { 2951 retval = option_set_callback_func(args->os_newval.string.data, &cfu_cb); 2952 if (retval == OK && !(args->os_flags & OPT_GLOBAL)) { 2953 set_buflocal_cfu_callback(buf); 2954 } 2955 } 2956 2957 return retval == FAIL ? e_invarg : NULL; 2958 } 2959 2960 /// Copy the global 'completefunc' callback function to the buffer-local 2961 /// 'completefunc' callback for "buf". 2962 void set_buflocal_cfu_callback(buf_T *buf) 2963 { 2964 copy_global_to_buflocal_cb(&cfu_cb, &buf->b_cfu_cb); 2965 } 2966 2967 /// Parse the 'omnifunc' option value and set the callback function. 2968 /// Invoked when the 'omnifunc' option is set. The option value can be a 2969 /// name of a function (string), or function(<name>) or funcref(<name>) or a 2970 /// lambda expression. 2971 const char *did_set_omnifunc(optset_T *args) 2972 { 2973 buf_T *buf = (buf_T *)args->os_buf; 2974 int retval; 2975 2976 if (args->os_flags & OPT_LOCAL) { 2977 retval = option_set_callback_func(args->os_newval.string.data, &buf->b_ofu_cb); 2978 } else { 2979 retval = option_set_callback_func(args->os_newval.string.data, &ofu_cb); 2980 if (retval == OK && !(args->os_flags & OPT_GLOBAL)) { 2981 set_buflocal_ofu_callback(buf); 2982 } 2983 } 2984 2985 return retval == FAIL ? e_invarg : NULL; 2986 } 2987 2988 /// Copy the global 'omnifunc' callback function to the buffer-local 'omnifunc' 2989 /// callback for "buf". 2990 void set_buflocal_ofu_callback(buf_T *buf) 2991 { 2992 copy_global_to_buflocal_cb(&ofu_cb, &buf->b_ofu_cb); 2993 } 2994 2995 /// Free an array of 'complete' F{func} callbacks and set the pointer to NULL. 2996 void clear_cpt_callbacks(Callback **callbacks, int count) 2997 { 2998 if (callbacks == NULL || *callbacks == NULL) { 2999 return; 3000 } 3001 3002 for (int i = 0; i < count; i++) { 3003 callback_free(&(*callbacks)[i]); 3004 } 3005 3006 XFREE_CLEAR(*callbacks); 3007 } 3008 3009 /// Copies a list of Callback structs from src to *dest, clearing any existing 3010 /// entries and allocating memory for the destination. 3011 static void copy_cpt_callbacks(Callback **dest, int *dest_cnt, Callback *src, int cnt) 3012 { 3013 if (cnt == 0) { 3014 return; 3015 } 3016 3017 clear_cpt_callbacks(dest, *dest_cnt); 3018 *dest = xcalloc((size_t)cnt, sizeof(Callback)); 3019 *dest_cnt = cnt; 3020 3021 for (int i = 0; i < cnt; i++) { 3022 if (src[i].type != kCallbackNone) { 3023 callback_copy(&(*dest)[i], &src[i]); 3024 } 3025 } 3026 } 3027 3028 /// Copy global 'complete' F{func} callbacks into the given buffer's local 3029 /// callback array. Clears any existing buffer-local callbacks first. 3030 void set_buflocal_cpt_callbacks(buf_T *buf) 3031 { 3032 if (buf == NULL || cpt_cb_count == 0) { 3033 return; 3034 } 3035 copy_cpt_callbacks(&buf->b_p_cpt_cb, &buf->b_p_cpt_count, cpt_cb, cpt_cb_count); 3036 } 3037 3038 /// Parse 'complete' option and initialize F{func} callbacks. 3039 /// Frees any existing callbacks and allocates new ones. 3040 /// Only F{func} entries are processed; others are ignored. 3041 int set_cpt_callbacks(optset_T *args) 3042 { 3043 bool local = (args->os_flags & OPT_LOCAL) != 0; 3044 3045 if (curbuf == NULL) { 3046 return FAIL; 3047 } 3048 3049 clear_cpt_callbacks(&curbuf->b_p_cpt_cb, curbuf->b_p_cpt_count); 3050 curbuf->b_p_cpt_count = 0; 3051 3052 int count = get_cpt_sources_count(); 3053 if (count == 0) { 3054 return OK; 3055 } 3056 3057 curbuf->b_p_cpt_cb = xcalloc((size_t)count, sizeof(Callback)); 3058 curbuf->b_p_cpt_count = count; 3059 3060 char buf[LSIZE]; 3061 int idx = 0; 3062 for (char *p = curbuf->b_p_cpt; *p != NUL;) { 3063 while (*p == ',' || *p == ' ') { 3064 p++; // Skip delimiters 3065 } 3066 if (*p != NUL) { 3067 size_t slen = copy_option_part(&p, buf, LSIZE, ","); // Advance p 3068 if (slen > 0 && buf[0] == 'F' && buf[1] != NUL) { 3069 char *caret = vim_strchr(buf, '^'); 3070 if (caret != NULL) { 3071 *caret = NUL; 3072 } 3073 if (option_set_callback_func(buf + 1, &curbuf->b_p_cpt_cb[idx]) != OK) { 3074 curbuf->b_p_cpt_cb[idx].type = kCallbackNone; 3075 } 3076 } 3077 idx++; 3078 } 3079 } 3080 3081 if (!local) { // ':set' used instead of ':setlocal' 3082 // Cache the callback array 3083 copy_cpt_callbacks(&cpt_cb, &cpt_cb_count, curbuf->b_p_cpt_cb, 3084 curbuf->b_p_cpt_count); 3085 } 3086 3087 return OK; 3088 } 3089 3090 /// Parse the 'thesaurusfunc' option value and set the callback function. 3091 /// Invoked when the 'thesaurusfunc' option is set. The option value can be a 3092 /// name of a function (string), or function(<name>) or funcref(<name>) or a 3093 /// lambda expression. 3094 const char *did_set_thesaurusfunc(optset_T *args FUNC_ATTR_UNUSED) 3095 { 3096 buf_T *buf = (buf_T *)args->os_buf; 3097 int retval; 3098 3099 if (args->os_flags & OPT_LOCAL) { 3100 // buffer-local option set 3101 retval = option_set_callback_func(buf->b_p_tsrfu, &buf->b_tsrfu_cb); 3102 } else { 3103 // global option set 3104 retval = option_set_callback_func(p_tsrfu, &tsrfu_cb); 3105 // when using :set, free the local callback 3106 if (!(args->os_flags & OPT_GLOBAL)) { 3107 callback_free(&buf->b_tsrfu_cb); 3108 } 3109 } 3110 3111 return retval == FAIL ? e_invarg : NULL; 3112 } 3113 3114 /// Mark "copyID" references in an array of F{func} callbacks so that they are 3115 /// not garbage collected. 3116 bool set_ref_in_cpt_callbacks(Callback *callbacks, int count, int copyID) 3117 { 3118 bool abort = false; 3119 3120 if (callbacks == NULL) { 3121 return false; 3122 } 3123 3124 for (int i = 0; i < count; i++) { 3125 abort = abort || set_ref_in_callback(&callbacks[i], copyID, NULL, NULL); 3126 } 3127 return abort; 3128 } 3129 3130 /// Mark the global 'completefunc' 'omnifunc' and 'thesaurusfunc' callbacks with 3131 /// "copyID" so that they are not garbage collected. 3132 bool set_ref_in_insexpand_funcs(int copyID) 3133 { 3134 bool abort = set_ref_in_callback(&cfu_cb, copyID, NULL, NULL); 3135 abort = abort || set_ref_in_callback(&ofu_cb, copyID, NULL, NULL); 3136 abort = abort || set_ref_in_callback(&tsrfu_cb, copyID, NULL, NULL); 3137 abort = abort || set_ref_in_cpt_callbacks(cpt_cb, cpt_cb_count, copyID); 3138 3139 return abort; 3140 } 3141 3142 /// Get the user-defined completion function name for completion "type" 3143 static char *get_complete_funcname(int type) 3144 { 3145 switch (type) { 3146 case CTRL_X_FUNCTION: 3147 return curbuf->b_p_cfu; 3148 case CTRL_X_OMNI: 3149 return curbuf->b_p_ofu; 3150 case CTRL_X_THESAURUS: 3151 return *curbuf->b_p_tsrfu == NUL ? p_tsrfu : curbuf->b_p_tsrfu; 3152 default: 3153 return ""; 3154 } 3155 } 3156 3157 /// Get the callback to use for insert mode completion. 3158 static Callback *get_insert_callback(int type) 3159 { 3160 if (type == CTRL_X_FUNCTION) { 3161 return &curbuf->b_cfu_cb; 3162 } 3163 if (type == CTRL_X_OMNI) { 3164 return &curbuf->b_ofu_cb; 3165 } 3166 // CTRL_X_THESAURUS 3167 return (*curbuf->b_p_tsrfu != NUL) ? &curbuf->b_tsrfu_cb : &tsrfu_cb; 3168 } 3169 3170 /// Execute user defined complete function 'completefunc', 'omnifunc' or 3171 /// 'thesaurusfunc', and get matches in "matches". 3172 /// 3173 /// @param type one of CTRL_X_OMNI or CTRL_X_FUNCTION or CTRL_X_THESAURUS 3174 /// @param cb set if triggered by a function in 'cpt' option, otherwise NULL 3175 static void expand_by_function(int type, char *base, Callback *cb) 3176 { 3177 list_T *matchlist = NULL; 3178 dict_T *matchdict = NULL; 3179 typval_T rettv; 3180 const int save_State = State; 3181 3182 assert(curbuf != NULL); 3183 3184 const bool is_cpt_function = (cb != NULL); 3185 if (!is_cpt_function) { 3186 char *funcname = get_complete_funcname(type); 3187 if (*funcname == NUL) { 3188 return; 3189 } 3190 cb = get_insert_callback(type); 3191 } 3192 3193 // Call 'completefunc' to obtain the list of matches. 3194 typval_T args[3]; 3195 args[0].v_type = VAR_NUMBER; 3196 args[1].v_type = VAR_STRING; 3197 args[2].v_type = VAR_UNKNOWN; 3198 args[0].vval.v_number = 0; 3199 args[1].vval.v_string = base != NULL ? base : ""; 3200 3201 pos_T pos = curwin->w_cursor; 3202 // Lock the text to avoid weird things from happening. Also disallow 3203 // switching to another window, it should not be needed and may end up in 3204 // Insert mode in another buffer. 3205 textlock++; 3206 3207 // Call a function, which returns a list or dict. 3208 if (callback_call(cb, 2, args, &rettv)) { 3209 switch (rettv.v_type) { 3210 case VAR_LIST: 3211 matchlist = rettv.vval.v_list; 3212 break; 3213 case VAR_DICT: 3214 matchdict = rettv.vval.v_dict; 3215 break; 3216 case VAR_SPECIAL: 3217 FALLTHROUGH; 3218 default: 3219 // TODO(brammool): Give error message? 3220 tv_clear(&rettv); 3221 break; 3222 } 3223 } 3224 textlock--; 3225 3226 curwin->w_cursor = pos; // restore the cursor position 3227 check_cursor(curwin); // make sure cursor position is valid, just in case 3228 validate_cursor(curwin); 3229 if (!equalpos(curwin->w_cursor, pos)) { 3230 emsg(_(e_compldel)); 3231 goto theend; 3232 } 3233 3234 if (matchlist != NULL) { 3235 ins_compl_add_list(matchlist); 3236 } else if (matchdict != NULL) { 3237 ins_compl_add_dict(matchdict); 3238 } 3239 3240 theend: 3241 // Restore State, it might have been changed. 3242 State = save_State; 3243 3244 if (matchdict != NULL) { 3245 tv_dict_unref(matchdict); 3246 } 3247 if (matchlist != NULL) { 3248 tv_list_unref(matchlist); 3249 } 3250 } 3251 3252 static inline int get_user_highlight_attr(const char *hlname) 3253 { 3254 if (hlname != NULL && *hlname != NUL) { 3255 return syn_name2attr(hlname); 3256 } 3257 return -1; 3258 } 3259 3260 /// Add a match to the list of matches from Vimscript object 3261 /// 3262 /// @param[in] tv Object to get matches from. 3263 /// @param[in] dir Completion direction. 3264 /// @param[in] fast use fast_breakcheck() instead of os_breakcheck(). 3265 /// 3266 /// @return NOTDONE if the given string is already in the list of completions, 3267 /// otherwise it is added to the list and OK is returned. FAIL will be 3268 /// returned in case of error. 3269 static int ins_compl_add_tv(typval_T *const tv, const Direction dir, bool fast) 3270 FUNC_ATTR_NONNULL_ALL 3271 { 3272 const char *word; 3273 bool dup = false; 3274 bool empty = false; 3275 int flags = fast ? CP_FAST : 0; 3276 char *(cptext[CPT_COUNT]); 3277 char *user_abbr_hlname = NULL; 3278 char *user_kind_hlname = NULL; 3279 int user_hl[2] = { -1, -1 }; 3280 typval_T user_data; 3281 3282 user_data.v_type = VAR_UNKNOWN; 3283 if (tv->v_type == VAR_DICT && tv->vval.v_dict != NULL) { 3284 word = tv_dict_get_string(tv->vval.v_dict, "word", false); 3285 cptext[CPT_ABBR] = tv_dict_get_string(tv->vval.v_dict, "abbr", true); 3286 cptext[CPT_MENU] = tv_dict_get_string(tv->vval.v_dict, "menu", true); 3287 cptext[CPT_KIND] = tv_dict_get_string(tv->vval.v_dict, "kind", true); 3288 cptext[CPT_INFO] = tv_dict_get_string(tv->vval.v_dict, "info", true); 3289 3290 user_abbr_hlname = tv_dict_get_string(tv->vval.v_dict, "abbr_hlgroup", false); 3291 user_hl[0] = get_user_highlight_attr(user_abbr_hlname); 3292 3293 user_kind_hlname = tv_dict_get_string(tv->vval.v_dict, "kind_hlgroup", false); 3294 user_hl[1] = get_user_highlight_attr(user_kind_hlname); 3295 3296 tv_dict_get_tv(tv->vval.v_dict, "user_data", &user_data); 3297 3298 if (tv_dict_get_number(tv->vval.v_dict, "icase")) { 3299 flags |= CP_ICASE; 3300 } 3301 dup = (bool)tv_dict_get_number(tv->vval.v_dict, "dup"); 3302 empty = (bool)tv_dict_get_number(tv->vval.v_dict, "empty"); 3303 if (tv_dict_get_string(tv->vval.v_dict, "equal", false) != NULL 3304 && tv_dict_get_number(tv->vval.v_dict, "equal")) { 3305 flags |= CP_EQUAL; 3306 } 3307 } else { 3308 word = tv_get_string_chk(tv); 3309 CLEAR_FIELD(cptext); 3310 } 3311 if (word == NULL || (!empty && *word == NUL)) { 3312 free_cptext(cptext); 3313 tv_clear(&user_data); 3314 return FAIL; 3315 } 3316 int status = ins_compl_add((char *)word, -1, NULL, cptext, true, 3317 &user_data, dir, flags, dup, user_hl, FUZZY_SCORE_NONE); 3318 if (status != OK) { 3319 tv_clear(&user_data); 3320 } 3321 return status; 3322 } 3323 3324 /// Add completions from a list. 3325 static void ins_compl_add_list(list_T *const list) 3326 { 3327 Direction dir = compl_direction; 3328 3329 // Go through the List with matches and add each of them. 3330 TV_LIST_ITER(list, li, { 3331 if (ins_compl_add_tv(TV_LIST_ITEM_TV(li), dir, true) == OK) { 3332 // If dir was BACKWARD then honor it just once. 3333 dir = FORWARD; 3334 } else if (did_emsg) { 3335 break; 3336 } 3337 }); 3338 } 3339 3340 /// Add completions from a dict. 3341 static void ins_compl_add_dict(dict_T *dict) 3342 { 3343 // Check for optional "refresh" item. 3344 compl_opt_refresh_always = false; 3345 dictitem_T *di_refresh = tv_dict_find(dict, S_LEN("refresh")); 3346 if (di_refresh != NULL && di_refresh->di_tv.v_type == VAR_STRING) { 3347 const char *v = di_refresh->di_tv.vval.v_string; 3348 3349 if (v != NULL && strcmp(v, "always") == 0) { 3350 compl_opt_refresh_always = true; 3351 } 3352 } 3353 3354 // Add completions from a "words" list. 3355 dictitem_T *di_words = tv_dict_find(dict, S_LEN("words")); 3356 if (di_words != NULL && di_words->di_tv.v_type == VAR_LIST) { 3357 ins_compl_add_list(di_words->di_tv.vval.v_list); 3358 } 3359 } 3360 3361 /// Save extmarks in "compl_orig_text" so that they may be restored when the 3362 /// completion is cancelled, or the original text is completed. 3363 static void save_orig_extmarks(void) 3364 { 3365 extmark_splice_delete(curbuf, curwin->w_cursor.lnum - 1, compl_col, curwin->w_cursor.lnum - 1, 3366 compl_col + compl_length, &compl_orig_extmarks, true, kExtmarkUndo); 3367 } 3368 3369 static void restore_orig_extmarks(void) 3370 { 3371 for (long i = (int)kv_size(compl_orig_extmarks) - 1; i > -1; i--) { 3372 ExtmarkUndoObject undo_info = kv_A(compl_orig_extmarks, i); 3373 extmark_apply_undo(undo_info, true); 3374 } 3375 } 3376 3377 /// Start completion for the complete() function. 3378 /// 3379 /// @param startcol where the matched text starts (1 is first column). 3380 /// @param list the list of matches. 3381 static void set_completion(colnr_T startcol, list_T *list) 3382 { 3383 int flags = CP_ORIGINAL_TEXT; 3384 unsigned cur_cot_flags = get_cot_flags(); 3385 bool compl_longest = (cur_cot_flags & kOptCotFlagLongest) != 0; 3386 bool compl_no_insert = (cur_cot_flags & kOptCotFlagNoinsert) != 0; 3387 bool compl_no_select = (cur_cot_flags & kOptCotFlagNoselect) != 0; 3388 3389 // If already doing completions stop it. 3390 if (ctrl_x_mode_not_default()) { 3391 ins_compl_prep(' '); 3392 } 3393 ins_compl_clear(); 3394 ins_compl_free(); 3395 compl_get_longest = compl_longest; 3396 3397 compl_direction = FORWARD; 3398 if (startcol > curwin->w_cursor.col) { 3399 startcol = curwin->w_cursor.col; 3400 } 3401 compl_col = startcol; 3402 compl_lnum = curwin->w_cursor.lnum; 3403 compl_length = curwin->w_cursor.col - startcol; 3404 // compl_pattern doesn't need to be set 3405 compl_orig_text = cbuf_to_string(get_cursor_line_ptr() + compl_col, 3406 (size_t)compl_length); 3407 save_orig_extmarks(); 3408 if (p_ic) { 3409 flags |= CP_ICASE; 3410 } 3411 if (ins_compl_add(compl_orig_text.data, (int)compl_orig_text.size, 3412 NULL, NULL, false, NULL, 0, 3413 flags | CP_FAST, false, NULL, FUZZY_SCORE_NONE) != OK) { 3414 return; 3415 } 3416 3417 ctrl_x_mode = CTRL_X_EVAL; 3418 3419 ins_compl_add_list(list); 3420 compl_matches = ins_compl_make_cyclic(); 3421 compl_started = true; 3422 compl_used_match = true; 3423 compl_cont_status = 0; 3424 int save_w_wrow = curwin->w_wrow; 3425 int save_w_leftcol = curwin->w_leftcol; 3426 3427 compl_curr_match = compl_first_match; 3428 bool no_select = compl_no_select || compl_longest; 3429 if (compl_no_insert || no_select) { 3430 ins_complete(K_DOWN, false); 3431 if (no_select) { 3432 ins_complete(K_UP, false); 3433 } 3434 } else { 3435 ins_complete(Ctrl_N, false); 3436 } 3437 compl_enter_selects = compl_no_insert; 3438 3439 // Lazily show the popup menu, unless we got interrupted. 3440 if (!compl_interrupted) { 3441 show_pum(save_w_wrow, save_w_leftcol); 3442 } 3443 3444 may_trigger_modechanged(); 3445 ui_flush(); 3446 } 3447 3448 /// "complete()" function 3449 void f_complete(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) 3450 { 3451 if ((State & MODE_INSERT) == 0) { 3452 emsg(_("E785: complete() can only be used in Insert mode")); 3453 return; 3454 } 3455 3456 // Check for undo allowed here, because if something was already inserted 3457 // the line was already saved for undo and this check isn't done. 3458 if (!undo_allowed(curbuf)) { 3459 return; 3460 } 3461 3462 if (argvars[1].v_type != VAR_LIST) { 3463 emsg(_(e_invarg)); 3464 } else { 3465 const colnr_T startcol = (colnr_T)tv_get_number_chk(&argvars[0], NULL); 3466 if (startcol > 0) { 3467 set_completion(startcol - 1, argvars[1].vval.v_list); 3468 } 3469 } 3470 } 3471 3472 /// "complete_add()" function 3473 void f_complete_add(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) 3474 { 3475 rettv->vval.v_number = ins_compl_add_tv(&argvars[0], 0, false); 3476 } 3477 3478 /// "complete_check()" function 3479 void f_complete_check(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) 3480 { 3481 int saved = RedrawingDisabled; 3482 3483 RedrawingDisabled = 0; 3484 ins_compl_check_keys(0, true); 3485 rettv->vval.v_number = ins_compl_interrupted(); 3486 RedrawingDisabled = saved; 3487 } 3488 3489 /// Return Insert completion mode name string 3490 static char *ins_compl_mode(void) 3491 { 3492 if (ctrl_x_mode_not_defined_yet() || ctrl_x_mode_scroll() || compl_started) { 3493 return ctrl_x_mode_names[ctrl_x_mode & ~CTRL_X_WANT_IDENT]; 3494 } 3495 return ""; 3496 } 3497 3498 /// Assign the sequence number to all the completion matches which don't have 3499 /// one assigned yet. 3500 static void ins_compl_update_sequence_numbers(void) 3501 { 3502 int number = 0; 3503 compl_T *match; 3504 3505 if (compl_dir_forward()) { 3506 // Search backwards for the first valid (!= -1) number. 3507 // This should normally succeed already at the first loop 3508 // cycle, so it's fast! 3509 for (match = compl_curr_match->cp_prev; 3510 match != NULL && !is_first_match(match); match = match->cp_prev) { 3511 if (match->cp_number != -1) { 3512 number = match->cp_number; 3513 break; 3514 } 3515 } 3516 if (match != NULL) { 3517 // go up and assign all numbers which are not assigned yet 3518 for (match = match->cp_next; 3519 match != NULL && match->cp_number == -1; 3520 match = match->cp_next) { 3521 match->cp_number = ++number; 3522 } 3523 } 3524 } else { // BACKWARD 3525 assert(compl_direction == BACKWARD); 3526 // Search forwards (upwards) for the first valid (!= -1) 3527 // number. This should normally succeed already at the 3528 // first loop cycle, so it's fast! 3529 for (match = compl_curr_match->cp_next; 3530 match != NULL && !is_first_match(match); match = match->cp_next) { 3531 if (match->cp_number != -1) { 3532 number = match->cp_number; 3533 break; 3534 } 3535 } 3536 if (match != NULL) { 3537 // go down and assign all numbers which are not assigned yet 3538 for (match = match->cp_prev; 3539 match && match->cp_number == -1; 3540 match = match->cp_prev) { 3541 match->cp_number = ++number; 3542 } 3543 } 3544 } 3545 } 3546 3547 /// Fill the dict of complete_info 3548 static void fill_complete_info_dict(dict_T *di, compl_T *match, bool add_match) 3549 { 3550 tv_dict_add_str(di, S_LEN("word"), match->cp_str.data); 3551 tv_dict_add_str(di, S_LEN("abbr"), match->cp_text[CPT_ABBR]); 3552 tv_dict_add_str(di, S_LEN("menu"), match->cp_text[CPT_MENU]); 3553 tv_dict_add_str(di, S_LEN("kind"), match->cp_text[CPT_KIND]); 3554 tv_dict_add_str(di, S_LEN("info"), match->cp_text[CPT_INFO]); 3555 if (add_match) { 3556 tv_dict_add_bool(di, S_LEN("match"), match->cp_in_match_array); 3557 } 3558 if (match->cp_user_data.v_type == VAR_UNKNOWN) { 3559 // Add an empty string for backwards compatibility 3560 tv_dict_add_str(di, S_LEN("user_data"), ""); 3561 } else { 3562 tv_dict_add_tv(di, S_LEN("user_data"), &match->cp_user_data); 3563 } 3564 } 3565 3566 /// Get complete information 3567 static void get_complete_info(list_T *what_list, dict_T *retdict) 3568 { 3569 #define CI_WHAT_MODE 0x01 3570 #define CI_WHAT_PUM_VISIBLE 0x02 3571 #define CI_WHAT_ITEMS 0x04 3572 #define CI_WHAT_SELECTED 0x08 3573 #define CI_WHAT_COMPLETED 0x10 3574 #define CI_WHAT_MATCHES 0x20 3575 #define CI_WHAT_PREINSERTED_TEXT 0x40 3576 #define CI_WHAT_ALL 0xff 3577 int what_flag; 3578 3579 if (what_list == NULL) { 3580 what_flag = CI_WHAT_ALL & ~(CI_WHAT_MATCHES|CI_WHAT_COMPLETED); 3581 } else { 3582 what_flag = 0; 3583 for (listitem_T *item = tv_list_first(what_list) 3584 ; item != NULL 3585 ; item = TV_LIST_ITEM_NEXT(what_list, item)) { 3586 const char *what = tv_get_string(TV_LIST_ITEM_TV(item)); 3587 3588 if (strcmp(what, "mode") == 0) { 3589 what_flag |= CI_WHAT_MODE; 3590 } else if (strcmp(what, "pum_visible") == 0) { 3591 what_flag |= CI_WHAT_PUM_VISIBLE; 3592 } else if (strcmp(what, "items") == 0) { 3593 what_flag |= CI_WHAT_ITEMS; 3594 } else if (strcmp(what, "selected") == 0) { 3595 what_flag |= CI_WHAT_SELECTED; 3596 } else if (strcmp(what, "completed") == 0) { 3597 what_flag |= CI_WHAT_COMPLETED; 3598 } else if (strcmp(what, "preinserted_text") == 0) { 3599 what_flag |= CI_WHAT_PREINSERTED_TEXT; 3600 } else if (strcmp(what, "matches") == 0) { 3601 what_flag |= CI_WHAT_MATCHES; 3602 } 3603 } 3604 } 3605 3606 int ret = OK; 3607 if (what_flag & CI_WHAT_MODE) { 3608 ret = tv_dict_add_str(retdict, S_LEN("mode"), ins_compl_mode()); 3609 } 3610 3611 if (ret == OK && (what_flag & CI_WHAT_PUM_VISIBLE)) { 3612 ret = tv_dict_add_nr(retdict, S_LEN("pum_visible"), pum_visible()); 3613 } 3614 3615 if (ret == OK && (what_flag & CI_WHAT_PREINSERTED_TEXT)) { 3616 char *line = get_cursor_line_ptr(); 3617 int len = compl_ins_end_col - curwin->w_cursor.col; 3618 ret = tv_dict_add_str_len(retdict, S_LEN("preinserted_text"), 3619 len > 0 ? line + curwin->w_cursor.col : "", MAX(len, 0)); 3620 } 3621 3622 if (ret == OK && (what_flag & (CI_WHAT_ITEMS|CI_WHAT_SELECTED 3623 |CI_WHAT_MATCHES|CI_WHAT_COMPLETED))) { 3624 list_T *li = NULL; 3625 int selected_idx = -1; 3626 bool has_items = what_flag & CI_WHAT_ITEMS; 3627 bool has_matches = what_flag & CI_WHAT_MATCHES; 3628 bool has_completed = what_flag & CI_WHAT_COMPLETED; 3629 if (has_items || has_matches) { 3630 li = tv_list_alloc(kListLenMayKnow); 3631 const char *key = (has_matches && !has_items) ? "matches" : "items"; 3632 ret = tv_dict_add_list(retdict, key, strlen(key), li); 3633 } 3634 if (ret == OK && what_flag & CI_WHAT_SELECTED) { 3635 if (compl_curr_match != NULL && compl_curr_match->cp_number == -1) { 3636 ins_compl_update_sequence_numbers(); 3637 } 3638 } 3639 if (ret == OK && compl_first_match != NULL) { 3640 int list_idx = 0; 3641 compl_T *match = compl_first_match; 3642 do { 3643 if (!match_at_original_text(match)) { 3644 if (has_items || (has_matches && match->cp_in_match_array)) { 3645 dict_T *di = tv_dict_alloc(); 3646 tv_list_append_dict(li, di); 3647 fill_complete_info_dict(di, match, has_matches && has_items); 3648 } 3649 if (compl_curr_match != NULL 3650 && compl_curr_match->cp_number == match->cp_number) { 3651 selected_idx = list_idx; 3652 } 3653 if (!has_matches || match->cp_in_match_array) { 3654 list_idx++; 3655 } 3656 } 3657 match = match->cp_next; 3658 } while (match != NULL && !is_first_match(match)); 3659 } 3660 if (ret == OK && (what_flag & CI_WHAT_SELECTED)) { 3661 ret = tv_dict_add_nr(retdict, S_LEN("selected"), selected_idx); 3662 win_T *wp = win_float_find_preview(); 3663 if (wp != NULL) { 3664 tv_dict_add_nr(retdict, S_LEN("preview_winid"), wp->handle); 3665 tv_dict_add_nr(retdict, S_LEN("preview_bufnr"), wp->w_buffer->handle); 3666 } 3667 } 3668 if (ret == OK && selected_idx != -1 && has_completed) { 3669 dict_T *di = tv_dict_alloc(); 3670 fill_complete_info_dict(di, compl_curr_match, false); 3671 ret = tv_dict_add_dict(retdict, S_LEN("completed"), di); 3672 } 3673 } 3674 3675 (void)ret; 3676 } 3677 3678 /// "complete_info()" function 3679 void f_complete_info(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) 3680 { 3681 tv_dict_alloc_ret(rettv); 3682 3683 list_T *what_list = NULL; 3684 3685 if (argvars[0].v_type != VAR_UNKNOWN) { 3686 if (argvars[0].v_type != VAR_LIST) { 3687 emsg(_(e_listreq)); 3688 return; 3689 } 3690 what_list = argvars[0].vval.v_list; 3691 } 3692 get_complete_info(what_list, rettv->vval.v_dict); 3693 } 3694 3695 /// Returns true when using a user-defined function for thesaurus completion. 3696 static bool thesaurus_func_complete(int type) 3697 { 3698 return type == CTRL_X_THESAURUS 3699 && (*curbuf->b_p_tsrfu != NUL || *p_tsrfu != NUL); 3700 } 3701 3702 /// Check if 'cpt' list index can be advanced to the next completion source. 3703 static bool may_advance_cpt_index(const char *cpt) 3704 { 3705 const char *p = cpt; 3706 3707 if (cpt_sources_index == -1) { 3708 return false; 3709 } 3710 while (*p == ',' || *p == ' ') { // Skip delimiters 3711 p++; 3712 } 3713 return (*p != NUL); 3714 } 3715 3716 /// Return value of process_next_cpt_value() 3717 enum { 3718 INS_COMPL_CPT_OK = 1, 3719 INS_COMPL_CPT_CONT, 3720 INS_COMPL_CPT_END, 3721 }; 3722 3723 /// Process the next 'complete' option value in st->e_cpt. 3724 /// 3725 /// If successful, the arguments are set as below: 3726 /// st->cpt - pointer to the next option value in "st->cpt" 3727 /// compl_type_arg - type of insert mode completion to use 3728 /// st->found_all - all matches of this type are found 3729 /// st->ins_buf - search for completions in this buffer 3730 /// st->first_match_pos - position of the first completion match 3731 /// st->last_match_pos - position of the last completion match 3732 /// st->set_match_pos - true if the first match position should be saved to 3733 /// avoid loops after the search wraps around. 3734 /// st->dict - name of the dictionary or thesaurus file to search 3735 /// st->dict_f - flag specifying whether "dict" is an exact file name or not 3736 /// 3737 /// @return INS_COMPL_CPT_OK if the next value is processed successfully. 3738 /// INS_COMPL_CPT_CONT to skip the current completion source matching 3739 /// the "st->e_cpt" option value and process the next matching source. 3740 /// INS_COMPL_CPT_END if all the values in "st->e_cpt" are processed. 3741 static int process_next_cpt_value(ins_compl_next_state_T *st, int *compl_type_arg, 3742 pos_T *start_match_pos, bool fuzzy_collect, bool *advance_cpt_idx) 3743 { 3744 int compl_type = -1; 3745 int status = INS_COMPL_CPT_OK; 3746 bool skip_source = compl_autocomplete && compl_from_nonkeyword; 3747 3748 st->found_all = false; 3749 *advance_cpt_idx = false; 3750 3751 while (*st->e_cpt == ',' || *st->e_cpt == ' ') { 3752 st->e_cpt++; 3753 } 3754 3755 if (*st->e_cpt == '.' && !curbuf->b_scanned && !skip_source 3756 && !compl_time_slice_expired) { 3757 st->ins_buf = curbuf; 3758 st->first_match_pos = *start_match_pos; 3759 // Move the cursor back one character so that ^N can match the 3760 // word immediately after the cursor. 3761 if (ctrl_x_mode_normal() && (!fuzzy_collect && dec(&st->first_match_pos) < 0)) { 3762 // Move the cursor to after the last character in the 3763 // buffer, so that word at start of buffer is found 3764 // correctly. 3765 st->first_match_pos.lnum = st->ins_buf->b_ml.ml_line_count; 3766 st->first_match_pos.col = ml_get_len(st->first_match_pos.lnum); 3767 } 3768 st->last_match_pos = st->first_match_pos; 3769 compl_type = 0; 3770 3771 // Remember the first match so that the loop stops when we 3772 // wrap and come back there a second time. 3773 st->set_match_pos = true; 3774 } else if (!skip_source && !compl_time_slice_expired 3775 && vim_strchr("buwU", (uint8_t)(*st->e_cpt)) != NULL 3776 && (st->ins_buf = ins_compl_next_buf(st->ins_buf, *st->e_cpt)) != curbuf) { 3777 // Scan a buffer, but not the current one. 3778 if (st->ins_buf->b_ml.ml_mfp != NULL) { // loaded buffer 3779 compl_started = true; 3780 st->first_match_pos.col = st->last_match_pos.col = 0; 3781 st->first_match_pos.lnum = st->ins_buf->b_ml.ml_line_count + 1; 3782 st->last_match_pos.lnum = 0; 3783 compl_type = 0; 3784 } else { // unloaded buffer, scan like dictionary 3785 st->found_all = true; 3786 if (st->ins_buf->b_fname == NULL) { 3787 status = INS_COMPL_CPT_CONT; 3788 goto done; 3789 } 3790 compl_type = CTRL_X_DICTIONARY; 3791 st->dict = st->ins_buf->b_fname; 3792 st->dict_f = DICT_EXACT; 3793 } 3794 if (!shortmess(SHM_COMPLETIONSCAN) && !compl_autocomplete) { 3795 msg_hist_off = true; // reset in msg_trunc() 3796 msg_ext_overwrite = true; 3797 msg_ext_set_kind("completion"); 3798 vim_snprintf(IObuff, IOSIZE, _("Scanning: %s"), 3799 st->ins_buf->b_fname == NULL 3800 ? buf_spname(st->ins_buf) 3801 : st->ins_buf->b_sfname == NULL 3802 ? st->ins_buf->b_fname 3803 : st->ins_buf->b_sfname); 3804 msg_trunc(IObuff, true, HLF_R); 3805 } 3806 } else if (*st->e_cpt == NUL) { 3807 status = INS_COMPL_CPT_END; 3808 } else { 3809 if (ctrl_x_mode_line_or_eval()) { 3810 // compl_type = -1; 3811 } else if (*st->e_cpt == 'F' || *st->e_cpt == 'o') { 3812 compl_type = CTRL_X_FUNCTION; 3813 st->func_cb = get_callback_if_cpt_func(st->e_cpt, cpt_sources_index); 3814 if (!st->func_cb) { 3815 compl_type = -1; 3816 } 3817 } else if (!skip_source) { 3818 if (*st->e_cpt == 'k' || *st->e_cpt == 's') { 3819 if (*st->e_cpt == 'k') { 3820 compl_type = CTRL_X_DICTIONARY; 3821 } else { 3822 compl_type = CTRL_X_THESAURUS; 3823 } 3824 if (*++st->e_cpt != ',' && *st->e_cpt != NUL) { 3825 st->dict = st->e_cpt; 3826 st->dict_f = DICT_FIRST; 3827 } 3828 } else if (*st->e_cpt == 'i') { 3829 compl_type = CTRL_X_PATH_PATTERNS; 3830 } else if (*st->e_cpt == 'd') { 3831 compl_type = CTRL_X_PATH_DEFINES; 3832 } else if (*st->e_cpt == 'f') { 3833 compl_type = CTRL_X_BUFNAMES; 3834 } else if (*st->e_cpt == ']' || *st->e_cpt == 't') { 3835 compl_type = CTRL_X_TAGS; 3836 if (!shortmess(SHM_COMPLETIONSCAN) && !compl_autocomplete) { 3837 msg_ext_set_kind("completion"); 3838 msg_hist_off = true; // reset in msg_trunc() 3839 msg_ext_overwrite = true; 3840 vim_snprintf(IObuff, IOSIZE, "%s", _("Scanning tags.")); 3841 msg_trunc(IObuff, true, HLF_R); 3842 } 3843 } 3844 } 3845 3846 // in any case e_cpt is advanced to the next entry 3847 copy_option_part(&st->e_cpt, IObuff, IOSIZE, ","); 3848 *advance_cpt_idx = may_advance_cpt_index(st->e_cpt); 3849 3850 st->found_all = true; 3851 if (compl_type == -1) { 3852 status = INS_COMPL_CPT_CONT; 3853 } 3854 } 3855 3856 done: 3857 *compl_type_arg = compl_type; 3858 return status; 3859 } 3860 3861 /// Get the next set of identifiers or defines matching "compl_pattern" in 3862 /// included files. 3863 static void get_next_include_file_completion(int compl_type) 3864 { 3865 find_pattern_in_path(compl_pattern.data, compl_direction, 3866 compl_pattern.size, false, false, 3867 ((compl_type == CTRL_X_PATH_DEFINES 3868 && !(compl_cont_status & CONT_SOL)) 3869 ? FIND_DEFINE : FIND_ANY), 3870 1, ACTION_EXPAND, 1, MAXLNUM, false, compl_autocomplete); 3871 } 3872 3873 /// Get the next set of words matching "compl_pattern" in dictionary or 3874 /// thesaurus files. 3875 static void get_next_dict_tsr_completion(int compl_type, char *dict, int dict_f) 3876 { 3877 if (thesaurus_func_complete(compl_type)) { 3878 expand_by_function(compl_type, compl_pattern.data, NULL); 3879 } else { 3880 ins_compl_dictionaries(dict != NULL 3881 ? dict 3882 : (compl_type == CTRL_X_THESAURUS 3883 ? (*curbuf->b_p_tsr == NUL ? p_tsr : curbuf->b_p_tsr) 3884 : (*curbuf->b_p_dict == NUL ? p_dict : curbuf->b_p_dict)), 3885 compl_pattern.data, 3886 dict != NULL ? dict_f : 0, 3887 compl_type == CTRL_X_THESAURUS); 3888 } 3889 } 3890 3891 /// Get the next set of tag names matching "compl_pattern". 3892 static void get_next_tag_completion(void) 3893 { 3894 // set p_ic according to p_ic, p_scs and pat for find_tags(). 3895 const int save_p_ic = p_ic; 3896 p_ic = ignorecase(compl_pattern.data); 3897 3898 // Find up to TAG_MANY matches. Avoids that an enormous number 3899 // of matches is found when compl_pattern is empty 3900 g_tag_at_cursor = true; 3901 char **matches; 3902 int num_matches; 3903 if (find_tags(compl_pattern.data, &num_matches, &matches, 3904 TAG_REGEXP | TAG_NAMES | TAG_NOIC | TAG_INS_COMP 3905 | (ctrl_x_mode_not_default() ? TAG_VERBOSE : 0), 3906 TAG_MANY, curbuf->b_ffname) == OK && num_matches > 0) { 3907 ins_compl_add_matches(num_matches, matches, p_ic); 3908 } 3909 g_tag_at_cursor = false; 3910 p_ic = save_p_ic; 3911 } 3912 3913 /// Compare function for qsort 3914 static int compare_scores(const void *a, const void *b) 3915 { 3916 int idx_a = *(const int *)a; 3917 int idx_b = *(const int *)b; 3918 int score_a = compl_fuzzy_scores[idx_a]; 3919 int score_b = compl_fuzzy_scores[idx_b]; 3920 return score_a == score_b ? (idx_a == idx_b ? 0 : (idx_a < idx_b ? -1 : 1)) 3921 : (score_a > score_b ? -1 : 1); 3922 } 3923 3924 /// insert prefix with redraw 3925 static void ins_compl_longest_insert(char *prefix) 3926 { 3927 ins_compl_delete(false); 3928 ins_compl_insert_bytes(prefix + get_compl_len(), -1); 3929 ins_redraw(false); 3930 } 3931 3932 /// Calculate the longest common prefix among the best fuzzy matches 3933 /// stored in compl_best_matches, and insert it as the longest. 3934 static void fuzzy_longest_match(void) 3935 { 3936 if (compl_num_bests == 0) { 3937 return; 3938 } 3939 3940 compl_T *nn_compl = compl_first_match->cp_next->cp_next; 3941 bool more_candidates = nn_compl && nn_compl != compl_first_match; 3942 3943 compl_T *compl = ctrl_x_mode_whole_line() ? compl_first_match 3944 : compl_first_match->cp_next; 3945 if (compl_num_bests == 1) { 3946 // no more candidates insert the match str 3947 if (!more_candidates) { 3948 ins_compl_longest_insert(compl->cp_str.data); 3949 compl_num_bests = 0; 3950 } 3951 compl_num_bests = 0; 3952 return; 3953 } 3954 3955 compl_best_matches = (compl_T **)xmalloc((size_t)compl_num_bests * sizeof(compl_T *)); 3956 3957 for (int i = 0; compl != NULL && i < compl_num_bests; i++) { 3958 compl_best_matches[i] = compl; 3959 compl = compl->cp_next; 3960 } 3961 3962 char *prefix = compl_best_matches[0]->cp_str.data; 3963 int prefix_len = (int)compl_best_matches[0]->cp_str.size; 3964 3965 for (int i = 1; i < compl_num_bests; i++) { 3966 char *match_str = compl_best_matches[i]->cp_str.data; 3967 char *prefix_ptr = prefix; 3968 char *match_ptr = match_str; 3969 int j = 0; 3970 3971 while (j < prefix_len && *match_ptr != NUL && *prefix_ptr != NUL) { 3972 if (strncmp(prefix_ptr, match_ptr, (size_t)utfc_ptr2len(prefix_ptr)) != 0) { 3973 break; 3974 } 3975 3976 MB_PTR_ADV(prefix_ptr); 3977 MB_PTR_ADV(match_ptr); 3978 j++; 3979 } 3980 3981 if (j > 0) { 3982 prefix_len = j; 3983 } 3984 } 3985 3986 char *leader = ins_compl_leader(); 3987 size_t leader_len = ins_compl_leader_len(); 3988 3989 // skip non-consecutive prefixes 3990 if (leader_len > 0 && strncmp(prefix, leader, leader_len) != 0) { 3991 goto end; 3992 } 3993 3994 prefix = xmemdupz(prefix, (size_t)prefix_len); 3995 ins_compl_longest_insert(prefix); 3996 xfree(prefix); 3997 3998 end: 3999 xfree(compl_best_matches); 4000 compl_best_matches = NULL; 4001 compl_num_bests = 0; 4002 } 4003 4004 /// Get the next set of filename matching "compl_pattern". 4005 static void get_next_filename_completion(void) 4006 { 4007 char **matches; 4008 int num_matches; 4009 char *leader = ins_compl_leader(); 4010 size_t leader_len = ins_compl_leader_len(); 4011 bool in_fuzzy_collect = (cot_fuzzy() && leader_len > 0); 4012 bool need_collect_bests = in_fuzzy_collect && compl_get_longest; 4013 int max_score = 0; 4014 Direction dir = compl_direction; 4015 4016 #ifdef BACKSLASH_IN_FILENAME 4017 char pathsep = (curbuf->b_p_csl[0] == 's') 4018 ? '/' : (curbuf->b_p_csl[0] == 'b') ? '\\' : PATHSEP; 4019 #else 4020 char pathsep = PATHSEP; 4021 #endif 4022 4023 if (in_fuzzy_collect) { 4024 #ifdef BACKSLASH_IN_FILENAME 4025 if (curbuf->b_p_csl[0] == 's') { 4026 for (size_t i = 0; i < leader_len; i++) { 4027 if (leader[i] == '\\') { 4028 leader[i] = '/'; 4029 } 4030 } 4031 } else if (curbuf->b_p_csl[0] == 'b') { 4032 for (size_t i = 0; i < leader_len; i++) { 4033 if (leader[i] == '/') { 4034 leader[i] = '\\'; 4035 } 4036 } 4037 } 4038 #endif 4039 char *last_sep = strrchr(leader, pathsep); 4040 if (last_sep == NULL) { 4041 // No path separator or separator is the last character, 4042 // fuzzy match the whole leader 4043 API_CLEAR_STRING(compl_pattern); 4044 compl_pattern = cbuf_to_string("*", 1); 4045 } else if (*(last_sep + 1) == NUL) { 4046 in_fuzzy_collect = false; 4047 } else { 4048 // Split leader into path and file parts 4049 size_t path_len = (size_t)(last_sep - leader) + 1; 4050 char *path_with_wildcard = xmalloc(path_len + 2); 4051 vim_snprintf(path_with_wildcard, path_len + 2, "%*.*s*", 4052 (int)path_len, (int)path_len, leader); 4053 API_CLEAR_STRING(compl_pattern); 4054 compl_pattern.data = path_with_wildcard; 4055 compl_pattern.size = path_len + 1; 4056 4057 // Move leader to the file part 4058 leader = last_sep + 1; 4059 leader_len -= path_len; 4060 } 4061 } 4062 4063 if (expand_wildcards(1, &compl_pattern.data, &num_matches, &matches, 4064 EW_FILE|EW_DIR|EW_ADDSLASH|EW_SILENT) != OK) { 4065 return; 4066 } 4067 4068 // May change home directory back to "~". 4069 tilde_replace(compl_pattern.data, num_matches, matches); 4070 #ifdef BACKSLASH_IN_FILENAME 4071 if (curbuf->b_p_csl[0] != NUL) { 4072 for (int i = 0; i < num_matches; i++) { 4073 char *ptr = matches[i]; 4074 while (*ptr != NUL) { 4075 if (curbuf->b_p_csl[0] == 's' && *ptr == '\\') { 4076 *ptr = '/'; 4077 } else if (curbuf->b_p_csl[0] == 'b' && *ptr == '/') { 4078 *ptr = '\\'; 4079 } 4080 ptr += utfc_ptr2len(ptr); 4081 } 4082 } 4083 } 4084 #endif 4085 4086 if (in_fuzzy_collect) { 4087 garray_T fuzzy_indices; 4088 ga_init(&fuzzy_indices, sizeof(int), 10); 4089 compl_fuzzy_scores = (int *)xmalloc(sizeof(int) * (size_t)num_matches); 4090 4091 for (int i = 0; i < num_matches; i++) { 4092 char *ptr = matches[i]; 4093 int score = fuzzy_match_str(ptr, leader); 4094 if (score != FUZZY_SCORE_NONE) { 4095 GA_APPEND(int, &fuzzy_indices, i); 4096 compl_fuzzy_scores[i] = score; 4097 } 4098 } 4099 4100 // prevent qsort from deref NULL pointer 4101 if (fuzzy_indices.ga_len > 0) { 4102 int *fuzzy_indices_data = (int *)fuzzy_indices.ga_data; 4103 qsort(fuzzy_indices_data, (size_t)fuzzy_indices.ga_len, sizeof(int), compare_scores); 4104 4105 for (int i = 0; i < fuzzy_indices.ga_len; i++) { 4106 char *match = matches[fuzzy_indices_data[i]]; 4107 int current_score = compl_fuzzy_scores[fuzzy_indices_data[i]]; 4108 if (ins_compl_add(match, -1, NULL, NULL, false, NULL, dir, 4109 CP_FAST | ((p_fic || p_wic) ? CP_ICASE : 0), 4110 false, NULL, current_score) == OK) { 4111 dir = FORWARD; 4112 } 4113 4114 if (need_collect_bests) { 4115 if (i == 0 || current_score == max_score) { 4116 compl_num_bests++; 4117 max_score = current_score; 4118 } 4119 } 4120 } 4121 4122 FreeWild(num_matches, matches); 4123 } else if (leader_len > 0) { 4124 FreeWild(num_matches, matches); 4125 num_matches = 0; 4126 } 4127 4128 xfree(compl_fuzzy_scores); 4129 ga_clear(&fuzzy_indices); 4130 4131 if (compl_num_bests > 0 && compl_get_longest) { 4132 fuzzy_longest_match(); 4133 } 4134 return; 4135 } 4136 4137 if (num_matches > 0) { 4138 ins_compl_add_matches(num_matches, matches, p_fic || p_wic); 4139 } 4140 } 4141 4142 /// Get the next set of command-line completions matching "compl_pattern". 4143 static void get_next_cmdline_completion(void) 4144 { 4145 char **matches; 4146 int num_matches; 4147 if (expand_cmdline(&compl_xp, compl_pattern.data, 4148 (int)compl_pattern.size, &num_matches, &matches) == EXPAND_OK) { 4149 ins_compl_add_matches(num_matches, matches, false); 4150 } 4151 } 4152 4153 /// Get the next set of spell suggestions matching "compl_pattern". 4154 static void get_next_spell_completion(linenr_T lnum) 4155 { 4156 char **matches; 4157 int num_matches = expand_spelling(lnum, compl_pattern.data, &matches); 4158 if (num_matches > 0) { 4159 ins_compl_add_matches(num_matches, matches, p_ic); 4160 } else { 4161 xfree(matches); 4162 } 4163 } 4164 4165 /// Return the next word or line from buffer "ins_buf" at position 4166 /// "cur_match_pos" for completion. The length of the match is set in "len". 4167 /// @param ins_buf buffer being scanned 4168 /// @param cur_match_pos current match position 4169 /// @param match_len 4170 /// @param cont_s_ipos next ^X<> will set initial_pos 4171 static char *ins_compl_get_next_word_or_line(buf_T *ins_buf, pos_T *cur_match_pos, int *match_len, 4172 bool *cont_s_ipos) 4173 { 4174 *match_len = 0; 4175 char *ptr = ml_get_buf(ins_buf, cur_match_pos->lnum) + cur_match_pos->col; 4176 int len = ml_get_buf_len(ins_buf, cur_match_pos->lnum) - cur_match_pos->col; 4177 if (ctrl_x_mode_line_or_eval()) { 4178 if (compl_status_adding()) { 4179 if (cur_match_pos->lnum >= ins_buf->b_ml.ml_line_count) { 4180 return NULL; 4181 } 4182 ptr = ml_get_buf(ins_buf, cur_match_pos->lnum + 1); 4183 len = ml_get_buf_len(ins_buf, cur_match_pos->lnum + 1); 4184 if (!p_paste) { 4185 char *tmp_ptr = ptr; 4186 ptr = skipwhite(tmp_ptr); 4187 len -= (int)(ptr - tmp_ptr); 4188 } 4189 } 4190 } else { 4191 char *tmp_ptr = ptr; 4192 4193 if (compl_status_adding() && compl_length <= len) { 4194 tmp_ptr += compl_length; 4195 // Skip if already inside a word. 4196 if (vim_iswordp(tmp_ptr)) { 4197 return NULL; 4198 } 4199 // Find start of next word. 4200 tmp_ptr = find_word_start(tmp_ptr); 4201 } 4202 // Find end of this word. 4203 tmp_ptr = find_word_end(tmp_ptr); 4204 len = (int)(tmp_ptr - ptr); 4205 4206 if (compl_status_adding() && len == compl_length) { 4207 if (cur_match_pos->lnum < ins_buf->b_ml.ml_line_count) { 4208 // Try next line, if any. the new word will be "join" as if the 4209 // normal command "J" was used. IOSIZE is always greater than 4210 // compl_length, so the next strncpy always works -- Acevedo 4211 strncpy(IObuff, ptr, (size_t)len); // NOLINT(runtime/printf) 4212 ptr = ml_get_buf(ins_buf, cur_match_pos->lnum + 1); 4213 tmp_ptr = ptr = skipwhite(ptr); 4214 // Find start of next word. 4215 tmp_ptr = find_word_start(tmp_ptr); 4216 // Find end of next word. 4217 tmp_ptr = find_word_end(tmp_ptr); 4218 if (tmp_ptr > ptr) { 4219 if (*ptr != ')' && IObuff[len - 1] != TAB) { 4220 if (IObuff[len - 1] != ' ') { 4221 IObuff[len++] = ' '; 4222 } 4223 // IObuf =~ "\k.* ", thus len >= 2 4224 if (p_js 4225 && (IObuff[len - 2] == '.' 4226 || IObuff[len - 2] == '?' 4227 || IObuff[len - 2] == '!')) { 4228 IObuff[len++] = ' '; 4229 } 4230 } 4231 // copy as much as possible of the new word 4232 if (tmp_ptr - ptr >= IOSIZE - len) { 4233 tmp_ptr = ptr + IOSIZE - len - 1; 4234 } 4235 xstrlcpy(IObuff + len, ptr, (size_t)(IOSIZE - len)); 4236 len += (int)(tmp_ptr - ptr); 4237 *cont_s_ipos = true; 4238 } 4239 IObuff[len] = NUL; 4240 ptr = IObuff; 4241 } 4242 if (len == compl_length) { 4243 return NULL; 4244 } 4245 } 4246 } 4247 4248 *match_len = len; 4249 return ptr; 4250 } 4251 4252 /// Get the next set of words matching "compl_pattern" for default completion(s) 4253 /// (normal ^P/^N and ^X^L). 4254 /// Search for "compl_pattern" in the buffer "st->ins_buf" starting from the 4255 /// position "st->start_pos" in the "compl_direction" direction. If 4256 /// "st->set_match_pos" is true, then set the "st->first_match_pos" and 4257 /// "st->last_match_pos". 4258 /// 4259 /// @return OK if a new next match is found, otherwise FAIL. 4260 static int get_next_default_completion(ins_compl_next_state_T *st, pos_T *start_pos) 4261 { 4262 char *ptr = NULL; 4263 int len = 0; 4264 bool in_fuzzy_collect = !compl_status_adding() && cot_fuzzy() && compl_length > 0; 4265 char *leader = ins_compl_leader(); 4266 int score = FUZZY_SCORE_NONE; 4267 const bool in_curbuf = st->ins_buf == curbuf; 4268 4269 // If 'infercase' is set, don't use 'smartcase' here 4270 const int save_p_scs = p_scs; 4271 assert(st->ins_buf); 4272 if (st->ins_buf->b_p_inf) { 4273 p_scs = false; 4274 } 4275 4276 // Buffers other than curbuf are scanned from the beginning or the 4277 // end but never from the middle, thus setting nowrapscan in this 4278 // buffers is a good idea, on the other hand, we always set 4279 // wrapscan for curbuf to avoid missing matches -- Acevedo,Webb 4280 const int save_p_ws = p_ws; 4281 if (!in_curbuf) { 4282 p_ws = false; 4283 } else if (*st->e_cpt == '.') { 4284 p_ws = true; 4285 } 4286 bool looped_around = false; 4287 int found_new_match = FAIL; 4288 while (true) { 4289 bool cont_s_ipos = false; 4290 4291 msg_silent++; // Don't want messages for wrapscan. 4292 4293 if (in_fuzzy_collect) { 4294 found_new_match = search_for_fuzzy_match(st->ins_buf, 4295 st->cur_match_pos, leader, compl_direction, 4296 start_pos, &len, &ptr, &score); 4297 // ctrl_x_mode_line_or_eval() || word-wise search that 4298 // has added a word that was at the beginning of the line. 4299 } else if (ctrl_x_mode_whole_line() || ctrl_x_mode_eval() 4300 || (compl_cont_status & CONT_SOL)) { 4301 found_new_match = search_for_exact_line(st->ins_buf, st->cur_match_pos, 4302 compl_direction, compl_pattern.data); 4303 } else { 4304 found_new_match = searchit(NULL, st->ins_buf, st->cur_match_pos, 4305 NULL, compl_direction, compl_pattern.data, 4306 compl_pattern.size, 4307 1, SEARCH_KEEP + SEARCH_NFMSG, RE_LAST, NULL); 4308 } 4309 msg_silent--; 4310 if (!compl_started || st->set_match_pos) { 4311 // set "compl_started" even on fail 4312 compl_started = true; 4313 st->first_match_pos = *st->cur_match_pos; 4314 st->last_match_pos = *st->cur_match_pos; 4315 st->set_match_pos = false; 4316 } else if (st->first_match_pos.lnum == st->last_match_pos.lnum 4317 && st->first_match_pos.col == st->last_match_pos.col) { 4318 found_new_match = FAIL; 4319 } else if (compl_dir_forward() 4320 && (st->prev_match_pos.lnum > st->cur_match_pos->lnum 4321 || (st->prev_match_pos.lnum == st->cur_match_pos->lnum 4322 && st->prev_match_pos.col >= st->cur_match_pos->col))) { 4323 if (looped_around) { 4324 found_new_match = FAIL; 4325 } else { 4326 looped_around = true; 4327 } 4328 } else if (!compl_dir_forward() 4329 && (st->prev_match_pos.lnum < st->cur_match_pos->lnum 4330 || (st->prev_match_pos.lnum == st->cur_match_pos->lnum 4331 && st->prev_match_pos.col <= st->cur_match_pos->col))) { 4332 if (looped_around) { 4333 found_new_match = FAIL; 4334 } else { 4335 looped_around = true; 4336 } 4337 } 4338 st->prev_match_pos = *st->cur_match_pos; 4339 if (found_new_match == FAIL) { 4340 break; 4341 } 4342 4343 // when ADDING, the text before the cursor matches, skip it 4344 if (compl_status_adding() && in_curbuf 4345 && start_pos->lnum == st->cur_match_pos->lnum 4346 && start_pos->col == st->cur_match_pos->col) { 4347 continue; 4348 } 4349 4350 if (!in_fuzzy_collect) { 4351 ptr = ins_compl_get_next_word_or_line(st->ins_buf, 4352 st->cur_match_pos, &len, &cont_s_ipos); 4353 } 4354 if (ptr == NULL || (ins_compl_has_preinsert() 4355 && strcmp(ptr, ins_compl_leader()) == 0)) { 4356 continue; 4357 } 4358 4359 if (is_nearest_active() && in_curbuf) { 4360 score = st->cur_match_pos->lnum - curwin->w_cursor.lnum; 4361 if (score < 0) { 4362 score = -score; 4363 } 4364 } 4365 4366 if (ins_compl_add_infercase(ptr, len, p_ic, 4367 in_curbuf ? NULL : st->ins_buf->b_sfname, 4368 0, cont_s_ipos, score) != NOTDONE) { 4369 if (in_fuzzy_collect && score == compl_first_match->cp_next->cp_score) { 4370 compl_num_bests++; 4371 } 4372 found_new_match = OK; 4373 break; 4374 } 4375 } 4376 p_scs = save_p_scs; 4377 p_ws = save_p_ws; 4378 4379 return found_new_match; 4380 } 4381 4382 /// Get completion matches from register contents. 4383 /// Extracts words from all available registers and adds them to the completion list. 4384 static void get_register_completion(void) 4385 { 4386 Direction dir = compl_direction; 4387 bool adding_mode = compl_status_adding(); 4388 4389 for (int i = 0; i < NUM_REGISTERS; i++) { 4390 int regname = get_register_name(i); 4391 // Skip invalid or black hole register 4392 if (!valid_yank_reg(regname, false) || regname == '_') { 4393 continue; 4394 } 4395 4396 yankreg_T *reg = copy_register(regname); 4397 4398 if (reg->y_array == NULL || reg->y_size == 0) { 4399 free_register(reg); 4400 xfree(reg); 4401 continue; 4402 } 4403 4404 for (size_t j = 0; j < reg->y_size; j++) { 4405 char *str = reg->y_array[j].data; 4406 if (str == NULL) { 4407 continue; 4408 } 4409 4410 if (adding_mode) { 4411 int str_len = (int)strlen(str); 4412 if (str_len == 0) { 4413 continue; 4414 } 4415 4416 if (!compl_orig_text.data 4417 || (p_ic ? STRNICMP(str, compl_orig_text.data, 4418 compl_orig_text.size) == 0 4419 : strncmp(str, compl_orig_text.data, 4420 compl_orig_text.size) == 0)) { 4421 if (ins_compl_add_infercase(str, str_len, p_ic, NULL, 4422 dir, false, FUZZY_SCORE_NONE) == OK) { 4423 dir = FORWARD; 4424 } 4425 } 4426 } else { 4427 // Calculate the safe end of string to avoid null byte issues 4428 char *str_end = str + strlen(str); 4429 char *p = str; 4430 4431 // Safely iterate through the string 4432 while (p < str_end && *p != NUL) { 4433 char *old_p = p; 4434 p = find_word_start(p); 4435 if (p >= str_end || *p == NUL) { 4436 break; 4437 } 4438 4439 char *word_end = find_word_end(p); 4440 4441 if (word_end <= p) { 4442 word_end = p + utfc_ptr2len(p); 4443 } 4444 4445 if (word_end > str_end) { 4446 word_end = str_end; 4447 } 4448 4449 int len = (int)(word_end - p); 4450 if (len > 0 && (!compl_orig_text.data 4451 || (p_ic ? STRNICMP(p, compl_orig_text.data, 4452 compl_orig_text.size) == 0 4453 : strncmp(p, compl_orig_text.data, 4454 compl_orig_text.size) == 0))) { 4455 if (ins_compl_add_infercase(p, len, p_ic, NULL, 4456 dir, false, FUZZY_SCORE_NONE) == OK) { 4457 dir = FORWARD; 4458 } 4459 } 4460 4461 p = word_end; 4462 4463 if (p <= old_p) { 4464 p = old_p + utfc_ptr2len(old_p); 4465 } 4466 } 4467 } 4468 } 4469 4470 free_register(reg); 4471 xfree(reg); 4472 } 4473 } 4474 4475 /// Return the callback function associated with "p" if it refers to a 4476 /// user-defined function in the 'complete' option. 4477 /// The "idx" parameter is used for indexing callback entries. 4478 static Callback *get_callback_if_cpt_func(char *p, int idx) 4479 { 4480 if (*p == 'o') { 4481 return &curbuf->b_ofu_cb; 4482 } 4483 4484 if (*p == 'F') { 4485 if (*++p != ',' && *p != NUL) { 4486 // 'F{func}' case 4487 return curbuf->b_p_cpt_cb[idx].type != kCallbackNone 4488 ? &curbuf->b_p_cpt_cb[idx] : NULL; 4489 } else { 4490 return &curbuf->b_cfu_cb; // 'cfu' 4491 } 4492 } 4493 4494 return NULL; 4495 } 4496 4497 /// get the next set of completion matches for "type". 4498 /// @return true if a new match is found, otherwise false. 4499 static bool get_next_completion_match(int type, ins_compl_next_state_T *st, pos_T *ini) 4500 { 4501 int found_new_match = FAIL; 4502 4503 switch (type) { 4504 case -1: 4505 break; 4506 case CTRL_X_PATH_PATTERNS: 4507 case CTRL_X_PATH_DEFINES: 4508 get_next_include_file_completion(type); 4509 break; 4510 4511 case CTRL_X_DICTIONARY: 4512 case CTRL_X_THESAURUS: 4513 get_next_dict_tsr_completion(type, st->dict, st->dict_f); 4514 st->dict = NULL; 4515 break; 4516 4517 case CTRL_X_TAGS: 4518 get_next_tag_completion(); 4519 break; 4520 4521 case CTRL_X_FILES: 4522 get_next_filename_completion(); 4523 break; 4524 4525 case CTRL_X_CMDLINE: 4526 case CTRL_X_CMDLINE_CTRL_X: 4527 get_next_cmdline_completion(); 4528 break; 4529 4530 case CTRL_X_FUNCTION: 4531 if (ctrl_x_mode_normal()) { // Invoked by a func in 'cpt' option 4532 get_cpt_func_completion_matches(st->func_cb); 4533 } else { 4534 expand_by_function(type, compl_pattern.data, NULL); 4535 } 4536 break; 4537 case CTRL_X_OMNI: 4538 expand_by_function(type, compl_pattern.data, NULL); 4539 break; 4540 4541 case CTRL_X_SPELL: 4542 get_next_spell_completion(st->first_match_pos.lnum); 4543 break; 4544 case CTRL_X_BUFNAMES: 4545 get_next_bufname_token(); 4546 break; 4547 case CTRL_X_REGISTER: 4548 get_register_completion(); 4549 break; 4550 4551 default: // normal ^P/^N and ^X^L 4552 found_new_match = get_next_default_completion(st, ini); 4553 if (found_new_match == FAIL && st->ins_buf == curbuf) { 4554 st->found_all = true; 4555 } 4556 } 4557 4558 // check if compl_curr_match has changed, (e.g. other type of 4559 // expansion added something) 4560 if (type != 0 && compl_curr_match != compl_old_match) { 4561 found_new_match = OK; 4562 } 4563 4564 return found_new_match; 4565 } 4566 4567 static void get_next_bufname_token(void) 4568 { 4569 FOR_ALL_BUFFERS(b) { 4570 if (b->b_p_bl && b->b_sfname != NULL) { 4571 char *tail = path_tail(b->b_sfname); 4572 if (strncmp(tail, compl_orig_text.data, compl_orig_text.size) == 0) { 4573 ins_compl_add(tail, (int)strlen(tail), NULL, NULL, false, NULL, 0, 4574 p_ic ? CP_ICASE : 0, false, NULL, FUZZY_SCORE_NONE); 4575 } 4576 } 4577 } 4578 } 4579 4580 /// Strips carets followed by numbers. This suffix typically represents the 4581 /// max_matches setting. 4582 static void strip_caret_numbers_in_place(char *str) 4583 { 4584 char *read = str, *write = str, *p; 4585 4586 if (str == NULL) { 4587 return; 4588 } 4589 4590 while (*read) { 4591 if (*read == '^') { 4592 p = read + 1; 4593 while (ascii_isdigit(*p)) { 4594 p++; 4595 } 4596 if ((*p == ',' || *p == '\0') && p != read + 1) { 4597 read = p; 4598 continue; 4599 } else { 4600 *write++ = *read++; 4601 } 4602 } else { 4603 *write++ = *read++; 4604 } 4605 } 4606 *write = '\0'; 4607 } 4608 4609 /// Call functions specified in the 'cpt' option with findstart=1, 4610 /// and retrieve the startcol. 4611 static void prepare_cpt_compl_funcs(void) 4612 { 4613 // Make a copy of 'cpt' in case the buffer gets wiped out 4614 char *cpt = xstrdup(curbuf->b_p_cpt); 4615 strip_caret_numbers_in_place(cpt); 4616 4617 int idx = 0; 4618 for (char *p = cpt; *p;) { 4619 while (*p == ',' || *p == ' ') { // Skip delimiters 4620 p++; 4621 } 4622 if (*p == NUL) { 4623 break; 4624 } 4625 4626 Callback *cb = get_callback_if_cpt_func(p, idx); 4627 if (cb) { 4628 int startcol; 4629 if (get_userdefined_compl_info(curwin->w_cursor.col, cb, &startcol) == FAIL) { 4630 if (startcol == -3) { 4631 cpt_sources_array[idx].cs_refresh_always = false; 4632 } else { 4633 startcol = -2; 4634 } 4635 } else if (startcol < 0 || startcol > curwin->w_cursor.col) { 4636 startcol = curwin->w_cursor.col; 4637 } 4638 cpt_sources_array[idx].cs_startcol = startcol; 4639 } else { 4640 cpt_sources_array[idx].cs_startcol = -3; 4641 } 4642 4643 (void)copy_option_part(&p, IObuff, IOSIZE, ","); // Advance p 4644 idx++; 4645 } 4646 4647 xfree(cpt); 4648 } 4649 4650 /// Start the timer for the current completion source. 4651 static void compl_source_start_timer(int source_idx) 4652 { 4653 if (compl_autocomplete || p_cto > 0) { 4654 cpt_sources_array[source_idx].compl_start_tv = os_hrtime(); 4655 compl_time_slice_expired = false; 4656 } 4657 } 4658 4659 /// Safely advance the cpt_sources_index by one. 4660 static int advance_cpt_sources_index_safe(void) 4661 { 4662 if (cpt_sources_index >= 0 && cpt_sources_index < cpt_sources_count - 1) { 4663 cpt_sources_index++; 4664 return OK; 4665 } 4666 semsg(_(e_list_index_out_of_range_nr), cpt_sources_index); 4667 return FAIL; 4668 } 4669 4670 /// Get the next expansion(s), using "compl_pattern". 4671 /// The search starts at position "ini" in curbuf and in the direction 4672 /// compl_direction. 4673 /// When "compl_started" is false start at that position, otherwise continue 4674 /// where we stopped searching before. 4675 /// This may return before finding all the matches. 4676 /// Return the total number of matches or -1 if still unknown -- Acevedo 4677 static int ins_compl_get_exp(pos_T *ini) 4678 { 4679 static ins_compl_next_state_T st; 4680 static bool st_cleared = false; 4681 int found_new_match; 4682 int type = ctrl_x_mode; 4683 bool may_advance_cpt_idx = false; 4684 pos_T start_pos = *ini; 4685 4686 assert(curbuf != NULL); 4687 4688 if (!compl_started) { 4689 FOR_ALL_BUFFERS(buf) { 4690 buf->b_scanned = false; 4691 } 4692 if (!st_cleared) { 4693 CLEAR_FIELD(st); 4694 st_cleared = true; 4695 } 4696 st.found_all = false; 4697 st.ins_buf = curbuf; 4698 xfree(st.e_cpt_copy); 4699 // Make a copy of 'complete', in case the buffer is wiped out. 4700 st.e_cpt_copy = xstrdup((compl_cont_status & CONT_LOCAL) ? "." : curbuf->b_p_cpt); 4701 strip_caret_numbers_in_place(st.e_cpt_copy); 4702 st.e_cpt = st.e_cpt_copy; 4703 4704 // In large buffers, timeout may miss nearby matches — search above cursor 4705 #define LOOKBACK_LINE_COUNT 1000 4706 if (compl_autocomplete && is_nearest_active()) { 4707 start_pos.lnum = MAX(1, start_pos.lnum - LOOKBACK_LINE_COUNT); 4708 start_pos.col = 0; 4709 } 4710 st.last_match_pos = st.first_match_pos = start_pos; 4711 } else if (st.ins_buf != curbuf && !buf_valid(st.ins_buf)) { 4712 st.ins_buf = curbuf; // In case the buffer was wiped out. 4713 } 4714 assert(st.ins_buf != NULL); 4715 4716 compl_old_match = compl_curr_match; // remember the last current match 4717 st.cur_match_pos = compl_dir_forward() ? &st.last_match_pos : &st.first_match_pos; 4718 4719 bool normal_mode_strict = ctrl_x_mode_normal() && !ctrl_x_mode_line_or_eval() 4720 && !(compl_cont_status & CONT_LOCAL) 4721 && cpt_sources_array != NULL; 4722 if (normal_mode_strict) { 4723 cpt_sources_index = 0; 4724 if (compl_autocomplete || p_cto > 0) { 4725 compl_source_start_timer(0); 4726 compl_time_slice_expired = false; 4727 compl_timeout_ms = compl_autocomplete 4728 ? (uint64_t)MAX(COMPL_INITIAL_TIMEOUT_MS, p_act) 4729 : (uint64_t)p_cto; 4730 } 4731 } 4732 4733 // For ^N/^P loop over all the flags/windows/buffers in 'complete' 4734 while (true) { 4735 found_new_match = FAIL; 4736 st.set_match_pos = false; 4737 4738 // For ^N/^P pick a new entry from e_cpt if compl_started is off, 4739 // or if found_all says this entry is done. For ^X^L only use the 4740 // entries from 'complete' that look in loaded buffers. 4741 if ((ctrl_x_mode_normal() || ctrl_x_mode_line_or_eval()) 4742 && (!compl_started || st.found_all)) { 4743 int status = process_next_cpt_value(&st, &type, &start_pos, 4744 cot_fuzzy(), &may_advance_cpt_idx); 4745 if (status == INS_COMPL_CPT_END) { 4746 break; 4747 } 4748 if (status == INS_COMPL_CPT_CONT) { 4749 if (may_advance_cpt_idx) { 4750 if (!advance_cpt_sources_index_safe()) { 4751 break; 4752 } 4753 compl_source_start_timer(cpt_sources_index); 4754 } 4755 continue; 4756 } 4757 } 4758 4759 uint64_t compl_timeout_save = 0; 4760 if (normal_mode_strict && type == CTRL_X_FUNCTION 4761 && (compl_autocomplete || p_cto > 0)) { 4762 // LSP servers may sporadically take >1s to respond (e.g., while 4763 // loading modules), but other sources might already have matches. 4764 // To show results quickly use a short timeout for keyword 4765 // completion. Allow longer timeout for non-keyword completion 4766 // where only function based sources (e.g. LSP) are active. 4767 compl_timeout_save = compl_timeout_ms; 4768 compl_timeout_ms = compl_from_nonkeyword 4769 ? COMPL_FUNC_TIMEOUT_NON_KW_MS : COMPL_FUNC_TIMEOUT_MS; 4770 } 4771 4772 // get the next set of completion matches 4773 found_new_match = get_next_completion_match(type, &st, &start_pos); 4774 4775 // If complete() was called then compl_pattern has been reset. 4776 // The following won't work then, bail out. 4777 if (compl_pattern.data == NULL) { 4778 break; 4779 } 4780 4781 if (may_advance_cpt_idx) { 4782 if (!advance_cpt_sources_index_safe()) { 4783 break; 4784 } 4785 compl_source_start_timer(cpt_sources_index); 4786 } 4787 4788 // break the loop for specialized modes (use 'complete' just for the 4789 // generic ctrl_x_mode == CTRL_X_NORMAL) or when we've found a new match 4790 if ((ctrl_x_mode_not_default() && !ctrl_x_mode_line_or_eval()) 4791 || found_new_match != FAIL) { 4792 if (got_int) { 4793 break; 4794 } 4795 // Fill the popup menu as soon as possible. 4796 if (type != -1) { 4797 ins_compl_check_keys(0, false); 4798 } 4799 4800 if ((ctrl_x_mode_not_default() && !ctrl_x_mode_line_or_eval()) 4801 || compl_interrupted) { 4802 break; 4803 } 4804 compl_started = !compl_time_slice_expired; 4805 } else { 4806 // Mark a buffer scanned when it has been scanned completely 4807 if (buf_valid(st.ins_buf) && (type == 0 || type == CTRL_X_PATH_PATTERNS)) { 4808 assert(st.ins_buf); 4809 st.ins_buf->b_scanned = true; 4810 } 4811 4812 compl_started = false; 4813 } 4814 4815 // Restore the timeout after collecting matches from function source 4816 if (normal_mode_strict && type == CTRL_X_FUNCTION 4817 && (compl_autocomplete || p_cto > 0)) { 4818 compl_timeout_ms = compl_timeout_save; 4819 } 4820 4821 // For `^P` completion, reset `compl_curr_match` to the head to avoid 4822 // mixing matches from different sources. 4823 if (!compl_dir_forward()) { 4824 while (compl_curr_match->cp_prev 4825 && !match_at_original_text(compl_curr_match->cp_prev)) { 4826 compl_curr_match = compl_curr_match->cp_prev; 4827 } 4828 } 4829 } 4830 cpt_sources_index = -1; 4831 compl_started = true; 4832 4833 if ((ctrl_x_mode_normal() || ctrl_x_mode_line_or_eval()) 4834 && *st.e_cpt == NUL) { // Got to end of 'complete' 4835 found_new_match = FAIL; 4836 } 4837 4838 int match_count = -1; // total of matches, unknown 4839 if (found_new_match == FAIL 4840 || (ctrl_x_mode_not_default() && !ctrl_x_mode_line_or_eval())) { 4841 match_count = ins_compl_make_cyclic(); 4842 } 4843 4844 if (cot_fuzzy() && compl_get_longest && compl_num_bests > 0) { 4845 fuzzy_longest_match(); 4846 } 4847 4848 if (compl_old_match != NULL) { 4849 // If several matches were added (FORWARD) or the search failed and has 4850 // just been made cyclic then we have to move compl_curr_match to the 4851 // next or previous entry (if any) -- Acevedo 4852 compl_curr_match = compl_dir_forward() 4853 ? compl_old_match->cp_next 4854 : compl_old_match->cp_prev; 4855 if (compl_curr_match == NULL) { 4856 compl_curr_match = compl_old_match; 4857 } 4858 } 4859 may_trigger_modechanged(); 4860 4861 if (match_count > 0 && !ctrl_x_mode_spell()) { 4862 if (is_nearest_active() && !ins_compl_has_preinsert()) { 4863 sort_compl_match_list(cp_compare_nearest); 4864 } 4865 4866 if (cot_fuzzy() && ins_compl_leader_len() > 0) { 4867 ins_compl_fuzzy_sort(); 4868 } 4869 } 4870 4871 return match_count; 4872 } 4873 4874 /// Update "compl_shown_match" to the actually shown match, it may differ when 4875 /// "compl_leader" is used to omit some of the matches. 4876 static void ins_compl_update_shown_match(void) 4877 { 4878 (void)get_leader_for_startcol(NULL, true); // Clear the cache 4879 String *leader = get_leader_for_startcol(compl_shown_match, true); 4880 4881 while (!ins_compl_equal(compl_shown_match, leader->data, leader->size) 4882 && compl_shown_match->cp_next != NULL 4883 && !is_first_match(compl_shown_match->cp_next)) { 4884 compl_shown_match = compl_shown_match->cp_next; 4885 leader = get_leader_for_startcol(compl_shown_match, true); 4886 } 4887 4888 // If we didn't find it searching forward, and compl_shows_dir is 4889 // backward, find the last match. 4890 if (compl_shows_dir_backward() 4891 && !ins_compl_equal(compl_shown_match, leader->data, leader->size) 4892 && (compl_shown_match->cp_next == NULL 4893 || is_first_match(compl_shown_match->cp_next))) { 4894 while (!ins_compl_equal(compl_shown_match, leader->data, leader->size) 4895 && compl_shown_match->cp_prev != NULL 4896 && !is_first_match(compl_shown_match->cp_prev)) { 4897 compl_shown_match = compl_shown_match->cp_prev; 4898 leader = get_leader_for_startcol(compl_shown_match, true); 4899 } 4900 } 4901 } 4902 4903 /// Delete the old text being completed. 4904 void ins_compl_delete(bool new_leader) 4905 { 4906 // Avoid deleting text that will be reinserted when changing leader. This 4907 // allows marks present on the original text to shrink/grow appropriately. 4908 int orig_col = 0; 4909 if (new_leader) { 4910 char *orig = compl_orig_text.data; 4911 char *leader = ins_compl_leader(); 4912 while (*orig != NUL && utf_ptr2char(orig) == utf_ptr2char(leader)) { 4913 leader += utf_ptr2len(leader); 4914 orig += utf_ptr2len(orig); 4915 } 4916 orig_col = (int)(orig - compl_orig_text.data); 4917 } 4918 4919 // In insert mode: Delete the typed part. 4920 // In replace mode: Put the old characters back, if any. 4921 int col = compl_col + (compl_status_adding() ? compl_length : orig_col); 4922 4923 if (ins_compl_preinsert_effect()) { 4924 col += (int)ins_compl_leader_len(); 4925 curwin->w_cursor.col = compl_ins_end_col; 4926 } 4927 4928 String remaining = STRING_INIT; 4929 if (curwin->w_cursor.lnum > compl_lnum) { 4930 if (curwin->w_cursor.col < get_cursor_line_len()) { 4931 remaining = cbuf_to_string(get_cursor_pos_ptr(), (size_t)get_cursor_pos_len()); 4932 } 4933 4934 while (curwin->w_cursor.lnum > compl_lnum) { 4935 if (ml_delete(curwin->w_cursor.lnum) == FAIL) { 4936 if (remaining.data) { 4937 xfree(remaining.data); 4938 } 4939 return; 4940 } 4941 deleted_lines_mark(curwin->w_cursor.lnum, 1); 4942 curwin->w_cursor.lnum--; 4943 } 4944 // move cursor to end of line 4945 curwin->w_cursor.col = get_cursor_line_len(); 4946 } 4947 4948 if ((int)curwin->w_cursor.col > col) { 4949 if (stop_arrow() == FAIL) { 4950 if (remaining.data) { 4951 xfree(remaining.data); 4952 } 4953 return; 4954 } 4955 backspace_until_column(col); 4956 compl_ins_end_col = curwin->w_cursor.col; 4957 } 4958 4959 if (remaining.data != NULL) { 4960 orig_col = curwin->w_cursor.col; 4961 ins_str(remaining.data, remaining.size); 4962 curwin->w_cursor.col = orig_col; 4963 xfree(remaining.data); 4964 } 4965 4966 // TODO(vim): is this sufficient for redrawing? Redrawing everything 4967 // causes flicker, thus we can't do that. 4968 changed_cline_bef_curs(curwin); 4969 // clear v:completed_item 4970 set_vim_var_dict(VV_COMPLETED_ITEM, tv_dict_alloc_lock(VAR_FIXED)); 4971 } 4972 4973 /// Insert a completion string that contains newlines. 4974 /// The string is split and inserted line by line. 4975 static void ins_compl_expand_multiple(char *str) 4976 { 4977 char *start = str; 4978 char *curr = str; 4979 int base_indent = get_indent(); 4980 while (*curr != NUL) { 4981 if (*curr == '\n') { 4982 // Insert the text chunk before newline 4983 if (curr > start) { 4984 ins_char_bytes(start, (size_t)(curr - start)); 4985 } 4986 4987 // Handle newline 4988 open_line(FORWARD, OPENLINE_KEEPTRAIL | OPENLINE_FORCE_INDENT, base_indent, NULL); 4989 start = curr + 1; 4990 } 4991 curr++; 4992 } 4993 4994 // Handle remaining text after last newline (if any) 4995 if (curr > start) { 4996 ins_char_bytes(start, (size_t)(curr - start)); 4997 } 4998 4999 compl_ins_end_col = curwin->w_cursor.col; 5000 } 5001 5002 /// Find the longest common prefix among the current completion matches. 5003 /// Returns a pointer to the first match string, with *prefix_len set to 5004 /// the length of the common prefix. 5005 /// If "curbuf_only" is true, restrict matches to the current buffer 5006 /// ('.' source in 'complete'). 5007 static char *find_common_prefix(size_t *prefix_len, bool curbuf_only) 5008 { 5009 bool is_cpt_completion = (cpt_sources_array != NULL); 5010 5011 if (!is_cpt_completion) { 5012 return NULL; 5013 } 5014 5015 int *match_count = xcalloc((size_t)cpt_sources_count, sizeof(int)); 5016 5017 (void)get_leader_for_startcol(NULL, true); // Clear the cache 5018 5019 compl_T *compl = compl_first_match; 5020 char *first = NULL; 5021 int len = -1; 5022 do { 5023 String *leader = get_leader_for_startcol(compl, true); 5024 5025 // Apply 'smartcase' behavior during normal mode 5026 if (ctrl_x_mode_normal() && !p_inf && leader->data && !ignorecase(leader->data)) { 5027 compl->cp_flags &= ~CP_ICASE; 5028 } 5029 5030 if (!match_at_original_text(compl) 5031 && (leader->data == NULL 5032 || ins_compl_equal(compl, leader->data, leader->size))) { 5033 // Limit number of items from each source if max_items is set. 5034 bool match_limit_exceeded = false; 5035 int cur_source = compl->cp_cpt_source_idx; 5036 5037 if (cur_source != -1) { 5038 match_count[cur_source]++; 5039 int max_matches = cpt_sources_array[cur_source].cs_max_matches; 5040 if (max_matches > 0 && match_count[cur_source] > max_matches) { 5041 match_limit_exceeded = true; 5042 } 5043 } 5044 5045 if (!match_limit_exceeded 5046 && (!curbuf_only || cpt_sources_array[cur_source].cs_flag == '.')) { 5047 if (first == NULL && strncmp(ins_compl_leader(), compl->cp_str.data, 5048 ins_compl_leader_len()) == 0) { 5049 first = compl->cp_str.data; 5050 len = (int)strlen(first); 5051 } else if (first != NULL) { 5052 int j = 0; // count in bytes 5053 char *s1 = first; 5054 char *s2 = compl->cp_str.data; 5055 5056 while (j < len && *s1 != NUL && *s2 != NUL) { 5057 if (MB_BYTE2LEN((uint8_t)(*s1)) != MB_BYTE2LEN((uint8_t)(*s2)) 5058 || memcmp(s1, s2, MB_BYTE2LEN((uint8_t)(*s1))) != 0) { 5059 break; 5060 } 5061 5062 j += MB_BYTE2LEN((uint8_t)(*s1)); 5063 MB_PTR_ADV(s1); 5064 MB_PTR_ADV(s2); 5065 } 5066 len = j; 5067 5068 if (len == 0) { 5069 break; 5070 } 5071 } 5072 } 5073 } 5074 compl = compl->cp_next; 5075 } while (compl != NULL && !is_first_match(compl)); 5076 5077 xfree(match_count); 5078 5079 if (len > (int)ins_compl_leader_len()) { 5080 assert(first != NULL); 5081 // Avoid inserting text that duplicates the text already present 5082 // after the cursor. 5083 if (len == (int)strlen(first)) { 5084 char *line = get_cursor_line_ptr(); 5085 char *p = line + curwin->w_cursor.col; 5086 if (p && !ascii_iswhite_or_nul(*p)) { 5087 char *end = find_word_end(p); 5088 int text_len = (int)(end - p); 5089 if (text_len > 0 && text_len < (len - (int)ins_compl_leader_len()) 5090 && strncmp(first + len - text_len, p, (size_t)text_len) == 0) { 5091 len -= text_len; 5092 } 5093 } 5094 } 5095 *prefix_len = (size_t)len; 5096 return first; 5097 } 5098 return NULL; 5099 } 5100 5101 /// Insert the new text being completed. 5102 /// "move_cursor" is used when 'completeopt' includes "preinsert" and when true 5103 /// cursor needs to move back from the inserted text to the compl_leader. 5104 /// When "insert_prefix" is true the longest common prefix is inserted instead 5105 /// of shown match. 5106 void ins_compl_insert(bool move_cursor, bool insert_prefix) 5107 { 5108 int compl_len = get_compl_len(); 5109 bool preinsert = ins_compl_has_preinsert(); 5110 char *cp_str = compl_shown_match->cp_str.data; 5111 size_t cp_str_len = compl_shown_match->cp_str.size; 5112 size_t leader_len = ins_compl_leader_len(); 5113 char *has_multiple = strchr(cp_str, '\n'); 5114 5115 if (insert_prefix) { 5116 cp_str = find_common_prefix(&cp_str_len, false); 5117 if (cp_str == NULL) { 5118 cp_str = find_common_prefix(&cp_str_len, true); 5119 if (cp_str == NULL) { 5120 cp_str = compl_shown_match->cp_str.data; 5121 cp_str_len = compl_shown_match->cp_str.size; 5122 } 5123 } 5124 } else if (cpt_sources_array != NULL) { 5125 // Since completion sources may provide matches with varying start 5126 // positions, insert only the portion of the match that corresponds to the 5127 // intended replacement range. 5128 int cpt_idx = compl_shown_match->cp_cpt_source_idx; 5129 if (cpt_idx >= 0 && compl_col >= 0) { 5130 int startcol = cpt_sources_array[cpt_idx].cs_startcol; 5131 if (startcol >= 0 && startcol < (int)compl_col) { 5132 int skip = (int)compl_col - startcol; 5133 if ((size_t)skip <= cp_str_len) { 5134 cp_str_len -= (size_t)skip; 5135 cp_str += skip; 5136 } 5137 } 5138 } 5139 } 5140 5141 // Make sure we don't go over the end of the string, this can happen with 5142 // illegal bytes. 5143 if (compl_len < (int)cp_str_len) { 5144 if (has_multiple) { 5145 ins_compl_expand_multiple(cp_str + compl_len); 5146 } else { 5147 ins_compl_insert_bytes(cp_str + compl_len, 5148 insert_prefix ? (int)cp_str_len - compl_len : -1); 5149 if ((preinsert || insert_prefix) && move_cursor) { 5150 curwin->w_cursor.col -= (colnr_T)(cp_str_len - leader_len); 5151 } 5152 } 5153 } 5154 compl_used_match = !(match_at_original_text(compl_shown_match) 5155 || (preinsert && !insert_prefix)); 5156 5157 dict_T *dict = ins_compl_dict_alloc(compl_shown_match); 5158 set_vim_var_dict(VV_COMPLETED_ITEM, dict); 5159 compl_hi_on_autocompl_longest = insert_prefix && move_cursor; 5160 } 5161 5162 /// show the file name for the completion match (if any). Truncate the file 5163 /// name to avoid a wait for return. 5164 static void ins_compl_show_filename(void) 5165 { 5166 char *const lead = _("match in file"); 5167 int space = sc_col - vim_strsize(lead) - 2; 5168 if (space <= 0) { 5169 return; 5170 } 5171 5172 // We need the tail that fits. With double-byte encoding going 5173 // back from the end is very slow, thus go from the start and keep 5174 // the text that fits in "space" between "s" and "e". 5175 char *s; 5176 char *e; 5177 for (s = e = compl_shown_match->cp_fname; *e != NUL; MB_PTR_ADV(e)) { 5178 space -= ptr2cells(e); 5179 while (space < 0) { 5180 space += ptr2cells(s); 5181 MB_PTR_ADV(s); 5182 } 5183 } 5184 if (!compl_autocomplete) { 5185 msg_hist_off = true; 5186 vim_snprintf(IObuff, IOSIZE, "%s %s%s", lead, 5187 s > compl_shown_match->cp_fname ? "<" : "", s); 5188 msg(IObuff, 0); 5189 msg_hist_off = false; 5190 redraw_cmdline = false; // don't overwrite! 5191 } 5192 } 5193 5194 /// Find the appropriate completion item when 'complete' ('cpt') includes 5195 /// a 'max_matches' postfix. In this case, we search for a match where 5196 /// 'cp_in_match_array' is set, indicating that the match is also present 5197 /// in 'compl_match_array'. 5198 static compl_T *find_next_match_in_menu(void) 5199 { 5200 bool is_forward = compl_shows_dir_forward(); 5201 compl_T *match = compl_shown_match; 5202 5203 do { 5204 match = is_forward ? match->cp_next : match->cp_prev; 5205 } while (match->cp_next && !match->cp_in_match_array 5206 && !match_at_original_text(match)); 5207 return match; 5208 } 5209 5210 /// Find the next set of matches for completion. Repeat the completion "todo" 5211 /// times. The number of matches found is returned in 'num_matches'. 5212 /// 5213 /// @param allow_get_expansion If true, then ins_compl_get_exp() may be called to 5214 /// get more completions. 5215 /// If false, then do nothing when there are no more 5216 /// completions in the given direction. 5217 /// @param todo repeat completion this many times 5218 /// @param advance If true, then completion will move to the first match. 5219 /// Otherwise, the original text will be shown. 5220 /// 5221 /// @return OK on success and -1 if the number of matches are unknown. 5222 static int find_next_completion_match(bool allow_get_expansion, int todo, bool advance, 5223 int *num_matches) 5224 { 5225 bool found_end = false; 5226 compl_T *found_compl = NULL; 5227 unsigned cur_cot_flags = get_cot_flags(); 5228 bool compl_no_select = (cur_cot_flags & kOptCotFlagNoselect) != 0 5229 || (compl_autocomplete && !ins_compl_has_preinsert()); 5230 5231 while (--todo >= 0) { 5232 if (compl_shows_dir_forward() && compl_shown_match->cp_next != NULL) { 5233 if (compl_match_array != NULL) { 5234 compl_shown_match = find_next_match_in_menu(); 5235 } else { 5236 compl_shown_match = compl_shown_match->cp_next; 5237 } 5238 found_end = (compl_first_match != NULL 5239 && (is_first_match(compl_shown_match->cp_next) 5240 || is_first_match(compl_shown_match))); 5241 } else if (compl_shows_dir_backward() 5242 && compl_shown_match->cp_prev != NULL) { 5243 found_end = is_first_match(compl_shown_match); 5244 if (compl_match_array != NULL) { 5245 compl_shown_match = find_next_match_in_menu(); 5246 } else { 5247 compl_shown_match = compl_shown_match->cp_prev; 5248 } 5249 found_end |= is_first_match(compl_shown_match); 5250 } else { 5251 if (!allow_get_expansion) { 5252 if (advance) { 5253 if (compl_shows_dir_backward()) { 5254 compl_pending -= todo + 1; 5255 } else { 5256 compl_pending += todo + 1; 5257 } 5258 } 5259 return -1; 5260 } 5261 5262 if (!compl_no_select && advance) { 5263 if (compl_shows_dir_backward()) { 5264 compl_pending--; 5265 } else { 5266 compl_pending++; 5267 } 5268 } 5269 5270 // Find matches. 5271 *num_matches = ins_compl_get_exp(&compl_startpos); 5272 5273 // handle any pending completions 5274 while (compl_pending != 0 && compl_direction == compl_shows_dir 5275 && advance) { 5276 if (compl_pending > 0 && compl_shown_match->cp_next != NULL) { 5277 compl_shown_match = compl_shown_match->cp_next; 5278 compl_pending--; 5279 } 5280 if (compl_pending < 0 && compl_shown_match->cp_prev != NULL) { 5281 compl_shown_match = compl_shown_match->cp_prev; 5282 compl_pending++; 5283 } else { 5284 break; 5285 } 5286 } 5287 found_end = false; 5288 } 5289 5290 String *leader = get_leader_for_startcol(compl_shown_match, false); 5291 5292 if (!match_at_original_text(compl_shown_match) 5293 && leader->data != NULL 5294 && !ins_compl_equal(compl_shown_match, leader->data, leader->size) 5295 && !(cot_fuzzy() && compl_shown_match->cp_score != FUZZY_SCORE_NONE)) { 5296 todo++; 5297 } else { 5298 // Remember a matching item. 5299 found_compl = compl_shown_match; 5300 } 5301 5302 // Stop at the end of the list when we found a usable match. 5303 if (found_end) { 5304 if (found_compl != NULL) { 5305 compl_shown_match = found_compl; 5306 break; 5307 } 5308 todo = 1; // use first usable match after wrapping around 5309 } 5310 } 5311 5312 return OK; 5313 } 5314 5315 /// Fill in the next completion in the current direction. 5316 /// If "allow_get_expansion" is true, then we may call ins_compl_get_exp() to 5317 /// get more completions. If it is false, then we just do nothing when there 5318 /// are no more completions in a given direction. The latter case is used when 5319 /// we are still in the middle of finding completions, to allow browsing 5320 /// through the ones found so far. 5321 /// @return the total number of matches, or -1 if still unknown -- webb. 5322 /// 5323 /// compl_curr_match is currently being used by ins_compl_get_exp(), so we use 5324 /// compl_shown_match here. 5325 /// 5326 /// Note that this function may be called recursively once only. First with 5327 /// "allow_get_expansion" true, which calls ins_compl_get_exp(), which in turn 5328 /// calls this function with "allow_get_expansion" false. 5329 /// 5330 /// @param count Repeat completion this many times; should be at least 1 5331 /// @param insert_match Insert the newly selected match 5332 static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match) 5333 { 5334 int num_matches = -1; 5335 int todo = count; 5336 const bool started = compl_started; 5337 buf_T *const orig_curbuf = curbuf; 5338 unsigned cur_cot_flags = get_cot_flags(); 5339 bool compl_no_insert = (cur_cot_flags & kOptCotFlagNoinsert) != 0 5340 || (compl_autocomplete && !ins_compl_has_preinsert()); 5341 bool compl_preinsert = ins_compl_has_preinsert(); 5342 bool has_autocomplete_delay = (compl_autocomplete && p_acl > 0); 5343 5344 // When user complete function return -1 for findstart which is next 5345 // time of 'always', compl_shown_match become NULL. 5346 if (compl_shown_match == NULL) { 5347 return -1; 5348 } 5349 5350 if (compl_leader.data != NULL 5351 && !match_at_original_text(compl_shown_match) 5352 && !cot_fuzzy()) { 5353 // Update "compl_shown_match" to the actually shown match 5354 ins_compl_update_shown_match(); 5355 } 5356 5357 if (allow_get_expansion && insert_match 5358 && (!compl_get_longest || compl_used_match)) { 5359 // Delete old text to be replaced 5360 ins_compl_delete(false); 5361 } 5362 5363 // When finding the longest common text we stick at the original text, 5364 // don't let CTRL-N or CTRL-P move to the first match. 5365 bool advance = count != 1 || !allow_get_expansion || !compl_get_longest; 5366 5367 // When restarting the search don't insert the first match either. 5368 if (compl_restarting) { 5369 advance = false; 5370 compl_restarting = false; 5371 } 5372 5373 // Repeat this for when <PageUp> or <PageDown> is typed. But don't wrap 5374 // around. 5375 if (find_next_completion_match(allow_get_expansion, todo, advance, 5376 &num_matches) == -1) { 5377 return -1; 5378 } 5379 5380 if (curbuf != orig_curbuf) { 5381 // In case some completion function switched buffer, don't want to 5382 // insert the completion elsewhere. 5383 return -1; 5384 } 5385 5386 // Insert the text of the new completion, or the compl_leader. 5387 if (!started && ins_compl_preinsert_longest()) { 5388 ins_compl_insert(true, true); 5389 if (has_autocomplete_delay) { 5390 update_screen(); // Show the inserted text right away 5391 } 5392 } else if (compl_no_insert && !started && !compl_preinsert) { 5393 ins_compl_insert_bytes(compl_orig_text.data + get_compl_len(), -1); 5394 compl_used_match = false; 5395 restore_orig_extmarks(); 5396 } else if (insert_match) { 5397 if (!compl_get_longest || compl_used_match) { 5398 bool preinsert_longest = ins_compl_preinsert_longest() 5399 && match_at_original_text(compl_shown_match); // none selected 5400 ins_compl_insert(compl_preinsert || preinsert_longest, preinsert_longest); 5401 } else { 5402 assert(compl_leader.data != NULL); 5403 ins_compl_insert_bytes(compl_leader.data + get_compl_len(), -1); 5404 } 5405 if (strequal(compl_shown_match->cp_str.data, compl_orig_text.data)) { 5406 restore_orig_extmarks(); 5407 } 5408 } else { 5409 compl_used_match = false; 5410 } 5411 5412 if (!allow_get_expansion) { 5413 // redraw to show the user what was inserted 5414 update_screen(); // TODO(bfredl): no! 5415 5416 if (!has_autocomplete_delay) { 5417 // display the updated popup menu 5418 ins_compl_show_pum(); 5419 } 5420 5421 // Delete old text to be replaced, since we're still searching and 5422 // don't want to match ourselves! 5423 ins_compl_delete(false); 5424 } 5425 5426 // Enter will select a match when the match wasn't inserted and the popup 5427 // menu is visible. 5428 if (compl_no_insert && !started && !match_at_original_text(compl_shown_match)) { 5429 compl_enter_selects = true; 5430 } else { 5431 compl_enter_selects = !insert_match && compl_match_array != NULL; 5432 } 5433 5434 // Show the file name for the match (if any) 5435 if (compl_shown_match->cp_fname != NULL) { 5436 ins_compl_show_filename(); 5437 } 5438 5439 return num_matches; 5440 } 5441 5442 /// Check if the current completion source exceeded its timeout. If so, stop 5443 /// collecting, and halve the timeout. 5444 static void check_elapsed_time(void) 5445 { 5446 uint64_t start_tv = cpt_sources_array[cpt_sources_index].compl_start_tv; 5447 uint64_t elapsed_ms = (os_hrtime() - start_tv) / 1000000; 5448 5449 if (elapsed_ms > compl_timeout_ms) { 5450 compl_time_slice_expired = true; 5451 DECAY_COMPL_TIMEOUT(); 5452 } 5453 } 5454 5455 /// Call this while finding completions, to check whether the user has hit a key 5456 /// that should change the currently displayed completion, or exit completion 5457 /// mode. Also, when compl_pending is not zero, show a completion as soon as 5458 /// possible. -- webb 5459 /// 5460 /// @param frequency specifies out of how many calls we actually check. 5461 /// @param in_compl_func true when called from complete_check(), don't set 5462 /// compl_curr_match. 5463 void ins_compl_check_keys(int frequency, bool in_compl_func) 5464 { 5465 static int count = 0; 5466 5467 // Don't check when reading keys from a script, :normal or feedkeys(). 5468 // That would break the test scripts. But do check for keys when called 5469 // from complete_check(). 5470 if (!in_compl_func && (using_script() || ex_normal_busy)) { 5471 return; 5472 } 5473 5474 // Only do this at regular intervals 5475 if (++count < frequency) { 5476 return; 5477 } 5478 count = 0; 5479 5480 // Check for a typed key. Do use mappings, otherwise vim_is_ctrl_x_key() 5481 // can't do its work correctly. 5482 int c = vpeekc_any(); 5483 if (c != NUL && !test_disable_char_avail) { 5484 if (vim_is_ctrl_x_key(c) && c != Ctrl_X && c != Ctrl_R) { 5485 c = safe_vgetc(); // Eat the character 5486 compl_shows_dir = ins_compl_key2dir(c); 5487 ins_compl_next(false, ins_compl_key2count(c), c != K_UP && c != K_DOWN); 5488 } else { 5489 // Need to get the character to have KeyTyped set. We'll put it 5490 // back with vungetc() below. But skip K_IGNORE. 5491 c = safe_vgetc(); 5492 if (c != K_IGNORE) { 5493 // Don't interrupt completion when the character wasn't typed, 5494 // e.g., when doing @q to replay keys. 5495 if (c != Ctrl_R && KeyTyped) { 5496 compl_interrupted = true; 5497 } 5498 5499 vungetc(c); 5500 } 5501 } 5502 } else { 5503 bool normal_mode_strict = ctrl_x_mode_normal() && !ctrl_x_mode_line_or_eval() 5504 && !(compl_cont_status & CONT_LOCAL) 5505 && cpt_sources_array != NULL && cpt_sources_index >= 0; 5506 if (normal_mode_strict && (compl_autocomplete || p_cto > 0)) { 5507 check_elapsed_time(); 5508 } 5509 } 5510 5511 if (compl_pending 5512 && !got_int 5513 && !(cot_flags & (kOptCotFlagNoinsert | kOptCotFlagFuzzy)) 5514 && (!compl_autocomplete || ins_compl_has_preinsert())) { 5515 // Insert the first match immediately and advance compl_shown_match, 5516 // before finding other matches. 5517 int todo = compl_pending > 0 ? compl_pending : -compl_pending; 5518 5519 compl_pending = 0; 5520 ins_compl_next(false, todo, true); 5521 } 5522 } 5523 5524 /// Decide the direction of Insert mode complete from the key typed. 5525 /// Returns BACKWARD or FORWARD. 5526 static int ins_compl_key2dir(int c) 5527 { 5528 if (c == K_EVENT || c == K_COMMAND || c == K_LUA) { 5529 return pum_want.item < compl_selected_item ? BACKWARD : FORWARD; 5530 } 5531 if (c == Ctrl_P || c == Ctrl_L 5532 || c == K_PAGEUP || c == K_KPAGEUP 5533 || c == K_S_UP || c == K_UP) { 5534 return BACKWARD; 5535 } 5536 return FORWARD; 5537 } 5538 5539 /// Check that "c" is a valid completion key only while the popup menu is shown 5540 /// 5541 /// @param c character to check 5542 static bool ins_compl_pum_key(int c) 5543 FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT 5544 { 5545 return pum_visible() && (c == K_PAGEUP || c == K_KPAGEUP || c == K_S_UP 5546 || c == K_PAGEDOWN || c == K_KPAGEDOWN 5547 || c == K_S_DOWN || c == K_UP || c == K_DOWN); 5548 } 5549 5550 /// Decide the number of completions to move forward. 5551 /// Returns 1 for most keys, height of the popup menu for page-up/down keys. 5552 static int ins_compl_key2count(int c) 5553 { 5554 if (c == K_EVENT || c == K_COMMAND || c == K_LUA) { 5555 int offset = pum_want.item - compl_selected_item; 5556 return abs(offset); 5557 } 5558 5559 if (ins_compl_pum_key(c) && c != K_UP && c != K_DOWN) { 5560 int h = pum_get_height(); 5561 if (h > 3) { 5562 h -= 2; // keep some context 5563 } 5564 return h; 5565 } 5566 return 1; 5567 } 5568 5569 /// Check that completion with "c" should insert the match, false if only 5570 /// to change the currently selected completion. 5571 /// 5572 /// @param c character to check 5573 static bool ins_compl_use_match(int c) 5574 FUNC_ATTR_CONST FUNC_ATTR_WARN_UNUSED_RESULT 5575 { 5576 switch (c) { 5577 case K_UP: 5578 case K_DOWN: 5579 case K_PAGEDOWN: 5580 case K_KPAGEDOWN: 5581 case K_S_DOWN: 5582 case K_PAGEUP: 5583 case K_KPAGEUP: 5584 case K_S_UP: 5585 return false; 5586 case K_EVENT: 5587 case K_COMMAND: 5588 case K_LUA: 5589 return pum_want.active && pum_want.insert; 5590 } 5591 return true; 5592 } 5593 5594 /// Get the pattern, column and length for normal completion (CTRL-N CTRL-P 5595 /// completion) 5596 /// Sets the global variables: compl_col, compl_length and compl_pattern. 5597 /// Uses the global variables: compl_cont_status and ctrl_x_mode 5598 static int get_normal_compl_info(char *line, int startcol, colnr_T curs_col) 5599 { 5600 if ((compl_cont_status & CONT_SOL) || ctrl_x_mode_path_defines()) { 5601 if (!compl_status_adding()) { 5602 while (--startcol >= 0 && vim_isIDc((uint8_t)line[startcol])) {} 5603 compl_col += ++startcol; 5604 compl_length = curs_col - startcol; 5605 } 5606 if (p_ic) { 5607 compl_pattern = cstr_as_string(str_foldcase(line + compl_col, 5608 compl_length, NULL, 0)); 5609 } else { 5610 compl_pattern = cbuf_to_string(line + compl_col, (size_t)compl_length); 5611 } 5612 } else if (compl_status_adding()) { 5613 char *prefix = "\\<"; 5614 size_t prefixlen = STRLEN_LITERAL("\\<"); 5615 5616 if (!vim_iswordp(line + compl_col) 5617 || (compl_col > 0 5618 && (vim_iswordp(mb_prevptr(line, line + compl_col))))) { 5619 prefix = ""; 5620 prefixlen = 0; 5621 } 5622 5623 // we need up to 2 extra chars for the prefix 5624 size_t n = quote_meta(NULL, line + compl_col, compl_length) + prefixlen; 5625 compl_pattern.data = xmalloc(n); 5626 STRCPY(compl_pattern.data, prefix); 5627 quote_meta(compl_pattern.data + prefixlen, line + compl_col, compl_length); 5628 compl_pattern.size = n - 1; 5629 } else if (--startcol < 0 5630 || !vim_iswordp(mb_prevptr(line, line + startcol + 1))) { 5631 // Match any word of at least two chars 5632 compl_pattern = cbuf_to_string(S_LEN("\\<\\k\\k")); 5633 compl_col += curs_col; 5634 compl_length = 0; 5635 compl_from_nonkeyword = true; 5636 } else { 5637 // Search the point of change class of multibyte character 5638 // or not a word single byte character backward. 5639 startcol -= utf_head_off(line, line + startcol); 5640 int base_class = mb_get_class(line + startcol); 5641 while (--startcol >= 0) { 5642 int head_off = utf_head_off(line, line + startcol); 5643 if (base_class != mb_get_class(line + startcol - head_off)) { 5644 break; 5645 } 5646 startcol -= head_off; 5647 } 5648 5649 compl_col += ++startcol; 5650 compl_length = (int)curs_col - startcol; 5651 if (compl_length == 1) { 5652 // Only match word with at least two chars -- webb 5653 // there's no need to call quote_meta, 5654 // xmalloc(7) is enough -- Acevedo 5655 compl_pattern.data = xmalloc(7); 5656 STRCPY(compl_pattern.data, "\\<"); 5657 quote_meta(compl_pattern.data + 2, line + compl_col, 1); 5658 strcat(compl_pattern.data, "\\k"); 5659 compl_pattern.size = strlen(compl_pattern.data); 5660 } else { 5661 size_t n = quote_meta(NULL, line + compl_col, compl_length) + 2; 5662 compl_pattern.data = xmalloc(n); 5663 STRCPY(compl_pattern.data, "\\<"); 5664 quote_meta(compl_pattern.data + 2, line + compl_col, compl_length); 5665 compl_pattern.size = n - 1; 5666 } 5667 } 5668 5669 // Call functions in 'complete' with 'findstart=1' 5670 if (ctrl_x_mode_normal() && !(compl_cont_status & CONT_LOCAL)) { 5671 // ^N completion, not complete() or ^X^N 5672 setup_cpt_sources(); 5673 prepare_cpt_compl_funcs(); 5674 } 5675 5676 return OK; 5677 } 5678 5679 /// Get the pattern, column and length for whole line completion or for the 5680 /// complete() function. 5681 /// Sets the global variables: compl_col, compl_length and compl_pattern. 5682 static int get_wholeline_compl_info(char *line, colnr_T curs_col) 5683 { 5684 compl_col = (colnr_T)getwhitecols(line); 5685 compl_length = (int)curs_col - (int)compl_col; 5686 if (compl_length < 0) { // cursor in indent: empty pattern 5687 compl_length = 0; 5688 } 5689 if (p_ic) { 5690 compl_pattern = cstr_as_string(str_foldcase(line + compl_col, 5691 compl_length, NULL, 0)); 5692 } else { 5693 compl_pattern = cbuf_to_string(line + compl_col, (size_t)compl_length); 5694 } 5695 5696 return OK; 5697 } 5698 5699 /// Get the pattern, column and length for filename completion. 5700 /// Sets the global variables: compl_col, compl_length and compl_pattern. 5701 static int get_filename_compl_info(char *line, int startcol, colnr_T curs_col) 5702 { 5703 // Go back to just before the first filename character. 5704 if (startcol > 0) { 5705 char *p = line + startcol; 5706 5707 MB_PTR_BACK(line, p); 5708 while (p > line && vim_isfilec(utf_ptr2char(p))) { 5709 MB_PTR_BACK(line, p); 5710 } 5711 bool p_is_filec = false; 5712 #ifdef MSWIN 5713 // check for drive letters on mswin 5714 if (p > line && path_has_drive_letter(p - 1, line + startcol - (p - 1))) { 5715 p -= p == line + 1 ? 1 : 2; 5716 p_is_filec = true; 5717 } 5718 #endif 5719 p_is_filec = p_is_filec || vim_isfilec(utf_ptr2char(p)); 5720 5721 if (p == line && p_is_filec) { 5722 startcol = 0; 5723 } else { 5724 startcol = (int)(p - line) + 1; 5725 } 5726 } 5727 5728 compl_col += startcol; 5729 compl_length = (int)curs_col - startcol; 5730 compl_pattern = cstr_as_string(addstar(line + compl_col, 5731 (size_t)compl_length, EXPAND_FILES)); 5732 5733 return OK; 5734 } 5735 5736 /// Get the pattern, column and length for command-line completion. 5737 /// Sets the global variables: compl_col, compl_length and compl_pattern. 5738 static int get_cmdline_compl_info(char *line, colnr_T curs_col) 5739 { 5740 compl_pattern = cbuf_to_string(line, (size_t)curs_col); 5741 set_cmd_context(&compl_xp, compl_pattern.data, 5742 (int)compl_pattern.size, curs_col, false); 5743 if (compl_xp.xp_context == EXPAND_LUA) { 5744 nlua_expand_pat(&compl_xp); 5745 } 5746 if (compl_xp.xp_context == EXPAND_UNSUCCESSFUL 5747 || compl_xp.xp_context == EXPAND_NOTHING) { 5748 // No completion possible, use an empty pattern to get a 5749 // "pattern not found" message. 5750 compl_col = curs_col; 5751 } else { 5752 compl_col = (int)(compl_xp.xp_pattern - compl_pattern.data); 5753 } 5754 compl_length = curs_col - compl_col; 5755 5756 return OK; 5757 } 5758 5759 /// Set global variables related to completion: 5760 /// compl_col, compl_length, compl_pattern, and cpt_compl_pattern. 5761 static void set_compl_globals(int startcol, colnr_T curs_col, bool is_cpt_compl) 5762 { 5763 if (is_cpt_compl) { 5764 API_CLEAR_STRING(cpt_compl_pattern); 5765 if (startcol < compl_col) { 5766 prepend_startcol_text(&cpt_compl_pattern, &compl_orig_text, startcol); 5767 return; 5768 } else { 5769 cpt_compl_pattern = copy_string(compl_orig_text, NULL); 5770 } 5771 } else { 5772 if (startcol < 0 || startcol > curs_col) { 5773 startcol = curs_col; 5774 } 5775 5776 // Re-obtain line in case it has changed 5777 char *line = ml_get(curwin->w_cursor.lnum); 5778 int len = curs_col - startcol; 5779 5780 compl_pattern = cbuf_to_string(line + startcol, (size_t)len); 5781 compl_col = startcol; 5782 compl_length = len; 5783 } 5784 } 5785 5786 /// Get the pattern, column and length for user defined completion ('omnifunc', 5787 /// 'completefunc' and 'thesaurusfunc') 5788 /// Uses the global variable: spell_bad_len 5789 /// 5790 /// @param cb set if triggered by a function in the 'cpt' option, otherwise NULL 5791 /// @param startcol when not NULL, contains the column returned by function. 5792 static int get_userdefined_compl_info(colnr_T curs_col, Callback *cb, int *startcol) 5793 { 5794 // Call user defined function 'completefunc' with "a:findstart" 5795 // set to 1 to obtain the length of text to use for completion. 5796 const int save_State = State; 5797 5798 const bool is_cpt_function = (cb != NULL); 5799 if (!is_cpt_function) { 5800 // Call 'completefunc' or 'omnifunc' or 'thesaurusfunc' and get pattern 5801 // length as a string 5802 char *funcname = get_complete_funcname(ctrl_x_mode); 5803 if (*funcname == NUL) { 5804 semsg(_(e_notset), ctrl_x_mode_function() ? "completefunc" : "omnifunc"); 5805 return FAIL; 5806 } 5807 cb = get_insert_callback(ctrl_x_mode); 5808 } 5809 5810 typval_T args[3]; 5811 args[0].v_type = VAR_NUMBER; 5812 args[1].v_type = VAR_STRING; 5813 args[2].v_type = VAR_UNKNOWN; 5814 args[0].vval.v_number = 1; 5815 args[1].vval.v_string = ""; 5816 5817 pos_T pos = curwin->w_cursor; 5818 textlock++; 5819 colnr_T col = (colnr_T)callback_call_retnr(cb, 2, args); 5820 textlock--; 5821 5822 State = save_State; 5823 curwin->w_cursor = pos; // restore the cursor position 5824 check_cursor(curwin); // make sure cursor position is valid, just in case 5825 validate_cursor(curwin); 5826 if (!equalpos(curwin->w_cursor, pos)) { 5827 emsg(_(e_compldel)); 5828 return FAIL; 5829 } 5830 5831 if (startcol != NULL) { 5832 *startcol = col; 5833 } 5834 5835 // Return value -2 means the user complete function wants to cancel the 5836 // complete without an error, do the same if the function did not execute 5837 // successfully. 5838 if (col == -2 || aborting()) { 5839 return FAIL; 5840 } 5841 5842 // Return value -3 does the same as -2 and leaves CTRL-X mode. 5843 if (col == -3) { 5844 if (is_cpt_function) { 5845 return FAIL; 5846 } 5847 ctrl_x_mode = CTRL_X_NORMAL; 5848 edit_submode = NULL; 5849 if (!shortmess(SHM_COMPLETIONMENU)) { 5850 msg_clr_cmdline(); 5851 } 5852 return FAIL; 5853 } 5854 5855 // Reset extended parameters of completion, when starting new 5856 // completion. 5857 compl_opt_refresh_always = false; 5858 5859 if (!is_cpt_function) { 5860 set_compl_globals(col, curs_col, false); 5861 } 5862 return OK; 5863 } 5864 5865 /// Get the pattern, column and length for spell completion. 5866 /// Sets the global variables: compl_col, compl_length and compl_pattern. 5867 /// Uses the global variable: spell_bad_len 5868 static int get_spell_compl_info(int startcol, colnr_T curs_col) 5869 { 5870 if (spell_bad_len > 0) { 5871 assert(spell_bad_len <= INT_MAX); 5872 compl_col = curs_col - (int)spell_bad_len; 5873 } else { 5874 compl_col = spell_word_start(startcol); 5875 } 5876 if (compl_col >= (colnr_T)startcol) { 5877 compl_length = 0; 5878 compl_col = curs_col; 5879 } else { 5880 spell_expand_check_cap(compl_col); 5881 compl_length = (int)curs_col - compl_col; 5882 } 5883 // Need to obtain "line" again, it may have become invalid. 5884 char *line = ml_get(curwin->w_cursor.lnum); 5885 compl_pattern = cbuf_to_string(line + compl_col, (size_t)compl_length); 5886 5887 return OK; 5888 } 5889 5890 /// Get the completion pattern, column and length. 5891 /// 5892 /// @param startcol start column number of the completion pattern/text 5893 /// @param cur_col current cursor column 5894 /// 5895 /// On return, "line_invalid" is set to true, if the current line may have 5896 /// become invalid and needs to be fetched again. 5897 /// 5898 /// @return OK on success. 5899 static int compl_get_info(char *line, int startcol, colnr_T curs_col, bool *line_invalid) 5900 { 5901 if (ctrl_x_mode_normal() || ctrl_x_mode_register() 5902 || ((ctrl_x_mode & CTRL_X_WANT_IDENT) 5903 && !thesaurus_func_complete(ctrl_x_mode))) { 5904 if (get_normal_compl_info(line, startcol, curs_col) != OK) { 5905 return FAIL; 5906 } 5907 *line_invalid = true; // 'cpt' func may have invalidated "line" 5908 } else if (ctrl_x_mode_line_or_eval()) { 5909 return get_wholeline_compl_info(line, curs_col); 5910 } else if (ctrl_x_mode_files()) { 5911 return get_filename_compl_info(line, startcol, curs_col); 5912 } else if (ctrl_x_mode == CTRL_X_CMDLINE) { 5913 return get_cmdline_compl_info(line, curs_col); 5914 } else if (ctrl_x_mode_function() || ctrl_x_mode_omni() 5915 || thesaurus_func_complete(ctrl_x_mode)) { 5916 if (get_userdefined_compl_info(curs_col, NULL, NULL) != OK) { 5917 return FAIL; 5918 } 5919 *line_invalid = true; // "line" may have become invalid 5920 } else if (ctrl_x_mode_spell()) { 5921 if (get_spell_compl_info(startcol, curs_col) == FAIL) { 5922 return FAIL; 5923 } 5924 *line_invalid = true; // "line" may have become invalid 5925 } else { 5926 internal_error("ins_complete()"); 5927 return FAIL; 5928 } 5929 5930 return OK; 5931 } 5932 5933 /// Continue an interrupted completion mode search in "line". 5934 /// 5935 /// If this same ctrl_x_mode has been interrupted use the text from 5936 /// "compl_startpos" to the cursor as a pattern to add a new word instead of 5937 /// expand the one before the cursor, in word-wise if "compl_startpos" is not in 5938 /// the same line as the cursor then fix it (the line has been split because it 5939 /// was longer than 'tw'). if SOL is set then skip the previous pattern, a word 5940 /// at the beginning of the line has been inserted, we'll look for that. 5941 static void ins_compl_continue_search(char *line) 5942 { 5943 // it is a continued search 5944 compl_cont_status &= ~CONT_INTRPT; // remove INTRPT 5945 if (ctrl_x_mode_normal() 5946 || ctrl_x_mode_path_patterns() 5947 || ctrl_x_mode_path_defines()) { 5948 if (compl_startpos.lnum != curwin->w_cursor.lnum) { 5949 // line (probably) wrapped, set compl_startpos to the 5950 // first non_blank in the line, if it is not a wordchar 5951 // include it to get a better pattern, but then we don't 5952 // want the "\\<" prefix, check it below. 5953 compl_col = (colnr_T)getwhitecols(line); 5954 compl_startpos.col = compl_col; 5955 compl_startpos.lnum = curwin->w_cursor.lnum; 5956 compl_cont_status &= ~CONT_SOL; // clear SOL if present 5957 } else { 5958 // S_IPOS was set when we inserted a word that was at the 5959 // beginning of the line, which means that we'll go to SOL 5960 // mode but first we need to redefine compl_startpos 5961 if (compl_cont_status & CONT_S_IPOS) { 5962 compl_cont_status |= CONT_SOL; 5963 compl_startpos.col = (colnr_T)(skipwhite(line + compl_length + compl_startpos.col) - line); 5964 } 5965 compl_col = compl_startpos.col; 5966 } 5967 compl_length = curwin->w_cursor.col - (int)compl_col; 5968 // IObuff is used to add a "word from the next line" would we 5969 // have enough space? just being paranoid 5970 #define MIN_SPACE 75 5971 if (compl_length > (IOSIZE - MIN_SPACE)) { 5972 compl_cont_status &= ~CONT_SOL; 5973 compl_length = (IOSIZE - MIN_SPACE); 5974 compl_col = curwin->w_cursor.col - compl_length; 5975 } 5976 compl_cont_status |= CONT_ADDING | CONT_N_ADDS; 5977 if (compl_length < 1) { 5978 compl_cont_status &= CONT_LOCAL; 5979 } 5980 } else if (ctrl_x_mode_line_or_eval() || ctrl_x_mode_register()) { 5981 compl_cont_status = CONT_ADDING | CONT_N_ADDS; 5982 } else { 5983 compl_cont_status = 0; 5984 } 5985 } 5986 5987 /// start insert mode completion 5988 static int ins_compl_start(void) 5989 { 5990 const bool save_did_ai = did_ai; 5991 5992 // First time we hit ^N or ^P (in a row, I mean) 5993 5994 did_ai = false; 5995 did_si = false; 5996 can_si = false; 5997 can_si_back = false; 5998 if (stop_arrow() == FAIL) { 5999 did_ai = save_did_ai; 6000 return FAIL; 6001 } 6002 6003 char *line = ml_get(curwin->w_cursor.lnum); 6004 colnr_T curs_col = curwin->w_cursor.col; 6005 compl_pending = 0; 6006 compl_lnum = curwin->w_cursor.lnum; 6007 6008 if ((compl_cont_status & CONT_INTRPT) == CONT_INTRPT 6009 && compl_cont_mode == ctrl_x_mode) { 6010 // this same ctrl-x_mode was interrupted previously. Continue the 6011 // completion. 6012 ins_compl_continue_search(line); 6013 } else { 6014 compl_cont_status &= CONT_LOCAL; 6015 } 6016 6017 int startcol = 0; // column where searched text starts 6018 if (!compl_status_adding()) { // normal expansion 6019 compl_cont_mode = ctrl_x_mode; 6020 if (ctrl_x_mode_not_default()) { 6021 // Remove LOCAL if ctrl_x_mode != CTRL_X_NORMAL 6022 compl_cont_status = 0; 6023 } 6024 compl_cont_status |= CONT_N_ADDS; 6025 compl_startpos = curwin->w_cursor; 6026 startcol = (int)curs_col; 6027 compl_col = 0; 6028 } 6029 6030 // Work out completion pattern and original text -- webb 6031 bool line_invalid = false; 6032 if (compl_get_info(line, startcol, curs_col, &line_invalid) == FAIL) { 6033 if (ctrl_x_mode_function() || ctrl_x_mode_omni() 6034 || thesaurus_func_complete(ctrl_x_mode)) { 6035 // restore did_ai, so that adding comment leader works 6036 did_ai = save_did_ai; 6037 } 6038 return FAIL; 6039 } 6040 // If "line" was changed while getting completion info get it again. 6041 if (line_invalid) { 6042 line = ml_get(curwin->w_cursor.lnum); 6043 } 6044 6045 if (compl_status_adding()) { 6046 if (!shortmess(SHM_COMPLETIONMENU)) { 6047 edit_submode_pre = _(" Adding"); 6048 } 6049 if (ctrl_x_mode_line_or_eval()) { 6050 // Insert a new line, keep indentation but ignore 'comments'. 6051 char *old = curbuf->b_p_com; 6052 6053 curbuf->b_p_com = ""; 6054 compl_startpos.lnum = curwin->w_cursor.lnum; 6055 compl_startpos.col = compl_col; 6056 ins_eol('\r'); 6057 curbuf->b_p_com = old; 6058 compl_length = 0; 6059 compl_col = curwin->w_cursor.col; 6060 compl_lnum = curwin->w_cursor.lnum; 6061 } 6062 } else { 6063 edit_submode_pre = NULL; 6064 compl_startpos.col = compl_col; 6065 } 6066 6067 if (!shortmess(SHM_COMPLETIONMENU) && !compl_autocomplete) { 6068 if (compl_cont_status & CONT_LOCAL) { 6069 edit_submode = _(ctrl_x_msgs[CTRL_X_LOCAL_MSG]); 6070 } else { 6071 edit_submode = _(CTRL_X_MSG(ctrl_x_mode)); 6072 } 6073 } 6074 6075 // If any of the original typed text has been changed we need to fix 6076 // the redo buffer. 6077 ins_compl_fixRedoBufForLeader(NULL); 6078 6079 // Always add completion for the original text. 6080 API_CLEAR_STRING(compl_orig_text); 6081 kv_destroy(compl_orig_extmarks); 6082 compl_orig_text = cbuf_to_string(line + compl_col, (size_t)compl_length); 6083 save_orig_extmarks(); 6084 int flags = CP_ORIGINAL_TEXT; 6085 if (p_ic) { 6086 flags |= CP_ICASE; 6087 } 6088 if (ins_compl_add(compl_orig_text.data, (int)compl_orig_text.size, 6089 NULL, NULL, false, NULL, 0, 6090 flags, false, NULL, FUZZY_SCORE_NONE) != OK) { 6091 API_CLEAR_STRING(compl_pattern); 6092 API_CLEAR_STRING(compl_orig_text); 6093 kv_destroy(compl_orig_extmarks); 6094 did_ai = save_did_ai; 6095 return FAIL; 6096 } 6097 6098 // showmode might reset the internal line pointers, so it must 6099 // be called before line = ml_get(), or when this address is no 6100 // longer needed. -- Acevedo. 6101 if (!shortmess(SHM_COMPLETIONMENU) && !compl_autocomplete) { 6102 edit_submode_extra = _("-- Searching..."); 6103 edit_submode_highl = HLF_COUNT; 6104 showmode(); 6105 edit_submode_extra = NULL; 6106 ui_flush(); 6107 } 6108 6109 did_ai = save_did_ai; 6110 return OK; 6111 } 6112 6113 /// display the completion status message 6114 static void ins_compl_show_statusmsg(void) 6115 { 6116 // we found no match if the list has only the "compl_orig_text"-entry 6117 if (is_first_match(compl_first_match->cp_next)) { 6118 edit_submode_extra = compl_status_adding() && compl_length > 1 ? _(e_hitend) : _(e_patnotf); 6119 edit_submode_highl = HLF_E; 6120 } 6121 6122 if (edit_submode_extra == NULL) { 6123 if (match_at_original_text(compl_curr_match)) { 6124 edit_submode_extra = _("Back at original"); 6125 edit_submode_highl = HLF_W; 6126 } else if (compl_cont_status & CONT_S_IPOS) { 6127 edit_submode_extra = _("Word from other line"); 6128 edit_submode_highl = HLF_COUNT; 6129 } else if (compl_curr_match->cp_next == compl_curr_match->cp_prev) { 6130 edit_submode_extra = _("The only match"); 6131 edit_submode_highl = HLF_COUNT; 6132 compl_curr_match->cp_number = 1; 6133 } else { 6134 // Update completion sequence number when needed. 6135 if (compl_curr_match->cp_number == -1) { 6136 ins_compl_update_sequence_numbers(); 6137 } 6138 6139 // The match should always have a sequence number now, this is 6140 // just a safety check. 6141 if (compl_curr_match->cp_number != -1) { 6142 // Space for 10 text chars. + 2x10-digit no.s = 31. 6143 // Translations may need more than twice that. 6144 static char match_ref[81]; 6145 6146 if (compl_matches > 0) { 6147 vim_snprintf(match_ref, sizeof(match_ref), 6148 _("match %d of %d"), 6149 compl_curr_match->cp_number, compl_matches); 6150 } else { 6151 vim_snprintf(match_ref, sizeof(match_ref), 6152 _("match %d"), 6153 compl_curr_match->cp_number); 6154 } 6155 edit_submode_extra = match_ref; 6156 edit_submode_highl = HLF_R; 6157 if (dollar_vcol >= 0) { 6158 curs_columns(curwin, false); 6159 } 6160 } 6161 } 6162 } 6163 6164 // Show a message about what (completion) mode we're in. 6165 redraw_mode = true; 6166 if (!shortmess(SHM_COMPLETIONMENU)) { 6167 if (edit_submode_extra != NULL) { 6168 if (!p_smd) { 6169 msg_hist_off = true; 6170 msg_ext_set_kind("completion"); 6171 msg(edit_submode_extra, (edit_submode_highl < HLF_COUNT 6172 ? (int)edit_submode_highl + 1 : 0)); 6173 msg_hist_off = false; 6174 } 6175 } else { 6176 msg_clr_cmdline(); // necessary for "noshowmode" 6177 } 6178 } 6179 } 6180 6181 /// Do Insert mode completion. 6182 /// Called when character "c" was typed, which has a meaning for completion. 6183 /// Returns OK if completion was done, FAIL if something failed. 6184 int ins_complete(int c, bool enable_pum) 6185 { 6186 const bool disable_ac_delay = compl_started && ctrl_x_mode_normal() 6187 && (c == Ctrl_N || c == Ctrl_P || c == Ctrl_R 6188 || ins_compl_pum_key(c)); 6189 6190 compl_direction = ins_compl_key2dir(c); 6191 int insert_match = ins_compl_use_match(c); 6192 6193 if (!compl_started) { 6194 if (ins_compl_start() == FAIL) { 6195 return FAIL; 6196 } 6197 } else if (insert_match && stop_arrow() == FAIL) { 6198 return FAIL; 6199 } 6200 6201 uint64_t compl_start_tv = 0; ///< Time when match collection starts 6202 if (compl_autocomplete && p_acl > 0 && !disable_ac_delay) { 6203 compl_start_tv = os_hrtime(); 6204 } 6205 compl_curr_win = curwin; 6206 compl_curr_buf = curwin->w_buffer; 6207 compl_shown_match = compl_curr_match; 6208 compl_shows_dir = compl_direction; 6209 compl_num_bests = 0; 6210 6211 // Find next match (and following matches). 6212 int save_w_wrow = curwin->w_wrow; 6213 int save_w_leftcol = curwin->w_leftcol; 6214 int n = ins_compl_next(true, ins_compl_key2count(c), insert_match); 6215 6216 // Reset autocompletion timer expiry flag 6217 if (compl_autocomplete) { 6218 compl_time_slice_expired = false; 6219 } 6220 6221 if (n > 1) { // all matches have been found 6222 compl_matches = n; 6223 } 6224 compl_curr_match = compl_shown_match; 6225 compl_direction = compl_shows_dir; 6226 6227 // Eat the ESC that vgetc() returns after a CTRL-C to avoid leaving Insert 6228 // mode. 6229 if (got_int && !global_busy) { 6230 vgetc(); 6231 got_int = false; 6232 } 6233 6234 // we found no match if the list has only the "compl_orig_text"-entry 6235 bool no_matches_found = is_first_match(compl_first_match->cp_next); 6236 if (no_matches_found) { 6237 // remove N_ADDS flag, so next ^X<> won't try to go to ADDING mode, 6238 // because we couldn't expand anything at first place, but if we used 6239 // ^P, ^N, ^X^I or ^X^D we might want to add-expand a single-char-word 6240 // (such as M in M'exico) if not tried already. -- Acevedo 6241 if (compl_length > 1 6242 || compl_status_adding() 6243 || (ctrl_x_mode_not_default() 6244 && !ctrl_x_mode_path_patterns() 6245 && !ctrl_x_mode_path_defines())) { 6246 compl_cont_status &= ~CONT_N_ADDS; 6247 } 6248 } 6249 6250 if (compl_curr_match->cp_flags & CP_CONT_S_IPOS) { 6251 compl_cont_status |= CONT_S_IPOS; 6252 } else { 6253 compl_cont_status &= ~CONT_S_IPOS; 6254 } 6255 6256 if (!shortmess(SHM_COMPLETIONMENU) && !compl_autocomplete) { 6257 ins_compl_show_statusmsg(); 6258 } 6259 6260 // Wait for the autocompletion delay to expire 6261 if (compl_autocomplete && p_acl > 0 && !disable_ac_delay && !no_matches_found 6262 && (os_hrtime() - compl_start_tv) / 1000000 < (uint64_t)p_acl) { 6263 setcursor(); 6264 ui_flush(); 6265 do { 6266 if (char_avail()) { 6267 if (ins_compl_preinsert_effect() && ins_compl_win_active(curwin)) { 6268 ins_compl_delete(false); // Remove pre-inserted text 6269 compl_ins_end_col = compl_col; 6270 } 6271 ins_compl_restart(); 6272 compl_interrupted = true; 6273 break; 6274 } else { 6275 os_delay(2L, true); 6276 } 6277 } while ((os_hrtime() - compl_start_tv) / 1000000 < (uint64_t)p_acl); 6278 } 6279 6280 // Show the popup menu, unless we got interrupted. 6281 if (enable_pum && !compl_interrupted) { 6282 show_pum(save_w_wrow, save_w_leftcol); 6283 } 6284 compl_was_interrupted = compl_interrupted; 6285 compl_interrupted = false; 6286 6287 return OK; 6288 } 6289 6290 /// Enable autocompletion 6291 void ins_compl_enable_autocomplete(void) 6292 { 6293 compl_autocomplete = true; 6294 compl_get_longest = false; 6295 } 6296 6297 /// Remove (if needed) and show the popup menu 6298 static void show_pum(int prev_w_wrow, int prev_w_leftcol) 6299 { 6300 // RedrawingDisabled may be set when invoked through complete(). 6301 int n = RedrawingDisabled; 6302 RedrawingDisabled = 0; 6303 6304 // If the cursor moved or the display scrolled we need to remove the pum 6305 // first. 6306 setcursor(); 6307 if (prev_w_wrow != curwin->w_wrow || prev_w_leftcol != curwin->w_leftcol) { 6308 ins_compl_del_pum(); 6309 } 6310 6311 ins_compl_show_pum(); 6312 setcursor(); 6313 RedrawingDisabled = n; 6314 } 6315 6316 // Looks in the first "len" chars. of "src" for search-metachars. 6317 // If dest is not NULL the chars. are copied there quoting (with 6318 // a backslash) the metachars, and dest would be NUL terminated. 6319 // Returns the length (needed) of dest 6320 static unsigned quote_meta(char *dest, char *src, int len) 6321 { 6322 unsigned m = (unsigned)len + 1; // one extra for the NUL 6323 6324 for (; --len >= 0; src++) { 6325 switch (*src) { 6326 case '.': 6327 case '*': 6328 case '[': 6329 if (ctrl_x_mode_dictionary() || ctrl_x_mode_thesaurus()) { 6330 break; 6331 } 6332 FALLTHROUGH; 6333 case '~': 6334 if (!magic_isset()) { // quote these only if magic is set 6335 break; 6336 } 6337 FALLTHROUGH; 6338 case '\\': 6339 if (ctrl_x_mode_dictionary() || ctrl_x_mode_thesaurus()) { 6340 break; 6341 } 6342 FALLTHROUGH; 6343 case '^': // currently it's not needed. 6344 case '$': 6345 m++; 6346 if (dest != NULL) { 6347 *dest++ = '\\'; 6348 } 6349 break; 6350 } 6351 if (dest != NULL) { 6352 *dest++ = *src; 6353 } 6354 // Copy remaining bytes of a multibyte character. 6355 const int mb_len = utfc_ptr2len(src) - 1; 6356 if (mb_len > 0 && len >= mb_len) { 6357 for (int i = 0; i < mb_len; i++) { 6358 len--; 6359 src++; 6360 if (dest != NULL) { 6361 *dest++ = *src; 6362 } 6363 } 6364 } 6365 } 6366 if (dest != NULL) { 6367 *dest = NUL; 6368 } 6369 6370 return m; 6371 } 6372 6373 #if defined(EXITFREE) 6374 void free_insexpand_stuff(void) 6375 { 6376 API_CLEAR_STRING(compl_orig_text); 6377 kv_destroy(compl_orig_extmarks); 6378 callback_free(&cfu_cb); 6379 callback_free(&ofu_cb); 6380 callback_free(&tsrfu_cb); 6381 clear_cpt_callbacks(&cpt_cb, cpt_cb_count); 6382 } 6383 #endif 6384 6385 /// Called when starting CTRL_X_SPELL mode: Move backwards to a previous badly 6386 /// spelled word, if there is one. 6387 static void spell_back_to_badword(void) 6388 { 6389 pos_T tpos = curwin->w_cursor; 6390 spell_bad_len = spell_move_to(curwin, BACKWARD, SMT_ALL, true, NULL); 6391 if (curwin->w_cursor.col != tpos.col) { 6392 start_arrow(&tpos); 6393 } 6394 } 6395 6396 /// Reset the info associated with completion sources. 6397 static void cpt_sources_clear(void) 6398 { 6399 XFREE_CLEAR(cpt_sources_array); 6400 cpt_sources_index = -1; 6401 cpt_sources_count = 0; 6402 } 6403 6404 /// Setup completion sources. 6405 static void setup_cpt_sources(void) 6406 { 6407 cpt_sources_clear(); 6408 6409 int count = get_cpt_sources_count(); 6410 if (count == 0) { 6411 return; 6412 } 6413 6414 cpt_sources_array = xcalloc((size_t)count, sizeof(cpt_source_T)); 6415 6416 char buf[LSIZE]; 6417 int idx = 0; 6418 for (char *p = curbuf->b_p_cpt; *p;) { 6419 while (*p == ',' || *p == ' ') { // Skip delimiters 6420 p++; 6421 } 6422 if (*p) { // If not end of string, count this segment 6423 cpt_sources_array[idx].cs_flag = *p; 6424 memset(buf, 0, LSIZE); 6425 size_t slen = copy_option_part(&p, buf, LSIZE, ","); // Advance p 6426 if (slen > 0) { 6427 char *caret = vim_strchr(buf, '^'); 6428 if (caret != NULL) { 6429 cpt_sources_array[idx].cs_max_matches = atoi(caret + 1); 6430 } 6431 } 6432 idx++; 6433 } 6434 } 6435 6436 cpt_sources_count = count; 6437 } 6438 6439 /// Return true if any of the completion sources have 'refresh' set to 'always'. 6440 static bool is_cpt_func_refresh_always(void) 6441 { 6442 for (int i = 0; i < cpt_sources_count; i++) { 6443 if (cpt_sources_array[i].cs_refresh_always) { 6444 return true; 6445 } 6446 } 6447 return false; 6448 } 6449 6450 /// Make the completion list non-cyclic. 6451 static void ins_compl_make_linear(void) 6452 { 6453 if (compl_first_match == NULL || compl_first_match->cp_prev == NULL) { 6454 return; 6455 } 6456 compl_T *m = compl_first_match->cp_prev; 6457 m->cp_next = NULL; 6458 compl_first_match->cp_prev = NULL; 6459 } 6460 6461 /// Remove the matches linked to the current completion source (as indicated by 6462 /// cpt_sources_index) from the completion list. 6463 static void remove_old_matches(void) 6464 { 6465 bool shown_match_removed = false; 6466 bool forward = (compl_first_match->cp_cpt_source_idx < 0); 6467 6468 if (cpt_sources_index < 0) { 6469 return; 6470 } 6471 6472 compl_direction = forward ? FORWARD : BACKWARD; 6473 compl_shows_dir = compl_direction; 6474 6475 // When 'fuzzy' is enabled, items are not ordered by their original source 6476 // order (cpt_sources_index). So, remove items one by one. 6477 for (compl_T *current = compl_first_match; current != NULL;) { 6478 if (current->cp_cpt_source_idx == cpt_sources_index) { 6479 compl_T *to_delete = current; 6480 6481 if (!shown_match_removed && compl_shown_match == current) { 6482 shown_match_removed = true; 6483 } 6484 6485 current = current->cp_next; 6486 6487 if (to_delete == compl_first_match) { // node to remove is at head 6488 compl_first_match = to_delete->cp_next; 6489 compl_first_match->cp_prev = NULL; 6490 } else if (to_delete->cp_next == NULL) { // node to remove is at tail 6491 to_delete->cp_prev->cp_next = NULL; 6492 } else { // node is in the moddle 6493 to_delete->cp_prev->cp_next = to_delete->cp_next; 6494 to_delete->cp_next->cp_prev = to_delete->cp_prev; 6495 } 6496 ins_compl_item_free(to_delete); 6497 } else { 6498 current = current->cp_next; 6499 } 6500 } 6501 6502 // Re-assign compl_shown_match if necessary 6503 if (shown_match_removed) { 6504 if (forward) { 6505 compl_shown_match = compl_first_match; 6506 } else { // Last node will have the prefix that is being completed 6507 compl_T *current; 6508 for (current = compl_first_match; current->cp_next != NULL; 6509 current = current->cp_next) {} 6510 compl_shown_match = current; 6511 } 6512 } 6513 6514 // Re-assign compl_curr_match 6515 compl_curr_match = compl_first_match; 6516 for (compl_T *current = compl_first_match; current != NULL;) { 6517 if ((forward ? current->cp_cpt_source_idx < cpt_sources_index 6518 : current->cp_cpt_source_idx > cpt_sources_index)) { 6519 compl_curr_match = forward ? current : current->cp_next; 6520 current = current->cp_next; 6521 } else { 6522 break; 6523 } 6524 } 6525 } 6526 6527 /// Retrieve completion matches using the callback function "cb" and store the 6528 /// 'refresh:always' flag. 6529 static void get_cpt_func_completion_matches(Callback *cb) 6530 { 6531 cpt_source_T *cpt_src = &cpt_sources_array[cpt_sources_index]; 6532 int startcol = cpt_src->cs_startcol; 6533 6534 if (startcol == -2 || startcol == -3) { 6535 return; 6536 } 6537 6538 set_compl_globals(startcol, curwin->w_cursor.col, true); 6539 6540 // Insert the leader string (previously removed) before expansion. 6541 // This prevents flicker when `func` (e.g. an LSP client) is slow and 6542 // calls 'sleep', which triggers ui_flush(). 6543 if (!cpt_src->cs_refresh_always) { 6544 ins_compl_insert_bytes(ins_compl_leader(), -1); 6545 } 6546 6547 expand_by_function(0, cpt_compl_pattern.data, cb); 6548 6549 if (!cpt_src->cs_refresh_always) { 6550 ins_compl_delete(false); 6551 } 6552 6553 cpt_src->cs_refresh_always = compl_opt_refresh_always; 6554 compl_opt_refresh_always = false; 6555 } 6556 6557 /// Retrieve completion matches from functions in the 'cpt' option where the 6558 /// 'refresh:always' flag is set. 6559 static void cpt_compl_refresh(void) 6560 { 6561 // Make the completion list linear (non-cyclic) 6562 ins_compl_make_linear(); 6563 // Make a copy of 'cpt' in case the buffer gets wiped out 6564 char *cpt = xstrdup(curbuf->b_p_cpt); 6565 strip_caret_numbers_in_place(cpt); 6566 6567 cpt_sources_index = 0; 6568 for (char *p = cpt; *p;) { 6569 while (*p == ',' || *p == ' ') { // Skip delimiters 6570 p++; 6571 } 6572 if (*p == NUL) { 6573 break; 6574 } 6575 6576 if (cpt_sources_array[cpt_sources_index].cs_refresh_always) { 6577 Callback *cb = get_callback_if_cpt_func(p, cpt_sources_index); 6578 if (cb) { 6579 remove_old_matches(); 6580 int startcol; 6581 int ret = get_userdefined_compl_info(curwin->w_cursor.col, cb, &startcol); 6582 if (ret == FAIL) { 6583 if (startcol == -3) { 6584 cpt_sources_array[cpt_sources_index].cs_refresh_always = false; 6585 } else { 6586 startcol = -2; 6587 } 6588 } else if (startcol < 0 || startcol > curwin->w_cursor.col) { 6589 startcol = curwin->w_cursor.col; 6590 } 6591 cpt_sources_array[cpt_sources_index].cs_startcol = startcol; 6592 if (ret == OK) { 6593 compl_source_start_timer(cpt_sources_index); 6594 get_cpt_func_completion_matches(cb); 6595 } 6596 } 6597 } 6598 6599 (void)copy_option_part(&p, IObuff, IOSIZE, ","); // Advance p 6600 if (may_advance_cpt_index(p)) { 6601 (void)advance_cpt_sources_index_safe(); 6602 } 6603 } 6604 cpt_sources_index = -1; 6605 6606 xfree(cpt); 6607 // Make the list cyclic 6608 compl_matches = ins_compl_make_cyclic(); 6609 } 6610 6611 /// "preinserted()" function 6612 void f_preinserted(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) 6613 { 6614 if (ins_compl_preinsert_effect()) { 6615 rettv->vval.v_number = 1; 6616 } 6617 }