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