1use gpui::{AppContext, Global, SemanticVersion};
2use once_cell::sync::Lazy;
3use std::env;
4
5#[doc(hidden)]
6static RELEASE_CHANNEL_NAME: Lazy<String> = if cfg!(debug_assertions) {
7 Lazy::new(|| {
8 env::var("ZED_RELEASE_CHANNEL")
9 .unwrap_or_else(|_| include_str!("../../zed/RELEASE_CHANNEL").trim().to_string())
10 })
11} else {
12 Lazy::new(|| include_str!("../../zed/RELEASE_CHANNEL").trim().to_string())
13};
14
15#[doc(hidden)]
16pub static RELEASE_CHANNEL: Lazy<ReleaseChannel> =
17 Lazy::new(|| match RELEASE_CHANNEL_NAME.as_str() {
18 "dev" => ReleaseChannel::Dev,
19 "nightly" => ReleaseChannel::Nightly,
20 "preview" => ReleaseChannel::Preview,
21 "stable" => ReleaseChannel::Stable,
22 _ => panic!("invalid release channel {}", *RELEASE_CHANNEL_NAME),
23 });
24
25#[derive(Clone)]
26pub struct AppCommitSha(pub String);
27
28struct GlobalAppCommitSha(AppCommitSha);
29
30impl Global for GlobalAppCommitSha {}
31
32impl AppCommitSha {
33 pub fn try_global(cx: &AppContext) -> Option<AppCommitSha> {
34 cx.try_global::<GlobalAppCommitSha>()
35 .map(|sha| sha.0.clone())
36 }
37
38 pub fn set_global(sha: AppCommitSha, cx: &mut AppContext) {
39 cx.set_global(GlobalAppCommitSha(sha))
40 }
41}
42
43struct GlobalAppVersion(SemanticVersion);
44
45impl Global for GlobalAppVersion {}
46
47pub struct AppVersion;
48
49impl AppVersion {
50 pub fn init(pkg_version: &str, cx: &mut AppContext) {
51 let version = if let Some(from_env) = env::var("ZED_APP_VERSION").ok() {
52 from_env.parse().expect("invalid ZED_APP_VERSION")
53 } else {
54 cx.app_metadata()
55 .app_version
56 .unwrap_or_else(|| pkg_version.parse().expect("invalid version in Cargo.toml"))
57 };
58 cx.set_global(GlobalAppVersion(version))
59 }
60
61 pub fn global(cx: &AppContext) -> SemanticVersion {
62 cx.global::<GlobalAppVersion>().0
63 }
64}
65
66#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)]
67pub enum ReleaseChannel {
68 #[default]
69 Dev,
70 Nightly,
71 Preview,
72 Stable,
73}
74
75struct GlobalReleaseChannel(ReleaseChannel);
76
77impl Global for GlobalReleaseChannel {}
78
79pub fn init(pkg_version: &str, cx: &mut AppContext) {
80 AppVersion::init(pkg_version, cx);
81 cx.set_global(GlobalReleaseChannel(*RELEASE_CHANNEL))
82}
83
84impl ReleaseChannel {
85 pub fn global(cx: &AppContext) -> Self {
86 cx.global::<GlobalReleaseChannel>().0
87 }
88
89 pub fn try_global(cx: &AppContext) -> Option<Self> {
90 cx.try_global::<GlobalReleaseChannel>()
91 .map(|channel| channel.0)
92 }
93
94 pub fn display_name(&self) -> &'static str {
95 match self {
96 ReleaseChannel::Dev => "Zed Dev",
97 ReleaseChannel::Nightly => "Zed Nightly",
98 ReleaseChannel::Preview => "Zed Preview",
99 ReleaseChannel::Stable => "Zed",
100 }
101 }
102
103 pub fn dev_name(&self) -> &'static str {
104 match self {
105 ReleaseChannel::Dev => "dev",
106 ReleaseChannel::Nightly => "nightly",
107 ReleaseChannel::Preview => "preview",
108 ReleaseChannel::Stable => "stable",
109 }
110 }
111
112 pub fn url_scheme(&self) -> &'static str {
113 match self {
114 ReleaseChannel::Dev => "zed-dev://",
115 ReleaseChannel::Nightly => "zed-nightly://",
116 ReleaseChannel::Preview => "zed-preview://",
117 ReleaseChannel::Stable => "zed://",
118 }
119 }
120
121 pub fn link_prefix(&self) -> &'static str {
122 match self {
123 ReleaseChannel::Dev => "https://zed.dev/dev/",
124 ReleaseChannel::Nightly => "https://zed.dev/nightly/",
125 ReleaseChannel::Preview => "https://zed.dev/preview/",
126 ReleaseChannel::Stable => "https://zed.dev/",
127 }
128 }
129
130 pub fn release_query_param(&self) -> Option<&'static str> {
131 match self {
132 Self::Dev => None,
133 Self::Nightly => Some("nightly=1"),
134 Self::Preview => Some("preview=1"),
135 Self::Stable => None,
136 }
137 }
138}
139
140pub fn parse_zed_link(link: &str) -> Option<&str> {
141 for release in [
142 ReleaseChannel::Dev,
143 ReleaseChannel::Nightly,
144 ReleaseChannel::Preview,
145 ReleaseChannel::Stable,
146 ] {
147 if let Some(stripped) = link.strip_prefix(release.link_prefix()) {
148 return Some(stripped);
149 }
150 if let Some(stripped) = link.strip_prefix(release.url_scheme()) {
151 return Some(stripped);
152 }
153 }
154 None
155}