delete sourcehightlighter.js

pull/1/head
yann300 8 years ago
parent c33a671148
commit e7f0512635
  1. 44
      src/app.js
  2. 2
      src/app/compiler-worker.js
  3. 24
      src/app/compiler.js
  4. 108
      src/app/debugger.js
  5. 34
      src/app/execution-context.js
  6. 206
      src/app/sourceHighlighter.js

@ -18,8 +18,6 @@ var UniversalDApp = require('./universal-dapp.js');
var Debugger = require('./app/debugger'); var Debugger = require('./app/debugger');
var FormalVerification = require('./app/formalVerification'); var FormalVerification = require('./app/formalVerification');
var EventManager = require('./lib/eventManager'); var EventManager = require('./lib/eventManager');
var SourceHighlighter = require('./app/sourceHighlighter');
// The event listener needs to be registered as early as possible, because the // The event listener needs to be registered as early as possible, because the
// parent will send the message upon the "load" event. // parent will send the message upon the "load" event.
var filesToLoad = null; var filesToLoad = null;
@ -234,7 +232,7 @@ var run = function () {
} }
return false; return false;
}); });
function swicthToFile (file) { function swicthToFile (file) {
editor.setCacheFile(utils.fileKey(file)); editor.setCacheFile(utils.fileKey(file));
updateFiles(); updateFiles();
@ -242,8 +240,7 @@ var run = function () {
function showFileHandler (ev) { function showFileHandler (ev) {
ev.preventDefault(); ev.preventDefault();
swicthToFile($(this).find('.name').text()) swicthToFile($(this).find('.name').text());
updateFiles();
return false; return false;
} }
@ -422,11 +419,14 @@ var run = function () {
} }
var executionContext = new ExecutionContext(); var executionContext = new ExecutionContext();
var transactionDebugger = new Debugger('#debugger', executionContext.event); var compiler = new Compiler(editor, queryParams, handleGithubCall, updateFiles);
transactionDebugger.addProvider('VM', executionContext.vm()); var formalVerification = new FormalVerification($('#verificationView'), compiler.event);
var transactionDebugger = new Debugger('#debugger', editor, compiler, executionContext.event, swicthToFile);
transactionDebugger.addProvider('vm', executionContext.vm());
transactionDebugger.switchProvider('VM'); transactionDebugger.switchProvider('VM');
transactionDebugger.addProvider('INTERNAL', executionContext.web3()); transactionDebugger.addProvider('injected', executionContext.web3());
transactionDebugger.addProvider('EXTERNAL', executionContext.web3()); transactionDebugger.addProvider('web3', executionContext.web3());
var udapp = new UniversalDApp(executionContext, { var udapp = new UniversalDApp(executionContext, {
removable: false, removable: false,
@ -434,14 +434,10 @@ var run = function () {
}, transactionDebugger); }, transactionDebugger);
udapp.event.register('debugRequested', this, function (txResult) { udapp.event.register('debugRequested', this, function (txResult) {
transactionDebugger.debug(txResult); startdebugging(txResult.transactionHash);
selectTab($('ul#options li.debugView'));
}); });
var compiler = new Compiler(editor, queryParams, handleGithubCall, updateFiles);
var formalVerification = new FormalVerification($('#verificationView'), compiler.event);
var renderer = new Renderer(editor, executionContext.web3(), updateFiles, udapp, executionContext, formalVerification.event, compiler.event); // eslint-disable-line var renderer = new Renderer(editor, executionContext.web3(), updateFiles, udapp, executionContext, formalVerification.event, compiler.event); // eslint-disable-line
var sourceHighlighter = new SourceHighlighter(editor, transactionDebugger.debugger, compiler.event, this.event, swicthToFile) // eslint-disable-line
executionContext.event.register('contextChanged', this, function (context) { executionContext.event.register('contextChanged', this, function (context) {
compiler.compile(); compiler.compile();
@ -451,8 +447,9 @@ var run = function () {
compiler.compile(); compiler.compile();
}); });
executionContext.event.register('compilerLoaded', this, function (context) { compiler.event.register('compilerLoaded', this, function (context) {
compiler.compile(); compiler.compile();
initWithQueryParams();
}); });
compiler.event.register('compilerLoaded', this, function (version) { compiler.event.register('compilerLoaded', this, function (version) {
@ -460,6 +457,23 @@ var run = function () {
compiler.compile(); compiler.compile();
}); });
function initWithQueryParams () {
if (queryParams.get().endpointurl) {
executionContext.setEndPointUrl(queryParams.get().endpointurl);
}
if (queryParams.get().context) {
executionContext.setContext(queryParams.get().context);
}
if (queryParams.get().debugtx) {
startdebugging(queryParams.get().debugtx);
}
}
function startdebugging (txHash) {
transactionDebugger.debug(txHash);
selectTab($('ul#options li.debugView'));
}
function setVersionText (text) { function setVersionText (text) {
$('#version').text(text); $('#version').text(text);
} }

@ -34,7 +34,7 @@ module.exports = function (self) {
break; break;
case 'compile': case 'compile':
missingInputs.length = 0; missingInputs.length = 0;
self.postMessage({cmd: 'compiled', data: compileJSON(data.source, data.optimize), missingInputs: missingInputs}); self.postMessage({cmd: 'compiled', data: compileJSON(data.source, data.optimize), missingInputs: missingInputs, source: data.source});
break; break;
} }
}, false); }, false);

@ -16,7 +16,7 @@ function Compiler (editor, queryParams, handleGithubCall, updateFiles) {
var compileJSON; var compileJSON;
var compilerAcceptsMultipleFiles; var compilerAcceptsMultipleFiles;
var previousInput = ''; var previousInput = '';
var cachedRemoteFiles = {}; var cachedRemoteFiles = {};
@ -60,7 +60,7 @@ function Compiler (editor, queryParams, handleGithubCall, updateFiles) {
}); });
}; };
this.compile = compile; this.compile = compile;
function setCompileJSON (_compileJSON) { function setCompileJSON (_compileJSON) {
compileJSON = _compileJSON; compileJSON = _compileJSON;
} }
@ -91,24 +91,28 @@ function Compiler (editor, queryParams, handleGithubCall, updateFiles) {
result = { error: 'Uncaught JavaScript exception:\n' + exception }; result = { error: 'Uncaught JavaScript exception:\n' + exception };
} }
compilationFinished(result, missingInputs); compilationFinished(result, missingInputs, source);
}; };
onCompilerLoaded(compiler.version()); onCompilerLoaded(compiler.version());
} }
} }
function compilationFinished (data, missingInputs) { this.lastCompilationResult = {
data: null,
source: null
}
function compilationFinished (data, missingInputs, source) {
var noFatalErrors = true; // ie warnings are ok var noFatalErrors = true; // ie warnings are ok
if (data['error'] !== undefined) { if (data['error'] !== undefined) {
self.event.trigger('compilationFinished', [false, [data['error']], editor.getValue()]); self.event.trigger('compilationFinished', [false, [data['error']], source]);
if (utils.errortype(data['error']) !== 'warning') { if (utils.errortype(data['error']) !== 'warning') {
noFatalErrors = false; noFatalErrors = false;
} }
} }
if (data['errors'] !== undefined) { if (data['errors'] !== undefined) {
self.event.trigger('compilationFinished', [false, data['errors'], editor.getValue()]); self.event.trigger('compilationFinished', [false, data['errors'], source]);
data['errors'].forEach(function (err) { data['errors'].forEach(function (err) {
if (utils.errortype(err) !== 'warning') { if (utils.errortype(err) !== 'warning') {
noFatalErrors = false; noFatalErrors = false;
@ -119,7 +123,11 @@ function Compiler (editor, queryParams, handleGithubCall, updateFiles) {
if (missingInputs !== undefined && missingInputs.length > 0) { if (missingInputs !== undefined && missingInputs.length > 0) {
compile(missingInputs); compile(missingInputs);
} else if (noFatalErrors) { } else if (noFatalErrors) {
self.event.trigger('compilationFinished', [true, data, editor.getValue()]); self.lastCompilationResult = {
data: data,
source: source
}
self.event.trigger('compilationFinished', [true, data, source]);
} }
} }
@ -170,7 +178,7 @@ function Compiler (editor, queryParams, handleGithubCall, updateFiles) {
} catch (exception) { } catch (exception) {
result = { 'error': 'Invalid JSON output from the compiler: ' + exception }; result = { 'error': 'Invalid JSON output from the compiler: ' + exception };
} }
compilationFinished(result, data.missingInputs); compilationFinished(result, data.missingInputs, data.source);
break; break;
} }
}); });

@ -1,38 +1,132 @@
var remix = require('ethereum-remix'); var remix = require('ethereum-remix');
var utils = require('./utils');
var ace = require('brace');
var Range = ace.acequire('ace/range').Range;
function Debugger (id, executionContextEvent) { /**
* Manage remix and source highlighting
*/
function Debugger (id, editor, compiler, executionContextEvent, switchToFile) {
this.el = document.querySelector(id); this.el = document.querySelector(id);
this.debugger = new remix.ui.Debugger(); this.debugger = new remix.ui.Debugger();
this.sourceMappingDecoder = new remix.util.SourceMappingDecoder()
this.el.appendChild(this.debugger.render()); this.el.appendChild(this.debugger.render());
this.editor = editor;
this.switchToFile = switchToFile;
this.compiler = compiler;
this.cache = new Cache()
var self = this; var self = this;
executionContextEvent.register('contextChanged', this, function (context) { executionContextEvent.register('contextChanged', this, function (context) {
context = context === 'vm' ? 'VM' : context;
context = context === 'injected' ? 'EXTERNAL' : context;
context = context === 'web3' ? 'INTERNAL' : context;
self.switchProvider(context); self.switchProvider(context);
}); });
this.lastCompilationResult = null;
this.debugger.register('newTraceLoaded', this, function () {
self.cache.clear()
self.lastCompilationResult = self.compiler.lastCompilationResult;
});
this.debugger.register('traceUnloaded', this, function () {
self.lastCompilationResult = null;
self.removeCurrentMarker()
self.cache.clear()
});
this.editor.onChangeSetup(function () {
if (arguments.length > 0) { // if arguments.length === 0 this is a session change, we don't want to stop debugging in that case
self.debugger.unLoad()
}
});
// register selected code item, highlight the corresponding source location
this.debugger.codeManager.register('changed', this, function (code, address, index) {
this.debugger.sourceLocationTracker.getSourceLocation(address, index, self.lastCompilationResult.data.contracts, function (error, rawLocation) {
if (!error) {
if (!self.cache.lineBreakPositionsByContent[address]) {
self.cache.lineBreakPositionsByContent[address] = self.sourceMappingDecoder.getLinebreakPositions(self.editor.getFile(self.lastCompilationResult.data.sourceList[rawLocation.file]))
}
var lineColumnPos = self.sourceMappingDecoder.convertOffsetToLineColumn(rawLocation, self.cache.lineBreakPositionsByContent[address])
self.highlight(lineColumnPos, rawLocation);
}
});
});
} }
Debugger.prototype.debug = function (receipt) { /**
var self = this * Start debugging using Remix
this.debugger.web3().eth.getTransaction(receipt.transactionHash, function (error, tx) { *
* @param {String} txHash - hash of the transaction
*/
Debugger.prototype.debug = function (txHash) {
var self = this;
this.debugger.web3().eth.getTransaction(txHash, function (error, tx) {
if (!error) { if (!error) {
self.debugger.debug(tx); self.debugger.debug(tx);
} }
}); });
}; };
/**
* highlight the given @arg lineColumnPos
*
* @param {Object} lineColumnPos - position of the source code to hightlight {start: {line, column}, end: {line, column}}
* @param {Object} rawLocation - raw position of the source code to hightlight {start, length, file, jump}
*/
Debugger.prototype.highlight = function (lineColumnPos, rawLocation) {
var name = utils.fileNameFromKey(this.editor.getCacheFile()); // current opened tab
var source = this.lastCompilationResult.data.sourceList[rawLocation.file]; // auto switch to that tab
this.removeCurrentMarker();
if (name !== source) {
this.switchToFile(source); // command the app to swicth to the next file
}
this.currentRange = new Range(lineColumnPos.start.line, lineColumnPos.start.column, lineColumnPos.end.line, lineColumnPos.end.column);
this.currentMarker = this.editor.addMarker(this.currentRange, 'highlightcode');
};
/**
* add a new web3 provider to remix
*
* @param {String} type - type/name of the provider to add
* @param {Object} obj - provider
*/
Debugger.prototype.addProvider = function (type, obj) { Debugger.prototype.addProvider = function (type, obj) {
this.debugger.addProvider(type, obj); this.debugger.addProvider(type, obj);
}; };
/**
* switch the provider
*
* @param {String} type - type/name of the provider to use
*/
Debugger.prototype.switchProvider = function (type) { Debugger.prototype.switchProvider = function (type) {
this.debugger.switchProvider(type); this.debugger.switchProvider(type);
}; };
/**
* get the current provider
*/
Debugger.prototype.web3 = function (type) { Debugger.prototype.web3 = function (type) {
return this.debugger.web3(); return this.debugger.web3();
}; };
/**
* unhighlight the current highlighted statement
*/
Debugger.prototype.removeCurrentMarker = function () {
if (this.currentMarker) {
this.editor.removeMarker(this.currentMarker);
this.currentMarker = null;
}
};
function Cache () {
this.contentLineBreakPosition = {}
}
Cache.prototype.clear = function () {
this.lineBreakPositionsByContent = {}
}
module.exports = Debugger; module.exports = Debugger;

@ -21,7 +21,6 @@ vm.stateManager.checkpoint();
/* /*
trigger contextChanged, web3EndpointChanged trigger contextChanged, web3EndpointChanged
*/ */
function ExecutionContext () { function ExecutionContext () {
var self = this; var self = this;
this.event = new EventManager(); this.event = new EventManager();
@ -39,6 +38,16 @@ function ExecutionContext () {
return vm; return vm;
}; };
this.setEndPointUrl = function (url) {
$web3endpoint.val(url);
};
this.setContext = function (context) {
executionContext = context;
executionContextChange(context);
setExecutionContextRadio()
};
var $injectedToggle = $('#injected-mode'); var $injectedToggle = $('#injected-mode');
var $vmToggle = $('#vm-mode'); var $vmToggle = $('#vm-mode');
var $web3Toggle = $('#web3-mode'); var $web3Toggle = $('#web3-mode');
@ -50,9 +59,9 @@ function ExecutionContext () {
setExecutionContextRadio(); setExecutionContextRadio();
$injectedToggle.on('change', executionContextChange); $injectedToggle.on('change', executionContextUIChange);
$vmToggle.on('change', executionContextChange); $vmToggle.on('change', executionContextUIChange);
$web3Toggle.on('change', executionContextChange); $web3Toggle.on('change', executionContextUIChange);
$web3endpoint.on('change', function () { $web3endpoint.on('change', function () {
setProviderFromEndpoint(); setProviderFromEndpoint();
if (executionContext === 'web3') { if (executionContext === 'web3') {
@ -60,20 +69,23 @@ function ExecutionContext () {
} }
}); });
function executionContextChange (ev) { function executionContextUIChange (ev) {
if (ev.target.value === 'web3' && !confirm('Are you sure you want to connect to a local ethereum node?')) { executionContextChange(ev.target.value);
}
function executionContextChange (context) {
if (context === 'web3' && !confirm('Are you sure you want to connect to a local ethereum node?')) {
setExecutionContextRadio(); setExecutionContextRadio();
} else if (ev.target.value === 'injected' && injectedProvider === undefined) { } else if (context === 'injected' && injectedProvider === undefined) {
setExecutionContextRadio(); setExecutionContextRadio();
} else { } else {
executionContext = ev.target.value; if (context === 'web3') {
if (executionContext === 'web3') {
setProviderFromEndpoint(); setProviderFromEndpoint();
self.event.trigger('contextChanged', ['web3']); self.event.trigger('contextChanged', ['web3']);
} else if (executionContext === 'injected') { } else if (context === 'injected') {
web3.setProvider(injectedProvider); web3.setProvider(injectedProvider);
self.event.trigger('contextChanged', ['injected']); self.event.trigger('contextChanged', ['injected']);
} else if (executionContext === 'vm') { } else if (context === 'vm') {
vm.stateManager.revert(function () { vm.stateManager.revert(function () {
vm.stateManager.checkpoint(); vm.stateManager.checkpoint();
}); });

@ -1,206 +0,0 @@
var utils = require('./utils')
var remix = require('ethereum-remix')
var ace = require('brace')
var Range = ace.acequire('ace/range').Range
/*
Provides source highlighting when debugging a transaction
*/
function SourceHighlighter (editor, txdebugger, compilerEvent, appEvent, switchToFile) {
this.switchToFile = switchToFile
this.editor = editor
this.txdebugger = txdebugger
this.sourceMappingDecoder = new remix.util.SourceMappingDecoder()
this.compilationData
this.currentSourceMap
this.currentLineColumnLayout // used to retrieve line/column from char/length
this.currentRange
this.currentMarker
this.currentExecutingAddress
this.currentFile
this.isDebugging = false
var self = this
/* hide/show marker when debugger does not have the focus */
appEvent.register('tabChanged', function (tab) {
if (tab !== 'debugView') {
self.editor.removeMarker(self.currentMarker)
} else {
if (self.currentRange) {
self.currentMarker = self.editor.addMarker(self.currentRange, 'highlightcode')
}
}
})
/* update compilation data */
compilerEvent.register('compilationFinished', this, function (success, data, source) {
if (!self.isDebugging) {
self.reset()
self.compilationData = success ? data : null
}
})
/* update marker, switch file if necessary */
txdebugger.codeManager.register('changed', this, function (code, address, index) {
if (!this.currentExecutingAddress !== address) {
// context changed, need to update srcmap
this.currentExecutingAddress = address
self.loadContext(txdebugger.tx, function (error, ctrName, srcmap) {
if (!error) {
self.currentSourceMap = srcmap
self.currentContractName = ctrName
self.highlightSource(index)
}
})
} else {
self.highlightSource(index)
}
})
txdebugger.register('newTraceLoaded', this, function () {
self.isDebugging = true
})
txdebugger.register('traceUnloaded', this, function () {
self.reset()
self.isDebugging = false
})
}
/*
* Load a new debugging context. A context is define by a new transaction.
* it:
* - builds the line/column layout from the source code.
* - retrieves the source map
*
* @param {Integer} index - the tx which defined the new debugging context
* @param {Function} callback - returns the decompressed source mapping for the given index {start, length, file, jump}
*/
SourceHighlighter.prototype.loadContext = function (tx, cb) {
var self = this
contractName(self.currentExecutingAddress, self, function (error, ctrName) {
if (!error) {
var srcmap = sourceMap(isContractCreation(self.currentExecutingAddress), ctrName, self.compilationData)
cb(null, ctrName, srcmap)
}
})
}
/*
* remove the editor marker and init attributes
*/
SourceHighlighter.prototype.reset = function () {
this.currentSourceMap = null
this.currentLineColumnLayout = null
this.removeCurrentMarker()
this.currentRange = null
this.currentMarker = null
this.currentExecutingAddress = null
this.currentFile = null
}
/*
* remove the current highlighted statement
*/
SourceHighlighter.prototype.removeCurrentMarker = function () {
if (this.currentMarker) {
this.editor.removeMarker(this.currentMarker)
this.currentMarker = null
}
}
/*
* highlight the statement with the given @arg index
*
* @param {Integer} index - the index of the assembly item to be highlighted
*/
SourceHighlighter.prototype.highlightSource = function (index) {
var self = this
this.sourceMappingDecoder.decompress(index, self.currentSourceMap, function (error, rawPos) { // retrieve the sourcemap location
if (!error) {
if (self.currentFile !== rawPos.file) { // source file changed, need to update the line/column layout
var file = self.compilationData.sourceList[rawPos.file]
self.sourceMappingDecoder.retrieveLineColumnLayout(self.editor.getFile(file), function (error, result) {
if (!error) {
self.currentLineColumnLayout = result
self.currentFile = rawPos.file
self.sourceMappingDecoder.getLineColumnPosition(rawPos, self.currentLineColumnLayout, function (error, pos) {
if (!error) {
self.highlight(pos, rawPos.file)
}
})
}
})
} else {
self.sourceMappingDecoder.getLineColumnPosition(rawPos, self.currentLineColumnLayout, function (error, pos) {
if (!error) {
self.highlight(pos, rawPos.file)
}
})
}
}
})
}
/*
* highlight the statement with the given @arg position
*
* @param {Object} position - the position to highlight { start: {line, column}, end: {line, column} }
*/
SourceHighlighter.prototype.highlight = function (position, fileIndex) {
var name = utils.fileNameFromKey(this.editor.getCacheFile()) // current opened tab
var source = this.compilationData.sourceList[parseInt(fileIndex)] // auto switch to that tab
this.removeCurrentMarker()
if (name !== source) {
this.switchToFile(source) // command the app to swicth to the curent file
}
this.currentRange = new Range(position.start.line, position.start.column, position.end.line, position.end.column)
this.currentMarker = this.editor.addMarker(this.currentRange, 'highlightcode')
}
function sourceMap (isConstructor, contractName, compilationData) {
if (isConstructor) {
return compilationData.contracts[contractName].srcmap
} else {
return srcmapRuntime(compilationData.contracts[contractName])
}
}
function contractName (executingAddress, self, cb) {
if (isContractCreation(executingAddress)) {
self.txdebugger.traceManager.getContractCreationCode(executingAddress, function (error, creationCode) {
if (!error) {
retrieveByteCode(creationCode, self.compilationData, 'bytecode', cb)
}
})
} else {
self.txdebugger.web3().eth.getCode(executingAddress, function (error, code) {
if (!error) {
retrieveByteCode(code, self.compilationData, 'runtimeBytecode', cb)
}
})
}
}
function retrieveByteCode (code, compilationData, prop, cb) {
for (var k in compilationData.contracts) {
if (code === '0x' + compilationData.contracts[k][prop]) {
cb(null, k)
return
}
cb('unable to retrieve contract name')
}
}
function srcmapRuntime (contract) {
return contract.srcmapRuntime ? contract.srcmapRuntime : contract['srcmap-runtime']
}
function isContractCreation (address) {
return address.indexOf('Contract Creation') !== -1
}
module.exports = SourceHighlighter
Loading…
Cancel
Save