Skip to content

Commit

Permalink
support right click annotation
Browse files Browse the repository at this point in the history
  • Loading branch information
shiraji committed Mar 23, 2024
1 parent 22e1821 commit 682f2af
Show file tree
Hide file tree
Showing 9 changed files with 121 additions and 50 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@
.idea/modules.xml
*.iml

# GitHub copilot
.idea/copilot/

# CMake
cmake-build-*/

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ import git4idea.repo.GitRepository
import java.util.Locale
import javax.swing.Icon

abstract class BaseFindPullRequestAction : AnAction() {
abstract class BaseFindPullRequestAction(private val prNumber: Int?) : AnAction() {

abstract fun actionPerform(e: AnActionEvent, url: String)

abstract fun menuText(project: Project, useShortName: Boolean): String?
abstract fun menuText(project: Project, useShortName: Boolean, prNumber: Int?): String?

private fun menuIcon(project: Project): Icon? {
val config = PropertiesComponent.getInstance(project) ?: return null
Expand Down Expand Up @@ -59,29 +59,36 @@ abstract class BaseFindPullRequestAction : AnAction() {

object : Task.Backgroundable(project, "Finding Pull Request...") {
override fun run(indicator: ProgressIndicator) {
val revisionHash = try {
gitHistoryService.findRevisionHash(project, repository, virtualFile, lineNumber)
} catch (e: VcsException) {
showErrorNotification("Could not find revision hash")
return
}

val webRepoUrl = model.createWebRepoUrl(repository)
if (webRepoUrl == null) {
showErrorNotification("Could not find GitHub repository url")
return
}

val hostingServices = FindPullRequestHostingServices.findBy(config.getHosting())
try {
val url = "$webRepoUrl/${model.createPullRequestPath(repository, revisionHash)}"

if (prNumber == null) {
val revisionHash = try {
gitHistoryService.findRevisionHash(project, repository, virtualFile, lineNumber)
} catch (e: VcsException) {
showErrorNotification("Could not find revision hash")
return
}

try {
val url = "$webRepoUrl/${model.createPullRequestPath(repository, revisionHash)}"
actionPerform(e, url)
} catch (ex: VcsException) {
val name =
FindPullRequestHostingServices.findBy(config.getHosting()).pullRequestName.lowercase(Locale.getDefault())
showErrorNotification("Could not find the $name for $revisionHash : ${ex.message}")
} catch (ex: NoPullRequestFoundException) {
val url = model.createCommitUrl(repository, hostingServices, webRepoUrl, revisionHash)
actionPerformForNoPullRequestFount(e, ex, url = url)
}
} else {
val url = "$webRepoUrl/${model.createPullRequestPath(repository, prNumber, hostingServices)}"
actionPerform(e, url)
} catch (ex: VcsException) {
val name = FindPullRequestHostingServices.findBy(config.getHosting()).pullRequestName.lowercase(Locale.getDefault())
showErrorNotification("Could not find the $name for $revisionHash : ${ex.message}")
} catch (ex: NoPullRequestFoundException) {
val url = model.createCommitUrl(repository, hostingServices, webRepoUrl, revisionHash)
actionPerformForNoPullRequestFount(e, ex, url = url)
}
}
}.queue()
Expand All @@ -96,7 +103,7 @@ abstract class BaseFindPullRequestAction : AnAction() {
val virtualFile: VirtualFile = e.getData(CommonDataKeys.VIRTUAL_FILE) ?: return
val repository = getGitRepository(project, virtualFile) ?: return
val useShortName = ActionPlaces.EDITOR_POPUP == e.place
val text = menuText(project, useShortName) ?: return
val text = menuText(project, useShortName, prNumber) ?: return
val icon = menuIcon(project)
val description = description(project, editor, virtualFile)
val gitRepositoryService = GitConfService()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import com.intellij.notification.Notification
import com.intellij.notification.NotificationListener
import com.intellij.notification.NotificationType
import com.intellij.notification.Notifications
import com.intellij.openapi.actionSystem.ActionUpdateThread
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.editor.Editor
Expand All @@ -21,7 +22,12 @@ import com.intellij.openapi.vfs.VirtualFile
import java.net.URLEncoder
import java.util.Locale

class FindPullRequestAction : BaseFindPullRequestAction() {
class FindPullRequestAction @JvmOverloads constructor(private val prNumber: Int? = null) : BaseFindPullRequestAction(prNumber) {

override fun getActionUpdateThread(): ActionUpdateThread {
return ActionUpdateThread.BGT
}

override fun actionPerformForNoPullRequestFount(e: AnActionEvent, ex: NoPullRequestFoundException, url: String) {
val project: Project = e.getData(CommonDataKeys.PROJECT) ?: return
val config = PropertiesComponent.getInstance(project) ?: return
Expand All @@ -45,12 +51,16 @@ class FindPullRequestAction : BaseFindPullRequestAction() {
BrowserUtil.open(url)
}

override fun menuText(project: Project, useShortName: Boolean): String? {
override fun menuText(project: Project, useShortName: Boolean, prNumber: Int?): String? {
val config = PropertiesComponent.getInstance(project) ?: return null
return if (useShortName) {
FindPullRequestHostingServices.findBy(config.getHosting()).pullRequestName
} else {
"Go to ${FindPullRequestHostingServices.findBy(config.getHosting()).pullRequestName} page"
if (prNumber != null) {
"Go to ${FindPullRequestHostingServices.findBy(config.getHosting()).pullRequestName}(#$prNumber) page"
} else {
"Go to ${FindPullRequestHostingServices.findBy(config.getHosting()).pullRequestName} page"
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import com.intellij.notification.Notification
import com.intellij.notification.NotificationListener
import com.intellij.notification.NotificationType
import com.intellij.notification.Notifications
import com.intellij.openapi.actionSystem.ActionUpdateThread
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.editor.Editor
Expand All @@ -24,7 +25,11 @@ import java.net.URLEncoder
import java.util.Locale
import javax.swing.event.HyperlinkEvent

class FindPullRequestCopyAction : BaseFindPullRequestAction() {
class FindPullRequestCopyAction @JvmOverloads constructor(currentLine: Int? = null) : BaseFindPullRequestAction(currentLine) {

override fun getActionUpdateThread(): ActionUpdateThread {
return ActionUpdateThread.BGT
}

inner class CopyNotificationAdapter : NotificationListener.Adapter() {
override fun hyperlinkActivated(notification: Notification, e: HyperlinkEvent) {
Expand Down Expand Up @@ -71,12 +76,16 @@ class FindPullRequestCopyAction : BaseFindPullRequestAction() {
CopyPasteManager.getInstance().setContents(TextTransferable(text as CharSequence))
}

override fun menuText(project: Project, useShortName: Boolean): String? {
override fun menuText(project: Project, useShortName: Boolean, prNumber: Int?): String? {
val config = PropertiesComponent.getInstance(project) ?: return null
return if (useShortName) {
"Copy Link to ${FindPullRequestHostingServices.findBy(config.getHosting()).pullRequestName}"
} else {
"Copy Link to ${FindPullRequestHostingServices.findBy(config.getHosting()).pullRequestName} URL"
if (prNumber != null) {
"Copy Link to ${FindPullRequestHostingServices.findBy(config.getHosting()).pullRequestName}(#$prNumber) URL"
} else {
"Copy Link to ${FindPullRequestHostingServices.findBy(config.getHosting()).pullRequestName} URL"
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import com.github.shiraji.getNumberFromCommitMessage
import com.github.shiraji.isSquashPullRequestCommit
import com.intellij.ide.util.PropertiesComponent
import com.intellij.openapi.Disposable
import com.intellij.openapi.actionSystem.ActionUpdateThread
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.actionSystem.ToggleAction
Expand All @@ -34,6 +35,10 @@ import git4idea.repo.GitRepository

class ListPullRequestToggleAction : ToggleAction() {

override fun getActionUpdateThread(): ActionUpdateThread {
return ActionUpdateThread.BGT
}

private fun isEnabled(e: AnActionEvent, project: Project): Boolean {
val selectedFiles = e.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY)
if (selectedFiles == null || selectedFiles.size != 1) return false
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package com.github.shiraji.findpullrequest.annotation

import com.github.shiraji.findpullrequest.action.FindPullRequestAction
import com.github.shiraji.findpullrequest.action.FindPullRequestCopyAction
import com.github.shiraji.findpullrequest.domain.GitPullRequestInfo
import com.github.shiraji.findpullrequest.model.FindPullRequestModel
import com.intellij.ide.BrowserUtil
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.Separator
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.EditorGutterAction
import com.intellij.openapi.editor.TextAnnotationGutterProvider
Expand All @@ -29,7 +32,20 @@ class ListPullRequestTextAnnotationGutterProvider(
) : TextAnnotationGutterProvider, EditorGutterAction {

override fun getPopupActions(line: Int, editor: Editor?): MutableList<AnAction> {
return mutableListOf()
val actions = mutableListOf<AnAction>()
val currentLine = upToDateLineNumberProvider.getLineNumber(line)
if (currentLine < 0) return actions
val hash = fileAnnotation.getLineRevisionNumber(currentLine)?.asString() ?: ""
val prNumber = gitHashesMap[hash]?.prNumber
if (prNumber != null) {
actions.add(Separator())
actions.add(FindPullRequestAction(prNumber))
actions.add(FindPullRequestCopyAction(prNumber))
} else {
// copy commit hash
// open commit page
}
return actions
}

override fun getColor(line: Int, editor: Editor?): ColorKey? {
Expand Down Expand Up @@ -84,6 +100,14 @@ class ListPullRequestTextAnnotationGutterProvider(
}

override fun getCursor(lineNum: Int): Cursor {
return Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)
val currentLine = upToDateLineNumberProvider.getLineNumber(lineNum)
if (currentLine < 0) return Cursor.getDefaultCursor()
val hash = fileAnnotation.getLineRevisionNumber(currentLine)?.asString() ?: ""
val prNumber = gitHashesMap[hash]?.prNumber
return if (prNumber != null || gitHashesMap[hash]?.revisionNumber?.shortRev != null) {
Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)
} else {
Cursor.getDefaultCursor()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ class FindPullRequestModel(
return createUrl(repository, hostingServices, path)
}

fun createPullRequestPath(repository: GitRepository, prNumber: Int, hostingService: FindPullRequestHostingServices): String {
val path = hostingService.urlPathFormat.format(prNumber)
return createUrl(repository, hostingService, path)
}

fun createPullRequestPath(repository: GitRepository, revisionHash: VcsRevisionNumber): String {
val debugMessage = StringBuilder()
if (config.isDebugMode()) {
Expand All @@ -67,17 +72,17 @@ class FindPullRequestModel(
throw NoPullRequestFoundException(debugMessage.toString())
}

val path = targetHostingService.urlPathFormat.format(prNumber)
createUrl(repository, targetHostingService, path)
createPullRequestPath(repository, prNumber, targetHostingService)
} else {
val commit = gitHistoryService.findCommitLog(project, repository, revisionHash)
val hostingServices = FindPullRequestHostingServices.values().firstOrNull {
commit.isSquashPullRequestCommit(it)
}

if (hostingServices != null) {
val path = hostingServices.urlPathFormat.format(commit.getNumberFromCommitMessage(hostingServices.squashCommitMessage))
createUrl(repository, hostingServices, path)
val prNumber = commit.getNumberFromCommitMessage(hostingServices.squashCommitMessage)
?: throw NoPullRequestFoundException(debugMessage.toString())
createPullRequestPath(repository, prNumber, hostingServices)
} else {
throw NoPullRequestFoundException(debugMessage.toString())
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,22 @@ class FindPullRequestActionTest {
val config: PropertiesComponent?,
val useShortName: Boolean,
val hosting: String,
val prNumber: Int?,
val expected: String?,
private val testName: String,
) {
C1(null, true, "GitHub", null, "Should return null when PropertiesComponent is null"),
C2(mockk(), true, "GitHub", FindPullRequestHostingServices.GitHub.pullRequestName, "Should return short name if useShortName is true"),
C3(mockk(), true, "Bitbucket", FindPullRequestHostingServices.Bitbucket.pullRequestName, "Should return short name if useShortName is true for Bitbucket"),
C4(mockk(), true, "GitLab", FindPullRequestHostingServices.GitLab.pullRequestName, "Should return short name if useShortName is true for GitLab"),
C5(mockk(), true, "", FindPullRequestHostingServices.GitHub.pullRequestName, "Should return GitHub's short name if hosting is invalid value"),
C6(mockk(), false, "GitHub", "Go to ${FindPullRequestHostingServices.GitHub.pullRequestName} page", "Should return long name if useShortName is false"),
C7(mockk(), false, "Bitbucket", "Go to ${FindPullRequestHostingServices.Bitbucket.pullRequestName} page", "Should return short name if useShortName is false for Bitbucket"),
C8(mockk(), false, "GitLab", "Go to ${FindPullRequestHostingServices.GitLab.pullRequestName} page", "Should return short name if useShortName is false for GitLab"),
C9(mockk(), false, "", "Go to ${FindPullRequestHostingServices.GitHub.pullRequestName} page", "Should return GitHub's short name if hosting is invalid value"),
C1(null, true, "GitHub", null, null, "Should return null when PropertiesComponent is null"),
C2(mockk(), true, "GitHub", null, FindPullRequestHostingServices.GitHub.pullRequestName, "Should return short name if useShortName is true"),
C3(mockk(), true, "Bitbucket", null, FindPullRequestHostingServices.Bitbucket.pullRequestName, "Should return short name if useShortName is true for Bitbucket"),
C4(mockk(), true, "GitLab", null, FindPullRequestHostingServices.GitLab.pullRequestName, "Should return short name if useShortName is true for GitLab"),
C5(mockk(), true, "", null, FindPullRequestHostingServices.GitHub.pullRequestName, "Should return GitHub's short name if hosting is invalid value"),
C6(mockk(), false, "GitHub", null, "Go to ${FindPullRequestHostingServices.GitHub.pullRequestName} page", "Should return long name if useShortName is false"),
C7(mockk(), false, "Bitbucket", null, "Go to ${FindPullRequestHostingServices.Bitbucket.pullRequestName} page", "Should return long name if useShortName is false for Bitbucket"),
C8(mockk(), false, "GitLab", null, "Go to ${FindPullRequestHostingServices.GitLab.pullRequestName} page", "Should return long name if useShortName is false for GitLab"),
C9(mockk(), false, "", null,"Go to ${FindPullRequestHostingServices.GitHub.pullRequestName} page", "Should return GitHub's long name if hosting is invalid value"),
C10(mockk(), false, "GitHub", 34,"Go to ${FindPullRequestHostingServices.GitHub.pullRequestName}(#34) page", "Should return GitHub's long name with pr number if hosting is GitHub and prNumber is not null"),
C11(mockk(), false, "Bitbucket", 35,"Go to ${FindPullRequestHostingServices.GitHub.pullRequestName}(#35) page", "Should return Bitbucket's long name with pr number if hosting is Bitbucket and prNumber is not null"),
C12(mockk(), false, "GitLab", 1,"Go to ${FindPullRequestHostingServices.GitHub.pullRequestName}(#1) page", "Should return GitLab's long name with pr number if hosting is GitLab and prNumber is not null"),

;

Expand All @@ -58,7 +62,7 @@ class FindPullRequestActionTest {
if (test.config != null) {
every { test.config.getHosting() } returns test.hosting
}
val result = action.menuText(DummyProject.getInstance(), test.useShortName)
val result = action.menuText(DummyProject.getInstance(), test.useShortName, test.prNumber)
if (test.expected == null) {
assertNull(result)
} else {
Expand Down
Loading

0 comments on commit 682f2af

Please sign in to comment.