TiogaOps2Impl.mesa
Copyright Ó 1985, 1987, 1989, 1991, 1992 by Xerox Corporation. All rights reserved.
written by Bill Paxton. June 1982
last written by Paxton. December 30, 1982 11:13 am
Last Edited by: Maxwell, January 6, 1983 11:48 am
Rick Beach, March 28, 1985 10:15:04 am PST
Russ Atkinson (RRA) January 23, 1986 0:02:15 am PST
Michael Plass, October 16, 1987 5:21:07 pm PDT
Willie-s, February 13, 1991 5:14 pm PST
Doug Wyatt, March 16, 1992 3:01 pm PST
DIRECTORY
Atom USING [GetPName, MakeAtom],
EditSpan USING [CompareNodeOrder, NodeOrder],
MessageWindow USING [Append],
NodeProps USING [CopyInfoProc, GetProp, MapProps, NullCopy, NullRead, NullWrite, PutProp, ReadSpecsProc, Register, RemProp, WriteSpecsProc],
NodeStyleOps USING [StyleNameForNode],
PFS USING [PathFromRope],
Rope USING [ROPE, IsEmpty],
TEditDocument USING [Selection, SpinAndLock, TEditDocumentData, Unlock],
TEditDocumentPrivate USING [CloseAndOpenPreviousFile, DefaultMenus, DoCloseAndNewViewer, DoCloseAndOpenImplFile, DoLoadFile, DoLoadImplFile, DoNewViewer, DoOpenFile, DoOpenImplFile, DoStoreFile, EmptyViewer, JumpToPrevious, LoadPreviousFile, OpenPreviousFile, Reselect, Reset, Save],
TEditInput USING [AllLevels, CloseEvent, CommandProc, FewerLevels, FirstLevelOnly, FreeTree, MoreLevels, Normalize, Register, UnRegister],
TEditInputOps USING [CallWithLocks, DoFindPlaceholders, DoNextViewer, DoSelectMatchingBrackets],
TEditOps USING [RememberCurrentPosition],
TEditProfile USING [selectionCaret],
TEditRefresh USING [ScrollToEndOfSel],
TEditScrolling USING [ScrollToPosition],
TEditSelection USING [MakeSelection, Position, pSel, SetSelLooks],
TextEdit USING [ChangeLooks, FromRope, GetFormat, Size, FetchLooks],
TextEditBogus USING [GetRope],
TextFind USING [Error, Target],
TextLooks USING [LooksToRope],
TextNode USING [FirstChild, FirstSibling, LastChild, LastLocWithin, LastSibling, LastWithin, Next, Parent, Previous, Root, StepBackward, StepForward],
Tioga USING [Node, Location, Looks, noLooks],
TiogaExtraOps USING [MapPropsAction],
TiogaFind USING [Match, Search, TargetFromNode],
TiogaIO USING [FromFile, ToFile],
TiogaMenuOps USING [],
TiogaOps USING [CommandProc, Dir, Pattern, PatternRec, PatternErrorCode, SearchDir, SetSelection],
TiogaOpsDefs USING [Order, WhichSelection],
ViewerClasses USING [Column, Viewer];
Search
Finder: TYPE = REF FinderRec;
FinderRec:
PUBLIC
TYPE =
RECORD [target: TextFind.Target, case, addBounds:
BOOL];
MakeName:
PROC [r:
ROPE]
RETURNS [
ATOM] ~ {
RETURN [IF r.IsEmpty THEN NIL ELSE Atom.MakeAtom[r]];
};
MalformedPattern:
PUBLIC
ERROR [ec: TiogaOps.PatternErrorCode] ~
CODE;
CreateGeneralPattern:
PUBLIC
PROC [
target: Node, -- node from which to get the pattern
text: BOOL ¬ TRUE, -- if true, match target text
looks: BOOL ¬ FALSE, -- if true, match target looks
format: BOOL ¬ FALSE, -- if true, match target format
style: BOOL ¬ FALSE, -- if true, match target style
comment: BOOL ¬ FALSE, -- if true, match target comment property
case: BOOL ¬ TRUE, -- if true, match case
literal: BOOL ¬ FALSE, -- if true, treat target literally rather than as a pattern
word: BOOL ¬ FALSE, -- if true, match words only
subset: BOOL ¬ TRUE, -- if true, use subset for looks test, else use equality
addBounds: BOOL ¬ FALSE] -- if true, add |'s to both ends of pattern
RETURNS [pattern: TiogaOps.Pattern] = {
txt: Node = target;
patternTxt: Node ¬ txt;
pattern ¬ NEW[TiogaOps.PatternRec];
IF looks
AND ~text
THEN {
-- make a phony search pattern and get the looks
size: INT = TextEdit.Size[txt];
lks: Looks = IF size=0 THEN noLooks ELSE TextEdit.FetchLooks[txt,0];
pattern.searchLooks ¬ TextLooks.LooksToRope[lks];
FOR i:
INT
IN [1..size)
DO
IF TextEdit.FetchLooks[txt,i]#lks
THEN {
MessageWindow.Append["Search pattern does not have uniform looks.",TRUE];
MessageWindow.Append[" Using looks from first char."];
EXIT
};
ENDLOOP;
literal ¬ FALSE;
patternTxt ¬ TextEdit.FromRope["**#**"];
TextEdit.ChangeLooks[root: NIL, text: patternTxt, add: lks];
};
pattern.text ¬ text;
pattern.looks ¬ looks;
pattern.word ¬ word;
pattern.looksExact ¬ ~subset;
pattern.commentControl ¬ IF ~comment OR txt=NIL THEN includeComments
ELSE IF txt.comment THEN commentsOnly ELSE excludeComments;
pattern.checkFormat ¬ format;
pattern.format ¬ Atom.GetPName[TextEdit.GetFormat[target]];
pattern.checkStyle ¬ style;
pattern.style ¬ IF ~style THEN NIL ELSE Atom.GetPName[NodeStyleOps.StyleNameForNode[target]];
IF text
OR looks
THEN {
-- create a description of the pattern
pattern.finder ¬
NEW[FinderRec ¬ [
target: TiogaFind.TargetFromNode[node: patternTxt, pattern: ~literal !
TextFind.Error => GOTO Malformed],
case: case,
addBounds: addBounds
]];
EXITS Malformed => ERROR MalformedPattern[other];
};
};
CreateSimplePattern:
PUBLIC
PROC [
target: ROPE, -- node from which to get the pattern
case: BOOL ¬ TRUE, -- if true, match case
literal: BOOL ¬ FALSE, -- if true, treat target literally rather than as a pattern
word: BOOL ¬ FALSE, -- if true, match words only
addBounds: BOOL ¬ FALSE] -- if true, add |'s to both ends of pattern
RETURNS [pattern: TiogaOps.Pattern] = {
RETURN CreateGeneralPattern[target: TextEdit.FromRope[target],
case: case, literal: literal, word: word, addBounds: addBounds];
};
SelectionSearch:
PUBLIC
PROC [
pattern: TiogaOps.Pattern, whichDir: TiogaOps.SearchDir ¬ forwards, interrupt:
REF
BOOL ¬
NIL,
startBoundaryNode, endBoundaryNode: Node ¬ NIL,
startBoundaryOffset: INT ¬ 0, endBoundaryOffset: INT ¬ LAST[INT]]
RETURNS [found: BOOL] = {
pSel: TEditDocument.Selection = TEditSelection.pSel;
Found:
PROC [tSel: TEditDocument.Selection] = {
tSel.viewer ¬ pSel.viewer;
tSel.data ¬ pSel.data;
TEditOps.RememberCurrentPosition[pSel.viewer];
TEditSelection.SetSelLooks[tSel];
TEditSelection.MakeSelection[new: tSel];
TEditInput.CloseEvent[];
TEditRefresh.ScrollToEndOfSel[tSel.viewer, FALSE]
};
Locations:
PROC
RETURNS [start, end: Location] = {
start ¬ pSel.start.pos; end ¬ pSel.end.pos
};
found ¬ DoSearch[pattern, whichDir, interrupt, Found, Locations,
startBoundaryNode, endBoundaryNode,
startBoundaryOffset, endBoundaryOffset]
};
NodeSearch:
PUBLIC
PROC [
pattern: TiogaOps.Pattern, whichDir: TiogaOps.SearchDir ¬ forwards,
startLoc, endLoc: Location, interrupt: REF BOOL ¬ NIL,
startBoundaryNode, endBoundaryNode: Node ¬ NIL,
startBoundaryOffset: INT ¬ 0, endBoundaryOffset: INT ¬ LAST[INT]]
RETURNS [found: BOOL, start, end: Location] = {
Found:
PROC [tSel: TEditDocument.Selection] = {
start ¬ tSel.start.pos; end ¬ tSel.end.pos;
};
Locations:
PROC
RETURNS [start, end: Location] = {
RETURN[start: startLoc, end: end];
};
found ¬ DoSearch[pattern, whichDir, interrupt, Found, Locations,
startBoundaryNode, endBoundaryNode,
startBoundaryOffset, endBoundaryOffset]
};
DoSearch:
PROC [pattern: TiogaOps.Pattern, whichDir: TiogaOps.SearchDir ¬ forwards, interrupt:
REF
BOOL ¬
NIL,
foundProc:
PROC [tSel: TEditDocument.Selection],
locationProc: PROC RETURNS [start, end: Location],
startBoundaryNode, endBoundaryNode: Node ¬ NIL,
startBoundaryOffset: INT ¬ 0, endBoundaryOffset: INT ¬ LAST[INT]]
RETURNS [found: BOOL ¬ FALSE] = {
at, atEnd, offset: INT ¬ 0;
first: Node;
where: Node;
startLoc, endLoc: Location;
DoLookForPattern:
PROC [root: Node, tSel: TEditDocument.Selection] = {
finder: Finder ~ pattern.finder;
target: TextFind.Target ~ IF finder#NIL THEN finder.target ELSE NIL;
case: BOOL ~ IF finder#NIL THEN finder.case ELSE TRUE;
match: TiogaFind.Match ~ IF finder#NIL AND finder.addBounds
THEN all ELSE IF pattern.word THEN word ELSE any;
Forwards:
PROC = {
IF (offset ¬ endLoc.where+1) >= TextEdit.Size[first ¬ endLoc.node]
THEN {
first ¬ TextNode.StepForward[first]; offset ¬ 0
};
[node: where, matchStart: at, matchEnd: atEnd] ¬ TiogaFind.Search[direction: forward,
loc1: [first, offset], loc2: [endBoundaryNode, endBoundaryOffset],
target: target, case: case, match: match,
checkLooks: pattern.looks, looksExact: pattern.looksExact,
checkComment: pattern.commentControl#includeComments,
comment: pattern.commentControl=commentsOnly,
checkFormat: pattern.checkFormat, format: MakeName[pattern.format],
checkStyle: pattern.checkStyle, style: MakeName[pattern.style],
styleProc: NodeStyleOps.StyleNameForNode, interrupt: interrupt];
};
Backwards:
PROC = {
IF (offset ¬ startLoc.where)=0
THEN {
first ¬ TextNode.StepBackward[startLoc.node];
offset ¬ LAST[INT]
}
ELSE first ¬ startLoc.node;
[node: where, matchStart: at, matchEnd: atEnd] ¬ TiogaFind.Search[direction: backward,
loc1: [startBoundaryNode, startBoundaryOffset], loc2: [first, offset],
target: target, case: case, match: match,
checkLooks: pattern.looks, looksExact: pattern.looksExact,
checkComment: pattern.commentControl#includeComments,
comment: pattern.commentControl=commentsOnly,
checkFormat: pattern.checkFormat, format: MakeName[pattern.format],
checkStyle: pattern.checkStyle, style: MakeName[pattern.style],
styleProc: NodeStyleOps.StyleNameForNode, interrupt: interrupt];
};
[startLoc, endLoc] ¬ locationProc[];
IF interrupt#NIL THEN interrupt ¬ FALSE;
SELECT whichDir
FROM
forwards => Forwards[];
backwards => Backwards[];
anywhere => {
Forwards[];
IF where#
NIL
THEN whichDir ¬ forwards
ELSE {
whichDir ¬ backwards; Backwards[]
}
};
ENDCASE => ERROR;
IF where=NIL THEN RETURN ELSE found ¬ TRUE;
tSel.start.pos ¬ [where,at];
tSel.end.pos ¬ [where,MAX[0,atEnd-1]];
tSel.granularity ¬
IF ~pattern.looks AND ~pattern.text THEN node
ELSE IF match=word THEN word ELSE char;
tSel.insertion ¬ IF TEditProfile.selectionCaret=before THEN before ELSE after;
foundProc[tSel];
};
TEditInputOps.CallWithLocks[DoLookForPattern, read]
};
SelectMatchingBrackets:
PUBLIC
PROC [before, after:
CHAR]
RETURNS [found:
BOOL] = {
found ¬ TEditInputOps.DoSelectMatchingBrackets[before, after]
};
NextPlaceholder:
PUBLIC
PROC [dir: TiogaOps.Dir ¬ forward, gotoend:
BOOL,
startBoundaryNode, endBoundaryNode: Node ¬ NIL,
startBoundaryOffset: INT ¬ 0, endBoundaryOffset: INT ¬ LAST[INT]]
RETURNS [found, wenttoend: BOOL] = {
[found, wenttoend] ¬ TEditInputOps.DoFindPlaceholders[
dir=forward, gotoend,
startBoundaryNode, endBoundaryNode,
startBoundaryOffset, endBoundaryOffset]
};
NextViewer:
PUBLIC
PROC [dir: TiogaOps.Dir ¬ forward]
RETURNS [found:
BOOL] = {
found ¬ TEditInputOps.DoNextViewer[dir=forward]
};
Files and text viewers
Save:
PUBLIC
PROC [viewer: Viewer] = {
TEditDocumentPrivate.Save[viewer];
};
Load:
PUBLIC
PROC [viewer: Viewer, fileName:
ROPE ¬
NIL,
fileNameProcViewer: Viewer ¬ NIL] = {
[] ¬ TEditDocumentPrivate.DoLoadFile[viewer, fileName, FALSE, fileNameProcViewer];
};
Open:
PUBLIC
PROC [fileName:
ROPE ¬
NIL, fileNameProcViewer: Viewer ¬
NIL, column: Column ¬ left]
RETURNS [Viewer] = {
RETURN [TEditDocumentPrivate.DoOpenFile[fileName: fileName, column: column, fileNameProcViewer: fileNameProcViewer]];
};
CloseAndOpen:
PUBLIC
PROC [viewer: Viewer, fileName:
ROPE ¬
NIL, fileNameProcViewer: Viewer ¬
NIL]
RETURNS [Viewer] = {
RETURN [TEditDocumentPrivate.DoLoadFile[viewer, fileName, TRUE, fileNameProcViewer]];
};
LoadImpl:
PUBLIC
PROC [viewer: Viewer, fileName:
ROPE ¬
NIL] = {
[] ¬ TEditDocumentPrivate.DoLoadImplFile[viewer, fileName];
};
OpenImpl:
PUBLIC
PROC [fileName:
ROPE ¬
NIL, column: Column ¬ left]
RETURNS [Viewer] = {
RETURN [TEditDocumentPrivate.DoOpenImplFile[fileName, column]];
};
CloseAndOpenImpl:
PUBLIC
PROC [viewer: Viewer, fileName:
ROPE ¬
NIL]
RETURNS [Viewer] = {
RETURN [TEditDocumentPrivate.DoCloseAndOpenImplFile[viewer, fileName]];
};
LoadPreviousFile:
PUBLIC
PROC [parent: Viewer] = {
TEditDocumentPrivate.LoadPreviousFile[parent];
};
OpenPreviousFile:
PUBLIC
PROC [parent: Viewer] = {
TEditDocumentPrivate.OpenPreviousFile[parent];
};
CloseAndOpenPreviousFile:
PUBLIC
PROC [parent: Viewer] = {
TEditDocumentPrivate.CloseAndOpenPreviousFile[parent];
};
DefaultMenus:
PUBLIC
PROC [viewer: Viewer, paint:
BOOL ¬
FALSE] = {
TEditDocumentPrivate.DefaultMenus[viewer, paint];
};
Store:
PUBLIC
PROC [viewer: Viewer, fileName:
ROPE ¬
NIL] = {
TEditDocumentPrivate.DoStoreFile[viewer, fileName];
};
New:
PUBLIC
PROC [column: Column ¬ left]
RETURNS [Viewer] = {
RETURN [TEditDocumentPrivate.DoNewViewer[column]];
};
Empty:
PUBLIC
PROC [viewer: Viewer] = {
TEditDocumentPrivate.EmptyViewer[viewer];
};
CloseAndNewViewer:
PUBLIC
PROC [viewer: Viewer]
RETURNS [Viewer] = {
RETURN [TEditDocumentPrivate.DoCloseAndNewViewer[viewer]];
};
Reset:
PUBLIC
PROC [viewer: Viewer] = {
TEditDocumentPrivate.Reset[viewer];
};
Jump:
PUBLIC
PROC [viewer: Viewer, loc: Location] = {
[] ¬ TEditScrolling.ScrollToPosition[viewer, loc];
};
TiogaExtraOps Implementation
Miscellaneous operations on nodes
GetRope:
PUBLIC
PROC [node: Node]
RETURNS [
ROPE] = {
RETURN [TextEditBogus.GetRope[node]]
};
Parent: PUBLIC PROC [node: Node] RETURNS [Node] = { RETURN [TextNode.Parent[node]] };
Root: PUBLIC PROC [node: Node] RETURNS [Node] = { RETURN [TextNode.Root[node]] };
Next: PUBLIC PROC [node: Node] RETURNS [Node] = { RETURN [TextNode.Next[node]] };
Previous: PUBLIC PROC [node: Node, parent: Node ¬ NIL] RETURNS [nx: Node] = { RETURN [TextNode.Previous[node]] };
StepForward: PUBLIC PROC [node: Node] RETURNS [nx: Node] = { RETURN [TextNode.StepForward[node]] };
StepBackward: PUBLIC PROC [node: Node, parent: Node ¬ NIL] RETURNS [back: Node] = { RETURN [TextNode.StepBackward[node, parent]] };
FirstSibling: PUBLIC PROC [node: Node] RETURNS [Node] = { RETURN [TextNode.FirstSibling[node]] };
LastSibling: PUBLIC PROC [node: Node] RETURNS [Node] = { RETURN [TextNode.LastSibling[node]] };
LastWithin: PUBLIC PROC [node: Node] RETURNS [Node] = { RETURN [TextNode.LastWithin[node]] };
LastLocWithin:
PUBLIC
PROC [node: Node]
RETURNS [Location] = {
RETURN [TextNode.LastLocWithin[node]];
};
FirstChild: PUBLIC PROC [node: Node] RETURNS [Node] = { RETURN [TextNode.FirstChild[node]] };
LastChild: PUBLIC PROC [node: Node] RETURNS [Node] = { RETURN [TextNode.LastChild[node]] };
IsDirty: PUBLIC PROC [node: Node] RETURNS [BOOL] = { RETURN [node.dirty] };
IsNew: PUBLIC PROC [node: Node] RETURNS [BOOL] = { RETURN [node.new] };
ClearDirty: PUBLIC PROC [node: Node] = { node.dirty ¬ FALSE };
ClearNew: PUBLIC PROC [node: Node] = { node.new ¬ FALSE };
ViewerDoc:
PUBLIC
PROC [viewer: Viewer]
RETURNS [root: Node] = {
tdd: TEditDocument.TEditDocumentData = NARROW[viewer.data];
IF tdd = NIL THEN RETURN [NIL];
[] ¬ TEditDocument.SpinAndLock[tdd, "ViewerDoc"]; -- make sure nothing else going on
root ¬ tdd.text;
TEditDocument.Unlock[tdd]
};
Node Property Lists
PutProp:
PUBLIC
PROC [n: Node, name:
ATOM, value:
REF] = {
NodeProps.PutProp[n, name, value]
};
GetProp:
PUBLIC
PROC [n: Node, name:
ATOM]
RETURNS [
REF] = {
RETURN [NodeProps.GetProp[n, name]]
};
RemProp:
PUBLIC
PROC [n: Node, name:
ATOM] = {
NodeProps.RemProp[n, name]
};
MapProps:
PUBLIC
PROC [n: Node, action: TiogaExtraOps.MapPropsAction, formatFlag, commentFlag:
BOOL ¬
TRUE]
RETURNS [
BOOL] = {
RETURN [NodeProps.MapProps[n, action, formatFlag, commentFlag]]
};
read, write, copy props
RegisterPropProc:
PUBLIC
PROC [name:
ATOM,
reader: NodeProps.ReadSpecsProc, writer: NodeProps.WriteSpecsProc, copier: NodeProps.CopyInfoProc] = {
NodeProps.Register[name, reader, writer, copier];
};
NullRead: PUBLIC NodeProps.ReadSpecsProc = { [] ¬ NodeProps.NullRead[name, specs] };
NullWrite: PUBLIC NodeProps.WriteSpecsProc = { [] ¬ NodeProps.NullWrite[name, value] };
NullCopy: PUBLIC NodeProps.CopyInfoProc = { [] ¬ NodeProps.NullCopy[name, value] };
Comparing order of nodes or locations in document
NodeOrder:
PROC [order: EditSpan.NodeOrder]
RETURNS [TiogaOpsDefs.Order] = {
RETURN [SELECT order FROM before => before, same => same, after => after, disjoint => disjoint, ENDCASE => ERROR] };
CompareLocOrder:
PUBLIC
PROC [loc1, loc2: Location]
RETURNS [order: TiogaOpsDefs.Order] = {
order ¬ NodeOrder[EditSpan.CompareNodeOrder[loc1.node, loc2.node]];
IF order=same
THEN order ¬
SELECT loc1.where
FROM
< loc2.where => before,
= loc2.where => same,
ENDCASE => after };
CompareNodeOrder:
PUBLIC
PROC [node1, node2: Node]
RETURNS [order: TiogaOpsDefs.Order] = {
RETURN [NodeOrder[EditSpan.CompareNodeOrder[node1, node2]]] };
File I/O
GetFile:
PUBLIC
PROC [name:
ROPE]
RETURNS [root: Node] = {
RETURN [TiogaIO.FromFile[PFS.PathFromRope[name]].root];
};
PutFile:
PUBLIC
PROC [name:
ROPE, root: Node] = {
[] ¬ TiogaIO.ToFile[PFS.PathFromRope[name], root];
};
FreeTree: PUBLIC PROC [root: Node] = { TEditInput.FreeTree[root] };
Make point selection
SelectPoint:
PUBLIC
PROC [viewer: Viewer, caret: Location, which: TiogaOpsDefs.WhichSelection ¬ primary] = {
TiogaOps.SetSelection[viewer: viewer, start: caret, end: caret, level: point, which: which];
};
Command registration
RegisterCommand:
PUBLIC
PROC [name:
ATOM, proc: TiogaOps.CommandProc, before:
BOOL ¬
TRUE] = {
TEditInput.Register[name, proc, before]
};
UnRegisterCommand:
PUBLIC
PROC [name:
ATOM, proc: TiogaOps.CommandProc] = {
TEditInput.UnRegister[name, proc]
};