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