Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Contribute 'Open Commit at GitHub' to SCM Graph item #229386

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
2 changes: 1 addition & 1 deletion extensions/github/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 21 additions & 4 deletions extensions/github/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"license": "MIT",
"version": "0.0.1",
"engines": {
"vscode": "^1.41.0"
"vscode": "^1.94.0"
},
"aiKey": "0c6ae279ed8443289764825290e4f9e2-1a736e7c-1324-4338-be46-fc2a58ae4d14-7255",
"icon": "images/icon.png",
Expand All @@ -29,8 +29,10 @@
"enabledApiProposals": [
"contribShareMenu",
"contribEditSessions",
"contribSourceControlHistoryItemMenu",
"canonicalUriProvider",
"shareProvider"
"shareProvider",
"scmHistoryProvider"
],
"contributes": {
"commands": [
Expand All @@ -54,7 +56,11 @@
"command": "github.openOnVscodeDev",
"title": "Open in vscode.dev",
"icon": "$(globe)"
}
},
{
"command": "github.openCommitOfHistoryItem",
"title": "Open Commit at GitHub"
}
],
"continueEditSession": [
{
Expand Down Expand Up @@ -86,6 +92,10 @@
{
"command": "github.openOnVscodeDev",
"when": "false"
},
{
"command": "github.openCommitOfHistoryItem",
"when": "false"
}
],
"file/share": [
Expand Down Expand Up @@ -127,7 +137,14 @@
"when": "github.hasGitHubRepo && resourceScheme != untitled && remoteName != 'codespaces'",
"group": "0_vscode@0"
}
]
],
"scm/historyItem/context": [
{
"command": "github.openCommitOfHistoryItem",
"when": "github.hasGitHubRepo",
"group": "0_view@10"
}
]
},
"configuration": [
{
Expand Down
25 changes: 25 additions & 0 deletions extensions/github/src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,25 @@ async function openVscodeDevLink(gitAPI: GitAPI): Promise<vscode.Uri | undefined
}
}

async function openCommit(gitAPI: GitAPI, sourceControl: vscode.SourceControl, historyItem: vscode.SourceControlHistoryItem): Promise<void> {
const repo = gitAPI.repositories.find((repo) => repo.rootUri.toString() === sourceControl.rootUri?.toString());
if (!repo) {
return;
}

// TODO - should we be smarter about which remote to go to, or won't it matter?
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lszomoru I'd value your opinion on the three TODOs I left here

// TODO - can we discover if the item is on any remote yet?
const remote = repo.state.remotes[0];
if (!remote?.fetchUrl) {
return;
}

// TODO - will this always work?
const rootUrl = remote.fetchUrl.endsWith('.git') ? remote.fetchUrl.slice(0, -4) : remote.fetchUrl;

vscode.env.openExternal(vscode.Uri.parse(`${rootUrl}/commit/${historyItem.id}`));
}

export function registerCommands(gitAPI: GitAPI): vscode.Disposable {
const disposables = new DisposableStore();

Expand Down Expand Up @@ -61,5 +80,11 @@ export function registerCommands(gitAPI: GitAPI): vscode.Disposable {
return openVscodeDevLink(gitAPI);
}));

disposables.add(vscode.commands.registerCommand('github.openCommitOfHistoryItem', async (sourceControl: vscode.SourceControl, historyItem: vscode.SourceControlHistoryItem) => {
if (sourceControl && historyItem) {
return openCommit(gitAPI, sourceControl, historyItem);
}
}));

return disposables;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

// empty placeholder for edit sessions contribution point from core

// https://github.com/microsoft/vscode/issues/157734 @joyceerhl
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

// empty placeholder declaration for the `file/share`-submenu contribution point
// https://github.com/microsoft/vscode/issues/176316
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

// empty placeholder declaration for the `scm/historyItem/context`-menu contribution point
// https://github.com/microsoft/vscode/issues/201997
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

declare module 'vscode' {
// https://github.com/microsoft/vscode/issues/185269

export interface SourceControl {
historyProvider?: SourceControlHistoryProvider;
}

export interface SourceControlHistoryProvider {
readonly currentHistoryItemRef: SourceControlHistoryItemRef | undefined;
readonly currentHistoryItemRemoteRef: SourceControlHistoryItemRef | undefined;
readonly currentHistoryItemBaseRef: SourceControlHistoryItemRef | undefined;

/**
* Fires when the current history item refs (local, remote, base)
* change after a user action (ex: commit, checkout, fetch, pull, push)
*/
onDidChangeCurrentHistoryItemRefs: Event<void>;

/**
* Fires when history item refs change
*/
onDidChangeHistoryItemRefs: Event<SourceControlHistoryItemRefsChangeEvent>;

provideHistoryItemRefs(historyItemRefs: string[] | undefined, token: CancellationToken): ProviderResult<SourceControlHistoryItemRef[]>;
provideHistoryItems(options: SourceControlHistoryOptions, token: CancellationToken): ProviderResult<SourceControlHistoryItem[]>;
provideHistoryItemChanges(historyItemId: string, historyItemParentId: string | undefined, token: CancellationToken): ProviderResult<SourceControlHistoryItemChange[]>;

resolveHistoryItemRefsCommonAncestor(historyItemRefs: string[], token: CancellationToken): ProviderResult<string>;
}

export interface SourceControlHistoryOptions {
readonly skip?: number;
readonly limit?: number | { id?: string };
readonly historyItemRefs?: readonly string[];
}

export interface SourceControlHistoryItemStatistics {
readonly files: number;
readonly insertions: number;
readonly deletions: number;
}

export interface SourceControlHistoryItem {
readonly id: string;
readonly parentIds: string[];
readonly message: string;
readonly displayId?: string;
readonly author?: string;
readonly timestamp?: number;
readonly statistics?: SourceControlHistoryItemStatistics;
readonly references?: SourceControlHistoryItemRef[];
}

export interface SourceControlHistoryItemRef {
readonly id: string;
readonly name: string;
readonly description?: string;
readonly revision?: string;
readonly category?: string;
readonly icon?: Uri | { light: Uri; dark: Uri } | ThemeIcon;
}

export interface SourceControlHistoryItemChange {
readonly uri: Uri;
readonly originalUri: Uri | undefined;
readonly modifiedUri: Uri | undefined;
readonly renameUri: Uri | undefined;
}

export interface SourceControlHistoryItemRefsChangeEvent {
readonly added: readonly SourceControlHistoryItemRef[];
readonly removed: readonly SourceControlHistoryItemRef[];
readonly modified: readonly SourceControlHistoryItemRef[];

/**
* Flag to indicate if the operation that caused the event to trigger was due
* to a user action or a background operation (ex: Auto Fetch). The flag is used
* to determine whether to automatically refresh the user interface or present
* the user with a visual cue that the user interface is outdated.
*/
readonly silent: boolean;
}
}
55 changes: 50 additions & 5 deletions extensions/github/src/typings/vscode.proposed.shareProvider.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,72 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

// https://github.com/microsoft/vscode/issues/176316
// https://github.com/microsoft/vscode/issues/176316 @joyceerhl

declare module 'vscode' {
export interface TreeItem {
shareableItem?: ShareableItem;
}

/**
* Data about an item which can be shared.
*/
export interface ShareableItem {
/**
* A resource in the workspace that can be shared.
*/
resourceUri: Uri;

/**
* If present, a selection within the `resourceUri`.
*/
selection?: Range;
}

/**
* A provider which generates share links for resources in the editor.
*/
export interface ShareProvider {

/**
* A unique ID for the provider.
* This will be used to activate specific extensions contributing share providers if necessary.
*/
readonly id: string;

/**
* A label which will be used to present this provider's options in the UI.
*/
readonly label: string;

/**
* The order in which the provider should be listed in the UI when there are multiple providers.
*/
readonly priority: number;

provideShare(item: ShareableItem, token: CancellationToken): ProviderResult<Uri>;
/**
*
* @param item Data about an item which can be shared.
* @param token A cancellation token.
* @returns A {@link Uri} representing an external link or sharing text. The provider result
* will be copied to the user's clipboard and presented in a confirmation dialog.
*/
provideShare(item: ShareableItem, token: CancellationToken): ProviderResult<Uri | string>;
}

export namespace window {

/**
* Register a share provider. An extension may register multiple share providers.
* There may be multiple share providers for the same {@link ShareableItem}.
* @param selector A document selector to filter whether the provider should be shown for a {@link ShareableItem}.
* @param provider A share provider.
*/
export function registerShareProvider(selector: DocumentSelector, provider: ShareProvider): Disposable;
}

export interface TreeItem {

/**
* An optional property which, when set, inlines a `Share` option in the context menu for this tree item.
*/
shareableItem?: ShareableItem;
}
}