@@ -17,7 +17,7 @@ use std::{hash::Hash, ops::Range, path::Path, sync::Arc, u32};
use text::{Point, PointUtf16};
use util::maybe;
-use crate::{Project, ProjectPath, buffer_store::BufferStore, worktree_store::WorktreeStore};
+use crate::{ProjectPath, buffer_store::BufferStore, worktree_store::WorktreeStore};
use super::session::ThreadId;
@@ -130,18 +130,12 @@ mod breakpoints_in_file {
#[derive(Clone)]
struct RemoteBreakpointStore {
upstream_client: AnyProtoClient,
- _upstream_project_id: u64,
-}
-
-#[derive(Clone)]
-struct LocalBreakpointStore {
- worktree_store: Entity<WorktreeStore>,
- buffer_store: Entity<BufferStore>,
+ upstream_project_id: u64,
}
#[derive(Clone)]
enum BreakpointStoreMode {
- Local(LocalBreakpointStore),
+ Local,
Remote(RemoteBreakpointStore),
}
@@ -155,6 +149,8 @@ pub struct ActiveStackFrame {
}
pub struct BreakpointStore {
+ buffer_store: Entity<BufferStore>,
+ worktree_store: Entity<WorktreeStore>,
breakpoints: BTreeMap<Arc<Path>, BreakpointsInFile>,
downstream_client: Option<(AnyProtoClient, u64)>,
active_stack_frame: Option<ActiveStackFrame>,
@@ -170,28 +166,34 @@ impl BreakpointStore {
pub fn local(worktree_store: Entity<WorktreeStore>, buffer_store: Entity<BufferStore>) -> Self {
BreakpointStore {
breakpoints: BTreeMap::new(),
- mode: BreakpointStoreMode::Local(LocalBreakpointStore {
- worktree_store,
- buffer_store,
- }),
+ mode: BreakpointStoreMode::Local,
+ buffer_store,
+ worktree_store,
downstream_client: None,
active_stack_frame: Default::default(),
}
}
- pub(crate) fn remote(upstream_project_id: u64, upstream_client: AnyProtoClient) -> Self {
+ pub(crate) fn remote(
+ upstream_project_id: u64,
+ upstream_client: AnyProtoClient,
+ buffer_store: Entity<BufferStore>,
+ worktree_store: Entity<WorktreeStore>,
+ ) -> Self {
BreakpointStore {
breakpoints: BTreeMap::new(),
mode: BreakpointStoreMode::Remote(RemoteBreakpointStore {
upstream_client,
- _upstream_project_id: upstream_project_id,
+ upstream_project_id,
}),
+ buffer_store,
+ worktree_store,
downstream_client: None,
active_stack_frame: Default::default(),
}
}
- pub(crate) fn shared(&mut self, project_id: u64, downstream_client: AnyProtoClient) {
+ pub fn shared(&mut self, project_id: u64, downstream_client: AnyProtoClient) {
self.downstream_client = Some((downstream_client, project_id));
}
@@ -202,27 +204,31 @@ impl BreakpointStore {
}
async fn handle_breakpoints_for_file(
- this: Entity<Project>,
+ this: Entity<Self>,
message: TypedEnvelope<proto::BreakpointsForFile>,
mut cx: AsyncApp,
) -> Result<()> {
- let breakpoints = cx.update(|cx| this.read(cx).breakpoint_store())?;
if message.payload.breakpoints.is_empty() {
return Ok(());
}
let buffer = this
.update(&mut cx, |this, cx| {
- let path =
- this.project_path_for_absolute_path(message.payload.path.as_ref(), cx)?;
- Some(this.open_buffer(path, cx))
+ let path = this
+ .worktree_store
+ .read(cx)
+ .project_path_for_absolute_path(message.payload.path.as_ref(), cx)?;
+ Some(
+ this.buffer_store
+ .update(cx, |this, cx| this.open_buffer(path, cx)),
+ )
})
.ok()
.flatten()
.context("Invalid project path")?
.await?;
- breakpoints.update(&mut cx, move |this, cx| {
+ this.update(&mut cx, move |this, cx| {
let bps = this
.breakpoints
.entry(Arc::<Path>::from(message.payload.path.as_ref()))
@@ -263,19 +269,20 @@ impl BreakpointStore {
}
async fn handle_toggle_breakpoint(
- this: Entity<Project>,
+ this: Entity<Self>,
message: TypedEnvelope<proto::ToggleBreakpoint>,
mut cx: AsyncApp,
) -> Result<proto::Ack> {
- let breakpoints = this.read_with(&cx, |this, _| this.breakpoint_store())?;
let path = this
.update(&mut cx, |this, cx| {
- this.project_path_for_absolute_path(message.payload.path.as_ref(), cx)
+ this.worktree_store
+ .read(cx)
+ .project_path_for_absolute_path(message.payload.path.as_ref(), cx)
})?
.context("Could not resolve provided abs path")?;
let buffer = this
.update(&mut cx, |this, cx| {
- this.buffer_store().read(cx).get_by_path(&path)
+ this.buffer_store.read(cx).get_by_path(&path)
})?
.context("Could not find buffer for a given path")?;
let breakpoint = message
@@ -292,7 +299,7 @@ impl BreakpointStore {
let breakpoint =
Breakpoint::from_proto(breakpoint).context("Could not deserialize breakpoint")?;
- breakpoints.update(&mut cx, |this, cx| {
+ this.update(&mut cx, |this, cx| {
this.toggle_breakpoint(
buffer,
BreakpointWithPosition {
@@ -547,7 +554,7 @@ impl BreakpointStore {
.to_proto(&abs_path, &breakpoint.position, &HashMap::default())
{
cx.background_spawn(remote.upstream_client.request(proto::ToggleBreakpoint {
- project_id: remote._upstream_project_id,
+ project_id: remote.upstream_project_id,
path: abs_path.to_str().map(ToOwned::to_owned).unwrap(),
breakpoint: Some(breakpoint),
}))
@@ -775,22 +782,21 @@ impl BreakpointStore {
breakpoints: BTreeMap<Arc<Path>, Vec<SourceBreakpoint>>,
cx: &mut Context<BreakpointStore>,
) -> Task<Result<()>> {
- if let BreakpointStoreMode::Local(mode) = &self.mode {
- let mode = mode.clone();
+ if let BreakpointStoreMode::Local = &self.mode {
+ let worktree_store = self.worktree_store.downgrade();
+ let buffer_store = self.buffer_store.downgrade();
cx.spawn(async move |this, cx| {
let mut new_breakpoints = BTreeMap::default();
for (path, bps) in breakpoints {
if bps.is_empty() {
continue;
}
- let (worktree, relative_path) = mode
- .worktree_store
+ let (worktree, relative_path) = worktree_store
.update(cx, |this, cx| {
this.find_or_create_worktree(&path, false, cx)
})?
.await?;
- let buffer = mode
- .buffer_store
+ let buffer = buffer_store
.update(cx, |this, cx| {
let path = ProjectPath {
worktree_id: worktree.read(cx).id(),
@@ -832,6 +832,7 @@ enum EntitySubscription {
LspStore(PendingEntitySubscription<LspStore>),
SettingsObserver(PendingEntitySubscription<SettingsObserver>),
DapStore(PendingEntitySubscription<DapStore>),
+ BreakpointStore(PendingEntitySubscription<BreakpointStore>),
}
#[derive(Debug, Clone)]
@@ -1378,8 +1379,14 @@ impl Project {
});
cx.subscribe(&lsp_store, Self::on_lsp_store_event).detach();
- let breakpoint_store =
- cx.new(|_| BreakpointStore::remote(REMOTE_SERVER_PROJECT_ID, remote_proto.clone()));
+ let breakpoint_store = cx.new(|_| {
+ BreakpointStore::remote(
+ REMOTE_SERVER_PROJECT_ID,
+ remote_proto.clone(),
+ buffer_store.clone(),
+ worktree_store.clone(),
+ )
+ });
let dap_store = cx.new(|cx| {
DapStore::new_remote(
@@ -1475,6 +1482,7 @@ impl Project {
remote_proto.subscribe_to_entity(REMOTE_SERVER_PROJECT_ID, &this.worktree_store);
remote_proto.subscribe_to_entity(REMOTE_SERVER_PROJECT_ID, &this.lsp_store);
remote_proto.subscribe_to_entity(REMOTE_SERVER_PROJECT_ID, &this.dap_store);
+ remote_proto.subscribe_to_entity(REMOTE_SERVER_PROJECT_ID, &this.breakpoint_store);
remote_proto.subscribe_to_entity(REMOTE_SERVER_PROJECT_ID, &this.settings_observer);
remote_proto.subscribe_to_entity(REMOTE_SERVER_PROJECT_ID, &this.git_store);
remote_proto.subscribe_to_entity(REMOTE_SERVER_PROJECT_ID, &this.agent_server_store);
@@ -1496,6 +1504,7 @@ impl Project {
TaskStore::init(Some(&remote_proto));
ToolchainStore::init(&remote_proto);
DapStore::init(&remote_proto, cx);
+ BreakpointStore::init(&remote_proto);
GitStore::init(&remote_proto);
AgentServerStore::init_remote(&remote_proto);
@@ -1525,6 +1534,9 @@ impl Project {
client.subscribe_to_entity::<SettingsObserver>(remote_id)?,
),
EntitySubscription::DapStore(client.subscribe_to_entity::<DapStore>(remote_id)?),
+ EntitySubscription::BreakpointStore(
+ client.subscribe_to_entity::<BreakpointStore>(remote_id)?,
+ ),
];
let committer = get_git_committer(&cx).await;
let response = client
@@ -1549,7 +1561,7 @@ impl Project {
async fn from_join_project_response(
response: TypedEnvelope<proto::JoinProjectResponse>,
- subscriptions: [EntitySubscription; 7],
+ subscriptions: [EntitySubscription; 8],
client: Arc<Client>,
run_tasks: bool,
user_store: Entity<UserStore>,
@@ -1583,8 +1595,14 @@ impl Project {
let environment =
cx.new(|cx| ProjectEnvironment::new(None, worktree_store.downgrade(), None, true, cx))?;
- let breakpoint_store =
- cx.new(|_| BreakpointStore::remote(remote_id, client.clone().into()))?;
+ let breakpoint_store = cx.new(|_| {
+ BreakpointStore::remote(
+ remote_id,
+ client.clone().into(),
+ buffer_store.clone(),
+ worktree_store.clone(),
+ )
+ })?;
let dap_store = cx.new(|cx| {
DapStore::new_collab(
remote_id,
@@ -1707,7 +1725,7 @@ impl Project {
remote_id,
replica_id,
},
- breakpoint_store,
+ breakpoint_store: breakpoint_store.clone(),
dap_store: dap_store.clone(),
git_store: git_store.clone(),
agent_server_store,
@@ -1766,6 +1784,9 @@ impl Project {
EntitySubscription::DapStore(subscription) => {
subscription.set_entity(&dap_store, &cx)
}
+ EntitySubscription::BreakpointStore(subscription) => {
+ subscription.set_entity(&breakpoint_store, &cx)
+ }
})
.collect::<Vec<_>>();
@@ -4580,11 +4601,9 @@ impl Project {
}
pub fn project_path_for_absolute_path(&self, abs_path: &Path, cx: &App) -> Option<ProjectPath> {
- self.find_worktree(abs_path, cx)
- .map(|(worktree, relative_path)| ProjectPath {
- worktree_id: worktree.read(cx).id(),
- path: relative_path,
- })
+ self.worktree_store
+ .read(cx)
+ .project_path_for_absolute_path(abs_path, cx)
}
pub fn get_workspace_root(&self, project_path: &ProjectPath, cx: &App) -> Option<PathBuf> {
@@ -53,6 +53,7 @@ pub struct HeadlessProject {
pub lsp_store: Entity<LspStore>,
pub task_store: Entity<TaskStore>,
pub dap_store: Entity<DapStore>,
+ pub breakpoint_store: Entity<BreakpointStore>,
pub agent_server_store: Entity<AgentServerStore>,
pub settings_observer: Entity<SettingsObserver>,
pub next_entry_id: Arc<AtomicUsize>,
@@ -131,8 +132,13 @@ impl HeadlessProject {
buffer_store
});
- let breakpoint_store =
- cx.new(|_| BreakpointStore::local(worktree_store.clone(), buffer_store.clone()));
+ let breakpoint_store = cx.new(|_| {
+ let mut breakpoint_store =
+ BreakpointStore::local(worktree_store.clone(), buffer_store.clone());
+ breakpoint_store.shared(REMOTE_SERVER_PROJECT_ID, session.clone());
+
+ breakpoint_store
+ });
let dap_store = cx.new(|cx| {
let mut dap_store = DapStore::new_local(
@@ -258,6 +264,7 @@ impl HeadlessProject {
session.subscribe_to_entity(REMOTE_SERVER_PROJECT_ID, &task_store);
session.subscribe_to_entity(REMOTE_SERVER_PROJECT_ID, &toolchain_store);
session.subscribe_to_entity(REMOTE_SERVER_PROJECT_ID, &dap_store);
+ session.subscribe_to_entity(REMOTE_SERVER_PROJECT_ID, &breakpoint_store);
session.subscribe_to_entity(REMOTE_SERVER_PROJECT_ID, &settings_observer);
session.subscribe_to_entity(REMOTE_SERVER_PROJECT_ID, &git_store);
session.subscribe_to_entity(REMOTE_SERVER_PROJECT_ID, &agent_server_store);
@@ -301,7 +308,7 @@ impl HeadlessProject {
ToolchainStore::init(&session);
DapStore::init(&session, cx);
// todo(debugger): Re init breakpoint store when we set it up for collab
- // BreakpointStore::init(&client);
+ BreakpointStore::init(&session);
GitStore::init(&session);
AgentServerStore::init_headless(&session);
@@ -315,6 +322,7 @@ impl HeadlessProject {
lsp_store,
task_store,
dap_store,
+ breakpoint_store,
agent_server_store,
languages,
extensions,