mirror of
https://github.com/stablyai/orca.git
synced 2026-11-04 11:07:42 +00:00
* perf(mobile): skip projection for abandoned diff replies * test(mobile): consolidate abandoned diff projection regressions --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
187 lines
6.1 KiB
TypeScript
187 lines
6.1 KiB
TypeScript
import { useCallback, useLayoutEffect, useRef, useState, type MutableRefObject } from 'react'
|
|
import type { RpcClient } from '../transport/rpc-client'
|
|
import type { ConnectionState } from '../transport/types'
|
|
import { refusedRpcMessageOrFallback } from '../transport/rpc-refusal-message'
|
|
import { triggerError, triggerSelection } from '../platform/haptics'
|
|
import { buildMobileDiffLines } from '../session/mobile-diff-lines'
|
|
import { shouldIgnoreTrimWhitespace } from '../../../src/shared/diff-whitespace'
|
|
import {
|
|
highlightMobileDiffLines,
|
|
resolveMobileSyntaxLanguage
|
|
} from '../session/mobile-file-syntax'
|
|
import {
|
|
canOpenMobileBranchCompareDiff,
|
|
type MobileGitBranchChangeEntry
|
|
} from './mobile-branch-compare'
|
|
import { gitBranchDiffRead } from './mobile-git-read-operations'
|
|
import type { MobileGitDiffReply } from './git-compare-reply-schema'
|
|
import type { MobileReviewRouteArea } from './mobile-review-route'
|
|
import type {
|
|
MobileBranchCompareState,
|
|
MobileBranchDiffPreviewState
|
|
} from './mobile-source-control-screen-state'
|
|
|
|
type Params = {
|
|
client: RpcClient | null
|
|
connState: ConnectionState
|
|
diffShowWhitespace: boolean
|
|
hostId: string
|
|
worktreeId: string
|
|
origin: string
|
|
branchCompareState: MobileBranchCompareState
|
|
mountedRef: MutableRefObject<boolean>
|
|
busyActionRef: MutableRefObject<string | null>
|
|
openingPathRef: MutableRefObject<string | null>
|
|
setActionError: (message: string | null) => void
|
|
openReviewScreen: (path: string, area: MobileReviewRouteArea) => void
|
|
}
|
|
|
|
export function useMobileBranchDiffPreview({
|
|
client,
|
|
connState,
|
|
diffShowWhitespace,
|
|
hostId,
|
|
worktreeId,
|
|
origin,
|
|
branchCompareState,
|
|
mountedRef,
|
|
busyActionRef,
|
|
openingPathRef,
|
|
setActionError,
|
|
openReviewScreen
|
|
}: Params) {
|
|
const [branchDiffPreview, updateBranchDiffPreview] =
|
|
useState<MobileBranchDiffPreviewState | null>(null)
|
|
const [openingBranchPath, setOpeningBranchPath] = useState<string | null>(null)
|
|
const openingBranchPathRef = useRef<string | null>(null)
|
|
const branchPreviewGeneration = useRef(0)
|
|
const previewScope = useRef({ client, hostId, worktreeId })
|
|
useLayoutEffect(() => {
|
|
if (
|
|
previewScope.current.client !== client ||
|
|
previewScope.current.hostId !== hostId ||
|
|
previewScope.current.worktreeId !== worktreeId
|
|
) {
|
|
previewScope.current = { client, hostId, worktreeId }
|
|
branchPreviewGeneration.current += 1
|
|
openingBranchPathRef.current = null
|
|
setOpeningBranchPath(null)
|
|
updateBranchDiffPreview(null)
|
|
}
|
|
}, [client, hostId, worktreeId])
|
|
const setBranchDiffPreview = useCallback((next: MobileBranchDiffPreviewState | null) => {
|
|
if (next === null) {
|
|
branchPreviewGeneration.current += 1
|
|
openingBranchPathRef.current = null
|
|
setOpeningBranchPath(null)
|
|
}
|
|
updateBranchDiffPreview(next)
|
|
}, [])
|
|
|
|
const openBranchDiff = useCallback(
|
|
async (entry: MobileGitBranchChangeEntry) => {
|
|
if (openingBranchPathRef.current || openingPathRef.current || busyActionRef.current) {
|
|
return
|
|
}
|
|
if (!client || connState !== 'connected') {
|
|
if (!mountedRef.current) {
|
|
return
|
|
}
|
|
setActionError('Waiting for desktop...')
|
|
return
|
|
}
|
|
if (branchCompareState.kind !== 'ready') {
|
|
return
|
|
}
|
|
const summary = branchCompareState.result.summary
|
|
if (!canOpenMobileBranchCompareDiff(summary) || !summary.headOid || !summary.mergeBase) {
|
|
return
|
|
}
|
|
|
|
const generation = ++branchPreviewGeneration.current
|
|
const isCurrentPreview = () =>
|
|
mountedRef.current && branchPreviewGeneration.current === generation
|
|
openingBranchPathRef.current = entry.path
|
|
setOpeningBranchPath(entry.path)
|
|
if (origin !== 'session') {
|
|
openReviewScreen(entry.path, 'branch')
|
|
openingBranchPathRef.current = null
|
|
if (mountedRef.current) {
|
|
setOpeningBranchPath(null)
|
|
}
|
|
return
|
|
}
|
|
updateBranchDiffPreview({ kind: 'loading', entry })
|
|
try {
|
|
const reply = await gitBranchDiffRead.request(client, {
|
|
worktree: `id:${worktreeId}`,
|
|
filePath: entry.path,
|
|
...(entry.oldPath ? { oldPath: entry.oldPath } : {}),
|
|
compare: {
|
|
baseRef: summary.baseRef,
|
|
...(summary.baseOid ? { baseOid: summary.baseOid } : {}),
|
|
headOid: summary.headOid,
|
|
mergeBase: summary.mergeBase
|
|
}
|
|
})
|
|
if (!isCurrentPreview()) {
|
|
return
|
|
}
|
|
let result: MobileGitDiffReply
|
|
try {
|
|
result = gitBranchDiffRead.interpret(reply)
|
|
} catch (error) {
|
|
throw new Error(refusedRpcMessageOrFallback(error, 'Unable to load committed diff'))
|
|
}
|
|
if (result.kind !== 'text') {
|
|
throw new Error('Binary branch diff preview unavailable on mobile')
|
|
}
|
|
const diff = buildMobileDiffLines(result.originalContent, result.modifiedContent, {
|
|
ignoreTrimWhitespace: shouldIgnoreTrimWhitespace(diffShowWhitespace)
|
|
})
|
|
const syntaxLanguage = resolveMobileSyntaxLanguage(entry.path)
|
|
updateBranchDiffPreview({
|
|
kind: 'ready',
|
|
entry,
|
|
summary,
|
|
lines: highlightMobileDiffLines(diff.lines, syntaxLanguage),
|
|
truncated: diff.truncated
|
|
})
|
|
triggerSelection()
|
|
} catch (err) {
|
|
if (!isCurrentPreview()) {
|
|
return
|
|
}
|
|
triggerError()
|
|
updateBranchDiffPreview({
|
|
kind: 'error',
|
|
entry,
|
|
message: err instanceof Error ? err.message : 'Unable to load committed diff'
|
|
})
|
|
} finally {
|
|
if (branchPreviewGeneration.current === generation) {
|
|
openingBranchPathRef.current = null
|
|
if (mountedRef.current) {
|
|
setOpeningBranchPath(null)
|
|
}
|
|
}
|
|
}
|
|
},
|
|
[
|
|
branchCompareState,
|
|
busyActionRef,
|
|
client,
|
|
connState,
|
|
diffShowWhitespace,
|
|
mountedRef,
|
|
openReviewScreen,
|
|
openingPathRef,
|
|
origin,
|
|
setActionError,
|
|
worktreeId
|
|
]
|
|
)
|
|
|
|
return { branchDiffPreview, setBranchDiffPreview, openingBranchPath, openBranchDiff }
|
|
}
|