<> <> DIRECTORY Feedback, FileNames, FS, GGBasicTypes, GGContainer, GGEvent, GGFileIn, GGFileOps, GGFont, GGInterfaceTypes, GGUserInput, GGModelTypes, GGScene, GGSegmentTypes, GGWindow, GList, Imager, IO, Match, MatchGrep, MatchTurtle, MatchViewer, Rope, SlackProcess, ViewerClasses, ViewerOps; MatchGrepImpl: CEDAR PROGRAM IMPORTS Feedback, FileNames, FS, GGEvent, GGFileIn, GGFileOps, GList, GGScene, GGWindow, IO, Match, MatchViewer, Rope, ViewerOps EXPORTS MatchGrep = BEGIN <> <> <> <> <> <> <> GGData: TYPE = GGInterfaceTypes.GGData; <> <> <> <> Point: TYPE = GGBasicTypes.Point; <> <> <> <> <> <> Scene: TYPE = GGModelTypes.Scene; <> <> <> <> <> <> <> <> <> <> <<>> fileList: LIST OF Rope.ROPE _ NIL; Grep: PUBLIC GGUserInput.UserInputProc = { <> FillFileList: FS.NameProc = { fileList _ CONS[fullFName, fileList]; RETURN[TRUE];}; grepData: GGData _ MatchViewer.GetGrepData[]; pattern: Rope.ROPE _ NARROW[event.rest.first]; IF pattern = NIL OR pattern = "" THEN MatchViewer.ErrorFeedback["Must select a filename pattern"] ELSE { fileList _ NIL; IF Rope.Index[pattern, 0, "!"] >= Rope.Length[pattern] THEN pattern _ Rope.Concat[pattern, "!H"]; -- if they don't specify a version, only enumerate the last FS.EnumerateForNames[pattern, FillFileList ! FS.Error => { mesg: Rope.ROPE _ IO.PutFR["Invalid filename pattern: %g", IO.rope[pattern]]; MatchViewer.ErrorFeedback[mesg]; GOTO Abort; };]; IF fileList = NIL THEN MatchViewer.ErrorFeedback["No files match the pattern."] ELSE { fileList _ NARROW[GList.DReverse[fileList]]; -- back in order of enumeration FOR files: LIST OF Rope.ROPE _ fileList, files.rest UNTIL files = NIL DO fileList _ files.rest; IF GrepFile[files.first, TRUE] THEN { SpawnViewer[grepData, files.first]; RETURN; }; ENDLOOP; MatchViewer.ErrorFeedback["No matches."]; }; }; EXITS Abort => Feedback.Blink[MatchViewer.GetToData[].feedback]; }; GrepListOnly: PUBLIC GGUserInput.UserInputProc = { <> FillFileList: FS.NameProc = { fileList _ CONS[fullFName, fileList]; RETURN[TRUE];}; matchData: MatchViewer.MatchData _ MatchViewer.GetMatchData[]; grepData: GGData _ MatchViewer.GetGrepData[]; pattern: Rope.ROPE _ NARROW[event.rest.first]; IF pattern = NIL OR pattern = "" THEN MatchViewer.ErrorFeedback["Must select a filename pattern"] ELSE { fileList _ NIL; IF Rope.Index[pattern, 0, "!"] >= Rope.Length[pattern] THEN pattern _ Rope.Concat[pattern, "!H"]; -- if they don't specify a version, only enumerate the last FS.EnumerateForNames[pattern, FillFileList ! FS.Error => { mesg: Rope.ROPE _ IO.PutFR["Invalid filename pattern: %g", IO.rope[pattern]]; MatchViewer.ErrorFeedback[mesg]; GOTO Abort; };]; IF fileList = NIL THEN MatchViewer.ErrorFeedback["No files match the pattern."] ELSE { fileList _ NARROW[GList.DReverse[fileList]]; -- back in order of enumeration FOR files: LIST OF Rope.ROPE _ fileList, files.rest UNTIL files = NIL DO IF GrepFile[files.first, TRUE] THEN IO.PutF[matchData.commander.out, "\n%g matched.", IO.rope[files.first]]; ENDLOOP; MatchViewer.ErrorFeedback["No matches."]; }; }; EXITS Abort => Feedback.Blink[MatchViewer.GetToData[].feedback]; }; GrepFile: PROC [fullFName: Rope.ROPE, verbose: BOOL _ TRUE] RETURNS [found: BOOL] = { <> grepData: GGData _ MatchViewer.GetGrepData[]; fullName: Rope.ROPE; success, versionSpecified: BOOL; [fullName, success, versionSpecified] _ GGFileOps.GetGargoyleFileName[fullFName, NIL, grepData.feedback, FALSE]; IF NOT success THEN { mesg: Rope.ROPE _ IO.PutFR["Couldn't load %g.\n", IO.rope[fullName]]; IF verbose THEN MatchViewer.ErrorFeedback[mesg]; RETURN[FALSE]; } ELSE { matchData: MatchViewer.MatchData _ MatchViewer.GetMatchData[]; f: FS.STREAM; IF verbose THEN Feedback.PutFHerald[grepData.feedback, oneLiner, "Loading %g.", IO.rope[fullName]]; f _ FS.StreamOpen[fullName, $read ! FS.Error, IO.Error => { msgRope: Rope.ROPE _ IO.PutFR["Could not find: %g", [rope[fullName]]]; Feedback.Append[grepData.feedback, msgRope, oneLiner]; GOTO Abort; };]; grepData.scene _ GGScene.CreateScene[]; -- give GGData a new clean slate/scene [] _ GGFileIn.FileinSceneOnly[f, grepData.scene]; f.Close[]; IF verbose THEN Feedback.PutFHerald[grepData.feedback, oneLiner, "Searching %g.", IO.rope[fullName]]; <> matchData.theirData _ NIL; -- force a reset of search lists success _ Match.Search[grepData, LIST[$MatchSearch, $SearchFromTop], FALSE]; IF success THEN { IF verbose THEN MatchViewer.ErrorFeedback["It matched!!!"]; RETURN [TRUE]; }; RETURN[FALSE]; }; EXITS Abort => { Feedback.Blink[MatchViewer.GetToData[].feedback]; RETURN[FALSE]; }; }; NextFile: PUBLIC GGUserInput.UserInputProc = { grepData: GGData _ MatchViewer.GetGrepData[]; IF fileList = NIL THEN MatchViewer.ErrorFeedback["No more file matches."] ELSE { FOR files: LIST OF Rope.ROPE _ fileList, files.rest UNTIL files = NIL DO fileList _ files.rest; IF GrepFile[files.first, TRUE] THEN { SpawnViewer[grepData, files.first]; RETURN; }; ENDLOOP; MatchViewer.ErrorFeedback["No more file matches."]; }; }; lastSpawned: GGData _ NIL; SpawnViewer: PROC [ggData: GGData, fileName: Rope.ROPE] = { <> f: FS.STREAM _ FS.StreamOpen[fileName, $read ! FS.Error, IO.Error => { msgRope: Rope.ROPE _ IO.PutFR["Could not find: %g", [rope[fileName]]]; Feedback.Append[ggData.feedback, msgRope, oneLiner]; GOTO Abort; };]; IF lastSpawned = NIL OR lastSpawned.outer.newVersion THEN { -- we create a gargoyle viewer lastSpawned _ GGWindow.CreateWindow[ggData.scene, TRUE, FALSE, fileName]; [] _ GGFileIn.FileinSceneAndOptions[f, lastSpawned, $OptionsOnly]; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintEntireScene, ggData: lastSpawned, remake: triggerBag, backgndOK: FALSE, edited: FALSE, okToClearFeedback: FALSE]; ViewerOps.OpenIcon[lastSpawned.outer]; MatchViewer.CenterSel[NIL, lastSpawned]; -- this may not happen, since OpenIcon is async. } ELSE { -- we use the old unedited viewer lastSpawned.scene _ ggData.scene; [] _ GGFileIn.FileinSceneAndOptions[f, lastSpawned, $OptionsOnly]; MatchViewer.CenterSel[NIL, lastSpawned]; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintEntireScene, ggData: lastSpawned, remake: triggerBag, backgndOK: FALSE, edited: FALSE, okToClearFeedback: FALSE]; }; <> lastSpawned.outer.file _ FileNames.StripVersionNumber[fileName]; lastSpawned.outer.label _ FileNames.GetShortName[path: fileName]; lastSpawned.outer.name _ fileName; GGEvent.ChangeIcon[lastSpawned, $clean]; -- will also repaint the label EXITS Abort => ERROR; -- we've already opened fileName prior to this, so something's screwy }; <<>> END.