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