Files
openidea/src/features/vcs/gitTabs.ts
T
Shohruh Ismoilovandshohruh-genius 9f2e6b570f feat(vcs): correct Git log graph projection and expand history views (#1076)
Git Log could lose commits when filtering by several paths, draw wrong
ancestry after filtering or collapsing rows, and open the wrong
repository in multi-root views. The graph is now projected over the full
commit DAG and laid out in Bek order, so filtered and collapsed views keep
the real ancestry; each log view keeps its own filters and requests.

Commit metadata, messages and path changes are kept in a persistent index
(by object id, in the IDE's cache directory) with seekable paging, and the
log gains parent-aware merge comparisons, a lazy revision browser,
read-only logs of repositories outside the project (opened with command
execution disabled), commit bookmarks, configurable built-in columns and
batched commit details. The adapted IntelliJ algorithms are attributed in
THIRD_PARTY_LICENSES.md.

Closes #872

Co-authored-by: shohruh-genius <7658451+shohruh-genius@users.noreply.github.com>
2026-11-05 02:31:32 +08:00

70 lines
2.7 KiB
TypeScript

/**
* Content tabs of the Commit and Git tool windows. With the non-modal commit interface
* the Commit window has Commit | Shelf | Stash; with the modal one (no Commit window)
* the Git window takes them as Local Changes | Shelf | Stash, before Log | Console |
* Worktrees. "Combine stashes and shelves" makes Shelf and Stash one tab.
*/
import { tx } from "@/platform/i18n";
import type { CommitTab } from "./commitStore";
import type { LogTab } from "./logStore";
import { baseName } from "./model";
export interface ContentTab {
id: string;
label: string;
closable?: boolean;
/** Count shown after the label (shelves / stashes). */
count?: number;
}
export interface StashTabsInput {
combine: boolean;
shelfCount: number;
stashCount: number;
/** The selected tab: an empty Shelf tab stays while it is shown. */
tab: string;
}
/** The tab a Shelf / Stash request lands on (the combined one when they are combined). */
export function stashTabOf(tab: CommitTab, combine: boolean): CommitTab {
return combine && tab === "shelf" ? "stashes" : tab;
}
/** Shelf and Stash tabs (Shelf only when there are shelves), or the combined one. */
export function stashTabs({ combine, shelfCount, stashCount, tab }: StashTabsInput): ContentTab[] {
if (combine) return [{ id: "stashes", label: "Stashes and Shelves", count: stashCount + shelfCount || undefined }];
return [
...(shelfCount || tab === "shelf" ? [{ id: "shelf", label: "Shelf", count: shelfCount || undefined }] : []),
{ id: "stashes", label: "Stash", count: stashCount || undefined },
];
}
/** Title of a log tab of its own. */
export function logTabLabel(t: LogTab): string {
return t.kind === "history" ? tx`History: ${baseName(t.target)}` : tx`Log: ${t.target}`;
}
export interface GitTabsInput extends StashTabsInput {
/** Modal commit interface: the Git window also shows the local changes, shelves and stashes. */
modal: boolean;
logTabs: readonly LogTab[];
}
export function gitTabs(input: GitTabsInput): ContentTab[] {
return [
...(input.modal ? [{ id: "changes", label: "Local Changes" }, ...stashTabs(input)] : []),
{ id: "log", label: "Log" },
...input.logTabs
.filter((t) => t.location !== "editor")
.map((t) => ({ id: t.id, label: logTabLabel(t), closable: true })),
{ id: "console", label: "Console" },
{ id: "worktrees", label: "Worktrees" },
];
}
/** The tab shown for `tab`: a tab no longer listed (the commit interface changed) falls back to the Log. */
export function shownTab(tab: string, tabs: readonly ContentTab[], combine: boolean): string {
const id = combine && tab === "shelf" ? "stashes" : tab;
return tabs.some((t) => t.id === id) ? id : "log";
}