Annotation of src/usr.bin/vim/edit.c, Revision 1.1
1.1 ! downsj 1: /* $OpenBSD$ */
! 2: /* vi:set ts=4 sw=4:
! 3: *
! 4: * VIM - Vi IMproved by Bram Moolenaar
! 5: *
! 6: * Do ":help uganda" in Vim to read copying and usage conditions.
! 7: * Do ":help credits" in Vim to see a list of people who contributed.
! 8: */
! 9:
! 10: /*
! 11: * edit.c: functions for insert mode
! 12: */
! 13:
! 14: #include "vim.h"
! 15: #include "globals.h"
! 16: #include "proto.h"
! 17: #include "option.h"
! 18: #include "ops.h" /* for op_type */
! 19:
! 20: #ifdef INSERT_EXPAND
! 21: /*
! 22: * definitions used for CTRL-X submode
! 23: */
! 24: #define CTRL_X_WANT_IDENT 0x100
! 25:
! 26: #define CTRL_X_NOT_DEFINED_YET (1)
! 27: #define CTRL_X_SCROLL (2)
! 28: #define CTRL_X_WHOLE_LINE (3)
! 29: #define CTRL_X_FILES (4)
! 30: #define CTRL_X_TAGS (5 + CTRL_X_WANT_IDENT)
! 31: #define CTRL_X_PATH_PATTERNS (6 + CTRL_X_WANT_IDENT)
! 32: #define CTRL_X_PATH_DEFINES (7 + CTRL_X_WANT_IDENT)
! 33: #define CTRL_X_FINISHED (8)
! 34: #define CTRL_X_DICTIONARY (9 + CTRL_X_WANT_IDENT)
! 35:
! 36: struct Completion
! 37: {
! 38: char_u *str;
! 39: char_u *fname;
! 40: int original;
! 41: struct Completion *next;
! 42: struct Completion *prev;
! 43: };
! 44:
! 45: struct Completion *first_match = NULL;
! 46: struct Completion *curr_match = NULL;
! 47:
! 48: static int add_completion __ARGS((char_u *str, int len, char_u *, int dir));
! 49: static int make_cyclic __ARGS((void));
! 50: static void complete_dictionaries __ARGS((char_u *, int));
! 51: static void free_completions __ARGS((void));
! 52: static int count_completions __ARGS((void));
! 53: #endif /* INSERT_EXPAND */
! 54:
! 55: #define BACKSPACE_CHAR 1
! 56: #define BACKSPACE_WORD 2
! 57: #define BACKSPACE_WORD_NOT_SPACE 3
! 58: #define BACKSPACE_LINE 4
! 59:
! 60: static void change_indent __ARGS((int type, int amount, int round));
! 61: static void insert_special __ARGS((int, int));
! 62: static void start_arrow __ARGS((FPOS *end_insert_pos));
! 63: static void stop_arrow __ARGS((void));
! 64: static void stop_insert __ARGS((FPOS *end_insert_pos));
! 65: static int echeck_abbr __ARGS((int));
! 66:
! 67: static FPOS Insstart; /* This is where the latest insert/append
! 68: * mode started. */
! 69: static colnr_t Insstart_textlen; /* length of line when insert started */
! 70: static colnr_t Insstart_blank_vcol; /* vcol for first inserted blank */
! 71:
! 72: static char_u *last_insert = NULL;
! 73: /* the text of the previous insert */
! 74: static int last_insert_skip;
! 75: /* number of chars in front of previous insert */
! 76: static int new_insert_skip;
! 77: /* number of chars in front of the current insert */
! 78: #ifdef INSERT_EXPAND
! 79: static char_u *original_text = NULL;
! 80: /* Original text typed before completion */
! 81: #endif
! 82:
! 83: #ifdef CINDENT
! 84: static int can_cindent; /* may do cindenting on this line */
! 85: #endif
! 86:
! 87: /*
! 88: * edit() returns TRUE if it returns because of a CTRL-O command
! 89: */
! 90: int
! 91: edit(initstr, startln, count)
! 92: int initstr;
! 93: int startln; /* if set, insert at start of line */
! 94: long count;
! 95: {
! 96: int c;
! 97: int cc;
! 98: char_u *ptr;
! 99: linenr_t lnum;
! 100: int temp = 0;
! 101: int mode;
! 102: int lastc = 0;
! 103: colnr_t mincol;
! 104: static linenr_t o_lnum = 0;
! 105: static int o_eol = FALSE;
! 106: int need_redraw = FALSE;
! 107: int i;
! 108: int did_backspace = TRUE; /* previous char was backspace */
! 109: #ifdef RIGHTLEFT
! 110: int revins; /* reverse insert mode */
! 111: int revinschars = 0; /* how much to skip after edit */
! 112: int revinslegal = 0; /* was the last char 'legal'? */
! 113: int revinsscol = -1; /* start column of revins session */
! 114: #endif
! 115: #ifdef INSERT_EXPAND
! 116: FPOS first_match_pos;
! 117: FPOS last_match_pos;
! 118: FPOS *complete_pos;
! 119: char_u *complete_pat = NULL;
! 120: char_u *tmp_ptr;
! 121: char_u *mesg = NULL; /* Message about completion */
! 122: char_u *quick_m; /* Message without sleep */
! 123: int started_completion = FALSE;
! 124: colnr_t complete_col = 0; /* init for gcc */
! 125: int complete_direction;
! 126: int done_dir = 0; /* Found all matches in this
! 127: * direction */
! 128: int num_matches;
! 129: char_u **matches;
! 130: regexp *prog;
! 131: int save_sm = -1; /* init for gcc */
! 132: int save_p_scs;
! 133: #endif
! 134: #ifdef CINDENT
! 135: int line_is_white = FALSE; /* line is empty before insert */
! 136: #endif
! 137: FPOS tpos;
! 138:
! 139: /* sleep before redrawing, needed for "CTRL-O :" that results in an
! 140: * error message */
! 141: if (msg_scroll || emsg_on_display)
! 142: {
! 143: mch_delay(1000L, TRUE);
! 144: msg_scroll = FALSE;
! 145: emsg_on_display = FALSE;
! 146: }
! 147: #ifdef SLEEP_IN_EMSG
! 148: if (need_sleep)
! 149: {
! 150: mch_delay(1000L, TRUE);
! 151: need_sleep = FALSE;
! 152: }
! 153: #endif
! 154:
! 155: #ifdef USE_MOUSE
! 156: /*
! 157: * When doing a paste with the middle mouse button, Insstart is set to
! 158: * where the paste started.
! 159: */
! 160: if (where_paste_started.lnum != 0)
! 161: Insstart = where_paste_started;
! 162: else
! 163: #endif
! 164: {
! 165: Insstart = curwin->w_cursor;
! 166: if (startln)
! 167: Insstart.col = 0;
! 168: }
! 169: Insstart_textlen = linetabsize(ml_get_curline());
! 170: Insstart_blank_vcol = MAXCOL;
! 171:
! 172: if (initstr != NUL && !restart_edit)
! 173: {
! 174: ResetRedobuff();
! 175: AppendNumberToRedobuff(count);
! 176: AppendCharToRedobuff(initstr);
! 177: if (initstr == 'g') /* "gI" command */
! 178: AppendCharToRedobuff('I');
! 179: }
! 180:
! 181: if (initstr == 'R')
! 182: State = REPLACE;
! 183: else
! 184: State = INSERT;
! 185:
! 186: #ifdef USE_MOUSE
! 187: setmouse();
! 188: #endif
! 189: clear_showcmd();
! 190: #ifdef RIGHTLEFT
! 191: revins = (State == INSERT && p_ri); /* there is no reverse replace mode */
! 192: if (revins)
! 193: undisplay_dollar();
! 194: #endif
! 195:
! 196: /*
! 197: * When CTRL-O . is used to repeat an insert, we get here with
! 198: * restart_edit non-zero, but something in the stuff buffer
! 199: */
! 200: if (restart_edit && stuff_empty())
! 201: {
! 202: #ifdef USE_MOUSE
! 203: /*
! 204: * After a paste we consider text typed to be part of the insert for
! 205: * the pasted text. You can backspace over the paste text too.
! 206: */
! 207: if (where_paste_started.lnum)
! 208: arrow_used = FALSE;
! 209: else
! 210: #endif
! 211: arrow_used = TRUE;
! 212: restart_edit = 0;
! 213: /*
! 214: * If the cursor was after the end-of-line before the CTRL-O
! 215: * and it is now at the end-of-line, put it after the end-of-line
! 216: * (this is not correct in very rare cases).
! 217: * Also do this if curswant is greater than the current virtual column.
! 218: * Eg after "^O$" or "^O80|".
! 219: */
! 220: if (((o_eol && curwin->w_cursor.lnum == o_lnum) ||
! 221: curwin->w_curswant > curwin->w_virtcol) &&
! 222: *(ptr = ml_get_curline() + curwin->w_cursor.col)
! 223: != NUL &&
! 224: *(ptr + 1) == NUL)
! 225: ++curwin->w_cursor.col;
! 226: }
! 227: else
! 228: {
! 229: arrow_used = FALSE;
! 230: o_eol = FALSE;
! 231: }
! 232: #ifdef USE_MOUSE
! 233: where_paste_started.lnum = 0;
! 234: #endif
! 235: #ifdef CINDENT
! 236: can_cindent = TRUE;
! 237: #endif
! 238:
! 239: if (p_smd)
! 240: showmode();
! 241:
! 242: if (!p_im)
! 243: change_warning(); /* give a warning if readonly */
! 244:
! 245: #ifdef DIGRAPHS
! 246: do_digraph(-1); /* clear digraphs */
! 247: #endif
! 248:
! 249: /*
! 250: * Get the current length of the redo buffer, those characters have to be
! 251: * skipped if we want to get to the inserted characters.
! 252: */
! 253: ptr = get_inserted();
! 254: new_insert_skip = STRLEN(ptr);
! 255: vim_free(ptr);
! 256:
! 257: old_indent = 0;
! 258:
! 259: for (;;)
! 260: {
! 261: #ifdef RIGHTLEFT
! 262: if (!revinslegal)
! 263: revinsscol = -1; /* reset on illegal motions */
! 264: else
! 265: revinslegal = 0;
! 266: #endif
! 267: if (arrow_used) /* don't repeat insert when arrow key used */
! 268: count = 0;
! 269:
! 270: /* set curwin->w_curswant for next K_DOWN or K_UP */
! 271: if (!arrow_used)
! 272: curwin->w_set_curswant = TRUE;
! 273:
! 274: /* Figure out where the cursor is based on curwin->w_cursor. */
! 275: mincol = curwin->w_col;
! 276: i = curwin->w_row;
! 277: cursupdate();
! 278:
! 279: /*
! 280: * When emsg() was called msg_scroll will have been set.
! 281: */
! 282: msg_scroll = FALSE;
! 283:
! 284: /*
! 285: * If we inserted a character at the last position of the last line in
! 286: * the window, scroll the window one line up. This avoids an extra
! 287: * redraw.
! 288: * This is detected when the cursor column is smaller after inserting
! 289: * something.
! 290: */
! 291: if (curwin->w_p_wrap && !did_backspace &&
! 292: (int)curwin->w_col < (int)mincol - curbuf->b_p_ts &&
! 293: i == curwin->w_winpos + curwin->w_height - 1 &&
! 294: curwin->w_cursor.lnum != curwin->w_topline)
! 295: {
! 296: ++curwin->w_topline;
! 297: updateScreen(VALID_TO_CURSCHAR);
! 298: cursupdate();
! 299: need_redraw = FALSE;
! 300: }
! 301: did_backspace = FALSE;
! 302:
! 303: /*
! 304: * redraw is postponed until after cursupdate() to make 'dollar'
! 305: * option work correctly.
! 306: */
! 307: if (need_redraw)
! 308: {
! 309: updateline();
! 310: need_redraw = FALSE;
! 311: }
! 312:
! 313: showruler(0);
! 314: setcursor();
! 315: emsg_on_display = FALSE; /* may remove error message now */
! 316:
! 317: c = vgetc();
! 318: if (c == Ctrl('C'))
! 319: got_int = FALSE;
! 320:
! 321: #ifdef RIGHTLEFT
! 322: if (p_hkmap && KeyTyped)
! 323: c = hkmap(c); /* Hebrew mode mapping */
! 324: #endif
! 325:
! 326: #ifdef INSERT_EXPAND
! 327: if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET)
! 328: {
! 329: /* We have just entered ctrl-x mode and aren't quite sure which
! 330: * ctrl-x mode it will be yet. Now we decide -- webb
! 331: */
! 332: switch (c)
! 333: {
! 334: case Ctrl('E'):
! 335: case Ctrl('Y'):
! 336: ctrl_x_mode = CTRL_X_SCROLL;
! 337: if (State == INSERT)
! 338: edit_submode = (char_u *)" (insert) Scroll (^E/^Y)";
! 339: else
! 340: edit_submode = (char_u *)" (replace) Scroll (^E/^Y)";
! 341: break;
! 342: case Ctrl('L'):
! 343: ctrl_x_mode = CTRL_X_WHOLE_LINE;
! 344: edit_submode = (char_u *)" Whole line completion (^L/^N/^P)";
! 345: break;
! 346: case Ctrl('F'):
! 347: ctrl_x_mode = CTRL_X_FILES;
! 348: edit_submode = (char_u *)" File name completion (^F/^N/^P)";
! 349: break;
! 350: case Ctrl('K'):
! 351: ctrl_x_mode = CTRL_X_DICTIONARY;
! 352: edit_submode = (char_u *)" Dictionary completion (^K/^N/^P)";
! 353: break;
! 354: case Ctrl(']'):
! 355: ctrl_x_mode = CTRL_X_TAGS;
! 356: edit_submode = (char_u *)" Tag completion (^]/^N/^P)";
! 357: break;
! 358: case Ctrl('I'):
! 359: ctrl_x_mode = CTRL_X_PATH_PATTERNS;
! 360: edit_submode = (char_u *)" Path pattern completion (^N/^P)";
! 361: break;
! 362: case Ctrl('D'):
! 363: ctrl_x_mode = CTRL_X_PATH_DEFINES;
! 364: edit_submode = (char_u *)" Definition completion (^D/^N/^P)";
! 365: break;
! 366: default:
! 367: ctrl_x_mode = 0;
! 368: break;
! 369: }
! 370: showmode();
! 371: }
! 372: else if (ctrl_x_mode)
! 373: {
! 374: /* We we're already in ctrl-x mode, do we stay in it? */
! 375: if (!is_ctrl_x_key(c))
! 376: {
! 377: if (ctrl_x_mode == CTRL_X_SCROLL)
! 378: ctrl_x_mode = 0;
! 379: else
! 380: ctrl_x_mode = CTRL_X_FINISHED;
! 381: edit_submode = NULL;
! 382: }
! 383: showmode();
! 384: }
! 385: if (started_completion || ctrl_x_mode == CTRL_X_FINISHED)
! 386: {
! 387: /* Show error message from attempted keyword completion (probably
! 388: * 'Pattern not found') until another key is hit, then go back to
! 389: * showing what mode we are in.
! 390: */
! 391: showmode();
! 392: if ((ctrl_x_mode == 0 && c != Ctrl('N') && c != Ctrl('P')) ||
! 393: ctrl_x_mode == CTRL_X_FINISHED)
! 394: {
! 395: /* Get here when we have finished typing a sequence of ^N and
! 396: * ^P or other completion characters in CTRL-X mode. Free up
! 397: * memory that was used, and make sure we can redo the insert
! 398: * -- webb.
! 399: */
! 400: if (curr_match != NULL)
! 401: {
! 402: /*
! 403: * If any of the original typed text has been changed,
! 404: * eg when ignorecase is set, we must add back-spaces to
! 405: * the redo buffer. We add as few as necessary to delete
! 406: * just the part of the original text that has changed
! 407: * -- webb
! 408: */
! 409: ptr = curr_match->str;
! 410: tmp_ptr = original_text;
! 411: while (*tmp_ptr && *tmp_ptr == *ptr)
! 412: {
! 413: ++tmp_ptr;
! 414: ++ptr;
! 415: }
! 416: for (temp = 0; tmp_ptr[temp]; ++temp)
! 417: AppendCharToRedobuff(K_BS);
! 418: if (*ptr)
! 419: AppendToRedobuff(ptr);
! 420: }
! 421: /* Break line if it's too long */
! 422: lnum = curwin->w_cursor.lnum;
! 423: insertchar(NUL, FALSE, -1);
! 424: if (lnum != curwin->w_cursor.lnum)
! 425: updateScreen(CURSUPD);
! 426: else
! 427: need_redraw = TRUE;
! 428:
! 429: vim_free(complete_pat);
! 430: complete_pat = NULL;
! 431: vim_free(original_text);
! 432: original_text = NULL;
! 433: free_completions();
! 434: started_completion = FALSE;
! 435: ctrl_x_mode = 0;
! 436: p_sm = save_sm;
! 437: if (edit_submode != NULL)
! 438: {
! 439: edit_submode = NULL;
! 440: showmode();
! 441: }
! 442: }
! 443: }
! 444: #endif /* INSERT_EXPAND */
! 445:
! 446: if (c != Ctrl('D')) /* remember to detect ^^D and 0^D */
! 447: lastc = c;
! 448:
! 449: #ifdef DIGRAPHS
! 450: c = do_digraph(c);
! 451: #endif /* DIGRAPHS */
! 452:
! 453: if (c == Ctrl('V') || c == Ctrl('Q'))
! 454: {
! 455: if (NextScreen != NULL)
! 456: screen_outchar('^', curwin->w_winpos + curwin->w_row,
! 457: #ifdef RIGHTLEFT
! 458: curwin->w_p_rl ? (int)Columns - 1 - curwin->w_col :
! 459: #endif
! 460: curwin->w_col);
! 461: AppendToRedobuff((char_u *)"\026"); /* CTRL-V */
! 462: cursupdate();
! 463:
! 464: if (!add_to_showcmd(c, FALSE))
! 465: setcursor();
! 466:
! 467: c = get_literal();
! 468: clear_showcmd();
! 469: insert_special(c, TRUE);
! 470: need_redraw = TRUE;
! 471: #ifdef RIGHTLEFT
! 472: revinschars++;
! 473: revinslegal++;
! 474: #endif
! 475: continue;
! 476: }
! 477:
! 478: #ifdef CINDENT
! 479: if (curbuf->b_p_cin
! 480: # ifdef INSERT_EXPAND
! 481: && !ctrl_x_mode
! 482: # endif
! 483: )
! 484: {
! 485: line_is_white = inindent(0);
! 486:
! 487: /*
! 488: * A key name preceded by a bang means that this
! 489: * key wasn't destined to be inserted. Skip ahead
! 490: * to the re-indenting if we find one.
! 491: */
! 492: if (in_cinkeys(c, '!', line_is_white))
! 493: goto force_cindent;
! 494:
! 495: /*
! 496: * A key name preceded by a star means that indenting
! 497: * has to be done before inserting the key.
! 498: */
! 499: if (can_cindent && in_cinkeys(c, '*', line_is_white))
! 500: {
! 501: stop_arrow();
! 502:
! 503: /* re-indent the current line */
! 504: fixthisline(get_c_indent);
! 505:
! 506: /* draw the changes on the screen later */
! 507: need_redraw = TRUE;
! 508: }
! 509: }
! 510: #endif /* CINDENT */
! 511:
! 512: #ifdef RIGHTLEFT
! 513: if (curwin->w_p_rl)
! 514: switch (c)
! 515: {
! 516: case K_LEFT: c = K_RIGHT; break;
! 517: case K_S_LEFT: c = K_S_RIGHT; break;
! 518: case K_RIGHT: c = K_LEFT; break;
! 519: case K_S_RIGHT: c = K_S_LEFT; break;
! 520: }
! 521: #endif
! 522:
! 523: switch (c) /* handle character in insert mode */
! 524: {
! 525: case K_INS: /* toggle insert/replace mode */
! 526: if (State == REPLACE)
! 527: State = INSERT;
! 528: else
! 529: State = REPLACE;
! 530: AppendCharToRedobuff(K_INS);
! 531: showmode();
! 532: break;
! 533:
! 534: #ifdef INSERT_EXPAND
! 535: case Ctrl('X'): /* Enter ctrl-x mode */
! 536: /* We're not sure which ctrl-x mode it will be yet */
! 537: ctrl_x_mode = CTRL_X_NOT_DEFINED_YET;
! 538: MSG("^X mode (^E/^Y/^L/^]/^F/^I/^K/^D)");
! 539: break;
! 540: #endif /* INSERT_EXPAND */
! 541:
! 542: case Ctrl('O'): /* execute one command */
! 543: if (echeck_abbr(Ctrl('O') + ABBR_OFF))
! 544: break;
! 545: count = 0;
! 546: if (State == INSERT)
! 547: restart_edit = 'I';
! 548: else
! 549: restart_edit = 'R';
! 550: o_lnum = curwin->w_cursor.lnum;
! 551: o_eol = (gchar_cursor() == NUL);
! 552: goto doESCkey;
! 553:
! 554: /* Hitting the help key in insert mode is like <ESC> <Help> */
! 555: case K_HELP:
! 556: case K_F1:
! 557: stuffcharReadbuff(K_HELP);
! 558: /*FALLTHROUGH*/
! 559:
! 560: case ESC: /* an escape ends input mode */
! 561: if (echeck_abbr(ESC + ABBR_OFF))
! 562: break;
! 563: /*FALLTHROUGH*/
! 564:
! 565: case Ctrl('C'):
! 566: doESCkey:
! 567: temp = curwin->w_cursor.col;
! 568: if (!arrow_used)
! 569: {
! 570: AppendToRedobuff(ESC_STR);
! 571:
! 572: if (--count > 0) /* repeat what was typed */
! 573: {
! 574: (void)start_redo_ins();
! 575: continue;
! 576: }
! 577: stop_insert(&curwin->w_cursor);
! 578: if (dollar_vcol)
! 579: {
! 580: dollar_vcol = 0;
! 581: /* may have to redraw status line if this was the
! 582: * first change, show "[+]" */
! 583: if (curwin->w_redr_status == TRUE)
! 584: must_redraw = NOT_VALID;
! 585: else
! 586: need_redraw = TRUE;
! 587: }
! 588: }
! 589: if (need_redraw)
! 590: updateline();
! 591:
! 592: /* When an autoindent was removed, curswant stays after the
! 593: * indent */
! 594: if (!restart_edit && (colnr_t)temp == curwin->w_cursor.col)
! 595: curwin->w_set_curswant = TRUE;
! 596:
! 597: /*
! 598: * The cursor should end up on the last inserted character.
! 599: */
! 600: if (curwin->w_cursor.col != 0 &&
! 601: (!restart_edit || gchar_cursor() == NUL)
! 602: #ifdef RIGHTLEFT
! 603: && !revins
! 604: #endif
! 605: )
! 606: --curwin->w_cursor.col;
! 607: if (State == REPLACE)
! 608: replace_flush(); /* free replace stack */
! 609: State = NORMAL;
! 610: #ifdef USE_MOUSE
! 611: setmouse();
! 612: #endif
! 613: /* inchar() may have deleted the "INSERT" message */
! 614: /* for CTRL-O we display -- INSERT COMMAND -- */
! 615: if (Recording || restart_edit)
! 616: showmode();
! 617: else if (p_smd)
! 618: MSG("");
! 619: old_indent = 0;
! 620: return (c == Ctrl('O'));
! 621:
! 622: /*
! 623: * Insert the previously inserted text.
! 624: * For ^@ the trailing ESC will end the insert, unless there
! 625: * is an error.
! 626: */
! 627: case K_ZERO:
! 628: case NUL:
! 629: case Ctrl('A'):
! 630: if (stuff_inserted(NUL, 1L, (c == Ctrl('A'))) == FAIL &&
! 631: c != Ctrl('A'))
! 632: goto doESCkey; /* quit insert mode */
! 633: break;
! 634:
! 635: /*
! 636: * insert the contents of a register
! 637: */
! 638: case Ctrl('R'):
! 639: if (NextScreen != NULL)
! 640: screen_outchar('"', curwin->w_winpos + curwin->w_row,
! 641: #ifdef RIGHTLEFT
! 642: curwin->w_p_rl ? (int)Columns - 1 - curwin->w_col :
! 643: #endif
! 644: curwin->w_col);
! 645: if (!add_to_showcmd(c, FALSE))
! 646: setcursor();
! 647: /* don't map the register name. This also prevents the
! 648: * mode message to be deleted when ESC is hit */
! 649: ++no_mapping;
! 650: #ifdef HAVE_LANGMAP
! 651: cc = vgetc();
! 652: LANGMAP_ADJUST(cc, TRUE);
! 653: if (insertbuf(cc) == FAIL)
! 654: #else
! 655: if (insertbuf(vgetc()) == FAIL)
! 656: #endif
! 657: {
! 658: beep_flush();
! 659: need_redraw = TRUE; /* remove the '"' */
! 660: }
! 661: --no_mapping;
! 662: clear_showcmd();
! 663: break;
! 664:
! 665: #ifdef RIGHTLEFT
! 666: case Ctrl('B'): /* toggle reverse insert mode */
! 667: p_ri = !p_ri;
! 668: revins = (State == INSERT && p_ri);
! 669: if (revins)
! 670: undisplay_dollar();
! 671: showmode();
! 672: break;
! 673:
! 674: case Ctrl('_'): /* toggle language: khmap and revins */
! 675: /* Move to end of reverse inserted text */
! 676: if (revins && revinschars && revinsscol >= 0)
! 677: while (gchar_cursor() != NUL && revinschars--)
! 678: ++curwin->w_cursor.col;
! 679: p_ri = !p_ri;
! 680: revins = (State == INSERT && p_ri);
! 681: if (revins)
! 682: {
! 683: revinsscol = curwin->w_cursor.col;
! 684: revinslegal++;
! 685: revinschars = 0;
! 686: undisplay_dollar();
! 687: }
! 688: else
! 689: revinsscol = -1;
! 690: p_hkmap = curwin->w_p_rl ^ p_ri; /* be consistent! */
! 691: showmode();
! 692: break;
! 693: #endif
! 694:
! 695: /*
! 696: * If the cursor is on an indent, ^T/^D insert/delete one
! 697: * shiftwidth. Otherwise ^T/^D behave like a "<<" or ">>".
! 698: * Always round the indent to 'shiftwith', this is compatible
! 699: * with vi. But vi only supports ^T and ^D after an
! 700: * autoindent, we support it everywhere.
! 701: */
! 702: case Ctrl('D'): /* make indent one shiftwidth smaller */
! 703: #ifdef INSERT_EXPAND
! 704: if (ctrl_x_mode == CTRL_X_PATH_DEFINES)
! 705: goto docomplete;
! 706: #endif /* INSERT_EXPAND */
! 707: /* FALLTHROUGH */
! 708: case Ctrl('T'): /* make indent one shiftwidth greater */
! 709: stop_arrow();
! 710: AppendCharToRedobuff(c);
! 711:
! 712: /*
! 713: * 0^D and ^^D: remove all indent.
! 714: */
! 715: if ((lastc == '0' || lastc == '^') && curwin->w_cursor.col)
! 716: {
! 717: --curwin->w_cursor.col;
! 718: (void)delchar(FALSE); /* delete the '^' or '0' */
! 719: if (lastc == '^')
! 720: old_indent = get_indent(); /* remember curr. indent */
! 721: change_indent(INDENT_SET, 0, TRUE);
! 722: }
! 723: else
! 724: change_indent(c == Ctrl('D') ? INDENT_DEC : INDENT_INC,
! 725: 0, TRUE);
! 726:
! 727: did_ai = FALSE;
! 728: did_si = FALSE;
! 729: can_si = FALSE;
! 730: can_si_back = FALSE;
! 731: #ifdef CINDENT
! 732: can_cindent = FALSE; /* no cindenting after ^D or ^T */
! 733: #endif
! 734: goto redraw;
! 735:
! 736: case K_DEL:
! 737: stop_arrow();
! 738: if (gchar_cursor() == NUL) /* delete newline */
! 739: {
! 740: temp = curwin->w_cursor.col;
! 741: if (!p_bs || /* only if 'bs' set */
! 742: u_save((linenr_t)(curwin->w_cursor.lnum - 1),
! 743: (linenr_t)(curwin->w_cursor.lnum + 2)) == FAIL ||
! 744: do_join(FALSE, TRUE) == FAIL)
! 745: beep_flush();
! 746: else
! 747: curwin->w_cursor.col = temp;
! 748: }
! 749: else if (delchar(FALSE) == FAIL)/* delete char under cursor */
! 750: beep_flush();
! 751: did_ai = FALSE;
! 752: did_si = FALSE;
! 753: can_si = FALSE;
! 754: can_si_back = FALSE;
! 755: AppendCharToRedobuff(c);
! 756: goto redraw;
! 757:
! 758: case K_BS:
! 759: case Ctrl('H'):
! 760: mode = BACKSPACE_CHAR;
! 761: dodel:
! 762: /* can't delete anything in an empty file */
! 763: /* can't backup past first character in buffer */
! 764: /* can't backup past starting point unless 'backspace' > 1 */
! 765: /* can backup to a previous line if 'backspace' == 0 */
! 766: if (bufempty() || (
! 767: #ifdef RIGHTLEFT
! 768: !revins &&
! 769: #endif
! 770: ((curwin->w_cursor.lnum == 1 &&
! 771: curwin->w_cursor.col <= 0) ||
! 772: (p_bs < 2 && (arrow_used ||
! 773: (curwin->w_cursor.lnum == Insstart.lnum &&
! 774: curwin->w_cursor.col <= Insstart.col) ||
! 775: (curwin->w_cursor.col <= 0 && p_bs == 0))))))
! 776: {
! 777: beep_flush();
! 778: goto redraw;
! 779: }
! 780:
! 781: stop_arrow();
! 782: #ifdef CINDENT
! 783: if (inindent(0))
! 784: can_cindent = FALSE;
! 785: #endif
! 786: #ifdef RIGHTLEFT
! 787: if (revins) /* put cursor after last inserted char */
! 788: inc_cursor();
! 789: #endif
! 790: if (curwin->w_cursor.col <= 0) /* delete newline! */
! 791: {
! 792: lnum = Insstart.lnum;
! 793: if (curwin->w_cursor.lnum == Insstart.lnum
! 794: #ifdef RIGHTLEFT
! 795: || revins
! 796: #endif
! 797: )
! 798: {
! 799: if (u_save((linenr_t)(curwin->w_cursor.lnum - 2),
! 800: (linenr_t)(curwin->w_cursor.lnum + 1)) == FAIL)
! 801: goto redraw;
! 802: --Insstart.lnum;
! 803: Insstart.col = 0;
! 804: }
! 805: /*
! 806: * In replace mode:
! 807: * cc < 0: NL was inserted, delete it
! 808: * cc >= 0: NL was replaced, put original characters back
! 809: */
! 810: cc = -1;
! 811: if (State == REPLACE)
! 812: cc = replace_pop();
! 813: /* in replace mode, in the line we started replacing, we
! 814: only move the cursor */
! 815: if (State != REPLACE || curwin->w_cursor.lnum > lnum)
! 816: {
! 817: temp = gchar_cursor(); /* remember current char */
! 818: --curwin->w_cursor.lnum;
! 819: (void)do_join(FALSE, curs_rows() == OK);
! 820: if (temp == NUL && gchar_cursor() != NUL)
! 821: ++curwin->w_cursor.col;
! 822: /*
! 823: * in REPLACE mode we have to put back the text that
! 824: * was replace by the NL. On the replace stack is
! 825: * first a NUL-terminated sequence of characters that
! 826: * were deleted and then the character that NL
! 827: * replaced.
! 828: */
! 829: if (State == REPLACE)
! 830: {
! 831: /*
! 832: * Do the next ins_char() in NORMAL state, to
! 833: * prevent ins_char() from replacing characters and
! 834: * avoiding showmatch().
! 835: */
! 836: State = NORMAL;
! 837: /*
! 838: * restore blanks deleted after cursor
! 839: */
! 840: while (cc > 0)
! 841: {
! 842: temp = curwin->w_cursor.col;
! 843: ins_char(cc);
! 844: curwin->w_cursor.col = temp;
! 845: cc = replace_pop();
! 846: }
! 847: cc = replace_pop();
! 848: if (cc > 0)
! 849: {
! 850: ins_char(cc);
! 851: dec_cursor();
! 852: }
! 853: State = REPLACE;
! 854: }
! 855: }
! 856: else
! 857: dec_cursor();
! 858: did_ai = FALSE;
! 859: }
! 860: else
! 861: {
! 862: #ifdef RIGHTLEFT
! 863: if (revins) /* put cursor on last inserted char */
! 864: dec_cursor();
! 865: #endif
! 866: mincol = 0;
! 867: /* keep indent */
! 868: if (mode == BACKSPACE_LINE && curbuf->b_p_ai
! 869: #ifdef RIGHTLEFT
! 870: && !revins
! 871: #endif
! 872: )
! 873: {
! 874: temp = curwin->w_cursor.col;
! 875: beginline(TRUE);
! 876: if (curwin->w_cursor.col < (colnr_t)temp)
! 877: mincol = curwin->w_cursor.col;
! 878: curwin->w_cursor.col = temp;
! 879: }
! 880:
! 881: /* delete upto starting point, start of line or previous
! 882: * word */
! 883: do
! 884: {
! 885: #ifdef RIGHTLEFT
! 886: if (!revins) /* put cursor on char to be deleted */
! 887: #endif
! 888: dec_cursor();
! 889:
! 890: /* start of word? */
! 891: if (mode == BACKSPACE_WORD &&
! 892: !vim_isspace(gchar_cursor()))
! 893: {
! 894: mode = BACKSPACE_WORD_NOT_SPACE;
! 895: temp = iswordchar(gchar_cursor());
! 896: }
! 897: /* end of word? */
! 898: else if (mode == BACKSPACE_WORD_NOT_SPACE &&
! 899: (vim_isspace(cc = gchar_cursor()) ||
! 900: iswordchar(cc) != temp))
! 901: {
! 902: #ifdef RIGHTLEFT
! 903: if (!revins)
! 904: #endif
! 905: inc_cursor();
! 906: #ifdef RIGHTLEFT
! 907: else if (State == REPLACE)
! 908: dec_cursor();
! 909: #endif
! 910: break;
! 911: }
! 912: if (State == REPLACE)
! 913: {
! 914: /*
! 915: * cc < 0: replace stack empty, just move cursor
! 916: * cc == 0: character was inserted, delete it
! 917: * cc > 0: character was replace, put original back
! 918: */
! 919: cc = replace_pop();
! 920: if (cc > 0)
! 921: pchar_cursor(cc);
! 922: else if (cc == 0)
! 923: (void)delchar(FALSE);
! 924: }
! 925: else /* State != REPLACE */
! 926: {
! 927: (void)delchar(FALSE);
! 928: #ifdef RIGHTLEFT
! 929: if (revinschars)
! 930: {
! 931: revinschars--;
! 932: revinslegal++;
! 933: }
! 934: if (revins && gchar_cursor() == NUL)
! 935: break;
! 936: #endif
! 937: }
! 938: /* Just a single backspace?: */
! 939: if (mode == BACKSPACE_CHAR)
! 940: break;
! 941: } while (
! 942: #ifdef RIGHTLEFT
! 943: revins ||
! 944: #endif
! 945: (curwin->w_cursor.col > mincol &&
! 946: (curwin->w_cursor.lnum != Insstart.lnum ||
! 947: curwin->w_cursor.col != Insstart.col)));
! 948: did_backspace = TRUE;
! 949: }
! 950: did_si = FALSE;
! 951: can_si = FALSE;
! 952: can_si_back = FALSE;
! 953: if (curwin->w_cursor.col <= 1)
! 954: did_ai = FALSE;
! 955: /*
! 956: * It's a little strange to put backspaces into the redo
! 957: * buffer, but it makes auto-indent a lot easier to deal
! 958: * with.
! 959: */
! 960: AppendCharToRedobuff(c);
! 961: redraw:
! 962: need_redraw = TRUE;
! 963: break;
! 964:
! 965: case Ctrl('W'): /* delete word before cursor */
! 966: mode = BACKSPACE_WORD;
! 967: goto dodel;
! 968:
! 969: case Ctrl('U'): /* delete inserted text in current line */
! 970: mode = BACKSPACE_LINE;
! 971: goto dodel;
! 972:
! 973: #ifdef USE_MOUSE
! 974: case K_LEFTMOUSE:
! 975: case K_LEFTDRAG:
! 976: case K_LEFTRELEASE:
! 977: case K_MIDDLEMOUSE:
! 978: case K_MIDDLEDRAG:
! 979: case K_MIDDLERELEASE:
! 980: case K_RIGHTMOUSE:
! 981: case K_RIGHTDRAG:
! 982: case K_RIGHTRELEASE:
! 983: #ifdef USE_GUI
! 984: /* When GUI is active, also move/paste when 'mouse' is empty */
! 985: if (!gui.in_use)
! 986: #endif
! 987: if (!mouse_has(MOUSE_INSERT))
! 988: break;
! 989:
! 990: undisplay_dollar();
! 991: tpos = curwin->w_cursor;
! 992: if (do_mouse(c, BACKWARD, 1L, FALSE))
! 993: {
! 994: start_arrow(&tpos);
! 995: # ifdef CINDENT
! 996: can_cindent = TRUE;
! 997: # endif
! 998: }
! 999:
! 1000: break;
! 1001:
! 1002: case K_IGNORE:
! 1003: break;
! 1004: #endif
! 1005:
! 1006: #ifdef USE_GUI
! 1007: case K_SCROLLBAR:
! 1008: undisplay_dollar();
! 1009: tpos = curwin->w_cursor;
! 1010: if (gui_do_scroll())
! 1011: {
! 1012: start_arrow(&tpos);
! 1013: # ifdef CINDENT
! 1014: can_cindent = TRUE;
! 1015: # endif
! 1016: }
! 1017: break;
! 1018:
! 1019: case K_HORIZ_SCROLLBAR:
! 1020: undisplay_dollar();
! 1021: tpos = curwin->w_cursor;
! 1022: if (gui_do_horiz_scroll())
! 1023: {
! 1024: start_arrow(&tpos);
! 1025: #ifdef CINDENT
! 1026: can_cindent = TRUE;
! 1027: #endif
! 1028: }
! 1029: break;
! 1030: #endif
! 1031:
! 1032: case K_LEFT:
! 1033: undisplay_dollar();
! 1034: tpos = curwin->w_cursor;
! 1035: if (oneleft() == OK)
! 1036: {
! 1037: start_arrow(&tpos);
! 1038: #ifdef RIGHTLEFT
! 1039: /* If exit reversed string, position is fixed */
! 1040: if (revinsscol != -1 &&
! 1041: (int)curwin->w_cursor.col >= revinsscol)
! 1042: revinslegal++;
! 1043: revinschars++;
! 1044: #endif
! 1045: }
! 1046:
! 1047: /*
! 1048: * if 'whichwrap' set for cursor in insert mode may go to
! 1049: * previous line
! 1050: */
! 1051: else if (vim_strchr(p_ww, '[') != NULL &&
! 1052: curwin->w_cursor.lnum > 1)
! 1053: {
! 1054: start_arrow(&tpos);
! 1055: --(curwin->w_cursor.lnum);
! 1056: coladvance(MAXCOL);
! 1057: curwin->w_set_curswant = TRUE; /* so we stay at the end */
! 1058: }
! 1059: else
! 1060: beep_flush();
! 1061: break;
! 1062:
! 1063: case K_HOME:
! 1064: undisplay_dollar();
! 1065: tpos = curwin->w_cursor;
! 1066: if ((mod_mask & MOD_MASK_CTRL))
! 1067: curwin->w_cursor.lnum = 1;
! 1068: curwin->w_cursor.col = 0;
! 1069: curwin->w_curswant = 0;
! 1070: start_arrow(&tpos);
! 1071: break;
! 1072:
! 1073: case K_END:
! 1074: undisplay_dollar();
! 1075: tpos = curwin->w_cursor;
! 1076: if ((mod_mask & MOD_MASK_CTRL))
! 1077: curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
! 1078: coladvance(MAXCOL);
! 1079: curwin->w_curswant = MAXCOL;
! 1080: start_arrow(&tpos);
! 1081: break;
! 1082:
! 1083: case K_S_LEFT:
! 1084: undisplay_dollar();
! 1085: if (curwin->w_cursor.lnum > 1 || curwin->w_cursor.col > 0)
! 1086: {
! 1087: start_arrow(&curwin->w_cursor);
! 1088: (void)bck_word(1L, 0, FALSE);
! 1089: }
! 1090: else
! 1091: beep_flush();
! 1092: break;
! 1093:
! 1094: case K_RIGHT:
! 1095: undisplay_dollar();
! 1096: if (gchar_cursor() != NUL)
! 1097: {
! 1098: start_arrow(&curwin->w_cursor);
! 1099: curwin->w_set_curswant = TRUE;
! 1100: ++curwin->w_cursor.col;
! 1101: #ifdef RIGHTLEFT
! 1102: revinslegal++;
! 1103: if (revinschars)
! 1104: revinschars--;
! 1105: #endif
! 1106: }
! 1107: /* if 'whichwrap' set for cursor in insert mode may go
! 1108: * to next line */
! 1109: else if (vim_strchr(p_ww, ']') != NULL &&
! 1110: curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
! 1111: {
! 1112: start_arrow(&curwin->w_cursor);
! 1113: curwin->w_set_curswant = TRUE;
! 1114: ++curwin->w_cursor.lnum;
! 1115: curwin->w_cursor.col = 0;
! 1116: }
! 1117: else
! 1118: beep_flush();
! 1119: break;
! 1120:
! 1121: case K_S_RIGHT:
! 1122: undisplay_dollar();
! 1123: if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count ||
! 1124: gchar_cursor() != NUL)
! 1125: {
! 1126: start_arrow(&curwin->w_cursor);
! 1127: (void)fwd_word(1L, 0, 0);
! 1128: }
! 1129: else
! 1130: beep_flush();
! 1131: break;
! 1132:
! 1133: case K_UP:
! 1134: undisplay_dollar();
! 1135: tpos = curwin->w_cursor;
! 1136: if (cursor_up(1L) == OK)
! 1137: {
! 1138: start_arrow(&tpos);
! 1139: #ifdef CINDENT
! 1140: can_cindent = TRUE;
! 1141: #endif
! 1142: }
! 1143: else
! 1144: beep_flush();
! 1145: break;
! 1146:
! 1147: case K_S_UP:
! 1148: case K_PAGEUP:
! 1149: undisplay_dollar();
! 1150: tpos = curwin->w_cursor;
! 1151: if (onepage(BACKWARD, 1L) == OK)
! 1152: {
! 1153: start_arrow(&tpos);
! 1154: #ifdef CINDENT
! 1155: can_cindent = TRUE;
! 1156: #endif
! 1157: }
! 1158: else
! 1159: beep_flush();
! 1160: break;
! 1161:
! 1162: case K_DOWN:
! 1163: undisplay_dollar();
! 1164: tpos = curwin->w_cursor;
! 1165: if (cursor_down(1L) == OK)
! 1166: {
! 1167: start_arrow(&tpos);
! 1168: #ifdef CINDENT
! 1169: can_cindent = TRUE;
! 1170: #endif
! 1171: }
! 1172: else
! 1173: beep_flush();
! 1174: break;
! 1175:
! 1176: case K_S_DOWN:
! 1177: case K_PAGEDOWN:
! 1178: undisplay_dollar();
! 1179: tpos = curwin->w_cursor;
! 1180: if (onepage(FORWARD, 1L) == OK)
! 1181: {
! 1182: start_arrow(&tpos);
! 1183: #ifdef CINDENT
! 1184: can_cindent = TRUE;
! 1185: #endif
! 1186: }
! 1187: else
! 1188: beep_flush();
! 1189: break;
! 1190:
! 1191: case TAB: /* TAB or Complete patterns along path */
! 1192: #ifdef INSERT_EXPAND
! 1193: if (ctrl_x_mode == CTRL_X_PATH_PATTERNS)
! 1194: goto docomplete;
! 1195: #endif /* INSERT_EXPAND */
! 1196:
! 1197: if (Insstart_blank_vcol == MAXCOL &&
! 1198: curwin->w_cursor.lnum == Insstart.lnum)
! 1199: Insstart_blank_vcol = curwin->w_virtcol;
! 1200: if (echeck_abbr(TAB + ABBR_OFF))
! 1201: break;
! 1202: i = inindent(0);
! 1203: #ifdef CINDENT
! 1204: if (i)
! 1205: can_cindent = FALSE;
! 1206: #endif
! 1207: if (!curbuf->b_p_et && !(p_sta && i))
! 1208: goto normalchar;
! 1209:
! 1210: stop_arrow();
! 1211: did_ai = FALSE;
! 1212: did_si = FALSE;
! 1213: can_si = FALSE;
! 1214: can_si_back = FALSE;
! 1215: AppendToRedobuff((char_u *)"\t");
! 1216:
! 1217: if (p_sta && i) /* insert tab in indent */
! 1218: {
! 1219: change_indent(INDENT_INC, 0, p_sr);
! 1220: goto redraw;
! 1221: }
! 1222:
! 1223: /*
! 1224: * p_et is set: expand a tab into spaces
! 1225: */
! 1226: temp = (int)curbuf->b_p_ts;
! 1227: temp -= curwin->w_virtcol % temp;
! 1228:
! 1229: /*
! 1230: * insert the first space with ins_char(); it will delete one
! 1231: * char in replace mode. Insert the rest with ins_str(); it
! 1232: * will not delete any chars
! 1233: */
! 1234: ins_char(' ');
! 1235: while (--temp)
! 1236: {
! 1237: ins_str((char_u *)" ");
! 1238: if (State == REPLACE) /* no char replaced */
! 1239: replace_push(NUL);
! 1240: }
! 1241: goto redraw;
! 1242:
! 1243: case CR:
! 1244: case NL:
! 1245: if (echeck_abbr(c + ABBR_OFF))
! 1246: break;
! 1247: stop_arrow();
! 1248: if (State == REPLACE)
! 1249: replace_push(NUL);
! 1250: #ifdef RIGHTLEFT
! 1251: /* NL in reverse insert will allways start in the end of
! 1252: * current line. */
! 1253: if (revins)
! 1254: while (gchar_cursor() != NUL)
! 1255: ++curwin->w_cursor.col;
! 1256: #endif
! 1257:
! 1258: AppendToRedobuff(NL_STR);
! 1259: if (has_format_option(FO_RET_COMS))
! 1260: fo_do_comments = TRUE;
! 1261: i = Opencmd(FORWARD, TRUE, FALSE);
! 1262: fo_do_comments = FALSE;
! 1263: #ifdef CINDENT
! 1264: can_cindent = TRUE;
! 1265: #endif
! 1266: if (!i)
! 1267: goto doESCkey; /* out of memory */
! 1268: break;
! 1269:
! 1270: #ifdef DIGRAPHS
! 1271: case Ctrl('K'):
! 1272: #ifdef INSERT_EXPAND
! 1273: if (ctrl_x_mode == CTRL_X_DICTIONARY)
! 1274: goto docomplete;
! 1275: #endif
! 1276: if (NextScreen != NULL)
! 1277: screen_outchar('?', curwin->w_winpos + curwin->w_row,
! 1278: #ifdef RIGHTLEFT
! 1279: curwin->w_p_rl ? (int)Columns - 1 - curwin->w_col :
! 1280: #endif
! 1281: curwin->w_col);
! 1282: if (!add_to_showcmd(c, FALSE))
! 1283: setcursor();
! 1284: /* don't map the digraph chars. This also prevents the
! 1285: * mode message to be deleted when ESC is hit */
! 1286: ++no_mapping;
! 1287: ++allow_keys;
! 1288: c = vgetc();
! 1289: --no_mapping;
! 1290: --allow_keys;
! 1291: if (IS_SPECIAL(c)) /* special key */
! 1292: {
! 1293: clear_showcmd();
! 1294: insert_special(c, TRUE);
! 1295: need_redraw = TRUE;
! 1296: break;
! 1297: }
! 1298: if (c != ESC)
! 1299: {
! 1300: if (charsize(c) == 1 && NextScreen != NULL)
! 1301: screen_outchar(c, curwin->w_winpos + curwin->w_row,
! 1302: #ifdef RIGHTLEFT
! 1303: curwin->w_p_rl ? (int)Columns - 1 - curwin->w_col :
! 1304: #endif
! 1305: curwin->w_col);
! 1306: if (!add_to_showcmd(c, FALSE))
! 1307: setcursor();
! 1308: ++no_mapping;
! 1309: ++allow_keys;
! 1310: cc = vgetc();
! 1311: --no_mapping;
! 1312: --allow_keys;
! 1313: if (cc != ESC)
! 1314: {
! 1315: AppendToRedobuff((char_u *)"\026"); /* CTRL-V */
! 1316: c = getdigraph(c, cc, TRUE);
! 1317: clear_showcmd();
! 1318: goto normalchar;
! 1319: }
! 1320: }
! 1321: clear_showcmd();
! 1322: need_redraw = TRUE;
! 1323: break;
! 1324: #else /* DIGRAPHS */
! 1325: # ifdef INSERT_EXPAND
! 1326: case Ctrl('K'):
! 1327: if (ctrl_x_mode != CTRL_X_DICTIONARY)
! 1328: goto normalchar;
! 1329: goto docomplete;
! 1330: # endif /* INSERT_EXPAND */
! 1331: #endif /* DIGRAPHS */
! 1332:
! 1333: #ifdef INSERT_EXPAND
! 1334: case Ctrl(']'): /* Tag name completion after ^X */
! 1335: if (ctrl_x_mode != CTRL_X_TAGS)
! 1336: goto normalchar;
! 1337: goto docomplete;
! 1338:
! 1339: case Ctrl('F'): /* File name completion after ^X */
! 1340: if (ctrl_x_mode != CTRL_X_FILES)
! 1341: goto normalchar;
! 1342: goto docomplete;
! 1343:
! 1344: case Ctrl('L'): /* Whole line completion after ^X */
! 1345: if (ctrl_x_mode != CTRL_X_WHOLE_LINE)
! 1346: goto normalchar;
! 1347: /* FALLTHROUGH */
! 1348:
! 1349: case Ctrl('P'): /* Do previous pattern completion */
! 1350: case Ctrl('N'): /* Do next pattern completion */
! 1351: docomplete:
! 1352: if (c == Ctrl('P') || c == Ctrl('L'))
! 1353: complete_direction = BACKWARD;
! 1354: else
! 1355: complete_direction = FORWARD;
! 1356: quick_m = mesg = NULL; /* No message by default */
! 1357: if (!started_completion)
! 1358: {
! 1359: /* First time we hit ^N or ^P (in a row, I mean) */
! 1360:
! 1361: /* Turn off 'sm' so we don't show matches with ^X^L */
! 1362: save_sm = p_sm;
! 1363: p_sm = FALSE;
! 1364:
! 1365: if (ctrl_x_mode == 0)
! 1366: {
! 1367: edit_submode = (char_u *)" Keyword completion (^P/^N)";
! 1368: showmode();
! 1369: }
! 1370: did_ai = FALSE;
! 1371: did_si = FALSE;
! 1372: can_si = FALSE;
! 1373: can_si_back = FALSE;
! 1374: stop_arrow();
! 1375: done_dir = 0;
! 1376: first_match_pos = curwin->w_cursor;
! 1377: ptr = tmp_ptr = ml_get(first_match_pos.lnum);
! 1378: complete_col = first_match_pos.col;
! 1379: temp = (int)complete_col - 1;
! 1380:
! 1381: /* Work out completion pattern and original text -- webb */
! 1382: if (ctrl_x_mode == 0 || (ctrl_x_mode & CTRL_X_WANT_IDENT))
! 1383: {
! 1384: if (temp < 0 || !iswordchar(ptr[temp]))
! 1385: {
! 1386: /* Match any word of at least two chars */
! 1387: complete_pat = strsave((char_u *)"\\<\\k\\k");
! 1388: if (complete_pat == NULL)
! 1389: break;
! 1390: tmp_ptr += complete_col;
! 1391: temp = 0;
! 1392: }
! 1393: else
! 1394: {
! 1395: while (temp >= 0 && iswordchar(ptr[temp]))
! 1396: temp--;
! 1397: tmp_ptr += ++temp;
! 1398: if ((temp = (int)complete_col - temp) == 1)
! 1399: {
! 1400: /* Only match word with at least two
! 1401: * chars -- webb
! 1402: */
! 1403: sprintf((char *)IObuff, "\\<%c\\k", *tmp_ptr);
! 1404: complete_pat = strsave(IObuff);
! 1405: if (complete_pat == NULL)
! 1406: break;
! 1407: }
! 1408: else
! 1409: {
! 1410: complete_pat = alloc(temp + 3);
! 1411: if (complete_pat == NULL)
! 1412: break;
! 1413: sprintf((char *)complete_pat, "\\<%.*s", temp,
! 1414: tmp_ptr);
! 1415: }
! 1416: }
! 1417: }
! 1418: else if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
! 1419: {
! 1420: tmp_ptr = skipwhite(ptr);
! 1421: temp = (int)complete_col - (tmp_ptr - ptr);
! 1422: complete_pat = strnsave(tmp_ptr, temp);
! 1423: if (complete_pat == NULL)
! 1424: break;
! 1425: }
! 1426: else if (ctrl_x_mode == CTRL_X_FILES)
! 1427: {
! 1428: while (temp >= 0 && isfilechar(ptr[temp]))
! 1429: temp--;
! 1430: tmp_ptr += ++temp;
! 1431: temp = (int)complete_col - temp;
! 1432: complete_pat = addstar(tmp_ptr, temp);
! 1433: if (complete_pat == NULL)
! 1434: break;
! 1435: }
! 1436: original_text = strnsave(tmp_ptr, temp);
! 1437: if (original_text == NULL)
! 1438: {
! 1439: vim_free(complete_pat);
! 1440: complete_pat = NULL;
! 1441: break;
! 1442: }
! 1443:
! 1444: complete_col = tmp_ptr - ptr;
! 1445: first_match_pos.col -= temp;
! 1446:
! 1447: /* So that ^N can match word immediately after cursor */
! 1448: if (ctrl_x_mode == 0)
! 1449: dec(&first_match_pos);
! 1450:
! 1451: last_match_pos = first_match_pos;
! 1452:
! 1453: /* Get list of all completions now, if appropriate */
! 1454: if (ctrl_x_mode == CTRL_X_PATH_PATTERNS ||
! 1455: ctrl_x_mode == CTRL_X_PATH_DEFINES)
! 1456: {
! 1457: started_completion = TRUE;
! 1458: find_pattern_in_path(complete_pat,
! 1459: (int)STRLEN(complete_pat), FALSE, FALSE,
! 1460: (ctrl_x_mode == CTRL_X_PATH_DEFINES) ? FIND_DEFINE
! 1461: : FIND_ANY, 1L, ACTION_EXPAND,
! 1462: (linenr_t)1, (linenr_t)MAXLNUM);
! 1463:
! 1464: if (make_cyclic() > 1)
! 1465: {
! 1466: sprintf((char *)IObuff, "There are %d matches",
! 1467: count_completions());
! 1468: mesg = IObuff;
! 1469: }
! 1470: }
! 1471: else if (ctrl_x_mode == CTRL_X_DICTIONARY)
! 1472: {
! 1473: started_completion = TRUE;
! 1474: if (*p_dict == NUL)
! 1475: mesg = (char_u *)"'dictionary' option is empty";
! 1476: else
! 1477: {
! 1478: complete_dictionaries(complete_pat,
! 1479: complete_direction);
! 1480: if (make_cyclic() > 1)
! 1481: {
! 1482: sprintf((char *)IObuff,
! 1483: "There are %d matching words",
! 1484: count_completions());
! 1485: mesg = IObuff;
! 1486: }
! 1487: }
! 1488: }
! 1489: else if (ctrl_x_mode == CTRL_X_TAGS)
! 1490: {
! 1491: started_completion = TRUE;
! 1492: /* set reg_ic according to p_ic, p_scs and pat */
! 1493: set_reg_ic(complete_pat);
! 1494: prog = vim_regcomp(complete_pat);
! 1495: if (prog != NULL &&
! 1496: find_tags(NULL, prog, &num_matches, &matches, FALSE)
! 1497: == OK && num_matches > 0)
! 1498: {
! 1499: for (i = 0; i < num_matches; i++)
! 1500: if (add_completion(matches[i], -1, NULL,
! 1501: FORWARD) == RET_ERROR)
! 1502: break;
! 1503: FreeWild(num_matches, matches);
! 1504: vim_free(prog);
! 1505: if (make_cyclic() > 1)
! 1506: {
! 1507: sprintf((char *)IObuff,
! 1508: "There are %d matching tags",
! 1509: count_completions());
! 1510: mesg = IObuff;
! 1511: }
! 1512: }
! 1513: else
! 1514: {
! 1515: vim_free(prog);
! 1516: vim_free(complete_pat);
! 1517: complete_pat = NULL;
! 1518: }
! 1519: }
! 1520: else if (ctrl_x_mode == CTRL_X_FILES)
! 1521: {
! 1522: started_completion = TRUE;
! 1523: expand_interactively = TRUE;
! 1524: if (ExpandWildCards(1, &complete_pat, &num_matches,
! 1525: &matches, FALSE, FALSE) == OK)
! 1526: {
! 1527: for (i = 0; i < num_matches; i++)
! 1528: if (add_completion(matches[i], -1, NULL,
! 1529: FORWARD) == RET_ERROR)
! 1530: break;
! 1531: FreeWild(num_matches, matches);
! 1532: if (make_cyclic() > 1)
! 1533: {
! 1534: sprintf((char *)IObuff,
! 1535: "There are %d matching file names",
! 1536: count_completions());
! 1537: mesg = IObuff;
! 1538: }
! 1539: }
! 1540: else
! 1541: {
! 1542: vim_free(complete_pat);
! 1543: complete_pat = NULL;
! 1544: }
! 1545: expand_interactively = FALSE;
! 1546: }
! 1547: }
! 1548: /*
! 1549: * In insert mode: Delete the typed part.
! 1550: * In replace mode: Put the old characters back, if any.
! 1551: */
! 1552: while (curwin->w_cursor.col > complete_col)
! 1553: {
! 1554: curwin->w_cursor.col--;
! 1555: if (State == REPLACE)
! 1556: {
! 1557: if ((cc = replace_pop()) > 0)
! 1558: pchar(curwin->w_cursor, cc);
! 1559: }
! 1560: else
! 1561: delchar(FALSE);
! 1562: }
! 1563: complete_pos = NULL;
! 1564: if (started_completion && curr_match == NULL &&
! 1565: (p_ws || done_dir == BOTH_DIRECTIONS))
! 1566: quick_m = e_patnotf;
! 1567: else if (curr_match != NULL && complete_direction == FORWARD &&
! 1568: curr_match->next != NULL)
! 1569: curr_match = curr_match->next;
! 1570: else if (curr_match != NULL && complete_direction == BACKWARD &&
! 1571: curr_match->prev != NULL)
! 1572: curr_match = curr_match->prev;
! 1573: else
! 1574: {
! 1575: complete_pos = (complete_direction == FORWARD) ?
! 1576: &last_match_pos : &first_match_pos;
! 1577: /*
! 1578: * If 'infercase' is set, don't use 'smartcase' here
! 1579: */
! 1580: save_p_scs = p_scs;
! 1581: if (curbuf->b_p_inf)
! 1582: p_scs = FALSE;
! 1583: for (;;)
! 1584: {
! 1585: if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
! 1586: temp = search_for_exact_line(complete_pos,
! 1587: complete_direction, complete_pat);
! 1588: else
! 1589: temp = searchit(complete_pos, complete_direction,
! 1590: complete_pat, 1L,
! 1591: SEARCH_KEEP + SEARCH_NFMSG, RE_LAST);
! 1592: if (temp == FAIL)
! 1593: {
! 1594: if (!p_ws && done_dir != -complete_direction)
! 1595: {
! 1596: /*
! 1597: * With nowrapscan, we haven't finished
! 1598: * looking in the other direction yet -- webb
! 1599: */
! 1600: temp = OK;
! 1601: done_dir = complete_direction;
! 1602: }
! 1603: else if (!p_ws)
! 1604: done_dir = BOTH_DIRECTIONS;
! 1605: break;
! 1606: }
! 1607: if (!started_completion)
! 1608: {
! 1609: started_completion = TRUE;
! 1610: first_match_pos = *complete_pos;
! 1611: last_match_pos = *complete_pos;
! 1612: }
! 1613: else if (first_match_pos.lnum == last_match_pos.lnum &&
! 1614: first_match_pos.col == last_match_pos.col)
! 1615: {
! 1616: /* We have found all the matches in this file */
! 1617: temp = FAIL;
! 1618: break;
! 1619: }
! 1620: ptr = ml_get_pos(complete_pos);
! 1621: if (ctrl_x_mode == CTRL_X_WHOLE_LINE)
! 1622: temp = STRLEN(ptr);
! 1623: else
! 1624: {
! 1625: tmp_ptr = ptr;
! 1626: temp = 0;
! 1627: while (*tmp_ptr != NUL && iswordchar(*tmp_ptr++))
! 1628: temp++;
! 1629: }
! 1630: if (add_completion_and_infercase(ptr, temp, NULL,
! 1631: complete_direction) != FAIL)
! 1632: {
! 1633: temp = OK;
! 1634: break;
! 1635: }
! 1636: }
! 1637: p_scs = save_p_scs;
! 1638: }
! 1639: if (complete_pos != NULL && temp == FAIL)
! 1640: {
! 1641: int tot;
! 1642:
! 1643: tot = count_completions(); /* Total num matches */
! 1644: if (curr_match != NULL)
! 1645: (void)make_cyclic();
! 1646: if (tot > 1)
! 1647: {
! 1648: sprintf((char *)IObuff,
! 1649: "All %d matches have now been found", tot);
! 1650: mesg = IObuff;
! 1651: }
! 1652: else if (tot == 0)
! 1653: quick_m = e_patnotf;
! 1654: }
! 1655:
! 1656: /* eat the ESC to avoid leaving insert mode */
! 1657: if (got_int)
! 1658: {
! 1659: (void)vgetc();
! 1660: got_int = FALSE;
! 1661: }
! 1662:
! 1663: /*
! 1664: * When using match from another file, show the file name.
! 1665: */
! 1666: if (curr_match != NULL)
! 1667: ptr = curr_match->str;
! 1668: else /* back to what has been typed */
! 1669: ptr = original_text;
! 1670:
! 1671: if (curr_match == NULL || curr_match->original)
! 1672: {
! 1673: edit_submode_extra = (char_u *)"Back at original";
! 1674: edit_submode_highl = TRUE;
! 1675: }
! 1676: else if (first_match != NULL && first_match->next != NULL &&
! 1677: (first_match->next == first_match ||
! 1678: first_match->next->original))
! 1679: {
! 1680: edit_submode_extra = (char_u *)"(the only match)";
! 1681: edit_submode_highl = FALSE;
! 1682: }
! 1683:
! 1684: /*
! 1685: * Use ins_char() to insert the text, it is a bit slower than
! 1686: * ins_str(), but it takes care of replace mode.
! 1687: */
! 1688: if (ptr != NULL)
! 1689: while (*ptr)
! 1690: ins_char(*ptr++);
! 1691:
! 1692: started_completion = TRUE;
! 1693: need_redraw = TRUE;
! 1694: (void)set_highlight('r');
! 1695: msg_highlight = TRUE;
! 1696: if (mesg != NULL)
! 1697: {
! 1698: msg(mesg);
! 1699: mch_delay(1000L, FALSE);
! 1700: }
! 1701: else if (quick_m != NULL)
! 1702: msg(quick_m);
! 1703: else if (edit_submode_extra != NULL)
! 1704: showmode();
! 1705: edit_submode_extra = NULL;
! 1706: msg_highlight = FALSE;
! 1707:
! 1708: /*
! 1709: * If there is a file name for the match, overwrite any
! 1710: * previous message, it's more interesting to know where the
! 1711: * match comes from, except when using the dictionary.
! 1712: * Truncate the file name to avoid a wait for return.
! 1713: */
! 1714: if (curr_match != NULL && curr_match->fname != NULL &&
! 1715: (ctrl_x_mode != CTRL_X_DICTIONARY ||
! 1716: (mesg == NULL && quick_m == NULL)))
! 1717: {
! 1718: STRCPY(IObuff, "match in file ");
! 1719: i = (strsize(curr_match->fname) + 16) - sc_col;
! 1720: if (i <= 0)
! 1721: i = 0;
! 1722: else
! 1723: STRCAT(IObuff, "<");
! 1724: STRCAT(IObuff, curr_match->fname + i);
! 1725: msg(IObuff);
! 1726: }
! 1727: break;
! 1728: #endif /* INSERT_EXPAND */
! 1729:
! 1730: case Ctrl('Y'): /* copy from previous line */
! 1731: #ifdef INSERT_EXPAND
! 1732: if (ctrl_x_mode == CTRL_X_SCROLL)
! 1733: {
! 1734: scrolldown_clamp();
! 1735: updateScreen(VALID);
! 1736: break;
! 1737: }
! 1738: #endif /* INSERT_EXPAND */
! 1739: lnum = curwin->w_cursor.lnum - 1;
! 1740: goto copychar;
! 1741:
! 1742: case Ctrl('E'): /* copy from next line */
! 1743: #ifdef INSERT_EXPAND
! 1744: if (ctrl_x_mode == CTRL_X_SCROLL)
! 1745: {
! 1746: scrollup_clamp();
! 1747: updateScreen(VALID);
! 1748: break;
! 1749: }
! 1750: #endif /* INSERT_EXPAND */
! 1751: lnum = curwin->w_cursor.lnum + 1;
! 1752: copychar:
! 1753: if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
! 1754: {
! 1755: beep_flush();
! 1756: break;
! 1757: }
! 1758:
! 1759: /* try to advance to the cursor column */
! 1760: temp = 0;
! 1761: ptr = ml_get(lnum);
! 1762: while ((colnr_t)temp < curwin->w_virtcol && *ptr)
! 1763: temp += lbr_chartabsize(ptr++, (colnr_t)temp);
! 1764:
! 1765: if ((colnr_t)temp > curwin->w_virtcol)
! 1766: --ptr;
! 1767: if ((c = *ptr) == NUL)
! 1768: {
! 1769: beep_flush();
! 1770: break;
! 1771: }
! 1772:
! 1773: /*FALLTHROUGH*/
! 1774: default:
! 1775: normalchar:
! 1776: /*
! 1777: * do some very smart indenting when entering '{' or '}'
! 1778: */
! 1779: if (((did_si || can_si_back) && c == '{') ||
! 1780: (can_si && c == '}'))
! 1781: {
! 1782: FPOS *pos, old_pos;
! 1783:
! 1784: /* for '}' set indent equal to indent of line
! 1785: * containing matching '{'
! 1786: */
! 1787: if (c == '}' && (pos = findmatch('{')) != NULL)
! 1788: {
! 1789: old_pos = curwin->w_cursor;
! 1790: /*
! 1791: * If the matching '{' has a ')' immediately before it
! 1792: * (ignoring white-space), then line up with the start
! 1793: * of the line containing the matching '(' if there is
! 1794: * one. This handles the case where an
! 1795: * "if (..\n..) {" statement continues over multiple
! 1796: * lines -- webb
! 1797: */
! 1798: ptr = ml_get(pos->lnum);
! 1799: i = pos->col;
! 1800: if (i > 0) /* skip blanks before '{' */
! 1801: while (--i > 0 && vim_iswhite(ptr[i]))
! 1802: ;
! 1803: curwin->w_cursor.lnum = pos->lnum;
! 1804: curwin->w_cursor.col = i;
! 1805: if (ptr[i] == ')' && (pos = findmatch('(')) != NULL)
! 1806: curwin->w_cursor = *pos;
! 1807: i = get_indent();
! 1808: curwin->w_cursor = old_pos;
! 1809: set_indent(i, TRUE);
! 1810: }
! 1811: else if (curwin->w_cursor.col > 0)
! 1812: {
! 1813: /*
! 1814: * when inserting '{' after "O" reduce indent, but not
! 1815: * more than indent of previous line
! 1816: */
! 1817: temp = TRUE;
! 1818: if (c == '{' && can_si_back &&
! 1819: curwin->w_cursor.lnum > 1)
! 1820: {
! 1821: old_pos = curwin->w_cursor;
! 1822: i = get_indent();
! 1823: while (curwin->w_cursor.lnum > 1)
! 1824: {
! 1825: ptr = skipwhite(
! 1826: ml_get(--(curwin->w_cursor.lnum)));
! 1827: /* ignore empty lines and lines starting with
! 1828: * '#'.
! 1829: */
! 1830: if (*ptr != '#' && *ptr != NUL)
! 1831: break;
! 1832: }
! 1833: if (get_indent() >= i)
! 1834: temp = FALSE;
! 1835: curwin->w_cursor = old_pos;
! 1836: }
! 1837: if (temp)
! 1838: shift_line(TRUE, FALSE, 1);
! 1839: }
! 1840: }
! 1841: /* set indent of '#' always to 0 */
! 1842: if (curwin->w_cursor.col > 0 && can_si && c == '#')
! 1843: {
! 1844: /* remember current indent for next line */
! 1845: old_indent = get_indent();
! 1846: set_indent(0, TRUE);
! 1847: }
! 1848:
! 1849: if (c == ' ')
! 1850: {
! 1851: #ifdef CINDENT
! 1852: if (inindent(0))
! 1853: can_cindent = FALSE;
! 1854: #endif
! 1855: if (Insstart_blank_vcol == MAXCOL &&
! 1856: curwin->w_cursor.lnum == Insstart.lnum)
! 1857: Insstart_blank_vcol = curwin->w_virtcol;
! 1858: }
! 1859:
! 1860: if (iswordchar(c) || !echeck_abbr(c))
! 1861: {
! 1862: insert_special(c, FALSE);
! 1863: need_redraw = TRUE;
! 1864: #ifdef RIGHTLEFT
! 1865: revinslegal++;
! 1866: revinschars++;
! 1867: #endif
! 1868: }
! 1869: break;
! 1870: } /* end of switch (c) */
! 1871:
! 1872: #ifdef CINDENT
! 1873: if (curbuf->b_p_cin && can_cindent
! 1874: # ifdef INSERT_EXPAND
! 1875: && !ctrl_x_mode
! 1876: # endif
! 1877: )
! 1878: {
! 1879: force_cindent:
! 1880: /*
! 1881: * Indent now if a key was typed that is in 'cinkeys'.
! 1882: */
! 1883: if (in_cinkeys(c, ' ', line_is_white))
! 1884: {
! 1885: stop_arrow();
! 1886:
! 1887: /* re-indent the current line */
! 1888: fixthisline(get_c_indent);
! 1889:
! 1890: /* draw the changes on the screen later */
! 1891: need_redraw = TRUE;
! 1892: }
! 1893: }
! 1894: #endif /* CINDENT */
! 1895:
! 1896: } /* for (;;) */
! 1897: }
! 1898:
! 1899: /*
! 1900: * Insert an indent (for <Tab> or CTRL-T) or delete an indent (for CTRL-D).
! 1901: * Keep the cursor on the same character.
! 1902: * type == INDENT_INC increase indent (for CTRL-T or <Tab>)
! 1903: * type == INDENT_DEC decrease indent (for CTRL-D)
! 1904: * type == INDENT_SET set indent to "amount"
! 1905: * if round is TRUE, round the indent to 'shiftwidth' (only with _INC and _Dec).
! 1906: */
! 1907: static void
! 1908: change_indent(type, amount, round)
! 1909: int type;
! 1910: int amount;
! 1911: int round;
! 1912: {
! 1913: int vcol;
! 1914: int last_vcol;
! 1915: int insstart_less; /* reduction for Insstart.col */
! 1916: int new_cursor_col;
! 1917: int i;
! 1918: char_u *ptr;
! 1919: int save_p_list;
! 1920:
! 1921: /* for the following tricks we don't want list mode */
! 1922: save_p_list = curwin->w_p_list;
! 1923: if (save_p_list)
! 1924: {
! 1925: curwin->w_p_list = FALSE;
! 1926: curs_columns(FALSE); /* recompute w_virtcol */
! 1927: }
! 1928: vcol = curwin->w_virtcol;
! 1929:
! 1930: /* determine offset from first non-blank */
! 1931: new_cursor_col = curwin->w_cursor.col;
! 1932: beginline(TRUE);
! 1933: new_cursor_col -= curwin->w_cursor.col;
! 1934:
! 1935: insstart_less = curwin->w_cursor.col;
! 1936:
! 1937: /*
! 1938: * If the cursor is in the indent, compute how many screen columns the
! 1939: * cursor is to the left of the first non-blank.
! 1940: */
! 1941: if (new_cursor_col < 0)
! 1942: vcol = get_indent() - vcol;
! 1943:
! 1944: /*
! 1945: * Set the new indent. The cursor will be put on the first non-blank.
! 1946: */
! 1947: if (type == INDENT_SET)
! 1948: set_indent(amount, TRUE);
! 1949: else
! 1950: shift_line(type == INDENT_DEC, round, 1);
! 1951: insstart_less -= curwin->w_cursor.col;
! 1952:
! 1953: /*
! 1954: * Try to put cursor on same character.
! 1955: * If the cursor is at or after the first non-blank in the line,
! 1956: * compute the cursor column relative to the column of the first
! 1957: * non-blank character.
! 1958: * If we are not in insert mode, leave the cursor on the first non-blank.
! 1959: * If the cursor is before the first non-blank, position it relative
! 1960: * to the first non-blank, counted in screen columns.
! 1961: */
! 1962: if (new_cursor_col >= 0)
! 1963: new_cursor_col += curwin->w_cursor.col;
! 1964: else if (!(State & INSERT))
! 1965: new_cursor_col = curwin->w_cursor.col;
! 1966: else
! 1967: {
! 1968: /*
! 1969: * Compute the screen column where the cursor should be.
! 1970: */
! 1971: vcol = get_indent() - vcol;
! 1972: curwin->w_virtcol = (vcol < 0) ? 0 : vcol;
! 1973:
! 1974: /*
! 1975: * Advance the cursor until we reach the right screen column.
! 1976: */
! 1977: vcol = last_vcol = 0;
! 1978: new_cursor_col = -1;
! 1979: ptr = ml_get_curline();
! 1980: while (vcol <= (int)curwin->w_virtcol)
! 1981: {
! 1982: last_vcol = vcol;
! 1983: ++new_cursor_col;
! 1984: vcol += lbr_chartabsize(ptr + new_cursor_col, (colnr_t)vcol);
! 1985: }
! 1986: vcol = last_vcol;
! 1987:
! 1988: /*
! 1989: * May need to insert spaces to be able to position the cursor on
! 1990: * the right screen column.
! 1991: */
! 1992: if (vcol != (int)curwin->w_virtcol)
! 1993: {
! 1994: curwin->w_cursor.col = new_cursor_col;
! 1995: i = (int)curwin->w_virtcol - vcol;
! 1996: ptr = alloc(i + 1);
! 1997: if (ptr != NULL)
! 1998: {
! 1999: new_cursor_col += i;
! 2000: ptr[i] = NUL;
! 2001: while (--i >= 0)
! 2002: ptr[i] = ' ';
! 2003: ins_str(ptr);
! 2004: vim_free(ptr);
! 2005: }
! 2006: }
! 2007:
! 2008: /*
! 2009: * When changing the indent while the cursor is in it, reset
! 2010: * Insstart_col to 0.
! 2011: */
! 2012: insstart_less = Insstart.col;
! 2013: }
! 2014:
! 2015: curwin->w_p_list = save_p_list;
! 2016:
! 2017: if (new_cursor_col <= 0)
! 2018: curwin->w_cursor.col = 0;
! 2019: else
! 2020: curwin->w_cursor.col = new_cursor_col;
! 2021: curwin->w_set_curswant = TRUE;
! 2022:
! 2023: /*
! 2024: * May have to adjust the start of the insert.
! 2025: */
! 2026: if ((State & INSERT) && curwin->w_cursor.lnum == Insstart.lnum &&
! 2027: Insstart.col != 0)
! 2028: {
! 2029: if ((int)Insstart.col <= insstart_less)
! 2030: Insstart.col = 0;
! 2031: else
! 2032: Insstart.col -= insstart_less;
! 2033: }
! 2034: }
! 2035:
! 2036: #ifdef INSERT_EXPAND
! 2037: /*
! 2038: * Is the character 'c' a valid key to keep us in the current ctrl-x mode?
! 2039: * -- webb
! 2040: */
! 2041: int
! 2042: is_ctrl_x_key(c)
! 2043: int c;
! 2044: {
! 2045: switch (ctrl_x_mode)
! 2046: {
! 2047: case 0: /* Not in any ctrl-x mode */
! 2048: break;
! 2049: case CTRL_X_NOT_DEFINED_YET:
! 2050: if (c == Ctrl('X') || c == Ctrl('Y') || c == Ctrl('E') ||
! 2051: c == Ctrl('L') || c == Ctrl('F') || c == Ctrl(']') ||
! 2052: c == Ctrl('I') || c == Ctrl('D') || c == Ctrl('P') ||
! 2053: c == Ctrl('N'))
! 2054: return TRUE;
! 2055: break;
! 2056: case CTRL_X_SCROLL:
! 2057: if (c == Ctrl('Y') || c == Ctrl('E'))
! 2058: return TRUE;
! 2059: break;
! 2060: case CTRL_X_WHOLE_LINE:
! 2061: if (c == Ctrl('L') || c == Ctrl('P') || c == Ctrl('N'))
! 2062: return TRUE;
! 2063: break;
! 2064: case CTRL_X_FILES:
! 2065: if (c == Ctrl('F') || c == Ctrl('P') || c == Ctrl('N'))
! 2066: return TRUE;
! 2067: break;
! 2068: case CTRL_X_DICTIONARY:
! 2069: if (c == Ctrl('K') || c == Ctrl('P') || c == Ctrl('N'))
! 2070: return TRUE;
! 2071: break;
! 2072: case CTRL_X_TAGS:
! 2073: if (c == Ctrl(']') || c == Ctrl('P') || c == Ctrl('N'))
! 2074: return TRUE;
! 2075: break;
! 2076: case CTRL_X_PATH_PATTERNS:
! 2077: if (c == Ctrl('P') || c == Ctrl('N'))
! 2078: return TRUE;
! 2079: break;
! 2080: case CTRL_X_PATH_DEFINES:
! 2081: if (c == Ctrl('D') || c == Ctrl('P') || c == Ctrl('N'))
! 2082: return TRUE;
! 2083: break;
! 2084: default:
! 2085: emsg(e_internal);
! 2086: break;
! 2087: }
! 2088: return FALSE;
! 2089: }
! 2090:
! 2091: /*
! 2092: * This is like add_completion(), but if ic and inf are set, then the
! 2093: * case of the originally typed text is used, and the case of the completed
! 2094: * text is infered, ie this tries to work out what case you probably wanted
! 2095: * the rest of the word to be in -- webb
! 2096: */
! 2097: int
! 2098: add_completion_and_infercase(str, len, fname, dir)
! 2099: char_u *str;
! 2100: int len;
! 2101: char_u *fname;
! 2102: int dir;
! 2103: {
! 2104: int has_lower = FALSE;
! 2105: int was_letter = FALSE;
! 2106: int orig_len;
! 2107: int idx;
! 2108:
! 2109: if (p_ic && curbuf->b_p_inf && len < IOSIZE)
! 2110: {
! 2111: /* Infer case of completed part -- webb */
! 2112: orig_len = STRLEN(original_text);
! 2113:
! 2114: /* Use IObuff, str would change text in buffer! */
! 2115: STRNCPY(IObuff, str, len);
! 2116: IObuff[len] = NUL;
! 2117:
! 2118: /* Rule 1: Were any chars converted to lower? */
! 2119: for (idx = 0; idx < orig_len; ++idx)
! 2120: {
! 2121: if (islower(original_text[idx]))
! 2122: {
! 2123: has_lower = TRUE;
! 2124: if (isupper(IObuff[idx]))
! 2125: {
! 2126: /* Rule 1 is satisfied */
! 2127: for (idx = orig_len; idx < len; ++idx)
! 2128: IObuff[idx] = TO_LOWER(IObuff[idx]);
! 2129: break;
! 2130: }
! 2131: }
! 2132: }
! 2133:
! 2134: /*
! 2135: * Rule 2: No lower case, 2nd consecutive letter converted to
! 2136: * upper case.
! 2137: */
! 2138: if (!has_lower)
! 2139: {
! 2140: for (idx = 0; idx < orig_len; ++idx)
! 2141: {
! 2142: if (was_letter && isupper(original_text[idx]) &&
! 2143: islower(IObuff[idx]))
! 2144: {
! 2145: /* Rule 2 is satisfied */
! 2146: for (idx = orig_len; idx < len; ++idx)
! 2147: IObuff[idx] = TO_UPPER(IObuff[idx]);
! 2148: break;
! 2149: }
! 2150: was_letter = isalpha(original_text[idx]);
! 2151: }
! 2152: }
! 2153:
! 2154: /* Copy the original case of the part we typed */
! 2155: STRNCPY(IObuff, original_text, orig_len);
! 2156:
! 2157: return add_completion(IObuff, len, fname, dir);
! 2158: }
! 2159: return add_completion(str, len, fname, dir);
! 2160: }
! 2161:
! 2162: /*
! 2163: * Add a match to the list of matches.
! 2164: * If the given string is already in the list of completions, then return
! 2165: * FAIL, otherwise add it to the list and return OK. If there is an error,
! 2166: * maybe because alloc returns NULL, then RET_ERROR is returned -- webb.
! 2167: */
! 2168: static int
! 2169: add_completion(str, len, fname, dir)
! 2170: char_u *str;
! 2171: int len;
! 2172: char_u *fname;
! 2173: int dir;
! 2174: {
! 2175: struct Completion *match;
! 2176:
! 2177: mch_breakcheck();
! 2178: if (got_int)
! 2179: return RET_ERROR;
! 2180: if (len < 0)
! 2181: len = STRLEN(str);
! 2182:
! 2183: /*
! 2184: * If the same match is already present, don't add it.
! 2185: */
! 2186: if (first_match != NULL)
! 2187: {
! 2188: match = first_match;
! 2189: do
! 2190: {
! 2191: if (STRNCMP(match->str, str, (size_t)len) == 0 &&
! 2192: match->str[len] == NUL)
! 2193: return FAIL;
! 2194: match = match->next;
! 2195: } while (match != NULL && match != first_match);
! 2196: }
! 2197:
! 2198: /*
! 2199: * Allocate a new match structure.
! 2200: * Copy the values to the new match structure.
! 2201: */
! 2202: match = (struct Completion *)alloc((unsigned)sizeof(struct Completion));
! 2203: if (match == NULL)
! 2204: return RET_ERROR;
! 2205: if ((match->str = strnsave(str, len)) == NULL)
! 2206: {
! 2207: vim_free(match);
! 2208: return RET_ERROR;
! 2209: }
! 2210: if (fname != NULL)
! 2211: match->fname = strsave(fname); /* ignore errors */
! 2212: else
! 2213: match->fname = NULL;
! 2214: match->original = FALSE;
! 2215:
! 2216: /*
! 2217: * Link the new match structure in the list of matches.
! 2218: */
! 2219: if (first_match == NULL)
! 2220: {
! 2221: first_match = curr_match = match;
! 2222: curr_match->next = curr_match->prev = NULL;
! 2223: }
! 2224: else
! 2225: {
! 2226: if (dir == FORWARD)
! 2227: {
! 2228: match->next = NULL;
! 2229: match->prev = curr_match;
! 2230: curr_match->next = match;
! 2231: curr_match = match;
! 2232: }
! 2233: else /* BACKWARD */
! 2234: {
! 2235: match->prev = NULL;
! 2236: match->next = curr_match;
! 2237: curr_match->prev = match;
! 2238: first_match = curr_match = match;
! 2239: }
! 2240: }
! 2241:
! 2242: return OK;
! 2243: }
! 2244:
! 2245: /*
! 2246: * Make the completion list cyclic. Add the original text at the end.
! 2247: * Return the number of matches (excluding the original).
! 2248: */
! 2249: static int
! 2250: make_cyclic()
! 2251: {
! 2252: struct Completion *match, *orig;
! 2253: int count = 0;
! 2254:
! 2255: if (first_match != NULL)
! 2256: {
! 2257: /*
! 2258: * Find the end of the list.
! 2259: */
! 2260: match = first_match;
! 2261: count = 1;
! 2262: while (match->next != NULL)
! 2263: {
! 2264: match = match->next;
! 2265: ++count;
! 2266: }
! 2267:
! 2268: if (original_text != NULL)
! 2269: {
! 2270: /*
! 2271: * Allocate a new structure for the original text.
! 2272: * Copy the original text to the new structure.
! 2273: * Link it in the list at the end.
! 2274: */
! 2275: orig = (struct Completion *)alloc((unsigned)sizeof(
! 2276: struct Completion));
! 2277: if (orig != NULL)
! 2278: {
! 2279: if ((orig->str = strsave(original_text)) == NULL)
! 2280: vim_free(orig);
! 2281: else
! 2282: {
! 2283: orig->fname = NULL;
! 2284: orig->original = TRUE;
! 2285: orig->prev = match;
! 2286: match->next = orig;
! 2287: match = orig;
! 2288: curr_match = orig;
! 2289: }
! 2290: }
! 2291: }
! 2292: match->next = first_match;
! 2293: first_match->prev = match;
! 2294: }
! 2295: return count;
! 2296: }
! 2297:
! 2298: /*
! 2299: * Add any identifiers that match the given pattern to the list of
! 2300: * completions.
! 2301: */
! 2302: static void
! 2303: complete_dictionaries(pat, dir)
! 2304: char_u *pat;
! 2305: int dir;
! 2306: {
! 2307: struct Completion *save_curr_match = curr_match;
! 2308: char_u *dict = p_dict;
! 2309: char_u *ptr;
! 2310: char_u *buf;
! 2311: char_u *fname;
! 2312: int at_start;
! 2313: FILE *fp;
! 2314: struct regexp *prog = NULL;
! 2315:
! 2316: if ((buf = alloc(LSIZE)) == NULL)
! 2317: return;
! 2318: if (curr_match != NULL)
! 2319: {
! 2320: while (curr_match->next != NULL)
! 2321: curr_match = curr_match->next;
! 2322: }
! 2323: if (*dict != NUL)
! 2324: {
! 2325: (void)set_highlight('r');
! 2326: msg_highlight = TRUE;
! 2327: MSG("Please wait, searching dictionaries");
! 2328: set_reg_ic(pat); /* set reg_ic according to p_ic, p_scs and pat */
! 2329: reg_magic = p_magic;
! 2330: prog = vim_regcomp(pat);
! 2331: }
! 2332: while (*dict != NUL && prog != NULL && !got_int)
! 2333: {
! 2334: /* copy one dictionary file name into buf */
! 2335: (void)copy_option_part(&dict, buf, LSIZE, ",");
! 2336:
! 2337: fp = fopen((char *)buf, "r"); /* open dictionary file */
! 2338:
! 2339: if (fp != NULL)
! 2340: {
! 2341: fname = strsave(buf); /* keep name of file */
! 2342: /*
! 2343: * Read dictionary file line by line.
! 2344: * Check each line for a match.
! 2345: */
! 2346: while (!got_int && !vim_fgets(buf, LSIZE, fp))
! 2347: {
! 2348: ptr = buf;
! 2349: at_start = TRUE;
! 2350: while (vim_regexec(prog, ptr, at_start))
! 2351: {
! 2352: at_start = FALSE;
! 2353: ptr = prog->startp[0];
! 2354: while (iswordchar(*ptr))
! 2355: ++ptr;
! 2356: if (add_completion_and_infercase(prog->startp[0],
! 2357: (int)(ptr - prog->startp[0]), fname, FORWARD)
! 2358: == RET_ERROR)
! 2359: break;
! 2360: }
! 2361: line_breakcheck();
! 2362: }
! 2363: fclose(fp);
! 2364: vim_free(fname);
! 2365: }
! 2366: }
! 2367: vim_free(prog);
! 2368: if (save_curr_match != NULL)
! 2369: curr_match = save_curr_match;
! 2370: else if (dir == BACKWARD)
! 2371: curr_match = first_match;
! 2372: vim_free(buf);
! 2373: }
! 2374:
! 2375: /*
! 2376: * Free the list of completions
! 2377: */
! 2378: static void
! 2379: free_completions()
! 2380: {
! 2381: struct Completion *match;
! 2382:
! 2383: if (first_match == NULL)
! 2384: return;
! 2385: curr_match = first_match;
! 2386: do
! 2387: {
! 2388: match = curr_match;
! 2389: curr_match = curr_match->next;
! 2390: vim_free(match->str);
! 2391: vim_free(match->fname);
! 2392: vim_free(match);
! 2393: } while (curr_match != NULL && curr_match != first_match);
! 2394: first_match = curr_match = NULL;
! 2395: }
! 2396:
! 2397: /*
! 2398: * Return the number of items in the Completion list
! 2399: */
! 2400: static int
! 2401: count_completions()
! 2402: {
! 2403: struct Completion *match;
! 2404: int num = 0;
! 2405:
! 2406: if (first_match == NULL)
! 2407: return 0;
! 2408: match = first_match;
! 2409: do
! 2410: {
! 2411: if (!match->original) /* original string doesn't count */
! 2412: num++;
! 2413: match = match->next;
! 2414: } while (match != NULL && match != first_match);
! 2415: return num;
! 2416: }
! 2417: #endif /* INSERT_EXPAND */
! 2418:
! 2419: /*
! 2420: * Next character is interpreted literally.
! 2421: * A one, two or three digit decimal number is interpreted as its byte value.
! 2422: * If one or two digits are entered, the next character is given to vungetc().
! 2423: */
! 2424: int
! 2425: get_literal()
! 2426: {
! 2427: int cc;
! 2428: int nc;
! 2429: int i;
! 2430:
! 2431: if (got_int)
! 2432: return Ctrl('C');
! 2433:
! 2434: #ifdef USE_GUI
! 2435: /*
! 2436: * In GUI there is no point inserting the internal code for a special key.
! 2437: * It is more useful to insert the string "<KEY>" instead. This would
! 2438: * probably be useful in a text window too, but it would not be
! 2439: * vi-compatible (maybe there should be an option for it?) -- webb
! 2440: */
! 2441: if (gui.in_use)
! 2442: ++allow_keys;
! 2443: #endif
! 2444: ++no_mapping; /* don't map the next key hits */
! 2445: cc = 0;
! 2446: for (i = 0; i < 3; ++i)
! 2447: {
! 2448: do
! 2449: nc = vgetc();
! 2450: while (nc == K_IGNORE || nc == K_SCROLLBAR || nc == K_HORIZ_SCROLLBAR);
! 2451: if (!(State & CMDLINE))
! 2452: add_to_showcmd(nc, FALSE);
! 2453: if (IS_SPECIAL(nc) || !isdigit(nc))
! 2454: break;
! 2455: cc = cc * 10 + nc - '0';
! 2456: if (cc > 255)
! 2457: cc = 255; /* limit range to 0-255 */
! 2458: nc = 0;
! 2459: }
! 2460: if (i == 0) /* no number entered */
! 2461: {
! 2462: if (nc == K_ZERO) /* NUL is stored as NL */
! 2463: {
! 2464: cc = '\n';
! 2465: nc = 0;
! 2466: }
! 2467: else
! 2468: {
! 2469: cc = nc;
! 2470: nc = 0;
! 2471: }
! 2472: }
! 2473:
! 2474: if (cc == 0) /* NUL is stored as NL */
! 2475: cc = '\n';
! 2476:
! 2477: --no_mapping;
! 2478: #ifdef USE_GUI
! 2479: if (gui.in_use)
! 2480: --allow_keys;
! 2481: #endif
! 2482: if (nc)
! 2483: vungetc(nc);
! 2484: got_int = FALSE; /* CTRL-C typed after CTRL-V is not an interrupt */
! 2485: return cc;
! 2486: }
! 2487:
! 2488: /*
! 2489: * Insert character, taking care of special keys and mod_mask
! 2490: */
! 2491: static void
! 2492: insert_special(c, allow_modmask)
! 2493: int c;
! 2494: int allow_modmask;
! 2495: {
! 2496: char_u *p;
! 2497: int len;
! 2498:
! 2499: /*
! 2500: * Special function key, translate into "<Key>". Up to the last '>' is
! 2501: * inserted with ins_str(), so as not to replace characters in replace
! 2502: * mode.
! 2503: * Only use mod_mask for special keys, to avoid things like <S-Space>,
! 2504: * unless 'allow_modmask' is TRUE.
! 2505: */
! 2506: if (IS_SPECIAL(c) || (mod_mask && allow_modmask))
! 2507: {
! 2508: p = get_special_key_name(c, mod_mask);
! 2509: len = STRLEN(p);
! 2510: c = p[len - 1];
! 2511: if (len > 2)
! 2512: {
! 2513: p[len - 1] = NUL;
! 2514: ins_str(p);
! 2515: AppendToRedobuff(p);
! 2516: }
! 2517: }
! 2518: insertchar(c, FALSE, -1);
! 2519: }
! 2520:
! 2521: /*
! 2522: * Special characters in this context are those that need processing other
! 2523: * than the simple insertion that can be performed here. This includes ESC
! 2524: * which terminates the insert, and CR/NL which need special processing to
! 2525: * open up a new line. This routine tries to optimize insertions performed by
! 2526: * the "redo", "undo" or "put" commands, so it needs to know when it should
! 2527: * stop and defer processing to the "normal" mechanism.
! 2528: */
! 2529: #define ISSPECIAL(c) ((c) < ' ' || (c) >= DEL)
! 2530:
! 2531: void
! 2532: insertchar(c, force_formatting, second_indent)
! 2533: unsigned c;
! 2534: int force_formatting; /* format line regardless of p_fo */
! 2535: int second_indent; /* indent for second line if >= 0 */
! 2536: {
! 2537: int haveto_redraw = FALSE;
! 2538: int textwidth;
! 2539: colnr_t leader_len;
! 2540: int first_line = TRUE;
! 2541: int fo_ins_blank;
! 2542: int save_char = NUL;
! 2543:
! 2544: stop_arrow();
! 2545:
! 2546: /*
! 2547: * find out textwidth to be used:
! 2548: * if 'textwidth' option is set, use it
! 2549: * else if 'wrapmargin' option is set, use Columns - 'wrapmargin'
! 2550: * if invalid value, use 0.
! 2551: * Set default to window width (maximum 79) for "Q" command.
! 2552: */
! 2553: textwidth = curbuf->b_p_tw;
! 2554: if (textwidth == 0 && curbuf->b_p_wm)
! 2555: textwidth = Columns - curbuf->b_p_wm;
! 2556: if (textwidth < 0)
! 2557: textwidth = 0;
! 2558: if (force_formatting && textwidth == 0)
! 2559: {
! 2560: textwidth = Columns - 1;
! 2561: if (textwidth > 79)
! 2562: textwidth = 79;
! 2563: }
! 2564:
! 2565: fo_ins_blank = has_format_option(FO_INS_BLANK);
! 2566:
! 2567: /*
! 2568: * Try to break the line in two or more pieces when:
! 2569: * - Always do this if we have been called to do formatting only.
! 2570: * - Otherwise:
! 2571: * - Don't do this if inserting a blank
! 2572: * - Don't do this if an existing character is being replaced.
! 2573: * - Do this if the cursor is not on the line where insert started
! 2574: * or - 'formatoptions' doesn't have 'l' or the line was not too long
! 2575: * before the insert.
! 2576: * - 'formatoptions' doesn't have 'b' or a blank was inserted at or
! 2577: * before 'textwidth'
! 2578: */
! 2579: if (force_formatting || (!vim_iswhite(c) &&
! 2580: !(State == REPLACE && *ml_get_cursor() != NUL) &&
! 2581: (curwin->w_cursor.lnum != Insstart.lnum ||
! 2582: ((!has_format_option(FO_INS_LONG) ||
! 2583: Insstart_textlen <= (colnr_t)textwidth) &&
! 2584: (!fo_ins_blank || Insstart_blank_vcol <= (colnr_t)textwidth)))))
! 2585: {
! 2586: /*
! 2587: * When 'ai' is off we don't want a space under the cursor to be
! 2588: * deleted. Replace it with an 'x' temporarily.
! 2589: */
! 2590: if (!curbuf->b_p_ai && vim_iswhite(gchar_cursor()))
! 2591: {
! 2592: save_char = gchar_cursor();
! 2593: pchar_cursor('x');
! 2594: }
! 2595: while (textwidth && curwin->w_virtcol >= (colnr_t)textwidth)
! 2596: {
! 2597: int startcol; /* Cursor column at entry */
! 2598: int wantcol; /* column at textwidth border */
! 2599: int foundcol; /* column for start of spaces */
! 2600: int end_foundcol = 0; /* column for start of word */
! 2601: colnr_t len;
! 2602:
! 2603: if (!force_formatting && has_format_option(FO_WRAP_COMS))
! 2604: fo_do_comments = TRUE;
! 2605:
! 2606: /* Don't break until after the comment leader */
! 2607: leader_len = get_leader_len(ml_get_curline(), NULL);
! 2608: if (!force_formatting && leader_len == 0 &&
! 2609: !has_format_option(FO_WRAP))
! 2610:
! 2611: {
! 2612: textwidth = 0;
! 2613: break;
! 2614: }
! 2615: if ((startcol = curwin->w_cursor.col) == 0)
! 2616: break;
! 2617: /* find column of textwidth border */
! 2618: coladvance((colnr_t)textwidth);
! 2619: wantcol = curwin->w_cursor.col;
! 2620:
! 2621: curwin->w_cursor.col = startcol - 1;
! 2622: foundcol = 0;
! 2623: /*
! 2624: * Find position to break at.
! 2625: * Stop at start of line.
! 2626: * Stop at first entered white when 'formatoptions' has 'v'
! 2627: */
! 2628: while (curwin->w_cursor.col > 0 &&
! 2629: ((!fo_ins_blank && !has_format_option(FO_INS_VI)) ||
! 2630: curwin->w_cursor.lnum != Insstart.lnum ||
! 2631: curwin->w_cursor.col >= Insstart.col))
! 2632: {
! 2633: if (vim_iswhite(gchar_cursor()))
! 2634: {
! 2635: /* remember position of blank just before text */
! 2636: end_foundcol = curwin->w_cursor.col;
! 2637: while (curwin->w_cursor.col > 0 &&
! 2638: vim_iswhite(gchar_cursor()))
! 2639: --curwin->w_cursor.col;
! 2640: if (curwin->w_cursor.col == 0 &&
! 2641: vim_iswhite(gchar_cursor()))
! 2642: break; /* only spaces in front of text */
! 2643: /* Don't break until after the comment leader */
! 2644: if (curwin->w_cursor.col < leader_len)
! 2645: break;
! 2646: foundcol = curwin->w_cursor.col + 1;
! 2647: if (curwin->w_cursor.col < (colnr_t)wantcol)
! 2648: break;
! 2649: }
! 2650: --curwin->w_cursor.col;
! 2651: }
! 2652:
! 2653: if (foundcol == 0) /* no spaces, cannot break line */
! 2654: {
! 2655: curwin->w_cursor.col = startcol;
! 2656: break;
! 2657: }
! 2658:
! 2659: /*
! 2660: * offset between cursor position and line break is used by
! 2661: * replace stack functions
! 2662: */
! 2663: replace_offset = startcol - end_foundcol - 1;
! 2664:
! 2665: /*
! 2666: * adjust startcol for spaces that will be deleted and
! 2667: * characters that will remain on top line
! 2668: */
! 2669: curwin->w_cursor.col = foundcol;
! 2670: while (vim_iswhite(gchar_cursor()))
! 2671: {
! 2672: ++curwin->w_cursor.col;
! 2673: --startcol;
! 2674: }
! 2675: startcol -= foundcol;
! 2676: if (startcol < 0)
! 2677: startcol = 0;
! 2678:
! 2679: /* put cursor after pos. to break line */
! 2680: curwin->w_cursor.col = foundcol;
! 2681:
! 2682: Opencmd(FORWARD, FALSE, TRUE);
! 2683:
! 2684: replace_offset = 0;
! 2685: if (second_indent >= 0 && first_line)
! 2686: set_indent(second_indent, TRUE);
! 2687: first_line = FALSE;
! 2688:
! 2689: /*
! 2690: * check if cursor is not past the NUL off the line, cindent may
! 2691: * have added or removed indent.
! 2692: */
! 2693: curwin->w_cursor.col += startcol;
! 2694: len = STRLEN(ml_get_curline());
! 2695: if (curwin->w_cursor.col > len)
! 2696: curwin->w_cursor.col = len;
! 2697:
! 2698: curs_columns(FALSE); /* update curwin->w_virtcol */
! 2699: haveto_redraw = TRUE;
! 2700: #ifdef CINDENT
! 2701: can_cindent = TRUE;
! 2702: #endif
! 2703: }
! 2704:
! 2705: if (save_char) /* put back space after cursor */
! 2706: pchar_cursor(save_char);
! 2707:
! 2708: if (c == NUL) /* formatting only */
! 2709: return;
! 2710: fo_do_comments = FALSE;
! 2711: if (haveto_redraw)
! 2712: {
! 2713: /*
! 2714: * If the cursor ended up just below the screen we scroll up here
! 2715: * to avoid a redraw of the whole screen in the most common cases.
! 2716: */
! 2717: if (curwin->w_cursor.lnum == curwin->w_botline &&
! 2718: !curwin->w_empty_rows)
! 2719: win_del_lines(curwin, 0, 1, TRUE, TRUE);
! 2720: updateScreen(CURSUPD);
! 2721: }
! 2722: }
! 2723: if (c == NUL) /* only formatting was wanted */
! 2724: return;
! 2725:
! 2726: did_ai = FALSE;
! 2727: did_si = FALSE;
! 2728: can_si = FALSE;
! 2729: can_si_back = FALSE;
! 2730:
! 2731: /*
! 2732: * If there's any pending input, grab up to INPUT_BUFLEN at once.
! 2733: * This speeds up normal text input considerably.
! 2734: */
! 2735: #define INPUT_BUFLEN 100
! 2736: if (!ISSPECIAL(c) && vpeekc() != NUL && State != REPLACE
! 2737: #ifdef RIGHTLEFT
! 2738: && !p_ri
! 2739: #endif
! 2740: )
! 2741: {
! 2742: char_u p[INPUT_BUFLEN + 1];
! 2743: int i;
! 2744:
! 2745: p[0] = c;
! 2746: i = 1;
! 2747: while ((c = vpeekc()) != NUL && !ISSPECIAL(c) && i < INPUT_BUFLEN &&
! 2748: (textwidth == 0 ||
! 2749: (curwin->w_virtcol += charsize(p[i - 1])) < (colnr_t)textwidth) &&
! 2750: !(!no_abbr && !iswordchar(c) && iswordchar(p[i - 1])))
! 2751: {
! 2752: #ifdef RIGHTLEFT
! 2753: c = vgetc();
! 2754: if (p_hkmap && KeyTyped)
! 2755: c = hkmap(c); /* Hebrew mode mapping */
! 2756: p[i++] = c;
! 2757: #else
! 2758: p[i++] = vgetc();
! 2759: #endif
! 2760: }
! 2761:
! 2762: #ifdef DIGRAPHS
! 2763: do_digraph(-1); /* clear digraphs */
! 2764: do_digraph(p[i-1]); /* may be the start of a digraph */
! 2765: #endif
! 2766: p[i] = '\0';
! 2767: ins_str(p);
! 2768: AppendToRedobuff(p);
! 2769: }
! 2770: else
! 2771: {
! 2772: ins_char(c);
! 2773: AppendCharToRedobuff(c);
! 2774: }
! 2775: }
! 2776:
! 2777: /*
! 2778: * start_arrow() is called when an arrow key is used in insert mode.
! 2779: * It resembles hitting the <ESC> key.
! 2780: */
! 2781: static void
! 2782: start_arrow(end_insert_pos)
! 2783: FPOS *end_insert_pos;
! 2784: {
! 2785: if (!arrow_used) /* something has been inserted */
! 2786: {
! 2787: AppendToRedobuff(ESC_STR);
! 2788: arrow_used = TRUE; /* this means we stopped the current insert */
! 2789: stop_insert(end_insert_pos);
! 2790: }
! 2791: }
! 2792:
! 2793: /*
! 2794: * stop_arrow() is called before a change is made in insert mode.
! 2795: * If an arrow key has been used, start a new insertion.
! 2796: */
! 2797: static void
! 2798: stop_arrow()
! 2799: {
! 2800: if (arrow_used)
! 2801: {
! 2802: (void)u_save_cursor(); /* errors are ignored! */
! 2803: Insstart = curwin->w_cursor; /* new insertion starts here */
! 2804: Insstart_textlen = linetabsize(ml_get_curline());
! 2805: ResetRedobuff();
! 2806: AppendToRedobuff((char_u *)"1i"); /* pretend we start an insertion */
! 2807: arrow_used = FALSE;
! 2808: }
! 2809: }
! 2810:
! 2811: /*
! 2812: * do a few things to stop inserting
! 2813: */
! 2814: static void
! 2815: stop_insert(end_insert_pos)
! 2816: FPOS *end_insert_pos; /* where insert ended */
! 2817: {
! 2818: stop_redo_ins();
! 2819:
! 2820: /*
! 2821: * save the inserted text for later redo with ^@
! 2822: */
! 2823: vim_free(last_insert);
! 2824: last_insert = get_inserted();
! 2825: last_insert_skip = new_insert_skip;
! 2826:
! 2827: /*
! 2828: * If we just did an auto-indent, remove the white space from the end of
! 2829: * the line, and put the cursor back.
! 2830: */
! 2831: if (did_ai && !arrow_used)
! 2832: {
! 2833: if (gchar_cursor() == NUL && curwin->w_cursor.col > 0)
! 2834: --curwin->w_cursor.col;
! 2835: while (vim_iswhite(gchar_cursor()))
! 2836: delchar(TRUE);
! 2837: if (gchar_cursor() != NUL)
! 2838: ++curwin->w_cursor.col; /* put cursor back on the NUL */
! 2839: if (curwin->w_p_list) /* the deletion is only seen in list
! 2840: * mode */
! 2841: updateline();
! 2842: }
! 2843: did_ai = FALSE;
! 2844: did_si = FALSE;
! 2845: can_si = FALSE;
! 2846: can_si_back = FALSE;
! 2847:
! 2848: /* set '[ and '] to the inserted text */
! 2849: curbuf->b_op_start = Insstart;
! 2850: curbuf->b_op_end = *end_insert_pos;
! 2851: }
! 2852:
! 2853: /*
! 2854: * Set the last inserted text to a single character.
! 2855: * Used for the replace command.
! 2856: */
! 2857: void
! 2858: set_last_insert(c)
! 2859: int c;
! 2860: {
! 2861: vim_free(last_insert);
! 2862: last_insert = alloc(4);
! 2863: if (last_insert != NULL)
! 2864: {
! 2865: last_insert[0] = Ctrl('V');
! 2866: last_insert[1] = c;
! 2867: last_insert[2] = ESC;
! 2868: last_insert[3] = NUL;
! 2869: /* Use the CTRL-V only when not entering a digit */
! 2870: last_insert_skip = isdigit(c) ? 1 : 0;
! 2871: }
! 2872: }
! 2873:
! 2874: /*
! 2875: * move cursor to start of line
! 2876: * if flag == TRUE move to first non-white
! 2877: * if flag == MAYBE then move to first non-white if startofline is set,
! 2878: * otherwise don't move at all.
! 2879: */
! 2880: void
! 2881: beginline(flag)
! 2882: int flag;
! 2883: {
! 2884: if (flag == MAYBE && !p_sol)
! 2885: coladvance(curwin->w_curswant);
! 2886: else
! 2887: {
! 2888: curwin->w_cursor.col = 0;
! 2889: if (flag)
! 2890: {
! 2891: register char_u *ptr;
! 2892:
! 2893: for (ptr = ml_get_curline(); vim_iswhite(*ptr); ++ptr)
! 2894: ++curwin->w_cursor.col;
! 2895: }
! 2896: curwin->w_set_curswant = TRUE;
! 2897: }
! 2898: }
! 2899:
! 2900: /*
! 2901: * oneright oneleft cursor_down cursor_up
! 2902: *
! 2903: * Move one char {right,left,down,up}.
! 2904: * Return OK when sucessful, FAIL when we hit a line of file boundary.
! 2905: */
! 2906:
! 2907: int
! 2908: oneright()
! 2909: {
! 2910: char_u *ptr;
! 2911:
! 2912: ptr = ml_get_cursor();
! 2913: if (*ptr++ == NUL || *ptr == NUL)
! 2914: return FAIL;
! 2915: curwin->w_set_curswant = TRUE;
! 2916: ++curwin->w_cursor.col;
! 2917: return OK;
! 2918: }
! 2919:
! 2920: int
! 2921: oneleft()
! 2922: {
! 2923: if (curwin->w_cursor.col == 0)
! 2924: return FAIL;
! 2925: curwin->w_set_curswant = TRUE;
! 2926: --curwin->w_cursor.col;
! 2927: return OK;
! 2928: }
! 2929:
! 2930: int
! 2931: cursor_up(n)
! 2932: long n;
! 2933: {
! 2934: if (n != 0 && curwin->w_cursor.lnum == 1)
! 2935: return FAIL;
! 2936: if (n >= curwin->w_cursor.lnum)
! 2937: curwin->w_cursor.lnum = 1;
! 2938: else
! 2939: curwin->w_cursor.lnum -= n;
! 2940:
! 2941: /* try to advance to the column we want to be at */
! 2942: coladvance(curwin->w_curswant);
! 2943:
! 2944: if (op_type == NOP)
! 2945: cursupdate(); /* make sure curwin->w_topline is valid */
! 2946:
! 2947: return OK;
! 2948: }
! 2949:
! 2950: int
! 2951: cursor_down(n)
! 2952: long n;
! 2953: {
! 2954: if (n != 0 && curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count)
! 2955: return FAIL;
! 2956: curwin->w_cursor.lnum += n;
! 2957: if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
! 2958: curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
! 2959:
! 2960: /* try to advance to the column we want to be at */
! 2961: coladvance(curwin->w_curswant);
! 2962:
! 2963: if (op_type == NOP)
! 2964: cursupdate(); /* make sure curwin->w_topline is valid */
! 2965:
! 2966: return OK;
! 2967: }
! 2968:
! 2969: /*
! 2970: * screengo() --
! 2971: *
! 2972: * move 'dist' lines in direction 'dir', counting lines by *screen*
! 2973: * lines rather than lines in the file
! 2974: * 'dist' must be positive.
! 2975: *
! 2976: * return OK if able to move cursor, FAIL otherwise.
! 2977: */
! 2978:
! 2979: int
! 2980: screengo(dir, dist)
! 2981: int dir;
! 2982: long dist;
! 2983: {
! 2984: int linelen = linetabsize(ml_get_curline());
! 2985: int retval = OK;
! 2986: int atend = FALSE;
! 2987: int n;
! 2988:
! 2989: op_motion_type = MCHAR;
! 2990: op_inclusive = FALSE;
! 2991:
! 2992: /*
! 2993: * Instead of sticking at the last character of the line in the file we
! 2994: * try to stick in the last column of the screen
! 2995: */
! 2996: if (curwin->w_curswant == MAXCOL)
! 2997: {
! 2998: atend = TRUE;
! 2999: curwin->w_curswant = ((curwin->w_virtcol +
! 3000: (curwin->w_p_nu ? 8 : 0)) / Columns + 1) * Columns - 1;
! 3001: if (curwin->w_p_nu && curwin->w_curswant > 8)
! 3002: curwin->w_curswant -= 8;
! 3003: }
! 3004: else
! 3005: while (curwin->w_curswant >= (colnr_t)(linelen + Columns))
! 3006: curwin->w_curswant -= Columns;
! 3007:
! 3008: while (dist--)
! 3009: {
! 3010: if (dir == BACKWARD)
! 3011: {
! 3012: /* move back within line */
! 3013: if ((long)curwin->w_curswant >= Columns)
! 3014: curwin->w_curswant -= Columns;
! 3015: else /* to previous line */
! 3016: {
! 3017: if (curwin->w_cursor.lnum == 1)
! 3018: {
! 3019: retval = FAIL;
! 3020: break;
! 3021: }
! 3022: --curwin->w_cursor.lnum;
! 3023: linelen = linetabsize(ml_get_curline());
! 3024: n = ((linelen + (curwin->w_p_nu ? 8 : 0) - 1) / Columns)
! 3025: * Columns;
! 3026: if (curwin->w_p_nu &&
! 3027: (long)curwin->w_curswant >= Columns - 8 && n)
! 3028: n -= Columns;
! 3029: curwin->w_curswant += n;
! 3030: }
! 3031: }
! 3032: else /* dir == FORWARD */
! 3033: {
! 3034: n = ((linelen + (curwin->w_p_nu ? 8 : 0) - 1) / Columns) * Columns;
! 3035: if (curwin->w_p_nu && n > 8)
! 3036: n -= 8;
! 3037: /* move forward within line */
! 3038: if (curwin->w_curswant < (colnr_t)n)
! 3039: curwin->w_curswant += Columns;
! 3040: else /* to next line */
! 3041: {
! 3042: if (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count)
! 3043: {
! 3044: retval = FAIL;
! 3045: break;
! 3046: }
! 3047: curwin->w_cursor.lnum++;
! 3048: linelen = linetabsize(ml_get_curline());
! 3049: curwin->w_curswant %= Columns;
! 3050: }
! 3051: }
! 3052: }
! 3053: coladvance(curwin->w_curswant);
! 3054: if (atend)
! 3055: curwin->w_curswant = MAXCOL; /* stick in the last column */
! 3056: if (op_type == NOP)
! 3057: cursupdate();
! 3058: return retval;
! 3059: }
! 3060:
! 3061: /*
! 3062: * move screen 'count' pages up or down and update screen
! 3063: *
! 3064: * return FAIL for failure, OK otherwise
! 3065: */
! 3066: int
! 3067: onepage(dir, count)
! 3068: int dir;
! 3069: long count;
! 3070: {
! 3071: linenr_t lp;
! 3072: long n;
! 3073: int off;
! 3074:
! 3075: if (curbuf->b_ml.ml_line_count == 1) /* nothing to do */
! 3076: return FAIL;
! 3077: for ( ; count > 0; --count)
! 3078: {
! 3079: if (dir == FORWARD ? (curwin->w_topline >=
! 3080: curbuf->b_ml.ml_line_count - 1) : (curwin->w_topline == 1))
! 3081: {
! 3082: beep_flush();
! 3083: return FAIL;
! 3084: }
! 3085: if (dir == FORWARD)
! 3086: {
! 3087: /* at end of file */
! 3088: if (curwin->w_botline > curbuf->b_ml.ml_line_count)
! 3089: curwin->w_topline = curbuf->b_ml.ml_line_count;
! 3090: /* next line is big */
! 3091: /* or just three lines on screen */
! 3092: else
! 3093: {
! 3094: if (plines(curwin->w_botline) >= curwin->w_height - 2 ||
! 3095: curwin->w_botline - curwin->w_topline <= 3)
! 3096: off = 0;
! 3097: else
! 3098: off = 2;
! 3099: curwin->w_topline = curwin->w_botline - off;
! 3100: curwin->w_cursor.lnum = curwin->w_topline;
! 3101: }
! 3102: comp_Botline(curwin);
! 3103: }
! 3104: else /* dir == BACKWARDS */
! 3105: {
! 3106: lp = curwin->w_topline;
! 3107: /*
! 3108: * If the first two lines on the screen are not too big, we keep
! 3109: * them on the screen.
! 3110: */
! 3111: if ((n = plines(lp)) > curwin->w_height / 2)
! 3112: --lp;
! 3113: else if (lp < curbuf->b_ml.ml_line_count &&
! 3114: n + plines(lp + 1) < curwin->w_height / 2)
! 3115: ++lp;
! 3116: curwin->w_cursor.lnum = lp;
! 3117: n = 0;
! 3118: while (n <= curwin->w_height && lp >= 1)
! 3119: {
! 3120: n += plines(lp);
! 3121: --lp;
! 3122: }
! 3123: if (n <= curwin->w_height) /* at begin of file */
! 3124: {
! 3125: curwin->w_topline = 1;
! 3126: comp_Botline(curwin);
! 3127: }
! 3128: else if (lp >= curwin->w_topline - 2) /* very long lines */
! 3129: {
! 3130: --curwin->w_topline;
! 3131: comp_Botline(curwin);
! 3132: curwin->w_cursor.lnum = curwin->w_botline - 1;
! 3133: }
! 3134: else
! 3135: {
! 3136: curwin->w_topline = lp + 2;
! 3137: comp_Botline(curwin);
! 3138: }
! 3139: }
! 3140: }
! 3141: cursor_correct();
! 3142: beginline(MAYBE);
! 3143: updateScreen(VALID);
! 3144: return OK;
! 3145: }
! 3146:
! 3147: /* #define KEEP_SCREEN_LINE */
! 3148:
! 3149: void
! 3150: halfpage(flag, Prenum)
! 3151: int flag;
! 3152: linenr_t Prenum;
! 3153: {
! 3154: long scrolled = 0;
! 3155: int i;
! 3156: int n;
! 3157:
! 3158: if (Prenum)
! 3159: curwin->w_p_scroll = (Prenum > curwin->w_height) ?
! 3160: curwin->w_height : Prenum;
! 3161: n = (curwin->w_p_scroll <= curwin->w_height) ?
! 3162: curwin->w_p_scroll : curwin->w_height;
! 3163:
! 3164: if (flag) /* scroll down */
! 3165: {
! 3166: while (n > 0 && curwin->w_botline <= curbuf->b_ml.ml_line_count)
! 3167: {
! 3168: i = plines(curwin->w_topline);
! 3169: n -= i;
! 3170: if (n < 0 && scrolled)
! 3171: break;
! 3172: scrolled += i;
! 3173: ++curwin->w_topline;
! 3174: comp_Botline(curwin); /* compute curwin->w_botline */
! 3175: #ifndef KEEP_SCREEN_LINE
! 3176: if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
! 3177: ++curwin->w_cursor.lnum;
! 3178: #endif
! 3179: }
! 3180: #ifndef KEEP_SCREEN_LINE
! 3181: /*
! 3182: * When hit bottom of the file: move cursor down.
! 3183: */
! 3184: if (n > 0)
! 3185: {
! 3186: curwin->w_cursor.lnum += n;
! 3187: if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
! 3188: curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
! 3189: }
! 3190: #else
! 3191: /* try to put the cursor in the same screen line */
! 3192: while ((curwin->w_cursor.lnum < curwin->w_topline || scrolled > 0)
! 3193: && curwin->w_cursor.lnum < curwin->w_botline - 1)
! 3194: {
! 3195: scrolled -= plines(curwin->w_cursor.lnum);
! 3196: if (scrolled < 0 && curwin->w_cursor.lnum >= curwin->w_topline)
! 3197: break;
! 3198: ++curwin->w_cursor.lnum;
! 3199: }
! 3200: #endif
! 3201: }
! 3202: else /* scroll up */
! 3203: {
! 3204: while (n > 0 && curwin->w_topline > 1)
! 3205: {
! 3206: i = plines(curwin->w_topline - 1);
! 3207: n -= i;
! 3208: if (n < 0 && scrolled)
! 3209: break;
! 3210: scrolled += i;
! 3211: --curwin->w_topline;
! 3212: #ifndef KEEP_SCREEN_LINE
! 3213: if (curwin->w_cursor.lnum > 1)
! 3214: --curwin->w_cursor.lnum;
! 3215: #endif
! 3216: }
! 3217: comp_Botline(curwin); /* compute curwin->w_botline */
! 3218: #ifndef KEEP_SCREEN_LINE
! 3219: /*
! 3220: * When hit top of the file: move cursor up.
! 3221: */
! 3222: if (n > 0)
! 3223: {
! 3224: if (curwin->w_cursor.lnum > (linenr_t)n)
! 3225: curwin->w_cursor.lnum -= n;
! 3226: else
! 3227: curwin->w_cursor.lnum = 1;
! 3228: }
! 3229: #else
! 3230: /* try to put the cursor in the same screen line */
! 3231: scrolled += n; /* move cursor when topline is 1 */
! 3232: while (curwin->w_cursor.lnum > curwin->w_topline &&
! 3233: (scrolled > 0 || curwin->w_cursor.lnum >= curwin->w_botline))
! 3234: {
! 3235: scrolled -= plines(curwin->w_cursor.lnum - 1);
! 3236: if (scrolled < 0 && curwin->w_cursor.lnum < curwin->w_botline)
! 3237: break;
! 3238: --curwin->w_cursor.lnum;
! 3239: }
! 3240: #endif
! 3241: }
! 3242: cursor_correct();
! 3243: beginline(MAYBE);
! 3244: updateScreen(VALID);
! 3245: }
! 3246:
! 3247: /*
! 3248: * Stuff the last inserted text in the read buffer.
! 3249: * Last_insert actually is a copy of the redo buffer, so we
! 3250: * first have to remove the command.
! 3251: */
! 3252: int
! 3253: stuff_inserted(c, count, no_esc)
! 3254: int c;
! 3255: long count;
! 3256: int no_esc;
! 3257: {
! 3258: char_u *esc_ptr = NULL;
! 3259: char_u *ptr;
! 3260:
! 3261: ptr = get_last_insert();
! 3262: if (ptr == NULL)
! 3263: {
! 3264: EMSG(e_noinstext);
! 3265: return FAIL;
! 3266: }
! 3267:
! 3268: if (c)
! 3269: stuffcharReadbuff(c);
! 3270: if (no_esc && (esc_ptr = (char_u *)vim_strrchr(ptr, 27)) != NULL)
! 3271: *esc_ptr = NUL; /* remove the ESC */
! 3272:
! 3273: do
! 3274: stuffReadbuff(ptr);
! 3275: while (--count > 0);
! 3276:
! 3277: if (esc_ptr != NULL)
! 3278: *esc_ptr = 27; /* put the ESC back */
! 3279:
! 3280: return OK;
! 3281: }
! 3282:
! 3283: char_u *
! 3284: get_last_insert()
! 3285: {
! 3286: if (last_insert == NULL)
! 3287: return NULL;
! 3288: return last_insert + last_insert_skip;
! 3289: }
! 3290:
! 3291: /*
! 3292: * Check the word in front of the cursor for an abbreviation.
! 3293: * Called when the non-id character "c" has been entered.
! 3294: * When an abbreviation is recognized it is removed from the text and
! 3295: * the replacement string is inserted in typebuf[], followed by "c".
! 3296: */
! 3297: static int
! 3298: echeck_abbr(c)
! 3299: int c;
! 3300: {
! 3301: if (p_paste || no_abbr) /* no abbreviations or in paste mode */
! 3302: return FALSE;
! 3303:
! 3304: return check_abbr(c, ml_get_curline(), curwin->w_cursor.col,
! 3305: curwin->w_cursor.lnum == Insstart.lnum ? Insstart.col : 0);
! 3306: }
! 3307:
! 3308: /*
! 3309: * replace-stack functions
! 3310: *
! 3311: * When replacing characters the replaced character is remembered
! 3312: * for each new character. This is used to re-insert the old text
! 3313: * when backspacing.
! 3314: *
! 3315: * replace_offset is normally 0, in which case replace_push will add a new
! 3316: * character at the end of the stack. If replace_offset is not 0, that many
! 3317: * characters will be left on the stack above the newly inserted character.
! 3318: */
! 3319:
! 3320: char_u *replace_stack = NULL;
! 3321: long replace_stack_nr = 0; /* next entry in replace stack */
! 3322: long replace_stack_len = 0; /* max. number of entries */
! 3323:
! 3324: void
! 3325: replace_push(c)
! 3326: int c; /* character that is replaced (NUL is none) */
! 3327: {
! 3328: char_u *p;
! 3329:
! 3330: if (replace_stack_nr < replace_offset) /* nothing to do */
! 3331: return;
! 3332: if (replace_stack_len <= replace_stack_nr)
! 3333: {
! 3334: replace_stack_len += 50;
! 3335: p = lalloc(sizeof(char_u) * replace_stack_len, TRUE);
! 3336: if (p == NULL) /* out of memory */
! 3337: {
! 3338: replace_stack_len -= 50;
! 3339: return;
! 3340: }
! 3341: if (replace_stack != NULL)
! 3342: {
! 3343: vim_memmove(p, replace_stack,
! 3344: (size_t)(replace_stack_nr * sizeof(char_u)));
! 3345: vim_free(replace_stack);
! 3346: }
! 3347: replace_stack = p;
! 3348: }
! 3349: p = replace_stack + replace_stack_nr - replace_offset;
! 3350: if (replace_offset)
! 3351: vim_memmove(p + 1, p, (size_t)(replace_offset * sizeof(char_u)));
! 3352: *p = c;
! 3353: ++replace_stack_nr;
! 3354: }
! 3355:
! 3356: /*
! 3357: * pop one item from the replace stack
! 3358: * return -1 if stack empty
! 3359: * return 0 if no character was replaced
! 3360: * return replaced character otherwise
! 3361: */
! 3362: int
! 3363: replace_pop()
! 3364: {
! 3365: if (replace_stack_nr == 0)
! 3366: return -1;
! 3367: return (int)replace_stack[--replace_stack_nr];
! 3368: }
! 3369:
! 3370: /*
! 3371: * make the replace stack empty
! 3372: * (called when exiting replace mode)
! 3373: */
! 3374: void
! 3375: replace_flush()
! 3376: {
! 3377: vim_free(replace_stack);
! 3378: replace_stack = NULL;
! 3379: replace_stack_len = 0;
! 3380: replace_stack_nr = 0;
! 3381: }
! 3382:
! 3383: #if defined(LISPINDENT) || defined(CINDENT)
! 3384: /*
! 3385: * Re-indent the current line, based on the current contents of it and the
! 3386: * surrounding lines. Fixing the cursor position seems really easy -- I'm very
! 3387: * confused what all the part that handles Control-T is doing that I'm not.
! 3388: * "get_the_indent" should be get_c_indent or get_lisp_indent.
! 3389: */
! 3390:
! 3391: void
! 3392: fixthisline(get_the_indent)
! 3393: int (*get_the_indent) __ARGS((void));
! 3394: {
! 3395: change_indent(INDENT_SET, get_the_indent(), FALSE);
! 3396: if (linewhite(curwin->w_cursor.lnum))
! 3397: did_ai = TRUE; /* delete the indent if the line stays empty */
! 3398: }
! 3399: #endif /* defined(LISPINDENT) || defined(CINDENT) */
! 3400:
! 3401: #ifdef CINDENT
! 3402: /*
! 3403: * return TRUE if 'cinkeys' contains the key "keytyped",
! 3404: * when == '*': Only if key is preceded with '*' (indent before insert)
! 3405: * when == '!': Only if key is prededed with '!' (don't insert)
! 3406: * when == ' ': Only if key is not preceded with '*'(indent afterwards)
! 3407: *
! 3408: * If line_is_empty is TRUE accept keys with '0' before them.
! 3409: */
! 3410: int
! 3411: in_cinkeys(keytyped, when, line_is_empty)
! 3412: int keytyped;
! 3413: int when;
! 3414: int line_is_empty;
! 3415: {
! 3416: char_u *look;
! 3417: int try_match;
! 3418: char_u *p;
! 3419:
! 3420: for (look = curbuf->b_p_cink; *look; )
! 3421: {
! 3422: /*
! 3423: * Find out if we want to try a match with this key, depending on
! 3424: * 'when' and a '*' or '!' before the key.
! 3425: */
! 3426: switch (when)
! 3427: {
! 3428: case '*': try_match = (*look == '*'); break;
! 3429: case '!': try_match = (*look == '!'); break;
! 3430: default: try_match = (*look != '*'); break;
! 3431: }
! 3432: if (*look == '*' || *look == '!')
! 3433: ++look;
! 3434:
! 3435: /*
! 3436: * If there is a '0', only accept a match if the line is empty.
! 3437: */
! 3438: if (*look == '0')
! 3439: {
! 3440: if (!line_is_empty)
! 3441: try_match = FALSE;
! 3442: ++look;
! 3443: }
! 3444:
! 3445: /*
! 3446: * does it look like a control character?
! 3447: */
! 3448: if (*look == '^' && look[1] >= '@' && look[1] <= '_')
! 3449: {
! 3450: if (try_match && keytyped == Ctrl(look[1]))
! 3451: return TRUE;
! 3452: look += 2;
! 3453: }
! 3454: /*
! 3455: * 'o' means "o" command, open forward.
! 3456: * 'O' means "O" command, open backward.
! 3457: */
! 3458: else if (*look == 'o')
! 3459: {
! 3460: if (try_match && keytyped == KEY_OPEN_FORW)
! 3461: return TRUE;
! 3462: ++look;
! 3463: }
! 3464: else if (*look == 'O')
! 3465: {
! 3466: if (try_match && keytyped == KEY_OPEN_BACK)
! 3467: return TRUE;
! 3468: ++look;
! 3469: }
! 3470:
! 3471: /*
! 3472: * 'e' means to check for "else" at start of line and just before the
! 3473: * cursor.
! 3474: */
! 3475: else if (*look == 'e')
! 3476: {
! 3477: if (try_match && keytyped == 'e' && curwin->w_cursor.col >= 4)
! 3478: {
! 3479: p = ml_get_curline();
! 3480: if (skipwhite(p) == p + curwin->w_cursor.col - 4 &&
! 3481: STRNCMP(p + curwin->w_cursor.col - 4, "else", 4) == 0)
! 3482: return TRUE;
! 3483: }
! 3484: ++look;
! 3485: }
! 3486:
! 3487: /*
! 3488: * ':' only causes an indent if it is at the end of a label or case
! 3489: * statement.
! 3490: */
! 3491: else if (*look == ':')
! 3492: {
! 3493: if (try_match && keytyped == ':')
! 3494: {
! 3495: p = ml_get_curline();
! 3496: if (iscase(p) || islabel(30))
! 3497: return TRUE;
! 3498: }
! 3499: ++look;
! 3500: }
! 3501:
! 3502:
! 3503: /*
! 3504: * Is it a key in <>, maybe?
! 3505: */
! 3506: else if (*look == '<')
! 3507: {
! 3508: if (try_match)
! 3509: {
! 3510: /*
! 3511: * make up some named keys <o>, <O>, <e>, <0>, <>>, <<>, <*>
! 3512: * and <!> so that people can re-indent on o, O, e, 0, <, >, *
! 3513: * and ! keys if they really really want to.
! 3514: */
! 3515: if (vim_strchr((char_u *)"<>!*oOe0", look[1]) != NULL &&
! 3516: keytyped == look[1])
! 3517: return TRUE;
! 3518:
! 3519: if (keytyped == get_special_key_code(look + 1))
! 3520: return TRUE;
! 3521: }
! 3522: while (*look && *look != '>')
! 3523: look++;
! 3524: while (*look == '>')
! 3525: look++;
! 3526: }
! 3527:
! 3528: /*
! 3529: * ok, it's a boring generic character.
! 3530: */
! 3531: else
! 3532: {
! 3533: if (try_match && *look == keytyped)
! 3534: return TRUE;
! 3535: ++look;
! 3536: }
! 3537:
! 3538: /*
! 3539: * Skip over ", ".
! 3540: */
! 3541: look = skip_to_option_part(look);
! 3542: }
! 3543: return FALSE;
! 3544: }
! 3545: #endif /* CINDENT */
! 3546:
! 3547: #if defined(RIGHTLEFT) || defined(PROTO)
! 3548: /*
! 3549: * Map Hebrew keyboard when in hkmap mode.
! 3550: */
! 3551: int
! 3552: hkmap(c)
! 3553: int c;
! 3554: {
! 3555: switch(c)
! 3556: {
! 3557: case '`': return ';';
! 3558: case '/': return '.';
! 3559: case '\'': return ',';
! 3560: case 'q': return '/';
! 3561: case 'w': return '\'';
! 3562:
! 3563: /* Hebrew letters - set offset from 'a' */
! 3564: case ',': c = '{'; break;
! 3565: case '.': c = 'v'; break;
! 3566: case ';': c = 't'; break;
! 3567: default: {
! 3568: static char str[] = "zqbcxlsjphmkwonu ydafe rig";
! 3569:
! 3570: if (c < 'a' || c > 'z')
! 3571: return c;
! 3572: c = str[c - 'a'];
! 3573: break;
! 3574: }
! 3575: }
! 3576:
! 3577: return c - 'a' + p_aleph;
! 3578: }
! 3579: #endif