From f52877e8c5d6a4869869163c283b250d1d1906d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Geis?= Date: Sat, 15 Nov 2025 13:08:46 +0900 Subject: [PATCH] fix minor memory leaks These are pretty minor: - The one in `editors.ts` only leaks memory until a new editor is opened. - The other one only happens when Dance is disabled. Also fixes iteration of recorder when reaching the start of a buffer. Co-authored-by: Enrico Lumetti --- src/state/editors.ts | 2 +- src/state/extension.ts | 19 ++++++++++++++++++- src/state/modes.ts | 9 ++++++++- src/state/recorder.ts | 6 +++++- 4 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/state/editors.ts b/src/state/editors.ts index c0f18705..aa54a26c 100644 --- a/src/state/editors.ts +++ b/src/state/editors.ts @@ -687,7 +687,7 @@ export class Editors implements vscode.Disposable { state.dispose(); } - this._lastRemovedEditorStates.length === 0; + this._lastRemovedEditorStates.length = 0; // Dispose of fallback editor, if any. const fallback = this._fallbacks.get(document); diff --git a/src/state/extension.ts b/src/state/extension.ts index c98cebab..f579b4af 100644 --- a/src/state/extension.ts +++ b/src/state/extension.ts @@ -204,7 +204,6 @@ export class Extension implements vscode.Disposable { }, true, ); - } /** @@ -219,6 +218,24 @@ export class Extension implements vscode.Disposable { assert(this._autoDisposables.size === 0); this.statusBar.dispose(); + + // Clear configuration handlers. + this._configurationChangeHandlers.clear(); + + // Dispose of all subscriptions. + for (const subscription of this._subscriptions) { + subscription.dispose(); + } + this._subscriptions.length = 0; + + // Dispose of core components. + this.editors.dispose(); + this.recorder.dispose(); + this.modes.dispose(); + this.registers.dispose(); + + // Dismiss error message, if any. + this.dismissErrorMessage(); } /** diff --git a/src/state/modes.ts b/src/state/modes.ts index 27d42afd..09b9aaf3 100644 --- a/src/state/modes.ts +++ b/src/state/modes.ts @@ -552,7 +552,7 @@ export declare namespace Mode { /** * The set of all modes. */ -export class Modes implements Iterable { +export class Modes implements Iterable, vscode.Disposable { private readonly _vscodeModeDefaults: Mode.Configuration = { cursorStyle: "line", inheritFrom: null, @@ -581,6 +581,13 @@ export class Modes implements Iterable { this._observePreferences(extension); } + public dispose(): void { + for (const mode of this._modes.values()) { + mode.dispose(); + } + this._modes.clear(); + } + /** * The default mode configured using `dance.defaultMode`. */ diff --git a/src/state/recorder.ts b/src/state/recorder.ts index 3e6bcf9f..f8fe6f0d 100644 --- a/src/state/recorder.ts +++ b/src/state/recorder.ts @@ -204,7 +204,11 @@ export class Recorder implements vscode.Disposable { * call. */ public cursorFromEnd() { - return new Cursor(this, this._previousBuffers.length, this._buffer.length - 1); + return new Cursor( + this, + this._previousBuffers.length, + this._buffer.length === 0 ? 0 : this._buffer.length - 1, + ); } /**