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