<> <> <> <> <> <<>> DIRECTORY Booting USING [RegisterProcs, RollbackProc], Buttons USING [ButtonProc], InputFocus USING [GetInputFocus, SetInputFocus], Menus USING [ClickProc, MouseButton], MessageWindow USING [Append, Blink, Clear], Process USING [Detach], Rope USING [Concat, ROPE], TEditDocument USING [Selection, SpinAndLock, TEditDocumentData, Unlock], TEditDocumentPrivate USING [AnonymousLoadFile, AnonymousLoadImplFile, CloseAndNewViewer, CloseAndOpenPreviousFile, DoCloseAndOpenFile, DoCloseAndOpenImplFile, DoLoadFile, DoLoadImplFile, DoOpenFile, DoOpenImplFile, DoStoreFile, EmptyViewer, FileIsMoreRecent, LoadPreviousFile, NewViewer, OpenPreviousFile, PositionHistory, PositionViewer, PreLoadPrevious], TEditInput USING [CheckSelection, CloseEvent, CommandProc, InterpretAtom, Register], TEditScrolling USING [AutoScroll], TEditSelection USING [MakeSelection], TextNode USING [Location, LocNumber, LocWithin], ViewerClasses USING [Viewer], ViewerForkers USING [CallBack, ForkCall], ViewerGroupLocks USING [CallRootAndLinksUnderWriteLock], ViewerMenus USING [Restore, Save], ViewerOps USING [AddProp, EnumerateViewers, EnumProc, FetchProp, PaintViewer], ViewerTools USING [GetSelectionContents]; TEditDocuments3Impl: CEDAR PROGRAM IMPORTS Booting, InputFocus, MessageWindow, Process, Rope, TEditDocument, TEditDocumentPrivate, TEditInput, TEditScrolling, TEditSelection, TextNode, ViewerForkers, ViewerGroupLocks, ViewerMenus, ViewerOps, ViewerTools EXPORTS TEditDocumentPrivate = BEGIN OPEN TEditDocumentPrivate; ROPE: TYPE ~ Rope.ROPE; Viewer: TYPE ~ ViewerClasses.Viewer; Do: PROC [viewer: REF ANY, atom: ATOM] = { TEditInput.InterpretAtom[NARROW[viewer], atom]; }; Register: PROC [atom: ATOM, op: TEditInput.CommandProc] = { TEditInput.Register[atom, op]; }; ForkViewerOp2: PROC [proc: PROC [parent: Viewer, fileName: ROPE _ NIL], parent: Viewer] RETURNS [BOOL _ FALSE] = { TEditInput.CloseEvent[]; ViewerForkers.ForkCall[parent, StackBase, NEW[Data2 _ [proc, parent, ViewerTools.GetSelectionContents[]]]]; }; ForkViewerOp: PROC [proc: PROC [parent: Viewer], parent: Viewer] RETURNS [BOOL _ FALSE] = { TEditInput.CloseEvent[]; ViewerForkers.ForkCall[parent, StackBase, NEW[Data1 _ [proc, parent]]]; }; Data1: TYPE = RECORD [ proc: PROC [parent: Viewer], viewer: Viewer]; Data2: TYPE = RECORD [ proc: PROC [parent: Viewer, fileName: ROPE], viewer: Viewer, fileName: ROPE]; StackBase: ViewerForkers.CallBack = { <<[data: REF ANY]>> WITH data SELECT FROM data1: REF Data1 => { data1.proc[data1.viewer ! ABORTED => CONTINUE]; }; data2: REF Data2 => { data2.proc[data2.viewer, data2.fileName ! ABORTED => CONTINUE]; }; ENDCASE; }; CheckFilesAfterRollback: Booting.RollbackProc = { <> Check: ViewerOps.EnumProc = { <<[v: ViewerClasses.Viewer] RETURNS [BOOL _ TRUE]>> WITH v.data SELECT FROM tdd: TEditDocument.TEditDocumentData => { IF FileIsMoreRecent[tdd.text, v.file] THEN { MessageWindow.Append[Rope.Concat["Loading newer version of ", v.file], TRUE]; ViewerMenus.Restore[v]; -- reload the file }; }; ENDCASE; RETURN [TRUE] --continue enumeration-- }; ViewerOps.EnumerateViewers[Check]; -- Check each top level viewer }; <> <<>> SelectMouse: PROC [mouseButton: Menus.MouseButton, redOp, yellowOp, blueOp: ATOM] RETURNS [ATOM] = { RETURN [SELECT mouseButton FROM red => redOp, yellow => yellowOp, blue => blueOp, ENDCASE => ERROR]; }; PreReset: PUBLIC Menus.ClickProc = { WITH parent SELECT FROM viewer: Viewer => MessageWindow.Append[ IF viewer.file = NIL THEN "Confirm clearing viewer" ELSE Rope.Concat["Confirm reloading of ", viewer.file], TRUE]; ENDCASE; }; Reset: PUBLIC Menus.ClickProc = { MessageWindow.Clear[]; Do[parent, SelectMouse[mouseButton, $RedReset, $YellowReset, $BlueReset]]; }; ResetOp: TEditInput.CommandProc = { <<[viewer: ViewerClasses.Viewer _ NIL] RETURNS [recordAtom: BOOL _ TRUE, quit: BOOL _ FALSE]>> inner: PROC = { FOR v: Viewer _ viewer, v.link UNTIL v = NIL DO WITH v.data SELECT FROM tdd: TEditDocument.TEditDocumentData => { [] _ TEditDocument.SpinAndLock[tdd, "Reset"]; ViewerOps.AddProp[v, $ResetLoc, NEW[INT _ TextNode.LocNumber[tdd.lineTable.lines[0].pos]]]; v.newVersion _ TRUE; -- to force the init proc to reread the file TEditDocument.Unlock[tdd]; }; ENDCASE; IF v.link=viewer THEN EXIT; ENDLOOP; FOR v: Viewer _ viewer, v.link UNTIL v = NIL DO WITH v.data SELECT FROM tdd: TEditDocument.TEditDocumentData => { IF InputFocus.GetInputFocus[].owner=v THEN InputFocus.SetInputFocus[]; WITH ViewerOps.FetchProp[v, $ResetLoc] SELECT FROM locRef: REF INT => { v.class.init[v]; v.newVersion _ v.newFile _ FALSE; [] _ TEditDocument.SpinAndLock[tdd, "Reset"]; IF ~PositionViewer[v,TextNode.LocWithin[tdd.text,locRef^],all] THEN ViewerOps.PaintViewer[v, all]; TEditDocument.Unlock[tdd]; }; ENDCASE; }; ENDCASE; IF v.link=viewer THEN EXIT; ENDLOOP; }; ViewerGroupLocks.CallRootAndLinksUnderWriteLock[inner, viewer]; }; <> <<>> Save: PUBLIC Menus.ClickProc = { MessageWindow.Clear[]; Do[parent, SelectMouse[mouseButton, $RedSave, $YellowSave, $BlueSave]]; }; SaveOp: TEditInput.CommandProc = { TEditInput.CloseEvent[]; IF ~viewer.saveInProgress THEN TRUSTED { [] _ Process.Detach[FORK ViewerMenus.Save[viewer]]; }; RETURN [FALSE]; }; <> <<>> PreClear: PUBLIC Menus.ClickProc = { <> MessageWindow.Append[clearFirst: TRUE, message: "Click LEFT to empty this viewer, MIDDLE to make new viewer, RIGHT for close & new"]; }; Clear: PUBLIC Menus.ClickProc = { <> Do[parent, SelectMouse[mouseButton, $Empty, $New, $CloseAndNew]]; }; <> <<>> EmptyOp: TEditInput.CommandProc = { EmptyViewer[viewer]; RETURN [FALSE] }; NewOp: TEditInput.CommandProc = { NewViewer[viewer]; RETURN [FALSE] }; NewButton: PUBLIC Buttons.ButtonProc = { NewViewer[NIL] }; <> CloseAndNewOp: TEditInput.CommandProc = { CloseAndNewViewer[viewer]; RETURN [FALSE] }; <> <<>> Store: PUBLIC Menus.ClickProc = { MessageWindow.Clear[]; Do[parent, SelectMouse[mouseButton, $RedStore, $YellowStore, $BlueStore]]; }; StoreOp: TEditInput.CommandProc = { RETURN [ForkViewerOp2[DoStoreFile,viewer]] }; <> <<>> PreviousFile: PUBLIC Menus.ClickProc = { PreLoadPrevious[parent]; Do[parent, SelectMouse[mouseButton, $LoadPrevious, $OpenPrevious, $CloseAndOpenPrevious]]; }; LoadPreviousOp: TEditInput.CommandProc = { RETURN [ForkViewerOp[LoadPreviousFile,viewer]]; }; OpenPreviousOp: TEditInput.CommandProc = { RETURN [ForkViewerOp[OpenPreviousFile,viewer]]; }; CloseAndOpenPreviousOp: TEditInput.CommandProc = { RETURN [ForkViewerOp[CloseAndOpenPreviousFile,viewer]]; }; <> <<>> AnonymousLoadImpl: PUBLIC Menus.ClickProc = { Do[parent,$AnonymousLoadImpl]; }; AnonymousLoadImplOp: TEditInput.CommandProc = { RETURN [ForkViewerOp[AnonymousLoadImplFile,viewer]]; }; AnonymousLoad: PUBLIC Menus.ClickProc = { Do[parent,$AnonymousLoad]; }; AnonymousLoadOp: TEditInput.CommandProc = { RETURN [ForkViewerOp[AnonymousLoadIt,viewer]]; }; AnonymousLoadIt: PROC [parent: Viewer] = { AnonymousLoadFile[parent]; }; <> <<>> PreGet, PreGetImpl: PUBLIC Menus.ClickProc = { viewer: Viewer = NARROW[parent]; MessageWindow.Append["Click LEFT to load in this viewer, MIDDLE for new viewer, RIGHT for close & new", TRUE]; }; Get: PUBLIC Menus.ClickProc = { <> Do[parent, SelectMouse[mouseButton, $Load, $Open, $CloseAndOpen]]; }; LoadOp: TEditInput.CommandProc = { RETURN [ForkViewerOp2[LoadIt,viewer]] }; LoadIt: PROC [parent: Viewer, fileName: ROPE _ NIL] = { [] _ DoLoadFile[parent, fileName, FALSE]; }; OpenOp: TEditInput.CommandProc = { RETURN [ForkViewerOp2[OpenIt,viewer]]; }; OpenIt: PROC [parent: Viewer, fileName: ROPE _ NIL] = { [] _ DoOpenFile[fileName, parent]; }; CloseAndOpenOp: TEditInput.CommandProc = { RETURN [ForkViewerOp2[CloseAndOpenIt,viewer]]; }; CloseAndOpenIt: PROC [parent: Viewer, fileName: ROPE _ NIL] = { [] _ DoCloseAndOpenFile[parent, fileName]; }; <> <<>> GetImpl: PUBLIC Menus.ClickProc = { <> Do[parent, SelectMouse[mouseButton, $LoadImpl, $OpenImpl, $CloseAndOpenImpl]]; }; LoadImplOp: TEditInput.CommandProc = { RETURN [ForkViewerOp2[LoadItImpl,viewer]]; }; LoadItImpl: PROC [parent: Viewer, fileName: ROPE _ NIL] = { [] _ DoLoadImplFile[parent, fileName, FALSE]; }; OpenImplOp: TEditInput.CommandProc = { RETURN [ForkViewerOp2[OpenItImpl,viewer]]; }; OpenItImpl: PROC [parent: Viewer, fileName: ROPE _ NIL] = { [] _ DoOpenImplFile[fileName, parent]; }; CloseAndOpenImplOp: TEditInput.CommandProc = { RETURN [ForkViewerOp2[CloseAndOpenItImpl,viewer]]; }; CloseAndOpenItImpl: PROC [parent: Viewer, fileName: ROPE _ NIL] = { [] _ DoCloseAndOpenImplFile[parent, fileName]; }; OpenButton: PUBLIC Buttons.ButtonProc = { <> [] _ ForkViewerOp2[OpenIt, NIL]; }; <> <<>> Normalize: PUBLIC Menus.ClickProc = { Do[parent, SelectMouse[mouseButton, $NormalizeToStart, $NormalizeToCaret, $NormalizeToEnd]]; }; Position: PUBLIC Menus.ClickProc = {Do[parent, IF shift THEN $PositionIncludingComments ELSE $Position]; }; JumpToPrevious: PUBLIC Menus.ClickProc = {Do[parent,$PrevPlace]}; PrevPlaceOp: TEditInput.CommandProc = { tdd: TEditDocument.TEditDocumentData _ NARROW[viewer.data]; prop: REF PositionHistory _ NARROW[ViewerOps.FetchProp[viewer, $PositionHistory]]; IF tdd # NIL AND prop # NIL THEN { loc: TextNode.Location _ prop.pos; IF loc = tdd.lineTable.lines[0].pos THEN loc _ prop.prev; IF PositionViewer[viewer, loc] THEN RETURN; IF loc # prop.prev AND PositionViewer[viewer, prop.prev] THEN RETURN }; MessageWindow.Append["No previous place saved.", TRUE]; MessageWindow.Blink[]; RETURN [FALSE]; }; Reselect: PUBLIC Menus.ClickProc = {Do[parent,$Reselect]}; ReselectOp: TEditInput.CommandProc = { tdd: TEditDocument.TEditDocumentData _ NARROW[viewer.data]; prop: TEditDocument.Selection _ NARROW[ViewerOps.FetchProp[viewer, $SelectionHistory]]; IF tdd # NIL AND prop # NIL AND TEditInput.CheckSelection[prop] THEN { TEditSelection.MakeSelection[selection: primary, new: prop]; TEditScrolling.AutoScroll[viewer,FALSE] } ELSE { MessageWindow.Append["No saved selection.", TRUE]; MessageWindow.Blink[] }; RETURN [FALSE]; }; Find: PUBLIC Menus.ClickProc = { Do[parent, SELECT mouseButton FROM red => IF shift THEN $FindNextCaseless ELSE $FindNext, yellow => IF shift THEN $FindAnyCaseless ELSE $FindAny, blue => IF shift THEN $FindPrevCaseless ELSE $FindPrev, ENDCASE => ERROR]; }; FindDef: PUBLIC Menus.ClickProc = { Do[parent, SELECT mouseButton FROM red => IF shift THEN $FindNextDefCaseless ELSE $FindNextDef, yellow => IF shift THEN $FindAnyDefCaseless ELSE $FindAnyDef, blue => IF shift THEN $FindPrevDefCaseless ELSE $FindPrevDef, ENDCASE => ERROR]; }; FindWord: PUBLIC Menus.ClickProc = { Do[parent, SELECT mouseButton FROM red => IF shift THEN $FindNextWordCaseless ELSE $FindNextWord, yellow => IF shift THEN $FindAnyWordCaseless ELSE $FindAnyWord, blue => IF shift THEN $FindPrevWordCaseless ELSE $FindPrevWord, ENDCASE => ERROR]; }; <> FewerLevels: PUBLIC Menus.ClickProc = {Do[parent,$FewerLevels]}; MoreLevels: PUBLIC Menus.ClickProc = {Do[parent,$MoreLevels]}; AllLevels: PUBLIC Menus.ClickProc = {Do[parent,$AllLevels]}; FirstLevelOnly: PUBLIC Menus.ClickProc = {Do[parent,$FirstLevelOnly]}; <<>> <> FewerLines: PUBLIC Menus.ClickProc = {Do[parent,$FewerLines]}; MoreLines: PUBLIC Menus.ClickProc = {Do[parent,$MoreLines]}; AllLines: PUBLIC Menus.ClickProc = {Do[parent,$AllLines]}; FirstLineOnly: PUBLIC Menus.ClickProc = {Do[parent,$FirstLineOnly]}; <