1 /* vi:set ts=8 sts=4 sw=4 noet: 2 * 3 * VIM - Vi IMproved by Bram Moolenaar 4 * 5 * Do ":help uganda" in Vim to read copying and usage conditions. 6 * Do ":help credits" in Vim to see a list of people who contributed. 7 * See README.txt for an overview of the Vim source code. 8 */ 9 10 /* 11 * edit.c: functions for Insert mode 12 */ 13 14 #include "vim.h" 15 16 #define BACKSPACE_CHAR 1 17 #define BACKSPACE_WORD 2 18 #define BACKSPACE_WORD_NOT_SPACE 3 19 #define BACKSPACE_LINE 4 20 21 // Set when doing something for completion that may call edit() recursively, 22 // which is not allowed. 23 static int compl_busy = FALSE; 24 25 26 static void ins_ctrl_v(void); 27 #ifdef FEAT_JOB_CHANNEL 28 static void init_prompt(int cmdchar_todo); 29 #endif 30 static void insert_special(int, int, int); 31 static void internal_format(int textwidth, int second_indent, int flags, int format_only, int c); 32 static void check_auto_format(int); 33 static void redo_literal(int c); 34 static void start_arrow_common(pos_T *end_insert_pos, int change); 35 #ifdef FEAT_SPELL 36 static void check_spell_redraw(void); 37 #endif 38 static void stop_insert(pos_T *end_insert_pos, int esc, int nomove); 39 static int echeck_abbr(int); 40 static void mb_replace_pop_ins(int cc); 41 static void replace_flush(void); 42 static void replace_do_bs(int limit_col); 43 static int del_char_after_col(int limit_col); 44 static void ins_reg(void); 45 static void ins_ctrl_g(void); 46 static void ins_ctrl_hat(void); 47 static int ins_esc(long *count, int cmdchar, int nomove); 48 #ifdef FEAT_RIGHTLEFT 49 static void ins_ctrl_(void); 50 #endif 51 static int ins_start_select(int c); 52 static void ins_insert(int replaceState); 53 static void ins_ctrl_o(void); 54 static void ins_shift(int c, int lastc); 55 static void ins_del(void); 56 static int ins_bs(int c, int mode, int *inserted_space_p); 57 #if defined(FEAT_GUI_TABLINE) || defined(PROTO) 58 static void ins_tabline(int c); 59 #endif 60 static void ins_left(void); 61 static void ins_home(int c); 62 static void ins_end(int c); 63 static void ins_s_left(void); 64 static void ins_right(void); 65 static void ins_s_right(void); 66 static void ins_up(int startcol); 67 static void ins_pageup(void); 68 static void ins_down(int startcol); 69 static void ins_pagedown(void); 70 #ifdef FEAT_DND 71 static void ins_drop(void); 72 #endif 73 static int ins_tab(void); 74 #ifdef FEAT_DIGRAPHS 75 static int ins_digraph(void); 76 #endif 77 static int ins_ctrl_ey(int tc); 78 #if defined(FEAT_EVAL) 79 static char_u *do_insert_char_pre(int c); 80 #endif 81 82 static colnr_T Insstart_textlen; // length of line when insert started 83 static colnr_T Insstart_blank_vcol; // vcol for first inserted blank 84 static int update_Insstart_orig = TRUE; // set Insstart_orig to Insstart 85 86 static char_u *last_insert = NULL; // the text of the previous insert, 87 // K_SPECIAL and CSI are escaped 88 static int last_insert_skip; // nr of chars in front of previous insert 89 static int new_insert_skip; // nr of chars in front of current insert 90 static int did_restart_edit; // "restart_edit" when calling edit() 91 92 #ifdef FEAT_CINDENT 93 static int can_cindent; // may do cindenting on this line 94 #endif 95 96 #ifdef FEAT_RIGHTLEFT 97 static int revins_on; // reverse insert mode on 98 static int revins_chars; // how much to skip after edit 99 static int revins_legal; // was the last char 'legal'? 100 static int revins_scol; // start column of revins session 101 #endif 102 103 static int ins_need_undo; // call u_save() before inserting a 104 // char. Set when edit() is called. 105 // after that arrow_used is used. 106 107 static int did_add_space = FALSE; // auto_format() added an extra space 108 // under the cursor 109 static int dont_sync_undo = FALSE; // CTRL-G U prevents syncing undo for 110 // the next left/right cursor key 111 112 /* 113 * edit(): Start inserting text. 114 * 115 * "cmdchar" can be: 116 * 'i' normal insert command 117 * 'a' normal append command 118 * K_PS bracketed paste 119 * 'R' replace command 120 * 'r' "r<CR>" command: insert one <CR>. Note: count can be > 1, for redo, 121 * but still only one <CR> is inserted. The <Esc> is not used for redo. 122 * 'g' "gI" command. 123 * 'V' "gR" command for Virtual Replace mode. 124 * 'v' "gr" command for single character Virtual Replace mode. 125 * 126 * This function is not called recursively. For CTRL-O commands, it returns 127 * and lets the caller handle the Normal-mode command. 128 * 129 * Return TRUE if a CTRL-O command caused the return (insert mode pending). 130 */ 131 int 132 edit( 133 int cmdchar, 134 int startln, // if set, insert at start of line 135 long count) 136 { 137 int c = 0; 138 char_u *ptr; 139 int lastc = 0; 140 int mincol; 141 static linenr_T o_lnum = 0; 142 int i; 143 int did_backspace = TRUE; // previous char was backspace 144 #ifdef FEAT_CINDENT 145 int line_is_white = FALSE; // line is empty before insert 146 #endif 147 linenr_T old_topline = 0; // topline before insertion 148 #ifdef FEAT_DIFF 149 int old_topfill = -1; 150 #endif 151 int inserted_space = FALSE; // just inserted a space 152 int replaceState = REPLACE; 153 int nomove = FALSE; // don't move cursor on return 154 #ifdef FEAT_JOB_CHANNEL 155 int cmdchar_todo = cmdchar; 156 #endif 157 158 // Remember whether editing was restarted after CTRL-O. 159 did_restart_edit = restart_edit; 160 161 // sleep before redrawing, needed for "CTRL-O :" that results in an 162 // error message 163 check_for_delay(TRUE); 164 165 // set Insstart_orig to Insstart 166 update_Insstart_orig = TRUE; 167 168 #ifdef HAVE_SANDBOX 169 // Don't allow inserting in the sandbox. 170 if (sandbox != 0) 171 { 172 emsg(_(e_sandbox)); 173 return FALSE; 174 } 175 #endif 176 // Don't allow changes in the buffer while editing the cmdline. The 177 // caller of getcmdline() may get confused. 178 if (textlock != 0) 179 { 180 emsg(_(e_secure)); 181 return FALSE; 182 } 183 184 // Don't allow recursive insert mode when busy with completion. 185 if (ins_compl_active() || compl_busy || pum_visible()) 186 { 187 emsg(_(e_secure)); 188 return FALSE; 189 } 190 ins_compl_clear(); // clear stuff for CTRL-X mode 191 192 /* 193 * Trigger InsertEnter autocommands. Do not do this for "r<CR>" or "grx". 194 */ 195 if (cmdchar != 'r' && cmdchar != 'v') 196 { 197 pos_T save_cursor = curwin->w_cursor; 198 199 #ifdef FEAT_EVAL 200 if (cmdchar == 'R') 201 ptr = (char_u *)"r"; 202 else if (cmdchar == 'V') 203 ptr = (char_u *)"v"; 204 else 205 ptr = (char_u *)"i"; 206 set_vim_var_string(VV_INSERTMODE, ptr, 1); 207 set_vim_var_string(VV_CHAR, NULL, -1); // clear v:char 208 #endif 209 ins_apply_autocmds(EVENT_INSERTENTER); 210 211 // Make sure the cursor didn't move. Do call check_cursor_col() in 212 // case the text was modified. Since Insert mode was not started yet 213 // a call to check_cursor_col() may move the cursor, especially with 214 // the "A" command, thus set State to avoid that. Also check that the 215 // line number is still valid (lines may have been deleted). 216 // Do not restore if v:char was set to a non-empty string. 217 if (!EQUAL_POS(curwin->w_cursor, save_cursor) 218 #ifdef FEAT_EVAL 219 && *get_vim_var_str(VV_CHAR) == NUL 220 #endif 221 && save_cursor.lnum <= curbuf->b_ml.ml_line_count) 222 { 223 int save_state = State; 224 225 curwin->w_cursor = save_cursor; 226 State = INSERT; 227 check_cursor_col(); 228 State = save_state; 229 } 230 } 231 232 #ifdef FEAT_CONCEAL 233 // Check if the cursor line needs redrawing before changing State. If 234 // 'concealcursor' is "n" it needs to be redrawn without concealing. 235 conceal_check_cursor_line(); 236 #endif 237 238 /* 239 * When doing a paste with the middle mouse button, Insstart is set to 240 * where the paste started. 241 */ 242 if (where_paste_started.lnum != 0) 243 Insstart = where_paste_started; 244 else 245 { 246 Insstart = curwin->w_cursor; 247 if (startln) 248 Insstart.col = 0; 249 } 250 Insstart_textlen = (colnr_T)linetabsize(ml_get_curline()); 251 Insstart_blank_vcol = MAXCOL; 252 if (!did_ai) 253 ai_col = 0; 254 255 if (cmdchar != NUL && restart_edit == 0) 256 { 257 ResetRedobuff(); 258 AppendNumberToRedobuff(count); 259 if (cmdchar == 'V' || cmdchar == 'v') 260 { 261 // "gR" or "gr" command 262 AppendCharToRedobuff('g'); 263 AppendCharToRedobuff((cmdchar == 'v') ? 'r' : 'R'); 264 } 265 else 266 { 267 if (cmdchar == K_PS) 268 AppendCharToRedobuff('a'); 269 else 270 AppendCharToRedobuff(cmdchar); 271 if (cmdchar == 'g') // "gI" command 272 AppendCharToRedobuff('I'); 273 else if (cmdchar == 'r') // "r<CR>" command 274 count = 1; // insert only one <CR> 275 } 276 } 277 278 if (cmdchar == 'R') 279 { 280 State = REPLACE; 281 } 282 else if (cmdchar == 'V' || cmdchar == 'v') 283 { 284 State = VREPLACE; 285 replaceState = VREPLACE; 286 orig_line_count = curbuf->b_ml.ml_line_count; 287 vr_lines_changed = 1; 288 } 289 else 290 State = INSERT; 291 292 stop_insert_mode = FALSE; 293 294 /* 295 * Need to recompute the cursor position, it might move when the cursor is 296 * on a TAB or special character. 297 */ 298 curs_columns(TRUE); 299 300 /* 301 * Enable langmap or IME, indicated by 'iminsert'. 302 * Note that IME may enabled/disabled without us noticing here, thus the 303 * 'iminsert' value may not reflect what is actually used. It is updated 304 * when hitting <Esc>. 305 */ 306 if (curbuf->b_p_iminsert == B_IMODE_LMAP) 307 State |= LANGMAP; 308 #ifdef HAVE_INPUT_METHOD 309 im_set_active(curbuf->b_p_iminsert == B_IMODE_IM); 310 #endif 311 312 setmouse(); 313 #ifdef FEAT_CMDL_INFO 314 clear_showcmd(); 315 #endif 316 #ifdef FEAT_RIGHTLEFT 317 // there is no reverse replace mode 318 revins_on = (State == INSERT && p_ri); 319 if (revins_on) 320 undisplay_dollar(); 321 revins_chars = 0; 322 revins_legal = 0; 323 revins_scol = -1; 324 #endif 325 if (!p_ek) 326 { 327 // Disable bracketed paste mode, we won't recognize the escape 328 // sequences. 329 out_str(T_BD); 330 331 // Disable modifyOtherKeys, keys with modifiers would cause exiting 332 // Insert mode. 333 out_str(T_CTE); 334 } 335 336 /* 337 * Handle restarting Insert mode. 338 * Don't do this for "CTRL-O ." (repeat an insert): In that case we get 339 * here with something in the stuff buffer. 340 */ 341 if (restart_edit != 0 && stuff_empty()) 342 { 343 /* 344 * After a paste we consider text typed to be part of the insert for 345 * the pasted text. You can backspace over the pasted text too. 346 */ 347 if (where_paste_started.lnum) 348 arrow_used = FALSE; 349 else 350 arrow_used = TRUE; 351 restart_edit = 0; 352 353 /* 354 * If the cursor was after the end-of-line before the CTRL-O and it is 355 * now at the end-of-line, put it after the end-of-line (this is not 356 * correct in very rare cases). 357 * Also do this if curswant is greater than the current virtual 358 * column. Eg after "^O$" or "^O80|". 359 */ 360 validate_virtcol(); 361 update_curswant(); 362 if (((ins_at_eol && curwin->w_cursor.lnum == o_lnum) 363 || curwin->w_curswant > curwin->w_virtcol) 364 && *(ptr = ml_get_curline() + curwin->w_cursor.col) != NUL) 365 { 366 if (ptr[1] == NUL) 367 ++curwin->w_cursor.col; 368 else if (has_mbyte) 369 { 370 i = (*mb_ptr2len)(ptr); 371 if (ptr[i] == NUL) 372 curwin->w_cursor.col += i; 373 } 374 } 375 ins_at_eol = FALSE; 376 } 377 else 378 arrow_used = FALSE; 379 380 // we are in insert mode now, don't need to start it anymore 381 need_start_insertmode = FALSE; 382 383 // Need to save the line for undo before inserting the first char. 384 ins_need_undo = TRUE; 385 386 where_paste_started.lnum = 0; 387 #ifdef FEAT_CINDENT 388 can_cindent = TRUE; 389 #endif 390 #ifdef FEAT_FOLDING 391 // The cursor line is not in a closed fold, unless 'insertmode' is set or 392 // restarting. 393 if (!p_im && did_restart_edit == 0) 394 foldOpenCursor(); 395 #endif 396 397 /* 398 * If 'showmode' is set, show the current (insert/replace/..) mode. 399 * A warning message for changing a readonly file is given here, before 400 * actually changing anything. It's put after the mode, if any. 401 */ 402 i = 0; 403 if (p_smd && msg_silent == 0) 404 i = showmode(); 405 406 if (!p_im && did_restart_edit == 0) 407 change_warning(i == 0 ? 0 : i + 1); 408 409 #ifdef CURSOR_SHAPE 410 ui_cursor_shape(); // may show different cursor shape 411 #endif 412 #ifdef FEAT_DIGRAPHS 413 do_digraph(-1); // clear digraphs 414 #endif 415 416 /* 417 * Get the current length of the redo buffer, those characters have to be 418 * skipped if we want to get to the inserted characters. 419 */ 420 ptr = get_inserted(); 421 if (ptr == NULL) 422 new_insert_skip = 0; 423 else 424 { 425 new_insert_skip = (int)STRLEN(ptr); 426 vim_free(ptr); 427 } 428 429 old_indent = 0; 430 431 /* 432 * Main loop in Insert mode: repeat until Insert mode is left. 433 */ 434 for (;;) 435 { 436 #ifdef FEAT_RIGHTLEFT 437 if (!revins_legal) 438 revins_scol = -1; // reset on illegal motions 439 else 440 revins_legal = 0; 441 #endif 442 if (arrow_used) // don't repeat insert when arrow key used 443 count = 0; 444 445 if (update_Insstart_orig) 446 Insstart_orig = Insstart; 447 448 if (stop_insert_mode && !pum_visible()) 449 { 450 // ":stopinsert" used or 'insertmode' reset 451 count = 0; 452 goto doESCkey; 453 } 454 455 // set curwin->w_curswant for next K_DOWN or K_UP 456 if (!arrow_used) 457 curwin->w_set_curswant = TRUE; 458 459 // If there is no typeahead may check for timestamps (e.g., for when a 460 // menu invoked a shell command). 461 if (stuff_empty()) 462 { 463 did_check_timestamps = FALSE; 464 if (need_check_timestamps) 465 check_timestamps(FALSE); 466 } 467 468 /* 469 * When emsg() was called msg_scroll will have been set. 470 */ 471 msg_scroll = FALSE; 472 473 #ifdef FEAT_GUI 474 // When 'mousefocus' is set a mouse movement may have taken us to 475 // another window. "need_mouse_correct" may then be set because of an 476 // autocommand. 477 if (need_mouse_correct) 478 gui_mouse_correct(); 479 #endif 480 481 #ifdef FEAT_FOLDING 482 // Open fold at the cursor line, according to 'foldopen'. 483 if (fdo_flags & FDO_INSERT) 484 foldOpenCursor(); 485 // Close folds where the cursor isn't, according to 'foldclose' 486 if (!char_avail()) 487 foldCheckClose(); 488 #endif 489 490 #ifdef FEAT_JOB_CHANNEL 491 if (bt_prompt(curbuf)) 492 { 493 init_prompt(cmdchar_todo); 494 cmdchar_todo = NUL; 495 } 496 #endif 497 498 /* 499 * If we inserted a character at the last position of the last line in 500 * the window, scroll the window one line up. This avoids an extra 501 * redraw. 502 * This is detected when the cursor column is smaller after inserting 503 * something. 504 * Don't do this when the topline changed already, it has 505 * already been adjusted (by insertchar() calling open_line())). 506 */ 507 if (curbuf->b_mod_set 508 && curwin->w_p_wrap 509 && !did_backspace 510 && curwin->w_topline == old_topline 511 #ifdef FEAT_DIFF 512 && curwin->w_topfill == old_topfill 513 #endif 514 ) 515 { 516 mincol = curwin->w_wcol; 517 validate_cursor_col(); 518 519 if ( 520 #ifdef FEAT_VARTABS 521 (int)curwin->w_wcol < mincol - tabstop_at( 522 get_nolist_virtcol(), curbuf->b_p_ts, 523 curbuf->b_p_vts_array) 524 #else 525 (int)curwin->w_wcol < mincol - curbuf->b_p_ts 526 #endif 527 && curwin->w_wrow == W_WINROW(curwin) 528 + curwin->w_height - 1 - get_scrolloff_value() 529 && (curwin->w_cursor.lnum != curwin->w_topline 530 #ifdef FEAT_DIFF 531 || curwin->w_topfill > 0 532 #endif 533 )) 534 { 535 #ifdef FEAT_DIFF 536 if (curwin->w_topfill > 0) 537 --curwin->w_topfill; 538 else 539 #endif 540 #ifdef FEAT_FOLDING 541 if (hasFolding(curwin->w_topline, NULL, &old_topline)) 542 set_topline(curwin, old_topline + 1); 543 else 544 #endif 545 set_topline(curwin, curwin->w_topline + 1); 546 } 547 } 548 549 // May need to adjust w_topline to show the cursor. 550 update_topline(); 551 552 did_backspace = FALSE; 553 554 validate_cursor(); // may set must_redraw 555 556 /* 557 * Redraw the display when no characters are waiting. 558 * Also shows mode, ruler and positions cursor. 559 */ 560 ins_redraw(TRUE); 561 562 if (curwin->w_p_scb) 563 do_check_scrollbind(TRUE); 564 565 if (curwin->w_p_crb) 566 do_check_cursorbind(); 567 update_curswant(); 568 old_topline = curwin->w_topline; 569 #ifdef FEAT_DIFF 570 old_topfill = curwin->w_topfill; 571 #endif 572 573 #ifdef USE_ON_FLY_SCROLL 574 dont_scroll = FALSE; // allow scrolling here 575 #endif 576 577 /* 578 * Get a character for Insert mode. Ignore K_IGNORE and K_NOP. 579 */ 580 if (c != K_CURSORHOLD) 581 lastc = c; // remember the previous char for CTRL-D 582 583 // After using CTRL-G U the next cursor key will not break undo. 584 if (dont_sync_undo == MAYBE) 585 dont_sync_undo = TRUE; 586 else 587 dont_sync_undo = FALSE; 588 if (cmdchar == K_PS) 589 // Got here from normal mode when bracketed paste started. 590 c = K_PS; 591 else 592 do 593 { 594 c = safe_vgetc(); 595 596 if (stop_insert_mode) 597 { 598 // Insert mode ended, possibly from a callback. 599 count = 0; 600 nomove = TRUE; 601 goto doESCkey; 602 } 603 } while (c == K_IGNORE || c == K_NOP); 604 605 // Don't want K_CURSORHOLD for the second key, e.g., after CTRL-V. 606 did_cursorhold = TRUE; 607 608 #ifdef FEAT_RIGHTLEFT 609 if (p_hkmap && KeyTyped) 610 c = hkmap(c); // Hebrew mode mapping 611 #endif 612 613 /* 614 * Special handling of keys while the popup menu is visible or wanted 615 * and the cursor is still in the completed word. Only when there is 616 * a match, skip this when no matches were found. 617 */ 618 if (ins_compl_active() 619 && pum_wanted() 620 && curwin->w_cursor.col >= ins_compl_col() 621 && ins_compl_has_shown_match()) 622 { 623 // BS: Delete one character from "compl_leader". 624 if ((c == K_BS || c == Ctrl_H) 625 && curwin->w_cursor.col > ins_compl_col() 626 && (c = ins_compl_bs()) == NUL) 627 continue; 628 629 // When no match was selected or it was edited. 630 if (!ins_compl_used_match()) 631 { 632 // CTRL-L: Add one character from the current match to 633 // "compl_leader". Except when at the original match and 634 // there is nothing to add, CTRL-L works like CTRL-P then. 635 if (c == Ctrl_L 636 && (!ctrl_x_mode_line_or_eval() 637 || ins_compl_long_shown_match())) 638 { 639 ins_compl_addfrommatch(); 640 continue; 641 } 642 643 // A non-white character that fits in with the current 644 // completion: Add to "compl_leader". 645 if (ins_compl_accept_char(c)) 646 { 647 #if defined(FEAT_EVAL) 648 // Trigger InsertCharPre. 649 char_u *str = do_insert_char_pre(c); 650 char_u *p; 651 652 if (str != NULL) 653 { 654 for (p = str; *p != NUL; MB_PTR_ADV(p)) 655 ins_compl_addleader(PTR2CHAR(p)); 656 vim_free(str); 657 } 658 else 659 #endif 660 ins_compl_addleader(c); 661 continue; 662 } 663 664 // Pressing CTRL-Y selects the current match. When 665 // ins_compl_enter_selects() is set the Enter key does the 666 // same. 667 if ((c == Ctrl_Y || (ins_compl_enter_selects() 668 && (c == CAR || c == K_KENTER || c == NL))) 669 && stop_arrow() == OK) 670 { 671 ins_compl_delete(); 672 ins_compl_insert(FALSE); 673 } 674 } 675 } 676 677 // Prepare for or stop CTRL-X mode. This doesn't do completion, but 678 // it does fix up the text when finishing completion. 679 ins_compl_init_get_longest(); 680 if (ins_compl_prep(c)) 681 continue; 682 683 // CTRL-\ CTRL-N goes to Normal mode, 684 // CTRL-\ CTRL-G goes to mode selected with 'insertmode', 685 // CTRL-\ CTRL-O is like CTRL-O but without moving the cursor. 686 if (c == Ctrl_BSL) 687 { 688 // may need to redraw when no more chars available now 689 ins_redraw(FALSE); 690 ++no_mapping; 691 ++allow_keys; 692 c = plain_vgetc(); 693 --no_mapping; 694 --allow_keys; 695 if (c != Ctrl_N && c != Ctrl_G && c != Ctrl_O) 696 { 697 // it's something else 698 vungetc(c); 699 c = Ctrl_BSL; 700 } 701 else if (c == Ctrl_G && p_im) 702 continue; 703 else 704 { 705 if (c == Ctrl_O) 706 { 707 ins_ctrl_o(); 708 ins_at_eol = FALSE; // cursor keeps its column 709 nomove = TRUE; 710 } 711 count = 0; 712 goto doESCkey; 713 } 714 } 715 716 #ifdef FEAT_DIGRAPHS 717 c = do_digraph(c); 718 #endif 719 720 if ((c == Ctrl_V || c == Ctrl_Q) && ctrl_x_mode_cmdline()) 721 goto docomplete; 722 if (c == Ctrl_V || c == Ctrl_Q) 723 { 724 ins_ctrl_v(); 725 c = Ctrl_V; // pretend CTRL-V is last typed character 726 continue; 727 } 728 729 #ifdef FEAT_CINDENT 730 if (cindent_on() && ctrl_x_mode_none()) 731 { 732 // A key name preceded by a bang means this key is not to be 733 // inserted. Skip ahead to the re-indenting below. 734 // A key name preceded by a star means that indenting has to be 735 // done before inserting the key. 736 line_is_white = inindent(0); 737 if (in_cinkeys(c, '!', line_is_white)) 738 goto force_cindent; 739 if (can_cindent && in_cinkeys(c, '*', line_is_white) 740 && stop_arrow() == OK) 741 do_c_expr_indent(); 742 } 743 #endif 744 745 #ifdef FEAT_RIGHTLEFT 746 if (curwin->w_p_rl) 747 switch (c) 748 { 749 case K_LEFT: c = K_RIGHT; break; 750 case K_S_LEFT: c = K_S_RIGHT; break; 751 case K_C_LEFT: c = K_C_RIGHT; break; 752 case K_RIGHT: c = K_LEFT; break; 753 case K_S_RIGHT: c = K_S_LEFT; break; 754 case K_C_RIGHT: c = K_C_LEFT; break; 755 } 756 #endif 757 758 /* 759 * If 'keymodel' contains "startsel", may start selection. If it 760 * does, a CTRL-O and c will be stuffed, we need to get these 761 * characters. 762 */ 763 if (ins_start_select(c)) 764 continue; 765 766 /* 767 * The big switch to handle a character in insert mode. 768 */ 769 switch (c) 770 { 771 case ESC: // End input mode 772 if (echeck_abbr(ESC + ABBR_OFF)) 773 break; 774 // FALLTHROUGH 775 776 case Ctrl_C: // End input mode 777 #ifdef FEAT_CMDWIN 778 if (c == Ctrl_C && cmdwin_type != 0) 779 { 780 // Close the cmdline window. 781 cmdwin_result = K_IGNORE; 782 got_int = FALSE; // don't stop executing autocommands et al. 783 nomove = TRUE; 784 goto doESCkey; 785 } 786 #endif 787 #ifdef FEAT_JOB_CHANNEL 788 if (c == Ctrl_C && bt_prompt(curbuf)) 789 { 790 if (invoke_prompt_interrupt()) 791 { 792 if (!bt_prompt(curbuf)) 793 // buffer changed to a non-prompt buffer, get out of 794 // Insert mode 795 goto doESCkey; 796 break; 797 } 798 } 799 #endif 800 801 #ifdef UNIX 802 do_intr: 803 #endif 804 // when 'insertmode' set, and not halfway a mapping, don't leave 805 // Insert mode 806 if (goto_im()) 807 { 808 if (got_int) 809 { 810 (void)vgetc(); // flush all buffers 811 got_int = FALSE; 812 } 813 else 814 vim_beep(BO_IM); 815 break; 816 } 817 doESCkey: 818 /* 819 * This is the ONLY return from edit()! 820 */ 821 // Always update o_lnum, so that a "CTRL-O ." that adds a line 822 // still puts the cursor back after the inserted text. 823 if (ins_at_eol && gchar_cursor() == NUL) 824 o_lnum = curwin->w_cursor.lnum; 825 826 if (ins_esc(&count, cmdchar, nomove)) 827 { 828 // When CTRL-C was typed got_int will be set, with the result 829 // that the autocommands won't be executed. When mapped got_int 830 // is not set, but let's keep the behavior the same. 831 if (cmdchar != 'r' && cmdchar != 'v' && c != Ctrl_C) 832 ins_apply_autocmds(EVENT_INSERTLEAVE); 833 did_cursorhold = FALSE; 834 return (c == Ctrl_O); 835 } 836 continue; 837 838 case Ctrl_Z: // suspend when 'insertmode' set 839 if (!p_im) 840 goto normalchar; // insert CTRL-Z as normal char 841 do_cmdline_cmd((char_u *)"stop"); 842 #ifdef CURSOR_SHAPE 843 ui_cursor_shape(); // may need to update cursor shape 844 #endif 845 continue; 846 847 case Ctrl_O: // execute one command 848 #ifdef FEAT_COMPL_FUNC 849 if (ctrl_x_mode_omni()) 850 goto docomplete; 851 #endif 852 if (echeck_abbr(Ctrl_O + ABBR_OFF)) 853 break; 854 ins_ctrl_o(); 855 856 // don't move the cursor left when 'virtualedit' has "onemore". 857 if (ve_flags & VE_ONEMORE) 858 { 859 ins_at_eol = FALSE; 860 nomove = TRUE; 861 } 862 count = 0; 863 goto doESCkey; 864 865 case K_INS: // toggle insert/replace mode 866 case K_KINS: 867 ins_insert(replaceState); 868 break; 869 870 case K_SELECT: // end of Select mode mapping - ignore 871 break; 872 873 case K_HELP: // Help key works like <ESC> <Help> 874 case K_F1: 875 case K_XF1: 876 stuffcharReadbuff(K_HELP); 877 if (p_im) 878 need_start_insertmode = TRUE; 879 goto doESCkey; 880 881 #ifdef FEAT_NETBEANS_INTG 882 case K_F21: // NetBeans command 883 ++no_mapping; // don't map the next key hits 884 i = plain_vgetc(); 885 --no_mapping; 886 netbeans_keycommand(i); 887 break; 888 #endif 889 890 case K_ZERO: // Insert the previously inserted text. 891 case NUL: 892 case Ctrl_A: 893 // For ^@ the trailing ESC will end the insert, unless there is an 894 // error. 895 if (stuff_inserted(NUL, 1L, (c == Ctrl_A)) == FAIL 896 && c != Ctrl_A && !p_im) 897 goto doESCkey; // quit insert mode 898 inserted_space = FALSE; 899 break; 900 901 case Ctrl_R: // insert the contents of a register 902 ins_reg(); 903 auto_format(FALSE, TRUE); 904 inserted_space = FALSE; 905 break; 906 907 case Ctrl_G: // commands starting with CTRL-G 908 ins_ctrl_g(); 909 break; 910 911 case Ctrl_HAT: // switch input mode and/or langmap 912 ins_ctrl_hat(); 913 break; 914 915 #ifdef FEAT_RIGHTLEFT 916 case Ctrl__: // switch between languages 917 if (!p_ari) 918 goto normalchar; 919 ins_ctrl_(); 920 break; 921 #endif 922 923 case Ctrl_D: // Make indent one shiftwidth smaller. 924 #if defined(FEAT_FIND_ID) 925 if (ctrl_x_mode_path_defines()) 926 goto docomplete; 927 #endif 928 // FALLTHROUGH 929 930 case Ctrl_T: // Make indent one shiftwidth greater. 931 if (c == Ctrl_T && ctrl_x_mode_thesaurus()) 932 { 933 if (has_compl_option(FALSE)) 934 goto docomplete; 935 break; 936 } 937 938 ins_shift(c, lastc); 939 auto_format(FALSE, TRUE); 940 inserted_space = FALSE; 941 break; 942 943 case K_DEL: // delete character under the cursor 944 case K_KDEL: 945 ins_del(); 946 auto_format(FALSE, TRUE); 947 break; 948 949 case K_BS: // delete character before the cursor 950 case Ctrl_H: 951 did_backspace = ins_bs(c, BACKSPACE_CHAR, &inserted_space); 952 auto_format(FALSE, TRUE); 953 break; 954 955 case Ctrl_W: // delete word before the cursor 956 #ifdef FEAT_JOB_CHANNEL 957 if (bt_prompt(curbuf) && (mod_mask & MOD_MASK_SHIFT) == 0) 958 { 959 // In a prompt window CTRL-W is used for window commands. 960 // Use Shift-CTRL-W to delete a word. 961 stuffcharReadbuff(Ctrl_W); 962 restart_edit = 'A'; 963 nomove = TRUE; 964 count = 0; 965 goto doESCkey; 966 } 967 #endif 968 did_backspace = ins_bs(c, BACKSPACE_WORD, &inserted_space); 969 auto_format(FALSE, TRUE); 970 break; 971 972 case Ctrl_U: // delete all inserted text in current line 973 # ifdef FEAT_COMPL_FUNC 974 // CTRL-X CTRL-U completes with 'completefunc'. 975 if (ctrl_x_mode_function()) 976 goto docomplete; 977 # endif 978 did_backspace = ins_bs(c, BACKSPACE_LINE, &inserted_space); 979 auto_format(FALSE, TRUE); 980 inserted_space = FALSE; 981 break; 982 983 case K_LEFTMOUSE: // mouse keys 984 case K_LEFTMOUSE_NM: 985 case K_LEFTDRAG: 986 case K_LEFTRELEASE: 987 case K_LEFTRELEASE_NM: 988 case K_MOUSEMOVE: 989 case K_MIDDLEMOUSE: 990 case K_MIDDLEDRAG: 991 case K_MIDDLERELEASE: 992 case K_RIGHTMOUSE: 993 case K_RIGHTDRAG: 994 case K_RIGHTRELEASE: 995 case K_X1MOUSE: 996 case K_X1DRAG: 997 case K_X1RELEASE: 998 case K_X2MOUSE: 999 case K_X2DRAG: 1000 case K_X2RELEASE: 1001 ins_mouse(c); 1002 break; 1003 1004 case K_MOUSEDOWN: // Default action for scroll wheel up: scroll up 1005 ins_mousescroll(MSCR_DOWN); 1006 break; 1007 1008 case K_MOUSEUP: // Default action for scroll wheel down: scroll down 1009 ins_mousescroll(MSCR_UP); 1010 break; 1011 1012 case K_MOUSELEFT: // Scroll wheel left 1013 ins_mousescroll(MSCR_LEFT); 1014 break; 1015 1016 case K_MOUSERIGHT: // Scroll wheel right 1017 ins_mousescroll(MSCR_RIGHT); 1018 break; 1019 1020 case K_PS: 1021 bracketed_paste(PASTE_INSERT, FALSE, NULL); 1022 if (cmdchar == K_PS) 1023 // invoked from normal mode, bail out 1024 goto doESCkey; 1025 break; 1026 case K_PE: 1027 // Got K_PE without K_PS, ignore. 1028 break; 1029 1030 #ifdef FEAT_GUI_TABLINE 1031 case K_TABLINE: 1032 case K_TABMENU: 1033 ins_tabline(c); 1034 break; 1035 #endif 1036 1037 case K_IGNORE: // Something mapped to nothing 1038 break; 1039 1040 case K_CURSORHOLD: // Didn't type something for a while. 1041 ins_apply_autocmds(EVENT_CURSORHOLDI); 1042 did_cursorhold = TRUE; 1043 break; 1044 1045 #ifdef FEAT_GUI_MSWIN 1046 // On MS-Windows ignore <M-F4>, we get it when closing the window 1047 // was cancelled. 1048 case K_F4: 1049 if (mod_mask != MOD_MASK_ALT) 1050 goto normalchar; 1051 break; 1052 #endif 1053 1054 #ifdef FEAT_GUI 1055 case K_VER_SCROLLBAR: 1056 ins_scroll(); 1057 break; 1058 1059 case K_HOR_SCROLLBAR: 1060 ins_horscroll(); 1061 break; 1062 #endif 1063 1064 case K_HOME: // <Home> 1065 case K_KHOME: 1066 case K_S_HOME: 1067 case K_C_HOME: 1068 ins_home(c); 1069 break; 1070 1071 case K_END: // <End> 1072 case K_KEND: 1073 case K_S_END: 1074 case K_C_END: 1075 ins_end(c); 1076 break; 1077 1078 case K_LEFT: // <Left> 1079 if (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL)) 1080 ins_s_left(); 1081 else 1082 ins_left(); 1083 break; 1084 1085 case K_S_LEFT: // <S-Left> 1086 case K_C_LEFT: 1087 ins_s_left(); 1088 break; 1089 1090 case K_RIGHT: // <Right> 1091 if (mod_mask & (MOD_MASK_SHIFT|MOD_MASK_CTRL)) 1092 ins_s_right(); 1093 else 1094 ins_right(); 1095 break; 1096 1097 case K_S_RIGHT: // <S-Right> 1098 case K_C_RIGHT: 1099 ins_s_right(); 1100 break; 1101 1102 case K_UP: // <Up> 1103 if (pum_visible()) 1104 goto docomplete; 1105 if (mod_mask & MOD_MASK_SHIFT) 1106 ins_pageup(); 1107 else 1108 ins_up(FALSE); 1109 break; 1110 1111 case K_S_UP: // <S-Up> 1112 case K_PAGEUP: 1113 case K_KPAGEUP: 1114 if (pum_visible()) 1115 goto docomplete; 1116 ins_pageup(); 1117 break; 1118 1119 case K_DOWN: // <Down> 1120 if (pum_visible()) 1121 goto docomplete; 1122 if (mod_mask & MOD_MASK_SHIFT) 1123 ins_pagedown(); 1124 else 1125 ins_down(FALSE); 1126 break; 1127 1128 case K_S_DOWN: // <S-Down> 1129 case K_PAGEDOWN: 1130 case K_KPAGEDOWN: 1131 if (pum_visible()) 1132 goto docomplete; 1133 ins_pagedown(); 1134 break; 1135 1136 #ifdef FEAT_DND 1137 case K_DROP: // drag-n-drop event 1138 ins_drop(); 1139 break; 1140 #endif 1141 1142 case K_S_TAB: // When not mapped, use like a normal TAB 1143 c = TAB; 1144 // FALLTHROUGH 1145 1146 case TAB: // TAB or Complete patterns along path 1147 #if defined(FEAT_FIND_ID) 1148 if (ctrl_x_mode_path_patterns()) 1149 goto docomplete; 1150 #endif 1151 inserted_space = FALSE; 1152 if (ins_tab()) 1153 goto normalchar; // insert TAB as a normal char 1154 auto_format(FALSE, TRUE); 1155 break; 1156 1157 case K_KENTER: // <Enter> 1158 c = CAR; 1159 // FALLTHROUGH 1160 case CAR: 1161 case NL: 1162 #if defined(FEAT_QUICKFIX) 1163 // In a quickfix window a <CR> jumps to the error under the 1164 // cursor. 1165 if (bt_quickfix(curbuf) && c == CAR) 1166 { 1167 if (curwin->w_llist_ref == NULL) // quickfix window 1168 do_cmdline_cmd((char_u *)".cc"); 1169 else // location list window 1170 do_cmdline_cmd((char_u *)".ll"); 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 #ifdef FEAT_JOB_CHANNEL 1183 if (bt_prompt(curbuf)) 1184 { 1185 invoke_prompt_callback(); 1186 if (!bt_prompt(curbuf)) 1187 // buffer changed to a non-prompt buffer, get out of 1188 // Insert mode 1189 goto doESCkey; 1190 break; 1191 } 1192 #endif 1193 if (ins_eol(c) == FAIL && !p_im) 1194 goto doESCkey; // out of memory 1195 auto_format(FALSE, FALSE); 1196 inserted_space = FALSE; 1197 break; 1198 1199 case Ctrl_K: // digraph or keyword completion 1200 if (ctrl_x_mode_dictionary()) 1201 { 1202 if (has_compl_option(TRUE)) 1203 goto docomplete; 1204 break; 1205 } 1206 #ifdef FEAT_DIGRAPHS 1207 c = ins_digraph(); 1208 if (c == NUL) 1209 break; 1210 #endif 1211 goto normalchar; 1212 1213 case Ctrl_X: // Enter CTRL-X mode 1214 ins_ctrl_x(); 1215 break; 1216 1217 case Ctrl_RSB: // Tag name completion after ^X 1218 if (!ctrl_x_mode_tags()) 1219 goto normalchar; 1220 goto docomplete; 1221 1222 case Ctrl_F: // File name completion after ^X 1223 if (!ctrl_x_mode_files()) 1224 goto normalchar; 1225 goto docomplete; 1226 1227 case 's': // Spelling completion after ^X 1228 case Ctrl_S: 1229 if (!ctrl_x_mode_spell()) 1230 goto normalchar; 1231 goto docomplete; 1232 1233 case Ctrl_L: // Whole line completion after ^X 1234 if (!ctrl_x_mode_whole_line()) 1235 { 1236 // CTRL-L with 'insertmode' set: Leave Insert mode 1237 if (p_im) 1238 { 1239 if (echeck_abbr(Ctrl_L + ABBR_OFF)) 1240 break; 1241 goto doESCkey; 1242 } 1243 goto normalchar; 1244 } 1245 // FALLTHROUGH 1246 1247 case Ctrl_P: // Do previous/next pattern completion 1248 case Ctrl_N: 1249 // if 'complete' is empty then plain ^P is no longer special, 1250 // but it is under other ^X modes 1251 if (*curbuf->b_p_cpt == NUL 1252 && (ctrl_x_mode_normal() || ctrl_x_mode_whole_line()) 1253 && !(compl_cont_status & CONT_LOCAL)) 1254 goto normalchar; 1255 1256 docomplete: 1257 compl_busy = TRUE; 1258 #ifdef FEAT_FOLDING 1259 disable_fold_update++; // don't redraw folds here 1260 #endif 1261 if (ins_complete(c, TRUE) == FAIL) 1262 compl_cont_status = 0; 1263 #ifdef FEAT_FOLDING 1264 disable_fold_update--; 1265 #endif 1266 compl_busy = FALSE; 1267 break; 1268 1269 case Ctrl_Y: // copy from previous line or scroll down 1270 case Ctrl_E: // copy from next line or scroll up 1271 c = ins_ctrl_ey(c); 1272 break; 1273 1274 default: 1275 #ifdef UNIX 1276 if (c == intr_char) // special interrupt char 1277 goto do_intr; 1278 #endif 1279 1280 normalchar: 1281 /* 1282 * Insert a normal character. 1283 */ 1284 #if defined(FEAT_EVAL) 1285 if (!p_paste) 1286 { 1287 // Trigger InsertCharPre. 1288 char_u *str = do_insert_char_pre(c); 1289 char_u *p; 1290 1291 if (str != NULL) 1292 { 1293 if (*str != NUL && stop_arrow() != FAIL) 1294 { 1295 // Insert the new value of v:char literally. 1296 for (p = str; *p != NUL; MB_PTR_ADV(p)) 1297 { 1298 c = PTR2CHAR(p); 1299 if (c == CAR || c == K_KENTER || c == NL) 1300 ins_eol(c); 1301 else 1302 ins_char(c); 1303 } 1304 AppendToRedobuffLit(str, -1); 1305 } 1306 vim_free(str); 1307 c = NUL; 1308 } 1309 1310 // If the new value is already inserted or an empty string 1311 // then don't insert any character. 1312 if (c == NUL) 1313 break; 1314 } 1315 #endif 1316 #ifdef FEAT_SMARTINDENT 1317 // Try to perform smart-indenting. 1318 ins_try_si(c); 1319 #endif 1320 1321 if (c == ' ') 1322 { 1323 inserted_space = TRUE; 1324 #ifdef FEAT_CINDENT 1325 if (inindent(0)) 1326 can_cindent = FALSE; 1327 #endif 1328 if (Insstart_blank_vcol == MAXCOL 1329 && curwin->w_cursor.lnum == Insstart.lnum) 1330 Insstart_blank_vcol = get_nolist_virtcol(); 1331 } 1332 1333 // Insert a normal character and check for abbreviations on a 1334 // special character. Let CTRL-] expand abbreviations without 1335 // inserting it. 1336 if (vim_iswordc(c) || (!echeck_abbr( 1337 // Add ABBR_OFF for characters above 0x100, this is 1338 // what check_abbr() expects. 1339 (has_mbyte && c >= 0x100) ? (c + ABBR_OFF) : c) 1340 && c != Ctrl_RSB)) 1341 { 1342 insert_special(c, FALSE, FALSE); 1343 #ifdef FEAT_RIGHTLEFT 1344 revins_legal++; 1345 revins_chars++; 1346 #endif 1347 } 1348 1349 auto_format(FALSE, TRUE); 1350 1351 #ifdef FEAT_FOLDING 1352 // When inserting a character the cursor line must never be in a 1353 // closed fold. 1354 foldOpenCursor(); 1355 #endif 1356 break; 1357 } // end of switch (c) 1358 1359 // If typed something may trigger CursorHoldI again. 1360 if (c != K_CURSORHOLD 1361 #ifdef FEAT_COMPL_FUNC 1362 // but not in CTRL-X mode, a script can't restore the state 1363 && ctrl_x_mode_normal() 1364 #endif 1365 ) 1366 did_cursorhold = FALSE; 1367 1368 // If the cursor was moved we didn't just insert a space 1369 if (arrow_used) 1370 inserted_space = FALSE; 1371 1372 #ifdef FEAT_CINDENT 1373 if (can_cindent && cindent_on() && ctrl_x_mode_normal()) 1374 { 1375 force_cindent: 1376 /* 1377 * Indent now if a key was typed that is in 'cinkeys'. 1378 */ 1379 if (in_cinkeys(c, ' ', line_is_white)) 1380 { 1381 if (stop_arrow() == OK) 1382 // re-indent the current line 1383 do_c_expr_indent(); 1384 } 1385 } 1386 #endif // FEAT_CINDENT 1387 1388 } // for (;;) 1389 // NOTREACHED 1390 } 1391 1392 int 1393 ins_need_undo_get(void) 1394 { 1395 return ins_need_undo; 1396 } 1397 1398 /* 1399 * Redraw for Insert mode. 1400 * This is postponed until getting the next character to make '$' in the 'cpo' 1401 * option work correctly. 1402 * Only redraw when there are no characters available. This speeds up 1403 * inserting sequences of characters (e.g., for CTRL-R). 1404 */ 1405 void 1406 ins_redraw(int ready) // not busy with something 1407 { 1408 #ifdef FEAT_CONCEAL 1409 linenr_T conceal_old_cursor_line = 0; 1410 linenr_T conceal_new_cursor_line = 0; 1411 int conceal_update_lines = FALSE; 1412 #endif 1413 1414 if (char_avail()) 1415 return; 1416 1417 // Trigger CursorMoved if the cursor moved. Not when the popup menu is 1418 // visible, the command might delete it. 1419 if (ready && (has_cursormovedI() 1420 # ifdef FEAT_PROP_POPUP 1421 || popup_visible 1422 # endif 1423 # if defined(FEAT_CONCEAL) 1424 || curwin->w_p_cole > 0 1425 # endif 1426 ) 1427 && !EQUAL_POS(last_cursormoved, curwin->w_cursor) 1428 && !pum_visible()) 1429 { 1430 # ifdef FEAT_SYN_HL 1431 // Need to update the screen first, to make sure syntax 1432 // highlighting is correct after making a change (e.g., inserting 1433 // a "(". The autocommand may also require a redraw, so it's done 1434 // again below, unfortunately. 1435 if (syntax_present(curwin) && must_redraw) 1436 update_screen(0); 1437 # endif 1438 if (has_cursormovedI()) 1439 { 1440 // Make sure curswant is correct, an autocommand may call 1441 // getcurpos(). 1442 update_curswant(); 1443 ins_apply_autocmds(EVENT_CURSORMOVEDI); 1444 } 1445 #ifdef FEAT_PROP_POPUP 1446 if (popup_visible) 1447 popup_check_cursor_pos(); 1448 #endif 1449 # ifdef FEAT_CONCEAL 1450 if (curwin->w_p_cole > 0) 1451 { 1452 conceal_old_cursor_line = last_cursormoved.lnum; 1453 conceal_new_cursor_line = curwin->w_cursor.lnum; 1454 conceal_update_lines = TRUE; 1455 } 1456 # endif 1457 last_cursormoved = curwin->w_cursor; 1458 } 1459 1460 // Trigger TextChangedI if b_changedtick differs. 1461 if (ready && has_textchangedI() 1462 && curbuf->b_last_changedtick != CHANGEDTICK(curbuf) 1463 && !pum_visible()) 1464 { 1465 aco_save_T aco; 1466 varnumber_T tick = CHANGEDTICK(curbuf); 1467 1468 // save and restore curwin and curbuf, in case the autocmd changes them 1469 aucmd_prepbuf(&aco, curbuf); 1470 apply_autocmds(EVENT_TEXTCHANGEDI, NULL, NULL, FALSE, curbuf); 1471 aucmd_restbuf(&aco); 1472 curbuf->b_last_changedtick = CHANGEDTICK(curbuf); 1473 if (tick != CHANGEDTICK(curbuf)) // see ins_apply_autocmds() 1474 u_save(curwin->w_cursor.lnum, 1475 (linenr_T)(curwin->w_cursor.lnum + 1)); 1476 } 1477 1478 // Trigger TextChangedP if b_changedtick differs. When the popupmenu closes 1479 // TextChangedI will need to trigger for backwards compatibility, thus use 1480 // different b_last_changedtick* variables. 1481 if (ready && has_textchangedP() 1482 && curbuf->b_last_changedtick_pum != CHANGEDTICK(curbuf) 1483 && pum_visible()) 1484 { 1485 aco_save_T aco; 1486 varnumber_T tick = CHANGEDTICK(curbuf); 1487 1488 // save and restore curwin and curbuf, in case the autocmd changes them 1489 aucmd_prepbuf(&aco, curbuf); 1490 apply_autocmds(EVENT_TEXTCHANGEDP, NULL, NULL, FALSE, curbuf); 1491 aucmd_restbuf(&aco); 1492 curbuf->b_last_changedtick_pum = CHANGEDTICK(curbuf); 1493 if (tick != CHANGEDTICK(curbuf)) // see ins_apply_autocmds() 1494 u_save(curwin->w_cursor.lnum, 1495 (linenr_T)(curwin->w_cursor.lnum + 1)); 1496 } 1497 1498 // Trigger SafeState if nothing is pending. 1499 may_trigger_safestate(ready 1500 && !ins_compl_active() 1501 && !pum_visible()); 1502 1503 #if defined(FEAT_CONCEAL) 1504 if ((conceal_update_lines 1505 && (conceal_old_cursor_line != conceal_new_cursor_line 1506 || conceal_cursor_line(curwin))) 1507 || need_cursor_line_redraw) 1508 { 1509 if (conceal_old_cursor_line != conceal_new_cursor_line) 1510 redrawWinline(curwin, conceal_old_cursor_line); 1511 redrawWinline(curwin, conceal_new_cursor_line == 0 1512 ? curwin->w_cursor.lnum : conceal_new_cursor_line); 1513 curwin->w_valid &= ~VALID_CROW; 1514 need_cursor_line_redraw = FALSE; 1515 } 1516 #endif 1517 if (must_redraw) 1518 update_screen(0); 1519 else if (clear_cmdline || redraw_cmdline) 1520 showmode(); // clear cmdline and show mode 1521 showruler(FALSE); 1522 setcursor(); 1523 emsg_on_display = FALSE; // may remove error message now 1524 } 1525 1526 /* 1527 * Handle a CTRL-V or CTRL-Q typed in Insert mode. 1528 */ 1529 static void 1530 ins_ctrl_v(void) 1531 { 1532 int c; 1533 int did_putchar = FALSE; 1534 int prev_mod_mask = mod_mask; 1535 1536 // may need to redraw when no more chars available now 1537 ins_redraw(FALSE); 1538 1539 if (redrawing() && !char_avail()) 1540 { 1541 edit_putchar('^', TRUE); 1542 did_putchar = TRUE; 1543 } 1544 AppendToRedobuff((char_u *)CTRL_V_STR); // CTRL-V 1545 1546 #ifdef FEAT_CMDL_INFO 1547 add_to_showcmd_c(Ctrl_V); 1548 #endif 1549 1550 c = get_literal(); 1551 if (did_putchar) 1552 // when the line fits in 'columns' the '^' is at the start of the next 1553 // line and will not removed by the redraw 1554 edit_unputchar(); 1555 #ifdef FEAT_CMDL_INFO 1556 clear_showcmd(); 1557 #endif 1558 1559 if ((c == ESC || c == CSI) && !(prev_mod_mask & MOD_MASK_SHIFT)) 1560 // Using CTRL-V: Change any modifyOtherKeys ESC sequence to a normal 1561 // key. Don't do this for CTRL-SHIFT-V. 1562 c = decodeModifyOtherKeys(c); 1563 1564 insert_special(c, FALSE, TRUE); 1565 #ifdef FEAT_RIGHTLEFT 1566 revins_chars++; 1567 revins_legal++; 1568 #endif 1569 } 1570 1571 /* 1572 * After getting an ESC or CSI for a literal key: If the typeahead buffer 1573 * contains a modifyOtherKeys sequence then decode it and return the result. 1574 * Otherwise return "c". 1575 * Note that this doesn't wait for characters, they must be in the typeahead 1576 * buffer already. 1577 */ 1578 int 1579 decodeModifyOtherKeys(int c) 1580 { 1581 char_u *p = typebuf.tb_buf + typebuf.tb_off; 1582 int idx; 1583 int form = 0; 1584 int argidx = 0; 1585 int arg[2] = {0, 0}; 1586 1587 // Recognize: 1588 // form 0: {lead}{key};{modifier}u 1589 // form 1: {lead}27;{modifier};{key}~ 1590 if ((c == CSI || (c == ESC && *p == '[')) && typebuf.tb_len >= 4) 1591 { 1592 idx = (*p == '['); 1593 if (p[idx] == '2' && p[idx + 1] == '7' && p[idx + 2] == ';') 1594 { 1595 form = 1; 1596 idx += 3; 1597 } 1598 while (idx < typebuf.tb_len && argidx < 2) 1599 { 1600 if (p[idx] == ';') 1601 ++argidx; 1602 else if (VIM_ISDIGIT(p[idx])) 1603 arg[argidx] = arg[argidx] * 10 + (p[idx] - '0'); 1604 else 1605 break; 1606 ++idx; 1607 } 1608 if (idx < typebuf.tb_len 1609 && p[idx] == (form == 1 ? '~' : 'u') 1610 && argidx == 1) 1611 { 1612 // Match, consume the code. 1613 typebuf.tb_off += idx + 1; 1614 typebuf.tb_len -= idx + 1; 1615 1616 mod_mask = decode_modifiers(arg[!form]); 1617 c = merge_modifyOtherKeys(arg[form]); 1618 } 1619 } 1620 1621 return c; 1622 } 1623 1624 /* 1625 * Put a character directly onto the screen. It's not stored in a buffer. 1626 * Used while handling CTRL-K, CTRL-V, etc. in Insert mode. 1627 */ 1628 static int pc_status; 1629 #define PC_STATUS_UNSET 0 // pc_bytes was not set 1630 #define PC_STATUS_RIGHT 1 // right halve of double-wide char 1631 #define PC_STATUS_LEFT 2 // left halve of double-wide char 1632 #define PC_STATUS_SET 3 // pc_bytes was filled 1633 static char_u pc_bytes[MB_MAXBYTES + 1]; // saved bytes 1634 static int pc_attr; 1635 static int pc_row; 1636 static int pc_col; 1637 1638 void 1639 edit_putchar(int c, int highlight) 1640 { 1641 int attr; 1642 1643 if (ScreenLines != NULL) 1644 { 1645 update_topline(); // just in case w_topline isn't valid 1646 validate_cursor(); 1647 if (highlight) 1648 attr = HL_ATTR(HLF_8); 1649 else 1650 attr = 0; 1651 pc_row = W_WINROW(curwin) + curwin->w_wrow; 1652 pc_col = curwin->w_wincol; 1653 pc_status = PC_STATUS_UNSET; 1654 #ifdef FEAT_RIGHTLEFT 1655 if (curwin->w_p_rl) 1656 { 1657 pc_col += curwin->w_width - 1 - curwin->w_wcol; 1658 if (has_mbyte) 1659 { 1660 int fix_col = mb_fix_col(pc_col, pc_row); 1661 1662 if (fix_col != pc_col) 1663 { 1664 screen_putchar(' ', pc_row, fix_col, attr); 1665 --curwin->w_wcol; 1666 pc_status = PC_STATUS_RIGHT; 1667 } 1668 } 1669 } 1670 else 1671 #endif 1672 { 1673 pc_col += curwin->w_wcol; 1674 if (mb_lefthalve(pc_row, pc_col)) 1675 pc_status = PC_STATUS_LEFT; 1676 } 1677 1678 // save the character to be able to put it back 1679 if (pc_status == PC_STATUS_UNSET) 1680 { 1681 screen_getbytes(pc_row, pc_col, pc_bytes, &pc_attr); 1682 pc_status = PC_STATUS_SET; 1683 } 1684 screen_putchar(c, pc_row, pc_col, attr); 1685 } 1686 } 1687 1688 #if defined(FEAT_JOB_CHANNEL) || defined(PROTO) 1689 /* 1690 * Return the effective prompt for the current buffer. 1691 */ 1692 char_u * 1693 prompt_text(void) 1694 { 1695 if (curbuf->b_prompt_text == NULL) 1696 return (char_u *)"% "; 1697 return curbuf->b_prompt_text; 1698 } 1699 1700 /* 1701 * Prepare for prompt mode: Make sure the last line has the prompt text. 1702 * Move the cursor to this line. 1703 */ 1704 static void 1705 init_prompt(int cmdchar_todo) 1706 { 1707 char_u *prompt = prompt_text(); 1708 char_u *text; 1709 1710 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; 1711 text = ml_get_curline(); 1712 if (STRNCMP(text, prompt, STRLEN(prompt)) != 0) 1713 { 1714 // prompt is missing, insert it or append a line with it 1715 if (*text == NUL) 1716 ml_replace(curbuf->b_ml.ml_line_count, prompt, TRUE); 1717 else 1718 ml_append(curbuf->b_ml.ml_line_count, prompt, 0, FALSE); 1719 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; 1720 coladvance((colnr_T)MAXCOL); 1721 changed_bytes(curbuf->b_ml.ml_line_count, 0); 1722 } 1723 1724 // Insert always starts after the prompt, allow editing text after it. 1725 if (Insstart_orig.lnum != curwin->w_cursor.lnum 1726 || Insstart_orig.col != (int)STRLEN(prompt)) 1727 { 1728 Insstart.lnum = curwin->w_cursor.lnum; 1729 Insstart.col = (int)STRLEN(prompt); 1730 Insstart_orig = Insstart; 1731 Insstart_textlen = Insstart.col; 1732 Insstart_blank_vcol = MAXCOL; 1733 arrow_used = FALSE; 1734 } 1735 1736 if (cmdchar_todo == 'A') 1737 coladvance((colnr_T)MAXCOL); 1738 if (cmdchar_todo == 'I' || curwin->w_cursor.col <= (int)STRLEN(prompt)) 1739 curwin->w_cursor.col = (int)STRLEN(prompt); 1740 // Make sure the cursor is in a valid position. 1741 check_cursor(); 1742 } 1743 1744 /* 1745 * Return TRUE if the cursor is in the editable position of the prompt line. 1746 */ 1747 int 1748 prompt_curpos_editable() 1749 { 1750 return curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count 1751 && curwin->w_cursor.col >= (int)STRLEN(prompt_text()); 1752 } 1753 #endif 1754 1755 /* 1756 * Undo the previous edit_putchar(). 1757 */ 1758 void 1759 edit_unputchar(void) 1760 { 1761 if (pc_status != PC_STATUS_UNSET && pc_row >= msg_scrolled) 1762 { 1763 if (pc_status == PC_STATUS_RIGHT) 1764 ++curwin->w_wcol; 1765 if (pc_status == PC_STATUS_RIGHT || pc_status == PC_STATUS_LEFT) 1766 redrawWinline(curwin, curwin->w_cursor.lnum); 1767 else 1768 screen_puts(pc_bytes, pc_row - msg_scrolled, pc_col, pc_attr); 1769 } 1770 } 1771 1772 /* 1773 * Called when p_dollar is set: display a '$' at the end of the changed text 1774 * Only works when cursor is in the line that changes. 1775 */ 1776 void 1777 display_dollar(colnr_T col) 1778 { 1779 colnr_T save_col; 1780 1781 if (!redrawing()) 1782 return; 1783 1784 cursor_off(); 1785 save_col = curwin->w_cursor.col; 1786 curwin->w_cursor.col = col; 1787 if (has_mbyte) 1788 { 1789 char_u *p; 1790 1791 // If on the last byte of a multi-byte move to the first byte. 1792 p = ml_get_curline(); 1793 curwin->w_cursor.col -= (*mb_head_off)(p, p + col); 1794 } 1795 curs_columns(FALSE); // recompute w_wrow and w_wcol 1796 if (curwin->w_wcol < curwin->w_width) 1797 { 1798 edit_putchar('$', FALSE); 1799 dollar_vcol = curwin->w_virtcol; 1800 } 1801 curwin->w_cursor.col = save_col; 1802 } 1803 1804 /* 1805 * Call this function before moving the cursor from the normal insert position 1806 * in insert mode. 1807 */ 1808 void 1809 undisplay_dollar(void) 1810 { 1811 if (dollar_vcol >= 0) 1812 { 1813 dollar_vcol = -1; 1814 redrawWinline(curwin, curwin->w_cursor.lnum); 1815 } 1816 } 1817 1818 /* 1819 * Truncate the space at the end of a line. This is to be used only in an 1820 * insert mode. It handles fixing the replace stack for REPLACE and VREPLACE 1821 * modes. 1822 */ 1823 void 1824 truncate_spaces(char_u *line) 1825 { 1826 int i; 1827 1828 // find start of trailing white space 1829 for (i = (int)STRLEN(line) - 1; i >= 0 && VIM_ISWHITE(line[i]); i--) 1830 { 1831 if (State & REPLACE_FLAG) 1832 replace_join(0); // remove a NUL from the replace stack 1833 } 1834 line[i + 1] = NUL; 1835 } 1836 1837 /* 1838 * Backspace the cursor until the given column. Handles REPLACE and VREPLACE 1839 * modes correctly. May also be used when not in insert mode at all. 1840 * Will attempt not to go before "col" even when there is a composing 1841 * character. 1842 */ 1843 void 1844 backspace_until_column(int col) 1845 { 1846 while ((int)curwin->w_cursor.col > col) 1847 { 1848 curwin->w_cursor.col--; 1849 if (State & REPLACE_FLAG) 1850 replace_do_bs(col); 1851 else if (!del_char_after_col(col)) 1852 break; 1853 } 1854 } 1855 1856 /* 1857 * Like del_char(), but make sure not to go before column "limit_col". 1858 * Only matters when there are composing characters. 1859 * Return TRUE when something was deleted. 1860 */ 1861 static int 1862 del_char_after_col(int limit_col UNUSED) 1863 { 1864 if (enc_utf8 && limit_col >= 0) 1865 { 1866 colnr_T ecol = curwin->w_cursor.col + 1; 1867 1868 // Make sure the cursor is at the start of a character, but 1869 // skip forward again when going too far back because of a 1870 // composing character. 1871 mb_adjust_cursor(); 1872 while (curwin->w_cursor.col < (colnr_T)limit_col) 1873 { 1874 int l = utf_ptr2len(ml_get_cursor()); 1875 1876 if (l == 0) // end of line 1877 break; 1878 curwin->w_cursor.col += l; 1879 } 1880 if (*ml_get_cursor() == NUL || curwin->w_cursor.col == ecol) 1881 return FALSE; 1882 del_bytes((long)((int)ecol - curwin->w_cursor.col), FALSE, TRUE); 1883 } 1884 else 1885 (void)del_char(FALSE); 1886 return TRUE; 1887 } 1888 1889 /* 1890 * Next character is interpreted literally. 1891 * A one, two or three digit decimal number is interpreted as its byte value. 1892 * If one or two digits are entered, the next character is given to vungetc(). 1893 * For Unicode a character > 255 may be returned. 1894 */ 1895 int 1896 get_literal(void) 1897 { 1898 int cc; 1899 int nc; 1900 int i; 1901 int hex = FALSE; 1902 int octal = FALSE; 1903 int unicode = 0; 1904 1905 if (got_int) 1906 return Ctrl_C; 1907 1908 #ifdef FEAT_GUI 1909 /* 1910 * In GUI there is no point inserting the internal code for a special key. 1911 * It is more useful to insert the string "<KEY>" instead. This would 1912 * probably be useful in a text window too, but it would not be 1913 * vi-compatible (maybe there should be an option for it?) -- webb 1914 */ 1915 if (gui.in_use) 1916 ++allow_keys; 1917 #endif 1918 #ifdef USE_ON_FLY_SCROLL 1919 dont_scroll = TRUE; // disallow scrolling here 1920 #endif 1921 ++no_mapping; // don't map the next key hits 1922 cc = 0; 1923 i = 0; 1924 for (;;) 1925 { 1926 nc = plain_vgetc(); 1927 #ifdef FEAT_CMDL_INFO 1928 if (!(State & CMDLINE) && MB_BYTE2LEN_CHECK(nc) == 1) 1929 add_to_showcmd(nc); 1930 #endif 1931 if (nc == 'x' || nc == 'X') 1932 hex = TRUE; 1933 else if (nc == 'o' || nc == 'O') 1934 octal = TRUE; 1935 else if (nc == 'u' || nc == 'U') 1936 unicode = nc; 1937 else 1938 { 1939 if (hex || unicode != 0) 1940 { 1941 if (!vim_isxdigit(nc)) 1942 break; 1943 cc = cc * 16 + hex2nr(nc); 1944 } 1945 else if (octal) 1946 { 1947 if (nc < '0' || nc > '7') 1948 break; 1949 cc = cc * 8 + nc - '0'; 1950 } 1951 else 1952 { 1953 if (!VIM_ISDIGIT(nc)) 1954 break; 1955 cc = cc * 10 + nc - '0'; 1956 } 1957 1958 ++i; 1959 } 1960 1961 if (cc > 255 && unicode == 0) 1962 cc = 255; // limit range to 0-255 1963 nc = 0; 1964 1965 if (hex) // hex: up to two chars 1966 { 1967 if (i >= 2) 1968 break; 1969 } 1970 else if (unicode) // Unicode: up to four or eight chars 1971 { 1972 if ((unicode == 'u' && i >= 4) || (unicode == 'U' && i >= 8)) 1973 break; 1974 } 1975 else if (i >= 3) // decimal or octal: up to three chars 1976 break; 1977 } 1978 if (i == 0) // no number entered 1979 { 1980 if (nc == K_ZERO) // NUL is stored as NL 1981 { 1982 cc = '\n'; 1983 nc = 0; 1984 } 1985 else 1986 { 1987 cc = nc; 1988 nc = 0; 1989 } 1990 } 1991 1992 if (cc == 0) // NUL is stored as NL 1993 cc = '\n'; 1994 if (enc_dbcs && (cc & 0xff) == 0) 1995 cc = '?'; // don't accept an illegal DBCS char, the NUL in the 1996 // second byte will cause trouble! 1997 1998 --no_mapping; 1999 #ifdef FEAT_GUI 2000 if (gui.in_use) 2001 --allow_keys; 2002 #endif 2003 if (nc) 2004 vungetc(nc); 2005 got_int = FALSE; // CTRL-C typed after CTRL-V is not an interrupt 2006 return cc; 2007 } 2008 2009 /* 2010 * Insert character, taking care of special keys and mod_mask 2011 */ 2012 static void 2013 insert_special( 2014 int c, 2015 int allow_modmask, 2016 int ctrlv) // c was typed after CTRL-V 2017 { 2018 char_u *p; 2019 int len; 2020 2021 /* 2022 * Special function key, translate into "<Key>". Up to the last '>' is 2023 * inserted with ins_str(), so as not to replace characters in replace 2024 * mode. 2025 * Only use mod_mask for special keys, to avoid things like <S-Space>, 2026 * unless 'allow_modmask' is TRUE. 2027 */ 2028 #ifdef MACOS_X 2029 // Command-key never produces a normal key 2030 if (mod_mask & MOD_MASK_CMD) 2031 allow_modmask = TRUE; 2032 #endif 2033 if (IS_SPECIAL(c) || (mod_mask && allow_modmask)) 2034 { 2035 p = get_special_key_name(c, mod_mask); 2036 len = (int)STRLEN(p); 2037 c = p[len - 1]; 2038 if (len > 2) 2039 { 2040 if (stop_arrow() == FAIL) 2041 return; 2042 p[len - 1] = NUL; 2043 ins_str(p); 2044 AppendToRedobuffLit(p, -1); 2045 ctrlv = FALSE; 2046 } 2047 } 2048 if (stop_arrow() == OK) 2049 insertchar(c, ctrlv ? INSCHAR_CTRLV : 0, -1); 2050 } 2051 2052 /* 2053 * Special characters in this context are those that need processing other 2054 * than the simple insertion that can be performed here. This includes ESC 2055 * which terminates the insert, and CR/NL which need special processing to 2056 * open up a new line. This routine tries to optimize insertions performed by 2057 * the "redo", "undo" or "put" commands, so it needs to know when it should 2058 * stop and defer processing to the "normal" mechanism. 2059 * '0' and '^' are special, because they can be followed by CTRL-D. 2060 */ 2061 #ifdef EBCDIC 2062 # define ISSPECIAL(c) ((c) < ' ' || (c) == '0' || (c) == '^') 2063 #else 2064 # define ISSPECIAL(c) ((c) < ' ' || (c) >= DEL || (c) == '0' || (c) == '^') 2065 #endif 2066 2067 #define WHITECHAR(cc) (VIM_ISWHITE(cc) && (!enc_utf8 || !utf_iscomposing(utf_ptr2char(ml_get_cursor() + 1)))) 2068 2069 /* 2070 * "flags": INSCHAR_FORMAT - force formatting 2071 * INSCHAR_CTRLV - char typed just after CTRL-V 2072 * INSCHAR_NO_FEX - don't use 'formatexpr' 2073 * 2074 * NOTE: passes the flags value straight through to internal_format() which, 2075 * beside INSCHAR_FORMAT (above), is also looking for these: 2076 * INSCHAR_DO_COM - format comments 2077 * INSCHAR_COM_LIST - format comments with num list or 2nd line indent 2078 */ 2079 void 2080 insertchar( 2081 int c, // character to insert or NUL 2082 int flags, // INSCHAR_FORMAT, etc. 2083 int second_indent) // indent for second line if >= 0 2084 { 2085 int textwidth; 2086 char_u *p; 2087 int fo_ins_blank; 2088 int force_format = flags & INSCHAR_FORMAT; 2089 2090 textwidth = comp_textwidth(force_format); 2091 fo_ins_blank = has_format_option(FO_INS_BLANK); 2092 2093 /* 2094 * Try to break the line in two or more pieces when: 2095 * - Always do this if we have been called to do formatting only. 2096 * - Always do this when 'formatoptions' has the 'a' flag and the line 2097 * ends in white space. 2098 * - Otherwise: 2099 * - Don't do this if inserting a blank 2100 * - Don't do this if an existing character is being replaced, unless 2101 * we're in VREPLACE mode. 2102 * - Do this if the cursor is not on the line where insert started 2103 * or - 'formatoptions' doesn't have 'l' or the line was not too long 2104 * before the insert. 2105 * - 'formatoptions' doesn't have 'b' or a blank was inserted at or 2106 * before 'textwidth' 2107 */ 2108 if (textwidth > 0 2109 && (force_format 2110 || (!VIM_ISWHITE(c) 2111 && !((State & REPLACE_FLAG) 2112 && !(State & VREPLACE_FLAG) 2113 && *ml_get_cursor() != NUL) 2114 && (curwin->w_cursor.lnum != Insstart.lnum 2115 || ((!has_format_option(FO_INS_LONG) 2116 || Insstart_textlen <= (colnr_T)textwidth) 2117 && (!fo_ins_blank 2118 || Insstart_blank_vcol <= (colnr_T)textwidth 2119 )))))) 2120 { 2121 // Format with 'formatexpr' when it's set. Use internal formatting 2122 // when 'formatexpr' isn't set or it returns non-zero. 2123 #if defined(FEAT_EVAL) 2124 int do_internal = TRUE; 2125 colnr_T virtcol = get_nolist_virtcol() 2126 + char2cells(c != NUL ? c : gchar_cursor()); 2127 2128 if (*curbuf->b_p_fex != NUL && (flags & INSCHAR_NO_FEX) == 0 2129 && (force_format || virtcol > (colnr_T)textwidth)) 2130 { 2131 do_internal = (fex_format(curwin->w_cursor.lnum, 1L, c) != 0); 2132 // It may be required to save for undo again, e.g. when setline() 2133 // was called. 2134 ins_need_undo = TRUE; 2135 } 2136 if (do_internal) 2137 #endif 2138 internal_format(textwidth, second_indent, flags, c == NUL, c); 2139 } 2140 2141 if (c == NUL) // only formatting was wanted 2142 return; 2143 2144 // Check whether this character should end a comment. 2145 if (did_ai && (int)c == end_comment_pending) 2146 { 2147 char_u *line; 2148 char_u lead_end[COM_MAX_LEN]; // end-comment string 2149 int middle_len, end_len; 2150 int i; 2151 2152 /* 2153 * Need to remove existing (middle) comment leader and insert end 2154 * comment leader. First, check what comment leader we can find. 2155 */ 2156 i = get_leader_len(line = ml_get_curline(), &p, FALSE, TRUE); 2157 if (i > 0 && vim_strchr(p, COM_MIDDLE) != NULL) // Just checking 2158 { 2159 // Skip middle-comment string 2160 while (*p && p[-1] != ':') // find end of middle flags 2161 ++p; 2162 middle_len = copy_option_part(&p, lead_end, COM_MAX_LEN, ","); 2163 // Don't count trailing white space for middle_len 2164 while (middle_len > 0 && VIM_ISWHITE(lead_end[middle_len - 1])) 2165 --middle_len; 2166 2167 // Find the end-comment string 2168 while (*p && p[-1] != ':') // find end of end flags 2169 ++p; 2170 end_len = copy_option_part(&p, lead_end, COM_MAX_LEN, ","); 2171 2172 // Skip white space before the cursor 2173 i = curwin->w_cursor.col; 2174 while (--i >= 0 && VIM_ISWHITE(line[i])) 2175 ; 2176 i++; 2177 2178 // Skip to before the middle leader 2179 i -= middle_len; 2180 2181 // Check some expected things before we go on 2182 if (i >= 0 && lead_end[end_len - 1] == end_comment_pending) 2183 { 2184 // Backspace over all the stuff we want to replace 2185 backspace_until_column(i); 2186 2187 // Insert the end-comment string, except for the last 2188 // character, which will get inserted as normal later. 2189 ins_bytes_len(lead_end, end_len - 1); 2190 } 2191 } 2192 } 2193 end_comment_pending = NUL; 2194 2195 did_ai = FALSE; 2196 #ifdef FEAT_SMARTINDENT 2197 did_si = FALSE; 2198 can_si = FALSE; 2199 can_si_back = FALSE; 2200 #endif 2201 2202 /* 2203 * If there's any pending input, grab up to INPUT_BUFLEN at once. 2204 * This speeds up normal text input considerably. 2205 * Don't do this when 'cindent' or 'indentexpr' is set, because we might 2206 * need to re-indent at a ':', or any other character (but not what 2207 * 'paste' is set).. 2208 * Don't do this when there an InsertCharPre autocommand is defined, 2209 * because we need to fire the event for every character. 2210 * Do the check for InsertCharPre before the call to vpeekc() because the 2211 * InsertCharPre autocommand could change the input buffer. 2212 */ 2213 #ifdef USE_ON_FLY_SCROLL 2214 dont_scroll = FALSE; // allow scrolling here 2215 #endif 2216 2217 if ( !ISSPECIAL(c) 2218 && (!has_mbyte || (*mb_char2len)(c) == 1) 2219 && !has_insertcharpre() 2220 && vpeekc() != NUL 2221 && !(State & REPLACE_FLAG) 2222 #ifdef FEAT_CINDENT 2223 && !cindent_on() 2224 #endif 2225 #ifdef FEAT_RIGHTLEFT 2226 && !p_ri 2227 #endif 2228 ) 2229 { 2230 #define INPUT_BUFLEN 100 2231 char_u buf[INPUT_BUFLEN + 1]; 2232 int i; 2233 colnr_T virtcol = 0; 2234 2235 buf[0] = c; 2236 i = 1; 2237 if (textwidth > 0) 2238 virtcol = get_nolist_virtcol(); 2239 /* 2240 * Stop the string when: 2241 * - no more chars available 2242 * - finding a special character (command key) 2243 * - buffer is full 2244 * - running into the 'textwidth' boundary 2245 * - need to check for abbreviation: A non-word char after a word-char 2246 */ 2247 while ( (c = vpeekc()) != NUL 2248 && !ISSPECIAL(c) 2249 && (!has_mbyte || MB_BYTE2LEN_CHECK(c) == 1) 2250 && i < INPUT_BUFLEN 2251 && (textwidth == 0 2252 || (virtcol += byte2cells(buf[i - 1])) < (colnr_T)textwidth) 2253 && !(!no_abbr && !vim_iswordc(c) && vim_iswordc(buf[i - 1]))) 2254 { 2255 #ifdef FEAT_RIGHTLEFT 2256 c = vgetc(); 2257 if (p_hkmap && KeyTyped) 2258 c = hkmap(c); // Hebrew mode mapping 2259 buf[i++] = c; 2260 #else 2261 buf[i++] = vgetc(); 2262 #endif 2263 } 2264 2265 #ifdef FEAT_DIGRAPHS 2266 do_digraph(-1); // clear digraphs 2267 do_digraph(buf[i-1]); // may be the start of a digraph 2268 #endif 2269 buf[i] = NUL; 2270 ins_str(buf); 2271 if (flags & INSCHAR_CTRLV) 2272 { 2273 redo_literal(*buf); 2274 i = 1; 2275 } 2276 else 2277 i = 0; 2278 if (buf[i] != NUL) 2279 AppendToRedobuffLit(buf + i, -1); 2280 } 2281 else 2282 { 2283 int cc; 2284 2285 if (has_mbyte && (cc = (*mb_char2len)(c)) > 1) 2286 { 2287 char_u buf[MB_MAXBYTES + 1]; 2288 2289 (*mb_char2bytes)(c, buf); 2290 buf[cc] = NUL; 2291 ins_char_bytes(buf, cc); 2292 AppendCharToRedobuff(c); 2293 } 2294 else 2295 { 2296 ins_char(c); 2297 if (flags & INSCHAR_CTRLV) 2298 redo_literal(c); 2299 else 2300 AppendCharToRedobuff(c); 2301 } 2302 } 2303 } 2304 2305 /* 2306 * Format text at the current insert position. 2307 * 2308 * If the INSCHAR_COM_LIST flag is present, then the value of second_indent 2309 * will be the comment leader length sent to open_line(). 2310 */ 2311 static void 2312 internal_format( 2313 int textwidth, 2314 int second_indent, 2315 int flags, 2316 int format_only, 2317 int c) // character to be inserted (can be NUL) 2318 { 2319 int cc; 2320 int save_char = NUL; 2321 int haveto_redraw = FALSE; 2322 int fo_ins_blank = has_format_option(FO_INS_BLANK); 2323 int fo_multibyte = has_format_option(FO_MBYTE_BREAK); 2324 int fo_white_par = has_format_option(FO_WHITE_PAR); 2325 int first_line = TRUE; 2326 colnr_T leader_len; 2327 int no_leader = FALSE; 2328 int do_comments = (flags & INSCHAR_DO_COM); 2329 #ifdef FEAT_LINEBREAK 2330 int has_lbr = curwin->w_p_lbr; 2331 2332 // make sure win_lbr_chartabsize() counts correctly 2333 curwin->w_p_lbr = FALSE; 2334 #endif 2335 2336 /* 2337 * When 'ai' is off we don't want a space under the cursor to be 2338 * deleted. Replace it with an 'x' temporarily. 2339 */ 2340 if (!curbuf->b_p_ai && !(State & VREPLACE_FLAG)) 2341 { 2342 cc = gchar_cursor(); 2343 if (VIM_ISWHITE(cc)) 2344 { 2345 save_char = cc; 2346 pchar_cursor('x'); 2347 } 2348 } 2349 2350 /* 2351 * Repeat breaking lines, until the current line is not too long. 2352 */ 2353 while (!got_int) 2354 { 2355 int startcol; // Cursor column at entry 2356 int wantcol; // column at textwidth border 2357 int foundcol; // column for start of spaces 2358 int end_foundcol = 0; // column for start of word 2359 colnr_T len; 2360 colnr_T virtcol; 2361 int orig_col = 0; 2362 char_u *saved_text = NULL; 2363 colnr_T col; 2364 colnr_T end_col; 2365 int wcc; // counter for whitespace chars 2366 2367 virtcol = get_nolist_virtcol() 2368 + char2cells(c != NUL ? c : gchar_cursor()); 2369 if (virtcol <= (colnr_T)textwidth) 2370 break; 2371 2372 if (no_leader) 2373 do_comments = FALSE; 2374 else if (!(flags & INSCHAR_FORMAT) 2375 && has_format_option(FO_WRAP_COMS)) 2376 do_comments = TRUE; 2377 2378 // Don't break until after the comment leader 2379 if (do_comments) 2380 leader_len = get_leader_len(ml_get_curline(), NULL, FALSE, TRUE); 2381 else 2382 leader_len = 0; 2383 2384 // If the line doesn't start with a comment leader, then don't 2385 // start one in a following broken line. Avoids that a %word 2386 // moved to the start of the next line causes all following lines 2387 // to start with %. 2388 if (leader_len == 0) 2389 no_leader = TRUE; 2390 if (!(flags & INSCHAR_FORMAT) 2391 && leader_len == 0 2392 && !has_format_option(FO_WRAP)) 2393 2394 break; 2395 if ((startcol = curwin->w_cursor.col) == 0) 2396 break; 2397 2398 // find column of textwidth border 2399 coladvance((colnr_T)textwidth); 2400 wantcol = curwin->w_cursor.col; 2401 2402 curwin->w_cursor.col = startcol; 2403 foundcol = 0; 2404 2405 /* 2406 * Find position to break at. 2407 * Stop at first entered white when 'formatoptions' has 'v' 2408 */ 2409 while ((!fo_ins_blank && !has_format_option(FO_INS_VI)) 2410 || (flags & INSCHAR_FORMAT) 2411 || curwin->w_cursor.lnum != Insstart.lnum 2412 || curwin->w_cursor.col >= Insstart.col) 2413 { 2414 if (curwin->w_cursor.col == startcol && c != NUL) 2415 cc = c; 2416 else 2417 cc = gchar_cursor(); 2418 if (WHITECHAR(cc)) 2419 { 2420 // remember position of blank just before text 2421 end_col = curwin->w_cursor.col; 2422 2423 // find start of sequence of blanks 2424 wcc = 0; 2425 while (curwin->w_cursor.col > 0 && WHITECHAR(cc)) 2426 { 2427 dec_cursor(); 2428 cc = gchar_cursor(); 2429 2430 // Increment count of how many whitespace chars in this 2431 // group; we only need to know if it's more than one. 2432 if (wcc < 2) 2433 wcc++; 2434 } 2435 if (curwin->w_cursor.col == 0 && WHITECHAR(cc)) 2436 break; // only spaces in front of text 2437 2438 // Don't break after a period when 'formatoptions' has 'p' and 2439 // there are less than two spaces. 2440 if (has_format_option(FO_PERIOD_ABBR) && cc == '.' && wcc < 2) 2441 continue; 2442 2443 // Don't break until after the comment leader 2444 if (curwin->w_cursor.col < leader_len) 2445 break; 2446 if (has_format_option(FO_ONE_LETTER)) 2447 { 2448 // do not break after one-letter words 2449 if (curwin->w_cursor.col == 0) 2450 break; // one-letter word at begin 2451 // do not break "#a b" when 'tw' is 2 2452 if (curwin->w_cursor.col <= leader_len) 2453 break; 2454 col = curwin->w_cursor.col; 2455 dec_cursor(); 2456 cc = gchar_cursor(); 2457 2458 if (WHITECHAR(cc)) 2459 continue; // one-letter, continue 2460 curwin->w_cursor.col = col; 2461 } 2462 2463 inc_cursor(); 2464 2465 end_foundcol = end_col + 1; 2466 foundcol = curwin->w_cursor.col; 2467 if (curwin->w_cursor.col <= (colnr_T)wantcol) 2468 break; 2469 } 2470 else if (cc >= 0x100 && fo_multibyte) 2471 { 2472 // Break after or before a multi-byte character. 2473 if (curwin->w_cursor.col != startcol) 2474 { 2475 // Don't break until after the comment leader 2476 if (curwin->w_cursor.col < leader_len) 2477 break; 2478 col = curwin->w_cursor.col; 2479 inc_cursor(); 2480 // Don't change end_foundcol if already set. 2481 if (foundcol != curwin->w_cursor.col) 2482 { 2483 foundcol = curwin->w_cursor.col; 2484 end_foundcol = foundcol; 2485 if (curwin->w_cursor.col <= (colnr_T)wantcol) 2486 break; 2487 } 2488 curwin->w_cursor.col = col; 2489 } 2490 2491 if (curwin->w_cursor.col == 0) 2492 break; 2493 2494 col = curwin->w_cursor.col; 2495 2496 dec_cursor(); 2497 cc = gchar_cursor(); 2498 2499 if (WHITECHAR(cc)) 2500 continue; // break with space 2501 // Don't break until after the comment leader 2502 if (curwin->w_cursor.col < leader_len) 2503 break; 2504 2505 curwin->w_cursor.col = col; 2506 2507 foundcol = curwin->w_cursor.col; 2508 end_foundcol = foundcol; 2509 if (curwin->w_cursor.col <= (colnr_T)wantcol) 2510 break; 2511 } 2512 if (curwin->w_cursor.col == 0) 2513 break; 2514 dec_cursor(); 2515 } 2516 2517 if (foundcol == 0) // no spaces, cannot break line 2518 { 2519 curwin->w_cursor.col = startcol; 2520 break; 2521 } 2522 2523 // Going to break the line, remove any "$" now. 2524 undisplay_dollar(); 2525 2526 /* 2527 * Offset between cursor position and line break is used by replace 2528 * stack functions. VREPLACE does not use this, and backspaces 2529 * over the text instead. 2530 */ 2531 if (State & VREPLACE_FLAG) 2532 orig_col = startcol; // Will start backspacing from here 2533 else 2534 replace_offset = startcol - end_foundcol; 2535 2536 /* 2537 * adjust startcol for spaces that will be deleted and 2538 * characters that will remain on top line 2539 */ 2540 curwin->w_cursor.col = foundcol; 2541 while ((cc = gchar_cursor(), WHITECHAR(cc)) 2542 && (!fo_white_par || curwin->w_cursor.col < startcol)) 2543 inc_cursor(); 2544 startcol -= curwin->w_cursor.col; 2545 if (startcol < 0) 2546 startcol = 0; 2547 2548 if (State & VREPLACE_FLAG) 2549 { 2550 /* 2551 * In VREPLACE mode, we will backspace over the text to be 2552 * wrapped, so save a copy now to put on the next line. 2553 */ 2554 saved_text = vim_strsave(ml_get_cursor()); 2555 curwin->w_cursor.col = orig_col; 2556 if (saved_text == NULL) 2557 break; // Can't do it, out of memory 2558 saved_text[startcol] = NUL; 2559 2560 // Backspace over characters that will move to the next line 2561 if (!fo_white_par) 2562 backspace_until_column(foundcol); 2563 } 2564 else 2565 { 2566 // put cursor after pos. to break line 2567 if (!fo_white_par) 2568 curwin->w_cursor.col = foundcol; 2569 } 2570 2571 /* 2572 * Split the line just before the margin. 2573 * Only insert/delete lines, but don't really redraw the window. 2574 */ 2575 open_line(FORWARD, OPENLINE_DELSPACES + OPENLINE_MARKFIX 2576 + (fo_white_par ? OPENLINE_KEEPTRAIL : 0) 2577 + (do_comments ? OPENLINE_DO_COM : 0) 2578 + ((flags & INSCHAR_COM_LIST) ? OPENLINE_COM_LIST : 0) 2579 , ((flags & INSCHAR_COM_LIST) ? second_indent : old_indent)); 2580 if (!(flags & INSCHAR_COM_LIST)) 2581 old_indent = 0; 2582 2583 replace_offset = 0; 2584 if (first_line) 2585 { 2586 if (!(flags & INSCHAR_COM_LIST)) 2587 { 2588 /* 2589 * This section is for auto-wrap of numeric lists. When not 2590 * in insert mode (i.e. format_lines()), the INSCHAR_COM_LIST 2591 * flag will be set and open_line() will handle it (as seen 2592 * above). The code here (and in get_number_indent()) will 2593 * recognize comments if needed... 2594 */ 2595 if (second_indent < 0 && has_format_option(FO_Q_NUMBER)) 2596 second_indent = 2597 get_number_indent(curwin->w_cursor.lnum - 1); 2598 if (second_indent >= 0) 2599 { 2600 if (State & VREPLACE_FLAG) 2601 change_indent(INDENT_SET, second_indent, 2602 FALSE, NUL, TRUE); 2603 else 2604 if (leader_len > 0 && second_indent - leader_len > 0) 2605 { 2606 int i; 2607 int padding = second_indent - leader_len; 2608 2609 // We started at the first_line of a numbered list 2610 // that has a comment. the open_line() function has 2611 // inserted the proper comment leader and positioned 2612 // the cursor at the end of the split line. Now we 2613 // add the additional whitespace needed after the 2614 // comment leader for the numbered list. 2615 for (i = 0; i < padding; i++) 2616 ins_str((char_u *)" "); 2617 } 2618 else 2619 { 2620 (void)set_indent(second_indent, SIN_CHANGED); 2621 } 2622 } 2623 } 2624 first_line = FALSE; 2625 } 2626 2627 if (State & VREPLACE_FLAG) 2628 { 2629 /* 2630 * In VREPLACE mode we have backspaced over the text to be 2631 * moved, now we re-insert it into the new line. 2632 */ 2633 ins_bytes(saved_text); 2634 vim_free(saved_text); 2635 } 2636 else 2637 { 2638 /* 2639 * Check if cursor is not past the NUL off the line, cindent 2640 * may have added or removed indent. 2641 */ 2642 curwin->w_cursor.col += startcol; 2643 len = (colnr_T)STRLEN(ml_get_curline()); 2644 if (curwin->w_cursor.col > len) 2645 curwin->w_cursor.col = len; 2646 } 2647 2648 haveto_redraw = TRUE; 2649 #ifdef FEAT_CINDENT 2650 can_cindent = TRUE; 2651 #endif 2652 // moved the cursor, don't autoindent or cindent now 2653 did_ai = FALSE; 2654 #ifdef FEAT_SMARTINDENT 2655 did_si = FALSE; 2656 can_si = FALSE; 2657 can_si_back = FALSE; 2658 #endif 2659 line_breakcheck(); 2660 } 2661 2662 if (save_char != NUL) // put back space after cursor 2663 pchar_cursor(save_char); 2664 2665 #ifdef FEAT_LINEBREAK 2666 curwin->w_p_lbr = has_lbr; 2667 #endif 2668 if (!format_only && haveto_redraw) 2669 { 2670 update_topline(); 2671 redraw_curbuf_later(VALID); 2672 } 2673 } 2674 2675 /* 2676 * Called after inserting or deleting text: When 'formatoptions' includes the 2677 * 'a' flag format from the current line until the end of the paragraph. 2678 * Keep the cursor at the same position relative to the text. 2679 * The caller must have saved the cursor line for undo, following ones will be 2680 * saved here. 2681 */ 2682 void 2683 auto_format( 2684 int trailblank, // when TRUE also format with trailing blank 2685 int prev_line) // may start in previous line 2686 { 2687 pos_T pos; 2688 colnr_T len; 2689 char_u *old; 2690 char_u *new, *pnew; 2691 int wasatend; 2692 int cc; 2693 2694 if (!has_format_option(FO_AUTO)) 2695 return; 2696 2697 pos = curwin->w_cursor; 2698 old = ml_get_curline(); 2699 2700 // may remove added space 2701 check_auto_format(FALSE); 2702 2703 // Don't format in Insert mode when the cursor is on a trailing blank, the 2704 // user might insert normal text next. Also skip formatting when "1" is 2705 // in 'formatoptions' and there is a single character before the cursor. 2706 // Otherwise the line would be broken and when typing another non-white 2707 // next they are not joined back together. 2708 wasatend = (pos.col == (colnr_T)STRLEN(old)); 2709 if (*old != NUL && !trailblank && wasatend) 2710 { 2711 dec_cursor(); 2712 cc = gchar_cursor(); 2713 if (!WHITECHAR(cc) && curwin->w_cursor.col > 0 2714 && has_format_option(FO_ONE_LETTER)) 2715 dec_cursor(); 2716 cc = gchar_cursor(); 2717 if (WHITECHAR(cc)) 2718 { 2719 curwin->w_cursor = pos; 2720 return; 2721 } 2722 curwin->w_cursor = pos; 2723 } 2724 2725 // With the 'c' flag in 'formatoptions' and 't' missing: only format 2726 // comments. 2727 if (has_format_option(FO_WRAP_COMS) && !has_format_option(FO_WRAP) 2728 && get_leader_len(old, NULL, FALSE, TRUE) == 0) 2729 return; 2730 2731 /* 2732 * May start formatting in a previous line, so that after "x" a word is 2733 * moved to the previous line if it fits there now. Only when this is not 2734 * the start of a paragraph. 2735 */ 2736 if (prev_line && !paragraph_start(curwin->w_cursor.lnum)) 2737 { 2738 --curwin->w_cursor.lnum; 2739 if (u_save_cursor() == FAIL) 2740 return; 2741 } 2742 2743 /* 2744 * Do the formatting and restore the cursor position. "saved_cursor" will 2745 * be adjusted for the text formatting. 2746 */ 2747 saved_cursor = pos; 2748 format_lines((linenr_T)-1, FALSE); 2749 curwin->w_cursor = saved_cursor; 2750 saved_cursor.lnum = 0; 2751 2752 if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) 2753 { 2754 // "cannot happen" 2755 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; 2756 coladvance((colnr_T)MAXCOL); 2757 } 2758 else 2759 check_cursor_col(); 2760 2761 // Insert mode: If the cursor is now after the end of the line while it 2762 // previously wasn't, the line was broken. Because of the rule above we 2763 // need to add a space when 'w' is in 'formatoptions' to keep a paragraph 2764 // formatted. 2765 if (!wasatend && has_format_option(FO_WHITE_PAR)) 2766 { 2767 new = ml_get_curline(); 2768 len = (colnr_T)STRLEN(new); 2769 if (curwin->w_cursor.col == len) 2770 { 2771 pnew = vim_strnsave(new, len + 2); 2772 pnew[len] = ' '; 2773 pnew[len + 1] = NUL; 2774 ml_replace(curwin->w_cursor.lnum, pnew, FALSE); 2775 // remove the space later 2776 did_add_space = TRUE; 2777 } 2778 else 2779 // may remove added space 2780 check_auto_format(FALSE); 2781 } 2782 2783 check_cursor(); 2784 } 2785 2786 /* 2787 * When an extra space was added to continue a paragraph for auto-formatting, 2788 * delete it now. The space must be under the cursor, just after the insert 2789 * position. 2790 */ 2791 static void 2792 check_auto_format( 2793 int end_insert) // TRUE when ending Insert mode 2794 { 2795 int c = ' '; 2796 int cc; 2797 2798 if (did_add_space) 2799 { 2800 cc = gchar_cursor(); 2801 if (!WHITECHAR(cc)) 2802 // Somehow the space was removed already. 2803 did_add_space = FALSE; 2804 else 2805 { 2806 if (!end_insert) 2807 { 2808 inc_cursor(); 2809 c = gchar_cursor(); 2810 dec_cursor(); 2811 } 2812 if (c != NUL) 2813 { 2814 // The space is no longer at the end of the line, delete it. 2815 del_char(FALSE); 2816 did_add_space = FALSE; 2817 } 2818 } 2819 } 2820 } 2821 2822 /* 2823 * Find out textwidth to be used for formatting: 2824 * if 'textwidth' option is set, use it 2825 * else if 'wrapmargin' option is set, use curwin->w_width - 'wrapmargin' 2826 * if invalid value, use 0. 2827 * Set default to window width (maximum 79) for "gq" operator. 2828 */ 2829 int 2830 comp_textwidth( 2831 int ff) // force formatting (for "gq" command) 2832 { 2833 int textwidth; 2834 2835 textwidth = curbuf->b_p_tw; 2836 if (textwidth == 0 && curbuf->b_p_wm) 2837 { 2838 // The width is the window width minus 'wrapmargin' minus all the 2839 // things that add to the margin. 2840 textwidth = curwin->w_width - curbuf->b_p_wm; 2841 #ifdef FEAT_CMDWIN 2842 if (cmdwin_type != 0) 2843 textwidth -= 1; 2844 #endif 2845 #ifdef FEAT_FOLDING 2846 textwidth -= curwin->w_p_fdc; 2847 #endif 2848 #ifdef FEAT_SIGNS 2849 if (signcolumn_on(curwin)) 2850 textwidth -= 1; 2851 #endif 2852 if (curwin->w_p_nu || curwin->w_p_rnu) 2853 textwidth -= 8; 2854 } 2855 if (textwidth < 0) 2856 textwidth = 0; 2857 if (ff && textwidth == 0) 2858 { 2859 textwidth = curwin->w_width - 1; 2860 if (textwidth > 79) 2861 textwidth = 79; 2862 } 2863 return textwidth; 2864 } 2865 2866 /* 2867 * Put a character in the redo buffer, for when just after a CTRL-V. 2868 */ 2869 static void 2870 redo_literal(int c) 2871 { 2872 char_u buf[10]; 2873 2874 // Only digits need special treatment. Translate them into a string of 2875 // three digits. 2876 if (VIM_ISDIGIT(c)) 2877 { 2878 vim_snprintf((char *)buf, sizeof(buf), "%03d", c); 2879 AppendToRedobuff(buf); 2880 } 2881 else 2882 AppendCharToRedobuff(c); 2883 } 2884 2885 /* 2886 * start_arrow() is called when an arrow key is used in insert mode. 2887 * For undo/redo it resembles hitting the <ESC> key. 2888 */ 2889 void 2890 start_arrow( 2891 pos_T *end_insert_pos) // can be NULL 2892 { 2893 start_arrow_common(end_insert_pos, TRUE); 2894 } 2895 2896 /* 2897 * Like start_arrow() but with end_change argument. 2898 * Will prepare for redo of CTRL-G U if "end_change" is FALSE. 2899 */ 2900 static void 2901 start_arrow_with_change( 2902 pos_T *end_insert_pos, // can be NULL 2903 int end_change) // end undoable change 2904 { 2905 start_arrow_common(end_insert_pos, end_change); 2906 if (!end_change) 2907 { 2908 AppendCharToRedobuff(Ctrl_G); 2909 AppendCharToRedobuff('U'); 2910 } 2911 } 2912 2913 static void 2914 start_arrow_common( 2915 pos_T *end_insert_pos, // can be NULL 2916 int end_change) // end undoable change 2917 { 2918 if (!arrow_used && end_change) // something has been inserted 2919 { 2920 AppendToRedobuff(ESC_STR); 2921 stop_insert(end_insert_pos, FALSE, FALSE); 2922 arrow_used = TRUE; // this means we stopped the current insert 2923 } 2924 #ifdef FEAT_SPELL 2925 check_spell_redraw(); 2926 #endif 2927 } 2928 2929 #ifdef FEAT_SPELL 2930 /* 2931 * If we skipped highlighting word at cursor, do it now. 2932 * It may be skipped again, thus reset spell_redraw_lnum first. 2933 */ 2934 static void 2935 check_spell_redraw(void) 2936 { 2937 if (spell_redraw_lnum != 0) 2938 { 2939 linenr_T lnum = spell_redraw_lnum; 2940 2941 spell_redraw_lnum = 0; 2942 redrawWinline(curwin, lnum); 2943 } 2944 } 2945 2946 #endif 2947 2948 /* 2949 * stop_arrow() is called before a change is made in insert mode. 2950 * If an arrow key has been used, start a new insertion. 2951 * Returns FAIL if undo is impossible, shouldn't insert then. 2952 */ 2953 int 2954 stop_arrow(void) 2955 { 2956 if (arrow_used) 2957 { 2958 Insstart = curwin->w_cursor; // new insertion starts here 2959 if (Insstart.col > Insstart_orig.col && !ins_need_undo) 2960 // Don't update the original insert position when moved to the 2961 // right, except when nothing was inserted yet. 2962 update_Insstart_orig = FALSE; 2963 Insstart_textlen = (colnr_T)linetabsize(ml_get_curline()); 2964 2965 if (u_save_cursor() == OK) 2966 { 2967 arrow_used = FALSE; 2968 ins_need_undo = FALSE; 2969 } 2970 2971 ai_col = 0; 2972 if (State & VREPLACE_FLAG) 2973 { 2974 orig_line_count = curbuf->b_ml.ml_line_count; 2975 vr_lines_changed = 1; 2976 } 2977 ResetRedobuff(); 2978 AppendToRedobuff((char_u *)"1i"); // pretend we start an insertion 2979 new_insert_skip = 2; 2980 } 2981 else if (ins_need_undo) 2982 { 2983 if (u_save_cursor() == OK) 2984 ins_need_undo = FALSE; 2985 } 2986 2987 #ifdef FEAT_FOLDING 2988 // Always open fold at the cursor line when inserting something. 2989 foldOpenCursor(); 2990 #endif 2991 2992 return (arrow_used || ins_need_undo ? FAIL : OK); 2993 } 2994 2995 /* 2996 * Do a few things to stop inserting. 2997 * "end_insert_pos" is where insert ended. It is NULL when we already jumped 2998 * to another window/buffer. 2999 */ 3000 static void 3001 stop_insert( 3002 pos_T *end_insert_pos, 3003 int esc, // called by ins_esc() 3004 int nomove) // <c-\><c-o>, don't move cursor 3005 { 3006 int cc; 3007 char_u *ptr; 3008 3009 stop_redo_ins(); 3010 replace_flush(); // abandon replace stack 3011 3012 /* 3013 * Save the inserted text for later redo with ^@ and CTRL-A. 3014 * Don't do it when "restart_edit" was set and nothing was inserted, 3015 * otherwise CTRL-O w and then <Left> will clear "last_insert". 3016 */ 3017 ptr = get_inserted(); 3018 if (did_restart_edit == 0 || (ptr != NULL 3019 && (int)STRLEN(ptr) > new_insert_skip)) 3020 { 3021 vim_free(last_insert); 3022 last_insert = ptr; 3023 last_insert_skip = new_insert_skip; 3024 } 3025 else 3026 vim_free(ptr); 3027 3028 if (!arrow_used && end_insert_pos != NULL) 3029 { 3030 // Auto-format now. It may seem strange to do this when stopping an 3031 // insertion (or moving the cursor), but it's required when appending 3032 // a line and having it end in a space. But only do it when something 3033 // was actually inserted, otherwise undo won't work. 3034 if (!ins_need_undo && has_format_option(FO_AUTO)) 3035 { 3036 pos_T tpos = curwin->w_cursor; 3037 3038 // When the cursor is at the end of the line after a space the 3039 // formatting will move it to the following word. Avoid that by 3040 // moving the cursor onto the space. 3041 cc = 'x'; 3042 if (curwin->w_cursor.col > 0 && gchar_cursor() == NUL) 3043 { 3044 dec_cursor(); 3045 cc = gchar_cursor(); 3046 if (!VIM_ISWHITE(cc)) 3047 curwin->w_cursor = tpos; 3048 } 3049 3050 auto_format(TRUE, FALSE); 3051 3052 if (VIM_ISWHITE(cc)) 3053 { 3054 if (gchar_cursor() != NUL) 3055 inc_cursor(); 3056 // If the cursor is still at the same character, also keep 3057 // the "coladd". 3058 if (gchar_cursor() == NUL 3059 && curwin->w_cursor.lnum == tpos.lnum 3060 && curwin->w_cursor.col == tpos.col) 3061 curwin->w_cursor.coladd = tpos.coladd; 3062 } 3063 } 3064 3065 // If a space was inserted for auto-formatting, remove it now. 3066 check_auto_format(TRUE); 3067 3068 // If we just did an auto-indent, remove the white space from the end 3069 // of the line, and put the cursor back. 3070 // Do this when ESC was used or moving the cursor up/down. 3071 // Check for the old position still being valid, just in case the text 3072 // got changed unexpectedly. 3073 if (!nomove && did_ai && (esc || (vim_strchr(p_cpo, CPO_INDENT) == NULL 3074 && curwin->w_cursor.lnum != end_insert_pos->lnum)) 3075 && end_insert_pos->lnum <= curbuf->b_ml.ml_line_count) 3076 { 3077 pos_T tpos = curwin->w_cursor; 3078 3079 curwin->w_cursor = *end_insert_pos; 3080 check_cursor_col(); // make sure it is not past the line 3081 for (;;) 3082 { 3083 if (gchar_cursor() == NUL && curwin->w_cursor.col > 0) 3084 --curwin->w_cursor.col; 3085 cc = gchar_cursor(); 3086 if (!VIM_ISWHITE(cc)) 3087 break; 3088 if (del_char(TRUE) == FAIL) 3089 break; // should not happen 3090 } 3091 if (curwin->w_cursor.lnum != tpos.lnum) 3092 curwin->w_cursor = tpos; 3093 else 3094 { 3095 // reset tpos, could have been invalidated in the loop above 3096 tpos = curwin->w_cursor; 3097 tpos.col++; 3098 if (cc != NUL && gchar_pos(&tpos) == NUL) 3099 ++curwin->w_cursor.col; // put cursor back on the NUL 3100 } 3101 3102 // <C-S-Right> may have started Visual mode, adjust the position for 3103 // deleted characters. 3104 if (VIsual_active && VIsual.lnum == curwin->w_cursor.lnum) 3105 { 3106 int len = (int)STRLEN(ml_get_curline()); 3107 3108 if (VIsual.col > len) 3109 { 3110 VIsual.col = len; 3111 VIsual.coladd = 0; 3112 } 3113 } 3114 } 3115 } 3116 did_ai = FALSE; 3117 #ifdef FEAT_SMARTINDENT 3118 did_si = FALSE; 3119 can_si = FALSE; 3120 can_si_back = FALSE; 3121 #endif 3122 3123 // Set '[ and '] to the inserted text. When end_insert_pos is NULL we are 3124 // now in a different buffer. 3125 if (end_insert_pos != NULL) 3126 { 3127 curbuf->b_op_start = Insstart; 3128 curbuf->b_op_start_orig = Insstart_orig; 3129 curbuf->b_op_end = *end_insert_pos; 3130 } 3131 } 3132 3133 /* 3134 * Set the last inserted text to a single character. 3135 * Used for the replace command. 3136 */ 3137 void 3138 set_last_insert(int c) 3139 { 3140 char_u *s; 3141 3142 vim_free(last_insert); 3143 last_insert = alloc(MB_MAXBYTES * 3 + 5); 3144 if (last_insert != NULL) 3145 { 3146 s = last_insert; 3147 // Use the CTRL-V only when entering a special char 3148 if (c < ' ' || c == DEL) 3149 *s++ = Ctrl_V; 3150 s = add_char2buf(c, s); 3151 *s++ = ESC; 3152 *s++ = NUL; 3153 last_insert_skip = 0; 3154 } 3155 } 3156 3157 #if defined(EXITFREE) || defined(PROTO) 3158 void 3159 free_last_insert(void) 3160 { 3161 VIM_CLEAR(last_insert); 3162 } 3163 #endif 3164 3165 /* 3166 * Add character "c" to buffer "s". Escape the special meaning of K_SPECIAL 3167 * and CSI. Handle multi-byte characters. 3168 * Returns a pointer to after the added bytes. 3169 */ 3170 char_u * 3171 add_char2buf(int c, char_u *s) 3172 { 3173 char_u temp[MB_MAXBYTES + 1]; 3174 int i; 3175 int len; 3176 3177 len = (*mb_char2bytes)(c, temp); 3178 for (i = 0; i < len; ++i) 3179 { 3180 c = temp[i]; 3181 // Need to escape K_SPECIAL and CSI like in the typeahead buffer. 3182 if (c == K_SPECIAL) 3183 { 3184 *s++ = K_SPECIAL; 3185 *s++ = KS_SPECIAL; 3186 *s++ = KE_FILLER; 3187 } 3188 #ifdef FEAT_GUI 3189 else if (c == CSI) 3190 { 3191 *s++ = CSI; 3192 *s++ = KS_EXTRA; 3193 *s++ = (int)KE_CSI; 3194 } 3195 #endif 3196 else 3197 *s++ = c; 3198 } 3199 return s; 3200 } 3201 3202 /* 3203 * move cursor to start of line 3204 * if flags & BL_WHITE move to first non-white 3205 * if flags & BL_SOL move to first non-white if startofline is set, 3206 * otherwise keep "curswant" column 3207 * if flags & BL_FIX don't leave the cursor on a NUL. 3208 */ 3209 void 3210 beginline(int flags) 3211 { 3212 if ((flags & BL_SOL) && !p_sol) 3213 coladvance(curwin->w_curswant); 3214 else 3215 { 3216 curwin->w_cursor.col = 0; 3217 curwin->w_cursor.coladd = 0; 3218 3219 if (flags & (BL_WHITE | BL_SOL)) 3220 { 3221 char_u *ptr; 3222 3223 for (ptr = ml_get_curline(); VIM_ISWHITE(*ptr) 3224 && !((flags & BL_FIX) && ptr[1] == NUL); ++ptr) 3225 ++curwin->w_cursor.col; 3226 } 3227 curwin->w_set_curswant = TRUE; 3228 } 3229 } 3230 3231 /* 3232 * oneright oneleft cursor_down cursor_up 3233 * 3234 * Move one char {right,left,down,up}. 3235 * Doesn't move onto the NUL past the end of the line, unless it is allowed. 3236 * Return OK when successful, FAIL when we hit a line of file boundary. 3237 */ 3238 3239 int 3240 oneright(void) 3241 { 3242 char_u *ptr; 3243 int l; 3244 3245 if (virtual_active()) 3246 { 3247 pos_T prevpos = curwin->w_cursor; 3248 3249 // Adjust for multi-wide char (excluding TAB) 3250 ptr = ml_get_cursor(); 3251 coladvance(getviscol() + ((*ptr != TAB 3252 && vim_isprintc((*mb_ptr2char)(ptr))) 3253 ? ptr2cells(ptr) : 1)); 3254 curwin->w_set_curswant = TRUE; 3255 // Return OK if the cursor moved, FAIL otherwise (at window edge). 3256 return (prevpos.col != curwin->w_cursor.col 3257 || prevpos.coladd != curwin->w_cursor.coladd) ? OK : FAIL; 3258 } 3259 3260 ptr = ml_get_cursor(); 3261 if (*ptr == NUL) 3262 return FAIL; // already at the very end 3263 3264 if (has_mbyte) 3265 l = (*mb_ptr2len)(ptr); 3266 else 3267 l = 1; 3268 3269 // move "l" bytes right, but don't end up on the NUL, unless 'virtualedit' 3270 // contains "onemore". 3271 if (ptr[l] == NUL && (ve_flags & VE_ONEMORE) == 0) 3272 return FAIL; 3273 curwin->w_cursor.col += l; 3274 3275 curwin->w_set_curswant = TRUE; 3276 return OK; 3277 } 3278 3279 int 3280 oneleft(void) 3281 { 3282 if (virtual_active()) 3283 { 3284 #ifdef FEAT_LINEBREAK 3285 int width; 3286 #endif 3287 int v = getviscol(); 3288 3289 if (v == 0) 3290 return FAIL; 3291 3292 #ifdef FEAT_LINEBREAK 3293 // We might get stuck on 'showbreak', skip over it. 3294 width = 1; 3295 for (;;) 3296 { 3297 coladvance(v - width); 3298 // getviscol() is slow, skip it when 'showbreak' is empty, 3299 // 'breakindent' is not set and there are no multi-byte 3300 // characters 3301 if ((*get_showbreak_value(curwin) == NUL && !curwin->w_p_bri 3302 && !has_mbyte) || getviscol() < v) 3303 break; 3304 ++width; 3305 } 3306 #else 3307 coladvance(v - 1); 3308 #endif 3309 3310 if (curwin->w_cursor.coladd == 1) 3311 { 3312 char_u *ptr; 3313 3314 // Adjust for multi-wide char (not a TAB) 3315 ptr = ml_get_cursor(); 3316 if (*ptr != TAB && vim_isprintc((*mb_ptr2char)(ptr)) 3317 && ptr2cells(ptr) > 1) 3318 curwin->w_cursor.coladd = 0; 3319 } 3320 3321 curwin->w_set_curswant = TRUE; 3322 return OK; 3323 } 3324 3325 if (curwin->w_cursor.col == 0) 3326 return FAIL; 3327 3328 curwin->w_set_curswant = TRUE; 3329 --curwin->w_cursor.col; 3330 3331 // if the character on the left of the current cursor is a multi-byte 3332 // character, move to its first byte 3333 if (has_mbyte) 3334 mb_adjust_cursor(); 3335 return OK; 3336 } 3337 3338 int 3339 cursor_up( 3340 long n, 3341 int upd_topline) // When TRUE: update topline 3342 { 3343 linenr_T lnum; 3344 3345 if (n > 0) 3346 { 3347 lnum = curwin->w_cursor.lnum; 3348 // This fails if the cursor is already in the first line or the count 3349 // is larger than the line number and '-' is in 'cpoptions' 3350 if (lnum <= 1 || (n >= lnum && vim_strchr(p_cpo, CPO_MINUS) != NULL)) 3351 return FAIL; 3352 if (n >= lnum) 3353 lnum = 1; 3354 else 3355 #ifdef FEAT_FOLDING 3356 if (hasAnyFolding(curwin)) 3357 { 3358 /* 3359 * Count each sequence of folded lines as one logical line. 3360 */ 3361 // go to the start of the current fold 3362 (void)hasFolding(lnum, &lnum, NULL); 3363 3364 while (n--) 3365 { 3366 // move up one line 3367 --lnum; 3368 if (lnum <= 1) 3369 break; 3370 // If we entered a fold, move to the beginning, unless in 3371 // Insert mode or when 'foldopen' contains "all": it will open 3372 // in a moment. 3373 if (n > 0 || !((State & INSERT) || (fdo_flags & FDO_ALL))) 3374 (void)hasFolding(lnum, &lnum, NULL); 3375 } 3376 if (lnum < 1) 3377 lnum = 1; 3378 } 3379 else 3380 #endif 3381 lnum -= n; 3382 curwin->w_cursor.lnum = lnum; 3383 } 3384 3385 // try to advance to the column we want to be at 3386 coladvance(curwin->w_curswant); 3387 3388 if (upd_topline) 3389 update_topline(); // make sure curwin->w_topline is valid 3390 3391 return OK; 3392 } 3393 3394 /* 3395 * Cursor down a number of logical lines. 3396 */ 3397 int 3398 cursor_down( 3399 long n, 3400 int upd_topline) // When TRUE: update topline 3401 { 3402 linenr_T lnum; 3403 3404 if (n > 0) 3405 { 3406 lnum = curwin->w_cursor.lnum; 3407 #ifdef FEAT_FOLDING 3408 // Move to last line of fold, will fail if it's the end-of-file. 3409 (void)hasFolding(lnum, NULL, &lnum); 3410 #endif 3411 // This fails if the cursor is already in the last line or would move 3412 // beyond the last line and '-' is in 'cpoptions' 3413 if (lnum >= curbuf->b_ml.ml_line_count 3414 || (lnum + n > curbuf->b_ml.ml_line_count 3415 && vim_strchr(p_cpo, CPO_MINUS) != NULL)) 3416 return FAIL; 3417 if (lnum + n >= curbuf->b_ml.ml_line_count) 3418 lnum = curbuf->b_ml.ml_line_count; 3419 else 3420 #ifdef FEAT_FOLDING 3421 if (hasAnyFolding(curwin)) 3422 { 3423 linenr_T last; 3424 3425 // count each sequence of folded lines as one logical line 3426 while (n--) 3427 { 3428 if (hasFolding(lnum, NULL, &last)) 3429 lnum = last + 1; 3430 else 3431 ++lnum; 3432 if (lnum >= curbuf->b_ml.ml_line_count) 3433 break; 3434 } 3435 if (lnum > curbuf->b_ml.ml_line_count) 3436 lnum = curbuf->b_ml.ml_line_count; 3437 } 3438 else 3439 #endif 3440 lnum += n; 3441 curwin->w_cursor.lnum = lnum; 3442 } 3443 3444 // try to advance to the column we want to be at 3445 coladvance(curwin->w_curswant); 3446 3447 if (upd_topline) 3448 update_topline(); // make sure curwin->w_topline is valid 3449 3450 return OK; 3451 } 3452 3453 /* 3454 * Stuff the last inserted text in the read buffer. 3455 * Last_insert actually is a copy of the redo buffer, so we 3456 * first have to remove the command. 3457 */ 3458 int 3459 stuff_inserted( 3460 int c, // Command character to be inserted 3461 long count, // Repeat this many times 3462 int no_esc) // Don't add an ESC at the end 3463 { 3464 char_u *esc_ptr; 3465 char_u *ptr; 3466 char_u *last_ptr; 3467 char_u last = NUL; 3468 3469 ptr = get_last_insert(); 3470 if (ptr == NULL) 3471 { 3472 emsg(_(e_noinstext)); 3473 return FAIL; 3474 } 3475 3476 // may want to stuff the command character, to start Insert mode 3477 if (c != NUL) 3478 stuffcharReadbuff(c); 3479 if ((esc_ptr = (char_u *)vim_strrchr(ptr, ESC)) != NULL) 3480 *esc_ptr = NUL; // remove the ESC 3481 3482 // when the last char is either "0" or "^" it will be quoted if no ESC 3483 // comes after it OR if it will inserted more than once and "ptr" 3484 // starts with ^D. -- Acevedo 3485 last_ptr = (esc_ptr ? esc_ptr : ptr + STRLEN(ptr)) - 1; 3486 if (last_ptr >= ptr && (*last_ptr == '0' || *last_ptr == '^') 3487 && (no_esc || (*ptr == Ctrl_D && count > 1))) 3488 { 3489 last = *last_ptr; 3490 *last_ptr = NUL; 3491 } 3492 3493 do 3494 { 3495 stuffReadbuff(ptr); 3496 // a trailing "0" is inserted as "<C-V>048", "^" as "<C-V>^" 3497 if (last) 3498 stuffReadbuff((char_u *)(last == '0' 3499 ? IF_EB("\026\060\064\070", CTRL_V_STR "xf0") 3500 : IF_EB("\026^", CTRL_V_STR "^"))); 3501 } 3502 while (--count > 0); 3503 3504 if (last) 3505 *last_ptr = last; 3506 3507 if (esc_ptr != NULL) 3508 *esc_ptr = ESC; // put the ESC back 3509 3510 // may want to stuff a trailing ESC, to get out of Insert mode 3511 if (!no_esc) 3512 stuffcharReadbuff(ESC); 3513 3514 return OK; 3515 } 3516 3517 char_u * 3518 get_last_insert(void) 3519 { 3520 if (last_insert == NULL) 3521 return NULL; 3522 return last_insert + last_insert_skip; 3523 } 3524 3525 /* 3526 * Get last inserted string, and remove trailing <Esc>. 3527 * Returns pointer to allocated memory (must be freed) or NULL. 3528 */ 3529 char_u * 3530 get_last_insert_save(void) 3531 { 3532 char_u *s; 3533 int len; 3534 3535 if (last_insert == NULL) 3536 return NULL; 3537 s = vim_strsave(last_insert + last_insert_skip); 3538 if (s != NULL) 3539 { 3540 len = (int)STRLEN(s); 3541 if (len > 0 && s[len - 1] == ESC) // remove trailing ESC 3542 s[len - 1] = NUL; 3543 } 3544 return s; 3545 } 3546 3547 /* 3548 * Check the word in front of the cursor for an abbreviation. 3549 * Called when the non-id character "c" has been entered. 3550 * When an abbreviation is recognized it is removed from the text and 3551 * the replacement string is inserted in typebuf.tb_buf[], followed by "c". 3552 */ 3553 static int 3554 echeck_abbr(int c) 3555 { 3556 // Don't check for abbreviation in paste mode, when disabled and just 3557 // after moving around with cursor keys. 3558 if (p_paste || no_abbr || arrow_used) 3559 return FALSE; 3560 3561 return check_abbr(c, ml_get_curline(), curwin->w_cursor.col, 3562 curwin->w_cursor.lnum == Insstart.lnum ? Insstart.col : 0); 3563 } 3564 3565 /* 3566 * replace-stack functions 3567 * 3568 * When replacing characters, the replaced characters are remembered for each 3569 * new character. This is used to re-insert the old text when backspacing. 3570 * 3571 * There is a NUL headed list of characters for each character that is 3572 * currently in the file after the insertion point. When BS is used, one NUL 3573 * headed list is put back for the deleted character. 3574 * 3575 * For a newline, there are two NUL headed lists. One contains the characters 3576 * that the NL replaced. The extra one stores the characters after the cursor 3577 * that were deleted (always white space). 3578 * 3579 * Replace_offset is normally 0, in which case replace_push will add a new 3580 * character at the end of the stack. If replace_offset is not 0, that many 3581 * characters will be left on the stack above the newly inserted character. 3582 */ 3583 3584 static char_u *replace_stack = NULL; 3585 static long replace_stack_nr = 0; // next entry in replace stack 3586 static long replace_stack_len = 0; // max. number of entries 3587 3588 void 3589 replace_push( 3590 int c) // character that is replaced (NUL is none) 3591 { 3592 char_u *p; 3593 3594 if (replace_stack_nr < replace_offset) // nothing to do 3595 return; 3596 if (replace_stack_len <= replace_stack_nr) 3597 { 3598 replace_stack_len += 50; 3599 p = ALLOC_MULT(char_u, replace_stack_len); 3600 if (p == NULL) // out of memory 3601 { 3602 replace_stack_len -= 50; 3603 return; 3604 } 3605 if (replace_stack != NULL) 3606 { 3607 mch_memmove(p, replace_stack, 3608 (size_t)(replace_stack_nr * sizeof(char_u))); 3609 vim_free(replace_stack); 3610 } 3611 replace_stack = p; 3612 } 3613 p = replace_stack + replace_stack_nr - replace_offset; 3614 if (replace_offset) 3615 mch_memmove(p + 1, p, (size_t)(replace_offset * sizeof(char_u))); 3616 *p = c; 3617 ++replace_stack_nr; 3618 } 3619 3620 /* 3621 * Push a character onto the replace stack. Handles a multi-byte character in 3622 * reverse byte order, so that the first byte is popped off first. 3623 * Return the number of bytes done (includes composing characters). 3624 */ 3625 int 3626 replace_push_mb(char_u *p) 3627 { 3628 int l = (*mb_ptr2len)(p); 3629 int j; 3630 3631 for (j = l - 1; j >= 0; --j) 3632 replace_push(p[j]); 3633 return l; 3634 } 3635 3636 /* 3637 * Pop one item from the replace stack. 3638 * return -1 if stack empty 3639 * return replaced character or NUL otherwise 3640 */ 3641 static int 3642 replace_pop(void) 3643 { 3644 if (replace_stack_nr == 0) 3645 return -1; 3646 return (int)replace_stack[--replace_stack_nr]; 3647 } 3648 3649 /* 3650 * Join the top two items on the replace stack. This removes to "off"'th NUL 3651 * encountered. 3652 */ 3653 void 3654 replace_join( 3655 int off) // offset for which NUL to remove 3656 { 3657 int i; 3658 3659 for (i = replace_stack_nr; --i >= 0; ) 3660 if (replace_stack[i] == NUL && off-- <= 0) 3661 { 3662 --replace_stack_nr; 3663 mch_memmove(replace_stack + i, replace_stack + i + 1, 3664 (size_t)(replace_stack_nr - i)); 3665 return; 3666 } 3667 } 3668 3669 /* 3670 * Pop bytes from the replace stack until a NUL is found, and insert them 3671 * before the cursor. Can only be used in REPLACE or VREPLACE mode. 3672 */ 3673 static void 3674 replace_pop_ins(void) 3675 { 3676 int cc; 3677 int oldState = State; 3678 3679 State = NORMAL; // don't want REPLACE here 3680 while ((cc = replace_pop()) > 0) 3681 { 3682 mb_replace_pop_ins(cc); 3683 dec_cursor(); 3684 } 3685 State = oldState; 3686 } 3687 3688 /* 3689 * Insert bytes popped from the replace stack. "cc" is the first byte. If it 3690 * indicates a multi-byte char, pop the other bytes too. 3691 */ 3692 static void 3693 mb_replace_pop_ins(int cc) 3694 { 3695 int n; 3696 char_u buf[MB_MAXBYTES + 1]; 3697 int i; 3698 int c; 3699 3700 if (has_mbyte && (n = MB_BYTE2LEN(cc)) > 1) 3701 { 3702 buf[0] = cc; 3703 for (i = 1; i < n; ++i) 3704 buf[i] = replace_pop(); 3705 ins_bytes_len(buf, n); 3706 } 3707 else 3708 ins_char(cc); 3709 3710 if (enc_utf8) 3711 // Handle composing chars. 3712 for (;;) 3713 { 3714 c = replace_pop(); 3715 if (c == -1) // stack empty 3716 break; 3717 if ((n = MB_BYTE2LEN(c)) == 1) 3718 { 3719 // Not a multi-byte char, put it back. 3720 replace_push(c); 3721 break; 3722 } 3723 else 3724 { 3725 buf[0] = c; 3726 for (i = 1; i < n; ++i) 3727 buf[i] = replace_pop(); 3728 if (utf_iscomposing(utf_ptr2char(buf))) 3729 ins_bytes_len(buf, n); 3730 else 3731 { 3732 // Not a composing char, put it back. 3733 for (i = n - 1; i >= 0; --i) 3734 replace_push(buf[i]); 3735 break; 3736 } 3737 } 3738 } 3739 } 3740 3741 /* 3742 * make the replace stack empty 3743 * (called when exiting replace mode) 3744 */ 3745 static void 3746 replace_flush(void) 3747 { 3748 VIM_CLEAR(replace_stack); 3749 replace_stack_len = 0; 3750 replace_stack_nr = 0; 3751 } 3752 3753 /* 3754 * Handle doing a BS for one character. 3755 * cc < 0: replace stack empty, just move cursor 3756 * cc == 0: character was inserted, delete it 3757 * cc > 0: character was replaced, put cc (first byte of original char) back 3758 * and check for more characters to be put back 3759 * When "limit_col" is >= 0, don't delete before this column. Matters when 3760 * using composing characters, use del_char_after_col() instead of del_char(). 3761 */ 3762 static void 3763 replace_do_bs(int limit_col) 3764 { 3765 int cc; 3766 int orig_len = 0; 3767 int ins_len; 3768 int orig_vcols = 0; 3769 colnr_T start_vcol; 3770 char_u *p; 3771 int i; 3772 int vcol; 3773 3774 cc = replace_pop(); 3775 if (cc > 0) 3776 { 3777 #ifdef FEAT_PROP_POPUP 3778 size_t len_before = 0; // init to shut up GCC 3779 3780 if (curbuf->b_has_textprop) 3781 { 3782 // Do not adjust text properties for individual delete and insert 3783 // operations, do it afterwards on the resulting text. 3784 len_before = STRLEN(ml_get_curline()); 3785 ++text_prop_frozen; 3786 } 3787 #endif 3788 if (State & VREPLACE_FLAG) 3789 { 3790 // Get the number of screen cells used by the character we are 3791 // going to delete. 3792 getvcol(curwin, &curwin->w_cursor, NULL, &start_vcol, NULL); 3793 orig_vcols = chartabsize(ml_get_cursor(), start_vcol); 3794 } 3795 if (has_mbyte) 3796 { 3797 (void)del_char_after_col(limit_col); 3798 if (State & VREPLACE_FLAG) 3799 orig_len = (int)STRLEN(ml_get_cursor()); 3800 replace_push(cc); 3801 } 3802 else 3803 { 3804 pchar_cursor(cc); 3805 if (State & VREPLACE_FLAG) 3806 orig_len = (int)STRLEN(ml_get_cursor()) - 1; 3807 } 3808 replace_pop_ins(); 3809 3810 if (State & VREPLACE_FLAG) 3811 { 3812 // Get the number of screen cells used by the inserted characters 3813 p = ml_get_cursor(); 3814 ins_len = (int)STRLEN(p) - orig_len; 3815 vcol = start_vcol; 3816 for (i = 0; i < ins_len; ++i) 3817 { 3818 vcol += chartabsize(p + i, vcol); 3819 i += (*mb_ptr2len)(p) - 1; 3820 } 3821 vcol -= start_vcol; 3822 3823 // Delete spaces that were inserted after the cursor to keep the 3824 // text aligned. 3825 curwin->w_cursor.col += ins_len; 3826 while (vcol > orig_vcols && gchar_cursor() == ' ') 3827 { 3828 del_char(FALSE); 3829 ++orig_vcols; 3830 } 3831 curwin->w_cursor.col -= ins_len; 3832 } 3833 3834 // mark the buffer as changed and prepare for displaying 3835 changed_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col); 3836 3837 #ifdef FEAT_PROP_POPUP 3838 if (curbuf->b_has_textprop) 3839 { 3840 size_t len_now = STRLEN(ml_get_curline()); 3841 3842 --text_prop_frozen; 3843 adjust_prop_columns(curwin->w_cursor.lnum, curwin->w_cursor.col, 3844 (int)(len_now - len_before), 0); 3845 } 3846 #endif 3847 } 3848 else if (cc == 0) 3849 (void)del_char_after_col(limit_col); 3850 } 3851 3852 #if defined(FEAT_RIGHTLEFT) || defined(PROTO) 3853 /* 3854 * Map Hebrew keyboard when in hkmap mode. 3855 */ 3856 int 3857 hkmap(int c) 3858 { 3859 if (p_hkmapp) // phonetic mapping, by Ilya Dogolazky 3860 { 3861 enum {hALEF=0, BET, GIMEL, DALET, HEI, VAV, ZAIN, HET, TET, IUD, 3862 KAFsofit, hKAF, LAMED, MEMsofit, MEM, NUNsofit, NUN, SAMEH, AIN, 3863 PEIsofit, PEI, ZADIsofit, ZADI, KOF, RESH, hSHIN, TAV}; 3864 static char_u map[26] = 3865 {(char_u)hALEF/*a*/, (char_u)BET /*b*/, (char_u)hKAF /*c*/, 3866 (char_u)DALET/*d*/, (char_u)-1 /*e*/, (char_u)PEIsofit/*f*/, 3867 (char_u)GIMEL/*g*/, (char_u)HEI /*h*/, (char_u)IUD /*i*/, 3868 (char_u)HET /*j*/, (char_u)KOF /*k*/, (char_u)LAMED /*l*/, 3869 (char_u)MEM /*m*/, (char_u)NUN /*n*/, (char_u)SAMEH /*o*/, 3870 (char_u)PEI /*p*/, (char_u)-1 /*q*/, (char_u)RESH /*r*/, 3871 (char_u)ZAIN /*s*/, (char_u)TAV /*t*/, (char_u)TET /*u*/, 3872 (char_u)VAV /*v*/, (char_u)hSHIN/*w*/, (char_u)-1 /*x*/, 3873 (char_u)AIN /*y*/, (char_u)ZADI /*z*/}; 3874 3875 if (c == 'N' || c == 'M' || c == 'P' || c == 'C' || c == 'Z') 3876 return (int)(map[CharOrd(c)] - 1 + p_aleph); 3877 // '-1'='sofit' 3878 else if (c == 'x') 3879 return 'X'; 3880 else if (c == 'q') 3881 return '\''; // {geresh}={'} 3882 else if (c == 246) 3883 return ' '; // \"o --> ' ' for a german keyboard 3884 else if (c == 228) 3885 return ' '; // \"a --> ' ' -- / -- 3886 else if (c == 252) 3887 return ' '; // \"u --> ' ' -- / -- 3888 #ifdef EBCDIC 3889 else if (islower(c)) 3890 #else 3891 // NOTE: islower() does not do the right thing for us on Linux so we 3892 // do this the same was as 5.7 and previous, so it works correctly on 3893 // all systems. Specifically, the e.g. Delete and Arrow keys are 3894 // munged and won't work if e.g. searching for Hebrew text. 3895 else if (c >= 'a' && c <= 'z') 3896 #endif 3897 return (int)(map[CharOrdLow(c)] + p_aleph); 3898 else 3899 return c; 3900 } 3901 else 3902 { 3903 switch (c) 3904 { 3905 case '`': return ';'; 3906 case '/': return '.'; 3907 case '\'': return ','; 3908 case 'q': return '/'; 3909 case 'w': return '\''; 3910 3911 // Hebrew letters - set offset from 'a' 3912 case ',': c = '{'; break; 3913 case '.': c = 'v'; break; 3914 case ';': c = 't'; break; 3915 default: { 3916 static char str[] = "zqbcxlsjphmkwonu ydafe rig"; 3917 3918 #ifdef EBCDIC 3919 // see note about islower() above 3920 if (!islower(c)) 3921 #else 3922 if (c < 'a' || c > 'z') 3923 #endif 3924 return c; 3925 c = str[CharOrdLow(c)]; 3926 break; 3927 } 3928 } 3929 3930 return (int)(CharOrdLow(c) + p_aleph); 3931 } 3932 } 3933 #endif 3934 3935 static void 3936 ins_reg(void) 3937 { 3938 int need_redraw = FALSE; 3939 int regname; 3940 int literally = 0; 3941 int vis_active = VIsual_active; 3942 3943 /* 3944 * If we are going to wait for a character, show a '"'. 3945 */ 3946 pc_status = PC_STATUS_UNSET; 3947 if (redrawing() && !char_avail()) 3948 { 3949 // may need to redraw when no more chars available now 3950 ins_redraw(FALSE); 3951 3952 edit_putchar('"', TRUE); 3953 #ifdef FEAT_CMDL_INFO 3954 add_to_showcmd_c(Ctrl_R); 3955 #endif 3956 } 3957 3958 #ifdef USE_ON_FLY_SCROLL 3959 dont_scroll = TRUE; // disallow scrolling here 3960 #endif 3961 3962 /* 3963 * Don't map the register name. This also prevents the mode message to be 3964 * deleted when ESC is hit. 3965 */ 3966 ++no_mapping; 3967 ++allow_keys; 3968 regname = plain_vgetc(); 3969 LANGMAP_ADJUST(regname, TRUE); 3970 if (regname == Ctrl_R || regname == Ctrl_O || regname == Ctrl_P) 3971 { 3972 // Get a third key for literal register insertion 3973 literally = regname; 3974 #ifdef FEAT_CMDL_INFO 3975 add_to_showcmd_c(literally); 3976 #endif 3977 regname = plain_vgetc(); 3978 LANGMAP_ADJUST(regname, TRUE); 3979 } 3980 --no_mapping; 3981 --allow_keys; 3982 3983 #ifdef FEAT_EVAL 3984 // Don't call u_sync() while typing the expression or giving an error 3985 // message for it. Only call it explicitly. 3986 ++no_u_sync; 3987 if (regname == '=') 3988 { 3989 pos_T curpos = curwin->w_cursor; 3990 # ifdef HAVE_INPUT_METHOD 3991 int im_on = im_get_status(); 3992 # endif 3993 // Sync undo when evaluating the expression calls setline() or 3994 // append(), so that it can be undone separately. 3995 u_sync_once = 2; 3996 3997 regname = get_expr_register(); 3998 3999 // Cursor may be moved back a column. 4000 curwin->w_cursor = curpos; 4001 check_cursor(); 4002 # ifdef HAVE_INPUT_METHOD 4003 // Restore the Input Method. 4004 if (im_on) 4005 im_set_active(TRUE); 4006 # endif 4007 } 4008 if (regname == NUL || !valid_yank_reg(regname, FALSE)) 4009 { 4010 vim_beep(BO_REG); 4011 need_redraw = TRUE; // remove the '"' 4012 } 4013 else 4014 { 4015 #endif 4016 if (literally == Ctrl_O || literally == Ctrl_P) 4017 { 4018 // Append the command to the redo buffer. 4019 AppendCharToRedobuff(Ctrl_R); 4020 AppendCharToRedobuff(literally); 4021 AppendCharToRedobuff(regname); 4022 4023 do_put(regname, BACKWARD, 1L, 4024 (literally == Ctrl_P ? PUT_FIXINDENT : 0) | PUT_CURSEND); 4025 } 4026 else if (insert_reg(regname, literally) == FAIL) 4027 { 4028 vim_beep(BO_REG); 4029 need_redraw = TRUE; // remove the '"' 4030 } 4031 else if (stop_insert_mode) 4032 // When the '=' register was used and a function was invoked that 4033 // did ":stopinsert" then stuff_empty() returns FALSE but we won't 4034 // insert anything, need to remove the '"' 4035 need_redraw = TRUE; 4036 4037 #ifdef FEAT_EVAL 4038 } 4039 --no_u_sync; 4040 if (u_sync_once == 1) 4041 ins_need_undo = TRUE; 4042 u_sync_once = 0; 4043 #endif 4044 #ifdef FEAT_CMDL_INFO 4045 clear_showcmd(); 4046 #endif 4047 4048 // If the inserted register is empty, we need to remove the '"' 4049 if (need_redraw || stuff_empty()) 4050 edit_unputchar(); 4051 4052 // Disallow starting Visual mode here, would get a weird mode. 4053 if (!vis_active && VIsual_active) 4054 end_visual_mode(); 4055 } 4056 4057 /* 4058 * CTRL-G commands in Insert mode. 4059 */ 4060 static void 4061 ins_ctrl_g(void) 4062 { 4063 int c; 4064 4065 // Right after CTRL-X the cursor will be after the ruler. 4066 setcursor(); 4067 4068 /* 4069 * Don't map the second key. This also prevents the mode message to be 4070 * deleted when ESC is hit. 4071 */ 4072 ++no_mapping; 4073 ++allow_keys; 4074 c = plain_vgetc(); 4075 --no_mapping; 4076 --allow_keys; 4077 switch (c) 4078 { 4079 // CTRL-G k and CTRL-G <Up>: cursor up to Insstart.col 4080 case K_UP: 4081 case Ctrl_K: 4082 case 'k': ins_up(TRUE); 4083 break; 4084 4085 // CTRL-G j and CTRL-G <Down>: cursor down to Insstart.col 4086 case K_DOWN: 4087 case Ctrl_J: 4088 case 'j': ins_down(TRUE); 4089 break; 4090 4091 // CTRL-G u: start new undoable edit 4092 case 'u': u_sync(TRUE); 4093 ins_need_undo = TRUE; 4094 4095 // Need to reset Insstart, esp. because a BS that joins 4096 // a line to the previous one must save for undo. 4097 update_Insstart_orig = FALSE; 4098 Insstart = curwin->w_cursor; 4099 break; 4100 4101 // CTRL-G U: do not break undo with the next char 4102 case 'U': 4103 // Allow one left/right cursor movement with the next char, 4104 // without breaking undo. 4105 dont_sync_undo = MAYBE; 4106 break; 4107 4108 // Unknown CTRL-G command, reserved for future expansion. 4109 default: vim_beep(BO_CTRLG); 4110 } 4111 } 4112 4113 /* 4114 * CTRL-^ in Insert mode. 4115 */ 4116 static void 4117 ins_ctrl_hat(void) 4118 { 4119 if (map_to_exists_mode((char_u *)"", LANGMAP, FALSE)) 4120 { 4121 // ":lmap" mappings exists, Toggle use of ":lmap" mappings. 4122 if (State & LANGMAP) 4123 { 4124 curbuf->b_p_iminsert = B_IMODE_NONE; 4125 State &= ~LANGMAP; 4126 } 4127 else 4128 { 4129 curbuf->b_p_iminsert = B_IMODE_LMAP; 4130 State |= LANGMAP; 4131 #ifdef HAVE_INPUT_METHOD 4132 im_set_active(FALSE); 4133 #endif 4134 } 4135 } 4136 #ifdef HAVE_INPUT_METHOD 4137 else 4138 { 4139 // There are no ":lmap" mappings, toggle IM 4140 if (im_get_status()) 4141 { 4142 curbuf->b_p_iminsert = B_IMODE_NONE; 4143 im_set_active(FALSE); 4144 } 4145 else 4146 { 4147 curbuf->b_p_iminsert = B_IMODE_IM; 4148 State &= ~LANGMAP; 4149 im_set_active(TRUE); 4150 } 4151 } 4152 #endif 4153 set_iminsert_global(); 4154 showmode(); 4155 #ifdef FEAT_GUI 4156 // may show different cursor shape or color 4157 if (gui.in_use) 4158 gui_update_cursor(TRUE, FALSE); 4159 #endif 4160 #if defined(FEAT_KEYMAP) 4161 // Show/unshow value of 'keymap' in status lines. 4162 status_redraw_curbuf(); 4163 #endif 4164 } 4165 4166 /* 4167 * Handle ESC in insert mode. 4168 * Returns TRUE when leaving insert mode, FALSE when going to repeat the 4169 * insert. 4170 */ 4171 static int 4172 ins_esc( 4173 long *count, 4174 int cmdchar, 4175 int nomove) // don't move cursor 4176 { 4177 int temp; 4178 static int disabled_redraw = FALSE; 4179 4180 #ifdef FEAT_SPELL 4181 check_spell_redraw(); 4182 #endif 4183 4184 temp = curwin->w_cursor.col; 4185 if (disabled_redraw) 4186 { 4187 --RedrawingDisabled; 4188 disabled_redraw = FALSE; 4189 } 4190 if (!arrow_used) 4191 { 4192 /* 4193 * Don't append the ESC for "r<CR>" and "grx". 4194 * When 'insertmode' is set only CTRL-L stops Insert mode. Needed for 4195 * when "count" is non-zero. 4196 */ 4197 if (cmdchar != 'r' && cmdchar != 'v') 4198 AppendToRedobuff(p_im ? (char_u *)"\014" : ESC_STR); 4199 4200 /* 4201 * Repeating insert may take a long time. Check for 4202 * interrupt now and then. 4203 */ 4204 if (*count > 0) 4205 { 4206 line_breakcheck(); 4207 if (got_int) 4208 *count = 0; 4209 } 4210 4211 if (--*count > 0) // repeat what was typed 4212 { 4213 // Vi repeats the insert without replacing characters. 4214 if (vim_strchr(p_cpo, CPO_REPLCNT) != NULL) 4215 State &= ~REPLACE_FLAG; 4216 4217 (void)start_redo_ins(); 4218 if (cmdchar == 'r' || cmdchar == 'v') 4219 stuffRedoReadbuff(ESC_STR); // no ESC in redo buffer 4220 ++RedrawingDisabled; 4221 disabled_redraw = TRUE; 4222 return FALSE; // repeat the insert 4223 } 4224 stop_insert(&curwin->w_cursor, TRUE, nomove); 4225 undisplay_dollar(); 4226 } 4227 4228 // When an autoindent was removed, curswant stays after the 4229 // indent 4230 if (restart_edit == NUL && (colnr_T)temp == curwin->w_cursor.col) 4231 curwin->w_set_curswant = TRUE; 4232 4233 // Remember the last Insert position in the '^ mark. 4234 if (!cmdmod.keepjumps) 4235 curbuf->b_last_insert = curwin->w_cursor; 4236 4237 /* 4238 * The cursor should end up on the last inserted character. 4239 * Don't do it for CTRL-O, unless past the end of the line. 4240 */ 4241 if (!nomove 4242 && (curwin->w_cursor.col != 0 4243 || curwin->w_cursor.coladd > 0) 4244 && (restart_edit == NUL 4245 || (gchar_cursor() == NUL && !VIsual_active)) 4246 #ifdef FEAT_RIGHTLEFT 4247 && !revins_on 4248 #endif 4249 ) 4250 { 4251 if (curwin->w_cursor.coladd > 0 || ve_flags == VE_ALL) 4252 { 4253 oneleft(); 4254 if (restart_edit != NUL) 4255 ++curwin->w_cursor.coladd; 4256 } 4257 else 4258 { 4259 --curwin->w_cursor.col; 4260 // Correct cursor for multi-byte character. 4261 if (has_mbyte) 4262 mb_adjust_cursor(); 4263 } 4264 } 4265 4266 #ifdef HAVE_INPUT_METHOD 4267 // Disable IM to allow typing English directly for Normal mode commands. 4268 // When ":lmap" is enabled don't change 'iminsert' (IM can be enabled as 4269 // well). 4270 if (!(State & LANGMAP)) 4271 im_save_status(&curbuf->b_p_iminsert); 4272 im_set_active(FALSE); 4273 #endif 4274 4275 State = NORMAL; 4276 // need to position cursor again (e.g. when on a TAB ) 4277 changed_cline_bef_curs(); 4278 4279 setmouse(); 4280 #ifdef CURSOR_SHAPE 4281 ui_cursor_shape(); // may show different cursor shape 4282 #endif 4283 if (!p_ek) 4284 { 4285 // Re-enable bracketed paste mode. 4286 out_str(T_BE); 4287 4288 // Re-enable modifyOtherKeys. 4289 out_str(T_CTI); 4290 } 4291 4292 // When recording or for CTRL-O, need to display the new mode. 4293 // Otherwise remove the mode message. 4294 if (reg_recording != 0 || restart_edit != NUL) 4295 showmode(); 4296 else if (p_smd && (got_int || !skip_showmode())) 4297 msg(""); 4298 4299 return TRUE; // exit Insert mode 4300 } 4301 4302 #ifdef FEAT_RIGHTLEFT 4303 /* 4304 * Toggle language: hkmap and revins_on. 4305 * Move to end of reverse inserted text. 4306 */ 4307 static void 4308 ins_ctrl_(void) 4309 { 4310 if (revins_on && revins_chars && revins_scol >= 0) 4311 { 4312 while (gchar_cursor() != NUL && revins_chars--) 4313 ++curwin->w_cursor.col; 4314 } 4315 p_ri = !p_ri; 4316 revins_on = (State == INSERT && p_ri); 4317 if (revins_on) 4318 { 4319 revins_scol = curwin->w_cursor.col; 4320 revins_legal++; 4321 revins_chars = 0; 4322 undisplay_dollar(); 4323 } 4324 else 4325 revins_scol = -1; 4326 p_hkmap = curwin->w_p_rl ^ p_ri; // be consistent! 4327 showmode(); 4328 } 4329 #endif 4330 4331 /* 4332 * If 'keymodel' contains "startsel", may start selection. 4333 * Returns TRUE when a CTRL-O and other keys stuffed. 4334 */ 4335 static int 4336 ins_start_select(int c) 4337 { 4338 if (km_startsel) 4339 switch (c) 4340 { 4341 case K_KHOME: 4342 case K_KEND: 4343 case K_PAGEUP: 4344 case K_KPAGEUP: 4345 case K_PAGEDOWN: 4346 case K_KPAGEDOWN: 4347 # ifdef MACOS_X 4348 case K_LEFT: 4349 case K_RIGHT: 4350 case K_UP: 4351 case K_DOWN: 4352 case K_END: 4353 case K_HOME: 4354 # endif 4355 if (!(mod_mask & MOD_MASK_SHIFT)) 4356 break; 4357 // FALLTHROUGH 4358 case K_S_LEFT: 4359 case K_S_RIGHT: 4360 case K_S_UP: 4361 case K_S_DOWN: 4362 case K_S_END: 4363 case K_S_HOME: 4364 // Start selection right away, the cursor can move with 4365 // CTRL-O when beyond the end of the line. 4366 start_selection(); 4367 4368 // Execute the key in (insert) Select mode. 4369 stuffcharReadbuff(Ctrl_O); 4370 if (mod_mask) 4371 { 4372 char_u buf[4]; 4373 4374 buf[0] = K_SPECIAL; 4375 buf[1] = KS_MODIFIER; 4376 buf[2] = mod_mask; 4377 buf[3] = NUL; 4378 stuffReadbuff(buf); 4379 } 4380 stuffcharReadbuff(c); 4381 return TRUE; 4382 } 4383 return FALSE; 4384 } 4385 4386 /* 4387 * <Insert> key in Insert mode: toggle insert/replace mode. 4388 */ 4389 static void 4390 ins_insert(int replaceState) 4391 { 4392 #ifdef FEAT_EVAL 4393 set_vim_var_string(VV_INSERTMODE, 4394 (char_u *)((State & REPLACE_FLAG) ? "i" 4395 : replaceState == VREPLACE ? "v" 4396 : "r"), 1); 4397 #endif 4398 ins_apply_autocmds(EVENT_INSERTCHANGE); 4399 if (State & REPLACE_FLAG) 4400 State = INSERT | (State & LANGMAP); 4401 else 4402 State = replaceState | (State & LANGMAP); 4403 AppendCharToRedobuff(K_INS); 4404 showmode(); 4405 #ifdef CURSOR_SHAPE 4406 ui_cursor_shape(); // may show different cursor shape 4407 #endif 4408 } 4409 4410 /* 4411 * Pressed CTRL-O in Insert mode. 4412 */ 4413 static void 4414 ins_ctrl_o(void) 4415 { 4416 if (State & VREPLACE_FLAG) 4417 restart_edit = 'V'; 4418 else 4419 if (State & REPLACE_FLAG) 4420 restart_edit = 'R'; 4421 else 4422 restart_edit = 'I'; 4423 if (virtual_active()) 4424 ins_at_eol = FALSE; // cursor always keeps its column 4425 else 4426 ins_at_eol = (gchar_cursor() == NUL); 4427 } 4428 4429 /* 4430 * If the cursor is on an indent, ^T/^D insert/delete one 4431 * shiftwidth. Otherwise ^T/^D behave like a "<<" or ">>". 4432 * Always round the indent to 'shiftwidth', this is compatible 4433 * with vi. But vi only supports ^T and ^D after an 4434 * autoindent, we support it everywhere. 4435 */ 4436 static void 4437 ins_shift(int c, int lastc) 4438 { 4439 if (stop_arrow() == FAIL) 4440 return; 4441 AppendCharToRedobuff(c); 4442 4443 /* 4444 * 0^D and ^^D: remove all indent. 4445 */ 4446 if (c == Ctrl_D && (lastc == '0' || lastc == '^') 4447 && curwin->w_cursor.col > 0) 4448 { 4449 --curwin->w_cursor.col; 4450 (void)del_char(FALSE); // delete the '^' or '0' 4451 // In Replace mode, restore the characters that '^' or '0' replaced. 4452 if (State & REPLACE_FLAG) 4453 replace_pop_ins(); 4454 if (lastc == '^') 4455 old_indent = get_indent(); // remember curr. indent 4456 change_indent(INDENT_SET, 0, TRUE, 0, TRUE); 4457 } 4458 else 4459 change_indent(c == Ctrl_D ? INDENT_DEC : INDENT_INC, 0, TRUE, 0, TRUE); 4460 4461 if (did_ai && *skipwhite(ml_get_curline()) != NUL) 4462 did_ai = FALSE; 4463 #ifdef FEAT_SMARTINDENT 4464 did_si = FALSE; 4465 can_si = FALSE; 4466 can_si_back = FALSE; 4467 #endif 4468 #ifdef FEAT_CINDENT 4469 can_cindent = FALSE; // no cindenting after ^D or ^T 4470 #endif 4471 } 4472 4473 static void 4474 ins_del(void) 4475 { 4476 int temp; 4477 4478 if (stop_arrow() == FAIL) 4479 return; 4480 if (gchar_cursor() == NUL) // delete newline 4481 { 4482 temp = curwin->w_cursor.col; 4483 if (!can_bs(BS_EOL) // only if "eol" included 4484 || do_join(2, FALSE, TRUE, FALSE, FALSE) == FAIL) 4485 vim_beep(BO_BS); 4486 else 4487 { 4488 curwin->w_cursor.col = temp; 4489 // Adjust orig_line_count in case more lines have been deleted than 4490 // have been added. That makes sure, that open_line() later 4491 // can access all buffer lines correctly 4492 if (State & VREPLACE_FLAG && 4493 orig_line_count > curbuf->b_ml.ml_line_count) 4494 orig_line_count = curbuf->b_ml.ml_line_count; 4495 } 4496 } 4497 else if (del_char(FALSE) == FAIL) // delete char under cursor 4498 vim_beep(BO_BS); 4499 did_ai = FALSE; 4500 #ifdef FEAT_SMARTINDENT 4501 did_si = FALSE; 4502 can_si = FALSE; 4503 can_si_back = FALSE; 4504 #endif 4505 AppendCharToRedobuff(K_DEL); 4506 } 4507 4508 /* 4509 * Delete one character for ins_bs(). 4510 */ 4511 static void 4512 ins_bs_one(colnr_T *vcolp) 4513 { 4514 dec_cursor(); 4515 getvcol(curwin, &curwin->w_cursor, vcolp, NULL, NULL); 4516 if (State & REPLACE_FLAG) 4517 { 4518 // Don't delete characters before the insert point when in 4519 // Replace mode 4520 if (curwin->w_cursor.lnum != Insstart.lnum 4521 || curwin->w_cursor.col >= Insstart.col) 4522 replace_do_bs(-1); 4523 } 4524 else 4525 (void)del_char(FALSE); 4526 } 4527 4528 /* 4529 * Handle Backspace, delete-word and delete-line in Insert mode. 4530 * Return TRUE when backspace was actually used. 4531 */ 4532 static int 4533 ins_bs( 4534 int c, 4535 int mode, 4536 int *inserted_space_p) 4537 { 4538 linenr_T lnum; 4539 int cc; 4540 int temp = 0; // init for GCC 4541 colnr_T save_col; 4542 colnr_T mincol; 4543 int did_backspace = FALSE; 4544 int in_indent; 4545 int oldState; 4546 int cpc[MAX_MCO]; // composing characters 4547 4548 /* 4549 * can't delete anything in an empty file 4550 * can't backup past first character in buffer 4551 * can't backup past starting point unless 'backspace' > 1 4552 * can backup to a previous line if 'backspace' == 0 4553 */ 4554 if ( BUFEMPTY() 4555 || ( 4556 #ifdef FEAT_RIGHTLEFT 4557 !revins_on && 4558 #endif 4559 ((curwin->w_cursor.lnum == 1 && curwin->w_cursor.col == 0) 4560 || (!can_bs(BS_START) 4561 && (arrow_used 4562 || (curwin->w_cursor.lnum == Insstart_orig.lnum 4563 && curwin->w_cursor.col <= Insstart_orig.col))) 4564 || (!can_bs(BS_INDENT) && !arrow_used && ai_col > 0 4565 && curwin->w_cursor.col <= ai_col) 4566 || (!can_bs(BS_EOL) && curwin->w_cursor.col == 0)))) 4567 { 4568 vim_beep(BO_BS); 4569 return FALSE; 4570 } 4571 4572 if (stop_arrow() == FAIL) 4573 return FALSE; 4574 in_indent = inindent(0); 4575 #ifdef FEAT_CINDENT 4576 if (in_indent) 4577 can_cindent = FALSE; 4578 #endif 4579 end_comment_pending = NUL; // After BS, don't auto-end comment 4580 #ifdef FEAT_RIGHTLEFT 4581 if (revins_on) // put cursor after last inserted char 4582 inc_cursor(); 4583 #endif 4584 4585 // Virtualedit: 4586 // BACKSPACE_CHAR eats a virtual space 4587 // BACKSPACE_WORD eats all coladd 4588 // BACKSPACE_LINE eats all coladd and keeps going 4589 if (curwin->w_cursor.coladd > 0) 4590 { 4591 if (mode == BACKSPACE_CHAR) 4592 { 4593 --curwin->w_cursor.coladd; 4594 return TRUE; 4595 } 4596 if (mode == BACKSPACE_WORD) 4597 { 4598 curwin->w_cursor.coladd = 0; 4599 return TRUE; 4600 } 4601 curwin->w_cursor.coladd = 0; 4602 } 4603 4604 /* 4605 * Delete newline! 4606 */ 4607 if (curwin->w_cursor.col == 0) 4608 { 4609 lnum = Insstart.lnum; 4610 if (curwin->w_cursor.lnum == lnum 4611 #ifdef FEAT_RIGHTLEFT 4612 || revins_on 4613 #endif 4614 ) 4615 { 4616 if (u_save((linenr_T)(curwin->w_cursor.lnum - 2), 4617 (linenr_T)(curwin->w_cursor.lnum + 1)) == FAIL) 4618 return FALSE; 4619 --Insstart.lnum; 4620 Insstart.col = (colnr_T)STRLEN(ml_get(Insstart.lnum)); 4621 } 4622 /* 4623 * In replace mode: 4624 * cc < 0: NL was inserted, delete it 4625 * cc >= 0: NL was replaced, put original characters back 4626 */ 4627 cc = -1; 4628 if (State & REPLACE_FLAG) 4629 cc = replace_pop(); // returns -1 if NL was inserted 4630 /* 4631 * In replace mode, in the line we started replacing, we only move the 4632 * cursor. 4633 */ 4634 if ((State & REPLACE_FLAG) && curwin->w_cursor.lnum <= lnum) 4635 { 4636 dec_cursor(); 4637 } 4638 else 4639 { 4640 if (!(State & VREPLACE_FLAG) 4641 || curwin->w_cursor.lnum > orig_line_count) 4642 { 4643 temp = gchar_cursor(); // remember current char 4644 --curwin->w_cursor.lnum; 4645 4646 // When "aw" is in 'formatoptions' we must delete the space at 4647 // the end of the line, otherwise the line will be broken 4648 // again when auto-formatting. 4649 if (has_format_option(FO_AUTO) 4650 && has_format_option(FO_WHITE_PAR)) 4651 { 4652 char_u *ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum, 4653 TRUE); 4654 int len; 4655 4656 len = (int)STRLEN(ptr); 4657 if (len > 0 && ptr[len - 1] == ' ') 4658 ptr[len - 1] = NUL; 4659 } 4660 4661 (void)do_join(2, FALSE, FALSE, FALSE, FALSE); 4662 if (temp == NUL && gchar_cursor() != NUL) 4663 inc_cursor(); 4664 } 4665 else 4666 dec_cursor(); 4667 4668 /* 4669 * In REPLACE mode we have to put back the text that was replaced 4670 * by the NL. On the replace stack is first a NUL-terminated 4671 * sequence of characters that were deleted and then the 4672 * characters that NL replaced. 4673 */ 4674 if (State & REPLACE_FLAG) 4675 { 4676 /* 4677 * Do the next ins_char() in NORMAL state, to 4678 * prevent ins_char() from replacing characters and 4679 * avoiding showmatch(). 4680 */ 4681 oldState = State; 4682 State = NORMAL; 4683 /* 4684 * restore characters (blanks) deleted after cursor 4685 */ 4686 while (cc > 0) 4687 { 4688 save_col = curwin->w_cursor.col; 4689 mb_replace_pop_ins(cc); 4690 curwin->w_cursor.col = save_col; 4691 cc = replace_pop(); 4692 } 4693 // restore the characters that NL replaced 4694 replace_pop_ins(); 4695 State = oldState; 4696 } 4697 } 4698 did_ai = FALSE; 4699 } 4700 else 4701 { 4702 /* 4703 * Delete character(s) before the cursor. 4704 */ 4705 #ifdef FEAT_RIGHTLEFT 4706 if (revins_on) // put cursor on last inserted char 4707 dec_cursor(); 4708 #endif 4709 mincol = 0; 4710 // keep indent 4711 if (mode == BACKSPACE_LINE 4712 && (curbuf->b_p_ai 4713 #ifdef FEAT_CINDENT 4714 || cindent_on() 4715 #endif 4716 ) 4717 #ifdef FEAT_RIGHTLEFT 4718 && !revins_on 4719 #endif 4720 ) 4721 { 4722 save_col = curwin->w_cursor.col; 4723 beginline(BL_WHITE); 4724 if (curwin->w_cursor.col < save_col) 4725 mincol = curwin->w_cursor.col; 4726 curwin->w_cursor.col = save_col; 4727 } 4728 4729 /* 4730 * Handle deleting one 'shiftwidth' or 'softtabstop'. 4731 */ 4732 if ( mode == BACKSPACE_CHAR 4733 && ((p_sta && in_indent) 4734 || ((get_sts_value() != 0 4735 #ifdef FEAT_VARTABS 4736 || tabstop_count(curbuf->b_p_vsts_array) 4737 #endif 4738 ) 4739 && curwin->w_cursor.col > 0 4740 && (*(ml_get_cursor() - 1) == TAB 4741 || (*(ml_get_cursor() - 1) == ' ' 4742 && (!*inserted_space_p 4743 || arrow_used)))))) 4744 { 4745 int ts; 4746 colnr_T vcol; 4747 colnr_T want_vcol; 4748 colnr_T start_vcol; 4749 4750 *inserted_space_p = FALSE; 4751 // Compute the virtual column where we want to be. Since 4752 // 'showbreak' may get in the way, need to get the last column of 4753 // the previous character. 4754 getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL); 4755 start_vcol = vcol; 4756 dec_cursor(); 4757 getvcol(curwin, &curwin->w_cursor, NULL, NULL, &want_vcol); 4758 inc_cursor(); 4759 #ifdef FEAT_VARTABS 4760 if (p_sta && in_indent) 4761 { 4762 ts = (int)get_sw_value(curbuf); 4763 want_vcol = (want_vcol / ts) * ts; 4764 } 4765 else 4766 want_vcol = tabstop_start(want_vcol, get_sts_value(), 4767 curbuf->b_p_vsts_array); 4768 #else 4769 if (p_sta && in_indent) 4770 ts = (int)get_sw_value(curbuf); 4771 else 4772 ts = (int)get_sts_value(); 4773 want_vcol = (want_vcol / ts) * ts; 4774 #endif 4775 4776 // delete characters until we are at or before want_vcol 4777 while (vcol > want_vcol 4778 && (cc = *(ml_get_cursor() - 1), VIM_ISWHITE(cc))) 4779 ins_bs_one(&vcol); 4780 4781 // insert extra spaces until we are at want_vcol 4782 while (vcol < want_vcol) 4783 { 4784 // Remember the first char we inserted 4785 if (curwin->w_cursor.lnum == Insstart_orig.lnum 4786 && curwin->w_cursor.col < Insstart_orig.col) 4787 Insstart_orig.col = curwin->w_cursor.col; 4788 4789 if (State & VREPLACE_FLAG) 4790 ins_char(' '); 4791 else 4792 { 4793 ins_str((char_u *)" "); 4794 if ((State & REPLACE_FLAG)) 4795 replace_push(NUL); 4796 } 4797 getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL); 4798 } 4799 4800 // If we are now back where we started delete one character. Can 4801 // happen when using 'sts' and 'linebreak'. 4802 if (vcol >= start_vcol) 4803 ins_bs_one(&vcol); 4804 } 4805 4806 /* 4807 * Delete up to starting point, start of line or previous word. 4808 */ 4809 else 4810 { 4811 int cclass = 0, prev_cclass = 0; 4812 4813 if (has_mbyte) 4814 cclass = mb_get_class(ml_get_cursor()); 4815 do 4816 { 4817 #ifdef FEAT_RIGHTLEFT 4818 if (!revins_on) // put cursor on char to be deleted 4819 #endif 4820 dec_cursor(); 4821 4822 cc = gchar_cursor(); 4823 // look multi-byte character class 4824 if (has_mbyte) 4825 { 4826 prev_cclass = cclass; 4827 cclass = mb_get_class(ml_get_cursor()); 4828 } 4829 4830 // start of word? 4831 if (mode == BACKSPACE_WORD && !vim_isspace(cc)) 4832 { 4833 mode = BACKSPACE_WORD_NOT_SPACE; 4834 temp = vim_iswordc(cc); 4835 } 4836 // end of word? 4837 else if (mode == BACKSPACE_WORD_NOT_SPACE 4838 && ((vim_isspace(cc) || vim_iswordc(cc) != temp) 4839 || prev_cclass != cclass)) 4840 { 4841 #ifdef FEAT_RIGHTLEFT 4842 if (!revins_on) 4843 #endif 4844 inc_cursor(); 4845 #ifdef FEAT_RIGHTLEFT 4846 else if (State & REPLACE_FLAG) 4847 dec_cursor(); 4848 #endif 4849 break; 4850 } 4851 if (State & REPLACE_FLAG) 4852 replace_do_bs(-1); 4853 else 4854 { 4855 if (enc_utf8 && p_deco) 4856 (void)utfc_ptr2char(ml_get_cursor(), cpc); 4857 (void)del_char(FALSE); 4858 /* 4859 * If there are combining characters and 'delcombine' is set 4860 * move the cursor back. Don't back up before the base 4861 * character. 4862 */ 4863 if (enc_utf8 && p_deco && cpc[0] != NUL) 4864 inc_cursor(); 4865 #ifdef FEAT_RIGHTLEFT 4866 if (revins_chars) 4867 { 4868 revins_chars--; 4869 revins_legal++; 4870 } 4871 if (revins_on && gchar_cursor() == NUL) 4872 break; 4873 #endif 4874 } 4875 // Just a single backspace?: 4876 if (mode == BACKSPACE_CHAR) 4877 break; 4878 } while ( 4879 #ifdef FEAT_RIGHTLEFT 4880 revins_on || 4881 #endif 4882 (curwin->w_cursor.col > mincol 4883 && (curwin->w_cursor.lnum != Insstart_orig.lnum 4884 || curwin->w_cursor.col != Insstart_orig.col))); 4885 } 4886 did_backspace = TRUE; 4887 } 4888 #ifdef FEAT_SMARTINDENT 4889 did_si = FALSE; 4890 can_si = FALSE; 4891 can_si_back = FALSE; 4892 #endif 4893 if (curwin->w_cursor.col <= 1) 4894 did_ai = FALSE; 4895 /* 4896 * It's a little strange to put backspaces into the redo 4897 * buffer, but it makes auto-indent a lot easier to deal 4898 * with. 4899 */ 4900 AppendCharToRedobuff(c); 4901 4902 // If deleted before the insertion point, adjust it 4903 if (curwin->w_cursor.lnum == Insstart_orig.lnum 4904 && curwin->w_cursor.col < Insstart_orig.col) 4905 Insstart_orig.col = curwin->w_cursor.col; 4906 4907 // vi behaviour: the cursor moves backward but the character that 4908 // was there remains visible 4909 // Vim behaviour: the cursor moves backward and the character that 4910 // was there is erased from the screen. 4911 // We can emulate the vi behaviour by pretending there is a dollar 4912 // displayed even when there isn't. 4913 // --pkv Sun Jan 19 01:56:40 EST 2003 4914 if (vim_strchr(p_cpo, CPO_BACKSPACE) != NULL && dollar_vcol == -1) 4915 dollar_vcol = curwin->w_virtcol; 4916 4917 #ifdef FEAT_FOLDING 4918 // When deleting a char the cursor line must never be in a closed fold. 4919 // E.g., when 'foldmethod' is indent and deleting the first non-white 4920 // char before a Tab. 4921 if (did_backspace) 4922 foldOpenCursor(); 4923 #endif 4924 4925 return did_backspace; 4926 } 4927 4928 /* 4929 * Handle receiving P_PS: start paste mode. Inserts the following text up to 4930 * P_PE literally. 4931 * When "drop" is TRUE then consume the text and drop it. 4932 */ 4933 int 4934 bracketed_paste(paste_mode_T mode, int drop, garray_T *gap) 4935 { 4936 int c; 4937 char_u buf[NUMBUFLEN + MB_MAXBYTES]; 4938 int idx = 0; 4939 char_u *end = find_termcode((char_u *)"PE"); 4940 int ret_char = -1; 4941 int save_allow_keys = allow_keys; 4942 int save_paste = p_paste; 4943 4944 // If the end code is too long we can't detect it, read everything. 4945 if (end != NULL && STRLEN(end) >= NUMBUFLEN) 4946 end = NULL; 4947 ++no_mapping; 4948 allow_keys = 0; 4949 if (!p_paste) 4950 // Also have the side effects of setting 'paste' to make it work much 4951 // faster. 4952 set_option_value((char_u *)"paste", TRUE, NULL, 0); 4953 4954 for (;;) 4955 { 4956 // When the end is not defined read everything there is. 4957 if (end == NULL && vpeekc() == NUL) 4958 break; 4959 do 4960 c = vgetc(); 4961 while (c == K_IGNORE || c == K_VER_SCROLLBAR || c == K_HOR_SCROLLBAR); 4962 if (c == NUL || got_int || (ex_normal_busy > 0 && c == Ctrl_C)) 4963 // When CTRL-C was encountered the typeahead will be flushed and we 4964 // won't get the end sequence. Except when using ":normal". 4965 break; 4966 4967 if (has_mbyte) 4968 idx += (*mb_char2bytes)(c, buf + idx); 4969 else 4970 buf[idx++] = c; 4971 buf[idx] = NUL; 4972 if (end != NULL && STRNCMP(buf, end, idx) == 0) 4973 { 4974 if (end[idx] == NUL) 4975 break; // Found the end of paste code. 4976 continue; 4977 } 4978 if (!drop) 4979 { 4980 switch (mode) 4981 { 4982 case PASTE_CMDLINE: 4983 put_on_cmdline(buf, idx, TRUE); 4984 break; 4985 4986 case PASTE_EX: 4987 if (gap != NULL && ga_grow(gap, idx) == OK) 4988 { 4989 mch_memmove((char *)gap->ga_data + gap->ga_len, 4990 buf, (size_t)idx); 4991 gap->ga_len += idx; 4992 } 4993 break; 4994 4995 case PASTE_INSERT: 4996 if (stop_arrow() == OK) 4997 { 4998 c = buf[0]; 4999 if (idx == 1 && (c == CAR || c == K_KENTER || c == NL)) 5000 ins_eol(c); 5001 else 5002 { 5003 ins_char_bytes(buf, idx); 5004 AppendToRedobuffLit(buf, idx); 5005 } 5006 } 5007 break; 5008 5009 case PASTE_ONE_CHAR: 5010 if (ret_char == -1) 5011 { 5012 if (has_mbyte) 5013 ret_char = (*mb_ptr2char)(buf); 5014 else 5015 ret_char = buf[0]; 5016 } 5017 break; 5018 } 5019 } 5020 idx = 0; 5021 } 5022 5023 --no_mapping; 5024 allow_keys = save_allow_keys; 5025 if (!save_paste) 5026 set_option_value((char_u *)"paste", FALSE, NULL, 0); 5027 5028 return ret_char; 5029 } 5030 5031 #if defined(FEAT_GUI_TABLINE) || defined(PROTO) 5032 static void 5033 ins_tabline(int c) 5034 { 5035 // We will be leaving the current window, unless closing another tab. 5036 if (c != K_TABMENU || current_tabmenu != TABLINE_MENU_CLOSE 5037 || (current_tab != 0 && current_tab != tabpage_index(curtab))) 5038 { 5039 undisplay_dollar(); 5040 start_arrow(&curwin->w_cursor); 5041 # ifdef FEAT_CINDENT 5042 can_cindent = TRUE; 5043 # endif 5044 } 5045 5046 if (c == K_TABLINE) 5047 goto_tabpage(current_tab); 5048 else 5049 { 5050 handle_tabmenu(); 5051 redraw_statuslines(); // will redraw the tabline when needed 5052 } 5053 } 5054 #endif 5055 5056 #if defined(FEAT_GUI) || defined(PROTO) 5057 void 5058 ins_scroll(void) 5059 { 5060 pos_T tpos; 5061 5062 undisplay_dollar(); 5063 tpos = curwin->w_cursor; 5064 if (gui_do_scroll()) 5065 { 5066 start_arrow(&tpos); 5067 # ifdef FEAT_CINDENT 5068 can_cindent = TRUE; 5069 # endif 5070 } 5071 } 5072 5073 void 5074 ins_horscroll(void) 5075 { 5076 pos_T tpos; 5077 5078 undisplay_dollar(); 5079 tpos = curwin->w_cursor; 5080 if (gui_do_horiz_scroll(scrollbar_value, FALSE)) 5081 { 5082 start_arrow(&tpos); 5083 # ifdef FEAT_CINDENT 5084 can_cindent = TRUE; 5085 # endif 5086 } 5087 } 5088 #endif 5089 5090 static void 5091 ins_left(void) 5092 { 5093 pos_T tpos; 5094 int end_change = dont_sync_undo == FALSE; // end undoable change 5095 5096 #ifdef FEAT_FOLDING 5097 if ((fdo_flags & FDO_HOR) && KeyTyped) 5098 foldOpenCursor(); 5099 #endif 5100 undisplay_dollar(); 5101 tpos = curwin->w_cursor; 5102 if (oneleft() == OK) 5103 { 5104 #if defined(FEAT_XIM) && defined(FEAT_GUI_GTK) 5105 // Only call start_arrow() when not busy with preediting, it will 5106 // break undo. K_LEFT is inserted in im_correct_cursor(). 5107 if (p_imst == IM_OVER_THE_SPOT || !im_is_preediting()) 5108 #endif 5109 { 5110 start_arrow_with_change(&tpos, end_change); 5111 if (!end_change) 5112 AppendCharToRedobuff(K_LEFT); 5113 } 5114 #ifdef FEAT_RIGHTLEFT 5115 // If exit reversed string, position is fixed 5116 if (revins_scol != -1 && (int)curwin->w_cursor.col >= revins_scol) 5117 revins_legal++; 5118 revins_chars++; 5119 #endif 5120 } 5121 5122 /* 5123 * if 'whichwrap' set for cursor in insert mode may go to 5124 * previous line 5125 */ 5126 else if (vim_strchr(p_ww, '[') != NULL && curwin->w_cursor.lnum > 1) 5127 { 5128 // always break undo when moving upwards/downwards, else undo may break 5129 start_arrow(&tpos); 5130 --(curwin->w_cursor.lnum); 5131 coladvance((colnr_T)MAXCOL); 5132 curwin->w_set_curswant = TRUE; // so we stay at the end 5133 } 5134 else 5135 vim_beep(BO_CRSR); 5136 dont_sync_undo = FALSE; 5137 } 5138 5139 static void 5140 ins_home(int c) 5141 { 5142 pos_T tpos; 5143 5144 #ifdef FEAT_FOLDING 5145 if ((fdo_flags & FDO_HOR) && KeyTyped) 5146 foldOpenCursor(); 5147 #endif 5148 undisplay_dollar(); 5149 tpos = curwin->w_cursor; 5150 if (c == K_C_HOME) 5151 curwin->w_cursor.lnum = 1; 5152 curwin->w_cursor.col = 0; 5153 curwin->w_cursor.coladd = 0; 5154 curwin->w_curswant = 0; 5155 start_arrow(&tpos); 5156 } 5157 5158 static void 5159 ins_end(int c) 5160 { 5161 pos_T tpos; 5162 5163 #ifdef FEAT_FOLDING 5164 if ((fdo_flags & FDO_HOR) && KeyTyped) 5165 foldOpenCursor(); 5166 #endif 5167 undisplay_dollar(); 5168 tpos = curwin->w_cursor; 5169 if (c == K_C_END) 5170 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; 5171 coladvance((colnr_T)MAXCOL); 5172 curwin->w_curswant = MAXCOL; 5173 5174 start_arrow(&tpos); 5175 } 5176 5177 static void 5178 ins_s_left() 5179 { 5180 int end_change = dont_sync_undo == FALSE; // end undoable change 5181 #ifdef FEAT_FOLDING 5182 if ((fdo_flags & FDO_HOR) && KeyTyped) 5183 foldOpenCursor(); 5184 #endif 5185 undisplay_dollar(); 5186 if (curwin->w_cursor.lnum > 1 || curwin->w_cursor.col > 0) 5187 { 5188 start_arrow_with_change(&curwin->w_cursor, end_change); 5189 if (!end_change) 5190 AppendCharToRedobuff(K_S_LEFT); 5191 (void)bck_word(1L, FALSE, FALSE); 5192 curwin->w_set_curswant = TRUE; 5193 } 5194 else 5195 vim_beep(BO_CRSR); 5196 dont_sync_undo = FALSE; 5197 } 5198 5199 static void 5200 ins_right(void) 5201 { 5202 int end_change = dont_sync_undo == FALSE; // end undoable change 5203 5204 #ifdef FEAT_FOLDING 5205 if ((fdo_flags & FDO_HOR) && KeyTyped) 5206 foldOpenCursor(); 5207 #endif 5208 undisplay_dollar(); 5209 if (gchar_cursor() != NUL || virtual_active()) 5210 { 5211 start_arrow_with_change(&curwin->w_cursor, end_change); 5212 if (!end_change) 5213 AppendCharToRedobuff(K_RIGHT); 5214 curwin->w_set_curswant = TRUE; 5215 if (virtual_active()) 5216 oneright(); 5217 else 5218 { 5219 if (has_mbyte) 5220 curwin->w_cursor.col += (*mb_ptr2len)(ml_get_cursor()); 5221 else 5222 ++curwin->w_cursor.col; 5223 } 5224 5225 #ifdef FEAT_RIGHTLEFT 5226 revins_legal++; 5227 if (revins_chars) 5228 revins_chars--; 5229 #endif 5230 } 5231 // if 'whichwrap' set for cursor in insert mode, may move the 5232 // cursor to the next line 5233 else if (vim_strchr(p_ww, ']') != NULL 5234 && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) 5235 { 5236 start_arrow(&curwin->w_cursor); 5237 curwin->w_set_curswant = TRUE; 5238 ++curwin->w_cursor.lnum; 5239 curwin->w_cursor.col = 0; 5240 } 5241 else 5242 vim_beep(BO_CRSR); 5243 dont_sync_undo = FALSE; 5244 } 5245 5246 static void 5247 ins_s_right() 5248 { 5249 int end_change = dont_sync_undo == FALSE; // end undoable change 5250 #ifdef FEAT_FOLDING 5251 if ((fdo_flags & FDO_HOR) && KeyTyped) 5252 foldOpenCursor(); 5253 #endif 5254 undisplay_dollar(); 5255 if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count 5256 || gchar_cursor() != NUL) 5257 { 5258 start_arrow_with_change(&curwin->w_cursor, end_change); 5259 if (!end_change) 5260 AppendCharToRedobuff(K_S_RIGHT); 5261 (void)fwd_word(1L, FALSE, 0); 5262 curwin->w_set_curswant = TRUE; 5263 } 5264 else 5265 vim_beep(BO_CRSR); 5266 dont_sync_undo = FALSE; 5267 } 5268 5269 static void 5270 ins_up( 5271 int startcol) // when TRUE move to Insstart.col 5272 { 5273 pos_T tpos; 5274 linenr_T old_topline = curwin->w_topline; 5275 #ifdef FEAT_DIFF 5276 int old_topfill = curwin->w_topfill; 5277 #endif 5278 5279 undisplay_dollar(); 5280 tpos = curwin->w_cursor; 5281 if (cursor_up(1L, TRUE) == OK) 5282 { 5283 if (startcol) 5284 coladvance(getvcol_nolist(&Insstart)); 5285 if (old_topline != curwin->w_topline 5286 #ifdef FEAT_DIFF 5287 || old_topfill != curwin->w_topfill 5288 #endif 5289 ) 5290 redraw_later(VALID); 5291 start_arrow(&tpos); 5292 #ifdef FEAT_CINDENT 5293 can_cindent = TRUE; 5294 #endif 5295 } 5296 else 5297 vim_beep(BO_CRSR); 5298 } 5299 5300 static void 5301 ins_pageup(void) 5302 { 5303 pos_T tpos; 5304 5305 undisplay_dollar(); 5306 5307 if (mod_mask & MOD_MASK_CTRL) 5308 { 5309 // <C-PageUp>: tab page back 5310 if (first_tabpage->tp_next != NULL) 5311 { 5312 start_arrow(&curwin->w_cursor); 5313 goto_tabpage(-1); 5314 } 5315 return; 5316 } 5317 5318 tpos = curwin->w_cursor; 5319 if (onepage(BACKWARD, 1L) == OK) 5320 { 5321 start_arrow(&tpos); 5322 #ifdef FEAT_CINDENT 5323 can_cindent = TRUE; 5324 #endif 5325 } 5326 else 5327 vim_beep(BO_CRSR); 5328 } 5329 5330 static void 5331 ins_down( 5332 int startcol) // when TRUE move to Insstart.col 5333 { 5334 pos_T tpos; 5335 linenr_T old_topline = curwin->w_topline; 5336 #ifdef FEAT_DIFF 5337 int old_topfill = curwin->w_topfill; 5338 #endif 5339 5340 undisplay_dollar(); 5341 tpos = curwin->w_cursor; 5342 if (cursor_down(1L, TRUE) == OK) 5343 { 5344 if (startcol) 5345 coladvance(getvcol_nolist(&Insstart)); 5346 if (old_topline != curwin->w_topline 5347 #ifdef FEAT_DIFF 5348 || old_topfill != curwin->w_topfill 5349 #endif 5350 ) 5351 redraw_later(VALID); 5352 start_arrow(&tpos); 5353 #ifdef FEAT_CINDENT 5354 can_cindent = TRUE; 5355 #endif 5356 } 5357 else 5358 vim_beep(BO_CRSR); 5359 } 5360 5361 static void 5362 ins_pagedown(void) 5363 { 5364 pos_T tpos; 5365 5366 undisplay_dollar(); 5367 5368 if (mod_mask & MOD_MASK_CTRL) 5369 { 5370 // <C-PageDown>: tab page forward 5371 if (first_tabpage->tp_next != NULL) 5372 { 5373 start_arrow(&curwin->w_cursor); 5374 goto_tabpage(0); 5375 } 5376 return; 5377 } 5378 5379 tpos = curwin->w_cursor; 5380 if (onepage(FORWARD, 1L) == OK) 5381 { 5382 start_arrow(&tpos); 5383 #ifdef FEAT_CINDENT 5384 can_cindent = TRUE; 5385 #endif 5386 } 5387 else 5388 vim_beep(BO_CRSR); 5389 } 5390 5391 #ifdef FEAT_DND 5392 static void 5393 ins_drop(void) 5394 { 5395 do_put('~', BACKWARD, 1L, PUT_CURSEND); 5396 } 5397 #endif 5398 5399 /* 5400 * Handle TAB in Insert or Replace mode. 5401 * Return TRUE when the TAB needs to be inserted like a normal character. 5402 */ 5403 static int 5404 ins_tab(void) 5405 { 5406 int ind; 5407 int i; 5408 int temp; 5409 5410 if (Insstart_blank_vcol == MAXCOL && curwin->w_cursor.lnum == Insstart.lnum) 5411 Insstart_blank_vcol = get_nolist_virtcol(); 5412 if (echeck_abbr(TAB + ABBR_OFF)) 5413 return FALSE; 5414 5415 ind = inindent(0); 5416 #ifdef FEAT_CINDENT 5417 if (ind) 5418 can_cindent = FALSE; 5419 #endif 5420 5421 /* 5422 * When nothing special, insert TAB like a normal character. 5423 */ 5424 if (!curbuf->b_p_et 5425 #ifdef FEAT_VARTABS 5426 && !(p_sta && ind 5427 // These five lines mean 'tabstop' != 'shiftwidth' 5428 && ((tabstop_count(curbuf->b_p_vts_array) > 1) 5429 || (tabstop_count(curbuf->b_p_vts_array) == 1 5430 && tabstop_first(curbuf->b_p_vts_array) 5431 != get_sw_value(curbuf)) 5432 || (tabstop_count(curbuf->b_p_vts_array) == 0 5433 && curbuf->b_p_ts != get_sw_value(curbuf)))) 5434 && tabstop_count(curbuf->b_p_vsts_array) == 0 5435 #else 5436 && !(p_sta && ind && curbuf->b_p_ts != get_sw_value(curbuf)) 5437 #endif 5438 && get_sts_value() == 0) 5439 return TRUE; 5440 5441 if (stop_arrow() == FAIL) 5442 return TRUE; 5443 5444 did_ai = FALSE; 5445 #ifdef FEAT_SMARTINDENT 5446 did_si = FALSE; 5447 can_si = FALSE; 5448 can_si_back = FALSE; 5449 #endif 5450 AppendToRedobuff((char_u *)"\t"); 5451 5452 #ifdef FEAT_VARTABS 5453 if (p_sta && ind) // insert tab in indent, use 'shiftwidth' 5454 { 5455 temp = (int)get_sw_value(curbuf); 5456 temp -= get_nolist_virtcol() % temp; 5457 } 5458 else if (tabstop_count(curbuf->b_p_vsts_array) > 0 || curbuf->b_p_sts != 0) 5459 // use 'softtabstop' when set 5460 temp = tabstop_padding(get_nolist_virtcol(), get_sts_value(), 5461 curbuf->b_p_vsts_array); 5462 else // otherwise use 'tabstop' 5463 temp = tabstop_padding(get_nolist_virtcol(), curbuf->b_p_ts, 5464 curbuf->b_p_vts_array); 5465 #else 5466 if (p_sta && ind) // insert tab in indent, use 'shiftwidth' 5467 temp = (int)get_sw_value(curbuf); 5468 else if (curbuf->b_p_sts != 0) // use 'softtabstop' when set 5469 temp = (int)get_sts_value(); 5470 else // otherwise use 'tabstop' 5471 temp = (int)curbuf->b_p_ts; 5472 temp -= get_nolist_virtcol() % temp; 5473 #endif 5474 5475 /* 5476 * Insert the first space with ins_char(). It will delete one char in 5477 * replace mode. Insert the rest with ins_str(); it will not delete any 5478 * chars. For VREPLACE mode, we use ins_char() for all characters. 5479 */ 5480 ins_char(' '); 5481 while (--temp > 0) 5482 { 5483 if (State & VREPLACE_FLAG) 5484 ins_char(' '); 5485 else 5486 { 5487 ins_str((char_u *)" "); 5488 if (State & REPLACE_FLAG) // no char replaced 5489 replace_push(NUL); 5490 } 5491 } 5492 5493 /* 5494 * When 'expandtab' not set: Replace spaces by TABs where possible. 5495 */ 5496 #ifdef FEAT_VARTABS 5497 if (!curbuf->b_p_et && (tabstop_count(curbuf->b_p_vsts_array) > 0 5498 || get_sts_value() > 0 5499 || (p_sta && ind))) 5500 #else 5501 if (!curbuf->b_p_et && (get_sts_value() || (p_sta && ind))) 5502 #endif 5503 { 5504 char_u *ptr; 5505 char_u *saved_line = NULL; // init for GCC 5506 pos_T pos; 5507 pos_T fpos; 5508 pos_T *cursor; 5509 colnr_T want_vcol, vcol; 5510 int change_col = -1; 5511 int save_list = curwin->w_p_list; 5512 5513 /* 5514 * Get the current line. For VREPLACE mode, don't make real changes 5515 * yet, just work on a copy of the line. 5516 */ 5517 if (State & VREPLACE_FLAG) 5518 { 5519 pos = curwin->w_cursor; 5520 cursor = &pos; 5521 saved_line = vim_strsave(ml_get_curline()); 5522 if (saved_line == NULL) 5523 return FALSE; 5524 ptr = saved_line + pos.col; 5525 } 5526 else 5527 { 5528 ptr = ml_get_cursor(); 5529 cursor = &curwin->w_cursor; 5530 } 5531 5532 // When 'L' is not in 'cpoptions' a tab always takes up 'ts' spaces. 5533 if (vim_strchr(p_cpo, CPO_LISTWM) == NULL) 5534 curwin->w_p_list = FALSE; 5535 5536 // Find first white before the cursor 5537 fpos = curwin->w_cursor; 5538 while (fpos.col > 0 && VIM_ISWHITE(ptr[-1])) 5539 { 5540 --fpos.col; 5541 --ptr; 5542 } 5543 5544 // In Replace mode, don't change characters before the insert point. 5545 if ((State & REPLACE_FLAG) 5546 && fpos.lnum == Insstart.lnum 5547 && fpos.col < Insstart.col) 5548 { 5549 ptr += Insstart.col - fpos.col; 5550 fpos.col = Insstart.col; 5551 } 5552 5553 // compute virtual column numbers of first white and cursor 5554 getvcol(curwin, &fpos, &vcol, NULL, NULL); 5555 getvcol(curwin, cursor, &want_vcol, NULL, NULL); 5556 5557 // Use as many TABs as possible. Beware of 'breakindent', 'showbreak' 5558 // and 'linebreak' adding extra virtual columns. 5559 while (VIM_ISWHITE(*ptr)) 5560 { 5561 i = lbr_chartabsize(NULL, (char_u *)"\t", vcol); 5562 if (vcol + i > want_vcol) 5563 break; 5564 if (*ptr != TAB) 5565 { 5566 *ptr = TAB; 5567 if (change_col < 0) 5568 { 5569 change_col = fpos.col; // Column of first change 5570 // May have to adjust Insstart 5571 if (fpos.lnum == Insstart.lnum && fpos.col < Insstart.col) 5572 Insstart.col = fpos.col; 5573 } 5574 } 5575 ++fpos.col; 5576 ++ptr; 5577 vcol += i; 5578 } 5579 5580 if (change_col >= 0) 5581 { 5582 int repl_off = 0; 5583 char_u *line = ptr; 5584 5585 // Skip over the spaces we need. 5586 while (vcol < want_vcol && *ptr == ' ') 5587 { 5588 vcol += lbr_chartabsize(line, ptr, vcol); 5589 ++ptr; 5590 ++repl_off; 5591 } 5592 if (vcol > want_vcol) 5593 { 5594 // Must have a char with 'showbreak' just before it. 5595 --ptr; 5596 --repl_off; 5597 } 5598 fpos.col += repl_off; 5599 5600 // Delete following spaces. 5601 i = cursor->col - fpos.col; 5602 if (i > 0) 5603 { 5604 #ifdef FEAT_PROP_POPUP 5605 if (!(State & VREPLACE_FLAG)) 5606 { 5607 char_u *newp; 5608 int col; 5609 5610 newp = alloc(curbuf->b_ml.ml_line_len - i); 5611 if (newp == NULL) 5612 return FALSE; 5613 5614 col = ptr - curbuf->b_ml.ml_line_ptr; 5615 if (col > 0) 5616 mch_memmove(newp, ptr - col, col); 5617 mch_memmove(newp + col, ptr + i, 5618 curbuf->b_ml.ml_line_len - col - i); 5619 5620 if (curbuf->b_ml.ml_flags & ML_LINE_DIRTY) 5621 vim_free(curbuf->b_ml.ml_line_ptr); 5622 curbuf->b_ml.ml_line_ptr = newp; 5623 curbuf->b_ml.ml_line_len -= i; 5624 curbuf->b_ml.ml_flags = 5625 (curbuf->b_ml.ml_flags | ML_LINE_DIRTY) & ~ML_EMPTY; 5626 } 5627 else 5628 #endif 5629 STRMOVE(ptr, ptr + i); 5630 // correct replace stack. 5631 if ((State & REPLACE_FLAG) && !(State & VREPLACE_FLAG)) 5632 for (temp = i; --temp >= 0; ) 5633 replace_join(repl_off); 5634 } 5635 #ifdef FEAT_NETBEANS_INTG 5636 if (netbeans_active()) 5637 { 5638 netbeans_removed(curbuf, fpos.lnum, cursor->col, (long)(i + 1)); 5639 netbeans_inserted(curbuf, fpos.lnum, cursor->col, 5640 (char_u *)"\t", 1); 5641 } 5642 #endif 5643 cursor->col -= i; 5644 5645 /* 5646 * In VREPLACE mode, we haven't changed anything yet. Do it now by 5647 * backspacing over the changed spacing and then inserting the new 5648 * spacing. 5649 */ 5650 if (State & VREPLACE_FLAG) 5651 { 5652 // Backspace from real cursor to change_col 5653 backspace_until_column(change_col); 5654 5655 // Insert each char in saved_line from changed_col to 5656 // ptr-cursor 5657 ins_bytes_len(saved_line + change_col, 5658 cursor->col - change_col); 5659 } 5660 } 5661 5662 if (State & VREPLACE_FLAG) 5663 vim_free(saved_line); 5664 curwin->w_p_list = save_list; 5665 } 5666 5667 return FALSE; 5668 } 5669 5670 /* 5671 * Handle CR or NL in insert mode. 5672 * Return FAIL when out of memory or can't undo. 5673 */ 5674 int 5675 ins_eol(int c) 5676 { 5677 int i; 5678 5679 if (echeck_abbr(c + ABBR_OFF)) 5680 return OK; 5681 if (stop_arrow() == FAIL) 5682 return FAIL; 5683 undisplay_dollar(); 5684 5685 /* 5686 * Strange Vi behaviour: In Replace mode, typing a NL will not delete the 5687 * character under the cursor. Only push a NUL on the replace stack, 5688 * nothing to put back when the NL is deleted. 5689 */ 5690 if ((State & REPLACE_FLAG) && !(State & VREPLACE_FLAG)) 5691 replace_push(NUL); 5692 5693 /* 5694 * In VREPLACE mode, a NL replaces the rest of the line, and starts 5695 * replacing the next line, so we push all of the characters left on the 5696 * line onto the replace stack. This is not done here though, it is done 5697 * in open_line(). 5698 */ 5699 5700 // Put cursor on NUL if on the last char and coladd is 1 (happens after 5701 // CTRL-O). 5702 if (virtual_active() && curwin->w_cursor.coladd > 0) 5703 coladvance(getviscol()); 5704 5705 #ifdef FEAT_RIGHTLEFT 5706 // NL in reverse insert will always start in the end of 5707 // current line. 5708 if (revins_on) 5709 curwin->w_cursor.col += (colnr_T)STRLEN(ml_get_cursor()); 5710 #endif 5711 5712 AppendToRedobuff(NL_STR); 5713 i = open_line(FORWARD, 5714 has_format_option(FO_RET_COMS) ? OPENLINE_DO_COM : 0, old_indent); 5715 old_indent = 0; 5716 #ifdef FEAT_CINDENT 5717 can_cindent = TRUE; 5718 #endif 5719 #ifdef FEAT_FOLDING 5720 // When inserting a line the cursor line must never be in a closed fold. 5721 foldOpenCursor(); 5722 #endif 5723 5724 return i; 5725 } 5726 5727 #ifdef FEAT_DIGRAPHS 5728 /* 5729 * Handle digraph in insert mode. 5730 * Returns character still to be inserted, or NUL when nothing remaining to be 5731 * done. 5732 */ 5733 static int 5734 ins_digraph(void) 5735 { 5736 int c; 5737 int cc; 5738 int did_putchar = FALSE; 5739 5740 pc_status = PC_STATUS_UNSET; 5741 if (redrawing() && !char_avail()) 5742 { 5743 // may need to redraw when no more chars available now 5744 ins_redraw(FALSE); 5745 5746 edit_putchar('?', TRUE); 5747 did_putchar = TRUE; 5748 #ifdef FEAT_CMDL_INFO 5749 add_to_showcmd_c(Ctrl_K); 5750 #endif 5751 } 5752 5753 #ifdef USE_ON_FLY_SCROLL 5754 dont_scroll = TRUE; // disallow scrolling here 5755 #endif 5756 5757 // don't map the digraph chars. This also prevents the 5758 // mode message to be deleted when ESC is hit 5759 ++no_mapping; 5760 ++allow_keys; 5761 c = plain_vgetc(); 5762 --no_mapping; 5763 --allow_keys; 5764 if (did_putchar) 5765 // when the line fits in 'columns' the '?' is at the start of the next 5766 // line and will not be removed by the redraw 5767 edit_unputchar(); 5768 5769 if (IS_SPECIAL(c) || mod_mask) // special key 5770 { 5771 #ifdef FEAT_CMDL_INFO 5772 clear_showcmd(); 5773 #endif 5774 insert_special(c, TRUE, FALSE); 5775 return NUL; 5776 } 5777 if (c != ESC) 5778 { 5779 did_putchar = FALSE; 5780 if (redrawing() && !char_avail()) 5781 { 5782 // may need to redraw when no more chars available now 5783 ins_redraw(FALSE); 5784 5785 if (char2cells(c) == 1) 5786 { 5787 ins_redraw(FALSE); 5788 edit_putchar(c, TRUE); 5789 did_putchar = TRUE; 5790 } 5791 #ifdef FEAT_CMDL_INFO 5792 add_to_showcmd_c(c); 5793 #endif 5794 } 5795 ++no_mapping; 5796 ++allow_keys; 5797 cc = plain_vgetc(); 5798 --no_mapping; 5799 --allow_keys; 5800 if (did_putchar) 5801 // when the line fits in 'columns' the '?' is at the start of the 5802 // next line and will not be removed by a redraw 5803 edit_unputchar(); 5804 if (cc != ESC) 5805 { 5806 AppendToRedobuff((char_u *)CTRL_V_STR); 5807 c = getdigraph(c, cc, TRUE); 5808 #ifdef FEAT_CMDL_INFO 5809 clear_showcmd(); 5810 #endif 5811 return c; 5812 } 5813 } 5814 #ifdef FEAT_CMDL_INFO 5815 clear_showcmd(); 5816 #endif 5817 return NUL; 5818 } 5819 #endif 5820 5821 /* 5822 * Handle CTRL-E and CTRL-Y in Insert mode: copy char from other line. 5823 * Returns the char to be inserted, or NUL if none found. 5824 */ 5825 int 5826 ins_copychar(linenr_T lnum) 5827 { 5828 int c; 5829 int temp; 5830 char_u *ptr, *prev_ptr; 5831 char_u *line; 5832 5833 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count) 5834 { 5835 vim_beep(BO_COPY); 5836 return NUL; 5837 } 5838 5839 // try to advance to the cursor column 5840 temp = 0; 5841 line = ptr = ml_get(lnum); 5842 prev_ptr = ptr; 5843 validate_virtcol(); 5844 while ((colnr_T)temp < curwin->w_virtcol && *ptr != NUL) 5845 { 5846 prev_ptr = ptr; 5847 temp += lbr_chartabsize_adv(line, &ptr, (colnr_T)temp); 5848 } 5849 if ((colnr_T)temp > curwin->w_virtcol) 5850 ptr = prev_ptr; 5851 5852 c = (*mb_ptr2char)(ptr); 5853 if (c == NUL) 5854 vim_beep(BO_COPY); 5855 return c; 5856 } 5857 5858 /* 5859 * CTRL-Y or CTRL-E typed in Insert mode. 5860 */ 5861 static int 5862 ins_ctrl_ey(int tc) 5863 { 5864 int c = tc; 5865 5866 if (ctrl_x_mode_scroll()) 5867 { 5868 if (c == Ctrl_Y) 5869 scrolldown_clamp(); 5870 else 5871 scrollup_clamp(); 5872 redraw_later(VALID); 5873 } 5874 else 5875 { 5876 c = ins_copychar(curwin->w_cursor.lnum + (c == Ctrl_Y ? -1 : 1)); 5877 if (c != NUL) 5878 { 5879 long tw_save; 5880 5881 // The character must be taken literally, insert like it 5882 // was typed after a CTRL-V, and pretend 'textwidth' 5883 // wasn't set. Digits, 'o' and 'x' are special after a 5884 // CTRL-V, don't use it for these. 5885 if (c < 256 && !isalnum(c)) 5886 AppendToRedobuff((char_u *)CTRL_V_STR); // CTRL-V 5887 tw_save = curbuf->b_p_tw; 5888 curbuf->b_p_tw = -1; 5889 insert_special(c, TRUE, FALSE); 5890 curbuf->b_p_tw = tw_save; 5891 #ifdef FEAT_RIGHTLEFT 5892 revins_chars++; 5893 revins_legal++; 5894 #endif 5895 c = Ctrl_V; // pretend CTRL-V is last character 5896 auto_format(FALSE, TRUE); 5897 } 5898 } 5899 return c; 5900 } 5901 5902 /* 5903 * Get the value that w_virtcol would have when 'list' is off. 5904 * Unless 'cpo' contains the 'L' flag. 5905 */ 5906 colnr_T 5907 get_nolist_virtcol(void) 5908 { 5909 // check validity of cursor in current buffer 5910 if (curwin->w_buffer == NULL 5911 || curwin->w_buffer->b_ml.ml_mfp == NULL 5912 || curwin->w_cursor.lnum > curwin->w_buffer->b_ml.ml_line_count) 5913 return 0; 5914 if (curwin->w_p_list && vim_strchr(p_cpo, CPO_LISTWM) == NULL) 5915 return getvcol_nolist(&curwin->w_cursor); 5916 validate_virtcol(); 5917 return curwin->w_virtcol; 5918 } 5919 5920 #if defined(FEAT_EVAL) 5921 /* 5922 * Handle the InsertCharPre autocommand. 5923 * "c" is the character that was typed. 5924 * Return a pointer to allocated memory with the replacement string. 5925 * Return NULL to continue inserting "c". 5926 */ 5927 static char_u * 5928 do_insert_char_pre(int c) 5929 { 5930 char_u *res; 5931 char_u buf[MB_MAXBYTES + 1]; 5932 int save_State = State; 5933 5934 // Return quickly when there is nothing to do. 5935 if (!has_insertcharpre()) 5936 return NULL; 5937 5938 if (has_mbyte) 5939 buf[(*mb_char2bytes)(c, buf)] = NUL; 5940 else 5941 { 5942 buf[0] = c; 5943 buf[1] = NUL; 5944 } 5945 5946 // Lock the text to avoid weird things from happening. 5947 ++textlock; 5948 set_vim_var_string(VV_CHAR, buf, -1); // set v:char 5949 5950 res = NULL; 5951 if (ins_apply_autocmds(EVENT_INSERTCHARPRE)) 5952 { 5953 // Get the value of v:char. It may be empty or more than one 5954 // character. Only use it when changed, otherwise continue with the 5955 // original character to avoid breaking autoindent. 5956 if (STRCMP(buf, get_vim_var_str(VV_CHAR)) != 0) 5957 res = vim_strsave(get_vim_var_str(VV_CHAR)); 5958 } 5959 5960 set_vim_var_string(VV_CHAR, NULL, -1); // clear v:char 5961 --textlock; 5962 5963 // Restore the State, it may have been changed. 5964 State = save_State; 5965 5966 return res; 5967 } 5968 #endif 5969 5970 #if defined(FEAT_CINDENT) || defined(PROTO) 5971 int 5972 get_can_cindent(void) 5973 { 5974 return can_cindent; 5975 } 5976 5977 void 5978 set_can_cindent(int val) 5979 { 5980 can_cindent = val; 5981 } 5982 #endif 5983 5984 /* 5985 * Trigger "event" and take care of fixing undo. 5986 */ 5987 int 5988 ins_apply_autocmds(event_T event) 5989 { 5990 varnumber_T tick = CHANGEDTICK(curbuf); 5991 int r; 5992 5993 r = apply_autocmds(event, NULL, NULL, FALSE, curbuf); 5994 5995 // If u_savesub() was called then we are not prepared to start 5996 // a new line. Call u_save() with no contents to fix that. 5997 if (tick != CHANGEDTICK(curbuf)) 5998 u_save(curwin->w_cursor.lnum, (linenr_T)(curwin->w_cursor.lnum + 1)); 5999 6000 return r; 6001 } 6002