agent_ui: Avoid querying `OnboardingUpsell` in prepaint (#49963)

Lukas Wirth created

This hits the sqlite database unnecessarily

Release Notes:

- N/A *or* Added/Fixed/Improved ...

Change summary

crates/acp_thread/src/acp_thread.rs |  2 
crates/agent_ui/src/agent_panel.rs  | 36 +++++++++++++++++++++++++++---
crates/text/src/text.rs             | 10 ++++----
3 files changed, 38 insertions(+), 10 deletions(-)

Detailed changes

crates/acp_thread/src/acp_thread.rs 🔗

@@ -2330,7 +2330,7 @@ impl AcpThread {
                     text_diff(old_text.as_str(), &content)
                         .into_iter()
                         .map(|(range, replacement)| {
-                            (snapshot.anchor_range_between(range), replacement)
+                            (snapshot.anchor_range_around(range), replacement)
                         })
                         .collect::<Vec<_>>()
                 })

crates/agent_ui/src/agent_panel.rs 🔗

@@ -1,4 +1,13 @@
-use std::{ops::Range, path::Path, rc::Rc, sync::Arc, time::Duration};
+use std::{
+    ops::Range,
+    path::Path,
+    rc::Rc,
+    sync::{
+        Arc,
+        atomic::{AtomicBool, Ordering},
+    },
+    time::Duration,
+};
 
 use acp_thread::{AcpThread, AgentSessionInfo, MentionUri};
 use agent::{ContextServerRegistry, SharedThread, ThreadStore};
@@ -241,7 +250,14 @@ pub fn init(cx: &mut App) {
                     window.dispatch_action(workspace::RestoreBanner.boxed_clone(), cx);
                     window.refresh();
                 })
-                .register_action(|_workspace, _: &ResetTrialUpsell, _window, cx| {
+                .register_action(|workspace, _: &ResetTrialUpsell, _window, cx| {
+                    if let Some(panel) = workspace.panel::<AgentPanel>(cx) {
+                        panel.update(cx, |panel, _| {
+                            panel
+                                .on_boarding_upsell_dismissed
+                                .store(false, Ordering::Release);
+                        });
+                    }
                     OnboardingUpsell::set_dismissed(false, cx);
                 })
                 .register_action(|_workspace, _: &ResetTrialEndUpsell, _window, cx| {
@@ -524,6 +540,7 @@ pub struct AgentPanel {
     selected_agent: AgentType,
     show_trust_workspace_message: bool,
     last_configuration_error_telemetry: Option<String>,
+    on_boarding_upsell_dismissed: AtomicBool,
 }
 
 impl AgentPanel {
@@ -743,11 +760,19 @@ impl AgentPanel {
                 .ok();
         });
 
+        let weak_panel = cx.entity().downgrade();
         let onboarding = cx.new(|cx| {
             AgentPanelOnboarding::new(
                 user_store.clone(),
                 client,
-                |_window, cx| {
+                move |_window, cx| {
+                    weak_panel
+                        .update(cx, |panel, _| {
+                            panel
+                                .on_boarding_upsell_dismissed
+                                .store(true, Ordering::Release);
+                        })
+                        .ok();
                     OnboardingUpsell::set_dismissed(true, cx);
                 },
                 cx,
@@ -803,6 +828,7 @@ impl AgentPanel {
             selected_agent: AgentType::default(),
             show_trust_workspace_message: false,
             last_configuration_error_telemetry: None,
+            on_boarding_upsell_dismissed: AtomicBool::new(OnboardingUpsell::dismissed()),
         };
 
         // Initial sync of agent servers from extensions
@@ -2773,7 +2799,7 @@ impl AgentPanel {
     }
 
     fn should_render_onboarding(&self, cx: &mut Context<Self>) -> bool {
-        if OnboardingUpsell::dismissed() {
+        if self.on_boarding_upsell_dismissed.load(Ordering::Acquire) {
             return false;
         }
 
@@ -2786,6 +2812,8 @@ impl AgentPanel {
                 .is_some_and(|date| date < chrono::Utc::now())
         {
             OnboardingUpsell::set_dismissed(true, cx);
+            self.on_boarding_upsell_dismissed
+                .store(true, Ordering::Release);
             return false;
         }
 

crates/text/src/text.rs 🔗

@@ -2403,13 +2403,13 @@ impl BufferSnapshot {
         }
     }
 
-    /// Returns an anchor range for the given input position range that is anchored to the text inbetween.
-    pub fn anchor_range_between<T: ToOffset>(&self, position: Range<T>) -> Range<Anchor> {
-        self.anchor_before(position.start)..self.anchor_after(position.end)
+    /// Returns an anchor range for the given input position range that is anchored to the text in the range.
+    pub fn anchor_range_around<T: ToOffset>(&self, position: Range<T>) -> Range<Anchor> {
+        self.anchor_after(position.start)..self.anchor_before(position.end)
     }
 
-    /// Returns an anchor range for the given input position range that is anchored to the text before the start position and after the end position.
-    pub fn anchor_range_around<T: ToOffset>(&self, position: Range<T>) -> Range<Anchor> {
+    /// Returns an anchor range for the given input position range that is anchored to the text before and after.
+    pub fn anchor_range_between<T: ToOffset>(&self, position: Range<T>) -> Range<Anchor> {
         self.anchor_before(position.start)..self.anchor_after(position.end)
     }