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