@@ -10,6 +10,7 @@ import EditorWorker from "worker-loader?name=editor.worker.js!monaco-editor/esm/
1010import FengariWorker from "worker-loader?name=fengari.worker.js!./fengari.worker" ;
1111import TsWorker from "worker-loader?name=ts.worker.js!./ts.worker" ;
1212import "../../assets/styles/play.scss" ;
13+ import { getInitialCode , updateCodeHistory } from "./code" ;
1314
1415// TODO: Use TypeScript 3.8 type imports
1516type 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 ( ) ;
0 commit comments