Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions Resources/shell-integration/cmux-bash-integration.bash
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,7 @@ _cmux_record_pr_command_hint() {
}

_cmux_emit_pr_command_hint() {
[[ "${CMUX_NO_PR_WATCH:-}" == "1" ]] && return 0
[[ -S "$CMUX_SOCKET_PATH" ]] || return 0
[[ -n "$CMUX_TAB_ID" ]] || return 0
[[ -n "$CMUX_PANEL_ID" ]] || return 0
Expand Down Expand Up @@ -867,6 +868,11 @@ _cmux_pr_request_probe() {
_cmux_report_pr_for_path() {
local repo_path="$1"
local force_probe="${2:-0}"
if [[ "${CMUX_NO_PR_WATCH:-}" == "1" ]]; then
_cmux_pr_cache_clear
_cmux_clear_pr_for_panel
return 0
fi
[[ -n "$repo_path" ]] || {
_cmux_pr_cache_clear
_cmux_clear_pr_for_panel
Expand Down Expand Up @@ -1070,6 +1076,10 @@ _cmux_stop_pr_poll_loop() {
}

_cmux_start_pr_poll_loop() {
if [[ "${CMUX_NO_PR_WATCH:-}" == "1" ]]; then
_cmux_stop_pr_poll_loop
return 0
fi
[[ "${CMUX_NO_GIT_WATCH:-}" == "1" ]] && return 0
[[ -S "$CMUX_SOCKET_PATH" ]] || return 0
[[ -n "$CMUX_TAB_ID" ]] || return 0
Expand Down
10 changes: 10 additions & 0 deletions Resources/shell-integration/cmux-zsh-integration.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,7 @@ _cmux_record_pr_command_hint() {
}

_cmux_emit_pr_command_hint() {
[[ "${CMUX_NO_PR_WATCH:-}" == "1" ]] && return 0
[[ -S "$CMUX_SOCKET_PATH" ]] || return 0
[[ -n "$CMUX_TAB_ID" ]] || return 0
[[ -n "$CMUX_PANEL_ID" ]] || return 0
Expand Down Expand Up @@ -999,6 +1000,11 @@ _cmux_pr_request_probe() {
_cmux_report_pr_for_path() {
local repo_path="$1"
local force_probe="${2:-0}"
if [[ "${CMUX_NO_PR_WATCH:-}" == "1" ]]; then
_cmux_pr_cache_clear
_cmux_clear_pr_for_panel
return 0
fi
[[ -n "$repo_path" ]] || {
_cmux_pr_cache_clear
_cmux_clear_pr_for_panel
Expand Down Expand Up @@ -1202,6 +1208,10 @@ _cmux_stop_pr_poll_loop() {
}

_cmux_start_pr_poll_loop() {
if [[ "${CMUX_NO_PR_WATCH:-}" == "1" ]]; then
_cmux_stop_pr_poll_loop
return 0
fi
[[ "${CMUX_NO_GIT_WATCH:-}" == "1" ]] && return 0
[[ -S "$CMUX_SOCKET_PATH" ]] || return 0
[[ -n "$CMUX_TAB_ID" ]] || return 0
Expand Down
4 changes: 4 additions & 0 deletions Sources/CmuxSettingsJSONPathSupport.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ extension SidebarWorkspaceDetailDefaults {
static func watchGitStatusValue(defaults: UserDefaults) -> Bool {
boolValue(defaults: defaults, key: watchGitStatusKey, defaultValue: watchGitStatus)
}

static func pullRequestPollingEnabled(defaults: UserDefaults) -> Bool {
watchGitStatusValue(defaults: defaults) && showPullRequestsValue(defaults: defaults)
}
}

enum AutomationSettings {
Expand Down
1 change: 1 addition & 0 deletions Sources/GhosttyTerminalView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6158,6 +6158,7 @@ final class TerminalSurface: Identifiable, ObservableObject {
setManagedEnvironmentValue("CMUX_SHELL_INTEGRATION_DIR", integrationDir)
Self.applyManagedGitWatchEnvironment(
watchGitStatusEnabled: SidebarWorkspaceDetailDefaults.watchGitStatusValue(defaults: .standard),
showPullRequestsEnabled: SidebarWorkspaceDetailDefaults.showPullRequestsValue(defaults: .standard),
to: &env,
protectedKeys: &protectedStartupEnvironmentKeys
)
Expand Down
101 changes: 84 additions & 17 deletions Sources/TabManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1253,6 +1253,7 @@ class TabManager: ObservableObject {
private var workspaceGitMetadataWatcherDescriptorGeneration: UInt64 = 0
private var workspaceGitMetadataFallbackTimer: DispatchSourceTimer?
private var lastSidebarGitMetadataWatchEnabled = SidebarWorkspaceDetailDefaults.watchGitStatusValue(defaults: .standard)
private var lastSidebarPullRequestPollingEnabled = SidebarWorkspaceDetailDefaults.pullRequestPollingEnabled(defaults: .standard)
private var workspacePullRequestProbeStateByKey: [WorkspaceGitProbeKey: WorkspaceGitProbeState] = [:]
private var workspacePullRequestNextPollAtByKey: [WorkspaceGitProbeKey: Date] = [:]
private var workspacePullRequestLastTerminalStateRefreshAtByKey: [WorkspaceGitProbeKey: Date] = [:]
Expand Down Expand Up @@ -1342,7 +1343,7 @@ class TabManager: ObservableObject {
queue: .main
) { [weak self] _ in
MainActor.assumeIsolated { [weak self] in
self?.sidebarGitMetadataWatchSettingsDidChange()
self?.sidebarMetadataSettingsDidChange()
self?.refreshTabCloseButtonVisibility()
}
})
Expand Down Expand Up @@ -1382,7 +1383,7 @@ class TabManager: ObservableObject {
}

private func updateWorkspacePullRequestPollTimer() {
guard sidebarGitMetadataWatchEnabled else {
guard sidebarPullRequestPollingEnabled else {
workspacePullRequestPollTimer?.cancel()
workspacePullRequestPollTimer = nil
return
Expand Down Expand Up @@ -1468,6 +1469,15 @@ class TabManager: ObservableObject {
SidebarWorkspaceDetailDefaults.watchGitStatusValue(defaults: .standard)
}

private var sidebarPullRequestPollingEnabled: Bool {
SidebarWorkspaceDetailDefaults.pullRequestPollingEnabled(defaults: .standard)
}

private func sidebarMetadataSettingsDidChange() {
sidebarGitMetadataWatchSettingsDidChange()
sidebarPullRequestPollingSettingsDidChange()
}

private func sidebarGitMetadataWatchSettingsDidChange() {
let isEnabled = sidebarGitMetadataWatchEnabled
guard isEnabled != lastSidebarGitMetadataWatchEnabled else {
Expand Down Expand Up @@ -1500,6 +1510,22 @@ class TabManager: ObservableObject {
updateWorkspaceGitMetadataFallbackTimer()
}

private func sidebarPullRequestPollingSettingsDidChange() {
let isEnabled = sidebarPullRequestPollingEnabled
guard isEnabled != lastSidebarPullRequestPollingEnabled else {
return
}
lastSidebarPullRequestPollingEnabled = isEnabled

guard isEnabled else {
resetWorkspacePullRequestRefreshState()
clearAllWorkspaceSidebarPullRequestMetadata()
return
}

refreshTrackedWorkspacePullRequestsIfNeeded(reason: "pullRequestVisibilityEnabled")
}

private func restartWorkspaceGitMetadataWatching(reason: String) {
for workspace in tabs where !workspace.isRemoteWorkspace {
for panelId in workspace.panels.keys {
Expand Down Expand Up @@ -1627,9 +1653,9 @@ class TabManager: ObservableObject {
reason: String,
allowCachedResultsOverride: Bool? = nil
) {
guard sidebarGitMetadataWatchEnabled else {
guard sidebarPullRequestPollingEnabled else {
resetWorkspacePullRequestRefreshState()
clearAllWorkspaceSidebarGitMetadata()
clearAllWorkspaceSidebarPullRequestMetadata()
return
}

Expand Down Expand Up @@ -1815,8 +1841,8 @@ class TabManager: ObservableObject {
reason: String
) {
let key = WorkspaceGitProbeKey(workspaceId: workspaceId, panelId: panelId)
guard sidebarGitMetadataWatchEnabled else {
clearWorkspaceGitMetadata(for: key)
guard sidebarPullRequestPollingEnabled else {
clearWorkspacePullRequestMetadata(for: key)
return
}
let shouldBypassRepoCache = !Self.workspacePullRequestRefreshAllowsRepoCache(reason: reason)
Expand Down Expand Up @@ -1847,6 +1873,12 @@ class TabManager: ObservableObject {
now: Date,
reason: String
) {
guard sidebarPullRequestPollingEnabled else {
resetWorkspacePullRequestRefreshState()
clearAllWorkspaceSidebarPullRequestMetadata()
return
}

for (repoSlug, repoResult) in repoResults {
guard case .success(let cacheEntry, let usedCache, _) = repoResult,
!usedCache else {
Expand Down Expand Up @@ -2049,6 +2081,14 @@ class TabManager: ObservableObject {
updateWorkspacePullRequestPollTimer()
}

private func clearWorkspacePullRequestMetadata(for key: WorkspaceGitProbeKey) {
clearWorkspacePullRequestTracking(for: key)
guard let workspace = tabs.first(where: { $0.id == key.workspaceId }) else {
return
}
workspace.clearPanelPullRequest(panelId: key.panelId)
}

private func resetWorkspacePullRequestRefreshState() {
workspacePullRequestRefreshTask?.cancel()
workspacePullRequestRefreshTask = nil
Expand Down Expand Up @@ -2152,7 +2192,7 @@ class TabManager: ObservableObject {
}

func sidebarGitMetadataWatchSettingsDidChangeForTesting() {
sidebarGitMetadataWatchSettingsDidChange()
sidebarMetadataSettingsDidChange()
}

func trackedWorkspaceGitMetadataPollCandidatePanelIdsForTesting(workspaceId: UUID) -> Set<UUID> {
Expand All @@ -2172,6 +2212,14 @@ class TabManager: ObservableObject {
return Set(probeKeys.map(\.panelId))
}

func workspacePullRequestTrackedPanelIdsForTesting(workspaceId: UUID) -> Set<UUID> {
let probeKeys = Set(workspacePullRequestProbeStateByKey.keys.filter { $0.workspaceId == workspaceId })
.union(workspacePullRequestNextPollAtByKey.keys.filter { $0.workspaceId == workspaceId })
.union(workspacePullRequestLastTerminalStateRefreshAtByKey.keys.filter { $0.workspaceId == workspaceId })
.union(workspacePullRequestTransientFailureCountByKey.keys.filter { $0.workspaceId == workspaceId })
return Set(probeKeys.map(\.panelId))
}

private func trackedWorkspaceGitMetadataPollCandidatePanelIds(
in workspace: Workspace,
activeProbeKeys: Set<WorkspaceGitProbeKey>
Expand Down Expand Up @@ -2827,6 +2875,12 @@ class TabManager: ObservableObject {
}
}

private func clearAllWorkspaceSidebarPullRequestMetadata() {
for workspace in tabs {
workspace.clearSidebarPullRequestMetadata()
}
}

private func clearWorkspaceGitProbes(workspaceId: UUID) {
let keys = Set(workspaceGitProbeStateByKey.keys.filter { $0.workspaceId == workspaceId })
.union(workspaceGitProbeTimersByKey.keys.filter { $0.workspaceId == workspaceId })
Expand Down Expand Up @@ -2860,7 +2914,9 @@ class TabManager: ObservableObject {
if case .inFlight = workspaceGitProbeStateByKey[probeKey] { return true }
return false
}()
let shouldTrackPullRequests = sidebarPullRequestPollingEnabled
let resolvedPullRequest: SidebarPullRequestState? = {
guard shouldTrackPullRequests else { return nil }
guard case .resolved(let pullRequest) = snapshot.pullRequest else { return nil }
return pullRequest
}()
Expand Down Expand Up @@ -2983,24 +3039,31 @@ class TabManager: ObservableObject {

switch snapshot.pullRequest {
case .resolved(let pullRequest):
workspace.updatePanelPullRequest(
panelId: probeKey.panelId,
number: pullRequest.number,
label: pullRequest.label,
url: pullRequest.url,
status: pullRequest.status,
branch: pullRequest.branch,
isStale: false
)
if shouldTrackPullRequests {
workspace.updatePanelPullRequest(
panelId: probeKey.panelId,
number: pullRequest.number,
label: pullRequest.label,
url: pullRequest.url,
status: pullRequest.status,
branch: pullRequest.branch,
isStale: false
)
} else if workspace.panelPullRequests[probeKey.panelId] != nil {
workspace.clearPanelPullRequest(panelId: probeKey.panelId)
}
case .notFound:
if workspace.panelPullRequests[probeKey.panelId] != nil {
workspace.clearPanelPullRequest(panelId: probeKey.panelId)
}
Comment thread
austinywang marked this conversation as resolved.
case .deferred, .unsupportedRepository, .transientFailure:
if !shouldTrackPullRequests, workspace.panelPullRequests[probeKey.panelId] != nil {
workspace.clearPanelPullRequest(panelId: probeKey.panelId)
}
break
}

if snapshot.branch != nil {
if snapshot.branch != nil, shouldTrackPullRequests {
scheduleWorkspacePullRequestRefresh(
workspaceId: probeKey.workspaceId,
panelId: probeKey.panelId,
Expand Down Expand Up @@ -5716,6 +5779,10 @@ class TabManager: ObservableObject {
target: String?
) {
guard let tab = tabs.first(where: { $0.id == tabId }) else { return }
guard sidebarPullRequestPollingEnabled else {
clearWorkspacePullRequestMetadata(for: WorkspaceGitProbeKey(workspaceId: tabId, panelId: surfaceId))
return
}
reconcileLocalPullRequestActionIfPossible(
workspace: tab,
panelId: surfaceId,
Expand Down
4 changes: 2 additions & 2 deletions Sources/TerminalController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19687,7 +19687,7 @@ class TerminalController {
options: parsed.options,
missingPanelUsage: "report_pr <number> <url> [--label=PR] [--state=open|merged|closed] [--branch=<name>] [--tab=X] [--panel=Y]"
) { tab, surfaceId in
guard SidebarWorkspaceDetailDefaults.watchGitStatusValue(defaults: .standard) else {
guard SidebarWorkspaceDetailDefaults.pullRequestPollingEnabled(defaults: .standard) else {
tab.clearPanelPullRequest(panelId: surfaceId)
return
}
Expand Down Expand Up @@ -19924,7 +19924,7 @@ class TerminalController {
options: parsed.options,
missingPanelUsage: "report_pr_action <merge|close|reopen|create|checkout|ready|edit|view> [--target=X] [--tab=X] [--panel=Y]"
) { tab, surfaceId in
guard SidebarWorkspaceDetailDefaults.watchGitStatusValue(defaults: .standard) else {
guard SidebarWorkspaceDetailDefaults.pullRequestPollingEnabled(defaults: .standard) else {
tab.clearPanelPullRequest(panelId: surfaceId)
return
}
Expand Down
3 changes: 3 additions & 0 deletions Sources/TerminalStartupEnvironment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,14 @@ extension TerminalSurface {

static func applyManagedGitWatchEnvironment(
watchGitStatusEnabled: Bool,
showPullRequestsEnabled: Bool = true,
to environment: inout [String: String],
protectedKeys: inout Set<String>
) {
environment["CMUX_NO_GIT_WATCH"] = watchGitStatusEnabled ? "" : "1"
protectedKeys.insert("CMUX_NO_GIT_WATCH")
environment["CMUX_NO_PR_WATCH"] = (watchGitStatusEnabled && showPullRequestsEnabled) ? "" : "1"
protectedKeys.insert("CMUX_NO_PR_WATCH")
}

static func mergedStartupEnvironment(
Expand Down
16 changes: 10 additions & 6 deletions Sources/Workspace.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10936,19 +10936,23 @@ final class Workspace: Identifiable, ObservableObject {
}
}

func clearSidebarPullRequestMetadata() {
if !panelPullRequests.isEmpty {
panelPullRequests.removeAll()
}
if pullRequest != nil {
pullRequest = nil
}
}

func clearSidebarGitMetadata() {
if !panelGitBranches.isEmpty {
panelGitBranches.removeAll()
}
if !panelPullRequests.isEmpty {
panelPullRequests.removeAll()
}
clearSidebarPullRequestMetadata()
if gitBranch != nil {
gitBranch = nil
}
if pullRequest != nil {
pullRequest = nil
}
}

func resetSidebarContext(reason: String = "unspecified") {
Expand Down
Loading
Loading