import React from 'react'; import type { FileDiffMetadata } from '@pierre/diffs'; import { Button } from '@/components/ui/button'; import { Icon } from '@/components/icon/Icon'; import { useRuntimeAPIs } from '@/hooks/useRuntimeAPIs'; import { useI18n } from '@/lib/i18n'; import { cn } from '@/lib/utils'; import { extractHunkPatch } from '@/lib/diff/patchFileDiff'; type HunkAction = 'stage' | 'unstage' | 'discard'; interface DiffHunkActionsProps { patch: string; fileDiff: FileDiffMetadata | undefined; directory: string; filePath: string; staged: boolean; onApplied: (action: HunkAction) => void; } export const DiffHunkActions = React.memo(({ patch, fileDiff, directory, filePath, staged, onApplied, }) => { const { t } = useI18n(); const { git } = useRuntimeAPIs(); const [busyKey, setBusyKey] = React.useState(null); const [error, setError] = React.useState(null); const hunks = fileDiff?.hunks; if (!hunks || hunks.length === 0 || !patch) { return null; } const run = async (hunkIndex: number, action: HunkAction) => { const hunkPatch = extractHunkPatch(patch, hunkIndex); if (!hunkPatch) { setError(t('diffView.hunk.unavailable')); return; } const key = `${hunkIndex}:${action}`; setBusyKey(key); setError(null); try { if (action === 'stage') { if (!git.stageGitHunk) throw new Error(t('diffView.hunk.unsupported')); await git.stageGitHunk(directory, filePath, hunkPatch); } else if (action === 'unstage') { if (!git.unstageGitHunk) throw new Error(t('diffView.hunk.unsupported')); await git.unstageGitHunk(directory, filePath, hunkPatch); } else { if (!git.revertGitHunk) throw new Error(t('diffView.hunk.unsupported')); await git.revertGitHunk(directory, filePath, hunkPatch); } onApplied(action); } catch (actionError) { setError(actionError instanceof Error ? actionError.message : String(actionError)); } finally { setBusyKey((current) => (current === key ? null : current)); } }; return (
{t('diffView.hunk.label')} {hunks.map((hunk, index) => { const additions = hunk.additionLines; const deletions = hunk.deletionLines; return (
{String(index + 1).padStart(2, '0')} {additions > 0 ? ( +{additions} ) : null} {deletions > 0 ? ( −{deletions} ) : null} {staged ? ( ) : ( <> )}
); })}
{error ? (
{error}
) : null}
); });