Skip to content

Commit ee42fa1

Browse files
committed
First pass at handling parameters
1 parent c59cff7 commit ee42fa1

File tree

4 files changed

+520
-114
lines changed

4 files changed

+520
-114
lines changed

src/blocks/mrc_class_method_def.ts

Lines changed: 114 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import * as Blockly from 'blockly';
2323
import { MRC_STYLE_CLASS_BLOCKS } from '../themes/styles';
2424
import { createFieldNonEditableText } from '../fields/FieldNonEditableText'
25+
import { createFieldFlydown } from '../fields/field_flydown';
2526
import * as ChangeFramework from './utils/change_framework'
2627
import { getLegalName } from './utils/python';
2728
import { Order } from 'blockly/python';
@@ -31,7 +32,7 @@ import { renameMethodCallers, mutateMethodCallers } from './mrc_call_python_func
3132
export const BLOCK_NAME = 'mrc_class_method_def';
3233

3334
export const MUTATOR_BLOCK_NAME = 'methods_mutatorarg';
34-
const PARAM_CONTAINER_BLOCK_NAME = 'method_param_container';
35+
const PARAM_CONTAINER_BLOCK_NAME = 'method_param_container';
3536

3637
export type Parameter = {
3738
name: string,
@@ -87,8 +88,7 @@ const CLASS_METHOD_DEF = {
8788
*/
8889
init: function (this: ClassMethodDefBlock): void {
8990
this.appendDummyInput("TITLE")
90-
.appendField('', 'NAME')
91-
.appendField('', 'PARAMS');
91+
.appendField('', 'NAME');
9292
this.setOutput(false);
9393
this.setStyle(MRC_STYLE_CLASS_BLOCKS);
9494
this.appendStatementInput('STACK').appendField('');
@@ -147,11 +147,11 @@ const CLASS_METHOD_DEF = {
147147
updateBlock_: function (this: ClassMethodDefBlock): void {
148148
const name = this.getFieldValue('NAME');
149149
const input = this.getInput('TITLE');
150-
if (!input){
150+
if (!input) {
151151
return;
152152
}
153153
input.removeField('NAME');
154-
154+
155155
if (this.mrcCanChangeSignature) {
156156
const nameField = new Blockly.FieldTextInput(name);
157157
input.insertFieldAt(0, nameField, 'NAME');
@@ -161,7 +161,7 @@ const CLASS_METHOD_DEF = {
161161
else {
162162
input.insertFieldAt(0, createFieldNonEditableText(name), 'NAME');
163163
//Case because a current bug in blockly where it won't allow passing null to Blockly.Block.setMutator makes it necessary.
164-
(this as Blockly.BlockSvg).setMutator( null );
164+
(this as Blockly.BlockSvg).setMutator(null);
165165
}
166166
this.mrcUpdateParams();
167167
},
@@ -171,9 +171,9 @@ const CLASS_METHOD_DEF = {
171171

172172
let paramBlock = containerBlock.getInputTargetBlock('STACK');
173173
while (paramBlock && !paramBlock.isInsertionMarker()) {
174-
const param : Parameter = {
175-
name : paramBlock.getFieldValue('NAME'),
176-
type : ''
174+
const param: Parameter = {
175+
name: paramBlock.getFieldValue('NAME'),
176+
type: ''
177177
}
178178
this.mrcParameters.push(param);
179179
paramBlock =
@@ -201,40 +201,41 @@ const CLASS_METHOD_DEF = {
201201
}
202202
return topBlock;
203203
},
204-
mrcUpdateParams: function (this : ClassMethodDefBlock) {
205-
let paramString = '';
206-
if (this.mrcParameters.length > 0){
207-
this.mrcParameters.forEach((param) => {
208-
if (paramString != '') {
209-
paramString += ', ';
210-
}
211-
paramString += param.name;
212-
});
213-
paramString = Blockly.Msg['PROCEDURES_BEFORE_PARAMS'] + ' ' + paramString;
214-
}
215-
// The params field is deterministic based on the mutation,
216-
// no need to fire a change event.
217-
Blockly.Events.disable();
218-
try {
219-
this.setFieldValue(paramString, 'PARAMS');
220-
} finally {
221-
Blockly.Events.enable();
204+
mrcUpdateParams: function (this: ClassMethodDefBlock) {
205+
if (this.mrcParameters.length > 0) {
206+
let input = this.getInput('TITLE');
207+
if (input) {
208+
this.removeParameterFields(input);
209+
this.mrcParameters.forEach((param) => {
210+
const paramName = 'PARAM_' + param.name;
211+
input.appendField(createFieldFlydown(param.name, false), paramName);
212+
});
213+
}
222214
}
223215
},
216+
removeParameterFields: function (input: Blockly.Input) {
217+
const fieldsToRemove = input.fieldRow
218+
.filter(field => field.name?.startsWith('PARAM_'))
219+
.map(field => field.name!);
220+
221+
fieldsToRemove.forEach(fieldName => {
222+
input.removeField(fieldName);
223+
});
224+
},
224225
mrcNameFieldValidator(this: ClassMethodDefBlock, nameField: Blockly.FieldTextInput, name: string): string {
225-
// When the user changes the method name on the block, clear the mrcPythonMethodName field.
226-
this.mrcPythonMethodName = '';
227-
228-
// Strip leading and trailing whitespace.
229-
name = name.trim();
230-
231-
const legalName = findLegalMethodName(name, this);
232-
const oldName = nameField.getValue();
233-
if (oldName && oldName !== name && oldName !== legalName) {
234-
// Rename any callers.
235-
renameMethodCallers(this.workspace, oldName, legalName);
236-
}
237-
return legalName;
226+
// When the user changes the method name on the block, clear the mrcPythonMethodName field.
227+
this.mrcPythonMethodName = '';
228+
229+
// Strip leading and trailing whitespace.
230+
name = name.trim();
231+
232+
const legalName = findLegalMethodName(name, this);
233+
const oldName = nameField.getValue();
234+
if (oldName && oldName !== name && oldName !== legalName) {
235+
// Rename any callers.
236+
renameMethodCallers(this.workspace, oldName, legalName);
237+
}
238+
return legalName;
238239
},
239240
};
240241

@@ -248,21 +249,21 @@ const CLASS_METHOD_DEF = {
248249
* @returns Non-colliding name.
249250
*/
250251
function findLegalMethodName(name: string, block: ClassMethodDefBlock): string {
251-
if (block.isInFlyout) {
252-
// Flyouts can have multiple methods called 'my_method'.
253-
return name;
254-
}
255-
name = name || 'unnamed';
256-
while (isMethodNameUsed(name, block.workspace, block)) {
257-
// Collision with another method.
258-
const r = name.match(/^(.*?)(\d+)$/);
259-
if (!r) {
260-
name += '2';
261-
} else {
262-
name = r[1] + (parseInt(r[2]) + 1);
252+
if (block.isInFlyout) {
253+
// Flyouts can have multiple methods called 'my_method'.
254+
return name;
263255
}
264-
}
265-
return name;
256+
name = name || 'unnamed';
257+
while (isMethodNameUsed(name, block.workspace, block)) {
258+
// Collision with another method.
259+
const r = name.match(/^(.*?)(\d+)$/);
260+
if (!r) {
261+
name += '2';
262+
} else {
263+
name = r[1] + (parseInt(r[2]) + 1);
264+
}
265+
}
266+
return name;
266267
}
267268

268269
/**
@@ -276,25 +277,25 @@ function findLegalMethodName(name: string, block: ClassMethodDefBlock): string {
276277
*/
277278
function isMethodNameUsed(
278279
name: string, workspace: Blockly.Workspace, opt_exclude?: Blockly.Block): boolean {
279-
const nameLowerCase = name.toLowerCase();
280-
for (const block of workspace.getBlocksByType('mrc_class_method_def')) {
281-
if (block === opt_exclude) {
282-
continue;
283-
}
284-
if (nameLowerCase === block.getFieldValue('NAME').toLowerCase()) {
285-
return true;
286-
}
287-
const classMethodDefBlock = block as ClassMethodDefBlock;
288-
if (classMethodDefBlock.mrcPythonMethodName &&
289-
nameLowerCase === classMethodDefBlock.mrcPythonMethodName.toLowerCase()) {
290-
return true;
280+
const nameLowerCase = name.toLowerCase();
281+
for (const block of workspace.getBlocksByType('mrc_class_method_def')) {
282+
if (block === opt_exclude) {
283+
continue;
284+
}
285+
if (nameLowerCase === block.getFieldValue('NAME').toLowerCase()) {
286+
return true;
287+
}
288+
const classMethodDefBlock = block as ClassMethodDefBlock;
289+
if (classMethodDefBlock.mrcPythonMethodName &&
290+
nameLowerCase === classMethodDefBlock.mrcPythonMethodName.toLowerCase()) {
291+
return true;
292+
}
291293
}
292-
}
293-
return false;
294+
return false;
294295
}
295296

296297
const METHOD_PARAM_CONTAINER = {
297-
init: function (this : Blockly.Block) {
298+
init: function (this: Blockly.Block) {
298299
this.appendDummyInput("TITLE").appendField('Parameters');
299300
this.appendStatementInput('STACK');
300301
this.setStyle(MRC_STYLE_CLASS_BLOCKS);
@@ -303,12 +304,12 @@ const METHOD_PARAM_CONTAINER = {
303304
};
304305

305306
type MethodMutatorArgBlock = Blockly.Block & MethodMutatorArgMixin & Blockly.BlockSvg;
306-
interface MethodMutatorArgMixin extends MethodMutatorArgMixinType{
307+
interface MethodMutatorArgMixin extends MethodMutatorArgMixinType {
307308

308309
}
309310
type MethodMutatorArgMixinType = typeof METHODS_MUTATORARG;
310311

311-
function setName(block: Blockly.BlockSvg){
312+
function setName(block: Blockly.BlockSvg) {
312313
const parentBlock = ChangeFramework.getParentOfType(block, PARAM_CONTAINER_BLOCK_NAME);
313314
if (parentBlock) {
314315
const variableBlocks = parentBlock!.getDescendants(true)
@@ -318,14 +319,14 @@ function setName(block: Blockly.BlockSvg){
318319
otherNames.push(variableBlock.getFieldValue('NAME'));
319320
}
320321
});
321-
const currentName = block.getFieldValue('NAME');
322+
const currentName = block.getFieldValue('NAME');
322323
block.setFieldValue(getLegalName(currentName, otherNames), 'NAME');
323324
updateMutatorFlyout(block.workspace);
324325
}
325326
}
326327

327328
const METHODS_MUTATORARG = {
328-
init: function (this : MethodMutatorArgBlock) {
329+
init: function (this: MethodMutatorArgBlock) {
329330
this.appendDummyInput()
330331
.appendField(new Blockly.FieldTextInput(Blockly.Procedures.DEFAULT_ARG), 'NAME');
331332
this.setPreviousStatement(true);
@@ -335,17 +336,17 @@ const METHODS_MUTATORARG = {
335336
ChangeFramework.registerCallback(MUTATOR_BLOCK_NAME, [Blockly.Events.BLOCK_MOVE, Blockly.Events.BLOCK_CHANGE], this.onBlockChanged);
336337
},
337338
onBlockChanged: function (block: Blockly.BlockSvg, blockEvent: Blockly.Events.BlockBase) {
338-
if (blockEvent.type == Blockly.Events.BLOCK_MOVE){
339+
if (blockEvent.type == Blockly.Events.BLOCK_MOVE) {
339340
let blockMoveEvent = blockEvent as Blockly.Events.BlockMove;
340341
if (blockMoveEvent.reason?.includes('connect')) {
341-
setName(block);
342+
setName(block);
342343
}
343344
}
344-
else{
345-
if(blockEvent.type == Blockly.Events.BLOCK_CHANGE){
345+
else {
346+
if (blockEvent.type == Blockly.Events.BLOCK_CHANGE) {
346347
setName(block);
347348
}
348-
}
349+
}
349350
},
350351
}
351352

@@ -357,24 +358,24 @@ const METHODS_MUTATORARG = {
357358
* is what is being updated.
358359
*/
359360
function updateMutatorFlyout(workspace: Blockly.WorkspaceSvg) {
360-
const usedNames = [];
361-
const blocks = workspace.getBlocksByType(MUTATOR_BLOCK_NAME, false);
362-
for (let i = 0, block; (block = blocks[i]); i++) {
363-
usedNames.push(block.getFieldValue('NAME'));
364-
}
365-
const argValue = Blockly.Variables.generateUniqueNameFromOptions(
366-
Blockly.Procedures.DEFAULT_ARG,
367-
usedNames,
368-
);
369-
const jsonBlock = {
370-
kind: 'block',
371-
type: MUTATOR_BLOCK_NAME,
372-
fields: {
373-
NAME: argValue,
374-
},
375-
};
376-
377-
workspace.updateToolbox({contents:[jsonBlock]});
361+
const usedNames = [];
362+
const blocks = workspace.getBlocksByType(MUTATOR_BLOCK_NAME, false);
363+
for (let i = 0, block; (block = blocks[i]); i++) {
364+
usedNames.push(block.getFieldValue('NAME'));
365+
}
366+
const argValue = Blockly.Variables.generateUniqueNameFromOptions(
367+
Blockly.Procedures.DEFAULT_ARG,
368+
usedNames,
369+
);
370+
const jsonBlock = {
371+
kind: 'block',
372+
type: MUTATOR_BLOCK_NAME,
373+
fields: {
374+
NAME: argValue,
375+
},
376+
};
377+
378+
workspace.updateToolbox({ contents: [jsonBlock] });
378379
}
379380

380381

@@ -386,37 +387,37 @@ function updateMutatorFlyout(workspace: Blockly.WorkspaceSvg) {
386387
* @internal
387388
*/
388389
export function mutatorOpenListener(e: Blockly.Events.Abstract) {
389-
if (e.type != Blockly.Events.BUBBLE_OPEN){
390-
return;
391-
}
390+
if (e.type != Blockly.Events.BUBBLE_OPEN) {
391+
return;
392+
}
392393
const bubbleEvent = e as Blockly.Events.BubbleOpen;
393394
if (
394-
!(bubbleEvent.bubbleType === 'mutator' && bubbleEvent.isOpen) ||
395-
!bubbleEvent.blockId
395+
!(bubbleEvent.bubbleType === 'mutator' && bubbleEvent.isOpen) ||
396+
!bubbleEvent.blockId
396397
) {
397-
return;
398+
return;
398399
}
399400
const workspaceId = bubbleEvent.workspaceId;
400401
const block = Blockly.common
401-
.getWorkspaceById(workspaceId)!
402-
.getBlockById(bubbleEvent.blockId) as Blockly.BlockSvg;
402+
.getWorkspaceById(workspaceId)!
403+
.getBlockById(bubbleEvent.blockId) as Blockly.BlockSvg;
403404

404405
if (block.type !== BLOCK_NAME) {
405-
return;
406+
return;
406407
}
407408
const workspace = (
408-
block.getIcon(Blockly.icons.MutatorIcon.TYPE) as Blockly.icons.MutatorIcon
409+
block.getIcon(Blockly.icons.MutatorIcon.TYPE) as Blockly.icons.MutatorIcon
409410
).getWorkspace()!;
410411

411412
updateMutatorFlyout(workspace);
412413
ChangeFramework.setup(workspace);
413-
}
414+
}
414415

415416

416-
export const setup = function() {
417-
Blockly.Blocks[BLOCK_NAME] = CLASS_METHOD_DEF;
418-
Blockly.Blocks[MUTATOR_BLOCK_NAME] = METHODS_MUTATORARG;
419-
Blockly.Blocks[PARAM_CONTAINER_BLOCK_NAME] = METHOD_PARAM_CONTAINER;
417+
export const setup = function () {
418+
Blockly.Blocks[BLOCK_NAME] = CLASS_METHOD_DEF;
419+
Blockly.Blocks[MUTATOR_BLOCK_NAME] = METHODS_MUTATORARG;
420+
Blockly.Blocks[PARAM_CONTAINER_BLOCK_NAME] = METHOD_PARAM_CONTAINER;
420421
};
421422

422423
export const pythonFromBlock = function (
@@ -457,11 +458,11 @@ export const pythonFromBlock = function (
457458
// After executing the function body, revisit this block for the return.
458459
xfix2 = xfix1;
459460
}
460-
if(block.mrcPythonMethodName == '__init__'){
461+
if (block.mrcPythonMethodName == '__init__') {
461462
let class_specific = generator.getClassSpecificForInit();
462463
branch = generator.INDENT + 'super().__init__(' + class_specific + ')\n' +
463464
generator.defineClassVariables() + branch;
464-
}
465+
}
465466
if (returnValue) {
466467
returnValue = generator.INDENT + 'return ' + returnValue + '\n';
467468
} else if (!branch) {

0 commit comments

Comments
 (0)