Skip to content

Commit

Permalink
feat: Windows Support & url replacements & multi-platform paths (#10)
Browse files Browse the repository at this point in the history
* Add workaround for Windows Users (useBuiltin)
* Add replacements
* Add support to multi-platform paths
  • Loading branch information
abeatrix authored Oct 26, 2021
1 parent 3597f8b commit 12faf83
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 11 deletions.
90 changes: 84 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,91 @@
# Open in Intellij Sourcegraph extension

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 Intellij.
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 Intellij.

<picture>
<source srcset="https://user-images.githubusercontent.com/37420160/96809054-23450b80-13e8-11eb-8e76-a0556e3b41e6.png" media="(prefers-color-scheme: dark)" />
<source srcset="https://user-images.githubusercontent.com/37420160/96809032-16281c80-13e8-11eb-9b24-3787300ee66f.png" media="(prefers-color-scheme: light)" />
<img src="https://user-images.githubusercontent.com/37420160/96809032-16281c80-13e8-11eb-9b24-3787300ee66f.png" alt="Screenshot" />
<source srcset="https://user-images.githubusercontent.com/37420160/96809054-23450b80-13e8-11eb-8e76-a0556e3b41e6.png" width="100%" media="(prefers-color-scheme: dark)" />
<source srcset="https://user-images.githubusercontent.com/37420160/96809032-16281c80-13e8-11eb-9b24-3787300ee66f.png" width="100%" media="(prefers-color-scheme: light)" />
<img src="https://user-images.githubusercontent.com/37420160/96809032-16281c80-13e8-11eb-9b24-3787300ee66f.png" width="100%" alt="Screenshot" />
</picture>

## Settings
## Configuration

- `openInIntellij.basePath`: The absolute path on your computer where your git repositories live. This extension requires all git repos to be already cloned under this path with their original names. `"/Users/yourusername/src"` is a valid absolute path, while `"~/src"` is not.
**This extension requires all git repos to be cloned and available on your local machine.**

Please add the following options in your Sourcegraph's User Settings to configure the extension:

- `openInIntellij.basePath`: [REQUIRED] String. The absolute path on your computer where your git repositories live. 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 this path with their original names, which the final path can later be altered using the `openInIntellij.replacements` option.
- Note: `"/Users/yourusername/src"` is a valid absolute path, while `"~/src"` is not.

- `openInIntellij.useBuiltin`: [OPTIONAL] Boolean. Set option to `true` in your user settings if you would like to open files using the Intellij's built-in REST API, or if you are using this extension on Windows.

- `openInIntellij.replacements`: [OPTIONAL] Set to an object that includes 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 `"openInIntellij.replacements": {"(?<=Documents\/)(.*[\\\/])": "sourcegraph-$1"}` will add `sourcegraph-` in front of the string that matches the `(?<=Documents\/)(.*[\\\/])` RegExp pattern, while `"openInIntellij.replacements": {"sourcegraph-": ""}` will remove `sourcegraph-` from the final URL.

- `openInIntellij.osPaths`: [OPTIONAL] Takes object. The extension uses the assigned path for the detected Operating System when available. If no platform is detected then we will keep using the basePath provided by `openInIntellij.basePath`.
- Note: Currently support `"windows"`, `"mac"`, and `"linux"` as keys.

## Configuration for Windows users

The `idea://` protocol handler that this extension is using to open files directly from a URL is currently not supported on Windows. As a workaround, Windows user can use the Intellij's built-in REST API to open files directly from a URL with extra configuration steps.

1. In the Intellij's Settings panel, go to `Build, Execution, Deployment`

1. Click on the `Debugger` tab and mark the box next to `Allow unsigned requests` as checked. This allows requests to be made to the built-in server from outside IntelliJ IDEA as stated in their [docs](https://www.jetbrains.com/help/idea/php-built-in-web-server.html#configuring-built-in-web-server)

1. **Intellij must be remained open for this workaround to work.**

## Examples

### Mac

To open repository files in your Documents directory:

```json
{
"extensions": {
"sourcegraph/open-in-intellij": true,
},
"openInIntellij.basePath": "/Users/USERNAME/Documents/"
}
```

### Windows

To open repository files in your user's IdeaProjects directory:

```json
{
"extensions": {
"sourcegraph/open-in-intellij": true,
},
"openInIntellij.basePath": "/C:/Users/USERNAME/IdeaProjects/",
"openInIntellij.useBuiltin": true,
}
```

### Set basePath for multiple platforms

Uses the assigned path for the detected Operating System when available:

```json
{
"extensions": {
"sourcegraph/open-in-intellij": true,
},
"openInIntellij.osPaths": {
// useBuiltin will automatically be set to true for windows
"windows": "/C:/Users/USERNAME/folder/",
"mac": "/Users/USERNAME/folder/",
"linux": "/home/USERNAME/folder/"
},
// set basePath as fallback path when no operating system is detected
"openInIntellij.basePath": "/Users/USERNAME/Documents/"
}
```

## Development

1. Run `yarn && yarn run serve` and keep the Parcel bundler process running
1. [Sideload the extension](https://docs.sourcegraph.com/extensions/authoring/local_development) (at the URL http://localhost:1234 by default) on your Sourcegraph instance or Sourcegraph.com

When you edit a source file in your editor, Parcel will recompile the extension. Reload the Sourcegraph web page to use the updated extension.
15 changes: 15 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,21 @@
"type": "string",
"format": "regex",
"pattern": "^[^~]+"
},
"openInIntellij.useBuiltin": {
"description": "Opens files using the Intellij's built-in REST API. You must enable this option with additional settings (see docs) to use this extension on Windows.",
"type": "boolean"
},
"openInIntellij.replacements": {
"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.",
"type": "object",
"format": "{}",
"examples": ["'(?<=Documents\/)(.*[\\\/])': 'string-to-add-$1'", "'string-to-remove': ''"]
},
"openInIntellij.osPaths": {
"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.",
"type": "object",
"format": "{}"
}
}
}
Expand Down
39 changes: 34 additions & 5 deletions src/open-in-intellij.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,31 @@ import * as path from 'path'

interface Settings {
'openInIntellij.basePath'?: string
'openInIntellij.useBuiltin'?: boolean
'openInIntellij.replacements'?: Record<string, string>
'openInIntellij.osPaths'?: Record<string, string>
}

function getOpenUrl(textDocumentUri: URL): URL {
const basePath = sourcegraph.configuration.get<Settings>().value['openInIntellij.basePath']
let basePath = sourcegraph.configuration.get<Settings>().value['openInIntellij.basePath']
let useBuiltin = sourcegraph.configuration.get<Settings>().value['openInIntellij.useBuiltin']
const osPaths: Record<string, string> = sourcegraph.configuration.get().value['openInIntellij.osPaths'] as Record<string, string>
const replacements = sourcegraph.configuration.get().value['openInIntellij.replacements'] as Record<string, string>
const learnMorePath = new URL('/extensions/sourcegraph/open-in-intellij', sourcegraph.internal.sourcegraphURL.href)
.href
const userSettingsPath = new URL('/user/settings', sourcegraph.internal.sourcegraphURL.href).href

// check platform and use assigned path when available;
if(osPaths){
if (navigator.userAgent.includes('Win') && osPaths.windows) {
basePath = osPaths.windows;
useBuiltin = true;
} else if (navigator.userAgent.includes('Mac') && osPaths.mac) {
basePath = osPaths.mac;
} else if (navigator.userAgent.includes('Linux') && osPaths.linux) {
basePath = osPaths.linux;
}
}
if (typeof basePath !== 'string') {
throw new TypeError(
`Add \`openInIntellij.basePath\` to your [user settings](${userSettingsPath}) to open files in the editor. [Learn more](${learnMorePath})`
Expand All @@ -26,20 +43,32 @@ function getOpenUrl(textDocumentUri: URL): URL {
const repoBaseName = rawRepoName.split('/').pop() ?? ''
const relativePath = decodeURIComponent(textDocumentUri.hash.slice('#'.length))
const absolutePath = path.join(basePath, repoBaseName, relativePath)
const openUrl = new URL('idea://open?file=' + absolutePath)
// Open files with IntelliJ's built-in REST API (port 63342) if useBuiltin is enabled instead of the idea:// protocol handler
// ref: https://www.jetbrains.com/help/idea/php-built-in-web-server.html#configuring-built-in-web-server
let openUrl = !useBuiltin ? 'idea://open?file=' + absolutePath : 'http://localhost:63342/api/file' + absolutePath;

if (sourcegraph.app.activeWindow?.activeViewComponent?.type === 'CodeEditor') {
const selection = sourcegraph.app.activeWindow?.activeViewComponent?.selection
if (selection) {
openUrl.searchParams.set('line', (selection.start.line + 1).toString())
openUrl += `:${selection.start.line + 1}`

if (selection && selection.start.character !== 0) {
openUrl.searchParams.set('column', (selection.start.character + 1).toString())
openUrl += `:${selection.start.character + 1}`
}
}
}

// Run replacements if available
if(replacements) {
for (const replacement in replacements) {
if (typeof replacement === 'string') {
const POST_REGEX = new RegExp(replacement);
openUrl = openUrl.replace(POST_REGEX, replacements[replacement])
}
}
}

return openUrl
return new URL(openUrl)
}

export function activate(context: sourcegraph.ExtensionContext): void {
Expand Down

0 comments on commit 12faf83

Please sign in to comment.