-- 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.
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 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: 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.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: 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 ~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:
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.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:
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.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:
BOOL ←
TRUE]
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:
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.