commit 7479a8a7b30eb85db1b28e9dd920a4f13791a563 from: ale date: Fri Jul 24 03:27:50 2026 UTC Add a Repository model and a branch-name status bar widget GotRepository/GotVcsRepositoryCreator/GotRepositoryManager plug into the platform's shared DVCS infrastructure (VcsRepositoryManager, AbstractRepositoryManager) rather than reimplementing repository tracking from scratch. GotBranchWidget (built on DvcsStatusWidget, the same base class git4idea's own branch widget uses) shows the current branch next to the project name in the main toolbar, matching Git's UI. Requires new compile dependencies on intellij.platform.vcs.dvcs and intellij.platform.vcs.dvcs.impl: Repository/RepositoryManager and the status widget base classes live outside com.intellij.modules.vcs. This Repository model is also the prerequisite for real PushSupport (native Ctrl+Shift+K dialog), which follows next. 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) { 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(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(project, GotVcs.getKey(), "got.repository.sync") { + + override fun getRepositories(): List = 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"/> + + +