refactor(snapshot): store unified patches in file diffs (#21244)

Co-authored-by: Adam <2363879+adamdotdevin@users.noreply.github.com>
This commit is contained in:
Dax
2026-04-07 19:48:23 -04:00
committed by GitHub
co-authored by Adam
parent 463318486f
commit b7fab49b64
30 changed files with 343 additions and 183 deletions
+15 -21
View File
@@ -15,7 +15,7 @@ import { getDirectory, getFilename } from "@opencode-ai/util/path"
import { checksum } from "@opencode-ai/util/encode"
import { createEffect, createMemo, For, Match, onCleanup, Show, Switch, untrack, type JSX } from "solid-js"
import { createStore } from "solid-js/store"
import { type FileContent, type FileDiff } from "@opencode-ai/sdk/v2"
import { type FileContent, type SnapshotFileDiff, type VcsFileDiff } from "@opencode-ai/sdk/v2"
import { PreloadMultiFileDiffResult } from "@pierre/diffs/ssr"
import { type SelectedLineRange } from "@pierre/diffs"
import { Dynamic } from "solid-js/web"
@@ -23,6 +23,7 @@ import { mediaKindFromPath } from "../pierre/media"
import { cloneSelectedLineRange, previewSelectedLines } from "../pierre/selection-bridge"
import { createLineCommentController } from "./line-comment-annotations"
import type { LineCommentEditorProps } from "./line-comment"
import { normalize, text, type ViewDiff } from "./session-diff"
const MAX_DIFF_CHANGED_LINES = 500
const REVIEW_MOUNT_MARGIN = 300
@@ -61,7 +62,8 @@ export type SessionReviewCommentActions = {
export type SessionReviewFocus = { file: string; id: string }
type ReviewDiff = FileDiff & { preloaded?: PreloadMultiFileDiffResult<any> }
type ReviewDiff = (SnapshotFileDiff | VcsFileDiff) & { preloaded?: PreloadMultiFileDiffResult<any> }
type Item = ViewDiff & { preloaded?: PreloadMultiFileDiffResult<any> }
export interface SessionReviewProps {
title?: JSX.Element
@@ -155,8 +157,8 @@ export const SessionReview = (props: SessionReviewProps) => {
const opened = () => store.opened
const open = () => props.open ?? store.open
const files = createMemo(() => props.diffs.map((diff) => diff.file))
const diffs = createMemo(() => new Map(props.diffs.map((diff) => [diff.file, diff] as const)))
const items = createMemo<Item[]>(() => props.diffs.map((diff) => ({ ...normalize(diff), preloaded: diff.preloaded })))
const files = createMemo(() => items().map((diff) => diff.file))
const grouped = createMemo(() => {
const next = new Map<string, SessionReviewComment[]>()
for (const comment of props.comments ?? []) {
@@ -246,10 +248,10 @@ export const SessionReview = (props: SessionReviewProps) => {
const selectionSide = (range: SelectedLineRange) => range.endSide ?? range.side ?? "additions"
const selectionPreview = (diff: FileDiff, range: SelectedLineRange) => {
const selectionPreview = (diff: ViewDiff, range: SelectedLineRange) => {
const side = selectionSide(range)
const contents = side === "deletions" ? diff.before : diff.after
if (typeof contents !== "string" || contents.length === 0) return undefined
const contents = text(diff, side)
if (contents.length === 0) return undefined
return previewSelectedLines(contents, range)
}
@@ -359,7 +361,7 @@ export const SessionReview = (props: SessionReviewProps) => {
<Show when={hasDiffs()} fallback={props.empty}>
<div class="pb-6">
<Accordion multiple value={open()} onChange={handleChange}>
<For each={props.diffs}>
<For each={items()}>
{(diff) => {
let wrapper: HTMLDivElement | undefined
const file = diff.file
@@ -371,8 +373,8 @@ export const SessionReview = (props: SessionReviewProps) => {
const comments = createMemo(() => grouped().get(file) ?? [])
const commentedLines = createMemo(() => comments().map((c) => c.selection))
const beforeText = () => (typeof diff.before === "string" ? diff.before : "")
const afterText = () => (typeof diff.after === "string" ? diff.after : "")
const beforeText = () => text(diff, "deletions")
const afterText = () => text(diff, "additions")
const changedLines = () => diff.additions + diff.deletions
const mediaKind = createMemo(() => mediaKindFromPath(file))
@@ -581,6 +583,7 @@ export const SessionReview = (props: SessionReviewProps) => {
<Dynamic
component={fileComponent}
mode="diff"
fileDiff={diff.fileDiff}
preloadedDiff={diff.preloaded}
diffStyle={diffStyle()}
onRendered={() => {
@@ -596,20 +599,11 @@ export const SessionReview = (props: SessionReviewProps) => {
renderHoverUtility={props.onLineComment ? commentsUi.renderHoverUtility : undefined}
selectedLines={selectedLines()}
commentedLines={commentedLines()}
before={{
name: file,
contents: typeof diff.before === "string" ? diff.before : "",
}}
after={{
name: file,
contents: typeof diff.after === "string" ? diff.after : "",
}}
media={{
mode: "auto",
path: file,
before: diff.before,
after: diff.after,
readFile: props.readFile,
deleted: diff.status === "deleted",
readFile: diff.status === "deleted" ? undefined : props.readFile,
}}
/>
</Match>