Skip to content
This repository was archived by the owner on Nov 14, 2023. It is now read-only.
Closed
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
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,14 @@ Please file an issue: https://github.com/sourcegraph/sourcegraph-jetbrains/issue

## Version History

#### v1.2

- Disable search menu entry when no text is selected.
- Fix handling of local branch
- Move menu entries into sub-menu
- Implement copy link functionality
- Use Project storage API to load config from

#### v1.1.2

- Fixed an error that occurred when trying to search with no selection.
Expand Down
17 changes: 12 additions & 5 deletions resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,25 @@
<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.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.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 modified 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> {

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 has been 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);
}
}
72 changes: 5 additions & 67 deletions src/Open.java
Original file line number Diff line number Diff line change
@@ -1,76 +1,14 @@
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.SelectionModel;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.editor.LogicalPosition;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.application.ApplicationInfo;

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

public class Open extends AnAction {
public class Open extends FileAction {

@Override
public void actionPerformed(AnActionEvent e) {
void handleFileUri(String uri) {
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()+"-/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;
}

// Open the URL in the browser.
try {
Desktop.getDesktop().browse(URI.create(uri));
Expand Down
32 changes: 31 additions & 1 deletion src/Search.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.application.ApplicationInfo;

import javax.annotation.Nullable;
import java.io.*;
import java.awt.Desktop;
import java.net.URI;
Expand Down Expand Up @@ -52,7 +53,7 @@ public void actionPerformed(AnActionEvent e) {
String productName = ApplicationInfo.getInstance().getVersionName();
String productVersion = ApplicationInfo.getInstance().getFullVersion();
try {
uri = Util.sourcegraphURL()+"-/editor"
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")
Expand All @@ -76,4 +77,33 @@ public void actionPerformed(AnActionEvent e) {
}
return;
}

@Override
public void update(AnActionEvent e) {
final Project project = e.getProject();
if (project == null) {
return;
}
String selectedText = getSelectedText(project);
e.getPresentation().setEnabled(selectedText != null && selectedText.length() > 0);
}

@Nullable
private String getSelectedText(Project project) {
Editor editor = FileEditorManager.getInstance(project).getSelectedTextEditor();
if (editor == null) {
return null;
}
Document currentDoc = editor.getDocument();
if (currentDoc == null) {
return null;
}
VirtualFile currentFile = FileDocumentManager.getInstance().getFile(currentDoc);
if (currentFile == null) {
return null;
}
SelectionModel sel = editor.getSelectionModel();

return sel.getSelectedText();
}
}
32 changes: 22 additions & 10 deletions src/Util.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;

import java.io.*;
import java.util.Properties;

public class Util {
public static String VERSION = "v1.1.2";
public static String VERSION = "v1.2";

// gitRemoteURL returns the remote URL for the given remote name.
// e.g. "origin" -> "git@github.com:foo/bar"
Expand Down Expand Up @@ -43,7 +44,22 @@ public static String gitBranch(String repoDir) throws IOException {
return exec("git rev-parse --abbrev-ref HEAD", repoDir).trim();
}

// verify that provided branch exists on remote
public static boolean isRemoteBranch(String branch, String repoDir) throws IOException {
return exec("git show-branch remotes/origin/" + branch, repoDir).length() > 0;
}

public static String sourcegraphURL(Project project) {
String url = Config.getInstance(project).getUrl();
if (url == null || url.length() == 0) {
Properties props = readProps();
url = props.getProperty("url", "https://sourcegraph.com/");
}
return url.endsWith("/") ? url : url + "/";
}

// readProps tries to read the $HOME/sourcegraph-jetbrains.properties file.
@Deprecated
private static Properties readProps() {
Properties props = new Properties();
InputStream input = null;
Expand All @@ -66,15 +82,6 @@ private static Properties readProps() {
return props;
}

public static String sourcegraphURL() {
Properties props = readProps();
String url = props.getProperty("url", "https://sourcegraph.com");
if (!url.endsWith("/")) {
return url + "/";
}
return url;
}

// repoInfo returns the Sourcegraph repository URI, and the file path
// relative to the repository root. If the repository URI cannot be
// determined, a RepoInfo with empty strings is returned.
Expand All @@ -91,6 +98,11 @@ public static RepoInfo repoInfo(String fileName) {
fileRel = fileName.substring(repoRoot.length()+1);
remoteURL = configuredGitRemoteURL(repoRoot);
branch = gitBranch(repoRoot);

// If user is on a local, use "master" instead
if (!isRemoteBranch(branch, repoRoot)) {
branch = "master";
}
} catch (Exception err) {
Logger.getInstance(Util.class).info(err);
err.printStackTrace();
Expand Down