<<-- TEditDocuments2Impl.mesa; Edited by Paxton on December 29, 1982 9:27 am>> <<-- Edited by McGregor on September 10, 1982 1:53 pm>> <> <> DIRECTORY CIFS USING [Error, Open, OpenFile, Close, GetPathname, read], Menus USING [Menu, MenuEntry, MenuProc, SetLine], MessageWindow USING [Append, Blink, Clear], NodeProps USING [GetProp, PutProp, Register, NullRead, NullWrite, NullCopy], Process USING [Detach], Rope USING [Concat, Equal, Fetch, Find, ROPE, Size, Substr], RopeEdit USING [BlankChar, IllegalChar], RTMiniModel USING [ImplementorName], TextEdit USING [Size], TextNode USING [FirstChild, LocNumber, Location, LocWithin, NarrowToTextNode, nullLocation, Offset, pZone, Ref, RefTextNode, Root], TEditDisplay USING [EstablishLine], TEditDocument USING [LineTableRec, maxClip, Selection, SpinAndLock, TEditDocumentData, Unlock], TEditDocumentPrivate, TEditInput USING [FreeTree], TEditInputOps USING [WaitForInsertToFinish], TEditOps, TEditProfile USING [DefaultMenuChoice, menu1, menu2, menu3, openFirstLevelOnly, sourceExtensions, implExtensions], TEditSelection USING [FindRope, LockSel, MakeSelection, pSel, sSel, fSel, UnlockSel], ViewerOps USING [AddProp, CloseViewer, ComputeColumn, CreateViewer, DestroyViewer, EstablishViewerPosition, FetchProp, MoveBelowViewer, OpenIcon, PaintHint, PaintViewer, SaveViewer, SetMenu], ViewerClasses USING [GetProc, Viewer, ViewerClass, ViewerClassRec], ViewerTools USING [GetContents, GetSelectionContents, SelPos, SelPosRec, SetSelection], VirtualDesktops USING [FindViewer]; TEditDocuments2Impl: CEDAR MONITOR IMPORTS CIFS, Menus, MessageWindow, NodeProps, Process, Rope, RopeEdit, RTMiniModel, TEditDocument, TEditDocumentPrivate, TextEdit, TextNode, TEditDisplay, TEditInput, TEditInputOps, TEditProfile, TEditSelection, ViewerOps, ViewerTools, VirtualDesktops EXPORTS TEditDocument, TEditDocumentPrivate, TEditOps SHARES ViewerClasses = BEGIN OPEN Rope, TEditDocument, TEditDocumentPrivate, ViewerClasses; ForceInitialCaret: PROC [viewer: Viewer] = INLINE {ViewerTools.SetSelection[viewer, initialCaret]}; initialCaret: ViewerTools.SelPos _ NEW[ViewerTools.SelPosRec]; CancelLinks: PUBLIC PROC [viewer: Viewer] = BEGIN ForgetViewer[viewer]; IF viewer.link.link=viewer THEN BEGIN viewer.link.link _ NIL; ViewerOps.PaintViewer[viewer.link, caption]; END ELSE FOR v: Viewer _ viewer.link.link, v.link UNTIL v.link=viewer DO REPEAT FINISHED => v.link _ viewer.link; ENDLOOP; viewer.link _ NIL; END; lastRoot: TextNode.Ref; lastViewer: ViewerClasses.Viewer; RecordViewerForRoot: PUBLIC ENTRY PROC [viewer: ViewerClasses.Viewer, root: TextNode.Ref] = { ENABLE UNWIND => NULL; RecordViewerForRootI[viewer, root] }; RecordViewerForRootI: INTERNAL PROC [viewer: ViewerClasses.Viewer, root: TextNode.Ref] = { NodeProps.PutProp[root,$Viewer,viewer]; IF root = lastRoot THEN lastViewer _ viewer; -- keep the cache up to date }; ForgetViewer: PUBLIC ENTRY PROC [viewer: ViewerClasses.Viewer] = { ENABLE UNWIND => NULL; tdd: TEditDocument.TEditDocumentData = NARROW[viewer.data]; root: TextNode.Ref; IF tdd=NIL THEN RETURN; root _ tdd.text; IF GetViewerForRootI[root] # viewer THEN RETURN; IF viewer.link # NIL THEN { -- change to a linked viewer RecordViewerForRootI[viewer.link,root]; RETURN }; RecordViewerForRootI[NIL,root] }; GetViewerForRoot: PUBLIC ENTRY PROC [root: TextNode.Ref] RETURNS [viewer: ViewerClasses.Viewer] = { ENABLE UNWIND => NULL; RETURN [GetViewerForRootI[root]] }; GetViewerForRootI: INTERNAL PROC [root: TextNode.Ref] RETURNS [viewer: ViewerClasses.Viewer] = { IF root = NIL THEN RETURN [NIL]; IF root = lastRoot THEN RETURN [lastViewer]; lastRoot _ root; RETURN [lastViewer _ NARROW[NodeProps.GetProp[root,$Viewer]]] }; LookupDirectoryName: PROC [file: Rope.ROPE] RETURNS [fullName: Rope.ROPE] = BEGIN fh: CIFS.OpenFile _ CIFS.Open[file, CIFS.read]; fullName _ CIFS.GetPathname[fh]; CIFS.Close[fh]; IF fullName=NIL THEN fullName _ file; -- temp hack until CIFS bug is fixed. IF Rope.Find[fullName,"/local/",0,FALSE]=0 THEN -- delete it from start of name fullName _ Rope.Substr[fullName, Rope.Size["/local/"]]; END; GetDirectoryName: PROC [file: Rope.ROPE] RETURNS [directoryName: Rope.ROPE, new: BOOL] = { new _ FALSE; IF Rope.Size[file]=0 THEN RETURN [NIL,TRUE]; directoryName _ LookupDirectoryName[file ! CIFS.Error => {directoryName _ file; new _ TRUE; CONTINUE}] }; PreStore: PUBLIC Menus.MenuProc = { -- called when Store menu item becomes unguarded new: BOOL; fileName: Rope.ROPE _ ViewerTools.GetSelectionContents[]; IF Rope.Size[fileName]=0 THEN {PleaseSelectFileName[]; RETURN}; IF ~CheckFileName[fileName] THEN RETURN; [fileName, new] _ GetDirectoryName[fileName]; MessageWindow.Append[Rope.Concat["Confirm Store to file: ", Rope.Concat[fileName, IF new THEN " [New File]" ELSE " [Old File]"]], TRUE] }; StoreFile: PUBLIC PROC [parent: ViewerClasses.Viewer] = { DoStoreFile[parent,NIL] }; DoStoreFile: PUBLIC PROC [parent: ViewerClasses.Viewer, fileName: Rope.ROPE _ NIL] = BEGIN new, linked: BOOL; tdd: TEditDocumentData; IF fileName=NIL THEN fileName _ ViewerTools.GetSelectionContents[]; IF Rope.Size[fileName]=0 THEN {PleaseSelectFileName[]; RETURN}; IF ~CheckFileName[fileName] THEN RETURN; [fileName, new] _ GetDirectoryName[fileName]; IF VirtualDesktops.FindViewer[fileName].viewer # NIL THEN { -- already loaded MessageWindow.Append[ Rope.Concat[fileName, " is already in a viewer! Cannot Store to that name."], TRUE]; MessageWindow.Blink; RETURN }; tdd _ NARROW[parent.data]; IF tdd = NIL THEN RETURN; [] _ SpinAndLock[tdd, "DoStoreFile"]; IF parent.file # NIL THEN SaveLoadHistory[parent]; IF linked _ (parent.link#NIL) THEN CancelLinks[parent]; -- remove viewer from link chain parent.name _ parent.file _ fileName; NodeProps.PutProp[tdd.text, $FileCreateDate, NIL]; -- remove so Save won't test Unlock[tdd]; ViewerOps.SaveViewer[parent]; IF linked THEN { -- copy tdd.text data structure loc: TextNode.Offset; KillSelections[parent]; [] _ SpinAndLock[tdd, "DoStoreFile2"]; loc _ TextNode.LocNumber[tdd.lineTable.lines[0].pos]; tdd.text _ NIL; -- so InitViewerDoc won't free it InitViewerDoc[parent, NIL]; IF ~PositionViewer[parent,TextNode.LocWithin[tdd.text,loc],all] THEN TRUSTED {Process.Detach[FORK PaintAndRemember[parent]]}; Unlock[tdd] }; END; KillSelections: PROC [parent: ViewerClasses.Viewer] = { OPEN TEditSelection; IF pSel # NIL AND pSel.viewer = parent THEN MakeSelection[selection: primary]; IF sSel # NIL AND sSel.viewer = parent THEN MakeSelection[selection: secondary]; IF fSel # NIL AND fSel.viewer = parent THEN MakeSelection[selection: feedback] }; EmptyViewer: PUBLIC PROC [parent: ViewerClasses.Viewer] = BEGIN WITH parent.data SELECT FROM tdd: TEditDocument.TEditDocumentData => { TEditSelection.LockSel[primary, "EmptyViewer"]; { ENABLE UNWIND => TEditSelection.UnlockSel[primary]; prop: REF LoadHistory; [] _ SpinAndLock[tdd, "EmptyViewer"]; KillSelections[parent]; SaveLoadHistory[parent]; prop _ NARROW[ViewerOps.FetchProp[parent, $LoadHistory]]; -- hang onto it IF parent.link#NIL THEN CancelLinks[parent] ELSE IF parent.newVersion AND ~parent.saveInProgress AND parent.file # NIL THEN RecordUnsavedDocument[parent.file, tdd.text] ELSE TEditInput.FreeTree[tdd.text]; parent.name _ "No Name"; parent.file _ NIL; parent.newVersion _ parent.newFile _ FALSE; tdd.text _ NIL; -- so InitViewerDoc won't free it InitViewerDoc[parent,NIL]; Unlock[tdd]; ClearPositionHistory[parent]; ViewerOps.AddProp[parent, $LoadHistory, prop]; -- restore file history ViewerOps.PaintViewer[parent, all]; ForceInitialCaret[parent] }; TEditSelection.UnlockSel[primary]; }; ENDCASE; END; PleaseSelectFileName: PROC = { MessageWindow.Append["Please select file name.", TRUE]; MessageWindow.Blink[] }; CheckFileName: PROC [directoryName: Rope.ROPE] RETURNS [BOOLEAN] = { FOR i:NAT IN [0..Rope.Size[directoryName]) DO char: CHAR _ Rope.Fetch[directoryName, i]; IF RopeEdit.BlankChar[char] OR RopeEdit.IllegalChar[char] THEN { MessageWindow.Append["Illegal file name", TRUE]; MessageWindow.Blink[]; RETURN [FALSE] }; ENDLOOP; RETURN [TRUE] }; UnknownFile: PROC [directoryName: Rope.ROPE] = { MessageWindow.Append[directoryName, TRUE]; MessageWindow.Append[" not found."]; MessageWindow.Blink[]; RETURN}; CheckName: PROC [name, ext: Rope.ROPE] RETURNS [file: Rope.ROPE, fileExists: BOOL] = { fileExists _ TRUE; file _ Rope.Concat[name, ext]; file _ LookupDirectoryName[file ! CIFS.Error => { fileExists _ FALSE; CONTINUE }] }; GetNameAndSearchRope: PROC [ sel: Rope.ROPE, fileNameProcViewer: ViewerClasses.Viewer] RETURNS [file, search: Rope.ROPE] = { name: Rope.ROPE; dot, extSize: INT; fileExists, standard, noDot: BOOL _ FALSE; MessageWindow.Append[Rope.Concat["Directory lookup for ", sel], TRUE]; [file, fileExists] _ CheckName[sel, NIL]; IF fileExists THEN RETURN; IF (dot _ Rope.Find[sel, "."]) < 0 THEN { -- no dot in selection FOR lst: LIST OF Rope.ROPE _ TEditProfile.sourceExtensions, lst.rest UNTIL lst=NIL DO [file, fileExists] _ CheckName[sel, lst.first]; IF fileExists THEN RETURN; ENDLOOP; noDot _ TRUE; name _ sel; search _ NIL } ELSE { name _ Rope.Substr[sel, 0, dot]; -- the text before the "." search _ Rope.Substr[sel, dot+1]; -- the text after the "." extSize _ Rope.Size[search]+1; FOR lst: LIST OF Rope.ROPE _ TEditProfile.sourceExtensions, lst.rest UNTIL lst=NIL DO IF Rope.Size[lst.first]=extSize AND Rope.Find[lst.first, search, 1, FALSE]=1 THEN { standard _ TRUE; EXIT }; -- this is one of the standard extensions ENDLOOP; }; IF fileNameProc # NIL THEN { srch: Rope.ROPE; [file, srch] _ fileNameProc[sel, fileNameProcViewer]; IF file # NIL THEN RETURN [file, srch] }; IF ~standard AND ~noDot THEN -- try from the list of standard extensions FOR lst: LIST OF Rope.ROPE _ TEditProfile.sourceExtensions, lst.rest UNTIL lst=NIL DO [file, fileExists] _ CheckName[name, lst.first]; IF fileExists THEN RETURN; ENDLOOP; file _ sel; search _ NIL }; fileNameProc: PROC [Rope.ROPE, ViewerClasses.Viewer] RETURNS [fileName: Rope.ROPE, search: Rope.ROPE] _ NIL; RegisterFileNameProc: PUBLIC PROC [proc: PROC [Rope.ROPE, ViewerClasses.Viewer] RETURNS [fileName: Rope.ROPE, search: Rope.ROPE]] = { fileNameProc _ proc }; GetImplNameAndSearchRope: PROC [sel: Rope.ROPE] RETURNS [impl, search: Rope.ROPE] = { name, defsName: Rope.ROPE; dot: INT; fileExists: BOOL; IF (dot _ Rope.Find[sel, "."]) < 0 THEN { defsName _ sel; search _ NIL } ELSE { defsName _ Rope.Substr[sel, 0, dot]; search _ Rope.Substr[sel, dot+1] }; IF Rope.Size[search] > 0 THEN { MessageWindow.Append[Rope.Concat["Model lookup for implementor of ", search], TRUE]; name _ RTMiniModel.ImplementorName[defsName, search] }; IF name=NIL THEN name _ Rope.Concat[defsName, "Impl"]; MessageWindow.Append[Rope.Concat["Directory lookup for ", name], TRUE]; FOR lst: LIST OF Rope.ROPE _ TEditProfile.implExtensions, lst.rest UNTIL lst=NIL DO [impl, fileExists] _ CheckName[name, lst.first]; IF fileExists THEN RETURN; ENDLOOP; RETURN [name, NIL] }; DoSearch: PROC [v: Viewer, search: Rope.ROPE] = { -- search for definition tdd: TEditDocument.TEditDocumentData _ NARROW[v.data]; loc: TextNode.Location; IF tdd = NIL OR Rope.Size[search] = 0 THEN RETURN; -- forget it IF (loc _ TextNode.LocWithin[tdd.text,0]) # tdd.lineTable.lines[0].pos THEN { TEditDisplay.EstablishLine[tdd, loc]; ViewerOps.PaintViewer[v, client] }; -- always search from start TEditSelection.FindRope[ viewer: v, rope: search, case: FALSE, word: TRUE, def: TRUE, id: feedback]; }; CopyPositionHistory: PUBLIC PROC [from, to: Viewer] = { old: REF PositionHistory _ NARROW[ViewerOps.FetchProp[from, $PositionHistory]]; new: REF PositionHistory _ NARROW[ViewerOps.FetchProp[to, $PositionHistory]]; IF old=NIL THEN RETURN; IF new=NIL THEN { new _ TextNode.pZone.NEW[PositionHistory]; ViewerOps.AddProp[to, $PositionHistory, new] }; new^ _ old^; }; ClearPositionHistory: PROC [viewer: Viewer] = { prop: REF PositionHistory _ NARROW[ViewerOps.FetchProp[viewer, $PositionHistory]]; IF prop = NIL THEN RETURN; prop.pos _ prop.prev _ TextNode.nullLocation; }; RememberCurrentPosition: PUBLIC PROC [viewer: Viewer] = { tdd: TEditDocument.TEditDocumentData _ NARROW[viewer.data]; prop: REF PositionHistory _ NARROW[ViewerOps.FetchProp[viewer, $PositionHistory]]; loc: TextNode.Location; IF tdd=NIL THEN RETURN; IF prop = NIL THEN { prop _ TextNode.pZone.NEW[PositionHistory]; ViewerOps.AddProp[viewer, $PositionHistory, prop] }; [] _ SpinAndLock[tdd, "RememberCurrentPosition"]; loc _ tdd.lineTable.lines[0].pos; Unlock[tdd]; IF loc = prop.pos THEN RETURN; prop.prev _ prop.pos; prop.pos _ loc }; CheckPosition: PROC [viewer: Viewer, loc: TextNode.Location] RETURNS [good: BOOLEAN, goodloc: TextNode.Location] = { root, node: TextNode.Ref; t1: TextNode.RefTextNode; tdd: TEditDocument.TEditDocumentData; IF viewer=NIL OR viewer.destroyed OR (node _ loc.node)=NIL THEN GOTO Failed; IF (tdd _ NARROW[viewer.data]) = NIL THEN GOTO Failed; IF (root _ tdd.text)=NIL THEN GOTO Failed; IF TextNode.Root[node] # root THEN GOTO Failed; -- make sure still in the tree IF (t1 _ TextNode.NarrowToTextNode[node])=NIL OR loc.where NOT IN [0..TextEdit.Size[t1]] THEN RETURN [TRUE, [node,0]]; RETURN [TRUE,loc]; EXITS Failed => RETURN [FALSE, TextNode.nullLocation]; }; PositionViewer: PUBLIC PROC [viewer: Viewer, loc: TextNode.Location, hint: ViewerOps.PaintHint _ client] RETURNS [ok: BOOLEAN] = { tdd: TEditDocument.TEditDocumentData _ NARROW[viewer.data]; node: TextNode.RefTextNode; [ok, loc] _ CheckPosition[viewer, loc]; IF tdd = NIL OR ~ok THEN RETURN; RememberCurrentPosition[viewer]; IF (node _ TextNode.NarrowToTextNode[loc.node]) # NIL THEN { -- backup to line start where: INT _ MAX[0, MIN[loc.where, TextEdit.Size[node]-1]]; backStop: INT _ MAX[0, where-300]; UNTIL where<=backStop OR Rope.Fetch[node.rope, where-1]=15C DO where _ where - 1; ENDLOOP; loc.where _ where }; TEditDisplay.EstablishLine[tdd, loc]; TRUSTED {Process.Detach[FORK ViewerOps.PaintViewer[viewer, hint ! ABORTED => CONTINUE]]}; }; LoadHistory: TYPE = RECORD [ name: Rope.ROPE, place: TextNode.Offset ]; CopyLoadHistory: PUBLIC PROC [from, to: Viewer] = { old: REF LoadHistory _ NARROW[ViewerOps.FetchProp[from, $LoadHistory]]; new: REF LoadHistory _ NARROW[ViewerOps.FetchProp[to, $LoadHistory]]; IF old=NIL THEN RETURN; IF new=NIL THEN { new _ TextNode.pZone.NEW[LoadHistory]; ViewerOps.AddProp[to, $LoadHistory, new] }; new^ _ old^; }; LoadPreviousFile: PUBLIC PROC [parent: ViewerClasses.Viewer] = BEGIN DoLoadPreviousFile[parent, FALSE, FALSE]; END; OpenPreviousFile: PUBLIC PROC [parent: ViewerClasses.Viewer] = BEGIN DoLoadPreviousFile[parent, TRUE, FALSE]; END; CloseAndOpenPreviousFile: PUBLIC PROC [parent: ViewerClasses.Viewer] = BEGIN DoLoadPreviousFile[parent, TRUE, TRUE]; END; PreLoadPrevious: PUBLIC Menus.MenuProc = { viewer: ViewerClasses.Viewer = NARROW[parent]; tdd: TEditDocumentData; prop: REF LoadHistory; propName: Rope.ROPE; tdd _ NARROW[viewer.data]; IF tdd = NIL THEN RETURN; [] _ SpinAndLock[tdd, "PreLoadPrevious"]; -- delay until after other op completes prop _ NARROW[ViewerOps.FetchProp[viewer, $LoadHistory]]; Unlock[tdd]; IF prop = NIL OR Rope.Equal[prop.name, viewer.file, FALSE] THEN { MessageWindow.Append["No record of previous file loaded in this viewer",TRUE]; MessageWindow.Blink[]; RETURN }; propName _ prop.name; IF ~CheckFileName[propName] THEN RETURN; MessageWindow.Append[clearFirst: TRUE, message: Rope.Concat[propName, " ~ Click LEFT to load, MIDDLE for new, RIGHT for close & new"]]; }; DoLoadPreviousFile: PROC [parent: ViewerClasses.Viewer, open, close: BOOL] = BEGIN tdd: TEditDocumentData; prop: REF LoadHistory; propName: Rope.ROPE; propPlace: TextNode.Offset; tdd _ NARROW[parent.data]; IF tdd = NIL THEN RETURN; [] _ SpinAndLock[tdd, "DoLoadPreviousFile"]; -- delay until after other op completes prop _ NARROW[ViewerOps.FetchProp[parent, $LoadHistory]]; Unlock[tdd]; IF prop = NIL OR Rope.Equal[prop.name, parent.file, FALSE] THEN { MessageWindow.Append["No record of previous file loaded in this viewer",TRUE]; MessageWindow.Blink[]; RETURN }; propName _ prop.name; propPlace _ prop.place; IF ~CheckFileName[propName] THEN RETURN; IF open AND ~close THEN [] _ DoOpen[propName, parent, propPlace] ELSE [] _ DoLoad[parent, propName, close, propPlace]; END; CheckAnonymous: PROC [parent: ViewerClasses.Viewer, txt: Rope.ROPE] RETURNS [BOOLEAN] = { IF Rope.Size[txt]=0 THEN { MessageWindow.Append["Enter a file name.",TRUE]; MessageWindow.Blink[]; RETURN[FALSE]}; IF ~CheckFileName[txt] THEN RETURN[FALSE]; RETURN [TRUE]; }; CheckNoName: PROC [parent: ViewerClasses.Viewer] RETURNS [BOOLEAN] = { IF ~Rope.Equal[parent.name, "No Name"] THEN { MessageWindow.Append["Not a \"No Name\" viewer",TRUE]; MessageWindow.Blink[]; RETURN [FALSE]}; RETURN [TRUE]; }; AnonymousLoadFile: PUBLIC PROC [ parent: ViewerClasses.Viewer, fileNameProcViewer: ViewerClasses.Viewer _ NIL] = { txt: Rope.ROPE; IF ~CheckNoName[parent] THEN RETURN; TEditInputOps.WaitForInsertToFinish[]; txt _ ViewerTools.GetContents[parent]; IF ~CheckAnonymous[parent, txt] THEN RETURN; [] _ LoadAndSearch[parent, txt, FALSE, fileNameProcViewer]; }; LoadAndSearch: PROC [ parent: ViewerClasses.Viewer, txt: Rope.ROPE, close: BOOL _ FALSE, fileNameProcViewer: ViewerClasses.Viewer _ NIL] RETURNS [viewer: ViewerClasses.Viewer] = { file, search: Rope.ROPE; IF fileNameProcViewer=NIL THEN fileNameProcViewer _ parent; [file, search] _ GetNameAndSearchRope[txt, fileNameProcViewer]; IF (viewer _ DoLoad[parent, file, close]) # NIL THEN DoSearch[viewer, search]; }; AnonymousLoadImplFile: PUBLIC PROC [parent: ViewerClasses.Viewer] = { txt: Rope.ROPE; IF ~CheckNoName[parent] THEN RETURN; TEditInputOps.WaitForInsertToFinish[]; txt _ ViewerTools.GetContents[parent]; IF ~CheckAnonymous[parent, txt] THEN RETURN; [] _ LoadImplAndSearch[parent, txt]; }; LoadImplAndSearch: PROC [parent: ViewerClasses.Viewer, txt: Rope.ROPE, close: BOOL _ FALSE] RETURNS [viewer: Viewer] = { impl, search: Rope.ROPE; [impl, search] _ GetImplNameAndSearchRope[txt]; IF (viewer _ DoLoad[parent, impl, close]) # NIL THEN DoSearch[viewer, search]; }; LoadFile: PUBLIC PROC [parent: ViewerClasses.Viewer] = { [] _ DoLoadFile[parent, NIL, FALSE] }; DoLoadFile: PUBLIC PROC [ parent: ViewerClasses.Viewer, fileName: ROPE _ NIL, close: BOOL _ FALSE, fileNameProcViewer: ViewerClasses.Viewer _ NIL] RETURNS [viewer: ViewerClasses.Viewer] = BEGIN tdd: TEditDocumentData; IF fileName=NIL THEN fileName _ ViewerTools.GetSelectionContents[]; tdd _ NARROW[parent.data]; IF tdd = NIL THEN RETURN; [] _ SpinAndLock[tdd, "DoLoadFile"]; Unlock[tdd]; -- let other op finish first IF ~PreLoadCheck[parent, fileName] THEN RETURN; viewer _ LoadAndSearch[parent, fileName, close, fileNameProcViewer]; END; LoadImplFile: PUBLIC PROC [parent: ViewerClasses.Viewer] = { [] _ DoLoadImplFile[parent, NIL] }; DoLoadImplFile: PUBLIC PROC [ parent: ViewerClasses.Viewer, fileName: ROPE _ NIL, close: BOOL _ FALSE] RETURNS [viewer: Viewer] = BEGIN tdd: TEditDocumentData; IF fileName=NIL THEN fileName _ ViewerTools.GetSelectionContents[]; tdd _ NARROW[parent.data]; IF tdd = NIL THEN RETURN; [] _ SpinAndLock[tdd ,"DoLoadImplFile"]; Unlock[tdd]; -- let other op finish first IF ~PreLoadCheck[parent, fileName] THEN RETURN; viewer _ LoadImplAndSearch[parent, fileName, close]; END; PreLoadCheck: PROC [parent: Viewer, sel: Rope.ROPE] RETURNS [BOOLEAN] = { IF Rope.Size[sel]=0 THEN {PleaseSelectFileName[]; RETURN[FALSE]}; IF ~CheckFileName[sel] THEN RETURN[FALSE]; RETURN [TRUE] }; AllocLoadHistory: PROC [viewer: Viewer] RETURNS [prop: REF LoadHistory] = { IF (prop _ NARROW[ViewerOps.FetchProp[viewer, $LoadHistory]]) # NIL THEN RETURN; prop _ TextNode.pZone.NEW[LoadHistory]; ViewerOps.AddProp[viewer, $LoadHistory, prop] }; SetLoadHistoryInfo: PROC [viewer: Viewer, prop: REF LoadHistory] = { tdd: TEditDocument.TEditDocumentData _ NARROW[viewer.data]; IF tdd = NIL THEN RETURN; prop.name _ viewer.file; prop.place _ TextNode.LocNumber[tdd.lineTable.lines[0].pos] }; SetLoadHistory: PROC [parent, viewer: Viewer] = { <> prop: REF LoadHistory _ AllocLoadHistory[viewer]; SetLoadHistoryInfo[parent, prop] }; SaveLoadHistory: PROC [viewer: Viewer] = { prop: REF LoadHistory _ AllocLoadHistory[viewer]; SetLoadHistoryInfo[viewer, prop] }; DoLoad: PROC [viewer: Viewer, file: Rope.ROPE, close: BOOL _ FALSE, place: TextNode.Offset _ 0] RETURNS [Viewer] = BEGIN new: BOOLEAN _ FALSE; tdd: TEditDocument.TEditDocumentData; oldViewer, destroyViewer: Viewer; tddOld: TEditDocument.TEditDocumentData; clearMessage: BOOL _ TRUE; directoryName: Rope.ROPE; [directoryName,new] _ GetDirectoryName[file]; IF new THEN { UnknownFile[directoryName]; RETURN[NIL] }; IF Rope.Equal[directoryName,viewer.name] THEN { MessageWindow.Append[Rope.Concat[directoryName," is already loaded."],TRUE]; RETURN [viewer] }; MessageWindow.Append[Rope.Concat["Loading ", directoryName],TRUE]; KillSelections[viewer]; tdd _ NARROW[viewer.data]; IF tdd = NIL THEN RETURN [viewer]; [] _ SpinAndLock[tdd, "DoLoad"]; IF viewer.file # NIL THEN SaveLoadHistory[viewer]; IF viewer.link=NIL THEN { IF close THEN { Unlock[tdd]; viewer _ ReplaceByNewViewer[viewer]; RETURN [DoLoad[viewer, file, FALSE, place]] }; -- try again ForgetViewer[viewer]; -- remove this from the root => viewer mapping IF viewer.newVersion AND ~viewer.saveInProgress AND viewer.file # NIL THEN RecordUnsavedDocument[viewer.file, tdd.text] ELSE TEditInput.FreeTree[tdd.text] } ELSE CancelLinks[viewer]; viewer.name _ viewer.file _ NIL; [oldViewer, ----] _ VirtualDesktops.FindViewer[directoryName]; viewer.name _ viewer.file _ directoryName; viewer.newVersion _ viewer.newFile _ FALSE; IF oldViewer # NIL AND NOT oldViewer.destroyed AND (tddOld _ NARROW[oldViewer.data]) # NIL THEN { -- link them viewer.newVersion _ oldViewer.newVersion; viewer.newFile _ oldViewer.newFile; [] _ SpinAndLock[tddOld, "DoLoad"]; tdd.text _ tddOld.text; tdd.tsInfo _ tddOld.tsInfo; Unlock[tddOld]; tdd.lineTable.lines[0].pos _ [TextNode.FirstChild[tdd.text],0]; tdd.clipLevel _ maxClip; tdd.commentFilter _ includeComments; viewer.link _ oldViewer; IF oldViewer.link=NIL THEN { oldViewer.link _ viewer; ViewerOps.PaintViewer[oldViewer, caption] } ELSE FOR v: Viewer _ oldViewer.link, v.link UNTIL v.link=oldViewer DO REPEAT FINISHED => v.link _ viewer; ENDLOOP; MessageWindow.Append[Rope.Concat[directoryName," was already loaded."],TRUE]; clearMessage _ FALSE; FOR v: Viewer _ oldViewer, v.link UNTIL v.link=oldViewer DO IF v.iconic THEN { destroyViewer _ v; EXIT }; -- destroy an iconic viewer ENDLOOP } ELSE { root: TextNode.Ref _ FindUnsavedDocument[directoryName]; tdd.text _ NIL; -- so InitViewerDoc won't worry about freeing it IF root # NIL THEN { MessageWindow.Append[ Rope.Concat[directoryName," restored with previous unsaved edits."],TRUE]; MessageWindow.Blink[]; clearMessage _ FALSE }; InitViewerDoc[viewer, root]; viewer.newVersion _ root # NIL; viewer.newFile _ FALSE }; ClearPositionHistory[viewer]; IF ~PositionViewer[viewer,TextNode.LocWithin[tdd.text,place],all] THEN TRUSTED {Process.Detach[FORK PaintAndRemember[viewer ! ABORTED => CONTINUE]]}; Unlock[tdd]; IF destroyViewer # NIL THEN ViewerOps.DestroyViewer[destroyViewer]; <> IF clearMessage THEN MessageWindow.Clear[]; RETURN[viewer]; END; PaintAndRemember: PROC [viewer: ViewerClasses.Viewer] = { ViewerOps.PaintViewer[viewer,all]; RememberCurrentPosition[viewer] }; ReplaceByNewViewer: PROC [parent: ViewerClasses.Viewer] RETURNS [viewer: Viewer] = { <> KillSelections[parent]; <> viewer _ MakeNewViewer[parent, FALSE]; <> viewer.openHeight _ parent.openHeight; viewer.position _ parent.position; SetLoadHistory[parent, viewer]; <> ViewerOps.CloseViewer[viewer: parent, paint: FALSE]; ViewerOps.PaintViewer[parent, all]; -- paint the icon }; MakeNewViewer: PROC [parent: ViewerClasses.Viewer, paint: BOOL _ TRUE] RETURNS [viewer: Viewer] = { <> viewer _ ViewerOps.CreateViewer[flavor: $Text, info: [name: "No Name", column: IF parent=NIL THEN left ELSE parent.column, iconic: TRUE], paint: FALSE]; IF TEditProfile.openFirstLevelOnly THEN { tdd: TEditDocument.TEditDocumentData _ NARROW[viewer.data]; IF tdd # NIL THEN tdd.clipLevel _ 1 }; ViewerOps.OpenIcon[icon: viewer, paint: FALSE]; <> IF parent # NIL THEN { -- move above parent and copy menus ViewerOps.MoveBelowViewer[altered: viewer, static: parent, paint: FALSE]; ViewerOps.SetMenu[viewer, parent.menu, FALSE]; ViewerOps.EstablishViewerPosition[viewer, viewer.wx, viewer.wy, viewer.ww, viewer.wh]; } ELSE DefaultMenus[viewer]; IF paint THEN ViewerOps.ComputeColumn[viewer.column]; -- paints the column }; CloseAndNewViewer: PUBLIC PROC [parent: Viewer] = { [] _ DoCloseAndNewViewer[parent] }; DoCloseAndNewViewer: PUBLIC PROC [parent: ViewerClasses.Viewer] RETURNS [new: ViewerClasses.Viewer] = { TEditSelection.LockSel[primary, "DoCloseAndNewViewer"]; { ENABLE UNWIND => TEditSelection.UnlockSel[primary]; new _ ReplaceByNewViewer[parent]; ViewerOps.PaintViewer[new, all]; ForceInitialCaret[new] }; TEditSelection.UnlockSel[primary]; }; NewViewer: PUBLIC PROC [parent: ViewerClasses.Viewer] = { [] _ DoNewViewer[parent] }; DoNewViewer: PUBLIC PROC [parent: ViewerClasses.Viewer _ NIL] RETURNS [new: ViewerClasses.Viewer] = BEGIN TEditSelection.LockSel[primary, "DoCloseAndNewViewer"]; { ENABLE UNWIND => TEditSelection.UnlockSel[primary]; ForceInitialCaret[new _ MakeNewViewer[parent,TRUE]] }; TEditSelection.UnlockSel[primary]; END; CloseAndOpenFile: PUBLIC PROC [parent: Viewer, fileNameProcViewer: Viewer _ NIL] = { [] _ DoLoadFile[parent, NIL, TRUE, fileNameProcViewer] }; DoCloseAndOpenFile: PUBLIC PROC [parent: Viewer, fileName: ROPE _ NIL] RETURNS [viewer: Viewer] = { RETURN [DoLoadFile[parent, fileName, TRUE]] }; OpenFile: PUBLIC PROC [parent: ViewerClasses.Viewer] = { [] _ DoOpenFile[NIL, parent] }; DoOpenFile: PUBLIC PROC [ fileName: ROPE _ NIL, parent, fileNameProcViewer: ViewerClasses.Viewer _ NIL] RETURNS [viewer: ViewerClasses.Viewer] = BEGIN file, search: Rope.ROPE; IF fileName=NIL THEN fileName _ ViewerTools.GetSelectionContents[]; IF ~PreOpenCheck[fileName] THEN RETURN; IF fileNameProcViewer=NIL THEN fileNameProcViewer _ parent; [file, search] _ GetNameAndSearchRope[fileName, fileNameProcViewer]; IF (viewer _ DoOpen[file,parent]) # NIL THEN DoSearch[viewer, search]; END; CloseAndOpenImplFile: PUBLIC PROC [parent: Viewer] = { [] _ DoCloseAndOpenImplFile[parent, NIL] }; DoCloseAndOpenImplFile: PUBLIC PROC [parent: Viewer, fileName: ROPE _ NIL] RETURNS [viewer: Viewer] = { RETURN [DoLoadImplFile[parent, fileName, TRUE]] }; OpenImplFile: PUBLIC PROC [parent: ViewerClasses.Viewer] = BEGIN [] _ DoOpenImplFile[NIL, parent]; END; DoOpenImplFile: PUBLIC PROC [fileName: ROPE _ NIL, parent: ViewerClasses.Viewer _ NIL] RETURNS [viewer: Viewer] = BEGIN impl, search: Rope.ROPE; IF fileName=NIL THEN fileName _ ViewerTools.GetSelectionContents[]; IF ~PreOpenCheck[fileName] THEN RETURN; [impl, search] _ GetImplNameAndSearchRope[fileName]; IF (viewer _ DoOpen[impl,parent]) # NIL THEN DoSearch[viewer, search]; END; PreOpenCheck: PROC [sel: Rope.ROPE] RETURNS [BOOLEAN] = { IF Rope.Size[sel]=0 THEN {PleaseSelectFileName[]; RETURN[FALSE]}; IF ~CheckFileName[sel] THEN RETURN[FALSE]; RETURN [TRUE] }; DoOpen: PROC [file: Rope.ROPE, parent: Viewer, place: TextNode.Offset _ 0] RETURNS [viewer: Viewer] = BEGIN <<-- this needs to work ok in case parent=NIL>> new: BOOLEAN _ FALSE; directoryName: Rope.ROPE; [directoryName,new] _ GetDirectoryName[file]; IF new THEN { UnknownFile[directoryName]; RETURN [NIL] }; viewer _ DoLoad[MakeNewViewer[parent,TRUE],directoryName,FALSE,place]; END; DefaultMenus: PUBLIC PROC [viewer: Viewer, paint: BOOL _ FALSE] = BEGIN menu: Menus.Menu _ viewer.menu; num: INTEGER _ 1; DoLine: PROC [which: TEditProfile.DefaultMenuChoice] = { entry: Menus.MenuEntry _ SELECT which FROM places => findMenu, levels => levelMenu, ENDCASE => NIL; IF entry = NIL THEN RETURN; Menus.SetLine[menu, num, entry]; num _ num+1 }; DoLine[TEditProfile.menu1]; DoLine[TEditProfile.menu2]; DoLine[TEditProfile.menu3]; ViewerOps.EstablishViewerPosition[viewer, viewer.wx, viewer.wy, viewer.ww, viewer.wh]; IF paint THEN ViewerOps.PaintViewer[viewer, all]; END; NodeProps.Register[$Viewer, NodeProps.NullRead, NodeProps.NullWrite, NodeProps.NullCopy]; NodeProps.Register[$FileCreateDate, NodeProps.NullRead, NodeProps.NullWrite, NodeProps.NullCopy]; NodeProps.Register[$FileExtension, NodeProps.NullRead, NodeProps.NullWrite, NodeProps.NullCopy]; END.