Skip to content

Commit

Permalink
Adds experimental setting to open changes in a multi-diff editor
Browse files Browse the repository at this point in the history
 - Adds `gitlens.experimental.openChangesInMultiDiffEditor` and requires `multiDiffEditor.experimental.enabled` to also be set
  • Loading branch information
eamodio committed Nov 30, 2023
1 parent 6ed7cb5 commit a3a4656
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 10 deletions.
7 changes: 7 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4295,6 +4295,13 @@
"scope": "window",
"order": 120
},
"gitlens.experimental.openChangesInMultiDiffEditor": {
"type": "boolean",
"default": false,
"markdownDescription": "(Experimental) Specifies whether to open multiple changes in VS Code's experimental multi-diff editor (single tab) or in individual diff editors (multiple tabs)",
"scope": "window",
"order": 120
},
"gitlens.advanced.useSymmetricDifferenceNotation": {
"deprecationMessage": "Deprecated. This setting is no longer used",
"markdownDescription": "Deprecated. This setting is no longer used"
Expand Down
1 change: 1 addition & 0 deletions src/commands/diffWith.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export class DiffWithCommand extends Command {
args = {
repoPath: commit.repoPath,
lhs: {
// Don't need to worry about verifying the previous sha, as the DiffWith command will
sha: commit.unresolvedPreviousSha,
uri: commit.file.originalUri ?? commit.file.uri,
},
Expand Down
1 change: 1 addition & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ export interface Config {
readonly experimental: {
readonly generateCommitMessagePrompt: string;
readonly nativeGit: boolean;
readonly openChangesInMultiDiffEditor: boolean;
};
readonly fileAnnotations: {
readonly command: string | null;
Expand Down
1 change: 1 addition & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,7 @@ export type CoreCommands =
| 'vscode.open'
| 'vscode.openFolder'
| 'vscode.openWith'
| 'vscode.changes'
| 'vscode.diff'
| 'vscode.executeCodeLensProvider'
| 'vscode.executeDocumentSymbolProvider'
Expand Down
79 changes: 70 additions & 9 deletions src/git/actions/commit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,19 @@ import type { OpenWorkingFileCommandArgs } from '../../commands/openWorkingFile'
import type { ShowQuickCommitCommandArgs } from '../../commands/showQuickCommit';
import type { ShowQuickCommitFileCommandArgs } from '../../commands/showQuickCommitFile';
import type { FileAnnotationType } from '../../config';
import { Commands } from '../../constants';
import { Commands, GlyphChars } from '../../constants';
import { Container } from '../../container';
import type { ShowInCommitGraphCommandArgs } from '../../plus/webviews/graph/protocol';
import { executeCommand, executeEditorCommand } from '../../system/command';
import { findOrOpenEditor, findOrOpenEditors } from '../../system/utils';
import { configuration } from '../../system/configuration';
import { findOrOpenEditor, findOrOpenEditors, openChangesEditor } from '../../system/utils';
import { GitUri } from '../gitUri';
import type { GitCommit } from '../models/commit';
import { isCommit } from '../models/commit';
import { deletedOrMissing } from '../models/constants';
import type { GitFile } from '../models/file';
import type { GitRevisionReference } from '../models/reference';
import { getReferenceFromRevision, isUncommitted, isUncommittedStaged } from '../models/reference';
import { getReferenceFromRevision, isUncommitted, isUncommittedStaged, shortenRevision } from '../models/reference';

type Ref = { repoPath: string; ref: string };
type RefRange = { repoPath: string; rhs: string; lhs: string };
Expand Down Expand Up @@ -92,8 +93,11 @@ export async function openAllChanges(
refsOrOptions: RefRange | TextDocumentShowOptions | undefined,
options?: TextDocumentShowOptions,
) {
const useChangesEditor = configuration.get('experimental.openChangesInMultiDiffEditor');

let files;
let refs: RefRange | undefined;
let title;
if (isCommit(commitOrFiles)) {
if (commitOrFiles.files == null) {
await commitOrFiles.ensureFullDetails();
Expand All @@ -103,17 +107,25 @@ export async function openAllChanges(
refs = {
repoPath: commitOrFiles.repoPath,
rhs: commitOrFiles.sha,
// Don't need to worry about verifying the previous sha, as the DiffWith command will
lhs: commitOrFiles.unresolvedPreviousSha,
lhs:
commitOrFiles.resolvedPreviousSha ??
(useChangesEditor
? (await commitOrFiles.getPreviousSha()) ?? commitOrFiles.unresolvedPreviousSha
: // Don't need to worry about verifying the previous sha, as the DiffWith command will
commitOrFiles.unresolvedPreviousSha),
};

options = refsOrOptions as TextDocumentShowOptions | undefined;
title = `Changes in ${shortenRevision(refs.rhs)}`;
} else {
files = commitOrFiles;
refs = refsOrOptions as RefRange;
title = `Changes between ${shortenRevision(refs.lhs)} ${GlyphChars.ArrowLeftRightLong} ${shortenRevision(
refs.rhs,
)}`;
}

if (files.length > 10) {
if (files.length > (useChangesEditor ? 50 : 10)) {
const result = await window.showWarningMessage(
`Are you sure you want to open the changes for all ${files.length} files?`,
{ title: 'Yes' },
Expand All @@ -124,9 +136,28 @@ export async function openAllChanges(

options = { preserveFocus: true, preview: false, ...options };

if (!useChangesEditor) {
for (const file of files) {
await openChanges(file, refs, options);
}
return;
}

const { git } = Container.instance;

const resources: Parameters<typeof openChangesEditor>[0] = [];
for (const file of files) {
await openChanges(file, refs, options);
const rhs =
file.status === 'D' ? undefined : (await git.getBestRevisionUri(refs.repoPath, file.path, refs.rhs))!;
const lhs =
file.status === 'A'
? undefined
: (await git.getBestRevisionUri(refs.repoPath, file.originalPath ?? file.path, refs.lhs))!;
const uri = (file.status === 'D' ? lhs : rhs) ?? GitUri.fromFile(file, refs.repoPath);
resources.push({ uri: uri, lhs: lhs, rhs: rhs });
}

await openChangesEditor(resources, title, options);
}

export async function openAllChangesWithDiffTool(commit: GitCommit): Promise<void>;
Expand Down Expand Up @@ -191,7 +222,9 @@ export async function openAllChangesWithWorking(
ref = refOrOptions as Ref;
}

if (files.length > 10) {
const useChangesEditor = configuration.get('experimental.openChangesInMultiDiffEditor');

if (files.length > (useChangesEditor ? 50 : 10)) {
const result = await window.showWarningMessage(
`Are you sure you want to open the changes for all ${files.length} files?`,
{ title: 'Yes' },
Expand All @@ -202,9 +235,37 @@ export async function openAllChangesWithWorking(

options = { preserveFocus: true, preview: false, ...options };

if (!useChangesEditor) {
for (const file of files) {
await openChangesWithWorking(file, ref, options);
}
return;
}

const { git } = Container.instance;

const resources: Parameters<typeof openChangesEditor>[0] = [];
for (const file of files) {
await openChangesWithWorking(file, ref, options);
const rhs =
file.status === 'D'
? undefined
: await git.getWorkingUri(
ref.repoPath,
(await git.getBestRevisionUri(ref.repoPath, file.path, ref.ref))!,
);
const lhs =
file.status === 'A'
? undefined
: (await git.getBestRevisionUri(ref.repoPath, file.originalPath ?? file.path, ref.ref))!;
const uri = (file.status === 'D' ? lhs : rhs) ?? GitUri.fromFile(file, ref.repoPath);
resources.push({ uri: uri, lhs: lhs, rhs: rhs });
}

await openChangesEditor(
resources,
`Changes between ${shortenRevision(ref.ref)} ${GlyphChars.ArrowLeftRightLong} Working Tree`,
options,
);
}

export async function openChanges(
Expand Down
9 changes: 8 additions & 1 deletion src/git/models/commit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,10 @@ export class GitCommit implements GitRevisionReference {
}

private _resolvedPreviousSha: string | undefined;
get resolvedPreviousSha(): string | undefined {
return this._resolvedPreviousSha;
}

get unresolvedPreviousSha(): string {
const previousSha =
this._resolvedPreviousSha ??
Expand Down Expand Up @@ -517,7 +521,10 @@ export class GitCommit implements GitRevisionReference {
}

const parent = this.parents[0];
if (parent != null && isSha(parent)) return parent;
if (parent != null && isSha(parent)) {
this._resolvedPreviousSha = parent;
return parent;
}

const sha = await this.container.git.resolveReference(
this.repoPath,
Expand Down
1 change: 1 addition & 0 deletions src/system/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ export function executeCoreCommand<T extends [...unknown[]] = [], U = any>(
if (
command != 'setContext' &&
command !== 'vscode.executeDocumentSymbolProvider' &&
command !== 'vscode.changes' &&
command !== 'vscode.diff' &&
command !== 'vscode.open'
) {
Expand Down
16 changes: 16 additions & 0 deletions src/system/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,22 @@ export async function openEditor(
}
}

export async function openChangesEditor(
resources: { uri: Uri; lhs: Uri | undefined; rhs: Uri | undefined }[],
title: string,
_options?: TextDocumentShowOptions,
): Promise<void> {
try {
await executeCoreCommand(
'vscode.changes',
title,
resources.map(r => [r.uri, r.lhs, r.rhs]),
);
} catch (ex) {
Logger.error(ex, 'openChangesEditor');
}
}

export async function openDiffEditor(
lhs: Uri,
rhs: Uri,
Expand Down

0 comments on commit a3a4656

Please sign in to comment.