Make tests less noisy (#12463)

When running the tests for linux, I found a lot of benign errors getting
logged. This PR cuts down some of the noise from unnecessary workspace
serialization and SVG renders

Release Notes:

- N/A
This commit is contained in:
Mikayla Maki 2024-05-29 18:06:45 -07:00 committed by GitHub
parent bdf627ce07
commit 5a149b970c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
36 changed files with 216 additions and 172 deletions

View File

@ -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);
}
}

View File

@ -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();

View File

@ -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();

View File

@ -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)
})
}

View File

@ -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(),

View File

@ -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

View File

@ -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,

View File

@ -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,

View File

@ -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);

View File

@ -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

View File

@ -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(),

View File

@ -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>> {

View File

@ -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>> {

View File

@ -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)]

View File

@ -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))
}
}
}

View File

@ -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))
}
}
}

View File

@ -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()))
}
}

View File

@ -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(&params.path)?;
let Some(bytes) = self.asset_source.load(&params.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> {

View File

@ -2347,13 +2347,14 @@ impl<'a> WindowContext<'a> {
let raster_bounds = self.text_system().raster_bounds(&params)?;
if !raster_bounds.is_zero() {
let tile =
self.window
.sprite_atlas
.get_or_insert_with(&params.clone().into(), &mut || {
let (size, bytes) = self.text_system().rasterize_glyph(&params)?;
Ok((size, Cow::Owned(bytes)))
})?;
let tile = self
.window
.sprite_atlas
.get_or_insert_with(&params.clone().into(), &mut || {
let (size, bytes) = self.text_system().rasterize_glyph(&params)?;
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(&params)?;
if !raster_bounds.is_zero() {
let tile =
self.window
.sprite_atlas
.get_or_insert_with(&params.clone().into(), &mut || {
let (size, bytes) = self.text_system().rasterize_glyph(&params)?;
Ok((size, Cow::Owned(bytes)))
})?;
let tile = self
.window
.sprite_atlas
.get_or_insert_with(&params.clone().into(), &mut || {
let (size, bytes) = self.text_system().rasterize_glyph(&params)?;
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(&params.clone().into(), &mut || {
let bytes = self.svg_renderer.render(&params)?;
Ok((params.size, Cow::Owned(bytes)))
})?;
let Some(bytes) = self.svg_renderer.render(&params)? 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(&params.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);

View File

@ -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

View File

@ -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

View File

@ -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;
}
}

View File

@ -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

View File

@ -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

View File

@ -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>> {

View File

@ -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);
}
}

View File

@ -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,
)

View File

@ -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();
}
}

View File

@ -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;
};

View File

@ -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>> {

View File

@ -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 {

View File

@ -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

View File

@ -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()?;

View File

@ -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();
}

View File

@ -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);
});
}

View File

@ -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();