chore(app): simplify review pane (#17066)

This commit is contained in:
Adam
2026-03-11 12:24:51 -05:00
committed by GitHub
parent 9c585bb58b
commit bcc0d19867
7 changed files with 319 additions and 809 deletions

View File

@@ -8,20 +8,6 @@ export type FindHost = {
isOpen: () => boolean
}
type FileFindSide = "additions" | "deletions"
export type FileFindReveal = {
side: FileFindSide
line: number
col: number
len: number
}
type FileFindHit = FileFindReveal & {
range: Range
alt?: number
}
const hosts = new Set<FindHost>()
let target: FindHost | undefined
let current: FindHost | undefined
@@ -112,7 +98,6 @@ type CreateFileFindOptions = {
wrapper: () => HTMLElement | undefined
overlay: () => HTMLDivElement | undefined
getRoot: () => ShadowRoot | undefined
shortcuts?: "global" | "disabled"
}
export function createFileFind(opts: CreateFileFindOptions) {
@@ -120,7 +105,7 @@ export function createFileFind(opts: CreateFileFindOptions) {
let overlayFrame: number | undefined
let overlayScroll: HTMLElement[] = []
let mode: "highlights" | "overlay" = "overlay"
let hits: FileFindHit[] = []
let hits: Range[] = []
const [open, setOpen] = createSignal(false)
const [query, setQuery] = createSignal("")
@@ -161,7 +146,7 @@ export function createFileFind(opts: CreateFileFindOptions) {
const frag = document.createDocumentFragment()
for (let i = 0; i < hits.length; i++) {
const range = hits[i].range
const range = hits[i]
const active = i === currentIndex
for (const rect of Array.from(range.getClientRects())) {
if (!rect.width || !rect.height) continue
@@ -237,7 +222,7 @@ export function createFileFind(opts: CreateFileFindOptions) {
const scan = (root: ShadowRoot, value: string) => {
const needle = value.toLowerCase()
const ranges: FileFindHit[] = []
const ranges: Range[] = []
const cols = Array.from(root.querySelectorAll("[data-content] [data-line], [data-column-content]")).filter(
(node): node is HTMLElement => node instanceof HTMLElement,
)
@@ -250,28 +235,6 @@ export function createFileFind(opts: CreateFileFindOptions) {
let at = hay.indexOf(needle)
if (at === -1) continue
const row = col.closest("[data-line], [data-alt-line]")
if (!(row instanceof HTMLElement)) continue
const primary = parseInt(row.dataset.line ?? "", 10)
const alt = parseInt(row.dataset.altLine ?? "", 10)
const line = (() => {
if (!Number.isNaN(primary)) return primary
if (!Number.isNaN(alt)) return alt
})()
if (line === undefined) continue
const side = (() => {
const code = col.closest("[data-code]")
if (code instanceof HTMLElement) return code.hasAttribute("data-deletions") ? "deletions" : "additions"
const row = col.closest("[data-line-type]")
if (!(row instanceof HTMLElement)) return "additions"
const type = row.dataset.lineType
if (type === "change-deletion") return "deletions"
return "additions"
})() as FileFindSide
const nodes: Text[] = []
const ends: number[] = []
const walker = document.createTreeWalker(col, NodeFilter.SHOW_TEXT)
@@ -305,14 +268,7 @@ export function createFileFind(opts: CreateFileFindOptions) {
const range = document.createRange()
range.setStart(start.node, start.offset)
range.setEnd(end.node, end.offset)
ranges.push({
range,
side,
line,
alt: Number.isNaN(alt) ? undefined : alt,
col: at + 1,
len: value.length,
})
ranges.push(range)
at = hay.indexOf(needle, at + value.length)
}
}
@@ -321,17 +277,12 @@ export function createFileFind(opts: CreateFileFindOptions) {
}
const scrollToRange = (range: Range) => {
const scroll = () => {
const start = range.startContainer
const el = start instanceof Element ? start : start.parentElement
el?.scrollIntoView({ block: "center", inline: "center" })
}
scroll()
requestAnimationFrame(scroll)
const start = range.startContainer
const el = start instanceof Element ? start : start.parentElement
el?.scrollIntoView({ block: "center", inline: "center" })
}
const setHighlights = (ranges: FileFindHit[], currentIndex: number) => {
const setHighlights = (ranges: Range[], currentIndex: number) => {
const api = (globalThis as unknown as { CSS?: { highlights?: any }; Highlight?: any }).CSS?.highlights
const Highlight = (globalThis as unknown as { Highlight?: any }).Highlight
if (!api || typeof Highlight !== "function") return false
@@ -339,37 +290,14 @@ export function createFileFind(opts: CreateFileFindOptions) {
api.delete("opencode-find")
api.delete("opencode-find-current")
const active = ranges[currentIndex]?.range
const active = ranges[currentIndex]
if (active) api.set("opencode-find-current", new Highlight(active))
const rest = ranges.flatMap((hit, i) => (i === currentIndex ? [] : [hit.range]))
const rest = ranges.filter((_, i) => i !== currentIndex)
if (rest.length > 0) api.set("opencode-find", new Highlight(...rest))
return true
}
const select = (currentIndex: number, scroll: boolean) => {
const active = hits[currentIndex]?.range
if (!active) return false
setIndex(currentIndex)
if (mode === "highlights") {
if (!setHighlights(hits, currentIndex)) {
mode = "overlay"
apply({ reset: true, scroll })
return false
}
if (scroll) scrollToRange(active)
return true
}
clearHighlightFind()
syncOverlayScroll()
if (scroll) scrollToRange(active)
scheduleOverlay()
return true
}
const apply = (args?: { reset?: boolean; scroll?: boolean }) => {
if (!open()) return
@@ -393,7 +321,7 @@ export function createFileFind(opts: CreateFileFindOptions) {
setCount(total)
setIndex(currentIndex)
const active = ranges[currentIndex]?.range
const active = ranges[currentIndex]
if (mode === "highlights") {
clearOverlay()
clearOverlayScroll()
@@ -420,23 +348,11 @@ export function createFileFind(opts: CreateFileFindOptions) {
if (current === host) current = undefined
}
const clear = () => {
setQuery("")
clearFind()
}
const activate = () => {
if (opts.shortcuts !== "disabled") {
if (current && current !== host) current.close()
current = host
target = host
}
if (!open()) setOpen(true)
}
const focus = () => {
activate()
if (current && current !== host) current.close()
current = host
target = host
if (!open()) setOpen(true)
requestAnimationFrame(() => {
apply({ scroll: true })
input?.focus()
@@ -450,30 +366,25 @@ export function createFileFind(opts: CreateFileFindOptions) {
if (total <= 0) return
const currentIndex = (index() + dir + total) % total
select(currentIndex, true)
}
setIndex(currentIndex)
const reveal = (targetHit: FileFindReveal) => {
if (!open()) return false
if (hits.length === 0) return false
const active = hits[currentIndex]
if (!active) return
const exact = hits.findIndex(
(hit) =>
hit.side === targetHit.side &&
hit.line === targetHit.line &&
hit.col === targetHit.col &&
hit.len === targetHit.len,
)
const fallback = hits.findIndex(
(hit) =>
(hit.line === targetHit.line || hit.alt === targetHit.line) &&
hit.col === targetHit.col &&
hit.len === targetHit.len,
)
if (mode === "highlights") {
if (!setHighlights(hits, currentIndex)) {
mode = "overlay"
apply({ reset: true, scroll: true })
return
}
scrollToRange(active)
return
}
const nextIndex = exact >= 0 ? exact : fallback
if (nextIndex < 0) return false
return select(nextIndex, true)
clearHighlightFind()
syncOverlayScroll()
scrollToRange(active)
scheduleOverlay()
}
const host: FindHost = {
@@ -486,21 +397,17 @@ export function createFileFind(opts: CreateFileFindOptions) {
onMount(() => {
mode = supportsHighlights() ? "highlights" : "overlay"
if (opts.shortcuts !== "disabled") {
installShortcuts()
hosts.add(host)
if (!target) target = host
}
installShortcuts()
hosts.add(host)
if (!target) target = host
onCleanup(() => {
if (opts.shortcuts !== "disabled") {
hosts.delete(host)
if (current === host) {
current = undefined
clearHighlightFind()
}
if (target === host) target = undefined
hosts.delete(host)
if (current === host) {
current = undefined
clearHighlightFind()
}
if (target === host) target = undefined
})
})
@@ -541,25 +448,20 @@ export function createFileFind(opts: CreateFileFindOptions) {
setInput: (el: HTMLInputElement) => {
input = el
},
setQuery: (value: string, args?: { scroll?: boolean }) => {
setQuery: (value: string) => {
setQuery(value)
setIndex(0)
apply({ reset: true, scroll: args?.scroll ?? true })
apply({ reset: true, scroll: true })
},
clear,
activate,
focus,
close,
next,
reveal,
refresh: (args?: { reset?: boolean; scroll?: boolean }) => apply(args),
onPointerDown: () => {
if (opts.shortcuts === "disabled") return
target = host
opts.wrapper()?.focus({ preventScroll: true })
},
onFocus: () => {
if (opts.shortcuts === "disabled") return
target = host
},
onInputKeyDown: (event: KeyboardEvent) => {