Merge remote-tracking branch 'origin/main' into ownership-post

This commit is contained in:
Nathan Sobo 2024-01-18 07:01:54 -07:00
commit 9e37232a13
21 changed files with 119 additions and 128 deletions

View file

@ -93,7 +93,9 @@ pub fn init(http_client: Arc<dyn HttpClient>, server_url: String, cx: &mut AppCo
cx.observe_new_views(|workspace: &mut Workspace, _cx| { cx.observe_new_views(|workspace: &mut Workspace, _cx| {
workspace.register_action(|_, action: &Check, cx| check(action, cx)); workspace.register_action(|_, action: &Check, cx| check(action, cx));
workspace.register_action(|_, action, cx| view_release_notes(action, cx)); workspace.register_action(|_, action, cx| {
view_release_notes(action, cx);
});
// @nate - code to trigger update notification on launch // @nate - code to trigger update notification on launch
// todo!("remove this when Nate is done") // todo!("remove this when Nate is done")
@ -140,24 +142,23 @@ pub fn check(_: &Check, cx: &mut WindowContext) {
} }
} }
pub fn view_release_notes(_: &ViewReleaseNotes, cx: &mut AppContext) { pub fn view_release_notes(_: &ViewReleaseNotes, cx: &mut AppContext) -> Option<()> {
if let Some(auto_updater) = AutoUpdater::get(cx) { let auto_updater = AutoUpdater::get(cx)?;
let release_channel = cx.try_global::<ReleaseChannel>()?;
if matches!(
release_channel,
ReleaseChannel::Stable | ReleaseChannel::Preview
) {
let auto_updater = auto_updater.read(cx); let auto_updater = auto_updater.read(cx);
let server_url = &auto_updater.server_url; let server_url = &auto_updater.server_url;
let release_channel = release_channel.dev_name();
let current_version = auto_updater.current_version; let current_version = auto_updater.current_version;
if cx.has_global::<ReleaseChannel>() { let url = format!("{server_url}/releases/{release_channel}/{current_version}");
match cx.global::<ReleaseChannel>() { cx.open_url(&url);
ReleaseChannel::Dev => {}
ReleaseChannel::Nightly => {}
ReleaseChannel::Preview => {
cx.open_url(&format!("{server_url}/releases/preview/{current_version}"))
}
ReleaseChannel::Stable => {
cx.open_url(&format!("{server_url}/releases/stable/{current_version}"))
}
}
}
} }
None
} }
pub fn notify_of_any_new_update(cx: &mut ViewContext<Workspace>) -> Option<()> { pub fn notify_of_any_new_update(cx: &mut ViewContext<Workspace>) -> Option<()> {
@ -257,11 +258,13 @@ impl AutoUpdater {
"{server_url}/api/releases/latest?token={ZED_SECRET_CLIENT_TOKEN}&asset=Zed.dmg" "{server_url}/api/releases/latest?token={ZED_SECRET_CLIENT_TOKEN}&asset=Zed.dmg"
); );
cx.update(|cx| { cx.update(|cx| {
if cx.has_global::<ReleaseChannel>() { if let Some(param) = cx
if let Some(param) = cx.global::<ReleaseChannel>().release_query_param() { .try_global::<ReleaseChannel>()
url_string += "&"; .map(|release_channel| release_channel.release_query_param())
url_string += param; .flatten()
} {
url_string += "&";
url_string += param;
} }
})?; })?;
@ -313,8 +316,8 @@ impl AutoUpdater {
let (installation_id, release_channel, telemetry) = cx.update(|cx| { let (installation_id, release_channel, telemetry) = cx.update(|cx| {
let installation_id = cx.global::<Arc<Client>>().telemetry().installation_id(); let installation_id = cx.global::<Arc<Client>>().telemetry().installation_id();
let release_channel = cx let release_channel = cx
.has_global::<ReleaseChannel>() .try_global::<ReleaseChannel>()
.then(|| cx.global::<ReleaseChannel>().display_name()); .map(|release_channel| release_channel.display_name());
let telemetry = TelemetrySettings::get_global(cx).metrics; let telemetry = TelemetrySettings::get_global(cx).metrics;
(installation_id, release_channel, telemetry) (installation_id, release_channel, telemetry)

View file

@ -40,7 +40,9 @@ impl Render for UpdateNotification {
.id("notes") .id("notes")
.child(Label::new("View the release notes")) .child(Label::new("View the release notes"))
.cursor_pointer() .cursor_pointer()
.on_click(|_, cx| crate::view_release_notes(&Default::default(), cx)), .on_click(|_, cx| {
crate::view_release_notes(&Default::default(), cx);
}),
) )
} }
} }

View file

@ -150,11 +150,9 @@ const FLUSH_INTERVAL: Duration = Duration::from_secs(60 * 5);
impl Telemetry { impl Telemetry {
pub fn new(client: Arc<dyn HttpClient>, cx: &mut AppContext) -> Arc<Self> { pub fn new(client: Arc<dyn HttpClient>, cx: &mut AppContext) -> Arc<Self> {
let release_channel = if cx.has_global::<ReleaseChannel>() { let release_channel = cx
Some(cx.global::<ReleaseChannel>().display_name()) .try_global::<ReleaseChannel>()
} else { .map(|release_channel| release_channel.display_name());
None
};
TelemetrySettings::register(cx); TelemetrySettings::register(cx);

View file

@ -308,11 +308,7 @@ impl EventEmitter<Event> for Copilot {}
impl Copilot { impl Copilot {
pub fn global(cx: &AppContext) -> Option<Model<Self>> { pub fn global(cx: &AppContext) -> Option<Model<Self>> {
if cx.has_global::<Model<Self>>() { cx.try_global::<Model<Self>>().map(|model| model.clone())
Some(cx.global::<Model<Self>>().clone())
} else {
None
}
} }
fn start( fn start(
@ -373,10 +369,11 @@ impl Copilot {
#[cfg(any(test, feature = "test-support"))] #[cfg(any(test, feature = "test-support"))]
pub fn fake(cx: &mut gpui::TestAppContext) -> (Model<Self>, lsp::FakeLanguageServer) { pub fn fake(cx: &mut gpui::TestAppContext) -> (Model<Self>, lsp::FakeLanguageServer) {
use lsp::FakeLanguageServer;
use node_runtime::FakeNodeRuntime; use node_runtime::FakeNodeRuntime;
let (server, fake_server) = let (server, fake_server) =
LanguageServer::fake("copilot".into(), Default::default(), cx.to_async()); FakeLanguageServer::new("copilot".into(), Default::default(), cx.to_async());
let http = util::http::FakeHttpClient::create(|_| async { unreachable!() }); let http = util::http::FakeHttpClient::create(|_| async { unreachable!() });
let node_runtime = FakeNodeRuntime::new(); let node_runtime = FakeNodeRuntime::new();
let this = cx.new_model(|cx| Self { let this = cx.new_model(|cx| Self {

View file

@ -57,18 +57,14 @@ impl FeatureFlagAppExt for AppContext {
} }
fn has_flag<T: FeatureFlag>(&self) -> bool { fn has_flag<T: FeatureFlag>(&self) -> bool {
if self.has_global::<FeatureFlags>() { self.try_global::<FeatureFlags>()
self.global::<FeatureFlags>().has_flag(T::NAME) .map(|flags| flags.has_flag(T::NAME))
} else { .unwrap_or(false)
false
}
} }
fn is_staff(&self) -> bool { fn is_staff(&self) -> bool {
if self.has_global::<FeatureFlags>() { self.try_global::<FeatureFlags>()
return self.global::<FeatureFlags>().staff; .map(|flags| flags.staff)
} else { .unwrap_or(false)
false
}
} }
} }

View file

@ -201,6 +201,7 @@ pub trait PlatformDispatcher: Send + Sync {
pub(crate) trait PlatformTextSystem: Send + Sync { pub(crate) trait PlatformTextSystem: Send + Sync {
fn add_fonts(&self, fonts: &[Arc<Vec<u8>>]) -> Result<()>; fn add_fonts(&self, fonts: &[Arc<Vec<u8>>]) -> Result<()>;
fn all_font_names(&self) -> Vec<String>; fn all_font_names(&self) -> Vec<String>;
fn all_font_families(&self) -> Vec<String>;
fn font_id(&self, descriptor: &Font) -> Result<FontId>; fn font_id(&self, descriptor: &Font) -> Result<FontId>;
fn font_metrics(&self, font_id: FontId) -> FontMetrics; fn font_metrics(&self, font_id: FontId) -> FontMetrics;
fn typographic_bounds(&self, font_id: FontId, glyph_id: GlyphId) -> Result<Bounds<f32>>; fn typographic_bounds(&self, font_id: FontId, glyph_id: GlyphId) -> Result<Bounds<f32>>;
@ -282,8 +283,6 @@ pub(crate) trait PlatformAtlas: Send + Sync {
key: &AtlasKey, key: &AtlasKey,
build: &mut dyn FnMut() -> Result<(Size<DevicePixels>, Cow<'a, [u8]>)>, build: &mut dyn FnMut() -> Result<(Size<DevicePixels>, Cow<'a, [u8]>)>,
) -> Result<AtlasTile>; ) -> Result<AtlasTile>;
fn clear(&self);
} }
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]

View file

@ -74,20 +74,6 @@ impl PlatformAtlas for MetalAtlas {
Ok(tile) Ok(tile)
} }
} }
fn clear(&self) {
let mut lock = self.0.lock();
lock.tiles_by_key.clear();
for texture in &mut lock.monochrome_textures {
texture.clear();
}
for texture in &mut lock.polychrome_textures {
texture.clear();
}
for texture in &mut lock.path_textures {
texture.clear();
}
}
} }
impl MetalAtlasState { impl MetalAtlasState {

View file

@ -85,7 +85,9 @@ impl PlatformTextSystem for MacTextSystem {
}; };
let mut names = BTreeSet::new(); let mut names = BTreeSet::new();
for descriptor in descriptors.into_iter() { for descriptor in descriptors.into_iter() {
names.insert(descriptor.display_name()); names.insert(descriptor.font_name());
names.insert(descriptor.family_name());
names.insert(descriptor.style_name());
} }
if let Ok(fonts_in_memory) = self.0.read().memory_source.all_families() { if let Ok(fonts_in_memory) = self.0.read().memory_source.all_families() {
names.extend(fonts_in_memory); names.extend(fonts_in_memory);
@ -93,6 +95,14 @@ impl PlatformTextSystem for MacTextSystem {
names.into_iter().collect() names.into_iter().collect()
} }
fn all_font_families(&self) -> Vec<String> {
self.0
.read()
.system_source
.all_families()
.expect("core text should never return an error")
}
fn font_id(&self, font: &Font) -> Result<FontId> { fn font_id(&self, font: &Font) -> Result<FontId> {
let lock = self.0.upgradable_read(); let lock = self.0.upgradable_read();
if let Some(font_id) = lock.font_selections.get(font) { if let Some(font_id) = lock.font_selections.get(font) {

View file

@ -325,10 +325,4 @@ impl PlatformAtlas for TestAtlas {
Ok(state.tiles[key].clone()) Ok(state.tiles[key].clone())
} }
fn clear(&self) {
let mut state = self.0.lock();
state.tiles = HashMap::default();
state.next_id = 0;
}
} }

View file

@ -13,7 +13,7 @@ use crate::{
SharedString, Size, UnderlineStyle, SharedString, Size, UnderlineStyle,
}; };
use anyhow::anyhow; use anyhow::anyhow;
use collections::{FxHashMap, FxHashSet}; use collections::{BTreeSet, FxHashMap, FxHashSet};
use core::fmt; use core::fmt;
use itertools::Itertools; use itertools::Itertools;
use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard}; use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard};
@ -66,15 +66,18 @@ impl TextSystem {
} }
pub fn all_font_names(&self) -> Vec<String> { pub fn all_font_names(&self) -> Vec<String> {
let mut families = self.platform_text_system.all_font_names(); let mut names: BTreeSet<_> = self
families.append( .platform_text_system
&mut self .all_font_names()
.fallback_font_stack .into_iter()
.collect();
names.extend(self.platform_text_system.all_font_families().into_iter());
names.extend(
self.fallback_font_stack
.iter() .iter()
.map(|font| font.family.to_string()) .map(|font| font.family.to_string()),
.collect(),
); );
families names.into_iter().collect()
} }
pub fn add_fonts(&self, fonts: &[Arc<Vec<u8>>]) -> Result<()> { pub fn add_fonts(&self, fonts: &[Arc<Vec<u8>>]) -> Result<()> {
self.platform_text_system.add_fonts(fonts) self.platform_text_system.add_fonts(fonts)

View file

@ -951,7 +951,7 @@ impl LanguageRegistry {
if language.fake_adapter.is_some() { if language.fake_adapter.is_some() {
let task = cx.spawn(|cx| async move { let task = cx.spawn(|cx| async move {
let (servers_tx, fake_adapter) = language.fake_adapter.as_ref().unwrap(); let (servers_tx, fake_adapter) = language.fake_adapter.as_ref().unwrap();
let (server, mut fake_server) = lsp::LanguageServer::fake( let (server, mut fake_server) = lsp::FakeLanguageServer::new(
fake_adapter.name.to_string(), fake_adapter.name.to_string(),
fake_adapter.capabilities.clone(), fake_adapter.capabilities.clone(),
cx.clone(), cx.clone(),

View file

@ -972,30 +972,18 @@ pub struct FakeLanguageServer {
} }
#[cfg(any(test, feature = "test-support"))] #[cfg(any(test, feature = "test-support"))]
impl LanguageServer { impl FakeLanguageServer {
pub fn full_capabilities() -> ServerCapabilities {
ServerCapabilities {
document_highlight_provider: Some(OneOf::Left(true)),
code_action_provider: Some(CodeActionProviderCapability::Simple(true)),
document_formatting_provider: Some(OneOf::Left(true)),
document_range_formatting_provider: Some(OneOf::Left(true)),
definition_provider: Some(OneOf::Left(true)),
type_definition_provider: Some(TypeDefinitionProviderCapability::Simple(true)),
..Default::default()
}
}
/// Construct a fake language server. /// Construct a fake language server.
pub fn fake( pub fn new(
name: String, name: String,
capabilities: ServerCapabilities, capabilities: ServerCapabilities,
cx: AsyncAppContext, cx: AsyncAppContext,
) -> (Self, FakeLanguageServer) { ) -> (LanguageServer, FakeLanguageServer) {
let (stdin_writer, stdin_reader) = async_pipe::pipe(); let (stdin_writer, stdin_reader) = async_pipe::pipe();
let (stdout_writer, stdout_reader) = async_pipe::pipe(); let (stdout_writer, stdout_reader) = async_pipe::pipe();
let (notifications_tx, notifications_rx) = channel::unbounded(); let (notifications_tx, notifications_rx) = channel::unbounded();
let server = Self::new_internal( let server = LanguageServer::new_internal(
LanguageServerId(0), LanguageServerId(0),
stdin_writer, stdin_writer,
stdout_reader, stdout_reader,
@ -1008,7 +996,7 @@ impl LanguageServer {
|_| {}, |_| {},
); );
let fake = FakeLanguageServer { let fake = FakeLanguageServer {
server: Arc::new(Self::new_internal( server: Arc::new(LanguageServer::new_internal(
LanguageServerId(0), LanguageServerId(0),
stdout_writer, stdout_writer,
stdin_reader, stdin_reader,
@ -1053,6 +1041,21 @@ impl LanguageServer {
} }
} }
#[cfg(any(test, feature = "test-support"))]
impl LanguageServer {
pub fn full_capabilities() -> ServerCapabilities {
ServerCapabilities {
document_highlight_provider: Some(OneOf::Left(true)),
code_action_provider: Some(CodeActionProviderCapability::Simple(true)),
document_formatting_provider: Some(OneOf::Left(true)),
document_range_formatting_provider: Some(OneOf::Left(true)),
definition_provider: Some(OneOf::Left(true)),
type_definition_provider: Some(TypeDefinitionProviderCapability::Simple(true)),
..Default::default()
}
}
}
#[cfg(any(test, feature = "test-support"))] #[cfg(any(test, feature = "test-support"))]
impl FakeLanguageServer { impl FakeLanguageServer {
/// See [`LanguageServer::notify`]. /// See [`LanguageServer::notify`].
@ -1188,7 +1191,7 @@ mod tests {
#[gpui::test] #[gpui::test]
async fn test_fake(cx: &mut TestAppContext) { async fn test_fake(cx: &mut TestAppContext) {
let (server, mut fake) = let (server, mut fake) =
LanguageServer::fake("the-lsp".to_string(), Default::default(), cx.to_async()); FakeLanguageServer::new("the-lsp".to_string(), Default::default(), cx.to_async());
let (message_tx, message_rx) = channel::unbounded(); let (message_tx, message_rx) = channel::unbounded();
let (diagnostics_tx, diagnostics_rx) = channel::unbounded(); let (diagnostics_tx, diagnostics_rx) = channel::unbounded();

View file

@ -42,7 +42,7 @@ impl FileAssociations {
} }
pub fn get_icon(path: &Path, cx: &AppContext) -> Option<Arc<str>> { pub fn get_icon(path: &Path, cx: &AppContext) -> Option<Arc<str>> {
let this = cx.has_global::<Self>().then(|| cx.global::<Self>())?; let this = cx.try_global::<Self>()?;
// FIXME: Associate a type with the languages and have the file's language // FIXME: Associate a type with the languages and have the file's language
// override these associations // override these associations
@ -58,7 +58,7 @@ impl FileAssociations {
} }
pub fn get_folder_icon(expanded: bool, cx: &AppContext) -> Option<Arc<str>> { pub fn get_folder_icon(expanded: bool, cx: &AppContext) -> Option<Arc<str>> {
let this = cx.has_global::<Self>().then(|| cx.global::<Self>())?; let this = cx.try_global::<Self>()?;
let key = if expanded { let key = if expanded {
EXPANDED_DIRECTORY_TYPE EXPANDED_DIRECTORY_TYPE
@ -72,7 +72,7 @@ impl FileAssociations {
} }
pub fn get_chevron_icon(expanded: bool, cx: &AppContext) -> Option<Arc<str>> { pub fn get_chevron_icon(expanded: bool, cx: &AppContext) -> Option<Arc<str>> {
let this = cx.has_global::<Self>().then(|| cx.global::<Self>())?; let this = cx.try_global::<Self>()?;
let key = if expanded { let key = if expanded {
EXPANDED_CHEVRON_TYPE EXPANDED_CHEVRON_TYPE

View file

@ -638,6 +638,12 @@ impl BufferSearchBar {
registrar.register_handler(|this, _: &editor::actions::Cancel, cx| { registrar.register_handler(|this, _: &editor::actions::Cancel, cx| {
this.dismiss(&Dismiss, cx); this.dismiss(&Dismiss, cx);
}); });
// register deploy buffer search for both search bar states, since we want to focus into the search bar
// when the deploy action is triggered in the buffer.
registrar.register_handler(|this, deploy, cx| {
this.deploy(deploy, cx);
});
registrar.register_handler_for_dismissed_search(|this, deploy, cx| { registrar.register_handler_for_dismissed_search(|this, deploy, cx| {
this.deploy(deploy, cx); this.deploy(deploy, cx);
}) })

View file

@ -275,11 +275,8 @@ pub struct SearchResult {
impl SemanticIndex { impl SemanticIndex {
pub fn global(cx: &mut AppContext) -> Option<Model<SemanticIndex>> { pub fn global(cx: &mut AppContext) -> Option<Model<SemanticIndex>> {
if cx.has_global::<Model<Self>>() { cx.try_global::<Model<Self>>()
Some(cx.global::<Model<SemanticIndex>>().clone()) .map(|semantic_index| semantic_index.clone())
} else {
None
}
} }
pub fn authenticate(&mut self, cx: &mut AppContext) -> bool { pub fn authenticate(&mut self, cx: &mut AppContext) -> bool {

View file

@ -28,11 +28,10 @@ impl ModeIndicator {
fn update_mode(&mut self, cx: &mut ViewContext<Self>) { fn update_mode(&mut self, cx: &mut ViewContext<Self>) {
// Vim doesn't exist in some tests // Vim doesn't exist in some tests
if !cx.has_global::<Vim>() { let Some(vim) = cx.try_global::<Vim>() else {
return; return;
} };
let vim = Vim::read(cx);
if vim.enabled { if vim.enabled {
self.mode = Some(vim.state().mode); self.mode = Some(vim.state().mode);
} else { } else {

View file

@ -586,13 +586,9 @@ impl<T: Item> ItemHandle for View<T> {
} }
fn to_followable_item_handle(&self, cx: &AppContext) -> Option<Box<dyn FollowableItemHandle>> { fn to_followable_item_handle(&self, cx: &AppContext) -> Option<Box<dyn FollowableItemHandle>> {
if cx.has_global::<FollowableItemBuilders>() { let builders = cx.try_global::<FollowableItemBuilders>()?;
let builders = cx.global::<FollowableItemBuilders>(); let item = self.to_any();
let item = self.to_any(); Some(builders.get(&item.entity_type())?.1(&item))
Some(builders.get(&item.entity_type())?.1(&item))
} else {
None
}
} }
fn on_release( fn on_release(

View file

@ -195,7 +195,7 @@ struct NavHistoryState {
next_timestamp: Arc<AtomicUsize>, next_timestamp: Arc<AtomicUsize>,
} }
#[derive(Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub enum NavigationMode { pub enum NavigationMode {
Normal, Normal,
GoingBack, GoingBack,
@ -1462,7 +1462,7 @@ impl Pane {
.icon_size(IconSize::Small) .icon_size(IconSize::Small)
.on_click({ .on_click({
let view = cx.view().clone(); let view = cx.view().clone();
move |_, cx| view.update(cx, Self::navigate_backward) move |_, cx| view.update(cx, Self::navigate_forward)
}) })
.disabled(!self.can_navigate_forward()) .disabled(!self.can_navigate_forward())
.tooltip(|cx| Tooltip::for_action("Go Forward", &GoForward, cx)), .tooltip(|cx| Tooltip::for_action("Go Forward", &GoForward, cx)),

View file

@ -698,6 +698,7 @@ mod element {
workspace workspace
.update(cx, |this, cx| this.schedule_serialize(cx)) .update(cx, |this, cx| this.schedule_serialize(cx))
.log_err(); .log_err();
cx.stop_propagation();
cx.refresh(); cx.refresh();
} }
@ -754,8 +755,10 @@ mod element {
workspace workspace
.update(cx, |this, cx| this.schedule_serialize(cx)) .update(cx, |this, cx| this.schedule_serialize(cx))
.log_err(); .log_err();
cx.refresh(); cx.refresh();
} }
cx.stop_propagation();
} }
} }
}); });

View file

@ -616,8 +616,8 @@ impl Workspace {
let modal_layer = cx.new_view(|_| ModalLayer::new()); let modal_layer = cx.new_view(|_| ModalLayer::new());
let mut active_call = None; let mut active_call = None;
if cx.has_global::<Model<ActiveCall>>() { if let Some(call) = cx.try_global::<Model<ActiveCall>>() {
let call = cx.global::<Model<ActiveCall>>().clone(); let call = call.clone();
let mut subscriptions = Vec::new(); let mut subscriptions = Vec::new();
subscriptions.push(cx.subscribe(&call, Self::on_active_call_event)); subscriptions.push(cx.subscribe(&call, Self::on_active_call_event));
active_call = Some((call, subscriptions)); active_call = Some((call, subscriptions));
@ -3686,11 +3686,8 @@ impl WorkspaceStore {
update: proto::update_followers::Variant, update: proto::update_followers::Variant,
cx: &AppContext, cx: &AppContext,
) -> Option<()> { ) -> Option<()> {
if !cx.has_global::<Model<ActiveCall>>() { let active_call = cx.try_global::<Model<ActiveCall>>()?;
return None; let room_id = active_call.read(cx).room()?.read(cx).id();
}
let room_id = ActiveCall::global(cx).read(cx).room()?.read(cx).id();
let follower_ids: Vec<_> = self let follower_ids: Vec<_> = self
.followers .followers
.iter() .iter()

View file

@ -102,13 +102,15 @@ fn main() {
let open_listener = listener.clone(); let open_listener = listener.clone();
app.on_open_urls(move |urls, _| open_listener.open_urls(&urls)); app.on_open_urls(move |urls, _| open_listener.open_urls(&urls));
app.on_reopen(move |cx| { app.on_reopen(move |cx| {
if cx.has_global::<Weak<AppState>>() { if let Some(app_state) = cx
if let Some(app_state) = cx.global::<Weak<AppState>>().upgrade() { .try_global::<Weak<AppState>>()
workspace::open_new(&app_state, cx, |workspace, cx| { .map(|app_state| app_state.upgrade())
Editor::new_file(workspace, &Default::default(), cx) .flatten()
}) {
.detach(); workspace::open_new(&app_state, cx, |workspace, cx| {
} Editor::new_file(workspace, &Default::default(), cx)
})
.detach();
} }
}); });