From 3182d0e29801f8ca1c6d80273f97a7bc2a9692e4 Mon Sep 17 00:00:00 2001 From: Matthew Kaney Date: Tue, 14 May 2024 18:57:23 -0400 Subject: [PATCH] Overhaul settings system to support color schemes --- app/desktop/src/ipc.ts | 1 + app/desktop/src/main/index.ts | 17 +- app/desktop/src/preload/index.ts | 2 + app/desktop/src/renderer/main.ts | 10 ++ core/extensions/console/icons.tsx | 1 - core/extensions/console/style.css | 61 ++++--- core/extensions/layout/style.css | 14 +- core/extensions/settings/editor.ts | 9 +- core/extensions/theme/base.css | 35 +--- core/extensions/theme/colors/defaultDark.json | 7 + .../extensions/theme/colors/defaultLight.json | 7 + core/extensions/theme/colors/index.ts | 66 ++++++++ core/extensions/theme/colors/schema.ts | 27 +++ core/extensions/theme/settings.ts | 9 + core/extensions/theme/theme.ts | 159 +++++++++--------- core/extensions/toolbar/style.css | 10 +- core/state/index.ts | 65 +++++-- core/state/schema.ts | 73 -------- package-lock.json | 123 +++++++++++++- package.json | 6 +- packages/languages/tidal/ghci.ts | 11 +- 21 files changed, 457 insertions(+), 256 deletions(-) create mode 100644 core/extensions/theme/colors/defaultDark.json create mode 100644 core/extensions/theme/colors/defaultLight.json create mode 100644 core/extensions/theme/colors/index.ts create mode 100644 core/extensions/theme/colors/schema.ts create mode 100644 core/extensions/theme/settings.ts diff --git a/app/desktop/src/ipc.ts b/app/desktop/src/ipc.ts index ef2a49a..e0a8051 100644 --- a/app/desktop/src/ipc.ts +++ b/app/desktop/src/ipc.ts @@ -30,4 +30,5 @@ export interface ToRendererChannels { toggleConsole: undefined; showAbout: string; tidalHighlight: HighlightEvent; + settingsData: any; } diff --git a/app/desktop/src/main/index.ts b/app/desktop/src/main/index.ts index 544c812..8f3396b 100644 --- a/app/desktop/src/main/index.ts +++ b/app/desktop/src/main/index.ts @@ -12,9 +12,9 @@ import { dialog } from "electron"; // autoUpdater.checkForUpdatesAndNotify(); -import { StateManagement } from "@core/state"; +import { Config } from "@core/state"; -import { GHCI, TidalSettingsSchema } from "@management/lang-tidal"; +import { GHCI } from "@management/lang-tidal"; import { Filesystem } from "./filesystem"; import { wrapIPC } from "./ipcMain"; @@ -24,9 +24,7 @@ const filesystem = new Filesystem(); const settingsPath = resolve(app.getPath("userData"), "settings.json"); -const createWindow = ( - configuration: StateManagement -) => { +const createWindow = (configuration: Config) => { const tidal = new GHCI(configuration); const window = new BrowserWindow({ @@ -178,6 +176,13 @@ const createWindow = ( }) ); + send("settingsData", configuration.data); + listeners.push( + configuration.on("change", (data) => { + send("settingsData", data); + }) + ); + // For now, load a blank document on startup filesystem.loadDoc(); @@ -224,7 +229,7 @@ const createWindow = ( import { readFile } from "fs/promises"; app.whenReady().then(async () => { - const settings = new StateManagement(TidalSettingsSchema); + const settings = new Config(); // Try loading settings let settingsData = {}; diff --git a/app/desktop/src/preload/index.ts b/app/desktop/src/preload/index.ts index ff4c742..60cba35 100644 --- a/app/desktop/src/preload/index.ts +++ b/app/desktop/src/preload/index.ts @@ -89,6 +89,8 @@ const ElectronAPI = { onTidalNow: listen("tidalNow"), onTidalHighlight: listen("tidalHighlight"), + + onSettingsData: listen("settingsData"), }; contextBridge.exposeInMainWorld("api", ElectronAPI); diff --git a/app/desktop/src/renderer/main.ts b/app/desktop/src/renderer/main.ts index c43e581..da4004f 100644 --- a/app/desktop/src/renderer/main.ts +++ b/app/desktop/src/renderer/main.ts @@ -5,12 +5,14 @@ import { basicSetup } from "@core/extensions/basicSetup"; import { oneDark } from "@core/extensions/theme/theme"; import { tidal } from "@management/lang-tidal/editor"; +import { Config } from "@core/state"; import { settings } from "@core/extensions/settings/editor"; import { LayoutView } from "@core/extensions/layout"; import { console as electronConsole } from "@core/extensions/console"; // import { peer } from "@core/extensions/peer"; import { toolbarConstructor } from "@core/extensions/toolbar"; +import { ColorScheme } from "@core/extensions/theme/colors"; import { fileSync } from "./file"; import { EditorTabView } from "@core/extensions/layout/tabs/editor"; @@ -32,6 +34,14 @@ const { api } = window as Window & api: typeof ElectronAPI; }; +const configuration = new Config(); +api.onSettingsData((data) => { + configuration.update(data); +}); + +// Color scheme extension +const colorScheme = new ColorScheme(configuration); + const background: string | null = null; export class Editor { diff --git a/core/extensions/console/icons.tsx b/core/extensions/console/icons.tsx index 5a55649..a88a589 100644 --- a/core/extensions/console/icons.tsx +++ b/core/extensions/console/icons.tsx @@ -15,7 +15,6 @@ export function ErrorIcon() { } function Icon({ svgSource }: { svgSource: string }) { - console.log(svgSource); return (
; + + private styleTag = document.head.appendChild(document.createElement("style")); + + private lightStyleMod: string; + private darkStyleMod: string; + + constructor(configuration: Config) { + this.config = configuration.extend(ThemeSettingsSchema); + + this.config.on("change", () => { + this.update(); + }); + + this.lightStyleMod = this.buildStyleRule(defaultLight, "light"); + this.darkStyleMod = this.buildStyleRule(defaultDark, "dark"); + + this.update(); + } + + private update() { + let { "theme.customColors": customColors } = this.config.data; + customColors = customColors ?? {}; + + //TODO: Filter custom colors + + let customStyleMod = this.buildStyleRule( + customColors as { [name: string]: string } + ); + + this.styleTag.textContent = [ + this.lightStyleMod, + this.darkStyleMod, + customStyleMod, + ].join("\n"); + } + + private buildStyleRule( + colorSpec: { [name: string]: string }, + mode?: "light" | "dark" + ) { + let properties: string[] = []; + + for (let key in colorSpec) { + properties.push(`--color-${dashify(key)}: ${colorSpec[key]};`); + } + + let rule = `:root { ${properties.join(" ")} }`; + + if (mode) { + rule = `@media (prefers-color-scheme: ${mode}) { ${rule} }`; + } + + return rule; + } +} diff --git a/core/extensions/theme/colors/schema.ts b/core/extensions/theme/colors/schema.ts new file mode 100644 index 0000000..41ff718 --- /dev/null +++ b/core/extensions/theme/colors/schema.ts @@ -0,0 +1,27 @@ +import { JSONSchema } from "json-schema-to-ts"; + +const color = { + type: "string", + format: "color", +} as const; + +export const ThemeColorSchema = { + type: "object", + default: {}, + properties: { + background: { ...color, description: "General background color" }, + foreground: { ...color, description: "General foreground color" }, + focusBorder: { ...color, description: "Border color for focused elements" }, + errorBackground: { + ...color, + description: "General background color for errors", + }, + errorForeground: { + ...color, + description: "General foreground color for errors", + }, + "ui.background": color, + "ui.backgroundInactive": color, + "ui.backgroundActive": color, + }, +} as const satisfies JSONSchema; diff --git a/core/extensions/theme/settings.ts b/core/extensions/theme/settings.ts new file mode 100644 index 0000000..280c9ee --- /dev/null +++ b/core/extensions/theme/settings.ts @@ -0,0 +1,9 @@ +import { SettingsSchema } from "@core/state/schema"; + +import { ThemeColorSchema } from "./colors/schema"; + +export const ThemeSettingsSchema = { + properties: { + "theme.customColors": ThemeColorSchema, + }, +} as const satisfies SettingsSchema; diff --git a/core/extensions/theme/theme.ts b/core/extensions/theme/theme.ts index 16c382b..6283d66 100644 --- a/core/extensions/theme/theme.ts +++ b/core/extensions/theme/theme.ts @@ -5,14 +5,13 @@ import { tags as t } from "@lezer/highlight"; // Using https://github.com/one-dark/vscode-one-dark-theme/ as reference for the colors -const col = (name: string) => `var(--col-${name})`; +const col = (name: string) => `var(--color-${name})`; const coral = "#e06c75", ivory = "#abb2bf", stone = "#7d8799", // Brightened compared to original to increase contrast whiskey = "#d19a66", violet = "#c678dd", - darkBackground = "#21252b", highlightBackground = "#2c313a", selection = "#3E4451"; @@ -67,106 +66,110 @@ export const layoutTheme = EditorView.theme({ }); /// The editor theme styles for One Dark. -export const oneDarkTheme = EditorView.theme( - { - "&": { - color: col("text"), - "& ::selection": { backgroundColor: selection }, - caretColor: col("text"), - fontFamily: "inherit", - }, +export const oneDarkTheme = EditorView.theme({ + "&": { + color: col("foreground"), + "& ::selection": { backgroundColor: selection }, + caretColor: col("foreground"), + fontFamily: "inherit", + }, - ".cm-content": { padding: 0 }, + ".cm-content": { padding: 0 }, - "&.cm-editor.cm-focused": { outline: "none" }, - "&.cm-focused .cm-cursor": { - borderLeftColor: col("text"), - borderLeftWidth: "2px", - marginLeft: "-1px", - }, + "&.cm-editor.cm-focused": { outline: "none" }, + "&.cm-focused .cm-cursor": { + borderLeftColor: col("foreground"), + borderLeftWidth: "2px", + marginLeft: "-1px", + }, - "&.cm-tab-focus": { - boxShadow: "inset 0 0 0 4px orange", - }, + "&.cm-tab-focus": { + boxShadow: "inset 0 0 0 4px orange", + }, - "&.cm-focused .cm-selectionBackground, .cm-selectionBackground": { - backgroundColor: col("text-invert"), - }, + "&.cm-focused .cm-selectionBackground, .cm-selectionBackground": { + backgroundColor: col("text-invert"), + }, - "& .cm-scroller": { - fontFamily: "Fira Code, monospace", - lineHeight: "inherit", - }, + "& .cm-scroller": { + fontFamily: "Fira Code, monospace", + lineHeight: "inherit", + }, - ".cm-line": { - backgroundColor: col("bg-shadow"), - }, + ".cm-line": { + backgroundColor: col("ui-background"), + }, - ".cm-searchMatch": { - backgroundColor: "#72a1ff59", - outline: "1px solid #457dff", - }, - ".cm-searchMatch.cm-searchMatch-selected": { - backgroundColor: "#6199ff2f", - }, + ".cm-line.cm-activeLine": { + boxShadow: "0 0 2px --color-background", + }, + + ".cm-searchMatch": { + backgroundColor: "#72a1ff59", + outline: "1px solid #457dff", + }, + ".cm-searchMatch.cm-searchMatch-selected": { + backgroundColor: "#6199ff2f", + }, - ".cm-selectionMatch": { backgroundColor: "#aafe661a" }, + ".cm-selectionMatch": { backgroundColor: "#aafe661a" }, - "&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket": { - backgroundColor: col("text-2"), - color: col("text-invert"), - }, + "&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket": { + backgroundColor: col("text-2"), + color: col("text-invert"), + }, - ".cm-matchingBracket, .cm-nonmatchingBracket": { - backgroundColor: "transparent", - boxShadow: `inset 0 0 0 2px ${col("text-2")}`, - }, + ".cm-matchingBracket, .cm-nonmatchingBracket": { + backgroundColor: "transparent", + boxShadow: `inset 0 0 0 2px ${col("text-2")}`, + }, - ".cm-gutters": { - backgroundColor: col("bg-shadow"), - color: col("text"), - border: "none", - }, + ".cm-gutters": { + backgroundColor: col("ui-background"), + color: col("foreground"), + border: "none", + }, - ".cm-lineNumbers .cm-gutterElement": { - color: "inherit", - }, + ".cm-lineNumbers .cm-gutterElement": { + color: "inherit", + }, - ".cm-foldPlaceholder": { - backgroundColor: "transparent", - border: "none", - color: "#ddd", - }, + ".cm-foldPlaceholder": { + backgroundColor: "transparent", + border: "none", + color: "#ddd", + }, - ".cm-tooltip": { - border: "1px solid #181a1f", - backgroundColor: darkBackground, - }, - ".cm-tooltip-autocomplete": { - "& > ul > li[aria-selected]": { - backgroundColor: highlightBackground, - color: ivory, - }, + ".cm-tooltip": { + border: "1px solid #181a1f", + backgroundColor: col("background"), + }, + ".cm-tooltip-autocomplete": { + "& > ul > li[aria-selected]": { + backgroundColor: highlightBackground, + color: ivory, }, + }, - "*::-webkit-scrollbar-thumb": { - backgroundColor: col("bg-shadow"), - }, - "*::-webkit-scrollbar-corner": { - backgroundColor: "transparent", - }, + "*::-webkit-scrollbar-thumb": { + backgroundColor: col("ui-background-inactive"), + }, + "*::-webkit-scrollbar-thumb:hover": { + backgroundColor: col("ui-background"), }, - { dark: true } -); + "*::-webkit-scrollbar-corner": { + backgroundColor: "transparent", + }, +}); /// 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: col("text"), + color: col("foreground"), }, - { tag: [t.function(t.variableName), t.labelName], color: col("text") }, + { tag: [t.function(t.variableName), t.labelName], color: col("foreground") }, { tag: [t.color, t.constant(t.name), t.standard(t.name)], color: whiskey }, { tag: [t.definition(t.name), t.separator], color: ivory }, { diff --git a/core/extensions/toolbar/style.css b/core/extensions/toolbar/style.css index 8cc3666..f43ddab 100644 --- a/core/extensions/toolbar/style.css +++ b/core/extensions/toolbar/style.css @@ -4,7 +4,7 @@ display: flex; justify-content: flex-end; padding: 0 18px; - border-top: solid 2px var(--col-bg-shadow); + border-top: solid 2px var(--color-ui-background-inactive); line-height: 30px; margin-top: 18px; } @@ -24,7 +24,7 @@ } .cm-active-menu .cm-menu-item-list { - background-color: var(--col-bg); + background-color: var(--color-background); display: flex; flex-direction: column; position: absolute; @@ -33,7 +33,7 @@ } .cm-menu-item-group { - border: solid var(--col-bg-shadow); + border: solid var(--color-ui-background); border-width: 2px 2px 0; } @@ -45,7 +45,7 @@ line-height: inherit; margin-top: -2px; padding: 2px 6px 0; - background-color: var(--col-bg-shadow-soft); + background-color: var(--color-ui-background-inactive); clip-path: inset( var(--in-top, 0) var(--in-right, 0) var(--in-bottom, 0) var(--in-left, 0) ); @@ -68,7 +68,7 @@ /* .cm-menu-trigger:hover, .cm-active-menu .cm-menu-trigger, .cm-menu-item:hover { - background-color: var(--col-bg-shadow); + background-color: var(--color-ui-background); } */ .cm-menu-item { diff --git a/core/state/index.ts b/core/state/index.ts index ed61a01..fdaf8e8 100644 --- a/core/state/index.ts +++ b/core/state/index.ts @@ -1,32 +1,61 @@ -import { EventEmitter } from "@core/events"; +import { Draft, Draft2019 } from "json-schema-library"; -import { getDefaults, getValid } from "./schema"; +import { EventEmitter } from "@core/events"; import { SettingsSchema, FromSchema } from "./schema"; -interface StateEvents { - change: FromSchema; +interface ConfigEvents { + change: T; } -export class StateManagement extends EventEmitter< - StateEvents -> { - private defaults: FromSchema; - private data: Partial>; +export class Config extends EventEmitter> { + private _data: any = {}; - constructor(private schema: S, initial: any = {}) { - super(); - - this.defaults = getDefaults(schema); - this.data = getValid(schema, initial); + get data() { + return this._data; } update(data: any) { - this.data = getValid(this.schema, data); - this.emit("change", this.getData()); + this._data = data; + this.emit("change", data); + } + + extend>( + schema: S + ): ConfigExtension { + return new ConfigExtension(schema, this); + } +} + +export type { ConfigExtension }; + +class ConfigExtension< + S extends SettingsSchema, + D = FromSchema +> extends EventEmitter> { + private draft: Draft; + private _data: D; + + get data() { + return this._data; + } + + constructor(schema: S, private parent: Config) { + super(); + + this.draft = new Draft2019({ ...schema, type: "object" }); + + this._data = this.getTemplate(); + + this.parent.on("change", () => { + this._data = this.getTemplate(); + this.emit("change", this.data); + }); } - getData(): FromSchema { - return { ...this.defaults, ...this.data }; + private getTemplate() { + return this.draft.getTemplate(this.parent.data, undefined, { + addOptionalProps: false, + }); } } diff --git a/core/state/schema.ts b/core/state/schema.ts index 4a839a9..10dc850 100644 --- a/core/state/schema.ts +++ b/core/state/schema.ts @@ -8,76 +8,3 @@ export type FromSchema = FromJSONSchema< S & { type: "object" } > & object; - -export function getDefaults< - S extends SettingsSchema, - SchemaData = FromSchema ->(schema: S): SchemaData { - const defaults: any = {}; - - for (let key in schema.properties) { - let valueOptions = schema.properties[key]; - - switch (valueOptions.type) { - case "number": - defaults[key] = valueOptions.default ?? 0; - break; - case "string": - defaults[key] = valueOptions.default ?? ""; - break; - case "boolean": - defaults[key] = valueOptions.default ?? false; - break; - case "array": - defaults[key] = []; - break; - } - } - - return defaults; -} - -export function getValid>( - schema: S, - data: any -): Partial { - const validData: any = {}; - - function getValidPrimitive(schema: JSONSchema & object, value: any) { - if (schema.type === "number" && typeof value === "number") { - return value; - } else if (schema.type === "string" && typeof value === "string") { - return value; - } else if (schema.type === "boolean" && typeof value === "boolean") { - return value; - } - } - - if (typeof data === "object") { - for (let key in data) { - if (key in schema.properties) { - let prop = schema.properties[key]; - if ( - prop.type === "number" || - prop.type === "string" || - prop.type === "boolean" - ) { - const value = getValidPrimitive(prop, data[key]); - if (value !== undefined) { - validData[key] = value; - } - } else if (prop.type === "array" && typeof prop.items === "object") { - const value = data[key]; - if (Array.isArray(value)) { - const arraySchema = prop.items; - validData[key] = value.filter((v) => - getValidPrimitive(arraySchema, v) - ); - } - } - } - } - } - - return validData; -} diff --git a/package-lock.json b/package-lock.json index fd504b9..619d009 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,14 +29,18 @@ "clsx": "^2.1.1", "codemirror-json-schema": "^0.4.5", "commander": "^9.5.0", + "dashify": "^2.0.0", "firebase": "^9.23.0", + "json-schema-library": "^10.0.0-rc1", "json-schema-to-ts": "^3.1.0", - "nano-jsx": "^0.1.0" + "nano-jsx": "^0.1.0", + "style-mod": "^4.1.2" }, "devDependencies": { "@parcel/packager-ts": "^2.12.0", "@parcel/transformer-inline-string": "^2.12.0", "@parcel/transformer-typescript-types": "^2.12.0", + "@types/dashify": "^1.0.3", "@types/jest": "^29.5.12", "firebase-tools": "^12.9.1", "jest": "^29.7.0", @@ -5288,6 +5292,12 @@ "@types/responselike": "^1.0.0" } }, + "node_modules/@types/dashify": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/dashify/-/dashify-1.0.3.tgz", + "integrity": "sha512-5tFbcvWDPO1Il1Ck6Rtb4GJvD9m7HXzex50Z9wm2+YrUqN1Da3NDJnaipqtr2WlmtvOY2O/ftUrPECMKu+Bc+Q==", + "dev": true + }, "node_modules/@types/debug": { "version": "4.1.12", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", @@ -7299,6 +7309,19 @@ "@lezer/common": "^1.0.3" } }, + "node_modules/codemirror-json-schema/node_modules/json-schema-library": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/json-schema-library/-/json-schema-library-8.0.0.tgz", + "integrity": "sha512-qqsEdyhuA68YHzuWNGrOk9ViknRKw1NfIbhT9wQ0z6l5cpfuYoqKRkbu8tgHAXjahmLEkpNdGwHq+gCgIrMYeA==", + "dependencies": { + "@sagold/json-pointer": "^5.1.1", + "@sagold/json-query": "^6.1.0", + "deepmerge": "^4.3.1", + "fast-copy": "^3.0.1", + "fast-deep-equal": "^3.1.3", + "valid-url": "^1.0.9" + } + }, "node_modules/codemirror-json5": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/codemirror-json5/-/codemirror-json5-1.0.3.tgz", @@ -8085,6 +8108,14 @@ "node": ">=0.10" } }, + "node_modules/dashify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dashify/-/dashify-2.0.0.tgz", + "integrity": "sha512-hpA5C/YrPjucXypHPPc0oJ1l9Hf6wWbiOL7Ik42cxnsUOhWiCB/fylKbKqqJalW9FgkNQCw16YO8uW9Hs0Iy1A==", + "engines": { + "node": ">=4" + } + }, "node_modules/data-uri-to-buffer": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", @@ -8379,6 +8410,11 @@ "minimatch": "^3.0.4" } }, + "node_modules/discontinuous-range": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz", + "integrity": "sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ==" + }, "node_modules/dmg-builder": { "version": "24.13.3", "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-24.13.3.tgz", @@ -12461,18 +12497,24 @@ "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" }, "node_modules/json-schema-library": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/json-schema-library/-/json-schema-library-8.0.0.tgz", - "integrity": "sha512-qqsEdyhuA68YHzuWNGrOk9ViknRKw1NfIbhT9wQ0z6l5cpfuYoqKRkbu8tgHAXjahmLEkpNdGwHq+gCgIrMYeA==", + "version": "10.0.0-rc1", + "resolved": "https://registry.npmjs.org/json-schema-library/-/json-schema-library-10.0.0-rc1.tgz", + "integrity": "sha512-X2Xu91uzRfEOcw5SLxsr1Rhlgm87b/0PIhMUzp8NOn7d4BH2hTlOqxm2eF1QfXmvw30vKaWlg2vCihsdeLrYjA==", "dependencies": { - "@sagold/json-pointer": "^5.1.1", - "@sagold/json-query": "^6.1.0", + "@sagold/json-pointer": "^6.0.1", + "@sagold/json-query": "^6.1.3", "deepmerge": "^4.3.1", - "fast-copy": "^3.0.1", + "fast-copy": "^3.0.2", "fast-deep-equal": "^3.1.3", + "smtp-address-parser": "1.0.10", "valid-url": "^1.0.9" } }, + "node_modules/json-schema-library/node_modules/@sagold/json-pointer": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@sagold/json-pointer/-/json-pointer-6.0.1.tgz", + "integrity": "sha512-yDOl6ljS0gHSwfLhQH/6mVB2dpN5WnG8MXSjiyPJvukJkq4iu7XZEzovobBxBYvI/o04a6PjYGnHXh2F9jLRzg==" + }, "node_modules/json-schema-to-ts": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-3.1.0.tgz", @@ -13672,6 +13714,11 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/moo": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz", + "integrity": "sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==" + }, "node_modules/morgan": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", @@ -13778,6 +13825,32 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node_modules/nearley": { + "version": "2.20.1", + "resolved": "https://registry.npmjs.org/nearley/-/nearley-2.20.1.tgz", + "integrity": "sha512-+Mc8UaAebFzgV+KpI5n7DasuuQCHA89dmwm7JXw3TV43ukfNQ9DnBH3Mdb2g/I4Fdxc26pwimBWvjIw0UAILSQ==", + "dependencies": { + "commander": "^2.19.0", + "moo": "^0.5.0", + "railroad-diagrams": "^1.0.0", + "randexp": "0.4.6" + }, + "bin": { + "nearley-railroad": "bin/nearley-railroad.js", + "nearley-test": "bin/nearley-test.js", + "nearley-unparse": "bin/nearley-unparse.js", + "nearleyc": "bin/nearleyc.js" + }, + "funding": { + "type": "individual", + "url": "https://nearley.js.org/#give-to-nearley" + } + }, + "node_modules/nearley/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, "node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -15156,6 +15229,23 @@ "right-now": "^1.0.0" } }, + "node_modules/railroad-diagrams": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz", + "integrity": "sha512-cz93DjNeLY0idrCNOH6PviZGRN9GJhsdm9hpn1YCS879fj4W+x5IFJhhkRZcwVgMmFF7R82UA/7Oh+R8lLZg6A==" + }, + "node_modules/randexp": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/randexp/-/randexp-0.4.6.tgz", + "integrity": "sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==", + "dependencies": { + "discontinuous-range": "1.0.0", + "ret": "~0.1.10" + }, + "engines": { + "node": ">=0.12" + } + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -15589,6 +15679,14 @@ "node": ">=8" } }, + "node_modules/ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "engines": { + "node": ">=0.12" + } + }, "node_modules/retry": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", @@ -16102,6 +16200,17 @@ "npm": ">= 3.0.0" } }, + "node_modules/smtp-address-parser": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/smtp-address-parser/-/smtp-address-parser-1.0.10.tgz", + "integrity": "sha512-Osg9LmvGeAG/hyao4mldbflLOkkr3a+h4m1lwKCK5U8M6ZAr7tdXEz/+/vr752TSGE4MNUlUl9cIK2cB8cgzXg==", + "dependencies": { + "nearley": "^2.20.1" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/socks": { "version": "2.8.3", "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", diff --git a/package.json b/package.json index bb72408..de3acef 100644 --- a/package.json +++ b/package.json @@ -54,14 +54,18 @@ "clsx": "^2.1.1", "codemirror-json-schema": "^0.4.5", "commander": "^9.5.0", + "dashify": "^2.0.0", "firebase": "^9.23.0", + "json-schema-library": "^10.0.0-rc1", "json-schema-to-ts": "^3.1.0", - "nano-jsx": "^0.1.0" + "nano-jsx": "^0.1.0", + "style-mod": "^4.1.2" }, "devDependencies": { "@parcel/packager-ts": "^2.12.0", "@parcel/transformer-inline-string": "^2.12.0", "@parcel/transformer-typescript-types": "^2.12.0", + "@types/dashify": "^1.0.3", "@types/jest": "^29.5.12", "firebase-tools": "^12.9.1", "jest": "^29.7.0", diff --git a/packages/languages/tidal/ghci.ts b/packages/languages/tidal/ghci.ts index c1eb954..e4eced1 100644 --- a/packages/languages/tidal/ghci.ts +++ b/packages/languages/tidal/ghci.ts @@ -8,7 +8,7 @@ import { parse } from "@core/osc/osc"; import { Evaluation, Log } from "@core/api"; import { Engine } from "../core/engine"; -import { StateManagement } from "@core/state"; +import { Config, ConfigExtension } from "@core/state"; export { TidalSettingsSchema } from "./settings"; import { TidalSettingsSchema } from "./settings"; @@ -33,14 +33,18 @@ interface GHCIEvents { } export class GHCI extends Engine { + private settings: ConfigExtension; + private socket: Promise; private process: Promise; private history: (Evaluation | Log)[] = []; - constructor(private settings: StateManagement) { + constructor(settings: Config) { super(); + this.settings = settings.extend(TidalSettingsSchema); + this.settings.on("change", () => { this.reloadSettings; }); @@ -94,12 +98,11 @@ export class GHCI extends Engine { private wrapper: ProcessWrapper | null = null; private async initProcess() { - console.log(JSON.stringify(this.settings.getData())); const { "tidal.boot.disableEditorIntegration": disableEditorIntegration, "tidal.boot.useDefaultFile": useDefaultBootfile, "tidal.boot.customFiles": bootFiles, - } = this.settings.getData(); + } = this.settings.data; const port = (await this.socket).address().port.toString(); // this.outputFilters.push(