From 94ff6297497c1dbe729332fe8b4b29eedd52496b Mon Sep 17 00:00:00 2001 From: serapath Date: Thu, 31 Aug 2017 23:49:32 +0200 Subject: [PATCH 01/13] add terminal menu bar with clear/filter/... --- src/app/panels/terminal.js | 98 +++++++++++++++++++++++++++----------- 1 file changed, 71 insertions(+), 27 deletions(-) diff --git a/src/app/panels/terminal.js b/src/app/panels/terminal.js index 9239eef834..053509213a 100644 --- a/src/app/panels/terminal.js +++ b/src/app/panels/terminal.js @@ -9,6 +9,7 @@ var EventManager = require('ethereum-remix').lib.EventManager var Web3 = require('web3') var executionContext = require('../../execution-context') +var Dropdown = require('../ui/dropdown') var css = csjs` .panel { @@ -27,17 +28,29 @@ var css = csjs` .bar { display : flex; - justify-content : flex-end; min-height : 1.7em; padding : 2px; - cursor : ns-resize; background-color : #eef; + z-index : 3; + } + .menu { + position : relative; + display : flex; + align-items : center; + width : 100%; + } + .title { + margin-right : 15px; } .minimize { - text-align : center; - padding-top : 3px; + margin-left : auto; width : 10px; - min-height : 100%; + cursor : pointer; + color : black; + } + .clear { + margin-right : 5px; + font-size : 15px; cursor : pointer; color : black; } @@ -172,6 +185,21 @@ class Terminal { } self.event = new EventManager() self._api = opts.api + self._components = {} + self._components.dropdown = new Dropdown({ + options: [ + 'knownTransaction', + 'unknownTransaction', + 'script' + ], + defaults: ['knownTransaction', 'script'] + }) + self._components.dropdown.event.register('deselect', function (label) { + console.log('deselect', label) + }) + self._components.dropdown.event.register('select', function (label) { + console.log('select', label) + }) self._view = { el: null, bar: null, input: null, term: null, journal: null, cli: null } self._templates = {} self.logger = {} @@ -198,14 +226,23 @@ class Terminal { ` self._view.icon = yo`` self._view.dragbar = yo`
` + self._view.dropdown = self._components.dropdown.render() self._view.bar = yo`
${self._view.dragbar} - ${self._view.icon} +
+
Remix Terminal
+
+ +
+ ${self._view.dropdown} +
+ ${self._view.icon} +
` self._view.term = yo` -
+
${self._view.journal} ${self._view.cli}
@@ -218,16 +255,15 @@ class Terminal { ` self._output(self.data.banner) - function focusinput (event) { - if (self._view.journal.offsetHeight - (self._view.term.scrollTop + self._view.term.offsetHeight) < 50) { - refocus() + function throttle (fn, wait) { + var time = Date.now() + return function debounce () { + if ((time + wait - Date.now()) < 0) { + fn.apply(this, arguments) + time = Date.now() + } } } - function refocus () { - self._view.input.focus() - reattach({ currentTarget: self._view.term }) - self.scroll2bottom() - } var css2 = csjs` .anchor { position : static; @@ -264,18 +300,20 @@ class Terminal { var placeholder = yo`
${background}${text}
` var inserted = false - function throttle (fn, wait) { - var time = Date.now() - return function () { - if ((time + wait - Date.now()) < 0) { - fn.apply(this, arguments) - time = Date.now() - } + function focusinput (event) { + if (self._view.journal.offsetHeight - (self._view.term.scrollTop + self._view.term.offsetHeight) < 50) { + refocus() } } + function refocus () { + self._view.input.focus() + reattach({ currentTarget: self._view.term }) + delete self.scroll2bottom + self.scroll2bottom() + } function reattach (event) { var el = event.currentTarget - var isBottomed = el.scrollHeight - el.scrollTop < el.clientHeight + 30 + var isBottomed = el.scrollHeight - el.scrollTop - el.clientHeight < 30 if (isBottomed) { if (inserted) { text.innerText = '' @@ -341,6 +379,16 @@ class Terminal { self.event.trigger('resize', []) } } + function filter (event) { + var input = event.currentTarget + setTimeout(function () { + console.log('filter', input.value) + }, 0) + } + function clear (event) { + refocus() + self._view.journal.innerHTML = '' + } // ----------------- resizeable ui --------------- function mousedown (event) { event.preventDefault() @@ -461,10 +509,6 @@ class Terminal { self._output.apply(self, args) } } - log () { - // @TODO: temporary to not break stuff that uses the old API - this._output.apply(this, arguments) - } _output () { var self = this var args = [...arguments] From 224eb8b71b7c18f8b0ffa132a3d69f03881e62fb Mon Sep 17 00:00:00 2001 From: serapath Date: Sat, 2 Sep 2017 20:31:00 +0200 Subject: [PATCH 02/13] REFACTOR terminal api + build index structure for filtering --- src/app/execution/txLogger.js | 16 ++-- src/app/panels/editor-panel.js | 8 +- src/app/panels/terminal.js | 140 +++++++++++++++++++-------------- 3 files changed, 91 insertions(+), 73 deletions(-) diff --git a/src/app/execution/txLogger.js b/src/app/execution/txLogger.js index 84781976b9..3a4e35885c 100644 --- a/src/app/execution/txLogger.js +++ b/src/app/execution/txLogger.js @@ -16,11 +16,15 @@ class TxLogger { constructor (opts = {}) { this.event = new EventManager() this.opts = opts - opts.api.editorpanel.registerLogType('knownTransaction', (data) => { - return renderKnownTransaction(this, data) + this.logKnownTX = opts.api.editorpanel.registerCommand('knownTransaction', (args, cmds, append) => { + var data = args[0] + var el = renderKnownTransaction(this, data) + append(el) }) - opts.api.editorpanel.registerLogType('unknownTransaction', (data) => { - return renderUnknownTransaction(this, data) + this.logUnknownTX = opts.api.editorpanel.registerCommand('unknownTransaction', (args, cmds, append) => { + var data = args[0] + var el = renderUnknownTransaction(this, data) + append(el) }) opts.api.editorpanel.registerLogType('emptyBlock', (data) => { return renderEmptyBlock(this, data) @@ -43,12 +47,12 @@ function log (self, tx, api) { if (resolvedTransaction) { api.parseLogs(tx, resolvedTransaction.contractName, api.compiledContracts(), (error, logs) => { if (!error) { - api.editorpanel.log({type: 'knownTransaction', value: { tx: tx, resolvedData: resolvedTransaction, logs: logs }}) + self.logKnownTX({ tx: tx, resolvedData: resolvedTransaction, logs: logs }) } }) } else { // contract unknown - just displaying raw tx. - api.editorpanel.log({ type: 'unknownTransaction', value: { tx: tx } }) + self.logUnknownTX({ tx: tx }) } } diff --git a/src/app/panels/editor-panel.js b/src/app/panels/editor-panel.js index 4674232e05..94795b2420 100644 --- a/src/app/panels/editor-panel.js +++ b/src/app/panels/editor-panel.js @@ -215,13 +215,9 @@ class EditorPanel { self._adjustLayout('top', self.data._layout.top.offset) return self._view.el } - registerLogType (typename, template) { + registerCommand (name, command) { var self = this - self._components.terminal.registerType(typename, template) - } - log () { - var self = this - self._components.terminal._output.apply(self._components.terminal, arguments) + return self._components.terminal.registerCommand(name, command) } _renderTabsbar () { var self = this diff --git a/src/app/panels/terminal.js b/src/app/panels/terminal.js index 053509213a..f26103e94a 100644 --- a/src/app/panels/terminal.js +++ b/src/app/panels/terminal.js @@ -91,17 +91,7 @@ var css = csjs` outline : none; font-family : monospace; } - - .error { - color : red; - } - .info { - color : blue; - } - .log { - color : black; - } - + .dragbarHorizontal { position : absolute; top : 0; @@ -201,10 +191,23 @@ class Terminal { console.log('select', label) }) self._view = { el: null, bar: null, input: null, term: null, journal: null, cli: null } - self._templates = {} - self.logger = {} - ;['log', 'info', 'error'].forEach(typename => { - self.registerType(typename, self._blocksRenderer(typename)) + self._commands = {} + self.commands = {} + self._INDEX = {} + self._INDEX.all = [] + self._INDEX.allMain = [] + self._INDEX.commands = {} + self._INDEX.commandsMain = {} + self.registerCommand('log', self._blocksRenderer('log')) + self.registerCommand('info', self._blocksRenderer('info')) + self.registerCommand('error', self._blocksRenderer('error')) + self.registerCommand('script', function execute (args, scopedCommands, append) { + var script = String(args[0]) + scopedCommands.log(`> ${script}`) + self._shell(script, function (error, output) { + if (error) scopedCommands.error(error) + else scopedCommands.log(output) + }) }) self._jsSandboxContext = {} self._jsSandbox = vm.createContext(self._jsSandboxContext) @@ -253,7 +256,7 @@ class Terminal { ${self._view.term}
` - self._output(self.data.banner) + self.commands.log(self.data.banner) function throttle (fn, wait) { var time = Date.now() @@ -466,12 +469,17 @@ class Terminal { editable.focus() } } + scroll2bottom () { + var self = this + setTimeout(function () { + self._view.term.scrollTop = self._view.term.scrollHeight + }, 0) + } _blocksRenderer (mode) { var self = this - var modes = { log: true, info: true, error: true } - if (modes[mode]) { - return function render () { - var args = [].slice.call(arguments) + mode = { log: 'black', info: 'blue', error: 'red' }[mode] // defaults + if (mode) { + return function logger (args, scopedCommands, append) { var types = args.map(type) var values = javascriptserialize.apply(null, args).map(function (val, idx) { if (typeof args[idx] === 'string') val = args[idx] @@ -480,59 +488,67 @@ class Terminal { var lines = val.match(new RegExp(pattern, 'g')) return lines.map(str => document.createTextNode(`${str}\n`)) }) - return values + append(yo`${values}`) } } else { throw new Error('mode is not supported') } } - execute (script) { + _scopeCommands (append) { var self = this - script = String(script) - self._output({ type: 'log', value: `> ${script}` }) - self._shell(script, function (error, output) { - if (error) { - self._output({ type: 'error', value: error }) - return error - } else { - self._output({ type: 'log', value: output }) - return output + var scopedCommands = {} + Object.keys(self.commands).forEach(function makeScopedCommand (cmd) { + var command = self._commands[cmd] + scopedCommands[cmd] = function _command () { + var args = arguments + command(args, scopedCommands, el => append(cmd, args, el)) } }) + return scopedCommands } - registerType (typename, template) { - var self = this - if (typeof template !== 'function') throw new Error('invalid template') - self._templates[typename] = template - self.logger[typename] = function () { - var args = [...arguments].map(x => ({ type: typename, value: x })) - self._output.apply(self, args) - } - } - _output () { + registerCommand (name, command) { var self = this - var args = [...arguments] - self.data.session.push(args) - args.forEach(function (data) { - if (!data || !data.type) data = { type: 'log', value: data } - var render = self._templates[data.type] - var blocks = render(data.value) - blocks = [].concat(blocks) - blocks.forEach(function (block) { + name = String(name) + if (self._commands[name]) throw new Error(`command "${name}" exists already`) + if (typeof command !== 'function') throw new Error(`invalid command: ${command}`) + self._commands[name] = command + self._INDEX.commands[name] = [] + self._INDEX.commandsMain[name] = [] + self.commands[name] = function _command () { + var args = [...arguments] + var steps = [] + var root = { steps, cmd: name } + var ITEM = { root, cmd: name } + root.gidx = self._INDEX.allMain.push(ITEM) - 1 + root.idx = self._INDEX.commandsMain[name].push(ITEM) - 1 + function append (cmd, params, el) { + var item + if (cmd) { // subcommand + item = { el, cmd, root } + } else { // command + item = ITEM + item.el = el + cmd = name + } + item.gidx = self._INDEX.all.push(item) - 1 + item.idx = self._INDEX.commands[cmd].push(item) - 1 + item.step = steps.push(item) - 1 + item.args = params self._view.journal.appendChild(yo` -
- ${block} -
+
${el}
`) self.scroll2bottom() - }) - }) - } - scroll2bottom () { - var self = this - setTimeout(function () { - self._view.term.scrollTop = self._view.term.scrollHeight - }, 0) + } + var scopedCommands = self._scopeCommands(append) + command(args, scopedCommands, el => append(null, args, el)) + } + var help = typeof command.help === 'string' ? command.help : [ + `// no help available for:`, + `terminal.commands.${name}(...)` + ].join('\n') + self.commands[name].toString = _ => { return help } + self.commands[name].help = help + return self.commands[name] } _shell (script, done) { // default shell var self = this @@ -552,7 +568,9 @@ function domTerminalFeatures (self) { return { web3: executionContext.getProvider() !== 'vm' ? new Web3(executionContext.web3().currentProvider) : null, console: { - log: function () { self._output.apply(self, arguments) } + log: function () { self.commands.log.apply(null, arguments) }, + info: function () { self.commands.info.apply(null, arguments) }, + error: function () { self.commands.error.apply(null, arguments) } } } } From 51fb91ea68a2c46aaaa6b5c76cef87104c19d7e5 Mon Sep 17 00:00:00 2001 From: serapath Date: Sun, 3 Sep 2017 05:13:15 +0200 Subject: [PATCH 03/13] REFACTOR + setup filter method stubs --- src/app/panels/editor-panel.js | 44 +++++++++++++- src/app/panels/terminal.js | 107 +++++++++++++++------------------ 2 files changed, 91 insertions(+), 60 deletions(-) diff --git a/src/app/panels/editor-panel.js b/src/app/panels/editor-panel.js index 94795b2420..818d0417ea 100644 --- a/src/app/panels/editor-panel.js +++ b/src/app/panels/editor-panel.js @@ -157,7 +157,49 @@ class EditorPanel { context () { return self._api.context() } - } + }, + banner: ` +/****************************************************************************** + + ........................................... + .....................:..................... + ....................o:;.................... + ...................oo:;;................... + ..................ooo:;;;.................. + .................oooo:;;;;................. + ................ooooo:;;;;;................ + ...............oooooo:;;;;;;............... + ..............ooooooo:;;;;;;;.............. + .............ooooooo;:';;;;;;;............. + ............ooooo;;;;:'''';;;;;............ + ...........oo;;;;;;;;:'''''''';;........... + ..........;;;;;;;;;;;:'''''''''''.......... + ..............;;;;;;;:'''''''.............. + ...........oo...;;;;;:'''''...;;........... + ............oooo...;;:''...;;;;............ + ..............oooo...:...;;;;.............. + ...............oooooo:;;;;;;............... + ................ooooo:;;;;;................ + .................oooo:;;;;................. + ..................ooo:;;;.................. + ...................oo:;;................... + ....................o:;.................... + .....................:..................... + ........................................... + + ######## ######## ## ## #### ## ## + ## ## ## ### ### ## ## ## + ## ## ## #### #### ## ## ## + ######## ###### ## ### ## ## ### + ## ## ## ## ## ## ## ## + ## ## ## ## ## ## ## ## + ## ## ######## ## ## #### ## ## + + + welcome to browser solidity + +******************************************************************************/ +` }) } self._components.terminal.event.register('resize', delta => self._adjustLayout('top', delta)) diff --git a/src/app/panels/terminal.js b/src/app/panels/terminal.js index f26103e94a..67e3c9d2a4 100644 --- a/src/app/panels/terminal.js +++ b/src/app/panels/terminal.js @@ -123,58 +123,15 @@ var ghostbar = yo`
` class Terminal { constructor (opts = { auto: true }) { var self = this + self.event = new EventManager() + self._api = opts.api 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 - -******************************************************************************/ -` + banner: opts.banner, + activeFilters: { commands: {}, input: '' } } - self.event = new EventManager() - self._api = opts.api + self._view = { el: null, bar: null, input: null, term: null, journal: null, cli: null } self._components = {} self._components.dropdown = new Dropdown({ options: [ @@ -185,12 +142,11 @@ class Terminal { defaults: ['knownTransaction', 'script'] }) self._components.dropdown.event.register('deselect', function (label) { - console.log('deselect', label) + self.updateJournal({ type: 'deselect', value: label }) }) self._components.dropdown.event.register('select', function (label) { - console.log('select', label) + self.updateJournal({ type: 'select', value: label }) }) - self._view = { el: null, bar: null, input: null, term: null, journal: null, cli: null } self._commands = {} self.commands = {} self._INDEX = {} @@ -256,7 +212,7 @@ class Terminal { ${self._view.term} ` - self.commands.log(self.data.banner) + if (self.data.banner) self.commands.log(self.data.banner) function throttle (fn, wait) { var time = Date.now() @@ -361,11 +317,11 @@ class Terminal { background.style.height = (self._view.journal.offsetHeight - (placeholder.offsetTop + placeholder.offsetHeight)) + 'px' background.onclick = undefined background.style.cursor = 'default' + background.style.pointerEvents = 'none' } else { background.style = '' text.style = '' background.onclick = function (event) { - console.error('background click') placeholder.scrollIntoView() check() } @@ -385,7 +341,7 @@ class Terminal { function filter (event) { var input = event.currentTarget setTimeout(function () { - console.log('filter', input.value) + self.updateJournal({ type: 'search', value: input.value }) }, 0) } function clear (event) { @@ -469,6 +425,43 @@ class Terminal { editable.focus() } } + updateJournal (filterEvent) { + // @TODO: updates `self.data.activeFilters: { commands: {}, input: '' }` + var value = filterEvent.value + if (filterEvent.type === 'select') { + console.log(value) + } else if (filterEvent.type === 'deselect') { + console.log(value) + } else if (filterEvent.type === 'search') { + console.log(value) + } + } + _keep (item) { + // @TODO: checks `self.data.activeFilters: { commands: {}, input: '' }` + // @TODO: return false (if item is currently filtered out / irrelevant + // according to `self.data.activeFilters` + // self._INDEX.all[item.gidx] + // + // self._INDEX.allMain + // self._INDEX.commands + // self._INDEX.commandsMain + // + // if () + // self.updateJournal( + // _INDEX + // + return true // false + } + _appendItem (item) { + var self = this + var { el, gidx } = item + if (self._keep(item)) { + self._view.journal.appendChild(yo` +
${el}
+ `) + self.scroll2bottom() + } + } scroll2bottom () { var self = this setTimeout(function () { @@ -534,10 +527,7 @@ class Terminal { item.idx = self._INDEX.commands[cmd].push(item) - 1 item.step = steps.push(item) - 1 item.args = params - self._view.journal.appendChild(yo` -
${el}
- `) - self.scroll2bottom() + self._appendItem(item) } var scopedCommands = self._scopeCommands(append) command(args, scopedCommands, el => append(null, args, el)) @@ -564,7 +554,6 @@ class Terminal { } function domTerminalFeatures (self) { - // @TODO add all the `console` functions return { web3: executionContext.getProvider() !== 'vm' ? new Web3(executionContext.web3().currentProvider) : null, console: { From add7b06b4104cb9496c7ee802adcc4b6c595b06a Mon Sep 17 00:00:00 2001 From: serapath Date: Mon, 4 Sep 2017 18:07:33 +0200 Subject: [PATCH 04/13] ADD keeping track of all active filters --- src/app/panels/terminal.js | 40 +++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/src/app/panels/terminal.js b/src/app/panels/terminal.js index 67e3c9d2a4..b73b32cb8f 100644 --- a/src/app/panels/terminal.js +++ b/src/app/panels/terminal.js @@ -426,31 +426,35 @@ class Terminal { } } updateJournal (filterEvent) { - // @TODO: updates `self.data.activeFilters: { commands: {}, input: '' }` + var self = this var value = filterEvent.value if (filterEvent.type === 'select') { - console.log(value) + self.data.activeFilters.commands[value] = true + // @TODO: add all items with `value === item.cmd` } else if (filterEvent.type === 'deselect') { - console.log(value) + self.data.activeFilters.commands[value] = false + // @TODO: remove all items with `value === item.cmd` } else if (filterEvent.type === 'search') { - console.log(value) + self.data.activeFilters.input = value + // @TODO: filter all active items with not `match(value, item.args)` + + // @TODO: implement a `match(query, args)` function + + // make use of: + // self._INDEX.all[item.gidx] + // self._INDEX.allMain + // self._INDEX.commands + // self._INDEX.commandsMain } } _keep (item) { - // @TODO: checks `self.data.activeFilters: { commands: {}, input: '' }` - // @TODO: return false (if item is currently filtered out / irrelevant - // according to `self.data.activeFilters` - // self._INDEX.all[item.gidx] - // - // self._INDEX.allMain - // self._INDEX.commands - // self._INDEX.commandsMain - // - // if () - // self.updateJournal( - // _INDEX - // - return true // false + var self = this + if (self.data.activeFilters.commands[item.root.cmd]) { + var query = self.data.activeFilters.input + // @TODO: filter item if not `match(value, item.args)` + // @TODO: implement a `match(query, args)` function + if (item.args === query) return true + } } _appendItem (item) { var self = this From 741df25034b5b9c309994ab1ec4363256e3babc4 Mon Sep 17 00:00:00 2001 From: serapath Date: Mon, 4 Sep 2017 20:44:20 +0200 Subject: [PATCH 05/13] FIX missing execute->commands.script reference update --- src/app/panels/terminal.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/panels/terminal.js b/src/app/panels/terminal.js index b73b32cb8f..30970b50e6 100644 --- a/src/app/panels/terminal.js +++ b/src/app/panels/terminal.js @@ -392,7 +392,7 @@ class Terminal { putCursor2End(self._view.input) } else { // event.preventDefault() - self.execute(self._view.input.innerText) + self.commands.script(self._view.input.innerText) self._view.input.innerHTML = '' } } @@ -497,7 +497,7 @@ class Terminal { Object.keys(self.commands).forEach(function makeScopedCommand (cmd) { var command = self._commands[cmd] scopedCommands[cmd] = function _command () { - var args = arguments + var args = [...arguments] command(args, scopedCommands, el => append(cmd, args, el)) } }) From e40d5e5991e99f60d3283162b8db09893916b006 Mon Sep 17 00:00:00 2001 From: serapath Date: Tue, 5 Sep 2017 04:29:53 +0200 Subject: [PATCH 06/13] research & implement filter methods (first draft) --- src/app/panels/terminal.js | 120 ++++++++++++++++++++++++++++--------- 1 file changed, 93 insertions(+), 27 deletions(-) diff --git a/src/app/panels/terminal.js b/src/app/panels/terminal.js index 30970b50e6..293a10ab22 100644 --- a/src/app/panels/terminal.js +++ b/src/app/panels/terminal.js @@ -1,4 +1,4 @@ -/* global Node */ +/* global Node, requestAnimationFrame */ var yo = require('yo-yo') var csjs = require('csjs-inject') var javascriptserialize = require('javascript-serialize') @@ -149,6 +149,8 @@ class Terminal { }) self._commands = {} self.commands = {} + self._JOURNAL = [] + self._jobs = [] self._INDEX = {} self._INDEX.all = [] self._INDEX.allMain = [] @@ -427,44 +429,71 @@ class Terminal { } updateJournal (filterEvent) { var self = this + var commands = self.data.activeFilters.commands var value = filterEvent.value if (filterEvent.type === 'select') { - self.data.activeFilters.commands[value] = true - // @TODO: add all items with `value === item.cmd` + commands[value] = true + if (!self._INDEX.commandsMain[value]) return + self._INDEX.commandsMain[value].forEach(item => { + item.root.steps.forEach(item => { + item.hide = false + self._JOURNAL[item.gidx] = item + }) + item.hide = false + self._JOURNAL[item.gidx] = item + }) } else if (filterEvent.type === 'deselect') { - self.data.activeFilters.commands[value] = false - // @TODO: remove all items with `value === item.cmd` + commands[value] = false + if (!self._INDEX.commandsMain[value]) return + self._INDEX.commandsMain[value].forEach(item => { + item.root.steps.forEach(item => { + item.hide = true + self._JOURNAL[item.gidx] = item + }) + item.hide = true + self._JOURNAL[item.gidx] = item + }) } else if (filterEvent.type === 'search') { - self.data.activeFilters.input = value - // @TODO: filter all active items with not `match(value, item.args)` - - // @TODO: implement a `match(query, args)` function - - // make use of: - // self._INDEX.all[item.gidx] - // self._INDEX.allMain - // self._INDEX.commands - // self._INDEX.commandsMain + var query = self.data.activeFilters.input = value + var items = self._JOURNAL + for (var gidx = 0, len = items.length; gidx < len; gidx++) { + var item = items[gidx] + if (item) { + var show = match(item.args, query) + item.hide = !show + } + } } + var df = document.createDocumentFragment() + // var children = self._JOURNAL.map(item => !item.hide && item.el) + self._JOURNAL.forEach(item => { + if (!item.hide && item.el) df.appendChild(item.el) + }) + requestAnimationFrame(function updateDOM () { + self._view.journal.innerHTML = '' + self._view.journal.appendChild(df) + }) } - _keep (item) { + _shouldAdd (item) { var self = this if (self.data.activeFilters.commands[item.root.cmd]) { var query = self.data.activeFilters.input - // @TODO: filter item if not `match(value, item.args)` - // @TODO: implement a `match(query, args)` function - if (item.args === query) return true + var args = item.args + return match(args, query) } } _appendItem (item) { var self = this var { el, gidx } = item - if (self._keep(item)) { - self._view.journal.appendChild(yo` -
${el}
- `) - self.scroll2bottom() + self._JOURNAL[gidx] = item + if (!self._jobs.length) { + requestAnimationFrame(function updateTerminal () { + self._jobs.forEach(el => self._view.journal.appendChild(el)) + self.scroll2bottom() + self._jobs = [] + }) } + self._jobs.push(el) } scroll2bottom () { var self = this @@ -498,7 +527,7 @@ class Terminal { var command = self._commands[cmd] scopedCommands[cmd] = function _command () { var args = [...arguments] - command(args, scopedCommands, el => append(cmd, args, el)) + command(args, scopedCommands, el => append(cmd, args, blockify(el))) } }) return scopedCommands @@ -531,10 +560,10 @@ class Terminal { item.idx = self._INDEX.commands[cmd].push(item) - 1 item.step = steps.push(item) - 1 item.args = params - self._appendItem(item) + if (self._shouldAdd(item)) self._appendItem(item) } var scopedCommands = self._scopeCommands(append) - command(args, scopedCommands, el => append(null, args, el)) + command(args, scopedCommands, el => append(null, args, blockify(el))) } var help = typeof command.help === 'string' ? command.help : [ `// no help available for:`, @@ -568,4 +597,41 @@ function domTerminalFeatures (self) { } } +function fuzzysearch (needle, haystack) { + var hlen = haystack.length + var nlen = needle.length + if (nlen > hlen) return + if (nlen === hlen) return needle === haystack + outer: for (var i = 0, j = 0; i < nlen; i++) { // eslint-disable-line + var nch = needle.charCodeAt(i) + while (j < hlen) if (haystack.charCodeAt(j++) === nch) continue outer // eslint-disable-line + return + } + return true +} + +function findDeep (object, fn, found = { break: false, value: undefined }) { + if (typeof object !== 'object' || object === null) return + for (var i in object) { + if (found.break) break + var el = object[i] + if (!fn(el, i, object)) findDeep(el, fn, found) + else if (found.break = true) return found.value = el // eslint-disable-line + } + return found.value +} + +function match (args, query) { + return findDeep(args, function check (value, key) { + if (value === undefined || value === null) return false + if (typeof value === 'function') return false + if (typeof value === 'object') return false + return fuzzysearch(query, String(value)) + }) +} + +function blockify (el) { + return yo`
${el}
` +} + module.exports = Terminal From 4d6bed6a89c89bfd0de5b3bb8b16c082980276b1 Mon Sep 17 00:00:00 2001 From: serapath Date: Tue, 5 Sep 2017 05:27:52 +0200 Subject: [PATCH 07/13] select/filter log entries works now --- src/app/panels/terminal.js | 48 ++++++++++++++------------------------ 1 file changed, 18 insertions(+), 30 deletions(-) diff --git a/src/app/panels/terminal.js b/src/app/panels/terminal.js index 293a10ab22..6186064d29 100644 --- a/src/app/panels/terminal.js +++ b/src/app/panels/terminal.js @@ -197,7 +197,7 @@ class Terminal { ${self._view.dropdown} - + ${self._view.icon} @@ -342,9 +342,7 @@ class Terminal { } function filter (event) { var input = event.currentTarget - setTimeout(function () { - self.updateJournal({ type: 'search', value: input.value }) - }, 0) + self.updateJournal({ type: 'search', value: input.value }) } function clear (event) { refocus() @@ -454,13 +452,15 @@ class Terminal { self._JOURNAL[item.gidx] = item }) } else if (filterEvent.type === 'search') { - var query = self.data.activeFilters.input = value - var items = self._JOURNAL - for (var gidx = 0, len = items.length; gidx < len; gidx++) { - var item = items[gidx] - if (item) { - var show = match(item.args, query) - item.hide = !show + if (value !== self.data.activeFilters.input) { + var query = self.data.activeFilters.input = value + var items = self._JOURNAL + for (var gidx = 0, len = items.length; gidx < len; gidx++) { + var item = items[gidx] + if (item) { + var show = query.length ? match(item.args, query) : true + item.hide = !show + } } } } @@ -479,7 +479,7 @@ class Terminal { if (self.data.activeFilters.commands[item.root.cmd]) { var query = self.data.activeFilters.input var args = item.args - return match(args, query) + return query.length ? match(args, query) : true } } _appendItem (item) { @@ -597,19 +597,6 @@ function domTerminalFeatures (self) { } } -function fuzzysearch (needle, haystack) { - var hlen = haystack.length - var nlen = needle.length - if (nlen > hlen) return - if (nlen === hlen) return needle === haystack - outer: for (var i = 0, j = 0; i < nlen; i++) { // eslint-disable-line - var nch = needle.charCodeAt(i) - while (j < hlen) if (haystack.charCodeAt(j++) === nch) continue outer // eslint-disable-line - return - } - return true -} - function findDeep (object, fn, found = { break: false, value: undefined }) { if (typeof object !== 'object' || object === null) return for (var i in object) { @@ -622,16 +609,17 @@ function findDeep (object, fn, found = { break: false, value: undefined }) { } function match (args, query) { - return findDeep(args, function check (value, key) { + query = query.trim() + var isMatch = !!findDeep(args, function check (value, key) { if (value === undefined || value === null) return false if (typeof value === 'function') return false if (typeof value === 'object') return false - return fuzzysearch(query, String(value)) + var contains = String(value).indexOf(query.trim()) !== -1 + return contains }) + return isMatch } -function blockify (el) { - return yo`
${el}
` -} +function blockify (el) { return yo`
${el}
` } module.exports = Terminal From db7d96a9d8620e18978e88c27ace0c3de1d02cdc Mon Sep 17 00:00:00 2001 From: serapath Date: Tue, 5 Sep 2017 05:50:34 +0200 Subject: [PATCH 08/13] FIX filter bug on typed input + fix file-explorer standardjs bug --- src/app/files/file-explorer.js | 1 - src/app/panels/terminal.js | 17 ++++------------- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/src/app/files/file-explorer.js b/src/app/files/file-explorer.js index fd4d940e15..d8e408b276 100755 --- a/src/app/files/file-explorer.js +++ b/src/app/files/file-explorer.js @@ -70,7 +70,6 @@ function fileExplorer (appAPI, files) { } }) - var self = this var fileEvents = files.event var treeView = new Treeview({ extractData: function (value, tree, key) { diff --git a/src/app/panels/terminal.js b/src/app/panels/terminal.js index 6186064d29..d787af417e 100644 --- a/src/app/panels/terminal.js +++ b/src/app/panels/terminal.js @@ -433,23 +433,15 @@ class Terminal { commands[value] = true if (!self._INDEX.commandsMain[value]) return self._INDEX.commandsMain[value].forEach(item => { - item.root.steps.forEach(item => { - item.hide = false - self._JOURNAL[item.gidx] = item - }) - item.hide = false + item.root.steps.forEach(item => { self._JOURNAL[item.gidx] = item }) self._JOURNAL[item.gidx] = item }) } else if (filterEvent.type === 'deselect') { commands[value] = false if (!self._INDEX.commandsMain[value]) return self._INDEX.commandsMain[value].forEach(item => { - item.root.steps.forEach(item => { - item.hide = true - self._JOURNAL[item.gidx] = item - }) - item.hide = true - self._JOURNAL[item.gidx] = item + item.root.steps.forEach(item => { self._JOURNAL[item.gidx] = undefined }) + self._JOURNAL[item.gidx] = undefined }) } else if (filterEvent.type === 'search') { if (value !== self.data.activeFilters.input) { @@ -465,9 +457,8 @@ class Terminal { } } var df = document.createDocumentFragment() - // var children = self._JOURNAL.map(item => !item.hide && item.el) self._JOURNAL.forEach(item => { - if (!item.hide && item.el) df.appendChild(item.el) + if (item && item.el && !item.hide) df.appendChild(item.el) }) requestAnimationFrame(function updateDOM () { self._view.journal.innerHTML = '' From d5d15f7f9ae8003e49b2e09a7e33656b505976c9 Mon Sep 17 00:00:00 2001 From: serapath Date: Tue, 5 Sep 2017 18:08:09 +0200 Subject: [PATCH 09/13] REFACTOR terminal --- src/app/panels/terminal.js | 23 ++++++++++++----------- test-browser/tests/compiling.js | 4 ++-- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/app/panels/terminal.js b/src/app/panels/terminal.js index d787af417e..ad6fdffdd0 100644 --- a/src/app/panels/terminal.js +++ b/src/app/panels/terminal.js @@ -162,7 +162,7 @@ class Terminal { self.registerCommand('script', function execute (args, scopedCommands, append) { var script = String(args[0]) scopedCommands.log(`> ${script}`) - self._shell(script, function (error, output) { + self._shell(script, scopedCommands, function (error, output) { if (error) scopedCommands.error(error) else scopedCommands.log(output) }) @@ -564,10 +564,11 @@ class Terminal { self.commands[name].help = help return self.commands[name] } - _shell (script, done) { // default shell + _shell (script, scopedCommands, done) { // default shell var self = this + var context = domTerminalFeatures(self, scopedCommands) try { - var context = vm.createContext(Object.assign(self._jsSandboxContext, domTerminalFeatures(self))) + var context = vm.createContext(Object.assign(self._jsSandboxContext, context)) var result = vm.runInContext(script, context) self._jsSandboxContext = Object.assign({}, context) done(null, result) @@ -577,15 +578,15 @@ class Terminal { } } -function domTerminalFeatures (self) { - return { - web3: executionContext.getProvider() !== 'vm' ? new Web3(executionContext.web3().currentProvider) : null, - console: { - log: function () { self.commands.log.apply(null, arguments) }, - info: function () { self.commands.info.apply(null, arguments) }, - error: function () { self.commands.error.apply(null, arguments) } - } +function domTerminalFeatures (self, scopedCommands) { + var ctx = scopedCommands + ctx.web3 = executionContext.getProvider() !== 'vm' ? new Web3(executionContext.web3().currentProvider) : null, + ctx.console = console = { + log: function () { scopedCommands.log.apply(scopedCommands, arguments) }, + info: function () { scopedCommands.info.apply(scopedCommands, arguments) }, + error: function () { scopedCommands.error.apply(scopedCommands, arguments) } } + return context } function findDeep (object, fn, found = { break: false, value: undefined }) { diff --git a/test-browser/tests/compiling.js b/test-browser/tests/compiling.js index b0d1c63de4..81a7654209 100644 --- a/test-browser/tests/compiling.js +++ b/test-browser/tests/compiling.js @@ -32,8 +32,8 @@ function runTests (browser) { .click('#runTabView div[class^="create"]') .waitForElementPresent('.instance button[title="f - transact (not payable)"]') .click('.instance button[title="f - transact (not payable)"]') - .waitForElementPresent('#editor-container div[class^="terminal"] .knownTransaction span[id="tx0xa178c603400a184ce5fedbcfab392d9b77822f6ffa7facdec693aded214523bc"]') - .assert.containsText('#editor-container div[class^="terminal"] .knownTransaction span[id="tx0xa178c603400a184ce5fedbcfab392d9b77822f6ffa7facdec693aded214523bc"]', '(vm): from:0xca3...a733c, to:0x692...77b3a, browser/Untitled.sol:TestContract.f(), value:0 wei, data:0x261...21ff0, 0 logs, hash:0xa17...523bc,DetailsDebug') + .waitForElementPresent('#editor-container div[class^="terminal"] span[id="tx0xa178c603400a184ce5fedbcfab392d9b77822f6ffa7facdec693aded214523bc"]') + .assert.containsText('#editor-container div[class^="terminal"] span[id="tx0xa178c603400a184ce5fedbcfab392d9b77822f6ffa7facdec693aded214523bc"]', '(vm): from:0xca3...a733c, to:0x692...77b3a, browser/Untitled.sol:TestContract.f(), value:0 wei, data:0x261...21ff0, 0 logs, hash:0xa17...523bc,DetailsDebug') .end() /* @TODO: need to check now the return value of the function From 7acc4c5d13b02fad0e8d7e5599ab82f87ecb382e Mon Sep 17 00:00:00 2001 From: serapath Date: Tue, 5 Sep 2017 18:11:00 +0200 Subject: [PATCH 10/13] restrict available terminal commands for scripts --- src/app/panels/terminal.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/app/panels/terminal.js b/src/app/panels/terminal.js index ad6fdffdd0..952dbac108 100644 --- a/src/app/panels/terminal.js +++ b/src/app/panels/terminal.js @@ -579,14 +579,14 @@ class Terminal { } function domTerminalFeatures (self, scopedCommands) { - var ctx = scopedCommands - ctx.web3 = executionContext.getProvider() !== 'vm' ? new Web3(executionContext.web3().currentProvider) : null, - ctx.console = console = { - log: function () { scopedCommands.log.apply(scopedCommands, arguments) }, - info: function () { scopedCommands.info.apply(scopedCommands, arguments) }, - error: function () { scopedCommands.error.apply(scopedCommands, arguments) } + return { + web3: executionContext.getProvider() !== 'vm' ? new Web3(executionContext.web3().currentProvider) : null, + console: { + log: function () { scopedCommands.log.apply(scopedCommands, arguments) }, + info: function () { scopedCommands.info.apply(scopedCommands, arguments) }, + error: function () { scopedCommands.error.apply(scopedCommands, arguments) } + } } - return context } function findDeep (object, fn, found = { break: false, value: undefined }) { From c27a30c58e278990ace676a0f59424513800d41f Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 5 Sep 2017 21:04:06 +0200 Subject: [PATCH 11/13] replace registerLogType registerCommand --- src/app/execution/txLogger.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/app/execution/txLogger.js b/src/app/execution/txLogger.js index 3a4e35885c..bc5b0d0468 100644 --- a/src/app/execution/txLogger.js +++ b/src/app/execution/txLogger.js @@ -26,13 +26,15 @@ class TxLogger { var el = renderUnknownTransaction(this, data) append(el) }) - opts.api.editorpanel.registerLogType('emptyBlock', (data) => { - return renderEmptyBlock(this, data) + this.logEmptyBlock = opts.api.editorpanel.registerCommand('emptyBlock', (args, cmds, append) => { + var data = args[0] + var el = renderEmptyBlock(this, data) + append(el) }) opts.events.txListener.register('newBlock', (block) => { if (!block.transactions.length) { - opts.api.editorpanel.log({type: 'emptyBlock', value: { block: block }}) + this.logEmptyBlock({ block: block }) } }) From dfe6deca47ff3b3ac7da8f7130c9bced31566840 Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 6 Sep 2017 10:20:21 +0200 Subject: [PATCH 12/13] add log function --- src/app/panels/editor-panel.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/app/panels/editor-panel.js b/src/app/panels/editor-panel.js index 818d0417ea..7447165e2d 100644 --- a/src/app/panels/editor-panel.js +++ b/src/app/panels/editor-panel.js @@ -236,6 +236,11 @@ class EditorPanel { var self = this self._view.tabs.onmouseenter() } + log (data = {}) { + var self = this + var command = self._components.terminal.commands[data.type] + if (typeof command === 'function') command(data.value) + } render () { var self = this if (self._view.el) return self._view.el From 3762100ae8637c1fb81add20ddf6c77862a4134d Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 6 Sep 2017 10:20:28 +0200 Subject: [PATCH 13/13] standard fix --- src/app/panels/terminal.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/panels/terminal.js b/src/app/panels/terminal.js index 952dbac108..568be164d0 100644 --- a/src/app/panels/terminal.js +++ b/src/app/panels/terminal.js @@ -568,8 +568,8 @@ class Terminal { var self = this var context = domTerminalFeatures(self, scopedCommands) try { - var context = vm.createContext(Object.assign(self._jsSandboxContext, context)) - var result = vm.runInContext(script, context) + var cmds = vm.createContext(Object.assign(self._jsSandboxContext, context)) + var result = vm.runInContext(script, cmds) self._jsSandboxContext = Object.assign({}, context) done(null, result) } catch (error) {