mirror of
https://github.com/alberti42/obsidian-plugins-annotations.git
synced 2026-07-22 10:10:24 +00:00
Attempting to switch to a factory of debounced functions.
This commit is contained in:
parent
7a34e8c98f
commit
59da6411e4
2 changed files with 132 additions and 8 deletions
56
src/main.ts
56
src/main.ts
|
|
@ -9,6 +9,7 @@ import {
|
|||
PluginManifest,
|
||||
FileSystemAdapter,
|
||||
TAbstractFile,
|
||||
App,
|
||||
// PluginSettingTab,
|
||||
// App,
|
||||
} from 'obsidian';
|
||||
|
|
@ -20,7 +21,7 @@ import { DEFAULT_SETTINGS } from 'defaults';
|
|||
import { PluginsAnnotationsSettingTab } from 'settings_tab'
|
||||
import * as path from 'path';
|
||||
import { readAnnotationsFromMdFile, writeAnnotationsToMdFile } from 'manageAnnotations';
|
||||
import { backupSettings, delay, sortAnnotations } from 'utils';
|
||||
import { backupSettings, debounceFactoryWithWaitMechanism, delay, sortAnnotations } from 'utils';
|
||||
import { annotationControl } from 'annotation_control';
|
||||
|
||||
export default class PluginsAnnotations extends Plugin {
|
||||
|
|
@ -51,6 +52,21 @@ export default class PluginsAnnotations extends Plugin {
|
|||
private savePromise: Promise<void> | null = null;
|
||||
private resolveSavePromise: (() => void) | null = null;
|
||||
|
||||
// public debouncedSaveAnnotations: (callback: () => void = (): void => {}): void;
|
||||
|
||||
constructor(app:App, manifest:PluginManifest) {
|
||||
super(app, manifest);
|
||||
|
||||
// const { waitFnc, debouncedFct } = debounceFactoryWithWaitMechanism(async (...args: unknown[]): Promise<void> => {
|
||||
// // Extract the callback if it's provided, otherwise default to a no-op function
|
||||
// const callback = typeof args[0] === 'function' ? args[0] as () => void : () => {};
|
||||
|
||||
// await this.saveSettings();
|
||||
// callback(); // Call the callback after saving settings
|
||||
// }, 100);
|
||||
|
||||
}
|
||||
|
||||
async onload() {
|
||||
|
||||
// console.clear();
|
||||
|
|
@ -77,6 +93,27 @@ export default class PluginsAnnotations extends Plugin {
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
const asyncFunc = async (msg: string) => {
|
||||
console.log("Processing:", msg);
|
||||
return `Processed: ${msg}`;
|
||||
};
|
||||
console.log("HEY");
|
||||
|
||||
const { debouncedFct, waitFnc } = debounceFactoryWithWaitMechanism(asyncFunc, 1000);
|
||||
|
||||
// Make multiple debounced calls, only the last one should execute
|
||||
debouncedFct("Message 1");
|
||||
debouncedFct("Message 2");
|
||||
// Wait for the last debounced call to finish
|
||||
waitFnc().then(() => {
|
||||
console.log("All debounced calls have been completed.");
|
||||
}).catch(error => {
|
||||
console.error("An unexpected error occurred:", error);
|
||||
});
|
||||
}
|
||||
|
||||
/* Load settings for different versions */
|
||||
|
|
@ -229,6 +266,8 @@ export default class PluginsAnnotations extends Plugin {
|
|||
|
||||
let isRestoreOperation;
|
||||
if(data === undefined) {
|
||||
// we load directly from file, but first wait until
|
||||
// the previous debounced writing operation is completed
|
||||
this.waitForSaveToComplete();
|
||||
data = await this.loadData();
|
||||
isRestoreOperation = false;
|
||||
|
|
@ -544,6 +583,9 @@ export default class PluginsAnnotations extends Plugin {
|
|||
descriptionDiv.appendChild(annotation_container);
|
||||
}
|
||||
}
|
||||
|
||||
const controlDiv = settingItemInfo.querySelector('.setting-item-control');
|
||||
console.log(controlDiv);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -603,14 +645,14 @@ export default class PluginsAnnotations extends Plugin {
|
|||
onunload() {
|
||||
// console.log('Unloading Plugins Annotations');
|
||||
|
||||
// Remove all comments
|
||||
this.removeCommentsFromTab();
|
||||
// // Remove all comments
|
||||
// this.removeCommentsFromTab();
|
||||
|
||||
// Just in case, disconnect observers if they still exist
|
||||
this.disconnectObservers();
|
||||
// // Just in case, disconnect observers if they still exist
|
||||
// this.disconnectObservers();
|
||||
|
||||
// Remove icons
|
||||
this.removeIcon();
|
||||
// // Remove icons
|
||||
// this.removeIcon();
|
||||
}
|
||||
|
||||
getUninstalledPlugins(): PluginAnnotationDict {
|
||||
|
|
|
|||
84
src/utils.ts
84
src/utils.ts
|
|
@ -112,6 +112,87 @@ export async function createFolderIfNotExists(vault: Vault, folderPath: string)
|
|||
}
|
||||
}
|
||||
|
||||
// Utility to debounce rebuilds
|
||||
export function debounceFactory<F extends (...args: unknown[]) => unknown>(func: F, wait: number) {
|
||||
let timeout: ReturnType<typeof setTimeout>;
|
||||
|
||||
return (...args: Parameters<F>): void => {
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(() => func(...args), wait);
|
||||
};
|
||||
}
|
||||
|
||||
export function debounceFactoryWithWaitMechanism<F extends (...args: unknown[]) => ReturnType<F> | Promise<ReturnType<F>>>(func: F, wait: number) {
|
||||
let timeout: ReturnType<typeof setTimeout> | null = null;
|
||||
let promise: Promise<ReturnType<F>> | null = null;
|
||||
let resolvePromise: (() => void) | null = null;
|
||||
|
||||
class CancelledExecution extends Error {
|
||||
constructor(message = 'Debounced function call was cancelled') {
|
||||
super(message);
|
||||
this.name = 'CancelledExecution';
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
// Function to wait for the completion of the current debounced call (if any)
|
||||
waitFnc: async (): Promise<void> => {
|
||||
while (promise) {
|
||||
try {
|
||||
await promise;
|
||||
} catch (error) {
|
||||
if (!(error instanceof CancelledExecution)) {
|
||||
throw error; // Re-throw if it's not a cancellation
|
||||
}
|
||||
// We do nothing if the execution was cancelled
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// The debounced function itself
|
||||
debouncedFct: (...args: Parameters<F>): Promise<ReturnType<F>> => {
|
||||
// Clear the previous timeout to cancel any pending execution
|
||||
if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
|
||||
// Store the previous resolvePromise to resolve it after the new promise is created
|
||||
const previousResolvePromise = resolvePromise;
|
||||
|
||||
// Create a new promise for the current execution
|
||||
|
||||
promise = new Promise<ReturnType<F>>((resolve, reject) => {
|
||||
// Now we set the new resolvePromise function
|
||||
resolvePromise = () => {
|
||||
reject(new CancelledExecution()); // Reject with a specific cancellation error
|
||||
};
|
||||
|
||||
// After the new promise is created, resolve the previous one
|
||||
if (previousResolvePromise) {
|
||||
previousResolvePromise(); // Resolve the previous promise to prevent leaks
|
||||
}
|
||||
|
||||
// Schedule the function to run after the debounce delay
|
||||
timeout = setTimeout(async () => {
|
||||
try {
|
||||
// Await the result of the function and cast it to the expected return type
|
||||
const result = (await func(...args)) as ReturnType<F>;
|
||||
resolve(result); // Resolve with the result of the function (sync or async)
|
||||
} catch (error) {
|
||||
reject(error); // Reject the promise if the function throws an error
|
||||
}
|
||||
|
||||
// Clear the stored promise and resolve function after execution
|
||||
promise = null;
|
||||
resolvePromise = null;
|
||||
}, wait);
|
||||
});
|
||||
// Return the promise, allowing the caller to await the debounced execution
|
||||
return promise;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/* File suggestions */
|
||||
export class FileSuggestion extends AbstractInputSuggest<TFile> {
|
||||
private files:TFile[] = [];
|
||||
|
|
@ -234,4 +315,5 @@ export async function backupSettings(backupName: string, toBeBackedUp: unknown,
|
|||
|
||||
export function delay(ms: number) {
|
||||
return new Promise( resolve => setTimeout(resolve, ms) );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue