-- TEditMesaOpsImpl.mesa Edited by Paxton on November 10, 1982 7:33 am
Last Edited by: Maxwell, January 14, 1983 9:41 am
DIRECTORY
EditSpan,
EditSpanSupport,
IO,
CedarScanner,
MessageWindow,
NodeAddrs,
NodeProps,
Rope,
RopeEdit,
RopeReader,
TEditDocument,
TEditInput,
TEditInputOps,
TEditLocks,
TEditMesaOps,
TEditSelection,
TextEdit,
TextLooks,
TextNode,
UndoEvent;
TEditMesaOpsImpl: CEDAR PROGRAM
IMPORTS EditSpan, EditSpanSupport, IO, CedarScanner, MessageWindow, NodeAddrs, NodeProps, 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: BOOLEAN] = {
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: BOOLEAN, procs, comments, keywords: INT] = {
root: TextNode.Ref = TextNode.Root[node];
pStart, pLen, size, i, first, end: TextNode.Offset ← 0;
lastChar: CHAR;
GetChar: PROC [data: REF, index: TextNode.Offset] RETURNS [char: CHAR] = {
OPEN RopeReader;
IF index >= end THEN { done ← TRUE; RETURN [0C] };
SetIndex[rdr,index];
char ← Get[rdr ! ReadOffEnd => { done ← TRUE; char ← 0C; CONTINUE }] };
CheckID: PROC [n: TextNode.RefTextNode, start, len: TextNode.Offset]
RETURNS [alpha, allcaps: BOOLEAN] = INLINE {
alpha ← allcaps ← TRUE;
RopeReader.SetPosition[rdr,n.rope,start];
UNTIL (len ← len-1)<0 DO
IF (lastChar ← RopeReader.Get[rdr]) NOT IN ['A..'Z] THEN allcaps ← FALSE;
IF ~RopeEdit.AlphaNumericChar[lastChar] THEN { alpha ← FALSE; EXIT };
ENDLOOP };
IsProc: PROC [n: TextNode.RefTextNode, start, len: TextNode.Offset] RETURNS [BOOLEAN] = INLINE {
IF ~(SELECT len FROM
4 => lastChar = 'C,
9 => lastChar = 'E,
ENDCASE => FALSE) THEN RETURN [FALSE]; -- quick test eliminates most
RopeReader.SetPosition[rdr,n.rope,start];
IF RopeReader.Get[rdr] # 'P THEN RETURN [FALSE];
IF RopeReader.Get[rdr] # 'R THEN RETURN [FALSE];
IF RopeReader.Get[rdr] # 'O THEN RETURN [FALSE];
IF RopeReader.Get[rdr] # 'C THEN RETURN [FALSE];
IF len = 4 THEN RETURN [TRUE];
IF len # 9 THEN RETURN [FALSE];
IF RopeReader.Get[rdr] # 'E THEN RETURN [FALSE];
IF RopeReader.Get[rdr] # 'D THEN RETURN [FALSE];
IF RopeReader.Get[rdr] # 'U THEN RETURN [FALSE];
IF RopeReader.Get[rdr] # 'R THEN RETURN [FALSE];
IF RopeReader.Get[rdr] # 'E THEN RETURN [FALSE];
RETURN [TRUE] };
done: BOOLEANFALSE;
allComments: BOOLEANTRUE;
lastLoc: TextNode.Location;
nameLooks: TextLooks.Looks ← TextLooks.noLooks;
mesaLooks: TextLooks.Looks ← TextLooks.noLooks;
size ← RopeEdit.Size[node.rope];
start ← MIN[start, size];
len ← MIN[len, size-start];
end ← start+len;
i ← first ← start;
stop ← FALSE;
procs ← comments ← keywords ← 0;
RopeReader.SetPosition[rdr,node.rope,start];
lastLoc ← [node,start];
mesaLooks['k] ← mesaLooks['c] ← mesaLooks['n] ← TRUE;
nameLooks['n] ← TRUE;
UNTIL done DO
add, alpha, allcaps, proc: BOOLEANFALSE;
addLooks, remLooks: TextLooks.Looks ← TextLooks.noLooks;
token: CedarScanner.Token;
TRUSTED {token ← CedarScanner.GetToken[[GetChar, rdr],i]};
i ← token.next;
start ← token.start;
len ← i-start;
remLooks ← mesaLooks;
SELECT token.kind FROM
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[node,start,len];
IF allcaps THEN {
proc ← IsProc[node,start,len];
add ← TRUE; addLooks['k] ← TRUE; remLooks['k] ← FALSE;
keywords ← keywords+1 }
ELSE IF alpha THEN { -- save since may be a proc name
pStart ← start; pLen ← len }};
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 done 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];
{ OPEN IO;
h: Handle ← CreateOutputStreamToRope[];
Put[h, int[keywords], IF keywords=1 THEN rope[" keyword, "] ELSE rope[" keywords, "]];
Put[h, int[comments], IF comments=1 THEN rope[" comment, "] ELSE rope[" comments, "]];
Put[h, int[procs], IF procs=1 THEN rope[" procedure name."] ELSE rope[" procedure names."]];
MessageWindow.Append[GetOutputStreamRope[h],TRUE] }}; 
TEditInput.Register[$SetMesaLooks, SetMesaLooksOp];
END...