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
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: BOOL ← FALSE;
DoIt:
PROC [node: TextNode.RefTextNode, start, len: TextNode.Offset, rdr: RopeReader.Ref, event: UndoEvent.Ref]
RETURNS [stop:
BOOL ←
FALSE] = {
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: BOOL ← TRUE;
nameLooks: TextLooks.Looks ← TextLooks.noLooks;
casabaLooks: TextLooks.Looks ← TextLooks.noLooks;
stream: STREAM ← NIL;
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: BOOL ← FALSE;
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.