DIRECTORY BackStop USING [Call], BasicTime USING [GMT, nullGMT], Convert, IO USING [PutRope, PutFR, PutFR1, STREAM], LineNumberExtras, PFS USING [Error, UniqueID, nullUniqueID, PathFromRope, RopeFromPath, FileInfo, GetWDir], PFSNames USING [PATH, Component, Cat, IsAbsolute, EmptyPath, ShortName, ComponentRope], Rope USING [Cat, Concat, Equal, Find, Length, ROPE], SourceFileOps, SourceFileOpsExtras, SystemNames USING [LocalDir], TEditDocument USING [SelectionId], TEditSelectionOps USING [ShowGivenPositionRange], TextNode USING [Ref], TiogaLies, TiogaMenuOps USING [Open], TiogaOps USING [GetProp, GetSelection, Location, LocOffset, Ref, Root, ViewerDoc, WhichSelection], ViewerClasses USING [Column, Viewer], ViewerOps USING [EnumerateViewers, OpenIcon], ViewerPrivate USING [rootViewerTree], ViewerTools USING [GetSelectionContents]; SourceFileOpsViewersImpl: CEDAR MONITOR IMPORTS BackStop, Convert, IO, LineNumberExtras, PFS, PFSNames, Rope, SystemNames, TEditSelectionOps, TiogaLies, TiogaMenuOps, TiogaOps, ViewerOps, ViewerPrivate, ViewerTools EXPORTS SourceFileOps, SourceFileOpsExtras = BEGIN OPEN SourceFileOpsExtras; FullPosition: TYPE ~ SourceFileOpsExtras.Position; ShortPosition: TYPE ~ SourceFileOps.Position; PATH: TYPE ~ PFSNames.PATH; STREAM: TYPE = IO.STREAM; Viewer: TYPE = ViewerClasses.Viewer; Severity: TYPE = {success, comment, warning, fatal}; ReportProc: TYPE = PROC [msg: ROPE, severity: Severity]; mySelectionToTiogaOpsSelection: ARRAY SourceFileOps.WhichSelection OF TiogaOps.WhichSelection = [primary, secondary, feedback]; mySelectionToTEditSelectionOpsSelection: ARRAY SourceFileOps.WhichSelection OF TEditDocument.SelectionId = [primary, secondary, feedback]; Expand: PROC [s: ShortPosition] RETURNS [FullPosition] ~ { RETURN [[s.fileName, nullUniqueID, s.index]]}; Restrict: PROC [f: FullPosition] RETURNS [ShortPosition] ~ { RETURN [[f.fileName, f.index]]}; GetSelection: PUBLIC PROC [selection: SourceFileOps.WhichSelection _ primary] RETURNS [ShortPosition] = {RETURN Restrict[FullGetSelection[selection].pos]}; FullGetSelection: PUBLIC PROC [selection: SourceFileOps.WhichSelection _ primary] RETURNS [pos: FullPosition, contents: ROPE] = { viewer: Viewer; start, end: TiogaOps.Location; [viewer: viewer, start: start, end: end] _ TiogaOps.GetSelection[mySelectionToTiogaOpsSelection[selection]]; contents _ ViewerTools.GetSelectionContents[]; IF viewer # NIL AND NOT viewer.destroyed AND NOT viewer.newFile THEN { root: TiogaOps.Ref _ TiogaOps.Root[start.node]; fileName: FileName _ PFS.PathFromRope[viewer.file]; charStart, charEnd: INT; createUnique: UniqueID; lines: LineNumberExtras.LineRange; lineRange: Range; createVal: REF ANY _ TiogaOps.GetProp[root, $FileCreateDate]; IF createVal#NIL THEN { rgmt: REF BasicTime.GMT; TRUSTED {rgmt _ LOOPHOLE[createVal]}; --YUK! createUnique _ [[rgmt^]]} ELSE createUnique _ nullUniqueID; IF fileName=PFSNames.EmptyPath THEN fileName _ NIL; charStart _ TiogaOps.LocOffset[loc1: [root, 0], loc2: start, skipCommentNodes: TRUE]; charEnd _ TiogaOps.LocOffset[loc1: [root, 0], loc2: end, skipCommentNodes: TRUE]; lines _ LineNumberExtras.PositionsToLines[TiogaLies.OpsRefToTextNodeRef[root], [charStart, charEnd], TRUE]; lineRange _ [MIN[lines.first, Index.LAST], MIN[lines.last, Index.LAST]]; IF start = end THEN {charEnd _ noIndex; lineRange.last _ noIndex}; SetHint[viewer]; RETURN [[fileName, createUnique, [char: [charStart, charEnd], line: lineRange]], contents]}; RETURN [noPosition, contents]}; OpenSource: PUBLIC PROC [desc: ROPE, pos: ShortPosition, feedBack: STREAM _ NIL, selection: WhichSelection _ feedback] = {FullOpenSource[desc, Expand[pos], feedBack, selection]}; FullOpenSource: PUBLIC PROC [desc: ROPE, pos: FullPosition, feedBack: STREAM _ NIL, selection: WhichSelection _ feedback] = { v: Viewer _ NIL; report: ReportProc--PROC [msg: ROPE, severity: Severity]-- = { IF feedBack # NIL THEN {feedBack.PutRope[msg]; feedBack.PutRope["\N"]}; RETURN}; inner: PROC = TRUSTED { ok _ NameToOpenViewer[pos, report, TRUE, selection]; RETURN}; ok: BOOL _ TRUE; err: ROPE _ NIL; err _ BackStop.Call[inner]; IF err#NIL THEN Report[report, fatal, " Can't open: ", err] ELSE IF ok THEN Report[report, success, " Source opened", FullFmtIdxs[pos], "."]; }; FormatPosition: PUBLIC PROC [pos: ShortPosition] RETURNS [Rope.ROPE] ~ {RETURN FullFormatPosition[Expand[pos]]}; FullFormatPosition: PUBLIC PROC [pos: FullPosition] RETURNS [Rope.ROPE] ~ { name: ROPE _ "a broken file name"; time: ROPE _ "a broken time"; IF pos.fileName#NIL AND pos.fileName#PFSNames.EmptyPath THEN name _ PFS.RopeFromPath[pos.fileName !PFS.Error => CONTINUE] ELSE name _ "an unnamed file"; IF pos.uniqueID.egmt.time=BasicTime.nullGMT THEN time _ "unspecified time" ELSE time _ Convert.RopeFromTime[pos.uniqueID.egmt.time, years, seconds, FALSE, FALSE !Convert.Error => CONTINUE]; IF pos.uniqueID.egmt.usecs#0 THEN time _ IO.PutFR["%g + %gus", [rope[time]], [cardinal[pos.uniqueID.egmt.usecs]] ]; IF pos.uniqueID.host#[0, 0] THEN time _ IO.PutFR["%g host [%xH, %xH]", [rope[time]], [cardinal[pos.uniqueID.host.a]], [cardinal[pos.uniqueID.host.b]] ]; RETURN name.Cat[" created at ", time, " ", FullFmtIdxs[pos]]}; FmtIdxs: PUBLIC PROC [pos: ShortPosition] RETURNS [ROPE] ~ {RETURN FullFmtIdxs[Expand[pos]]}; FullFmtIdxs: PUBLIC PROC [pos: FullPosition] RETURNS [ROPE] ~ { SELECT TRUE FROM pos.index = ALL[noRange] => RETURN [" (no position)"]; pos.index[line] = noRange => RETURN IO.PutFR1[" (%g)", [rope[FmtRange[pos.index[char], "char ", "chars "]]]]; pos.index[char] = noRange => RETURN IO.PutFR1[" (%g)", [rope[FmtRange[pos.index[line], "line ", "line "]]]]; ENDCASE => RETURN IO.PutFR[" (%g = %g)", [rope[FmtRange[pos.index[char], "char ", "chars "]]], [rope[FmtRange[pos.index[line], "line ", "line "]]]]}; FmtRange: PUBLIC PROC [r: Range, introSingular, introPlural: ROPE _ NIL] RETURNS [ROPE] ~ { IF r = noRange THEN RETURN introPlural.Concat["unspecified"]; IF r.last = noIndex THEN RETURN introSingular.Concat[Convert.RopeFromInt[r.first]]; RETURN IO.PutFR["%g%g..%g", [rope[introPlural]], [integer[r.first]], [integer[r.last]] ]}; Report: PROC [report: ReportProc, severity: Severity, r1,r2,r3,r4: ROPE _ NIL] = { IF report # NIL THEN { msg: ROPE _ Rope.Cat[r1, r2, r3, r4]; report[msg, severity]; }; }; ColumnLocked: PROC [column: ViewerClasses.Column] RETURNS [locked: BOOL _ FALSE] ~ { viewer: ViewerClasses.Viewer _ ViewerPrivate.rootViewerTree[column]; IF viewer = NIL THEN RETURN[FALSE]; DO IF viewer.lock.count > 0 THEN RETURN[TRUE]; IF (viewer _ viewer.sibling) = NIL THEN EXIT; ENDLOOP; }; NameToOpenViewer: PROC [pos: FullPosition, report: ReportProc, ignoreOnesBeingChanged: BOOL, selection: WhichSelection] RETURNS [BOOL] = { name: PATH ~ pos.fileName; IF name # NIL AND name # PFSNames.EmptyPath THEN { short: PFSNames.Component _ name.ShortName; nameRope: ROPE _ PFS.RopeFromPath[name]; viewer: Viewer _ NIL; viewer _ FindViewer[ fileName: short.ComponentRope, created: pos.uniqueID.egmt.time, ignoreOnesBeingChanged: ignoreOnesBeingChanged]; IF viewer = NIL OR viewer.destroyed THEN TRUSTED { column: ViewerClasses.Column _ IF ColumnLocked[left] THEN right ELSE left; IF ColumnLocked[column] THEN { viewer _ NIL; Report[report, warning, " Due to a locked column, ", nameRope, " wasn't opened."]; } ELSE { Report[report, comment, " Opening ", nameRope, "... "]; viewer _ TiogaMenuOps.Open[nameRope,, column]; }; }; IF viewer#NIL AND viewer.iconic THEN IF ColumnLocked[viewer.column] THEN viewer _ NIL ELSE ViewerOps.OpenIcon[viewer]; SELECT TRUE FROM viewer=NIL => { Report[report, warning, Rope.Concat[ " couldn't open; would have highlighted ", FullFmtIdxs[pos]]]; RETURN [FALSE]}; pos.index[char]#noRange => TEditSelectionOps.ShowGivenPositionRange[viewer, mySelectionToTEditSelectionOpsSelection[selection], pos.index[char].first, MAX[pos.index[char].first+3, pos.index[char].last], TRUE, FALSE]; pos.index[line]#noRange => LineNumberExtras.ToSelectionRange[viewer, [pos.index[line].first, IF pos.index[line].last=noIndex THEN pos.index[line].first ELSE pos.index[line].last], TRUE]; ENDCASE => NULL; RETURN [TRUE]}; RETURN [FALSE]}; FindViewer: PROC [fileName: Rope.ROPE, created: BasicTime.GMT, 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 v.class.flavor # $Text THEN RETURN [TRUE]; 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 created # BasicTime.nullGMT THEN { root: TiogaOps.Ref _ TiogaOps.ViewerDoc[v]; createVal: REF ANY _ TiogaOps.GetProp[root, $FileCreateDate]; IF createVal#NIL THEN { rgmt: REF BasicTime.GMT; TRUSTED {rgmt _ LOOPHOLE[createVal]}; --YUK! BasicTime.GMT is opaque IF rgmt^ # created THEN RETURN [TRUE]; } ELSE RETURN [TRUE]; }; viewer _ v; RETURN [FALSE]; }; }; viewer _ GetHint[fileName]; IF viewer # NIL AND NOT visit[viewer] THEN RETURN; viewer _ NIL; ViewerOps.EnumerateViewers[visit]; RETURN}; GetHint: PROC [name: ROPE] RETURNS [Viewer _ NIL] = { viewer: Viewer _ hintViewer; SELECT TRUE FROM viewer = NIL => {}; viewer.destroyed => {}; Rope.Equal[name, viewer.file, FALSE] => RETURN [viewer]; ENDCASE; RETURN [NIL]; }; SetHint: PROC [viewer: Viewer] = { hintViewer _ viewer }; hintViewer: Viewer _ NIL; systemDir: ROPE ~ PFS.RopeFromPath[PFS.GetWDir[]]; commandsDir: ROPE ~ SystemNames.LocalDir["Commands"]; pathPrefixes: LIST OF ROPE _ LIST[NIL, commandsDir, systemDir]; FullFileName: PROC [shortPath: PATH, uniqueID: PFS.UniqueID _ PFS.nullUniqueID] RETURNS [fullPath: PATH _ NIL] = { wPath: PATH; IF shortPath.IsAbsolute THEN RETURN [shortPath]; FOR paths: LIST OF ROPE _ pathPrefixes, paths.rest UNTIL paths = NIL DO ENABLE PFS.Error => IF error.group # bug THEN LOOP; wPath _ PFS.PathFromRope[paths.first]; fullPath _ shortPath.Cat[wPath]; RETURN [PFS.FileInfo[name: fullPath, wantedUniqueID: uniqueID ! PFS.Error => IF error.group # bug THEN LOOP ].fullFName]; ENDLOOP; }; END. nSourceFileOpsViewersImpl.mesa Copyright Ó 1989, 1990, 1991, 1992 by Xerox Corporation. All rights reserved. Linda Howe October 16, 1989 11:28:13 am PDT Coolidge, July 31, 1990 6:23 pm PDT Christian Jacobi, August 25, 1990 0:30 am PDT Last tweaked by Mike Spreitzer on April 9, 1992 8:09 am PDT Some basic feedback operations on source files. This is the impl to use when Viewers is available. Philip James, February 14, 1992 9:34 am PST Useful types success => operation is completed comment => intermediate information warning => something is wrong, but not fatal fatal => operation is completed, but did not succeed ... is the type of user-supplied procedure used to report results in above operations EXPORTS to CirioViewerOps -- return TRUE to continue, FALSE to stop Ignore non-text viewers 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 create date 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. first try the current default for the running process ... then try the Commands subdirectory (stuff from Environment.df) ... then try the default system directory (stuff from BootEssentials.df) returns NIL if not found checkThis: BOOL _ NeedsCheck[createTime, fullName]; NeedsCheck: PROC [createTime: BasicTime.GMT, fullName: ROPE] RETURNS [BOOL] = { No need to check unless date is unbound and the file is remote. If we change our policy on this here is the place to change it. RETURN [createTime = BasicTime.nullGMT AND NOT Rope.Match["[]*", fullName]]; }; Ê =˜codešœ™KšœN™NK™+K™#K™-K™;—K™™cK™K™+—˜šÏk ˜ Kšœ œ˜Kšœ œœ ˜K˜Kšœœœ˜*K˜KšœœP˜YKšœ œœC˜WKšœœ$œ˜4Kšœ˜Kšœ˜Kšœ œ ˜Kšœœ˜"Kšœœ˜1Kšœ œ˜K˜ Kšœ œ˜Kšœ œT˜bKšœœ˜%Kšœ œ˜-Kšœœ˜%Kšœ œ˜)K˜——K˜šÏnœœ˜'Kšœœœz˜®Kšœ#˜*Kšœœœ˜!K˜—šœ ™ K˜Kšœœ ˜2Kšœœ˜-Kšœœ œ˜Kšœœ œ˜Kšœœ˜$K˜šœ œ&˜4Kšœ!™!Kšœ#™#Kšœ,™,Kšœ4™4K˜—šž œœœœ˜8KšœU™U—K˜K˜—K™šœ™K˜—K˜Kšœ œœ:˜Kšœ)œœ<˜ŠK˜šžœœœ˜:Kšœ(˜.—šžœœœ˜Kšœ œœ1˜GKšœ˜—š œœœ˜Kšœ#œ ˜4Kšœ˜—Kšœœœ˜Kšœœœ˜K˜Kšœœœ,˜;KšœœœB˜QK˜—K˜š žœœœœœ˜DKšœœ"˜+—K˜š žœœœœœ˜KKšœœ˜"Kšœœ˜šœœœ ˜7Kšœœœ œ˜AKšœ˜—šœ)˜+Kšœ˜KšœEœœœ˜r—KšœœœH˜sKšœœœn˜˜Kšœ8˜>—K˜š žœœœœœ˜8Kšœœ˜$—K˜š ž œœœœœ˜?šœœ˜Kšœ œ œ˜6KšœœœG˜mKšœœœF˜lKšœœœ˜•—K˜—šžœœœ(œœœœ˜[Kšœ œœ#˜=Kšœœœ4˜SKšœœQ˜Z—K˜šžœœ7œœ˜Ršœ œœ˜Kšœœ˜%K˜K˜—K˜K˜—š ž œœ œ œœ˜TKšœD˜DKš œ œœœœ˜#š˜Kšœœœœ˜+Kšœœœœ˜-Kšœ˜—Kšœ˜K˜—š žœœAœœœ˜ŠKšœœ˜šœœœœ˜2Kšœ+˜+Kšœ œœ˜(Kšœœ˜šœ˜Kšœp˜p—š œ œœœœ˜2KšœJ˜Jšœœ˜Kšœ œV˜bšœ˜Kšœ7˜7Kšœ.˜.—K˜—Kšœ˜—šœœœ˜$šœ˜#Kšœ ˜ —š˜K˜——šœœ˜šœœ˜šœ$˜$Kšœ*˜*Kšœ˜—Kšœœ˜—Kšœ—œ1œœ˜ØKš œ]œœœœ˜ºKšœœ˜—Kšœœ˜—Kšœœ˜K˜—šž œœœœœ œœ˜š œœœ œœœœ˜>KšŸ)™)Kšœ œ ˜Kšœœ˜ š œœœœœœ˜AKšœ˜Kšœœœœ˜'šœœœ ˜*Kšœœœœ˜'Kšœ˜—K˜—šœœœœ˜-K™—šœœœ˜DKšœœœ˜Kšœ7™7—šœ œœ˜#Kšœ)™)—Kšœœœœ˜.Kšœ$œ˜+šœ œ˜Kšœ)™)šœœ˜%Kšœ+˜+Kšœ œœ+˜=šœ œœ˜Kšœœ œ˜Kšœ œŸ˜DKšœœœœ˜&K˜—Kšœœœ˜K˜—Kšœ ˜ Kšœœ˜K˜—Kšœ˜—Kšœ˜Kš œ œœœœœ˜2Kšœ œ˜ Kšœ"˜"Kšœ˜K˜—š žœœœœ œ˜5Kšœ‰™‰Kšœ˜šœœ˜Kšœ œ˜Kšœ˜Kšœœœ ˜8Kšœ˜—Kšœœ˜ K˜K˜—šžœœ˜"Kšœ˜K˜K˜—Kšœœ˜K˜Kšœ œœœ ˜2Kšœ œ$˜5K˜š œœœœœœ˜?Kšœ5™5K™BK™HK˜—šž œœ œ œ œœ œœ˜rK™Kšœœ˜ Kšœœœ ˜0š œœœœœ œ˜GKš œœ œœœ˜3Kšœœ˜&K˜ Kšœ œ$™3šœœ2˜=Kšœœ œœ˜-Kšœ ˜ —Kšœ˜—Kšœ˜—K˜š ž œœœ œœœ™OK™€Kšœ!œœ™LK™—K˜K˜K˜šœ˜K˜K˜—J˜—…—(ˆ=3