SCM - add support for multi-select in the history graph (#222186)

This commit is contained in:
Ladislau Szomoru
2024-07-19 16:23:01 +02:00
committed by GitHub
parent 39450a2a81
commit 0c0837460f
2 changed files with 85 additions and 27 deletions

View File

@@ -4192,17 +4192,33 @@ export class CommandCenter {
}
@command('git.viewCommit', { repository: true })
async viewCommit(repository: Repository, historyItem: SourceControlHistoryItem): Promise<void> {
if (!repository || !historyItem) {
async viewCommit(repository: Repository, historyItem1: SourceControlHistoryItem, historyItem2?: SourceControlHistoryItem): Promise<void> {
if (!repository || !historyItem1) {
return;
}
const commit = await repository.getCommit(historyItem.id);
const title = `${historyItem.id.substring(0, 8)} - ${commit.message}`;
if (historyItem2) {
const mergeBase = await repository.getMergeBase(historyItem1.id, historyItem2.id);
if (!mergeBase || (mergeBase !== historyItem1.id && mergeBase !== historyItem2.id)) {
return;
}
}
const multiDiffSourceUri = toGitUri(Uri.file(repository.root), historyItem.id, { scheme: 'git-commit' });
const historyItemId = historyItem1.id;
const historyItemParentId = historyItem2 ? historyItem2.id :
historyItem1.parentIds.length > 0 ? historyItem1.parentIds[0] : `${historyItemId}^`;
await this._viewChanges(repository, historyItem, multiDiffSourceUri, title);
let title = '';
if (!historyItem2) {
const commit = await repository.getCommit(historyItemId);
title = `${historyItemId.substring(0, 8)} - ${commit.message}`;
} else {
title = l10n.t('All Changes ({0} ↔ {1})', historyItemParentId.substring(0, 8), historyItemId.substring(0, 8));
}
const multiDiffSourceUri = toGitUri(Uri.file(repository.root), `${historyItemParentId}..${historyItemId}`, { scheme: 'git-commit', });
await this._viewChanges(repository, historyItemId, historyItemParentId, multiDiffSourceUri, title);
}
@command('git.viewAllChanges', { repository: true })
@@ -4217,18 +4233,17 @@ export class CommandCenter {
const multiDiffSourceUri = toGitUri(Uri.file(repository.root), historyItem.id, { scheme: 'git-changes' });
await this._viewChanges(repository, historyItem, multiDiffSourceUri, title);
await this._viewChanges(repository, modifiedShortRef, originalShortRef, multiDiffSourceUri, title);
}
async _viewChanges(repository: Repository, historyItem: SourceControlHistoryItem, multiDiffSourceUri: Uri, title: string): Promise<void> {
const historyItemParentId = historyItem.parentIds.length > 0 ? historyItem.parentIds[0] : `${historyItem.id}^`;
const changes = await repository.diffBetween(historyItemParentId, historyItem.id);
async _viewChanges(repository: Repository, historyItemId: string, historyItemParentId: string, multiDiffSourceUri: Uri, title: string): Promise<void> {
const changes = await repository.diffBetween(historyItemParentId, historyItemId);
if (changes.length === 0) {
return;
}
const resources = changes.map(c => toMultiFileDiffEditorUris(c, historyItemParentId, historyItem.id));
const resources = changes.map(c => toMultiFileDiffEditorUris(c, historyItemParentId, historyItemId));
await commands.executeCommand('_workbench.openMultiDiffEditor', { multiDiffSourceUri, title, resources });
}

View File

@@ -822,28 +822,66 @@ class HistoryItemGroupRenderer implements ICompressibleTreeRenderer<SCMHistoryIt
class HistoryItemActionRunner extends ActionRunner {
protected override async runAction(action: IAction, context: SCMHistoryItemTreeElement | SCMHistoryItemViewModelTreeElement): Promise<any> {
protected override async runAction(action: IAction, context: SCMHistoryItemTreeElement): Promise<any> {
if (!(action instanceof MenuItemAction)) {
return super.runAction(action, context);
}
const args: (ISCMProvider | ISCMHistoryItem)[] = [];
if (isSCMHistoryItemTreeElement(context)) {
args.push(context.historyItemGroup.repository.provider);
} else {
args.push(context.repository.provider);
args.push(context.historyItemGroup.repository.provider);
args.push({
id: context.id,
parentIds: context.parentIds,
message: context.message,
author: context.author,
icon: context.icon,
timestamp: context.timestamp,
statistics: context.statistics,
} satisfies ISCMHistoryItem);
await action.run(...args);
}
}
class HistoryItemActionRunner2 extends ActionRunner {
constructor(private readonly getSelectedHistoryItems: () => SCMHistoryItemViewModelTreeElement[]) {
super();
}
protected override async runAction(action: IAction, context: SCMHistoryItemViewModelTreeElement): Promise<any> {
if (!(action instanceof MenuItemAction)) {
return super.runAction(action, context);
}
const historyItem = isSCMHistoryItemTreeElement(context) ? context : context.historyItemViewModel.historyItem;
args.push({
id: historyItem.id,
parentIds: historyItem.parentIds,
message: historyItem.message,
author: historyItem.author,
icon: historyItem.icon,
timestamp: historyItem.timestamp,
statistics: historyItem.statistics,
} satisfies ISCMHistoryItem);
const args: (ISCMProvider | ISCMHistoryItem)[] = [];
args.push(context.repository.provider);
const selection = this.getSelectedHistoryItems();
const contextIsSelected = selection.some(s => s === context);
if (contextIsSelected && selection.length > 1) {
args.push(...[selection[0], selection[selection.length - 1]]
.map(h => (
{
id: h.historyItemViewModel.historyItem.id,
parentIds: h.historyItemViewModel.historyItem.parentIds,
message: h.historyItemViewModel.historyItem.message,
author: h.historyItemViewModel.historyItem.author,
icon: h.historyItemViewModel.historyItem.icon,
timestamp: h.historyItemViewModel.historyItem.timestamp,
statistics: h.historyItemViewModel.historyItem.statistics,
} satisfies ISCMHistoryItem)));
} else {
args.push({
id: context.historyItemViewModel.historyItem.id,
parentIds: context.historyItemViewModel.historyItem.parentIds,
message: context.historyItemViewModel.historyItem.message,
author: context.historyItemViewModel.historyItem.author,
icon: context.historyItemViewModel.historyItem.icon,
timestamp: context.historyItemViewModel.historyItem.timestamp,
statistics: context.historyItemViewModel.historyItem.statistics,
} satisfies ISCMHistoryItem);
}
await action.run(...args);
}
@@ -3517,7 +3555,7 @@ export class SCMViewPane extends ViewPane {
const menus = this.scmViewService.menus.getRepositoryMenus(element.repository.provider);
const menu = menus.historyProviderMenu?.getHistoryItemMenu2(element);
if (menu) {
actionRunner = new HistoryItemActionRunner();
actionRunner = new HistoryItemActionRunner2(() => this.getSelectedHistoryItems());
actions = collectContextMenuActions(menu);
}
}
@@ -3544,6 +3582,11 @@ export class SCMViewPane extends ViewPane {
.filter(r => !!r && !isSCMResourceGroup(r))! as any;
}
private getSelectedHistoryItems(): SCMHistoryItemViewModelTreeElement[] {
return this.tree.getSelection()
.filter(r => !!r && isSCMHistoryItemViewModelTreeElement(r))!;
}
private getViewMode(): ViewMode {
let mode = this.configurationService.getValue<'tree' | 'list'>('scm.defaultViewMode') === 'list' ? ViewMode.List : ViewMode.Tree;
const storageMode = this.storageService.get(`scm.viewMode`, StorageScope.WORKSPACE) as ViewMode;