<<-- TextLooks.mesa>> <<-- written by Bill Paxton, February 1981>> <<-- last edit by Bill Paxton, December 13, 1982 1:17 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. >> <> DIRECTORY Rope; TextLooks: CEDAR DEFINITIONS = BEGIN Runs: TYPE = REF RunsBody; 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]; Offset: TYPE = LONG INTEGER; MaxOffset: Offset = LAST[Offset]; OutOfBounds: ERROR; LooksToRope: PROC [looks: Looks] RETURNS [rope: Rope.ROPE]; RopeToLooks: PROC [rope: Rope.ROPE] RETURNS [looks: Looks]; <<-- **** General operations on runs ****>> CreateRun: PROC [len: Offset, looks: Looks _ noLooks] RETURNS [Runs]; FetchLooks: PROC [runs: Runs, index: Offset] RETURNS [Looks]; <<-- returns the looks for the character at the given location>> CountRuns: PROC [runs: Runs, start, len: Offset, limit: Offset _ MaxOffset, merge: BOOLEAN _ FALSE, firstLooks: Looks _ noLooks] RETURNS [count: Offset, 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>> Size: PROC [base: Runs] RETURNS [size: Offset] = TRUSTED INLINE { RETURN [IF base = NIL THEN 0 ELSE WITH x:base SELECT FROM base => IF x.length=0 THEN 0 ELSE x[x.length-1].after, node => LOOPHOLE[base, REF Tconcat].size, ENDCASE => ERROR] }; <<-- **** Operations to change looks ****>> ChangeLooks: PROC [ runs: Runs, size: Offset, remove, add: Looks, start: Offset _ 0, len: Offset _ MaxOffset] RETURNS [Runs]; <<-- first remove then add in the given range>> AddLooks: PROC [ runs: Runs, size: Offset, add: Looks, start: Offset _ 0, len: Offset _ MaxOffset] RETURNS [Runs] = INLINE { RETURN [ ChangeLooks[runs, size, noLooks, add, start, len] ] }; RemoveLooks: PROC [ runs: Runs, size: Offset, remove: Looks _ allLooks, start: Offset _ 0, len: Offset _ MaxOffset] RETURNS [Runs] = INLINE { RETURN [ ChangeLooks[runs, size, remove, noLooks, start, len] ] }; SetLooks: PROC [ runs: Runs, size: Offset, new: Looks, start: Offset _ 0, len: Offset _ MaxOffset] RETURNS [Runs] = INLINE { RETURN [ ChangeLooks[runs, size, allLooks, new, start, len] ] }; ClearLooks: PROC [ runs: Runs, size: Offset, start: Offset _ 0, len: Offset _ MaxOffset] RETURNS [Runs] = INLINE { RETURN [ ChangeLooks[runs, size, allLooks, noLooks, start, len] ] }; <<-- **** Editing Operations ****>> Substr: PROC [base: Runs, start: Offset, len: Offset] RETURNS [Runs]; <<-- returns a substring of the runs>> Flatten: PROC [base: Runs] RETURNS [new: Runs]; <<-- returns a flattened version of base runs>> <<-- returns a flattened version of base runs>> <<-- new has at most 5 pieces; reuses biggest pieces of base>> Concat: PROC [base, rest: Runs, baseLen, restLen: Offset] RETURNS [Runs]; <<-- returns the concatenation of two Runs>> Replace: PROC [ base: Runs, start, len: Offset, replace: Runs, baseSize, repSize: Offset, tryFlat: BOOLEAN _ TRUE] RETURNS [Runs]; <<-- returns new Runs with the given range replaced>> Delete: PROC [base: Runs, start, len, baseSize: Offset] RETURNS [Runs] = INLINE { RETURN [ Replace[base,start,len,NIL,baseSize,0] ] }; Insert: PROC [base, insert: Runs, loc, baseSize, insertSize: Offset] RETURNS [Runs] = INLINE { RETURN [ Replace[base,loc,0,insert,baseSize,insertSize] ] }; Copy: PROC [dest: Runs, destLoc: Offset, source: Runs, start, len, destSize: Offset] RETURNS [Runs]; ReplaceByRun: PROC [ dest: Runs, start, len, runLen, destSize: Offset, inherit: BOOLEAN, looks: Looks] RETURNS [Runs]; <<-- equivalent to, but faster than,>> <<-- Replace[dest,start,len,CreateRun[runLen,xlooks],destSize,runLen]>> <<-- where xlooks determined in the following manner:>> <<-- if inherit is false, looks specifed in arg list >> <<-- if inherit is true, looks found in following manner:>> <<-- if destSize is 0, then take looks from argument list, else>> <<-- if start > 0, then looks of previous char,>> <<-- else looks following replacement>> LooksStats: PROC [base: Runs, start: Offset _ 0, len: Offset _ MaxOffset] RETURNS [size, pieces, depth: Offset]; <<-- ***** Initialization>> Start: PROC; -- for initialization only <<-- ***** Offseternal declarations>> LooksBytes: TYPE = MACHINE DEPENDENT RECORD [ byte0(0:0..7), byte1(0:8..15), byte2(1:0..7), byte3(1:8..15): [0..255] _ 0]; qZone: ZONE; -- quantized zone for allocating looks records pZone: ZONE; -- prefixed zone for allocating looks records RunsBody: TYPE = RECORD [SELECT tag: * FROM <<-- RunsBody is modeled after RopeRep from ROPE.Mesa>> base => [runs: SEQUENCE length: NAT OF Run], node => [SELECT case: * FROM substr => [size: Offset, base: Runs, start: Offset], concat => [size: Offset, base,rest: Runs, pos: Offset], replace => [size: Offset, base,replace: Runs, start,oldPos,newPos: Offset], change => [size: Offset, base: Runs, remove,add:Looks, start,len: Offset], ENDCASE], ENDCASE]; Run: TYPE = RECORD [after: Offset _ 0, looks: Looks _ noLooks]; BaseRuns: TYPE = REF Tbase; Tbase: TYPE = base RunsBody; Tsubstr: TYPE = substr node RunsBody; Tconcat: TYPE = concat node RunsBody; Treplace: TYPE = replace node RunsBody; Tchange: TYPE = change node RunsBody; FlatMax: Offset = 10; -- flatten if length of run <= FlatMax END.