Commit 80d5aff7 authored by tom's avatar tom

highlight code of the main contract

Fixes #1676
parent a5a42116
...@@ -163,6 +163,7 @@ const ContractSourceCode = ({ address, implementationAddress }: Props) => { ...@@ -163,6 +163,7 @@ const ContractSourceCode = ({ address, implementationAddress }: Props) => {
libraries={ primaryContractQuery.data?.external_libraries ?? undefined } libraries={ primaryContractQuery.data?.external_libraries ?? undefined }
language={ primaryContractQuery.data?.language ?? undefined } language={ primaryContractQuery.data?.language ?? undefined }
mainFile={ primaryEditorData[0]?.file_path } mainFile={ primaryEditorData[0]?.file_path }
contractName={ primaryContractQuery.data?.name || undefined }
/> />
</Box> </Box>
{ secondaryEditorData && ( { secondaryEditorData && (
...@@ -173,6 +174,7 @@ const ContractSourceCode = ({ address, implementationAddress }: Props) => { ...@@ -173,6 +174,7 @@ const ContractSourceCode = ({ address, implementationAddress }: Props) => {
libraries={ secondaryContractQuery.data?.external_libraries ?? undefined } libraries={ secondaryContractQuery.data?.external_libraries ?? undefined }
language={ secondaryContractQuery.data?.language ?? undefined } language={ secondaryContractQuery.data?.language ?? undefined }
mainFile={ secondaryEditorData?.[0]?.file_path } mainFile={ secondaryEditorData?.[0]?.file_path }
contractName={ secondaryContractQuery.data?.name || undefined }
/> />
</Box> </Box>
) } ) }
......
...@@ -19,6 +19,7 @@ import CodeEditorSideBar, { CONTAINER_WIDTH as SIDE_BAR_WIDTH } from './CodeEdit ...@@ -19,6 +19,7 @@ import CodeEditorSideBar, { CONTAINER_WIDTH as SIDE_BAR_WIDTH } from './CodeEdit
import CodeEditorTabs from './CodeEditorTabs'; import CodeEditorTabs from './CodeEditorTabs';
import addExternalLibraryWarningDecoration from './utils/addExternalLibraryWarningDecoration'; import addExternalLibraryWarningDecoration from './utils/addExternalLibraryWarningDecoration';
import addFileImportDecorations from './utils/addFileImportDecorations'; import addFileImportDecorations from './utils/addFileImportDecorations';
import addMainContractCodeDecoration from './utils/addMainContractCodeDecoration';
import getFullPathOfImportedFile from './utils/getFullPathOfImportedFile'; import getFullPathOfImportedFile from './utils/getFullPathOfImportedFile';
import * as themes from './utils/themes'; import * as themes from './utils/themes';
import useThemeColors from './utils/useThemeColors'; import useThemeColors from './utils/useThemeColors';
...@@ -42,9 +43,10 @@ interface Props { ...@@ -42,9 +43,10 @@ interface Props {
libraries?: Array<SmartContractExternalLibrary>; libraries?: Array<SmartContractExternalLibrary>;
language?: string; language?: string;
mainFile?: string; mainFile?: string;
contractName?: string;
} }
const CodeEditor = ({ data, remappings, libraries, language, mainFile }: Props) => { const CodeEditor = ({ data, remappings, libraries, language, mainFile, contractName }: Props) => {
const [ instance, setInstance ] = React.useState<Monaco | undefined>(); const [ instance, setInstance ] = React.useState<Monaco | undefined>();
const [ editor, setEditor ] = React.useState<monaco.editor.IStandaloneCodeEditor | undefined>(); const [ editor, setEditor ] = React.useState<monaco.editor.IStandaloneCodeEditor | undefined>();
const [ index, setIndex ] = React.useState(0); const [ index, setIndex ] = React.useState(0);
...@@ -82,9 +84,10 @@ const CodeEditor = ({ data, remappings, libraries, language, mainFile }: Props) ...@@ -82,9 +84,10 @@ const CodeEditor = ({ data, remappings, libraries, language, mainFile }: Props)
if (language === 'solidity') { if (language === 'solidity') {
loadedModels.concat(newModels) loadedModels.concat(newModels)
.forEach((models) => { .forEach((model) => {
addFileImportDecorations(models); contractName && mainFile === model.uri.path && addMainContractCodeDecoration(model, contractName, editor);
libraries?.length && addExternalLibraryWarningDecoration(models, libraries); addFileImportDecorations(model);
libraries?.length && addExternalLibraryWarningDecoration(model, libraries);
}); });
} }
...@@ -192,6 +195,13 @@ const CodeEditor = ({ data, remappings, libraries, language, mainFile }: Props) ...@@ -192,6 +195,13 @@ const CodeEditor = ({ data, remappings, libraries, language, mainFile }: Props)
'.monaco-editor .overflow-guard': { '.monaco-editor .overflow-guard': {
'border-bottom-left-radius': borderRadius, 'border-bottom-left-radius': borderRadius,
}, },
'.monaco-editor .core-guide': {
zIndex: 1,
},
// '.monaco-editor .currentFindMatch': // TODO: find a better way to style this
'.monaco-editor .findMatch': {
backgroundColor: themeColors['custom.findMatchHighlightBackground'],
},
'.highlight': { '.highlight': {
backgroundColor: themeColors['custom.findMatchHighlightBackground'], backgroundColor: themeColors['custom.findMatchHighlightBackground'],
}, },
...@@ -206,6 +216,18 @@ const CodeEditor = ({ data, remappings, libraries, language, mainFile }: Props) ...@@ -206,6 +216,18 @@ const CodeEditor = ({ data, remappings, libraries, language, mainFile }: Props)
'.risk-warning': { '.risk-warning': {
backgroundColor: themeColors['custom.riskWarning.background'], backgroundColor: themeColors['custom.riskWarning.background'],
}, },
'.main-contract-header': {
backgroundColor: themeColors['custom.mainContract.header'],
},
'.main-contract-body': {
backgroundColor: themeColors['custom.mainContract.body'],
},
'.main-contract-glyph': {
zIndex: 1,
background: 'url(/static/contract_star.png) no-repeat center center',
backgroundSize: '12px',
cursor: 'pointer',
},
}), [ editorWidth, themeColors, borderRadius ]); }), [ editorWidth, themeColors, borderRadius ]);
const renderErrorScreen = React.useCallback(() => { const renderErrorScreen = React.useCallback(() => {
......
...@@ -2,6 +2,8 @@ import type * as monaco from 'monaco-editor/esm/vs/editor/editor.api'; ...@@ -2,6 +2,8 @@ import type * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
import type { SmartContractExternalLibrary } from 'types/api/contract'; import type { SmartContractExternalLibrary } from 'types/api/contract';
import sortByEndLineNumberAsc from './sortByEndLineNumberAsc';
export default function addExternalLibraryWarningDecoration(model: monaco.editor.ITextModel, libraries: Array<SmartContractExternalLibrary>) { export default function addExternalLibraryWarningDecoration(model: monaco.editor.ITextModel, libraries: Array<SmartContractExternalLibrary>) {
const options: monaco.editor.IModelDecorationOptions = { const options: monaco.editor.IModelDecorationOptions = {
isWholeLine: true, isWholeLine: true,
...@@ -81,15 +83,3 @@ const getLibraryName = (model: monaco.editor.ITextModel) => (library: SmartContr ...@@ -81,15 +83,3 @@ const getLibraryName = (model: monaco.editor.ITextModel) => (library: SmartContr
return libraryName; return libraryName;
}; };
const sortByEndLineNumberAsc = (a: monaco.editor.FindMatch, b: monaco.editor.FindMatch) => {
if (a.range.endLineNumber < b.range.endLineNumber) {
return -1;
}
if (a.range.endLineNumber > b.range.endLineNumber) {
return 1;
}
return 0;
};
import type * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
import sortByEndLineNumberAsc from './sortByEndLineNumberAsc';
export default function addMainContractCodeDecoration(model: monaco.editor.ITextModel, contractName: string, editor: monaco.editor.IStandaloneCodeEditor) {
const options: monaco.editor.IModelDecorationOptions = {
isWholeLine: true,
};
const contractBlockMatches = model.findMatches(`^contract\\s`, false, true, false, null, true);
if (contractBlockMatches.length < 2) {
return;
}
const [ firstLineMatch ] = model.findMatches(`(^contract ${ contractName })( is .+)?\\s?\\{`, false, true, false, null, true);
if (!firstLineMatch) {
return;
}
const firstLineDecoration: monaco.editor.IModelDeltaDecoration = {
range: {
startColumn: 1,
endColumn: 10, // doesn't really matter since isWholeLine is true
startLineNumber: firstLineMatch.range.startLineNumber,
endLineNumber: firstLineMatch.range.startLineNumber,
},
options: {
...options,
className: '.main-contract-header',
marginClassName: '.main-contract-header',
glyphMarginClassName: '.main-contract-glyph',
glyphMarginHoverMessage: [
{ value: 'Main contract' },
],
},
};
const lastLineRange: monaco.IRange = {
startLineNumber: firstLineMatch.range.startLineNumber,
startColumn: 1,
endColumn: 10,
endLineNumber: model.getLineCount(),
};
const [ lastLineMatch ] = model
.findMatches(`^\\}`, lastLineRange, true, false, null, true)
.sort(sortByEndLineNumberAsc);
const restDecoration: monaco.editor.IModelDeltaDecoration = {
range: {
startLineNumber: firstLineMatch.range.startLineNumber + 1,
endLineNumber: lastLineMatch.range.startLineNumber,
startColumn: 1,
endColumn: 10, // doesn't really matter since isWholeLine is true
},
options: {
...options,
className: '.main-contract-body',
marginClassName: '.main-contract-body',
},
};
editor.updateOptions({ glyphMargin: true });
model.deltaDecorations([], [ firstLineDecoration, restDecoration ]);
}
import type * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
export default function sortByEndLineNumberAsc(a: monaco.editor.FindMatch, b: monaco.editor.FindMatch) {
if (a.range.endLineNumber < b.range.endLineNumber) {
return -1;
}
if (a.range.endLineNumber > b.range.endLineNumber) {
return 1;
}
return 0;
}
...@@ -37,6 +37,8 @@ export const light = { ...@@ -37,6 +37,8 @@ export const light = {
'custom.fileLink.hoverForeground': '#4299E1', // blue.400 'custom.fileLink.hoverForeground': '#4299E1', // blue.400
'custom.riskWarning.primaryBackground': '#FEEBCB', // orange.100 'custom.riskWarning.primaryBackground': '#FEEBCB', // orange.100
'custom.riskWarning.background': '#FFFAF0', // orange.50 'custom.riskWarning.background': '#FFFAF0', // orange.50
'custom.mainContract.header': 'rgba(233, 216, 253, 1)', // purple.100
'custom.mainContract.body': 'rgba(250, 245, 255, 1)', // purple.50
} as const, } as const,
}; };
...@@ -79,5 +81,7 @@ export const dark = { ...@@ -79,5 +81,7 @@ export const dark = {
'custom.fileLink.hoverForeground': '#4299E1', // blue.400 'custom.fileLink.hoverForeground': '#4299E1', // blue.400
'custom.riskWarning.primaryBackground': 'rgba(246, 173, 85, 0.3)', // orange.300 'custom.riskWarning.primaryBackground': 'rgba(246, 173, 85, 0.3)', // orange.300
'custom.riskWarning.background': 'rgba(246, 173, 85, 0.1)', // orange.300 'custom.riskWarning.background': 'rgba(246, 173, 85, 0.1)', // orange.300
'custom.mainContract.header': 'rgba(183, 148, 244, 0.3)', // purple.300
'custom.mainContract.body': 'rgba(214, 188, 250, 0.1)', // purple.200
} as const, } as const,
}; };
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment