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 // When recording or for CTRL-O, need to display the new mode. 4562 // Otherwise remove the mode message. 4563 if (reg_recording != 0 || restart_edit != NUL) 4564 showmode(); 4565 else if (p_smd && (got_int || !skip_showmode())) 4566 msg(""); 4567 4568 return TRUE; /* exit Insert mode */ 4569 } 4570 4571 #ifdef FEAT_RIGHTLEFT 4572 /* 4573 * Toggle language: hkmap and revins_on. 4574 * Move to end of reverse inserted text. 4575 */ 4576 static void 4577 ins_ctrl_(void) 4578 { 4579 if (revins_on && revins_chars && revins_scol >= 0) 4580 { 4581 while (gchar_cursor() != NUL && revins_chars--) 4582 ++curwin->w_cursor.col; 4583 } 4584 p_ri = !p_ri; 4585 revins_on = (State == INSERT && p_ri); 4586 if (revins_on) 4587 { 4588 revins_scol = curwin->w_cursor.col; 4589 revins_legal++; 4590 revins_chars = 0; 4591 undisplay_dollar(); 4592 } 4593 else 4594 revins_scol = -1; 4595 p_hkmap = curwin->w_p_rl ^ p_ri; // be consistent! 4596 showmode(); 4597 } 4598 #endif 4599 4600 /* 4601 * If 'keymodel' contains "startsel", may start selection. 4602 * Returns TRUE when a CTRL-O and other keys stuffed. 4603 */ 4604 static int 4605 ins_start_select(int c) 4606 { 4607 if (km_startsel) 4608 switch (c) 4609 { 4610 case K_KHOME: 4611 case K_KEND: 4612 case K_PAGEUP: 4613 case K_KPAGEUP: 4614 case K_PAGEDOWN: 4615 case K_KPAGEDOWN: 4616 # ifdef MACOS_X 4617 case K_LEFT: 4618 case K_RIGHT: 4619 case K_UP: 4620 case K_DOWN: 4621 case K_END: 4622 case K_HOME: 4623 # endif 4624 if (!(mod_mask & MOD_MASK_SHIFT)) 4625 break; 4626 /* FALLTHROUGH */ 4627 case K_S_LEFT: 4628 case K_S_RIGHT: 4629 case K_S_UP: 4630 case K_S_DOWN: 4631 case K_S_END: 4632 case K_S_HOME: 4633 /* Start selection right away, the cursor can move with 4634 * CTRL-O when beyond the end of the line. */ 4635 start_selection(); 4636 4637 /* Execute the key in (insert) Select mode. */ 4638 stuffcharReadbuff(Ctrl_O); 4639 if (mod_mask) 4640 { 4641 char_u buf[4]; 4642 4643 buf[0] = K_SPECIAL; 4644 buf[1] = KS_MODIFIER; 4645 buf[2] = mod_mask; 4646 buf[3] = NUL; 4647 stuffReadbuff(buf); 4648 } 4649 stuffcharReadbuff(c); 4650 return TRUE; 4651 } 4652 return FALSE; 4653 } 4654 4655 /* 4656 * <Insert> key in Insert mode: toggle insert/replace mode. 4657 */ 4658 static void 4659 ins_insert(int replaceState) 4660 { 4661 #ifdef FEAT_EVAL 4662 set_vim_var_string(VV_INSERTMODE, 4663 (char_u *)((State & REPLACE_FLAG) ? "i" 4664 : replaceState == VREPLACE ? "v" 4665 : "r"), 1); 4666 #endif 4667 ins_apply_autocmds(EVENT_INSERTCHANGE); 4668 if (State & REPLACE_FLAG) 4669 State = INSERT | (State & LANGMAP); 4670 else 4671 State = replaceState | (State & LANGMAP); 4672 AppendCharToRedobuff(K_INS); 4673 showmode(); 4674 #ifdef CURSOR_SHAPE 4675 ui_cursor_shape(); /* may show different cursor shape */ 4676 #endif 4677 } 4678 4679 /* 4680 * Pressed CTRL-O in Insert mode. 4681 */ 4682 static void 4683 ins_ctrl_o(void) 4684 { 4685 if (State & VREPLACE_FLAG) 4686 restart_edit = 'V'; 4687 else 4688 if (State & REPLACE_FLAG) 4689 restart_edit = 'R'; 4690 else 4691 restart_edit = 'I'; 4692 if (virtual_active()) 4693 ins_at_eol = FALSE; /* cursor always keeps its column */ 4694 else 4695 ins_at_eol = (gchar_cursor() == NUL); 4696 } 4697 4698 /* 4699 * If the cursor is on an indent, ^T/^D insert/delete one 4700 * shiftwidth. Otherwise ^T/^D behave like a "<<" or ">>". 4701 * Always round the indent to 'shiftwidth', this is compatible 4702 * with vi. But vi only supports ^T and ^D after an 4703 * autoindent, we support it everywhere. 4704 */ 4705 static void 4706 ins_shift(int c, int lastc) 4707 { 4708 if (stop_arrow() == FAIL) 4709 return; 4710 AppendCharToRedobuff(c); 4711 4712 /* 4713 * 0^D and ^^D: remove all indent. 4714 */ 4715 if (c == Ctrl_D && (lastc == '0' || lastc == '^') 4716 && curwin->w_cursor.col > 0) 4717 { 4718 --curwin->w_cursor.col; 4719 (void)del_char(FALSE); /* delete the '^' or '0' */ 4720 /* In Replace mode, restore the characters that '^' or '0' replaced. */ 4721 if (State & REPLACE_FLAG) 4722 replace_pop_ins(); 4723 if (lastc == '^') 4724 old_indent = get_indent(); /* remember curr. indent */ 4725 change_indent(INDENT_SET, 0, TRUE, 0, TRUE); 4726 } 4727 else 4728 change_indent(c == Ctrl_D ? INDENT_DEC : INDENT_INC, 0, TRUE, 0, TRUE); 4729 4730 if (did_ai && *skipwhite(ml_get_curline()) != NUL) 4731 did_ai = FALSE; 4732 #ifdef FEAT_SMARTINDENT 4733 did_si = FALSE; 4734 can_si = FALSE; 4735 can_si_back = FALSE; 4736 #endif 4737 #ifdef FEAT_CINDENT 4738 can_cindent = FALSE; /* no cindenting after ^D or ^T */ 4739 #endif 4740 } 4741 4742 static void 4743 ins_del(void) 4744 { 4745 int temp; 4746 4747 if (stop_arrow() == FAIL) 4748 return; 4749 if (gchar_cursor() == NUL) /* delete newline */ 4750 { 4751 temp = curwin->w_cursor.col; 4752 if (!can_bs(BS_EOL) /* only if "eol" included */ 4753 || do_join(2, FALSE, TRUE, FALSE, FALSE) == FAIL) 4754 vim_beep(BO_BS); 4755 else 4756 { 4757 curwin->w_cursor.col = temp; 4758 /* Adjust orig_line_count in case more lines have been deleted than 4759 * have been added. That makes sure, that open_line() later 4760 * can access all buffer lines correctly */ 4761 if (State & VREPLACE_FLAG && 4762 orig_line_count > curbuf->b_ml.ml_line_count) 4763 orig_line_count = curbuf->b_ml.ml_line_count; 4764 } 4765 } 4766 else if (del_char(FALSE) == FAIL) /* delete char under cursor */ 4767 vim_beep(BO_BS); 4768 did_ai = FALSE; 4769 #ifdef FEAT_SMARTINDENT 4770 did_si = FALSE; 4771 can_si = FALSE; 4772 can_si_back = FALSE; 4773 #endif 4774 AppendCharToRedobuff(K_DEL); 4775 } 4776 4777 /* 4778 * Delete one character for ins_bs(). 4779 */ 4780 static void 4781 ins_bs_one(colnr_T *vcolp) 4782 { 4783 dec_cursor(); 4784 getvcol(curwin, &curwin->w_cursor, vcolp, NULL, NULL); 4785 if (State & REPLACE_FLAG) 4786 { 4787 /* Don't delete characters before the insert point when in 4788 * Replace mode */ 4789 if (curwin->w_cursor.lnum != Insstart.lnum 4790 || curwin->w_cursor.col >= Insstart.col) 4791 replace_do_bs(-1); 4792 } 4793 else 4794 (void)del_char(FALSE); 4795 } 4796 4797 /* 4798 * Handle Backspace, delete-word and delete-line in Insert mode. 4799 * Return TRUE when backspace was actually used. 4800 */ 4801 static int 4802 ins_bs( 4803 int c, 4804 int mode, 4805 int *inserted_space_p) 4806 { 4807 linenr_T lnum; 4808 int cc; 4809 int temp = 0; /* init for GCC */ 4810 colnr_T save_col; 4811 colnr_T mincol; 4812 int did_backspace = FALSE; 4813 int in_indent; 4814 int oldState; 4815 int cpc[MAX_MCO]; /* composing characters */ 4816 4817 /* 4818 * can't delete anything in an empty file 4819 * can't backup past first character in buffer 4820 * can't backup past starting point unless 'backspace' > 1 4821 * can backup to a previous line if 'backspace' == 0 4822 */ 4823 if ( BUFEMPTY() 4824 || ( 4825 #ifdef FEAT_RIGHTLEFT 4826 !revins_on && 4827 #endif 4828 ((curwin->w_cursor.lnum == 1 && curwin->w_cursor.col == 0) 4829 || (!can_bs(BS_START) 4830 && (arrow_used 4831 || (curwin->w_cursor.lnum == Insstart_orig.lnum 4832 && curwin->w_cursor.col <= Insstart_orig.col))) 4833 || (!can_bs(BS_INDENT) && !arrow_used && ai_col > 0 4834 && curwin->w_cursor.col <= ai_col) 4835 || (!can_bs(BS_EOL) && curwin->w_cursor.col == 0)))) 4836 { 4837 vim_beep(BO_BS); 4838 return FALSE; 4839 } 4840 4841 if (stop_arrow() == FAIL) 4842 return FALSE; 4843 in_indent = inindent(0); 4844 #ifdef FEAT_CINDENT 4845 if (in_indent) 4846 can_cindent = FALSE; 4847 #endif 4848 #ifdef FEAT_COMMENTS 4849 end_comment_pending = NUL; /* After BS, don't auto-end comment */ 4850 #endif 4851 #ifdef FEAT_RIGHTLEFT 4852 if (revins_on) /* put cursor after last inserted char */ 4853 inc_cursor(); 4854 #endif 4855 4856 /* Virtualedit: 4857 * BACKSPACE_CHAR eats a virtual space 4858 * BACKSPACE_WORD eats all coladd 4859 * BACKSPACE_LINE eats all coladd and keeps going 4860 */ 4861 if (curwin->w_cursor.coladd > 0) 4862 { 4863 if (mode == BACKSPACE_CHAR) 4864 { 4865 --curwin->w_cursor.coladd; 4866 return TRUE; 4867 } 4868 if (mode == BACKSPACE_WORD) 4869 { 4870 curwin->w_cursor.coladd = 0; 4871 return TRUE; 4872 } 4873 curwin->w_cursor.coladd = 0; 4874 } 4875 4876 /* 4877 * Delete newline! 4878 */ 4879 if (curwin->w_cursor.col == 0) 4880 { 4881 lnum = Insstart.lnum; 4882 if (curwin->w_cursor.lnum == lnum 4883 #ifdef FEAT_RIGHTLEFT 4884 || revins_on 4885 #endif 4886 ) 4887 { 4888 if (u_save((linenr_T)(curwin->w_cursor.lnum - 2), 4889 (linenr_T)(curwin->w_cursor.lnum + 1)) == FAIL) 4890 return FALSE; 4891 --Insstart.lnum; 4892 Insstart.col = (colnr_T)STRLEN(ml_get(Insstart.lnum)); 4893 } 4894 /* 4895 * In replace mode: 4896 * cc < 0: NL was inserted, delete it 4897 * cc >= 0: NL was replaced, put original characters back 4898 */ 4899 cc = -1; 4900 if (State & REPLACE_FLAG) 4901 cc = replace_pop(); /* returns -1 if NL was inserted */ 4902 /* 4903 * In replace mode, in the line we started replacing, we only move the 4904 * cursor. 4905 */ 4906 if ((State & REPLACE_FLAG) && curwin->w_cursor.lnum <= lnum) 4907 { 4908 dec_cursor(); 4909 } 4910 else 4911 { 4912 if (!(State & VREPLACE_FLAG) 4913 || curwin->w_cursor.lnum > orig_line_count) 4914 { 4915 temp = gchar_cursor(); /* remember current char */ 4916 --curwin->w_cursor.lnum; 4917 4918 /* When "aw" is in 'formatoptions' we must delete the space at 4919 * the end of the line, otherwise the line will be broken 4920 * again when auto-formatting. */ 4921 if (has_format_option(FO_AUTO) 4922 && has_format_option(FO_WHITE_PAR)) 4923 { 4924 char_u *ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum, 4925 TRUE); 4926 int len; 4927 4928 len = (int)STRLEN(ptr); 4929 if (len > 0 && ptr[len - 1] == ' ') 4930 ptr[len - 1] = NUL; 4931 } 4932 4933 (void)do_join(2, FALSE, FALSE, FALSE, FALSE); 4934 if (temp == NUL && gchar_cursor() != NUL) 4935 inc_cursor(); 4936 } 4937 else 4938 dec_cursor(); 4939 4940 /* 4941 * In REPLACE mode we have to put back the text that was replaced 4942 * by the NL. On the replace stack is first a NUL-terminated 4943 * sequence of characters that were deleted and then the 4944 * characters that NL replaced. 4945 */ 4946 if (State & REPLACE_FLAG) 4947 { 4948 /* 4949 * Do the next ins_char() in NORMAL state, to 4950 * prevent ins_char() from replacing characters and 4951 * avoiding showmatch(). 4952 */ 4953 oldState = State; 4954 State = NORMAL; 4955 /* 4956 * restore characters (blanks) deleted after cursor 4957 */ 4958 while (cc > 0) 4959 { 4960 save_col = curwin->w_cursor.col; 4961 mb_replace_pop_ins(cc); 4962 curwin->w_cursor.col = save_col; 4963 cc = replace_pop(); 4964 } 4965 /* restore the characters that NL replaced */ 4966 replace_pop_ins(); 4967 State = oldState; 4968 } 4969 } 4970 did_ai = FALSE; 4971 } 4972 else 4973 { 4974 /* 4975 * Delete character(s) before the cursor. 4976 */ 4977 #ifdef FEAT_RIGHTLEFT 4978 if (revins_on) /* put cursor on last inserted char */ 4979 dec_cursor(); 4980 #endif 4981 mincol = 0; 4982 /* keep indent */ 4983 if (mode == BACKSPACE_LINE 4984 && (curbuf->b_p_ai 4985 #ifdef FEAT_CINDENT 4986 || cindent_on() 4987 #endif 4988 ) 4989 #ifdef FEAT_RIGHTLEFT 4990 && !revins_on 4991 #endif 4992 ) 4993 { 4994 save_col = curwin->w_cursor.col; 4995 beginline(BL_WHITE); 4996 if (curwin->w_cursor.col < save_col) 4997 mincol = curwin->w_cursor.col; 4998 curwin->w_cursor.col = save_col; 4999 } 5000 5001 /* 5002 * Handle deleting one 'shiftwidth' or 'softtabstop'. 5003 */ 5004 if ( mode == BACKSPACE_CHAR 5005 && ((p_sta && in_indent) 5006 || ((get_sts_value() != 0 5007 #ifdef FEAT_VARTABS 5008 || tabstop_count(curbuf->b_p_vsts_array) 5009 #endif 5010 ) 5011 && curwin->w_cursor.col > 0 5012 && (*(ml_get_cursor() - 1) == TAB 5013 || (*(ml_get_cursor() - 1) == ' ' 5014 && (!*inserted_space_p 5015 || arrow_used)))))) 5016 { 5017 int ts; 5018 colnr_T vcol; 5019 colnr_T want_vcol; 5020 colnr_T start_vcol; 5021 5022 *inserted_space_p = FALSE; 5023 /* Compute the virtual column where we want to be. Since 5024 * 'showbreak' may get in the way, need to get the last column of 5025 * the previous character. */ 5026 getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL); 5027 start_vcol = vcol; 5028 dec_cursor(); 5029 getvcol(curwin, &curwin->w_cursor, NULL, NULL, &want_vcol); 5030 inc_cursor(); 5031 #ifdef FEAT_VARTABS 5032 if (p_sta && in_indent) 5033 { 5034 ts = (int)get_sw_value(curbuf); 5035 want_vcol = (want_vcol / ts) * ts; 5036 } 5037 else 5038 want_vcol = tabstop_start(want_vcol, get_sts_value(), 5039 curbuf->b_p_vsts_array); 5040 #else 5041 if (p_sta && in_indent) 5042 ts = (int)get_sw_value(curbuf); 5043 else 5044 ts = (int)get_sts_value(); 5045 want_vcol = (want_vcol / ts) * ts; 5046 #endif 5047 5048 /* delete characters until we are at or before want_vcol */ 5049 while (vcol > want_vcol 5050 && (cc = *(ml_get_cursor() - 1), VIM_ISWHITE(cc))) 5051 ins_bs_one(&vcol); 5052 5053 /* insert extra spaces until we are at want_vcol */ 5054 while (vcol < want_vcol) 5055 { 5056 /* Remember the first char we inserted */ 5057 if (curwin->w_cursor.lnum == Insstart_orig.lnum 5058 && curwin->w_cursor.col < Insstart_orig.col) 5059 Insstart_orig.col = curwin->w_cursor.col; 5060 5061 if (State & VREPLACE_FLAG) 5062 ins_char(' '); 5063 else 5064 { 5065 ins_str((char_u *)" "); 5066 if ((State & REPLACE_FLAG)) 5067 replace_push(NUL); 5068 } 5069 getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL); 5070 } 5071 5072 /* If we are now back where we started delete one character. Can 5073 * happen when using 'sts' and 'linebreak'. */ 5074 if (vcol >= start_vcol) 5075 ins_bs_one(&vcol); 5076 } 5077 5078 /* 5079 * Delete upto starting point, start of line or previous word. 5080 */ 5081 else 5082 { 5083 int cclass = 0, prev_cclass = 0; 5084 5085 if (has_mbyte) 5086 cclass = mb_get_class(ml_get_cursor()); 5087 do 5088 { 5089 #ifdef FEAT_RIGHTLEFT 5090 if (!revins_on) /* put cursor on char to be deleted */ 5091 #endif 5092 dec_cursor(); 5093 5094 cc = gchar_cursor(); 5095 /* look multi-byte character class */ 5096 if (has_mbyte) 5097 { 5098 prev_cclass = cclass; 5099 cclass = mb_get_class(ml_get_cursor()); 5100 } 5101 5102 /* start of word? */ 5103 if (mode == BACKSPACE_WORD && !vim_isspace(cc)) 5104 { 5105 mode = BACKSPACE_WORD_NOT_SPACE; 5106 temp = vim_iswordc(cc); 5107 } 5108 /* end of word? */ 5109 else if (mode == BACKSPACE_WORD_NOT_SPACE 5110 && ((vim_isspace(cc) || vim_iswordc(cc) != temp) 5111 || prev_cclass != cclass)) 5112 { 5113 #ifdef FEAT_RIGHTLEFT 5114 if (!revins_on) 5115 #endif 5116 inc_cursor(); 5117 #ifdef FEAT_RIGHTLEFT 5118 else if (State & REPLACE_FLAG) 5119 dec_cursor(); 5120 #endif 5121 break; 5122 } 5123 if (State & REPLACE_FLAG) 5124 replace_do_bs(-1); 5125 else 5126 { 5127 if (enc_utf8 && p_deco) 5128 (void)utfc_ptr2char(ml_get_cursor(), cpc); 5129 (void)del_char(FALSE); 5130 /* 5131 * If there are combining characters and 'delcombine' is set 5132 * move the cursor back. Don't back up before the base 5133 * character. 5134 */ 5135 if (enc_utf8 && p_deco && cpc[0] != NUL) 5136 inc_cursor(); 5137 #ifdef FEAT_RIGHTLEFT 5138 if (revins_chars) 5139 { 5140 revins_chars--; 5141 revins_legal++; 5142 } 5143 if (revins_on && gchar_cursor() == NUL) 5144 break; 5145 #endif 5146 } 5147 /* Just a single backspace?: */ 5148 if (mode == BACKSPACE_CHAR) 5149 break; 5150 } while ( 5151 #ifdef FEAT_RIGHTLEFT 5152 revins_on || 5153 #endif 5154 (curwin->w_cursor.col > mincol 5155 && (curwin->w_cursor.lnum != Insstart_orig.lnum 5156 || curwin->w_cursor.col != Insstart_orig.col))); 5157 } 5158 did_backspace = TRUE; 5159 } 5160 #ifdef FEAT_SMARTINDENT 5161 did_si = FALSE; 5162 can_si = FALSE; 5163 can_si_back = FALSE; 5164 #endif 5165 if (curwin->w_cursor.col <= 1) 5166 did_ai = FALSE; 5167 /* 5168 * It's a little strange to put backspaces into the redo 5169 * buffer, but it makes auto-indent a lot easier to deal 5170 * with. 5171 */ 5172 AppendCharToRedobuff(c); 5173 5174 /* If deleted before the insertion point, adjust it */ 5175 if (curwin->w_cursor.lnum == Insstart_orig.lnum 5176 && curwin->w_cursor.col < Insstart_orig.col) 5177 Insstart_orig.col = curwin->w_cursor.col; 5178 5179 /* vi behaviour: the cursor moves backward but the character that 5180 * was there remains visible 5181 * Vim behaviour: the cursor moves backward and the character that 5182 * was there is erased from the screen. 5183 * We can emulate the vi behaviour by pretending there is a dollar 5184 * displayed even when there isn't. 5185 * --pkv Sun Jan 19 01:56:40 EST 2003 */ 5186 if (vim_strchr(p_cpo, CPO_BACKSPACE) != NULL && dollar_vcol == -1) 5187 dollar_vcol = curwin->w_virtcol; 5188 5189 #ifdef FEAT_FOLDING 5190 /* When deleting a char the cursor line must never be in a closed fold. 5191 * E.g., when 'foldmethod' is indent and deleting the first non-white 5192 * char before a Tab. */ 5193 if (did_backspace) 5194 foldOpenCursor(); 5195 #endif 5196 5197 return did_backspace; 5198 } 5199 5200 #ifdef FEAT_MOUSE 5201 static void 5202 ins_mouse(int c) 5203 { 5204 pos_T tpos; 5205 win_T *old_curwin = curwin; 5206 5207 # ifdef FEAT_GUI 5208 /* When GUI is active, also move/paste when 'mouse' is empty */ 5209 if (!gui.in_use) 5210 # endif 5211 if (!mouse_has(MOUSE_INSERT)) 5212 return; 5213 5214 undisplay_dollar(); 5215 tpos = curwin->w_cursor; 5216 if (do_mouse(NULL, c, BACKWARD, 1L, 0)) 5217 { 5218 win_T *new_curwin = curwin; 5219 5220 if (curwin != old_curwin && win_valid(old_curwin)) 5221 { 5222 /* Mouse took us to another window. We need to go back to the 5223 * previous one to stop insert there properly. */ 5224 curwin = old_curwin; 5225 curbuf = curwin->w_buffer; 5226 #ifdef FEAT_JOB_CHANNEL 5227 if (bt_prompt(curbuf)) 5228 // Restart Insert mode when re-entering the prompt buffer. 5229 curbuf->b_prompt_insert = 'A'; 5230 #endif 5231 } 5232 start_arrow(curwin == old_curwin ? &tpos : NULL); 5233 if (curwin != new_curwin && win_valid(new_curwin)) 5234 { 5235 curwin = new_curwin; 5236 curbuf = curwin->w_buffer; 5237 } 5238 # ifdef FEAT_CINDENT 5239 can_cindent = TRUE; 5240 # endif 5241 } 5242 5243 /* redraw status lines (in case another window became active) */ 5244 redraw_statuslines(); 5245 } 5246 5247 static void 5248 ins_mousescroll(int dir) 5249 { 5250 pos_T tpos; 5251 win_T *old_curwin = curwin, *wp; 5252 # ifdef FEAT_INS_EXPAND 5253 int did_scroll = FALSE; 5254 # endif 5255 5256 tpos = curwin->w_cursor; 5257 5258 if (mouse_row >= 0 && mouse_col >= 0) 5259 { 5260 int row, col; 5261 5262 row = mouse_row; 5263 col = mouse_col; 5264 5265 /* find the window at the pointer coordinates */ 5266 wp = mouse_find_win(&row, &col); 5267 if (wp == NULL) 5268 return; 5269 curwin = wp; 5270 curbuf = curwin->w_buffer; 5271 } 5272 if (curwin == old_curwin) 5273 undisplay_dollar(); 5274 5275 # ifdef FEAT_INS_EXPAND 5276 /* Don't scroll the window in which completion is being done. */ 5277 if (!pum_visible() || curwin != old_curwin) 5278 # endif 5279 { 5280 if (dir == MSCR_DOWN || dir == MSCR_UP) 5281 { 5282 if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)) 5283 scroll_redraw(dir, 5284 (long)(curwin->w_botline - curwin->w_topline)); 5285 else 5286 scroll_redraw(dir, 3L); 5287 } 5288 #ifdef FEAT_GUI 5289 else 5290 { 5291 int val, step = 6; 5292 5293 if (mod_mask & (MOD_MASK_SHIFT | MOD_MASK_CTRL)) 5294 step = curwin->w_width; 5295 val = curwin->w_leftcol + (dir == MSCR_RIGHT ? -step : step); 5296 if (val < 0) 5297 val = 0; 5298 gui_do_horiz_scroll(val, TRUE); 5299 } 5300 #endif 5301 # ifdef FEAT_INS_EXPAND 5302 did_scroll = TRUE; 5303 # endif 5304 } 5305 5306 curwin->w_redr_status = TRUE; 5307 5308 curwin = old_curwin; 5309 curbuf = curwin->w_buffer; 5310 5311 # ifdef FEAT_INS_EXPAND 5312 /* The popup menu may overlay the window, need to redraw it. 5313 * TODO: Would be more efficient to only redraw the windows that are 5314 * overlapped by the popup menu. */ 5315 if (pum_visible() && did_scroll) 5316 { 5317 redraw_all_later(NOT_VALID); 5318 ins_compl_show_pum(); 5319 } 5320 # endif 5321 5322 if (!EQUAL_POS(curwin->w_cursor, tpos)) 5323 { 5324 start_arrow(&tpos); 5325 # ifdef FEAT_CINDENT 5326 can_cindent = TRUE; 5327 # endif 5328 } 5329 } 5330 #endif 5331 5332 /* 5333 * Handle receiving P_PS: start paste mode. Inserts the following text up to 5334 * P_PE literally. 5335 * When "drop" is TRUE then consume the text and drop it. 5336 */ 5337 int 5338 bracketed_paste(paste_mode_T mode, int drop, garray_T *gap) 5339 { 5340 int c; 5341 char_u buf[NUMBUFLEN + MB_MAXBYTES]; 5342 int idx = 0; 5343 char_u *end = find_termcode((char_u *)"PE"); 5344 int ret_char = -1; 5345 int save_allow_keys = allow_keys; 5346 int save_paste = p_paste; 5347 5348 /* If the end code is too long we can't detect it, read everything. */ 5349 if (STRLEN(end) >= NUMBUFLEN) 5350 end = NULL; 5351 ++no_mapping; 5352 allow_keys = 0; 5353 if (!p_paste) 5354 // Also have the side effects of setting 'paste' to make it work much 5355 // faster. 5356 set_option_value((char_u *)"paste", TRUE, NULL, 0); 5357 5358 for (;;) 5359 { 5360 // When the end is not defined read everything there is. 5361 if (end == NULL && vpeekc() == NUL) 5362 break; 5363 do 5364 c = vgetc(); 5365 while (c == K_IGNORE || c == K_VER_SCROLLBAR || c == K_HOR_SCROLLBAR); 5366 if (c == NUL || got_int) 5367 // When CTRL-C was encountered the typeahead will be flushed and we 5368 // won't get the end sequence. 5369 break; 5370 5371 if (has_mbyte) 5372 idx += (*mb_char2bytes)(c, buf + idx); 5373 else 5374 buf[idx++] = c; 5375 buf[idx] = NUL; 5376 if (end != NULL && STRNCMP(buf, end, idx) == 0) 5377 { 5378 if (end[idx] == NUL) 5379 break; /* Found the end of paste code. */ 5380 continue; 5381 } 5382 if (!drop) 5383 { 5384 switch (mode) 5385 { 5386 case PASTE_CMDLINE: 5387 put_on_cmdline(buf, idx, TRUE); 5388 break; 5389 5390 case PASTE_EX: 5391 if (gap != NULL && ga_grow(gap, idx) == OK) 5392 { 5393 mch_memmove((char *)gap->ga_data + gap->ga_len, 5394 buf, (size_t)idx); 5395 gap->ga_len += idx; 5396 } 5397 break; 5398 5399 case PASTE_INSERT: 5400 if (stop_arrow() == OK) 5401 { 5402 c = buf[0]; 5403 if (idx == 1 && (c == CAR || c == K_KENTER || c == NL)) 5404 ins_eol(c); 5405 else 5406 { 5407 ins_char_bytes(buf, idx); 5408 AppendToRedobuffLit(buf, idx); 5409 } 5410 } 5411 break; 5412 5413 case PASTE_ONE_CHAR: 5414 if (ret_char == -1) 5415 { 5416 if (has_mbyte) 5417 ret_char = (*mb_ptr2char)(buf); 5418 else 5419 ret_char = buf[0]; 5420 } 5421 break; 5422 } 5423 } 5424 idx = 0; 5425 } 5426 5427 --no_mapping; 5428 allow_keys = save_allow_keys; 5429 if (!save_paste) 5430 set_option_value((char_u *)"paste", FALSE, NULL, 0); 5431 5432 return ret_char; 5433 } 5434 5435 #if defined(FEAT_GUI_TABLINE) || defined(PROTO) 5436 static void 5437 ins_tabline(int c) 5438 { 5439 /* We will be leaving the current window, unless closing another tab. */ 5440 if (c != K_TABMENU || current_tabmenu != TABLINE_MENU_CLOSE 5441 || (current_tab != 0 && current_tab != tabpage_index(curtab))) 5442 { 5443 undisplay_dollar(); 5444 start_arrow(&curwin->w_cursor); 5445 # ifdef FEAT_CINDENT 5446 can_cindent = TRUE; 5447 # endif 5448 } 5449 5450 if (c == K_TABLINE) 5451 goto_tabpage(current_tab); 5452 else 5453 { 5454 handle_tabmenu(); 5455 redraw_statuslines(); /* will redraw the tabline when needed */ 5456 } 5457 } 5458 #endif 5459 5460 #if defined(FEAT_GUI) || defined(PROTO) 5461 void 5462 ins_scroll(void) 5463 { 5464 pos_T tpos; 5465 5466 undisplay_dollar(); 5467 tpos = curwin->w_cursor; 5468 if (gui_do_scroll()) 5469 { 5470 start_arrow(&tpos); 5471 # ifdef FEAT_CINDENT 5472 can_cindent = TRUE; 5473 # endif 5474 } 5475 } 5476 5477 void 5478 ins_horscroll(void) 5479 { 5480 pos_T tpos; 5481 5482 undisplay_dollar(); 5483 tpos = curwin->w_cursor; 5484 if (gui_do_horiz_scroll(scrollbar_value, FALSE)) 5485 { 5486 start_arrow(&tpos); 5487 # ifdef FEAT_CINDENT 5488 can_cindent = TRUE; 5489 # endif 5490 } 5491 } 5492 #endif 5493 5494 static void 5495 ins_left(void) 5496 { 5497 pos_T tpos; 5498 int end_change = dont_sync_undo == FALSE; // end undoable change 5499 5500 #ifdef FEAT_FOLDING 5501 if ((fdo_flags & FDO_HOR) && KeyTyped) 5502 foldOpenCursor(); 5503 #endif 5504 undisplay_dollar(); 5505 tpos = curwin->w_cursor; 5506 if (oneleft() == OK) 5507 { 5508 #if defined(FEAT_XIM) && defined(FEAT_GUI_GTK) 5509 /* Only call start_arrow() when not busy with preediting, it will 5510 * break undo. K_LEFT is inserted in im_correct_cursor(). */ 5511 if (p_imst == IM_OVER_THE_SPOT || !im_is_preediting()) 5512 #endif 5513 { 5514 start_arrow_with_change(&tpos, end_change); 5515 if (!end_change) 5516 AppendCharToRedobuff(K_LEFT); 5517 } 5518 #ifdef FEAT_RIGHTLEFT 5519 /* If exit reversed string, position is fixed */ 5520 if (revins_scol != -1 && (int)curwin->w_cursor.col >= revins_scol) 5521 revins_legal++; 5522 revins_chars++; 5523 #endif 5524 } 5525 5526 /* 5527 * if 'whichwrap' set for cursor in insert mode may go to 5528 * previous line 5529 */ 5530 else if (vim_strchr(p_ww, '[') != NULL && curwin->w_cursor.lnum > 1) 5531 { 5532 /* always break undo when moving upwards/downwards, else undo may break */ 5533 start_arrow(&tpos); 5534 --(curwin->w_cursor.lnum); 5535 coladvance((colnr_T)MAXCOL); 5536 curwin->w_set_curswant = TRUE; /* so we stay at the end */ 5537 } 5538 else 5539 vim_beep(BO_CRSR); 5540 dont_sync_undo = FALSE; 5541 } 5542 5543 static void 5544 ins_home(int c) 5545 { 5546 pos_T tpos; 5547 5548 #ifdef FEAT_FOLDING 5549 if ((fdo_flags & FDO_HOR) && KeyTyped) 5550 foldOpenCursor(); 5551 #endif 5552 undisplay_dollar(); 5553 tpos = curwin->w_cursor; 5554 if (c == K_C_HOME) 5555 curwin->w_cursor.lnum = 1; 5556 curwin->w_cursor.col = 0; 5557 curwin->w_cursor.coladd = 0; 5558 curwin->w_curswant = 0; 5559 start_arrow(&tpos); 5560 } 5561 5562 static void 5563 ins_end(int c) 5564 { 5565 pos_T tpos; 5566 5567 #ifdef FEAT_FOLDING 5568 if ((fdo_flags & FDO_HOR) && KeyTyped) 5569 foldOpenCursor(); 5570 #endif 5571 undisplay_dollar(); 5572 tpos = curwin->w_cursor; 5573 if (c == K_C_END) 5574 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; 5575 coladvance((colnr_T)MAXCOL); 5576 curwin->w_curswant = MAXCOL; 5577 5578 start_arrow(&tpos); 5579 } 5580 5581 static void 5582 ins_s_left() 5583 { 5584 int end_change = dont_sync_undo == FALSE; // end undoable change 5585 #ifdef FEAT_FOLDING 5586 if ((fdo_flags & FDO_HOR) && KeyTyped) 5587 foldOpenCursor(); 5588 #endif 5589 undisplay_dollar(); 5590 if (curwin->w_cursor.lnum > 1 || curwin->w_cursor.col > 0) 5591 { 5592 start_arrow_with_change(&curwin->w_cursor, end_change); 5593 if (!end_change) 5594 AppendCharToRedobuff(K_S_LEFT); 5595 (void)bck_word(1L, FALSE, FALSE); 5596 curwin->w_set_curswant = TRUE; 5597 } 5598 else 5599 vim_beep(BO_CRSR); 5600 dont_sync_undo = FALSE; 5601 } 5602 5603 static void 5604 ins_right(void) 5605 { 5606 int end_change = dont_sync_undo == FALSE; // end undoable change 5607 5608 #ifdef FEAT_FOLDING 5609 if ((fdo_flags & FDO_HOR) && KeyTyped) 5610 foldOpenCursor(); 5611 #endif 5612 undisplay_dollar(); 5613 if (gchar_cursor() != NUL || virtual_active()) 5614 { 5615 start_arrow_with_change(&curwin->w_cursor, end_change); 5616 if (!end_change) 5617 AppendCharToRedobuff(K_RIGHT); 5618 curwin->w_set_curswant = TRUE; 5619 if (virtual_active()) 5620 oneright(); 5621 else 5622 { 5623 if (has_mbyte) 5624 curwin->w_cursor.col += (*mb_ptr2len)(ml_get_cursor()); 5625 else 5626 ++curwin->w_cursor.col; 5627 } 5628 5629 #ifdef FEAT_RIGHTLEFT 5630 revins_legal++; 5631 if (revins_chars) 5632 revins_chars--; 5633 #endif 5634 } 5635 /* if 'whichwrap' set for cursor in insert mode, may move the 5636 * cursor to the next line */ 5637 else if (vim_strchr(p_ww, ']') != NULL 5638 && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) 5639 { 5640 start_arrow(&curwin->w_cursor); 5641 curwin->w_set_curswant = TRUE; 5642 ++curwin->w_cursor.lnum; 5643 curwin->w_cursor.col = 0; 5644 } 5645 else 5646 vim_beep(BO_CRSR); 5647 dont_sync_undo = FALSE; 5648 } 5649 5650 static void 5651 ins_s_right() 5652 { 5653 int end_change = dont_sync_undo == FALSE; // end undoable change 5654 #ifdef FEAT_FOLDING 5655 if ((fdo_flags & FDO_HOR) && KeyTyped) 5656 foldOpenCursor(); 5657 #endif 5658 undisplay_dollar(); 5659 if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count 5660 || gchar_cursor() != NUL) 5661 { 5662 start_arrow_with_change(&curwin->w_cursor, end_change); 5663 if (!end_change) 5664 AppendCharToRedobuff(K_S_RIGHT); 5665 (void)fwd_word(1L, FALSE, 0); 5666 curwin->w_set_curswant = TRUE; 5667 } 5668 else 5669 vim_beep(BO_CRSR); 5670 dont_sync_undo = FALSE; 5671 } 5672 5673 static void 5674 ins_up( 5675 int startcol) /* when TRUE move to Insstart.col */ 5676 { 5677 pos_T tpos; 5678 linenr_T old_topline = curwin->w_topline; 5679 #ifdef FEAT_DIFF 5680 int old_topfill = curwin->w_topfill; 5681 #endif 5682 5683 undisplay_dollar(); 5684 tpos = curwin->w_cursor; 5685 if (cursor_up(1L, TRUE) == OK) 5686 { 5687 if (startcol) 5688 coladvance(getvcol_nolist(&Insstart)); 5689 if (old_topline != curwin->w_topline 5690 #ifdef FEAT_DIFF 5691 || old_topfill != curwin->w_topfill 5692 #endif 5693 ) 5694 redraw_later(VALID); 5695 start_arrow(&tpos); 5696 #ifdef FEAT_CINDENT 5697 can_cindent = TRUE; 5698 #endif 5699 } 5700 else 5701 vim_beep(BO_CRSR); 5702 } 5703 5704 static void 5705 ins_pageup(void) 5706 { 5707 pos_T tpos; 5708 5709 undisplay_dollar(); 5710 5711 if (mod_mask & MOD_MASK_CTRL) 5712 { 5713 /* <C-PageUp>: tab page back */ 5714 if (first_tabpage->tp_next != NULL) 5715 { 5716 start_arrow(&curwin->w_cursor); 5717 goto_tabpage(-1); 5718 } 5719 return; 5720 } 5721 5722 tpos = curwin->w_cursor; 5723 if (onepage(BACKWARD, 1L) == OK) 5724 { 5725 start_arrow(&tpos); 5726 #ifdef FEAT_CINDENT 5727 can_cindent = TRUE; 5728 #endif 5729 } 5730 else 5731 vim_beep(BO_CRSR); 5732 } 5733 5734 static void 5735 ins_down( 5736 int startcol) /* when TRUE move to Insstart.col */ 5737 { 5738 pos_T tpos; 5739 linenr_T old_topline = curwin->w_topline; 5740 #ifdef FEAT_DIFF 5741 int old_topfill = curwin->w_topfill; 5742 #endif 5743 5744 undisplay_dollar(); 5745 tpos = curwin->w_cursor; 5746 if (cursor_down(1L, TRUE) == OK) 5747 { 5748 if (startcol) 5749 coladvance(getvcol_nolist(&Insstart)); 5750 if (old_topline != curwin->w_topline 5751 #ifdef FEAT_DIFF 5752 || old_topfill != curwin->w_topfill 5753 #endif 5754 ) 5755 redraw_later(VALID); 5756 start_arrow(&tpos); 5757 #ifdef FEAT_CINDENT 5758 can_cindent = TRUE; 5759 #endif 5760 } 5761 else 5762 vim_beep(BO_CRSR); 5763 } 5764 5765 static void 5766 ins_pagedown(void) 5767 { 5768 pos_T tpos; 5769 5770 undisplay_dollar(); 5771 5772 if (mod_mask & MOD_MASK_CTRL) 5773 { 5774 /* <C-PageDown>: tab page forward */ 5775 if (first_tabpage->tp_next != NULL) 5776 { 5777 start_arrow(&curwin->w_cursor); 5778 goto_tabpage(0); 5779 } 5780 return; 5781 } 5782 5783 tpos = curwin->w_cursor; 5784 if (onepage(FORWARD, 1L) == OK) 5785 { 5786 start_arrow(&tpos); 5787 #ifdef FEAT_CINDENT 5788 can_cindent = TRUE; 5789 #endif 5790 } 5791 else 5792 vim_beep(BO_CRSR); 5793 } 5794 5795 #ifdef FEAT_DND 5796 static void 5797 ins_drop(void) 5798 { 5799 do_put('~', BACKWARD, 1L, PUT_CURSEND); 5800 } 5801 #endif 5802 5803 /* 5804 * Handle TAB in Insert or Replace mode. 5805 * Return TRUE when the TAB needs to be inserted like a normal character. 5806 */ 5807 static int 5808 ins_tab(void) 5809 { 5810 int ind; 5811 int i; 5812 int temp; 5813 5814 if (Insstart_blank_vcol == MAXCOL && curwin->w_cursor.lnum == Insstart.lnum) 5815 Insstart_blank_vcol = get_nolist_virtcol(); 5816 if (echeck_abbr(TAB + ABBR_OFF)) 5817 return FALSE; 5818 5819 ind = inindent(0); 5820 #ifdef FEAT_CINDENT 5821 if (ind) 5822 can_cindent = FALSE; 5823 #endif 5824 5825 /* 5826 * When nothing special, insert TAB like a normal character. 5827 */ 5828 if (!curbuf->b_p_et 5829 #ifdef FEAT_VARTABS 5830 && !(p_sta && ind 5831 /* These five lines mean 'tabstop' != 'shiftwidth' */ 5832 && ((tabstop_count(curbuf->b_p_vts_array) > 1) 5833 || (tabstop_count(curbuf->b_p_vts_array) == 1 5834 && tabstop_first(curbuf->b_p_vts_array) 5835 != get_sw_value(curbuf)) 5836 || (tabstop_count(curbuf->b_p_vts_array) == 0 5837 && curbuf->b_p_ts != get_sw_value(curbuf)))) 5838 && tabstop_count(curbuf->b_p_vsts_array) == 0 5839 #else 5840 && !(p_sta && ind && curbuf->b_p_ts != get_sw_value(curbuf)) 5841 #endif 5842 && get_sts_value() == 0) 5843 return TRUE; 5844 5845 if (stop_arrow() == FAIL) 5846 return TRUE; 5847 5848 did_ai = FALSE; 5849 #ifdef FEAT_SMARTINDENT 5850 did_si = FALSE; 5851 can_si = FALSE; 5852 can_si_back = FALSE; 5853 #endif 5854 AppendToRedobuff((char_u *)"\t"); 5855 5856 #ifdef FEAT_VARTABS 5857 if (p_sta && ind) /* insert tab in indent, use 'shiftwidth' */ 5858 { 5859 temp = (int)get_sw_value(curbuf); 5860 temp -= get_nolist_virtcol() % temp; 5861 } 5862 else if (tabstop_count(curbuf->b_p_vsts_array) > 0 || curbuf->b_p_sts != 0) 5863 /* use 'softtabstop' when set */ 5864 temp = tabstop_padding(get_nolist_virtcol(), get_sts_value(), 5865 curbuf->b_p_vsts_array); 5866 else /* otherwise use 'tabstop' */ 5867 temp = tabstop_padding(get_nolist_virtcol(), curbuf->b_p_ts, 5868 curbuf->b_p_vts_array); 5869 #else 5870 if (p_sta && ind) /* insert tab in indent, use 'shiftwidth' */ 5871 temp = (int)get_sw_value(curbuf); 5872 else if (curbuf->b_p_sts != 0) /* use 'softtabstop' when set */ 5873 temp = (int)get_sts_value(); 5874 else /* otherwise use 'tabstop' */ 5875 temp = (int)curbuf->b_p_ts; 5876 temp -= get_nolist_virtcol() % temp; 5877 #endif 5878 5879 /* 5880 * Insert the first space with ins_char(). It will delete one char in 5881 * replace mode. Insert the rest with ins_str(); it will not delete any 5882 * chars. For VREPLACE mode, we use ins_char() for all characters. 5883 */ 5884 ins_char(' '); 5885 while (--temp > 0) 5886 { 5887 if (State & VREPLACE_FLAG) 5888 ins_char(' '); 5889 else 5890 { 5891 ins_str((char_u *)" "); 5892 if (State & REPLACE_FLAG) /* no char replaced */ 5893 replace_push(NUL); 5894 } 5895 } 5896 5897 /* 5898 * When 'expandtab' not set: Replace spaces by TABs where possible. 5899 */ 5900 #ifdef FEAT_VARTABS 5901 if (!curbuf->b_p_et && (tabstop_count(curbuf->b_p_vsts_array) > 0 5902 || get_sts_value() > 0 5903 || (p_sta && ind))) 5904 #else 5905 if (!curbuf->b_p_et && (get_sts_value() || (p_sta && ind))) 5906 #endif 5907 { 5908 char_u *ptr; 5909 char_u *saved_line = NULL; /* init for GCC */ 5910 pos_T pos; 5911 pos_T fpos; 5912 pos_T *cursor; 5913 colnr_T want_vcol, vcol; 5914 int change_col = -1; 5915 int save_list = curwin->w_p_list; 5916 5917 /* 5918 * Get the current line. For VREPLACE mode, don't make real changes 5919 * yet, just work on a copy of the line. 5920 */ 5921 if (State & VREPLACE_FLAG) 5922 { 5923 pos = curwin->w_cursor; 5924 cursor = &pos; 5925 saved_line = vim_strsave(ml_get_curline()); 5926 if (saved_line == NULL) 5927 return FALSE; 5928 ptr = saved_line + pos.col; 5929 } 5930 else 5931 { 5932 ptr = ml_get_cursor(); 5933 cursor = &curwin->w_cursor; 5934 } 5935 5936 /* When 'L' is not in 'cpoptions' a tab always takes up 'ts' spaces. */ 5937 if (vim_strchr(p_cpo, CPO_LISTWM) == NULL) 5938 curwin->w_p_list = FALSE; 5939 5940 /* Find first white before the cursor */ 5941 fpos = curwin->w_cursor; 5942 while (fpos.col > 0 && VIM_ISWHITE(ptr[-1])) 5943 { 5944 --fpos.col; 5945 --ptr; 5946 } 5947 5948 /* In Replace mode, don't change characters before the insert point. */ 5949 if ((State & REPLACE_FLAG) 5950 && fpos.lnum == Insstart.lnum 5951 && fpos.col < Insstart.col) 5952 { 5953 ptr += Insstart.col - fpos.col; 5954 fpos.col = Insstart.col; 5955 } 5956 5957 /* compute virtual column numbers of first white and cursor */ 5958 getvcol(curwin, &fpos, &vcol, NULL, NULL); 5959 getvcol(curwin, cursor, &want_vcol, NULL, NULL); 5960 5961 /* Use as many TABs as possible. Beware of 'breakindent', 'showbreak' 5962 * and 'linebreak' adding extra virtual columns. */ 5963 while (VIM_ISWHITE(*ptr)) 5964 { 5965 i = lbr_chartabsize(NULL, (char_u *)"\t", vcol); 5966 if (vcol + i > want_vcol) 5967 break; 5968 if (*ptr != TAB) 5969 { 5970 *ptr = TAB; 5971 if (change_col < 0) 5972 { 5973 change_col = fpos.col; /* Column of first change */ 5974 /* May have to adjust Insstart */ 5975 if (fpos.lnum == Insstart.lnum && fpos.col < Insstart.col) 5976 Insstart.col = fpos.col; 5977 } 5978 } 5979 ++fpos.col; 5980 ++ptr; 5981 vcol += i; 5982 } 5983 5984 if (change_col >= 0) 5985 { 5986 int repl_off = 0; 5987 char_u *line = ptr; 5988 5989 /* Skip over the spaces we need. */ 5990 while (vcol < want_vcol && *ptr == ' ') 5991 { 5992 vcol += lbr_chartabsize(line, ptr, vcol); 5993 ++ptr; 5994 ++repl_off; 5995 } 5996 if (vcol > want_vcol) 5997 { 5998 /* Must have a char with 'showbreak' just before it. */ 5999 --ptr; 6000 --repl_off; 6001 } 6002 fpos.col += repl_off; 6003 6004 /* Delete following spaces. */ 6005 i = cursor->col - fpos.col; 6006 if (i > 0) 6007 { 6008 STRMOVE(ptr, ptr + i); 6009 /* correct replace stack. */ 6010 if ((State & REPLACE_FLAG) && !(State & VREPLACE_FLAG)) 6011 for (temp = i; --temp >= 0; ) 6012 replace_join(repl_off); 6013 #ifdef FEAT_TEXT_PROP 6014 curbuf->b_ml.ml_line_len -= i; 6015 #endif 6016 } 6017 #ifdef FEAT_NETBEANS_INTG 6018 if (netbeans_active()) 6019 { 6020 netbeans_removed(curbuf, fpos.lnum, cursor->col, (long)(i + 1)); 6021 netbeans_inserted(curbuf, fpos.lnum, cursor->col, 6022 (char_u *)"\t", 1); 6023 } 6024 #endif 6025 cursor->col -= i; 6026 6027 /* 6028 * In VREPLACE mode, we haven't changed anything yet. Do it now by 6029 * backspacing over the changed spacing and then inserting the new 6030 * spacing. 6031 */ 6032 if (State & VREPLACE_FLAG) 6033 { 6034 /* Backspace from real cursor to change_col */ 6035 backspace_until_column(change_col); 6036 6037 /* Insert each char in saved_line from changed_col to 6038 * ptr-cursor */ 6039 ins_bytes_len(saved_line + change_col, 6040 cursor->col - change_col); 6041 } 6042 } 6043 6044 if (State & VREPLACE_FLAG) 6045 vim_free(saved_line); 6046 curwin->w_p_list = save_list; 6047 } 6048 6049 return FALSE; 6050 } 6051 6052 /* 6053 * Handle CR or NL in insert mode. 6054 * Return FAIL when out of memory or can't undo. 6055 */ 6056 int 6057 ins_eol(int c) 6058 { 6059 int i; 6060 6061 if (echeck_abbr(c + ABBR_OFF)) 6062 return OK; 6063 if (stop_arrow() == FAIL) 6064 return FAIL; 6065 undisplay_dollar(); 6066 6067 /* 6068 * Strange Vi behaviour: In Replace mode, typing a NL will not delete the 6069 * character under the cursor. Only push a NUL on the replace stack, 6070 * nothing to put back when the NL is deleted. 6071 */ 6072 if ((State & REPLACE_FLAG) && !(State & VREPLACE_FLAG)) 6073 replace_push(NUL); 6074 6075 /* 6076 * In VREPLACE mode, a NL replaces the rest of the line, and starts 6077 * replacing the next line, so we push all of the characters left on the 6078 * line onto the replace stack. This is not done here though, it is done 6079 * in open_line(). 6080 */ 6081 6082 /* Put cursor on NUL if on the last char and coladd is 1 (happens after 6083 * CTRL-O). */ 6084 if (virtual_active() && curwin->w_cursor.coladd > 0) 6085 coladvance(getviscol()); 6086 6087 #ifdef FEAT_RIGHTLEFT 6088 /* NL in reverse insert will always start in the end of 6089 * current line. */ 6090 if (revins_on) 6091 curwin->w_cursor.col += (colnr_T)STRLEN(ml_get_cursor()); 6092 #endif 6093 6094 AppendToRedobuff(NL_STR); 6095 i = open_line(FORWARD, 6096 #ifdef FEAT_COMMENTS 6097 has_format_option(FO_RET_COMS) ? OPENLINE_DO_COM : 6098 #endif 6099 0, old_indent); 6100 old_indent = 0; 6101 #ifdef FEAT_CINDENT 6102 can_cindent = TRUE; 6103 #endif 6104 #ifdef FEAT_FOLDING 6105 /* When inserting a line the cursor line must never be in a closed fold. */ 6106 foldOpenCursor(); 6107 #endif 6108 6109 return i; 6110 } 6111 6112 #ifdef FEAT_DIGRAPHS 6113 /* 6114 * Handle digraph in insert mode. 6115 * Returns character still to be inserted, or NUL when nothing remaining to be 6116 * done. 6117 */ 6118 static int 6119 ins_digraph(void) 6120 { 6121 int c; 6122 int cc; 6123 int did_putchar = FALSE; 6124 6125 pc_status = PC_STATUS_UNSET; 6126 if (redrawing() && !char_avail()) 6127 { 6128 /* may need to redraw when no more chars available now */ 6129 ins_redraw(FALSE); 6130 6131 edit_putchar('?', TRUE); 6132 did_putchar = TRUE; 6133 #ifdef FEAT_CMDL_INFO 6134 add_to_showcmd_c(Ctrl_K); 6135 #endif 6136 } 6137 6138 #ifdef USE_ON_FLY_SCROLL 6139 dont_scroll = TRUE; /* disallow scrolling here */ 6140 #endif 6141 6142 /* don't map the digraph chars. This also prevents the 6143 * mode message to be deleted when ESC is hit */ 6144 ++no_mapping; 6145 ++allow_keys; 6146 c = plain_vgetc(); 6147 --no_mapping; 6148 --allow_keys; 6149 if (did_putchar) 6150 /* when the line fits in 'columns' the '?' is at the start of the next 6151 * line and will not be removed by the redraw */ 6152 edit_unputchar(); 6153 6154 if (IS_SPECIAL(c) || mod_mask) /* special key */ 6155 { 6156 #ifdef FEAT_CMDL_INFO 6157 clear_showcmd(); 6158 #endif 6159 insert_special(c, TRUE, FALSE); 6160 return NUL; 6161 } 6162 if (c != ESC) 6163 { 6164 did_putchar = FALSE; 6165 if (redrawing() && !char_avail()) 6166 { 6167 /* may need to redraw when no more chars available now */ 6168 ins_redraw(FALSE); 6169 6170 if (char2cells(c) == 1) 6171 { 6172 ins_redraw(FALSE); 6173 edit_putchar(c, TRUE); 6174 did_putchar = TRUE; 6175 } 6176 #ifdef FEAT_CMDL_INFO 6177 add_to_showcmd_c(c); 6178 #endif 6179 } 6180 ++no_mapping; 6181 ++allow_keys; 6182 cc = plain_vgetc(); 6183 --no_mapping; 6184 --allow_keys; 6185 if (did_putchar) 6186 /* when the line fits in 'columns' the '?' is at the start of the 6187 * next line and will not be removed by a redraw */ 6188 edit_unputchar(); 6189 if (cc != ESC) 6190 { 6191 AppendToRedobuff((char_u *)CTRL_V_STR); 6192 c = getdigraph(c, cc, TRUE); 6193 #ifdef FEAT_CMDL_INFO 6194 clear_showcmd(); 6195 #endif 6196 return c; 6197 } 6198 } 6199 #ifdef FEAT_CMDL_INFO 6200 clear_showcmd(); 6201 #endif 6202 return NUL; 6203 } 6204 #endif 6205 6206 /* 6207 * Handle CTRL-E and CTRL-Y in Insert mode: copy char from other line. 6208 * Returns the char to be inserted, or NUL if none found. 6209 */ 6210 int 6211 ins_copychar(linenr_T lnum) 6212 { 6213 int c; 6214 int temp; 6215 char_u *ptr, *prev_ptr; 6216 char_u *line; 6217 6218 if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count) 6219 { 6220 vim_beep(BO_COPY); 6221 return NUL; 6222 } 6223 6224 /* try to advance to the cursor column */ 6225 temp = 0; 6226 line = ptr = ml_get(lnum); 6227 prev_ptr = ptr; 6228 validate_virtcol(); 6229 while ((colnr_T)temp < curwin->w_virtcol && *ptr != NUL) 6230 { 6231 prev_ptr = ptr; 6232 temp += lbr_chartabsize_adv(line, &ptr, (colnr_T)temp); 6233 } 6234 if ((colnr_T)temp > curwin->w_virtcol) 6235 ptr = prev_ptr; 6236 6237 c = (*mb_ptr2char)(ptr); 6238 if (c == NUL) 6239 vim_beep(BO_COPY); 6240 return c; 6241 } 6242 6243 /* 6244 * CTRL-Y or CTRL-E typed in Insert mode. 6245 */ 6246 static int 6247 ins_ctrl_ey(int tc) 6248 { 6249 int c = tc; 6250 6251 #ifdef FEAT_INS_EXPAND 6252 if (ctrl_x_mode_scroll()) 6253 { 6254 if (c == Ctrl_Y) 6255 scrolldown_clamp(); 6256 else 6257 scrollup_clamp(); 6258 redraw_later(VALID); 6259 } 6260 else 6261 #endif 6262 { 6263 c = ins_copychar(curwin->w_cursor.lnum + (c == Ctrl_Y ? -1 : 1)); 6264 if (c != NUL) 6265 { 6266 long tw_save; 6267 6268 /* The character must be taken literally, insert like it 6269 * was typed after a CTRL-V, and pretend 'textwidth' 6270 * wasn't set. Digits, 'o' and 'x' are special after a 6271 * CTRL-V, don't use it for these. */ 6272 if (c < 256 && !isalnum(c)) 6273 AppendToRedobuff((char_u *)CTRL_V_STR); /* CTRL-V */ 6274 tw_save = curbuf->b_p_tw; 6275 curbuf->b_p_tw = -1; 6276 insert_special(c, TRUE, FALSE); 6277 curbuf->b_p_tw = tw_save; 6278 #ifdef FEAT_RIGHTLEFT 6279 revins_chars++; 6280 revins_legal++; 6281 #endif 6282 c = Ctrl_V; /* pretend CTRL-V is last character */ 6283 auto_format(FALSE, TRUE); 6284 } 6285 } 6286 return c; 6287 } 6288 6289 #ifdef FEAT_SMARTINDENT 6290 /* 6291 * Try to do some very smart auto-indenting. 6292 * Used when inserting a "normal" character. 6293 */ 6294 static void 6295 ins_try_si(int c) 6296 { 6297 pos_T *pos, old_pos; 6298 char_u *ptr; 6299 int i; 6300 int temp; 6301 6302 /* 6303 * do some very smart indenting when entering '{' or '}' 6304 */ 6305 if (((did_si || can_si_back) && c == '{') || (can_si && c == '}')) 6306 { 6307 /* 6308 * for '}' set indent equal to indent of line containing matching '{' 6309 */ 6310 if (c == '}' && (pos = findmatch(NULL, '{')) != NULL) 6311 { 6312 old_pos = curwin->w_cursor; 6313 /* 6314 * If the matching '{' has a ')' immediately before it (ignoring 6315 * white-space), then line up with the start of the line 6316 * containing the matching '(' if there is one. This handles the 6317 * case where an "if (..\n..) {" statement continues over multiple 6318 * lines -- webb 6319 */ 6320 ptr = ml_get(pos->lnum); 6321 i = pos->col; 6322 if (i > 0) /* skip blanks before '{' */ 6323 while (--i > 0 && VIM_ISWHITE(ptr[i])) 6324 ; 6325 curwin->w_cursor.lnum = pos->lnum; 6326 curwin->w_cursor.col = i; 6327 if (ptr[i] == ')' && (pos = findmatch(NULL, '(')) != NULL) 6328 curwin->w_cursor = *pos; 6329 i = get_indent(); 6330 curwin->w_cursor = old_pos; 6331 if (State & VREPLACE_FLAG) 6332 change_indent(INDENT_SET, i, FALSE, NUL, TRUE); 6333 else 6334 (void)set_indent(i, SIN_CHANGED); 6335 } 6336 else if (curwin->w_cursor.col > 0) 6337 { 6338 /* 6339 * when inserting '{' after "O" reduce indent, but not 6340 * more than indent of previous line 6341 */ 6342 temp = TRUE; 6343 if (c == '{' && can_si_back && curwin->w_cursor.lnum > 1) 6344 { 6345 old_pos = curwin->w_cursor; 6346 i = get_indent(); 6347 while (curwin->w_cursor.lnum > 1) 6348 { 6349 ptr = skipwhite(ml_get(--(curwin->w_cursor.lnum))); 6350 6351 /* ignore empty lines and lines starting with '#'. */ 6352 if (*ptr != '#' && *ptr != NUL) 6353 break; 6354 } 6355 if (get_indent() >= i) 6356 temp = FALSE; 6357 curwin->w_cursor = old_pos; 6358 } 6359 if (temp) 6360 shift_line(TRUE, FALSE, 1, TRUE); 6361 } 6362 } 6363 6364 /* 6365 * set indent of '#' always to 0 6366 */ 6367 if (curwin->w_cursor.col > 0 && can_si && c == '#') 6368 { 6369 /* remember current indent for next line */ 6370 old_indent = get_indent(); 6371 (void)set_indent(0, SIN_CHANGED); 6372 } 6373 6374 /* Adjust ai_col, the char at this position can be deleted. */ 6375 if (ai_col > curwin->w_cursor.col) 6376 ai_col = curwin->w_cursor.col; 6377 } 6378 #endif 6379 6380 /* 6381 * Get the value that w_virtcol would have when 'list' is off. 6382 * Unless 'cpo' contains the 'L' flag. 6383 */ 6384 colnr_T 6385 get_nolist_virtcol(void) 6386 { 6387 // check validity of cursor in current buffer 6388 if (curwin->w_buffer == NULL 6389 || curwin->w_buffer->b_ml.ml_mfp == NULL 6390 || curwin->w_cursor.lnum > curwin->w_buffer->b_ml.ml_line_count) 6391 return 0; 6392 if (curwin->w_p_list && vim_strchr(p_cpo, CPO_LISTWM) == NULL) 6393 return getvcol_nolist(&curwin->w_cursor); 6394 validate_virtcol(); 6395 return curwin->w_virtcol; 6396 } 6397 6398 #if defined(FEAT_EVAL) 6399 /* 6400 * Handle the InsertCharPre autocommand. 6401 * "c" is the character that was typed. 6402 * Return a pointer to allocated memory with the replacement string. 6403 * Return NULL to continue inserting "c". 6404 */ 6405 static char_u * 6406 do_insert_char_pre(int c) 6407 { 6408 char_u *res; 6409 char_u buf[MB_MAXBYTES + 1]; 6410 int save_State = State; 6411 6412 /* Return quickly when there is nothing to do. */ 6413 if (!has_insertcharpre()) 6414 return NULL; 6415 6416 if (has_mbyte) 6417 buf[(*mb_char2bytes)(c, buf)] = NUL; 6418 else 6419 { 6420 buf[0] = c; 6421 buf[1] = NUL; 6422 } 6423 6424 /* Lock the text to avoid weird things from happening. */ 6425 ++textlock; 6426 set_vim_var_string(VV_CHAR, buf, -1); /* set v:char */ 6427 6428 res = NULL; 6429 if (ins_apply_autocmds(EVENT_INSERTCHARPRE)) 6430 { 6431 /* Get the value of v:char. It may be empty or more than one 6432 * character. Only use it when changed, otherwise continue with the 6433 * original character to avoid breaking autoindent. */ 6434 if (STRCMP(buf, get_vim_var_str(VV_CHAR)) != 0) 6435 res = vim_strsave(get_vim_var_str(VV_CHAR)); 6436 } 6437 6438 set_vim_var_string(VV_CHAR, NULL, -1); /* clear v:char */ 6439 --textlock; 6440 6441 // Restore the State, it may have been changed. 6442 State = save_State; 6443 6444 return res; 6445 } 6446 #endif 6447 6448 #if defined(FEAT_CINDENT) || defined(PROTO) 6449 int 6450 can_cindent_get(void) 6451 { 6452 return can_cindent; 6453 } 6454 #endif 6455 6456 /* 6457 * Trigger "event" and take care of fixing undo. 6458 */ 6459 int 6460 ins_apply_autocmds(event_T event) 6461 { 6462 varnumber_T tick = CHANGEDTICK(curbuf); 6463 int r; 6464 6465 r = apply_autocmds(event, NULL, NULL, FALSE, curbuf); 6466 6467 // If u_savesub() was called then we are not prepared to start 6468 // a new line. Call u_save() with no contents to fix that. 6469 if (tick != CHANGEDTICK(curbuf)) 6470 u_save(curwin->w_cursor.lnum, (linenr_T)(curwin->w_cursor.lnum + 1)); 6471 6472 return r; 6473 } 6474