mirror of
https://github.com/l0ng-ai/openidea.git
synced 2026-11-06 08:07:49 +00:00
fix(vcs): sync Git Log file tree with diff navigation (#445)
Moving between files in a commit's diff (F7 / next file) left the Git Log changed-files tree on the previous file. The tree now follows the active diff when it belongs to this commit, expanding and revealing the file without taking focus or reopening the diff. Co-authored-by: CS-Bob <31512182+CS-Bob@users.noreply.github.com>
This commit is contained in:
@@ -18,6 +18,7 @@ import clsx from "clsx";
|
||||
import { useVirtualizer } from "@tanstack/react-virtual";
|
||||
import type { Branch, ChangedFile, Commit, RevisionChange } from "@/bindings";
|
||||
import { call, commands } from "@/platform/ipc";
|
||||
import { maybeEditorService, type EditorInput } from "@/workbench/contributions";
|
||||
import {
|
||||
EmptyState,
|
||||
Icon,
|
||||
@@ -32,6 +33,7 @@ import {
|
||||
fileIconName,
|
||||
showContextMenu,
|
||||
type MenuItem,
|
||||
type TreeHandle,
|
||||
T,
|
||||
copyText,
|
||||
} from "@/ui";
|
||||
@@ -76,6 +78,7 @@ import {
|
||||
} from "./branches";
|
||||
import { chooseDateRange, chooseMany, promptText } from "./dialogs";
|
||||
import { buildFileTree, dirKeys, type FileTreeNode } from "./fileTree";
|
||||
import { DIFF_KIND, diffInput } from "./diffInput";
|
||||
import {
|
||||
absolutePath,
|
||||
filesUnder,
|
||||
@@ -1236,6 +1239,9 @@ export function CommitDetails({ commits }: { commits: Commit[] }) {
|
||||
|
||||
const groupByDirectory = useLogOptions((s) => s.groupByDirectory);
|
||||
const [selectedKeys, setSelectedKeys] = useState<ReadonlySet<string>>(() => new Set());
|
||||
const treeRef = useRef<TreeHandle>(null);
|
||||
const [diffToReveal, setDiffToReveal] = useState<{ key: string } | null>(null);
|
||||
const syncingDiff = useRef(false);
|
||||
const changes = useMemo(
|
||||
() => (files && commit ? toLogChanges(files, many ? null : commit, commitRoot) : []),
|
||||
[files, commit, many, commitRoot],
|
||||
@@ -1256,6 +1262,7 @@ export function CommitDetails({ commits }: { commits: Commit[] }) {
|
||||
useEffect(() => () => clearTimeout(previewTimer.current), []);
|
||||
const previewSelection = (sel: ReadonlySet<string>) => {
|
||||
clearTimeout(previewTimer.current);
|
||||
if (syncingDiff.current) return;
|
||||
if (!logOptions().diffPreview || sel.size !== 1) return;
|
||||
const file = fileNodeAt(tree, [...sel][0]!)?.file;
|
||||
// A preview that cannot open (no editor yet, the file went away) is just skipped.
|
||||
@@ -1263,6 +1270,36 @@ export function CommitDetails({ commits }: { commits: Commit[] }) {
|
||||
previewTimer.current = setTimeout(() => void showChangesDiff([file], true).catch(() => undefined), PREVIEW_DELAY);
|
||||
};
|
||||
|
||||
// Follow only this pane's exact diff (path AND revisions); another commit or
|
||||
// Compare with Local must not move its selection. Never take focus from F7.
|
||||
useEffect(() => {
|
||||
const editor = maybeEditorService();
|
||||
const followDiff = (input: EditorInput | null) => {
|
||||
if (input?.kind !== DIFF_KIND) return;
|
||||
const change = ordered.find((c) => diffInput(c.diff).key === input.key);
|
||||
if (!change) return;
|
||||
clearTimeout(previewTimer.current);
|
||||
const rel = relTo(root, change.path);
|
||||
setExpanded((current) => {
|
||||
const next = new Set(current ?? allDirs);
|
||||
for (const key of allDirs) if (rel.startsWith(key.slice(2) + "/")) next.add(key);
|
||||
return next;
|
||||
});
|
||||
setDiffToReveal({ key: `f:${rel}` });
|
||||
};
|
||||
followDiff(editor?.activeInput?.() ?? null);
|
||||
return editor?.onActiveInputChange?.(followDiff);
|
||||
}, [ordered, allDirs, root]);
|
||||
|
||||
// Tree.reveal needs the expanded rows to have rendered. Suppress the reverse
|
||||
// preview update so it cannot reopen the diff and lose its requested chunk.
|
||||
useLayoutEffect(() => {
|
||||
if (!diffToReveal) return;
|
||||
syncingDiff.current = true;
|
||||
treeRef.current?.reveal(diffToReveal.key);
|
||||
syncingDiff.current = false;
|
||||
}, [diffToReveal]);
|
||||
|
||||
useEffect(() => {
|
||||
useLogChanges.setState({ commits: chosen, all: ordered, selected: chosenChanges });
|
||||
}, [chosen, ordered, chosenChanges]);
|
||||
@@ -1344,6 +1381,7 @@ export function CommitDetails({ commits }: { commits: Commit[] }) {
|
||||
)}
|
||||
{files && (
|
||||
<Tree<FileTreeNode<LogChange>>
|
||||
handleRef={treeRef}
|
||||
roots={tree}
|
||||
getKey={(n) => n.key}
|
||||
getLabel={(n) => n.name}
|
||||
|
||||
Reference in New Issue
Block a user