Merge branch 'master' of https://github.com/ethereum/remix-project into optimizecircle

pull/2868/head
filip mertens 2 years ago
commit f471d520a5
  1. 5
      .circleci/config.yml
  2. 6
      apps/remix-ide-e2e/src/commands/addFile.ts
  3. 4
      apps/remix-ide-e2e/src/helpers/init.ts
  4. 6
      apps/remix-ide-e2e/src/tests/generalSettings.test.ts
  5. 26
      apps/remix-ide/src/app/plugins/parser/code-parser.tsx
  6. 128
      apps/remix-ide/src/app/plugins/parser/services/code-parser-compiler.ts
  7. 82
      apps/remix-ide/src/app/plugins/parser/services/code-parser-imports.ts
  8. 8
      apps/remix-ide/src/assets/css/themes/bootstrap-cyborg.min.css
  9. 4
      apps/remix-ide/src/assets/css/themes/bootstrap-flatly.min.css
  10. 4
      apps/remix-ide/src/assets/css/themes/bootstrap-spacelab.min.css
  11. 2
      apps/remix-ide/src/assets/css/themes/remix-dark_tvx1s2.css
  12. 99
      libs/remix-ui/editor/src/lib/providers/completion/completionGlobals.ts
  13. 198
      libs/remix-ui/editor/src/lib/providers/completion/contracts/contracts.txt
  14. 132
      libs/remix-ui/editor/src/lib/providers/completionProvider.ts
  15. 18
      libs/remix-ui/editor/src/lib/providers/definitionProvider.ts
  16. 4
      libs/remix-ui/editor/src/lib/remix-ui-editor.tsx
  17. 2
      libs/remix-ui/panel/src/lib/plugins/remix-ui-panel.tsx
  18. 2
      libs/remix-ui/permission-handler/src/lib/permission-dialog.tsx
  19. 2
      libs/remix-ui/search/src/index.ts
  20. 4
      libs/remix-ui/static-analyser/src/lib/remix-ui-static-analyser.tsx
  21. 2
      libs/remix-ui/tabs/src/lib/remix-ui-tabs.tsx
  22. 2
      libs/remix-ui/workspace/src/lib/css/remix-ui-workspace.css
  23. 5
      package.json
  24. 10
      yarn.lock

@ -496,10 +496,10 @@ jobs:
working_directory: ~/remix-project
steps:
- checkout
- node/install:
install-yarn: true
node-version: "v14.17.6"
- checkout
- run: yarn
- run: yarn run downloadsolc_assets
- run: yarn run build:production
@ -529,6 +529,9 @@ jobs:
steps:
- checkout
- node/install:
install-yarn: true
node-version: "v14.17.6"
- run: yarn
- run: yarn run downloadsolc_assets
- run: yarn run build:production

@ -13,8 +13,9 @@ class AddFile extends EventEmitter {
}
}
function addFile(browser: NightwatchBrowser, name: string, content: NightwatchContractContent, done: VoidFunction) {
function addFile (browser: NightwatchBrowser, name: string, content: NightwatchContractContent, done: VoidFunction) {
browser
.saveScreenshot('./reports/screenshots/addFile.png')
.isVisible({
selector: "//*[@data-id='sidePanelSwapitTitle' and contains(.,'File explorer')]",
locateStrategy: 'xpath',
@ -23,8 +24,11 @@ function addFile(browser: NightwatchBrowser, name: string, content: NightwatchCo
}, (okVisible) => {
if (!okVisible.value) {
browser.clickLaunchIcon('filePanel')
.saveScreenshot('./reports/screenshots/addFile2.png')
}
})
.scrollInto('li[data-id="treeViewLitreeViewItemREADME.txt"]')
.saveScreenshot('./reports/screenshots/addFile3.png')
.waitForElementVisible('li[data-id="treeViewLitreeViewItemREADME.txt"]')
.click('li[data-id="treeViewLitreeViewItemREADME.txt"]').pause(1000) // focus on root directory
.elements('css selector', `li[data-id="treeViewLitreeViewItem${name}"]`, (res) => {

@ -26,8 +26,8 @@ export default function (browser: NightwatchBrowser, callback: VoidFunction, url
.waitForElementVisible('[data-id="sidePanelSwapitTitle"]')
.perform(done())
})
.maximizeWindow()
.fullscreenWindow(() => {
//.maximizeWindow()
.perform(() => {
if (preloadPlugins) {
initModules(browser, () => {
browser

@ -163,7 +163,7 @@ const remixIdeThemes = {
},
flatly: {
primary: '#2C3E50',
secondary: '#95a5a6',
secondary: '#dadfe0',
success: '#18BC9C',
info: '#3498DB',
warning: '#F39C12',
@ -171,7 +171,7 @@ const remixIdeThemes = {
},
spacelab: {
primary: '#446E9B',
secondary: '#999',
secondary: '#dadfe0',
success: '#3CB521',
info: '#3399F3',
warning: '#D47500',
@ -179,7 +179,7 @@ const remixIdeThemes = {
},
cyborg: {
primary: '#2A9FD6',
secondary: '#555',
secondary: '#3c3939',
success: '#77B300',
info: '#93C',
warning: '#F80',

@ -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)
@ -94,7 +98,7 @@ export class CodeParser extends Plugin {
}
const showGasSettings = await this.call('config', 'getAppParameter', 'show-gas')
const showErrorSettings = await this.call('config', 'getAppParameter', 'display-errors')
if(showGasSettings || showErrorSettings || completionSettings) {
if (showGasSettings || showErrorSettings || completionSettings) {
await this.compilerService.compile()
}
}
@ -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,22 +8,23 @@ 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
severity: MarkerSeverity
position: {
start: {
line: number
column: number
},
end: {
line: number
column: number
}
start: {
line: number
column: number
},
end: {
line: number
column: number
}
},
file: string
}
}
export default class CodeParserCompiler {
plugin: CodeParser
compiler: any // used to compile the current file seperately from the main compiler
@ -43,36 +44,47 @@ 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
for (const error of data.errors) {
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
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
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)
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)
if (displayErrors) await this.plugin.call('editor', 'addErrorMarker', allErrors)
this.addDecorators(allErrors, sources)
} else {
await this.plugin.call('editor', 'clearErrorMarkers', result.getSourceCode().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",
}
}
@ -143,14 +155,14 @@ export default class CodeParserCompiler {
this.compiler.compile(sources, this.plugin.currentFile)
}
} catch (e) {
// do nothing
// do nothing
}
}
async addDecorators(allErrors: errorMarker[], sources: any) {
const displayErrors = await this.plugin.call('config', 'getAppParameter', 'display-errors')
if(!displayErrors) return
const errorsPerFiles: {[fileName: string]: errorMarker[]} = {}
if (!displayErrors) return
const errorsPerFiles: { [fileName: string]: errorMarker[] } = {}
for (const error of allErrors) {
if (!errorsPerFiles[error.file]) {
errorsPerFiles[error.file] = []
@ -164,7 +176,7 @@ export default class CodeParserCompiler {
}
// sort errorPerFiles by error priority
const sortedErrorsPerFiles: {[fileName: string]: errorMarker[]} = {}
const sortedErrorsPerFiles: { [fileName: string]: errorMarker[] } = {}
for (const fileName in errorsPerFiles) {
const errors = errorsPerFiles[fileName]
errors.sort((a, b) => {
@ -178,10 +190,11 @@ 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,
fileStateType: errors[0].severity == MarkerSeverity.Error ? fileDecorationType.Error : fileDecorationType.Warning,
fileStateLabelClass: errors[0].severity == MarkerSeverity.Error ? 'text-danger' : 'text-warning',
fileStateIconClass: '',
fileStateIcon: '',
@ -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]
}
}

@ -25,7 +25,7 @@
--gray:#555;
--gray-dark:#222;
--primary:#2a9fd6;
--secondary:#555;
--secondary:#3c3939;
--success:#77b300;
--info:#93c;
--warning:#f80;
@ -5595,7 +5595,7 @@ a.bg-primary:focus,a.bg-primary:hover,button.bg-primary:focus,button.bg-primary:
background-color:#2180ac!important
}
.bg-secondary {
background-color:#555!important
background-color:#3c3939!important
}
a.bg-secondary:focus,a.bg-secondary:hover,button.bg-secondary:focus,button.bg-secondary:hover {
background-color:#3c3c3c!important
@ -8358,7 +8358,7 @@ a.text-warning:focus,a.text-warning:hover {
color:#b35f00!important
}
.text-danger {
color:#c00!important
color:#ff4242!important
}
a.text-danger:focus,a.text-danger:hover {
color:maroon!important
@ -8594,7 +8594,7 @@ legend {
color:#555
}
.nav-pills .nav-link.active,.nav-tabs .nav-link.active {
background-color:#2a9fd6
background-color:#034767
}
.breadcrumb a {
color:#fff

@ -24,7 +24,7 @@
--gray:#95a5a6;
--gray-dark:#343a40;
--primary:#2c3e50;
--secondary:#95a5a6;
--secondary:#dadfe0;
--success:#18bc9c;
--info:#3498db;
--warning:#f39c12;
@ -4460,7 +4460,7 @@ a.bg-primary:focus,a.bg-primary:hover,button.bg-primary:focus,button.bg-primary:
background-color:#1a252f!important
}
.bg-secondary {
background-color:#95a5a6!important
background-color:#dadfe0!important
}
a.bg-secondary:focus,a.bg-secondary:hover,button.bg-secondary:focus,button.bg-secondary:hover {
background-color:#798d8f!important

@ -25,7 +25,7 @@
--gray:#777;
--gray-dark:#333;
--primary:#446e9b;
--secondary:#999;
--secondary:#dadfe0;
--success:#3cb521;
--info:#3399f3;
--warning:#d47500;
@ -5596,7 +5596,7 @@ a.bg-primary:focus,a.bg-primary:hover,button.bg-primary:focus,button.bg-primary:
background-color:#345578!important
}
.bg-secondary {
background-color:#999!important
background-color:#dadfe0!important
}
a.bg-secondary:focus,a.bg-secondary:hover,button.bg-secondary:focus,button.bg-secondary:hover {
background-color:gray!important

@ -3641,7 +3641,7 @@ input[type="submit"].btn-block {
.nav-tabs .nav-item.show .nav-link,
.nav-tabs .nav-link.active {
color: #fff;
background-color: var(--body-bg);
background-color: #2a2c3f;
border-color: #3f4455;
}
.nav-tabs .dropdown-menu {

@ -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,
@ -330,7 +330,7 @@ function CreateCompletionItem(label: string, kind: monaco.languages.CompletionIt
export function GetCompletionKeywords(range: IRange, monaco): monaco.languages.CompletionItem[] {
const completionItems = [];
const keywords = ['modifier', 'mapping', 'break', 'continue', 'delete', 'else', 'for',
'after', 'promise', 'alias', 'apply','auto', 'copyof', 'default', 'define', 'final', 'implements',
'after', 'promise', 'alias', 'apply', 'auto', 'copyof', 'default', 'define', 'final', 'implements',
'inline', 'let', 'macro', 'match', 'mutable', 'null', 'of', 'partial', 'reference', 'relocatable',
'sealed', 'sizeof', 'static', 'supports', 'switch', 'typedef',
'if', 'new', 'return', 'returns', 'while', 'using', 'emit', 'anonymous', 'indexed',
@ -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,11 +16,11 @@ 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')
if(!completionSettings) return
if (!completionSettings) return
const word = model.getWordUntilPosition(position);
const range = {
startLineNumber: position.lineNumber,
@ -33,62 +33,84 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
let nodes: AstNode[] = []
let suggestions: monaco.languages.CompletionItem[] = []
if (context.triggerCharacter === '.') {
const lineTextBeforeCursor: string = line.substring(0, position.column - 1)
const lastNodeInExpression = await this.getLastNodeInExpression(lineTextBeforeCursor)
const expressionElements = lineTextBeforeCursor.split('.')
let dotCompleted = false
if (context.triggerCharacter === '"' || context.triggerCharacter === '@' || context.triggerCharacter === '/') {
// handles completion from for builtin types
if(lastNodeInExpression.memberName === 'sender') { // exception for this member
lastNodeInExpression.name = 'sender'
}
const globalCompletion = getContextualAutoCompleteByGlobalVariable(lastNodeInExpression.name, range, this.monaco)
if (globalCompletion) {
dotCompleted = true
suggestions = [...suggestions, ...globalCompletion]
setTimeout(() => {
// eslint-disable-next-line no-debugger
// debugger
}, 2000)
}
// handle completion for global THIS.
if (lastNodeInExpression.name === 'this') {
dotCompleted = true
nodes = [...nodes, ...await this.getThisCompletions(position)]
}
// handle completion for other dot completions
if (expressionElements.length > 1 && !dotCompleted) {
const lastpart = line.substring(0, position.column - 1).split(';').pop()
const nameOfLastTypedExpression = lastNodeInExpression.name || lastNodeInExpression.memberName
const dotCompletions = await this.getDotCompletions(position, nameOfLastTypedExpression, range)
nodes = [...nodes, ...dotCompletions.nodes]
suggestions = [...suggestions, ...dotCompletions.suggestions]
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 {
} else
// handles contract completions and other suggestions
suggestions = [...suggestions,
...GetGlobalVariable(range, this.monaco),
...getCompletionSnippets(range, this.monaco),
...GetCompletionTypes(range, this.monaco),
...GetCompletionKeywords(range, this.monaco),
...GetGlobalFunctions(range, this.monaco),
...GeCompletionUnits(range, this.monaco),
]
let contractCompletions = await this.getContractCompletions(position)
if (context.triggerCharacter === '.') {
const lineTextBeforeCursor: string = line.substring(0, position.column - 1)
const lastNodeInExpression = await this.getLastNodeInExpression(lineTextBeforeCursor)
const expressionElements = lineTextBeforeCursor.split('.')
let dotCompleted = false
// we can't have external nodes without using this.
contractCompletions = contractCompletions.filter(node => {
if (node.visibility && node.visibility === 'external') {
return false
// handles completion from for builtin types
if (lastNodeInExpression.memberName === 'sender') { // exception for this member
lastNodeInExpression.name = 'sender'
}
return true
})
nodes = [...nodes, ...contractCompletions]
const globalCompletion = getContextualAutoCompleteByGlobalVariable(lastNodeInExpression.name, range, this.monaco)
if (globalCompletion) {
dotCompleted = true
suggestions = [...suggestions, ...globalCompletion]
setTimeout(() => {
// eslint-disable-next-line no-debugger
// debugger
}, 2000)
}
// handle completion for global THIS.
if (lastNodeInExpression.name === 'this') {
dotCompleted = true
nodes = [...nodes, ...await this.getThisCompletions(position)]
}
// handle completion for other dot completions
if (expressionElements.length > 1 && !dotCompleted) {
}
const nameOfLastTypedExpression = lastNodeInExpression.name || lastNodeInExpression.memberName
const dotCompletions = await this.getDotCompletions(position, nameOfLastTypedExpression, range)
nodes = [...nodes, ...dotCompletions.nodes]
suggestions = [...suggestions, ...dotCompletions.suggestions]
}
} else {
// handles contract completions and other suggestions
suggestions = [...suggestions,
...GetGlobalVariable(range, this.monaco),
...getCompletionSnippets(range, this.monaco),
...GetCompletionTypes(range, this.monaco),
...GetCompletionKeywords(range, this.monaco),
...GetGlobalFunctions(range, this.monaco),
...GeCompletionUnits(range, this.monaco),
]
let contractCompletions = await this.getContractCompletions(position)
// we can't have external nodes without using this.
contractCompletions = contractCompletions.filter(node => {
if (node.visibility && node.visibility === 'external') {
return false
}
return true
})
nodes = [...nodes, ...contractCompletions]
}
// remove duplicates
const nodeIds = {};
@ -244,7 +266,7 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
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 )
|| (contractNode['kind'] === 'constructor' && ANTLRBlock.name === null)
) {
let nodeOfScope = await this.props.plugin.call('codeParser', 'getNodesWithScope', (contractNode as any).id)
nodes = [...nodes, ...nodeOfScope]
@ -279,7 +301,7 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
return true
}
}
if(node.outSideBlock){ return true }
if (node.outSideBlock) { return true }
return false
})
@ -387,9 +409,9 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
nodes = [...nodes, ...filterNodes(nodeOfScope.members, nodeOfScope)]
} else if (nodeOfScope.typeName && nodeOfScope.typeName.nodeType === 'ArrayTypeName') {
suggestions = [...suggestions, ...getContextualAutoCompleteBTypeName('ArrayTypeName', range, this.monaco)]
} else if(nodeOfScope.typeName && nodeOfScope.typeName.nodeType === 'ElementaryTypeName' && nodeOfScope.typeName.name === 'bytes') {
} else if (nodeOfScope.typeName && nodeOfScope.typeName.nodeType === 'ElementaryTypeName' && nodeOfScope.typeName.name === 'bytes') {
suggestions = [...suggestions, ...getContextualAutoCompleteBTypeName('bytes', range, this.monaco)]
} else if(nodeOfScope.typeName && nodeOfScope.typeName.nodeType === 'ElementaryTypeName' && nodeOfScope.typeName.name === 'address') {
} else if (nodeOfScope.typeName && nodeOfScope.typeName.nodeType === 'ElementaryTypeName' && nodeOfScope.typeName.name === 'address') {
suggestions = [...suggestions, ...getContextualAutoCompleteBTypeName('address', range, this.monaco)]
}
}

@ -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: {

@ -158,6 +158,7 @@ export const EditorUI = (props: EditorUIProps) => {
const infoColor = formatColor('--info')
const darkColor = formatColor('--dark')
const secondaryColor = formatColor('--secondary')
const primaryColor = formatColor('--primary')
const textColor = formatColor('--text') || darkColor
const textbackground = formatColor('--text-background') || lightColor
@ -266,7 +267,8 @@ export const EditorUI = (props: EditorUIProps) => {
'editorSuggestWidget.background': lightColor,
'editorSuggestWidget.selectedBackground': secondaryColor,
'editorSuggestWidget.selectedForeground': textColor,
'editorSuggestWidget.highlightForeground': infoColor,
'editorSuggestWidget.highlightForeground': primaryColor,
'editorSuggestWidget.focusHighlightForeground': infoColor,
'editor.lineHighlightBorder': secondaryColor,
'editor.lineHighlightBackground': textbackground === darkColor ? lightColor : secondaryColor,
'editorGutter.background': lightColor,

@ -15,7 +15,7 @@ export function RemixPluginPanel (props: RemixPanelProps) {
<>
{props.header}
<div className="pluginsContainer">
<div className='plugins pb-2' id='plugins'>
<div className='plugins' id='plugins'>
{Object.values(props.plugins).map((pluginRecord) => {
return <RemixUIPanelPlugin key={pluginRecord.profile.name} pluginRecord={pluginRecord} />
})}

@ -52,7 +52,7 @@ const PermissionHandlerDialog = (props: PermissionHandlerProps) => {
<h6>{to.displayName} :</h6>
<p> {to.description || <i>No description Provided</i>}</p>
{pluginMessage()}
{ sensitiveCall ? <p className='text-warning'><i className="fas fa-exclamation-triangle mr-2" aria-hidden="true"></i>You are going to process a sensitive call. Please make sure you trust this plugin.</p> : '' }
{ sensitiveCall ? <p className='text-warning'><i className="fas fa-exclamation-triangle mr-2" aria-hidden="true"></i>Make sure you trust this plugin before processing this call.</p> : '' }
</article>
<article className='remember'>
{ !sensitiveCall && <div className='form-check'>

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

@ -80,9 +80,9 @@ export const RemixUiStaticAnalyser = (props: RemixUiStaticAnalyserProps) => {
const tmp: RegExpExecArray | null = /^(\d+.\d+.\d+)/.exec(version)
return tmp ? tmp[1] : version
}
if (version != '' && !semver.gt(truncateVersion(version), '0.4.12')) {
if (version && version != '' && !semver.gt(truncateVersion(version), '0.4.12')) {
setIsSupportedVersion(false)
setRunButtonTitle('Sselect Solidity compiler version greater than 0.4.12.')
setRunButtonTitle('Select Solidity compiler version greater than 0.4.12.')
} else {
setIsSupportedVersion(true)
setRunButtonTitle('Run static analysis')

@ -186,7 +186,7 @@ export const TabsUI = (props: TabsUIProps) => {
}}
>
<TabList className="d-flex flex-row align-items-center">
{props.tabs.map((tab, i) => <Tab className="py-1" key={tab.name}>{renderTab(tab, i)}</Tab>)}
{props.tabs.map((tab, i) => <Tab className="" key={tab.name}>{renderTab(tab, i)}</Tab>)}
</TabList>
{props.tabs.map((tab) => <TabPanel key={tab.name} ></TabPanel>)}
</Tabs>

@ -7,7 +7,7 @@
}
.remixui_fileexplorer {
position : relative;
overflow-y : auto;
overflow-y : hidden;
}
.remixui_fileExplorerTree {
cursor : default;

@ -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