pull/5370/head
filip mertens 2 years ago
parent a52e530c60
commit 1fe8525209
  1. 4
      apps/remix-ide/src/app/editor/editor.js
  2. 15
      apps/remix-ide/src/app/plugins/parser/code-parser.tsx
  3. 54
      apps/remix-ide/src/app/plugins/parser/services/antlr-worker.ts
  4. 136
      apps/remix-ide/src/app/plugins/parser/services/code-parser-antlr-service.ts
  5. 1948
      apps/remix-ide/src/assets/js/parser/antlr.js
  6. 6
      apps/remix-ide/src/assets/js/parser/antlr.js.map
  7. 42251
      apps/remix-ide/src/assets/js/parser/index.iife.js
  8. 7
      apps/remix-ide/src/assets/js/parser/index.iife.js.map
  9. 2
      apps/remix-ide/src/index.html
  10. 118
      libs/remix-ui/editor/src/lib/providers/completionProvider.ts
  11. 2
      libs/remix-ui/editor/src/lib/providers/definitionProvider.ts
  12. 6
      libs/remix-ui/editor/src/lib/remix-ui-editor.tsx

@ -367,8 +367,8 @@ class Editor extends Plugin {
/** /**
* The position of the cursor * The position of the cursor
*/ */
getCursorPosition () { getCursorPosition (offset = true) {
return this.api.getCursorPosition() return this.api.getCursorPosition(offset)
} }
/** /**

@ -57,8 +57,6 @@ interface codeParserIndex {
export class CodeParser extends Plugin { export class CodeParser extends Plugin {
antlrParserResult: antlr.ParseResult // contains the simple parsed AST for the current file
compilerAbstract: CompilerAbstract compilerAbstract: CompilerAbstract
currentFile: string currentFile: string
nodeIndex: codeParserIndex nodeIndex: codeParserIndex
@ -90,10 +88,9 @@ export class CodeParser extends Plugin {
async handleChangeEvents() { async handleChangeEvents() {
const completionSettings = await this.call('config', 'getAppParameter', 'auto-completion') const completionSettings = await this.call('config', 'getAppParameter', 'auto-completion')
if (completionSettings) { if (completionSettings) {
// current timestamp this.antlrService.enableWorker()
console.log('get ast', Date.now()) } else {
//this.antlrService.getCurrentFileAST() this.antlrService.disableWorker()
console.log('done', Date.now())
} }
const showGasSettings = await this.call('config', 'getAppParameter', 'show-gas') const showGasSettings = await this.call('config', 'getAppParameter', 'show-gas')
const showErrorSettings = await this.call('config', 'getAppParameter', 'display-errors') const showErrorSettings = await this.call('config', 'getAppParameter', 'display-errors')
@ -127,6 +124,10 @@ export class CodeParser extends Plugin {
this.on('fileManager', 'currentFileChanged', async () => { this.on('fileManager', 'currentFileChanged', async () => {
await this.call('editor', 'discardLineTexts') await this.call('editor', 'discardLineTexts')
const completionSettings = await this.call('config', 'getAppParameter', 'auto-completion')
if (completionSettings) {
this.antlrService.getCurrentFileAST()
}
await this.handleChangeEvents() await this.handleChangeEvents()
}) })
@ -408,6 +409,7 @@ export class CodeParser extends Plugin {
return nodeDefinition return nodeDefinition
} else { } else {
const astNodes = await this.antlrService.listAstNodes() const astNodes = await this.antlrService.listAstNodes()
if (astNodes && astNodes.length) {
for (const node of astNodes) { for (const node of astNodes) {
if (node.range[0] <= position && node.range[1] >= position) { if (node.range[0] <= position && node.range[1] >= position) {
if (nodeDefinition && nodeDefinition.range[0] < node.range[0]) { if (nodeDefinition && nodeDefinition.range[0] < node.range[0]) {
@ -422,6 +424,7 @@ export class CodeParser extends Plugin {
} }
return nodeDefinition return nodeDefinition
} }
}
} }

@ -0,0 +1,54 @@
let parser: any
// 'DedicatedWorkerGlobalScope' object (the Worker global scope) is accessible through the self keyword
// 'dom' and 'webworker' library files can't be included together https://github.com/microsoft/TypeScript/issues/20595
export default function (self) { // eslint-disable-line @typescript-eslint/explicit-module-boundary-types
self.addEventListener('message', (e) => {
const data: any = e.data
switch (data.cmd) {
case 'load':
{
delete self.Module
// NOTE: workaround some browsers?
self.Module = undefined
// importScripts() method of synchronously imports one or more scripts into the worker's scope
self.importScripts(e.data.url)
// @ts-ignore
parser = SolidityParser as any;
self.postMessage({
cmd: 'loaded',
})
break
}
case 'parse':
if (data.text && parser) {
try {
let startTime = performance.now()
const blocks = parser.parseBlock(data.text, { loc: true, range: true, tolerant: true })
const blockDuration = performance.now() - startTime
startTime = performance.now()
const ast = parser.parse(data.text, { loc: true, range: true, tolerant: true })
const endTime = performance.now()
self.postMessage({
cmd: 'parsed',
timestamp: data.timestamp,
ast,
text: data.text,
file: data.file,
duration: endTime - startTime,
blockDuration,
blocks
})
} catch (e) {
// do nothing
}
}
break
}
}, false)
}

@ -3,18 +3,109 @@
import { AstNode } from "@remix-project/remix-solidity-ts" import { AstNode } from "@remix-project/remix-solidity-ts"
import { CodeParser } from "../code-parser" import { CodeParser } from "../code-parser"
import { antlr } from '../types' import { antlr } from '../types'
import work from 'webworkify-webpack'
const SolidityParser = (window as any).SolidityParser = (window as any).SolidityParser || [] const SolidityParser = (window as any).SolidityParser = (window as any).SolidityParser || []
interface BlockDefinition {
end: number
endColumn: number
endLine: number
name: string
parent: string
start: number
startColumn: number
startLine: number
type: string
}
export default class CodeParserAntlrService { export default class CodeParserAntlrService {
plugin: CodeParser plugin: CodeParser
worker: Worker
parserStartTime: number = 0
workerTimer: NodeJS.Timer
parserTreshHold: number = 10
cache: {
[name: string]: {
text: string,
ast: antlr.ParseResult | null,
duration?: number,
blockDuration?: number,
parsingEnabled?: boolean,
blocks?: BlockDefinition[]
}
} = {};
constructor(plugin: CodeParser) { constructor(plugin: CodeParser) {
this.plugin = plugin this.plugin = plugin
this.createWorker()
} }
/* createWorker() {
* simple parsing is used to quickly parse the current file or a text source without using the compiler or having to resolve imports this.worker = work(require.resolve('./antlr-worker'));
*/ this.worker.postMessage({
cmd: 'load',
url: document.location.protocol + '//' + document.location.host + '/assets/js/parser/antlr.js',
});
const self = this
this.worker.addEventListener('message', function (ev) {
switch (ev.data.cmd) {
case 'parsed':
if (ev.data.ast && self.parserStartTime === ev.data.timestamp) {
self.setFileParsingState(ev.data.file, ev.data.blockDuration)
self.cache[ev.data.file] = {
...self.cache[ev.data.file],
text: ev.data.text,
ast: ev.data.ast,
duration: ev.data.duration,
blockDuration: ev.data.blockDuration,
blocks: ev.data.blocks,
}
}
break;
}
});
}
setFileParsingState(file: string, duration: number) {
if (this.cache[file]) {
if (this.cache[file].blockDuration) {
if(this.cache[file].blockDuration > this.parserTreshHold && duration > this.parserTreshHold) {
this.cache[file].parsingEnabled = false
this.plugin.call('notification', 'toast', `This file is big so some autocomplete features will be disabled.`)
} else{
this.cache[file].parsingEnabled = true
}
}
}
}
enableWorker() {
if (!this.workerTimer) {
this.workerTimer = setInterval(() => {
this.getCurrentFileAST()
}, 5000)
}
}
disableWorker() {
clearInterval(this.workerTimer)
}
async parseWithWorker(text: string, file: string) {
this.parserStartTime = Date.now()
this.worker.postMessage({
cmd: 'parse',
text,
timestamp: this.parserStartTime,
file,
parsingEnabled: (this.cache[file] && this.cache[file].parsingEnabled) || true
});
}
async parseSolidity(text: string) { async parseSolidity(text: string) {
const ast: antlr.ParseResult = (SolidityParser as any).parse(text, { loc: true, range: true, tolerant: true }) const ast: antlr.ParseResult = (SolidityParser as any).parse(text, { loc: true, range: true, tolerant: true })
@ -28,17 +119,30 @@ export default class CodeParserAntlrService {
* @returns * @returns
*/ */
async getCurrentFileAST(text: string | null = null) { async getCurrentFileAST(text: string | null = null) {
try {
this.plugin.currentFile = await this.plugin.call('fileManager', 'file') this.plugin.currentFile = await this.plugin.call('fileManager', 'file')
if (this.plugin.currentFile && this.plugin.currentFile.endsWith('.sol')) { if (this.plugin.currentFile && this.plugin.currentFile.endsWith('.sol')) {
if (!this.plugin.currentFile) return if (!this.plugin.currentFile) return
const fileContent = text || await this.plugin.call('fileManager', 'readFile', this.plugin.currentFile) const fileContent = text || await this.plugin.call('fileManager', 'readFile', this.plugin.currentFile)
if (!this.cache[this.plugin.currentFile]) {
this.cache[this.plugin.currentFile] = {
text: '',
ast: null,
parsingEnabled: true
}
}
if (this.cache[this.plugin.currentFile] && this.cache[this.plugin.currentFile].text !== fileContent) {
try { try {
const ast = (SolidityParser as any).parse(fileContent, { loc: true, range: true, tolerant: true }) await this.parseWithWorker(fileContent, this.plugin.currentFile)
this.plugin.antlrParserResult = ast
} catch (e) { } catch (e) {
// do nothing // do nothing
} }
return this.plugin.antlrParserResult } else {
// do nothing
}
}
} catch (e) {
// do nothing
} }
} }
@ -48,9 +152,10 @@ export default class CodeParserAntlrService {
* @returns * @returns
*/ */
async listAstNodes() { async listAstNodes() {
await this.getCurrentFileAST(); this.plugin.currentFile = await this.plugin.call('fileManager', 'file')
if (!this.cache[this.plugin.currentFile]) return
const nodes: AstNode[] = []; const nodes: AstNode[] = [];
(SolidityParser as any).visit(this.plugin.antlrParserResult, { (SolidityParser as any).visit(this.cache[this.plugin.currentFile].ast, {
StateVariableDeclaration: (node: antlr.StateVariableDeclaration) => { StateVariableDeclaration: (node: antlr.StateVariableDeclaration) => {
if (node.variables) { if (node.variables) {
for (const variable of node.variables) { for (const variable of node.variables) {
@ -132,11 +237,19 @@ export default class CodeParserAntlrService {
*/ */
async getCurrentFileBlocks(text: string | null = null) { async getCurrentFileBlocks(text: string | null = null) {
this.plugin.currentFile = await this.plugin.call('fileManager', 'file') this.plugin.currentFile = await this.plugin.call('fileManager', 'file')
if (this.cache[this.plugin.currentFile]) {
if (!this.cache[this.plugin.currentFile].parsingEnabled) {
return
}
}
if (this.plugin.currentFile && this.plugin.currentFile.endsWith('.sol')) { if (this.plugin.currentFile && this.plugin.currentFile.endsWith('.sol')) {
if (!this.plugin.currentFile) return if (!this.plugin.currentFile) return
const fileContent = text || await this.plugin.call('fileManager', 'readFile', this.plugin.currentFile) const fileContent = text || await this.plugin.call('fileManager', 'readFile', this.plugin.currentFile)
try { try {
const startTime = Date.now()
const blocks = (SolidityParser as any).parseBlock(fileContent, { loc: true, range: true, tolerant: true }) const blocks = (SolidityParser as any).parseBlock(fileContent, { loc: true, range: true, tolerant: true })
this.setFileParsingState(this.plugin.currentFile, Date.now() - startTime)
if(blocks) this.cache[this.plugin.currentFile].blocks = blocks
return blocks return blocks
} catch (e) { } catch (e) {
// do nothing // do nothing
@ -152,11 +265,12 @@ export default class CodeParserAntlrService {
* @return {any} * @return {any}
* */ * */
async getANTLRBlockAtPosition(position: any, text: string = null) { async getANTLRBlockAtPosition(position: any, text: string = null) {
const blocks = await this.getCurrentFileBlocks(text) const blocks: any[] = await this.getCurrentFileBlocks(text)
const walkAst = (blocks) => { const walkAst = (blocks) => {
let nodeFound = null let nodeFound = null
for (const object of blocks) { for (const object of blocks) {
if(object.start <= position && object.end >= position){ if (object.start <= position) {
nodeFound = object nodeFound = object
break break
} }
@ -164,8 +278,8 @@ export default class CodeParserAntlrService {
return nodeFound return nodeFound
} }
if (!blocks) return if (!blocks) return
blocks.reverse()
const block = walkAst(blocks) const block = walkAst(blocks)
console.log(block)
return block return block
} }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -41,7 +41,7 @@
<script type="text/javascript" src="assets/js/loader.js"></script> <script type="text/javascript" src="assets/js/loader.js"></script>
<script src="https://kit.fontawesome.com/41dd021e94.js" crossorigin="anonymous"></script> <script src="https://kit.fontawesome.com/41dd021e94.js" crossorigin="anonymous"></script>
<script type="text/javascript" src="assets/js/intro.min.js"></script> <script type="text/javascript" src="assets/js/intro.min.js"></script>
<script type="text/javascript" src="assets/js/parser/index.iife.js"></script> <script type="text/javascript" src="assets/js/parser/antlr.js"></script>
</body> </body>
</html> </html>

@ -1,4 +1,3 @@
import { sourceMappingDecoder } from "@remix-project/remix-debug"
import { AstNode } from "@remix-project/remix-solidity-ts" import { AstNode } from "@remix-project/remix-solidity-ts"
import { isArray } from "lodash" import { isArray } from "lodash"
import { editor, languages, Position } from "monaco-editor" import { editor, languages, Position } from "monaco-editor"
@ -10,6 +9,7 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
props: EditorUIProps props: EditorUIProps
monaco: any monaco: any
maximumItemsForContractCompletion = 100
constructor(props: any, monaco: any) { constructor(props: any, monaco: any) {
this.props = props this.props = props
@ -21,6 +21,7 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
const completionSettings = await this.props.plugin.call('config', 'getAppParameter', 'settings/auto-completion') const completionSettings = await this.props.plugin.call('config', 'getAppParameter', 'settings/auto-completion')
if (!completionSettings) return if (!completionSettings) return
const word = model.getWordUntilPosition(position); const word = model.getWordUntilPosition(position);
const range = { const range = {
startLineNumber: position.lineNumber, startLineNumber: position.lineNumber,
@ -48,21 +49,17 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
if (globalCompletion) { if (globalCompletion) {
dotCompleted = true dotCompleted = true
suggestions = [...suggestions, ...globalCompletion] suggestions = [...suggestions, ...globalCompletion]
setTimeout(() => {
// eslint-disable-next-line no-debugger
// debugger
}, 2000)
} }
// handle completion for global THIS. // handle completion for global THIS.
if (lastNodeInExpression.name === 'this') { if (lastNodeInExpression.name === 'this') {
dotCompleted = true dotCompleted = true
nodes = [...nodes, ...await this.getThisCompletions(position)] nodes = [...nodes, ...await this.getThisCompletions()]
} }
// handle completion for other dot completions // handle completion for other dot completions
if (expressionElements.length > 1 && !dotCompleted) { if (expressionElements.length > 1 && !dotCompleted) {
const nameOfLastTypedExpression = lastNodeInExpression.name || lastNodeInExpression.memberName const nameOfLastTypedExpression = lastNodeInExpression.name || lastNodeInExpression.memberName
const dotCompletions = await this.getDotCompletions(position, nameOfLastTypedExpression, range) const dotCompletions = await this.getDotCompletions(nameOfLastTypedExpression, range)
nodes = [...nodes, ...dotCompletions.nodes] nodes = [...nodes, ...dotCompletions.nodes]
suggestions = [...suggestions, ...dotCompletions.suggestions] suggestions = [...suggestions, ...dotCompletions.suggestions]
} }
@ -77,7 +74,8 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
...GetGlobalFunctions(range, this.monaco), ...GetGlobalFunctions(range, this.monaco),
...GeCompletionUnits(range, this.monaco), ...GeCompletionUnits(range, this.monaco),
] ]
let contractCompletions = await this.getContractCompletions(position)
let contractCompletions = await this.getContractCompletions()
// we can't have external nodes without using this. // we can't have external nodes without using this.
contractCompletions = contractCompletions.filter(node => { contractCompletions = contractCompletions.filter(node => {
@ -86,13 +84,14 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
} }
return true return true
}) })
nodes = [...nodes, ...contractCompletions] nodes = [...nodes, ...contractCompletions]
} }
// remove duplicates // remove duplicates
const nodeIds = {}; const nodeIds = {};
const filteredNodes = nodes.filter((node) => { let filteredNodes = nodes.filter((node) => {
if (node.id) { if (node.id) {
if (nodeIds[node.id]) { if (nodeIds[node.id]) {
return false; return false;
@ -102,6 +101,12 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
return true; return true;
}); });
// truncate for performance
if (filteredNodes.length > this.maximumItemsForContractCompletion) {
await this.props.plugin.call('notification', 'toast', `Too many completion items. Only ${this.maximumItemsForContractCompletion} items will be shown.`)
filteredNodes = filteredNodes.slice(0, this.maximumItemsForContractCompletion)
}
const getNodeLink = async (node: any) => { const getNodeLink = async (node: any) => {
return await this.props.plugin.call('codeParser', 'getNodeLink', node) return await this.props.plugin.call('codeParser', 'getNodeLink', node)
} }
@ -228,68 +233,13 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
} }
} }
private getBlockNodesAtPosition = async (position: Position, ANTLRBlock) => { private getContractCompletions = async () => {
let nodes: any[] = []
const cursorPosition = this.props.editorAPI.getCursorPosition()
const nodesAtPosition = await this.props.plugin.call('codeParser', 'nodesAtPosition', cursorPosition)
// if the block has a name and a type we can maybe find it in the contract nodes
const fileNodes = await this.props.plugin.call('codeParser', 'getCurrentFileNodes')
if (isArray(nodesAtPosition) && nodesAtPosition.length) {
for (const node of nodesAtPosition) {
// try to find the real block in the AST and get the nodes in that scope
if (node.nodeType === 'ContractDefinition') {
const contractNodes = fileNodes.contracts[node.name].contractNodes
for (const contractNode of Object.values(contractNodes)) {
if (contractNode['name'] === ANTLRBlock.name
|| (contractNode['kind'] === 'constructor' && ANTLRBlock.name === null )
) {
let nodeOfScope = await this.props.plugin.call('codeParser', 'getNodesWithScope', (contractNode as any).id)
nodes = [...nodes, ...nodeOfScope]
if (contractNode['body']) {
nodeOfScope = await this.props.plugin.call('codeParser', 'getNodesWithScope', (contractNode['body'] as any).id)
nodes = [...nodes, ...nodeOfScope]
}
}
}
}
// blocks can have statements
/*
if (node.statements){
console.log('statements', node.statements)
for (const statement of node.statements) {
if(statement.expression){
const declaration = await this.props.plugin.call('codeParser', 'declarationOf', statement.expression)
declaration.outSideBlock = true
nodes = [...nodes, declaration]
}
}
}
*/
}
}
// we are only interested in nodes that are in the same block as the cursor
nodes = nodes.filter(node => {
if (node.src) {
const position = sourceMappingDecoder.decode(node.src)
if (position.start >= ANTLRBlock.start && (position.start + position.length) <= ANTLRBlock.end) {
return true
}
}
if(node.outSideBlock){ return true }
return false
})
return nodes;
}
private getContractCompletions = async (position: Position) => {
let nodes: any[] = [] let nodes: any[] = []
const cursorPosition = this.props.editorAPI.getCursorPosition() const cursorPosition = this.props.editorAPI.getCursorPosition()
let nodesAtPosition = await this.props.plugin.call('codeParser', 'nodesAtPosition', cursorPosition) let nodesAtPosition = await this.props.plugin.call('codeParser', 'nodesAtPosition', cursorPosition)
// if no nodes exits at position, try to get the block of which the position is in // if no nodes exits at position, try to get the block of which the position is in
const block = await this.props.plugin.call('codeParser', 'getANTLRBlockAtPosition', cursorPosition, null) const block = await this.props.plugin.call('codeParser', 'getANTLRBlockAtPosition', cursorPosition, null)
const fileNodes = await this.props.plugin.call('codeParser', 'getCurrentFileNodes')
if (!nodesAtPosition.length) { if (!nodesAtPosition.length) {
if (block) { if (block) {
nodesAtPosition = await this.props.plugin.call('codeParser', 'nodesAtPosition', block.start) nodesAtPosition = await this.props.plugin.call('codeParser', 'nodesAtPosition', block.start)
@ -301,13 +251,26 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
for (const node of nodesAtPosition) { for (const node of nodesAtPosition) {
if (node.nodeType === 'ContractDefinition') { if (node.nodeType === 'ContractDefinition') {
contractNode = node contractNode = node
const fileNodes = await this.props.plugin.call('codeParser', 'getCurrentFileNodes')
const contractNodes = fileNodes.contracts[node.name] const contractNodes = fileNodes.contracts[node.name]
nodes = [...Object.values(contractNodes.contractScopeNodes), ...nodes] nodes = [...Object.values(contractNodes.contractScopeNodes), ...nodes]
nodes = [...Object.values(contractNodes.baseNodesWithBaseContractScope), ...nodes] nodes = [...Object.values(contractNodes.baseNodesWithBaseContractScope), ...nodes]
nodes = [...Object.values(fileNodes.imports), ...nodes] nodes = [...Object.values(fileNodes.imports), ...nodes]
// at the nodes at the block itself // add the nodes at the block itself
nodes = [...nodes, ...await this.getBlockNodesAtPosition(position, block)] if (node.nodeType === 'ContractDefinition' && block && block.name) {
const contractNodes = fileNodes.contracts[node.name].contractNodes
for (const contractNode of Object.values(contractNodes)) {
if (contractNode['name'] === block.name
|| (contractNode['kind'] === 'constructor' && block.name === 'constructor')
) {
let nodeOfScope = await this.props.plugin.call('codeParser', 'getNodesWithScope', (contractNode as any).id)
nodes = [...nodes, ...nodeOfScope]
if (contractNode['body']) {
nodeOfScope = await this.props.plugin.call('codeParser', 'getNodesWithScope', (contractNode['body'] as any).id)
nodes = [...nodes, ...nodeOfScope]
}
}
}
}
// filter private nodes, only allow them when contract ID is the same as the current contract // filter private nodes, only allow them when contract ID is the same as the current contract
nodes = nodes.filter(node => { nodes = nodes.filter(node => {
if (node.visibility) { if (node.visibility) {
@ -323,14 +286,17 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
} }
} else { } else {
// get all the nodes from a simple code parser which only parses the current file // get all the nodes from a simple code parser which only parses the current file
nodes = [...nodes, ...await this.props.plugin.call('codeParser', 'listAstNodes')] const allNodesFromAntlr = await this.props.plugin.call('codeParser', 'listAstNodes')
if (allNodesFromAntlr) {
nodes = [...nodes, ...allNodesFromAntlr]
}
} }
return nodes return nodes
} }
private getThisCompletions = async (position: Position) => { private getThisCompletions = async () => {
let nodes: any[] = [] let nodes: any[] = []
let thisCompletionNodes = await this.getContractCompletions(position) let thisCompletionNodes = await this.getContractCompletions()
const allowedTypesForThisCompletion = ['VariableDeclaration', 'FunctionDefinition'] const allowedTypesForThisCompletion = ['VariableDeclaration', 'FunctionDefinition']
// with this. you can't have internal nodes and no contractDefinitions // with this. you can't have internal nodes and no contractDefinitions
thisCompletionNodes = thisCompletionNodes.filter(node => { thisCompletionNodes = thisCompletionNodes.filter(node => {
@ -343,15 +309,11 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
return true return true
}) })
nodes = [...nodes, ...thisCompletionNodes] nodes = [...nodes, ...thisCompletionNodes]
setTimeout(() => {
// eslint-disable-next-line no-debugger
// debugger
}, 2000)
return nodes return nodes
} }
private getDotCompletions = async (position: Position, nameOfLastTypedExpression: string, range) => { private getDotCompletions = async (nameOfLastTypedExpression: string, range) => {
const contractCompletions = await this.getContractCompletions(position) const contractCompletions = await this.getContractCompletions()
let nodes: any[] = [] let nodes: any[] = []
let suggestions: monaco.languages.CompletionItem[] = [] let suggestions: monaco.languages.CompletionItem[] = []

@ -14,7 +14,7 @@ export class RemixDefinitionProvider implements monaco.languages.DefinitionProvi
async provideDefinition(model: monaco.editor.ITextModel, position: monaco.Position, token: monaco.CancellationToken): Promise<monaco.languages.Definition | monaco.languages.LocationLink[]> { async provideDefinition(model: monaco.editor.ITextModel, position: monaco.Position, token: monaco.CancellationToken): Promise<monaco.languages.Definition | monaco.languages.LocationLink[]> {
const cursorPosition = this.props.editorAPI.getCursorPosition() const cursorPosition = this.props.editorAPI.getCursorPosition()
const jumpLocation = await this.jumpToDefinition(cursorPosition) const jumpLocation = await this.jumpToDefinition(cursorPosition)
if(!jumpLocation || !jumpLocation.fileName) return []
return [{ return [{
uri: this.monaco.Uri.parse(jumpLocation.fileName), uri: this.monaco.Uri.parse(jumpLocation.fileName),
range: { range: {

@ -103,7 +103,7 @@ export interface EditorUIProps {
findMatches: (uri: string, value: string) => any findMatches: (uri: string, value: string) => any
getFontSize: () => number, getFontSize: () => number,
getValue: (uri: string) => string getValue: (uri: string) => string
getCursorPosition: () => number getCursorPosition: (offset?: boolean) => number | IPosition
getHoverPosition: (position: IPosition) => number getHoverPosition: (position: IPosition) => number
addDecoration: (marker: sourceMarker, filePath: string, typeOfDecoration: string) => DecorationsReturn addDecoration: (marker: sourceMarker, filePath: string, typeOfDecoration: string) => DecorationsReturn
clearDecorationsByPlugin: (filePath: string, plugin: string, typeOfDecoration: string, registeredDecorations: any, currentDecorations: any) => DecorationsReturn clearDecorationsByPlugin: (filePath: string, plugin: string, typeOfDecoration: string, registeredDecorations: any, currentDecorations: any) => DecorationsReturn
@ -476,11 +476,11 @@ export const EditorUI = (props: EditorUIProps) => {
} }
} }
props.editorAPI.getCursorPosition = () => { props.editorAPI.getCursorPosition = (offset:boolean = true) => {
if (!monacoRef.current) return if (!monacoRef.current) return
const model = editorModelsState[currentFileRef.current]?.model const model = editorModelsState[currentFileRef.current]?.model
if (model) { if (model) {
return model.getOffsetAt(editorRef.current.getPosition()) return offset? model.getOffsetAt(editorRef.current.getPosition()): editorRef.current.getPosition()
} }
} }

Loading…
Cancel
Save