@@ -20,6 +20,8 @@ Elm.debuggerAttach = function(module, hotSwapState /* =undefined */) {
23+var EVENTS_PER_SAVE = 100;
23function dispatchElmDebuggerInit() {
25function dispatchElmDebuggerInit() {
24 if (parent.window) {
26 if (parent.window) {
25 var dispatch = function() {
27 var dispatch = function() {
@@ -38,8 +40,10 @@ function debugModule(module, runtime) {
38 var programPaused = false;
40 var programPaused = false;
39 var recordedEvents = [];
41 var recordedEvents = [];
40 var asyncCallbacks = [];
42 var asyncCallbacks = [];
41 var watchTracker = Elm.Native.Debug.make(runtime).watchTracker;
44 var watchTracker = Elm.Native.Debug.make(runtime).watchTracker;
42 var pauseTime = 0;
45 var pauseTime = 0;
46+ var eventsUntilSnapshot = EVENTS_PER_SAVE;
44 // runtime is the prototype of wrappedRuntime
48 // runtime is the prototype of wrappedRuntime
45 // so we can access all runtime properties too
49 // so we can access all runtime properties too
@@ -66,6 +70,8 @@ function debugModule(module, runtime) {
66 var signalGraphNodes = flattenSignalGraph(wrappedRuntime.inputs);
70 var signalGraphNodes = flattenSignalGraph(wrappedRuntime.inputs);
67 var tracePath = tracePathInit(runtime, debuggedModule.main);
71 var tracePath = tracePathInit(runtime, debuggedModule.main);
73+ snapshots.push(snapshotSignalGraph(signalGraphNodes));
69 function wrapNotify(id, v) {
75 function wrapNotify(id, v) {
70 var timestep = runtime.timer.now();
76 var timestep = runtime.timer.now();
@@ -77,6 +83,11 @@ function debugModule(module, runtime) {
78 var changed = runtime.notify(id, v, timestep);
84 var changed = runtime.notify(id, v, timestep);
79 recordEvent(id, v, timestep);
85 recordEvent(id, v, timestep);
86+ if (eventsUntilSnapshot <= 1) {
88+ eventsUntilSnapshot = EVENTS_PER_SAVE;
90+ eventsUntilSnapshot -= 1;
80 if (parent.window) {
91 if (parent.window) {
81 parent.window.postMessage("elmNotify", window.location.origin);
92 parent.window.postMessage("elmNotify", window.location.origin);
@@ -133,6 +144,20 @@ function debugModule(module, runtime) {
133 recordedEvents = events.slice();
144 recordedEvents = events.slice();
147+ function clearSnapshots() {
148+ snapshots = [snapshotSignalGraph(signalGraphNodes)];
151+ function getSnapshotAt(i) {
152+ var snapshotEvent = Math.floor(i / EVENTS_PER_SAVE);
153+ assert(snapshotEvent < snapshots.length && snapshotEvent >= 0, "Out of bounds index: " + snapshotEvent);
154+ return snapshots[snapshotEvent];
157+ function saveSnapshot() {
158+ snapshots.push(snapshotSignalGraph(signalGraphNodes));
136 function setPaused() {
161 function setPaused() {
137 programPaused = true;
162 programPaused = true;
138 clearAsyncCallbacks();
163 clearAsyncCallbacks();
@@ -147,6 +172,9 @@ function debugModule(module, runtime) {
147 if (position > 0) {
172 if (position > 0) {
148 // If we're not unpausing at the head, then we need to dump the
173 // If we're not unpausing at the head, then we need to dump the
149 // events that are ahead of where we're continuing.
174 // events that are ahead of where we're continuing.
175+ var lastSnapshotPosition = Math.ceil(position / EVENTS_PER_SAVE);
176+ eventsUntilSnapshot = EVENTS_PER_SAVE - (position % EVENTS_PER_SAVE);
177+ snapshots = snapshots.slice(0, lastSnapshotPosition);
150 recordedEvents = recordedEvents.slice(0, position);
178 recordedEvents = recordedEvents.slice(0, position);
151 executeCallbacks(asyncCallbacks, false);
179 executeCallbacks(asyncCallbacks, false);
@@ -169,6 +197,9 @@ function debugModule(module, runtime) {
169 getRecordedEventAt: getRecordedEventAt,
197 getRecordedEventAt: getRecordedEventAt,
170 copyRecordedEvents: copyRecordedEvents,
198 copyRecordedEvents: copyRecordedEvents,
171 loadRecordedEvents: loadRecordedEvents,
199 loadRecordedEvents: loadRecordedEvents,
200+ clearSnapshots: clearSnapshots,
201+ getSnapshotAt: getSnapshotAt,
202+ saveSnapshot: saveSnapshot,
172 getPaused: getPaused,
203 getPaused: getPaused,
173 setPaused: setPaused,
204 setPaused: setPaused,
174 setContinue: setContinue,
205 setContinue: setContinue,
@@ -180,17 +211,20 @@ function debugModule(module, runtime) {
180function debuggerInit(debugModule, runtime, hotSwapState /* =undefined */) {
211function debuggerInit(debugModule, runtime, hotSwapState /* =undefined */) {
181 var currentEventIndex = 0;
212 var currentEventIndex = 0;
183− function resetProgram() {
214+ function resetProgram(position) {
215+ var closestSnapshot = debugModule.getSnapshotAt(position);
184 debugModule.clearAsyncCallbacks();
216 debugModule.clearAsyncCallbacks();
185− restoreSnapshot(debugModule.signalGraphNodes, debugModule.initialSnapshot);
217+ restoreSnapshot(debugModule.signalGraphNodes, closestSnapshot);
218+ // clear traces here.
186 redrawGraphics();
219 redrawGraphics();
189 function restartProgram() {
222 function restartProgram() {
190− resetProgram();
223+ resetProgram(0);
191 debugModule.watchTracker.clear();
224 debugModule.watchTracker.clear();
192 debugModule.tracePath.clearTraces();
225 debugModule.tracePath.clearTraces();
193 debugModule.clearRecordedEvents();
226 debugModule.clearRecordedEvents();
227+ debugModule.clearSnapshots();
194 debugModule.setContinue(0);
228 debugModule.setContinue(0);
195 executeCallbacks(debugModule.initialAsyncCallbacks, true);
229 executeCallbacks(debugModule.initialAsyncCallbacks, true);
@@ -207,11 +241,10 @@ function debuggerInit(debugModule, runtime, hotSwapState /* =undefined */) {
207 restartProgram();
241 restartProgram();
244+ var closestSnapshotIndex = Math.floor(currentEventIndex / EVENTS_PER_SAVE) * EVENTS_PER_SAVE;
210− resetProgram();
245+ resetProgram(currentEventIndex);
211 var continueIndex = currentEventIndex;
246 var continueIndex = currentEventIndex;
212− currentEventIndex = 0;
247+ currentEventIndex = closestSnapshotIndex;
213− debugModule.tracePath.clearTraces();
214− debugModule.tracePath.startRecording();
215 stepTo(continueIndex);
248 stepTo(continueIndex);
216 debugModule.setContinue(currentEventIndex);
249 debugModule.setContinue(currentEventIndex);
@@ -228,8 +261,9 @@ function debuggerInit(debugModule, runtime, hotSwapState /* =undefined */) {
230 if (index < currentEventIndex) {
263 if (index < currentEventIndex) {
264+ var closestSnapshotIndex = Math.floor(index / EVENTS_PER_SAVE) * EVENTS_PER_SAVE;
231− resetProgram();
265+ resetProgram(index);
232− currentEventIndex = 0;
266+ currentEventIndex = closestSnapshotIndex;
235 while (currentEventIndex < index) {
269 while (currentEventIndex < index) {
@@ -277,10 +311,21 @@ function debuggerInit(debugModule, runtime, hotSwapState /* =undefined */) {
277 var paused = top.debug.paused;
311 var paused = top.debug.paused;
278 debugModule.setPaused();
312 debugModule.setPaused();
279 debugModule.loadRecordedEvents(hotSwapState.recordedEvents);
313 debugModule.loadRecordedEvents(hotSwapState.recordedEvents);
314+ var index = getMaxSteps();
315+ var eventsUntilSnapshot = EVENTS_PER_SAVE;
281 // draw new trace path
317 // draw new trace path
282 debugModule.tracePath.startRecording();
318 debugModule.tracePath.startRecording();
283− stepTo(getMaxSteps());
319+ while(currentEventIndex < index) {
320+ var nextEvent = debugModule.getRecordedEventAt(currentEventIndex);
321+ runtime.notify(nextEvent.id, nextEvent.value, nextEvent.timestep);
322+ if (eventsUntilSnapshot <= 1) {
323+ debugModule.saveSnapshot();
324+ eventsUntilSnapshot = EVENTS_PER_SAVE;
326+ eventsUntilSnapshot -= 1;
327+ currentEventIndex += 1;
284 debugModule.tracePath.stopRecording();
329 debugModule.tracePath.stopRecording();
286 stepTo(hotSwapState.currentEventIndex);
331 stepTo(hotSwapState.currentEventIndex);