diff --git a/src/app.js b/src/app.js index 80ea2ac93a..7a0a6fabe2 100644 --- a/src/app.js +++ b/src/app.js @@ -332,6 +332,7 @@ Please make a backup of your contracts and start using http://remix.ethereum.org engine.register([ menuicons, landingPage, + hiddenPanel, sidePanel, pluginManagerComponent, filePanel, @@ -384,7 +385,7 @@ Please make a backup of your contracts and start using http://remix.ethereum.org await appManager.activatePlugin(['contentImport', 'theme', 'editor', 'fileManager', 'compilerMetadata', 'compilerArtefacts', 'network', 'offsetToLineColumnConverter']) await appManager.activatePlugin(['mainPanel', 'menuicons']) - await appManager.activatePlugin(['home', 'sidePanel', 'pluginManager', 'fileExplorers', 'settings', 'contextualListener', 'terminal']) + await appManager.activatePlugin(['home', 'sidePanel', 'hiddenPanel', 'pluginManager', 'fileExplorers', 'settings', 'contextualListener', 'scriptRunner', 'terminal']) // Set workspace after initial activation if (Array.isArray(workspace)) await appManager.activatePlugin(workspace) diff --git a/src/app/components/hidden-panel.js b/src/app/components/hidden-panel.js index 73c6fb26e6..048df1fd51 100644 --- a/src/app/components/hidden-panel.js +++ b/src/app/components/hidden-panel.js @@ -14,7 +14,7 @@ const profile = { displayName: 'Hidden Panel', description: '', version: packageJson.version, - methods: [] + methods: ['addView', 'removeView'] } export class HiddenPanel extends AbstractPanel { diff --git a/src/app/panels/terminal.js b/src/app/panels/terminal.js index 6b94f7774b..f93feba8c7 100644 --- a/src/app/panels/terminal.js +++ b/src/app/panels/terminal.js @@ -81,7 +81,7 @@ class Terminal extends Plugin { scopedCommands.log(`> ${script}`) self._shell(script, scopedCommands, function (error, output) { if (error) scopedCommands.error(error) - else scopedCommands.log(output) + else if (output) scopedCommands.log(output) }) }, { activate: true }) function basicFilter (value, query) { try { return value.indexOf(query) !== -1 } catch (e) { return false } } @@ -98,6 +98,26 @@ class Terminal extends Plugin { if (opts.shell) self._shell = opts.shell // ??? register(self) } + onActivation () { + this.on('scriptRunner', 'log', (msg) => { + this.commands['log'].apply(this.commands, msg.data) + }) + this.on('scriptRunner', 'info', (msg) => { + this.commands['info'].apply(this.commands, msg.data) + }) + this.on('scriptRunner', 'warn', (msg) => { + this.commands['warn'].apply(this.commands, msg.data) + }) + this.on('scriptRunner', 'error', (msg) => { + this.commands['error'].apply(this.commands, msg.data) + }) + } + onDeactivation () { + this.off('scriptRunner', 'log') + this.off('scriptRunner', 'info') + this.off('scriptRunner', 'warn') + this.off('scriptRunner', 'error') + } logHtml (html) { var command = this.commands['html'] if (typeof command === 'function') command(html) @@ -124,6 +144,7 @@ class Terminal extends Plugin { ${self._view.input} ` + self._view.icon = yo` ` @@ -659,17 +680,27 @@ class Terminal extends Plugin { } return self.commands[name] } - _shell (script, scopedCommands, done) { // default shell + async _shell (script, scopedCommands, done) { // default shell if (script.indexOf('remix:') === 0) { return done(null, 'This type of command has been deprecated and is not functionning anymore. Please run remix.help() to list available commands.') } var self = this - var context = domTerminalFeatures(self, scopedCommands, self.blockchain) + if (script.indexOf('remix.') === 0) { + // we keep the old feature. This will basically only be called when the command is querying the "remix" object. + // for all the other case, we use the Code Executor plugin + var context = domTerminalFeatures(self, scopedCommands, self.blockchain) + try { + var cmds = vm.createContext(Object.assign(self._jsSandboxContext, context, self._jsSandboxRegistered)) + var result = vm.runInContext(script, cmds) + self._jsSandboxContext = Object.assign(cmds, context) + return done(null, result) + } catch (error) { + return done(error.message) + } + } try { - var cmds = vm.createContext(Object.assign(self._jsSandboxContext, context, self._jsSandboxRegistered)) - var result = vm.runInContext(script, cmds) - self._jsSandboxContext = Object.assign(cmds, context) - done(null, result) + await this.call('scriptRunner', 'execute', script) + done() } catch (error) { done(error.message) } diff --git a/src/remixAppManager.js b/src/remixAppManager.js index 809a5b136b..8c3dcd6fa1 100644 --- a/src/remixAppManager.js +++ b/src/remixAppManager.js @@ -4,7 +4,7 @@ import { EventEmitter } from 'events' import QueryParams from './lib/query-params' const requiredModules = [ // services + layout views + system views - 'manager', 'compilerArtefacts', 'compilerMetadata', 'contextualListener', 'editor', 'offsetToLineColumnConverter', 'network', 'theme', 'fileManager', 'contentImport', + 'manager', 'compilerArtefacts', 'compilerMetadata', 'contextualListener', 'editor', 'offsetToLineColumnConverter', 'network', 'theme', 'fileManager', 'contentImport', 'scriptRunner', 'mainPanel', 'hiddenPanel', 'sidePanel', 'menuicons', 'fileExplorers', 'terminal', 'settings', 'pluginManager'] diff --git a/test-browser/tests/terminal.js b/test-browser/tests/terminal.js index efede033d6..7e16e04426 100644 --- a/test-browser/tests/terminal.js +++ b/test-browser/tests/terminal.js @@ -10,7 +10,7 @@ module.exports = { 'Should execution a simple console command': function (browser) { browser .waitForElementVisible('*[data-id="terminalCli"]', 10000) - .executeScript('1+1') + .executeScript('console.log(1 + 1)') .journalLastChild('2') }, @@ -52,8 +52,63 @@ module.exports = { .executeScript('remix.debugHelp()') .journalChildIncludes('Here are some examples of scripts that can be run (using remix.exeCurrent() or directly from the console)') .journalChildIncludes('Please see https://www.npmjs.com/package/remix-debug for more informations') + }, + + 'Async/Await Script': function (browser) { + browser + .addFile('asyncAwait.js', { content: asyncAwait }) + .switchFile('browser/asyncAwait.js') + .executeScript(`remix.execute('browser/asyncAwait.js')`) + .journalLastChild('Waiting Promise') + .pause(5500) + .journalLastChild('result - Promise Resolved') + }, + + 'Call Remix File Manager from a script': function (browser) { + browser + .addFile('asyncAwaitWithFileManagerAccess.js', { content: asyncAwaitWithFileManagerAccess }) + .switchFile('browser/asyncAwaitWithFileManagerAccess.js') + .executeScript(`remix.execute('browser/asyncAwaitWithFileManagerAccess.js')`) + .journalLastChildIncludes('contract Ballot {') .end() }, tearDown: sauce } + +const asyncAwait = ` + var p = function () { + return new Promise(function (resolve, reject) { + setTimeout(function () { + resolve("Promise Resolved") + }, 5000) + }) + } + + var run = async () => { + console.log('Waiting Promise') + var result = await p() + console.log('result - ', result) + } + + run() +` + +const asyncAwaitWithFileManagerAccess = ` + var p = function () { + return new Promise(function (resolve, reject) { + setTimeout(function () { + resolve("Promise Resolved") + }, 0) + }) + } + + var run = async () => { + console.log('Waiting Promise') + var result = await p() + let text = await remix.call('fileManager', 'getFile', 'browser/3_Ballot.sol') + console.log('result - ', text) + } + + run() +`