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