@launchmenu/core
Version:
An environment for visual keyboard controlled applets
298 lines • 22.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CoreSearchExecuter = void 0;
const model_react_1 = require("model-react");
const createCallbackHook_1 = require("../createCallbackHook");
const PromiseAll_1 = require("./PromiseAll");
const Queue_1 = require("../Queue");
/**
* The core of the search executer that will obtain all the results
*/
class CoreSearchExecuter {
/**
* Creates a new search executor
* @param config The search configuration
*/
constructor({ searchable, onUpdate, onRemove, executer, }) {
this.query = new model_react_1.Field(null);
this.nodes = {};
/** The update queues, in order of priority, empties searchUpdate before removal, etc */
this.queues = {
searchUpdate: new Queue_1.Queue(),
removal: new Queue_1.Queue(),
update: new Queue_1.Queue(),
addition: new Queue_1.Queue(),
};
this.searching = new model_react_1.Field(false);
this.searchPromise = Promise.resolve();
this.continue = null;
this.destroyed = new model_react_1.Field(false);
this.rootSearchable = searchable;
this.onUpdate = onUpdate;
this.onRemove = onRemove;
this.executer = executer;
// Add the root searchable, with itself as its own parent
this.scheduleAddition(searchable, searchable.ID, true);
}
/**
* Sets the query to look for
* @param query The new query
* @returns A promise that resolves when the search fully finished
*/
async setQuery(query) {
if (this.destroyed.get())
return;
this.query.set(query);
// this.results.forEach(ID => this.queues.searchUpdate.push(ID));
Object.entries(this.nodes).forEach(([ID, node]) => {
if (node.result)
this.queues.searchUpdate.push(ID);
else if (!node.update.scheduled)
this.queues.update.push(ID);
node.update = {
scheduled: true,
required: true,
};
});
this.initSearch();
return this.searchPromise;
}
/**
* Retrieves the current query
* @param hook The hook to subscribe to changes
* @returns The current query
*/
getQuery(hook) {
return this.query.get(hook);
}
/**
* Retrieves whether a search is currently in progress
* @param hook The hook to subscribe to changes
* @returns Whether any search is in progress
*/
isSearching(hook) {
return this.searching.get(hook);
}
/**
* Destroys the search executer
* @param keepResults Whether to preserve the items (instead of calling onRemove for all)
*/
destroy(keepResults) {
this.destroyed.set(true);
Object.values(this.nodes).forEach(node => {
var _a, _b;
(_a = node.destroyHook) === null || _a === void 0 ? void 0 : _a.call(node);
if (!keepResults && ((_b = node.result) === null || _b === void 0 ? void 0 : _b.item))
this.onRemove(node.searchable.ID, node.result);
});
}
/**
* Starts or continues the search, if it wasn't already going
*/
initSearch() {
var _a;
(_a = this.continue) === null || _a === void 0 ? void 0 : _a.call(this);
if (!this.searching.get())
this.search();
}
/**
* Starts the search process
* @returns A promise that resolves once the search finishes
*/
search() {
this.searchPromise = (async () => {
const queues = this.queues;
let runningPromise = new PromiseAll_1.PromiseAll();
this.searching.set(true);
let running = true;
while (running && !this.destroyed.get()) {
const query = this.query.get();
let ID;
if (query != null && (ID = queues.searchUpdate.pop())) {
runningPromise.add(this.updateNode(query, ID));
}
else if ((ID = queues.removal.pop())) {
this.removeNode(ID);
}
else if (query != null && (ID = queues.update.pop())) {
runningPromise.add(this.updateNode(query, ID));
}
else if (query != null && (ID = queues.addition.pop())) {
runningPromise.add(this.updateNode(query, ID));
}
else {
// Create a promise that can be used to listen for any activity requests
let finish = null;
const continuePromise = new Promise(res => {
this.continue = () => {
finish = null;
res();
};
finish = res;
});
// If all running promises finish before the search got continued (finish is still present),
// Finish the search by invoking continue, and setting running to false
runningPromise.promise.then(() => {
if (finish) {
running = false;
this.searching.set(false);
finish();
}
});
// Wait for more items to come along
await continuePromise;
this.continue = null;
}
}
})();
return this.searchPromise;
}
/* Schedule node changes */
/**
* Schedules the addition of a new searchable
* May also be used to 'add' nodes that are already in the system, under a new parent
* @param searchable The searchable node to be scheduled
* @param parent The parent of the searchable node to add
* @param dontStartSearch Whether to prevent a search from starting based on this addition
*/
scheduleAddition(searchable, parent, dontStartSearch) {
const ID = searchable.ID;
const node = this.nodes[ID];
if (node) {
node.parents.add(parent);
node.removal.required = false;
if (node.update.required && !node.update.scheduled)
this.scheduleUpdate(ID);
}
else {
this.nodes[ID] = {
removal: {
scheduled: false,
required: false,
},
update: {
scheduled: true,
required: true,
},
parents: new Set([parent]),
executeVersion: 0,
searchable,
};
this.queues.addition.push(ID);
}
if (!dontStartSearch)
this.initSearch();
}
/**
* Schedules an update for the node with the given ID
* @param ID The ID of the node to schedule an update for
*/
scheduleUpdate(ID) {
const node = this.nodes[ID];
if (node) {
if (!node.update.scheduled)
this.queues.update.push(ID);
node.update = {
required: true,
scheduled: true,
};
}
this.initSearch();
}
/**
* Schedules the removal of the node with the given ID.
* Only schedules the removal if this node has no more parents
* @param ID The ID of the node to schedule the removal for
* @param parent The parent from which this node was removed
*/
scheduleRemoval(ID, parent) {
const node = this.nodes[ID];
if (node) {
const parents = node.parents;
parents.delete(parent);
if (parents.size == 0) {
if (!node.removal.scheduled)
this.queues.removal.push(ID);
node.removal = {
required: true,
scheduled: true,
};
}
}
this.initSearch();
}
/* Manage nodes */
/**
* Updates the given node, using the new query
* @param query The query to use for the update
* @param ID The ID of the node to be updated
* @returns A promise that resolves once the node is updated
*/
async updateNode(query, ID) {
var _a, _b;
const node = this.nodes[ID];
if (!node)
return;
node.update.scheduled = false;
// If the node is about to be deleted, skip updating
if (node.removal.required)
return;
// If update is no longer required, skip it
if (!node.update.required)
return;
node.update.required = false;
// Execute the search
const version = ++node.executeVersion;
(_a = node.destroyHook) === null || _a === void 0 ? void 0 : _a.call(node);
const [hook, destroyHook] = createCallbackHook_1.createCallbackHook(() => this.scheduleUpdate(ID), 0);
const { children, item, patternMatch } = await node.searchable.search(query, hook, this.executer);
node.destroyHook = destroyHook;
if (node.deleted || node.executeVersion != version)
return;
// Store the data
const oldResult = (_b = node.result) !== null && _b !== void 0 ? _b : { children: new Set() };
const newChildren = new Set((children !== null && children !== void 0 ? children : []).map(({ ID }) => ID));
node.result = {
item,
patternMatch,
children: newChildren,
};
// Schedule the child additions and removals
const parentID = ID;
const added = children === null || children === void 0 ? void 0 : children.filter(({ ID }) => !oldResult.children.has(ID));
const removed = [...oldResult.children].filter(ID => !newChildren.has(ID));
added === null || added === void 0 ? void 0 : added.forEach(n => this.scheduleAddition(n, parentID));
removed.forEach(ID => this.scheduleRemoval(ID, parentID));
// Update the results
this.onUpdate(ID, node.result, oldResult);
}
/**
* Removes a node with the given ID from the system
* @param ID The ID of the node to be removed
*/
removeNode(ID) {
var _a;
const node = this.nodes[ID];
if (!node)
return;
node.removal.scheduled = false;
// If the update is no longer required, skip it
if (!node.removal.required)
return;
node.removal.required = false;
// Delete the node
node.deleted = true;
delete this.nodes[ID];
(_a = node.destroyHook) === null || _a === void 0 ? void 0 : _a.call(node);
const result = node.result;
if (result) {
// Schedule the children to be removed
const parentID = ID;
result.children.forEach(ID => this.scheduleRemoval(ID, parentID));
// Remove any result data
this.onRemove(ID, result);
}
}
}
exports.CoreSearchExecuter = CoreSearchExecuter;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ29yZVNlYXJjaEV4ZWN1dGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3V0aWxzL3NlYXJjaEV4ZWN1dGVyL0NvcmVTZWFyY2hFeGVjdXRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSw2Q0FBNkM7QUFFN0MsOERBQXlEO0FBQ3pELDZDQUF3QztBQUN4QyxvQ0FBK0I7QUFTL0I7O0dBRUc7QUFDSCxNQUFhLGtCQUFrQjtJQTJCM0I7OztPQUdHO0lBQ0gsWUFBbUIsRUFDZixVQUFVLEVBQ1YsUUFBUSxFQUNSLFFBQVEsRUFDUixRQUFRLEdBQ3NCO1FBMUJ4QixVQUFLLEdBQUcsSUFBSSxtQkFBSyxDQUFDLElBQWdCLENBQUMsQ0FBQztRQUVwQyxVQUFLLEdBQXlDLEVBQUUsQ0FBQztRQUUzRCx3RkFBd0Y7UUFDOUUsV0FBTSxHQUFHO1lBQ2YsWUFBWSxFQUFFLElBQUksYUFBSyxFQUFTO1lBQ2hDLE9BQU8sRUFBRSxJQUFJLGFBQUssRUFBUztZQUMzQixNQUFNLEVBQUUsSUFBSSxhQUFLLEVBQVM7WUFDMUIsUUFBUSxFQUFFLElBQUksYUFBSyxFQUFTO1NBQy9CLENBQUM7UUFFUSxjQUFTLEdBQUcsSUFBSSxtQkFBSyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzdCLGtCQUFhLEdBQUcsT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ2xDLGFBQVEsR0FBMEMsSUFBSSxDQUFDO1FBQ3ZELGNBQVMsR0FBRyxJQUFJLG1CQUFLLENBQUMsS0FBSyxDQUFDLENBQUM7UUFZbkMsSUFBSSxDQUFDLGNBQWMsR0FBRyxVQUFVLENBQUM7UUFDakMsSUFBSSxDQUFDLFFBQVEsR0FBRyxRQUFRLENBQUM7UUFDekIsSUFBSSxDQUFDLFFBQVEsR0FBRyxRQUFRLENBQUM7UUFDekIsSUFBSSxDQUFDLFFBQVEsR0FBRyxRQUFRLENBQUM7UUFFekIseURBQXlEO1FBQ3pELElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxVQUFVLEVB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