DIRECTORY Rope USING [ROPE], ViewerClasses USING [Viewer]; TiogaOps: CEDAR DEFINITIONS = BEGIN ROPE: TYPE ~ Rope.ROPE; Viewer: TYPE ~ ViewerClasses.Viewer; Ref: TYPE = REF NodeBody; -- points to a Tioga node NodeBody: TYPE; Location: TYPE = RECORD [node: Ref, where: INT]; Order: TYPE = { before, same, after, disjoint }; WhichNodes: TYPE = { root, selection }; SelectionGrain: TYPE = { point, char, word, node, branch }; WhichSelection: TYPE = { primary, secondary, feedback }; GetCaret: PROC RETURNS [loc: Location]; CaretBefore: PROC; CaretAfter: PROC; CaretOnly: PROC; GoToNextCharacter: PROC [n: INT _ 1]; GoToNextWord: PROC [n: INT _ 1]; GoToNextNode: PROC [n: INT _ 1]; GoToPreviousCharacter: PROC [n: INT _ 1]; GoToPreviousWord: PROC [n: INT _ 1]; GoToPreviousNode: PROC [n: INT _ 1]; ToPrimary: PROC; ToSecondary: PROC; Transpose: PROC; InsertLineBreak: PROC; BackSpace: PROC [n: INT _ 1]; BackWord: PROC [n: INT _ 1]; DeleteNextCharacter: PROC [n: INT _ 1]; DeleteNextWord: PROC [n: INT _ 1]; InsertTime: PROC; InsertBrackets: PROC [left, right: CHAR]; MakeControlCharacter: PROC; UnMakeControlCharacter: PROC; MakeOctalCharacter: PROC; UnMakeOctalCharacter: PROC; ExpandAbbreviation: PROC; MesaFormatting: PROC; Repeat: PROC; Undo: PROC; WhichLooks: TYPE = { caret, selection }; SetSelectionLooks: PROC [which: WhichSelection _ primary]; SetLooks: PROC [looks: ROPE, which: WhichLooks _ selection]; AddLooks: PROC [looks: ROPE, which: WhichLooks _ selection]; SubtractLooks: PROC [looks: ROPE, which: WhichLooks _ selection]; ClearLooks: PROC [which: WhichLooks _ selection]; CopyLooks: PROC; CaretNodeFormat: PROC; InsertFormat: PROC; CopyFormat: PROC; SelectMatchingBrackets: PROC [before, after: CHAR] RETURNS [found: BOOL]; NextPlaceholder: PROC [dir: Dir _ forward, gotoend: BOOL, startBoundaryNode, endBoundaryNode: Ref _ NIL, startBoundaryOffset: INT _ 0, endBoundaryOffset: INT _ LAST[INT]] RETURNS [found, wenttoend: BOOL]; NextViewer: PROC [dir: Dir _ forward] RETURNS [found: BOOL]; Dir: TYPE = { forward, backwards }; FindText: PROC [viewer: Viewer, rope: ROPE _ NIL, whichDir: SearchDir _ forwards, which: WhichSelection _ primary, case: BOOL _ TRUE -- case => case of characters is significant -- ] RETURNS [found: BOOL]; FindWord: PROC [viewer: Viewer, rope: ROPE _ NIL, whichDir: SearchDir _ forwards, which: WhichSelection _ primary, case: BOOL _ TRUE -- case => case of characters is significant -- ] RETURNS [found: BOOL]; FindDef: PROC [viewer: Viewer, rope: ROPE _ NIL, whichDir: SearchDir _ forwards, which: WhichSelection _ primary, case: BOOL _ TRUE -- case => case of characters is significant -- ] RETURNS [found: BOOL]; GetSelection: PROC [which: WhichSelection _ primary] RETURNS [viewer: Viewer, start, end: Location, level: SelectionGrain, caretBefore: BOOL, pendingDelete: BOOL]; SelectionRoot: PROC [which: WhichSelection _ primary] RETURNS [root: Ref]; SetSelection: PROC [viewer: Viewer, start, end: Location, level: SelectionGrain _ char, caretBefore: BOOL _ TRUE, pendingDelete: BOOL _ FALSE, which: WhichSelection _ primary]; SelectPoint: PROC [viewer: Viewer, caret: Location, which: WhichSelection _ primary]; SelectNodes: PROC [viewer: Viewer, start, end: Ref, level: SelectionGrain _ node, caretBefore: BOOL _ TRUE, pendingDelete: BOOL _ FALSE, which: WhichSelection _ primary]; SelectBranches: PROC [viewer: Viewer, start, end: Ref, level: SelectionGrain _ node, caretBefore: BOOL _ TRUE, pendingDelete: BOOL _ FALSE, which: WhichSelection _ primary]; SelectDocument: PROC [viewer: Viewer, level: SelectionGrain _ node, caretBefore: BOOL _ TRUE, pendingDelete: BOOL _ FALSE, which: WhichSelection _ primary]; SelectionError: ERROR [ec: SelectionErrorCode]; -- can be raised by the above procedures SelectionErrorCode: TYPE = { IllegalViewer, -- either NIL or destroyed or no document data IllegalNode, -- either start or end node is NIL WrongDoc, -- start node not part of the viewer document WrongOrder, -- start location doesn't come before end location BadStartOffset, -- not within size of start node BadEndOffset }; -- not within size of end node CancelSelection: PROC [which: WhichSelection _ primary]; SaveSelA: PROC; RestoreSelA: PROC; SaveSelB: PROC; RestoreSelB: PROC; GrowSelection: PROC; GrowSelectionToBlanks: PROC; GrowSelectionToSomething: PROC [left, right: PROC [CHAR] RETURNS [BOOL]]; LockSel: PROC [which: WhichSelection _ primary]; UnlockSel: PROC [which: WhichSelection _ primary]; ViewerDoc: PROC [viewer: Viewer] RETURNS [Ref]; Jump: PROC [viewer: Viewer, loc: Location]; PutTextKey: PROC [node: Ref, where: INT, key: REF]; GetTextKey: PROC [node: Ref, key: REF] RETURNS [loc: Location]; TextKeyNotFound: ERROR; -- raised by GetTextKey RemoveTextKey: PROC [node: Ref, key: REF]; MapTextKeys: PROC [node: Ref, proc: PROC [key: REF, where: INT] RETURNS [BOOL] ] RETURNS [BOOL]; GetStyle: PROC [node: Ref] RETURNS [ROPE]; -- NIL for default IsDirty: PROC [node: Node] RETURNS [BOOL]; IsNew: PROC [node: Node] RETURNS [BOOL]; ClearDirty: PROC [n: Ref]; ClearNew: PROC [n: Ref]; CallWithLocks: PROC [proc: PROC [root: Ref], root: Ref _ NIL]; NoSelection: ERROR; Lock: PROC [root: Ref]; Unlock: PROC [root: Ref]; SelectionSearch: PROC [pattern: Pattern, whichDir: SearchDir _ forwards, interrupt: REF BOOL _ NIL, startBoundaryNode, endBoundaryNode: Ref _ NIL, startBoundaryOffset: INT _ 0, endBoundaryOffset: INT _ LAST[INT]] RETURNS [found: BOOL]; NodeSearch: PROC [pattern: Pattern, whichDir: SearchDir _ forwards, startLoc, endLoc: Location, interrupt: REF BOOL _ NIL, startBoundaryNode, endBoundaryNode: Ref _ NIL, startBoundaryOffset: INT _ 0, endBoundaryOffset: INT _ LAST[INT]] RETURNS [found: BOOL, start, end: Location]; SearchDir: TYPE = { forwards, backwards, anywhere }; CreateSimplePattern: 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: Pattern]; CreateGeneralPattern: PROC [ target: Ref, -- 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: Pattern]; MalformedPattern: ERROR [ec: PatternErrorCode]; PatternErrorCode: TYPE = { toobig, -- pattern too long endquote, -- pattern ends with ' endtilda, -- pattern ends with ~ boundary, -- pattern has | inside rather than at beginning or end missingNameEnd, -- pattern has < without matching > unmatchedNameEnd, -- pattern has > without previous < other -- other unspecified error in pattern }; Pattern: TYPE = REF PatternRec; PatternRec: TYPE = RECORD [ finder: Finder, text: BOOL, looks: BOOL, looksExact: BOOL, word: BOOL, commentControl: CommentControl, checkFormat: BOOL, format: ROPE, checkStyle: BOOL, style: ROPE, searchLooks: ROPE ]; Finder: TYPE = REF FinderRec; FinderRec: TYPE; CommentControl: TYPE = { includeComments, excludeComments, commentsOnly }; CommandProc: TYPE = PROC [viewer: Viewer _ NIL] RETURNS [recordAtom: BOOL _ TRUE, quit: BOOL _ FALSE]; RegisterCommand: PROC [name: ATOM, proc: CommandProc, before: BOOL _ TRUE]; UnRegisterCommand: PROC [name: ATOM, proc: CommandProc]; Interpret: PROC [viewer: Viewer, params: LIST OF REF ANY]; RegisterAbbrevFailedProc: PROC [proc: PROC RETURNS [BOOL]]; RegisterFileNameProc: PROC [ proc: PROC [ROPE, Viewer] RETURNS [fileName: ROPE, search: ROPE] ]; GetFile: PROC [name: ROPE] RETURNS [root: Ref]; PutFile: PROC [name: ROPE, root: Ref]; FreeTree: PROC [root: Ref]; END. ΐTempTiogaOps.mesa Copyright c 1985, 1986 by Xerox Corporation. All rights reserved. written by Bill Paxton. June 1982 last written by Paxton. December 29, 1982 10:56 am last written by Teitelman. January 19, 1983 12:02 pm Michael Plass, March 15, 1985 10:56:12 am PST Rick Beach, March 15, 1985 10:22:38 am PST Doug Wyatt, September 12, 1986 6:33:55 pm PDT Feedback selection is provided as a mechanism for giving visible mark without changing edit selections. You can explicitly cancel it, but it will go away automatically as soon as a non-feedback selection is made in the same viewer. Operations on/using selections Caret Operations (for primary selection) Edits requiring secondary selections Editing applying to primary selection inserts a CR and then copies blanks from front of previous line Looks sets the selection looks from the looks of the character next to the caret copies looks from secondary selection to primary selection see LooksReader.mesa if you need to read a lot of looks Formats will delete the word to the left of the caret and make it the format of the caret node inserts the format name copies format from secondary selection to primary selection Searching To search for a specified pattern, see SelectionSearch in section on Search below. If gotoend is true and doesn't find placeholder and not already at end of document, will make point selection at end and return with found=false and wenttoend=true. FindText, FindWord, and FindDef correspond to Find, Word, Def in the Places menu. if rope is NIL, uses contents of primary selection instead doesn't give user message if fails to find which parameter determines which selection to make Making/changing a selection Returns the document root for the selection. grows until procs return true. Locking a Selection Note: CallWithLocks, described below, is the recommended way of locking selections and documents. If for some reason you cannot use CallWithLocks, here are more primitive locking procedures. ensures that no other process will change primary selection. same process can re-Lock several times. make sure you UnlockSel as many times as you LockSel. Operations on nodes Viewer operations Returns root node for a text or typescript viewer. Normalizes the viewer with respect to the indicated location. loc must be in the document already being displayed in the viewer. Text keys: persistent "addresses" for characters in text nodes Associates the key with the given offset in the text node. Key moves with the text as edits take place in the node. Key can move to new node. Tells you where the key is in the node at the current time. loc node may be different if addr has been moved Calls proc for all the keys for the given node. Returns true if&when an action returns true Looks, Formats, Styles Dirty and New bits on nodes turns off the dirty bit on the node turns off the new bit on the node Locking a node This is the recommended way to take care of locking selections and documents. This procedure locks the primary selection. If root is NIL, it gets SelectionRoot[]. Then it locks the document by calling Lock[root]. After calling proc with the root, it unlocks both the document and the selection. It also takes care of unlocking them if it sees an UNWIND signal. If root is NIL and there is no selection, it raises the error NoSelection. raised by CallWithLocks If for some good reason you cannot use CallWithLocks, here are the primitive locking procedures. ensures that no other process will edit document. same process can re-Lock several times. make sure you Unlock as many times as you Lock. repaints are deferred until document is unlocked. Searching SelectionSearch searches the document that contains the current selection, and when finished, changes the current selection. NodeSearch is not tied to, nor does it change, the selection, but starts with a specified node, and traverses the tree, returning a location if the search is successful. Both take patterns which can be created as described below. startBoundaryNode and startBoundaryOffset limit how far backwards the search will go. if startBoundaryNode=NIL, search will go to start of document endBoundaryNode and endBoundaryOffset limit how far forwards the search will go. if endBoundaryNode=NIL, search will go to end of document. Similar to SelectionSearch, but doesn't change the selection. Just returns the result. startLoc and endLoc args serve to determine where to start the search just as primary selection serves in LookForPattern. This can be used to search in documents that are not currently being displayed in a viewer. CreateSimplePattern and CreateGeneralPattern can result in MalformedPattern being raised. Registering Command procedures These operations let you modify and extend the standard Tioga commands or add new commands of your own. The Tioga command interpreter keeps a table mapping each command atom to a list of CommandProc's. When it is given an atom to interpret, it gets the corresponding list of command procs and calls them one-by-one until someone returns with quit=TRUE. If any command proc returns with recordAtom=TRUE, the atom will be added to the repeat list for the current edit event (and will thus be re-interpreted if the user hits Repeat). The viewer argument to the command proc is the one passed to the interpreter which typically is the input focus viewer. For menu commands, the viewer is the one that contains the button. If before is true, proc goes at front of list, else goes at end of list. Remove the proc from the list for the atom. this calls the Tioga interpreter. params can be atoms or ropes. atoms are interpreted in manner described above, ropes are inserted at the caret. Miscellaneous call-back procedures If abbreviation expansion fails (i.e., cannot find the key), calls this proc. If it returns true, then it has done something useful. Otherwise, user gets normal error message. There can only be one of these registered at a time. Call RegisterAbbrevFailedProc with NIL to un-register. If try to load/open a file and filename is unknown, call this proc to get a corrected file name. There can only be one of these registered at a time. Call RegisterFileNameProc with NIL to un-register. File I/O If you have gotten access to the root by GetFile and know that there are no remaining references to it, call FreeTree to have all of the intra-tree pointers set to NIL. This causes circular reference chains to be broken so that the garbage collector can reclaim the tree. If you are not sure, don't call this! Κ ˜codešœ™Kšœ Οmœ7™BKšœ!™!Kšœ2™2Kšœ4™4K™-J™*K™-—K™šΟk ˜ Kšœžœžœ˜Kšœžœ ˜—K˜KšΠblœžœž ˜šœž˜K˜Kšžœžœžœ˜Kšœžœ˜$K˜Kšœžœžœ Οc˜3šœ žœ˜K˜—šœ žœžœžœ˜0K˜—šœžœ%˜0K˜—šœ žœ˜'K˜—šœžœ'˜;K˜—šœžœ$˜8K™θK˜——headšœ™šœ(™(šΟnœžœžœ˜'K˜—š‘ œžœ˜K˜—š‘ œžœ˜K˜—š‘ œžœ˜K˜—š‘œžœžœ˜%K˜—š‘ œžœžœ˜ K˜—š‘ œžœžœ˜ K˜—š‘œžœžœ˜)K˜—š‘œžœžœ˜$K˜—Kš‘œžœžœ˜$K˜—šœ$™$š‘ œžœ˜K˜—š‘ œžœ˜K˜—Kš‘ œžœ˜K˜—šœ%™%š‘œžœ˜Kšœ?™?K˜—š‘ œžœžœ˜K˜—š‘œžœžœ˜K˜—š‘œžœžœ˜'K˜—š‘œžœžœ˜"K˜—š‘ œžœ˜K˜—š‘œžœžœ˜)K˜—š‘œžœ˜K˜—š‘œžœ˜K˜—š‘œžœ˜K˜—š‘œžœ˜K˜—š‘œžœ˜K˜—š‘œžœ˜K˜—š‘œžœ˜ K˜—Kš‘œžœ˜ K˜—šœ™šœ žœ˜(K˜—š‘œžœ#˜:KšœJ™J—K˜š‘œžœ žœ!˜Kšœ  ˜0Kšœ ˜.K˜—š‘œžœ#˜8K˜—š‘œžœ˜K˜—š‘ œžœ˜K˜—š‘œžœ˜K˜—š‘ œžœ˜K˜—š‘ œžœ˜K˜—š‘œžœ˜K˜—š ‘œžœžœžœžœžœ˜IK™—K™—™K™ΎK˜š‘œžœ#˜0Kšœd™dK˜—š‘ œžœ#˜2K™5K™———šœ™™š‘ œžœžœ˜/K™2K™—š‘œžœ!˜+Kšœ€™€K™——šœ>™>š‘ œžœžœžœ˜3Kšœ™K˜—š‘ œžœžœžœ˜?K™;K™0K˜—Kšœžœ ˜/K˜Kš‘ œžœžœ˜*K˜š‘ œžœžœžœ žœžœžœžœžœ˜aK™/Kšœ+™+——™š ‘œžœ žœžœ ˜=K˜——šœ™š‘œžœžœžœ˜*K˜—š‘œžœžœžœ˜(K˜—š‘ œžœ ˜Kšœ#™#K˜—š‘œžœ ˜Kšœ!™!K™——™š‘ œžœžœžœ˜>K™ΉK™—šœ žœ˜Kšœ™—K™K™`K™š‘œžœ ˜KšœY™YK˜—š‘œžœ ˜K™bK™———šœ ™ Kšœβ™β˜š‘œžœ?žœžœžœ,žœžœžœžœžœžœ žœ˜λKšœ”™”KšœŒ™Œ—K™š‘ œžœ3žœ'žœžœžœžœ*žœžœžœžœžœžœžœ žœ˜˜K™VKšœΦ™Φ—K˜Kšœ žœ%˜4K˜š!‘œžœ žœ %œžœžœ œ žœžœ ;œžœžœ œ žœžœ +žœ˜ήK˜—šC‘œžœ %œžœžœ œžœžœ œ žœžœ œžœžœ œ žœžœ )œžœžœ œ žœžœ ;œžœžœ œ žœžœ 8œ žœžœ +žœ˜ΌK˜—K™YK™Kšœžœ˜/šœžœ˜Kšœ ˜Kšœ  ˜ Kšœ  ˜ Kšœ  7˜AKšœ #˜3Kšœ #˜5Kšœ %˜+K˜—K˜Kšœ žœžœ ˜šœ žœžœ˜Kšœ˜Kšœžœ˜ Kšœžœ˜ Kšœ žœ˜Kšœžœ˜ Kšœ˜Kšœ žœ˜Kšœžœ˜ Kšœ žœ˜Kšœžœ˜ Kšœ ž˜Kšœ˜K˜—Kšœžœžœ ˜šœ žœ˜K˜—Kšœžœ6˜J——šœ™Kšœέžœ/žœ™•™šœ žœžœžœžœžœžœžœžœ˜gK™»K˜—š ‘œžœžœžœžœ˜KK™HK˜—š‘œžœžœ˜8K™+—K˜š ‘ œžœžœžœžœžœ˜:K™!™K™Q—K™———šœ#™#š ‘œžœžœžœžœ˜;KšœŒžœ™ŸK™—š‘œžœ žœžœ žœ žœ žœ˜`Kšœ·žœ™Κ——šœ™Kš‘œžœžœžœ ˜/K˜Kš‘œžœžœ ˜&K˜š‘œžœ ˜Kšœ€žœ™·——K˜Kšžœ˜—…— (Gw