Skip to content

Commit d15df70

Browse files
eanders-msjwunderl
andauthored
pxt-core changes for bedrock target (#10475)
* pxt-bedrock initial prototype * add editor extension point * fix tests * rename * rename * hide sim, no hex download * launch config * support shimmed properties * update timer calls * runtime tweaks * make driver optional * better support for static methods * tweaks to RefRecord * Add `unfetteredInitializers` compiler option * make runtime more friendly to native types * expose compiler build task * update extension point * support for multi-step dialog * add editor extension init call * add nonEscapable dialog param * lint * return compilerresult from typecheck * rework extension points * header change listener * remove duplicate flag * whitespace * revert formatting change * revert unneeded change * revert type change * revert more things * another revert * driver null check * fix decompiler * bring back download button * cdn script preload * 10.1.0 * cli: default to "shell: true" when spawning child process on win32 * flag to hide run button * 10.1.1 * restore message listeners * 10.1.2 * tweaks * asyncify typecheckasync, fix workerOpAsync return value * [WIP] start on electron file deploy (#10183) * start on file deploy * throw on error * 10.1.3 * Add generated name mirrored from vscode-edu (#10186) * Add generated name mirrored from vscode-edu * prefill in open screen * 10.1.4 * show downloadmenuitems in cogwheel if headless (#10187) * string-valued enums, etc. * stringify * 10.1.5 * lint * 10.1.6 * add bin to package.json * 10.1.7 * update launch script * stub node services * lint * 10.1.8 * 10.1.9 * add rollup * support wasm * 10.1.10 * undo * 10.1.11 * fix merge * scoped value selector * whitespace * remove unneeded deps * restore error message * remove timer stuff * cleanup * sim display tweaks * remove unneeded change * unfettered check * restore return type * remove dup flag * rollback unrelated changes * remove unrelated changes * restore missing API * resolve merge issues * fix typecheckAsync * address PR feedback * revert * close dropdown on item click * use a ref * better "closeOnClick" impl for DropDownMenu * whitespace --------- Co-authored-by: Joey Wunderlich <jowunder@microsoft.com> Co-authored-by: Joey Wunderlich <jwunderl@users.noreply.github.com>
1 parent 31f5932 commit d15df70

31 files changed

+548
-75
lines changed

.vscode/launch.json

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,21 @@
11
{
22
"version": "0.2.0",
33
"configurations": [
4+
{
5+
"name": "codegen (pxt-bedrock)",
6+
"type": "node",
7+
"request": "launch",
8+
"runtimeArgs": [
9+
"run-script",
10+
"vscode:debug"
11+
],
12+
"runtimeExecutable": "npm",
13+
"stopOnEntry": false,
14+
"sourceMaps": true,
15+
"outFiles": [],
16+
"localRoot": "${workspaceRoot}/../pxt-bedrock/codegen",
17+
"console": "integratedTerminal"
18+
},
419
{
520
"name": "pxt ci (pxt-core)",
621
"type": "node",
@@ -65,6 +80,27 @@
6580
"sourceMaps": false,
6681
"outFiles": []
6782
},
83+
{
84+
"name": "pxt ci (bedrock)",
85+
"type": "node",
86+
"request": "launch",
87+
"program": "${workspaceRoot}/built/pxt.js",
88+
"stopOnEntry": false,
89+
"args": [
90+
"ci",
91+
],
92+
"cwd": "${workspaceRoot}/../pxt-bedrock",
93+
"runtimeExecutable": null,
94+
"runtimeArgs": [
95+
"--nolazy"
96+
],
97+
"env": {
98+
"NODE_ENV": "development"
99+
},
100+
"console": "integratedTerminal",
101+
"sourceMaps": false,
102+
"outFiles": []
103+
},
68104
{
69105
"name": "pxt serve (microbit)",
70106
"type": "node",
@@ -115,6 +151,28 @@
115151
"sourceMaps": false,
116152
"outFiles": []
117153
},
154+
{
155+
"name": "pxt serve (bedrock)",
156+
"type": "node",
157+
"request": "launch",
158+
"program": "${workspaceRoot}/built/pxt.js",
159+
"stopOnEntry": false,
160+
"args": [
161+
"serve",
162+
"--debug"
163+
],
164+
"cwd": "${workspaceRoot}/../pxt-bedrock",
165+
"runtimeExecutable": null,
166+
"runtimeArgs": [
167+
"--nolazy"
168+
],
169+
"env": {
170+
"NODE_ENV": "development"
171+
},
172+
"console": "integratedTerminal",
173+
"sourceMaps": false,
174+
"outFiles": []
175+
},
118176
{
119177
"name": "rebundle",
120178
"type": "node",

docs/static/icons/ts-logo-512.svg

Lines changed: 1 addition & 0 deletions
Loading

localtypings/pxtarget.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ declare namespace pxt {
261261
stopOnChange?: boolean;
262262
emptyRunCode?: string; // when non-empty and autoRun is disabled, this code is run upon simulator first start
263263
hideRestart?: boolean;
264+
hideRun?: boolean;
264265
// moved to theme
265266
// moved to theme
266267
// debugger?: boolean;
@@ -774,6 +775,7 @@ declare namespace ts.pxtc {
774775
utf8?: boolean;
775776
switches: CompileSwitches;
776777
deployDrives?: string; // partial name of drives where the .hex file should be copied
778+
fileDeployPaths?: pxt.Map<string>; // Path IDs => path for file deployments
777779
deployFileMarker?: string;
778780
shortPointers?: boolean; // set to true for 16 bit pointers
779781
flashCodeAlign?: number; // defaults to 1k
@@ -796,6 +798,7 @@ declare namespace ts.pxtc {
796798
debugMode?: boolean; // set dynamically, not in config
797799
compilerExtension?: string; // JavaScript code to load in compiler
798800
shimRenames?: pxt.Map<string>;
801+
unfetteredInitializers?: boolean; // removes isNumericLiteral check on default argument values
799802
}
800803

801804
type BlockContentPart = BlockLabel | BlockParameter | BlockImage;
@@ -1123,6 +1126,7 @@ declare namespace ts.pxtc {
11231126

11241127
/* @internal */
11251128
ignoreFileResolutionErrors?: boolean; // ignores triple-slash directive errors; debug only
1129+
unfetteredInitializers?: boolean; // removes isNumericLiteral check on default argument values
11261130
}
11271131

11281132
interface BuiltSimJsInfo {

localtypings/pxteditor.d.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1148,9 +1148,17 @@ declare namespace pxt.editor {
11481148
monacoToolbox?: ToolboxDefinition;
11491149
}
11501150

1151+
export interface ExtensionInitOptions {
1152+
confirmAsync: (options: any) => Promise<number>;
1153+
infoNotification: (msg: string) => void;
1154+
warningNotification: (msg: string) => void;
1155+
errorNotification: (msg: string) => void;
1156+
}
1157+
11511158
export interface ExtensionResult {
11521159
hexFileImporters?: IHexFileImporter[];
11531160
resourceImporters?: IResourceImporter[];
1161+
initAsync?: (opts: ExtensionInitOptions) => Promise<void>;
11541162
beforeCompile?: () => void;
11551163
patchCompileResultAsync?: (r: pxtc.CompileResult) => Promise<void>;
11561164
deployAsync?: (r: pxtc.CompileResult) => Promise<void>;
@@ -1165,6 +1173,11 @@ declare namespace pxt.editor {
11651173
blocklyPatch?: (pkgTargetVersion: string, dom: Element) => void;
11661174
webUsbPairDialogAsync?: (pairAsync: () => Promise<boolean>, confirmAsync: (options: any) => Promise<number>) => Promise<number>;
11671175
mkPacketIOWrapper?: (io: pxt.packetio.PacketIO) => pxt.packetio.PacketIOWrapper;
1176+
getDownloadMenuItems?: () => any[]; /* sui.ItemProps[] */
1177+
notifyProjectCompiled?: (headerId: string, compileResult: pxtc.CompileResult) => void;
1178+
notifyProjectSaved?: (header: pxt.workspace.Header) => void;
1179+
onDownloadButtonClick?: () => Promise<void>;
1180+
getDefaultProjectName?: () => string; // If defined, replaces 'Untitled' as the default project name
11681181
onPostHostMessage?: (msg: pxt.editor.EditorMessageRequest) => void;
11691182
perfMeasurementThresholdMs?: number;
11701183
onPerfMilestone?: (payload: { milestone: string, time: number, params?: Map<string> }) => void;

localtypings/pxtelectron.d.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ declare namespace pxt.electron {
66
banned?: string[];
77
timeStamp?: string; // In the format of (new Date()).toISOString()
88
isDriveDeployBanned?: boolean;
9+
isFileDeployBanned?: boolean;
910
}
1011

1112
export const enum UpdateStatus {
@@ -50,18 +51,26 @@ declare namespace pxt.electron {
5051
configData?: any[];
5152
}
5253

54+
// Request to deploy files to a specified location
55+
export interface FileDeployRequest {
56+
location: string; // id for location to attempt to deploy to
57+
files: pxt.Map<string>; // Files to write, key is filename in subpath, value is b64 file content
58+
}
59+
5360
// The object that gets injected into the window
5461
export interface PxtElectron {
5562
onTelemetry: (handler: (ev: TelemetryEvent) => void) => void; // Registers a handler to invoke when the app shell requests a telemetry event to be sent to AI.
5663
onUpdateInstalled: (handler: () => void) => void; // Registers a handler to invoke when the app shell notifies that an update was installed.
5764
onUpdateStatus: (handler: (st: UpdateStatus) => void) => void; // Registers a handler to invoke when the app shell replies with the current update status.
5865
onCriticalUpdateFailed: (handler: () => void) => void; // Registers a handler to invoke when the app shell notifies us that a critical update has failed.
5966
onDriveDeployResult: (handler: (isSuccess: boolean) => void) => void; // Registers a handler to invoke when the app shell replies with the result of the last drive deploy attempt.
67+
onFileDeployResult: (handler: (isSuccess: boolean) => void) => void; // Registers a handler to invoke when the app shell replies with the result of the last file deploy attempt.
6068

6169
sendUpdateStatusCheck: () => void; // Asks the app shell about the current update status. The answer will come as a separate, asynchronous message.
6270
sendQuit: () => void; // Asks the app shell to quit.
6371
sendOpenDevTools: () => void; // Asks the app shell to open dev tools.
6472
sendDriveDeploy: (compileResult: CompileResult) => void; // Asks the app to deploy the program to the device via USB file copy.
73+
sendFileDeploy: (files: FileDeployRequest) => void // Asks the app to deploy the given files to a known folder.
6574
versions: VersionInfo; // Various versions for telemetry base properties
6675
}
6776
}

pxtblocks/fields/fieldEditorRegistry.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import { FieldMusicEditor } from "./field_musiceditor";
3030
import { FieldSoundEffect } from "./field_sound_effect";
3131
import { FieldAutoComplete } from "./field_autocomplete";
3232
import { FieldColorWheel } from "./field_colorwheel";
33+
import { FieldScopedValueSelector } from "./field_scopedvalueselector";
3334

3435
interface FieldEditorOptions {
3536
field: FieldCustomConstructor;
@@ -66,6 +67,7 @@ export function initFieldEditors() {
6667
registerFieldEditor('melody', FieldCustomMelody);
6768
registerFieldEditor('soundeffect', FieldSoundEffect);
6869
registerFieldEditor('autocomplete', FieldAutoComplete);
70+
registerFieldEditor('scopedvalueselector', FieldScopedValueSelector);
6971
if (pxt.appTarget.appTheme?.songEditor) {
7072
registerFieldEditor('musiceditor', FieldMusicEditor);
7173
}
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
/// <reference path="../../built/pxtlib.d.ts" />
2+
3+
import * as Blockly from "blockly";
4+
import { FieldCustom, FieldCustomOptions, setBlockDataForField, getBlockDataForField } from "./field_utils";
5+
6+
interface FieldScopedValueSelectorOptions extends FieldCustomOptions {
7+
defl?: string;
8+
type?: string;
9+
types?: string; // comma separated list
10+
}
11+
12+
export class FieldScopedValueSelector extends Blockly.FieldLabel implements FieldCustom {
13+
public isFieldCustom_ = true;
14+
defl: string | undefined;
15+
types: string[] = [];
16+
scopedValue: string | undefined;
17+
dragging = false;
18+
19+
constructor(value: string, params: FieldScopedValueSelectorOptions) {
20+
super(value);
21+
this.defl = params.defl;
22+
if (params.types) this.types = params.types.split(",");
23+
else if (params.type) this.types = [params.type];
24+
this.types = this.types.map(t => t.trim().replace(/['"]+/g, ""));
25+
}
26+
27+
init(): void {
28+
super.init();
29+
if (this.sourceBlock_) {
30+
this.scopedValue = getBlockDataForField(this.sourceBlock_, "scopedValue");
31+
this.sourceBlock_.workspace.addChangeListener(this.onWorkspaceChange);
32+
}
33+
}
34+
35+
dispose(): void {
36+
if (this.sourceBlock_) {
37+
this.sourceBlock_.workspace.removeChangeListener(this.onWorkspaceChange);
38+
}
39+
super.dispose();
40+
}
41+
42+
getValue(): string | null {
43+
// compiler emits into typescript
44+
if (this.sourceBlock_?.isInFlyout) {
45+
return lf("(dynamic)");
46+
} else if (this.dragging) {
47+
return lf("what will it be?");
48+
}
49+
if (this.sourceBlock_ && !this.scopedValue) {
50+
this.scopedValue = getBlockDataForField(this.sourceBlock_, "scopedValue");
51+
}
52+
return this.scopedValue || this.defl || lf("unknown");
53+
}
54+
55+
setValue(newValue: any, fireChangeEvent?: boolean): void {
56+
this.scopedValue = newValue || this.defl || lf("unknown");
57+
if (this.sourceBlock_)
58+
setBlockDataForField(this.sourceBlock_, "scopedValue", this.scopedValue || "");
59+
super.setValue(this.scopedValue, fireChangeEvent);
60+
this.forceRerender();
61+
}
62+
63+
onDragEvent = (ev: Blockly.Events.BlockDrag) => {
64+
// Make sure our block is in the event
65+
const block = ev.blocks.find(b => b.id === this.sourceBlock_.id);
66+
if (!block) return;
67+
68+
this.dragging = ev.isStart;
69+
if (ev.isStart) {
70+
this.forceRerender();
71+
return;
72+
}
73+
74+
// gather all scopes where we might find a compatible value
75+
const scopes: Blockly.Block[] = [];
76+
{
77+
let parent = this.sourceBlock_.getParent()?.getParent();
78+
while (parent) {
79+
scopes.push(parent);
80+
parent = parent.getParent();
81+
}
82+
}
83+
84+
const getCodeCard = (block: Blockly.Block): pxt.CodeCard => {
85+
return (block as any).codeCard;
86+
}
87+
88+
const apiInfos = pxt.getBundledApiInfo();
89+
const getSymbolInfo = (block: Blockly.Block): ts.pxtc.SymbolInfo | undefined => {
90+
const card = getCodeCard(block);
91+
if (!card || !card.name) return null;
92+
// check each entry in apiInfo
93+
for (const info of Object.values(apiInfos)) {
94+
if (info.apis.byQName[card.name]) {
95+
return info.apis.byQName[card.name];
96+
}
97+
}
98+
return undefined;
99+
}
100+
101+
// find the value in the scopes
102+
this.scopedValue = null;
103+
for (const scope of scopes) {
104+
if (scope.type === "variables_set") {
105+
const inputList = scope.inputList;
106+
const input = inputList.find(i => i.name === "VALUE");
107+
if (!input) continue;
108+
const fieldRow = input.fieldRow;
109+
if (!fieldRow) continue;
110+
const field = fieldRow.find(f => f.name === "VAR") as Blockly.FieldVariable;
111+
if (!field) continue;
112+
const variable = field.getVariable();
113+
if (!variable) continue;
114+
//if (this.types.includes(variable.type)) {
115+
{
116+
return this.setValue(variable.name);
117+
}
118+
continue;
119+
}
120+
const symbol = getSymbolInfo(scope);
121+
if (!symbol) continue;
122+
for (const parameter of symbol.parameters) {
123+
if (parameter.handlerParameters) {
124+
for (const handlerParameter of parameter.handlerParameters) {
125+
if (this.types.includes(handlerParameter.type)) {
126+
return this.setValue(handlerParameter.name);
127+
}
128+
}
129+
}
130+
}
131+
}
132+
this.setValue(this.defl);
133+
}
134+
135+
onWorkspaceChange = (ev: Blockly.Events.Abstract) => {
136+
if (!this.sourceBlock_ || !this.sourceBlock_.workspace || this.sourceBlock_.disposed) return;
137+
if (ev.type === Blockly.Events.BLOCK_DRAG) return this.onDragEvent(ev as Blockly.Events.BlockDrag);
138+
}
139+
}

pxtblocks/loader.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,8 @@ function isSubtype(apis: pxtc.ApisInfo, specific: string, general: string) {
204204

205205
function initBlock(block: Blockly.Block, info: pxtc.BlocksInfo, fn: pxtc.SymbolInfo, comp: pxt.blocks.BlockCompileInfo) {
206206
const ns = (fn.attributes.blockNamespace || fn.namespace).split('.')[0];
207-
const instance = fn.kind == pxtc.SymbolKind.Method || fn.kind == pxtc.SymbolKind.Property;
207+
let instance = fn.kind == pxtc.SymbolKind.Method || fn.kind == pxtc.SymbolKind.Property;
208+
if (typeof fn.isInstance === "boolean" && !fn.attributes?.defaultInstance) instance = fn.isInstance;
208209
const nsinfo = info.apis.byQName[ns];
209210
const color =
210211
// blockNamespace overrides color on block

pxtcompiler/emitter/backjs.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,7 @@ function ${id}(s) {
426426
else if (e.data === null) return "null"
427427
else if (e.data === undefined) return "undefined"
428428
else if (typeof e.data == "number") return e.data + ""
429+
else if (typeof e.data == "string") return `"${e.data}"`
429430
else throw oops("invalid data: " + typeof e.data);
430431
case EK.PointerLiteral:
431432
if (e.ptrlabel()) {

0 commit comments

Comments
 (0)