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