-- TextLooks.mesa -- written by Bill Paxton, February 1981 -- last edit by Bill Paxton, March 24, 1981 3:46 PM -- This package provides Looks for text in Tioga -- it allows a client to associate looks with characters in a rope -- looks are represented as a vector of 32 bits -- The implementation expects that long sequences will have the same looks -- and thus uses a run encoding to save space. -- The runs of looks are immutable just like the text in a rope. -- i.e., you don't change runs; -- instead you build new ones out of parts of old ones -- Also like ropes, we use piece tables in the implementation -- thus making the cost of setting looks independent of the size of the rope. TextLooks: DEFINITIONS = BEGIN Runs: TYPE = REF RunsBody; RunsBody: TYPE = PRIVATE RECORD [SELECT kind:OfRuns FROM substr => [base:Runs, start,len:Card], concat => [base,rest:Runs, size,pos:Card], replace => [base,replace:Runs, start,oldPos,newPos,size:Card], change => [base:Runs, remove,add:Looks, start,len,size:Card], base => [runs:SEQUENCE length:NAT OF Run], ENDCASE]; OfRuns: PRIVATE TYPE = {substr, concat, replace, change, base}; Run: TYPE = PRIVATE RECORD [after: Card _ 0, looks: Looks _ noLooks]; BaseRuns: PRIVATE TYPE = REF base RunsBody; FlatMax: Card = 10; -- flatten if length of run <= FlatMax Looks: TYPE = PACKED ARRAY Look OF Bit; Look: TYPE = CHARACTER ['a..'a+31]; -- 32 bits; indexed from "a" Bit: TYPE = BOOLEAN _ FALSE; noLooks: Looks = ALL[FALSE]; allLooks: Looks = ALL[TRUE]; LooksBytes: TYPE = MACHINE DEPENDENT RECORD [ byte0(0:0..7), byte1(0:8..15), byte2(1:0..7): [0..255] _ 0, extra(1:8..9): [0..3] _ 0, spare(1:10..15): [0..63] _ 0]; LooksExtra: PROC [looks: Looks] RETURNS [[0..3]] = INLINE { RETURN[LOOPHOLE[looks, LooksBytes].extra] }; Card: TYPE = LONG CARDINAL; MaxCard: Card = LAST[Card]; OutOfBounds: ERROR; -- **** General operations **** FetchLooks: PROC [runs: Runs, index: Card] RETURNS [Looks]; -- returns the looks for the character at the given location CreateRun: PROC [len: Card, looks: Looks _ noLooks] RETURNS [Runs]; -- **** Operations on runs **** CountRuns: PROC [runs: Runs, start, len: Card, limit: Card _ MaxCard, merge: BOOLEAN _ FALSE, firstLooks: Looks _ noLooks] RETURNS [count: Card, nonempty: BOOLEAN, lastLooks: Looks]; -- counts the number of runs in the given range -- stops counting if reaches limit -- if merge is true, then doesn't count first run if its looks=firstLooks ChangeLooks: PROC [ runs: Runs, size: Card, remove, add: Looks, start: Card _ 0, len: Card _ MaxCard] RETURNS [Runs]; -- first remove then add in the given range AddLooks: PROC [ runs: Runs, size: Card, add: Looks, start: Card _ 0, len: Card _ MaxCard] RETURNS [Runs] = INLINE { RETURN [ ChangeLooks[runs, size, noLooks, add, start, len] ] }; RemoveLooks: PROC [ runs: Runs, size: Card, remove: Looks _ allLooks, start: Card _ 0, len: Card _ MaxCard] RETURNS [Runs] = INLINE { RETURN [ ChangeLooks[runs, size, remove, noLooks, start, len] ] }; SetLooks: PROC [ runs: Runs, size: Card, new: Looks, start: Card _ 0, len: Card _ MaxCard] RETURNS [Runs] = INLINE { RETURN [ ChangeLooks[runs, size, allLooks, new, start, len] ] }; ClearLooks: PROC [ runs: Runs, size: Card, start: Card _ 0, len: Card _ MaxCard] RETURNS [Runs] = INLINE { RETURN [ ChangeLooks[runs, size, allLooks, noLooks, start, len] ] }; -- there is no MapLookRuns. use TiogaRunReader's instead -- **** Editing Operations **** Substr: PROC [base: Runs, start: Card _ 0, len: Card _ MaxCard] RETURNS [Runs]; -- returns a substring of the runs Concat: PROC [base, rest: Runs, baseLen, restLen: Card] RETURNS [Runs]; -- returns the concatenation of two Runs Replace: PROC [base, replace: Runs, start, len, baseSize, repSize: Card] RETURNS [Runs]; -- returns new Runs with the given range replaced Delete: PROC [base: Runs, start, len, baseSize: Card] RETURNS [Runs] = INLINE { RETURN [ Replace[base, NIL, start, len, baseSize, 0] ] }; Insert: PROC [base, insert: Runs, loc, baseSize, insertSize: Card] RETURNS [Runs] = INLINE { RETURN [ Replace[base, insert, loc, 0, baseSize, insertSize] ] }; Copy: PROC [dest,source: Runs, destSize,destLoc,start,len: Card] RETURNS [Runs] = INLINE { RETURN [ Replace[dest, Substr[source,start,len], destLoc, 0, destSize, len]] }; Move: PROC [base: Runs, baseSize, dest, start, len: Card] RETURNS [Runs]; -- dest must not be in [start..start+len) Transpose: PROC [base: Runs, baseSize, astart, alen, bstart, blen: Card] RETURNS [Runs]; -- [astart..astart+alen) must not intersect [bstart..bstart+blen) BadMove, BadTranspose: ERROR; AddRun: PROC [ base: Runs, baseSize, loc, len: Card, inherit: BOOLEAN _ TRUE, looks: Looks _ noLooks] RETURNS [Runs]; END. (635)