parent
5b6c1444b3
commit
629bbaa821
@ -1,194 +0,0 @@ |
||||
'use strict' |
||||
import { sourceMappingDecoder } from '@remix-project/remix-debug' |
||||
import Registry from '../state/registry' |
||||
const yo = require('yo-yo') |
||||
|
||||
const css = require('./styles/contextView-styles') |
||||
|
||||
/* |
||||
Display information about the current focused code: |
||||
- if it's a reference, display information about the declaration |
||||
- jump to the declaration |
||||
- number of references |
||||
- rename declaration/references |
||||
*/ |
||||
class ContextView { |
||||
constructor (opts) { |
||||
this._components = {} |
||||
this._components.registry = Registry.getInstance() |
||||
this.contextualListener = opts.contextualListener |
||||
this.editor = opts.editor |
||||
this._deps = { |
||||
compilersArtefacts: this._components.registry.get('compilersartefacts').api, |
||||
offsetToLineColumnConverter: this._components.registry.get('offsettolinecolumnconverter').api, |
||||
config: this._components.registry.get('config').api, |
||||
fileManager: this._components.registry.get('filemanager').api |
||||
} |
||||
this._view = null |
||||
this._nodes = null |
||||
this._current = null |
||||
this.sourceMappingDecoder = sourceMappingDecoder |
||||
this.previousElement = null |
||||
this.contextualListener.event.register('contextChanged', nodes => { |
||||
this.show() |
||||
this._nodes = nodes |
||||
this.update() |
||||
}) |
||||
this.contextualListener.event.register('stopHighlighting', () => { |
||||
}) |
||||
} |
||||
|
||||
render () { |
||||
const view = yo` |
||||
<div class="${css.contextview} ${css.contextviewcontainer} bg-light text-dark border-0"> |
||||
<div class=${css.container}> |
||||
${this._renderTarget()} |
||||
</div> |
||||
</div>` |
||||
if (!this._view) { |
||||
this._view = view |
||||
} |
||||
return view |
||||
} |
||||
|
||||
hide () { |
||||
if (this._view) { |
||||
this._view.style.display = 'none' |
||||
} |
||||
} |
||||
|
||||
show () { |
||||
if (this._view) { |
||||
this._view.style.display = 'block' |
||||
} |
||||
} |
||||
|
||||
update () { |
||||
if (this._view) { |
||||
yo.update(this._view, this.render()) |
||||
} |
||||
} |
||||
|
||||
_renderTarget () { |
||||
let last |
||||
const previous = this._current |
||||
if (this._nodes && this._nodes.length) { |
||||
last = this._nodes[this._nodes.length - 1] |
||||
if (isDefinition(last)) { |
||||
this._current = last |
||||
} else { |
||||
const target = this.contextualListener.declarationOf(last) |
||||
if (target) { |
||||
this._current = target |
||||
} else { |
||||
this._current = null |
||||
} |
||||
} |
||||
} |
||||
if (!this._current || !previous || previous.id !== this._current.id || (this.previousElement && !this.previousElement.children.length)) { |
||||
this.previousElement = this._render(this._current, last) |
||||
} |
||||
return this.previousElement |
||||
} |
||||
|
||||
_jumpToInternal (position) { |
||||
const jumpToLine = (lineColumn) => { |
||||
if (lineColumn.start && lineColumn.start.line && lineColumn.start.column) { |
||||
this.editor.gotoLine(lineColumn.start.line, lineColumn.end.column + 1) |
||||
} |
||||
} |
||||
const lastCompilationResult = this._deps.compilersArtefacts.__last |
||||
if (lastCompilationResult && lastCompilationResult.languageversion.indexOf('soljson') === 0 && lastCompilationResult.data) { |
||||
const lineColumn = this._deps.offsetToLineColumnConverter.offsetToLineColumn( |
||||
position, |
||||
position.file, |
||||
lastCompilationResult.getSourceCode().sources, |
||||
lastCompilationResult.getAsts()) |
||||
const filename = lastCompilationResult.getSourceName(position.file) |
||||
// TODO: refactor with rendererAPI.errorClick
|
||||
if (filename !== this._deps.config.get('currentFile')) { |
||||
const provider = this._deps.fileManager.fileProviderOf(filename) |
||||
if (provider) { |
||||
provider.exists(filename).then(exist => { |
||||
this._deps.fileManager.open(filename) |
||||
jumpToLine(lineColumn) |
||||
}).catch(error => { |
||||
if (error) return console.log(error) |
||||
}) |
||||
} |
||||
} else { |
||||
jumpToLine(lineColumn) |
||||
} |
||||
} |
||||
} |
||||
|
||||
_render (node, nodeAtCursorPosition) { |
||||
if (!node) return yo`<div></div>` |
||||
let references = this.contextualListener.referencesOf(node) |
||||
const type = node.typeDescriptions && node.typeDescriptions.typeString ? node.typeDescriptions.typeString : node.nodeType |
||||
references = `${references ? references.length : '0'} reference(s)` |
||||
|
||||
let ref = 0 |
||||
const nodes = this.contextualListener.getActiveHighlights() |
||||
for (const k in nodes) { |
||||
if (nodeAtCursorPosition.id === nodes[k].nodeId) { |
||||
ref = k |
||||
break |
||||
} |
||||
} |
||||
|
||||
// JUMP BETWEEN REFERENCES
|
||||
const jump = (e) => { |
||||
e.target.dataset.action === 'next' ? ref++ : ref-- |
||||
if (ref < 0) ref = nodes.length - 1 |
||||
if (ref >= nodes.length) ref = 0 |
||||
this._jumpToInternal(nodes[ref].position) |
||||
} |
||||
|
||||
const jumpTo = () => { |
||||
if (node && node.src) { |
||||
const position = this.sourceMappingDecoder.decode(node.src) |
||||
if (position) { |
||||
this._jumpToInternal(position) |
||||
} |
||||
} |
||||
} |
||||
|
||||
const showGasEstimation = () => { |
||||
if (node.nodeType === 'FunctionDefinition') { |
||||
const result = this.contextualListener.gasEstimation(node) |
||||
const executionCost = ' Execution cost: ' + result.executionCost + ' gas' |
||||
const codeDepositCost = 'Code deposit cost: ' + result.codeDepositCost + ' gas' |
||||
const estimatedGas = result.codeDepositCost ? `${codeDepositCost}, ${executionCost}` : `${executionCost}` |
||||
return yo` |
||||
<div class=${css.gasEstimation}> |
||||
<i class="fas fa-gas-pump ${css.gasStationIcon}" title='Gas estimation'></i> |
||||
<span>${estimatedGas}</span> |
||||
</div> |
||||
` |
||||
} |
||||
} |
||||
|
||||
return yo` |
||||
<div class=${css.line}>${showGasEstimation()} |
||||
<div title=${type} class=${css.type}>${type}</div> |
||||
<div title=${node.name} class=${css.name}>${node.name}</div> |
||||
<i class="fas fa-share ${css.jump}" aria-hidden="true" onclick=${jumpTo}></i> |
||||
<span class=${css.referencesnb}>${references}</span> |
||||
<i data-action='previous' class="fas fa-chevron-up ${css.jump}" aria-hidden="true" onclick=${jump}></i> |
||||
<i data-action='next' class="fas fa-chevron-down ${css.jump}" aria-hidden="true" onclick=${jump}></i> |
||||
</div> |
||||
` |
||||
} |
||||
} |
||||
|
||||
function isDefinition (node) { |
||||
return node.nodeType === 'ContractDefinition' || |
||||
node.nodeType === 'FunctionDefinition' || |
||||
node.nodeType === 'ModifierDefinition' || |
||||
node.nodeType === 'VariableDeclaration' || |
||||
node.nodeType === 'StructDefinition' || |
||||
node.nodeType === 'EventDefinition' |
||||
} |
||||
|
||||
module.exports = ContextView |
@ -1,70 +0,0 @@ |
||||
var yo = require('yo-yo') |
||||
var csjs = require('csjs-inject') |
||||
var EventManager = require('../../lib/events') |
||||
|
||||
module.exports = class Card { |
||||
constructor (api, events, opts) { |
||||
const self = this |
||||
self._api = api |
||||
self._events = events |
||||
self._opts = opts |
||||
self._view = {} |
||||
self.event = new EventManager() |
||||
} |
||||
|
||||
render () { |
||||
const self = this |
||||
if (self._view.el) return self._view.el |
||||
|
||||
self._view.cardBody = yo`<div></div>` |
||||
self._view.arrow = yo`<i class="${css.arrow} fas fa-angle-down" onclick="${() => trigger(this)}"></i>` |
||||
|
||||
self._view.expandCollapseButton = yo` |
||||
<div>${self._view.arrow}</div>` |
||||
|
||||
self._view.statusBar = yo`<div>${self._opts.collapsedView}</div>` |
||||
self._view.cardHeader = yo` |
||||
<div class="d-flex justify-content-between align-items-center" onclick=${() => trigger(self._view.arrow)}> |
||||
<div class="pr-1 d-flex flex-row"> |
||||
<div>${self._opts.title}</div> |
||||
${self._view.statusBar} |
||||
</div> |
||||
<div>${self._view.expandCollapseButton}</div> |
||||
</div>` |
||||
|
||||
function trigger (el) { |
||||
var body = self._view.cardBody |
||||
var status = self._view.statusBar |
||||
if (el.classList) { |
||||
el.classList.toggle('fa-angle-up') |
||||
var arrow = el.classList.toggle('fa-angle-down') ? 'up' : 'down' |
||||
self.event.trigger('expandCollapseCard', [arrow, body, status]) |
||||
} |
||||
} |
||||
|
||||
// HTML
|
||||
self._view.el = yo` |
||||
<div class="${css.cardContainer} list-group-item border-0"> |
||||
${self._view.cardHeader} |
||||
${self._view.cardBody} |
||||
</div>` |
||||
|
||||
return self._view.el |
||||
} |
||||
} |
||||
|
||||
const css = csjs` |
||||
.cardContainer { |
||||
padding : 0 24px 16px; |
||||
margin : 0; |
||||
background : none; |
||||
} |
||||
.arrow { |
||||
font-weight : bold; |
||||
cursor : pointer; |
||||
font-size : 14px; |
||||
} |
||||
.arrow:hover { |
||||
} |
||||
|
||||
` |
@ -1,83 +0,0 @@ |
||||
var yo = require('yo-yo') |
||||
// -------------- copyToClipboard ----------------------
|
||||
var csjs = require('csjs-inject') |
||||
|
||||
var css = csjs` |
||||
.container |
||||
{ |
||||
display: none; |
||||
position: fixed; |
||||
border-radius: 2px; |
||||
z-index: 1000; |
||||
box-shadow: 0 0 4px var(--dark); |
||||
} |
||||
.liitem |
||||
{ |
||||
padding: 2px; |
||||
padding-left: 6px; |
||||
cursor: pointer; |
||||
color: var(--text-dark); |
||||
background-color: var(--light); |
||||
} |
||||
.liitem:hover |
||||
{ |
||||
background-color: var(--secondary); |
||||
} |
||||
#menuitems |
||||
{ |
||||
list-style: none; |
||||
margin: 0px; |
||||
} |
||||
` |
||||
|
||||
module.exports = (event, items, linkItems) => { |
||||
event.preventDefault() |
||||
|
||||
function hide (event, force) { |
||||
if (container && container.parentElement && (force || (event.target !== container))) { |
||||
container.parentElement.removeChild(container) |
||||
} |
||||
window.removeEventListener('click', hide) |
||||
} |
||||
|
||||
const menu = Object.keys(items).map((item, index) => { |
||||
const current = yo`<li id="menuitem${item.toLowerCase()}" class=${css.liitem}>${item}</li>` |
||||
current.onclick = () => { hide(null, true); items[item]() } |
||||
return current |
||||
}) |
||||
|
||||
let menuForLinks = yo`` |
||||
if (linkItems) { |
||||
menuForLinks = Object.keys(linkItems).map((item, index) => { |
||||
const current = yo`<li id="menuitem${item.toLowerCase()}" class=${css.liitem}><a href=${linkItems[item]} target="_blank">${item}</a></li>` |
||||
current.onclick = () => { hide(null, true) } |
||||
return current |
||||
}) |
||||
} |
||||
|
||||
const container = yo` |
||||
<div id="menuItemsContainer" class="p-1 ${css.container} bg-light shadow border"> |
||||
<ul id='menuitems'>${menu} ${menuForLinks}</ul> |
||||
</div> |
||||
` |
||||
|
||||
container.style.left = event.pageX + 'px' |
||||
container.style.top = event.pageY + 'px' |
||||
container.style.display = 'block' |
||||
document.querySelector('body').appendChild(container) |
||||
|
||||
const menuItemsContainer = document.getElementById('menuItemsContainer') |
||||
const boundary = menuItemsContainer.getBoundingClientRect() |
||||
|
||||
if (boundary.bottom > (window.innerHeight || document.documentElement.clientHeight)) { |
||||
menuItemsContainer.style.position = 'absolute' |
||||
menuItemsContainer.style.bottom = '10px' |
||||
menuItemsContainer.style.top = null |
||||
} |
||||
|
||||
setTimeout(() => { |
||||
window.addEventListener('click', hide) |
||||
}, 500) |
||||
|
||||
return { hide } |
||||
} |
@ -1,39 +0,0 @@ |
||||
var yo = require('yo-yo') |
||||
// -------------- copyToClipboard ----------------------
|
||||
const copy = require('copy-to-clipboard') |
||||
var addTooltip = require('./tooltip') |
||||
// -------------- styling ----------------------
|
||||
var csjs = require('csjs-inject') |
||||
|
||||
var css = csjs` |
||||
.copyIcon { |
||||
margin-left: 5px; |
||||
cursor: pointer; |
||||
} |
||||
` |
||||
|
||||
module.exports = function copyToClipboard (getContent, tip = 'Copy value to clipboard', icon = 'fa-copy') { |
||||
var copyIcon = yo`<i title="${tip}" class="${css.copyIcon} far ${icon} p-2" data-id="copyToClipboardCopyIcon" aria-hidden="true"></i>` |
||||
copyIcon.onclick = (event) => { |
||||
event.stopPropagation() |
||||
var copiableContent |
||||
try { |
||||
copiableContent = getContent() |
||||
} catch (e) { |
||||
addTooltip(e.message) |
||||
return |
||||
} |
||||
if (copiableContent) { // module `copy` keeps last copied thing in the memory, so don't show tooltip if nothing is copied, because nothing was added to memory
|
||||
try { |
||||
if (typeof copiableContent !== 'string') { |
||||
copiableContent = JSON.stringify(copiableContent, null, '\t') |
||||
} |
||||
} catch (e) {} |
||||
copy(copiableContent) |
||||
addTooltip('Copied value to clipboard.') |
||||
} else { |
||||
addTooltip('Cannot copy empty content!') |
||||
} |
||||
} |
||||
return copyIcon |
||||
} |
@ -1,131 +0,0 @@ |
||||
'use strict' |
||||
var yo = require('yo-yo') |
||||
var csjs = require('csjs-inject') |
||||
|
||||
var css = csjs` |
||||
.containerDraggableModal { |
||||
position: absolute; |
||||
z-index: 1000; |
||||
text-align: center; |
||||
width: 500px; |
||||
height: 500px; |
||||
overflow-y: hidden; |
||||
} |
||||
|
||||
.headerDraggableModal { |
||||
cursor: move; |
||||
z-index: 10; |
||||
text-overflow: ellipsis; |
||||
overflow-x: hidden; |
||||
} |
||||
|
||||
.modalActions { |
||||
float: right; |
||||
} |
||||
|
||||
.modalAction { |
||||
padding-right: 1px; |
||||
padding-left: 1px; |
||||
cursor: pointer; |
||||
} |
||||
` |
||||
|
||||
module.exports = |
||||
class DraggableContent { |
||||
constructor (closeCb) { |
||||
this.closeCb = closeCb |
||||
this.isMaximised = false |
||||
} |
||||
|
||||
render (title, url, content) { |
||||
this.content = content |
||||
var el = yo` |
||||
<div class=${css.containerDraggableModal}> |
||||
<div> |
||||
<div class="${css.headerDraggableModal} title" title=${title}><span title="${title}" >${title}</span><span title="${url}" > - ${url}</span> |
||||
<div class=${css.modalActions}> |
||||
<i onclick=${() => { this.minimize() }} class="fas fa-window-minimize ${css.modalAction}"></i> |
||||
<i onclick=${() => { this.maximise() }} class="fas fa-window-maximize ${css.modalAction}"></i> |
||||
<i onclick=${() => { this.close() }} class="fas fa-window-close-o ${css.modalAction}"></i> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
${content} |
||||
</div> ` |
||||
dragElement(el) |
||||
el.style.top = '20%' |
||||
el.style.left = '50%' |
||||
this.el = el |
||||
return el |
||||
} |
||||
|
||||
setTitle (title) { |
||||
this.el.querySelector('.title span').innerHTML = title |
||||
} |
||||
|
||||
minimize () { |
||||
this.isMaximised = false |
||||
this.content.style.display = 'none' |
||||
this.el.style.height = 'inherit' |
||||
this.el.style.width = '150px' |
||||
this.el.querySelector('.title').style.width = '146px' |
||||
} |
||||
|
||||
maximise () { |
||||
this.content.style.display = 'block' |
||||
var body = document.querySelector('body') |
||||
this.el.style.height = this.isMaximised ? '500px' : body.offsetHeight + 'px' |
||||
this.el.style.width = this.isMaximised ? '500px' : body.offsetWidth + 'px' |
||||
this.isMaximised = !this.isMaximised |
||||
this.el.style.top = this.isMaximised ? '0%' : '20%' |
||||
this.el.style.left = this.isMaximised ? '0%' : '50%' |
||||
this.el.querySelector('.title').style.width = 'inherit' |
||||
} |
||||
|
||||
close () { |
||||
if (this.closeCb) this.closeCb() |
||||
if (this.el.parentElement) { |
||||
this.el.parentElement.removeChild(this.el) |
||||
} |
||||
} |
||||
} |
||||
|
||||
function dragElement (elmnt) { |
||||
var pos1 = 0 |
||||
var pos2 = 0 |
||||
var pos3 = 0 |
||||
var pos4 = 0 |
||||
|
||||
elmnt.querySelector('.title').onmousedown = dragMouseDown |
||||
|
||||
function dragMouseDown (e) { |
||||
e = e || window.event |
||||
if (e.button !== 0) return |
||||
e.preventDefault() |
||||
// get the mouse cursor position at startup:
|
||||
pos3 = e.clientX |
||||
pos4 = e.clientY |
||||
document.onmouseup = closeDragElement |
||||
// call a function whenever the cursor moves:
|
||||
document.onmousemove = elementDrag |
||||
} |
||||
|
||||
function elementDrag (e) { |
||||
e = e || window.event |
||||
e.preventDefault() |
||||
// calculate the new cursor position:
|
||||
pos1 = pos3 - e.clientX |
||||
pos2 = pos4 - e.clientY |
||||
pos3 = e.clientX |
||||
pos4 = e.clientY |
||||
// set the element's new position:
|
||||
elmnt.style.top = (elmnt.offsetTop - pos2) + 'px' |
||||
elmnt.style.left = (elmnt.offsetLeft - pos1) + 'px' |
||||
} |
||||
|
||||
function closeDragElement () { |
||||
/* stop moving when mouse button is released: */ |
||||
document.onmouseup = null |
||||
document.onmousemove = null |
||||
} |
||||
} |
@ -1,128 +0,0 @@ |
||||
var yo = require('yo-yo') |
||||
var EventManager = require('../../lib/events') |
||||
|
||||
// -------------- styling ----------------------
|
||||
|
||||
var css = require('./styles/dropdown-styles') |
||||
|
||||
/* USAGE: |
||||
|
||||
var dropdown = new Dropdown({ |
||||
options: [ |
||||
'knownTransaction', |
||||
'unknownTransaction', |
||||
'log', |
||||
'info', |
||||
'error' |
||||
], |
||||
defaults: ['knownTransaction'] |
||||
}) |
||||
dropdown.event.register('deselect', function (label) { }) |
||||
dropdown.event.register('select', function (label) { }) |
||||
|
||||
*/ |
||||
class Dropdown { |
||||
constructor (opts = {}) { |
||||
var self = this |
||||
self.event = new EventManager() |
||||
self.data = { |
||||
_options: opts.options || [], |
||||
_dependencies: opts.dependencies || [], |
||||
selected: opts.defaults || [], |
||||
_elements: [] |
||||
} |
||||
self._view = {} |
||||
self._api = opts.api |
||||
self._events = opts.events |
||||
} |
||||
|
||||
render () { |
||||
var self = this |
||||
if (self._view.el) return self._view.el |
||||
self._view.selected = yo` |
||||
<div class=${css.selectbox}> |
||||
<span class=${css.selected}> [${self.data.selected.length}] ${self.data.selected.join(', ')}</span> |
||||
<i class="${css.icon} fas fa-caret-down"></i> |
||||
</div> |
||||
` |
||||
self._view.el = yo` |
||||
<div name="dropdown" class="${css.dropdown} form-control form-control-sm" onclick=${show}> |
||||
${self._view.selected} |
||||
<div class="${css.options} bg-light" style="display: none;}"> |
||||
${self.data._options.map(label => { |
||||
const index = self.data._elements.length |
||||
var input = yo` |
||||
<input |
||||
data-idx=${index} |
||||
onchange=${emit} |
||||
type="${index === 2 ? 'checkbox' : 'radio'}" |
||||
id="${label}" |
||||
/> |
||||
` |
||||
if (self.data.selected.indexOf(label) !== -1) { |
||||
input.checked = true |
||||
self.event.trigger('select', [label]) |
||||
} |
||||
self.data._elements.push(input) |
||||
return yo` |
||||
<div class=${css.option}> |
||||
${input} |
||||
<label class="text-dark" for="${label}">${label}</label> |
||||
</div> |
||||
` |
||||
})} |
||||
</div> |
||||
</div> |
||||
` |
||||
return self._view.el |
||||
function emit (event) { |
||||
var input = event.currentTarget |
||||
var label = input.nextSibling.innerText |
||||
if (input.checked) { |
||||
self.data.selected.push(label) |
||||
if (event.type === 'change') { |
||||
self.event.trigger('select', [label]) |
||||
updateDependencies(label) |
||||
} |
||||
} else { |
||||
var idx = self.data.selected.indexOf(label) |
||||
self.data.selected.splice(idx, 1) |
||||
if (event.type === 'change') { |
||||
self.event.trigger('deselect', [label]) |
||||
updateDependencies(label) |
||||
} |
||||
} |
||||
self._view.selected.children[0].innerText = `[${self.data.selected.length}] ${self.data.selected.join(', ')}` |
||||
} |
||||
function updateDependencies (changed) { |
||||
if (self.data._dependencies[changed]) { |
||||
for (var dep in self.data._dependencies[changed]) { |
||||
var label = self.data._dependencies[changed][dep] |
||||
var el = self.data._elements[self.data._options.indexOf(label)] |
||||
el.checked = !el.checked |
||||
emit({ currentTarget: el, type: 'changeDependencies' }) |
||||
} |
||||
} |
||||
} |
||||
function show (event) { |
||||
event.stopPropagation() |
||||
var options = event.currentTarget.children[1] |
||||
var parent = event.target.parentElement |
||||
var isOption = parent === options || parent.parentElement === options |
||||
if (isOption) return |
||||
if (options.style.display === 'none') { |
||||
options.style.display = '' |
||||
document.body.addEventListener('click', handler) |
||||
} else { |
||||
options.style.display = 'none' |
||||
document.body.removeEventListener('click', handler) |
||||
} |
||||
function handler (event) { |
||||
options.style.display = 'none' |
||||
document.body.removeEventListener('click', handler) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
module.exports = Dropdown |
@ -1,153 +0,0 @@ |
||||
'use strict' |
||||
|
||||
var $ = require('jquery') |
||||
var yo = require('yo-yo') |
||||
const { default: Registry } = require('../state/registry') |
||||
var css = require('./styles/renderer-styles') |
||||
|
||||
/** |
||||
* After refactor, the renderer is only used to render error/warning |
||||
* TODO: This don't need to be an object anymore. Simplify and just export the renderError function. |
||||
* |
||||
*/ |
||||
function Renderer (service) { |
||||
const self = this |
||||
self.service = service |
||||
self._components = {} |
||||
self._components.registry = Registry.getInstance() |
||||
// dependencies
|
||||
self._deps = { |
||||
fileManager: self._components.registry.get('filemanager').api, |
||||
config: self._components.registry.get('config').api |
||||
} |
||||
if (document && document.head) { |
||||
document.head.appendChild(css) |
||||
} |
||||
} |
||||
|
||||
Renderer.prototype._error = function (file, error) { |
||||
const self = this |
||||
if (file === self._deps.config.get('currentFile')) { |
||||
self.service.call('editor', 'addAnnotation', error, file) |
||||
} |
||||
} |
||||
|
||||
Renderer.prototype._errorClick = function (errFile, errLine, errCol) { |
||||
const self = this |
||||
const editor = self._components.registry.get('editor').api |
||||
if (errFile !== self._deps.config.get('currentFile')) { |
||||
// TODO: refactor with this._components.contextView.jumpTo
|
||||
var provider = self._deps.fileManager.fileProviderOf(errFile) |
||||
if (provider) { |
||||
provider.exists(errFile).then(exist => { |
||||
self._deps.fileManager.open(errFile) |
||||
editor.gotoLine(errLine, errCol) |
||||
}).catch(error => { |
||||
if (error) return console.log(error) |
||||
}) |
||||
} |
||||
} else { |
||||
editor.gotoLine(errLine, errCol) |
||||
} |
||||
} |
||||
|
||||
function getPositionDetails (msg) { |
||||
const result = {} |
||||
|
||||
// To handle some compiler warning without location like SPDX license warning etc
|
||||
if (!msg.includes(':')) return { errLine: -1, errCol: -1, errFile: msg } |
||||
|
||||
// extract line / column
|
||||
let position = msg.match(/^(.*?):([0-9]*?):([0-9]*?)?/) |
||||
result.errLine = position ? parseInt(position[2]) - 1 : -1 |
||||
result.errCol = position ? parseInt(position[3]) : -1 |
||||
|
||||
// extract file
|
||||
position = msg.match(/^(https:.*?|http:.*?|.*?):/) |
||||
result.errFile = position ? position[1] : '' |
||||
return result |
||||
} |
||||
|
||||
/** |
||||
* format msg like error or warning, |
||||
* |
||||
* @param {String or DOMElement} message |
||||
* @param {DOMElement} container |
||||
* @param {Object} options { |
||||
* useSpan, |
||||
* noAnnotations, |
||||
* click:(Function), |
||||
* type:( |
||||
* warning, |
||||
* error |
||||
* ), |
||||
* errFile, |
||||
* errLine, |
||||
* errCol |
||||
* } |
||||
*/ |
||||
|
||||
Renderer.prototype.error = function (message, container, opt) { |
||||
if (!message) return |
||||
if (container === undefined) return |
||||
opt = opt || {} |
||||
|
||||
var text |
||||
if (typeof message === 'string') { |
||||
text = message |
||||
message = yo`<span>${message}</span>` |
||||
} else if (message.innerText) { |
||||
text = message.innerText |
||||
} |
||||
|
||||
// ^ e.g:
|
||||
// browser/gm.sol: Warning: Source file does not specify required compiler version! Consider adding "pragma solidity ^0.6.12
|
||||
// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.2.0/contracts/introspection/IERC1820Registry.sol:3:1: ParserError: Source file requires different compiler version (current compiler is 0.7.4+commit.3f05b770.Emscripten.clang) - note that nightly builds are considered to be strictly less than the released version
|
||||
|
||||
let position = getPositionDetails(text) |
||||
|
||||
// For compiler version 0.8.0 and upcoming versions, errors and warning will be reported in a different way
|
||||
// Above method regex will return type of error as 'errFile'
|
||||
// Comparison of 'errFile' with passed error type will ensure the reporter type
|
||||
if (!position.errFile || (opt.errorType && opt.errorType === position.errFile)) { |
||||
// Updated error reported includes '-->' before file details
|
||||
const errorDetails = text.split('-->') |
||||
// errorDetails[1] will have file details
|
||||
if (errorDetails.length > 1) position = getPositionDetails(errorDetails[1]) |
||||
} |
||||
|
||||
opt.errLine = position.errLine |
||||
opt.errCol = position.errCol |
||||
opt.errFile = position.errFile.trim() |
||||
|
||||
if (!opt.noAnnotations && opt.errFile) { |
||||
this._error(opt.errFile, { |
||||
row: opt.errLine, |
||||
column: opt.errCol, |
||||
text: text, |
||||
type: opt.type |
||||
}) |
||||
} |
||||
|
||||
var $pre = $(opt.useSpan ? yo`<span></span>` : yo`<pre></pre>`).html(message) |
||||
|
||||
const classList = opt.type === 'error' ? 'alert alert-danger' : 'alert alert-warning' |
||||
var $error = $(yo`<div class="sol ${opt.type} ${classList}" data-id="${opt.errFile}"><div class="close" data-id="renderer"><i class="fas fa-times"></i></div></div>`).prepend($pre) |
||||
$(container).append($error) |
||||
|
||||
$error.click((ev) => { |
||||
if (opt.click) { |
||||
opt.click(message) |
||||
} else if (opt.errFile !== undefined && opt.errLine !== undefined && opt.errCol !== undefined) { |
||||
this._errorClick(opt.errFile, opt.errLine, opt.errCol) |
||||
} |
||||
}) |
||||
|
||||
$error.find('.close').click(function (ev) { |
||||
ev.preventDefault() |
||||
$error.remove() |
||||
return false |
||||
}) |
||||
} |
||||
|
||||
module.exports = Renderer |
@ -1,52 +0,0 @@ |
||||
var yo = require('yo-yo') |
||||
|
||||
var css = yo`<style>
|
||||
.sol.success, |
||||
.sol.error, |
||||
.sol.warning { |
||||
white-space: pre-line; |
||||
word-wrap: break-word; |
||||
cursor: pointer; |
||||
position: relative; |
||||
margin: 0.5em 0 1em 0; |
||||
border-radius: 5px; |
||||
line-height: 20px; |
||||
padding: 8px 15px; |
||||
} |
||||
|
||||
.sol.success pre, |
||||
.sol.error pre, |
||||
.sol.warning pre { |
||||
white-space: pre-line; |
||||
overflow-y: hidden; |
||||
background-color: transparent; |
||||
margin: 0; |
||||
font-size: 12px; |
||||
border: 0 none; |
||||
padding: 0; |
||||
border-radius: 0; |
||||
} |
||||
|
||||
.sol.success .close, |
||||
.sol.error .close, |
||||
.sol.warning .close { |
||||
white-space: pre-line; |
||||
font-weight: bold; |
||||
position: absolute; |
||||
color: hsl(0, 0%, 0%); /* black in style-guide.js */ |
||||
top: 0; |
||||
right: 0; |
||||
padding: 0.5em; |
||||
} |
||||
|
||||
.sol.error { |
||||
} |
||||
|
||||
.sol.warning { |
||||
} |
||||
|
||||
.sol.success { |
||||
/* background-color: // styles.rightPanel.message_Success_BackgroundColor; */ |
||||
}</style>` |
||||
|
||||
module.exports = css |
@ -1,590 +0,0 @@ |
||||
'use strict' |
||||
var yo = require('yo-yo') |
||||
var copyToClipboard = require('./copy-to-clipboard') |
||||
|
||||
// -------------- styling ----------------------
|
||||
var csjs = require('csjs-inject') |
||||
var remixLib = require('@remix-project/remix-lib') |
||||
|
||||
var EventManager = require('../../lib/events') |
||||
var helper = require('../../lib/helper') |
||||
var modalDialog = require('./modal-dialog-custom') |
||||
const { default: Registry } = require('../state/registry') |
||||
|
||||
var typeConversion = remixLib.execution.typeConversion |
||||
|
||||
var css = csjs` |
||||
.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; |
||||
}` |
||||
/** |
||||
* This just export a function that register to `newTransaction` and forward them to the logger. |
||||
* |
||||
*/ |
||||
class TxLogger { |
||||
constructor (terminal, blockchain) { |
||||
this.event = new EventManager() |
||||
this.seen = {} |
||||
function filterTx (value, query) { |
||||
if (value.length) { |
||||
return helper.find(value, query) |
||||
} |
||||
return false |
||||
} |
||||
this.eventsDecoder = Registry.getInstance().get('eventsDecoder').api |
||||
this.txListener = Registry.getInstance().get('txlistener').api |
||||
this.terminal = terminal |
||||
// dependencies
|
||||
this._deps = { |
||||
compilersArtefacts: Registry.getInstance().get('compilersartefacts').api |
||||
} |
||||
|
||||
this.logKnownTX = this.terminal.registerCommand('knownTransaction', (args, cmds, append) => { |
||||
var data = args[0] |
||||
var el |
||||
if (data.tx.isCall) { |
||||
el = renderCall(this, data) |
||||
} else { |
||||
el = renderKnownTransaction(this, data, blockchain) |
||||
} |
||||
this.seen[data.tx.hash] = el |
||||
append(el) |
||||
}, { activate: true, filterFn: filterTx }) |
||||
|
||||
this.logUnknownTX = this.terminal.registerCommand('unknownTransaction', (args, cmds, append) => { |
||||
// triggered for transaction AND call
|
||||
var data = args[0] |
||||
var el = renderUnknownTransaction(this, data, blockchain) |
||||
append(el) |
||||
}, { activate: false, filterFn: filterTx }) |
||||
|
||||
this.logEmptyBlock = this.terminal.registerCommand('emptyBlock', (args, cmds, append) => { |
||||
var data = args[0] |
||||
var el = renderEmptyBlock(this, data) |
||||
append(el) |
||||
}, { activate: true }) |
||||
|
||||
this.txListener.event.register('newBlock', (block) => { |
||||
if (!block.transactions || (block.transactions && !block.transactions.length)) { |
||||
this.logEmptyBlock({ block: block }) |
||||
} |
||||
}) |
||||
|
||||
this.txListener.event.register('newTransaction', (tx, receipt) => { |
||||
log(this, tx, receipt) |
||||
}) |
||||
|
||||
this.txListener.event.register('newCall', (tx) => { |
||||
log(this, tx, null) |
||||
}) |
||||
|
||||
this.terminal.updateJournal({ type: 'select', value: 'unknownTransaction' }) |
||||
this.terminal.updateJournal({ type: 'select', value: 'knownTransaction' }) |
||||
} |
||||
} |
||||
|
||||
function debug (e, data, self) { |
||||
e.stopPropagation() |
||||
if (data.tx.isCall && data.tx.envMode !== 'vm') { |
||||
modalDialog.alert('Cannot debug this call. Debugging calls is only possible in JavaScript VM mode.') |
||||
} else { |
||||
self.event.trigger('debuggingRequested', [data.tx.hash]) |
||||
} |
||||
} |
||||
|
||||
function log (self, tx, receipt) { |
||||
var resolvedTransaction = self.txListener.resolvedTransaction(tx.hash) |
||||
if (resolvedTransaction) { |
||||
var compiledContracts = null |
||||
if (self._deps.compilersArtefacts.__last) { |
||||
compiledContracts = self._deps.compilersArtefacts.__last.getContracts() |
||||
} |
||||
self.eventsDecoder.parseLogs(tx, resolvedTransaction.contractName, compiledContracts, (error, logs) => { |
||||
if (!error) { |
||||
self.logKnownTX({ tx: tx, receipt: receipt, resolvedData: resolvedTransaction, logs: logs }) |
||||
} |
||||
}) |
||||
} else { |
||||
// contract unknown - just displaying raw tx.
|
||||
self.logUnknownTX({ tx: tx, receipt: receipt }) |
||||
} |
||||
} |
||||
|
||||
function renderKnownTransaction (self, data, blockchain) { |
||||
var from = data.tx.from |
||||
var to = data.resolvedData.contractName + '.' + data.resolvedData.fn |
||||
var obj = { from, to } |
||||
var txType = 'knownTx' |
||||
var tx = yo` |
||||
<span id="tx${data.tx.hash}" data-id="txLogger${data.tx.hash}"> |
||||
<div class="${css.log}" onclick=${e => txDetails(e, tx, data, obj)}> |
||||
${checkTxStatus(data.receipt, txType)} |
||||
${context(self, { from, to, data }, blockchain)} |
||||
<div class=${css.buttons}> |
||||
<button |
||||
class="${css.debug} btn btn-primary btn-sm" |
||||
data-shared="txLoggerDebugButton" |
||||
data-id="txLoggerDebugButton${data.tx.hash}" |
||||
onclick=${(e) => debug(e, data, self)} |
||||
> |
||||
Debug |
||||
</div> |
||||
</div> |
||||
<i class="${css.arrow} fas fa-angle-down"></i> |
||||
</div> |
||||
</span> |
||||
` |
||||
return tx |
||||
} |
||||
|
||||
function renderCall (self, data) { |
||||
var to = data.resolvedData.contractName + '.' + data.resolvedData.fn |
||||
var from = data.tx.from ? data.tx.from : ' - ' |
||||
var input = data.tx.input ? helper.shortenHexData(data.tx.input) : '' |
||||
var obj = { from, to } |
||||
var txType = 'call' |
||||
var tx = yo` |
||||
<span id="tx${data.tx.hash}"> |
||||
<div class="${css.log}" onclick=${e => txDetails(e, tx, data, obj)}> |
||||
${checkTxStatus(data.tx, txType)} |
||||
<span class=${css.txLog}> |
||||
<span class=${css.tx}>[call]</span> |
||||
<div class=${css.txItem}><span class=${css.txItemTitle}>from:</span> ${from}</div> |
||||
<div class=${css.txItem}><span class=${css.txItemTitle}>to:</span> ${to}</div> |
||||
<div class=${css.txItem}><span class=${css.txItemTitle}>data:</span> ${input}</div> |
||||
</span> |
||||
<div class=${css.buttons}> |
||||
<div class="${css.debug} btn btn-primary btn-sm" onclick=${(e) => debug(e, data, self)}>Debug</div> |
||||
</div> |
||||
<i class="${css.arrow} fas fa-angle-down"></i> |
||||
</div> |
||||
</span> |
||||
` |
||||
return tx |
||||
} |
||||
|
||||
function renderUnknownTransaction (self, data, blockchain) { |
||||
var from = data.tx.from |
||||
var to = data.tx.to |
||||
var obj = { from, to } |
||||
var txType = 'unknown' + (data.tx.isCall ? 'Call' : 'Tx') |
||||
var tx = yo` |
||||
<span id="tx${data.tx.hash}"> |
||||
<div class="${css.log}" onclick=${e => txDetails(e, tx, data, obj)}> |
||||
${checkTxStatus(data.receipt || data.tx, txType)} |
||||
${context(self, { from, to, data }, blockchain)} |
||||
<div class=${css.buttons}> |
||||
<div class="${css.debug} btn btn-primary btn-sm" onclick=${(e) => debug(e, data, self)}>Debug</div> |
||||
</div> |
||||
<i class="${css.arrow} fas fa-angle-down"></i> |
||||
</div> |
||||
</span> |
||||
` |
||||
return tx |
||||
} |
||||
|
||||
function renderEmptyBlock (self, data) { |
||||
return yo` |
||||
<span class=${css.txLog}> |
||||
<span class='${css.tx}'><div class=${css.txItem}>[<span class=${css.txItemTitle}>block:${data.block.number} - </span> 0 transactions]</span></span> |
||||
</span>` |
||||
} |
||||
|
||||
function checkTxStatus (tx, type) { |
||||
if (tx.status === '0x1' || tx.status === true) { |
||||
return yo`<i class="${css.txStatus} ${css.succeeded} fas fa-check-circle"></i>` |
||||
} |
||||
if (type === 'call' || type === 'unknownCall') { |
||||
return yo`<i class="${css.txStatus} ${css.call}">call</i>` |
||||
} else if (tx.status === '0x0' || tx.status === false) { |
||||
return yo`<i class="${css.txStatus} ${css.failed} fas fa-times-circle"></i>` |
||||
} else { |
||||
return yo`<i class="${css.txStatus} ${css.notavailable} fas fa-circle-thin" title='Status not available' ></i>` |
||||
} |
||||
} |
||||
|
||||
function context (self, opts, blockchain) { |
||||
var data = opts.data || '' |
||||
var from = opts.from ? helper.shortenHexData(opts.from) : '' |
||||
var to = opts.to |
||||
if (data.tx.to) to = to + ' ' + helper.shortenHexData(data.tx.to) |
||||
var val = data.tx.value |
||||
var hash = data.tx.hash ? helper.shortenHexData(data.tx.hash) : '' |
||||
var input = data.tx.input ? helper.shortenHexData(data.tx.input) : '' |
||||
var logs = data.logs && data.logs.decoded && data.logs.decoded.length ? data.logs.decoded.length : 0 |
||||
var block = data.receipt ? data.receipt.blockNumber : data.tx.blockNumber || '' |
||||
var i = data.receipt ? data.receipt.transactionIndex : data.tx.transactionIndex |
||||
var value = val ? typeConversion.toInt(val) : 0 |
||||
if (blockchain.getProvider() === 'vm') { |
||||
return yo` |
||||
<div> |
||||
<span class=${css.txLog}> |
||||
<span class=${css.tx}>[vm]</span> |
||||
<div class=${css.txItem}><span class=${css.txItemTitle}>from:</span> ${from}</div> |
||||
<div class=${css.txItem}><span class=${css.txItemTitle}>to:</span> ${to}</div> |
||||
<div class=${css.txItem}><span class=${css.txItemTitle}>value:</span> ${value} wei</div> |
||||
<div class=${css.txItem}><span class=${css.txItemTitle}>data:</span> ${input}</div> |
||||
<div class=${css.txItem}><span class=${css.txItemTitle}>logs:</span> ${logs}</div> |
||||
<div class=${css.txItem}><span class=${css.txItemTitle}>hash:</span> ${hash}</div> |
||||
</span> |
||||
</div>` |
||||
} else if (blockchain.getProvider() !== 'vm' && data.resolvedData) { |
||||
return yo` |
||||
<div> |
||||
<span class=${css.txLog}> |
||||
<span class='${css.tx}'>[block:${block} txIndex:${i}]</span> |
||||
<div class=${css.txItem}><span class=${css.txItemTitle}>from:</span> ${from}</div> |
||||
<div class=${css.txItem}><span class=${css.txItemTitle}>to:</span> ${to}</div> |
||||
<div class=${css.txItem}><span class=${css.txItemTitle}>value:</span> ${value} wei</div> |
||||
<div class=${css.txItem}><span class=${css.txItemTitle}>data:</span> ${input}</div> |
||||
<div class=${css.txItem}><span class=${css.txItemTitle}>logs:</span> ${logs}</div> |
||||
<div class=${css.txItem}><span class=${css.txItemTitle}>hash:</span> ${hash}</div> |
||||
</span> |
||||
</div>` |
||||
} else { |
||||
to = helper.shortenHexData(to) |
||||
hash = helper.shortenHexData(data.tx.blockHash) |
||||
return yo` |
||||
<div> |
||||
<span class=${css.txLog}> |
||||
<span class='${css.tx}'>[block:${block} txIndex:${i}]</span> |
||||
<div class=${css.txItem}><span class=${css.txItemTitle}>from:</span> ${from}</div> |
||||
<div class=${css.txItem}><span class=${css.txItemTitle}>to:</span> ${to}</div> |
||||
<div class=${css.txItem}><span class=${css.txItemTitle}>value:</span> ${value} wei</div> |
||||
</span> |
||||
</div>` |
||||
} |
||||
} |
||||
|
||||
module.exports = TxLogger |
||||
|
||||
// helpers
|
||||
|
||||
function isDescendant (parent, child) { |
||||
var node = child.parentNode |
||||
while (node != null) { |
||||
if (node === parent) { |
||||
return true |
||||
} |
||||
node = node.parentNode |
||||
} |
||||
return false |
||||
} |
||||
|
||||
function txDetails (e, tx, data, obj) { |
||||
const from = obj.from |
||||
const to = obj.to |
||||
const arrowUp = yo`<i class="${css.arrow} fas fa-angle-up"></i>` |
||||
const arrowDown = yo`<i class="${css.arrow} fas fa-angle-down"></i>` |
||||
|
||||
let blockElement = e.target |
||||
while (true) { // get the parent block element
|
||||
if (blockElement.className.startsWith('block')) break |
||||
else if (blockElement.parentElement) { |
||||
blockElement = blockElement.parentElement |
||||
} else break |
||||
} |
||||
|
||||
const tables = blockElement.querySelectorAll(`#${tx.id} [class^="txTable"]`) |
||||
const logs = blockElement.querySelectorAll(`#${tx.id} [class^='log']`) |
||||
const arrows = blockElement.querySelectorAll(`#${tx.id} [class^='arrow']`) |
||||
|
||||
let table = [...tables].filter((t) => isDescendant(tx, t))[0] |
||||
const log = [...logs].filter((t) => isDescendant(tx, t))[0] |
||||
const arrow = [...arrows].filter((t) => isDescendant(tx, t))[0] |
||||
|
||||
if (table && table.parentNode) { |
||||
tx.removeChild(table) |
||||
log.removeChild(arrow) |
||||
log.appendChild(arrowDown) |
||||
} else { |
||||
log.removeChild(arrow) |
||||
log.appendChild(arrowUp) |
||||
table = createTable({ |
||||
hash: data.tx.hash, |
||||
status: data.receipt ? data.receipt.status : null, |
||||
isCall: data.tx.isCall, |
||||
contractAddress: data.tx.contractAddress, |
||||
data: data.tx, |
||||
from, |
||||
to, |
||||
gas: data.tx.gas, |
||||
input: data.tx.input, |
||||
'decoded input': data.resolvedData && data.resolvedData.params ? JSON.stringify(typeConversion.stringify(data.resolvedData.params), null, '\t') : ' - ', |
||||
'decoded output': data.resolvedData && data.resolvedData.decodedReturnValue ? JSON.stringify(typeConversion.stringify(data.resolvedData.decodedReturnValue), null, '\t') : ' - ', |
||||
logs: data.logs, |
||||
val: data.tx.value, |
||||
transactionCost: data.tx.transactionCost, |
||||
executionCost: data.tx.executionCost |
||||
}) |
||||
tx.appendChild(table) |
||||
} |
||||
} |
||||
|
||||
function createTable (opts) { |
||||
var table = yo`<table class="${css.txTable}" id="txTable" data-id="txLoggerTable${opts.hash}"></table>` |
||||
if (!opts.isCall) { |
||||
var msg = '' |
||||
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' |
||||
} |
||||
table.appendChild(yo` |
||||
<tr class="${css.tr}"> |
||||
<td class="${css.td}" data-shared="key_${opts.hash}"> status </td> |
||||
<td class="${css.td}" data-id="txLoggerTableStatus${opts.hash}" data-shared="pair_${opts.hash}">${opts.status}${msg}</td> |
||||
</tr>`) |
||||
} |
||||
|
||||
var transactionHash = yo` |
||||
<tr class="${css.tr}"> |
||||
<td class="${css.td}" data-shared="key_${opts.hash}"> transaction hash </td> |
||||
<td class="${css.td}" data-id="txLoggerTableHash${opts.hash}" data-shared="pair_${opts.hash}">${opts.hash} |
||||
${copyToClipboard(() => opts.hash)} |
||||
</td> |
||||
</tr> |
||||
` |
||||
table.appendChild(transactionHash) |
||||
|
||||
var contractAddress = yo` |
||||
<tr class="${css.tr}"> |
||||
<td class="${css.td}" data-shared="key_${opts.hash}"> contract address </td> |
||||
<td class="${css.td}" data-id="txLoggerTableContractAddress${opts.hash}" data-shared="pair_${opts.hash}">${opts.contractAddress} |
||||
${copyToClipboard(() => opts.contractAddress)} |
||||
</td> |
||||
</tr> |
||||
` |
||||
if (opts.contractAddress) table.appendChild(contractAddress) |
||||
|
||||
var from = yo` |
||||
<tr class="${css.tr}"> |
||||
<td class="${css.td} ${css.tableTitle}" data-shared="key_${opts.hash}"> from </td> |
||||
<td class="${css.td}" data-id="txLoggerTableFrom${opts.hash}" data-shared="pair_${opts.hash}">${opts.from} |
||||
${copyToClipboard(() => opts.from)} |
||||
</td> |
||||
</tr> |
||||
` |
||||
if (opts.from) table.appendChild(from) |
||||
|
||||
var toHash |
||||
var data = opts.data // opts.data = data.tx
|
||||
if (data.to) { |
||||
toHash = opts.to + ' ' + data.to |
||||
} else { |
||||
toHash = opts.to |
||||
} |
||||
var to = yo` |
||||
<tr class="${css.tr}"> |
||||
<td class="${css.td}" data-shared="key_${opts.hash}"> to </td> |
||||
<td class="${css.td}" data-id="txLoggerTableTo${opts.hash}" data-shared="pair_${opts.hash}">${toHash} |
||||
${copyToClipboard(() => data.to ? data.to : toHash)} |
||||
</td> |
||||
</tr> |
||||
` |
||||
if (opts.to) table.appendChild(to) |
||||
|
||||
var gas = yo` |
||||
<tr class="${css.tr}"> |
||||
<td class="${css.td}" data-shared="key_${opts.hash}"> gas </td> |
||||
<td class="${css.td}" data-id="txLoggerTableGas${opts.hash}" data-shared="pair_${opts.hash}">${opts.gas} gas |
||||
${copyToClipboard(() => opts.gas)} |
||||
</td> |
||||
</tr> |
||||
` |
||||
if (opts.gas) table.appendChild(gas) |
||||
|
||||
var callWarning = '' |
||||
if (opts.isCall) { |
||||
callWarning = '(Cost only applies when called by a contract)' |
||||
} |
||||
if (opts.transactionCost) { |
||||
table.appendChild(yo` |
||||
<tr class="${css.tr}"> |
||||
<td class="${css.td}" data-shared="key_${opts.hash}"> transaction cost </td> |
||||
<td class="${css.td}" data-id="txLoggerTableTransactionCost${opts.hash}" data-shared="pair_${opts.hash}">${opts.transactionCost} gas ${callWarning} |
||||
${copyToClipboard(() => opts.transactionCost)} |
||||
</td> |
||||
</tr>`) |
||||
} |
||||
|
||||
if (opts.executionCost) { |
||||
table.appendChild(yo` |
||||
<tr class="${css.tr}"> |
||||
<td class="${css.td}" data-shared="key_${opts.hash}"> execution cost </td> |
||||
<td class="${css.td}" data-id="txLoggerTableExecutionHash${opts.hash}" data-shared="pair_${opts.hash}">${opts.executionCost} gas ${callWarning} |
||||
${copyToClipboard(() => opts.executionCost)} |
||||
</td> |
||||
</tr>`) |
||||
} |
||||
|
||||
var hash = yo` |
||||
<tr class="${css.tr}"> |
||||
<td class="${css.td}" data-shared="key_${opts.hash}"> hash </td> |
||||
<td class="${css.td}" data-id="txLoggerTableHash${opts.hash}" data-shared="pair_${opts.hash}">${opts.hash} |
||||
${copyToClipboard(() => opts.hash)} |
||||
</td> |
||||
</tr> |
||||
` |
||||
if (opts.hash) table.appendChild(hash) |
||||
|
||||
var input = yo` |
||||
<tr class="${css.tr}"> |
||||
<td class="${css.td}" data-shared="key_${opts.hash}"> input </td> |
||||
<td class="${css.td}" data-id="txLoggerTableInput${opts.hash}" data-shared="pair_${opts.hash}">${helper.shortenHexData(opts.input)} |
||||
${copyToClipboard(() => opts.input)} |
||||
</td> |
||||
</tr> |
||||
` |
||||
if (opts.input) table.appendChild(input) |
||||
|
||||
if (opts['decoded input']) { |
||||
var inputDecoded = yo` |
||||
<tr class="${css.tr}"> |
||||
<td class="${css.td}" data-shared="key_${opts.hash}"> decoded input </td> |
||||
<td class="${css.td}" data-id="txLoggerTableDecodedInput${opts.hash}" data-shared="pair_${opts.hash}">${opts['decoded input']} |
||||
${copyToClipboard(() => opts['decoded input'])} |
||||
</td> |
||||
</tr>` |
||||
table.appendChild(inputDecoded) |
||||
} |
||||
|
||||
if (opts['decoded output']) { |
||||
var outputDecoded = yo` |
||||
<tr class="${css.tr}"> |
||||
<td class="${css.td}" data-shared="key_${opts.hash}"> decoded output </td> |
||||
<td class="${css.td}" id="decodedoutput" data-id="txLoggerTableDecodedOutput${opts.hash}" data-shared="pair_${opts.hash}">${opts['decoded output']} |
||||
${copyToClipboard(() => opts['decoded output'])} |
||||
</td> |
||||
</tr>` |
||||
table.appendChild(outputDecoded) |
||||
} |
||||
|
||||
var stringified = ' - ' |
||||
if (opts.logs && opts.logs.decoded) { |
||||
stringified = typeConversion.stringify(opts.logs.decoded) |
||||
} |
||||
var logs = yo` |
||||
<tr class="${css.tr}"> |
||||
<td class="${css.td}" data-shared="key_${opts.hash}"> logs </td> |
||||
<td class="${css.td}" id="logs" data-id="txLoggerTableLogs${opts.hash}" data-shared="pair_${opts.hash}"> |
||||
${JSON.stringify(stringified, null, '\t')} |
||||
${copyToClipboard(() => JSON.stringify(stringified, null, '\t'))} |
||||
${copyToClipboard(() => JSON.stringify(opts.logs.raw || '0'))} |
||||
</td> |
||||
</tr> |
||||
` |
||||
if (opts.logs) table.appendChild(logs) |
||||
|
||||
var val = opts.val != null ? typeConversion.toInt(opts.val) : 0 |
||||
val = yo` |
||||
<tr class="${css.tr}"> |
||||
<td class="${css.td}" data-shared="key_${opts.hash}"> value </td> |
||||
<td class="${css.td}" data-id="txLoggerTableValue${opts.hash}" data-shared="pair_${opts.hash}">${val} wei |
||||
${copyToClipboard(() => `${val} wei`)} |
||||
</td> |
||||
</tr> |
||||
` |
||||
if (opts.val) table.appendChild(val) |
||||
|
||||
return table |
||||
} |
@ -1,132 +0,0 @@ |
||||
'use strict' |
||||
import { CompilerImports } from '@remix-project/core-plugin' |
||||
import Registry from '../app/state/registry' |
||||
var yo = require('yo-yo') |
||||
var async = require('async') |
||||
var EventManager = require('../lib/events') |
||||
|
||||
var toolTip = require('../app/ui/tooltip') |
||||
|
||||
class CmdInterpreterAPI { |
||||
constructor (terminal, blockchain) { |
||||
const self = this |
||||
self.event = new EventManager() |
||||
self.blockchain = blockchain |
||||
self._components = {} |
||||
self._components.registry = Registry.getInstance() |
||||
self._components.terminal = terminal |
||||
self._components.fileImport = new CompilerImports() |
||||
self._deps = { |
||||
fileManager: self._components.registry.get('filemanager').api, |
||||
editor: self._components.registry.get('editor').api, |
||||
compilersArtefacts: self._components.registry.get('compilersartefacts').api, |
||||
offsetToLineColumnConverter: self._components.registry.get('offsettolinecolumnconverter').api |
||||
} |
||||
self.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' |
||||
} |
||||
} |
||||
|
||||
log () { arguments[0] != null ? this._components.terminal.commands.html(arguments[0]) : this._components.terminal.commands.html(arguments[1]) } |
||||
loadgist (id, cb) { |
||||
this._components.terminal.call('gistHandler', 'load', id) |
||||
if (cb) cb() |
||||
} |
||||
|
||||
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() |
||||
} |
||||
}) |
||||
} |
||||
|
||||
exeCurrent (cb) { |
||||
return this.execute(undefined, cb) |
||||
} |
||||
|
||||
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) |
||||
if (cb) cb() |
||||
return |
||||
} |
||||
|
||||
_execute(content, cb) |
||||
}) |
||||
} |
||||
|
||||
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 '' |
||||
} |
||||
} |
||||
|
||||
module.exports = CmdInterpreterAPI |
Loading…
Reference in new issue