Merge branch 'main' into window_context_2

This commit is contained in:
Antonio Scandurra 2023-04-20 16:01:47 +02:00
commit c52b6328b7
47 changed files with 3046 additions and 1772 deletions

View file

@ -48,7 +48,10 @@ pub trait Item: View {
fn navigate(&mut self, _: Box<dyn Any>, _: &mut ViewContext<Self>) -> bool {
false
}
fn tab_description<'a>(&'a self, _: usize, _: &'a AppContext) -> Option<Cow<'a, str>> {
fn tab_tooltip_text(&self, _: &AppContext) -> Option<Cow<str>> {
None
}
fn tab_description<'a>(&'a self, _: usize, _: &'a AppContext) -> Option<Cow<str>> {
None
}
fn tab_content(
@ -170,7 +173,8 @@ pub trait ItemHandle: 'static + fmt::Debug {
cx: &mut WindowContext,
handler: Box<dyn Fn(ItemEvent, &mut WindowContext)>,
) -> gpui::Subscription;
fn tab_description<'a>(&self, detail: usize, cx: &'a AppContext) -> Option<Cow<'a, str>>;
fn tab_tooltip_text<'a>(&self, cx: &'a AppContext) -> Option<Cow<'a, str>>;
fn tab_description<'a>(&'a self, detail: usize, cx: &'a AppContext) -> Option<Cow<'a, str>>;
fn tab_content(
&self,
detail: Option<usize>,
@ -260,7 +264,11 @@ impl<T: Item> ItemHandle for ViewHandle<T> {
})
}
fn tab_description<'a>(&self, detail: usize, cx: &'a AppContext) -> Option<Cow<'a, str>> {
fn tab_tooltip_text<'a>(&self, cx: &'a AppContext) -> Option<Cow<'a, str>> {
self.read(cx).tab_tooltip_text(cx)
}
fn tab_description<'a>(&'a self, detail: usize, cx: &'a AppContext) -> Option<Cow<'a, str>> {
self.read(cx).tab_description(detail, cx)
}
@ -912,7 +920,7 @@ pub(crate) mod test {
}
impl Item for TestItem {
fn tab_description<'a>(&'a self, detail: usize, _: &'a AppContext) -> Option<Cow<'a, str>> {
fn tab_description(&self, detail: usize, _: &AppContext) -> Option<Cow<str>> {
self.tab_descriptions.as_ref().and_then(|descriptions| {
let description = *descriptions.get(detail).or_else(|| descriptions.last())?;
Some(description.into())

View file

@ -1389,6 +1389,9 @@ impl Pane {
let detail = detail.clone();
let theme = cx.global::<Settings>().theme.clone();
let mut tooltip_theme = theme.tooltip.clone();
tooltip_theme.max_text_width = None;
let tab_tooltip_text = item.tab_tooltip_text(cx).map(|a| a.to_string());
move |mouse_state, cx| {
let tab_style =
@ -1396,39 +1399,56 @@ impl Pane {
let hovered = mouse_state.hovered();
enum Tab {}
MouseEventHandler::<Tab, Pane>::new(ix, cx, |_, cx| {
Self::render_tab::<Pane>(
&item,
pane.clone(),
ix == 0,
detail,
hovered,
tab_style,
cx,
)
})
.on_down(MouseButton::Left, move |_, _, cx| {
cx.dispatch_action(ActivateItem(ix));
})
.on_click(MouseButton::Middle, {
let item = item.clone();
let pane = pane.clone();
move |_, _, cx| {
cx.dispatch_action(CloseItemById {
item_id: item.id(),
pane: pane.clone(),
})
}
})
.on_down(MouseButton::Right, move |e, _, cx| {
let item = item.clone();
cx.dispatch_action(DeployTabContextMenu {
position: e.position,
item_id: item.id(),
pane: pane.clone(),
});
})
.boxed()
let mouse_event_handler =
MouseEventHandler::<Tab, Pane>::new(ix, cx, |_, cx| {
Self::render_tab::<Pane>(
&item,
pane.clone(),
ix == 0,
detail,
hovered,
tab_style,
cx,
)
})
.on_down(MouseButton::Left, move |_, _, cx| {
cx.dispatch_action(ActivateItem(ix));
})
.on_click(MouseButton::Middle, {
let item = item.clone();
let pane = pane.clone();
move |_, _, cx| {
cx.dispatch_action(CloseItemById {
item_id: item.id(),
pane: pane.clone(),
})
}
})
.on_down(
MouseButton::Right,
move |e, _, cx| {
let item = item.clone();
cx.dispatch_action(DeployTabContextMenu {
position: e.position,
item_id: item.id(),
pane: pane.clone(),
});
},
);
if let Some(tab_tooltip_text) = tab_tooltip_text {
return mouse_event_handler
.with_tooltip::<Self>(
ix,
tab_tooltip_text,
None,
tooltip_theme,
cx,
)
.boxed();
}
mouse_event_handler.boxed()
}
});

View file

@ -14,7 +14,10 @@ use gpui::{
};
use settings::Settings;
use smallvec::SmallVec;
use std::sync::{Arc, Weak};
use std::{
borrow::Cow,
sync::{Arc, Weak},
};
pub enum Event {
Close,
@ -94,6 +97,9 @@ impl View for SharedScreen {
}
impl Item for SharedScreen {
fn tab_tooltip_text(&self, _: &AppContext) -> Option<Cow<str>> {
Some(format!("{}'s screen", self.user.github_login).into())
}
fn deactivated(&mut self, cx: &mut ViewContext<Self>) {
if let Some(nav_history) = self.nav_history.as_ref() {
nav_history.push::<()>(None, cx);

View file

@ -70,6 +70,7 @@ impl View for Toolbar {
for (item, position) in &self.items {
match *position {
ToolbarItemLocation::Hidden => {}
ToolbarItemLocation::PrimaryLeft { flex } => {
let left_item = ChildView::new(item.as_any(), cx)
.aligned()
@ -81,6 +82,7 @@ impl View for Toolbar {
primary_left_items.push(left_item.boxed());
}
}
ToolbarItemLocation::PrimaryRight { flex } => {
let right_item = ChildView::new(item.as_any(), cx)
.aligned()
@ -93,6 +95,7 @@ impl View for Toolbar {
primary_right_items.push(right_item.boxed());
}
}
ToolbarItemLocation::Secondary => {
secondary_item = Some(
ChildView::new(item.as_any(), cx)
@ -300,7 +303,10 @@ impl<T: ToolbarItemView> ToolbarItemViewHandle for ViewHandle<T> {
}
fn pane_focus_update(&mut self, pane_focused: bool, cx: &mut WindowContext) {
self.update(cx, |this, cx| this.pane_focus_update(pane_focused, cx));
self.update(cx, |this, cx| {
this.pane_focus_update(pane_focused, cx);
cx.notify();
});
}
}

View file

@ -290,7 +290,7 @@ pub fn init(app_state: Arc<AppState>, cx: &mut AppContext) {
let app_state = Arc::downgrade(&app_state);
move |action: &OpenPaths, cx: &mut AppContext| {
if let Some(app_state) = app_state.upgrade() {
open_paths(&action.paths, &app_state, cx).detach();
open_paths(&action.paths, &app_state, None, cx).detach();
}
}
});
@ -303,15 +303,28 @@ pub fn init(app_state: Arc<AppState>, cx: &mut AppContext) {
}
let app_state = app_state.upgrade()?;
let window_id = cx.window_id();
let action = action.clone();
let close = workspace.prepare_to_close(false, cx);
let is_remote = workspace.project.read(cx).is_remote();
let has_worktree = workspace.project.read(cx).worktrees(cx).next().is_some();
let has_dirty_items = workspace.items(cx).any(|item| item.is_dirty(cx));
let close_task = if is_remote || has_worktree || has_dirty_items {
None
} else {
Some(workspace.prepare_to_close(false, cx))
};
Some(cx.spawn_weak(|_, mut cx| async move {
let can_close = close.await?;
if can_close {
cx.update(|cx| open_paths(&action.paths, &app_state, cx))
.await?;
}
let window_id_to_replace = if let Some(close_task) = close_task {
if !close_task.await? {
return Ok(());
}
Some(window_id)
} else {
None
};
cx.update(|cx| open_paths(&action.paths, &app_state, window_id_to_replace, cx))
.await?;
Ok(())
}))
}
@ -854,6 +867,7 @@ impl Workspace {
fn new_local(
abs_paths: Vec<PathBuf>,
app_state: Arc<AppState>,
requesting_window_id: Option<usize>,
cx: &mut AppContext,
) -> Task<(
ViewHandle<Workspace>,
@ -868,7 +882,8 @@ impl Workspace {
);
cx.spawn(|mut cx| async move {
let serialized_workspace = persistence::DB.workspace_for_roots(&abs_paths.as_slice());
let mut serialized_workspace =
persistence::DB.workspace_for_roots(&abs_paths.as_slice());
let paths_to_open = serialized_workspace
.as_ref()
@ -915,7 +930,7 @@ impl Workspace {
let mut workspace = Workspace::new(
serialized_workspace,
workspace_id,
project_handle,
project_handle.clone(),
app_state.dock_default_item_factory,
app_state.background_actions,
cx,
@ -924,46 +939,54 @@ impl Workspace {
workspace
};
let workspace = {
let (bounds, display) = if let Some(bounds) = window_bounds_override {
(Some(bounds), None)
} else {
serialized_workspace
.as_ref()
.and_then(|serialized_workspace| {
let display = serialized_workspace.display?;
let mut bounds = serialized_workspace.bounds?;
// 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 {
if let Some(screen) = cx.platform().screen_by_id(display) {
let screen_bounds = screen.bounds();
window_bounds.set_origin_x(
window_bounds.origin_x() + screen_bounds.origin_x(),
);
window_bounds.set_origin_y(
window_bounds.origin_y() + screen_bounds.origin_y(),
);
bounds = WindowBounds::Fixed(window_bounds);
} else {
// Screen no longer exists. Return none here.
return None;
}
}
Some((bounds, display))
let workspace = requesting_window_id
.and_then(|window_id| {
cx.update(|cx| {
cx.replace_root_view(window_id, |cx| {
build_workspace(cx, serialized_workspace.take())
})
.unzip()
};
})
})
.unwrap_or_else(|| {
let (bounds, display) = if let Some(bounds) = window_bounds_override {
(Some(bounds), None)
} else {
serialized_workspace
.as_ref()
.and_then(|serialized_workspace| {
let display = serialized_workspace.display?;
let mut bounds = serialized_workspace.bounds?;
// Use the serialized workspace to construct the new window
cx.add_window(
(app_state.build_window_options)(bounds, display, cx.platform().as_ref()),
|cx| build_workspace(cx, serialized_workspace),
)
.1
};
// 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 {
if let Some(screen) = cx.platform().screen_by_id(display) {
let screen_bounds = screen.bounds();
window_bounds.set_origin_x(
window_bounds.origin_x() + screen_bounds.origin_x(),
);
window_bounds.set_origin_y(
window_bounds.origin_y() + screen_bounds.origin_y(),
);
bounds = WindowBounds::Fixed(window_bounds);
} else {
// Screen no longer exists. Return none here.
return None;
}
}
Some((bounds, display))
})
.unzip()
};
// Use the serialized workspace to construct the new window
cx.add_window(
(app_state.build_window_options)(bounds, display, cx.platform().as_ref()),
|cx| build_workspace(cx, serialized_workspace),
)
.1
});
notify_if_database_failed(&workspace, &mut cx);
@ -1056,7 +1079,7 @@ impl Workspace {
if self.project.read(cx).is_local() {
Task::Ready(Some(Ok(callback(self, cx))))
} else {
let task = Self::new_local(Vec::new(), app_state.clone(), cx);
let task = Self::new_local(Vec::new(), app_state.clone(), None, cx);
cx.spawn(|_vh, mut cx| async move {
let (workspace, _) = task.await;
workspace.update(&mut cx, callback)
@ -3025,6 +3048,7 @@ pub async fn last_opened_workspace_paths() -> Option<WorkspaceLocation> {
pub fn open_paths(
abs_paths: &[PathBuf],
app_state: &Arc<AppState>,
requesting_window_id: Option<usize>,
cx: &mut AppContext,
) -> Task<
Result<(
@ -3057,7 +3081,8 @@ pub fn open_paths(
.contains(&false);
cx.update(|cx| {
let task = Workspace::new_local(abs_paths, app_state.clone(), cx);
let task =
Workspace::new_local(abs_paths, app_state.clone(), requesting_window_id, cx);
cx.spawn(|mut cx| async move {
let (workspace, items) = task.await;
@ -3081,7 +3106,7 @@ pub fn open_new(
cx: &mut AppContext,
init: impl FnOnce(&mut Workspace, &mut ViewContext<Workspace>) + 'static,
) -> Task<()> {
let task = Workspace::new_local(Vec::new(), app_state.clone(), cx);
let task = Workspace::new_local(Vec::new(), app_state.clone(), None, cx);
cx.spawn(|mut cx| async move {
let (workspace, opened_paths) = task.await;