commit - 7479a8a7b30eb85db1b28e9dd920a4f13791a563
commit + 7ec62b12361bdec10782a2cd24c4125cf0585d98
blob - 71f3a0954bab5118fb9fe7ed584cbadb0c13b056
blob + 4fb1f50fbdb4bf46e11a89b1330a03e41e92e66b
--- README.md
+++ README.md
- Native diff and modified-lines gutter (`got cat` against the base commit)
- Commit and rollback from the Commit tool window (`got commit`, `got revert`)
- File history (`got log`) and Update Project (`got update` / `got fetch`)
-- A **Send** action (`got send`), bound to `Ctrl+Shift+K` by default
+- Current branch name shown in the main toolbar, and the native Push dialog
+ (`Ctrl+Shift+K`) for `got send`
- A Settings panel (*Settings > Version Control > got*) to override the
`got` binary path and `SSH_AUTH_SOCK`, for setups where auto-detection
doesn't apply
| Rollback | `got revert -R <paths>` |
| History | `got log` |
| Update Project | `got fetch` + `got update` |
-| Send | `got send` |
+| Branch widget | `got info` ("work tree branch reference") |
+| Push | `got send` |
Source is organized by responsibility under `dev.nezzontli.gotvcs`:
- `cli` — the single wrapper around `got` invocations (`GotCommandLineWrapper`)
- `changes`, `checkin`, `history`, `update`, `roots` — one package per VCS
extension point implemented
+- `repo` — the `Repository` model and the branch-name status bar widget
+- `push` — native Push dialog support (`PushSupport` and friends)
- `settings` — the persisted configuration and its Settings panel
-- `actions` — the `Send` menu action
## Requirements
blob - 013a80906f0cc310c026f4a16fa95ce921844391
blob + 59801df9877633c858b4d08ab598a6e0a8b2799d
--- build.gradle.kts
+++ build.gradle.kts
// classes live here, not under com.intellij.modules.vcs.
bundledModule("intellij.platform.vcs.dvcs")
bundledModule("intellij.platform.vcs.dvcs.impl")
+ // Referenced by OutgoingResult's commit list type (com.intellij.dvcs.push).
+ bundledModule("intellij.platform.vcs.log")
}
}
}
changeNotes = """
- Read-only file status, native diff, commit/rollback, history,
- update/fetch, a Send action, and a Settings panel for the got
- binary path and SSH_AUTH_SOCK.
+ File status, native diff, commit/rollback, history, update/fetch,
+ a branch-name widget, the native Push dialog, and a Settings
+ panel for the got binary path and SSH_AUTH_SOCK.
""".trimIndent()
}
blob - 0f1813e13cbe9ec189834ba3e7bd4fcf19b8dbc7 (mode 644)
blob + /dev/null
--- src/main/kotlin/dev/nezzontli/gotvcs/actions/GotSendAction.kt
+++ /dev/null
-package dev.nezzontli.gotvcs.actions
-
-import com.intellij.notification.NotificationGroupManager
-import com.intellij.notification.NotificationType
-import com.intellij.openapi.actionSystem.AnAction
-import com.intellij.openapi.actionSystem.AnActionEvent
-import com.intellij.openapi.progress.ProgressIndicator
-import com.intellij.openapi.progress.ProgressManager
-import com.intellij.openapi.progress.Task
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.vcs.ProjectLevelVcsManager
-import com.intellij.openapi.vcs.VcsException
-import com.intellij.openapi.vfs.VirtualFile
-import dev.nezzontli.gotvcs.GotVcs
-import dev.nezzontli.gotvcs.cli.GotCommandLineWrapper
-import java.io.File
-
-/**
- * Simple menu action for `got send` (the equivalent of "push"). This does
- * not hook into IntelliJ's native Push dialog (Ctrl+Shift+K): that requires
- * a PushSupport backed by a full Repository/RepositoryManager model,
- * comparable in size to the rest of this plugin combined. A single action
- * that runs `got send` and reports the result covers the real use case
- * without that complexity.
- */
-class GotSendAction : AnAction() {
-
- override fun update(e: AnActionEvent) {
- e.presentation.isEnabledAndVisible = e.project?.let { gotRoots(it).isNotEmpty() } ?: false
- }
-
- override fun actionPerformed(e: AnActionEvent) {
- val project = e.project ?: return
- val roots = gotRoots(project)
- if (roots.isEmpty()) return
-
- val commandLine = GotCommandLineWrapper()
- ProgressManager.getInstance().run(object : Task.Backgroundable(project, "got send", true) {
- override fun run(indicator: ProgressIndicator) {
- val errors = mutableListOf<String>()
- for (root in roots) {
- try {
- commandLine.send(File(root.path))
- } catch (ex: VcsException) {
- errors.add("${root.path}: ${ex.message}")
- }
- }
- val group = NotificationGroupManager.getInstance().getNotificationGroup("got")
- if (errors.isEmpty()) {
- group.createNotification("got send: changes sent successfully", NotificationType.INFORMATION)
- .notify(project)
- } else {
- group.createNotification("got send failed", errors.joinToString("\n"), NotificationType.ERROR)
- .notify(project)
- }
- }
- })
- }
-
- private fun gotRoots(project: Project): List<VirtualFile> {
- val vcsManager = ProjectLevelVcsManager.getInstance(project)
- val gotVcs = vcsManager.findVcsByName(GotVcs.NAME) ?: return emptyList()
- return vcsManager.getRootsUnderVcs(gotVcs).toList()
- }
-}
blob - /dev/null
blob + a2df57f27c8576ff4321027caeb61a6e2c2217dc (mode 644)
--- /dev/null
+++ src/main/kotlin/dev/nezzontli/gotvcs/push/GotOutgoingCommitsProvider.kt
+package dev.nezzontli.gotvcs.push
+
+import com.intellij.dvcs.push.OutgoingCommitsProvider
+import com.intellij.dvcs.push.OutgoingResult
+import com.intellij.dvcs.push.PushSpec
+import dev.nezzontli.gotvcs.repo.GotRepository
+
+/**
+ * got has no cheap local equivalent of "commits not yet on the remote"
+ * without contacting the server first, so this reports an empty preview
+ * rather than an inaccurate one. The Push dialog still works; it just
+ * doesn't list outgoing commits ahead of time.
+ */
+class GotOutgoingCommitsProvider : OutgoingCommitsProvider<GotRepository, GotPushSource, GotPushTarget>() {
+ override fun getOutgoingCommits(
+ repository: GotRepository,
+ pushSpec: PushSpec<GotPushSource, GotPushTarget>,
+ initial: Boolean,
+ ): OutgoingResult = OutgoingResult(emptyList(), emptyList())
+}
blob - /dev/null
blob + c569400424f0a71f3b7c8132e9e28a03eedac88d (mode 644)
--- /dev/null
+++ src/main/kotlin/dev/nezzontli/gotvcs/push/GotPushSource.kt
+package dev.nezzontli.gotvcs.push
+
+import com.intellij.dvcs.push.PushSource
+
+class GotPushSource(private val branch: String) : PushSource {
+ override fun getPresentation(): String = branch
+}
blob - /dev/null
blob + ae7f6076ead4322cc0a63a24d017ac0f76b98a8e (mode 644)
--- /dev/null
+++ src/main/kotlin/dev/nezzontli/gotvcs/push/GotPushSupport.kt
+package dev.nezzontli.gotvcs.push
+
+import com.intellij.dvcs.push.PushSupport
+import com.intellij.dvcs.push.PushTargetPanel
+import com.intellij.dvcs.repo.RepositoryManager
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.vcs.AbstractVcs
+import com.intellij.openapi.vcs.ProjectLevelVcsManager
+import dev.nezzontli.gotvcs.GotVcs
+import dev.nezzontli.gotvcs.cli.GotCommandLineWrapper
+import dev.nezzontli.gotvcs.repo.GotRepository
+import dev.nezzontli.gotvcs.repo.GotRepositoryManager
+
+class GotPushSupport(private val project: Project) : PushSupport<GotRepository, GotPushSource, GotPushTarget>() {
+
+ private val commandLine = GotCommandLineWrapper()
+ private val pusher = GotPusher(commandLine)
+ private val outgoingCommitsProvider = GotOutgoingCommitsProvider()
+
+ override fun getVcs(): AbstractVcs = ProjectLevelVcsManager.getInstance(project).findVcsByName(GotVcs.NAME)!!
+
+ override fun getPusher() = pusher
+
+ override fun getOutgoingCommitsProvider() = outgoingCommitsProvider
+
+ override fun getDefaultTarget(repository: GotRepository): GotPushTarget? {
+ val branch = repository.currentBranchName ?: return null
+ return GotPushTarget("origin", branch)
+ }
+
+ override fun getSource(repository: GotRepository): GotPushSource =
+ GotPushSource(repository.currentBranchName ?: "")
+
+ override fun getRepositoryManager(): RepositoryManager<GotRepository> =
+ project.getService(GotRepositoryManager::class.java)
+
+ override fun createTargetPanel(
+ repository: GotRepository,
+ source: GotPushSource,
+ target: GotPushTarget?,
+ ): PushTargetPanel<GotPushTarget> = GotPushTargetPanel(target ?: GotPushTarget("origin", source.presentation))
+
+ override fun isForcePushAllowed(repository: GotRepository, target: GotPushTarget): Boolean = true
+
+ override fun isSilentForcePushAllowed(target: GotPushTarget): Boolean = false
+
+ override fun saveSilentForcePushTarget(target: GotPushTarget) = Unit
+}
blob - /dev/null
blob + ba31c5d498654310fa732f8323f263e9daa97f3b (mode 644)
--- /dev/null
+++ src/main/kotlin/dev/nezzontli/gotvcs/push/GotPushTarget.kt
+package dev.nezzontli.gotvcs.push
+
+import com.intellij.dvcs.push.PushTarget
+
+/**
+ * got does not expose a cheap way to tell ahead of time whether a send would
+ * be a no-op, so [hasSomethingToPush] always returns true: `got send` itself
+ * reports "nothing to send" if that turns out to be the case.
+ */
+class GotPushTarget(private val remoteName: String, private val branch: String) : PushTarget {
+ override fun hasSomethingToPush(): Boolean = true
+ override fun getPresentation(): String = "$remoteName/$branch"
+}
blob - /dev/null
blob + 6938d5fb20afe3150e1254d9cf4a0d07f65c14a5 (mode 644)
--- /dev/null
+++ src/main/kotlin/dev/nezzontli/gotvcs/push/GotPushTargetPanel.kt
+package dev.nezzontli.gotvcs.push
+
+import com.intellij.dvcs.push.PushTargetPanel
+import com.intellij.dvcs.push.ui.PushTargetEditorListener
+import com.intellij.openapi.ui.ValidationInfo
+import com.intellij.ui.ColoredTreeCellRenderer
+import com.intellij.ui.SimpleTextAttributes
+
+/**
+ * A read-only target panel: got sends to whichever remote/branch got.conf
+ * and the work tree resolve by default, so there is nothing to edit here
+ * (unlike Git, which lets you retarget a push to an arbitrary branch).
+ */
+class GotPushTargetPanel(private val target: GotPushTarget) : PushTargetPanel<GotPushTarget>() {
+
+ override fun render(renderer: ColoredTreeCellRenderer, isSelected: Boolean, isActive: Boolean, text: String?) {
+ renderer.append(target.presentation, SimpleTextAttributes.REGULAR_ATTRIBUTES)
+ }
+
+ override fun getValue(): GotPushTarget = target
+
+ override fun fireOnCancel() = Unit
+
+ override fun fireOnChange() = Unit
+
+ override fun verify(): ValidationInfo? = null
+
+ override fun setFireOnChangeAction(action: Runnable) = Unit
+
+ override fun addTargetEditorListener(listener: PushTargetEditorListener) = Unit
+}
blob - /dev/null
blob + b974d16779def762c4a4d1815d1e6b8aae07b979 (mode 644)
--- /dev/null
+++ src/main/kotlin/dev/nezzontli/gotvcs/push/GotPusher.kt
+package dev.nezzontli.gotvcs.push
+
+import com.intellij.dvcs.push.PushSpec
+import com.intellij.dvcs.push.Pusher
+import com.intellij.dvcs.push.VcsPushOptionValue
+import com.intellij.notification.NotificationGroupManager
+import com.intellij.notification.NotificationType
+import com.intellij.openapi.vcs.VcsException
+import dev.nezzontli.gotvcs.cli.GotCommandLineWrapper
+import dev.nezzontli.gotvcs.repo.GotRepository
+import java.io.File
+
+class GotPusher(private val commandLine: GotCommandLineWrapper) :
+ Pusher<GotRepository, GotPushSource, GotPushTarget>() {
+
+ override fun push(
+ pushSpecs: MutableMap<GotRepository, PushSpec<GotPushSource, GotPushTarget>>,
+ forcePushOptionValue: VcsPushOptionValue?,
+ force: Boolean,
+ ) {
+ val errors = mutableListOf<String>()
+ for (repository in pushSpecs.keys) {
+ try {
+ commandLine.send(File(repository.root.path))
+ } catch (e: VcsException) {
+ errors.add("${repository.root.path}: ${e.message}")
+ }
+ }
+
+ val project = pushSpecs.keys.firstOrNull()?.project ?: return
+ val group = NotificationGroupManager.getInstance().getNotificationGroup("got")
+ if (errors.isEmpty()) {
+ group.createNotification("got send: changes sent successfully", NotificationType.INFORMATION).notify(project)
+ } else {
+ group.createNotification("got send failed", errors.joinToString("\n"), NotificationType.ERROR).notify(project)
+ }
+ }
+}
blob - 22f036062dac0b0f2971b4e5d54c5738836fd31b
blob + 10b7ba43876f4f2897f39aa65ff5c2488054c3e1
--- src/main/resources/META-INF/plugin.xml
+++ src/main/resources/META-INF/plugin.xml
<li>File status, native diff, and modified-lines gutter</li>
<li>Commit and rollback from the Commit tool window</li>
<li>File history and Update Project (got update / got fetch)</li>
- <li>Send action (got send) and a Settings panel for the got binary path</li>
+ <li>Branch name widget and native Push dialog (Ctrl+Shift+K)</li>
+ <li>Settings panel for the got binary path and SSH_AUTH_SOCK</li>
</ul>
See the <a href="https://github.com/Richard7987/gotvcs-intellij">README</a> for details on how each feature maps to the underlying got command.
]]></description>
<statusBarWidgetFactory id="got.branch.widget"
implementation="dev.nezzontli.gotvcs.repo.GotBranchWidget$Factory"
order="after CodeStyleStatusBarWidget"/>
+ <pushSupport implementation="dev.nezzontli.gotvcs.push.GotPushSupport"/>
</extensions>
-
- <actions>
- <action id="Got.Send" class="dev.nezzontli.gotvcs.actions.GotSendAction" text="Send (got send)"
- description="Sends local changes to the remote via got send">
- <add-to-group group-id="Vcs.Operations.Popup" anchor="last"/>
- <keyboard-shortcut keymap="$default" first-keystroke="ctrl shift K"/>
- </action>
- </actions>
</idea-plugin>