mirror of
https://codeberg.org/uzu/strudel
synced 2026-07-30 16:33:19 -04:00
bind custom keyboard shortcuts via codemirror
+ add reevaluate and panic shortcuts
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { controls, evalScope } from '@strudel.cycles/core';
|
||||
import { CodeMirror, useHighlighting, useKeydown, useStrudel, flash } from '@strudel.cycles/react';
|
||||
import { CodeMirror, useHighlighting, useStrudel, flash } from '@strudel.cycles/react';
|
||||
import {
|
||||
getAudioContext,
|
||||
initAudioOnFirstClick,
|
||||
@@ -93,32 +93,6 @@ function App() {
|
||||
});
|
||||
|
||||
const error = evalError || schedulerError;
|
||||
useKeydown(
|
||||
useCallback(
|
||||
async (e) => {
|
||||
if (e.ctrlKey || e.altKey) {
|
||||
if (e.code === 'Enter') {
|
||||
e.preventDefault();
|
||||
flash(view);
|
||||
await evaluate(code);
|
||||
if (e.shiftKey) {
|
||||
panic();
|
||||
scheduler.stop();
|
||||
scheduler.start();
|
||||
}
|
||||
if (!scheduler.started) {
|
||||
scheduler.start();
|
||||
}
|
||||
} else if (e.code === 'Period') {
|
||||
scheduler.stop();
|
||||
panic();
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
},
|
||||
[scheduler, evaluate, view, code],
|
||||
),
|
||||
);
|
||||
return (
|
||||
<div>
|
||||
<nav className="z-[12] w-full flex justify-center fixed bottom-0">
|
||||
@@ -136,7 +110,28 @@ function App() {
|
||||
</div>
|
||||
{error && <p>error {error.message}</p>}
|
||||
</nav>
|
||||
<CodeMirror value={code} onChange={setCode} onViewChanged={setView} />
|
||||
<CodeMirror
|
||||
value={code}
|
||||
onChange={setCode}
|
||||
onViewChanged={setView}
|
||||
onEvaluate={async () => {
|
||||
flash(view);
|
||||
await evaluate(code);
|
||||
if (!scheduler.started) {
|
||||
scheduler.start();
|
||||
}
|
||||
}}
|
||||
onReEvaluate={async () => {
|
||||
await evaluate(code);
|
||||
panic();
|
||||
scheduler.stop();
|
||||
scheduler.start();
|
||||
}}
|
||||
onStop={() => {
|
||||
scheduler.stop();
|
||||
panic();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -29,6 +29,10 @@ export default function CodeMirror({
|
||||
onViewChanged,
|
||||
onSelectionChange,
|
||||
onDocChange,
|
||||
onEvaluate,
|
||||
onReEvaluate,
|
||||
onPanic,
|
||||
onStop,
|
||||
theme,
|
||||
keybindings,
|
||||
isLineNumbersDisplayed,
|
||||
@@ -94,14 +98,33 @@ export default function CodeMirror({
|
||||
_extensions.push(autocompletion({ override: [] }));
|
||||
}
|
||||
|
||||
_extensions.push([keymap.of({})]);
|
||||
_extensions.push(
|
||||
keymap.of([
|
||||
{
|
||||
key: 'Ctrl-Enter',
|
||||
run: () => onEvaluate?.(),
|
||||
},
|
||||
{
|
||||
key: 'Ctrl-.',
|
||||
run: () => 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]);
|
||||
}, [keybindings, isAutoCompletionEnabled, isLineWrappingEnabled, onEvaluate, onStop]);
|
||||
|
||||
const basicSetup = useMemo(() => ({ lineNumbers: isLineNumbersDisplayed }), [isLineNumbersDisplayed]);
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ import { Icon } from './Icon';
|
||||
import './style.css';
|
||||
import { logger } from '@strudel.cycles/core';
|
||||
import useEvent from '../hooks/useEvent.mjs';
|
||||
import useKeydown from '../hooks/useKeydown.mjs';
|
||||
|
||||
const getTime = () => getAudioContext().currentTime;
|
||||
|
||||
@@ -92,27 +91,6 @@ export function MiniRepl({
|
||||
getTime: () => scheduler.now(),
|
||||
});
|
||||
|
||||
// keyboard shortcuts
|
||||
useKeydown(
|
||||
useCallback(
|
||||
async (e) => {
|
||||
if (view?.hasFocus) {
|
||||
if (e.ctrlKey || e.altKey) {
|
||||
if (e.code === 'Enter') {
|
||||
e.preventDefault();
|
||||
flash(view);
|
||||
await activateCode();
|
||||
} else if (e.key === '.' || e.code === 'Period') {
|
||||
stop();
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
[activateCode, stop, view],
|
||||
),
|
||||
);
|
||||
|
||||
const [log, setLog] = useState([]);
|
||||
useLogger(
|
||||
useCallback((e) => {
|
||||
@@ -164,6 +142,11 @@ export function MiniRepl({
|
||||
fontSize={fontSize}
|
||||
keybindings={keybindings}
|
||||
isLineNumbersDisplayed={isLineNumbersDisplayed}
|
||||
onEvaluate={() => {
|
||||
flash(view);
|
||||
activateCode();
|
||||
}}
|
||||
onStop={() => stop()}
|
||||
/>
|
||||
)}
|
||||
{error && <div className="text-right p-1 text-md text-red-200">{error.message}</div>}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
import { useLayoutEffect } from 'react';
|
||||
|
||||
// set active pattern on ctrl+enter
|
||||
const useKeydown = (callback) =>
|
||||
useLayoutEffect(() => {
|
||||
window.addEventListener('keydown', callback, true);
|
||||
return () => window.removeEventListener('keydown', callback, true);
|
||||
}, [callback]);
|
||||
|
||||
export default useKeydown;
|
||||
Reference in New Issue
Block a user