✨ feat(vscode): 代码阅读差异加「只看改动」(连着没变的块折成一条、按工作区记住)、上一处 / 下一处改动、右边缘总览条
This commit is contained in:
1 parent
707d85c324
commit
6120c85bc0
14 files changed
+533
-42
No files matched your search
@@ -8,11 +8,13 @@ import { TriangleAlert } from 'lucide-react'
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { BlockLevel } from './BlockTree'
|
||||
import { DiffBar, NewFileBanner } from './DiffBar'
|
||||
import { diffTree, openedByDiff } from './diffView'
|
||||
import { changeStops, diffTree, foldUnchanged, openedByDiff } from './diffView'
|
||||
import { acceptNames, DisplayNameContext, documentNames } from './displayNames'
|
||||
import { coveredByEditing, startEditing } from './editing'
|
||||
import { applyFilter, excludedBy, keptWhileEditing } from './filter'
|
||||
import { FilterBar } from './FilterBar'
|
||||
import { OverviewRuler } from './OverviewRuler'
|
||||
import { useChangeNav } from './useChangeNav'
|
||||
import { useDefinitionLinks } from './useDefinitionLinks'
|
||||
import { HighlightContext, useOccurrences } from './useOccurrences'
|
||||
import { useQa } from './useQa'
|
||||
@@ -56,6 +58,16 @@ export function App(): ReactElement | null {
|
||||
const collapsed = useMemo(() => collapsedIds(doc?.blocks ?? [], view.folds, openedByDiff(changes)), [doc, view.folds, changes])
|
||||
const filter = useMemo(() => applyFilter(doc?.blocks ?? [], excluded, keep), [doc, excluded, keep])
|
||||
const covered = useMemo(() => coveredByEditing(doc?.blocks ?? [], new Set(view.editing)), [doc, view.editing])
|
||||
/** 「只看改动」开着(整个工作区共用,扩展端记着);本地不改,改了发给扩展端、等它发回来 */
|
||||
const [onlyChanges, setOnlyChanges] = useState(false)
|
||||
/** 「只看改动」时点开过的几段没变的块(按第一块的 id),筛选一变就重新折 */
|
||||
const [openedRuns, setOpenedRuns] = useState<ReadonlySet<string>>(NONE)
|
||||
const folded = useMemo(() => doc && changes && onlyChanges
|
||||
? foldUnchanged(doc.blocks, changes, block => !filter.hidden.has(block.id) && !covered.has(block.id), openedRuns, keep)
|
||||
: undefined, [doc, changes, onlyChanges, filter, covered, openedRuns, keep])
|
||||
/** 页面上没画出来的块:被筛掉的,和「只看改动」折起来的 */
|
||||
const unshown = useMemo(() => folded ? new Set([...filter.hidden, ...folded.folded]) : filter.hidden, [filter, folded])
|
||||
const stops = useMemo(() => doc && changes ? changeStops(doc.blocks, changes, filter.hidden) : [], [doc, changes, filter])
|
||||
/** 记下这几块、属性行、子行折叠还是展开,从此不再按默认 */
|
||||
const setFolded = useCallback((ids: string[], folded: boolean) => setView(prev => ({
|
||||
...prev,
|
||||
@@ -65,16 +77,17 @@ export function App(): ReactElement | null {
|
||||
const show = useCallback((ids: string[]) => setKeep(prev => new Set([...prev, ...ids])), [])
|
||||
const revealed = useCallback(() => setReveal(null), [])
|
||||
useScrollPosition(doc)
|
||||
useReveal(doc, reveal, collapsed, filter.hidden, covered, show, expand, revealed)
|
||||
useReveal(doc, reveal, collapsed, unshown, covered, show, expand, revealed)
|
||||
useDefinitionLinks(doc?.version)
|
||||
const nav = useChangeNav(stops, collapsed, expand)
|
||||
const occurrencePage = useMemo((): OccurrencePage | undefined => doc
|
||||
? {
|
||||
blocks: doc.blocks,
|
||||
skip: id => filter.hidden.has(id) || covered.has(id) || view.editing.includes(id),
|
||||
skip: id => unshown.has(id) || covered.has(id) || view.editing.includes(id),
|
||||
collapsed,
|
||||
expand,
|
||||
}
|
||||
: undefined, [doc, filter, covered, view.editing, collapsed, expand])
|
||||
: undefined, [doc, unshown, covered, view.editing, collapsed, expand])
|
||||
const highlight = useOccurrences(doc?.version, doc?.translatorId, occurrencePage)
|
||||
|
||||
useEffect(() => {
|
||||
@@ -95,7 +108,9 @@ export function App(): ReactElement | null {
|
||||
return
|
||||
case 'filter':
|
||||
setExcluded(msg.excluded)
|
||||
setOnlyChanges(msg.onlyChanges)
|
||||
setKeep(NONE)
|
||||
setOpenedRuns(NONE)
|
||||
return
|
||||
case 'diff':
|
||||
setDiff(msg.diff)
|
||||
@@ -133,7 +148,9 @@ export function App(): ReactElement | null {
|
||||
onToggleFold: id => setFolded([id], !collapsed.has(id)),
|
||||
...(qa.state.available && { qa }),
|
||||
...(changes && { diff: changes }),
|
||||
}, [doc, view, collapsed, filter, covered, kindName, focusId, onFocused, setFolded, qa, changes])
|
||||
...(folded && { folded }),
|
||||
onOpenRun: id => setOpenedRuns(prev => new Set([...prev, id])),
|
||||
}, [doc, view, collapsed, filter, covered, kindName, focusId, onFocused, setFolded, qa, changes, folded])
|
||||
|
||||
if (!doc || !tree)
|
||||
return null
|
||||
@@ -150,8 +167,17 @@ export function App(): ReactElement | null {
|
||||
translators={doc.translators}
|
||||
translatorId={doc.translatorId}
|
||||
onSelectTranslator={id => postMessage({ type: 'selectTranslator', id })}
|
||||
below={diff && doc.error === undefined && <DiffBar diff={diff} />}
|
||||
below={diff && doc.error === undefined && (
|
||||
<DiffBar
|
||||
diff={diff}
|
||||
onlyChanges={onlyChanges}
|
||||
onToggleOnly={() => postMessage({ type: 'setOnlyChanges', on: !onlyChanges })}
|
||||
canMove={stops.length > 0}
|
||||
onMove={nav.move}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{changes && diff && <OverviewRuler stops={stops} lineCount={diff.lineCount} onPick={nav.goTo} />}
|
||||
<div className="mx-auto box-content max-w-[880px] px-6 py-5">
|
||||
{diff?.newFile !== undefined && doc.error === undefined && <NewFileBanner detail={diff.newFile} />}
|
||||
{doc.error !== undefined && (
|
||||
|
||||
Reference in new issue
Block a user