more error handling

pull/2917/head
filip mertens 2 years ago
parent 58390a8a49
commit 6b115f5550
  1. 128
      apps/remix-ide/src/app/plugins/parser/services/code-parser-compiler.ts
  2. 6
      apps/remix-ide/src/app/plugins/parser/services/code-parser-imports.ts
  3. 7
      libs/remix-ui/editor/src/lib/providers/completion/completionGlobals.ts
  4. 31
      libs/remix-ui/editor/src/lib/providers/completion/contracts/contracts.txt
  5. 7
      libs/remix-ui/editor/src/lib/providers/completionProvider.ts
  6. 18
      libs/remix-ui/editor/src/lib/providers/definitionProvider.ts
  7. 4
      libs/remix-ui/search/src/index.ts
  8. 2
      package.json

@ -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
@ -39,41 +40,51 @@ export default class CodeParserCompiler {
init() {
this.onAstFinished = async (success, data: CompilationResult, source: CompilationSource, input: any, version) => {
//console.log('onAstFinished', success, data, source, input, version)
this.plugin.call('editor', 'clearAnnotations')
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) {
//console.log(error)
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)
@ -144,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] = []
@ -165,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) => {
@ -179,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: '',
@ -194,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: '',
@ -212,9 +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
if (!sources) return
for (const fileName of Object.keys(sources)) {
const decorator: fileDecoration = {
path: fileName,
@ -234,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
}
}

@ -23,8 +23,6 @@ export default class CodeParserImports {
async init() {
// @ts-ignore
const txt = await import('raw-loader!libs/remix-ui/editor/src/lib/providers/completion/contracts/contracts.txt')
// eslint-disable-next-line @typescript-eslint/no-unused-vars
this.data.modules = txt.default.split('\n')
.filter(x => x !== '')
.map(x => x.replace('./node_modules/', ''))
@ -38,13 +36,11 @@ export default class CodeParserImports {
// get unique first words of the values in the array
this.data.packages = [...new Set(this.data.modules.map(x => x.split('/')[0]))]
console.log(this.data)
}
setFileTree = async () => {
this.data.files = await this.getDirectory('/')
this.data.files = this.data.files.filter(x => x.endsWith('.sol') && !x.startsWith('.deps'))
console.log(this.data)
this.data.files = this.data.files.filter(x => x.endsWith('.sol') && !x.startsWith('.deps') && !x.startsWith('.git'))
}
getDirectory = async (dir: string) => {

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

@ -1,3 +1,34 @@
./node_modules/@hq20/contracts/contracts/access/AccessControlBasic.sol
./node_modules/@hq20/contracts/contracts/access/Administered.sol
./node_modules/@hq20/contracts/contracts/access/AuthorizedAccess.sol
./node_modules/@hq20/contracts/contracts/access/Community.sol
./node_modules/@hq20/contracts/contracts/access/Democracy.sol
./node_modules/@hq20/contracts/contracts/access/Hierarchy.sol
./node_modules/@hq20/contracts/contracts/classifieds/Classifieds.sol
./node_modules/@hq20/contracts/contracts/dao/DAO.sol
./node_modules/@hq20/contracts/contracts/dao/VentureEth.sol
./node_modules/@hq20/contracts/contracts/energy/EnergyMarket.sol
./node_modules/@hq20/contracts/contracts/exchange/UniswapExchange.sol
./node_modules/@hq20/contracts/contracts/exchange/UniswapFactory.sol
./node_modules/@hq20/contracts/contracts/introspection/erc165/ERC20Whitelisted.sol
./node_modules/@hq20/contracts/contracts/introspection/erc165/IWhitelist.sol
./node_modules/@hq20/contracts/contracts/introspection/erc165/WhitelistERC165.sol
./node_modules/@hq20/contracts/contracts/introspection/erc165/WhitelistInterfaceId.sol
./node_modules/@hq20/contracts/contracts/issuance/Issuance.sol
./node_modules/@hq20/contracts/contracts/issuance/IssuanceEth.sol
./node_modules/@hq20/contracts/contracts/lists/DoubleLinkedList.sol
./node_modules/@hq20/contracts/contracts/lists/LinkedList.sol
./node_modules/@hq20/contracts/contracts/math/DecimalMath.sol
./node_modules/@hq20/contracts/contracts/state/StateMachine.sol
./node_modules/@hq20/contracts/contracts/token/ERC20DividendableEth.sol
./node_modules/@hq20/contracts/contracts/token/ERC20Mintable.sol
./node_modules/@hq20/contracts/contracts/token/ERC721Mintable.sol
./node_modules/@hq20/contracts/contracts/token/IERC20Detailed.sol
./node_modules/@hq20/contracts/contracts/token/IERC20Mintable.sol
./node_modules/@hq20/contracts/contracts/utils/SafeCast.sol
./node_modules/@hq20/contracts/contracts/voting/Democratic.sol
./node_modules/@hq20/contracts/contracts/voting/OneManOneVote.sol
./node_modules/@hq20/contracts/contracts/voting/OneTokenOneVote.sol
./node_modules/@openzeppelin/contracts/access/AccessControl.sol
./node_modules/@openzeppelin/contracts/access/AccessControlCrossChain.sol
./node_modules/@openzeppelin/contracts/access/AccessControlEnumerable.sol

@ -28,16 +28,16 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
startColumn: word.startColumn,
endColumn: word.endColumn
};
console.log(word)
const line = model.getLineContent(position.lineNumber)
let nodes: AstNode[] = []
let suggestions: monaco.languages.CompletionItem[] = []
console.log('context', context.triggerCharacter)
if (context.triggerCharacter === '"' || context.triggerCharacter === '@' || context.triggerCharacter === '/') {
const lastpart = line.substring(0, position.column - 1).split(';').pop()
console.log('lastpart', lastpart)
if (lastpart.startsWith('import')) {
const imports = await this.props.plugin.call('codeParser', 'getImports')
if (context.triggerCharacter === '"' || context.triggerCharacter === '@') {
@ -46,7 +46,6 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
]
} else if (context.triggerCharacter === '/') {
const word = line.split('"')[1]
console.log(word)
suggestions = [...suggestions,
...GetImports(range, this.monaco, imports, word),
]

@ -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 { SearchTab } from './lib/components/Search';
export * from './lib/components/results/SearchHelper';
export * from './lib/types';

@ -109,7 +109,7 @@
"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",
"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"
"build-contracts": "find ./node_modules/@hq20/contracts | grep -i '.sol' > libs/remix-ui/editor/src/lib/providers/completion/contracts/contracts.txt && 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": [

Loading…
Cancel
Save