Merge branch 'main' into copilot-disabled-globs
This commit is contained in:
commit
9d41f83b1b
81 changed files with 1649 additions and 1545 deletions
|
@ -271,11 +271,11 @@ impl Dock {
|
|||
}
|
||||
}
|
||||
|
||||
fn focus_dock(workspace: &mut Workspace, _: &FocusDock, cx: &mut ViewContext<Workspace>) {
|
||||
pub fn focus_dock(workspace: &mut Workspace, _: &FocusDock, cx: &mut ViewContext<Workspace>) {
|
||||
Self::set_dock_position(workspace, workspace.dock.position.show(), true, cx);
|
||||
}
|
||||
|
||||
fn hide_dock(workspace: &mut Workspace, _: &HideDock, cx: &mut ViewContext<Workspace>) {
|
||||
pub fn hide_dock(workspace: &mut Workspace, _: &HideDock, cx: &mut ViewContext<Workspace>) {
|
||||
Self::set_dock_position(workspace, workspace.dock.position.hide(), true, cx);
|
||||
}
|
||||
|
||||
|
@ -374,8 +374,8 @@ impl Dock {
|
|||
.with_background_color(style.wash_color)
|
||||
})
|
||||
.capture_all()
|
||||
.on_down(MouseButton::Left, |_, _, cx| {
|
||||
cx.dispatch_action(HideDock);
|
||||
.on_down(MouseButton::Left, |_, workspace, cx| {
|
||||
Dock::hide_dock(workspace, &Default::default(), cx)
|
||||
})
|
||||
.with_cursor_style(CursorStyle::Arrow),
|
||||
)
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use super::{icon_for_dock_anchor, Dock, FocusDock, HideDock};
|
||||
use crate::{handle_dropped_item, StatusItemView, Workspace};
|
||||
use gpui::{
|
||||
elements::{Empty, MouseEventHandler, Svg},
|
||||
platform::CursorStyle,
|
||||
|
@ -6,10 +8,6 @@ use gpui::{
|
|||
};
|
||||
use settings::Settings;
|
||||
|
||||
use crate::{handle_dropped_item, StatusItemView, Workspace};
|
||||
|
||||
use super::{icon_for_dock_anchor, FocusDock, HideDock};
|
||||
|
||||
pub struct ToggleDockButton {
|
||||
workspace: WeakViewHandle<Workspace>,
|
||||
}
|
||||
|
@ -82,8 +80,12 @@ impl View for ToggleDockButton {
|
|||
|
||||
if dock_position.is_visible() {
|
||||
button
|
||||
.on_click(MouseButton::Left, |_, _, cx| {
|
||||
cx.dispatch_action(HideDock);
|
||||
.on_click(MouseButton::Left, |_, this, cx| {
|
||||
if let Some(workspace) = this.workspace.upgrade(cx) {
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
Dock::hide_dock(workspace, &Default::default(), cx)
|
||||
})
|
||||
}
|
||||
})
|
||||
.with_tooltip::<Self>(
|
||||
0,
|
||||
|
@ -94,8 +96,12 @@ impl View for ToggleDockButton {
|
|||
)
|
||||
} else {
|
||||
button
|
||||
.on_click(MouseButton::Left, |_, _, cx| {
|
||||
cx.dispatch_action(FocusDock);
|
||||
.on_click(MouseButton::Left, |_, this, cx| {
|
||||
if let Some(workspace) = this.workspace.upgrade(cx) {
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
Dock::focus_dock(workspace, &Default::default(), cx)
|
||||
})
|
||||
}
|
||||
})
|
||||
.with_tooltip::<Self>(
|
||||
0,
|
||||
|
|
|
@ -114,17 +114,14 @@ impl Workspace {
|
|||
pub fn show_toast(&mut self, toast: Toast, cx: &mut ViewContext<Self>) {
|
||||
self.dismiss_notification::<simple_message_notification::MessageNotification>(toast.id, cx);
|
||||
self.show_notification(toast.id, cx, |cx| {
|
||||
cx.add_view(|_cx| match &toast.click {
|
||||
Some((click_msg, action)) => {
|
||||
simple_message_notification::MessageNotification::new_boxed_action(
|
||||
toast.msg.clone(),
|
||||
action.boxed_clone(),
|
||||
click_msg.clone(),
|
||||
)
|
||||
}
|
||||
None => {
|
||||
simple_message_notification::MessageNotification::new_message(toast.msg.clone())
|
||||
cx.add_view(|_cx| match toast.on_click.as_ref() {
|
||||
Some((click_msg, on_click)) => {
|
||||
let on_click = on_click.clone();
|
||||
simple_message_notification::MessageNotification::new(toast.msg.clone())
|
||||
.with_click_message(click_msg.clone())
|
||||
.on_click(move |cx| on_click(cx))
|
||||
}
|
||||
None => simple_message_notification::MessageNotification::new(toast.msg.clone()),
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -152,19 +149,17 @@ impl Workspace {
|
|||
}
|
||||
|
||||
pub mod simple_message_notification {
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
use gpui::{
|
||||
actions,
|
||||
elements::{Flex, MouseEventHandler, Padding, ParentElement, Svg, Text},
|
||||
impl_actions,
|
||||
platform::{CursorStyle, MouseButton},
|
||||
Action, AppContext, Element, Entity, View, ViewContext,
|
||||
AppContext, Element, Entity, View, ViewContext,
|
||||
};
|
||||
use menu::Cancel;
|
||||
use serde::Deserialize;
|
||||
use settings::Settings;
|
||||
use std::{borrow::Cow, sync::Arc};
|
||||
|
||||
use crate::Workspace;
|
||||
|
||||
|
@ -194,7 +189,7 @@ pub mod simple_message_notification {
|
|||
|
||||
pub struct MessageNotification {
|
||||
message: Cow<'static, str>,
|
||||
click_action: Option<Box<dyn Action>>,
|
||||
on_click: Option<Arc<dyn Fn(&mut ViewContext<Self>)>>,
|
||||
click_message: Option<Cow<'static, str>>,
|
||||
}
|
||||
|
||||
|
@ -207,36 +202,31 @@ pub mod simple_message_notification {
|
|||
}
|
||||
|
||||
impl MessageNotification {
|
||||
pub fn new_message<S: Into<Cow<'static, str>>>(message: S) -> MessageNotification {
|
||||
pub fn new<S>(message: S) -> MessageNotification
|
||||
where
|
||||
S: Into<Cow<'static, str>>,
|
||||
{
|
||||
Self {
|
||||
message: message.into(),
|
||||
click_action: None,
|
||||
on_click: None,
|
||||
click_message: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_boxed_action<S1: Into<Cow<'static, str>>, S2: Into<Cow<'static, str>>>(
|
||||
message: S1,
|
||||
click_action: Box<dyn Action>,
|
||||
click_message: S2,
|
||||
) -> Self {
|
||||
Self {
|
||||
message: message.into(),
|
||||
click_action: Some(click_action),
|
||||
click_message: Some(click_message.into()),
|
||||
}
|
||||
pub fn with_click_message<S>(mut self, message: S) -> Self
|
||||
where
|
||||
S: Into<Cow<'static, str>>,
|
||||
{
|
||||
self.click_message = Some(message.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn new<S1: Into<Cow<'static, str>>, A: Action, S2: Into<Cow<'static, str>>>(
|
||||
message: S1,
|
||||
click_action: A,
|
||||
click_message: S2,
|
||||
) -> Self {
|
||||
Self {
|
||||
message: message.into(),
|
||||
click_action: Some(Box::new(click_action) as Box<dyn Action>),
|
||||
click_message: Some(click_message.into()),
|
||||
}
|
||||
pub fn on_click<F>(mut self, on_click: F) -> Self
|
||||
where
|
||||
F: 'static + Fn(&mut ViewContext<Self>),
|
||||
{
|
||||
self.on_click = Some(Arc::new(on_click));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn dismiss(&mut self, _: &CancelMessageNotification, cx: &mut ViewContext<Self>) {
|
||||
|
@ -255,14 +245,10 @@ pub mod simple_message_notification {
|
|||
|
||||
enum MessageNotificationTag {}
|
||||
|
||||
let click_action = self
|
||||
.click_action
|
||||
.as_ref()
|
||||
.map(|action| action.boxed_clone());
|
||||
let click_message = self.click_message.as_ref().map(|message| message.clone());
|
||||
let click_message = self.click_message.clone();
|
||||
let message = self.message.clone();
|
||||
|
||||
let has_click_action = click_action.is_some();
|
||||
let on_click = self.on_click.clone();
|
||||
let has_click_action = on_click.is_some();
|
||||
|
||||
MouseEventHandler::<MessageNotificationTag, _>::new(0, cx, |state, cx| {
|
||||
Flex::column()
|
||||
|
@ -292,8 +278,8 @@ pub mod simple_message_notification {
|
|||
.with_height(style.button_width)
|
||||
})
|
||||
.with_padding(Padding::uniform(5.))
|
||||
.on_click(MouseButton::Left, move |_, _, cx| {
|
||||
cx.dispatch_action(CancelMessageNotification)
|
||||
.on_click(MouseButton::Left, move |_, this, cx| {
|
||||
this.dismiss(&Default::default(), cx);
|
||||
})
|
||||
.with_cursor_style(CursorStyle::PointingHand)
|
||||
.aligned()
|
||||
|
@ -326,10 +312,10 @@ pub mod simple_message_notification {
|
|||
// Since we're not using a proper overlay, we have to capture these extra events
|
||||
.on_down(MouseButton::Left, |_, _, _| {})
|
||||
.on_up(MouseButton::Left, |_, _, _| {})
|
||||
.on_click(MouseButton::Left, move |_, _, cx| {
|
||||
if let Some(click_action) = click_action.as_ref() {
|
||||
cx.dispatch_any_action(click_action.boxed_clone());
|
||||
cx.dispatch_action(CancelMessageNotification)
|
||||
.on_click(MouseButton::Left, move |_, this, cx| {
|
||||
if let Some(on_click) = on_click.as_ref() {
|
||||
on_click(cx);
|
||||
this.dismiss(&Default::default(), cx);
|
||||
}
|
||||
})
|
||||
.with_cursor_style(if has_click_action {
|
||||
|
@ -372,7 +358,7 @@ where
|
|||
Err(err) => {
|
||||
workspace.show_notification(0, cx, |cx| {
|
||||
cx.add_view(|_cx| {
|
||||
simple_message_notification::MessageNotification::new_message(format!(
|
||||
simple_message_notification::MessageNotification::new(format!(
|
||||
"Error: {:?}",
|
||||
err,
|
||||
))
|
||||
|
|
|
@ -2,7 +2,7 @@ mod dragged_item_receiver;
|
|||
|
||||
use super::{ItemHandle, SplitDirection};
|
||||
use crate::{
|
||||
dock::{icon_for_dock_anchor, AnchorDockBottom, AnchorDockRight, ExpandDock, HideDock},
|
||||
dock::{icon_for_dock_anchor, AnchorDockBottom, AnchorDockRight, Dock, ExpandDock},
|
||||
item::WeakItemHandle,
|
||||
toolbar::Toolbar,
|
||||
Item, NewFile, NewSearch, NewTerminal, Workspace,
|
||||
|
@ -259,6 +259,10 @@ impl Pane {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn workspace(&self) -> &WeakViewHandle<Workspace> {
|
||||
&self.workspace
|
||||
}
|
||||
|
||||
pub fn is_active(&self) -> bool {
|
||||
self.is_active
|
||||
}
|
||||
|
@ -1340,8 +1344,8 @@ impl Pane {
|
|||
cx,
|
||||
)
|
||||
})
|
||||
.on_down(MouseButton::Left, move |_, _, cx| {
|
||||
cx.dispatch_action(ActivateItem(ix));
|
||||
.on_down(MouseButton::Left, move |_, this, cx| {
|
||||
this.activate_item(ix, true, true, cx);
|
||||
})
|
||||
.on_click(MouseButton::Middle, {
|
||||
let item_id = item.id();
|
||||
|
@ -1639,7 +1643,15 @@ impl Pane {
|
|||
3,
|
||||
"icons/x_mark_8.svg",
|
||||
cx,
|
||||
|_, cx| cx.dispatch_action(HideDock),
|
||||
|this, cx| {
|
||||
if let Some(workspace) = this.workspace.upgrade(cx) {
|
||||
cx.window_context().defer(move |cx| {
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
Dock::hide_dock(workspace, &Default::default(), cx)
|
||||
})
|
||||
});
|
||||
}
|
||||
},
|
||||
None,
|
||||
)
|
||||
}))
|
||||
|
@ -1693,8 +1705,8 @@ impl View for Pane {
|
|||
})
|
||||
.on_down(
|
||||
MouseButton::Left,
|
||||
move |_, _, cx| {
|
||||
cx.dispatch_action(ActivateItem(active_item_index));
|
||||
move |_, this, cx| {
|
||||
this.activate_item(active_item_index, true, true, cx);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
@ -1759,15 +1771,27 @@ impl View for Pane {
|
|||
})
|
||||
.on_down(
|
||||
MouseButton::Navigate(NavigationDirection::Back),
|
||||
move |_, _, cx| {
|
||||
let pane = cx.weak_handle();
|
||||
cx.dispatch_action(GoBack { pane: Some(pane) });
|
||||
move |_, pane, cx| {
|
||||
if let Some(workspace) = pane.workspace.upgrade(cx) {
|
||||
let pane = cx.weak_handle();
|
||||
cx.window_context().defer(move |cx| {
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
Pane::go_back(workspace, Some(pane), cx).detach_and_log_err(cx)
|
||||
})
|
||||
})
|
||||
}
|
||||
},
|
||||
)
|
||||
.on_down(MouseButton::Navigate(NavigationDirection::Forward), {
|
||||
move |_, _, cx| {
|
||||
let pane = cx.weak_handle();
|
||||
cx.dispatch_action(GoForward { pane: Some(pane) })
|
||||
move |_, pane, cx| {
|
||||
if let Some(workspace) = pane.workspace.upgrade(cx) {
|
||||
let pane = cx.weak_handle();
|
||||
cx.window_context().defer(move |cx| {
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
Pane::go_forward(workspace, Some(pane), cx).detach_and_log_err(cx)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
.into_any_named("pane")
|
||||
|
|
|
@ -279,9 +279,9 @@ impl View for SidebarButtons {
|
|||
.with_style(style.container)
|
||||
})
|
||||
.with_cursor_style(CursorStyle::PointingHand)
|
||||
.on_click(MouseButton::Left, {
|
||||
let action = action.clone();
|
||||
move |_, _, cx| cx.dispatch_action(action.clone())
|
||||
.on_click(MouseButton::Left, move |_, this, cx| {
|
||||
this.sidebar
|
||||
.update(cx, |sidebar, cx| sidebar.toggle_item(ix, cx));
|
||||
})
|
||||
.with_tooltip::<Self>(
|
||||
ix,
|
||||
|
|
|
@ -130,8 +130,23 @@ impl View for Toolbar {
|
|||
tooltip_style.clone(),
|
||||
enable_go_backward,
|
||||
spacing,
|
||||
super::GoBack {
|
||||
pane: Some(pane.clone()),
|
||||
{
|
||||
let pane = pane.clone();
|
||||
move |toolbar, cx| {
|
||||
if let Some(workspace) = toolbar
|
||||
.pane
|
||||
.upgrade(cx)
|
||||
.and_then(|pane| pane.read(cx).workspace().upgrade(cx))
|
||||
{
|
||||
let pane = pane.clone();
|
||||
cx.window_context().defer(move |cx| {
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
Pane::go_back(workspace, Some(pane.clone()), cx)
|
||||
.detach_and_log_err(cx);
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
super::GoBack { pane: None },
|
||||
"Go Back",
|
||||
|
@ -143,7 +158,24 @@ impl View for Toolbar {
|
|||
tooltip_style,
|
||||
enable_go_forward,
|
||||
spacing,
|
||||
super::GoForward { pane: Some(pane) },
|
||||
{
|
||||
let pane = pane.clone();
|
||||
move |toolbar, cx| {
|
||||
if let Some(workspace) = toolbar
|
||||
.pane
|
||||
.upgrade(cx)
|
||||
.and_then(|pane| pane.read(cx).workspace().upgrade(cx))
|
||||
{
|
||||
let pane = pane.clone();
|
||||
cx.window_context().defer(move |cx| {
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
Pane::go_forward(workspace, Some(pane.clone()), cx)
|
||||
.detach_and_log_err(cx);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
super::GoForward { pane: None },
|
||||
"Go Forward",
|
||||
cx,
|
||||
|
@ -161,13 +193,13 @@ impl View for Toolbar {
|
|||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn nav_button<A: Action + Clone>(
|
||||
fn nav_button<A: Action, F: 'static + Fn(&mut Toolbar, &mut ViewContext<Toolbar>)>(
|
||||
svg_path: &'static str,
|
||||
style: theme::Interactive<theme::IconButton>,
|
||||
tooltip_style: TooltipStyle,
|
||||
enabled: bool,
|
||||
spacing: f32,
|
||||
action: A,
|
||||
on_click: F,
|
||||
tooltip_action: A,
|
||||
action_name: &str,
|
||||
cx: &mut ViewContext<Toolbar>,
|
||||
|
@ -195,8 +227,8 @@ fn nav_button<A: Action + Clone>(
|
|||
} else {
|
||||
CursorStyle::default()
|
||||
})
|
||||
.on_click(MouseButton::Left, move |_, _, cx| {
|
||||
cx.dispatch_action(action.clone())
|
||||
.on_click(MouseButton::Left, move |_, toolbar, cx| {
|
||||
on_click(toolbar, cx)
|
||||
})
|
||||
.with_tooltip::<A>(
|
||||
0,
|
||||
|
|
|
@ -42,8 +42,9 @@ use gpui::{
|
|||
CursorStyle, MouseButton, PathPromptOptions, Platform, PromptLevel, WindowBounds,
|
||||
WindowOptions,
|
||||
},
|
||||
Action, AnyModelHandle, AnyViewHandle, AppContext, AsyncAppContext, Entity, ModelContext,
|
||||
ModelHandle, SizeConstraint, Subscription, Task, View, ViewContext, ViewHandle, WeakViewHandle,
|
||||
AnyModelHandle, AnyViewHandle, AppContext, AsyncAppContext, Entity, ModelContext, ModelHandle,
|
||||
SizeConstraint, Subscription, Task, View, ViewContext, ViewHandle, WeakViewHandle,
|
||||
WindowContext,
|
||||
};
|
||||
use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ProjectItem};
|
||||
use language::{LanguageRegistry, Rope};
|
||||
|
@ -59,7 +60,7 @@ use std::{
|
|||
};
|
||||
|
||||
use crate::{
|
||||
notifications::simple_message_notification::{MessageNotification, OsOpen},
|
||||
notifications::simple_message_notification::MessageNotification,
|
||||
persistence::model::{SerializedPane, SerializedPaneGroup, SerializedWorkspace},
|
||||
};
|
||||
use lazy_static::lazy_static;
|
||||
|
@ -139,7 +140,7 @@ pub struct ActivatePane(pub usize);
|
|||
pub struct Toast {
|
||||
id: usize,
|
||||
msg: Cow<'static, str>,
|
||||
click: Option<(Cow<'static, str>, Box<dyn Action>)>,
|
||||
on_click: Option<(Cow<'static, str>, Arc<dyn Fn(&mut WindowContext)>)>,
|
||||
}
|
||||
|
||||
impl Toast {
|
||||
|
@ -147,21 +148,17 @@ impl Toast {
|
|||
Toast {
|
||||
id,
|
||||
msg: msg.into(),
|
||||
click: None,
|
||||
on_click: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_action<I1: Into<Cow<'static, str>>, I2: Into<Cow<'static, str>>>(
|
||||
id: usize,
|
||||
msg: I1,
|
||||
click_msg: I2,
|
||||
action: impl Action,
|
||||
) -> Self {
|
||||
Toast {
|
||||
id,
|
||||
msg: msg.into(),
|
||||
click: Some((click_msg.into(), Box::new(action))),
|
||||
}
|
||||
pub fn on_click<F, M>(mut self, message: M, on_click: F) -> Self
|
||||
where
|
||||
M: Into<Cow<'static, str>>,
|
||||
F: Fn(&mut WindowContext) + 'static,
|
||||
{
|
||||
self.on_click = Some((message.into(), Arc::new(on_click)));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -169,7 +166,7 @@ impl PartialEq for Toast {
|
|||
fn eq(&self, other: &Self) -> bool {
|
||||
self.id == other.id
|
||||
&& self.msg == other.msg
|
||||
&& self.click.is_some() == other.click.is_some()
|
||||
&& self.on_click.is_some() == other.on_click.is_some()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -178,10 +175,7 @@ impl Clone for Toast {
|
|||
Toast {
|
||||
id: self.id,
|
||||
msg: self.msg.to_owned(),
|
||||
click: self
|
||||
.click
|
||||
.as_ref()
|
||||
.map(|(msg, click)| (msg.to_owned(), click.boxed_clone())),
|
||||
on_click: self.on_click.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -216,52 +210,12 @@ pub fn init(app_state: Arc<AppState>, cx: &mut AppContext) {
|
|||
}
|
||||
}
|
||||
});
|
||||
cx.add_action({
|
||||
let app_state = Arc::downgrade(&app_state);
|
||||
move |_, _: &Open, cx: &mut ViewContext<Workspace>| {
|
||||
let mut paths = cx.prompt_for_paths(PathPromptOptions {
|
||||
files: true,
|
||||
directories: true,
|
||||
multiple: true,
|
||||
});
|
||||
|
||||
if let Some(app_state) = app_state.upgrade() {
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
if let Some(paths) = paths.recv().await.flatten() {
|
||||
if let Some(task) = this
|
||||
.update(&mut cx, |this, cx| {
|
||||
this.open_workspace_for_paths(paths, app_state, cx)
|
||||
})
|
||||
.log_err()
|
||||
{
|
||||
task.await.log_err();
|
||||
}
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
}
|
||||
});
|
||||
cx.add_global_action({
|
||||
let app_state = Arc::downgrade(&app_state);
|
||||
move |_: &NewWindow, cx: &mut AppContext| {
|
||||
if let Some(app_state) = app_state.upgrade() {
|
||||
open_new(&app_state, cx, |_, cx| cx.dispatch_action(NewFile)).detach();
|
||||
}
|
||||
}
|
||||
});
|
||||
cx.add_global_action({
|
||||
let app_state = Arc::downgrade(&app_state);
|
||||
move |_: &NewFile, cx: &mut AppContext| {
|
||||
if let Some(app_state) = app_state.upgrade() {
|
||||
open_new(&app_state, cx, |_, cx| cx.dispatch_action(NewFile)).detach();
|
||||
}
|
||||
}
|
||||
});
|
||||
cx.add_async_action(Workspace::open);
|
||||
|
||||
cx.add_async_action(Workspace::follow_next_collaborator);
|
||||
cx.add_async_action(Workspace::close);
|
||||
cx.add_global_action(Workspace::close_global);
|
||||
cx.add_global_action(restart);
|
||||
cx.add_async_action(Workspace::save_all);
|
||||
cx.add_action(Workspace::add_folder_to_project);
|
||||
cx.add_action(
|
||||
|
@ -305,9 +259,7 @@ pub fn init(app_state: Arc<AppState>, cx: &mut AppContext) {
|
|||
} else {
|
||||
workspace.show_notification(1, cx, |cx| {
|
||||
cx.add_view(|_| {
|
||||
MessageNotification::new_message(
|
||||
"Successfully installed the `zed` binary",
|
||||
)
|
||||
MessageNotification::new("Successfully installed the `zed` binary")
|
||||
})
|
||||
});
|
||||
}
|
||||
|
@ -316,17 +268,16 @@ pub fn init(app_state: Arc<AppState>, cx: &mut AppContext) {
|
|||
.detach();
|
||||
});
|
||||
|
||||
cx.add_action({
|
||||
let app_state = app_state.clone();
|
||||
cx.add_action(
|
||||
move |_: &mut Workspace, _: &OpenSettings, cx: &mut ViewContext<Workspace>| {
|
||||
create_and_open_local_file(&paths::SETTINGS, app_state.clone(), cx, || {
|
||||
create_and_open_local_file(&paths::SETTINGS, cx, || {
|
||||
Settings::initial_user_settings_content(&Assets)
|
||||
.as_ref()
|
||||
.into()
|
||||
})
|
||||
.detach_and_log_err(cx);
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
let client = &app_state.client;
|
||||
client.add_view_request_handler(Workspace::handle_follow);
|
||||
|
@ -934,7 +885,6 @@ impl Workspace {
|
|||
/// to the callback. Otherwise, a new empty window will be created.
|
||||
pub fn with_local_workspace<T, F>(
|
||||
&mut self,
|
||||
app_state: &Arc<AppState>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
callback: F,
|
||||
) -> Task<Result<T>>
|
||||
|
@ -945,7 +895,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(), None, cx);
|
||||
let task = Self::new_local(Vec::new(), self.app_state.clone(), None, cx);
|
||||
cx.spawn(|_vh, mut cx| async move {
|
||||
let (workspace, _) = task.await;
|
||||
workspace.update(&mut cx, callback)
|
||||
|
@ -981,12 +931,18 @@ impl Workspace {
|
|||
}
|
||||
|
||||
pub fn close_global(_: &CloseWindow, cx: &mut AppContext) {
|
||||
let id = cx.window_ids().find(|&id| cx.window_is_active(id));
|
||||
if let Some(id) = id {
|
||||
//This can only get called when the window's project connection has been lost
|
||||
//so we don't need to prompt the user for anything and instead just close the window
|
||||
cx.remove_window(id);
|
||||
}
|
||||
cx.spawn(|mut cx| async move {
|
||||
let id = cx
|
||||
.window_ids()
|
||||
.into_iter()
|
||||
.find(|&id| cx.window_is_active(id));
|
||||
if let Some(id) = id {
|
||||
//This can only get called when the window's project connection has been lost
|
||||
//so we don't need to prompt the user for anything and instead just close the window
|
||||
cx.remove_window(id);
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
||||
pub fn close(
|
||||
|
@ -1011,19 +967,14 @@ impl Workspace {
|
|||
) -> Task<Result<bool>> {
|
||||
let active_call = self.active_call().cloned();
|
||||
let window_id = cx.window_id();
|
||||
let workspace_count = cx
|
||||
.window_ids()
|
||||
.collect::<Vec<_>>()
|
||||
.into_iter()
|
||||
.filter_map(|window_id| {
|
||||
cx.app_context()
|
||||
.root_view(window_id)?
|
||||
.clone()
|
||||
.downcast::<Workspace>()
|
||||
})
|
||||
.count();
|
||||
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
let workspace_count = cx
|
||||
.window_ids()
|
||||
.into_iter()
|
||||
.filter_map(|window_id| cx.root_view(window_id)?.clone().downcast::<Workspace>())
|
||||
.count();
|
||||
|
||||
if let Some(active_call) = active_call {
|
||||
if !quitting
|
||||
&& workspace_count == 1
|
||||
|
@ -1114,10 +1065,29 @@ impl Workspace {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn open(&mut self, _: &Open, cx: &mut ViewContext<Self>) -> Option<Task<Result<()>>> {
|
||||
let mut paths = cx.prompt_for_paths(PathPromptOptions {
|
||||
files: true,
|
||||
directories: true,
|
||||
multiple: true,
|
||||
});
|
||||
|
||||
Some(cx.spawn(|this, mut cx| async move {
|
||||
if let Some(paths) = paths.recv().await.flatten() {
|
||||
if let Some(task) = this
|
||||
.update(&mut cx, |this, cx| this.open_workspace_for_paths(paths, cx))
|
||||
.log_err()
|
||||
{
|
||||
task.await?
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn open_workspace_for_paths(
|
||||
&mut self,
|
||||
paths: Vec<PathBuf>,
|
||||
app_state: Arc<AppState>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Task<Result<()>> {
|
||||
let window_id = cx.window_id();
|
||||
|
@ -1129,6 +1099,7 @@ impl Workspace {
|
|||
} else {
|
||||
Some(self.prepare_to_close(false, cx))
|
||||
};
|
||||
let app_state = self.app_state.clone();
|
||||
|
||||
cx.spawn(|_, mut cx| async move {
|
||||
let window_id_to_replace = if let Some(close_task) = close_task {
|
||||
|
@ -2682,36 +2653,37 @@ impl Workspace {
|
|||
}
|
||||
|
||||
fn notify_if_database_failed(workspace: &WeakViewHandle<Workspace>, cx: &mut AsyncAppContext) {
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
if (*db::ALL_FILE_DB_FAILED).load(std::sync::atomic::Ordering::Acquire) {
|
||||
workspace.show_notification_once(0, cx, |cx| {
|
||||
cx.add_view(|_| {
|
||||
MessageNotification::new(
|
||||
"Failed to load any database file.",
|
||||
OsOpen::new("https://github.com/zed-industries/community/issues/new?assignees=&labels=defect%2Ctriage&template=2_bug_report.yml".to_string()),
|
||||
"Click to let us know about this error"
|
||||
)
|
||||
})
|
||||
});
|
||||
} else {
|
||||
let backup_path = (*db::BACKUP_DB_PATH).read();
|
||||
if let Some(backup_path) = &*backup_path {
|
||||
const REPORT_ISSUE_URL: &str ="https://github.com/zed-industries/community/issues/new?assignees=&labels=defect%2Ctriage&template=2_bug_report.yml";
|
||||
|
||||
workspace
|
||||
.update(cx, |workspace, cx| {
|
||||
if (*db::ALL_FILE_DB_FAILED).load(std::sync::atomic::Ordering::Acquire) {
|
||||
workspace.show_notification_once(0, cx, |cx| {
|
||||
cx.add_view(|_| {
|
||||
let backup_path = backup_path.to_string_lossy();
|
||||
MessageNotification::new(
|
||||
format!(
|
||||
"Database file was corrupted. Old database backed up to {}",
|
||||
backup_path
|
||||
),
|
||||
OsOpen::new(backup_path.to_string()),
|
||||
"Click to show old database in finder",
|
||||
)
|
||||
MessageNotification::new("Failed to load any database file.")
|
||||
.with_click_message("Click to let us know about this error")
|
||||
.on_click(|cx| cx.platform().open_url(REPORT_ISSUE_URL))
|
||||
})
|
||||
});
|
||||
} else {
|
||||
let backup_path = (*db::BACKUP_DB_PATH).read();
|
||||
if let Some(backup_path) = backup_path.clone() {
|
||||
workspace.show_notification_once(0, cx, move |cx| {
|
||||
cx.add_view(move |_| {
|
||||
MessageNotification::new(format!(
|
||||
"Database file was corrupted. Old database backed up to {}",
|
||||
backup_path.display()
|
||||
))
|
||||
.with_click_message("Click to show old database in finder")
|
||||
.on_click(move |cx| {
|
||||
cx.platform().open_url(&backup_path.to_string_lossy())
|
||||
})
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}).log_err();
|
||||
})
|
||||
.log_err();
|
||||
}
|
||||
|
||||
impl Entity for Workspace {
|
||||
|
@ -2891,10 +2863,10 @@ impl std::fmt::Debug for OpenPaths {
|
|||
pub struct WorkspaceCreated(WeakViewHandle<Workspace>);
|
||||
|
||||
pub fn activate_workspace_for_project(
|
||||
cx: &mut AppContext,
|
||||
cx: &mut AsyncAppContext,
|
||||
predicate: impl Fn(&mut Project, &mut ModelContext<Project>) -> bool,
|
||||
) -> Option<WeakViewHandle<Workspace>> {
|
||||
for window_id in cx.window_ids().collect::<Vec<_>>() {
|
||||
for window_id in cx.window_ids() {
|
||||
let handle = cx
|
||||
.update_window(window_id, |cx| {
|
||||
if let Some(workspace_handle) = cx.root_view().clone().downcast::<Workspace>() {
|
||||
|
@ -2933,13 +2905,14 @@ pub fn open_paths(
|
|||
> {
|
||||
log::info!("open paths {:?}", abs_paths);
|
||||
|
||||
// Open paths in existing workspace if possible
|
||||
let existing =
|
||||
activate_workspace_for_project(cx, |project, cx| project.contains_paths(abs_paths, cx));
|
||||
|
||||
let app_state = app_state.clone();
|
||||
let abs_paths = abs_paths.to_vec();
|
||||
cx.spawn(|mut cx| async move {
|
||||
// Open paths in existing workspace if possible
|
||||
let existing = activate_workspace_for_project(&mut cx, |project, cx| {
|
||||
project.contains_paths(&abs_paths, cx)
|
||||
});
|
||||
|
||||
if let Some(existing) = existing {
|
||||
Ok((
|
||||
existing.clone(),
|
||||
|
@ -2997,12 +2970,11 @@ pub fn open_new(
|
|||
|
||||
pub fn create_and_open_local_file(
|
||||
path: &'static Path,
|
||||
app_state: Arc<AppState>,
|
||||
cx: &mut ViewContext<Workspace>,
|
||||
default_content: impl 'static + Send + FnOnce() -> Rope,
|
||||
) -> Task<Result<Box<dyn ItemHandle>>> {
|
||||
cx.spawn(|workspace, mut cx| async move {
|
||||
let fs = &app_state.fs;
|
||||
let fs = workspace.read_with(&cx, |workspace, _| workspace.app_state().fs.clone())?;
|
||||
if !fs.is_file(path).await {
|
||||
fs.create_file(path, Default::default()).await?;
|
||||
fs.save(path, &default_content(), Default::default())
|
||||
|
@ -3011,7 +2983,7 @@ pub fn create_and_open_local_file(
|
|||
|
||||
let mut items = workspace
|
||||
.update(&mut cx, |workspace, cx| {
|
||||
workspace.with_local_workspace(&app_state, cx, |workspace, cx| {
|
||||
workspace.with_local_workspace(cx, |workspace, cx| {
|
||||
workspace.open_paths(vec![path.to_path_buf()], false, cx)
|
||||
})
|
||||
})?
|
||||
|
@ -3030,13 +3002,16 @@ pub fn join_remote_project(
|
|||
cx: &mut AppContext,
|
||||
) -> Task<Result<()>> {
|
||||
cx.spawn(|mut cx| async move {
|
||||
let existing_workspace = cx.update(|cx| {
|
||||
cx.window_ids()
|
||||
.filter_map(|window_id| cx.root_view(window_id)?.clone().downcast::<Workspace>())
|
||||
.find(|workspace| {
|
||||
let existing_workspace = cx
|
||||
.window_ids()
|
||||
.into_iter()
|
||||
.filter_map(|window_id| cx.root_view(window_id)?.clone().downcast::<Workspace>())
|
||||
.find(|workspace| {
|
||||
cx.read_window(workspace.window_id(), |cx| {
|
||||
workspace.read(cx).project().read(cx).remote_id() == Some(project_id)
|
||||
})
|
||||
});
|
||||
.unwrap_or(false)
|
||||
});
|
||||
|
||||
let workspace = if let Some(existing_workspace) = existing_workspace {
|
||||
existing_workspace.downgrade()
|
||||
|
@ -3104,6 +3079,59 @@ pub fn join_remote_project(
|
|||
})
|
||||
}
|
||||
|
||||
pub fn restart(_: &Restart, cx: &mut AppContext) {
|
||||
let should_confirm = cx.global::<Settings>().confirm_quit;
|
||||
cx.spawn(|mut cx| async move {
|
||||
let mut workspaces = cx
|
||||
.window_ids()
|
||||
.into_iter()
|
||||
.filter_map(|window_id| {
|
||||
Some(
|
||||
cx.root_view(window_id)?
|
||||
.clone()
|
||||
.downcast::<Workspace>()?
|
||||
.downgrade(),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// If multiple windows have unsaved changes, and need a save prompt,
|
||||
// prompt in the active window before switching to a different window.
|
||||
workspaces.sort_by_key(|workspace| !cx.window_is_active(workspace.window_id()));
|
||||
|
||||
if let (true, Some(workspace)) = (should_confirm, workspaces.first()) {
|
||||
let answer = cx.prompt(
|
||||
workspace.window_id(),
|
||||
PromptLevel::Info,
|
||||
"Are you sure you want to restart?",
|
||||
&["Restart", "Cancel"],
|
||||
);
|
||||
|
||||
if let Some(mut answer) = answer {
|
||||
let answer = answer.next().await;
|
||||
if answer != Some(0) {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the user cancels any save prompt, then keep the app open.
|
||||
for workspace in workspaces {
|
||||
if !workspace
|
||||
.update(&mut cx, |workspace, cx| {
|
||||
workspace.prepare_to_close(true, cx)
|
||||
})?
|
||||
.await?
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
cx.platform().restart();
|
||||
anyhow::Ok(())
|
||||
})
|
||||
.detach_and_log_err(cx);
|
||||
}
|
||||
|
||||
fn parse_pixel_position_env_var(value: &str) -> Option<Vector2F> {
|
||||
let mut parts = value.split(',');
|
||||
let width: usize = parts.next()?.parse().ok()?;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue