UNPKG

@launchmenu/core

Version:

An environment for visual keyboard controlled applets

298 lines 22.3 kB
"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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