DIRECTORY BasicTime, FS, Feedback, GGEvent, GGInterfaceTypes, GGBasicTypes, GGSessionLog, GGState, GGUserInput, GGUtility, GGWindow, IO, Rope, SessionLog, SlackProcess; GGSessionLogImpl: CEDAR PROGRAM IMPORTS BasicTime, FS, Feedback, GGEvent, GGState, GGUserInput, GGUtility, GGWindow, IO, Rope, SessionLog, SlackProcess EXPORTS GGSessionLog = BEGIN CharClass: TYPE = IO.CharClass; GGData: TYPE = GGInterfaceTypes.GGData; Point: TYPE = GGBasicTypes.Point; OpenScript: PUBLIC PROC [fileName: Rope.ROPE, ggData: GGData] = { stream: IO.STREAM; fullName: Rope.ROPE; success: BOOL _ FALSE; IF ggData.debug.logStream#NIL THEN CloseScript[ggData]; [fullName, success] _ GGUtility.GetScriptFileName[fileName, ggData.currentWDir, ggData.feedback]; IF NOT success THEN RETURN; stream _ FS.StreamOpen[fullName, $create ! FS.Error => GOTO FSError]; ggData.debug.logFileName _ fullName; ggData.debug.logStream _ stream; GGEvent.InitializeAlignments[ggData, NIL]; Feedback.Append[ggData.feedback, Rope.Cat["Opened ", fullName, " for scripting"], oneLiner]; CaptureSessionState[ggData]; EXITS FSError => {Feedback.Append[ggData.feedback, Rope.Concat["FSError while trying ", fileName], oneLiner]; Feedback.Blink[ggData.feedback];}; }; AppendScript: PUBLIC PROC [fileName: Rope.ROPE, ggData: GGData] = { stream: IO.STREAM; fullName: Rope.ROPE; success: BOOL _ FALSE; IF ggData.debug.logStream#NIL THEN CloseScript[ggData]; [fullName, success] _ GGUtility.GetScriptFileName[fileName, ggData.currentWDir, ggData.feedback]; IF NOT success THEN RETURN; stream _ FS.StreamOpen[fullName, $append ! FS.Error => GOTO FSError]; ggData.debug.logFileName _ fullName; ggData.debug.logStream _ stream; Feedback.Append[ggData.feedback, Rope.Cat["Opened ", fullName, " for appending"], oneLiner]; EXITS FSError => {Feedback.Append[ggData.feedback, Rope.Concat["FSError while trying ", fileName], oneLiner]; Feedback.Blink[ggData.feedback];}; }; CaptureSessionState: PROC [ggData: GGData] = { gravExtent: REAL; showColors, gravityOn, midpointsOn, heuristicsOn: BOOL; showColors _ GGState.GetShowColors[ggData]; EnterAction[ggData, LIST[$SetShowColors, IF showColors THEN "T" ELSE "F"]]; gravExtent _ GGWindow.GetGravityExtent[ggData]; EnterAction[ggData, LIST[$SetGravityExtent, NEW[REAL _ gravExtent]]]; gravityOn _ GGState.Gravity[ggData]; EnterAction[ggData, LIST[$SetGravity, IF gravityOn THEN "T" ELSE "F"]]; midpointsOn _ GGState.Midpoints[ggData]; EnterAction[ggData, LIST[$SetMidpoints, IF midpointsOn THEN "T" ELSE "F"]]; heuristicsOn _ GGState.Heuristics[ggData]; EnterAction[ggData, LIST[$SetHeuristics, IF heuristicsOn THEN "T" ELSE "F"]]; EnterAction[ggData, LIST[$InitializeAlignments]]; }; CloseScript: PUBLIC PROC [ggData: GGData] = { IF ggData.debug.logStream=NIL THEN GOTO NotLogging; ggData.debug.logStream.Close[]; Feedback.Append[ggData.feedback, Rope.Concat["Closed ", ggData.debug.logFileName], oneLiner]; ggData.debug.logStream _ NIL; ggData.debug.logFileName _ NIL; EXITS NotLogging => Feedback.Append[ggData.feedback, "Not scripting this session", oneLiner]; }; EnterAction: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; stream: IO.STREAM _ ggData.debug.logStream; IF stream=NIL THEN { Feedback.AppendHerald[ggData.feedback, "Attempted script entry without open script file", oneLiner]; Feedback.Blink[ggData.feedback]; RETURN; }; IF event.first = $SawStartOp OR event.first = $SawSelectAll OR event.first = $SawTextFinish THEN RETURN; SessionLog.EnterAction[stream, event]; }; PlaybackFromFile: PUBLIC PROC [fileName: Rope.ROPE, ggData: GGData] = { fullName: Rope.ROPE; success: BOOL _ FALSE; endOfStream: BOOL _ FALSE; f: IO.STREAM; startTime: BasicTime.GMT; startTimeCard: CARD; BEGIN [fullName, success] _ GGUtility.GetScriptFileName[fileName, ggData.currentWDir, ggData.feedback]; IF NOT success THEN {fullName _ fileName; GOTO OpenFileProblem}; [f, success] _ OpenExistingFile[fullName, ggData]; IF NOT success THEN GOTO OpenFileProblem; GGEvent.InitializeAlignments[ggData, NIL]; ggData.aborted[playback] _ FALSE; -- just in case there was one from last playback startTime _ BasicTime.Now[]; startTimeCard _ BasicTime.ToNSTime[startTime]; WHILE NOT endOfStream DO endOfStream _ SessionLog.PlayAction[f, ggData, GGUserInput.PlayAction]; IF ggData.aborted[playback] THEN { Feedback.Append[ggData.feedback, Rope.Cat["Aborted playback of ", fullName], oneLiner]; SlackProcess.FlushQueue[ggData.slackHandle]; ggData.refresh.suppressRefresh _ FALSE; -- in case you killed FastPlayback ggData.aborted[playback] _ FALSE; RETURN; }; ENDLOOP; GGUserInput.PlayAction[ggData, LIST[$EndOfSessionLogMessage, fullName, NEW[CARD _ startTimeCard]]]; ggData.aborted[playback] _ FALSE; EXITS OpenFileProblem => { Feedback.Append[ggData.feedback, Rope.Cat["Could not open ", fullName, " for playback"], oneLiner]; Feedback.Blink[ggData.feedback]; RETURN; }; END; }; EndOfScriptMessage: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { ggData: GGData _ NARROW[clientData]; logName: Rope.ROPE _ NARROW[event.rest.first]; startTimeCard: CARD _ NARROW[event.rest.rest.first, REF CARD]^; startTime: BasicTime.GMT _ BasicTime.FromNSTime[startTimeCard]; endTime: BasicTime.GMT; totalTime: INT; endTime _ BasicTime.Now[]; totalTime _ BasicTime.Period[startTime, endTime]; Feedback.PutF[ggData.feedback, oneLiner, "Finished playback of %g in time (%r)", [rope[logName]], [integer[totalTime]]]; }; OpenExistingFile: PROC [name: Rope.ROPE, ggData: GGData] RETURNS [f: IO.STREAM, success: BOOL] = { success _ TRUE; f _ FS.StreamOpen[name ! FS.Error => { IF error.group = user THEN { success _ FALSE; Feedback.Append[ggData.feedback, error.explanation, oneLiner]; Feedback.Blink[ggData.feedback]; } ELSE ERROR; CONTINUE}]; }; END. ϊGGSessionLogImpl.mesa Last edited by Bier on April 28, 1987 0:12:03 am PDT. Contents: Routines for saving TIP Table atoms in a file to aid in interface evaluation and for playback. Pier, May 5, 1987 6:48:48 pm PDT this PROC sets up for logging but does not start it. Client must also call SlackProcess.EnableSessionLogging to start logging events. YOU MAY NOT EXECUTE THIS CODE EVEN THOUGH YOU ABORT A PLAYBACK. REASON: the slack queue. This proc can complete long before anything actually happens because of the queue, so you have to handle aborts at the abort detector. This code only gets executed if you abort while the queue is backed up. Two possiblilities 1) File doesn't exist. Print error message. 2) File does exist. File it in. Succeed. Κ ˜code™Kšœ1Οkœ™5šΟnœœG™iKšœ ™ ——K˜š ˜ Kšœ œnœ!˜ž—K˜šžœœ˜Kšœ œ@œ!˜xKšœ˜—K˜Kšœ œœ ˜Kšœœ˜'Kšœœ˜!K˜šž œœœœ˜AKšœœ|™…Kšœœœ˜Kšœœ˜Kšœ œœ˜Kšœœœ˜7Kšœa˜aKšœœ œœ˜Kšœ œ œ œ ˜EKšœ$˜$Kšœ ˜ Kšœ%œ˜*Kšœ\˜\Kšœ˜š˜KšœŠ˜Š—Kšœ˜K˜—šž œœœœ˜CKšœœœ˜Kšœœ˜Kšœ œœ˜Kšœœœ˜7Kšœa˜aKšœœ œœ˜Kšœ œ œ œ ˜EKšœ$˜$Kšœ ˜ Kšœ\˜\š˜KšœŠ˜Š—K˜K˜—šžœœ˜.Kšœ œ˜Kšœ2œ˜7Kšœ+˜+Kš œœœ œœ˜KKšœ/˜/Kšœœœœ˜EKšœ$˜$Kš œœœ œœ˜GKšœ(˜(Kš œœœ œœ˜KKšœ*˜*Kš œœœœœ˜MKšœœ˜1K˜K˜—šž œœœ˜-Kšœœœœ ˜3Kšœ˜Kšœ]˜]Kšœœ˜Kšœœ˜š˜KšœW˜W—K˜K˜—K˜K˜šž œœœœœ œœœœ˜JKšœœ ˜$Kšœœœ˜+šœœœ˜Kšœd˜dKšœ ˜ Kšœ˜K˜—Kš œœœœœ˜hKšœ&˜&K˜K˜—šžœœœœ˜GKšœœ˜Kšœ œœ˜Kšœ œœ˜Kšœœœ˜ Kšœœ˜Kšœœ˜š˜Kšœa˜aKšœœ œœ˜@Kšœ2˜2Kšœœ œœ˜)Kšœ%œ˜*KšœœΟc0˜RKšΟb˜Kšœ.˜.šœœ ˜Kšœ œ$˜Gšœœ˜"KšΠbk ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ‘ ™?Kš‘œγ™ιKšœW˜WKšœ,˜,Kšœ!œŸ"˜JKšœœ˜!Kšœ˜K˜—Kšœ˜—Kšœœ$œœ˜cKšœœ˜!š˜˜Kšœc˜cKšœ ˜ Kšœ˜K˜——Kšœ˜—Kšœ˜K˜—šžœœœœœ œœœœ˜QKšœœ ˜$Kšœœœ˜.Kš œœœœœ˜?Kšœœ'˜?Kšœœ˜Kšœ œ˜Kš ˜Kšœ1˜1Kšœx˜xK˜K˜—šžœœ œœœœ œ˜bKšœ œ˜šœ™Kšœ-™-Kšœ+™+—šœœ˜šœœ ˜šœœ˜Kšœ œ˜Kšœ>˜>Kšœ ˜ Kšœ˜—Kšœœ˜ Kšœ˜ ——K˜K˜—K˜Kšœ˜K˜K˜K˜—…—š ž