Merge branch 'master' into importautocomplete

pull/5370/head
bunsenstraat 2 years ago committed by GitHub
commit 020069e199
  1. 4
      .circleci/config.yml
  2. 49
      apps/remix-ide-e2e/src/tests/ballot.test.ts
  3. 38
      apps/remix-ide-e2e/src/tests/ballot_0_4_11.test.ts
  4. 21
      apps/remix-ide/src/app.js
  5. 82
      apps/remix-ide/src/app/plugins/code-format.ts
  6. 61
      apps/remix-ide/src/app/plugins/code-format/index.ts
  7. 197
      apps/remix-ide/src/app/plugins/code-format/parser.ts
  8. 2
      apps/remix-ide/src/remixAppManager.js
  9. 23
      libs/remix-ui/editor/src/lib/remix-ui-editor.tsx
  10. 2
      package.json
  11. 50
      yarn.lock

@ -111,7 +111,7 @@ jobs:
- COMMIT_AUTHOR: "Circle CI"
working_directory: ~/remix-project
parallelism: 80
parallelism: 90
steps:
- browser-tools/install-chrome
- browser-tools/install-chromedriver
@ -197,7 +197,7 @@ jobs:
- COMMIT_AUTHOR: "Circle CI"
working_directory: ~/remix-project
parallelism: 80
parallelism: 90
steps:
- browser-tools/install-firefox
- browser-tools/install-geckodriver

@ -9,13 +9,18 @@ const sources = [
]
module.exports = {
"@disabled": true,
before: function (browser: NightwatchBrowser, done: VoidFunction) {
init(browser, done)
},
'@sources': function () {
return sources
},
'Deploy Ballot': function (browser: NightwatchBrowser) {
'Add Ballot #group2': function (browser: NightwatchBrowser) {
browser
.addFile('Untitled.sol', sources[0]['Untitled.sol'])
},
'Deploy Ballot #group1': function (browser: NightwatchBrowser) {
browser
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000)
.clickLaunchIcon('solidity')
@ -34,7 +39,7 @@ module.exports = {
})
},
'Call method from Ballot to check return value': function (browser: NightwatchBrowser) {
'Call method from Ballot to check return value #group1': function (browser: NightwatchBrowser) {
browser
.clickFunction('winnerName - call')
// Test in terminal
@ -47,7 +52,7 @@ module.exports = {
.assert.containsText('*[data-id="treeViewDiv0"]', 'bytes32: winnerName_ 0x48656c6c6f20576f726c64210000000000000000000000000000000000000000')
},
'Debug Ballot / delegate': function (browser: NightwatchBrowser) {
'Debug Ballot / delegate #group1': function (browser: NightwatchBrowser) {
browser.pause(500)
.debugTransaction(1)
.waitForElementVisible('*[data-id="buttonNavigatorJumpPreviousBreakpoint"]')
@ -60,16 +65,24 @@ module.exports = {
.checkVariableDebug('soliditylocals', localsCheck)
},
'Access Ballot via at address': function (browser: NightwatchBrowser) {
'Access Ballot via at address #group1': function (browser: NightwatchBrowser) {
browser.clickLaunchIcon('udapp')
.click('*[data-id="universalDappUiUdappClose"]')
.addFile('ballot.abi', { content: ballotABI })
.clickLaunchIcon('udapp')
.click({
selector: '*[data-id="deployAndRunClearInstances"]',
abortOnFailure: false,
suppressNotFoundErrors: true,
})
// we are not changing the visibility for not checksumed contracts
// .addAtAddressInstance('0x692a70D2e424a56D2C6C27aA97D1a86395877b3B', true, false)
.clickLaunchIcon('filePanel')
.addAtAddressInstance('0x692a70D2e424a56D2C6C27aA97D1a86395877b3A', true, true)
.pause(500)
.waitForElementPresent('*[data-id="universalDappUiContractActionWrapper"]', 60000)
.waitForElementVisible({
locateStrategy: 'xpath',
selector: "//*[@id='instance0x692a70D2e424a56D2C6C27aA97D1a86395877b3A']"
})
.clickInstance(0)
.clickFunction('delegate - transact (not payable)', { types: 'address to', values: '"0x4b0897b0513fdc7c541b6d9d7e929c4e5364d2db"' })
.testFunction('last',
@ -79,19 +92,11 @@ module.exports = {
})
},
'Deploy and use Ballot using external web3': function (browser: NightwatchBrowser) {
'Deploy and use Ballot using external web3 #group2': function (browser: NightwatchBrowser) {
browser
.openFile('Untitled.sol')
.clickLaunchIcon('udapp')
.switchEnvironment('External Http Provider')
.waitForElementPresent('[data-id="basic-http-provider-modal-footer-ok-react"]')
.execute(function () {
const modal = document.querySelector('[data-id="basic-http-provider-modal-footer-ok-react"]') as any
modal.click()
})
.pause(5000)
.waitForElementContainsText('#selectExEnvOptions button', 'External Http Provider')
.connectToExternalHttpProvider('http://localhost:8545', 'Custom')
.clickLaunchIcon('solidity')
.clickLaunchIcon('udapp')
.pause(2000)
@ -105,7 +110,7 @@ module.exports = {
.journalLastChildIncludes('data: 0x5c1...a733c')
},
'Call method from Ballot to check return value using external web3': function (browser: NightwatchBrowser) {
'Call method from Ballot to check return value using external web3 #group2': function (browser: NightwatchBrowser) {
browser
.clickFunction('winnerName - call')
// Test in terminal
@ -118,9 +123,9 @@ module.exports = {
.assert.containsText('*[data-id="treeViewDiv0"]', 'bytes32: winnerName_ 0x48656c6c6f20576f726c64210000000000000000000000000000000000000000')
},
'Compile Ballot using config file': function (browser: NightwatchBrowser) {
'Compile Ballot using config file #group2': function (browser: NightwatchBrowser) {
browser
.addFile('cf.json', {content: configFile})
.addFile('cf.json', { content: configFile })
.clickLaunchIcon('solidity')
.waitForElementVisible('*[data-id="scConfigExpander"]')
.click('*[data-id="scConfigExpander"]')
@ -133,12 +138,12 @@ module.exports = {
.setValue('*[data-id="scConfigFilePathInput"]', 'cf.json')
.sendKeys('*[data-id$="scConfigFilePathInput"]', browser.Keys.ENTER)
.openFile('Untitled.sol')
.verifyContracts(['Ballot'], {wait: 2000, runs: '300'})
.verifyContracts(['Ballot'], { wait: 2000, runs: '300' })
},
'Compile and deploy sample yul file': function (browser: NightwatchBrowser) {
'Compile and deploy sample yul file #group2': function (browser: NightwatchBrowser) {
browser
.addFile('sample.yul', {content: yulSample})
.addFile('sample.yul', { content: yulSample })
.clickLaunchIcon('solidity')
.waitForElementVisible('*[data-id="scConfigExpander"]')
.click('*[data-id="scManualConfiguration"]')

@ -9,13 +9,14 @@ const sources = [
]
module.exports = {
'@disabled': true,
before: function (browser: NightwatchBrowser, done: VoidFunction) {
init(browser, done, null, false)
},
'@sources': function () {
return sources
},
'Compile Ballot with compiler version 0.4.11': function (browser: NightwatchBrowser) {
'Set Ballot 0.4.11': function (browser: NightwatchBrowser) {
browser
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000)
.clickLaunchIcon('solidity')
@ -23,10 +24,13 @@ module.exports = {
.waitForElementVisible('[for="autoCompile"]')
.click('[for="autoCompile"]')
.verify.elementPresent('[data-id="compilerContainerAutoCompile"]:checked')
},
'Compile Ballot with compiler version 0.4.11 #group1 #group2': function (browser: NightwatchBrowser) {
browser
.testContracts('Untitled.sol', sources[0]['Untitled.sol'], ['Ballot'])
},
'Deploy Ballot': function (browser: NightwatchBrowser) {
'Deploy Ballot #group1': function (browser: NightwatchBrowser) {
browser.pause(500)
.clickLaunchIcon('udapp')
.selectAccount('0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c')
@ -42,7 +46,7 @@ module.exports = {
})
},
'Debug Ballot / delegate': function (browser: NightwatchBrowser) {
'Debug Ballot / delegate #group1': function (browser: NightwatchBrowser) {
browser.pause(500)
.debugTransaction(1)
.pause(2000)
@ -55,16 +59,24 @@ module.exports = {
.checkVariableDebug('callstackpanel', ['0x692a70D2e424a56D2C6C27aA97D1a86395877b3A'])
},
'Access Ballot via at address': function (browser: NightwatchBrowser) {
'Access Ballot via at address #group1': function (browser: NightwatchBrowser) {
browser.clickLaunchIcon('udapp')
.click('*[data-id="universalDappUiUdappClose"]')
.addFile('ballot.abi', { content: ballotABI })
.clickLaunchIcon('udapp')
.click({
selector: '*[data-id="deployAndRunClearInstances"]',
abortOnFailure: false,
suppressNotFoundErrors: true,
})
// we are not changing the visibility for not checksumed contracts
// .addAtAddressInstance('0x692a70D2e424a56D2C6C27aA97D1a86395877b3B', true, false)
.clickLaunchIcon('filePanel')
.addAtAddressInstance('0x692a70D2e424a56D2C6C27aA97D1a86395877b3A', true, true)
.pause(500)
.waitForElementPresent('*[data-id="universalDappUiContractActionWrapper"]', 60000)
.waitForElementVisible({
locateStrategy: 'xpath',
selector: "//*[@id='instance0x692a70D2e424a56D2C6C27aA97D1a86395877b3A']"
})
.clickInstance(0)
.clickFunction('delegate - transact (not payable)', { types: 'address to', values: '"0x4b0897b0513fdc7c541b6d9d7e929c4e5364d2db"' })
.testFunction('last',
@ -73,18 +85,11 @@ module.exports = {
'decoded input': { 'address to': '0x4B0897b0513fdC7C541B6d9D7E929C4e5364D2dB' }
})
},
'Deploy and use Ballot using external web3': function (browser: NightwatchBrowser) {
'Deploy and use Ballot using external web3 #group2': function (browser: NightwatchBrowser) {
browser
.openFile('Untitled.sol')
.clickLaunchIcon('udapp')
.switchEnvironment('External Http Provider')
.waitForElementPresent('[data-id="basic-http-provider-modal-footer-ok-react"]')
.execute(function () {
const modal = document.querySelector('[data-id="basic-http-provider-modal-footer-ok-react"]') as any
modal.click()
})
.clickLaunchIcon('udapp')
.connectToExternalHttpProvider('http://localhost:8545', 'Custom')
.clickLaunchIcon('solidity')
.clickLaunchIcon('udapp')
.pause(2000)
@ -96,7 +101,6 @@ module.exports = {
.clickFunction('delegate - transact (not payable)', { types: 'address to', values: '0xCA35b7d915458EF540aDe6068dFe2F44E8fa733c' })
.journalLastChildIncludes('Ballot.delegate(address)')
.journalLastChildIncludes('data: 0x5c1...a733c')
.end()
}
}

@ -33,6 +33,7 @@ import { ExternalHttpProvider } from './app/tabs/external-http-provider'
import { Injected0ptimismProvider } from './app/tabs/injected-optimism-provider'
import { InjectedArbitrumOneProvider } from './app/tabs/injected-arbitrum-one-provider'
import { FileDecorator } from './app/plugins/file-decorator'
import { CodeFormat } from './app/plugins/code-format'
const isElectron = require('is-electron')
@ -63,7 +64,7 @@ const Terminal = require('./app/panels/terminal')
const { TabProxy } = require('./app/panels/tab-proxy.js')
class AppComponent {
constructor () {
constructor() {
this.appManager = new RemixAppManager({})
this.queryParams = new QueryParams()
this._components = {}
@ -100,7 +101,7 @@ class AppComponent {
})
}
async run () {
async run() {
// APP_MANAGER
const appManager = this.appManager
const pluginLoader = this.appManager.pluginLoader
@ -161,6 +162,9 @@ class AppComponent {
// ------- FILE DECORATOR PLUGIN ------------------
const fileDecorator = new FileDecorator()
// ------- CODE FORMAT PLUGIN ------------------
const codeFormat = new CodeFormat()
//----- search
const search = new SearchPlugin()
@ -213,7 +217,7 @@ class AppComponent {
}
}
)
const codeParser = new CodeParser(new AstWalker())
@ -221,7 +225,7 @@ class AppComponent {
const configPlugin = new ConfigPlugin()
this.layout = new Layout()
const permissionHandler = new PermissionHandlerPlugin()
this.engine.register([
@ -241,6 +245,7 @@ class AppComponent {
offsetToLineColumnConverter,
codeParser,
fileDecorator,
codeFormat,
terminal,
web3Provider,
compileAndRun,
@ -351,10 +356,10 @@ class AppComponent {
}
}
async activate () {
async activate() {
const queryParams = new QueryParams()
const params = queryParams.get()
try {
this.engine.register(await this.appManager.registeredPlugins())
} catch (e) {
@ -368,9 +373,9 @@ class AppComponent {
await this.appManager.activatePlugin(['sidePanel']) // activating host plugin separately
await this.appManager.activatePlugin(['home'])
await this.appManager.activatePlugin(['settings', 'config'])
await this.appManager.activatePlugin(['hiddenPanel', 'pluginManager', 'codeParser', 'fileDecorator', 'terminal', 'blockchain', 'fetchAndCompile', 'contentImport', 'gistHandler'])
await this.appManager.activatePlugin(['hiddenPanel', 'pluginManager', 'codeParser', 'codeFormatter', 'fileDecorator', 'terminal', 'blockchain', 'fetchAndCompile', 'contentImport', 'gistHandler'])
await this.appManager.activatePlugin(['settings'])
await this.appManager.activatePlugin(['walkthrough','storage', 'search','compileAndRun', 'recorder'])
await this.appManager.activatePlugin(['walkthrough', 'storage', 'search', 'compileAndRun', 'recorder'])
this.appManager.on(
'filePanel',

@ -0,0 +1,82 @@
'use strict'
import { Plugin } from '@remixproject/engine'
import prettier from 'prettier/standalone'
import { Options } from 'prettier';
import sol from './code-format/index'
import * as ts from 'prettier/parser-typescript'
import * as babel from 'prettier/parser-babel'
import * as espree from 'prettier/parser-espree'
import path from 'path'
const profile = {
name: 'codeFormatter',
desciption: 'prettier plugin for Remix',
methods: ['format'],
events: [''],
version: '0.0.1'
}
export class CodeFormat extends Plugin {
constructor() {
super(profile)
}
async format(file: string) {
try {
const content = await this.call('fileManager', 'readFile', file)
if (!content) return
let parserName = ''
let options: Options = {
}
switch (path.extname(file)) {
case '.sol':
parserName = 'solidity-parse'
break
case '.ts':
parserName = 'typescript'
options = {
...options,
trailingComma: 'all',
semi: false,
singleQuote: true,
quoteProps: 'as-needed',
bracketSpacing: true,
arrowParens: 'always',
}
break
case '.js':
parserName = "espree"
options = {
...options,
semi: false,
singleQuote: true,
}
break
case '.json':
parserName = 'json'
break
}
const result = prettier.format(content, {
plugins: [sol as any, ts, babel, espree],
parser: parserName,
...options
})
await this.call('fileManager', 'writeFile', file, result)
} catch (e) {
// do nothing
}
}
}
function getRange(index, node) {
if (node.range) {
return node.range[index];
}
if (node.expression && node.expression.range) {
return node.expression.range[index];
}
return null;
}

@ -0,0 +1,61 @@
import { handleComments, printComment } from 'prettier-plugin-solidity/src/comments';
import massageAstNode from 'prettier-plugin-solidity/src/clean.js';
import options from 'prettier-plugin-solidity/src/options.js';
import print from 'prettier-plugin-solidity/src/printer.js';
import loc from 'prettier-plugin-solidity/src/loc.js';
import { parse } from './parser'
// https://prettier.io/docs/en/plugins.html#languages
// https://github.com/ikatyang/linguist-languages/blob/master/data/Solidity.json
const languages = [
{
linguistLanguageId: 237469032,
name: 'Solidity',
type: 'programming',
color: '#AA6746',
aceMode: 'text',
tmScope: 'source.solidity',
extensions: ['.sol'],
parsers: ['solidity-parse'],
vscodeLanguageIds: ['solidity']
}
];
// https://prettier.io/docs/en/plugins.html#parsers
const parser = { astFormat: 'solidity-ast', parse, ...loc };
const parsers = {
'solidity-parse': parser
};
const canAttachComment = (node) =>
node.type && node.type !== 'BlockComment' && node.type !== 'LineComment';
// https://prettier.io/docs/en/plugins.html#printers
const printers = {
'solidity-ast': {
canAttachComment,
handleComments: {
ownLine: handleComments.handleOwnLineComment,
endOfLine: handleComments.handleEndOfLineComment,
remaining: handleComments.handleRemainingComment
},
isBlockComment: handleComments.isBlockComment,
massageAstNode,
print,
printComment
}
};
// https://prettier.io/docs/en/plugins.html#defaultoptions
const defaultOptions = {
bracketSpacing: false,
tabWidth: 4
};
export default {
languages,
parsers,
printers,
options,
defaultOptions
};

@ -0,0 +1,197 @@
// https://prettier.io/docs/en/plugins.html#parsers
import extractComments from 'solidity-comments-extractor';
// use the parser already included in the app
const parser = (window as any).SolidityParser
import semver from 'semver';
const tryHug = (node, operators) => {
if (node.type === 'BinaryOperation' && operators.includes(node.operator))
return {
type: 'TupleExpression',
components: [node],
isArray: false
};
return node;
};
export function parse(text, _parsers, options) {
const compiler = semver.coerce(options.compiler);
const parsed = parser.parse(text, { loc: true, range: true });
parsed.comments = extractComments(text)
parser.visit(parsed, {
PragmaDirective(ctx) {
// if the pragma is not for solidity we leave.
if (ctx.name !== 'solidity') return;
// if the compiler option has not been provided we leave.
if (!compiler) return;
// we make a check against each pragma directive in the document.
if (!semver.satisfies(compiler, ctx.value)) {
// @TODO: investigate the best way to warn that would apply to
// different editors.
// eslint-disable-next-line no-console
console.warn(
`[prettier-solidity] The compiler option is set to '${options.compiler}', which does not satisfy 'pragma solidity ${ctx.value}'.`
);
}
},
ModifierDefinition(ctx) {
if (!ctx.parameters) {
ctx.parameters = [];
}
},
FunctionDefinition(ctx) {
if (!ctx.isConstructor) {
ctx.modifiers.forEach((modifier) => {
if (modifier.arguments && modifier.arguments.length === 0) {
// eslint-disable-next-line no-param-reassign
modifier.arguments = null;
}
});
}
},
ForStatement(ctx) {
if (ctx.initExpression) {
ctx.initExpression.omitSemicolon = true;
}
ctx.loopExpression.omitSemicolon = true;
},
HexLiteral(ctx) {
ctx.value = options.singleQuote
? `hex'${ctx.value.slice(4, -1)}'`
: `hex"${ctx.value.slice(4, -1)}"`;
},
ElementaryTypeName(ctx) {
// if the compiler is below 0.8.0 we will recognize the type 'byte' as an
// alias of 'bytes1'. Otherwise we will ignore this and enforce always
// 'bytes1'.
const pre080 = compiler && semver.satisfies(compiler, '<0.8.0');
if (!pre080 && ctx.name === 'byte') ctx.name = 'bytes1';
if (options.explicitTypes === 'always') {
if (ctx.name === 'uint') ctx.name = 'uint256';
if (ctx.name === 'int') ctx.name = 'int256';
if (pre080 && ctx.name === 'byte') ctx.name = 'bytes1';
} else if (options.explicitTypes === 'never') {
if (ctx.name === 'uint256') ctx.name = 'uint';
if (ctx.name === 'int256') ctx.name = 'int';
if (pre080 && ctx.name === 'bytes1') ctx.name = 'byte';
}
},
BinaryOperation(ctx) {
switch (ctx.operator) {
case '+':
case '-':
ctx.left = tryHug(ctx.left, ['%']);
ctx.right = tryHug(ctx.right, ['%']);
break;
case '*':
ctx.left = tryHug(ctx.left, ['/', '%']);
break;
case '/':
ctx.left = tryHug(ctx.left, ['*', '%']);
break;
case '%':
ctx.left = tryHug(ctx.left, ['*', '/', '%']);
break;
case '**':
// If the compiler has not been given as an option using we leave a**b**c.
if (!compiler) break;
if (semver.satisfies(compiler, '<0.8.0')) {
// If the compiler is less than 0.8.0 then a**b**c is formatted as
// (a**b)**c.
ctx.left = tryHug(ctx.left, ['**']);
break;
}
if (
ctx.left.type === 'BinaryOperation' &&
ctx.left.operator === '**'
) {
// the parser still organizes the a**b**c as (a**b)**c so we need
// to restructure it.
ctx.right = {
type: 'TupleExpression',
components: [
{
type: 'BinaryOperation',
operator: '**',
left: ctx.left.right,
right: ctx.right
}
],
isArray: false
};
ctx.left = ctx.left.left;
}
break;
case '<<':
case '>>':
ctx.left = tryHug(ctx.left, ['+', '-', '*', '/', '**', '<<', '>>']);
ctx.right = tryHug(ctx.right, ['+', '-', '*', '/', '**']);
break;
case '&':
ctx.left = tryHug(ctx.left, ['+', '-', '*', '/', '**', '<<', '>>']);
ctx.right = tryHug(ctx.right, ['+', '-', '*', '/', '**', '<<', '>>']);
break;
case '|':
ctx.left = tryHug(ctx.left, [
'+',
'-',
'*',
'/',
'**',
'<<',
'>>',
'&',
'^'
]);
ctx.right = tryHug(ctx.right, [
'+',
'-',
'*',
'/',
'**',
'<<',
'>>',
'&',
'^'
]);
break;
case '^':
ctx.left = tryHug(ctx.left, [
'+',
'-',
'*',
'/',
'**',
'<<',
'>>',
'&'
]);
ctx.right = tryHug(ctx.right, [
'+',
'-',
'*',
'/',
'**',
'<<',
'>>',
'&'
]);
break;
case '||':
ctx.left = tryHug(ctx.left, ['&&']);
ctx.right = tryHug(ctx.right, ['&&']);
break;
case '&&':
default:
break;
}
}
});
return parsed;
}

@ -11,7 +11,7 @@ const requiredModules = [ // services + layout views + system views
'filePanel', 'terminal', 'settings', 'pluginManager', 'tabs', 'udapp', 'dGitProvider', 'solidity', 'solidity-logic', 'gistHandler', 'layout',
'notification', 'permissionhandler', 'walkthrough', 'storage', 'restorebackupzip', 'link-libraries', 'deploy-libraries', 'openzeppelin-proxy',
'hardhat-provider', 'ganache-provider', 'foundry-provider', 'basic-http-provider', 'injected-optimism-provider', 'injected-arbitrum-one-provider',
'compileAndRun', 'search', 'recorder', 'fileDecorator', 'codeParser']
'compileAndRun', 'search', 'recorder', 'fileDecorator', 'codeParser', 'codeFormatter']
// dependentModules shouldn't be manually activated (e.g hardhat is activated by remixd)
const dependentModules = ['hardhat', 'truffle', 'slither']

@ -122,9 +122,11 @@ export const EditorUI = (props: EditorUIProps) => {
\t\t\t\t\t\t\t|_| \\_\\ |_____| |_| |_| |___| /_/\\_\\ |___| |____/ |_____|\n\n
\t\t\t\t\t\t\tKeyboard Shortcuts:\n
\t\t\t\t\t\t\t\tCTRL + S: Compile the current contract\n
\t\t\t\t\t\t\t\tCtrl + Shift + F : Open the File Explorer\n
\t\t\t\t\t\t\t\tCtrl + Shift + A : Open the Plugin Manager\n
\t\t\t\t\t\t\t\tCTRL + SHIFT + S: Compile the current contract & Run an associated script\n\n
\t\t\t\t\t\t\t\tCTRL + Shift + F : Open the File Explorer\n
\t\t\t\t\t\t\t\tCTRL + Shift + A : Open the Plugin Manager\n
\t\t\t\t\t\t\t\tCTRL + SHIFT + S: Compile the current contract & Run an associated script\n
\t\t\t\t\t\t\tEditor Keyboard Shortcuts:\n
\t\t\t\t\t\t\t\tCTRL + Alt + F : Format the code in the current file\n
\t\t\t\t\t\t\tImportant Links:\n
\t\t\t\t\t\t\t\tOfficial website about the Remix Project: https://remix-project.org/\n
\t\t\t\t\t\t\t\tOfficial documentation: https://remix-ide.readthedocs.io/en/latest/\n
@ -568,6 +570,21 @@ export const EditorUI = (props: EditorUIProps) => {
],
run: () => { editor.updateOptions({ fontSize: editor.getOption(43).fontSize - 1 }) },
}
const formatAction = {
id: "autoFormat",
label: "Format Code",
contextMenuOrder: 0, // choose the order
contextMenuGroupId: "formatting", // create a new grouping
keybindings: [
// eslint-disable-next-line no-bitwise
monacoRef.current.KeyMod.Shift | monacoRef.current.KeyMod.Alt | monacoRef.current.KeyCode.KeyF,
],
run: async () => {
const file = await props.plugin.call('fileManager', 'getCurrentFile')
await props.plugin.call('codeFormatter', 'format', file)
},
}
editor.addAction(formatAction)
editor.addAction(zoomOutAction)
editor.addAction(zoominAction)
const editorService = editor._codeEditorService;

@ -198,6 +198,8 @@
"merge": "^2.1.1",
"monaco-editor": "^0.30.1",
"npm-install-version": "^6.0.2",
"prettier": "^2.7.1",
"prettier-plugin-solidity": "^1.0.0-beta.24",
"raw-loader": "^4.0.2",
"react": "^17.0.2",
"react-beautiful-dnd": "^13.1.0",

@ -4103,6 +4103,13 @@
dependencies:
"@sinonjs/commons" "^1.7.0"
"@solidity-parser/parser@^0.14.3":
version "0.14.3"
resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.14.3.tgz#0d627427b35a40d8521aaa933cc3df7d07bfa36f"
integrity sha512-29g2SZ29HtsqA58pLCtopI1P/cPy5/UAzlcAXO6T/CNJimG6yA8kx4NaseMyJULiC+TEs02Y9/yeHzClqoA0hw==
dependencies:
antlr4ts "^0.5.0-alpha.4"
"@svgr/babel-plugin-add-jsx-attribute@^5.4.0":
version "5.4.0"
resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-5.4.0.tgz#81ef61947bb268eb9d50523446f9c638fb355906"
@ -5349,6 +5356,11 @@ ansistyles@~0.1.3:
resolved "https://registry.yarnpkg.com/ansistyles/-/ansistyles-0.1.3.tgz#5de60415bda071bb37127854c864f41b23254539"
integrity sha512-6QWEyvMgIXX0eO972y7YPBLSBsq7UWKFAoNNTLGaOJ9bstcEL9sCbcjf96dVfNDdUsRoGOK82vWFJlKApXds7g==
antlr4ts@^0.5.0-alpha.4:
version "0.5.0-alpha.4"
resolved "https://registry.yarnpkg.com/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz#71702865a87478ed0b40c0709f422cf14d51652a"
integrity sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==
any-promise@^1.0.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
@ -9750,6 +9762,11 @@ emittery@^0.8.1:
resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.8.1.tgz#bb23cc86d03b30aa75a7f734819dee2e1ba70860"
integrity sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==
emoji-regex@^10.1.0:
version "10.1.0"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.1.0.tgz#d50e383743c0f7a5945c47087295afc112e3cf66"
integrity sha512-xAEnNCT3w2Tg6MA7ly6QqYJvEoY1tm9iIjJ3yMKK9JPlWuRHAMoe5iETwQnx3M9TVbFMfsrBgWKR+IsmswwNjg==
emoji-regex@^7.0.1:
version "7.0.3"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
@ -9999,7 +10016,7 @@ escape-html@~1.0.3:
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=
escape-string-regexp@4.0.0:
escape-string-regexp@4.0.0, escape-string-regexp@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
@ -19128,6 +19145,23 @@ preserve@^0.2.0:
resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=
prettier-plugin-solidity@^1.0.0-beta.24:
version "1.0.0-beta.24"
resolved "https://registry.yarnpkg.com/prettier-plugin-solidity/-/prettier-plugin-solidity-1.0.0-beta.24.tgz#67573ca87098c14f7ccff3639ddd8a4cab2a87eb"
integrity sha512-6JlV5BBTWzmDSq4kZ9PTXc3eLOX7DF5HpbqmmaF+kloyUwOZbJ12hIYsUaZh2fVgZdV2t0vWcvY6qhILhlzgqg==
dependencies:
"@solidity-parser/parser" "^0.14.3"
emoji-regex "^10.1.0"
escape-string-regexp "^4.0.0"
semver "^7.3.7"
solidity-comments-extractor "^0.0.7"
string-width "^4.2.3"
prettier@^2.7.1:
version "2.7.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64"
integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==
pretty-format@^26.6.2:
version "26.6.2"
resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.6.2.tgz#e35c2705f14cb7fe2fe94fa078345b444120fc93"
@ -20961,6 +20995,13 @@ semver@^6.0.0, semver@^6.1.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semve
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
semver@^7.3.7:
version "7.3.7"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f"
integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==
dependencies:
lru-cache "^6.0.0"
send@0.17.1:
version "0.17.1"
resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8"
@ -21380,6 +21421,11 @@ solc@0.7.4:
semver "^5.5.0"
tmp "0.0.33"
solidity-comments-extractor@^0.0.7:
version "0.0.7"
resolved "https://registry.yarnpkg.com/solidity-comments-extractor/-/solidity-comments-extractor-0.0.7.tgz#99d8f1361438f84019795d928b931f4e5c39ca19"
integrity sha512-wciNMLg/Irp8OKGrh3S2tfvZiZ0NEyILfcRCXCD4mp7SgK/i9gzLfhY2hY7VMCQJ3kH9UB9BzNdibIVMchzyYw==
sort-keys@^1.0.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad"
@ -21808,7 +21854,7 @@ string-width@^1.0.1, string-width@^1.0.2:
is-fullwidth-code-point "^2.0.0"
strip-ansi "^4.0.0"
"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2:
"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==

Loading…
Cancel
Save