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
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] = {
this PROC sets up for logging but does not start it. Client must also call SlackProcess.EnableSessionLogging to start logging events.
stream: IO.STREAM;
fullName: Rope.ROPE;
success: BOOLFALSE;
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: BOOLFALSE;
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: BOOLFALSE;
endOfStream: BOOLFALSE;
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 {
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.
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.ROPENARROW[event.rest.first];
startTimeCard: CARDNARROW[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;
Two possiblilities
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.