gpui: Add SharedUrl type (#3975)

This PR adds a `SharedUrl` type to GPUI.

It's just like a `SharedString`, but for denoting that the contained
value is a URL.

Mainlined from @nathansobo's GPUI blog post:
https://github.com/zed-industries/zed/pull/3968/files#diff-7ee75937e2daf7dd53f71b17698d8bd6d46993d06928d411781b9bd739b5f231R9-R12

Release Notes:

- N/A
This commit is contained in:
Marshall Bowers 2024-01-09 10:55:49 -05:00 committed by GitHub
parent fa53353c57
commit f0ef63bfa0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 48 additions and 21 deletions

View file

@ -3,7 +3,7 @@ use anyhow::{anyhow, Context, Result};
use collections::{hash_map::Entry, HashMap, HashSet}; use collections::{hash_map::Entry, HashMap, HashSet};
use feature_flags::FeatureFlagAppExt; use feature_flags::FeatureFlagAppExt;
use futures::{channel::mpsc, Future, StreamExt}; use futures::{channel::mpsc, Future, StreamExt};
use gpui::{AsyncAppContext, EventEmitter, Model, ModelContext, SharedString, Task}; use gpui::{AsyncAppContext, EventEmitter, Model, ModelContext, SharedUrl, Task};
use postage::{sink::Sink, watch}; use postage::{sink::Sink, watch};
use rpc::proto::{RequestMessage, UsersResponse}; use rpc::proto::{RequestMessage, UsersResponse};
use std::sync::{Arc, Weak}; use std::sync::{Arc, Weak};
@ -19,7 +19,7 @@ pub struct ParticipantIndex(pub u32);
pub struct User { pub struct User {
pub id: UserId, pub id: UserId,
pub github_login: String, pub github_login: String,
pub avatar_uri: SharedString, pub avatar_uri: SharedUrl,
} }
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]

View file

@ -1,10 +1,10 @@
use gpui::{img, prelude::*, AnyElement}; use gpui::{img, prelude::*, AnyElement, SharedUrl};
use smallvec::SmallVec; use smallvec::SmallVec;
use ui::prelude::*; use ui::prelude::*;
#[derive(IntoElement)] #[derive(IntoElement)]
pub struct CollabNotification { pub struct CollabNotification {
avatar_uri: SharedString, avatar_uri: SharedUrl,
accept_button: Button, accept_button: Button,
dismiss_button: Button, dismiss_button: Button,
children: SmallVec<[AnyElement; 2]>, children: SmallVec<[AnyElement; 2]>,
@ -12,7 +12,7 @@ pub struct CollabNotification {
impl CollabNotification { impl CollabNotification {
pub fn new( pub fn new(
avatar_uri: impl Into<SharedString>, avatar_uri: impl Into<SharedUrl>,
accept_button: Button, accept_button: Button,
dismiss_button: Button, dismiss_button: Button,
) -> Self { ) -> Self {

View file

@ -2,7 +2,7 @@ use std::sync::Arc;
use crate::{ use crate::{
point, size, BorrowWindow, Bounds, DevicePixels, Element, ImageData, InteractiveElement, point, size, BorrowWindow, Bounds, DevicePixels, Element, ImageData, InteractiveElement,
InteractiveElementState, Interactivity, IntoElement, LayoutId, Pixels, SharedString, Size, InteractiveElementState, Interactivity, IntoElement, LayoutId, Pixels, SharedUrl, Size,
StyleRefinement, Styled, WindowContext, StyleRefinement, Styled, WindowContext,
}; };
use futures::FutureExt; use futures::FutureExt;
@ -12,13 +12,13 @@ use util::ResultExt;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum ImageSource { pub enum ImageSource {
/// Image content will be loaded from provided URI at render time. /// Image content will be loaded from provided URI at render time.
Uri(SharedString), Uri(SharedUrl),
Data(Arc<ImageData>), Data(Arc<ImageData>),
Surface(CVImageBuffer), Surface(CVImageBuffer),
} }
impl From<SharedString> for ImageSource { impl From<SharedUrl> for ImageSource {
fn from(value: SharedString) -> Self { fn from(value: SharedUrl) -> Self {
Self::Uri(value) Self::Uri(value)
} }
} }

View file

@ -18,6 +18,7 @@ mod platform;
pub mod prelude; pub mod prelude;
mod scene; mod scene;
mod shared_string; mod shared_string;
mod shared_url;
mod style; mod style;
mod styled; mod styled;
mod subscription; mod subscription;
@ -67,6 +68,7 @@ pub use refineable::*;
pub use scene::*; pub use scene::*;
use seal::Sealed; use seal::Sealed;
pub use shared_string::*; pub use shared_string::*;
pub use shared_url::*;
pub use smol::Timer; pub use smol::Timer;
pub use style::*; pub use style::*;
pub use styled::*; pub use styled::*;

View file

@ -1,4 +1,4 @@
use crate::{ImageData, ImageId, SharedString}; use crate::{ImageData, ImageId, SharedUrl};
use collections::HashMap; use collections::HashMap;
use futures::{ use futures::{
future::{BoxFuture, Shared}, future::{BoxFuture, Shared},
@ -44,7 +44,7 @@ impl From<ImageError> for Error {
pub struct ImageCache { pub struct ImageCache {
client: Arc<dyn HttpClient>, client: Arc<dyn HttpClient>,
images: Arc<Mutex<HashMap<SharedString, FetchImageFuture>>>, images: Arc<Mutex<HashMap<SharedUrl, FetchImageFuture>>>,
} }
type FetchImageFuture = Shared<BoxFuture<'static, Result<Arc<ImageData>, Error>>>; type FetchImageFuture = Shared<BoxFuture<'static, Result<Arc<ImageData>, Error>>>;
@ -59,7 +59,7 @@ impl ImageCache {
pub fn get( pub fn get(
&self, &self,
uri: impl Into<SharedString>, uri: impl Into<SharedUrl>,
) -> Shared<BoxFuture<'static, Result<Arc<ImageData>, Error>>> { ) -> Shared<BoxFuture<'static, Result<Arc<ImageData>, Error>>> {
let uri = uri.into(); let uri = uri.into();
let mut images = self.images.lock(); let mut images = self.images.lock();

View file

@ -0,0 +1,25 @@
use derive_more::{Deref, DerefMut};
use crate::SharedString;
/// A [`SharedString`] containing a URL.
#[derive(Deref, DerefMut, Default, PartialEq, Eq, Hash, Clone)]
pub struct SharedUrl(SharedString);
impl std::fmt::Debug for SharedUrl {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
impl std::fmt::Display for SharedUrl {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0.as_ref())
}
}
impl<T: Into<SharedString>> From<T> for SharedUrl {
fn from(value: T) -> Self {
Self(value.into())
}
}

View file

@ -1,4 +1,4 @@
use gpui::Render; use gpui::{Render, SharedUrl};
use story::Story; use story::Story;
use crate::{prelude::*, Avatar}; use crate::{prelude::*, Avatar};
@ -43,7 +43,7 @@ impl Render for ListItemStory {
.child( .child(
ListItem::new("with_start slot avatar") ListItem::new("with_start slot avatar")
.child("Hello, world!") .child("Hello, world!")
.start_slot(Avatar::new(SharedString::from( .start_slot(Avatar::new(SharedUrl::from(
"https://avatars.githubusercontent.com/u/1714999?v=4", "https://avatars.githubusercontent.com/u/1714999?v=4",
))), ))),
) )
@ -51,7 +51,7 @@ impl Render for ListItemStory {
.child( .child(
ListItem::new("with_left_avatar") ListItem::new("with_left_avatar")
.child("Hello, world!") .child("Hello, world!")
.end_slot(Avatar::new(SharedString::from( .end_slot(Avatar::new(SharedUrl::from(
"https://avatars.githubusercontent.com/u/1714999?v=4", "https://avatars.githubusercontent.com/u/1714999?v=4",
))), ))),
) )
@ -62,23 +62,23 @@ impl Render for ListItemStory {
.end_slot( .end_slot(
h_stack() h_stack()
.gap_2() .gap_2()
.child(Avatar::new(SharedString::from( .child(Avatar::new(SharedUrl::from(
"https://avatars.githubusercontent.com/u/1789?v=4", "https://avatars.githubusercontent.com/u/1789?v=4",
))) )))
.child(Avatar::new(SharedString::from( .child(Avatar::new(SharedUrl::from(
"https://avatars.githubusercontent.com/u/1789?v=4", "https://avatars.githubusercontent.com/u/1789?v=4",
))) )))
.child(Avatar::new(SharedString::from( .child(Avatar::new(SharedUrl::from(
"https://avatars.githubusercontent.com/u/1789?v=4", "https://avatars.githubusercontent.com/u/1789?v=4",
))) )))
.child(Avatar::new(SharedString::from( .child(Avatar::new(SharedUrl::from(
"https://avatars.githubusercontent.com/u/1789?v=4", "https://avatars.githubusercontent.com/u/1789?v=4",
))) )))
.child(Avatar::new(SharedString::from( .child(Avatar::new(SharedUrl::from(
"https://avatars.githubusercontent.com/u/1789?v=4", "https://avatars.githubusercontent.com/u/1789?v=4",
))), ))),
) )
.end_hover_slot(Avatar::new(SharedString::from( .end_hover_slot(Avatar::new(SharedUrl::from(
"https://avatars.githubusercontent.com/u/1714999?v=4", "https://avatars.githubusercontent.com/u/1714999?v=4",
))), ))),
) )