EditPropertiesImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Michael Plass, October 28, 1986 1:00:59 pm PST
DIRECTORY TEditSelection, Atom, TiogaAccess, TiogaOps, Rope, NodeProps, TEditInput, ViewerClasses, NodePropsExtras, RefText, RopeEdit, RuntimeError, TEditSelectionOps, ViewerOps, TextNode, TEditDocument;
EditPropertiesImpl: CEDAR PROGRAM
IMPORTS TEditSelection, Atom, TiogaAccess, TiogaOps, Rope, NodeProps, TEditInput, NodePropsExtras, RefText, RopeEdit, RuntimeError, TEditSelectionOps, ViewerOps, TextNode
~ BEGIN
ROPE: TYPE ~ Rope.ROPE;
TranslateToOpenProperties: PROC [reader: TiogaAccess.Reader, writer: TiogaAccess.Writer] ~ {
t: TiogaAccess.TiogaChar ← [charSet: 0, char: 0C, looks: ALL[FALSE], format: NIL, comment: FALSE, endOfNode: FALSE, deltaLevel: 0, propList: NIL];
node: TiogaAccess.TiogaChar ← [charSet: 0, char: 15C, looks: ALL[FALSE], format: $code, comment: FALSE, endOfNode: TRUE, deltaLevel: 0, propList: NIL];
nest: TiogaAccess.TiogaChar ← [charSet: 0, char: 15C, looks: ALL[FALSE], format: $code, comment: FALSE, endOfNode: TRUE, deltaLevel: 1, propList: NIL];
outc: TiogaAccess.TiogaChar ← [charSet: 0, char: 0C, looks: ALL[FALSE], format: NIL, comment: FALSE, endOfNode: FALSE, deltaLevel: 0, propList: NIL];
PutRope: PROC [rope: ROPE] ~ {
FOR i: INT IN [0..Rope.Size[rope]) DO
outc.char ← Rope.Fetch[rope, i];
TiogaAccess.Put[writer, outc];
ENDLOOP;
};
PutOctal: PROC [b: [0..256)] ~ {
outc.char ← '0+b/64;
TiogaAccess.Put[writer, outc];
outc.char ← '0+(b/8) MOD 8;
TiogaAccess.Put[writer, outc];
outc.char ← '0+b MOD 8;
TiogaAccess.Put[writer, outc];
};
PutPropName: PROC [atom: ATOM] ~ {
save: TiogaAccess.Looks ← outc.looks;
outc.looks['n] ← TRUE;
PutRope[Atom.GetPName[atom]];
outc.looks ← save;
PutRope[": "];
};
PutKey: PROC [rope: ROPE] ~ {
save: TiogaAccess.Looks ← outc.looks;
outc.looks['k] ← TRUE;
outc.looks['b] ← TRUE;
PutRope[rope];
outc.looks ← save;
};
PutProperties: PROC [propList: Atom.PropList] ~ {
FOR each: Atom.PropList ← propList, each.rest UNTIL each = NIL DO
key: ATOM ~ NARROW[each.first.key];
PutProperty[key, each.first.val];
ENDLOOP;
};
PutProperty: PROC [key: ATOM, value: REF] ~ {
IF value # NIL THEN {
rope: ROPE ~ TiogaAccess.GetExternalProp[key, value];
PutPropName[key];
IF rope = NIL OR NodePropsExtras.Is[key, $ClientOnly]
THEN {
save: TiogaAccess.Looks ← outc.looks;
outc.looks['c] ← TRUE;
PutRope["(opaque)"];
outc.looks ← save;
node.propList ← CONS[NEW[Atom.DottedPairNode ← [key: $OpaqueValue, val: value]], node.propList];
TiogaAccess.Put[writer, node];
node.propList ← node.propList.rest;
}
ELSE {
PutRope[rope];
TiogaAccess.Put[writer, node];
};
};
};
TranslateNodeContents: PROC ~ {
UNTIL t.endOfNode DO
looks: TiogaAccess.Looks ~ t.looks;
propList: Atom.PropList ~ t.propList;
IF t.charSet = 0 AND t.char IN [' ..'~]
THEN {
Emit a run of printable ascii characters, all with the same looks and properties
PutPropName[$Text];
WHILE NOT t.endOfNode AND t.charSet = 0 AND t.char IN [' ..'~] AND t.looks=looks AND t.propList = propList DO
save: TiogaAccess.Looks ← outc.looks;
outc.char ← t.char;
outc.looks['o] ← TRUE;
TiogaAccess.Put[writer, outc];
outc.looks ← save;
t ← TiogaAccess.Get[reader];
ENDLOOP;
}
ELSE {
Emit a single XC character
PutPropName[$Char];
PutRope["("];
PutOctal[t.charSet];
PutRope["|"];
PutOctal[ORD[t.char]];
PutRope[")"];
t ← TiogaAccess.Get[reader];
};
TiogaAccess.Put[writer, node];
IF looks # ALL[FALSE] THEN {
Emit the looks that apply to the previous text or character
TiogaAccess.Nest[writer, 1];
PutKey["LOOKS"];
PutRope["("];
FOR c: CHAR IN TiogaAccess.Look DO
IF looks[c] THEN {outc.char ← c; TiogaAccess.Put[writer, outc]};
ENDLOOP;
PutRope[")"];
TiogaAccess.Put[writer, node];
TiogaAccess.Nest[writer, -1];
};
IF propList # NIL THEN {
Emit the properties that apply to the previous text or character
TiogaAccess.Nest[writer, 1];
PutProperties[propList];
TiogaAccess.Nest[writer, -1];
};
ENDLOOP;
};
UNTIL TiogaAccess.EndOf[reader] DO
t ← TiogaAccess.Get[reader];
PutKey["BEGIN NODE"]; TiogaAccess.Put[writer, nest];
IF NOT t.endOfNode THEN {
PutKey["CONTENTS"]; TiogaAccess.Put[writer, nest];
TranslateNodeContents[];
TiogaAccess.Nest[writer, -1];
};
PutKey["PROPERTIES"]; TiogaAccess.Put[writer, nest];
PutProperty[$Comment, IF t.comment THEN NodeProps.true ELSE NodeProps.false];
PutProperty[$Format, t.format];
PutProperties[t.propList];
TiogaAccess.Nest[writer, -1];
PutKey["END NODE"];
TiogaAccess.Put[writer, node];
TiogaAccess.Nest[writer, t.deltaLevel-1];
ENDLOOP;
};
Cant: ERROR ~ CODE;
TranslateFromOpenProperties: PROC [reader: TiogaAccess.Reader, writer: TiogaAccess.Writer] ~ {
Must: PROC [assertion: BOOL] ~ {IF NOT assertion THEN Cant[]};
break: TiogaAccess.TiogaChar ← [charSet: 0, char: 0C, looks: ALL[FALSE], format: NIL, comment: FALSE, endOfNode: FALSE, deltaLevel: 0, propList: NIL];
Match: PROC [rope: ROPE] RETURNS [BOOL] ~ {
targetLen: INT ~ Rope.Size[rope];
input: ROPE ~ TiogaAccess.PeekRope[reader];
matchLen: INT ~ Rope.Run[s1: rope, s2: input, case: TRUE];
IF matchLen=targetLen THEN {
FOR i: INT IN [0..targetLen) DO [] ← TiogaAccess.Get[reader] ENDLOOP;
RETURN [TRUE];
};
RETURN [FALSE];
};
level: INT ← 0;
MatchBreak: PROC RETURNS [BOOL] ~ {
IF TiogaAccess.Peek[reader].endOfNode THEN {
break ← TiogaAccess.Get[reader];
level ← level + break.deltaLevel;
RETURN [TRUE];
};
RETURN [FALSE];
};
MustNest: PROC ~ {Must[MatchBreak[] AND break.deltaLevel = 1]};
GetOctal3: PROC RETURNS [[0..256)] ~ {
v: CARDINAL ← 0;
FOR i: NAT IN [0..3) DO
t: TiogaAccess.TiogaChar ← TiogaAccess.Get[reader];
Must[t.char IN ['0..'8) AND t.charSet = 0];
v ← v*8 + (t.char-'0);
ENDLOOP;
Must[v IN [0..256)];
RETURN [v];
};
RopeToEnd: PROC RETURNS [ROPE] ~ {
rope: ROPE ← TiogaAccess.PeekRope[reader];
FOR i: INT IN [0..Rope.Size[rope]) DO [] ← TiogaAccess.Get[reader] ENDLOOP;
RETURN [rope];
};
ParseProp: PROC RETURNS [Atom.DottedPairNode] ~ {
keyText: REF TEXT ~ RefText.ObtainScratch[100];
t: TiogaAccess.TiogaChar ← TiogaAccess.Get[reader];
key: ATOMNIL;
rope: ROPENIL;
value: REF;
WHILE t.charSet = 0 AND RopeEdit.AlphaNumericChar[t.char] DO
Must[keyText.length < keyText.maxLength];
keyText[keyText.length] ← t.char;
keyText.length ← keyText.length + 1;
t ← TiogaAccess.Get[reader];
ENDLOOP;
Must[keyText.length > 0];
Must[t.charSet = 0 AND t.char = ':];
Must[Match[" "]];
rope ← RopeToEnd[];
Must[MatchBreak[]];
key ← Atom.MakeAtomFromRefText[keyText];
value ← Atom.GetPropFromList[break.propList, $OpaqueValue];
IF value = NIL THEN value ← TiogaAccess.GetInternalProp[key, rope];
RefText.ReleaseScratch[keyText];
RETURN [[key: key, val: value]];
};
UNTIL TiogaAccess.EndOf[reader] DO
IF Match["BEGIN NODE"]
THEN {
node: TiogaAccess.TiogaChar ← [charSet: 0, char: 15C, looks: ALL[FALSE], format: NIL, comment: FALSE, endOfNode: TRUE, deltaLevel: 0, propList: NIL];
level ← 0;
MustNest[];
IF Match["CONTENTS"] THEN {
MustNest[];
WHILE level >= 2 DO
outc: TiogaAccess.TiogaChar ← [charSet: 0, char: 0C, looks: ALL[FALSE], format: NIL, comment: FALSE, endOfNode: FALSE, deltaLevel: 0, propList: NIL];
rope: ROPENIL;
Must[level = 2];
IF Match["Text: "]
THEN rope ← RopeToEnd[]
ELSE {
Must[Match["Char: ("]];
outc.charSet ← GetOctal3[];
Must[Match["|"]];
rope ← Rope.FromChar[VAL[GetOctal3[]]];
Must[Match[")"]];
};
Must[MatchBreak[]];
WHILE level >= 3 DO
Must[level = 3];
IF Match["LOOKS("] THEN {
t: TiogaAccess.TiogaChar ← TiogaAccess.Peek[reader];
WHILE t.charSet = 0 AND t.char IN TiogaAccess.Look DO
t ← TiogaAccess.Get[reader];
outc.looks[t.char] ← TRUE;
t ← TiogaAccess.Peek[reader];
ENDLOOP;
Must[Match[")"]];
Must[MatchBreak[]];
}
ELSE {
pair: Atom.DottedPairNode ~ ParseProp[];
outc.propList ← CONS[NEW[Atom.DottedPairNode ← pair], outc.propList];
};
ENDLOOP;
IF rope # NIL THEN {
action: Rope.ActionType = { outc.char ← c; TiogaAccess.Put[writer, outc] };
[] ← Rope.Map[base: rope, action: action];
};
ENDLOOP;
};
IF Match["PROPERTIES"] THEN {
MustNest[];
WHILE level >= 2 DO
pair: Atom.DottedPairNode;
Must[level = 2];
pair ← ParseProp[];
SELECT pair.key FROM
$Comment => WITH pair.val SELECT FROM b: REF BOOL => node.comment ← b^ ENDCASE;
$Format => WITH pair.val SELECT FROM a: ATOM => node.format ← a ENDCASE;
ENDCASE => node.propList ← CONS[NEW[Atom.DottedPairNode ← pair], node.propList];
ENDLOOP;
};
Must[level = 1];
Must[Match["END NODE"]];
Must[MatchBreak[]];
node.deltaLevel ← level;
TiogaAccess.Put[writer, node];
}
ELSE {
Must[TiogaAccess.CopyNode[writer, reader].nodeEnd];
};
ENDLOOP;
};
MakeNodeSelection: PROC ~ {
tSel: TEditDocument.Selection;
IF TEditSelection.pSel=NIL OR TEditSelection.pSel.viewer=NIL THEN RETURN;
tSel ← TEditSelection.Alloc[];
TEditSelection.Copy[source: TEditSelection.pSel, dest: tSel];
SELECT tSel.granularity FROM
point, char, word => {
tSel.start.pos.where ← 0;
tSel.end.pos.where ← TextNode.EndPos[tSel.end.pos.node];
tSel.granularity ← node;
};
ENDCASE => NULL;
TEditSelection.MakeSelection[new: tSel];
TEditSelection.Free[tSel]
};
OpenPropertiesOp: TEditInput.CommandProc ~ {
OpenProperties: PROC [root: TiogaOps.Ref] ~ {
reader: TiogaAccess.Reader ← NIL;
writer: TiogaAccess.Writer ← NIL;
MakeNodeSelection[];
reader ← TiogaAccess.FromSelection[];
writer ← TiogaAccess.Create[];
TranslateToOpenProperties[reader, writer];
TiogaAccess.WriteSelection[writer];
};
TiogaOps.CallWithLocks[OpenProperties];
quit ← TRUE;
};
ClosePropertiesOp: TEditInput.CommandProc ~ {
PROC [viewer: ViewerClasses.Viewer ← NIL] RETURNS [recordAtom: BOOLTRUE, quit: BOOLFALSE];
error: {none, cant, uncaught} ← none;
errorPosition: INT ← 0;
CloseProperties: PROC [root: TiogaOps.Ref] ~ {
reader: TiogaAccess.Reader ← NIL;
writer: TiogaAccess.Writer ← NIL;
MakeNodeSelection[];
reader ← TiogaAccess.FromSelection[];
writer ← TiogaAccess.Create[];
TranslateFromOpenProperties[reader, writer !
Cant => {errorPosition ← TiogaAccess.GetPosition[reader]}
];
TiogaAccess.WriteSelection[writer];
};
TiogaOps.CallWithLocks[CloseProperties !
Cant => {error ← cant; CONTINUE};
RuntimeError.UNCAUGHT => {error ← uncaught; CONTINUE};
];
SELECT error FROM
none => NULL;
cant => {
TEditSelectionOps.ShowGivenPosition[viewer: viewer, pos: errorPosition, skipCommentNodes: TRUE];
ViewerOps.BlinkViewer[viewer, 200];
};
uncaught => CloseProperties[NIL]; -- do without lock for easy debug
ENDCASE => ERROR;
quit ← TRUE;
};
TEditInput.Register[name: $OpenProperties, proc: OpenPropertiesOp, before: TRUE];
TEditInput.Register[name: $CloseProperties, proc: ClosePropertiesOp, before: TRUE];
END.