Compare commits

...

2 Commits

Author SHA1 Message Date
Conrad Irwin
f802444e79 Remove can_open_windows
Co-Authored-By: Mikayla <mikayla@zed.dev>
2024-06-10 15:24:01 -06:00
Conrad Irwin
7716fa8312 Make window initialization fallible 2024-06-10 15:20:20 -06:00
29 changed files with 272 additions and 204 deletions

7
Cargo.lock generated
View File

@@ -1511,7 +1511,7 @@ dependencies = [
[[package]]
name = "blade-graphics"
version = "0.4.0"
source = "git+https://github.com/kvark/blade?rev=bdaf8c534fbbc9fbca71d1cf272f45640b3a068d#bdaf8c534fbbc9fbca71d1cf272f45640b3a068d"
source = "git+https://github.com/zed-industries/blade?rev=86bf7228f50f44058edf7872055261efd9eca9de#86bf7228f50f44058edf7872055261efd9eca9de"
dependencies = [
"ash",
"ash-window",
@@ -1541,7 +1541,7 @@ dependencies = [
[[package]]
name = "blade-macros"
version = "0.2.1"
source = "git+https://github.com/kvark/blade?rev=bdaf8c534fbbc9fbca71d1cf272f45640b3a068d#bdaf8c534fbbc9fbca71d1cf272f45640b3a068d"
source = "git+https://github.com/zed-industries/blade?rev=86bf7228f50f44058edf7872055261efd9eca9de#86bf7228f50f44058edf7872055261efd9eca9de"
dependencies = [
"proc-macro2",
"quote",
@@ -1551,7 +1551,7 @@ dependencies = [
[[package]]
name = "blade-util"
version = "0.1.0"
source = "git+https://github.com/kvark/blade?rev=bdaf8c534fbbc9fbca71d1cf272f45640b3a068d#bdaf8c534fbbc9fbca71d1cf272f45640b3a068d"
source = "git+https://github.com/zed-industries/blade?rev=86bf7228f50f44058edf7872055261efd9eca9de#86bf7228f50f44058edf7872055261efd9eca9de"
dependencies = [
"blade-graphics",
"bytemuck",
@@ -13152,6 +13152,7 @@ version = "0.140.0"
dependencies = [
"activity_indicator",
"anyhow",
"ashpd",
"assets",
"assistant",
"audio",

View File

@@ -267,9 +267,9 @@ async-tar = "0.4.2"
async-trait = "0.1"
async_zip = { version = "0.0.17", features = ["deflate", "deflate64"] }
bitflags = "2.4.2"
blade-graphics = { git = "https://github.com/kvark/blade", rev = "bdaf8c534fbbc9fbca71d1cf272f45640b3a068d" }
blade-macros = { git = "https://github.com/kvark/blade", rev = "bdaf8c534fbbc9fbca71d1cf272f45640b3a068d" }
blade-util = { git = "https://github.com/kvark/blade", rev = "bdaf8c534fbbc9fbca71d1cf272f45640b3a068d" }
blade-graphics = { git = "https://github.com/zed-industries/blade", rev = "86bf7228f50f44058edf7872055261efd9eca9de" }
blade-macros = { git = "https://github.com/zed-industries/blade", rev = "86bf7228f50f44058edf7872055261efd9eca9de" }
blade-util = { git = "https://github.com/zed-industries/blade", rev = "86bf7228f50f44058edf7872055261efd9eca9de" }
cap-std = "3.0"
cargo_toml = "0.20"
chrono = { version = "0.4", features = ["serde"] }

View File

@@ -97,7 +97,7 @@ pub fn open_prompt_library(
},
|cx| cx.new_view(|cx| PromptLibrary::new(store, language_registry, cx)),
)
})
})?
})
}
}

View File

@@ -8,6 +8,7 @@ use settings::Settings;
use std::sync::{Arc, Weak};
use theme::ThemeSettings;
use ui::{prelude::*, Button, Label};
use util::ResultExt;
use workspace::AppState;
pub fn init(app_state: &Arc<AppState>, cx: &mut AppContext) {
@@ -27,16 +28,21 @@ pub fn init(app_state: &Arc<AppState>, cx: &mut AppContext) {
for screen in cx.displays() {
let options = notification_window_options(screen, window_size, cx);
let window = cx.open_window(options, |cx| {
cx.new_view(|_| {
ProjectSharedNotification::new(
owner.clone(),
*project_id,
worktree_root_names.clone(),
app_state.clone(),
)
let Some(window) = cx
.open_window(options, |cx| {
cx.new_view(|_| {
ProjectSharedNotification::new(
owner.clone(),
*project_id,
worktree_root_names.clone(),
app_state.clone(),
)
})
})
});
.log_err()
else {
continue;
};
notification_windows
.entry(*project_id)
.or_insert(Vec::new())

View File

@@ -509,6 +509,7 @@ fn test_clone(cx: &mut TestAppContext) {
.update(cx, |editor, cx| {
cx.open_window(Default::default(), |cx| cx.new_view(|cx| editor.clone(cx)))
})
.unwrap()
.unwrap();
let snapshot = editor.update(cx, |e, cx| e.snapshot(cx)).unwrap();
@@ -7657,6 +7658,7 @@ async fn test_following(cx: &mut gpui::TestAppContext) {
},
|cx| cx.new_view(|cx| build_editor(buffer.clone(), cx)),
)
.unwrap()
});
let is_still_following = Rc::new(RefCell::new(true));

View File

@@ -76,6 +76,7 @@ fn main() {
cx.open_window(options, |cx| {
cx.activate(false);
cx.new_view(|_cx| AnimationExample {})
});
})
.unwrap();
});
}

View File

@@ -34,6 +34,7 @@ fn main() {
text: "World".into(),
})
},
);
)
.unwrap();
});
}

View File

@@ -93,6 +93,7 @@ fn main() {
local_resource: Arc::new(PathBuf::from_str("examples/image/app-icon.png").unwrap()),
remote_resource: "https://picsum.photos/512/512".into(),
})
});
})
.unwrap();
});
}

View File

@@ -29,7 +29,8 @@ fn main() {
}]);
cx.open_window(WindowOptions::default(), |cx| {
cx.new_view(|_cx| SetMenus {})
});
})
.unwrap();
});
}

View File

@@ -61,7 +61,8 @@ fn main() {
cx.new_view(|_| WindowContent {
text: format!("{:?}", screen.id()).into(),
})
});
})
.unwrap();
}
});
}

View File

@@ -490,26 +490,26 @@ impl AppContext {
&mut self,
options: crate::WindowOptions,
build_root_view: impl FnOnce(&mut WindowContext) -> View<V>,
) -> WindowHandle<V> {
) -> anyhow::Result<WindowHandle<V>> {
self.update(|cx| {
let id = cx.windows.insert(None);
let handle = WindowHandle::new(id);
let mut window = Window::new(handle.into(), options, cx);
let root_view = build_root_view(&mut WindowContext::new(cx, &mut window));
window.root_view.replace(root_view.into());
cx.window_handles.insert(id, window.handle);
cx.windows.get_mut(id).unwrap().replace(window);
handle
match Window::new(handle.into(), options, cx) {
Ok(mut window) => {
let root_view = build_root_view(&mut WindowContext::new(cx, &mut window));
window.root_view.replace(root_view.into());
cx.window_handles.insert(id, window.handle);
cx.windows.get_mut(id).unwrap().replace(window);
Ok(handle)
}
Err(e) => {
cx.windows.remove(id);
return Err(e);
}
}
})
}
/// Returns Ok() if the platform supports opening windows.
/// This returns false (for example) on linux when we could
/// not establish a connection to X or Wayland.
pub fn can_open_windows(&self) -> anyhow::Result<()> {
self.platform.can_open_windows()
}
/// Instructs the platform to activate the application by bringing it to the foreground.
pub fn activate(&self, ignoring_other_apps: bool) {
self.platform.activate(ignoring_other_apps);

View File

@@ -151,7 +151,7 @@ impl AsyncAppContext {
.upgrade()
.ok_or_else(|| anyhow!("app was released"))?;
let mut lock = app.borrow_mut();
Ok(lock.open_window(options, build_root_view))
lock.open_window(options, build_root_view)
}
/// Schedule a future to be polled in the background.

View File

@@ -193,19 +193,22 @@ impl TestAppContext {
},
|cx| cx.new_view(build_window),
)
.unwrap()
}
/// Adds a new window with no content.
pub fn add_empty_window(&mut self) -> &mut VisualTestContext {
let mut cx = self.app.borrow_mut();
let bounds = Bounds::maximized(None, &mut cx);
let window = cx.open_window(
WindowOptions {
window_bounds: Some(WindowBounds::Windowed(bounds)),
..Default::default()
},
|cx| cx.new_view(|_| Empty),
);
let window = cx
.open_window(
WindowOptions {
window_bounds: Some(WindowBounds::Windowed(bounds)),
..Default::default()
},
|cx| cx.new_view(|_| Empty),
)
.unwrap();
drop(cx);
let cx = VisualTestContext::from_window(*window.deref(), self).as_mut();
cx.run_until_parked();
@@ -222,13 +225,15 @@ impl TestAppContext {
{
let mut cx = self.app.borrow_mut();
let bounds = Bounds::maximized(None, &mut cx);
let window = cx.open_window(
WindowOptions {
window_bounds: Some(WindowBounds::Windowed(bounds)),
..Default::default()
},
|cx| cx.new_view(build_root_view),
);
let window = cx
.open_window(
WindowOptions {
window_bounds: Some(WindowBounds::Windowed(bounds)),
..Default::default()
},
|cx| cx.new_view(build_root_view),
)
.unwrap();
drop(cx);
let view = window.root_view(self).unwrap();
let cx = VisualTestContext::from_window(*window.deref(), self).as_mut();

View File

@@ -486,6 +486,7 @@ mod test {
focus_handle: cx.focus_handle(),
})
})
.unwrap()
});
cx.update(|cx| {

View File

@@ -106,14 +106,12 @@ pub(crate) trait Platform: 'static {
fn displays(&self) -> Vec<Rc<dyn PlatformDisplay>>;
fn primary_display(&self) -> Option<Rc<dyn PlatformDisplay>>;
fn active_window(&self) -> Option<AnyWindowHandle>;
fn can_open_windows(&self) -> anyhow::Result<()> {
Ok(())
}
fn open_window(
&self,
handle: AnyWindowHandle,
options: WindowParams,
) -> Box<dyn PlatformWindow>;
) -> anyhow::Result<Box<dyn PlatformWindow>>;
/// Returns the appearance of the application's windows.
fn window_appearance(&self) -> WindowAppearance;

View File

@@ -59,10 +59,6 @@ impl LinuxClient for HeadlessClient {
None
}
fn can_open_windows(&self) -> anyhow::Result<()> {
return Err(anyhow::anyhow!("neither DISPLAY, nor WAYLAND_DISPLAY found. You can still run zed for remote development with --dev-server-token."));
}
fn active_window(&self) -> Option<AnyWindowHandle> {
None
}
@@ -71,8 +67,10 @@ impl LinuxClient for HeadlessClient {
&self,
_handle: AnyWindowHandle,
_params: WindowParams,
) -> Box<dyn PlatformWindow> {
unimplemented!()
) -> anyhow::Result<Box<dyn PlatformWindow>> {
Err(anyhow::anyhow!(
"neither DISPLAY nor WAYLAND_DISPLAY is set. You can run in headless mode"
))
}
fn set_cursor_style(&self, _style: CursorStyle) {}

View File

@@ -65,7 +65,7 @@ pub trait LinuxClient {
&self,
handle: AnyWindowHandle,
options: WindowParams,
) -> Box<dyn PlatformWindow>;
) -> anyhow::Result<Box<dyn PlatformWindow>>;
fn set_cursor_style(&self, style: CursorStyle);
fn open_uri(&self, uri: &str);
fn write_to_primary(&self, item: ClipboardItem);
@@ -245,7 +245,7 @@ impl<P: LinuxClient + 'static> Platform for P {
&self,
handle: AnyWindowHandle,
options: WindowParams,
) -> Box<dyn PlatformWindow> {
) -> anyhow::Result<Box<dyn PlatformWindow>> {
self.open_window(handle, options)
}

View File

@@ -559,7 +559,7 @@ impl LinuxClient for WaylandClient {
&self,
handle: AnyWindowHandle,
params: WindowParams,
) -> Box<dyn PlatformWindow> {
) -> anyhow::Result<Box<dyn PlatformWindow>> {
let mut state = self.0.borrow_mut();
let (window, surface_id) = WaylandWindow::new(
@@ -568,10 +568,10 @@ impl LinuxClient for WaylandClient {
WaylandClientStatePtr(Rc::downgrade(&self.0)),
params,
state.common.appearance,
);
)?;
state.windows.insert(surface_id, window.0.clone());
Box::new(window)
Ok(Box::new(window))
}
fn set_cursor_style(&self, style: CursorStyle) {

View File

@@ -107,7 +107,7 @@ impl WaylandWindowState {
client: WaylandClientStatePtr,
globals: Globals,
options: WindowParams,
) -> Self {
) -> anyhow::Result<Self> {
let bounds = options.bounds.map(|p| p.0 as u32);
let raw = RawWindow {
@@ -130,7 +130,7 @@ impl WaylandWindowState {
},
)
}
.unwrap(),
.map_err(|e| anyhow::anyhow!("{:?}", e))?,
);
let config = BladeSurfaceConfig {
size: gpu::Extent {
@@ -141,7 +141,7 @@ impl WaylandWindowState {
transparent: options.window_background != WindowBackgroundAppearance::Opaque,
};
Self {
Ok(Self {
xdg_surface,
acknowledged_first_configure: false,
surface,
@@ -164,7 +164,7 @@ impl WaylandWindowState {
appearance,
handle,
active: false,
}
})
}
}
@@ -224,7 +224,7 @@ impl WaylandWindow {
client: WaylandClientStatePtr,
params: WindowParams,
appearance: WindowAppearance,
) -> (Self, ObjectId) {
) -> anyhow::Result<(Self, ObjectId)> {
let surface = globals.compositor.create_surface(&globals.qh, ());
let xdg_surface = globals
.wm_base
@@ -267,14 +267,14 @@ impl WaylandWindow {
client,
globals,
params,
))),
)?)),
callbacks: Rc::new(RefCell::new(Callbacks::default())),
});
// Kick things off
surface.commit();
(this, surface.id())
Ok((this, surface.id()))
}
}

View File

@@ -923,7 +923,7 @@ impl LinuxClient for X11Client {
&self,
handle: AnyWindowHandle,
params: WindowParams,
) -> Box<dyn PlatformWindow> {
) -> anyhow::Result<Box<dyn PlatformWindow>> {
let mut state = self.0.borrow_mut();
let x_window = state.xcb_connection.generate_id().unwrap();
@@ -938,7 +938,7 @@ impl LinuxClient for X11Client {
&state.atoms,
state.scale_factor,
state.common.appearance,
);
)?;
let screen_resources = state
.xcb_connection
@@ -1006,7 +1006,7 @@ impl LinuxClient for X11Client {
};
state.windows.insert(x_window, window_ref);
Box::new(window)
Ok(Box::new(window))
}
fn set_cursor_style(&self, style: CursorStyle) {

View File

@@ -216,7 +216,7 @@ impl X11WindowState {
atoms: &XcbAtoms,
scale_factor: f32,
appearance: WindowAppearance,
) -> Self {
) -> anyhow::Result<Self> {
let x_screen_index = params
.display_id
.map_or(x_main_screen_index, |did| did.0 as usize);
@@ -248,8 +248,7 @@ impl X11WindowState {
xcb_connection
.create_colormap(xproto::ColormapAlloc::NONE, id, visual_set.root, visual.id)
.unwrap()
.check()
.unwrap();
.check()?;
id
};
@@ -281,8 +280,7 @@ impl X11WindowState {
&win_aux,
)
.unwrap()
.check()
.unwrap();
.check()?;
if let Some(titlebar) = params.titlebar {
if let Some(title) = titlebar.title {
@@ -345,7 +343,7 @@ impl X11WindowState {
},
)
}
.unwrap(),
.map_err(|e| anyhow::anyhow!("{:?}", e))?,
);
let config = BladeSurfaceConfig {
@@ -355,7 +353,7 @@ impl X11WindowState {
transparent: params.window_background != WindowBackgroundAppearance::Opaque,
};
Self {
Ok(Self {
client,
executor,
display: Rc::new(X11Display::new(xcb_connection, x_screen_index).unwrap()),
@@ -368,7 +366,7 @@ impl X11WindowState {
input_handler: None,
appearance,
handle,
}
})
}
fn content_size(&self) -> Size<Pixels> {
@@ -426,8 +424,8 @@ impl X11Window {
atoms: &XcbAtoms,
scale_factor: f32,
appearance: WindowAppearance,
) -> Self {
Self(X11WindowStatePtr {
) -> anyhow::Result<Self> {
Ok(Self(X11WindowStatePtr {
state: Rc::new(RefCell::new(X11WindowState::new(
handle,
client,
@@ -439,11 +437,11 @@ impl X11Window {
atoms,
scale_factor,
appearance,
))),
)?)),
callbacks: Rc::new(RefCell::new(Callbacks::default())),
xcb_connection: xcb_connection.clone(),
x_window,
})
}))
}
fn set_wm_hints(&self, wm_hint_property_state: WmHintPropertyState, prop1: u32, prop2: u32) {

View File

@@ -187,14 +187,14 @@ impl Platform for TestPlatform {
&self,
handle: AnyWindowHandle,
params: WindowParams,
) -> Box<dyn crate::PlatformWindow> {
) -> anyhow::Result<Box<dyn crate::PlatformWindow>> {
let window = TestWindow::new(
handle,
params,
self.weak.clone(),
self.active_display.clone(),
);
Box::new(window)
Ok(Box::new(window))
}
fn window_appearance(&self) -> WindowAppearance {

View File

@@ -605,7 +605,7 @@ impl Window {
handle: AnyWindowHandle,
options: WindowOptions,
cx: &mut AppContext,
) -> Self {
) -> Result<Self> {
let WindowOptions {
window_bounds,
titlebar,
@@ -633,7 +633,7 @@ impl Window {
display_id,
window_background,
},
);
)?;
let display_id = platform_window.display().map(|display| display.id());
let sprite_atlas = platform_window.sprite_atlas();
let mouse_position = platform_window.mouse_position();
@@ -761,7 +761,7 @@ impl Window {
platform_window.set_app_id(&app_id);
}
Window {
Ok(Window {
handle,
removed: false,
platform_window,
@@ -807,7 +807,7 @@ impl Window {
focus_enabled: true,
pending_input: None,
prompt: None,
}
})
}
fn new_focus_listener(
&mut self,

View File

@@ -147,7 +147,8 @@ pub fn main() {
cx,
)
})
});
})
.unwrap();
});
}

View File

@@ -5,7 +5,7 @@ use client::{telemetry::Telemetry, TelemetrySettings};
use db::kvp::KEY_VALUE_STORE;
use gpui::{
svg, AnyElement, AppContext, EventEmitter, FocusHandle, FocusableView, InteractiveElement,
ParentElement, Render, Styled, Subscription, View, ViewContext, VisualContext, WeakView,
ParentElement, Render, Styled, Subscription, Task, View, ViewContext, VisualContext, WeakView,
WindowContext,
};
use settings::{Settings, SettingsStore};
@@ -36,19 +36,21 @@ pub fn init(cx: &mut AppContext) {
base_keymap_picker::init(cx);
}
pub fn show_welcome_view(app_state: Arc<AppState>, cx: &mut AppContext) {
pub fn show_welcome_view(
app_state: Arc<AppState>,
cx: &mut AppContext,
) -> Task<anyhow::Result<()>> {
open_new(app_state, cx, |workspace, cx| {
workspace.toggle_dock(DockPosition::Left, cx);
let welcome_page = WelcomePage::new(workspace, cx);
workspace.add_item_to_center(Box::new(welcome_page.clone()), cx);
cx.focus_view(&welcome_page);
cx.notify();
})
.detach();
db::write_and_log(cx, || {
KEY_VALUE_STORE.write_kvp(FIRST_OPEN.to_string(), "false".to_string())
});
db::write_and_log(cx, || {
KEY_VALUE_STORE.write_kvp(FIRST_OPEN.to_string(), "false".to_string())
});
})
}
pub struct WelcomePage {

View File

@@ -4839,18 +4839,16 @@ pub fn open_new(
app_state: Arc<AppState>,
cx: &mut AppContext,
init: impl FnOnce(&mut Workspace, &mut ViewContext<Workspace>) + 'static + Send,
) -> Task<()> {
) -> Task<anyhow::Result<()>> {
let task = Workspace::new_local(Vec::new(), app_state, None, cx);
cx.spawn(|mut cx| async move {
if let Some((workspace, opened_paths)) = task.await.log_err() {
workspace
.update(&mut cx, |workspace, cx| {
if opened_paths.is_empty() {
init(workspace, cx)
}
})
.log_err();
}
let (workspace, opened_paths) = task.await?;
workspace.update(&mut cx, |workspace, cx| {
if opened_paths.is_empty() {
init(workspace, cx)
}
})?;
Ok(())
})
}
@@ -4922,7 +4920,7 @@ pub fn join_hosted_project(
Workspace::new(Default::default(), project, app_state.clone(), cx)
})
})
})?
})??
};
workspace.update(&mut cx, |_, cx| {
@@ -4987,7 +4985,7 @@ pub fn join_dev_server_project(
Workspace::new(Default::default(), project, app_state.clone(), cx)
})
})
})?
})??
}
};
@@ -5050,7 +5048,7 @@ pub fn join_in_room_project(
Workspace::new(Default::default(), project, app_state.clone(), cx)
})
})
})?
})??
};
workspace.update(&mut cx, |workspace, cx| {

View File

@@ -103,6 +103,9 @@ zed_actions.workspace = true
[target.'cfg(target_os = "windows")'.build-dependencies]
winresource = "0.1"
[target.'cfg(target_os = "linux")'.dependencies]
ashpd.workspace = true
[dev-dependencies]
call = { workspace = true, features = ["test-support"] }
editor = { workspace = true, features = ["test-support"] }

View File

@@ -56,21 +56,58 @@ use crate::zed::inline_completion_registry;
static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
fn fail_to_launch(e: anyhow::Error) {
eprintln!("Zed failed to launch: {:?}", e);
App::new().run(move |cx| {
let window = cx.open_window(gpui::WindowOptions::default(), |cx| cx.new_view(|_| gpui::Empty));
window.update(cx, |_, cx| {
let response = cx.prompt(gpui::PromptLevel::Critical, "Zed failed to launch", Some(&format!("{}\n\nFor help resolving this, please open an issue on https://github.com/zed-industries/zed", e)), &["Exit"]);
if let Ok(window) = cx.open_window(gpui::WindowOptions::default(), |cx| cx.new_view(|_| gpui::Empty)) {
window.update(cx, |_, cx| {
let response = cx.prompt(gpui::PromptLevel::Critical, "Zed failed to launch", Some(&format!("{}\n\nFor help resolving this, please open an issue on https://github.com/zed-industries/zed", e)), &["Exit"]);
cx.spawn(|_, mut cx| async move {
response.await?;
cx.update(|cx| {
cx.quit()
})
}).detach_and_log_err(cx);
}).log_err();
cx.spawn(|_, mut cx| async move {
response.await?;
cx.update(|cx| {
cx.quit()
})
}).detach_and_log_err(cx);
}).log_err();
} else {
fail_to_open_window(e, cx)
}
})
}
fn fail_to_open_window_async(e: anyhow::Error, cx: &mut AsyncAppContext) {
cx.update(|cx| fail_to_open_window(e, cx)).log_err();
}
fn fail_to_open_window(e: anyhow::Error, _cx: &mut AppContext) {
eprintln!("Zed failed to open a window: {:?}", e);
#[cfg(target_os = "linux")]
{
use ashpd::desktop::notification::{Notification, NotificationProxy, Priority};
_cx.spawn(|cx| async move {
let proxy = NotificationProxy::new().await?;
let notification_id = "dev.zed.Oops";
proxy
.add_notification(
notification_id,
Notification::new("Zed failed to launch")
.body(Some(format!("{:?}", e).as_str()))
.priority(Priority::High)
.icon(ashpd::desktop::Icon::with_names(&[
"dialog-question-symbolic",
])),
)
.await?;
cx.update(|cx| {
cx.quit();
})
})
.detach();
}
}
enum AppMode {
Headless(DevServerToken),
Ui,
@@ -122,10 +159,6 @@ fn init_ui(app_state: Arc<AppState>, cx: &mut AppContext) -> Result<()> {
}
};
if let Err(err) = cx.can_open_windows() {
return Err(err);
}
SystemAppearance::init(cx);
load_embedded_fonts(cx);
@@ -319,7 +352,11 @@ fn main() {
{
cx.spawn({
let app_state = app_state.clone();
|cx| async move { restore_or_create_workspace(app_state, cx).await }
|mut cx| async move {
if let Err(e) = restore_or_create_workspace(app_state, &mut cx).await {
fail_to_open_window_async(e, &mut cx)
}
}
})
.detach();
}
@@ -421,7 +458,11 @@ fn main() {
init_ui(app_state.clone(), cx).unwrap();
cx.spawn({
let app_state = app_state.clone();
|cx| async move { restore_or_create_workspace(app_state, cx).await }
|mut cx| async move {
if let Err(e) = restore_or_create_workspace(app_state, &mut cx).await {
fail_to_open_window_async(e, &mut cx)
}
}
})
.detach();
}
@@ -448,13 +489,12 @@ fn handle_open_request(request: OpenRequest, app_state: Arc<AppState>, cx: &mut
let app_state = app_state.clone();
cx.spawn(move |cx| handle_cli_connection(connection, app_state, cx))
.detach();
return;
}
if let Err(e) = init_ui(app_state.clone(), cx) {
log::error!("{}", e);
fail_to_open_window(e, cx);
return;
}
};
let mut task = None;
if !request.open_paths.is_empty() {
@@ -478,48 +518,59 @@ fn handle_open_request(request: OpenRequest, app_state: Arc<AppState>, cx: &mut
if !request.open_channel_notes.is_empty() || request.join_channel.is_some() {
cx.spawn(|mut cx| async move {
if let Some(task) = task {
task.await?;
}
let client = app_state.client.clone();
// we continue even if authentication fails as join_channel/ open channel notes will
// show a visible error message.
authenticate(client, &cx).await.log_err();
let result = maybe!(async {
if let Some(task) = task {
task.await?;
}
let client = app_state.client.clone();
// we continue even if authentication fails as join_channel/ open channel notes will
// show a visible error message.
authenticate(client, &cx).await.log_err();
if let Some(channel_id) = request.join_channel {
cx.update(|cx| {
workspace::join_channel(
client::ChannelId(channel_id),
app_state.clone(),
None,
cx,
)
})?
.await?;
}
if let Some(channel_id) = request.join_channel {
cx.update(|cx| {
workspace::join_channel(
client::ChannelId(channel_id),
app_state.clone(),
None,
cx,
)
})?
.await?;
}
let workspace_window =
workspace::get_any_active_workspace(app_state, cx.clone()).await?;
let workspace = workspace_window.root_view(&cx)?;
let workspace_window =
workspace::get_any_active_workspace(app_state, cx.clone()).await?;
let workspace = workspace_window.root_view(&cx)?;
let mut promises = Vec::new();
for (channel_id, heading) in request.open_channel_notes {
promises.push(cx.update_window(workspace_window.into(), |_, cx| {
ChannelView::open(
client::ChannelId(channel_id),
heading,
workspace.clone(),
cx,
)
.log_err()
})?)
let mut promises = Vec::new();
for (channel_id, heading) in request.open_channel_notes {
promises.push(cx.update_window(workspace_window.into(), |_, cx| {
ChannelView::open(
client::ChannelId(channel_id),
heading,
workspace.clone(),
cx,
)
.log_err()
})?)
}
future::join_all(promises).await;
anyhow::Ok(())
})
.await;
if let Err(err) = result {
fail_to_open_window_async(err, &mut cx);
}
future::join_all(promises).await;
anyhow::Ok(())
})
.detach_and_log_err(cx);
.detach()
} else if let Some(task) = task {
task.detach_and_log_err(cx)
cx.spawn(|mut cx| async move {
if let Err(err) = task.await {
fail_to_open_window_async(err, &mut cx);
}
})
.detach();
}
}
@@ -562,41 +613,39 @@ async fn installation_id() -> Result<(String, bool)> {
Ok((installation_id, false))
}
async fn restore_or_create_workspace(app_state: Arc<AppState>, cx: AsyncAppContext) {
maybe!(async {
let restore_behaviour =
cx.update(|cx| WorkspaceSettings::get(None, cx).restore_on_startup)?;
let location = match restore_behaviour {
workspace::RestoreOnStartupBehaviour::LastWorkspace => {
workspace::last_opened_workspace_paths().await
}
_ => None,
};
if let Some(location) = location {
cx.update(|cx| {
workspace::open_paths(
location.paths().as_ref(),
app_state,
workspace::OpenOptions::default(),
cx,
)
})?
.await
.log_err();
} else if matches!(KEY_VALUE_STORE.read_kvp(FIRST_OPEN), Ok(None)) {
cx.update(|cx| show_welcome_view(app_state, cx)).log_err();
} else {
cx.update(|cx| {
workspace::open_new(app_state, cx, |workspace, cx| {
Editor::new_file(workspace, &Default::default(), cx)
})
.detach();
})?;
async fn restore_or_create_workspace(
app_state: Arc<AppState>,
cx: &mut AsyncAppContext,
) -> Result<()> {
let restore_behaviour = cx.update(|cx| WorkspaceSettings::get(None, cx).restore_on_startup)?;
let location = match restore_behaviour {
workspace::RestoreOnStartupBehaviour::LastWorkspace => {
workspace::last_opened_workspace_paths().await
}
anyhow::Ok(())
})
.await
.log_err();
_ => None,
};
if let Some(location) = location {
cx.update(|cx| {
workspace::open_paths(
location.paths().as_ref(),
app_state,
workspace::OpenOptions::default(),
cx,
)
})?
.await?;
} else if matches!(KEY_VALUE_STORE.read_kvp(FIRST_OPEN), Ok(None)) {
cx.update(|cx| show_welcome_view(app_state, cx))?.await?;
} else {
cx.update(|cx| {
workspace::open_new(app_state, cx, |workspace, cx| {
Editor::new_file(workspace, &Default::default(), cx)
})
})?
.await?;
}
Ok(())
}
fn init_paths() -> anyhow::Result<()> {

View File

@@ -1314,7 +1314,8 @@ mod tests {
Editor::new_file(workspace, &Default::default(), cx)
})
})
.await;
.await
.unwrap();
cx.run_until_parked();
let workspace = cx