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, TV, TVType, UnderClass], 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], Rope USING [Cat, Concat, Equal, Fetch, Find, Flatten, Length, Match, ROPE, Size, Text], TEditDocument USING [LineTable, TEditDocumentData], TEditSelectionOps USING [ShowGivenPosition], TEditTouchup USING [LockAfterRefresh, UnlockAfterRefresh], TextNode USING [Forward, Location, Ref], TiogaMenuOps USING [Open], TiogaOps USING [GetSelection, Location, LocOffset, Ref, Root], VersionMapDefaults USING [FileNameFromVersion], ViewerClasses USING [Viewer], ViewerEvents USING [EventProc, EventRegistration, RegisterEventProc, UnRegisterEventProc], ViewerOps USING [EnumerateViewers, OpenIcon], WorldVM USING [LocalWorld, World]; AMViewerOpsImpl: CEDAR MONITOR IMPORTS AMBridge, AMFiles, AMModel, AMModelBridge, AMTypes, BackStop, BasicTime, FS, IO, Rope, TEditSelectionOps, TEditTouchup, TextNode, TiogaMenuOps, TiogaOps, VersionMapDefaults, ViewerEvents, ViewerOps, WorldVM EXPORTS AMViewerOps, FileViewerOps = BEGIN OPEN AMViewerOps, FileViewerOps; Context: TYPE = AMModel.Context; Section: TYPE = AMModel.Section; Source: TYPE = AMModel.Source; ROPE: TYPE = Rope.ROPE; TV: TYPE = AMTypes.TV; VersionStamp: TYPE = BcdDefs.VersionStamp; NullVersion: VersionStamp = BcdDefs.NullVersion; Viewer: TYPE = ViewerClasses.Viewer; World: TYPE = WorldVM.World; ViewerFromSection: PUBLIC PROC [section: Section, report: ReportProc] RETURNS [viewer: Viewer _ NIL] = TRUSTED { errmsg: ROPE _ NIL; inner: PROC = TRUSTED { sourceVersion: 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 = 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 selection"; WITH s: source^ SELECT FROM field => start _ s.firstCharIndex; ENDCASE; viewer _ NameToOpenViewer[name, sourceVersion, report, TRUE, start]; IF viewer = NIL THEN RETURN; 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] = { viewer: 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: TRUE]; index _ offset; fileName _ viewer.file; SetHint[viewer]; }; }; SectionFromSelection: PUBLIC PROC [world: World _ NIL, which: SelectionOption _ primary] RETURNS [section: Section _ NIL, contexts: LIST OF Context _ NIL] = { 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 Context _ NIL] = TRUSTED { shortName: ROPE _ StripDir[name]; IF Rope.Length[shortName] # 0 THEN { sourceVersion: VersionStamp _ FileVersion[name].version; source: Source _ NIL; context: 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: VersionStamp _ NullVersion] RETURNS [fullName: ROPE _ NIL, version: VersionStamp _ NullVersion] = { gmt: BasicTime.GMT = IF desiredVersion = 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: Viewer _ NIL; report: ReportProc--PROC [msg: ROPE, severity: Severity]-- = { IF feedBack # NIL THEN feedBack.PutRope[msg]; }; inner: PROC = TRUSTED { viewer _ NameToOpenViewer[fileName, NullVersion, report, TRUE, index]; }; 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: 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]; }; NameToOpenViewer: PROC [name: ROPE, version: VersionStamp, report: ReportProc, ignoreOnesBeingChanged: BOOL, index: INT] RETURNS [viewer: Viewer _ NIL] = { IF Rope.Length[name] # 0 THEN { short: ROPE _ NIL; IF version = 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[IO.PutFR["%g|%g", [rope[name]], [integer[index]] ]]; RETURN; }; IF viewer.iconic THEN ViewerOps.OpenIcon[viewer]; TEditSelectionOps.ShowGivenPosition[viewer, index]; }; }; VersionExpectedMessage: PROC [version: VersionStamp] RETURNS [ROPE] = { RETURN[IO.PutFR["source of %g expected", [time[BasicTime.FromNSTime[version.time]]]]]; }; SourceToFullName: PROC [source: Source, report: ReportProc] RETURNS [ROPE] = TRUSTED { fileVersion, sourceVersion: VersionStamp _ NullVersion; name: ROPE _ 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) "]; RETURN [VersionMapDefaults.FileNameFromVersion[$Source, sourceVersion].name]; }; StripDir: PROC [name: ROPE] RETURNS [Rope.Text] = { size,pos: INT _ Rope.Size[name]; start: INT _ 0; DO IF pos = 0 THEN {pos _ size; EXIT}; pos _ pos - 1; SELECT Rope.Fetch[name, pos] FROM '! => EXIT; '. => {pos _ size; EXIT}; ENDCASE; ENDLOOP; start _ pos; WHILE start > 0 DO SELECT Rope.Fetch[name, start _ start - 1] FROM '/, '\\, '[, '], '<, '> => { start _ start + 1; EXIT}; ENDCASE; ENDLOOP; RETURN [Rope.Flatten[name, start, pos-start]]; }; FindViewer: PROC [fileName: Rope.ROPE, version: VersionStamp, ignoreOnesBeingChanged: BOOL] RETURNS [viewer: Viewer _ NIL] = { visit: SAFE PROC [v: Viewer] RETURNS [BOOL _ TRUE] = TRUSTED { vname: Rope.ROPE _ v.file; pos: INT; someSaveInProgress: PROC RETURNS[ans: BOOL _ FALSE] = CHECKED { vv: 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; IF Rope.Length[vname] = 0 THEN RETURN [FALSE]; pos _ Rope.Find[vname, fileName, 0, FALSE]; IF pos >= 0 THEN { IF version # NullVersion THEN { fileVersion: VersionStamp = FileVersion[vname, version].version; IF fileVersion # version THEN RETURN [TRUE]; }; viewer _ v; RETURN [FALSE]; }; }; viewer _ GetHint[fileName]; IF viewer # NIL AND NOT visit[viewer] THEN RETURN; viewer _ NIL; ViewerOps.EnumerateViewers[visit]; }; GetHint: ENTRY PROC [name: ROPE] RETURNS [Viewer _ NIL] = { SELECT TRUE FROM hintViewer = NIL => {}; hintViewer.destroyed => hintViewer _ NIL; Rope.Equal[name, hintName, FALSE] => RETURN [hintViewer]; ENDCASE; RETURN [NIL]; }; SetHint: ENTRY PROC [viewer: Viewer] = { IF hintRegistration # NIL THEN { ViewerEvents.UnRegisterEventProc[hintRegistration, destroy]; hintRegistration _ NIL; }; IF viewer = NIL THEN hintName _ NIL ELSE hintName _ viewer.file; hintViewer _ viewer; IF viewer # NIL THEN { hintRegistration _ ViewerEvents.RegisterEventProc[FlushHint, destroy, viewer, TRUE]; }; }; FlushHint: ViewerEvents.EventProc = { SetHint[NIL]; }; hintName: ROPE _ NIL; hintViewer: Viewer _ NIL; hintRegistration: ViewerEvents.EventRegistration _ NIL; END. ζAMViewerOpsImpl.mesa Copyright c 1985, 1986 by Xerox Corporation. All rights reserved. Russ Atkinson (RRA) March 31, 1986 7:54:46 pm PST Useful types 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 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 We keep a hint which indicates the last viewer we used to make a selection. If that viewer is no longer valid (NIL or destroyed), or if it does not have the same short file name as the one we are seeking, then we return NIL. Otherwise the hint has saved us some valuable time, and we are more likely to find the selected viewer if we have multiple viewers or split viewers for the same file. ΚH˜codešœ™Kšœ Οmœ7™BK™1—˜šΟk ˜ Kšœ žœ ˜Kšœžœ˜Kšœžœ˜ŽKšœžœ?˜RKšœ žœ˜)Kšœžœžœ˜5Kšœ žœ˜Kšœ žœžœ!˜5Kšœžœ˜*Kšœžœ˜&Kšžœžœ˜Kšžœžœžœ˜"Kšœžœ;žœ˜WKšœžœ ˜3Kšœžœ˜,Kšœ žœ(˜:Kšœ žœ˜(Kšœ žœ˜Kšœ žœ0˜>Kšœžœ˜/Kšœžœ ˜Kšœ žœH˜ZKšœ žœ˜-Kšœžœ˜"K˜——K˜šΠblœžœž˜KšžœJžœžœ˜ΦKšžœ˜"Kšœžœžœ˜(K˜—šœ ™ K˜Kšœ žœ˜ Kšœ žœ˜ Kšœžœ˜Kšžœžœžœ˜Kšžœžœ žœ˜šœžœ˜*Kšœ0˜0—Kšœžœ˜$Kšœžœ˜—K™šœ™K˜—š Οnœžœžœ'žœžœžœ˜pKšœžœžœ˜šœžœžœ˜Kšœ˜Kšœ0˜0Kšœžœ"˜,Kšœžœ˜šžœžœžœ˜Kšœ!˜!Kšžœ˜—Kšœ.˜.šžœžœ˜%Kšœ*˜*Kšžœ˜—Kšœ(˜(šžœžœžœ˜Kšœ/˜/Kšžœ˜—K˜šžœ žœž˜Kšœ"˜"Kšžœ˜—Kšœ7žœ ˜DKšžœ žœžœžœ˜Kšœ žœ˜ Kšœ˜—Kšœžœ˜!Kšžœ žœžœ˜"Kšžœ žœžœ˜+K˜K˜—š  œž œ#žœ žœžœ žœ ˜wKšœ™Kšœžœ˜Kšœ˜šœ ˜ Kšœžœžœ žœ ˜E—šžœ žœžœžœžœžœžœ˜FKšœ/˜/šœžœ˜ KšœCžœ˜I—K˜Kšœ˜Kšœ˜K˜—Kšœ˜K˜—š œžœžœžœ#žœžœ žœžœ žœ˜žKšœ±™±Kšœžœžœ˜Kšœžœ˜Kšœ+˜+Kšœ<˜Kšžœ žœžœ˜-Kšœ˜—š‘œžœžœ˜Kšœ9žœ ˜FK˜—Kšœžœžœ˜K˜šžœž˜ Kšžœ,˜0Kšžœ-˜1—K˜K˜—š œžœ7žœžœ˜RKšœžœ˜%K˜K˜K˜—š œžœ,žœžœ˜LKšœV™VKšžœ žœžœžœžœžœžœ˜8Kš žœžœžœžœžœ˜9šžœ žœž˜šœ)˜)Kšœ)™)šžœ0žœ˜8Kšœw™wKšžœžœ*˜8Kšœ/˜/Kšœžœžœ˜šžœ žœžœžœ˜-Kšœ(˜(Kšœ6˜6Kšœ ˜ Kš žœžœžœžœžœ ˜MKš žœžœžœžœžœ ˜Kšžœžœž˜Kšžœžœ žœžœ˜/Kšžœžœžœ˜Kšœ!˜!Kšžœ˜—Kšžœ˜K˜—Kšœ%˜%Kšžœ ˜K˜—K˜—Kšžœ˜—Kšžœžœ˜K˜K˜—š œžœžœEžœ žœžœžœ˜›šžœžœ˜Kšœžœžœ˜Kšžœžœ%˜BKšœ˜šœ˜KšœS˜S—š žœ žœžœžœžœ˜2Kšœ3˜3Kšœžœ2˜OKšžœ˜Kšœ˜—Kšžœžœ˜1Kšœ3˜3K˜—K˜K˜—š œžœžœžœ˜GKšžœžœM˜VK˜K˜—š  œžœ&žœžœžœ˜VKšœ<™K™)Kšœ žœ ˜Kšœžœ˜ š  œžœžœžœžœžœ˜@Kšœ˜Kšžœžœžœžœ˜'šžœžœžœ ž˜*Kšžœžœžœžœ˜'Kšžœ˜—K˜—šžœžœžœ˜DKšžœžœžœ˜Kšœ7™7—šžœ žœžœ˜#Kšœ)™)—Kšžœžœžœžœ˜.Kšœ$žœ˜+šžœ žœ˜Kšœ+™+šžœžœ˜Kšœ@˜@Kšžœžœžœžœ˜,K˜—Kšœ ˜ Kšžœžœ˜K˜—Kšœ˜—Kšœ˜Kš žœ žœžœžœžœžœ˜2Kšœ žœ˜ Kšœ"˜"K˜K˜—š  œžœžœžœžœ žœ˜;Kšœ‰™‰šžœžœž˜Kšœ žœ˜Kšœ%žœ˜)Kšœžœžœ˜9Kšžœ˜—Kšžœžœ˜ K˜K˜—š œžœžœ˜(šžœžœžœ˜ Kšœ<˜