editorcontextDummy
filip mertens 3 years ago
parent d1fa6f1e56
commit c83e363ec0
  1. 16
      libs/remix-core-plugin/src/lib/editor-context-listener.ts
  2. 1
      libs/remix-solidity/src/compiler/compiler.ts
  3. 2
      libs/remix-ui/editor-context-view/src/lib/remix-ui-editor-context-view.tsx
  4. 162
      libs/remix-ui/editor/src/lib/providers/completionProvider.ts
  5. 56
      libs/remix-ui/editor/src/lib/providers/hoverProvider.ts
  6. 5
      libs/remix-ui/editor/src/lib/web-types.ts

@ -7,7 +7,7 @@ import { canUseWorker, Compiler, CompilerAbstract, urlFromVersion } from '@remix
const profile = {
name: 'contextualListener',
methods: ['getNodes', 'compile', 'getNodeById', 'getLastCompilationResult', 'positionOfDefinition', 'definitionAtPosition', 'jumpToDefinition', 'referrencesAtPosition', 'nodesAtEditorPosition', 'referencesOf', 'getActiveHighlights', 'gasEstimation', 'declarationOf', 'jumpToPosition'],
methods: ['nodesWithScope', 'getNodes', 'compile', 'getNodeById', 'getLastCompilationResult', 'positionOfDefinition', 'definitionAtPosition', 'jumpToDefinition', 'referrencesAtPosition', 'nodesAtEditorPosition', 'referencesOf', 'getActiveHighlights', 'gasEstimation', 'declarationOf', 'jumpToPosition'],
events: [],
version: '0.0.1'
}
@ -57,7 +57,7 @@ export class EditorContextListener extends Plugin {
this.on('editor', 'contentChanged', () => { this._stopHighlighting() })
this.on('solidity', 'astFinished', async (file, source, languageVersion, data, input, version) => {
console.log('compilation result', Object.keys(data.sources))
// console.log('compilation result', Object.keys(data.sources))
if (languageVersion.indexOf('soljson') !== 0 || !data.sources) return
if (data.sources && Object.keys(data.sources).length === 0) return
this.lastCompilationResult = new CompilerAbstract(languageVersion, data, source, input)
@ -134,12 +134,12 @@ export class EditorContextListener extends Plugin {
return results
}
async nodesAtEditorPosition(position: any) {
async nodesAtEditorPosition(position: any, type: string = '') {
const lastCompilationResult = this.lastCompilationResult // await this.call('compilerArtefacts', 'getLastCompilationResult')
if (!lastCompilationResult) return false
let urlFromPath = await this.call('fileManager', 'getUrlFromPath', this.currentFile)
if (lastCompilationResult && lastCompilationResult.languageversion.indexOf('soljson') === 0 && lastCompilationResult.data) {
const nodes = sourceMappingDecoder.nodesAtPosition(null, position, lastCompilationResult.data.sources[this.currentFile] || lastCompilationResult.data.sources[urlFromPath.file])
const nodes = sourceMappingDecoder.nodesAtPosition(type, position, lastCompilationResult.data.sources[this.currentFile] || lastCompilationResult.data.sources[urlFromPath.file])
return nodes
}
return []
@ -163,6 +163,14 @@ export class EditorContextListener extends Plugin {
}
}
async nodesWithScope(scope: any) {
const nodes = []
for(const node of Object.values(this._index.FlatReferences) as any[]){
if(node.scope === scope) nodes.push(node)
}
return nodes
}
async definitionAtPosition(position: any) {
const nodes = await this.nodesAtEditorPosition(position)
console.log('nodes at position', nodes)

@ -253,7 +253,6 @@ export class Compiler {
*/
loadWorker (url: string): void {
console.log("WEB", webworkify)
this.state.worker = webworkify(require.resolve('./compiler-worker'))
const jobs: Record<'sources', SourceWithTarget> [] = []

@ -98,7 +98,7 @@ export function RemixUiEditorContextView (props: RemixUiEditorContextViewProps)
}
}
const activeHighlights: Array<astNodeLight> = await props.getActiveHighlights()
console.log('active highlights', activeHighlights)
// console.log('active highlights', activeHighlights)
if (nextNode && activeHighlights && activeHighlights.length) {
loopOverReferences.current = activeHighlights.findIndex((el: astNodeLight) => `${el.position.start}:${el.position.length}:${el.position.file}` === nextNode.src)
loopOverReferences.current = loopOverReferences.current === -1 ? 0 : loopOverReferences.current

@ -1,4 +1,3 @@
export class RemixCompletionProvider {
props: any
@ -8,42 +7,133 @@ export class RemixCompletionProvider {
this.monaco = monaco
}
async provideCompletionItems(model: any, position: any) {
console.log('AUTOCOMPLETE')
triggerCharacters = ['.', '']
async provideCompletionItems(model: any, position: any, context: any) {
console.log('AUTOCOMPLETE', context)
return await this.run(model, position, context)
return new Promise((resolve, reject) => {
this.props.plugin.once('contextualListener', 'astFinished', async () => {
console.log('AST FINISHED')
resolve(await this.run(model, position))
resolve(await this.run(model, position, context))
})
this.props.plugin.call('contextualListener', 'compile')
})
}
async run(model: any, position: any) {
async run(model: any, position: any, context: any) {
const textUntilPosition = model.getValueInRange({
startLineNumber: 1,
startColumn: 1,
endLineNumber: position.lineNumber,
endColumn: position.column
});
const word = model.getWordUntilPosition(position);
const range = {
startLineNumber: position.lineNumber,
endLineNumber: position.lineNumber,
startColumn: word.startColumn,
endColumn: word.endColumn
};
const nodes = await this.props.plugin.call('contextualListener', 'getNodes')
startLineNumber: 1,
startColumn: 1,
endLineNumber: position.lineNumber,
endColumn: position.column
});
const word = model.getWordUntilPosition(position);
const wordAt = model.getWordAtPosition(position);
const range = {
startLineNumber: position.lineNumber,
endLineNumber: position.lineNumber,
startColumn: word.startColumn,
endColumn: word.endColumn
};
const getlinearizedBaseContracts = async (node: any) => {
let params = []
if (node.linearizedBaseContracts) {
for (const id of node.linearizedBaseContracts) {
if (id !== node.id) {
const baseContract = await this.props.plugin.call('contextualListener', 'getNodeById', id)
params = [...params, ...[baseContract]]
}
}
}
return params
}
const line = model.getLineContent(position.lineNumber)
let nodes
if (context.triggerCharacter === '.') {
console.log('TEXT', line)
const splits = line.split('.')
console.log('splits', splits)
if (splits.length > 1) {
const last = splits[splits.length - 2].trim()
console.log('last', last)
const cursorPosition = this.props.editorAPI.getCursorPosition()
const nodesAtPosition = await this.props.plugin.call('contextualListener', 'nodesAtEditorPosition', cursorPosition)
console.log('NODES AT POSITION', nodesAtPosition)
for (const node of nodesAtPosition) {
const nodesOfScope = await this.props.plugin.call('contextualListener', 'nodesWithScope', node.id)
console.log('NODES OF SCOPE ', node.name, node.id, nodesOfScope)
for (const nodeOfScope of nodesOfScope) {
if (nodeOfScope.name === last) {
console.log('FOUND NODE', nodeOfScope)
if (nodeOfScope.typeName && nodeOfScope.typeName.nodeType === 'UserDefinedTypeName') {
const declarationOf = await this.props.plugin.call('contextualListener', 'declarationOf', nodeOfScope.typeName)
console.log('HAS DECLARATION OF', declarationOf)
nodes = declarationOf.nodes
}
}
}
}
}
/*
console.log('TEXT', line)
const splits = line.split('.')
console.log('splits', splits)
if(splits.length > 1) {
const last = splits[splits.length - 2].trim()
console.log('last', last)
for(const node of Object.values(nodes) as any[]){
if(node.name === last) {
console.log('FOUND', node)
const cursorPosition = this.props.editorAPI.getCursorPosition()
const nodeAtPosition = await this.props.plugin.call('contextualListener', 'definitionAtPosition', cursorPosition)
console.log('NODE AT POSITION', nodeAtPosition)
if(nodeAtPosition && nodeAtPosition.nodeType === 'Block'){
if(node.scope && node.scope === nodeAtPosition.id) {
console.log('NODE IN SCOPE', node)
}
}
}
}
}
*/
} else {
const cursorPosition = this.props.editorAPI.getCursorPosition()
const nodesAtPosition = await this.props.plugin.call('contextualListener', 'nodesAtEditorPosition', cursorPosition)
nodes = []
console.log('NODES AT POSITION', nodesAtPosition)
for (const node of nodesAtPosition) {
const nodesOfScope = await this.props.plugin.call('contextualListener', 'nodesWithScope', node.id)
nodes = [...nodes, ...nodesOfScope]
}
for (const node of nodesAtPosition) {
const baseContracts = await getlinearizedBaseContracts(node)
for (const baseContract of baseContracts) {
nodes = [...nodes, ...baseContract.nodes]
}
}
//nodes = await this.props.plugin.call('contextualListener', 'getNodes')
}
console.log('WORD', word, wordAt)
console.log('NODES', nodes)
console.log('NODES', Object.values(nodes))
const getLinks = async (node: any) => {
const position = await this.props.plugin.call('contextualListener', 'positionOfDefinition', node)
const lastCompilationResult = await this.props.plugin.call('contextualListener', 'getLastCompilationResult')
const filename = lastCompilationResult.getSourceName(position.file)
console.log(filename, position)
const lineColumn = await this.props.plugin.call('offsetToLineColumnConverter', 'offsetToLineColumn',
position,
position.file,
@ -95,30 +185,30 @@ export class RemixCompletionProvider {
}
const suggestions = []
for(const node of Object.values(nodes) as any[]){
for (const node of Object.values(nodes) as any[]) {
if(!node.name) continue
if (node.nodeType === 'VariableDeclaration') {
const completion = {
label: {label: `"${node.name}"`, description: await getLinks(node), detail: ` ${await getVariableDeclaration(node)}`},
label: { label: `"${node.name}"`, description: await getLinks(node), detail: ` ${await getVariableDeclaration(node)}` },
kind: this.monaco.languages.CompletionItemKind.Variable,
insertText: node.name,
range: range,
documentation: await getDocs(node)
}
suggestions.push(completion)
} else
if (node.nodeType === 'FunctionDefinition') {
} else if (node.nodeType === 'FunctionDefinition') {
const completion = {
label: {label: `"${node.name}"`, description: await getLinks(node), detail: ` -> ${node.name} ${await getParamaters(node.parameters)}`},
label: { label: `"${node.name}"`, description: await getLinks(node), detail: ` -> ${node.name} ${await getParamaters(node.parameters)}` },
kind: this.monaco.languages.CompletionItemKind.Function,
insertText: `${node.name} ${await completeParameters(node.parameters)}`,
insertText: `${node.name}${await completeParameters(node.parameters)};`,
range: range,
documentation: await getDocs(node)
}
suggestions.push(completion)
} else if
(node.nodeType === 'ContractDefinition') {
(node.nodeType === 'ContractDefinition') {
const completion = {
label: {label: `"${node.name}"`, description: await getLinks(node), detail: ` ${node.name}`},
label: { label: `"${node.name}"`, description: await getLinks(node), detail: ` ${node.name}` },
kind: this.monaco.languages.CompletionItemKind.Interface,
insertText: node.name,
range: range,
@ -126,9 +216,9 @@ export class RemixCompletionProvider {
}
suggestions.push(completion)
} else if
(node.nodeType === 'StructDefinition') {
(node.nodeType === 'StructDefinition') {
const completion = {
label: {label: `"${node.name}"`, description: await getLinks(node), detail: ` ${node.name}`},
label: { label: `"${node.name}"`, description: await getLinks(node), detail: ` ${node.name}` },
kind: this.monaco.languages.CompletionItemKind.Struct,
insertText: node.name,
range: range,
@ -136,9 +226,9 @@ export class RemixCompletionProvider {
}
suggestions.push(completion)
} else if
(node.nodeType === 'EnumDefinition') {
(node.nodeType === 'EnumDefinition') {
const completion = {
label: {label: `"${node.name}"`, description: await getLinks(node), detail: ` ${node.name}`},
label: { label: `"${node.name}"`, description: await getLinks(node), detail: ` ${node.name}` },
kind: this.monaco.languages.CompletionItemKind.Enum,
insertText: node.name,
range: range,
@ -146,9 +236,9 @@ export class RemixCompletionProvider {
}
suggestions.push(completion)
} else if
(node.nodeType === 'EventDefinition') {
(node.nodeType === 'EventDefinition') {
const completion = {
label: {label: `"${node.name}"`, description: await getLinks(node), detail: ` ${node.name}`},
label: { label: `"${node.name}"`, description: await getLinks(node), detail: ` ${node.name}` },
kind: this.monaco.languages.CompletionItemKind.Event,
insertText: node.name,
range: range,
@ -156,9 +246,9 @@ export class RemixCompletionProvider {
}
suggestions.push(completion)
} else if
(node.nodeType === 'ModifierDefinition') {
(node.nodeType === 'ModifierDefinition') {
const completion = {
label: {label: `"${node.name}"`, description: await getLinks(node), detail: ` ${node.name}`},
label: { label: `"${node.name}"`, description: await getLinks(node), detail: ` ${node.name}` },
kind: this.monaco.languages.CompletionItemKind.Method,
insertText: node.name,
range: range,

@ -10,6 +10,8 @@ export class RemixHoverProvider {
}
provideHover = async function (model: any, position: any) {
console.log('HOVERING')
return await this.run(model, position)
return new Promise((resolve, reject) => {
this.props.plugin.once('contextualListener', 'astFinished', async () => {
console.log('AST FINISHED')
@ -22,8 +24,8 @@ export class RemixHoverProvider {
async run(model: any, position: any) {
const cursorPosition = this.props.editorAPI.getHoverPosition(position)
const nodeDefinition = await this.props.plugin.call('contextualListener', 'definitionAtPosition', cursorPosition)
console.log(nodeDefinition)
const nodeAtPosition = await this.props.plugin.call('contextualListener', 'definitionAtPosition', cursorPosition)
console.log(nodeAtPosition)
const contents = []
const getDocs = async (node: any) => {
@ -39,6 +41,20 @@ export class RemixHoverProvider {
}
}
const getScope = async (node: any) => {
if (node.id) {
contents.push({
value: `id: ${node.id}`
})
}
if (node.scope) {
contents.push({
value: `scope: ${node.scope}`
})
}
}
const getLinks = async (node: any) => {
const position = await this.props.plugin.call('contextualListener', 'positionOfDefinition', node)
const lastCompilationResult = await this.props.plugin.call('contextualListener', 'getLastCompilationResult')
@ -101,50 +117,50 @@ export class RemixHoverProvider {
return ''
}
if (!nodeDefinition) {
if (!nodeAtPosition) {
contents.push({
value: 'No definition found. Please compile the source code.'
})
}
if (nodeDefinition) {
if (nodeDefinition.absolutePath) {
const target = await this.props.plugin.call('fileManager', 'getPathFromUrl', nodeDefinition.absolutePath)
if (target.file !== nodeDefinition.absolutePath) {
if (nodeAtPosition) {
if (nodeAtPosition.absolutePath) {
const target = await this.props.plugin.call('fileManager', 'getPathFromUrl', nodeAtPosition.absolutePath)
if (target.file !== nodeAtPosition.absolutePath) {
contents.push({
value: `${target.file}`
})
}
contents.push({
value: `${nodeDefinition.absolutePath}`
value: `${nodeAtPosition.absolutePath}`
})
}
if (nodeDefinition.typeDescriptions && nodeDefinition.nodeType === 'VariableDeclaration') {
if (nodeAtPosition.typeDescriptions && nodeAtPosition.nodeType === 'VariableDeclaration') {
contents.push({
value: await getVariableDeclaration(nodeDefinition)
value: await getVariableDeclaration(nodeAtPosition)
})
}
else if (nodeDefinition.typeDescriptions && nodeDefinition.nodeType === 'ElementaryTypeName') {
else if (nodeAtPosition.typeDescriptions && nodeAtPosition.nodeType === 'ElementaryTypeName') {
contents.push({
value: `${nodeDefinition.typeDescriptions.typeString}`
value: `${nodeAtPosition.typeDescriptions.typeString}`
})
} else if (nodeDefinition.nodeType === 'FunctionDefinition') {
} else if (nodeAtPosition.nodeType === 'FunctionDefinition') {
contents.push({
value: `function ${nodeDefinition.name} ${await getParamaters(nodeDefinition.parameters)} ${nodeDefinition.visibility} ${nodeDefinition.stateMutability}${await getOverrides(nodeDefinition)} returns ${await getParamaters(nodeDefinition.returnParameters)}`
value: `function ${nodeAtPosition.name} ${await getParamaters(nodeAtPosition.parameters)} ${nodeAtPosition.visibility} ${nodeAtPosition.stateMutability}${await getOverrides(nodeAtPosition)} returns ${await getParamaters(nodeAtPosition.returnParameters)}`
})
} else if (nodeDefinition.nodeType === 'ContractDefinition') {
} else if (nodeAtPosition.nodeType === 'ContractDefinition') {
contents.push({
value: `${nodeDefinition.contractKind} ${nodeDefinition.name} ${await getlinearizedBaseContracts(nodeDefinition)}`
value: `${nodeAtPosition.contractKind} ${nodeAtPosition.name} ${await getlinearizedBaseContracts(nodeAtPosition)}`
})
} else {
contents.push({
value: `${nodeDefinition.nodeType}`
value: `${nodeAtPosition.nodeType}`
})
}
@ -152,9 +168,9 @@ export class RemixHoverProvider {
for (const key in contents) {
contents[key].value = '```remix-solidity\n' + contents[key].value + '\n```'
}
getLinks(nodeDefinition)
getDocs(nodeDefinition)
getLinks(nodeAtPosition)
getDocs(nodeAtPosition)
getScope(nodeAtPosition)
}

@ -156,13 +156,11 @@ export const loadTypes = async (monaco) => {
// @ts-ignore
const versionEthers = await import('raw-loader!ethers/lib/_version.d.ts')
versionEthers.default = versionEthers.default.replace(/@ethersproject\//g, '@ethersproject_')
console.log(versionEthers.default)
monaco.languages.typescript.typescriptDefaults.addExtraLib(versionEthers.default, `file:///node_modules/@types/_version-ethers-lib/index.d.ts`)
// @ts-ignore
const utilEthers = await import('raw-loader!ethers/lib/utils.d.ts')
utilEthers.default = utilEthers.default.replace(/@ethersproject\//g, '@ethersproject_')
console.log(utilEthers.default)
monaco.languages.typescript.typescriptDefaults.addExtraLib(utilEthers.default, `file:///node_modules/@types/utils-ethers-lib/index.d.ts`)
// @ts-ignore
@ -171,14 +169,12 @@ export const loadTypes = async (monaco) => {
ethers.default = ethers.default.replace(/.\/_version/g, '_version-ethers-lib')
ethers.default = ethers.default.replace(/.\/ethers/g, 'ethers-lib')
ethers.default = ethers.default.replace(/@ethersproject\//g, '@ethersproject_')
console.log(ethers.default)
monaco.languages.typescript.typescriptDefaults.addExtraLib(ethers.default, `file:///node_modules/@types/ethers-lib/index.d.ts`)
// @ts-ignore
const indexEthers = await import('raw-loader!ethers/lib/index.d.ts')
indexEthers.default = indexEthers.default.replace(/.\/ethers/g, 'ethers-lib')
indexEthers.default = indexEthers.default.replace(/@ethersproject\//g, '@ethersproject_')
console.log(indexEthers.default)
monaco.languages.typescript.typescriptDefaults.addExtraLib(indexEthers.default, `file:///node_modules/@types/ethers/index.d.ts`)
// Web3
@ -222,5 +218,4 @@ export const loadTypes = async (monaco) => {
}
`
monaco.languages.typescript.typescriptDefaults.addExtraLib(indexRemixApi)
console.log('loaded monaco types')
}
Loading…
Cancel
Save