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