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