!******************************************************************************
!
!         SSSSS   EEEEEEE  DDDDD    IIIIIII  TTTTTTT     1      3333
!        S     S  E        D    D      I        T       11     3    3
!        S        E        D     D     I        T        1          3
!         SSSSS   EEEEEEE  D     D     I        T        1      3333
!              S  E        D     D     I        T        1          3
!        S     S  E        D    D      I        T        1     3    3
!         SSSSS   EEEEEEE  DDDDD    IIIIIII     T     1111111   3333
!
!******************************************************************************
!        SEDIT -- SCREEN EDITOR for SDOS
!        11/26/82 IRA BAXTER
!******************************************************************************

!        BUGS/THINGS TO DO
! supress extra blanks while justifying unless <tab> to right in same line
!               ???left margin that glues itself to last tab used?
!               COMPRESSED BLANKS
!               ESC <NUM> RUBOUT
!               USE TOP LINE OF SCREEN TO DISPLAY STATUS?
!               PRESENCE OF TABS SHOULD NOT AFFECT AUTO-WRAP!
!               ILLEGAL TO WRAP IF BREAKOFF POINT IS A TAB!
!               RUBOUT AT COLUMN="LMARGIN" DELETES ENTIRE LMARGIN...
!                  only IF RMARGIN<>INFINITY???
!               DONT INSERT LMARGIN AFTER <CR> IF LMARGIN IS PRESENT
!               SEDIT SHOULD ALWAYS BE ABLE TO INSERT TEXT INTO BUFFER,
!                    EVEN WHEN BUFFER IS FULL.
!               MODIFY (REWRITE?) TO ALLOW SEDIT TO OPERATE WITH COMPLETE
!                    FREEDOM OVER ENTIRE FILE!
!               INTELLIGENT TABS???
!               FIX "CAN'T <ESC>R IF BUFFER IS FULL"
!               WOULD LIKE COMMAND TO ALLOW RE-EDIT OF FILE W/O EXIT SEDIT
!               ALLOW INSERT OF <FORM> CHARACTER IN TEXT
!               ALLOW INSERT OF <TAB> CHARACTERS
!               SHOULD NOT REDISPLAY UNTIL NEXT KEYBOARD INPUT REQUEST IS MADE
!               ESC -, ESC R SHOULD NEVER FLASH THE SCREEN!
!               JUSTIFY AFTER RUBOUT? IN PARTICULAR, AFTER DELETE <CR>?
!               ESC % CENTERS WITHIN MARGINS?
!               CAN'T <CTL-U> SOMETIMES -- PERHAPS BUFFER IS FULL?
!               ADD COMMAND TO GET TO END OF FILE.
!               THIS GUY WOULD BE LOTS EASIER IF HE BUILT A SCREEN IMAGE
!               AND SIMPLY COMPARED IT TO THE LAST SCREEN IMAGE HE DISPLAYED.
!               GET RID OF THE EXTRA <CR> AT END OF BUFFER; CAUSES CONFUSION.
!               KEEP BUFFER PRIED APART AROUND "DOT" TO MINIMIZE ACTUAL SHUFFLE
! **** REVISION HISTORY ****
!
! 1.0d 12/20/80
!             Fixed input line buffer overflow on read from file with long lines
!             Added ESC Q
!             Change to keep last <cr> in buffer if none immediately prior
!             Fixed <esc>F<unfindable string><esc><esc>X --> BEEP!
! 1.1A 1/27/81
!             INSTALLED ROWWIDTH VECTORS TO SIMPLIFY SCREEN MANAGEMENT
!             IMPLEMENTED <ESC> NUM FOR MOST COMMANDS
!             FIXED BLANKS$ TO BE LARGE ENOUGH FOR 132 WIDE SCREEN
!             FIXED DISASTER RECOVERY TO PREVENT "ILLEGAL DEV OP"
!             ADDED <ESC> N, CHANGED <ESC>F, <ESC> C SLIGHTLY...
!             TO MAKE MULTIPLE CHANGES MORE CONSISTENT
!             ALLOW <CR> INSERT AT END OF LINE
!             CONVERTED TEXT$ TO A DYNAMICALLY ALLOCATED STRING
!             ADDED CTL-U AS "DELETE CHARACTER UNDER CURSOR"
! 1.1B 3/4/81
!             FIXED "CUT" ACROSS END OF TEXT BUFFER GOOFS DISPLAY
!             SEDIT OPENS CONSOLE: ON CHANNEL 4 IF ISCONSOLE: FAILS
!             FIXED <ESC>A ACROSS TEXT BUFFER BOUNDARIES CAUSES EDIT FAILURE
!             FIXED <ESC>R PAST END OF LINE RESTORES TEXT IN WRONG PLACE
!
! 1.2A 4/16/81 THIS IS THE LAST REV THAT OPERATES WITHOUT THE VT DRIVER
!             MADE SEDIT DISPLAY "FIND" AND "CHANGE" STRINGS FOR EDITING
!             INSTALLED <ESC><TAB>,<ESC>"<",<ESC>">",<ESC>T<DIGIT>
!             INSTALLED CHEAP <TAB>S: EXPAND <TAB> INTO MULTIPLE BLANKS
!             ADDED AUTOMATIC RIGHT MARGIN BREAKOFF WHEN RMARGIN<>INFINITY
!             ADDED <ESC>J TO JUSTIFY TEXT OVER REGION
!             <GOUP> AT TOP OF SCREEN ROLLS TEXT DOWN 1/2 PAGE
!             FIXED ESC - PAST END OF LINE CUTS PART OF NEXT
!             ESC 0 ESC F ... FINDS STRING AT LEFT SIDE OF LINE
!             .SEDIT <filename> doesn't prompt for filename
! 1.2B 6/15/81 FIXED <SP><SP><CR> --> **POOF**
!              FIXED "DO" FILE RUNNING SEDIT CAUSE "CHANNEL ALREADY OPEN" ERR
! 1.2C 6/17/81 FIXED "WRAP AT END OF BUFFER" BLOWS UP
!              FIX STEAL FROM NEXT LINE IN JUSTIFY ALLOWS 1 MORE CHAR THAN RMARGIN
!              DO RASCII ZERO BYTES FROM CONSOLE AT EXIT
!              DO JUSTIFY AFTER CTL-U TO <CR> OR RUBOUT <CR>
!              <ESC>J WITH NO DISTINGUISHED POINT JUSTIFIES TO NEXT PARAGRAPH
!              ADD LINE THAT STARTS WITH "." IS A PARAGRAPH BREAK
!              FIX "JUSTIFY EVEN WHEN RMARGIN=RMARGININFINITY"
! 1.2D 6/21/81 FIX INSERT IN JUSTIFY MODE GETS STUCK IN LOOP IF NO PLACE TO BRK
!              FIX INSERT IN JUSTIFY MODE TO LEFT OF BLANK LEAVES
!              CURSOR IN LMARGIN OF NEXT LINE IF LINE OVERFLOWS
! 1.2E 6/23/81 FIX <BEEP> ON INSERT/DELETE IN FIRST WINDOW ON LARGE FILE
!                  (BUFFER IS FULL!)
!              MAKE <ESC><CR>,<ESC><UP>,<ESC><DOWN> PUT CURSOR AT LEFTMARGIN
!              FIXED <ESC>J TO OBJECT IF CURSOR IS PAST END OF LINE
!              FIXED <ESC>F, <ESC>N WHEN CURSOR PAST END OF LINE
!                CAUSES ERR 11 OR INCORRECT CURSOR PLACEMENT
!                    BOTTOM OF BUFFER -- WILL HAVE TO CHASE BUG
! 1.2F 9/14/81 FIX INSERT <TAB> PAST END OF LINE CAUSES EDIT FAILURE
!              <CONTROL-N> IS NOW ILLEGAL
!              <ESC>B, <ESC>Z SET CURSOR TO LEFTMARGIN INSTEAD OF 0
!              INSERTING OR DELETING TEXT NOW ADJUSTS DISTINGUISHED PT PROPERLY
!              REPORT EDIT FAILURES USING TEXT MESSAGE
!              FIXED create new file, enter <ESC>T0<TAB><CTL-U> --> EDIT FAILURE
!              FIXED BLOWS UP IN GETLINEFROMFILE1 WHEN SEARCHING FOR STRING...
!                    IN FILE WITH LINES MUCH WIDER THAN SCREEN
! 1.3A    1/1/82
!         MODIFIED TO OPERATE WITH VT DRIVER DOING SINGLE CHARACTER ACTIVATION
! 1.3B    FIXED <ESC>Q TO SET ACTIVATION ON CONSOLE BACK TO NORMAL.
!         CREATES "EDITORnnn+1.TMP" IF "FILE IS BEING CREATED" ERROR OCCURS
!         WHEN ATTEMPTING TO CREATE "EDITORnnn.TMP"
! 1.3C    USES "DELETEDnnn.TMP" WHEN USING "EDITORnnn.TMP"
! 1.3D    FIXED "DOESN'T SET ACTIVATION IF CREATING A NEW FILE"
!         MODIFIED TO CREATE "filename.TMP" AND "filename.DEL" WHEN EDITING
!         CHANGED TO HANDLE PATHNAMEPREFIXES PROPERLY FOR SDNET.
!         MADE OPERATOR INTERFACE A LITTLE FRIENDLIER IF "NO SUCH FILE".
! 1.3E    5/21/82
!         FIXED <ESC><LF> AT END OF BUFFER OVERSHOOTS IF LAST LINE DOESN'T HAVE
!         <CR> OF ITS OWN.  MODIFIED GETLINE TO EXPAND TAB CHARACTERS IF FOUND.
!         ADDED <ESC>: COMMAND: EXCHANGES "." AND CURSOR LOCATION IN BUFFER.
!         MODIFIED SO <RUBOUT> PAST END OF LINE SIMPLY ISSUES <BS>.!
!         FIXED <ESC>T1 WITH ">" IN RIGHTMOST MARGIN DOESN'T CRASH EDITOR.
!         ALSO HANDLE SEDIT.TAB LINE WIDER THAN CURRENT SCREEN.
!         MOD'D <ESC><PERIOD> AND <ESC><COLON> TO OBJECT IF CURSOR PAST <CR>,
!             (THIS PREVENTS DOT FROM BEING PLACED IN ANOTHER LINE)
!         FIXED FINDNEXT DOESN'T FIND A STRING IF IT IS FIRST THING IN BUFFER
!             AFTER WINDOW MOVES
! 1.3F    11/26/82
!         SEDIT.TAB NOW COMES FROM SAME DEVICE AS FILE BEING EDITED.
!         FIXED "STUCK LOOPING WHEN ATTEMPT TO INSERT A CHAR"
!         FIXED <DOWN> ERRONEOUSLY RE-ECHOES LAST LINE OF BUFFER WHEN AT
!             END OF BUFFER AND BUFFER IS FULL.
!         REVISED "CLEARSCREENDISPLAYPAGE" FOR ENHANCED DISPLAY PERFORMANCE
! 1.3G    8/20/84
!         FIXED "FINDBEGINLINE gets subscript error if past end of window"
!         ALLOW ^F FOR <ESC><CR> AND ^R FOR <ESC>@ (MATCHES VT DRIVER)
!         <ESC><DOWN> AT EOF DOES <BEEP><ESC>Z
!         SET ACTIVATION EARLIER TO ALLOW <ESC>F TYPEAHEAD WHEN START SEDIT
!^L
        DIM VERSION$/"V1.3g "/
        DIM CLEARSCREEN$/:C/
        DIM LINE$(255)
        DIM FILENAME$(50),FILENAMEDOTBAK$(50),DEVICE$(32)
        DIM EDITORTMP$(50),DELETEDTMP$(50)
        DIM OPERATORINPUT/0/,FILE/1/,TEMPFILE/2/,DELETEDTEXT/3/,...
&           TABSFILE/4/,ALTERNATEINPUT/5/
        DIM CURSORTEXTBASEPTR,CURSORTEXTLINEPTR,CURSORTEXTLINELENGTH,CURSORTEXTPTR
        DIM CURSORROW,CURSORCOL
        DIM CHARACTER$(1),CHARACTER,BEEP$/:7/,BACKSPACE$/:8/
        DIM CR$/:D/,CR/:D/,TAB$/:9/,TABCHARACTER/9/,BLANK/:20/
        DIM BLANKS$(132)
        DIM ALPHA$/"abcdefghijklmnopqrstuvwxyz",...
&                  "ABCDEFGHIJKLMNOPQRSTUVWXYZ",...
&                  "0123456789"/
        DIM I,J,K,L
        DIM LINEBASE,NEXTLINELENGTH,OLDLINELENGTH
        DIM SCREENDEPTH,SCREENWIDTH
        REM NEVER WRITE ANYTHING IN LAST COLUMN OF SCREEN.
        DIM FINDSTRING$(80),CHANGETOSTRING$(80),DELETEDSTRING$(500)
        DIM DELETEDTEXTISINFILE
        DIM GETSCREENPARAMS$/:F,:E,0,:5/
        DIM ISCONSOLE$/:1A,2/
        DIM ECHO$/:E,4,0,:10/,NOECHO$/:E,4,0,:11/
        DIM RASCII1$/:A,:E,0,1/,SETACTIVATION$/:E,8,0,:14/
        REM ACTIVATION SET DOES NOT INCLUDE ^C!!
        DIM ACTIVATIONSET$/:F3,:FF,:A4,:FF,:FF,:FF,:FF,:FF,...
&                          :FF,:FF,:FF,:FF,:FF,:FF,:FF,:FF/
        DIM EXITSET$/0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0/
        DIM COPYRGHT$/"Copyright (C) 1980 Software Dynamics"/
        DIM COPYRGHTCKSUM/3106/
        DIM SOURCELINETOOLONG$/"<<< Source Line was too long >>>"/
        DIM ROWWIDTH(64)
        DIM LEFTMARGIN/0/,RIGHTMARGIN/256/,RMARGININFINITY/255/,TABS$(50)

!^L
!***********************************************************
!*    SCREEN EDITOR INITIALIZATION CODE STARTS HERE
!************************************************************

REM *** DEFINE FRONT DOOR TO DYNAMIC STRING CONSTRUCTION ROUTINE

DEF CONSTRUCTDYNAMICSTRING$ EXTERNAL

START:   CALL SCREENEDIT(CONSTRUCTDYNAMICSTRING$)
REM *** NEVER RETURNS! ***
    STOP

SUBROUTINE SCREENEDIT( TEXT$ )
REM BEGIN EDIT CODE
REM "TEXT$" IS A STRING CONSTRUCTED DYNAMICALLY TO FILL REST OF USER SPACE
        PRINT CLEARSCREEN$;
        PRINT "Screen Edit ";VERSION$;COPYRGHT$
        FOR I=1 TO MAXLEN(BLANKS$) DO BLANKS$(I)=:20
        LET LEN(BLANKS$)=MAXLEN(BLANKS$)
        J=0
        FOR I=1 TO LEN(COPYRGHT$) DO J=J+COPYRGHT$(I)
        IF J<>COPYRGHTCKSUM
        THEN
            ERROR 1072
        FI
        IF ERROR WHEN SYSCALL ISCONSOLE$
        THEN
            IF ERR=1059
            THEN
                OPERATORINPUT=ALTERNATEINPUT
                OPEN #OPERATORINPUT,"CONSOLE:"
             ELSE ERROR
        FI
        SYSCALL #OPERATORINPUT,GETSCREENPARAMS$,'',FILENAME$
        LET SCREENWIDTH=FILENAME$(1)
        SCREENDEPTH=FILENAME$(2)
        IF SCREENDEPTH=0
        THEN
            PRINT "SEDIT requires use of CRT, Bye!"
            EXIT
        FI
        IF SCREENWIDTH>LEN(BLANKS$)
        THEN
            PRINT "CRT Screen is too wide!"
            EXIT
        FI
        IF SCREENDEPTH>LEN(ROWWIDTH)
        THEN
            PRINT "CRT Screen is too deep!"
            EXIT
        FI
        IF COL(0)=1 THEN PRINT "Name of file to edit: ";
        INPUT "" FILENAME$
100     TEXT$=CR$ \ ! MAKE THE TEXT BUFFER EMPTY, INITIALLY
        ! SEE IF FILENAME ALREADY EXISTS...
        IF ERROR WHEN OPEN #FILE,FILENAME$
        THEN
            IF ERR<>1011 OR OPERATORINPUT<>0 THEN ERROR \ ! GASP WHEEZE DIE...
            PRINT "That file does not exist."
            PRINT "Enter <RETURN> to exit, CREATE to create a new file,"
            INPUT "or the name of a file to edit: " LINE$
            IF LEN(LINE$)=0 THEN PRINT "Bye."\EXIT
            ELSEIF FIND(UPPERCASE$(LINE$),"CREATE")=1 AND LEN(LINE$)=6
                   THEN CREATE #FILE,FILENAME$
            ELSE FILENAME$=LINE$\GOTO 100
        FI
        ! MAKE THE WORLD SAFE FOR SEDIT, ALLOW <ESC> TYPEAHEAD
        SYSCALL #OPERATORINPUT,NOECHO$
        SYSCALL #OPERATORINPUT,SETACTIVATION$,ACTIVATIONSET$
110     REM CHECK FOR TEXT BUFFER IS REASONABLY FULL
        IF LEN(TEXT$)+MAXLEN(LINE$)+SCREENWIDTH*SCREENDEPTH>MAXLEN(TEXT$)
        THEN 200
        IF ERROR WHEN INPUT #FILE,LINE$
        THEN
            IF ERR<>8 THEN ERROR
            REM LINE FROM SOURCE FILE IS TOO LONG!
            PRINT BEEP$;
            LINE$=SOURCELINETOOLONG$
        FI
        IF EOF(FILE) THEN 200
115     GOSUB GETLINEFROMFILE1 \ ! INSERT NEW LINE INTO TEXT BUFFER
        GOTO 110

200     ! EXTRACT PATHNAMEPREFIX FROM FILENAME
        FOR I=LEN(FILENAME$) TO 1 STEP -1 UNTIL FILENAME$(I)=ASC(":") DO ! NADA
        LET DEVICE$=FILENAME$[1,I]
        LET FILENAME$=RIGHT$(FILENAME$,I+1)
        ! EXTRACT PART OF FILENAME ON WHICH TO CONCATENATE EXTENSIONS
        LET I=FIND(FILENAME$,'.')
        IF I=0 THEN LET I=LEN(FILENAME$)+1
        LET FILENAMEDOTBAK$=FILENAME$[1,IF I<=12 THEN I-1 ELSE 12 FI]
        LET FILENAMEDOTBAK$=DEVICE$ CAT FILENAMEDOTBAK$
        LET FILENAME$=DEVICE$ CAT FILENAME$ \ ! RECONSTRUCT ORIGINAL FILE NAME
        ! NOW CONSTRUCT VARIOUS VERSIONS OF FILENAME WITH DIFFERENT EXTENSIONS
        REM CONSTRUCT TEMPORARY OUTPUT FILE NAME = "filename.TMP"
        REM CONSTRUCT NAME OF FILE TO HOLD DELETED TEXT = "filename.DEL"
        LET EDITORTMP$=FILENAMEDOTBAK$ CAT '.TMP'
        LET DELETEDTMP$=FILENAMEDOTBAK$ CAT '.DEL'
        LET FILENAMEDOTBAK$=FILENAMEDOTBAK$ CAT '.BAK'
        CREATE #TEMPFILE,EDITORTMP$ \ ! CREATE THE OUTPUT FILE
        IF ERROR WHEN OPEN #DELETEDTEXT,DELETEDTMP$
        THEN
            IF ERR<>1011 THEN ERROR
            LET DELETEDTEXTISINFILE=FALSE
            LET DELETEDSTRING$=""
        ELSE
            LET DELETEDTEXTISINFILE=TRUE
            REM FIND OUT HOW MUCH TEXT IS IN DELETED.TMP
            LET DELETECOUNT=0
            REPEAT
                READ #DELETEDTEXT,LINE$
                DELETECOUNT=DELETECOUNT+LEN(LINE$)
            UNLESS EOF(DELETEDTEXT) END
        FI
    LET LINE$="" \ ! SET DEFAULT TAB LIST TO "NONE"
    IF ERROR WHEN OPEN #TABSFILE, DEVICE$ CAT "SEDIT.TAB"
    THEN
        IF ERR<>1011 THEN ERROR
        LET TABSFILEISOPEN=FALSE
    ELSE
        LET TABSFILEISOPEN=TRUE
        INPUT #TABSFILE,LINE$ \ ! READ DEFAULT TAB LIST
    FI
    GOSUB PROCESSRULER
210 GOSUB 50000\ REM RUN SCREEN EDITOR
    REM THE FILE HAS BEEN EDITED
    GOSUB COPYRESTOFFILE
    ON ERROR GOTO 250
    DELETE FILENAMEDOTBAK$
255 ON ERROR GOTO 260
    RENAME FILENAME$, FILENAMEDOTBAK$
270 ON ERROR GOTO 280
    RENAME EDITORTMP$,FILENAME$
    PRINT \ REM MAKE AN EMPTY LINE ON THE SCREEN
280 ON ERROR GOTO 290
    GOSUB RESETCONSOLE 
290 EXIT

RESETCONSOLE: ! RESTORE CONSOLE TO ECHO, STANDARD CHARACTER SET
    SYSCALL #OPERATORINPUT,ECHO$
    SYSCALL #OPERATORINPUT,SETACTIVATION$,EXITSET$
    RETURN

260 IF ERR<>1011 THEN ERROR ELSE 270

250 IF ERR<>1011 THEN ERROR ELSE 255

COPYRESTOFFILE:
    REPEAT
        WRITE #TEMPFILE,TEXT$
        READ #FILE,TEXT$
    WHEN LEN(TEXT$)>0 END
    CLOSE #TEMPFILE
    CLOSE #FILE
    RETURN

DISASTER:
    ON ERROR GOTO 0
    PRINT @(SCREENDEPTH-1,0)
    PRINT "*** EDITOR FAILURE ***"
    GOSUB RESETCONSOLE
    IF ERR=1015 THEN ERROR \ ! LET SDOS TELL USER THAT DISK IS FULL...
    PRINT "ERROR ";ERR;"@";ELN;"/";HEX$(ELN)
    GOSUB COPYRESTOFFILE
    PRINT "(Try looking in ";EDITORTMP$;" to recover your text)"
    EXIT

!^L
!**************************************************************************
!       MAIN SCREEN EDITOR CODE BEGINS HERE
!**************************************************************************

    DEF FINDBEGINLINE(FINDBEGINLINETEXTPTR)
    REM DO FAST BACKWARDS SEARCH FOR CR$
    FINDBEGINLINEK = IF FINDBEGINLINETEXTPTR <= LEN(TEXT$)
                     THEN FINDBEGINLINETEXTPTR ELSE LEN(TEXT$) FI
    FINDBEGINLINEI=FINDBEGINLINEK
51155   LET FINDBEGINLINEI=FINDBEGINLINEI-60\REM 60 = AVG LINE LENGTH
    IF FINDBEGINLINEI<1 THEN FINDBEGINLINEJ=1-FINDBEGINLINEI\ GOTO 51160
    FINDBEGINLINEJ=FIND(TEXT$(FINDBEGINLINEI,...
&                       FINDBEGINLINEK-FINDBEGINLINEI),CR$)
    IF FINDBEGINLINEJ=0 THEN 51155
    REM NOW WE HAVE OVERSHOT, SEARCH FORWARD
51160   FINDBEGINLINEI=FINDBEGINLINEI+FINDBEGINLINEJ
    FINDBEGINLINEJ=FIND(TEXT$(FINDBEGINLINEI,...
&                       FINDBEGINLINEK-FINDBEGINLINEI),CR$)
    IF FINDBEGINLINEJ<>0 THEN 51160
    RETURN FINDBEGINLINEI
    END

DEF KEYSTROKE
    SYSCALL #OPERATORINPUT,RASCII1$,'',CHARACTER$
    RETURN CHARACTER$(1)&:7F
END

!^L
50000   REM SCREEN EDITOR
        REM EDITS CHUNK OF TEXT IN TEXT$
        REM ASSERT TEXT$(LEN(TEXT$))=CR FOR CONVENIENCE
        REM COMMANDS: (CURSOR) UP, DOWN, LEFT, RIGHT
        REM           RUBOUT, IMPLIED INSERT
        REM           ESCAPE <CHARACTER>
        REM
        REM VARIABLES USED TO KEEP TRACK OF CURSOR AND TEXT:
        REM CURSORROW:             CURRENT ROW NUMBER OF CURSOR
        REM CURSORCOL:             CURRENT COLUMN NUMBER OF CURSOR
        REM CURSORTEXTBASEPTR:     INDEX OF TEXT$ OF CHARACTER DISPLAYED AT (0,0) ON SCREEN
        REM                        NOT VALID IF CURSORCOL > CURSORTEXTLINELENGTH
        REM
        REM THE FOLLOWING VARIABLES, WHEN USED, ARE DERIVED FROM THE ABOVE:
        REM CURSORTEXTLINEPTR:     INDEX OF TEXT$ OF CHAR DISPLAYED AT (CURSORROW,0)
        REM CURSORTEXTLINELENGTH:  LENGTH OF LINE DISPLAYED AT (CURSORROW,X)
        REM                        NOT INCLUDING THE <CR>
        REM CURSORTEXTPTR:         INDEX OF TEXT$ OF CHAR DISPLAYED AT (CURSORROW,CURSORCOL)

        REM Variables used to keep track of margins:
        REM LEFTMARGIN:            = Number of blanks to insert after <CR>
        REM RIGHTMARGIN:           Column number where line is broken off,
        REM                        and <CR> is automatically inserted
        REM SET UP TO ACTIVATE ON ENTIRE CHARACTER SET
        DISTINGUISHEDPOINT=0
        LET FINDLONG=FALSE
        ON ERROR GOTO DISASTER
ESCAPEB: REM ESC B -- MOVE CURSOR TO 1ST PAGE OF TEXT
        LET CURSORTEXTBASEPTR=1
        CURSORTEXTLINEPTR=CURSORTEXTBASEPTR
        CURSORCOL=LEFTMARGIN
        CURSORROW=0
        CURSORTEXTPTR=CURSORTEXTLINEPTR+CURSORCOL
        CURSORTEXTLINELENGTH=FIND(RIGHT$(TEXT$,CURSORTEXTLINEPTR),CR$)-1
50900   REM CAUSE CURRENT TEXT PAGE TO BE RE-DISPLAYED
        GOSUB CLEARSCREENDISPLAYPAGE
NEXTCMD: REM PROCESS NEXT EDIT COMMAND
        LET ARGUMENT=0 \ ! MEANS 'ARGUMENT NOT GIVEN'
        LET CHARACTER=KEYSTROKE
INSPECTCHARACTER: IF CHARACTER=:7F THEN RUBOUT
        IF CHARACTER>=:20 THEN INSERTCHARACTER
        ON CHARACTER+1 GOTO...
&       NEXTCMD,ILLEGAL,ILLEGAL,ESCAPEQ,ILLEGAL,ERASETOEOL,ESCAPECR,ILLEGAL,...
&       GOLEFT,INSERTTAB,GODOWN,GOUP,GORIGHT,INSERTCR,ILLEGAL,ILLEGAL,...
&       ILLEGAL,ILLEGAL,ESCATSIGN,ILLEGAL,ILLEGAL,DELETEUNDERCURSOR,ILLEGAL,ILLEGAL,...
&       CANCELLINE,ILLEGAL,ILLEGAL,ESCAPESEQUENCE,ILLEGAL,ILLEGAL,ILLEGAL,ILLEGAL
ILLEGAL: PRINT BEEP$;
        GOTO NEXTCMD

!^L
ESCAPESEQUENCE:   REM HANDLE ESCAPE CHARACTER
        LET CHARACTER=KEYSTROKE
        IF CHARACTER>=96 THEN LET CHARACTER=CHARACTER-32
ESCAPEINSPECTCHARACTER:
        ON CHARACTER GOTO...
&       ILLEGAL,ILLEGAL,ILLEGAL,ILLEGAL,ILLEGAL,ILLEGAL,ILLEGAL,...
&       ESCAPEGOLEFT,ESCAPETAB,ESCAPEGODOWN,ESCAPEGOUP,...
&                    ESCAPEGORIGHT,ESCAPECR,ESCAPEGOUP,ILLEGAL,...
&       ILLEGAL,ILLEGAL,ILLEGAL,ILLEGAL,ILLEGAL,ILLEGAL,ILLEGAL,ILLEGAL,...
&       ILLEGAL,ILLEGAL,ILLEGAL,ILLEGAL,ILLEGAL,ILLEGAL,ILLEGAL,ILLEGAL,...
&       ILLEGAL,ILLEGAL,ILLEGAL,ILLEGAL,ILLEGAL,ILLEGAL,ILLEGAL,ILLEGAL,...
&       ILLEGAL,ILLEGAL,ILLEGAL,ILLEGAL,ILLEGAL,ESCMINUS,ESCPERIOD,ILLEGAL,...
&       ESCDIGIT,ESCDIGIT,ESCDIGIT,ESCDIGIT,ESCDIGIT,ESCDIGIT,ESCDIGIT,ESCDIGIT,...
&       ESCDIGIT,ESCDIGIT,ESCCOLON,ILLEGAL,ESCAPELT,ILLEGAL,ESCAPEGT,ESCAPEQM,...
&       ESCATSIGN,...
&       ESCAPEA,ESCAPEB,ESCAPEC,ESCAPED,ILLEGAL,ESCAPEF,ILLEGAL,ESCAPEH,...
&       ILLEGAL,ESCAPEJ,ESCAPEK,ILLEGAL,ILLEGAL,ESCAPEN,ILLEGAL,ILLEGAL,...
&       ESCAPEQ,ESCAPER,ILLEGAL,ESCAPET,ILLEGAL,ILLEGAL,ILLEGAL,ESCAPEX,...
&       ILLEGAL,ESCAPEZ
        GOTO ILLEGAL

ESCDIGIT:   REM ESC DIGITS
        LET ARGUMENT=0
51755   LET ARGUMENT=ARGUMENT*10+CHARACTER-ASC('0')
        LET CHARACTER=KEYSTROKE
        IF CHARACTER>=ASC('0') AND CHARACTER<=ASC('9') THEN 51755
        GOTO INSPECTCHARACTER

!^L
GORIGHT: REM HANDLE GORIGHT CHARACTER
        IF ARGUMENT=0 THEN ARGUMENT=1
        IF CURSORCOL=SCREENWIDTH-1 THEN ILLEGAL
        IF CURSORCOL+ARGUMENT>=SCREENWIDTH
        THEN
            LET CURSORCOL=SCREENWIDTH-1
            LET CURSORTEXTPTR=CURSORTEXTLINEPTR+CURSORCOL
            GOSUB POSITIONCURSOR
            GOTO ILLEGAL
        ELSE
            LET CURSORCOL=CURSORCOL+ARGUMENT
            LET CURSORTEXTPTR=CURSORTEXTPTR+ARGUMENT
            GOSUB POSITIONCURSOR
            GOTO NEXTCMD
        FI

!^L
GOLEFT: REM HANDLE BACKSPACE
    IF CURSORTEXTLINELENGTH<CURSORCOL AND ARGUMENT=0
    THEN
        FOR I=CURSORTEXTLINELENGTH+1 TO CURSORCOL DO PRINT BACKSPACE$;
        LET CURSORCOL=CURSORTEXTLINELENGTH\
        LET CURSORTEXTPTR=CURSORTEXTLINEPTR+CURSORCOL
        GOTO NEXTCMD
    FI
    IF ARGUMENT=0 THEN ARGUMENT=1
    FOR CMDITERATION=1 TO ARGUMENT
        IF CURSORCOL<>0
        THEN
            PRINT BACKSPACE$;
            LET CURSORCOL=CURSORCOL-1
            LET CURSORTEXTPTR=CURSORTEXTPTR-1
        ELSE
            REM BACKSPACE AT BEGIN LINE
            REM DO A GO UP, AND THEN POSITION CURSOR AT RIGHT HAND END OF LINE
            IF CURSORTEXTLINEPTR=1 THEN ILLEGAL\ REM NO PLACE TO GO
            REM THERE EXISTS A PLACE TO GO UP TO
            LET CURSORTEXTLINEPTR=FINDBEGINLINE(CURSORTEXTLINEPTR-1)
            LET CURSORTEXTLINELENGTH=FIND(RIGHT$(TEXT$,CURSORTEXTLINEPTR),CR$)-1
            LET CURSORCOL=...
&               IF CURSORTEXTLINELENGTH>=SCREENWIDTH
                   THEN SCREENWIDTH-1 ELSE CURSORTEXTLINELENGTH FI
            LET CURSORTEXTPTR=CURSORTEXTLINEPTR+CURSORCOL
            IF CURSORROW=0
            THEN
                REM AT TOP OF SCREEN
                LET CURSORTEXTBASEPTR=CURSORTEXTLINEPTR
                GOSUB DISPLAYPAGEFROMCURSORROW
            ELSE
                REM NOT AT TOP OF SCREEN, EASY CASE
                LET CURSORROW=CURSORROW-1
                GOSUB POSITIONCURSOR
            FI
            IF CURSORTEXTLINELENGTH>=SCREENWIDTH THEN ILLEGAL FI
        FI
    NEXT CMDITERATION
    GOTO NEXTCMD

!^L
GODOWN: REM HANDLE LINEFEED
    IF ARGUMENT=0 THEN ARGUMENT=1
    FOR CMDITERATION=1 TO ARGUMENT
        IF CURSORTEXTPTR=LEN(TEXT$) AND...
&          ( CURSORTEXTLINELENGTH>0 OR EOF(FILE) ) THEN ILLEGAL
        IF CURSORTEXTLINEPTR+CURSORTEXTLINELENGTH<LEN(TEXT$)
        THEN
            REM NOT AT LAST LINE OF TEXT BUFFER
            IF CURSORROW<SCREENDEPTH-1
            THEN
                REM NOT AT BOTTOM OF SCREEN
                LET CURSORROW=CURSORROW+1
                LET CURSORTEXTLINEPTR=CURSORTEXTLINEPTR+CURSORTEXTLINELENGTH+1
                LET CURSORTEXTLINELENGTH=...
&                   FIND(RIGHT$(TEXT$,CURSORTEXTLINEPTR),CR$)-1
                LET CURSORTEXTPTR=CURSORTEXTLINEPTR+CURSORCOL
            ELSE
                REM LINEFEED AT BOTTOM OF SCREEN
                LET CURSORTEXTBASEPTR=CURSORTEXTBASEPTR+...
&                   FIND(RIGHT$(TEXT$,CURSORTEXTBASEPTR),CR$)
                REM LEAVE CURSOR LOCATION ALONE
                LET CURSORTEXTLINEPTR=CURSORTEXTLINEPTR+CURSORTEXTLINELENGTH+1
                LET CURSORTEXTLINELENGTH=...
&                   FIND(RIGHT$(TEXT$,CURSORTEXTLINEPTR),CR$)-1
                LET CURSORTEXTPTR=CURSORTEXTLINEPTR+CURSORCOL
                REM NOW ROLL THE SCREEN UP ONE LINE, AND DISPLAY THE NEW LINE
                FOR I=0 TO SCREENDEPTH-2 DO ROWWIDTH(I)=ROWWIDTH(I+1)
                PRINT
                LET ROWWIDTH(SCREENDEPTH-1)=...
&                   IF CURSORTEXTLINELENGTH>=SCREENWIDTH
                    THEN SCREENWIDTH-1 ELSE CURSORTEXTLINELENGTH FI
                PRINT TEXT$[CURSORTEXTLINEPTR,ROWWIDTH(SCREENDEPTH-1)];
            FI
        ELSE
            REM WE ARE IN LAST LINE OF BUFFER
            IF CURSORTEXTLINELENGTH>0
            THEN
                REM NOT ABSOLUTELY AT END OF TEXT, MOVE CURSOR TO END
                IF CURSORTEXTLINELENGTH>=SCREENWIDTH
                THEN CURSORCOL=SCREENWIDTH-1
                ELSE CURSORCOL=CURSORTEXTLINELENGTH
                LET CURSORTEXTPTR=CURSORTEXTLINEPTR+CURSORCOL
            ELSE
GODOWNFILE:     REM GODOWN AT END OF TEXT
                REM ASSERT: CURSORTEXTLINEPTR=LEN(TEXT$)
                REM READ IN NEXT LINE FROM INPUT FILE
                GOSUB GETLINEFROMFILE
                IF EOF(FILE) THEN ESCAPEZ
                IF CURSORTEXTLINEPTR=LEN(TEXT$) THEN ILLEGAL \ ! NO ROOM
                REM DISPLAY NEW LINE ON SCREEN
                POSITION #0,CURSORROW**8 \ ! REM THIS LINE IS BLANK
                LET J=IF LEN(LINE$)>=SCREENWIDTH THEN SCREENWIDTH-1 ELSE LEN(LINE$) FI
                PRINT LINE$(1,J)
                IF CURSORROW<SCREENDEPTH-1
                THEN
                    ROWWIDTH(CURSORROW)=J
                    CURSORROW=CURSORROW+1
                ELSE
                    FOR I=0 TO SCREENDEPTH-3 DO ROWWIDTH(I)=ROWWIDTH(I+1)
                    ROWWIDTH(SCREENDEPTH-2)=J
                    REM ASSERT: ROWWIDTH(SCREENDEPTH-1) = 0
                    CURSORTEXTBASEPTR=...
&                   CURSORTEXTBASEPTR+FIND(RIGHT$(TEXT$,CURSORTEXTBASEPTR),CR$)
                FI
                LET CURSORTEXTLINEPTR=LEN(TEXT$)
                LET CURSORTEXTLINELENGTH=0
                LET CURSORTEXTPTR=CURSORTEXTLINEPTR+CURSORCOL
            FI
        FI
        REM PUT THE CURSOR IN THE PROPER PLACE
        GOSUB POSITIONCURSOR
    NEXT CMDITERATION
    GOTO NEXTCMD

!^L
GOUP: REM GO UP CHARACTER
    IF ARGUMENT=0 THEN ARGUMENT=1
    IF ARGUMENT<=CURSORROW
    THEN
        REM THERE EXISTS A PLACE TO GO UP TO
        FOR CMDITERATION=1 TO ARGUMENT
            LET CURSORTEXTLINEPTR=FINDBEGINLINE(CURSORTEXTLINEPTR-1)
            LET CURSORTEXTLINELENGTH=FIND(RIGHT$(TEXT$,CURSORTEXTLINEPTR),CR$)-1
            LET CURSORTEXTPTR=CURSORTEXTLINEPTR+CURSORCOL
            LET CURSORROW=CURSORROW-1
        NEXT CMDITERATION
        GOSUB POSITIONCURSOR
    ELSE
        REM GO UP ACROSS TOP OF SCREEN
        FOR CMDITERATION=1 TO ARGUMENT
            IF CURSORTEXTLINEPTR=1
            THEN
                REM AT TOP OF TEXT BUFFER
                IF CURSORTEXTPTR>1
                THEN CURSORTEXTPTR=1
                ELSE PRINT BEEP$;\ EXIT CMDITERATION
            ELSE
                LET CURSORTEXTLINEPTR=FINDBEGINLINE(CURSORTEXTLINEPTR-1)
                LET CURSORTEXTPTR=CURSORTEXTLINEPTR+CURSORCOL
            FI
        NEXT CMDITERATION
        GOSUB SETUPCURSORCONTEXT
        GOSUB CLEARSCREENDISPLAYPAGE
    FI
    GOTO NEXTCMD

!^L
ESCATSIGN: REM ESC @ MOVE CURSORTEXTPTR TO END OF TEXT LINE
    LET CURSORTEXTPTR=CURSORTEXTLINEPTR+CURSORTEXTLINELENGTH
    GOSUB SETUPCURSORCOL \ ! AND YELL IF OFF THE SCREEN
    GOSUB POSITIONCURSOR
    GOTO NEXTCMD

ESCCOLON: REM ESC : SWAP CURSORTEXTPTR WITH DISTINGUISHEDPOINT
    IF CURSORCOL>CURSORTEXTLINELENGTH THEN ILLEGAL
    IF DISTINGUISHEDPOINT=0 THEN ILLEGAL
    LET I=DISTINGUISHEDPOINT
    LET DISTINGUISHEDPOINT=CURSORTEXTPTR
    LET CURSORTEXTPTR=I
    LET WINDOWMOVED=FALSE
    GOTO FINDDONE \ ! AND DISPLAY NEW CONTEXT

ESCPERIOD: REM ESC . REMEMBER CURRENT TEXT LOCATION
    IF CURSORCOL>CURSORTEXTLINELENGTH THEN ILLEGAL
    DISTINGUISHEDPOINT=CURSORTEXTPTR
    GOTO NEXTCMD

ESCMINUS: REM ESC - DELETE TEXT FROM DISTINGUISHED LOCATION TO HERE
    IF DISTINGUISHEDPOINT=0 THEN ILLEGAL
    IF DISTINGUISHEDPOINT>=CURSORTEXTPTR THEN ILLEGAL
    IF CURSORCOL>CURSORTEXTLINELENGTH THEN ILLEGAL
    LET I=CURSORTEXTPTR
    LET CURSORTEXTPTR=DISTINGUISHEDPOINT
    CALL DELETESTRING(DISTINGUISHEDPOINT,I)
    DISTINGUISHEDPOINT=0\ REM PREVENT INADVERTANT USER GOOFS
    IF CURSORTEXTPTR>=CURSORTEXTBASEPTR
    THEN
        REM DELETE WITHIN SAME SCREENFUL OF TEXT
        GOSUB SETUPLINECONTEXT
        GOSUB DISPLAYPAGEFROMCURSORROW
    ELSE
        GOSUB SETUPCURSORCONTEXT
        GOSUB CLEARSCREENDISPLAYPAGE
    FI
    GOTO NEXTCMD

!^L
SETUPLINECONTEXT: REM ASSERT:  CURSORTEXTPTR < ONE SCREENFUL FROM CURSORTEXTBASEPTR
    REM SETS UP CURSOR CONTEXT FOR RE-DISPLAY OF REST OF SCREEN
    CURSORTEXTLINEPTR=FINDBEGINLINE(CURSORTEXTPTR)
SETUPLINECONTEXTATENDWINDOW: ! ENTRY POINT FROM <ESC><DOWN> AT END WINDOW
    CURSORTEXTLINELENGTH=FIND(RIGHT$(TEXT$,CURSORTEXTLINEPTR),CR$)-1
    LET I=CURSORTEXTBASEPTR
    FOR CURSORROW=0 TO SCREENDEPTH-1 UNTIL I=CURSORTEXTLINEPTR DO
        LET I=I+FIND(RIGHT$(TEXT$,I),CR$)
    END
SETUPCURSORCOL: REM SET UP CURSOR COLUMN. BEEP IF OFF RIGHT SIDE OF SCREEN
    LET CURSORCOL=CURSORTEXTPTR-CURSORTEXTLINEPTR
    IF CURSORCOL>=SCREENWIDTH
    THEN
        REM SIGH...CURSOR OFF RIGHT SIDE OF SCREEN
        PRINT BEEP$;
        LET CURSORCOL=SCREENWIDTH-1
        LET CURSORTEXTPTR=CURSORTEXTLINEPTR+CURSORCOL
    FI
    RETURN

SETUPCURSORCONTEXT: REM GIVEN CURSORTEXTPTR,...
    REM COMPUTE CURSORTEXTBASEPTR,CURSORTEXTLINEPTR,CURSORTEXTLINELENGTH
    REM MUST CALL CLEARSCREENDISPLAYPAGE AFTER INVOCATION OF THIS ROUTINE
    CURSORTEXTLINEPTR=FINDBEGINLINE(CURSORTEXTPTR)
    CURSORTEXTLINELENGTH=FIND(RIGHT$(TEXT$,CURSORTEXTLINEPTR),CR$)-1
    LET CURSORTEXTBASEPTR=CURSORTEXTLINEPTR
    FOR CURSORROW=0 TO (SCREENDEPTH-1)**-1 UNTIL CURSORTEXTBASEPTR=1
        CURSORTEXTBASEPTR=FINDBEGINLINE(CURSORTEXTBASEPTR-1)
    NEXT CURSORROW
    GOTO SETUPCURSORCOL

!^L
SUBROUTINE DELETESTRING(DELETEFROM,DELETETO)
        REM BYTES DELETEFROM..DELETETO-1 ARE DELETED
        REM MUST CALL SETUPCURSORCONTEXT AFTER CALLING DELETESTRING
        IF DELETEDTEXTISINFILE
        THEN CLOSE #DELETEDTEXT
        LET DELETECOUNT=DELETETO-DELETEFROM
        IF DELETECOUNT<=MAXLEN(DELETEDSTRING$)
        THEN
            LET DELETEDSTRING$=TEXT$(DELETEFROM,DELETECOUNT)
            LET DELETEDTEXTISINFILE=FALSE
        ELSE
            CREATE #DELETEDTEXT,DELETEDTMP$
            WRITE #DELETEDTEXT,TEXT$(DELETEFROM,DELETECOUNT)
            LET DELETEDTEXTISINFILE=TRUE
            LET DELETEDSTRING$=""
        FI
        LET TEXT$(DELETEFROM,LEN(TEXT$)-DELETETO+1)=...
&                RIGHT$(TEXT$,DELETETO)
        LET LEN(TEXT$)=LEN(TEXT$)-DELETECOUNT
        IF DISTINGUISHEDPOINT>=DELETEFROM
        THEN DISTINGUISHEDPOINT=...
&            IF DISTINGUISHEDPOINT<DELETETO
             THEN 0
             ELSE DISTINGUISHEDPOINT-(DELETETO-DELETEFROM) FI
        EXIT SUBROUTINE
END

!^L
SUBROUTINE ADJUSTHOLESIZE(HOLEBASE,OLDHOLESIZE,NEWHOLESIZE)
    REM SUBROUTINE TO CHANGE SIZE OF HOLE IN TEXT$
    REM EXPANDS OR SHRINKS HOLE ACCORDING TO OLDHOLESIZE AND NEWHOLESIZE
    REM ADJUSTS SIZE OF TEXT$ APPROPRIATELY
    REM ADJUSTS DISTINGUISHED POINT, ALSO
    IF NEWHOLESIZE<=OLDHOLESIZE
    THEN
        REM SHRINK THE HOLE IF NECESSARY
        IF NEWHOLESIZE<OLDHOLESIZE
        THEN
            REM IT'S NECESSARY TO SHRINK THE HOLE
            LET TEXT$[HOLEBASE+NEWHOLESIZE,...
&                     LEN(TEXT$)-(HOLEBASE+OLDHOLESIZE)+1]=...
&               RIGHT$(TEXT$,HOLEBASE+OLDHOLESIZE)
            LET LEN(TEXT$)=LEN(TEXT$)-OLDHOLESIZE+NEWHOLESIZE
        FI
    ELSE
        REM MUST EXPAND THE HOLE
        LET J=LEN(TEXT$)
        LET LEN(TEXT$)=LEN(TEXT$)-OLDHOLESIZE+NEWHOLESIZE
        LET TEXT$[HOLEBASE+NEWHOLESIZE,J-(HOLEBASE+OLDHOLESIZE)+1]=...
&           TEXT$[HOLEBASE+OLDHOLESIZE,J-(HOLEBASE+OLDHOLESIZE)+1]
    FI
    REM NOW ADJUST DISTINGUISHED POINT
    REM IF IT IS IN REGION THAT IS ADJUSTED, THEN FORGET IT
    IF DISTINGUISHEDPOINT>=HOLEBASE
    THEN DISTINGUISHEDPOINT=...
&        IF DISTINGUISHEDPOINT<HOLEBASE+OLDHOLESIZE
         THEN 0
         ELSE DISTINGUISHEDPOINT+NEWHOLESIZE-OLDHOLESIZE FI
    EXIT SUBROUTINE
END

!^L
DEF MAKEROOM(MAKEROOMSIZE)
    REM RETURNS MIN(MAKEROOMSIZE,AVAILABLE ROOM)
    REM ATTEMPTS TO MAKE ENOUGH ROOM FOR "MAKEROOMSIZE" FREE BYTES
    IF MAXLEN(TEXT$)-LEN(TEXT$)>=MAKEROOMSIZE THEN RETURN MAKEROOMSIZE
    LET I=FIND(RIGHT$(TEXT$,MAKEROOMSIZE+1),CR$)+MAKEROOMSIZE
    IF I>CURSORTEXTLINEPTR THEN LET I=CURSORTEXTLINEPTR
    I=I-1
    WRITE #TEMPFILE,TEXT$(1,I)
    LET TEXT$=RIGHT$(TEXT$,I+1)
    IF CURSORTEXTBASEPTR<I
    THEN
        CURSORTEXTPTRSAVE=0 \ ! MUST SET UP CURSOR CONTEXT
        LET CURSORTEXTBASEPTR=1
    ELSE LET CURSORTEXTBASEPTR=CURSORTEXTBASEPTR-I
    IF CURSORTEXTPTRSAVE>0 THEN CURSORTEXTPTRSAVE=CURSORTEXTPTRSAVE-I FI
    LET CURSORTEXTLINEPTR=CURSORTEXTLINEPTR-I
    LET CURSORTEXTPTR=CURSORTEXTPTR-I
    IF DISTINGUISHEDPOINT<=I
    THEN LET DISTINGUISHEDPOINT=0
    ELSE LET DISTINGUISHEDPOINT=DISTINGUISHEDPOINT-I
    RETURN IF MAXLEN(TEXT$)-LEN(TEXT$)>MAKEROOMSIZE...
&          THEN MAKEROOMSIZE ELSE MAXLEN(TEXT$)-LEN(TEXT$) FI
END

!^L
ESCAPER: REM ESC R -- RESTORE DELETED TEXT HERE
REM THIS SHOULD NEVER FLASH THE SCREEN!
    INSERTEDBLANKCOUNT=...
&       IF CURSORCOL>=CURSORTEXTLINELENGTH
        THEN CURSORCOL-CURSORTEXTLINELENGTH ELSE 0 FI
    IF DELETECOUNT+INSERTEDBLANKCOUNT >...
&      (CURSORTEXTLINEPTR-1)+(MAXLEN(TEXT$)-LEN(TEXT$))
    THEN ILLEGAL
    IF INSERTEDBLANKCOUNT>0
    THEN
        REM MUST INSTALL BLANKS BEFORE DOING <ESC> R
        LET CURSORTEXTPTR=CURSORTEXTLINEPTR+CURSORTEXTLINELENGTH
        LET AMOUNTTOBEINSERTED=INSERTEDBLANKCOUNT
        UNTIL AMOUNTTOBEINSERTED=0 DO
            AMOUNTINSERTEDTHISTIME=MAKEROOM(AMOUNTTOBEINSERTED)
            ADJUSTHOLESIZE(CURSORTEXTPTR,0,AMOUNTINSERTEDTHISTIME)
            LET TEXT$[CURSORTEXTPTR,AMOUNTINSERTEDTHISTIME]=...
&               BLANKS$[1,AMOUNTINSERTEDTHISTIME]
            LET CURSORTEXTPTR=CURSORTEXTPTR+AMOUNTINSERTEDTHISTIME
            LET AMOUNTTOBEINSERTED=AMOUNTTOBEINSERTED-AMOUNTINSERTEDTHISTIME
        END
    FI
    CURSORTEXTPTRSAVE=CURSORTEXTPTR \ ! REMEMBER WHERE CURSOR IS NOW FOR LATER REDISPLAY
    REM INSERT DELETED TEXT
    IF DELETEDTEXTISINFILE THEN POSITION #DELETEDTEXT@0 \ ! REWIND TO READ IT
    LET AMOUNTTOBEINSERTED=DELETECOUNT
    UNTIL AMOUNTTOBEINSERTED=0 DO
        AMOUNTINSERTEDTHISTIME=MAKEROOM(AMOUNTTOBEINSERTED)
        ADJUSTHOLESIZE(CURSORTEXTPTR,0,AMOUNTINSERTEDTHISTIME)
        IF DELETEDTEXTISINFILE
        THEN READ #DELETEDTEXT,TEXT$[CURSORTEXTPTR,AMOUNTINSERTEDTHISTIME]
        ELSE
            LET TEXT$(CURSORTEXTPTR,AMOUNTINSERTEDTHISTIME)=...
&               DELETEDSTRING$[LEN(DELETEDSTRING$)-AMOUNTTOBEINSERTED+1,...
&                              AMOUNTINSERTEDTHISTIME]
        FI
        LET CURSORTEXTPTR=CURSORTEXTPTR+AMOUNTINSERTEDTHISTIME
        LET AMOUNTTOBEINSERTED=...
&           AMOUNTTOBEINSERTED-AMOUNTINSERTEDTHISTIME
   END
DISPLAYAFTERINSERT:
   IF CURSORTEXTPTRSAVE=0
   THEN
       REM OLD SCREEN DISPLAY IS COMPLETELY INVALID
       GOSUB SETUPCURSORCONTEXT
       GOSUB CLEARSCREENDISPLAYPAGE
   ELSE
       REM MAKEROOM DIDN'T DAMAGE CURSORTEXTBASEPTR FROM USER'S VIEWPOINT
       REM FIND OUT IF CURSORTEXTPTR IS IN THE SAME SCREENFUL OF TEXT
       CURSORTEXTLINEPTR=FINDBEGINLINE(CURSORTEXTPTR)
       CURSORTEXTLINELENGTH=FIND(RIGHT$(TEXT$,CURSORTEXTLINEPTR),CR$)-1
       LET I=CURSORTEXTBASEPTR
       FOR CURSORROW=0 TO SCREENDEPTH-1 UNTIL I=CURSORTEXTLINEPTR DO
           LET I=I+FIND(RIGHT$(TEXT$,I),CR$)
       END
       IF CURSORROW=SCREENDEPTH
       THEN
           REM CURSORTEXTPTR HAS MOVED TOO FAR
           GOSUB SETUPCURSORCONTEXT
           GOSUB CLEARSCREENDISPLAYPAGE
       ELSE
           REM UPDATE SCREEN DISPLAY
           LET I=CURSORTEXTPTR
           LET CURSORTEXTPTR=CURSORTEXTPTRSAVE
           LET CURSORTEXTPTRSAVE=I
           GOSUB SETUPLINECONTEXT
           GOSUB DISPLAYPAGEFROMCURSORROW
           LET I=CURSORTEXTPTR
           LET CURSORTEXTPTR=CURSORTEXTPTRSAVE
           LET CURSORTEXTPTRSAVE=I
           GOSUB SETUPLINECONTEXT
           GOSUB POSITIONCURSOR
       FI
   FI
   GOTO NEXTCMD

!^L
ESCAPEQ: REM ESC Q
    PRINT CLEARSCREEN$;"Verify: Quit without Update? ";
    LET CHARACTER=KEYSTROKE
    IF CHARACTER>=ASC(' ') THEN PRINT CHR$(CHARACTER);\ ! ECHO THE RESPONSE
    IF CHARACTER=ASC('Y') OR CHARACTER=ASC('y')
    THEN
        CLOSE #TEMPFILE
        DELETE EDITORTMP$
        IF NOT DELETEDTEXTISINFILE
        THEN
            CREATE #DELETEDTEXT,DELETEDTMP$
            WRITE #DELETEDTEXT,DELETEDSTRING$
        FI
        PRINT
        GOSUB RESETCONSOLE
        EXIT \ ! LEAVE FAST!
    FI \ ! ELSE DO "HELP" COMMAND
!^L
ESCAPEH: REM ESC H
    PRINT CLEARSCREEN$;
    PRINT "Type to INSERT; <RUBOUT> deletes insert; <CTL-U> deletes under cursor"
    PRINT "<UP> <DOWN> <LEFT> <RIGHT>: Move cursor in specified direction"
    PRINT "ESC <UP> or <DOWN>: Move cursor one screen in specified direction"
    PRINT "ESC <LEFT> or <RIGHT>: Move cursor left or right to start of word"
    PRINT "ESC <CR>: Move cursor to start of current line"
    PRINT "ESC <PERIOD>: Mark cursor location as start of 'Delete' or 'Justify'"
    PRINT "ESC -: Delete text from marked point to cursor"
    PRINT "ESC ?: Redisplay the screen, centering cursor context"
    PRINT "ESC A: Again, repeat change and find next occurrence"
    PRINT "ESC B: Move cursor to top of text window"
    PRINT "ESC C <string> ESC: Change found string to <string>"
    PRINT "ESC D: Delete Word"
    PRINT "ESC F <string> ESC: FIND <string>"
    PRINT "ESC H ESC: Displays this text"
    PRINT "ESC J: Force text between marked point and cursor to fit margins"
    PRINT "ESC K: Delete (Kill) rest of line"
    PRINT "ESC N: Find next occurrence of <ESC>F string"
    PRINT "ESC Q: Quit editing, don't update file"
    PRINT "ESC R: Restore deleted text here"
    PRINT "ESC X: Exit edit mode, update file"
    PRINT "ESC Z: Move cursor to bottom of text window"
    PRINT "ESC < or ESC >: Set Left Margin/Right Margin"
    PRINT "ESC <TAB>: Set/Reset Tab Stop"
    PRINT "ESC T <digit>: Select new Ruler from SEDIT.TAB";
rem PRINT "<CTL-E> erases to end-of-line; <CTL-X> cancels line"
rem PRINT "ESC<digits>: Repeat next command <digits> times"
rem PRINT "ESC @: Moves cursor to end of line"
rem PRINT "ESC <COLON>: Swaps cursor position with marked text location"
    UNTIL KEYSTROKE=:1B DO PRINT BEEP$; END
    GOSUB CLEARSCREENDISPLAYPAGE
    GOTO NEXTCMD
!^L
SUBROUTINE EDITLINE(EDITLINE$,EDITLINEPTR,EDITLEFTMARGIN,EDITRIGHTMARGIN)
    REM THIS SUBROUTINE DOES EDITING WITHIN A SINGLE LINE
    REM EDITLINE$ HOLDS THE TEXT BEING EDITED (INCLUDING <CR>)
    REM IT ASSUMES THAT THE CURSOR IS PRESENTLY AT (CURSORROW,CURSORCOL)
    REM AND THAT EDITLINE$ IS ALREADY DISPLAYED AT CURSORROW
    REM CHARACTER CONTAINS 1ST COMMAND TO BE EXECUTED
    REM THIS SUBROUTINE DOES NOT CHECK FOR TEXT BUFFER SPACE AVAILABLE!
    REM EDITLINE$ MUST HAVE A <CR> AS ITS LAST CHARARACTER
    REM THIS SUBROUTINE HANDLES THE FOLLOWING COMMANDS:
    REM <GORIGHT> <GOLEFT> <RUBOUT> <CONTROL-U> <INSERTME> <TAB>
    REM <CONTROL-X> <CONTROL-E>
    REM ALL OTHER COMMANDS ARE LEFT IN "CHARACTER" AND THE SUBROUTINE EXITS
    REM EDITLINEPTR IS USED AS A POINTER INTO LINE$
    Rem EDITRIGHTMARGIN is the last column (zero-origin)...
    Rem in which a character may be placed
    Rem EDITLEFTMARGIN is the first column (zero-origin) in which a character
    Rem may be placed; 0<=EDITLEFTMARGIN<EDITRIGHTMARGIN
    GOTO EDITLINEINSPECTCHARACTER

EDITLINEILLEGAL: PRINT BEEP$;
EDITLINELOOP: REM USER IS EDITING WITHIN A LINE
    LET CHARACTER=KEYSTROKE
EDITLINEINSPECTCHARACTER: REM ACT ON COMMAND
    IF CHARACTER>=BLANK
    THEN IF CHARACTER=:7F THEN EDITLINERUBOUT ELSE EDITLINEINSERTCHAR FI
    ELSEIF CHARACTER=:00 THEN EDITLINELOOP
    ELSEIF CHARACTER=:05 THEN EDITLINEERASETOEOL
    ELSEIF CHARACTER=:08 THEN EDITLINEGOLEFT
    ELSEIF CHARACTER=:09 THEN EDITLINEINSERTTAB
    ELSEIF CHARACTER=:0C THEN EDITLINEGORIGHT
    ELSEIF CHARACTER=:15 THEN EDITLINEDELETEUNDERCURSOR
    ELSEIF CHARACTER=:18 THEN EDITLINECANCELLINE
EDITLINEQUIT: REM NOT A LINE EDITING CHARACTER,...
    REM OR CAN'T HANDLE IT HERE, SO LEAVE!
    RETURN SUBROUTINE
!^L
EDITLINEINSERTTAB: REM REPLACE <TAB> BY MULTIPLE BLANKS TO NEXT TAB COLUMN
    REM **** THIS NEEDS TO BE REPLACED WHEN VT DRIVER IS INSTALLED ***
    FOR I=1 TO LEN(TABS$) UNTIL TABS$[I]>CURSORCOL DO REM LOCATE NEXT TAB STOP
    REM SET I TO DESIRED VALUE OF CURSORCOL AFTER TAB INSERTED
    I=IF I>LEN(TABS$) THEN CURSORCOL+1 ELSE TABS$[I] FI
    REM CHECK FOR TAB PAST MARGINS
    IF I>EDITRIGHTMARGIN OR I>=SCREENWIDTH THEN EDITLINEILLEGAL
    IF LEN(EDITLINE$)-1>EDITRIGHTMARGIN THEN EDITLINEILLEGAL
    REM LINE IS NOT WIDER THAN MARGINS
    IF CURSORCOL<LEN(EDITLINE$)
    THEN
        REM INSERTING TAB IN MIDDLE OF LINE
        INSERTEDBLANKCOUNT=I-CURSORCOL
        IF LEN(EDITLINE$)+INSERTEDBLANKCOUNT>=MAXLEN(EDITLINE$)
        THEN EDITLINEILLEGAL \ ! EDITLINE$ IS FULL
        REM NOW INSERT THE BLANKS IN THE LINE
        LET LEN(EDITLINE$)=LEN(EDITLINE$)+INSERTEDBLANKCOUNT
        LET RIGHT$(EDITLINE$,EDITLINEPTR+INSERTEDBLANKCOUNT)=...
&           EDITLINE$[EDITLINEPTR,...
&                     (LEN(EDITLINE$)-INSERTEDBLANKCOUNT)-EDITLINEPTR+1]
        LET EDITLINE$[EDITLINEPTR,INSERTEDBLANKCOUNT]=...
&           BLANKS$[1,INSERTEDBLANKCOUNT]
        IF LEN(EDITLINE$)>SCREENWIDTH
        THEN PRINT EDITLINE$[EDITLINEPTR,SCREENWIDTH-1-CURSORCOL];
        ELSE PRINT EDITLINE$[EDITLINEPTR,LEN(EDITLINE$)-EDITLINEPTR];
        LET EDITLINEPTR=I+1
        LET CURSORCOL=I
        IF CURSORCOL<>LEN(EDITLINE$)-1 THEN GOSUB POSITIONCURSOR FI
    ELSE
        REM INSERTING TAB PAST END OF LINE
        INSERTEDBLANKCOUNT=I-LEN(EDITLINE$)+1
        IF LEN(EDITLINE$)+INSERTEDBLANKCOUNT>=MAXLEN(EDITLINE$)
        THEN EDITLINEILLEGAL \ ! EDITLINE$ IS FULL
        REM NOW INSERT THE BLANKS IN THE LINE
        LET LEN(EDITLINE$)=LEN(EDITLINE$)+INSERTEDBLANKCOUNT
        LET EDITLINE$[LEN(EDITLINE$)-INSERTEDBLANKCOUNT,INSERTEDBLANKCOUNT]=...
&           BLANKS$[1,INSERTEDBLANKCOUNT]
        LET EDITLINE$[LEN(EDITLINE$)]=CR
        LET EDITLINEPTR=LEN(EDITLINE$)
        LET CURSORCOL=I
        GOSUB POSITIONCURSOR
    FI
    GOTO EDITLINELOOP
!^L
EDITLINEGOLEFT: REM HANDLE BACKSPACE
    IF CURSORCOL=0 THEN EDITLINEQUIT
    IF LEN(EDITLINE$)<=CURSORCOL
    THEN
        FOR I=LEN(EDITLINE$) TO CURSORCOL DO PRINT BACKSPACE$;
        LET EDITLINEPTR=LEN(EDITLINE$)
        LET CURSORCOL=EDITLINEPTR-1
    ELSE
        PRINT BACKSPACE$;
        LET CURSORCOL=CURSORCOL-1
        LET EDITLINEPTR=EDITLINEPTR-1
    FI
    GOTO EDITLINELOOP

EDITLINEGORIGHT: REM HANDLE GORIGHT CHARACTER
    IF CURSORCOL=SCREENWIDTH-1 THEN EDITLINEILLEGAL
    LET CURSORCOL=CURSORCOL+1
    LET EDITLINEPTR=EDITLINEPTR+1
    GOSUB POSITIONCURSOR
    GOTO EDITLINELOOP
!^L
EDITLINERUBOUT: REM HANDLE RUBOUT WITHIN LINE BEING EDITED
    IF CURSORCOL=0 THEN EDITLINEQUIT \ ! UNDER ALL CIRCUMSTANCES!
    IF CURSORCOL>=LEN(EDITLINE$)
    THEN
        ! JUST BACKSPACE
        CURSORCOL=CURSORCOL-1
        EDITLINEPTR=EDITLINEPTR-1
        PRINT BACKSPACE$;
        GOTO EDITLINELOOP
    FI
    REM CHECK FOR RUBOUT LEFTMARGIN GAP
    IF CURSORCOL=LEFTMARGIN
    THEN
        REM WANTS TO DELETE INTO LEFTMARGIN
        FOR I=1 TO LEFTMARGIN
            IF EDITLINE$[I]<>BLANK THEN EDITLINERUBOUT1
        NEXT I
        REM LEFTMARGIN IS COMPLETELY BLANK! TIME TO DELETE IT
        GOTO EDITLINEQUIT \ ! AND LET SEDIT HANDLE IT
    FI
 EDITLINERUBOUT1: REM REALLY DO IT!
    REM IDENTICAL IN FUNCTION TO "BS" "<CONTROL-U>"
    LET CURSORCOL=CURSORCOL-1
    LET EDITLINEPTR=EDITLINEPTR-1
    PRINT BACKSPACE$;
EDITLINEDELETEUNDERCURSOR: REM DELETE CHARACTER UNDER CURSOR
    REM MOVE REST OF LINE TO LEFT ONE CHARACTER SLOT
    IF CURSORCOL>=LEN(EDITLINE$) OR CURSORCOL=SCREENWIDTH-1
    THEN EDITLINEILLEGAL \ REM WANTS TO DELETE PAST END OF LINE
    IF EDITLINE$(EDITLINEPTR)=CR THEN EDITLINEQUIT
    REM EASY CASE-- NOT DELETEING <CR>
    LET EDITLINE$[EDITLINEPTR,LEN(EDITLINE$)-EDITLINEPTR]=...
&       RIGHT$(EDITLINE$,EDITLINEPTR+1)
    LET LEN(EDITLINE$)=LEN(EDITLINE$)-1
    IF LEN(EDITLINE$)>=SCREENWIDTH
    THEN PRINT EDITLINE$[EDITLINEPTR,SCREENWIDTH-1-CURSORCOL];
    ELSE PRINT EDITLINE$[EDITLINEPTR,LEN(EDITLINE$)-1-CURSORCOL];" ";
    GOSUB POSITIONCURSOR
    GOTO EDITLINELOOP
!^L
EDITLINECANCELLINE: REM HANDLE <CONTROL-X> (CANCEL LINE)
    LET CURSORCOL=0
    LET EDITLINEPTR=1
    GOSUB POSITIONCURSOR
EDITLINEERASETOEOL: REM HANDLE ERASE TO END-OF-LINE
    IF CURSORCOL>=LEN(EDITLINE$)+1 THEN EDITLINEILLEGAL
    IF LEN(EDITLINE$)>=SCREENWIDTH
    THEN PRINT BLANKS$[1,SCREENWIDTH-1-CURSORCOL];
    ELSE PRINT BLANKS$[1,LEN(EDITLINE$)-1-CURSORCOL];
    GOSUB POSITIONCURSOR
    LET EDITLINE$[CURSORCOL+1]=CR
    LET LEN(EDITLINE$)=CURSORCOL+1
    GOTO EDITLINELOOP
!^L
EDITLINEINSERTCHAR: REM HANDLE IMPLIED CHARACTER INSERT IN LINE BEING EDITED
    IF CURSORCOL>EDITRIGHTMARGIN OR CURSORCOL=SCREENWIDTH-1
    THEN EDITLINEQUIT\!Can't handle this here
Rem special handling needed if Tabs are present!
    REM IF DISPLAYEDWIDTH OF EDITLINE>=EDITRIGHTMARGIN THEN EDITLINEQUIT
    IF LEN(EDITLINE$)-1>EDITRIGHTMARGIN THEN EDITLINEQUIT
    REM LINE IS NOT WIDER THAN MARGINS
    INSERTEDBLANKCOUNT=...
&       IF CURSORCOL>=LEN(EDITLINE$)
        THEN CURSORCOL-LEN(EDITLINE$)+1 ELSE 0 FI
    IF LEN(EDITLINE$)+INSERTEDBLANKCOUNT>=MAXLEN(EDITLINE$)
    THEN GOTO EDITLINEILLEGAL \ REM EDITLINE$ IS FULL
    IF INSERTEDBLANKCOUNT>0
    THEN
        REM EXTEND EDITLINE$ WITH BLANKS
        LET LEN(EDITLINE$)=LEN(EDITLINE$)+INSERTEDBLANKCOUNT
        LET EDITLINE$[LEN(EDITLINE$)-INSERTEDBLANKCOUNT,INSERTEDBLANKCOUNT]=...
&           BLANKS$[1,INSERTEDBLANKCOUNT]
        LET EDITLINE$[LEN(EDITLINE$)]=CR
        LET EDITLINEPTR=LEN(EDITLINE$)
    FI
    REM INSERT THE CHARACTER INTO THE EDIT LINE BUFFER
    LET LEN(EDITLINE$)=LEN(EDITLINE$)+1
    LET EDITLINE$[EDITLINEPTR+1,LEN(EDITLINE$)-EDITLINEPTR]=...
&       EDITLINE$[EDITLINEPTR,LEN(EDITLINE$)-EDITLINEPTR]
    LET EDITLINE$[EDITLINEPTR]=CHARACTER
    IF LEN(EDITLINE$)>SCREENWIDTH
    THEN PRINT EDITLINE$[EDITLINEPTR,SCREENWIDTH-1-CURSORCOL];
    ELSE PRINT EDITLINE$[EDITLINEPTR,LEN(EDITLINE$)-1-CURSORCOL];
    CURSORCOL=CURSORCOL+1
    IF CURSORCOL<>LEN(EDITLINE$)-1 THEN GOSUB POSITIONCURSOR
    LET EDITLINEPTR=EDITLINEPTR+1
    GOTO EDITLINELOOP

REM END OF EDITLINE SUBROUTINE
END

!*********THIS TEXT NEEDS TO BE MOVED!
    REM RIGHTMARGIN gives 0-origin column number of last legal place to put char
    REM Assert: RIGHTMARGIN <> SCREENWIDTH-1
!*********

!^L
DEF ISROOM(ISROOMDESIRED)
    REM THIS SUBROUTINE MAKES SURE THAT "ISROOMDESIRED" BYTES
    REM ARE AVAILABLE IN TEXT$ WITHOUT MOVING CURSORTEXTBASEPTR
ISROOMLOOP: REM NOT ENOUGH ROOM, PERHAPS DUMPING 1ST SCREEN WILL HELP
    IF MAXLEN(TEXT$)-LEN(TEXT$)>=ISROOMDESIRED THEN RETURN TRUE
    IF (CURSORTEXTBASEPTR-1)+(MAXLEN(TEXT$)-LEN(TEXT$))<ISROOMDESIRED
    THEN RETURN FALSE
    GOSUB DUMPFIRSTSCREEN
    GOTO ISROOMLOOP
END

INSERTTAB: REM INSERT A TAB CHARACTER
    GOTO EDITCURRENTLINE

CANCELLINE: REM HANDLE <CANCEL> KEY
ERASETOEOL: REM HANDLE <CONTROL-E> KEY
EDITCURRENTLINE: REM EDIT THE LINE AT CURSORTEXTLINEPTR IN THE TEXT$ BUFFER
    REM FIRST VERIFY THAT TEXT$ HAS ENOUGH ROOM TO HOLD MAXLEN(LINE$)
    IF NOT ISROOM(MAXLEN(LINE$)) THEN ILLEGAL
REM **************
REM HERE WE SHOULD DROP THE FIRST LINE OFF THE BEGINNING OF THE BUFFER
REM AND CHECK TO SEE IF THERE IS ENOUGH ROOM; REPEAT UNTIL NO MORE LINES
REM CAN BE DROPPED. NOTE THAT WE CAN STILL END UP WITH NO AVAILABLE SPACE
REM **************
    REM EXTRACT LINE TO BE EDITED FROM TEXT$
    REM LINE$ INCLUDES THE <CR>
    REM LEAVE HOLE WHERE LINE$ WAS EXTRACTED
    IF CURSORTEXTLINELENGTH>=MAXLEN(LINE$) THEN ILLEGAL
    LET LINE$=TEXT$(CURSORTEXTLINEPTR,CURSORTEXTLINELENGTH+1)
    LET CURSORLINEPTR=CURSORTEXTPTR-CURSORTEXTLINEPTR+1
    REM LINE$ HOLDS THE TEXT TO BE EDITED
    REM THE LINE HAS BEEN REMOVED FROM TEXT$
    REM ASSERT: LEN(TEXT$)+LEN(LINE$)<=MAXLEN(TEXT$)
    REM CURSORTEXTLINEPTR REMEMBERS WHERE THE LINE$ BELONGS IN TEXT$
    EDITLINE(LINE$,CURSORLINEPTR,LEFTMARGIN,RIGHTMARGIN)
EDITCURRENTLINEQUIT: REM LOOKS LIKE LINE EDITING IS COMPLETE, PUT LINE$ BACK INTO TEXT$
    REM FILL UP HOLE WHERE LINE$ WAS EXTRACTED FROM
    REM SUPRESS TRAILING BLANKS
    WHILE LEN(LINE$)>1 AND LINE$(LEN(LINE$)-1)=BLANK DO
          LEN(LINE$)=LEN(LINE$)-1
    END
    LINE$(LEN(LINE$))=CR
    ADJUSTHOLESIZE(CURSORTEXTLINEPTR,CURSORTEXTLINELENGTH+1,LEN(LINE$))
    LET TEXT$[CURSORTEXTLINEPTR,LEN(LINE$)]=LINE$
    LET CURSORTEXTPTR=CURSORTEXTLINEPTR+CURSORLINEPTR-1
    LET CURSORTEXTLINELENGTH=LEN(LINE$)-1
    LET ROWWIDTH(CURSORROW)=...
&       IF CURSORTEXTLINELENGTH<SCREENWIDTH
        THEN CURSORTEXTLINELENGTH ELSE SCREENWIDTH-1 FI
    GOTO INSPECTCHARACTER
!^L
INSERTCHARACTER: REM HANDLE IMPLIED CHARACTER INSERT (<TAB>, <CR> NOT INCLUDED)
    IF FIND(TEXT$[CURSORTEXTLINEPTR,CURSORTEXTLINELENGTH],TAB$)=0 ...
&      AND CURSORCOL<=RIGHTMARGIN AND CURSORTEXTLINELENGTH<=RIGHTMARGIN...
&      AND CURSORCOL<SCREENWIDTH-1
    THEN EDITCURRENTLINE \ ! IT IS OK TO LET EDITCURRENTLINE INSERT A CHARACTER
    IF NOT ISROOM(1) THEN ILLEGAL \ ! WE HAVE TO HAVE SOMEPLACE TO PUT IT!
    IF FIND(TEXT$[CURSORTEXTLINEPTR,CURSORTEXTLINELENGTH],TAB$)
    THEN ILLEGAL \ !<TAB> IS PRESENT, THIS CODE NOT IMPLEMENTED!
    REM NO <TAB>S PRESENT IN THIS LINE
    IF CURSORCOL=SCREENWIDTH-1 AND...
&      (RIGHTMARGIN=RMARGININFINITY OR CHARACTER<>BLANK)
    THEN ILLEGAL \!Can't insert at SCREENWIDTH-1
    IF CURSORCOL>CURSORTEXTLINELENGTH
    THEN
        REM SIGH... MUST INSTALL BLANKS BEFORE INSERTING CHARACTER
        INSERTEDBLANKCOUNT=CURSORCOL-CURSORTEXTLINELENGTH
        IF NOT ISROOM(INSERTEDBLANKCOUNT+1) THEN ILLEGAL
        ADJUSTHOLESIZE(CURSORTEXTLINEPTR+CURSORTEXTLINELENGTH,...
&                      0,INSERTEDBLANKCOUNT)\! ALSO SHUFFLES <CR> TO MAKE ROOM
        LET TEXT$[CURSORTEXTLINEPTR+CURSORTEXTLINELENGTH,INSERTEDBLANKCOUNT]=...
&           BLANKS$[1,INSERTEDBLANKCOUNT]
        LET CURSORTEXTLINELENGTH=CURSORTEXTLINELENGTH+INSERTEDBLANKCOUNT
        REM NOW CURSORTEXTPTR IS VALID
    FI
    IF CURSORTEXTLINELENGTH>RIGHTMARGIN+1 THEN INSERTTHENADJUSTMARGINS
    IF CURSORCOL>RIGHTMARGIN+1 THEN ILLEGAL \ ! Can't insert past RIGHTMARGIN
    IF CURSORCOL<=RIGHTMARGIN THEN INSERTTHENADJUSTMARGINS
    Rem ASSERT: CURSORCOL=RIGHTMARGIN+1
    IF CHARACTER=BLANK THEN INSERTCR \ ! INSTEAD OF THE BLANK!
INSERTTHENADJUSTMARGINS: ! INSERT CHARACTER, THEN FORCE MARGINS TO FIT
    ADJUSTHOLESIZE(CURSORTEXTPTR,0,1) \ ! INSERT THE CHARACTER
    LET TEXT$[CURSORTEXTPTR]=CHARACTER
    LET CURSORTEXTPTR=CURSORTEXTPTR+1 \ ! ADVANCE PAST IT
    REM ADJUST MARGINS UNTIL A PARAGRAPH BREAK IS REACHED
    CALL MAKEFITMARGINS(CURSORTEXTLINEPTR,CURSORTEXTPTR,0)
    GOSUB DISPLAYPAGEFROMCURSORROW \ ! UPDATE THE SCREEN
    UNTIL CURSORTEXTPTR<CURSORTEXTLINEPTR+...
&                       FIND(RIGHT$(TEXT$,CURSORTEXTLINEPTR),CR$) DO
        REM CURSORTEXTPTR IS NO LONGER IN THE LINE WHERE INSERT OCCURRED
        LET CURSORTEXTLINEPTR=CURSORTEXTLINEPTR+...
&                             FIND(RIGHT$(TEXT$,CURSORTEXTLINEPTR),CR$)
        IF CURSORROW<SCREENDEPTH-1
        THEN CURSORROW=CURSORROW+1
        ELSE
            REM LINE BREAKOFF OCCURRED AT BOTTOM LINE OF SCREEN
            REM SO WE NEED TO ROLL SCREEN UP ONE LINE, DISPLAY NEW LINE,
            REM AND FIDDLE ALL THE CONTEXT POINTERS
            PRINT \ ! ROLLS SCREEN UP ONE LINE
            LET CURSORTEXTBASEPTR=CURSORTEXTBASEPTR+...
&               FIND(RIGHT$(TEXT$,CURSORTEXTBASEPTR),CR$)
            FOR I=0 TO SCREENDEPTH-2 DO ROWWIDTH(I)=ROWWIDTH(I+1)
            LET CURSORTEXTLINELENGTH=...
&               FIND(RIGHT$(TEXT$,CURSORTEXTLINEPTR),CR$)-1
            LET ROWWIDTH(SCREENDEPTH-1)=...
&               IF CURSORTEXTLINELENGTH<SCREENWIDTH
                THEN CURSORTEXTLINELENGTH ELSE SCREENWIDTH-1 FI
            PRINT @(CURSORROW,0),...
&                 TEXT$(CURSORTEXTLINEPTR,ROWWIDTH(SCREENDEPTH-1));
        FI
    END \ ! UNTIL
    LET CURSORTEXTLINELENGTH=FIND(RIGHT$(TEXT$,CURSORTEXTLINEPTR),CR$)-1
    LET CURSORCOL=CURSORTEXTPTR-CURSORTEXTLINEPTR \ ! NEW CURSOR POSITION
    GOSUB POSITIONCURSOR
    GOTO NEXTCMD
!^L
REM    HERE'S SOMETHING WE MIGHT DO SOMEDAY...
REM    AFTER INSERTING <CR>,
REM    IF LEFTMARGIN>0
REM    THEN
REM        REM NOW INSERT LEFT MARGIN TAB IF LMARGIN IS ACTIVATED
REM        IF INTELLIGENTTABS
REM        THEN PEEK AT PREVIOUS LINE TO GET TAB DISTANCE
REM        INSERTEDBLANKCOUNT=....
REM    FI

INSERTCR: REM HANDLE INSERTED <CR>
    REM WHEN INSERTING <CR>, RIGHT MARGIN IS UNIMPORTANT!
    REM AFTER INSERTING <CR>, INSERT LEFTMARGIN BLANKS
    IF NOT ISROOM(LEFTMARGIN+1) THEN ILLEGAL
    REM DO AN ERASE TO END OF LINE BY PADDING CURRENT LINE WITH BLANKS
    IF CURSORTEXTLINELENGTH>CURSORCOL
    THEN IF CURSORTEXTLINELENGTH>=SCREENWIDTH
         THEN PRINT BLANKS$(1,SCREENWIDTH-1-CURSORCOL)
         ELSE PRINT BLANKS$[1,CURSORTEXTLINELENGTH-CURSORCOL)
    ELSE
        REM CURSOR IS PAST END OF LINE; CURSORTEXTPTR IS INVALID
        LET CURSORTEXTPTR=CURSORTEXTLINEPTR+CURSORTEXTLINELENGTH
        PRINT
    FI
    REM NOW CURSOR IS ON LINE FOLLOWING THE INSERT
    REM REMOVE EXTRANEOUS BLANKS PRECEDING PLACE TO INSERT <CR>
    FOR I=CURSORTEXTPTR-1 TO CURSORTEXTLINEPTR STEP -1
        IF TEXT$[I]<>BLANK THEN EXIT I
    NEXT I
    LET I=CURSORTEXTPTR-I-1\! NUMBER OF BLANKS TO REMOVE
    LET ROWWIDTH(CURSORROW)=ROWWIDTH(CURSORROW)-I
    LET CURSORTEXTPTR=CURSORTEXTPTR-I
    REM INSERT THE CR INTO THE TEXT BUFFER
    ADJUSTHOLESIZE(CURSORTEXTPTR,I,1+LEFTMARGIN)
    LET TEXT$[CURSORTEXTPTR]=CR
    LET CURSORTEXTLINEPTR=CURSORTEXTPTR+1
    LET TEXT$[CURSORTEXTLINEPTR,LEFTMARGIN]=BLANKS$[1,LEFTMARGIN]
    LET CURSORTEXTPTR=CURSORTEXTLINEPTR+LEFTMARGIN
    LET CURSORROW=CURSORROW+1
    LET CURSORCOL=CURSORTEXTPTR-CURSORTEXTLINEPTR
    LET CURSORTEXTLINELENGTH=FIND(RIGHT$(TEXT$,CURSORTEXTLINEPTR),CR$)-1
    IF CURSORROW=SCREENDEPTH
    THEN
        REM INSERT AT BOTTOM OF SCREEN
        REM SCREEN HAS ROLLED UP ONE LINE
        LET CURSORROW=SCREENDEPTH-1
        LET CURSORTEXTBASEPTR=CURSORTEXTBASEPTR+...
&       FIND(RIGHT$(TEXT$,CURSORTEXTBASEPTR),CR$)
        FOR I=0 TO SCREENDEPTH-2 DO ROWWIDTH(I)=ROWWIDTH(I+1)
        LET ROWWIDTH(SCREENDEPTH-1)=...
&           IF CURSORTEXTLINELENGTH<SCREENWIDTH
            THEN CURSORTEXTLINELENGTH ELSE SCREENWIDTH-1 FI
        PRINT TEXT$(CURSORTEXTLINEPTR,ROWWIDTH(SCREENDEPTH-1));
        GOSUB POSITIONCURSOR
    ELSE
        REM INSERT WAS NOT ON BOTTOM LINE OF SCREEN
        GOSUB DISPLAYPAGEFROMCURSORROW
    FI
    GOTO NEXTCMD
!^L
DELETEUNDERCURSOR:
    IF TEXT$[CURSORTEXTPTR]<>CR THEN EDITCURRENTLINE
    REM DELETING <CR>
    IF CURSORTEXTPTR=LEN(TEXT$) THEN ILLEGAL
    ADJUSTHOLESIZE(CURSORTEXTPTR,1,0)
    REM ADJUST TO FIT MARGINS IF LINE IS TOO LONG
    CALL MAKEFITMARGINS(CURSORTEXTLINEPTR,CURSORTEXTPTR,0)
    GOSUB DISPLAYPAGEFROMCURSORROW
    GOSUB SETUPLINECONTEXT
    GOSUB POSITIONCURSOR
    GOTO NEXTCMD

RUBOUT: REM HANDLE <RUBOUT>
    REM USER WANTS TO MODIFY THIS LINE
    IF CURSORCOL>0
    THEN
        IF CURSORCOL<>LEFTMARGIN THEN EDITCURRENTLINE
        REM USER WANTS TO DELETE LEFTMARGIN GAP AND PRECEDING <CR>
        REM VERIFY THAT LEFTMARGIN GAP IS BLANK-FILLED
        FOR I=CURSORTEXTLINEPTR TO CURSORTEXTLINEPTR+LEFTMARGIN-1
            IF TEXT$[I]=CR THEN EXIT I \ ! TO HANDLE MAL-FORMED BLANK LEFTMARGINS
            IF TEXT$[I]<>BLANK THEN EDITCURRENTLINE
        END
        REM LEFTMARGIN GAP IS COMPLETELY BLANK, DELETE IT
        LET CURSORTEXTPTR=CURSORTEXTLINEPTR
        ADJUSTHOLESIZE(CURSORTEXTPTR,I-CURSORTEXTLINEPTR,0)
        REM HANDLE SPECIAL CASE OF TRY TO DELETE LEFTMARGIN AT BEGIN TEXT WINDOW
        IF CURSORTEXTPTR=1
        THEN
            CURSORCOL=0 \ ! THIS IS WHERE THE CURSOR WENT
            GOSUB POSITIONCURSOR
            GOTO NEXTCMD
        FI
    FI
    REM MUST GO BACK TO END OF PREVIOUS LINE, AND RUBOUT THE GAP AND THE <CR>
    IF CURSORTEXTPTR=1 THEN ILLEGAL
    LET CURSORTEXTPTR=CURSORTEXTPTR-1
    ADJUSTHOLESIZE(CURSORTEXTPTR,1,0) \ ! RIP OUT THE <CR>
    IF CURSORROW>0
    THEN
        CURSORROW=CURSORROW-1
        LET CURSORTEXTLINEPTR=FINDBEGINLINE(CURSORTEXTPTR)
        REM ADJUST TO FIT MARGINS IF LINE IS TOO LONG
        CALL MAKEFITMARGINS(CURSORTEXTLINEPTR,CURSORTEXTPTR,0)
        REM AFTER DELETE, CURSOR IS STILL ON SCREEN
        GOSUB DISPLAYPAGEFROMCURSORROW
        GOSUB SETUPLINECONTEXT
        GOSUB POSITIONCURSOR
    ELSE
        REM DELETING A CHARACTER ON A PREVIOUS SCREEN
        CALL MAKEFITMARGINS(CURSORTEXTPTR,CURSORTEXTPTR,0)
        GOSUB SETUPCURSORCONTEXT
        GOSUB CLEARSCREENDISPLAYPAGE
    FI
    GOTO NEXTCMD

!^L
ESCAPECR:   REM ESC <CR>
    CURSORCOL=LEFTMARGIN
    LET CURSORTEXTPTR=CURSORTEXTLINEPTR+CURSORCOL
    GOSUB POSITIONCURSOR
    GOTO NEXTCMD

ESCAPEQM: REM ESCAPE ?
    IF CURSORCOL>=CURSORTEXTLINELENGTH
    THEN CURSORTEXTPTR=CURSORTEXTLINEPTR+CURSORTEXTLINELENGTH
    GOTO DISPLAYNEWCONTEXT

SUBROUTINE COLLECTSTRING(COLLECTEDSTRING$)
    REM COLLECT A SINGLE LINE OF TEXT INTO COLLECTEDSTRING$
    REM COLLECTEDSTRING$ ALWAYS HAS DUMMY <CR> ADDED ON THE END
    LET LEN(COLLECTEDSTRING$)=LEN(COLLECTEDSTRING$)+1
    LET COLLECTEDSTRING$(LEN(COLLECTEDSTRING$))=CR
    LET SAVECURSORCOL=CURSORCOL
    REM DISPLAY COLLECTEDSTRING ON SAME ROW AS CURSOR
    POSITION #0@(CURSORROW,0)
    IF LEN(COLLECTEDSTRING$)>=SCREENWIDTH
    THEN PRINT COLLECTEDSTRING$[1,SCREENWIDTH-1];
    ELSE
        PRINT COLLECTEDSTRING$[1,LEN(COLLECTEDSTRING$)-1];
        IF ROWWIDTH(CURSORROW)>=LEN(COLLECTEDSTRING$)
        THEN PRINT BLANKS$[1,ROWWIDTH(CURSORROW)-(LEN(COLLECTEDSTRING$)-1)];
    FI
    REM GO EDIT THE STRING
    LET CURSORCOL=0
    POSITION #0@(CURSORROW,CURSORCOL)
    CURSORLINEPTR=1
COLLECTSTRINGLOOP:
    LET CHARACTER=0 \ ! THE IGNORED COMMAND
    EDITLINE(COLLECTEDSTRING$,CURSORLINEPTR,0,RMARGININFINITY)
    IF CHARACTER<>:1B THEN PRINT BEEP$;\GOTO COLLECTSTRINGLOOP
    GOSUB REPAINTCURRENTLINE
    REM STRIP OFF DUMMY <CR> ON END OF COLLECTEDSTRING$
    LET LEN(COLLECTEDSTRING$)=LEN(COLLECTEDSTRING$)-1
    LET CURSORCOL=SAVECURSORCOL
    GOSUB POSITIONCURSOR
    RETURN SUBROUTINE
END

!^L
ESCAPEF: REM ESC F: FIND STRING IN TEXT BUFFER
    LET ANCHOREDSEARCHFLAG=(ARGUMENT=1)
    COLLECTSTRING(FINDSTRING$)
    LET FINDLONG=FALSE
ESCAPEN: REM ESC N   FIND NEXT OCCURRENCE OF STRING (EVEN ACROSS BUFFERS)
    WINDOWMOVED=FALSE
    GOSUB FINDNEXT
    IF FOUND=FALSE THEN PRINT BEEP$;
FINDDONE: REM FIND IS COMPLETED, NOW DISPLAY NEW CONTEXT
    REM CHECK TO SEE IF IN SAME DISPLAYED PAGE
    IF WINDOWMOVED THEN DISPLAYNEWCONTEXT
    LET I=CURSORTEXTBASEPTR
    LET I0=I
    FOR CURSORROW=0 TO SCREENDEPTH-1 UNTIL I>=LEN(TEXT$)
        LET I=I+FIND(RIGHT$(TEXT$,I),CR$)
        IF I0<=CURSORTEXTPTR AND CURSORTEXTPTR<I
        THEN
            REM FOUND STRING IN SAME PAGE
            CURSORTEXTLINEPTR=FINDBEGINLINE(CURSORTEXTPTR)
            CURSORTEXTLINELENGTH=FIND(RIGHT$(TEXT$,CURSORTEXTLINEPTR),CR$)-1
            LET CURSORCOL=CURSORTEXTPTR-CURSORTEXTLINEPTR
            IF CURSORCOL>=SCREENWIDTH
            THEN
                REM FOUND STRING, BUT CAN'T PLACE CURSOR OFF SCREEN
                PRINT BEEP$;
                LET CURSORCOL=SCREENWIDTH-1
                LET CURSORTEXTPTR=CURSORTEXTLINEPTR+CURSORCOL
            FI
            GOSUB POSITIONCURSOR
            GOTO NEXTCMD
        FI
    NEXT CURSORROW
    REM FOUND STRING ISN'T ON CURRENTLY DISPLAYED PAGE
DISPLAYNEWCONTEXT: REM CURSORTEXTPTR MOVED, SET UP AND DISPLAY NEW CONTEXT
    GOSUB SETUPCURSORCONTEXT
    GOSUB CLEARSCREENDISPLAYPAGE
    GOTO NEXTCMD
!^L
DEF FINDSTRINGINBUFFER(FINDSTART)
    REM SEARCH FOR FINDSTRING$ IN BUFFER BEGINNING AT FINDSTART
    REM RETURNS "0" IF NOT FOUND IN BUFFER; PTR TO STRING IF FOUND
    REM IF ANCHOREDSEARCHFLAG = TRUE, THEN ONLY LOOK IN "LABEL" FIELD
    LET I=FINDSTART \ ! REMEMBER "LAST" PLACE WE FOUND THE STRING
    REPEAT
        REM ASSERT: I POINTS TO LAST PLACE THAT STRING WAS FOUND IN BUFFER
        LET I0=FIND(RIGHT$(TEXT$,I+1),FINDSTRING$) \ ! FIND NEXT IN BUFFER
        IF I0=0 THEN...
&          IF I>FINDSTART AND ( ANCHOREDSEARCHFLAG=FALSE OR TEXT$[I-1]=CR )
           THEN RETURN I ELSE RETURN 0 \ ! NOT FOUND
        LET I=I+I0 \ ! MAKE I POINT TO NEWLY FOUND OCCURRENCE OF STRING
    WHEN ANCHOREDSEARCHFLAG AND TEXT$[I-1]<>CR END
    RETURN I
    END

FINDNEXT: REM FIND NEXT OCCURRENCE OF STRING
    REM MUST RE-POSITION CURSOR IF WINDOWMOVED=FALSE; ELSE MUST REPAINT SCREEN
    REM IF CURSOR IS PAST END OF LINE, FORCE IT TO END BEFORE SEARCHING
    IF CURSORCOL>CURSORTEXTLINELENGTH
    THEN CURSORTEXTPTR=CURSORTEXTLINEPTR+CURSORTEXTLINELENGTH
    FOUND=FALSE
    IF LEN(FINDSTRING$)=0 THEN RETURN \ ! GET RID OF STUPID EDGE CONDITION
    REPEAT
        LET I=FINDSTRINGINBUFFER(CURSORTEXTPTR)
        IF I>0 THEN LET CURSORTEXTPTR=I\FOUND=TRUE\RETURN
        IF FINDLONG=FALSE THEN FINDLONG=TRUE \ RETURN
        REM SEARCH ACROSS TEXT BUFFER BOUNDARIES
        IF EOF(FILE) THEN RETURN \ REM WITH FOUND=FALSE
        LET WINDOWMOVED=TRUE
        LET CURSORTEXTBASEPTR=LEN(TEXT$)
        LET CURSORTEXTLINEPTR=CURSORTEXTBASEPTR
        LET CURSORTEXTPTR=CURSORTEXTLINEPTR
        FOR J=0 TO SCREENDEPTH-1 DO GOSUB GETLINEFROMFILE
        ! HANDLE EDGE CONDITION OF WINDOW MOVED...
        !   AND DESIRED STRING IS 1ST LINE OF NEXT CHUNK OF TEXT
        IF FIND(RIGHT$(TEXT$,CURSORTEXTPTR),FINDSTRING$)=1
        THEN FOUND=TRUE\RETURN
    END

!^L
ESCAPEA: REM ESC A
    LET CURSORTEXTPTRSAVE=CURSORTEXTPTR
    GOSUB CHANGENEXT
    WINDOWMOVED=FALSE
    GOSUB FINDNEXT
    IF FOUND=FALSE THEN PRINT BEEP$;
    IF WINDOWMOVED THEN DISPLAYNEWCONTEXT
    GOTO DISPLAYAFTERINSERT

ESCAPEC: REM ESC C
    COLLECTSTRING(CHANGETOSTRING$)
    GOSUB CHANGENEXT
    GOTO SETUPLINECONTEXTDISPLAYRESTOFPAGE

CHANGENEXT: REM CHANGE FOUND OCCURRENCE OF STRING
    IF FIND(RIGHT$(TEXT$,CURSORTEXTPTR),FINDSTRING$)<>1
    THEN GOSUB POP 1\ GOTO ILLEGAL
    IF LEN(TEXT$)-LEN(FINDSTRING$)+LEN(CHANGETOSTRING$)>MAXLEN(TEXT$)
    THEN
        GOSUB DUMPFIRSTSCREEN
        IF LEN(TEXT$)-LEN(FINDSTRING$)+LEN(CHANGETOSTRING$)>MAXLEN(TEXT$)
        THEN ILLEGAL FI
    FI
    ADJUSTHOLESIZE(CURSORTEXTPTR,LEN(FINDSTRING$),LEN(CHANGETOSTRING$))
    LET TEXT$[CURSORTEXTPTR,LEN(CHANGETOSTRING$)]=CHANGETOSTRING$
    RETURN

!^L
ESCAPED: REM ESCAPE D -- DELETE WORD
    IF CURSORCOL>CURSORTEXTLINELENGTH THEN ILLEGAL \ ! IN EMPTY SPACE
    IF ARGUMENT=0 THEN ARGUMENT=1
    REM WORD IS ALL ALPHA$ STUFF FROM CURSORTEXTPTR TO ...
    IF FIND(ALPHA$,TEXT$(CURSORTEXTPTR,1))=0 THEN ILLEGAL
    LET I=CURSORTEXTPTR+1
    FOR CMDITERATION=1 TO ARGUMENT-1
        REM FIND END OF WORD TO BE DELETED
        WHILE FIND(ALPHA$,TEXT$(I,1))<>0 DO I=I+1 END
        REM FIND BEGINNING OF NEXT WORD
        WHILE FIND(ALPHA$,TEXT$(I,1))=0 DO
            REM CHECK TO MAKE SURE WE AREN'T DELETING OFF END OF TEXT
            IF I=LEN(TEXT$) THEN ILLEGAL
            I=I+1
        END
    NEXT CMDITERATION
    REM FIND END OF WORD ON LAST WORD TO BE DELETED
    WHILE FIND(ALPHA$,TEXT$(I,1))<>0 DO I=I+1 END
    CALL DELETESTRING(CURSORTEXTPTR,I)
SETUPLINECONTEXTDISPLAYRESTOFPAGE:
    GOSUB SETUPLINECONTEXT
    GOSUB DISPLAYPAGEFROMCURSORROW
    GOTO NEXTCMD

ESCAPEK:   REM ESC K
    IF CURSORCOL>CURSORTEXTLINELENGTH OR CURSORTEXTPTR=LEN(TEXT$)
    THEN ILLEGAL
    IF ARGUMENT=0 THEN ARGUMENT=1
    LET I=CURSORTEXTPTR
    FOR CMDITERATION=1 TO ARGUMENT UNTIL I=LEN(TEXT$)
        LET I=FIND(RIGHT$(TEXT$,I),CR$)+I
    NEXT CMDITERATION
    IF CMDITERATION<>ARGUMENT+1 THEN ILLEGAL
    CALL DELETESTRING(CURSORTEXTPTR,I)
53415   REM IF DELETE LAST LINE, SHOULD DO "BS" TO END OF PREV LINE
    REM PRESERVE CR IF AT END OF TEXT
    IF CURSORTEXTPTR=LEN(TEXT$)+1
    THEN LET LEN(TEXT$)=LEN(TEXT$)+1\LET TEXT$(LEN(TEXT$))=CR
    LET CURSORTEXTLINELENGTH=FIND(RIGHT$(TEXT$,CURSORTEXTLINEPTR),CR$)-1
    GOSUB DISPLAYPAGEFROMCURSORROW
    GOTO NEXTCMD

!^L
ESCAPEGOUP:   REM ESC <UP>
    IF ARGUMENT=0 THEN ARGUMENT=1
    FOR CMDITERATION=1 TO ARGUMENT
        FOR J=0 TO SCREENDEPTH-1
            IF CURSORTEXTBASEPTR=1
            THEN
                PRINT BEEP$;
                EXIT CMDITERATION
            FI
            LET CURSORTEXTBASEPTR=FINDBEGINLINE(CURSORTEXTBASEPTR-1)
        NEXT J
    NEXT CMDITERATION
    REM FOUND BEGINNING OF PAGE
ESCAPEUPDOWNDISPLAYPAGE: ! DISPLAY PAGE STARTING AT CURSORTEXTBASEPTR
    ! TRY TO ESTABLISH CURSOR POSITION IN MIDDLE OF PAGE
    LET CURSORTEXTLINEPTR=CURSORTEXTBASEPTR
    LET CURSORCOL=LEFTMARGIN \ ! ASSUME CURSOR COLUMN WILL BE LEFT MARGIN
    FOR CURSORROW=0 TO SCREENDEPTH**-1
        LET CURSORTEXTLINEPTR=CURSORTEXTLINEPTR+...
&                             FIND(RIGHT$(TEXT$,CURSORTEXTLINEPTR),CR$)
        IF CURSORTEXTLINEPTR>LEN(TEXT$)
        THEN
            ! FELL OFF END OF TEXT BUFFER, HANDLE POSSIBLE PARTIAL LAST LINE
            LET CURSORTEXTLINEPTR=FINDBEGINLINE(LEN(TEXT$))
            LET CURSORCOL=LEN(TEXT$)-CURSORTEXTLINEPTR
            EXIT CURSORROW
        FI
    NEXT CURSORROW
    LET CURSORTEXTLINELENGTH=FIND(RIGHT$(TEXT$,CURSORTEXTLINEPTR),CR$)-1
    LET CURSORTEXTPTR=CURSORTEXTLINEPTR+CURSORCOL
    GOSUB CLEARSCREENDISPLAYPAGE
    GOTO NEXTCMD

ESCAPEGODOWN: REM ESC <DOWN>
    IF ARGUMENT=0 THEN ARGUMENT=1
    LET CURSORTEXTPTRSAVE=CURSORTEXTBASEPTR
    FOR CMDITERATION=0 TO ARGUMENT
        LET CURSORTEXTBASEPTR=CURSORTEXTPTRSAVE
        FOR J=0 TO SCREENDEPTH-1
            IF CURSORTEXTPTRSAVE<LEN(TEXT$)
            THEN
                LET CURSORTEXTPTRSAVE=CURSORTEXTPTRSAVE...
&                                     +FIND(RIGHT$(TEXT$,CURSORTEXTPTRSAVE),CR$)
            ELSE
                REM MUST GO DOWN FILE, FINISH OUT THIS PAGE
                GOSUB GETLINEFROMFILE
                LET CURSORTEXTPTRSAVE=LEN(TEXT$)
                IF EOF(FILE)
                THEN
                    PRINT BEEP$;
                    EXIT CMDITERATION
                FI
                IF J=SCREENDEPTH-1 AND CMDITERATION=0 AND ARGUMENT=1
                THEN
                    CURSORTEXTLINEPTR=FINDBEGINLINE(CURSORTEXTPTR-CURSORCOL)
                    GOSUB SETUPLINECONTEXTATENDWINDOW
                    GOSUB DISPLAYPAGEFROMCURSORROW
                    GOTO NEXTCMD
                FI
            FI
        NEXT J
    NEXT CMDITERATION
    GOTO ESCAPEUPDOWNDISPLAYPAGE

!^L
GETLINEFROMFILE: REM FETCH LINE FROM FILE AND INSERT AT END OF TEXT$
    IF LEN(TEXT$)+MAXLEN(LINE$)+1>MAXLEN(TEXT$)
    THEN
        REM NOT ENOUGH ROOM IN BUFFER FOR ANOTHER LINE!
        GOSUB DUMPFIRSTSCREEN \ ! HOPING TO GET SOME SPACE
        IF LEN(TEXT$)+MAXLEN(LINE$)+1>MAXLEN(TEXT$)
        THEN RETURN \ ! CAN'T GET ENOUGH ROOM, DON'T FETCH MORE!
    FI
    IF ERROR WHEN INPUT #FILE,LINE$
    THEN
        IF ERR<>8 THEN DISASTER
        REM SOURCE LINE TOO LONG, LEFT TRUNCATED
        PRINT BEEP$;
        LET LINE$=SOURCELINETOOLONG$
    FI
    ON ERROR GOTO DISASTER
    IF EOF(FILE) THEN RETURN
GETLINEFROMFILE1: REM INSERT NEW LINE INTO TEXT BUFFER
    WHILE FIND(LINE$,TAB$) DO
          REM *** UNTIL WE CAN HANDLE TABS, EXPAND THEM INTO SPACES! ***
          LET I0=FIND(LINE$,TAB$)
          LET I=8-((I0-1)&7) \ ! # SPACES TO REPLACE THE TAB, ASSERT: I>0
          IF MAXLEN(LINE$)<LEN(LINE$)+I-1
          THEN LET LINE$(I)=BLANK
          ELSE
              ! STUFF IN "I" BLANKS WHERE TAB$ USED TO BE...
              LET LEN(LINE$)=LEN(LINE$)+I-1 \ ! EXPAND THE LINE
              LET RIGHT$(LINE$,I0+I)=RIGHT$(LINE$,I0+1) \ ! MAKE BLANK ROOM
              LET LINE$[I0,I]=BLANKS$[1,I]
          FI
    END
    LET I=LEN(TEXT$)
    LET LEN(TEXT$)=LEN(TEXT$)+LEN(LINE$)+1
    LET TEXT$(I,LEN(LINE$))=LINE$
    LET TEXT$(LEN(TEXT$)-1)=CR
    LET TEXT$(LEN(TEXT$))=CR
    RETURN

DUMPFIRSTSCREEN: REM DUMP ROUGHLY A SCREEN'S WORTH TO THE FILE
    REM NEVER HAVE TO REDISPLAY THE SCREEN AFTER DUMPFIRSTSCREEN IS CALLED
    IF CURSORTEXTBASEPTR=1 THEN RETURN \ REM HOPELESS CASE
    LET I=1
    FOR K=0 TO SCREENDEPTH-1 UNTIL I=CURSORTEXTBASEPTR
        LET I=I+FIND(RIGHT$(TEXT$,I),CR$)
    NEXT K
    LET I=I-1
    WRITE #TEMPFILE,TEXT$(1,I)
    LET TEXT$=RIGHT$(TEXT$,I+1)
    IF CURSORTEXTPTRSAVE>0 THEN CURSORTEXTPTRSAVE=CURSORTEXTPTRSAVE-I
    LET CURSORTEXTBASEPTR=CURSORTEXTBASEPTR-I
    LET CURSORTEXTLINEPTR=CURSORTEXTLINEPTR-I
    LET CURSORTEXTPTR=CURSORTEXTPTR-I
    IF DISTINGUISHEDPOINT<I
    THEN LET DISTINGUISHEDPOINT=0
    ELSE LET DISTINGUISHEDPOINT=DISTINGUISHEDPOINT-I
    RETURN
!^L
ESCAPEZ: REM ESC Z -- MOVE TO END OF BUFFER
    IF CURSORTEXTPTR=LEN(TEXT$) AND CURSORROW=SCREENDEPTH-1 THEN ILLEGAL
    LET CURSORTEXTBASEPTR=FINDBEGINLINE(LEN(TEXT$))
    CURSORTEXTLINEPTR=CURSORTEXTBASEPTR
    REM NOW FIND START OF TEXT LINE FOR EACH SCREEN DISPLAY LINE
    FOR CURSORROW=0 TO SCREENDEPTH-2 UNTIL CURSORTEXTBASEPTR=1
        LET CURSORTEXTBASEPTR=FINDBEGINLINE(CURSORTEXTBASEPTR-1)
    NEXT CURSORROW
    CURSORCOL=LEFTMARGIN
    LET CURSORTEXTLINELENGTH=FIND(RIGHT$(TEXT$,CURSORTEXTLINEPTR),CR$)-1
    LET CURSORTEXTPTR=CURSORTEXTLINEPTR+CURSORCOL
    GOTO 50900
!^L
ESCAPEX:   REM ESC X
    IF LEN(TEXT$)>=2 AND TEXT$[LEN(TEXT$)-1]=CR
    THEN
        REM STRIP OFF DUMMY <CR> AT END OF TEXT$
        LET LEN(TEXT$)=LEN(TEXT$)-1
    FI
    LET CURSORROW=SCREENDEPTH-1
    LET CURSORCOL=0
    GOSUB POSITIONCURSOR
    IF NOT DELETEDTEXTISINFILE
    THEN
        REM WRITE DELETEDSTRING$ TO DELETED.TMP SO IT CAN BE <ESC>R'D LATER
        CREATE #DELETEDTEXT,DELETEDTMP$
        WRITE #DELETEDTEXT,DELETEDSTRING$
    FI
    ON ERROR GOTO 0\ REM DISABLE THE ERROR TRAP SET ON ENTRY
    RETURN
!^L
ESCAPEGORIGHT: REM ESC GORIGHT, LOCATE NEXT WORD BOUNDARY
    REM 1) SKIP ALPHA
    REM 2) SKIP NON-ALPHA (STOP ON CR$)
    IF ARGUMENT=0 THEN ARGUMENT=1
    WINDOWMOVED=FALSE
    FOR CMDITERATION=1 TO ARGUMENT
        IF CURSORTEXTPTR=LEN(TEXT$)
        THEN PRINT BEEP$;\ EXIT CMDITERATION
        IF CURSORCOL<CURSORTEXTLINELENGTH
        THEN
            WHILE FIND(ALPHA$,TEXT$(CURSORTEXTPTR,1))<>0 DO
                  CURSORTEXTPTR=CURSORTEXTPTR+1
            END
            REM ASSERT TEXT$(LEN(TEXT$)) IS NOT IN ALPHA$!
            WHILE FIND(ALPHA$,TEXT$(CURSORTEXTPTR,1))=0 ...
&                     AND TEXT$(CURSORTEXTPTR)<>CR DO
                  CURSORTEXTPTR=CURSORTEXTPTR+1
            END
            REM THIS LOOP GAURANTEED TO STOP BECAUSE TEXT$(LEN(TEXT$))=CR
        ELSE
            REM SKIP CR TO START OF NEXT LINE
            CURSORTEXTPTR=CURSORTEXTLINEPTR+CURSORTEXTLINELENGTH+1
            CURSORTEXTLINEPTR=CURSORTEXTPTR
            CURSORTEXTLINELENGTH=FIND(RIGHT$(TEXT$,CURSORTEXTPTR),CR$)-1
            CURSORROW=CURSORROW+1
            IF CURSORROW=SCREENDEPTH
            THEN
                CURSORROW=0
                WINDOWMOVED=TRUE
            FI
        FI
        CURSORCOL=CURSORTEXTPTR-CURSORTEXTLINEPTR
    NEXT CMDITERATION
ESCAPENEXTWORDDONE: REM FOUND NEXT WORD
    IF WINDOWMOVED
    THEN
        GOSUB SETUPCURSORCONTEXT
        GOSUB CLEARSCREENDISPLAYPAGE
    ELSE
        GOSUB SETUPLINECONTEXT
        GOSUB POSITIONCURSOR
    FI
    GOTO NEXTCMD
!^L
ESCAPEGOLEFT: REM ESC GOLEFT, LOCATE PREVIOUS WORD BOUNDARY
    REM 1) SKIP LEFT OVER NON-ALPHA UNTIL START OF LINE FOUND
    REM 2) SKIP LEFT OVER ALPHA
    IF ARGUMENT=0 THEN ARGUMENT=1
    WINDOWMOVED=FALSE
    FOR CMDITERATION=1 TO ARGUMENT
        IF CURSORTEXTPTR=1
        THEN PRINT BEEP$;\ EXIT CMDITERATION
        IF CURSORCOL>0
        THEN
            IF CURSORCOL>=CURSORTEXTLINELENGTH
            THEN LET CURSORTEXTPTR=CURSORTEXTLINEPTR+CURSORTEXTLINELENGTH
            LET CURSORTEXTPTR=CURSORTEXTPTR-1
            WHILE CURSORTEXTPTR>0 AND FIND(ALPHA$,TEXT$(CURSORTEXTPTR,1))=0 ...
&                                 AND TEXT$(CURSORTEXTPTR)<>CR DO
                  CURSORTEXTPTR=CURSORTEXTPTR-1
            END
            WHILE CURSORTEXTPTR>0 AND FIND(ALPHA$,TEXT$(CURSORTEXTPTR,1))<>0 ...
&                                 AND TEXT$(CURSORTEXTPTR)<>CR DO
                  CURSORTEXTPTR=CURSORTEXTPTR-1
            END
            LET CURSORTEXTPTR=CURSORTEXTPTR+1
        ELSE
            REM SKIP CR TO END OF PREVIOUS LINE
            CURSORTEXTPTR=CURSORTEXTPTR-1
            CURSORTEXTLINEPTR=FINDBEGINLINE(CURSORTEXTPTR)
            CURSORTEXTLINELENGTH=FIND(RIGHT$(TEXT$,CURSORTEXTLINEPTR),CR$)-1
            IF CURSORROW=0
            THEN
                CURSORROW=SCREENDEPTH-1
                WINDOWMOVED=TRUE
            ELSE
                CURSORROW=CURSORROW-1
            FI
        FI
        CURSORCOL=CURSORTEXTPTR-CURSORTEXTLINEPTR
    NEXT CMDITERATION
    GOTO ESCAPENEXTWORDDONE
!^L
ESCAPELT: REM ESCAPE <    SET LEFT MARGIN
    GOSUB DISPLAYRULER \ ! DISPLAY UNTARNISHED RULER
MODIFYRULERESCAPELT:
    REM CHECK FOR LEFT MARGIN AT OR PAST FIRST TAB OR RIGHTMARGIN
    IF CURSORCOL>=RIGHTMARGIN THEN MODIFYRULERILLEGAL\! MARGINS CANNOT OVERLAP
    LEFTMARGIN=CURSORCOL\ ! SET NEW LEFT MARGIN
    WHILE LEN(TABS$)>0 AND LEFTMARGIN>=TABS$(1) DO
        REM NEW LEFT MARGIN TO RIGHT OF TAB, DELETE IT
        LET TABS$[1,LEN(TABS$)-1]=RIGHT$(TABS$,2)
        LET LEN(TABS$)=LEN(TABS$)-1
    END
    GOSUB DISPLAYRULER \ ! DISPLAY CORRECTED RULER
    GOTO MODIFYRULER

ESCAPEGT: REM ESCAPE >    SET RIGHT MARGIN
    GOSUB DISPLAYRULER \ ! DISPLAY UNTARNISHED RULER
MODIFYRULERESCAPEGT:
    IF CURSORCOL<=LEFTMARGIN THEN MODIFYRULERILLEGAL \ ! MARGINS CANNOT OVERLAP
    RIGHTMARGIN= IF CURSORCOL=SCREENWIDTH-1
                 THEN RMARGININFINITY ELSE CURSORCOL FI
    WHILE LEN(TABS$)>0 AND RIGHTMARGIN<TABS$(LEN(TABS$)) DO
        REM NEW RIGHT MARGIN IS TO LEFT OF TAB, DELETE THE TAB
        LET LEN(TABS$)=LEN(TABS$)-1
    END
    GOSUB DISPLAYRULER \ ! DISPLAY CORRECTED RULER
    GOTO MODIFYRULER
!^L
ESCAPETAB: REM ESCAPE<TAB>  SET/REMOVE TAB STOP
    GOSUB DISPLAYRULER
MODIFYRULERESCAPETAB:
    REM CANNOT FOOL WITH TABS IF OUTSIDE OF MARGINS
    IF CURSORCOL<=LEFTMARGIN OR CURSORCOL>=RIGHTMARGIN THEN MODIFYRULERILLEGAL
    FOR I=1 TO LEN(TABS$)
        IF CURSORCOL=TABS$(I)
        THEN ESCAPETABCLEAR
        ELSEIF CURSORCOL<TABS$(I) THEN EXIT I \ ! USER WANTS TO SET A NEW TAB
    NEXT I
    REM SET A NEW TAB
    IF LEN(TABS$)=MAXLEN(TABS$) THEN MODIFYRULERILLEGAL \ ! TOO MANY TAB STOPS
    TEMP=CURSORCOL
    FOR I=I TO LEN(TABS$)
        TEMP1=TABS$(I)
        TABS$(I)=TEMP
        TEMP=TEMP1
    NEXT I
    LEN(TABS$)=LEN(TABS$)+1
    TABS$(LEN(TABS$))=TEMP
    REM TELL VT DRIVER ABOUT TABS STOPS HERE
    GOSUB DISPLAYRULER
    GOTO MODIFYRULER

ESCAPETABCLEAR: REM USER WANTS TO REMOVE A TAB, DO IT
    FOR I=I TO LEN(TABS$) DO LET TABS$(I)=TABS$(I+1)
    LET LEN(TABS$)=LEN(TABS$)-1
    GOSUB DISPLAYRULER
    GOTO MODIFYRULER

MODIFYRULERGOLEFT: REM LEFT ARROW AFTER RULER CHANGE
    IF CURSORCOL=0 THEN MODIFYRULERILLEGAL
    CURSORCOL=CURSORCOL-1
    PRINT BACKSPACE$;
    GOTO MODIFYRULER

MODIFYRULERGORIGHT: REM RIGHT ARROW AFTER RULER CHANGE
    IF CURSORCOL=SCREENWIDTH-1 THEN MODIFYRULERILLEGAL
    CURSORCOL=CURSORCOL+1
    GOSUB POSITIONCURSOR
    GOTO MODIFYRULER

MODIFYRULERILLEGAL: PRINT BEEP$;
MODIFYRULER: REM ALLOW <LEFT>, <RIGHT>, <ESC> <, <ESC><TAB>, OR <ESC> >
    REM OTHERWISE ERASE RULER, PUT UP ORIGINAL LINE, AND CONTINUE
    LET CHARACTER=KEYSTROKE
    IF CHARACTER=:8 THEN MODIFYRULERGOLEFT
    ELSEIF CHARACTER=:C THEN MODIFYRULERGORIGHT
    ELSEIF CHARACTER<>:1B
    THEN
        LET CURSORTEXTPTR=CURSORTEXTLINEPTR+CURSORCOL
        IF RULERCHANGED
        THEN GOSUB CLEARSCREENDISPLAYPAGE \ ! BECAUSE TABS MAY HAVE CHANGED
        ELSE GOSUB REPAINTCURRENTLINE
        GOTO INSPECTCHARACTER
    FI
    REM ESCAPE CHARACTER
    LET CHARACTER=KEYSTROKE
MODIFYRULERINSPECTESCCHARACTER:
    IF CHARACTER>=96 THEN CHARACTER=CHARACTER-32
    IF CHARACTER=ASC("<") THEN MODIFYRULERESCAPELT
    ELSEIF CHARACTER=ASC(">") THEN MODIFYRULERESCAPEGT
    ELSEIF CHARACTER=TABCHARACTER THEN MODIFYRULERESCAPETAB
    ELSE
        LET CURSORTEXTPTR=CURSORTEXTLINEPTR+CURSORCOL
        IF RULERCHANGED
        THEN GOSUB CLEARSCREENDISPLAYPAGE \ ! BECAUSE TABS MAY HAVE CHANGED
        ELSE GOSUB REPAINTCURRENTLINE
        GOTO ESCAPEINSPECTCHARACTER
    FI
!^L
DISPLAYRULER: REM DISPLAY TAB RULER, AND ALLOW MODIFICATION
    POSITION #0@(CURSORROW,0)
    REM ASSERT LEFTMARGIN < SCREENWIDTH
    LET COLUMNDIV10=0\COLUMNMODULO10=1\! COL(0)=COLUMNDIV10*10+COLUMNMODULO10
    FOR I=0 TO LEFTMARGIN-1 DO GOSUB PRINTCOLUMNDIGIT
    PRINT "<"; \ ! ASSERT: COL(0)=LEFTMARGIN IN ZERO ORIGIN
    GOSUB BUMPCOLUMNCOUNT
    NEXTTAB=1 \ ! SEARCH FOR 1ST TAB COLUMN
    FOR I=LEFTMARGIN+1 TO IF RIGHTMARGIN<SCREENWIDTH
                          THEN RIGHTMARGIN-1 ELSE SCREENWIDTH-2 FI
        REM CURSOR IS IN COLUMN I (ZERO ORIGIN)
        IF LEN(TABS$)>=NEXTTAB AND I=TABS$(NEXTTAB)
        THEN
            PRINT "+";
            NEXTTAB=NEXTTAB+1
            GOSUB BUMPCOLUMNCOUNT
        ELSE GOSUB PRINTCOLUMNDIGIT
    NEXT I
    IF I=RIGHTMARGIN
    THEN
        REM RIGHTMARGIN APPEARS ON THE SCREEN
        PRINT ">";
        REM BLANK THE REST OF THE LINE
        PRINT BLANKS$[1,SCREENWIDTH-1-I-1];
    FI
    GOSUB POSITIONCURSOR
    RULERCHANGED=FALSE \ ! REMEMBER THAT NO RULER CHANGES HAVE BEEN MADE
    RETURN

PRINTCOLUMNDIGIT: REM PRINT OUT COLUMN NUMBER DIGIT
    PRINT USING "#",IF COLUMNMODULO10>0
                    THEN COLUMNMODULO10 ELSE COLUMNDIV10 FI;
BUMPCOLUMNCOUNT: REM INCREMENT COLUMN NUMBER
    IF COLUMNMODULO10<9
    THEN COLUMNMODULO10=COLUMNMODULO10+1
    ELSE COLUMNMODULO10=0\COLUMNDIV10=COLUMNDIV10+1
    RETURN
!^L
REPAINTCURRENTLINE: REM RE-DISPLAY THE LINE OF TEXT AT CURSORROW
    POSITION #0@(CURSORROW,0)
    IF CURSORTEXTLINELENGTH>=SCREENWIDTH
    THEN PRINT TEXT$(CURSORTEXTLINEPTR,SCREENWIDTH-1);
    ELSE
        PRINT TEXT$(CURSORTEXTLINEPTR,CURSORTEXTLINELENGTH);
        PRINT LEFT$(BLANKS$,SCREENWIDTH-CURSORTEXTLINELENGTH-1);
    FI
    GOSUB POSITIONCURSOR
    RETURN
!^L
ESCAPET: REM ESCAPE T    SELECT TAB STOPS FROM FILE
    CHARACTER=KEYSTROKE
    IF CHARACTER<ASC("0") OR CHARACTER>ASC("9") THEN ILLEGAL
    IF CHARACTER=ASC("0")
    THEN
        REM USER WANTS TO DESTROY CURRENT RULER
        LEFTMARGIN=0
        RIGHTMARGIN=RMARGININFINITY
        LEN(TABS$)=0
    ELSE
        REM USER WANTS TO PICK RULER FROM "SEDIT.TABS"
        IF NOT TABSFILEISOPEN THEN ILLEGAL
        POSITION #TABSFILE,0
        REM READ THE SELECTED LINE FROM THE TABS FILE
        FOR I=1 TO CHARACTER-ASC("0")
            INPUT #TABSFILE,LINE$ \ ! ERR 8 OCCURS IF LINE IS TOO LONG...
            IF EOF(TABSFILE) THEN ILLEGAL
        NEXT I
        GOSUB PROCESSRULER
    FI
    SAVECURSORCOL=CURSORCOL
    GOSUB DISPLAYRULER
    GOTO MODIFYRULER

PROCESSRULER: REM SCAN RULER TO GET MARGINS AND TAB STOPS
    RIGHTMARGIN=RMARGININFINITY \ ! DEFAULT RIGHTMARGIN IF NOT SUPPLIED
    LEN(TABS$)=0    \ ! MAKE TAB LIST EMPTY
    REM FIND LEFT MARGIN; DEFAULT TO ZERO IF NONE GIVEN
    IF FIND(LINE$,TAB$)
    THEN
        REM RULERS CANNOT HAVE <TAB> CHARACTERS IN THEM!!!
        LET LEFTMARGIN=0 \ ! DEFAULT LEFT MARGIN
        PRINT BEEP$;
        RETURN
    FI
    LET LEFTMARGIN=FIND(LINE$,"<")
    IF LEFTMARGIN>0 THEN LEFTMARGIN=LEFTMARGIN-1
    FOR I=LEFTMARGIN+2 TO LEN(LINE$)
        IF LINE$(I)=ASC(">")
        THEN
            IF I-1<SCREENWIDTH THEN RIGHTMARGIN=I-1 ELSE PRINT BEEP$;
            EXIT I
        FI
        IF LINE$(I)=ASC("+") AND LEN(TABS$)<MAXLEN(TABS$)
        THEN
            REM ADD NEW TAB STOP TO TAB STOP LIST
            LET LEN(TABS$)=LEN(TABS$)+1
            LET TABS$[LEN(TABS$)]=I-1
        FI
    NEXT I
    RETURN
!^L
SUBROUTINE TRACE(TRACE$)
! DEBUGGING TOOL, CAN BE REM'D OUT WHEN SEDIT IS PERFECT (HAH!)
    PRINT @(SCREENDEPTH-1,0),BLANKS$[1,SCREENWIDTH-1];
    PRINT @(SCREENDEPTH-1,0),TRACE$;
    TRACE1=KEYSTROKE
    GOSUB POSITIONCURSOR
    RETURN SUBROUTINE
END
!^L
ESCAPEJ: REM FORCE TEXT BETWEEN DISTINGUISHED PT. AND CURSOR TO FIT MARGINS
    IF CURSORCOL>CURSORTEXTLINELENGTH THEN ILLEGAL \ ! CURSOR NOT OVER TEXT
    IF RIGHTMARGIN=RMARGININFINITY THEN ILLEGAL \ ! CAN'T JUSTIFY NOW
    IF DISTINGUISHEDPOINT>=CURSORTEXTPTR
    THEN ILLEGAL \ ! CAN'T DO THIS IF TEXT REGION INCORRECTLY SPECIFIED
    IF DISTINGUISHEDPOINT=0
    THEN CALL MAKEFITMARGINS(CURSORTEXTLINEPTR,CURSORTEXTPTR,0)
    ELSE CALL MAKEFITMARGINS(DISTINGUISHEDPOINT,CURSORTEXTPTR,TRUE)
    LET DISTINGUISHEDPOINT=0 \ ! FORGET OLD DISTINGUISHED POINT
    GOSUB SETUPCURSORCONTEXT
    GOSUB CLEARSCREENDISPLAYPAGE
    GOTO NEXTCMD

DEF PARAGRAPHBREAK(PARAGRAPHBREAKLINE)
    REM FUNCTION THAT RETURNS "TRUE" IF LINE SELECTED BY ARGUMENT....
    REM IS A PARAGRAPH BREAK BY THE FOLLOWING DEFINITION:
    REM     PARAGRAPH BREAK = LINE WITH A MAL-FORMED LEFTMARGIN,
    REM                       OR A LINE WHOSE LEFT MARGIN IS NOT ALL BLANKS,
    REM                       OR A LINE THAT CONTAINS A <TAB>
    REM                       OR A LINE WHICH IS SIMPLY <CR>
    REM                       OR A LINE WHOSE LEFT MARGIN IS FOLLOWED BY BLANK,
    REM                       OR A LINE WHOSE FIRST NON-BLANK IS A "."
    REM                       OR A LINE WHICH STARTS PAST THE END OF THE BUFFER
    IF PARAGRAPHBREAKLINE>LEN(TEXT$) THEN RETURN TRUE
    IF TEXT$[PARAGRAPHBREAKLINE]=CR THEN RETURN TRUE \ ! EMPTY LINE IS PARAGRAPH BREAK
    FOR I=PARAGRAPHBREAKLINE TO PARAGRAPHBREAKLINE+LEFTMARGIN-1
        IF TEXT$[I]<>BLANK THEN RETURN TRUE\! MAL-FORMED MARGIN OR NOT BLANK
    NEXT I
    IF TEXT$[I]=BLANK OR TEXT$[I]=ASC(".")
    THEN RETURN TRUE \! 1ST CHARACTER BEYOND LMARGIN IS BLANK OR "." (TYPE!)
    LET I=FIND(RIGHT$(TEXT$,PARAGRAPHBREAKLINE),CR$)
    RETURN FIND(TEXT$[PARAGRAPHBREAKLINE,I],TAB$)
END
!^L
SUBROUTINE MAKEFITMARGINS(MAKEFITSTART,MAKEFITEND,MAKEFITLIMITFLAG)
REM???? COULD THIS ALSO DO TRUE JUSTIFICATION?????
    REM THIS SUBROUTINE MAKES TEXT BETWEEN MAKEFITLINE AND AN UPPER LIMIT...
    REM FIT THE MARGINS SPECIFIED CURRENTLY BY LEFTMARGIN AND RIGHTMARGIN
    REM MAKEFITEND IS ADJUSTED PROPERLY IF THE TEXT IS MODIFIED
    REM THE UPPER BOUND ON TEXT ADJUSTMENT DEPENDS ON MAKEFITLIMITFLAG:
    REM IF MAKEFITLIMITFLAG=0, THEN MARGIN FITTING WILL QUIT WHEN THE
    REM NEXT PARAGRAPH BREAK IS REACHED.
    REM IF MAKEFITLIMITFLAG <>0, MARGIN FITTING STOPS AS SOON AS
    REM ALL TEXT UP TO AND INCLUDING MAKEFITEND HAS BEEN ADJUSTED
    IF RIGHTMARGIN=RMARGININFINITY THEN RETURN SUBROUTINE \ ! DON'T JUSTIFY
    LET MAKEFITLINE=FINDBEGINLINE(MAKEFITSTART)
    IF MAKEFITLIMITFLAG<>0 AND MAKEFITLINE>=MAKEFITEND THEN RETURN SUBROUTINE
    REPEAT
        REM MAKE THE LINE SELECTED BY "MAKEFITLINE" FIT THE MARGINS!
        LET MAKEFITLINELENGTH=FIND(RIGHT$(TEXT$,MAKEFITLINE),CR$)
        LET MAKEFITNEXTLINE=MAKEFITLINE+MAKEFITLINELENGTH
        LET MAKEFITLINELENGTH=MAKEFITLINELENGTH-1
        REM IF LINE FITS IN MARGINS...
        IF MAKEFITLINELENGTH<=RIGHTMARGIN+1
        THEN
            REM LINE FITS WITHIN MARGINS DESIRED
            IF MAKEFITLIMITFLAG AND MAKEFITEND<=MAKEFITNEXTLINE
            THEN RETURN SUBROUTINE \ ! QUIT NOW IF DONE
            IF PARAGRAPHBREAK(MAKEFITNEXTLINE) OR MAKEFITLINELENGTH=0
            THEN LET MAKEFITLINE=MAKEFITNEXTLINE\!CAN'T STEAL FROM NEXT LINE
            ELSE
                REM TRY TO EXTEND THIS LINE BY STEALING FROM NEXT
                LINEBREAKOFFPOINT=0 \ ! I.E. "NO PLACE TO BREAK NEXT LINE"
                LET I=MAKEFITNEXTLINE+LEFTMARGIN-1
                REPEAT
                    I=I+1
                    IF ( TEXT$[I]=BLANK OR TEXT$[I]=CR ) AND...
&                      MAKEFITLINELENGTH+1+(I-(MAKEFITNEXTLINE+LEFTMARGIN))...
&                           <= RIGHTMARGIN+1
                    THEN LINEBREAKOFFPOINT=I
                UNLESS TEXT$[I]=CR END
                IF LINEBREAKOFFPOINT=0
                THEN LET MAKEFITLINE=MAKEFITNEXTLINE\!CAN'T BREAK NEXT LINE
                ELSE
                    REM WE CAN STEAL UP TO LINEBREAKOFFPOINT
                    IF TEXT$[LINEBREAKOFFPOINT]=BLANK
                    THEN
                        REM CHANGE XXXXX<CR><LEFTMARGINBLANKS>YYYY<BLANK>...
                        REM TO     XXXXX<BLANK>YYYY<CR><LEFTMARGINBLANKS>
                        REM FIRST, ADJUST MAKEFITEND IF POINTS INTO REGION
                        IF MAKEFITEND>=MAKEFITNEXTLINE
                        THEN IF MAKEFITEND<=MAKEFITNEXTLINE+LEFTMARGIN
                             THEN MAKEFITEND=MAKEFITNEXTLINE-1
                             ELSE IF MAKEFITEND<=LINEBREAKOFFPOINT
                                  THEN MAKEFITEND=MAKEFITEND-LEFTMARGIN
                        REM ADJUST DISTINGUISHEDPOINT
                        IF DISTINGUISHEDPOINT>=MAKEFITNEXTLINE
                        THEN IF DISTINGUISHEDPOINT<=MAKEFITNEXTLINE+LEFTMARGIN
                             THEN DISTINGUISHEDPOINT=MAKEFITNEXTLINE-1
                             ELSE IF DISTINGUISHEDPOINT<=LINEBREAKOFFPOINT
                                  THEN DISTINGUISHEDPOINT=...
&                                      DISTINGUISHEDPOINT-LEFTMARGIN
                        REM COMPUTE # BYTES TO SHUFFLE
                        LET I=LINEBREAKOFFPOINT-MAKEFITNEXTLINE-LEFTMARGIN+1
                        LET TEXT$[MAKEFITNEXTLINE-1]=BLANK
                        LET TEXT$[MAKEFITNEXTLINE,I]=...
&                           TEXT$[MAKEFITNEXTLINE+LEFTMARGIN,I]
                        LET TEXT$[LINEBREAKOFFPOINT-LEFTMARGIN]=CR
                        LET TEXT$[LINEBREAKOFFPOINT-LEFTMARGIN+1,LEFTMARGIN]=...
&                           BLANKS$[1,LEFTMARGIN]
                        LET MAKEFITLINE=LINEBREAKOFFPOINT-LEFTMARGIN+1
                    ELSE
                        REM CHANGE XXX<CR><LEFTMARGINBLANKS>YYYY<CR>...
                        REM TO     XXX<BLANK>YYYY<CR>
                        ADJUSTHOLESIZE(MAKEFITNEXTLINE,LEFTMARGIN,0)
                        LET TEXT$[MAKEFITNEXTLINE-1]=BLANK
                        IF MAKEFITEND>=MAKEFITNEXTLINE
                        THEN IF MAKEFITEND<=MAKEFITNEXTLINE+LEFTMARGIN
                             THEN MAKEFITEND=MAKEFITNEXTLINE
                             ELSE MAKEFITEND=MAKEFITEND-LEFTMARGIN
                    FI
                FI
            FI
        ELSE
            REM LINE DOES NOT FIT BETWEEN MARGINS, ADJUST IT!
            REM NOTE: MAKEFITNEXTLINE-1 POINTS TO A <CR> AND NEED NOT BE EXAMINED
            FOR LINEBREAKOFFPOINT=MAKEFITNEXTLINE-2 ...
&                                 TO MAKEFITLINE+LEFTMARGIN STEP -1
                IF TEXT$[LINEBREAKOFFPOINT]=TABCHARACTER
                THEN MAKEFITMARGINSCANT\!TAB DEPENDS ON CONTENT OF LINE
                IF TEXT$[LINEBREAKOFFPOINT]=BLANK AND...
&                  LINEBREAKOFFPOINT-MAKEFITLINE<=RIGHTMARGIN
                THEN EXIT LINEBREAKOFFPOINT
            END
            IF LINEBREAKOFFPOINT<=MAKEFITLINE+LEFTMARGIN-1
            THEN MAKEFITMARGINSCANT \ ! NO PLACE TO BREAK THIS LINE
            REM WE FOUND WHERE TO BREAK OFF THE LINE!
            REM INSTALL THE LINE BREAK
            IF PARAGRAPHBREAK(MAKEFITNEXTLINE) OR...
&              MAKEFITLIMITFLAG AND MAKEFITNEXTLINE>=MAKEFITEND
            THEN
                REM MAKE ROOM FOR LINE BREAK WHERE NEEDED
                IF NOT ISROOM(LEFTMARGIN) THEN MAKEFITMARGINSCANT \ ! FULL!!
                ADJUSTHOLESIZE(LINEBREAKOFFPOINT,1,LEFTMARGIN+1)
                IF MAKEFITEND>LINEBREAKOFFPOINT
                THEN MAKEFITEND=MAKEFITEND+LEFTMARGIN FI
            ELSE
                REM CHANGE <BLANK>X..X<CR><LEFTMARGINBLANKS>
                REM TO <CR><LEFTMARGINBLANKS>X..X<BLANK>
                REM FIRST, ADJUST MAKEFITEND IF POINTS INTO MODIFIED REGION
                IF MAKEFITEND>LINEBREAKOFFPOINT
                THEN IF MAKEFITEND<=MAKEFITNEXTLINE
                     THEN MAKEFITEND=MAKEFITEND+LEFTMARGIN
                     ELSE IF MAKEFITEND<=MAKEFITNEXTLINE+LEFTMARGIN
                          THEN MAKEFITEND=MAKEFITNEXTLINE+LEFTMARGIN
                REM ADJUST DISTINGUISHEDPOINT
                IF DISTINGUISHEDPOINT>LINEBREAKOFFPOINT
                THEN IF DISTINGUISHEDPOINT<=MAKEFITNEXTLINE
                     THEN DISTINGUISHEDPOINT=DISTINGUISHEDPOINT+LEFTMARGIN
                     ELSE IF DISTINGUISHEDPOINT<=MAKEFITNEXTLINE+LEFTMARGIN
                          THEN DISTINGUISHEDPOINT=...
&                              DISTINGUISHEDPOINT+LEFTMARGIN
                REM COMPUTE NUMBER OF BYTES TO SHUFFLE
                I=MAKEFITNEXTLINE-LINEBREAKOFFPOINT-2
                LET TEXT$[LINEBREAKOFFPOINT+LEFTMARGIN+1,I]=...
&                   TEXT$[LINEBREAKOFFPOINT+1,I]
                REM INSTALL THE RIGHTMOST BLANK
                LET TEXT$[MAKEFITNEXTLINE+LEFTMARGIN-1]=BLANK
            FI
            REM PLACE TEXT FOR LINE BREAK INTO BUFFER
            TEXT$(LINEBREAKOFFPOINT)=CR
            LET TEXT$[LINEBREAKOFFPOINT+1,LEFTMARGIN]=BLANKS$[1,LEFTMARGIN]
            LET MAKEFITLINE=LINEBREAKOFFPOINT+1
        FI
        IF MAKEFITLIMITFLAG=0 AND PARAGRAPHBREAK(MAKEFITLINE)
        THEN RETURN SUBROUTINE \ ! EXIT FOR JUSTIFYING TIL PARAGRAPH
    END \ ! REPEAT UNTIL MARGINS ALL FIT

MAKEFITMARGINSCANT: REM CANNOT MAKE THIS LINE FIT MARGINS
    REM IT IS UNREASONABLE TO BREAK THIS LINE!!!
    REM CURSOR SHOULD BE SET TO THIS PLACE SO USER SEES PROBLEM
    PRINT BEEP$;
    RETURN SUBROUTINE
END
!^L
CLEARSCREENDISPLAYPAGE:   REM DISPLAY SCREEN-FULL OF TEXT
    REM ONLY PRINTING CHARACTERS AND CR ARE ALLOWED IN RAW TEXT
    PRINT CLEARSCREEN$;
    LET I=CURSORTEXTBASEPTR\I0=I \ ! I0 IS LAST PLACE SO FAR UNDISPLAYED
    ! THE LOGIC OF THE LOOP BELOW IS ESSENTIALLY TO COLLECT AS BIG
    ! A CHUNK OF TEXT AS POSSIBLE BEFORE TRYING TO DISPLAY IT.
    ! THIS GIVE SDOS/MT AND THE VT DRIVER GOOD PERFORMANCE PROPERTIES.
    ! COULD PUT SCREEN IN CHOP MODE, AND THEN JUST SHOW TEXT!
    FOR J=0 TO SCREENDEPTH-1
        IF I<=LEN(TEXT$)
        THEN
            REM HAVEN'T RUN OFF END OF TEXT$ YET
            LET NEXTLINELENGTH=FIND(RIGHT$(TEXT$,I),CR$)-1
            IF NEXTLINELENGTH<SCREENWIDTH
            THEN
                ROWWIDTH(J)=NEXTLINELENGTH
                ! WE AREN'T FORCED TO PRINT ANYTHING YET
                LET I=I+NEXTLINELENGTH+(J<SCREENDEPTH-1)
            ELSE
                ROWWIDTH(J)=SCREENWIDTH-1
                PRINT TEXT$(I0,I+ROWWIDTH(J)-I0); \ ! MUST PRINT TEXT TO HERE
                LET I=I+NEXTLINELENGTH+1 \ LET I0=I
                IF J<SCREENDEPTH-1 THEN PRINT FI
            FI
        ELSE
            REM END OF TEXT ENCOUNTERED
            ROWWIDTH(J)=0
        FI
    NEXT J
    PRINT TEXT$(I0,I-I0); \ ! PRINT WHATEVER TEXT WE HAVEN'T PRINTED YET
    REM SCREEN DISPLAY COMPLETED
POSITIONCURSOR: REM POSITION THE CURSOR ON THE SCREEN
   POSITION #0@(CURSORROW,CURSORCOL)
   RETURN
!^L
DISPLAYPAGEFROMCURSORROW: REM RE-DISPLAY ALL LINES STARTING WITH CURSORROW
    LET I=CURSORTEXTLINEPTR
    POSITION #0@(CURSORROW,0)
    FOR J=CURSORROW TO SCREENDEPTH-1
        IF I<=LEN(TEXT$)
        THEN
            REM HAVEN'T RUN OFF END OF TEXT$
            LET NEXTLINELENGTH=FIND(RIGHT$(TEXT$,I),CR$)-1
            IF NEXTLINELENGTH>=ROWWIDTH(J)
            THEN
                REM NEWLY DISPLAYED LINE WILL OBLITERATE OLD
                ROWWIDTH(J)=...
&               IF NEXTLINELENGTH<SCREENWIDTH
                THEN NEXTLINELENGTH ELSE SCREENWIDTH-1 FI
                PRINT TEXT$(I,ROWWIDTH(J));
            ELSE
                REM OLD LINE IS LONGER THAN NEW
                PRINT TEXT$(I,NEXTLINELENGTH);
                PRINT LEFT$(BLANKS$,ROWWIDTH(J)-NEXTLINELENGTH);
                ROWWIDTH(J)=NEXTLINELENGTH
            FI
            LET I=I+NEXTLINELENGTH+1
        ELSE
            REM END OF TEXT ENCOUNTERERD
            PRINT LEFT$(BLANKS$,ROWWIDTH(J));
            ROWWIDTH(J)=0
        FI
        IF J<SCREENDEPTH-1 THEN PRINT
    NEXT J
    GOTO POSITIONCURSOR

END
! *** OF "SCREENEDIT" SUBROUTINE

END
! *** OF THE SCREEN EDITOR ***
