Skip to content

Commit

Permalink
vscode.dev links in share and editor gutter menus (microsoft#176104)
Browse files Browse the repository at this point in the history
  • Loading branch information
joyceerhl authored Mar 4, 2023
1 parent b5ffce1 commit 2b44aa5
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 17 deletions.
31 changes: 31 additions & 0 deletions extensions/github/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
},
"enabledApiProposals": [
"contribShareMenu",
"contribEditorLineNumberMenu",
"contribEditSessions"
],
"contributes": {
Expand All @@ -43,6 +44,10 @@
"command": "github.copyVscodeDevLinkFile",
"title": "Copy vscode.dev Link"
},
{
"command": "github.copyVscodeDevLinkWithoutRange",
"title": "Copy vscode.dev Link"
},
{
"command": "github.openOnVscodeDev",
"title": "Open in vscode.dev",
Expand Down Expand Up @@ -72,6 +77,10 @@
"command": "github.copyVscodeDevLinkFile",
"when": "false"
},
{
"command": "github.copyVscodeDevLinkWithoutRange",
"when": "false"
},
{
"command": "github.openOnVscodeDev",
"when": "false"
Expand All @@ -90,7 +99,29 @@
"when": "github.hasGitHubRepo && resourceScheme != untitled",
"group": "0_vscode@0"
}
],
"explorer/context/share": [
{
"command": "github.copyVscodeDevLinkWithoutRange",
"when": "github.hasGitHubRepo && resourceScheme != untitled",
"group": "0_vscode@0"
}
],
"editor/lineNumber/context": [
{
"command": "github.copyVscodeDevLink",
"when": "github.hasGitHubRepo && resourceScheme != untitled",
"group": "1_cutcopypaste@2"
}
],
"editor/title/context/share": [
{
"command": "github.copyVscodeDevLinkWithoutRange",
"when": "github.hasGitHubRepo && resourceScheme != untitled",
"group": "0_vscode@0"
}
]

},
"configuration": [
{
Expand Down
18 changes: 11 additions & 7 deletions extensions/github/src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ import * as vscode from 'vscode';
import { API as GitAPI } from './typings/git';
import { publishRepository } from './publish';
import { DisposableStore } from './util';
import { getLink } from './links';
import { LinkContext, getLink } from './links';

function getVscodeDevHost(): string {
return `https://${vscode.env.appName.toLowerCase().includes('insiders') ? 'insiders.' : ''}vscode.dev/github`;
}

async function copyVscodeDevLink(gitAPI: GitAPI, useSelection: boolean) {
async function copyVscodeDevLink(gitAPI: GitAPI, useSelection: boolean, context: LinkContext, includeRange = true) {
try {
const permalink = getLink(gitAPI, useSelection, getVscodeDevHost());
const permalink = getLink(gitAPI, useSelection, getVscodeDevHost(), undefined, context, includeRange);
if (permalink) {
return vscode.env.clipboard.writeText(permalink);
}
Expand Down Expand Up @@ -45,12 +45,16 @@ export function registerCommands(gitAPI: GitAPI): vscode.Disposable {
}
}));

disposables.add(vscode.commands.registerCommand('github.copyVscodeDevLink', async () => {
return copyVscodeDevLink(gitAPI, true);
disposables.add(vscode.commands.registerCommand('github.copyVscodeDevLink', async (context: LinkContext) => {
return copyVscodeDevLink(gitAPI, true, context);
}));

disposables.add(vscode.commands.registerCommand('github.copyVscodeDevLinkFile', async () => {
return copyVscodeDevLink(gitAPI, false);
disposables.add(vscode.commands.registerCommand('github.copyVscodeDevLinkFile', async (context: LinkContext) => {
return copyVscodeDevLink(gitAPI, false, context);
}));

disposables.add(vscode.commands.registerCommand('github.copyVscodeDevLinkWithoutRange', async (context: LinkContext) => {
return copyVscodeDevLink(gitAPI, true, context, false);
}));

disposables.add(vscode.commands.registerCommand('github.openOnVscodeDev', async () => {
Expand Down
43 changes: 33 additions & 10 deletions extensions/github/src/links.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,22 +40,45 @@ interface INotebookPosition {
range: vscode.Range | undefined;
}

function getFileAndPosition(): IFilePosition | INotebookPosition | undefined {
let uri: vscode.Uri | undefined;
interface EditorLineNumberContext {
uri: vscode.Uri;
lineNumber: number;
}
export type LinkContext = vscode.Uri | EditorLineNumberContext | undefined;

function extractContext(context: LinkContext): { fileUri: vscode.Uri | undefined; lineNumber: number | undefined } {
if (context instanceof vscode.Uri) {
return { fileUri: context, lineNumber: undefined };
} else if (context !== undefined && 'lineNumber' in context && 'uri' in context) {
return { fileUri: context.uri, lineNumber: context.lineNumber };
} else {
return { fileUri: undefined, lineNumber: undefined };
}
}

function getFileAndPosition(context: LinkContext): IFilePosition | INotebookPosition | undefined {
let range: vscode.Range | undefined;
if (vscode.window.activeTextEditor) {
uri = vscode.window.activeTextEditor.document.uri;

const { fileUri, lineNumber } = extractContext(context);
const uri = fileUri ?? vscode.window.activeTextEditor?.document.uri;

if (uri) {
if (uri.scheme === 'vscode-notebook-cell' && vscode.window.activeNotebookEditor?.notebook.uri.fsPath === uri.fsPath) {
// if the active editor is a notebook editor and the focus is inside any a cell text editor
// generate deep link for text selection for the notebook cell.
const cell = vscode.window.activeNotebookEditor.notebook.getCells().find(cell => cell.document.uri.fragment === uri?.fragment);
const cellIndex = cell?.index ?? vscode.window.activeNotebookEditor.selection.start;
const range = cell !== undefined ? vscode.window.activeTextEditor.selection : undefined;

let range;
if (lineNumber !== undefined) {
range = new vscode.Range(new vscode.Position(lineNumber - 1, 0), new vscode.Position(lineNumber - 1, 1));
} else if (cell !== undefined) {
range = vscode.window.activeTextEditor?.selection;
}
return { type: LinkType.Notebook, uri, cellIndex, range };
} else {
// the active editor is a text editor
range = vscode.window.activeTextEditor.selection;
range = lineNumber !== undefined ? new vscode.Range(lineNumber - 1, 0, lineNumber - 1, 1) : vscode.window.activeTextEditor?.selection;
return { type: LinkType.File, uri, range };
}
}
Expand Down Expand Up @@ -95,9 +118,9 @@ export function notebookCellRangeString(index: number | undefined, range: vscode
return hash;
}

export function getLink(gitAPI: GitAPI, useSelection: boolean, hostPrefix?: string, linkType: 'permalink' | 'headlink' = 'permalink'): string | undefined {
export function getLink(gitAPI: GitAPI, useSelection: boolean, hostPrefix?: string, linkType: 'permalink' | 'headlink' = 'permalink', context?: LinkContext, useRange?: boolean): string | undefined {
hostPrefix = hostPrefix ?? 'https://github.com';
const fileAndPosition = getFileAndPosition();
const fileAndPosition = getFileAndPosition(context);
if (!fileAndPosition) {
return;
}
Expand Down Expand Up @@ -127,8 +150,8 @@ export function getLink(gitAPI: GitAPI, useSelection: boolean, hostPrefix?: stri

const blobSegment = (gitRepo.state.HEAD?.ahead === 0) ? `/blob/${linkType === 'headlink' ? gitRepo.state.HEAD.name : gitRepo.state.HEAD?.commit}` : '';
const fileSegments = fileAndPosition.type === LinkType.File
? (useSelection ? `${uri.path.substring(gitRepo.rootUri.path.length)}${rangeString(fileAndPosition.range)}` : '')
: (useSelection ? `${uri.path.substring(gitRepo.rootUri.path.length)}${notebookCellRangeString(fileAndPosition.cellIndex, fileAndPosition.range)}` : '');
? (useSelection ? `${uri.path.substring(gitRepo.rootUri.path.length)}${useRange ? rangeString(fileAndPosition.range) : ''}` : '')
: (useSelection ? `${uri.path.substring(gitRepo.rootUri.path.length)}${useRange ? notebookCellRangeString(fileAndPosition.cellIndex, fileAndPosition.range) : ''}` : '');

return `${hostPrefix}/${repo.owner}/${repo.repo}${blobSegment
}${fileSegments}`;
Expand Down

0 comments on commit 2b44aa5

Please sign in to comment.