Skip to content

Commit

Permalink
Implement Share > Copy Permalink as Markdown (#4886)
Browse files Browse the repository at this point in the history
  • Loading branch information
joyceerhl authored Jun 9, 2023
1 parent 66d6913 commit a3d2482
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 9 deletions.
55 changes: 50 additions & 5 deletions src/@types/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;
}
}
56 changes: 52 additions & 4 deletions src/issues/shareProviders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import * as pathLib from 'path';
import * as vscode from 'vscode';
import { Commit, Remote, Repository } from '../api/api';
import { GitApiImpl } from '../api/api1';
Expand All @@ -22,6 +23,7 @@ export class ShareProviderManager implements vscode.Disposable {
this.disposables.push(
new GitHubDevShareProvider(repositoryManager, gitAPI),
new GitHubPermalinkShareProvider(repositoryManager, gitAPI),
new GitHubPermalinkAsMarkdownShareProvider(repositoryManager, gitAPI),
new GitHubHeadLinkShareProvider(repositoryManager, gitAPI)
);
}
Expand Down Expand Up @@ -97,7 +99,7 @@ abstract class AbstractShareProvider implements vscode.Disposable, vscode.ShareP
protected abstract getBlob(folderManager: FolderRepositoryManager, uri: vscode.Uri): Promise<string>;
protected abstract getUpstream(repository: Repository, commit: string): Promise<Remote | undefined>;

public async provideShare(item: vscode.ShareableItem): Promise<vscode.Uri | undefined> {
public async provideShare(item: vscode.ShareableItem): Promise<vscode.Uri | string | undefined> {
// Get the blob
const folderManager = this.repositoryManager.getManagerForFile(item.resourceUri);
if (!folderManager) {
Expand Down Expand Up @@ -147,8 +149,14 @@ export class GitHubDevShareProvider extends AbstractShareProvider implements vsc
}

export class GitHubPermalinkShareProvider extends AbstractShareProvider implements vscode.ShareProvider {
constructor(repositoryManager: RepositoriesManager, gitApi: GitApiImpl) {
super(repositoryManager, gitApi, 'githubComPermalink', vscode.l10n.t('Copy GitHub Permalink'), 11);
constructor(
repositoryManager: RepositoriesManager,
gitApi: GitApiImpl,
id: string = 'githubComPermalink',
label: string = vscode.l10n.t('Copy GitHub Permalink'),
priority: number = 11
) {
super(repositoryManager, gitApi, id, label, priority);
}

protected shouldRegister() {
Expand Down Expand Up @@ -194,9 +202,49 @@ export class GitHubPermalinkShareProvider extends AbstractShareProvider implemen
}
}

export class GitHubPermalinkAsMarkdownShareProvider extends GitHubPermalinkShareProvider {

constructor(repositoryManager: RepositoriesManager, gitApi: GitApiImpl) {
super(repositoryManager, gitApi, 'githubComPermalinkAsMarkdown', vscode.l10n.t('Copy GitHub Permalink as Markdown'), 12);
}

async provideShare(item: vscode.ShareableItem): Promise<vscode.Uri | string | undefined> {
const link = await super.provideShare(item);

const text = await this.getMarkdownLinkText(item);
if (link) {
return `[${text?.trim() ?? ''}](${link.toString()})`;
}
}

private async getMarkdownLinkText(item: vscode.ShareableItem): Promise<string | undefined> {
const fileName = pathLib.basename(item.resourceUri.path);

if (item.selection) {
const document = await vscode.workspace.openTextDocument(item.resourceUri);

const editorSelection = item.selection.start === item.selection.end
? item.selection
: new vscode.Range(item.selection.start, new vscode.Position(item.selection.start.line + 1, 0));

const selectedText = document.getText(editorSelection);
if (selectedText) {
return selectedText;
}

const wordRange = document.getWordRangeAtPosition(item.selection.start);
if (wordRange) {
return document.getText(wordRange);
}
}

return fileName;
}
}

export class GitHubHeadLinkShareProvider extends AbstractShareProvider implements vscode.ShareProvider {
constructor(repositoryManager: RepositoriesManager, gitApi: GitApiImpl) {
super(repositoryManager, gitApi, 'githubComHeadLink', vscode.l10n.t('Copy GitHub HEAD Link'), 12);
super(repositoryManager, gitApi, 'githubComHeadLink', vscode.l10n.t('Copy GitHub HEAD Link'), 13);
}

protected shouldRegister() {
Expand Down

0 comments on commit a3d2482

Please sign in to comment.