diff --git a/package.json b/package.json
index f8100b67..5552a1e2 100644
--- a/package.json
+++ b/package.json
@@ -18,6 +18,7 @@
],
"activationEvents": [
"onCommand:extension.open",
+ "onCommand:extension.copyUrl",
"onCommand:extension.search.selection",
"onCommand:extension.search"
],
@@ -28,6 +29,10 @@
"command": "extension.open",
"title": "Sourcegraph: Open"
},
+ {
+ "command": "extension.copyUrl",
+ "title": "Sourcegraph: Copy Url"
+ },
{
"command": "extension.search.selection",
"title": "Sourcegraph: Search Selection"
@@ -74,6 +79,13 @@
"default": {},
"description": "For each item in this object, replace key with value in the remote url."
},
+ "sourcegraph.remoteRegexUrlReplacements": {
+ "type": [
+ "object"
+ ],
+ "default": {},
+ "description": "For each item in this object, replace RegEx key with value in the remote url."
+ },
"sourcegraph.defaultBranch": {
"type": [
"string"
diff --git a/src/extension.ts b/src/extension.ts
index 7d27cd35..3f42a5f8 100644
--- a/src/extension.ts
+++ b/src/extension.ts
@@ -1,7 +1,7 @@
import open from 'open'
import * as vscode from 'vscode'
import { getSourcegraphUrl } from './config'
-import { repoInfo } from './git'
+import { repoInfo, RepositoryInfo } from './git'
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
const { version } = require('../package.json')
@@ -23,6 +23,23 @@ const handleCommandErrors =
(command: (...args: P) => Pr
}
}
+/**
+ * Returns the Sourcegraph URL for a cursor selection.
+ */
+const getSelectionSourcegraphUrl = (editor: vscode.TextEditor, repositoryInfo: RepositoryInfo): string => {
+ const { remoteURL, branch, fileRelative } = repositoryInfo
+ return `${getSourcegraphUrl()}/-/editor` +
+ `?remote_url=${encodeURIComponent(remoteURL)}` +
+ `&branch=${encodeURIComponent(branch)}` +
+ `&file=${encodeURIComponent(fileRelative)}` +
+ `&editor=${encodeURIComponent('VSCode')}` +
+ `&version=${encodeURIComponent(version)}` +
+ `&start_row=${encodeURIComponent(String(editor.selection.start.line))}` +
+ `&start_col=${encodeURIComponent(String(editor.selection.start.character))}` +
+ `&end_row=${encodeURIComponent(String(editor.selection.end.line))}` +
+ `&end_col=${encodeURIComponent(String(editor.selection.end.character))}`
+}
+
/**
* The command implementation for opening a cursor selection on Sourcegraph.
*/
@@ -35,21 +52,24 @@ async function openCommand(): Promise {
if (!repositoryInfo) {
return
}
- const { remoteURL, branch, fileRelative } = repositoryInfo
-
// Open in browser.
- await open(
- `${getSourcegraphUrl()}/-/editor` +
- `?remote_url=${encodeURIComponent(remoteURL)}` +
- `&branch=${encodeURIComponent(branch)}` +
- `&file=${encodeURIComponent(fileRelative)}` +
- `&editor=${encodeURIComponent('VSCode')}` +
- `&version=${encodeURIComponent(version)}` +
- `&start_row=${encodeURIComponent(String(editor.selection.start.line))}` +
- `&start_col=${encodeURIComponent(String(editor.selection.start.character))}` +
- `&end_row=${encodeURIComponent(String(editor.selection.end.line))}` +
- `&end_col=${encodeURIComponent(String(editor.selection.end.character))}`
- )
+ await open(getSelectionSourcegraphUrl(editor, repositoryInfo))
+}
+
+/**
+ * The command implementation for copying the Sourcegraph URL of a cursor selection.
+ */
+async function copyUrlCommand(): Promise {
+ const editor = vscode.window.activeTextEditor
+ if (!editor) {
+ throw new Error('No active editor')
+ }
+ const repositoryInfo = await repoInfo(editor.document.uri.fsPath)
+ if (!repositoryInfo) {
+ return
+ }
+ // Copy to clipboard.
+ await vscode.env.clipboard.writeText(getSelectionSourcegraphUrl(editor, repositoryInfo))
}
/**
@@ -74,12 +94,12 @@ async function searchSelectionCommand(): Promise {
// Search in browser.
await open(
`${getSourcegraphUrl()}/-/editor` +
- `?remote_url=${encodeURIComponent(remoteURL)}` +
- `&branch=${encodeURIComponent(branch)}` +
- `&file=${encodeURIComponent(fileRelative)}` +
- `&editor=${encodeURIComponent('VSCode')}` +
- `&version=${encodeURIComponent(version)}` +
- `&search=${encodeURIComponent(query)}`
+ `?remote_url=${encodeURIComponent(remoteURL)}` +
+ `&branch=${encodeURIComponent(branch)}` +
+ `&file=${encodeURIComponent(fileRelative)}` +
+ `&editor=${encodeURIComponent('VSCode')}` +
+ `&version=${encodeURIComponent(version)}` +
+ `&search=${encodeURIComponent(query)}`
)
}
@@ -101,11 +121,18 @@ async function searchCommand(): Promise {
*/
export function activate(context: vscode.ExtensionContext): void {
// Register our extension commands (see package.json).
- context.subscriptions.push(vscode.commands.registerCommand('extension.open', handleCommandErrors(openCommand)))
- context.subscriptions.push(
- vscode.commands.registerCommand('extension.search.selection', handleCommandErrors(searchSelectionCommand))
- )
- context.subscriptions.push(vscode.commands.registerCommand('extension.search', handleCommandErrors(searchCommand)))
+ context.subscriptions.push(vscode.commands.registerCommand(
+ 'extension.open',
+ handleCommandErrors(openCommand)))
+ context.subscriptions.push(vscode.commands.registerCommand(
+ 'extension.copyUrl',
+ handleCommandErrors(copyUrlCommand)))
+ context.subscriptions.push(vscode.commands.registerCommand(
+ 'extension.search.selection',
+ handleCommandErrors(searchSelectionCommand)))
+ context.subscriptions.push(vscode.commands.registerCommand(
+ 'extension.search',
+ handleCommandErrors(searchCommand)))
}
export function deactivate(): void {
diff --git a/src/git/index.ts b/src/git/index.ts
index 862518e4..b055995f 100644
--- a/src/git/index.ts
+++ b/src/git/index.ts
@@ -5,7 +5,7 @@ import { gitHelpers } from './helpers'
import { Branch, gitRemoteNameAndBranch } from './remoteNameAndBranch'
import { gitRemoteUrlWithReplacements } from './remoteUrl'
-interface RepositoryInfo extends Branch {
+export interface RepositoryInfo extends Branch {
/** Git repository remote URL */
remoteURL: string