Detailed changes
@@ -16,9 +16,9 @@ use rust_embed::RustEmbed;
pub struct Assets;
impl AssetSource for Assets {
- fn load(&self, path: &str) -> Result<std::borrow::Cow<'static, [u8]>> {
+ fn load(&self, path: &str) -> Result<Option<std::borrow::Cow<'static, [u8]>>> {
Self::get(path)
- .map(|f| f.data)
+ .map(|f| Some(f.data))
.ok_or_else(|| anyhow!("could not find asset at path \"{}\"", path))
}
@@ -42,7 +42,10 @@ impl Assets {
let mut embedded_fonts = Vec::new();
for font_path in font_paths {
if font_path.ends_with(".ttf") {
- let font_bytes = cx.asset_source().load(&font_path)?;
+ let font_bytes = cx
+ .asset_source()
+ .load(&font_path)?
+ .expect("Assets should never return None");
embedded_fonts.push(font_bytes);
}
}
@@ -41,7 +41,12 @@ impl SoundRegistry {
}
let path = format!("sounds/{}.wav", name);
- let bytes = self.assets.load(&path)?.into_owned();
+ let bytes = self
+ .assets
+ .load(&path)?
+ .map(|asset| Ok(asset))
+ .unwrap_or_else(|| Err(anyhow::anyhow!("No such asset available")))?
+ .into_owned();
let cursor = Cursor::new(bytes);
let source = Decoder::new(cursor)?.convert_samples::<f32>().buffered();
@@ -42,7 +42,7 @@ use std::{
},
};
use text::Point;
-use workspace::{Workspace, WorkspaceId};
+use workspace::Workspace;
#[gpui::test(iterations = 10)]
async fn test_host_disconnect(
@@ -85,14 +85,8 @@ async fn test_host_disconnect(
assert!(worktree_a.read_with(cx_a, |tree, _| tree.as_local().unwrap().is_shared()));
- let workspace_b = cx_b.add_window(|cx| {
- Workspace::new(
- WorkspaceId::default(),
- project_b.clone(),
- client_b.app_state.clone(),
- cx,
- )
- });
+ let workspace_b = cx_b
+ .add_window(|cx| Workspace::new(None, project_b.clone(), client_b.app_state.clone(), cx));
let cx_b = &mut VisualTestContext::from_window(*workspace_b, cx_b);
let workspace_b_view = workspace_b.root_view(cx_b).unwrap();
@@ -42,7 +42,7 @@ use std::{
Arc,
},
};
-use workspace::{Workspace, WorkspaceId, WorkspaceStore};
+use workspace::{Workspace, WorkspaceStore};
pub struct TestServer {
pub app_state: Arc<AppState>,
@@ -906,12 +906,7 @@ impl TestClient {
) -> (View<Workspace>, &'a mut VisualTestContext) {
cx.add_window_view(|cx| {
cx.activate_window();
- Workspace::new(
- WorkspaceId::default(),
- project.clone(),
- self.app_state.clone(),
- cx,
- )
+ Workspace::new(None, project.clone(), self.app_state.clone(), cx)
})
}
@@ -922,12 +917,7 @@ impl TestClient {
let project = self.build_test_project(cx).await;
cx.add_window_view(|cx| {
cx.activate_window();
- Workspace::new(
- WorkspaceId::default(),
- project.clone(),
- self.app_state.clone(),
- cx,
- )
+ Workspace::new(None, project.clone(), self.app_state.clone(), cx)
})
}
@@ -400,7 +400,11 @@ impl Item for ChannelView {
None
}
- fn clone_on_split(&self, _: WorkspaceId, cx: &mut ViewContext<Self>) -> Option<View<Self>> {
+ fn clone_on_split(
+ &self,
+ _: Option<WorkspaceId>,
+ cx: &mut ViewContext<Self>,
+ ) -> Option<View<Self>> {
Some(cx.new_view(|cx| {
Self::new(
self.project.clone(),
@@ -704,7 +704,7 @@ impl Item for ProjectDiagnosticsEditor {
fn clone_on_split(
&self,
- _workspace_id: workspace::WorkspaceId,
+ _workspace_id: Option<workspace::WorkspaceId>,
cx: &mut ViewContext<Self>,
) -> Option<View<Self>>
where
@@ -484,7 +484,7 @@ pub struct Editor {
current_line_highlight: CurrentLineHighlight,
collapse_matches: bool,
autoindent_mode: Option<AutoindentMode>,
- workspace: Option<(WeakView<Workspace>, WorkspaceId)>,
+ workspace: Option<(WeakView<Workspace>, Option<WorkspaceId>)>,
keymap_context_layers: BTreeMap<TypeId, KeyContext>,
input_enabled: bool,
use_modal_editing: bool,
@@ -657,7 +657,7 @@ impl Item for Editor {
fn clone_on_split(
&self,
- _workspace_id: WorkspaceId,
+ _workspace_id: Option<WorkspaceId>,
cx: &mut ViewContext<Self>,
) -> Option<View<Editor>>
where
@@ -846,9 +846,12 @@ impl Item for Editor {
}
fn added_to_workspace(&mut self, workspace: &mut Workspace, cx: &mut ViewContext<Self>) {
- let workspace_id = workspace.database_id();
- let item_id = cx.view().item_id().as_u64() as ItemId;
self.workspace = Some((workspace.weak_handle(), workspace.database_id()));
+ let Some(workspace_id) = workspace.database_id() else {
+ return;
+ };
+
+ let item_id = cx.view().item_id().as_u64() as ItemId;
fn serialize(
buffer: Model<Buffer>,
@@ -873,7 +876,7 @@ impl Item for Editor {
serialize(buffer.clone(), workspace_id, item_id, cx);
cx.subscribe(&buffer, |this, buffer, event, cx| {
- if let Some((_, workspace_id)) = this.workspace.as_ref() {
+ if let Some((_, Some(workspace_id))) = this.workspace.as_ref() {
if let language::Event::FileHandleChanged = event {
serialize(
buffer,
@@ -389,7 +389,8 @@ impl Editor {
cx: &mut ViewContext<Self>,
) {
hide_hover(self, cx);
- let workspace_id = self.workspace.as_ref().map(|workspace| workspace.1);
+ let workspace_id = self.workspace.as_ref().and_then(|workspace| workspace.1);
+
self.scroll_manager.set_scroll_position(
scroll_position,
&display_map,
@@ -409,7 +410,7 @@ impl Editor {
pub fn set_scroll_anchor(&mut self, scroll_anchor: ScrollAnchor, cx: &mut ViewContext<Self>) {
hide_hover(self, cx);
- let workspace_id = self.workspace.as_ref().map(|workspace| workspace.1);
+ let workspace_id = self.workspace.as_ref().and_then(|workspace| workspace.1);
let top_row = scroll_anchor
.anchor
.to_point(&self.buffer().read(cx).snapshot(cx))
@@ -424,7 +425,7 @@ impl Editor {
cx: &mut ViewContext<Self>,
) {
hide_hover(self, cx);
- let workspace_id = self.workspace.as_ref().map(|workspace| workspace.1);
+ let workspace_id = self.workspace.as_ref().and_then(|workspace| workspace.1);
let snapshot = &self.buffer().read(cx).snapshot(cx);
if !scroll_anchor.anchor.is_valid(snapshot) {
log::warn!("Invalid scroll anchor: {:?}", scroll_anchor);
@@ -992,7 +992,7 @@ impl Item for ExtensionsPage {
fn clone_on_split(
&self,
- _workspace_id: WorkspaceId,
+ _workspace_id: Option<WorkspaceId>,
_: &mut ViewContext<Self>,
) -> Option<View<Self>> {
None
@@ -38,11 +38,10 @@ impl FileIcons {
pub fn new(assets: impl AssetSource) -> Self {
assets
.load("icons/file_icons/file_types.json")
- .and_then(|file| {
- serde_json::from_str::<FileIcons>(str::from_utf8(&file).unwrap())
- .map_err(Into::into)
- })
- .unwrap_or_else(|_| FileIcons {
+ .ok()
+ .flatten()
+ .and_then(|file| serde_json::from_str::<FileIcons>(str::from_utf8(&file).unwrap()).ok())
+ .unwrap_or_else(|| FileIcons {
stems: HashMap::default(),
suffixes: HashMap::default(),
types: HashMap::default(),
@@ -5,8 +5,11 @@ use gpui::*;
struct Assets {}
impl AssetSource for Assets {
- fn load(&self, path: &str) -> Result<std::borrow::Cow<'static, [u8]>> {
- std::fs::read(path).map(Into::into).map_err(Into::into)
+ fn load(&self, path: &str) -> Result<Option<std::borrow::Cow<'static, [u8]>>> {
+ std::fs::read(path)
+ .map(Into::into)
+ .map_err(Into::into)
+ .map(|result| Some(result))
}
fn list(&self, path: &str) -> Result<Vec<SharedString>> {
@@ -1,5 +1,5 @@
use crate::{size, DevicePixels, Result, SharedString, Size};
-use anyhow::anyhow;
+
use image::{Bgra, ImageBuffer};
use std::{
borrow::Cow,
@@ -11,18 +11,15 @@ use std::{
/// A source of assets for this app to use.
pub trait AssetSource: 'static + Send + Sync {
/// Load the given asset from the source path.
- fn load(&self, path: &str) -> Result<Cow<'static, [u8]>>;
+ fn load(&self, path: &str) -> Result<Option<Cow<'static, [u8]>>>;
/// List the assets at the given path.
fn list(&self, path: &str) -> Result<Vec<SharedString>>;
}
impl AssetSource for () {
- fn load(&self, path: &str) -> Result<Cow<'static, [u8]>> {
- Err(anyhow!(
- "load called on empty asset provider with \"{}\"",
- path
- ))
+ fn load(&self, _path: &str) -> Result<Option<Cow<'static, [u8]>>> {
+ Ok(None)
}
fn list(&self, _path: &str) -> Result<Vec<SharedString>> {
@@ -344,8 +344,8 @@ pub(crate) trait PlatformAtlas: Send + Sync {
fn get_or_insert_with<'a>(
&self,
key: &AtlasKey,
- build: &mut dyn FnMut() -> Result<(Size<DevicePixels>, Cow<'a, [u8]>)>,
- ) -> Result<AtlasTile>;
+ build: &mut dyn FnMut() -> Result<Option<(Size<DevicePixels>, Cow<'a, [u8]>)>>,
+ ) -> Result<Option<AtlasTile>>;
}
#[derive(Clone, Debug, PartialEq, Eq)]
@@ -114,18 +114,20 @@ impl PlatformAtlas for BladeAtlas {
fn get_or_insert_with<'a>(
&self,
key: &AtlasKey,
- build: &mut dyn FnMut() -> Result<(Size<DevicePixels>, Cow<'a, [u8]>)>,
- ) -> Result<AtlasTile> {
+ build: &mut dyn FnMut() -> Result<Option<(Size<DevicePixels>, Cow<'a, [u8]>)>>,
+ ) -> Result<Option<AtlasTile>> {
let mut lock = self.0.lock();
if let Some(tile) = lock.tiles_by_key.get(key) {
- Ok(tile.clone())
+ Ok(Some(tile.clone()))
} else {
profiling::scope!("new tile");
- let (size, bytes) = build()?;
+ let Some((size, bytes)) = build()? else {
+ return Ok(None);
+ };
let tile = lock.allocate(size, key.texture_kind());
lock.upload_texture(tile.texture_id, tile.bounds, &bytes);
lock.tiles_by_key.insert(key.clone(), tile.clone());
- Ok(tile)
+ Ok(Some(tile))
}
}
}
@@ -60,20 +60,22 @@ impl PlatformAtlas for MetalAtlas {
fn get_or_insert_with<'a>(
&self,
key: &AtlasKey,
- build: &mut dyn FnMut() -> Result<(Size<DevicePixels>, Cow<'a, [u8]>)>,
- ) -> Result<AtlasTile> {
+ build: &mut dyn FnMut() -> Result<Option<(Size<DevicePixels>, Cow<'a, [u8]>)>>,
+ ) -> Result<Option<AtlasTile>> {
let mut lock = self.0.lock();
if let Some(tile) = lock.tiles_by_key.get(key) {
- Ok(tile.clone())
+ Ok(Some(tile.clone()))
} else {
- let (size, bytes) = build()?;
+ let Some((size, bytes)) = build()? else {
+ return Ok(None);
+ };
let tile = lock
.allocate(size, key.texture_kind())
.ok_or_else(|| anyhow!("failed to allocate"))?;
let texture = lock.texture(tile.texture_id);
texture.upload(tile.bounds, &bytes);
lock.tiles_by_key.insert(key.clone(), tile.clone());
- Ok(tile)
+ Ok(Some(tile))
}
}
}
@@ -291,25 +291,26 @@ impl PlatformAtlas for TestAtlas {
fn get_or_insert_with<'a>(
&self,
key: &crate::AtlasKey,
- build: &mut dyn FnMut() -> anyhow::Result<(
- Size<crate::DevicePixels>,
- std::borrow::Cow<'a, [u8]>,
- )>,
- ) -> anyhow::Result<crate::AtlasTile> {
+ build: &mut dyn FnMut() -> anyhow::Result<
+ Option<(Size<crate::DevicePixels>, std::borrow::Cow<'a, [u8]>)>,
+ >,
+ ) -> anyhow::Result<Option<crate::AtlasTile>> {
let mut state = self.0.lock();
if let Some(tile) = state.tiles.get(key) {
- return Ok(tile.clone());
+ return Ok(Some(tile.clone()));
}
+ drop(state);
+
+ let Some((size, _)) = build()? else {
+ return Ok(None);
+ };
+ let mut state = self.0.lock();
state.next_id += 1;
let texture_id = state.next_id;
state.next_id += 1;
let tile_id = state.next_id;
- drop(state);
- let (size, _) = build()?;
- let mut state = self.0.lock();
-
state.tiles.insert(
key.clone(),
crate::AtlasTile {
@@ -326,6 +327,6 @@ impl PlatformAtlas for TestAtlas {
},
);
- Ok(state.tiles[key].clone())
+ Ok(Some(state.tiles[key].clone()))
}
}
@@ -24,13 +24,15 @@ impl SvgRenderer {
Self { asset_source }
}
- pub fn render(&self, params: &RenderSvgParams) -> Result<Vec<u8>> {
+ pub fn render(&self, params: &RenderSvgParams) -> Result<Option<Vec<u8>>> {
if params.size.is_zero() {
return Err(anyhow!("can't render at a zero size"));
}
// Load the tree.
- let bytes = self.asset_source.load(¶ms.path)?;
+ let Some(bytes) = self.asset_source.load(¶ms.path)? else {
+ return Ok(None);
+ };
let pixmap = self.render_pixmap(&bytes, SvgSize::Size(params.size))?;
@@ -40,7 +42,7 @@ impl SvgRenderer {
.iter()
.map(|p| p.alpha())
.collect::<Vec<_>>();
- Ok(alpha_mask)
+ Ok(Some(alpha_mask))
}
pub fn render_pixmap(&self, bytes: &[u8], size: SvgSize) -> Result<Pixmap, usvg::Error> {
@@ -2347,13 +2347,14 @@ impl<'a> WindowContext<'a> {
let raster_bounds = self.text_system().raster_bounds(¶ms)?;
if !raster_bounds.is_zero() {
- let tile =
- self.window
- .sprite_atlas
- .get_or_insert_with(¶ms.clone().into(), &mut || {
- let (size, bytes) = self.text_system().rasterize_glyph(¶ms)?;
- Ok((size, Cow::Owned(bytes)))
- })?;
+ let tile = self
+ .window
+ .sprite_atlas
+ .get_or_insert_with(¶ms.clone().into(), &mut || {
+ let (size, bytes) = self.text_system().rasterize_glyph(¶ms)?;
+ Ok(Some((size, Cow::Owned(bytes))))
+ })?
+ .expect("Callback above only errors or returns Some");
let bounds = Bounds {
origin: glyph_origin.map(|px| px.floor()) + raster_bounds.origin.map(Into::into),
size: tile.bounds.size.map(Into::into),
@@ -2410,13 +2411,15 @@ impl<'a> WindowContext<'a> {
let raster_bounds = self.text_system().raster_bounds(¶ms)?;
if !raster_bounds.is_zero() {
- let tile =
- self.window
- .sprite_atlas
- .get_or_insert_with(¶ms.clone().into(), &mut || {
- let (size, bytes) = self.text_system().rasterize_glyph(¶ms)?;
- Ok((size, Cow::Owned(bytes)))
- })?;
+ let tile = self
+ .window
+ .sprite_atlas
+ .get_or_insert_with(¶ms.clone().into(), &mut || {
+ let (size, bytes) = self.text_system().rasterize_glyph(¶ms)?;
+ Ok(Some((size, Cow::Owned(bytes))))
+ })?
+ .expect("Callback above only errors or returns Some");
+
let bounds = Bounds {
origin: glyph_origin.map(|px| px.floor()) + raster_bounds.origin.map(Into::into),
size: tile.bounds.size.map(Into::into),
@@ -2464,13 +2467,18 @@ impl<'a> WindowContext<'a> {
.map(|pixels| DevicePixels::from((pixels.0 * 2.).ceil() as i32)),
};
- let tile =
+ let Some(tile) =
self.window
.sprite_atlas
.get_or_insert_with(¶ms.clone().into(), &mut || {
- let bytes = self.svg_renderer.render(¶ms)?;
- Ok((params.size, Cow::Owned(bytes)))
- })?;
+ let Some(bytes) = self.svg_renderer.render(¶ms)? else {
+ return Ok(None);
+ };
+ Ok(Some((params.size, Cow::Owned(bytes))))
+ })?
+ else {
+ return Ok(());
+ };
let content_mask = self.content_mask().scale(scale_factor);
self.window
@@ -2513,8 +2521,9 @@ impl<'a> WindowContext<'a> {
.window
.sprite_atlas
.get_or_insert_with(¶ms.clone().into(), &mut || {
- Ok((data.size(), Cow::Borrowed(data.as_bytes())))
- })?;
+ Ok(Some((data.size(), Cow::Borrowed(data.as_bytes()))))
+ })?
+ .expect("Callback above only returns Some");
let content_mask = self.content_mask().scale(scale_factor);
let corner_radii = corner_radii.scale(scale_factor);
@@ -95,17 +95,19 @@ impl Item for ImageView {
let workspace_id = workspace.database_id();
let image_path = self.path.clone();
- cx.background_executor()
- .spawn({
- let image_path = image_path.clone();
- async move {
- IMAGE_VIEWER
- .save_image_path(item_id, workspace_id, image_path)
- .await
- .log_err();
- }
- })
- .detach();
+ if let Some(workspace_id) = workspace_id {
+ cx.background_executor()
+ .spawn({
+ let image_path = image_path.clone();
+ async move {
+ IMAGE_VIEWER
+ .save_image_path(item_id, workspace_id, image_path)
+ .await
+ .log_err();
+ }
+ })
+ .detach();
+ }
}
fn serialized_item_kind() -> Option<&'static str> {
@@ -133,7 +135,7 @@ impl Item for ImageView {
fn clone_on_split(
&self,
- _workspace_id: WorkspaceId,
+ _workspace_id: Option<WorkspaceId>,
cx: &mut ViewContext<Self>,
) -> Option<View<Self>>
where
@@ -407,7 +407,7 @@ impl Item for SyntaxTreeView {
fn clone_on_split(
&self,
- _: workspace::WorkspaceId,
+ _: Option<workspace::WorkspaceId>,
cx: &mut ViewContext<Self>,
) -> Option<View<Self>>
where
@@ -287,7 +287,7 @@ impl PickerDelegate for RecentProjectsDelegate {
};
workspace
.update(cx, |workspace, cx| {
- if workspace.database_id() == *candidate_workspace_id {
+ if workspace.database_id() == Some(*candidate_workspace_id) {
Task::ready(Ok(()))
} else {
match candidate_workspace_location {
@@ -675,7 +675,7 @@ impl RecentProjectsDelegate {
) -> bool {
if let Some(workspace) = self.workspace.upgrade() {
let workspace = workspace.read(cx);
- if workspace_id == workspace.database_id() {
+ if Some(workspace_id) == workspace.database_id() {
return true;
}
}
@@ -456,7 +456,7 @@ impl Item for ProjectSearchView {
fn clone_on_split(
&self,
- _workspace_id: WorkspaceId,
+ _workspace_id: Option<WorkspaceId>,
cx: &mut ViewContext<Self>,
) -> Option<View<Self>>
where
@@ -283,7 +283,7 @@ impl Item for ProjectIndexDebugView {
fn clone_on_split(
&self,
- _: workspace::WorkspaceId,
+ _: Option<workspace::WorkspaceId>,
cx: &mut ViewContext<Self>,
) -> Option<View<Self>>
where
@@ -15,10 +15,11 @@ use rust_embed::RustEmbed;
pub struct Assets;
impl AssetSource for Assets {
- fn load(&self, path: &str) -> Result<Cow<'static, [u8]>> {
+ fn load(&self, path: &str) -> Result<Option<Cow<'static, [u8]>>> {
Self::get(path)
.map(|f| f.data)
.ok_or_else(|| anyhow!("could not find asset at path \"{}\"", path))
+ .map(|data| Some(data))
}
fn list(&self, path: &str) -> Result<Vec<SharedString>> {
@@ -128,7 +128,10 @@ fn load_embedded_fonts(cx: &AppContext) -> gpui::Result<()> {
let mut embedded_fonts = Vec::new();
for font_path in font_paths {
if font_path.ends_with(".ttf") {
- let font_bytes = cx.asset_source().load(&font_path)?;
+ let font_bytes = cx
+ .asset_source()
+ .load(&font_path)?
+ .expect("Should never be None in the storybook");
embedded_fonts.push(font_bytes);
}
}
@@ -221,7 +221,9 @@ impl TerminalPanel {
let (panel, pane, items) = workspace.update(&mut cx, |workspace, cx| {
let panel = cx.new_view(|cx| TerminalPanel::new(workspace, cx));
- let items = if let Some(serialized_panel) = serialized_panel.as_ref() {
+ let items = if let Some((serialized_panel, database_id)) =
+ serialized_panel.as_ref().zip(workspace.database_id())
+ {
panel.update(cx, |panel, cx| {
cx.notify();
panel.height = serialized_panel.height.map(|h| h.round());
@@ -234,7 +236,7 @@ impl TerminalPanel {
TerminalView::deserialize(
workspace.project().clone(),
workspace.weak_handle(),
- workspace.database_id(),
+ database_id,
*item_id,
cx,
)
@@ -91,7 +91,7 @@ pub struct TerminalView {
blinking_paused: bool,
blink_epoch: usize,
can_navigate_to_selected_word: bool,
- workspace_id: WorkspaceId,
+ workspace_id: Option<WorkspaceId>,
show_title: bool,
_subscriptions: Vec<Subscription>,
_terminal_subscriptions: Vec<Subscription>,
@@ -142,7 +142,7 @@ impl TerminalView {
pub fn new(
terminal: Model<Terminal>,
workspace: WeakView<Workspace>,
- workspace_id: WorkspaceId,
+ workspace_id: Option<WorkspaceId>,
cx: &mut ViewContext<Self>,
) -> Self {
let workspace_handle = workspace.clone();
@@ -458,15 +458,16 @@ fn subscribe_for_terminal_events(
if terminal.task().is_none() {
if let Some(cwd) = terminal.get_cwd() {
let item_id = cx.entity_id();
- let workspace_id = this.workspace_id;
- cx.background_executor()
- .spawn(async move {
- TERMINAL_DB
- .save_working_directory(item_id.as_u64(), workspace_id, cwd)
- .await
- .log_err();
- })
- .detach();
+ if let Some(workspace_id) = this.workspace_id {
+ cx.background_executor()
+ .spawn(async move {
+ TERMINAL_DB
+ .save_working_directory(item_id.as_u64(), workspace_id, cwd)
+ .await
+ .log_err();
+ })
+ .detach();
+ }
}
}
}
@@ -853,7 +854,7 @@ impl Item for TerminalView {
fn clone_on_split(
&self,
- _workspace_id: WorkspaceId,
+ _workspace_id: Option<WorkspaceId>,
_cx: &mut ViewContext<Self>,
) -> Option<View<Self>> {
//From what I can tell, there's no way to tell the current working
@@ -941,20 +942,18 @@ impl Item for TerminalView {
project.create_terminal(cwd, None, window, cx)
})??;
pane.update(&mut cx, |_, cx| {
- cx.new_view(|cx| TerminalView::new(terminal, workspace, workspace_id, cx))
+ cx.new_view(|cx| TerminalView::new(terminal, workspace, Some(workspace_id), cx))
})
})
}
fn added_to_workspace(&mut self, workspace: &mut Workspace, cx: &mut ViewContext<Self>) {
if self.terminal().read(cx).task().is_none() {
- cx.background_executor()
- .spawn(TERMINAL_DB.update_workspace_id(
- workspace.database_id(),
- self.workspace_id,
- cx.entity_id().as_u64(),
- ))
- .detach();
+ if let Some((new_id, old_id)) = workspace.database_id().zip(self.workspace_id) {
+ cx.background_executor()
+ .spawn(TERMINAL_DB.update_workspace_id(new_id, old_id, cx.entity_id().as_u64()))
+ .detach();
+ }
self.workspace_id = workspace.database_id();
}
}
@@ -1,5 +1,5 @@
-use std::path::Path;
use std::sync::Arc;
+use std::{fmt::Debug, path::Path};
use anyhow::{anyhow, Context, Result};
use collections::HashMap;
@@ -226,7 +226,7 @@ impl ThemeRegistry {
.filter(|path| path.ends_with(".json"));
for path in theme_paths {
- let Some(theme) = self.assets.load(&path).log_err() else {
+ let Some(theme) = self.assets.load(&path).log_err().flatten() else {
continue;
};
@@ -11,10 +11,11 @@ use rust_embed::RustEmbed;
pub struct Assets;
impl AssetSource for Assets {
- fn load(&self, path: &str) -> Result<Cow<'static, [u8]>> {
+ fn load(&self, path: &str) -> Result<Option<Cow<'static, [u8]>>> {
Self::get(path)
.map(|f| f.data)
.ok_or_else(|| anyhow!("could not find asset at path \"{}\"", path))
+ .map(|result| Some(result))
}
fn list(&self, path: &str) -> Result<Vec<SharedString>> {
@@ -313,7 +313,7 @@ impl Item for WelcomePage {
fn clone_on_split(
&self,
- _workspace_id: WorkspaceId,
+ _workspace_id: Option<WorkspaceId>,
cx: &mut ViewContext<Self>,
) -> Option<View<Self>> {
Some(cx.new_view(|cx| WelcomePage {
@@ -172,7 +172,7 @@ pub trait Item: FocusableView + EventEmitter<Self::Event> {
fn set_nav_history(&mut self, _: ItemNavHistory, _: &mut ViewContext<Self>) {}
fn clone_on_split(
&self,
- _workspace_id: WorkspaceId,
+ _workspace_id: Option<WorkspaceId>,
_: &mut ViewContext<Self>,
) -> Option<View<Self>>
where
@@ -287,7 +287,7 @@ pub trait ItemHandle: 'static + Send {
fn boxed_clone(&self) -> Box<dyn ItemHandle>;
fn clone_on_split(
&self,
- workspace_id: WorkspaceId,
+ workspace_id: Option<WorkspaceId>,
cx: &mut WindowContext,
) -> Option<Box<dyn ItemHandle>>;
fn added_to_pane(
@@ -437,7 +437,7 @@ impl<T: Item> ItemHandle for View<T> {
fn clone_on_split(
&self,
- workspace_id: WorkspaceId,
+ workspace_id: Option<WorkspaceId>,
cx: &mut WindowContext,
) -> Option<Box<dyn ItemHandle>> {
self.update(cx, |item, cx| item.clone_on_split(workspace_id, cx))
@@ -528,7 +528,6 @@ impl<T: Item> ItemHandle for View<T> {
{
pane
} else {
- log::error!("unexpected item event after pane was dropped");
return;
};
@@ -883,7 +882,7 @@ pub mod test {
}
pub struct TestItem {
- pub workspace_id: WorkspaceId,
+ pub workspace_id: Option<WorkspaceId>,
pub state: String,
pub label: String,
pub save_count: usize,
@@ -964,7 +963,7 @@ pub mod test {
pub fn new_deserialized(id: WorkspaceId, cx: &mut ViewContext<Self>) -> Self {
let mut this = Self::new(cx);
- this.workspace_id = id;
+ this.workspace_id = Some(id);
this
}
@@ -1081,7 +1080,7 @@ pub mod test {
fn clone_on_split(
&self,
- _workspace_id: WorkspaceId,
+ _workspace_id: Option<WorkspaceId>,
cx: &mut ViewContext<Self>,
) -> Option<View<Self>>
where
@@ -119,7 +119,7 @@ impl Item for SharedScreen {
fn clone_on_split(
&self,
- _workspace_id: WorkspaceId,
+ _workspace_id: Option<WorkspaceId>,
cx: &mut ViewContext<Self>,
) -> Option<View<Self>> {
let track = self.track.upgrade()?;
@@ -588,7 +588,7 @@ pub struct Workspace {
window_edited: bool,
active_call: Option<(Model<ActiveCall>, Vec<Subscription>)>,
leader_updates_tx: mpsc::UnboundedSender<(PeerId, proto::UpdateFollowers)>,
- database_id: WorkspaceId,
+ database_id: Option<WorkspaceId>,
app_state: Arc<AppState>,
dispatching_keystrokes: Rc<RefCell<Vec<Keystroke>>>,
_subscriptions: Vec<Subscription>,
@@ -622,7 +622,7 @@ impl Workspace {
const MAX_PADDING: f32 = 0.4;
pub fn new(
- workspace_id: WorkspaceId,
+ workspace_id: Option<WorkspaceId>,
project: Model<Project>,
app_state: Arc<AppState>,
cx: &mut ViewContext<Self>,
@@ -795,13 +795,15 @@ impl Workspace {
if let Some(display) = cx.display() {
if let Some(display_uuid) = display.uuid().log_err() {
let window_bounds = cx.window_bounds();
- cx.background_executor()
- .spawn(DB.set_window_open_status(
- workspace_id,
- SerializedWindowBounds(window_bounds),
- display_uuid,
- ))
- .detach_and_log_err(cx);
+ if let Some(database_id) = workspace_id {
+ cx.background_executor()
+ .spawn(DB.set_window_open_status(
+ database_id,
+ SerializedWindowBounds(window_bounds),
+ display_uuid,
+ ))
+ .detach_and_log_err(cx);
+ }
}
}
this.bounds_save_task_queued.take();
@@ -956,7 +958,12 @@ impl Workspace {
let window = if let Some(window) = requesting_window {
cx.update_window(window.into(), |_, cx| {
cx.replace_root_view(|cx| {
- Workspace::new(workspace_id, project_handle.clone(), app_state.clone(), cx)
+ Workspace::new(
+ Some(workspace_id),
+ project_handle.clone(),
+ app_state.clone(),
+ cx,
+ )
});
})?;
window
@@ -994,7 +1001,7 @@ impl Workspace {
move |cx| {
cx.new_view(|cx| {
let mut workspace =
- Workspace::new(workspace_id, project_handle, app_state, cx);
+ Workspace::new(Some(workspace_id), project_handle, app_state, cx);
workspace.centered_layout = centered_layout;
workspace
})
@@ -3464,9 +3471,12 @@ impl Workspace {
pub fn on_window_activation_changed(&mut self, cx: &mut ViewContext<Self>) {
if cx.is_window_active() {
self.update_active_view_for_followers(cx);
- cx.background_executor()
- .spawn(persistence::DB.update_timestamp(self.database_id()))
- .detach();
+
+ if let Some(database_id) = self.database_id {
+ cx.background_executor()
+ .spawn(persistence::DB.update_timestamp(database_id))
+ .detach();
+ }
} else {
for pane in &self.panes {
pane.update(cx, |pane, cx| {
@@ -3506,7 +3516,7 @@ impl Workspace {
}
}
- pub fn database_id(&self) -> WorkspaceId {
+ pub fn database_id(&self) -> Option<WorkspaceId> {
self.database_id
}
@@ -3566,6 +3576,10 @@ impl Workspace {
}
fn serialize_workspace_internal(&self, cx: &mut WindowContext) -> Task<()> {
+ let Some(database_id) = self.database_id() else {
+ return Task::ready(());
+ };
+
fn serialize_pane_handle(pane_handle: &View<Pane>, cx: &WindowContext) -> SerializedPane {
let (items, active) = {
let pane = pane_handle.read(cx);
@@ -3701,7 +3715,7 @@ impl Workspace {
let docks = build_serialized_docks(self, cx);
let window_bounds = Some(SerializedWindowBounds(cx.window_bounds()));
let serialized_workspace = SerializedWorkspace {
- id: self.database_id,
+ id: database_id,
location,
center_group,
window_bounds,
@@ -3944,9 +3958,11 @@ impl Workspace {
pub fn toggle_centered_layout(&mut self, _: &ToggleCenteredLayout, cx: &mut ViewContext<Self>) {
self.centered_layout = !self.centered_layout;
- cx.background_executor()
- .spawn(DB.set_centered_layout(self.database_id, self.centered_layout))
- .detach_and_log_err(cx);
+ if let Some(database_id) = self.database_id() {
+ cx.background_executor()
+ .spawn(DB.set_centered_layout(database_id, self.centered_layout))
+ .detach_and_log_err(cx);
+ }
cx.notify();
}
@@ -832,7 +832,7 @@ fn load_embedded_fonts(cx: &AppContext) {
}
scope.spawn(async {
- let font_bytes = asset_source.load(font_path).unwrap();
+ let font_bytes = asset_source.load(font_path).unwrap().unwrap();
embedded_fonts.lock().push(font_bytes);
});
}
@@ -3043,8 +3043,14 @@ mod tests {
fn test_bundled_settings_and_themes(cx: &mut AppContext) {
cx.text_system()
.add_fonts(vec![
- Assets.load("fonts/zed-sans/zed-sans-extended.ttf").unwrap(),
- Assets.load("fonts/zed-mono/zed-mono-extended.ttf").unwrap(),
+ Assets
+ .load("fonts/zed-sans/zed-sans-extended.ttf")
+ .unwrap()
+ .unwrap(),
+ Assets
+ .load("fonts/zed-mono/zed-mono-extended.ttf")
+ .unwrap()
+ .unwrap(),
])
.unwrap();
let themes = ThemeRegistry::default();