diff --git a/src/common.ts b/src/common.ts index 5d78139f..650e6a8c 100644 --- a/src/common.ts +++ b/src/common.ts @@ -69,3 +69,29 @@ export async function pathExists( return false; } } + +// Creates a debounced version of a function with the specified delay. If the function is invoked before the delay runs +// out, then the previous invocation of the function gets cancelled and a new one is scheduled. +// +// Example: +// ```typescript +// // Invoking debouncedFoo will only execute after a second has passed since the last of all invocations +// const debouncedFoo = debounce(this.foo.bind(this), 1000); +// ``` +export function debounce(fn: (...args: any[]) => Promise, delay: number) { + let timeoutID: NodeJS.Timeout | null = null; + + return function (...args: any[]) { + if (timeoutID) { + clearTimeout(timeoutID); + } + + return new Promise((resolve, reject) => { + timeoutID = setTimeout(() => { + fn(...args) + .then((result) => resolve(result)) + .catch((error) => reject(error)); + }, delay); + }); + }; +} diff --git a/src/workspace.ts b/src/workspace.ts index c8a3cd1a..71348fa0 100644 --- a/src/workspace.ts +++ b/src/workspace.ts @@ -11,6 +11,7 @@ import { LOG_CHANNEL, WorkspaceInterface, STATUS_EMITTER, + debounce, } from "./common"; import { WorkspaceChannel } from "./workspaceChannel"; @@ -256,11 +257,15 @@ export class Workspace implements WorkspaceInterface { const watcher = vscode.workspace.createFileSystemWatcher( new vscode.RelativePattern(this.workspaceFolder, pattern), ); - context.subscriptions.push(watcher); - watcher.onDidChange(this.restart.bind(this)); - watcher.onDidCreate(this.restart.bind(this)); - watcher.onDidDelete(this.restart.bind(this)); + const debouncedRestart = debounce(this.restart.bind(this), 5000); + + context.subscriptions.push( + watcher, + watcher.onDidChange(debouncedRestart), + watcher.onDidCreate(debouncedRestart), + watcher.onDidDelete(debouncedRestart), + ); } private registerRebaseWatcher(context: vscode.ExtensionContext) { @@ -276,7 +281,6 @@ export class Workspace implements WorkspaceInterface { ".git/{rebase-merge,rebase-apply}", ), ); - context.subscriptions.push(workspaceWatcher, parentWatcher); const startRebase = () => { this.#rebaseInProgress = true; @@ -286,10 +290,13 @@ export class Workspace implements WorkspaceInterface { await this.restart(); }; - // When one of the rebase files are created, we set this flag to prevent restarting during the rebase - workspaceWatcher.onDidCreate(startRebase); - - // Once they are deleted and the rebase is complete, then we restart - workspaceWatcher.onDidDelete(stopRebase); + context.subscriptions.push( + workspaceWatcher, + parentWatcher, + // When one of the rebase files are created, we set this flag to prevent restarting during the rebase + workspaceWatcher.onDidCreate(startRebase), + // Once they are deleted and the rebase is complete, then we restart + workspaceWatcher.onDidDelete(stopRebase), + ); } }