Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add indexing of dropdown entries #2004

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 35 additions & 6 deletions plugins/toolbox-search/src/block_searcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export class BlockSearcher {
* scenes, it creates a workspace, loads the specified block types on it,
* indexes their types and human-readable text, and cleans up after
* itself.
*
* @param blockTypes A list of block types to index.
*/
indexBlocks(blockTypes: string[]) {
Expand All @@ -29,28 +30,54 @@ export class BlockSearcher {
this.indexBlockText(blockType.replaceAll('_', ' '), blockType);
block.inputList.forEach((input) => {
input.fieldRow.forEach((field) => {
this.indexDropdownOption(field, blockType);
this.indexBlockText(field.getText(), blockType);
});
});
});
}

/**
* Check if the field is a dropdown, and index every text in the option
*
* @param field We need to check the type of field
* @param blockType The block type to associate the trigrams with.
*/
private indexDropdownOption(field: Blockly.Field, blockType: string) {
if (field instanceof Blockly.FieldDropdown) {
field.getOptions(true).forEach((option) => {
if (typeof option[0] === 'string') {
this.indexBlockText(option[0], blockType);
} else if ('alt' in option[0]) {
this.indexBlockText(option[0].alt, blockType);
}
});
}
}

/**
* Filters the available blocks based on the current query string.
*
* @param query The text to use to match blocks against.
* @returns A list of block types matching the query.
*/
blockTypesMatching(query: string): string[] {
return [...this.generateTrigrams(query).map((trigram) => {
return this.trigramsToBlocks.get(trigram) ?? new Set<string>();
}).reduce((matches, current) => {
return this.getIntersection(matches, current);
}).values()];
return [
...this.generateTrigrams(query)
.map((trigram) => {
return this.trigramsToBlocks.get(trigram) ?? new Set<string>();
})
.reduce((matches, current) => {
return this.getIntersection(matches, current);
})
.values(),
];
}

/**
* Generates trigrams for the given text and associates them with the given
* block type.
*
* @param text The text to generate trigrams of.
* @param blockType The block type to associate the trigrams with.
*/
Expand All @@ -64,6 +91,7 @@ export class BlockSearcher {

/**
* Generates a list of trigrams for a given string.
*
* @param input The string to generate trigrams of.
* @returns A list of trigrams of the given string.
*/
Expand All @@ -82,11 +110,12 @@ export class BlockSearcher {

/**
* Returns the intersection of two sets.
*
* @param a The first set.
* @param b The second set.
* @returns The intersection of the two sets.
*/
private getIntersection(a: Set<string>, b: Set<string>): Set<string> {
return new Set([...a].filter((value) => b.has(value)));
}
}
}
32 changes: 32 additions & 0 deletions plugins/toolbox-search/src/toolbox_search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,38 @@ export class ToolboxSearchCategory extends Blockly.ToolboxCategory {
this.flyoutItems_ = query ?
this.blockSearcher.blockTypesMatching(query).map(
(blockType) => {

// create a new workspace not to disturb the current workspace
// as creation of a block may trigger other changes as adding variables
const options = {};
const workspace = new Blockly.WorkspaceSvg(
new Blockly.Options(options));
const block = workspace.newBlock(blockType);
const inputs = block.inputList;

for (const input of inputs) {
const fields = input.fieldRow;
for (const field of fields) {
if (field instanceof Blockly.FieldDropdown) {
const options = field.getOptions();
for (const option of options) {
// check if the query is in the option
// make sure the option is text
if (typeof option[0] === 'string' &&
option[0].toLowerCase().includes(
query.toLowerCase())) {
const fields = {}
fields[field.name] = option[1]
return {
kind: 'block',
type: blockType,
fields: fields
};
};
};
};
};
};
return {
kind: 'block',
type: blockType,
Expand Down