MatchGrep.mesa
Last edited by: David Kurlander - September 6, 1987 5:18:03 pm PDT
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
BitVector: TYPE = GGBasicTypes.BitVector;
BoundBox: TYPE = GGModelTypes.BoundBox;
Caret: TYPE = REF CaretObj;
CaretObj: TYPE = GGInterfaceTypes.CaretObj;
ChoiceData: TYPE = MatchViewer.ChoiceData;
FontData: TYPE = GGFont.FontData;
GGDataObj: TYPE = GGInterfaceTypes.GGDataObj;
GGData: TYPE = GGInterfaceTypes.GGData;
ItemMatch: TYPE = Match.ItemMatch;
LooksInfo: TYPE = Match.LooksInfo;
MatchData: TYPE = MatchViewer.MatchData;
MatchDescriptor: TYPE = Match.MatchDescriptor;
Point: TYPE = GGBasicTypes.Point;
SearchInfo: TYPE = Match.SearchInfo;
SearchState: TYPE = Match.SearchState;
Segment: TYPE = GGSegmentTypes.Segment;
SegmentGenerator: TYPE = GGModelTypes.SegmentGenerator;
Sequence: TYPE = GGModelTypes.Sequence;
SequenceOfReal: TYPE = GGModelTypes.SequenceOfReal;
Scene: TYPE = GGModelTypes.Scene;
Slice: TYPE = GGModelTypes.Slice;
SliceDescriptor: TYPE = GGModelTypes.SliceDescriptor;
SliceDescriptorGenerator: TYPE = GGModelTypes.SliceDescriptorGenerator;
SliceDescriptorObj: TYPE = GGModelTypes.SliceDescriptorObj;
SliceGenerator: TYPE = GGModelTypes.SliceGenerator;
SliceParts: TYPE = REF ANY;
Traj: TYPE = GGModelTypes.Traj;
TrajGenerator: TYPE = GGModelTypes.TrajGenerator;
TurtleHeader: TYPE = MatchTurtle.TurtleHeader;
TurtleInfo: TYPE = MatchTurtle.TurtleInfo;
fileList: LIST OF Rope.ROPENIL;
Grep: PUBLIC GGUserInput.UserInputProc = {
The interactive grep (compared to GrepListOnly). Invokes a gargoyle viewer on the matched scene file.
FillFileList: FS.NameProc = { fileList ← CONS[fullFName, fileList]; RETURN[TRUE];};
grepData: GGData ← MatchViewer.GetGrepData[];
pattern: Rope.ROPENARROW[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.ROPEIO.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 = {
Greps for graphical matches, only printing out their names in the invoker commander when there's a hit.
FillFileList: FS.NameProc = { fileList ← CONS[fullFName, fileList]; RETURN[TRUE];};
matchData: MatchViewer.MatchData ← MatchViewer.GetMatchData[];
grepData: GGData ← MatchViewer.GetGrepData[];
pattern: Rope.ROPENARROW[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.ROPEIO.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: BOOLTRUE] RETURNS [found: BOOL] = {
Returns true if there is a match between the MatchTool From viewer and the gargoyle scene file described by fullFName.
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.ROPEIO.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.ROPEIO.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]];
Now do search
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] = {
Creates a gargoyle viewer, stuffs the scene from ggData into that Gargoyle viewer, and loads the various scene state info (from fileName)
f: FS.STREAMFS.StreamOpen[fileName, $read ! FS.Error, IO.Error => {
msgRope: Rope.ROPEIO.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];
};
Now change the viewer file, label, and name
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.