|
|
1.1 ! root 1: /* vcmd.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: /* This file contains the functions that handle VI commands */ ! 12: ! 13: ! 14: #include "config.h" ! 15: #include "vi.h" ! 16: #if MSDOS ! 17: #include <process.h> ! 18: #include <string.h> ! 19: #endif ! 20: #if TOS ! 21: #include <osbind.h> ! 22: #include <string.h> ! 23: #endif ! 24: #if OSK ! 25: # include <stdio.h> ! 26: #endif ! 27: ! 28: ! 29: /* This function puts the editor in EX mode */ ! 30: MARK v_quit() ! 31: { ! 32: move(LINES - 1, 0); ! 33: mode = MODE_EX; ! 34: return cursor; ! 35: } ! 36: ! 37: /* This function causes the screen to be redrawn */ ! 38: MARK v_redraw() ! 39: { ! 40: redraw(MARK_UNSET, FALSE); ! 41: return cursor; ! 42: } ! 43: ! 44: /* This function executes a single EX command, and waits for a user keystroke ! 45: * before returning to the VI screen. If that keystroke is another ':', then ! 46: * another EX command is read and executed. ! 47: */ ! 48: /*ARGSUSED*/ ! 49: MARK v_1ex(m, text) ! 50: MARK m; /* the current line */ ! 51: char *text; /* the first command to execute */ ! 52: { ! 53: /* run the command. be careful about modes & output */ ! 54: exwrote = (mode == MODE_COLON); ! 55: doexcmd(text); ! 56: exrefresh(); ! 57: ! 58: /* if mode is no longer MODE_VI, then we should quit right away! */ ! 59: if (mode != MODE_VI && mode != MODE_COLON) ! 60: return cursor; ! 61: ! 62: /* The command did some output. Wait for a keystoke. */ ! 63: if (exwrote) ! 64: { ! 65: mode = MODE_VI; ! 66: msg("[Hit <RETURN> to continue]"); ! 67: if (getkey(0) == ':') ! 68: { mode = MODE_COLON; ! 69: addch('\n'); ! 70: } ! 71: else ! 72: redraw(MARK_UNSET, FALSE); ! 73: } ! 74: ! 75: return cursor; ! 76: } ! 77: ! 78: /* This function undoes the last change */ ! 79: /*ARGSUSED*/ ! 80: MARK v_undo(m) ! 81: MARK m; /* (ignored) */ ! 82: { ! 83: if (undo()) ! 84: { ! 85: redraw(MARK_UNSET, FALSE); ! 86: } ! 87: return cursor; ! 88: } ! 89: ! 90: /* This function deletes the character(s) that the cursor is on */ ! 91: MARK v_xchar(m, cnt, cmd) ! 92: MARK m; /* where to start deletions */ ! 93: long cnt; /* number of chars to delete */ ! 94: int cmd; /* either 'x' or 'X' */ ! 95: { ! 96: DEFAULT(1); ! 97: ! 98: /* for 'X', adjust so chars are deleted *BEFORE* cursor */ ! 99: if (cmd == 'X') ! 100: { ! 101: if (markidx(m) < cnt) ! 102: return MARK_UNSET; ! 103: m -= cnt; ! 104: } ! 105: ! 106: /* make sure we don't try to delete more thars than there are */ ! 107: pfetch(markline(m)); ! 108: if (markidx(m + cnt) > plen) ! 109: { ! 110: cnt = plen - markidx(m); ! 111: } ! 112: if (cnt == 0L) ! 113: { ! 114: return MARK_UNSET; ! 115: } ! 116: ! 117: /* do it */ ! 118: ChangeText ! 119: { ! 120: cut(m, m + cnt); ! 121: delete(m, m + cnt); ! 122: } ! 123: return m; ! 124: } ! 125: ! 126: /* This function defines a mark */ ! 127: /*ARGSUSED*/ ! 128: MARK v_mark(m, count, key) ! 129: MARK m; /* where the mark will be */ ! 130: long count; /* (ignored) */ ! 131: int key; /* the ASCII label of the mark */ ! 132: { ! 133: if (key < 'a' || key > 'z') ! 134: { ! 135: msg("Marks must be from a to z"); ! 136: } ! 137: else ! 138: { ! 139: mark[key - 'a'] = m; ! 140: } ! 141: return m; ! 142: } ! 143: ! 144: /* This function toggles upper & lower case letters */ ! 145: MARK v_ulcase(m, cnt) ! 146: MARK m; /* where to make the change */ ! 147: long cnt; /* number of chars to flip */ ! 148: { ! 149: REG char *pos; ! 150: REG int i, j; ! 151: static char flip[] = ! 152: "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ[](){}<>"; ! 153: ! 154: DEFAULT(1); ! 155: ! 156: /* fetch the current version of the line */ ! 157: pfetch(markline(m)); ! 158: ! 159: /* for each position in the line */ ! 160: for (j = 0, i = markidx(m); j < cnt && ptext[i]; j++, i++) ! 161: { ! 162: tmpblk.c[j] = 0; ! 163: ! 164: /* one of the standard chars? */ ! 165: for (pos = flip; *pos && *pos != ptext[i]; pos++) ! 166: { ! 167: } ! 168: if (*pos) ! 169: { ! 170: tmpblk.c[j] = flip[(int)(pos - flip) ^ 1]; ! 171: } ! 172: #ifndef NO_DIGRAPH ! 173: else /* one of the non-standard chars? */ ! 174: { ! 175: for (pos = o_flipcase; *pos && *pos != ptext[i]; pos++) ! 176: { ! 177: } ! 178: if (*pos) ! 179: { ! 180: tmpblk.c[j] = o_flipcase[(int)(pos - o_flipcase) ^ 1]; ! 181: } ! 182: } ! 183: #endif ! 184: ! 185: /* if nothing special, then don't change it */ ! 186: if (tmpblk.c[j] == 0) ! 187: { ! 188: tmpblk.c[j] = ptext[i]; ! 189: } ! 190: } ! 191: ! 192: /* if the new text is different from the old, then change it */ ! 193: if (strncmp(tmpblk.c, &ptext[markidx(m)], j)) ! 194: { ! 195: ChangeText ! 196: { ! 197: tmpblk.c[j] = '\0'; ! 198: change(m, m + j, tmpblk.c); ! 199: } ! 200: } ! 201: ! 202: return m + j; ! 203: } ! 204: ! 205: ! 206: MARK v_replace(m, cnt, key) ! 207: MARK m; /* first char to be replaced */ ! 208: long cnt; /* number of chars to replace */ ! 209: int key; /* what to replace them with */ ! 210: { ! 211: REG char *text; ! 212: REG int i; ! 213: ! 214: DEFAULT(1); ! 215: ! 216: /* map ^M to '\n' */ ! 217: if (key == '\r') ! 218: { ! 219: key = '\n'; ! 220: } ! 221: ! 222: /* make sure the resulting line isn't too long */ ! 223: if (cnt > BLKSIZE - 2 - markidx(m)) ! 224: { ! 225: cnt = BLKSIZE - 2 - markidx(m); ! 226: } ! 227: ! 228: /* build a string of the desired character with the desired length */ ! 229: for (text = tmpblk.c, i = cnt; i > 0; i--) ! 230: { ! 231: *text++ = key; ! 232: } ! 233: *text = '\0'; ! 234: ! 235: /* make sure cnt doesn't extend past EOL */ ! 236: pfetch(markline(m)); ! 237: key = markidx(m); ! 238: if (key + cnt > plen) ! 239: { ! 240: cnt = plen - key; ! 241: } ! 242: ! 243: /* do the replacement */ ! 244: ChangeText ! 245: { ! 246: change(m, m + cnt, tmpblk.c); ! 247: } ! 248: ! 249: if (*tmpblk.c == '\n') ! 250: { ! 251: return (m & ~(BLKSIZE - 1)) + cnt * BLKSIZE; ! 252: } ! 253: else ! 254: { ! 255: return m + cnt - 1; ! 256: } ! 257: } ! 258: ! 259: MARK v_overtype(m) ! 260: MARK m; /* where to start overtyping */ ! 261: { ! 262: MARK end; /* end of a substitution */ ! 263: static long width; /* width of a single-line replace */ ! 264: ! 265: /* the "doingdot" version of replace is really a substitution */ ! 266: if (doingdot) ! 267: { ! 268: /* was the last one really repeatable? */ ! 269: if (width < 0) ! 270: { ! 271: msg("Can't repeat a multi-line overtype command"); ! 272: return MARK_UNSET; ! 273: } ! 274: ! 275: /* replacing nothing by nothing? Don't bother */ ! 276: if (width == 0) ! 277: { ! 278: return m; ! 279: } ! 280: ! 281: /* replace some chars by repeated text */ ! 282: return v_subst(m, width); ! 283: } ! 284: ! 285: /* Normally, we input starting here, in replace mode */ ! 286: ChangeText ! 287: { ! 288: end = input(m, m, WHEN_VIREP); ! 289: } ! 290: ! 291: /* if we ended on the same line we started on, then this ! 292: * overtype is repeatable via the dot key. ! 293: */ ! 294: if (markline(end) == markline(m) && end >= m - 1L) ! 295: { ! 296: width = end - m + 1L; ! 297: } ! 298: else /* it isn't repeatable */ ! 299: { ! 300: width = -1L; ! 301: } ! 302: ! 303: return end; ! 304: } ! 305: ! 306: ! 307: /* This function selects which cut buffer to use */ ! 308: /*ARGSUSED*/ ! 309: MARK v_selcut(m, cnt, key) ! 310: MARK m; ! 311: long cnt; ! 312: int key; ! 313: { ! 314: cutname(key); ! 315: return m; ! 316: } ! 317: ! 318: /* This function pastes text from a cut buffer */ ! 319: /*ARGSUSED*/ ! 320: MARK v_paste(m, cnt, cmd) ! 321: MARK m; /* where to paste the text */ ! 322: long cnt; /* (ignored) */ ! 323: int cmd; /* either 'p' or 'P' */ ! 324: { ! 325: ChangeText ! 326: { ! 327: m = paste(m, cmd == 'p', FALSE); ! 328: } ! 329: return m; ! 330: } ! 331: ! 332: /* This function yanks text into a cut buffer */ ! 333: MARK v_yank(m, n) ! 334: MARK m, n; /* range of text to yank */ ! 335: { ! 336: cut(m, n); ! 337: return m; ! 338: } ! 339: ! 340: /* This function deletes a range of text */ ! 341: MARK v_delete(m, n) ! 342: MARK m, n; /* range of text to delete */ ! 343: { ! 344: /* illegal to try and delete nothing */ ! 345: if (n <= m) ! 346: { ! 347: return MARK_UNSET; ! 348: } ! 349: ! 350: /* Do it */ ! 351: ChangeText ! 352: { ! 353: cut(m, n); ! 354: delete(m, n); ! 355: } ! 356: return m; ! 357: } ! 358: ! 359: ! 360: /* This starts input mode without deleting anything */ ! 361: MARK v_insert(m, cnt, key) ! 362: MARK m; /* where to start (sort of) */ ! 363: long cnt; /* repeat how many times? */ ! 364: int key; /* what command is this for? {a,A,i,I,o,O} */ ! 365: { ! 366: int wasdot; ! 367: long reps; ! 368: int after; /* are we appending or inserting? */ ! 369: ! 370: DEFAULT(1); ! 371: ! 372: ChangeText ! 373: { ! 374: /* tweak the insertion point, based on command key */ ! 375: switch (key) ! 376: { ! 377: case 'i': ! 378: after = FALSE; ! 379: break; ! 380: ! 381: case 'a': ! 382: pfetch(markline(m)); ! 383: if (plen > 0) ! 384: { ! 385: m++; ! 386: } ! 387: after = TRUE; ! 388: break; ! 389: ! 390: case 'I': ! 391: m = m_front(m, 1L); ! 392: after = FALSE; ! 393: break; ! 394: ! 395: case 'A': ! 396: pfetch(markline(m)); ! 397: m = (m & ~(BLKSIZE - 1)) + plen; ! 398: after = TRUE; ! 399: break; ! 400: ! 401: case 'O': ! 402: m &= ~(BLKSIZE - 1); ! 403: add(m, "\n"); ! 404: after = FALSE; ! 405: break; ! 406: ! 407: case 'o': ! 408: m = (m & ~(BLKSIZE - 1)) + BLKSIZE; ! 409: add(m, "\n"); ! 410: after = FALSE; ! 411: break; ! 412: } ! 413: ! 414: /* insert the same text once or more */ ! 415: for (reps = cnt, wasdot = doingdot; reps > 0; reps--, doingdot = TRUE) ! 416: { ! 417: m = input(m, m, WHEN_VIINP); ! 418: if (after) ! 419: { ! 420: m++; ! 421: } ! 422: } ! 423: if (after) ! 424: { ! 425: m--; ! 426: } ! 427: ! 428: doingdot = wasdot; ! 429: } ! 430: ! 431: #ifndef CRUNCH ! 432: # ifndef NO_EXTENSIONS ! 433: if (key == 'i' && *o_inputmode) ! 434: { ! 435: msg("Now in visual command mode! To return to input mode, hit <i>."); ! 436: } ! 437: # endif ! 438: #endif ! 439: ! 440: return m; ! 441: } ! 442: ! 443: /* This starts input mode with some text deleted */ ! 444: MARK v_change(m, n) ! 445: MARK m, n; /* the range of text to change */ ! 446: { ! 447: int lnmode; /* is this a line-mode change? */ ! 448: ! 449: /* swap them if they're in reverse order */ ! 450: if (m > n) ! 451: { ! 452: MARK tmp; ! 453: tmp = m; ! 454: m = n; ! 455: n = tmp; ! 456: } ! 457: ! 458: /* for line mode, retain the last newline char */ ! 459: lnmode = (markidx(m) == 0 && markidx(n) == 0 && m != n); ! 460: if (lnmode) ! 461: { ! 462: n -= BLKSIZE; ! 463: pfetch(markline(n)); ! 464: n = (n & ~(BLKSIZE - 1)) + plen; ! 465: } ! 466: ! 467: ChangeText ! 468: { ! 469: cut(m, n); ! 470: m = input(m, n, WHEN_VIINP); ! 471: } ! 472: ! 473: return m; ! 474: } ! 475: ! 476: /* This function replaces a given number of characters with input */ ! 477: MARK v_subst(m, cnt) ! 478: MARK m; /* where substitutions start */ ! 479: long cnt; /* number of chars to replace */ ! 480: { ! 481: DEFAULT(1); ! 482: ! 483: /* make sure we don't try replacing past EOL */ ! 484: pfetch(markline(m)); ! 485: if (markidx(m) + cnt > plen) ! 486: { ! 487: cnt = plen - markidx(m); ! 488: } ! 489: ! 490: /* Go for it! */ ! 491: ChangeText ! 492: { ! 493: cut(m, m + cnt); ! 494: m = input(m, m + cnt, WHEN_VIINP); ! 495: } ! 496: return m; ! 497: } ! 498: ! 499: /* This calls the ex "join" command to join some lines together */ ! 500: MARK v_join(m, cnt) ! 501: MARK m; /* the first line to be joined */ ! 502: long cnt; /* number of other lines to join */ ! 503: { ! 504: MARK joint; /* where the lines were joined */ ! 505: ! 506: DEFAULT(1); ! 507: ! 508: /* figure out where the joint will be */ ! 509: pfetch(markline(m)); ! 510: joint = (m & ~(BLKSIZE - 1)) + plen; ! 511: ! 512: /* join the lines */ ! 513: cmd_join(m, m + MARK_AT_LINE(cnt), CMD_JOIN, 0, ""); ! 514: mustredraw = TRUE; ! 515: ! 516: /* the cursor should be left at the joint */ ! 517: return joint; ! 518: } ! 519: ! 520: /* This calls the ex shifter command to shift some lines */ ! 521: static MARK shift_help(m, n, excmd) ! 522: MARK m, n; /* range of lines to shift */ ! 523: CMD excmd; /* which way do we shift? */ ! 524: { ! 525: /* adjust for inclusive endmarks in ex */ ! 526: n -= BLKSIZE; ! 527: ! 528: cmd_shift(m, n, excmd, 0, ""); ! 529: return m; ! 530: } ! 531: ! 532: /* This calls the ex "<" command to shift some lines left */ ! 533: MARK v_lshift(m, n) ! 534: MARK m, n; /* range of lines to shift */ ! 535: { ! 536: return shift_help(m, n, CMD_SHIFTL); ! 537: } ! 538: ! 539: /* This calls the ex ">" command to shift some lines right */ ! 540: MARK v_rshift(m, n) ! 541: MARK m, n; /* range of lines to shift */ ! 542: { ! 543: return shift_help(m, n, CMD_SHIFTR); ! 544: } ! 545: ! 546: /* This runs some lines through a filter program */ ! 547: MARK v_filter(m, n) ! 548: MARK m, n; /* range of lines to shift */ ! 549: { ! 550: char cmdln[100]; /* a shell command line */ ! 551: ! 552: /* adjust for inclusive endmarks in ex */ ! 553: n -= BLKSIZE; ! 554: ! 555: if (vgets('!', cmdln, sizeof(cmdln)) > 0) ! 556: { ! 557: filter(m, n, cmdln); ! 558: } ! 559: ! 560: redraw(MARK_UNSET, FALSE); ! 561: return m; ! 562: } ! 563: ! 564: ! 565: /* This function runs the ex "file" command to show the file's status */ ! 566: MARK v_status() ! 567: { ! 568: cmd_file(cursor, cursor, CMD_FILE, 0, ""); ! 569: return cursor; ! 570: } ! 571: ! 572: ! 573: /* This function runs the ":&" command to repeat the previous :s// */ ! 574: MARK v_again(m, n) ! 575: MARK m, n; ! 576: { ! 577: cmd_substitute(m, n - BLKSIZE, CMD_SUBAGAIN, TRUE, ""); ! 578: return cursor; ! 579: } ! 580: ! 581: ! 582: ! 583: /* This function switches to the previous file, if possible */ ! 584: MARK v_switch() ! 585: { ! 586: if (!*prevorig) ! 587: msg("No previous file"); ! 588: else ! 589: { strcpy(tmpblk.c, prevorig); ! 590: cmd_edit(cursor, cursor, CMD_EDIT, 0, tmpblk.c); ! 591: } ! 592: return cursor; ! 593: } ! 594: ! 595: /* This function does a tag search on a keyword */ ! 596: /*ARGSUSED*/ ! 597: MARK v_tag(keyword, m, cnt) ! 598: char *keyword; ! 599: MARK m; ! 600: long cnt; ! 601: { ! 602: /* move the cursor to the start of the tag name, where m is */ ! 603: cursor = m; ! 604: ! 605: /* perform the tag search */ ! 606: cmd_tag(cursor, cursor, CMD_TAG, 0, keyword); ! 607: ! 608: return cursor; ! 609: } ! 610: ! 611: #ifndef NO_EXTENSIONS ! 612: /* This function looks up a keyword by calling the helpprog program */ ! 613: /*ARGSUSED*/ ! 614: MARK v_keyword(keyword, m, cnt) ! 615: char *keyword; ! 616: MARK m; ! 617: long cnt; ! 618: { ! 619: int waswarn; ! 620: char cmdline[130]; ! 621: ! 622: move(LINES - 1, 0); ! 623: addstr("---------------------------------------------------------\n"); ! 624: clrtoeol(); ! 625: refresh(); ! 626: sprintf(cmdline, "%s %s", o_keywordprg, keyword); ! 627: waswarn = *o_warn; ! 628: *o_warn = FALSE; ! 629: suspend_curses(); ! 630: if (system(cmdline)) ! 631: { ! 632: addstr("<<< failed >>>\n"); ! 633: } ! 634: resume_curses(FALSE); ! 635: mode = MODE_VI; ! 636: redraw(MARK_UNSET, FALSE); ! 637: *o_warn = waswarn; ! 638: ! 639: return m; ! 640: } ! 641: ! 642: ! 643: ! 644: MARK v_increment(keyword, m, cnt) ! 645: char *keyword; ! 646: MARK m; ! 647: long cnt; ! 648: { ! 649: static sign; ! 650: char newval[12]; ! 651: long atol(); ! 652: ! 653: DEFAULT(1); ! 654: ! 655: /* get one more keystroke, unless doingdot */ ! 656: if (!doingdot) ! 657: { ! 658: sign = getkey(0); ! 659: } ! 660: ! 661: /* adjust the number, based on that second keystroke */ ! 662: switch (sign) ! 663: { ! 664: case '+': ! 665: case '#': ! 666: cnt = atol(keyword) + cnt; ! 667: break; ! 668: ! 669: case '-': ! 670: cnt = atol(keyword) - cnt; ! 671: break; ! 672: ! 673: case '=': ! 674: break; ! 675: ! 676: default: ! 677: return MARK_UNSET; ! 678: } ! 679: sprintf(newval, "%ld", cnt); ! 680: ! 681: ChangeText ! 682: { ! 683: change(m, m + strlen(keyword), newval); ! 684: } ! 685: ! 686: return m; ! 687: } ! 688: #endif ! 689: ! 690: ! 691: /* This function acts like the EX command "xit" */ ! 692: /*ARGSUSED*/ ! 693: MARK v_xit(m, cnt, key) ! 694: MARK m; /* ignored */ ! 695: long cnt; /* ignored */ ! 696: int key; /* must be a second 'Z' */ ! 697: { ! 698: /* if second char wasn't 'Z', fail */ ! 699: if (key != 'Z') ! 700: { ! 701: return MARK_UNSET; ! 702: } ! 703: ! 704: /* move the cursor to the bottom of the screen */ ! 705: move(LINES - 1, 0); ! 706: clrtoeol(); ! 707: ! 708: /* do the xit command */ ! 709: cmd_xit(m, m, CMD_XIT, FALSE, ""); ! 710: ! 711: /* return the cursor */ ! 712: return m; ! 713: } ! 714: ! 715: ! 716: /* This function undoes changes to a single line, if possible */ ! 717: MARK v_undoline(m) ! 718: MARK m; /* where we hope to undo the change */ ! 719: { ! 720: /* make sure we have the right line in the buffer */ ! 721: if (markline(m) != U_line) ! 722: { ! 723: return MARK_UNSET; ! 724: } ! 725: ! 726: /* fix it */ ! 727: ChangeText ! 728: { ! 729: strcat(U_text, "\n"); ! 730: change(MARK_AT_LINE(U_line), MARK_AT_LINE(U_line + 1), U_text); ! 731: } ! 732: ! 733: /* nothing in the buffer anymore */ ! 734: U_line = -1L; ! 735: ! 736: /* return, with the cursor at the front of the line */ ! 737: return m & ~(BLKSIZE - 1); ! 738: } ! 739: ! 740: ! 741: #ifndef NO_ERRLIST ! 742: MARK v_errlist(m) ! 743: MARK m; ! 744: { ! 745: cmd_errlist(m, m, CMD_ERRLIST, FALSE, ""); ! 746: return cursor; ! 747: } ! 748: #endif ! 749: ! 750: ! 751: #ifndef NO_AT ! 752: /*ARGSUSED*/ ! 753: MARK v_at(m, cnt, key) ! 754: MARK m; ! 755: long cnt; ! 756: int key; ! 757: { ! 758: if (!fromcutbuf(key)) ! 759: { ! 760: return MARK_UNSET; ! 761: } ! 762: return cursor; ! 763: } ! 764: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.