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