diff --git a/extensions/git/src/historyProvider.ts b/extensions/git/src/historyProvider.ts index a7fd51cef93..60e6cddb24a 100644 --- a/extensions/git/src/historyProvider.ts +++ b/extensions/git/src/historyProvider.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ -import { Disposable, Event, EventEmitter, FileDecoration, FileDecorationProvider, SourceControlActionButton, SourceControlHistoryItem, SourceControlHistoryItemChange, SourceControlHistoryItemGroup, SourceControlHistoryOptions, SourceControlHistoryProvider, ThemeIcon, Uri, window, l10n } from 'vscode'; +import { Disposable, Event, EventEmitter, FileDecoration, FileDecorationProvider, SourceControlActionButton, SourceControlHistoryItem, SourceControlHistoryItemChange, SourceControlHistoryItemGroup, SourceControlHistoryOptions, SourceControlHistoryProvider, ThemeIcon, Uri, window, l10n, SourceControlHistoryItemStatistics } from 'vscode'; import { Repository, Resource } from './repository'; import { IDisposable } from './util'; import { toGitUri } from './uri'; @@ -195,8 +195,22 @@ export class GitHistoryProvider implements SourceControlHistoryProvider, FileDec } private async getSummaryHistoryItem(ref1: string, ref2: string): Promise { + let statistics: SourceControlHistoryItemStatistics | undefined; + const diffShortStat = await this.repository.diffBetweenShortStat(ref1, ref2); - return { id: `${ref1}..${ref2}`, parentIds: [], icon: new ThemeIcon('files'), label: l10n.t('All Changes'), description: diffShortStat }; + const regex = /(\d+) files? changed(?:, (\d+) insertions\(\+\))?(?:, (\d+) deletions\(-\))?/; + const matches = diffShortStat.match(regex); + + if (matches) { + const [, files, insertions = undefined, deletions = undefined] = matches; + statistics = { + files: parseInt(files), + insertions: parseInt(insertions ?? '0'), + deletions: parseInt(deletions ?? '0') + }; + } + + return { id: `${ref1}..${ref2}`, parentIds: [], icon: new ThemeIcon('files'), label: l10n.t('All Changes'), statistics }; } dispose(): void { diff --git a/src/vs/workbench/api/common/extHostSCM.ts b/src/vs/workbench/api/common/extHostSCM.ts index 6a7132ad998..7f372aea4c6 100644 --- a/src/vs/workbench/api/common/extHostSCM.ts +++ b/src/vs/workbench/api/common/extHostSCM.ts @@ -1002,14 +1002,7 @@ export class ExtHostSCM implements ExtHostSCMShape { const historyProvider = this._sourceControls.get(sourceControlHandle)?.historyProvider; const historyItems = await historyProvider?.provideHistoryItems(historyItemGroupId, options, token); - return historyItems?.map(item => ({ - id: item.id, - parentIds: item.parentIds, - label: item.label, - description: item.description, - icon: getHistoryItemIconDto(item), - timestamp: item.timestamp, - })) ?? undefined; + return historyItems?.map(item => ({ ...item, icon: getHistoryItemIconDto(item) })) ?? undefined; } async $provideHistoryItemChanges(sourceControlHandle: number, historyItemId: string, token: CancellationToken): Promise { diff --git a/src/vs/workbench/contrib/scm/browser/media/scm.css b/src/vs/workbench/contrib/scm/browser/media/scm.css index 9ceb67dff74..2aa7d1cf30f 100644 --- a/src/vs/workbench/contrib/scm/browser/media/scm.css +++ b/src/vs/workbench/contrib/scm/browser/media/scm.css @@ -144,6 +144,49 @@ padding-right: 4px; } +.scm-view .monaco-list-row .history-item { + display: flex; + align-items: center; +} + +.scm-view .monaco-list-row .history-item .stats-container { + display: flex; + font-size: 11px; + line-height: 11px; +} + +.scm-view .monaco-list-row .history-item .stats-container .monaco-icon-label { + min-height: 18px; + padding: 0 2px; + border-radius: 2px; + border: 1px solid var(--vscode-contrastBorder); + background-color: var(--vscode-badge-background); + color: var(--vscode-badge-foreground); +} + +.scm-view .monaco-list-row .history-item .stats-container .monaco-icon-label .codicon { + margin: 0 1px; +} + +.scm-view .monaco-list-row .history-item .stats-container .monaco-icon-label .codicon.codicon-diff-added { + color: var(--vscode-editorGutter-addedBackground); + margin-top: 1px; +} + +.scm-view .monaco-list-row .history-item .stats-container .monaco-icon-label .codicon.codicon-diff-removed { + color: var(--vscode-editorGutter-deletedBackground); + margin-top: 1px; +} + +.scm-view .monaco-list-row .history-item .stats-container .monaco-icon-label .monaco-highlighted-label { + display: flex; + align-items: center; +} + +.scm-view .monaco-list-row .history-item .stats-container .codicon { + font-size: 11px; +} + .scm-view .monaco-list-row .history-item .monaco-icon-label .icon-container { display: flex; font-size: 14px; diff --git a/src/vs/workbench/contrib/scm/browser/scmViewPane.ts b/src/vs/workbench/contrib/scm/browser/scmViewPane.ts index 85488c1de77..6829069c7e4 100644 --- a/src/vs/workbench/contrib/scm/browser/scmViewPane.ts +++ b/src/vs/workbench/contrib/scm/browser/scmViewPane.ts @@ -735,6 +735,8 @@ interface HistoryItemTemplate { readonly iconContainer: HTMLElement; // readonly avatarImg: HTMLImageElement; readonly iconLabel: IconLabel; + readonly statsContainer: HTMLElement; + readonly statsLabel: IconLabel; // readonly timestampContainer: HTMLElement; // readonly timestamp: HTMLSpanElement; readonly disposables: IDisposable; @@ -750,15 +752,19 @@ class HistoryItemRenderer implements ICompressibleTreeRenderer, index: number, templateData: HistoryItemTemplate, height: number | undefined): void { @@ -780,6 +786,17 @@ class HistoryItemRenderer implements ICompressibleTreeRenderer