editorcontextDummy
filip mertens 2 years ago
parent 32c1be281e
commit abba2e3487
  1. 102
      apps/remix-ide-e2e/src/examples/editor-test-contracts.ts
  2. 311
      apps/remix-ide-e2e/src/tests/editorAutoComplete.test.ts
  3. 23
      libs/remix-ui/editor/src/lib/providers/completionProvider.ts

@ -1,12 +1,13 @@
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
const testContract = { const testContract = {
name: 'test.sol', name: 'contracts/test.sol',
content: ` content: `
// SPDX-License-Identifier: GPL-3.0 // SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0; pragma solidity >=0.7.0 <0.9.0;
import "contracts/base.sol"; import "contracts/base.sol";
import "contracts/import1.sol";
contract test is base { contract test is base {
string public publicstring; string public publicstring;
string private privatestring; string private privatestring;
@ -20,6 +21,7 @@ const testContract = {
TestBookDefinition public mybook; TestBookDefinition public mybook;
enum MyEnum{ SMALL, MEDIUM, LARGE } enum MyEnum{ SMALL, MEDIUM, LARGE }
event MyEvent(uint abc); event MyEvent(uint abc);
importcontract importedcontract;
modifier costs(uint price) { modifier costs(uint price) {
if (msg.value >= price) { if (msg.value >= price) {
@ -46,12 +48,12 @@ const testContract = {
} }
}`} }`}
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
const baseContract = { const baseContract = {
name: 'base.sol', name: 'contracts/base.sol',
content: ` content: `
// SPDX-License-Identifier: GPL-3.0 // SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0; pragma solidity >=0.7.0 <0.9.0;
@ -67,11 +69,11 @@ const testContract = {
} }
Book public book; Book public book;
}`} }`}
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
const baseOfBaseContract = { const baseOfBaseContract = {
name: 'baseofbase.sol', name: 'contracts/baseofbase.sol',
content: ` content: `
// SPDX-License-Identifier: GPL-3.0 // SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0; pragma solidity >=0.7.0 <0.9.0;
@ -102,8 +104,70 @@ const testContract = {
} }
}`} }`}
export default { const import1Contract = {
testContract, name: 'contracts/import1.sol',
baseContract, content: `
baseOfBaseContract // SPDX-License-Identifier: MIT
} pragma solidity >=0.7.0 <0.9.0;
import "contracts/importbase.sol";
import "contracts/secondimport.sol";
contract importcontract is importbase {
struct ImportedBook {
string title;
string author;
uint book_id;
}
ImportedBook public importedbook;
string private importprivatestring;
string internal internalimportstring;
string public importpublicstring;
function privateimport() private {
}
function internalimport() internal {
}
function publicimport() public {
}
function externalimport() external {
}
}`}
const importbase = {
name: 'contracts/importbase.sol',
content: `
// SPDX-License-Identifier: MIT
pragma solidity >=0.7.0 <0.9.0;
contract importbase {
string public importbasestring;
}
`}
const secondimport = {
name: 'contracts/secondimport.sol',
content: `
// SPDX-License-Identifier: MIT
pragma solidity >=0.7.0 <0.9.0;
contract secondimport {
string public secondimportstring;
}
`}
export default {
testContract,
baseContract,
baseOfBaseContract,
import1Contract,
importbase,
secondimport
}

@ -13,10 +13,13 @@ module.exports = {
init(browser, done, 'http://127.0.0.1:8080', false) init(browser, done, 'http://127.0.0.1:8080', false)
}, },
'Should add test and base files #group2': function (browser: NightwatchBrowser) { 'Should add test and base files #group2': function (browser: NightwatchBrowser) {
browser.addFile('contracts/test.sol', examples.testContract) browser.addFile(examples.testContract.name, examples.testContract)
.addFile('contracts/base.sol', examples.baseContract) .addFile(examples.baseContract.name, examples.baseContract)
.addFile('contracts/baseofbase.sol', examples.baseOfBaseContract) .addFile(examples.import1Contract.name, examples.import1Contract)
.openFile('contracts/test.sol').pause(3000) .addFile(examples.baseOfBaseContract.name, examples.baseOfBaseContract)
.addFile(examples.secondimport.name, examples.secondimport)
.addFile(examples.importbase.name, examples.importbase)
.openFile(examples.testContract.name)
}, },
'Should put cursor in the () of the function #group2': function (browser: NightwatchBrowser) { 'Should put cursor in the () of the function #group2': function (browser: NightwatchBrowser) {
browser.scrollToLine(18) browser.scrollToLine(18)
@ -27,49 +30,49 @@ module.exports = {
}, },
'Should complete variable declaration types in a function definition #group2': function (browser: NightwatchBrowser) { 'Should complete variable declaration types in a function definition #group2': function (browser: NightwatchBrowser) {
browser browser
.perform(function () { .perform(function () {
const actions = this.actions({ async: true }); const actions = this.actions({ async: true });
return actions. return actions.
sendKeys('uint25') sendKeys('uint25')
}) })
.waitForElementPresent(autoCompleteLineElement('uint256')) .waitForElementPresent(autoCompleteLineElement('uint256'))
.click(autoCompleteLineElement('uint256')) .click(autoCompleteLineElement('uint256'))
.perform(function () { .perform(function () {
const actions = this.actions({ async: true }); const actions = this.actions({ async: true });
return actions. return actions.
sendKeys(' abc, testb') sendKeys(' abc, testb')
}) })
.waitForElementPresent(autoCompleteLineElement('"TestBookDefinition"')) .waitForElementPresent(autoCompleteLineElement('"TestBookDefinition"'))
.click(autoCompleteLineElement('"TestBookDefinition"')) .click(autoCompleteLineElement('"TestBookDefinition"'))
.perform(function () { .perform(function () {
const actions = this.actions({ async: true }); const actions = this.actions({ async: true });
return actions. return actions.
sendKeys(' memo') sendKeys(' memo')
}) })
.waitForElementPresent(autoCompleteLineElement('memory')) .waitForElementPresent(autoCompleteLineElement('memory'))
.click(autoCompleteLineElement('memory')) .click(autoCompleteLineElement('memory'))
.perform(function () { .perform(function () {
const actions = this.actions({ async: true }); const actions = this.actions({ async: true });
return actions. return actions.
sendKeys(' t, BaseB') sendKeys(' btextbook, BaseB')
}) })
.waitForElementPresent(autoCompleteLineElement('"BaseBook"')) .waitForElementPresent(autoCompleteLineElement('"BaseBook"'))
.click(autoCompleteLineElement('"BaseBook"')) .click(autoCompleteLineElement('"BaseBook"'))
.perform(function () { .perform(function () {
const actions = this.actions({ async: true }); const actions = this.actions({ async: true });
return actions. return actions.
sendKeys(' stor') sendKeys(' stor')
}) })
.waitForElementPresent(autoCompleteLineElement('storage')) .waitForElementPresent(autoCompleteLineElement('storage'))
.click(autoCompleteLineElement('storage')) .click(autoCompleteLineElement('storage'))
.perform(function () { .perform(function () {
const actions = this.actions({ async: true }); const actions = this.actions({ async: true });
return actions. return actions.
sendKeys(' b') sendKeys(' localbbook')
}) }).pause(3000)
}, },
'Should put cursor at the end of function #group2': function (browser: NightwatchBrowser) { 'Should put cursor at the end of function #group2': function (browser: NightwatchBrowser) {
const path = "//*[@class='view-line' and contains(.,'myprivatefunction') and contains(.,'private')]//span//span[contains(.,'{')]" const path = "//*[@class='view-line' and contains(.,'myprivatefunction') and contains(.,'private')]//span//span[contains(.,'{')]"
browser browser
.useXpath() .useXpath()
@ -82,7 +85,139 @@ module.exports = {
sendKeys(this.Keys.ARROW_RIGHT) sendKeys(this.Keys.ARROW_RIGHT)
}) })
}, },
'Should autcomplete address types': function (browser: NightwatchBrowser) {
browser
.perform(function () {
const actions = this.actions({ async: true });
return actions.
sendKeys('addre')
})
.waitForElementPresent(autoCompleteLineElement('address'))
.click(autoCompleteLineElement('address'))
.perform(function () {
const actions = this.actions({ async: true });
return actions.
sendKeys(' someaddress;')
.sendKeys(this.Keys.ENTER)
}).pause(2000)
.perform(function () {
const actions = this.actions({ async: true });
return actions.
sendKeys('someaddress.')
})
.waitForElementVisible(autoCompleteLineElement('balance'))
.waitForElementVisible(autoCompleteLineElement('send'))
.waitForElementVisible(autoCompleteLineElement('transfer'))
.waitForElementVisible(autoCompleteLineElement('code'))
.click(autoCompleteLineElement('balance'))
.perform(function () {
const actions = this.actions({ async: true });
return actions
.sendKeys(this.Keys.ENTER)
})
},
'Should autcomplete array types': function (browser: NightwatchBrowser) {
browser
.perform(function () {
const actions = this.actions({ async: true });
return actions.
sendKeys('uin')
})
.waitForElementPresent(autoCompleteLineElement('uint'))
.click(autoCompleteLineElement('uint'))
.perform(function () {
const actions = this.actions({ async: true });
return actions.
sendKeys('[] mem')
})
.waitForElementVisible(autoCompleteLineElement('memory'))
.click(autoCompleteLineElement('memory'))
.perform(function () {
const actions = this.actions({ async: true });
return actions.
sendKeys(' somearray;')
}
).pause(2000)
.perform(function () {
const actions = this.actions({ async: true });
return actions
.sendKeys(this.Keys.ENTER)
.sendKeys('somearray.')
})
.waitForElementVisible(autoCompleteLineElement('push'))
.waitForElementVisible(autoCompleteLineElement('pop'))
.waitForElementVisible(autoCompleteLineElement('length'))
.click(autoCompleteLineElement('length'))
.perform(function () {
const actions = this.actions({ async: true });
return actions
.sendKeys(this.Keys.ENTER)
})
},
'Should see and autocomplete second import because it was imported by the first import #group2': function (browser: NightwatchBrowser) {
browser
.perform(function () {
const actions = this.actions({ async: true });
return actions.
sendKeys('secondi')
})
.waitForElementPresent(autoCompleteLineElement('secondimport'))
.click(autoCompleteLineElement('secondimport'))
.perform(function () {
const actions = this.actions({ async: true });
return actions.
sendKeys(' sec;')
.sendKeys(this.Keys.ENTER)
}).pause(3000)
.perform(function () {
const actions = this.actions({ async: true });
return actions.
sendKeys('sec.')
})
.waitForElementVisible(autoCompleteLineElement('secondimportstring'))
.click(autoCompleteLineElement('secondimportstring'))
.perform(function () {
const actions = this.actions({ async: true });
return actions.
sendKeys(';')
.sendKeys(this.Keys.ENTER)
})
},
'Should see and autocomplete imported local class #group2': function (browser: NightwatchBrowser) {
browser
.perform(function () {
const actions = this.actions({ async: true });
return actions.
sendKeys('import')
})
.waitForElementPresent(autoCompleteLineElement('importedcontract'))
.click(autoCompleteLineElement('importedcontract'))
.perform(function () {
const actions = this.actions({ async: true });
return actions.
sendKeys('.')
})
.waitForElementVisible(autoCompleteLineElement('externalimport'))
.waitForElementVisible(autoCompleteLineElement('importbasestring'))
.waitForElementVisible(autoCompleteLineElement('importedbook'))
.waitForElementVisible(autoCompleteLineElement('importpublicstring'))
.waitForElementVisible(autoCompleteLineElement('publicimport'))
// no private
.waitForElementNotPresent(autoCompleteLineElement('importprivatestring'))
.waitForElementNotPresent(autoCompleteLineElement('privateimport'))
// no internal
.waitForElementNotPresent(autoCompleteLineElement('importinternalstring'))
.waitForElementNotPresent(autoCompleteLineElement('internalimport'))
.click(autoCompleteLineElement('importbasestring'))
.perform(function () {
const actions = this.actions({ async: true });
return actions.
sendKeys(';')
.sendKeys(this.Keys.ENTER)
})
},
'Should autocomplete derived and local event when not using this. #group2': function (browser: NightwatchBrowser) { 'Should autocomplete derived and local event when not using this. #group2': function (browser: NightwatchBrowser) {
browser.perform(function () { browser.perform(function () {
const actions = this.actions({ async: true }); const actions = this.actions({ async: true });
@ -106,15 +241,15 @@ module.exports = {
return actions. return actions.
sendKeys('emit MyEv') sendKeys('emit MyEv')
}) })
.waitForElementVisible(autoCompleteLineElement('MyEvent')) .waitForElementVisible(autoCompleteLineElement('MyEvent'))
.click(autoCompleteLineElement('MyEvent')) .click(autoCompleteLineElement('MyEvent'))
.perform(function () { .perform(function () {
const actions = this.actions({ async: true }); const actions = this.actions({ async: true });
return actions return actions
.sendKeys('3232') .sendKeys('3232')
.sendKeys(this.Keys.TAB) .sendKeys(this.Keys.TAB)
.sendKeys(this.Keys.ENTER) .sendKeys(this.Keys.ENTER)
}) })
}, },
'Should type and get msg options #group2': function (browser: NightwatchBrowser) { 'Should type and get msg options #group2': function (browser: NightwatchBrowser) {
@ -134,7 +269,17 @@ module.exports = {
.perform(function () { .perform(function () {
const actions = this.actions({ async: true }); const actions = this.actions({ async: true });
return actions. return actions.
sendKeys(';'). sendKeys('.')
})
.waitForElementVisible(autoCompleteLineElement('balance'))
.waitForElementVisible(autoCompleteLineElement('code'))
.waitForElementVisible(autoCompleteLineElement('codehash'))
.waitForElementVisible(autoCompleteLineElement('send'))
.waitForElementVisible(autoCompleteLineElement('transfer'))
.click(autoCompleteLineElement('balance'))
.perform(function () {
const actions = this.actions({ async: true });
return actions.
sendKeys(this.Keys.ENTER) sendKeys(this.Keys.ENTER)
}) })
}, },
@ -194,6 +339,62 @@ module.exports = {
.sendKeys(this.Keys.ENTER) .sendKeys(this.Keys.ENTER)
}) })
}, },
'Should block scoped localbbook #group2': function (browser: NightwatchBrowser) {
browser.pause(4000).
perform(function () {
const actions = this.actions({ async: true });
return actions.
sendKeys(this.Keys.ENTER).
sendKeys('localb')
})
.waitForElementVisible(autoCompleteLineElement('localbbook'))
.click(autoCompleteLineElement('localbbook'))
},
'Should autcomplete derived struct from block localbbook #group2': function (browser: NightwatchBrowser) {
browser.perform(function () {
const actions = this.actions({ async: true });
return actions.
sendKeys('.')
})
.waitForElementVisible(autoCompleteLineElement('author'))
.waitForElementVisible(autoCompleteLineElement('book_id'))
.waitForElementVisible(autoCompleteLineElement('title'))
.click(autoCompleteLineElement('title'))
.perform(function () {
const actions = this.actions({ async: true });
return actions.
sendKeys(';')
.sendKeys(this.Keys.ENTER)
})
},
'Should block scoped btextbook #group2': function (browser: NightwatchBrowser) {
browser.
perform(function () {
const actions = this.actions({ async: true });
return actions.
sendKeys(this.Keys.ENTER).
sendKeys('btext')
})
.waitForElementVisible(autoCompleteLineElement('btextbook'))
.click(autoCompleteLineElement('btextbook'))
},
'Should autcomplete derived struct from block btextbook #group2': function (browser: NightwatchBrowser) {
browser.perform(function () {
const actions = this.actions({ async: true });
return actions.
sendKeys('.')
})
.waitForElementVisible(autoCompleteLineElement('author'))
.waitForElementVisible(autoCompleteLineElement('book_id'))
.waitForElementVisible(autoCompleteLineElement('title'))
.click(autoCompleteLineElement('title'))
.perform(function () {
const actions = this.actions({ async: true });
return actions.
sendKeys(';')
.sendKeys(this.Keys.ENTER)
})
},
'Should find private and internal local functions #group2': function (browser: NightwatchBrowser) { 'Should find private and internal local functions #group2': function (browser: NightwatchBrowser) {
browser.perform(function () { browser.perform(function () {
const actions = this.actions({ async: true }); const actions = this.actions({ async: true });

@ -263,11 +263,22 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
} }
} }
} }
//const nodesOfScope = await this.props.plugin.call('codeParser', 'getNodesWithScope', node.id) // blocks can have statements
// nodes = [...nodes, ...nodesOfScope] /*
if (node.statements){
console.log('statements', node.statements)
for (const statement of node.statements) {
if(statement.expression){
const declaration = await this.props.plugin.call('codeParser', 'declarationOf', statement.expression)
declaration.outSideBlock = true
nodes = [...nodes, declaration]
}
}
}
*/
} }
} }
console.log('NODES AT BLOCK SCOPE', nodes)
// we are only interested in nodes that are in the same block as the cursor // we are only interested in nodes that are in the same block as the cursor
nodes = nodes.filter(node => { nodes = nodes.filter(node => {
if (node.src) { if (node.src) {
@ -276,9 +287,12 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
return true return true
} }
} }
if(node.outSideBlock){ return true }
return false return false
}) })
console.log('NODES AT BLOCK SCOPE', nodes)
return nodes; return nodes;
} }
@ -373,7 +387,7 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
for (const nodeOfScope of contractCompletions) { for (const nodeOfScope of contractCompletions) {
// console.log('nodeOfScope', nodeOfScope.name, nodeOfScope) console.log('nodeOfScope', nodeOfScope.name, nodeOfScope.memberName, nodeOfScope)
if (nodeOfScope.name === nameOfLastTypedExpression) { if (nodeOfScope.name === nameOfLastTypedExpression) {
console.log('FOUND NODE', nodeOfScope) console.log('FOUND NODE', nodeOfScope)
if (nodeOfScope.typeName && nodeOfScope.typeName.nodeType === 'UserDefinedTypeName') { if (nodeOfScope.typeName && nodeOfScope.typeName.nodeType === 'UserDefinedTypeName') {
@ -396,6 +410,7 @@ export class RemixCompletionProvider implements languages.CompletionItemProvider
suggestions = [...suggestions, ...getContextualAutoCompleteBTypeName('address', range, this.monaco)] suggestions = [...suggestions, ...getContextualAutoCompleteBTypeName('address', range, this.monaco)]
} }
} }
} }

Loading…
Cancel
Save