TEditMesaOpsImpl.mesa
Copyright © 1985, 1986 by Xerox Corporation. All rights reserved.
Paxton on November 10, 1982 7:33 am
Maxwell, January 14, 1983 9:41 am
Russ Atkinson, September 27, 1983 6:42 pm
Michael Plass, March 25, 1986 10:04:55 am PST
Doug Wyatt, September 2, 1986 4:42:09 pm PDT
DIRECTORY
Convert USING [AppendInt],
EditSpan USING [AddLooks, ChangeLooks, noLooks, RemoveLooks],
EditSpanSupport USING [Apply],
IO USING [GetCedarToken, GetIndex, RIS, SetIndex, STREAM, TokenKind],
MessageWindow USING [Append],
NodeAddrs USING [GetTextAddr, PutTextAddr, RemTextAddr],
NodeProps USING [true],
RefText USING [AppendRope, Equal, New],
Rope USING [Equal, FromRefText, ROPE, Size, Substr],
RopeEdit USING [AlphaNumericChar, BlankChar],
RopeReader USING [Create, Get, GetIndex, Peek, PeekBackwards, ReadOffEnd, Ref, SetPosition],
TEditDocument USING [Selection],
TEditInput USING [CommandProc, currentEvent, Register],
TEditInputOps USING [CallWithLocks],
TEditLocks USING [Lock, Unlock],
TEditMesaOps USING [],
TEditSelection USING [MakeSelection, pSel, SetSelLooks],
TextEdit USING [DeleteText, PutProp],
TextLooks USING [Looks, noLooks],
TextNode USING [EndPos, Location, MaxLen, Node, NodeItself, Root, Span],
UndoEvent USING [Event];
TEditMesaOpsImpl: CEDAR PROGRAM
IMPORTS Convert, EditSpan, EditSpanSupport, IO, MessageWindow, NodeAddrs, NodeProps, RefText, Rope, RopeEdit, RopeReader, TEditInput, TEditInputOps, TEditLocks, TEditSelection, TextEdit, TextNode
EXPORTS TEditMesaOps
= BEGIN
ROPE: TYPE = Rope.ROPE;
STREAM: TYPE = IO.STREAM;
SetSpanMesaLooks:
PUBLIC
PROC [span: TextNode.Span, event: UndoEvent.Event]
RETURNS [procs, comments, keywords:
INT] = {
root: TextNode.Node = TextNode.Root[span.start.node];
rdr: RopeReader.Ref ← RopeReader.Create[];
skipComments: BOOL = span.start.node # span.end.node;
SetMesaLooks:
PROC [node: TextNode.Node, start, len:
INT]
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];
};
namifyTypes:
BOOL ←
FALSE;
DoIt:
PROC [node: TextNode.Node, start, len:
INT, rdr: RopeReader.Ref, event: UndoEvent.Event]
RETURNS [stop:
BOOL ←
FALSE, procs, comments, keywords:
INT ← 0] = {
root: TextNode.Node = TextNode.Root[node];
pStart, pLen: INT ← 0;
lastChar: CHAR ← '\000;
token: REF TEXT ← RefText.New[40];
Match:
PROC [a:
REF
READONLY
TEXT]
RETURNS [
BOOL] ~
INLINE {
RETURN [a.length=token.length AND RefText.Equal[a, token]]
};
tokenKind: IO.TokenKind ← tokenERROR;
CheckID:
PROC
RETURNS [alpha, allcaps:
BOOL ←
TRUE] = {
IF token = NIL THEN RETURN [FALSE, FALSE];
IF token.length = 1 THEN allcaps ← 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;
};
allComments: BOOL ← TRUE;
nameLooks: TextLooks.Looks ← TextLooks.noLooks;
mesaLooks: 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, procName, procNameColon, procNameDef} ← null;
stream ← IO.RIS[node.rope.Substr[0, end]];
IO.SetIndex[stream, first];
mesaLooks['k] ← mesaLooks['c] ← mesaLooks['n] ← TRUE;
nameLooks['n] ← TRUE;
IF end > first THEN EditSpan.RemoveLooks[root, [[node, first], [node, end-1]], mesaLooks, event];
UNTIL tokenKind = tokenEOF
DO
add, alpha, allcaps: BOOL ← FALSE;
addLooks, remLooks: TextLooks.Looks ← TextLooks.noLooks;
tokStart, tokLen: INT ← 0;
[tokenKind, token] ← IO.GetCedarToken[stream, token, FALSE];
tokLen ← token.length;
tokStart ← IO.GetIndex[stream]-tokLen;
remLooks ← mesaLooks;
SELECT tokenKind
FROM
tokenEOF => NULL;
tokenCOMMENT => {
add ← TRUE;
addLooks['c] ← TRUE;
remLooks['c] ← FALSE;
comments ← comments+1;
};
tokenID => {
allComments ← FALSE;
[alpha, allcaps] ← CheckID[];
SELECT
TRUE
FROM
allcaps => {
add ← TRUE;
addLooks['k] ← TRUE;
remLooks['k] ← FALSE;
keywords ← keywords+1;
IF NOT namifyTypes AND Match["TYPE"] THEN state ← null;
IF Match["PUBLIC"] OR Match["PRIVATE"] THEN NULL
ELSE {state ← IF state = procNameColon THEN procNameDef ELSE null};
};
alpha
AND token[0]
IN ['A..'Z]
AND state = null => {
save positions & text since may be a proc name
pStart ← tokStart;
pLen ← tokLen;
state ← procName;
};
alpha => {state ← IF state = procNameColon AND token[0] IN ['A..'Z] THEN procNameDef ELSE null}
ENDCASE;
};
tokenSINGLE => {
allComments ← FALSE;
state ←
SELECT token[0]
FROM
': => SELECT state FROM procName => procNameColon ENDCASE => null,
ENDCASE => null;
};
ENDCASE => {allComments ← FALSE; state ← null};
IF add
THEN {
EditSpan.ChangeLooks[root, [[node,tokStart], [node,tokStart+tokLen-1]], remLooks, addLooks, event];
add ← FALSE;
addLooks ← TextLooks.noLooks;
remLooks ← mesaLooks;
};
IF state = procNameDef
THEN {
state ← null;
IF pLen > 0
THEN {
procs ← procs+1;
EditSpan.AddLooks[root, [[node, pStart], [node, pStart+pLen-1]], nameLooks, event]
};
pLen ← 0;
};
ENDLOOP;
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 ← 0;
msg: REF TEXT ← NEW[TEXT[40]];
Append:
PROC [value:
INT, what:
ROPE, dlm:
ROPE] ~ {
msg ← Convert.AppendInt[msg, value];
msg ← RefText.AppendRope[msg, what];
IF value # 1 THEN msg ← RefText.AppendRope[msg, "s"];
msg ← RefText.AppendRope[msg, dlm];
};
DoSet:
PROC [root: TextNode.Node, tSel: TEditDocument.Selection] = {
span: TextNode.Span ← [tSel.start.pos, tSel.end.pos];
firstText: TextNode.Node ~ tSel.start.pos.node;
lastText: TextNode.Node ~ 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] };
[procs, comments, keywords] ← SetSpanMesaLooks[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];
Append[keywords, " keyword", ", "];
Append[comments, " comment", ", "];
Append[procs, " procedure name", "."];
MessageWindow.Append[Rope.FromRefText[msg], TRUE];
};
TEditInput.Register[$SetMesaLooks, SetMesaLooksOp, FALSE];
END.