Add focusable view and restore workspace deserialization. Partially restore split and tab functions
This commit is contained in:
parent
e905ababcd
commit
78cea69172
14 changed files with 173 additions and 110 deletions
|
@ -41,8 +41,8 @@ use git::diff_hunk_to_display;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
action, actions, div, point, prelude::*, px, relative, rems, size, uniform_list, AnyElement,
|
action, actions, div, point, prelude::*, px, relative, rems, size, uniform_list, AnyElement,
|
||||||
AppContext, AsyncWindowContext, BackgroundExecutor, Bounds, ClipboardItem, Component, Context,
|
AppContext, AsyncWindowContext, BackgroundExecutor, Bounds, ClipboardItem, Component, Context,
|
||||||
EventEmitter, FocusHandle, FontFeatures, FontStyle, FontWeight, HighlightStyle, Hsla,
|
EventEmitter, FocusHandle, FocusableView, FontFeatures, FontStyle, FontWeight, HighlightStyle,
|
||||||
InputHandler, KeyContext, Model, MouseButton, ParentComponent, Pixels, Render, Styled,
|
Hsla, InputHandler, KeyContext, Model, MouseButton, ParentComponent, Pixels, Render, Styled,
|
||||||
Subscription, Task, TextStyle, UniformListScrollHandle, View, ViewContext, VisualContext,
|
Subscription, Task, TextStyle, UniformListScrollHandle, View, ViewContext, VisualContext,
|
||||||
WeakView, WindowContext,
|
WeakView, WindowContext,
|
||||||
};
|
};
|
||||||
|
@ -9367,6 +9367,12 @@ pub struct EditorReleased(pub WeakView<Editor>);
|
||||||
//
|
//
|
||||||
impl EventEmitter<Event> for Editor {}
|
impl EventEmitter<Event> for Editor {}
|
||||||
|
|
||||||
|
impl FocusableView for Editor {
|
||||||
|
fn focus_handle(&self, cx: &AppContext) -> FocusHandle {
|
||||||
|
self.focus_handle.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Render for Editor {
|
impl Render for Editor {
|
||||||
type Element = EditorElement;
|
type Element = EditorElement;
|
||||||
|
|
||||||
|
|
|
@ -527,10 +527,6 @@ fn deserialize_anchor(buffer: &MultiBufferSnapshot, anchor: proto::EditorAnchor)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Item for Editor {
|
impl Item for Editor {
|
||||||
fn focus_handle(&self) -> FocusHandle {
|
|
||||||
self.focus_handle.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn navigate(&mut self, data: Box<dyn std::any::Any>, cx: &mut ViewContext<Self>) -> bool {
|
fn navigate(&mut self, data: Box<dyn std::any::Any>, cx: &mut ViewContext<Self>) -> bool {
|
||||||
todo!();
|
todo!();
|
||||||
// if let Ok(data) = data.downcast::<NavigationData>() {
|
// if let Ok(data) = data.downcast::<NavigationData>() {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
AnyView, AnyWindowHandle, AppCell, AppContext, BackgroundExecutor, Context, ForegroundExecutor,
|
AnyView, AnyWindowHandle, AppCell, AppContext, BackgroundExecutor, Context, FocusableView,
|
||||||
Model, ModelContext, Render, Result, Task, View, ViewContext, VisualContext, WindowContext,
|
ForegroundExecutor, Model, ModelContext, Render, Result, Task, View, ViewContext,
|
||||||
WindowHandle,
|
VisualContext, WindowContext, WindowHandle,
|
||||||
};
|
};
|
||||||
use anyhow::{anyhow, Context as _};
|
use anyhow::{anyhow, Context as _};
|
||||||
use derive_more::{Deref, DerefMut};
|
use derive_more::{Deref, DerefMut};
|
||||||
|
@ -307,4 +307,13 @@ impl VisualContext for AsyncWindowContext {
|
||||||
self.window
|
self.window
|
||||||
.update(self, |_, cx| cx.replace_root_view(build_view))
|
.update(self, |_, cx| cx.replace_root_view(build_view))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn focus_view<V>(&mut self, view: &View<V>) -> Self::Result<()>
|
||||||
|
where
|
||||||
|
V: FocusableView,
|
||||||
|
{
|
||||||
|
self.window.update(self, |_, cx| {
|
||||||
|
view.read(cx).focus_handle(cx).clone().focus(cx);
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,6 +68,7 @@ impl EntityMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Move an entity to the stack.
|
/// Move an entity to the stack.
|
||||||
|
#[track_caller]
|
||||||
pub fn lease<'a, T>(&mut self, model: &'a Model<T>) -> Lease<'a, T> {
|
pub fn lease<'a, T>(&mut self, model: &'a Model<T>) -> Lease<'a, T> {
|
||||||
self.assert_valid_context(model);
|
self.assert_valid_context(model);
|
||||||
let entity = Some(
|
let entity = Some(
|
||||||
|
|
|
@ -560,6 +560,14 @@ impl<'a> VisualContext for VisualTestContext<'a> {
|
||||||
.update(self.cx, |_, cx| cx.replace_root_view(build_view))
|
.update(self.cx, |_, cx| cx.replace_root_view(build_view))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn focus_view<V: crate::FocusableView>(&mut self, view: &View<V>) -> Self::Result<()> {
|
||||||
|
self.window
|
||||||
|
.update(self.cx, |_, cx| {
|
||||||
|
view.read(cx).focus_handle(cx).clone().focus(cx)
|
||||||
|
})
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AnyWindowHandle {
|
impl AnyWindowHandle {
|
||||||
|
|
|
@ -135,6 +135,10 @@ pub trait VisualContext: Context {
|
||||||
) -> Self::Result<View<V>>
|
) -> Self::Result<View<V>>
|
||||||
where
|
where
|
||||||
V: Render;
|
V: Render;
|
||||||
|
|
||||||
|
fn focus_view<V>(&mut self, view: &View<V>) -> Self::Result<()>
|
||||||
|
where
|
||||||
|
V: FocusableView;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Entity<T>: Sealed {
|
pub trait Entity<T>: Sealed {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
private::Sealed, AnyBox, AnyElement, AnyModel, AnyWeakModel, AppContext, AvailableSpace,
|
private::Sealed, AnyBox, AnyElement, AnyModel, AnyWeakModel, AppContext, AvailableSpace,
|
||||||
Bounds, Component, Element, ElementId, Entity, EntityId, Flatten, LayoutId, Model, Pixels,
|
Bounds, Component, Element, ElementId, Entity, EntityId, Flatten, FocusHandle, FocusableView,
|
||||||
Size, ViewContext, VisualContext, WeakModel, WindowContext,
|
LayoutId, Model, Pixels, Size, ViewContext, VisualContext, WeakModel, WindowContext,
|
||||||
};
|
};
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use std::{
|
use std::{
|
||||||
|
@ -73,6 +73,13 @@ impl<V: 'static> View<V> {
|
||||||
component: Some(component),
|
component: Some(component),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn focus_handle(&self, cx: &AppContext) -> FocusHandle
|
||||||
|
where
|
||||||
|
V: FocusableView,
|
||||||
|
{
|
||||||
|
self.read(cx).focus_handle(cx)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V> Clone for View<V> {
|
impl<V> Clone for View<V> {
|
||||||
|
|
|
@ -185,6 +185,10 @@ impl Drop for FocusHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait FocusableView: Render {
|
||||||
|
fn focus_handle(&self, cx: &AppContext) -> FocusHandle;
|
||||||
|
}
|
||||||
|
|
||||||
// Holds the state for a specific window.
|
// Holds the state for a specific window.
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
pub(crate) handle: AnyWindowHandle,
|
pub(crate) handle: AnyWindowHandle,
|
||||||
|
@ -1550,6 +1554,12 @@ impl VisualContext for WindowContext<'_> {
|
||||||
self.window.root_view = Some(view.clone().into());
|
self.window.root_view = Some(view.clone().into());
|
||||||
view
|
view
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn focus_view<V: crate::FocusableView>(&mut self, view: &View<V>) -> Self::Result<()> {
|
||||||
|
self.update_view(view, |view, cx| {
|
||||||
|
view.focus_handle(cx).clone().focus(cx);
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> std::ops::Deref for WindowContext<'a> {
|
impl<'a> std::ops::Deref for WindowContext<'a> {
|
||||||
|
@ -2213,9 +2223,7 @@ impl<'a, V: 'static> ViewContext<'a, V> {
|
||||||
.set_input_handler(Box::new(input_handler));
|
.set_input_handler(Box::new(input_handler));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<V> ViewContext<'_, V> {
|
|
||||||
pub fn emit<Evt>(&mut self, event: Evt)
|
pub fn emit<Evt>(&mut self, event: Evt)
|
||||||
where
|
where
|
||||||
Evt: 'static,
|
Evt: 'static,
|
||||||
|
@ -2228,6 +2236,13 @@ impl<V> ViewContext<'_, V> {
|
||||||
event: Box::new(event),
|
event: Box::new(event),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn focus_self(&mut self)
|
||||||
|
where
|
||||||
|
V: FocusableView,
|
||||||
|
{
|
||||||
|
self.defer(|view, cx| view.focus_handle(cx).focus(cx))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V> Context for ViewContext<'_, V> {
|
impl<V> Context for ViewContext<'_, V> {
|
||||||
|
@ -2303,6 +2318,10 @@ impl<V: 'static> VisualContext for ViewContext<'_, V> {
|
||||||
{
|
{
|
||||||
self.window_cx.replace_root_view(build_view)
|
self.window_cx.replace_root_view(build_view)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn focus_view<W: FocusableView>(&mut self, view: &View<W>) -> Self::Result<()> {
|
||||||
|
self.window_cx.focus_view(view)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, V> std::ops::Deref for ViewContext<'a, V> {
|
impl<'a, V> std::ops::Deref for ViewContext<'a, V> {
|
||||||
|
|
|
@ -9,10 +9,10 @@ use file_associations::FileAssociations;
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
actions, div, px, uniform_list, Action, AppContext, AssetSource, AsyncWindowContext,
|
actions, div, px, uniform_list, Action, AppContext, AssetSource, AsyncWindowContext,
|
||||||
ClipboardItem, Component, Div, EventEmitter, FocusHandle, Focusable, InteractiveComponent,
|
ClipboardItem, Component, Div, EventEmitter, FocusHandle, Focusable, FocusableView,
|
||||||
Model, MouseButton, ParentComponent, Pixels, Point, PromptLevel, Render, Stateful,
|
InteractiveComponent, Model, MouseButton, ParentComponent, Pixels, Point, PromptLevel, Render,
|
||||||
StatefulInteractiveComponent, Styled, Task, UniformListScrollHandle, View, ViewContext,
|
Stateful, StatefulInteractiveComponent, Styled, Task, UniformListScrollHandle, View,
|
||||||
VisualContext as _, WeakView, WindowContext,
|
ViewContext, VisualContext as _, WeakView, WindowContext,
|
||||||
};
|
};
|
||||||
use menu::{Confirm, SelectNext, SelectPrev};
|
use menu::{Confirm, SelectNext, SelectPrev};
|
||||||
use project::{
|
use project::{
|
||||||
|
@ -1524,25 +1524,19 @@ impl workspace::dock::Panel for ProjectPanel {
|
||||||
("Project Panel".into(), Some(Box::new(ToggleFocus)))
|
("Project Panel".into(), Some(Box::new(ToggleFocus)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// fn should_change_position_on_event(event: &Self::Event) -> bool {
|
|
||||||
// matches!(event, Event::DockPositionChanged)
|
|
||||||
// }
|
|
||||||
|
|
||||||
fn has_focus(&self, _: &WindowContext) -> bool {
|
fn has_focus(&self, _: &WindowContext) -> bool {
|
||||||
self.has_focus
|
self.has_focus
|
||||||
}
|
}
|
||||||
|
|
||||||
fn persistent_name(&self) -> &'static str {
|
fn persistent_name() -> &'static str {
|
||||||
"Project Panel"
|
"Project Panel"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn focus_handle(&self, _cx: &WindowContext) -> FocusHandle {
|
|
||||||
self.focus_handle.clone()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// fn is_focus_event(event: &Self::Event) -> bool {
|
impl FocusableView for ProjectPanel {
|
||||||
// matches!(event, Event::Focus)
|
fn focus_handle(&self, _cx: &AppContext) -> FocusHandle {
|
||||||
// }
|
self.focus_handle.clone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClipboardEntry {
|
impl ClipboardEntry {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use crate::{status_bar::StatusItemView, Axis, Workspace};
|
use crate::{status_bar::StatusItemView, Axis, Workspace};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
div, px, Action, AnyView, AppContext, Component, Div, Entity, EntityId, EventEmitter,
|
div, px, Action, AnyView, AppContext, Component, Div, Entity, EntityId, EventEmitter,
|
||||||
FocusHandle, ParentComponent, Render, Styled, Subscription, View, ViewContext, WeakView,
|
FocusHandle, FocusableView, ParentComponent, Render, Styled, Subscription, View, ViewContext,
|
||||||
WindowContext,
|
WeakView, WindowContext,
|
||||||
};
|
};
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -17,8 +17,8 @@ pub enum PanelEvent {
|
||||||
Focus,
|
Focus,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Panel: Render + EventEmitter<PanelEvent> {
|
pub trait Panel: FocusableView + EventEmitter<PanelEvent> {
|
||||||
fn persistent_name(&self) -> &'static str;
|
fn persistent_name() -> &'static str;
|
||||||
fn position(&self, cx: &WindowContext) -> DockPosition;
|
fn position(&self, cx: &WindowContext) -> DockPosition;
|
||||||
fn position_is_valid(&self, position: DockPosition) -> bool;
|
fn position_is_valid(&self, position: DockPosition) -> bool;
|
||||||
fn set_position(&mut self, position: DockPosition, cx: &mut ViewContext<Self>);
|
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_zoomed(&mut self, _zoomed: bool, _cx: &mut ViewContext<Self>) {}
|
||||||
fn set_active(&mut self, _active: bool, _cx: &mut ViewContext<Self>) {}
|
fn set_active(&mut self, _active: bool, _cx: &mut ViewContext<Self>) {}
|
||||||
fn has_focus(&self, cx: &WindowContext) -> bool;
|
fn has_focus(&self, cx: &WindowContext) -> bool;
|
||||||
fn focus_handle(&self, cx: &WindowContext) -> FocusHandle;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PanelHandle: Send + Sync {
|
pub trait PanelHandle: Send + Sync {
|
||||||
fn id(&self) -> EntityId;
|
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(&self, cx: &WindowContext) -> DockPosition;
|
||||||
fn position_is_valid(&self, position: DockPosition, cx: &WindowContext) -> bool;
|
fn position_is_valid(&self, position: DockPosition, cx: &WindowContext) -> bool;
|
||||||
fn set_position(&self, position: DockPosition, cx: &mut WindowContext);
|
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_tooltip(&self, cx: &WindowContext) -> (String, Option<Box<dyn Action>>);
|
||||||
fn icon_label(&self, cx: &WindowContext) -> Option<String>;
|
fn icon_label(&self, cx: &WindowContext) -> Option<String>;
|
||||||
fn has_focus(&self, cx: &WindowContext) -> bool;
|
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;
|
fn to_any(&self) -> AnyView;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,8 +64,8 @@ where
|
||||||
self.entity_id()
|
self.entity_id()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn persistent_name(&self, cx: &WindowContext) -> &'static str {
|
fn persistent_name(&self) -> &'static str {
|
||||||
self.read(cx).persistent_name()
|
T::persistent_name()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn position(&self, cx: &WindowContext) -> DockPosition {
|
fn position(&self, cx: &WindowContext) -> DockPosition {
|
||||||
|
@ -121,7 +120,7 @@ where
|
||||||
self.clone().into()
|
self.clone().into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn focus_handle(&self, cx: &WindowContext) -> FocusHandle {
|
fn focus_handle(&self, cx: &AppContext) -> FocusHandle {
|
||||||
self.read(cx).focus_handle(cx).clone()
|
self.read(cx).focus_handle(cx).clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,6 +138,14 @@ pub struct Dock {
|
||||||
active_panel_index: usize,
|
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)]
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
|
||||||
#[serde(rename_all = "lowercase")]
|
#[serde(rename_all = "lowercase")]
|
||||||
pub enum DockPosition {
|
pub enum DockPosition {
|
||||||
|
@ -220,12 +227,14 @@ impl Dock {
|
||||||
// .position(|entry| entry.panel.as_any().is::<T>())
|
// .position(|entry| entry.panel.as_any().is::<T>())
|
||||||
// }
|
// }
|
||||||
|
|
||||||
pub fn panel_index_for_ui_name(&self, _ui_name: &str, _cx: &AppContext) -> Option<usize> {
|
pub fn panel_index_for_persistent_name(
|
||||||
todo!()
|
&self,
|
||||||
// self.panel_entries.iter().position(|entry| {
|
ui_name: &str,
|
||||||
// let panel = entry.panel.as_any();
|
_cx: &AppContext,
|
||||||
// cx.view_ui_name(panel.window(), panel.id()) == Some(ui_name)
|
) -> Option<usize> {
|
||||||
// })
|
self.panel_entries
|
||||||
|
.iter()
|
||||||
|
.position(|entry| entry.panel.persistent_name() == ui_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn active_panel_index(&self) -> usize {
|
pub fn active_panel_index(&self) -> usize {
|
||||||
|
@ -647,7 +656,7 @@ impl Render for PanelButtons {
|
||||||
div().children(
|
div().children(
|
||||||
dock.panel_entries
|
dock.panel_entries
|
||||||
.iter()
|
.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 {
|
impl Panel for TestPanel {
|
||||||
fn persistent_name(&self) -> &'static str {
|
fn persistent_name() -> &'static str {
|
||||||
"TestPanel"
|
"TestPanel"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -746,8 +755,10 @@ pub mod test {
|
||||||
fn has_focus(&self, _cx: &WindowContext) -> bool {
|
fn has_focus(&self, _cx: &WindowContext) -> bool {
|
||||||
self.has_focus
|
self.has_focus
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn focus_handle(&self, cx: &WindowContext) -> FocusHandle {
|
impl FocusableView for TestPanel {
|
||||||
|
fn focus_handle(&self, cx: &AppContext) -> FocusHandle {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,8 +12,9 @@ use client2::{
|
||||||
Client,
|
Client,
|
||||||
};
|
};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
AnyElement, AnyView, AppContext, Entity, EntityId, EventEmitter, FocusHandle, HighlightStyle,
|
AnyElement, AnyView, AppContext, Entity, EntityId, EventEmitter, FocusHandle, FocusableView,
|
||||||
Model, Pixels, Point, Render, SharedString, Task, View, ViewContext, WeakView, WindowContext,
|
HighlightStyle, Model, Pixels, Point, SharedString, Task, View, ViewContext, WeakView,
|
||||||
|
WindowContext,
|
||||||
};
|
};
|
||||||
use project2::{Project, ProjectEntryId, ProjectPath};
|
use project2::{Project, ProjectEntryId, ProjectPath};
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
|
@ -91,8 +92,7 @@ pub struct BreadcrumbText {
|
||||||
pub highlights: Option<Vec<(Range<usize>, HighlightStyle)>>,
|
pub highlights: Option<Vec<(Range<usize>, HighlightStyle)>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Item: Render + EventEmitter<ItemEvent> {
|
pub trait Item: FocusableView + EventEmitter<ItemEvent> {
|
||||||
fn focus_handle(&self) -> FocusHandle;
|
|
||||||
fn deactivated(&mut self, _: &mut ViewContext<Self>) {}
|
fn deactivated(&mut self, _: &mut ViewContext<Self>) {}
|
||||||
fn workspace_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 {
|
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> {
|
impl<T: Item> ItemHandle for View<T> {
|
||||||
fn focus_handle(&self, cx: &WindowContext) -> FocusHandle {
|
fn focus_handle(&self, cx: &WindowContext) -> FocusHandle {
|
||||||
self.read(cx).focus_handle()
|
self.focus_handle(cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subscribe_to_item_events(
|
fn subscribe_to_item_events(
|
||||||
|
|
|
@ -8,8 +8,8 @@ use anyhow::Result;
|
||||||
use collections::{HashMap, HashSet, VecDeque};
|
use collections::{HashMap, HashSet, VecDeque};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
actions, prelude::*, register_action, AppContext, AsyncWindowContext, Component, Div, EntityId,
|
actions, prelude::*, register_action, AppContext, AsyncWindowContext, Component, Div, EntityId,
|
||||||
EventEmitter, FocusHandle, Focusable, Model, PromptLevel, Render, Task, View, ViewContext,
|
EventEmitter, FocusHandle, Focusable, FocusableView, Model, PromptLevel, Render, Task, View,
|
||||||
VisualContext, WeakView, WindowContext,
|
ViewContext, VisualContext, WeakView, WindowContext,
|
||||||
};
|
};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use project2::{Project, ProjectEntryId, ProjectPath};
|
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 {
|
impl Render for Pane {
|
||||||
type Element = Focusable<Self, Div<Self>>;
|
type Element = Focusable<Self, Div<Self>>;
|
||||||
|
|
||||||
|
|
|
@ -148,6 +148,10 @@ impl PaneGroup {
|
||||||
self.root.collect_panes(&mut panes);
|
self.root.collect_panes(&mut panes);
|
||||||
panes
|
panes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn first_pane(&self) -> View<Pane> {
|
||||||
|
self.root.first_pane()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq)]
|
#[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(
|
pub fn render(
|
||||||
&self,
|
&self,
|
||||||
project: &Model<Project>,
|
project: &Model<Project>,
|
||||||
|
|
|
@ -38,9 +38,9 @@ use futures::{
|
||||||
use gpui::{
|
use gpui::{
|
||||||
actions, div, point, prelude::*, rems, size, Action, AnyModel, AnyView, AnyWeakView,
|
actions, div, point, prelude::*, rems, size, Action, AnyModel, AnyView, AnyWeakView,
|
||||||
AppContext, AsyncAppContext, AsyncWindowContext, Bounds, Component, Div, Entity, EntityId,
|
AppContext, AsyncAppContext, AsyncWindowContext, Bounds, Component, Div, Entity, EntityId,
|
||||||
EventEmitter, GlobalPixels, KeyContext, Model, ModelContext, ParentComponent, Point, Render,
|
EventEmitter, FocusHandle, FocusableView, GlobalPixels, KeyContext, Model, ModelContext,
|
||||||
Size, Styled, Subscription, Task, View, ViewContext, WeakView, WindowBounds, WindowContext,
|
ParentComponent, Point, Render, Size, Styled, Subscription, Task, View, ViewContext, WeakView,
|
||||||
WindowHandle, WindowOptions,
|
WindowBounds, WindowContext, WindowHandle, WindowOptions,
|
||||||
};
|
};
|
||||||
use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ItemSettings, ProjectItem};
|
use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ItemSettings, ProjectItem};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
@ -685,7 +685,7 @@ 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 AppContext,
|
cx: &mut AppContext,
|
||||||
) -> Task<
|
) -> Task<
|
||||||
anyhow::Result<(
|
anyhow::Result<(
|
||||||
|
@ -703,7 +703,8 @@ impl Workspace {
|
||||||
);
|
);
|
||||||
|
|
||||||
cx.spawn(|mut cx| async move {
|
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);
|
let paths_to_open = Arc::new(abs_paths);
|
||||||
|
|
||||||
|
@ -732,15 +733,14 @@ impl Workspace {
|
||||||
DB.next_id().await.unwrap_or(0)
|
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.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)
|
||||||
|
@ -754,12 +754,13 @@ impl Workspace {
|
||||||
// Stored bounds are relative to the containing display.
|
// Stored bounds are relative to the containing display.
|
||||||
// So convert back to global coordinates if that screen still exists
|
// So convert back to global coordinates if that screen still exists
|
||||||
if let WindowBounds::Fixed(mut window_bounds) = bounds {
|
if let WindowBounds::Fixed(mut window_bounds) = bounds {
|
||||||
let screen =
|
let screen = cx
|
||||||
cx.update(|cx|
|
.update(|cx| {
|
||||||
cx.displays()
|
cx.displays().into_iter().find(|display| {
|
||||||
.into_iter()
|
display.uuid().ok() == Some(serialized_display)
|
||||||
.find(|display| display.uuid().ok() == Some(serialized_display))
|
})
|
||||||
).ok()??;
|
})
|
||||||
|
.ok()??;
|
||||||
let screen_bounds = screen.bounds();
|
let screen_bounds = screen.bounds();
|
||||||
window_bounds.origin.x += screen_bounds.origin.x;
|
window_bounds.origin.x += screen_bounds.origin.x;
|
||||||
window_bounds.origin.y += screen_bounds.origin.y;
|
window_bounds.origin.y += screen_bounds.origin.y;
|
||||||
|
@ -807,12 +808,7 @@ impl Workspace {
|
||||||
notify_if_database_failed(window, &mut cx);
|
notify_if_database_failed(window, &mut cx);
|
||||||
let opened_items = window
|
let opened_items = window
|
||||||
.update(&mut cx, |_workspace, cx| {
|
.update(&mut cx, |_workspace, cx| {
|
||||||
open_items(
|
open_items(serialized_workspace, project_paths, app_state, cx)
|
||||||
serialized_workspace,
|
|
||||||
project_paths,
|
|
||||||
app_state,
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
})?
|
})?
|
||||||
.await
|
.await
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
@ -3043,13 +3039,15 @@ impl Workspace {
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
// fn schedule_serialize(&mut self, cx: &mut ViewContext<Self>) {
|
fn schedule_serialize(&mut self, cx: &mut ViewContext<Self>) {
|
||||||
// self._schedule_serialize = Some(cx.spawn(|this, cx| async move {
|
self._schedule_serialize = Some(cx.spawn(|this, mut cx| async move {
|
||||||
// cx.background().timer(Duration::from_millis(100)).await;
|
cx.background_executor()
|
||||||
// this.read_with(&cx, |this, cx| this.serialize_workspace(cx))
|
.timer(Duration::from_millis(100))
|
||||||
// .ok();
|
.await;
|
||||||
// }));
|
this.update(&mut cx, |this, cx| this.serialize_workspace(cx))
|
||||||
// }
|
.log_err();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
fn serialize_workspace(&self, cx: &mut ViewContext<Self>) {
|
fn serialize_workspace(&self, cx: &mut ViewContext<Self>) {
|
||||||
fn serialize_pane_handle(pane_handle: &View<Pane>, cx: &WindowContext) -> SerializedPane {
|
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_visible = left_dock.is_open();
|
||||||
let left_active_panel = left_dock
|
let left_active_panel = left_dock
|
||||||
.visible_panel()
|
.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
|
let left_dock_zoom = left_dock
|
||||||
.visible_panel()
|
.visible_panel()
|
||||||
.map(|panel| panel.is_zoomed(cx))
|
.map(|panel| panel.is_zoomed(cx))
|
||||||
|
@ -3115,7 +3113,7 @@ impl Workspace {
|
||||||
let right_visible = right_dock.is_open();
|
let right_visible = right_dock.is_open();
|
||||||
let right_active_panel = right_dock
|
let right_active_panel = right_dock
|
||||||
.visible_panel()
|
.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
|
let right_dock_zoom = right_dock
|
||||||
.visible_panel()
|
.visible_panel()
|
||||||
.map(|panel| panel.is_zoomed(cx))
|
.map(|panel| panel.is_zoomed(cx))
|
||||||
|
@ -3125,7 +3123,7 @@ impl Workspace {
|
||||||
let bottom_visible = bottom_dock.is_open();
|
let bottom_visible = bottom_dock.is_open();
|
||||||
let bottom_active_panel = bottom_dock
|
let bottom_active_panel = bottom_dock
|
||||||
.visible_panel()
|
.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
|
let bottom_dock_zoom = bottom_dock
|
||||||
.visible_panel()
|
.visible_panel()
|
||||||
.map(|panel| panel.is_zoomed(cx))
|
.map(|panel| panel.is_zoomed(cx))
|
||||||
|
@ -3231,45 +3229,34 @@ impl Workspace {
|
||||||
|
|
||||||
// Swap workspace center group
|
// Swap workspace center group
|
||||||
workspace.center = PaneGroup::with_root(center_group);
|
workspace.center = PaneGroup::with_root(center_group);
|
||||||
|
workspace.last_active_center_pane = active_pane.as_ref().map(|p| p.downgrade());
|
||||||
// Change the focus to the workspace first so that we retrigger focus in on the pane.
|
if let Some(active_pane) = active_pane {
|
||||||
// todo!()
|
workspace.active_pane = active_pane;
|
||||||
// cx.focus_self();
|
cx.focus_self();
|
||||||
// if let Some(active_pane) = active_pane {
|
|
||||||
// cx.focus(&active_pane);
|
|
||||||
// } else {
|
|
||||||
// cx.focus(workspace.panes.last().unwrap());
|
|
||||||
// }
|
|
||||||
} else {
|
} else {
|
||||||
// todo!()
|
workspace.active_pane = workspace.center.first_pane().clone();
|
||||||
// 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;
|
let docks = serialized_workspace.docks;
|
||||||
workspace.left_dock.update(cx, |dock, cx| {
|
workspace.left_dock.update(cx, |dock, cx| {
|
||||||
dock.set_open(docks.left.visible, cx);
|
dock.set_open(docks.left.visible, cx);
|
||||||
if let Some(active_panel) = docks.left.active_panel {
|
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.activate_panel(ix, cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dock.active_panel()
|
dock.active_panel()
|
||||||
.map(|panel| panel.set_zoomed(docks.left.zoom, cx));
|
.map(|panel| panel.set_zoomed(docks.left.zoom, cx));
|
||||||
if docks.left.visible && docks.left.zoom {
|
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
|
// TODO: I think the bug is that setting zoom or active undoes the bottom zoom or something
|
||||||
workspace.right_dock.update(cx, |dock, cx| {
|
workspace.right_dock.update(cx, |dock, cx| {
|
||||||
dock.set_open(docks.right.visible, cx);
|
dock.set_open(docks.right.visible, cx);
|
||||||
if let Some(active_panel) = docks.right.active_panel {
|
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);
|
dock.activate_panel(ix, cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3277,14 +3264,13 @@ impl Workspace {
|
||||||
.map(|panel| panel.set_zoomed(docks.right.zoom, cx));
|
.map(|panel| panel.set_zoomed(docks.right.zoom, cx));
|
||||||
|
|
||||||
if docks.right.visible && docks.right.zoom {
|
if docks.right.visible && docks.right.zoom {
|
||||||
// todo!()
|
cx.focus_self()
|
||||||
// cx.focus_self()
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
workspace.bottom_dock.update(cx, |dock, cx| {
|
workspace.bottom_dock.update(cx, |dock, cx| {
|
||||||
dock.set_open(docks.bottom.visible, cx);
|
dock.set_open(docks.bottom.visible, cx);
|
||||||
if let Some(active_panel) = docks.bottom.active_panel {
|
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);
|
dock.activate_panel(ix, cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3293,8 +3279,7 @@ impl Workspace {
|
||||||
.map(|panel| panel.set_zoomed(docks.bottom.zoom, cx));
|
.map(|panel| panel.set_zoomed(docks.bottom.zoom, cx));
|
||||||
|
|
||||||
if docks.bottom.visible && docks.bottom.zoom {
|
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 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 {
|
impl Render for Workspace {
|
||||||
type Element = Div<Self>;
|
type Element = Div<Self>;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue