ti-debug
Version:
Server-side components for WebKit Remote Debugging
408 lines (343 loc) • 11.2 kB
JavaScript
var DataTypeHelper = require('../util/data_type_helper');
/* ************************************************************************** */
function doLoadContexts(session, level, callback) {
var level = level;
session.backendSocket.sendMessage(
'context_names',
{
'd' : level
},
function (res) {
var data = res.context[0] ? res.context : [res.context];
var compiled = [];
var locked = data.length;
data.forEach(function (data, i) {
var data = data, i = i;
switch (data.name) {
case 'Locals':
data.name = 'local';
break;
case 'Superglobals': // xdebug
case 'Globals': // komodo python
data.name = 'global';
break;
case 'Code Objects': // komodo python
case 'Self': // komodo ruby
data.name = 'closure';
break;
case 'Builtins': // komodo ruby
case 'Special': // komodo ruby
data.name = 'with';
break;
default:
if (session.backend.logger) {
session.backend.logger.warn('Unrecognized context name: ' + data.name);
}
break;
}
compiled[i] = {
type : data.name,
object : {
type : 'object',
objectId : '|lvl' + level + '|ctx' + data.id
}
};
});
callback(compiled);
}
);
}
function doFreezeFrame(session, callback) {
session.backendSocket.sendMessage(
'stack_get',
function (res) {
var data = res.stack[0] ? res.stack : [res.stack];
var compiled = [];
var locked = data.length;
data.forEach(function (data, i) {
var data = data, i = i;
session.protocol.Debugger._mentionParsedScript(data.filename);
doLoadContexts(session, data.level, function (result) {
compiled[i] = {
callFrameId : data.level.toString(),
functionName : data.where,
location : {
scriptId : data.filename,
lineNumber : parseInt(data.lineno) - 1,
columnNumber : 0
},
scopeChain : result,
'this' : null
};
if (-- locked == 0) {
callback(compiled);
}
});
});
}
);
}
function doHandleContinue(session, data) {
if (data.status == 'break') {
doFreezeFrame(
session,
function (res) {
session.frontendSocket.sendInspectorMessage(
'Debugger.paused',
{
callFrames : res,
reason : 'other'
}
);
}
);
} else if (data.status == 'stopping') {
session.detach('Program has terminated.');
}
}
/* ************************************************************************** */
function Debugger(session) {
this.parsedScripts = {};
this.session = session;
}
/* ************************************************************************** */
Debugger.prototype._mentionParsedScript = function (scriptId) {
if (!this.parsedScripts[scriptId]) {
this.parsedScripts[scriptId] = true;
this.session.frontendSocket.sendInspectorMessage(
'Debugger.scriptParsed',
{
scriptId : scriptId,
url : scriptId,
startLine : 0,
startColumn : 0,
endLine : 200,
endColumn : 200
},
function () {}
);
}
};
Debugger.prototype.enable = function (params, callback) {
this.session.backendSocket.sendMessage(
'step_into',
doHandleContinue.bind(this, this.session)
);
callback(null);
};
Debugger.prototype.getScriptSource = function (params, callback) {
var callback = callback;
this.session.backendSocket.sendMessage(
'source',
{
f : params.scriptId
},
function (res) {
if (res['encoding'] == 'base64') {
callback({
scriptSource : new Buffer(res['$t'], 'base64').toString('utf8')
});
} else {
callback({
scriptSource : res['$1']
});
}
}
);
};
Debugger.prototype.stepOver = function (params, callback) {
this.session.backendSocket.sendMessage(
'step_over',
doHandleContinue.bind(this, this.session)
);
callback(null);
};
Debugger.prototype.stepInto = function (params, callback) {
this.session.backendSocket.sendMessage(
'step_into',
doHandleContinue.bind(this, this.session)
);
callback(null);
};
Debugger.prototype.stepOut = function (params, callback) {
this.session.backendSocket.sendMessage(
'step_out',
doHandleContinue.bind(this, this.session)
);
callback(null);
};
Debugger.prototype.resume = function (params, callback) {
this.session.backendSocket.sendMessage(
'run',
doHandleContinue.bind(this, this.session)
);
callback(null);
};
Debugger.prototype.pause = function (params, callback) {
this.session.backendSocket.sendMessage(
'break',
doHandleContinue.bind(this, this.session)
);
callback(null);
};
Debugger.prototype.evaluateOnCallFrame = function (params, callback) {
var callback = callback;
if (params.objectGroup == 'console' || params.objectGroup == 'watch-group') {
this.session.backendSocket.sendMessage(
'eval',
params.expression,
function (data) {
if (data.error) {
callback({
result : {
type : 'string',
value : data.error.code + ': ' + data.error.message
},
wasThrown : true
});
} else {
callback({
result : DataTypeHelper.getRemoteObject(DataTypeHelper.convertComplexObject(data.property))
});
}
}
);
} else if (params.objectGroup == 'popover') {
/*
if (params.expression[0] != '$') {
callback({
result : {
type : 'object',
subtype : 'null',
value : null
}
});
return;
}
*/
this.session.backendSocket.sendMessage('property_get', { d : params.callFrameId, n : params.expression }, function (res) {
if (res.error) {
// seen when hovering $GLOBALS
callback({
result : {
type : 'object',
subtype : 'null',
value : null
}
});
return;
}
callback({
result : DataTypeHelper.getRemoteObject(DataTypeHelper.convertComplexObject(res.property), '|lvl' + params.callFrameId + '|ctx0|')
});
});
} else {
callback({
result : {
type : 'object',
subtype : 'null',
value : null
}
});
}
};
Debugger.prototype.setBreakpointByUrl = function (params, callback) {
var callback = callback;
this.session.backendSocket.sendMessage(
'breakpoint_set',
{
t : 'line',
f : params.url,
n : params.lineNumber + 1
},
function (data) {
callback({
breakpointId : data.id.toString(),
locations : [
{
scriptId : params.url,
lineNumber : params.lineNumber,
columnNumber : 0
}
]
});
}
);
};
Debugger.prototype.removeBreakpoint = function (params, callback) {
var callback = callback;
this.session.backendSocket.sendMessage(
'breakpoint_remove',
{
d : params.breakpointId.toString()
},
function () {
callback();
}
);
};
Debugger.prototype.setPauseOnExceptions = function (params, callback) {
callback();
};
Debugger.prototype.causesRecompilation = function (params, callback) {
callback({
result : false
});
};
Debugger.prototype.supportsSeparateScriptCompilationAndExecution = function (params, callback) {
callback({
result : false
});
};
Debugger.prototype.supportsNativeBreakpoints = function (params, callback) {
callback({
result : false
});
};
Debugger.prototype.canSetScriptSource = function (params, callback) {
callback({
result : false
});
};
Debugger.prototype.setOverlayMessage = function (params, callback) {
callback();
};
Debugger.prototype.setVariableValue = function (params, callback) {
var args = [
'property_set',
{
d : params.callFrameId,
c : params.scopeNumber,
n : params.variableName
}
];
if (params.newValue.objectId) {
var objectIdParts = params.newValue.objectId.split('@');
args[1].a = objectIdParts[1];
} else {
switch (typeof params.newValue.value) {
case 'undefined':
args[1].t = 'null';
args.push('');
break;
case 'string':
args[1].t = 'string';
args.push(params.newValue.value);
break;
case 'boolean':
args[1].t = 'bool';
args.push(params.newValue.value ? 'true' : 'false');
break;
case 'number':
args[1].t = (params.newValue.value % 1 === 0) ? 'int' : 'float';
args.push(params.newValue.value.toString());
break;
default:
args.push(params.newValue.value);
}
}
args.push(function () { callback(); });
this.session.backendSocket.sendMessage.apply(this.session.backendSocket, args);
};
/* ************************************************************************** */
module.exports = Debugger;