<<>> <> <> <> <> <> <> <> <> <> <> 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]; TiogaOps2Impl: CEDAR PROGRAM IMPORTS Atom, EditSpan, MessageWindow, NodeProps, NodeStyleOps, PFS, Rope, TEditDocument, TEditDocumentPrivate, TEditInput, TEditInputOps, TEditOps, TEditProfile, TEditRefresh, TEditScrolling, TEditSelection, TextEdit, TextEditBogus, TextFind, TextLooks, TextNode, TiogaFind, TiogaIO, TiogaOps EXPORTS TiogaOps, TiogaMenuOps, TiogaExtraOps ~ BEGIN ROPE: TYPE ~ Rope.ROPE; Viewer: TYPE ~ ViewerClasses.Viewer; Column: TYPE ~ ViewerClasses.Column; Node: TYPE ~ Tioga.Node; Location: TYPE ~ Tioga.Location; Looks: TYPE ~ Tioga.Looks; noLooks: Looks ~ Tioga.noLooks; <> 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] }; <<>> <> Position: PUBLIC PROC [viewer: Viewer] = { TEditSelection.Position[viewer]; }; Normalize: PUBLIC PROC [viewer: Viewer] = { [] ¬ TEditInput.Normalize[viewer]; }; PrevPlace: PUBLIC PROC [viewer: Viewer] = { TEditDocumentPrivate.JumpToPrevious[viewer]; }; Reselect: PUBLIC PROC [viewer: Viewer] = { TEditDocumentPrivate.Reselect[viewer]; }; <> 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]; }; <> FirstLevelOnly: PUBLIC PROC [viewer: Viewer] = { [] ¬ TEditInput.FirstLevelOnly[viewer] }; MoreLevels: PUBLIC PROC [viewer: Viewer] = { [] ¬ TEditInput.MoreLevels[viewer] }; FewerLevels: PUBLIC PROC [viewer: Viewer] = { [] ¬ TEditInput.FewerLevels[viewer] }; AllLevels: PUBLIC PROC [viewer: Viewer] = { [] ¬ TEditInput.AllLevels[viewer] }; <> <> <<>> 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] }; <> <<>> 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]] }; <> 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] }; <> <<>> 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]]] }; <<>> <> <<>> 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] }; <<>> <> <<>> SelectPoint: PUBLIC PROC [viewer: Viewer, caret: Location, which: TiogaOpsDefs.WhichSelection ¬ primary] = { TiogaOps.SetSelection[viewer: viewer, start: caret, end: caret, level: point, which: which]; }; <> <<>> 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] }; <<>> END.