diff --git a/packages/codemirror/Autocomplete.jsx b/packages/codemirror/Autocomplete.jsx
new file mode 100644
index 00000000..18f172ee
--- /dev/null
+++ b/packages/codemirror/Autocomplete.jsx
@@ -0,0 +1,88 @@
+import { createRoot } from 'react-dom/client';
+import jsdoc from '../../doc.json';
+// import { javascriptLanguage } from '@codemirror/lang-javascript';
+import { autocompletion } from '@codemirror/autocomplete';
+
+const getDocLabel = (doc) => doc.name || doc.longname;
+const getInnerText = (html) => {
+ var div = document.createElement('div');
+ div.innerHTML = html;
+ return div.textContent || div.innerText || '';
+};
+
+export function Autocomplete({ doc }) {
+ return (
+
+
{getDocLabel(doc)}
+
+
+ {doc.params?.map(({ name, type, description }, i) => (
+ -
+ {name} : {type.names?.join(' | ')} {description ? <> - {getInnerText(description)}> : ''}
+
+ ))}
+
+
+ {doc.examples?.map((example, i) => (
+
+
{
+ console.log('ola!');
+ navigator.clipboard.writeText(example);
+ e.stopPropagation();
+ }}
+ >
+ {example}
+
+
+ ))}
+
+
+ );
+}
+
+const jsdocCompletions = jsdoc.docs
+ .filter(
+ (doc) =>
+ getDocLabel(doc) &&
+ !getDocLabel(doc).startsWith('_') &&
+ !['package'].includes(doc.kind) &&
+ !['superdirtOnly', 'noAutocomplete'].some((tag) => doc.tags?.find((t) => t.originalTitle === tag)),
+ )
+ // https://codemirror.net/docs/ref/#autocomplete.Completion
+ .map((doc) /*: Completion */ => ({
+ label: getDocLabel(doc),
+ // detail: 'xxx', // An optional short piece of information to show (with a different style) after the label.
+ info: () => {
+ const node = document.createElement('div');
+ // if Autocomplete is non-interactive, it could also be rendered at build time..
+ // .. using renderToStaticMarkup
+ createRoot(node).render();
+ return node;
+ },
+ type: 'function', // https://codemirror.net/docs/ref/#autocomplete.Completion.type
+ }));
+
+export const strudelAutocomplete = (context /* : CompletionContext */) => {
+ let word = context.matchBefore(/\w*/);
+ if (word.from == word.to && !context.explicit) return null;
+ return {
+ from: word.from,
+ options: jsdocCompletions,
+ /* options: [
+ { label: 'match', type: 'keyword' },
+ { label: 'hello', type: 'variable', info: '(World)' },
+ { label: 'magic', type: 'text', apply: '⠁⭒*.✩.*⭒⠁', detail: 'macro' },
+ ], */
+ };
+};
+
+export function isAutoCompletionEnabled(on) {
+ return on
+ ? [
+ autocompletion({ override: [strudelAutocomplete] }),
+ //javascriptLanguage.data.of({ autocomplete: strudelAutocomplete }),
+ ]
+ : []; // autocompletion({ override: [] })
+}
diff --git a/packages/codemirror/codemirror.mjs b/packages/codemirror/codemirror.mjs
index 2094416e..8c64372d 100644
--- a/packages/codemirror/codemirror.mjs
+++ b/packages/codemirror/codemirror.mjs
@@ -1,36 +1,78 @@
-import { defaultKeymap } from '@codemirror/commands';
+import { closeBrackets } from '@codemirror/autocomplete';
+// import { search, highlightSelectionMatches } from '@codemirror/search';
+import { history } from '@codemirror/commands';
import { javascript } from '@codemirror/lang-javascript';
import { defaultHighlightStyle, syntaxHighlighting } from '@codemirror/language';
-import { EditorState } from '@codemirror/state';
-import { EditorView, highlightActiveLineGutter, keymap, lineNumbers } from '@codemirror/view';
-import { Drawer, repl } from '@strudel.cycles/core';
-import { flashField, flash } from './flash.mjs';
-import { highlightExtension, highlightMiniLocations } from './highlight.mjs';
-import { oneDark } from './themes/one-dark';
+import { Compartment, EditorState } from '@codemirror/state';
+import { EditorView, highlightActiveLineGutter, highlightActiveLine, keymap, lineNumbers } from '@codemirror/view';
+import { Pattern, Drawer, repl, cleanupDraw } from '@strudel.cycles/core';
+import { isAutoCompletionEnabled } from './Autocomplete';
+import { flash, isFlashEnabled } from './flash.mjs';
+import { highlightMiniLocations, isPatternHighlightingEnabled, updateMiniLocations } from './highlight.mjs';
+import { keybindings } from './keybindings.mjs';
+import { theme } from './themes.mjs';
+import { updateWidgets, sliderPlugin } from './slider.mjs';
+
+const extensions = {
+ isLineWrappingEnabled: (on) => (on ? EditorView.lineWrapping : []),
+ isLineNumbersDisplayed: (on) => (on ? lineNumbers() : []),
+ theme,
+ isAutoCompletionEnabled,
+ isPatternHighlightingEnabled,
+ isFlashEnabled,
+ keybindings,
+};
+const compartments = Object.fromEntries(Object.keys(extensions).map((key) => [key, new Compartment()]));
// https://codemirror.net/docs/guide/
-export function initEditor({ initialCode = '', onChange, onEvaluate, onStop, theme = oneDark, root }) {
+export function initEditor({ initialCode = '', onChange, onEvaluate, onStop, settings, root }) {
+ const initialSettings = Object.keys(compartments).map((key) =>
+ compartments[key].of(extensions[key](parseBooleans(settings[key]))),
+ );
let state = EditorState.create({
doc: initialCode,
extensions: [
- theme,
+ /* search(),
+ highlightSelectionMatches(), */
+ ...initialSettings,
javascript(),
- lineNumbers(),
- highlightExtension,
+ sliderPlugin,
+ // indentOnInput(), // works without. already brought with javascript extension?
+ // bracketMatching(), // does not do anything
+ closeBrackets(),
highlightActiveLineGutter(),
+ highlightActiveLine(),
syntaxHighlighting(defaultHighlightStyle),
- keymap.of(defaultKeymap),
- flashField,
+ history(),
EditorView.updateListener.of((v) => onChange(v)),
keymap.of([
{
key: 'Ctrl-Enter',
- run: () => onEvaluate(),
+ run: () => onEvaluate?.(),
+ },
+ {
+ key: 'Alt-Enter',
+ run: () => onEvaluate?.(),
},
{
key: 'Ctrl-.',
- run: () => onStop(),
+ run: () => onStop?.(),
},
+ {
+ key: 'Alt-.',
+ run: (_, e) => {
+ e.preventDefault();
+ onStop?.();
+ },
+ },
+ /* {
+ key: 'Ctrl-Shift-.',
+ run: () => (onPanic ? onPanic() : onStop?.()),
+ },
+ {
+ key: 'Ctrl-Shift-Enter',
+ run: () => (onReEvaluate ? onReEvaluate() : onEvaluate?.()),
+ }, */
]),
],
});
@@ -43,71 +85,158 @@ export function initEditor({ initialCode = '', onChange, onEvaluate, onStop, the
export class StrudelMirror {
constructor(options) {
- const { root, initialCode = '', onDraw, drawTime = [-2, 2], prebake, ...replOptions } = options;
+ const { root, initialCode = '', onDraw, drawTime = [-2, 2], prebake, settings, ...replOptions } = options;
this.code = initialCode;
+ this.root = root;
+ this.miniLocations = [];
+ this.widgets = [];
+ this.painters = [];
+ this.onDraw = onDraw;
+ const self = this;
this.drawer = new Drawer((haps, time) => {
const currentFrame = haps.filter((hap) => time >= hap.whole.begin && time <= hap.endClipped);
this.highlight(currentFrame, time);
- onDraw?.(haps, time, currentFrame);
+ this.onDraw?.(haps, time, currentFrame, this.painters);
}, drawTime);
- const prebaked = prebake();
- prebaked.then(async () => {
- if (!onDraw) {
- return;
- }
- const { scheduler, evaluate } = await this.repl;
- // draw first frame instantly
- prebaked.then(async () => {
- await evaluate(this.code, false);
- this.drawer.invalidate(scheduler);
- onDraw?.(this.drawer.visibleHaps, 0, []);
- });
- });
+ // this approach might not work with multiple repls on screen..
+ Pattern.prototype.onPaint = function (onPaint) {
+ self.painters.push(onPaint);
+ return this;
+ };
+
+ this.prebaked = prebake();
+ // this.drawFirstFrame();
this.repl = repl({
...replOptions,
- onToggle: async (started) => {
+ onToggle: (started) => {
replOptions?.onToggle?.(started);
- const { scheduler } = await this.repl;
if (started) {
- this.drawer.start(scheduler);
+ this.drawer.start(this.repl.scheduler);
} else {
this.drawer.stop();
+ updateMiniLocations(this.editor, []);
+ cleanupDraw(false);
}
},
beforeEval: async () => {
- await prebaked;
+ cleanupDraw();
+ this.painters = [];
+ await this.prebaked;
+ await replOptions?.beforeEval?.();
},
afterEval: (options) => {
+ // remember for when highlighting is toggled on
+ this.miniLocations = options.meta?.miniLocations;
+ this.widgets = options.meta?.widgets;
+ updateWidgets(this.editor, this.widgets);
+ updateMiniLocations(this.editor, this.miniLocations);
replOptions?.afterEval?.(options);
this.drawer.invalidate();
},
});
this.editor = initEditor({
root,
+ settings,
initialCode,
onChange: (v) => {
- this.code = v.state.doc.toString();
+ if (v.docChanged) {
+ this.code = v.state.doc.toString();
+ this.repl.setCode(this.code);
+ }
},
onEvaluate: () => this.evaluate(),
onStop: () => this.stop(),
});
}
+ async drawFirstFrame() {
+ if (!this.onDraw) {
+ return;
+ }
+ // draw first frame instantly
+ await this.prebaked;
+ try {
+ await this.repl.evaluate(this.code, false);
+ this.drawer.invalidate(this.repl.scheduler);
+ this.onDraw?.(this.drawer.visibleHaps, 0, []);
+ } catch (err) {
+ console.warn('first frame could not be painted');
+ }
+ }
async evaluate() {
- const { evaluate } = await this.repl;
this.flash();
- await evaluate(this.code);
+ await this.repl.evaluate(this.code);
}
async stop() {
- const { scheduler } = await this.repl;
- scheduler.stop();
+ this.repl.scheduler.stop();
+ }
+ async toggle() {
+ if (this.repl.scheduler.started) {
+ this.repl.scheduler.stop();
+ } else {
+ this.evaluate();
+ }
}
flash(ms) {
flash(this.editor, ms);
}
highlight(haps, time) {
- highlightMiniLocations(this.editor.view, time, haps);
+ highlightMiniLocations(this.editor, time, haps);
+ }
+ setFontSize(size) {
+ this.root.style.fontSize = size + 'px';
+ }
+ setFontFamily(family) {
+ this.root.style.fontFamily = family;
+ }
+ reconfigureExtension(key, value) {
+ if (!extensions[key]) {
+ console.warn(`extension ${key} is not known`);
+ return;
+ }
+ value = parseBooleans(value);
+ const newValue = extensions[key](value, this);
+ this.editor.dispatch({
+ effects: compartments[key].reconfigure(newValue),
+ });
+ }
+ setLineWrappingEnabled(enabled) {
+ this.reconfigureExtension('isLineWrappingEnabled', enabled);
+ }
+ setLineNumbersDisplayed(enabled) {
+ this.reconfigureExtension('isLineNumbersDisplayed', enabled);
+ }
+ setTheme(theme) {
+ this.reconfigureExtension('theme', theme);
+ }
+ setAutocompletionEnabled(enabled) {
+ this.reconfigureExtension('isAutoCompletionEnabled', enabled);
+ }
+ updateSettings(settings) {
+ this.setFontSize(settings.fontSize);
+ this.setFontFamily(settings.fontFamily);
+ for (let key in extensions) {
+ this.reconfigureExtension(key, settings[key]);
+ }
+ }
+ changeSetting(key, value) {
+ if (extensions[key]) {
+ this.reconfigureExtension(key, value);
+ return;
+ } else if (key === 'fontFamily') {
+ this.setFontFamily(value);
+ } else if (key === 'fontSize') {
+ this.setFontSize(value);
+ }
+ }
+ setCode(code) {
+ const changes = { from: 0, to: this.editor.state.doc.length, insert: code };
+ this.editor.dispatch({ changes });
}
}
+
+function parseBooleans(value) {
+ return { true: true, false: false }[value] ?? value;
+}
diff --git a/packages/codemirror/flash.mjs b/packages/codemirror/flash.mjs
index 9bc5c593..6b37038f 100644
--- a/packages/codemirror/flash.mjs
+++ b/packages/codemirror/flash.mjs
@@ -33,3 +33,5 @@ export const flash = (view, ms = 200) => {
view.dispatch({ effects: setFlash.of(false) });
}, ms);
};
+
+export const isFlashEnabled = (on) => (on ? flashField : []);
diff --git a/packages/codemirror/highlight.mjs b/packages/codemirror/highlight.mjs
index 317c5fdf..79724f8f 100644
--- a/packages/codemirror/highlight.mjs
+++ b/packages/codemirror/highlight.mjs
@@ -124,3 +124,12 @@ const miniLocationHighlights = EditorView.decorations.compute([miniLocations, vi
});
export const highlightExtension = [miniLocations, visibleMiniLocations, miniLocationHighlights];
+
+export const isPatternHighlightingEnabled = (on, config) => {
+ on &&
+ config &&
+ setTimeout(() => {
+ updateMiniLocations(config.editor, config.miniLocations);
+ }, 100);
+ return on ? highlightExtension : [];
+};
diff --git a/packages/codemirror/keybindings.mjs b/packages/codemirror/keybindings.mjs
new file mode 100644
index 00000000..6fe00eda
--- /dev/null
+++ b/packages/codemirror/keybindings.mjs
@@ -0,0 +1,31 @@
+import { Prec } from '@codemirror/state';
+import { keymap, ViewPlugin } from '@codemirror/view';
+// import { searchKeymap } from '@codemirror/search';
+import { emacs } from '@replit/codemirror-emacs';
+import { vim } from '@replit/codemirror-vim';
+import { vscodeKeymap } from '@replit/codemirror-vscode-keymap';
+import { defaultKeymap, historyKeymap } from '@codemirror/commands';
+
+const vscodePlugin = ViewPlugin.fromClass(
+ class {
+ constructor() {}
+ },
+ {
+ provide: () => {
+ return Prec.highest(keymap.of([...vscodeKeymap]));
+ },
+ },
+);
+const vscodeExtension = (options) => [vscodePlugin].concat(options ?? []);
+
+const keymaps = {
+ vim,
+ emacs,
+ vscode: vscodeExtension,
+};
+
+export function keybindings(name) {
+ const active = keymaps[name];
+ return [keymap.of(defaultKeymap), keymap.of(historyKeymap), active ? active() : []];
+ // keymap.of(searchKeymap),
+}
diff --git a/packages/codemirror/package.json b/packages/codemirror/package.json
index 4e443648..a309efa2 100644
--- a/packages/codemirror/package.json
+++ b/packages/codemirror/package.json
@@ -33,13 +33,21 @@
},
"homepage": "https://github.com/tidalcycles/strudel#readme",
"dependencies": {
+ "@codemirror/autocomplete": "^6.6.0",
"@codemirror/commands": "^6.2.4",
"@codemirror/lang-javascript": "^6.1.7",
"@codemirror/language": "^6.6.0",
+ "@codemirror/search": "^6.0.0",
"@codemirror/state": "^6.2.0",
"@codemirror/view": "^6.10.0",
"@lezer/highlight": "^1.1.4",
- "@strudel.cycles/core": "workspace:*"
+ "@replit/codemirror-emacs": "^6.0.1",
+ "@replit/codemirror-vim": "^6.0.14",
+ "@replit/codemirror-vscode-keymap": "^6.0.2",
+ "@strudel.cycles/core": "workspace:*",
+ "@uiw/codemirror-themes": "^4.19.16",
+ "@uiw/codemirror-themes-all": "^4.19.16",
+ "react-dom": "^18.2.0"
},
"devDependencies": {
"vite": "^4.3.3"
diff --git a/packages/codemirror/themes.mjs b/packages/codemirror/themes.mjs
new file mode 100644
index 00000000..1f520623
--- /dev/null
+++ b/packages/codemirror/themes.mjs
@@ -0,0 +1,484 @@
+import {
+ abcdef,
+ androidstudio,
+ atomone,
+ aura,
+ bespin,
+ darcula,
+ dracula,
+ duotoneDark,
+ eclipse,
+ githubDark,
+ gruvboxDark,
+ materialDark,
+ nord,
+ okaidia,
+ solarizedDark,
+ sublime,
+ tokyoNight,
+ tokyoNightStorm,
+ vscodeDark,
+ xcodeDark,
+ bbedit,
+ duotoneLight,
+ githubLight,
+ gruvboxLight,
+ materialLight,
+ noctisLilac,
+ solarizedLight,
+ tokyoNightDay,
+ xcodeLight,
+} from '@uiw/codemirror-themes-all';
+
+import strudelTheme from './themes/strudel-theme';
+import bluescreen, { settings as bluescreenSettings } from './themes/bluescreen';
+import blackscreen, { settings as blackscreenSettings } from './themes/blackscreen';
+import whitescreen, { settings as whitescreenSettings } from './themes/whitescreen';
+import teletext, { settings as teletextSettings } from './themes/teletext';
+import algoboy, { settings as algoboySettings } from './themes/algoboy';
+import terminal, { settings as terminalSettings } from './themes/terminal';
+
+export const themes = {
+ strudelTheme,
+ bluescreen,
+ blackscreen,
+ whitescreen,
+ teletext,
+ algoboy,
+ terminal,
+ abcdef,
+ androidstudio,
+ atomone,
+ aura,
+ bespin,
+ darcula,
+ dracula,
+ duotoneDark,
+ eclipse,
+ githubDark,
+ gruvboxDark,
+ materialDark,
+ nord,
+ okaidia,
+ solarizedDark,
+ sublime,
+ tokyoNight,
+ tokyoNightStorm,
+ vscodeDark,
+ xcodeDark,
+ bbedit,
+ duotoneLight,
+ githubLight,
+ gruvboxLight,
+ materialLight,
+ noctisLilac,
+ solarizedLight,
+ tokyoNightDay,
+ xcodeLight,
+};
+
+// lineBackground is background with 50% opacity, to make sure the selection below is visible
+
+export const settings = {
+ strudelTheme: {
+ background: '#222',
+ lineBackground: '#22222299',
+ foreground: '#fff',
+ // foreground: '#75baff',
+ caret: '#ffcc00',
+ selection: 'rgba(128, 203, 196, 0.5)',
+ selectionMatch: '#036dd626',
+ // lineHighlight: '#8a91991a', // original
+ lineHighlight: '#00000050',
+ gutterBackground: 'transparent',
+ // gutterForeground: '#8a919966',
+ gutterForeground: '#8a919966',
+ },
+ bluescreen: bluescreenSettings,
+ blackscreen: blackscreenSettings,
+ whitescreen: whitescreenSettings,
+ teletext: teletextSettings,
+ algoboy: algoboySettings,
+ terminal: terminalSettings,
+ abcdef: {
+ background: '#0f0f0f',
+ lineBackground: '#0f0f0f99',
+ foreground: '#defdef',
+ caret: '#00FF00',
+ selection: '#515151',
+ selectionMatch: '#515151',
+ gutterBackground: '#555',
+ gutterForeground: '#FFFFFF',
+ lineHighlight: '#314151',
+ },
+ androidstudio: {
+ background: '#282b2e',
+ lineBackground: '#282b2e99',
+ foreground: '#a9b7c6',
+ caret: '#00FF00',
+ selection: '#343739',
+ selectionMatch: '#343739',
+ lineHighlight: '#343739',
+ },
+ atomone: {
+ background: '#272C35',
+ lineBackground: '#272C3599',
+ foreground: '#9d9b97',
+ caret: '#797977',
+ selection: '#ffffff30',
+ selectionMatch: '#2B323D',
+ gutterBackground: '#272C35',
+ gutterForeground: '#465063',
+ gutterBorder: 'transparent',
+ lineHighlight: '#2B323D',
+ },
+ aura: {
+ background: '#21202e',
+ lineBackground: '#21202e99',
+ foreground: '#edecee',
+ caret: '#a277ff',
+ selection: '#3d375e7f',
+ selectionMatch: '#3d375e7f',
+ gutterBackground: '#21202e',
+ gutterForeground: '#edecee',
+ gutterBorder: 'transparent',
+ lineHighlight: '#a394f033',
+ },
+ bbedit: {
+ light: true,
+ background: '#FFFFFF',
+ lineBackground: '#FFFFFF99',
+ foreground: '#000000',
+ caret: '#FBAC52',
+ selection: '#FFD420',
+ selectionMatch: '#FFD420',
+ gutterBackground: '#f5f5f5',
+ gutterForeground: '#4D4D4C',
+ gutterBorder: 'transparent',
+ lineHighlight: '#00000012',
+ },
+ bespin: {
+ background: '#28211c',
+ lineBackground: '#28211c99',
+ foreground: '#9d9b97',
+ caret: '#797977',
+ selection: '#36312e',
+ selectionMatch: '#4f382b',
+ gutterBackground: '#28211c',
+ gutterForeground: '#666666',
+ lineHighlight: 'rgba(255, 255, 255, 0.1)',
+ },
+ darcula: {
+ background: '#2B2B2B',
+ lineBackground: '#2B2B2B99',
+ foreground: '#f8f8f2',
+ caret: '#FFFFFF',
+ selection: 'rgba(255, 255, 255, 0.1)',
+ selectionMatch: 'rgba(255, 255, 255, 0.2)',
+ gutterBackground: 'rgba(255, 255, 255, 0.1)',
+ gutterForeground: '#999',
+ gutterBorder: 'transparent',
+ lineHighlight: 'rgba(255, 255, 255, 0.1)',
+ },
+ dracula: {
+ background: '#282a36',
+ lineBackground: '#282a3699',
+ foreground: '#f8f8f2',
+ caret: '#f8f8f0',
+ selection: 'rgba(255, 255, 255, 0.1)',
+ selectionMatch: 'rgba(255, 255, 255, 0.2)',
+ gutterBackground: '#282a36',
+ gutterForeground: '#6D8A88',
+ gutterBorder: 'transparent',
+ lineHighlight: 'rgba(255, 255, 255, 0.1)',
+ },
+ duotoneLight: {
+ light: true,
+ background: '#faf8f5',
+ lineBackground: '#faf8f599',
+ foreground: '#b29762',
+ caret: '#93abdc',
+ selection: '#e3dcce',
+ selectionMatch: '#e3dcce',
+ gutterBackground: '#faf8f5',
+ gutterForeground: '#cdc4b1',
+ gutterBorder: 'transparent',
+ lineHighlight: '#EFEFEF',
+ },
+ duotoneDark: {
+ background: '#2a2734',
+ lineBackground: '#2a273499',
+ foreground: '#6c6783',
+ caret: '#ffad5c',
+ selection: 'rgba(255, 255, 255, 0.1)',
+ gutterBackground: '#2a2734',
+ gutterForeground: '#545167',
+ lineHighlight: '#36334280',
+ },
+ eclipse: {
+ light: true,
+ background: '#fff',
+ lineBackground: '#ffffff99',
+ foreground: '#000',
+ caret: '#FFFFFF',
+ selection: '#d7d4f0',
+ selectionMatch: '#d7d4f0',
+ gutterBackground: '#f7f7f7',
+ gutterForeground: '#999',
+ lineHighlight: '#e8f2ff',
+ gutterBorder: 'transparent',
+ },
+ githubLight: {
+ light: true,
+ background: '#fff',
+ lineBackground: '#ffffff99',
+ foreground: '#24292e',
+ selection: '#BBDFFF',
+ selectionMatch: '#BBDFFF',
+ gutterBackground: '#fff',
+ gutterForeground: '#6e7781',
+ },
+ githubDark: {
+ background: '#0d1117',
+ lineBackground: '#0d111799',
+ foreground: '#c9d1d9',
+ caret: '#c9d1d9',
+ selection: '#003d73',
+ selectionMatch: '#003d73',
+ lineHighlight: '#36334280',
+ },
+ gruvboxDark: {
+ background: '#282828',
+ lineBackground: '#28282899',
+ foreground: '#ebdbb2',
+ caret: '#ebdbb2',
+ selection: '#bdae93',
+ selectionMatch: '#bdae93',
+ lineHighlight: '#3c3836',
+ gutterBackground: '#282828',
+ gutterForeground: '#7c6f64',
+ },
+ gruvboxLight: {
+ light: true,
+ background: '#fbf1c7',
+ lineBackground: '#fbf1c799',
+ foreground: '#3c3836',
+ caret: '#af3a03',
+ selection: '#ebdbb2',
+ selectionMatch: '#bdae93',
+ lineHighlight: '#ebdbb2',
+ gutterBackground: '#ebdbb2',
+ gutterForeground: '#665c54',
+ gutterBorder: 'transparent',
+ },
+ materialDark: {
+ background: '#2e3235',
+ lineBackground: '#2e323599',
+ foreground: '#bdbdbd',
+ caret: '#a0a4ae',
+ selection: '#d7d4f0',
+ selectionMatch: '#d7d4f0',
+ gutterBackground: '#2e3235',
+ gutterForeground: '#999',
+ gutterActiveForeground: '#4f5b66',
+ lineHighlight: '#545b61',
+ },
+ materialLight: {
+ light: true,
+ background: '#FAFAFA',
+ lineBackground: '#FAFAFA99',
+ foreground: '#90A4AE',
+ caret: '#272727',
+ selection: '#80CBC440',
+ selectionMatch: '#FAFAFA',
+ gutterBackground: '#FAFAFA',
+ gutterForeground: '#90A4AE',
+ gutterBorder: 'transparent',
+ lineHighlight: '#CCD7DA50',
+ },
+ noctisLilac: {
+ light: true,
+ background: '#f2f1f8',
+ lineBackground: '#f2f1f899',
+ foreground: '#0c006b',
+ caret: '#5c49e9',
+ selection: '#d5d1f2',
+ selectionMatch: '#d5d1f2',
+ gutterBackground: '#f2f1f8',
+ gutterForeground: '#0c006b70',
+ lineHighlight: '#e1def3',
+ },
+ nord: {
+ background: '#2e3440',
+ lineBackground: '#2e344099',
+ foreground: '#FFFFFF',
+ caret: '#FFFFFF',
+ selection: '#3b4252',
+ selectionMatch: '#e5e9f0',
+ gutterBackground: '#2e3440',
+ gutterForeground: '#4c566a',
+ gutterActiveForeground: '#d8dee9',
+ lineHighlight: '#4c566a',
+ },
+ okaidia: {
+ background: '#272822',
+ lineBackground: '#27282299',
+ foreground: '#FFFFFF',
+ caret: '#FFFFFF',
+ selection: '#49483E',
+ selectionMatch: '#49483E',
+ gutterBackground: '#272822',
+ gutterForeground: '#FFFFFF70',
+ lineHighlight: '#00000059',
+ },
+ solarizedLight: {
+ light: true,
+ background: '#fdf6e3',
+ lineBackground: '#fdf6e399',
+ foreground: '#657b83',
+ caret: '#586e75',
+ selection: '#dfd9c8',
+ selectionMatch: '#dfd9c8',
+ gutterBackground: '#00000010',
+ gutterForeground: '#657b83',
+ lineHighlight: '#dfd9c8',
+ },
+ solarizedDark: {
+ background: '#002b36',
+ lineBackground: '#002b3699',
+ foreground: '#93a1a1',
+ caret: '#839496',
+ selection: '#173541',
+ selectionMatch: '#aafe661a',
+ gutterBackground: '#00252f',
+ gutterForeground: '#839496',
+ lineHighlight: '#173541',
+ },
+ sublime: {
+ background: '#303841',
+ lineBackground: '#30384199',
+ foreground: '#FFFFFF',
+ caret: '#FBAC52',
+ selection: '#4C5964',
+ selectionMatch: '#3A546E',
+ gutterBackground: '#303841',
+ gutterForeground: '#FFFFFF70',
+ lineHighlight: '#00000059',
+ },
+ tokyoNightDay: {
+ light: true,
+ background: '#e1e2e7',
+ lineBackground: '#e1e2e799',
+ foreground: '#3760bf',
+ caret: '#3760bf',
+ selection: '#99a7df',
+ selectionMatch: '#99a7df',
+ gutterBackground: '#e1e2e7',
+ gutterForeground: '#3760bf',
+ gutterBorder: 'transparent',
+ lineHighlight: '#5f5faf11',
+ },
+ tokyoNightStorm: {
+ background: '#24283b',
+ lineBackground: '#24283b99',
+ foreground: '#7982a9',
+ caret: '#c0caf5',
+ selection: '#6f7bb630',
+ selectionMatch: '#1f2335',
+ gutterBackground: '#24283b',
+ gutterForeground: '#7982a9',
+ gutterBorder: 'transparent',
+ lineHighlight: '#292e42',
+ },
+ tokyoNight: {
+ background: '#1a1b26',
+ lineBackground: '#1a1b2699',
+ foreground: '#787c99',
+ caret: '#c0caf5',
+ selection: '#515c7e40',
+ selectionMatch: '#16161e',
+ gutterBackground: '#1a1b26',
+ gutterForeground: '#787c99',
+ gutterBorder: 'transparent',
+ lineHighlight: '#1e202e',
+ },
+ vscodeDark: {
+ background: '#1e1e1e',
+ lineBackground: '#1e1e1e99',
+ foreground: '#9cdcfe',
+ caret: '#c6c6c6',
+ selection: '#6199ff2f',
+ selectionMatch: '#72a1ff59',
+ lineHighlight: '#ffffff0f',
+ gutterBackground: '#1e1e1e',
+ gutterForeground: '#838383',
+ gutterActiveForeground: '#fff',
+ },
+ xcodeLight: {
+ light: true,
+ background: '#fff',
+ lineBackground: '#ffffff99',
+ foreground: '#3D3D3D',
+ selection: '#BBDFFF',
+ selectionMatch: '#BBDFFF',
+ gutterBackground: '#fff',
+ gutterForeground: '#AFAFAF',
+ lineHighlight: '#EDF4FF',
+ },
+ xcodeDark: {
+ background: '#292A30',
+ lineBackground: '#292A3099',
+ foreground: '#CECFD0',
+ caret: '#fff',
+ selection: '#727377',
+ selectionMatch: '#727377',
+ lineHighlight: '#2F3239',
+ },
+};
+
+function getColors(str) {
+ const colorRegex = /#([0-9A-Fa-f]{6}|[0-9A-Fa-f]{3})/g;
+ const colors = [];
+
+ let match;
+ while ((match = colorRegex.exec(str)) !== null) {
+ const color = match[0];
+ if (!colors.includes(color)) {
+ colors.push(color);
+ }
+ }
+
+ return colors;
+}
+
+// TODO: remove
+export function themeColors(theme) {
+ return getColors(stringifySafe(theme));
+}
+
+function getCircularReplacer() {
+ const seen = new WeakSet();
+ return (key, value) => {
+ if (typeof value === 'object' && value !== null) {
+ if (seen.has(value)) {
+ return;
+ }
+ seen.add(value);
+ }
+ return value;
+ };
+}
+
+function stringifySafe(json) {
+ return JSON.stringify(json, getCircularReplacer());
+}
+
+export function injectStyle(rule) {
+ const newStyle = document.createElement('style');
+ document.head.appendChild(newStyle);
+ const styleSheet = newStyle.sheet;
+ const ruleIndex = styleSheet.insertRule(rule, 0);
+ return () => styleSheet.deleteRule(ruleIndex);
+}
+
+export const theme = (theme) => themes[theme] || themes.strudelTheme;
diff --git a/packages/codemirror/themes/algoboy.mjs b/packages/codemirror/themes/algoboy.mjs
new file mode 100644
index 00000000..399370e1
--- /dev/null
+++ b/packages/codemirror/themes/algoboy.mjs
@@ -0,0 +1,41 @@
+import { tags as t } from '@lezer/highlight';
+import { createTheme } from '@uiw/codemirror-themes';
+export const settings = {
+ background: '#9bbc0f',
+ foreground: '#0f380f', // whats that?
+ caret: '#0f380f',
+ selection: '#306230',
+ selectionMatch: '#ffffff26',
+ lineHighlight: '#8bac0f',
+ lineBackground: '#9bbc0f50',
+ //lineBackground: 'transparent',
+ gutterBackground: 'transparent',
+ gutterForeground: '#0f380f',
+ light: true,
+ customStyle: '.cm-line { line-height: 1 }',
+};
+export default createTheme({
+ theme: 'light',
+ settings,
+ styles: [
+ { tag: t.keyword, color: '#0f380f' },
+ { tag: t.operator, color: '#0f380f' },
+ { tag: t.special(t.variableName), color: '#0f380f' },
+ { tag: t.typeName, color: '#0f380f' },
+ { tag: t.atom, color: '#0f380f' },
+ { tag: t.number, color: '#0f380f' },
+ { tag: t.definition(t.variableName), color: '#0f380f' },
+ { tag: t.string, color: '#0f380f' },
+ { tag: t.special(t.string), color: '#0f380f' },
+ { tag: t.comment, color: '#0f380f' },
+ { tag: t.variableName, color: '#0f380f' },
+ { tag: t.tagName, color: '#0f380f' },
+ { tag: t.bracket, color: '#0f380f' },
+ { tag: t.meta, color: '#0f380f' },
+ { tag: t.attributeName, color: '#0f380f' },
+ { tag: t.propertyName, color: '#0f380f' },
+ { tag: t.className, color: '#0f380f' },
+ { tag: t.invalid, color: '#0f380f' },
+ { tag: [t.unit, t.punctuation], color: '#0f380f' },
+ ],
+});
diff --git a/packages/codemirror/themes/blackscreen.mjs b/packages/codemirror/themes/blackscreen.mjs
new file mode 100644
index 00000000..135285a3
--- /dev/null
+++ b/packages/codemirror/themes/blackscreen.mjs
@@ -0,0 +1,38 @@
+import { tags as t } from '@lezer/highlight';
+import { createTheme } from '@uiw/codemirror-themes';
+export const settings = {
+ background: 'black',
+ foreground: 'white', // whats that?
+ caret: 'white',
+ selection: '#ffffff20',
+ selectionMatch: '#036dd626',
+ lineHighlight: '#ffffff10',
+ lineBackground: '#00000050',
+ gutterBackground: 'transparent',
+ gutterForeground: '#8a919966',
+};
+export default createTheme({
+ theme: 'dark',
+ settings,
+ styles: [
+ { tag: t.keyword, color: 'white' },
+ { tag: t.operator, color: 'white' },
+ { tag: t.special(t.variableName), color: 'white' },
+ { tag: t.typeName, color: 'white' },
+ { tag: t.atom, color: 'white' },
+ { tag: t.number, color: 'white' },
+ { tag: t.definition(t.variableName), color: 'white' },
+ { tag: t.string, color: 'white' },
+ { tag: t.special(t.string), color: 'white' },
+ { tag: t.comment, color: 'white' },
+ { tag: t.variableName, color: 'white' },
+ { tag: t.tagName, color: 'white' },
+ { tag: t.bracket, color: 'white' },
+ { tag: t.meta, color: 'white' },
+ { tag: t.attributeName, color: 'white' },
+ { tag: t.propertyName, color: 'white' },
+ { tag: t.className, color: 'white' },
+ { tag: t.invalid, color: 'white' },
+ { tag: [t.unit, t.punctuation], color: 'white' },
+ ],
+});
diff --git a/packages/codemirror/themes/bluescreen.mjs b/packages/codemirror/themes/bluescreen.mjs
new file mode 100644
index 00000000..aa6489d6
--- /dev/null
+++ b/packages/codemirror/themes/bluescreen.mjs
@@ -0,0 +1,41 @@
+import { tags as t } from '@lezer/highlight';
+import { createTheme } from '@uiw/codemirror-themes';
+export const settings = {
+ background: '#051DB5',
+ lineBackground: '#051DB550',
+ foreground: 'white', // whats that?
+ caret: 'white',
+ selection: 'rgba(128, 203, 196, 0.5)',
+ selectionMatch: '#036dd626',
+ // lineHighlight: '#8a91991a', // original
+ lineHighlight: '#00000050',
+ gutterBackground: 'transparent',
+ // gutterForeground: '#8a919966',
+ gutterForeground: '#8a919966',
+};
+
+export default createTheme({
+ theme: 'dark',
+ settings,
+ styles: [
+ { tag: t.keyword, color: 'white' },
+ { tag: t.operator, color: 'white' },
+ { tag: t.special(t.variableName), color: 'white' },
+ { tag: t.typeName, color: 'white' },
+ { tag: t.atom, color: 'white' },
+ { tag: t.number, color: 'white' },
+ { tag: t.definition(t.variableName), color: 'white' },
+ { tag: t.string, color: 'white' },
+ { tag: t.special(t.string), color: 'white' },
+ { tag: t.comment, color: 'white' },
+ { tag: t.variableName, color: 'white' },
+ { tag: t.tagName, color: 'white' },
+ { tag: t.bracket, color: 'white' },
+ { tag: t.meta, color: 'white' },
+ { tag: t.attributeName, color: 'white' },
+ { tag: t.propertyName, color: 'white' },
+ { tag: t.className, color: 'white' },
+ { tag: t.invalid, color: 'white' },
+ { tag: [t.unit, t.punctuation], color: 'white' },
+ ],
+});
diff --git a/packages/codemirror/themes/one-dark.mjs b/packages/codemirror/themes/one-dark.mjs
deleted file mode 100644
index cce83699..00000000
--- a/packages/codemirror/themes/one-dark.mjs
+++ /dev/null
@@ -1,139 +0,0 @@
-import { EditorView } from '@codemirror/view';
-import { HighlightStyle, syntaxHighlighting } from '@codemirror/language';
-import { tags as t } from '@lezer/highlight';
-
-// Using https://github.com/one-dark/vscode-one-dark-theme/ as reference for the colors
-
-const chalky = '#e5c07b',
- coral = '#e06c75',
- cyan = '#56b6c2',
- invalid = '#ffffff',
- ivory = '#abb2bf',
- stone = '#7d8799', // Brightened compared to original to increase contrast
- malibu = '#61afef',
- sage = '#98c379',
- whiskey = '#d19a66',
- violet = '#c678dd',
- darkBackground = '#21252b',
- highlightBackground = '#2c313a',
- background = '#282c34',
- tooltipBackground = '#353a42',
- selection = '#3E4451',
- cursor = '#528bff';
-
-/// The colors used in the theme, as CSS color strings.
-export const color = {
- chalky,
- coral,
- cyan,
- invalid,
- ivory,
- stone,
- malibu,
- sage,
- whiskey,
- violet,
- darkBackground,
- highlightBackground,
- background,
- tooltipBackground,
- selection,
- cursor,
-};
-
-/// The editor theme styles for One Dark.
-export const oneDarkTheme = EditorView.theme(
- {
- '&': {
- color: ivory,
- backgroundColor: background,
- },
-
- '.cm-content': {
- caretColor: cursor,
- },
-
- '.cm-cursor, .cm-dropCursor': { borderLeftColor: cursor },
- '&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection':
- { backgroundColor: selection },
-
- '.cm-panels': { backgroundColor: darkBackground, color: ivory },
- '.cm-panels.cm-panels-top': { borderBottom: '2px solid black' },
- '.cm-panels.cm-panels-bottom': { borderTop: '2px solid black' },
-
- '.cm-searchMatch': {
- backgroundColor: '#72a1ff59',
- outline: '1px solid #457dff',
- },
- '.cm-searchMatch.cm-searchMatch-selected': {
- backgroundColor: '#6199ff2f',
- },
-
- '.cm-activeLine': { backgroundColor: '#6699ff0b' },
- '.cm-selectionMatch': { backgroundColor: '#aafe661a' },
-
- '&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket': {
- backgroundColor: '#bad0f847',
- },
-
- '.cm-gutters': {
- backgroundColor: background,
- color: stone,
- border: 'none',
- },
-
- '.cm-activeLineGutter': {
- backgroundColor: highlightBackground,
- },
-
- '.cm-foldPlaceholder': {
- backgroundColor: 'transparent',
- border: 'none',
- color: '#ddd',
- },
-
- '.cm-tooltip': {
- border: 'none',
- backgroundColor: tooltipBackground,
- },
- '.cm-tooltip .cm-tooltip-arrow:before': {
- borderTopColor: 'transparent',
- borderBottomColor: 'transparent',
- },
- '.cm-tooltip .cm-tooltip-arrow:after': {
- borderTopColor: tooltipBackground,
- borderBottomColor: tooltipBackground,
- },
- '.cm-tooltip-autocomplete': {
- '& > ul > li[aria-selected]': {
- backgroundColor: highlightBackground,
- color: ivory,
- },
- },
- },
- { dark: true },
-);
-
-/// The highlighting style for code in the One Dark theme.
-export const oneDarkHighlightStyle = HighlightStyle.define([
- { tag: t.keyword, color: violet },
- { tag: [t.name, t.deleted, t.character, t.propertyName, t.macroName], color: coral },
- { tag: [t.function(t.variableName), t.labelName], color: malibu },
- { tag: [t.color, t.constant(t.name), t.standard(t.name)], color: whiskey },
- { tag: [t.definition(t.name), t.separator], color: ivory },
- { tag: [t.typeName, t.className, t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace], color: chalky },
- { tag: [t.operator, t.operatorKeyword, t.url, t.escape, t.regexp, t.link, t.special(t.string)], color: cyan },
- { tag: [t.meta, t.comment], color: stone },
- { tag: t.strong, fontWeight: 'bold' },
- { tag: t.emphasis, fontStyle: 'italic' },
- { tag: t.strikethrough, textDecoration: 'line-through' },
- { tag: t.link, color: stone, textDecoration: 'underline' },
- { tag: t.heading, fontWeight: 'bold', color: coral },
- { tag: [t.atom, t.bool, t.special(t.variableName)], color: whiskey },
- { tag: [t.processingInstruction, t.string, t.inserted], color: sage },
- { tag: t.invalid, color: invalid },
-]);
-
-/// Extension to enable the One Dark theme (both the editor theme and
-/// the highlight style).
-export const oneDark = [oneDarkTheme, syntaxHighlighting(oneDarkHighlightStyle)];
diff --git a/packages/codemirror/themes/strudel-theme.mjs b/packages/codemirror/themes/strudel-theme.mjs
new file mode 100644
index 00000000..4ae31060
--- /dev/null
+++ b/packages/codemirror/themes/strudel-theme.mjs
@@ -0,0 +1,45 @@
+import { tags as t } from '@lezer/highlight';
+import { createTheme } from '@uiw/codemirror-themes';
+export default createTheme({
+ theme: 'dark',
+ settings: {
+ background: '#222',
+ foreground: '#75baff', // whats that?
+ caret: '#ffcc00',
+ selection: 'rgba(128, 203, 196, 0.5)',
+ selectionMatch: '#036dd626',
+ // lineHighlight: '#8a91991a', // original
+ lineHighlight: '#00000050',
+ gutterBackground: 'transparent',
+ // gutterForeground: '#8a919966',
+ gutterForeground: '#8a919966',
+ },
+ styles: [
+ { tag: t.keyword, color: '#c792ea' },
+ { tag: t.operator, color: '#89ddff' },
+ { tag: t.special(t.variableName), color: '#eeffff' },
+ // { tag: t.typeName, color: '#f07178' }, // original
+ { tag: t.typeName, color: '#c3e88d' },
+ { tag: t.atom, color: '#f78c6c' },
+ // { tag: t.number, color: '#ff5370' }, // original
+ { tag: t.number, color: '#c3e88d' },
+ { tag: t.definition(t.variableName), color: '#82aaff' },
+ { tag: t.string, color: '#c3e88d' },
+ // { tag: t.special(t.string), color: '#f07178' }, // original
+ { tag: t.special(t.string), color: '#c3e88d' },
+ { tag: t.comment, color: '#7d8799' },
+ // { tag: t.variableName, color: '#f07178' }, // original
+ { tag: t.variableName, color: '#c792ea' },
+ // { tag: t.tagName, color: '#ff5370' }, // original
+ { tag: t.tagName, color: '#c3e88d' },
+ { tag: t.bracket, color: '#525154' },
+ // { tag: t.bracket, color: '#a2a1a4' }, // original
+ { tag: t.meta, color: '#ffcb6b' },
+ { tag: t.attributeName, color: '#c792ea' },
+ { tag: t.propertyName, color: '#c792ea' },
+
+ { tag: t.className, color: '#decb6b' },
+ { tag: t.invalid, color: '#ffffff' },
+ { tag: [t.unit, t.punctuation], color: '#82aaff' },
+ ],
+});
diff --git a/packages/codemirror/themes/teletext.mjs b/packages/codemirror/themes/teletext.mjs
new file mode 100644
index 00000000..5fd9a557
--- /dev/null
+++ b/packages/codemirror/themes/teletext.mjs
@@ -0,0 +1,50 @@
+import { tags as t } from '@lezer/highlight';
+import { createTheme } from '@uiw/codemirror-themes';
+
+let colorA = '#6edee4';
+//let colorB = 'magenta';
+let colorB = 'white';
+let colorC = 'red';
+let colorD = '#f8fc55';
+
+export const settings = {
+ background: '#000000',
+ foreground: colorA, // whats that?
+ caret: colorC,
+ selection: colorD,
+ selectionMatch: colorA,
+ lineHighlight: '#6edee440', // panel bg
+ lineBackground: '#00000040',
+ gutterBackground: 'transparent',
+ gutterForeground: '#8a919966',
+ customStyle: '.cm-line { line-height: 1 }',
+};
+
+let punctuation = colorD;
+let mini = colorB;
+
+export default createTheme({
+ theme: 'dark',
+ settings,
+ styles: [
+ { tag: t.keyword, color: colorA },
+ { tag: t.operator, color: mini },
+ { tag: t.special(t.variableName), color: colorA },
+ { tag: t.typeName, color: colorA },
+ { tag: t.atom, color: colorA },
+ { tag: t.number, color: mini },
+ { tag: t.definition(t.variableName), color: colorA },
+ { tag: t.string, color: mini },
+ { tag: t.special(t.string), color: mini },
+ { tag: t.comment, color: punctuation },
+ { tag: t.variableName, color: colorA },
+ { tag: t.tagName, color: colorA },
+ { tag: t.bracket, color: punctuation },
+ { tag: t.meta, color: colorA },
+ { tag: t.attributeName, color: colorA },
+ { tag: t.propertyName, color: colorA }, // methods
+ { tag: t.className, color: colorA },
+ { tag: t.invalid, color: colorC },
+ { tag: [t.unit, t.punctuation], color: punctuation },
+ ],
+});
diff --git a/packages/codemirror/themes/terminal.mjs b/packages/codemirror/themes/terminal.mjs
new file mode 100644
index 00000000..1374bb86
--- /dev/null
+++ b/packages/codemirror/themes/terminal.mjs
@@ -0,0 +1,36 @@
+import { tags as t } from '@lezer/highlight';
+import { createTheme } from '@uiw/codemirror-themes';
+export const settings = {
+ background: 'black',
+ foreground: '#41FF00', // whats that?
+ caret: '#41FF00',
+ selection: '#ffffff20',
+ selectionMatch: '#036dd626',
+ lineHighlight: '#ffffff10',
+ gutterBackground: 'transparent',
+ gutterForeground: '#8a919966',
+};
+export default createTheme({
+ theme: 'dark',
+ settings,
+ styles: [
+ { tag: t.keyword, color: '#41FF00' },
+ { tag: t.operator, color: '#41FF00' },
+ { tag: t.special(t.variableName), color: '#41FF00' },
+ { tag: t.typeName, color: '#41FF00' },
+ { tag: t.atom, color: '#41FF00' },
+ { tag: t.number, color: '#41FF00' },
+ { tag: t.definition(t.variableName), color: '#41FF00' },
+ { tag: t.string, color: '#41FF00' },
+ { tag: t.special(t.string), color: '#41FF00' },
+ { tag: t.comment, color: '#41FF00' },
+ { tag: t.variableName, color: '#41FF00' },
+ { tag: t.tagName, color: '#41FF00' },
+ { tag: t.bracket, color: '#41FF00' },
+ { tag: t.meta, color: '#41FF00' },
+ { tag: t.attributeName, color: '#41FF00' },
+ { tag: t.propertyName, color: '#41FF00' },
+ { tag: t.className, color: '#41FF00' },
+ { tag: t.invalid, color: '#41FF00' },
+ ],
+});
diff --git a/packages/codemirror/themes/whitescreen.mjs b/packages/codemirror/themes/whitescreen.mjs
new file mode 100644
index 00000000..22abad9e
--- /dev/null
+++ b/packages/codemirror/themes/whitescreen.mjs
@@ -0,0 +1,38 @@
+import { tags as t } from '@lezer/highlight';
+import { createTheme } from '@uiw/codemirror-themes';
+export const settings = {
+ background: 'white',
+ foreground: 'black', // whats that?
+ caret: 'black',
+ selection: 'rgba(128, 203, 196, 0.5)',
+ selectionMatch: '#ffffff26',
+ lineHighlight: '#cccccc50',
+ lineBackground: '#ffffff50',
+ gutterBackground: 'transparent',
+ gutterForeground: 'black',
+ light: true,
+};
+export default createTheme({
+ theme: 'light',
+ settings,
+ styles: [
+ { tag: t.keyword, color: 'black' },
+ { tag: t.operator, color: 'black' },
+ { tag: t.special(t.variableName), color: 'black' },
+ { tag: t.typeName, color: 'black' },
+ { tag: t.atom, color: 'black' },
+ { tag: t.number, color: 'black' },
+ { tag: t.definition(t.variableName), color: 'black' },
+ { tag: t.string, color: 'black' },
+ { tag: t.special(t.string), color: 'black' },
+ { tag: t.comment, color: 'black' },
+ { tag: t.variableName, color: 'black' },
+ { tag: t.tagName, color: 'black' },
+ { tag: t.bracket, color: 'black' },
+ { tag: t.meta, color: 'black' },
+ { tag: t.attributeName, color: 'black' },
+ { tag: t.propertyName, color: 'black' },
+ { tag: t.className, color: 'black' },
+ { tag: t.invalid, color: 'black' },
+ ],
+});
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 98f6441f..f6f446e1 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1,5 +1,9 @@
lockfileVersion: '6.0'
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
importers:
.:
@@ -71,6 +75,9 @@ importers:
packages/codemirror:
dependencies:
+ '@codemirror/autocomplete':
+ specifier: ^6.6.0
+ version: 6.6.0(@codemirror/language@6.6.0)(@codemirror/state@6.2.0)(@codemirror/view@6.10.0)(@lezer/common@1.0.2)
'@codemirror/commands':
specifier: ^6.2.4
version: 6.2.4
@@ -80,6 +87,9 @@ importers:
'@codemirror/language':
specifier: ^6.6.0
version: 6.6.0
+ '@codemirror/search':
+ specifier: ^6.0.0
+ version: 6.2.3
'@codemirror/state':
specifier: ^6.2.0
version: 6.2.0
@@ -89,9 +99,27 @@ importers:
'@lezer/highlight':
specifier: ^1.1.4
version: 1.1.4
+ '@replit/codemirror-emacs':
+ specifier: ^6.0.1
+ version: 6.0.1(@codemirror/autocomplete@6.6.0)(@codemirror/commands@6.2.4)(@codemirror/search@6.2.3)(@codemirror/state@6.2.0)(@codemirror/view@6.10.0)
+ '@replit/codemirror-vim':
+ specifier: ^6.0.14
+ version: 6.0.14(@codemirror/commands@6.2.4)(@codemirror/language@6.6.0)(@codemirror/search@6.2.3)(@codemirror/state@6.2.0)(@codemirror/view@6.10.0)
+ '@replit/codemirror-vscode-keymap':
+ specifier: ^6.0.2
+ version: 6.0.2(@codemirror/autocomplete@6.6.0)(@codemirror/commands@6.2.4)(@codemirror/language@6.6.0)(@codemirror/lint@6.1.0)(@codemirror/search@6.2.3)(@codemirror/state@6.2.0)(@codemirror/view@6.10.0)
'@strudel.cycles/core':
specifier: workspace:*
version: link:../core
+ '@uiw/codemirror-themes':
+ specifier: ^4.19.16
+ version: 4.19.16(@codemirror/language@6.6.0)(@codemirror/state@6.2.0)(@codemirror/view@6.10.0)
+ '@uiw/codemirror-themes-all':
+ specifier: ^4.19.16
+ version: 4.19.16(@codemirror/language@6.6.0)(@codemirror/state@6.2.0)(@codemirror/view@6.10.0)
+ react-dom:
+ specifier: ^18.2.0
+ version: 18.2.0(react@18.2.0)
devDependencies:
vite:
specifier: ^4.3.3
@@ -5572,6 +5600,7 @@ packages:
/b4a@1.6.4:
resolution: {integrity: sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==}
+ requiresBuild: true
optional: true
/babel-plugin-add-module-exports@0.2.1:
@@ -6154,6 +6183,7 @@ packages:
/color-string@1.9.1:
resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==}
+ requiresBuild: true
dependencies:
color-name: 1.1.4
simple-swizzle: 0.2.2
@@ -6166,6 +6196,7 @@ packages:
/color@4.2.3:
resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==}
engines: {node: '>=12.5.0'}
+ requiresBuild: true
dependencies:
color-convert: 2.0.1
color-string: 1.9.1
@@ -6629,6 +6660,7 @@ packages:
/detect-libc@2.0.2:
resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==}
engines: {node: '>=8'}
+ requiresBuild: true
optional: true
/detective-amd@4.0.1:
@@ -7472,6 +7504,7 @@ packages:
/fast-fifo@1.3.2:
resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==}
+ requiresBuild: true
optional: true
/fast-glob@3.2.12:
@@ -10579,6 +10612,7 @@ packages:
/node-addon-api@6.1.0:
resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==}
+ requiresBuild: true
optional: true
/node-domexception@1.0.0:
@@ -11875,6 +11909,7 @@ packages:
/queue-tick@1.0.1:
resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==}
+ requiresBuild: true
optional: true
/quick-lru@4.0.1:
@@ -12730,6 +12765,7 @@ packages:
/simple-swizzle@0.2.2:
resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
+ requiresBuild: true
dependencies:
is-arrayish: 0.3.2
optional: true
@@ -12943,6 +12979,7 @@ packages:
/streamx@2.15.2:
resolution: {integrity: sha512-b62pAV/aeMjUoRN2C/9F0n+G8AfcJjNC0zw/ZmOHeFsIe4m4GzjVW9m6VHXVjk536NbdU9JRwKMJRfkc+zUFTg==}
+ requiresBuild: true
dependencies:
fast-fifo: 1.3.2
queue-tick: 1.0.1
@@ -13220,6 +13257,7 @@ packages:
/tar-fs@3.0.4:
resolution: {integrity: sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==}
+ requiresBuild: true
dependencies:
mkdirp-classic: 0.5.3
pump: 3.0.0
@@ -13238,6 +13276,7 @@ packages:
/tar-stream@3.1.6:
resolution: {integrity: sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==}
+ requiresBuild: true
dependencies:
b4a: 1.6.4
fast-fifo: 1.3.2