diff --git a/wt-jetbrains-plugin/src/main/kotlin/com/block/wt/actions/WtAction.kt b/wt-jetbrains-plugin/src/main/kotlin/com/block/wt/actions/WtAction.kt index 98b6818..f5ce722 100644 --- a/wt-jetbrains-plugin/src/main/kotlin/com/block/wt/actions/WtAction.kt +++ b/wt-jetbrains-plugin/src/main/kotlin/com/block/wt/actions/WtAction.kt @@ -53,7 +53,9 @@ abstract class WtConfigAction : WtAction() { protected fun requireConfig(e: AnActionEvent): ContextConfig? { val project = e.project ?: return null - return ContextService.getInstance(project).getCurrentConfig() + val contextService = ContextService.getInstance(project) + contextService.reload() + return contextService.getCurrentConfig() } } diff --git a/wt-jetbrains-plugin/src/main/kotlin/com/block/wt/actions/worktree/RemoveWorktreeAction.kt b/wt-jetbrains-plugin/src/main/kotlin/com/block/wt/actions/worktree/RemoveWorktreeAction.kt index ccd961e..d42fd48 100644 --- a/wt-jetbrains-plugin/src/main/kotlin/com/block/wt/actions/worktree/RemoveWorktreeAction.kt +++ b/wt-jetbrains-plugin/src/main/kotlin/com/block/wt/actions/worktree/RemoveWorktreeAction.kt @@ -7,10 +7,10 @@ import com.block.wt.progress.asScope import com.block.wt.services.ContextService import com.block.wt.services.SymlinkSwitchService import com.block.wt.services.WorktreeService +import com.block.wt.settings.BranchDeletionMode import com.block.wt.settings.WtPluginSettings import com.block.wt.ui.Notifications import com.block.wt.ui.WorktreePanel -import com.block.wt.util.normalizeSafe import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.project.Project @@ -18,6 +18,8 @@ import com.intellij.openapi.ui.Messages import com.intellij.openapi.ui.popup.JBPopupFactory import com.intellij.openapi.ui.popup.PopupStep import com.intellij.openapi.ui.popup.util.BaseListPopupStep +import git4idea.branch.GitBrancher +import git4idea.repo.GitRepositoryManager class RemoveWorktreeAction : WtConfigAction() { @@ -68,11 +70,11 @@ class RemoveWorktreeAction : WtConfigAction() { } private fun confirmAndRemove(project: Project, wt: WorktreeInfo, worktreeService: WorktreeService) { - val config = ContextService.getInstance(project).getCurrentConfig() - if (config != null && wt.path.normalizeSafe() == config.mainRepoRoot.normalizeSafe()) { + if (wt.isMain) { Notifications.error(project, "Cannot Remove", "Cannot remove the main repository worktree") return } + val config = ContextService.getInstance(project).getCurrentConfig() val needsConfirmation = WtPluginSettings.getInstance().state.confirmBeforeRemove || wt.isDirty == true @@ -113,11 +115,13 @@ class RemoveWorktreeAction : WtConfigAction() { result.fold( onSuccess = { - scope.fraction(0.95) + scope.fraction(0.90) scope.text("Refreshing worktree list...") worktreeService.refreshWorktreeList() scope.fraction(1.0) Notifications.info(project, "Worktree Removed", "Removed ${wt.displayName}") + + offerBranchDeletion(project, wt.branch) }, onFailure = { ex -> Notifications.error(project, "Remove Failed", ex.message ?: "Unknown error") @@ -125,4 +129,42 @@ class RemoveWorktreeAction : WtConfigAction() { ) } } + + private fun offerBranchDeletion(project: Project, branch: String?) { + if (branch.isNullOrBlank() || branch in PROTECTED_BRANCHES) return + + val mode = try { + BranchDeletionMode.valueOf(WtPluginSettings.getInstance().state.branchDeletionAfterRemove) + } catch (_: IllegalArgumentException) { + BranchDeletionMode.ASK + } + if (mode == BranchDeletionMode.NEVER) return + + val shouldDelete = when (mode) { + BranchDeletionMode.ALWAYS -> true + BranchDeletionMode.ASK -> { + var answer = Messages.NO + ApplicationManager.getApplication().invokeAndWait { + answer = Messages.showYesNoDialog( + project, + "Delete branch '$branch'?", + "Delete Branch", + Messages.getQuestionIcon(), + ) + } + answer == Messages.YES + } + BranchDeletionMode.NEVER -> false + } + if (!shouldDelete) return + + ApplicationManager.getApplication().invokeLater { + val repos = GitRepositoryManager.getInstance(project).repositories + GitBrancher.getInstance(project).deleteBranches(mapOf(branch to repos), null) + } + } + + companion object { + private val PROTECTED_BRANCHES = setOf("main", "master") + } } diff --git a/wt-jetbrains-plugin/src/main/kotlin/com/block/wt/settings/WtPluginSettings.kt b/wt-jetbrains-plugin/src/main/kotlin/com/block/wt/settings/WtPluginSettings.kt index b245e7f..ee4e366 100644 --- a/wt-jetbrains-plugin/src/main/kotlin/com/block/wt/settings/WtPluginSettings.kt +++ b/wt-jetbrains-plugin/src/main/kotlin/com/block/wt/settings/WtPluginSettings.kt @@ -7,6 +7,8 @@ import com.intellij.openapi.components.State import com.intellij.openapi.components.Storage import com.intellij.openapi.components.service +enum class BranchDeletionMode { ASK, ALWAYS, NEVER } + @Service(Service.Level.APP) @State( name = "com.block.wt.settings.WtPluginSettings", @@ -27,6 +29,7 @@ class WtPluginSettings : PersistentStateComponent { var lastWelcomeVersion: String = "", var enhancedSessionDetection: Boolean = true, var agentTerminalNavigation: Boolean = true, + var branchDeletionAfterRemove: String = "ASK", ) @Volatile diff --git a/wt-jetbrains-plugin/src/main/kotlin/com/block/wt/settings/WtSettingsComponent.kt b/wt-jetbrains-plugin/src/main/kotlin/com/block/wt/settings/WtSettingsComponent.kt index 9efaa3b..d169bef 100644 --- a/wt-jetbrains-plugin/src/main/kotlin/com/block/wt/settings/WtSettingsComponent.kt +++ b/wt-jetbrains-plugin/src/main/kotlin/com/block/wt/settings/WtSettingsComponent.kt @@ -2,6 +2,7 @@ package com.block.wt.settings import com.intellij.openapi.ui.DialogPanel import com.intellij.ui.dsl.builder.bindIntValue +import com.intellij.ui.dsl.builder.bindItem import com.intellij.ui.dsl.builder.bindSelected import com.intellij.ui.dsl.builder.panel import javax.swing.JComponent @@ -55,6 +56,14 @@ class WtSettingsComponent { checkBox("Confirm before removing worktrees") .bindSelected(settings.state::confirmBeforeRemove) } + row("After removing worktree, delete branch:") { + comboBox(BranchDeletionMode.entries.toList()) + .bindItem( + { BranchDeletionMode.valueOf(settings.state.branchDeletionAfterRemove) }, + { settings.state.branchDeletionAfterRemove = (it ?: BranchDeletionMode.ASK).name }, + ) + .comment("Ask = prompt each time, Always = delete without asking, Never = keep branch") + } } }