Commit abb098ab authored by serapath's avatar serapath Committed by yann300

ADD terminal value parsing + basic evaluation

parent d0d13b00
...@@ -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",
......
/* global Node */
var yo = require('yo-yo') var yo = require('yo-yo')
var csjs = require('csjs-inject') 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 EventManager = require('ethereum-remix').lib.EventManager
var css = csjs` var css = csjs`
...@@ -54,10 +58,10 @@ var css = csjs` ...@@ -54,10 +58,10 @@ var css = csjs`
.block { .block {
word-break : break-all; word-break : break-all;
white-space : pre-wrap; white-space : pre-wrap;
line-height : 1ch; line-height : 2ch;
min-height : 1ch;
width : 80ch; width : 80ch;
background-color : darkblue; background-color : black;
margin : 1ch;
} }
.cli { .cli {
...@@ -73,6 +77,15 @@ var css = csjs` ...@@ -73,6 +77,15 @@ var css = csjs`
outline : none; outline : none;
font-family : monospace; font-family : monospace;
} }
.error {
color : red;
}
.info {
color : blue;
}
.log {
color : white;
}
.ghostbar { .ghostbar {
position : absolute; position : absolute;
height : 6px; height : 6px;
...@@ -85,17 +98,55 @@ var css = csjs` ...@@ -85,17 +98,55 @@ var css = csjs`
} }
` `
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>` var ghostbar = yo`<div class=${css.ghostbar}></div>`
class Terminal { class Terminal {
constructor (opts = {}) { constructor (opts = { auto: true }) {
var self = this var self = this
self.data = { self.data = {
lineLength: opts.lineLength || 80,
session: [], session: [],
banner: opts.banner || ` banner: opts.banner || `
/****************************************************************************** /******************************************************************************
........................................... ...........................................
.....................:..................... .....................:.....................
....................o:;.................... ....................o:;....................
...@@ -121,8 +172,8 @@ class Terminal { ...@@ -121,8 +172,8 @@ class Terminal {
....................o:;.................... ....................o:;....................
.....................:..................... .....................:.....................
........................................... ...........................................
######## ######## ## ## #### ## ## ######## ######## ## ## #### ## ##
## ## ## ### ### ## ## ## ## ## ## ### ### ## ## ##
## ## ## #### #### ## ## ## ## ## ## #### #### ## ## ##
...@@ -130,12 +181,13 @@ class Terminal { ...@@ -130,12 +181,13 @@ class Terminal {
## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
## ## ######## ## ## #### ## ## ## ## ######## ## ## #### ## ##
welcome to browser solidity welcome to browser solidity
new features: new features:
- dom terminal v0.0.1-alpha - dom terminal v0.0.1-alpha
******************************************************************************/ ******************************************************************************/
` `
} }
...@@ -143,6 +195,7 @@ class Terminal { ...@@ -143,6 +195,7 @@ class Terminal {
self._api = opts.api self._api = opts.api
self._view = { panel: null, bar: null, input: null, term: null, log: null, cli: null } self._view = { panel: null, bar: null, input: null, term: null, log: null, cli: null }
if (opts.shell) self._shell = opts.shell if (opts.shell) self._shell = opts.shell
// @TODO: listen to all relevant events
// var events = opts.events // var events = opts.events
// events.txlistener.register('newBlock', function (block) { // events.txlistener.register('newBlock', function (block) {
// self.log(block) // self.log(block)
...@@ -152,18 +205,13 @@ class Terminal { ...@@ -152,18 +205,13 @@ class Terminal {
// // - trans.sent and info about it once it's mined // // - trans.sent and info about it once it's mined
// // - everything related to the address // // - everything related to the address
// }) // })
// //////// register(self)
// make `web3` object available in the console vm
// web3.object creates contract
// * create transaction
// * when transaction is mined
// => show all transactions, that are mined and have known addresses
} }
render () { render () {
var self = this var self = this
if (self._view.panel) return self._view.panel if (self._view.panel) return self._view.panel
self._view.log = yo`<div class=${css.log}></div>` self._view.log = yo`<div class=${css.log}></div>`
window.INPUT = self._view.input = yo` self._view.input = yo`
<span class=${css.input} contenteditable="true" onkeydown=${change}></span> <span class=${css.input} contenteditable="true" onkeydown=${change}></span>
` `
self._view.cli = yo` self._view.cli = yo`
...@@ -179,7 +227,7 @@ class Terminal { ...@@ -179,7 +227,7 @@ class Terminal {
</div> </div>
` `
self._view.term = yo` self._view.term = yo`
<div class=${css.terminal}> <div class=${css.terminal} onscroll=${reattach}>
${self._view.log} ${self._view.log}
${self._view.cli} ${self._view.cli}
</div> </div>
...@@ -191,8 +239,18 @@ class Terminal { ...@@ -191,8 +239,18 @@ class Terminal {
</div> </div>
` `
self.log(self.data.banner) self.log(self.data.banner)
// @TODO: on manual scroll, stop auto-scroll-to-bottom
// @TODO: while in stopped mode: show indicator about new lines getting logged 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: while in stopped mode: show indicator about new lines getting logged
}
}
function hover (event) { event.currentTarget.classList.toggle(css.hover) } function hover (event) { event.currentTarget.classList.toggle(css.hover) }
function minimize (event) { function minimize (event) {
event.preventDefault() event.preventDefault()
...@@ -237,51 +295,91 @@ class Terminal { ...@@ -237,51 +295,91 @@ class Terminal {
} }
return self._view.panel return self._view.panel
function change (event) { function change (event) {
if (event.which === 13) { if (event.which === 13) {
if (event.ctrlKey) { // <ctrl+enter> if (event.ctrlKey) { // <ctrl+enter>
// console.log('enter')
self._view.input.appendChild(document.createElement('br')) self._view.input.appendChild(document.createElement('br'))
self.scroll2bottom() self.scroll2bottom()
} else { putCursor2End(self._view.input)
} else { // <enter>
event.preventDefault() event.preventDefault()
self.execute(self._view.input.innerText)
self._view.input.innerHTML = ''
} }
} }
console.log(event.which, event.keyCode) }
// console.log('----------------') function putCursor2End (editable) {
// console.log(event.key) // Control var range = document.createRange()
// console.log('-----') range.selectNode(editable)
// console.log(event.code) // ControlLeft var child = editable
// console.log('-----------') var chars
// console.log('event.altKey ' + event.altKey)
// console.log('event.ctrlKey ' + event.ctrlKey) while (child) {
// console.log('event.metaKey ' + event.metaKey) if (child.lastChild) child = child.lastChild
// console.log('event.shiftKey ' + event.shiftKey) else break
// console.log(event.location) if (child.nodeType === Node.TEXT_NODE) {
// console.log('event.location') chars = child.textContent.length
// console.log(event.returnValue) } else {
// console.log('event.returnValue') chars = child.innerHTML.length
// console.log(event.type) }
// console.log('event.type') }
// console.log('-----')
// console.log(event) range.setEnd(child, chars)
var toStart = true
var toEnd = !toStart
range.collapse(toEnd)
var sel = window.getSelection()
sel.removeAllRanges()
sel.addRange(range)
editable.focus()
} }
} }
log (obj) { _log (mode) {
var self = this var self = this
// var entries = self._serialize(obj) var modes = { log: true, info: true, error: true }
// @TODO: convert types to \n string arrays if (modes[mode]) {
return function logger () {
var entries = obj.split('\n') var args = [].slice.call(arguments)
self.data.session.push(entries) self.data.session.push(args)
var block = yo` var types = args.map(type)
<div class=${css.block}> var values = javascriptserialize.apply(null, args).map(function (x, i) {
${entries.map(str => document.createTextNode(`${str}\n`))} return (typeof args[i] === 'string') ? args[i] : x
</div> })
` values.forEach(function (val, idx) {
self._view.log.appendChild(block) if (types[idx] === 'element') val = jsbeautify.html(val)
self.scroll2bottom() var pattern = '.{1,' + self.data.lineLength + '}'
return entries var lines = val.match(new RegExp(pattern, 'g'))
var block = yo`
<div class="${css.block} ${css[mode]}">
${lines.map(str => {
return document.createTextNode(`${str}\n`)
})}
</div>
`
self._view.log.appendChild(block)
self.scroll2bottom()
return lines
})
}
}
}
log () {
var self = this
var logger = self._log('log')
return logger.apply(self, arguments)
}
info () {
var self = this
var logger = self._log('info')
return logger.apply(self, arguments)
}
error () {
var self = this
var logger = self._log('error')
return logger.apply(self, arguments)
} }
scroll2bottom () { scroll2bottom () {
var self = this var self = this
...@@ -289,12 +387,33 @@ class Terminal { ...@@ -289,12 +387,33 @@ class Terminal {
self._view.term.scrollTop = self._view.term.scrollHeight self._view.term.scrollTop = self._view.term.scrollHeight
}, 0) }, 0)
} }
_serialize (obj) { return JSON.stringify(obj, null, 2) } execute (input) {
_shell (text) { // default shell
var self = this var self = this
self.log(text) input = String(input)
var result = self.evaluate(text) self.log(`> ${input}`)
self.log(result) 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
// web3.object creates contract
// * create transaction
// * when transaction is mined
// => show all transactions, that are mined and have known addresses
try {
var result = eval(input) // eslint-disable-line
done(null, result)
} catch (error) {
done(error.message)
}
} }
} }
......
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