Commit 0fc681fc authored by yann300's avatar yann300 Committed by GitHub

Merge pull request #687 from ethereum/terminalSerapath

Terminal serapath
parents 0e07828b 38978aba
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
"brace": "^0.8.0", "brace": "^0.8.0",
"browserify-reload": "^1.0.3", "browserify-reload": "^1.0.3",
"clipboard-copy": "^1.2.0", "clipboard-copy": "^1.2.0",
"component-type": "^1.2.1",
"csjs-inject": "^1.0.1", "csjs-inject": "^1.0.1",
"csslint": "^1.0.2", "csslint": "^1.0.2",
"ethereum-remix": "https://github.com/ethereum/remix", "ethereum-remix": "https://github.com/ethereum/remix",
...@@ -26,9 +27,12 @@ ...@@ -26,9 +27,12 @@
"execr": "^1.0.1", "execr": "^1.0.1",
"exorcist": "^0.4.0", "exorcist": "^0.4.0",
"fast-async": "^6.1.2", "fast-async": "^6.1.2",
"fast-levenshtein": "^2.0.6",
"http-server": "0.9.0", "http-server": "0.9.0",
"javascript-serialize": "^1.6.1",
"jquery": "^2.2.0", "jquery": "^2.2.0",
"js-base64": "^2.1.9", "js-base64": "^2.1.9",
"js-beautify": "^1.6.14",
"minixhr": "^3.2.2", "minixhr": "^3.2.2",
"mkdirp": "^0.5.1", "mkdirp": "^0.5.1",
"nightwatch": "^0.9.3", "nightwatch": "^0.9.3",
...@@ -45,8 +49,7 @@ ...@@ -45,8 +49,7 @@
"watchify": "^3.9.0", "watchify": "^3.9.0",
"web3": "^0.18.0", "web3": "^0.18.0",
"webworkify": "^1.2.1", "webworkify": "^1.2.1",
"yo-yo": "^1.2.2", "yo-yo": "^1.2.2"
"fast-levenshtein": "^2.0.6"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
......
...@@ -32,7 +32,7 @@ var RighthandPanel = require('./app/panels/righthand-panel') ...@@ -32,7 +32,7 @@ var RighthandPanel = require('./app/panels/righthand-panel')
var examples = require('./app/editor/example-contracts') var examples = require('./app/editor/example-contracts')
var modalDialogCustom = require('./app/ui/modal-dialog-custom') var modalDialogCustom = require('./app/ui/modal-dialog-custom')
var Txlistener = require('./app/execution/txListener') var Txlistener = require('./app/execution/txListener')
var txLogger = require('./app/execution/txLogger') var TxLogger = require('./app/execution/txLogger')
var EventsDecoder = require('./app/execution/eventsDecoder') var EventsDecoder = require('./app/execution/eventsDecoder')
var Web3VMProvider = remix.web3.web3VMProvider var Web3VMProvider = remix.web3.web3VMProvider
...@@ -107,7 +107,7 @@ class App { ...@@ -107,7 +107,7 @@ class App {
self._components.editor = new Editor({}) // @TODO: put into editorpanel self._components.editor = new Editor({}) // @TODO: put into editorpanel
// ----------------- editor panel ---------------------- // ----------------- editor panel ----------------------
self._components.editorpanel = new EditorPanel({ self._components.editorpanel = new EditorPanel({
api: { editor: self._components.editor } api: { editor: self._components.editor, config: self._api.config }
}) })
self._components.editorpanel.event.register('resize', direction => self._adjustLayout(direction)) self._components.editorpanel.event.register('resize', direction => self._adjustLayout(direction))
} }
...@@ -813,16 +813,9 @@ function run () { ...@@ -813,16 +813,9 @@ function run () {
txlistener.startListening() txlistener.startListening()
txLogger({ var txLogger = new TxLogger({
api: { api: {
/** editorpanel: self._components.editorpanel,
* log the given transaction.
*
* @param {Object} tx - DOM element representing the transaction
*/
log: function (tx) {
// terminal.log(tx)
},
resolvedTransaction: function (hash) { resolvedTransaction: function (hash) {
return txlistener.resolvedTransaction(hash) return txlistener.resolvedTransaction(hash)
}, },
...@@ -831,6 +824,9 @@ function run () { ...@@ -831,6 +824,9 @@ function run () {
}, },
compiledContracts: function () { compiledContracts: function () {
return compiledContracts() return compiledContracts()
},
context: function () {
return executionContext.getProvider()
} }
}, },
events: { events: {
...@@ -838,6 +834,10 @@ function run () { ...@@ -838,6 +834,10 @@ function run () {
} }
}) })
txLogger.event.register('debugRequested', (hash) => {
startdebugging(hash)
})
// ----------------- autoCompile ----------------- // ----------------- autoCompile -----------------
var autoCompile = document.querySelector('#autoCompile').checked var autoCompile = document.querySelector('#autoCompile').checked
if (config.exists('autoCompile')) { if (config.exists('autoCompile')) {
......
...@@ -8,10 +8,8 @@ var Range = ace.acequire('ace/range').Range ...@@ -8,10 +8,8 @@ var Range = ace.acequire('ace/range').Range
require('./mode-solidity.js') require('./mode-solidity.js')
var css = csjs` var css = csjs`
.ace-editor { .ace-editor {
font-size : 1.1em; width : 100%;
width : 100%;
height : 100%;
} }
` `
document.head.appendChild(yo` document.head.appendChild(yo`
......
'use strict' 'use strict'
var yo = require('yo-yo')
var remix = require('ethereum-remix')
var EventManager = remix.lib.EventManager
var helper = require('../../lib/helper')
var ethJSUtil = require('ethereumjs-util')
var BN = ethJSUtil.BN
/** /**
* This just export a function that register to `newTransaction` and forward them to the logger. * This just export a function that register to `newTransaction` and forward them to the logger.
* Emit debugRequested
* *
*/ */
module.exports = (opts = {}) => { class TxLogger {
opts.events.txListener.register('newTransaction', (tx) => { constructor (opts = {}) {
log(tx, opts.api) this.event = new EventManager()
}) this.opts = opts
opts.api.editorpanel.registerLogType('knownTransaction', (data) => {
return renderKnownTransaction(this, data)
})
opts.api.editorpanel.registerLogType('unknownTransaction', (data) => {
return renderUnknownTransaction(this, data)
})
opts.events.txListener.register('newTransaction', (tx) => {
log(this, tx, opts.api)
})
}
} }
function log (tx, api) { function log (self, tx, api) {
var resolvedTransaction = api.resolvedTransaction(tx.hash) var resolvedTransaction = api.resolvedTransaction(tx.hash)
if (resolvedTransaction) { if (resolvedTransaction) {
api.parseLogs(tx, resolvedTransaction.contractName, api.compiledContracts(), (error, logs) => { api.parseLogs(tx, resolvedTransaction.contractName, api.compiledContracts(), (error, logs) => {
if (!error) { if (!error) {
api.log(renderResolvedTransaction(tx, resolvedTransaction, logs)) api.editorpanel.log({type: 'knownTransaction', value: { tx: tx, resolvedData: resolvedTransaction, logs: logs }})
} }
}) })
} else { } else {
// contract unknown - just displaying raw tx. // contract unknown - just displaying raw tx.
api.log(renderTransaction(tx)) api.editorpanel.log({ type: 'unknownTransaction', value: { tx: tx } })
}
}
function renderKnownTransaction (self, data) {
var to = data.tx.to
if (to) to = helper.shortenAddress(data.tx.to)
function debug () {
self.event.trigger('debugRequested', [data.tx.hash])
}
function detail () {
// @TODO here should open a modal containing some info (e.g input params, logs, ...)
} }
return yo`<span>${context(self, data.tx)}: from:${helper.shortenAddress(data.tx.from)}, to:${to}, ${data.resolvedData.contractName}.${data.resolvedData.fn}, value:${value(data.tx.value)} wei, data:${helper.shortenHexData(data.tx.input)}, ${data.logs.length} logs, hash:${helper.shortenHexData((data.tx.hash))},<button onclick=${detail}>Details</button> <button onclick=${debug}>Debug</button></span>`
} }
function renderResolvedTransaction (tx, resolvedTransaction, logs) { function renderUnknownTransaction (self, data) {
console.log([tx, resolvedTransaction]) var to = data.tx.to
return JSON.stringify([tx, resolvedTransaction]) if (to) to = helper.shortenAddress(data.tx.to)
function debug () {
self.event.trigger('debugRequested', [data.tx.hash])
}
function detail () {
// @TODO here should open a modal containing some info (e.g input params, logs, ...)
}
return yo`<span>${context(self, data.tx)}: from:${helper.shortenAddress(data.tx.from)}, to:${to}, value:${value(data.tx.value)} wei, data:${helper.shortenHexData((data.tx.input))}, hash:${helper.shortenHexData((data.tx.hash))}, <button onclick=${detail}>Details</button> <button onclick=${debug}>Debug</button></span>`
}
function context (self, tx) {
if (self.opts.api.context() === 'vm') {
return yo`<span>(vm)</span>`
} else {
return yo`<span>block:${tx.blockNumber}, txIndex:${tx.transactionIndex}`
}
} }
function renderTransaction (tx) { function value (v) {
console.log(tx) try {
return JSON.stringify(tx) if (v.indexOf && v.indexOf('0x') === 0) {
return (new BN(v.replace('0x', ''), 16)).toString(10)
} else {
return v.toString(10)
}
} catch (e) {
console.log(e)
return v
}
} }
module.exports = TxLogger
...@@ -2,7 +2,14 @@ var csjs = require('csjs-inject') ...@@ -2,7 +2,14 @@ var csjs = require('csjs-inject')
var yo = require('yo-yo') var yo = require('yo-yo')
var EventManager = require('ethereum-remix').lib.EventManager var EventManager = require('ethereum-remix').lib.EventManager
var Terminal = require('./terminal')
var css = csjs` var css = csjs`
.editorpanel {
display : flex;
flex-direction : column;
height : 100%;
}
.tabsbar { .tabsbar {
display : flex; display : flex;
overflow : hidden; overflow : hidden;
...@@ -105,17 +112,75 @@ var css = csjs` ...@@ -105,17 +112,75 @@ var css = csjs`
pointer-events : none; pointer-events : none;
transition : .3s opacity ease-in; transition : .3s opacity ease-in;
} }
.content {
position : relative;
display : flex;
flex-direction : column;
height : 100%;
width : 100%;
}
` `
class EditorPanel { class EditorPanel {
constructor (opts = {}) { constructor (opts = {}) {
var self = this var self = this
self._api = { config: opts.api.config }
self.event = new EventManager()
self.data = { self.data = {
_FILE_SCROLL_DELTA: 200 _FILE_SCROLL_DELTA: 200,
_layout: {
top: {
offset: self._api.config.get('terminal-top-offset') || 500,
show: true
}
}
} }
self._view = {} self._view = {}
self._api = { editor: opts.api.editor } self._components = {
self.event = new EventManager() editor: opts.api.editor, // @TODO: instantiate in eventpanel instead of passing via `opts`
terminal: new Terminal({
api: {
getPosition (event) {
var limitUp = 36
var limitDown = 20
var height = window.innerHeight
var newpos = (event.pageY < limitUp) ? limitUp : event.pageY
newpos = (newpos < height - limitDown) ? newpos : height - limitDown
return newpos
}
}
})
}
self._components.terminal.event.register('resize', delta => self._adjustLayout('top', delta))
}
_adjustLayout (direction, delta) {
var limitUp = 36
var limitDown = 20
var containerHeight = window.innerHeight - limitUp // - menu bar containerHeight
var self = this
var layout = self.data._layout[direction]
if (layout) {
if (delta === undefined) {
layout.show = !layout.show
if (layout.show) delta = layout.offset
else delta = containerHeight
} else {
layout.show = true
self._api.config.set(`terminal-${direction}-offset`, delta)
layout.offset = delta
}
}
var tmp = delta - limitDown
delta = tmp > 0 ? tmp : 0
if (direction === 'top') {
var height = containerHeight - delta
height = height < 0 ? 0 : height
self._view.editor.style.height = `${delta}px`
self._view.terminal.style.height = `${height}px` // - menu bar height
self._components.editor.resize((document.querySelector('#editorWrap') || {}).checked)
self._components.terminal.scroll2bottom()
}
} }
refresh () { refresh () {
var self = this var self = this
...@@ -124,12 +189,32 @@ class EditorPanel { ...@@ -124,12 +189,32 @@ class EditorPanel {
render () { render () {
var self = this var self = this
if (self._view.el) return self._view.el if (self._view.el) return self._view.el
self._view.el = [ self._view.editor = self._components.editor.render()
self._renderTabsbar(), self._view.terminal = self._components.terminal.render()
self._api.editor.render() self._view.content = yo`
] <div class=${css.content}>
${self._view.editor}
${self._view.terminal}
</div>
`
self._view.el = yo`
<div class=${css.editorpanel}>
${self._renderTabsbar()}
${self._view.content}
</div>
`
// INIT
self._adjustLayout('top', self.data._layout.top.offset)
return self._view.el return self._view.el
} }
registerLogType (typename, template) {
var self = this
self._components.terminal.registerType(typename, template)
}
log () {
var self = this
self._components.terminal.log.apply(self._components.terminal, arguments)
}
_renderTabsbar () { _renderTabsbar () {
var self = this var self = this
if (self._view.tabsbar) return self._view.tabsbar if (self._view.tabsbar) return self._view.tabsbar
...@@ -197,8 +282,8 @@ class EditorPanel { ...@@ -197,8 +282,8 @@ class EditorPanel {
this.children[0].classList.toggle('fa-angle-double-left') this.children[0].classList.toggle('fa-angle-double-left')
self.event.trigger('resize', ['right']) self.event.trigger('resize', ['right'])
} }
function increase () { self._api.editor.editorFontSize(1) } function increase () { self._components.editor.editorFontSize(1) }
function decrease () { self._api.editor.editorFontSize(-1) } function decrease () { self._components.editor.editorFontSize(-1) }
function scrollLeft (event) { function scrollLeft (event) {
var leftArrow = this var leftArrow = this
var rightArrow = this.nextElementSibling.nextElementSibling var rightArrow = this.nextElementSibling.nextElementSibling
......
...@@ -228,7 +228,7 @@ function filepanel (appAPI, filesProvider) { ...@@ -228,7 +228,7 @@ function filepanel (appAPI, filesProvider) {
newpos = (newpos < (rhp - limit)) ? newpos : (rhp - limit) newpos = (newpos < (rhp - limit)) ? newpos : (rhp - limit)
return newpos return newpos
} }
function moveGhostbar (event) { function moveGhostbar (event) { // @NOTE VERTICAL ghostbar
ghostbar.style.left = getPosition(event) + 'px' ghostbar.style.left = getPosition(event) + 'px'
} }
function removeGhostbar (event) { function removeGhostbar (event) {
......
...@@ -132,7 +132,7 @@ function RighthandPanel (appAPI, events, opts) { ...@@ -132,7 +132,7 @@ function RighthandPanel (appAPI, events, opts) {
newpos = (newpos > (lhp + limit)) ? newpos : lhp + limit newpos = (newpos > (lhp + limit)) ? newpos : lhp + limit
return newpos return newpos
} }
function moveGhostbar (event) { function moveGhostbar (event) { // @NOTE VERTICAL ghostbar
ghostbar.style.left = getPosition(event) + 'px' ghostbar.style.left = getPosition(event) + 'px'
} }
function removeGhostbar (event) { function removeGhostbar (event) {
......
/* global Node */
var yo = require('yo-yo')
var csjs = require('csjs-inject')
var javascriptserialize = require('javascript-serialize')
var jsbeautify = require('js-beautify')
var type = require('component-type')
var EventManager = require('ethereum-remix').lib.EventManager
var css = csjs`
.panel {
position : relative;
display : flex;
flex-direction : column;
font-size : 12px;
font-family : monospace;
color : white;
background-color : grey;
margin-top : auto;
height : 100%;
min-height : 1.7em;
}
.bar {
display : flex;
justify-content : flex-end;
min-height : 1.7em;
padding : 2px;
cursor : ns-resize;
background-color : #eef;
}
.minimize {
text-align : center;
padding-top : 3px;
width : 10px;
min-height : 100%;
cursor : pointer;
color : black;
}
.hover {
color : orange;
}
.terminal {
display : flex;
flex-direction : column;
height : 100%;
padding-left : 5px;
padding-right : 5px;
padding-bottom : 3px;
overflow-y : auto;
font-family : monospace;
}
.log {
margin-top : auto;
font-family : monospace;
}
.block {
word-break : break-all;
white-space : pre-wrap;
line-height : 2ch;
margin : 1ch;
}
.cli {
line-height : 1.7em;
font-family : monospace;
}
.prompt {
margin-right : 0.5em;
font-family : monospace;
}
.input {
word-break : break-all;
outline : none;
font-family : monospace;
}
.error {
color : red;
}
.info {
color : blue;
}
.default {
color : white;
}
.ghostbar {
position : absolute;
height : 6px;
background-color : #C6CFF7;
opacity : 0.5;
cursor : row-resize;
z-index : 9999;
left : 0;
right : 0;
}
`
var currentError
window.addEventListener('error', function (event) {
currentError = new Error(event.message)
currentError.timeStamp = event.timeStamp
currentError.isTrusted = event.isTrusted
currentError.filename = event.filename
currentError.lineno = event.lineno
currentError.colno = event.colno
currentError.error = event.error
currentError.type = event.type
})
window.onerror = function (msg, url, lineno, col, error) {
if (!error) error = currentError
var val = { msg: msg, url: url, lineno: lineno, col: col, error: error }
console.error(val)
}
var KONSOLES = []
// var KONSOLES = [{
// error: console.error.bind(console),
// info: console.info.bind(console),
// log: console.log.bind(console)
// }]
// console.error = broadcast('error')
// console.info = broadcast('info')
// console.log = broadcast('log')
//
// function broadcast (mode) {
// return function broadcastMode () {
// var args = arguments
// KONSOLES.forEach(function (api) { api[mode].apply(api, args) })
// }
// }
function register (api) { KONSOLES.push(api) }
var ghostbar = yo`<div class=${css.ghostbar}></div>`
class Terminal {
constructor (opts = { auto: true }) {
var self = this
self.data = {
lineLength: opts.lineLength || 80,
session: [],
banner: opts.banner || `
/******************************************************************************
...........................................
.....................:.....................
....................o:;....................
...................oo:;;...................
..................ooo:;;;..................
.................oooo:;;;;.................
................ooooo:;;;;;................
...............oooooo:;;;;;;...............
..............ooooooo:;;;;;;;..............
.............ooooooo;:';;;;;;;.............
............ooooo;;;;:'''';;;;;............
...........oo;;;;;;;;:'''''''';;...........
..........;;;;;;;;;;;:'''''''''''..........
..............;;;;;;;:'''''''..............
...........oo...;;;;;:'''''...;;...........
............oooo...;;:''...;;;;............
..............oooo...:...;;;;..............
...............oooooo:;;;;;;...............
................ooooo:;;;;;................
.................oooo:;;;;.................
..................ooo:;;;..................
...................oo:;;...................
....................o:;....................
.....................:.....................
...........................................
######## ######## ## ## #### ## ##
## ## ## ### ### ## ## ##
## ## ## #### #### ## ## ##
######## ###### ## ### ## ## ###
## ## ## ## ## ## ## ##
## ## ## ## ## ## ## ##
## ## ######## ## ## #### ## ##
welcome to browser solidity
new features:
- dom terminal v0.0.1-alpha
******************************************************************************/
`
}
self.event = new EventManager()
self._api = opts.api
self._view = { panel: null, bar: null, input: null, term: null, log: null, cli: null }
self._templates = {}
self._templates.default = self._blocksRenderer('default')
self._templates.error = self._blocksRenderer('error')
self._templates.info = self._blocksRenderer('info')
if (opts.shell) self._shell = opts.shell
register(self)
}
render () {
var self = this
if (self._view.panel) return self._view.panel
self._view.log = yo`<div class=${css.log}></div>`
self._view.input = yo`
<span class=${css.input} contenteditable="true" onkeydown=${change}></span>
`
self._view.cli = yo`
<div class=${css.cli} onclick=${e => self._view.input.focus()}>
<span class=${css.prompt}>${'>'}</span>
${self._view.input}
</div>
`
self._view.icon = yo`<i onmouseenter=${hover} onmouseleave=${hover} onmousedown=${minimize} class="${css.minimize} fa fa-angle-double-down"></i>`
self._view.bar = yo`
<div class=${css.bar} onmousedown=${mousedown}>
${self._view.icon}
</div>
`
self._view.term = yo`
<div class=${css.terminal} onscroll=${reattach}>
${self._view.log}
${self._view.cli}
</div>
`
self._view.panel = yo`
<div class=${css.panel}>
${self._view.bar}
${self._view.term}
</div>
`
self.log(self.data.banner)
function reattach (event) {
var el = event.currentTarget
var isBottomed = el.scrollHeight - el.scrollTop === el.clientHeight
if (isBottomed) {
delete self.scroll2bottom
// @TODO: delete new message indicator
} else {
// self.scroll2bottom = function () { }
// @TODO: the reattach is not working
// @TODO: while in stopped mode: show indicator about new lines getting logged
}
}
function hover (event) { event.currentTarget.classList.toggle(css.hover) }
function minimize (event) {
event.preventDefault()
event.stopPropagation()
var classList = self._view.icon.classList
classList.toggle('fa-angle-double-down')
classList.toggle('fa-angle-double-up')
self.event.trigger('resize', [])
}
// ----------------- resizeable ui ---------------
function mousedown (event) {
event.preventDefault()
if (event.which === 1) {
moveGhostbar(event)
document.body.appendChild(ghostbar)
document.addEventListener('mousemove', moveGhostbar)
document.addEventListener('mouseup', removeGhostbar)
document.addEventListener('keydown', cancelGhostbar)
}
}
function cancelGhostbar (event) {
if (event.keyCode === 27) {
document.body.removeChild(ghostbar)
document.removeEventListener('mousemove', moveGhostbar)
document.removeEventListener('mouseup', removeGhostbar)
document.removeEventListener('keydown', cancelGhostbar)
}
}
function moveGhostbar (event) { // @NOTE HORIZONTAL ghostbar
ghostbar.style.top = self._api.getPosition(event) + 'px'
}
function removeGhostbar (event) {
if (self._view.icon.classList.contains('fa-angle-double-up')) {
self._view.icon.classList.toggle('fa-angle-double-down')
self._view.icon.classList.toggle('fa-angle-double-up')
}
document.body.removeChild(ghostbar)
document.removeEventListener('mousemove', moveGhostbar)
document.removeEventListener('mouseup', removeGhostbar)
document.removeEventListener('keydown', cancelGhostbar)
self.event.trigger('resize', [self._api.getPosition(event)])
}
return self._view.panel
function change (event) {
if (event.which === 13) {
if (event.ctrlKey) { // <ctrl+enter>
self._view.input.appendChild(document.createElement('br'))
self.scroll2bottom()
putCursor2End(self._view.input)
} else { // <enter>
event.preventDefault()
self.execute(self._view.input.innerText)
self._view.input.innerHTML = ''
}
}
}
function putCursor2End (editable) {
var range = document.createRange()
range.selectNode(editable)
var child = editable
var chars
while (child) {
if (child.lastChild) child = child.lastChild
else break
if (child.nodeType === Node.TEXT_NODE) {
chars = child.textContent.length
} else {
chars = child.innerHTML.length
}
}
range.setEnd(child, chars)
var toStart = true
var toEnd = !toStart
range.collapse(toEnd)
var sel = window.getSelection()
sel.removeAllRanges()
sel.addRange(range)
editable.focus()
}
}
_blocksRenderer (mode) {
var self = this
var modes = { log: true, info: true, error: true, default: true }
if (modes[mode]) {
return function render () {
var args = [].slice.call(arguments)
var types = args.map(type)
var values = javascriptserialize.apply(null, args).map(function (val, idx) {
if (types[idx] === 'element') val = jsbeautify.html(val)
var pattern = '.{1,' + self.data.lineLength + '}'
var lines = val.match(new RegExp(pattern, 'g'))
return lines.map(str => document.createTextNode(`${str}\n`))
})
return values
}
} else {
throw new Error('mode is not supported')
}
}
registerType (typename, template) {
var self = this
if (typeof template !== 'function') throw new Error('invalid template')
self._templates[typename] = template
}
log () {
var self = this
var args = [...arguments]
self.data.session.push(args)
args.forEach(function (data = {}) {
if (!data.type) data = { type: 'default', value: data }
var render = self._templates[data.type]
if (!render) render = self._templates.default
var blocks = render(data.value)
blocks = blocks instanceof Array ? blocks : [blocks]
blocks.forEach(function (block) {
self._view.log.appendChild(yo`
<div class="${css.block} ${css[data.type] || data.type}">
${block}
</div>
`)
self.scroll2bottom()
})
})
}
scroll2bottom () {
var self = this
setTimeout(function () {
self._view.term.scrollTop = self._view.term.scrollHeight
}, 0)
}
execute (input) {
var self = this
input = String(input)
self.log(`> ${input}`)
self._shell(input, function (error, output) {
if (error) {
self.error(error)
return error
} else {
self.log(output)
return output
}
})
}
_shell (input, done) { // default shell
// @TODO: add environment and proxy console.log to self.log
// make `web3` object available in the console vm
try {
var result = eval(input) // eslint-disable-line
done(null, result)
} catch (error) {
done(error.message)
}
}
}
module.exports = Terminal
...@@ -2,5 +2,10 @@ module.exports = { ...@@ -2,5 +2,10 @@ module.exports = {
shortenAddress: function (address, etherBalance) { shortenAddress: function (address, etherBalance) {
var len = address.length var len = address.length
return address.slice(0, 5) + '...' + address.slice(len - 5, len) + (etherBalance ? ' (' + etherBalance.toString() + ' ether)' : '') return address.slice(0, 5) + '...' + address.slice(len - 5, len) + (etherBalance ? ' (' + etherBalance.toString() + ' ether)' : '')
},
shortenHexData: function (data) {
if (data.length < 5) return data
var len = data.length
return data.slice(0, 5) + '...' + data.slice(len - 5, len)
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment