-- 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, April 15, 1983 1:10 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] = {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 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
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.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[] };
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.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];
};
CheckNoFile: PROC [parent: ViewerClasses.Viewer] RETURNS [BOOLEAN] = {
IF parent.file # NIL 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.file;
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.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;
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.