31
31
WebInspector.DebuggerPresentationModel = function()
33
this._breakpoints = {};
34
this._sourceLocationToBreakpointId = {};
36
WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointAdded, this._breakpointAdded, this);
37
WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointRemoved, this._breakpointRemoved, this);
35
WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerWasEnabled, this._debuggerWasEnabled, this);
36
WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.ParsedScriptSource, this._parsedScriptSource, this);
37
WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.FailedToParseScriptSource, this._failedToParseScriptSource, this);
38
WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.ScriptSourceChanged, this._scriptSourceChanged, this);
38
39
WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointResolved, this._breakpointResolved, this);
41
42
WebInspector.DebuggerPresentationModel.Events = {
43
SourceFileAdded: "source-file-added",
44
SourceFileChanged: "source-file-changed",
42
45
BreakpointAdded: "breakpoint-added",
43
46
BreakpointRemoved: "breakpoint-removed"
46
49
WebInspector.DebuggerPresentationModel.prototype = {
47
breakpointsForSourceName: function(sourceName)
50
_debuggerWasEnabled: function()
52
this._restoreBreakpoints();
55
sourceFile: function(sourceFileId)
57
return this._sourceFiles[sourceFileId];
60
requestSourceFileContent: function(sourceFileId, callback)
62
var sourceFile = this._sourceFiles[sourceFileId];
63
var script = sourceFile._script;
64
var resource = sourceFile._resource;
66
// FIXME: move provider's load functions here.
67
var provider = new WebInspector.SourceFrameDelegateForScriptsPanel(null, null, script);
68
if (resource.finished)
69
provider._loadResourceContent(resource, callback);
71
provider._loadAndConcatenateScriptsContent(callback);
73
function didRequestSource(source)
75
callback("text/javascript", source);
77
script.requestSource(didRequestSource);
81
_parsedScriptSource: function(event)
83
this._addScript(event.data);
86
_failedToParseScriptSource: function(event)
88
this._addScript(event.data);
91
_addScript: function(script)
93
var sourceFileId = script.sourceURL || script.sourceID;
94
if (sourceFileId in this._sourceFiles)
98
sourceFile.id = sourceFileId;
99
sourceFile.url = script.sourceURL;
100
sourceFile.isExtensionScript = script.worldType === WebInspector.Script.WorldType.EXTENSIONS_WORLD;
101
sourceFile._script = script;
102
sourceFile._resource = script.sourceURL ? this._resourceForURL(script.sourceURL) : null;
103
this._sourceFiles[sourceFileId] = sourceFile;
105
if (!sourceFile._resource || sourceFile._resource.finished)
106
this._sourceFileAdded(sourceFile);
108
sourceFile._pending = true;
109
function resourceFinished()
111
if (sourceFile._pending) {
112
delete sourceFile._pending;
113
this._sourceFileAdded(sourceFile);
115
// Source file was forcibly added before resource was finished.
116
this.dispatchEventToListeners(WebInspector.DebuggerPresentationModel.Events.SourceFileChanged, sourceFile);
119
sourceFile._resource.addEventListener("finished", resourceFinished.bind(this));
123
_ensureSourceFileAdded: function(script)
125
var sourceFile = this._sourceFiles[script.sourceURL || script.sourceID];
126
if (!sourceFile._resource || sourceFile._resource.finished)
129
if (sourceFile._pending) {
130
delete sourceFile._pending;
131
this._sourceFileAdded(sourceFile);
133
// FIXME: dispatch event only if source file content changed.
134
this.dispatchEventToListeners(WebInspector.DebuggerPresentationModel.Events.SourceFileChanged, sourceFile);
138
_resourceForURL: function(url)
140
return WebInspector.networkManager.inflightResourceForURL(url) || WebInspector.resourceForURL(url);
143
_scriptSourceChanged: function(event)
145
var sourceID = event.data.sourceID;
146
var oldSource = event.data.oldSource;
147
var script = WebInspector.debuggerModel.scriptForSourceID(sourceID);
149
var resource = WebInspector.resourceForURL(script.sourceURL);
151
var revertHandle = WebInspector.debuggerModel.editScriptSource.bind(WebInspector.debuggerModel, script.sourceID, oldSource);
152
resource.setContent(script.source, revertHandle);
155
var sourceFileId = script.sourceURL || script.sourceID;
157
// Clear and re-create breakpoints according to text diff.
158
var diff = Array.diff(oldSource.split("\n"), script.source.split("\n"));
159
for (var id in this._presentationBreakpoints) {
160
var breakpoint = this._presentationBreakpoints[id];
161
if (breakpoint.sourceFileId !== sourceFileId)
163
var lineNumber = breakpoint.lineNumber;
164
this.removeBreakpoint(sourceFileId, lineNumber);
166
var newLineNumber = diff.left[lineNumber].row;
167
if (newLineNumber === undefined) {
168
for (var i = lineNumber - 1; i >= 0; --i) {
169
if (diff.left[i].row === undefined)
171
var shiftedLineNumber = diff.left[i].row + lineNumber - i;
172
if (shiftedLineNumber < diff.right.length) {
173
var originalLineNumber = diff.right[shiftedLineNumber].row;
174
if (originalLineNumber === lineNumber || originalLineNumber === undefined)
175
newLineNumber = shiftedLineNumber;
180
if (newLineNumber !== undefined)
181
this.setBreakpoint(sourceFileId, newLineNumber, breakpoint.condition, breakpoint.enabled);
184
var sourceFile = this._sourceFiles[sourceFileId];
185
this.dispatchEventToListeners(WebInspector.DebuggerPresentationModel.Events.SourceFileChanged, sourceFile);
188
_sourceFileAdded: function(sourceFile)
190
sourceFile._breakpoints = [];
191
var breakpoints = WebInspector.debuggerModel.breakpoints;
192
for (var id in breakpoints) {
193
if (!(id in this._presentationBreakpoints))
194
this._breakpointAdded(breakpoints[id]);
196
this.dispatchEventToListeners(WebInspector.DebuggerPresentationModel.Events.SourceFileAdded, sourceFile);
199
continueToLine: function(sourceFileId, lineNumber)
201
var location = this._sourceLocationToActualLocation(sourceFileId, lineNumber);
202
if (location.sourceID)
203
WebInspector.debuggerModel.continueToLocation(location.sourceID, location.lineNumber, location.columnNumber);
206
breakpointsForSourceFileId: function(sourceFileId)
208
var sourceFile = this.sourceFile(sourceFileId);
49
211
var breakpoints = [];
50
for (var id in this._breakpoints) {
51
var breakpoint = this._breakpoints[id];
52
if (breakpoint.sourceName === sourceName)
53
breakpoints.push(breakpoint);
212
for (var lineNumber in sourceFile._breakpoints)
213
breakpoints.push(sourceFile._breakpoints[lineNumber]);
55
214
return breakpoints;
58
_breakpointAdded: function(event)
60
var breakpoint = event.data;
217
setBreakpoint: function(sourceFileId, lineNumber, condition, enabled)
219
function didSetBreakpoint(breakpoint)
222
this._breakpointAdded(breakpoint);
223
this._saveBreakpoints();
226
var location = this._sourceLocationToActualLocation(sourceFileId, lineNumber);
228
WebInspector.debuggerModel.setBreakpoint(location.url, location.lineNumber, location.columnNumber, condition, enabled, didSetBreakpoint.bind(this));
230
WebInspector.debuggerModel.setBreakpointBySourceId(location.sourceID, location.lineNumber, location.columnNumber, condition, enabled, didSetBreakpoint.bind(this));
233
setBreakpointEnabled: function(sourceFileId, lineNumber, enabled)
235
var breakpoint = this.removeBreakpoint(sourceFileId, lineNumber);
236
this.setBreakpoint(sourceFileId, lineNumber, breakpoint.condition, enabled);
239
updateBreakpoint: function(sourceFileId, lineNumber, condition, enabled)
241
this.removeBreakpoint(sourceFileId, lineNumber);
242
this.setBreakpoint(sourceFileId, lineNumber, condition, enabled);
245
removeBreakpoint: function(sourceFileId, lineNumber)
247
var breakpoint = this.findBreakpoint(sourceFileId, lineNumber);
248
WebInspector.debuggerModel.removeBreakpoint(breakpoint._id);
249
this._breakpointRemoved(breakpoint._id);
250
this._saveBreakpoints();
254
findBreakpoint: function(sourceFileId, lineNumber)
256
var sourceFile = this.sourceFile(sourceFileId);
258
return sourceFile._breakpoints[lineNumber];
261
_breakpointAdded: function(breakpoint)
61
263
var location = breakpoint.locations.length ? breakpoint.locations[0] : breakpoint;
62
var sourceLocation = this._actualLocationToSourceLocation(breakpoint.url || breakpoint.sourceID, location.lineNumber, location.columnNumber);
264
var sourceLocation = this._actualLocationToSourceLocation(breakpoint.url, breakpoint.sourceID, location.lineNumber, location.columnNumber);
64
var encodedSourceLocation = this._encodeSourceLocation(sourceLocation.sourceName, sourceLocation.lineNumber);
65
if (encodedSourceLocation in this._sourceLocationToBreakpointId) {
66
// We can't show more than one breakpoint on a single source frame line. Remove newly added breakpoint.
268
if (this.findBreakpoint(sourceLocation.sourceFileId, sourceLocation.lineNumber)) {
269
// We can't show more than one breakpoint on a single source file line.
67
270
WebInspector.debuggerModel.removeBreakpoint(breakpoint.id);
71
274
var presentationBreakpoint = {
72
sourceName: sourceLocation.sourceName,
275
sourceFileId: sourceLocation.sourceFileId,
73
276
lineNumber: sourceLocation.lineNumber,
74
277
url: breakpoint.url,
75
278
resolved: !!breakpoint.locations.length,
76
279
condition: breakpoint.condition,
77
enabled: breakpoint.enabled
280
enabled: breakpoint.enabled,
80
this._sourceLocationToBreakpointId[encodedSourceLocation] = breakpoint.id;
81
this._breakpoints[breakpoint.id] = presentationBreakpoint;
283
if (location.sourceID) {
284
var script = WebInspector.debuggerModel.scriptForSourceID(location.sourceID);
285
presentationBreakpoint.loadSnippet = script.sourceLine.bind(script, location.lineNumber);
288
this._presentationBreakpoints[breakpoint.id] = presentationBreakpoint;
289
var sourceFile = this.sourceFile(sourceLocation.sourceFileId);
290
sourceFile._breakpoints[sourceLocation.lineNumber] = presentationBreakpoint;
83
291
this.dispatchEventToListeners(WebInspector.DebuggerPresentationModel.Events.BreakpointAdded, presentationBreakpoint);
86
_breakpointRemoved: function(event)
294
_breakpointRemoved: function(breakpointId)
88
var breakpointId = event.data;
89
var breakpoint = this._breakpoints[breakpointId];
90
var encodedSourceLocation = this._encodeSourceLocation(breakpoint.sourceName, breakpoint.lineNumber);
91
delete this._breakpoints[breakpointId];
92
delete this._sourceLocationToBreakpointId[encodedSourceLocation];
296
var breakpoint = this._presentationBreakpoints[breakpointId];
297
delete this._presentationBreakpoints[breakpointId];
298
var sourceFile = this.sourceFile(breakpoint.sourceFileId);
299
delete sourceFile._breakpoints[breakpoint.lineNumber];
93
300
this.dispatchEventToListeners(WebInspector.DebuggerPresentationModel.Events.BreakpointRemoved, breakpoint);
96
303
_breakpointResolved: function(event)
98
305
var breakpoint = event.data;
99
this._breakpointRemoved({ data: breakpoint.id });
100
this._breakpointAdded({ data: breakpoint });
103
_encodeSourceLocation: function(sourceName, lineNumber)
105
return sourceName + ":" + lineNumber;
108
_actualLocationToSourceLocation: function(sourceName, lineNumber, columnNumber)
306
if (!(breakpoint.id in this._presentationBreakpoints))
308
this._breakpointRemoved(breakpoint.id);
309
this._breakpointAdded(breakpoint);
312
_restoreBreakpoints: function()
314
function didSetBreakpoint(breakpoint)
317
this._breakpointAdded(breakpoint);
319
var breakpoints = WebInspector.settings.breakpoints;
320
for (var i = 0; i < breakpoints.length; ++i) {
321
var breakpoint = breakpoints[i];
322
WebInspector.debuggerModel.setBreakpoint(breakpoint.url, breakpoint.lineNumber, breakpoint.columnNumber, breakpoint.condition, breakpoint.enabled, didSetBreakpoint.bind(this));
326
_saveBreakpoints: function()
328
var serializedBreakpoints = [];
329
var breakpoints = WebInspector.debuggerModel.breakpoints;
330
for (var id in breakpoints) {
331
var breakpoint = breakpoints[id];
334
var serializedBreakpoint = {};
335
serializedBreakpoint.url = breakpoint.url;
336
serializedBreakpoint.lineNumber = breakpoint.lineNumber;
337
serializedBreakpoint.columnNumber = breakpoint.columnNumber;
338
serializedBreakpoint.condition = breakpoint.condition;
339
serializedBreakpoint.enabled = breakpoint.enabled;
340
serializedBreakpoints.push(serializedBreakpoint);
342
WebInspector.settings.breakpoints = serializedBreakpoints;
345
set selectedCallFrame(callFrame)
347
this._selectedCallFrame = callFrame;
351
var script = WebInspector.debuggerModel.scriptForSourceID(callFrame.sourceID);
352
this._ensureSourceFileAdded(script);
353
callFrame.sourceLocation = this._actualLocationToSourceLocation(script.sourceURL, script.sourceID, callFrame.line, callFrame.column);
354
this.dispatchEventToListeners(WebInspector.DebuggerPresentationModel.Events.CallFrameSelected, callFrame);
357
get selectedCallFrame()
359
return this._selectedCallFrame;
362
_actualLocationToSourceLocation: function(scriptURL, scriptId, lineNumber, columnNumber)
110
364
// TODO: use source mapping to obtain source location.
111
return { sourceName: sourceName, lineNumber: lineNumber, columnNumber: columnNumber };
365
var sourceFile = this._sourceFiles[scriptURL || scriptId];
366
if (sourceFile && !sourceFile._pending)
367
return { sourceFileId: sourceFile.id, lineNumber: lineNumber, columnNumber: columnNumber };
370
_sourceLocationToActualLocation: function(sourceFileId, lineNumber)
372
// TODO: use source mapping to obtain actual location.
373
function filter(script)
375
return (script.sourceURL || script.sourceID) === sourceFileId;
377
var script = WebInspector.debuggerModel.queryScripts(filter)[0];
378
return { url: script.sourceURL, sourceID: script.sourceID, lineNumber: lineNumber, columnNumber: 0 };
383
this._sourceFiles = {};
384
this._presentationBreakpoints = {};