import { c as _c } from "react-compiler-runtime"; import type { StructuredPatchHunk } from 'diff'; import React, { useEffect, useMemo, useRef, useState } from 'react'; import type { CommandResultDisplay } from '../../commands.js'; import { useRegisterOverlay } from '../../context/overlayContext.js'; import { type DiffData, useDiffData } from '../../hooks/useDiffData.js'; import { type TurnDiff, useTurnDiffs } from '../../hooks/useTurnDiffs.js'; import { Box, Text } from '../../ink.js'; import { useKeybindings } from '../../keybindings/useKeybinding.js'; import { useShortcutDisplay } from '../../keybindings/useShortcutDisplay.js'; import type { Message } from '../../types/message.js'; import { plural } from '../../utils/stringUtils.js'; import { Byline } from '../design-system/Byline.js'; import { Dialog } from '../design-system/Dialog.js'; import { DiffDetailView } from './DiffDetailView.js'; import { DiffFileList } from './DiffFileList.js'; type Props = { messages: Message[]; onDone: (result?: string, options?: { display?: CommandResultDisplay; }) => void; }; type ViewMode = 'list' | 'detail'; type DiffSource = { type: 'current'; } | { type: 'turn'; turn: TurnDiff; }; function turnDiffToDiffData(turn: TurnDiff): DiffData { const files = Array.from(turn.files.values()).map(f => ({ path: f.filePath, linesAdded: f.linesAdded, linesRemoved: f.linesRemoved, isBinary: false, isLargeFile: false, isTruncated: false, isNewFile: f.isNewFile })).sort((a, b) => a.path.localeCompare(b.path)); const hunks = new Map(); for (const f of turn.files.values()) { hunks.set(f.filePath, f.hunks); } return { stats: { filesCount: turn.stats.filesChanged, linesAdded: turn.stats.linesAdded, linesRemoved: turn.stats.linesRemoved }, files, hunks, loading: false }; } export function DiffDialog(t0) { const $ = _c(73); const { messages, onDone } = t0; const gitDiffData = useDiffData(); const turnDiffs = useTurnDiffs(messages); const [viewMode, setViewMode] = useState("list"); const [selectedIndex, setSelectedIndex] = useState(0); const [sourceIndex, setSourceIndex] = useState(0); let t1; if ($[0] === Symbol.for("react.memo_cache_sentinel")) { t1 = { type: "current" }; $[0] = t1; } else { t1 = $[0]; } let t2; if ($[1] !== turnDiffs) { t2 = [t1, ...turnDiffs.map(_temp)]; $[1] = turnDiffs; $[2] = t2; } else { t2 = $[2]; } const sources = t2; const currentSource = sources[sourceIndex]; const currentTurn = currentSource?.type === "turn" ? currentSource.turn : null; let t3; if ($[3] !== currentTurn || $[4] !== gitDiffData) { t3 = currentTurn ? turnDiffToDiffData(currentTurn) : gitDiffData; $[3] = currentTurn; $[4] = gitDiffData; $[5] = t3; } else { t3 = $[5]; } const diffData = t3; const selectedFile = diffData.files[selectedIndex]; let t4; if ($[6] !== diffData.hunks || $[7] !== selectedFile) { t4 = selectedFile ? diffData.hunks.get(selectedFile.path) || [] : []; $[6] = diffData.hunks; $[7] = selectedFile; $[8] = t4; } else { t4 = $[8]; } const selectedHunks = t4; let t5; let t6; if ($[9] !== sourceIndex || $[10] !== sources.length) { t5 = () => { if (sourceIndex >= sources.length) { setSourceIndex(Math.max(0, sources.length - 1)); } }; t6 = [sources.length, sourceIndex]; $[9] = sourceIndex; $[10] = sources.length; $[11] = t5; $[12] = t6; } else { t5 = $[11]; t6 = $[12]; } useEffect(t5, t6); const prevSourceIndex = useRef(sourceIndex); let t7; let t8; if ($[13] !== sourceIndex) { t7 = () => { if (prevSourceIndex.current !== sourceIndex) { setSelectedIndex(0); prevSourceIndex.current = sourceIndex; } }; t8 = [sourceIndex]; $[13] = sourceIndex; $[14] = t7; $[15] = t8; } else { t7 = $[14]; t8 = $[15]; } useEffect(t7, t8); useRegisterOverlay("diff-dialog"); let t10; let t9; if ($[16] !== sources.length || $[17] !== viewMode) { t9 = () => { if (viewMode === "detail") { setViewMode("list"); } else { if (viewMode === "list" && sources.length > 1) { setSourceIndex(_temp2); } } }; t10 = () => { if (viewMode === "list" && sources.length > 1) { setSourceIndex(prev_0 => Math.min(sources.length - 1, prev_0 + 1)); } }; $[16] = sources.length; $[17] = viewMode; $[18] = t10; $[19] = t9; } else { t10 = $[18]; t9 = $[19]; } let t11; if ($[20] !== viewMode) { t11 = () => { if (viewMode === "detail") { setViewMode("list"); } }; $[20] = viewMode; $[21] = t11; } else { t11 = $[21]; } let t12; if ($[22] !== selectedFile || $[23] !== viewMode) { t12 = () => { if (viewMode === "list" && selectedFile) { setViewMode("detail"); } }; $[22] = selectedFile; $[23] = viewMode; $[24] = t12; } else { t12 = $[24]; } let t13; if ($[25] !== viewMode) { t13 = () => { if (viewMode === "list") { setSelectedIndex(_temp3); } }; $[25] = viewMode; $[26] = t13; } else { t13 = $[26]; } let t14; if ($[27] !== diffData.files.length || $[28] !== viewMode) { t14 = () => { if (viewMode === "list") { setSelectedIndex(prev_2 => Math.min(diffData.files.length - 1, prev_2 + 1)); } }; $[27] = diffData.files.length; $[28] = viewMode; $[29] = t14; } else { t14 = $[29]; } let t15; if ($[30] !== t10 || $[31] !== t11 || $[32] !== t12 || $[33] !== t13 || $[34] !== t14 || $[35] !== t9) { t15 = { "diff:previousSource": t9, "diff:nextSource": t10, "diff:back": t11, "diff:viewDetails": t12, "diff:previousFile": t13, "diff:nextFile": t14 }; $[30] = t10; $[31] = t11; $[32] = t12; $[33] = t13; $[34] = t14; $[35] = t9; $[36] = t15; } else { t15 = $[36]; } let t16; if ($[37] === Symbol.for("react.memo_cache_sentinel")) { t16 = { context: "DiffDialog" }; $[37] = t16; } else { t16 = $[37]; } useKeybindings(t15, t16); let t17; if ($[38] !== diffData.stats) { t17 = diffData.stats ? {diffData.stats.filesCount} {plural(diffData.stats.filesCount, "file")}{" "}changed{diffData.stats.linesAdded > 0 && +{diffData.stats.linesAdded}}{diffData.stats.linesRemoved > 0 && -{diffData.stats.linesRemoved}} : null; $[38] = diffData.stats; $[39] = t17; } else { t17 = $[39]; } const subtitle = t17; const headerTitle = currentTurn ? `Turn ${currentTurn.turnIndex}` : "Uncommitted changes"; const headerSubtitle = currentTurn ? currentTurn.userPromptPreview ? `"${currentTurn.userPromptPreview}"` : "" : "(git diff HEAD)"; let t18; if ($[40] !== sourceIndex || $[41] !== sources) { t18 = sources.length > 1 ? {sourceIndex > 0 && }{sources.map((source, i) => { const isSelected = i === sourceIndex; const label = source.type === "current" ? "Current" : `T${source.turn.turnIndex}`; return {i > 0 ? " \xB7 " : ""}{label}; })}{sourceIndex < sources.length - 1 && } : null; $[40] = sourceIndex; $[41] = sources; $[42] = t18; } else { t18 = $[42]; } const sourceSelector = t18; const dismissShortcut = useShortcutDisplay("diff:dismiss", "DiffDialog", "esc"); let t19; bb0: { if (diffData.loading) { t19 = "Loading diff\u2026"; break bb0; } if (currentTurn) { t19 = "No file changes in this turn"; break bb0; } if (diffData.stats && diffData.stats.filesCount > 0 && diffData.files.length === 0) { t19 = "Too many files to display details"; break bb0; } t19 = "Working tree is clean"; } const emptyMessage = t19; let t20; if ($[43] !== headerSubtitle) { t20 = headerSubtitle && {headerSubtitle}; $[43] = headerSubtitle; $[44] = t20; } else { t20 = $[44]; } let t21; if ($[45] !== headerTitle || $[46] !== t20) { t21 = {headerTitle}{t20}; $[45] = headerTitle; $[46] = t20; $[47] = t21; } else { t21 = $[47]; } const title = t21; let t22; if ($[48] !== onDone || $[49] !== viewMode) { t22 = function handleCancel() { if (viewMode === "detail") { setViewMode("list"); } else { onDone("Diff dialog dismissed", { display: "system" }); } }; $[48] = onDone; $[49] = viewMode; $[50] = t22; } else { t22 = $[50]; } const handleCancel = t22; let t23; if ($[51] !== dismissShortcut || $[52] !== sources.length || $[53] !== viewMode) { t23 = exitState => exitState.pending ? Press {exitState.keyName} again to exit : viewMode === "list" ? {sources.length > 1 && ←/→ source}↑/↓ selectEnter view{dismissShortcut} close : ← back{dismissShortcut} close; $[51] = dismissShortcut; $[52] = sources.length; $[53] = viewMode; $[54] = t23; } else { t23 = $[54]; } let t24; if ($[55] !== diffData.files || $[56] !== emptyMessage || $[57] !== selectedFile?.isBinary || $[58] !== selectedFile?.isLargeFile || $[59] !== selectedFile?.isTruncated || $[60] !== selectedFile?.isUntracked || $[61] !== selectedFile?.path || $[62] !== selectedHunks || $[63] !== selectedIndex || $[64] !== viewMode) { t24 = diffData.files.length === 0 ? {emptyMessage} : viewMode === "list" ? : ; $[55] = diffData.files; $[56] = emptyMessage; $[57] = selectedFile?.isBinary; $[58] = selectedFile?.isLargeFile; $[59] = selectedFile?.isTruncated; $[60] = selectedFile?.isUntracked; $[61] = selectedFile?.path; $[62] = selectedHunks; $[63] = selectedIndex; $[64] = viewMode; $[65] = t24; } else { t24 = $[65]; } let t25; if ($[66] !== handleCancel || $[67] !== sourceSelector || $[68] !== subtitle || $[69] !== t23 || $[70] !== t24 || $[71] !== title) { t25 = {sourceSelector}{subtitle}{t24}; $[66] = handleCancel; $[67] = sourceSelector; $[68] = subtitle; $[69] = t23; $[70] = t24; $[71] = title; $[72] = t25; } else { t25 = $[72]; } return t25; } function _temp3(prev_1) { return Math.max(0, prev_1 - 1); } function _temp2(prev) { return Math.max(0, prev - 1); } function _temp(turn) { return { type: "turn", turn }; }