TextEdit.mesa
Copyright © 1985, 1986 by Xerox Corporation. All rights reserved.
written by Bill Paxton, February 1981
last edit by Bill Paxton, April 23, 1982 6:14 am
last edit by Russ Atkinson, July 22, 1983 9:51 am
Michael Plass, April 1, 1985 4:05:55 pm PST
Doug Wyatt, September 9, 1986 12:54:15 pm PDT
=
BEGIN
ROPE: TYPE = Rope.ROPE;
Runs: TYPE = TextLooks.Runs;
Looks: TYPE = TextLooks.Looks;
noLooks: Looks = TextLooks.noLooks;
allLooks: Looks = TextLooks.allLooks;
Node: TYPE = TextNode.Node;
Location: TYPE = TextNode.Location;
Event: TYPE = UndoEvent.Event;
CharSet:
TYPE ~ [0..256);
-- for XNS 16-bit character set; use in conjunction with 8-bit
CHAR
Note: Character properties are implemented using a ROSARY (an immutable sequence of REFs; see Rosary.mesa), appearing in the CharSets property of the node. The values in this ROSARY are of type REF CharSet.
Text:
TYPE ~
RECORD [node: Node, start:
INT ← 0, len:
INT ←
INT.
LAST];
represents the characters [start..start+len) in node
end:
PROC [text: Text]
RETURNS [
INT] ~
INLINE {
RETURN[text.start+text.len] };
LocationInText:
PROC [loc: Location, text: Text]
RETURNS [
BOOL] ~
INLINE {
RETURN[loc.node=text.node AND loc.where IN[text.start..text.end)];
};
Overview
A text node contains a rope and runs of looks
Looks are represented by a vector of 32 bits
Each character in a text node has looks vector associated with it
Run encoding is used to reduce the storage needed to represent the looks
See TextLooks.mesa for more information about looks
See TextNode.mesa for the details of text node structure
Text editing
operations are provided to edit the contents of text nodes
unlike ropes or runs of looks, text nodes are mutable
i.e., the edit changes the node rather than returning a new node
the looks related commands are
AddLooks, RemoveLooks, SetLooks, ClearLooks, and ChangeLooks
the text related commands are
ReplaceText, DeleteText, CopyText, MoveText, MoveTextOnto, TransposeText
in addition there are commands taking a character/string/rope as source
ReplaceByChar, InsertChar, AppendChar
ReplaceByString, InsertString, AppendString
ReplaceByRope, InsertRope, AppendRope
several commands are available for changing capitalization
AllCaps, AllLower, InitialCaps
Persistent addresses in text of a node
You can associate an address with a character location in a text node
the address persists with the same character even if the text is edited
the address is an arbitrary REF supplied by the client program
see NodeAddrs.mesa for the persistent addressing operations
Property lists
Each node includes a property list of key-value pairs
The keys are ATOMs and the values are arbitrary REFs
Clients can register routines to read/write properties to files
and to copy property values when nodes are copied
see NodeProps.Mesa for the property list operations
Character property lists
Each character may include a property list of key-value pairs
The keys are ATOMs and the values are arbitrary REFs
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
operations to read/write nodes to files are found in PutGet.mesa
Edit notification procedures
Client's can register procedures to be called before/after edits
the client procedure is called with the node(s) changed by the edit
and a record describing the details of the edit
see EditNotify.mesa for more information
Tree editing
nodes can have children
there is a set of tree editing operations available
see EditSpan.mesa for details
General operations
FetchChar:
PROC [text: Node, index:
INT]
RETURNS [charSet: CharSet, char:
CHAR];
fetches the indexed information
use rope readers if want characters from contiguous locations
FetchLooks:
PROC [text: Node, index:
INT]
RETURNS [Looks];
returns the looks for the character at the given location
use readers if getting looks for sequence of locations
Fetch:
PROC [text: Node, index:
INT]
RETURNS [charSet: CharSet, char:
CHAR, looks: Looks];
fetches the indexed information, except for character properties
use rope & looks readers if want info from contiguous locations
GetRope:
PROC [text: Node]
RETURNS [
ROPE];
GetRuns:
PROC [text: Node]
RETURNS [Runs];
Size:
PROC [text: Node]
RETURNS [
INT];
Flatten:
PROC [text: Node]
RETURNS [
BOOL];
returns true if it decides to flatten rope & runs
this is done automatically after a certain number of edits to the node
Operations to add or delete looks
ChangeLooks:
PROC [root: Node, text: Text, remove, add: Looks, event: Event ←
NIL];
first remove then add in the given range
AddLooks:
PROC [root: Node, text: Text, add: Looks, event: Event ←
NIL];
RemoveLooks:
PROC [root: Node, text: Text, remove: Looks ← allLooks, event: Event ←
NIL];
SetLooks:
PROC [root: Node, text: Text, new: Looks, event: Event ←
NIL];
ClearLooks:
PROC [root: Node, text: Text, event: Event ←
NIL];
Character Properties
GetCharProp:
PROC [node: Node, index:
INT, name:
ATOM]
RETURNS [value:
REF];
PutCharProp:
PROC [node: Node, index:
INT, name:
ATOM, value:
REF, nChars:
INT ← 1,
event: Event ←
NIL, root: Node ←
NIL];
Places the value on the character property lists of the chars in the specified range.
Use value = NIL to remove a character property.
MapPropsAction:
TYPE ~
PROC [name:
ATOM, value:
REF]
RETURNS [quit:
BOOL ←
FALSE];
MapCharProps:
PROC [node: Node, index:
INT, action: MapPropsAction]
RETURNS [quit:
BOOL];
Used for traversing all the properites attached to a particular character.
ModifyPropsAction:
TYPE ~
PROC [value:
REF, index:
INT, nChars:
INT]
RETURNS [quit:
BOOL ←
FALSE, newValue:
REF];
ModifyCharProps:
PROC [node: Node, name:
ATOM, index:
INT ← 0, nChars:
INT ←
INT.
LAST, action: ModifyPropsAction, event: Event ←
NIL, root: Node ←
NIL]
RETURNS [quit:
BOOL];
Used for traversing and altering the values of a character property ofer a range of characters; the action procedure is called for runs of properties, but adjacent runs are not necessarily merged.
PropList:
TYPE ~ Atom.PropList;
This property list mechanism regards a PropList as an immutable value.
GetCharPropList: PROC [node: Node, index: INT] RETURNS [PropList];
PutCharPropList:
PROC [node: Node, index:
INT, propList: PropList,
nChars:
INT ← 1, event: Event ←
NIL, root: Node ←
NIL];
GetPropFromList: PROC [propList: PropList, key: ATOM] RETURNS [value: REF];
PutPropOnList: PROC [propList: PropList, key: ATOM, value: REF] RETURNS [new: PropList];
Editing Operations for text
NOTE: edit operations do not create or delete addrs,
but they can change their locations within the text
ReplaceText:
PROC [destRoot, sourceRoot: Node, dest: Text, source: Text, event: Event ←
NIL]
RETURNS [result: Text];
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 [root: Node, text: Text, event: Event ←
NIL];
delete the specified range of text
addrs that are in the deleted section move to start
CopyText:
PROC [destRoot, sourceRoot: Node, dest: Location, source: Text, event: Event ←
NIL]
RETURNS [result: Text];
copy the specified text
add length of inserted text to addrs that are beyond dest.where
MoveText:
PROC [destRoot, sourceRoot: Node, dest: Location, source: Text, event: Event ←
NIL]
RETURNS [result: Text];
move source to dest
no-op if LocationInText[dest, source]
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
MoveTextOnto:
PROC [destRoot, sourceRoot: Node, dest: Text, source: Text, event: Event ←
NIL]
RETURNS [result: Text];
move source onto dest
implemented by appropriate calls on MoveText and DeleteText
TransposeText:
PROC [alphaRoot, betaRoot: Node, alpha: Text, beta: Text, event: Event ←
NIL]
RETURNS [alphaResult: Text, betaResult: Text];
transpose alpha and beta
addrs treated same as in Move
move with the text if alpha.node = beta.node,
or move to respective starts if alpha.node # beta.node
ReplaceByChar:
PROC [root: Node, dest: Text, char:
CHAR, inherit:
BOOL ←
TRUE, looks: Looks ← noLooks, charSet: CharSet ← 0, event: Event ←
NIL]
RETURNS [result: Text];
replacement characters don't get any character properties
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 start > 0, then gets looks from previous char,
else gets looks from char following replacement
InsertChar:
PROC [root: Node, dest: Location, char:
CHAR,
inherit:
BOOL ←
TRUE, looks: Looks ← noLooks, charSet: CharSet ← 0,
event: Event ←
NIL]
RETURNS [result: Text];
AppendChar:
PROC [root: Node, dest: Node, char:
CHAR,
inherit:
BOOL ←
TRUE, looks: Looks ← noLooks, charSet: CharSet ← 0,
event: Event ←
NIL]
RETURNS [result: Text];
ReplaceByRope:
PROC [root: Node, dest: Text, rope:
ROPE,
inherit:
BOOL ←
TRUE, looks: Looks ← noLooks, charSet: CharSet ← 0,
event: Event ←
NIL]
RETURNS [result: Text];
InsertRope:
PROC [root: Node, dest: Location, rope:
ROPE,
inherit:
BOOL ←
TRUE, looks: Looks ← noLooks, charSet: CharSet ← 0,
event: Event ←
NIL]
RETURNS [result: Text];
AppendRope:
PROC [root: Node, dest: Node, rope:
ROPE,
inherit:
BOOL ←
TRUE, looks: Looks ← noLooks, charSet: CharSet ← 0,
event: Event ←
NIL]
RETURNS [result: Text];
String:
TYPE ~
RECORD [text:
REF
READONLY
TEXT, start:
NAT ← 0, len:
NAT ←
NAT.
LAST];
ReplaceByString:
PROC [root: Node, dest: Text, string: String,
inherit:
BOOL ←
TRUE, looks: Looks ← noLooks, charSet: CharSet ← 0,
event: Event ←
NIL]
RETURNS [result: Text];
InsertString:
PROC [root: Node, dest: Location, string: String,
inherit:
BOOL ←
TRUE, looks: Looks ← noLooks, charSet: CharSet ← 0,
event: Event ←
NIL]
RETURNS [result: Text];
AppendString:
PROC [root: Node, dest: Node, string: String,
inherit:
BOOL ←
TRUE, looks: Looks ← noLooks, charSet: CharSet ← 0,
event: Event ←
NIL]
RETURNS [result: Text];
Caps and Lowercase
CapChange:
TYPE = {allCaps, allLower, initCaps, firstCap};
ChangeCaps:
PROC [root: Node, dest: Text, how: CapChange ← allCaps, event: Event ←
NIL];
AllCaps:
PROC [root: Node, dest: Text, event: Event ←
NIL];
force specified span to all uppercase
AllLower:
PROC [root: Node, dest: Text, event: Event ←
NIL];
force specified span to all lowercase
InitialCaps:
PROC [root: Node, dest: Text, event: Event ←
NIL];
force first letter of words uppercase