mirror of
https://codeberg.org/uzu/strudel
synced 2026-07-30 08:23:18 -04:00
1f765e54ca
+ use new prebake
156 lines
3.9 KiB
React
156 lines
3.9 KiB
React
import { autocompletion } from '@codemirror/autocomplete';
|
|
import { Prec } from '@codemirror/state';
|
|
import { javascript, javascriptLanguage } from '@codemirror/lang-javascript';
|
|
import { ViewPlugin, EditorView, keymap } from '@codemirror/view';
|
|
import { emacs } from '@replit/codemirror-emacs';
|
|
import { vim } from '@replit/codemirror-vim';
|
|
import { vscodeKeymap } from '@replit/codemirror-vscode-keymap';
|
|
import _CodeMirror from '@uiw/react-codemirror';
|
|
import React, { useCallback, useMemo } from 'react';
|
|
import strudelTheme from '../themes/strudel-theme';
|
|
import { strudelAutocomplete } from './Autocomplete';
|
|
import {
|
|
highlightExtension,
|
|
flashField,
|
|
flash,
|
|
highlightMiniLocations,
|
|
updateMiniLocations,
|
|
} from '@strudel/codemirror';
|
|
import './style.css';
|
|
import { sliderPlugin } from '@strudel/codemirror/slider.mjs';
|
|
|
|
export { flash, highlightMiniLocations, updateMiniLocations };
|
|
|
|
const staticExtensions = [javascript(), flashField, highlightExtension, sliderPlugin];
|
|
|
|
export default function CodeMirror({
|
|
value,
|
|
onChange,
|
|
onViewChanged,
|
|
onSelectionChange,
|
|
onDocChange,
|
|
onEvaluate,
|
|
onReEvaluate,
|
|
onPanic,
|
|
onStop,
|
|
theme,
|
|
keybindings,
|
|
isLineNumbersDisplayed,
|
|
isAutoCompletionEnabled,
|
|
isLineWrappingEnabled,
|
|
fontSize = 18,
|
|
fontFamily = 'monospace',
|
|
}) {
|
|
const handleOnChange = useCallback(
|
|
(value) => {
|
|
onChange?.(value);
|
|
},
|
|
[onChange],
|
|
);
|
|
|
|
const handleOnCreateEditor = useCallback(
|
|
(view) => {
|
|
onViewChanged?.(view);
|
|
},
|
|
[onViewChanged],
|
|
);
|
|
|
|
const handleOnUpdate = useCallback(
|
|
(viewUpdate) => {
|
|
if (viewUpdate.docChanged && onDocChange) {
|
|
onDocChange?.(viewUpdate);
|
|
}
|
|
if (viewUpdate.selectionSet && onSelectionChange) {
|
|
onSelectionChange?.(viewUpdate.state.selection);
|
|
}
|
|
},
|
|
[onSelectionChange],
|
|
);
|
|
|
|
const vscodePlugin = ViewPlugin.fromClass(
|
|
class {
|
|
constructor(view) {}
|
|
},
|
|
{
|
|
provide: (plugin) => {
|
|
return Prec.highest(keymap.of([...vscodeKeymap]));
|
|
},
|
|
},
|
|
);
|
|
|
|
const vscodeExtension = (options) => [vscodePlugin].concat(options ?? []);
|
|
|
|
const extensions = useMemo(() => {
|
|
let _extensions = [...staticExtensions];
|
|
let bindings = {
|
|
vim,
|
|
emacs,
|
|
vscode: vscodeExtension,
|
|
};
|
|
|
|
if (bindings[keybindings]) {
|
|
_extensions.push(bindings[keybindings]());
|
|
}
|
|
|
|
if (isAutoCompletionEnabled) {
|
|
_extensions.push(javascriptLanguage.data.of({ autocomplete: strudelAutocomplete }));
|
|
} else {
|
|
_extensions.push(autocompletion({ override: [] }));
|
|
}
|
|
|
|
_extensions.push(
|
|
keymap.of([
|
|
{
|
|
key: 'Ctrl-Enter',
|
|
run: () => onEvaluate?.(),
|
|
},
|
|
{
|
|
key: 'Alt-Enter',
|
|
run: () => onEvaluate?.(),
|
|
},
|
|
{
|
|
key: 'Ctrl-.',
|
|
run: () => onStop?.(),
|
|
},
|
|
{
|
|
key: 'Alt-.',
|
|
run: (_, e) => {
|
|
e.preventDefault();
|
|
onStop?.();
|
|
},
|
|
},
|
|
{
|
|
key: 'Ctrl-Shift-.',
|
|
run: () => (onPanic ? onPanic() : onStop?.()),
|
|
},
|
|
{
|
|
key: 'Ctrl-Shift-Enter',
|
|
run: () => (onReEvaluate ? onReEvaluate() : onEvaluate?.()),
|
|
},
|
|
]),
|
|
);
|
|
|
|
if (isLineWrappingEnabled) {
|
|
_extensions.push(EditorView.lineWrapping);
|
|
}
|
|
|
|
return _extensions;
|
|
}, [keybindings, isAutoCompletionEnabled, isLineWrappingEnabled, onEvaluate, onReEvaluate, onStop, onPanic]);
|
|
|
|
const basicSetup = useMemo(() => ({ lineNumbers: isLineNumbersDisplayed }), [isLineNumbersDisplayed]);
|
|
|
|
return (
|
|
<div style={{ fontSize, fontFamily }} className="w-full">
|
|
<_CodeMirror
|
|
value={value}
|
|
theme={theme || strudelTheme}
|
|
onChange={handleOnChange}
|
|
onCreateEditor={handleOnCreateEditor}
|
|
onUpdate={handleOnUpdate}
|
|
extensions={extensions}
|
|
basicSetup={basicSetup}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|