Commit Diff


commit - 4a9d1c555f6ed4615c6b891e5d20aa1c6b4644a0
commit + 7479a8a7b30eb85db1b28e9dd920a4f13791a563
blob - 433791abb5e6f61c2e92d3464a74c7e6b9489db3
blob + 013a80906f0cc310c026f4a16fa95ce921844391
--- build.gradle.kts
+++ build.gradle.kts
@@ -26,6 +26,10 @@ dependencies {
             intellijIdea("2026.1.4")
         }
         bundledModule("com.intellij.modules.vcs")
+        // Repository/RepositoryManager and the DVCS status widget base
+        // classes live here, not under com.intellij.modules.vcs.
+        bundledModule("intellij.platform.vcs.dvcs")
+        bundledModule("intellij.platform.vcs.dvcs.impl")
     }
 }
 
blob - abc3903426b56dde246cb7d78df9fa3e99f74036
blob + 061b30b9cccd625922be97ff4080fa8d96371d65
--- src/main/kotlin/dev/nezzontli/gotvcs/cli/GotCommandLineWrapper.kt
+++ src/main/kotlin/dev/nezzontli/gotvcs/cli/GotCommandLineWrapper.kt
@@ -88,7 +88,16 @@ class GotCommandLineWrapper {
         return line.substringAfter("work tree base commit:").trim()
     }
 
+    /** Current branch name (e.g. "main"), parsed from `got info`'s "work tree branch reference" line. */
     @Throws(VcsException::class)
+    fun currentBranch(workDir: File): String? {
+        val output = run(workDir, "info")
+        val line = output.lineSequence().firstOrNull { it.trimStart().startsWith("work tree branch reference:") }
+            ?: return null
+        return line.substringAfter("work tree branch reference:").trim().removePrefix("refs/heads/")
+    }
+
+    @Throws(VcsException::class)
     fun commit(workDir: File, message: String, paths: List<String>) {
         if (paths.isEmpty()) return
         run(workDir, *(arrayOf("commit", "-m", message) + paths))
blob - /dev/null
blob + 5cfb8547432e834d0bab37bc6130158b86a1ac21 (mode 644)
--- /dev/null
+++ src/main/kotlin/dev/nezzontli/gotvcs/repo/GotBranchWidget.kt
@@ -0,0 +1,41 @@
+package dev.nezzontli.gotvcs.repo
+
+import com.intellij.dvcs.ui.DvcsStatusWidget
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.vfs.VirtualFile
+import com.intellij.openapi.wm.StatusBarWidget
+import com.intellij.openapi.wm.StatusBarWidgetFactory
+
+private const val WIDGET_ID = "got.branch.widget"
+
+class GotBranchWidget(project: Project) : DvcsStatusWidget<GotRepository>(project, "got") {
+
+    override fun ID(): String = WIDGET_ID
+
+    override fun copy(): StatusBarWidget = GotBranchWidget(project)
+
+    override fun guessCurrentRepository(project: Project, selectedFile: VirtualFile?): GotRepository? {
+        val manager = project.getService(GotRepositoryManager::class.java)
+        selectedFile?.let { manager.getRepositoryForFileQuick(it) }?.let { return it }
+        return manager.repositories.firstOrNull()
+    }
+
+    override fun getFullBranchName(repository: GotRepository): String = repository.currentBranchName ?: "got"
+
+    override fun isMultiRoot(project: Project): Boolean = project.getService(GotRepositoryManager::class.java).moreThanOneRoot()
+
+    override fun rememberRecentRoot(path: String) = Unit
+
+    class Factory : StatusBarWidgetFactory {
+        override fun getId(): String = WIDGET_ID
+
+        override fun getDisplayName(): String = "got Branch Widget"
+
+        override fun isAvailable(project: Project): Boolean =
+            project.getService(GotRepositoryManager::class.java).repositories.isNotEmpty()
+
+        override fun createWidget(project: Project): StatusBarWidget = GotBranchWidget(project)
+
+        override fun isEnabledByDefault(): Boolean = true
+    }
+}
blob - /dev/null
blob + 47adf6a68fa6f4aaa132832d08eb15c65b970ba4 (mode 644)
--- /dev/null
+++ src/main/kotlin/dev/nezzontli/gotvcs/repo/GotRepository.kt
@@ -0,0 +1,61 @@
+package dev.nezzontli.gotvcs.repo
+
+import com.intellij.dvcs.repo.Repository
+import com.intellij.openapi.Disposable
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.util.Disposer
+import com.intellij.openapi.vcs.AbstractVcs
+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
+
+class GotRepository(
+    private val project: Project,
+    private val root: VirtualFile,
+    private val commandLine: GotCommandLineWrapper,
+    parentDisposable: Disposable,
+) : Repository {
+
+    private var disposed = false
+
+    init {
+        Disposer.register(parentDisposable, this)
+    }
+
+    override fun getRoot(): VirtualFile = root
+
+    override fun getPresentableUrl(): String = root.presentableUrl
+
+    override fun getProject(): Project = project
+
+    override fun getState(): Repository.State = Repository.State.NORMAL
+
+    override fun getCurrentBranchName(): String? = try {
+        commandLine.currentBranch(File(root.path))
+    } catch (e: VcsException) {
+        null
+    }
+
+    override fun getVcs(): AbstractVcs = ProjectLevelVcsManager.getInstance(project).findVcsByName(GotVcs.NAME)!!
+
+    override fun getCurrentRevision(): String? = try {
+        commandLine.baseCommit(File(root.path))
+    } catch (e: VcsException) {
+        null
+    }
+
+    override fun isFresh(): Boolean = false
+
+    override fun update() = Unit
+
+    override fun toLogString(): String = "GotRepository{root=$root}"
+
+    override fun dispose() {
+        disposed = true
+    }
+
+    override fun isDisposed(): Boolean = disposed
+}
blob - /dev/null
blob + 9531ed74274324eda46a8ba44e3fd3847bf6e157 (mode 644)
--- /dev/null
+++ src/main/kotlin/dev/nezzontli/gotvcs/repo/GotRepositoryManager.kt
@@ -0,0 +1,13 @@
+package dev.nezzontli.gotvcs.repo
+
+import com.intellij.dvcs.repo.AbstractRepositoryManager
+import com.intellij.openapi.project.Project
+import dev.nezzontli.gotvcs.GotVcs
+
+class GotRepositoryManager(project: Project) :
+    AbstractRepositoryManager<GotRepository>(project, GotVcs.getKey(), "got.repository.sync") {
+
+    override fun getRepositories(): List<GotRepository> = getRepositories(GotRepository::class.java)
+
+    override fun isSyncEnabled(): Boolean = false
+}
blob - /dev/null
blob + 82d0707f568ac22de03dc0b540174b5beabf26ae (mode 644)
--- /dev/null
+++ src/main/kotlin/dev/nezzontli/gotvcs/repo/GotVcsRepositoryCreator.kt
@@ -0,0 +1,21 @@
+package dev.nezzontli.gotvcs.repo
+
+import com.intellij.dvcs.repo.Repository
+import com.intellij.dvcs.repo.VcsRepositoryCreator
+import com.intellij.openapi.Disposable
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.vcs.VcsKey
+import com.intellij.openapi.vfs.VirtualFile
+import dev.nezzontli.gotvcs.GotVcs
+import dev.nezzontli.gotvcs.cli.GotCommandLineWrapper
+import java.io.File
+
+class GotVcsRepositoryCreator : VcsRepositoryCreator {
+
+    override fun getVcsKey(): VcsKey = GotVcs.getKey()
+
+    override fun createRepositoryIfValid(project: Project, root: VirtualFile, parentDisposable: Disposable): Repository? {
+        if (!File(root.path, ".got").isDirectory) return null
+        return GotRepository(project, root, GotCommandLineWrapper(), parentDisposable)
+    }
+}
blob - 2e3aa6efb3c254a6db025a06c9d04e04bccf1533
blob + 22f036062dac0b0f2971b4e5d54c5738836fd31b
--- src/main/resources/META-INF/plugin.xml
+++ src/main/resources/META-INF/plugin.xml
@@ -22,9 +22,14 @@
              displayName="got"
              administrativeAreaName=".got"/>
         <vcsRootChecker implementation="dev.nezzontli.gotvcs.roots.GotVcsRootChecker"/>
+        <vcsRepositoryCreator implementation="dev.nezzontli.gotvcs.repo.GotVcsRepositoryCreator"/>
         <applicationService serviceImplementation="dev.nezzontli.gotvcs.settings.GotSettingsState"/>
         <applicationConfigurable instance="dev.nezzontli.gotvcs.settings.GotConfigurable" displayName="got" parentId="vcs"/>
         <notificationGroup id="got" displayType="BALLOON"/>
+        <projectService serviceImplementation="dev.nezzontli.gotvcs.repo.GotRepositoryManager"/>
+        <statusBarWidgetFactory id="got.branch.widget"
+                                 implementation="dev.nezzontli.gotvcs.repo.GotBranchWidget$Factory"
+                                 order="after CodeStyleStatusBarWidget"/>
     </extensions>
 
     <actions>