import { EditorState , Extension } from '@codemirror/state' ; import { EditorView , drawSelection , highlightSpecialChars , ViewUpdate } from '@codemirror/view' ; import { markdown } from '@codemirror/lang-markdown' ; import { defaultHighlightStyle , HighlightStyle , tags } from '@codemirror/highlight' ; import { undo , redo , history , undoDepth , redoDepth } from '@codemirror/history' ; interface CodeMirrorResult { editor : EditorView ; undo : Function ; redo : Function ; } function postMessage ( name , data ) { ( window as any ) . ReactNativeWebView . postMessage ( JSON . stringify ( { data , name , } ) ) ; } function logMessage ( ... msg ) { postMessage ( 'onLog' , { value : msg } ) ; } const createTheme = ( theme ) : Extension => { const baseTheme = EditorView . baseTheme ( { '&' : { color : theme . color , backgroundColor : theme . backgroundColor , fontFamily : theme . fontFamily , fontSize : `${ theme . fontSize }px` , } , '&.cm-focused' : { outline : 'none' , } , } ) ; const appearanceTheme = EditorView . theme ( { } , { dark : theme . appearance === 'dark' } ) ; const baseHeadingStyle = { fontWeight : 'bold' , fontFamily : theme . fontFamily , } ; const syntaxHighlighting = HighlightStyle . define ( [ { tag : tags . strong , fontWeight : 'bold' , } , { tag : tags . emphasis , fontStyle : 'italic' , } , { ... baseHeadingStyle , tag : tags . heading1 , fontSize : '1.6em' , borderBottom : `1px solid ${ theme . dividerColor }` , } , { ... baseHeadingStyle , tag : tags . heading2 , fontSize : '1.4em' , } , { ... baseHeadingStyle , tag : tags . heading3 , fontSize : '1.3em' , } , { ... baseHeadingStyle , tag : tags . heading4 , fontSize : '1.2em' , } , { ... baseHeadingStyle , tag : tags . heading5 , fontSize : '1.1em' , } , { ... baseHeadingStyle , tag : tags . heading6 , fontSize : '1.0em' , } , { tag : tags . list , fontFamily : theme . fontFamily , } , ] ) ; return [ baseTheme , appearanceTheme , syntaxHighlighting , ] ; } ; export function initCodeMirror ( parentElement , initialText , theme ) { logMessage ( 'Initializing CodeMirror...' ) ; let schedulePostUndoRedoDepthChangeId_ = 0 ; function schedulePostUndoRedoDepthChange ( editor , doItNow = false ) { if ( schedulePostUndoRedoDepthChangeId_ ) { if ( doItNow ) { clearTimeout ( schedulePostUndoRedoDepthChangeId_ ) ; } else { return ; } } schedulePostUndoRedoDepthChangeId_ = setTimeout ( ( ) => { schedulePostUndoRedoDepthChangeId_ = null ; postMessage ( 'onUndoRedoDepthChange' , { undoDepth : undoDepth ( editor . state ) , redoDepth : redoDepth ( editor . state ) , } ) ; } , doItNow ? 0 : 1000 ) ; } const editor = new EditorView ( { state : EditorState . create ( { extensions : [ markdown ( ) , createTheme ( theme ) , history ( ) , drawSelection ( ) , highlightSpecialChars ( ) , EditorView . lineWrapping , EditorView . contentAttributes . of ( { autocapitalize : 'sentence' } ) , defaultHighlightStyle . fallback , EditorView . updateListener . of ( ( viewUpdate ) => { if ( viewUpdate . docChanged ) { postMessage ( 'onChange' , { value : editor . state . doc . toString ( ) } ) ; schedulePostUndoRedoDepthChange ( editor ) ; } } ) , ] , doc : initialText , } ) , parent : parentElement , } ) ; return { editor , undo : ( ) => { undo ( editor ) ; schedulePostUndoRedoDepthChange ( editor , true ) ; } , redo : ( ) => { redo ( editor ) ; schedulePostUndoRedoDepthChange ( editor , true ) ; } , } ; }