Put vm debugger components together

pull/453/head
ioedeveloper 4 years ago
parent 2ac2af11ee
commit 0a1363f2eb
  1. 43
      libs/remix-ui/debugger-ui/src/hooks/extract-data.tsx
  2. 2
      libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx
  3. 20
      libs/remix-ui/debugger-ui/src/lib/vm-debugger/code-list-view.tsx
  4. 51
      libs/remix-ui/debugger-ui/src/lib/vm-debugger/dropdown-panel.tsx
  5. 44
      libs/remix-ui/debugger-ui/src/lib/vm-debugger/solidity-locals.tsx
  6. 39
      libs/remix-ui/debugger-ui/src/lib/vm-debugger/solidity-state.tsx
  7. 0
      libs/remix-ui/debugger-ui/src/lib/vm-debugger/utils/solidity-type-formatter.ts
  8. 90
      libs/remix-ui/debugger-ui/src/lib/vm-debugger/vm-debugger.tsx
  9. 14
      libs/remix-ui/debugger-ui/src/types/index.ts
  10. 42
      libs/remix-ui/debugger-ui/src/utils/solidityTypeFormatter.ts
  11. 10
      libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx
  12. 6
      libs/remix-ui/tree-view/src/types/index.ts

@ -1,9 +1,32 @@
import React, { useState, useEffect } from 'react'
import { ExtractData, ExtractFunc } from '../types'
export const useExtractData = (json, extractFunc?): Array<{ [key: string]: ExtractData }> => {
export const useExtractData = (json, extractFunc?: ExtractFunc): Array<{ key: string, data: ExtractData }> => {
const [data, setData] = useState(null)
const extractDataDefault = (item, parent?) => {
useEffect(() => {
const data: Array<{ key: string, data: ExtractData }> = Object.keys(json).map((innerKey) => {
if (extractFunc) {
return {
key: innerKey,
data : extractFunc(json[innerKey], json)
}
} else {
return {
key: innerKey,
data: extractDataDefault(json[innerKey], json)
}
}
})
setData(data)
return () => {
setData(null)
}
}, [json, extractFunc])
const extractDataDefault: ExtractFunc = (item, parent?) => {
const ret: ExtractData = {}
if (item instanceof Array) {
@ -29,22 +52,6 @@ export const useExtractData = (json, extractFunc?): Array<{ [key: string]: Extra
return ret
}
useEffect(() => {
const data: Array<{ [key: string]: ExtractData }> = Object.keys(json).map((innerKey) => {
if (extractFunc) {
return { [innerKey]: extractFunc(json[innerKey], json) }
} else {
return { [innerKey]: extractDataDefault(json[innerKey], json) }
}
})
setData(data)
return () => {
setData(null)
}
}, [json, extractFunc])
return data
}

@ -1,4 +1,6 @@
import React from 'react'
import StepManager from './step-manager/step-manager'
import
const DebuggerUI = () => {
return (

@ -1,16 +1,23 @@
import React, { useState, useRef } from 'react'
import React, { useState, useEffect } from 'react'
import DropdownPanel from './dropdown-panel'
import EventManager from '../../../../../apps/remix-ide/src/lib/events'
/* eslint-disable-next-line */
import EventManager from '../../../../../../apps/remix-ide/src/lib/events'
export const CodeListView = ({ vmDebuggerLogic }) => {
export const CodeListView = ({ vmDebuggerLogic, asm }) => {
const event = new EventManager()
const [state, setState] = useState({
code: '',
code: [],
address: '',
itemSelected: null,
index: null
})
useEffect(() => {
const { code, address, index } = asm
changed(code, address, index)
}, [asm])
const indexChanged = (index) => {
if(index < 0) return
setState(prevState => {
@ -21,10 +28,6 @@ export const CodeListView = ({ vmDebuggerLogic }) => {
})
}
const reset = () => {
changed([], '', -1)
}
const changed = (code, address, index) => {
if (state.address === address) {
return indexChanged(index)
@ -36,7 +39,6 @@ export const CodeListView = ({ vmDebuggerLogic }) => {
address
}
})
this.basicPanel.setContent(this.renderAssemblyItems())
indexChanged(index)
}

@ -3,15 +3,17 @@ import AssemblyItems from './assembly-items'
/* eslint-disable-next-line */
import { TreeView, TreeViewItem } from '../../../../tree-view/src/index'
import useExtractData from '../../hooks/extract-data'
import { ExtractData, ExtractFunc, DropdownPanelProps } from '../../types'
import { DropdownPanelProps, ExtractData } from '../../types'
import './styles/dropdown-panel.css'
import EventManager from '../../../../../apps/remix-ide/src/lib/events'
import copyToClipboard from '../../../../../apps/remix-ide/src/app/ui/copy-to-clipboard'
/* eslint-disable-next-line */
import EventManager from '../../../../../../apps/remix-ide/src/lib/events'
/* eslint-disable-next-line */
import copyToClipboard from '../../../../../../apps/remix-ide/src/app/ui/copy-to-clipboard'
export const DropdownPanel = (props: DropdownPanelProps) => {
const { dropdownName, opts, codeView, index, calldata, header, extractFunc } = props
const { dropdownName, opts, codeView, index, calldata, header, extractFunc, formatSelfFunc } = props
const data = useExtractData(calldata, extractFunc)
const event = new EventManager()
const dropdownRawEl = useRef(null)
@ -150,9 +152,46 @@ export const DropdownPanel = (props: DropdownPanelProps) => {
event.trigger('show', [])
}
let content = <div>Empty</div>
const formatSelfDefault = (key: string, data: ExtractData) => {
return (
<div className="d-flex mb-1 flex-row label_item">
<label className="small font-weight-bold pr-1 label_key">{key}:</label>
<label className="m-0 label_value">{data.self}</label>
</div>
)
}
const renderData = (item: ExtractData, key: string) => {
const children = (item.children || []).map((child) => {
const childKey = key + '/' + child.key
return (
<TreeViewItem key={childKey} label={ formatSelfFunc ? formatSelfFunc(childKey, item) : formatSelfDefault(childKey, item)}>
{ renderData(child.value, childKey) }
</TreeViewItem>
)
})
if (children && children.length > 0 ) {
return (
<TreeView key={key}>
{ children }
</TreeView>
)
} else {
return <TreeViewItem key={key} label={ formatSelfFunc ? formatSelfFunc(key, item) : formatSelfDefault(key, item) } />
}
}
let content: JSX.Element | JSX.Element[] = <div>Empty</div>
if (state.json) {
content = treeView.render({}, null)
content = data.map(item => {
return (
<TreeView key={item.key}>
{ renderData(item.data, item.key) }
</TreeView>
)
})
}
const title = !state.displayContentOnly ?
<div className="py-0 px-1 title">

@ -0,0 +1,44 @@
import React from 'react'
import DropdownPanel from './dropdown-panel'
import { extractData } from '../../utils/solidityTypeFormatter'
import { ExtractData } from '../../types'
export const SolidityLocals = () => {
const formatSelf = (key: string, data: ExtractData) => {
let color = 'var(--primary)'
if (data.isArray || data.isStruct || data.isMapping) {
color = 'var(--info)'
} else if (
data.type.indexOf('uint') === 0 ||
data.type.indexOf('int') === 0 ||
data.type.indexOf('bool') === 0 ||
data.type.indexOf('enum') === 0
) {
color = 'var(--green)'
} else if (data.type === 'string') {
color = 'var(--teal)'
} else if (data.self == 0x0) { // eslint-disable-line
color = 'var(--gray)'
}
return (
<label className='mb-0' style={{ color: data.isProperty ? 'var(--info)' : '', whiteSpace: 'pre-wrap' }}>
{' ' + key}:
<label className='mb-0' style={{ color }}>
{' ' + data.self}
</label>
<label style={{ fontStyle: 'italic' }}>
{data.isProperty || !data.type ? '' : ' ' + data.type}
</label>
</label>
)
}
return (
<div id='soliditylocals' data-id="solidityLocals">
<DropdownPanel dropdownName='Solidity Locals' opts={{ json: true }} extractFunc={extractData} formatSelfFunc={formatSelf} />
</div>
)
}
export default SolidityLocals

@ -1,11 +1,44 @@
import React from 'react'
import DropdownPanel from './dropdown-panel'
import { extractData } from '../../utils/solidityTypeFormatter'
import { ExtractData } from '../../types'
export const SolidityState = () => {
const formatSelf = (key: string, data: ExtractData) => {
let color = 'var(--primary)'
if (data.isArray || data.isStruct || data.isMapping) {
color = 'var(--info)'
} else if (
data.type.indexOf('uint') === 0 ||
data.type.indexOf('int') === 0 ||
data.type.indexOf('bool') === 0 ||
data.type.indexOf('enum') === 0
) {
color = 'var(--green)'
} else if (data.type === 'string') {
color = 'var(--teal)'
} else if (data.self == 0x0) { // eslint-disable-line
color = 'var(--gray)'
}
return (
<label className='mb-0' style={{ color: data.isProperty ? 'var(--info)' : '', whiteSpace: 'pre-wrap' }}>
{' ' + key}:
<label className='mb-0' style={{ color }}>
{' ' + data.self}
</label>
<label style={{ fontStyle: 'italic' }}>
{data.isProperty || !data.type ? '' : ' ' + data.type}
</label>
</label>
)
}
return (
<DropdownPanel dropdownName='Solidity State' opts={{
}} />
<div id='soliditylocals' data-id='solidityLocals'>
{
<DropdownPanel dropdownName='Solidity State' opts={{ json: true }} formatSelfFunc={formatSelf} extractFunc={extractData} />
}
</div>
)
}

@ -1,15 +1,97 @@
import React, { useState } from 'react'
import React, { useState, useEffect } from 'react'
import CodeListView from './code-list-view'
import CalldataPanel from './calldata-panel'
import MemoryPanel from './memory-panel'
import CallstackPanel from './callstack-panel'
import FunctionPanel from './function-panel'
import StackPanel from './stack-panel'
import StoragePanel from './storage-panel'
import StepDetail from './step-detail'
import SolidityState from './solidity-state'
import SolidityLocals from './solidity-locals'
import FullStoragesChangesPanel from './full-storages-changes'
import DropdownPanel from './dropdown-panel'
import './vm-debugger.css';
export const VmDebugger = ({ vmDebuggerLogic }) => {
const [state, setState] = useState({
})
const [asm, setAsm] = useState({
code: null,
address: null,
index: null
})
const [calldataPanel, setCalldataPanel] = useState(null)
const [memoryPanel, setMemoryPanel] = useState(null)
const [callStackPanel, setCallStackPanel] = useState(null)
useEffect(() => {
vmDebuggerLogic.event.register('codeManagerChanged', updateAsm)
vmDebuggerLogic.event.register('traceUnloaded', resetAsm)
vmDebuggerLogic.event.register('traceManagerCallDataUpdate', updateCalldataPanel)
vmDebuggerLogic.event.register('traceManagerMemoryUpdate', updateMemoryPanel)
vmDebuggerLogic.event.register('traceManagerCallStackUpdate', updateCallStackPanel)
}, [])
const updateAsm = (code, address, index) => {
setAsm({
code,
address,
index
})
}
const resetAsm = () => {
setAsm({
code: [],
address: '',
index: -1
})
}
const updateCalldataPanel = (calldata) => {
setCalldataPanel(calldata)
}
const updateMemoryPanel = (calldata) => {
setMemoryPanel(calldata)
}
const updateCallStackPanel = (calldata) => {
setCallStackPanel(calldata)
}
useEffect(() => {
vmDebuggerLogic.event.register('codeManagerChanged', )
}, [])
const renderHead = () => {
return (
<div id="vmheadView" className="mt-1 px-0">
<div className="d-flex flex-column">
<div className="w-100" hidden>
{this.functionPanel.render()}
{this.solidityLocals.render()}
{this.solidityState.render()}
</div>
<div className="w-100">{this.asmCode.render()}</div>
<div className="w-100">{this.stepDetail.render()}</div>
</div>
</div>
)
}
return (
<div>
<h1>Welcome to vmDebugger!</h1>
<div id="vmdebugger" className="px-2">
<div>
{this.stackPanel.render()}
{this.memoryPanel.render()}
{this.storagePanel.render()}
{this.callstackPanel.render()}
{this.calldataPanel.render()}
{this.returnValuesPanel.render()}
{this.fullStoragesChangesPanel.render()}
</div>
</div>
);
};

@ -1,12 +1,13 @@
export interface ExtractData {
children?: Array<{key: number | string, value: string}> | { key: number | string, value: string }
self?: string,
children?: Array<{key: number | string, value: ExtractData}>
self?: string | number,
isNode?: boolean,
isLeaf?: boolean,
isArray?: boolean,
isStruct?: boolean,
isMapping?: boolean,
type?: string
type?: string,
isProperty?: boolean
}
export type ExtractFunc = (json: any, parent?: any) => ExtractData
@ -26,5 +27,8 @@ export interface DropdownPanelProps {
[key: string]: string
},
header?: string,
extractFunc?: ExtractFunc
}
extractFunc?: ExtractFunc,
formatSelfFunc?: FormatSelfFunc
}
export type FormatSelfFunc = (key: string, data: ExtractData) => JSX.Element

@ -0,0 +1,42 @@
import { BN } from 'ethereumjs-util'
import { ExtractData } from '../types'
export function extractData (item, parent): ExtractData {
const ret: ExtractData = {}
if (item.isProperty) {
return item
}
if (item.type.lastIndexOf(']') === item.type.length - 1) {
ret.children = (item.value || []).map(function (item, index) {
return {key: index, value: item}
})
ret.children.unshift({
key: 'length',
value: {
self: (new BN(item.length.replace('0x', ''), 16)).toString(10),
type: 'uint',
isProperty: true
}
})
ret.isArray = true
ret.self = parent.isArray ? '' : item.type
} else if (item.type.indexOf('struct') === 0) {
ret.children = Object.keys((item.value || {})).map(function (key) {
return {key: key, value: item.value[key]}
})
ret.self = item.type
ret.isStruct = true
} else if (item.type.indexOf('mapping') === 0) {
ret.children = Object.keys((item.value || {})).map(function (key) {
return {key: key, value: item.value[key]}
})
ret.isMapping = true
ret.self = item.type
} else {
ret.children = null
ret.self = item.value
ret.type = item.type
}
return ret
}

@ -1,8 +1,10 @@
import React, { useState } from 'react'
import { TreeViewItemProps } from '../../types'
import './tree-view-item.css'
export const TreeViewItem = ({ key, children, label, ...otherProps }) => {
export const TreeViewItem = (props: TreeViewItemProps) => {
const { key, children, label, ...otherProps } = props
const [isExpanded, setIsExpanded] = useState(false)
return (
@ -15,7 +17,7 @@ export const TreeViewItem = ({ key, children, label, ...otherProps }) => {
</div>
{ isExpanded ? children : null }
</li>
);
};
)
}
export default TreeViewItem;
export default TreeViewItem

@ -1,4 +1,10 @@
export interface TreeViewProps {
children?: React.ReactNode,
key: string
}
export interface TreeViewItemProps {
children?: React.ReactNode,
key: string,
label: string | number | React.ReactNode
}
Loading…
Cancel
Save