@pyscript/core 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core.js +3 -3
- package/dist/core.js.map +1 -1
- package/dist/py-terminal-_uJ8pDjX.js +2 -0
- package/dist/py-terminal-_uJ8pDjX.js.map +1 -0
- package/dist.zip +0 -0
- package/package.json +6 -4
- package/src/config.js +1 -1
- package/src/core.js +1 -3
- package/src/plugins/py-terminal.js +158 -0
- package/src/plugins.js +1 -0
- package/src/stdlib.js +12 -4
- package/types/core.d.ts +2 -1
- package/types/plugins/py-terminal.d.ts +2 -0
- package/types/plugins.d.ts +4 -3
@@ -0,0 +1,2 @@
|
|
1
|
+
import{TYPES as e,hooks as t}from"./core.js";const r="https://cdn.jsdelivr.net/npm/xterm",n="5.3.0",o=[...e.keys()].map((e=>`script[type="${e}"][terminal],${e}-script[terminal]`)).join(","),i=async()=>{const e=document.querySelectorAll(o);if(!e.length)return;e.length>1&&console.warn("Unable to satisfy multiple terminals"),s.disconnect();const[i]=e;if(i.matches('script[type="mpy"],mpy-script'))throw new Error("Unsupported terminal");document.querySelector(`link[href^="${r}"]`)||document.head.append(Object.assign(document.createElement("link"),{rel:"stylesheet",href:`${r}@${n}/css/xterm.min.css`}));const[{Terminal:d},{Readline:a}]=await Promise.all([import(`${r}@${n}/+esm`),import(`${r}-readline@1.1.1/+esm`)]),c=new a,l=e=>{let t=i;const r=i.getAttribute("target");if(r){if(t=document.getElementById(r)||document.querySelector(r),!t)throw new Error(`Unknown target ${r}`)}else t=document.createElement("py-terminal"),t.style.display="block",i.after(t);const n=new d({theme:{background:"#191A19",foreground:"#F5F2E7"},...e});n.loadAddon(c),n.open(t),n.focus()};if(i.hasAttribute("worker")){const e=({interpreter:e},{sync:t})=>{t.pyterminal_drop_hooks();const r=new TextDecoder,n={isatty:!0,write:e=>(t.pyterminal_write(r.decode(e)),e.length)};e.setStdout(n),e.setStderr(n)},r="\n import builtins\n from pyscript import sync as _sync\n\n builtins.input = lambda prompt: _sync.pyterminal_read(prompt)\n ",n="\n import code as _code\n _code.interact()\n ";t.main.onWorker.add((function o(i,s){t.main.onWorker.delete(o),l({disableStdin:!1,cursorBlink:!0,cursorStyle:"block"}),s.sync.pyterminal_read=c.read.bind(c),s.sync.pyterminal_write=c.write.bind(c),s.sync.pyterminal_drop_hooks=()=>{t.worker.onReady.delete(e),t.worker.codeBeforeRun.delete(r),t.worker.codeAfterRun.delete(n)}})),t.worker.onReady.add(e),t.worker.codeBeforeRun.add(r),t.worker.codeAfterRun.add(n)}else t.main.onReady.add((function e({io:r}){console.warn("py-terminal is read only on main thread"),t.main.onReady.delete(e),l({disableStdin:!0,cursorBlink:!1,cursorStyle:"underline"}),r.stdout=e=>{c.write(`${e}\n`)},r.stderr=e=>{c.write(`${e.message||e}\n`)}}))},s=new MutationObserver(i);s.observe(document,{childList:!0,subtree:!0});var d=i();export{d as default};
|
2
|
+
//# sourceMappingURL=py-terminal-_uJ8pDjX.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"py-terminal-_uJ8pDjX.js","sources":["../src/plugins/py-terminal.js"],"sourcesContent":["// PyScript py-terminal plugin\nimport { TYPES, hooks } from \"../core.js\";\n\nconst CDN = \"https://cdn.jsdelivr.net/npm/xterm\";\nconst XTERM = \"5.3.0\";\nconst XTERM_READLINE = \"1.1.1\";\nconst SELECTOR = [...TYPES.keys()]\n .map((type) => `script[type=\"${type}\"][terminal],${type}-script[terminal]`)\n .join(\",\");\n\nconst pyTerminal = async () => {\n const terminals = document.querySelectorAll(SELECTOR);\n\n // no results will look further for runtime nodes\n if (!terminals.length) return;\n\n // we currently support only one terminal as in \"classic\"\n if (terminals.length > 1)\n console.warn(\"Unable to satisfy multiple terminals\");\n\n // if we arrived this far, let's drop the MutationObserver\n mo.disconnect();\n\n const [element] = terminals;\n // hopefully to be removed in the near future!\n if (element.matches('script[type=\"mpy\"],mpy-script'))\n throw new Error(\"Unsupported terminal\");\n\n // import styles once and lazily (only on valid terminal)\n if (!document.querySelector(`link[href^=\"${CDN}\"]`)) {\n document.head.append(\n Object.assign(document.createElement(\"link\"), {\n rel: \"stylesheet\",\n href: `${CDN}@${XTERM}/css/xterm.min.css`,\n }),\n );\n }\n\n // lazy load these only when a valid terminal is found\n const [{ Terminal }, { Readline }] = await Promise.all([\n import(/* webpackIgnore: true */ `${CDN}@${XTERM}/+esm`),\n import(\n /* webpackIgnore: true */ `${CDN}-readline@${XTERM_READLINE}/+esm`\n ),\n ]);\n\n const readline = new Readline();\n\n // common main thread initialization for both worker\n // or main case, bootstrapping the terminal on its target\n const init = (options) => {\n let target = element;\n const selector = element.getAttribute(\"target\");\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(\"py-terminal\");\n target.style.display = \"block\";\n element.after(target);\n }\n const terminal = new Terminal({\n theme: {\n background: \"#191A19\",\n foreground: \"#F5F2E7\",\n },\n ...options,\n });\n terminal.loadAddon(readline);\n terminal.open(target);\n terminal.focus();\n };\n\n // branch logic for the worker\n if (element.hasAttribute(\"worker\")) {\n // when the remote thread onReady triggers:\n // setup the interpreter stdout and stderr\n const workerReady = ({ interpreter }, { sync }) => {\n sync.pyterminal_drop_hooks();\n const decoder = new TextDecoder();\n const generic = {\n isatty: true,\n write(buffer) {\n sync.pyterminal_write(decoder.decode(buffer));\n return buffer.length;\n },\n };\n interpreter.setStdout(generic);\n interpreter.setStderr(generic);\n };\n\n // run in python code able to replace builtins.input\n // using the xworker.sync non blocking prompt\n const codeBefore = `\n import builtins\n from pyscript import sync as _sync\n\n builtins.input = lambda prompt: _sync.pyterminal_read(prompt)\n `;\n\n // at the end of the code, make the terminal interactive\n const codeAfter = `\n import code as _code\n _code.interact()\n `;\n\n // add a hook on the main thread to setup all sync helpers\n // also bootstrapping the XTerm target on main\n hooks.main.onWorker.add(function worker(_, xworker) {\n hooks.main.onWorker.delete(worker);\n init({\n disableStdin: false,\n cursorBlink: true,\n cursorStyle: \"block\",\n });\n xworker.sync.pyterminal_read = readline.read.bind(readline);\n xworker.sync.pyterminal_write = readline.write.bind(readline);\n // allow a worker to drop main thread hooks ASAP\n xworker.sync.pyterminal_drop_hooks = () => {\n hooks.worker.onReady.delete(workerReady);\n hooks.worker.codeBeforeRun.delete(codeBefore);\n hooks.worker.codeAfterRun.delete(codeAfter);\n };\n });\n\n // setup remote thread JS/Python code for whenever the\n // worker is ready to become a terminal\n hooks.worker.onReady.add(workerReady);\n hooks.worker.codeBeforeRun.add(codeBefore);\n hooks.worker.codeAfterRun.add(codeAfter);\n } else {\n // in the main case, just bootstrap XTerm without\n // allowing any input as that's not possible / awkward\n hooks.main.onReady.add(function main({ io }) {\n console.warn(\"py-terminal is read only on main thread\");\n hooks.main.onReady.delete(main);\n init({\n disableStdin: true,\n cursorBlink: false,\n cursorStyle: \"underline\",\n });\n io.stdout = (value) => {\n readline.write(`${value}\\n`);\n };\n io.stderr = (error) => {\n readline.write(`${error.message || error}\\n`);\n };\n });\n }\n};\n\nconst mo = new MutationObserver(pyTerminal);\nmo.observe(document, { childList: true, subtree: true });\n\n// try to check the current document ASAP\nexport default pyTerminal();\n"],"names":["CDN","XTERM","SELECTOR","TYPES","keys","map","type","join","pyTerminal","async","terminals","document","querySelectorAll","length","console","warn","mo","disconnect","element","matches","Error","querySelector","head","append","Object","assign","createElement","rel","href","Terminal","Readline","Promise","all","import","readline","init","options","target","selector","getAttribute","getElementById","style","display","after","terminal","theme","background","foreground","loadAddon","open","focus","hasAttribute","workerReady","interpreter","sync","pyterminal_drop_hooks","decoder","TextDecoder","generic","isatty","write","buffer","pyterminal_write","decode","setStdout","setStderr","codeBefore","codeAfter","hooks","main","onWorker","add","worker","_","xworker","delete","disableStdin","cursorBlink","cursorStyle","pyterminal_read","read","bind","onReady","codeBeforeRun","codeAfterRun","io","stdout","value","stderr","error","message","MutationObserver","observe","childList","subtree","pyTerminal$1"],"mappings":"6CAGA,MAAMA,EAAM,qCACNC,EAAQ,QAERC,EAAW,IAAIC,EAAMC,QACtBC,KAAKC,GAAS,gBAAgBA,iBAAoBA,uBAClDC,KAAK,KAEJC,EAAaC,UACf,MAAMC,EAAYC,SAASC,iBAAiBV,GAG5C,IAAKQ,EAAUG,OAAQ,OAGnBH,EAAUG,OAAS,GACnBC,QAAQC,KAAK,wCAGjBC,EAAGC,aAEH,MAAOC,GAAWR,EAElB,GAAIQ,EAAQC,QAAQ,iCAChB,MAAM,IAAIC,MAAM,wBAGfT,SAASU,cAAc,eAAerB,QACvCW,SAASW,KAAKC,OACVC,OAAOC,OAAOd,SAASe,cAAc,QAAS,CAC1CC,IAAK,aACLC,KAAM,GAAG5B,KAAOC,yBAM5B,OAAO4B,SAAEA,IAAYC,SAAEA,UAAoBC,QAAQC,IAAI,CACnDC,OAAiC,GAAGjC,KAAOC,UAC3CgC,OAC8B,GAAGjC,2BAI/BkC,EAAW,IAAIJ,EAIfK,EAAQC,IACV,IAAIC,EAASnB,EACb,MAAMoB,EAAWpB,EAAQqB,aAAa,UACtC,GAAID,GAIA,GAHAD,EACI1B,SAAS6B,eAAeF,IACxB3B,SAASU,cAAciB,IACtBD,EAAQ,MAAM,IAAIjB,MAAM,kBAAkBkB,UAE/CD,EAAS1B,SAASe,cAAc,eAChCW,EAAOI,MAAMC,QAAU,QACvBxB,EAAQyB,MAAMN,GAElB,MAAMO,EAAW,IAAIf,EAAS,CAC1BgB,MAAO,CACHC,WAAY,UACZC,WAAY,cAEbX,IAEPQ,EAASI,UAAUd,GACnBU,EAASK,KAAKZ,GACdO,EAASM,OAAO,EAIpB,GAAIhC,EAAQiC,aAAa,UAAW,CAGhC,MAAMC,EAAc,EAAGC,gBAAiBC,WACpCA,EAAKC,wBACL,MAAMC,EAAU,IAAIC,YACdC,EAAU,CACZC,QAAQ,EACRC,MAAMC,IACFP,EAAKQ,iBAAiBN,EAAQO,OAAOF,IAC9BA,EAAOhD,SAGtBwC,EAAYW,UAAUN,GACtBL,EAAYY,UAAUP,EAAQ,EAK5BQ,EAAa,uKAQbC,EAAY,6EAOlBC,EAAMC,KAAKC,SAASC,KAAI,SAASC,EAAOC,EAAGC,GACvCN,EAAMC,KAAKC,SAASK,OAAOH,GAC3BrC,EAAK,CACDyC,cAAc,EACdC,aAAa,EACbC,YAAa,UAEjBJ,EAAQpB,KAAKyB,gBAAkB7C,EAAS8C,KAAKC,KAAK/C,GAClDwC,EAAQpB,KAAKQ,iBAAmB5B,EAAS0B,MAAMqB,KAAK/C,GAEpDwC,EAAQpB,KAAKC,sBAAwB,KACjCa,EAAMI,OAAOU,QAAQP,OAAOvB,GAC5BgB,EAAMI,OAAOW,cAAcR,OAAOT,GAClCE,EAAMI,OAAOY,aAAaT,OAAOR,EAAU,CAE3D,IAIQC,EAAMI,OAAOU,QAAQX,IAAInB,GACzBgB,EAAMI,OAAOW,cAAcZ,IAAIL,GAC/BE,EAAMI,OAAOY,aAAab,IAAIJ,EACtC,MAGQC,EAAMC,KAAKa,QAAQX,KAAI,SAASF,GAAKgB,GAAEA,IACnCvE,QAAQC,KAAK,2CACbqD,EAAMC,KAAKa,QAAQP,OAAON,GAC1BlC,EAAK,CACDyC,cAAc,EACdC,aAAa,EACbC,YAAa,cAEjBO,EAAGC,OAAUC,IACTrD,EAAS0B,MAAM,GAAG2B,MAAU,EAEhCF,EAAGG,OAAUC,IACTvD,EAAS0B,MAAM,GAAG6B,EAAMC,SAAWD,MAAU,CAE7D,GACK,EAGCzE,EAAK,IAAI2E,iBAAiBnF,GAChCQ,EAAG4E,QAAQjF,SAAU,CAAEkF,WAAW,EAAMC,SAAS,IAGjD,IAAAC,EAAevF"}
|
package/dist.zip
ADDED
Binary file
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@pyscript/core",
|
3
|
-
"version": "0.3.
|
3
|
+
"version": "0.3.2",
|
4
4
|
"type": "module",
|
5
5
|
"description": "PyScript",
|
6
6
|
"module": "./index.js",
|
@@ -20,11 +20,12 @@
|
|
20
20
|
},
|
21
21
|
"scripts": {
|
22
22
|
"server": "npx static-handler --coi .",
|
23
|
-
"build": "npm run build:toml && npm run build:stdlib && npm run build:plugins && npm run build:core && eslint src/ && npm run ts",
|
23
|
+
"build": "npm run build:toml && npm run build:stdlib && npm run build:plugins && npm run build:core && eslint src/ && npm run ts && npm run test:mpy",
|
24
24
|
"build:core": "rm -rf dist && rollup --config rollup/core.config.js",
|
25
25
|
"build:plugins": "node rollup/plugins.cjs",
|
26
26
|
"build:stdlib": "node rollup/stdlib.cjs",
|
27
27
|
"build:toml": "node rollup/toml.cjs",
|
28
|
+
"test:mpy": "static-handler --coi . 2>/dev/null & SH_PID=$!; EXIT_CODE=0; playwright test --fully-parallel test/ || EXIT_CODE=$?; kill $SH_PID 2>/dev/null; exit $EXIT_CODE",
|
28
29
|
"dev": "node dev.cjs",
|
29
30
|
"release": "npm run build && npm run zip",
|
30
31
|
"size": "echo -e \"\\033[1mdist/*.js file size\\033[0m\"; for js in $(ls dist/*.js); do echo -e \"\\033[2m$js:\\033[0m $(cat $js | brotli | wc -c) bytes\"; done",
|
@@ -40,18 +41,19 @@
|
|
40
41
|
"dependencies": {
|
41
42
|
"@ungap/with-resolvers": "^0.1.0",
|
42
43
|
"basic-devtools": "^0.1.6",
|
43
|
-
"polyscript": "^0.5.
|
44
|
+
"polyscript": "^0.5.6",
|
44
45
|
"sticky-module": "^0.1.0",
|
45
46
|
"to-json-callback": "^0.1.1",
|
46
47
|
"type-checked-collections": "^0.1.7"
|
47
48
|
},
|
48
49
|
"devDependencies": {
|
50
|
+
"@playwright/test": "^1.39.0",
|
49
51
|
"@rollup/plugin-node-resolve": "^15.2.3",
|
50
52
|
"@rollup/plugin-terser": "^0.4.4",
|
51
53
|
"@webreflection/toml-j0.4": "^1.1.3",
|
52
54
|
"chokidar": "^3.5.3",
|
53
55
|
"eslint": "^8.52.0",
|
54
|
-
"rollup": "^4.
|
56
|
+
"rollup": "^4.2.0",
|
55
57
|
"rollup-plugin-postcss": "^4.0.2",
|
56
58
|
"rollup-plugin-string": "^3.0.0",
|
57
59
|
"static-handler": "^0.4.3",
|
package/src/config.js
CHANGED
@@ -113,7 +113,7 @@ for (const [TYPE] of TYPES) {
|
|
113
113
|
value().then(({ notify }) => notify(error.message));
|
114
114
|
}
|
115
115
|
} else if (!parsed?.plugins?.includes(`!${key}`)) {
|
116
|
-
toBeAwaited.push(value());
|
116
|
+
toBeAwaited.push(value().then(({ default: p }) => p));
|
117
117
|
}
|
118
118
|
}
|
119
119
|
|
package/src/core.js
CHANGED
@@ -21,7 +21,6 @@ import "./all-done.js";
|
|
21
21
|
import TYPES from "./types.js";
|
22
22
|
import configs from "./config.js";
|
23
23
|
import sync from "./sync.js";
|
24
|
-
import stdlib from "./stdlib.js";
|
25
24
|
import bootstrapNodeAndPlugins from "./plugins-helper.js";
|
26
25
|
import { ErrorCode } from "./exceptions.js";
|
27
26
|
import { robustFetch as fetch, getText } from "./fetch.js";
|
@@ -52,8 +51,6 @@ const registerModule = ({ XWorker: $XWorker, interpreter, io }) => {
|
|
52
51
|
: currentElement.id;
|
53
52
|
},
|
54
53
|
});
|
55
|
-
|
56
|
-
interpreter.runPython(stdlib, { globals: interpreter.runPython("{}") });
|
57
54
|
};
|
58
55
|
|
59
56
|
// avoid multiple initialization of the same library
|
@@ -73,6 +70,7 @@ const [
|
|
73
70
|
});
|
74
71
|
|
75
72
|
export {
|
73
|
+
TYPES,
|
76
74
|
exportedPyWorker as PyWorker,
|
77
75
|
exportedHooks as hooks,
|
78
76
|
exportedConfig as config,
|
@@ -0,0 +1,158 @@
|
|
1
|
+
// PyScript py-terminal plugin
|
2
|
+
import { TYPES, hooks } from "../core.js";
|
3
|
+
|
4
|
+
const CDN = "https://cdn.jsdelivr.net/npm/xterm";
|
5
|
+
const XTERM = "5.3.0";
|
6
|
+
const XTERM_READLINE = "1.1.1";
|
7
|
+
const SELECTOR = [...TYPES.keys()]
|
8
|
+
.map((type) => `script[type="${type}"][terminal],${type}-script[terminal]`)
|
9
|
+
.join(",");
|
10
|
+
|
11
|
+
const pyTerminal = async () => {
|
12
|
+
const terminals = document.querySelectorAll(SELECTOR);
|
13
|
+
|
14
|
+
// no results will look further for runtime nodes
|
15
|
+
if (!terminals.length) return;
|
16
|
+
|
17
|
+
// we currently support only one terminal as in "classic"
|
18
|
+
if (terminals.length > 1)
|
19
|
+
console.warn("Unable to satisfy multiple terminals");
|
20
|
+
|
21
|
+
// if we arrived this far, let's drop the MutationObserver
|
22
|
+
mo.disconnect();
|
23
|
+
|
24
|
+
const [element] = terminals;
|
25
|
+
// hopefully to be removed in the near future!
|
26
|
+
if (element.matches('script[type="mpy"],mpy-script'))
|
27
|
+
throw new Error("Unsupported terminal");
|
28
|
+
|
29
|
+
// import styles once and lazily (only on valid terminal)
|
30
|
+
if (!document.querySelector(`link[href^="${CDN}"]`)) {
|
31
|
+
document.head.append(
|
32
|
+
Object.assign(document.createElement("link"), {
|
33
|
+
rel: "stylesheet",
|
34
|
+
href: `${CDN}@${XTERM}/css/xterm.min.css`,
|
35
|
+
}),
|
36
|
+
);
|
37
|
+
}
|
38
|
+
|
39
|
+
// lazy load these only when a valid terminal is found
|
40
|
+
const [{ Terminal }, { Readline }] = await Promise.all([
|
41
|
+
import(/* webpackIgnore: true */ `${CDN}@${XTERM}/+esm`),
|
42
|
+
import(
|
43
|
+
/* webpackIgnore: true */ `${CDN}-readline@${XTERM_READLINE}/+esm`
|
44
|
+
),
|
45
|
+
]);
|
46
|
+
|
47
|
+
const readline = new Readline();
|
48
|
+
|
49
|
+
// common main thread initialization for both worker
|
50
|
+
// or main case, bootstrapping the terminal on its target
|
51
|
+
const init = (options) => {
|
52
|
+
let target = element;
|
53
|
+
const selector = element.getAttribute("target");
|
54
|
+
if (selector) {
|
55
|
+
target =
|
56
|
+
document.getElementById(selector) ||
|
57
|
+
document.querySelector(selector);
|
58
|
+
if (!target) throw new Error(`Unknown target ${selector}`);
|
59
|
+
} else {
|
60
|
+
target = document.createElement("py-terminal");
|
61
|
+
target.style.display = "block";
|
62
|
+
element.after(target);
|
63
|
+
}
|
64
|
+
const terminal = new Terminal({
|
65
|
+
theme: {
|
66
|
+
background: "#191A19",
|
67
|
+
foreground: "#F5F2E7",
|
68
|
+
},
|
69
|
+
...options,
|
70
|
+
});
|
71
|
+
terminal.loadAddon(readline);
|
72
|
+
terminal.open(target);
|
73
|
+
terminal.focus();
|
74
|
+
};
|
75
|
+
|
76
|
+
// branch logic for the worker
|
77
|
+
if (element.hasAttribute("worker")) {
|
78
|
+
// when the remote thread onReady triggers:
|
79
|
+
// setup the interpreter stdout and stderr
|
80
|
+
const workerReady = ({ interpreter }, { sync }) => {
|
81
|
+
sync.pyterminal_drop_hooks();
|
82
|
+
const decoder = new TextDecoder();
|
83
|
+
const generic = {
|
84
|
+
isatty: true,
|
85
|
+
write(buffer) {
|
86
|
+
sync.pyterminal_write(decoder.decode(buffer));
|
87
|
+
return buffer.length;
|
88
|
+
},
|
89
|
+
};
|
90
|
+
interpreter.setStdout(generic);
|
91
|
+
interpreter.setStderr(generic);
|
92
|
+
};
|
93
|
+
|
94
|
+
// run in python code able to replace builtins.input
|
95
|
+
// using the xworker.sync non blocking prompt
|
96
|
+
const codeBefore = `
|
97
|
+
import builtins
|
98
|
+
from pyscript import sync as _sync
|
99
|
+
|
100
|
+
builtins.input = lambda prompt: _sync.pyterminal_read(prompt)
|
101
|
+
`;
|
102
|
+
|
103
|
+
// at the end of the code, make the terminal interactive
|
104
|
+
const codeAfter = `
|
105
|
+
import code as _code
|
106
|
+
_code.interact()
|
107
|
+
`;
|
108
|
+
|
109
|
+
// add a hook on the main thread to setup all sync helpers
|
110
|
+
// also bootstrapping the XTerm target on main
|
111
|
+
hooks.main.onWorker.add(function worker(_, xworker) {
|
112
|
+
hooks.main.onWorker.delete(worker);
|
113
|
+
init({
|
114
|
+
disableStdin: false,
|
115
|
+
cursorBlink: true,
|
116
|
+
cursorStyle: "block",
|
117
|
+
});
|
118
|
+
xworker.sync.pyterminal_read = readline.read.bind(readline);
|
119
|
+
xworker.sync.pyterminal_write = readline.write.bind(readline);
|
120
|
+
// allow a worker to drop main thread hooks ASAP
|
121
|
+
xworker.sync.pyterminal_drop_hooks = () => {
|
122
|
+
hooks.worker.onReady.delete(workerReady);
|
123
|
+
hooks.worker.codeBeforeRun.delete(codeBefore);
|
124
|
+
hooks.worker.codeAfterRun.delete(codeAfter);
|
125
|
+
};
|
126
|
+
});
|
127
|
+
|
128
|
+
// setup remote thread JS/Python code for whenever the
|
129
|
+
// worker is ready to become a terminal
|
130
|
+
hooks.worker.onReady.add(workerReady);
|
131
|
+
hooks.worker.codeBeforeRun.add(codeBefore);
|
132
|
+
hooks.worker.codeAfterRun.add(codeAfter);
|
133
|
+
} else {
|
134
|
+
// in the main case, just bootstrap XTerm without
|
135
|
+
// allowing any input as that's not possible / awkward
|
136
|
+
hooks.main.onReady.add(function main({ io }) {
|
137
|
+
console.warn("py-terminal is read only on main thread");
|
138
|
+
hooks.main.onReady.delete(main);
|
139
|
+
init({
|
140
|
+
disableStdin: true,
|
141
|
+
cursorBlink: false,
|
142
|
+
cursorStyle: "underline",
|
143
|
+
});
|
144
|
+
io.stdout = (value) => {
|
145
|
+
readline.write(`${value}\n`);
|
146
|
+
};
|
147
|
+
io.stderr = (error) => {
|
148
|
+
readline.write(`${error.message || error}\n`);
|
149
|
+
};
|
150
|
+
});
|
151
|
+
}
|
152
|
+
};
|
153
|
+
|
154
|
+
const mo = new MutationObserver(pyTerminal);
|
155
|
+
mo.observe(document, { childList: true, subtree: true });
|
156
|
+
|
157
|
+
// try to check the current document ASAP
|
158
|
+
export default pyTerminal();
|
package/src/plugins.js
CHANGED
package/src/stdlib.js
CHANGED
@@ -10,16 +10,22 @@ import pyscript from "./stdlib/pyscript.js";
|
|
10
10
|
|
11
11
|
const { entries } = Object;
|
12
12
|
|
13
|
-
const python = [
|
13
|
+
const python = [
|
14
|
+
"import os as _os",
|
15
|
+
"from pathlib import Path as _Path",
|
16
|
+
"_path = None",
|
17
|
+
];
|
14
18
|
|
15
19
|
const write = (base, literal) => {
|
16
20
|
for (const [key, value] of entries(literal)) {
|
17
|
-
|
21
|
+
python.push(`_path = _Path("${base}/${key}")`);
|
18
22
|
if (typeof value === "string") {
|
19
23
|
const code = JSON.stringify(value);
|
20
|
-
python.push(
|
24
|
+
python.push(`_path.write_text(${code})`);
|
21
25
|
} else {
|
22
|
-
|
26
|
+
// @see https://github.com/pyscript/pyscript/pull/1813#issuecomment-1781502909
|
27
|
+
python.push(`if not _os.path.exists("${base}/${key}"):`);
|
28
|
+
python.push(" _path.mkdir(parents=True, exist_ok=True)");
|
23
29
|
write(`${base}/${key}`, value);
|
24
30
|
}
|
25
31
|
}
|
@@ -28,6 +34,8 @@ const write = (base, literal) => {
|
|
28
34
|
write(".", pyscript);
|
29
35
|
|
30
36
|
python.push("del _Path");
|
37
|
+
python.push("del _path");
|
38
|
+
python.push("del _os");
|
31
39
|
python.push("\n");
|
32
40
|
|
33
41
|
export default python.join("\n");
|
package/types/core.d.ts
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
+
import TYPES from "./types.js";
|
1
2
|
declare const exportedPyWorker: any;
|
2
3
|
declare const exportedHooks: any;
|
3
4
|
declare const exportedConfig: any;
|
4
5
|
declare const exportedWhenDefined: any;
|
5
|
-
export { exportedPyWorker as PyWorker, exportedHooks as hooks, exportedConfig as config, exportedWhenDefined as whenDefined };
|
6
|
+
export { TYPES, exportedPyWorker as PyWorker, exportedHooks as hooks, exportedConfig as config, exportedWhenDefined as whenDefined };
|
package/types/plugins.d.ts
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
declare
|
2
|
-
|
3
|
-
|
1
|
+
declare const _default: {
|
2
|
+
error: () => Promise<typeof import("./plugins/error.js")>;
|
3
|
+
"py-terminal": () => Promise<typeof import("./plugins/py-terminal.js")>;
|
4
|
+
};
|
4
5
|
export default _default;
|