mirror of
https://gitea.toothfairyai.com/ToothFairyAI/tf_code.git
synced 2026-04-08 01:39:12 +00:00
chore(app): simplify review pane (#17066)
This commit is contained in:
@@ -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) => {
|
||||
|
||||
Reference in New Issue
Block a user