DIRECTORY EditSpan, EditSpanSupport, IO, MessageWindow, NodeAddrs, NodeProps, RefText, Rope, RopeEdit, RopeReader, TEditDocument, TEditInput, TEditInputOps, TEditLocks, TEditMesaOps, TEditSelection, TextEdit, TextLooks, TextNode, UndoEvent; TEditMesaOpsImpl: CEDAR PROGRAM IMPORTS EditSpan, EditSpanSupport, IO, MessageWindow, NodeAddrs, NodeProps, RefText, Rope, RopeEdit, RopeReader, TEditInput, TEditInputOps, TEditLocks, TEditSelection, TextEdit, TextLooks, TextNode EXPORTS TEditMesaOps = BEGIN ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; 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 => { 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 => 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 => { 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; IF ~Rope.Fetch[rope,pStart] IN ['A..'Z] THEN RETURN[FALSE]; 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 { 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 = { 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 { 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]}; }; TEditInput.Register[$SetMesaLooks, SetMesaLooksOp]; END... :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 quick kill on the length saves bogus procedure calls We have reached the end of this node. So just exit. save positions & text since may be a proc name -- must start with a cap alpha -- must be followed immediately by a colon doing entire node; check Comment property -- scan selection looking for Mesa keywords and comments -- set the keywords look k -- set the comments look c -- set procedure names look n do the entire node ʘšÏc™Jš#™#J™!J™)J™—šÏk ˜ J˜ J˜Jšžœ˜J˜J˜ J˜ J˜J˜J˜ J˜ J˜J˜ J˜J˜ J˜ J˜J˜ J˜ J˜ Jšœ ˜ J˜—šœž ˜šž˜Jšœžœ ˜½—Jšžœ ˜Jšœž˜—J˜Jšžœžœžœ˜Jšžœžœžœžœ˜J˜š Ïnœžœžœ-žœžœ˜vJ˜4J˜*Jšœžœ#˜5šŸ œžœ:˜LJšžœžœ˜Jšœ žœ˜ šžœžœ ˜ Jšžœžœ˜$Jšžœ3˜7—J˜@—J˜ J˜/J˜)J˜J˜—J˜šŸœž˜ Jšœd˜dJšžœžœžœžœ ˜DJ˜)J˜7Jšœ žœ˜šŸœžœ˜Jšžœžœžœžœ˜0Jš žœ žœžœžœžœžœ˜*šžœžœžœž˜&Jšœ˜Jšžœžœžœ žœ˜7Jšžœžœ%žœ žœ˜>Jšžœ˜—Jšœ˜—šŸœžœžœžœ˜"šžœ žœž˜šžœž˜˜Jšœ4™4šžœ˜Jšœ2˜2Jšžœ:˜<—J˜—Jšžœ˜——Jšžœžœ˜Jšœ˜—Jšœ žœžœ˜J˜J˜/J˜/Jšœžœžœ˜"Jšœ žœ ˜Jšœžœžœ˜J˜J˜ Jšœžœ˜Jšœžœ˜J˜J˜Jšœ žœžœ˜*J˜Jšœ0žœ˜5Jšœžœ˜šž˜Jšœžœžœ˜(J˜8Jšœžœžœ˜Jšžœ žœžœ&˜:Jšœ(˜(Jšœ2˜2J˜—Jšœ#˜#J˜šœžœžœžœ˜šžœ˜Jšœ˜Jšžœ žœžœ˜D—šžœ˜Jšœ˜Jšžœ žœžœ˜D—šžœ˜Jšœ˜Jšžœ žœžœ˜M—Jšœžœžœ˜.—Jšœ˜J˜—J˜3J˜Jšžœ˜J˜—…—Ô%'