-- 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.