Merge pull request #426 from ethereum/cleanTerminal_unusedCommand

Clean terminal unused commands
pull/428/head
yann300 4 years ago committed by GitHub
commit 39333492fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      apps/remix-ide-e2e/src/tests/compiler_api.test.ts
  2. 13
      apps/remix-ide-e2e/src/tests/terminal.test.ts
  3. 10
      apps/remix-ide/src/app/files/file-explorer.js
  4. 2
      apps/remix-ide/src/app/panels/file-panel.js
  5. 76
      apps/remix-ide/src/app/panels/terminal.js
  6. 2
      apps/remix-ide/src/app/ui/auto-complete-popup.js
  7. 160
      apps/remix-ide/src/lib/cmdInterpreterAPI.js
  8. 13
      apps/remix-ide/src/lib/commands.js

@ -23,7 +23,7 @@ module.exports = {
.addFile('test_jsCompile.js', { content: jsCompile })
.executeScript('remix.exeCurrent()')
.pause(5000)
.journalChildIncludes(`version: '0.6.8+commit.0bbfe453'`)
.journalChildIncludes(`"languageversion": "0.6.8+commit.0bbfe453"`)
},
'Should update the compiler configuration with "setCompilerConfig" API': function (browser: NightwatchBrowser) {

@ -35,24 +35,11 @@ module.exports = {
browser
.waitForElementVisible('*[data-id="terminalCli"]')
.executeScript('remix.help()')
.journalChildIncludes('remix.call(message: {name, key, payload})')
.journalChildIncludes('remix.getFile(path)')
.journalChildIncludes('remix.debug(hash)')
.journalChildIncludes('remix.loadgist(id)')
.journalChildIncludes('remix.loadurl(url)')
.journalChildIncludes('remix.setproviderurl(url)')
.journalChildIncludes('remix.execute(filepath)')
.journalChildIncludes('remix.exeCurrent()')
.journalChildIncludes('remix.help()')
.journalChildIncludes('remix.debugHelp()')
},
'Should execute remix.debugHelp() command': function (browser: NightwatchBrowser) {
browser
.waitForElementVisible('*[data-id="terminalCli"]')
.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: NightwatchBrowser) {

@ -16,7 +16,7 @@ const globalRegistry = require('../../global/registry')
const queryParams = new QueryParams()
let MENU_HANDLE
function fileExplorer (localRegistry, files, menuItems) {
function fileExplorer (localRegistry, files, menuItems, plugin) {
var self = this
this.events = new EventManager()
// file provider backend
@ -292,6 +292,14 @@ function fileExplorer (localRegistry, files, menuItems) {
() => {}
)
}
if (key.endsWith('.js')) {
actions['Run'] = async () => {
provider.get(key, (error, content) => {
if (error) return console.log(error)
plugin.call('scriptRunner', 'execute', content)
})
}
}
}
MENU_HANDLE = contextMenu(event, actions)
})

@ -54,7 +54,7 @@ module.exports = class Filepanel extends ViewPlugin {
}
function createProvider (key, menuItems) {
return new FileExplorer(self._components.registry, self._deps.fileProviders[key], menuItems)
return new FileExplorer(self._components.registry, self._deps.fileProviders[key], menuItems, self)
}
var fileExplorer = createProvider('browser', ['createNewFile', 'publishToGist', canUpload ? 'uploadFile' : ''])

@ -5,12 +5,9 @@ import * as packageJson from '../../../../../package.json'
var yo = require('yo-yo')
var javascriptserialize = require('javascript-serialize')
var jsbeautify = require('js-beautify')
var ethers = require('ethers')
var type = require('component-type')
var vm = require('vm')
var EventManager = require('../../lib/events')
var Web3 = require('web3')
var swarmgw = require('swarmgw')()
var CommandInterpreterAPI = require('../../lib/cmdInterpreterAPI')
var AutoCompletePopup = require('../ui/auto-complete-popup')
@ -77,7 +74,6 @@ class Terminal extends Plugin {
self.registerCommand('error', self._blocksRenderer('error'), { activate: true })
self.registerCommand('script', function execute (args, scopedCommands, append) {
var script = String(args[0])
scopedCommands.log(`> ${script}`)
self._shell(script, scopedCommands, function (error, output) {
if (error) scopedCommands.error(error)
else if (output) scopedCommands.log(output)
@ -91,9 +87,6 @@ class Terminal extends Plugin {
self.registerFilter('error', basicFilter)
self.registerFilter('script', basicFilter)
self._jsSandboxContext = {}
self._jsSandboxRegistered = {}
if (opts.shell) self._shell = opts.shell // ???
register(self)
}
@ -451,20 +444,26 @@ class Terminal extends Plugin {
var intro = yo`
<div><div> - Welcome to Remix ${packageJson.version} - </div><br>
<div>You can use this terminal for: </div>
<div>You can use this terminal to: </div>
<ul class=${css2.ul}>
<li>Checking transactions details and start debugging.</li>
<li>Running JavaScript scripts. The following libraries are accessible:
<li>Check transactions details and start debugging.</li>
<li>Execute JavaScript scripts:
<br />
<i> - Input a script directly in the command line interface </i>
<br />
<i> - Select a Javascript file in the file explorer and then run \`remix.execute()\` or \`remix.exeCurrent()\` in the command line interface </i>
<br />
<i> - Right click on a JavaScript file in the file explorer and then click \`Run\` </i>
The following libraries are accessible:
<ul class=${css2.ul}>
<li><a target="_blank" href="https://web3js.readthedocs.io/en/1.0/">web3 version 1.0.0</a></li>
<li><a target="_blank" href="https://docs.ethers.io/ethers.js/html/">ethers.js</a> </li>
<li><a target="_blank" href="https://docs.ethers.io">ethers.js</a> </li>
<li><a target="_blank" href="https://www.npmjs.com/package/swarmgw">swarmgw</a> </li>
<li>remix (run remix.help() for more info)</li>
</ul>
</li>
<li>Executing common command to interact with the Remix interface (see list of commands above). Note that these commands can also be included and run from a JavaScript script.</li>
<li>Use exports/.register(key, obj)/.remove(key)/.clear() to register and reuse object across script executions.</li>
</ul>
</div>
`
@ -481,6 +480,21 @@ class Terminal extends Plugin {
return self._view.el
function wrapScript (script) {
if (script.startsWith('remix.')) return script
return `
try {
const ret = ${script};
if (ret instanceof Promise) {
ret.then((result) => { console.log(result) }).catch((error) => { console.log(error) })
} else {
console.log(ret)
}
} catch (e) {
console.log(e.message)
}
`
}
function change (event) {
if (self._components.autoCompletePopup.handleAutoComplete(
event,
@ -500,7 +514,7 @@ class Terminal extends Plugin {
self._view.input.innerText = '\n'
if (script.length) {
self._cmdHistory.unshift(script)
self.commands.script(script)
self.commands.script(wrapScript(script))
}
self._components.autoCompletePopup.removeAutoComplete()
}
@ -624,15 +638,18 @@ class Terminal extends Plugin {
error: 'text-danger' }[mode] // defaults
if (mode) {
const filterUndefined = (el) => el !== undefined && el !== null
return function logger (args, scopedCommands, append) {
var types = args.map(type)
var values = javascriptserialize.apply(null, args).map(function (val, idx) {
var types = args.filter(filterUndefined).map(type)
var values = javascriptserialize.apply(null, args.filter(filterUndefined)).map(function (val, idx) {
if (typeof args[idx] === 'string') val = args[idx]
if (types[idx] === 'element') val = jsbeautify.html(val)
return val
})
if (values.length) {
append(yo`<span class="${mode}" >${values}</span>`)
}
}
} else {
throw new Error('mode is not supported')
}
@ -707,9 +724,8 @@ class Terminal extends Plugin {
// 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 cmds = vm.createContext(context)
var result = vm.runInContext(script, cmds)
self._jsSandboxContext = Object.assign(cmds, context)
return done(null, result)
} catch (error) {
return done(error.message)
@ -726,29 +742,7 @@ class Terminal extends Plugin {
function domTerminalFeatures (self, scopedCommands, blockchain) {
return {
swarmgw,
ethers,
remix: self._components.cmdInterpreter,
web3: new Web3(blockchain.web3().currentProvider),
console: {
log: function () { scopedCommands.log.apply(scopedCommands, arguments) },
info: function () { scopedCommands.info.apply(scopedCommands, arguments) },
warn: function () { scopedCommands.warn.apply(scopedCommands, arguments) },
error: function () { scopedCommands.error.apply(scopedCommands, arguments) }
},
setTimeout: (fn, time) => {
return setTimeout(() => { self._shell('(' + fn.toString() + ')()', scopedCommands, () => {}) }, time)
},
setInterval: (fn, time) => {
return setInterval(() => { self._shell('(' + fn.toString() + ')()', scopedCommands, () => {}) }, time)
},
clearTimeout: clearTimeout,
clearInterval: clearInterval,
exports: {
register: (key, obj) => { self._jsSandboxRegistered[key] = obj },
remove: (key) => { delete self._jsSandboxRegistered[key] },
clear: () => { self._jsSandboxRegistered = {} }
}
remix: self._components.cmdInterpreter
}
}

@ -192,7 +192,7 @@ class AutoCompletePopup {
this.opts.appManager.event.on('activate', async (profile) => {
if (!profile.methods) return
profile.methods.forEach((method) => {
const key = `remix.call({name: '${profile.name}', key:'${method}', payload: []}).then((result) => { console.log(result) }).catch((error) => { console.log(error) })`
const key = `remix.call('${profile.name}', '${method}')`
const keyValue = {}
keyValue[key] = `call ${profile.name} - ${method}`
if (this.extraCommands.includes(keyValue)) return

@ -1,16 +1,12 @@
'use strict'
var yo = require('yo-yo')
var async = require('async')
var remixDebug = require('@remix-project/remix-debug')
var EventManager = require('../lib/events')
var CompilerImport = require('../app/compiler/compiler-imports')
var toolTip = require('../app/ui/tooltip')
var globalRegistry = require('../global/registry')
var SourceHighlighter = require('../app/editor/sourceHighlighter')
var RemixDebug = require('@remix-project/remix-debug').EthDebugger
var TreeView = require('../app/ui/TreeView') // TODO setup a direct reference to the UI components
var solidityTypeFormatter = require('../app/tabs/debugger/debuggerUI/vmDebugger/utils/SolidityTypeFormatter')
var GistHandler = require('./gist-handler')
class CmdInterpreterAPI {
@ -31,112 +27,14 @@ class CmdInterpreterAPI {
offsetToLineColumnConverter: self._components.registry.get('offsettolinecolumnconverter').api
}
self.commandHelp = {
'remix.call(message: {name, key, payload})': 'Call a registered plugins',
'remix.getFile(path)': 'Returns the content of the file located at the given path',
'remix.setFile(path, content)': 'set the content of the file located at the given path',
'remix.debug(hash)': 'Start debugging a transaction.',
'remix.loadgist(id)': 'Load a gist in the file explorer.',
'remix.loadurl(url)': 'Load the given url in the file explorer. The url can be of type github, swarm, ipfs or raw http',
'remix.setproviderurl(url)': 'Change the current provider to Web3 provider and set the url endpoint.',
'remix.execute(filepath)': 'Run the script specified by file path. If filepath is empty, script currently displayed in the editor is executed.',
'remix.exeCurrent()': 'Run the script currently displayed in the editor',
'remix.help()': 'Display this help message',
'remix.debugHelp()': 'Display help message for debugging'
}
}
call (message) {
return this._components.terminal.externalApi.request(message)
}
log () { arguments[0] != null ? this._components.terminal.commands.html(arguments[0]) : this._components.terminal.commands.html(arguments[1]) }
highlight (rawLocation) {
var self = this
if (!rawLocation) {
self._components.sourceHighlighter.currentSourceLocation(null)
return
}
var lineColumnPos = self._deps.offsetToLineColumnConverter.offsetToLineColumn(rawLocation, rawLocation.file,
self._deps.compilersArtefacts['__last'].getSourceCode().sources,
self._deps.compilersArtefacts['__last'].getAsts())
self._components.sourceHighlighter.currentSourceLocation(lineColumnPos, rawLocation)
}
debug (hash, cb) {
var self = this
delete self.d
self.blockchain.web3().eth.getTransaction(hash, (error, tx) => {
if (error) return cb(error)
var debugSession = new RemixDebug({
compilationResult: () => {
return self._deps.compilersArtefacts['__last'].getData()
}
})
debugSession.addProvider('web3', self.blockchain.web3())
debugSession.switchProvider('web3')
debugSession.debug(tx)
self.d = debugSession
this._components.terminal.commands.log('A new debugging session is available at remix.d')
if (cb) cb(null, debugSession)
// helpers
self.d.highlight = (address, vmtraceIndex) => {
if (!address) return self.highlight()
self.d.sourceLocationFromVMTraceIndex(address, vmtraceIndex, (error, rawLocation) => {
if (!error && rawLocation) {
self.highlight(rawLocation)
}
})
}
self.d.stateAt = (vmTraceIndex) => {
self.d.extractStateAt(vmTraceIndex, (error, state) => {
if (error) return self.log(error)
self.d.decodeStateAt(vmTraceIndex, state, (error, state) => {
if (error) return this._components.terminal.commands.html(error)
var treeView = new TreeView({
json: true,
formatSelf: solidityTypeFormatter.formatSelf,
extractData: solidityTypeFormatter.extractData
})
self.log('State at ' + vmTraceIndex)
self._components.terminal.commands.html(treeView.render(state, true))
})
})
}
self.d.localsAt = (contractAddress, vmTraceIndex) => {
debugSession.sourceLocationFromVMTraceIndex(contractAddress, vmTraceIndex, (error, location) => {
if (error) return self.log(error)
debugSession.decodeLocalsAt(23, location, (error, locals) => {
if (error) return this._components.terminal.commands.html(error)
var treeView = new TreeView({
json: true,
formatSelf: solidityTypeFormatter.formatSelf,
extractData: solidityTypeFormatter.extractData
})
self.log('Locals at ' + vmTraceIndex)
self._components.terminal.commands.html(treeView.render(locals, true))
})
})
}
self.d.goTo = (row) => {
if (self._deps.editor.current()) {
var breakPoint = new remixDebug.BreakpointManager(self.d, (sourceLocation) => {
return self._deps.offsetToLineColumnConverter.offsetToLineColumn(sourceLocation, sourceLocation.file,
self._deps.compilersArtefacts['__last'].getSourceCode().sources,
self._deps.compilersArtefacts['__last'].getAsts())
})
breakPoint.event.register('breakpointHit', (sourceLocation, currentStep) => {
self.log(null, 'step index ' + currentStep)
self.highlight(sourceLocation)
self.d.stateAt(currentStep)
self.d.traceManager.getCurrentCalledAddressAt(currentStep, (error, address) => {
if (error) return self.log(address)
self.d.localsAt(address, currentStep)
})
})
breakPoint.event.register('NoBreakpointHit', () => { self.log('line ' + row + ' is not part of the current execution') })
breakPoint.add({fileName: self._deps.editor.current(), row: row - 1})
breakPoint.jumpNextBreakpoint(0, true)
}
}
})
}
loadgist (id, cb) {
const self = this
self._components.gistHandler.loadFromGist({gist: id}, this._deps.fileManager)
@ -179,36 +77,9 @@ class CmdInterpreterAPI {
}
})
}
setproviderurl (url, cb) {
this.blockchain.setProviderFromEndpoint(url, 'web3', (error) => {
if (error) toolTip(error)
if (cb) cb()
})
}
exeCurrent (cb) {
return this.execute(undefined, cb)
}
getFile (path, cb) {
var provider = this._deps.fileManager.fileProviderOf(path)
if (provider) {
provider.get(path, cb)
} else {
cb('file not found')
}
}
setFile (path, content, cb) {
cb = cb || function () {}
var provider = this._deps.fileManager.fileProviderOf(path)
if (provider) {
provider.set(path, content, (error) => {
if (error) return cb(error)
this._deps.fileManager.syncEditor(path)
cb()
})
} else {
cb('file not found')
}
}
execute (file, cb) {
const self = this
@ -257,37 +128,6 @@ class CmdInterpreterAPI {
if (cb) cb()
return ''
}
debugHelp (cb) {
const self = this
var help = yo`<div>Here are some examples of scripts that can be run (using remix.exeCurrent() or directly from the console)</div>`
help.appendChild(yo`<br>`)
help.appendChild(yo`<br>`)
help.appendChild(yo`<div>remix.debug('0x3c247ac268afb9a9c183feb9d4e83df51efbc8a2f4624c740789b788dac43029', function (error, debugSession) {
remix.log = function () { arguments[0] != null ? console.log(arguments[0]) : console.log(arguments[1]) }
remix.d.traceManager.getLength(remix.log)
remix.storageView = remix.d.storageViewAt(97, '0x692a70d2e424a56d2c6c27aa97d1a86395877b3a')
console.log('storage at 97 :')
remix.storageView.storageRange(remix.log)
})<br/></div>`)
help.appendChild(yo`<div>remix.log = function () { arguments[0] != null ? console.log(arguments[0]) : console.log(arguments[1]) }
remix.d.extractStateAt(2, function (error, state) {
remix.d.decodeStateAt(97, state, remix.log)
})<br/></div>`)
help.appendChild(yo`<br>`)
help.appendChild(yo`<div>remix.highlight(contractAddress, vmTraceIndex)</div>`)
help.appendChild(yo`<br>`)
help.appendChild(yo`<div>remix.goTo(row) (this log the index in the vm trace, state and local variables)</div>`)
help.appendChild(yo`<br>`)
help.appendChild(yo`<div>remix.stateAt(vmTraceIndex)</div>`)
help.appendChild(yo`<br>`)
help.appendChild(yo`<div>remix.localsAt(vmTraceIndex)</div>`)
help.appendChild(yo`<br>`)
help.appendChild(yo`<div>Please see <a href="https://www.npmjs.com/package/remix-debug" target="_blank">https://www.npmjs.com/package/remix-debug</a> for more informations</div>`)
self._components.terminal.commands.html(help)
if (cb) cb()
return ''
}
}
module.exports = CmdInterpreterAPI

@ -6,16 +6,11 @@ const allPrograms = [
]
const allCommands = [
{'remix.debug(hash)': 'Start debugging a transaction.'},
{'remix.debugHelp()': 'Display help message for debugging'},
{'remix.execute(filepath)': 'Run the script specified by file path. If filepath is empty, script currently displayed in the editor is executed.'},
{'remix.exeCurrent()': 'Run the script currently displayed in the editor.'},
{'remix.getFile(path)': 'Returns the content of the file located at the given path'},
{'remix.help()': 'Display this help message.'},
{'remix.loadgist(id)': 'Load a gist in the file explorer.'},
{'remix.loadurl(url)': 'Load the given url in the file explorer. The url can be of type github, swarm or ipfs.'},
{'remix.setFile(path, content)': 'set the content of the file located at the given path'},
{'remix.setproviderurl(url)': 'Change the current provider to Web3 provider and set the url endpoint.'},
{'swarmgw.get(url, cb)': 'Download files from Swarm via https://swarm-gateways.net/'},
{'swarmgw.put(content, cb)': 'Upload files to Swarm via https://swarm-gateways.net/'},
@ -31,7 +26,6 @@ const allCommands = [
{'ethers.Wallet': 'A wallet manages a private/public key pair which is used to cryptographically sign transactions and prove ownership on the Ethereum network.'},
{'ethers.version': 'Contains the version of the ethers container object.'},
{'web3.bzz': 'Bzz module for interacting with the swarm network.'},
{'web3.eth': 'Eth module for interacting with the Ethereum network.'},
{'web3.eth.accounts': 'The web3.eth.accounts contains functions to generate Ethereum accounts and sign transactions and data.'},
{'web3.eth.abi': 'The web3.eth.abi functions let you de- and encode parameters to ABI (Application Binary Interface) for function calls to the EVM (Ethereum Virtual Machine).'},
@ -49,7 +43,12 @@ const allCommands = [
{'web3.eth.clearSubscriptions();': 'Resets subscriptions.'},
{'web3.eth.Contract(jsonInterface[, address][, options])': 'The web3.eth.Contract object makes it easy to interact with smart contracts on the ethereum blockchain.'},
{'web3.eth.accounts.create([entropy]);': 'The web3.eth.accounts contains functions to generate Ethereum accounts and sign transactions and data.'}
{'web3.eth.accounts.create([entropy]);': 'The web3.eth.accounts contains functions to generate Ethereum accounts and sign transactions and data.'},
{'web3.eth.getAccounts();': 'Retrieve the list of accounts'},
{'web3.eth.accounts.privateKeyToAccount(privateKey [, ignoreLength ]);': 'Get the account from the private key'},
{'web3.eth.accounts.signTransaction(tx, privateKey [, callback]);': 'Sign Transaction'},
{'web3.eth.accounts.recoverTransaction(rawTransaction);': 'Sign Transaction'},
{'web3.eth.accounts.hashMessage(message);': 'Hash message'},
]
module.exports = {

Loading…
Cancel
Save