Detailed changes
@@ -661,6 +661,7 @@ dependencies = [
"log",
"menu",
"project",
+ "release_channel",
"schemars",
"serde",
"serde_derive",
@@ -1188,6 +1189,7 @@ dependencies = [
"parking_lot 0.11.2",
"postage",
"rand 0.8.5",
+ "release_channel",
"rpc",
"schemars",
"serde",
@@ -1361,6 +1363,7 @@ dependencies = [
"parking_lot 0.11.2",
"postage",
"rand 0.8.5",
+ "release_channel",
"rpc",
"schemars",
"serde",
@@ -1596,6 +1599,7 @@ dependencies = [
"anyhow",
"client",
"collections",
+ "copilot",
"ctor",
"editor",
"env_logger",
@@ -1606,6 +1610,7 @@ dependencies = [
"menu",
"picker",
"project",
+ "release_channel",
"serde",
"serde_json",
"settings",
@@ -2040,6 +2045,7 @@ dependencies = [
"lazy_static",
"log",
"parking_lot 0.11.2",
+ "release_channel",
"serde",
"serde_derive",
"smol",
@@ -2512,6 +2518,7 @@ dependencies = [
"postage",
"project",
"regex",
+ "release_channel",
"serde",
"serde_derive",
"serde_json",
@@ -4907,9 +4914,9 @@ dependencies = [
[[package]]
name = "once_cell"
-version = "1.18.0"
+version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
+checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "opaque-debug"
@@ -6108,6 +6115,14 @@ version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
+[[package]]
+name = "release_channel"
+version = "0.1.0"
+dependencies = [
+ "gpui",
+ "once_cell",
+]
+
[[package]]
name = "rend"
version = "0.4.0"
@@ -6849,6 +6864,7 @@ dependencies = [
"pretty_assertions",
"project",
"rand 0.8.5",
+ "release_channel",
"rpc",
"rusqlite",
"rust-embed",
@@ -6988,6 +7004,7 @@ dependencies = [
"lazy_static",
"postage",
"pretty_assertions",
+ "release_channel",
"rust-embed",
"schemars",
"serde",
@@ -9139,6 +9156,7 @@ dependencies = [
"async-trait",
"collections",
"command_palette",
+ "copilot",
"diagnostics",
"editor",
"futures 0.3.28",
@@ -9687,6 +9705,7 @@ dependencies = [
"client",
"collections",
"db",
+ "derive_more",
"env_logger",
"fs",
"futures 0.3.28",
@@ -9840,6 +9859,7 @@ dependencies = [
"rand 0.8.5",
"recent_projects",
"regex",
+ "release_channel",
"rope",
"rpc",
"rsa 0.4.0",
@@ -59,6 +59,7 @@ members = [
"crates/project_symbols",
"crates/quick_action_bar",
"crates/recent_projects",
+ "crates/release_channel",
"crates/rope",
"crates/rpc",
"crates/search",
@@ -2,7 +2,7 @@ use std::{io::Cursor, sync::Arc};
use anyhow::Result;
use collections::HashMap;
-use gpui::{AppContext, AssetSource};
+use gpui::{AppContext, AssetSource, Global};
use rodio::{
source::{Buffered, SamplesConverter},
Decoder, Source,
@@ -15,6 +15,10 @@ pub struct SoundRegistry {
assets: Box<dyn AssetSource>,
}
+struct GlobalSoundRegistry(Arc<SoundRegistry>);
+
+impl Global for GlobalSoundRegistry {}
+
impl SoundRegistry {
pub fn new(source: impl AssetSource) -> Arc<Self> {
Arc::new(Self {
@@ -24,7 +28,11 @@ impl SoundRegistry {
}
pub fn global(cx: &AppContext) -> Arc<Self> {
- cx.global::<Arc<Self>>().clone()
+ cx.global::<GlobalSoundRegistry>().0.clone()
+ }
+
+ pub(crate) fn set_global(source: impl AssetSource, cx: &mut AppContext) {
+ cx.set_global(GlobalSoundRegistry(SoundRegistry::new(source)));
}
pub fn get(&self, name: &str) -> Result<impl Source<Item = f32>> {
@@ -1,12 +1,12 @@
use assets::SoundRegistry;
-use gpui::{AppContext, AssetSource};
+use gpui::{AppContext, AssetSource, Global};
use rodio::{OutputStream, OutputStreamHandle};
use util::ResultExt;
mod assets;
pub fn init(source: impl AssetSource, cx: &mut AppContext) {
- cx.set_global(SoundRegistry::new(source));
+ SoundRegistry::set_global(source, cx);
cx.set_global(Audio::new());
}
@@ -37,6 +37,8 @@ pub struct Audio {
output_handle: Option<OutputStreamHandle>,
}
+impl Global for Audio {}
+
impl Audio {
pub fn new() -> Self {
Self {
@@ -15,6 +15,7 @@ client = { path = "../client" }
gpui = { path = "../gpui" }
menu = { path = "../menu" }
project = { path = "../project" }
+release_channel = { path = "../release_channel" }
settings = { path = "../settings" }
theme = { path = "../theme" }
workspace = { path = "../workspace" }
@@ -5,8 +5,8 @@ use client::{Client, TelemetrySettings, ZED_APP_PATH, ZED_APP_VERSION};
use db::kvp::KEY_VALUE_STORE;
use db::RELEASE_CHANNEL;
use gpui::{
- actions, AppContext, AsyncAppContext, Context as _, Model, ModelContext, SemanticVersion, Task,
- ViewContext, VisualContext, WindowContext,
+ actions, AppContext, AsyncAppContext, Context as _, Global, Model, ModelContext,
+ SemanticVersion, Task, ViewContext, VisualContext, WindowContext,
};
use isahc::AsyncBody;
@@ -18,6 +18,7 @@ use smol::io::AsyncReadExt;
use settings::{Settings, SettingsStore};
use smol::{fs::File, process::Command};
+use release_channel::{AppCommitSha, ReleaseChannel};
use std::{
env::consts::{ARCH, OS},
ffi::OsString,
@@ -25,11 +26,7 @@ use std::{
time::Duration,
};
use update_notification::UpdateNotification;
-use util::http::HttpClient;
-use util::{
- channel::{AppCommitSha, ReleaseChannel},
- http::ZedHttpClient,
-};
+use util::http::{HttpClient, ZedHttpClient};
use workspace::Workspace;
const SHOULD_SHOW_UPDATE_NOTIFICATION_KEY: &str = "auto-updater-should-show-updated-notification";
@@ -94,6 +91,11 @@ impl Settings for AutoUpdateSetting {
}
}
+#[derive(Default)]
+struct GlobalAutoUpdate(Option<Model<AutoUpdater>>);
+
+impl Global for GlobalAutoUpdate {}
+
pub fn init(http_client: Arc<ZedHttpClient>, cx: &mut AppContext) {
AutoUpdateSetting::register(cx);
@@ -127,7 +129,7 @@ pub fn init(http_client: Arc<ZedHttpClient>, cx: &mut AppContext) {
updater
});
- cx.set_global(Some(auto_updater));
+ cx.set_global(GlobalAutoUpdate(Some(auto_updater)));
}
}
@@ -146,7 +148,7 @@ pub fn check(_: &Check, cx: &mut WindowContext) {
pub fn view_release_notes(_: &ViewReleaseNotes, cx: &mut AppContext) -> Option<()> {
let auto_updater = AutoUpdater::get(cx)?;
- let release_channel = cx.try_global::<ReleaseChannel>()?;
+ let release_channel = ReleaseChannel::try_global(cx)?;
if matches!(
release_channel,
@@ -191,7 +193,7 @@ pub fn notify_of_any_new_update(cx: &mut ViewContext<Workspace>) -> Option<()> {
impl AutoUpdater {
pub fn get(cx: &mut AppContext) -> Option<Model<Self>> {
- cx.default_global::<Option<Model<Self>>>().clone()
+ cx.default_global::<GlobalAutoUpdate>().0.clone()
}
fn new(current_version: SemanticVersion, http_client: Arc<ZedHttpClient>) -> Self {
@@ -253,8 +255,7 @@ impl AutoUpdater {
OS, ARCH
));
cx.update(|cx| {
- if let Some(param) = cx
- .try_global::<ReleaseChannel>()
+ if let Some(param) = ReleaseChannel::try_global(cx)
.map(|release_channel| release_channel.release_query_param())
.flatten()
{
@@ -276,7 +277,9 @@ impl AutoUpdater {
let should_download = match *RELEASE_CHANNEL {
ReleaseChannel::Nightly => cx
- .try_read_global::<AppCommitSha, _>(|sha, _| release.version != sha.0)
+ .update(|cx| AppCommitSha::try_global(cx).map(|sha| release.version != sha.0))
+ .ok()
+ .flatten()
.unwrap_or(true),
_ => release.version.parse::<SemanticVersion>()? > current_version,
};
@@ -311,9 +314,8 @@ impl AutoUpdater {
let mut dmg_file = File::create(&dmg_path).await?;
let (installation_id, release_channel, telemetry) = cx.update(|cx| {
- let installation_id = cx.global::<Arc<Client>>().telemetry().installation_id();
- let release_channel = cx
- .try_global::<ReleaseChannel>()
+ let installation_id = Client::global(cx).telemetry().installation_id();
+ let release_channel = ReleaseChannel::try_global(cx)
.map(|release_channel| release_channel.display_name());
let telemetry = TelemetrySettings::get_global(cx).metrics;
@@ -3,7 +3,7 @@ use gpui::{
SemanticVersion, StatefulInteractiveElement, Styled, ViewContext,
};
use menu::Cancel;
-use util::channel::ReleaseChannel;
+use release_channel::ReleaseChannel;
use workspace::ui::{h_flex, v_flex, Icon, IconName, Label, StyledExt};
pub struct UpdateNotification {
@@ -14,7 +14,7 @@ impl EventEmitter<DismissEvent> for UpdateNotification {}
impl Render for UpdateNotification {
fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> impl IntoElement {
- let app_name = cx.global::<ReleaseChannel>().display_name();
+ let app_name = ReleaseChannel::global(cx).display_name();
v_flex()
.on_action(cx.listener(UpdateNotification::dismiss))
@@ -9,8 +9,8 @@ use client::{proto, Client, TypedEnvelope, User, UserStore, ZED_ALWAYS_ACTIVE};
use collections::HashSet;
use futures::{channel::oneshot, future::Shared, Future, FutureExt};
use gpui::{
- AppContext, AsyncAppContext, Context, EventEmitter, Model, ModelContext, Subscription, Task,
- WeakModel,
+ AppContext, AsyncAppContext, Context, EventEmitter, Global, Model, ModelContext, Subscription,
+ Task, WeakModel,
};
use postage::watch;
use project::Project;
@@ -21,11 +21,15 @@ use std::sync::Arc;
pub use participant::ParticipantLocation;
pub use room::Room;
+struct GlobalActiveCall(Model<ActiveCall>);
+
+impl Global for GlobalActiveCall {}
+
pub fn init(client: Arc<Client>, user_store: Model<UserStore>, cx: &mut AppContext) {
CallSettings::register(cx);
let active_call = cx.new_model(|cx| ActiveCall::new(client, user_store, cx));
- cx.set_global(active_call);
+ cx.set_global(GlobalActiveCall(active_call));
}
pub struct OneAtATime {
@@ -154,7 +158,12 @@ impl ActiveCall {
}
pub fn global(cx: &AppContext) -> Model<Self> {
- cx.global::<Model<Self>>().clone()
+ cx.global::<GlobalActiveCall>().0.clone()
+ }
+
+ pub fn try_global(cx: &AppContext) -> Option<Model<Self>> {
+ cx.try_global::<GlobalActiveCall>()
+ .map(|call| call.0.clone())
}
pub fn invite(
@@ -21,6 +21,7 @@ util = { path = "../util" }
rpc = { path = "../rpc" }
text = { path = "../text" }
language = { path = "../language" }
+release_channel = { path = "../release_channel" }
settings = { path = "../settings" }
feature_flags = { path = "../feature_flags" }
sum_tree = { path = "../sum_tree" }
@@ -5,13 +5,13 @@ use anyhow::{anyhow, Result};
use channel_index::ChannelIndex;
use client::{Client, Subscription, User, UserId, UserStore};
use collections::{hash_map, HashMap, HashSet};
-use db::RELEASE_CHANNEL;
use futures::{channel::mpsc, future::Shared, Future, FutureExt, StreamExt};
use gpui::{
- AppContext, AsyncAppContext, Context, EventEmitter, Model, ModelContext, SharedString, Task,
- WeakModel,
+ AppContext, AsyncAppContext, Context, EventEmitter, Global, Model, ModelContext, SharedString,
+ Task, WeakModel,
};
use language::Capability;
+use release_channel::RELEASE_CHANNEL;
use rpc::{
proto::{self, ChannelRole, ChannelVisibility},
TypedEnvelope,
@@ -22,7 +22,7 @@ use util::{async_maybe, maybe, ResultExt};
pub fn init(client: &Arc<Client>, user_store: Model<UserStore>, cx: &mut AppContext) {
let channel_store =
cx.new_model(|cx| ChannelStore::new(client.clone(), user_store.clone(), cx));
- cx.set_global(channel_store);
+ cx.set_global(GlobalChannelStore(channel_store));
}
pub const RECONNECT_TIMEOUT: Duration = Duration::from_secs(30);
@@ -143,9 +143,13 @@ enum OpenedModelHandle<E> {
Loading(Shared<Task<Result<Model<E>, Arc<anyhow::Error>>>>),
}
+struct GlobalChannelStore(Model<ChannelStore>);
+
+impl Global for GlobalChannelStore {}
+
impl ChannelStore {
pub fn global(cx: &AppContext) -> Model<Self> {
- cx.global::<Model<Self>>().clone()
+ cx.global::<GlobalChannelStore>().0.clone()
}
pub fn new(
@@ -18,6 +18,7 @@ collections = { path = "../collections" }
db = { path = "../db" }
gpui = { path = "../gpui" }
util = { path = "../util" }
+release_channel = { path = "../release_channel" }
rpc = { path = "../rpc" }
text = { path = "../text" }
settings = { path = "../settings" }
@@ -15,13 +15,14 @@ use futures::{
TryFutureExt as _, TryStreamExt,
};
use gpui::{
- actions, AnyModel, AnyWeakModel, AppContext, AsyncAppContext, Model, SemanticVersion, Task,
- WeakModel,
+ actions, AnyModel, AnyWeakModel, AppContext, AsyncAppContext, Global, Model, SemanticVersion,
+ Task, WeakModel,
};
use lazy_static::lazy_static;
use parking_lot::RwLock;
use postage::watch;
use rand::prelude::*;
+use release_channel::ReleaseChannel;
use rpc::proto::{AnyTypedEnvelope, EntityMessage, EnvelopedMessage, PeerId, RequestMessage};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
@@ -41,8 +42,7 @@ use std::{
use telemetry::Telemetry;
use thiserror::Error;
use url::Url;
-use util::http::HttpClient;
-use util::{channel::ReleaseChannel, http::ZedHttpClient};
+use util::http::{HttpClient, ZedHttpClient};
use util::{ResultExt, TryFutureExt};
pub use rpc::*;
@@ -149,6 +149,10 @@ pub fn init(client: &Arc<Client>, cx: &mut AppContext) {
});
}
+struct GlobalClient(Arc<Client>);
+
+impl Global for GlobalClient {}
+
pub struct Client {
id: AtomicU64,
peer: Arc<Peer>,
@@ -483,6 +487,13 @@ impl Client {
self
}
+ pub fn global(cx: &AppContext) -> Arc<Self> {
+ cx.global::<GlobalClient>().0.clone()
+ }
+ pub fn set_global(client: Arc<Client>, cx: &mut AppContext) {
+ cx.set_global(GlobalClient(client))
+ }
+
pub fn user_id(&self) -> Option<u64> {
self.state
.read()
@@ -996,7 +1007,10 @@ impl Client {
credentials: &Credentials,
cx: &AsyncAppContext,
) -> Task<Result<Connection, EstablishConnectionError>> {
- let release_channel = cx.try_read_global(|channel: &ReleaseChannel, _| *channel);
+ let release_channel = cx
+ .update(|cx| ReleaseChannel::try_global(cx))
+ .ok()
+ .flatten();
let request = Request::builder()
.header(
@@ -5,6 +5,7 @@ use chrono::{DateTime, Utc};
use futures::Future;
use gpui::{AppContext, AppMetadata, BackgroundExecutor, Task};
use parking_lot::Mutex;
+use release_channel::ReleaseChannel;
use serde::Serialize;
use settings::{Settings, SettingsStore};
use std::{env, io::Write, mem, path::PathBuf, sync::Arc, time::Duration};
@@ -15,7 +16,7 @@ use tempfile::NamedTempFile;
use util::http::{HttpClient, ZedHttpClient};
#[cfg(not(debug_assertions))]
use util::ResultExt;
-use util::{channel::ReleaseChannel, TryFutureExt};
+use util::TryFutureExt;
use self::event_coalescer::EventCoalescer;
@@ -143,9 +144,8 @@ const FLUSH_INTERVAL: Duration = Duration::from_secs(60 * 5);
impl Telemetry {
pub fn new(client: Arc<ZedHttpClient>, cx: &mut AppContext) -> Arc<Self> {
- let release_channel = cx
- .try_global::<ReleaseChannel>()
- .map(|release_channel| release_channel.display_name());
+ let release_channel =
+ ReleaseChannel::try_global(cx).map(|release_channel| release_channel.display_name());
TelemetrySettings::register(cx);
@@ -11,13 +11,4 @@ pub type HashMap<K, V> = std::collections::HashMap<K, V>;
pub type HashSet<T> = std::collections::HashSet<T>;
pub use rustc_hash::{FxHashMap, FxHashSet};
-use std::any::TypeId;
pub use std::collections::*;
-
-// NEW TYPES
-
-#[derive(Default)]
-pub struct CommandPaletteFilter {
- pub hidden_namespaces: HashSet<&'static str>,
- pub hidden_action_types: HashSet<TypeId>,
-}
@@ -12,11 +12,14 @@ doctest = false
[dependencies]
client = { path = "../client" }
collections = { path = "../collections" }
+# HACK: We're only depending on `copilot` here for `CommandPaletteFilter`. See the attached comment on that type.
+copilot = { path = "../copilot" }
editor = { path = "../editor" }
fuzzy = { path = "../fuzzy" }
gpui = { path = "../gpui" }
picker = { path = "../picker" }
project = { path = "../project" }
+release_channel = { path = "../release_channel" }
settings = { path = "../settings" }
theme = { path = "../theme" }
ui = { path = "../ui" }
@@ -4,19 +4,18 @@ use std::{
};
use client::telemetry::Telemetry;
-use collections::{CommandPaletteFilter, HashMap};
+use collections::HashMap;
+use copilot::CommandPaletteFilter;
use fuzzy::{StringMatch, StringMatchCandidate};
use gpui::{
- actions, Action, AppContext, DismissEvent, EventEmitter, FocusHandle, FocusableView,
+ actions, Action, AppContext, DismissEvent, EventEmitter, FocusHandle, FocusableView, Global,
ParentElement, Render, Styled, View, ViewContext, VisualContext, WeakView,
};
use picker::{Picker, PickerDelegate};
+use release_channel::{parse_zed_link, ReleaseChannel};
use ui::{h_flex, prelude::*, v_flex, HighlightedLabel, KeyBinding, ListItem, ListItemSpacing};
-use util::{
- channel::{parse_zed_link, ReleaseChannel, RELEASE_CHANNEL},
- ResultExt,
-};
+use util::ResultExt;
use workspace::{ModalView, Workspace};
use zed_actions::OpenZedUrl;
@@ -100,8 +99,11 @@ impl Render for CommandPalette {
}
}
-pub type CommandPaletteInterceptor =
- Box<dyn Fn(&str, &AppContext) -> Option<CommandInterceptResult>>;
+pub struct CommandPaletteInterceptor(
+ pub Box<dyn Fn(&str, &AppContext) -> Option<CommandInterceptResult>>,
+);
+
+impl Global for CommandPaletteInterceptor {}
pub struct CommandInterceptResult {
pub action: Box<dyn Action>,
@@ -139,6 +141,8 @@ impl Clone for Command {
#[derive(Default)]
struct HitCounts(HashMap<String, usize>);
+impl Global for HitCounts {}
+
impl CommandPaletteDelegate {
fn new(
command_palette: WeakView<CommandPalette>,
@@ -229,11 +233,14 @@ impl PickerDelegate for CommandPaletteDelegate {
let mut intercept_result = cx
.try_read_global(|interceptor: &CommandPaletteInterceptor, cx| {
- (interceptor)(&query, cx)
+ (interceptor.0)(&query, cx)
})
.flatten();
-
- if *RELEASE_CHANNEL == ReleaseChannel::Dev {
+ let release_channel = cx
+ .update(|cx| ReleaseChannel::try_global(cx))
+ .ok()
+ .flatten();
+ if release_channel == Some(ReleaseChannel::Dev) {
if parse_zed_link(&query).is_some() {
intercept_result = Some(CommandInterceptResult {
action: OpenZedUrl { url: query.clone() }.boxed_clone(),
@@ -5,7 +5,7 @@ use async_tar::Archive;
use collections::{HashMap, HashSet};
use futures::{channel::oneshot, future::Shared, Future, FutureExt, TryFutureExt};
use gpui::{
- actions, AppContext, AsyncAppContext, Context, Entity, EntityId, EventEmitter, Model,
+ actions, AppContext, AsyncAppContext, Context, Entity, EntityId, EventEmitter, Global, Model,
ModelContext, Task, WeakModel,
};
use language::{
@@ -32,6 +32,17 @@ use util::{
ResultExt,
};
+// HACK: This type is only defined in `copilot` since it is the earliest ancestor
+// of the crates that use it.
+//
+// This is not great. Let's find a better place for it to live.
+#[derive(Default)]
+pub struct CommandPaletteFilter {
+ pub hidden_namespaces: HashSet<&'static str>,
+ pub hidden_action_types: HashSet<TypeId>,
+}
+
+impl Global for CommandPaletteFilter {}
actions!(
copilot,
[
@@ -54,7 +65,7 @@ pub fn init(
let node_runtime = node_runtime.clone();
move |cx| Copilot::start(new_server_id, http, node_runtime, cx)
});
- cx.set_global(copilot.clone());
+ Copilot::set_global(copilot.clone(), cx);
cx.observe(&copilot, |handle, cx| {
let copilot_action_types = [
TypeId::of::<Suggest>(),
@@ -65,7 +76,7 @@ pub fn init(
let copilot_auth_action_types = [TypeId::of::<SignOut>()];
let copilot_no_auth_action_types = [TypeId::of::<SignIn>()];
let status = handle.read(cx).status();
- let filter = cx.default_global::<collections::CommandPaletteFilter>();
+ let filter = cx.default_global::<CommandPaletteFilter>();
match status {
Status::Disabled => {
@@ -307,9 +318,18 @@ pub enum Event {
impl EventEmitter<Event> for Copilot {}
+struct GlobalCopilot(Model<Copilot>);
+
+impl Global for GlobalCopilot {}
+
impl Copilot {
pub fn global(cx: &AppContext) -> Option<Model<Self>> {
- cx.try_global::<Model<Self>>().map(|model| model.clone())
+ cx.try_global::<GlobalCopilot>()
+ .map(|model| model.0.clone())
+ }
+
+ pub fn set_global(copilot: Model<Self>, cx: &mut AppContext) {
+ cx.set_global(GlobalCopilot(copilot));
}
fn start(
@@ -15,6 +15,7 @@ test-support = []
[dependencies]
collections = { path = "../collections" }
gpui = { path = "../gpui" }
+release_channel = { path = "../release_channel" }
sqlez = { path = "../sqlez" }
sqlez_macros = { path = "../sqlez_macros" }
util = { path = "../util" }
@@ -10,16 +10,16 @@ pub use lazy_static;
pub use smol;
pub use sqlez;
pub use sqlez_macros;
-pub use util::channel::{RELEASE_CHANNEL, RELEASE_CHANNEL_NAME};
pub use util::paths::DB_DIR;
+use release_channel::ReleaseChannel;
+pub use release_channel::RELEASE_CHANNEL;
use sqlez::domain::Migrator;
use sqlez::thread_safe_connection::ThreadSafeConnection;
use sqlez_macros::sql;
use std::future::Future;
use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicBool, Ordering};
-use util::channel::ReleaseChannel;
use util::{async_maybe, ResultExt};
const CONNECTION_INITIALIZE_QUERY: &'static str = sql!(
@@ -223,7 +223,7 @@ mod tests {
.prefix("DbTests")
.tempdir()
.unwrap();
- let _bad_db = open_db::<BadDB>(tempdir.path(), &util::channel::ReleaseChannel::Dev).await;
+ let _bad_db = open_db::<BadDB>(tempdir.path(), &release_channel::ReleaseChannel::Dev).await;
}
/// Test that DB exists but corrupted (causing recreate)
@@ -261,11 +261,12 @@ mod tests {
.unwrap();
{
let corrupt_db =
- open_db::<CorruptedDB>(tempdir.path(), &util::channel::ReleaseChannel::Dev).await;
+ open_db::<CorruptedDB>(tempdir.path(), &release_channel::ReleaseChannel::Dev).await;
assert!(corrupt_db.persistent());
}
- let good_db = open_db::<GoodDB>(tempdir.path(), &util::channel::ReleaseChannel::Dev).await;
+ let good_db =
+ open_db::<GoodDB>(tempdir.path(), &release_channel::ReleaseChannel::Dev).await;
assert!(
good_db.select_row::<usize>("SELECT * FROM test2").unwrap()()
.unwrap()
@@ -309,7 +310,7 @@ mod tests {
{
// Setup the bad database
let corrupt_db =
- open_db::<CorruptedDB>(tempdir.path(), &util::channel::ReleaseChannel::Dev).await;
+ open_db::<CorruptedDB>(tempdir.path(), &release_channel::ReleaseChannel::Dev).await;
assert!(corrupt_db.persistent());
}
@@ -320,7 +321,7 @@ mod tests {
let guard = thread::spawn(move || {
let good_db = smol::block_on(open_db::<GoodDB>(
tmp_path.as_path(),
- &util::channel::ReleaseChannel::Dev,
+ &release_channel::ReleaseChannel::Dev,
));
assert!(
good_db.select_row::<usize>("SELECT * FROM test2").unwrap()()
@@ -104,7 +104,6 @@ use std::{
ops::{ControlFlow, Deref, DerefMut, Range, RangeInclusive},
path::Path,
sync::Arc,
- sync::Weak,
time::{Duration, Instant},
};
pub use sum_tree::Bias;
@@ -241,7 +240,7 @@ pub fn init(cx: &mut AppContext) {
.detach();
cx.on_action(move |_: &workspace::NewFile, cx| {
- let app_state = cx.global::<Weak<workspace::AppState>>();
+ let app_state = workspace::AppState::global(cx);
if let Some(app_state) = app_state.upgrade() {
workspace::open_new(&app_state, cx, |workspace, cx| {
Editor::new_file(workspace, &Default::default(), cx)
@@ -250,7 +249,7 @@ pub fn init(cx: &mut AppContext) {
}
});
cx.on_action(move |_: &workspace::NewWindow, cx| {
- let app_state = cx.global::<Weak<workspace::AppState>>();
+ let app_state = workspace::AppState::global(cx);
if let Some(app_state) = app_state.upgrade() {
workspace::open_new(&app_state, cx, |workspace, cx| {
Editor::new_file(workspace, &Default::default(), cx)
@@ -7226,7 +7226,7 @@ async fn test_copilot(executor: BackgroundExecutor, cx: &mut gpui::TestAppContex
init_test(cx, |_| {});
let (copilot, copilot_lsp) = Copilot::fake(cx);
- _ = cx.update(|cx| cx.set_global(copilot));
+ _ = cx.update(|cx| Copilot::set_global(copilot, cx));
let mut cx = EditorLspTestContext::new_rust(
lsp::ServerCapabilities {
completion_provider: Some(lsp::CompletionOptions {
@@ -7479,7 +7479,7 @@ async fn test_copilot_completion_invalidation(
init_test(cx, |_| {});
let (copilot, copilot_lsp) = Copilot::fake(cx);
- _ = cx.update(|cx| cx.set_global(copilot));
+ _ = cx.update(|cx| Copilot::set_global(copilot, cx));
let mut cx = EditorLspTestContext::new_rust(
lsp::ServerCapabilities {
completion_provider: Some(lsp::CompletionOptions {
@@ -7543,7 +7543,7 @@ async fn test_copilot_multibuffer(executor: BackgroundExecutor, cx: &mut gpui::T
init_test(cx, |_| {});
let (copilot, copilot_lsp) = Copilot::fake(cx);
- _ = cx.update(|cx| cx.set_global(copilot));
+ _ = cx.update(|cx| Copilot::set_global(copilot, cx));
let buffer_1 = cx.new_model(|cx| {
Buffer::new(
@@ -7660,7 +7660,7 @@ async fn test_copilot_disabled_globs(executor: BackgroundExecutor, cx: &mut gpui
});
let (copilot, copilot_lsp) = Copilot::fake(cx);
- _ = cx.update(|cx| cx.set_global(copilot));
+ _ = cx.update(|cx| Copilot::set_global(copilot, cx));
let fs = FakeFs::new(cx.executor());
fs.insert_tree(
@@ -10,7 +10,7 @@ use crate::{
MultiBufferSnapshot, ToPoint,
};
pub use autoscroll::{Autoscroll, AutoscrollStrategy};
-use gpui::{point, px, AppContext, Entity, Pixels, Task, ViewContext};
+use gpui::{point, px, AppContext, Entity, Global, Pixels, Task, ViewContext};
use language::{Bias, Point};
pub use scroll_amount::ScrollAmount;
use std::{
@@ -27,6 +27,8 @@ const SCROLLBAR_SHOW_INTERVAL: Duration = Duration::from_secs(1);
#[derive(Default)]
pub struct ScrollbarAutoHide(pub bool);
+impl Global for ScrollbarAutoHide {}
+
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct ScrollAnchor {
pub offset: gpui::Point<f32>,
@@ -1,4 +1,4 @@
-use gpui::{AppContext, Subscription, ViewContext};
+use gpui::{AppContext, Global, Subscription, ViewContext};
#[derive(Default)]
struct FeatureFlags {
@@ -12,6 +12,8 @@ impl FeatureFlags {
}
}
+impl Global for FeatureFlags {}
+
pub trait FeatureFlag {
const NAME: &'static str;
}
@@ -19,6 +19,7 @@ gpui = { path = "../gpui" }
language = { path = "../language" }
menu = { path = "../menu" }
project = { path = "../project" }
+release_channel = { path = "../release_channel" }
settings = { path = "../settings" }
theme = { path = "../theme" }
ui = { path = "../ui" }
@@ -225,7 +225,7 @@ impl FeedbackModal {
None,
&["Yes, Submit!", "No"],
);
- let client = cx.global::<Arc<Client>>().clone();
+ let client = Client::global(cx).clone();
let specs = self.system_specs.clone();
cx.spawn(|this, mut cx| async move {
let answer = answer.await.ok();
@@ -1,10 +1,10 @@
use client::ZED_APP_VERSION;
use gpui::AppContext;
use human_bytes::human_bytes;
+use release_channel::ReleaseChannel;
use serde::Serialize;
use std::{env, fmt::Display};
use sysinfo::{RefreshKind, System, SystemExt};
-use util::channel::ReleaseChannel;
#[derive(Clone, Debug, Serialize)]
pub struct SystemSpecs {
@@ -21,7 +21,7 @@ impl SystemSpecs {
let app_version = ZED_APP_VERSION
.or_else(|| cx.app_metadata().app_version)
.map(|v| v.to_string());
- let release_channel = cx.global::<ReleaseChannel>().display_name();
+ let release_channel = ReleaseChannel::global(cx).display_name();
let os_name = cx.app_metadata().os_name;
let system = System::new_with_specifics(RefreshKind::new().with_memory());
let memory = system.total_memory();
@@ -17,7 +17,7 @@ use time::UtcOffset;
use crate::{
current_platform, image_cache::ImageCache, init_app_menus, Action, ActionRegistry, Any,
AnyView, AnyWindowHandle, AppMetadata, AssetSource, BackgroundExecutor, ClipboardItem, Context,
- DispatchPhase, DisplayId, Entity, EventEmitter, ForegroundExecutor, KeyBinding, Keymap,
+ DispatchPhase, DisplayId, Entity, EventEmitter, ForegroundExecutor, Global, KeyBinding, Keymap,
Keystroke, LayoutId, Menu, PathPromptOptions, Pixels, Platform, PlatformDisplay, Point, Render,
SharedString, SubscriberSet, Subscription, SvgRenderer, Task, TextStyle, TextStyleRefinement,
TextSystem, View, ViewContext, Window, WindowContext, WindowHandle, WindowId,
@@ -823,13 +823,13 @@ impl AppContext {
}
/// Check whether a global of the given type has been assigned.
- pub fn has_global<G: 'static>(&self) -> bool {
+ pub fn has_global<G: Global>(&self) -> bool {
self.globals_by_type.contains_key(&TypeId::of::<G>())
}
/// Access the global of the given type. Panics if a global for that type has not been assigned.
#[track_caller]
- pub fn global<G: 'static>(&self) -> &G {
+ pub fn global<G: Global>(&self) -> &G {
self.globals_by_type
.get(&TypeId::of::<G>())
.map(|any_state| any_state.downcast_ref::<G>().unwrap())
@@ -838,7 +838,7 @@ impl AppContext {
}
/// Access the global of the given type if a value has been assigned.
- pub fn try_global<G: 'static>(&self) -> Option<&G> {
+ pub fn try_global<G: Global>(&self) -> Option<&G> {
self.globals_by_type
.get(&TypeId::of::<G>())
.map(|any_state| any_state.downcast_ref::<G>().unwrap())
@@ -846,7 +846,7 @@ impl AppContext {
/// Access the global of the given type mutably. Panics if a global for that type has not been assigned.
#[track_caller]
- pub fn global_mut<G: 'static>(&mut self) -> &mut G {
+ pub fn global_mut<G: Global>(&mut self) -> &mut G {
let global_type = TypeId::of::<G>();
self.push_effect(Effect::NotifyGlobalObservers { global_type });
self.globals_by_type
@@ -858,7 +858,7 @@ impl AppContext {
/// Access the global of the given type mutably. A default value is assigned if a global of this type has not
/// yet been assigned.
- pub fn default_global<G: 'static + Default>(&mut self) -> &mut G {
+ pub fn default_global<G: Global + Default>(&mut self) -> &mut G {
let global_type = TypeId::of::<G>();
self.push_effect(Effect::NotifyGlobalObservers { global_type });
self.globals_by_type
@@ -869,7 +869,7 @@ impl AppContext {
}
/// Sets the value of the global of the given type.
- pub fn set_global<G: Any>(&mut self, global: G) {
+ pub fn set_global<G: Global>(&mut self, global: G) {
let global_type = TypeId::of::<G>();
self.push_effect(Effect::NotifyGlobalObservers { global_type });
self.globals_by_type.insert(global_type, Box::new(global));
@@ -882,7 +882,7 @@ impl AppContext {
}
/// Remove the global of the given type from the app context. Does not notify global observers.
- pub fn remove_global<G: Any>(&mut self) -> G {
+ pub fn remove_global<G: Global>(&mut self) -> G {
let global_type = TypeId::of::<G>();
self.push_effect(Effect::NotifyGlobalObservers { global_type });
*self
@@ -895,7 +895,7 @@ impl AppContext {
/// Updates the global of the given type with a closure. Unlike `global_mut`, this method provides
/// your closure with mutable access to the `AppContext` and the global simultaneously.
- pub fn update_global<G: 'static, R>(&mut self, f: impl FnOnce(&mut G, &mut Self) -> R) -> R {
+ pub fn update_global<G: Global, R>(&mut self, f: impl FnOnce(&mut G, &mut Self) -> R) -> R {
self.update(|cx| {
let mut global = cx.lease_global::<G>();
let result = f(&mut global, cx);
@@ -905,7 +905,7 @@ impl AppContext {
}
/// Register a callback to be invoked when a global of the given type is updated.
- pub fn observe_global<G: 'static>(
+ pub fn observe_global<G: Global>(
&mut self,
mut f: impl FnMut(&mut Self) + 'static,
) -> Subscription {
@@ -921,7 +921,7 @@ impl AppContext {
}
/// Move the global of the given type to the stack.
- pub(crate) fn lease_global<G: 'static>(&mut self) -> GlobalLease<G> {
+ pub(crate) fn lease_global<G: Global>(&mut self) -> GlobalLease<G> {
GlobalLease::new(
self.globals_by_type
.remove(&TypeId::of::<G>())
@@ -931,7 +931,7 @@ impl AppContext {
}
/// Restore the global of the given type after it is moved to the stack.
- pub(crate) fn end_global_lease<G: 'static>(&mut self, lease: GlobalLease<G>) {
+ pub(crate) fn end_global_lease<G: Global>(&mut self, lease: GlobalLease<G>) {
let global_type = TypeId::of::<G>();
self.push_effect(Effect::NotifyGlobalObservers { global_type });
self.globals_by_type.insert(global_type, lease.global);
@@ -1293,12 +1293,12 @@ pub(crate) enum Effect {
}
/// Wraps a global variable value during `update_global` while the value has been moved to the stack.
-pub(crate) struct GlobalLease<G: 'static> {
+pub(crate) struct GlobalLease<G: Global> {
global: Box<dyn Any>,
global_type: PhantomData<G>,
}
-impl<G: 'static> GlobalLease<G> {
+impl<G: Global> GlobalLease<G> {
fn new(global: Box<dyn Any>) -> Self {
GlobalLease {
global,
@@ -1307,7 +1307,7 @@ impl<G: 'static> GlobalLease<G> {
}
}
-impl<G: 'static> Deref for GlobalLease<G> {
+impl<G: Global> Deref for GlobalLease<G> {
type Target = G;
fn deref(&self) -> &Self::Target {
@@ -1315,7 +1315,7 @@ impl<G: 'static> Deref for GlobalLease<G> {
}
}
-impl<G: 'static> DerefMut for GlobalLease<G> {
+impl<G: Global> DerefMut for GlobalLease<G> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.global.downcast_mut().unwrap()
}
@@ -1,6 +1,6 @@
use crate::{
AnyView, AnyWindowHandle, AppCell, AppContext, BackgroundExecutor, Context, DismissEvent,
- FocusableView, ForegroundExecutor, Model, ModelContext, Render, Result, Task, View,
+ FocusableView, ForegroundExecutor, Global, Model, ModelContext, Render, Result, Task, View,
ViewContext, VisualContext, WindowContext, WindowHandle,
};
use anyhow::{anyhow, Context as _};
@@ -144,7 +144,7 @@ impl AsyncAppContext {
/// Determine whether global state of the specified type has been assigned.
/// Returns an error if the `AppContext` has been dropped.
- pub fn has_global<G: 'static>(&self) -> Result<bool> {
+ pub fn has_global<G: Global>(&self) -> Result<bool> {
let app = self
.app
.upgrade()
@@ -157,7 +157,7 @@ impl AsyncAppContext {
///
/// Panics if no global state of the specified type has been assigned.
/// Returns an error if the `AppContext` has been dropped.
- pub fn read_global<G: 'static, R>(&self, read: impl FnOnce(&G, &AppContext) -> R) -> Result<R> {
+ pub fn read_global<G: Global, R>(&self, read: impl FnOnce(&G, &AppContext) -> R) -> Result<R> {
let app = self
.app
.upgrade()
@@ -172,7 +172,7 @@ impl AsyncAppContext {
/// if no state of the specified type has been assigned.
///
/// Returns an error if no state of the specified type has been assigned the `AppContext` has been dropped.
- pub fn try_read_global<G: 'static, R>(
+ pub fn try_read_global<G: Global, R>(
&self,
read: impl FnOnce(&G, &AppContext) -> R,
) -> Option<R> {
@@ -183,7 +183,7 @@ impl AsyncAppContext {
/// A convenience method for [AppContext::update_global]
/// for updating the global state of the specified type.
- pub fn update_global<G: 'static, R>(
+ pub fn update_global<G: Global, R>(
&mut self,
update: impl FnOnce(&mut G, &mut AppContext) -> R,
) -> Result<R> {
@@ -235,7 +235,7 @@ impl AsyncWindowContext {
}
/// A convenience method for [`AppContext::global`].
- pub fn read_global<G: 'static, R>(
+ pub fn read_global<G: Global, R>(
&mut self,
read: impl FnOnce(&G, &WindowContext) -> R,
) -> Result<R> {
@@ -249,7 +249,7 @@ impl AsyncWindowContext {
update: impl FnOnce(&mut G, &mut WindowContext) -> R,
) -> Result<R>
where
- G: 'static,
+ G: Global,
{
self.window.update(self, |_, cx| cx.update_global(update))
}
@@ -1,6 +1,6 @@
use crate::{
AnyView, AnyWindowHandle, AppContext, AsyncAppContext, Context, Effect, Entity, EntityId,
- EventEmitter, Model, Subscription, Task, View, WeakModel, WindowContext, WindowHandle,
+ EventEmitter, Global, Model, Subscription, Task, View, WeakModel, WindowContext, WindowHandle,
};
use anyhow::Result;
use derive_more::{Deref, DerefMut};
@@ -193,7 +193,7 @@ impl<'a, T: 'static> ModelContext<'a, T> {
/// Updates the given global
pub fn update_global<G, R>(&mut self, f: impl FnOnce(&mut G, &mut Self) -> R) -> R
where
- G: 'static,
+ G: Global,
{
let mut global = self.app.lease_global::<G>();
let result = f(&mut global, self);
@@ -1,8 +1,8 @@
use crate::{
Action, AnyElement, AnyView, AnyWindowHandle, AppCell, AppContext, AsyncAppContext,
AvailableSpace, BackgroundExecutor, Bounds, ClipboardItem, Context, Entity, EventEmitter,
- ForegroundExecutor, InputEvent, Keystroke, Model, ModelContext, Pixels, Platform, Point,
- Render, Result, Size, Task, TestDispatcher, TestPlatform, TestWindow, TextSystem, View,
+ ForegroundExecutor, Global, InputEvent, Keystroke, Model, ModelContext, Pixels, Platform,
+ Point, Render, Result, Size, Task, TestDispatcher, TestPlatform, TestWindow, TextSystem, View,
ViewContext, VisualContext, WindowContext, WindowHandle, WindowOptions,
};
use anyhow::{anyhow, bail};
@@ -256,20 +256,20 @@ impl TestAppContext {
}
/// true if the given global is defined
- pub fn has_global<G: 'static>(&self) -> bool {
+ pub fn has_global<G: Global>(&self) -> bool {
let app = self.app.borrow();
app.has_global::<G>()
}
/// runs the given closure with a reference to the global
/// panics if `has_global` would return false.
- pub fn read_global<G: 'static, R>(&self, read: impl FnOnce(&G, &AppContext) -> R) -> R {
+ pub fn read_global<G: Global, R>(&self, read: impl FnOnce(&G, &AppContext) -> R) -> R {
let app = self.app.borrow();
read(app.global(), &app)
}
/// runs the given closure with a reference to the global (if set)
- pub fn try_read_global<G: 'static, R>(
+ pub fn try_read_global<G: Global, R>(
&self,
read: impl FnOnce(&G, &AppContext) -> R,
) -> Option<R> {
@@ -278,13 +278,13 @@ impl TestAppContext {
}
/// sets the global in this context.
- pub fn set_global<G: 'static>(&mut self, global: G) {
+ pub fn set_global<G: Global>(&mut self, global: G) {
let mut lock = self.app.borrow_mut();
lock.set_global(global);
}
/// updates the global in this context. (panics if `has_global` would return false)
- pub fn update_global<G: 'static, R>(
+ pub fn update_global<G: Global, R>(
&mut self,
update: impl FnOnce(&mut G, &mut AppContext) -> R,
) -> R {
@@ -17,11 +17,11 @@
use crate::{
point, px, size, Action, AnyDrag, AnyElement, AnyTooltip, AnyView, AppContext, Bounds,
- ClickEvent, DispatchPhase, Element, ElementContext, ElementId, FocusHandle, IntoElement,
- IsZero, KeyContext, KeyDownEvent, KeyUpEvent, LayoutId, MouseButton, MouseDownEvent,
- MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, Point, Render, ScrollWheelEvent,
- SharedString, Size, StackingOrder, Style, StyleRefinement, Styled, Task, View, Visibility,
- WindowContext,
+ ClickEvent, DispatchPhase, Element, ElementContext, ElementId, FocusHandle, Global,
+ IntoElement, IsZero, KeyContext, KeyDownEvent, KeyUpEvent, LayoutId, MouseButton,
+ MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, Point, Render,
+ ScrollWheelEvent, SharedString, Size, StackingOrder, Style, StyleRefinement, Styled, Task,
+ View, Visibility, WindowContext,
};
use collections::HashMap;
@@ -2070,6 +2070,8 @@ impl ElementClickedState {
#[derive(Default)]
pub(crate) struct GroupBounds(HashMap<SharedString, SmallVec<[Bounds<Pixels>; 1]>>);
+impl Global for GroupBounds {}
+
impl GroupBounds {
pub fn get(name: &SharedString, cx: &mut AppContext) -> Option<Bounds<Pixels>> {
cx.default_global::<Self>()
@@ -258,14 +258,14 @@ pub trait EventEmitter<E: Any>: 'static {}
/// can be used interchangeably.
pub trait BorrowAppContext {
/// Set a global value on the context.
- fn set_global<T: 'static>(&mut self, global: T);
+ fn set_global<T: Global>(&mut self, global: T);
}
impl<C> BorrowAppContext for C
where
C: BorrowMut<AppContext>,
{
- fn set_global<G: 'static>(&mut self, global: G) {
+ fn set_global<G: Global>(&mut self, global: G) {
self.borrow_mut().set_global(global)
}
}
@@ -287,3 +287,8 @@ impl<T> Flatten<T> for Result<T> {
self
}
}
+
+/// A marker trait for types that can be stored in GPUI's global state.
+///
+/// Implement this on types you want to store in the context as a global.
+pub trait Global: 'static {}
@@ -3,8 +3,8 @@ use std::{iter, mem, ops::Range};
use crate::{
black, phi, point, quad, rems, AbsoluteLength, Bounds, ContentMask, Corners, CornersRefinement,
CursorStyle, DefiniteLength, Edges, EdgesRefinement, ElementContext, Font, FontFeatures,
- FontStyle, FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Rgba, SharedString, Size,
- SizeRefinement, Styled, TextRun,
+ FontStyle, FontWeight, Global, Hsla, Length, Pixels, Point, PointRefinement, Rgba,
+ SharedString, Size, SizeRefinement, Styled, TextRun,
};
use collections::HashSet;
use refineable::Refineable;
@@ -20,6 +20,8 @@ pub use taffy::style::{
/// GPUI.
pub struct DebugBelow;
+impl Global for DebugBelow {}
+
/// The CSS styling that can be applied to an element via the `Styled` trait
#[derive(Clone, Refineable, Debug)]
#[refineable(Debug)]
@@ -2,7 +2,7 @@ use crate::{
px, size, transparent_black, Action, AnyDrag, AnyView, AppContext, Arena, AsyncWindowContext,
AvailableSpace, Bounds, Context, Corners, CursorStyle, DispatchActionListener, DispatchNodeId,
DispatchTree, DisplayId, Edges, Effect, Entity, EntityId, EventEmitter, FileDropEvent, Flatten,
- GlobalElementId, Hsla, KeyBinding, KeyContext, KeyDownEvent, KeyMatch, KeymatchMode,
+ Global, GlobalElementId, Hsla, KeyBinding, KeyContext, KeyDownEvent, KeyMatch, KeymatchMode,
KeymatchResult, Keystroke, KeystrokeEvent, Model, ModelContext, Modifiers, MouseButton,
MouseMoveEvent, MouseUpEvent, Pixels, PlatformAtlas, PlatformDisplay, PlatformInput,
PlatformWindow, Point, PromptLevel, Render, ScaledPixels, SharedString, Size, SubscriberSet,
@@ -708,7 +708,7 @@ impl<'a> WindowContext<'a> {
/// access both to the global and the context.
pub fn update_global<G, R>(&mut self, f: impl FnOnce(&mut G, &mut Self) -> R) -> R
where
- G: 'static,
+ G: Global,
{
let mut global = self.app.lease_global::<G>();
let result = f(&mut global, self);
@@ -1441,7 +1441,7 @@ impl<'a> WindowContext<'a> {
/// Register the given handler to be invoked whenever the global of the given type
/// is updated.
- pub fn observe_global<G: 'static>(
+ pub fn observe_global<G: Global>(
&mut self,
f: impl Fn(&mut WindowContext<'_>) + 'static,
) -> Subscription {
@@ -2198,7 +2198,7 @@ impl<'a, V: 'static> ViewContext<'a, V> {
/// Updates the global state of the given type.
pub fn update_global<G, R>(&mut self, f: impl FnOnce(&mut G, &mut Self) -> R) -> R
where
- G: 'static,
+ G: Global,
{
let mut global = self.app.lease_global::<G>();
let result = f(&mut global, self);
@@ -2207,7 +2207,7 @@ impl<'a, V: 'static> ViewContext<'a, V> {
}
/// Register a callback to be invoked when the given global state changes.
- pub fn observe_global<G: 'static>(
+ pub fn observe_global<G: Global>(
&mut self,
mut f: impl FnMut(&mut V, &mut ViewContext<'_, V>) + 'static,
) -> Subscription {
@@ -3,7 +3,9 @@ use channel::{ChannelMessage, ChannelMessageId, ChannelStore};
use client::{Client, UserStore};
use collections::HashMap;
use db::smol::stream::StreamExt;
-use gpui::{AppContext, AsyncAppContext, Context as _, EventEmitter, Model, ModelContext, Task};
+use gpui::{
+ AppContext, AsyncAppContext, Context as _, EventEmitter, Global, Model, ModelContext, Task,
+};
use rpc::{proto, Notification, TypedEnvelope};
use std::{ops::Range, sync::Arc};
use sum_tree::{Bias, SumTree};
@@ -12,9 +14,13 @@ use util::ResultExt;
pub fn init(client: Arc<Client>, user_store: Model<UserStore>, cx: &mut AppContext) {
let notification_store = cx.new_model(|cx| NotificationStore::new(client, user_store, cx));
- cx.set_global(notification_store);
+ cx.set_global(GlobalNotificationStore(notification_store));
}
+struct GlobalNotificationStore(Model<NotificationStore>);
+
+impl Global for GlobalNotificationStore {}
+
pub struct NotificationStore {
client: Arc<Client>,
user_store: Model<UserStore>,
@@ -70,7 +76,7 @@ struct NotificationId(u64);
impl NotificationStore {
pub fn global(cx: &AppContext) -> Model<Self> {
- cx.global::<Model<Self>>().clone()
+ cx.global::<GlobalNotificationStore>().0.clone()
}
pub fn new(
@@ -2,7 +2,7 @@ use std::{path::Path, str, sync::Arc};
use collections::HashMap;
-use gpui::{AppContext, AssetSource};
+use gpui::{AppContext, AssetSource, Global};
use serde_derive::Deserialize;
use util::{maybe, paths::PathExt};
@@ -17,6 +17,8 @@ pub struct FileAssociations {
types: HashMap<String, TypeConfig>,
}
+impl Global for FileAssociations {}
+
const COLLAPSED_DIRECTORY_TYPE: &'static str = "collapsed_folder";
const EXPANDED_DIRECTORY_TYPE: &'static str = "expanded_folder";
const COLLAPSED_CHEVRON_TYPE: &'static str = "collapsed_chevron";
@@ -0,0 +1,10 @@
+[package]
+name = "release_channel"
+version = "0.1.0"
+edition = "2021"
+publish = false
+license = "GPL-3.0-or-later"
+
+[dependencies]
+gpui = { path = "../gpui" }
+once_cell = "1.19.0"
@@ -0,0 +1 @@
+../../LICENSE-GPL
@@ -1,24 +1,44 @@
-use lazy_static::lazy_static;
+use gpui::{AppContext, Global};
+use once_cell::sync::Lazy;
use std::env;
-lazy_static! {
- pub static ref RELEASE_CHANNEL_NAME: String = if cfg!(debug_assertions) {
+#[doc(hidden)]
+pub static RELEASE_CHANNEL_NAME: Lazy<String> = if cfg!(debug_assertions) {
+ Lazy::new(|| {
env::var("ZED_RELEASE_CHANNEL")
.unwrap_or_else(|_| include_str!("../../zed/RELEASE_CHANNEL").to_string())
- } else {
- include_str!("../../zed/RELEASE_CHANNEL").to_string()
- };
- pub static ref RELEASE_CHANNEL: ReleaseChannel = match RELEASE_CHANNEL_NAME.as_str().trim() {
+ })
+} else {
+ Lazy::new(|| include_str!("../../zed/RELEASE_CHANNEL").to_string())
+};
+#[doc(hidden)]
+pub static RELEASE_CHANNEL: Lazy<ReleaseChannel> =
+ Lazy::new(|| match RELEASE_CHANNEL_NAME.as_str().trim() {
"dev" => ReleaseChannel::Dev,
"nightly" => ReleaseChannel::Nightly,
"preview" => ReleaseChannel::Preview,
"stable" => ReleaseChannel::Stable,
_ => panic!("invalid release channel {}", *RELEASE_CHANNEL_NAME),
- };
-}
+ });
+#[derive(Clone)]
pub struct AppCommitSha(pub String);
+struct GlobalAppCommitSha(AppCommitSha);
+
+impl Global for GlobalAppCommitSha {}
+
+impl AppCommitSha {
+ pub fn try_global(cx: &AppContext) -> Option<AppCommitSha> {
+ cx.try_global::<GlobalAppCommitSha>()
+ .map(|sha| sha.0.clone())
+ }
+
+ pub fn set_global(sha: AppCommitSha, cx: &mut AppContext) {
+ cx.set_global(GlobalAppCommitSha(sha))
+ }
+}
+
#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
pub enum ReleaseChannel {
#[default]
@@ -28,7 +48,24 @@ pub enum ReleaseChannel {
Stable,
}
+struct GlobalReleaseChannel(ReleaseChannel);
+
+impl Global for GlobalReleaseChannel {}
+
impl ReleaseChannel {
+ pub fn init(cx: &mut AppContext) {
+ cx.set_global(GlobalReleaseChannel(*RELEASE_CHANNEL))
+ }
+
+ pub fn global(cx: &AppContext) -> Self {
+ cx.global::<GlobalReleaseChannel>().0
+ }
+
+ pub fn try_global(cx: &AppContext) -> Option<Self> {
+ cx.try_global::<GlobalReleaseChannel>()
+ .map(|channel| channel.0)
+ }
+
pub fn display_name(&self) -> &'static str {
match self {
ReleaseChannel::Dev => "Zed Dev",
@@ -13,10 +13,10 @@ use editor::{
use editor::{EditorElement, EditorStyle};
use gpui::{
actions, div, Action, AnyElement, AnyView, AppContext, Context as _, Element, EntityId,
- EventEmitter, FocusHandle, FocusableView, FontStyle, FontWeight, Hsla, InteractiveElement,
- IntoElement, KeyContext, Model, ModelContext, ParentElement, PromptLevel, Render, SharedString,
- Styled, Subscription, Task, TextStyle, View, ViewContext, VisualContext, WeakModel, WeakView,
- WhiteSpace, WindowContext,
+ EventEmitter, FocusHandle, FocusableView, FontStyle, FontWeight, Global, Hsla,
+ InteractiveElement, IntoElement, KeyContext, Model, ModelContext, ParentElement, PromptLevel,
+ Render, SharedString, Styled, Subscription, Task, TextStyle, View, ViewContext, VisualContext,
+ WeakModel, WeakView, WhiteSpace, WindowContext,
};
use menu::Confirm;
use project::{
@@ -58,6 +58,8 @@ actions!(
#[derive(Default)]
struct ActiveSettings(HashMap<WeakModel<Project>, ProjectSearchSettings>);
+impl Global for ActiveSettings {}
+
pub fn init(cx: &mut AppContext) {
cx.set_global(ActiveSettings::default());
cx.observe_new_views(|workspace: &mut Workspace, _cx| {
@@ -17,6 +17,7 @@ language = { path = "../language" }
project = { path = "../project" }
workspace = { path = "../workspace" }
util = { path = "../util" }
+release_channel = { path = "../release_channel" }
rpc = { path = "../rpc" }
settings = { path = "../settings" }
anyhow.workspace = true
@@ -15,8 +15,8 @@ use db::VectorDatabase;
use embedding_queue::{EmbeddingQueue, FileToEmbed};
use futures::{future, FutureExt, StreamExt};
use gpui::{
- AppContext, AsyncAppContext, BorrowWindow, Context, Model, ModelContext, Task, ViewContext,
- WeakModel,
+ AppContext, AsyncAppContext, BorrowWindow, Context, Global, Model, ModelContext, Task,
+ ViewContext, WeakModel,
};
use language::{Anchor, Bias, Buffer, Language, LanguageRegistry};
use lazy_static::lazy_static;
@@ -25,6 +25,7 @@ use parking_lot::Mutex;
use parsing::{CodeContextRetriever, Span, SpanDigest, PARSEABLE_ENTIRE_FILE_TYPES};
use postage::watch;
use project::{Fs, PathChange, Project, ProjectEntryId, Worktree, WorktreeId};
+use release_channel::ReleaseChannel;
use settings::Settings;
use smol::channel;
use std::{
@@ -38,7 +39,7 @@ use std::{
time::{Duration, Instant, SystemTime},
};
use util::paths::PathMatcher;
-use util::{channel::RELEASE_CHANNEL_NAME, http::HttpClient, paths::EMBEDDINGS_DIR, ResultExt};
+use util::{http::HttpClient, paths::EMBEDDINGS_DIR, ResultExt};
use workspace::Workspace;
const SEMANTIC_INDEX_VERSION: usize = 11;
@@ -58,7 +59,7 @@ pub fn init(
SemanticIndexSettings::register(cx);
let db_file_path = EMBEDDINGS_DIR
- .join(Path::new(RELEASE_CHANNEL_NAME.as_str()))
+ .join(Path::new(ReleaseChannel::global(cx).dev_name()))
.join("embeddings_db");
cx.observe_new_views(
@@ -101,7 +102,7 @@ pub fn init(
)
.await?;
- cx.update(|cx| cx.set_global(semantic_index.clone()))?;
+ cx.update(|cx| cx.set_global(GlobalSemanticIndex(semantic_index.clone())))?;
anyhow::Ok(())
})
@@ -130,6 +131,10 @@ pub struct SemanticIndex {
projects: HashMap<WeakModel<Project>, ProjectState>,
}
+struct GlobalSemanticIndex(Model<SemanticIndex>);
+
+impl Global for GlobalSemanticIndex {}
+
struct ProjectState {
worktrees: HashMap<WorktreeId, WorktreeState>,
pending_file_count_rx: watch::Receiver<usize>,
@@ -274,8 +279,8 @@ pub struct SearchResult {
impl SemanticIndex {
pub fn global(cx: &mut AppContext) -> Option<Model<SemanticIndex>> {
- cx.try_global::<Model<Self>>()
- .map(|semantic_index| semantic_index.clone())
+ cx.try_global::<GlobalSemanticIndex>()
+ .map(|semantic_index| semantic_index.0.clone())
}
pub fn authenticate(&mut self, cx: &mut AppContext) -> Task<bool> {
@@ -17,6 +17,7 @@ collections = { path = "../collections" }
gpui = { path = "../gpui" }
fs = { path = "../fs" }
feature_flags = { path = "../feature_flags" }
+release_channel = { path = "../release_channel" }
util = { path = "../util" }
anyhow.workspace = true
@@ -1,6 +1,6 @@
use anyhow::{anyhow, Context, Result};
use collections::{btree_map, hash_map, BTreeMap, HashMap};
-use gpui::{AppContext, AsyncAppContext};
+use gpui::{AppContext, AsyncAppContext, Global};
use lazy_static::lazy_static;
use schemars::{gen::SchemaGenerator, schema::RootSchema, JsonSchema};
use serde::{de::DeserializeOwned, Deserialize as _, Serialize};
@@ -13,9 +13,7 @@ use std::{
str,
sync::Arc,
};
-use util::{
- channel::RELEASE_CHANNEL_NAME, merge_non_null_json_value_into, RangeExt, ResultExt as _,
-};
+use util::{merge_non_null_json_value_into, RangeExt, ResultExt as _};
/// A value that can be defined as a user setting.
///
@@ -139,6 +137,8 @@ pub struct SettingsStore {
)>,
}
+impl Global for SettingsStore {}
+
impl Default for SettingsStore {
fn default() -> Self {
SettingsStore {
@@ -207,7 +207,10 @@ impl SettingsStore {
user_values_stack = vec![user_settings];
}
- if let Some(release_settings) = &self.raw_user_settings.get(&*RELEASE_CHANNEL_NAME) {
+ if let Some(release_settings) = &self
+ .raw_user_settings
+ .get(&*release_channel::RELEASE_CHANNEL_NAME)
+ {
if let Some(release_settings) = setting_value
.deserialize_setting(&release_settings)
.log_err()
@@ -537,7 +540,10 @@ impl SettingsStore {
paths_stack.push(None);
}
- if let Some(release_settings) = &self.raw_user_settings.get(&*RELEASE_CHANNEL_NAME) {
+ if let Some(release_settings) = &self
+ .raw_user_settings
+ .get(&*release_channel::RELEASE_CHANNEL_NAME)
+ {
if let Some(release_settings) = setting_value
.deserialize_setting(&release_settings)
.log_err()
@@ -6,7 +6,7 @@ use anyhow::{anyhow, Context, Result};
use derive_more::{Deref, DerefMut};
use fs::Fs;
use futures::StreamExt;
-use gpui::{AppContext, AssetSource, HighlightStyle, SharedString};
+use gpui::{AppContext, AssetSource, Global, HighlightStyle, SharedString};
use parking_lot::RwLock;
use refineable::Refineable;
use util::ResultExt;
@@ -32,10 +32,7 @@ pub struct ThemeMeta {
#[derive(Default, Deref, DerefMut)]
struct GlobalThemeRegistry(Arc<ThemeRegistry>);
-/// Initializes the theme registry.
-pub fn init(assets: Box<dyn AssetSource>, cx: &mut AppContext) {
- cx.set_global(GlobalThemeRegistry(Arc::new(ThemeRegistry::new(assets))));
-}
+impl Global for GlobalThemeRegistry {}
struct ThemeRegistryState {
themes: HashMap<SharedString, Arc<Theme>>,
@@ -59,6 +56,11 @@ impl ThemeRegistry {
cx.default_global::<GlobalThemeRegistry>().0.clone()
}
+ /// Sets the global [`ThemeRegistry`].
+ pub(crate) fn set_global(assets: Box<dyn AssetSource>, cx: &mut AppContext) {
+ cx.set_global(GlobalThemeRegistry(Arc::new(ThemeRegistry::new(assets))));
+ }
+
pub fn new(assets: Box<dyn AssetSource>) -> Self {
let registry = Self {
state: RwLock::new(ThemeRegistryState {
@@ -2,7 +2,8 @@ use crate::one_themes::one_dark;
use crate::{SyntaxTheme, Theme, ThemeRegistry, ThemeStyleContent};
use anyhow::Result;
use gpui::{
- px, AppContext, Font, FontFeatures, FontStyle, FontWeight, Pixels, Subscription, ViewContext,
+ px, AppContext, Font, FontFeatures, FontStyle, FontWeight, Global, Pixels, Subscription,
+ ViewContext,
};
use refineable::Refineable;
use schemars::{
@@ -34,6 +35,8 @@ pub struct ThemeSettings {
#[derive(Default)]
pub(crate) struct AdjustedBufferFontSize(Pixels);
+impl Global for AdjustedBufferFontSize {}
+
#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)]
pub struct ThemeSettingsContent {
#[serde(default)]
@@ -60,7 +60,7 @@ pub fn init(themes_to_load: LoadThemes, cx: &mut AppContext) {
LoadThemes::JustBase => (Box::new(()) as Box<dyn AssetSource>, false),
LoadThemes::All(assets) => (assets, true),
};
- registry::init(assets, cx);
+ ThemeRegistry::set_global(assets, cx);
if load_user_themes {
ThemeRegistry::global(cx).load_bundled_themes();
@@ -36,24 +36,6 @@ pub fn toggle(workspace: &mut Workspace, _: &Toggle, cx: &mut ViewContext<Worksp
});
}
-#[cfg(debug_assertions)]
-pub fn reload(cx: &mut AppContext) {
- let current_theme_name = cx.theme().name.clone();
- let current_theme = cx.update_global(|registry: &mut ThemeRegistry, _cx| {
- registry.clear();
- registry.get(¤t_theme_name)
- });
- match current_theme {
- Ok(theme) => {
- ThemeSelectorDelegate::set_theme(theme, cx);
- log::info!("reloaded theme {}", current_theme_name);
- }
- Err(error) => {
- log::error!("failed to load theme {}: {:?}", current_theme_name, error)
- }
- }
-}
-
impl ModalView for ThemeSelector {}
pub struct ThemeSelector {
@@ -1,5 +1,4 @@
pub mod arc_cow;
-pub mod channel;
pub mod fs;
pub mod github;
pub mod http;
@@ -28,6 +28,8 @@ regex.workspace = true
collections = { path = "../collections" }
command_palette = { path = "../command_palette" }
+# HACK: We're only depending on `copilot` here for `CommandPaletteFilter`. See the attached comment on that type.
+copilot = { path = "../copilot" }
editor = { path = "../editor" }
gpui = { path = "../gpui" }
language = { path = "../language" }
@@ -15,11 +15,12 @@ mod utils;
mod visual;
use anyhow::Result;
-use collections::{CommandPaletteFilter, HashMap};
+use collections::HashMap;
use command_palette::CommandPaletteInterceptor;
+use copilot::CommandPaletteFilter;
use editor::{movement, Editor, EditorEvent, EditorMode};
use gpui::{
- actions, impl_actions, Action, AppContext, EntityId, KeyContext, Subscription, View,
+ actions, impl_actions, Action, AppContext, EntityId, Global, KeyContext, Subscription, View,
ViewContext, WeakView, WindowContext,
};
use language::{CursorShape, Point, Selection, SelectionGoal};
@@ -171,9 +172,9 @@ pub fn observe_keystrokes(cx: &mut WindowContext) {
.detach()
}
-/// The state pertaining to Vim mode. Stored as a global.
+/// The state pertaining to Vim mode.
#[derive(Default)]
-pub struct Vim {
+struct Vim {
active_editor: Option<WeakView<Editor>>,
editor_subscription: Option<Subscription>,
enabled: bool,
@@ -182,6 +183,8 @@ pub struct Vim {
default_state: EditorState,
}
+impl Global for Vim {}
+
impl Vim {
fn read(cx: &mut AppContext) -> &Self {
cx.global::<Self>()
@@ -512,7 +515,9 @@ impl Vim {
});
if self.enabled {
- cx.set_global::<CommandPaletteInterceptor>(Box::new(command::command_interceptor));
+ cx.set_global::<CommandPaletteInterceptor>(CommandPaletteInterceptor(Box::new(
+ command::command_interceptor,
+ )));
} else if cx.has_global::<CommandPaletteInterceptor>() {
let _ = cx.remove_global::<CommandPaletteInterceptor>();
}
@@ -43,6 +43,7 @@ async-recursion = "1.0.0"
itertools = "0.10"
bincode = "1.2.1"
anyhow.workspace = true
+derive_more.workspace = true
futures.workspace = true
lazy_static.workspace = true
log.workspace = true
@@ -1,7 +1,7 @@
use crate::{Toast, Workspace};
use collections::HashMap;
use gpui::{
- AnyView, AppContext, AsyncWindowContext, DismissEvent, Entity, EntityId, EventEmitter,
+ AnyView, AppContext, AsyncWindowContext, DismissEvent, Entity, EntityId, EventEmitter, Global,
PromptLevel, Render, Task, View, ViewContext, VisualContext, WindowContext,
};
use std::{any::TypeId, ops::DerefMut};
@@ -39,6 +39,8 @@ pub(crate) struct NotificationTracker {
notifications_sent: HashMap<TypeId, Vec<usize>>,
}
+impl Global for NotificationTracker {}
+
impl std::ops::Deref for NotificationTracker {
type Target = HashMap<TypeId, Vec<usize>>;
@@ -18,6 +18,7 @@ use client::{
Client, ErrorExt, Status, TypedEnvelope, UserStore,
};
use collections::{hash_map, HashMap, HashSet};
+use derive_more::{Deref, DerefMut};
use dock::{Dock, DockPosition, Panel, PanelButtons, PanelHandle};
use futures::{
channel::{mpsc, oneshot},
@@ -28,7 +29,7 @@ use gpui::{
actions, canvas, div, impl_actions, point, px, size, Action, AnyElement, AnyModel, AnyView,
AnyWeakView, AppContext, AsyncAppContext, AsyncWindowContext, Bounds, Context, Div,
DragMoveEvent, Element, ElementContext, Entity, EntityId, EventEmitter, FocusHandle,
- FocusableView, GlobalPixels, InteractiveElement, IntoElement, KeyContext, LayoutId,
+ FocusableView, Global, GlobalPixels, InteractiveElement, IntoElement, KeyContext, LayoutId,
ManagedView, Model, ModelContext, ParentElement, PathPromptOptions, Pixels, Point, PromptLevel,
Render, SharedString, Size, Styled, Subscription, Task, View, ViewContext, VisualContext,
WeakView, WindowBounds, WindowContext, WindowHandle, WindowOptions,
@@ -59,6 +60,7 @@ use std::{
borrow::Cow,
cmp, env,
path::{Path, PathBuf},
+ sync::Weak,
sync::{atomic::AtomicUsize, Arc},
time::Duration,
};
@@ -256,8 +258,13 @@ pub fn init(app_state: Arc<AppState>, cx: &mut AppContext) {
});
}
-type ProjectItemBuilders =
- HashMap<TypeId, fn(Model<Project>, AnyModel, &mut ViewContext<Pane>) -> Box<dyn ItemHandle>>;
+#[derive(Clone, Default, Deref, DerefMut)]
+struct ProjectItemBuilders(
+ HashMap<TypeId, fn(Model<Project>, AnyModel, &mut ViewContext<Pane>) -> Box<dyn ItemHandle>>,
+);
+
+impl Global for ProjectItemBuilders {}
+
pub fn register_project_item<I: ProjectItem>(cx: &mut AppContext) {
let builders = cx.default_global::<ProjectItemBuilders>();
builders.insert(TypeId::of::<I::Item>(), |project, model, cx| {
@@ -273,13 +280,20 @@ type FollowableItemBuilder = fn(
&mut Option<proto::view::Variant>,
&mut WindowContext,
) -> Option<Task<Result<Box<dyn FollowableItemHandle>>>>;
-type FollowableItemBuilders = HashMap<
- TypeId,
- (
- FollowableItemBuilder,
- fn(&AnyView) -> Box<dyn FollowableItemHandle>,
- ),
->;
+
+#[derive(Default, Deref, DerefMut)]
+struct FollowableItemBuilders(
+ HashMap<
+ TypeId,
+ (
+ FollowableItemBuilder,
+ fn(&AnyView) -> Box<dyn FollowableItemHandle>,
+ ),
+ >,
+);
+
+impl Global for FollowableItemBuilders {}
+
pub fn register_followable_item<I: FollowableItem>(cx: &mut AppContext) {
let builders = cx.default_global::<FollowableItemBuilders>();
builders.insert(
@@ -296,16 +310,22 @@ pub fn register_followable_item<I: FollowableItem>(cx: &mut AppContext) {
);
}
-type ItemDeserializers = HashMap<
- Arc<str>,
- fn(
- Model<Project>,
- WeakView<Workspace>,
- WorkspaceId,
- ItemId,
- &mut ViewContext<Pane>,
- ) -> Task<Result<Box<dyn ItemHandle>>>,
->;
+#[derive(Default, Deref, DerefMut)]
+struct ItemDeserializers(
+ HashMap<
+ Arc<str>,
+ fn(
+ Model<Project>,
+ WeakView<Workspace>,
+ WorkspaceId,
+ ItemId,
+ &mut ViewContext<Pane>,
+ ) -> Task<Result<Box<dyn ItemHandle>>>,
+ >,
+);
+
+impl Global for ItemDeserializers {}
+
pub fn register_deserializable_item<I: Item>(cx: &mut AppContext) {
if let Some(serialized_item_kind) = I::serialized_item_kind() {
let deserializers = cx.default_global::<ItemDeserializers>();
@@ -331,6 +351,10 @@ pub struct AppState {
pub node_runtime: Arc<dyn NodeRuntime>,
}
+struct GlobalAppState(Weak<AppState>);
+
+impl Global for GlobalAppState {}
+
pub struct WorkspaceStore {
workspaces: HashSet<WindowHandle<Workspace>>,
followers: Vec<Follower>,
@@ -345,6 +369,17 @@ struct Follower {
}
impl AppState {
+ pub fn global(cx: &AppContext) -> Weak<Self> {
+ cx.global::<GlobalAppState>().0.clone()
+ }
+ pub fn try_global(cx: &AppContext) -> Option<Weak<Self>> {
+ cx.try_global::<GlobalAppState>()
+ .map(|state| state.0.clone())
+ }
+ pub fn set_global(state: Weak<AppState>, cx: &mut AppContext) {
+ cx.set_global(GlobalAppState(state));
+ }
+
#[cfg(any(test, feature = "test-support"))]
pub fn test(cx: &mut AppContext) -> Arc<Self> {
use node_runtime::FakeNodeRuntime;
@@ -616,7 +651,7 @@ impl Workspace {
let modal_layer = cx.new_view(|_| ModalLayer::new());
let mut active_call = None;
- if let Some(call) = cx.try_global::<Model<ActiveCall>>() {
+ if let Some(call) = ActiveCall::try_global(cx) {
let call = call.clone();
let mut subscriptions = Vec::new();
subscriptions.push(cx.subscribe(&call, Self::on_active_call_event));
@@ -3657,7 +3692,7 @@ impl WorkspaceStore {
update: proto::update_followers::Variant,
cx: &AppContext,
) -> Option<()> {
- let active_call = cx.try_global::<Model<ActiveCall>>()?;
+ let active_call = ActiveCall::try_global(cx)?;
let room_id = active_call.read(cx).room()?.read(cx).id();
let follower_ids: Vec<_> = self
.followers
@@ -59,6 +59,7 @@ project_panel = { path = "../project_panel" }
project_symbols = { path = "../project_symbols" }
quick_action_bar = { path = "../quick_action_bar" }
recent_projects = { path = "../recent_projects" }
+release_channel = { path = "../release_channel" }
rope = { path = "../rope"}
rpc = { path = "../rpc" }
settings = { path = "../settings" }
@@ -19,6 +19,7 @@ use log::LevelFilter;
use assets::Assets;
use node_runtime::RealNodeRuntime;
use parking_lot::Mutex;
+use release_channel::{parse_zed_link, AppCommitSha, ReleaseChannel, RELEASE_CHANNEL};
use serde::{Deserialize, Serialize};
use settings::{
default_settings, handle_settings_file_changes, watch_config_file, Settings, SettingsStore,
@@ -34,14 +35,13 @@ use std::{
path::{Path, PathBuf},
sync::{
atomic::{AtomicU32, Ordering},
- Arc, Weak,
+ Arc,
},
thread,
};
use theme::{ActiveTheme, ThemeRegistry, ThemeSettings};
use util::{
async_maybe,
- channel::{parse_zed_link, AppCommitSha, ReleaseChannel, RELEASE_CHANNEL},
http::{self, HttpClient, ZedHttpClient},
paths::{self, CRASHES_DIR, CRASHES_RETIRED_DIR},
ResultExt,
@@ -102,8 +102,7 @@ fn main() {
let open_listener = listener.clone();
app.on_open_urls(move |urls, _| open_listener.open_urls(&urls));
app.on_reopen(move |cx| {
- if let Some(app_state) = cx
- .try_global::<Weak<AppState>>()
+ if let Some(app_state) = AppState::try_global(cx)
.map(|app_state| app_state.upgrade())
.flatten()
{
@@ -115,12 +114,12 @@ fn main() {
});
app.run(move |cx| {
- cx.set_global(*RELEASE_CHANNEL);
+ ReleaseChannel::init(cx);
if let Some(build_sha) = option_env!("ZED_COMMIT_SHA") {
- cx.set_global(AppCommitSha(build_sha.into()))
+ AppCommitSha::set_global(AppCommitSha(build_sha.into()), cx);
}
- cx.set_global(listener.clone());
+ OpenListener::set_global(listener.clone(), cx);
load_embedded_fonts(cx);
@@ -148,7 +147,7 @@ fn main() {
let user_store = cx.new_model(|cx| UserStore::new(client.clone(), cx));
let workspace_store = cx.new_model(|cx| WorkspaceStore::new(client.clone(), cx));
- cx.set_global(client.clone());
+ Client::set_global(client.clone(), cx);
zed::init(cx);
theme::init(theme::LoadThemes::All(Box::new(Assets)), cx);
@@ -242,7 +241,7 @@ fn main() {
workspace_store,
node_runtime,
});
- cx.set_global(Arc::downgrade(&app_state));
+ AppState::set_global(Arc::downgrade(&app_state), cx);
audio::init(Assets, cx);
auto_update::init(http.clone(), cx);
@@ -565,7 +564,7 @@ fn init_panic_hook(app: &App, installation_id: Option<String>, session_id: Strin
.or_else(|| info.payload().downcast_ref::<String>().map(|s| s.clone()))
.unwrap_or_else(|| "Box<Any>".to_string());
- if *util::channel::RELEASE_CHANNEL == ReleaseChannel::Dev {
+ if *release_channel::RELEASE_CHANNEL == ReleaseChannel::Dev {
let location = info.location().unwrap();
let backtrace = Backtrace::new();
eprintln!(
@@ -5,7 +5,7 @@ use std::{
time::Duration,
};
-use util::channel::ReleaseChannel;
+use release_channel::ReleaseChannel;
const LOCALHOST: Ipv4Addr = Ipv4Addr::new(127, 0, 0, 1);
const CONNECT_TIMEOUT: Duration = Duration::from_millis(10);
@@ -13,7 +13,7 @@ const RECEIVE_TIMEOUT: Duration = Duration::from_millis(35);
const SEND_TIMEOUT: Duration = Duration::from_millis(20);
fn address() -> SocketAddr {
- let port = match *util::channel::RELEASE_CHANNEL {
+ let port = match *release_channel::RELEASE_CHANNEL {
ReleaseChannel::Dev => 43737,
ReleaseChannel::Preview => 43738,
ReleaseChannel::Stable => 43739,
@@ -24,7 +24,7 @@ fn address() -> SocketAddr {
}
fn instance_handshake() -> &'static str {
- match *util::channel::RELEASE_CHANNEL {
+ match *release_channel::RELEASE_CHANNEL {
ReleaseChannel::Dev => "Zed Editor Dev Instance Running",
ReleaseChannel::Nightly => "Zed Editor Nightly Instance Running",
ReleaseChannel::Preview => "Zed Editor Preview Instance Running",
@@ -39,7 +39,7 @@ pub enum IsOnlyInstance {
}
pub fn ensure_only_instance() -> IsOnlyInstance {
- if *db::ZED_STATELESS || *util::channel::RELEASE_CHANNEL == ReleaseChannel::Dev {
+ if *db::ZED_STATELESS || *release_channel::RELEASE_CHANNEL == ReleaseChannel::Dev {
return IsOnlyInstance::Yes;
}
@@ -6,8 +6,9 @@ use editor::Editor;
use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender};
use futures::channel::{mpsc, oneshot};
use futures::{FutureExt, SinkExt, StreamExt};
-use gpui::AsyncAppContext;
+use gpui::{AppContext, AsyncAppContext, Global};
use language::{Bias, Point};
+use release_channel::parse_zed_link;
use std::collections::HashMap;
use std::ffi::OsStr;
use std::os::unix::prelude::OsStrExt;
@@ -17,7 +18,6 @@ use std::sync::Arc;
use std::thread;
use std::time::Duration;
use std::{path::PathBuf, sync::atomic::AtomicBool};
-use util::channel::parse_zed_link;
use util::paths::PathLikeWithPosition;
use util::ResultExt;
use workspace::AppState;
@@ -42,7 +42,19 @@ pub struct OpenListener {
pub triggered: AtomicBool,
}
+struct GlobalOpenListener(Arc<OpenListener>);
+
+impl Global for GlobalOpenListener {}
+
impl OpenListener {
+ pub fn global(cx: &AppContext) -> Arc<Self> {
+ cx.global::<GlobalOpenListener>().0.clone()
+ }
+
+ pub fn set_global(listener: Arc<OpenListener>, cx: &mut AppContext) {
+ cx.set_global(GlobalOpenListener(listener))
+ }
+
pub fn new() -> (Self, UnboundedReceiver<OpenRequest>) {
let (tx, rx) = mpsc::unbounded();
(
@@ -20,6 +20,7 @@ use assets::Assets;
use futures::{channel::mpsc, select_biased, StreamExt};
use project_panel::ProjectPanel;
use quick_action_bar::QuickActionBar;
+use release_channel::{AppCommitSha, ReleaseChannel};
use rope::Rope;
use search::project_search::ProjectSearchBar;
use settings::{initial_local_settings_content, KeymapFile, Settings, SettingsStore};
@@ -27,7 +28,6 @@ use std::{borrow::Cow, ops::Deref, path::Path, sync::Arc};
use terminal_view::terminal_panel::{self, TerminalPanel};
use util::{
asset_str,
- channel::{AppCommitSha, ReleaseChannel},
paths::{self, LOCAL_SETTINGS_RELATIVE_PATH},
ResultExt,
};
@@ -202,8 +202,7 @@ pub fn initialize_workspace(app_state: Arc<AppState>, cx: &mut AppContext) {
cx.toggle_full_screen();
})
.register_action(|_, action: &OpenZedUrl, cx| {
- cx.global::<Arc<OpenListener>>()
- .open_urls(&[action.url.clone()])
+ OpenListener::global(cx).open_urls(&[action.url.clone()])
})
.register_action(|_, action: &OpenBrowser, cx| cx.open_url(&action.url))
.register_action(move |_, _: &IncreaseBufferFontSize, cx| {
@@ -370,12 +369,12 @@ fn initialize_pane(workspace: &mut Workspace, pane: &View<Pane>, cx: &mut ViewCo
}
fn about(_: &mut Workspace, _: &About, cx: &mut gpui::ViewContext<Workspace>) {
- let app_name = cx.global::<ReleaseChannel>().display_name();
+ let app_name = ReleaseChannel::global(cx).display_name();
let version = env!("CARGO_PKG_VERSION");
let message = format!("{app_name} {version}");
- let detail = cx.try_global::<AppCommitSha>().map(|sha| sha.0.as_ref());
+ let detail = AppCommitSha::try_global(cx).map(|sha| sha.0.clone());
- let prompt = cx.prompt(PromptLevel::Info, &message, detail, &["OK"]);
+ let prompt = cx.prompt(PromptLevel::Info, &message, detail.as_deref(), &["OK"]);
cx.foreground_executor()
.spawn(async {
prompt.await.ok();