-- TEditDocuments2Impl.mesa; Edited by Paxton on June 7, 1983 9:38 am
-- Edited by McGregor on September 10, 1982 1:53 pm
Last Edited by: Maxwell, January 6, 1983 11:06 am
Last Edited by: Plass, October 11, 1983 5:05 pm
DIRECTORY
CIFS USING [Error, Open, OpenFile, Close, GetPathname, read],
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,
ViewerClasses USING [Viewer],
ViewerTools USING [GetContents, GetSelectionContents, SelPos, SelPosRec, SetSelection];
TEditDocuments2Impl: CEDAR MONITOR
IMPORTS CIFS, MessageWindow, NodeProps, Process, Rope, RopeEdit, RTMiniModel, TEditDocument, TEditDocumentPrivate, TextEdit, TextNode, TEditDisplay, TEditInput, TEditInputOps, TEditProfile, TEditSelection, ViewerOps, ViewerTools
EXPORTS
TEditDocument,
RecordViewerForRoot, ForgetViewer, GetViewerForRoot
TEditDocumentPrivate,
CancelLinks, EmptyViewer, NewViewer, DoNewViewer, CloseAndNewViewer, DoCloseAndNewViewer, OpenFile, DoOpenFile, CloseAndOpenFile, DoCloseAndOpenFile, OpenImplFile, DoOpenImplFile, CloseAndOpenImplFile, DoCloseAndOpenImplFile, LoadFile, DoLoadFile, LoadImplFile, DoLoadImplFile, AnonymousLoadFile, AnonymousLoadImplFile, LoadPreviousFile, OpenPreviousFile, CloseAndOpenPreviousFile, StoreFile, DoStoreFile, PositionViewer, DefaultMenus
TEditOps
RememberCurrentPosition, CopyPositionHistory, CopyLoadHistory, RegisterFileNameProc
= BEGIN OPEN Rope, TEditDocument, TEditDocumentPrivate;
Viewer: TYPE = ViewerClasses.Viewer;
ForceInitialCaret: PROC [viewer: Viewer] = {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.ROPENIL] = 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 ViewerOps.FindViewer[fileName] # 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.name # NIL AND NOT parent.name.Equal["No Name"] THEN SaveLoadHistory[parent];
IF linked ← (parent.link#NIL) THEN CancelLinks[parent]; -- remove viewer from link chain
parent.name ← 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
IF parent#NIL AND parent.data#NIL THEN 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.name # NIL AND NOT parent.name.Equal["No Name"] THEN
RecordUnsavedDocument[parent.name, tdd.text]
ELSE TEditInput.FreeTree[tdd.text];
parent.name ← "No Name";
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[] };
IllegalFileName: PROC = {
MessageWindow.Append["Illegal 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 {
TRUSTED { Process.Detach[FORK IllegalFileName[]] };
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: BOOLFALSE;
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: INTMAX[0, MIN[loc.where, TextEdit.Size[node]-1]];
backStop: INTMAX[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.name, 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.name, 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];
};
CheckNoFile: PROC [parent: ViewerClasses.Viewer] RETURNS [BOOLEAN] = {
IF NOT parent.name.Equal["No Name"] THEN {
MessageWindow.Append["Viewer already contains a file.",TRUE];
MessageWindow.Blink[];
RETURN [FALSE]};
RETURN [TRUE];
};
AnonymousLoadFile: PUBLIC PROC [
parent: ViewerClasses.Viewer, fileNameProcViewer: ViewerClasses.Viewer ← NIL] = {
txt: Rope.ROPE;
IF ~CheckNoFile[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: BOOLFALSE, 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 ~CheckNoFile[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: BOOLFALSE]
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: ROPENIL, close: BOOLFALSE,
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: ROPENIL, close: BOOLFALSE]
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.name;
prop.place ← TextNode.LocNumber[tdd.lineTable.lines[0].pos] };
SetLoadHistory: PROC [parent, viewer: Viewer] = {
Make viewer's load history point to current contents of parent
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: BOOLFALSE, place: TextNode.Offset ← 0]
RETURNS [Viewer] = BEGIN
new: BOOLEANFALSE;
tdd: TEditDocument.TEditDocumentData;
oldViewer, destroyViewer: Viewer;
tddOld: TEditDocument.TEditDocumentData;
clearMessage: BOOLTRUE;
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.name.Equal["No Name"] 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.name # NIL THEN
RecordUnsavedDocument[viewer.name, tdd.text]
ELSE TEditInput.FreeTree[tdd.text] }
ELSE CancelLinks[viewer];
viewer.name ← viewer.name ← NIL;
oldViewer ← ViewerOps.FindViewer[directoryName];
viewer.name ← viewer.name ← 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;
TRUSTED {Process.Detach[FORK WasLoadedMessage[directoryName]] };
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 {
TRUSTED {Process.Detach[FORK ReloadedMessage[directoryName]] }; -- can deadlock if don't fork
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];
Cannot do the destroy until after have released lock.
IF clearMessage THEN MessageWindow.Clear[];
RETURN[viewer];
END;
WasLoadedMessage: PROC [name: Rope.ROPE] = {
MessageWindow.Append[Rope.Concat[name," was already loaded."],TRUE] };
ReloadedMessage: PROC [name: Rope.ROPE] = {
MessageWindow.Append[
Rope.Concat[name," restored with previous unsaved edits."],TRUE];
MessageWindow.Blink[] };
PaintAndRemember: PROC [viewer: ViewerClasses.Viewer] = {
ViewerOps.PaintViewer[viewer,all]; RememberCurrentPosition[viewer] };
ReplaceByNewViewer: PROC [parent: ViewerClasses.Viewer] RETURNS [viewer: Viewer] = {
Cannot have document or tdd locked when call this or may deadlock.
KillSelections[parent];
need to deselect before make new viewer
viewer ← MakeNewViewer[parent, FALSE];
copy height and position info from old to new
viewer.openHeight ← parent.openHeight;
viewer.position ← parent.position;
SetLoadHistory[parent, viewer];
make parent iconic without doing paints in the column, just paint the icon
ViewerOps.CloseViewer[viewer: parent, paint: FALSE];
ViewerOps.PaintViewer[parent, all]; -- paint the icon
};
MakeNewViewer: PROC [parent: ViewerClasses.Viewer, paint: BOOLTRUE]
RETURNS [viewer: Viewer] = {
Cannot have document or tdd locked when call this or may deadlock.
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];
Create it iconic and then open to minimize time that have a bad viewer tree.
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: ROPENIL]
RETURNS [viewer: Viewer] = { RETURN [DoLoadFile[parent, fileName, TRUE]] };
OpenFile: PUBLIC PROC [parent: ViewerClasses.Viewer] = {
[] ← DoOpenFile[NIL, parent] };
DoOpenFile: PUBLIC PROC [
fileName: ROPENIL, 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: ROPENIL]
RETURNS [viewer: Viewer] = { RETURN [DoLoadImplFile[parent, fileName, TRUE]] };
OpenImplFile: PUBLIC PROC [parent: ViewerClasses.Viewer] = BEGIN
[] ← DoOpenImplFile[NIL, parent];
END;
DoOpenImplFile: PUBLIC PROC [fileName: ROPENIL, 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: BOOLEANFALSE;
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: BOOLFALSE] = 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.