<> <> <> <> DIRECTORY BasicTime, Feedback, FS, IO, Rope, SessionLog, SlackProcess, SV2d, SVEvent, SVInterfaceTypes, SVSessionLog, SVState, SVUserInput, SVUtility, SVWindow; SVSessionLogImpl: CEDAR PROGRAM IMPORTS BasicTime, Feedback, FS, IO, Rope, SessionLog, SlackProcess, SVEvent, SVUserInput, SVUtility EXPORTS SVSessionLog = BEGIN CharClass: TYPE = IO.CharClass; SVData: TYPE = SVInterfaceTypes.SVData; Point2d: TYPE = SV2d.Point2d; OpenScript: PUBLIC PROC [fileName: Rope.ROPE, svData: SVData] = { <> stream: IO.STREAM; fullName: Rope.ROPE; success: BOOL _ FALSE; IF svData.debug.logStream#NIL THEN CloseScript[svData]; [fullName, success] _ SVUtility.GetScriptFileName[fileName, svData.currentWDir, svData.feedback]; IF NOT success THEN RETURN; stream _ FS.StreamOpen[fullName, $create ! FS.Error => GOTO FSError]; svData.debug.logFileName _ fullName; svData.debug.logStream _ stream; SVEvent.InitializeAlignments[NIL, svData]; Feedback.Append[svData.feedback, Rope.Cat["Opened ", fullName, " for scripting"], oneLiner]; CaptureSessionState[svData]; EXITS FSError => {Feedback.Append[svData.feedback, Rope.Concat["FSError while trying ", fileName], oneLiner]; Feedback.Blink[svData.feedback];}; }; AppendScript: PUBLIC PROC [fileName: Rope.ROPE, svData: SVData] = { stream: IO.STREAM; fullName: Rope.ROPE; success: BOOL _ FALSE; IF svData.debug.logStream#NIL THEN CloseScript[svData]; [fullName, success] _ SVUtility.GetScriptFileName[fileName, svData.currentWDir, svData.feedback]; IF NOT success THEN RETURN; stream _ FS.StreamOpen[fullName, $append ! FS.Error => GOTO FSError]; svData.debug.logFileName _ fullName; svData.debug.logStream _ stream; Feedback.Append[svData.feedback, Rope.Cat["Opened ", fullName, " for appending"], oneLiner]; EXITS FSError => {Feedback.Append[svData.feedback, Rope.Concat["FSError while trying ", fileName], oneLiner]; Feedback.Blink[svData.feedback];}; }; CaptureSessionState: PROC [svData: SVData] = { <> <> <> <> <> <> <> <> <> <> <> <> <> }; CloseScript: PUBLIC PROC [svData: SVData] = { IF svData.debug.logStream=NIL THEN GOTO NotLogging; svData.debug.logStream.Close[]; Feedback.Append[svData.feedback, Rope.Concat["Closed ", svData.debug.logFileName], oneLiner]; svData.debug.logStream _ NIL; svData.debug.logFileName _ NIL; EXITS NotLogging => Feedback.Append[svData.feedback, "Not scripting this session", oneLiner]; }; EnterAction: PUBLIC PROC [clientData: REF ANY, event: LIST OF REF ANY] = { <> svData: SVData _ NARROW[clientData]; stream: IO.STREAM _ svData.debug.logStream; IF stream=NIL THEN { Feedback.AppendHerald[svData.feedback, "Attempted script entry without open script file", oneLiner]; Feedback.Blink[svData.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, svData: SVData] = { fullName: Rope.ROPE; success: BOOL _ FALSE; endOfStream: BOOL _ FALSE; f: IO.STREAM; startTime: BasicTime.GMT; startTimeCard: CARD; BEGIN [fullName, success] _ SVUtility.GetScriptFileName[fileName, svData.currentWDir, svData.feedback]; IF NOT success THEN {fullName _ fileName; GOTO OpenFileProblem}; [f, success] _ OpenExistingFile[fullName, svData]; IF NOT success THEN GOTO OpenFileProblem; SVEvent.InitializeAlignments[NIL, svData]; svData.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, svData, SVUserInput.EventNotify]; IF svData.aborted[playback] THEN { <> <> Feedback.Append[svData.feedback, Rope.Cat["Aborted playback of ", fullName], oneLiner]; SlackProcess.FlushQueue[svData.slackHandle]; svData.refresh.suppressRefresh _ FALSE; -- in case you killed FastPlayback svData.aborted[playback] _ FALSE; RETURN; }; ENDLOOP; SVUserInput.EventNotify[svData, LIST[$EndOfSessionLogMessage, fullName, NEW[CARD _ startTimeCard]]]; svData.aborted[playback] _ FALSE; EXITS OpenFileProblem => { Feedback.Append[svData.feedback, Rope.Cat["Could not open ", fullName, " for playback"], oneLiner]; Feedback.Blink[svData.feedback]; RETURN; }; END; }; EndOfSessionLogMessage: PUBLIC PROC [event: LIST OF REF ANY, svData: SVData] = { 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[svData.feedback, oneLiner, "Finished playback of %g in time (%r)", [rope[logName]], [integer[totalTime]]]; }; OpenExistingFile: PROC [name: Rope.ROPE, svData: SVData] 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[svData.feedback, error.explanation, oneLiner]; Feedback.Blink[svData.feedback]; } ELSE ERROR; CONTINUE}]; }; END.