mirror of
https://codeberg.org/uzu/strudel
synced 2026-07-13 06:19:33 -04:00
116 lines
3.5 KiB
JavaScript
116 lines
3.5 KiB
JavaScript
import { toggleLineComment } from '@codemirror/commands';
|
|
import { javascript, javascriptLanguage } from '@codemirror/lang-javascript';
|
|
import { defaultHighlightStyle, syntaxHighlighting } from '@codemirror/language';
|
|
import { Compartment, EditorState, Prec } from '@codemirror/state';
|
|
import { drawSelection, EditorView, keymap } from '@codemirror/view';
|
|
import { logger } from '@strudel/core';
|
|
import { basicSetup, flash, initTheme, extensions, parseBooleans, codemirrorSettings } from '@strudel/codemirror';
|
|
import { evaluate } from '@strudel/transpiler';
|
|
|
|
export class PrebakeCodeMirror {
|
|
constructor(initialCode, storePrebake, container) {
|
|
const settings = codemirrorSettings.get();
|
|
this.storePrebake = storePrebake;
|
|
const compartments = Object.fromEntries(Object.keys(extensions).map((key) => [key, new Compartment()]));
|
|
const initialSettings = Object.keys(compartments).map((key) =>
|
|
compartments[key].of(extensions[key](parseBooleans(settings[key]))),
|
|
);
|
|
initTheme(settings.theme);
|
|
let state = EditorState.create({
|
|
doc: initialCode,
|
|
extensions: [
|
|
...initialSettings,
|
|
basicSetup,
|
|
javascript(),
|
|
javascriptLanguage.data.of({
|
|
closeBrackets: { brackets: ['(', '[', '{', "'", '"', '<'] },
|
|
bracketMatching: { brackets: ['(', '[', '{', "'", '"', '<'] },
|
|
}),
|
|
syntaxHighlighting(defaultHighlightStyle),
|
|
EditorView.updateListener.of((v) => {
|
|
if (v.docChanged) {
|
|
this.code = v.state.doc.toString();
|
|
}
|
|
}),
|
|
drawSelection({ cursorBlinkRate: 0 }),
|
|
Prec.highest(
|
|
keymap.of([
|
|
{
|
|
mac: 'Meta-Enter',
|
|
run: () => {
|
|
this.savePrebake();
|
|
},
|
|
},
|
|
{
|
|
key: 'Ctrl-Enter',
|
|
run: () => {
|
|
this.savePrebake();
|
|
},
|
|
},
|
|
{
|
|
key: 'Alt-Enter',
|
|
run: () => {
|
|
this.savePrebake();
|
|
},
|
|
},
|
|
]),
|
|
),
|
|
],
|
|
});
|
|
|
|
this.code = initialCode;
|
|
this.view = new EditorView({
|
|
state,
|
|
parent: container,
|
|
});
|
|
|
|
const handleSaveEvent = async (e) => {
|
|
if (e.detail.view !== this.view) {
|
|
return; // ignore events from other editors
|
|
}
|
|
await this.savePrebake();
|
|
e?.cancelable && e.preventDefault?.();
|
|
};
|
|
const handleToggleComment = (e) => {
|
|
if (e.detail.view !== this.view) {
|
|
return; // ignore events from other editors
|
|
}
|
|
this.toggleComment();
|
|
e?.cancelable && e.preventDefault?.();
|
|
};
|
|
|
|
document.addEventListener('repl-evaluate', handleSaveEvent);
|
|
document.addEventListener('repl-toggle-comment', handleToggleComment);
|
|
this.cleanup = () => {
|
|
document.removeEventListener('prebake-evaluate', handleSaveEvent);
|
|
document.removeEventListener('prebake-toggle-comment', handleToggleComment);
|
|
};
|
|
}
|
|
|
|
async savePrebake() {
|
|
flash(this.view);
|
|
this.storePrebake(this.code);
|
|
evaluate(this.code, { addReturn: false }); // run prebake
|
|
logger('[prebake] prebake saved');
|
|
}
|
|
|
|
toggleComment() {
|
|
try {
|
|
// Honor selections; toggleLineComment handles both selections and
|
|
// single line
|
|
toggleLineComment(this.view);
|
|
} catch (err) {
|
|
console.error('Error handling repl-toggle-comment event', err);
|
|
}
|
|
}
|
|
|
|
setCode(code) {
|
|
const changes = {
|
|
from: 0,
|
|
to: this.view.state.doc.length,
|
|
insert: code,
|
|
};
|
|
this.view.dispatch({ changes });
|
|
}
|
|
}
|