<<>> <> <> <> <> <> <> <> <> <> <> 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}; < operation is completed>> < intermediate information>> < something is wrong, but not fatal>> < operation is completed, but did not succeed>> ReportProc: TYPE = PROC [msg: ROPE, severity: Severity]; <<... is the type of user-supplied procedure used to report results in above operations>> <<>> <> 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 { <<-- return TRUE to continue, FALSE to stop>> 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]; <> <<... then try the Commands subdirectory (stuff from Environment.df)>> <<... then try the default system directory (stuff from BootEssentials.df)>> 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.