TEditMesaOpsImpl.mesa
Paxton on November 10, 1982 7:33 am
Maxwell, January 14, 1983 9:41 am
Russ Atkinson, September 27, 1983 6:42 pm
TEditMesaOpsImpl:
CEDAR PROGRAM
IMPORTS
EditSpan, EditSpanSupport, IO, MessageWindow, NodeAddrs, NodeProps, RefText, Rope, RopeEdit, RopeReader, TEditInput, TEditInputOps, TEditLocks, TEditSelection, TextEdit, TextLooks, TextNode
EXPORTS TEditMesaOps
= BEGIN
SetSpanMesaLooks:
PUBLIC
PROC [span: TextNode.Span, event: UndoEvent.Ref]
RETURNS [procs, comments, keywords:
INT] = {
root: TextNode.Ref = TextNode.Root[span.start.node];
rdr: RopeReader.Ref ← RopeReader.Create[];
skipComments: BOOL = span.start.node # span.end.node;
SetMesaLooks:
PROC [node: TextNode.RefTextNode, start, len: TextNode.Offset]
RETURNS [stop: BOOL] = {
p, c, k: INT;
IF node.comment
AND skipComments
THEN { p ← c ← k ← 0; stop ← FALSE }
ELSE [stop,p,c,k] ← DoIt[node, start, len, rdr, event];
procs ← procs+p; comments ← comments+c; keywords ← keywords+k };
procs ← comments ← keywords ← 0;
[] ← TEditLocks.Lock[root, "SetSpanMesaLooks"];
EditSpanSupport.Apply[span,SetMesaLooks];
TEditLocks.Unlock[root];
};
DoIt:
PROC
[node: TextNode.RefTextNode, start, len: TextNode.Offset, rdr: RopeReader.Ref, event: UndoEvent.Ref]
RETURNS [stop: BOOL ← FALSE, procs, comments, keywords: INT ← 0] = {
root: TextNode.Ref = TextNode.Root[node];
pStart, pLen, size, i, first, end: TextNode.Offset ← 0;
lastChar: CHAR;
CheckID:
PROC []
RETURNS [alpha, allcaps: BOOL ← TRUE] = INLINE {
IF token = NIL THEN RETURN [FALSE, FALSE];
FOR index:
NAT
IN [0..token.length)
DO
lastChar ← token[index];
IF lastChar > 'Z OR lastChar < 'A THEN allcaps ← FALSE;
IF NOT RopeEdit.AlphaNumericChar[lastChar] THEN alpha ← FALSE;
ENDLOOP;
};
IsProc:
PROC []
RETURNS [
BOOL] = {
IF token #
NIL
THEN
SELECT token.length
FROM
4,9 => {
quick kill on the length saves bogus procedure calls
RETURN [
Rope.Equal[RefText.TrustTextAsRope[token], "PROC"]
OR Rope.Equal[RefText.TrustTextAsRope[token], "PROCEDURE"]];
};
ENDCASE;
RETURN [FALSE];
};
allComments: BOOL ← TRUE;
lastLoc: TextNode.Location;
nameLooks: TextLooks.Looks ← TextLooks.noLooks;
mesaLooks: TextLooks.Looks ← TextLooks.noLooks;
token: REF TEXT ← RefText.New[40];
tokenKind: IO.TokenKind;
stream: STREAM ← NIL;
size ← RopeEdit.Size[node.rope];
start ← MIN[start, size];
len ← MIN[len, size-start];
end ← start+len;
i ← first ← start;
stream ← IO.RIS[node.rope.Substr[0, end]];
lastLoc ← [node,start];
mesaLooks['k] ← mesaLooks['c] ← mesaLooks['n] ← TRUE;
nameLooks['n] ← TRUE;
DO
add, alpha, allcaps, proc: BOOL ← FALSE;
addLooks, remLooks: TextLooks.Looks ← TextLooks.noLooks;
[tokenKind, token] ← IO.GetCedarToken[stream, token, FALSE];
i ← IO.GetIndex[stream];
len ← token.length;
start ← i-len;
remLooks ← mesaLooks;
SELECT tokenKind
FROM
tokenEOF =>
We have reached the end of this node. So just exit.
EXIT;
tokenCOMMENT => {
IF ~TextLooks.FetchLooks[node.runs, start]['c]
THEN {add ← TRUE; addLooks['c] ← TRUE; remLooks['c] ← FALSE }
ELSE lastLoc.where ← start+len; -- don't change comment looks
comments ← comments+1;
};
tokenID => {
allComments ← FALSE;
[alpha, allcaps] ← CheckID[];
SELECT
TRUE
FROM
allcaps => {
proc ← token[0] = 'P AND IsProc[];
add ← TRUE;
addLooks['k] ← TRUE;
remLooks['k] ← FALSE;
keywords ← keywords+1;
};
alpha => {
save positions & text since may be a proc name
pStart ← start;
pLen ← len;
};
ENDCASE;
};
ENDCASE => allComments ← FALSE;
IF add
THEN {
IF lastLoc.where < start
THEN
EditSpan.RemoveLooks[root,[lastLoc,[node,start-1]],mesaLooks,event];
lastLoc.where ← start+len;
EditSpan.ChangeLooks[root,[[node,start],[node,start+len-1]],remLooks,addLooks,event];
add ← FALSE;
addLooks ← TextLooks.noLooks;
remLooks ← mesaLooks };
IF proc
THEN {
ReallyIsProc:
PROC
RETURNS [
BOOL] = {
rope: Rope.ROPE = node.rope;
-- must start with a cap alpha
IF ~Rope.Fetch[rope,pStart] IN ['A..'Z] THEN RETURN[FALSE];
-- must be followed immediately by a colon
IF pStart+pLen >= Rope.Size[rope] THEN RETURN[FALSE];
IF Rope.Fetch[rope,pStart+pLen] # ': THEN RETURN[FALSE];
RETURN [TRUE] };
proc ← FALSE;
IF pLen > 0
AND ReallyIsProc[]
THEN {
procs ← procs+1;
EditSpan.AddLooks[root,[[node,pStart],[node,pStart+pLen-1]],nameLooks,event] };
pLen ← 0 };
ENDLOOP;
IF lastLoc.where < end
THEN
EditSpan.RemoveLooks[root,[lastLoc,[node,end-1]],mesaLooks,event];
IF first=0
AND end = size
THEN {
doing entire node; check Comment property
isComment: BOOL ← allComments AND comments > 0;
IF isComment
AND
NOT node.comment
THEN {
-- change it
NextCharIsBlank:
PROC
RETURNS [blank:
BOOL] = {
blank ← RopeEdit.BlankChar[RopeReader.Peek[rdr !
RopeReader.ReadOffEnd => { blank ← FALSE; CONTINUE }]] };
commentLooks: TextLooks.Looks ← TextLooks.noLooks;
commentLooks['c] ← TRUE;
RopeReader.SetPosition[rdr,node.rope,0];
WHILE RopeEdit.BlankChar[RopeReader.Get[rdr]] DO --skip blanks-- ENDLOOP;
IF RopeReader.PeekBackwards[rdr] # '- THEN ERROR;
IF RopeReader.Get[rdr] # '- THEN ERROR;
WHILE NextCharIsBlank[]
DO
--skip blanks
[] ← RopeReader.Get[rdr]; ENDLOOP;
TextEdit.DeleteText[root, node, 0, RopeReader.GetIndex[rdr], event];
EditSpan.RemoveLooks[root,[[node,0],[node,TextNode.MaxLen]],commentLooks,event];
TextEdit.PutProp[node, "Comment", NodeProps.true, event];
}};
};
SetMesaLooksOp:
PUBLIC TEditInput.CommandProc = {
-- scan selection looking for Mesa keywords and comments
-- set the keywords look k
-- set the comments look c
-- set procedure names look n
procs, comments, keywords: INT;
DoSet:
PROC [root: TextEdit.Ref, tSel: TEditDocument.Selection] = {
span: TextNode.Span ← [tSel.start.pos, tSel.end.pos];
selStart, selEnd: TextNode.Ref;
firstText, lastText: TextNode.RefTextNode;
IF (firstText ← TextNode.NarrowToTextNode[selStart ← tSel.start.pos.node]) #
NIL
THEN
NodeAddrs.PutTextAddr[firstText,$Start,tSel.start.pos.where];
IF (lastText ← TextNode.NarrowToTextNode[selEnd ← tSel.end.pos.node]) #
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] };
[procs, comments, keywords] ← SetSpanMesaLooks[span, TEditInput.currentEvent];
tSel.start.pos ← [selStart,
IF firstText=NIL THEN TextNode.NodeItself
ELSE NodeAddrs.GetTextAddr[firstText,$Start].location];
tSel.end.pos ← [selEnd,
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];
{h:
STREAM ←
IO.
ROS[];
IO.Put[
h, [integer[keywords]],
IF keywords=1 THEN [rope[" keyword, "]] ELSE [rope[" keywords, "]]];
IO.Put[
h, [integer[comments]],
IF comments=1 THEN [rope[" comment, "]] ELSE [rope[" comments, "]]];
IO.Put[
h, [integer[procs]],
IF procs=1 THEN [rope[" procedure name."]] ELSE [rope[" procedure names."]]];
MessageWindow.Append[IO.RopeFromROS[h],TRUE]};
};