mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-21 00:59:03 +01:00
Add a Share menu and a share vscode.dev command (#152765)
* Add a share menu Fixes #146309 * Add vscod.dev command in github extension * Make share menu proposed * Add share submenu into editor context * Add proposed to editor share menu
This commit is contained in:
@@ -7,6 +7,7 @@ import * as vscode from 'vscode';
|
||||
import { API as GitAPI } from './typings/git';
|
||||
import { publishRepository } from './publish';
|
||||
import { DisposableStore } from './util';
|
||||
import { getPermalink } from './links';
|
||||
|
||||
export function registerCommands(gitAPI: GitAPI): vscode.Disposable {
|
||||
const disposables = new DisposableStore();
|
||||
@@ -19,5 +20,16 @@ export function registerCommands(gitAPI: GitAPI): vscode.Disposable {
|
||||
}
|
||||
}));
|
||||
|
||||
disposables.add(vscode.commands.registerCommand('github.copyVscodeDevLink', async () => {
|
||||
try {
|
||||
const permalink = getPermalink(gitAPI, 'https://vscode.dev/github');
|
||||
if (permalink) {
|
||||
vscode.env.clipboard.writeText(permalink);
|
||||
}
|
||||
} catch (err) {
|
||||
vscode.window.showErrorMessage(err.message);
|
||||
}
|
||||
}));
|
||||
|
||||
return disposables;
|
||||
}
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
|
||||
import { commands, Disposable, ExtensionContext, extensions } from 'vscode';
|
||||
import { GithubRemoteSourceProvider } from './remoteSourceProvider';
|
||||
import { GitExtension } from './typings/git';
|
||||
import { API, GitExtension } from './typings/git';
|
||||
import { registerCommands } from './commands';
|
||||
import { GithubCredentialProviderManager } from './credentialProvider';
|
||||
import { DisposableStore } from './util';
|
||||
import { DisposableStore, repositoryHasGitHubRemote } from './util';
|
||||
import { GithubPushErrorHandler } from './pushErrorHandler';
|
||||
import { GitBaseExtension } from './typings/git-base';
|
||||
import { GithubRemoteSourcePublisher } from './remoteSourcePublisher';
|
||||
@@ -48,6 +48,21 @@ function initializeGitBaseExtension(): Disposable {
|
||||
return disposables;
|
||||
}
|
||||
|
||||
function setGitHubContext(gitAPI: API, disposables: DisposableStore) {
|
||||
if (gitAPI.repositories.find(repo => repositoryHasGitHubRemote(repo))) {
|
||||
commands.executeCommand('setContext', 'github.hasGitHubRepo', true);
|
||||
} else {
|
||||
const openRepoDisposable = gitAPI.onDidOpenRepository(async e => {
|
||||
await e.status();
|
||||
if (repositoryHasGitHubRemote(e)) {
|
||||
commands.executeCommand('setContext', 'github.hasGitHubRepo', true);
|
||||
openRepoDisposable.dispose();
|
||||
}
|
||||
});
|
||||
disposables.add(openRepoDisposable);
|
||||
}
|
||||
}
|
||||
|
||||
function initializeGitExtension(): Disposable {
|
||||
const disposables = new DisposableStore();
|
||||
|
||||
@@ -64,6 +79,7 @@ function initializeGitExtension(): Disposable {
|
||||
disposables.add(new GithubCredentialProviderManager(gitAPI));
|
||||
disposables.add(gitAPI.registerPushErrorHandler(new GithubPushErrorHandler()));
|
||||
disposables.add(gitAPI.registerRemoteSourcePublisher(new GithubRemoteSourcePublisher(gitAPI)));
|
||||
setGitHubContext(gitAPI, disposables);
|
||||
|
||||
commands.executeCommand('setContext', 'git-base.gitEnabled', true);
|
||||
} else {
|
||||
|
||||
78
extensions/github/src/links.ts
Normal file
78
extensions/github/src/links.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { API as GitAPI, Repository } from './typings/git';
|
||||
import { getRepositoryFromUrl } from './util';
|
||||
|
||||
export function isFileInRepo(repository: Repository, file: vscode.Uri): boolean {
|
||||
return file.path.toLowerCase() === repository.rootUri.path.toLowerCase() ||
|
||||
(file.path.toLowerCase().startsWith(repository.rootUri.path.toLowerCase()) &&
|
||||
file.path.substring(repository.rootUri.path.length).startsWith('/'));
|
||||
}
|
||||
|
||||
export function getRepositoryForFile(gitAPI: GitAPI, file: vscode.Uri): Repository | undefined {
|
||||
for (const repository of gitAPI.repositories) {
|
||||
if (isFileInRepo(repository, file)) {
|
||||
return repository;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getFileAndPosition(): { uri: vscode.Uri | undefined; range: vscode.Range | undefined } {
|
||||
let uri: vscode.Uri | undefined;
|
||||
let range: vscode.Range | undefined;
|
||||
if (vscode.window.activeTextEditor) {
|
||||
uri = vscode.window.activeTextEditor.document.uri;
|
||||
range = vscode.window.activeTextEditor.selection;
|
||||
}
|
||||
return { uri, range };
|
||||
}
|
||||
|
||||
function rangeString(range: vscode.Range | undefined) {
|
||||
if (!range) {
|
||||
return '';
|
||||
}
|
||||
let hash = `#L${range.start.line + 1}`;
|
||||
if (range.start.line !== range.end.line) {
|
||||
hash += `-L${range.end.line + 1}`;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
export function getPermalink(gitAPI: GitAPI, hostPrefix?: string): string | undefined {
|
||||
hostPrefix = hostPrefix ?? 'https://github.com';
|
||||
const { uri, range } = getFileAndPosition();
|
||||
if (!uri) {
|
||||
return;
|
||||
}
|
||||
const gitRepo = getRepositoryForFile(gitAPI, uri);
|
||||
if (!gitRepo) {
|
||||
return;
|
||||
}
|
||||
let repo: { owner: string; repo: string } | undefined;
|
||||
gitRepo.state.remotes.find(remote => {
|
||||
if (remote.fetchUrl) {
|
||||
const foundRepo = getRepositoryFromUrl(remote.fetchUrl);
|
||||
if (foundRepo && (remote.name === gitRepo.state.HEAD?.upstream?.remote)) {
|
||||
repo = foundRepo;
|
||||
return;
|
||||
} else if (foundRepo && !repo) {
|
||||
repo = foundRepo;
|
||||
}
|
||||
}
|
||||
return;
|
||||
});
|
||||
if (!repo) {
|
||||
return;
|
||||
}
|
||||
|
||||
const commitHash = gitRepo.state.HEAD?.commit;
|
||||
const pathSegment = uri.path.substring(gitRepo.rootUri.path.length);
|
||||
|
||||
return `${hostPrefix}/${repo.owner}/${repo.repo}/blob/${commitHash
|
||||
}${pathSegment}${rangeString(range)}`;
|
||||
}
|
||||
@@ -7,17 +7,7 @@ import { workspace } from 'vscode';
|
||||
import { RemoteSourceProvider, RemoteSource } from './typings/git-base';
|
||||
import { getOctokit } from './auth';
|
||||
import { Octokit } from '@octokit/rest';
|
||||
|
||||
function getRepositoryFromUrl(url: string): { owner: string; repo: string } | undefined {
|
||||
const match = /^https:\/\/github\.com\/([^/]+)\/([^/]+)\.git/i.exec(url)
|
||||
|| /^git@github\.com:([^/]+)\/([^/]+)\.git/i.exec(url);
|
||||
return match ? { owner: match[1], repo: match[2] } : undefined;
|
||||
}
|
||||
|
||||
function getRepositoryFromQuery(query: string): { owner: string; repo: string } | undefined {
|
||||
const match = /^([^/]+)\/([^/]+)$/i.exec(query);
|
||||
return match ? { owner: match[1], repo: match[2] } : undefined;
|
||||
}
|
||||
import { getRepositoryFromQuery, getRepositoryFromUrl } from './util';
|
||||
|
||||
function asRemoteSource(raw: any): RemoteSource {
|
||||
const protocol = workspace.getConfiguration('github').get<'https' | 'ssh'>('gitProtocol');
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { Repository } from './typings/git';
|
||||
|
||||
export class DisposableStore {
|
||||
|
||||
@@ -21,3 +22,18 @@ export class DisposableStore {
|
||||
this.disposables.clear();
|
||||
}
|
||||
}
|
||||
|
||||
export function getRepositoryFromUrl(url: string): { owner: string; repo: string } | undefined {
|
||||
const match = /^https:\/\/github\.com\/([^/]+)\/([^/]+?)(\.git)?$/i.exec(url)
|
||||
|| /^git@github\.com:([^/]+)\/([^/]+?)(\.git)?$/i.exec(url);
|
||||
return match ? { owner: match[1], repo: match[2] } : undefined;
|
||||
}
|
||||
|
||||
export function getRepositoryFromQuery(query: string): { owner: string; repo: string } | undefined {
|
||||
const match = /^([^/]+)\/([^/]+)$/i.exec(query);
|
||||
return match ? { owner: match[1], repo: match[2] } : undefined;
|
||||
}
|
||||
|
||||
export function repositoryHasGitHubRemote(repository: Repository) {
|
||||
return !!repository.state.remotes.find(remote => remote.fetchUrl ? getRepositoryFromUrl(remote.fetchUrl) : undefined);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user