jumpToDefinition

pull/5370/head
bunsenstraat 3 years ago
parent ad90f2e3ff
commit eb4e2b42bb
  1. 72
      libs/remix-core-plugin/src/lib/editor-context-listener.ts
  2. 40
      libs/remix-ui/editor-context-view/src/lib/remix-ui-editor-context-view.tsx
  3. 66
      libs/remix-ui/editor/src/lib/remix-ui-editor.tsx
  4. 63460
      package-lock.json

@ -2,14 +2,24 @@
import { Plugin } from '@remixproject/engine'
import { sourceMappingDecoder } from '@remix-project/remix-debug'
import { AstNode } from '@remix-project/remix-solidity-ts'
const profile = {
name: 'contextualListener',
methods: ['referencesOf', 'getActiveHighlights', 'gasEstimation', 'declarationOf'],
methods: ['jumpToDefinition', 'nodesAtEditorPosition', 'referencesOf', 'getActiveHighlights', 'gasEstimation', 'declarationOf', 'jumpTo'],
events: [],
version: '0.0.1'
}
export function isDefinition(node: any) {
return node.nodeType === 'ContractDefinition' ||
node.nodeType === 'FunctionDefinition' ||
node.nodeType === 'ModifierDefinition' ||
node.nodeType === 'VariableDeclaration' ||
node.nodeType === 'StructDefinition' ||
node.nodeType === 'EventDefinition'
}
/*
trigger contextChanged(nodes)
*/
@ -50,6 +60,7 @@ export class EditorContextListener extends Plugin {
FlatReferences: {}
}
this._buildIndex(data, source)
console.log(this._index)
})
setInterval(async () => {
@ -87,6 +98,62 @@ export class EditorContextListener extends Plugin {
return this._index.Declarations[node.id]
}
async nodesAtEditorPosition(position: any){
const lastCompilationResult = await this.call('compilerArtefacts', 'getLastCompilationResult')
if (lastCompilationResult && lastCompilationResult.languageversion.indexOf('soljson') === 0 && lastCompilationResult.data) {
const nodes = sourceMappingDecoder.nodesAtPosition(null, position, lastCompilationResult.data.sources[this.currentFile])
return nodes
}
return []
}
async jumpToDefinition(position: any) {
const nodes = await this.nodesAtEditorPosition(position)
console.log(nodes)
let nodeDeclaration: AstNode
let node: AstNode
if (nodes && nodes.length) {
node = nodes[nodes.length - 1]
if (!isDefinition(node)) {
nodeDeclaration = await this.declarationOf(node)
} else {
nodeDeclaration = node
}
}
console.log(node, nodeDeclaration)
if (nodeDeclaration && nodeDeclaration.src) {
console.log(nodeDeclaration)
const position = sourceMappingDecoder.decode(nodeDeclaration.src)
if (position) {
await this.jumpToPosition(position)
}
}
}
/*
* onClick jump to position of ast node in the editor
*/
async jumpToPosition(position: any) {
const jumpToLine = async (fileName: string, lineColumn: any) => {
if (fileName !== await this.call('fileManager', 'file')) {
await this.call('fileManager', 'open', fileName)
}
if (lineColumn.start && lineColumn.start.line >= 0 && lineColumn.start.column >= 0) {
this.call('editor', 'gotoLine', lineColumn.start.line, lineColumn.end.column + 1)
}
}
const lastCompilationResult = await this.call('compilerArtefacts', 'getLastCompilationResult')
if (lastCompilationResult && lastCompilationResult.languageversion.indexOf('soljson') === 0 && lastCompilationResult.data) {
const lineColumn = await this.call('offsetToLineColumnConverter', 'offsetToLineColumn',
position,
position.file,
lastCompilationResult.getSourceCode().sources,
lastCompilationResult.getAsts())
const filename = lastCompilationResult.getSourceName(position.file)
// TODO: refactor with rendererAPI.errorClick
jumpToLine(filename, lineColumn)
}
}
async _highlightItems(cursorPosition, compilationResult, file) {
if (this.currentPosition === cursorPosition) return
this._stopHighlighting()
@ -95,6 +162,7 @@ export class EditorContextListener extends Plugin {
if (compilationResult && compilationResult.data && compilationResult.data.sources[file]) {
const nodes = sourceMappingDecoder.nodesAtPosition(null, cursorPosition, compilationResult.data.sources[file])
this.nodes = nodes
console.log(nodes)
if (nodes && nodes.length && nodes[nodes.length - 1]) {
await this._highlightExpressions(nodes[nodes.length - 1], compilationResult)
}
@ -222,6 +290,8 @@ export class EditorContextListener extends Plugin {
}
}
_getInputParams(node) {
const params = []
const target = node.parameters

@ -35,14 +35,9 @@ export type gasEstimationType = {
}
export interface RemixUiEditorContextViewProps {
hide: boolean,
gotoLine: (line: number, column: number) => void,
openFile: (fileName: string) => void,
getLastCompilationResult: () => any,
offsetToLineColumn: (position: any, file: any, sources: any, asts: any) => any,
getCurrentFileName: () => string
jumpToPosition: (position: any) => void
onContextListenerChanged: (listener: onContextListenerChangedListener) => void
onCurrentFileChanged: (listener: ononCurrentFileChangedListener) => void
referencesOf: (nodes: astNode) => Array<astNode>
getActiveHighlights: () => Array<astNodeLight>
gasEstimation: (node: astNode) => gasEstimationType
declarationOf: (node: astNode) => astNode
@ -91,6 +86,7 @@ export function RemixUiEditorContextView (props: RemixUiEditorContextViewProps)
nextNodeDeclaration = nextNode
}
}
console.log(nextNode, nextNodeDeclaration)
if (nextNodeDeclaration && currentNodeDeclaration.current && nextNodeDeclaration.id === currentNodeDeclaration.current.id) return
currentNodeDeclaration.current = nextNodeDeclaration
@ -134,35 +130,13 @@ export function RemixUiEditorContextView (props: RemixUiEditorContextViewProps)
}
}
/*
* onClick jump to ast node in the editor
*/
const _jumpToInternal = async (position: any) => {
const jumpToLine = async (fileName: string, lineColumn: any) => {
if (fileName !== await props.getCurrentFileName()) {
await props.openFile(fileName)
}
if (lineColumn.start && lineColumn.start.line >= 0 && lineColumn.start.column >= 0) {
props.gotoLine(lineColumn.start.line, lineColumn.end.column + 1)
}
}
const lastCompilationResult = await props.getLastCompilationResult()
if (lastCompilationResult && lastCompilationResult.languageversion.indexOf('soljson') === 0 && lastCompilationResult.data) {
const lineColumn = await props.offsetToLineColumn(
position,
position.file,
lastCompilationResult.getSourceCode().sources,
lastCompilationResult.getAsts())
const filename = lastCompilationResult.getSourceName(position.file)
// TODO: refactor with rendererAPI.errorClick
jumpToLine(filename, lineColumn)
}
}
const _render = () => {
const node = currentNodeDeclaration.current
if (!node) return (<div></div>)
const references = state.activeHighlights
console.log(node)
const type = node.typeDescriptions && node.typeDescriptions.typeString ? node.typeDescriptions.typeString : node.nodeType
const referencesCount = `${references ? references.length : '0'} reference(s)`
@ -170,9 +144,10 @@ export function RemixUiEditorContextView (props: RemixUiEditorContextViewProps)
const jumpTo = () => {
if (node && node.src) {
console.log(node)
const position = sourceMappingDecoder.decode(node.src)
if (position) {
_jumpToInternal(position)
props.jumpToPosition(position)
}
}
}
@ -182,7 +157,8 @@ export function RemixUiEditorContextView (props: RemixUiEditorContextViewProps)
e.target.dataset.action === 'next' ? loopOverReferences.current++ : loopOverReferences.current--
if (loopOverReferences.current < 0) loopOverReferences.current = nodes.length - 1
if (loopOverReferences.current >= nodes.length) loopOverReferences.current = 0
_jumpToInternal(nodes[loopOverReferences.current].position)
console.log(loopOverReferences.current)
props.jumpToPosition(nodes[loopOverReferences.current].position)
}
return (

@ -1,12 +1,15 @@
import React, { useState, useRef, useEffect, useReducer } from 'react' // eslint-disable-line
import { RemixUiEditorContextView, astNode } from '@remix-ui/editor-context-view'
import Editor, { loader } from '@monaco-editor/react'
import Editor, { loader, Monaco } from '@monaco-editor/react'
import { reducerActions, reducerListener, initialState } from './actions/editor'
import { language, conf } from './syntax'
import { cairoLang, cairoConf } from './cairoSyntax'
import './remix-ui-editor.css'
import { loadTypes } from './web-types'
import monaco from '../types/monaco'
import { IPosition, languages } from 'monaco-editor'
import { sourceMappingDecoder } from '@remix-project/remix-debug'
type cursorPosition = {
startLineNumber: number,
@ -67,6 +70,7 @@ export interface EditorUIProps {
getFontSize: () => number,
getValue: (uri: string) => string
getCursorPosition: () => cursorPosition
getHoverPosition: (position: IPosition) => number
addDecoration: (marker: sourceMarker, filePath: string, typeOfDecoration: string) => DecorationsReturn
clearDecorationsByPlugin: (filePath: string, plugin: string, typeOfDecoration: string, registeredDecorations: any, currentDecorations: any) => DecorationsReturn
keepDecorationsFor: (filePath: string, plugin: string, typeOfDecoration: string, registeredDecorations: any, currentDecorations: any) => DecorationsReturn
@ -349,6 +353,16 @@ export const EditorUI = (props: EditorUIProps) => {
}
}
props.editorAPI.getHoverPosition = (position: monaco.Position) => {
if (!monacoRef.current) return
const model = editorModelsState[currentFileRef.current]?.model
if (model) {
return model.getOffsetAt(position)
}else{
return 0
}
}
props.editorAPI.getFontSize = () => {
if (!editorRef.current) return
return editorRef.current.getOption(43).fontSize
@ -411,6 +425,49 @@ export const EditorUI = (props: EditorUIProps) => {
monacoRef.current.languages.setMonarchTokensProvider('remix-cairo', cairoLang)
monacoRef.current.languages.setLanguageConfiguration('remix-cairo', cairoConf)
// register Definition Provider
monacoRef.current.languages.registerDefinitionProvider('remix-solidity', {
provideDefinition(model: monaco.editor.ITextModel, position: monaco.Position, token: monaco.CancellationToken){
const cursorPosition = props.editorAPI.getCursorPosition()
props.plugin.call('contextualListener', 'jumpToDefinition', cursorPosition)
return null
}
})
monacoRef.current.languages.registerHoverProvider('remix-solidity', {
provideHover: async function (model: any, position: monaco.Position) {
//console.log(position)
const cursorPosition = props.editorAPI.getHoverPosition(position)
//console.log(cursorPosition)
const compilationResult = await props.plugin.call('compilerArtefacts', 'getLastCompilationResult')
const file = await props.plugin.call('fileManager', 'file')
if (compilationResult && compilationResult.data && compilationResult.data.sources[file]) {
const nodes = sourceMappingDecoder.nodesAtPosition(null, cursorPosition, compilationResult.data.sources[file])
// console.log(cursorPosition, nodes)
// loop over nodes
if (nodes && nodes.length) {
nodes.forEach((node) => {
const position = sourceMappingDecoder.decode(node.src)
const fileTarget = compilationResult.getSourceName(position.file)
// console.log(position, fileTarget)
})
}
}
return {
range: new monaco.Range(
position.lineNumber,
position.column,
position.lineNumber,
model.getLineMaxColumn(position.lineNumber)
),
contents: [
{ value: '<div>test html</div>' }
]
};
}
})
loadTypes(monacoRef.current)
}
@ -427,14 +484,9 @@ export const EditorUI = (props: EditorUIProps) => {
<div className="contextview">
<RemixUiEditorContextView
hide={false}
gotoLine={(line, column) => props.plugin.call('editor', 'gotoLine', line, column)}
openFile={(file) => props.plugin.call('fileManager', 'switchFile', file)}
getLastCompilationResult={() => { return props.plugin.call('compilerArtefacts', 'getLastCompilationResult') } }
offsetToLineColumn={(position, file, sources, asts) => { return props.plugin.call('offsetToLineColumnConverter', 'offsetToLineColumn', position, file, sources, asts) } }
getCurrentFileName={() => { return props.plugin.call('fileManager', 'file') } }
jumpToPosition={(position) => props.plugin.call('contextualListener', 'jumpToPosition', position)}
onContextListenerChanged={(listener) => { props.plugin.on('contextualListener', 'contextChanged', listener) }}
onCurrentFileChanged={(listener) => { props.plugin.on('fileManager', 'currentFileChanged', listener) }}
referencesOf={(node: astNode) => { return props.plugin.call('contextualListener', 'referencesOf', node) }}
getActiveHighlights={() => { return props.plugin.call('contextualListener', 'getActiveHighlights') }}
gasEstimation={(node: astNode) => { return props.plugin.call('contextualListener', 'gasEstimation', node) }}
declarationOf={(node: astNode) => { return props.plugin.call('contextualListener', 'declarationOf', node) }}

63460
package-lock.json generated

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save