import React , { useState , useEffect } from 'react' ; import AceEditor from 'react-ace' ; import 'brace/theme/tomorrow' ; import 'brace/ext/language_tools' ; import Style from './CodeEditor.less' ; import Dialog from '../../components/Dialog' ; import { Select , Option } from '../../components/Select' ; import Button from '../../components/Button' ; const languages = [ 'javascript' , 'typescript' , 'text' , 'java' , 'c_cpp' , 'python' , 'ruby' , 'php' , 'golang' , 'csharp' , 'html' , 'css' , 'sql' , 'json' , ] ; interface LoadedLanguage { [ key ] : boolean ; } const loadedLanguage = { } ; interface CodeEditorProps { visible : boolean ; onClose : ( ) => void ; onSend : ( language : string , code : string ) => void ; } function CodeEditor ( props ) { const { visible , onClose , onSend } = props ; const [ language , setLanguage ] = useState ( 'javascript' ) ; const [ value , setValue ] = useState ( '' ) ; const [ timestamp , setTimestamp ] = useState ( 0 ) ; useEffect ( ( ) => { if ( visible ) { setValue ( '' ) ; } } , [ visible ] ) ; useEffect ( ( ) => { ( async ( ) => { if ( visible && ! loadedLanguage [ language ] ) { /**
                 * 为了减小打包产物体积, 这里是逐个引入所需的语音包
                 * 如果直接用变量路径, 会将该目录下的文件全部打包
                 * 另外不单个引入也不好设置 webpackChunkName
                 */ switch ( language ) { case 'javascript' : { await import ( 'brace/mode/javascript' ) ; break ; } case 'typescript' : { await import ( 'brace/mode/typescript' ) ; break ; } case 'java' : { await import ( 'brace/mode/java' ) ; break ; } case 'c_cpp' : { await import ( 'brace/mode/c_cpp' ) ; break ; } case 'python' : { await import ( 'brace/mode/python' ) ; break ; } case 'ruby' : { await import ( 'brace/mode/ruby' ) ; break ; } case 'php' : { await import ( 'brace/mode/php' ) ; break ; } case 'golang' : { await import ( 'brace/mode/golang' ) ; break ; } case 'csharp' : { await import ( 'brace/mode/csharp' ) ; break ; } case 'html' : { await import ( 'brace/mode/html' ) ; break ; } case 'css' : { await import ( 'brace/mode/css' ) ; break ; } case 'text' : { await import ( 'brace/mode/markdown' ) ; break ; } case 'sql' : { await import ( 'brace/mode/sql' ) ; break ; } case 'json' : { await import ( 'brace/mode/json' ) ; break ; } default : { console . warn ( '不支持的语言包' , language ) ; } } loadedLanguage [ language ] = true ; setTimestamp ( Date . now ( ) ) ; } } ) ( ) ; } , [ visible , language ] ) ; function renderEditor ( ) { if ( ! loadedLanguage [ language ] ) { return null ; } const editorProps = { theme : 'tomorrow' , value , onChange : ( newValue ) => setValue ( newValue ) , fontSize : 12 , width : '100%' , height : '100%' , showPrintMargin : true , showGutter : true , highlightActiveLine : true , setOptions : { enableBasicAutocompletion : true , enableLiveAutocompletion : true , enableSnippets : false , showLineNumbers : true , tabSize : 4 , } , } ; return ( < AceEditor mode = { language === 'text' ? 'markdown' : language } { ... editorProps } />); } return ( < > < Dialog className = { Style . codeEditor } title = "请输入要发送的代码" visible = { visible } onClose = { onClose } > < div className = { Style . container } > < div className = { Style . selectContainer } > < h3 className = { Style . title } > 编程语言 : < /h3> < Select className = { Style . languageSelect } defaultValue = { languages [ 0 ] } onSelect = { ( lang ) => setLanguage ( lang ) } > { languages . map ( ( lang ) => ( < Option value = { lang } key = { lang } > { lang } < /Option>))} < /Select> < /div> < div className = { Style . editorContainer } > { renderEditor ( ) } < /div> < Button className = { Style . sendButton } onClick = { ( ) => onSend ( language , value ) } > 发送 < /Button> < /div> < /Dialog> < span className = "hide" > { timestamp } < /span> < />); } export default CodeEditor ;