@bhsd/codemirror-mediawiki
Version: 
Modified CodeMirror mode based on wikimedia/mediawiki-extensions-CodeMirror
77 lines (76 loc) • 2.45 kB
JavaScript
import { StateField, StateEffect } from '@codemirror/state';
import { Decoration, EditorView, WidgetType, ViewPlugin } from '@codemirror/view';
import { getLSP } from '@bhsd/browser';
import { posToIndex } from './hover';
class InlayHintWidget extends WidgetType {
    constructor(label) {
        super();
        this.label = label;
    }
    toDOM() {
        const element = document.createElement('span');
        element.textContent = this.label;
        element.className = 'cm-inlay-hint';
        return element;
    }
}
const stateEffect = StateEffect.define(), field = StateField.define({
    create() {
        return Decoration.none;
    },
    update(deco, { state: { doc }, effects }) {
        const str = doc.toString();
        for (const effect of effects) {
            if (effect.is(stateEffect)) {
                const { value: { text, inlayHints } } = effect;
                if (str === text) {
                    return inlayHints
                        ? Decoration.set(inlayHints.reverse()
                            .map(({ position, label }) => [posToIndex(doc, position), label])
                            .sort(([a], [b]) => a - b)
                            .map(([index, label]) => Decoration.widget({ widget: new InlayHintWidget(label) }).range(index)))
                        : Decoration.none;
                }
            }
        }
        return deco;
    },
    provide(f) {
        return EditorView.decorations.from(f);
    },
});
const updateField = async ({ view, docChanged }) => {
    if (docChanged) {
        const text = view.state.doc.toString();
        view.dispatch({
            effects: stateEffect.of({
                text,
                inlayHints: await getLSP(view)?.provideInlayHints(text),
            }),
        });
    }
};
export default (cm) => [
    field,
    ViewPlugin.fromClass(class {
        constructor(view) {
            const timer = setInterval(() => {
                if (getLSP(view, false, cm.getWikiConfig)) {
                    clearInterval(timer);
                    void updateField({ view, docChanged: true });
                }
            }, 100);
        }
        update(update) {
            void updateField(update);
        }
    }),
    EditorView.theme({
        '.cm-inlay-hint': {
            color: '#969696',
            fontStyle: 'italic',
            '-webkitUserSelect': 'none',
            userSelect: 'none',
        },
    }),
];