DIRECTORY BackStop USING [Call], BasicTime USING [GMT, nullGMT], Convert, IO, LineNumber, 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, TEditDocument USING [SelectionId], TEditSelectionOps USING [ShowGivenPositionRange], 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, LineNumber, PFS, PFSNames, Rope, TEditSelectionOps, TiogaMenuOps, TiogaOps, ViewerOps, ViewerPrivate, ViewerTools EXPORTS SourceFileOps = BEGIN OPEN SourceFileOps; Position: TYPE ~ SourceFileOps.Position; ROPE: TYPE ~ Rope.ROPE; 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]; GetSelection: PUBLIC PROC [selection: SourceFileOps.WhichSelection ¬ primary] RETURNS [pos: Position, 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: LineNumber.LaORange; lineRange: Range; createVal: REF ANY ¬ TiogaOps.GetProp[root, $FileCreateDate]; IF createVal#NIL THEN { rgmt: REF BasicTime.GMT; TRUSTED {rgmt ¬ LOOPHOLE[createVal]}; --YUK! createUnique ¬ [[rgmt­, 0]]} 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 ¬ LineNumber.PositionsToLines[root, [charStart, charEnd], TRUE]; lineRange ¬ [MIN[lines.first.line, Index.LAST], MIN[lines.last.line, 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: Position, 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", FmtIdxs[pos], "."]; }; FormatPosition: PUBLIC PROC [pos: Position] 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.gmt=BasicTime.nullGMT THEN time ¬ "unspecified time" ELSE time ¬ Convert.RopeFromTime[pos.uniqueID.egmt.gmt, 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, " ", FmtIdxs[pos]]}; FmtIdxs: PUBLIC PROC [pos: Position] 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: Position, 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.gmt, 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, " couldn't open"]; 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 => LineNumber.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[]]; pathPrefixes: LIST OF ROPE ¬ LIST[NIL, 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. 4 SourceFileOpsViewersImpl.mesa Copyright Σ 1989, 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 September 11, 1992 9:38 am PDT Willie-s, February 14, 1992 6:19 pm PST Doug Wyatt, December 19, 1991 12:51 pm PST Philip James, February 14, 1992 9:34 am PST Some basic feedback operations on source files. This is the impl to use when Viewers is available. 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. commandsDir: ROPE ~ SystemNames.LocalDir["Commands"]; pathPrefixes: LIST OF ROPE ¬ LIST[NIL, commandsDir, systemDir]; 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]]; }; Κ {–(cedarcode) style•NewlineDelimiter ™codešœ™Kšœ Οeœ=™HK™+K™#K™-K™@K™'K™*K™+K˜K™c—˜šΟk ˜ Kšœ žœ˜Kšœ žœžœ ˜K˜Kšžœ˜K˜ KšžœžœP˜YKšœ žœžœC˜WKšœžœ$žœ˜4Kšœ˜Kšœžœ˜"Kšœžœ˜1Kšœ žœ˜Kšœ žœT˜bKšœžœ˜%Kšœ žœ˜-Kšœžœ˜%Kšœ žœ˜)K˜——K˜šΟnœžœž˜'Kšžœžœžœb˜Kšžœ˜Kšœžœžœ˜K˜—šœ ™ K˜Kšœ žœ˜(Kšžœžœžœ˜Kšžœžœ žœ˜Kšžœžœž œ˜Kšœžœ˜$K˜šœ žœ&˜4Kšœ!™!Kšœ#™#Kšœ,™,Kšœ4™4K˜—šŸ œžœžœžœ˜8KšœU™U—K˜K˜—K™šœ™K˜—K˜Kšœ žœžœ:˜Kšœ)žœžœ<˜ŠK˜š Ÿ œžœžœ5žœžœ˜yKšœ˜Kšœ˜Kšœl˜lKšœ.˜.šžœ žœžœžœžœžœžœ˜FKšœ/˜/Kšœžœ˜3Kšœžœ˜Kšœ˜K˜K˜Kšœ žœžœ+˜=šžœ žœžœ˜Kšœžœ žœ˜Kšžœ žœΟc˜,Kšœ˜—Kšžœ˜!Kšžœžœ žœ˜3KšœOžœ˜UKšœKžœ˜QKšœ@žœ˜FKš œ žœžœžœžœ˜RKšžœ žœ/˜BKšœ˜KšžœV˜\—Kšžœ˜K˜—š Ÿ œžœžœžœžœžœ+˜uKšœ žœ˜šΟbœ  (œ˜>Kšžœ žœžœ1˜GKšžœ˜—š‘œžœžœ˜Kšœ#žœ ˜4Kšžœ˜—Kšœžœžœ˜Kšœžœžœ˜K˜Kšžœžœžœ,˜;Kšžœžœžœ>˜MK˜—K˜š Ÿœžœžœžœžœ˜CKšœžœ˜"Kšœžœ˜šžœžœžœ ˜7Kšžœžœžœ žœ˜AKšžœ˜—šžœ(˜*Kšžœ˜KšžœDžœžœžœ˜q—KšžœžœžœH˜sKšžœžœžœn˜˜Kšžœ4˜:—K˜š Ÿœžœžœžœžœ˜7šžœžœž˜Kšœ žœ žœ˜6KšœžœžœG˜mKšœžœžœF˜lKšžœžœžœ˜•—K˜—šŸœžœžœ(žœžœžœžœ˜[Kšžœ žœžœ#˜=Kšžœžœžœ4˜SKšžœžœQ˜Z—K˜šŸœžœ7žœžœ˜Ršžœ žœžœ˜Kšœžœ˜%K˜K˜—K˜K˜—š Ÿ œžœ žœ žœžœ˜TK˜DKš žœ žœžœžœžœ˜#šž˜Kšžœžœžœžœ˜+Kšžœžœžœžœ˜-Kšžœ˜—Kšœ˜K˜—š Ÿœžœ=žœžœžœ˜†Kšœžœ˜šžœžœžœžœ˜2Kšœ+˜+Kšœ žœžœ˜(Kšœžœ˜šœ˜Kšœo˜o—š žœ žœžœžœžœ˜2Kšœžœžœžœ˜Jšžœžœ˜Kšœ žœ˜ K˜RK˜šžœ˜Kšœ7˜7K˜.—K˜—Kšœ˜—šžœžœžœžœ˜%šžœž˜#Kšœ ž˜ —šž˜K˜—K˜—šžœžœž˜Kšœžœ0žœžœ˜JKšœ—žœ1žœžœ˜ΨKš œZžœžœžœžœ˜Έ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š œžœžœžœžœžœ™?š œžœžœžœžœžœ ˜2Kšœ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˜——…—#ψ8§