TERMINAL I/O

Class new title: ’UserView’;
    fields: ’screenrect <Rectangle> current screen size
        vtab <Integer=0mod2> offset from hardware top
        htab <Integer=0mod16> offset from hardware left
        scale <Integer=1 or 2> 2 means double bits mode
        color <Integer=0 or 1> 1 means reverse field
        screenfile <File> for saving current bitmap
        disp <Dispframe> default message stream
        sched <PriorityScheduler> tasks for this view’

screen overlays
UserView understands: ’
install
    [user close. self reconfigure. user ← self open]’
UserView understands: ’
reconfigure [] primitive: 62’    tell OOZE and others
UserView understands: ’
close
    [screenfile open.        write out the old bitmap
    screenfile write: screenrect height*(screenrect width+15/16)/256
        from: mem◦066.
    screenfile close]’
UserView understands: ’
open
    [screenfile open.        read in the new bitmap
    screenfile read: screenrect height*(screenrect width+15/16)/256
        to: mem◦066.
    screenfile close]’

terminal interaction
UserView understands: ’
kbd [!kbMap◦self rawkbd]’
UserView understands: ’
kbck
    [self rawkbck?[!kbMap◦self rawkbck] !false ]’
UserView understands: ’
rawkbd [] primitive: 63’
UserView understands: ’
rawkbck [] primitive: 64’
UserView understands: ’
buttons
    [!7-(mem◦0177030 land: 7)]’
UserView understands: ’
redbug [!self buttons=4]’
UserView understands: ’
yellowbug [!self buttons=1]’
UserView understands: ’
bluebug [!self buttons=2]’
UserView understands: ’
anybug [!self buttons>0]’
UserView understands: ’
keyset
    [!037-((mem◦0177030 lshift: ¬3) land: 37)]’
UserView understands: ’
mp
    [!Point new x: mem◦0424-htab y: mem◦0425-vtab]’
UserView understands: ’
cursorloc ← pt
    [mem◦0426 ← pt x+htab. mem◦0427 ← pt y+vtab]’

display control
UserView understands: ’
loadcursorbitsfrom: bitstr | i
    [for⦂ i to: 16 do⦂
        [mem◦(0430+i) ← bitstr word: i]]’
UserView understands: ’
displayoffwhile⦂ expr | t v
    [t ← mem◦067. mem◦067 ← 60.
    v ← expr eval. mem◦067 ← t. !v]’
UserView understands: ’
restoredisplay
    [mem◦067 ← screenrect height/2]’
UserView understands: ’
screenextent: extent tab: tab
    [mem◦065 ← (0400*(tab x/16))+(extent x/16|2).
    mem◦067 ← extent y/2. mem◦063 ← tab y/2.
    htab ← tab x|16. vtab ← tab y|2.
    screenrect ← 0@0 rect: (extent x|32)@(extent y|2).
    self reconfigure]’

system messages
UserView understands: ’
ev [disp ev]’
UserView understands: ’request: s [!disp request: s]’
UserView understands: ’
show: str
    [disp append: str; show]’
UserView understands: ’
cr [disp cr]’
UserView understands: ’
clearshow: str
    [disp clear; append: str; show]’
UserView understands: ’
notify: str
    [self restoredisplay. disp append: str; cr; show.
    disp append: thisContext sender trace; show.
    thisContext sender debug. self restart]’
UserView understands: ’
restart
    [self restart⦂ [disp ev]]’
UserView understands: ’
restart⦂ code
    [code sender ← nil.
    thisContext sender ← nil.        release caller chain
    CodeKeeper ← (Vector new: 10) asStream.        release held code
    disp cr; append: ’’ ** restart’’; show.
    while⦂ true do⦂ [code eval]]’
UserView understands: ’
screenrect [!screenrect]’

window scheduling
UserView understands: ’
schedule: window
    [sched≡nil?
        [(sched ← Vector new: 1)◦1 ← window]
    sched ← sched , window]’
UserView understands: ’
unschedule: window
    [0<(t← sched find: window)?
        [sched ← sched◦(1 to: t-1) concat: sched◦(t+1 to: sched length)]]’
UserView understands: ’
sched [!sched]’
UserView understands: ’
run | s
    [while⦂ (screenrect has: user mp) do⦂
        [for⦂ s from: sched do⦂ [s startup]]]’
UserView understands: ’
printon: strm
    [strm append: ’’a UserView’’]’

OOZE save/load
UserView understands: ’
OutLd [] primitive: 85’
    ↪returns true from call; false from OS resume↪
UserView understands: ’
InLd: fileid
    [user notify: ’’file problem’’] primitive: 86’
UserView understands: ’
overlay: fileid
    [self OutLd?[self InLd: fileid]]’
UserView understands: ’
quit | t
    [t ← Vector new: 5; all ← 0. self overlay: t]’
UserView understands: ’
Swat [] primitive: 90’

PARAGRAPH EDITOR
Smalltalk define "Peditorstuff as "Peditorstuff ← SymbolTable new.
Peditorstuff insertall: "(bs del esc doit paste typing editmenu
        Scrap Deletion ctlchars runvals p1 p2 selon oldpara oldheight)
    with: "(010 0177 033 036 02 typing editmenu
        Scrap Deletion ctlchars runvals p1 p2 selon oldpara oldheight).
Class new title: ’ParagraphEditor’;
    subclassof: Textframe;
    fields: ’loc1 loc2’;
    sharing: ’Peditorstuff’
ParagraphEditor understands: ’enter: window
    [frame ← window inset: 4 @ 2 and: 2 @ 2.
    oldpara ← oldheight ← false. self show]’
ParagraphEditor understands: ’
leave
    [self comp: p1 to: p2]’

ParagraphEditor understands: ’
kbd: boss | more char
    [more ← Stream default.
    while⦂ user kbck do⦂
        [(char ← user kbd)=del? []
        char=bs? [more empty?[loc1 ← 1 max: loc1-1].        ↪backspace↪
                more skip: ¬1]
        more next← char].
    self replace: more contents]’

ParagraphEditor understands: ’
redbug: boss | a t drag2
    [t ← self charnearpt: user mp.
    t=loc1 and: loc1=loc2 ? [self selectword]        ↪ double-bug ↪
        [loc1=t?[drag2 ← false]
        drag2 ← true. loc2=t?[]        ↪ pick up old selection ↪
        self comp: p1 to: p2. loc1 ← loc2 ← t.        ↪ start new selection ↪
        p2 ← 1@0 + (p1 ← reply1).
        self comp: p1 to: p2].
    while⦂ user redbug do⦂                    ↪ draw out selection ↪
        [a ← reply1.
            [loc1=loc2?[drag2 ← t≥loc2]].
            [drag2? [ [t<loc1?[t←loc1. a←self ptofchar: t]].
                    self comp: a to: p2. loc2 ← t. p2 ← a]
                [t>loc2?[t←loc2. a←self ptofchar: t]].
                self comp: p1 to: a. loc1 ← t. p1 ← a].
            [p1=p2?[self comp: p1 to: (p2 ← 1@0 + p1)]].
        t ← self charnearpt: user mp]]’

ParagraphEditor understands: ’
replace: t
    [    [oldpara?[] oldpara ← para].
    para ← para replace: loc1 to: loc2-1 by: t.
    loc1 ← loc2 ← loc1 + t length.
    self show]’
ParagraphEditor understands: ’
selection
    [!para copy: loc1 to: loc2-1]’

ParagraphEditor understands: ’
show
    [super show.
    [loc1≡nil? [loc1←loc2←1]].
    user kbck?[] self select]’
ParagraphEditor understands: ’
select
    [p1 ← self ptofchar: loc1.
    p2 ← [loc2=loc1?[1@0 + p1] self ptofchar: loc2].
    self comp: p1 to: p2]’

ParagraphEditor understands: ’
comp: a to: b | t        ↪complement from a to b↪
    [    [a y<b y?[] (a y=b y) and: (a x<b x)?[] t←a. a←b. b←t].        ↪in case they were reversed↪
        [a y < b y?
            [(a rect: (window corner x-4) @ (a y+self lineheight)) comp.    ↪top line↪
             a ← (window origin x+4) @ (a y+self lineheight).
             a y < b y?
                [(a rect: (window corner x-4) @ b y) comp]    ↪middle (if any)↪
            ]].
        a y > b y?[]
        (a x @ b y rect: b x @ (b y + self lineheight)) comp.    ↪bottom (or only)↪]’

ParagraphEditor understands: ’
selectword | a b dir t level open close
    [self comp: p1 to: p2.
    a← b← dir← ¬1.
    open ← ’’([{< ’’’’↪
’’.
    close ← ’’)]}> ’’’’↪
’’.
        [loc1>para length?[]
            loc1≤1?[dir←1]
            t←open find: (a←para◦(loc1-1)). t>0?        ↪delim on left↪
                [dir←1. b←close◦t.        ↪match to the right↪
                a=b?[a←¬2]]        ↪non-nesting↪
            t←close find: (a←para◦loc1). t>0?        ↪delim on right↪
                [dir←¬1. b←open◦t.        ↪match to the left↪
                a=b?[a←¬2]]        ↪non-nesting↪
            a← ¬1].        ↪no delims - select a token↪
        t←loc1-1. level←1.
        until⦂ [t≤1?[] t≥para length?[] level=0?[] false] do⦂
            [para◦(t← t+dir) = b? [level← level-1];        ↪leaving nest↪
            = a? [level← level+1].        ↪entering nest↪
            a=¬1?[(para◦t) tokenish?[]        ↪token check goes left ↪
                    dir=¬1?[loc1 ← t+1. dir←1. t←loc2]    ↪then right↪
                    level← 0]]
    [dir=1?[loc2← t] loc1← t+1].
    self select]’
Integer understands: ’tokenish
        ↪test for token-chars↪
    [self isletter?[!true]    ↪lower-case↪
     self isdigit?[!true]    ↪digits↪
     !’’¬.:⦂’’ has: self]’    ↪also high-minus and dot↪

CLASS EDITOR
Class new title: ’ClassEditor’;
    subclassof: ParagraphEditor;
    fields: ’class selector’
ClassEditor understands: ’firsttime
    [window has: user mp?
        [window outline. self enter: window]
    !false]’
ClassEditor understands: ’
eachtime
    [window has: user mp?
        [user kbck?[self kbd: nil]
        user anybug?
            [user redbug?[!self redbug: nil]
            user yellowbug?[self yellowbug: nil]
            user bluebug?[window ← Rectangle new fromuser.
                    self firsttime]]]
    user yellowbug?[self close. !false]
    user anybug?[self leave. !false]]’
ClassEditor understands: ’
lasttime
    [self leave]’

ClassEditor understands: ’
class: class selector: selector
        para: para window: window
    [para ← para asParagraph. style ← DefaultTextStyle.
    self enter: window]’
ClassEditor understands: ’
yellowbug: boss
    [class understands: para]’
ClassEditor understands: ’
close
    [(window inset: ¬2 @ ¬2) clear: backround.
    user unschedule: self]’

Class understands: ’
edit: selector
    [user schedule: (ClassEditor new class: self selector: selector
            para: (self code: selector) window: Rectangle new fromuser)]’

Dispframe understands: ’firsttime
    [text window has: user mp?
        [text window outline. self cr; append: ’’fi’’; show]
    !false]’
Dispframe understands: ’eachtime
    [text window has: user mp?
        [user kbck?[t← self read.
            self print: [t≡nil?[self doit] nilⓢt].
            self cr; append: ’’fi’’; show]]
    user anybug?[!false]]’
Dispframe understands: ’lasttime
    [self skip: [¬2 max: 0-position]; show]’

****** NOT DONE BEYOND HERE ******

↪OTHER PARAGRAPH STUFF↪
ParagraphEditor understands: ’kbdlook | t c
    [(c← user rawkbck)>170?
        [t← ctlchars find: c.
        t>0?[kbd. changed ← true.
                para changestyle: runvals◦t from: loc1+1 to: loc2]
        !false]
    !false]’
Peditorstuff insertall: "(ctlchars runvals) with: "(
        (226 233 224 173 242        ↪ctl- b i ... - r↪
            176 177 178 179 180 181 182 183 184 185    ↪ctl- 0 thru 9↪
            193 194 195 196 197 198)                    ↪ctl- A thru F↪
        (1 2 4 8 ¬1
            0 1 2 3 4 5 6 7 8 9
            10 11 12 13 14 15)
        ).
"t ← Peditorstuff◦"runvals.
    for i ← 6 to t length do
        (t[a] ← 16*t[a]).        ↪font number left 4 bits↪

ParagraphEditor understands: ’readchange
    [self cleanup. changed←false. !para]’
ParagraphEditor understands: ’fixframe: x
    [!x]’
ParagraphEditor understands: ’close: x []’
ParagraphEditor understands: ’outside: x [!false]’
ParagraphEditor understands: ’asParagraph
    [!para]’
ParagraphEditor understands: ’changed
    [!changed]’
ParagraphEditor understands: ’selection
    [!para copy: loc1 to: loc2-1]’


WINDOW FRAME AND CONTROL
Class new title: ’UserWindow’;
    fields: ’frame contents title’;
    sharing: Userstuff
UserWindow understands: ’frame: f contents: contents
    [frame ← contents fixframe f. self show]’
UserWindow understands: ’of: c
    [self frame: Rectangle new fromuser contents: c]’
UserWindow understands: ’show
    [self showin: user screenrect]’
UserWindow understands: ’showin: r | a
        [(a ← frame intersect: r) empty? []
        a color: dkgray mode: storing.
        ((frame inset: p1 and: p2) intersect: r) color: white mode: storing.
        contents enter: r.
        whitey show: contents title clipped: r]

UserWindow understands: ’firsttime
    [frame has: user mp? [self show] !false]’
UserWindow understands: ’eachtime
    [frame has: user mp?
        [user buttonck?
            [user redbug?[!contents redbug: self]
            user yellowbug?[!contents yellowbug: self]
            user bluebug?[!contents bluebug: self]]
        user kbck?[contents kbd: self]
        user keysetck?[contents keyset: self]]
    contents outside: self?[]
    user buttonck?[frame has mp?[] !false]
    user kbck?[user kbd; user flash] ↪flush typing outside↪]’
UserWindow understands: ’lasttime
    [!contents leave]’

UserWindow understands: ’newframe
    [while⦂ user buttonck do⦂ [].
    frame ← Rectangle new origin: (a← user mp) corner: a.
    while⦂ user buttonck do⦂
        [frame color: dkgray mode: xoring.
        frame ← contents fixframe: (frame growto: user mp).
        frame color: dkgray mode: xoring].
    frame color: dkgray mode: storing.
    whitey show: contents title.
    windowSched fillholes: (oldframe nonintersect: frame).
    !frame]’
UserWindow understands: ’close
    [contents close: self]’
UserWindow understands: ’movegrow
    [frame color: white mode: storing.
    frame ← self newframe.
    "a ← frame inset p1 p2.
    a paint 12 white.
    contents enter a inset p3 p4]’
↪***↪
UserWindow evals ["p1 ← point 3 fontheight+4. "p2 ← point 3 3.
        "p3 ← point 4 2. "p4 ← point 4 0. "p5 ← point 3 2.
        "whitey ← textframe rectangle p1 p1]’

FORMATTED TEXT
Paragraph understands: ’runfind b | a            ↪**index into run**↪
    [a←1.
    while⦂ true do⦂
        [runs◦a≥b? [!a , b]        ↪return run, index↪
        b ← b-(runs◦a). a ← a+2]]’
Paragraph understands: ’runs
        ↪**subrange of run**↪
    [%[?["a ← :.        ↪indexed by text, not run↪
            %to?
                ["b ← [%end?["c←runs length-1. point c runs[c]]
                        self runfind :]. %].
                a>text length?[!’’] "a ← self runfind a.
                "c ← runs[a x to b x+1].        ↪copy the sub-run↪
                c length=0?[!c]
                a x = b x?[0= c[1]← 1+ b y-a y ?[!’’] !c]
                c[1] ← 1+runs[a x] - a y.            ↪trim the end lengths↪
                c[c length-1] ← b y. !c]
            %]. !runs[self runfind a x+1]]
        !runs]’
string understands "runcat
        ↪**concatenate runs**↪
    ["x←:. x length=0?[] self length=0?[!x]
        self[self length]=x[2]?
            [!self[1 to self length-2]+
                [makerun self[self length-1]+x[1] x[2]]+
                x[3 to x length]]
        !self + x]’
Paragraph understands: ’asString [!text]’
Paragraph understands: ’[
        ↪**subranges and subscripting of text**↪
    ["a←:.
        %to?["b←:. %].
            %replace?["c←:.    ↪**alters self; doesn’t copy↪
                "runs ← self runs[1 to a-1]
                    runcat [c is string?[makerun c length self runs[b]] c runs]
                    runcat self runs[b+1 to end].
                "text ← text[a to b] replace
                    [c is string?[c] c text]]
            %changestyle?["c←:.
                "runs ← self runs[1 to a-1]
                    runcat [self mergestyle c into self runs[a to b]]
                    runcat self runs[b+1 to end]]
            %←?[%all?[text[a to b] ← all :]
                    text[a to b] ← :]
            !paragraph with text[a to b] self runs[a to b]]↪**copy align**↪
        %]. %←?[!text[a]←:]
        !text[a]]’
Paragraph understands: ’mergestyle
    ["a←:. %into. "b←:.
        for c← 2 to b length by 2 do
            [b[c] ← [a=¬1? [0]            ↪reset↪
                0<a≤017? [a &- b[c]]        ↪toggle emphasis↪
                a+017 &* b[c]]].    ↪new font↪
        !b]

"makerun ← function [run len str] ["len←:. "run←:.
        len=0?[!’’] "str←stream. repeat do
            [run<256?[str←len. str←run. !str contents]
            str←255. str←run. "len←len-255]]’
paragraphⓢinitcode ←
    ["alignment ← 0. %with?["text ← :.
            "runs ← [%onerun?[makerun text length :] :]]
        "text ← string 0]’
Paragraph understands: ’runshow | strm i
        ↪**print a run**↪
    [strm ← stream. for⦂ i from: (1 to: runs length by: 2) do⦂
        [strm append: (runs◦i) asString; append: ’.’.
        strm append: (runs◦(i+1)) asString; append: ’, ’]
    !strm contents]’

MENUS
"menu ← class [[pt i bits][str text thisline frame but][pt2][]] [] [] []’

menuⓢinitcode ←
    ["str←:. "but←:.
    "text ← textframe rectangle "pt←point 0 0 point 1000 1000 with str.
    for i to str length+1 do
        ["pt ← pt max text ptofchar i]
    textⓢframe growto pt+point 4 text fontheight.
    textⓢpara center.
    "frame ← textⓢframe inset "pt2←point ¬2 ¬2 pt2.
    "thisline←rectangle textⓢ frameⓢorigin
                point textⓢframeⓢextent x text fontheight]’
menu understands: ’bug
    ["pt←mp-thisline center.        ↪center prev item on mouse↪
        textⓢframe moveby pt. thisline moveby pt.
        frame moveby pt. "bits ← frame makebuff.        ↪save background↪
        frame paint 12 ¬1. text show.
        0=mouse 7?[frame loadbuff bits. !0]            ↪accidental bug returns 0↪
        thisline comp.
        repeat do [
            frame has "pt←mp?        ↪in the menu↪
                [button but?            ↪button still down↪
                    [thisline has pt?[]
                    text charnearpt pt. "pt←text reply.
                    thisline comp. thisline moveto    ↪selection follows mouse↪
                         point textⓢframeⓢorigin x pt y.
                    thisline comp]
                frame loadbuff bits.    ↪restore background, return index↪
                !1+[thislineⓢorigin-frameⓢorigin]y/text fontheight]
                thisline comp.         ↪he left the menu↪
            repeat do [button but?[frame has mp?[thisline comp. done]]
                        frame loadbuff bits. !0]    ↪return 0 for abort↪
        ]]’
menu understands: ’rebug
    [showcursor [but=1?[bug2cursor] bug3cursor]
            repeat do [button but?[done]]        ↪wait for button down again↪
        !self bug]’

BRAVO CONVERSION
"bravo2para ← function [a b c f ff i p q s st]
        ["f←:. f end?[!false]
        "a ← f upto 26. f next.        ↪pick up ascii↪
        "p ← paragraph.
        "b ← f upto 13. f next.            ↪pick up trailer↪
        "s ← stream of b. "st ← stream.
        repeat do
            ["c ← s next.                ↪scan for useful para info↪
            c=’c’[1]?[p center]
            c=’j’[1]?[p justify]
            c=’\’[1]?[done]
            st ← c]                ↪stache rest for later bravo output↪
        ↪pⓢtrailer ← st contents.↪ st reset.
        "ff← "len ← "run ← 0. "q←1.
        repeat do
            [s end?[done]
            "c ← s next.
            0< "i← ’bBiIuUnNfoy’[1 to 11] find c ?
            ["[["run ← run+1]        ["run ← run-1]        ↪bold↪
                ["run ← run+2]        ["run ← run-2]        ↪italic↪
                ["run ← run+4]        ["run ← run-4]        ↪underline↪
                ["run ← run+8]        ["run ← run-8]        ↪strikeout↪
                ["run ← [run &* 017] + 16*"ff← scannum s]    ↪font↪
                ["r←scannum s. "run ← [run &* 017] +         ↪super/sub script↪
                    16*[r=0?[ff] r>128?[11] 10]]                    ↪later vary by font↪
                [scannum s]]        ↪tab color↪
                [i] eval]
            060≤c≤071?[s skip ¬1. "r ← scannum s.    ↪get run length↪
                "len ← len+r.        ↪later merge across ignored changes↪
                st ← makerun r run]]
        [0< "r← a length-len?
            [st ← makerun r run]]
        pⓢchars ← a. pⓢruns ← st contents. !p]’
"scannum ← function [f c i] ["f←:. "i←0.
    repeat do
        ["c←f next.
        060≤c≤071?["i← [10*i] + c-060]
        f skip ¬1. done]
    !i]’