Skip to content

Commit a0114f7

Browse files
Caio-Zeclaude
andcommitted
workspace: Treat undeclared active_profile as no-op instead of clear
Preserves a manual settings_profile_selector::Toggle selection when the effective active worktree declares no active_profile, composing cleanly with the picker as a declarative/imperative pair (mirrors theme vs. Theme Selector). Worktrees that declare active_profile still re-assert on every activation hook fire, matching the "project-level default wins on entry" intuition. Previously the (None, Some(_)) match arm called cx.remove_global::<ActiveSettingsProfileName>() on any activation event in an undeclared worktree, which wiped a manual picker selection on e.g. window-sidebar switches. The arm is now folded into a single (None, _) => {} no-op, with an expanded doc comment stating the interaction contract with settings_profile_selector explicitly so the composition is self-documenting in the source. See private/specs/persistent-active-profile.md Decision 3 and Decision 5 (both revised 2026-04-10) for the full rationale and example flows. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent b186395 commit a0114f7

1 file changed

Lines changed: 17 additions & 4 deletions

File tree

crates/workspace/src/workspace.rs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5711,6 +5711,19 @@ impl Workspace {
57115711
/// collaborators who clone a project without the profile defined see
57125712
/// default behavior rather than an error. Idempotent: no-op if the
57135713
/// target equals the current profile.
5714+
///
5715+
/// Interaction with `settings_profile_selector` (the profile picker):
5716+
/// the picker and this function both mutate the runtime global
5717+
/// `ActiveSettingsProfileName`. When the effective worktree declares
5718+
/// an `active_profile`, the declaration wins on every activation
5719+
/// event — any transient picker override is replaced. When the
5720+
/// effective worktree does *not* declare one, this function is a
5721+
/// no-op: a manual picker selection is preserved until the user
5722+
/// moves focus to a worktree that declares its own profile. This
5723+
/// mirrors how `theme` composes with the Theme Selector: declarative
5724+
/// state is a project-level default, imperative picker actions are
5725+
/// overrides that survive until a new declarative value asserts
5726+
/// itself.
57145727
pub(crate) fn apply_local_active_profile(&self, cx: &mut App) {
57155728
let Some(worktree_id) = self.effective_active_worktree_id(cx) else {
57165729
return;
@@ -5730,10 +5743,10 @@ impl Workspace {
57305743
(Some(new_name), _) => {
57315744
cx.set_global(ActiveSettingsProfileName(new_name));
57325745
}
5733-
(None, Some(_)) => {
5734-
cx.remove_global::<ActiveSettingsProfileName>();
5735-
}
5736-
(None, None) => {}
5746+
// Worktree declares no `active_profile`: leave the global
5747+
// alone so a manual picker selection is preserved. See the
5748+
// doc comment above for the declarative/imperative rationale.
5749+
(None, _) => {}
57375750
}
57385751
}
57395752

0 commit comments

Comments
 (0)