DIRECTORY AMBridge USING [ContextPC], AMFiles USING [FullFileName], AMModel USING [Context, ContextSection, RootContext, Section, SectionSource, Source, SourceFileName, SourceObj, SourceSection, SourceVersion], AMModelBridge USING [LoadedSection, LoadedSectionForProc, LoadedSectionForProgPC], AMViewerOps USING [ReportProc, Severity], AMTypes USING [GlobalParent, TVType, UnderClass, TV], BackStop USING [Call], BasicTime USING [GMT, nullGMT, ToNSTime, FromNSTime], BcdDefs USING [NullVersion, VersionStamp], FileViewerOps USING [SelectionOption], FS USING [Error, FileInfo], IO USING [PutRope, PutFR, STREAM], Process USING [Pause, SecondsToTicks], ProcessExtras USING [CheckForAbort], Rope USING [Cat, Concat, Fetch, Find, Flatten, Match, ROPE, Size, Text, Length], TEditDocument USING [LineTable, TEditDocumentData], TEditScrolling USING [AutoScroll, ScrollToPosition], TEditTouchup USING [LockAfterRefresh, UnlockAfterRefresh], TextNode USING [Forward, Location, Ref], TiogaMenuOps USING [Open], TiogaOps USING [GetSelection, Location, LocOffset, LocRelative, Ref, Root, SetSelection, ViewerDoc], VersionMapDefaults USING [FileNameFromVersion], ViewerClasses USING [Viewer], ViewerOps USING [EnumerateViewers, OpenIcon, DestroyViewer, BlinkIcon, CreateViewer], ViewerTools USING [SelPos, SelPosRec, SetSelection], WorldVM USING [LocalWorld, World]; AMViewerOpsImpl: CEDAR MONITOR IMPORTS AMBridge, AMFiles, AMModel, AMModelBridge, AMTypes, BackStop, BasicTime, FS, IO, Process, ProcessExtras, Rope, TEditScrolling, TEditTouchup, TextNode, TiogaMenuOps, TiogaOps, VersionMapDefaults, ViewerOps, ViewerTools, WorldVM EXPORTS AMViewerOps, FileViewerOps = BEGIN OPEN AMViewerOps, FileViewerOps; Section: TYPE = AMModel.Section; Source: TYPE = AMModel.Source; ROPE: TYPE = Rope.ROPE; TV: TYPE = AMTypes.TV; World: TYPE = WorldVM.World; oldSetSel: BOOL _ FALSE; AutoScrollOK: BOOL _ TRUE; skipComments: BOOL _ TRUE; lagLagMsg, lagMsg: ROPE _ NIL; lagErr: ROPE _ NIL; ViewerFromSection: PUBLIC PROC [section: AMModel.Section, report: ReportProc] RETURNS [viewer: ViewerClasses.Viewer _ NIL] = TRUSTED { errmsg: ROPE _ NIL; inner: PROC = TRUSTED { sourceVersion: BcdDefs.VersionStamp; source: Source _ AMModel.SectionSource[section]; name: ROPE _ AMModel.SourceFileName[source]; start: INT _ 0; IF name = NIL THEN { errmsg _ "can't get source name"; RETURN}; sourceVersion _ AMModel.SourceVersion[source]; IF sourceVersion = BcdDefs.NullVersion THEN { errmsg _ "can't get source version stamp"; RETURN}; name _ SourceToFullName[source, report]; IF name = NIL THEN { errmsg _ VersionExpectedMessage[sourceVersion]; RETURN}; errmsg _ "can't set source"; viewer _ NameToOpenViewer[name, sourceVersion, report, TRUE]; errmsg _ "can't set selection"; WITH s: source^ SELECT FROM field => start _ s.firstCharIndex; ENDCASE; SetSel[viewer, start, 2, name]; errmsg _ NIL; }; msg: ROPE _ BackStop.Call[inner]; IF errmsg = NIL THEN errmsg _ msg; IF errmsg # NIL THEN report[errmsg, fatal]; }; SourceFromSelection: PUBLIC PROC [which: SelectionOption _ primary] RETURNS [fileName: ROPE _ NIL, index: INT _ -1] = TRUSTED { viewer: ViewerClasses.Viewer _ NIL; start: TiogaOps.Location; [viewer: viewer, start: start] _ TiogaOps.GetSelection[IF which = primary THEN primary ELSE feedback]; IF viewer # NIL AND NOT viewer.destroyed AND NOT viewer.newFile THEN { root: TiogaOps.Ref _ TiogaOps.Root[start.node]; offset: INT _ TiogaOps.LocOffset[loc1: [root, 0], loc2: start, skipCommentNodes: skipComments]; index _ offset; fileName _ viewer.name; }; }; SectionFromSelection: PUBLIC PROC [world: World _ NIL, which: SelectionOption _ primary] RETURNS [section: Section _ NIL, contexts: LIST OF AMModel.Context _ NIL] = TRUSTED { name: ROPE _ NIL; index: INT _ -1; [name, index] _ SourceFromSelection[which]; [section, contexts] _ SectionFromSource[world, name, index]; }; SectionFromSource: PUBLIC PROC [world: World _ NIL, name: ROPE _ NIL, index: INT _ 0] RETURNS [section: Section _ NIL, contexts: LIST OF AMModel.Context _ NIL] = TRUSTED { shortName: ROPE _ StripDir[name]; sourceVersion: BcdDefs.VersionStamp _ FileVersion[name].version; source: Source _ NIL; context: AMModel.Context _ AMModel.RootContext[IF world = NIL THEN WorldVM.LocalWorld[] ELSE world]; IF index <= 0 THEN source _ NEW[AMModel.SourceObj _ [ fileName: shortName, class: prog, versionStamp: sourceVersion, sourceRange: entire[]]] ELSE source _ NEW[AMModel.SourceObj _ [ fileName: shortName, class: statement, versionStamp: sourceVersion, sourceRange: field[index, index]]]; [section, contexts] _ AMModel.SourceSection[source, context]; }; FileVersion: PROC [name: ROPE, desiredVersion: BcdDefs.VersionStamp _ BcdDefs.NullVersion] RETURNS [fullName: ROPE _ NIL, version: BcdDefs.VersionStamp _ BcdDefs.NullVersion] = { gmt: BasicTime.GMT = IF desiredVersion = BcdDefs.NullVersion THEN BasicTime.nullGMT ELSE BasicTime.FromNSTime[desiredVersion.time]; fullName _ AMFiles.FullFileName[name, gmt]; IF fullName.Length[] = 0 THEN RETURN; version.time _ BasicTime.ToNSTime[ FS.FileInfo[name: fullName, wantedCreatedTime: gmt ! FS.Error => CONTINUE].created ]; }; SourceFromTV: PUBLIC PROC [tv: TV, report: ReportProc] RETURNS [name: ROPE _ NIL, index: INT _ -1] = { errmsg: ROPE _ NIL; inner: PROC = TRUSTED { section: Section _ NIL; source: Source _ NIL; SELECT AMTypes.UnderClass[AMTypes.TVType[tv]] FROM procedure => section _ AMModelBridge.LoadedSectionForProc[tv].section; globalFrame => section _ AMModel.ContextSection[tv]; localFrame => { section _ AMModelBridge.LoadedSectionForProgPC[ prog: AMTypes.GlobalParent[tv], pc: AMBridge.ContextPC[tv]].section; }; ENDCASE => {errmsg _ "invalid TV"; RETURN}; source _ AMModel.SectionSource[section]; name _ SourceToFullName[source, report]; IF name = NIL THEN { errmsg _ VersionExpectedMessage[AMModel.SourceVersion[source]]; RETURN}; WITH s: source^ SELECT FROM entire => index _ 0; field => index _ s.firstCharIndex; ENDCASE => ERROR; }; err: ROPE _ NIL; Report[report, comment, " Finding source... "]; err _ BackStop.Call[inner]; IF errmsg = NIL THEN errmsg _ err; IF errmsg # NIL THEN Report[report, fatal, " No source: ", errmsg] ELSE Report[report, success]; }; OpenSource: PUBLIC PROC [fileName: ROPE, index: INT, chars: INT _ 2, feedBack: IO.STREAM _ NIL] = { viewer: ViewerClasses.Viewer _ NIL; report: ReportProc--PROC [msg: ROPE, severity: Severity]-- = { IF feedBack # NIL THEN feedBack.PutRope[msg]; }; inner: PROC = TRUSTED { viewer _ NameToOpenViewer[fileName, BcdDefs.NullVersion, report, TRUE]; IF viewer # NIL AND index > 0 THEN SetSel[viewer, index, chars, fileName]; }; err: ROPE _ NIL; err _ BackStop.Call[inner]; IF err # NIL THEN Report[report, fatal, " Can't open: ", err] ELSE Report[report, success, " Source opened."]; }; Report: PROC [report: ReportProc, severity: Severity, r1,r2,r3,r4: ROPE _ NIL] = { msg: ROPE _ Rope.Cat[r1, r2, r3, r4]; report[msg, severity]; }; OnScreen: PROC [viewer: ViewerClasses.Viewer, point: TextNode.Location] RETURNS [BOOL] = { IF viewer = NIL OR point.node = NIL THEN RETURN [FALSE]; IF viewer.destroyed OR viewer.iconic THEN RETURN [FALSE]; WITH viewer.data SELECT FROM tdd: TEditDocument.TEditDocumentData => { IF TEditTouchup.LockAfterRefresh[tdd, "OnScreen"] THEN { ENABLE {UNWIND => TEditTouchup.UnlockAfterRefresh[tdd]}; lines: TEditDocument.LineTable _ tdd.lineTable; found: BOOL _ FALSE; IF lines # NIL AND lines.lastLine >= 4 THEN { first: TextNode.Location _ lines[1].pos; last: TextNode.Location _ lines[lines.lastLine-1].pos; each: TextNode.Ref _ first.node; IF point.node = first.node AND point.where < first.where THEN GO TO quickOut; IF point.node = last.node AND point.where > last.where THEN GO TO quickOut; WHILE each # NIL DO IF each = point.node THEN {found _ TRUE; EXIT}; IF each = last.node THEN EXIT; each _ TextNode.Forward[each].nx; ENDLOOP; EXITS quickOut => {}; }; TEditTouchup.UnlockAfterRefresh[tdd]; RETURN [found]; }; }; ENDCASE; RETURN [FALSE]; }; SetSel: PROC [viewer: ViewerClasses.Viewer, pos,len: INT, openName: ROPE _ NIL] = TRUSTED { WHILE viewer.iconic AND NOT viewer.destroyed DO ViewerOps.OpenIcon[viewer]; Process.Pause[Process.SecondsToTicks[1]]; ENDLOOP; IF viewer.destroyed THEN RETURN; IF oldSetSel THEN ViewerTools.SetSelection[viewer, NEW[ViewerTools.SelPosRec _ [pos, len]]] ELSE { x: TiogaOps.Ref _ TiogaOps.ViewerDoc[viewer]; loc1: TiogaOps.Location _ TiogaOps.LocRelative[location: [x, 0], count: pos, skipCommentNodes: skipComments]; loc2: TiogaOps.Location _ TiogaOps.LocRelative[location: loc1, count: len, skipCommentNodes: skipComments]; r: REF _ loc1.node; opaqueLoc: TextNode.Location _ [NARROW[r], loc1.where]; TiogaOps.SetSelection [ viewer: viewer, start: loc1, end: loc2, level: char, caretBefore: TRUE, pendingDelete: FALSE, which: feedback]; IF AutoScrollOK OR OnScreen[viewer, opaqueLoc] THEN TEditScrolling.AutoScroll[viewer: viewer, tryToGlitch: TRUE, id: feedback] ELSE TEditScrolling.ScrollToPosition[viewer, opaqueLoc]; }; }; NameToOpenViewer: PROC [name: ROPE, version: BcdDefs.VersionStamp, report: ReportProc, ignoreOnesBeingChanged: BOOL] RETURNS [viewer: ViewerClasses.Viewer _ NIL] = { short: ROPE _ NIL; IF version = BcdDefs.NullVersion THEN version _ FileVersion[name].version; short _ StripDir[name]; viewer _ FindViewer[fileName: short, version: version, ignoreOnesBeingChanged: ignoreOnesBeingChanged]; IF viewer = NIL OR viewer.destroyed THEN TRUSTED { Report[report, comment, " Opening ", name, "... "]; viewer _ TiogaMenuOps.Open[name]; }; IF viewer.iconic THEN ViewerOps.OpenIcon[viewer]; }; VersionExpectedMessage: PROC [version: BcdDefs.VersionStamp] RETURNS [ROPE] = { RETURN[IO.PutFR["source of %g expected", [time[BasicTime.FromNSTime[version.time]]]]]; }; SourceToFullName: PROC [source: Source, report: ReportProc] RETURNS [name: ROPE] = TRUSTED { fileVersion, sourceVersion: BcdDefs.VersionStamp _ BcdDefs.NullVersion; name _ AMModel.SourceFileName[source]; IF NOT Rope.Match["*.mesa*", name, FALSE] THEN name _ name.Concat[".mesa"]; sourceVersion _ AMModel.SourceVersion[source]; [name, fileVersion] _ FileVersion[name, sourceVersion]; IF fileVersion = sourceVersion THEN RETURN [name]; Report[report, comment, " (version map) "]; name _ VersionMapDefaults.FileNameFromVersion[$Source, sourceVersion]; }; StripDir: PROC [name: ROPE] RETURNS [Rope.Text] = { size,pos: INT _ name.Size[]; start: INT _ 0; WHILE (pos _ pos - 1) >= 0 DO SELECT name.Fetch[pos] FROM '! => EXIT; '. => {pos _ size; EXIT}; ENDCASE; ENDLOOP; start _ pos; WHILE start > 0 DO SELECT name.Fetch[start _ start - 1] FROM '/, '\\, '[, '], '<, '> => { start _ start + 1; EXIT}; ENDCASE; ENDLOOP; RETURN [name.Flatten[start, pos-start]]; }; FindViewer: PROC [ fileName: Rope.ROPE, version: BcdDefs.VersionStamp, ignoreOnesBeingChanged: BOOL] RETURNS[viewer: ViewerClasses.Viewer _ NIL] = { visit: SAFE PROC [v: ViewerClasses.Viewer] RETURNS [BOOL _ TRUE] = TRUSTED { vname: Rope.ROPE _ v.file; pos: INT; someSaveInProgress: PROC RETURNS[ans: BOOL _ FALSE] = CHECKED { vv: ViewerClasses.Viewer _ v; IF vv.saveInProgress THEN RETURN[TRUE]; WHILE (vv _ vv.link) # NIL AND (vv # v) DO IF vv.saveInProgress THEN RETURN[TRUE]; ENDLOOP; }; IF ignoreOnesBeingChanged AND (v.newVersion OR someSaveInProgress[]) THEN RETURN [TRUE]; IF vname = NIL THEN vname _ v.name; pos _ Rope.Find[vname, fileName, 0, FALSE]; IF pos >= 0 THEN { IF version # BcdDefs.NullVersion THEN { fileVersion: BcdDefs.VersionStamp = FileVersion[vname, version].version; IF fileVersion # version THEN RETURN [TRUE]; }; viewer _ v; RETURN [FALSE]; }; }; ViewerOps.EnumerateViewers[visit]; }; ShowLog: PUBLIC PROC [ fileName: Rope.ROPE, destroyIt: BOOL _ FALSE, createIconic: BOOL _ FALSE, blinkIfIconic: BOOL _ TRUE] = { logViewer: ViewerClasses.Viewer _ NIL; FileExists: PROC [fileName: Rope.ROPE] RETURNS[ans: BOOL _ TRUE] = { [] _ FS.FileInfo[fileName ! FS.Error => {ans _ FALSE; CONTINUE}]; }; CreateLog: PROC [fileName: Rope.ROPE, iconic: BOOL] RETURNS[viewer: ViewerClasses.Viewer] = { IF iconic THEN viewer _ ViewerOps.CreateViewer [flavor: $Text, info: [name: fileName, file: fileName, iconic: iconic, icon: typescript]] ELSE {viewer _ TiogaMenuOps.Open[fileName]; viewer.icon _ typescript}; }; logViewer _ FindViewer[fileName: fileName, version: BcdDefs.NullVersion, ignoreOnesBeingChanged: TRUE]; IF destroyIt THEN {IF logViewer # NIL THEN {ViewerOps.DestroyViewer[logViewer]; logViewer _ NIL}} ELSE { IF logViewer = NIL AND FileExists[fileName] THEN logViewer _ CreateLog[fileName: fileName, iconic: createIconic]; IF logViewer # NIL AND logViewer.iconic AND blinkIfIconic THEN ViewerOps.BlinkIcon[logViewer]; }; }; WaitUntilSaved: PUBLIC PROC [fileName: Rope.ROPE, feedBack: IO.STREAM _ NIL] = { viewer: ViewerClasses.Viewer _ NIL; viewer _ FindViewer[ fileName: fileName, version: BcdDefs.NullVersion, ignoreOnesBeingChanged: FALSE]; IF viewer # NIL AND viewer.newVersion THEN { SomeSaveInProgress: PROC RETURNS[ans: BOOL _ FALSE] = CHECKED { v: ViewerClasses.Viewer _ viewer; IF viewer.saveInProgress THEN RETURN[TRUE]; WHILE (v _ v.link) # NIL AND (v # viewer) DO IF v.saveInProgress THEN RETURN[TRUE]; ENDLOOP; }; IF feedBack # NIL AND NOT SomeSaveInProgress[] THEN feedBack.PutRope[Rope.Cat["***Please save ", viewer.name, "..."]]; UNTIL SomeSaveInProgress[] DO Process.Pause[Process.SecondsToTicks[1]]; ProcessExtras.CheckForAbort[]; ENDLOOP; IF feedBack # NIL AND SomeSaveInProgress[] THEN feedBack.PutRope[Rope.Cat["***Waiting for ", viewer.name, " to finish being saved..."]]; WHILE SomeSaveInProgress[] DO TRUSTED { Process.Pause[Process.SecondsToTicks[1]]; ProcessExtras.CheckForAbort[]; }; ENDLOOP; IF feedBack # NIL THEN feedBack.PutRope["ok\n"]; }; }; END. PAMViewerOpsImpl.mesa Russ Atkinson, October 13, 1983 1:36 pm Paul Rovner, December 15, 1983 11:44 am Useful types Global variables EXPORTS to AMViewerOps ... returns the selected viewer's name and the source index into the viewer. Returns [NIL, -1] if the selection is not in a valid Tioga viewer. ... returns a location for the given selection (primary or feedback); returns NIL if can't do it. If world = NIL then world _ LocalWorld. warn = TRUE => the version of the source file for the given location does not correspond to the viewer (although this is no guarantee that the wrong thing happened). returns BcdDefs.NullVersion if any errors occur (like missing file) gets the source file name and the source index for the given TV, which must be a local frame or global frame, if not successful, then name = NIL & index < 0 uses the results of GetSource to open a viewer on the source if index >= 0, then also sets the selection to the given index (for chars characters) OnScreen determines whether or not the given location is visible for the given viewer. Now we know that we have a Tioga document At this point tdd is really and truly locked up. We must release it at the end of the block or bad things will happen. returns NIL if the file is not available in the right source ... turns a long path name into a short path name, stripping off the version information and the directory, but preserving the extension. -- return TRUE to continue, FALSE to stop don't find viewers with changed contents or being saved just in case the file name is not present Same short name, so check the version stamp Κ˜šœ™Jšœ'™'Jšœ'™'—J˜šΟk ˜ Jšœ œ ˜Jšœœ˜šœ˜ Jšœ€˜€—Jšœœ?˜RJšœ œ˜)Jšœœ$œ˜5Jšœ œ˜Jšœ œœ!˜5Jšœœ˜*Jšœœ˜&Jšœœ˜Jšœœœ˜"Jšœœ˜&Jšœœ˜$Jšœœ,œ˜PJšœœ ˜3Jšœœ ˜4Jšœ œ(˜:Jšœ œ˜(Jšœ œ˜šœ ˜JšœU˜U—Jšœœ˜/Jšœœ ˜Jšœ œF˜UJšœ œ#˜4Jšœœ˜"J˜—J˜šΠblœœ˜Jšœγ˜κJšœ˜"Jšœœœ˜(J˜—šœ ™ J˜Jšœ œ˜ Jšœœ˜Jšœœœ˜Jšœœ œ˜Jšœœ˜J˜—™J˜Jšœ œœ˜Jšœœœ˜Jšœœœ˜Jšœœœ˜J˜Jšœœœ˜—J™šœ™J˜—šΟnœœ˜Jšœ.˜.Jšœ!œœ˜8Jšœœœ˜šœœœ˜J˜$Jšœ0˜0Jšœœ"˜,Jšœœ˜šœœœ˜Jšœ!˜!Jšœ˜—Jšœ.˜.šœ%œ˜-Jšœ*˜*Jšœ˜—Jšœ(˜(šœœœ˜Jšœ/˜/Jšœ˜—J˜Jšœ7œ˜=J˜šœ œ˜Jšœ"˜"Jšœ˜—J˜Jšœ œ˜ Jšœ˜—Jšœœ˜!Jšœ œœ˜"Jšœ œœ˜+J˜J˜—šŸœ ˜ Jšœ"˜"Jš œ œœ œ œ˜;Jšœ™Jšœœ˜#Jšœ˜šœ ˜ Jšœœœ œ ˜E—šœ œœœœœœ˜FJšœ/˜/šœœ˜ JšœQ˜Q—J˜Jšœ˜J˜—Jšœ˜J˜—šŸœœ˜!Jšœœ#˜6Jš œœ œœœœ˜UJšœ±™±Jšœœœ˜Jšœœ˜Jšœ+˜+Jšœ<˜Jšœ œœ˜-Jšœ˜—š œœœ˜Jšœ?œ˜GJšœ œœ œ(˜JJ˜—Jšœœœ˜J˜šœ˜ Jšœ,˜0Jšœ-˜1—J˜J˜—šŸœœ7œœ˜RJšœœ˜%J˜J˜J˜—šŸœœ:œœ˜ZJšœV™VJšœ œœœœœœ˜8Jš œœœœœ˜9šœ œ˜šœ)˜)Jšœ)™)šœ0œ˜8Jšœw™wJšœœ*˜8Jšœ/˜/Jšœœœ˜šœ œœœ˜-Jšœ(˜(Jšœ6˜6Jšœ ˜ Jš œœœœœ ˜MJš œœœœœ ˜Kšœœ˜Jšœœ œœ˜/Jšœœœ˜Jšœ!˜!Jšœ˜—Jšœ˜J˜—Jšœ%˜%Jšœ ˜J˜—J˜—Jšœ˜—Jšœœ˜J˜J˜—š Ÿœœ)œ œœœ˜[šœœœ˜/Jšœ˜J˜)Jšœ˜—Jšœœœ˜ šœ ˜ š˜Jšœ!œ%˜I—šœ˜Jšœ-˜-šœ˜JšœS˜S—šœ˜JšœQ˜Q—Jšœœ ˜Jšœ œ˜7˜JšœBœœ˜o—šœœ˜.Jšœ8œ˜OJšœ4˜8—Jšœ˜——J˜J˜—šŸœ˜JšœœKœ˜]Jšœ!œ˜0Jšœœœ˜Jšœœ%˜JJšœ˜šœ˜šœ˜Jšœ˜Jšœ5˜5——š œ œœœœ˜2Jšœ3˜3Jšœ!˜!Jšœ˜—Jšœœ˜1J˜J˜—šŸœœ!œœ˜OJšœœM˜VJ˜J˜—šŸœ˜Jšœ%œœœ˜EJšœ<™