Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
B
baas-ide
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
JIRA
JIRA
Merge Requests
1
Merge Requests
1
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
guxukai
baas-ide
Commits
b56c1c80
Commit
b56c1c80
authored
Aug 11, 2021
by
davidzagi93@gmail.com
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: clear-console, terminal-search, fix-input terminal input to buttom
parent
8c6afc23
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
1310 additions
and
347 deletions
+1310
-347
app.js
apps/remix-ide/src/app.js
+5
-2
terminal.js
apps/remix-ide/src/app/panels/terminal.js
+301
-182
terminalAction.ts
libs/remix-ui/terminal/src/lib/actions/terminalAction.ts
+103
-3
terminalReducer.ts
libs/remix-ui/terminal/src/lib/reducers/terminalReducer.ts
+34
-3
remix-ui-terminal.css
libs/remix-ui/terminal/src/lib/remix-ui-terminal.css
+121
-3
remix-ui-terminal.tsx
libs/remix-ui/terminal/src/lib/remix-ui-terminal.tsx
+536
-154
helper.ts
libs/remix-ui/terminal/src/lib/utils/helper.ts
+176
-0
utils.ts
libs/remix-ui/terminal/src/lib/utils/utils.ts
+34
-0
No files found.
apps/remix-ide/src/app.js
View file @
b56c1c80
...
...
@@ -288,6 +288,8 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
// -------------------Terminal----------------------------------------
// move this up for *** level so as to access it in the terminal
makeUdapp
(
blockchain
,
compilersArtefacts
,
(
domEl
)
=>
terminal
.
logHtml
(
domEl
))
const
terminal
=
new
Terminal
(
{
appManager
,
blockchain
},
{
...
...
@@ -300,10 +302,11 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
return
height
-
newpos
}
},
{
config
:
registry
.
get
(
'config'
).
api
}
{
config
:
registry
.
get
(
'config'
).
api
},
registry
)
makeUdapp
(
blockchain
,
compilersArtefacts
,
(
domEl
)
=>
terminal
.
logHtml
(
domEl
))
// previous *** level for makeUdapp method
const
contextualListener
=
new
ContextualListener
({
editor
})
engine
.
register
([
...
...
apps/remix-ide/src/app/panels/terminal.js
View file @
b56c1c80
...
...
@@ -18,6 +18,11 @@ var AutoCompletePopup = require('../ui/auto-complete-popup')
var
css
=
require
(
'./styles/terminal-styles'
)
import
{
CompilerImports
}
from
'@remix-project/core-plugin'
// eslint-disable-line
var
globalRegistry
=
require
(
'../../global/registry'
)
var
SourceHighlighter
=
require
(
'../../app/editor/sourceHighlighter'
)
var
GistHandler
=
require
(
'../../lib/gist-handler'
)
var
KONSOLES
=
[]
function
register
(
api
)
{
KONSOLES
.
push
(
api
)
}
...
...
@@ -32,12 +37,32 @@ const profile = {
}
class
Terminal
extends
Plugin
{
constructor
(
opts
,
api
,
config
)
{
constructor
(
opts
,
api
,
config
,
registry
)
{
super
(
profile
)
this
.
fileImport
=
new
CompilerImports
()
this
.
gistHandler
=
new
GistHandler
()
this
.
event
=
new
EventManager
()
this
.
registry
=
registry
this
.
globalRegistry
=
globalRegistry
this
.
element
=
document
.
createElement
(
'div'
)
this
.
element
.
setAttribute
(
'class'
,
'panel_2A0YE0'
)
this
.
element
.
setAttribute
(
'id'
,
'terminal-view'
)
this
.
event
=
new
EventManager
()
this
.
eventsDecoder
=
this
.
globalRegistry
.
get
(
'eventsDecoder'
).
api
this
.
txListener
=
this
.
globalRegistry
.
get
(
'txlistener'
).
api
this
.
sourceHighlighter
=
new
SourceHighlighter
()
this
.
_deps
=
{
fileManager
:
this
.
registry
.
get
(
'filemanager'
).
api
,
editor
:
this
.
registry
.
get
(
'editor'
).
api
,
compilersArtefacts
:
this
.
registry
.
get
(
'compilersartefacts'
).
api
,
offsetToLineColumnConverter
:
this
.
registry
.
get
(
'offsettolinecolumnconverter'
).
api
}
this
.
commandHelp
=
{
'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.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'
}
this
.
blockchain
=
opts
.
blockchain
this
.
vm
=
vm
this
.
_api
=
api
...
...
@@ -54,14 +79,14 @@ class Terminal extends Plugin {
this
.
_components
=
{}
this
.
_components
.
cmdInterpreter
=
new
CommandInterpreterAPI
(
this
,
null
,
this
.
blockchain
)
this
.
_components
.
autoCompletePopup
=
new
AutoCompletePopup
(
this
.
_opts
)
this
.
_components
.
autoCompletePopup
.
event
.
register
(
'handleSelect'
,
function
(
input
)
{
const
textList
=
this
.
_view
.
input
.
innerText
.
split
(
' '
)
textList
.
pop
()
textList
.
push
(
input
)
this
.
_view
.
input
.
innerText
=
textList
this
.
_view
.
input
.
focus
()
this
.
putCursor2End
(
this
.
_view
.
input
)
})
//
this._components.autoCompletePopup.event.register('handleSelect', function (input) {
//
const textList = this._view.input.innerText.split(' ')
//
textList.pop()
//
textList.push(input)
//
this._view.input.innerText = textList
//
this._view.input.focus()
//
this.putCursor2End(this._view.input)
//
})
this
.
_commands
=
{}
this
.
commands
=
{}
this
.
_JOURNAL
=
[]
...
...
@@ -86,31 +111,10 @@ class Terminal extends Plugin {
this
.
off
(
'scriptRunner'
,
'error'
)
}
log
(
message
)
{
var
command
=
this
.
commands
[
message
.
type
]
if
(
typeof
command
===
'function'
)
{
if
(
typeof
message
.
value
===
'string'
&&
message
.
type
===
'html'
)
{
var
el
=
document
.
createElement
(
'div'
)
el
.
innerHTML
=
remixBleach
.
sanitize
(
message
.
value
,
{
list
:
[
'a'
,
'b'
,
'p'
,
'em'
,
'strong'
,
'div'
,
'span'
,
'ul'
,
'li'
,
'ol'
,
'hr'
]
})
message
.
value
=
el
}
command
(
message
.
value
)
};
}
// logHtml (html) {
// var command = this.commands.html
// if (typeof command === 'function') command(html)
// }
logHtml
(
html
)
{
var
command
=
this
.
commands
.
html
...
...
@@ -128,7 +132,7 @@ class Terminal extends Plugin {
autoCompletePopupEvent
=
{
this
.
_components
.
autoCompletePopup
.
event
}
blockchain
=
{
this
.
blockchain
}
api
=
{
this
.
_api
}
options
=
{
this
.
opts
}
options
=
{
this
.
_
opts
}
data
=
{
this
.
data
}
cmdInterpreter
=
{
this
.
_components
.
cmdInterpreter
}
autoCompletePopup
=
{
this
.
_components
.
autoCompletePopup
}
...
...
@@ -138,170 +142,285 @@ class Terminal extends Plugin {
config
=
{
this
.
config
}
thisState
=
{
this
}
vm
=
{
this
.
vm
}
blockchain
=
{
this
.
blockchain
}
commandHelp
=
{
this
.
commandHelp
}
event
=
{
this
.
event
}
_deps
=
{
this
.
_deps
}
fileImport
=
{
this
.
fileImport
}
sourceHighlighter
=
{
this
.
sourceHighlighter
}
gistHandler
=
{
this
.
gistHandler
}
registry
=
{
this
.
registry
}
commands
=
{
this
.
commands
}
txListener
=
{
this
.
txListener
}
eventsDecoder
=
{
this
.
eventsDecoder
}
/>
,
this
.
element
)
}
_appendItem
(
item
)
{
var
self
=
this
var
{
el
,
gidx
}
=
item
self
.
_JOURNAL
[
gidx
]
=
item
if
(
!
self
.
_jobs
.
length
)
{
requestAnimationFrame
(
function
updateTerminal
()
{
self
.
_jobs
.
forEach
(
el
=>
self
.
_view
.
journal
.
appendChild
(
el
))
self
.
scroll2bottom
()
self
.
_jobs
=
[]
})
}
if
(
self
.
data
.
activeFilters
.
commands
[
item
.
cmd
])
self
.
_jobs
.
push
(
el
)
}
//
_appendItem (item) {
//
var self = this
//
var { el, gidx } = item
//
self._JOURNAL[gidx] = item
//
if (!self._jobs.length) {
//
requestAnimationFrame(function updateTerminal () {
//
self._jobs.forEach(el => self._view.journal.appendChild(el))
//
self.scroll2bottom()
//
self._jobs = []
//
})
//
}
//
if (self.data.activeFilters.commands[item.cmd]) self._jobs.push(el)
//
}
scroll2bottom
()
{
var
self
=
this
setTimeout
(
function
()
{
self
.
_view
.
term
.
scrollTop
=
self
.
_view
.
term
.
scrollHeight
//
self._view.term.scrollTop = self._view.term.scrollHeight
},
0
)
}
_blocksRenderer
(
mode
)
{
if
(
mode
===
'html'
)
{
return
function
logger
(
args
,
scopedCommands
,
append
)
{
if
(
args
.
length
)
append
(
args
[
0
])
}
}
mode
=
{
log
:
'text-info'
,
info
:
'text-info'
,
warn
:
'text-warning'
,
error
:
'text-danger'
}[
mode
]
// defaults
if
(
mode
)
{
const
filterUndefined
=
(
el
)
=>
el
!==
undefined
&&
el
!==
null
return
function
logger
(
args
,
scopedCommands
,
append
)
{
var
types
=
args
.
filter
(
filterUndefined
).
map
(
type
)
var
values
=
javascriptserialize
.
apply
(
null
,
args
.
filter
(
filterUndefined
)).
map
(
function
(
val
,
idx
)
{
if
(
typeof
args
[
idx
]
===
'string'
)
{
const
el
=
document
.
createElement
(
'div'
)
el
.
innerHTML
=
args
[
idx
].
replace
(
/
(\r\n
|
\n
|
\r)
/gm
,
'<br>'
)
val
=
el
.
children
.
length
===
0
?
el
.
firstChild
:
el
}
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'
)
}
}
// _blocksRenderer (mode) {
// if (mode === 'html') {
// return function logger (args, scopedCommands, append) {
// if (args.length) append(args[0])
// }
// }
// mode = {
// log: 'text-info',
// info: 'text-info',
// warn: 'text-warning',
// error: 'text-danger'
// }[mode] // defaults
_scopeCommands
(
append
)
{
var
self
=
this
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
,
blockify
(
el
)))
}
})
return
scopedCommands
}
// if (mode) {
// const filterUndefined = (el) => el !== undefined && el !== null
// return function logger (args, scopedCommands, append) {
// var types = args.filter(filterUndefined).map(type)
// var values = javascriptserialize.apply(null, args.filter(filterUndefined)).map(function (val, idx) {
// if (typeof args[idx] === 'string') {
// const el = document.createElement('div')
// el.innerHTML = args[idx].replace(/(\r\n|\n|\r)/gm, '<br>')
// val = el.children.length === 0 ? el.firstChild : el
// }
// 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')
// }
// }
registerFilter
(
commandName
,
filterFn
)
{
this
.
data
.
filterFns
[
commandName
]
=
filterFn
}
// _scopeCommands (append) {
// var self = this
// 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, blockify(el)))
// }
// })
// return scopedCommands
// }
registerCommand
(
name
,
command
,
opts
)
{
var
self
=
this
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
console
.
log
({
command
})
console
.
log
(
self
.
_commands
)
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
.
_appendItem
(
item
)
}
var
scopedCommands
=
self
.
_scopeCommands
(
append
)
command
(
args
,
scopedCommands
,
el
=>
append
(
null
,
args
,
blockify
(
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
self
.
data
.
activeFilters
.
commands
[
name
]
=
opts
&&
opts
.
activate
if
(
opts
.
filterFn
)
{
self
.
registerFilter
(
name
,
opts
.
filterFn
)
}
return
self
.
commands
[
name
]
}
// registerFilter (commandName, filterFn) {
// this.data.filterFns[commandName] = filterFn
// }
async
_shell
(
script
,
scopedCommands
,
done
)
{
// default shell
if
(
script
.
indexOf
(
'remix:'
)
===
0
)
{
return
done
(
null
,
'This type of command has been deprecated and is not functionning anymore. Please run remix.help() to list available commands.'
)
}
var
self
=
this
if
(
script
.
indexOf
(
'remix.'
)
===
0
)
{
// we keep the old feature. This will basically only be called when the command is querying the "remix" object.
// for all the other case, we use the Code Executor plugin
var
context
=
domTerminalFeatures
(
scopedCommands
,
self
.
blockchain
)
try
{
var
cmds
=
vm
.
createContext
(
context
)
var
result
=
vm
.
runInContext
(
script
,
cmds
)
return
done
(
null
,
result
)
}
catch
(
error
)
{
return
done
(
error
.
message
)
}
}
try
{
let
result
if
(
script
.
trim
().
startsWith
(
'git'
))
{
// result = await this.call('git', 'execute', script)
}
else
{
result
=
await
this
.
call
(
'scriptRunner'
,
'execute'
,
script
)
}
if
(
result
)
self
.
commands
.
html
(
yo
`<pre>
${
result
}
</pre>`
)
done
()
}
catch
(
error
)
{
done
(
error
.
message
||
error
)
}
}
}
// registerCommand (name, command, opts) {
// var self = this
// name = String(name)
// if (this._commands[name]) throw new Error(`command "${name}" exists already`)
// if (typeof command !== 'function') throw new Error(`invalid command: ${command}`)
// this._commands[name] = command
// console.log({ command })
// console.log(self._commands)
// this._INDEX.commands[name] = []
// this._INDEX.commandsMain[name] = []
// this.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._appendItem(item)
// }
// var scopedCommands = self._scopeCommands(append)
// command(args, scopedCommands, el => append(null, args, blockify(el)))
// }
// var help = typeof command.help === 'string' ? command.help : [
// '// no help available for:',
// `terminal.commands.${name}(...)`
// ].join('\n')
// this.commands[name].toString = _ => { return help }
// this.commands[name].help = help
// this.data.activeFilters.commands[name] = opts && opts.activate
// if (opts.filterFn) {
// this.registerFilter(name, opts.filterFn)
// }
// return this.commands[name]
// }
function
domTerminalFeatures
(
scopedCommands
,
blockchain
)
{
return
{
remix
:
this
.
_components
.
cmdInterpreter
}
}
// async _shell (script, scopedCommands, done) { // default shell
// if (script.indexOf('remix:') === 0) {
// return done(null, 'This type of command has been deprecated and is not functionning anymore. Please run remix.help() to list available commands.')
// }
// var self = this
// if (script.indexOf('remix.') === 0) {
// // we keep the old feature. This will basically only be called when the command is querying the "remix" object.
// // for all the other case, we use the Code Executor plugin
// var context = domTerminalFeatures(scopedCommands, self.blockchain)
// try {
// var cmds = vm.createContext(context)
// var result = vm.runInContext(script, cmds)
// return done(null, result)
// } catch (error) {
// return done(error.message)
// }
// }
// try {
// let result
// if (script.trim().startsWith('git')) {
// // result = await this.call('git', 'execute', script)
// } else {
// result = await this.call('scriptRunner', 'execute', script)
// }
// if (result) self.commands.html(yo`<pre>${result}</pre>`)
// done()
// } catch (error) {
// done(error.message || error)
// }
// }
// }
// function domTerminalFeatures (scopedCommands, blockchain) {
// return {
// remix: {
// blockchain: this.blockchain,
// commandHelp: this.commandHelp,
// event: this.event,
// _deps: this._deps
// }
// }
// }
// function loadgist (id, cb) {
// const self = this
// self._components.gistHandler.loadFromGist({ gist: id }, this._deps.fileManager)
// if (cb) cb()
// }
// function loadurl (url, cb) {
// const self = this
// self._components.fileImport.import(url,
// (loadingMsg) => { toolTip(loadingMsg) },
// (err, content, cleanUrl, type, url) => {
// if (err) {
// toolTip(`Unable to load ${url}: ${err}`)
// if (cb) cb(err)
// } else {
// self._deps.fileManager.writeFile(type + '/' + cleanUrl, content)
// try {
// content = JSON.parse(content)
// async.eachOfSeries(content.sources, (value, file, callbackSource) => {
// var url = value.urls[0] // @TODO retrieve all other contents ?
// self._components.fileImport.import(url,
// (loadingMsg) => { toolTip(loadingMsg) },
// async (error, content, cleanUrl, type, url) => {
// if (error) {
// toolTip(`Cannot retrieve the content of ${url}: ${error}`)
// return callbackSource(`Cannot retrieve the content of ${url}: ${error}`)
// } else {
// try {
// await self._deps.fileManager.writeFile(type + '/' + cleanUrl, content)
// callbackSource()
// } catch (e) {
// callbackSource(e.message)
// }
// }
// })
// }, (error) => {
// if (cb) cb(error)
// })
// } catch (e) {}
// if (cb) cb()
// }
// })
// }
// function exeCurrent (cb) {
// return this.execute(undefined, cb)
// }
// function execute (file, cb) {
// const self = this
// function _execute (content, cb) {
// if (!content) {
// toolTip('no content to execute')
// if (cb) cb()
// return
// }
// self._components.terminal.commands.script(content)
// }
// if (typeof file === 'undefined') {
// var content = self._deps.editor.currentContent()
// _execute(content, cb)
// return
// }
// var provider = self._deps.fileManager.fileProviderOf(file)
// if (!provider) {
// toolTip(`provider for path ${file} not found`)
// if (cb) cb()
// return
// }
// provider.get(file, (error, content) => {
// if (error) {
// // toolTip(error)
// // TODO: pop up
// if (cb) cb()
// return
// }
// _execute(content, cb)
// })
// }
// function help (cb) {
// const self = this
// var help = yo`<div></div>`
// for (var k in self.commandHelp) {
// help.appendChild(yo`<div>${k}: ${self.commandHelp[k]}</div>`)
// help.appendChild(yo`<br>`)
// }
// self._components.terminal.commands.html(help)
// if (cb) cb()
// return ''
// }
}
function
blockify
(
el
)
{
return
yo
`<div class="px-4
${
css
.
block
}
" data-id="block_
${
el
.
getAttribute
?
el
.
getAttribute
(
'id'
)
:
''
}
">
${
el
}
</div>`
}
module
.
exports
=
Terminal
libs/remix-ui/terminal/src/lib/actions/terminalAction.ts
View file @
b56c1c80
...
...
@@ -70,8 +70,9 @@ export const registerCommandAction = (name, command, activate, dispatch) => {
if
(
activate
.
filterFn
)
{
registerFilter
(
name
,
activate
.
filterFn
)
}
dispatch
({
type
:
name
,
payload
:
{
commands
:
commands
,
_commands
:
_commands
,
data
:
data
}
})
if
(
name
!==
(
'knownTransaction'
||
'unkownTransaction'
||
'emptyBlock'
))
{
dispatch
({
type
:
name
,
payload
:
{
commands
:
commands
,
_commands
:
_commands
,
data
:
data
}
})
}
const
blockify
=
(
el
)
=>
{
return
`<div class="px-4 block_2A0YE0" data-id="block_null">
${
el
}
</div>`
}
...
...
@@ -89,7 +90,6 @@ export const registerCommandAction = (name, command, activate, dispatch) => {
console
.
log
({
scopedCommands
})
return
scopedCommands
}
}
export
const
filterFnAction
=
(
name
,
filterFn
,
dispatch
)
=>
{
...
...
@@ -133,3 +133,103 @@ export const registerErrorScriptRunnerAction = (event, commandName, commandFn, d
export
const
registerRemixWelcomeTextAction
=
(
welcomeText
,
dispatch
)
=>
{
dispatch
({
type
:
'welcomeText'
,
payload
:
{
welcomeText
}
})
}
export
const
listenOnNetworkAction
=
async
(
props
,
isListening
)
=>
{
props
.
event
.
trigger
(
'listenOnNetWork'
,
[
isListening
])
}
export
const
initListeningOnNetwork
=
(
props
,
dispatch
)
=>
{
props
.
txListener
.
event
.
register
(
'newBlock'
,
(
block
)
=>
{
if
(
!
block
.
transactions
||
(
block
.
transactions
&&
!
block
.
transactions
.
length
))
{
dispatch
({
type
:
'emptyBlock'
,
payload
:
{
message
:
0
}
})
console
.
log
({
block
},
' david'
)
// registerCommandAction('emptyBlock', (args, cmds, append) => {
// const data = args[0]
// console.log({ data }, ' useEffect props')
// // // var el = renderEmptyBlock(this, data)
// // // append(el)
// }, { activate: true }, dispatch)
}
else
{
registerCommandAction
(
'knownTransaction'
,
function
(
args
,
cmds
,
append
)
{
var
data
=
args
[
0
]
console
.
log
({
data
})
// let el
// if (data.tx.isCall) {
// console.log({ data })
// // el = renderCall(this, data)
// } else {
// // el = renderKnownTransaction(this, data, blockchain)
// }
// this.seen[data.tx.hash] = el
// append(el)
},
{
activate
:
true
},
dispatch
)
}
})
props
.
txListener
.
event
.
register
(
'newCall'
,
(
tx
)
=>
{
console
.
log
(
'new call action'
)
// log(this, tx, null)
})
props
.
txListener
.
event
.
register
(
'newTransaction'
,
(
tx
,
receipt
)
=>
{
log
(
props
,
tx
,
receipt
,
dispatch
)
registerCommandAction
(
'knownTransaction'
,
function
(
args
,
cmds
,
append
)
{
var
data
=
args
[
0
]
console
.
log
({
data
})
// let el
// if (data.tx.isCall) {
// console.log({ data })
// // el = renderCall(this, data)
// } else {
// // el = renderKnownTransaction(this, data, blockchain)
// }
// this.seen[data.tx.hash] = el
// append(el)
},
{
activate
:
true
},
dispatch
)
// const result = Object.assign([], tx)
// console.log({ result })
// scriptRunnerDispatch({ type: 'knownTransaction', payload: { message: result } })
})
const
log
=
async
(
props
,
tx
,
receipt
,
dispatch
)
=>
{
const
resolvedTransaction
=
await
props
.
txListener
.
resolvedTransaction
(
tx
.
hash
)
if
(
resolvedTransaction
)
{
var
compiledContracts
=
null
if
(
props
.
_deps
.
compilersArtefacts
.
__last
)
{
compiledContracts
=
await
props
.
_deps
.
compilersArtefacts
.
__last
.
getContracts
()
}
console
.
log
({
compiledContracts
})
await
props
.
eventsDecoder
.
parseLogs
(
tx
,
resolvedTransaction
.
contractName
,
compiledContracts
,
(
error
,
logs
)
=>
{
if
(
!
error
)
{
console
.
log
({
tx
:
tx
,
receipt
:
receipt
,
resolvedData
:
resolvedTransaction
,
logs
:
logs
})
console
.
log
(
'knownTransaction'
)
// logKnownTX({ tx: tx, receipt: receipt, resolvedData: resolvedTransaction, logs: logs })
registerCommandAction
(
'knownTransaction'
,
function
(
args
,
cmds
,
append
)
{
var
data
=
args
[
0
]
console
.
log
({
data
},
'knownTransaction'
)
// let el
// if (data.tx.isCall) {
// console.log({ data })
// // el = renderCall(this, data)
// } else {
// // el = renderKnownTransaction(this, data, blockchain)
// }
// this.seen[data.tx.hash] = el
// append(el)
},
{
activate
:
true
},
dispatch
)
}
})
}
else
{
console
.
log
(
'unknownTransaction'
)
// contract unknown - just displaying raw tx.
// logUnknownTX({ tx: tx, receipt: receipt })
await
dispatch
({
type
:
'unknownTransaction'
,
payload
:
{
message
:
[{
tx
:
tx
,
receipt
:
receipt
}]
}
})
}
}
props
.
txListener
.
event
.
register
(
'debuggingRequested'
,
async
(
hash
)
=>
{
// TODO should probably be in the run module
console
.
log
({
hash
},
'register Call'
)
if
(
!
await
props
.
options
.
appManager
.
isActive
(
'debugger'
))
await
props
.
options
.
appManager
.
activatePlugin
(
'debugger'
)
props
.
thisState
.
call
(
'menuicons'
,
'select'
,
'debugger'
)
props
.
thisState
.
call
(
'debugger'
,
'debug'
,
hash
)
})
}
libs/remix-ui/terminal/src/lib/reducers/terminalReducer.ts
View file @
b56c1c80
...
...
@@ -67,6 +67,17 @@ export const registerCommandReducer = (state, action) => {
commands
:
Object
.
assign
(
initialState
.
commands
,
action
.
payload
.
commands
),
data
:
Object
.
assign
(
initialState
.
data
,
action
.
payload
.
data
)
}
case
'clearconsole'
:
return
{
...
state
,
...
state
.
journalBlocks
.
splice
(
0
)
}
case
'listenOnNetWork'
:
console
.
log
({
action
:
action
.
payload
})
return
{
...
state
,
journalBlocks
:
initialState
.
journalBlocks
.
push
({
message
:
action
.
payload
.
message
,
style
:
'text-info'
})
}
default
:
return
{
state
}
}
...
...
@@ -75,14 +86,12 @@ export const registerCommandReducer = (state, action) => {
export
const
registerFilterReducer
=
(
state
,
action
)
=>
{
switch
(
action
.
type
)
{
case
'log'
:
console
.
log
({
action
},
{
state
},
'register Filter'
)
return
{
...
state
,
data
:
Object
.
assign
(
initialState
.
data
.
filterFns
,
action
.
payload
.
data
.
filterFns
)
}
case
'info'
:
console
.
log
({
action
},
'registerFilter'
)
return
{
...
state
,
data
:
Object
.
assign
(
initialState
.
data
.
filterFns
,
action
.
payload
.
data
.
filterFns
)
...
...
@@ -132,7 +141,8 @@ export const remixWelcomeTextReducer = (state, action) => {
}
export
const
registerScriptRunnerReducer
=
(
state
,
action
)
=>
{
console
.
log
({
state
},
{
action
},
'register script runner reducer'
)
const
result
=
Object
.
assign
([],
action
.
payload
.
message
)
console
.
log
({
result
})
switch
(
action
.
type
)
{
case
'log'
:
return
{
...
...
@@ -159,5 +169,26 @@ export const registerScriptRunnerReducer = (state, action) => {
...
state
,
journalBlocks
:
initialState
.
journalBlocks
.
push
({
message
:
action
.
payload
.
message
,
style
:
'text-log'
})
}
case
'knownTransaction'
:
return
{
...
state
,
journalBlocks
:
initialState
.
journalBlocks
.
push
({
message
:
action
.
payload
.
message
,
style
:
''
,
name
:
'knownTransaction'
})
}
case
'unknownTransaction'
:
return
{
...
state
,
journalBlocks
:
initialState
.
journalBlocks
.
push
({
message
:
action
.
payload
.
message
,
style
:
''
,
name
:
'knownTransaction'
})
}
case
'emptyBlock'
:
console
.
log
({
action
:
action
.
payload
.
message
},
' emptyBLock reducer'
)
return
{
...
state
,
journalBlocks
:
initialState
.
journalBlocks
.
push
({
message
:
action
.
payload
.
message
,
style
:
''
,
name
:
'emptyBlock'
})
}
case
'newTransaction'
:
return
{
...
state
,
journalBlocks
:
initialState
.
journalBlocks
.
push
({
message
:
action
.
payload
.
message
,
style
:
''
})
}
}
}
libs/remix-ui/terminal/src/lib/remix-ui-terminal.css
View file @
b56c1c80
...
...
@@ -17,6 +17,18 @@ element.style {
input
#terminalCliInput
{
}
.border-primary
{
border-color
:
#007aa6
!important
;
}
.border
{
border
:
1px
solid
#3f4455
!important
;
}
.selectedOptions
{
background-color
:
#222336
;
}
.panel
{
position
:
relative
;
display
:
flex
;
...
...
@@ -138,6 +150,10 @@ input #terminalCliInput {
cursor
:
row-resize
;
z-index
:
999
;
}
.console
{
cursor
:
pointer
;
}
.dragbarHorizontal
:hover
{
background-color
:
#007AA6
;
...
...
@@ -171,7 +187,6 @@ input #terminalCliInput {
.popup
{
position
:
absolute
;
text-align
:
left
;
display
:
none
;
width
:
95%
;
font-family
:
monospace
;
background-color
:
var
(
--secondary
);
...
...
@@ -234,4 +249,108 @@ input #terminalCliInput {
@keyframes
animatetop
{
from
{
bottom
:
-300px
;
opacity
:
0
}
to
{
bottom
:
0
;
opacity
:
1
}
}
\ No newline at end of file
}
/* tx logger css*/
.log
{
display
:
flex
;
cursor
:
pointer
;
align-items
:
center
;
cursor
:
pointer
;
}
.log
:hover
{
opacity
:
0.8
;
}
.arrow
{
color
:
var
(
--text-info
);
font-size
:
20px
;
cursor
:
pointer
;
display
:
flex
;
margin-left
:
10px
;
}
.arrow
:hover
{
color
:
var
(
--secondary
);
}
.txLog
{
}
.txStatus
{
display
:
flex
;
font-size
:
20px
;
margin-right
:
20px
;
float
:
left
;
}
.succeeded
{
color
:
var
(
--success
);
}
.failed
{
color
:
var
(
--danger
);
}
.notavailable
{
}
.call
{
font-size
:
7px
;
border-radius
:
50%
;
min-width
:
20px
;
min-height
:
20px
;
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
color
:
var
(
--text-info
);
text-transform
:
uppercase
;
font-weight
:
bold
;
}
.txItem
{
color
:
var
(
--text-info
);
margin-right
:
5px
;
float
:
left
;
}
.txItemTitle
{
font-weight
:
bold
;
}
.tx
{
color
:
var
(
--text-info
);
font-weight
:
bold
;
float
:
left
;
margin-right
:
10px
;
}
.txTable
,
.tr
,
.td
{
border-collapse
:
collapse
;
font-size
:
10px
;
color
:
var
(
--text-info
);
border
:
1px
solid
var
(
--text-info
);
}
#txTable
{
margin-top
:
1%
;
margin-bottom
:
5%
;
align-self
:
center
;
width
:
85%
;
}
.tr
,
.td
{
padding
:
4px
;
vertical-align
:
baseline
;
}
.td
:first-child
{
min-width
:
30%
;
width
:
30%
;
align-items
:
baseline
;
font-weight
:
bold
;
}
.tableTitle
{
width
:
25%
;
}
.buttons
{
display
:
flex
;
margin-left
:
auto
;
}
.debug
{
white-space
:
nowrap
;
}
.debug
:hover
{
opacity
:
0.8
;
}
libs/remix-ui/terminal/src/lib/remix-ui-terminal.tsx
View file @
b56c1c80
import
React
,
{
useState
,
useEffect
,
useReducer
,
useRef
,
SyntheticEvent
,
MouseEvent
}
from
'react'
// eslint-disable-line
import
{
useKeyPress
}
from
'./custom-hooks/useKeyPress'
// eslint-disable-line
import
{
useWindowResize
}
from
'beautiful-react-hooks'
import
{
registerCommandAction
,
filterFnAction
,
registerLogScriptRunnerAction
,
registerInfoScriptRunnerAction
,
registerErrorScriptRunnerAction
,
registerWarnScriptRunnerAction
,
registerRemixWelcomeTextAction
}
from
'./actions/terminalAction'
import
{
registerCommandAction
,
filterFnAction
,
registerLogScriptRunnerAction
,
registerInfoScriptRunnerAction
,
registerErrorScriptRunnerAction
,
registerWarnScriptRunnerAction
,
registerRemixWelcomeTextAction
,
listenOnNetworkAction
,
initListeningOnNetwork
}
from
'./actions/terminalAction'
import
{
initialState
,
registerCommandReducer
,
registerFilterReducer
,
addCommandHistoryReducer
,
registerScriptRunnerReducer
,
remixWelcomeTextReducer
}
from
'./reducers/terminalReducer'
import
{
remixWelcome
}
from
'./reducers/remixWelcom'
import
{
getKeyOf
,
getValueOf
}
from
'./utils/utils'
import
{
getKeyOf
,
getValueOf
,
Objectfilter
,
matched
,
find
}
from
'./utils/utils'
import
{
allCommands
,
allPrograms
}
from
'./commands'
// eslint-disable-line
import
{
CopyToClipboard
}
from
'@remix-ui/clipboard'
// eslint-disable-line
import
{
ModalDialog
}
from
'@remix-ui/modal-dialog'
// const TxLogger from '../../../apps/'
import
vm
from
'vm'
import
javascriptserialize
from
'javascript-serialize'
import
jsbeautify
from
'js-beautify'
import
helper
from
'../../../../../apps/remix-ide/src/lib/helper'
import
parse
from
'html-react-parser'
import
'./remix-ui-terminal.css'
import
{
debug
}
from
'console'
import
{
eventNames
}
from
'process'
const
remixLib
=
require
(
'@remix-project/remix-lib'
)
var
typeConversion
=
remixLib
.
execution
.
typeConversion
/* eslint-disable-next-line */
export
interface
RemixUiTerminalProps
{
...
...
@@ -27,6 +38,15 @@ export interface RemixUiTerminalProps {
config
:
any
thisState
:
any
vm
:
any
commandHelp
:
any
,
_deps
:
any
,
fileImport
:
any
,
gistHandler
:
any
,
sourceHighlighter
:
any
,
registry
:
any
,
commands
:
any
,
txListener
:
any
,
eventsDecoder
:
any
}
export
interface
ClipboardEvent
<
T
=
Element
>
extends
SyntheticEvent
<
T
,
any
>
{
...
...
@@ -34,7 +54,6 @@ export interface ClipboardEvent<T = Element> extends SyntheticEvent<T, any> {
}
export
const
RemixUiTerminal
=
(
props
:
RemixUiTerminalProps
)
=>
{
const
[
toggleDownUp
,
setToggleDownUp
]
=
useState
(
'fa-angle-double-down'
)
const
[
inserted
,
setInserted
]
=
useState
(
false
)
const
[
_cmdIndex
,
setCmdIndex
]
=
useState
(
-
1
)
...
...
@@ -51,12 +70,14 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
const
[
cmdHistory
,
cmdHistoryDispatch
]
=
useReducer
(
addCommandHistoryReducer
,
initialState
)
const
[
scriptRunnserState
,
scriptRunnerDispatch
]
=
useReducer
(
registerScriptRunnerReducer
,
initialState
)
const
[
welcomeTextState
,
welcomTextDispath
]
=
useReducer
(
remixWelcomeTextReducer
,
initialState
)
const
[
isListeningOnNetwork
,
setIsListeningOnNetwork
]
=
useState
(
false
)
const
[
autoCompletState
,
setAutoCompleteState
]
=
useState
({
activeSuggestion
:
0
,
data
:
{
_options
:
[]
},
_startingElement
:
0
,
autoCompleteSelectedItem
:
{},
_elementToShow
:
4
,
_selectedElement
:
0
,
filteredCommands
:
[],
...
...
@@ -64,58 +85,13 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
showSuggestions
:
false
,
text
:
''
,
userInput
:
''
,
extraCommands
:
[]
})
const
[
state
,
setState
]
=
useState
({
journalBlocks
:
{
intro
:
(
<
div
>
<
div
>
- Welcome to Remix
{
props
.
version
}
-
</
div
>
<
br
/>
<
div
>
You can use this terminal to:
</
div
>
<
ul
className=
'ul'
>
<
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
>
</
li
>
</
ul
>
<
div
>
The following libraries are accessible:
</
div
>
<
ul
className=
'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
</
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
>
</
div
>
),
text
:
(<
div
>
David
</
div
>)
},
data
:
{
// lineLength: props.options.lineLength || 80,
session
:
[],
activeFilters
:
{
commands
:
{},
input
:
''
},
filterFns
:
{}
},
_commands
:
{},
commands
:
{},
_JOURNAL
:
[],
_jobs
:
[],
_INDEX
:
{},
_INDEXall
:
[],
_INDEXallMain
:
[],
_INDEXcommands
:
{},
_INDEXcommandsMain
:
{}
extraCommands
:
[],
commandHistoryIndex
:
0
})
const
_scopedCommands
=
()
=>
{
}
const
[
searchInput
,
setSearchInput
]
=
useState
(
''
)
// const [showTableDetails, setShowTableDetails] = useState([])
const
[
showTableDetails
,
setShowTableDetails
]
=
useState
(
null
)
useWindowResize
(()
=>
{
setWindowHeight
(
window
.
innerHeight
)
...
...
@@ -125,7 +101,8 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
const
inputEl
=
useRef
(
null
)
// events
useEffect
(()
=>
{
registerRemixWelcomeTextAction
(
remixWelcome
,
welcomTextDispath
)
initListeningOnNetwork
(
props
,
scriptRunnerDispatch
)
// registerRemixWelcomeTextAction(remixWelcome, welcomTextDispath)
registerLogScriptRunnerAction
(
props
.
thisState
,
'log'
,
newstate
.
commands
,
scriptRunnerDispatch
)
registerInfoScriptRunnerAction
(
props
.
thisState
,
'info'
,
newstate
.
commands
,
scriptRunnerDispatch
)
registerWarnScriptRunnerAction
(
props
.
thisState
,
'warn'
,
newstate
.
commands
,
scriptRunnerDispatch
)
...
...
@@ -135,15 +112,18 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
registerCommandAction
(
'info'
,
_blocksRenderer
(
'info'
),
{
activate
:
true
},
dispatch
)
registerCommandAction
(
'warn'
,
_blocksRenderer
(
'warn'
),
{
activate
:
true
},
dispatch
)
registerCommandAction
(
'error'
,
_blocksRenderer
(
'error'
),
{
activate
:
true
},
dispatch
)
registerCommandAction
(
'script'
,
function
execute
(
args
,
scopedCommands
,
append
)
{
var
script
=
String
(
args
[
0
])
console
.
log
({
script
})
console
.
log
({
scopedCommands
})
_shell
(
script
,
scopedCommands
,
function
(
error
,
output
)
{
console
.
log
({
error
},
'registerCommand scrpt'
)
console
.
log
({
output
},
'registerCommand scrpt 2'
)
if
(
error
)
scriptRunnerDispatch
({
type
:
'error'
,
payload
:
{
message
:
error
}
})
else
if
(
output
)
scriptRunnerDispatch
({
type
:
'error'
,
payload
:
{
message
:
output
}
})
if
(
output
)
scriptRunnerDispatch
({
type
:
'script'
,
payload
:
{
message
:
'5'
}
})
})
},
{
activate
:
true
},
dispatch
)
filterFnAction
(
'log'
,
basicFilter
,
filterDispatch
)
filterFnAction
(
'info'
,
basicFilter
,
filterDispatch
)
filterFnAction
(
'warn'
,
basicFilter
,
filterDispatch
)
...
...
@@ -157,7 +137,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
// dispatch({ type: 'html', payload: { commands: htmlresullt.commands } })
// dispatch({ type: 'log', payload: { _commands: logresult._commands } })
// registerCommand('log', _blocksRenderer('log'), { activate: true })
},
[
newstate
.
journalBlocks
,
props
.
thisState
.
autoCompletePopup
,
autoCompletState
.
text
])
},
[
props
.
thisState
.
autoCompletePopup
,
autoCompletState
.
text
])
const
placeCaretAtEnd
=
(
el
)
=>
{
el
.
focus
()
...
...
@@ -169,6 +149,53 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
sel
.
addRange
(
range
)
}
const
domTerminalFeatures
=
()
=>
{
return
{
remix
:
props
.
cmdInterpreter
}
}
function
exeCurrent
(
cb
)
{
return
execute
(
undefined
,
cb
)
}
function
execute
(
file
,
cb
)
{
function
_execute
(
content
,
cb
)
{
if
(
!
content
)
{
// toolTip('no content to execute')
if
(
cb
)
cb
()
return
}
newstate
.
commands
.
script
(
content
)
}
if
(
typeof
file
===
'undefined'
)
{
var
content
=
props
.
_deps
.
editor
.
currentContent
()
_execute
(
content
,
cb
)
return
}
var
provider
=
props
.
_deps
.
fileManager
.
fileProviderOf
(
file
)
if
(
!
provider
)
{
// toolTip(`provider for path ${file} not found`)
if
(
cb
)
cb
()
return
}
provider
.
get
(
file
,
(
error
,
content
)
=>
{
if
(
error
)
{
// toolTip(error)
// TODO: pop up
if
(
cb
)
cb
()
return
}
_execute
(
content
,
cb
)
})
}
const
_shell
=
async
(
script
,
scopedCommands
,
done
)
=>
{
// default shell
if
(
script
.
indexOf
(
'remix:'
)
===
0
)
{
return
done
(
null
,
'This type of command has been deprecated and is not functionning anymore. Please run remix.help() to list available commands.'
)
...
...
@@ -177,21 +204,36 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
if
(
script
.
indexOf
(
'remix.'
)
===
0
)
{
// we keep the old feature. This will basically only be called when the command is querying the "remix" object.
// for all the other case, we use the Code Executor plugin
var
context
=
props
.
cmdInterpreter
var
context
=
domTerminalFeatures
()
try
{
var
cmds
=
props
.
vm
.
createContext
(
context
)
var
result
=
props
.
vm
.
runInContext
(
script
,
cmds
)
return
done
(
null
,
result
)
const
cmds
=
vm
.
createContext
(
context
)
// const result
let
result
=
vm
.
runInContext
(
script
,
cmds
)
if
(
script
===
'remix.exeCurrent()'
)
{
result
=
exeCurrent
(
undefined
)
}
else
{
if
(
result
===
{})
{
for
(
const
k
in
result
)
{
result
=
+
`<div> {k}:
${
result
[
k
]}
</div> <br>`
}
}
}
console
.
log
(
result
===
{},
' is result === object'
)
console
.
log
({
result
})
return
done
(
null
,
''
)
}
catch
(
error
)
{
return
done
(
error
.
message
)
}
}
try
{
let
result
:
any
if
(
script
.
trim
().
startsWith
(
'git'
))
{
// result = await this.call('git', 'execute', script)
}
else
{
result
=
await
props
.
thisState
.
call
(
'scriptRunner'
,
'execute'
,
script
)
}
console
.
log
({
result
})
done
()
}
catch
(
error
)
{
done
(
error
.
message
||
error
)
...
...
@@ -231,7 +273,6 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
}
}
const
_appendItem
=
(
item
:
any
)
=>
{
let
{
_JOURNAL
,
_jobs
,
data
}
=
state
const
self
=
props
...
...
@@ -268,7 +309,20 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
}
const
handleKeyDown
=
(
event
)
=>
{
if
(
event
.
which
===
13
)
{
const
suggestionCount
=
autoCompletState
.
activeSuggestion
if
(
autoCompletState
.
userInput
!==
''
&&
(
event
.
which
===
27
||
event
.
which
===
8
||
event
.
which
===
46
))
{
console
.
log
(
' enter esc and delete'
)
// backspace or any key that should remove the autocompletion
setAutoCompleteState
(
prevState
=>
({
...
prevState
,
showSuggestions
:
false
}))
}
if
(
autoCompletState
.
showSuggestions
&&
(
event
.
which
===
13
||
event
.
which
===
9
))
{
if
(
autoCompletState
.
userInput
.
length
===
1
)
{
setAutoCompleteState
(
prevState
=>
({
...
prevState
,
showSuggestions
:
false
,
userInput
:
Object
.
keys
(
autoCompletState
.
data
.
_options
[
0
]).
toString
()
}))
}
else
{
setAutoCompleteState
(
prevState
=>
({
...
prevState
,
showSuggestions
:
false
,
userInput
:
autoCompletState
.
userInput
}))
}
}
if
(
event
.
which
===
13
&&
!
autoCompletState
.
showSuggestions
)
{
if
(
event
.
ctrlKey
)
{
// <ctrl+enter>
// on enter, append the value in the cli input to the journal
inputEl
.
current
.
focus
()
...
...
@@ -287,7 +341,50 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
inputEl
.
current
.
focus
()
setAutoCompleteState
(
prevState
=>
({
...
prevState
,
showSuggestions
:
false
}))
}
}
else
if
(
event
.
which
===
38
)
{
// <arrowUp>
}
else
if
(
newstate
.
_commandHistory
.
length
&&
event
.
which
===
38
&&
!
autoCompletState
.
showSuggestions
&&
(
autoCompletState
.
userInput
===
''
))
{
console
.
log
(
'previous command up'
)
// if (autoCompletState.commandHistoryIndex < 1) {
event
.
preventDefault
()
console
.
log
(
newstate
.
_commandHistory
[
0
],
' up value'
)
setAutoCompleteState
(
prevState
=>
({
...
prevState
,
userInput
:
newstate
.
_commandHistory
[
0
]
}))
// }
// else if (newstate._commandHistory.length < autoCompletState.commandHistoryIndex) {
// setAutoCompleteState(prevState => ({ ...prevState, commandHistoryIndex: --autoCompletState.commandHistoryIndex }))
// console.log(newstate._commandHistory[newstate._commandHistory.length > 1 ? autoCompletState.commandHistoryIndex-- : newstate._commandHistory.length + 1], ' up value')
// } else if (newstate._commandHistory.length === autoCompletState.commandHistoryIndex) {
// console.log(newstate._commandHistory.length === autoCompletState.commandHistoryIndex, ' up value middle')
// setAutoCompleteState(prevState => ({ ...prevState, commandHistoryIndex: autoCompletState.commandHistoryIndex - 2, userInput: newstate._commandHistory[autoCompletState.commandHistoryIndex] }))
// } else {
// setAutoCompleteState(prevState => ({ ...prevState, commandHistoryIndex: autoCompletState.commandHistoryIndex - 1, userInput: newstate._commandHistory[autoCompletState.commandHistoryIndex] }))
// console.log(newstate._commandHistory[newstate._commandHistory.length - 1], ' up value last')
// }
// if (newstate._commandHistory.length === 0) {
// setAutoCompleteState(prevState => ({ ...prevState, userInput: newstate[0] }))
// }
// setAutoCompleteState(prevState => ({ ...prevState, userInput: newstate[autoCompletState.commandHistoryIndex] }))
// TODO: giving error => need to work on the logic
// // } else if (newstate._commandHistory.length && event.which === 40 && !autoCompletState.showSuggestions && (autoCompletState.userInput !== '')) {
// // console.log('previous command down')
// // if (autoCompletState.commandHistoryIndex < newstate._commandHistory.length) {
// // setAutoCompleteState(prevState => ({ ...prevState, commandHistoryIndex: autoCompletState.commandHistoryIndex + 1, userInput: newstate._commandHistory[autoCompletState.commandHistoryIndex + 1] }))
// // console.log(newstate._commandHistory[newstate._commandHistory.length > 1 ? autoCompletState.commandHistoryIndex++ : newstate._commandHistory.length - 1], ' down ++ value')
// // } else {
// // console.log(newstate._commandHistory[newstate._commandHistory.length - 1], ' down value last')
// // setAutoCompleteState(prevState => ({ ...prevState, commandHistoryIndex: newstate._commandHistory.length - 1, userInput: newstate._commandHistory[newstate._commandHistory.length - 1] }))
// // }
// // // if (autoCompletState.commandHistoryIndex === newstate._commandHistory.length) {
// // // return
// // // }
// setAutoCompleteState(prevState => ({ ...prevState, userInput: newstate[autoCompletState.commandHistoryIndex] + 1 }))
}
else
if
(
event
.
which
===
38
&&
autoCompletState
.
showSuggestions
)
{
event
.
preventDefault
()
if
(
autoCompletState
.
activeSuggestion
===
0
)
{
return
}
setAutoCompleteState
(
prevState
=>
({
...
prevState
,
activeSuggestion
:
suggestionCount
-
1
,
userInput
:
Object
.
keys
(
autoCompletState
.
data
.
_options
[
autoCompletState
.
activeSuggestion
-
1
]).
toString
()
}))
console
.
log
(
'disable up an down key in input box'
)
}
else
if
(
event
.
which
===
38
&&
!
autoCompletState
.
showSuggestions
)
{
// <arrowUp>
const
len
=
_cmdHistory
.
length
if
(
len
===
0
)
event
.
preventDefault
()
if
(
_cmdHistory
.
length
-
1
>
_cmdIndex
)
{
...
...
@@ -295,8 +392,14 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
}
inputEl
.
current
.
innerText
=
_cmdHistory
[
_cmdIndex
]
inputEl
.
current
.
focus
()
}
else
if
(
event
.
which
===
40
)
{
}
else
if
(
event
.
which
===
40
&&
autoCompletState
.
showSuggestions
)
{
event
.
preventDefault
()
if
((
autoCompletState
.
activeSuggestion
+
1
)
===
autoCompletState
.
data
.
_options
.
length
)
{
return
}
setAutoCompleteState
(
prevState
=>
({
...
prevState
,
activeSuggestion
:
suggestionCount
+
1
,
userInput
:
Object
.
keys
(
autoCompletState
.
data
.
_options
[
autoCompletState
.
activeSuggestion
+
1
]).
toString
()
}))
console
.
log
(
'disable up an down key in input box'
)
}
else
if
(
event
.
which
===
40
&&
!
autoCompletState
.
showSuggestions
)
{
if
(
_cmdIndex
>
-
1
)
{
setCmdIndex
(
prevState
=>
prevState
--
)
}
...
...
@@ -305,6 +408,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
}
else
{
setCmdTemp
(
inputEl
.
current
.
innerText
)
}
console
.
log
({
autoCompletState
})
}
const
moveGhostbar
=
(
event
)
=>
{
...
...
@@ -326,14 +430,6 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
const
mousedown
=
(
event
:
MouseEvent
)
=>
{
setSeparatorYPosition
(
event
.
clientY
)
setDragging
(
true
)
// console.log({ windowHeight })
// console.log(event.which === 1, 'event.which === 1')
// event.preventDefault()
// moveGhostbar(event)
// if (event.which === 1) {
// console.log('event .which code 1')
// moveGhostbar(event)
// }
}
const
onMouseMove
:
any
=
(
e
:
MouseEvent
)
=>
{
...
...
@@ -352,36 +448,13 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
setDragging
(
false
)
}
/* end of mouse event */
const
cancelGhostbar
=
(
event
)
=>
{
if
(
event
.
keyCode
===
27
)
{
console
.
log
(
'event .key code 27'
)
}
}
useEffect
(()
=>
{
// document.addEventListener('mousemove', changeBg)
// function changeBg () {
// document.getElementById('dragId').style.backgroundColor = 'skyblue'
// }
// document.addEventListener('mouseup', changeBg2)
// function changeBg2 () {
// document.getElementById('dragId').style.backgroundColor = ''
// }
document
.
addEventListener
(
'mousemove'
,
onMouseMove
)
document
.
addEventListener
(
'mouseup'
,
onMouseUp
)
return
()
=>
{
// document.addEventListener('mousemove', changeBg)
// function changeBg () {
// document.getElementById('dragId').style.backgroundColor = 'skyblue'
// }
// document.addEventListener('mouseup', changeBg2)
// function changeBg2 () {
// document.getElementById('dragId').style.backgroundColor = ''
// }
document
.
removeEventListener
(
'mousemove'
,
onMouseMove
)
document
.
removeEventListener
(
'mouseup'
,
onMouseUp
)
}
...
...
@@ -448,85 +521,378 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
/* end of block content that gets rendered from script Runner */
const
handleClearConsole
=
()
=>
{
dispatch
({
type
:
'clearconsole'
,
payload
:
[]
})
inputEl
.
current
.
focus
()
}
/* start of autoComplete */
const
handleSelect
=
(
text
)
=>
{
props
.
thisState
.
event
.
trigger
(
'handleSelect'
,
[
text
])
const
listenOnNetwork
=
(
event
:
any
)
=>
{
const
isListening
=
event
.
target
.
checked
setIsListeningOnNetwork
(
isListening
)
listenOnNetworkAction
(
props
,
isListening
)
}
const
onChange
=
(
event
:
any
)
=>
{
event
.
preventDefault
()
const
inputString
=
event
.
target
.
value
console
.
log
(
event
)
console
.
log
({
inputString
})
setAutoCompleteState
(
prevState
=>
({
...
prevState
,
showSuggestions
:
true
,
userInput
:
inputString
}))
const
textList
=
inputString
.
split
(
' '
)
const
autoCompleteInput
=
textList
.
length
>
1
?
textList
[
textList
.
length
-
1
]
:
textList
[
0
]
allPrograms
.
forEach
(
item
=>
{
const
program
=
getKeyOf
(
item
)
console
.
log
({
program
})
if
(
program
.
substring
(
0
,
program
.
length
-
1
).
includes
(
autoCompleteInput
.
trim
()))
{
setAutoCompleteState
(
prevState
=>
({
...
prevState
,
data
:
{
_options
:
[
item
]
}
}))
}
else
if
(
autoCompleteInput
.
trim
().
includes
(
program
)
||
(
program
===
autoCompleteInput
.
trim
()))
{
allCommands
.
forEach
(
item
=>
{
console
.
log
({
item
})
const
command
=
getKeyOf
(
item
)
if
(
command
.
includes
(
autoCompleteInput
.
trim
()))
{
setAutoCompleteState
(
prevState
=>
({
...
prevState
,
data
:
{
_options
:
[
item
]
}
}))
}
})
if
(
matched
(
allPrograms
,
inputString
)
||
inputString
.
includes
(
'.'
))
{
setAutoCompleteState
(
prevState
=>
({
...
prevState
,
showSuggestions
:
true
,
userInput
:
inputString
}))
const
textList
=
inputString
.
split
(
'.'
)
if
(
textList
.
length
===
1
)
{
setAutoCompleteState
(
prevState
=>
({
...
prevState
,
data
:
{
_options
:
[]
}
}))
const
result
=
Objectfilter
(
allPrograms
,
autoCompletState
.
userInput
)
setAutoCompleteState
(
prevState
=>
({
...
prevState
,
data
:
{
_options
:
result
}
}))
}
else
{
setAutoCompleteState
(
prevState
=>
({
...
prevState
,
data
:
{
_options
:
[]
}
}))
const
result
=
Objectfilter
(
allCommands
,
autoCompletState
.
userInput
)
setAutoCompleteState
(
prevState
=>
({
...
prevState
,
data
:
{
_options
:
result
}
}))
}
})
autoCompletState
.
extraCommands
.
forEach
(
item
=>
{
const
command
=
getKeyOf
(
item
)
if
(
command
.
includes
(
autoCompleteInput
.
trim
()))
{
setAutoCompleteState
(
prevState
=>
({
...
prevState
,
data
:
{
_options
:
[
item
]
}
}))
}
else
{
setAutoCompleteState
(
prevState
=>
({
...
prevState
,
showSuggestions
:
false
,
userInput
:
inputString
}))
}
}
const
handleSelect
=
(
event
)
=>
{
const
suggestionCount
=
autoCompletState
.
activeSuggestion
if
(
event
.
keyCode
===
38
)
{
if
(
autoCompletState
.
activeSuggestion
===
0
)
{
return
}
setAutoCompleteState
(
prevState
=>
({
...
prevState
,
activeSuggestion
:
suggestionCount
-
1
}))
}
else
if
(
event
.
keyCode
===
40
)
{
if
(
autoCompletState
.
activeSuggestion
-
1
===
autoCompletState
.
data
.
_options
.
length
)
{
return
}
setAutoCompleteState
(
prevState
=>
({
...
prevState
,
activeSuggestion
:
suggestionCount
+
1
}))
}
// props.thisState.event.trigger('handleSelect', [text])
}
const
checkTxStatus
=
(
tx
,
type
)
=>
{
if
(
tx
.
status
===
'0x1'
||
tx
.
status
===
true
)
{
return
(<
i
className=
'txStatus succeeded fas fa-check-circle'
></
i
>)
}
if
(
type
===
'call'
||
type
===
'unknownCall'
||
type
===
'unknown'
)
{
return
(<
i
className=
'txStatus call'
>
call
</
i
>)
}
else
if
(
tx
.
status
===
'0x0'
||
tx
.
status
===
false
)
{
return
(<
i
className=
'txStatus failed fas fa-times-circle'
></
i
>)
}
else
{
return
(<
i
className=
'txStatus notavailable fas fa-circle-thin'
title=
'Status not available'
></
i
>)
}
}
const
context
=
(
opts
,
blockchain
)
=>
{
const
data
=
opts
.
tx
||
''
const
from
=
opts
.
from
?
helper
.
shortenHexData
(
opts
.
from
)
:
''
let
to
=
opts
.
to
if
(
data
.
to
)
to
=
to
+
' '
+
helper
.
shortenHexData
(
data
.
to
)
const
val
=
data
.
value
let
hash
=
data
.
hash
?
helper
.
shortenHexData
(
data
.
hash
)
:
''
const
input
=
data
.
input
?
helper
.
shortenHexData
(
data
.
input
)
:
''
const
logs
=
data
.
logs
&&
data
.
logs
.
decoded
&&
data
.
logs
.
decoded
.
length
?
data
.
logs
.
decoded
.
length
:
0
const
block
=
data
.
receipt
?
data
.
receipt
.
blockNumber
:
data
.
blockNumber
||
''
const
i
=
data
?
data
.
transactionIndex
:
data
.
transactionIndex
const
value
=
val
?
typeConversion
.
toInt
(
val
)
:
0
if
(
blockchain
.
getProvider
()
===
'vm'
)
{
return
(
<
div
>
<
span
className=
'txLog_7Xiho'
>
<
span
className=
'tx'
>
[
{
vm
}
]
</
span
>
<
div
className=
'txItem'
><
span
className=
'txItemTitle'
>
from:
</
span
>
{
from
}
</
div
>
<
div
className=
'txItem'
><
span
className=
'txItemTitle'
>
to:
</
span
>
{
to
}
</
div
>
<
div
className=
'txItem'
><
span
className=
'txItemTitle'
>
value:
</
span
>
{
value
}
wei
</
div
>
<
div
className=
'txItem'
><
span
className=
'txItemTitle'
>
data:
</
span
>
{
input
}
</
div
>
<
div
className=
'txItem'
><
span
className=
'txItemTitle'
>
logs:
</
span
>
{
logs
}
</
div
>
<
div
className=
'txItem'
><
span
className=
'txItemTitle'
>
hash:
</
span
>
{
hash
}
</
div
>
</
span
>
</
div
>)
}
else
if
(
blockchain
.
getProvider
()
!==
'vm'
&&
data
.
resolvedData
)
{
return
(
<
div
>
<
span
className=
'txLog_7Xiho'
>
<
span
className=
'tx'
>
[block:$
{
block
}
txIndex:$
{
i
}
]
</
span
>
<
div
className=
'txItem'
><
span
className=
'txItemTitle'
>
from:
</
span
>
{
from
}
</
div
>
<
div
className=
'txItem'
><
span
className=
'txItemTitle'
>
to:
</
span
>
{
to
}
</
div
>
<
div
className=
'txItem'
><
span
className=
'txItemTitle'
>
value:
</
span
>
{
value
}
wei
</
div
>
<
div
className=
'txItem'
><
span
className=
'txItemTitle'
>
data:
</
span
>
{
input
}
</
div
>
<
div
className=
'txItem'
><
span
className=
'txItemTitle'
>
logs:
</
span
>
{
logs
}
</
div
>
<
div
className=
'txItem'
><
span
className=
'txItemTitle'
>
hash:
</
span
>
{
hash
}
</
div
>
</
span
>
</
div
>)
}
else
{
to
=
helper
.
shortenHexData
(
to
)
hash
=
helper
.
shortenHexData
(
data
.
blockHash
)
return
(
<
div
>
<
span
className=
'txLog'
>
<
span
className=
'tx'
>
[block:$
{
block
}
txIndex:$
{
i
}
]
</
span
>
<
div
className=
'txItem'
><
span
className=
'txItemTitle'
>
from:
</
span
>
{
from
}
</
div
>
<
div
className=
'txItem'
><
span
className=
'txItemTitle'
>
to:
</
span
>
{
to
}
</
div
>
<
div
className=
'txItem'
><
span
className=
'txItemTitle'
>
value:
</
span
>
{
value
}
wei
</
div
>
</
span
>
</
div
>)
}
}
const
txDetails
=
(
event
,
tx
,
obj
)
=>
{
if
(
showTableDetails
===
null
)
{
setShowTableDetails
(
true
)
}
else
{
setShowTableDetails
(
null
)
}
// if (showTableDetails.length === 0) {
// setShowTableDetails([{ hash: tx.hash, show: true }])
// }
// const id = showTableDetails.filter(x => x.hash !== tx.hash)
// if ((showTableDetails.length !== 0) && (id[0] === tx.hash)) {
// setShowTableDetails(currentState => ([...currentState, { hash: tx.hash, show: false }]))
// }
// console.log((showTableDetails.length !== 0) && (id[0] === tx.hash))
// console.log({ showTableDetails }, ' clicked button')
}
const
showTable
=
(
opts
)
=>
{
let
msg
=
''
let
toHash
const
data
=
opts
.
data
// opts.data = data.tx
if
(
data
.
to
)
{
toHash
=
opts
.
to
+
' '
+
data
.
to
}
else
{
toHash
=
opts
.
to
}
let
callWarning
=
''
if
(
opts
.
isCall
)
{
callWarning
=
'(Cost only applies when called by a contract)'
}
if
(
!
opts
.
isCall
)
{
if
(
opts
.
status
!==
undefined
&&
opts
.
status
!==
null
)
{
if
(
opts
.
status
===
'0x0'
||
opts
.
status
===
false
)
{
msg
=
' Transaction mined but execution failed'
}
else
if
(
opts
.
status
===
'0x1'
||
opts
.
status
===
true
)
{
msg
=
' Transaction mined and execution succeed'
}
}
else
{
msg
=
' Status not available at the moment'
}
})
if
(
autoCompletState
.
data
.
_options
.
length
===
1
&&
event
.
which
===
9
)
{
// if only one option and tab is pressed, we resolve it
event
.
preventDefault
()
textList
.
pop
()
textList
.
push
(
getKeyOf
(
autoCompletState
.
data
.
_options
[
0
]))
handleSelect
(
`
${
textList
}
`
.
replace
(
/,/g
,
' '
))
}
let
stringified
=
' - '
if
(
opts
.
logs
&&
opts
.
logs
.
decoded
)
{
stringified
=
typeConversion
.
stringify
(
opts
.
logs
.
decoded
)
}
const
val
=
opts
.
val
!=
null
?
typeConversion
.
toInt
(
opts
.
val
)
:
0
return
(
<
table
className=
'txTable'
id=
'txTable'
data
-
id=
{
`txLoggerTable${opts.hash}`
}
>
<
tr
className=
'tr'
>
<
td
className=
'td'
data
-
shared=
{
`key_${opts.hash}`
}
>
status
</
td
>
<
td
className=
'td'
data
-
id=
{
`txLoggerTableStatus${opts.hash}`
}
data
-
shared=
{
`pair_${opts.hash}`
}
>
{
opts
.
status
}{
msg
}
</
td
>
</
tr
>
<
tr
className=
'tr'
>
<
td
className=
'td'
data
-
shared=
{
`key_${opts.hash}`
}
>
transaction hash
</
td
>
<
td
className=
'td'
data
-
id=
{
`txLoggerTableHash${opts.hash}`
}
data
-
shared=
{
`pair_${opts.hash}`
}
>
{
opts
.
hash
}
<
CopyToClipboard
content=
{
opts
.
hash
}
/>
</
td
>
</
tr
>
{
opts
.
contractAddress
&&
(
<
tr
className=
'tr'
>
<
td
className=
'td'
data
-
shared=
{
`key_${opts.hash}`
}
>
contract address
</
td
>
<
td
className=
'td'
data
-
id=
{
`txLoggerTableContractAddress${opts.hash}`
}
data
-
shared=
{
`pair_${opts.hash}`
}
>
{
opts
.
contractAddress
}
<
CopyToClipboard
content=
{
opts
.
contractAddress
}
/>
</
td
>
</
tr
>
)
}
{
opts
.
from
&&
(
<
tr
className=
'tr'
>
<
td
className=
'td tableTitle'
data
-
shared=
{
`key_${opts.hash}`
}
>
from
</
td
>
<
td
className=
'td'
data
-
id=
{
`txLoggerTableFrom${opts.hash}`
}
data
-
shared=
{
`pair_${opts.hash}`
}
>
{
opts
.
from
}
<
CopyToClipboard
content=
{
opts
.
from
}
/>
</
td
>
</
tr
>
)
}
{
opts
.
to
&&
(
<
tr
className=
'tr'
>
<
td
className=
'td'
data
-
shared=
{
`key_${opts.hash}`
}
>
to
</
td
>
<
td
className=
'td'
data
-
id=
{
`txLoggerTableTo${opts.hash}`
}
data
-
shared=
{
`pair_${opts.hash}`
}
>
{
toHash
}
<
CopyToClipboard
content=
{
data
.
to
?
data
.
to
:
toHash
}
/>
</
td
>
</
tr
>
)
}
{
opts
.
gas
&&
(
<
tr
className=
'tr'
>
<
td
className=
'td'
data
-
shared=
{
`key_${opts.hash}`
}
>
gas
</
td
>
<
td
className=
'td'
data
-
id=
{
`txLoggerTableGas${opts.hash}`
}
data
-
shared=
{
`pair_${opts.hash}`
}
>
{
opts
.
gas
}
gas
<
CopyToClipboard
content=
{
opts
.
gas
}
/>
</
td
>
</
tr
>
)
}
{
opts
.
transactionCost
&&
(
<
tr
className=
'tr'
>
<
td
className=
'td'
data
-
shared=
{
`key_${opts.hash}`
}
>
transaction cost
</
td
>
<
td
className=
'td'
data
-
id=
{
`txLoggerTableTransactionCost${opts.hash}`
}
data
-
shared=
{
`pair_${opts.hash}`
}
>
{
opts
.
transactionCost
}
gas
{
callWarning
}
<
CopyToClipboard
content=
{
opts
.
transactionCost
}
/>
</
td
>
</
tr
>
)
}
{
opts
.
executionCost
&&
(
<
tr
className=
'tr'
>
<
td
className=
'td'
data
-
shared=
{
`key_${opts.hash}`
}
>
execution cost
</
td
>
<
td
className=
'td'
data
-
id=
{
`txLoggerTableExecutionHash${opts.hash}`
}
data
-
shared=
{
`pair_${opts.hash}`
}
>
{
opts
.
executionCost
}
gas
{
callWarning
}
<
CopyToClipboard
content=
{
opts
.
executionCost
}
/>
</
td
>
</
tr
>
)
}
{
opts
.
hash
&&
(
<
tr
className=
'tr'
>
<
td
className=
'td'
data
-
shared=
{
`key_${opts.hash}`
}
>
hash
</
td
>
<
td
className=
'td'
data
-
id=
{
`txLoggerTableHash${opts.hash}`
}
data
-
shared=
{
`pair_${opts.hash}`
}
>
{
opts
.
hash
}
<
CopyToClipboard
content=
{
opts
.
hash
}
/>
</
td
>
</
tr
>
)
}
{
opts
.
input
&&
(
<
tr
className=
'tr'
>
<
td
className=
'td'
data
-
shared=
{
`key_${opts.hash}`
}
>
input
</
td
>
<
td
className=
'td'
data
-
id=
{
`txLoggerTableHash${opts.hash}`
}
data
-
shared=
{
`pair_${opts.hash}`
}
>
{
helper
.
shortenHexData
(
opts
.
input
)
}
<
CopyToClipboard
content=
{
opts
.
input
}
/>
</
td
>
</
tr
>
)
}
{
opts
[
'decoded input'
]
&&
(
<
tr
className=
'tr'
>
<
td
className=
'td'
data
-
shared=
{
`key_${opts.hash}`
}
>
decode input
</
td
>
<
td
className=
'td'
data
-
id=
{
`txLoggerTableHash${opts.hash}`
}
data
-
shared=
{
`pair_${opts.hash}`
}
>
{
opts
[
'decoded input'
]
}
<
CopyToClipboard
content=
{
opts
[
'decoded input'
]
}
/>
</
td
>
</
tr
>
)
}
{
opts
[
'decoded output'
]
&&
(
<
tr
className=
'tr'
>
<
td
className=
'td'
data
-
shared=
{
`key_${opts.hash}`
}
>
decode output
</
td
>
<
td
className=
'td'
data
-
id=
{
`txLoggerTableHash${opts.hash}`
}
data
-
shared=
{
`pair_${opts.hash}`
}
>
{
opts
[
'decoded output'
]
}
<
CopyToClipboard
content=
{
opts
[
'decoded output'
]
}
/>
</
td
>
</
tr
>
)
}
{
opts
.
logs
&&
(
<
tr
className=
'tr'
>
<
td
className=
'td'
data
-
shared=
{
`key_${opts.hash}`
}
>
logs
</
td
>
<
td
className=
'td'
data
-
id=
{
`txLoggerTableHash${opts.hash}`
}
data
-
shared=
{
`pair_${opts.hash}`
}
>
{
JSON
.
stringify
(
stringified
,
null
,
'
\
t'
)
}
<
CopyToClipboard
content=
{
JSON
.
stringify
(
stringified
,
null
,
'
\
t'
)
}
/>
<
CopyToClipboard
content=
{
JSON
.
stringify
(
opts
.
logs
.
raw
||
'0'
)
}
/>
</
td
>
</
tr
>
)
}
{
opts
.
val
&&
(
<
tr
className=
'tr'
>
<
td
className=
'td'
data
-
shared=
{
`key_${opts.hash}`
}
>
val
</
td
>
<
td
className=
'td'
data
-
id=
{
`txLoggerTableHash${opts.hash}`
}
data
-
shared=
{
`pair_${opts.hash}`
}
>
{
val
}
wei
<
CopyToClipboard
content=
{
`${val} wei`
}
/>
</
td
>
</
tr
>
)
}
</
table
>
)
}
const
debug
=
(
event
,
tx
)
=>
{
event
.
stopPropagation
()
if
(
tx
.
isCall
&&
tx
.
envMode
!==
'vm'
)
{
console
.
log
(
'start debugging'
)
return
(<
ModalDialog
hide=
{
false
}
handleHide=
{
()
=>
{}
}
message=
"Cannot debug this call. Debugging calls is only possible in JavaScript VM mode."
/>)
}
else
{
props
.
event
.
trigger
(
'debuggingRequested'
,
[
tx
.
hash
])
console
.
log
(
'trigger '
,
{
tx
:
props
.
event
.
trigger
})
}
}
const
renderKnownTransactions
=
(
tx
,
receipt
,
index
)
=>
{
const
from
=
tx
.
from
const
to
=
tx
.
to
const
obj
=
{
from
,
to
}
const
showDetails
=
showTableDetails
===
tx
.
from
const
txType
=
'unknown'
+
(
tx
.
isCall
?
'Call'
:
'Tx'
)
return
(
<
span
id=
{
`tx${tx.hash}`
}
key=
{
index
}
>
<
div
className=
"log"
onClick=
{
(
event
)
=>
txDetails
(
event
,
tx
,
obj
)
}
>
{
/* onClick={e => txDetails(e, tx, data, obj)} */
}
{
checkTxStatus
(
receipt
||
tx
,
txType
)
}
{
context
({
from
,
to
,
tx
},
props
.
blockchain
)
}
<
div
className=
'buttons'
>
<
div
className=
'debug btn btn-primary btn-sm'
onClick=
{
(
event
)
=>
debug
(
event
,
tx
)
}
>
Debug
</
div
>
</
div
>
<
i
className
=
{`
arrow
fas
$
{(
showDetails
)
?
'
fa
-
angle
-
up
'
:
'
fa
-
angle
-
down
'}`}
></
i
>
</
div
>
{
showTableDetails
?
showTable
({
hash
:
tx
.
hash
,
status
:
receipt
!==
null
?
receipt
.
status
:
null
,
isCall
:
tx
.
isCall
,
contractAddress
:
tx
.
contractAddress
,
data
:
tx
,
from
,
to
,
gas
:
tx
.
gas
,
input
:
tx
.
input
,
'decoded input'
:
tx
.
resolvedData
&&
tx
.
resolvedData
.
params
?
JSON
.
stringify
(
typeConversion
.
stringify
(
tx
.
resoparams
),
null
,
'
\
t'
)
:
' - '
,
'decoded output'
:
tx
.
resolvedData
&&
tx
.
resolvedData
.
decodedReturnValue
?
JSON
.
stringify
(
typeConversion
.
stringify
(
tx
.
resolvedData
.
decodedReturnValue
),
null
,
'
\
t'
)
:
' - '
,
logs
:
tx
.
logs
,
val
:
tx
.
value
,
transactionCost
:
tx
.
transactionCost
,
executionCost
:
tx
.
executionCost
})
:
null
}
</
span
>
)
}
const
handleAutoComplete
=
()
=>
(
<
div
className=
"popup alert alert-secondary"
>
<
div
className=
'popup alert alert-secondary'
style=
{
{
display
:
autoCompletState
.
showSuggestions
&&
autoCompletState
.
userInput
!==
''
?
'block'
:
'none'
}
}
>
<
div
>
$
{
autoCompletState
.
data
.
_options
.
map
((
item
,
index
)
=>
{
{
autoCompletState
.
data
.
_options
.
map
((
item
,
index
)
=>
{
return
(
<
div
key=
{
index
}
>
auto complete here
</
div
>
// <div data-id="autoCompletePopUpAutoCompleteItem" className=
{
`autoCompleteItem listHandlerHide item ${_selectedElement === index ? 'border border-primary' : ''}`
}
>
// <div value=
{
index
}
onClick
=
{(
event
)
=>
{
handleSelect
(
event
.
srcElement
.
innerText
)
}}
>
//
{
getKeyOf
(
item
)}
// </div>
// <div>
//
{
getValueOf
(
item
)}
// </div>
// </div>
<
div
key=
{
index
}
data
-
id=
"autoCompletePopUpAutoCompleteItem"
className=
{
`autoCompleteItem listHandlerShow item ${autoCompletState.data._options[autoCompletState.activeSuggestion] === item ? 'border border-primary selectedOptions' : ''}`
}
onKeyDown=
{
handleSelect
}
>
<
div
>
{
getKeyOf
(
item
)
}
</
div
>
<
div
>
{
getValueOf
(
item
)
}
</
div
>
</
div
>
)
})
}
</
div
>
{
/* <div className="listHandlerHide">
<div className="pageNumberAlignment">Page ${(self._startingElement / self._elementsToShow) + 1} of ${Math.ceil(data._options.length / self._elementsToShow)}</div>
</div> */
}
</
div
>
)
/* end of autoComplete */
return
(
<
div
style=
{
{
height
:
'323px'
}
}
className=
'panel_2A0YE0'
>
<
div
style=
{
{
height
:
'323px'
,
flexGrow
:
1
}
}
className=
'panel_2A0YE0'
>
{
console
.
log
({
newstate
})
}
{
console
.
log
({
props
})
}
{
console
.
log
({
autoCompletState
})
}
<
div
className=
"bar_2A0YE0"
>
{
/* ${self._view.dragbar} */
}
<
div
className=
"dragbarHorizontal"
onMouseDown=
{
mousedown
}
id=
'dragId'
></
div
>
<
div
className=
"menu_2A0YE0 border-top border-dark bg-light"
data
-
id=
"terminalToggleMenu"
>
{
/* ${self._view.icon} */
}
<
i
className=
{
`mx-2 toggleTerminal_2A0YE0 fas ${toggleDownUp}`
}
data
-
id=
"terminalToggleIcon"
onClick=
{
handleMinimizeTerminal
}
></
i
>
<
div
className=
"mx-2
"
id=
"clearConsole"
data
-
id=
"terminalClearConsole"
>
<
div
className=
"mx-2
console"
id=
"clearConsole"
data
-
id=
"terminalClearConsole"
onClick=
{
handleClearConsole
}
>
<
i
className=
"fas fa-ban"
aria
-
hidden=
"true"
title=
"Clear console"
></
i
>
</
div
>
...
...
@@ -537,7 +903,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
<
input
className=
"custom-control-input"
id=
"listenNetworkCheck"
// onChange=$
{listenOnNetwork}
onChange=
{
listenOnNetwork
}
type=
"checkbox"
title=
"If checked Remix will listen on all transactions mined in the current environment and not only transactions created by you"
/>
...
...
@@ -554,6 +920,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
{
/* ${self._view.inputSearch} */
}
<
input
// spellcheck = "false"
onChange=
{
(
event
)
=>
setSearchInput
(
event
.
target
.
value
)
}
type=
"text"
className=
"border filter_2A0YE0 form-control"
id=
"searchInput"
...
...
@@ -565,7 +932,7 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
</
div
>
<
div
tabIndex=
{
-
1
}
className=
"terminal_container_2A0YE0"
data
-
id=
"terminalContainer"
>
{
(
autoCompletState
.
showSuggestions
&&
autoCompletState
.
userInput
)
&&
handleAutoComplete
()
handleAutoComplete
()
}
<
div
data
-
id=
"terminalContainerDisplay"
style
=
{{
position
:
'
absolute
',
...
...
@@ -576,11 +943,26 @@ export const RemixUiTerminal = (props: RemixUiTerminalProps) => {
}}
></
div
>
<
div
className=
"terminal_2A0YE0"
>
<
div
id=
"journal"
className=
"journal_2A0YE0"
data
-
id=
"terminalJournal"
>
{
(
newstate
.
journalBlocks
).
map
((
x
,
index
)
=>
(
<
div
className=
"px-4 block_2A0YE0"
data
-
id=
"block_null"
key=
{
index
}
>
<
span
className=
{
x
.
style
}
>
{
x
.
message
}
</
span
>
</
div
>
))
}
{
newstate
.
journalBlocks
&&
newstate
.
journalBlocks
.
map
((
x
,
index
)
=>
{
if
(
x
.
name
===
'emptyBlock'
)
{
return
(
<
div
className=
"px-4 block_2A0YE0"
data
-
id=
"block_null"
key=
{
index
}
>
<
span
className=
'txLog'
>
<
span
className=
'tx'
><
div
className=
'txItem'
>
[
<
span
className=
'txItemTitle'
>
block:
{
x
.
message
}
-
</
span
>
0
{
'transactions'
}
]
</
div
></
span
></
span
>
</
div
>
)
}
else
if
(
x
.
name
===
'unknownTransaction'
||
x
.
name
===
'knownTransaction'
)
{
return
x
.
message
.
filter
(
x
=>
x
.
tx
.
hash
.
includes
(
searchInput
)
||
x
.
tx
.
from
.
includes
(
searchInput
)
||
x
.
tx
.
to
.
includes
(
searchInput
)).
map
((
trans
)
=>
{
return
(<
div
className=
'px-4 block_2A0YE0'
data
-
id=
{
`block_tx${trans.tx.hash}`
}
>
{
renderKnownTransactions
(
trans
.
tx
,
trans
.
receipt
,
index
)
}
</
div
>)
})
}
else
{
return
(
<
div
className=
"px-4 block_2A0YE0"
data
-
id=
"block_null"
key=
{
index
}
>
<
span
className=
{
x
.
style
}
>
{
x
.
message
}
</
span
>
</
div
>
)
}
})
}
<
div
className=
"anchor"
>
{
/* ${background} */
}
<
div
className=
"overlay background"
></
div
>
...
...
libs/remix-ui/terminal/src/lib/utils/helper.ts
0 → 100644
View file @
b56c1c80
// var async = require('async')
// const ethJSUtil = require('ethereumjs-util')
// export const shortenAddress = (address, etherBalance) => {
// var len = address.length
// return address.slice(0, 5) + '...' + address.slice(len - 5, len) + (etherBalance ? ' (' + etherBalance.toString() + ' ether)' : '')
// }
// export const addressToString = (address) => {
// if (!address) return null
// if (typeof address !== 'string') {
// address = address.toString('hex')
// }
// if (address.indexOf('0x') === -1) {
// address = '0x' + address
// }
// return ethJSUtil.toChecksumAddress(address)
// }
// export const shortenHexData = (data) => {
// if (!data) return ''
// if (data.length < 5) return data
// var len = data.length
// return data.slice(0, 5) + '...' + data.slice(len - 5, len)
// }
// export const createNonClashingNameWithPrefix = (name, fileProvider, prefix, cb) => {
// if (!name) name = 'Undefined'
// var counter = ''
// var ext = 'sol'
// var reg = /(.*)\.([^.]+)/g
// var split = reg.exec(name)
// if (split) {
// name = split[1]
// ext = split[2]
// }
// var exist = true
// async.whilst(
// () => { return exist },
// (callback) => {
// fileProvider.exists(name + counter + prefix + '.' + ext).then(currentExist => {
// exist = currentExist
// if (exist) counter = (counter | 0) + 1
// callback()
// }).catch(error => {
// if (error) console.log(error)
// })
// },
// (error) => { cb(error, name + counter + prefix + '.' + ext) }
// )
// }
// export const createNonClashingName = (name, fileProvider, cb) => {
// this.createNonClashingNameWithPrefix(name, fileProvider, '', cb)
// },
// export const createNonClashingNameAsync = async (name, fileManager, prefix = '') => {
// if (!name) name = 'Undefined'
// let counter = ''
// let ext = 'sol'
// const reg = /(.*)\.([^.]+)/g
// const split = reg.exec(name)
// if (split) {
// name = split[1]
// ext = split[2]
// }
// let exist = true
// do {
// const isDuplicate = await fileManager.exists(name + counter + prefix + '.' + ext)
// if (isDuplicate) counter = (counter | 0) + 1
// else exist = false
// } while (exist)
// return name + counter + prefix + '.' + ext
// }
// export const createNonClashingDirNameAsync = async (name, fileManager) => {
// if (!name) name = 'Undefined'
// let counter = ''
// let exist = true
// do {
// const isDuplicate = await fileManager.exists(name + counter)
// if (isDuplicate) counter = (counter | 0) + 1
// else exist = false
// } while (exist)
// return name + counter
// }
// export const checkSpecialChars = (name) => {
// return name.match(/[:*?"<>\\'|]/) != null
// }
// export const checkSlash = (name) => {
// return name.match(/\//) != null
// }
// export const isHexadecimal = (value) => {
// return /^[0-9a-fA-F]+$/.test(value) && (value.length % 2 === 0)
// }
// export const is0XPrefixed = (value) => {
// return value.substr(0, 2) === '0x'
// }
// export const isNumeric = (value) => {
// return /^\+?(0|[1-9]\d*)$/.test(value)
// }
// export const isValidHash = (hash) => { // 0x prefixed, hexadecimal, 64digit
// const hexValue = hash.slice(2, hash.length)
// return this.is0XPrefixed(hash) && /^[0-9a-fA-F]{64}$/.test(hexValue)
// }
// export const removeTrailingSlashes = (text) {
// // Remove single or consecutive trailing slashes
// return text.replace(/\/+$/g, '')
// },
// removeMultipleSlashes (text) {
// // Replace consecutive slashes with '/'
// return text.replace(/\/+/g, '/')
// },
// find: find,
// getPathIcon (path) {
// return path.endsWith('.txt')
// ? 'far fa-file-alt' : path.endsWith('.md')
// ? 'far fa-file-alt' : path.endsWith('.sol')
// ? 'fak fa-solidity-mono' : path.endsWith('.js')
// ? 'fab fa-js' : path.endsWith('.json')
// ? 'fas fa-brackets-curly' : path.endsWith('.vy')
// ? 'fak fa-vyper-mono' : path.endsWith('.lex')
// ? 'fak fa-lexon' : path.endsWith('.contract')
// ? 'fab fa-ethereum' : 'far fa-file'
// },
// joinPath (...paths) {
// paths = paths.filter((value) => value !== '').map((path) => path.replace(/^\/|\/$/g, '')) // remove first and last slash)
// if (paths.length === 1) return paths[0]
// return paths.join('/')
// },
// extractNameFromKey (key) {
// const keyPath = key.split('/')
// return keyPath[keyPath.length - 1]
// }
// const 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 (el && el.innerText !== undefined && el.innerText !== null) el = el.innerText
// if (fn(el, i, object)) {
// found.value = el
// found.break = true
// break
// } else {
// findDeep(el, fn, found)
// }
// }
// return found.value
// }
// const find = (args, query) => {
// 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
// var contains = String(value).indexOf(query.trim()) !== -1
// return contains
// })
// return isMatch
// }
libs/remix-ui/terminal/src/lib/utils/utils.ts
View file @
b56c1c80
...
...
@@ -6,3 +6,37 @@ export const getKeyOf = (item) => {
export
const
getValueOf
=
(
item
)
=>
{
return
Object
.
values
(
item
)[
0
]
}
export
const
Objectfilter
=
(
obj
:
any
,
filterValue
:
any
)
=>
obj
.
filter
((
item
:
any
)
=>
Object
.
keys
(
item
)[
0
].
indexOf
(
filterValue
)
>
-
1
)
export
const
matched
=
(
arr
,
value
)
=>
arr
.
map
(
x
=>
Object
.
keys
(
x
).
some
(
x
=>
x
.
startsWith
(
value
))).
some
(
x
=>
x
===
true
)
const
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
(
el
&&
el
.
innerText
!==
undefined
&&
el
.
innerText
!==
null
)
el
=
el
.
innerText
if
(
fn
(
el
,
i
,
object
))
{
found
.
value
=
el
found
.
break
=
true
break
}
else
{
findDeep
(
el
,
fn
,
found
)
}
}
return
found
.
value
}
export
const
find
=
(
args
,
query
)
=>
{
query
=
query
.
trim
()
var
isMatch
=
!!
findDeep
(
args
,
function
check
(
value
)
{
if
(
value
===
undefined
||
value
===
null
)
return
false
if
(
typeof
value
===
'function'
)
return
false
if
(
typeof
value
===
'object'
)
return
false
var
contains
=
String
(
value
).
indexOf
(
query
.
trim
())
!==
-
1
return
contains
})
return
isMatch
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment