Skip to content

Commit 38f309f

Browse files
committed
feat: support & add python demo
1 parent e28a6f2 commit 38f309f

File tree

7 files changed

+164
-54
lines changed

7 files changed

+164
-54
lines changed

README.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@ Visit: https://coldemo.github.io/
66

77
- [ ] vscode tsconfig src/\* alias (being reverted by npm-run-dev)
88
- [ ] antd4, safe js exec sandbox - see pureproxy
9-
- [ ] lang ts/tsx/vue/py/rb/java
10-
- [ ] storage list, reset btn, responsive, screenshot
11-
- [ ] faked location/window, vue-jsx
12-
- [x] error-handling, assetsNode, load-parallel, crank-jsx
9+
- [ ] storage list, responsive, screenshot, code-splitting
10+
- [ ] faked location/window, cookie/storage partition
11+
- [ ] btn-back/reset/export/upload/fullscreen
12+
- [ ] lang vue/rb/java, mjs-import
13+
- [x] crank-jsx, vue-jsx, ts/tsx, py
14+
- [x] error-handling, assetsNode, load-parallel
1315
- [x] gh-pages, lang js/jsx, react/vue, umd-hack
1416
- [x] code read from url, storybook cards
1517
- [x] web worker for babel transform

public/code/index.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
- turtle.py
12
- crank-todomvc.jsx
23
- crank-async-generator.jsx
34
- vue-threejs-movement.js

public/code/turtle.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# skulpt example
2+
# https://github.com/skulpt/skulpt/blob/master/example/turtle.html
3+
import turtle
4+
5+
wn = turtle.Screen()
6+
7+
babbage = turtle.Turtle()
8+
babbage.shape("triangle")
9+
10+
n = 8
11+
angle = 360 / n
12+
colors = ['red', 'blue', 'green', 'orange', 'purple']
13+
14+
for i in range(n):
15+
color = colors[i % len(colors)]
16+
babbage.color(color)
17+
# babbage.right(angle)
18+
babbage.left(angle)
19+
babbage.forward(70)
20+
babbage.stamp()
21+
22+
print "Hello World"
23+
24+
class Test:
25+
def run(self, b):
26+
self.a = 10 + b
27+
return self.a
28+
29+
a = Test()
30+
print a.run(123)

public/code/turtle.py.png

31.1 KB
Loading

src/playground/Playground.tsx

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as Antd from 'antd';
22
import 'codemirror/lib/codemirror.css';
33
// import 'codemirror/mode/javascript/javascript';
44
import 'codemirror/mode/jsx/jsx';
5+
import 'codemirror/mode/python/python';
56
import 'codemirror/theme/material.css';
67
import _ from 'lodash';
78
import React, { useCallback, useEffect, useState } from 'react';
@@ -21,7 +22,7 @@ import { useFormBinding } from '../hooks/useFormBinding';
2122
import { useInterval } from '../hooks/useInterval';
2223
import { useModel } from '../hooks/useModel';
2324
import { useTrigger } from '../hooks/useTrigger';
24-
import { babelTransform } from './babelMaster';
25+
import { codeTransform } from './codeTransform';
2526
import './page.css';
2627
import { MainCol, MainRow, MountNode } from './styled';
2728
import {
@@ -31,7 +32,6 @@ import {
3132
loadCss,
3233
appendJs,
3334
appendCss,
34-
wrapCode,
3535
} from './util';
3636

3737
Object.assign(window, {
@@ -60,6 +60,8 @@ Object.assign(window, {
6060
export let Playground: React.FC = () => {
6161
let history = useHistory();
6262
let { file } = useParams() as { file: string };
63+
let isPy = file.endsWith('.py');
64+
6365
// let initialCode = useMemo(() => {
6466
// return localStorage.getItem(storeKeyCode) || _initialCode;
6567
// }, []);
@@ -130,10 +132,7 @@ export let Playground: React.FC = () => {
130132
if (!code) return;
131133
setCompiling(true);
132134
try {
133-
let res = wrapCode(code);
134-
let hasJsx = file && ['.jsx', '.tsx'].some(ext => file.endsWith(ext));
135-
let hasTs = file && ['.ts', '.tsx'].some(ext => file.endsWith(ext));
136-
if (hasJsx || hasTs) res = await babelTransform(res, file);
135+
let res = await codeTransform(code, file);
137136
setPreview(res);
138137
} catch (err) {
139138
displayError(err);
@@ -224,7 +223,7 @@ export let Playground: React.FC = () => {
224223
<CodeMirror
225224
className="main-editor"
226225
options={{
227-
mode: 'text/typescript-jsx',
226+
mode: isPy ? 'python' : 'text/typescript-jsx',
228227
theme: 'material',
229228
lineNumbers: true,
230229
}}

src/playground/codeTransform.ts

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
import { babelTransform } from './babelMaster';
2+
3+
export let codeTransform = async (code: string, file: string) => {
4+
let isPy = file.endsWith('.py');
5+
if (isPy) return wrapPy(code);
6+
7+
code = wrapJs(code);
8+
let hasJsx = file && ['.jsx', '.tsx'].some(ext => file.endsWith(ext));
9+
let hasTs = file && ['.ts', '.tsx'].some(ext => file.endsWith(ext));
10+
if (hasJsx || hasTs) code = await babelTransform(code, file);
11+
return code;
12+
};
13+
14+
export let wrapPy = (code: string) => {
15+
return `
16+
(async () => {
17+
setRendering(true)
18+
19+
let a0 = assetsNode
20+
a0.id = 'assetsNodeOutdated'
21+
let a1 = document.createElement('div')
22+
a1.id = 'assetsNode'
23+
a0.parentNode.appendChild(a1)
24+
25+
// mountNode.innerHTML = '' // can cause error in react
26+
ReactDOM.unmountComponentAtNode(mountNode)
27+
28+
try {
29+
await loadJs('http://www.skulpt.org/js/skulpt.min.js')
30+
await loadJs('http://www.skulpt.org/js/skulpt-stdlib.js')
31+
32+
appendCss(\`
33+
#py-container { padding: 20px }
34+
#py-canvas { transform: scale(0.7); transform-origin: top center; }
35+
\`)
36+
37+
let outf = (text) => {
38+
let mypre = document.getElementById("py-output");
39+
mypre.innerHTML = mypre.innerHTML + text;
40+
}
41+
let builtinRead = (x) => {
42+
if (Sk.builtinFiles === undefined || Sk.builtinFiles["files"][x] === undefined)
43+
throw "File not found: '" + x + "'";
44+
return Sk.builtinFiles["files"][x];
45+
}
46+
47+
setTimeout(() => {
48+
let prog = ${JSON.stringify(code)};
49+
Sk.pre = "py-output";
50+
Sk.configure({ output: outf, read: builtinRead });
51+
52+
(Sk.TurtleGraphics || (Sk.TurtleGraphics = {})).target = 'py-canvas';
53+
let myPromise = Sk.misceval.asyncToPromise(function() {
54+
return Sk.importMainWithBody("<stdin>", false, prog, true);
55+
});
56+
myPromise.then(function(mod) {
57+
console.log('success');
58+
}, function(err) {
59+
console.error(['displayError', err])
60+
displayError(String(err))
61+
});
62+
}, 0)
63+
64+
let h = React.createElement
65+
ReactDOM.render(h('div', { id: 'py-container' }, [
66+
h('pre', { key: 1, id: 'py-output' }),
67+
h('div', { key: 2, id: 'py-canvas' }),
68+
]), mountNode)
69+
a0.parentNode.removeChild(a0)
70+
} catch (err) {
71+
console.error(['displayError', err])
72+
displayError(err)
73+
} finally {
74+
setRendering(false)
75+
}
76+
})()
77+
`.trim();
78+
};
79+
80+
export let wrapJs = (code: string) => {
81+
return `
82+
(async () => {
83+
setRendering(true)
84+
85+
let a0 = assetsNode
86+
a0.id = 'assetsNodeOutdated'
87+
let a1 = document.createElement('div')
88+
a1.id = 'assetsNode'
89+
a0.parentNode.appendChild(a1)
90+
91+
// mountNode.innerHTML = '' // can cause error in react
92+
ReactDOM.unmountComponentAtNode(mountNode)
93+
94+
try {
95+
let { useRef, useMemo, useState, useEffect, useLayoutEffect, useReducer, useContext, useCallback, useImperativeHandle } = React
96+
97+
;;${code};;
98+
99+
if (typeof App !== 'undefined') {
100+
let isVueLike = _.isPlainObject(App)
101+
if (isVueLike) {
102+
if (!mountNode.children[0]) {
103+
let innerNode = document.createElement('div')
104+
mountNode.appendChild(innerNode)
105+
}
106+
let curr = mountNode.children[0]
107+
new Vue(App).$mount(curr)
108+
} else {
109+
ReactDOM.render(React.createElement(App), mountNode)
110+
}
111+
}
112+
a0.parentNode.removeChild(a0)
113+
} catch (err) {
114+
console.error(['displayError', err])
115+
displayError(err)
116+
} finally {
117+
setRendering(false)
118+
}
119+
})()
120+
`.trim();
121+
};

src/playground/util.tsx

Lines changed: 0 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -86,46 +86,3 @@ export let appendCss = (code: string) => {
8686
el.innerHTML = code;
8787
window.assetsNode.appendChild(el);
8888
};
89-
90-
export let wrapCode = (code: string) => {
91-
return `
92-
(async () => {
93-
setRendering(true)
94-
95-
let a0 = assetsNode
96-
a0.id = 'assetsNodeOutdated'
97-
let a1 = document.createElement('div')
98-
a1.id = 'assetsNode'
99-
a0.parentNode.appendChild(a1)
100-
101-
// mountNode.innerHTML = '' // can cause error in react
102-
ReactDOM.unmountComponentAtNode(mountNode)
103-
104-
try {
105-
let { useRef, useMemo, useState, useEffect, useLayoutEffect, useReducer, useContext, useCallback, useImperativeHandle } = React
106-
107-
;;${code};;
108-
109-
if (typeof App !== 'undefined') {
110-
let isVueLike = _.isPlainObject(App)
111-
if (isVueLike) {
112-
if (!mountNode.children[0]) {
113-
let innerNode = document.createElement('div')
114-
mountNode.appendChild(innerNode)
115-
}
116-
let curr = mountNode.children[0]
117-
new Vue(App).$mount(curr)
118-
} else {
119-
ReactDOM.render(React.createElement(App), mountNode)
120-
}
121-
}
122-
a0.parentNode.removeChild(a0)
123-
} catch (err) {
124-
console.error(['displayError', err])
125-
displayError(err)
126-
} finally {
127-
setRendering(false)
128-
}
129-
})()
130-
`.trim();
131-
};

0 commit comments

Comments
 (0)