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/view": "^6.7.3",
"@lezer/highlight": "^1.1.3",
"@replit/codemirror-emacs": "^6.0.0",
"@replit/codemirror-vim": "^6.0.6",
"@strudel.cycles/core": "workspace:*",
"@strudel.cycles/transpiler": "workspace:*",

View File

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

View File

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

16
pnpm-lock.yaml generated
View File

@ -164,6 +164,7 @@ importers:
'@codemirror/state': ^6.2.0
'@codemirror/view': ^6.7.3
'@lezer/highlight': ^1.1.3
'@replit/codemirror-emacs': ^6.0.0
'@replit/codemirror-vim': ^6.0.6
'@strudel.cycles/core': workspace:*
'@strudel.cycles/transpiler': workspace:*
@ -186,6 +187,7 @@ importers:
'@codemirror/state': 6.2.0
'@codemirror/view': 6.7.3
'@lezer/highlight': 1.1.3
'@replit/codemirror-emacs': 6.0.0_cgfc5aojxuwjajwhkrgidrzxoa
'@replit/codemirror-vim': 6.0.6_a4vbhepr4qhxm5cldqd4jpyase
'@strudel.cycles/core': link:../core
'@strudel.cycles/transpiler': link:../transpiler
@ -3404,6 +3406,20 @@ packages:
tsm: 2.3.0
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:
resolution: {integrity: sha512-/Lc+5AmV+T5pTm5P+rWpL+gseNHNye7xaUWpULczHai5ZLVg/ZE3+MBwK3Ai+/SmZKR/mK2YuXgNKnTGToEGYg==}
peerDependencies:

View File

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

View File

@ -206,34 +206,107 @@ function SamplesTab() {
</div>
);
}
function SettingsTab() {
const { state, update } = useStore();
const { theme, vim } = state;
function ButtonGroup({ value, onChange, items }) {
return (
<div className="text-foreground grid space-y-4 p-2">
<label className="space-x-2">
<span>Theme</span>
<select
className="p-2 bg-background rounded-md text-foreground"
value={theme}
onChange={(e) => update((current) => ({ ...current, theme: e.target.value }))}
<div className="flex grow">
{Object.entries(items).map(([key, label], i, arr) => (
<button
key={key}
onClick={() => onChange(key)}
className={cx(
'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]) => (
<option key={k} className="bg-background">
{k}
</option>
))}
</select>
</label>
<label className="space-x-2">
<input
className="bg-background w-5 h-5 rounded-md"
type="checkbox"
checked={vim}
onChange={(e) => update((current) => ({ ...current, vim: e.target.checked }))}
/>
<span>Vim Mode</span>
</label>
{label}
</button>
))}
</div>
);
}
function SelectInput({ value, options, onChange }) {
return (
<select
className="p-2 bg-background rounded-md text-foreground"
value={value}
onChange={(e) => onChange(e.target.value)}
>
{Object.entries(options).map(([k, 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>
);
}

View File

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