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: 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 {
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.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;
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.