Add focusable view and restore workspace deserialization. Partially restore split and tab functions

This commit is contained in:
Mikayla 2023-11-15 16:36:43 -08:00
parent e905ababcd
commit 78cea69172
No known key found for this signature in database
14 changed files with 173 additions and 110 deletions

View file

@ -1,8 +1,8 @@
use crate::{status_bar::StatusItemView, Axis, Workspace};
use gpui::{
div, px, Action, AnyView, AppContext, Component, Div, Entity, EntityId, EventEmitter,
FocusHandle, ParentComponent, Render, Styled, Subscription, View, ViewContext, WeakView,
WindowContext,
FocusHandle, FocusableView, ParentComponent, Render, Styled, Subscription, View, ViewContext,
WeakView, WindowContext,
};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
@ -17,8 +17,8 @@ pub enum PanelEvent {
Focus,
}
pub trait Panel: Render + EventEmitter<PanelEvent> {
fn persistent_name(&self) -> &'static str;
pub trait Panel: FocusableView + EventEmitter<PanelEvent> {
fn persistent_name() -> &'static str;
fn position(&self, cx: &WindowContext) -> DockPosition;
fn position_is_valid(&self, position: DockPosition) -> bool;
fn set_position(&mut self, position: DockPosition, cx: &mut ViewContext<Self>);
@ -35,12 +35,11 @@ pub trait Panel: Render + EventEmitter<PanelEvent> {
fn set_zoomed(&mut self, _zoomed: bool, _cx: &mut ViewContext<Self>) {}
fn set_active(&mut self, _active: bool, _cx: &mut ViewContext<Self>) {}
fn has_focus(&self, cx: &WindowContext) -> bool;
fn focus_handle(&self, cx: &WindowContext) -> FocusHandle;
}
pub trait PanelHandle: Send + Sync {
fn id(&self) -> EntityId;
fn persistent_name(&self, cx: &WindowContext) -> &'static str;
fn persistent_name(&self) -> &'static str;
fn position(&self, cx: &WindowContext) -> DockPosition;
fn position_is_valid(&self, position: DockPosition, cx: &WindowContext) -> bool;
fn set_position(&self, position: DockPosition, cx: &mut WindowContext);
@ -53,7 +52,7 @@ pub trait PanelHandle: Send + Sync {
fn icon_tooltip(&self, cx: &WindowContext) -> (String, Option<Box<dyn Action>>);
fn icon_label(&self, cx: &WindowContext) -> Option<String>;
fn has_focus(&self, cx: &WindowContext) -> bool;
fn focus_handle(&self, cx: &WindowContext) -> FocusHandle;
fn focus_handle(&self, cx: &AppContext) -> FocusHandle;
fn to_any(&self) -> AnyView;
}
@ -65,8 +64,8 @@ where
self.entity_id()
}
fn persistent_name(&self, cx: &WindowContext) -> &'static str {
self.read(cx).persistent_name()
fn persistent_name(&self) -> &'static str {
T::persistent_name()
}
fn position(&self, cx: &WindowContext) -> DockPosition {
@ -121,7 +120,7 @@ where
self.clone().into()
}
fn focus_handle(&self, cx: &WindowContext) -> FocusHandle {
fn focus_handle(&self, cx: &AppContext) -> FocusHandle {
self.read(cx).focus_handle(cx).clone()
}
}
@ -139,6 +138,14 @@ pub struct Dock {
active_panel_index: usize,
}
impl FocusableView for Dock {
fn focus_handle(&self, cx: &AppContext) -> FocusHandle {
self.panel_entries[self.active_panel_index]
.panel
.focus_handle(cx)
}
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum DockPosition {
@ -220,12 +227,14 @@ impl Dock {
// .position(|entry| entry.panel.as_any().is::<T>())
// }
pub fn panel_index_for_ui_name(&self, _ui_name: &str, _cx: &AppContext) -> Option<usize> {
todo!()
// self.panel_entries.iter().position(|entry| {
// let panel = entry.panel.as_any();
// cx.view_ui_name(panel.window(), panel.id()) == Some(ui_name)
// })
pub fn panel_index_for_persistent_name(
&self,
ui_name: &str,
_cx: &AppContext,
) -> Option<usize> {
self.panel_entries
.iter()
.position(|entry| entry.panel.persistent_name() == ui_name)
}
pub fn active_panel_index(&self) -> usize {
@ -647,7 +656,7 @@ impl Render for PanelButtons {
div().children(
dock.panel_entries
.iter()
.map(|panel| panel.panel.persistent_name(cx)),
.map(|panel| panel.panel.persistent_name()),
)
}
}
@ -698,7 +707,7 @@ pub mod test {
}
impl Panel for TestPanel {
fn persistent_name(&self) -> &'static str {
fn persistent_name() -> &'static str {
"TestPanel"
}
@ -746,8 +755,10 @@ pub mod test {
fn has_focus(&self, _cx: &WindowContext) -> bool {
self.has_focus
}
}
fn focus_handle(&self, cx: &WindowContext) -> FocusHandle {
impl FocusableView for TestPanel {
fn focus_handle(&self, cx: &AppContext) -> FocusHandle {
unimplemented!()
}
}

View file

@ -12,8 +12,9 @@ use client2::{
Client,
};
use gpui::{
AnyElement, AnyView, AppContext, Entity, EntityId, EventEmitter, FocusHandle, HighlightStyle,
Model, Pixels, Point, Render, SharedString, Task, View, ViewContext, WeakView, WindowContext,
AnyElement, AnyView, AppContext, Entity, EntityId, EventEmitter, FocusHandle, FocusableView,
HighlightStyle, Model, Pixels, Point, SharedString, Task, View, ViewContext, WeakView,
WindowContext,
};
use project2::{Project, ProjectEntryId, ProjectPath};
use schemars::JsonSchema;
@ -91,8 +92,7 @@ pub struct BreadcrumbText {
pub highlights: Option<Vec<(Range<usize>, HighlightStyle)>>,
}
pub trait Item: Render + EventEmitter<ItemEvent> {
fn focus_handle(&self) -> FocusHandle;
pub trait Item: FocusableView + EventEmitter<ItemEvent> {
fn deactivated(&mut self, _: &mut ViewContext<Self>) {}
fn workspace_deactivated(&mut self, _: &mut ViewContext<Self>) {}
fn navigate(&mut self, _: Box<dyn Any>, _: &mut ViewContext<Self>) -> bool {
@ -286,7 +286,7 @@ impl dyn ItemHandle {
impl<T: Item> ItemHandle for View<T> {
fn focus_handle(&self, cx: &WindowContext) -> FocusHandle {
self.read(cx).focus_handle()
self.focus_handle(cx)
}
fn subscribe_to_item_events(

View file

@ -8,8 +8,8 @@ use anyhow::Result;
use collections::{HashMap, HashSet, VecDeque};
use gpui::{
actions, prelude::*, register_action, AppContext, AsyncWindowContext, Component, Div, EntityId,
EventEmitter, FocusHandle, Focusable, Model, PromptLevel, Render, Task, View, ViewContext,
VisualContext, WeakView, WindowContext,
EventEmitter, FocusHandle, Focusable, FocusableView, Model, PromptLevel, Render, Task, View,
ViewContext, VisualContext, WeakView, WindowContext,
};
use parking_lot::Mutex;
use project2::{Project, ProjectEntryId, ProjectPath};
@ -1899,6 +1899,12 @@ impl Pane {
}
}
impl FocusableView for Pane {
fn focus_handle(&self, _cx: &AppContext) -> FocusHandle {
self.focus_handle.clone()
}
}
impl Render for Pane {
type Element = Focusable<Self, Div<Self>>;

View file

@ -148,6 +148,10 @@ impl PaneGroup {
self.root.collect_panes(&mut panes);
panes
}
pub(crate) fn first_pane(&self) -> View<Pane> {
self.root.first_pane()
}
}
#[derive(Clone, PartialEq)]
@ -181,6 +185,13 @@ impl Member {
}
}
fn first_pane(&self) -> View<Pane> {
match self {
Member::Axis(axis) => axis.members[0].first_pane(),
Member::Pane(pane) => pane.clone(),
}
}
pub fn render(
&self,
project: &Model<Project>,

View file

@ -38,9 +38,9 @@ use futures::{
use gpui::{
actions, div, point, prelude::*, rems, size, Action, AnyModel, AnyView, AnyWeakView,
AppContext, AsyncAppContext, AsyncWindowContext, Bounds, Component, Div, Entity, EntityId,
EventEmitter, GlobalPixels, KeyContext, Model, ModelContext, ParentComponent, Point, Render,
Size, Styled, Subscription, Task, View, ViewContext, WeakView, WindowBounds, WindowContext,
WindowHandle, WindowOptions,
EventEmitter, FocusHandle, FocusableView, GlobalPixels, KeyContext, Model, ModelContext,
ParentComponent, Point, Render, Size, Styled, Subscription, Task, View, ViewContext, WeakView,
WindowBounds, WindowContext, WindowHandle, WindowOptions,
};
use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ItemSettings, ProjectItem};
use itertools::Itertools;
@ -685,7 +685,7 @@ impl Workspace {
fn new_local(
abs_paths: Vec<PathBuf>,
app_state: Arc<AppState>,
_requesting_window: Option<WindowHandle<Workspace>>,
requesting_window: Option<WindowHandle<Workspace>>,
cx: &mut AppContext,
) -> Task<
anyhow::Result<(
@ -703,7 +703,8 @@ impl Workspace {
);
cx.spawn(|mut cx| async move {
let serialized_workspace: Option<SerializedWorkspace> = None; //persistence::DB.workspace_for_roots(&abs_paths.as_slice());
let serialized_workspace: Option<SerializedWorkspace> =
persistence::DB.workspace_for_roots(&abs_paths.as_slice());
let paths_to_open = Arc::new(abs_paths);
@ -732,15 +733,14 @@ impl Workspace {
DB.next_id().await.unwrap_or(0)
};
// todo!()
let window = /*if let Some(window) = requesting_window {
let window = if let Some(window) = requesting_window {
cx.update_window(window.into(), |old_workspace, cx| {
cx.replace_root_view(|cx| {
Workspace::new(workspace_id, project_handle.clone(), app_state.clone(), cx)
});
});
})?;
window
} else */ {
} else {
let window_bounds_override = window_bounds_env_override(&cx);
let (bounds, display) = if let Some(bounds) = window_bounds_override {
(Some(bounds), None)
@ -754,12 +754,13 @@ impl Workspace {
// Stored bounds are relative to the containing display.
// So convert back to global coordinates if that screen still exists
if let WindowBounds::Fixed(mut window_bounds) = bounds {
let screen =
cx.update(|cx|
cx.displays()
.into_iter()
.find(|display| display.uuid().ok() == Some(serialized_display))
).ok()??;
let screen = cx
.update(|cx| {
cx.displays().into_iter().find(|display| {
display.uuid().ok() == Some(serialized_display)
})
})
.ok()??;
let screen_bounds = screen.bounds();
window_bounds.origin.x += screen_bounds.origin.x;
window_bounds.origin.y += screen_bounds.origin.y;
@ -807,12 +808,7 @@ impl Workspace {
notify_if_database_failed(window, &mut cx);
let opened_items = window
.update(&mut cx, |_workspace, cx| {
open_items(
serialized_workspace,
project_paths,
app_state,
cx,
)
open_items(serialized_workspace, project_paths, app_state, cx)
})?
.await
.unwrap_or_default();
@ -3043,13 +3039,15 @@ impl Workspace {
cx.notify();
}
// fn schedule_serialize(&mut self, cx: &mut ViewContext<Self>) {
// self._schedule_serialize = Some(cx.spawn(|this, cx| async move {
// cx.background().timer(Duration::from_millis(100)).await;
// this.read_with(&cx, |this, cx| this.serialize_workspace(cx))
// .ok();
// }));
// }
fn schedule_serialize(&mut self, cx: &mut ViewContext<Self>) {
self._schedule_serialize = Some(cx.spawn(|this, mut cx| async move {
cx.background_executor()
.timer(Duration::from_millis(100))
.await;
this.update(&mut cx, |this, cx| this.serialize_workspace(cx))
.log_err();
}));
}
fn serialize_workspace(&self, cx: &mut ViewContext<Self>) {
fn serialize_pane_handle(pane_handle: &View<Pane>, cx: &WindowContext) -> SerializedPane {
@ -3105,7 +3103,7 @@ impl Workspace {
let left_visible = left_dock.is_open();
let left_active_panel = left_dock
.visible_panel()
.and_then(|panel| Some(panel.persistent_name(cx).to_string()));
.and_then(|panel| Some(panel.persistent_name().to_string()));
let left_dock_zoom = left_dock
.visible_panel()
.map(|panel| panel.is_zoomed(cx))
@ -3115,7 +3113,7 @@ impl Workspace {
let right_visible = right_dock.is_open();
let right_active_panel = right_dock
.visible_panel()
.and_then(|panel| Some(panel.persistent_name(cx).to_string()));
.and_then(|panel| Some(panel.persistent_name().to_string()));
let right_dock_zoom = right_dock
.visible_panel()
.map(|panel| panel.is_zoomed(cx))
@ -3125,7 +3123,7 @@ impl Workspace {
let bottom_visible = bottom_dock.is_open();
let bottom_active_panel = bottom_dock
.visible_panel()
.and_then(|panel| Some(panel.persistent_name(cx).to_string()));
.and_then(|panel| Some(panel.persistent_name().to_string()));
let bottom_dock_zoom = bottom_dock
.visible_panel()
.map(|panel| panel.is_zoomed(cx))
@ -3231,45 +3229,34 @@ impl Workspace {
// Swap workspace center group
workspace.center = PaneGroup::with_root(center_group);
// Change the focus to the workspace first so that we retrigger focus in on the pane.
// todo!()
// cx.focus_self();
// if let Some(active_pane) = active_pane {
// cx.focus(&active_pane);
// } else {
// cx.focus(workspace.panes.last().unwrap());
// }
} else {
// todo!()
// 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()
// }
workspace.last_active_center_pane = active_pane.as_ref().map(|p| p.downgrade());
if let Some(active_pane) = active_pane {
workspace.active_pane = active_pane;
cx.focus_self();
} else {
workspace.active_pane = workspace.center.first_pane().clone();
}
}
let docks = serialized_workspace.docks;
workspace.left_dock.update(cx, |dock, cx| {
dock.set_open(docks.left.visible, cx);
if let Some(active_panel) = docks.left.active_panel {
if let Some(ix) = dock.panel_index_for_ui_name(&active_panel, cx) {
if let Some(ix) = dock.panel_index_for_persistent_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 {
// todo!()
// 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) {
if let Some(ix) = dock.panel_index_for_persistent_name(&active_panel, cx) {
dock.activate_panel(ix, cx);
}
}
@ -3277,14 +3264,13 @@ impl Workspace {
.map(|panel| panel.set_zoomed(docks.right.zoom, cx));
if docks.right.visible && docks.right.zoom {
// todo!()
// cx.focus_self()
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) {
if let Some(ix) = dock.panel_index_for_persistent_name(&active_panel, cx) {
dock.activate_panel(ix, cx);
}
}
@ -3293,8 +3279,7 @@ impl Workspace {
.map(|panel| panel.set_zoomed(docks.bottom.zoom, cx));
if docks.bottom.visible && docks.bottom.zoom {
// todo!()
// cx.focus_self()
cx.focus_self()
}
});
@ -3699,6 +3684,12 @@ fn notify_if_database_failed(workspace: WindowHandle<Workspace>, cx: &mut AsyncA
impl EventEmitter<Event> for Workspace {}
impl FocusableView for Workspace {
fn focus_handle(&self, cx: &AppContext) -> FocusHandle {
self.active_pane.focus_handle(cx)
}
}
impl Render for Workspace {
type Element = Div<Self>;