CasabaFormattingImpl.Mesa
Copyright Ó 1988 by Xerox Corporation. All rights reserved.
Shamelessly stolen from Tioga's TEditMesaOpsImpl
James Rauen, July 8, 1988 3:55:38 pm PDT
Last edited by: James Rauen July 10, 1988 11:11:00 am PDT
DIRECTORY
EditSpan USING [AddLooks, ChangeLooks, noLooks, RemoveLooks],
EditSpanSupport USING [Apply],
IO USING [GetCedarToken, GetIndex, RIS, SetIndex, STREAM, TokenKind],
NodeAddrs USING [GetTextAddr, PutTextAddr, RemTextAddr],
RefText USING [New],
Rope USING [Equal, FromRefText, ROPE, Size, Substr],
RopeReader USING [Create, Ref],
RuntimeError USING [BoundsFault],
TEditDocument USING [Selection],
TEditInput USING [CommandProc, currentEvent, Register],
TEditInputOps USING [CallWithLocks],
TEditLocks USING [Lock, Unlock],
TEditMesaOps USING [],
TEditSelection USING [MakeSelection, pSel, SetSelLooks],
TextEdit USING [Size],
TextLooks USING [Looks, noLooks],
TextNode USING [EndPos, Location, NodeItself, Offset, Ref, RefTextNode, Root, Span],
UndoEvent USING [Ref];
CasabaFormattingImpl: CEDAR PROGRAM
IMPORTS EditSpan, EditSpanSupport, IO, NodeAddrs, RefText, Rope, RopeReader, RuntimeError, TEditInput, TEditInputOps, TEditLocks, TEditSelection, TextEdit, TextNode
= BEGIN
ROPE: TYPE = Rope.ROPE;
STREAM: TYPE = IO.STREAM;
Keywords: LIST OF ROPE = LIST["AbstractProduction", "AbstractType", "BaseFunction", "BaseType", "Begin", "Build", "Builds", "CedarEnumType", "CedarFunction", "CedarType", "Control", "DamagedReps", "else", "End", "EnumeratedBaseType", "for", "From", "GenericToken", "if", "in", "Include", "let", "Module", "NonTerminal", "Returns", "SharedReps", "SimpleTokens", "SourceLength", "SourcePosition", "then", "TreeRecursiveFunction", "where"];
Keyword: PROC [r: ROPE] RETURNS[BOOLEAN] = BEGIN
Return TRUE if r is a Casaba keyword.
k: LIST OF ROPE ← Keywords;
WHILE k # NIL DO
IF Rope.Equal[k.first, r] THEN RETURN[TRUE];
k ← k.rest;
ENDLOOP;
RETURN[FALSE];
END;
SetSpanCasabaLooks: PROC [span: TextNode.Span, event: UndoEvent.Ref] = {
root: TextNode.Ref = TextNode.Root[span.start.node];
rdr: RopeReader.Ref ← RopeReader.Create[];
SetMesaLooks: PROC [node: TextNode.RefTextNode, start, len: TextNode.Offset]
RETURNS [stop: BOOL] = {
p, c, k: INT ← 0;
IF node.comment AND start = 0 AND len = TextEdit.Size[node]
THEN { -- skip the entire comment node -- stop ← FALSE }
ELSE stop ← DoIt[node, start, len, rdr, event];
};
[] ← TEditLocks.Lock[root, "SetSpanMesaLooks"];
EditSpanSupport.Apply[span, SetMesaLooks];
TEditLocks.Unlock[root];
};
namifyTypes: BOOLFALSE;
DoIt: PROC [node: TextNode.RefTextNode, start, len: TextNode.Offset, rdr: RopeReader.Ref, event: UndoEvent.Ref] RETURNS [stop: BOOLFALSE] = {
root: TextNode.Ref = TextNode.Root[node];
pStart, pLen: TextNode.Offset ← 0;
lastChar: CHAR ← '\000;
token: REF TEXT ← RefText.New[40];
tokenKind: IO.TokenKind ← tokenERROR;
allComments: BOOLTRUE;
nameLooks: TextLooks.Looks ← TextLooks.noLooks;
casabaLooks: TextLooks.Looks ← TextLooks.noLooks;
stream: STREAMNIL;
size: INT ~ Rope.Size[node.rope];
first: INT ~ MIN[start, size];
length: INT ~ MIN[len, size-start];
end: INT ~ start+length;
state: {null, name, nameColon} ← null;
stream ← IO.RIS[node.rope.Substr[0, end]];
IO.SetIndex[stream, first];
casabaLooks['i] ← casabaLooks['z] ← casabaLooks['n] ← TRUE;
nameLooks['n] ← TRUE;
IF end > first THEN EditSpan.RemoveLooks[root, [[node, first], [node, end-1]], casabaLooks, event];
UNTIL tokenKind = tokenEOF DO
add, alpha, keyword: BOOLFALSE;
addLooks, remLooks: TextLooks.Looks ← TextLooks.noLooks;
tokStart, tokLen: INT ← 0;
[tokenKind, token] ← IO.GetCedarToken[stream, token, FALSE !
RuntimeError.BoundsFault => { tokenKind ← tokenERROR; token.length ← 0; CONTINUE }
];
tokLen ← token.length;
tokStart ← IO.GetIndex[stream]-tokLen;
remLooks ← casabaLooks;
SELECT tokenKind FROM
tokenID => {
IF Keyword[Rope.FromRefText[token]]
THEN {
add ← TRUE;
addLooks['i] ← TRUE;
remLooks['i] ← FALSE;
addLooks['z] ← TRUE;
remLooks['z] ← FALSE;
state ← null;
}
ELSE {
IF state = name
THEN {
pLen ← pLen + tokLen;
}
ELSE {
pStart ← tokStart;
pLen ← tokLen;
};
state ← name;
};
};
tokenSINGLE => {
IF (state = name AND token[0] = ':)
THEN state ← nameColon
ELSE {
IF state = name THEN pLen ← pLen + 1;
};
};
ENDCASE => state ← null;
IF add THEN {
EditSpan.ChangeLooks[root, [[node,tokStart], [node,tokStart+tokLen-1]], remLooks, addLooks, event];
add ← FALSE;
addLooks ← TextLooks.noLooks;
remLooks ← casabaLooks;
};
IF state = nameColon THEN {
state ← null;
IF pLen > 0 THEN {
EditSpan.AddLooks[root, [[node, pStart], [node, pStart+pLen-1]], nameLooks, event]
};
pLen ← 0;
};
ENDLOOP;
};
SetCasabaLooksOp: TEditInput.CommandProc = {
DoSet: PROC [root: TextNode.Ref, tSel: TEditDocument.Selection] = {
span: TextNode.Span ← [tSel.start.pos, tSel.end.pos];
firstText: TextNode.RefTextNode ~ tSel.start.pos.node;
lastText: TextNode.RefTextNode ~ tSel.end.pos.node;
IF firstText # NIL THEN NodeAddrs.PutTextAddr[firstText, $Start, tSel.start.pos.where];
IF lastText # NIL THEN NodeAddrs.PutTextAddr[lastText, $End, tSel.end.pos.where+1];
IF tSel.granularity=point OR (tSel.granularity=char AND tSel.start.pos=tSel.end.pos) THEN {
do the entire node
span.start.where ← 0;
span.end.where ← TextNode.EndPos[span.end.node] };
SetSpanCasabaLooks[span, TEditInput.currentEvent];
tSel.start.pos ← [firstText,
IF firstText=NIL THEN TextNode.NodeItself
ELSE NodeAddrs.GetTextAddr[firstText,$Start].location];
tSel.end.pos ← [lastText,
IF lastText=NIL
THEN TextNode.NodeItself
ELSE MAX[NodeAddrs.GetTextAddr[lastText, $End].location, 1] - 1
];
IF firstText#NIL THEN NodeAddrs.RemTextAddr[firstText, $Start];
IF lastText#NIL THEN NodeAddrs.RemTextAddr[lastText, $End];
TEditSelection.MakeSelection[new: tSel];
TEditSelection.SetSelLooks[TEditSelection.pSel];
};
TEditInputOps.CallWithLocks[DoSet];
quit ← TRUE;
};
TEditInput.Register[$SetCasabaLooks, SetCasabaLooksOp, TRUE];
END.