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 #if defined(FEAT_CLIENTSERVER) || defined(FEAT_EVAL) 1616 if (typebuf.tb_len == 0) 1617 typebuf_was_filled = FALSE; 1618 #endif 1619 1620 mod_mask = decode_modifiers(arg[!form]); 1621 c = merge_modifyOtherKeys(arg[form]); 1622 } 1623 } 1624 1625 return c; 1626 } 1627 1628 /* 1629 * Put a character directly onto the screen. It's not stored in a buffer. 1630 * Used while handling CTRL-K, CTRL-V, etc. in Insert mode. 1631 */ 1632 static int pc_status; 1633 #define PC_STATUS_UNSET 0 // pc_bytes was not set 1634 #define PC_STATUS_RIGHT 1 // right halve of double-wide char 1635 #define PC_STATUS_LEFT 2 // left halve of double-wide char 1636 #define PC_STATUS_SET 3 // pc_bytes was filled 1637 static char_u pc_bytes[MB_MAXBYTES + 1]; // saved bytes 1638 static int pc_attr; 1639 static int pc_row; 1640 static int pc_col; 1641 1642 void 1643 edit_putchar(int c, int highlight) 1644 { 1645 int attr; 1646 1647 if (ScreenLines != NULL) 1648 { 1649 update_topline(); // just in case w_topline isn't valid 1650 validate_cursor(); 1651 if (highlight) 1652 attr = HL_ATTR(HLF_8); 1653 else 1654 attr = 0; 1655 pc_row = W_WINROW(curwin) + curwin->w_wrow; 1656 pc_col = curwin->w_wincol; 1657 pc_status = PC_STATUS_UNSET; 1658 #ifdef FEAT_RIGHTLEFT 1659 if (curwin->w_p_rl) 1660 { 1661 pc_col += curwin->w_width - 1 - curwin->w_wcol; 1662 if (has_mbyte) 1663 { 1664 int fix_col = mb_fix_col(pc_col, pc_row); 1665 1666 if (fix_col != pc_col) 1667 { 1668 screen_putchar(' ', pc_row, fix_col, attr); 1669 --curwin->w_wcol; 1670 pc_status = PC_STATUS_RIGHT; 1671 } 1672 } 1673 } 1674 else 1675 #endif 1676 { 1677 pc_col += curwin->w_wcol; 1678 if (mb_lefthalve(pc_row, pc_col)) 1679 pc_status = PC_STATUS_LEFT; 1680 } 1681 1682 // save the character to be able to put it back 1683 if (pc_status == PC_STATUS_UNSET) 1684 { 1685 screen_getbytes(pc_row, pc_col, pc_bytes, &pc_attr); 1686 pc_status = PC_STATUS_SET; 1687 } 1688 screen_putchar(c, pc_row, pc_col, attr); 1689 } 1690 } 1691 1692 #if defined(FEAT_JOB_CHANNEL) || defined(PROTO) 1693 /* 1694 * Return the effective prompt for the current buffer. 1695 */ 1696 char_u * 1697 prompt_text(void) 1698 { 1699 if (curbuf->b_prompt_text == NULL) 1700 return (char_u *)"% "; 1701 return curbuf->b_prompt_text; 1702 } 1703 1704 /* 1705 * Prepare for prompt mode: Make sure the last line has the prompt text. 1706 * Move the cursor to this line. 1707 */ 1708 static void 1709 init_prompt(int cmdchar_todo) 1710 { 1711 char_u *prompt = prompt_text(); 1712 char_u *text; 1713 1714 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; 1715 text = ml_get_curline(); 1716 if (STRNCMP(text, prompt, STRLEN(prompt)) != 0) 1717 { 1718 // prompt is missing, insert it or append a line with it 1719 if (*text == NUL) 1720 ml_replace(curbuf->b_ml.ml_line_count, prompt, TRUE); 1721 else 1722 ml_append(curbuf->b_ml.ml_line_count, prompt, 0, FALSE); 1723 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; 1724 coladvance((colnr_T)MAXCOL); 1725 changed_bytes(curbuf->b_ml.ml_line_count, 0); 1726 } 1727 1728 // Insert always starts after the prompt, allow editing text after it. 1729 if (Insstart_orig.lnum != curwin->w_cursor.lnum 1730 || Insstart_orig.col != (int)STRLEN(prompt)) 1731 { 1732 Insstart.lnum = curwin->w_cursor.lnum; 1733 Insstart.col = (int)STRLEN(prompt); 1734 Insstart_orig = Insstart; 1735 Insstart_textlen = Insstart.col; 1736 Insstart_blank_vcol = MAXCOL; 1737 arrow_used = FALSE; 1738 } 1739 1740 if (cmdchar_todo == 'A') 1741 coladvance((colnr_T)MAXCOL); 1742 if (cmdchar_todo == 'I' || curwin->w_cursor.col <= (int)STRLEN(prompt)) 1743 curwin->w_cursor.col = (int)STRLEN(prompt); 1744 // Make sure the cursor is in a valid position. 1745 check_cursor(); 1746 } 1747 1748 /* 1749 * Return TRUE if the cursor is in the editable position of the prompt line. 1750 */ 1751 int 1752 prompt_curpos_editable() 1753 { 1754 return curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count 1755 && curwin->w_cursor.col >= (int)STRLEN(prompt_text()); 1756 } 1757 #endif 1758 1759 /* 1760 * Undo the previous edit_putchar(). 1761 */ 1762 void 1763 edit_unputchar(void) 1764 { 1765 if (pc_status != PC_STATUS_UNSET && pc_row >= msg_scrolled) 1766 { 1767 if (pc_status == PC_STATUS_RIGHT) 1768 ++curwin->w_wcol; 1769 if (pc_status == PC_STATUS_RIGHT || pc_status == PC_STATUS_LEFT) 1770 redrawWinline(curwin, curwin->w_cursor.lnum); 1771 else 1772 screen_puts(pc_bytes, pc_row - msg_scrolled, pc_col, pc_attr); 1773 } 1774 } 1775 1776 /* 1777 * Called when p_dollar is set: display a '$' at the end of the changed text 1778 * Only works when cursor is in the line that changes. 1779 */ 1780 void 1781 display_dollar(colnr_T col) 1782 { 1783 colnr_T save_col; 1784 1785 if (!redrawing()) 1786 return; 1787 1788 cursor_off(); 1789 save_col = curwin->w_cursor.col; 1790 curwin->w_cursor.col = col; 1791 if (has_mbyte) 1792 { 1793 char_u *p; 1794 1795 // If on the last byte of a multi-byte move to the first byte. 1796 p = ml_get_curline(); 1797 curwin->w_cursor.col -= (*mb_head_off)(p, p + col); 1798 } 1799 curs_columns(FALSE); // recompute w_wrow and w_wcol 1800 if (curwin->w_wcol < curwin->w_width) 1801 { 1802 edit_putchar('$', FALSE); 1803 dollar_vcol = curwin->w_virtcol; 1804 } 1805 curwin->w_cursor.col = save_col; 1806 } 1807 1808 /* 1809 * Call this function before moving the cursor from the normal insert position 1810 * in insert mode. 1811 */ 1812 void 1813 undisplay_dollar(void) 1814 { 1815 if (dollar_vcol >= 0) 1816 { 1817 dollar_vcol = -1; 1818 redrawWinline(curwin, curwin->w_cursor.lnum); 1819 } 1820 } 1821 1822 /* 1823 * Truncate the space at the end of a line. This is to be used only in an 1824 * insert mode. It handles fixing the replace stack for REPLACE and VREPLACE 1825 * modes. 1826 */ 1827 void 1828 truncate_spaces(char_u *line) 1829 { 1830 int i; 1831 1832 // find start of trailing white space 1833 for (i = (int)STRLEN(line) - 1; i >= 0 && VIM_ISWHITE(line[i]); i--) 1834 { 1835 if (State & REPLACE_FLAG) 1836 replace_join(0); // remove a NUL from the replace stack 1837 } 1838 line[i + 1] = NUL; 1839 } 1840 1841 /* 1842 * Backspace the cursor until the given column. Handles REPLACE and VREPLACE 1843 * modes correctly. May also be used when not in insert mode at all. 1844 * Will attempt not to go before "col" even when there is a composing 1845 * character. 1846 */ 1847 void 1848 backspace_until_column(int col) 1849 { 1850 while ((int)curwin->w_cursor.col > col) 1851 { 1852 curwin->w_cursor.col--; 1853 if (State & REPLACE_FLAG) 1854 replace_do_bs(col); 1855 else if (!del_char_after_col(col)) 1856 break; 1857 } 1858 } 1859 1860 /* 1861 * Like del_char(), but make sure not to go before column "limit_col". 1862 * Only matters when there are composing characters. 1863 * Return TRUE when something was deleted. 1864 */ 1865 static int 1866 del_char_after_col(int limit_col UNUSED) 1867 { 1868 if (enc_utf8 && limit_col >= 0) 1869 { 1870 colnr_T ecol = curwin->w_cursor.col + 1; 1871 1872 // Make sure the cursor is at the start of a character, but 1873 // skip forward again when going too far back because of a 1874 // composing character. 1875 mb_adjust_cursor(); 1876 while (curwin->w_cursor.col < (colnr_T)limit_col) 1877 { 1878 int l = utf_ptr2len(ml_get_cursor()); 1879 1880 if (l == 0) // end of line 1881 break; 1882 curwin->w_cursor.col += l; 1883 } 1884 if (*ml_get_cursor() == NUL || curwin->w_cursor.col == ecol) 1885 return FALSE; 1886 del_bytes((long)((int)ecol - curwin->w_cursor.col), FALSE, TRUE); 1887 } 1888 else 1889 (void)del_char(FALSE); 1890 return TRUE; 1891 } 1892 1893 /* 1894 * Next character is interpreted literally. 1895 * A one, two or three digit decimal number is interpreted as its byte value. 1896 * If one or two digits are entered, the next character is given to vungetc(). 1897 * For Unicode a character > 255 may be returned. 1898 */ 1899 int 1900 get_literal(void) 1901 { 1902 int cc; 1903 int nc; 1904 int i; 1905 int hex = FALSE; 1906 int octal = FALSE; 1907 int unicode = 0; 1908 1909 if (got_int) 1910 return Ctrl_C; 1911 1912 #ifdef FEAT_GUI 1913 /* 1914 * In GUI there is no point inserting the internal code for a special key. 1915 * It is more useful to insert the string "<KEY>" instead. This would 1916 * probably be useful in a text window too, but it would not be 1917 * vi-compatible (maybe there should be an option for it?) -- webb 1918 */ 1919 if (gui.in_use) 1920 ++allow_keys; 1921 #endif 1922 #ifdef USE_ON_FLY_SCROLL 1923 dont_scroll = TRUE; // disallow scrolling here 1924 #endif 1925 ++no_mapping; // don't map the next key hits 1926 cc = 0; 1927 i = 0; 1928 for (;;) 1929 { 1930 nc = plain_vgetc(); 1931 #ifdef FEAT_CMDL_INFO 1932 if (!(State & CMDLINE) && MB_BYTE2LEN_CHECK(nc) == 1) 1933 add_to_showcmd(nc); 1934 #endif 1935 if (nc == 'x' || nc == 'X') 1936 hex = TRUE; 1937 else if (nc == 'o' || nc == 'O') 1938 octal = TRUE; 1939 else if (nc == 'u' || nc == 'U') 1940 unicode = nc; 1941 else 1942 { 1943 if (hex || unicode != 0) 1944 { 1945 if (!vim_isxdigit(nc)) 1946 break; 1947 cc = cc * 16 + hex2nr(nc); 1948 } 1949 else if (octal) 1950 { 1951 if (nc < '0' || nc > '7') 1952 break; 1953 cc = cc * 8 + nc - '0'; 1954 } 1955 else 1956 { 1957 if (!VIM_ISDIGIT(nc)) 1958 break; 1959 cc = cc * 10 + nc - '0'; 1960 } 1961 1962 ++i; 1963 } 1964 1965 if (cc > 255 && unicode == 0) 1966 cc = 255; // limit range to 0-255 1967 nc = 0; 1968 1969 if (hex) // hex: up to two chars 1970 { 1971 if (i >= 2) 1972 break; 1973 } 1974 else if (unicode) // Unicode: up to four or eight chars 1975 { 1976 if ((unicode == 'u' && i >= 4) || (unicode == 'U' && i >= 8)) 1977 break; 1978 } 1979 else if (i >= 3) // decimal or octal: up to three chars 1980 break; 1981 } 1982 if (i == 0) // no number entered 1983 { 1984 if (nc == K_ZERO) // NUL is stored as NL 1985 { 1986 cc = '\n'; 1987 nc = 0; 1988 } 1989 else 1990 { 1991 cc = nc; 1992 nc = 0; 1993 } 1994 } 1995 1996 if (cc == 0) // NUL is stored as NL 1997 cc = '\n'; 1998 if (enc_dbcs && (cc & 0xff) == 0) 1999 cc = '?'; // don't accept an illegal DBCS char, the NUL in the 2000 // second byte will cause trouble! 2001 2002 --no_mapping; 2003 #ifdef FEAT_GUI 2004 if (gui.in_use) 2005 --allow_keys; 2006 #endif 2007 if (nc) 2008 vungetc(nc); 2009 got_int = FALSE; // CTRL-C typed after CTRL-V is not an interrupt 2010 return cc; 2011 } 2012 2013 /* 2014 * Insert character, taking care of special keys and mod_mask 2015 */ 2016 static void 2017 insert_special( 2018 int c, 2019 int allow_modmask, 2020 int ctrlv) // c was typed after CTRL-V 2021 { 2022 char_u *p; 2023 int len; 2024 2025 /* 2026 * Special function key, translate into "<Key>". Up to the last '>' is 2027 * inserted with ins_str(), so as not to replace characters in replace 2028 * mode. 2029 * Only use mod_mask for special keys, to avoid things like <S-Space>, 2030 * unless 'allow_modmask' is TRUE. 2031 */ 2032 #ifdef MACOS_X 2033 // Command-key never produces a normal key 2034 if (mod_mask & MOD_MASK_CMD) 2035 allow_modmask = TRUE; 2036 #endif 2037 if (IS_SPECIAL(c) || (mod_mask && allow_modmask)) 2038 { 2039 p = get_special_key_name(c, mod_mask); 2040 len = (int)STRLEN(p); 2041 c = p[len - 1]; 2042 if (len > 2) 2043 { 2044 if (stop_arrow() == FAIL) 2045 return; 2046 p[len - 1] = NUL; 2047 ins_str(p); 2048 AppendToRedobuffLit(p, -1); 2049 ctrlv = FALSE; 2050 } 2051 } 2052 if (stop_arrow() == OK) 2053 insertchar(c, ctrlv ? INSCHAR_CTRLV : 0, -1); 2054 } 2055 2056 /* 2057 * Special characters in this context are those that need processing other 2058 * than the simple insertion that can be performed here. This includes ESC 2059 * which terminates the insert, and CR/NL which need special processing to 2060 * open up a new line. This routine tries to optimize insertions performed by 2061 * the "redo", "undo" or "put" commands, so it needs to know when it should 2062 * stop and defer processing to the "normal" mechanism. 2063 * '0' and '^' are special, because they can be followed by CTRL-D. 2064 */ 2065 #ifdef EBCDIC 2066 # define ISSPECIAL(c) ((c) < ' ' || (c) == '0' || (c) == '^') 2067 #else 2068 # define ISSPECIAL(c) ((c) < ' ' || (c) >= DEL || (c) == '0' || (c) == '^') 2069 #endif 2070 2071 #define WHITECHAR(cc) (VIM_ISWHITE(cc) && (!enc_utf8 || !utf_iscomposing(utf_ptr2char(ml_get_cursor() + 1)))) 2072 2073 /* 2074 * "flags": INSCHAR_FORMAT - force formatting 2075 * INSCHAR_CTRLV - char typed just after CTRL-V 2076 * INSCHAR_NO_FEX - don't use 'formatexpr' 2077 * 2078 * NOTE: passes the flags value straight through to internal_format() which, 2079 * beside INSCHAR_FORMAT (above), is also looking for these: 2080 * INSCHAR_DO_COM - format comments 2081 * INSCHAR_COM_LIST - format comments with num list or 2nd line indent 2082 */ 2083 void 2084 insertchar( 2085 int c, // character to insert or NUL 2086 int flags, // INSCHAR_FORMAT, etc. 2087 int second_indent) // indent for second line if >= 0 2088 { 2089 int textwidth; 2090 char_u *p; 2091 int fo_ins_blank; 2092 int force_format = flags & INSCHAR_FORMAT; 2093 2094 textwidth = comp_textwidth(force_format); 2095 fo_ins_blank = has_format_option(FO_INS_BLANK); 2096 2097 /* 2098 * Try to break the line in two or more pieces when: 2099 * - Always do this if we have been called to do formatting only. 2100 * - Always do this when 'formatoptions' has the 'a' flag and the line 2101 * ends in white space. 2102 * - Otherwise: 2103 * - Don't do this if inserting a blank 2104 * - Don't do this if an existing character is being replaced, unless 2105 * we're in VREPLACE mode. 2106 * - Do this if the cursor is not on the line where insert started 2107 * or - 'formatoptions' doesn't have 'l' or the line was not too long 2108 * before the insert. 2109 * - 'formatoptions' doesn't have 'b' or a blank was inserted at or 2110 * before 'textwidth' 2111 */ 2112 if (textwidth > 0 2113 && (force_format 2114 || (!VIM_ISWHITE(c) 2115 && !((State & REPLACE_FLAG) 2116 && !(State & VREPLACE_FLAG) 2117 && *ml_get_cursor() != NUL) 2118 && (curwin->w_cursor.lnum != Insstart.lnum 2119 || ((!has_format_option(FO_INS_LONG) 2120 || Insstart_textlen <= (colnr_T)textwidth) 2121 && (!fo_ins_blank 2122 || Insstart_blank_vcol <= (colnr_T)textwidth 2123 )))))) 2124 { 2125 // Format with 'formatexpr' when it's set. Use internal formatting 2126 // when 'formatexpr' isn't set or it returns non-zero. 2127 #if defined(FEAT_EVAL) 2128 int do_internal = TRUE; 2129 colnr_T virtcol = get_nolist_virtcol() 2130 + char2cells(c != NUL ? c : gchar_cursor()); 2131 2132 if (*curbuf->b_p_fex != NUL && (flags & INSCHAR_NO_FEX) == 0 2133 && (force_format || virtcol > (colnr_T)textwidth)) 2134 { 2135 do_internal = (fex_format(curwin->w_cursor.lnum, 1L, c) != 0); 2136 // It may be required to save for undo again, e.g. when setline() 2137 // was called. 2138 ins_need_undo = TRUE; 2139 } 2140 if (do_internal) 2141 #endif 2142 internal_format(textwidth, second_indent, flags, c == NUL, c); 2143 } 2144 2145 if (c == NUL) // only formatting was wanted 2146 return; 2147 2148 // Check whether this character should end a comment. 2149 if (did_ai && (int)c == end_comment_pending) 2150 { 2151 char_u *line; 2152 char_u lead_end[COM_MAX_LEN]; // end-comment string 2153 int middle_len, end_len; 2154 int i; 2155 2156 /* 2157 * Need to remove existing (middle) comment leader and insert end 2158 * comment leader. First, check what comment leader we can find. 2159 */ 2160 i = get_leader_len(line = ml_get_curline(), &p, FALSE, TRUE); 2161 if (i > 0 && vim_strchr(p, COM_MIDDLE) != NULL) // Just checking 2162 { 2163 // Skip middle-comment string 2164 while (*p && p[-1] != ':') // find end of middle flags 2165 ++p; 2166 middle_len = copy_option_part(&p, lead_end, COM_MAX_LEN, ","); 2167 // Don't count trailing white space for middle_len 2168 while (middle_len > 0 && VIM_ISWHITE(lead_end[middle_len - 1])) 2169 --middle_len; 2170 2171 // Find the end-comment string 2172 while (*p && p[-1] != ':') // find end of end flags 2173 ++p; 2174 end_len = copy_option_part(&p, lead_end, COM_MAX_LEN, ","); 2175 2176 // Skip white space before the cursor 2177 i = curwin->w_cursor.col; 2178 while (--i >= 0 && VIM_ISWHITE(line[i])) 2179 ; 2180 i++; 2181 2182 // Skip to before the middle leader 2183 i -= middle_len; 2184 2185 // Check some expected things before we go on 2186 if (i >= 0 && lead_end[end_len - 1] == end_comment_pending) 2187 { 2188 // Backspace over all the stuff we want to replace 2189 backspace_until_column(i); 2190 2191 // Insert the end-comment string, except for the last 2192 // character, which will get inserted as normal later. 2193 ins_bytes_len(lead_end, end_len - 1); 2194 } 2195 } 2196 } 2197 end_comment_pending = NUL; 2198 2199 did_ai = FALSE; 2200 #ifdef FEAT_SMARTINDENT 2201 did_si = FALSE; 2202 can_si = FALSE; 2203 can_si_back = FALSE; 2204 #endif 2205 2206 /* 2207 * If there's any pending input, grab up to INPUT_BUFLEN at once. 2208 * This speeds up normal text input considerably. 2209 * Don't do this when 'cindent' or 'indentexpr' is set, because we might 2210 * need to re-indent at a ':', or any other character (but not what 2211 * 'paste' is set).. 2212 * Don't do this when there an InsertCharPre autocommand is defined, 2213 * because we need to fire the event for every character. 2214 * Do the check for InsertCharPre before the call to vpeekc() because the 2215 * InsertCharPre autocommand could change the input buffer. 2216 */ 2217 #ifdef USE_ON_FLY_SCROLL 2218 dont_scroll = FALSE; // allow scrolling here 2219 #endif 2220 2221 if ( !ISSPECIAL(c) 2222 && (!has_mbyte || (*mb_char2len)(c) == 1) 2223 && !has_insertcharpre() 2224 && vpeekc() != NUL 2225 && !(State & REPLACE_FLAG) 2226 #ifdef FEAT_CINDENT 2227 && !cindent_on() 2228 #endif 2229 #ifdef FEAT_RIGHTLEFT 2230 && !p_ri 2231 #endif 2232 ) 2233 { 2234 #define INPUT_BUFLEN 100 2235 char_u buf[INPUT_BUFLEN + 1]; 2236 int i; 2237 colnr_T virtcol = 0; 2238 2239 buf[0] = c; 2240 i = 1; 2241 if (textwidth > 0) 2242 virtcol = get_nolist_virtcol(); 2243 /* 2244 * Stop the string when: 2245 * - no more chars available 2246 * - finding a special character (command key) 2247 * - buffer is full 2248 * - running into the 'textwidth' boundary 2249 * - need to check for abbreviation: A non-word char after a word-char 2250 */ 2251 while ( (c = vpeekc()) != NUL 2252 && !ISSPECIAL(c) 2253 && (!has_mbyte || MB_BYTE2LEN_CHECK(c) == 1) 2254 && i < INPUT_BUFLEN 2255 && (textwidth == 0 2256 || (virtcol += byte2cells(buf[i - 1])) < (colnr_T)textwidth) 2257 && !(!no_abbr && !vim_iswordc(c) && vim_iswordc(buf[i - 1]))) 2258 { 2259 #ifdef FEAT_RIGHTLEFT 2260 c = vgetc(); 2261 if (p_hkmap && KeyTyped) 2262 c = hkmap(c); // Hebrew mode mapping 2263 buf[i++] = c; 2264 #else 2265 buf[i++] = vgetc(); 2266 #endif 2267 } 2268 2269 #ifdef FEAT_DIGRAPHS 2270 do_digraph(-1); // clear digraphs 2271 do_digraph(buf[i-1]); // may be the start of a digraph 2272 #endif 2273 buf[i] = NUL; 2274 ins_str(buf); 2275 if (flags & INSCHAR_CTRLV) 2276 { 2277 redo_literal(*buf); 2278 i = 1; 2279 } 2280 else 2281 i = 0; 2282 if (buf[i] != NUL) 2283 AppendToRedobuffLit(buf + i, -1); 2284 } 2285 else 2286 { 2287 int cc; 2288 2289 if (has_mbyte && (cc = (*mb_char2len)(c)) > 1) 2290 { 2291 char_u buf[MB_MAXBYTES + 1]; 2292 2293 (*mb_char2bytes)(c, buf); 2294 buf[cc] = NUL; 2295 ins_char_bytes(buf, cc); 2296 AppendCharToRedobuff(c); 2297 } 2298 else 2299 { 2300 ins_char(c); 2301 if (flags & INSCHAR_CTRLV) 2302 redo_literal(c); 2303 else 2304 AppendCharToRedobuff(c); 2305 } 2306 } 2307 } 2308 2309 /* 2310 * Format text at the current insert position. 2311 * 2312 * If the INSCHAR_COM_LIST flag is present, then the value of second_indent 2313 * will be the comment leader length sent to open_line(). 2314 */ 2315 static void 2316 internal_format( 2317 int textwidth, 2318 int second_indent, 2319 int flags, 2320 int format_only, 2321 int c) // character to be inserted (can be NUL) 2322 { 2323 int cc; 2324 int save_char = NUL; 2325 int haveto_redraw = FALSE; 2326 int fo_ins_blank = has_format_option(FO_INS_BLANK); 2327 int fo_multibyte = has_format_option(FO_MBYTE_BREAK); 2328 int fo_white_par = has_format_option(FO_WHITE_PAR); 2329 int first_line = TRUE; 2330 colnr_T leader_len; 2331 int no_leader = FALSE; 2332 int do_comments = (flags & INSCHAR_DO_COM); 2333 #ifdef FEAT_LINEBREAK 2334 int has_lbr = curwin->w_p_lbr; 2335 2336 // make sure win_lbr_chartabsize() counts correctly 2337 curwin->w_p_lbr = FALSE; 2338 #endif 2339 2340 /* 2341 * When 'ai' is off we don't want a space under the cursor to be 2342 * deleted. Replace it with an 'x' temporarily. 2343 */ 2344 if (!curbuf->b_p_ai && !(State & VREPLACE_FLAG)) 2345 { 2346 cc = gchar_cursor(); 2347 if (VIM_ISWHITE(cc)) 2348 { 2349 save_char = cc; 2350 pchar_cursor('x'); 2351 } 2352 } 2353 2354 /* 2355 * Repeat breaking lines, until the current line is not too long. 2356 */ 2357 while (!got_int) 2358 { 2359 int startcol; // Cursor column at entry 2360 int wantcol; // column at textwidth border 2361 int foundcol; // column for start of spaces 2362 int end_foundcol = 0; // column for start of word 2363 colnr_T len; 2364 colnr_T virtcol; 2365 int orig_col = 0; 2366 char_u *saved_text = NULL; 2367 colnr_T col; 2368 colnr_T end_col; 2369 int wcc; // counter for whitespace chars 2370 2371 virtcol = get_nolist_virtcol() 2372 + char2cells(c != NUL ? c : gchar_cursor()); 2373 if (virtcol <= (colnr_T)textwidth) 2374 break; 2375 2376 if (no_leader) 2377 do_comments = FALSE; 2378 else if (!(flags & INSCHAR_FORMAT) 2379 && has_format_option(FO_WRAP_COMS)) 2380 do_comments = TRUE; 2381 2382 // Don't break until after the comment leader 2383 if (do_comments) 2384 leader_len = get_leader_len(ml_get_curline(), NULL, FALSE, TRUE); 2385 else 2386 leader_len = 0; 2387 2388 // If the line doesn't start with a comment leader, then don't 2389 // start one in a following broken line. Avoids that a %word 2390 // moved to the start of the next line causes all following lines 2391 // to start with %. 2392 if (leader_len == 0) 2393 no_leader = TRUE; 2394 if (!(flags & INSCHAR_FORMAT) 2395 && leader_len == 0 2396 && !has_format_option(FO_WRAP)) 2397 2398 break; 2399 if ((startcol = curwin->w_cursor.col) == 0) 2400 break; 2401 2402 // find column of textwidth border 2403 coladvance((colnr_T)textwidth); 2404 wantcol = curwin->w_cursor.col; 2405 2406 curwin->w_cursor.col = startcol; 2407 foundcol = 0; 2408 2409 /* 2410 * Find position to break at. 2411 * Stop at first entered white when 'formatoptions' has 'v' 2412 */ 2413 while ((!fo_ins_blank && !has_format_option(FO_INS_VI)) 2414 || (flags & INSCHAR_FORMAT) 2415 || curwin->w_cursor.lnum != Insstart.lnum 2416 || curwin->w_cursor.col >= Insstart.col) 2417 { 2418 if (curwin->w_cursor.col == startcol && c != NUL) 2419 cc = c; 2420 else 2421 cc = gchar_cursor(); 2422 if (WHITECHAR(cc)) 2423 { 2424 // remember position of blank just before text 2425 end_col = curwin->w_cursor.col; 2426 2427 // find start of sequence of blanks 2428 wcc = 0; 2429 while (curwin->w_cursor.col > 0 && WHITECHAR(cc)) 2430 { 2431 dec_cursor(); 2432 cc = gchar_cursor(); 2433 2434 // Increment count of how many whitespace chars in this 2435 // group; we only need to know if it's more than one. 2436 if (wcc < 2) 2437 wcc++; 2438 } 2439 if (curwin->w_cursor.col == 0 && WHITECHAR(cc)) 2440 break; // only spaces in front of text 2441 2442 // Don't break after a period when 'formatoptions' has 'p' and 2443 // there are less than two spaces. 2444 if (has_format_option(FO_PERIOD_ABBR) && cc == '.' && wcc < 2) 2445 continue; 2446 2447 // Don't break until after the comment leader 2448 if (curwin->w_cursor.col < leader_len) 2449 break; 2450 if (has_format_option(FO_ONE_LETTER)) 2451 { 2452 // do not break after one-letter words 2453 if (curwin->w_cursor.col == 0) 2454 break; // one-letter word at begin 2455 // do not break "#a b" when 'tw' is 2 2456 if (curwin->w_cursor.col <= leader_len) 2457 break; 2458 col = curwin->w_cursor.col; 2459 dec_cursor(); 2460 cc = gchar_cursor(); 2461 2462 if (WHITECHAR(cc)) 2463 continue; // one-letter, continue 2464 curwin->w_cursor.col = col; 2465 } 2466 2467 inc_cursor(); 2468 2469 end_foundcol = end_col + 1; 2470 foundcol = curwin->w_cursor.col; 2471 if (curwin->w_cursor.col <= (colnr_T)wantcol) 2472 break; 2473 } 2474 else if (cc >= 0x100 && fo_multibyte) 2475 { 2476 // Break after or before a multi-byte character. 2477 if (curwin->w_cursor.col != startcol) 2478 { 2479 // Don't break until after the comment leader 2480 if (curwin->w_cursor.col < leader_len) 2481 break; 2482 col = curwin->w_cursor.col; 2483 inc_cursor(); 2484 // Don't change end_foundcol if already set. 2485 if (foundcol != curwin->w_cursor.col) 2486 { 2487 foundcol = curwin->w_cursor.col; 2488 end_foundcol = foundcol; 2489 if (curwin->w_cursor.col <= (colnr_T)wantcol) 2490 break; 2491 } 2492 curwin->w_cursor.col = col; 2493 } 2494 2495 if (curwin->w_cursor.col == 0) 2496 break; 2497 2498 col = curwin->w_cursor.col; 2499 2500 dec_cursor(); 2501 cc = gchar_cursor(); 2502 2503 if (WHITECHAR(cc)) 2504 continue; // break with space 2505 // Don't break until after the comment leader 2506 if (curwin->w_cursor.col < leader_len) 2507 break; 2508 2509 curwin->w_cursor.col = col; 2510 2511 foundcol = curwin->w_cursor.col; 2512 end_foundcol = foundcol; 2513 if (curwin->w_cursor.col <= (colnr_T)wantcol) 2514 break; 2515 } 2516 if (curwin->w_cursor.col == 0) 2517 break; 2518 dec_cursor(); 2519 } 2520 2521 if (foundcol == 0) // no spaces, cannot break line 2522 { 2523 curwin->w_cursor.col = startcol; 2524 break; 2525 } 2526 2527 // Going to break the line, remove any "$" now. 2528 undisplay_dollar(); 2529 2530 /* 2531 * Offset between cursor position and line break is used by replace 2532 * stack functions. VREPLACE does not use this, and backspaces 2533 * over the text instead. 2534 */ 2535 if (State & VREPLACE_FLAG) 2536 orig_col = startcol; // Will start backspacing from here 2537 else 2538 replace_offset = startcol - end_foundcol; 2539 2540 /* 2541 * adjust startcol for spaces that will be deleted and 2542 * characters that will remain on top line 2543 */ 2544 curwin->w_cursor.col = foundcol; 2545 while ((cc = gchar_cursor(), WHITECHAR(cc)) 2546 && (!fo_white_par || curwin->w_cursor.col < startcol)) 2547 inc_cursor(); 2548 startcol -= curwin->w_cursor.col; 2549 if (startcol < 0) 2550 startcol = 0; 2551 2552 if (State & VREPLACE_FLAG) 2553 { 2554 /* 2555 * In VREPLACE mode, we will backspace over the text to be 2556 * wrapped, so save a copy now to put on the next line. 2557 */ 2558 saved_text = vim_strsave(ml_get_cursor()); 2559 curwin->w_cursor.col = orig_col; 2560 if (saved_text == NULL) 2561 break; // Can't do it, out of memory 2562 saved_text[startcol] = NUL; 2563 2564 // Backspace over characters that will move to the next line 2565 if (!fo_white_par) 2566 backspace_until_column(foundcol); 2567 } 2568 else 2569 { 2570 // put cursor after pos. to break line 2571 if (!fo_white_par) 2572 curwin->w_cursor.col = foundcol; 2573 } 2574 2575 /* 2576 * Split the line just before the margin. 2577 * Only insert/delete lines, but don't really redraw the window. 2578 */ 2579 open_line(FORWARD, OPENLINE_DELSPACES + OPENLINE_MARKFIX 2580 + (fo_white_par ? OPENLINE_KEEPTRAIL : 0) 2581 + (do_comments ? OPENLINE_DO_COM : 0) 2582 + ((flags & INSCHAR_COM_LIST) ? OPENLINE_COM_LIST : 0) 2583 , ((flags & INSCHAR_COM_LIST) ? second_indent : old_indent)); 2584 if (!(flags & INSCHAR_COM_LIST)) 2585 old_indent = 0; 2586 2587 replace_offset = 0; 2588 if (first_line) 2589 { 2590 if (!(flags & INSCHAR_COM_LIST)) 2591 { 2592 /* 2593 * This section is for auto-wrap of numeric lists. When not 2594 * in insert mode (i.e. format_lines()), the INSCHAR_COM_LIST 2595 * flag will be set and open_line() will handle it (as seen 2596 * above). The code here (and in get_number_indent()) will 2597 * recognize comments if needed... 2598 */ 2599 if (second_indent < 0 && has_format_option(FO_Q_NUMBER)) 2600 second_indent = 2601 get_number_indent(curwin->w_cursor.lnum - 1); 2602 if (second_indent >= 0) 2603 { 2604 if (State & VREPLACE_FLAG) 2605 change_indent(INDENT_SET, second_indent, 2606 FALSE, NUL, TRUE); 2607 else 2608 if (leader_len > 0 && second_indent - leader_len > 0) 2609 { 2610 int i; 2611 int padding = second_indent - leader_len; 2612 2613 // We started at the first_line of a numbered list 2614 // that has a comment. the open_line() function has 2615 // inserted the proper comment leader and positioned 2616 // the cursor at the end of the split line. Now we 2617 // add the additional whitespace needed after the 2618 // comment leader for the numbered list. 2619 for (i = 0; i < padding; i++) 2620 ins_str((char_u *)" "); 2621 } 2622 else 2623 { 2624 (void)set_indent(second_indent, SIN_CHANGED); 2625 } 2626 } 2627 } 2628 first_line = FALSE; 2629 } 2630 2631 if (State & VREPLACE_FLAG) 2632 { 2633 /* 2634 * In VREPLACE mode we have backspaced over the text to be 2635 * moved, now we re-insert it into the new line. 2636 */ 2637 ins_bytes(saved_text); 2638 vim_free(saved_text); 2639 } 2640 else 2641 { 2642 /* 2643 * Check if cursor is not past the NUL off the line, cindent 2644 * may have added or removed indent. 2645 */ 2646 curwin->w_cursor.col += startcol; 2647 len = (colnr_T)STRLEN(ml_get_curline()); 2648 if (curwin->w_cursor.col > len) 2649 curwin->w_cursor.col = len; 2650 } 2651 2652 haveto_redraw = TRUE; 2653 #ifdef FEAT_CINDENT 2654 can_cindent = TRUE; 2655 #endif 2656 // moved the cursor, don't autoindent or cindent now 2657 did_ai = FALSE; 2658 #ifdef FEAT_SMARTINDENT 2659 did_si = FALSE; 2660 can_si = FALSE; 2661 can_si_back = FALSE; 2662 #endif 2663 line_breakcheck(); 2664 } 2665 2666 if (save_char != NUL) // put back space after cursor 2667 pchar_cursor(save_char); 2668 2669 #ifdef FEAT_LINEBREAK 2670 curwin->w_p_lbr = has_lbr; 2671 #endif 2672 if (!format_only && haveto_redraw) 2673 { 2674 update_topline(); 2675 redraw_curbuf_later(VALID); 2676 } 2677 } 2678 2679 /* 2680 * Called after inserting or deleting text: When 'formatoptions' includes the 2681 * 'a' flag format from the current line until the end of the paragraph. 2682 * Keep the cursor at the same position relative to the text. 2683 * The caller must have saved the cursor line for undo, following ones will be 2684 * saved here. 2685 */ 2686 void 2687 auto_format( 2688 int trailblank, // when TRUE also format with trailing blank 2689 int prev_line) // may start in previous line 2690 { 2691 pos_T pos; 2692 colnr_T len; 2693 char_u *old; 2694 char_u *new, *pnew; 2695 int wasatend; 2696 int cc; 2697 2698 if (!has_format_option(FO_AUTO)) 2699 return; 2700 2701 pos = curwin->w_cursor; 2702 old = ml_get_curline(); 2703 2704 // may remove added space 2705 check_auto_format(FALSE); 2706 2707 // Don't format in Insert mode when the cursor is on a trailing blank, the 2708 // user might insert normal text next. Also skip formatting when "1" is 2709 // in 'formatoptions' and there is a single character before the cursor. 2710 // Otherwise the line would be broken and when typing another non-white 2711 // next they are not joined back together. 2712 wasatend = (pos.col == (colnr_T)STRLEN(old)); 2713 if (*old != NUL && !trailblank && wasatend) 2714 { 2715 dec_cursor(); 2716 cc = gchar_cursor(); 2717 if (!WHITECHAR(cc) && curwin->w_cursor.col > 0 2718 && has_format_option(FO_ONE_LETTER)) 2719 dec_cursor(); 2720 cc = gchar_cursor(); 2721 if (WHITECHAR(cc)) 2722 { 2723 curwin->w_cursor = pos; 2724 return; 2725 } 2726 curwin->w_cursor = pos; 2727 } 2728 2729 // With the 'c' flag in 'formatoptions' and 't' missing: only format 2730 // comments. 2731 if (has_format_option(FO_WRAP_COMS) && !has_format_option(FO_WRAP) 2732 && get_leader_len(old, NULL, FALSE, TRUE) == 0) 2733 return; 2734 2735 /* 2736 * May start formatting in a previous line, so that after "x" a word is 2737 * moved to the previous line if it fits there now. Only when this is not 2738 * the start of a paragraph. 2739 */ 2740 if (prev_line && !paragraph_start(curwin->w_cursor.lnum)) 2741 { 2742 --curwin->w_cursor.lnum; 2743 if (u_save_cursor() == FAIL) 2744 return; 2745 } 2746 2747 /* 2748 * Do the formatting and restore the cursor position. "saved_cursor" will 2749 * be adjusted for the text formatting. 2750 */ 2751 saved_cursor = pos; 2752 format_lines((linenr_T)-1, FALSE); 2753 curwin->w_cursor = saved_cursor; 2754 saved_cursor.lnum = 0; 2755 2756 if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) 2757 { 2758 // "cannot happen" 2759 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; 2760 coladvance((colnr_T)MAXCOL); 2761 } 2762 else 2763 check_cursor_col(); 2764 2765 // Insert mode: If the cursor is now after the end of the line while it 2766 // previously wasn't, the line was broken. Because of the rule above we 2767 // need to add a space when 'w' is in 'formatoptions' to keep a paragraph 2768 // formatted. 2769 if (!wasatend && has_format_option(FO_WHITE_PAR)) 2770 { 2771 new = ml_get_curline(); 2772 len = (colnr_T)STRLEN(new); 2773 if (curwin->w_cursor.col == len) 2774 { 2775 pnew = vim_strnsave(new, len + 2); 2776 pnew[len] = ' '; 2777 pnew[len + 1] = NUL; 2778 ml_replace(curwin->w_cursor.lnum, pnew, FALSE); 2779 // remove the space later 2780 did_add_space = TRUE; 2781 } 2782 else 2783 // may remove added space 2784 check_auto_format(FALSE); 2785 } 2786 2787 check_cursor(); 2788 } 2789 2790 /* 2791 * When an extra space was added to continue a paragraph for auto-formatting, 2792 * delete it now. The space must be under the cursor, just after the insert 2793 * position. 2794 */ 2795 static void 2796 check_auto_format( 2797 int end_insert) // TRUE when ending Insert mode 2798 { 2799 int c = ' '; 2800 int cc; 2801 2802 if (did_add_space) 2803 { 2804 cc = gchar_cursor(); 2805 if (!WHITECHAR(cc)) 2806 // Somehow the space was removed already. 2807 did_add_space = FALSE; 2808 else 2809 { 2810 if (!end_insert) 2811 { 2812 inc_cursor(); 2813 c = gchar_cursor(); 2814 dec_cursor(); 2815 } 2816 if (c != NUL) 2817 { 2818 // The space is no longer at the end of the line, delete it. 2819 del_char(FALSE); 2820 did_add_space = FALSE; 2821 } 2822 } 2823 } 2824 } 2825 2826 /* 2827 * Find out textwidth to be used for formatting: 2828 * if 'textwidth' option is set, use it 2829 * else if 'wrapmargin' option is set, use curwin->w_width - 'wrapmargin' 2830 * if invalid value, use 0. 2831 * Set default to window width (maximum 79) for "gq" operator. 2832 */ 2833 int 2834 comp_textwidth( 2835 int ff) // force formatting (for "gq" command) 2836 { 2837 int textwidth; 2838 2839 textwidth = curbuf->b_p_tw; 2840 if (textwidth == 0 && curbuf->b_p_wm) 2841 { 2842 // The width is the window width minus 'wrapmargin' minus all the 2843 // things that add to the margin. 2844 textwidth = curwin->w_width - curbuf->b_p_wm; 2845 #ifdef FEAT_CMDWIN 2846 if (cmdwin_type != 0) 2847 textwidth -= 1; 2848 #endif 2849 #ifdef FEAT_FOLDING 2850 textwidth -= curwin->w_p_fdc; 2851 #endif 2852 #ifdef FEAT_SIGNS 2853 if (signcolumn_on(curwin)) 2854 textwidth -= 1; 2855 #endif 2856 if (curwin->w_p_nu || curwin->w_p_rnu) 2857 textwidth -= 8; 2858 } 2859 if (textwidth < 0) 2860 textwidth = 0; 2861 if (ff && textwidth == 0) 2862 { 2863 textwidth = curwin->w_width - 1; 2864 if (textwidth > 79) 2865 textwidth = 79; 2866 } 2867 return textwidth; 2868 } 2869 2870 /* 2871 * Put a character in the redo buffer, for when just after a CTRL-V. 2872 */ 2873 static void 2874 redo_literal(int c) 2875 { 2876 char_u buf[10]; 2877 2878 // Only digits need special treatment. Translate them into a string of 2879 // three digits. 2880 if (VIM_ISDIGIT(c)) 2881 { 2882 vim_snprintf((char *)buf, sizeof(buf), "%03d", c); 2883 AppendToRedobuff(buf); 2884 } 2885 else 2886 AppendCharToRedobuff(c); 2887 } 2888 2889 /* 2890 * start_arrow() is called when an arrow key is used in insert mode. 2891 * For undo/redo it resembles hitting the <ESC> key. 2892 */ 2893 void 2894 start_arrow( 2895 pos_T *end_insert_pos) // can be NULL 2896 { 2897 start_arrow_common(end_insert_pos, TRUE); 2898 } 2899 2900 /* 2901 * Like start_arrow() but with end_change argument. 2902 * Will prepare for redo of CTRL-G U if "end_change" is FALSE. 2903 */ 2904 static void 2905 start_arrow_with_change( 2906 pos_T *end_insert_pos, // can be NULL 2907 int end_change) // end undoable change 2908 { 2909 start_arrow_common(end_insert_pos, end_change); 2910 if (!end_change) 2911 { 2912 AppendCharToRedobuff(Ctrl_G); 2913 AppendCharToRedobuff('U'); 2914 } 2915 } 2916 2917 static void 2918 start_arrow_common( 2919 pos_T *end_insert_pos, // can be NULL 2920 int end_change) // end undoable change 2921 { 2922 if (!arrow_used && end_change) // something has been inserted 2923 { 2924 AppendToRedobuff(ESC_STR); 2925 stop_insert(end_insert_pos, FALSE, FALSE); 2926 arrow_used = TRUE; // this means we stopped the current insert 2927 } 2928 #ifdef FEAT_SPELL 2929 check_spell_redraw(); 2930 #endif 2931 } 2932 2933 #ifdef FEAT_SPELL 2934 /* 2935 * If we skipped highlighting word at cursor, do it now. 2936 * It may be skipped again, thus reset spell_redraw_lnum first. 2937 */ 2938 static void 2939 check_spell_redraw(void) 2940 { 2941 if (spell_redraw_lnum != 0) 2942 { 2943 linenr_T lnum = spell_redraw_lnum; 2944 2945 spell_redraw_lnum = 0; 2946 redrawWinline(curwin, lnum); 2947 } 2948 } 2949 2950 #endif 2951 2952 /* 2953 * stop_arrow() is called before a change is made in insert mode. 2954 * If an arrow key has been used, start a new insertion. 2955 * Returns FAIL if undo is impossible, shouldn't insert then. 2956 */ 2957 int 2958 stop_arrow(void) 2959 { 2960 if (arrow_used) 2961 { 2962 Insstart = curwin->w_cursor; // new insertion starts here 2963 if (Insstart.col > Insstart_orig.col && !ins_need_undo) 2964 // Don't update the original insert position when moved to the 2965 // right, except when nothing was inserted yet. 2966 update_Insstart_orig = FALSE; 2967 Insstart_textlen = (colnr_T)linetabsize(ml_get_curline()); 2968 2969 if (u_save_cursor() == OK) 2970 { 2971 arrow_used = FALSE; 2972 ins_need_undo = FALSE; 2973 } 2974 2975 ai_col = 0; 2976 if (State & VREPLACE_FLAG) 2977 { 2978 orig_line_count = curbuf->b_ml.ml_line_count; 2979 vr_lines_changed = 1; 2980 } 2981 ResetRedobuff(); 2982 AppendToRedobuff((char_u *)"1i"); // pretend we start an insertion 2983 new_insert_skip = 2; 2984 } 2985 else if (ins_need_undo) 2986 { 2987 if (u_save_cursor() == OK) 2988 ins_need_undo = FALSE; 2989 } 2990 2991 #ifdef FEAT_FOLDING 2992 // Always open fold at the cursor line when inserting something. 2993 foldOpenCursor(); 2994 #endif 2995 2996 return (arrow_used || ins_need_undo ? FAIL : OK); 2997 } 2998 2999 /* 3000 * Do a few things to stop inserting. 3001 * "end_insert_pos" is where insert ended. It is NULL when we already jumped 3002 * to another window/buffer. 3003 */ 3004 static void 3005 stop_insert( 3006 pos_T *end_insert_pos, 3007 int esc, // called by ins_esc() 3008 int nomove) // <c-\><c-o>, don't move cursor 3009 { 3010 int cc; 3011 char_u *ptr; 3012 3013 stop_redo_ins(); 3014 replace_flush(); // abandon replace stack 3015 3016 /* 3017 * Save the inserted text for later redo with ^@ and CTRL-A. 3018 * Don't do it when "restart_edit" was set and nothing was inserted, 3019 * otherwise CTRL-O w and then <Left> will clear "last_insert". 3020 */ 3021 ptr = get_inserted(); 3022 if (did_restart_edit == 0 || (ptr != NULL 3023 && (int)STRLEN(ptr) > new_insert_skip)) 3024 { 3025 vim_free(last_insert); 3026 last_insert = ptr; 3027 last_insert_skip = new_insert_skip; 3028 } 3029 else 3030 vim_free(ptr); 3031 3032 if (!arrow_used && end_insert_pos != NULL) 3033 { 3034 // Auto-format now. It may seem strange to do this when stopping an 3035 // insertion (or moving the cursor), but it's required when appending 3036 // a line and having it end in a space. But only do it when something 3037 // was actually inserted, otherwise undo won't work. 3038 if (!ins_need_undo && has_format_option(FO_AUTO)) 3039 { 3040 pos_T tpos = curwin->w_cursor; 3041 3042 // When the cursor is at the end of the line after a space the 3043 // formatting will move it to the following word. Avoid that by 3044 // moving the cursor onto the space. 3045 cc = 'x'; 3046 if (curwin->w_cursor.col > 0 && gchar_cursor() == NUL) 3047 { 3048 dec_cursor(); 3049 cc = gchar_cursor(); 3050 if (!VIM_ISWHITE(cc)) 3051 curwin->w_cursor = tpos; 3052 } 3053 3054 auto_format(TRUE, FALSE); 3055 3056 if (VIM_ISWHITE(cc)) 3057 { 3058 if (gchar_cursor() != NUL) 3059 inc_cursor(); 3060 // If the cursor is still at the same character, also keep 3061 // the "coladd". 3062 if (gchar_cursor() == NUL 3063 && curwin->w_cursor.lnum == tpos.lnum 3064 && curwin->w_cursor.col == tpos.col) 3065 curwin->w_cursor.coladd = tpos.coladd; 3066 } 3067 } 3068 3069 // If a space was inserted for auto-formatting, remove it now. 3070 check_auto_format(TRUE); 3071 3072 // If we just did an auto-indent, remove the white space from the end 3073 // of the line, and put the cursor back. 3074 // Do this when ESC was used or moving the cursor up/down. 3075 // Check for the old position still being valid, just in case the text 3076 // got changed unexpectedly. 3077 if (!nomove && did_ai && (esc || (vim_strchr(p_cpo, CPO_INDENT) == NULL 3078 && curwin->w_cursor.lnum != end_insert_pos->lnum)) 3079 && end_insert_pos->lnum <= curbuf->b_ml.ml_line_count) 3080 { 3081 pos_T tpos = curwin->w_cursor; 3082 3083 curwin->w_cursor = *end_insert_pos; 3084 check_cursor_col(); // make sure it is not past the line 3085 for (;;) 3086 { 3087 if (gchar_cursor() == NUL && curwin->w_cursor.col > 0) 3088 --curwin->w_cursor.col; 3089 cc = gchar_cursor(); 3090 if (!VIM_ISWHITE(cc)) 3091 break; 3092 if (del_char(TRUE) == FAIL) 3093 break; // should not happen 3094 } 3095 if (curwin->w_cursor.lnum != tpos.lnum) 3096 curwin->w_cursor = tpos; 3097 else 3098 { 3099 // reset tpos, could have been invalidated in the loop above 3100 tpos = curwin->w_cursor; 3101 tpos.col++; 3102 if (cc != NUL && gchar_pos(&tpos) == NUL) 3103 ++curwin->w_cursor.col; // put cursor back on the NUL 3104 } 3105 3106 // <C-S-Right> may have started Visual mode, adjust the position for 3107 // deleted characters. 3108 if (VIsual_active && VIsual.lnum == curwin->w_cursor.lnum) 3109 { 3110 int len = (int)STRLEN(ml_get_curline()); 3111 3112 if (VIsual.col > len) 3113 { 3114 VIsual.col = len; 3115 VIsual.coladd = 0; 3116 } 3117 } 3118 } 3119 } 3120 did_ai = FALSE; 3121 #ifdef FEAT_SMARTINDENT 3122 did_si = FALSE; 3123 can_si = FALSE; 3124 can_si_back = FALSE; 3125 #endif 3126 3127 // Set '[ and '] to the inserted text. When end_insert_pos is NULL we are 3128 // now in a different buffer. 3129 if (end_insert_pos != NULL) 3130 { 3131 curbuf->b_op_start = Insstart; 3132 curbuf->b_op_start_orig = Insstart_orig; 3133 curbuf->b_op_end = *end_insert_pos; 3134 } 3135 } 3136 3137 /* 3138 * Set the last inserted text to a single character. 3139 * Used for the replace command. 3140 */ 3141 void 3142 set_last_insert(int c) 3143 { 3144 char_u *s; 3145 3146 vim_free(last_insert); 3147 last_insert = alloc(MB_MAXBYTES * 3 + 5); 3148 if (last_insert != NULL) 3149 { 3150 s = last_insert; 3151 // Use the CTRL-V only when entering a special char 3152 if (c < ' ' || c == DEL) 3153 *s++ = Ctrl_V; 3154 s = add_char2buf(c, s); 3155 *s++ = ESC; 3156 *s++ = NUL; 3157 last_insert_skip = 0; 3158 } 3159 } 3160 3161 #if defined(EXITFREE) || defined(PROTO) 3162 void 3163 free_last_insert(void) 3164 { 3165 VIM_CLEAR(last_insert); 3166 } 3167 #endif 3168 3169 /* 3170 * Add character "c" to buffer "s". Escape the special meaning of K_SPECIAL 3171 * and CSI. Handle multi-byte characters. 3172 * Returns a pointer to after the added bytes. 3173 */ 3174 char_u * 3175 add_char2buf(int c, char_u *s) 3176 { 3177 char_u temp[MB_MAXBYTES + 1]; 3178 int i; 3179 int len; 3180 3181 len = (*mb_char2bytes)(c, temp); 3182 for (i = 0; i < len; ++i) 3183 { 3184 c = temp[i]; 3185 // Need to escape K_SPECIAL and CSI like in the typeahead buffer. 3186 if (c == K_SPECIAL) 3187 { 3188 *s++ = K_SPECIAL; 3189 *s++ = KS_SPECIAL; 3190 *s++ = KE_FILLER; 3191 } 3192 #ifdef FEAT_GUI 3193 else if (c == CSI) 3194 { 3195 *s++ = CSI; 3196 *s++ = KS_EXTRA; 3197 *s++ = (int)KE_CSI; 3198 } 3199 #endif 3200 else 3201 *s++ = c; 3202 } 3203 return s; 3204 } 3205 3206 /* 3207 * move cursor to start of line 3208 * if flags & BL_WHITE move to first non-white 3209 * if flags & BL_SOL move to first non-white if startofline is set, 3210 * otherwise keep "curswant" column 3211 * if flags & BL_FIX don't leave the cursor on a NUL. 3212 */ 3213 void 3214 beginline(int flags) 3215 { 3216 if ((flags & BL_SOL) && !p_sol) 3217 coladvance(curwin->w_curswant); 3218 else 3219 { 3220 curwin->w_cursor.col = 0; 3221 curwin->w_cursor.coladd = 0; 3222 3223 if (flags & (BL_WHITE | BL_SOL)) 3224 { 3225 char_u *ptr; 3226 3227 for (ptr = ml_get_curline(); VIM_ISWHITE(*ptr) 3228 && !((flags & BL_FIX) && ptr[1] == NUL); ++ptr) 3229 ++curwin->w_cursor.col; 3230 } 3231 curwin->w_set_curswant = TRUE; 3232 } 3233 } 3234 3235 /* 3236 * oneright oneleft cursor_down cursor_up 3237 * 3238 * Move one char {right,left,down,up}. 3239 * Doesn't move onto the NUL past the end of the line, unless it is allowed. 3240 * Return OK when successful, FAIL when we hit a line of file boundary. 3241 */ 3242 3243 int 3244 oneright(void) 3245 { 3246 char_u *ptr; 3247 int l; 3248 3249 if (virtual_active()) 3250 { 3251 pos_T prevpos = curwin->w_cursor; 3252 3253 // Adjust for multi-wide char (excluding TAB) 3254 ptr = ml_get_cursor(); 3255 coladvance(getviscol() + ((*ptr != TAB 3256 && vim_isprintc((*mb_ptr2char)(ptr))) 3257 ? ptr2cells(ptr) : 1)); 3258 curwin->w_set_curswant = TRUE; 3259 // Return OK if the cursor moved, FAIL otherwise (at window edge). 3260 return (prevpos.col != curwin->w_cursor.col 3261 || prevpos.coladd != curwin->w_cursor.coladd) ? OK : FAIL; 3262 } 3263 3264 ptr = ml_get_cursor(); 3265 if (*ptr == NUL) 3266 return FAIL; // already at the very end 3267 3268 if (has_mbyte) 3269 l = (*mb_ptr2len)(ptr); 3270 else 3271 l = 1; 3272 3273 // move "l" bytes right, but don't end up on the NUL, unless 'virtualedit' 3274 // contains "onemore". 3275 if (ptr[l] == NUL && (ve_flags & VE_ONEMORE) == 0) 3276 return FAIL; 3277 curwin->w_cursor.col += l; 3278 3279 curwin->w_set_curswant = TRUE; 3280 return OK; 3281 } 3282 3283 int 3284 oneleft(void) 3285 { 3286 if (virtual_active()) 3287 { 3288 #ifdef FEAT_LINEBREAK 3289 int width; 3290 #endif 3291 int v = getviscol(); 3292 3293 if (v == 0) 3294 return FAIL; 3295 3296 #ifdef FEAT_LINEBREAK 3297 // We might get stuck on 'showbreak', skip over it. 3298 width = 1; 3299 for (;;) 3300 { 3301 coladvance(v - width); 3302 // getviscol() is slow, skip it when 'showbreak' is empty, 3303 // 'breakindent' is not set and there are no multi-byte 3304 // characters 3305 if ((*get_showbreak_value(curwin) == NUL && !curwin->w_p_bri 3306 && !has_mbyte) || getviscol() < v) 3307 break; 3308 ++width; 3309 } 3310 #else 3311 coladvance(v - 1); 3312 #endif 3313 3314 if (curwin->w_cursor.coladd == 1) 3315 { 3316 char_u *ptr; 3317 3318 // Adjust for multi-wide char (not a TAB) 3319 ptr = ml_get_cursor(); 3320 if (*ptr != TAB && vim_isprintc((*mb_ptr2char)(ptr)) 3321 && ptr2cells(ptr) > 1) 3322 curwin->w_cursor.coladd = 0; 3323 } 3324 3325 curwin->w_set_curswant = TRUE; 3326 return OK; 3327 } 3328 3329 if (curwin->w_cursor.col == 0) 3330 return FAIL; 3331 3332 curwin->w_set_curswant = TRUE; 3333 --curwin->w_cursor.col; 3334 3335 // if the character on the left of the current cursor is a multi-byte 3336 // character, move to its first byte 3337 if (has_mbyte) 3338 mb_adjust_cursor(); 3339 return OK; 3340 } 3341 3342 int 3343 cursor_up( 3344 long n, 3345 int upd_topline) // When TRUE: update topline 3346 { 3347 linenr_T lnum; 3348 3349 if (n > 0) 3350 { 3351 lnum = curwin->w_cursor.lnum; 3352 // This fails if the cursor is already in the first line or the count 3353 // is larger than the line number and '-' is in 'cpoptions' 3354 if (lnum <= 1 || (n >= lnum && vim_strchr(p_cpo, CPO_MINUS) != NULL)) 3355 return FAIL; 3356 if (n >= lnum) 3357 lnum = 1; 3358 else 3359 #ifdef FEAT_FOLDING 3360 if (hasAnyFolding(curwin)) 3361 { 3362 /* 3363 * Count each sequence of folded lines as one logical line. 3364 */ 3365 // go to the start of the current fold 3366 (void)hasFolding(lnum, &lnum, NULL); 3367 3368 while (n--) 3369 { 3370 // move up one line 3371 --lnum; 3372 if (lnum <= 1) 3373 break; 3374 // If we entered a fold, move to the beginning, unless in 3375 // Insert mode or when 'foldopen' contains "all": it will open 3376 // in a moment. 3377 if (n > 0 || !((State & INSERT) || (fdo_flags & FDO_ALL))) 3378 (void)hasFolding(lnum, &lnum, NULL); 3379 } 3380 if (lnum < 1) 3381 lnum = 1; 3382 } 3383 else 3384 #endif 3385 lnum -= n; 3386 curwin->w_cursor.lnum = lnum; 3387 } 3388 3389 // try to advance to the column we want to be at 3390 coladvance(curwin->w_curswant); 3391 3392 if (upd_topline) 3393 update_topline(); // make sure curwin->w_topline is valid 3394 3395 return OK; 3396 } 3397 3398 /* 3399 * Cursor down a number of logical lines. 3400 */ 3401 int 3402 cursor_down( 3403 long n, 3404 int upd_topline) // When TRUE: update topline 3405 { 3406 linenr_T lnum; 3407 3408 if (n > 0) 3409 { 3410 lnum = curwin->w_cursor.lnum; 3411 #ifdef FEAT_FOLDING 3412 // Move to last line of fold, will fail if it's the end-of-file. 3413 (void)hasFolding(lnum, NULL, &lnum); 3414 #endif 3415 // This fails if the cursor is already in the last line or would move 3416 // beyond the last line and '-' is in 'cpoptions' 3417 if (lnum >= curbuf->b_ml.ml_line_count 3418 || (lnum + n > curbuf->b_ml.ml_line_count 3419 && vim_strchr(p_cpo, CPO_MINUS) != NULL)) 3420 return FAIL; 3421 if (lnum + n >= curbuf->b_ml.ml_line_count) 3422 lnum = curbuf->b_ml.ml_line_count; 3423 else 3424 #ifdef FEAT_FOLDING 3425 if (hasAnyFolding(curwin)) 3426 { 3427 linenr_T last; 3428 3429 // count each sequence of folded lines as one logical line 3430 while (n--) 3431 { 3432 if (hasFolding(lnum, NULL, &last)) 3433 lnum = last + 1; 3434 else 3435 ++lnum; 3436 if (lnum >= curbuf->b_ml.ml_line_count) 3437 break; 3438 } 3439 if (lnum > curbuf->b_ml.ml_line_count) 3440 lnum = curbuf->b_ml.ml_line_count; 3441 } 3442 else 3443 #endif 3444 lnum += n; 3445 curwin->w_cursor.lnum = lnum; 3446 } 3447 3448 // try to advance to the column we want to be at 3449 coladvance(curwin->w_curswant); 3450 3451 if (upd_topline) 3452 update_topline(); // make sure curwin->w_topline is valid 3453 3454 return OK; 3455 } 3456 3457 /* 3458 * Stuff the last inserted text in the read buffer. 3459 * Last_insert actually is a copy of the redo buffer, so we 3460 * first have to remove the command. 3461 */ 3462 int 3463 stuff_inserted( 3464 int c, // Command character to be inserted 3465 long count, // Repeat this many times 3466 int no_esc) // Don't add an ESC at the end 3467 { 3468 char_u *esc_ptr; 3469 char_u *ptr; 3470 char_u *last_ptr; 3471 char_u last = NUL; 3472 3473 ptr = get_last_insert(); 3474 if (ptr == NULL) 3475 { 3476 emsg(_(e_noinstext)); 3477 return FAIL; 3478 } 3479 3480 // may want to stuff the command character, to start Insert mode 3481 if (c != NUL) 3482 stuffcharReadbuff(c); 3483 if ((esc_ptr = (char_u *)vim_strrchr(ptr, ESC)) != NULL) 3484 *esc_ptr = NUL; // remove the ESC 3485 3486 // when the last char is either "0" or "^" it will be quoted if no ESC 3487 // comes after it OR if it will inserted more than once and "ptr" 3488 // starts with ^D. -- Acevedo 3489 last_ptr = (esc_ptr ? esc_ptr : ptr + STRLEN(ptr)) - 1; 3490 if (last_ptr >= ptr && (*last_ptr == '0' || *last_ptr == '^') 3491 && (no_esc || (*ptr == Ctrl_D && count > 1))) 3492 { 3493 last = *last_ptr; 3494 *last_ptr = NUL; 3495 } 3496 3497 do 3498 { 3499 stuffReadbuff(ptr); 3500 // a trailing "0" is inserted as "<C-V>048", "^" as "<C-V>^" 3501 if (last) 3502 stuffReadbuff((char_u *)(last == '0' 3503 ? IF_EB("\026\060\064\070", CTRL_V_STR "xf0") 3504 : IF_EB("\026^", CTRL_V_STR "^"))); 3505 } 3506 while (--count > 0); 3507 3508 if (last) 3509 *last_ptr = last; 3510 3511 if (esc_ptr != NULL) 3512 *esc_ptr = ESC; // put the ESC back 3513 3514 // may want to stuff a trailing ESC, to get out of Insert mode 3515 if (!no_esc) 3516 stuffcharReadbuff(ESC); 3517 3518 return OK; 3519 } 3520 3521 char_u * 3522 get_last_insert(void) 3523 { 3524 if (last_insert == NULL) 3525 return NULL; 3526 return last_insert + last_insert_skip; 3527 } 3528 3529 /* 3530 * Get last inserted string, and remove trailing <Esc>. 3531 * Returns pointer to allocated memory (must be freed) or NULL. 3532 */ 3533 char_u * 3534 get_last_insert_save(void) 3535 { 3536 char_u *s; 3537 int len; 3538 3539 if (last_insert == NULL) 3540 return NULL; 3541 s = vim_strsave(last_insert + last_insert_skip); 3542 if (s != NULL) 3543 { 3544 len = (int)STRLEN(s); 3545 if (len > 0 && s[len - 1] == ESC) // remove trailing ESC 3546 s[len - 1] = NUL; 3547 } 3548 return s; 3549 } 3550 3551 /* 3552 * Check the word in front of the cursor for an abbreviation. 3553 * Called when the non-id character "c" has been entered. 3554 * When an abbreviation is recognized it is removed from the text and 3555 * the replacement string is inserted in typebuf.tb_buf[], followed by "c". 3556 */ 3557 static int 3558 echeck_abbr(int c) 3559 { 3560 // Don't check for abbreviation in paste mode, when disabled and just 3561 // after moving around with cursor keys. 3562 if (p_paste || no_abbr || arrow_used) 3563 return FALSE; 3564 3565 return check_abbr(c, ml_get_curline(), curwin->w_cursor.col, 3566 curwin->w_cursor.lnum == Insstart.lnum ? Insstart.col : 0); 3567 } 3568 3569 /* 3570 * replace-stack functions 3571 * 3572 * When replacing characters, the replaced characters are remembered for each 3573 * new character. This is used to re-insert the old text when backspacing. 3574 * 3575 * There is a NUL headed list of characters for each character that is 3576 * currently in the file after the insertion point. When BS is used, one NUL 3577 * headed list is put back for the deleted character. 3578 * 3579 * For a newline, there are two NUL headed lists. One contains the characters 3580 * that the NL replaced. The extra one stores the characters after the cursor 3581 * that were deleted (always white space). 3582 * 3583 * Replace_offset is normally 0, in which case replace_push will add a new 3584 * character at the end of the stack. If replace_offset is not 0, that many 3585 * characters will be left on the stack above the newly inserted character. 3586 */ 3587 3588 static char_u *replace_stack = NULL; 3589 static long replace_stack_nr = 0; // next entry in replace stack 3590 static long replace_stack_len = 0; // max. number of entries 3591 3592 void 3593 replace_push( 3594 int c) // character that is replaced (NUL is none) 3595 { 3596 char_u *p; 3597 3598 if (replace_stack_nr < replace_offset) // nothing to do 3599 return; 3600 if (replace_stack_len <= replace_stack_nr) 3601 { 3602 replace_stack_len += 50; 3603 p = ALLOC_MULT(char_u, replace_stack_len); 3604 if (p == NULL) // out of memory 3605 { 3606 replace_stack_len -= 50; 3607 return; 3608 } 3609 if (replace_stack != NULL) 3610 { 3611 mch_memmove(p, replace_stack, 3612 (size_t)(replace_stack_nr * sizeof(char_u))); 3613 vim_free(replace_stack); 3614 } 3615 replace_stack = p; 3616 } 3617 p = replace_stack + replace_stack_nr - replace_offset; 3618 if (replace_offset) 3619 mch_memmove(p + 1, p, (size_t)(replace_offset * sizeof(char_u))); 3620 *p = c; 3621 ++replace_stack_nr; 3622 } 3623 3624 /* 3625 * Push a character onto the replace stack. Handles a multi-byte character in 3626 * reverse byte order, so that the first byte is popped off first. 3627 * Return the number of bytes done (includes composing characters). 3628 */ 3629 int 3630 replace_push_mb(char_u *p) 3631 { 3632 int l = (*mb_ptr2len)(p); 3633 int j; 3634 3635 for (j = l - 1; j >= 0; --j) 3636 replace_push(p[j]); 3637 return l; 3638 } 3639 3640 /* 3641 * Pop one item from the replace stack. 3642 * return -1 if stack empty 3643 * return replaced character or NUL otherwise 3644 */ 3645 static int 3646 replace_pop(void) 3647 { 3648 if (replace_stack_nr == 0) 3649 return -1; 3650 return (int)replace_stack[--replace_stack_nr]; 3651 } 3652 3653 /* 3654 * Join the top two items on the replace stack. This removes to "off"'th NUL 3655 * encountered. 3656 */ 3657 void 3658 replace_join( 3659 int off) // offset for which NUL to remove 3660 { 3661 int i; 3662 3663 for (i = replace_stack_nr; --i >= 0; ) 3664 if (replace_stack[i] == NUL && off-- <= 0) 3665 { 3666 --replace_stack_nr; 3667 mch_memmove(replace_stack + i, replace_stack + i + 1, 3668 (size_t)(replace_stack_nr - i)); 3669 return; 3670 } 3671 } 3672 3673 /* 3674 * Pop bytes from the replace stack until a NUL is found, and insert them 3675 * before the cursor. Can only be used in REPLACE or VREPLACE mode. 3676 */ 3677 static void 3678 replace_pop_ins(void) 3679 { 3680 int cc; 3681 int oldState = State; 3682 3683 State = NORMAL; // don't want REPLACE here 3684 while ((cc = replace_pop()) > 0) 3685 { 3686 mb_replace_pop_ins(cc); 3687 dec_cursor(); 3688 } 3689 State = oldState; 3690 } 3691 3692 /* 3693 * Insert bytes popped from the replace stack. "cc" is the first byte. If it 3694 * indicates a multi-byte char, pop the other bytes too. 3695 */ 3696 static void 3697 mb_replace_pop_ins(int cc) 3698 { 3699 int n; 3700 char_u buf[MB_MAXBYTES + 1]; 3701 int i; 3702 int c; 3703 3704 if (has_mbyte && (n = MB_BYTE2LEN(cc)) > 1) 3705 { 3706 buf[0] = cc; 3707 for (i = 1; i < n; ++i) 3708 buf[i] = replace_pop(); 3709 ins_bytes_len(buf, n); 3710 } 3711 else 3712 ins_char(cc); 3713 3714 if (enc_utf8) 3715 // Handle composing chars. 3716 for (;;) 3717 { 3718 c = replace_pop(); 3719 if (c == -1) // stack empty 3720 break; 3721 if ((n = MB_BYTE2LEN(c)) == 1) 3722 { 3723 // Not a multi-byte char, put it back. 3724 replace_push(c); 3725 break; 3726 } 3727 else 3728 { 3729 buf[0] = c; 3730 for (i = 1; i < n; ++i) 3731 buf[i] = replace_pop(); 3732 if (utf_iscomposing(utf_ptr2char(buf))) 3733 ins_bytes_len(buf, n); 3734 else 3735 { 3736 // Not a composing char, put it back. 3737 for (i = n - 1; i >= 0; --i) 3738 replace_push(buf[i]); 3739 break; 3740 } 3741 } 3742 } 3743 } 3744 3745 /* 3746 * make the replace stack empty 3747 * (called when exiting replace mode) 3748 */ 3749 static void 3750 replace_flush(void) 3751 { 3752 VIM_CLEAR(replace_stack); 3753 replace_stack_len = 0; 3754 replace_stack_nr = 0; 3755 } 3756 3757 /* 3758 * Handle doing a BS for one character. 3759 * cc < 0: replace stack empty, just move cursor 3760 * cc == 0: character was inserted, delete it 3761 * cc > 0: character was replaced, put cc (first byte of original char) back 3762 * and check for more characters to be put back 3763 * When "limit_col" is >= 0, don't delete before this column. Matters when 3764 * using composing characters, use del_char_after_col() instead of del_char(). 3765 */ 3766 static void 3767 replace_do_bs(int limit_col) 3768 { 3769 int cc; 3770 int orig_len = 0; 3771 int ins_len; 3772 int orig_vcols = 0; 3773 colnr_T start_vcol; 3774 char_u *p; 3775 int i; 3776 int vcol; 3777 3778 cc = replace_pop(); 3779 if (cc > 0) 3780 { 3781 #ifdef FEAT_PROP_POPUP 3782 size_t len_before = 0; // init to shut up GCC 3783 3784 if (curbuf->b_has_textprop) 3785 { 3786 // Do not adjust text properties for individual delete and insert 3787 // operations, do it afterwards on the resulting text. 3788 len_before = STRLEN(ml_get_curline()); 3789 ++text_prop_frozen; 3790 } 3791 #endif 3792 if (State & VREPLACE_FLAG) 3793 { 3794 // Get the number of screen cells used by the character we are 3795 // going to delete. 3796 getvcol(curwin, &curwin->w_cursor, NULL, &start_vcol, NULL); 3797 orig_vcols = chartabsize(ml_get_cursor(), start_vcol); 3798 } 3799 if (has_mbyte) 3800 { 3801 (void)del_char_after_col(limit_col); 3802 if (State & VREPLACE_FLAG) 3803 orig_len = (int)STRLEN(ml_get_cursor()); 3804 replace_push(cc); 3805 } 3806 else 3807 { 3808 pchar_cursor(cc); 3809 if (State & VREPLACE_FLAG) 3810 orig_len = (int)STRLEN(ml_get_cursor()) - 1; 3811 } 3812 replace_pop_ins(); 3813 3814 if (State & VREPLACE_FLAG) 3815 { 3816 // Get the number of screen cells used by the inserted characters 3817 p = ml_get_cursor(); 3818 ins_len = (int)STRLEN(p) - orig_len; 3819 vcol = start_vcol; 3820 for (i = 0; i < ins_len; ++i) 3821 { 3822 vcol += chartabsize(p + i, vcol); 3823 i += (*mb_ptr2len)(p) - 1; 3824 } 3825 vcol -= start_vcol; 3826 3827 // Delete spaces that were inserted after the cursor to keep the 3828 // text aligned. 3829 curwin->w_cursor.col += ins_len; 3830 while (vcol > orig_vcols && gchar_cursor() == ' ') 3831 { 3832 del_char(FALSE); 3833 ++orig_vcols; 3834 } 3835 curwin->w_cursor.col -= ins_len; 3836 } 3837 3838 // mark the buffer as changed and prepare for displaying 3839 changed_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col); 3840 3841 #ifdef FEAT_PROP_POPUP 3842 if (curbuf->b_has_textprop) 3843 { 3844 size_t len_now = STRLEN(ml_get_curline()); 3845 3846 --text_prop_frozen; 3847 adjust_prop_columns(curwin->w_cursor.lnum, curwin->w_cursor.col, 3848 (int)(len_now - len_before), 0); 3849 } 3850 #endif 3851 } 3852 else if (cc == 0) 3853 (void)del_char_after_col(limit_col); 3854 } 3855 3856 #if defined(FEAT_RIGHTLEFT) || defined(PROTO) 3857 /* 3858 * Map Hebrew keyboard when in hkmap mode. 3859 */ 3860 int 3861 hkmap(int c) 3862 { 3863 if (p_hkmapp) // phonetic mapping, by Ilya Dogolazky 3864 { 3865 enum {hALEF=0, BET, GIMEL, DALET, HEI, VAV, ZAIN, HET, TET, IUD, 3866 KAFsofit, hKAF, LAMED, MEMsofit, MEM, NUNsofit, NUN, SAMEH, AIN, 3867 PEIsofit, PEI, ZADIsofit, ZADI, KOF, RESH, hSHIN, TAV}; 3868 static char_u map[26] = 3869 {(char_u)hALEF/*a*/, (char_u)BET /*b*/, (char_u)hKAF /*c*/, 3870 (char_u)DALET/*d*/, (char_u)-1 /*e*/, (char_u)PEIsofit/*f*/, 3871 (char_u)GIMEL/*g*/, (char_u)HEI /*h*/, (char_u)IUD /*i*/, 3872 (char_u)HET /*j*/, (char_u)KOF /*k*/, (char_u)LAMED /*l*/, 3873 (char_u)MEM /*m*/, (char_u)NUN /*n*/, (char_u)SAMEH /*o*/, 3874 (char_u)PEI /*p*/, (char_u)-1 /*q*/, (char_u)RESH /*r*/, 3875 (char_u)ZAIN /*s*/, (char_u)TAV /*t*/, (char_u)TET /*u*/, 3876 (char_u)VAV /*v*/, (char_u)hSHIN/*w*/, (char_u)-1 /*x*/, 3877 (char_u)AIN /*y*/, (char_u)ZADI /*z*/}; 3878 3879 if (c == 'N' || c == 'M' || c == 'P' || c == 'C' || c == 'Z') 3880 return (int)(map[CharOrd(c)] - 1 + p_aleph); 3881 // '-1'='sofit' 3882 else if (c == 'x') 3883 return 'X'; 3884 else if (c == 'q') 3885 return '\''; // {geresh}={'} 3886 else if (c == 246) 3887 return ' '; // \"o --> ' ' for a german keyboard 3888 else if (c == 228) 3889 return ' '; // \"a --> ' ' -- / -- 3890 else if (c == 252) 3891 return ' '; // \"u --> ' ' -- / -- 3892 #ifdef EBCDIC 3893 else if (islower(c)) 3894 #else 3895 // NOTE: islower() does not do the right thing for us on Linux so we 3896 // do this the same was as 5.7 and previous, so it works correctly on 3897 // all systems. Specifically, the e.g. Delete and Arrow keys are 3898 // munged and won't work if e.g. searching for Hebrew text. 3899 else if (c >= 'a' && c <= 'z') 3900 #endif 3901 return (int)(map[CharOrdLow(c)] + p_aleph); 3902 else 3903 return c; 3904 } 3905 else 3906 { 3907 switch (c) 3908 { 3909 case '`': return ';'; 3910 case '/': return '.'; 3911 case '\'': return ','; 3912 case 'q': return '/'; 3913 case 'w': return '\''; 3914 3915 // Hebrew letters - set offset from 'a' 3916 case ',': c = '{'; break; 3917 case '.': c = 'v'; break; 3918 case ';': c = 't'; break; 3919 default: { 3920 static char str[] = "zqbcxlsjphmkwonu ydafe rig"; 3921 3922 #ifdef EBCDIC 3923 // see note about islower() above 3924 if (!islower(c)) 3925 #else 3926 if (c < 'a' || c > 'z') 3927 #endif 3928 return c; 3929 c = str[CharOrdLow(c)]; 3930 break; 3931 } 3932 } 3933 3934 return (int)(CharOrdLow(c) + p_aleph); 3935 } 3936 } 3937 #endif 3938 3939 static void 3940 ins_reg(void) 3941 { 3942 int need_redraw = FALSE; 3943 int regname; 3944 int literally = 0; 3945 int vis_active = VIsual_active; 3946 3947 /* 3948 * If we are going to wait for a character, show a '"'. 3949 */ 3950 pc_status = PC_STATUS_UNSET; 3951 if (redrawing() && !char_avail()) 3952 { 3953 // may need to redraw when no more chars available now 3954 ins_redraw(FALSE); 3955 3956 edit_putchar('"', TRUE); 3957 #ifdef FEAT_CMDL_INFO 3958 add_to_showcmd_c(Ctrl_R); 3959 #endif 3960 } 3961 3962 #ifdef USE_ON_FLY_SCROLL 3963 dont_scroll = TRUE; // disallow scrolling here 3964 #endif 3965 3966 /* 3967 * Don't map the register name. This also prevents the mode message to be 3968 * deleted when ESC is hit. 3969 */ 3970 ++no_mapping; 3971 ++allow_keys; 3972 regname = plain_vgetc(); 3973 LANGMAP_ADJUST(regname, TRUE); 3974 if (regname == Ctrl_R || regname == Ctrl_O || regname == Ctrl_P) 3975 { 3976 // Get a third key for literal register insertion 3977 literally = regname; 3978 #ifdef FEAT_CMDL_INFO 3979 add_to_showcmd_c(literally); 3980 #endif 3981 regname = plain_vgetc(); 3982 LANGMAP_ADJUST(regname, TRUE); 3983 } 3984 --no_mapping; 3985 --allow_keys; 3986 3987 #ifdef FEAT_EVAL 3988 // Don't call u_sync() while typing the expression or giving an error 3989 // message for it. Only call it explicitly. 3990 ++no_u_sync; 3991 if (regname == '=') 3992 { 3993 pos_T curpos = curwin->w_cursor; 3994 # ifdef HAVE_INPUT_METHOD 3995 int im_on = im_get_status(); 3996 # endif 3997 // Sync undo when evaluating the expression calls setline() or 3998 // append(), so that it can be undone separately. 3999 u_sync_once = 2; 4000 4001 regname = get_expr_register(); 4002 4003 // Cursor may be moved back a column. 4004 curwin->w_cursor = curpos; 4005 check_cursor(); 4006 # ifdef HAVE_INPUT_METHOD 4007 // Restore the Input Method. 4008 if (im_on) 4009 im_set_active(TRUE); 4010 # endif 4011 } 4012 if (regname == NUL || !valid_yank_reg(regname, FALSE)) 4013 { 4014 vim_beep(BO_REG); 4015 need_redraw = TRUE; // remove the '"' 4016 } 4017 else 4018 { 4019 #endif 4020 if (literally == Ctrl_O || literally == Ctrl_P) 4021 { 4022 // Append the command to the redo buffer. 4023 AppendCharToRedobuff(Ctrl_R); 4024 AppendCharToRedobuff(literally); 4025 AppendCharToRedobuff(regname); 4026 4027 do_put(regname, BACKWARD, 1L, 4028 (literally == Ctrl_P ? PUT_FIXINDENT : 0) | PUT_CURSEND); 4029 } 4030 else if (insert_reg(regname, literally) == FAIL) 4031 { 4032 vim_beep(BO_REG); 4033 need_redraw = TRUE; // remove the '"' 4034 } 4035 else if (stop_insert_mode) 4036 // When the '=' register was used and a function was invoked that 4037 // did ":stopinsert" then stuff_empty() returns FALSE but we won't 4038 // insert anything, need to remove the '"' 4039 need_redraw = TRUE; 4040 4041 #ifdef FEAT_EVAL 4042 } 4043 --no_u_sync; 4044 if (u_sync_once == 1) 4045 ins_need_undo = TRUE; 4046 u_sync_once = 0; 4047 #endif 4048 #ifdef FEAT_CMDL_INFO 4049 clear_showcmd(); 4050 #endif 4051 4052 // If the inserted register is empty, we need to remove the '"' 4053 if (need_redraw || stuff_empty()) 4054 edit_unputchar(); 4055 4056 // Disallow starting Visual mode here, would get a weird mode. 4057 if (!vis_active && VIsual_active) 4058 end_visual_mode(); 4059 } 4060 4061 /* 4062 * CTRL-G commands in Insert mode. 4063 */ 4064 static void 4065 ins_ctrl_g(void) 4066 { 4067 int c; 4068 4069 // Right after CTRL-X the cursor will be after the ruler. 4070 setcursor(); 4071 4072 /* 4073 * Don't map the second key. This also prevents the mode message to be 4074 * deleted when ESC is hit. 4075 */ 4076 ++no_mapping; 4077 ++allow_keys; 4078 c = plain_vgetc(); 4079 --no_mapping; 4080 --allow_keys; 4081 switch (c) 4082 { 4083 // CTRL-G k and CTRL-G <Up>: cursor up to Insstart.col 4084 case K_UP: 4085 case Ctrl_K: 4086 case 'k': ins_up(TRUE); 4087 break; 4088 4089 // CTRL-G j and CTRL-G <Down>: cursor down to Insstart.col 4090 case K_DOWN: 4091 case Ctrl_J: 4092 case 'j': ins_down(TRUE); 4093 break; 4094 4095 // CTRL-G u: start new undoable edit 4096 case 'u': u_sync(TRUE); 4097 ins_need_undo = TRUE; 4098 4099 // Need to reset Insstart, esp. because a BS that joins 4100 // a line to the previous one must save for undo. 4101 update_Insstart_orig = FALSE; 4102 Insstart = curwin->w_cursor; 4103 break; 4104 4105 // CTRL-G U: do not break undo with the next char 4106 case 'U': 4107 // Allow one left/right cursor movement with the next char, 4108 // without breaking undo. 4109 dont_sync_undo = MAYBE; 4110 break; 4111 4112 // Unknown CTRL-G command, reserved for future expansion. 4113 default: vim_beep(BO_CTRLG); 4114 } 4115 } 4116 4117 /* 4118 * CTRL-^ in Insert mode. 4119 */ 4120 static void 4121 ins_ctrl_hat(void) 4122 { 4123 if (map_to_exists_mode((char_u *)"", LANGMAP, FALSE)) 4124 { 4125 // ":lmap" mappings exists, Toggle use of ":lmap" mappings. 4126 if (State & LANGMAP) 4127 { 4128 curbuf->b_p_iminsert = B_IMODE_NONE; 4129 State &= ~LANGMAP; 4130 } 4131 else 4132 { 4133 curbuf->b_p_iminsert = B_IMODE_LMAP; 4134 State |= LANGMAP; 4135 #ifdef HAVE_INPUT_METHOD 4136 im_set_active(FALSE); 4137 #endif 4138 } 4139 } 4140 #ifdef HAVE_INPUT_METHOD 4141 else 4142 { 4143 // There are no ":lmap" mappings, toggle IM 4144 if (im_get_status()) 4145 { 4146 curbuf->b_p_iminsert = B_IMODE_NONE; 4147 im_set_active(FALSE); 4148 } 4149 else 4150 { 4151 curbuf->b_p_iminsert = B_IMODE_IM; 4152 State &= ~LANGMAP; 4153 im_set_active(TRUE); 4154 } 4155 } 4156 #endif 4157 set_iminsert_global(); 4158 showmode(); 4159 #ifdef FEAT_GUI 4160 // may show different cursor shape or color 4161 if (gui.in_use) 4162 gui_update_cursor(TRUE, FALSE); 4163 #endif 4164 #if defined(FEAT_KEYMAP) 4165 // Show/unshow value of 'keymap' in status lines. 4166 status_redraw_curbuf(); 4167 #endif 4168 } 4169 4170 /* 4171 * Handle ESC in insert mode. 4172 * Returns TRUE when leaving insert mode, FALSE when going to repeat the 4173 * insert. 4174 */ 4175 static int 4176 ins_esc( 4177 long *count, 4178 int cmdchar, 4179 int nomove) // don't move cursor 4180 { 4181 int temp; 4182 static int disabled_redraw = FALSE; 4183 4184 #ifdef FEAT_SPELL 4185 check_spell_redraw(); 4186 #endif 4187 4188 temp = curwin->w_cursor.col; 4189 if (disabled_redraw) 4190 { 4191 --RedrawingDisabled; 4192 disabled_redraw = FALSE; 4193 } 4194 if (!arrow_used) 4195 { 4196 /* 4197 * Don't append the ESC for "r<CR>" and "grx". 4198 * When 'insertmode' is set only CTRL-L stops Insert mode. Needed for 4199 * when "count" is non-zero. 4200 */ 4201 if (cmdchar != 'r' && cmdchar != 'v') 4202 AppendToRedobuff(p_im ? (char_u *)"\014" : ESC_STR); 4203 4204 /* 4205 * Repeating insert may take a long time. Check for 4206 * interrupt now and then. 4207 */ 4208 if (*count > 0) 4209 { 4210 line_breakcheck(); 4211 if (got_int) 4212 *count = 0; 4213 } 4214 4215 if (--*count > 0) // repeat what was typed 4216 { 4217 // Vi repeats the insert without replacing characters. 4218 if (vim_strchr(p_cpo, CPO_REPLCNT) != NULL) 4219 State &= ~REPLACE_FLAG; 4220 4221 (void)start_redo_ins(); 4222 if (cmdchar == 'r' || cmdchar == 'v') 4223 stuffRedoReadbuff(ESC_STR); // no ESC in redo buffer 4224 ++RedrawingDisabled; 4225 disabled_redraw = TRUE; 4226 return FALSE; // repeat the insert 4227 } 4228 stop_insert(&curwin->w_cursor, TRUE, nomove); 4229 undisplay_dollar(); 4230 } 4231 4232 // When an autoindent was removed, curswant stays after the 4233 // indent 4234 if (restart_edit == NUL && (colnr_T)temp == curwin->w_cursor.col) 4235 curwin->w_set_curswant = TRUE; 4236 4237 // Remember the last Insert position in the '^ mark. 4238 if (!cmdmod.keepjumps) 4239 curbuf->b_last_insert = curwin->w_cursor; 4240 4241 /* 4242 * The cursor should end up on the last inserted character. 4243 * Don't do it for CTRL-O, unless past the end of the line. 4244 */ 4245 if (!nomove 4246 && (curwin->w_cursor.col != 0 4247 || curwin->w_cursor.coladd > 0) 4248 && (restart_edit == NUL 4249 || (gchar_cursor() == NUL && !VIsual_active)) 4250 #ifdef FEAT_RIGHTLEFT 4251 && !revins_on 4252 #endif 4253 ) 4254 { 4255 if (curwin->w_cursor.coladd > 0 || ve_flags == VE_ALL) 4256 { 4257 oneleft(); 4258 if (restart_edit != NUL) 4259 ++curwin->w_cursor.coladd; 4260 } 4261 else 4262 { 4263 --curwin->w_cursor.col; 4264 // Correct cursor for multi-byte character. 4265 if (has_mbyte) 4266 mb_adjust_cursor(); 4267 } 4268 } 4269 4270 #ifdef HAVE_INPUT_METHOD 4271 // Disable IM to allow typing English directly for Normal mode commands. 4272 // When ":lmap" is enabled don't change 'iminsert' (IM can be enabled as 4273 // well). 4274 if (!(State & LANGMAP)) 4275 im_save_status(&curbuf->b_p_iminsert); 4276 im_set_active(FALSE); 4277 #endif 4278 4279 State = NORMAL; 4280 // need to position cursor again (e.g. when on a TAB ) 4281 changed_cline_bef_curs(); 4282 4283 setmouse(); 4284 #ifdef CURSOR_SHAPE 4285 ui_cursor_shape(); // may show different cursor shape 4286 #endif 4287 if (!p_ek) 4288 { 4289 // Re-enable bracketed paste mode. 4290 out_str(T_BE); 4291 4292 // Re-enable modifyOtherKeys. 4293 out_str(T_CTI); 4294 } 4295 4296 // When recording or for CTRL-O, need to display the new mode. 4297 // Otherwise remove the mode message. 4298 if (reg_recording != 0 || restart_edit != NUL) 4299 showmode(); 4300 else if (p_smd && (got_int || !skip_showmode())) 4301 msg(""); 4302 4303 return TRUE; // exit Insert mode 4304 } 4305 4306 #ifdef FEAT_RIGHTLEFT 4307 /* 4308 * Toggle language: hkmap and revins_on. 4309 * Move to end of reverse inserted text. 4310 */ 4311 static void 4312 ins_ctrl_(void) 4313 { 4314 if (revins_on && revins_chars && revins_scol >= 0) 4315 { 4316 while (gchar_cursor() != NUL && revins_chars--) 4317 ++curwin->w_cursor.col; 4318 } 4319 p_ri = !p_ri; 4320 revins_on = (State == INSERT && p_ri); 4321 if (revins_on) 4322 { 4323 revins_scol = curwin->w_cursor.col; 4324 revins_legal++; 4325 revins_chars = 0; 4326 undisplay_dollar(); 4327 } 4328 else 4329 revins_scol = -1; 4330 p_hkmap = curwin->w_p_rl ^ p_ri; // be consistent! 4331 showmode(); 4332 } 4333 #endif 4334 4335 /* 4336 * If 'keymodel' contains "startsel", may start selection. 4337 * Returns TRUE when a CTRL-O and other keys stuffed. 4338 */ 4339 static int 4340 ins_start_select(int c) 4341 { 4342 if (km_startsel) 4343 switch (c) 4344 { 4345 case K_KHOME: 4346 case K_KEND: 4347 case K_PAGEUP: 4348 case K_KPAGEUP: 4349 case K_PAGEDOWN: 4350 case K_KPAGEDOWN: 4351 # ifdef MACOS_X 4352 case K_LEFT: 4353 case K_RIGHT: 4354 case K_UP: 4355 case K_DOWN: 4356 case K_END: 4357 case K_HOME: 4358 # endif 4359 if (!(mod_mask & MOD_MASK_SHIFT)) 4360 break; 4361 // FALLTHROUGH 4362 case K_S_LEFT: 4363 case K_S_RIGHT: 4364 case K_S_UP: 4365 case K_S_DOWN: 4366 case K_S_END: 4367 case K_S_HOME: 4368 // Start selection right away, the cursor can move with 4369 // CTRL-O when beyond the end of the line. 4370 start_selection(); 4371 4372 // Execute the key in (insert) Select mode. 4373 stuffcharReadbuff(Ctrl_O); 4374 if (mod_mask) 4375 { 4376 char_u buf[4]; 4377 4378 buf[0] = K_SPECIAL; 4379 buf[1] = KS_MODIFIER; 4380 buf[2] = mod_mask; 4381 buf[3] = NUL; 4382 stuffReadbuff(buf); 4383 } 4384 stuffcharReadbuff(c); 4385 return TRUE; 4386 } 4387 return FALSE; 4388 } 4389 4390 /* 4391 * <Insert> key in Insert mode: toggle insert/replace mode. 4392 */ 4393 static void 4394 ins_insert(int replaceState) 4395 { 4396 #ifdef FEAT_EVAL 4397 set_vim_var_string(VV_INSERTMODE, 4398 (char_u *)((State & REPLACE_FLAG) ? "i" 4399 : replaceState == VREPLACE ? "v" 4400 : "r"), 1); 4401 #endif 4402 ins_apply_autocmds(EVENT_INSERTCHANGE); 4403 if (State & REPLACE_FLAG) 4404 State = INSERT | (State & LANGMAP); 4405 else 4406 State = replaceState | (State & LANGMAP); 4407 AppendCharToRedobuff(K_INS); 4408 showmode(); 4409 #ifdef CURSOR_SHAPE 4410 ui_cursor_shape(); // may show different cursor shape 4411 #endif 4412 } 4413 4414 /* 4415 * Pressed CTRL-O in Insert mode. 4416 */ 4417 static void 4418 ins_ctrl_o(void) 4419 { 4420 if (State & VREPLACE_FLAG) 4421 restart_edit = 'V'; 4422 else 4423 if (State & REPLACE_FLAG) 4424 restart_edit = 'R'; 4425 else 4426 restart_edit = 'I'; 4427 if (virtual_active()) 4428 ins_at_eol = FALSE; // cursor always keeps its column 4429 else 4430 ins_at_eol = (gchar_cursor() == NUL); 4431 } 4432 4433 /* 4434 * If the cursor is on an indent, ^T/^D insert/delete one 4435 * shiftwidth. Otherwise ^T/^D behave like a "<<" or ">>". 4436 * Always round the indent to 'shiftwidth', this is compatible 4437 * with vi. But vi only supports ^T and ^D after an 4438 * autoindent, we support it everywhere. 4439 */ 4440 static void 4441 ins_shift(int c, int lastc) 4442 { 4443 if (stop_arrow() == FAIL) 4444 return; 4445 AppendCharToRedobuff(c); 4446 4447 /* 4448 * 0^D and ^^D: remove all indent. 4449 */ 4450 if (c == Ctrl_D && (lastc == '0' || lastc == '^') 4451 && curwin->w_cursor.col > 0) 4452 { 4453 --curwin->w_cursor.col; 4454 (void)del_char(FALSE); // delete the '^' or '0' 4455 // In Replace mode, restore the characters that '^' or '0' replaced. 4456 if (State & REPLACE_FLAG) 4457 replace_pop_ins(); 4458 if (lastc == '^') 4459 old_indent = get_indent(); // remember curr. indent 4460 change_indent(INDENT_SET, 0, TRUE, 0, TRUE); 4461 } 4462 else 4463 change_indent(c == Ctrl_D ? INDENT_DEC : INDENT_INC, 0, TRUE, 0, TRUE); 4464 4465 if (did_ai && *skipwhite(ml_get_curline()) != NUL) 4466 did_ai = FALSE; 4467 #ifdef FEAT_SMARTINDENT 4468 did_si = FALSE; 4469 can_si = FALSE; 4470 can_si_back = FALSE; 4471 #endif 4472 #ifdef FEAT_CINDENT 4473 can_cindent = FALSE; // no cindenting after ^D or ^T 4474 #endif 4475 } 4476 4477 static void 4478 ins_del(void) 4479 { 4480 int temp; 4481 4482 if (stop_arrow() == FAIL) 4483 return; 4484 if (gchar_cursor() == NUL) // delete newline 4485 { 4486 temp = curwin->w_cursor.col; 4487 if (!can_bs(BS_EOL) // only if "eol" included 4488 || do_join(2, FALSE, TRUE, FALSE, FALSE) == FAIL) 4489 vim_beep(BO_BS); 4490 else 4491 { 4492 curwin->w_cursor.col = temp; 4493 // Adjust orig_line_count in case more lines have been deleted than 4494 // have been added. That makes sure, that open_line() later 4495 // can access all buffer lines correctly 4496 if (State & VREPLACE_FLAG && 4497 orig_line_count > curbuf->b_ml.ml_line_count) 4498 orig_line_count = curbuf->b_ml.ml_line_count; 4499 } 4500 } 4501 else if (del_char(FALSE) == FAIL) // delete char under cursor 4502 vim_beep(BO_BS); 4503 did_ai = FALSE; 4504 #ifdef FEAT_SMARTINDENT 4505 did_si = FALSE; 4506 can_si = FALSE; 4507 can_si_back = FALSE; 4508 #endif 4509 AppendCharToRedobuff(K_DEL); 4510 } 4511 4512 /* 4513 * Delete one character for ins_bs(). 4514 */ 4515 static void 4516 ins_bs_one(colnr_T *vcolp) 4517 { 4518 dec_cursor(); 4519 getvcol(curwin, &curwin->w_cursor, vcolp, NULL, NULL); 4520 if (State & REPLACE_FLAG) 4521 { 4522 // Don't delete characters before the insert point when in 4523 // Replace mode 4524 if (curwin->w_cursor.lnum != Insstart.lnum 4525 || curwin->w_cursor.col >= Insstart.col) 4526 replace_do_bs(-1); 4527 } 4528 else 4529 (void)del_char(FALSE); 4530 } 4531 4532 /* 4533 * Handle Backspace, delete-word and delete-line in Insert mode. 4534 * Return TRUE when backspace was actually used. 4535 */ 4536 static int 4537 ins_bs( 4538 int c, 4539 int mode, 4540 int *inserted_space_p) 4541 { 4542 linenr_T lnum; 4543 int cc; 4544 int temp = 0; // init for GCC 4545 colnr_T save_col; 4546 colnr_T mincol; 4547 int did_backspace = FALSE; 4548 int in_indent; 4549 int oldState; 4550 int cpc[MAX_MCO]; // composing characters 4551 4552 /* 4553 * can't delete anything in an empty file 4554 * can't backup past first character in buffer 4555 * can't backup past starting point unless 'backspace' > 1 4556 * can backup to a previous line if 'backspace' == 0 4557 */ 4558 if ( BUFEMPTY() 4559 || ( 4560 #ifdef FEAT_RIGHTLEFT 4561 !revins_on && 4562 #endif 4563 ((curwin->w_cursor.lnum == 1 && curwin->w_cursor.col == 0) 4564 || (!can_bs(BS_START) 4565 && (arrow_used 4566 || (curwin->w_cursor.lnum == Insstart_orig.lnum 4567 && curwin->w_cursor.col <= Insstart_orig.col))) 4568 || (!can_bs(BS_INDENT) && !arrow_used && ai_col > 0 4569 && curwin->w_cursor.col <= ai_col) 4570 || (!can_bs(BS_EOL) && curwin->w_cursor.col == 0)))) 4571 { 4572 vim_beep(BO_BS); 4573 return FALSE; 4574 } 4575 4576 if (stop_arrow() == FAIL) 4577 return FALSE; 4578 in_indent = inindent(0); 4579 #ifdef FEAT_CINDENT 4580 if (in_indent) 4581 can_cindent = FALSE; 4582 #endif 4583 end_comment_pending = NUL; // After BS, don't auto-end comment 4584 #ifdef FEAT_RIGHTLEFT 4585 if (revins_on) // put cursor after last inserted char 4586 inc_cursor(); 4587 #endif 4588 4589 // Virtualedit: 4590 // BACKSPACE_CHAR eats a virtual space 4591 // BACKSPACE_WORD eats all coladd 4592 // BACKSPACE_LINE eats all coladd and keeps going 4593 if (curwin->w_cursor.coladd > 0) 4594 { 4595 if (mode == BACKSPACE_CHAR) 4596 { 4597 --curwin->w_cursor.coladd; 4598 return TRUE; 4599 } 4600 if (mode == BACKSPACE_WORD) 4601 { 4602 curwin->w_cursor.coladd = 0; 4603 return TRUE; 4604 } 4605 curwin->w_cursor.coladd = 0; 4606 } 4607 4608 /* 4609 * Delete newline! 4610 */ 4611 if (curwin->w_cursor.col == 0) 4612 { 4613 lnum = Insstart.lnum; 4614 if (curwin->w_cursor.lnum == lnum 4615 #ifdef FEAT_RIGHTLEFT 4616 || revins_on 4617 #endif 4618 ) 4619 { 4620 if (u_save((linenr_T)(curwin->w_cursor.lnum - 2), 4621 (linenr_T)(curwin->w_cursor.lnum + 1)) == FAIL) 4622 return FALSE; 4623 --Insstart.lnum; 4624 Insstart.col = (colnr_T)STRLEN(ml_get(Insstart.lnum)); 4625 } 4626 /* 4627 * In replace mode: 4628 * cc < 0: NL was inserted, delete it 4629 * cc >= 0: NL was replaced, put original characters back 4630 */ 4631 cc = -1; 4632 if (State & REPLACE_FLAG) 4633 cc = replace_pop(); // returns -1 if NL was inserted 4634 /* 4635 * In replace mode, in the line we started replacing, we only move the 4636 * cursor. 4637 */ 4638 if ((State & REPLACE_FLAG) && curwin->w_cursor.lnum <= lnum) 4639 { 4640 dec_cursor(); 4641 } 4642 else 4643 { 4644 if (!(State & VREPLACE_FLAG) 4645 || curwin->w_cursor.lnum > orig_line_count) 4646 { 4647 temp = gchar_cursor(); // remember current char 4648 --curwin->w_cursor.lnum; 4649 4650 // When "aw" is in 'formatoptions' we must delete the space at 4651 // the end of the line, otherwise the line will be broken 4652 // again when auto-formatting. 4653 if (has_format_option(FO_AUTO) 4654 && has_format_option(FO_WHITE_PAR)) 4655 { 4656 char_u *ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum, 4657 TRUE); 4658 int len; 4659 4660 len = (int)STRLEN(ptr); 4661 if (len > 0 && ptr[len - 1] == ' ') 4662 ptr[len - 1] = NUL; 4663 } 4664 4665 (void)do_join(2, FALSE, FALSE, FALSE, FALSE); 4666 if (temp == NUL && gchar_cursor() != NUL) 4667 inc_cursor(); 4668 } 4669 else 4670 dec_cursor(); 4671 4672 /* 4673 * In REPLACE mode we have to put back the text that was replaced 4674 * by the NL. On the replace stack is first a NUL-terminated 4675 * sequence of characters that were deleted and then the 4676 * characters that NL replaced. 4677 */ 4678 if (State & REPLACE_FLAG) 4679 { 4680 /* 4681 * Do the next ins_char() in NORMAL state, to 4682 * prevent ins_char() from replacing characters and 4683 * avoiding showmatch(). 4684 */ 4685 oldState = State; 4686 State = NORMAL; 4687 /* 4688 * restore characters (blanks) deleted after cursor 4689 */ 4690 while (cc > 0) 4691 { 4692 save_col = curwin->w_cursor.col; 4693 mb_replace_pop_ins(cc); 4694 curwin->w_cursor.col = save_col; 4695 cc = replace_pop(); 4696 } 4697 // restore the characters that NL replaced 4698 replace_pop_ins(); 4699 State = oldState; 4700 } 4701 } 4702 did_ai = FALSE; 4703 } 4704 else 4705 { 4706 /* 4707 * Delete character(s) before the cursor. 4708 */ 4709 #ifdef FEAT_RIGHTLEFT 4710 if (revins_on) // put cursor on last inserted char 4711 dec_cursor(); 4712 #endif 4713 mincol = 0; 4714 // keep indent 4715 if (mode == BACKSPACE_LINE 4716 && (curbuf->b_p_ai 4717 #ifdef FEAT_CINDENT 4718 || cindent_on() 4719 #endif 4720 ) 4721 #ifdef FEAT_RIGHTLEFT 4722 && !revins_on 4723 #endif 4724 ) 4725 { 4726 save_col = curwin->w_cursor.col; 4727 beginline(BL_WHITE); 4728 if (curwin->w_cursor.col < save_col) 4729 mincol = curwin->w_cursor.col; 4730 curwin->w_cursor.col = save_col; 4731 } 4732 4733 /* 4734 * Handle deleting one 'shiftwidth' or 'softtabstop'. 4735 */ 4736 if ( mode == BACKSPACE_CHAR 4737 && ((p_sta && in_indent) 4738 || ((get_sts_value() != 0 4739 #ifdef FEAT_VARTABS 4740 || tabstop_count(curbuf->b_p_vsts_array) 4741 #endif 4742 ) 4743 && curwin->w_cursor.col > 0 4744 && (*(ml_get_cursor() - 1) == TAB 4745 || (*(ml_get_cursor() - 1) == ' ' 4746 && (!*inserted_space_p 4747 || arrow_used)))))) 4748 { 4749 int ts; 4750 colnr_T vcol; 4751 colnr_T want_vcol; 4752 colnr_T start_vcol; 4753 4754 *inserted_space_p = FALSE; 4755 // Compute the virtual column where we want to be. Since 4756 // 'showbreak' may get in the way, need to get the last column of 4757 // the previous character. 4758 getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL); 4759 start_vcol = vcol; 4760 dec_cursor(); 4761 getvcol(curwin, &curwin->w_cursor, NULL, NULL, &want_vcol); 4762 inc_cursor(); 4763 #ifdef FEAT_VARTABS 4764 if (p_sta && in_indent) 4765 { 4766 ts = (int)get_sw_value(curbuf); 4767 want_vcol = (want_vcol / ts) * ts; 4768 } 4769 else 4770 want_vcol = tabstop_start(want_vcol, get_sts_value(), 4771 curbuf->b_p_vsts_array); 4772 #else 4773 if (p_sta && in_indent) 4774 ts = (int)get_sw_value(curbuf); 4775 else 4776 ts = (int)get_sts_value(); 4777 want_vcol = (want_vcol / ts) * ts; 4778 #endif 4779 4780 // delete characters until we are at or before want_vcol 4781 while (vcol > want_vcol 4782 && (cc = *(ml_get_cursor() - 1), VIM_ISWHITE(cc))) 4783 ins_bs_one(&vcol); 4784 4785 // insert extra spaces until we are at want_vcol 4786 while (vcol < want_vcol) 4787 { 4788 // Remember the first char we inserted 4789 if (curwin->w_cursor.lnum == Insstart_orig.lnum 4790 && curwin->w_cursor.col < Insstart_orig.col) 4791 Insstart_orig.col = curwin->w_cursor.col; 4792 4793 if (State & VREPLACE_FLAG) 4794 ins_char(' '); 4795 else 4796 { 4797 ins_str((char_u *)" "); 4798 if ((State & REPLACE_FLAG)) 4799 replace_push(NUL); 4800 } 4801 getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL); 4802 } 4803 4804 // If we are now back where we started delete one character. Can 4805 // happen when using 'sts' and 'linebreak'. 4806 if (vcol >= start_vcol) 4807 ins_bs_one(&vcol); 4808 } 4809 4810 /* 4811 * Delete up to starting point, start of line or previous word. 4812 */ 4813 else 4814 { 4815 int cclass = 0, prev_cclass = 0; 4816 4817 if (has_mbyte) 4818 cclass = mb_get_class(ml_get_cursor()); 4819 do 4820 { 4821 #ifdef FEAT_RIGHTLEFT 4822 if (!revins_on) // put cursor on char to be deleted 4823 #endif 4824 dec_cursor(); 4825 4826 cc = gchar_cursor(); 4827 // look multi-byte character class 4828 if (has_mbyte) 4829 { 4830 prev_cclass = cclass; 4831 cclass = mb_get_class(ml_get_cursor()); 4832 } 4833 4834 // start of word? 4835 if (mode == BACKSPACE_WORD && !vim_isspace(cc)) 4836 { 4837 mode = BACKSPACE_WORD_NOT_SPACE; 4838 temp = vim_iswordc(cc); 4839 } 4840 // end of word? 4841 else if (mode == BACKSPACE_WORD_NOT_SPACE 4842 && ((vim_isspace(cc) || vim_iswordc(cc) != temp) 4843 || prev_cclass != cclass)) 4844 { 4845 #ifdef FEAT_RIGHTLEFT 4846 if (!revins_on) 4847 #endif 4848 inc_cursor(); 4849 #ifdef FEAT_RIGHTLEFT 4850 else if (State & REPLACE_FLAG) 4851 dec_cursor(); 4852 #endif 4853 break; 4854 } 4855 if (State & REPLACE_FLAG) 4856 replace_do_bs(-1); 4857 else 4858 { 4859 if (enc_utf8 && p_deco) 4860 (void)utfc_ptr2char(ml_get_cursor(), cpc); 4861 (void)del_char(FALSE); 4862 /* 4863 * If there are combining characters and 'delcombine' is set 4864 * move the cursor back. Don't back up before the base 4865 * character. 4866 */ 4867 if (enc_utf8 && p_deco && cpc[0] != NUL) 4868 inc_cursor(); 4869 #ifdef FEAT_RIGHTLEFT 4870 if (revins_chars) 4871 { 4872 revins_chars--; 4873 revins_legal++; 4874 } 4875 if (revins_on && gchar_cursor() == NUL) 4876 break; 4877 #endif 4878 } 4879 // Just a single backspace?: 4880 if (mode == BACKSPACE_CHAR) 4881 break; 4882 } while ( 4883 #ifdef FEAT_RIGHTLEFT 4884 revins_on || 4885 #endif 4886 (curwin->w_cursor.col > mincol 4887 && (curwin->w_cursor.lnum != Insstart_orig.lnum 4888 || curwin->w_cursor.col != Insstart_orig.col))); 4889 } 4890 did_backspace = TRUE; 4891 } 4892 #ifdef FEAT_SMARTINDENT 4893 did_si = FALSE; 4894 can_si = FALSE; 4895 can_si_back = FALSE; 4896 #endif 4897 if (curwin->w_cursor.col <= 1) 4898 did_ai = FALSE; 4899 /* 4900 * It's a little strange to put backspaces into the redo 4901 * buffer, but it makes auto-indent a lot easier to deal 4902 * with. 4903 */ 4904 AppendCharToRedobuff(c); 4905 4906 // If deleted before the insertion point, adjust it 4907 if (curwin->w_cursor.lnum == Insstart_orig.lnum 4908 && curwin->w_cursor.col < Insstart_orig.col) 4909 Insstart_orig.col = curwin->w_cursor.col; 4910 4911 // vi behaviour: the cursor moves backward but the character that 4912 // was there remains visible 4913 // Vim behaviour: the cursor moves backward and the character that 4914 // was there is erased from the screen. 4915 // We can emulate the vi behaviour by pretending there is a dollar 4916 // displayed even when there isn't. 4917 // --pkv Sun Jan 19 01:56:40 EST 2003 4918 if (vim_strchr(p_cpo, CPO_BACKSPACE) != NULL && dollar_vcol == -1) 4919 dollar_vcol = curwin->w_virtcol; 4920 4921 #ifdef FEAT_FOLDING 4922 // When deleting a char the cursor line must never be in a closed fold. 4923 // E.g., when 'foldmethod' is indent and deleting the first non-white 4924 // char before a Tab. 4925 if (did_backspace) 4926 foldOpenCursor(); 4927 #endif 4928 4929 return did_backspace; 4930 } 4931 4932 /* 4933 * Handle receiving P_PS: start paste mode. Inserts the following text up to 4934 * P_PE literally. 4935 * When "drop" is TRUE then consume the text and drop it. 4936 */ 4937 int 4938 bracketed_paste(paste_mode_T mode, int drop, garray_T *gap) 4939 { 4940 int c; 4941 char_u buf[NUMBUFLEN + MB_MAXBYTES]; 4942 int idx = 0; 4943 char_u *end = find_termcode((char_u *)"PE"); 4944 int ret_char = -1; 4945 int save_allow_keys = allow_keys; 4946 int save_paste = p_paste; 4947 4948 // If the end code is too long we can't detect it, read everything. 4949 if (end != NULL && STRLEN(end) >= NUMBUFLEN) 4950 end = NULL; 4951 ++no_mapping; 4952 allow_keys = 0; 4953 if (!p_paste) 4954 // Also have the side effects of setting 'paste' to make it work much 4955 // faster. 4956 set_option_value((char_u *)"paste", TRUE, NULL, 0); 4957 4958 for (;;) 4959 { 4960 // When the end is not defined read everything there is. 4961 if (end == NULL && vpeekc() == NUL) 4962 break; 4963 do 4964 c = vgetc(); 4965 while (c == K_IGNORE || c == K_VER_SCROLLBAR || c == K_HOR_SCROLLBAR); 4966 if (c == NUL || got_int || (ex_normal_busy > 0 && c == Ctrl_C)) 4967 // When CTRL-C was encountered the typeahead will be flushed and we 4968 // won't get the end sequence. Except when using ":normal". 4969 break; 4970 4971 if (has_mbyte) 4972 idx += (*mb_char2bytes)(c, buf + idx); 4973 else 4974 buf[idx++] = c; 4975 buf[idx] = NUL; 4976 if (end != NULL && STRNCMP(buf, end, idx) == 0) 4977 { 4978 if (end[idx] == NUL) 4979 break; // Found the end of paste code. 4980 continue; 4981 } 4982 if (!drop) 4983 { 4984 switch (mode) 4985 { 4986 case PASTE_CMDLINE: 4987 put_on_cmdline(buf, idx, TRUE); 4988 break; 4989 4990 case PASTE_EX: 4991 if (gap != NULL && ga_grow(gap, idx) == OK) 4992 { 4993 mch_memmove((char *)gap->ga_data + gap->ga_len, 4994 buf, (size_t)idx); 4995 gap->ga_len += idx; 4996 } 4997 break; 4998 4999 case PASTE_INSERT: 5000 if (stop_arrow() == OK) 5001 { 5002 c = buf[0]; 5003 if (idx == 1 && (c == CAR || c == K_KENTER || c == NL)) 5004 ins_eol(c); 5005 else 5006 { 5007 ins_char_bytes(buf, idx); 5008 AppendToRedobuffLit(buf, idx); 5009 } 5010 } 5011 break; 5012 5013 case PASTE_ONE_CHAR: 5014 if (ret_char == -1) 5015 { 5016 if (has_mbyte) 5017 ret_char = (*mb_ptr2char)(buf); 5018 else 5019 ret_char = buf[0]; 5020 } 5021 break; 5022 } 5023 } 5024 idx = 0; 5025 } 5026 5027 --no_mapping; 5028 allow_keys = save_allow_keys; 5029 if (!save_paste) 5030 set_option_value((char_u *)"paste", FALSE, NULL, 0); 5031 5032 return ret_char; 5033 } 5034 5035 #if defined(FEAT_GUI_TABLINE) || defined(PROTO) 5036 static void 5037 ins_tabline(int c) 5038 { 5039 // We will be leaving the current window, unless closing another tab. 5040 if (c != K_TABMENU || current_tabmenu != TABLINE_MENU_CLOSE 5041 || (current_tab != 0 && current_tab != tabpage_index(curtab))) 5042 { 5043 undisplay_dollar(); 5044 start_arrow(&curwin->w_cursor); 5045 # ifdef FEAT_CINDENT 5046 can_cindent = TRUE; 5047 # endif 5048 } 5049 5050 if (c == K_TABLINE) 5051 goto_tabpage(current_tab); 5052 else 5053 { 5054 handle_tabmenu(); 5055 redraw_statuslines(); // will redraw the tabline when needed 5056 } 5057 } 5058 #endif 5059 5060 #if defined(FEAT_GUI) || defined(PROTO) 5061 void 5062 ins_scroll(void) 5063 { 5064 pos_T tpos; 5065 5066 undisplay_dollar(); 5067 tpos = curwin->w_cursor; 5068 if (gui_do_scroll()) 5069 { 5070 start_arrow(&tpos); 5071 # ifdef FEAT_CINDENT 5072 can_cindent = TRUE; 5073 # endif 5074 } 5075 } 5076 5077 void 5078 ins_horscroll(void) 5079 { 5080 pos_T tpos; 5081 5082 undisplay_dollar(); 5083 tpos = curwin->w_cursor; 5084 if (gui_do_horiz_scroll(scrollbar_value, FALSE)) 5085 { 5086 start_arrow(&tpos); 5087 # ifdef FEAT_CINDENT 5088 can_cindent = TRUE; 5089 # endif 5090 } 5091 } 5092 #endif 5093 5094 static void 5095 ins_left(void) 5096 { 5097 pos_T tpos; 5098 int end_change = dont_sync_undo == FALSE; // end undoable change 5099 5100 #ifdef FEAT_FOLDING 5101 if ((fdo_flags & FDO_HOR) && KeyTyped) 5102 foldOpenCursor(); 5103 #endif 5104 undisplay_dollar(); 5105 tpos = curwin->w_cursor; 5106 if (oneleft() == OK) 5107 { 5108 #if defined(FEAT_XIM) && defined(FEAT_GUI_GTK) 5109 // Only call start_arrow() when not busy with preediting, it will 5110 // break undo. K_LEFT is inserted in im_correct_cursor(). 5111 if (p_imst == IM_OVER_THE_SPOT || !im_is_preediting()) 5112 #endif 5113 { 5114 start_arrow_with_change(&tpos, end_change); 5115 if (!end_change) 5116 AppendCharToRedobuff(K_LEFT); 5117 } 5118 #ifdef FEAT_RIGHTLEFT 5119 // If exit reversed string, position is fixed 5120 if (revins_scol != -1 && (int)curwin->w_cursor.col >= revins_scol) 5121 revins_legal++; 5122 revins_chars++; 5123 #endif 5124 } 5125 5126 /* 5127 * if 'whichwrap' set for cursor in insert mode may go to 5128 * previous line 5129 */ 5130 else if (vim_strchr(p_ww, '[') != NULL && curwin->w_cursor.lnum > 1) 5131 { 5132 // always break undo when moving upwards/downwards, else undo may break 5133 start_arrow(&tpos); 5134 --(curwin->w_cursor.lnum); 5135 coladvance((colnr_T)MAXCOL); 5136 curwin->w_set_curswant = TRUE; // so we stay at the end 5137 } 5138 else 5139 vim_beep(BO_CRSR); 5140 dont_sync_undo = FALSE; 5141 } 5142 5143 static void 5144 ins_home(int c) 5145 { 5146 pos_T tpos; 5147 5148 #ifdef FEAT_FOLDING 5149 if ((fdo_flags & FDO_HOR) && KeyTyped) 5150 foldOpenCursor(); 5151 #endif 5152 undisplay_dollar(); 5153 tpos = curwin->w_cursor; 5154 if (c == K_C_HOME) 5155 curwin->w_cursor.lnum = 1; 5156 curwin->w_cursor.col = 0; 5157 curwin->w_cursor.coladd = 0; 5158 curwin->w_curswant = 0; 5159 start_arrow(&tpos); 5160 } 5161 5162 static void 5163 ins_end(int c) 5164 { 5165 pos_T tpos; 5166 5167 #ifdef FEAT_FOLDING 5168 if ((fdo_flags & FDO_HOR) && KeyTyped) 5169 foldOpenCursor(); 5170 #endif 5171 undisplay_dollar(); 5172 tpos = curwin->w_cursor; 5173 if (c == K_C_END) 5174 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; 5175 coladvance((colnr_T)MAXCOL); 5176 curwin->w_curswant = MAXCOL; 5177 5178 start_arrow(&tpos); 5179 } 5180 5181 static void 5182 ins_s_left() 5183 { 5184 int end_change = dont_sync_undo == FALSE; // end undoable change 5185 #ifdef FEAT_FOLDING 5186 if ((fdo_flags & FDO_HOR) && KeyTyped) 5187 foldOpenCursor(); 5188 #endif 5189 undisplay_dollar(); 5190 if (curwin->w_cursor.lnum > 1 || curwin->w_cursor.col > 0) 5191 { 5192 start_arrow_with_change(&curwin->w_cursor, end_change); 5193 if (!end_change) 5194 AppendCharToRedobuff(K_S_LEFT); 5195 (void)bck_word(1L, FALSE, FALSE); 5196 curwin->w_set_curswant = TRUE; 5197 } 5198 else 5199 vim_beep(BO_CRSR); 5200 dont_sync_undo = FALSE; 5201 } 5202 5203 static void 5204 ins_right(void) 5205 { 5206 int end_change = dont_sync_undo == FALSE; // end undoable change 5207 5208 #ifdef FEAT_FOLDING 5209 if ((fdo_flags & FDO_HOR) && KeyTyped) 5210 foldOpenCursor(); 5211 #endif 5212 undisplay_dollar(); 5213 if (gchar_cursor() != NUL || virtual_active()) 5214 { 5215 start_arrow_with_change(&curwin->w_cursor, end_change); 5216 if (!end_change) 5217 AppendCharToRedobuff(K_RIGHT); 5218 curwin->w_set_curswant = TRUE; 5219 if (virtual_active()) 5220 oneright(); 5221 else 5222 { 5223 if (has_mbyte) 5224 curwin->w_cursor.col += (*mb_ptr2len)(ml_get_cursor()); 5225 else 5226 ++curwin->w_cursor.col; 5227 } 5228 5229 #ifdef FEAT_RIGHTLEFT 5230 revins_legal++; 5231 if (revins_chars) 5232 revins_chars--; 5233 #endif 5234 } 5235 // if 'whichwrap' set for cursor in insert mode, may move the 5236 // cursor to the next line 5237 else if (vim_strchr(p_ww, ']') != NULL 5238 && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) 5239 { 5240 start_arrow(&curwin->w_cursor); 5241 curwin->w_set_curswant = TRUE; 5242 ++curwin->w_cursor.lnum; 5243 curwin->w_cursor.col = 0; 5244 } 5245 else 5246 vim_beep(BO_CRSR); 5247 dont_sync_undo = FALSE; 5248 } 5249 5250 static void 5251 ins_s_right() 5252 { 5253 int end_change = dont_sync_undo == FALSE; // end undoable change 5254 #ifdef FEAT_FOLDING 5255 if ((fdo_flags & FDO_HOR) && KeyTyped) 5256 foldOpenCursor(); 5257 #endif 5258 undisplay_dollar(); 5259 if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count 5260 || gchar_cursor() != NUL) 5261 { 5262 start_arrow_with_change(&curwin->w_cursor, end_change); 5263 if (!end_change) 5264 AppendCharToRedobuff(K_S_RIGHT); 5265 (void)fwd_word(1L, FALSE, 0); 5266 curwin->w_set_curswant = TRUE; 5267 } 5268 else 5269 vim_beep(BO_CRSR); 5270 dont_sync_undo = FALSE; 5271 } 5272 5273 static void 5274 ins_up( 5275 int startcol) // when TRUE move to Insstart.col 5276 { 5277 pos_T tpos; 5278 linenr_T old_topline = curwin->w_topline; 5279 #ifdef FEAT_DIFF 5280 int old_topfill = curwin->w_topfill; 5281 #endif 5282 5283 undisplay_dollar(); 5284 tpos = curwin->w_cursor; 5285 if (cursor_up(1L, TRUE) == OK) 5286 { 5287 if (startcol) 5288 coladvance(getvcol_nolist(&Insstart)); 5289 if (old_topline != curwin->w_topline 5290 #ifdef FEAT_DIFF 5291 || old_topfill != curwin->w_topfill 5292 #endif 5293 ) 5294 redraw_later(VALID); 5295 start_arrow(&tpos); 5296 #ifdef FEAT_CINDENT 5297 can_cindent = TRUE; 5298 #endif 5299 } 5300 else 5301 vim_beep(BO_CRSR); 5302 } 5303 5304 static void 5305 ins_pageup(void) 5306 { 5307 pos_T tpos; 5308 5309 undisplay_dollar(); 5310 5311 if (mod_mask & MOD_MASK_CTRL) 5312 { 5313 // <C-PageUp>: tab page back 5314 if (first_tabpage->tp_next != NULL) 5315 { 5316 start_arrow(&curwin->w_cursor); 5317 goto_tabpage(-1); 5318 } 5319 return; 5320 } 5321 5322 tpos = curwin->w_cursor; 5323 if (onepage(BACKWARD, 1L) == OK) 5324 { 5325 start_arrow(&tpos); 5326 #ifdef FEAT_CINDENT 5327 can_cindent = TRUE; 5328 #endif 5329 } 5330 else 5331 vim_beep(BO_CRSR); 5332 } 5333 5334 static void 5335 ins_down( 5336 int startcol) // when TRUE move to Insstart.col 5337 { 5338 pos_T tpos; 5339 linenr_T old_topline = curwin->w_topline; 5340 #ifdef FEAT_DIFF 5341 int old_topfill = curwin->w_topfill; 5342 #endif 5343 5344 undisplay_dollar(); 5345 tpos = curwin->w_cursor; 5346 if (cursor_down(1L, TRUE) == OK) 5347 { 5348 if (startcol) 5349 coladvance(getvcol_nolist(&Insstart)); 5350 if (old_topline != curwin->w_topline 5351 #ifdef FEAT_DIFF 5352 || old_topfill != curwin->w_topfill 5353 #endif 5354 ) 5355 redraw_later(VALID); 5356 start_arrow(&tpos); 5357 #ifdef FEAT_CINDENT 5358 can_cindent = TRUE; 5359 #endif 5360 } 5361 else 5362 vim_beep(BO_CRSR); 5363 } 5364 5365 static void 5366 ins_pagedown(void) 5367 { 5368 pos_T tpos; 5369 5370 undisplay_dollar(); 5371 5372 if (mod_mask & MOD_MASK_CTRL) 5373 { 5374 // <C-PageDown>: tab page forward 5375 if (first_tabpage->tp_next != NULL) 5376 { 5377 start_arrow(&curwin->w_cursor); 5378 goto_tabpage(0); 5379 } 5380 return; 5381 } 5382 5383 tpos = curwin->w_cursor; 5384 if (onepage(FORWARD, 1L) == OK) 5385 { 5386 start_arrow(&tpos); 5387 #ifdef FEAT_CINDENT 5388 can_cindent = TRUE; 5389 #endif 5390 } 5391 else 5392 vim_beep(BO_CRSR); 5393 } 5394 5395 #ifdef FEAT_DND 5396 static void 5397 ins_drop(void) 5398 { 5399 do_put('~', BACKWARD, 1L, PUT_CURSEND); 5400 } 5401 #endif 5402 5403 /* 5404 * Handle TAB in Insert or Replace mode. 5405 * Return TRUE when the TAB needs to be inserted like a normal character. 5406 */ 5407 static int 5408 ins_tab(void) 5409 { 5410 int ind; 5411 int i; 5412 int temp; 5413 5414 if (Insstart_blank_vcol == MAXCOL && curwin->w_cursor.lnum == Insstart.lnum) 5415 Insstart_blank_vcol = get_nolist_virtcol(); 5416 if (echeck_abbr(TAB + ABBR_OFF)) 5417 return FALSE; 5418 5419 ind = inindent(0); 5420 #ifdef FEAT_CINDENT 5421 if (ind) 5422 can_cindent = FALSE; 5423 #endif 5424 5425 /* 5426 * When nothing special, insert TAB like a normal character. 5427 */ 5428 if (!curbuf->b_p_et 5429 #ifdef FEAT_VARTABS 5430 && !(p_sta && ind 5431 // These five lines mean 'tabstop' != 'shiftwidth' 5432 && ((tabstop_count(curbuf->b_p_vts_array) > 1) 5433 || (tabstop_count(curbuf->b_p_vts_array) == 1 5434 && tabstop_first(curbuf->b_p_vts_array) 5435 != get_sw_value(curbuf)) 5436 || (tabstop_count(curbuf->b_p_vts_array) == 0 5437 && curbuf->b_p_ts != get_sw_value(curbuf)))) 5438 && tabstop_count(curbuf->b_p_vsts_array) == 0 5439 #else 5440 && !(p_sta && ind && curbuf->b_p_ts != get_sw_value(curbuf)) 5441 #endif 5442 && get_sts_value() == 0) 5443 return TRUE; 5444 5445 if (stop_arrow() == FAIL) 5446 return TRUE; 5447 5448 did_ai = FALSE; 5449 #ifdef FEAT_SMARTINDENT 5450 did_si = FALSE; 5451 can_si = FALSE; 5452 can_si_back = FALSE; 5453 #endif 5454 AppendToRedobuff((char_u *)"\t"); 5455 5456 #ifdef FEAT_VARTABS 5457 if (p_sta && ind) // insert tab in indent, use 'shiftwidth' 5458 { 5459 temp = (int)get_sw_value(curbuf); 5460 temp -= get_nolist_virtcol() % temp; 5461 } 5462 else if (tabstop_count(curbuf->b_p_vsts_array) > 0 || curbuf->b_p_sts != 0) 5463 // use 'softtabstop' when set 5464 temp = tabstop_padding(get_nolist_virtcol(), get_sts_value(), 5465 curbuf->b_p_vsts_array); 5466 else // otherwise use 'tabstop' 5467 temp = tabstop_padding(get_nolist_virtcol(), curbuf->b_p_ts, 5468 curbuf->b_p_vts_array); 5469 #else 5470 if (p_sta && ind) // insert tab in indent, use 'shiftwidth' 5471 temp = (int)get_sw_value(curbuf); 5472 else if (curbuf->b_p_sts != 0) // use 'softtabstop' when set 5473 temp = (int)get_sts_value(); 5474 else // otherwise use 'tabstop' 5475 temp = (int)curbuf->b_p_ts; 5476 temp -= get_nolist_virtcol() % temp; 5477 #endif 5478 5479 /* 5480 * Insert the first space with ins_char(). It will delete one char in 5481 * replace mode. Insert the rest with ins_str(); it will not delete any 5482 * chars. For VREPLACE mode, we use ins_char() for all characters. 5483 */ 5484 ins_char(' '); 5485 while (--temp > 0) 5486 { 5487 if (State & VREPLACE_FLAG) 5488 ins_char(' '); 5489 else 5490 { 5491 ins_str((char_u *)" "); 5492 if (State & REPLACE_FLAG) // no char replaced 5493 replace_push(NUL); 5494 } 5495 } 5496 5497 /* 5498 * When 'expandtab' not set: Replace spaces by TABs where possible. 5499 */ 5500 #ifdef FEAT_VARTABS 5501 if (!curbuf->b_p_et && (tabstop_count(curbuf->b_p_vsts_array) > 0 5502 || get_sts_value() > 0 5503 || (p_sta && ind))) 5504 #else 5505 if (!curbuf->b_p_et && (get_sts_value() || (p_sta && ind))) 5506 #endif 5507 { 5508 char_u *ptr; 5509 char_u *saved_line = NULL; // init for GCC 5510 pos_T pos; 5511 pos_T fpos; 5512 pos_T *cursor; 5513 colnr_T want_vcol, vcol; 5514 int change_col = -1; 5515 int save_list = curwin->w_p_list; 5516 5517 /* 5518 * Get the current line. For VREPLACE mode, don't make real changes 5519 * yet, just work on a copy of the line. 5520 */ 5521 if (State & VREPLACE_FLAG) 5522 { 5523 pos = curwin->w_cursor; 5524 cursor = &pos; 5525 saved_line = vim_strsave(ml_get_curline()); 5526 if (saved_line == NULL) 5527 return FALSE; 5528 ptr = saved_line + pos.col; 5529 } 5530 else 5531 { 5532 ptr = ml_get_cursor(); 5533 cursor = &curwin->w_cursor; 5534 } 5535 5536 // When 'L' is not in 'cpoptions' a tab always takes up 'ts' spaces. 5537 if (vim_strchr(p_cpo, CPO_LISTWM) == NULL) 5538 curwin->w_p_list = FALSE; 5539 5540 // Find first white before the cursor 5541 fpos = curwin->w_cursor; 5542 while (fpos.col > 0 && VIM_ISWHITE(ptr[-1])) 5543 { 5544 --fpos.col; 5545 --ptr; 5546 } 5547 5548 // In Replace mode, don't change characters before the insert point. 5549 if ((State & REPLACE_FLAG) 5550 && fpos.lnum == Insstart.lnum 5551 && fpos.col < Insstart.col) 5552 { 5553 ptr += Insstart.col - fpos.col; 5554 fpos.col = Insstart.col; 5555 } 5556 5557 // compute virtual column numbers of first white and cursor 5558 getvcol(curwin, &fpos, &vcol, NULL, NULL); 5559 getvcol(curwin, cursor, &want_vcol, NULL, NULL); 5560 5561 // Use as many TABs as possible. Beware of 'breakindent', 'showbreak' 5562 // and 'linebreak' adding extra virtual columns. 5563 while (VIM_ISWHITE(*ptr)) 5564 { 5565 i = lbr_chartabsize(NULL, (char_u *)"\t", vcol); 5566 if (vcol + i > want_vcol) 5567 break; 5568 if (*ptr != TAB) 5569 { 5570 *ptr = TAB; 5571 if (change_col < 0) 5572 { 5573 change_col = fpos.col; // Column of first change 5574 // May have to adjust Insstart 5575 if (fpos.lnum == Insstart.lnum && fpos.col < Insstart.col) 5576 Insstart.col = fpos.col; 5577 } 5578 } 5579 ++fpos.col; 5580 ++ptr; 5581 vcol += i; 5582 } 5583 5584 if (change_col >= 0) 5585 { 5586 int repl_off = 0; 5587 char_u *line = ptr; 5588 5589 // Skip over the spaces we need. 5590 while (vcol < want_vcol && *ptr == ' ') 5591 { 5592 vcol += lbr_chartabsize(line, ptr, vcol); 5593 ++ptr; 5594 ++repl_off; 5595 } 5596 if (vcol > want_vcol) 5597 { 5598 // Must have a char with 'showbreak' just before it. 5599 --ptr; 5600 --repl_off; 5601 } 5602 fpos.col += repl_off; 5603 5604 // Delete following spaces. 5605 i = cursor->col - fpos.col; 5606 if (i > 0) 5607 { 5608 #ifdef FEAT_PROP_POPUP 5609 if (!(State & VREPLACE_FLAG)) 5610 { 5611 char_u *newp; 5612 int col; 5613 5614 newp = alloc(curbuf->b_ml.ml_line_len - i); 5615 if (newp == NULL) 5616 return FALSE; 5617 5618 col = ptr - curbuf->b_ml.ml_line_ptr; 5619 if (col > 0) 5620 mch_memmove(newp, ptr - col, col); 5621 mch_memmove(newp + col, ptr + i, 5622 curbuf->b_ml.ml_line_len - col - i); 5623 5624 if (curbuf->b_ml.ml_flags & ML_LINE_DIRTY) 5625 vim_free(curbuf->b_ml.ml_line_ptr); 5626 curbuf->b_ml.ml_line_ptr = newp; 5627 curbuf->b_ml.ml_line_len -= i; 5628 curbuf->b_ml.ml_flags = 5629 (curbuf->b_ml.ml_flags | ML_LINE_DIRTY) & ~ML_EMPTY; 5630 } 5631 else 5632 #endif 5633 STRMOVE(ptr, ptr + i); 5634 // correct replace stack. 5635 if ((State & REPLACE_FLAG) && !(State & VREPLACE_FLAG)) 5636 for (temp = i; --temp >= 0; ) 5637 replace_join(repl_off); 5638 } 5639 #ifdef FEAT_NETBEANS_INTG 5640 if (netbeans_active()) 5641 { 5642 netbeans_removed(curbuf, fpos.lnum, cursor->col, (long)(i + 1)); 5643 netbeans_inserted(curbuf, fpos.lnum, cursor->col, 5644 (char_u *)"\t", 1); 5645 } 5646 #endif 5647 cursor->col -= i; 5648 5649 /* 5650 * In VREPLACE mode, we haven't changed anything yet. Do it now by 5651 * backspacing over the changed spacing and then inserting the new 5652 * spacing. 5653 */ 5654 if (State & VREPLACE_FLAG) 5655 { 5656 // Backspace from real cursor to change_col 5657 backspace_until_column(change_col); 5658 5659 // Insert each char in saved_line from changed_col to 5660 // ptr-cursor 5661 ins_bytes_len(saved_line + change_col, 5662 cursor->col - change_col); 5663 } 5664 } 5665 5666 if (State & VREPLACE_FLAG) 5667 vim_free(saved_line); 5668 curwin->w_p_list = save_list; 5669 } 5670 5671 return FALSE; 5672 } 5673 5674 /* 5675 * Handle CR or NL in insert mode. 5676 * Return FAIL when out of memory or can't undo. 5677 */ 5678 int 5679 ins_eol(int c) 5680 { 5681 int i; 5682 5683 if (echeck_abbr(c + ABBR_OFF)) 5684 return OK; 5685 if (stop_arrow() == FAIL) 5686 return FAIL; 5687 undisplay_dollar(); 5688 5689 /* 5690 * Strange Vi behaviour: In Replace mode, typing a NL will not delete the 5691 * character under the cursor. Only push a NUL on the replace stack, 5692 * nothing to put back when the NL is deleted. 5693 */ 5694 if ((State & REPLACE_FLAG) && !(State & VREPLACE_FLAG)) 5695 replace_push(NUL); 5696 5697 /* 5698 * In VREPLACE mode, a NL replaces the rest of the line, and starts 5699 * replacing the next line, so we push all of the characters left on the 5700 * line onto the replace stack. This is not done here though, it is done 5701 * in open_line(). 5702 */ 5703 5704 // Put cursor on NUL if on the last char and coladd is 1 (happens after 5705 // CTRL-O). 5706 if (virtual_active() && curwin->w_cursor.coladd > 0) 5707 coladvance(getviscol()); 5708 5709 #ifdef FEAT_RIGHTLEFT 5710 // NL in reverse insert will always start in the end of 5711 // current line. 5712 if (revins_on) 5713 curwin->w_cursor.col += (colnr_T)STRLEN(ml_get_cursor()); 5714 #endif 5715 5716 AppendToRedobuff(NL_STR); 5717 i = open_line(FORWARD, 5718 has_format_option(FO_RET_COMS) ? OPENLINE_DO_COM : 0, old_indent); 5719 old_indent = 0; 5720 #ifdef FEAT_CINDENT 5721 can_cindent = TRUE; 5722 #endif 5723 #ifdef FEAT_FOLDING 5724 // When inserting a line the cursor line must never be in a closed fold. 5725 foldOpenCursor(); 5726 #endif 5727 5728 return i; 5729 } 5730 5731 #ifdef FEAT_DIGRAPHS 5732 /* 5733 * Handle digraph in insert mode. 5734 * Returns character still to be inserted, or NUL when nothing remaining to be 5735 * done. 5736 */ 5737 static int 5738 ins_digraph(void) 5739 { 5740 int c; 5741 int cc; 5742 int did_putchar = FALSE; 5743 5744 pc_status = PC_STATUS_UNSET; 5745 if (redrawing() && !char_avail()) 5746 { 5747 // may need to redraw when no more chars available now 5748 ins_redraw(FALSE); 5749 5750 edit_putchar('?', TRUE); 5751 did_putchar = TRUE; 5752 #ifdef FEAT_CMDL_INFO 5753 add_to_showcmd_c(Ctrl_K); 5754 #endif 5755 } 5756 5757 #ifdef USE_ON_FLY_SCROLL 5758 dont_scroll = TRUE; // disallow scrolling here 5759 #endif 5760 5761 // don't map the digraph chars. This also prevents the 5762 // mode message to be deleted when ESC is hit 5763 ++no_mapping; 5764 ++allow_keys; 5765 c = plain_vgetc(); 5766 --no_mapping; 5767 --allow_keys; 5768 if (did_putchar) 5769 // when the line fits in 'columns' the '?' is at the start of the next 5770 // line and will not be removed by the redraw 5771 edit_unputchar(); 5772 5773 if (IS_SPECIAL(c) || mod_mask) // special key 5774 { 5775 #ifdef FEAT_CMDL_INFO 5776 clear_showcmd(); 5777 #endif 5778 insert_special(c, TRUE, FALSE); 5779 return NUL; 5780 } 5781 if (c != ESC) 5782 { 5783 did_putchar = FALSE; 5784 if (redrawing() && !char_avail()) 5785 { 5786 // may need to redraw when no more chars available now 5787 ins_redraw(FALSE); 5788 5789 if (char2cells(c) == 1) 5790 { 5791 ins_redraw(FALSE); 5792 edit_putchar(c, TRUE); 5793 did_putchar = TRUE; 5794 } 5795 #ifdef FEAT_CMDL_INFO 5796 add_to_showcmd_c(c); 5797 #endif 5798 } 5799 ++no_mapping; 5800 ++allow_keys; 5801 cc = plain_vgetc(); 5802 --no_mapping; 5803 --allow_keys; 5804 if (did_putchar) 5805 // when the line fits in 'columns' the '?' is at the start of the 5806 // next line and will not be removed by a redraw 5807 edit_unputchar(); 5808 if (cc != ESC) 5809 { 5810 AppendToRedobuff((char_u *)CTRL_V_STR); 5811 c = getdigraph(c, cc, TRUE); 5812 #ifdef FEAT_CMDL_INFO 5813 clear_showcmd(); 5814 #endif 5815 return c; 5816 } 5817 } 5818 #ifdef FEAT_CMDL_INFO 5819 clear_showcmd(); 5820 #endif 5821 return NUL; 5822 } 5823 #endif 5824 5825 /* 5826 * Handle CTRL-E and CTRL-Y in Insert mode: copy char from other line. 5827 * Returns the char to be inserted, or NUL if none found. 5828 */ 5829 int 5830 ins_copychar(linenr_T lnum) 5831 { 5832 int c; 5833 int temp; 5834 char_u *ptr, *prev_ptr; 5835 char_u *line; 5836 5837 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count) 5838 { 5839 vim_beep(BO_COPY); 5840 return NUL; 5841 } 5842 5843 // try to advance to the cursor column 5844 temp = 0; 5845 line = ptr = ml_get(lnum); 5846 prev_ptr = ptr; 5847 validate_virtcol(); 5848 while ((colnr_T)temp < curwin->w_virtcol && *ptr != NUL) 5849 { 5850 prev_ptr = ptr; 5851 temp += lbr_chartabsize_adv(line, &ptr, (colnr_T)temp); 5852 } 5853 if ((colnr_T)temp > curwin->w_virtcol) 5854 ptr = prev_ptr; 5855 5856 c = (*mb_ptr2char)(ptr); 5857 if (c == NUL) 5858 vim_beep(BO_COPY); 5859 return c; 5860 } 5861 5862 /* 5863 * CTRL-Y or CTRL-E typed in Insert mode. 5864 */ 5865 static int 5866 ins_ctrl_ey(int tc) 5867 { 5868 int c = tc; 5869 5870 if (ctrl_x_mode_scroll()) 5871 { 5872 if (c == Ctrl_Y) 5873 scrolldown_clamp(); 5874 else 5875 scrollup_clamp(); 5876 redraw_later(VALID); 5877 } 5878 else 5879 { 5880 c = ins_copychar(curwin->w_cursor.lnum + (c == Ctrl_Y ? -1 : 1)); 5881 if (c != NUL) 5882 { 5883 long tw_save; 5884 5885 // The character must be taken literally, insert like it 5886 // was typed after a CTRL-V, and pretend 'textwidth' 5887 // wasn't set. Digits, 'o' and 'x' are special after a 5888 // CTRL-V, don't use it for these. 5889 if (c < 256 && !isalnum(c)) 5890 AppendToRedobuff((char_u *)CTRL_V_STR); // CTRL-V 5891 tw_save = curbuf->b_p_tw; 5892 curbuf->b_p_tw = -1; 5893 insert_special(c, TRUE, FALSE); 5894 curbuf->b_p_tw = tw_save; 5895 #ifdef FEAT_RIGHTLEFT 5896 revins_chars++; 5897 revins_legal++; 5898 #endif 5899 c = Ctrl_V; // pretend CTRL-V is last character 5900 auto_format(FALSE, TRUE); 5901 } 5902 } 5903 return c; 5904 } 5905 5906 /* 5907 * Get the value that w_virtcol would have when 'list' is off. 5908 * Unless 'cpo' contains the 'L' flag. 5909 */ 5910 colnr_T 5911 get_nolist_virtcol(void) 5912 { 5913 // check validity of cursor in current buffer 5914 if (curwin->w_buffer == NULL 5915 || curwin->w_buffer->b_ml.ml_mfp == NULL 5916 || curwin->w_cursor.lnum > curwin->w_buffer->b_ml.ml_line_count) 5917 return 0; 5918 if (curwin->w_p_list && vim_strchr(p_cpo, CPO_LISTWM) == NULL) 5919 return getvcol_nolist(&curwin->w_cursor); 5920 validate_virtcol(); 5921 return curwin->w_virtcol; 5922 } 5923 5924 #if defined(FEAT_EVAL) 5925 /* 5926 * Handle the InsertCharPre autocommand. 5927 * "c" is the character that was typed. 5928 * Return a pointer to allocated memory with the replacement string. 5929 * Return NULL to continue inserting "c". 5930 */ 5931 static char_u * 5932 do_insert_char_pre(int c) 5933 { 5934 char_u *res; 5935 char_u buf[MB_MAXBYTES + 1]; 5936 int save_State = State; 5937 5938 // Return quickly when there is nothing to do. 5939 if (!has_insertcharpre()) 5940 return NULL; 5941 5942 if (has_mbyte) 5943 buf[(*mb_char2bytes)(c, buf)] = NUL; 5944 else 5945 { 5946 buf[0] = c; 5947 buf[1] = NUL; 5948 } 5949 5950 // Lock the text to avoid weird things from happening. 5951 ++textlock; 5952 set_vim_var_string(VV_CHAR, buf, -1); // set v:char 5953 5954 res = NULL; 5955 if (ins_apply_autocmds(EVENT_INSERTCHARPRE)) 5956 { 5957 // Get the value of v:char. It may be empty or more than one 5958 // character. Only use it when changed, otherwise continue with the 5959 // original character to avoid breaking autoindent. 5960 if (STRCMP(buf, get_vim_var_str(VV_CHAR)) != 0) 5961 res = vim_strsave(get_vim_var_str(VV_CHAR)); 5962 } 5963 5964 set_vim_var_string(VV_CHAR, NULL, -1); // clear v:char 5965 --textlock; 5966 5967 // Restore the State, it may have been changed. 5968 State = save_State; 5969 5970 return res; 5971 } 5972 #endif 5973 5974 #if defined(FEAT_CINDENT) || defined(PROTO) 5975 int 5976 get_can_cindent(void) 5977 { 5978 return can_cindent; 5979 } 5980 5981 void 5982 set_can_cindent(int val) 5983 { 5984 can_cindent = val; 5985 } 5986 #endif 5987 5988 /* 5989 * Trigger "event" and take care of fixing undo. 5990 */ 5991 int 5992 ins_apply_autocmds(event_T event) 5993 { 5994 varnumber_T tick = CHANGEDTICK(curbuf); 5995 int r; 5996 5997 r = apply_autocmds(event, NULL, NULL, FALSE, curbuf); 5998 5999 // If u_savesub() was called then we are not prepared to start 6000 // a new line. Call u_save() with no contents to fix that. 6001 if (tick != CHANGEDTICK(curbuf)) 6002 u_save(curwin->w_cursor.lnum, (linenr_T)(curwin->w_cursor.lnum + 1)); 6003 6004 return r; 6005 } 6006