From 54a41f2431c3d60f5845a15447f13413299e41f2 Mon Sep 17 00:00:00 2001
From: memdmp <memdmp@estrogen.zone>
Date: Mon, 24 Feb 2025 01:09:00 +0100
Subject: feat: da extension

---
 src/routes/Monaco.svelte | 144 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 144 insertions(+)
 create mode 100644 src/routes/Monaco.svelte

(limited to 'src/routes/Monaco.svelte')

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>
-- 
cgit v1.2.3

