-- TextEdit.mesa
-- written by Bill Paxton, February 1981
-- last edit by Bill Paxton, March 19, 1981 4:55 PM
-- This package provides editing of Text nodes as used in Tioga
-- a text node contains the following elements:
-- a rope (supplied by TextRope.Mesa)
-- runs of looks (supplied by TiogaLooks.Mesa)
-- "persistent" addresses for locations within the node
-- a property list
-- Editing
-- Operations are available to edit the contents of text nodes
-- unlike ropes or runs of looks, text nodes are mutable
-- Persistent addresses
-- You can associate an address with a location in a text node
-- the address persists at the same location even if the node is edited
-- the address is an arbitrary REF ANY supplied by the client program
-- Property list
-- Each node includes a property list
-- The keys and the values are arbitrary REF ANY's
-- Filing
-- There are operations to read and write files containing text nodes
-- The characters go at the front of the file, followed by 0's
-- then the information about looks, etc.
-- and finally a password and a pointer to the end of the text.
-- Thus programs that simply want to look at the characters can read up to 0's
-- Edit notification procedures
-- Client's can register procedures to be called before/after edits
-- The details are in EditNotify.Mesa
DIRECTORY
--File,
TextRope,
TextLooks,
TextNode,
NodeProps,
CardAddrs,
NodeAddrs;
TextEdit: DEFINITIONS
IMPORTS CardAddrs, NodeAddrs, NodeProps, TextLooks, TextRope =
BEGIN
OPEN
nodeI: TextNode,
propsI: NodeProps,
addrsI: NodeAddrs,
cardAddr: CardAddrs,
ropeI: TextRope,
looksI: TextLooks;
Ref: TYPE = nodeI.Ref;
RefTextNode: TYPE = nodeI.RefTextNode;
Rope: TYPE = ropeI.Rope;
Looks: TYPE = looksI.Looks;
noLooks: Looks = looksI.noLooks;
allLooks: Looks = looksI.allLooks;
Char: TYPE = CHARACTER;
Card: TYPE = LONG CARDINAL;
MaxLen: Card = LAST[Card];
MaxCard: Card = LAST[Card];
-- **** Operations to create/save a text node ****
FromRope: PROC [rope: Rope] RETURNS [RefTextNode];
-- create a text node with looks from a normal rope
FromString: PROC [string: REF READONLY TEXT] RETURNS [RefTextNode];
-- copies the contents of the string
GetRope: PROC [text: RefTextNode] RETURNS [Rope];
GetRuns: PROC [text: RefTextNode] RETURNS [looksI.Runs];
FileCapability: TYPE = REF; -- phony decl until goto Pilot
ToFile: PROC [file: FileCapability, node: Ref];
-- write the node on the specified file
FromFile: PROC [file: FileCapability] RETURNS [Ref];
-- create node from the contents of a file
-- if file was not created by ToFile (i.e., password not correct)
-- then returns FromRope[RopeFrom.File[file]]
-- **** Property List Operations ****
PutProp: PROC [node: Ref, name, val: REF] =
-- adds name & val to property list for node
INLINE { propsI.PutProp[node, name, val] };
RemProp: PROC [node: Ref, name: REF] RETURNS [REF] =
-- removes name & val from property list for node
-- returns old value, if any
INLINE { RETURN [propsI.RemProp[node, name]] };
GetProp: PROC [node: Ref, name: REF] RETURNS [REF] =
-- returns the value associated with the given name
-- value is NIL if name is not on the property list
INLINE { RETURN [propsI.GetProp[node, name]] };
MapProps: PROC [node: Ref, action: MapPropsAction] RETURNS [BOOLEAN] =
INLINE { RETURN [propsI.MapProps[node, LOOPHOLE[action]]] };
-- apply the action to each name & value pair for the node
-- returns true if&when an action returns true
MapPropsAction: TYPE = PROC [name, val: REF] RETURNS [BOOLEAN];
-- **** Persistent addressing for characters in text node ****
PutTextAddr: PROC [node: RefTextNode, addr: REF, location: Card] =
-- assigns addr to location in text
-- ok if addr was previously assigned elsewhere in the text
-- location automatically updated when text is edited
INLINE { addrsI.PutTextAddr[node, addr, location] };
RemTextAddr: PROC [node: RefTextNode, addr: REF] =
-- removes the given addr
INLINE { addrsI.RemTextAddr[node, addr] };
GetTextAddr: PROC [node: RefTextNode, addr: REF] RETURNS [location: Card] =
-- generates ERROR TextAddrNotFound if the addr is not in the mapping
INLINE { RETURN [
addrsI.GetTextAddr[node, addr
! cardAddr.AddrNotFound => ERROR TextAddrNotFound]] };
TryGetTextAddr: PROC [node: RefTextNode, addr: REF]
RETURNS [found: BOOLEAN, location: Card] =
INLINE { [found, location] ← addrsI.TryGetTextAddr[node, addr] };
TextAddrNotFound: ERROR;
MapTextAddrs: PROC [node: RefTextNode, action: TextAddrsAction]
RETURNS [BOOLEAN] =
INLINE { RETURN [addrsI.MapTextAddrs[node, action]] };
-- apply the action to each addr&location pair for the text
-- returns true if&when an action returns true
TextAddrsAction: TYPE = addrsI.TextAddrsAction;
-- = PROC [addr: REF, location: Card] RETURNS [BOOLEAN];
-- **** Persistent addressing for children of node ****
PutChildAddr: PROC [node: Ref, addr: REF, location: Card] =
-- assigns addr to node child number given by location
-- ok if addr was previously assigned in the node
-- location automatically updated when node children are edited
INLINE { addrsI.PutChildAddr[node, addr, location] };
RemChildAddr: PROC [node: Ref, addr: REF] =
-- removes the given addr
INLINE { addrsI.RemChildAddr[node, addr] };
GetChildAddr: PROC [node: Ref, addr: REF] RETURNS [location: Card] =
-- generates ERROR ChildAddrNotFound if the addr is not in the mapping
INLINE { RETURN [
addrsI.GetChildAddr[node, addr
! cardAddr.AddrNotFound => ERROR ChildAddrNotFound]] };
TryGetChildAddr: PROC [node: Ref, addr: REF]
RETURNS [found: BOOLEAN, location: Card] =
INLINE { [found, location] ← addrsI.TryGetChildAddr[node, addr] };
ChildAddrNotFound: ERROR;
FollowChildAddrs: PROC [node: Ref, addr: REF] RETURNS [Ref] =
-- follows addr chain down starting from node
-- returns first node in chain for which addr not found
INLINE { RETURN [ addrsI.FollowChildAddrs[node, addr]] };
MapChildAddrs: PROC [node: Ref, action: ChildAddrsAction]
RETURNS [BOOLEAN] =
INLINE { RETURN [addrsI.MapChildAddrs[node, action]] };
-- apply the action to each addr&location pair for the node
-- returns true if&when an action returns true
ChildAddrsAction: TYPE = addrsI.ChildAddrsAction;
-- = PROC [addr: REF, location: Card] RETURNS [BOOLEAN];
-- **** Operations to add or delete looks ****
-- Looks are represented by a vector of 32 bits
-- Each character in a text node has looks associated with it
-- see TiogaLooks.Mesa for more operations
ChangeLooks: PROC [
text: RefTextNode, remove, add: Looks,
start: Card ← 0, len: Card ← MaxCard];
-- first remove then add in the given range
AddLooks: PROC [
text: RefTextNode, add: Looks,
start: Card ← 0, len: Card ← MaxCard]
= INLINE { ChangeLooks[text, noLooks, add, start, len] };
RemoveLooks: PROC [
text: RefTextNode, remove: Looks ← allLooks,
start: Card ← 0, len: Card ← MaxCard]
= INLINE { ChangeLooks[text, remove, noLooks, start, len] };
SetLooks: PROC [
text: RefTextNode, new: Looks,
start: Card ← 0, len: Card ← MaxCard]
= INLINE { ChangeLooks[text, allLooks, new, start, len] };
ClearLooks: PROC [
text: RefTextNode, start: Card ← 0, len: Card ← MaxCard]
= INLINE { ChangeLooks[text, allLooks, noLooks, start, len] };
FetchLooks: PROC [text: RefTextNode, location: Card] RETURNS [Looks];
-- returns the looks for the character at the given location
-- use reader's if getting looks for sequence of locations
-- **** Changing Style / Type of node ****
ChangeType: PROC [
node: Ref, newStyle, newType: BOOLEAN,
styleName: nodeI.StyleName, typeName: nodeI.TypeName];
-- change style and/or type of node
-- **** Editing Operations for text ****
-- NOTE: edit operations do not create or delete addrs,
-- but they can change their locations within the text
ReplaceText: PROC [
dest: RefTextNode, destStart: Card ← 0, destLen: Card ← MaxLen,
source: RefTextNode, sourceStart: Card ← 0, sourceLen: Card ← MaxLen];
-- replace the dest text by a copy of the source text
-- addrs that are in the replaced text move to destStart
-- addrs that are after the replaced text are adjusted
DeleteText: PROC [
text: RefTextNode, start: Card ← 0, len: Card ← MaxLen] = INLINE {
-- delete the specified range of text
-- addrs that are in the deleted section move to start
ReplaceText[text, start, len, NIL] };
CopyText: PROC [
dest: RefTextNode, destLoc: Card,
source: RefTextNode, start: Card ← 0, len: Card ← MaxLen] = INLINE {
-- copy the specified text
-- add length of inserted text to addrs that are beyond destLoc
ReplaceText[dest, destLoc, 0, source, start, len] };
MoveText: PROC [
dest: RefTextNode, destLoc: Card,
source: RefTextNode, start: Card ← 0, len: Card ← MaxLen];
-- move the specified text
-- addrs that are in the moved text do one of the following:
-- move with the text if dest = source,
-- or move to start if dest # source
TransposeText: PROC [
alpha: RefTextNode, alphaStart: Card ← 0, alphaLen: Card ← MaxLen,
beta: RefTextNode, betaStart: Card ← 0, betaLen: Card ← MaxLen];
-- transpose the alpha text and the beta text
-- addrs treated same as in Move
-- move with the text if alpha = beta,
-- or move to respective starts if alpha # beta
ReplaceWords: PROC [
dest: RefTextNode, destStart: Card ← 0, destLen: Card ← MaxLen,
source: RefTextNode, sourceStart: Card ← 0, sourceLen: Card ← MaxLen];
-- replace the dest words by a copy of the source words
-- adjusts appropriately to retain proper spacing
-- calls notify procs with a ReplacingText change record
CopyWords: PROC [
dest: RefTextNode, destLoc: Card,
source: RefTextNode, start: Card ← 0, len: Card ← MaxLen] = INLINE {
-- copy the specified words
-- adjusts appropriately to retain proper spacing
ReplaceWords[dest, destLoc, 0, source, start, len] };
MoveWords: PROC [
dest: RefTextNode, destLoc: Card,
source: RefTextNode, start: Card ← 0, len: Card ← MaxLen];
-- move the specified words
-- adjusts appropriately to retain proper spacing
-- calls notify procs with a MovingText change record
TransposeWords: PROC [
alpha: RefTextNode, alphaStart: Card ← 0, alphaLen: Card ← MaxLen,
beta: RefTextNode, betaStart: Card ← 0, betaLen: Card ← MaxLen];
-- transpose the alpha words and the beta words
-- adjusts appropriately to retain proper spacing
-- calls notify procs with a TransposingText change record
InsertChar: PROC [
dest: RefTextNode, char: Char, destLoc: Card ← 0,
inherit: BOOLEAN ← TRUE, looks: Looks ← noLooks];
-- insert character at specified location
-- if destLoc >= size[dest], put character at end of dest
-- if inherit is false, char gets specifed looks
-- if inherit is true, char gets looks in following manner:
-- if dest length is 0, then gets looks from argument list, else
-- if location > 0, then looks and list of previous char,
-- else looks and list of following char
-- add 1 to location of names that are beyond destLoc
AppendChar: PROC [
dest: RefTextNode, char: Char, destLoc: Card ← MaxLen-1,
inherit: BOOLEAN ← TRUE, looks: Looks ← noLooks] = INLINE {
InsertChar[dest, char, destLoc+1, inherit, looks] };
InsertString: PROC [
dest: RefTextNode, string: REF READONLY TEXT, destLoc: Card ← 0,
stringStart: NAT ← 0, stringNum: NAT ← LAST[NAT],
inherit: BOOLEAN ← TRUE, looks: Looks ← noLooks];
-- if destLoc >= size[dest], put string at end of dest
-- insert stringNum chars from string starting at stringStart
-- looks specified same as for InsertChar
-- add length of insert to names that are beyond destLoc
AppendString: PROC [
dest: RefTextNode, string: REF READONLY TEXT, destLoc: Card ← MaxLen-1,
stringStart: NAT ← 0, stringNum: NAT ← LAST[NAT],
inherit: BOOLEAN ← TRUE, looks: Looks ← noLooks] = INLINE {
InsertString[dest, string, destLoc+1, stringStart, stringNum,
inherit, looks] };
InsertRope: PROC [
dest: RefTextNode, rope: Rope, destLoc: Card ← 0,
inherit: BOOLEAN ← TRUE, looks: Looks ← noLooks];
-- insert rope at specified location
-- if destLoc >= size[dest], put rope at end of dest
-- looks specified same as for InsertChar
-- add length of insert to names that are beyond destLoc
AppendRope: PROC [
dest: RefTextNode, rope: Rope, destLoc: Card ← MaxLen-1,
inherit: BOOLEAN ← TRUE, looks: Looks ← noLooks] = INLINE {
InsertRope[dest, rope, destLoc+1, inherit, looks] };
FetchChar: PROC [text: RefTextNode, index: Card] RETURNS [Char];
-- fetches the indexed information
-- use readers if want info from contiquous locations
Fetch: PROC [text: RefTextNode, index: Card] RETURNS [Char, Looks];
-- fetches the indexed information
-- use readers if want info from contiquous locations
-- **** Editing Operations related to node structure ****
MoveNodes: PROC [
destParent: Ref, destLoc: Card,
sourceParent: Ref, sourceStart, sourceLen: Card];
-- delete sourceLen children from sourceParent starting at sourceStart
-- insert them in destParent at destLoc
-- e.g., destLoc=0 to move to start of dest
-- and destLoc=NumChildren[dest] to move to end
ReplaceNodes: PROC [
destParent: Ref, destStart, destLen: Card,
sourceParent: Ref, sourceStart, sourceLen: Card];
-- replace destLen children in destParent starting at destStart
-- by sourceLen children from sourceParent starting at sourceStart
-- this covers copying and deleting nodes also
TransposeNodes: PROC [
alphaParent: Ref, alphaStart, alphaLen: Card,
betaParent: Ref, betaStart, betaLen: Card];
-- exchange alphaLen children of alphaParent starting with alphaStart
-- with betaLen children of betaParent starting with betaStart
InsertNode: PROC [
destParent: Ref, destLoc: Card];
-- insert a new node as destLoc'th child of destParent
SplitNode: PROC [
node: RefTextNode, loc: Card];
-- split the text node at specified character position
-- text before the split will remain in the node
-- other text goes in new node that will be inserted as next sibling
MergeNodes: PROC [
firstNode: RefTextNode, numberMerged: Card];
-- merge numberMerged text nodes starting at firstNode
END.