pxt-core 9.3.13 → 9.3.15

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.
Files changed (42) hide show
  1. package/README.md +11 -0
  2. package/built/cli.js +7 -2
  3. package/built/pxt.js +57 -3
  4. package/built/pxtblockly.js +97 -57
  5. package/built/pxtblocks.d.ts +59 -21
  6. package/built/pxtblocks.js +97 -57
  7. package/built/pxtlib.d.ts +22 -0
  8. package/built/pxtlib.js +50 -1
  9. package/built/target.js +1 -1
  10. package/built/tests/blocksrunner.js +1 -1
  11. package/built/web/main.js +1 -1
  12. package/built/web/multiplayer/js/{main.78cecdcb.js → main.75ca8c58.js} +2 -2
  13. package/built/web/pxtapp.js +1 -1
  14. package/built/web/pxtasseteditor.js +1 -1
  15. package/built/web/pxtblockly.js +2 -2
  16. package/built/web/pxtblocks.js +1 -1
  17. package/built/web/pxtembed.js +2 -2
  18. package/built/web/pxtlib.js +1 -1
  19. package/built/web/pxtworker.js +1 -1
  20. package/built/web/rtlsemantic.css +1 -1
  21. package/built/web/runnerembed.js +1 -0
  22. package/built/web/semantic.css +1 -1
  23. package/built/web/skillmap/js/{main.8222bb34.js → main.236bd49e.js} +2 -2
  24. package/built/web/teachertool/css/main.e9386f28.css +1 -0
  25. package/built/web/teachertool/js/{main.3a94a341.js → main.8aa6604c.js} +2 -2
  26. package/localtypings/projectheader.d.ts +21 -0
  27. package/{built → localtypings}/pxteditor.d.ts +1095 -1090
  28. package/package.json +1 -1
  29. package/react-common/components/controls/MenuDropdown.tsx +5 -2
  30. package/react-common/components/util.tsx +1 -1
  31. package/theme/pxt.less +1 -0
  32. package/theme/themepacks.less +41 -0
  33. package/webapp/public/embed.js +1 -1
  34. package/webapp/public/multiplayer.html +1 -1
  35. package/webapp/public/skillmap.html +1 -1
  36. package/webapp/public/teachertool.html +1 -3
  37. package/built/pxteditor.js +0 -1834
  38. package/built/pxtrunner.d.ts +0 -151
  39. package/built/pxtrunner.js +0 -2626
  40. package/built/web/pxteditor.js +0 -1
  41. package/built/web/pxtrunner.js +0 -1
  42. package/built/web/teachertool/css/main.59776cd1.css +0 -1
@@ -1,1834 +0,0 @@
1
- var pxt;
2
- (function (pxt) {
3
- var editor;
4
- (function (editor) {
5
- let SimState;
6
- (function (SimState) {
7
- SimState[SimState["Stopped"] = 0] = "Stopped";
8
- // waiting to be started
9
- SimState[SimState["Pending"] = 1] = "Pending";
10
- SimState[SimState["Starting"] = 2] = "Starting";
11
- SimState[SimState["Running"] = 3] = "Running";
12
- })(SimState = editor.SimState || (editor.SimState = {}));
13
- function isBlocks(f) {
14
- return pxt.U.endsWith(f.name, ".blocks");
15
- }
16
- editor.isBlocks = isBlocks;
17
- let ErrorListState;
18
- (function (ErrorListState) {
19
- ErrorListState["HeaderOnly"] = "errorListHeader";
20
- ErrorListState["Expanded"] = "errorListExpanded";
21
- })(ErrorListState = editor.ErrorListState || (editor.ErrorListState = {}));
22
- let MuteState;
23
- (function (MuteState) {
24
- MuteState["Muted"] = "muted";
25
- MuteState["Unmuted"] = "unmuted";
26
- MuteState["Disabled"] = "disabled";
27
- })(MuteState = editor.MuteState || (editor.MuteState = {}));
28
- let FilterState;
29
- (function (FilterState) {
30
- FilterState[FilterState["Hidden"] = 0] = "Hidden";
31
- FilterState[FilterState["Visible"] = 1] = "Visible";
32
- FilterState[FilterState["Disabled"] = 2] = "Disabled";
33
- })(FilterState = editor.FilterState || (editor.FilterState = {}));
34
- editor.initExtensionsAsync = opts => Promise.resolve({});
35
- editor.initFieldExtensionsAsync = opts => Promise.resolve({});
36
- editor.HELP_IMAGE_URI = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjYiIGhlaWdodD0iMjYiIHZpZXdCb3g9IjAgMCAyNiAyNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPGNpcmNsZSBjeD0iMTMiIGN5PSIxMyIgcj0iMTMiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGQ9Ik0xNy45NTIgOS4xODQwMkMxNy45NTIgMTAuMjU2IDE3LjgxNiAxMS4wNzIgMTcuNTQ0IDExLjYzMkMxNy4yODggMTIuMTkyIDE2Ljc1MiAxMi43OTIgMTUuOTM2IDEzLjQzMkMxNS4xMiAxNC4wNzIgMTQuNTc2IDE0LjU4NCAxNC4zMDQgMTQuOTY4QzE0LjA0OCAxNS4zMzYgMTMuOTIgMTUuNzM2IDEzLjkyIDE2LjE2OFYxNi45NkgxMS44MDhDMTEuNDI0IDE2LjQ2NCAxMS4yMzIgMTUuODQgMTEuMjMyIDE1LjA4OEMxMS4yMzIgMTQuNjg4IDExLjM4NCAxNC4yODggMTEuNjg4IDEzLjg4OEMxMS45OTIgMTMuNDg4IDEyLjUzNiAxMi45NjggMTMuMzIgMTIuMzI4QzE0LjEwNCAxMS42NzIgMTQuNjI0IDExLjE2OCAxNC44OCAxMC44MTZDMTUuMTM2IDEwLjQ0OCAxNS4yNjQgOS45NjgwMiAxNS4yNjQgOS4zNzYwMkMxNS4yNjQgOC4yMDgwMiAxNC40MTYgNy42MjQwMiAxMi43MiA3LjYyNDAyQzExLjc2IDcuNjI0MDIgMTAuNzUyIDcuNzM2MDIgOS42OTYgNy45NjAwMkw5LjE0NCA4LjA4MDAyTDkgNi4wODgwMkMxMC40ODggNS41NjAwMiAxMS44NCA1LjI5NjAyIDEzLjA1NiA1LjI5NjAyQzE0LjczNiA1LjI5NjAyIDE1Ljk2OCA1LjYwODAyIDE2Ljc1MiA2LjIzMjAyQzE3LjU1MiA2Ljg0MDAyIDE3Ljk1MiA3LjgyNDAyIDE3Ljk1MiA5LjE4NDAyWk0xMS40IDIyVjE4LjY0SDE0LjE4NFYyMkgxMS40WiIgZmlsbD0iIzU5NUU3NCIvPgo8L3N2Zz4K';
37
- let _initEditorExtensionsPromise;
38
- function initEditorExtensionsAsync() {
39
- if (!_initEditorExtensionsPromise) {
40
- _initEditorExtensionsPromise = Promise.resolve();
41
- if (pxt.appTarget && pxt.appTarget.appTheme && pxt.appTarget.appTheme.extendFieldEditors) {
42
- const opts = {};
43
- _initEditorExtensionsPromise = _initEditorExtensionsPromise
44
- .then(() => pxt.BrowserUtils.loadBlocklyAsync())
45
- .then(() => pxt.BrowserUtils.loadScriptAsync("fieldeditors.js"))
46
- .then(() => pxt.editor.initFieldExtensionsAsync(opts))
47
- .then(res => {
48
- if (res.fieldEditors)
49
- res.fieldEditors.forEach(fi => {
50
- pxt.blocks.registerFieldEditor(fi.selector, fi.editor, fi.validator);
51
- });
52
- });
53
- }
54
- }
55
- return _initEditorExtensionsPromise;
56
- }
57
- editor.initEditorExtensionsAsync = initEditorExtensionsAsync;
58
- })(editor = pxt.editor || (pxt.editor = {}));
59
- })(pxt || (pxt = {}));
60
- var pxt;
61
- (function (pxt) {
62
- var editor;
63
- (function (editor_1) {
64
- const pendingRequests = {};
65
- /**
66
- * Binds incoming window messages to the project view.
67
- * Requires the "allowParentController" flag in the pxtarget.json/appTheme object.
68
- *
69
- * When the project view receives a request (EditorMessageRequest),
70
- * it starts the command and returns the result upon completion.
71
- * The response (EditorMessageResponse) contains the request id and result.
72
- * Some commands may be async, use the ``id`` field to correlate to the original request.
73
- */
74
- function bindEditorMessages(getEditorAsync) {
75
- const allowEditorMessages = (pxt.appTarget.appTheme.allowParentController || pxt.shell.isControllerMode())
76
- && pxt.BrowserUtils.isIFrame();
77
- const allowExtensionMessages = pxt.appTarget.appTheme.allowPackageExtensions;
78
- const allowSimTelemetry = pxt.appTarget.appTheme.allowSimulatorTelemetry;
79
- if (!allowEditorMessages && !allowExtensionMessages && !allowSimTelemetry)
80
- return;
81
- window.addEventListener("message", (msg) => {
82
- const data = msg.data;
83
- if (!data || !/^pxt(host|editor|pkgext|sim)$/.test(data.type))
84
- return false;
85
- if (data.type === "pxtpkgext" && allowExtensionMessages) {
86
- // Messages sent to the editor iframe from a child iframe containing an extension
87
- getEditorAsync().then(projectView => {
88
- projectView.handleExtensionRequest(data);
89
- });
90
- }
91
- else if (data.type === "pxtsim" && allowSimTelemetry) {
92
- const event = data;
93
- if (event.action === "event") {
94
- if (event.category || event.message) {
95
- pxt.reportError(event.category, event.message, event.data);
96
- }
97
- else {
98
- pxt.tickEvent(event.tick, event.data);
99
- }
100
- }
101
- }
102
- else if (allowEditorMessages) {
103
- // Messages sent to the editor from the parent frame
104
- let p = Promise.resolve();
105
- let resp = undefined;
106
- if (data.type == "pxthost") { // response from the host
107
- const req = pendingRequests[data.id];
108
- if (!req) {
109
- pxt.debug(`pxthost: unknown request ${data.id}`);
110
- }
111
- else {
112
- p = p.then(() => req.resolve(data));
113
- }
114
- }
115
- else if (data.type == "pxteditor") { // request from the editor
116
- p = p.then(() => {
117
- return getEditorAsync().then(projectView => {
118
- const req = data;
119
- pxt.debug(`pxteditor: ${req.action}`);
120
- switch (req.action.toLowerCase()) {
121
- case "switchjavascript": return Promise.resolve().then(() => projectView.openJavaScript());
122
- case "switchpython": return Promise.resolve().then(() => projectView.openPython());
123
- case "switchblocks": return Promise.resolve().then(() => projectView.openBlocks());
124
- case "startsimulator": return Promise.resolve().then(() => projectView.startSimulator());
125
- case "restartsimulator": return Promise.resolve().then(() => projectView.restartSimulator());
126
- case "hidesimulator": return Promise.resolve().then(() => projectView.collapseSimulator());
127
- case "showsimulator": return Promise.resolve().then(() => projectView.expandSimulator());
128
- case "closeflyout": return Promise.resolve().then(() => projectView.closeFlyout());
129
- case "unloadproject": return Promise.resolve().then(() => projectView.unloadProjectAsync());
130
- case "saveproject": return projectView.saveProjectAsync();
131
- case "redo": return Promise.resolve()
132
- .then(() => {
133
- const editor = projectView.editor;
134
- if (editor && editor.hasRedo())
135
- editor.redo();
136
- });
137
- case "undo": return Promise.resolve()
138
- .then(() => {
139
- const editor = projectView.editor;
140
- if (editor && editor.hasUndo())
141
- editor.undo();
142
- });
143
- case "setscale": {
144
- const zoommsg = data;
145
- return Promise.resolve()
146
- .then(() => projectView.editor.setScale(zoommsg.scale));
147
- }
148
- case "stopsimulator": {
149
- const stop = data;
150
- return Promise.resolve()
151
- .then(() => projectView.stopSimulator(stop.unload));
152
- }
153
- case "newproject": {
154
- const create = data;
155
- return Promise.resolve()
156
- .then(() => projectView.newProject(create.options));
157
- }
158
- case "importproject": {
159
- const load = data;
160
- return Promise.resolve()
161
- .then(() => projectView.importProjectAsync(load.project, {
162
- filters: load.filters,
163
- searchBar: load.searchBar
164
- }));
165
- }
166
- case "openheader": {
167
- const open = data;
168
- return projectView.openProjectByHeaderIdAsync(open.headerId);
169
- }
170
- case "startactivity": {
171
- const msg = data;
172
- let tutorialPath = msg.path;
173
- let editorProjectName = undefined;
174
- if (/^([jt]s|py|blocks?):/i.test(tutorialPath)) {
175
- if (/^py:/i.test(tutorialPath))
176
- editorProjectName = pxt.PYTHON_PROJECT_NAME;
177
- else if (/^[jt]s:/i.test(tutorialPath))
178
- editorProjectName = pxt.JAVASCRIPT_PROJECT_NAME;
179
- else
180
- editorProjectName = pxt.BLOCKS_PROJECT_NAME;
181
- tutorialPath = tutorialPath.substr(tutorialPath.indexOf(':') + 1);
182
- }
183
- return Promise.resolve()
184
- .then(() => projectView.startActivity({
185
- activity: msg.activityType,
186
- path: tutorialPath,
187
- title: msg.title,
188
- editor: editorProjectName,
189
- previousProjectHeaderId: msg.previousProjectHeaderId,
190
- carryoverPreviousCode: msg.carryoverPreviousCode
191
- }));
192
- }
193
- case "importtutorial": {
194
- const load = data;
195
- return Promise.resolve()
196
- .then(() => projectView.importTutorialAsync(load.markdown));
197
- }
198
- case "proxytosim": {
199
- const simmsg = data;
200
- return Promise.resolve()
201
- .then(() => projectView.proxySimulatorMessage(simmsg.content));
202
- }
203
- case "renderblocks": {
204
- const rendermsg = data;
205
- return Promise.resolve()
206
- .then(() => projectView.renderBlocksAsync(rendermsg))
207
- .then(r => {
208
- return r.xml.then((svg) => {
209
- resp = svg.xml;
210
- });
211
- });
212
- }
213
- case "renderpython": {
214
- const rendermsg = data;
215
- return Promise.resolve()
216
- .then(() => projectView.renderPythonAsync(rendermsg))
217
- .then(r => {
218
- resp = r.python;
219
- });
220
- }
221
- case "toggletrace": {
222
- const togglemsg = data;
223
- return Promise.resolve()
224
- .then(() => projectView.toggleTrace(togglemsg.intervalSpeed));
225
- }
226
- case "settracestate": {
227
- const trcmsg = data;
228
- return Promise.resolve()
229
- .then(() => projectView.setTrace(trcmsg.enabled, trcmsg.intervalSpeed));
230
- }
231
- case "setsimulatorfullscreen": {
232
- const fsmsg = data;
233
- return Promise.resolve()
234
- .then(() => projectView.setSimulatorFullScreen(fsmsg.enabled));
235
- }
236
- case "togglehighcontrast": {
237
- return Promise.resolve()
238
- .then(() => projectView.toggleHighContrast());
239
- }
240
- case "sethighcontrast": {
241
- const hcmsg = data;
242
- return Promise.resolve()
243
- .then(() => projectView.setHighContrast(hcmsg.on));
244
- }
245
- case "togglegreenscreen": {
246
- return Promise.resolve()
247
- .then(() => projectView.toggleGreenScreen());
248
- }
249
- case "print": {
250
- return Promise.resolve()
251
- .then(() => projectView.printCode());
252
- }
253
- case "pair": {
254
- return projectView.pairAsync().then(() => { });
255
- }
256
- case "info": {
257
- return Promise.resolve()
258
- .then(() => {
259
- resp = {
260
- versions: pxt.appTarget.versions,
261
- locale: ts.pxtc.Util.userLanguage(),
262
- availableLocales: pxt.appTarget.appTheme.availableLocales
263
- };
264
- });
265
- }
266
- case "shareproject": {
267
- const msg = data;
268
- return projectView.anonymousPublishHeaderByIdAsync(msg.headerId, msg.projectName)
269
- .then(scriptInfo => {
270
- resp = scriptInfo;
271
- });
272
- }
273
- case "savelocalprojectstocloud": {
274
- const msg = data;
275
- return projectView.saveLocalProjectsToCloudAsync(msg.headerIds)
276
- .then(guidMap => {
277
- resp = {
278
- headerIdMap: guidMap
279
- };
280
- });
281
- }
282
- case "requestprojectcloudstatus": {
283
- // Responses are sent as separate "projectcloudstatus" messages.
284
- const msg = data;
285
- return projectView.requestProjectCloudStatus(msg.headerIds);
286
- }
287
- case "convertcloudprojectstolocal": {
288
- const msg = data;
289
- return projectView.convertCloudProjectsToLocal(msg.userId);
290
- }
291
- case "setlanguagerestriction": {
292
- const msg = data;
293
- if (msg.restriction === "no-blocks") {
294
- console.warn("no-blocks language restriction is not supported");
295
- throw new Error("no-blocks language restriction is not supported");
296
- }
297
- return projectView.setLanguageRestrictionAsync(msg.restriction);
298
- }
299
- }
300
- return Promise.resolve();
301
- });
302
- });
303
- }
304
- p.then(() => sendResponse(data, resp, true, undefined), (err) => sendResponse(data, resp, false, err));
305
- }
306
- return true;
307
- }, false);
308
- }
309
- editor_1.bindEditorMessages = bindEditorMessages;
310
- /**
311
- * Sends analytics messages upstream to container if any
312
- */
313
- function enableControllerAnalytics() {
314
- if (!pxt.appTarget.appTheme.allowParentController || !pxt.BrowserUtils.isIFrame())
315
- return;
316
- const te = pxt.tickEvent;
317
- pxt.tickEvent = function (id, data) {
318
- if (te)
319
- te(id, data);
320
- postHostMessageAsync({
321
- type: 'pxthost',
322
- action: 'event',
323
- tick: id,
324
- response: false,
325
- data
326
- });
327
- };
328
- const rexp = pxt.reportException;
329
- pxt.reportException = function (err, data) {
330
- if (rexp)
331
- rexp(err, data);
332
- try {
333
- postHostMessageAsync({
334
- type: 'pxthost',
335
- action: 'event',
336
- tick: 'error',
337
- message: err.message,
338
- response: false,
339
- data
340
- });
341
- }
342
- catch (e) {
343
- }
344
- };
345
- const re = pxt.reportError;
346
- pxt.reportError = function (cat, msg, data) {
347
- if (re)
348
- re(cat, msg, data);
349
- postHostMessageAsync({
350
- type: 'pxthost',
351
- action: 'event',
352
- tick: 'error',
353
- category: cat,
354
- message: msg,
355
- data
356
- });
357
- };
358
- }
359
- editor_1.enableControllerAnalytics = enableControllerAnalytics;
360
- function sendResponse(request, resp, success, error) {
361
- if (request.response) {
362
- window.parent.postMessage({
363
- type: request.type,
364
- id: request.id,
365
- resp,
366
- success,
367
- error
368
- }, "*");
369
- }
370
- }
371
- /**
372
- * Determines if host messages should be posted
373
- */
374
- function shouldPostHostMessages() {
375
- return pxt.appTarget.appTheme.allowParentController && pxt.BrowserUtils.isIFrame();
376
- }
377
- editor_1.shouldPostHostMessages = shouldPostHostMessages;
378
- /**
379
- * Posts a message from the editor to the host
380
- */
381
- function postHostMessageAsync(msg) {
382
- return new Promise((resolve, reject) => {
383
- const env = pxt.Util.clone(msg);
384
- env.id = ts.pxtc.Util.guidGen();
385
- if (msg.response)
386
- pendingRequests[env.id] = { resolve, reject };
387
- window.parent.postMessage(env, "*");
388
- if (!msg.response)
389
- resolve(undefined);
390
- });
391
- }
392
- editor_1.postHostMessageAsync = postHostMessageAsync;
393
- })(editor = pxt.editor || (pxt.editor = {}));
394
- })(pxt || (pxt = {}));
395
- var pxt;
396
- (function (pxt) {
397
- var editor;
398
- (function (editor) {
399
- var experiments;
400
- (function (experiments_1) {
401
- function key(experiment) {
402
- const id = (typeof experiment === "object") ? experiment.id : experiment;
403
- return `experiments-${id}`;
404
- }
405
- function syncTheme() {
406
- const theme = pxt.savedAppTheme();
407
- const r = {};
408
- const experiments = all();
409
- experiments.forEach(experiment => {
410
- const enabled = isEnabled(experiment);
411
- theme[experiment.id] = !!enabled;
412
- if (enabled)
413
- r[experiment.id] = enabled ? 1 : 0;
414
- });
415
- if (experiments.length && Object.keys(r).length) {
416
- pxt.tickEvent("experiments.loaded", r);
417
- pxt.reloadAppTargetVariant();
418
- }
419
- return pxt.appTarget.appTheme;
420
- }
421
- experiments_1.syncTheme = syncTheme;
422
- function all() {
423
- const ids = pxt.appTarget.appTheme.experiments;
424
- if (!ids)
425
- return [];
426
- return [
427
- {
428
- id: "print",
429
- name: lf("Print Code"),
430
- description: lf("Print the code from the current project"),
431
- feedbackUrl: "https://github.com/microsoft/pxt/issues/4740"
432
- },
433
- {
434
- id: "greenScreen",
435
- name: lf("Green screen"),
436
- description: lf("Display a webcam video stream or a green background behind the code."),
437
- feedbackUrl: "https://github.com/microsoft/pxt/issues/4738"
438
- },
439
- {
440
- id: "allowPackageExtensions",
441
- name: lf("Editor Extensions"),
442
- description: lf("Allow Extensions to add buttons in the editor."),
443
- feedbackUrl: "https://github.com/microsoft/pxt/issues/4741"
444
- },
445
- {
446
- id: "instructions",
447
- name: lf("Wiring Instructions"),
448
- description: lf("Generate step-by-step assembly instructions for breadboard wiring."),
449
- feedbackUrl: "https://github.com/microsoft/pxt/issues/4739"
450
- },
451
- {
452
- id: "debugger",
453
- name: lf("Debugger"),
454
- description: lf("Step through code and inspect variables in the debugger"),
455
- feedbackUrl: "https://github.com/microsoft/pxt/issues/4729"
456
- },
457
- {
458
- id: "bluetoothUartConsole",
459
- name: "Bluetooth Console",
460
- description: lf("Receives UART message through Web Bluetooth"),
461
- feedbackUrl: "https://github.com/microsoft/pxt/issues/4796"
462
- },
463
- {
464
- id: "bluetoothPartialFlashing",
465
- name: "Bluetooth Download",
466
- description: lf("Download code via Web Bluetooth"),
467
- feedbackUrl: "https://github.com/microsoft/pxt/issues/4807"
468
- },
469
- {
470
- id: "simScreenshot",
471
- name: lf("Simulator Screenshots"),
472
- description: lf("Download screenshots of the simulator"),
473
- feedbackUrl: "https://github.com/microsoft/pxt/issues/5232"
474
- },
475
- {
476
- id: "python",
477
- name: lf("Static Python"),
478
- description: lf("Use Static Python to code your device"),
479
- feedbackUrl: "https://github.com/microsoft/pxt/issues/5390"
480
- },
481
- {
482
- id: "simGif",
483
- name: lf("Simulator Gifs"),
484
- description: lf("Download gifs of the simulator"),
485
- feedbackUrl: "https://github.com/microsoft/pxt/issues/5297"
486
- },
487
- {
488
- id: "qrCode",
489
- name: lf("Shared QR Code"),
490
- description: lf("Generate a QR Code form the shared project url"),
491
- feedbackUrl: "https://github.com/microsoft/pxt/issues/5456"
492
- },
493
- {
494
- id: "importExtensionFiles",
495
- name: lf("Import Extension Files"),
496
- description: lf("Import Extensions from compiled project files")
497
- },
498
- {
499
- id: "debugExtensionCode",
500
- name: lf("Debug Extension Code"),
501
- description: lf("Use the JavaScript debugger to debug extension code")
502
- },
503
- {
504
- id: "snippetBuilder",
505
- name: lf("Snippet Builder"),
506
- description: lf("Try out the new snippet dialogs.")
507
- },
508
- {
509
- id: "experimentalHw",
510
- name: lf("Experimental Hardware"),
511
- description: lf("Enable support for hardware marked 'experimental' in the hardware seletion dialog")
512
- },
513
- {
514
- id: "checkForHwVariantWebUSB",
515
- name: lf("Detect Hardware with WebUSB"),
516
- description: lf("When compiling, use WebUSB to detect hardware configuration.")
517
- },
518
- {
519
- id: "githubEditor",
520
- name: lf("GitHub editor"),
521
- description: lf("Review, commit and push to GitHub."),
522
- feedbackUrl: "https://github.com/microsoft/pxt/issues/6419",
523
- enableOnline: true,
524
- },
525
- {
526
- id: "githubCompiledJs",
527
- name: lf("GitHub Pages JavaScript"),
528
- description: lf("Commit compiled javascript when creating a release"),
529
- enableOnline: true,
530
- },
531
- {
532
- id: "blocksCollapsing",
533
- name: lf("Collapse blocks"),
534
- description: lf("Collapse and expand functions or event blocks")
535
- },
536
- {
537
- id: "tutorialBlocksDiff",
538
- name: lf("Tutorial Block Diffs"),
539
- description: lf("Automatially render blocks diff in tutorials")
540
- },
541
- {
542
- id: "openProjectNewTab",
543
- name: lf("Open in New Tab"),
544
- description: lf("Open an editor in a new tab.")
545
- },
546
- {
547
- id: "openProjectNewDependentTab",
548
- name: lf("Open in New Connected Tab"),
549
- description: lf("Open connected editors in different browser tabs.")
550
- },
551
- {
552
- id: "accessibleBlocks",
553
- name: lf("Accessible Blocks"),
554
- description: lf("Use the WASD keys to move and modify blocks."),
555
- feedbackUrl: "https://github.com/microsoft/pxt/issues/6850"
556
- },
557
- {
558
- id: "errorList",
559
- name: lf("Error List"),
560
- description: lf("Show an error list panel for JavaScript and Python.")
561
- },
562
- {
563
- id: "blocksErrorList",
564
- name: lf("Blocks Error List"),
565
- description: lf("Show an error list panel for Blocks")
566
- },
567
- {
568
- id: "timeMachine",
569
- name: lf("Time Machine"),
570
- description: lf("Save and restore past versions of a project")
571
- },
572
- ].filter(experiment => ids.indexOf(experiment.id) > -1 && !(pxt.BrowserUtils.isPxtElectron() && experiment.enableOnline));
573
- }
574
- experiments_1.all = all;
575
- function clear() {
576
- all().forEach(experiment => pxt.storage.removeLocal(key(experiment)));
577
- syncTheme();
578
- }
579
- experiments_1.clear = clear;
580
- function someEnabled() {
581
- return all().some(experiment => isEnabled(experiment));
582
- }
583
- experiments_1.someEnabled = someEnabled;
584
- function isEnabled(experiment) {
585
- return !!pxt.storage.getLocal(key(experiment));
586
- }
587
- experiments_1.isEnabled = isEnabled;
588
- function toggle(experiment) {
589
- setState(experiment, !isEnabled(experiment));
590
- }
591
- experiments_1.toggle = toggle;
592
- function state() {
593
- const r = {};
594
- all().forEach(experiment => r[experiment.id] = isEnabled(experiment));
595
- return JSON.stringify(r);
596
- }
597
- experiments_1.state = state;
598
- function setState(experiment, enabled) {
599
- if (enabled == isEnabled(experiment))
600
- return; // no changes
601
- if (enabled)
602
- pxt.storage.setLocal(key(experiment), "1");
603
- else
604
- pxt.storage.removeLocal(key(experiment));
605
- // sync theme
606
- syncTheme();
607
- }
608
- experiments_1.setState = setState;
609
- })(experiments = editor.experiments || (editor.experiments = {}));
610
- })(editor = pxt.editor || (pxt.editor = {}));
611
- })(pxt || (pxt = {}));
612
- var pxt;
613
- (function (pxt) {
614
- var workspace;
615
- (function (workspace) {
616
- // 5 minutes. This is overridden in pxtarget.json
617
- const DEFAULT_DIFF_HISTORY_INTERVAL = 1000 * 60 * 5;
618
- // 15 minutes. This is overridden in pxtarget.json
619
- const DEFAULT_SNAPSHOT_HISTORY_INTERVAL = 1000 * 60 * 15;
620
- const ONE_DAY = 1000 * 60 * 60 * 24;
621
- function collapseHistory(history, text, options, diff, patch) {
622
- var _a, _b;
623
- const newHistory = [];
624
- let current = Object.assign({}, text);
625
- let lastVersion = (_b = (_a = pxt.appTarget) === null || _a === void 0 ? void 0 : _a.versions) === null || _b === void 0 ? void 0 : _b.target;
626
- let lastTime = undefined;
627
- let lastTimeIndex = undefined;
628
- let lastTimeText = undefined;
629
- let { interval, minTime, maxTime } = options;
630
- if (minTime === undefined) {
631
- minTime = 0;
632
- }
633
- if (maxTime === undefined) {
634
- maxTime = history[history.length - 1].timestamp;
635
- }
636
- for (let i = history.length - 1; i >= 0; i--) {
637
- const entry = history[i];
638
- if (entry.timestamp > maxTime) {
639
- newHistory.unshift(entry);
640
- current = applyDiff(current, entry, patch);
641
- continue;
642
- }
643
- else if (entry.timestamp < minTime) {
644
- if (lastTimeIndex !== undefined) {
645
- if (lastTimeIndex - i > 1) {
646
- newHistory.unshift({
647
- timestamp: lastTime,
648
- editorVersion: lastVersion,
649
- changes: diffScriptText(current, lastTimeText, lastTime, diff).changes
650
- });
651
- }
652
- else {
653
- newHistory.unshift(history[lastTimeIndex]);
654
- }
655
- }
656
- newHistory.unshift(entry);
657
- lastTimeIndex = undefined;
658
- continue;
659
- }
660
- else if (lastTimeIndex === undefined) {
661
- lastTimeText = Object.assign({}, current);
662
- lastTime = entry.timestamp;
663
- lastVersion = entry.editorVersion;
664
- lastTimeIndex = i;
665
- current = applyDiff(current, entry, patch);
666
- continue;
667
- }
668
- if (lastTime - entry.timestamp > interval) {
669
- if (lastTimeIndex - i > 1) {
670
- newHistory.unshift({
671
- timestamp: lastTime,
672
- editorVersion: lastVersion,
673
- changes: diffScriptText(current, lastTimeText, lastTime, diff).changes
674
- });
675
- }
676
- else {
677
- newHistory.unshift(history[lastTimeIndex]);
678
- }
679
- lastTimeText = Object.assign({}, current);
680
- current = applyDiff(current, entry, patch);
681
- lastTimeIndex = i;
682
- lastTime = entry.timestamp;
683
- lastVersion = entry.editorVersion;
684
- }
685
- else {
686
- current = applyDiff(current, entry, patch);
687
- }
688
- }
689
- if (lastTimeIndex !== undefined) {
690
- if (lastTimeIndex) {
691
- newHistory.unshift({
692
- timestamp: lastTime,
693
- editorVersion: lastVersion,
694
- changes: diffScriptText(current, lastTimeText, lastTime, diff).changes
695
- });
696
- }
697
- else {
698
- newHistory.unshift(history[0]);
699
- }
700
- }
701
- return newHistory;
702
- }
703
- workspace.collapseHistory = collapseHistory;
704
- function diffScriptText(oldVersion, newVersion, time, diff) {
705
- var _a, _b;
706
- const changes = [];
707
- for (const file of Object.keys(oldVersion)) {
708
- if (!(file.endsWith(".ts") || file.endsWith(".jres") || file.endsWith(".py") || file.endsWith(".blocks") || file === "pxt.json"))
709
- continue;
710
- if (newVersion[file] == undefined) {
711
- changes.push({
712
- type: "removed",
713
- filename: file,
714
- value: oldVersion[file]
715
- });
716
- }
717
- else if (oldVersion[file] !== newVersion[file]) {
718
- changes.push({
719
- type: "edited",
720
- filename: file,
721
- patch: diff(newVersion[file], oldVersion[file])
722
- });
723
- }
724
- }
725
- for (const file of Object.keys(newVersion)) {
726
- if (!(file.endsWith(".ts") || file.endsWith(".jres") || file.endsWith(".py") || file.endsWith(".blocks") || file === "pxt.json"))
727
- continue;
728
- if (oldVersion[file] == undefined) {
729
- changes.push({
730
- type: "added",
731
- filename: file,
732
- value: newVersion[file]
733
- });
734
- }
735
- }
736
- if (!changes.length)
737
- return undefined;
738
- return {
739
- timestamp: time,
740
- editorVersion: (_b = (_a = pxt.appTarget) === null || _a === void 0 ? void 0 : _a.versions) === null || _b === void 0 ? void 0 : _b.target,
741
- changes
742
- };
743
- }
744
- workspace.diffScriptText = diffScriptText;
745
- function applyDiff(text, history, patch) {
746
- const result = Object.assign({}, text);
747
- for (const change of history.changes) {
748
- if (change.type === "added") {
749
- delete result[change.filename];
750
- }
751
- else if (change.type === "removed") {
752
- result[change.filename] = change.value;
753
- }
754
- else {
755
- result[change.filename] = patch(change.patch, text[change.filename]);
756
- }
757
- }
758
- return result;
759
- }
760
- workspace.applyDiff = applyDiff;
761
- function createSnapshot(text) {
762
- try {
763
- const result = {};
764
- const config = JSON.parse(text[pxt.CONFIG_NAME]);
765
- for (const file of config.files) {
766
- // these files will just get regenrated
767
- if (file === pxt.IMAGES_CODE || file === pxt.TILEMAP_CODE) {
768
- result[file] = "";
769
- }
770
- else {
771
- result[file] = text[file];
772
- }
773
- }
774
- result[pxt.CONFIG_NAME] = text[pxt.CONFIG_NAME];
775
- // main.ts will also be regenerated if blocks/python
776
- if (config.preferredEditor === pxt.BLOCKS_PROJECT_NAME) {
777
- if (result[pxt.MAIN_BLOCKS])
778
- result[pxt.MAIN_TS] = "";
779
- }
780
- else if (config.preferredEditor === pxt.PYTHON_PROJECT_NAME) {
781
- if (result[pxt.MAIN_PY])
782
- result[pxt.MAIN_TS] = "";
783
- }
784
- if (config.testFiles) {
785
- for (const file of config.testFiles) {
786
- result[file] = text[file];
787
- }
788
- }
789
- return result;
790
- }
791
- catch (e) {
792
- return Object.assign({}, text);
793
- }
794
- }
795
- workspace.createSnapshot = createSnapshot;
796
- function applySnapshot(text, snapshot) {
797
- var _a;
798
- try {
799
- const result = Object.assign({}, snapshot);
800
- const config = JSON.parse(text[pxt.CONFIG_NAME]);
801
- // preserve any files from the current text that aren't in the config; this is just to make
802
- // sure that our internal files like history, markdown, serial output are preserved
803
- for (const file of Object.keys(text)) {
804
- if (config.files.indexOf(file) === -1 && ((_a = config.testFiles) === null || _a === void 0 ? void 0 : _a.indexOf(file)) === -1 && !result[file]) {
805
- result[file] = text[file];
806
- }
807
- }
808
- return result;
809
- }
810
- catch (e) {
811
- const result = Object.assign({}, text);
812
- for (const file of Object.keys(snapshot)) {
813
- result[file] = snapshot[file];
814
- }
815
- return result;
816
- }
817
- }
818
- workspace.applySnapshot = applySnapshot;
819
- function parseHistoryFile(text) {
820
- const result = JSON.parse(text);
821
- if (!result.entries)
822
- result.entries = [];
823
- if (!result.shares)
824
- result.shares = [];
825
- if (!result.snapshots)
826
- result.snapshots = [];
827
- return result;
828
- }
829
- workspace.parseHistoryFile = parseHistoryFile;
830
- function updateHistory(previousText, toWrite, currentTime, shares, diff, patch) {
831
- let history;
832
- // Always base the history off of what was in the previousText,
833
- // which is written to disk. The new text could have corrupted it
834
- // in some way
835
- if (previousText[pxt.HISTORY_FILE]) {
836
- history = pxt.workspace.parseHistoryFile(previousText[pxt.HISTORY_FILE]);
837
- }
838
- else {
839
- history = {
840
- entries: [],
841
- snapshots: [takeSnapshot(previousText, currentTime - 1)],
842
- shares: []
843
- };
844
- }
845
- // First save any new project shares
846
- for (const share of shares) {
847
- if (!history.shares.some(s => s.id === share.id)) {
848
- history.shares.push({
849
- id: share.id,
850
- timestamp: currentTime,
851
- });
852
- }
853
- }
854
- // If no source changed, we can bail at this point
855
- if (scriptEquals(previousText, toWrite)) {
856
- toWrite[pxt.HISTORY_FILE] = JSON.stringify(history);
857
- return;
858
- }
859
- // Next, update the diff entries. We always update this, but may
860
- // combine it with the previous diff if it's been less than the
861
- // interval time
862
- let shouldCombine = false;
863
- if (history.entries.length > 1) {
864
- const topTime = history.entries[history.entries.length - 1].timestamp;
865
- const prevTime = history.entries[history.entries.length - 2].timestamp;
866
- if (currentTime - topTime < diffInterval() && topTime - prevTime < diffInterval()) {
867
- shouldCombine = true;
868
- }
869
- }
870
- if (shouldCombine) {
871
- // Roll back the last diff and create a new one
872
- const prevText = applyDiff(previousText, history.entries.pop(), patch);
873
- const diffed = diffScriptText(prevText, toWrite, currentTime, diff);
874
- if (diffed) {
875
- history.entries.push(diffed);
876
- }
877
- }
878
- else {
879
- const diffed = diffScriptText(previousText, toWrite, currentTime, diff);
880
- if (diffed) {
881
- history.entries.push(diffed);
882
- }
883
- }
884
- // Finally, update the snapshots. These are failsafes in case something
885
- // goes wrong with the diff history. We keep one snapshot per interval for
886
- // the past 24 hours and one snapshot per day prior to that
887
- if (history.snapshots.length == 0) {
888
- history.snapshots.push(takeSnapshot(previousText, currentTime - 1));
889
- }
890
- else if (currentTime - history.snapshots[history.snapshots.length - 1].timestamp >= snapshotInterval()) {
891
- history.snapshots.push(takeSnapshot(previousText, currentTime));
892
- const trimmed = [];
893
- let currentDay = Math.floor(currentTime / ONE_DAY) * ONE_DAY;
894
- for (let i = 0; i < history.snapshots.length; i++) {
895
- const current = history.snapshots[history.snapshots.length - 1 - i];
896
- if (currentTime - current.timestamp < ONE_DAY || i === history.snapshots.length - 1) {
897
- trimmed.unshift(current);
898
- }
899
- else if (current.timestamp < currentDay) {
900
- trimmed.unshift(current);
901
- currentDay = Math.floor(current.timestamp / ONE_DAY) * ONE_DAY;
902
- }
903
- }
904
- history.snapshots = trimmed;
905
- }
906
- toWrite[pxt.HISTORY_FILE] = JSON.stringify(history);
907
- }
908
- workspace.updateHistory = updateHistory;
909
- function pushSnapshotOnHistory(text, currentTime) {
910
- let history;
911
- if (text[pxt.HISTORY_FILE]) {
912
- history = pxt.workspace.parseHistoryFile(text[pxt.HISTORY_FILE]);
913
- }
914
- else {
915
- history = {
916
- entries: [],
917
- snapshots: [],
918
- shares: []
919
- };
920
- }
921
- history.snapshots.push(takeSnapshot(text, currentTime));
922
- text[pxt.HISTORY_FILE] = JSON.stringify(history);
923
- }
924
- workspace.pushSnapshotOnHistory = pushSnapshotOnHistory;
925
- function updateShareHistory(text, currentTime, shares) {
926
- let history;
927
- if (text[pxt.HISTORY_FILE]) {
928
- history = pxt.workspace.parseHistoryFile(text[pxt.HISTORY_FILE]);
929
- }
930
- else {
931
- history = {
932
- entries: [],
933
- snapshots: [],
934
- shares: []
935
- };
936
- }
937
- for (const share of shares) {
938
- if (!history.shares.some(s => s.id === share.id)) {
939
- history.shares.push({
940
- id: share.id,
941
- timestamp: currentTime,
942
- });
943
- }
944
- }
945
- text[pxt.HISTORY_FILE] = JSON.stringify(history);
946
- }
947
- workspace.updateShareHistory = updateShareHistory;
948
- function takeSnapshot(text, time) {
949
- return {
950
- timestamp: time,
951
- editorVersion: pxt.appTarget.versions.target,
952
- text: pxt.workspace.createSnapshot(text)
953
- };
954
- }
955
- function scriptEquals(a, b) {
956
- const aKeys = Object.keys(a);
957
- const bKeys = Object.keys(b);
958
- if (aKeys.length !== bKeys.length)
959
- return false;
960
- for (const key of aKeys) {
961
- if (bKeys.indexOf(key) === -1)
962
- return false;
963
- if (a[key] !== b[key])
964
- return false;
965
- }
966
- return true;
967
- }
968
- function diffInterval() {
969
- var _a, _b;
970
- if (((_b = (_a = pxt.appTarget) === null || _a === void 0 ? void 0 : _a.appTheme) === null || _b === void 0 ? void 0 : _b.timeMachineDiffInterval) != undefined) {
971
- return pxt.appTarget.appTheme.timeMachineDiffInterval;
972
- }
973
- return DEFAULT_DIFF_HISTORY_INTERVAL;
974
- }
975
- function snapshotInterval() {
976
- var _a, _b;
977
- if (((_b = (_a = pxt.appTarget) === null || _a === void 0 ? void 0 : _a.appTheme) === null || _b === void 0 ? void 0 : _b.timeMachineSnapshotInterval) != undefined) {
978
- return pxt.appTarget.appTheme.timeMachineSnapshotInterval;
979
- }
980
- return DEFAULT_SNAPSHOT_HISTORY_INTERVAL;
981
- }
982
- })(workspace = pxt.workspace || (pxt.workspace = {}));
983
- })(pxt || (pxt = {}));
984
- /// <reference path="../localtypings/monaco.d.ts" />
985
- /// <reference path="../built/pxtlib.d.ts"/>
986
- /// <reference path="../built/pxtblocks.d.ts"/>
987
- var pxt;
988
- (function (pxt) {
989
- var vs;
990
- (function (vs) {
991
- function syncModels(mainPkg, libs, currFile, readOnly) {
992
- if (readOnly)
993
- return;
994
- let extraLibs = monaco.languages.typescript.typescriptDefaults.getExtraLibs();
995
- let modelMap = {};
996
- mainPkg.sortedDeps().forEach(pkg => {
997
- pkg.getFiles().forEach(f => {
998
- let fp = pkg.id + "/" + f;
999
- let proto = "pkg:" + fp;
1000
- if (/\.(ts)$/.test(f) && fp != currFile) {
1001
- if (!monaco.languages.typescript.typescriptDefaults.getExtraLibs()[fp]) {
1002
- // inserting a space creates syntax errors in Python
1003
- let content = pkg.readFile(f) || "\n";
1004
- libs[fp] = monaco.languages.typescript.typescriptDefaults.addExtraLib(content, fp);
1005
- }
1006
- modelMap[fp] = "1";
1007
- }
1008
- });
1009
- });
1010
- // dispose of any extra libraries, the typescript worker will be killed as a result of this
1011
- Object.keys(extraLibs)
1012
- .filter(lib => /\.(ts)$/.test(lib) && !modelMap[lib])
1013
- .forEach(lib => {
1014
- libs[lib].dispose();
1015
- });
1016
- }
1017
- vs.syncModels = syncModels;
1018
- function initMonacoAsync(element) {
1019
- return new Promise((resolve, reject) => {
1020
- if (typeof (window.monaco) === 'object') {
1021
- // monaco is already loaded
1022
- resolve(createEditor(element));
1023
- return;
1024
- }
1025
- let monacoPaths = window.MonacoPaths;
1026
- let onGotAmdLoader = () => {
1027
- let req = window.require;
1028
- req.config({ paths: monacoPaths });
1029
- // Load monaco
1030
- req(['vs/editor/editor.main'], () => {
1031
- setupMonaco();
1032
- resolve(createEditor(element));
1033
- });
1034
- };
1035
- // Load AMD loader if necessary
1036
- if (!window.require) {
1037
- let loaderScript = document.createElement('script');
1038
- loaderScript.type = 'text/javascript';
1039
- loaderScript.src = monacoPaths['vs/loader'];
1040
- loaderScript.addEventListener('load', onGotAmdLoader);
1041
- document.body.appendChild(loaderScript);
1042
- }
1043
- else {
1044
- onGotAmdLoader();
1045
- }
1046
- });
1047
- }
1048
- vs.initMonacoAsync = initMonacoAsync;
1049
- function setupMonaco() {
1050
- initAsmMonarchLanguage();
1051
- initTypeScriptLanguageDefinition();
1052
- }
1053
- function createEditor(element) {
1054
- const inverted = pxt.appTarget.appTheme.invertedMonaco;
1055
- const hasFieldEditors = !!(pxt.appTarget.appTheme.monacoFieldEditors && pxt.appTarget.appTheme.monacoFieldEditors.length);
1056
- const isAndroid = pxt.BrowserUtils.isAndroid();
1057
- let editor = monaco.editor.create(element, {
1058
- model: null,
1059
- ariaLabel: pxt.Util.lf("JavaScript editor"),
1060
- fontFamily: "'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', 'monospace'",
1061
- scrollBeyondLastLine: true,
1062
- language: "typescript",
1063
- mouseWheelZoom: false,
1064
- wordBasedSuggestions: true,
1065
- lineNumbersMinChars: 3,
1066
- formatOnPaste: true,
1067
- folding: hasFieldEditors,
1068
- glyphMargin: hasFieldEditors || pxt.appTarget.appTheme.debugger,
1069
- minimap: {
1070
- enabled: false
1071
- },
1072
- fixedOverflowWidgets: true,
1073
- autoIndent: "full",
1074
- useTabStops: true,
1075
- dragAndDrop: true,
1076
- matchBrackets: "always",
1077
- occurrencesHighlight: false,
1078
- quickSuggestionsDelay: 200,
1079
- theme: inverted ? 'vs-dark' : 'vs',
1080
- renderIndentGuides: true,
1081
- accessibilityHelpUrl: "",
1082
- // disable completions on android
1083
- quickSuggestions: {
1084
- "other": !isAndroid,
1085
- "comments": !isAndroid,
1086
- "strings": !isAndroid
1087
- },
1088
- acceptSuggestionOnCommitCharacter: !isAndroid,
1089
- acceptSuggestionOnEnter: !isAndroid ? "on" : "off",
1090
- accessibilitySupport: !isAndroid ? "on" : "off"
1091
- });
1092
- editor.layout();
1093
- return editor;
1094
- }
1095
- vs.createEditor = createEditor;
1096
- function initAsmMonarchLanguage() {
1097
- monaco.languages.register({ id: 'asm', extensions: ['.asm'] });
1098
- monaco.languages.setMonarchTokensProvider('asm', {
1099
- // Set defaultToken to invalid to see what you do not tokenize yet
1100
- // defaultToken: 'invalid',
1101
- tokenPostfix: '',
1102
- //Extracted from http://infocenter.arm.com/help/topic/com.arm.doc.qrc0006e/QRC0006_UAL16.pdf
1103
- //Should be a superset of the instructions emitted
1104
- keywords: [
1105
- 'movs', 'mov', 'adds', 'add', 'adcs', 'adr', 'subs', 'sbcs', 'sub', 'rsbs',
1106
- 'muls', 'cmp', 'cmn', 'ands', 'eors', 'orrs', 'bics', 'mvns', 'tst', 'lsls',
1107
- 'lsrs', 'asrs', 'rors', 'ldr', 'ldrh', 'ldrb', 'ldrsh', 'ldrsb', 'ldm',
1108
- 'str', 'strh', 'strb', 'stm', 'push', 'pop', 'cbz', 'cbnz', 'b', 'bl', 'bx', 'blx',
1109
- 'sxth', 'sxtb', 'uxth', 'uxtb', 'rev', 'rev16', 'revsh', 'svc', 'cpsid', 'cpsie',
1110
- 'setend', 'bkpt', 'nop', 'sev', 'wfe', 'wfi', 'yield',
1111
- 'beq', 'bne', 'bcs', 'bhs', 'bcc', 'blo', 'bmi', 'bpl', 'bvs', 'bvc', 'bhi', 'bls',
1112
- 'bge', 'blt', 'bgt', 'ble', 'bal',
1113
- //Registers
1114
- 'r0', 'r1', 'r2', 'r3', 'r4', 'r5', 'r6', 'r7', 'r8', 'r9', 'r10', 'r11', 'r12', 'r13', 'r14', 'r15',
1115
- 'pc', 'sp', 'lr'
1116
- ],
1117
- typeKeywords: [
1118
- '.startaddr', '.hex', '.short', '.space', '.section', '.string', '.byte'
1119
- ],
1120
- operators: [],
1121
- // Not all of these are valid in ARM Assembly
1122
- symbols: /[:\*]+/,
1123
- // C# style strings
1124
- escapes: /\\(?:[abfnrtv\\"']|x[0-9A-Fa-f]{1,4}|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})/,
1125
- // The main tokenizer for our languages
1126
- tokenizer: {
1127
- root: [
1128
- // identifiers and keywords
1129
- [/(\.)?[a-z_$\.][\w$]*/, {
1130
- cases: {
1131
- '@typeKeywords': 'keyword',
1132
- '@keywords': 'keyword',
1133
- '@default': 'identifier'
1134
- }
1135
- }],
1136
- // whitespace
1137
- { include: '@whitespace' },
1138
- // delimiters and operators
1139
- [/[{}()\[\]]/, '@brackets'],
1140
- [/[<>](?!@symbols)/, '@brackets'],
1141
- [/@symbols/, {
1142
- cases: {
1143
- '@operators': 'operator',
1144
- '@default': ''
1145
- }
1146
- }],
1147
- // @ annotations.
1148
- [/@\s*[a-zA-Z_\$][\w\$]*/, { token: 'annotation' }],
1149
- // numbers
1150
- //[/\d*\.\d+([eE][\-+]?\d+)?/, 'number.float'],
1151
- [/(#|(0[xX]))?[0-9a-fA-F]+/, 'number'],
1152
- // delimiter: after number because of .\d floats
1153
- [/[;,.]/, 'delimiter'],
1154
- // strings
1155
- [/"([^"\\]|\\.)*$/, 'string.invalid'],
1156
- [/"/, { token: 'string.quote', bracket: '@open', next: '@string' }],
1157
- // characters
1158
- [/'[^\\']'/, 'string'],
1159
- [/(')(@escapes)(')/, ['string', 'string.escape', 'string']],
1160
- [/'/, 'string.invalid']
1161
- ],
1162
- comment: [],
1163
- string: [
1164
- [/[^\\"]+/, 'string'],
1165
- [/@escapes/, 'string.escape'],
1166
- [/\\./, 'string.escape.invalid'],
1167
- [/"/, { token: 'string.quote', bracket: '@close', next: '@pop' }]
1168
- ],
1169
- whitespace: [
1170
- [/[ \t\r\n]+/, 'white'],
1171
- [/\/\*/, 'comment', '@comment'],
1172
- [/;.*$/, 'comment'],
1173
- ],
1174
- }
1175
- });
1176
- }
1177
- function initTypeScriptLanguageDefinition() {
1178
- if (!monaco.languages.typescript) {
1179
- return;
1180
- }
1181
- // validation settings
1182
- monaco.languages.typescript.typescriptDefaults.setDiagnosticsOptions({
1183
- noSyntaxValidation: true,
1184
- noSemanticValidation: true
1185
- });
1186
- // Register our worker
1187
- monaco.languages.typescript.typescriptDefaults.setWorkerOptions({
1188
- customWorkerPath: pxt.webConfig.typeScriptWorkerJs
1189
- });
1190
- // compiler options
1191
- monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
1192
- allowUnreachableCode: true,
1193
- noImplicitAny: true,
1194
- allowJs: false,
1195
- allowUnusedLabels: true,
1196
- target: monaco.languages.typescript.ScriptTarget.ES5,
1197
- outDir: "built",
1198
- rootDir: ".",
1199
- noLib: true,
1200
- mouseWheelZoom: false
1201
- });
1202
- }
1203
- })(vs = pxt.vs || (pxt.vs = {}));
1204
- })(pxt || (pxt = {}));
1205
- /// <reference path="../built/pxtlib.d.ts"/>
1206
- var pxt;
1207
- (function (pxt) {
1208
- var workspace;
1209
- (function (workspace) {
1210
- function freshHeader(name, modTime) {
1211
- let header = {
1212
- target: pxt.appTarget.id,
1213
- targetVersion: pxt.appTarget.versions.target,
1214
- name: name,
1215
- meta: {},
1216
- editor: pxt.JAVASCRIPT_PROJECT_NAME,
1217
- pubId: "",
1218
- pubCurrent: false,
1219
- _rev: null,
1220
- id: pxt.U.guidGen(),
1221
- recentUse: modTime,
1222
- modificationTime: modTime,
1223
- cloudUserId: null,
1224
- cloudCurrent: false,
1225
- cloudVersion: null,
1226
- cloudLastSyncTime: 0,
1227
- isDeleted: false,
1228
- };
1229
- return header;
1230
- }
1231
- workspace.freshHeader = freshHeader;
1232
- })(workspace = pxt.workspace || (pxt.workspace = {}));
1233
- })(pxt || (pxt = {}));
1234
- /// <reference path="../../localtypings/monaco.d.ts" />
1235
- var pxt;
1236
- (function (pxt) {
1237
- var editor;
1238
- (function (editor) {
1239
- const definitions = {};
1240
- function registerMonacoFieldEditor(name, definition) {
1241
- definitions[name] = definition;
1242
- }
1243
- editor.registerMonacoFieldEditor = registerMonacoFieldEditor;
1244
- function getMonacoFieldEditor(name) {
1245
- return definitions[name];
1246
- }
1247
- editor.getMonacoFieldEditor = getMonacoFieldEditor;
1248
- })(editor = pxt.editor || (pxt.editor = {}));
1249
- })(pxt || (pxt = {}));
1250
- /// <reference path="./monacoFieldEditor.ts" />
1251
- var pxt;
1252
- (function (pxt) {
1253
- var editor;
1254
- (function (editor) {
1255
- const fieldEditorId = "image-editor";
1256
- class MonacoReactFieldEditor {
1257
- getId() {
1258
- return fieldEditorId;
1259
- }
1260
- showEditorAsync(fileType, editrange, host) {
1261
- this.fileType = fileType;
1262
- this.editrange = editrange;
1263
- this.host = host;
1264
- return this.initAsync().then(() => {
1265
- const value = this.textToValue(host.getText(editrange));
1266
- if (!value) {
1267
- return Promise.resolve(null);
1268
- }
1269
- this.fv = pxt.react.getFieldEditorView(this.getFieldEditorId(), value, this.getOptions());
1270
- this.fv.onHide(() => {
1271
- this.onClosed();
1272
- });
1273
- this.fv.show();
1274
- return new Promise((resolve, reject) => {
1275
- this.resolver = resolve;
1276
- this.rejecter = reject;
1277
- });
1278
- });
1279
- }
1280
- onClosed() {
1281
- if (this.resolver) {
1282
- this.resolver({
1283
- range: this.editrange,
1284
- replacement: this.resultToText(this.fv.getResult())
1285
- });
1286
- this.editrange = undefined;
1287
- this.resolver = undefined;
1288
- this.rejecter = undefined;
1289
- }
1290
- }
1291
- dispose() {
1292
- this.onClosed();
1293
- }
1294
- initAsync() {
1295
- return Promise.resolve();
1296
- }
1297
- textToValue(text) {
1298
- return null;
1299
- }
1300
- resultToText(result) {
1301
- return result + "";
1302
- }
1303
- getFieldEditorId() {
1304
- return "";
1305
- }
1306
- getOptions() {
1307
- return null;
1308
- }
1309
- }
1310
- editor.MonacoReactFieldEditor = MonacoReactFieldEditor;
1311
- })(editor = pxt.editor || (pxt.editor = {}));
1312
- })(pxt || (pxt = {}));
1313
- /// <reference path="./monacoFieldEditor.ts" />
1314
- /// <reference path="./field_react.ts" />
1315
- var pxt;
1316
- (function (pxt) {
1317
- var editor;
1318
- (function (editor) {
1319
- const fieldEditorId = "music-editor";
1320
- class MonacoSongEditor extends editor.MonacoReactFieldEditor {
1321
- textToValue(text) {
1322
- this.isPython = text.indexOf("`") === -1;
1323
- this.text = text;
1324
- const match = pxt.parseAssetTSReference(text);
1325
- if (match) {
1326
- const { type, name: matchedName } = match;
1327
- const name = matchedName.trim();
1328
- const project = pxt.react.getTilemapProject();
1329
- this.isAsset = true;
1330
- const asset = project.lookupAssetByName("song" /* pxt.AssetType.Song */, name);
1331
- if (asset) {
1332
- return asset;
1333
- }
1334
- else {
1335
- const newAsset = project.createNewSong(pxt.assets.music.getEmptySong(2));
1336
- if (name && !project.isNameTaken("song" /* pxt.AssetType.Song */, name) && pxt.validateAssetName(name)) {
1337
- newAsset.meta.displayName = name;
1338
- }
1339
- return newAsset;
1340
- }
1341
- }
1342
- const hexLiteralMatch = /hex\s*(?:`|\(""")\s*([a-fA-F0-9]*)\s*(?:`|"""\))\s*(?:;?)/m.exec(text);
1343
- if (hexLiteralMatch) {
1344
- const contents = hexLiteralMatch[1].trim();
1345
- if (contents) {
1346
- return createFakeAsset(pxt.assets.music.decodeSongFromHex(contents));
1347
- }
1348
- return createFakeAsset(pxt.assets.music.getEmptySong(2));
1349
- }
1350
- return undefined; // never
1351
- }
1352
- resultToText(result) {
1353
- var _a;
1354
- if ((_a = result.meta) === null || _a === void 0 ? void 0 : _a.displayName) {
1355
- const project = pxt.react.getTilemapProject();
1356
- if (this.isAsset || project.lookupAsset(result.type, result.id)) {
1357
- result = project.updateAsset(result);
1358
- }
1359
- else {
1360
- result = project.createNewSong(result.song, result.meta.displayName);
1361
- }
1362
- this.isAsset = true;
1363
- return pxt.getTSReferenceForAsset(result, this.isPython);
1364
- }
1365
- let hexString = pxt.assets.music.encodeSongToHex(result.song);
1366
- if (this.isPython) {
1367
- hexString = `hex("""${hexString}""")`;
1368
- }
1369
- else {
1370
- hexString = "hex`" + hexString + "`";
1371
- }
1372
- return this.text.replace(/hex\s*(?:`|\(""")\s*([a-fA-F0-9]*)\s*(?:`|"""\))\s*(?:;?)/m, hexString);
1373
- }
1374
- getFieldEditorId() {
1375
- return fieldEditorId;
1376
- }
1377
- getOptions() {
1378
- return {
1379
- blocksInfo: this.host.blocksInfo()
1380
- };
1381
- }
1382
- }
1383
- editor.MonacoSongEditor = MonacoSongEditor;
1384
- function createFakeAsset(song) {
1385
- return {
1386
- type: "song" /* pxt.AssetType.Song */,
1387
- id: "",
1388
- internalID: 0,
1389
- meta: {},
1390
- song
1391
- };
1392
- }
1393
- editor.songEditorDefinition = {
1394
- id: fieldEditorId,
1395
- foldMatches: true,
1396
- glyphCssClass: "fas fa-music sprite-focus-hover",
1397
- heightInPixels: 510,
1398
- matcher: {
1399
- /**
1400
- * This is horrendous-looking regex matches both the asset reference syntax:
1401
- * assets.song`name`
1402
- * assets.song("""name""")
1403
- *
1404
- * and the hex-literal syntax:
1405
- * music.createSong(hex`01234`
1406
- * music.create_song(hex("""01234""")
1407
- *
1408
- * For the hex literal matches, it includes the call to music.createSong since
1409
- * hex buffers can also be used for other things
1410
- */
1411
- searchString: "(?:(?:assets\\s*\\.\\s*song)|(?:music\\s*\\.\\s*create(?:S|_s)ong\\s*\\(\\s*hex))\\s*(?:`|\\(\\s*\"\"\")(?:(?:[^(){}:\\[\\]\"';?/,+\\-=*&|^%!`~]|\\n)*)\\s*(?:`|\"\"\"\\s*\\))",
1412
- isRegex: true,
1413
- matchCase: true,
1414
- matchWholeWord: false
1415
- },
1416
- proto: MonacoSongEditor
1417
- };
1418
- editor.registerMonacoFieldEditor(fieldEditorId, editor.songEditorDefinition);
1419
- })(editor = pxt.editor || (pxt.editor = {}));
1420
- })(pxt || (pxt = {}));
1421
- /// <reference path="./monacoFieldEditor.ts" />
1422
- /// <reference path="./field_react.ts" />
1423
- var pxt;
1424
- (function (pxt) {
1425
- var editor;
1426
- (function (editor) {
1427
- const fieldEditorId = "soundeffect-editor";
1428
- // music.createSoundEffect(WaveShape.Sine, 5000, 0, 255, 0, 500, SoundExpressionEffect.None, InterpolationCurve.Linear
1429
- class MonacoSoundEffectEditor extends editor.MonacoReactFieldEditor {
1430
- textToValue(text) {
1431
- const out = defaultSound();
1432
- this.value = out;
1433
- const argMatch = /\(([^)]*)\)/.exec(text);
1434
- const args = argMatch[1].split(",").map(a => a.replace(/\s/g, ""));
1435
- if (args.length !== 8)
1436
- return out;
1437
- switch (args[0]) {
1438
- case "WaveShape.Sawtooth":
1439
- out.wave = "sawtooth";
1440
- break;
1441
- case "WaveShape.Square":
1442
- out.wave = "square";
1443
- break;
1444
- case "WaveShape.Noise":
1445
- out.wave = "noise";
1446
- break;
1447
- case "WaveShape.Triangle":
1448
- out.wave = "triangle";
1449
- break;
1450
- case "WaveShape.Sine":
1451
- default:
1452
- out.wave = "sine";
1453
- break;
1454
- }
1455
- const withDefault = (val, def) => {
1456
- return isNaN(val) ? def : val;
1457
- };
1458
- out.startFrequency = withDefault(parseInt(args[1]), out.startFrequency);
1459
- out.endFrequency = withDefault(parseInt(args[2]), out.endFrequency);
1460
- out.startVolume = withDefault(parseInt(args[3]), out.startVolume);
1461
- out.endVolume = withDefault(parseInt(args[4]), out.endVolume);
1462
- out.duration = withDefault(parseInt(args[5]), out.duration);
1463
- switch (args[6]) {
1464
- case "SoundExpressionEffect.Vibrato":
1465
- out.effect = "vibrato";
1466
- break;
1467
- case "SoundExpressionEffect.Tremolo":
1468
- out.effect = "tremolo";
1469
- break;
1470
- case "SoundExpressionEffect.Warble":
1471
- out.effect = "warble";
1472
- break;
1473
- case "SoundExpressionEffect.None":
1474
- default:
1475
- out.effect = "none";
1476
- break;
1477
- }
1478
- switch (args[7]) {
1479
- case "InterpolationCurve.Logarithmic":
1480
- out.interpolation = "logarithmic";
1481
- break;
1482
- case "InterpolationCurve.Curve":
1483
- out.interpolation = "curve";
1484
- break;
1485
- case "InterpolationCurve.Linear":
1486
- default:
1487
- out.interpolation = "linear";
1488
- break;
1489
- }
1490
- return out;
1491
- }
1492
- resultToText(result) {
1493
- result = this.value;
1494
- let waveShape;
1495
- switch (result.wave) {
1496
- case "sine":
1497
- waveShape = "WaveShape.Sine";
1498
- break;
1499
- case "square":
1500
- waveShape = "WaveShape.Square";
1501
- break;
1502
- case "triangle":
1503
- waveShape = "WaveShape.Triangle";
1504
- break;
1505
- case "noise":
1506
- waveShape = "WaveShape.Noise";
1507
- break;
1508
- case "sawtooth":
1509
- waveShape = "WaveShape.Sawtooth";
1510
- break;
1511
- }
1512
- let effect;
1513
- switch (result.effect) {
1514
- case "vibrato":
1515
- effect = "SoundExpressionEffect.Vibrato";
1516
- break;
1517
- case "tremolo":
1518
- effect = "SoundExpressionEffect.Tremolo";
1519
- break;
1520
- case "warble":
1521
- effect = "SoundExpressionEffect.Warble";
1522
- break;
1523
- case "none":
1524
- effect = "SoundExpressionEffect.None";
1525
- break;
1526
- }
1527
- let interpolation;
1528
- switch (result.interpolation) {
1529
- case "curve":
1530
- interpolation = "InterpolationCurve.Curve";
1531
- break;
1532
- case "linear":
1533
- interpolation = "InterpolationCurve.Linear";
1534
- break;
1535
- case "logarithmic":
1536
- interpolation = "InterpolationCurve.Logarithmic";
1537
- break;
1538
- }
1539
- return `music.createSoundEffect(${waveShape}, ${Math.round(result.startFrequency)}, ${Math.round(result.endFrequency)}, ${Math.round(result.startVolume)}, ${Math.round(result.endVolume)}, ${Math.round(result.duration)}, ${effect}, ${interpolation})`;
1540
- }
1541
- getFieldEditorId() {
1542
- return fieldEditorId;
1543
- }
1544
- getOptions() {
1545
- return {
1546
- onClose: () => this.fv.hide(),
1547
- onSoundChange: (newValue) => this.value = newValue,
1548
- initialSound: this.value,
1549
- useFlex: true,
1550
- useMixerSynthesizer: pxt.appTarget.id !== "microbit" // FIXME
1551
- };
1552
- }
1553
- }
1554
- editor.MonacoSoundEffectEditor = MonacoSoundEffectEditor;
1555
- function validateRange(range, model) {
1556
- let currentLine = range.startLineNumber;
1557
- let currentColumn = 0;
1558
- let foundStart = false;
1559
- let parenCount = 0;
1560
- const methodName = "createSoundEffect";
1561
- const totalLines = model.getLineCount();
1562
- while (currentLine < totalLines) {
1563
- const lineContent = model.getLineContent(currentLine);
1564
- const startIndex = lineContent.indexOf(methodName);
1565
- if (startIndex !== -1) {
1566
- foundStart = true;
1567
- currentColumn = startIndex + methodName.length;
1568
- }
1569
- if (foundStart) {
1570
- while (currentColumn < lineContent.length) {
1571
- const currentChar = lineContent.charAt(currentColumn);
1572
- if (currentChar === "(") {
1573
- parenCount++;
1574
- }
1575
- else if (currentChar === ")") {
1576
- parenCount--;
1577
- if (parenCount === 0) {
1578
- return new monaco.Range(range.startLineNumber, range.startColumn, currentLine, currentColumn + model.getLineMinColumn(currentLine) + 1);
1579
- }
1580
- }
1581
- currentColumn++;
1582
- }
1583
- }
1584
- currentColumn = 0;
1585
- currentLine++;
1586
- }
1587
- return undefined;
1588
- }
1589
- function defaultSound() {
1590
- return {
1591
- wave: "sine",
1592
- startFrequency: 5000,
1593
- endFrequency: 0,
1594
- startVolume: 255,
1595
- endVolume: 0,
1596
- duration: 500,
1597
- effect: "none",
1598
- interpolation: "linear"
1599
- };
1600
- }
1601
- editor.soundEditorDefinition = {
1602
- id: fieldEditorId,
1603
- foldMatches: true,
1604
- glyphCssClass: "fas fa-music sprite-focus-hover",
1605
- heightInPixels: 510,
1606
- matcher: {
1607
- // match both JS and python
1608
- searchString: "music\\s*\\.\\s*createSoundEffect\\s*\\(",
1609
- isRegex: true,
1610
- matchCase: true,
1611
- matchWholeWord: false,
1612
- validateRange
1613
- },
1614
- proto: MonacoSoundEffectEditor
1615
- };
1616
- editor.registerMonacoFieldEditor(fieldEditorId, editor.soundEditorDefinition);
1617
- })(editor = pxt.editor || (pxt.editor = {}));
1618
- })(pxt || (pxt = {}));
1619
- /// <reference path="./monacoFieldEditor.ts" />
1620
- /// <reference path="./field_react.ts" />
1621
- var pxt;
1622
- (function (pxt) {
1623
- var editor;
1624
- (function (editor) {
1625
- const fieldEditorId = "image-editor";
1626
- class MonacoSpriteEditor extends editor.MonacoReactFieldEditor {
1627
- textToValue(text) {
1628
- this.isPython = text.indexOf("`") === -1;
1629
- const match = pxt.parseAssetTSReference(text);
1630
- if (match) {
1631
- const { type, name: matchedName } = match;
1632
- const name = matchedName.trim();
1633
- const project = pxt.react.getTilemapProject();
1634
- this.isAsset = true;
1635
- const asset = project.lookupAssetByName("image" /* pxt.AssetType.Image */, name);
1636
- if (asset) {
1637
- return asset;
1638
- }
1639
- else {
1640
- const newAsset = project.createNewImage();
1641
- if (name && !project.isNameTaken("image" /* pxt.AssetType.Image */, name) && pxt.validateAssetName(name)) {
1642
- newAsset.meta.displayName = name;
1643
- }
1644
- return newAsset;
1645
- }
1646
- }
1647
- return createFakeAsset(pxt.sprite.imageLiteralToBitmap(text));
1648
- }
1649
- resultToText(result) {
1650
- var _a;
1651
- if ((_a = result.meta) === null || _a === void 0 ? void 0 : _a.displayName) {
1652
- const project = pxt.react.getTilemapProject();
1653
- if (this.isAsset || project.lookupAsset(result.type, result.id)) {
1654
- result = project.updateAsset(result);
1655
- }
1656
- else {
1657
- result = project.createNewProjectImage(result.bitmap, result.meta.displayName);
1658
- }
1659
- this.isAsset = true;
1660
- return pxt.getTSReferenceForAsset(result, this.isPython);
1661
- }
1662
- return pxt.sprite.bitmapToImageLiteral(pxt.sprite.Bitmap.fromData(result.bitmap), this.isPython ? "python" : "typescript");
1663
- }
1664
- getFieldEditorId() {
1665
- return "image-editor";
1666
- }
1667
- getOptions() {
1668
- return {
1669
- initWidth: 16,
1670
- initHeight: 16,
1671
- blocksInfo: this.host.blocksInfo()
1672
- };
1673
- }
1674
- }
1675
- editor.MonacoSpriteEditor = MonacoSpriteEditor;
1676
- function createFakeAsset(bitmap) {
1677
- return {
1678
- type: "image" /* pxt.AssetType.Image */,
1679
- id: "",
1680
- internalID: 0,
1681
- bitmap: bitmap.data(),
1682
- meta: {},
1683
- jresData: ""
1684
- };
1685
- }
1686
- editor.spriteEditorDefinition = {
1687
- id: fieldEditorId,
1688
- foldMatches: true,
1689
- glyphCssClass: "sprite-editor-glyph sprite-focus-hover",
1690
- heightInPixels: 510,
1691
- matcher: {
1692
- // match both JS and python
1693
- searchString: "(?:img|assets\\s*\\.\\s*image)\\s*(?:`|\\(\\s*\"\"\")(?:(?:[^(){}:\\[\\]\"';?/,+\\-=*&|^%!`~]|\\n)*)\\s*(?:`|\"\"\"\\s*\\))",
1694
- isRegex: true,
1695
- matchCase: true,
1696
- matchWholeWord: false
1697
- },
1698
- proto: MonacoSpriteEditor
1699
- };
1700
- editor.registerMonacoFieldEditor(fieldEditorId, editor.spriteEditorDefinition);
1701
- })(editor = pxt.editor || (pxt.editor = {}));
1702
- })(pxt || (pxt = {}));
1703
- /// <reference path="./monacoFieldEditor.ts" />
1704
- /// <reference path="./field_react.ts" />
1705
- var pxt;
1706
- (function (pxt) {
1707
- var editor;
1708
- (function (editor) {
1709
- const fieldEditorId = "tilemap-editor";
1710
- class MonacoTilemapEditor extends editor.MonacoReactFieldEditor {
1711
- textToValue(text) {
1712
- const tm = this.readTilemap(text);
1713
- const project = pxt.react.getTilemapProject();
1714
- pxt.sprite.addMissingTilemapTilesAndReferences(project, tm);
1715
- return tm;
1716
- }
1717
- readTilemap(text) {
1718
- const project = pxt.react.getTilemapProject();
1719
- if (/^\s*tiles\s*\./.test(text)) {
1720
- this.isTilemapLiteral = false;
1721
- if (text) {
1722
- try {
1723
- const data = pxt.sprite.decodeTilemap(text, "typescript", project);
1724
- return createFakeAsset(data);
1725
- }
1726
- catch (e) {
1727
- // If the user is still typing, they might try to open the editor on an incomplete tilemap
1728
- }
1729
- return null;
1730
- }
1731
- }
1732
- this.isTilemapLiteral = true;
1733
- // This matches the regex for the field editor, so it should always match
1734
- const match = /^\s*(tilemap(?:8|16|32)?)\s*(?:`([^`]*)`)|(?:\(\s*"""([^"]*)"""\s*\))\s*$/.exec(text);
1735
- const name = (match[2] || match[3] || "").trim();
1736
- this.tilemapLiteral = match[1];
1737
- let proj;
1738
- let id;
1739
- if (name) {
1740
- id = ts.pxtc.escapeIdentifier(name);
1741
- proj = project.getTilemap(id) || project.lookupAssetByName("tilemap" /* AssetType.Tilemap */, name);
1742
- }
1743
- if (!proj) {
1744
- let tileWidth = 16;
1745
- if (this.tilemapLiteral === "tilemap8") {
1746
- tileWidth = 8;
1747
- }
1748
- else if (this.tilemapLiteral === "tilemap32") {
1749
- tileWidth = 32;
1750
- }
1751
- const [name] = project.createNewTilemap(id, tileWidth, 16, 16);
1752
- proj = project.getTilemap(name);
1753
- id = name;
1754
- }
1755
- return proj;
1756
- }
1757
- resultToText(asset) {
1758
- const project = pxt.react.getTilemapProject();
1759
- project.pushUndo();
1760
- pxt.sprite.updateTilemapReferencesFromResult(project, asset);
1761
- if (this.isTilemapLiteral) {
1762
- project.updateAsset(asset);
1763
- return pxt.getTSReferenceForAsset(asset, this.fileType === "python");
1764
- }
1765
- else {
1766
- return pxt.sprite.encodeTilemap(asset.data, this.fileType === "typescript" ? "typescript" : "python");
1767
- }
1768
- }
1769
- getFieldEditorId() {
1770
- return "tilemap-editor";
1771
- }
1772
- getOptions() {
1773
- return {
1774
- initWidth: 16,
1775
- initHeight: 16,
1776
- blocksInfo: this.host.blocksInfo()
1777
- };
1778
- }
1779
- getCreateTilemapRange() {
1780
- const start = this.editrange.getStartPosition();
1781
- let current = this.editrange.getEndPosition();
1782
- let range;
1783
- let openParen = 1;
1784
- while (true) {
1785
- range = new monaco.Range(current.lineNumber, current.column, current.lineNumber + 1, 0);
1786
- const line = this.host.getText(range);
1787
- for (let i = 0; i < line.length; i++) {
1788
- if (line.charAt(i) === "(") {
1789
- openParen++;
1790
- }
1791
- else if (line.charAt(i) === ")") {
1792
- openParen--;
1793
- if (openParen === 0) {
1794
- const end = new monaco.Position(current.lineNumber, current.column + i + 2);
1795
- return monaco.Range.fromPositions(start, end);
1796
- }
1797
- }
1798
- }
1799
- current = range.getEndPosition();
1800
- if (current.lineNumber > start.lineNumber + 20) {
1801
- return null;
1802
- }
1803
- }
1804
- }
1805
- }
1806
- editor.MonacoTilemapEditor = MonacoTilemapEditor;
1807
- function createFakeAsset(data) {
1808
- return {
1809
- type: "tilemap" /* pxt.AssetType.Tilemap */,
1810
- id: "",
1811
- internalID: 0,
1812
- meta: {},
1813
- data
1814
- };
1815
- }
1816
- editor.tilemapEditorDefinition = {
1817
- id: fieldEditorId,
1818
- foldMatches: true,
1819
- alwaysBuildOnClose: true,
1820
- glyphCssClass: "sprite-focus-hover ms-Icon ms-Icon--Nav2DMapView",
1821
- heightInPixels: 510,
1822
- weight: 5,
1823
- matcher: {
1824
- // match both JS and python
1825
- searchString: "(?:tilemap(?:8|16|32)?\\s*(?:`|\\(\"\"\")(?:[ a-zA-Z0-9_]|\\n)*\\s*(?:`|\"\"\"\\)))|(?:tiles\\s*\\.\\s*createTilemap\\s*\\([^\\)]+\\))",
1826
- isRegex: true,
1827
- matchCase: true,
1828
- matchWholeWord: false
1829
- },
1830
- proto: MonacoTilemapEditor
1831
- };
1832
- editor.registerMonacoFieldEditor(fieldEditorId, editor.tilemapEditorDefinition);
1833
- })(editor = pxt.editor || (pxt.editor = {}));
1834
- })(pxt || (pxt = {}));