Merge pull request #2917 from ethereum/importautocomplete

add imports to auto-complete
pull/2921/head^2
bunsenstraat 2 years ago committed by GitHub
commit 6916ebd7fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 24
      apps/remix-ide/src/app/plugins/parser/code-parser.tsx
  2. 80
      apps/remix-ide/src/app/plugins/parser/services/code-parser-compiler.ts
  3. 82
      apps/remix-ide/src/app/plugins/parser/services/code-parser-imports.ts
  4. 97
      libs/remix-ui/editor/src/lib/providers/completion/completionGlobals.ts
  5. 198
      libs/remix-ui/editor/src/lib/providers/completion/contracts/contracts.txt
  6. 26
      libs/remix-ui/editor/src/lib/providers/completionProvider.ts
  7. 18
      libs/remix-ui/editor/src/lib/providers/definitionProvider.ts
  8. 2
      libs/remix-ui/search/src/index.ts
  9. 5
      package.json
  10. 10
      yarn.lock

@ -6,6 +6,7 @@ import { CompilationResult } from '@remix-project/remix-solidity'
import CodeParserGasService from './services/code-parser-gas-service'
import CodeParserCompiler from './services/code-parser-compiler'
import CodeParserAntlrService from './services/code-parser-antlr-service'
import CodeParserImports, { CodeParserImportsData } from './services/code-parser-imports'
import React from 'react'
import { Profile } from '@remixproject/plugin-utils'
import { ContractDefinitionAstNode, EventDefinitionAstNode, FunctionCallAstNode, FunctionDefinitionAstNode, IdentifierAstNode, ImportDirectiveAstNode, ModifierDefinitionAstNode, SourceUnitAstNode, StructDefinitionAstNode, VariableDeclarationAstNode } from 'dist/libs/remix-analyzer/src/types'
@ -15,7 +16,7 @@ import { ParseResult } from './types/antlr-types'
const profile: Profile = {
name: 'codeParser',
methods: ['nodesAtPosition', 'getContractNodes', 'getCurrentFileNodes', 'getLineColumnOfNode', 'getLineColumnOfPosition', 'getFunctionParamaters', 'getDeclaration', 'getFunctionReturnParameters', 'getVariableDeclaration', 'getNodeDocumentation', 'getNodeLink', 'listAstNodes', 'getANTLRBlockAtPosition', 'getLastNodeInLine', 'resolveImports', 'parseSolidity', 'getNodesWithScope', 'getNodesWithName', 'getNodes', 'compile', 'getNodeById', 'getLastCompilationResult', 'positionOfDefinition', 'definitionAtPosition', 'jumpToDefinition', 'referrencesAtPosition', 'referencesOf', 'getActiveHighlights', 'gasEstimation', 'declarationOf', 'getGasEstimates'],
methods: ['nodesAtPosition', 'getContractNodes', 'getCurrentFileNodes', 'getLineColumnOfNode', 'getLineColumnOfPosition', 'getFunctionParamaters', 'getDeclaration', 'getFunctionReturnParameters', 'getVariableDeclaration', 'getNodeDocumentation', 'getNodeLink', 'listAstNodes', 'getANTLRBlockAtPosition', 'getLastNodeInLine', 'resolveImports', 'parseSolidity', 'getNodesWithScope', 'getNodesWithName', 'getNodes', 'compile', 'getNodeById', 'getLastCompilationResult', 'positionOfDefinition', 'definitionAtPosition', 'jumpToDefinition', 'referrencesAtPosition', 'referencesOf', 'getActiveHighlights', 'gasEstimation', 'declarationOf', 'getGasEstimates', 'getImports'],
events: [],
version: '0.0.1'
}
@ -70,12 +71,15 @@ export class CodeParser extends Plugin {
gasService: CodeParserGasService
compilerService: CodeParserCompiler
antlrService: CodeParserAntlrService
importService: CodeParserImports
parseSolidity: (text: string) => Promise<antlr.ParseResult>
getLastNodeInLine: (ast: string) => Promise<any>
listAstNodes: () => Promise<any>
getANTLRBlockAtPosition: (position: any, text?: string) => Promise<any>
getCurrentFileAST: (text?: string) => Promise<ParseResult>
getImports: () => Promise<CodeParserImportsData[]>
constructor(astWalker: any) {
super(profile)
@ -104,13 +108,14 @@ export class CodeParser extends Plugin {
this.gasService = new CodeParserGasService(this)
this.compilerService = new CodeParserCompiler(this)
this.antlrService = new CodeParserAntlrService(this)
this.importService = new CodeParserImports(this)
this.parseSolidity = this.antlrService.parseSolidity.bind(this.antlrService)
this.getLastNodeInLine = this.antlrService.getLastNodeInLine.bind(this.antlrService)
this.listAstNodes = this.antlrService.listAstNodes.bind(this.antlrService)
this.getANTLRBlockAtPosition = this.antlrService.getANTLRBlockAtPosition.bind(this.antlrService)
this.getCurrentFileAST = this.antlrService.getCurrentFileAST.bind(this.antlrService)
this.getImports = this.importService.getImports.bind(this.importService)
this.on('editor', 'didChangeFile', async (file) => {
await this.call('editor', 'discardLineTexts')
@ -119,9 +124,18 @@ export class CodeParser extends Plugin {
this.on('filePanel', 'setWorkspace', async () => {
await this.call('fileDecorator', 'clearFileDecorators')
await this.importService.setFileTree()
})
this.on('fileManager', 'fileAdded', async () => {
await this.importService.setFileTree()
})
this.on('fileManager', 'fileRemoved', async () => {
await this.importService.setFileTree()
})
this.on('fileManager', 'currentFileChanged', async () => {
await this.call('editor', 'discardLineTexts')
await this.handleChangeEvents()
@ -135,8 +149,6 @@ export class CodeParser extends Plugin {
}
/**
*
* @returns
@ -145,10 +157,6 @@ export class CodeParser extends Plugin {
return this.compilerAbstract
}
getSubNodes<T extends genericASTNode>(node: T): number[] {
return node.nodeType == "ContractDefinition" && node.contractDependencies;
}

@ -8,6 +8,7 @@ import { fileDecoration, fileDecorationType } from '@remix-ui/file-decorators'
import { sourceMappingDecoder } from '@remix-project/remix-debug'
import { CompilerRetriggerMode } from '@remix-project/remix-solidity-ts';
import { MarkerSeverity } from 'monaco-editor';
import { findLinesInStringWithMatch, SearchResultLine } from '@remix-ui/search'
type errorMarker = {
message: string
@ -43,34 +44,45 @@ export default class CodeParserCompiler {
this.errorState = true
const result = new CompilerAbstract('soljson', data, source, input)
let allErrors: errorMarker[] = []
if (data.errors) {
const sources = result.getSourceCode().sources
if (data.errors || data.error) {
const file = await this.plugin.call('fileManager', 'getCurrentFile')
const currentFileContent = await this.plugin.call('fileManager', 'readFile', file)
const sources = result.getSourceCode().sources || []
if (data.error) {
if (data.error.formattedMessage) {
// mark this file as error
const errorMarker = await this.createErrorMarker(data.error, file, { start: { line: 0, column: 0 }, end: { line: 0, column: 100 } })
allErrors = [...allErrors, errorMarker]
}
} else {
for (const error of data.errors) {
if (!error.sourceLocation) {
// mark this file as error
const errorMarker = await this.createErrorMarker(error, file, { start: { line: 0, column: 0 }, end: { line: 0, column: 100 } })
allErrors = [...allErrors, errorMarker]
} else {
const lineBreaks = sourceMappingDecoder.getLinebreakPositions(sources[error.sourceLocation.file].content)
const lineColumn = sourceMappingDecoder.convertOffsetToLineColumn({
start: error.sourceLocation.start,
length: error.sourceLocation.end - error.sourceLocation.start
}, lineBreaks)
const filePath = error.sourceLocation.file
const fileTarget = await this.plugin.call('fileManager', 'getUrlFromPath', filePath)
allErrors = [...allErrors, {
message: error.formattedMessage,
severity: error.severity === 'error' ? MarkerSeverity.Error : MarkerSeverity.Warning,
position: {
start: {
line: ((lineColumn.start && lineColumn.start.line) || 0) + 1,
column: ((lineColumn.start && lineColumn.start.column) || 0) + 1
},
end: {
line: ((lineColumn.end && lineColumn.end.line) || 0) + 1,
column: ((lineColumn.end && lineColumn.end.column) || 0) + 1
const importFilePositions = await this.getPositionForImportErrors(fileTarget.file, currentFileContent)
for (const importFilePosition of importFilePositions) {
for (const line of importFilePosition.lines) {
allErrors = [...allErrors, await this.createErrorMarker(error, file, line.position)]
}
}
allErrors = [...allErrors, await this.createErrorMarker(error, filePath, lineColumn)]
}
}
, file: filePath
}]
}
const displayErrors = await this.plugin.call('config', 'getAppParameter', 'display-errors')
if (displayErrors) await this.plugin.call('editor', 'addErrorMarker', allErrors)
this.addDecorators(allErrors, sources)
@ -131,7 +143,7 @@ export default class CodeParserCompiler {
"*": ["evm.gasEstimates"]
}
},
"evmVersion": state.evmVersion && state.evmVersion.toString() || "byzantium",
"evmVersion": state.evmVersion && state.evmVersion.toString() || "berlin",
}
}
@ -178,8 +190,9 @@ export default class CodeParserCompiler {
const decorators: fileDecoration[] = []
for (const fileName in sortedErrorsPerFiles) {
const errors = sortedErrorsPerFiles[fileName]
const fileTarget = await this.plugin.call('fileManager', 'getPathFromUrl', fileName)
const decorator: fileDecoration = {
path: fileName,
path: fileTarget.file,
isDirectory: false,
fileStateType: errors[0].severity == MarkerSeverity.Error ? fileDecorationType.Error : fileDecorationType.Warning,
fileStateLabelClass: errors[0].severity == MarkerSeverity.Error ? 'text-danger' : 'text-warning',
@ -193,8 +206,9 @@ export default class CodeParserCompiler {
decorators.push(decorator)
}
for (const fileName of filesWithOutErrors) {
const fileTarget = await this.plugin.call('fileManager', 'getPathFromUrl', fileName)
const decorator: fileDecoration = {
path: fileName,
path: fileTarget.file,
isDirectory: false,
fileStateType: fileDecorationType.None,
fileStateLabelClass: '',
@ -211,8 +225,27 @@ export default class CodeParserCompiler {
}
async createErrorMarker(error: any, filePath: string, lineColumn): Promise<errorMarker> {
return {
message: error.formattedMessage,
severity: error.severity === 'error' ? MarkerSeverity.Error : MarkerSeverity.Warning,
position: {
start: {
line: ((lineColumn.start && lineColumn.start.line) || 0) + 1,
column: ((lineColumn.start && lineColumn.start.column) || 0) + 1
},
end: {
line: ((lineColumn.end && lineColumn.end.line) || 0) + 1,
column: ((lineColumn.end && lineColumn.end.column) || 0) + 1
}
}
, file: filePath
}
}
async clearDecorators(sources: any) {
const decorators: fileDecoration[] = []
if (!sources) return
for (const fileName of Object.keys(sources)) {
const decorator: fileDecoration = {
path: fileName,
@ -232,4 +265,13 @@ export default class CodeParserCompiler {
await this.plugin.call('fileDecorator', 'setFileDecorators', decorators)
}
async getPositionForImportErrors(importedFileName: string, text: string) {
const re = new RegExp(importedFileName, 'gi')
const result: SearchResultLine[] = findLinesInStringWithMatch(
text,
re
)
return result
}
}

@ -0,0 +1,82 @@
'use strict'
import { CodeParser } from "../code-parser";
export type CodeParserImportsData= {
files?: string[],
modules?: string[],
packages?: string[],
}
export default class CodeParserImports {
plugin: CodeParser
data: CodeParserImportsData = {}
constructor(plugin: CodeParser) {
this.plugin = plugin
this.init()
}
async getImports(){
return this.data
}
async init() {
// @ts-ignore
const txt = await import('raw-loader!libs/remix-ui/editor/src/lib/providers/completion/contracts/contracts.txt')
this.data.modules = txt.default.split('\n')
.filter(x => x !== '')
.map(x => x.replace('./node_modules/', ''))
.filter(x => {
if(x.includes('@openzeppelin')) {
return !x.includes('mock')
}else{
return true
}
})
// get unique first words of the values in the array
this.data.packages = [...new Set(this.data.modules.map(x => x.split('/')[0]))]
}
setFileTree = async () => {
this.data.files = await this.getDirectory('/')
this.data.files = this.data.files.filter(x => x.endsWith('.sol') && !x.startsWith('.deps') && !x.startsWith('.git'))
}
getDirectory = async (dir: string) => {
let result = []
const files = await this.plugin.call('fileManager', 'readdir', dir)
const fileArray = this.normalize(files)
for (const fi of fileArray) {
if (fi) {
const type = fi.data.isDirectory
if (type === true) {
result = [...result, ...(await this.getDirectory(`${fi.filename}`))]
} else {
result = [...result, fi.filename]
}
}
}
return result
}
normalize = filesList => {
const folders = []
const files = []
Object.keys(filesList || {}).forEach(key => {
if (filesList[key].isDirectory) {
folders.push({
filename: key,
data: filesList[key]
})
} else {
files.push({
filename: key,
data: filesList[key]
})
}
})
return [...folders, ...files]
}
}

@ -1,5 +1,12 @@
import { IRange } from "monaco-editor";
import monaco from "../../../types/monaco";
import path from "path";
type CodeParserImportsData = {
files?: string[],
modules?: string[],
packages?: string[],
}
export function getStringCompletionItems(range: IRange, monaco): monaco.languages.CompletionItem[] {
return [
@ -176,13 +183,6 @@ export function getCompletionSnippets(range: IRange, monaco): monaco.languages.C
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
range
},
{
label: 'import',
kind: monaco.languages.CompletionItemKind.Snippet,
insertText: 'import "${1:library}";',
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
range
},
{
label: 'SPDX-License-Identifier',
kind: monaco.languages.CompletionItemKind.Snippet,
@ -390,6 +390,89 @@ export function GeCompletionUnits(range: IRange, monaco): monaco.languages.Compl
return completionItems;
}
export function GetImports(range: IRange
, monaco, data: CodeParserImportsData
, word: string
): monaco.languages.CompletionItem[] {
let list = []
if (!word.startsWith('@')) {
word = word.replace('"', '');
const nextPaths = [...new Set(data.files
.filter((item) => item.startsWith(word))
.map((item) => item.replace(word, '').split('/')[0]))]
list = [...list, ...nextPaths
.filter((item) => !item.endsWith('.sol'))
.map((item) => {
return {
kind: monaco.languages.CompletionItemKind.Folder,
range: range,
label: `${item}`,
insertText: `${item}`,
}
})]
list = [...list,
...data.files
.filter((item) => item.startsWith(word))
.map((item) => {
return {
kind: monaco.languages.CompletionItemKind.File,
range: range,
label: `${item}`,
insertText: `${item.replace(word, '')}`,
}
})]
}
if (word === '@' || word === '') {
list = [...list, ...data.packages.map((item) => {
return {
kind: monaco.languages.CompletionItemKind.Module,
range: range,
label: `${item}`,
insertText: word === '@' ? `${item.replace('@', '')}` : `${item}`,
}
})]
}
if (word.startsWith('@') && word.length > 1) {
const nextPaths = [...new Set(data.modules
.filter((item) => item.startsWith(word))
.map((item) => item.replace(word, '').split('/')[0]))]
list = [...list, ...nextPaths
.filter((item) => !item.endsWith('.sol'))
.map((item) => {
return {
kind: monaco.languages.CompletionItemKind.Folder,
range: range,
label: `${item}`,
insertText: `${item}`,
}
})]
list = [...list
, ...data.modules
.filter((item) => item.startsWith(word))
.map((item) => {
// remove the first part if it starts with @
let label = item;
if (label.startsWith('@')) {
label = label.substring(label.indexOf('/') + 1);
}
const filename = path.basename(label)
return {
kind: monaco.languages.CompletionItemKind.Reference,
range: range,
label: `${filename}: ${label}`,
insertText: `${item.replace(word, '')}`,
}
})
]
}
return list;
};
export function GetGlobalVariable(range: IRange, monaco): monaco.languages.CompletionItem[] {
return [
{

@ -0,0 +1,198 @@
./node_modules/@openzeppelin/contracts/access/AccessControl.sol
./node_modules/@openzeppelin/contracts/access/AccessControlCrossChain.sol
./node_modules/@openzeppelin/contracts/access/AccessControlEnumerable.sol
./node_modules/@openzeppelin/contracts/access/IAccessControl.sol
./node_modules/@openzeppelin/contracts/access/IAccessControlEnumerable.sol
./node_modules/@openzeppelin/contracts/access/Ownable.sol
./node_modules/@openzeppelin/contracts/crosschain/amb/CrossChainEnabledAMB.sol
./node_modules/@openzeppelin/contracts/crosschain/amb/LibAMB.sol
./node_modules/@openzeppelin/contracts/crosschain/arbitrum/CrossChainEnabledArbitrumL1.sol
./node_modules/@openzeppelin/contracts/crosschain/arbitrum/CrossChainEnabledArbitrumL2.sol
./node_modules/@openzeppelin/contracts/crosschain/arbitrum/LibArbitrumL1.sol
./node_modules/@openzeppelin/contracts/crosschain/arbitrum/LibArbitrumL2.sol
./node_modules/@openzeppelin/contracts/crosschain/CrossChainEnabled.sol
./node_modules/@openzeppelin/contracts/crosschain/errors.sol
./node_modules/@openzeppelin/contracts/crosschain/optimism/CrossChainEnabledOptimism.sol
./node_modules/@openzeppelin/contracts/crosschain/optimism/LibOptimism.sol
./node_modules/@openzeppelin/contracts/crosschain/polygon/CrossChainEnabledPolygonChild.sol
./node_modules/@openzeppelin/contracts/finance/PaymentSplitter.sol
./node_modules/@openzeppelin/contracts/finance/VestingWallet.sol
./node_modules/@openzeppelin/contracts/governance/compatibility/GovernorCompatibilityBravo.sol
./node_modules/@openzeppelin/contracts/governance/compatibility/IGovernorCompatibilityBravo.sol
./node_modules/@openzeppelin/contracts/governance/extensions/GovernorCountingSimple.sol
./node_modules/@openzeppelin/contracts/governance/extensions/GovernorPreventLateQuorum.sol
./node_modules/@openzeppelin/contracts/governance/extensions/GovernorProposalThreshold.sol
./node_modules/@openzeppelin/contracts/governance/extensions/GovernorSettings.sol
./node_modules/@openzeppelin/contracts/governance/extensions/GovernorTimelockCompound.sol
./node_modules/@openzeppelin/contracts/governance/extensions/GovernorTimelockControl.sol
./node_modules/@openzeppelin/contracts/governance/extensions/GovernorVotes.sol
./node_modules/@openzeppelin/contracts/governance/extensions/GovernorVotesComp.sol
./node_modules/@openzeppelin/contracts/governance/extensions/GovernorVotesQuorumFraction.sol
./node_modules/@openzeppelin/contracts/governance/extensions/IGovernorTimelock.sol
./node_modules/@openzeppelin/contracts/governance/Governor.sol
./node_modules/@openzeppelin/contracts/governance/IGovernor.sol
./node_modules/@openzeppelin/contracts/governance/TimelockController.sol
./node_modules/@openzeppelin/contracts/governance/utils/IVotes.sol
./node_modules/@openzeppelin/contracts/governance/utils/Votes.sol
./node_modules/@openzeppelin/contracts/interfaces/draft-IERC1822.sol
./node_modules/@openzeppelin/contracts/interfaces/draft-IERC2612.sol
./node_modules/@openzeppelin/contracts/interfaces/IERC1155.sol
./node_modules/@openzeppelin/contracts/interfaces/IERC1155MetadataURI.sol
./node_modules/@openzeppelin/contracts/interfaces/IERC1155Receiver.sol
./node_modules/@openzeppelin/contracts/interfaces/IERC1271.sol
./node_modules/@openzeppelin/contracts/interfaces/IERC1363.sol
./node_modules/@openzeppelin/contracts/interfaces/IERC1363Receiver.sol
./node_modules/@openzeppelin/contracts/interfaces/IERC1363Spender.sol
./node_modules/@openzeppelin/contracts/interfaces/IERC165.sol
./node_modules/@openzeppelin/contracts/interfaces/IERC1820Implementer.sol
./node_modules/@openzeppelin/contracts/interfaces/IERC1820Registry.sol
./node_modules/@openzeppelin/contracts/interfaces/IERC20.sol
./node_modules/@openzeppelin/contracts/interfaces/IERC20Metadata.sol
./node_modules/@openzeppelin/contracts/interfaces/IERC2981.sol
./node_modules/@openzeppelin/contracts/interfaces/IERC3156.sol
./node_modules/@openzeppelin/contracts/interfaces/IERC3156FlashBorrower.sol
./node_modules/@openzeppelin/contracts/interfaces/IERC3156FlashLender.sol
./node_modules/@openzeppelin/contracts/interfaces/IERC4626.sol
./node_modules/@openzeppelin/contracts/interfaces/IERC721.sol
./node_modules/@openzeppelin/contracts/interfaces/IERC721Enumerable.sol
./node_modules/@openzeppelin/contracts/interfaces/IERC721Metadata.sol
./node_modules/@openzeppelin/contracts/interfaces/IERC721Receiver.sol
./node_modules/@openzeppelin/contracts/interfaces/IERC777.sol
./node_modules/@openzeppelin/contracts/interfaces/IERC777Recipient.sol
./node_modules/@openzeppelin/contracts/interfaces/IERC777Sender.sol
./node_modules/@openzeppelin/contracts/metatx/ERC2771Context.sol
./node_modules/@openzeppelin/contracts/metatx/MinimalForwarder.sol
./node_modules/@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol
./node_modules/@openzeppelin/contracts/proxy/beacon/IBeacon.sol
./node_modules/@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol
./node_modules/@openzeppelin/contracts/proxy/Clones.sol
./node_modules/@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol
./node_modules/@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol
./node_modules/@openzeppelin/contracts/proxy/Proxy.sol
./node_modules/@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol
./node_modules/@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol
./node_modules/@openzeppelin/contracts/proxy/utils/Initializable.sol
./node_modules/@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol
./node_modules/@openzeppelin/contracts/security/Pausable.sol
./node_modules/@openzeppelin/contracts/security/PullPayment.sol
./node_modules/@openzeppelin/contracts/security/ReentrancyGuard.sol
./node_modules/@openzeppelin/contracts/token/common/ERC2981.sol
./node_modules/@openzeppelin/contracts/token/ERC1155/ERC1155.sol
./node_modules/@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Burnable.sol
./node_modules/@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Pausable.sol
./node_modules/@openzeppelin/contracts/token/ERC1155/extensions/ERC1155Supply.sol
./node_modules/@openzeppelin/contracts/token/ERC1155/extensions/ERC1155URIStorage.sol
./node_modules/@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol
./node_modules/@openzeppelin/contracts/token/ERC1155/IERC1155.sol
./node_modules/@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol
./node_modules/@openzeppelin/contracts/token/ERC1155/presets/ERC1155PresetMinterPauser.sol
./node_modules/@openzeppelin/contracts/token/ERC1155/utils/ERC1155Holder.sol
./node_modules/@openzeppelin/contracts/token/ERC1155/utils/ERC1155Receiver.sol
./node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol
./node_modules/@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol
./node_modules/@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol
./node_modules/@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol
./node_modules/@openzeppelin/contracts/token/ERC20/extensions/ERC20Capped.sol
./node_modules/@openzeppelin/contracts/token/ERC20/extensions/ERC20FlashMint.sol
./node_modules/@openzeppelin/contracts/token/ERC20/extensions/ERC20Pausable.sol
./node_modules/@openzeppelin/contracts/token/ERC20/extensions/ERC20Snapshot.sol
./node_modules/@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol
./node_modules/@openzeppelin/contracts/token/ERC20/extensions/ERC20VotesComp.sol
./node_modules/@openzeppelin/contracts/token/ERC20/extensions/ERC20Wrapper.sol
./node_modules/@openzeppelin/contracts/token/ERC20/extensions/ERC4626.sol
./node_modules/@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol
./node_modules/@openzeppelin/contracts/token/ERC20/IERC20.sol
./node_modules/@openzeppelin/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol
./node_modules/@openzeppelin/contracts/token/ERC20/presets/ERC20PresetMinterPauser.sol
./node_modules/@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol
./node_modules/@openzeppelin/contracts/token/ERC20/utils/TokenTimelock.sol
./node_modules/@openzeppelin/contracts/token/ERC721/ERC721.sol
./node_modules/@openzeppelin/contracts/token/ERC721/extensions/draft-ERC721Votes.sol
./node_modules/@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol
./node_modules/@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol
./node_modules/@openzeppelin/contracts/token/ERC721/extensions/ERC721Pausable.sol
./node_modules/@openzeppelin/contracts/token/ERC721/extensions/ERC721Royalty.sol
./node_modules/@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol
./node_modules/@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol
./node_modules/@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol
./node_modules/@openzeppelin/contracts/token/ERC721/IERC721.sol
./node_modules/@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol
./node_modules/@openzeppelin/contracts/token/ERC721/presets/ERC721PresetMinterPauserAutoId.sol
./node_modules/@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol
./node_modules/@openzeppelin/contracts/token/ERC777/ERC777.sol
./node_modules/@openzeppelin/contracts/token/ERC777/IERC777.sol
./node_modules/@openzeppelin/contracts/token/ERC777/IERC777Recipient.sol
./node_modules/@openzeppelin/contracts/token/ERC777/IERC777Sender.sol
./node_modules/@openzeppelin/contracts/token/ERC777/presets/ERC777PresetFixedSupply.sol
./node_modules/@openzeppelin/contracts/utils/Address.sol
./node_modules/@openzeppelin/contracts/utils/Arrays.sol
./node_modules/@openzeppelin/contracts/utils/Base64.sol
./node_modules/@openzeppelin/contracts/utils/Checkpoints.sol
./node_modules/@openzeppelin/contracts/utils/Context.sol
./node_modules/@openzeppelin/contracts/utils/Counters.sol
./node_modules/@openzeppelin/contracts/utils/Create2.sol
./node_modules/@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol
./node_modules/@openzeppelin/contracts/utils/cryptography/ECDSA.sol
./node_modules/@openzeppelin/contracts/utils/cryptography/MerkleProof.sol
./node_modules/@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol
./node_modules/@openzeppelin/contracts/utils/escrow/ConditionalEscrow.sol
./node_modules/@openzeppelin/contracts/utils/escrow/Escrow.sol
./node_modules/@openzeppelin/contracts/utils/escrow/RefundEscrow.sol
./node_modules/@openzeppelin/contracts/utils/introspection/ERC165.sol
./node_modules/@openzeppelin/contracts/utils/introspection/ERC165Checker.sol
./node_modules/@openzeppelin/contracts/utils/introspection/ERC165Storage.sol
./node_modules/@openzeppelin/contracts/utils/introspection/ERC1820Implementer.sol
./node_modules/@openzeppelin/contracts/utils/introspection/IERC165.sol
./node_modules/@openzeppelin/contracts/utils/introspection/IERC1820Implementer.sol
./node_modules/@openzeppelin/contracts/utils/introspection/IERC1820Registry.sol
./node_modules/@openzeppelin/contracts/utils/math/Math.sol
./node_modules/@openzeppelin/contracts/utils/math/SafeCast.sol
./node_modules/@openzeppelin/contracts/utils/math/SafeMath.sol
./node_modules/@openzeppelin/contracts/utils/math/SignedMath.sol
./node_modules/@openzeppelin/contracts/utils/math/SignedSafeMath.sol
./node_modules/@openzeppelin/contracts/utils/Multicall.sol
./node_modules/@openzeppelin/contracts/utils/StorageSlot.sol
./node_modules/@openzeppelin/contracts/utils/Strings.sol
./node_modules/@openzeppelin/contracts/utils/structs/BitMaps.sol
./node_modules/@openzeppelin/contracts/utils/structs/DoubleEndedQueue.sol
./node_modules/@openzeppelin/contracts/utils/structs/EnumerableMap.sol
./node_modules/@openzeppelin/contracts/utils/structs/EnumerableSet.sol
./node_modules/@openzeppelin/contracts/utils/Timers.sol
./node_modules/@openzeppelin/contracts/vendor/amb/IAMB.sol
./node_modules/@openzeppelin/contracts/vendor/arbitrum/IArbSys.sol
./node_modules/@openzeppelin/contracts/vendor/arbitrum/IBridge.sol
./node_modules/@openzeppelin/contracts/vendor/arbitrum/IInbox.sol
./node_modules/@openzeppelin/contracts/vendor/arbitrum/IMessageProvider.sol
./node_modules/@openzeppelin/contracts/vendor/arbitrum/IOutbox.sol
./node_modules/@openzeppelin/contracts/vendor/compound/ICompoundTimelock.sol
./node_modules/@openzeppelin/contracts/vendor/optimism/ICrossDomainMessenger.sol
./node_modules/@openzeppelin/contracts/vendor/polygon/IFxMessageProcessor.sol
./node_modules/@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3FlashCallback.sol
./node_modules/@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3MintCallback.sol
./node_modules/@uniswap/v3-core/contracts/interfaces/callback/IUniswapV3SwapCallback.sol
./node_modules/@uniswap/v3-core/contracts/interfaces/IERC20Minimal.sol
./node_modules/@uniswap/v3-core/contracts/interfaces/IUniswapV3Factory.sol
./node_modules/@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol
./node_modules/@uniswap/v3-core/contracts/interfaces/IUniswapV3PoolDeployer.sol
./node_modules/@uniswap/v3-core/contracts/interfaces/pool/IUniswapV3PoolActions.sol
./node_modules/@uniswap/v3-core/contracts/interfaces/pool/IUniswapV3PoolDerivedState.sol
./node_modules/@uniswap/v3-core/contracts/interfaces/pool/IUniswapV3PoolEvents.sol
./node_modules/@uniswap/v3-core/contracts/interfaces/pool/IUniswapV3PoolImmutables.sol
./node_modules/@uniswap/v3-core/contracts/interfaces/pool/IUniswapV3PoolOwnerActions.sol
./node_modules/@uniswap/v3-core/contracts/interfaces/pool/IUniswapV3PoolState.sol
./node_modules/@uniswap/v3-core/contracts/libraries/BitMath.sol
./node_modules/@uniswap/v3-core/contracts/libraries/FixedPoint128.sol
./node_modules/@uniswap/v3-core/contracts/libraries/FixedPoint96.sol
./node_modules/@uniswap/v3-core/contracts/libraries/FullMath.sol
./node_modules/@uniswap/v3-core/contracts/libraries/LiquidityMath.sol
./node_modules/@uniswap/v3-core/contracts/libraries/LowGasSafeMath.sol
./node_modules/@uniswap/v3-core/contracts/libraries/Oracle.sol
./node_modules/@uniswap/v3-core/contracts/libraries/Position.sol
./node_modules/@uniswap/v3-core/contracts/libraries/SafeCast.sol
./node_modules/@uniswap/v3-core/contracts/libraries/SqrtPriceMath.sol
./node_modules/@uniswap/v3-core/contracts/libraries/SwapMath.sol
./node_modules/@uniswap/v3-core/contracts/libraries/Tick.sol
./node_modules/@uniswap/v3-core/contracts/libraries/TickBitmap.sol
./node_modules/@uniswap/v3-core/contracts/libraries/TickMath.sol
./node_modules/@uniswap/v3-core/contracts/libraries/TransferHelper.sol
./node_modules/@uniswap/v3-core/contracts/libraries/UnsafeMath.sol

@ -4,7 +4,7 @@ import { isArray } from "lodash"
import { editor, languages, Position } from "monaco-editor"
import monaco from "../../types/monaco"
import { EditorUIProps } from "../remix-ui-editor"
import { GeCompletionUnits, GetCompletionKeywords, getCompletionSnippets, GetCompletionTypes, getContextualAutoCompleteBTypeName, getContextualAutoCompleteByGlobalVariable, GetGlobalFunctions, GetGlobalVariable } from "./completion/completionGlobals"
import { GeCompletionUnits, GetCompletionKeywords, getCompletionSnippets, GetCompletionTypes, getContextualAutoCompleteBTypeName, getContextualAutoCompleteByGlobalVariable, GetGlobalFunctions, GetGlobalVariable, GetImports } from "./completion/completionGlobals"
export class RemixCompletionProvider implements languages.CompletionItemProvider {
@ -16,7 +16,7 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
this.monaco = monaco
}
triggerCharacters = ['.', '']
triggerCharacters = ['.', '', '"', '@', '/']
async provideCompletionItems(model: editor.ITextModel, position: Position, context: monaco.languages.CompletionContext): Promise<monaco.languages.CompletionList | undefined> {
const completionSettings = await this.props.plugin.call('config', 'getAppParameter', 'settings/auto-completion')
@ -33,6 +33,28 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
let nodes: AstNode[] = []
let suggestions: monaco.languages.CompletionItem[] = []
if (context.triggerCharacter === '"' || context.triggerCharacter === '@' || context.triggerCharacter === '/') {
const lastpart = line.substring(0, position.column - 1).split(';').pop()
if (lastpart.startsWith('import')) {
const imports = await this.props.plugin.call('codeParser', 'getImports')
if (context.triggerCharacter === '"' || context.triggerCharacter === '@') {
suggestions = [...suggestions,
...GetImports(range, this.monaco, imports, context.triggerCharacter),
]
} else if (context.triggerCharacter === '/') {
const word = line.split('"')[1]
suggestions = [...suggestions,
...GetImports(range, this.monaco, imports, word),
]
} else {
return
}
}
} else
if (context.triggerCharacter === '.') {
const lineTextBeforeCursor: string = line.substring(0, position.column - 1)
const lastNodeInExpression = await this.getLastNodeInExpression(lineTextBeforeCursor)

@ -13,8 +13,22 @@ export class RemixDefinitionProvider implements monaco.languages.DefinitionProvi
// eslint-disable-next-line @typescript-eslint/no-unused-vars
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 jumpLocation = await this.jumpToDefinition(cursorPosition)
let jumpLocation = await this.jumpToDefinition(cursorPosition)
if (!jumpLocation || !jumpLocation.fileName) {
const line = model.getLineContent(position.lineNumber)
const lastpart = line.substring(0, position.column - 1).split(';').pop()
if (lastpart.startsWith('import')) {
const importPath = line.substring(lastpart.indexOf('"') + 1)
const importPath2 = importPath.substring(0, importPath.indexOf('"'))
jumpLocation = {
startLineNumber: 1,
startColumn: 1,
endColumn: 1,
endLineNumber: 1,
fileName: importPath2
}
}
}
return [{
uri: this.monaco.Uri.parse(jumpLocation.fileName),
range: {

@ -1 +1,3 @@
export { SearchTab } from './lib/components/Search';
export * from './lib/components/results/SearchHelper';
export * from './lib/types';

@ -108,7 +108,8 @@
"test-browser": "npm-run-all -lpr selenium make-mock-compiler serve browsertest",
"watch": "watchify apps/remix-ide/src/index.js -dv -p browserify-reload -o apps/remix-ide/build/app.js --exclude solc",
"reinstall": "rm ./node-modules/ -rf && rm yarn.lock && rm ./build/ -rf && yarn install & yarn run build",
"ganache-cli": "npx ganache-cli"
"ganache-cli": "npx ganache-cli",
"build-contracts": "find ./node_modules/@openzeppelin/contracts | grep -i '.sol' > libs/remix-ui/editor/src/lib/providers/completion/contracts/contracts.txt && find ./node_modules/@uniswap/v3-core/contracts | grep -i '.sol' >> libs/remix-ui/editor/src/lib/providers/completion/contracts/contracts.txt"
},
"browserify": {
"transform": [
@ -263,6 +264,8 @@
"@types/ws": "^7.2.4",
"@typescript-eslint/eslint-plugin": "^4.32.0",
"@typescript-eslint/parser": "^4.32.0",
"@uniswap/v2-core": "^1.0.1",
"@uniswap/v3-core": "^1.0.1",
"ace-mode-lexon": "^1.*.*",
"ace-mode-move": "0.0.1",
"ace-mode-solidity": "^0.1.0",

@ -4813,6 +4813,16 @@
resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44"
integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==
"@uniswap/v2-core@^1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@uniswap/v2-core/-/v2-core-1.0.1.tgz#af8f508bf183204779938969e2e54043e147d425"
integrity sha512-MtybtkUPSyysqLY2U210NBDeCHX+ltHt3oADGdjqoThZaFRDKwM6k1Nb3F0A3hk5hwuQvytFWhrWHOEq6nVJ8Q==
"@uniswap/v3-core@^1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@uniswap/v3-core/-/v3-core-1.0.1.tgz#b6d2bdc6ba3c3fbd610bdc502395d86cd35264a0"
integrity sha512-7pVk4hEm00j9tc71Y9+ssYpO6ytkeI0y7WE9P6UcmNzhxPePwyAxImuhVsTqWK9YFvzgtvzJHi64pBl4jUzKMQ==
"@webassemblyjs/ast@1.8.5":
version "1.8.5"
resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.8.5.tgz#51b1c5fe6576a34953bf4b253df9f0d490d9e359"

Loading…
Cancel
Save