diff options
feat: da extension
Diffstat (limited to 'src/routes/Monaco.svelte')
-rw-r--r-- | src/routes/Monaco.svelte | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/src/routes/Monaco.svelte b/src/routes/Monaco.svelte new file mode 100644 index 0000000..efdd67a --- /dev/null +++ b/src/routes/Monaco.svelte @@ -0,0 +1,144 @@ +<script lang="ts"> + import type monaco from 'monaco-editor'; + import { onDestroy, onMount } from 'svelte'; + import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'; + import jsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker'; + import cssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker'; + import htmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker'; + import tsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker'; + // @ts-ignore + import wrqTypes from '@types/webextension-polyfill/namespaces/webRequest.d.ts?raw'; + // @ts-ignore + import evTypes from '@types/webextension-polyfill/namespaces/events.d.ts?raw'; + import userland from './userland.d.ts?raw'; + + let divEl: HTMLDivElement | null = $state(null); + let editor: monaco.editor.IStandaloneCodeEditor = $state(null as any); + let Monaco: typeof monaco; + let { + defaultValue = `processRequest = (rq) => rq; +processResponse = (rs) => rs; +`, + typeDefs = `import type { UserlandBrowser } from './userland'; +declare global { + /** + * The subset of the host extension's browser type available to the extension + * Note: We don't properly sandbox anything. You can likely easily get access to shit outside of here from the browser global. + */ + declare const browser: UserlandBrowser; +} +`, + value = $bindable(''), + }: { + value?: string; + defaultValue?: string; + typeDefs?: string; + } = $props(); + let writeDebounce = false; + + onMount(async () => { + // @ts-ignore + globalThis.MonacoEnvironment = { + getWorker: function (_moduleId: any, label: string) { + if (label === 'json') { + return new jsonWorker(); + } + if (label === 'css' || label === 'scss' || label === 'less') { + return new cssWorker(); + } + if (label === 'html' || label === 'handlebars' || label === 'razor') { + return new htmlWorker(); + } + if (label === 'typescript' || label === 'javascript') { + return new tsWorker(); + } + return new editorWorker(); + }, + }; + + Monaco = await import('monaco-editor'); + Monaco.languages.typescript.typescriptDefaults.setCompilerOptions({ + allowNonTsExtensions: true, + moduleResolution: Monaco.languages.typescript.ModuleResolutionKind.NodeJs, + module: Monaco.languages.typescript.ModuleKind.ESNext, + noEmit: true, + typeRoots: ['node_modules/@types'], + }); + Monaco.editor.defineTheme('redirext', { + base: 'vs-dark', + inherit: true, + rules: [], + colors: { + 'editor.foreground': '#dedede', + 'editor.background': '#23222b', + 'editor.selectionBackground': '#4c2889', + 'editor.inactiveSelectionBackground': '#444d56', + 'editor.lineHighlightBackground': '#444d56', + 'editorCursor.foreground': '#ffffff', + 'editorWhitespace.foreground': '#6a737d', + 'editorIndentGuide.background': '#6a737d', + 'editorIndentGuide.activeBackground': '#f6f8fa', + 'editor.selectionHighlightBorder': '#444d56', + }, + }); + if (!divEl) while (!divEl) await new Promise((rs) => setTimeout(rs, 100)); + Monaco.languages.typescript.typescriptDefaults.addExtraLib( + evTypes, + 'node_modules/@types/webextension-polyfill/namespaces/events.d.ts' + ); + Monaco.languages.typescript.typescriptDefaults.addExtraLib( + wrqTypes, + 'node_modules/@types/webextension-polyfill/namespaces/webRequest.d.ts' + ); + Monaco.languages.typescript.typescriptDefaults.addExtraLib( + `export * from './namespaces/webRequest';`, + 'node_modules/@types/webextension-polyfill/index.d.ts' + ); + Monaco.languages.typescript.typescriptDefaults.addExtraLib( + userland, + 'node_modules/@types/redirext/userland.d.ts' + ); + Monaco.languages.typescript.typescriptDefaults.addExtraLib( + typeDefs, + 'node_modules/@types/redirext/index.d.ts' + ); + editor = Monaco.editor.create(divEl, { + value: defaultValue, + language: 'typescript', + theme: 'redirext', + autoDetectHighContrast: false, + }); + editor.getModel()?.onDidChangeContent((e) => { + writeDebounce = true; + const upd = () => { + try { + value = + editor.getValue({ lineEnding: '\n', preserveBOM: false }).trim() + + '\n'; + // console.debug('Updated value from editor to:', value); + } catch (error) { + writeDebounce = false; + throw error; + } + setTimeout(() => { + writeDebounce = false; + }, 0); + }; + setTimeout(upd, 0); + }); + }); + $effect(() => { + if (editor && !writeDebounce) { + // console.debug('Updating editor with value', value); + editor.setValue(value.trim() + '\n'); + } + }); + onDestroy(() => { + if (editor) editor.dispose(); + }); +</script> + +<div + bind:this={divEl} + class="h-screen overflow-hidden bg-card box-border max-h-full" +></div> |