|
|
1.1 ! root 1: /* Copyright (c) 1981 Regents of the University of California */ ! 2: static char *sccsid = "@(#)ex_vmain.c 7.3 6/10/83"; ! 3: #include "ex.h" ! 4: #include "ex_tty.h" ! 5: #include "ex_vis.h" ! 6: ! 7: /* ! 8: * This is the main routine for visual. ! 9: * We here decode the count and possible named buffer specification ! 10: * preceding a command and interpret a few of the commands. ! 11: * Commands which involve a target (i.e. an operator) are decoded ! 12: * in the routine operate in ex_voperate.c. ! 13: */ ! 14: ! 15: #define forbid(a) { if (a) goto fonfon; } ! 16: ! 17: vmain() ! 18: { ! 19: register int c, cnt, i; ! 20: char esave[TUBECOLS]; ! 21: char *oglobp; ! 22: short d; ! 23: line *addr; ! 24: int ind, nlput; ! 25: int shouldpo = 0; ! 26: int onumber, olist, (*OPline)(), (*OPutchar)(); ! 27: ! 28: vch_mac = VC_NOTINMAC; ! 29: ! 30: /* ! 31: * If we started as a vi command (on the command line) ! 32: * then go process initial commands (recover, next or tag). ! 33: */ ! 34: if (initev) { ! 35: oglobp = globp; ! 36: globp = initev; ! 37: hadcnt = cnt = 0; ! 38: i = tchng; ! 39: addr = dot; ! 40: goto doinit; ! 41: } ! 42: ! 43: /* ! 44: * NB: ! 45: * ! 46: * The current line is always in the line buffer linebuf, ! 47: * and the cursor at the position cursor. You should do ! 48: * a vsave() before moving off the line to make sure the disk ! 49: * copy is updated if it has changed, and a getDOT() to get ! 50: * the line back if you mung linebuf. The motion ! 51: * routines in ex_vwind.c handle most of this. ! 52: */ ! 53: for (;;) { ! 54: /* ! 55: * Decode a visual command. ! 56: * First sync the temp file if there has been a reasonable ! 57: * amount of change. Clear state for decoding of next ! 58: * command. ! 59: */ ! 60: TSYNC(); ! 61: vglobp = 0; ! 62: vreg = 0; ! 63: hold = 0; ! 64: seenprompt = 1; ! 65: wcursor = 0; ! 66: Xhadcnt = hadcnt = 0; ! 67: Xcnt = cnt = 1; ! 68: splitw = 0; ! 69: if (i = holdupd) { ! 70: if (state == VISUAL) ! 71: ignore(peekkey()); ! 72: holdupd = 0; ! 73: /* ! 74: if (LINE(0) < ZERO) { ! 75: vclear(); ! 76: vcnt = 0; ! 77: i = 3; ! 78: } ! 79: */ ! 80: if (state != VISUAL) { ! 81: vcnt = 0; ! 82: vsave(); ! 83: vrepaint(cursor); ! 84: } else if (i == 3) ! 85: vredraw(WTOP); ! 86: else ! 87: vsync(WTOP); ! 88: vfixcurs(); ! 89: } ! 90: ! 91: /* ! 92: * Gobble up counts and named buffer specifications. ! 93: */ ! 94: for (;;) { ! 95: looptop: ! 96: #ifdef MDEBUG ! 97: if (trace) ! 98: fprintf(trace, "pc=%c",peekkey()); ! 99: #endif ! 100: if (isdigit(peekkey()) && peekkey() != '0') { ! 101: hadcnt = 1; ! 102: cnt = vgetcnt(); ! 103: forbid (cnt <= 0); ! 104: } ! 105: if (peekkey() != '"') ! 106: break; ! 107: ignore(getkey()), c = getkey(); ! 108: /* ! 109: * Buffer names be letters or digits. ! 110: * But not '0' as that is the source of ! 111: * an 'empty' named buffer spec in the routine ! 112: * kshift (see ex_temp.c). ! 113: */ ! 114: forbid (c == '0' || !isalpha(c) && !isdigit(c)); ! 115: vreg = c; ! 116: } ! 117: reread: ! 118: /* ! 119: * Come to reread from below after some macro expansions. ! 120: * The call to map allows use of function key pads ! 121: * by performing a terminal dependent mapping of inputs. ! 122: */ ! 123: #ifdef MDEBUG ! 124: if (trace) ! 125: fprintf(trace,"pcb=%c,",peekkey()); ! 126: #endif ! 127: op = getkey(); ! 128: maphopcnt = 0; ! 129: do { ! 130: /* ! 131: * Keep mapping the char as long as it changes. ! 132: * This allows for double mappings, e.g., q to #, ! 133: * #1 to something else. ! 134: */ ! 135: c = op; ! 136: op = map(c,arrows); ! 137: #ifdef MDEBUG ! 138: if (trace) ! 139: fprintf(trace,"pca=%c,",c); ! 140: #endif ! 141: /* ! 142: * Maybe the mapped to char is a count. If so, we have ! 143: * to go back to the "for" to interpret it. Likewise ! 144: * for a buffer name. ! 145: */ ! 146: if ((isdigit(c) && c!='0') || c == '"') { ! 147: ungetkey(c); ! 148: goto looptop; ! 149: } ! 150: if (!value(REMAP)) { ! 151: c = op; ! 152: break; ! 153: } ! 154: if (++maphopcnt > 256) ! 155: error("Infinite macro loop"); ! 156: } while (c != op); ! 157: ! 158: /* ! 159: * Begin to build an image of this command for possible ! 160: * later repeat in the buffer workcmd. It will be copied ! 161: * to lastcmd by the routine setLAST ! 162: * if/when completely specified. ! 163: */ ! 164: lastcp = workcmd; ! 165: if (!vglobp) ! 166: *lastcp++ = c; ! 167: ! 168: /* ! 169: * First level command decode. ! 170: */ ! 171: switch (c) { ! 172: ! 173: /* ! 174: * ^L Clear screen e.g. after transmission error. ! 175: */ ! 176: ! 177: /* ! 178: * ^R Retype screen, getting rid of @ lines. ! 179: * If in open, equivalent to ^L. ! 180: * On terminals where the right arrow key sends ! 181: * ^L we make ^R act like ^L, since there is no ! 182: * way to get ^L. These terminals (adm31, tvi) ! 183: * are intelligent so ^R is useless. Soroc ! 184: * will probably foul this up, but nobody has ! 185: * one of them. ! 186: */ ! 187: case CTRL(l): ! 188: case CTRL(r): ! 189: if (c == CTRL(l) || (KR && *KR==CTRL(l))) { ! 190: vclear(); ! 191: vdirty(0, vcnt); ! 192: } ! 193: if (state != VISUAL) { ! 194: /* ! 195: * Get a clean line, throw away the ! 196: * memory of what is displayed now, ! 197: * and move back onto the current line. ! 198: */ ! 199: vclean(); ! 200: vcnt = 0; ! 201: vmoveto(dot, cursor, 0); ! 202: continue; ! 203: } ! 204: vredraw(WTOP); ! 205: /* ! 206: * Weird glitch -- when we enter visual ! 207: * in a very small window we may end up with ! 208: * no lines on the screen because the line ! 209: * at the top is too long. This forces the screen ! 210: * to be expanded to make room for it (after ! 211: * we have printed @'s ick showing we goofed). ! 212: */ ! 213: if (vcnt == 0) ! 214: vrepaint(cursor); ! 215: vfixcurs(); ! 216: continue; ! 217: ! 218: /* ! 219: * $ Escape just cancels the current command ! 220: * with a little feedback. ! 221: */ ! 222: case ESCAPE: ! 223: beep(); ! 224: continue; ! 225: ! 226: /* ! 227: * @ Macros. Bring in the macro and put it ! 228: * in vmacbuf, point vglobp there and punt. ! 229: */ ! 230: case '@': ! 231: c = getesc(); ! 232: if (c == 0) ! 233: continue; ! 234: if (c == '@') ! 235: c = lastmac; ! 236: if (isupper(c)) ! 237: c = tolower(c); ! 238: forbid(!islower(c)); ! 239: lastmac = c; ! 240: vsave(); ! 241: CATCH ! 242: char tmpbuf[BUFSIZ]; ! 243: ! 244: regbuf(c,tmpbuf,sizeof(vmacbuf)); ! 245: macpush(tmpbuf, 1); ! 246: ONERR ! 247: lastmac = 0; ! 248: splitw = 0; ! 249: getDOT(); ! 250: vrepaint(cursor); ! 251: continue; ! 252: ENDCATCH ! 253: vmacp = vmacbuf; ! 254: goto reread; ! 255: ! 256: /* ! 257: * . Repeat the last (modifying) open/visual command. ! 258: */ ! 259: case '.': ! 260: /* ! 261: * Check that there was a last command, and ! 262: * take its count and named buffer unless they ! 263: * were given anew. Special case if last command ! 264: * referenced a numeric named buffer -- increment ! 265: * the number and go to a named buffer again. ! 266: * This allows a sequence like "1pu.u.u... ! 267: * to successively look for stuff in the kill chain ! 268: * much as one does in EMACS with C-Y and M-Y. ! 269: */ ! 270: forbid (lastcmd[0] == 0); ! 271: if (hadcnt) ! 272: lastcnt = cnt; ! 273: if (vreg) ! 274: lastreg = vreg; ! 275: else if (isdigit(lastreg) && lastreg < '9') ! 276: lastreg++; ! 277: vreg = lastreg; ! 278: cnt = lastcnt; ! 279: hadcnt = lasthad; ! 280: vglobp = lastcmd; ! 281: goto reread; ! 282: ! 283: /* ! 284: * ^U Scroll up. A count sticks around for ! 285: * future scrolls as the scroll amount. ! 286: * Attempt to hold the indentation from the ! 287: * top of the screen (in logical lines). ! 288: * ! 289: * BUG: A ^U near the bottom of the screen ! 290: * on a dumb terminal (which can't roll back) ! 291: * causes the screen to be cleared and then ! 292: * redrawn almost as it was. In this case ! 293: * one should simply move the cursor. ! 294: */ ! 295: case CTRL(u): ! 296: if (hadcnt) ! 297: vSCROLL = cnt; ! 298: cnt = vSCROLL; ! 299: if (state == VISUAL) ! 300: ind = vcline, cnt += ind; ! 301: else ! 302: ind = 0; ! 303: vmoving = 0; ! 304: vup(cnt, ind, 1); ! 305: vnline(NOSTR); ! 306: continue; ! 307: ! 308: /* ! 309: * ^D Scroll down. Like scroll up. ! 310: */ ! 311: case CTRL(d): ! 312: #ifdef TRACE ! 313: if (trace) ! 314: fprintf(trace, "before vdown in ^D, dot=%d, wdot=%d, dol=%d\n", lineno(dot), lineno(wdot), lineno(dol)); ! 315: #endif ! 316: if (hadcnt) ! 317: vSCROLL = cnt; ! 318: cnt = vSCROLL; ! 319: if (state == VISUAL) ! 320: ind = vcnt - vcline - 1, cnt += ind; ! 321: else ! 322: ind = 0; ! 323: vmoving = 0; ! 324: vdown(cnt, ind, 1); ! 325: #ifdef TRACE ! 326: if (trace) ! 327: fprintf(trace, "before vnline in ^D, dot=%d, wdot=%d, dol=%d\n", lineno(dot), lineno(wdot), lineno(dol)); ! 328: #endif ! 329: vnline(NOSTR); ! 330: #ifdef TRACE ! 331: if (trace) ! 332: fprintf(trace, "after vnline in ^D, dot=%d, wdot=%d, dol=%d\n", lineno(dot), lineno(wdot), lineno(dol)); ! 333: #endif ! 334: continue; ! 335: ! 336: /* ! 337: * ^E Glitch the screen down (one) line. ! 338: * Cursor left on same line in file. ! 339: */ ! 340: case CTRL(e): ! 341: if (state != VISUAL) ! 342: continue; ! 343: if (!hadcnt) ! 344: cnt = 1; ! 345: /* Bottom line of file already on screen */ ! 346: forbid(lineDOL()-lineDOT() <= vcnt-1-vcline); ! 347: ind = vcnt - vcline - 1 + cnt; ! 348: vdown(ind, ind, 1); ! 349: vnline(cursor); ! 350: continue; ! 351: ! 352: /* ! 353: * ^Y Like ^E but up ! 354: */ ! 355: case CTRL(y): ! 356: if (state != VISUAL) ! 357: continue; ! 358: if (!hadcnt) ! 359: cnt = 1; ! 360: forbid(lineDOT()-1<=vcline); /* line 1 already there */ ! 361: ind = vcline + cnt; ! 362: vup(ind, ind, 1); ! 363: vnline(cursor); ! 364: continue; ! 365: ! 366: ! 367: /* ! 368: * m Mark position in mark register given ! 369: * by following letter. Return is ! 370: * accomplished via ' or `; former ! 371: * to beginning of line where mark ! 372: * was set, latter to column where marked. ! 373: */ ! 374: case 'm': ! 375: /* ! 376: * Getesc is generally used when a character ! 377: * is read as a latter part of a command ! 378: * to allow one to hit rubout/escape to cancel ! 379: * what you have typed so far. These characters ! 380: * are mapped to 0 by the subroutine. ! 381: */ ! 382: c = getesc(); ! 383: if (c == 0) ! 384: continue; ! 385: ! 386: /* ! 387: * Markreg checks that argument is a letter ! 388: * and also maps ' and ` to the end of the range ! 389: * to allow '' or `` to reference the previous ! 390: * context mark. ! 391: */ ! 392: c = markreg(c); ! 393: forbid (c == 0); ! 394: vsave(); ! 395: names[c - 'a'] = (*dot &~ 01); ! 396: ncols[c - 'a'] = cursor; ! 397: anymarks = 1; ! 398: continue; ! 399: ! 400: /* ! 401: * ^F Window forwards, with 2 lines of continuity. ! 402: * Count repeats. ! 403: */ ! 404: case CTRL(f): ! 405: vsave(); ! 406: if (vcnt > 2) { ! 407: addr = dot + (vcnt - vcline) - 2 + (cnt-1)*basWLINES; ! 408: forbid(addr > dol); ! 409: dot = addr; ! 410: vcnt = vcline = 0; ! 411: } ! 412: vzop(0, 0, '+'); ! 413: continue; ! 414: ! 415: /* ! 416: * ^B Window backwards, with 2 lines of continuity. ! 417: * Inverse of ^F. ! 418: */ ! 419: case CTRL(b): ! 420: vsave(); ! 421: if (one + vcline != dot && vcnt > 2) { ! 422: addr = dot - vcline + 2 + (cnt-1)*basWLINES; ! 423: forbid (addr <= zero); ! 424: dot = addr; ! 425: vcnt = vcline = 0; ! 426: } ! 427: vzop(0, 0, '^'); ! 428: continue; ! 429: ! 430: /* ! 431: * z Screen adjustment, taking a following character: ! 432: * z<CR> current line to top ! 433: * z<NL> like z<CR> ! 434: * z- current line to bottom ! 435: * also z+, z^ like ^F and ^B. ! 436: * A preceding count is line to use rather ! 437: * than current line. A count between z and ! 438: * specifier character changes the screen size ! 439: * for the redraw. ! 440: * ! 441: */ ! 442: case 'z': ! 443: if (state == VISUAL) { ! 444: i = vgetcnt(); ! 445: if (i > 0) ! 446: vsetsiz(i); ! 447: c = getesc(); ! 448: if (c == 0) ! 449: continue; ! 450: } ! 451: vsave(); ! 452: vzop(hadcnt, cnt, c); ! 453: continue; ! 454: ! 455: /* ! 456: * Y Yank lines, abbreviation for y_ or yy. ! 457: * Yanked lines can be put later if no ! 458: * changes intervene, or can be put in named ! 459: * buffers and put anytime in this session. ! 460: */ ! 461: case 'Y': ! 462: ungetkey('_'); ! 463: c = 'y'; ! 464: break; ! 465: ! 466: /* ! 467: * J Join lines, 2 by default. Count is number ! 468: * of lines to join (no join operator sorry.) ! 469: */ ! 470: case 'J': ! 471: forbid (dot == dol); ! 472: if (cnt == 1) ! 473: cnt = 2; ! 474: if (cnt > (i = dol - dot + 1)) ! 475: cnt = i; ! 476: vsave(); ! 477: vmacchng(1); ! 478: setLAST(); ! 479: cursor = strend(linebuf); ! 480: vremote(cnt, join, 0); ! 481: notenam = "join"; ! 482: vmoving = 0; ! 483: killU(); ! 484: vreplace(vcline, cnt, 1); ! 485: if (!*cursor && cursor > linebuf) ! 486: cursor--; ! 487: if (notecnt == 2) ! 488: notecnt = 0; ! 489: vrepaint(cursor); ! 490: continue; ! 491: ! 492: /* ! 493: * S Substitute text for whole lines, abbrev for c_. ! 494: * Count is number of lines to change. ! 495: */ ! 496: case 'S': ! 497: ungetkey('_'); ! 498: c = 'c'; ! 499: break; ! 500: ! 501: /* ! 502: * O Create a new line above current and accept new ! 503: * input text, to an escape, there. ! 504: * A count specifies, for dumb terminals when ! 505: * slowopen is not set, the number of physical ! 506: * line space to open on the screen. ! 507: * ! 508: * o Like O, but opens lines below. ! 509: */ ! 510: case 'O': ! 511: case 'o': ! 512: vmacchng(1); ! 513: voOpen(c, cnt); ! 514: continue; ! 515: ! 516: /* ! 517: * C Change text to end of line, short for c$. ! 518: */ ! 519: case 'C': ! 520: if (*cursor) { ! 521: ungetkey('$'), c = 'c'; ! 522: break; ! 523: } ! 524: goto appnd; ! 525: ! 526: /* ! 527: * ~ Switch case of letter under cursor ! 528: */ ! 529: case '~': ! 530: { ! 531: char mbuf[4]; ! 532: setLAST(); ! 533: mbuf[0] = 'r'; ! 534: mbuf[1] = *cursor; ! 535: mbuf[2] = cursor[1]==0 ? 0 : ' '; ! 536: mbuf[3] = 0; ! 537: if (isalpha(mbuf[1])) ! 538: mbuf[1] ^= ' '; /* toggle the case */ ! 539: macpush(mbuf, 1); ! 540: } ! 541: continue; ! 542: ! 543: ! 544: /* ! 545: * A Append at end of line, short for $a. ! 546: */ ! 547: case 'A': ! 548: operate('$', 1); ! 549: appnd: ! 550: c = 'a'; ! 551: /* fall into ... */ ! 552: ! 553: /* ! 554: * a Appends text after cursor. Text can continue ! 555: * through arbitrary number of lines. ! 556: */ ! 557: case 'a': ! 558: if (*cursor) { ! 559: if (state == HARDOPEN) ! 560: putchar(*cursor); ! 561: cursor++; ! 562: } ! 563: goto insrt; ! 564: ! 565: /* ! 566: * I Insert at beginning of whitespace of line, ! 567: * short for ^i. ! 568: */ ! 569: case 'I': ! 570: operate('^', 1); ! 571: c = 'i'; ! 572: /* fall into ... */ ! 573: ! 574: /* ! 575: * R Replace characters, one for one, by input ! 576: * (logically), like repeated r commands. ! 577: * ! 578: * BUG: This is like the typeover mode of many other ! 579: * editors, and is only rarely useful. Its ! 580: * implementation is a hack in a low level ! 581: * routine and it doesn't work very well, e.g. ! 582: * you can't move around within a R, etc. ! 583: */ ! 584: case 'R': ! 585: /* fall into... */ ! 586: ! 587: /* ! 588: * i Insert text to an escape in the buffer. ! 589: * Text is arbitrary. This command reminds of ! 590: * the i command in bare teco. ! 591: */ ! 592: case 'i': ! 593: insrt: ! 594: /* ! 595: * Common code for all the insertion commands. ! 596: * Save for redo, position cursor, prepare for append ! 597: * at command and in visual undo. Note that nothing ! 598: * is doomed, unless R when all is, and save the ! 599: * current line in a the undo temporary buffer. ! 600: */ ! 601: vmacchng(1); ! 602: setLAST(); ! 603: vcursat(cursor); ! 604: prepapp(); ! 605: vnoapp(); ! 606: doomed = c == 'R' ? 10000 : 0; ! 607: if(FIXUNDO) ! 608: vundkind = VCHNG; ! 609: vmoving = 0; ! 610: CP(vutmp, linebuf); ! 611: ! 612: /* ! 613: * If this is a repeated command, then suppress ! 614: * fake insert mode on dumb terminals which looks ! 615: * ridiculous and wastes lots of time even at 9600B. ! 616: */ ! 617: if (vglobp) ! 618: hold = HOLDQIK; ! 619: vappend(c, cnt, 0); ! 620: continue; ! 621: ! 622: /* ! 623: * ^? An attention, normally a ^?, just beeps. ! 624: * If you are a vi command within ex, then ! 625: * two ATTN's will drop you back to command mode. ! 626: */ ! 627: case ATTN: ! 628: beep(); ! 629: if (initev || peekkey() != ATTN) ! 630: continue; ! 631: /* fall into... */ ! 632: ! 633: /* ! 634: * ^\ A quit always gets command mode. ! 635: */ ! 636: case QUIT: ! 637: /* ! 638: * Have to be careful if we were called ! 639: * g/xxx/vi ! 640: * since a return will just start up again. ! 641: * So we simulate an interrupt. ! 642: */ ! 643: if (inglobal) ! 644: onintr(); ! 645: /* fall into... */ ! 646: ! 647: #ifdef notdef ! 648: /* ! 649: * q Quit back to command mode, unless called as ! 650: * vi on command line in which case dont do it ! 651: */ ! 652: case 'q': /* quit */ ! 653: if (initev) { ! 654: vsave(); ! 655: CATCH ! 656: error("Q gets ex command mode, :q leaves vi"); ! 657: ENDCATCH ! 658: splitw = 0; ! 659: getDOT(); ! 660: vrepaint(cursor); ! 661: continue; ! 662: } ! 663: #endif ! 664: /* fall into... */ ! 665: ! 666: /* ! 667: * Q Is like q, but always gets to command mode ! 668: * even if command line invocation was as vi. ! 669: */ ! 670: case 'Q': ! 671: vsave(); ! 672: /* ! 673: * If we are in the middle of a macro, throw away ! 674: * the rest and fix up undo. ! 675: * This code copied from getbr(). ! 676: */ ! 677: if (vmacp) { ! 678: vmacp = 0; ! 679: if (inopen == -1) /* don't screw up undo for esc esc */ ! 680: vundkind = VMANY; ! 681: inopen = 1; /* restore old setting now that macro done */ ! 682: } ! 683: return; ! 684: ! 685: ! 686: /* ! 687: * ZZ Like :x ! 688: */ ! 689: case 'Z': ! 690: forbid(getkey() != 'Z'); ! 691: oglobp = globp; ! 692: globp = "x"; ! 693: vclrech(0); ! 694: goto gogo; ! 695: ! 696: /* ! 697: * P Put back text before cursor or before current ! 698: * line. If text was whole lines goes back ! 699: * as whole lines. If part of a single line ! 700: * or parts of whole lines splits up current ! 701: * line to form many new lines. ! 702: * May specify a named buffer, or the delete ! 703: * saving buffers 1-9. ! 704: * ! 705: * p Like P but after rather than before. ! 706: */ ! 707: case 'P': ! 708: case 'p': ! 709: vmoving = 0; ! 710: #ifdef notdef ! 711: forbid (!vreg && value(UNDOMACRO) && inopen < 0); ! 712: #endif ! 713: /* ! 714: * If previous delete was partial line, use an ! 715: * append or insert to put it back so as to ! 716: * use insert mode on intelligent terminals. ! 717: */ ! 718: if (!vreg && DEL[0]) { ! 719: forbid ((DEL[0] & (QUOTE|TRIM)) == OVERBUF); ! 720: vglobp = DEL; ! 721: ungetkey(c == 'p' ? 'a' : 'i'); ! 722: goto reread; ! 723: } ! 724: ! 725: /* ! 726: * If a register wasn't specified, then make ! 727: * sure there is something to put back. ! 728: */ ! 729: forbid (!vreg && unddol == dol); ! 730: /* ! 731: * If we just did a macro the whole buffer is in ! 732: * the undo save area. We don't want to put THAT. ! 733: */ ! 734: forbid (vundkind == VMANY && undkind==UNDALL); ! 735: vsave(); ! 736: vmacchng(1); ! 737: setLAST(); ! 738: i = 0; ! 739: if (vreg && partreg(vreg) || !vreg && pkill[0]) { ! 740: /* ! 741: * Restoring multiple lines which were partial ! 742: * lines; will leave cursor in middle ! 743: * of line after shoving restored text in to ! 744: * split the current line. ! 745: */ ! 746: i++; ! 747: if (c == 'p' && *cursor) ! 748: cursor++; ! 749: } else { ! 750: /* ! 751: * In whole line case, have to back up dot ! 752: * for P; also want to clear cursor so ! 753: * cursor will eventually be positioned ! 754: * at the beginning of the first put line. ! 755: */ ! 756: cursor = 0; ! 757: if (c == 'P') { ! 758: dot--, vcline--; ! 759: c = 'p'; ! 760: } ! 761: } ! 762: killU(); ! 763: ! 764: /* ! 765: * The call to putreg can potentially ! 766: * bomb since there may be nothing in a named buffer. ! 767: * We thus put a catch in here. If we didn't and ! 768: * there was an error we would end up in command mode. ! 769: */ ! 770: addr = dol; /* old dol */ ! 771: CATCH ! 772: vremote(1, vreg ? putreg : put, vreg); ! 773: ONERR ! 774: if (vreg == -1) { ! 775: splitw = 0; ! 776: if (op == 'P') ! 777: dot++, vcline++; ! 778: goto pfixup; ! 779: } ! 780: ENDCATCH ! 781: splitw = 0; ! 782: nlput = dol - addr + 1; ! 783: if (!i) { ! 784: /* ! 785: * Increment undap1, undap2 to make up ! 786: * for their incorrect initialization in the ! 787: * routine vremote before calling put/putreg. ! 788: */ ! 789: if (FIXUNDO) ! 790: undap1++, undap2++; ! 791: vcline++; ! 792: nlput--; ! 793: ! 794: /* ! 795: * After a put want current line first line, ! 796: * and dot was made the last line put in code ! 797: * run so far. This is why we increment vcline ! 798: * above and decrease dot here. ! 799: */ ! 800: dot -= nlput - 1; ! 801: } ! 802: #ifdef TRACE ! 803: if (trace) ! 804: fprintf(trace, "vreplace(%d, %d, %d), undap1=%d, undap2=%d, dot=%d\n", vcline, i, nlput, lineno(undap1), lineno(undap2), lineno(dot)); ! 805: #endif ! 806: vreplace(vcline, i, nlput); ! 807: if (state != VISUAL) { ! 808: /* ! 809: * Special case in open mode. ! 810: * Force action on the screen when a single ! 811: * line is put even if it is identical to ! 812: * the current line, e.g. on YP; otherwise ! 813: * you can't tell anything happened. ! 814: */ ! 815: vjumpto(dot, cursor, '.'); ! 816: continue; ! 817: } ! 818: pfixup: ! 819: vrepaint(cursor); ! 820: vfixcurs(); ! 821: continue; ! 822: ! 823: /* ! 824: * ^^ Return to previous file. ! 825: * Like a :e #, and thus can be used after a ! 826: * "No Write" diagnostic. ! 827: */ ! 828: case CTRL(^): ! 829: forbid (hadcnt); ! 830: vsave(); ! 831: ckaw(); ! 832: oglobp = globp; ! 833: if (value(AUTOWRITE)) ! 834: globp = "e! #"; ! 835: else ! 836: globp = "e #"; ! 837: goto gogo; ! 838: ! 839: /* ! 840: * ^] Takes word after cursor as tag, and then does ! 841: * tag command. Read ``go right to''. ! 842: */ ! 843: case CTRL(]): ! 844: grabtag(); ! 845: oglobp = globp; ! 846: globp = "tag"; ! 847: goto gogo; ! 848: ! 849: /* ! 850: * & Like :& ! 851: */ ! 852: case '&': ! 853: oglobp = globp; ! 854: globp = "&"; ! 855: goto gogo; ! 856: ! 857: /* ! 858: * ^G Bring up a status line at the bottom of ! 859: * the screen, like a :file command. ! 860: * ! 861: * BUG: Was ^S but doesn't work in cbreak mode ! 862: */ ! 863: case CTRL(g): ! 864: oglobp = globp; ! 865: globp = "file"; ! 866: gogo: ! 867: addr = dot; ! 868: vsave(); ! 869: goto doinit; ! 870: ! 871: #ifdef SIGTSTP ! 872: /* ! 873: * ^Z: suspend editor session and temporarily return ! 874: * to shell. Only works with Berkeley/IIASA process ! 875: * control in kernel. ! 876: */ ! 877: case CTRL(z): ! 878: forbid(dosusp == 0 || !ldisc); ! 879: vsave(); ! 880: oglobp = globp; ! 881: globp = "stop"; ! 882: goto gogo; ! 883: #endif ! 884: ! 885: /* ! 886: * : Read a command from the echo area and ! 887: * execute it in command mode. ! 888: */ ! 889: case ':': ! 890: forbid (hadcnt); ! 891: vsave(); ! 892: i = tchng; ! 893: addr = dot; ! 894: if (readecho(c)) { ! 895: esave[0] = 0; ! 896: goto fixup; ! 897: } ! 898: getDOT(); ! 899: /* ! 900: * Use the visual undo buffer to store the global ! 901: * string for command mode, since it is idle right now. ! 902: */ ! 903: oglobp = globp; strcpy(vutmp, genbuf+1); globp = vutmp; ! 904: doinit: ! 905: esave[0] = 0; ! 906: fixech(); ! 907: ! 908: /* ! 909: * Have to finagle around not to lose last ! 910: * character after this command (when run from ex ! 911: * command mode). This is clumsy. ! 912: */ ! 913: d = peekc; ungetchar(0); ! 914: if (shouldpo) { ! 915: /* ! 916: * So after a "Hit return..." ":", we do ! 917: * another "Hit return..." the next time ! 918: */ ! 919: pofix(); ! 920: shouldpo = 0; ! 921: } ! 922: CATCH ! 923: /* ! 924: * Save old values of options so we can ! 925: * notice when they change; switch into ! 926: * cooked mode so we are interruptible. ! 927: */ ! 928: onumber = value(NUMBER); ! 929: olist = value(LIST); ! 930: OPline = Pline; ! 931: OPutchar = Putchar; ! 932: #ifndef CBREAK ! 933: vcook(); ! 934: #endif ! 935: commands(1, 1); ! 936: if (dot == zero && dol > zero) ! 937: dot = one; ! 938: #ifndef CBREAK ! 939: vraw(); ! 940: #endif ! 941: ONERR ! 942: #ifndef CBREAK ! 943: vraw(); ! 944: #endif ! 945: copy(esave, vtube[WECHO], TUBECOLS); ! 946: ENDCATCH ! 947: fixol(); ! 948: Pline = OPline; ! 949: Putchar = OPutchar; ! 950: ungetchar(d); ! 951: globp = oglobp; ! 952: ! 953: /* ! 954: * If we ended up with no lines in the buffer, make ! 955: * a line, and don't consider the buffer changed. ! 956: */ ! 957: if (dot == zero) { ! 958: fixzero(); ! 959: sync(); ! 960: } ! 961: splitw = 0; ! 962: ! 963: /* ! 964: * Special case: did list/number options change? ! 965: */ ! 966: if (onumber != value(NUMBER)) ! 967: setnumb(value(NUMBER)); ! 968: if (olist != value(LIST)) ! 969: setlist(value(LIST)); ! 970: ! 971: fixup: ! 972: /* ! 973: * If a change occurred, other than ! 974: * a write which clears changes, then ! 975: * we should allow an undo even if . ! 976: * didn't move. ! 977: * ! 978: * BUG: You can make this wrong by ! 979: * tricking around with multiple commands ! 980: * on one line of : escape, and including ! 981: * a write command there, but its not ! 982: * worth worrying about. ! 983: */ ! 984: if (FIXUNDO && tchng && tchng != i) ! 985: vundkind = VMANY, cursor = 0; ! 986: ! 987: /* ! 988: * If we are about to do another :, hold off ! 989: * updating of screen. ! 990: */ ! 991: if (vcnt < 0 && Peekkey == ':') { ! 992: getDOT(); ! 993: shouldpo = 1; ! 994: continue; ! 995: } ! 996: shouldpo = 0; ! 997: ! 998: /* ! 999: * In the case where the file being edited is ! 1000: * new; e.g. if the initial state hasn't been ! 1001: * saved yet, then do so now. ! 1002: */ ! 1003: if (unddol == truedol) { ! 1004: vundkind = VNONE; ! 1005: Vlines = lineDOL(); ! 1006: if (!inglobal) ! 1007: savevis(); ! 1008: addr = zero; ! 1009: vcnt = 0; ! 1010: if (esave[0] == 0) ! 1011: copy(esave, vtube[WECHO], TUBECOLS); ! 1012: } ! 1013: ! 1014: /* ! 1015: * If the current line moved reset the cursor position. ! 1016: */ ! 1017: if (dot != addr) { ! 1018: vmoving = 0; ! 1019: cursor = 0; ! 1020: } ! 1021: ! 1022: /* ! 1023: * If current line is not on screen or if we are ! 1024: * in open mode and . moved, then redraw. ! 1025: */ ! 1026: i = vcline + (dot - addr); ! 1027: if (i < 0 || i >= vcnt && i >= -vcnt || state != VISUAL && dot != addr) { ! 1028: if (state == CRTOPEN) ! 1029: vup1(); ! 1030: if (vcnt > 0) ! 1031: vcnt = 0; ! 1032: vjumpto(dot, (char *) 0, '.'); ! 1033: } else { ! 1034: /* ! 1035: * Current line IS on screen. ! 1036: * If we did a [Hit return...] then ! 1037: * restore vcnt and clear screen if in visual ! 1038: */ ! 1039: vcline = i; ! 1040: if (vcnt < 0) { ! 1041: vcnt = -vcnt; ! 1042: if (state == VISUAL) ! 1043: vclear(); ! 1044: else if (state == CRTOPEN) { ! 1045: vcnt = 0; ! 1046: } ! 1047: } ! 1048: ! 1049: /* ! 1050: * Limit max value of vcnt based on $ ! 1051: */ ! 1052: i = vcline + lineDOL() - lineDOT() + 1; ! 1053: if (i < vcnt) ! 1054: vcnt = i; ! 1055: ! 1056: /* ! 1057: * Dirty and repaint. ! 1058: */ ! 1059: vdirty(0, LINES); ! 1060: vrepaint(cursor); ! 1061: } ! 1062: ! 1063: /* ! 1064: * If in visual, put back the echo area ! 1065: * if it was clobberred. ! 1066: */ ! 1067: if (state == VISUAL) { ! 1068: int sdc = destcol, sdl = destline; ! 1069: ! 1070: splitw++; ! 1071: vigoto(WECHO, 0); ! 1072: for (i = 0; i < TUBECOLS - 1; i++) { ! 1073: if (esave[i] == 0) ! 1074: break; ! 1075: vputchar(esave[i]); ! 1076: } ! 1077: splitw = 0; ! 1078: vgoto(sdl, sdc); ! 1079: } ! 1080: continue; ! 1081: ! 1082: /* ! 1083: * u undo the last changing command. ! 1084: */ ! 1085: case 'u': ! 1086: vundo(1); ! 1087: continue; ! 1088: ! 1089: /* ! 1090: * U restore current line to initial state. ! 1091: */ ! 1092: case 'U': ! 1093: vUndo(); ! 1094: continue; ! 1095: ! 1096: fonfon: ! 1097: beep(); ! 1098: vmacp = 0; ! 1099: inopen = 1; /* might have been -1 */ ! 1100: continue; ! 1101: } ! 1102: ! 1103: /* ! 1104: * Rest of commands are decoded by the operate ! 1105: * routine. ! 1106: */ ! 1107: operate(c, cnt); ! 1108: } ! 1109: } ! 1110: ! 1111: /* ! 1112: * Grab the word after the cursor so we can look for it as a tag. ! 1113: */ ! 1114: grabtag() ! 1115: { ! 1116: register char *cp, *dp; ! 1117: ! 1118: cp = vpastwh(cursor); ! 1119: if (*cp) { ! 1120: dp = lasttag; ! 1121: do { ! 1122: if (dp < &lasttag[sizeof lasttag - 2]) ! 1123: *dp++ = *cp; ! 1124: cp++; ! 1125: } while (isalpha(*cp) || isdigit(*cp) || *cp == '_'); ! 1126: *dp++ = 0; ! 1127: } ! 1128: } ! 1129: ! 1130: /* ! 1131: * Before appending lines, set up addr1 and ! 1132: * the command mode undo information. ! 1133: */ ! 1134: prepapp() ! 1135: { ! 1136: ! 1137: addr1 = dot; ! 1138: deletenone(); ! 1139: addr1++; ! 1140: appendnone(); ! 1141: } ! 1142: ! 1143: /* ! 1144: * Execute function f with the address bounds addr1 ! 1145: * and addr2 surrounding cnt lines starting at dot. ! 1146: */ ! 1147: vremote(cnt, f, arg) ! 1148: int cnt, (*f)(), arg; ! 1149: { ! 1150: register int oing = inglobal; ! 1151: ! 1152: addr1 = dot; ! 1153: addr2 = dot + cnt - 1; ! 1154: inglobal = 0; ! 1155: if (FIXUNDO) ! 1156: undap1 = undap2 = dot; ! 1157: (*f)(arg); ! 1158: inglobal = oing; ! 1159: if (FIXUNDO) ! 1160: vundkind = VMANY; ! 1161: vmcurs = 0; ! 1162: } ! 1163: ! 1164: /* ! 1165: * Save the current contents of linebuf, if it has changed. ! 1166: */ ! 1167: vsave() ! 1168: { ! 1169: char temp[LBSIZE]; ! 1170: ! 1171: CP(temp, linebuf); ! 1172: if (FIXUNDO && vundkind == VCHNG || vundkind == VCAPU) { ! 1173: /* ! 1174: * If the undo state is saved in the temporary buffer ! 1175: * vutmp, then we sync this into the temp file so that ! 1176: * we will be able to undo even after we have moved off ! 1177: * the line. It would be possible to associate a line ! 1178: * with vutmp but we assume that vutmp is only associated ! 1179: * with line dot (e.g. in case ':') above, so beware. ! 1180: */ ! 1181: prepapp(); ! 1182: strcLIN(vutmp); ! 1183: putmark(dot); ! 1184: vremote(1, yank, 0); ! 1185: vundkind = VMCHNG; ! 1186: notecnt = 0; ! 1187: undkind = UNDCHANGE; ! 1188: } ! 1189: /* ! 1190: * Get the line out of the temp file and do nothing if it hasn't ! 1191: * changed. This may seem like a loss, but the line will ! 1192: * almost always be in a read buffer so this may well avoid disk i/o. ! 1193: */ ! 1194: getDOT(); ! 1195: if (strcmp(linebuf, temp) == 0) ! 1196: return; ! 1197: strcLIN(temp); ! 1198: putmark(dot); ! 1199: } ! 1200: ! 1201: #undef forbid ! 1202: #define forbid(a) if (a) { beep(); return; } ! 1203: ! 1204: /* ! 1205: * Do a z operation. ! 1206: * Code here is rather long, and very uninteresting. ! 1207: */ ! 1208: vzop(hadcnt, cnt, c) ! 1209: bool hadcnt; ! 1210: int cnt; ! 1211: register int c; ! 1212: { ! 1213: register line *addr; ! 1214: ! 1215: if (state != VISUAL) { ! 1216: /* ! 1217: * Z from open; always like a z=. ! 1218: * This code is a mess and should be cleaned up. ! 1219: */ ! 1220: vmoveitup(1, 1); ! 1221: vgoto(outline, 0); ! 1222: ostop(normf); ! 1223: setoutt(); ! 1224: addr2 = dot; ! 1225: vclear(); ! 1226: destline = WECHO; ! 1227: zop2(Xhadcnt ? Xcnt : value(WINDOW) - 1, '='); ! 1228: if (state == CRTOPEN) ! 1229: putnl(); ! 1230: putNFL(); ! 1231: termreset(); ! 1232: Outchar = vputchar; ! 1233: ignore(ostart()); ! 1234: vcnt = 0; ! 1235: outline = destline = 0; ! 1236: vjumpto(dot, cursor, 0); ! 1237: return; ! 1238: } ! 1239: if (hadcnt) { ! 1240: addr = zero + cnt; ! 1241: if (addr < one) ! 1242: addr = one; ! 1243: if (addr > dol) ! 1244: addr = dol; ! 1245: markit(addr); ! 1246: } else ! 1247: switch (c) { ! 1248: ! 1249: case '+': ! 1250: addr = dot + vcnt - vcline; ! 1251: break; ! 1252: ! 1253: case '^': ! 1254: addr = dot - vcline - 1; ! 1255: forbid (addr < one); ! 1256: c = '-'; ! 1257: break; ! 1258: ! 1259: default: ! 1260: addr = dot; ! 1261: break; ! 1262: } ! 1263: switch (c) { ! 1264: ! 1265: case '.': ! 1266: case '-': ! 1267: break; ! 1268: ! 1269: case '^': ! 1270: forbid (addr <= one); ! 1271: break; ! 1272: ! 1273: case '+': ! 1274: forbid (addr >= dol); ! 1275: /* fall into ... */ ! 1276: ! 1277: case CR: ! 1278: case NL: ! 1279: c = CR; ! 1280: break; ! 1281: ! 1282: default: ! 1283: beep(); ! 1284: return; ! 1285: } ! 1286: vmoving = 0; ! 1287: vjumpto(addr, NOSTR, c); ! 1288: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.