Skip to content
This repository was archived by the owner on Nov 14, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839

*.jar

# User-specific stuff:
.idea/**/workspace.xml
.idea/**/tasks.xml
Expand Down
2 changes: 1 addition & 1 deletion .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

56 changes: 33 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# Sourcegraph for JetBrains IDEs [![JetBrains Plugin](https://img.shields.io/badge/JetBrains-Sourcegraph-green.svg)](https://plugins.jetbrains.com/plugin/9682-sourcegraph)

The Sourcegraph plugin for JetBrains IDEs enables you to quickly open and search code on Sourcegraph easily and efficiently in JetBrains IDEs such as IntelliJ. This plugin works with most JetBrains IDEs:
- Search snippets of code on Sourcegraph.
- Copy and share a link to code on Sourcegraph.
- Quickly go from files in your editor to Sourcegraph.

The plugin works with all JetBrains IDEs including:

- IntelliJ IDEA
- IntelliJ IDEA Community Edition
Expand All @@ -16,49 +20,45 @@ The Sourcegraph plugin for JetBrains IDEs enables you to quickly open and search
- Rider
- Android Studio


## Installation

- Select `IntelliJ IDEA` then `Preferences` (or use <kbd>⌘,</kbd>)
- Click `Plugins` in the left-hand pane.
- Choose `Browse repositories...`
- Search for `Sourcegraph` -> `Install`
- Restart your IDE if needed, then select some code and choose `Sourcegraph` in the right-click context menu to see actions and keyboard shortcuts.

## Configuring for use with a private Sourcegraph instance

## Usage

Right click any code or selection and choose `Sourcegraph: Open` or `Sourcegraph: Search`.

Keyboard Shortcuts:
The plugin is configurable _globally_ by creating a `sourcegraph-jetbrains.properties` in your home directory. For example, modify the following URL to match your on-premises Sourcegraph instance URL:

| Description | Mac | Linux / Windows |
|---------------------------------|---------------------|------------------|
| Open file in Sourcegraph | <kbd>Option+A</kbd> | <kbd>Alt+A</kbd> |
| Search selection in Sourcegraph | <kbd>Option+S</kbd> | <kbd>Alt+S</kbd> |


## Settings
```
url = https://sourcegraph.example.com
```

The plugin is configurable by creating a `sourcegraph-jetbrains.properties` in your home directory. For example, modify the following URL to match your on-premises Sourcegraph instance URL:
You may also choose to configure it _per repository_ using a `.idea/sourcegraph.xml` file in your repository like so:

```
url = https://sourcegraph.com
```xml
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Config">
<option name="url" value="https://sourcegraph.example.com" />
</component>
</project>
```

By default, the plugin will use the `origin` git remote to determine which repository on Sourcegraph corresponds to the local repository. You may configure this by adding a `sourcegraph` remote which will take priority.
By default, the plugin will use the `origin` git remote to determine which repository on Sourcegraph corresponds to your local repository. If your `origin` remote doesn't match Sourcegraph, you may instead configure a `sourcegraph` Git remote which will take priority.

## Questions & Feedback

Please file an issue: https://github.com/sourcegraph/sourcegraph-jetbrains/issues/new


## Uninstallation

- Select `IntelliJ IDEA` then `Preferences` (or use <kbd>⌘,</kbd>)
- Click `Plugins` in the left-hand pane.
- Search for `Sourcegraph` -> Right click -> `Uninstall` (or uncheck to disable)


## Development

- Start IntelliJ and choose `Check out from Version Control` -> `Git` -> `https://github.com/sourcegraph/sourcegraph-jetbrains`
Expand All @@ -67,13 +67,23 @@ Please file an issue: https://github.com/sourcegraph/sourcegraph-jetbrains/issue
1. Update `plugin.xml` (change version AND describe changes in change notes).
2. Update `Util.java` (change `VERSION` constant).
3. Update `README.md` (copy changelog from plugin.xml).
5. choose `Build` -> `Prepare Plugin Module 'sourcegraph' For Deployment`
6. `git commit -m "all: release v<THE VERSION>"` and `git push` and `git tag v<THE VERSION>` and `git push --tags`
4. choose `Build` -> `Prepare Plugin Module 'sourcegraph' For Deployment`
5. `git commit -m "all: release v<THE VERSION>"` and `git push` and `git tag v<THE VERSION>` and `git push --tags`
6. Upload the jar to the releases tab of this repository.
7. Publish according to http://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/publishing_plugin.html (note: it takes ~2 business days for JetBrains support team to review the plugin).


## Version History

#### v1.2.0

- The search menu entry is now no longer present when no text has been selected.
- When on a branch that does not exist remotely, `master` will now be used instead.
- Menu entries (Open file, etc.) are now under a Sourcegraph sub-menu.
- Added a "Copy link to file" action (alt+c / opt+c).
- Added a "Search in repository" action (alt+r / opt+r).
- It is now possible to configure the plugin per-repository using a `.idea/sourcegraph.xml` file. See the README for details.
- Special thanks: @oliviernotteghem for contributing the new features in this release!

#### v1.1.2

- Fixed an error that occurred when trying to search with no selection.
Expand Down
43 changes: 34 additions & 9 deletions resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
@@ -1,20 +1,34 @@
<idea-plugin>
<id>com.sourcegraph.jetbrains</id>
<name>Sourcegraph</name>
<version>1.1.2</version>
<version>1.2.0</version>
<vendor email="hi@sourcegraph.com" url="https://sourcegraph.com">Sourcegraph</vendor>

<description><![CDATA[
Sourcegraph for JetBrains IDEs (IntelliJ, PyCharm, GoLand, etc.)<br>
<ul>
<li>Search snippets of code on Sourcegraph.</li>
<li>Copy and share a link to code on Sourcegraph.</li>
<li>Quickly go from files in your editor to Sourcegraph.</li>
</ul>
]]></description>

<change-notes><![CDATA[
<ul>
<li>v1.1.2 - Minor bug fixes around searching.
<ul>
<li>Fixed an error that occurred when trying to search with no selection.</li>
<li>v1.2.0 - Copy link to file, search in repository, per-repository configuration, bug fixes & more
<ul>
<li>The search menu entry is now no longer present when no text has been selected.</li>
<li>When on a branch that does not exist remotely, `master` will now be used instead.</li>
<li>Menu entries (Open file, etc.) are now under a Sourcegraph sub-menu.</li>
<li>Added a "Copy link to file" action (alt+c / opt+c).</li>
<li>Added a "Search in repository" action (alt+r / opt+r).</li>
<li>It is now possible to configure the plugin per-repository using a `.idea/sourcegraph.xml` file. See the README for details.</li>
<li>Special thanks: @oliviernotteghem for contributing the new features in this release!</li>
</ul>
</li>
<li>v1.1.2 - Minor bug fixes around searching.
<ul>
<li>Fixed an error that occurred when trying to search with no selection.</li>
<li>The git remote used for repository detection is now `sourcegraph` and then `origin`, instead of the previously poor choice of just the first git remote.</li>
</ul>
</li>
Expand Down Expand Up @@ -45,18 +59,29 @@
<depends>com.intellij.modules.lang</depends>

<extensions defaultExtensionNs="com.intellij">
<!-- Add your extensions here -->
<projectService serviceInterface="Config" serviceImplementation="Config"/>
</extensions>

<actions>
<action id="sourcegraph.open" class="Open" text="Sourcegraph: Open" description="Open selection in Sourcegraph">
<add-to-group group-id="EditorPopupMenu" anchor="last"/>
<action id="sourcegraph.open" class="Open" text="Open file" description="Open selection in Sourcegraph">
<keyboard-shortcut first-keystroke="alt A" keymap="$default"/>
</action>
<action id="sourcegraph.search" class="Search" text="Sourcegraph: Search" description="Search selection on Sourcegraph">
<add-to-group group-id="EditorPopupMenu" anchor="last"/>
<action id="sourcegraph.search" class="Search" text="Search selection" description="Search selection on Sourcegraph">
<keyboard-shortcut first-keystroke="alt s" keymap="$default"/>
</action>
<action id="sourcegraph.searchRepository" class="SearchRepository" text="Search in repository" description="Search selection in repository on Sourcegraph">
<keyboard-shortcut first-keystroke="alt r" keymap="$default"/>
</action>
<action id="sourcegraph.copy" class="Copy" text="Copy link to file" description="Copy link to Sourcegraph">
<keyboard-shortcut first-keystroke="alt c" keymap="$default"/>
</action>
<group id="SourcegraphEditor" icon="/icons/icon.png" popup="true" text="Sourcegraph">
<reference ref="sourcegraph.search"/>
<reference ref="sourcegraph.searchRepository"/>
<reference ref="sourcegraph.open"/>
<reference ref="sourcegraph.copy"/>
<add-to-group anchor="last" group-id="EditorPopupMenu"/>
</group>
</actions>

</idea-plugin>
Binary file added resources/icons/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added resources/icons/icon@2x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed sourcegraph.jar
Binary file not shown.
34 changes: 34 additions & 0 deletions src/Config.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import com.intellij.openapi.components.PersistentStateComponent;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.components.State;
import com.intellij.openapi.components.Storage;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

@State(
name = "Config",
storages = {@Storage("sourcegraph.xml")})
class Config implements PersistentStateComponent<Config> {

public String url;

public String getUrl() {
return url;
}

@Nullable
@Override
public Config getState() {
return this;
}

@Override
public void loadState(@NotNull Config config) {
this.url = config.url;
}

@Nullable static Config getInstance(Project project) {
return ServiceManager.getService(project, Config.class);
}
}
20 changes: 20 additions & 0 deletions src/Copy.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications;
import com.intellij.openapi.ide.CopyPasteManager;

import java.awt.datatransfer.StringSelection;

public class Copy extends FileAction {

@Override
void handleFileUri(String uri) {
// Copy file uri to clipboard
CopyPasteManager.getInstance().setContents(new StringSelection(uri));

// Display bubble
Notification notification = new Notification("Sourcegraph", "Sourcegraph",
"File URL copied to clipboard.", NotificationType.INFORMATION);
Notifications.Bus.notify(notification);
}
}
80 changes: 80 additions & 0 deletions src/FileAction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.application.ApplicationInfo;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.LogicalPosition;
import com.intellij.openapi.editor.SelectionModel;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;

import java.awt.*;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLEncoder;

public abstract class FileAction extends AnAction {

abstract void handleFileUri(String uri);

@Override
public void actionPerformed(AnActionEvent e) {
Logger logger = Logger.getInstance(this.getClass());

// Get project, editor, document, file, and position information.
final Project project = e.getProject();
if (project == null) {
return;
}
Editor editor = FileEditorManager.getInstance(project).getSelectedTextEditor();
if (editor == null) {
return;
}
Document currentDoc = editor.getDocument();
if (currentDoc == null) {
return;
}
VirtualFile currentFile = FileDocumentManager.getInstance().getFile(currentDoc);
if (currentFile == null) {
return;
}
SelectionModel sel = editor.getSelectionModel();

// Get repo information.
RepoInfo repoInfo = Util.repoInfo(currentFile.getPath());
if (repoInfo.remoteURL == "") {
return;
}

// Build the URL that we will open.
String productName = ApplicationInfo.getInstance().getVersionName();
String productVersion = ApplicationInfo.getInstance().getFullVersion();
String uri;
try {
LogicalPosition start = editor.visualToLogicalPosition(sel.getSelectionStartPosition());
LogicalPosition end = editor.visualToLogicalPosition(sel.getSelectionEndPosition());
uri = Util.sourcegraphURL(project)+"-/editor"
+ "?remote_url=" + URLEncoder.encode(repoInfo.remoteURL, "UTF-8")
+ "&branch=" + URLEncoder.encode(repoInfo.branch, "UTF-8")
+ "&file=" + URLEncoder.encode(repoInfo.fileRel, "UTF-8")
+ "&editor=" + URLEncoder.encode("JetBrains", "UTF-8")
+ "&version=" + URLEncoder.encode(Util.VERSION, "UTF-8")
+ "&utm_product_name=" + URLEncoder.encode(productName, "UTF-8")
+ "&utm_product_version=" + URLEncoder.encode(productVersion, "UTF-8")
+ "&start_row=" + URLEncoder.encode(Integer.toString(start.line), "UTF-8")
+ "&start_col=" + URLEncoder.encode(Integer.toString(start.column), "UTF-8")
+ "&end_row=" + URLEncoder.encode(Integer.toString(end.line), "UTF-8")
+ "&end_col=" + URLEncoder.encode(Integer.toString(end.column), "UTF-8");
} catch (UnsupportedEncodingException err) {
logger.debug("failed to build URL");
err.printStackTrace();
return;
}

handleFileUri(uri);
}
}
Loading