<> <> <> <> 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; <> <<1) File doesn't exist. Print error message.>> <<2) File does exist. File it in. Succeed.>> 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.