This commit is contained in:
Mikayla 2023-11-01 11:45:31 -07:00
parent 337a79e35f
commit 1c1b53ecf6
No known key found for this signature in database
5 changed files with 452 additions and 421 deletions

View file

@ -13,7 +13,7 @@ use client2::{
}; };
use gpui2::{ use gpui2::{
AnyElement, AnyView, AppContext, EventEmitter, HighlightStyle, Model, Pixels, Point, Render, AnyElement, AnyView, AppContext, EventEmitter, HighlightStyle, Model, Pixels, Point, Render,
SharedString, Task, View, ViewContext, WeakView, WindowContext, SharedString, Task, View, ViewContext, WeakView, WindowContext, WindowHandle,
}; };
use parking_lot::Mutex; use parking_lot::Mutex;
use project2::{Project, ProjectEntryId, ProjectPath}; use project2::{Project, ProjectEntryId, ProjectPath};
@ -190,7 +190,7 @@ pub trait Item: Render + EventEmitter + Send {
fn deserialize( fn deserialize(
_project: Model<Project>, _project: Model<Project>,
_workspace: WeakView<Workspace>, _workspace: WindowHandle<Workspace>,
_workspace_id: WorkspaceId, _workspace_id: WorkspaceId,
_item_id: ItemId, _item_id: ItemId,
_cx: &mut ViewContext<Pane>, _cx: &mut ViewContext<Pane>,
@ -401,87 +401,86 @@ impl<T: Item> ItemHandle for View<T> {
let pending_update = Arc::new(Mutex::new(None)); let pending_update = Arc::new(Mutex::new(None));
let pending_update_scheduled = Arc::new(AtomicBool::new(false)); let pending_update_scheduled = Arc::new(AtomicBool::new(false));
let mut event_subscription = let event_subscription = Some(cx.subscribe(self, move |workspace, item, event, cx| {
Some(cx.subscribe(self, move |workspace, item, event, cx| { let pane = if let Some(pane) = workspace
let pane = if let Some(pane) = workspace .panes_by_item
.panes_by_item .get(&item.id())
.get(&item.id()) .and_then(|pane| pane.upgrade())
.and_then(|pane| pane.upgrade()) {
{ pane
pane } else {
} else { log::error!("unexpected item event after pane was dropped");
log::error!("unexpected item event after pane was dropped"); return;
return; };
};
if let Some(item) = item.to_followable_item_handle(cx) { if let Some(item) = item.to_followable_item_handle(cx) {
let _is_project_item = item.is_project_item(cx); let _is_project_item = item.is_project_item(cx);
let leader_id = workspace.leader_for_pane(&pane); let leader_id = workspace.leader_for_pane(&pane);
if leader_id.is_some() && item.should_unfollow_on_event(event, cx) { if leader_id.is_some() && item.should_unfollow_on_event(event, cx) {
workspace.unfollow(&pane, cx); workspace.unfollow(&pane, cx);
}
if item.add_event_to_update_proto(event, &mut *pending_update.lock(), cx)
&& !pending_update_scheduled.load(Ordering::SeqCst)
{
pending_update_scheduled.store(true, Ordering::SeqCst);
todo!("replace with on_next_frame?");
// cx.after_window_update({
// let pending_update = pending_update.clone();
// let pending_update_scheduled = pending_update_scheduled.clone();
// move |this, cx| {
// pending_update_scheduled.store(false, Ordering::SeqCst);
// this.update_followers(
// is_project_item,
// proto::update_followers::Variant::UpdateView(
// proto::UpdateView {
// id: item
// .remote_id(&this.app_state.client, cx)
// .map(|id| id.to_proto()),
// variant: pending_update.borrow_mut().take(),
// leader_id,
// },
// ),
// cx,
// );
// }
// });
}
} }
for item_event in T::to_item_events(event).into_iter() { if item.add_event_to_update_proto(event, &mut *pending_update.lock(), cx)
match item_event { && !pending_update_scheduled.load(Ordering::SeqCst)
ItemEvent::CloseItem => { {
pane.update(cx, |pane, cx| { pending_update_scheduled.store(true, Ordering::SeqCst);
pane.close_item_by_id(item.id(), crate::SaveIntent::Close, cx) todo!("replace with on_next_frame?");
}) // cx.after_window_update({
.detach_and_log_err(cx); // let pending_update = pending_update.clone();
return; // let pending_update_scheduled = pending_update_scheduled.clone();
} // move |this, cx| {
// pending_update_scheduled.store(false, Ordering::SeqCst);
// this.update_followers(
// is_project_item,
// proto::update_followers::Variant::UpdateView(
// proto::UpdateView {
// id: item
// .remote_id(&this.app_state.client, cx)
// .map(|id| id.to_proto()),
// variant: pending_update.borrow_mut().take(),
// leader_id,
// },
// ),
// cx,
// );
// }
// });
}
}
ItemEvent::UpdateTab => { for item_event in T::to_item_events(event).into_iter() {
pane.update(cx, |_, cx| { match item_event {
cx.emit(pane::Event::ChangeItemTitle); ItemEvent::CloseItem => {
cx.notify(); pane.update(cx, |pane, cx| {
pane.close_item_by_id(item.id(), crate::SaveIntent::Close, cx)
})
.detach_and_log_err(cx);
return;
}
ItemEvent::UpdateTab => {
pane.update(cx, |_, cx| {
cx.emit(pane::Event::ChangeItemTitle);
cx.notify();
});
}
ItemEvent::Edit => {
let autosave = WorkspaceSettings::get_global(cx).autosave;
if let AutosaveSetting::AfterDelay { milliseconds } = autosave {
let delay = Duration::from_millis(milliseconds);
let item = item.clone();
pending_autosave.fire_new(delay, cx, move |workspace, cx| {
Pane::autosave_item(&item, workspace.project().clone(), cx)
}); });
} }
ItemEvent::Edit => {
let autosave = WorkspaceSettings::get_global(cx).autosave;
if let AutosaveSetting::AfterDelay { milliseconds } = autosave {
let delay = Duration::from_millis(milliseconds);
let item = item.clone();
pending_autosave.fire_new(delay, cx, move |workspace, cx| {
Pane::autosave_item(&item, workspace.project().clone(), cx)
});
}
}
_ => {}
} }
_ => {}
} }
})); }
}));
todo!("observe focus"); todo!("observe focus");
// cx.observe_focus(self, move |workspace, item, focused, cx| { // cx.observe_focus(self, move |workspace, item, focused, cx| {
@ -494,12 +493,12 @@ impl<T: Item> ItemHandle for View<T> {
// }) // })
// .detach(); // .detach();
let item_id = self.id(); // let item_id = self.id();
cx.observe_release(self, move |workspace, _, _| { // cx.observe_release(self, move |workspace, _, _| {
workspace.panes_by_item.remove(&item_id); // workspace.panes_by_item.remove(&item_id);
event_subscription.take(); // event_subscription.take();
}) // })
.detach(); // .detach();
} }
cx.defer(|workspace, cx| { cx.defer(|workspace, cx| {

View file

@ -1,21 +1,14 @@
use crate::{ use crate::{Axis, WorkspaceId};
item::ItemHandle, Axis, ItemDeserializers, Member, Pane, PaneAxis, Workspace, WorkspaceId,
};
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use async_recursion::async_recursion;
use db2::sqlez::{ use db2::sqlez::{
bindable::{Bind, Column, StaticColumnCount}, bindable::{Bind, Column, StaticColumnCount},
statement::Statement, statement::Statement,
}; };
use gpui2::{ use gpui2::WindowBounds;
AsyncAppContext, AsyncWindowContext, Model, Task, View, WeakView, WindowBounds, WindowHandle,
};
use project2::Project;
use std::{ use std::{
path::{Path, PathBuf}, path::{Path, PathBuf},
sync::Arc, sync::Arc,
}; };
use util::ResultExt;
use uuid::Uuid; use uuid::Uuid;
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
@ -149,73 +142,75 @@ impl Default for SerializedPaneGroup {
} }
} }
impl SerializedPaneGroup { // impl SerializedPaneGroup {
#[async_recursion(?Send)] // #[async_recursion(?Send)]
pub(crate) async fn deserialize( // pub(crate) async fn deserialize(
self, // self,
project: &Model<Project>, // project: &Model<Project>,
workspace_id: WorkspaceId, // workspace_id: WorkspaceId,
workspace: WindowHandle<Workspace>, // workspace: WeakView<Workspace>,
cx: &mut AsyncAppContext, // cx: &mut AsyncAppContext,
) -> Option<(Member, Option<View<Pane>>, Vec<Option<Box<dyn ItemHandle>>>)> { // ) -> Option<(Member, Option<View<Pane>>, Vec<Option<Box<dyn ItemHandle>>>)> {
match self { // match self {
SerializedPaneGroup::Group { // SerializedPaneGroup::Group {
axis, // axis,
children, // children,
flexes, // flexes,
} => { // } => {
let mut current_active_pane = None; // let mut current_active_pane = None;
let mut members = Vec::new(); // let mut members = Vec::new();
let mut items = Vec::new(); // let mut items = Vec::new();
for child in children { // for child in children {
if let Some((new_member, active_pane, new_items)) = child // if let Some((new_member, active_pane, new_items)) = child
.deserialize(project, workspace_id, workspace, cx) // .deserialize(project, workspace_id, workspace, cx)
.await // .await
{ // {
members.push(new_member); // members.push(new_member);
items.extend(new_items); // items.extend(new_items);
current_active_pane = current_active_pane.or(active_pane); // current_active_pane = current_active_pane.or(active_pane);
} // }
} // }
if members.is_empty() { // if members.is_empty() {
return None; // return None;
} // }
if members.len() == 1 { // if members.len() == 1 {
return Some((members.remove(0), current_active_pane, items)); // return Some((members.remove(0), current_active_pane, items));
} // }
Some(( // Some((
Member::Axis(PaneAxis::load(axis, members, flexes)), // Member::Axis(PaneAxis::load(axis, members, flexes)),
current_active_pane, // current_active_pane,
items, // items,
)) // ))
} // }
SerializedPaneGroup::Pane(serialized_pane) => { // SerializedPaneGroup::Pane(serialized_pane) => {
let pane = workspace // let pane = workspace
.update(cx, |workspace, cx| workspace.add_pane(cx).downgrade()) // .update(cx, |workspace, cx| workspace.add_pane(cx).downgrade())
.log_err()?; // .log_err()?;
let active = serialized_pane.active; // let active = serialized_pane.active;
let new_items = serialized_pane // let new_items = serialized_pane
.deserialize_to(project, &pane, workspace_id, workspace, cx) // .deserialize_to(project, &pane, workspace_id, workspace, cx)
.await // .await
.log_err()?; // .log_err()?;
if pane.update(cx, |pane, _| pane.items_len() != 0).log_err()? { // // todo!();
let pane = pane.upgrade()?; // // if pane.update(cx, |pane, _| pane.items_len() != 0).log_err()? {
Some((Member::Pane(pane.clone()), active.then(|| pane), new_items)) // // let pane = pane.upgrade()?;
} else { // // Some((Member::Pane(pane.clone()), active.then(|| pane), new_items))
let pane = pane.upgrade()?; // // } else {
workspace // // let pane = pane.upgrade()?;
.update(cx, |workspace, cx| workspace.force_remove_pane(&pane, cx)) // // workspace
.log_err()?; // // .update(cx, |workspace, cx| workspace.force_remove_pane(&pane, cx))
None // // .log_err()?;
} // // None
} // // }
} // None
} // }
} // }
// }
// }
#[derive(Debug, PartialEq, Eq, Default, Clone)] #[derive(Debug, PartialEq, Eq, Default, Clone)]
pub struct SerializedPane { pub struct SerializedPane {
@ -228,53 +223,55 @@ impl SerializedPane {
SerializedPane { children, active } SerializedPane { children, active }
} }
pub async fn deserialize_to( // pub async fn deserialize_to(
&self, // &self,
project: &Model<Project>, // _project: &Model<Project>,
pane: &WeakView<Pane>, // _pane: &WeakView<Pane>,
workspace_id: WorkspaceId, // _workspace_id: WorkspaceId,
workspace: WindowHandle<Workspace>, // _workspace: WindowHandle<Workspace>,
cx: &mut AsyncAppContext, // _cx: &mut AsyncAppContext,
) -> Result<Vec<Option<Box<dyn ItemHandle>>>> { // ) -> Result<Vec<Option<Box<dyn ItemHandle>>>> {
let mut items = Vec::new(); // anyhow::bail!("todo!()")
let mut active_item_index = None; // // todo!()
for (index, item) in self.children.iter().enumerate() { // // let mut items = Vec::new();
let project = project.clone(); // // let mut active_item_index = None;
let item_handle = pane // // for (index, item) in self.children.iter().enumerate() {
.update(cx, |_, cx| { // // let project = project.clone();
if let Some(deserializer) = cx.global::<ItemDeserializers>().get(&item.kind) { // // let item_handle = pane
deserializer(project, workspace, workspace_id, item.item_id, cx) // // .update(cx, |_, cx| {
} else { // // if let Some(deserializer) = cx.global::<ItemDeserializers>().get(&item.kind) {
Task::ready(Err(anyhow::anyhow!( // // deserializer(project, workspace, workspace_id, item.item_id, cx)
"Deserializer does not exist for item kind: {}", // // } else {
item.kind // // Task::ready(Err(anyhow::anyhow!(
))) // // "Deserializer does not exist for item kind: {}",
} // // item.kind
})? // // )))
.await // // }
.log_err(); // // })?
// // .await
// // .log_err();
items.push(item_handle.clone()); // // items.push(item_handle.clone());
if let Some(item_handle) = item_handle { // // if let Some(item_handle) = item_handle {
pane.update(cx, |pane, cx| { // // pane.update(cx, |pane, cx| {
pane.add_item(item_handle.clone(), true, true, None, cx); // // pane.add_item(item_handle.clone(), true, true, None, cx);
})?; // // })?;
} // // }
if item.active { // // if item.active {
active_item_index = Some(index); // // active_item_index = Some(index);
} // // }
} // // }
if let Some(active_item_index) = active_item_index { // // if let Some(active_item_index) = active_item_index {
pane.update(cx, |pane, cx| { // // pane.update(cx, |pane, cx| {
pane.activate_item(active_item_index, false, false, cx); // // pane.activate_item(active_item_index, false, false, cx);
})?; // // })?;
} // // }
anyhow::Ok(items) // // anyhow::Ok(items)
} // }
} }
pub type GroupId = i64; pub type GroupId = i64;
@ -288,15 +285,15 @@ pub struct SerializedItem {
pub active: bool, pub active: bool,
} }
impl SerializedItem { // impl SerializedItem {
pub fn new(kind: impl AsRef<str>, item_id: ItemId, active: bool) -> Self { // pub fn new(kind: impl AsRef<str>, item_id: ItemId, active: bool) -> Self {
Self { // Self {
kind: Arc::from(kind.as_ref()), // kind: Arc::from(kind.as_ref()),
item_id, // item_id,
active, // active,
} // }
} // }
} // }
#[cfg(test)] #[cfg(test)]
impl Default for SerializedItem { impl Default for SerializedItem {

View file

@ -25,16 +25,16 @@ use dock::{Dock, DockPosition, PanelButtons};
use futures::{ use futures::{
channel::{mpsc, oneshot}, channel::{mpsc, oneshot},
future::try_join_all, future::try_join_all,
FutureExt, StreamExt, Future, FutureExt, StreamExt,
}; };
use gpui2::{ use gpui2::{
div, point, size, AnyModel, AnyView, AppContext, AsyncAppContext, AsyncWindowContext, Bounds, div, point, size, AnyModel, AnyView, AppContext, AsyncAppContext, AsyncWindowContext, Bounds,
Context, Div, Entity, EventEmitter, GlobalPixels, MainThread, Model, ModelContext, Point, Context, Div, EventEmitter, GlobalPixels, MainThread, Model, ModelContext, Point, Render, Size,
Render, Size, Subscription, Task, View, ViewContext, VisualContext, WeakView, WindowBounds, Subscription, Task, View, ViewContext, VisualContext, WeakView, WindowBounds, WindowContext,
WindowContext, WindowHandle, WindowOptions, WindowHandle, WindowOptions,
}; };
use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ProjectItem}; use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ProjectItem};
use language2::LanguageRegistry; use language2::{LanguageRegistry, LocalFile};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use node_runtime::NodeRuntime; use node_runtime::NodeRuntime;
use notifications::{simple_message_notification::MessageNotification, NotificationHandle}; use notifications::{simple_message_notification::MessageNotification, NotificationHandle};
@ -412,7 +412,7 @@ pub fn register_deserializable_item<I: Item>(cx: &mut AppContext) {
Arc::from(serialized_item_kind), Arc::from(serialized_item_kind),
|project, workspace, workspace_id, item_id, cx| { |project, workspace, workspace_id, item_id, cx| {
let task = I::deserialize(project, workspace, workspace_id, item_id, cx); let task = I::deserialize(project, workspace, workspace_id, item_id, cx);
cx.spawn_on_main(|cx| async { Ok(Box::new(task.await?) as Box<_>) }) cx.spawn_on_main(|_| async { Ok(Box::new(task.await?) as Box<_>) })
}, },
); );
} }
@ -428,10 +428,10 @@ pub struct AppState {
pub build_window_options: pub build_window_options:
fn(Option<WindowBounds>, Option<Uuid>, &mut MainThread<AppContext>) -> WindowOptions, fn(Option<WindowBounds>, Option<Uuid>, &mut MainThread<AppContext>) -> WindowOptions,
pub initialize_workspace: fn( pub initialize_workspace: fn(
WindowHandle<Workspace>, WeakView<Workspace>,
bool, bool,
Arc<AppState>, Arc<AppState>,
AsyncAppContext, AsyncWindowContext,
) -> Task<anyhow::Result<()>>, ) -> Task<anyhow::Result<()>>,
pub node_runtime: Arc<dyn NodeRuntime>, pub node_runtime: Arc<dyn NodeRuntime>,
} }
@ -568,6 +568,9 @@ pub struct Workspace {
pane_history_timestamp: Arc<AtomicUsize>, pane_history_timestamp: Arc<AtomicUsize>,
} }
trait AssertSend: Send {}
impl AssertSend for WindowHandle<Workspace> {}
// struct ActiveModal { // struct ActiveModal {
// view: Box<dyn ModalHandle>, // view: Box<dyn ModalHandle>,
// previously_focused_view_id: Option<usize>, // previously_focused_view_id: Option<usize>,
@ -700,7 +703,7 @@ impl Workspace {
cx.build_view(|cx| PanelButtons::new(bottom_dock.clone(), weak_handle.clone(), cx)); cx.build_view(|cx| PanelButtons::new(bottom_dock.clone(), weak_handle.clone(), cx));
let right_dock_buttons = let right_dock_buttons =
cx.build_view(|cx| PanelButtons::new(right_dock.clone(), weak_handle.clone(), cx)); cx.build_view(|cx| PanelButtons::new(right_dock.clone(), weak_handle.clone(), cx));
let status_bar = cx.build_view(|cx| { let _status_bar = cx.build_view(|cx| {
let mut status_bar = StatusBar::new(&center_pane.clone(), cx); let mut status_bar = StatusBar::new(&center_pane.clone(), cx);
status_bar.add_left_item(left_dock_buttons, cx); status_bar.add_left_item(left_dock_buttons, cx);
status_bar.add_right_item(right_dock_buttons, cx); status_bar.add_right_item(right_dock_buttons, cx);
@ -791,12 +794,14 @@ impl Workspace {
fn new_local( fn new_local(
abs_paths: Vec<PathBuf>, abs_paths: Vec<PathBuf>,
app_state: Arc<AppState>, app_state: Arc<AppState>,
requesting_window: Option<WindowHandle<Workspace>>, _requesting_window: Option<WindowHandle<Workspace>>,
cx: &mut MainThread<AppContext>, cx: &mut MainThread<AppContext>,
) -> Task<( ) -> Task<
WeakView<Workspace>, anyhow::Result<(
Vec<Option<Result<Box<dyn ItemHandle>, anyhow::Error>>>, WindowHandle<Workspace>,
)> { Vec<Option<Result<Box<dyn ItemHandle>, anyhow::Error>>>,
)>,
> {
let project_handle = Project::local( let project_handle = Project::local(
app_state.client.clone(), app_state.client.clone(),
app_state.node_runtime.clone(), app_state.node_runtime.clone(),
@ -807,7 +812,7 @@ impl Workspace {
); );
cx.spawn_on_main(|mut cx| async move { cx.spawn_on_main(|mut cx| async move {
let serialized_workspace = persistence::DB.workspace_for_roots(&abs_paths.as_slice()); let serialized_workspace: Option<SerializedWorkspace> = None; //persistence::DB.workspace_for_roots(&abs_paths.as_slice());
let paths_to_open = Arc::new(abs_paths); let paths_to_open = Arc::new(abs_paths);
@ -836,14 +841,15 @@ impl Workspace {
DB.next_id().await.unwrap_or(0) DB.next_id().await.unwrap_or(0)
}; };
let window = if let Some(window) = requesting_window { // todo!()
let window = /*if let Some(window) = requesting_window {
cx.update_window(window.into(), |old_workspace, cx| { cx.update_window(window.into(), |old_workspace, cx| {
cx.replace_root_view(|cx| { cx.replace_root_view(|cx| {
Workspace::new(workspace_id, project_handle.clone(), app_state.clone(), cx) Workspace::new(workspace_id, project_handle.clone(), app_state.clone(), cx)
}); });
}); });
window window
} else { } else */ {
let window_bounds_override = window_bounds_env_override(&cx); let window_bounds_override = window_bounds_env_override(&cx);
let (bounds, display) = if let Some(bounds) = window_bounds_override { let (bounds, display) = if let Some(bounds) = window_bounds_override {
(Some(bounds), None) (Some(bounds), None)
@ -873,23 +879,34 @@ impl Workspace {
// Use the serialized workspace to construct the new window // Use the serialized workspace to construct the new window
let options = let options =
cx.update(|cx| (app_state.build_window_options)(bounds, display, cx))?; cx.update(|cx| (app_state.build_window_options)(bounds, display, cx))?;
cx.open_window(options, |cx| {
cx.open_window(options, {
let app_state = app_state.clone();
let workspace_id = workspace_id.clone();
let project_handle = project_handle.clone();
move |cx| {
cx.build_view(|cx| { cx.build_view(|cx| {
Workspace::new(workspace_id, project_handle.clone(), app_state.clone(), cx) Workspace::new(workspace_id, project_handle, app_state, cx)
}) })
})? }})?
}; };
// todo!() Ask how to do this
let weak_view = window.update(&mut cx, |_, cx| cx.view().downgrade())?;
let async_cx = window.update(&mut cx, |_, cx| cx.to_async())?;
(app_state.initialize_workspace)( (app_state.initialize_workspace)(
window, weak_view,
serialized_workspace.is_some(), serialized_workspace.is_some(),
app_state.clone(), app_state.clone(),
cx.clone(), async_cx,
) )
.await .await
.log_err(); .log_err();
window.update(&mut cx, |_, cx| cx.activate_window()); window
.update(&mut cx, |_, cx| cx.activate_window())
.log_err();
notify_if_database_failed(window, &mut cx); notify_if_database_failed(window, &mut cx);
let opened_items = window let opened_items = window
@ -897,16 +914,16 @@ impl Workspace {
let workspace = cx.view().downgrade(); let workspace = cx.view().downgrade();
open_items( open_items(
serialized_workspace, serialized_workspace,
&workspace, // &workspace,
project_paths, project_paths,
app_state, app_state,
cx, cx,
) )
}) })?
.await .await
.unwrap_or_default(); .unwrap_or_default();
(window, opened_items) Ok((window, opened_items))
}) })
} }
@ -2102,9 +2119,9 @@ impl Workspace {
> { > {
let project = self.project().clone(); let project = self.project().clone();
let project_item = project.update(cx, |project, cx| project.open_path(path, cx)); let project_item = project.update(cx, |project, cx| project.open_path(path, cx));
cx.spawn(|_, cx| async move { cx.spawn(|_, mut cx| async move {
let (project_entry_id, project_item) = project_item.await?; let (project_entry_id, project_item) = project_item.await?;
let build_item = cx.update(|cx| { let build_item = cx.update(|_, cx| {
cx.default_global::<ProjectItemBuilders>() cx.default_global::<ProjectItemBuilders>()
.get(&project_item.type_id()) .get(&project_item.type_id())
.ok_or_else(|| anyhow!("no item builder for project item")) .ok_or_else(|| anyhow!("no item builder for project item"))
@ -2747,7 +2764,7 @@ impl Workspace {
title.push_str(""); title.push_str("");
} }
todo!() // todo!()
// cx.set_window_title(&title); // cx.set_window_title(&title);
} }
@ -3372,122 +3389,126 @@ impl Workspace {
cx: &mut ViewContext<Workspace>, cx: &mut ViewContext<Workspace>,
) -> Task<Result<Vec<Option<Box<dyn ItemHandle>>>>> { ) -> Task<Result<Vec<Option<Box<dyn ItemHandle>>>>> {
cx.spawn(|workspace, mut cx| async move { cx.spawn(|workspace, mut cx| async move {
let (project, old_center_pane) = workspace.update(&mut cx, |workspace, _| { // let (project, old_center_pane) = workspace.update(&mut cx, |workspace, _| {
( // (
workspace.project().clone(), // workspace.project().clone(),
workspace.last_active_center_pane.clone(), // workspace.last_active_center_pane.clone(),
) // )
})?; // })?;
let mut center_group = None; // // let mut center_group: Option = None;
let mut center_items = None; // // let mut center_items: Option<Vec<Option<Box<dyn ItemHandle>>>> = None;
// Traverse the splits tree and add to things
if let Some((group, active_pane, items)) = serialized_workspace
.center_group
.deserialize(&project, serialized_workspace.id, workspace, &mut cx)
.await
{
center_items = Some(items);
center_group = Some((group, active_pane))
}
let mut items_by_project_path = cx.update(|cx| { // // todo!()
center_items // // // Traverse the splits tree and add to things
.unwrap_or_default() // if let Some((group, active_pane, items)) = serialized_workspace
.into_iter() // .center_group
.filter_map(|item| { // .deserialize(&project, serialized_workspace.id, workspace, &mut cx)
let item = item?; // .await
let project_path = item.project_path(cx)?; // {
Some((project_path, item)) // center_items = Some(items);
}) // center_group = Some((group, active_pane))
.collect::<HashMap<_, _>>() // }
})?;
let opened_items = paths_to_open // let mut items_by_project_path = cx.update(|_, cx| {
.into_iter() // center_items
.map(|path_to_open| { // .unwrap_or_default()
path_to_open // .into_iter()
.and_then(|path_to_open| items_by_project_path.remove(&path_to_open)) // .filter_map(|item| {
}) // let item = item?;
.collect::<Vec<_>>(); // let project_path = item.project_path(cx)?;
// Some((project_path, item))
// })
// .collect::<HashMap<_, _>>()
// })?;
// Remove old panes from workspace panes list // let opened_items = paths_to_open
workspace.update(&mut cx, |workspace, cx| { // .into_iter()
if let Some((center_group, active_pane)) = center_group { // .map(|path_to_open| {
workspace.remove_panes(workspace.center.root.clone(), cx); // path_to_open
// .and_then(|path_to_open| items_by_project_path.remove(&path_to_open))
// })
// .collect::<Vec<_>>();
// Swap workspace center group // todo!()
workspace.center = PaneGroup::with_root(center_group); // // Remove old panes from workspace panes list
// workspace.update(&mut cx, |workspace, cx| {
// if let Some((center_group, active_pane)) = center_group {
// workspace.remove_panes(workspace.center.root.clone(), cx);
// Change the focus to the workspace first so that we retrigger focus in on the pane. // // Swap workspace center group
cx.focus_self(); // workspace.center = PaneGroup::with_root(center_group);
if let Some(active_pane) = active_pane { // // Change the focus to the workspace first so that we retrigger focus in on the pane.
cx.focus(&active_pane); // cx.focus_self();
} else {
cx.focus(workspace.panes.last().unwrap());
}
} else {
let old_center_handle = old_center_pane.and_then(|weak| weak.upgrade());
if let Some(old_center_handle) = old_center_handle {
cx.focus(&old_center_handle)
} else {
cx.focus_self()
}
}
let docks = serialized_workspace.docks; // if let Some(active_pane) = active_pane {
workspace.left_dock.update(cx, |dock, cx| { // cx.focus(&active_pane);
dock.set_open(docks.left.visible, cx); // } else {
if let Some(active_panel) = docks.left.active_panel { // cx.focus(workspace.panes.last().unwrap());
if let Some(ix) = dock.panel_index_for_ui_name(&active_panel, cx) { // }
dock.activate_panel(ix, cx); // } else {
} // let old_center_handle = old_center_pane.and_then(|weak| weak.upgrade());
} // if let Some(old_center_handle) = old_center_handle {
dock.active_panel() // cx.focus(&old_center_handle)
.map(|panel| panel.set_zoomed(docks.left.zoom, cx)); // } else {
if docks.left.visible && docks.left.zoom { // cx.focus_self()
cx.focus_self() // }
} // }
});
// TODO: I think the bug is that setting zoom or active undoes the bottom zoom or something
workspace.right_dock.update(cx, |dock, cx| {
dock.set_open(docks.right.visible, cx);
if let Some(active_panel) = docks.right.active_panel {
if let Some(ix) = dock.panel_index_for_ui_name(&active_panel, cx) {
dock.activate_panel(ix, cx);
}
}
dock.active_panel()
.map(|panel| panel.set_zoomed(docks.right.zoom, cx));
if docks.right.visible && docks.right.zoom { // let docks = serialized_workspace.docks;
cx.focus_self() // workspace.left_dock.update(cx, |dock, cx| {
} // dock.set_open(docks.left.visible, cx);
}); // if let Some(active_panel) = docks.left.active_panel {
workspace.bottom_dock.update(cx, |dock, cx| { // if let Some(ix) = dock.panel_index_for_ui_name(&active_panel, cx) {
dock.set_open(docks.bottom.visible, cx); // dock.activate_panel(ix, cx);
if let Some(active_panel) = docks.bottom.active_panel { // }
if let Some(ix) = dock.panel_index_for_ui_name(&active_panel, cx) { // }
dock.activate_panel(ix, cx); // dock.active_panel()
} // .map(|panel| panel.set_zoomed(docks.left.zoom, cx));
} // if docks.left.visible && docks.left.zoom {
// cx.focus_self()
// }
// });
// // TODO: I think the bug is that setting zoom or active undoes the bottom zoom or something
// workspace.right_dock.update(cx, |dock, cx| {
// dock.set_open(docks.right.visible, cx);
// if let Some(active_panel) = docks.right.active_panel {
// if let Some(ix) = dock.panel_index_for_ui_name(&active_panel, cx) {
// dock.activate_panel(ix, cx);
// }
// }
// dock.active_panel()
// .map(|panel| panel.set_zoomed(docks.right.zoom, cx));
dock.active_panel() // if docks.right.visible && docks.right.zoom {
.map(|panel| panel.set_zoomed(docks.bottom.zoom, cx)); // cx.focus_self()
// }
// });
// workspace.bottom_dock.update(cx, |dock, cx| {
// dock.set_open(docks.bottom.visible, cx);
// if let Some(active_panel) = docks.bottom.active_panel {
// if let Some(ix) = dock.panel_index_for_ui_name(&active_panel, cx) {
// dock.activate_panel(ix, cx);
// }
// }
if docks.bottom.visible && docks.bottom.zoom { // dock.active_panel()
cx.focus_self() // .map(|panel| panel.set_zoomed(docks.bottom.zoom, cx));
}
});
cx.notify(); // if docks.bottom.visible && docks.bottom.zoom {
})?; // cx.focus_self()
// }
// });
// cx.notify();
// })?;
// Serialize ourself to make sure our timestamps and any pane / item changes are replicated // Serialize ourself to make sure our timestamps and any pane / item changes are replicated
workspace.update(&mut cx, |workspace, cx| workspace.serialize_workspace(cx))?; // workspace.update(&mut cx, |workspace, cx| workspace.serialize_workspace(cx))?;
Ok(opened_items) // Ok(opened_items)
anyhow::bail!("todo")
}) })
} }
@ -3558,49 +3579,50 @@ fn window_bounds_env_override(cx: &MainThread<AsyncAppContext>) -> Option<Window
}) })
} }
async fn open_items( fn open_items(
serialized_workspace: Option<SerializedWorkspace>, _serialized_workspace: Option<SerializedWorkspace>,
mut project_paths_to_open: Vec<(PathBuf, Option<ProjectPath>)>, project_paths_to_open: Vec<(PathBuf, Option<ProjectPath>)>,
app_state: Arc<AppState>, app_state: Arc<AppState>,
mut cx: &mut MainThread<ViewContext<'_, Workspace>>, cx: &mut MainThread<ViewContext<'_, Workspace>>,
) -> Result<Vec<Option<Result<Box<dyn ItemHandle>>>>> { ) -> impl Future<Output = Result<Vec<Option<Result<Box<dyn ItemHandle>>>>>> {
let mut opened_items = Vec::with_capacity(project_paths_to_open.len()); let mut opened_items = Vec::with_capacity(project_paths_to_open.len());
if let Some(serialized_workspace) = serialized_workspace { // todo!()
let restored_items = Workspace::load_workspace( // if let Some(serialized_workspace) = serialized_workspace {
serialized_workspace, // let restored_items = Workspace::load_workspace(
project_paths_to_open // serialized_workspace,
.iter() // project_paths_to_open
.map(|(_, project_path)| project_path) // .iter()
.cloned() // .map(|(_, project_path)| project_path)
.collect(), // .cloned()
cx, // .collect(),
) // cx,
.await?; // )
// .await?;
let restored_project_paths = restored_items // let restored_project_paths = restored_items
.iter() // .iter()
.filter_map(|item| item.as_ref()?.project_path(cx)) // .filter_map(|item| item.as_ref()?.project_path(cx))
.collect::<HashSet<_>>(); // .collect::<HashSet<_>>();
for restored_item in restored_items { // for restored_item in restored_items {
opened_items.push(restored_item.map(Ok)); // opened_items.push(restored_item.map(Ok));
} // }
project_paths_to_open // project_paths_to_open
.iter_mut() // .iter_mut()
.for_each(|(_, project_path)| { // .for_each(|(_, project_path)| {
if let Some(project_path_to_open) = project_path { // if let Some(project_path_to_open) = project_path {
if restored_project_paths.contains(project_path_to_open) { // if restored_project_paths.contains(project_path_to_open) {
*project_path = None; // *project_path = None;
} // }
} // }
}); // });
} else { // } else {
for _ in 0..project_paths_to_open.len() { for _ in 0..project_paths_to_open.len() {
opened_items.push(None); opened_items.push(None);
}
} }
// }
assert!(opened_items.len() == project_paths_to_open.len()); assert!(opened_items.len() == project_paths_to_open.len());
let tasks = let tasks =
@ -3629,16 +3651,17 @@ async fn open_items(
}) })
}); });
for maybe_opened_path in futures::future::join_all(tasks.into_iter()) let tasks = tasks.collect::<Vec<_>>();
.await async move {
.into_iter() let tasks = futures::future::join_all(tasks.into_iter());
{ for maybe_opened_path in tasks.await.into_iter() {
if let Some((i, path_open_result)) = maybe_opened_path { if let Some((i, path_open_result)) = maybe_opened_path {
opened_items[i] = Some(path_open_result); opened_items[i] = Some(path_open_result);
}
} }
}
Ok(opened_items) Ok(opened_items)
}
} }
// fn notify_of_new_dock(workspace: &WeakView<Workspace>, cx: &mut AsyncAppContext) { // fn notify_of_new_dock(workspace: &WeakView<Workspace>, cx: &mut AsyncAppContext) {
@ -4102,8 +4125,8 @@ pub async fn activate_workspace_for_project(
continue; continue;
}; };
let predicate = cx let predicate = workspace
.update_window_root(&workspace, |workspace, cx| { .update(cx, |workspace, cx| {
let project = workspace.project.read(cx); let project = workspace.project.read(cx);
if predicate(project, cx) { if predicate(project, cx) {
cx.activate_window(); cx.activate_window();
@ -4326,10 +4349,11 @@ pub fn open_paths(
> { > {
let app_state = app_state.clone(); let app_state = app_state.clone();
let abs_paths = abs_paths.to_vec(); let abs_paths = abs_paths.to_vec();
cx.spawn(move |mut cx| async move { cx.spawn_on_main(move |mut cx| async move {
// Open paths in existing workspace if possible // Open paths in existing workspace if possible
let existing = activate_workspace_for_project(&mut cx, move |project, cx| { let existing = activate_workspace_for_project(&mut cx, {
project.contains_paths(&abs_paths, cx) let abs_paths = abs_paths.clone();
move |project, cx| project.contains_paths(&abs_paths, cx)
}) })
.await; .await;
@ -4343,32 +4367,30 @@ pub fn open_paths(
// )) // ))
todo!() todo!()
} else { } else {
// Ok(cx cx.update(move |cx| {
// .update(|cx| { Workspace::new_local(abs_paths, app_state.clone(), requesting_window, cx)
// Workspace::new_local(abs_paths, app_state.clone(), requesting_window, cx) })?
// }) .await
// .await)
todo!()
} }
}) })
} }
pub fn open_new( pub fn open_new(
app_state: &Arc<AppState>, app_state: &Arc<AppState>,
cx: &mut AppContext, cx: &mut MainThread<AppContext>,
init: impl FnOnce(&mut Workspace, &mut ViewContext<Workspace>) + 'static, init: impl FnOnce(&mut Workspace, &mut ViewContext<Workspace>) + 'static + Send,
) -> Task<()> { ) -> Task<()> {
let task = Workspace::new_local(Vec::new(), app_state.clone(), None, cx); let task = Workspace::new_local(Vec::new(), app_state.clone(), None, cx);
cx.spawn(|mut cx| async move { cx.spawn_on_main(|mut cx| async move {
let (workspace, opened_paths) = task.await; if let Some((workspace, opened_paths)) = task.await.log_err() {
workspace
workspace .update(&mut cx, |workspace, cx| {
.update(&mut cx, |workspace, cx| { if opened_paths.is_empty() {
if opened_paths.is_empty() { init(workspace, cx)
init(workspace, cx) }
} })
}) .log_err();
.log_err(); }
}) })
} }

View file

@ -12,7 +12,7 @@ use client2::UserStore;
use db2::kvp::KEY_VALUE_STORE; use db2::kvp::KEY_VALUE_STORE;
use fs2::RealFs; use fs2::RealFs;
use futures::{channel::mpsc, SinkExt, StreamExt}; use futures::{channel::mpsc, SinkExt, StreamExt};
use gpui2::{Action, App, AppContext, AsyncAppContext, Context, SemanticVersion, Task}; use gpui2::{Action, App, AppContext, AsyncAppContext, Context, MainThread, SemanticVersion, Task};
use isahc::{prelude::Configurable, Request}; use isahc::{prelude::Configurable, Request};
use language2::LanguageRegistry; use language2::LanguageRegistry;
use log::LevelFilter; use log::LevelFilter;
@ -24,7 +24,7 @@ use settings2::{
default_settings, handle_settings_file_changes, watch_config_file, Settings, SettingsStore, default_settings, handle_settings_file_changes, watch_config_file, Settings, SettingsStore,
}; };
use simplelog::ConfigBuilder; use simplelog::ConfigBuilder;
use smol::process::Command; use smol::{future::FutureExt, process::Command};
use std::{ use std::{
env, env,
ffi::OsStr, ffi::OsStr,
@ -40,6 +40,7 @@ use std::{
time::{SystemTime, UNIX_EPOCH}, time::{SystemTime, UNIX_EPOCH},
}; };
use util::{ use util::{
async_maybe,
channel::{parse_zed_link, ReleaseChannel, RELEASE_CHANNEL}, channel::{parse_zed_link, ReleaseChannel, RELEASE_CHANNEL},
http::{self, HttpClient}, http::{self, HttpClient},
paths, ResultExt, paths, ResultExt,
@ -242,7 +243,7 @@ fn main() {
// .detach_and_log_err(cx) // .detach_and_log_err(cx)
} }
Ok(None) | Err(_) => cx Ok(None) | Err(_) => cx
.spawn({ .spawn_on_main({
let app_state = app_state.clone(); let app_state = app_state.clone();
|cx| async move { restore_or_create_workspace(&app_state, cx).await } |cx| async move { restore_or_create_workspace(&app_state, cx).await }
}) })
@ -313,21 +314,33 @@ async fn installation_id() -> Result<String> {
} }
} }
async fn restore_or_create_workspace(app_state: &Arc<AppState>, mut cx: AsyncAppContext) { async fn restore_or_create_workspace(
if let Some(location) = workspace2::last_opened_workspace_paths().await { app_state: &Arc<AppState>,
cx.update(|cx| workspace2::open_paths(location.paths().as_ref(), app_state, None, cx))? mut cx: MainThread<AsyncAppContext>,
.await ) {
.log_err(); async_maybe!({
} else if matches!(KEY_VALUE_STORE.read_kvp(FIRST_OPEN), Ok(None)) { if let Some(location) = workspace2::last_opened_workspace_paths().await {
cx.update(|cx| show_welcome_experience(app_state, cx)); cx.update(|cx| workspace2::open_paths(location.paths().as_ref(), app_state, None, cx))?
} else { .await
cx.update(|cx| { .log_err();
workspace2::open_new(app_state, cx, |workspace, cx| { } else if matches!(KEY_VALUE_STORE.read_kvp("******* THIS IS A BAD KEY PLEASE UNCOMMENT BELOW TO FIX THIS VERY LONG LINE *******"), Ok(None)) {
Editor::new_file(workspace, &Default::default(), cx) // todo!(welcome)
}) //} else if matches!(KEY_VALUE_STORE.read_kvp(FIRST_OPEN), Ok(None)) {
.detach(); //todo!()
}); // cx.update(|cx| show_welcome_experience(app_state, cx));
} } else {
cx.update(|cx| {
workspace2::open_new(app_state, cx, |workspace, cx| {
// todo!(editor)
// Editor::new_file(workspace, &Default::default(), cx)
})
.detach();
})?;
}
anyhow::Ok(())
})
.await
.log_err();
} }
fn init_paths() { fn init_paths() {

View file

@ -7,7 +7,7 @@ pub use assets::*;
use collections::HashMap; use collections::HashMap;
use gpui2::{ use gpui2::{
point, px, AppContext, AsyncAppContext, AsyncWindowContext, MainThread, Point, Task, point, px, AppContext, AsyncAppContext, AsyncWindowContext, MainThread, Point, Task,
TitlebarOptions, WeakView, WindowBounds, WindowKind, WindowOptions, TitlebarOptions, WeakView, WindowBounds, WindowHandle, WindowKind, WindowOptions,
}; };
pub use only_instance::*; pub use only_instance::*;
pub use open_listener::*; pub use open_listener::*;
@ -165,7 +165,7 @@ pub async fn handle_cli_connection(
if paths.is_empty() { if paths.is_empty() {
let (done_tx, done_rx) = oneshot::channel(); let (done_tx, done_rx) = oneshot::channel();
let _subscription = let _subscription =
cx.update_window_root(&workspace, move |_, cx| { workspace.update(&mut cx, move |_, cx| {
cx.on_release(|_, _| { cx.on_release(|_, _| {
let _ = done_tx.send(()); let _ = done_tx.send(());
}) })