|
|
1.1 ! root 1: /* vi.c */ ! 2: ! 3: /* Author: ! 4: * Steve Kirkendall ! 5: * 16820 SW Tallac Way ! 6: * Beaverton, OR 97006 ! 7: * [email protected], or ...uunet!tektronix!psueea!jove!kirkenda ! 8: */ ! 9: ! 10: ! 11: #include "config.h" ! 12: #include <ctype.h> ! 13: #include "vi.h" ! 14: ! 15: ! 16: ! 17: /* This array describes what each key does */ ! 18: #define NO_FUNC (MARK (*)())0 ! 19: #define NO_ARGS 0 ! 20: #define CURSOR_COUNT 1 ! 21: #define CURSOR 2 ! 22: #define CURSOR_CNT_KEY 3 ! 23: #define CURSOR_MOVED 4 ! 24: #define CURSOR_EOL 5 ! 25: #define ZERO 6 ! 26: #define DIGIT 7 ! 27: #define CURSOR_TEXT 8 ! 28: #define CURSOR_CNT_CMD 9 ! 29: #define KEYWORD 10 ! 30: #define NO_FLAGS 0x00 ! 31: #define MVMT 0x01 /* this is a movement command */ ! 32: #define PTMV 0x02 /* this can be *part* of a movement command */ ! 33: #define FRNT 0x04 /* after move, go to front of line */ ! 34: #define INCL 0x08 /* include last char when used with c/d/y */ ! 35: #define LNMD 0x10 /* use line mode of c/d/y */ ! 36: #define NCOL 0x20 /* this command can't change the column# */ ! 37: #define NREL 0x40 /* this is "non-relative" -- set the '' mark */ ! 38: #define SDOT 0x80 /* set the "dot" variables, for the "." cmd */ ! 39: static struct keystru ! 40: { ! 41: MARK (*func)(); /* the function to run */ ! 42: uchar args; /* description of the args needed */ ! 43: uchar flags; /* other stuff */ ! 44: } ! 45: vikeys[] = ! 46: { ! 47: /* NUL not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, ! 48: /* ^A not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, ! 49: /* ^B page backward */ {m_scroll, CURSOR_CNT_CMD, FRNT}, ! 50: /* ^C not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, ! 51: /* ^D scroll dn 1/2page*/ {m_scroll, CURSOR_CNT_CMD, NCOL}, ! 52: /* ^E scroll up */ {m_scroll, CURSOR_CNT_CMD, NCOL}, ! 53: /* ^F page forward */ {m_scroll, CURSOR_CNT_CMD, FRNT}, ! 54: /* ^G show file status */ {v_status, NO_ARGS, NO_FLAGS}, ! 55: /* ^H move left, like h*/ {m_left, CURSOR_COUNT, MVMT}, ! 56: /* ^I not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, ! 57: /* ^J move down */ {m_updnto, CURSOR_CNT_CMD, MVMT|LNMD}, ! 58: /* ^K not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, ! 59: /* ^L redraw screen */ {v_redraw, NO_ARGS, NO_FLAGS}, ! 60: /* ^M mv front next ln */ {m_updnto, CURSOR_CNT_CMD, MVMT|FRNT|LNMD}, ! 61: /* ^N move down */ {m_updnto, CURSOR_CNT_CMD, MVMT|LNMD}, ! 62: /* ^O not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, ! 63: /* ^P move up */ {m_updnto, CURSOR_CNT_CMD, MVMT|LNMD}, ! 64: /* ^Q not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, ! 65: /* ^R redraw screen */ {v_redraw, NO_ARGS, NO_FLAGS}, ! 66: /* ^S not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, ! 67: /* ^T not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, ! 68: /* ^U scroll up 1/2page*/ {m_scroll, CURSOR_CNT_CMD, NCOL}, ! 69: /* ^V not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, ! 70: /* ^W not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, ! 71: /* ^X not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, ! 72: /* ^Y scroll down */ {m_scroll, CURSOR_CNT_CMD, NCOL}, ! 73: /* ^Z not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, ! 74: /* ESC not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, ! 75: /* ^\ not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, ! 76: /* ^] keyword is tag */ {v_tag, KEYWORD, NO_FLAGS}, ! 77: /* ^^ previous file */ {v_switch, CURSOR, NO_FLAGS}, ! 78: /* ^_ not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, ! 79: /* SPC move right,like l*/ {m_right, CURSOR_COUNT, MVMT}, ! 80: /* ! run thru filter */ {v_filter, CURSOR_MOVED, FRNT|LNMD|INCL}, ! 81: /* " select cut buffer*/ {v_selcut, CURSOR_CNT_KEY, PTMV}, ! 82: #ifndef NO_EXTENSIONS ! 83: /* # increment number */ {v_increment, KEYWORD, SDOT}, ! 84: #else ! 85: /* # not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, ! 86: #endif ! 87: /* $ move to rear */ {m_rear, CURSOR, MVMT|INCL}, ! 88: /* % move to match */ {m_match, CURSOR, MVMT|INCL}, ! 89: /* & repeat subst */ {v_again, CURSOR_MOVED, SDOT|NCOL|LNMD|INCL}, ! 90: /* ' move to a mark */ {m_tomark, CURSOR_CNT_KEY, MVMT|FRNT|NREL|LNMD|INCL}, ! 91: #ifndef NO_SENTENCE ! 92: /* ( mv back sentence */ {m_bsentence, CURSOR_COUNT, MVMT}, ! 93: /* ) mv fwd sentence */ {m_fsentence, CURSOR_COUNT, MVMT}, ! 94: #else ! 95: /* ( not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, ! 96: /* ) not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, ! 97: #endif ! 98: #ifndef NO_ERRLIST ! 99: /* * errlist */ {v_errlist, CURSOR, FRNT|NREL}, ! 100: #else ! 101: /* * not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, ! 102: #endif ! 103: /* + mv front next ln */ {m_updnto, CURSOR_CNT_CMD, MVMT|FRNT|LNMD}, ! 104: #ifndef NO_CHARSEARCH ! 105: /* , reverse [fFtT] cmd*/ {m__ch, CURSOR_CNT_CMD, MVMT|INCL}, ! 106: #else ! 107: /* , not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, ! 108: #endif ! 109: /* - mv front prev ln */ {m_updnto, CURSOR_CNT_CMD, MVMT|FRNT|LNMD}, ! 110: /* . special... */ {NO_FUNC, NO_ARGS, NO_FLAGS}, ! 111: /* / forward search */ {m_fsrch, CURSOR_TEXT, MVMT|NREL}, ! 112: /* 0 part of count? */ {NO_FUNC, ZERO, MVMT|PTMV}, ! 113: /* 1 part of count */ {NO_FUNC, DIGIT, PTMV}, ! 114: /* 2 part of count */ {NO_FUNC, DIGIT, PTMV}, ! 115: /* 3 part of count */ {NO_FUNC, DIGIT, PTMV}, ! 116: /* 4 part of count */ {NO_FUNC, DIGIT, PTMV}, ! 117: /* 5 part of count */ {NO_FUNC, DIGIT, PTMV}, ! 118: /* 6 part of count */ {NO_FUNC, DIGIT, PTMV}, ! 119: /* 7 part of count */ {NO_FUNC, DIGIT, PTMV}, ! 120: /* 8 part of count */ {NO_FUNC, DIGIT, PTMV}, ! 121: /* 9 part of count */ {NO_FUNC, DIGIT, PTMV}, ! 122: /* : run single EX cmd*/ {v_1ex, CURSOR_TEXT, NO_FLAGS}, ! 123: #ifndef NO_CHARSEARCH ! 124: /* ; repeat [fFtT] cmd*/ {m__ch, CURSOR_CNT_CMD, MVMT|INCL}, ! 125: #else ! 126: /* ; not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, ! 127: #endif ! 128: /* < shift text left */ {v_lshift, CURSOR_MOVED, SDOT|FRNT|LNMD|INCL}, ! 129: /* = not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, ! 130: /* > shift text right */ {v_rshift, CURSOR_MOVED, SDOT|FRNT|LNMD|INCL}, ! 131: /* ? backward search */ {m_bsrch, CURSOR_TEXT, MVMT|NREL}, ! 132: #ifndef NO_AT ! 133: /* @ execute a cutbuf */ {v_at, CURSOR_CNT_KEY, NO_FLAGS}, ! 134: #else ! 135: /* @ undefined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, ! 136: #endif ! 137: /* A append at EOL */ {v_insert, CURSOR_CNT_CMD, SDOT}, ! 138: /* B move back Word */ {m_bword, CURSOR_CNT_CMD, MVMT}, ! 139: /* C change to EOL */ {v_change, CURSOR_EOL, SDOT}, ! 140: /* D delete to EOL */ {v_delete, CURSOR_EOL, SDOT}, ! 141: /* E move end of Word */ {m_eword, CURSOR_CNT_CMD, MVMT|INCL}, ! 142: #ifndef NO_CHARSEARCH ! 143: /* F move bk to char */ {m_Fch, CURSOR_CNT_KEY, MVMT|INCL}, ! 144: #else ! 145: /* F not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, ! 146: #endif ! 147: /* G move to line # */ {m_updnto, CURSOR_CNT_CMD, MVMT|NREL|LNMD|FRNT|INCL}, ! 148: /* H move to row */ {m_row, CURSOR_CNT_CMD, MVMT|FRNT}, ! 149: /* I insert at front */ {v_insert, CURSOR_CNT_CMD, SDOT}, ! 150: /* J join lines */ {v_join, CURSOR_COUNT, SDOT}, ! 151: #ifndef NO_EXTENSIONS ! 152: /* K look up keyword */ {v_keyword, KEYWORD, NO_FLAGS}, ! 153: #else ! 154: /* K not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, ! 155: #endif ! 156: /* L move to last row */ {m_row, CURSOR_CNT_CMD, MVMT|FRNT}, ! 157: /* M move to mid row */ {m_row, CURSOR_CNT_CMD, MVMT|FRNT}, ! 158: /* N reverse prev srch*/ {m_Nsrch, CURSOR, MVMT}, ! 159: /* O insert above line*/ {v_insert, CURSOR_CNT_CMD, SDOT}, ! 160: /* P paste before */ {v_paste, CURSOR_CNT_CMD, NO_FLAGS}, ! 161: /* Q quit to EX mode */ {v_quit, NO_ARGS, NO_FLAGS}, ! 162: /* R overtype */ {v_overtype, CURSOR, SDOT}, ! 163: /* S change line */ {v_change, CURSOR_MOVED, SDOT}, ! 164: #ifndef NO_CHARSEARCH ! 165: /* T move bk to char */ {m_Tch, CURSOR_CNT_KEY, MVMT|INCL}, ! 166: #else ! 167: /* T not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, ! 168: #endif ! 169: /* U undo whole line */ {v_undoline, CURSOR, FRNT}, ! 170: /* V not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, ! 171: /* W move forward Word*/ {m_fword, CURSOR_CNT_CMD, MVMT}, ! 172: /* X delete to left */ {v_xchar, CURSOR_CNT_CMD, SDOT}, ! 173: /* Y yank text */ {v_yank, CURSOR_MOVED, NCOL}, ! 174: /* Z save file & exit */ {v_xit, CURSOR_CNT_KEY, NO_FLAGS}, ! 175: /* [ move back section*/ {m_bsection, CURSOR_CNT_KEY, MVMT|LNMD|NREL}, ! 176: /* \ not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, ! 177: /* ] move fwd section */ {m_fsection, CURSOR_CNT_KEY, MVMT|LNMD|NREL}, ! 178: /* ^ move to front */ {m_front, CURSOR, MVMT}, ! 179: /* _ not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, ! 180: /* ` move to mark */ {m_tomark, CURSOR_CNT_KEY, MVMT|NREL}, ! 181: /* a append at cursor */ {v_insert, CURSOR_CNT_CMD, SDOT}, ! 182: /* b move back word */ {m_bword, CURSOR_CNT_CMD, MVMT}, ! 183: /* c change text */ {v_change, CURSOR_MOVED, SDOT}, ! 184: /* d delete op */ {v_delete, CURSOR_MOVED, SDOT|NCOL}, ! 185: /* e move end word */ {m_eword, CURSOR_CNT_CMD, MVMT|INCL}, ! 186: #ifndef NO_CHARSEARCH ! 187: /* f move fwd for char*/ {m_fch, CURSOR_CNT_KEY, MVMT|INCL}, ! 188: #else ! 189: /* f not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, ! 190: #endif ! 191: /* g not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, ! 192: /* h move left */ {m_left, CURSOR_COUNT, MVMT}, ! 193: /* i insert at cursor */ {v_insert, CURSOR_CNT_CMD, SDOT}, ! 194: /* j move down */ {m_updnto, CURSOR_CNT_CMD, MVMT|NCOL|LNMD}, ! 195: /* k move up */ {m_updnto, CURSOR_CNT_CMD, MVMT|NCOL|LNMD}, ! 196: /* l move right */ {m_right, CURSOR_COUNT, MVMT}, ! 197: /* m define a mark */ {v_mark, CURSOR_CNT_KEY, NO_FLAGS}, ! 198: /* n repeat prev srch */ {m_nsrch, CURSOR, MVMT}, ! 199: /* o insert below line*/ {v_insert, CURSOR_CNT_CMD, SDOT}, ! 200: /* p paste after */ {v_paste, CURSOR_CNT_CMD, NO_FLAGS}, ! 201: /* q not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, ! 202: /* r replace chars */ {v_replace, CURSOR_CNT_KEY, SDOT}, ! 203: /* s subst N chars */ {v_subst, CURSOR_COUNT, SDOT}, ! 204: #ifndef NO_CHARSEARCH ! 205: /* t move fwd to char */ {m_tch, CURSOR_CNT_KEY, MVMT|INCL}, ! 206: #else ! 207: /* t not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, ! 208: #endif ! 209: /* u undo */ {v_undo, CURSOR, NO_FLAGS}, ! 210: /* v not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, ! 211: /* w move fwd word */ {m_fword, CURSOR_CNT_CMD, MVMT}, ! 212: /* x delete character */ {v_xchar, CURSOR_CNT_CMD, SDOT}, ! 213: /* y yank text */ {v_yank, CURSOR_MOVED, NCOL}, ! 214: /* z adjust scrn row */ {m_z, CURSOR_CNT_KEY, NCOL}, ! 215: /* { back paragraph */ {m_bparagraph, CURSOR_COUNT, MVMT|LNMD}, ! 216: /* | move to column */ {m_tocol, CURSOR_COUNT, NREL}, ! 217: /* } fwd paragraph */ {m_fparagraph, CURSOR_COUNT, MVMT|LNMD}, ! 218: /* ~ upper/lowercase */ {v_ulcase, CURSOR_COUNT, SDOT}, ! 219: /* DEL not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}, ! 220: }; ! 221: ! 222: ! 223: ! 224: void vi() ! 225: { ! 226: REG int key; /* keystroke from user */ ! 227: long count; /* numeric argument to some functions */ ! 228: REG struct keystru *keyptr;/* pointer to vikeys[] element */ ! 229: MARK tcurs; /* temporary cursor */ ! 230: int prevkey;/* previous key, if d/c/y/</>/! */ ! 231: MARK range; /* start of range for d/c/y/</>/! */ ! 232: char text[100]; ! 233: int dotkey; /* last "key" of a change */ ! 234: int dotpkey;/* last "prevkey" of a change */ ! 235: int dotkey2;/* last extra "getkey()" of a change */ ! 236: int dotcnt; /* last "count" of a change */ ! 237: int firstkey; ! 238: REG int i; ! 239: ! 240: /* tell the redraw() function to start from scratch */ ! 241: redraw(MARK_UNSET, FALSE); ! 242: ! 243: #ifdef lint ! 244: /* lint says that "range" might be used before it is set. This ! 245: * can't really happen due to the way "range" and "prevkey" are used, ! 246: * but lint doesn't know that. This line is here ONLY to keep lint ! 247: * happy. ! 248: */ ! 249: range = 0L; ! 250: #endif ! 251: ! 252: /* safeguard against '.' with no previous command */ ! 253: dotkey = 0; ! 254: ! 255: /* go immediately into insert mode, if ":set inputmode" */ ! 256: firstkey = 0; ! 257: #ifndef NO_EXTENSIONS ! 258: if (*o_inputmode) ! 259: { ! 260: firstkey = 'i'; ! 261: } ! 262: #endif ! 263: ! 264: /* Repeatedly handle VI commands */ ! 265: for (count = 0, prevkey = '\0'; mode == MODE_VI; ) ! 266: { ! 267: /* if we've moved off the undoable line, then we can't undo it at all */ ! 268: if (markline(cursor) != U_line) ! 269: { ! 270: U_line = 0L; ! 271: } ! 272: ! 273: /* report any changes from the previous command */ ! 274: if (rptlines >= *o_report) ! 275: { ! 276: redraw(cursor, FALSE); ! 277: msg("%ld lines %s", rptlines, rptlabel); ! 278: } ! 279: rptlines = 0L; ! 280: ! 281: /* get the next command key. It must be ASCII */ ! 282: if (firstkey) ! 283: { ! 284: key = firstkey; ! 285: firstkey = 0; ! 286: } ! 287: else ! 288: { ! 289: do ! 290: { ! 291: key = getkey(WHEN_VICMD); ! 292: } while (key < 0 || key > 127); ! 293: } ! 294: ! 295: /* change cw and cW commands to ce and cE, respectively */ ! 296: /* (Why? because the real vi does it that way!) */ ! 297: if (prevkey == 'c') ! 298: { ! 299: if (key == 'w') ! 300: key = 'e'; ! 301: else if (key == 'W') ! 302: key = 'E'; ! 303: ! 304: /* wouldn't work right at the end of a word unless we ! 305: * backspace one character before doing the move. This ! 306: * will fix most cases. !!! but not all. ! 307: */ ! 308: if (markidx(cursor) > 0 && (key == 'e' || key == 'E')) ! 309: { ! 310: cursor--; ! 311: } ! 312: } ! 313: ! 314: /* look up the structure describing this command */ ! 315: keyptr = &vikeys[key]; ! 316: ! 317: /* if we're in the middle of a d/c/y/</>/! command, reject ! 318: * anything but movement or a doubled version like "dd". ! 319: */ ! 320: if (prevkey && key != prevkey && !(keyptr->flags & (MVMT|PTMV))) ! 321: { ! 322: beep(); ! 323: prevkey = 0; ! 324: count = 0; ! 325: continue; ! 326: } ! 327: ! 328: /* set the "dot" variables, if we're supposed to */ ! 329: if ((keyptr->flags & SDOT) ! 330: || (prevkey && vikeys[prevkey].flags & SDOT)) ! 331: { ! 332: dotkey = key; ! 333: dotpkey = prevkey; ! 334: dotkey2 = '\0'; ! 335: dotcnt = count; ! 336: ! 337: /* remember the line before any changes are made */ ! 338: if (U_line != markline(cursor)) ! 339: { ! 340: U_line = markline(cursor); ! 341: strcpy(U_text, fetchline(U_line)); ! 342: } ! 343: } ! 344: ! 345: /* if this is "." then set other vars from the "dot" vars */ ! 346: if (key == '.') ! 347: { ! 348: key = dotkey; ! 349: keyptr = &vikeys[key]; ! 350: prevkey = dotpkey; ! 351: if (prevkey) ! 352: { ! 353: range = cursor; ! 354: } ! 355: if (count == 0) ! 356: { ! 357: count = dotcnt; ! 358: } ! 359: doingdot = TRUE; ! 360: ! 361: /* remember the line before any changes are made */ ! 362: if (U_line != markline(cursor)) ! 363: { ! 364: U_line = markline(cursor); ! 365: strcpy(U_text, fetchline(U_line)); ! 366: } ! 367: } ! 368: else ! 369: { ! 370: doingdot = FALSE; ! 371: } ! 372: ! 373: /* process the key as a command */ ! 374: tcurs = cursor; ! 375: switch (keyptr->args) ! 376: { ! 377: case ZERO: ! 378: if (count == 0) ! 379: { ! 380: tcurs = cursor & ~(BLKSIZE - 1); ! 381: break; ! 382: } ! 383: /* else fall through & treat like other digits... */ ! 384: ! 385: case DIGIT: ! 386: count = count * 10 + key - '0'; ! 387: break; ! 388: ! 389: case KEYWORD: ! 390: /* if not on a keyword, fail */ ! 391: pfetch(markline(cursor)); ! 392: key = markidx(cursor); ! 393: if (isascii(ptext[key]) ! 394: && !isalnum(ptext[key]) && ptext[key] != '_') ! 395: { ! 396: tcurs = MARK_UNSET; ! 397: break; ! 398: } ! 399: ! 400: /* find the start of the keyword */ ! 401: while (key > 0 && (!isascii(ptext[key-1]) || ! 402: isalnum(ptext[key - 1]) || ptext[key - 1] == '_')) ! 403: { ! 404: key--; ! 405: } ! 406: tcurs = (cursor & ~(BLKSIZE - 1)) + key; ! 407: ! 408: /* copy it into a buffer, and NUL-terminate it */ ! 409: i = 0; ! 410: do ! 411: { ! 412: text[i++] = ptext[key++]; ! 413: } while (!isascii(ptext[key]) || isalnum(ptext[key]) || ptext[key] == '_'); ! 414: text[i] = '\0'; ! 415: ! 416: /* call the function */ ! 417: tcurs = (*keyptr->func)(text, tcurs, count); ! 418: count = 0L; ! 419: break; ! 420: ! 421: case NO_ARGS: ! 422: if (keyptr->func) ! 423: { ! 424: (*keyptr->func)(); ! 425: } ! 426: else ! 427: { ! 428: beep(); ! 429: } ! 430: count = 0L; ! 431: break; ! 432: ! 433: case CURSOR_COUNT: ! 434: tcurs = (*keyptr->func)(cursor, count); ! 435: count = 0L; ! 436: break; ! 437: ! 438: case CURSOR: ! 439: tcurs = (*keyptr->func)(cursor); ! 440: count = 0L; ! 441: break; ! 442: ! 443: case CURSOR_CNT_KEY: ! 444: if (doingdot) ! 445: { ! 446: tcurs = (*keyptr->func)(cursor, count, dotkey2); ! 447: } ! 448: else ! 449: { ! 450: /* get a key */ ! 451: i = getkey(0); ! 452: if (i == '\033') /* ESC */ ! 453: { ! 454: count = 0; ! 455: tcurs = MARK_UNSET; ! 456: break; /* exit from "case CURSOR_CNT_KEY" */ ! 457: } ! 458: else if (i == ('V' & 0x1f)) ! 459: { ! 460: i = getkey(0); ! 461: } ! 462: ! 463: /* if part of an SDOT command, remember it */ ! 464: if (keyptr->flags & SDOT ! 465: || (prevkey && vikeys[prevkey].flags & SDOT)) ! 466: { ! 467: dotkey2 = i; ! 468: } ! 469: ! 470: /* do it */ ! 471: tcurs = (*keyptr->func)(cursor, count, i); ! 472: } ! 473: count = 0L; ! 474: break; ! 475: ! 476: case CURSOR_MOVED: ! 477: /* '&' and uppercase keys always act like doubled */ ! 478: if (key == '&' || isascii(key) && isupper(key)) ! 479: { ! 480: prevkey = key; ! 481: } ! 482: ! 483: if (prevkey) ! 484: { ! 485: /* doubling up a command */ ! 486: if (!count) count = 1L; ! 487: range = cursor; ! 488: tcurs = range + MARK_AT_LINE(count - 1L); ! 489: count = 0L; ! 490: } ! 491: else ! 492: { ! 493: prevkey = key; ! 494: range = cursor; ! 495: key = -1; /* so we don't think we doubled yet */ ! 496: } ! 497: break; ! 498: ! 499: case CURSOR_EOL: ! 500: prevkey = key; ! 501: /* a zero-length line needs special treatment */ ! 502: pfetch(markline(cursor)); ! 503: if (plen == 0) ! 504: { ! 505: /* act on a zero-length section of text */ ! 506: range = tcurs = cursor; ! 507: key = ' '; ! 508: } ! 509: else ! 510: { ! 511: /* act like CURSOR_MOVED with '$' movement */ ! 512: range = cursor; ! 513: tcurs = m_rear(cursor, 1L); ! 514: key = '$'; ! 515: } ! 516: count = 0L; ! 517: keyptr = &vikeys[key]; ! 518: break; ! 519: ! 520: case CURSOR_TEXT: ! 521: do ! 522: { ! 523: text[0] = key; ! 524: if (vgets(key, text + 1, sizeof text - 1) >= 0) ! 525: { ! 526: /* reassure user that <CR> was hit */ ! 527: qaddch('\r'); ! 528: refresh(); ! 529: ! 530: /* call the function with the text */ ! 531: tcurs = (*keyptr->func)(cursor, text); ! 532: } ! 533: else ! 534: { ! 535: if (exwrote || mode == MODE_COLON) ! 536: { ! 537: redraw(MARK_UNSET, FALSE); ! 538: } ! 539: mode = MODE_VI; ! 540: } ! 541: } while (mode == MODE_COLON); ! 542: count = 0L; ! 543: break; ! 544: ! 545: case CURSOR_CNT_CMD: ! 546: tcurs = (*keyptr->func)(cursor, count, key); ! 547: count = 0L; ! 548: break; ! 549: } ! 550: ! 551: /* if that command took us out of vi mode, then exit the loop ! 552: * NOW, without tweaking the cursor or anything. This is very ! 553: * important when mode == MODE_QUIT. ! 554: */ ! 555: if (mode != MODE_VI) ! 556: { ! 557: break; ! 558: } ! 559: ! 560: /* now move the cursor, as appropriate */ ! 561: if (keyptr->args == CURSOR_MOVED) ! 562: { ! 563: /* the < and > keys have FRNT, ! 564: * but it shouldn't be applied yet ! 565: */ ! 566: tcurs = adjmove(cursor, tcurs, 0); ! 567: } ! 568: else ! 569: { ! 570: tcurs = adjmove(cursor, tcurs, (int)keyptr->flags); ! 571: } ! 572: ! 573: /* was that the end of a d/c/y/</>/! command? */ ! 574: if (prevkey && (prevkey == key || (keyptr->flags & MVMT)) && count == 0L) ! 575: { ! 576: /* if the movement command failed, cancel operation */ ! 577: if (tcurs == MARK_UNSET) ! 578: { ! 579: prevkey = 0; ! 580: count = 0; ! 581: continue; ! 582: } ! 583: ! 584: /* make sure range=front and tcurs=rear. Either way, ! 585: * leave cursor=range since that's where we started. ! 586: */ ! 587: cursor = range; ! 588: if (tcurs < range) ! 589: { ! 590: range = tcurs; ! 591: tcurs = cursor; ! 592: } ! 593: ! 594: ! 595: /* adjust for line mode & inclusion of last char/line */ ! 596: i = (keyptr->flags | vikeys[prevkey].flags); ! 597: if (key == prevkey) ! 598: { ! 599: i |= (INCL|LNMD); ! 600: } ! 601: switch (i & (INCL|LNMD)) ! 602: { ! 603: case INCL: ! 604: tcurs++; ! 605: break; ! 606: ! 607: case INCL|LNMD: ! 608: tcurs += BLKSIZE; ! 609: /* fall through... */ ! 610: ! 611: case LNMD: ! 612: range &= ~(BLKSIZE - 1); ! 613: tcurs &= ~(BLKSIZE - 1); ! 614: break; ! 615: } ! 616: ! 617: /* run the function */ ! 618: tcurs = (*vikeys[prevkey].func)(range, tcurs); ! 619: (void)adjmove(cursor, cursor, 0); ! 620: cursor = adjmove(cursor, tcurs, (int)vikeys[prevkey].flags); ! 621: ! 622: /* cleanup */ ! 623: prevkey = 0; ! 624: } ! 625: else if (!prevkey) ! 626: { ! 627: cursor = tcurs; ! 628: } ! 629: } ! 630: } ! 631: ! 632: /* This function adjusts the MARK value that they return; here we make sure ! 633: * it isn't past the end of the line, and that the column hasn't been ! 634: * *accidentally* changed. ! 635: */ ! 636: MARK adjmove(old, new, flags) ! 637: MARK old; /* the cursor position before the command */ ! 638: REG MARK new; /* the cursor position after the command */ ! 639: int flags; /* various flags regarding cursor mvmt */ ! 640: { ! 641: static int colno; /* the column number that we want */ ! 642: REG char *text; /* used to scan through the line's text */ ! 643: REG int i; ! 644: ! 645: #ifdef DEBUG ! 646: watch(); ! 647: #endif ! 648: ! 649: /* if the command failed, bag it! */ ! 650: if (new == MARK_UNSET) ! 651: { ! 652: beep(); ! 653: return old; ! 654: } ! 655: ! 656: /* if this is a non-relative movement, set the '' mark */ ! 657: if (flags & NREL) ! 658: { ! 659: mark[26] = old; ! 660: } ! 661: ! 662: /* make sure it isn't past the end of the file */ ! 663: if (markline(new) < 1) ! 664: { ! 665: new = MARK_FIRST; ! 666: } ! 667: else if (markline(new) > nlines) ! 668: { ! 669: new = MARK_LAST; ! 670: } ! 671: ! 672: /* fetch the new line */ ! 673: pfetch(markline(new)); ! 674: ! 675: /* move to the front, if we're supposed to */ ! 676: if (flags & FRNT) ! 677: { ! 678: new = m_front(new, 1L); ! 679: } ! 680: ! 681: /* change the column#, or change the mark to suit the column# */ ! 682: if (!(flags & NCOL)) ! 683: { ! 684: /* change the column# */ ! 685: i = markidx(new); ! 686: if (i == BLKSIZE - 1) ! 687: { ! 688: new &= ~(BLKSIZE - 1); ! 689: if (plen > 0) ! 690: { ! 691: new += plen - 1; ! 692: } ! 693: colno = BLKSIZE * 8; /* one heck of a big colno */ ! 694: } ! 695: else if (plen > 0) ! 696: { ! 697: if (i >= plen) ! 698: { ! 699: new = (new & ~(BLKSIZE - 1)) + plen - 1; ! 700: } ! 701: colno = idx2col(new, ptext, FALSE); ! 702: } ! 703: else ! 704: { ! 705: new &= ~(BLKSIZE - 1); ! 706: colno = 0; ! 707: } ! 708: } ! 709: else ! 710: { ! 711: /* adjust the mark to get as close as possible to column# */ ! 712: for (i = 0, text = ptext; i <= colno && *text; text++) ! 713: { ! 714: if (*text == '\t' && !*o_list) ! 715: { ! 716: i += *o_tabstop - (i % *o_tabstop); ! 717: } ! 718: else if (UCHAR(*text) < ' ' || *text == 127) ! 719: { ! 720: i += 2; ! 721: } ! 722: #ifndef NO_CHARATTR ! 723: else if (*o_charattr && text[0] == '\\' && text[1] == 'f' && text[2]) ! 724: { ! 725: text += 2; /* plus one more in "for()" stmt */ ! 726: } ! 727: #endif ! 728: else ! 729: { ! 730: i++; ! 731: } ! 732: } ! 733: if (text > ptext) ! 734: { ! 735: text--; ! 736: } ! 737: new = (new & ~(BLKSIZE - 1)) + (int)(text - ptext); ! 738: } ! 739: ! 740: return new; ! 741: } ! 742: ! 743: ! 744: #ifdef DEBUG ! 745: watch() ! 746: { ! 747: static wasset; ! 748: ! 749: if (*origname) ! 750: { ! 751: wasset = TRUE; ! 752: } ! 753: else if (wasset) ! 754: { ! 755: msg("origname was clobbered"); ! 756: endwin(); ! 757: abort(); ! 758: } ! 759: ! 760: if (nlines == 0) ! 761: { ! 762: msg("nlines=0"); ! 763: endwin(); ! 764: abort(); ! 765: } ! 766: } ! 767: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.