TiogaOps2Impl.Mesa
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
DIRECTORY
TiogaOpsDefs,
EditSpan,
MessageWindow,
NameSymbolTable,
NodeStyle,
Rope,
RunReader,
TiogaDocument,
TiogaDocumentPrivate,
TiogaInput,
TiogaInputOps,
TiogaLocks,
TiogaMesaOps,
TiogaOps,
TiogaProfile,
TiogaRefresh,
TiogaScrolling,
TiogaSelection,
TextEdit,
TextFind,
TextFindPrivate,
TiogaLooks,
TiogaLooksSupport,
TiogaNode,
TiogaNodeOps,
TiogaOps,
TiogaExtraOps,
TiogaMenuOps,
TreeFind;
TiogaOps2Impl: CEDAR PROGRAM
IMPORTS
MessageWindow,
NameSymbolTable,
NodeStyle,
Rope,
RunReader,
TiogaDocumentPrivate,
TiogaInput,
TiogaInputOps,
TiogaOps,
TiogaProfile,
TiogaRefresh,
TiogaScrolling,
TiogaSelection,
TextEdit,
TextFind,
TiogaLooksSupport,
TiogaNodeOps,
TreeFind
EXPORTS TiogaOpsDefs, TiogaOps, TiogaMenuOps =
BEGIN OPEN TiogaOps, TiogaMenuOps, TiogaOpsDefs;
Ref: TYPE = REF NodeBody; -- points to a Tioga node
NodeBody: PUBLIC TYPE = TiogaNode.Body;
Finder: TYPE = REF FinderRec;
FinderRec: PUBLIC TYPE = TextFindPrivate.FinderRecord;
Search
LooksRope: PROC [looks: TiogaLooks.Looks] RETURNS [r: ROPE] = {
FOR c: CHAR IN TiogaLooks.Look DO
IF looks[c] THEN r ← Rope.Concat[r, Rope.FromChar[c]];
ENDLOOP
};
RopeToLooks: PROC [r: ROPE] RETURNS [looks: TiogaLooks.Looks] = {
Set: PROC [c: CHAR] RETURNS [quit: BOOLFALSE] = { looks[c] ← TRUE };
[] ← Rope.Map[base: r, action: Set];
};
CreateGeneralPattern: PUBLIC PROC [
target: Ref, -- node from which to get the pattern
text: BOOLTRUE, -- if true, match target text
looks: BOOLFALSE, -- if true, match target looks
format: BOOLFALSE, -- if true, match target format
style: BOOLFALSE, -- if true, match target style
comment: BOOLFALSE, -- if true, match target comment property
case: BOOLTRUE, -- if true, match case
literal: BOOLFALSE, -- if true, treat target literally rather than as a pattern
word: BOOLFALSE, -- if true, match words only
subset: BOOLTRUE, -- if true, use subset for looks test, else use equality
addBounds: BOOLFALSE] -- if true, add |'s to both ends of pattern
RETURNS [pattern: Pattern] = {
txt: TiogaNode.RefTextNode = TiogaNodeOps.NarrowToTextNode[target];
patternTxt: TiogaNode.RefTextNode ← txt;
pattern ← NEW[PatternRec];
IF looks AND ~text THEN { -- make a phony search pattern and get the looks
size: Offset = TextEdit.Size[txt];
lks: TiogaLooks.Looks = IF size=0 THEN TiogaLooks.noLooks ELSE TextEdit.FetchLooks[txt,0];
pattern.searchLooks ← LooksRope[lks];
FOR i: Offset IN [1..size) DO
IF TextEdit.FetchLooks[txt,i]#lks THEN {
OPEN MessageWindow;
Append["Search pattern does not have uniform looks.",TRUE];
Append[" Using looks from first char."];
EXIT };
ENDLOOP;
literal ← FALSE;
patternTxt ← TextEdit.FromRope["#*"];
TextEdit.SetLooks[NIL, patternTxt, 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 ← IF target=NIL OR target.format=TiogaNode.nullName THEN NIL ELSE
NameSymbolTable.RopeFromName[target.format];
pattern.checkStyle ← style;
pattern.style ← IF ~style THEN NIL
ELSE NameSymbolTable.RopeFromName[NodeStyle.StyleNameForNode[target]];
IF text OR looks THEN TRUSTED { -- create a description of the pattern
pattern.finder ← LOOPHOLE[
TreeFind.Create[patternTxt, literal, word, ~looks, ~case, addBounds]]};
};
CreateSimplePattern: PUBLIC PROC [
target: ROPE, -- node from which to get the pattern
case: BOOLTRUE, -- if true, match case
literal: BOOLFALSE, -- if true, treat target literally rather than as a pattern
word: BOOLFALSE, -- if true, match words only
addBounds: BOOLFALSE] -- if true, add |'s to both ends of pattern
RETURNS [pattern: Pattern] = {
pattern ← NEW[PatternRec];
pattern.text ← TRUE;
pattern.looks ← FALSE;
pattern.word ← word;
pattern.commentControl ← includeComments;
pattern.checkFormat ← FALSE;
pattern.format ← NIL;
pattern.checkStyle ← FALSE;
pattern.style ← NIL;
TRUSTED {pattern.finder ← LOOPHOLE[TreeFind.CreateFromRope[target, literal, word, ~case, addBounds]]};
};
FindCC: PROC [cc: CommentControl] RETURNS [TreeFind.CommentControl] = INLINE {
RETURN [SELECT cc FROM
includeComments => includeComments,
excludeComments => excludeComments,
commentsOnly => commentsOnly,
ENDCASE => ERROR] };
SelectionSearch: PUBLIC PROC [
pattern: Pattern, whichDir: SearchDir ← forwards, interrupt: REF BOOLNIL,
startBoundaryNode, endBoundaryNode: Ref ← NIL,
startBoundaryOffset: Offset ← 0, endBoundaryOffset: Offset ← LAST[Offset]]
RETURNS [found: BOOL] = {
pSel: TiogaDocument.Selection = TiogaSelection.pSel;
Found: PROC [tSel: TiogaDocument.Selection] = {
tSel.viewer ← pSel.viewer;
tSel.data ← pSel.data;
TiogaOps.RememberCurrentPosition[pSel.viewer];
TiogaSelection.SetSelLooks[tSel];
TiogaSelection.MakeSelection[new: tSel];
TiogaInput.CloseEvent[];
TiogaRefresh.ScrollToEndOfSel[tSel.viewer, FALSE] };
Locations: PROC RETURNS [start, end: TiogaNode.Location] = {
start ← pSel.start.pos; end ← pSel.end.pos };
found ← DoSearch[pattern, whichDir, interrupt, Found, Locations,
startBoundaryNode, endBoundaryNode,
startBoundaryOffset, endBoundaryOffset] };
DocLoc: PROC [loc: Location] RETURNS [TiogaNode.Location] = INLINE {
RETURN [[loc.node, loc.where]] };
MyLoc: PROC [loc: TiogaNode.Location] RETURNS [Location] = INLINE {
RETURN [[loc.node, loc.where]] };
NodeSearch: PUBLIC PROC [
pattern: Pattern, whichDir: SearchDir ← forwards,
startLoc, endLoc: Location, interrupt: REF BOOLNIL,
startBoundaryNode, endBoundaryNode: Ref ← NIL,
startBoundaryOffset: Offset ← 0, endBoundaryOffset: Offset ← LAST[Offset]]
RETURNS [found: BOOL, start, end: Location] = {
Found: PROC [tSel: TiogaDocument.Selection] = {
start ← MyLoc[tSel.start.pos]; end ← MyLoc[tSel.end.pos] };
Locations: PROC RETURNS [start, end: TiogaNode.Location] = {
start ← DocLoc[startLoc]; end ← DocLoc[endLoc] };
found ← DoSearch[pattern, whichDir, interrupt, Found, Locations,
startBoundaryNode, endBoundaryNode,
startBoundaryOffset, endBoundaryOffset] };
DoSearch: PROC [
pattern: Pattern, whichDir: SearchDir ← forwards, interrupt: REF BOOLNIL,
foundProc: PROC [tSel: TiogaDocument.Selection],
locationProc: PROC RETURNS [start, end: TiogaNode.Location],
startBoundaryNode, endBoundaryNode: Ref ← NIL,
startBoundaryOffset: Offset ← 0, endBoundaryOffset: Offset ← LAST[Offset]]
RETURNS [found: BOOL] = {
at, atEnd, offset: TiogaNode.Offset;
first: TiogaNode.Ref;
where: TiogaNode.RefTextNode;
startLoc, endLoc: TiogaNode.Location;
DoLookForPattern: PROC [
root: TiogaNode.RefBranchNode, tSel: TiogaDocument.Selection] = {
Forwards: PROC = TRUSTED {
IF (offset ← endLoc.where+1) >=
TextEdit.Size[TiogaNodeOps.NarrowToTextNode[first ← endLoc.node]] THEN {
first ← TiogaNodeOps.StepForward[first]; offset ← 0 };
[found,where,at,atEnd,,] ←
TreeFind.Try[finder: LOOPHOLE[pattern.finder], first: first, start: offset,
last: endBoundaryNode, lastLen: endBoundaryOffset,
interrupt: interrupt,
looksExact: pattern.looksExact,
checkFormat: pattern.checkFormat,
format: NameSymbolTable.MakeNameFromRope[pattern.format],
commentControl: FindCC[pattern.commentControl],
checkStyle: pattern.checkStyle,
style: NameSymbolTable.MakeNameFromRope[pattern.style],
styleProc: NodeStyle.StyleNameForNode] };
Backwards: PROC = TRUSTED {
IF (offset ← startLoc.where)=0 THEN {
first ← TiogaNode.StepBackward[startLoc.node];
offset ← TreeFind.MaxLen }
ELSE first ← startLoc.node;
[found,where,at,atEnd,,] ←
TreeFind.TryBackwards[finder: LOOPHOLE[pattern.finder],
first: first, len: offset,
last: startBoundaryNode, lastStart: startBoundaryOffset,
interrupt: interrupt,
looksExact: pattern.looksExact,
checkFormat: pattern.checkFormat,
format: NameSymbolTable.MakeNameFromRope[pattern.format],
commentControl: FindCC[pattern.commentControl],
checkStyle: pattern.checkStyle,
style: NameSymbolTable.MakeNameFromRope[pattern.style],
styleProc: NodeStyle.StyleNameForNode] };
[startLoc, endLoc] ← locationProc[];
IF interrupt#NIL THEN interrupt^ ← FALSE;
SELECT whichDir FROM
forwards => Forwards[];
backwards => Backwards[];
anywhere => {
Forwards[];
IF found THEN whichDir ← forwards ELSE {
whichDir ← backwards; Backwards[] }};
ENDCASE => ERROR;
IF ~found OR where=NIL THEN RETURN;
IF pattern.looks AND ~pattern.text AND ~pattern.word THEN
[at,atEnd] ← Extend[whichDir=forwards,
pattern.looksExact, RopeToLooks[pattern.searchLooks], where, at, atEnd];
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 pattern.word THEN word ELSE char;
tSel.insertion ← IF TiogaProfile.selectionCaret=before THEN before ELSE after;
foundProc[tSel];
};
TiogaInputOps.CallWithLocks[DoLookForPattern, read] };
Extend: PROC
[forward, looksExact: BOOLEAN, searchLooks: TiogaLooks.Looks,
where: TiogaNode.RefTextNode, at, atEnd: TiogaNode.Offset,
last: TiogaNode.Ref ← NIL, lastLen: TiogaNode.Offset ← TiogaNode.MaxLen]
RETURNS [newAt, newAtEnd: TiogaNode.Offset] = {
runrdr: RunReader.Ref ← RunReader.GetRunReader[];
{ -- for EXITS
looks: TiogaLooks.Looks;
runLen: TiogaNode.Offset;
runs: TiogaLooks.Runs ← where.runs;
IF forward THEN { -- extend toward end of node
size: TiogaNode.Offset ← TextEdit.Size[where];
IF atEnd=size OR size=0 THEN GOTO Done;
lastLen ← IF where=last THEN MIN[size,lastLen] ELSE size;
RunReader.SetPosition[runrdr,runs,atEnd];
WHILE atEnd < lastLen DO
IF runs=NIL THEN { runLen ← size-atEnd; looks ← TiogaLooks.noLooks }
ELSE [runLen,looks] ← RunReader.Get[runrdr];
IF ~looksExact THEN looks ← TiogaLooksSupport.LooksAND[looks,searchLooks];
IF searchLooks # looks THEN EXIT;
atEnd ← atEnd+runLen;
ENDLOOP;
RunReader.FreeRunReader[runrdr];
RETURN [at,MIN[atEnd,lastLen]] };
IF at=0 THEN GOTO Done;
RunReader.SetPosition[runrdr,runs,at];
WHILE at > 0 DO
IF runs=NIL THEN { runLen ← at; looks ← TiogaLooks.noLooks }
ELSE [runLen,looks] ← RunReader.Backwards[runrdr];
IF ~looksExact THEN looks ← TiogaLooksSupport.LooksAND[looks,searchLooks];
IF searchLooks # looks THEN EXIT;
at ← at-runLen;
ENDLOOP;
RunReader.FreeRunReader[runrdr];
RETURN [at,atEnd];
EXITS Done => { RunReader.FreeRunReader[runrdr]; RETURN }}};
SelectMatchingBrackets: PUBLIC PROC [before, after: CHAR] RETURNS [found: BOOL] = {
found ← TiogaInputOps.DoSelectMatchingBrackets[before, after] };
NextPlaceholder: PUBLIC PROC [dir: Dir ← forward, gotoend: BOOL,
startBoundaryNode, endBoundaryNode: Ref ← NIL,
startBoundaryOffset: Offset ← 0, endBoundaryOffset: Offset ← LAST[Offset]]
RETURNS [found, wenttoend: BOOL] = {
[found, wenttoend] ← TiogaInputOps.DoFindPlaceholders[
dir=forward, gotoend,
startBoundaryNode, endBoundaryNode,
startBoundaryOffset, endBoundaryOffset] };
NextViewer: PUBLIC PROC [dir: Dir ← forward] RETURNS [found: BOOL] = {
found ← TiogaInputOps.DoNextViewer[dir=forward] };
SearchWhere: PROC [whichDir: SearchDir] RETURNS [TiogaSelection.FindWhere] = INLINE {
RETURN [SELECT whichDir FROM
forwards => forwards,
backwards => backwards,
anywhere => anywhere,
ENDCASE => ERROR] };
Places menu commands
Position: PUBLIC PROC [viewer: Viewer] = { TiogaSelection.Position[viewer] };
Normalize: PUBLIC PROC [viewer: Viewer] = { [] ← TiogaInput.Normalize[] };
PrevPlace: PUBLIC PROC [viewer: Viewer] = {
TiogaDocumentPrivate.JumpToPrevious[viewer] };
Reselect: PUBLIC PROC [viewer: Viewer] = {
TiogaDocumentPrivate.Reselect[viewer] };
Files and text viewers
Save: PUBLIC PROC [viewer: Viewer] = {
TiogaDocumentPrivate.Save[viewer] };
Load: PUBLIC PROC [viewer: Viewer, fileName: ROPENIL,
fileNameProcViewer: Viewer ← NIL] = {
[] ← TiogaDocumentPrivate.DoLoadFile[
viewer, fileName, FALSE, fileNameProcViewer] };
Open: PUBLIC PROC [fileName: ROPENIL, fileNameProcViewer: Viewer ← NIL]
RETURNS [Viewer] = {
RETURN [TiogaDocumentPrivate.DoOpenFile[fileName, fileNameProcViewer]] };
CloseAndOpen: PUBLIC PROC [
viewer: Viewer, fileName: ROPENIL, fileNameProcViewer: Viewer ← NIL]
RETURNS [Viewer] = {
RETURN [TiogaDocumentPrivate.DoLoadFile[
viewer, fileName, TRUE, fileNameProcViewer]] };
LoadImpl: PUBLIC PROC [viewer: Viewer, fileName: ROPENIL] = {
[] ← TiogaDocumentPrivate.DoLoadImplFile[viewer, fileName] };
OpenImpl: PUBLIC PROC [fileName: ROPENIL] RETURNS [Viewer] = {
RETURN [TiogaDocumentPrivate.DoOpenImplFile[fileName]] };
CloseAndOpenImpl: PUBLIC PROC [viewer: Viewer, fileName: ROPENIL]
RETURNS [Viewer] = {
RETURN [TiogaDocumentPrivate.DoCloseAndOpenImplFile[viewer, fileName]] };
LoadPreviousFile: PUBLIC PROC [parent: Viewer] = {
TiogaDocumentPrivate.LoadPreviousFile[parent] };
OpenPreviousFile: PUBLIC PROC [parent: Viewer] = {
TiogaDocumentPrivate.OpenPreviousFile[parent] };
CloseAndOpenPreviousFile: PUBLIC PROC [parent: Viewer] = {
TiogaDocumentPrivate.CloseAndOpenPreviousFile[parent] };
DefaultMenus: PUBLIC PROC [viewer: Viewer, paint: BOOLFALSE] = {
TiogaDocumentPrivate.DefaultMenus[viewer, paint] };
Store: PUBLIC PROC [viewer: Viewer, fileName: ROPENIL] = {
TiogaDocumentPrivate.DoStoreFile[viewer, fileName] };
New: PUBLIC PROC RETURNS [Viewer] = {
RETURN [TiogaDocumentPrivate.DoNewViewer[]] };
Empty: PUBLIC PROC [viewer: Viewer] = {
TiogaDocumentPrivate.EmptyViewer[viewer] };
CloseAndNewViewer: PUBLIC PROC [viewer: Viewer] RETURNS [Viewer] = {
RETURN [TiogaDocumentPrivate.DoCloseAndNewViewer[viewer]] };
Reset: PUBLIC PROC [viewer: Viewer] = {
TiogaDocumentPrivate.Reset[viewer] };
Jump: PUBLIC PROC [viewer: Viewer, loc: Location] = {
DocLoc: PROC [loc: Location] RETURNS [TiogaNode.Location] = INLINE {
RETURN [[loc.node, loc.where]] };
[] ← TiogaScrolling.ScrollToPosition[viewer, DocLoc[loc]] };
Levels menu commands
FirstLevelOnly: PUBLIC PROC [viewer: Viewer] = { [] ← TiogaInput.FirstLevelOnly[viewer] };
MoreLevels: PUBLIC PROC [viewer: Viewer] = { [] ← TiogaInput.MoreLevels[viewer] };
FewerLevels: PUBLIC PROC [viewer: Viewer] = { [] ← TiogaInput.FewerLevels[viewer] };
AllLevels: PUBLIC PROC [viewer: Viewer] = { [] ← TiogaInput.AllLevels[viewer] };
END.