add emacs mode + fontSize slider

This commit is contained in:
Felix Roos 2023-02-19 13:49:55 +01:00
parent 014555fe5d
commit ceb3aa0627
7 changed files with 143 additions and 34 deletions

View File

@ -37,6 +37,7 @@
"@codemirror/state": "^6.2.0", "@codemirror/state": "^6.2.0",
"@codemirror/view": "^6.7.3", "@codemirror/view": "^6.7.3",
"@lezer/highlight": "^1.1.3", "@lezer/highlight": "^1.1.3",
"@replit/codemirror-emacs": "^6.0.0",
"@replit/codemirror-vim": "^6.0.6", "@replit/codemirror-vim": "^6.0.6",
"@strudel.cycles/core": "workspace:*", "@strudel.cycles/core": "workspace:*",
"@strudel.cycles/transpiler": "workspace:*", "@strudel.cycles/transpiler": "workspace:*",

View File

@ -9,6 +9,7 @@ import { useCallback } from 'react';
import { autocompletion } from '@codemirror/autocomplete'; import { autocompletion } from '@codemirror/autocomplete';
import { strudelAutocomplete } from './Autocomplete'; import { strudelAutocomplete } from './Autocomplete';
import { vim } from '@replit/codemirror-vim'; import { vim } from '@replit/codemirror-vim';
import { emacs } from '@replit/codemirror-emacs';
export const setFlash = StateEffect.define(); export const setFlash = StateEffect.define();
const flashField = StateField.define({ const flashField = StateField.define({
@ -98,7 +99,8 @@ export default function CodeMirror({
onViewChanged, onViewChanged,
onSelectionChange, onSelectionChange,
theme, theme,
vimMode, keybindings,
fontSize = 18,
options, options,
editorDidMount, editorDidMount,
}) { }) {
@ -122,9 +124,18 @@ export default function CodeMirror({
}, },
[onSelectionChange], [onSelectionChange],
); );
const extensions = useMemo(() => [...staticExtensions, ...(vimMode ? [vim()] : [])], [vimMode]); const extensions = useMemo(() => {
let bindings = {
vim,
emacs,
};
if (bindings[keybindings]) {
return [...staticExtensions, bindings[keybindings]()];
}
return staticExtensions;
}, [keybindings]);
return ( return (
<> <div style={{ fontSize }} className="w-full">
<_CodeMirror <_CodeMirror
value={value} value={value}
theme={theme || strudelTheme} theme={theme || strudelTheme}
@ -133,7 +144,7 @@ export default function CodeMirror({
onUpdate={handleOnUpdate} onUpdate={handleOnUpdate}
extensions={extensions} extensions={extensions}
/> />
</> </div>
); );
} }

View File

@ -2,7 +2,6 @@
background-color: transparent !important; background-color: transparent !important;
height: 100%; height: 100%;
z-index: 11; z-index: 11;
font-size: 18px;
} }
.cm-theme { .cm-theme {

16
pnpm-lock.yaml generated
View File

@ -164,6 +164,7 @@ importers:
'@codemirror/state': ^6.2.0 '@codemirror/state': ^6.2.0
'@codemirror/view': ^6.7.3 '@codemirror/view': ^6.7.3
'@lezer/highlight': ^1.1.3 '@lezer/highlight': ^1.1.3
'@replit/codemirror-emacs': ^6.0.0
'@replit/codemirror-vim': ^6.0.6 '@replit/codemirror-vim': ^6.0.6
'@strudel.cycles/core': workspace:* '@strudel.cycles/core': workspace:*
'@strudel.cycles/transpiler': workspace:* '@strudel.cycles/transpiler': workspace:*
@ -186,6 +187,7 @@ importers:
'@codemirror/state': 6.2.0 '@codemirror/state': 6.2.0
'@codemirror/view': 6.7.3 '@codemirror/view': 6.7.3
'@lezer/highlight': 1.1.3 '@lezer/highlight': 1.1.3
'@replit/codemirror-emacs': 6.0.0_cgfc5aojxuwjajwhkrgidrzxoa
'@replit/codemirror-vim': 6.0.6_a4vbhepr4qhxm5cldqd4jpyase '@replit/codemirror-vim': 6.0.6_a4vbhepr4qhxm5cldqd4jpyase
'@strudel.cycles/core': link:../core '@strudel.cycles/core': link:../core
'@strudel.cycles/transpiler': link:../transpiler '@strudel.cycles/transpiler': link:../transpiler
@ -3404,6 +3406,20 @@ packages:
tsm: 2.3.0 tsm: 2.3.0
dev: false dev: false
/@replit/codemirror-emacs/6.0.0_cgfc5aojxuwjajwhkrgidrzxoa:
resolution: {integrity: sha512-zxSDg3UKm7811hjqNtgvK9G0IBtCWf82Idb9nZQo0ldmGl4d9SV7oCSuXQ58NmOG4AV7coD7kgFSZhEqHhyQhA==}
peerDependencies:
'@codemirror/autocomplete': ^6.0.2
'@codemirror/commands': ^6.0.0
'@codemirror/search': ^6.0.0
'@codemirror/state': ^6.0.1
'@codemirror/view': ^6.0.2
dependencies:
'@codemirror/autocomplete': 6.4.0_a4vbhepr4qhxm5cldqd4jpyase
'@codemirror/state': 6.2.0
'@codemirror/view': 6.7.3
dev: false
/@replit/codemirror-vim/6.0.6_a4vbhepr4qhxm5cldqd4jpyase: /@replit/codemirror-vim/6.0.6_a4vbhepr4qhxm5cldqd4jpyase:
resolution: {integrity: sha512-/Lc+5AmV+T5pTm5P+rWpL+gseNHNye7xaUWpULczHai5ZLVg/ZE3+MBwK3Ai+/SmZKR/mK2YuXgNKnTGToEGYg==} resolution: {integrity: sha512-/Lc+5AmV+T5pTm5P+rWpL+gseNHNye7xaUWpULczHai5ZLVg/ZE3+MBwK3Ai+/SmZKR/mK2YuXgNKnTGToEGYg==}
peerDependencies: peerDependencies:

View File

@ -1,7 +1,15 @@
export const storeKey = 'strudel-settings'; export const storeKey = 'strudel-settings';
const defaults = {
keybindings: 'codemirror',
theme: 'strudelTheme',
fontSize: 18,
};
export function get(prop) { export function get(prop) {
const state = JSON.parse(localStorage.getItem(storeKey)); let state = {
...defaults,
...JSON.parse(localStorage.getItem(storeKey) || '{}'),
};
if (!prop) { if (!prop) {
return state; return state;
} }

View File

@ -206,34 +206,107 @@ function SamplesTab() {
</div> </div>
); );
} }
function SettingsTab() {
const { state, update } = useStore(); function ButtonGroup({ value, onChange, items }) {
const { theme, vim } = state;
return ( return (
<div className="text-foreground grid space-y-4 p-2"> <div className="flex grow">
<label className="space-x-2"> {Object.entries(items).map(([key, label], i, arr) => (
<span>Theme</span> <button
<select key={key}
className="p-2 bg-background rounded-md text-foreground" onClick={() => onChange(key)}
value={theme} className={cx(
onChange={(e) => update((current) => ({ ...current, theme: e.target.value }))} 'p-2 grow',
i === 0 && 'rounded-l-md',
i === arr.length - 1 && 'rounded-r-md',
value === key ? 'bg-background' : 'bg-lineHighlight',
)}
> >
{Object.entries(themes).map(([k, t]) => ( {label}
<option key={k} className="bg-background"> </button>
{k} ))}
</option> </div>
))} );
</select> }
</label>
<label className="space-x-2"> function SelectInput({ value, options, onChange }) {
<input return (
className="bg-background w-5 h-5 rounded-md" <select
type="checkbox" className="p-2 bg-background rounded-md text-foreground"
checked={vim} value={value}
onChange={(e) => update((current) => ({ ...current, vim: e.target.checked }))} onChange={(e) => onChange(e.target.value)}
/> >
<span>Vim Mode</span> {Object.entries(options).map(([k, label]) => (
</label> <option key={k} className="bg-background" value={k}>
{label}
</option>
))}
</select>
);
}
function NumberSlider({ value, onChange, step = 1, ...rest }) {
return (
<div className="flex space-x-2 gap-1">
<input
className="p-2 grow"
type="range"
value={value}
step={step}
onChange={(e) => onChange(Number(e.target.value))}
{...rest}
/>
<input
type="number"
value={value}
step={step}
className="w-16 bg-background rounded-md"
onChange={(e) => onChange(Number(e.target.value))}
/>
</div>
);
}
function FormItem({ label, children }) {
return (
<div className="grid gap-2">
<label>{label}</label>
{children}
</div>
);
}
const themeOptions = Object.fromEntries(Object.keys(themes).map((k) => [k, k]));
function SettingsTab() {
const { state, update } = useStore();
const { theme, keybindings, fontSize } = state;
return (
<div className="text-foreground p-4 space-y-4">
<div className="grid grid-cols-2 gap-2">
<FormItem label="Theme">
<SelectInput
options={themeOptions}
value={theme}
onChange={(theme) => update((current) => ({ ...current, theme }))}
/>
</FormItem>
<FormItem label="Font Size">
<NumberSlider
value={fontSize}
onChange={(fontSize) => update((current) => ({ ...current, fontSize }))}
min={10}
max={40}
step={2}
/>
</FormItem>
</div>
<FormItem label="Keybindings">
<ButtonGroup
value={keybindings}
onChange={(keybindings) => update((current) => ({ ...current, keybindings }))}
items={{ codemirror: 'Codemirror', vim: 'Vim', emacs: 'Emacs' }}
></ButtonGroup>
</FormItem>
</div> </div>
); );
} }

View File

@ -121,7 +121,7 @@ export function Repl({ embedded = false }) {
const { theme, themeSettings } = useTheme(); const { theme, themeSettings } = useTheme();
const { const {
state: { vim }, state: { keybindings, fontSize },
} = useStore(); } = useStore();
const { code, setCode, scheduler, evaluate, activateCode, isDirty, activeCode, pattern, started, stop, error } = const { code, setCode, scheduler, evaluate, activateCode, isDirty, activeCode, pattern, started, stop, error } =
@ -282,7 +282,8 @@ export function Repl({ embedded = false }) {
<CodeMirror <CodeMirror
theme={themes[theme] || themes.strudelTheme} theme={themes[theme] || themes.strudelTheme}
value={code} value={code}
vimMode={vim} keybindings={keybindings}
fontSize={fontSize}
onChange={handleChangeCode} onChange={handleChangeCode}
onViewChanged={setView} onViewChanged={setView}
onSelectionChange={handleSelectionChange} onSelectionChange={handleSelectionChange}