remix-project mirror
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
remix-project/libs/remix-ui/editor/src/lib/remix-ui-editor.tsx

656 lines
27 KiB

3 years ago
import React, { useState, useRef, useEffect, useReducer } from 'react' // eslint-disable-line
3 years ago
3 years ago
import Editor, { loader, Monaco } from '@monaco-editor/react'
3 years ago
import { reducerActions, reducerListener, initialState } from './actions/editor'
import { solidityTokensProvider, solidityLanguageConfig } from './syntaxes/solidity'
import { cairoTokensProvider, cairoLanguageConfig } from './syntaxes/cairo'
import { zokratesTokensProvider, zokratesLanguageConfig } from './syntaxes/zokrates'
3 years ago
import './remix-ui-editor.css'
import { loadTypes } from './web-types'
3 years ago
import monaco from '../types/monaco'
import { IMarkdownString, IPosition, MarkerSeverity } from 'monaco-editor'
3 years ago
3 years ago
import { RemixHoverProvider } from './providers/hoverProvider'
3 years ago
import { RemixReferenceProvider } from './providers/referenceProvider'
3 years ago
import { RemixCompletionProvider } from './providers/completionProvider'
import { RemixHighLightProvider } from './providers/highlightProvider'
import { RemixDefinitionProvider } from './providers/definitionProvider'
3 years ago
type sourceAnnotation = {
row: number,
column: number,
text: string,
type: 'error' | 'warning' | 'info'
hide: boolean
from: string // plugin name
}
type sourceMarker = {
position: {
start: {
line: number
column: number
},
end: {
line: number
column: number
}
},
from: string // plugin name
hide: boolean
}
export type lineText = {
position: {
start: {
line: number
column: number
},
end: {
line: number
column: number
}
},
3 years ago
from?: string // plugin name
content: string
className: string
afterContentClassName: string
hide: boolean,
hoverMessage: IMarkdownString | IMarkdownString[]
}
3 years ago
type errorMarker = {
message: string
severity: MarkerSeverity | 'warning' | 'info' | 'error' | 'hint'
3 years ago
position: {
start: {
line: number
column: number
},
end: {
line: number
column: number
}
},
file: string
}
3 years ago
3 years ago
loader.config({ paths: { vs: 'assets/js/monaco-editor/dev/vs' } })
3 years ago
export type DecorationsReturn = {
currentDecorations: Array<string>
registeredDecorations?: Array<any>
}
/* eslint-disable-next-line */
3 years ago
export interface EditorUIProps {
contextualListener: any
3 years ago
activated: boolean
themeType: string
3 years ago
currentFile: string
3 years ago
events: {
onBreakPointAdded: (file: string, line: number) => void
onBreakPointCleared: (file: string, line: number) => void
onDidChangeContent: (file: string) => void
onEditorMounted: () => void
}
plugin: {
on: (plugin: string, event: string, listener: any) => void
call: (plugin: string, method: string, arg1?: any, arg2?: any, arg3?: any, arg4?: any) => any
3 years ago
}
editorAPI: {
3 years ago
findMatches: (uri: string, value: string) => any
getFontSize: () => number,
getValue: (uri: string) => string
3 years ago
getCursorPosition: () => number
3 years ago
getHoverPosition: (position: IPosition) => number
3 years ago
addDecoration: (marker: sourceMarker, filePath: string, typeOfDecoration: string) => DecorationsReturn
clearDecorationsByPlugin: (filePath: string, plugin: string, typeOfDecoration: string, registeredDecorations: any, currentDecorations: any) => DecorationsReturn
keepDecorationsFor: (filePath: string, plugin: string, typeOfDecoration: string, registeredDecorations: any, currentDecorations: any) => DecorationsReturn
addErrorMarker: (errors: errorMarker[], from: string) => void
clearErrorMarkers: (sources: string[] | {[fileName: string]: any}, from: string) => void
3 years ago
}
}
export const EditorUI = (props: EditorUIProps) => {
const [, setCurrentBreakpoints] = useState({})
const defaultEditorValue = `
3 years ago
\t\t\t\t\t\t\t ____ _____ __ __ ___ __ __ ___ ____ _____
\t\t\t\t\t\t\t| _ \\ | ____| | \\/ | |_ _| \\ \\/ / |_ _| | _ \\ | ____|
\t\t\t\t\t\t\t| |_) | | _| | |\\/| | | | \\ / | | | | | | | _|
\t\t\t\t\t\t\t| _ < | |___ | | | | | | / \\ | | | |_| | | |___
\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
2 years ago
\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
3 years ago
\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
3 years ago
\t\t\t\t\t\t\t\tOfficial documentation: https://remix-ide.readthedocs.io/en/latest/\n
3 years ago
\t\t\t\t\t\t\t\tGithub: https://github.com/ethereum/remix-project\n
\t\t\t\t\t\t\t\tGitter: https://gitter.im/ethereum/remix\n
3 years ago
\t\t\t\t\t\t\t\tMedium: https://medium.com/remix-ide\n
\t\t\t\t\t\t\t\tTwitter: https://twitter.com/ethereumremix\n
`
3 years ago
const editorRef = useRef(null)
3 years ago
const monacoRef = useRef<Monaco>(null)
3 years ago
const currentFileRef = useRef('')
3 years ago
// const currentDecorations = useRef({ sourceAnnotationsPerFile: {}, markerPerFile: {} }) // decorations that are currently in use by the editor
// const registeredDecorations = useRef({}) // registered decorations
3 years ago
3 years ago
const [editorModelsState, dispatch] = useReducer(reducerActions, initialState)
const formatColor = (name) => {
let color = window.getComputedStyle(document.documentElement).getPropertyValue(name).trim()
if (color.length === 4) {
color = color.concat(color.substr(1))
}
return color
}
const defineAndSetTheme = (monaco) => {
const themeType = props.themeType === 'dark' ? 'vs-dark' : 'vs'
const themeName = props.themeType === 'dark' ? 'remix-dark' : 'remix-light'
// see https://microsoft.github.io/monaco-editor/playground.html#customizing-the-appearence-exposed-colors
const lightColor = formatColor('--light')
const infoColor = formatColor('--info')
const darkColor = formatColor('--dark')
const secondaryColor = formatColor('--secondary')
const primaryColor = formatColor('--primary')
const textColor = formatColor('--text') || darkColor
const textbackground = formatColor('--text-background') || lightColor
const blueColor = formatColor('--blue')
const successColor = formatColor('--success')
const warningColor = formatColor('--warning')
const yellowColor = formatColor('--yellow')
const pinkColor = formatColor('--pink')
const locationColor = '#9e7e08'
3 years ago
// const purpleColor = formatColor('--purple')
const dangerColor = formatColor('--danger')
const greenColor = formatColor('--green')
const orangeColor = formatColor('--orange')
const grayColor = formatColor('--gray')
monaco.editor.defineTheme(themeName, {
base: themeType,
inherit: true, // can also be false to completely replace the builtin rules
rules: [
{ background: darkColor.replace('#', '') },
{ foreground: textColor.replace('#', '') },
// global variables
{ token: 'keyword.abi', foreground: blueColor },
{ token: 'keyword.block', foreground: blueColor },
{ token: 'keyword.bytes', foreground: blueColor },
{ token: 'keyword.msg', foreground: blueColor },
{ token: 'keyword.tx', foreground: blueColor },
// global functions
{ token: 'keyword.assert', foreground: blueColor },
{ token: 'keyword.require', foreground: blueColor },
{ token: 'keyword.revert', foreground: blueColor },
{ token: 'keyword.blockhash', foreground: blueColor },
{ token: 'keyword.keccak256', foreground: blueColor },
{ token: 'keyword.sha256', foreground: blueColor },
{ token: 'keyword.ripemd160', foreground: blueColor },
{ token: 'keyword.ecrecover', foreground: blueColor },
{ token: 'keyword.addmod', foreground: blueColor },
{ token: 'keyword.mulmod', foreground: blueColor },
{ token: 'keyword.selfdestruct', foreground: blueColor },
{ token: 'keyword.type ', foreground: blueColor },
{ token: 'keyword.gasleft', foreground: blueColor },
// specials
{ token: 'keyword.super', foreground: infoColor },
{ token: 'keyword.this', foreground: infoColor },
{ token: 'keyword.virtual', foreground: infoColor },
// for state variables
{ token: 'keyword.constants', foreground: grayColor },
{ token: 'keyword.override', foreground: grayColor },
{ token: 'keyword.immutable', foreground: grayColor },
// data location
{ token: 'keyword.memory', foreground: locationColor },
{ token: 'keyword.storage', foreground: locationColor },
{ token: 'keyword.calldata', foreground: locationColor },
// for Events
{ token: 'keyword.indexed', foreground: yellowColor },
{ token: 'keyword.anonymous', foreground: yellowColor },
// for functions
{ token: 'keyword.external', foreground: successColor },
{ token: 'keyword.internal', foreground: successColor },
{ token: 'keyword.private', foreground: successColor },
{ token: 'keyword.public', foreground: successColor },
{ token: 'keyword.view', foreground: successColor },
{ token: 'keyword.pure', foreground: successColor },
{ token: 'keyword.payable', foreground: successColor },
{ token: 'keyword.nonpayable', foreground: successColor },
// Errors
{ token: 'keyword.Error', foreground: dangerColor },
{ token: 'keyword.Panic', foreground: dangerColor },
// special functions
{ token: 'keyword.fallback', foreground: pinkColor },
{ token: 'keyword.receive', foreground: pinkColor },
{ token: 'keyword.constructor', foreground: pinkColor },
// identifiers
{ token: 'keyword.identifier', foreground: warningColor },
{ token: 'keyword.for', foreground: warningColor },
{ token: 'keyword.break', foreground: warningColor },
{ token: 'keyword.continue', foreground: warningColor },
{ token: 'keyword.while', foreground: warningColor },
{ token: 'keyword.do', foreground: warningColor },
{ token: 'keyword.if', foreground: yellowColor },
{ token: 'keyword.else', foreground: yellowColor },
{ token: 'keyword.throw', foreground: orangeColor },
{ token: 'keyword.catch', foreground: orangeColor },
{ token: 'keyword.try', foreground: orangeColor },
// returns
{ token: 'keyword.returns', foreground: greenColor },
{ token: 'keyword.return', foreground: greenColor }
],
colors: {
// see https://code.visualstudio.com/api/references/theme-color for more settings
'editor.background': textbackground,
'editorSuggestWidget.background': lightColor,
'editorSuggestWidget.selectedBackground': secondaryColor,
'editorSuggestWidget.selectedForeground': textColor,
'editorSuggestWidget.highlightForeground': primaryColor,
'editorSuggestWidget.focusHighlightForeground': infoColor,
'editor.lineHighlightBorder': secondaryColor,
'editor.lineHighlightBackground': textbackground === darkColor ? lightColor : secondaryColor,
'editorGutter.background': lightColor,
//'editor.selectionHighlightBackground': secondaryColor,
'minimap.background': lightColor,
'menu.foreground': textColor,
'menu.background': textbackground,
'menu.selectionBackground': secondaryColor,
'menu.selectionForeground': textColor,
'menu.selectionBorder': secondaryColor
}
})
monacoRef.current.editor.setTheme(themeName)
}
3 years ago
useEffect(() => {
if (!monacoRef.current) return
defineAndSetTheme(monacoRef.current)
})
3 years ago
useEffect(() => {
3 years ago
if (!editorRef.current || !props.currentFile) return
3 years ago
currentFileRef.current = props.currentFile
const file = editorModelsState[props.currentFile]
editorRef.current.setModel(file.model)
3 years ago
editorRef.current.updateOptions({ readOnly: editorModelsState[props.currentFile].readOnly })
if (file.language === 'sol') {
monacoRef.current.editor.setModelLanguage(file.model, 'remix-solidity')
} else if (file.language === 'cairo') {
monacoRef.current.editor.setModelLanguage(file.model, 'remix-cairo')
} else if (file.language === 'zokrates') {
monacoRef.current.editor.setModelLanguage(file.model, 'remix-zokrates')
3 years ago
}
3 years ago
}, [props.currentFile])
3 years ago
const convertToMonacoDecoration = (decoration: lineText | sourceAnnotation | sourceMarker, typeOfDecoration: string) => {
if (typeOfDecoration === 'sourceAnnotationsPerFile') {
decoration = decoration as sourceAnnotation
return {
type: typeOfDecoration,
range: new monacoRef.current.Range(decoration.row + 1, 1, decoration.row + 1, 1),
options: {
isWholeLine: false,
glyphMarginHoverMessage: { value: (decoration.from ? `from ${decoration.from}:\n` : '') + decoration.text },
glyphMarginClassName: `fal fa-exclamation-square text-${decoration.type === 'error' ? 'danger' : (decoration.type === 'warning' ? 'warning' : 'info')}`
}
}
}
if (typeOfDecoration === 'markerPerFile') {
decoration = decoration as sourceMarker
let isWholeLine = false
if ((decoration.position.start.line === decoration.position.end.line && decoration.position.end.column - decoration.position.start.column < 2) ||
(decoration.position.start.line !== decoration.position.end.line)) {
// in this case we force highlighting the whole line (doesn't make sense to highlight 2 chars)
isWholeLine = true
}
return {
type: typeOfDecoration,
range: new monacoRef.current.Range(decoration.position.start.line + 1, decoration.position.start.column + 1, decoration.position.end.line + 1, decoration.position.end.column + 1),
options: {
isWholeLine,
inlineClassName: `${isWholeLine ? 'alert-info' : 'inline-class'} border-0 highlightLine${decoration.position.start.line + 1}`
}
}
}
if (typeOfDecoration === 'lineTextPerFile') {
3 years ago
const lineTextDecoration = decoration as lineText
return {
type: typeOfDecoration,
range: new monacoRef.current.Range(lineTextDecoration.position.start.line + 1, lineTextDecoration.position.start.column + 1, lineTextDecoration.position.start.line + 1, 1024),
options: {
after: { content: ` ${lineTextDecoration.content}`, inlineClassName: `${lineTextDecoration.className}` },
afterContentClassName: `${lineTextDecoration.afterContentClassName}`,
hoverMessage : lineTextDecoration.hoverMessage
},
}
}
if (typeOfDecoration === 'lineTextPerFile') {
const lineTextDecoration = decoration as lineText
return {
type: typeOfDecoration,
range: new monacoRef.current.Range(lineTextDecoration.position.start.line + 1, lineTextDecoration.position.start.column + 1, lineTextDecoration.position.start.line + 1, 1024),
options: {
after: { content: ` ${lineTextDecoration.content}`, inlineClassName: `${lineTextDecoration.className}` },
afterContentClassName: `${lineTextDecoration.afterContentClassName}`,
hoverMessage : lineTextDecoration.hoverMessage
},
}
}
}
3 years ago
props.editorAPI.clearDecorationsByPlugin = (filePath: string, plugin: string, typeOfDecoration: string, registeredDecorations: any, currentDecorations: any) => {
const model = editorModelsState[filePath]?.model
if (!model) return {
currentDecorations: [],
registeredDecorations: []
}
const decorations = []
const newRegisteredDecorations = []
3 years ago
if (registeredDecorations) {
for (const decoration of registeredDecorations) {
if (decoration.type === typeOfDecoration && decoration.value.from !== plugin) {
decorations.push(convertToMonacoDecoration(decoration.value, typeOfDecoration))
newRegisteredDecorations.push(decoration)
}
}
}
3 years ago
return {
currentDecorations: model.deltaDecorations(currentDecorations, decorations),
registeredDecorations: newRegisteredDecorations
}
}
3 years ago
3 years ago
props.editorAPI.keepDecorationsFor = (filePath: string, plugin: string, typeOfDecoration: string, registeredDecorations: any, currentDecorations: any) => {
const model = editorModelsState[filePath]?.model
if (!model) return {
currentDecorations: []
}
const decorations = []
3 years ago
if (registeredDecorations) {
for (const decoration of registeredDecorations) {
if (decoration.value.from === plugin) {
decorations.push(convertToMonacoDecoration(decoration.value, typeOfDecoration))
}
}
}
3 years ago
return {
currentDecorations: model.deltaDecorations(currentDecorations, decorations)
}
}
const addDecoration = (decoration: sourceAnnotation | sourceMarker, filePath: string, typeOfDecoration: string) => {
const model = editorModelsState[filePath]?.model
3 years ago
if (!model) return { currentDecorations: [] }
const monacoDecoration = convertToMonacoDecoration(decoration, typeOfDecoration)
3 years ago
return {
currentDecorations: model.deltaDecorations([], [monacoDecoration]),
registeredDecorations: [{ value: decoration, type: typeOfDecoration }]
}
}
3 years ago
3 years ago
props.editorAPI.addDecoration = (marker: sourceMarker, filePath: string, typeOfDecoration: string) => {
return addDecoration(marker, filePath, typeOfDecoration)
}
props.editorAPI.addErrorMarker = async (errors: errorMarker[], from: string) => {
3 years ago
3 years ago
const allMarkersPerfile: Record<string, Array<monaco.editor.IMarkerData>> = {}
3 years ago
3 years ago
for (const error of errors) {
3 years ago
let filePath = error.file
3 years ago
if (!filePath) return
const fileFromUrl = await props.plugin.call('fileManager', 'getPathFromUrl', filePath)
filePath = fileFromUrl.file
const model = editorModelsState[filePath]?.model
const errorServerityMap = {
'error': MarkerSeverity.Error,
'warning': MarkerSeverity.Warning,
'info': MarkerSeverity.Info
}
3 years ago
if (model) {
const markerData: monaco.editor.IMarkerData = {
severity: (typeof error.severity === 'string') ? errorServerityMap[error.severity] : error.severity,
3 years ago
startLineNumber: ((error.position.start && error.position.start.line) || 0),
startColumn: ((error.position.start && error.position.start.column) || 0),
endLineNumber: ((error.position.end && error.position.end.line) || 0),
endColumn: ((error.position.end && error.position.end.column) || 0),
message: error.message,
3 years ago
}
3 years ago
if (!allMarkersPerfile[filePath]) {
allMarkersPerfile[filePath] = []
}
allMarkersPerfile[filePath].push(markerData)
}
}
for (const filePath in allMarkersPerfile) {
const model = editorModelsState[filePath]?.model
if (model) {
monacoRef.current.editor.setModelMarkers(model, from, allMarkersPerfile[filePath])
3 years ago
}
}
}
props.editorAPI.clearErrorMarkers = async (sources: string[] | {[fileName: string]: any}, from: string) => {
3 years ago
if (sources) {
for (const source of (Array.isArray(sources) ? sources : Object.keys(sources))) {
const filePath = source
const model = editorModelsState[filePath]?.model
if (model) {
monacoRef.current.editor.setModelMarkers(model, from, [])
3 years ago
}
3 years ago
}
}
}
3 years ago
props.editorAPI.findMatches = (uri: string, value: string) => {
if (!editorRef.current) return
3 years ago
const model = editorModelsState[uri]?.model
3 years ago
if (model) return model.findMatches(value)
}
props.editorAPI.getValue = (uri: string) => {
if (!editorRef.current) return
3 years ago
const model = editorModelsState[uri]?.model
3 years ago
if (model) {
return model.getValue()
}
}
props.editorAPI.getCursorPosition = () => {
if (!monacoRef.current) return
3 years ago
const model = editorModelsState[currentFileRef.current]?.model
3 years ago
if (model) {
return model.getOffsetAt(editorRef.current.getPosition())
}
}
3 years ago
props.editorAPI.getHoverPosition = (position: monaco.Position) => {
if (!monacoRef.current) return
const model = editorModelsState[currentFileRef.current]?.model
if (model) {
return model.getOffsetAt(position)
3 years ago
} else {
3 years ago
return 0
}
}
3 years ago
props.editorAPI.getFontSize = () => {
if (!editorRef.current) return
return editorRef.current.getOption(43).fontSize
3 years ago
}
(window as any).addRemixBreakpoint = (position) => { // make it available from e2e testing...
const model = editorRef.current.getModel()
if (model) {
setCurrentBreakpoints(prevState => {
const currentFile = currentFileRef.current
if (!prevState[currentFile]) prevState[currentFile] = {}
const decoration = Object.keys(prevState[currentFile]).filter((line) => parseInt(line) === position.lineNumber)
if (decoration.length) {
3 years ago
props.events.onBreakPointCleared(currentFile, position.lineNumber)
3 years ago
model.deltaDecorations([prevState[currentFile][position.lineNumber]], [])
delete prevState[currentFile][position.lineNumber]
} else {
3 years ago
props.events.onBreakPointAdded(currentFile, position.lineNumber)
3 years ago
const decorationIds = model.deltaDecorations([], [{
range: new monacoRef.current.Range(position.lineNumber, 1, position.lineNumber, 1),
options: {
isWholeLine: false,
glyphMarginClassName: 'fas fa-circle text-info'
}
}])
prevState[currentFile][position.lineNumber] = decorationIds[0]
}
return prevState
})
}
}
3 years ago
function handleEditorDidMount(editor) {
3 years ago
editorRef.current = editor
defineAndSetTheme(monacoRef.current)
reducerListener(props.plugin, dispatch, monacoRef.current, editorRef.current, props.events)
3 years ago
props.events.onEditorMounted()
3 years ago
editor.onMouseUp((e) => {
if (e && e.target && e.target.toString().startsWith('GUTTER')) {
(window as any).addRemixBreakpoint(e.target.position)
}
})
// zoomin zoomout
3 years ago
editor.addCommand(monacoRef.current.KeyMod.CtrlCmd | (monacoRef.current.KeyCode as any).US_EQUAL, () => {
editor.updateOptions({ fontSize: editor.getOption(43).fontSize + 1 })
})
3 years ago
editor.addCommand(monacoRef.current.KeyMod.CtrlCmd | (monacoRef.current.KeyCode as any).US_MINUS, () => {
editor.updateOptions({ fontSize: editor.getOption(43).fontSize - 1 })
})
3 years ago
// add context menu items
const zoominAction = {
id: "zoomIn",
label: "Zoom In",
contextMenuOrder: 0, // choose the order
contextMenuGroupId: "zooming", // create a new grouping
keybindings: [
// eslint-disable-next-line no-bitwise
monacoRef.current.KeyMod.CtrlCmd | monacoRef.current.KeyCode.Equal,
],
run: () => { editor.updateOptions({ fontSize: editor.getOption(43).fontSize + 1 }) },
}
const zoomOutAction = {
id: "zoomOut",
label: "Zoom Out",
contextMenuOrder: 0, // choose the order
contextMenuGroupId: "zooming", // create a new grouping
keybindings: [
// eslint-disable-next-line no-bitwise
monacoRef.current.KeyMod.CtrlCmd | monacoRef.current.KeyCode.Minus,
],
run: () => { editor.updateOptions({ fontSize: editor.getOption(43).fontSize - 1 }) },
}
2 years ago
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 () => {
2 years ago
const file = await props.plugin.call('fileManager', 'getCurrentFile')
await props.plugin.call('codeFormatter', 'format', file)
2 years ago
},
}
editor.addAction(formatAction)
editor.addAction(zoomOutAction)
editor.addAction(zoominAction)
const editorService = editor._codeEditorService;
const openEditorBase = editorService.openCodeEditor.bind(editorService);
editorService.openCodeEditor = async (input , source) => {
3 years ago
const result = await openEditorBase(input, source)
if (input && input.resource && input.resource.path) {
try {
await props.plugin.call('fileManager', 'open', input.resource.path)
if (input.options && input.options.selection) {
editor.revealRange(input.options.selection)
editor.setPosition({ column: input.options.selection.startColumn, lineNumber: input.options.selection.startLineNumber })
}
3 years ago
} catch (e) {
console.log(e)
}
3 years ago
}
return result
}
2 years ago
console.log('editor mounted')
3 years ago
}
3 years ago
function handleEditorWillMount(monaco) {
3 years ago
monacoRef.current = monaco
// Register a new language
3 years ago
monacoRef.current.languages.register({ id: 'remix-solidity' })
monacoRef.current.languages.register({ id: 'remix-cairo' })
monacoRef.current.languages.register({ id: 'remix-zokrates' })
3 years ago
// Register a tokens provider for the language
monacoRef.current.languages.setMonarchTokensProvider('remix-solidity', solidityTokensProvider as any)
monacoRef.current.languages.setLanguageConfiguration('remix-solidity', solidityLanguageConfig as any )
3 years ago
monacoRef.current.languages.setMonarchTokensProvider('remix-cairo', cairoTokensProvider as any)
monacoRef.current.languages.setLanguageConfiguration('remix-cairo', cairoLanguageConfig as any)
3 years ago
3 years ago
monacoRef.current.languages.setMonarchTokensProvider('remix-zokrates', zokratesTokensProvider as any)
monacoRef.current.languages.setLanguageConfiguration('remix-zokrates', zokratesLanguageConfig as any)
monacoRef.current.languages.registerDefinitionProvider('remix-solidity', new RemixDefinitionProvider(props, monaco))
monacoRef.current.languages.registerDocumentHighlightProvider('remix-solidity', new RemixHighLightProvider(props, monaco))
3 years ago
monacoRef.current.languages.registerReferenceProvider('remix-solidity', new RemixReferenceProvider(props, monaco))
3 years ago
monacoRef.current.languages.registerHoverProvider('remix-solidity', new RemixHoverProvider(props, monaco))
3 years ago
monacoRef.current.languages.registerCompletionItemProvider('remix-solidity', new RemixCompletionProvider(props, monaco))
3 years ago
loadTypes(monacoRef.current)
3 years ago
}
return (
<div className="w-100 h-100 d-flex flex-column-reverse">
3 years ago
<Editor
width="100%"
path={props.currentFile}
language={editorModelsState[props.currentFile] ? editorModelsState[props.currentFile].language : 'text'}
onMount={handleEditorDidMount}
beforeMount={handleEditorWillMount}
3 years ago
options={{ glyphMargin: true, readOnly: (!editorRef.current || !props.currentFile) }}
defaultValue={defaultEditorValue}
3 years ago
/>
3 years ago
</div>
3 years ago
)
}
3 years ago
export default EditorUI