Commit 69ee2021 authored by gxkai's avatar gxkai

chore: ace

parent 549a4cc4
const nxWebpack = require('@nrwl/react/plugins/webpack') const nxWebpack = require('@nrwl/react/plugins/webpack')
const TerserPlugin = require('terser-webpack-plugin') const TerserPlugin = require('terser-webpack-plugin')
// const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
module.exports = config => { module.exports = config => {
const nxWebpackConfig = nxWebpack(config) const nxWebpackConfig = nxWebpack(config)
// nxWebpackConfig.plugins.push(new MonacoWebpackPlugin())
const webpackConfig = { const webpackConfig = {
...nxWebpackConfig, ...nxWebpackConfig,
node: { node: {
...@@ -12,7 +14,7 @@ module.exports = config => { ...@@ -12,7 +14,7 @@ module.exports = config => {
net: 'empty', net: 'empty',
module: 'empty', module: 'empty',
child_process: 'empty' child_process: 'empty'
} },
} }
if (process.env.NODE_ENV === 'production') { if (process.env.NODE_ENV === 'production') {
......
export * from './lib/remix-ui-editor' export * from './lib/ace-remix-ui-editor'
import React, { useState, useRef, useEffect, useReducer } from 'react' // eslint-disable-line
import { reducerActions, reducerListener, initialState } from './actions/ace-editor'
import './remix-ui-editor.css'
///
import AceEditor from 'react-ace'
import "ace-builds/src-min-noconflict/ext-language_tools";
import 'ace-builds/webpack-resolver'
// Custom mode and theme import
import 'ace-mode-solidity/build/remix-ide/mode-solidity'
import './utils/theme-solidity';
import { Ace } from 'ace-builds'
import * as AceBuilds from 'ace-builds'
type cursorPosition = {
startLineNumber: number,
startColumn: number,
endLineNumber: number,
endColumn: number
}
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
}
type sourceAnnotationMap = {
[key: string]: [sourceAnnotation];
}
type sourceMarkerMap = {
[key: string]: [sourceMarker];
}
/* eslint-disable-next-line */
export interface EditorUIProps {
activated: boolean
theme: string
currentFile: string
sourceAnnotationsPerFile: sourceAnnotationMap
markerPerFile: sourceMarkerMap
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
}
editorAPI:{
findMatches: (uri: string, value: string) => any
getFontSize: () => number,
getValue: (uri: string) => string
getCursorPosition: () => cursorPosition
}
}
export const EditorUI = (props: EditorUIProps) => {
const [, setCurrentBreakpoints] = useState({})
const [currentAnnotations, setCurrentAnnotations] = useState({})
const [currentMarkers, setCurrentMarkers] = useState({})
const editorRef = useRef<Ace.Editor>(null)
const currentFileRef = useRef('')
const aceRef = useRef(null)
const [editorModelsState, dispatch] = useReducer(reducerActions, initialState)
const setAnnotationsbyFile = (uri) => {
if (props.sourceAnnotationsPerFile[uri]) {
const model = editorModelsState[uri]?.model
const newAnnotations = []
for (const annotation of props.sourceAnnotationsPerFile[uri]) {
if (!annotation.hide) {
newAnnotations.push({
// range: new monacoRef.current.Range(annotation.row + 1, 1, annotation.row + 1, 1),
options: {
isWholeLine: false,
glyphMarginHoverMessage: { value: (annotation.from ? `from ${annotation.from}:\n` : '') + annotation.text },
glyphMarginClassName: `fal fa-exclamation-square text-${annotation.type === 'error' ? 'danger' : (annotation.type === 'warning' ? 'warning' : 'info')}`
}
})
}
}
setCurrentAnnotations(prevState => {
// prevState[uri] = model.deltaDecorations(currentAnnotations[uri] || [], newAnnotations)
return prevState
})
}
}
const setMarkerbyFile = (uri) => {
if (props.markerPerFile[uri]) {
const model = editorModelsState[uri]?.model
const newMarkers = []
for (const marker of props.markerPerFile[uri]) {
if (!marker.hide) {
let isWholeLine = false
if (marker.position.start.line === marker.position.end.line && marker.position.end.column - marker.position.start.column < 3) {
// in this case we force highlighting the whole line (doesn't make sense to highlight 2 chars)
isWholeLine = true
}
newMarkers.push({
// range: new monacoRef.current.Range(marker.position.start.line + 1, marker.position.start.column + 1, marker.position.end.line + 1, marker.position.end.column + 1),
options: {
isWholeLine,
inlineClassName: `bg-info highlightLine${marker.position.start.line + 1}`
}
})
}
}
setCurrentMarkers(prevState => {
// prevState[uri] = model.deltaDecorations(currentMarkers[uri] || [], newMarkers)
return prevState
})
}
}
useEffect(() => {
if (!editorRef.current) return
currentFileRef.current = props.currentFile
// editorRef.current.setModel(editorModelsState[props.currentFile].model)
// editorRef.current.updateOptions({ readOnly: editorModelsState[props.currentFile].readOnly })
setAnnotationsbyFile(props.currentFile)
setMarkerbyFile(props.currentFile)
}, [props.currentFile])
useEffect(() => {
setAnnotationsbyFile(props.currentFile)
}, [JSON.stringify(props.sourceAnnotationsPerFile)])
useEffect(() => {
setMarkerbyFile(props.currentFile)
}, [JSON.stringify(props.markerPerFile)])
props.editorAPI.findMatches = (uri: string, value: string) => {
if (!editorRef.current) return
const model = editorModelsState[uri]?.model
// if (model) return model.findMatches(value)
}
props.editorAPI.getValue = (uri: string) => {
if (!editorRef.current) return
const model = editorModelsState[uri]?.model
if (model) {
return model.getValue()
}
}
// props.editorAPI.getCursorPosition = () => {
// // if (!monacoRef.current) return
// const model = editorModelsState[currentFileRef.current]?.model
// if (model) {
// return model.getOffsetAt(editorRef.current.getPosition())
// }
// }
props.editorAPI.getCursorPosition = () => {
if (!aceRef.current) return
const model = editorModelsState[currentFileRef.current]?.model
if (model) {
const point = model.getCursorPosition()
return {
startColumn: point.column,
startLineNumber: point.row,
endColumn: point.column,
endLineNumber: point.row,
}
}
}
props.editorAPI.getFontSize = () => {
if (!editorRef.current) return
return Number(editorRef.current.getFontSize())
}
function onLoad(editor: Ace.Editor) {
editorRef.current = editor
reducerListener(props.plugin, dispatch, aceRef.current, editorRef.current, props.events)
props.events.onEditorMounted()
// @ts-ignore
editor.on('guttermousedown', e => {
const row = e.getDocumentPosition().row
const target = e.domEvent.target
if (target.className.indexOf("ace_gutter-cell") == -1){
return;
}
if (!editor.isFocused()){
return;
}
if (e.clientX > 25 + target.getBoundingClientRect().left){
return;
}
// If there's a breakpoint already defined, it should be removed, offering the toggle feature
const breakpoints = e.editor.session.getBreakpoints()
const currentFile = currentFileRef.current
if(breakpoints[row] === undefined){
props.events.onBreakPointAdded(currentFile, row)
e.editor.session.setBreakpoint(row, 'ace_breakpoint');
}else{
props.events.onBreakPointCleared(currentFile, row)
e.editor.session.clearBreakpoint(row);
}
e.stop();
})
}
function onBeforeunload(ace: typeof AceBuilds) {
aceRef.current = ace
}
///
return (
<AceEditor
theme="solidity"
mode="solidity"
name="solidity-editor"
enableBasicAutocompletion
enableLiveAutocompletion
enableSnippets
editorProps={{ $blockScrolling: true }}
style={{lineHeight: 1.75, height: '100%', width: '100%'}}
onLoad={onLoad}
onBeforeLoad={onBeforeunload}
showGutter
/>
)
}
export default EditorUI
```typescript
ace.session.setMode(`ace/mode/solidity`)
```
import { Ace } from 'ace-builds' import { Ace } from 'ace-builds'
import * as AceBuilds from 'ace-builds'
export interface Action { export interface Action {
type: string; type: string;
payload: Record<string, any> payload: Record<string, any>
ace: Ace.Editor, ace: typeof AceBuilds,
editor: any editor: Ace.Editor
} }
export const initialState:{[uri: string]: { export const initialState:{[uri: string]: {
...@@ -25,17 +26,16 @@ export const reducerActions = (models= initialState, action: Action) => { ...@@ -25,17 +26,16 @@ export const reducerActions = (models= initialState, action: Action) => {
const language = action.payload.language const language = action.payload.language
const readOnly = action.payload.readOnly const readOnly = action.payload.readOnly
if (models[uri]) return models // already existing if (models[uri]) return models // already existing
debugger
models[uri] = { language, uri, readOnly } models[uri] = { language, uri, readOnly }
ace.setValue(value) editor.setValue(value)
models[uri].model = ace models[uri].model = editor
ace.on('change', () => action.payload.events.onDidChangeContent(uri)) editor.on('change', () => action.payload.events.onDidChangeContent(uri))
return models return models
} }
case 'DISPOSE_MODEL': { case 'DISPOSE_MODEL': {
const uri = action.payload.uri const uri = action.payload.uri
const model = models[uri]?.model const model = models[uri]?.model
// if (model) model.dispose() if (model) model.session.destroy()
delete models[uri] delete models[uri]
return models return models
} }
...@@ -44,6 +44,7 @@ export const reducerActions = (models= initialState, action: Action) => { ...@@ -44,6 +44,7 @@ export const reducerActions = (models= initialState, action: Action) => {
const uri = action.payload.uri const uri = action.payload.uri
const value = action.payload.value const value = action.payload.value
const model = models[uri]?.model const model = models[uri]?.model
editor.setValue(value)
if (model) { if (model) {
model.setValue(value) model.setValue(value)
} }
...@@ -53,8 +54,12 @@ export const reducerActions = (models= initialState, action: Action) => { ...@@ -53,8 +54,12 @@ export const reducerActions = (models= initialState, action: Action) => {
if (!editor) return models if (!editor) return models
const line = action.payload.line const line = action.payload.line
const column = action.payload.column const column = action.payload.column
editor.revealLine(line) // editor.revealLine(line)
editor.setPosition({ column, lineNumber: line }) editor.moveCursorToPosition({
column,
row: line,
})
// editor.setPosition({ column, lineNumber: line })
return models return models
} }
case 'FOCUS': { case 'FOCUS': {
...@@ -65,13 +70,13 @@ export const reducerActions = (models= initialState, action: Action) => { ...@@ -65,13 +70,13 @@ export const reducerActions = (models= initialState, action: Action) => {
case 'SET_FONTSIZE': { case 'SET_FONTSIZE': {
if (!editor) return models if (!editor) return models
const size = action.payload.size const size = action.payload.size
editor.updateOptions({ fontSize: size }) editor.setFontSize(size)
return models return models
} }
case 'SET_WORDWRAP': { case 'SET_WORDWRAP': {
if (!editor) return models if (!editor) return models
const wrap = action.payload.wrap const wrap = action.payload.wrap
editor.updateOptions({ wordWrap: wrap ? 'on' : 'off' }) editor.setWrapBehavioursEnabled(wrap)
return models return models
} }
} }
...@@ -79,7 +84,6 @@ export const reducerActions = (models= initialState, action: Action) => { ...@@ -79,7 +84,6 @@ export const reducerActions = (models= initialState, action: Action) => {
export const reducerListener = (plugin, dispatch, ace, editor, events) => { export const reducerListener = (plugin, dispatch, ace, editor, events) => {
plugin.on('editor', 'addModel', (value, language, uri, readOnly) => { plugin.on('editor', 'addModel', (value, language, uri, readOnly) => {
debugger
dispatch({ dispatch({
type: 'ADD_MODEL', type: 'ADD_MODEL',
payload: { uri, value, language, readOnly, events }, payload: { uri, value, language, readOnly, events },
...@@ -89,7 +93,6 @@ export const reducerListener = (plugin, dispatch, ace, editor, events) => { ...@@ -89,7 +93,6 @@ export const reducerListener = (plugin, dispatch, ace, editor, events) => {
}) })
plugin.on('editor', 'disposeModel', (uri) => { plugin.on('editor', 'disposeModel', (uri) => {
debugger
dispatch({ dispatch({
type: 'DISPOSE_MODEL', type: 'DISPOSE_MODEL',
payload: { uri }, payload: { uri },
...@@ -99,7 +102,6 @@ export const reducerListener = (plugin, dispatch, ace, editor, events) => { ...@@ -99,7 +102,6 @@ export const reducerListener = (plugin, dispatch, ace, editor, events) => {
}) })
plugin.on('editor', 'setValue', (uri, value) => { plugin.on('editor', 'setValue', (uri, value) => {
debugger
dispatch({ dispatch({
type: 'SET_VALUE', type: 'SET_VALUE',
payload: { uri, value }, payload: { uri, value },
...@@ -109,7 +111,6 @@ export const reducerListener = (plugin, dispatch, ace, editor, events) => { ...@@ -109,7 +111,6 @@ export const reducerListener = (plugin, dispatch, ace, editor, events) => {
}) })
plugin.on('editor', 'revealLine', (line, column) => { plugin.on('editor', 'revealLine', (line, column) => {
debugger
dispatch({ dispatch({
type: 'REVEAL_LINE', type: 'REVEAL_LINE',
payload: { line, column }, payload: { line, column },
...@@ -119,7 +120,6 @@ export const reducerListener = (plugin, dispatch, ace, editor, events) => { ...@@ -119,7 +120,6 @@ export const reducerListener = (plugin, dispatch, ace, editor, events) => {
}) })
plugin.on('editor', 'focus', () => { plugin.on('editor', 'focus', () => {
debugger
dispatch({ dispatch({
type: 'FOCUS', type: 'FOCUS',
payload: {}, payload: {},
...@@ -129,7 +129,6 @@ export const reducerListener = (plugin, dispatch, ace, editor, events) => { ...@@ -129,7 +129,6 @@ export const reducerListener = (plugin, dispatch, ace, editor, events) => {
}) })
plugin.on('editor', 'setFontSize', (size) => { plugin.on('editor', 'setFontSize', (size) => {
debugger
dispatch({ dispatch({
type: 'SET_FONTSIZE', type: 'SET_FONTSIZE',
payload: { size }, payload: { size },
...@@ -139,7 +138,6 @@ export const reducerListener = (plugin, dispatch, ace, editor, events) => { ...@@ -139,7 +138,6 @@ export const reducerListener = (plugin, dispatch, ace, editor, events) => {
}) })
plugin.on('editor', 'setWordWrap', (wrap) => { plugin.on('editor', 'setWordWrap', (wrap) => {
debugger
dispatch({ dispatch({
type: 'SET_WORDWRAP', type: 'SET_WORDWRAP',
payload: { wrap }, payload: { wrap },
......
import React, { useImperativeHandle, useEffect, useRef, useState } from 'react';
import * as monaco from 'monaco-editor';
import {editor, languages} from 'monaco-editor';
function noop() {}
export type IMonacoEditor = typeof monaco;
export interface MonacoEditorProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'>{
/**
* width of editor.
* Defaults to `100%`
*/
width?: number | string;
/**
* height of editor.
* Defaults to `100%`.
*/
height?: number | string;
/**
* value of the auto created model in the editor.
*/
value?: string;
/**
* the initial value of the auto created model in the editor.
*/
defaultValue?: string;
/**
* The initial language of the auto created model in the editor.
* To not create automatically a model, use `model: null`.
*/
language?: monaco.editor.IStandaloneEditorConstructionOptions['language'];
/**
* User provided extension function provider for auto-complete.
*/
autoComplete?: (model: monaco.editor.ITextModel, position: monaco.Position) => languages.CompletionItem[];
/**
* Initial theme to be used for rendering.
* The current out-of-the-box available themes are: 'vs' (default), 'vs-dark', 'hc-black'.
* You can create custom themes via `monaco.editor.defineTheme`.
* To switch a theme, use `monaco.editor.setTheme`
*/
theme?: monaco.editor.IStandaloneEditorConstructionOptions['theme'];
/**
* The options to create an editor.
*/
options?: monaco.editor.IStandaloneEditorConstructionOptions;
/**
* an event emitted when the editor has been mounted (similar to `componentDidMount` of React)
*/
editorDidMount?: (editor: monaco.editor.IStandaloneCodeEditor, monaco: IMonacoEditor) => void;
/**
* an event emitted when the content of the current model has changed.
*/
onChange?: (value: string, event: monaco.editor.IModelContentChangedEvent) => void;
}
export interface RefEditorInstance {
container: HTMLDivElement | null;
editor?: monaco.editor.IStandaloneCodeEditor;
monaco: IMonacoEditor;
}
function MonacoEditor(props: MonacoEditorProps, ref: ((instance: RefEditorInstance) => void) | React.RefObject<RefEditorInstance> | null | undefined) {
const { width = '100%', height = '100%', value = '', theme = '', language = 'javascript', autoComplete, options = {}, editorDidMount = noop, onChange = noop, defaultValue = '', ...other } = props;
options.language = language || options.language;
options.theme = theme || options.theme;
const [val, setVal] = useState(defaultValue);
const container = useRef<HTMLDivElement>(null);
const editor = useRef<monaco.editor.IStandaloneCodeEditor>();
useImperativeHandle(ref, () => ({ container: container.current, editor: editor.current, monaco }));
useEffect(() => {
if (container.current) {
editor.current = monaco.editor.create(container.current, {
value: val,
language,
...options,
});
if (options.theme) {
monaco.editor.setTheme(options.theme);
}
// After initializing monaco editor
editorDidMount!(editor.current, monaco);
editor.current.onDidChangeModelContent((event) => {
const valueCurrent = editor.current!.getValue();
// Always refer to the latest value
onChange!(valueCurrent, event);
});
}
}, []);
useEffect(() => {
if (value !== val && editor.current) {
if (autoComplete) {
if (editor?.current?.getModel() && editor?.current?.getPosition()) {
monaco.languages.registerCompletionItemProvider(language, {
provideCompletionItems: (model, position) => {
return {
suggestions: autoComplete(model, position)
};
}
});
}
}
setVal(value);
editor.current.setValue(value);
}
}, [value]);
useEffect(() => {
if (editor.current) {
const model = editor.current.getModel();
if (model) {
monaco.editor.setModelLanguage(model, props.language || '');
}
}
}, [language]);
useEffect(() => {
if (editor.current) {
const optionsRaw = editor.current.getRawOptions();
;(Object.keys(optionsRaw) as (keyof editor.IEditorOptions)[]).forEach((keyname) => {
const propsOpt = options[keyname];
if (optionsRaw[keyname] !== propsOpt && propsOpt !== undefined) {
editor.current!.updateOptions({ [keyname]: propsOpt });
}
});
}
}, [options]);
return <div {...other} ref={container} style={{ ...other.style, width, height }} />;
}
export default React.forwardRef<RefEditorInstance, MonacoEditorProps>(MonacoEditor);
import React, { useState, useRef, useEffect, useReducer } from 'react' // eslint-disable-line
import Editor from '@monaco-editor/react'
import { reducerActions, reducerListener, initialState } from './actions/editor'
import './remix-ui-editor.css'
import MonacoEditor from 'react-monaco-editor'
type cursorPosition = {
startLineNumber: number,
startColumn: number,
endLineNumber: number,
endColumn: number
}
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
}
type sourceAnnotationMap = {
[key: string]: [sourceAnnotation];
}
type sourceMarkerMap = {
[key: string]: [sourceMarker];
}
/* eslint-disable-next-line */
export interface EditorUIProps {
activated: boolean
theme: string
currentFile: string
sourceAnnotationsPerFile: sourceAnnotationMap
markerPerFile: sourceMarkerMap
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
}
editorAPI:{
findMatches: (uri: string, value: string) => any
getFontSize: () => number,
getValue: (uri: string) => string
getCursorPosition: () => cursorPosition
}
}
export const EditorUI = (props: EditorUIProps) => {
const [, setCurrentBreakpoints] = useState({})
const [currentAnnotations, setCurrentAnnotations] = useState({})
const [currentMarkers, setCurrentMarkers] = useState({})
const editorRef = useRef(null)
const monacoRef = useRef(null)
const currentFileRef = useRef('')
const [editorModelsState, dispatch] = useReducer(reducerActions, initialState)
useEffect(() => {
if (!monacoRef.current) return
monacoRef.current.editor.setTheme(props.theme)
}, [props.theme])
if (monacoRef.current) monacoRef.current.editor.setTheme(props.theme)
const setAnnotationsbyFile = (uri) => {
if (props.sourceAnnotationsPerFile[uri]) {
const model = editorModelsState[uri]?.model
const newAnnotations = []
for (const annotation of props.sourceAnnotationsPerFile[uri]) {
if (!annotation.hide) {
newAnnotations.push({
range: new monacoRef.current.Range(annotation.row + 1, 1, annotation.row + 1, 1),
options: {
isWholeLine: false,
glyphMarginHoverMessage: { value: (annotation.from ? `from ${annotation.from}:\n` : '') + annotation.text },
glyphMarginClassName: `fal fa-exclamation-square text-${annotation.type === 'error' ? 'danger' : (annotation.type === 'warning' ? 'warning' : 'info')}`
}
})
}
}
setCurrentAnnotations(prevState => {
prevState[uri] = model.deltaDecorations(currentAnnotations[uri] || [], newAnnotations)
return prevState
})
}
}
const setMarkerbyFile = (uri) => {
if (props.markerPerFile[uri]) {
const model = editorModelsState[uri]?.model
const newMarkers = []
for (const marker of props.markerPerFile[uri]) {
if (!marker.hide) {
let isWholeLine = false
if (marker.position.start.line === marker.position.end.line && marker.position.end.column - marker.position.start.column < 3) {
// in this case we force highlighting the whole line (doesn't make sense to highlight 2 chars)
isWholeLine = true
}
newMarkers.push({
range: new monacoRef.current.Range(marker.position.start.line + 1, marker.position.start.column + 1, marker.position.end.line + 1, marker.position.end.column + 1),
options: {
isWholeLine,
inlineClassName: `bg-info highlightLine${marker.position.start.line + 1}`
}
})
}
}
setCurrentMarkers(prevState => {
prevState[uri] = model.deltaDecorations(currentMarkers[uri] || [], newMarkers)
return prevState
})
}
}
useEffect(() => {
if (!editorRef.current) return
currentFileRef.current = props.currentFile
editorRef.current.setModel(editorModelsState[props.currentFile].model)
editorRef.current.updateOptions({ readOnly: editorModelsState[props.currentFile].readOnly })
setAnnotationsbyFile(props.currentFile)
setMarkerbyFile(props.currentFile)
}, [props.currentFile])
useEffect(() => {
setAnnotationsbyFile(props.currentFile)
}, [JSON.stringify(props.sourceAnnotationsPerFile)])
useEffect(() => {
setMarkerbyFile(props.currentFile)
}, [JSON.stringify(props.markerPerFile)])
props.editorAPI.findMatches = (uri: string, value: string) => {
if (!editorRef.current) return
const model = editorModelsState[uri]?.model
if (model) return model.findMatches(value)
}
props.editorAPI.getValue = (uri: string) => {
if (!editorRef.current) return
const model = editorModelsState[uri]?.model
if (model) {
return model.getValue()
}
}
props.editorAPI.getCursorPosition = () => {
if (!monacoRef.current) return
const model = editorModelsState[currentFileRef.current]?.model
if (model) {
return model.getOffsetAt(editorRef.current.getPosition())
}
}
props.editorAPI.getFontSize = () => {
if (!editorRef.current) return
return editorRef.current.getOption(42).fontSize
}
(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) {
props.events.onBreakPointCleared(currentFile, position.lineNumber)
model.deltaDecorations([prevState[currentFile][position.lineNumber]], [])
delete prevState[currentFile][position.lineNumber]
} else {
props.events.onBreakPointAdded(currentFile, position.lineNumber)
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
})
}
}
function handleEditorDidMount (editor) {
editorRef.current = editor
monacoRef.current.editor.setTheme(props.theme)
reducerListener(props.plugin, dispatch, monacoRef.current, editorRef.current, props.events)
props.events.onEditorMounted()
editor.onMouseUp((e) => {
if (e && e.target && e.target.toString().startsWith('GUTTER')) {
(window as any).addRemixBreakpoint(e.target.position)
}
})
}
function handleEditorWillMount (monaco) {
monacoRef.current = monaco
// see https://microsoft.github.io/monaco-editor/playground.html#customizing-the-appearence-exposed-colors
const lightColor = window.getComputedStyle(document.documentElement).getPropertyValue('--light').trim()
const infoColor = window.getComputedStyle(document.documentElement).getPropertyValue('--info').trim()
const darkColor = window.getComputedStyle(document.documentElement).getPropertyValue('--dark').trim()
const grayColor = window.getComputedStyle(document.documentElement).getPropertyValue('--gray-dark').trim()
monaco.editor.defineTheme('remix-dark', {
base: 'vs-dark',
inherit: true, // can also be false to completely replace the builtin rules
rules: [{ background: darkColor.replace('#', '') }],
colors: {
'editor.background': darkColor,
'editorSuggestWidget.background': lightColor,
'editorSuggestWidget.selectedBackground': lightColor,
'editorSuggestWidget.highlightForeground': infoColor,
'editor.lineHighlightBorder': lightColor,
'editor.lineHighlightBackground': grayColor,
'editorGutter.background': lightColor
}
})
}
return (
// <Editor
// width="100%"
// height="100%"
// path={props.currentFile}
// language={editorModelsState[props.currentFile] ? editorModelsState[props.currentFile].language : 'text'}
// onMount={handleEditorDidMount}
// beforeMount={handleEditorWillMount}
// options= { { glyphMargin: true } }
// />
<MonacoEditor
// width="100%"
// height="100%"
// path={props.currentFile}
// language={editorModelsState[props.currentFile] ? editorModelsState[props.currentFile].language : 'text'}
// onMount={handleEditorDidMount}
// beforeMount={handleEditorWillMount}
// options= { { glyphMargin: true } }
/>
)
}
export default EditorUI
import React, { useState, useRef, useEffect, useReducer } from 'react' // eslint-disable-line
import MonacoEditor from './editor';
import { reducerActions, reducerListener, initialState } from './actions/editor'
import './remix-ui-editor.css'
import { editor } from 'monaco-editor'
import * as monaco from 'monaco-editor';
type cursorPosition = {
startLineNumber: number,
startColumn: number,
endLineNumber: number,
endColumn: number
}
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
}
type sourceAnnotationMap = {
[key: string]: [sourceAnnotation];
}
type sourceMarkerMap = {
[key: string]: [sourceMarker];
}
/* eslint-disable-next-line */
export interface EditorUIProps {
activated: boolean
theme: string
currentFile: string
sourceAnnotationsPerFile: sourceAnnotationMap
markerPerFile: sourceMarkerMap
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
}
editorAPI:{
findMatches: (uri: string, value: string) => any
getFontSize: () => number,
getValue: (uri: string) => string
getCursorPosition: () => cursorPosition
}
}
export const EditorUI = (props: EditorUIProps) => {
const [, setCurrentBreakpoints] = useState({})
const [currentAnnotations, setCurrentAnnotations] = useState({})
const [currentMarkers, setCurrentMarkers] = useState({})
const editorRef = useRef(null)
const monacoRef = useRef(null)
const currentFileRef = useRef('')
const [editorModelsState, dispatch] = useReducer(reducerActions, initialState)
useEffect(() => {
if (!monacoRef.current) return
monacoRef.current.editor.setTheme(props.theme)
}, [props.theme])
if (monacoRef.current) monacoRef.current.editor.setTheme(props.theme)
const setAnnotationsbyFile = (uri) => {
if (props.sourceAnnotationsPerFile[uri]) {
const model = editorModelsState[uri]?.model
const newAnnotations = []
for (const annotation of props.sourceAnnotationsPerFile[uri]) {
if (!annotation.hide) {
newAnnotations.push({
range: new monacoRef.current.Range(annotation.row + 1, 1, annotation.row + 1, 1),
options: {
isWholeLine: false,
glyphMarginHoverMessage: { value: (annotation.from ? `from ${annotation.from}:\n` : '') + annotation.text },
glyphMarginClassName: `fal fa-exclamation-square text-${annotation.type === 'error' ? 'danger' : (annotation.type === 'warning' ? 'warning' : 'info')}`
}
})
}
}
setCurrentAnnotations(prevState => {
prevState[uri] = model.deltaDecorations(currentAnnotations[uri] || [], newAnnotations)
return prevState
})
}
}
const setMarkerbyFile = (uri) => {
if (props.markerPerFile[uri]) {
const model = editorModelsState[uri]?.model
const newMarkers = []
for (const marker of props.markerPerFile[uri]) {
if (!marker.hide) {
let isWholeLine = false
if (marker.position.start.line === marker.position.end.line && marker.position.end.column - marker.position.start.column < 3) {
// in this case we force highlighting the whole line (doesn't make sense to highlight 2 chars)
isWholeLine = true
}
newMarkers.push({
range: new monacoRef.current.Range(marker.position.start.line + 1, marker.position.start.column + 1, marker.position.end.line + 1, marker.position.end.column + 1),
options: {
isWholeLine,
inlineClassName: `bg-info highlightLine${marker.position.start.line + 1}`
}
})
}
}
setCurrentMarkers(prevState => {
prevState[uri] = model.deltaDecorations(currentMarkers[uri] || [], newMarkers)
return prevState
})
}
}
useEffect(() => {
if (!editorRef.current) return
currentFileRef.current = props.currentFile
if(editorModelsState[props.currentFile]) {
editorRef.current.setModel(editorModelsState[props.currentFile].model)
editorRef.current.updateOptions({ readOnly: editorModelsState[props.currentFile].readOnly })
}
setAnnotationsbyFile(props.currentFile)
setMarkerbyFile(props.currentFile)
}, [props.currentFile])
useEffect(() => {
setAnnotationsbyFile(props.currentFile)
}, [JSON.stringify(props.sourceAnnotationsPerFile)])
useEffect(() => {
setMarkerbyFile(props.currentFile)
}, [JSON.stringify(props.markerPerFile)])
props.editorAPI.findMatches = (uri: string, value: string) => {
if (!editorRef.current) return
const model = editorModelsState[uri]?.model
if (model) return model.findMatches(value)
}
props.editorAPI.getValue = (uri: string) => {
if (!editorRef.current) return
const model = editorModelsState[uri]?.model
if (model) {
return model.getValue()
}
}
props.editorAPI.getCursorPosition = () => {
if (!monacoRef.current) return
const model = editorModelsState[currentFileRef.current]?.model
if (model) {
return model.getOffsetAt(editorRef.current.getPosition())
}
}
props.editorAPI.getFontSize = () => {
if (!editorRef.current) return
return editorRef.current.getOption(42).fontSize
}
(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) {
props.events.onBreakPointCleared(currentFile, position.lineNumber)
model.deltaDecorations([prevState[currentFile][position.lineNumber]], [])
delete prevState[currentFile][position.lineNumber]
} else {
props.events.onBreakPointAdded(currentFile, position.lineNumber)
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
})
}
}
function handleEditorDidMount (editor, monaco) {
editorRef.current = editor
monacoRef.current = monaco
monacoRef.current.editor.setTheme(props.theme)
reducerListener(props.plugin, dispatch, monacoRef.current, editorRef.current, props.events)
props.events.onEditorMounted()
editor.onMouseUp((e) => {
if (e && e.target && e.target.toString().startsWith('GUTTER')) {
(window as any).addRemixBreakpoint(e.target.position)
}
})
}
function handleEditorWillMount (monaco) {
monacoRef.current = monaco
// see https://microsoft.github.io/monaco-editor/playground.html#customizing-the-appearence-exposed-colors
const lightColor = window.getComputedStyle(document.documentElement).getPropertyValue('--light').trim()
const infoColor = window.getComputedStyle(document.documentElement).getPropertyValue('--info').trim()
const darkColor = window.getComputedStyle(document.documentElement).getPropertyValue('--dark').trim()
const grayColor = window.getComputedStyle(document.documentElement).getPropertyValue('--gray-dark').trim()
monaco.editor.defineTheme('remix-dark', {
base: 'vs-dark',
inherit: true, // can also be false to completely replace the builtin rules
rules: [{ background: darkColor.replace('#', '') }],
colors: {
'editor.background': darkColor,
'editorSuggestWidget.background': lightColor,
'editorSuggestWidget.selectedBackground': lightColor,
'editorSuggestWidget.highlightForeground': infoColor,
'editor.lineHighlightBorder': lightColor,
'editor.lineHighlightBackground': grayColor,
'editorGutter.background': lightColor
}
})
}
const options: editor.IStandaloneEditorConstructionOptions & editor.IEditorScrollbarOptions = {
selectOnLineNumbers: true,
roundedSelection: false,
cursorStyle: 'line',
automaticLayout: false,
glyphMargin: true
};
// return (
// <MonacoEditor
// value={'1111'}
// />
// )
const divEl = useRef<HTMLDivElement>(null);
let editor: monaco.editor.IStandaloneCodeEditor;
useEffect(() => {
if (divEl.current) {
debugger
editor = monaco.editor.create(divEl.current, {
value: ['function x() {', '\tconsole.log("Hello world!");', '}'].join('\n'),
language: 'typescript'
});
}
return () => {
editor.dispose();
};
}, []);
return <div className="Editor" style={{height:'100%', width: '100%'}} ref={divEl}></div>;
}
export default EditorUI
.hover-row { .hover-row {
white-space: pre; white-space: pre;
margin-left : 10px; margin-left : 10px;
background : var(--light); background : var(--light);
font-weight : bold; font-weight : bold;
font-family : monospace; font-family : monospace;
padding : 10px; padding : 10px;
border-radius : 10px; border-radius : 10px;
height: auto; height: auto;
width: auto; width: auto;
} }
\ No newline at end of file .ace_breakpoint {
background-color: var(--secondary);
}
import React, { useState, useRef, useEffect, useReducer } from 'react' // eslint-disable-line import React, { useState, useRef, useEffect, useReducer } from 'react' // eslint-disable-line
import Editor from '@monaco-editor/react' import Editor from '@monaco-editor/react'
import { reducerActions, reducerListener, initialState } from './actions/ace-editor' import { reducerActions, reducerListener, initialState } from './actions/editor'
import './remix-ui-editor.css' import './remix-ui-editor.css'
///
import AceEditor from 'react-ace'
import "ace-builds/src-min-noconflict/ext-language_tools";
// Custom mode and theme import
import 'ace-mode-solidity/build/remix-ide/mode-solidity'
import './utils/theme-solidity';
import { Ace } from 'ace-builds'
type cursorPosition = { type cursorPosition = {
startLineNumber: number, startLineNumber: number,
startColumn: number, startColumn: number,
...@@ -79,11 +72,18 @@ export const EditorUI = (props: EditorUIProps) => { ...@@ -79,11 +72,18 @@ export const EditorUI = (props: EditorUIProps) => {
const [currentAnnotations, setCurrentAnnotations] = useState({}) const [currentAnnotations, setCurrentAnnotations] = useState({})
const [currentMarkers, setCurrentMarkers] = useState({}) const [currentMarkers, setCurrentMarkers] = useState({})
const editorRef = useRef(null) const editorRef = useRef(null)
const monacoRef = useRef(null)
const currentFileRef = useRef('') const currentFileRef = useRef('')
const aceRef = useRef(null)
const [editorModelsState, dispatch] = useReducer(reducerActions, initialState) const [editorModelsState, dispatch] = useReducer(reducerActions, initialState)
useEffect(() => {
if (!monacoRef.current) return
monacoRef.current.editor.setTheme(props.theme)
}, [props.theme])
if (monacoRef.current) monacoRef.current.editor.setTheme(props.theme)
const setAnnotationsbyFile = (uri) => { const setAnnotationsbyFile = (uri) => {
if (props.sourceAnnotationsPerFile[uri]) { if (props.sourceAnnotationsPerFile[uri]) {
const model = editorModelsState[uri]?.model const model = editorModelsState[uri]?.model
...@@ -91,7 +91,7 @@ export const EditorUI = (props: EditorUIProps) => { ...@@ -91,7 +91,7 @@ export const EditorUI = (props: EditorUIProps) => {
for (const annotation of props.sourceAnnotationsPerFile[uri]) { for (const annotation of props.sourceAnnotationsPerFile[uri]) {
if (!annotation.hide) { if (!annotation.hide) {
newAnnotations.push({ newAnnotations.push({
// range: new monacoRef.current.Range(annotation.row + 1, 1, annotation.row + 1, 1), range: new monacoRef.current.Range(annotation.row + 1, 1, annotation.row + 1, 1),
options: { options: {
isWholeLine: false, isWholeLine: false,
glyphMarginHoverMessage: { value: (annotation.from ? `from ${annotation.from}:\n` : '') + annotation.text }, glyphMarginHoverMessage: { value: (annotation.from ? `from ${annotation.from}:\n` : '') + annotation.text },
...@@ -101,7 +101,7 @@ export const EditorUI = (props: EditorUIProps) => { ...@@ -101,7 +101,7 @@ export const EditorUI = (props: EditorUIProps) => {
} }
} }
setCurrentAnnotations(prevState => { setCurrentAnnotations(prevState => {
// prevState[uri] = model.deltaDecorations(currentAnnotations[uri] || [], newAnnotations) prevState[uri] = model.deltaDecorations(currentAnnotations[uri] || [], newAnnotations)
return prevState return prevState
}) })
} }
...@@ -119,7 +119,7 @@ export const EditorUI = (props: EditorUIProps) => { ...@@ -119,7 +119,7 @@ export const EditorUI = (props: EditorUIProps) => {
isWholeLine = true isWholeLine = true
} }
newMarkers.push({ newMarkers.push({
// range: new monacoRef.current.Range(marker.position.start.line + 1, marker.position.start.column + 1, marker.position.end.line + 1, marker.position.end.column + 1), range: new monacoRef.current.Range(marker.position.start.line + 1, marker.position.start.column + 1, marker.position.end.line + 1, marker.position.end.column + 1),
options: { options: {
isWholeLine, isWholeLine,
inlineClassName: `bg-info highlightLine${marker.position.start.line + 1}` inlineClassName: `bg-info highlightLine${marker.position.start.line + 1}`
...@@ -128,7 +128,7 @@ export const EditorUI = (props: EditorUIProps) => { ...@@ -128,7 +128,7 @@ export const EditorUI = (props: EditorUIProps) => {
} }
} }
setCurrentMarkers(prevState => { setCurrentMarkers(prevState => {
// prevState[uri] = model.deltaDecorations(currentMarkers[uri] || [], newMarkers) prevState[uri] = model.deltaDecorations(currentMarkers[uri] || [], newMarkers)
return prevState return prevState
}) })
} }
...@@ -137,8 +137,8 @@ export const EditorUI = (props: EditorUIProps) => { ...@@ -137,8 +137,8 @@ export const EditorUI = (props: EditorUIProps) => {
useEffect(() => { useEffect(() => {
if (!editorRef.current) return if (!editorRef.current) return
currentFileRef.current = props.currentFile currentFileRef.current = props.currentFile
// editorRef.current.setModel(editorModelsState[props.currentFile].model) editorRef.current.setModel(editorModelsState[props.currentFile].model)
// editorRef.current.updateOptions({ readOnly: editorModelsState[props.currentFile].readOnly }) editorRef.current.updateOptions({ readOnly: editorModelsState[props.currentFile].readOnly })
setAnnotationsbyFile(props.currentFile) setAnnotationsbyFile(props.currentFile)
setMarkerbyFile(props.currentFile) setMarkerbyFile(props.currentFile)
}, [props.currentFile]) }, [props.currentFile])
...@@ -154,7 +154,7 @@ export const EditorUI = (props: EditorUIProps) => { ...@@ -154,7 +154,7 @@ export const EditorUI = (props: EditorUIProps) => {
props.editorAPI.findMatches = (uri: string, value: string) => { props.editorAPI.findMatches = (uri: string, value: string) => {
if (!editorRef.current) return if (!editorRef.current) return
const model = editorModelsState[uri]?.model const model = editorModelsState[uri]?.model
// if (model) return model.findMatches(value) if (model) return model.findMatches(value)
} }
props.editorAPI.getValue = (uri: string) => { props.editorAPI.getValue = (uri: string) => {
...@@ -165,13 +165,13 @@ export const EditorUI = (props: EditorUIProps) => { ...@@ -165,13 +165,13 @@ export const EditorUI = (props: EditorUIProps) => {
} }
} }
// props.editorAPI.getCursorPosition = () => { props.editorAPI.getCursorPosition = () => {
// // if (!monacoRef.current) return if (!monacoRef.current) return
// const model = editorModelsState[currentFileRef.current]?.model const model = editorModelsState[currentFileRef.current]?.model
// if (model) { if (model) {
// return model.getOffsetAt(editorRef.current.getPosition()) return model.getOffsetAt(editorRef.current.getPosition())
// } }
// } }
props.editorAPI.getFontSize = () => { props.editorAPI.getFontSize = () => {
if (!editorRef.current) return if (!editorRef.current) return
...@@ -192,7 +192,7 @@ export const EditorUI = (props: EditorUIProps) => { ...@@ -192,7 +192,7 @@ export const EditorUI = (props: EditorUIProps) => {
} else { } else {
props.events.onBreakPointAdded(currentFile, position.lineNumber) props.events.onBreakPointAdded(currentFile, position.lineNumber)
const decorationIds = model.deltaDecorations([], [{ const decorationIds = model.deltaDecorations([], [{
// range: new monacoRef.current.Range(position.lineNumber, 1, position.lineNumber, 1), range: new monacoRef.current.Range(position.lineNumber, 1, position.lineNumber, 1),
options: { options: {
isWholeLine: false, isWholeLine: false,
glyphMarginClassName: 'fas fa-circle text-info' glyphMarginClassName: 'fas fa-circle text-info'
...@@ -205,55 +205,50 @@ export const EditorUI = (props: EditorUIProps) => { ...@@ -205,55 +205,50 @@ export const EditorUI = (props: EditorUIProps) => {
} }
} }
// function handleEditorDidMount (editor) { function handleEditorDidMount (editor) {
// editorRef.current = editor
// reducerListener(props.plugin, dispatch, monacoRef.current, editorRef.current, props.events)
// props.events.onEditorMounted()
// editor.onMouseUp((e) => {
// if (e && e.target && e.target.toString().startsWith('GUTTER')) {
// (window as any).addRemixBreakpoint(e.target.position)
// }
// })
// }
function onLoad(editor: Ace.Editor) {
editorRef.current = editor editorRef.current = editor
aceRef.current = editor monacoRef.current.editor.setTheme(props.theme)
reducerListener(props.plugin, dispatch, aceRef.current, editorRef.current, props.events) reducerListener(props.plugin, dispatch, monacoRef.current, editorRef.current, props.events)
props.events.onEditorMounted() props.events.onEditorMounted()
// editor.onMouseUp((e) => { editor.onMouseUp((e) => {
// if (e && e.target && e.target.toString().startsWith('GUTTER')) { if (e && e.target && e.target.toString().startsWith('GUTTER')) {
// (window as any).addRemixBreakpoint(e.target.position) (window as any).addRemixBreakpoint(e.target.position)
// } }
// }) })
} }
function handleEditorWillMount (monaco) { function handleEditorWillMount (monaco) {
monacoRef.current = monaco
// see https://microsoft.github.io/monaco-editor/playground.html#customizing-the-appearence-exposed-colors
const lightColor = window.getComputedStyle(document.documentElement).getPropertyValue('--light').trim()
const infoColor = window.getComputedStyle(document.documentElement).getPropertyValue('--info').trim()
const darkColor = window.getComputedStyle(document.documentElement).getPropertyValue('--dark').trim()
const grayColor = window.getComputedStyle(document.documentElement).getPropertyValue('--gray-dark').trim()
monaco.editor.defineTheme('remix-dark', {
base: 'vs-dark',
inherit: true, // can also be false to completely replace the builtin rules
rules: [{ background: darkColor.replace('#', '') }],
colors: {
'editor.background': darkColor,
'editorSuggestWidget.background': lightColor,
'editorSuggestWidget.selectedBackground': lightColor,
'editorSuggestWidget.highlightForeground': infoColor,
'editor.lineHighlightBorder': lightColor,
'editor.lineHighlightBackground': grayColor,
'editorGutter.background': lightColor
}
})
} }
///
return ( return (
// <Editor <Editor
// width="100%" width="100%"
// height="100%" height="100%"
// path={props.currentFile} path={props.currentFile}
// language={editorModelsState[props.currentFile] ? editorModelsState[props.currentFile].language : 'text'} language={editorModelsState[props.currentFile] ? editorModelsState[props.currentFile].language : 'text'}
// onMount={handleEditorDidMount} onMount={handleEditorDidMount}
// beforeMount={handleEditorWillMount} beforeMount={handleEditorWillMount}
// options= { { glyphMargin: true } } options= { { glyphMargin: true } }
// />
<AceEditor
mode="solidity"
theme="solidity"
onChange={console.log}
value={''}
name="solidity-editor"
enableBasicAutocompletion={true}
enableLiveAutocompletion={true}
onCursorChange={console.log}
editorProps={{ $blockScrolling: true }}
style={{lineHeight: 1.75}}
onLoad={onLoad}
/> />
) )
} }
......
...@@ -11198,6 +11198,22 @@ ...@@ -11198,6 +11198,22 @@
"eslint-visitor-keys": "^2.0.0" "eslint-visitor-keys": "^2.0.0"
} }
}, },
"@uiw/react-monacoeditor": {
"version": "3.4.5",
"resolved": "https://registry.npmjs.org/@uiw/react-monacoeditor/-/react-monacoeditor-3.4.5.tgz",
"integrity": "sha512-IqE/toXxPKOIy0FpwJE9cSfVNMWexNgN8CtrNxaMoIaBhV6kvlQbIDf5aEfPEHp++cR0s6cysNLtlR+7B2oIHA==",
"requires": {
"@babel/runtime": "^7.15.3",
"monaco-editor": "0.29.1"
},
"dependencies": {
"monaco-editor": {
"version": "0.29.1",
"resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.29.1.tgz",
"integrity": "sha512-rguaEG/zrPQSaKzQB7IfX/PpNa0qxF1FY8ZXRkN4WIl8qZdTQRSRJCtRto7IMcSgrU6H53RXI+fTcywOBC4aVw=="
}
}
},
"@ungap/promise-all-settled": { "@ungap/promise-all-settled": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz",
...@@ -15294,6 +15310,11 @@ ...@@ -15294,6 +15310,11 @@
"q": "^1.1.2" "q": "^1.1.2"
} }
}, },
"code-example": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/code-example/-/code-example-3.3.1.tgz",
"integrity": "sha512-Kj+3NvIsqzWUQ8ndEz6savEYopLZLFVnVRI9TmZIGHukj+jwuq+7xuqzk/cKl9fyfH2JAl2N3P9CX3cDLCGKMA=="
},
"code-point-at": { "code-point-at": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
...@@ -32409,6 +32430,20 @@ ...@@ -32409,6 +32430,20 @@
"integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==", "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==",
"dev": true "dev": true
}, },
"monaco-editor": {
"version": "0.30.1",
"resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.30.1.tgz",
"integrity": "sha512-B/y4+b2O5G2gjuxIFtCE2EkM17R2NM7/3F8x0qcPsqy4V83bitJTIO4TIeZpYlzu/xy6INiY/+84BEm6+7Cmzg=="
},
"monaco-editor-webpack-plugin": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/monaco-editor-webpack-plugin/-/monaco-editor-webpack-plugin-6.0.0.tgz",
"integrity": "sha512-vC886Mzpd2AkSM35XLkfQMjH+Ohz6RISVwhAejDUzZDheJAiz6G34lky1vyO8fZ702v7IrcKmsGwL1rRFnwvUA==",
"dev": true,
"requires": {
"loader-utils": "^2.0.0"
}
},
"morphdom": { "morphdom": {
"version": "2.6.1", "version": "2.6.1",
"resolved": "https://registry.npmjs.org/morphdom/-/morphdom-2.6.1.tgz", "resolved": "https://registry.npmjs.org/morphdom/-/morphdom-2.6.1.tgz",
...@@ -40479,6 +40514,14 @@ ...@@ -40479,6 +40514,14 @@
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
}, },
"react-monaco-editor": {
"version": "0.46.0",
"resolved": "https://registry.npmjs.org/react-monaco-editor/-/react-monaco-editor-0.46.0.tgz",
"integrity": "sha512-/GyQ0tQLbjHAuMUNRfKecBYN68o8TwA4fnwH9P+lHbF80ayMAo0PQ60joTQH6R6j839kMn6o9Kk/cbzOxK5DzA==",
"requires": {
"prop-types": "^15.7.2"
}
},
"react-overlays": { "react-overlays": {
"version": "5.1.1", "version": "5.1.1",
"resolved": "https://registry.npmjs.org/react-overlays/-/react-overlays-5.1.1.tgz", "resolved": "https://registry.npmjs.org/react-overlays/-/react-overlays-5.1.1.tgz",
...@@ -156,6 +156,7 @@ ...@@ -156,6 +156,7 @@
"@remixproject/plugin-utils": "^0.3.24", "@remixproject/plugin-utils": "^0.3.24",
"@remixproject/plugin-webview": "^0.3.24", "@remixproject/plugin-webview": "^0.3.24",
"@remixproject/plugin-ws": "^0.3.24", "@remixproject/plugin-ws": "^0.3.24",
"@uiw/react-monacoeditor": "^3.4.5",
"ace-builds": "^1.4.13", "ace-builds": "^1.4.13",
"ansi-gray": "^0.1.1", "ansi-gray": "^0.1.1",
"async": "^2.6.2", "async": "^2.6.2",
...@@ -163,6 +164,7 @@ ...@@ -163,6 +164,7 @@
"brace": "^0.8.0", "brace": "^0.8.0",
"change-case": "^4.1.1", "change-case": "^4.1.1",
"chokidar": "^2.1.8", "chokidar": "^2.1.8",
"code-example": "^3.3.1",
"color-support": "^1.1.3", "color-support": "^1.1.3",
"commander": "^2.20.3", "commander": "^2.20.3",
"deep-equal": "^1.0.1", "deep-equal": "^1.0.1",
...@@ -183,12 +185,14 @@ ...@@ -183,12 +185,14 @@
"jszip": "^3.6.0", "jszip": "^3.6.0",
"latest-version": "^5.1.0", "latest-version": "^5.1.0",
"merge": "^2.1.1", "merge": "^2.1.1",
"monaco-editor": "^0.30.1",
"npm-install-version": "^6.0.2", "npm-install-version": "^6.0.2",
"react": "^17.0.2", "react": "^17.0.2",
"react-ace": "^9.5.0", "react-ace": "^9.5.0",
"react-beautiful-dnd": "^13.1.0", "react-beautiful-dnd": "^13.1.0",
"react-bootstrap": "^1.6.4", "react-bootstrap": "^1.6.4",
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
"react-monaco-editor": "^0.46.0",
"react-tabs": "^3.2.2", "react-tabs": "^3.2.2",
"selenium": "^2.20.0", "selenium": "^2.20.0",
"signale": "^1.4.0", "signale": "^1.4.0",
...@@ -290,6 +294,7 @@ ...@@ -290,6 +294,7 @@
"minixhr": "^3.2.2", "minixhr": "^3.2.2",
"mkdirp": "^0.5.1", "mkdirp": "^0.5.1",
"mocha": "^8.0.1", "mocha": "^8.0.1",
"monaco-editor-webpack-plugin": "^6.0.0",
"nanohtml": "^1.6.3", "nanohtml": "^1.6.3",
"nightwatch": "^1.7.11", "nightwatch": "^1.7.11",
"nodemon": "^2.0.4", "nodemon": "^2.0.4",
......
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