commit 7ec62b12361bdec10782a2cd24c4125cf0585d98 from: ale date: Fri Jul 24 04:37:41 2026 UTC Replace the simple Send action with a native Push dialog Adds GotPushSource/GotPushTarget/GotPusher/GotOutgoingCommitsProvider/ GotPushTargetPanel/GotPushSupport, wired to the Repository model added previously. This enables IntelliJ's native Push dialog (Ctrl+Shift+K) for got send, showing the current branch and target ('origin/') the same way Git does, instead of a plain menu action with no preview. GotOutgoingCommitsProvider reports an empty outgoing-commits list: got has no cheap local way to compute what a send would push without contacting the server first, so the dialog works but doesn't preview commits ahead of time. GotPushTargetPanel is read-only (got resolves its own remote/branch via got.conf), unlike Git's editable target. GotSendAction is removed; the same got send functionality is now reached through the Push dialog instead of a VCS Operations Popup entry. commit - 7479a8a7b30eb85db1b28e9dd920a4f13791a563 commit + 7ec62b12361bdec10782a2cd24c4125cf0585d98 blob - 71f3a0954bab5118fb9fe7ed584cbadb0c13b056 blob + 4fb1f50fbdb4bf46e11a89b1330a03e41e92e66b --- README.md +++ README.md @@ -17,7 +17,8 @@ and update/push workflow you get with Git, backed by t - 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 @@ -37,15 +38,17 @@ corresponding IntelliJ Platform VCS API. | Rollback | `got revert -R ` | | 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 @@ -30,6 +30,8 @@ dependencies { // 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") } } @@ -40,9 +42,9 @@ intellijPlatform { } 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 @@ -1,65 +0,0 @@ -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() - 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 { - 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 @@ -0,0 +1,20 @@ +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() { + override fun getOutgoingCommits( + repository: GotRepository, + pushSpec: PushSpec, + initial: Boolean, + ): OutgoingResult = OutgoingResult(emptyList(), emptyList()) +} blob - /dev/null blob + c569400424f0a71f3b7c8132e9e28a03eedac88d (mode 644) --- /dev/null +++ src/main/kotlin/dev/nezzontli/gotvcs/push/GotPushSource.kt @@ -0,0 +1,7 @@ +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 @@ -0,0 +1,48 @@ +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() { + + 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 = + project.getService(GotRepositoryManager::class.java) + + override fun createTargetPanel( + repository: GotRepository, + source: GotPushSource, + target: GotPushTarget?, + ): PushTargetPanel = 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 @@ -0,0 +1,13 @@ +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 @@ -0,0 +1,31 @@ +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() { + + 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 @@ -0,0 +1,38 @@ +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() { + + override fun push( + pushSpecs: MutableMap>, + forcePushOptionValue: VcsPushOptionValue?, + force: Boolean, + ) { + val errors = mutableListOf() + 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 @@ -9,7 +9,8 @@
  • File status, native diff, and modified-lines gutter
  • Commit and rollback from the Commit tool window
  • File history and Update Project (got update / got fetch)
  • -
  • Send action (got send) and a Settings panel for the got binary path
  • +
  • Branch name widget and native Push dialog (Ctrl+Shift+K)
  • +
  • Settings panel for the got binary path and SSH_AUTH_SOCK
  • See the README for details on how each feature maps to the underlying got command. ]]> @@ -30,13 +31,6 @@ + - - - - - - -