Skip to content

Commit 8244823

Browse files
authored
feat: url replacements & remote host & per-platform paths support (#25)
* Add replacements feature * Add remote host support * Add support for per-platform path
1 parent 5f4092b commit 8244823

File tree

3 files changed

+155
-18
lines changed

3 files changed

+155
-18
lines changed

README.md

Lines changed: 83 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,49 @@
11
# VS Code Sourcegraph extension
22

3-
Adds a button at the top of files in both Sourcegraph app and code hosts like GitHub (when the Sourcegraph browser extension is installed) that will open the current file in VS Code.
3+
Adds a button to the Sourcegraph's extension panel and at the top of files in code hosts like GitHub (when the Sourcegraph browser extension is installed) that will open the current file in VS Code.
4+
5+
**This extension requires all git repos to be cloned and available on your local machine.**
46

57
![image](https://user-images.githubusercontent.com/10532611/79975469-550e0180-849b-11ea-83cb-54e9e25225d6.png)
68

79
## Configuration
810

9-
- Set `vscode.open.basePath` in your user settings to a local folder that contains your Git repositories.
10-
The extension will try to open the file in a clone named by the last segment of the repository name in that folder.
11+
Please add the following options in your Sourcegraph's User Settings to configure the extension:
12+
13+
- `vscode.open.basePath`: [REQUIRED] String. The absolute path on your local machine that contains your Git repositories.
14+
The extension will try to open the file in a clone named by the last segment of the repository name in that folder. This extension requires all git repos to be already cloned under the provided path with their original names, which can then be altered using the `vscode.open.replacements` option.
15+
16+
- `vscode.open.uncPath`: [OPTIONAL] Boolean. Set option to `true` in your user settings to enable support for UNC (Universal Naming Convention) paths.
1117

12-
- Set `vscode.open.uncPath` to true in your user settings to enable support for UNC (Universal Naming Convention) paths.
18+
- `vscode.open.useMode`: [OPTIONAL] String. Specifies the mode you would like to use with VS Code. Currently support opening VS Code in the following modes:
19+
- `"insiders"`: Open files in VS Code Insiders instead of regular VS Code.
20+
- `"ssh"`: Open files from a remote server via ssh. This requires `vscode.open.remoteHost` configured in your User Setting and VS Code extension [Remote Development by Microsoft](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack) installed in your VS Code to work.
1321

14-
- Set `vscode.open.insidersMode` to true in your user settings to open files in VS Code Insiders instead of regular VS Code.
22+
- `vscode.open.replacements`: [OPTIONAL] Object. Take object with pairs of strings, where each key will be replaced by its value in the final url. The key can be a string or a RegExp, and the value must be a string. For example, using `"vscode.open.replacements": {"sourcegraph-": ""}` will remove `sourcegraph-` from the final URL.
23+
24+
- `vscode.open.remoteHost`: [OPTIONAL] String. Set option to your desired `USER@HOSTNAME` to work with remote repositories. This requires VS Code extension [Remote Development by Microsoft](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack) with `"vscode.open.useMode": "ssh"` configured in your Sourcegraph's User Setting to work.
25+
26+
- `vscode.open.osPaths`: [OPTIONAL] Object. We will use the assigned path for the detected Operating System when available. If no platform is detected then we will keep using the path provided with `vscode.open.basePath`. Currently support `"windows"`, `"mac"`, and `"linux"` as keys.
1527

1628
## Examples
1729

30+
### Configured base paths for different platforms
31+
32+
```json
33+
{
34+
"extensions": {
35+
"sourcegraph/open-in-vscode": true
36+
},
37+
"vscode.open.osPaths": {
38+
"windows": "/C:/Users/USERNAME/folder/",
39+
"mac": "/Users/USERNAME/folder/",
40+
"linux": "/home/USERNAME/folder/"
41+
},
42+
// set basePath as fallback path when no operating system is detected
43+
"vscode.open.basePath": "/Users/USERNAME/Documents/",
44+
}
45+
```
46+
1847
### Mac
1948

2049
To open repository files in your Documents directory:
@@ -66,6 +95,55 @@ To open repository files in your Home directory:
6695
}
6796
```
6897

98+
### Replacements
99+
100+
Adds `sourcegraph-` in front of the string that matches the `(?<=Documents\/)(.*[\\\/])` RegExp pattern, which is the string after `Documents/` and before the final slash. This turns the final url from `vscode://file//Users/USERNAME/Documents/REPO-NAME/package.json` to `vscode://file//Users/USERNAME/Documents/sourcegraph-REPO-NAME/package.json`
101+
102+
```json
103+
{
104+
"extensions": {
105+
"sourcegraph/open-in-vscode": true
106+
},
107+
"vscode.open.basePath": "/Users/USERNAME/Documents/",
108+
"vscode.open.replacements": {"(?<=Documents\/)(.*[\\\/])": "sourcegraph-$1"},
109+
}
110+
```
111+
112+
### Remote SSH Server
113+
114+
**This requires VS Code extension [Remote Development by Microsoft](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack) to work.**
115+
116+
To open repository files reside in a remote server:
117+
118+
```json
119+
{
120+
"extensions": {
121+
"sourcegraph/open-in-vscode": true
122+
},
123+
// File path for where the repositories reside in the remote server
124+
"vscode.open.basePath": "/Users/USERNAME/Documents/",
125+
// Specifies extension to run VS Code with a SSH server
126+
"vscode.open.useMode": "ssh",
127+
// Replaces USER and HOSTNAME as appropriate
128+
"vscode.open.remoteHost": "USER@HOSTNAME",
129+
}
130+
```
131+
132+
### Open folders instead of files
133+
134+
To open directory where the repository files reside:
135+
136+
```json
137+
{
138+
"extensions": {
139+
"sourcegraph/open-in-vscode": true
140+
},
141+
"vscode.open.basePath": "/Users/USERNAME/Documents/",
142+
// Use RegExp to remove file names
143+
"vscode.open.replacements": {"\/[^\/]*$": ""},
144+
}
145+
```
146+
69147
## Development
70148

71149
1. Run `yarn && yarn run serve` and keep the Parcel bundler process running.

package.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,23 @@
5555
"vscode.open.uncPath": {
5656
"description": "Set true to enable support for Universal naming convention (UNC) paths, which use double slashes or backslashes before the host device name (as used in Windows or WSL).",
5757
"type": "boolean"
58+
},
59+
"vscode.open.useMode": {
60+
"description": "Open VS Code in one of the following modes: 'insiders', 'ssh'.",
61+
"type": "string",
62+
"enum": ["insiders", "ssh"]
63+
},
64+
"vscode.open.osPaths": {
65+
"description": "The file path on each platform to the folder that is expected to contain all repositories. Currently supports 'windows', 'mac', and 'linux' as keys.",
66+
"type": "object"
67+
},
68+
"vscode.open.replacements": {
69+
"description": "Take key-value pairs where each key is replaced by its value in the final url. The key can be a string or a RegExp pattern, and the value must be a string. The final path must be a valid path on the machine to the folder that is expected to contain all repositories.",
70+
"type": "object"
71+
},
72+
"vscode.open.remoteHost": {
73+
"description": "Set option to your desired `USER@HOSTNAME` to work with remote repositories when using the 'ssh' mode.",
74+
"type": "string"
5875
}
5976
}
6077
}

src/open-in-vscode.ts

Lines changed: 55 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,40 +5,82 @@ function getOpenUrl(textDocumentUri: URL): URL {
55
const rawRepoName = decodeURIComponent(textDocumentUri.hostname + textDocumentUri.pathname)
66
// TODO support different folder layouts, e.g. repo nested under owner name
77
const repoBaseName = rawRepoName.split('/').pop()!
8-
const basePath: unknown = sourcegraph.configuration.get().value['vscode.open.basePath']
8+
let basePath: string = sourcegraph.configuration.get().value['vscode.open.basePath']
9+
const osPaths: Record<string, string> = sourcegraph.configuration.get().value['vscode.open.osPaths']
910
const isUNC: boolean = sourcegraph.configuration.get().value['vscode.open.uncPath']
10-
const insidersMode: boolean = sourcegraph.configuration.get().value['vscode.open.insidersMode']
11+
const useMode: string = sourcegraph.configuration.get().value['vscode.open.useMode']
12+
const replacements: Record<string, string> = sourcegraph.configuration.get().value['vscode.open.replacements']
13+
const remoteHost: string = sourcegraph.configuration.get().value['vscode.open.remoteHost']
14+
15+
// check platform and use assigned path if osPaths is configured;
16+
if(osPaths){
17+
if (navigator.userAgent.includes('Win') && osPaths.windows) {
18+
basePath = osPaths.windows;
19+
} else if (navigator.userAgent.includes('Mac') && osPaths.mac) {
20+
basePath = osPaths.mac;
21+
} else if (navigator.userAgent.includes('Linux') && osPaths.linux) {
22+
basePath = osPaths.linux;
23+
}
24+
}
25+
1126
if (typeof basePath !== 'string') {
1227
throw new Error(
13-
`Setting \`vscode.open.basePath\` must be set in your [user settings](${new URL('/user/settings', sourcegraph.internal.sourcegraphURL.href).href}) to open files in VS Code.`
28+
`Setting \`vscode.open.basePath\` must be included in your [user settings](${new URL('/user/settings', sourcegraph.internal.sourcegraphURL.href).href}) to open files in VS Code.`
1429
)
1530
}
1631
if (!path.isAbsolute(basePath)) {
1732
throw new Error(
18-
`\`vscode.open.basePath\` value \`${basePath}\` is not an absolute path. Please correct the error in your [user settings](${new URL('/user/settings', sourcegraph.internal.sourcegraphURL.href).href}).`
33+
`\`${basePath}\` is not an absolute path. Please correct the error in your [user settings](${new URL('/user/settings', sourcegraph.internal.sourcegraphURL.href).href}).`
1934
)
2035
}
2136
const relativePath = decodeURIComponent(textDocumentUri.hash.slice('#'.length))
2237
const absolutePath = path.join(basePath, repoBaseName, relativePath)
23-
2438
// if windows or enabled UNC path, add an extra slash in the beginning
2539
const uncPath = /^[a-zA-Z]:\\/.test(basePath) || isUNC ? '/' : '';
26-
// check if vscode-insiders mode is enabled
27-
const mode = insidersMode ? 'vscode-insiders' : 'vscode';
28-
// construct uri
29-
const uri = mode + '://file' + uncPath + absolutePath;
3040

31-
const openUrl = new URL(uri)
41+
// check for configured mode then construct uri. uses 'vscode://' by default.
42+
let uri = '';
43+
switch(useMode) {
44+
case 'insiders':
45+
uri = 'vscode-insiders://file' + uncPath + absolutePath;
46+
break;
47+
case 'ssh':
48+
if(!remoteHost){
49+
throw new Error(
50+
`Setting \`vscode.open.remoteHost\` must be included in your [user settings](${new URL('/user/settings', sourcegraph.internal.sourcegraphURL.href).href}) to run VS Code in ssh mode.`
51+
)
52+
}
53+
uri = 'vscode://vscode-remote/ssh-remote+' + remoteHost + uncPath + absolutePath;
54+
break;
55+
default:
56+
uri = 'vscode://file' + uncPath + absolutePath;
57+
}
58+
3259
if (sourcegraph.app.activeWindow?.activeViewComponent?.type === 'CodeEditor') {
3360
const selection = sourcegraph.app.activeWindow?.activeViewComponent?.selection
3461
if (selection) {
35-
openUrl.pathname += `:${selection.start.line + 1}`
62+
uri += `:${selection.start.line + 1}`
3663
if (selection.start.character !== 0) {
37-
openUrl.pathname += `:${selection.start.character + 1}`
64+
uri += `:${selection.start.character + 1}`
65+
}
66+
} else if(remoteHost) {
67+
// :line is required for the vscode protocol to identify files and folders
68+
// if no line is selected, we will always open files with line 1 selected
69+
uri += ':1';
70+
}
71+
}
72+
73+
// Run replacements if available
74+
if(replacements) {
75+
for (const replacement in replacements) {
76+
if (typeof replacement === 'string') {
77+
const POST_REGEX = new RegExp(replacement);
78+
uri = uri.replace(POST_REGEX, replacements[replacement])
3879
}
3980
}
4081
}
41-
return openUrl
82+
83+
return new URL(uri)
4284
}
4385

4486
export function activate(ctx: sourcegraph.ExtensionContext): void {

0 commit comments

Comments
 (0)