diff --git a/apps/remix-ide-e2e/src/tests/vyper_api.test.ts b/apps/remix-ide-e2e/src/tests/vyper_api.test.ts index 5ef312d8a2..3ac5b65610 100644 --- a/apps/remix-ide-e2e/src/tests/vyper_api.test.ts +++ b/apps/remix-ide-e2e/src/tests/vyper_api.test.ts @@ -41,8 +41,30 @@ module.exports = { .openFile('examples/auctions/blind_auction.vy') }, + 'Context menu click to compile blind_auction should succeed #group1': function (browser: NightwatchBrowser) { + browser + .click('*[data-id="treeViewLitreeViewItemexamples/auctions/blind_auction.vy"]') + .rightClick('*[data-id="treeViewLitreeViewItemexamples/auctions/blind_auction.vy"]') + .waitForElementPresent('[data-id="contextMenuItemvyper"]') + .click('[data-id="contextMenuItemvyper"]') + .clickLaunchIcon('vyper') + // @ts-ignore + .frame(0) + .waitForElementVisible({ + selector:'[data-id="compilation-details"]', + timeout: 120000 + }) + .click('[data-id="compilation-details"]') + .frameParent() + .waitForElementVisible('[data-id="copy-abi"]') + .waitForElementVisible({ + selector: "//*[@class='variable-value' and contains(.,'highestBidder')]", + locateStrategy: 'xpath', + }) + }, + 'Compile blind_auction should success #group1': function (browser: NightwatchBrowser) { - browser.clickLaunchIcon('vyper') + browser // @ts-ignore .frame(0) .click('[data-id="remote-compiler"]') diff --git a/apps/remix-ide/src/remixAppManager.js b/apps/remix-ide/src/remixAppManager.js index 19716a2f84..8fa3fb15dd 100644 --- a/apps/remix-ide/src/remixAppManager.js +++ b/apps/remix-ide/src/remixAppManager.js @@ -153,7 +153,7 @@ export class RemixAppManager extends PluginManager { if (Registry.getInstance().get('platform').api.isDesktop()) { requiredModules = [...requiredModules, 'fs', 'electronTemplates', 'isogit', 'remix-templates', 'electronconfig', 'xterm', 'compilerloader', 'ripgrep'] } - + } async canActivatePlugin(from, to) { @@ -331,6 +331,17 @@ export class RemixAppManager extends PluginManager { sticky: true, group: 7 }) + await this.call('filePanel', 'registerContextMenuItem', { + id: 'vyper', + name: 'vyperCompileCustomAction', + label: 'Compile for Vyper', + type: [], + extension: ['.vy'], + path: [], + pattern: [], + sticky: true, + group: 7 + }) if (Registry.getInstance().get('platform').api.isDesktop()) { await this.call('filePanel', 'registerContextMenuItem', { id: 'fs', diff --git a/apps/vyper/src/app/app.tsx b/apps/vyper/src/app/app.tsx index ebcfdd3aac..0a20e9d462 100644 --- a/apps/vyper/src/app/app.tsx +++ b/apps/vyper/src/app/app.tsx @@ -28,7 +28,7 @@ interface OutputMap { const App = () => { const [contract, setContract] = useState() - const [output, setOutput] = useState({}) + const [output, setOutput] = useState(remixClient.compilerOutput) const [state, setState] = useState({ status: 'idle', environment: 'remote', @@ -53,6 +53,30 @@ const App = () => { start() }, []) + useEffect(() => { + remixClient.eventEmitter.on('resetCompilerState', () => { + resetCompilerResultState() + }) + + return () => { + remixClient.eventEmitter.off('resetCompilerState', () => { + resetCompilerResultState() + }) + } + }, []) + + useEffect(() => { + remixClient.eventEmitter.on('setOutput', (payload) => { + setOutput(payload) + }) + + return () => { + remixClient.eventEmitter.off('setOutput', (payload) => { + setOutput(payload) + }) + } + }, []) + /** Update the environment state value */ function setEnvironment(environment: 'local' | 'remote') { setState({...state, environment}) @@ -67,7 +91,7 @@ const App = () => { } function resetCompilerResultState() { - setOutput({}) + setOutput(remixClient.compilerOutput) } return ( diff --git a/apps/vyper/src/app/components/CompilerButton.tsx b/apps/vyper/src/app/components/CompilerButton.tsx index ad04d0ba04..f7d2331348 100644 --- a/apps/vyper/src/app/components/CompilerButton.tsx +++ b/apps/vyper/src/app/components/CompilerButton.tsx @@ -1,7 +1,6 @@ import React, { Fragment, useState } from 'react' -import {isVyper, compile, toStandardOutput, isCompilationError, remixClient, normalizeContractPath} from '../utils' +import {isVyper, compile, toStandardOutput, isCompilationError, remixClient, normalizeContractPath, compileContract} from '../utils' import Button from 'react-bootstrap/Button' -import _ from 'lodash' interface Props { compilerUrl: string @@ -21,112 +20,14 @@ function CompilerButton({contract, setOutput, compilerUrl, resetCompilerState}: } /** Compile a Contract */ - async function compileContract() { - resetCompilerState() - setLoadingSpinnerState(true) - try { - // await remixClient.discardHighlight() - let _contract: any - try { - _contract = await remixClient.getContract() - } catch (e: any) { - setOutput('', {status: 'failed', message: e.message}) - return - } - remixClient.changeStatus({ - key: 'loading', - type: 'info', - title: 'Compiling' - }) - let output - try { - output = await compile(compilerUrl, _contract) - } catch (e: any) { - remixClient.changeStatus({ - key: 'failed', - type: 'error', - title: e.message - }) - return - } - const compileReturnType = () => { - const t: any = toStandardOutput(contract, output) - const temp = _.merge(t['contracts'][contract]) - const normal = normalizeContractPath(contract)[2] - const abi = temp[normal]['abi'] - const evm = _.merge(temp[normal]['evm']) - const dpb = evm.deployedBytecode - const runtimeBytecode = evm.bytecode - const methodIdentifiers = evm.methodIdentifiers - - const result = { - contractName: normal, - abi: abi, - bytecode: dpb, - runtimeBytecode: runtimeBytecode, - ir: '', - methodIdentifiers: methodIdentifiers - } - return result - } - - // ERROR - if (isCompilationError(output)) { - const line = output.line - if (line) { - const lineColumnPos = { - start: {line: line - 1, column: 10}, - end: {line: line - 1, column: 10} - } - // remixClient.highlight(lineColumnPos as any, _contract.name, '#e0b4b4') - } else { - const regex = output?.message?.match(/line ((\d+):(\d+))+/g) - const errors = output?.message?.split(/line ((\d+):(\d+))+/g) // extract error message - if (regex) { - let errorIndex = 0 - regex.map((errorLocation) => { - const location = errorLocation?.replace('line ', '').split(':') - let message = errors[errorIndex] - errorIndex = errorIndex + 4 - if (message && message?.split('\n\n').length > 0) { - try { - message = message?.split('\n\n')[message.split('\n\n').length - 1] - } catch (e) {} - } - if (location?.length > 0) { - const lineColumnPos = { - start: {line: parseInt(location[0]) - 1, column: 10}, - end: {line: parseInt(location[0]) - 1, column: 10} - } - // remixClient.highlight(lineColumnPos as any, _contract.name, message) - } - }) - } - } - throw new Error(output.message) - } - // SUCCESS - // remixClient.discardHighlight() - remixClient.changeStatus({ - key: 'succeed', - type: 'success', - title: 'success' - }) - const data = toStandardOutput(_contract.name, output) - remixClient.compilationFinish(_contract.name, _contract.content, data) - setOutput(_contract.name, compileReturnType()) - } catch (err: any) { - remixClient.changeStatus({ - key: 'failed', - type: 'error', - title: err.message - }) - } - } return ( -