Date: 7 MAY 1979 1259-PDT From: DEKLEER at PARC-MAXC2 Subject: file #2 To: miller at MIT-AI docDocumentation of an interface between EMACS and INTERLISP. Robert Boyer, August 1978 (MMCM provided the solutions to most of the hard problems.) 0. Advertisement Why would anyone want to use EMACS together with Interlisp? a. When you are typing to Interlisp, you are already using a text editor, one of the world's worst: it has only delete, control-U, control-W, and control-R (which works poorly). If you use EMACS, you get far more control over your type-in because you can arbitrarily backup and edit. But far more importantly, it becomes very difficult to make parenthesis mistakes: if you type line feed instead of carriage return, the next line is indented to the correct place; when you type a close parenthesis, you see displayed automatically the open parenthesis to which it corresponds. b. When you use EDITF, you have to keep doing P commands to see where you are and what you have done. That is probably just right for a 100 baud teletype. But it is silly for a 9600 baud display, with its ability to keep constantly before your eyes what you are working on. Until EMACS came, however, the only available display oriented editors working on Datamedia's were for text, not code. Working on LISP code with, say, TV or TVEDIT commands, is arguably worse than using EDITF which knows so much about the structure of LISP sexpressions. But EMACS is approximately as informed about the structure of LISP as is EDITF. And EMACS, besides keeping your work right before your eyes, is far better at the character and single parenthesis level than EDITF. Read about all the control-meta commands in the EMACS documentation. The TECO under EMACS really knows the syntax of LISP (including ', %, and "). 1. User's Guide To Use The Interface To use the interface, start LISP and load the file NEMACS.COM into LISP and call (START.EMACS). When that returns (it takes a cpu second or two), you can edit functions, variables, and property lists with EMACS. To edit a function, invoke the function CF on the name of the function (for example CF(FOO)). The function definition is written into the EMACS buffer surrounded in a (DEFINEQ...). The virtual buffer boundaries are narrowed to the contents of the definition. You are placed in EMACS, where you may edit away. To return to LISP, type meta-z. But first put point at the beginning of the "(DEFINEQ", which can usually be gotten to by control-meta-a or control-<. When you return to LISP nothing has yet happened to your function. But if you execute the function E. (that's E followed by a period to remind you of the TECO point) of no arguments (e.g. "E.]"), then the (modified) DEFINEQ is executed. When you return to LISP, your display is refreshed to contain some of the text it held before the descent into CF. You may resume ordinary LISP interaction now, or you can call CF on another function and it will also be inserted in the buffer (and you will be put down into EMACS again). Again you edit, exit with meta-z, and then you can execute E. if you want. If you wish to pop up to LISP in the middle of an edit, then type meta-z and return to EMACS by invoking (DOWN). To edit a variable, use CV. To edit a property list, use CP. The foregoing is all you need to know to edit. It may be useful to know a little more. To get rid of an EMACS interface, call (FLUSH.EMACS). To get EMACS to insert into its buffer anything you want, simply write to the file that is the value of the variable EMACS.TEMP.FILE. Then call (DOWN) and the stuff written to the temp file will appear in the buffer at the end (as with the A command). The virtual buffer is narrowed to the text that is inserted. (If nothing has been written to EMACS.TEMP.FILE since the last return to LISP, (DOWN) simply returns you to the state in which you last left EMACS. are returned to lisp. If you execute E.], then the sexp Repeated E.]'s will evaluate through the buffer. If you want to read from the buffer yourself, feel free: the file is named EMACS.MAP.FILE. Upon return to LISP, the file pointer of EMACS.MAP.FILE is set to the point of the EMACS buffer. Warning: never close EMACS.TEMP.FILE or EMACS.MAP.FILE "by hand." Use FLUSH.EMACS to get rid of them. CLOSEALL() will not close them, but CLOSEF and CLOSEALL(T) will. A dribble file is used by the interface to refresh the screen. If you are using DRIBBLE when you start using NEMACS, or if you start using DRIBBLE after you start using NEMACS, then the screen refreshment will not occur. If you call (DOWN T), then instead of being inserted, the text that would have been inserted upon entry to EMACS is executed (as TECO code, of course). 2. Guide to the implementation. START.EMACS creates a fork (via SUBSYS) and opens up two files, the values of the variables EMACS.MAP.FILE and EMACS.TEMP.FILE. EMACS is passed the instruction MMLOAD LIBINTERMACSFSEXIT via the FJ (RSCAN) command. The library INTERMACS contains several EMACS ^R commands. The library initialization initializes the communication between the two forks. The EMACS fork handle is the CAR of LASTEMACS. Whenever control is passed to the EMACS fork, (by a call to DOWN), a teco macro in FS SUPERIOR is invoked, given a single numeric argument. The number's absolute value is the file pointer of EMACS.TEMP.FILE at the time of descent. If the number is positive, then the FSSUPERIOR macro inserts the contents of EMACS.TEMP.FILE (up to the file pointer) at the end of the buffer, narrows the virtual buffer boundaries to the test inserted, and refreshes the screen. If the arg is negative, the stuff that would have been inserted is macroed (in q-register a). Nothing happens if the arg is 0 except that the screen is refreshed. When the FSSUPERIOR macro exits, you are in ordinary EMACS control-r mode. Before returning to LISP, the command meta-z closes the gap. Upon return to LISP, we make sure that every page of the current EMACS buffer is PMAPed into a page of EMACS.MAP.FILE (the same page numbers for both). We further set the variables EMACS.BEG, EMACS.PT, and EMACS.Z to the appropriate numbers so that they can serve as file pointers into EMACS.MAP.FILE for the beginning, point, and end of the EMACS buffer. We set the file pointer of EMACS.MAP.FILE to EMACS.PT. That's why E. reads from point. But you can read anywhere from EMACS.BEG to EMACS.Z. You should read with EMACS.READ.TABLE (or a modification thereof that leaves the handling of control-c the same) to catch reading past the end of the buffer by mistake. We place a sequence of four characters (space, control-c, double quote mark, control-c) at the bottom of the buffer (and delete them upon return) to catch unbalanced expression reading. The file pointer of EMACS.TEMP.FILE is set to 0 upon return to LISP. The full details of the hook EMACS has for doing these things are found in the last few pages of TECORD. 3. Miscellaneous Notes on IO The variable DUMP.SCREEN.AMOUNT controls how many characters of the dribble file are written to the screen after returning to LISP from EMACS. Nothing is written unless DISPLAYTERMFLG is non-NIL. In the file INTERMACS, the delimiter table (what's in ..D) is fixed to reflect Interlisp (as opposed to the default Maclisp). In particular, all control characters except tab, carriage return, and line feed are "OTHER" (i.e. just like ordinary alphabetic letters); % quotes the next character, " delimits strings (it takes the place of | in Maclisp, which has no strings (on DEC machines), but uses | to delimit weird atoms); /,|, and ; have no significance. Square brackets mean nothing to EMACS. If you (SETQ #RPARS NIL), then the Interlisp pretty printer (PRINTDEF) will not use square brackets for parentheses, even during MAKEFILE. You can still type them in to LISP. But you should set #RPARS (in your init file, perhaps) because often CF gets the text of a function from your files, where MAKEFILE might have written square brackets. The function would still be editable in EMACS, but the parenthesis commands of EMACS would not respect the square brackets. When you are down in EMACS, you can pretty print expressions in two ways. ^R Format Code (on control-meta-g, which may be entered by typing hold-g) will pretty print the expression after point. It works well on small expressions, less well on large. On large expressions, (particularly the on the result of editing previously reasonably formatted expressions), ^R Indent Sexp (control-meta-q) works well. The reason it works well is that it inserts no carriage returns at all, but merely fixes the number of leading spaces on each line. ^R Format Code is a version of the ITS grinder modified to know about %, ", etc. If you set NORMALCOMMENTSFLG to NIL and if you print to EMACS.TEMP.FILE yourself, be sure to readjust PRETTYPRINTMACROS by consing (* . GETTCOMMENT) on or you'll get your comments mapped into the EMACS temp file. If you set NORMALCOMMENTSFLG to NIL and if you read from EMACS.MAP.FILE yourself, then you should bind NORMALCOMMENTSFLG to NIL during the read. When typing into EMACS, your close parentheses will cause the cursor to bounce back to the balancing open parentheses. The cursor will stay there 1 second or until you type another character. To suppress this feature, execute 0m.vLISP ) Hack$ in a minibuffer. To get a longer delay, use the integral number of seconds you want instead of 0. To get bouncing to occur only when the corresponding open parenthesis is on the screen, use the negative of the number of seconds. 4. Specification of the Interlisp commands START.EMACS[] creates a new fork containing the EMACS editor and returns to LISP. DOWN[NEGATE.ARG.FLG] passes control to the EMACS fork. If negate.arg.flg is NIL, then EMACS will insert at the end of the buffer everything in the file EMACS.TEMP.FILE from 0 to the current file pointer. If there is something to insert, then the virtual buffer boundaries are narrowed to what is inserted. (The buffer boundaries can be widened to the whole buffer with ^R Set Bound Full (on control-x-w)). The screen is refreshed. If negate.arg.flg is non-NIL the text that would have been inserted is put in q-register a and executed. All of the following commands that descend to EMACS do so through calls to DOWN. Upon return to LISP, the file pointer of EMACS.TEMP.FILE is set to 0. The screen is refreshed with the last DUMP.SCREEN.AMOUNT characters from the in the dribble file. All the pages of EMACS containing the current EMACS buffer are mapped into the file EMACS.MAP.FILE. EMACS.BEG, EMACS.PT, EMACS.Z, and EMACS.MODIFF are set to the corresponding values in the buffer block (see TECORD). EMACS.PT is an appropriate file pointer to use to read from EMACS.MAP.FILE starting at the point. The file pointer of EMACS.MAP.FILE is set to EMACS.PT. An error is caused if EMACS returns to LISP without first closing the gap. (The proper return is via meta-z, but 1F? FSEXIT is sufficient if you want to do it yourself.) E.[] executes the sexpression starting at the current point in the EMACS buffer. The execution is recorded as an event on the history list just as if it had been typed into the top level read-print-eval loop. The appearance of the execution on the dribble file is "faked" by printing it to a shallow depth so that when the screen is refreshed, it looks vaguely like you typed something in. But the event is really there, so that ??, REDO, UNDO, etc. all work. E![N] executes sexpressions starting at the current point in the EMACS buffer using E. (above). If N is a number, then N sexpressions are read and executed. If N is NIL, then all the sexpressions in the buffer after point are executed. CF[FNNAME] writes the definition of a function into the end of the EMACS buffer and dives down to EMACS with point at the beginning of the insertion. The definition is inside a DEFINEQ and hence suitable for later execution with E.[]. The definition of the function is fetched much the way that EDITF does except that no spelling correction is attempted. In particular, if fnname is NIL, lastword is used. If fnname has an expr definition, the unadvised, unbroken version is used. If fn does not have a expr definition but does have an EXPR property, that is used. Otherwise, the definition of the function in the first file said to contain it is used. (Using WHEREIS to find it and using filemaps to get it quickly into the EMACS buffer without going through LISP). When CF returns, the function has not been changed at all; to cause the redefinition, use E., E!, (or C-M-Y from TECO). CV[X] writes a variable name and definition inside an RPAQQ into the EMACS buffer at the end and descends to EMACS. The variable has not been affected when you return to LISP; to cause the resetting, use E., E!, (or C-M-Y from TECO). CP[X] writes a litatom and its property list inside a SETPROPLIST into the EMACS buffer at the end and descends to EMACS. The property list has not been changed when you return to EMACS; to set the property list, use E., E!, (or C-M-Y from TECO). TECO[STR] runs the lower level EMACS on the result of PRIN1ing STR and then exits. For example, TECO(HK) clear the EMACS buffer and returns to LISP. EDIT.DRIBBLE.FILE[] runs EMACS on the Lisp dribble file in a buffer called DRIBBLE. INFO[] runs the INFO program. 5. The commands available in the EMACS fork. Besides the ordinary control-meta commands that are part of EMACS and the linefeed and LISP ) hack that come with EMACS lisp mode, there are a few other commands useful in the Interlisp EMACS interface. Meta-z runs the macro ^R Exit to LISP. Simply returns control to LISP after control has been passed to EMACS by DOWN (or CF, CV, or CP which call DOWN). Closes the gap so that LISP can read from the buffer. Places the sequence space, control-c, ", control-c at the end of the buffer to stop reading beyond the end of the buffer. If the new release of TOPS-20 permits the effective setting of the end of file pointer for a file without the necessity of closing it, these characters will not be inserted (eventually). Control-p runs the macro ^R Print to Level. Prints into a second window what EDITF prints for the P command. Useful if the current sexpression is bigger than a screen full. To get rid of a second window, you can call ^R One Window, which is hung on ^X-1. Control-meta-? runs the macro ^R ARGLIST. Prints into a second window the arglist of the function after point (or after the ( after point if there is one.) On a datamedia, this command is entered by typing hold (control-_) followed by ?. To get rid of a second window, you can call ^R One Window, which is hung on ^X-1. Control-meta-y runs the macro ^R UP EVAL. Does an exit up to lisp and then E.'s the expression after point and retfrom's DOWN. Approximately identical to meta-z followed by E. Currently, the above 3 commands all work by calling ^R Exit to LISP with an argument. That argument is deposited in AC3 when EMACS exits. When DOWN gets control back, it retrieves the argument and sassoc's down the alist EMACS.RETURN.ALIST. If a pair is found, then the CDR of the pair is LISPXEVALED. After evaluation, or if no pair is found, DOWN refreshes the LISP screen and exits. Control-meta-y, for example does the E. and then retfrom's DOWN. ------- ^_ Date: 7 MAY 1979 1257-PDT From: DEKLEER at PARC-MAXC2 Subject: file #1 To: miller at MIT-AI (FILECREATED "28-Dec-78 17:58:56" NEMACS..144 28948 changes to: GETDEF CF EMACS.GETDEF NEMACSFNS previous date: "28-Dec-78 17:44:56" NEMACS..143) (PRETTYCOMPRINT NEMACSCOMS) (RPAQQ NEMACSCOMS ((FNS * NEMACSFNS) (VARS * NEMACSVARS) (P (PUTD (QUOTE SUBSYS0) (VIRGINFN (QUOTE SUBSYS)))) (ADDVARS (ERRORTYPELST (16 (COND ((AND (NEQ (QUOTE NOBIND) (GETATOMVAL (QUOTE EMACS.MAP.FILE))) (EQ (CADR ERRORMESS) EMACS.MAP.FILE)) (ERROR "End of EMACS buffer!")) ((AND (NEQ (QUOTE NOBIND) (GETATOMVAL (QUOTE EMACS.TEMP.FILE))) (EQ (CADR ERRORMESS) EMACS.TEMP.FILE)) (ERROR "End of EMACS temporary file!"))))) ) (DECLARE: DONTEVAL@LOAD DOEVAL@COMPILE DONTCOPY COMPILERVARS (ADDVARS (NLAMA) (NLAML) (LAMA))))) (RPAQQ NEMACSFNS (,, BINARYMODE CF CP CV DISPLAY.IN.ECHO.AND.DIVE DOWN DUMP.SCREEN DUMPX DUMPX1 DWN E! E. EDIT.DRIBBLE.FILE EMACS. EMACS.?= EMACS.GETDEF EMACS.P EMACS.PP EMACS.RETURN ENABLE.CONTROL.C.CAPABILITY FLUSH.EMACS GET.EMACS.BUFFER HK INFO MAKE.QUOTE MAP.BYTES MAP.PROCESS.TO.FILE PAGE.OF.BYTE PUTSTRING READ.AC SET.EMACS.VARS SETUP.FANCY.DRIBBLE SFCOC START.EMACS STIW SUBSYS1 SUBSYS2 TECO WRITE.RSCAN)) (DEFINEQ (,, (LAMBDA (X Y) (LOGOR (LLSH X 18) Y))) (BINARYMODE (LAMBDA NIL (JSYS 72 65 (LOGAND (LOGXOR (LLSH 1 6) -1) (JSYS 71 65 NIL NIL 2))) (* We turn off B29 in the JFN Mode Word of the current output device. If the user is in ASCII mode, this puts him in Binary mode, which is what is required by EMACS.) NIL)) (CF (LAMBDA (NAME) (* Gets the definition of a function and dives down to EMACS. Like Teitelman's EDITF, CF uses LASTWORD if given NIL. The unbroken, unadvised version of the function is obtained. If the function is compiled, we check first for an EXPR. Otherwise we try to get it from the first file that contains it.) (EMACS.GETDEF NAME))) (CP (LAMBDA (X) (* Like EDITP, it dives down to EMACS with the property list of a litatom to edit.) (COND ((NULL X) (SETQ X LASTWORD) (PRINT LASTWORD T))) (COND ((AND X (LITATOM X)) (PRIN3 "(SETPROPLIST " EMACS.TEMP.FILE) (PRIN4 (KWOTE X) EMACS.TEMP.FILE) (SPACES 1 EMACS.TEMP.FILE) (DUMPX (LIST (QUOTE QUOTE) (GETPROPLIST X))) (PRIN3 ") " EMACS.TEMP.FILE) (DOWN)) (T (ERROR "No editable property list: " X))))) (CV (LAMBDA (X) (* Like EDITV, it dives down to EMACS with the value of a variable to edit.) (COND ((NULL X) (SETQ X LASTWORD) (PRINT LASTWORD T))) (COND ((NEQ (GETTOPVAL X) (QUOTE NOBIND)) (PRIN3 "(RPAQQ " EMACS.TEMP.FILE) (PRIN4 X EMACS.TEMP.FILE) (SPACES 1 EMACS.TEMP.FILE) (DUMPX (GETTOPVAL X)) (PRIN3 ") " EMACS.TEMP.FILE) (DOWN)) (T (ERROR X " has no value."))))) (DISPLAY.IN.ECHO.AND.DIVE (LAMBDA (LIST) (PRIN3 "MM^R Two Windows MMSELECT BUFFERPRINT HK I" EMACS.TEMP.FILE) (PRIN3 (APPLY (FUNCTION CONCAT) LIST) EMACS.TEMP.FILE) (PRIN3 " 0J QWINDOW 2 SIZE-3%"N 3-QWINDOW 2 SIZEMM^R GROW WINDOW' MM^R OTHER WINDOW MM& MULTI-WINDOW REFRESH" EMACS.TEMP.FILE) (RETEVAL (QUOTE DOWN) (QUOTE (DOWN T))))) (DOWN (LAMBDA (NEGATE.ARG.FLG) (* This is the main function of the EMACS interface for diving down to EMACS. Once START.EMACS has been called, DOWN may be called at any time to enter EMACS. Meta-z will exit from EMACS and return to down. When DOWN invokes EMACS, it passes to EMACS a number whose absolute value is the current file pointer of the file EMACS.TEMP.FILE. The number is passed to a teco macro in FSSUPERIOR which is invoked when the EMACS gains control. If the argument to DOWN is NIL, then the current file pointer is passed and EMACS simply inserts the text at the end of the buffer. If DOWN is given the argument T, then the negative of the current file pointer is passed. EMACS takes a negative number to be the instruction to insert that much text, put it into q-register a, delete the text and macro A. Thus, if you simply want to insert some text into the EMACS buffer, just print that text into EMACS.TEMP.FILE and call (DOWN). But if you want a fancier event to occur when EMACS gains control, then print teco code to EMACS.TEMP.FILE and then call (DOWN T).) (PROG (TEMP) (SETQ TEMP (GETFILEPTR EMACS.TEMP.FILE)) (CLOSER EMACS.ARG.LOC (COND (NEGATE.ARG.FLG (IMINUS TEMP)) (T TEMP))) (* EMACS.ARG.LOC is a location in a page of lisp that is identical to the spot that FSSUPERIOR looks for its argument. See the last few pages of TECORD.) (SETFILEPTR EMACS.TEMP.FILE 0) (JSYS 41 65 CLEAR.SCREEN.NUMBER) (* See DUMP.SCREEN.) (SETQ LASTEMACS (SUBSYS2 LASTEMACS NIL NIL (QUOTE START) T)) (GET.EMACS.BUFFER) LOOP(COND ((NOT (ZEROP EMACS.EXTRAC)) (PRIN1 " Illegal exit from EMACS. Exit from EMACS only with meta-Z. (The gap is not closed.) Returning to EMACS. " T) (DISMISS 3000) (SETQ LASTEMACS (SUBSYS2 LASTEMACS NIL NIL NIL NIL)) (GO LOOP))) (EMACS.RETURN) (DUMP.SCREEN DUMP.SCREEN.AMOUNT)))) (DUMP.SCREEN (LAMBDA (N) (PROG (TEMP TEMP1) (COND ((AND DISPLAYTERMFLG (EQ (DRIBBLEFILE) FANCY.DRIBBLE.FILE)) (* We ship out to the terminal a 30, which will cause the screen to clear. We don't PRIN1 it because we do not want it to get into the dribble file. Then we flash up onto the scrren the last page or so of text that appeared on the screen during LISP.) (JSYS 41 65 CLEAR.SCREEN.NUMBER) (SETQ TEMP (GETEOFPTR FANCY.DRIBBLE.FILE)) (SETQ TEMP1 (IDIFFERENCE TEMP N)) (COND ((LESSP TEMP1 0) (SETQ TEMP1 0))) (COPYBYTES FANCY.DRIBBLE.FILE T TEMP1 TEMP)))))) (DUMPX (LAMBDA (X) (COND ((AND (LISTP X) (EQ (CAR X) (QUOTE DEFINEQ)) (LISTP (CDR X)) (NULL (CDDR X)) (LISTP (CADR X)) (LISTP (CDADR X)) (NULL (CDDADR X))) (PRIN3 "(DEFINEQ (" EMACS.TEMP.FILE) (PRIN4 (CAADR X) EMACS.TEMP.FILE) (PRIN3 " " EMACS.TEMP.FILE) (DUMPX1 (CAR (CDADR X))) (PRIN3 ")) " EMACS.TEMP.FILE)) (T (DUMPX1 X))))) (DUMPX1 (LAMBDA (X DEF) (* We write X into EMACS.TEMP.FILE using the pretty print algorithm on PPR. We set the LINELENGTH to 79 because EMACS stupidly causes wraparound at 80 (instead of 81). The GETCOMMENT stuff causes lisp comments that are currently mapped out (because NORMALCOMMENTSFLG is NIL) to get sent down to EMACS.) (RESETFORM (LINELENGTH 79) (RESETFORM (OUTFILE EMACS.TEMP.FILE) (PROGN (COND ((GETD (QUOTE PPRIND)) (PROG ((FORCEIN 1000)) (PPRIND X 0 0 (QUOTE ( (* . GETCOMMENT) (QUOTE . MAKE.QUOTE))))) ) (T (PROG ((PRETTYPRINTMACROS (CONS (QUOTE (* . GETCOMMENT)) PRETTYPRINTMACROS))) (PRINTDEF X 0 DEF))))))))) (DWN (LAMBDA NIL (SETFILEPTR EMACS.TEMP.FILE 0) (PRIN3 " " EMACS.TEMP.FILE) (DOWN))) (E! (LAMBDA (N) (COND ((NUMBERP N) (FOR I FROM 1 TO N DO (E.))) (T (PROG (OLDLOC) LOOP(SETQ OLDLOC (GETFILEPTR EMACS.MAP.FILE)) (WHILE (SYNTAXP (CHCON1 (PEEKC EMACS.MAP.FILE)) (QUOTE SEPR) EMACS.READ.TABLE) DO (READC EMACS.MAP.FILE)) (COND ((LESSP (GETFILEPTR EMACS.MAP.FILE) (DIFFERENCE EMACS.Z 4)) (SETFILEPTR EMACS.MAP.FILE OLDLOC) (E.) (GO LOOP)) (T (RETURN)))))) (PACKC (QUOTE (8))))) (E. (LAMBDA NIL (* This function is for calling after DOWN has returned. It causes the lisp sexpression after point in the EMACS buffer to be read and evaluated. Actually, the form is evaluated with LISPXEVAL so that it becomes (somewhat) undoable, just as if you had literally typed it into lisp.) (PROG (TEMP) (SETQ TEMP (PROG ((NORMALCOMMENTSFLG T)) (RETURN (READ EMACS.MAP.FILE EMACS.READ.TABLE)) (* We must make lisp read in the comments because text in the buffer is very likely to get deleted or edited.) )) (PROMPTCHAR (QUOTE _) NIL LISPXHISTORY) (RESETFORM (PRINTLEVEL (QUOTE (3 . 4))) (PRINT TEMP T)) (SETQ TEMP (LISPXEVAL TEMP)) (RESETFORM (PRINTLEVEL (QUOTE (3 . 4))) (PRINT TEMP T)) (RETURN TEMP)) (PACKC (QUOTE (8))))) (EDIT.DRIBBLE.FILE (LAMBDA NIL (DRIBBLE (IOFILE (DRIBBLE)) T T) (PRIN3 "MMSelect BufferDRIBBLE ER" EMACS.TEMP.FILE) (PRIN3 FANCY.DRIBBLE.FILE EMACS.TEMP.FILE) (PRIN3 "HK ^A ZJ -1MM^R New Window" EMACS.TEMP.FILE) (DOWN T))) (EMACS. (LAMBDA NIL (DUMP.SCREEN DUMP.SCREEN.AMOUNT) (RETFROM (QUOTE DOWN) (E.)))) (EMACS.?= (LAMBDA NIL (PROG (NAME) (COND ((EQ (SETQ NAME (RATOM EMACS.MAP.FILE EMACS.READ.TABLE)) (QUOTE %()) (SETQ NAME (RATOM EMACS.MAP.FILE EMACS.READ.TABLE)))) (DISPLAY.IN.ECHO.AND.DIVE (COND ((GETD NAME) (CONS NAME (CONS "[" (NCONC1 (COND ((NLISTP (ARGLIST NAME)) (LIST (ARGLIST NAME))) (T (FOR ARGLIST ON (ARGLIST NAME) JOIN (CONS (CAR ARGLIST) (COND ((NULL (CDR ARGLIST)) NIL) (T (CONS "," NIL))))))) "]")))) (T (LIST "Not a function."))))))) (EMACS.GETDEF (LAMBDA (NAME) (* Gets the definition of a litatom, as described in CF.) (PROG (DEF FILE SPOT MAP WHEREIS) (COND ((NULL NAME) (SETQ NAME LASTWORD) (PRINT LASTWORD T))) (SETQ DEF (VIRGINFN NAME)) (COND ((LISTP DEF) (DUMPX (LIST (QUOTE DEFINEQ) (LIST NAME DEF))) (RETURN (DOWN)))) (COND ((GETP NAME (QUOTE EXPR)) (DUMPX (LIST (QUOTE DEFINEQ) (LIST NAME (GETP NAME (QUOTE EXPR))))) (RETURN (DOWN)))) (COND ((SETQ FILE (CAR (WHEREIS NAME))) (COND ((SETQ MAP (GETP FILE (QUOTE FILEMAP)))) (T (LOADFNS NIL (CDAR (GETP FILE (QUOTE FILEDATES))) T NIL) (SETQ MAP (GETP FILE (QUOTE FILEMAP))))) (COND ((SETQ SPOT (ASSOC NAME (CDDR (CADADR (GETP FILE (QUOTE FILEMAP))) ))) (SETQ FILE (CDAR (GETP FILE (QUOTE FILEDATES)))) (PRINT FILE T) (PRIN3 "[0E[FNE]ZJ.U0 I(DEFINEQ " EMACS.TEMP.FILE) (PRIN3 "ER" EMACS.TEMP.FILE) (PRIN3 FILE EMACS.TEMP.FILE) (PRIN3 " " EMACS.TEMP.FILE) (PRIN3 (CADR SPOT) EMACS.TEMP.FILE) (PRIN3 "FSIFACCESS" EMACS.TEMP.FILE) (PRIN3 (DIFFERENCE (CDDR SPOT) (CADR SPOT)) EMACS.TEMP.FILE) (PRIN3 "FY I) 0FSDVERSION Q0J .,ZFSBOUNDARIES F+ 0:F :F " EMACS.TEMP.FILE) (RETURN (DOWN T))) (T (ERROR "No Definition Found For" NAME)))) (T (ERROR "No Definition Found. " NAME)))))) (EMACS.P (LAMBDA NIL (PRIN3 "MM^R Two Windows MMSELECT BUFFERPRINT HK I" EMACS.TEMP.FILE) (PROG ((PLVLFILEFLG T)) (RESETFORM (PRINTLEVEL EMACS.P.PRINT.LEVEL) (PRIN3 (PROG ((NORMALCOMMENTSFLG T)) (RETURN (READ EMACS.MAP.FILE EMACS.READ.TABLE))) EMACS.TEMP.FILE))) (PRIN3 " 0J QWINDOW 2 SIZE-3%"N 3-QWINDOW 2 SIZEMM^R GROW WINDOW' MM^R OTHER WINDOW MM& MULTI-WINDOW REFRESH" EMACS.TEMP.FILE) (RETEVAL (QUOTE DOWN) (QUOTE (DOWN T))))) (EMACS.PP (LAMBDA NIL (SETFILEPTR EMACS.MAP.FILE EMACS.BEGV) (PROG (OLDLOC TEMP (NORMALCOMMENTSFLG T)) LOOP(SETQ OLDLOC (GETFILEPTR EMACS.MAP.FILE)) (WHILE (SYNTAXP (CHCON1 (PEEKC EMACS.MAP.FILE)) (QUOTE SEPR) EMACS.READ.TABLE) DO (READC EMACS.MAP.FILE)) (COND ((LESSP (GETFILEPTR EMACS.MAP.FILE) (DIFFERENCE EMACS.Z 4)) (SETFILEPTR EMACS.MAP.FILE OLDLOC) (SETQ TEMP (NLSETQ (READ EMACS.MAP.FILE EMACS.READ.TABLE)) ) (COND ((NULL TEMP) (PRIN1 "Unbalanced Sexpression! " T) (DISMISS 3000) (SETFILEPTR EMACS.TEMP.FILE 0) (RETEVAL (QUOTE DOWN) (QUOTE (DOWN)))) (T (DUMPX (CAR TEMP)) (TERPRI EMACS.TEMP.FILE) (TERPRI EMACS.TEMP.FILE))) (GO LOOP)) (T (RETEVAL (QUOTE DOWN) (QUOTE (DOWN)))))) (PACKC (QUOTE (8))))) (EMACS.RETURN (LAMBDA NIL (EVAL (CDR (SASSOC EMACS.FSEXIT.ARG EMACS.RETURN.ALIST))))) (ENABLE.CONTROL.C.CAPABILITY (LAMBDA NIL (JSYS 105 OURPROCESS 0 (,, 131072 0)))) (FLUSH.EMACS (LAMBDA NIL (* This function gets rid of the EMACS fork and closes the 3 files that EMACS uses.) (COND ((FIXP (CAR (GETATOMVAL (QUOTE LASTEMACS)))) (KFORK (CAR (GETATOMVAL (QUOTE LASTEMACS)))))) (COND ((AND (NEQ (QUOTE NOBIND) (GETATOMVAL (QUOTE EMACS.MAP.FILE))) (LITATOM EMACS.MAP.FILE) (OPENP EMACS.MAP.FILE)) (CLOSEF EMACS.MAP.FILE))) (COND ((AND (NEQ (QUOTE NOBIND) (GETATOMVAL (QUOTE EMACS.TEMP.FILE))) (LITATOM EMACS.TEMP.FILE) (OPENP EMACS.TEMP.FILE)) (CLOSEF EMACS.TEMP.FILE))) (COND ((AND (NEQ (QUOTE NOBIND) (GETATOMVAL (QUOTE FANCY.DRIBBLE.FILE))) (LITATOM FANCY.DRIBBLE.FILE) (OPENP FANCY.DRIBBLE.FILE)) (DRIBBLE NIL))) (NLSETQ (RELBLK (VAG OUR.BLOCK.START) EMACS.BLK.SIZE)) (NLSETQ (RELBLK (VAG EMACS.AC.BLK.START) 1)))) (GET.EMACS.BUFFER (LAMBDA NIL (* We assume we have just returned from EMACS and that the gap has been closed (with 1F?). We find out where the beginning and end and point of the current buffer are and we make sure that every page of the buffer is mapped into EMACS.MAP.FILE so we can read it with lisp READ.) (SET.EMACS.VARS) (MAP.BYTES EMACS.BEG EMACS.Z) (COND ((GREATERP EMACS.Z EMACS.MAP.FILE.EOF) (SETFILEPTR EMACS.MAP.FILE EMACS.Z) (SETQ EMACS.MAP.FILE.EOF EMACS.Z))) (SETFILEPTR EMACS.MAP.FILE EMACS.PT))) (HK (LAMBDA NIL (TECO "HK"))) (INFO (LAMBDA NIL (TECO "MMINFO"))) (MAKE.QUOTE (LAMBDA (X) (COND ((AND (LISTP (CDR X)) (LITATOM (CADR X)) (NULL (CDDR X))) (PACK* (QUOTE ') (CADR X))) (T (CONS (QUOTE QUOTE) (CDR X)))))) (MAP.BYTES (LAMBDA (START END) (FOR I FROM (PAGE.OF.BYTE START) TO (PAGE.OF.BYTE END) DO (COND ((MEMBER I MAPPED.PAGES)) (T (MAP.PROCESS.TO.FILE (CAR LASTEMACS) I EMACS.MAP.FILE.JFN) (SETQ MAPPED.PAGES (CONS I MAPPED.PAGES))))))) (MAP.PROCESS.TO.FILE (LAMBDA (PROCESS PAGE JFN) (* We make a page of PROCESS to a page of EMACS.TEMP.FILE and then map it back into the process. Future changes to the process page or file page affect the other (immediately).) (JSYS 46 (,, PROCESS PAGE) (,, JFN PAGE) (,, 61440 0)) (JSYS 46 (,, JFN PAGE) (,, PROCESS PAGE) (,, 61440 0)))) (PAGE.OF.BYTE (LAMBDA (BYTE) (PROG (QUO REM) (SETQ QUO (IQUOTIENT BYTE 5)) (SETQ REM (IREMAINDER BYTE 5)) (RETURN (LLSH (COND ((ZEROP REM) (ADD1 QUO)) (T QUO)) -11Q))))) (PUTSTRING (LAMBDA (STR ADDR) (* We write the bytes in STR starting a ADDR 5 bytes (of 7 bits each) to a word with a 0 bit at the end. We make sure that a 0 byte is added at the end. In fact, the last word ends with 0 bytes.) (UNTIL (GREATERP CHAR (ADD1 (NCHARS STR))) BIND LOC FIRST (SETQ LOC ADDR) BIND WORD BIND CHAR FIRST (SETQ CHAR 1) DO (SETQ WORD 0) (FOR J FROM 1 TO 5 DO (SETQ WORD (LLSH WORD 7)) (SETQ WORD (LOGOR WORD (COND ((GREATERP CHAR (NCHARS STR)) 0) (T (CHCON1 (NTHCHAR STR CHAR)))))) (SETQ CHAR (ADD1 CHAR))) (CLOSER LOC (LLSH WORD 1)) (SETQ LOC (ADD1 LOC))) ADDR)) (READ.AC (LAMBDA (ACN PROCESS) (JSYS 113 PROCESS EMACS.AC.BLK.START) (OPENR (LOGOR EMACS.AC.BLK.START ACN)))) (SET.EMACS.VARS (LAMBDA NIL (* Sets LISP variables to the contents of the EMACS buffer block (as documented in TECORD).) (SETQ EMACS.BEG (OPENR EMACS.BEG.LOC)) (SETQ EMACS.BEGV (OPENR EMACS.BEGV.LOC)) (SETQ EMACS.PT (OPENR EMACS.PT.LOC)) (SETQ EMACS.ZV (OPENR EMACS.ZV.LOC)) (SETQ EMACS.Z (OPENR EMACS.Z.LOC)) (SETQ EMACS.EXTRAC (OPENR EMACS.EXTRAC.LOC)) (SETQ EMACS.MODIFF (OPENR EMACS.MODIFF.LOC)) (SETQ EMACS.FSEXIT.ARG (READ.AC 3 (CAR LASTEMACS))))) (SETUP.FANCY.DRIBBLE (LAMBDA NIL (* To refresh the screen upon returning to LISP, we use the dribble file to find out what was recently typed. We first open the file with IOFILE. Kindly, DRIBBLE lets us get away with that, because if you first open a dribble file, you can't open it for read later.) (COND ((DRIBBLEFILE) (SETQ FANCY.DRIBBLE.FILE (CONS NIL NIL))) (T (SETQ FANCY.DRIBBLE.FILE (OUTPUT (OUTFILE (QUOTE LISP.DRIBBLE.-1;T)))) (CLOSEF FANCY.DRIBBLE.FILE) (IOFILE FANCY.DRIBBLE.FILE) (DRIBBLE FANCY.DRIBBLE.FILE T T))))) (SFCOC (LAMBDA (TUPLE) (PROG1 (LIST (JSYS 74 4 NIL NIL 2) (JSYS 74 4 NIL NIL 3)) (COND (TUPLE (JSYS 75 4 (CAR TUPLE) (CADR TUPLE))))))) (START.EMACS (LAMBDA NIL (PROG (TEMP NAME RSCAN.BLK) (* When we read from the EMACS buffer, we are sure (provided we exited with meta z) that the buffer ends with the sequence space, control-c, double quote mark, control-c. We set up a read table that causes an error upon encountering a control-c in the file. The extra control-c and double quote mark handle the case that we are inside a string read. All this to prevent reading beyond the end of the emacs buffer. If we could set the eof mark of EMACS.MAP.FILE, we would. But there is no way we know to do that. If the buffer had been large, the eof mark could conceivably been far beyond where the buffer we are reading now ends, and consequently, it is possible that LISP might read a long time before stopping.) (SETQ EMACS.READ.TABLE (COPYREADTABLE FILERDTBL)) (SETSYNTAX 3 (QUOTE (MACRO IMMEDIATE (LAMBDA (FL RDTBL) (ERROR "End of EMACS buffer!")))) EMACS.READ.TABLE) (SETSYNTAX (QUOTE ') (GETSYNTAX (QUOTE ') (GETREADTABLE T)) EMACS.READ.TABLE) (* Since the user will naturally type in single quote marks, we want them to get turned into QUOTE's. Unfortunately, INTERLISP does not do that when reading from a file (with the default FILEREADTBL.)) (COND (LASTEMACS (FLUSH.EMACS))) (* Our first step is always to get rid of any EMACS fork and associated files around.) (SETQ EMACS.TEMP.FILE (OUTPUT (OUTFILE (QUOTE EMACS.TEMP.-1;T) ))) (* EMACS.TEMP.FILE will be the file to which we print in lisp and from which EMACS reads (via FSSUPERIOR).) (SETFILEPTR EMACS.TEMP.FILE MAX.EMACS.INPUT) (SPACES 1 EMACS.TEMP.FILE) (CLOSEF EMACS.TEMP.FILE) (IOFILE EMACS.TEMP.FILE) (* We IOFILE the temp file so that we can write it and EMACS can read it.) (SETQ NAME (MKATOM (SIXBIT (JSYS 127)))) (* We are going to SETNM and want to restore.) (SETNM (QUOTE LISP)) (SETQ RSCAN.BLK (LOC (GETBLK 1))) (* We now put into the RSCAN area a string that EMACS will execute when it is fired up. The string that EMACS obtains via FJ is the string put into the RSCAN minus the first word. EMACS executes the TECO code after the first altmode in the JCL returned by FJ. This execution is coded in EMACS.INIT.) (WRITE.RSCAN "EMACS MMLOAD LIBINTERMACSFSEXIT") (SETQ LASTEMACS (SUBSYS2 (QUOTE SYS:EMACS.EXE) NIL NIL NIL NIL)) (COND ((NEQ NAME (QUOTE LISP)) (SETNM NAME))) (* We dive down to EMACS.) (SETQ EMACS.AC.BLK.START (LOC (GETBLK 1))) (SETQ EMACS.BUFFER.BLOCK (READ.AC 2 (CAR LASTEMACS))) (* AC2 contains the beginning of EMACS' buffer block. See TECORD.) (COND ((EQP (LLSH EMACS.BUFFER.BLOCK -9) (LLSH (PLUS EMACS.BUFFER.BLOCK 9) -9)) (SETQ EMACS.BLK.SIZE 1)) (T (SETQ EMACS.BLK.SIZE 2))) (* We aim to map in the EMACS buffer block into LISP so that we can see what's gone on down there and so that we can give an arg to FSSUPERIOR. We may need one page or two depending upon where the buffer lies.) (SETQ OUR.BLOCK.START (LOC (GETBLK EMACS.BLK.SIZE))) (* We grab a block (or two) from LISP and save (the boxed) start.) (FOR VAR IN (QUOTE (EMACS.BEG.LOC EMACS.BEGV.LOC EMACS.PT.LOC EMACS.GPT.LOC EMACS.ZV.LOC EMACS.Z.LOC EMACS.EXTRAC.LOC EMACS.RESTART.LOC EMACS.ARG.LOC EMACS.MODIFF.LOC)) AS I FROM 0 DO (SET VAR (PLUS I (LOGOR OUR.BLOCK.START (LOGAND 511 EMACS.BUFFER.BLOCK)) ))) (* We set the values of variables to be the location (in lisp) of the EMACS buffer block contents.) (* Now map the EMACS buffer block page (s) in.) (JSYS 46 (,, (CAR LASTEMACS) (LLSH EMACS.BUFFER.BLOCK -9)) (,, OURPROCESS (LLSH OUR.BLOCK.START -9)) (,, 53248 0)) (COND ((EQP EMACS.BLK.SIZE 2) (JSYS 46 (,, (CAR LASTEMACS) (ADD1 (LLSH EMACS.BUFFER.BLOCK -9))) (,, OURPROCESS (ADD1 (LLSH OUR.BLOCK.START -9))) (,, 53248 0)))) (* We may have to map in two pages.) (* Now we put the entry vector for EMACS at the end of the buffer block. When we start up the fork again with SUBSYS1 (which calls SUBSYS) we will ask for the process to be STARTed. This causes the control to go the FSSUPERIOR, since the entry vector is sitting at the location one is supposed to commence to get FSSUPERIOR fired up.) (JSYS 132 (CAR LASTEMACS) (,, 1 (PLUS EMACS.BUFFER.BLOCK 7))) (SETQ EMACS.MAP.FILE (OUTPUT (OUTFILE (QUOTE EMACS.MAP.-1;T))) ) (* EMACS.MAP.FILE is the file into which we will PMAP the buffer pages of EMACS. We read from that file to get the value of the edits performed.) (CLOSEF EMACS.MAP.FILE) (IOFILE EMACS.MAP.FILE) (* We have to have the map file open for read and for write. Only way to do this in LISP is to first create a file and then close it and then open it with IOFILE.) (SETQ EMACS.MAP.FILE.EOF 0) (* In order to avoid LISP causing an unjustified EOF error when reading from the buffer, we must before reading make sure that the EOF is beyond the end of the buffer. We achieve the effect with SETFILEPOINTER. To avoid needless calls of GETEOFPTR and SETFILEPTR we keep track of the maximum we have set the EOF pointer to.) (SETQ EMACS.MAP.FILE.JFN (OPNJFN EMACS.MAP.FILE)) (SETQ MAPPED.PAGES NIL) (* MAPPED.PAGES is a list of the EMACS process that we have mapped into EMACS.MAP.FILE.) (ECHOCONTROL CLEAR.SCREEN.NUMBER (QUOTE REAL)) (* A real 36Q on a datamedia clears the screen and puts the cursor at the top.) (SETUP.FANCY.DRIBBLE) (* We need the RSCAN block no more.) (RELBLK (VAG RSCAN.BLK) 1) (TERPRI T) (WHENCLOSE EMACS.MAP.FILE (QUOTE CLOSEALL) (QUOTE NO)) (WHENCLOSE EMACS.TEMP.FILE (QUOTE CLOSEALL) (QUOTE NO)) (RETURN NIL)))) (STIW (LAMBDA (W) (PROG1 (JSYS 123 -5 NIL NIL 2) (COND (W (JSYS 124 -5 W)))))) (SUBSYS1 (LAMBDA (THREE INCOMFILE OUTCOMFILE ENTRYPOINTFLG BINARYMODE) (* Interlisp's SUBSYS does not work when the process started up fiddles with the terminal interrupt words, the control character output control, and the binary/ascii mode word. SUBSYS1 tries to do the job right by returning a triple containing the lower process handle, the coc, and the tiw. Also, an extra arg permits the forcing of entry into binary mode when the lower process is restarted. (A call in SUBSYS to SFMOD prevents us from determining whether the lower process was in binary mode.) Clearly, someone should do SUBSYS right. SUBSYS0 is just the unadvised version of SUBSYS.) (PROG (FORK TIW COC) (COND ((LITATOM THREE) (ENABLE.CONTROL.C.CAPABILITY) (SETQ FORK THREE) (SETQ TIW (STIW)) (SETQ COC (SFCOC))) (T (SETQ FORK (CAR THREE)) (SETQ TIW (CADR THREE)) (SETQ COC (CADDR THREE)))) (RETURN (RESETFORM (STIW TIW) (RESETFORM (SFCOC COC) (PROGN (COND (BINARYMODE (BINARYMODE))) (LIST (SUBSYS0 FORK INCOMFILE OUTCOMFILE ENTRYPOINTFLG) (STIW) (SFCOC))))))))) (SUBSYS2 (LAMBDA (THREE INCOMFILE OUTCOMFILE ENTRYPOINTFLG BINARYMODE) (PROG (FORKTHREE) (SETQ FORKTHREE (SUBSYS1 THREE INCOMFILE OUTCOMFILE ENTRYPOINTFLG BINARYMODE)) CONTROL-C-LOOP (COND ((NOT (ZEROP (LOGAND 17179869184 (JSYS 93 (CAR FORKTHREE) NIL NIL 2)))) (* True if and only if EMACS was exited with a control-c.) (JSYS 120) (DISMISS 1000) (* We dismiss to permit the operating system to arrange for the left half of ac1 returned by RFSTS on the EMACS fork to be 2 instead of 0.0 This is a horrible hack that is necessitated by a poor implementation of RFSTS.) (SETQ FORKTHREE (SUBSYS1 FORKTHREE NIL NIL NIL T)) (GO CONTROL-C-LOOP)) (T (RETURN FORKTHREE)))))) (TECO (LAMBDA (MESS) (PROG (DISPLAYTERMFLG) (PRIN3 " F+ 0:F :F " EMACS.TEMP.FILE) (PRIN3 MESS EMACS.TEMP.FILE) (PRIN3 " MM^R Exit To LISP" EMACS.TEMP.FILE) (DOWN T)))) (WRITE.RSCAN (LAMBDA (STR) (PUTSTRING STR RSCAN.BLK) (* RSCAN) (JSYS 320 (LOGOR (LLSH 147904 18) RSCAN.BLK)))) ) (RPAQQ NEMACSVARS ((DUMP.SCREEN.AMOUNT 500) EMACS.P.PRINT.LEVEL EMACS.RETURN.ALIST OURPROCESS MAX.EMACS.INPUT (LASTEMACS NIL) (CLEAR.SCREEN.NUMBER 30) (BL (CHARACTER CLEAR.SCREEN.NUMBER)))) (RPAQ DUMP.SCREEN.AMOUNT 500) (RPAQQ EMACS.P.PRINT.LEVEL (2 . 7)) (RPAQQ EMACS.RETURN.ALIST ((1000 EMACS.) (1001 EMACS.?=) (1002 EMACS.P) (1003 EMACS.PP))) (RPAQQ OURPROCESS 131072) (RPAQQ MAX.EMACS.INPUT 896000) (RPAQ LASTEMACS NIL) (RPAQ CLEAR.SCREEN.NUMBER 30) (RPAQ BL (CHARACTER CLEAR.SCREEN.NUMBER)) (PUTD (QUOTE SUBSYS0) (VIRGINFN (QUOTE SUBSYS))) (ADDTOVAR ERRORTYPELST (16 (COND ((AND (NEQ (QUOTE NOBIND) (GETATOMVAL (QUOTE EMACS.MAP.FILE))) (EQ (CADR ERRORMESS) EMACS.MAP.FILE)) (ERROR "End of EMACS buffer!")) ((AND (NEQ (QUOTE NOBIND) (GETATOMVAL (QUOTE EMACS.TEMP.FILE))) (EQ (CADR ERRORMESS) EMACS.TEMP.FILE)) (ERROR "End of EMACS temporary file!") )))) (DECLARE: DONTEVAL@LOAD DOEVAL@COMPILE DONTCOPY COMPILERVARS (ADDTOVAR NLAMA ) (ADDTOVAR NLAML ) (ADDTOVAR LAMA ) ) (DECLARE: DONTCOPY (FILEMAP (NIL (1372 27740 (,, 1384 . 1438) (BINARYMODE 1442 . 1759) (CF 1763 . 2153) (CP 2157 . 2661) (CV 2665 . 3114) (DISPLAY.IN.ECHO.AND.DIVE 3118 . 3519) (DOWN 3523 . 5680) (DUMP.SCREEN 5684 . 6361) (DUMPX 6365 . 6776) (DUMPX1 6780 . 7628) (DWN 7632 . 7737) (E! 7741 . 8240) (E. 8244 . 9179) (EDIT.DRIBBLE.FILE 9183 . 9449) (EMACS. 9453 . 9555) (EMACS.?= 9559 . 10183) (EMACS.GETDEF 10187 . 11763) (EMACS.P 11767 . 12305) ( EMACS.PP 12309 . 13187) (EMACS.RETURN 13191 . 13284) ( ENABLE.CONTROL.C.CAPABILITY 13288 . 13376) (FLUSH.EMACS 13380 . 14280) ( GET.EMACS.BUFFER 14284 . 14870) (HK 14874 . 14911) (INFO 14915 . 14960) (MAKE.QUOTE 14964 . 15169) (MAP.BYTES 15173 . 15448) ( MAP.PROCESS.TO.FILE 15452 . 15850) (PAGE.OF.BYTE 15854 . 16088) ( PUTSTRING 16092 . 16794) (READ.AC 16798 . 16920) (SET.EMACS.VARS 16924 . 17448) (SETUP.FANCY.DRIBBLE 17452 . 18065) (SFCOC 18069 . 18234) ( START.EMACS 18238 . 25086) (STIW 25090 . 25188) (SUBSYS1 25192 . 26482) (SUBSYS2 26486 . 27353) (TECO 27357 . 27584) (WRITE.RSCAN 27588 . 27737) )))) STOP ------- ^_ Date: 7 MAY 1979 1312-PDT From: DEKLEER at PARC-MAXC2 Subject: file #3 To: miller at MIT-AI !* -*-TECO-*- *! !~Filename~:! !Commands for Interlisp interface! INTERMACS !Grind Sexp:! !C Grind the sexp after the pointer. A modification of the MIT Grind Sexp that recognizes that in Interlisp, % quotes a character, " starts a long string, and ; has no significance. Uses QMiser Column to decide where to start using "Miser" format, and QFill Column as the page width to aim for. Saves the old sexp on the kill ring.! 1:< FDL R !* Find the next list.! F[VB F[VZ FL FSBOUND !* Narrow bounds to that list.! F=MODELISP"N OConfirm' z-b-1000"g !Confirm! ^FTDo_you_really_want_to_Grind_this_s-expression?_(Y_or_N): FI :FC - Y(  FS Echo Display C FS Echo Display)"N '' Z: M(M.M &_Save_Region_and_Query) !* No arg so no query, just save region.! W J [2 [3 !*** Now normalize the expression; put it into the form PRIN1 would print.! [D 128*5,32:ID !* In QD make a dispatch that! 11.*5:F D -D :M2 !* turns any whitespace into a single space,! 15.*5:F D RK :M2 !* deletes CRLFs and the indentation after them,! 12.*5:F D -D :M2 %*5:F D C !* Handle %'s and "'s right.! "*5:F D R ^FLL (*5:F D :M3 !* Make sure no whitespace follows ('s and ''s! !"! '*5:F D :M3 )*5:F D R M3 C !* or precedes )'s.! :; D> 32I :; D> HD J .( 0FS VBW 0L .FS VB )J !* Include all of line, up to (, after B,! !* so that FS HPOS is accurate.! !*** Now decode the grinding parameters.! FS WIDTH-10[W !* Figure the width to aim at! FS WIDTH*2/3[C !* and the comment column.! 0FO ..Q Fill_Column F"N UW QWUC' -1FO ..Q Comment_Column +1F"G -1UC' QC[M !* Figure the place to switch to Miser fmt.! -1FO ..Q Miser_Column +1F"G -1UM' [R :IR /8+1*8 0FO ..Q Comment_Rounding F"N UR' M.M &_Indent [I !* G gets recursive macro to grind and pass 1 sexp.! !* It expects numerc arg = depth in parens.! [G ^:IG` [2 S' R !* Pass by all leading quotes.! 1A-("N ^FWL ' !* Atoms, just skip over.! FL-.-QW++(FS HPOSU2 Q2)"L FLL ' !* Lists that fit in line, skip over.! C Q2-QM"L !* If not yet far enough for Miser fmt,! !"! 1A F()"L ^FWL 1A-32"E C''' !* Skip 1st element, so get 2 on 1st line.! !* But if 1st element is a list, use miser fmt anyway.! FS HPOS U2 !* Q2 gets column to put rest of elements at.! !LP! 1a-32"E D O LP' !* Don't be confused by whitespace.! 1A-)"E C ' !* Until end of this list,! FS HPOSU3 Q3-Q2"N 13I 10I !* and for lists, indent to right place! Q2/8,9I Q2&7,32I' +1MG O LP !* and recursively grind.! ` 0MG !* DO IT! J 7F~ (DEFUN_"E !* Now, if list is (DEFUN FOO..., then! ^FLL 8F= ______"E 8D .U3 L !* Get the thing after FOO onto first line,! Q3,. F~FEXPR *(Q3,. F~MACRO )"E !* and if it is a function property name,! -2D 6D''' !* get it on that line too.! J HU2U3 > !* end errset! J Z: !* Leave region around the ground sexp.! Q3,Q2 !& LISP SUPERIOR:! !S Insert as directed by call from LISP.! [A [B [0 .U0 ZJ Z-3"G 0A-3"E -4D'' Q0J !* We delete the four characters at the! !* end that are used to stop LISP from! !* reading too far! "N FSIFILEUA !* The most recently opened input file! QLISPFILEUB !* The EMACS.TEMP.FILE! FS UREAD"N !* If anything is open,! F~AB"N !* then if it's not EMACS.TEMP.FILE! E[ !* push the input! F[ D FILE !* push the default! FN E] !* pop the input on exit from here! ERB' !* and open up EMACS.TEMP.FILE! 0FSIFACCESS' !* start reading at the beginning! FS UREAD"E !* if nothing is open! ERB' !* read EMACS.TEMP.FILE! U0 "L -Q0U0' !* The absolute value of the arg in 0! "G MM^R_SET/POP_MARK ZJ' Q0FY "L .+,.FXA !* If the arg is negative we put! MA' !* the stuff in A, delete and macro it.! "G R .,ZFSBOUNDARIES' ' !* We do nothing on a zero arg! +1"G F+ !* If arg nonnegative, clear screen and refresh.! :F'  !^R UP EVAL:! !^R Return to LISP and evaluate sexp after point.! 1000MM^R_Exit_To_LISP  !^R ARGLIST:! !^R Write into lower buffer arglist atom after point. Writes into lower buffer LISP arglist of function after point (or after open parenthesis after point.)! 1001MM^R_Exit_To_LISP  !^R Pretty Print:! !^R Pretty print buffer (using LISP pretty printer). Leaves point close to where it was, namely after the rightmost close parenthesis before point.! [0 0u0 <-:S(; %0> 1003MM^R_Exit_To_LISP .-B"E Q0:S('  !^R Print to Level:! !^R Print sexp after point with PRINTLEVEL set. Prints sexpression after point into lower buffer with PRINTLEVEL set to EMACS.P.PRINT.LEVEL.! 1002MM^R_Exit_To_LISP  !^R Exit To LISP:! !^R Simply return to LISP. Follows the protocol of closing the gap and leaving at the end of the buffer a string guaranteed to stop a LISP read.! [0 .U0 ZJ I_" 1F? !* Close the gap, so LISP can! !* read from the buffer! Q0J -1FSPJATY FSEXIT  !& Setup INTERMACS Library:! !S SETUP! [J 1M.VLISPFILE FSJNAMEUJ F~JLISP"E FS MSNAME FS D SNAME EREMACS.TEMP.FILE.0 FS I FILE ULISPFILE F~Editor_NameDMACS"E M.M^R_Pretty_PrintU...T M.M^R_Pretty_PrintU:.X(T) M.M^R_Print_To_Level U..T M.M^R_Exit_To_LISPM.VMM_Quit M.M^R_ARGLIST U.A M.M^R_Up_EVAL U.V' "#M.M^R_Pretty_PrintU...P M.M^R_Print_To_Level U..P M.M^R_Exit_To_LISP U ..Z M.M^R_Exit_To_LISP U...Z M.M^R_ARGLIST U...? M.M^R_Up_EVAL U...Y' M.M&_LISP_SuperiorFSSUPERIOR' mmLISP_MODE 1m.vLISP_)_HACK MM&_Process_Options :I..D_A____A____A____A____A____A____A____A____A______________A_____________A____A____A____A____A____A____A____A____A____A____A____A____A____A____A____A____A____A_________A____|____A___AA___A/____A____'____(____)____A____A____A____A___AA____A___AA___AA___AA___AA___AA___AA___AA___AA___AA___AA____A____A____A____A____A____A____A___AA___AA___AA___AA___AA___AA___AA___AA___AA___AA___AA___AA___AA___AA___AA___AA___AA___AA___AA___AA___AA___AA___AA___AA___AA___AA____A____A____A____A____A____A___AA___AA___AA___AA___AA___AA___AA___AA___AA___AA___AA___AA___AA___AA___AA___AA___AA___AA___AA___AA___AA___AA___AA___AA___AA___AA____A____A____A____A________  **** The END *****