{"version":3,"file":"py-editor-CmqzUo2Z.js","sources":["../src/plugins/py-editor.js"],"sourcesContent":["// PyScript py-editor plugin\nimport { Hook, XWorker, dedent, defineProperties } from \"polyscript/exports\";\nimport { TYPES, offline_interpreter, stdlib } from \"../core.js\";\n\nconst RUN_BUTTON = ``;\n\nlet id = 0;\nconst getID = (type) => `${type}-editor-${id++}`;\n\nconst envs = new Map();\nconst configs = new Map();\n\nconst hooks = {\n worker: {\n codeBeforeRun: () => stdlib,\n // works on both Pyodide and MicroPython\n onReady: ({ runAsync, io }, { sync }) => {\n io.stdout = io.buffered(sync.write);\n io.stderr = io.buffered(sync.writeErr);\n sync.revoke();\n sync.runAsync = runAsync;\n },\n },\n};\n\nasync function execute({ currentTarget }) {\n const { env, pySrc, outDiv } = this;\n const hasRunButton = !!currentTarget;\n\n if (hasRunButton) {\n currentTarget.disabled = true;\n outDiv.innerHTML = \"\";\n }\n\n if (!envs.has(env)) {\n const srcLink = URL.createObjectURL(new Blob([\"\"]));\n const details = { type: this.interpreter };\n const { config } = this;\n if (config) {\n details.configURL = config;\n const { parse } = config.endsWith(\".toml\")\n ? await import(/* webpackIgnore: true */ \"../3rd-party/toml.js\")\n : JSON;\n details.config = parse(await fetch(config).then((r) => r.text()));\n details.version = offline_interpreter(details.config);\n }\n else {\n details.config = {};\n }\n\n const xworker = XWorker.call(new Hook(null, hooks), srcLink, details);\n\n const { sync } = xworker;\n const { promise, resolve } = Promise.withResolvers();\n envs.set(env, promise);\n sync.revoke = () => {\n URL.revokeObjectURL(srcLink);\n resolve(xworker);\n };\n }\n\n // wait for the env then set the target div\n // before executing the current code\n return envs.get(env).then((xworker) => {\n xworker.onerror = ({ error }) => {\n if (hasRunButton) {\n outDiv.innerHTML += `${\n error.message || error\n }\\n`;\n }\n console.error(error);\n };\n\n const enable = () => {\n if (hasRunButton) currentTarget.disabled = false;\n };\n const { sync } = xworker;\n sync.write = (str) => {\n if (hasRunButton) outDiv.innerText += `${str}\\n`;\n };\n sync.writeErr = (str) => {\n if (hasRunButton) {\n outDiv.innerHTML += `${str}\\n`;\n }\n };\n sync.runAsync(pySrc).then(enable, enable);\n });\n}\n\nconst makeRunButton = (listener, type) => {\n const runButton = document.createElement(\"button\");\n runButton.className = `absolute ${type}-editor-run-button`;\n runButton.innerHTML = RUN_BUTTON;\n runButton.setAttribute(\"aria-label\", \"Python Script Run Button\");\n runButton.addEventListener(\"click\", listener);\n return runButton;\n};\n\nconst makeEditorDiv = (listener, type) => {\n const editorDiv = document.createElement(\"div\");\n editorDiv.className = `${type}-editor-input`;\n editorDiv.setAttribute(\"aria-label\", \"Python Script Area\");\n\n const runButton = makeRunButton(listener, type);\n const editorShadowContainer = document.createElement(\"div\");\n\n // avoid outer elements intercepting key events (reveal as example)\n editorShadowContainer.addEventListener(\"keydown\", (event) => {\n event.stopPropagation();\n });\n\n editorDiv.append(runButton, editorShadowContainer);\n\n return editorDiv;\n};\n\nconst makeOutDiv = (type) => {\n const outDiv = document.createElement(\"div\");\n outDiv.className = `${type}-editor-output`;\n outDiv.id = `${getID(type)}-output`;\n return outDiv;\n};\n\nconst makeBoxDiv = (listener, type) => {\n const boxDiv = document.createElement(\"div\");\n boxDiv.className = `${type}-editor-box`;\n\n const editorDiv = makeEditorDiv(listener, type);\n const outDiv = makeOutDiv(type);\n boxDiv.append(editorDiv, outDiv);\n\n return [boxDiv, outDiv];\n};\n\nconst init = async (script, type, interpreter) => {\n const [\n { basicSetup, EditorView },\n { Compartment },\n { python },\n { indentUnit },\n { keymap },\n { defaultKeymap },\n ] = await Promise.all([\n import(/* webpackIgnore: true */ \"../3rd-party/codemirror.js\"),\n import(/* webpackIgnore: true */ \"../3rd-party/codemirror_state.js\"),\n import(\n /* webpackIgnore: true */ \"../3rd-party/codemirror_lang-python.js\"\n ),\n import(/* webpackIgnore: true */ \"../3rd-party/codemirror_language.js\"),\n import(/* webpackIgnore: true */ \"../3rd-party/codemirror_view.js\"),\n import(/* webpackIgnore: true */ \"../3rd-party/codemirror_commands.js\"),\n ]);\n\n let isSetup = script.hasAttribute(\"setup\");\n const hasConfig = script.hasAttribute(\"config\");\n const env = `${interpreter}-${script.getAttribute(\"env\") || getID(type)}`;\n\n if (hasConfig && configs.has(env)) {\n throw new SyntaxError(\n configs.get(env)\n ? `duplicated config for env: ${env}`\n : `unable to add a config to the env: ${env}`,\n );\n }\n\n configs.set(env, hasConfig);\n\n let source = script.src\n ? await fetch(script.src).then((b) => b.text())\n : script.textContent;\n const context = {\n interpreter,\n env,\n config:\n hasConfig &&\n new URL(script.getAttribute(\"config\"), location.href).href,\n get pySrc() {\n return isSetup ? source : editor.state.doc.toString();\n },\n get outDiv() {\n return isSetup ? null : outDiv;\n },\n };\n\n let target;\n defineProperties(script, {\n target: { get: () => target },\n process: {\n /**\n * Simulate a setup node overriding the source to evaluate.\n * @param {string} code the Python code to evaluate.\n * @returns {Promise<...>} fulfill once code has been evaluated.\n */\n value(code) {\n const wasSetup = isSetup;\n const wasSource = source;\n isSetup = true;\n source = code;\n const restore = () => {\n isSetup = wasSetup;\n source = wasSource;\n };\n return execute\n .call(context, { currentTarget: null })\n .then(restore, restore);\n },\n },\n });\n\n const notify = () => {\n const event = new Event(`${type}-editor`, { bubbles: true });\n script.dispatchEvent(event);\n };\n\n if (isSetup) {\n await execute.call(context, { currentTarget: null });\n notify();\n return;\n }\n\n const selector = script.getAttribute(\"target\");\n\n if (selector) {\n target =\n document.getElementById(selector) ||\n document.querySelector(selector);\n if (!target) throw new Error(`Unknown target ${selector}`);\n } else {\n target = document.createElement(`${type}-editor`);\n target.style.display = \"block\";\n script.after(target);\n }\n\n if (!target.id) target.id = getID(type);\n if (!target.hasAttribute(\"exec-id\")) target.setAttribute(\"exec-id\", 0);\n if (!target.hasAttribute(\"root\")) target.setAttribute(\"root\", target.id);\n\n // @see https://github.com/JeffersGlass/mkdocs-pyscript/blob/main/mkdocs_pyscript/js/makeblocks.js\n const listener = execute.bind(context);\n const [boxDiv, outDiv] = makeBoxDiv(listener, type);\n boxDiv.dataset.env = script.hasAttribute(\"env\") ? env : interpreter;\n\n const inputChild = boxDiv.querySelector(`.${type}-editor-input > div`);\n const parent = inputChild.attachShadow({ mode: \"open\" });\n // avoid inheriting styles from the outer component\n parent.innerHTML = ``;\n\n target.appendChild(boxDiv);\n\n const doc = dedent(script.textContent).trim();\n\n // preserve user indentation, if any\n const indentation = /^(\\s+)/m.test(doc) ? RegExp.$1 : \" \";\n\n const editor = new EditorView({\n extensions: [\n indentUnit.of(indentation),\n new Compartment().of(python()),\n keymap.of([\n ...defaultKeymap,\n { key: \"Ctrl-Enter\", run: listener, preventDefault: true },\n { key: \"Cmd-Enter\", run: listener, preventDefault: true },\n { key: \"Shift-Enter\", run: listener, preventDefault: true },\n ]),\n basicSetup,\n ],\n parent,\n doc,\n });\n\n editor.focus();\n notify();\n};\n\n// avoid too greedy MutationObserver operations at distance\nlet timeout = 0;\n\n// avoid delayed initialization\nlet queue = Promise.resolve();\n\n// reset interval value then check for new scripts\nconst resetTimeout = () => {\n timeout = 0;\n pyEditor();\n};\n\n// triggered both ASAP on the living DOM and via MutationObserver later\nconst pyEditor = () => {\n if (timeout) return;\n timeout = setTimeout(resetTimeout, 250);\n for (const [type, interpreter] of TYPES) {\n const selector = `script[type=\"${type}-editor\"]`;\n for (const script of document.querySelectorAll(selector)) {\n // avoid any further bootstrap by changing the type as active\n script.type += \"-active\";\n // don't await in here or multiple calls might happen\n // while the first script is being initialized\n queue = queue.then(() => init(script, type, interpreter));\n }\n }\n return queue;\n};\n\nnew MutationObserver(pyEditor).observe(document, {\n childList: true,\n subtree: true,\n});\n\n// try to check the current document ASAP\nexport default pyEditor();\n"],"names":["id","getID","type","envs","Map","configs","hooks","worker","codeBeforeRun","stdlib","onReady","runAsync","io","sync","stdout","buffered","write","stderr","writeErr","revoke","async","execute","currentTarget","env","pySrc","outDiv","this","hasRunButton","disabled","innerHTML","has","srcLink","URL","createObjectURL","Blob","details","interpreter","config","configURL","parse","endsWith","import","JSON","fetch","then","r","text","version","offline_interpreter","xworker","XWorker","call","Hook","promise","resolve","Promise","withResolvers","set","revokeObjectURL","get","onerror","error","message","console","enable","str","innerText","makeEditorDiv","listener","editorDiv","document","createElement","className","setAttribute","runButton","addEventListener","makeRunButton","editorShadowContainer","event","stopPropagation","append","makeBoxDiv","boxDiv","makeOutDiv","init","script","basicSetup","EditorView","Compartment","python","indentUnit","keymap","defaultKeymap","all","n","x","q","isSetup","hasAttribute","hasConfig","getAttribute","SyntaxError","source","src","b","textContent","context","location","href","editor","state","doc","toString","target","defineProperties","process","value","code","wasSetup","wasSource","restore","notify","Event","bubbles","dispatchEvent","selector","getElementById","querySelector","Error","style","display","after","bind","dataset","parent","attachShadow","mode","appendChild","dedent","trim","indentation","test","RegExp","$1","extensions","of","key","run","preventDefault","focus","timeout","queue","resetTimeout","pyEditor","setTimeout","TYPES","querySelectorAll","MutationObserver","observe","childList","subtree","pyEditor$1"],"mappings":"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"}