Skip to content

Commit 3f05a33

Browse files
committed
Refactor playground code
1 parent 825b5e9 commit 3f05a33

File tree

4 files changed

+126
-120
lines changed

4 files changed

+126
-120
lines changed

assets/layout/play.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
</div>
2626
<div id="editor-output-terminal">
2727
<div id="editor-output-terminal-header">
28-
TypescriptToLua version ...
28+
TypeScriptToLua version ...
2929
</div>
3030
<div id="editor-output-terminal-content">
3131
</div>

src/playground/code.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
const example = `/** @noSelfInFile */
2+
3+
// Declare exposed API
4+
type Vector = [number, number, number];
5+
6+
declare interface OnSpellStartEvent {
7+
caster: Unit;
8+
targetLocation: Vector;
9+
}
10+
11+
declare class Unit {
12+
getLevel(): number;
13+
isEnemy(other: Unit): boolean;
14+
kill(): void;
15+
}
16+
17+
declare function print(...messages: any[]): void;
18+
declare function FindUnitsInRadius(location: Vector, radius: number): Unit[];
19+
20+
// Use declared API in code
21+
function onSpellStart(event: OnSpellStartEvent): void {
22+
const units = FindUnitsInRadius(event.targetLocation, 500);
23+
const enemies = units.filter(unit => event.caster.isEnemy(unit));
24+
25+
for (const unit of enemies) {
26+
print(unit, unit.getLevel());
27+
unit.kill();
28+
}
29+
}
30+
`;
31+
32+
export function getInitialCode() {
33+
if (window.location.hash.startsWith("#src=")) {
34+
const code = window.location.hash.replace("#src=", "").trim();
35+
return decodeURIComponent(code);
36+
}
37+
38+
return example;
39+
}
40+
41+
let ignoreHashChange = false;
42+
window.onhashchange = () => {
43+
if (ignoreHashChange) {
44+
ignoreHashChange = false;
45+
return;
46+
}
47+
};
48+
49+
export function updateCodeHistory(code: string) {
50+
window.location.replace("#src=" + encodeURIComponent(code));
51+
ignoreHashChange = true;
52+
}

src/playground/index.ts

Lines changed: 72 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import EditorWorker from "worker-loader?name=editor.worker.js!monaco-editor/esm/
1010
import FengariWorker from "worker-loader?name=fengari.worker.js!./fengari.worker";
1111
import TsWorker from "worker-loader?name=ts.worker.js!./ts.worker";
1212
import "../../assets/styles/play.scss";
13+
import { getInitialCode, updateCodeHistory } from "./code";
1314

1415
// TODO: Use TypeScript 3.8 type imports
1516
type CustomTypeScriptWorker = import("./ts.worker").CustomTypeScriptWorker;
@@ -24,134 +25,87 @@ type CustomTypeScriptWorker = import("./ts.worker").CustomTypeScriptWorker;
2425
},
2526
};
2627

27-
const container = document.getElementById("editor-ts");
28-
const outputTerminalHeader = document.getElementById("editor-output-terminal-header");
29-
const outputTerminalContent = document.getElementById("editor-output-terminal-content");
30-
const exampleLua = document.getElementById("editor-lua");
31-
const astLua = document.getElementById("editor-lua-ast");
28+
renderjson.set_show_to_level(1);
29+
renderjson.set_replacer((key: string, value: any) => {
30+
if (key === "kind") {
31+
return lua.SyntaxKind[value];
32+
}
3233

33-
// Set tstl version
34-
outputTerminalHeader!.textContent = `TypescriptToLua version ${tstlVersion}`;
34+
return value;
35+
});
3536

36-
// Layout stuff
37-
const luaTabText = document.getElementById("lua-tab-text") as HTMLDivElement | null;
38-
const luaTabAst = document.getElementById("lua-tab-ast") as HTMLDivElement | null;
39-
if (luaTabText && luaTabAst && exampleLua && astLua) {
40-
const tabOnclick = () => {
41-
luaTabText.classList.toggle("lua-tab-active");
42-
luaTabAst.classList.toggle("lua-tab-active");
43-
exampleLua.classList.toggle("editor-lua-active");
44-
astLua.classList.toggle("editor-lua-active");
45-
};
46-
luaTabText.onclick = tabOnclick;
47-
luaTabAst.onclick = tabOnclick;
48-
}
37+
const tsEditorContainer = document.getElementById("editor-ts")!;
38+
const luaEditorContainer = document.getElementById("editor-lua")!;
39+
const luaAstContainer = document.getElementById("editor-lua-ast")!;
40+
const outputTerminalContent = document.getElementById("editor-output-terminal-content")!;
4941

50-
// Actual editor and transpilation
51-
let example = `/** @noSelfInFile */
42+
// Set tstl version
43+
const outputTerminalHeader = document.getElementById("editor-output-terminal-header")!;
44+
outputTerminalHeader.textContent = `TypeScriptToLua version ${tstlVersion}`;
5245

53-
// Declare exposed API
54-
type Vector = [number, number, number];
46+
// Layout stuff
47+
const luaTabText = document.querySelector<HTMLDivElement>("#lua-tab-text")!;
48+
const luaTabAst = document.querySelector<HTMLDivElement>("#lua-tab-ast")!;
49+
const onTabClick = () => {
50+
luaTabText.classList.toggle("lua-tab-active");
51+
luaTabAst.classList.toggle("lua-tab-active");
52+
luaEditorContainer.classList.toggle("editor-lua-active");
53+
luaAstContainer.classList.toggle("editor-lua-active");
54+
};
5555

56-
declare interface OnSpellStartEvent {
57-
caster: Unit;
58-
targetLocation: Vector;
59-
}
56+
luaTabText.onclick = onTabClick;
57+
luaTabAst.onclick = onTabClick;
6058

61-
declare class Unit {
62-
getLevel(): number;
63-
isEnemy(other: Unit): boolean;
64-
kill(): void;
59+
function setLuaAST(ast: lua.Block) {
60+
luaAstContainer.innerText = "";
61+
luaAstContainer.appendChild(renderjson(ast));
6562
}
6663

67-
declare function print(...messages: any[]): void;
68-
declare function FindUnitsInRadius(location: Vector, radius: number): Unit[];
69-
70-
// Use declared API in code
71-
function onSpellStart(event: OnSpellStartEvent): void {
72-
const units = FindUnitsInRadius(event.targetLocation, 500);
73-
const enemies = units.filter(unit => event.caster.isEnemy(unit));
74-
75-
for (const unit of enemies) {
76-
print(unit, unit.getLevel());
77-
unit.kill();
78-
}
79-
}`;
64+
async function onCodeChanged() {
65+
const model = tsEditor.getModel()!;
66+
const getWorker = await monaco.languages.typescript.getTypeScriptWorker();
67+
const client: CustomTypeScriptWorker = await getWorker(model.uri);
8068

81-
var queryStringSrcStart = window.location.hash.indexOf("#src=");
82-
if (queryStringSrcStart == 0) {
83-
var encoded = window.location.hash.substring("#src=".length);
84-
example = decodeURIComponent(encoded);
69+
const { code, ast } = await client.getTranspileOutput();
70+
luaEditor.setValue(code);
71+
setLuaAST(ast);
72+
fengariWorker.postMessage({ luaStr: code });
8573
}
8674

87-
if (container && exampleLua && astLua) {
88-
renderjson.set_show_to_level(1);
89-
renderjson.set_replacer((key: string, value: any) => {
90-
if (key === "kind") {
91-
return lua.SyntaxKind[value];
92-
}
93-
94-
return value;
95-
});
96-
97-
async function compileLua() {
98-
const model = tsEditor.getModel()!;
99-
const getWorker = await monaco.languages.typescript.getTypeScriptWorker();
100-
const client = (await getWorker(model.uri)) as CustomTypeScriptWorker;
101-
const { code, ast } = await client.getTranspileOutput();
102-
103-
luaEditor.setValue(code);
104-
astLua!.innerText = "";
105-
astLua!.appendChild(renderjson(ast));
106-
fengariWorker.postMessage({ luaStr: code });
107-
}
75+
const fengariWorker = new FengariWorker();
76+
fengariWorker.onmessage = event => {
77+
outputTerminalContent.innerText = event.data.luaPrint;
78+
};
10879

109-
let tsEditor = monaco.editor.create(container, {
110-
value: example,
111-
language: "typescript",
112-
minimap: { enabled: false },
113-
theme: "vs-dark",
114-
});
115-
116-
let luaEditor = monaco.editor.create(exampleLua, {
117-
value: "",
118-
language: "lua",
119-
minimap: { enabled: false },
120-
theme: "vs-dark",
121-
readOnly: true,
122-
});
123-
124-
window.onresize = () => {
125-
tsEditor.layout();
126-
luaEditor.layout();
127-
};
128-
129-
compileLua();
130-
131-
let timerVar: any;
132-
let ignoreHashChange = false;
133-
134-
tsEditor.onDidChangeModelContent(e => {
135-
clearInterval(timerVar);
136-
// Update transpile result only once per 250s
137-
timerVar = setTimeout(() => {
138-
compileLua();
139-
window.location.replace("#src=" + encodeURIComponent(tsEditor.getValue()));
140-
ignoreHashChange = true;
141-
}, 250);
142-
});
143-
144-
window.onhashchange = () => {
145-
if (ignoreHashChange) {
146-
ignoreHashChange = false;
147-
return;
148-
}
149-
};
80+
const tsEditor = monaco.editor.create(tsEditorContainer, {
81+
value: getInitialCode(),
82+
language: "typescript",
83+
minimap: { enabled: false },
84+
theme: "vs-dark",
85+
});
86+
87+
const luaEditor = monaco.editor.create(luaEditorContainer, {
88+
value: "",
89+
language: "lua",
90+
minimap: { enabled: false },
91+
theme: "vs-dark",
92+
readOnly: true,
93+
});
94+
95+
// More performant than `automaticLayout: true`, because container sizes can change only with window
96+
window.onresize = () => {
97+
tsEditor.layout();
98+
luaEditor.layout();
99+
};
150100

151-
const fengariWorker = new FengariWorker();
152-
fengariWorker.onmessage = (event: MessageEvent) => {
153-
if (outputTerminalContent) {
154-
outputTerminalContent.innerText = event.data.luaPrint;
155-
}
156-
};
157-
}
101+
let contentChangeTimeout: any;
102+
tsEditor.onDidChangeModelContent(e => {
103+
clearTimeout(contentChangeTimeout);
104+
// Update transpile result no more often than every 250ms
105+
contentChangeTimeout = setTimeout(() => {
106+
onCodeChanged();
107+
updateCodeHistory(tsEditor.getValue());
108+
}, 250);
109+
});
110+
111+
onCodeChanged();

src/playground/ts.worker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import * as tstl from "typescript-to-lua";
77
const emitHost: tstl.EmitHost = {
88
getCurrentDirectory: () => ".",
99
readFile: (fileName: string) => {
10-
let featureName = fileName.replace("/dist/lualib/", "").replace(".lua", "");
10+
const featureName = fileName.replace("/dist/lualib/", "").replace(".lua", "");
1111
return require(`raw-loader!typescript-to-lua/dist/lualib/${featureName}.lua`).default;
1212
},
1313
};

0 commit comments

Comments
 (0)