|
|
1.1 ! root 1: /* vcmd.c */ ! 2: ! 3: /* Author: ! 4: * Steve Kirkendall ! 5: * 14407 SW Teal Blvd. #C ! 6: * Beaverton, OR 97005 ! 7: * [email protected] ! 8: */ ! 9: ! 10: ! 11: /* This file contains the functions that handle VI commands */ ! 12: ! 13: ! 14: #include "config.h" ! 15: #include "ctype.h" ! 16: #include "vi.h" ! 17: #if MSDOS ! 18: # include <process.h> ! 19: # include <string.h> ! 20: #endif ! 21: #if TOS ! 22: # include <osbind.h> ! 23: # include <string.h> ! 24: #endif ! 25: #if OSK ! 26: # include <stdio.h> ! 27: #endif ! 28: ! 29: ! 30: /* This function puts the editor in EX mode */ ! 31: MARK v_quit() ! 32: { ! 33: move(LINES - 1, 0); ! 34: mode = MODE_EX; ! 35: return cursor; ! 36: } ! 37: ! 38: /* This function causes the screen to be redrawn */ ! 39: MARK v_redraw() ! 40: { ! 41: redraw(MARK_UNSET, FALSE); ! 42: return cursor; ! 43: } ! 44: ! 45: /* This function executes a string of EX commands, and waits for a user keystroke ! 46: * before returning to the VI screen. If that keystroke is another ':', then ! 47: * another EX command is read and executed. ! 48: */ ! 49: /*ARGSUSED*/ ! 50: MARK v_1ex(m, text) ! 51: MARK m; /* the current line */ ! 52: char *text; /* the first command to execute */ ! 53: { ! 54: /* run the command. be careful about modes & output */ ! 55: exwrote = (mode == MODE_COLON); ! 56: doexcmd(text); ! 57: exrefresh(); ! 58: ! 59: /* if mode is no longer MODE_VI, then we should quit right away! */ ! 60: if (mode != MODE_VI && mode != MODE_COLON) ! 61: return cursor; ! 62: ! 63: /* The command did some output. Wait for a keystoke. */ ! 64: if (exwrote) ! 65: { ! 66: mode = MODE_VI; ! 67: msg("[Hit <RETURN> to continue]"); ! 68: if (getkey(0) == ':') ! 69: { mode = MODE_COLON; ! 70: addch('\n'); ! 71: } ! 72: else ! 73: redraw(MARK_UNSET, FALSE); ! 74: } ! 75: ! 76: return cursor; ! 77: } ! 78: ! 79: /* This function undoes the last change */ ! 80: /*ARGSUSED*/ ! 81: MARK v_undo(m) ! 82: MARK m; /* (ignored) */ ! 83: { ! 84: if (undo()) ! 85: { ! 86: redraw(MARK_UNSET, FALSE); ! 87: } ! 88: return cursor; ! 89: } ! 90: ! 91: /* This function deletes the character(s) that the cursor is on */ ! 92: MARK v_xchar(m, cnt, cmd) ! 93: MARK m; /* where to start deletions */ ! 94: long cnt; /* number of chars to delete */ ! 95: int cmd; /* either 'x' or 'X' */ ! 96: { ! 97: DEFAULT(1); ! 98: ! 99: /* for 'X', adjust so chars are deleted *BEFORE* cursor */ ! 100: if (cmd == 'X') ! 101: { ! 102: if (markidx(m) < cnt) ! 103: return MARK_UNSET; ! 104: m -= cnt; ! 105: } ! 106: ! 107: /* make sure we don't try to delete more thars than there are */ ! 108: pfetch(markline(m)); ! 109: if (markidx(m + cnt) > plen) ! 110: { ! 111: cnt = plen - markidx(m); ! 112: } ! 113: if (cnt == 0L) ! 114: { ! 115: return MARK_UNSET; ! 116: } ! 117: ! 118: /* do it */ ! 119: ChangeText ! 120: { ! 121: cut(m, m + cnt); ! 122: delete(m, m + cnt); ! 123: } ! 124: return m; ! 125: } ! 126: ! 127: /* This function defines a mark */ ! 128: /*ARGSUSED*/ ! 129: MARK v_mark(m, count, key) ! 130: MARK m; /* where the mark will be */ ! 131: long count; /* (ignored) */ ! 132: int key; /* the ASCII label of the mark */ ! 133: { ! 134: if (key < 'a' || key > 'z') ! 135: { ! 136: msg("Marks must be from a to z"); ! 137: } ! 138: else ! 139: { ! 140: mark[key - 'a'] = m; ! 141: } ! 142: return m; ! 143: } ! 144: ! 145: /* This function toggles upper & lower case letters */ ! 146: MARK v_ulcase(m, cnt) ! 147: MARK m; /* where to make the change */ ! 148: long cnt; /* number of chars to flip */ ! 149: { ! 150: REG char *pos; ! 151: REG int j; ! 152: ! 153: DEFAULT(1); ! 154: ! 155: /* fetch the current version of the line */ ! 156: pfetch(markline(m)); ! 157: ! 158: /* for each position in the line */ ! 159: for (j = 0, pos = &ptext[markidx(m)]; j < cnt && *pos; j++, pos++) ! 160: { ! 161: if (isupper(*pos)) ! 162: { ! 163: tmpblk.c[j] = tolower(*pos); ! 164: } ! 165: else ! 166: { ! 167: tmpblk.c[j] = toupper(*pos); ! 168: } ! 169: } ! 170: ! 171: /* if the new text is different from the old, then change it */ ! 172: if (strncmp(tmpblk.c, &ptext[markidx(m)], j)) ! 173: { ! 174: ChangeText ! 175: { ! 176: tmpblk.c[j] = '\0'; ! 177: change(m, m + j, tmpblk.c); ! 178: } ! 179: } ! 180: ! 181: return m + j; ! 182: } ! 183: ! 184: ! 185: MARK v_replace(m, cnt, key) ! 186: MARK m; /* first char to be replaced */ ! 187: long cnt; /* number of chars to replace */ ! 188: int key; /* what to replace them with */ ! 189: { ! 190: REG char *text; ! 191: REG int i; ! 192: ! 193: DEFAULT(1); ! 194: ! 195: /* map ^M to '\n' */ ! 196: if (key == '\r') ! 197: { ! 198: key = '\n'; ! 199: } ! 200: ! 201: /* make sure the resulting line isn't too long */ ! 202: if (cnt > BLKSIZE - 2 - markidx(m)) ! 203: { ! 204: cnt = BLKSIZE - 2 - markidx(m); ! 205: } ! 206: ! 207: /* build a string of the desired character with the desired length */ ! 208: for (text = tmpblk.c, i = cnt; i > 0; i--) ! 209: { ! 210: *text++ = key; ! 211: } ! 212: *text = '\0'; ! 213: ! 214: /* make sure cnt doesn't extend past EOL */ ! 215: pfetch(markline(m)); ! 216: key = markidx(m); ! 217: if (key + cnt > plen) ! 218: { ! 219: cnt = plen - key; ! 220: } ! 221: ! 222: /* do the replacement */ ! 223: ChangeText ! 224: { ! 225: change(m, m + cnt, tmpblk.c); ! 226: } ! 227: ! 228: if (*tmpblk.c == '\n') ! 229: { ! 230: return (m & ~(BLKSIZE - 1)) + cnt * BLKSIZE; ! 231: } ! 232: else ! 233: { ! 234: return m + cnt - 1; ! 235: } ! 236: } ! 237: ! 238: MARK v_overtype(m) ! 239: MARK m; /* where to start overtyping */ ! 240: { ! 241: MARK end; /* end of a substitution */ ! 242: static long width; /* width of a single-line replace */ ! 243: ! 244: /* the "doingdot" version of replace is really a substitution */ ! 245: if (doingdot) ! 246: { ! 247: /* was the last one really repeatable? */ ! 248: if (width < 0) ! 249: { ! 250: msg("Can't repeat a multi-line overtype command"); ! 251: return MARK_UNSET; ! 252: } ! 253: ! 254: /* replacing nothing by nothing? Don't bother */ ! 255: if (width == 0) ! 256: { ! 257: return m; ! 258: } ! 259: ! 260: /* replace some chars by repeated text */ ! 261: return v_subst(m, width); ! 262: } ! 263: ! 264: /* Normally, we input starting here, in replace mode */ ! 265: ChangeText ! 266: { ! 267: end = input(m, m, WHEN_VIREP, 0); ! 268: } ! 269: ! 270: /* if we ended on the same line we started on, then this ! 271: * overtype is repeatable via the dot key. ! 272: */ ! 273: if (markline(end) == markline(m) && end >= m - 1L) ! 274: { ! 275: width = end - m + 1L; ! 276: } ! 277: else /* it isn't repeatable */ ! 278: { ! 279: width = -1L; ! 280: } ! 281: ! 282: return end; ! 283: } ! 284: ! 285: ! 286: /* This function selects which cut buffer to use */ ! 287: /*ARGSUSED*/ ! 288: MARK v_selcut(m, cnt, key) ! 289: MARK m; ! 290: long cnt; ! 291: int key; ! 292: { ! 293: cutname(key); ! 294: return m; ! 295: } ! 296: ! 297: /* This function pastes text from a cut buffer */ ! 298: /*ARGSUSED*/ ! 299: MARK v_paste(m, cnt, cmd) ! 300: MARK m; /* where to paste the text */ ! 301: long cnt; /* (ignored) */ ! 302: int cmd; /* either 'p' or 'P' */ ! 303: { ! 304: MARK dest; ! 305: ! 306: ChangeText ! 307: { ! 308: /* paste the text, and find out where it ends */ ! 309: dest = paste(m, cmd == 'p', TRUE); ! 310: ! 311: /* was that a line-mode paste? */ ! 312: if (dest && markline(dest) != markline(m)) ! 313: { ! 314: /* line-mode pastes leave the cursor at the front ! 315: * of the first pasted line. ! 316: */ ! 317: dest = m; ! 318: if (cmd == 'p') ! 319: { ! 320: dest += BLKSIZE; ! 321: } ! 322: force_flags |= FRNT; ! 323: } ! 324: } ! 325: return dest; ! 326: } ! 327: ! 328: /* This function yanks text into a cut buffer */ ! 329: MARK v_yank(m, n) ! 330: MARK m, n; /* range of text to yank */ ! 331: { ! 332: cut(m, n); ! 333: return m; ! 334: } ! 335: ! 336: /* This function deletes a range of text */ ! 337: MARK v_delete(m, n) ! 338: MARK m, n; /* range of text to delete */ ! 339: { ! 340: /* illegal to try and delete nothing */ ! 341: if (n <= m) ! 342: { ! 343: return MARK_UNSET; ! 344: } ! 345: ! 346: /* Do it */ ! 347: ChangeText ! 348: { ! 349: cut(m, n); ! 350: delete(m, n); ! 351: } ! 352: return m; ! 353: } ! 354: ! 355: ! 356: /* This starts input mode without deleting anything */ ! 357: MARK v_insert(m, cnt, key) ! 358: MARK m; /* where to start (sort of) */ ! 359: long cnt; /* repeat how many times? */ ! 360: int key; /* what command is this for? {a,A,i,I,o,O} */ ! 361: { ! 362: int wasdot; ! 363: long reps; ! 364: int delta = 0;/* 1 to take autoindent from line below, -1 for above */ ! 365: ! 366: DEFAULT(1); ! 367: ! 368: ChangeText ! 369: { ! 370: /* tweak the insertion point, based on command key */ ! 371: switch (key) ! 372: { ! 373: case 'i': ! 374: break; ! 375: ! 376: case 'a': ! 377: pfetch(markline(m)); ! 378: if (plen > 0) ! 379: { ! 380: m++; ! 381: } ! 382: break; ! 383: ! 384: case 'I': ! 385: m = m_front(m, 1L); ! 386: break; ! 387: ! 388: case 'A': ! 389: pfetch(markline(m)); ! 390: m = (m & ~(BLKSIZE - 1)) + plen; ! 391: break; ! 392: ! 393: case 'O': ! 394: m &= ~(BLKSIZE - 1); ! 395: add(m, "\n"); ! 396: delta = 1; ! 397: break; ! 398: ! 399: case 'o': ! 400: m = (m & ~(BLKSIZE - 1)) + BLKSIZE; ! 401: add(m, "\n"); ! 402: delta = -1; ! 403: break; ! 404: } ! 405: ! 406: /* insert the same text once or more */ ! 407: for (reps = cnt, wasdot = doingdot; reps > 0; reps--, doingdot = TRUE) ! 408: { ! 409: m = input(m, m, WHEN_VIINP, delta) + 1; ! 410: } ! 411: if (markidx(m) > 0) ! 412: { ! 413: m--; ! 414: } ! 415: ! 416: doingdot = wasdot; ! 417: } ! 418: ! 419: #ifndef CRUNCH ! 420: # ifndef NO_EXTENSIONS ! 421: if (key == 'i' && *o_inputmode && mode == MODE_VI) ! 422: { ! 423: msg("Now in command mode! To return to input mode, hit <i>"); ! 424: } ! 425: # endif ! 426: #endif ! 427: ! 428: return m; ! 429: } ! 430: ! 431: /* This starts input mode with some text deleted */ ! 432: MARK v_change(m, n) ! 433: MARK m, n; /* the range of text to change */ ! 434: { ! 435: int lnmode; /* is this a line-mode change? */ ! 436: ! 437: /* swap them if they're in reverse order */ ! 438: if (m > n) ! 439: { ! 440: MARK tmp; ! 441: tmp = m; ! 442: m = n; ! 443: n = tmp; ! 444: } ! 445: ! 446: /* for line mode, retain the last newline char */ ! 447: lnmode = (markidx(m) == 0 && markidx(n) == 0 && m != n); ! 448: if (lnmode) ! 449: { ! 450: n -= BLKSIZE; ! 451: pfetch(markline(n)); ! 452: n = (n & ~(BLKSIZE - 1)) + plen; ! 453: } ! 454: ! 455: ChangeText ! 456: { ! 457: cut(m, n); ! 458: m = input(m, n, WHEN_VIINP, 0); ! 459: } ! 460: ! 461: return m; ! 462: } ! 463: ! 464: /* This function replaces a given number of characters with input */ ! 465: MARK v_subst(m, cnt) ! 466: MARK m; /* where substitutions start */ ! 467: long cnt; /* number of chars to replace */ ! 468: { ! 469: DEFAULT(1); ! 470: ! 471: /* make sure we don't try replacing past EOL */ ! 472: pfetch(markline(m)); ! 473: if (markidx(m) + cnt > plen) ! 474: { ! 475: cnt = plen - markidx(m); ! 476: } ! 477: ! 478: /* Go for it! */ ! 479: ChangeText ! 480: { ! 481: cut(m, m + cnt); ! 482: m = input(m, m + cnt, WHEN_VIINP, 0); ! 483: } ! 484: return m; ! 485: } ! 486: ! 487: /* This calls the ex "join" command to join some lines together */ ! 488: MARK v_join(m, cnt) ! 489: MARK m; /* the first line to be joined */ ! 490: long cnt; /* number of other lines to join */ ! 491: { ! 492: MARK joint; /* where the lines were joined */ ! 493: ! 494: DEFAULT(1); ! 495: ! 496: /* figure out where the joint will be */ ! 497: pfetch(markline(m)); ! 498: joint = (m & ~(BLKSIZE - 1)) + plen; ! 499: ! 500: /* join the lines */ ! 501: cmd_join(m, m + MARK_AT_LINE(cnt), CMD_JOIN, 0, ""); ! 502: ! 503: /* the cursor should be left at the joint */ ! 504: return joint; ! 505: } ! 506: ! 507: ! 508: /* This calls the ex "<" command to shift some lines left */ ! 509: MARK v_lshift(m, n) ! 510: MARK m, n; /* range of lines to shift */ ! 511: { ! 512: /* adjust for inclusive endmarks in ex */ ! 513: n -= BLKSIZE; ! 514: ! 515: cmd_shift(m, n, CMD_SHIFTL, FALSE, (char *)0); ! 516: ! 517: return m; ! 518: } ! 519: ! 520: /* This calls the ex ">" command to shift some lines right */ ! 521: MARK v_rshift(m, n) ! 522: MARK m, n; /* range of lines to shift */ ! 523: { ! 524: /* adjust for inclusive endmarks in ex */ ! 525: n -= BLKSIZE; ! 526: ! 527: cmd_shift(m, n, CMD_SHIFTR, FALSE, (char *)0); ! 528: ! 529: return m; ! 530: } ! 531: ! 532: /* This filters some lines through a preset program, to reformat them */ ! 533: MARK v_reformat(m, n) ! 534: MARK m, n; /* range of lines to shift */ ! 535: { ! 536: /* adjust for inclusive endmarks in ex */ ! 537: n -= BLKSIZE; ! 538: ! 539: /* run the filter command */ ! 540: filter(m, n, o_equalprg, TRUE); ! 541: ! 542: redraw(MARK_UNSET, FALSE); ! 543: return m; ! 544: } ! 545: ! 546: ! 547: /* This runs some lines through a filter program */ ! 548: MARK v_filter(m, n) ! 549: MARK m, n; /* range of lines to shift */ ! 550: { ! 551: char cmdln[150]; /* a shell command line */ ! 552: ! 553: /* adjust for inclusive endmarks in ex */ ! 554: n -= BLKSIZE; ! 555: ! 556: if (vgets('!', cmdln, sizeof(cmdln)) > 0) ! 557: { ! 558: filter(m, n, cmdln, TRUE); ! 559: } ! 560: ! 561: redraw(MARK_UNSET, FALSE); ! 562: return m; ! 563: } ! 564: ! 565: ! 566: /* This function runs the ex "file" command to show the file's status */ ! 567: MARK v_status() ! 568: { ! 569: cmd_file(cursor, cursor, CMD_FILE, 0, ""); ! 570: return cursor; ! 571: } ! 572: ! 573: ! 574: /* This function runs the ":&" command to repeat the previous :s// */ ! 575: MARK v_again(m, n) ! 576: MARK m, n; ! 577: { ! 578: cmd_substitute(m, n - BLKSIZE, CMD_SUBAGAIN, TRUE, ""); ! 579: return cursor; ! 580: } ! 581: ! 582: ! 583: ! 584: /* This function switches to the previous file, if possible */ ! 585: MARK v_switch() ! 586: { ! 587: if (!*prevorig) ! 588: msg("No previous file"); ! 589: else ! 590: { strcpy(tmpblk.c, prevorig); ! 591: cmd_edit(cursor, cursor, CMD_EDIT, 0, tmpblk.c); ! 592: } ! 593: return cursor; ! 594: } ! 595: ! 596: /* This function does a tag search on a keyword */ ! 597: /*ARGSUSED*/ ! 598: MARK v_tag(keyword, m, cnt) ! 599: char *keyword; ! 600: MARK m; ! 601: long cnt; ! 602: { ! 603: /* move the cursor to the start of the tag name, where m is */ ! 604: cursor = m; ! 605: ! 606: /* perform the tag search */ ! 607: cmd_tag(cursor, cursor, CMD_TAG, 0, keyword); ! 608: ! 609: return cursor; ! 610: } ! 611: ! 612: #ifndef NO_EXTENSIONS ! 613: /* This function looks up a keyword by calling the helpprog program */ ! 614: /*ARGSUSED*/ ! 615: MARK v_keyword(keyword, m, cnt) ! 616: char *keyword; ! 617: MARK m; ! 618: long cnt; ! 619: { ! 620: int waswarn; ! 621: char cmdline[130]; ! 622: ! 623: move(LINES - 1, 0); ! 624: addstr("---------------------------------------------------------\n"); ! 625: clrtoeol(); ! 626: refresh(); ! 627: sprintf(cmdline, "%s %s", o_keywordprg, keyword); ! 628: waswarn = *o_warn; ! 629: *o_warn = FALSE; ! 630: suspend_curses(); ! 631: if (system(cmdline)) ! 632: { ! 633: addstr("<<< failed >>>\n"); ! 634: } ! 635: resume_curses(FALSE); ! 636: mode = MODE_VI; ! 637: redraw(MARK_UNSET, FALSE); ! 638: *o_warn = waswarn; ! 639: ! 640: return m; ! 641: } ! 642: ! 643: ! 644: ! 645: MARK v_increment(keyword, m, cnt) ! 646: char *keyword; ! 647: MARK m; ! 648: long cnt; ! 649: { ! 650: static sign; ! 651: char newval[12]; ! 652: long atol(); ! 653: ! 654: DEFAULT(1); ! 655: ! 656: /* get one more keystroke, unless doingdot */ ! 657: if (!doingdot) ! 658: { ! 659: sign = getkey(0); ! 660: } ! 661: ! 662: /* adjust the number, based on that second keystroke */ ! 663: switch (sign) ! 664: { ! 665: case '+': ! 666: case '#': ! 667: cnt = atol(keyword) + cnt; ! 668: break; ! 669: ! 670: case '-': ! 671: cnt = atol(keyword) - cnt; ! 672: break; ! 673: ! 674: case '=': ! 675: break; ! 676: ! 677: default: ! 678: return MARK_UNSET; ! 679: } ! 680: sprintf(newval, "%ld", cnt); ! 681: ! 682: ChangeText ! 683: { ! 684: change(m, m + strlen(keyword), newval); ! 685: } ! 686: ! 687: return m; ! 688: } ! 689: #endif ! 690: ! 691: ! 692: /* This function acts like the EX command "xit" */ ! 693: /*ARGSUSED*/ ! 694: MARK v_xit(m, cnt, key) ! 695: MARK m; /* ignored */ ! 696: long cnt; /* ignored */ ! 697: int key; /* must be a second 'Z' */ ! 698: { ! 699: /* if second char wasn't 'Z', fail */ ! 700: if (key != 'Z') ! 701: { ! 702: return MARK_UNSET; ! 703: } ! 704: ! 705: /* move the cursor to the bottom of the screen */ ! 706: move(LINES - 1, 0); ! 707: clrtoeol(); ! 708: ! 709: /* do the xit command */ ! 710: cmd_xit(m, m, CMD_XIT, FALSE, ""); ! 711: ! 712: /* return the cursor */ ! 713: return m; ! 714: } ! 715: ! 716: ! 717: /* This function undoes changes to a single line, if possible */ ! 718: MARK v_undoline(m) ! 719: MARK m; /* where we hope to undo the change */ ! 720: { ! 721: /* make sure we have the right line in the buffer */ ! 722: if (markline(m) != U_line) ! 723: { ! 724: return MARK_UNSET; ! 725: } ! 726: ! 727: /* fix it */ ! 728: ChangeText ! 729: { ! 730: strcat(U_text, "\n"); ! 731: change(MARK_AT_LINE(U_line), MARK_AT_LINE(U_line + 1), U_text); ! 732: } ! 733: ! 734: /* nothing in the buffer anymore */ ! 735: U_line = -1L; ! 736: ! 737: /* return, with the cursor at the front of the line */ ! 738: return m & ~(BLKSIZE - 1); ! 739: } ! 740: ! 741: ! 742: #ifndef NO_ERRLIST ! 743: MARK v_errlist(m) ! 744: MARK m; ! 745: { ! 746: cmd_errlist(m, m, CMD_ERRLIST, FALSE, ""); ! 747: return cursor; ! 748: } ! 749: #endif ! 750: ! 751: ! 752: #ifndef NO_AT ! 753: /*ARGSUSED*/ ! 754: MARK v_at(m, cnt, key) ! 755: MARK m; ! 756: long cnt; ! 757: int key; ! 758: { ! 759: int size; ! 760: ! 761: size = cb2str(key, tmpblk.c, BLKSIZE); ! 762: if (size <= 0 || size == BLKSIZE) ! 763: { ! 764: return MARK_UNSET; ! 765: } ! 766: ! 767: execmap(0, tmpblk.c, FALSE); ! 768: return cursor; ! 769: } ! 770: #endif ! 771: ! 772: ! 773: #ifdef SIGTSTP ! 774: MARK v_suspend() ! 775: { ! 776: cmd_suspend(MARK_UNSET, MARK_UNSET, CMD_SUSPEND, FALSE, ""); ! 777: return MARK_UNSET; ! 778: } ! 779: #endif ! 780: ! 781: ! 782: #ifndef NO_VISIBLE ! 783: /*ARGSUSED*/ ! 784: MARK v_start(m, cnt, cmd) ! 785: MARK m; /* starting point for a v or V command */ ! 786: long cnt; /* ignored */ ! 787: int cmd; /* either 'v' or 'V' */ ! 788: { ! 789: if (V_from) ! 790: { ! 791: V_from = MARK_UNSET; ! 792: } ! 793: else ! 794: { ! 795: V_from = m; ! 796: V_linemd = isupper(cmd); ! 797: } ! 798: return m; ! 799: } ! 800: #endif ! 801: ! 802: #ifndef NO_POPUP ! 803: # define MENU_HEIGHT 11 ! 804: # define MENU_WIDTH 23 ! 805: MARK v_popup(m, n) ! 806: MARK m, n; /* the range of text to change */ ! 807: { ! 808: int i; ! 809: int y, x; /* position where the window will pop up at */ ! 810: int key; /* keystroke from the user */ ! 811: int sel; /* index of the selected operation */ ! 812: static int dfltsel;/* default value of sel */ ! 813: static char *labels[11] = ! 814: { ! 815: "ESC cancel! ", ! 816: " d delete (cut) ", ! 817: " y yank (copy) ", ! 818: " p paste after ", ! 819: " P paste before ", ! 820: " > more indented ", ! 821: " < less indented ", ! 822: " = reformat ", ! 823: " ! external filter ", ! 824: " ZZ save & exit ", ! 825: " u undo previous " ! 826: }; ! 827: ! 828: /* try to position the menu near the cursor */ ! 829: x = physcol - (MENU_WIDTH / 2); ! 830: if (x < 0) ! 831: x = 0; ! 832: else if (x + MENU_WIDTH + 2 > COLS) ! 833: x = COLS - MENU_WIDTH - 2; ! 834: if (markline(cursor) < topline || markline(cursor) > botline) ! 835: y = 0; ! 836: else if (markline(cursor) + 1L + MENU_HEIGHT > botline) ! 837: y = (int)(markline(cursor) - topline) - MENU_HEIGHT; ! 838: else ! 839: y = (int)(markline(cursor) - topline) + 1L; ! 840: ! 841: /* draw the menu */ ! 842: for (sel = 0; sel < MENU_HEIGHT; sel++) ! 843: { ! 844: move(y + sel, x); ! 845: do_POPUP(); ! 846: if (sel == dfltsel) ! 847: qaddstr("-->"); ! 848: else ! 849: qaddstr(" "); ! 850: qaddstr(labels[sel]); ! 851: do_SE(); ! 852: } ! 853: ! 854: /* get a selection */ ! 855: move(y + dfltsel, x + 4); ! 856: for (sel = dfltsel; (key = getkey(WHEN_POPUP)) != '\\' && key != '\r'; ) ! 857: { ! 858: /* erase the selection arrow */ ! 859: move(y + sel, x); ! 860: do_POPUP(); ! 861: qaddstr(" "); ! 862: qaddstr(labels[sel]); ! 863: do_SE(); ! 864: ! 865: /* process the user's keystroke */ ! 866: if (key == 'j' && sel < MENU_HEIGHT - 1) ! 867: { ! 868: sel++; ! 869: } ! 870: else if (key == 'k' && sel > 0) ! 871: { ! 872: sel--; ! 873: } ! 874: else if (key == '\033') ! 875: { ! 876: sel = 0; ! 877: break; ! 878: } ! 879: else ! 880: { ! 881: for (i = 1; i < MENU_HEIGHT && labels[i][1] != key; i++) ! 882: { ! 883: } ! 884: if (i < MENU_HEIGHT) ! 885: { ! 886: sel = i; ! 887: break; ! 888: } ! 889: } ! 890: ! 891: /* redraw the arrow, possibly in a new place */ ! 892: move(y + sel, x); ! 893: do_POPUP(); ! 894: qaddstr("-->"); ! 895: qaddstr(labels[sel]); ! 896: do_SE(); ! 897: move(y + sel, x + 4); ! 898: } ! 899: ! 900: /* in most cases, the default selection is "paste after" */ ! 901: dfltsel = 3; ! 902: ! 903: /* perform the appropriate action */ ! 904: switch (sel) ! 905: { ! 906: case 0: ! 907: m = cursor; ! 908: dfltsel = 0; ! 909: break; ! 910: ! 911: case 1: /* delete (cut) */ ! 912: m = v_delete(m, n); ! 913: break; ! 914: ! 915: case 2: /* yank (copy) */ ! 916: m = v_yank(m, n); ! 917: break; ! 918: ! 919: case 3: /* paste after */ ! 920: m = v_paste(n, 1L, 'P'); ! 921: break; ! 922: ! 923: case 4: /* paste before */ ! 924: m = v_paste(m, 1L, 'P'); ! 925: dfltsel = 4; ! 926: break; ! 927: ! 928: case 5: /* more indented */ ! 929: m = v_rshift(m, n); ! 930: dfltsel = 5; ! 931: break; ! 932: ! 933: case 6: /* less indented */ ! 934: m = v_lshift(m, n); ! 935: dfltsel = 6; ! 936: break; ! 937: ! 938: case 7: /* reformat */ ! 939: m = v_reformat(m, n); ! 940: dfltsel = 7; ! 941: break; ! 942: ! 943: case 8: /* external filter */ ! 944: m = v_filter(m, n); ! 945: dfltsel = 0; ! 946: break; ! 947: ! 948: case 9: /* save & exit */ ! 949: /* get confirmation first */ ! 950: do ! 951: { ! 952: key = getkey(0); ! 953: } while (key != '\\' && key != 'Z' && key != '\r' /* good */ ! 954: && key != '\033'); /* bad */ ! 955: if (key != '\033') ! 956: { ! 957: m = v_xit(m, 0L, 'Z'); ! 958: } ! 959: break; ! 960: ! 961: case 10: /* undo previous */ ! 962: m = v_undo(m); ! 963: dfltsel = 9; ! 964: break; ! 965: } ! 966: ! 967: /* arrange for the menu to be erased (except "save & exit" doesn't care) ! 968: */ ! 969: if (sel != 9) ! 970: redraw(MARK_UNSET, FALSE); ! 971: ! 972: return m; ! 973: } ! 974: #endif /* undef NO_POPUP */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.