-- 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.
Last Edited by: Maxwell, January 5, 1983 12:35 pm
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 = BOOLEANFALSE;
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: BOOLEANFALSE, 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: BOOLEANTRUE]
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.