Skip to content

Redesign lifecycle event registration in BoundDestinationLifecycle #612

@couimet

Description

@couimet

Summary

Redesign lifecycle event registration in BoundDestinationLifecycle from hard-coded per-type listener methods to a LifecycleEvent interface / hook-based abstraction that destination types implement. Currently each lifecycle event (terminal close, document close) is wired as a separate private method with destination-type branching. A generic LifecycleEvent interface with hooks (e.g., onClose, onDelete) that destination types implement would make adding new destination types and new lifecycle events trivial without modifying the lifecycle module itself.

Motivation

The initial BoundDestinationLifecycle extraction (see separate issue) is a pure extraction — moving existing listener logic out of PasteDestinationManager without changing behavior. The current design has each listener as a separate method (setupTerminalCloseListener, setupDocumentCloseListener) with switch-on-type logic inside. Adding a new destination type (e.g., file-picker output channel) or a new lifecycle event (e.g., file deletion) requires adding a new method and new branching. A hook-based design means you just implement the relevant interface on the destination class.

Proposed Design

  • Define a LifecycleEvent interface (or set of interfaces) that exposes hooks like onClose(lifecycleContext): Disposable, onDelete(lifecycleContext): Disposable, etc.
  • Destination types (TerminalDestination, TextEditorDestination) implement the hooks relevant to their lifecycle. Terminal implements onClose. TextEditor implements onClose and can optionally implement onDelete.
  • BoundDestinationLifecycle iterates registered destinations and collects their hooks at bind time. When an event fires (e.g., VS Code onDidCloseTerminal), the lifecycle module dispatches to the relevant hook implementations instead of running hard-coded per-type listeners.
  • The lifecycleContext parameter provides each hook with the unbind function, logger, and VS Code adapter so hooks can perform their cleanup without importing PasteDestinationManager directly.

Relevant Code

  • Terminal close listener: PasteDestinationManager.ts lines 382-404 — checks isTerminalDestination, compares terminal identity, calls unbind
  • Document close listener: PasteDestinationManager.ts lines 658-697 — checks isEditorDestination, compares URI, handles isClosed=false for language-mode transitions, calls unbind
  • Both follow the same structural pattern: guard → compare identity → handle edge case → log → unbind → status bar message

Backward Compatibility

All existing behavior must be preserved:

  • Terminal auto-unbind on terminal close (silent unbind + status bar message)
  • Text editor auto-unbind on document close (with isClosed=false language-mode transition guard)
  • Lazy unbind strategy (unbind only on actual close, not tab switch)
  • Status bar messages (STATUS_BAR_DESTINATION_UNBOUND_TERMINAL_CLOSED, STATUS_BAR_DESTINATION_UNBOUND_EDITOR_CLOSED)

Tasks

  1. Design and define LifecycleEvent interface(s) with hook signatures
  2. Implement hooks on TerminalDestination and TextEditorDestination
  3. Refactor BoundDestinationLifecycle to collect hooks at bind time and dispatch events
  4. Remove the two private listener setup methods after migration
  5. Add unit tests for: hook registration, event dispatch routing, edge cases (language-mode transition, unmatched terminal/editor), and the contract that adding a new destination type with hooks works without modifying BoundaryDestinationLifecycle
  6. Verify backward compatibility via existing integration tests

Dependencies

Depends on: BoundDestinationLifecycle extraction (#610). This redesign should not begin until that extraction is merged, as it builds on the extracted module.

Non-goals

  • No new lifecycle events beyond what currently exists (close is the only one); the interface should be extensible but this issue only refactors existing events
  • No changes to PasteDestinationManager's bind/unbind flow
  • No changes to status bar messages or logging format

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requesttype:refactorCode refactoring without behavior change

    Projects

    Status
    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions