diff --git a/Cargo.lock b/Cargo.lock index 2ffabd1f9e..ce211b32d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8035,6 +8035,7 @@ dependencies = [ "language", "log", "lsp", + "multi_buffer", "node_runtime", "parking_lot", "pathdiff", diff --git a/crates/project/Cargo.toml b/crates/project/Cargo.toml index 1819cf879f..03bf0dd70d 100644 --- a/crates/project/Cargo.toml +++ b/crates/project/Cargo.toml @@ -72,6 +72,7 @@ text.workspace = true util.workspace = true unicase.workspace = true which.workspace = true +multi_buffer.workspace = true [dev-dependencies] client = { workspace = true, features = ["test-support"] } diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index ce701e1cfa..abb01d6501 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -142,6 +142,8 @@ pub use worktree::{ FS_WATCH_LATENCY, }; +pub use multi_buffer::MultiBuffer; + const MAX_SERVER_REINSTALL_ATTEMPT_COUNT: u64 = 4; const SERVER_REINSTALL_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1); const SERVER_LAUNCHING_BEFORE_SHUTDOWN_TIMEOUT: Duration = Duration::from_secs(5); @@ -183,7 +185,7 @@ pub struct Project { language_server_ids: HashMap<(WorktreeId, LanguageServerName), LanguageServerId>, debug_adapters: HashMap, pub open_breakpoints: Arc>>>, - closed_breakpoints: Option>>>>, + pub closed_breakpoints: Arc>>>, language_server_statuses: BTreeMap, last_formatting_failure: Option, last_workspace_edits_by_language_server: HashMap, @@ -1312,15 +1314,13 @@ impl Project { )) } - pub fn serialize_breakpoints(&self, cx: &ModelContext) -> Vec<(PathBuf, Vec)> { + pub fn serialize_breakpoints(&self, cx: &ModelContext) -> HashMap> { let breakpoint_read_guard = self.open_breakpoints.read(); - let mut result = Vec::new(); + let mut result: HashMap> = Default::default(); for buffer_id in breakpoint_read_guard.keys() { - if let Some(serialize_breakpoints) = - self.serialize_breakpoint_for_buffer_id(&buffer_id, cx) - { - result.push(serialize_breakpoints) + if let Some((key, value)) = self.serialize_breakpoint_for_buffer_id(&buffer_id, cx) { + result.insert(key, value); } } @@ -2222,12 +2222,37 @@ impl Project { cx: &mut ModelContext, ) -> Task, AnyModel)>> { let task = self.open_buffer(path.clone(), cx); - cx.spawn(move |_, cx| async move { + cx.spawn(move |project, mut cx| async move { let buffer = task.await?; - let project_entry_id = buffer.read_with(&cx, |buffer, cx| { - File::from_dyn(buffer.file()).and_then(|file| file.project_entry_id(cx)) + let (project_entry_id, buffer_id) = buffer.read_with(&cx, |buffer, cx| { + ( + File::from_dyn(buffer.file()).and_then(|file| file.project_entry_id(cx)), + buffer.remote_id(), + ) })?; + let multi_buffer = cx.new_model(|cx| MultiBuffer::singleton(buffer.clone(), cx))?; + dbg!("Opening a path", path.path.clone()); + project.update(&mut cx, |project, cx| { + let breakpoint_rows = { project.closed_breakpoints.write().remove(&path) }; + dbg!(&project.closed_breakpoints.read()); + let snapshot = multi_buffer.read(cx).snapshot(cx); + dbg!(&breakpoint_rows); + + if let Some(breakpoint_row) = breakpoint_rows { + let mut write_guard = project.open_breakpoints.write(); + let buffer_breakpoints = write_guard.entry(buffer_id).or_default(); + dbg!(&buffer_breakpoints); + + for row in breakpoint_row { + let position = snapshot.anchor_at(Point::new(row as u32, 0), Bias::Left); + + buffer_breakpoints.insert(Breakpoint { position }); + } + } + })?; + + dbg!("Path open successfully"); let buffer: &AnyModel = &buffer; Ok((project_entry_id, buffer.clone())) }) diff --git a/crates/workspace/src/persistence.rs b/crates/workspace/src/persistence.rs index 34dfedb286..d6d8360964 100644 --- a/crates/workspace/src/persistence.rs +++ b/crates/workspace/src/persistence.rs @@ -499,7 +499,7 @@ impl WorkspaceDb { }) .and_then(|mut prepared_statement| (prepared_statement)(workspace_id)); - let breakpoints: Option)>> = match breakpoints { + let breakpoints: HashMap> = match breakpoints { Ok(bp) => { if bp.is_empty() { log::error!("Breakpoints are empty"); @@ -511,15 +511,11 @@ impl WorkspaceDb { map.entry(file_path).or_default().push(breakpoint.position); } - Some( - map.into_iter() - .map(|(file_path, breakpoints)| (file_path, breakpoints)) - .collect(), - ) + map } Err(msg) => { log::error!("{msg}"); - None + Default::default() } }; @@ -654,7 +650,7 @@ impl WorkspaceDb { display, docks, session_id: None, - breakpoints: None, + breakpoints: Default::default(), }) } @@ -669,39 +665,39 @@ impl WorkspaceDb { DELETE FROM panes WHERE workspace_id = ?1;))?(workspace.id) .context("Clearing old panes")?; - if let Some(breakpoints) = workspace.breakpoints { - for (file_path, rows) in breakpoints { - let path = file_path.as_path(); + for (file_path, rows) in workspace.breakpoints { + let path = file_path.as_path(); + + match conn.exec_bound(sql!( + DELETE FROM breakpoints + WHERE workspace_id = ?1 AND file_path = ?2;))?((workspace.id, path)) { + Err(err) => { + log::error!("{err}"); + // continue; + } + Ok(_) => {} + } + + for row in rows { match conn.exec_bound(sql!( - DELETE FROM breakpoints - WHERE workspace_id = ?1 AND file_path = ?2;))?((workspace.id, path)) { + INSERT INTO breakpoints (workspace_id, file_path, breakpoint_location) + VALUES (?1, ?2, ?3);))? + (( + workspace.id, + path, + Breakpoint { position: row }, + )) { Err(err) => { log::error!("{err}"); - // continue; + continue; } Ok(_) => {} } - - for row in rows { - match conn.exec_bound(sql!( - INSERT INTO breakpoints (workspace_id, file_path, breakpoint_location) - VALUES (?1, ?2, ?3);))? - (( - workspace.id, - path, - Breakpoint { position: row }, - )) { - Err(err) => { - log::error!("{err}"); - continue; - } - Ok(_) => {} - } - } } } + match workspace.location { SerializedWorkspaceLocation::Local(local_paths, local_paths_order) => { conn.exec_bound(sql!( @@ -1278,7 +1274,7 @@ mod tests { docks: Default::default(), centered_layout: false, session_id: None, - breakpoints: None, + breakpoints: Default::deafult(), }; let workspace_2 = SerializedWorkspace { @@ -1290,7 +1286,7 @@ mod tests { docks: Default::default(), centered_layout: false, session_id: None, - breakpoints: None, + breakpoints: Default::deafult(), }; db.save_workspace(workspace_1.clone()).await; @@ -1394,7 +1390,7 @@ mod tests { docks: Default::default(), centered_layout: false, session_id: None, - breakpoints: None, + breakpoints: Default::deafult(), }; db.save_workspace(workspace.clone()).await; @@ -1428,7 +1424,7 @@ mod tests { docks: Default::default(), centered_layout: false, session_id: None, - breakpoints: None, + breakpoints: Default::deafult(), }; let mut workspace_2 = SerializedWorkspace { @@ -1440,7 +1436,7 @@ mod tests { docks: Default::default(), centered_layout: false, session_id: None, - breakpoints: None, + breakpoints: Default::deafult(), }; db.save_workspace(workspace_1.clone()).await; @@ -1482,7 +1478,7 @@ mod tests { docks: Default::default(), centered_layout: false, session_id: None, - breakpoints: None, + breakpoints: Default::deafult(), }; db.save_workspace(workspace_3.clone()).await; @@ -1518,7 +1514,7 @@ mod tests { docks: Default::default(), centered_layout: false, session_id: Some("session-id-1".to_owned()), - breakpoints: None, + breakpoints: Default::deafult(), }; let workspace_2 = SerializedWorkspace { @@ -1530,7 +1526,7 @@ mod tests { docks: Default::default(), centered_layout: false, session_id: Some("session-id-1".to_owned()), - breakpoints: None, + breakpoints: Default::deafult(), }; let workspace_3 = SerializedWorkspace { @@ -1542,7 +1538,7 @@ mod tests { docks: Default::default(), centered_layout: false, session_id: Some("session-id-2".to_owned()), - breakpoints: None, + breakpoints: Default::deafult(), }; let workspace_4 = SerializedWorkspace { @@ -1554,7 +1550,7 @@ mod tests { docks: Default::default(), centered_layout: false, session_id: None, - breakpoints: None, + breakpoints: Default::deafult(), }; db.save_workspace(workspace_1.clone()).await; @@ -1592,7 +1588,7 @@ mod tests { docks: Default::default(), centered_layout: false, session_id: None, - breakpoints: None, + breakpoints: Default::deafult(), } } diff --git a/crates/workspace/src/persistence/model.rs b/crates/workspace/src/persistence/model.rs index fcd888004b..1bec39b112 100644 --- a/crates/workspace/src/persistence/model.rs +++ b/crates/workspace/src/persistence/model.rs @@ -5,6 +5,7 @@ use crate::{ use anyhow::{Context, Result}; use async_recursion::async_recursion; use client::DevServerProjectId; +use collections::HashMap; use db::sqlez::{ bindable::{Bind, Column, StaticColumnCount}, statement::Statement, @@ -216,7 +217,7 @@ pub(crate) struct SerializedWorkspace { pub(crate) display: Option, pub(crate) docks: DockStructure, pub(crate) session_id: Option, - pub(crate) breakpoints: Option)>>, + pub(crate) breakpoints: HashMap>, } #[derive(Debug, PartialEq, Clone, Default)] diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index cb28d72c6c..7ba3a7328b 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -1089,6 +1089,7 @@ impl Workspace { let mut worktree_roots: HashSet> = Default::default(); let mut project_paths: Vec<(PathBuf, Option)> = Vec::with_capacity(paths_to_open.len()); + for path in paths_to_open.into_iter() { if let Some((worktree, project_entry)) = cx .update(|cx| { @@ -4035,7 +4036,7 @@ impl Workspace { docks, centered_layout: self.centered_layout, session_id: self.session_id.clone(), - breakpoints: Some(breakpoint_lines), + breakpoints: breakpoint_lines, }; return cx.spawn(|_| persistence::DB.save_workspace(serialized_workspace)); } @@ -4100,6 +4101,8 @@ impl Workspace { let mut center_items = None; // Traverse the splits tree and add to things + // Add unopened breakpoints to project before opening any + // buffer if let Some((group, active_pane, items)) = serialized_workspace .center_group .deserialize( @@ -4133,6 +4136,26 @@ impl Workspace { } })?; + dbg!(&serialized_workspace.breakpoints); + workspace.update(&mut cx, |workspace, cx| { + workspace.project().update(cx, |project, _cx| { + let mut write_guard = project.closed_breakpoints.write(); + + for project_path in items_by_project_path.keys() { + write_guard.insert( + project_path.clone(), + serialized_workspace + .breakpoints + .get(&project_path.path.to_path_buf()) + .unwrap_or(&vec![1]) + .clone(), + ); + } + + dbg!(&write_guard); + }) + })?; + let opened_items = paths_to_open .into_iter() .map(|path_to_open| {