DIRECTORY AbbrevExpand, Atom, Basics, EditSpan, FS, IO, PutGet, RefTab, Rope, RopeEdit, RopeReader, TextEdit, TextLooks, TextNode; AbbrevExpandImpl: CEDAR MONITOR IMPORTS Atom, EditSpan, FS, Basics, IO, PutGet, RefTab, Rope, RopeEdit, RopeReader, TextEdit, TextNode EXPORTS AbbrevExpand = BEGIN OPEN AbbrevExpand; dictTable: RefTab.Ref _ RefTab.Create[mod: 67]; Entry: TYPE = REF EntryRec; EntryRec: TYPE = RECORD [ next: Entry, hash: CARDINAL, keyRope: ROPE, node: RefTextNode, commands: LIST OF REF ANY ]; Load: PUBLIC PROC [fileName, dictName: ROPE, start: Offset _ 0, len: Offset _ MaxLen] RETURNS [count: NAT] = { rdr: RopeReader.Ref; dict: ATOM = GetDictAtom[dictName]; root: Ref; count _ 0; [] _ RefTab.Store[dictTable, dict, NoDictAtom]; -- clears the dictionary root _ PutGet.FromFile[fileName, start, len]; rdr _ RopeReader.GetRopeReader[]; FOR n: Ref _ TextNode.FirstChild[root], TextNode.Next[n] UNTIL n=NIL DO node: RefTextNode _ TextNode.NarrowToTextNode[n]; IF node=NIL OR node.rope=NIL THEN LOOP; AddToDict[root, node, dict, rdr]; count _ count+1; ENDLOOP; RopeReader.FreeRopeReader[rdr] }; AddToDict: ENTRY PROC [ root: Ref, node: RefTextNode, dictAtom: ATOM, rdr: RopeReader.Ref _ NIL] = { ENABLE UNWIND => NULL; dict: Entry _ GetDict[dictAtom]; keyRope: ROPE _ node.rope; keyStart: Offset = 0; hash: CARDINAL; entry: Entry; keyLen: NAT; freeRdr: BOOL _ FALSE; resultStart: Offset; commands: LIST OF REF ANY; IF rdr=NIL THEN { rdr _ RopeReader.GetRopeReader[]; freeRdr _ TRUE }; keyLen _ FindKeyLen[keyRope,rdr]; IF keyLen=0 THEN { IF freeRdr THEN RopeReader.FreeRopeReader[rdr]; RETURN }; -- not an entry hash _ KeyHash[keyRope,keyStart,keyLen,rdr]; entry _ LookupInternal[dict,hash,keyRope,keyStart,keyLen,rdr]; IF entry = NIL THEN { -- add new entry entry _ TextNode.pZone.NEW[EntryRec]; IF dict # NIL THEN { entry.next _ dict.next; dict.next _ entry } ELSE [] _ RefTab.Store[dictTable,dictAtom,entry] }; entry.hash _ hash; entry.keyRope _ RopeEdit.Substr[keyRope,keyStart,keyLen]; entry.node _ node; [resultStart,commands] _ ParseCommands[keyRope,keyStart+keyLen,rdr]; entry.commands _ commands; TextEdit.DeleteText[root,node,0,resultStart]; IF freeRdr THEN RopeReader.FreeRopeReader[rdr]; }; ParseCommands: PROC [keyRope: ROPE, start: Offset, rdr: RopeReader.Ref] RETURNS [end: Offset, commands: LIST OF REF ANY] = { OPEN RopeReader; ENABLE ReadOffEnd => GOTO Bad; blank: BOOL; SetPosition[rdr, keyRope, start]; IF RopeEdit.BlankChar[Peek[rdr]] THEN { blank _ TRUE; [] _ Get[rdr] } ELSE blank _ FALSE; IF Peek[rdr] = '( THEN { -- parse command list h: IO.STREAM _ IO.RIS[RopeEdit.Substr[keyRope,start _ GetIndex[rdr]]]; -- commands _ NARROW[IO.GetRefAny[h]]; start _ start+IO.GetIndex[h]; IO.Close[h]; SetPosition[rdr, keyRope, start]; IF RopeEdit.BlankChar[Peek[rdr]] THEN { blank _ TRUE; [] _ Get[rdr] } ELSE blank _ FALSE; }; IF Peek[rdr] = '= THEN { -- check for blank [] _ Get[rdr]; IF blank AND Peek[rdr] = ' THEN [] _ Get[rdr]; -- skip blank after = if there was one before end _ GetIndex[rdr]; } ELSE end _ RopeEdit.Size[keyRope]; EXITS Bad => RETURN [RopeEdit.Size[keyRope],commands]; }; Clear: PUBLIC ENTRY PROC [dictName: ROPE] = { ENABLE UNWIND => NULL; [] _ RefTab.Store[dictTable, GetDictAtom[dictName], NIL] }; IllFormedDef: PUBLIC ERROR = CODE; GetDictAtom: PROC [dictName: ROPE] RETURNS [dict: ATOM] = { force: SAFE PROC RETURNS [c: CHAR] = CHECKED { IF (c _ Rope.Fetch[dictName,i]) IN ['A..'Z] THEN c _ c-'A+'a; i _ i+1 }; i: INT _ 0; RETURN [Atom.MakeAtom[Rope.FromProc[Rope.Size[dictName],force]]]; }; Expand: PUBLIC PROC [keyNode: RefTextNode, keyEnd: Offset, dict: ROPE, event: Event _ NIL] RETURNS [foundIt: BOOL, keyDeterminesDict: BOOL, keyStart, keyLen, resultLen: Offset, commands: LIST OF REF ANY] = { FindEntry: PROC [dictAtom: ATOM] RETURNS [BOOL] = { dict: Entry _ GetDict[dictAtom]; IF dict#NIL THEN entry _ Lookup[dict,hash,keyRope,keyStart,kLen,rdr]; RETURN [entry # NIL]; }; rdr: RopeReader.Ref; dictAtom: ATOM = GetDictAtom[dict]; keyRope: ROPE _ keyNode.rope; kLen: NAT; kStart: Offset; hash: CARDINAL; entry: Entry; foundIt _ keyDeterminesDict _ FALSE; resultLen _ 0; rdr _ RopeReader.GetRopeReader[]; keyEnd _ MAX[0,MIN[keyEnd,RopeEdit.Size[keyRope]]]; kStart _ keyStart _ FindKeyStart[keyRope,keyEnd,rdr]; kLen _ keyLen _ keyEnd-keyStart; hash _ KeyHash[keyRope,keyStart,keyEnd,rdr]; RopeReader.SetPosition[rdr,keyRope,keyStart]; IF keyStart > 0 AND RopeReader.Backwards[rdr]='. THEN { -- try to get the dictName from the key nameStart: Offset _ FindKeyStart[keyRope,keyStart-1,rdr]; IF nameStart < keyStart-1 THEN { dictName: ATOM _ Atom.MakeAtom[RopeEdit.Substr[keyRope,nameStart,keyStart-1-nameStart]]; [] _ FindEntry[dictName]; keyDeterminesDict _ TRUE; keyLen _ keyEnd - (keyStart _ nameStart) }}; IF entry = NIL THEN [] _ FindEntry[dictAtom]; IF entry = NIL THEN { RopeReader.FreeRopeReader[rdr]; RETURN }; { -- do it CheckCaps: PROC = INLINE { allcaps _ FALSE; RopeReader.SetPosition[rdr,keyRope,kStart]; initialcap _ RopeReader.Peek[rdr] IN ['A..'Z]; FOR i:Offset IN [0..kLen) DO IF RopeReader.Get[rdr] NOT IN ['A..'Z] THEN RETURN; ENDLOOP; allcaps _ TRUE }; node: RefTextNode = entry.node; root: Ref = TextNode.Root[node]; keyRoot: Ref = TextNode.Root[keyNode]; nodeRope: ROPE _ node.rope; looks: TextLooks.Looks _ TextEdit.FetchLooks[keyNode,kStart]; allcaps, initialcap: BOOL _ FALSE; type: TextNode.TypeName; child: RefTextNode _ TextNode.NarrowToTextNode[TextNode.FirstChild[node]]; textLen: Offset _ RopeEdit.Size[nodeRope]; CheckCaps; RopeReader.FreeRopeReader[rdr]; [,resultLen] _ TextEdit.ReplaceText[ destRoot: keyRoot, sourceRoot: root, dest:keyNode, destStart:keyStart, destLen:keyLen, source:node, sourceStart:0, sourceLen:textLen, event:event]; IF resultLen # textLen THEN ERROR; IF looks # TextLooks.noLooks THEN TextEdit.AddLooks[keyRoot,keyNode,looks,keyStart,textLen,event]; IF allcaps THEN TextEdit.AllCaps[keyRoot,keyNode,keyStart,textLen,event] ELSE IF initialcap AND textLen > 0 THEN -- make first letter uppercase TextEdit.AllCaps[keyRoot,keyNode,keyStart,1,event]; SELECT type _ TextNode.NodeType[node] FROM TextNode.nullTypeName, TextNode.NodeType[keyNode] => NULL; ENDCASE => TextEdit.ChangeType[keyNode,type,event,keyRoot]; IF child # NIL THEN { -- insert as children of keyNode new: TextNode.Span _ EditSpan.Copy[keyRoot,root,TextNode.MakeNodeLoc[keyNode], TextNode.MakeNodeSpan[child,TextNode.LastWithin[node]], FALSE,after,1,event]; last: TextNode.RefTextNode _ TextNode.NarrowToTextNode[new.end.node]; IF last # NIL AND keyStart+textLen < TextEdit.Size[keyNode] THEN -- move text after key to end of last new node [] _ TextEdit.MoveText[ destRoot: keyRoot, sourceRoot: keyRoot, dest: last, destLoc: TextEdit.MaxLen, source: keyNode, start: keyStart+textLen, len: TextEdit.MaxLen, event: event] }; foundIt _ TRUE; commands _ entry.commands; }}; KeyHash: PROC [keyRope: ROPE, keyStart, keyEnd: Offset, rdr: RopeReader.Ref] RETURNS [h: CARDINAL] = { len: NAT _ keyEnd-keyStart; RopeReader.SetPosition[rdr,keyRope,keyStart]; h _ 0; FOR i: NAT IN [1..MIN[3,len]) DO -- use the first 3 characters h _ Basics.BITXOR[Basics.BITSHIFT[h,2], RopeEdit.UpperCase[RopeReader.Get[rdr]]-0C]; ENDLOOP; IF len >= 2 THEN { -- use the last 2 characters RopeReader.SetPosition[rdr,keyRope,keyEnd]; FOR i: NAT IN [len-2..len) DO h _ Basics.BITXOR[Basics.BITSHIFT[h,2], RopeEdit.UpperCase[RopeReader.Backwards[rdr]]-0C]; ENDLOOP }}; Lookup: ENTRY PROC [dict: Entry, hash: CARDINAL, keyRope: ROPE, keyStart: Offset, keyLen: NAT, rdr1, rdr2, rdr3: RopeReader.Ref _ NIL] RETURNS [entry: Entry] = INLINE { ENABLE UNWIND => NULL; RETURN [LookupInternal[dict,hash,keyRope,keyStart,keyLen,rdr1,rdr2,rdr3]] }; LookupInternal: PROC [dict: Entry, hash: CARDINAL, keyRope: ROPE, keyStart: Offset, keyLen: NAT, rdr1, rdr2, rdr3: RopeReader.Ref _ NIL] RETURNS [entry: Entry] = { FreeReaders: PROC = INLINE { IF free1 THEN RopeReader.FreeRopeReader[rdr1]; IF free2 THEN RopeReader.FreeRopeReader[rdr2]; IF free3 THEN RopeReader.FreeRopeReader[rdr3] }; free1, free2, free3: BOOL _ FALSE; pred: Entry _ NIL; IF keyLen=0 THEN RETURN [NIL]; IF rdr1=NIL THEN { free1 _ TRUE; rdr1 _ RopeReader.GetRopeReader[] }; IF rdr2=NIL THEN { free2 _ TRUE; rdr2 _ RopeReader.GetRopeReader[] }; IF rdr3=NIL THEN { free3 _ TRUE; rdr3 _ RopeReader.GetRopeReader[] }; RopeReader.SetPosition[rdr1, keyRope, keyStart]; -- leave this at the start of the key [] _ RopeReader.Peek[rdr1]; -- prime the reader for the key entry _ NIL; -- will stay nil if don't find key in dict FOR e: Entry _ dict, e.next UNTIL e=NIL DO IF e.hash = hash AND RopeEdit.Size[e.keyRope] = keyLen THEN { -- check the ropes rdr2^ _ rdr1^; IF RopeReader.CompareSubstrs[keyRope,e.keyRope, keyStart,keyLen,0,keyLen,rdr2,rdr3,FALSE] = equal THEN { IF pred # NIL THEN { -- move entry to front pred.next _ e.next; e.next _ dict.next; dict.next _ e }; entry _ e; EXIT }}; pred _ e; ENDLOOP; FreeReaders[] }; FindKeyLen: PROC [keyRope: ROPE, rdr: RopeReader.Ref] RETURNS [len: NAT] = { size: Offset _ RopeEdit.Size[keyRope]; IF size=0 THEN RETURN [0]; RopeReader.SetPosition[rdr,keyRope,0]; IF RopeEdit.PunctuationChar[RopeReader.Peek[rdr]] THEN RETURN [1]; len _ 0; WHILE len0 AND RopeEdit.AlphaNumericChar[RopeReader.Backwards[rdr]] DO start _ start-1; ENDLOOP }; NoDictAtom: ATOM = $NoDictionaryAvailable; GetDict: PROC [dictName: ATOM] RETURNS [entry: Entry] = { prop: REF ANY; prop _ RefTab.Fetch[dictTable,dictName].val; WITH prop SELECT FROM x: Entry => RETURN [x]; x: ATOM => IF x = NoDictAtom THEN RETURN [NIL] ELSE ERROR; ENDCASE => { -- try to load it r: ROPE _ Atom.GetPName[dictName]; fileName: ROPE _ RopeEdit.Concat[r,".Abbreviations"]; [] _ RefTab.Store[dictTable, dictName, NoDictAtom]; [] _ Load[fileName, r ! FS.Error => CHECKED {CONTINUE}]; RETURN [GetDict[dictName]] }}; Start: PUBLIC PROC = { }; END. ØAbbrevExpandImpl.mesa - implements abbreviation expansion in Tioga written by Bill Paxton, May 1981 Paxton, November 8, 1982 1:31 pm Plass, April 13, 1983 1:25 pm Russ Atkinson, September 26, 1983 1:21 pm -- ***** Declarations -- ***** Operations ***** -- clear the specified abbreviation dictionary -- force dictName lowercase before create the atom -- see if have '. before -- hash must be independent of case of chars -- ***** Initialization Ê É˜šÏcB™BJš ™ Jš ™ J™J™)—J˜šÏk ˜ J˜ J˜J˜J˜ Jšžœ˜Jšžœ˜J˜J˜J˜J˜ J˜ J˜ J˜ J˜ —J˜šœž ˜šž˜Jšœžœ žœ@˜^—Jšžœ ˜Jšœž œ˜—J˜Jš™˜J˜/J˜Jšœžœžœ ˜šœ žœžœ˜J˜ Jšœžœ˜Jšœ žœ˜J˜Jšœ žœžœžœž˜J˜—J˜—Jš™J˜šÏnœžœž˜Jšœžœ*˜CJšžœ žœ˜J˜Jšœžœ˜#J˜ J˜ Jšœ0˜HJ˜-J˜!šžœ6žœžœž˜GJ˜1Jš žœžœžœ žœžœžœ˜'J˜!J˜Jšžœ˜—J˜!J˜—šŸ œžœžœ˜Jšœ(žœžœ˜LJšžœžœžœ˜J˜J˜ Jšœ žœ ˜J˜Jšœžœ˜J˜ Jšœžœ˜ Jšœ žœžœ˜J˜Jš œ žœžœžœžœ˜J˜Jšžœžœžœ/žœ˜EJ˜!Jš žœ žœžœ žœ!žœ˜\J˜,J˜>šžœ žœžœ˜&Jšœžœ ˜%Jšžœžœžœ.˜@Jšžœ/˜3—J˜J˜9J˜J˜DJ˜J˜-Jšžœ žœ ˜/J˜J˜—šŸ œžœ žœ%˜GJš žœžœžœžœžœžœ ˜EJšžœžœ˜Jšœžœ˜ J˜!Jš žœžœ žœžœ žœ˜Yšžœžœ˜.Jš œžœžœžœžœ1˜FJšœžœžœ˜&Jšœžœ ˜Jšžœ ˜ J˜!Jš žœžœ žœžœ žœ˜YJ˜—šžœžœ˜+J˜Jšžœžœžœ-˜]J˜J˜—Jšžœ˜"Jšžœžœ#˜6J˜J˜—š Ÿœžœžœžœ žœ˜-Jš.™.Jšžœžœžœ˜Jšœ4žœ˜;J˜—Jšœžœžœžœ˜"J˜š Ÿ œžœ žœžœžœ˜;Jš2™2š œžœžœžœžœžœ˜.Jšžœžœ žœ ˜=J˜ —Jšœžœ˜ Jšžœ;˜AJ˜J˜—šŸœžœž˜Jšœ-žœžœ˜Fšžœ žœžœ1žœžœžœžœ˜tJ˜—š Ÿ œžœ žœžœžœ˜3J˜ Jšžœžœžœ5˜EJšžœ žœ˜Jšœ˜J˜—J˜Jšœ žœ˜#Jšœ žœ˜Jšœžœ˜ J˜Jšœžœ˜J˜ Jšœžœ˜$J˜J˜!Jšœ žœžœ!˜3J˜5J˜ J˜,Jš-™-J˜-šžœžœžœ'˜_J˜9šžœžœ˜ Jšœ žœJ˜XJ˜Jšœžœ˜J˜,——Jšžœ žœžœ˜-J˜Jšžœ žœžœ#žœ˜?Jšœ˜ ˜šŸ œžœžœ˜Jšœ žœ˜J˜+Jšœ"žœ ˜.šžœ žœ ž˜Jš žœžœžœ žœžœ˜3Jšžœ˜—Jšœ žœ˜J˜—J˜J˜ J˜&Jšœ žœ ˜J˜=Jšœžœžœ˜"J˜J˜JJ˜*J˜ J˜˜$J˜$J˜1J˜<—Jšžœžœžœ˜"šžœž˜!J˜@—Jšžœ žœ9˜Hš žœžœ žœ žœ˜FJ˜3—šžœ ž˜*Jšœ5žœ˜:Jšžœ4˜;—šžœ žœžœ ˜6˜NJ˜7Jšžœ˜—J˜Ešžœžœž˜Jšœ*žœ.˜]˜J˜MJ˜P———Jšœ žœ˜J˜J˜J˜——šŸœž˜ Jšœ žœ0˜>Jšžœžœ˜Jš,™,Jšœžœ˜J˜-J˜š žœžœžœžœ žœ˜>šœ žœžœ˜'J˜,—Jšžœ˜—šžœ žœ˜/J˜+šžœžœžœž˜šœ žœžœ˜'J˜2—Jšžœ˜ J˜———šŸœžœž˜šœžœ žœžœ˜KJšœ#žœ˜'—Jšžœžœ˜!Jšžœžœžœ˜JšžœF˜LJ˜—šŸœž˜šœžœ žœžœ˜KJšœ#žœ˜'—Jšžœ˜šŸ œžœžœ˜Jšžœžœ!˜.Jšžœžœ!˜.Jšžœžœ#˜0—Jšœžœžœ˜"Jšœžœ˜Jšžœ žœžœžœ˜Jšžœžœžœ žœ&˜EJšžœžœžœ žœ&˜EJšžœžœžœ žœ&˜EJšœ1%˜VJšœ˜;Jšœžœ*˜7šžœžœžœž˜*šžœžœ#žœ˜PJ˜šžœ-˜/šœ#žœ žœ˜8šžœžœžœ˜+J˜J˜J˜—Jšœ žœ˜———J˜ Jšžœ˜—J˜J˜—š Ÿ œžœ žœžœžœ˜LJ˜&Jšžœžœžœ˜J˜&Jšžœ0žœžœ˜BJ˜šžœ žœ0ž˜DJšœ žœ˜J˜——šŸ œžœ žœ&˜GJšžœ˜Jšžœžœ žœžœ˜4J˜+Jšžœ9žœžœ ˜RJ˜šžœ žœ6ž˜IJšœžœ˜J˜——Jšœ žœ˜*J˜šŸœžœ žœžœ˜9Jšœžœžœ˜J˜,šžœžœž˜Jšœ žœ˜Jšœžœžœžœžœžœžœžœ˜:šžœ˜Jšœžœ˜"Jšœ žœ'˜5J˜3Jšœžœ žœžœ˜8Jšžœ˜J˜———Jš™J˜šŸœžœžœ˜J˜J˜—Jšžœ˜J˜—…—(5±