DIRECTORY Buttons USING [Create], Convert USING [RopeFromInt], EditSpanSupport USING [Apply], FS USING [Create, Error, GetName, Lock, nullOpenFile, Open, OpenFile], FSExtras USING [GetWDir], Menus USING [AppendMenuEntry, ChangeNumberOfLines, ClickProc, CreateEntry, CreateMenu, GetLine, GetNumberOfLines, InsertMenuEntry, Menu, MenuEntry, MenuLine, MenuProc, SetLine], MessageWindow USING [Append, Blink, Clear], NodeProps USING [GetProp, MapProps, PutProp], Process USING [Detach, GetCurrent], PutGet USING [FromFileC, FromFileError, FromRope, ToFileC, ToRope, WriteRopePlain], Rope USING [Cat, Concat, Equal, Flatten, FromRefText, Length, ROPE, SkipTo, Substr], TEditCompile USING [minAvgLineLeading], TEditDocument USING [ForgetViewer, LineTable, LineTableRec, RecordViewerForRoot, Selection, TEditDocumentData, TEditDocumentDataRec], TEditDocumentPrivate USING [AllLevels, Clear, FewerLevels, Find, FindDef, FindWord, FirstLevelOnly, Get, GetImpl, JumpToPrevious, KillSelections, MoreLevels, NewButton, Normalize, OpenButton, Position, PreReset, PreStore, PreviousFile, RecordUnsavedDocument, Reselect, Reset, Save, Split, Store, Time], TEditImpl USING [PaintTEditDocument, TEditNotifyProc], TEditInput USING [CommandProc, FreeTree, InterpretAtom, Register], TEditInputOps USING [CallWithLocks], TEditLocks USING [Lock, LockDocAndTdd, Unlock, UnlockDocAndTdd], TEditProfile USING [DoList], TEditRefresh USING [ScrollToEndOfSel], TEditScrolling USING [ScrollTEditDocument], TEditSelection USING [Alloc, Free, InputModify, MakeSelection], TEditTouchup USING [fullUpdate], TextEdit USING [DocFromNode, FromRope], TextLooks USING [noLooks], TextNode USING [FirstChild, LastLocWithin, Location, LocNumber, LocOffset, LocRelative, LocWithin, NodeProps, Offset, Ref, RefTextNode], TiogaMenuOps USING [], -- exports tiogaMenu TIPUser USING [InstantiateNewTIPTable, InvalidTable, TIPTable], UserProfile USING [Number], ViewerBLT USING [ChangeNumberOfLines], ViewerClasses USING [AdjustProc, DestroyProc, GetProc, InitProc, Lock, SaveAborted, SaveProc, SetProc, Viewer, ViewerClass, ViewerClassRec], ViewerForkers USING [ForkPaint], ViewerLocks USING [CallUnderViewerTreeLock], ViewerOps USING [AddProp, EnumerateChildren, EnumerateViewers, FetchProp, FetchViewerClass, PaintHint, PaintViewer, RegisterViewerClass, SetMenu], ViewerTools USING [EnableUserEdits, SelPos, SelPosRec, TiogaContents, TiogaContentsRec]; QueryTEditDocumentsImpl: CEDAR MONITOR IMPORTS Buttons, Convert, EditSpanSupport, FS, FSExtras, Menus, MessageWindow, NodeProps, Process, PutGet, Rope, TEditDocument, TEditDocumentPrivate, TextEdit, TextNode, TEditImpl, TEditInput, TEditInputOps, TEditLocks, TEditProfile, TEditRefresh, TEditTouchup, TEditScrolling, TEditSelection, TIPUser, UserProfile, ViewerBLT, ViewerClasses, ViewerForkers, ViewerOps, ViewerLocks, ViewerTools EXPORTS TEditImpl, TEditDocument, TEditDocumentPrivate, TiogaMenuOps SHARES Menus, ViewerClasses = BEGIN ROPE: TYPE ~ Rope.ROPE; fatalTiogaError: PUBLIC ERROR = CODE; -- for RETURN WITH ERROR monitor clearing punts InitTEditDocument: PUBLIC ViewerClasses.InitProc = { data: REF ANY _ self.data; self.data _ NIL; InitViewerDoc[self, data] }; InitViewerDoc: PUBLIC PROC [self: ViewerClasses.Viewer, data: REF ANY] = { InitViewerDocInternal[self: self, file: FS.nullOpenFile, data: data]; }; InitViewerDocInternal: PUBLIC PROC [self: ViewerClasses.Viewer, file: FS.OpenFile, data: REF ANY] = { tdd: TEditDocument.TEditDocumentData _ NARROW[self.data]; InitTddText: PROC = { IF tdd.text # NIL THEN TEditInput.FreeTree[tdd.text]; tdd.text _ NIL; IF file=FS.nullOpenFile THEN { IF self.file#NIL THEN file _ FS.Open[self.file ! FS.Error => CONTINUE]; }; IF file#FS.nullOpenFile THEN { self.file _ FS.GetName[file].fullFName; tdd.text _ PutGet.FromFileC[file ! FS.Error => { self.newFile _ TRUE; CONTINUE }; PutGet.FromFileError => { MessageWindow.Append["TEditDocumentsImpl: Error in Tioga formatting of ", TRUE]; MessageWindow.Append[self.file, FALSE]; MessageWindow.Blink[]; CONTINUE; }; ]; }; IF tdd.text=NIL THEN { tdd.text _ TextEdit.DocFromNode[TextEdit.FromRope[""]]; }; }; InitLineTable: PROC = { IF NodeProps.GetProp[tdd.text, $OpenFirstLevelOnly]#NIL THEN tdd.clipLevel _ 1; tdd.lineTable.lastLine _ 0; tdd.lineTable[0].pos _ [TextNode.FirstChild[tdd.text], 0]; }; IF self.link#NIL THEN { otherInit: ViewerClasses.Viewer _ NIL; IF tdd=NIL THEN self.data _ tdd _ NARROW[data]; -- someday I should really find out how to fix this in a less horrible manner [] _ SpinAndLock[tdd, "InitViewerDoc"]; FOR v: ViewerClasses.Viewer _ self.link, v.link UNTIL v=self DO IF ~v.newVersion THEN {otherInit _ v; EXIT}; ENDLOOP; IF otherInit=NIL THEN InitTddText[] ELSE { otherTdd: TEditDocument.TEditDocumentData _ NARROW[otherInit.data]; tdd.text _ otherTdd.text; }; InitLineTable[]; } ELSE IF data=NIL THEN { IF tdd=NIL THEN tdd _ AllocateDataForNewViewer[self]; [] _ SpinAndLock[tdd, "InitViewerDoc"]; InitTddText[]; InitLineTable[]; } ELSE WITH data SELECT FROM d: TEditDocument.TEditDocumentData => { self.data _ tdd _ d; [] _ SpinAndLock[tdd, "InitViewerDoc"]; InitTddText[]; InitLineTable[]; }; root: TextNode.RefTextNode => { IF tdd=NIL THEN tdd _ AllocateDataForNewViewer[self]; [] _ SpinAndLock[tdd, "InitViewerDoc"]; tdd.text _ root; InitLineTable[]; }; r: Rope.ROPE => { IF tdd=NIL THEN tdd _ AllocateDataForNewViewer[self]; [] _ SpinAndLock[tdd, "InitViewerDoc"]; tdd.text _ TextEdit.DocFromNode[TextEdit.FromRope[r]]; InitLineTable[]; }; t: REF TEXT => { IF tdd=NIL THEN tdd _ AllocateDataForNewViewer[self]; [] _ SpinAndLock[tdd, "InitViewerDoc"]; tdd.text _ TextEdit.DocFromNode[TextEdit.FromRope[Rope.FromRefText[t]]]; InitLineTable[]; }; ENDCASE => { IF tdd=NIL THEN tdd _ AllocateDataForNewViewer[self]; [] _ SpinAndLock[tdd, "InitViewerDoc"]; tdd.text _ PutGet.FromRope["*ERROR*"]; InitLineTable[]; }; TEditDocument.RecordViewerForRoot[self,tdd.text]; ViewerTools.EnableUserEdits[self]; Unlock[tdd]; }; AllocateDataForNewViewer: PROC [self: ViewerClasses.Viewer] RETURNS [tdd: TEditDocument.TEditDocumentData] = { tdd _ NEW[TEditDocument.TEditDocumentDataRec]; { -- for now, just hack in a conservative size line table maxLines: NAT ~ MAX[2, (self.ch/TEditCompile.minAvgLineLeading)+1]; lineTable: TEditDocument.LineTable ~ NEW[TEditDocument.LineTableRec[maxLines]]; lineTable.lastLine _ 0; lineTable.lastY _ 0; tdd.lineTable _ lineTable; }; IF self.column#static AND self.parent=NIL THEN ViewerOps.SetMenu[self, tiogaMenu, FALSE]; self.data _ tdd; }; number: INT _ 0; SaveTEditDocument: PUBLIC ViewerClasses.SaveProc = { tdd: TEditDocument.TEditDocumentData _ NARROW[self.data]; root: TextNode.Ref; name: ROPE _ self.file; errorMessage: ROPE _ NIL; IF name.Length = 0 THEN { IF ~force THEN ERROR ViewerClasses.SaveAborted["no file name!"]; name _ Rope.Flatten[Rope.Cat[ "SaveAllEdits-", Convert.RopeFromInt[number _ number + 1], ".tioga" ]]; }; IF tdd.readOnly THEN ERROR ViewerClasses.SaveAborted["read only document!"]; IF ~force THEN { MessageWindow.Clear[]; TEditDocumentPrivate.KillSelections[self]; [] _ SpinAndLock[tdd, "SaveTEditDocument"]; -- may have other operation in progress root _ tdd.text; Unlock[tdd]; -- don't need to keep this locked during rest of Save [] _ TEditLocks.Lock[root, "SaveTEditDocument", read]; } ELSE root _ tdd.text; { ENABLE FS.Error => { errorMessage _ error.explanation; CONTINUE }; defaultKeep: INT _ UserProfile.Number["Tioga.defaultKeep", 2]; file: FS.OpenFile ~ FS.Create[name: RemoveVersionNumber[name], setPages: FALSE, setKeep: FALSE, keep: defaultKeep]; newFile: ROPE ~ FS.GetName[file].fullFName; newName: ROPE ~ RemoveVersionNumber[newFile]; [] _ PutGet.ToFileC[file, root]; FOR v: ViewerClasses.Viewer _ self, v.link DO v.name _ newName; v.file _ newFile; SELECT v.link FROM NIL, self => EXIT; ENDCASE; ENDLOOP; }; IF ~force THEN TEditLocks.Unlock[root]; IF errorMessage#NIL THEN ERROR ViewerClasses.SaveAborted[errorMessage]; }; RemoveVersionNumber: PROC[name: ROPE] RETURNS[ROPE] = { RETURN[name.Flatten[start: 0, len: name.SkipTo[0, "!"]]]; }; FileIsMoreRecent: PUBLIC PROC [root: TextNode.Ref, file: Rope.ROPE] RETURNS [BOOL] = { RETURN [FALSE]; }; nullNode: TextNode.RefTextNode = TextEdit.FromRope[NIL]; SetTEditDocument: ViewerClasses.SetProc = { IF NOT self.destroyed THEN WITH self.data SELECT FROM tdd: TEditDocument.TEditDocumentData => { SELECT op FROM NIL, $TiogaContents, $TiogaDocument, $KeepRootStyleProps => { hint: ViewerOps.PaintHint _ client; rope: Rope.ROPE; IF self.link#NIL THEN ERROR; -- not yet implemented TEditDocumentPrivate.KillSelections[self]; [] _ SpinAndLock[tdd, "SetTEditDocument"]; SELECT op FROM NIL, $KeepRootStyleProps => { root: TextNode.RefTextNode = tdd.text; node: TextNode.RefTextNode = root; formatName: ATOM = root.formatName; child: TextNode.RefTextNode = IF node=NIL THEN NIL ELSE node.child; rope _ IF data=NIL THEN "" ELSE NARROW[data]; IF child#NIL AND child.last AND child.child=NIL THEN { RemoveProps: PROC [name: ATOM, value: REF] RETURNS [BOOL] = { IF name#$DocumentLock AND name#$Viewer AND ~(op=$KeepRootStyleProps AND (name=$Prefix OR name=$Postfix)) THEN NodeProps.PutProp[root, name, NIL]; RETURN [FALSE] }; rootProps: TextNode.NodeProps; child^ _ nullNode^; rootProps _ root.props; root^ _ nullNode^; root.props _ rootProps; root.child _ child; child.next _ root; root.last _ child.last _ TRUE; child.rope _ rope; IF op = $KeepRootStyleProps THEN root.formatName _ formatName; [] _ NodeProps.MapProps[root, RemoveProps, FALSE, FALSE] } ELSE { prefix, postfix: REF; IF op=$KeepRootStyleProps THEN { prefix _ NodeProps.GetProp[root, $Prefix]; postfix _ NodeProps.GetProp[root, $Postfix] }; TEditInput.FreeTree[root]; tdd.text _ TextEdit.DocFromNode[TextEdit.FromRope[rope]]; IF op=$KeepRootStyleProps THEN { IF prefix#NIL THEN NodeProps.PutProp[tdd.text, $Prefix, prefix]; IF postfix#NIL THEN NodeProps.PutProp[tdd.text, $Postfix, postfix]; tdd.text.formatName _ formatName }; }; }; $TiogaContents => { info: ViewerTools.TiogaContents _ NARROW[data]; rope _ Rope.Concat[info.contents, info.formatting]; TEditInput.FreeTree[tdd.text]; tdd.text _ PutGet.FromRope[rope]; }; $TiogaDocument => { root: TextNode.RefTextNode _ NARROW[data]; TEditInput.FreeTree[tdd.text]; tdd.text _ root }; ENDCASE; tdd.lineTable.lastLine _ 0; tdd.lineTable[0].pos _ [TextNode.FirstChild[tdd.text], 0]; TEditDocument.RecordViewerForRoot[self,tdd.text]; self.newVersion _ FALSE; -- clear edited bit Unlock[tdd]; IF finalise THEN { ViewerForkers.ForkPaint[self, hint, TRUE, TEditTouchup.fullUpdate, TRUE]; }; }; $SelPos => IF ~self.iconic AND ~ self.destroyed THEN { tSel: TEditDocument.Selection _ TEditSelection.Alloc[]; sel: ViewerTools.SelPos _ NARROW[data]; start, length: INT; [] _ TEditLocks.LockDocAndTdd[tdd, "SetTEditDocument", read]; IF sel=NIL THEN { IF tdd.tsInfo#NIL THEN { start _ TextNode.LocNumber[ at: TextNode.LastLocWithin[tdd.text], skipCommentNodes: TRUE]; length _ 0 } ELSE { start _ 0; length _ TextNode.LocNumber[ at: TextNode.LastLocWithin[tdd.text], skipCommentNodes: TRUE]-1 }; } ELSE { tiogaFile: BOOL _ (NodeProps.GetProp[tdd.text, $FromTiogaFile] = $Yes); start _ sel.start; IF ~tiogaFile THEN start _ start+1; -- hack to compensate for leading CR length _ sel.length }; tSel.start.pos _ TextNode.LocWithin[n: tdd.text, count: start, skipCommentNodes: TRUE]; tSel.end.pos _ TextNode.LocRelative[ location: tSel.start.pos, count: MAX[length-1, 0], skipCommentNodes: TRUE]; TEditLocks.UnlockDocAndTdd[tdd]; tSel.granularity _ IF length=0 THEN point ELSE char; tSel.viewer _ self; tSel.data _ tdd; tSel.insertion _ IF length=0 THEN before ELSE after; tSel.pendingDelete _ TRUE; tSel.looks _ TextLooks.noLooks; TEditSelection.MakeSelection[new: tSel]; TEditSelection.Free[tSel]; TEditRefresh.ScrollToEndOfSel[self, FALSE]; }; $ReadOnly => { [] _ TEditLocks.LockDocAndTdd[tdd, "SetTEditDocument", read]; self.tipTable _ readonlyTIP; tdd.readOnly _ TRUE; TEditLocks.UnlockDocAndTdd[tdd]; }; $ReadWrite => { [] _ TEditLocks.LockDocAndTdd[tdd, "SetTEditDocument", read]; self.tipTable _ tiogaTIP; tdd.readOnly _ FALSE; TEditLocks.UnlockDocAndTdd[tdd]; }; ENDCASE; }; ENDCASE; }; GetTEditDocument: ViewerClasses.GetProc = { data _ NIL; WITH self.data SELECT FROM tdd: TEditDocument.TEditDocumentData => SELECT op FROM NIL => { node: TextNode.RefTextNode = tdd.text.child; IF node#NIL AND node.last AND node.child=NIL THEN data _ node.rope ELSE data _ PutGet.WriteRopePlain[tdd.text]; }; $TiogaContents => { contents, formatting: Rope.ROPE; dataLen, count: INT; [dataLen, count, contents] _ PutGet.ToRope[tdd.text]; formatting _ Rope.Substr[base: contents, start: dataLen, len: count-dataLen]; contents _ Rope.Substr[base: contents, start: 0, len: dataLen]; data _ NEW[ViewerTools.TiogaContentsRec _ [contents, formatting]]; }; $SelChars => { rope: Rope.ROPE; -- hack to fix compiler problem DoSelChars: PROC [root: TextNode.RefTextNode, tSel: TEditDocument.Selection] = { SelConcat: PROC [node: TextNode.RefTextNode, start, len: TextNode.Offset] RETURNS [stop: BOOL] = { rope _ IF rope = NIL THEN Rope.Substr[node.rope, start, len] ELSE Rope.Cat[rope, "\n", Rope.Substr[node.rope, start, len]]; RETURN [FALSE]; }; IF tSel.viewer # NIL AND tSel.granularity # point THEN EditSpanSupport.Apply[[tSel.start.pos, tSel.end.pos], SelConcat]; IF rope=NIL THEN rope _ ""; }; TEditInputOps.CallWithLocks[DoSelChars, read]; data _ rope; }; $SelPos => { sel: ViewerTools.SelPos _ NEW[ViewerTools.SelPosRec]; DoSelPos: PROC [root: TextNode.RefTextNode, tSel: TEditDocument.Selection] = { sel.start _ TextNode.LocNumber[at: tSel.start.pos, skipCommentNodes: TRUE]; sel.length _ TextNode.LocOffset[ loc1: tSel.start.pos, loc2: tSel.end.pos, skipCommentNodes: TRUE] }; TEditInputOps.CallWithLocks[DoSelPos, read]; data _ sel; } ENDCASE; ENDCASE; }; DestroyTEditDocument: ViewerClasses.DestroyProc = { TEditDocument.ForgetViewer[self]; IF self.link # NIL THEN RETURN; -- linked, so not finished with document yet TRUSTED {Process.Detach[FORK CleanupAfterDestroy[self, self.file, NARROW[self.data]]] } }; CleanupAfterDestroy: PROC [self: ViewerClasses.Viewer, file: Rope.ROPE, tdd: TEditDocument.TEditDocumentData] = { root: TextNode.Ref; IF tdd = NIL THEN RETURN; -- anybody remember why this is here (SM)? [] _ SpinAndLock[tdd, "DestroyTEditDocument"]; root _ tdd.text; IF self.newVersion AND ~self.saveInProgress AND file # NIL THEN TEditDocumentPrivate.RecordUnsavedDocument[file, root] ELSE TEditInput.FreeTree[root]; Unlock[tdd] }; ChangeMenu: PROC [viewer: ViewerClasses.Viewer, subMenu: Menus.MenuEntry] = { menu: Menus.Menu _ viewer.menu; found: BOOL _ FALSE; numLines: Menus.MenuLine = Menus.GetNumberOfLines[menu]; newLines: Menus.MenuLine _ numLines; FOR i: Menus.MenuLine IN [1..numLines) DO IF Rope.Equal[Menus.GetLine[menu,i].name, subMenu.name] THEN { -- yes, so remove it FOR j: Menus.MenuLine IN (i..numLines) DO Menus.SetLine[menu, j-1, Menus.GetLine[menu, j]]; ENDLOOP; newLines _ newLines-1; found _ TRUE; EXIT }; ENDLOOP; IF ~found THEN { GoesBefore: PROC [m1, m2: Menus.MenuEntry] RETURNS [BOOL] = { Priority: PROC [m: Menus.MenuEntry] RETURNS [INTEGER] = { RETURN [SELECT TRUE FROM Rope.Equal[m.name, "Find"] => 1, Rope.Equal[m.name, "FirstLevelOnly"] => 0, ENDCASE => -1 -- unknown menu goes at bottom -- ] }; RETURN [Priority[m1] > Priority[m2]] }; newLast: Menus.MenuLine = MIN[numLines, LAST[Menus.MenuLine]]; newLines _ newLines+1; FOR i: Menus.MenuLine IN [1..numLines) DO IF GoesBefore[subMenu, Menus.GetLine[menu, i]] THEN { FOR j: Menus.MenuLine DECREASING IN (i..newLast] DO Menus.SetLine[menu, j, Menus.GetLine[menu, j-1]]; ENDLOOP; Menus.SetLine[menu, i, subMenu]; found _ TRUE; EXIT }; ENDLOOP; IF ~found THEN Menus.SetLine[menu, newLast, subMenu]; }; ViewerBLT.ChangeNumberOfLines[viewer, newLines]; }; LevelMenu: PUBLIC Menus.MenuProc = { ChangeMenu[NARROW[parent], levelMenu] }; FindMenu: PUBLIC Menus.MenuProc = { ChangeMenu[NARROW[parent], findMenu] }; unlocked: CONDITION; SpinAndLock: PUBLIC ENTRY PROC [tdd: TEditDocument.TEditDocumentData, who: Rope.ROPE, interrupt, defer: BOOL _ FALSE] RETURNS [ok: BOOL] = TRUSTED { ENABLE UNWIND => NULL; myProcess: PROCESS = LOOPHOLE[Process.GetCurrent[]]; IF myProcess#tdd.lockProcess THEN { IF interrupt THEN { IF defer AND tdd.interrupt > 0 THEN RETURN [FALSE]; tdd.interrupt _ tdd.interrupt+1 }; WHILE tdd.lock>0 DO WAIT unlocked; ENDLOOP; tdd.lockProcess _ myProcess; tdd.who _ who; -- save the first guy who got the lock IF interrupt THEN tdd.interrupt _ tdd.interrupt-1; }; tdd.lock _ tdd.lock+1; RETURN [TRUE]; }; Unlock: PUBLIC ENTRY PROC [tdd: TEditDocument.TEditDocumentData] = TRUSTED { ENABLE UNWIND => NULL; IF tdd.lockProcess # Process.GetCurrent[] THEN ERROR; IF (tdd.lock _ tdd.lock-1) = 0 THEN BROADCAST unlocked }; systemDir: ROPE ~ FSExtras.GetWDir[]; -- the BootEssentials live here SystemTip: PROC [base: ROPE] RETURNS [ROPE] ~ { RETURN [Rope.Cat[systemDir, base, ".tip"]]; }; ReloadTipTable: PUBLIC PROC = { newTIP: TIPUser.TIPTable _ ReloadTable[tiogaTIP, "TiogaTIP", SystemTip["Tioga"]]; IF newTIP # NIL THEN tiogaClass.tipTable _ tiogaTIP _ newTIP; }; ReloadReadonlyTipTable: PUBLIC PROC = { newTIP: TIPUser.TIPTable _ ReloadTable[readonlyTIP, "ReadonlyTiogaTIP", SystemTip["ReadonlyTioga"]]; IF newTIP # NIL THEN readonlyTIP _ newTIP; }; readonlyTIP: TIPUser.TIPTable; tiogaTIP: PUBLIC TIPUser.TIPTable; ChangeTipTables: PROC [newTIP, oldTIP: TIPUser.TIPTable] = { WithViewerTreeLocked: PROC ~ { changeTip: PROC [v: ViewerClasses.Viewer] RETURNS [BOOL _ TRUE] = { WITH v.data SELECT FROM tdd: TEditDocument.TEditDocumentData => { IF v.tipTable = oldTIP THEN v.tipTable _ newTIP; }; ENDCASE => NULL; ViewerOps.EnumerateChildren[v, changeTip]; }; typescriptClass: ViewerClasses.ViewerClass ~ ViewerOps.FetchViewerClass[$Typescript]; ViewerOps.EnumerateViewers[changeTip]; IF tiogaClass.tipTable = oldTIP THEN tiogaClass.tipTable _ newTIP; IF tiogaTIP = oldTIP THEN tiogaTIP _ newTIP; IF readonlyTIP = oldTIP THEN readonlyTIP _ newTIP; IF typescriptClass#NIL AND typescriptClass.tipTable = oldTIP THEN typescriptClass.tipTable _ newTIP; }; ViewerLocks.CallUnderViewerTreeLock[WithViewerTreeLocked]; }; ReloadTable: PUBLIC PROC [oldTIP: TIPUser.TIPTable, profileKey, default: Rope.ROPE] RETURNS [newTIP: TIPUser.TIPTable] = { ok: BOOL _ TRUE; AddTable: PROC [r: Rope.ROPE] = { bad: BOOL _ FALSE; t: TIPUser.TIPTable; msg: Rope.ROPE; IF ~ok THEN RETURN; IF Rope.Equal[r,"default",FALSE] THEN { TEditProfile.DoList["", AddTable, default]; RETURN }; t _ TIPUser.InstantiateNewTIPTable[r ! FS.Error => { bad _ TRUE; msg _ Rope.Concat["Cannot read TIP table file: ", r]; CONTINUE }; TIPUser.InvalidTable => { bad _ TRUE; msg _ Rope.Concat["Error(s) saved on TIP.Errors for: ", r]; CONTINUE }]; IF bad THEN { ok _ FALSE; MessageWindow.Append[msg, TRUE]; RETURN }; IF newTIP=NIL THEN { newTIP _ t; RETURN }; FOR x: TIPUser.TIPTable _ newTIP, x.link UNTIL x=NIL DO FOR y: TIPUser.TIPTable _ t, y.link UNTIL y=NIL DO IF x # y THEN LOOP; ok _ FALSE; MessageWindow.Append[Rope.Concat["Loop in TIP table layers caused by ", r], TRUE]; RETURN; ENDLOOP; ENDLOOP; FOR x: TIPUser.TIPTable _ newTIP, x.link UNTIL x.link=NIL DO REPEAT FINISHED => { newTIP.mouseTicks _ MIN[t.mouseTicks, newTIP.mouseTicks]; x.opaque _ FALSE; x.link _ t; }; ENDLOOP; }; TEditProfile.DoList[profileKey, AddTable, default]; IF ~ok AND oldTIP=NIL THEN { ok _ TRUE; TEditProfile.DoList["", AddTable, default] }; IF oldTIP # NIL AND newTIP # NIL THEN TRUSTED { Process.Detach[FORK ChangeTipTables[newTIP, oldTIP]]; }; }; alwaysInvalid: BOOL _ FALSE; LocalAdjust: ViewerClasses.AdjustProc = { IF self = NIL OR self.iconic OR self.destroyed OR self.paintingWedged THEN RETURN [FALSE]; WITH self.data SELECT FROM tdd: TEditDocument.TEditDocumentData => { ch: INTEGER _ self.ch; lines: TEditDocument.LineTable _ tdd.lineTable; IF lines # NIL THEN FOR i: INT IN [0..lines.lastLine] DO IF lines[i].valid THEN IF alwaysInvalid OR lines[i].yOffset >= ch THEN lines[i].valid _ FALSE; ENDLOOP; }; ENDCASE; RETURN [TRUE]; }; tiogaClass: ViewerClasses.ViewerClass _ NEW[ViewerClasses.ViewerClassRec _ [ paint: TEditImpl.PaintTEditDocument, bltV: top, -- use blt to copy screen contents to top of viewer when height changes bltH: none, -- but not if width changes notify: TEditImpl.TEditNotifyProc, modify: TEditSelection.InputModify, adjust: LocalAdjust, init: InitTEditDocument, set: SetTEditDocument, get: GetTEditDocument, save: SaveTEditDocument, destroy: DestroyTEditDocument, scroll: TEditScrolling.ScrollTEditDocument ]]; tiogaMenu: PUBLIC Menus.Menu _ Menus.CreateMenu[]; findMenu, levelMenu, lineMenu: PUBLIC Menus.MenuEntry; preReset: REF Menus.ClickProc = NEW[Menus.ClickProc _ TEditDocumentPrivate.PreReset]; preStore: REF Menus.ClickProc = NEW[Menus.ClickProc _ TEditDocumentPrivate.PreStore]; StyleKindClick: PUBLIC Menus.ClickProc = { TEditInput.InterpretAtom[NARROW[parent], SELECT mouseButton FROM red => $StyleKindScreen, yellow, blue => $StyleKindPrint, ENDCASE => ERROR]; }; StyleKindScreenOp: TEditInput.CommandProc = { old: REF ~ ViewerOps.FetchProp[viewer, $StyleKind]; IF old#NIL THEN { ViewerOps.AddProp[viewer, $StyleKind, NIL]; ViewerOps.PaintViewer[viewer: viewer, hint: client, clearClient: TRUE]; }; }; StyleKindPrintOp: TEditInput.CommandProc = { old: REF ~ ViewerOps.FetchProp[viewer, $StyleKind]; IF old#$Print THEN { ViewerOps.AddProp[viewer, $StyleKind, $Print]; ViewerOps.PaintViewer[viewer: viewer, hint: client, clearClient: TRUE]; }; }; TEditInput.Register[$StyleKindPrint, StyleKindPrintOp]; TEditInput.Register[$StyleKindScreen, StyleKindScreenOp]; Menus.AppendMenuEntry[menu: tiogaMenu, entry: Menus.CreateEntry[name: "Clear", proc: TEditDocumentPrivate.Clear --, guarded: TRUE, documentation: preClear--]]; Menus.AppendMenuEntry[menu: tiogaMenu, entry: Menus.CreateEntry[name: "Reset", proc: TEditDocumentPrivate.Reset, guarded: TRUE, documentation: preReset]]; Menus.AppendMenuEntry[menu: tiogaMenu, entry: Menus.CreateEntry[name: "Get", proc: TEditDocumentPrivate.Get --, guarded: TRUE, documentation: preGet--]]; Menus.AppendMenuEntry[menu: tiogaMenu, entry: Menus.CreateEntry[name: "GetImpl", proc: TEditDocumentPrivate.GetImpl --,guarded: TRUE, documentation: preGetImpl--]]; Menus.AppendMenuEntry[menu: tiogaMenu, entry: Menus.CreateEntry[name: "PrevFile", proc: TEditDocumentPrivate.PreviousFile --,guarded: TRUE, documentation: preLoadPrevious--]]; Menus.AppendMenuEntry[menu: tiogaMenu, entry: Menus.CreateEntry[name: "Store", proc: TEditDocumentPrivate.Store, guarded: TRUE, documentation: preStore]]; Menus.AppendMenuEntry[menu: tiogaMenu, entry: Menus.CreateEntry[name: "Save", proc: TEditDocumentPrivate.Save --, guarded: TRUE, documentation: preSave--]]; Menus.AppendMenuEntry[tiogaMenu, Menus.CreateEntry["Time", TEditDocumentPrivate.Time]]; Menus.AppendMenuEntry[tiogaMenu, Menus.CreateEntry["Split", TEditDocumentPrivate.Split]]; Menus.AppendMenuEntry[tiogaMenu, Menus.CreateEntry["Places", FindMenu]]; Menus.AppendMenuEntry[tiogaMenu, Menus.CreateEntry["Levels", LevelMenu]]; Menus.InsertMenuEntry[tiogaMenu, Menus.CreateEntry["StyleKind", StyleKindClick], 1]; Menus.InsertMenuEntry[tiogaMenu, Menus.CreateEntry["Reselect", TEditDocumentPrivate.Reselect], 1]; Menus.InsertMenuEntry[tiogaMenu, Menus.CreateEntry["PrevPlace", TEditDocumentPrivate.JumpToPrevious], 1]; Menus.InsertMenuEntry[tiogaMenu, Menus.CreateEntry["Normalize", TEditDocumentPrivate.Normalize], 1]; Menus.InsertMenuEntry[tiogaMenu, Menus.CreateEntry["Position", TEditDocumentPrivate.Position], 1]; Menus.InsertMenuEntry[tiogaMenu, Menus.CreateEntry["Def", TEditDocumentPrivate.FindDef], 1]; Menus.InsertMenuEntry[tiogaMenu, Menus.CreateEntry["Word", TEditDocumentPrivate.FindWord], 1]; Menus.InsertMenuEntry[tiogaMenu, Menus.CreateEntry["Find", TEditDocumentPrivate.Find], 1]; findMenu _ Menus.GetLine[tiogaMenu, 1]; Menus.SetLine[tiogaMenu, 1, NIL]; Menus.InsertMenuEntry[tiogaMenu, Menus.CreateEntry["AllLevels", TEditDocumentPrivate.AllLevels], 1]; Menus.InsertMenuEntry[tiogaMenu, Menus.CreateEntry["FewerLevels", TEditDocumentPrivate.FewerLevels], 1]; Menus.InsertMenuEntry[tiogaMenu, Menus.CreateEntry["MoreLevels", TEditDocumentPrivate.MoreLevels], 1]; Menus.InsertMenuEntry[tiogaMenu, Menus.CreateEntry["FirstLevelOnly", TEditDocumentPrivate.FirstLevelOnly], 1]; levelMenu _ Menus.GetLine[tiogaMenu, 1]; Menus.SetLine[tiogaMenu, 1, NIL]; Menus.ChangeNumberOfLines[tiogaMenu, 1]; -- only show the top level to start ReloadTipTable[]; ReloadReadonlyTipTable[]; ViewerOps.RegisterViewerClass [$QueryText, tiogaClass]; [] _ Buttons.Create[info: [name: "New"], proc: TEditDocumentPrivate.NewButton, fork: FALSE]; [] _ Buttons.Create[info: [name: "Open"], proc: TEditDocumentPrivate.OpenButton]; END. èQueryTEditDocumentsImpl.mesa Copyright Ó 1985, 1986, 1987 by Xerox Corporation. All rights reserved. Michael Plass, July 19, 1985 2:18:22 pm PDT Russ Atkinson (RRA) August 19, 1985 4:07:47 pm PDT Doug Wyatt, January 26, 1987 12:19:48 pm PST Doug Terry, April 9, 1987 1:51:13 pm PDT make sure another link didn't already init and if so, copy that data somebody else already did the init bad data old heuristic: IF HasBrackets[self.file] THEN ViewerTools.InhibitUserEdits[self] ELSE lock so no edits while saving We want to kill off selections so we don't lock up the world while saving. Save the file. Unlock the document if it was locked to begin with. Returns true if the file on the disk has a more recent create date than the root file create date. RRA sez that this should never happen in the wonderful world of Cedar 5.0. [self: ViewerClasses.Viewer, data: REF ANY, finalise: BOOL _ TRUE, op: ATOM _ NIL] reuse rather than reallocate Should really have a write lock on the document for this. change for Tioga2. Need a repaint no iconic selections please for typescripts, NIL => caret at end includes 1 for root, so must subtract 1 for other text viewers, NIL => entire contents includes 1 for root, so must subtract 1 [self: ViewerClasses.Viewer, op: ATOM _ NIL] RETURNS [data: REF ANY] simple case of only one node this also fixes up the Root => Viewer mapping if necessary Need to pass self.file as variable because it will be set to NIL see if already showing the submenu Menus.ChangeNumberOfLines[menu, newLast-1]; add it. do insertion sort to get it in the right place higher priority means goes above in series of submenus looks at rope for first item to identify the subMenu. put it here Would really like to enumerate viewer classes here . . . try the default by itself [self: ViewerClasses.Viewer] RETURNS [adjusted: BOOL _ FALSE] tipTable set below preSave: REF Menus.ClickProc = NEW[Menus.ClickProc _ PreSave]; preClear: REF Menus.ClickProc = NEW[Menus.ClickProc _ PreClear]; preLoadPrevious: REF Menus.ClickProc = NEW[Menus.ClickProc _ PreLoadPrevious]; preGet: REF Menus.ClickProc = NEW[Menus.ClickProc _ PreGet]; preGetImpl: REF Menus.ClickProc = NEW[Menus.ClickProc _ PreGetImpl]; first row Stuff for StyleKind button (should live in TEditDocuments3Impl, but I didn't want to change or add interfaces.  MFP) Menu creation build the places menu StyleKind in the places menu is flakey, but there's room build the levels menu don't fork since will change the selection; want to capture following typein ʘcodešœ™KšœH™HKšœ+™+K™2Kšœ,™,K™(—K™šÏk ˜ Kšœœ ˜Kšœœ˜Kšœœ ˜Kšœœ>˜FKšœ œ ˜Kšœœ¦˜±Kšœœ˜+Kšœ œ˜-Kšœœ˜#KšœœG˜SKšœœ4œ˜TKšœ œ˜'Kšœœr˜…Kšœœ”˜®Kšœ œ'˜6Kšœ œ2˜BKšœœ˜$Kšœ œ0˜@Kšœ œ ˜Kšœ œ˜&Kšœœ˜+Kšœœ+˜?Kšœ œ˜ Kšœ œ˜'Kšœ œ ˜Kšœ œz˜ˆKšœ œÏc˜+Kšœœ2˜?Kšœ œ ˜Kšœ œ˜&Kšœœy˜ŒKšœœ ˜ Kšœ œ˜,Kšœ œƒ˜’Kšœ œG˜X—K˜šÐblœœ˜&Kšœ$œÛ˜ˆKšœ=˜DKšœ˜Kšœ˜K˜Kšœœœ˜Kšœœœœž/˜Ušœœ˜4Kšœœœ ˜Kšœ œ˜K˜K˜K˜—š Ïn œœœ$œœ˜JKšœ(œ˜EK˜—K˜š  œœœ$œœœ˜eKšœ'œ ˜9K˜š  œœ˜Kšœ œœ˜5Kšœ œ˜šœœœ˜Kš œ œœœœ œ˜GK˜—šœœœ˜Kšœ œ˜'˜"Kšœœœ˜.˜KšœJœ˜PKšœ œ˜'K˜Kšœ˜ K˜—K˜—K˜—šœ œœ˜K˜7K˜—K˜—K˜š  œœ˜Kšœ2œœ˜OK˜K˜:K˜—K˜šœ œœ˜Kšœ*™*Kšœ™Kšœ"œ˜&Kš œœœœ žM˜~K˜'šœ-œ˜?Kšœœœ˜,Kšœ˜—šœ ˜Kšœ˜šœ˜Kšœ"™"Kšœ,œ˜CK˜K˜——K˜K˜—šœœœœ˜Kšœœœ&˜5K˜'K˜K˜K˜—šœœœ˜˜'K˜K˜'K˜K˜K˜—˜Kšœœœ&˜5K˜'K˜K˜K˜—šœœ˜Kšœœœ&˜5K˜'K˜6K˜K˜—šœœœ˜Kšœœœ&˜5K˜'K˜HK˜K˜—šœ˜ Kšœ™Kšœœœ&˜5K˜'K˜&K˜K˜——K˜1KšœU™UK˜"K˜ K˜—K˜š œœœ+˜nKšœœ%˜.šœž7˜9Kšœ œœ0˜CKšœ%œ'˜OKšœ,˜,Kšœ˜K˜—Kš œœ œœ$œ˜YK˜K˜—Kšœœ˜š œœ˜4Kšœ'œ ˜9K˜Kšœœ ˜Kšœœœ˜K˜šœœ˜Kšœ œ,˜@šœ˜Kšœ˜Kšœ)˜)K˜Kšœ˜—K˜—K˜šœ˜Kšœ2˜7—K˜šœ˜ šœ˜Kšœ™K˜˜*KšœJ™J—Kšœ,ž'˜SK˜Kšœ ž5˜BK˜6K˜—Kšœ˜—K˜Kšœ™˜Kšœœ.œ˜BKšœ œ.˜>Kš œœ œ4œ œ˜tKšœ œœ˜+Kšœ œ ˜-K˜ šœ(˜-K˜K˜šœ˜Kšœ œ˜Kšœ˜—Kšœ˜—K˜—K™Kšœ3™3Kšœœ˜'Kšœœœœ)˜GK˜—K˜š  œœœœœ˜7Kšœ3˜9K˜—K˜š  œœœ!œœœ˜VKšœ®™®Kšœœ˜K˜—K˜Kšœ3œ˜8•StartOfExpansionV -- [self: ViewerClasses.Viewer, data: REF ANY, finalise: BOOL _ TRUE, op: ATOM _ NIL]˜+KšÐckR™Ršœœ˜šœ œ˜šœ)˜)šœ˜šœ:˜=K˜#Kšœ œ˜Kš œ œœœž˜3K˜*K˜*šœ˜šœ˜K˜&K˜"Kšœ œ˜#Kš œœœœœœ ˜CKš œœœœœœ˜-š œœœ œ ˜/šœ˜Kšœ™š   œœœ œœœ˜=Kšœœœœœœœ˜’Kšœœ˜K˜—K˜KšœM™MK˜K˜BK˜&Kšœœ˜1Kšœœ˜>Kšœ+œœ˜9K˜—šœ˜Kšœœ˜šœœ˜ K˜*K˜,K˜—K˜K˜9šœœ˜ Kšœœœ.˜@Kšœ œœ0˜CK˜!K˜—K˜——K˜—šœ˜Kšœ"œ˜/K˜3K˜K˜!K˜—šœ˜Kšœœ˜*K˜K˜K˜—Kšœ˜—K˜K˜:K˜1Kšœœž˜,K˜ šœ œ˜Kšœ™Kšœ$œœ˜IK˜—K˜—šœ ˜ šœœœ˜+Kšœ™K˜7Kšœœ˜'Kšœœ˜K˜=šœœœ˜šœ œœ˜Kšœœ™$šœ˜Kšœ'™'Kšœ8œ˜>—K˜ K˜—šœ˜Kšœœ™.K˜ šœ˜Kšœ'™'Kšœ8œ˜?—K˜—K˜—šœ˜Kšœ œ8˜GK˜Kšœ œž$˜IK˜K˜—KšœQœ˜W˜$Kšœ!œ!œ˜K—K˜ Kšœœ œœ˜4K˜K˜Kšœœ œœ˜4Kšœœ˜K˜K˜(K˜Kšœ$œ˜+K˜——šœ˜K˜=K˜Kšœœ˜K˜ K˜—šœ˜K˜=K˜Kšœœ˜K˜ K˜—Kšœ˜—K˜—Kšœ˜——K˜—K˜–H -- [self: ViewerClasses.Viewer, op: ATOM _ NIL] RETURNS [data: REF ANY]˜+Kš¡D™DKšœœ˜ šœ œ˜šœ'˜'šœ˜šœ˜K˜,š œœœ œ ˜,šœ˜Kšœ™—Kšœ)˜-—K˜—šœ˜Kšœœ˜ Kšœœ˜K˜5K˜MK˜?Kšœœ8˜BK˜—šœ˜Kšœ œž˜0š  œœ@˜Pš  œœ;œœ˜bšœœ˜Kšœ#˜'Kšœ:˜>—Kšœœ˜K˜—Kšœœœœ˜7K˜AKšœœœ ˜K˜—K˜.Kšœ ˜ K˜—šœ˜Kšœœ˜5š œœ@˜NKšœEœ˜K˜ Kšœ<œ˜B—K˜—K˜,Kšœ ˜ K˜—Kšœ˜—Kšœ˜——K˜—K˜˜3šœ!˜!Kšœ:™:—Kš œ œœœž,˜LKšœœ&œ˜WK˜K˜—š œœ)œ+˜qKšœ@™@K˜Kš œœœœž*˜DK˜.K˜Kš œœœœ˜?K˜6Kšœ˜K˜ K˜K˜—š  œœ=˜MK˜Kšœœœ˜K˜8K˜$šœœ˜)Kšœ"™"šœ6œž˜Sšœœ˜)K˜1Kšœ˜—Kšœ+™+K˜Kšœœœ˜K˜—Kšœ˜—šœœ˜Kšœ7™7š  œœœœ˜=š œœœœ˜9Kšœ6™6Kšœ5™5šœœœ˜K˜ K˜*Kšœž!œ˜2—K˜—Kšœ˜%K˜—Kšœœ œ˜>K˜šœœ˜)šœ-œ˜5Kšœ ™ šœ œœ˜3Kšœ2œ˜:—K˜ Kšœœœ˜K˜—Kšœ˜—Kšœœ'˜5K˜—K˜0K˜—K˜Kšœ œœ˜MKšœ œœ˜KKšœ œ˜š  œœœœ2œœœœœœ˜”Kšœœœ˜Kšœ œœ˜4šœœ˜#šœ œ˜Kš œœœœœ˜3K˜ K˜—Kšœ œœ œ˜+K˜Kšœž'˜6Kšœ œ!˜2K˜—K˜Kšœœ˜K˜—K˜š  œœœœ*œ˜LKšœœœ˜Kšœ(œœ˜5Kšœœ œ ˜7K˜—K˜Kšœ œž˜Eš   œœœœœ˜/Kšœ%˜+K˜—K˜š œœœ˜K˜QKšœ œœ)˜=K˜—K˜š œœœ˜'˜K˜I—Kšœ œœ˜*K˜—K˜K˜Kšœ œ˜"š œœ'˜<š œœ˜š œ œœœœ˜Cšœœ˜˜)Kšœœ˜0K˜—Kšœœ˜—K˜*K˜—KšœU˜UK˜&™8Kšœœ˜BKšœœ˜,Kšœœ˜2Kšœœœ#œ#˜d—K˜—K˜:K˜—K˜š   œœœ6œœ˜zKšœœœ˜š œœ œ˜!Kšœœœ˜K˜Kšœ œ˜Kšœœœ˜šœœœ˜'K˜+Kšœ˜K˜—˜$˜šœ ˜ Kšœœ˜ K˜5Kš˜K˜—˜Kšœœ˜ K˜;Kš˜K˜———Kš œœœœœ˜DKšœœœœ˜*šœ&œœ˜7šœ!œœ˜2Kšœœœ˜Kšœœ˜ KšœLœ˜RKšœ˜Kšœ˜—Kšœ˜—šœ&œœ˜<šœœ˜Kšœœ"˜9Kšœ œ˜K˜ K˜—Kšœ˜—K˜—K˜3šœœœœ˜Kšœ™Kšœœ-˜6K˜—š œ œœ œœœ˜/Kšœœ"˜5K˜—K˜K˜—K–A -- [self: ViewerClasses.Viewer] RETURNS [adjusted: BOOL _ FALSE]šœœœ˜šœ)˜)Kš¡=™=K–w[viewer: ViewerClasses.Viewer, hint: ViewerOps.PaintHint, clearClient: BOOL _ TRUE, whatChanged: REF ANY _ NIL]šœœœ œœœœœ˜Zšœ œ˜˜)Kšœœ ˜Kšœ/˜/šœ œ˜šœœœ˜$šœ˜šœœ˜/Kšœœ˜——Kšœ˜——K˜—Kšœ˜—Kšœœ˜K˜K˜—šœ(œ!˜LK˜$Kšœ žG˜RKšœ ž˜'K˜"K˜#K˜K˜K˜K˜K˜K˜K˜*Kšœ™K˜—K˜Kšœ œ!˜2K˜Kšœœ˜6Kšœ>™>Kšœ œœ2˜UKšœ@™@Kšœ œœ2˜UKšœN™NKšœ<™