TEditDocuments3Impl.mesa
Copyright Ó 1985, 1987, 1988, 1989, 1990, 1991, 1992 by Xerox Corporation. All rights reserved.
Russ Atkinson (RRA) August 19, 1985 4:05:04 pm PDT
Michael Plass, March 23, 1989 2:32:33 pm PST
Doug Wyatt, October 18, 1991 12:08 pm PDT
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, 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],
ViewerOps USING [AddProp, FetchProp, PaintViewer, SaveViewer],
ViewerTools USING [GetSelectionContents];
TEditDocuments3Impl: CEDAR PROGRAM
IMPORTS InputFocus, MessageWindow, Process, Rope, TEditDocument, TEditDocumentPrivate, TEditInput, TEditScrolling, TEditSelection, TextNode, ViewerForkers, ViewerGroupLocks, ViewerOps, ViewerTools
EXPORTS TEditDocumentPrivate
= BEGIN OPEN TEditDocumentPrivate;
ROPE: TYPE ~ Rope.ROPE;
Viewer: TYPE ~ ViewerClasses.Viewer;
Do: PROC [viewer: REF ANY, atom: ATOM] = INLINE --gfi saver-- {
TEditInput.InterpretAtom[NARROW[viewer], atom];
};
Register: PROC [atom: ATOM, op: TEditInput.CommandProc] = INLINE --gfi saver-- {
TEditInput.Register[atom, op];
};
ForkViewerOp2: PROC [proc: PROC [parent: Viewer, fileName: ROPE ¬ NIL], parent: Viewer] RETURNS [BOOL] = {
TEditInput.CloseEvent[];
ViewerForkers.ForkCall[parent, StackBase, NEW[Data2 ¬ [proc, parent, ViewerTools.GetSelectionContents[]]]];
RETURN [FALSE]
};
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 = {
This is called after Rollback to see if any viewers need to be Reset.
Check: ViewerOps.EnumProc = {
[v: ViewerClasses.Viewer] RETURNS [BOOLTRUE]
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];
ViewerOps.RestoreViewer[v]; -- reload the file
};
};
ENDCASE;
RETURN [TRUE] --continue enumeration--
};
ViewerOps.EnumerateViewers[Check]; -- Check each top level viewer
};
Reset
SelectMouse: PROC [mouseButton: Menus.MouseButton, redOp, yellowOp, blueOp: ATOM] RETURNS [ATOM] = INLINE --gfi saver-- {
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: BOOLTRUE, quit: BOOLFALSE]
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
Save: PUBLIC Menus.ClickProc = {
MessageWindow.Clear[];
Do[parent, SelectMouse[mouseButton, $RedSave, $YellowSave, $BlueSave]];
};
SaveViewer: PROC [viewer: Viewer] = { [] ¬ ViewerOps.SaveViewer[viewer] };
SaveOp: TEditInput.CommandProc = {
TEditInput.CloseEvent[];
IF NOT viewer.saveInProgress AND (viewer.newFile OR viewer.newVersion) THEN {
[] ¬ Process.Detach[FORK SaveViewer[viewer]];
};
RETURN [FALSE];
};
Clear = Empty, New, or CloseAndNew
PreClear: PUBLIC Menus.ClickProc = {
called when Clear menu item becomes unguarded
MessageWindow.Append[clearFirst: TRUE, message:
"Click LEFT to empty this viewer, MIDDLE to make new viewer, RIGHT for close & new"];
};
Clear: PUBLIC Menus.ClickProc = {
PreClear[parent];
Do[parent, SelectMouse[mouseButton, $Empty, $New, $CloseAndNew]];
};
Don't fork these operations since they change the selection; want to capture typein that follows calls on these.
EmptyOp: TEditInput.CommandProc = {
IF viewer.newVersion
THEN {
MessageWindow.Append["Clear would lose edits.", TRUE];
MessageWindow.Blink[];
}
ELSE {
EmptyViewer[viewer];
};
RETURN [FALSE];
};
NewOp: TEditInput.CommandProc = { NewViewer[viewer]; RETURN [FALSE] };
NewButton: PUBLIC Buttons.ButtonProc = { NewViewer[NIL] };
This is the button in the upper left corner.
CloseAndNewOp: TEditInput.CommandProc = {
CloseAndNewViewer[viewer]; RETURN [FALSE] };
Store
Store: PUBLIC Menus.ClickProc = {
MessageWindow.Clear[];
Do[parent, SelectMouse[mouseButton, $RedStore, $YellowStore, $BlueStore]];
};
StoreOp: TEditInput.CommandProc = { RETURN [ForkViewerOp2[DoStoreFile, viewer]] };
PreviousFile = LoadPrevious, OpenPrevious, or CloseAndOpenPrevious
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]];
};
Anonymous Loads -- into NoName viewers
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];
};
Get = Load, Open, or CloseAndOpen
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 = {
PreGet[parent];
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: fileName, column: IF parent # NIL THEN parent.column ELSE left, parent: parent];
};
CloseAndOpenOp: TEditInput.CommandProc = {
RETURN [ForkViewerOp2[CloseAndOpenIt, viewer]];
};
CloseAndOpenIt: PROC [parent: Viewer, fileName: ROPE ¬ NIL] = {
[] ¬ DoCloseAndOpenFile[parent, fileName];
};
GetImpl = LoadImpl, OpenImpl, or CloseAndOpenImpl
GetImpl: PUBLIC Menus.ClickProc = {
PreGetImpl[parent];
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: fileName, column: IF parent # NIL THEN parent.column ELSE left, parent: parent];
};
CloseAndOpenImplOp: TEditInput.CommandProc = {
RETURN [ForkViewerOp2[CloseAndOpenItImpl, viewer]];
};
CloseAndOpenItImpl: PROC [parent: Viewer, fileName: ROPE ¬ NIL] = {
[] ¬ DoCloseAndOpenImplFile[parent, fileName];
};
OpenButton: PUBLIC Buttons.ButtonProc = {
This is the Open button in the upper right corner of the screen.
[] ¬ ForkViewerOp2[OpenIt, NIL];
};
Places menu commands
Normalize: PUBLIC Menus.ClickProc = {
Do[parent, SelectMouse[mouseButton, $NormalizeToStart, $NormalizeToCaret, $NormalizeToEnd]];
};
Position: PUBLIC Menus.ClickProc = {
Do[parent,
SELECT mouseButton FROM
red =>  IF shift THEN $PositionIncludingComments  ELSE $Position,
yellow =>  IF shift THEN $MsgPositionIncludingComments  ELSE $MsgPosition,
blue =>  IF shift THEN $StuffPositionIncludingComments  ELSE $StuffPosition,
ENDCASE => ERROR
];
};
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];
};
Levels menu commands
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]};
Lines menu commands
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]};
Time
Time: PUBLIC Menus.ClickProc = {Do[parent, $Time]};
Split
Split: PUBLIC Menus.ClickProc = {Do[parent,
SelectMouse[mouseButton, $RedSplit, $YellowSplit, $BlueSplit]];
};
Booting.RegisterProcs[r: CheckFilesAfterRollback];
Register[$RedReset, ResetOp]; Register[$YellowReset, ResetOp]; Register[$BlueReset, ResetOp];
Register[$RedSave, SaveOp]; Register[$YellowSave, SaveOp]; Register[$BlueSave, SaveOp];
Register[$Empty, EmptyOp];
Register[$New, NewOp];
Register[$CloseAndNew, CloseAndNewOp];
Register[$RedStore, StoreOp]; Register[$YellowStore, StoreOp]; Register[$BlueStore, StoreOp];
Register[$LoadPrevious, LoadPreviousOp];
Register[$OpenPrevious, OpenPreviousOp];
Register[$CloseAndOpenPrevious, CloseAndOpenPreviousOp];
Register[$AnonymousLoadImpl, AnonymousLoadImplOp];
Register[$AnonymousLoad, AnonymousLoadOp];
Register[$Load, LoadOp];
Register[$Open, OpenOp];
Register[$CloseAndOpen, CloseAndOpenOp];
Register[$LoadImpl, LoadImplOp];
Register[$OpenImpl, OpenImplOp];
Register[$CloseAndOpenImpl, CloseAndOpenImplOp];
Register[$PrevPlace, PrevPlaceOp];
Register[$Reselect, ReselectOp];
END.