Skip to content

Preview as sidebar companion — reactive file viewer driven by Sidebar and Chat #931

Description

@jeonghun-jj-lee

Important

Problem: The Preview tab is a self-contained Finder (directory listing, breadcrumbs, search) that duplicates the Sidebar's file tree. Clicking a file in the Sidebar opens a native VS Code editor tab, bypassing Preview entirely — the two surfaces are disconnected. Users navigate files in the Sidebar but view them in a separate VS Code tab, splitting attention across windows.

Approach: Turn Preview into a reactive companion viewer driven by file selection in the Sidebar and Chat. Strip the Finder from Preview (the Sidebar is the file tree), route single-clicks to Preview via an extension-mediated bridge, and reserve double-clicks for native VS Code editor tabs.

Approaches considered:

  • Extension-mediated bridge (chosen) — sidebar → extension host → chat webview → SolidJS state. Matches existing bridge patterns, reliable, no polling.
  • Shared VS Code state — workspaceState polling. Rejected: no reliable change events for webviews, adds latency.
  • Direct webview-to-webview messaging — collapses to the bridge approach (VS Code routes all webview messages through the extension host).

Scope: Preview tab + sidebar click handlers + chat file-pill routing. Does not touch: Pulse Inspector, Files Changed, Context tab, Home tab, sidebar tree rendering/structure, no-project fallback (deferred).

Assumptions: The side panel auto-open API works reliably from the bridge message handler. The ~250ms single/double-click debounce is acceptable UX latency.

Acceptance Criteria

  • Sidebar single-click → Preview: clicking a file in the Sidebar opens it in the Preview tab. If the side panel is closed or on another tab, it auto-opens and switches to Preview.
  • Sidebar double-click → VS Code tab: double-clicking a file in the Sidebar opens a native VS Code editor tab.
  • Chat file pills → Preview: clicking a file reference in chat opens the file in Preview instead of a VS Code tab.
  • Finder stripped: Preview has no directory listing, no breadcrumb navigation, no search input, no walk-tree cache. File selection comes exclusively from external sources (Sidebar, Chat).
  • Empty state: when no file is selected, Preview shows a "Select a file from the sidebar" placeholder.
  • File rendering unchanged: markdown renders with Preview/Edit toggle; text/code opens in CM6 editor; images/PDFs render inline; binary/error/oversize show placeholders.
  • Per-file state preserved: mode (preview/edit), scroll position, and unsaved content survive across file switches within a session.
  • Single/double-click debounce: single-click fires only after ~250ms with no following double-click. Double-click fires immediately.

Testing Decisions

Extend the existing preview test suite (preview-file-routing, preview-nav-state). Add integration tests for the bridge message flow (sidebar → extension → chat webview). Unit tests for the single/double-click debounce logic in the sidebar webview.

Key Decisions

Click model: single = Preview, double = VS Code

Mirrors VS Code's own preview-tab convention. Single-click is non-committal viewing; double-click commits to a full editor session.

Extension-mediated bridge

Message chain: sidebar webview → extension host → chat webview → SolidJS app. New message kind preview-file (extension → chat). The existing open-file from sidebar is re-routed at the extension host. Chat file-pill open-file is similarly re-routed.

Preview state lifted to session layout

selectedFile moves from a component-local store to a signal at the session-layout level (reachable from the bridge message handler). The per-file store shrinks to mode/scroll/unsaved only.

No-project sessions show empty state

The prior fallback mode (listing session-touched files) is deferred — not part of this design.

Data Contracts

New bridge message (extension → chat webview):

{ source: "amicode", kind: "preview-file", path: string }

New sidebar message (sidebar webview → extension host):

{ kind: "open-file-editor", path: string }

Existing messages re-routed:

  • Sidebar { kind: "open-file", path } — extension host forwards as preview-file instead of calling showTextDocument.
  • Chat { source: "amicode", kind: "open-file", url } — extension host forwards as preview-file instead of calling vscode.open.

Constraints & Invariants

  • Preview never navigates on its own — it is file-in, content-out.
  • The Sidebar is the sole file picker for the side panel's Preview tab.
  • Chat file references are a secondary source, using the same preview-file bridge message.
  • Double-click always escapes to a native VS Code tab — Preview never blocks access to the full editor.
  • The side panel's other tabs (Home, Files Changed, Context, Pulse Inspector) are unaffected.

Prior Art

  • VS Code's own preview-tab model (single-click = transient preview, double-click = persistent tab).
  • The existing chat bridge open-file handler pattern.
  • ADR 0006 (inspectors-to-work-column) established the side panel as a multi-tab work surface.

Source

Notes

Metadata

Metadata

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions