All files / lib/common code-editor.view.ts

0% Statements 0/28
0% Branches 0/3
0% Functions 0/6
0% Lines 0/28

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89                                                                                                                                                                                 
import { combineLatest, ReplaySubject } from 'rxjs'
import { SourcePath } from './models'
import CodeMirror from 'codemirror'
import { HTMLElement$, VirtualDOM } from '@youwol/flux-view'
import { IdeState } from './ide.state'
import { filter } from 'rxjs/operators'
 
const defaultConfig = {
    value: '',
    lineNumbers: true,
    theme: 'blackboard',
    lineWrapping: false,
    indentUnit: 4,
}
export class CodeEditorView {
    public readonly editorUid = `${Math.floor(Math.random()) * 1e6}`
    public readonly ideState: IdeState
    public readonly config: { [k: string]: unknown }
    public readonly language: string
    public readonly class = 'w-100 h-100 d-flex flex-column overflow-auto'
    public readonly style = {
        'font-size': 'initial',
    }
    public readonly path: SourcePath
    public readonly change$ = new ReplaySubject<CodeMirror.EditorChange[]>(1)
    public readonly cursor$ = new ReplaySubject<CodeMirror.Position>(1)
    public readonly children: VirtualDOM[]
 
    public readonly nativeEditor$ = new ReplaySubject<CodeMirror.Editor>(1)
 
    constructor(params: {
        ideState: IdeState
        path: SourcePath
        language: string
        config?: unknown
    }) {
        Object.assign(this, params)
 
        const config = {
            ...defaultConfig,
            ...this.config,
            mode: this.language,
            value: this.ideState.updates$[this.path].getValue().content,
        }
        combineLatest([
            this.ideState.updates$[this.path].pipe(
                filter((update) => update.updateOrigin.uid != this.editorUid),
            ),
            this.nativeEditor$,
        ]).subscribe(([{ content }, nativeEditor]) => {
            const cursor = nativeEditor.getCursor()
            nativeEditor.setValue(content)
            nativeEditor.setCursor(cursor)
        })
 
        this.children = [
            {
                id: 'code-mirror-editor',
                class: 'w-100 h-100',
                connectedCallback: (elem: HTMLElement$ & HTMLDivElement) => {
                    const editor: CodeMirror.Editor = window['CodeMirror'](
                        elem,
                        config,
                    )
                    this.nativeEditor$.next(editor)
                    editor.on('changes', (_, changeObj) => {
                        this.change$.next(changeObj)
                        Iif (
                            changeObj.length == 1 &&
                            changeObj[0].origin == 'setValue'
                        ) {
                            return
                        }
                        this.ideState.update({
                            path: this.path,
                            content: editor.getValue(),
                            updateOrigin: { uid: this.editorUid },
                        })
                    })
                    elem.querySelector('.CodeMirror').classList.add('h-100')
                    editor.on('cursorActivity', () => {
                        this.cursor$.next(editor.getCursor())
                    })
                },
            },
        ]
    }
}