Replace `lazy_static` with `std::sync::LazyLock` (#16066)

Sinan Gençoğlu and Marshall Bowers created

Closes #15860 

Since rust std now supports LazyLock replacing lazy_static with it
reduce the external dependency.

Release Notes:

- N/A

---------

Co-authored-by: Marshall Bowers <elliott.codes@gmail.com>

Change summary

Cargo.lock                                        | 15 -----
Cargo.toml                                        |  1 
crates/client/Cargo.toml                          |  1 
crates/client/src/client.rs                       | 49 +++++++++-------
crates/collab_ui/Cargo.toml                       |  1 
crates/collab_ui/src/chat_panel/message_editor.rs | 20 +++---
crates/db/Cargo.toml                              |  1 
crates/db/src/db.rs                               | 36 ++++++-----
crates/editor/Cargo.toml                          |  1 
crates/editor/src/display_map/wrap_map.rs         | 16 ++---
crates/fs/Cargo.toml                              |  1 
crates/fs/src/fs.rs                               |  5 -
crates/git/Cargo.toml                             |  1 
crates/git/src/git.rs                             |  8 +-
crates/gpui/Cargo.toml                            |  1 
crates/gpui/src/app/entity_map.rs                 |  6 -
crates/language/Cargo.toml                        |  1 
crates/language/src/buffer.rs                     | 11 +--
crates/language/src/buffer_tests.rs               |  9 +-
crates/language/src/language.rs                   | 23 +++----
crates/languages/Cargo.toml                       |  1 
crates/languages/src/go.rs                        | 15 ++--
crates/languages/src/rust.rs                      | 12 +--
crates/settings/Cargo.toml                        |  1 
crates/settings/src/settings_store.rs             | 16 ++---
crates/sqlez/Cargo.toml                           |  1 
crates/sqlez/src/thread_safe_connection.rs        | 25 ++++---
crates/sqlez_macros/Cargo.toml                    |  1 
crates/sqlez_macros/src/sqlez_macros.rs           | 16 +++--
crates/text/Cargo.toml                            |  1 
crates/text/src/locator.rs                        |  8 +-
crates/text/src/text.rs                           |  9 +-
crates/vim/Cargo.toml                             |  1 
crates/vim/src/digraph.rs                         | 22 +++----
crates/workspace/Cargo.toml                       |  1 
crates/workspace/src/workspace.rs                 | 18 +++--
36 files changed, 160 insertions(+), 195 deletions(-)

Detailed changes

Cargo.lock πŸ”—

@@ -2329,7 +2329,6 @@ dependencies = [
  "futures 0.3.30",
  "gpui",
  "http_client",
- "lazy_static",
  "log",
  "once_cell",
  "parking_lot",
@@ -2531,7 +2530,6 @@ dependencies = [
  "gpui",
  "http_client",
  "language",
- "lazy_static",
  "menu",
  "notifications",
  "parking_lot",
@@ -3263,7 +3261,6 @@ dependencies = [
  "anyhow",
  "gpui",
  "indoc",
- "lazy_static",
  "log",
  "paths",
  "release_channel",
@@ -3543,7 +3540,6 @@ dependencies = [
  "indoc",
  "itertools 0.11.0",
  "language",
- "lazy_static",
  "linkify",
  "log",
  "lsp",
@@ -4306,7 +4302,6 @@ dependencies = [
  "git",
  "git2",
  "gpui",
- "lazy_static",
  "libc",
  "notify",
  "objc",
@@ -4632,7 +4627,6 @@ dependencies = [
  "git2",
  "gpui",
  "http_client",
- "lazy_static",
  "log",
  "parking_lot",
  "pretty_assertions",
@@ -4831,7 +4825,6 @@ dependencies = [
  "http_client",
  "image",
  "itertools 0.11.0",
- "lazy_static",
  "linkme",
  "log",
  "media",
@@ -5947,7 +5940,6 @@ dependencies = [
  "http_client",
  "indoc",
  "itertools 0.11.0",
- "lazy_static",
  "log",
  "lsp",
  "parking_lot",
@@ -6081,7 +6073,6 @@ dependencies = [
  "gpui",
  "http_client",
  "language",
- "lazy_static",
  "log",
  "lsp",
  "node_runtime",
@@ -9741,7 +9732,6 @@ dependencies = [
  "futures 0.3.30",
  "gpui",
  "indoc",
- "lazy_static",
  "log",
  "paths",
  "pretty_assertions",
@@ -10153,7 +10143,6 @@ dependencies = [
  "collections",
  "futures 0.3.30",
  "indoc",
- "lazy_static",
  "libsqlite3-sys",
  "parking_lot",
  "smol",
@@ -10166,7 +10155,6 @@ dependencies = [
 name = "sqlez_macros"
 version = "0.1.0"
 dependencies = [
- "lazy_static",
  "sqlez",
  "sqlformat",
  "syn 1.0.109",
@@ -11014,7 +11002,6 @@ dependencies = [
  "env_logger",
  "gpui",
  "http_client",
- "lazy_static",
  "log",
  "parking_lot",
  "postage",
@@ -12212,7 +12199,6 @@ dependencies = [
  "indoc",
  "itertools 0.11.0",
  "language",
- "lazy_static",
  "log",
  "lsp",
  "multi_buffer",
@@ -13555,7 +13541,6 @@ dependencies = [
  "http_client",
  "itertools 0.11.0",
  "language",
- "lazy_static",
  "log",
  "node_runtime",
  "parking_lot",

Cargo.toml πŸ”—

@@ -359,7 +359,6 @@ isahc = { version = "1.7.2", default-features = false, features = [
 ] }
 itertools = "0.11.0"
 jsonwebtoken = "9.3"
-lazy_static = "1.4.0"
 libc = "0.2"
 linkify = "0.10.0"
 log = { version = "0.4.16", features = ["kv_unstable_serde", "serde"] }

crates/client/Cargo.toml πŸ”—

@@ -27,7 +27,6 @@ fs.workspace = true
 futures.workspace = true
 gpui.workspace = true
 http_client.workspace = true
-lazy_static.workspace = true
 log.workspace = true
 once_cell.workspace = true
 paths.workspace = true

crates/client/src/client.rs πŸ”—

@@ -22,7 +22,6 @@ use gpui::{
     actions, AnyModel, AnyWeakModel, AppContext, AsyncAppContext, Global, Model, Task, WeakModel,
 };
 use http_client::{AsyncBody, HttpClient, HttpClientWithUrl};
-use lazy_static::lazy_static;
 use parking_lot::RwLock;
 use postage::watch;
 use proto::ProtoClient;
@@ -43,7 +42,7 @@ use std::{
     path::PathBuf,
     sync::{
         atomic::{AtomicU64, Ordering},
-        Arc, Weak,
+        Arc, LazyLock, Weak,
     },
     time::{Duration, Instant},
 };
@@ -65,27 +64,35 @@ impl fmt::Display for DevServerToken {
     }
 }
 
-lazy_static! {
-    static ref ZED_SERVER_URL: Option<String> = std::env::var("ZED_SERVER_URL").ok();
-    static ref ZED_RPC_URL: Option<String> = std::env::var("ZED_RPC_URL").ok();
-    /// An environment variable whose presence indicates that the development auth
-    /// provider should be used.
-    ///
-    /// Only works in development. Setting this environment variable in other release
-    /// channels is a no-op.
-    pub static ref ZED_DEVELOPMENT_AUTH: bool =
-        std::env::var("ZED_DEVELOPMENT_AUTH").map_or(false, |value| !value.is_empty());
-    pub static ref IMPERSONATE_LOGIN: Option<String> = std::env::var("ZED_IMPERSONATE")
+static ZED_SERVER_URL: LazyLock<Option<String>> =
+    LazyLock::new(|| std::env::var("ZED_SERVER_URL").ok());
+static ZED_RPC_URL: LazyLock<Option<String>> = LazyLock::new(|| std::env::var("ZED_RPC_URL").ok());
+
+/// An environment variable whose presence indicates that the development auth
+/// provider should be used.
+///
+/// Only works in development. Setting this environment variable in other release
+/// channels is a no-op.
+pub static ZED_DEVELOPMENT_AUTH: LazyLock<bool> = LazyLock::new(|| {
+    std::env::var("ZED_DEVELOPMENT_AUTH").map_or(false, |value| !value.is_empty())
+});
+pub static IMPERSONATE_LOGIN: LazyLock<Option<String>> = LazyLock::new(|| {
+    std::env::var("ZED_IMPERSONATE")
         .ok()
-        .and_then(|s| if s.is_empty() { None } else { Some(s) });
-    pub static ref ADMIN_API_TOKEN: Option<String> = std::env::var("ZED_ADMIN_API_TOKEN")
+        .and_then(|s| if s.is_empty() { None } else { Some(s) })
+});
+
+pub static ADMIN_API_TOKEN: LazyLock<Option<String>> = LazyLock::new(|| {
+    std::env::var("ZED_ADMIN_API_TOKEN")
         .ok()
-        .and_then(|s| if s.is_empty() { None } else { Some(s) });
-    pub static ref ZED_APP_PATH: Option<PathBuf> =
-        std::env::var("ZED_APP_PATH").ok().map(PathBuf::from);
-    pub static ref ZED_ALWAYS_ACTIVE: bool =
-        std::env::var("ZED_ALWAYS_ACTIVE").map_or(false, |e| !e.is_empty());
-}
+        .and_then(|s| if s.is_empty() { None } else { Some(s) })
+});
+
+pub static ZED_APP_PATH: LazyLock<Option<PathBuf>> =
+    LazyLock::new(|| std::env::var("ZED_APP_PATH").ok().map(PathBuf::from));
+
+pub static ZED_ALWAYS_ACTIVE: LazyLock<bool> =
+    LazyLock::new(|| std::env::var("ZED_ALWAYS_ACTIVE").map_or(false, |e| !e.is_empty()));
 
 pub const INITIAL_RECONNECTION_DELAY: Duration = Duration::from_millis(500);
 pub const MAX_RECONNECTION_DELAY: Duration = Duration::from_secs(10);

crates/collab_ui/Cargo.toml πŸ”—

@@ -42,7 +42,6 @@ futures.workspace = true
 fuzzy.workspace = true
 gpui.workspace = true
 language.workspace = true
-lazy_static.workspace = true
 menu.workspace = true
 notifications.workspace = true
 parking_lot.workspace = true

crates/collab_ui/src/chat_panel/message_editor.rs πŸ”—

@@ -12,11 +12,10 @@ use language::{
     language_settings::SoftWrap, Anchor, Buffer, BufferSnapshot, CodeLabel, LanguageRegistry,
     LanguageServerId, ToOffset,
 };
-use lazy_static::lazy_static;
 use parking_lot::RwLock;
 use project::{search::SearchQuery, Completion};
 use settings::Settings;
-use std::{ops::Range, sync::Arc, time::Duration};
+use std::{ops::Range, sync::Arc, sync::LazyLock, time::Duration};
 use theme::ThemeSettings;
 use ui::{prelude::*, TextSize};
 
@@ -24,17 +23,17 @@ use crate::panel_settings::MessageEditorSettings;
 
 const MENTIONS_DEBOUNCE_INTERVAL: Duration = Duration::from_millis(50);
 
-lazy_static! {
-    static ref MENTIONS_SEARCH: SearchQuery = SearchQuery::regex(
+static MENTIONS_SEARCH: LazyLock<SearchQuery> = LazyLock::new(|| {
+    SearchQuery::regex(
         "@[-_\\w]+",
         false,
         false,
         false,
         Default::default(),
-        Default::default()
+        Default::default(),
     )
-    .unwrap();
-}
+    .unwrap()
+});
 
 pub struct MessageEditor {
     pub editor: View<Editor>,
@@ -399,8 +398,8 @@ impl MessageEditor {
         end_anchor: Anchor,
         cx: &mut ViewContext<Self>,
     ) -> Option<(Anchor, String, &'static [StringMatchCandidate])> {
-        lazy_static! {
-            static ref EMOJI_FUZZY_MATCH_CANDIDATES: Vec<StringMatchCandidate> = {
+        static EMOJI_FUZZY_MATCH_CANDIDATES: LazyLock<Vec<StringMatchCandidate>> =
+            LazyLock::new(|| {
                 let emojis = emojis::iter()
                     .flat_map(|s| s.shortcodes())
                     .map(|emoji| StringMatchCandidate {
@@ -410,8 +409,7 @@ impl MessageEditor {
                     })
                     .collect::<Vec<_>>();
                 emojis
-            };
-        }
+            });
 
         let end_offset = end_anchor.to_offset(buffer.read(cx));
 

crates/db/Cargo.toml πŸ”—

@@ -19,7 +19,6 @@ test-support = []
 anyhow.workspace = true
 gpui.workspace = true
 indoc.workspace = true
-lazy_static.workspace = true
 log.workspace = true
 paths.workspace = true
 release_channel.workspace = true

crates/db/src/db.rs πŸ”—

@@ -6,7 +6,6 @@ pub use anyhow;
 use anyhow::Context;
 use gpui::AppContext;
 pub use indoc::indoc;
-pub use lazy_static;
 pub use paths::database_dir;
 pub use smol;
 pub use sqlez;
@@ -17,9 +16,11 @@ pub use release_channel::RELEASE_CHANNEL;
 use sqlez::domain::Migrator;
 use sqlez::thread_safe_connection::ThreadSafeConnection;
 use sqlez_macros::sql;
+use std::env;
 use std::future::Future;
 use std::path::{Path, PathBuf};
 use std::sync::atomic::{AtomicBool, Ordering};
+use std::sync::LazyLock;
 use util::{maybe, ResultExt};
 
 const CONNECTION_INITIALIZE_QUERY: &str = sql!(
@@ -37,10 +38,10 @@ const FALLBACK_DB_NAME: &str = "FALLBACK_MEMORY_DB";
 
 const DB_FILE_NAME: &str = "db.sqlite";
 
-lazy_static::lazy_static! {
-    pub static ref ZED_STATELESS: bool = std::env::var("ZED_STATELESS").map_or(false, |v| !v.is_empty());
-    pub static ref ALL_FILE_DB_FAILED: AtomicBool = AtomicBool::new(false);
-}
+pub static ZED_STATELESS: LazyLock<bool> =
+    LazyLock::new(|| env::var("ZED_STATELESS").map_or(false, |v| !v.is_empty()));
+
+pub static ALL_FILE_DB_FAILED: LazyLock<AtomicBool> = LazyLock::new(|| AtomicBool::new(false));
 
 /// Open or create a database at the given directory path.
 /// This will retry a couple times if there are failures. If opening fails once, the db directory
@@ -138,15 +139,16 @@ macro_rules! define_connection {
             }
         }
 
+        use std::sync::LazyLock;
         #[cfg(any(test, feature = "test-support"))]
-        $crate::lazy_static::lazy_static! {
-            pub static ref $id: $t = $t($crate::smol::block_on($crate::open_test_db(stringify!($id))));
-        }
+        pub static $id: LazyLock<$t> = LazyLock::new(|| {
+            $t($crate::smol::block_on($crate::open_test_db(stringify!($id))))
+        });
 
         #[cfg(not(any(test, feature = "test-support")))]
-        $crate::lazy_static::lazy_static! {
-            pub static ref $id: $t = $t($crate::smol::block_on($crate::open_db($crate::database_dir(), &$crate::RELEASE_CHANNEL)));
-        }
+        pub static $id: LazyLock<$t> = LazyLock::new(|| {
+            $t($crate::smol::block_on($crate::open_db($crate::database_dir(), &$crate::RELEASE_CHANNEL)))
+        });
     };
     (pub static ref $id:ident: $t:ident<$($d:ty),+> = $migrations:expr;) => {
         pub struct $t($crate::sqlez::thread_safe_connection::ThreadSafeConnection<( $($d),+, $t )>);
@@ -170,14 +172,14 @@ macro_rules! define_connection {
         }
 
         #[cfg(any(test, feature = "test-support"))]
-        $crate::lazy_static::lazy_static! {
-            pub static ref $id: $t = $t($crate::smol::block_on($crate::open_test_db(stringify!($id))));
-        }
+        pub static $id: std::sync::LazyLock<$t> = std::sync::LazyLock::new(|| {
+            $t($crate::smol::block_on($crate::open_test_db(stringify!($id))))
+        });
 
         #[cfg(not(any(test, feature = "test-support")))]
-        $crate::lazy_static::lazy_static! {
-            pub static ref $id: $t = $t($crate::smol::block_on($crate::open_db($crate::database_dir(), &$crate::RELEASE_CHANNEL)));
-        }
+        pub static $id: std::sync::LazyLock<$t> = std::sync::LazyLock::new(|| {
+            $t($crate::smol::block_on($crate::open_db($crate::database_dir(), &$crate::RELEASE_CHANNEL)))
+        });
     };
 }
 

crates/editor/Cargo.toml πŸ”—

@@ -47,7 +47,6 @@ http_client.workspace = true
 indoc.workspace = true
 itertools.workspace = true
 language.workspace = true
-lazy_static.workspace = true
 linkify.workspace = true
 log.workspace = true
 lsp.workspace = true

crates/editor/src/display_map/wrap_map.rs πŸ”—

@@ -5,9 +5,9 @@ use super::{
 };
 use gpui::{AppContext, Context, Font, LineWrapper, Model, ModelContext, Pixels, Task};
 use language::{Chunk, Point};
-use lazy_static::lazy_static;
 use multi_buffer::MultiBufferSnapshot;
 use smol::future::yield_now;
+use std::sync::LazyLock;
 use std::{cmp, collections::VecDeque, mem, ops::Range, time::Duration};
 use sum_tree::{Bias, Cursor, SumTree};
 use text::Patch;
@@ -887,14 +887,12 @@ impl Transform {
     }
 
     fn wrap(indent: u32) -> Self {
-        lazy_static! {
-            static ref WRAP_TEXT: String = {
-                let mut wrap_text = String::new();
-                wrap_text.push('\n');
-                wrap_text.extend((0..LineWrapper::MAX_INDENT as usize).map(|_| ' '));
-                wrap_text
-            };
-        }
+        static WRAP_TEXT: LazyLock<String> = LazyLock::new(|| {
+            let mut wrap_text = String::new();
+            wrap_text.push('\n');
+            wrap_text.extend((0..LineWrapper::MAX_INDENT as usize).map(|_| ' '));
+            wrap_text
+        });
 
         Self {
             summary: TransformSummary {

crates/fs/Cargo.toml πŸ”—

@@ -20,7 +20,6 @@ futures.workspace = true
 git.workspace = true
 git2.workspace = true
 gpui.workspace = true
-lazy_static.workspace = true
 libc.workspace = true
 parking_lot.workspace = true
 paths.workspace = true

crates/fs/src/fs.rs πŸ”—

@@ -794,9 +794,8 @@ impl FakeFsState {
 }
 
 #[cfg(any(test, feature = "test-support"))]
-lazy_static::lazy_static! {
-    pub static ref FS_DOT_GIT: &'static OsStr = OsStr::new(".git");
-}
+pub static FS_DOT_GIT: std::sync::LazyLock<&'static OsStr> =
+    std::sync::LazyLock::new(|| OsStr::new(".git"));
 
 #[cfg(any(test, feature = "test-support"))]
 impl FakeFs {

crates/git/Cargo.toml πŸ”—

@@ -20,7 +20,6 @@ derive_more.workspace = true
 git2.workspace = true
 gpui.workspace = true
 http_client.workspace = true
-lazy_static.workspace = true
 log.workspace = true
 parking_lot.workspace = true
 rope.workspace = true

crates/git/src/git.rs πŸ”—

@@ -5,9 +5,9 @@ use serde::{Deserialize, Serialize};
 use std::ffi::OsStr;
 use std::fmt;
 use std::str::FromStr;
+use std::sync::LazyLock;
 
 pub use git2 as libgit;
-pub use lazy_static::lazy_static;
 
 pub use crate::hosting_provider::*;
 
@@ -17,10 +17,8 @@ pub mod diff;
 pub mod repository;
 pub mod status;
 
-lazy_static! {
-    pub static ref DOT_GIT: &'static OsStr = OsStr::new(".git");
-    pub static ref GITIGNORE: &'static OsStr = OsStr::new(".gitignore");
-}
+pub static DOT_GIT: LazyLock<&'static OsStr> = LazyLock::new(|| OsStr::new(".git"));
+pub static GITIGNORE: LazyLock<&'static OsStr> = LazyLock::new(|| OsStr::new(".gitignore"));
 
 #[derive(Clone, Copy, Eq, Hash, PartialEq)]
 pub struct Oid(libgit::Oid);

crates/gpui/Cargo.toml πŸ”—

@@ -43,7 +43,6 @@ gpui_macros.workspace = true
 http_client.workspace = true
 image = "0.25.1"
 itertools.workspace = true
-lazy_static.workspace = true
 linkme = "0.3"
 log.workspace = true
 num_cpus = "1.13"

crates/gpui/src/app/entity_map.rs πŸ”—

@@ -642,10 +642,8 @@ impl<T> PartialEq<Model<T>> for WeakModel<T> {
 }
 
 #[cfg(any(test, feature = "test-support"))]
-lazy_static::lazy_static! {
-    static ref LEAK_BACKTRACE: bool =
-        std::env::var("LEAK_BACKTRACE").map_or(false, |b| !b.is_empty());
-}
+static LEAK_BACKTRACE: std::sync::LazyLock<bool> =
+    std::sync::LazyLock::new(|| std::env::var("LEAK_BACKTRACE").map_or(false, |b| !b.is_empty()));
 
 #[cfg(any(test, feature = "test-support"))]
 #[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq)]

crates/language/Cargo.toml πŸ”—

@@ -37,7 +37,6 @@ globset.workspace = true
 gpui.workspace = true
 http_client.workspace = true
 itertools.workspace = true
-lazy_static.workspace = true
 log.workspace = true
 lsp.workspace = true
 parking_lot.workspace = true

crates/language/src/buffer.rs πŸ”—

@@ -24,7 +24,6 @@ use gpui::{
     AnyElement, AppContext, EventEmitter, HighlightStyle, ModelContext, Task, TaskLabel,
     WindowContext,
 };
-use lazy_static::lazy_static;
 use lsp::LanguageServerId;
 use parking_lot::Mutex;
 use serde_json::Value;
@@ -44,7 +43,7 @@ use std::{
     ops::{Deref, Range},
     path::{Path, PathBuf},
     str,
-    sync::Arc,
+    sync::{Arc, LazyLock},
     time::{Duration, Instant, SystemTime},
     vec,
 };
@@ -67,11 +66,9 @@ pub use {tree_sitter_rust, tree_sitter_typescript};
 
 pub use lsp::DiagnosticSeverity;
 
-lazy_static! {
-    /// A label for the background task spawned by the buffer to compute
-    /// a diff against the contents of its file.
-    pub static ref BUFFER_DIFF_TASK: TaskLabel = TaskLabel::new();
-}
+/// A label for the background task spawned by the buffer to compute
+/// a diff against the contents of its file.
+pub static BUFFER_DIFF_TASK: LazyLock<TaskLabel> = LazyLock::new(|| TaskLabel::new());
 
 /// Indicate whether a [Buffer] has permissions to edit.
 #[derive(PartialEq, Clone, Copy, Debug)]

crates/language/src/buffer_tests.rs πŸ”—

@@ -16,6 +16,7 @@ use settings::SettingsStore;
 use std::{
     env,
     ops::Range,
+    sync::LazyLock,
     time::{Duration, Instant},
 };
 use text::network::Network;
@@ -24,12 +25,12 @@ use text::{Point, ToPoint};
 use unindent::Unindent as _;
 use util::{assert_set_eq, post_inc, test::marked_text_ranges, RandomCharIter};
 
-lazy_static! {
-    static ref TRAILING_WHITESPACE_REGEX: Regex = RegexBuilder::new("[ \t]+$")
+pub static TRAILING_WHITESPACE_REGEX: LazyLock<regex::Regex> = LazyLock::new(|| {
+    RegexBuilder::new(r"[ \t]+$")
         .multi_line(true)
         .build()
-        .unwrap();
-}
+        .expect("Failed to create TRAILING_WHITESPACE_REGEX")
+});
 
 #[cfg(test)]
 #[ctor::ctor]

crates/language/src/language.rs πŸ”—

@@ -28,7 +28,6 @@ use futures::Future;
 use gpui::{AppContext, AsyncAppContext, Model, SharedString, Task};
 pub use highlight_map::HighlightMap;
 use http_client::HttpClient;
-use lazy_static::lazy_static;
 use lsp::{CodeActionKind, LanguageServerBinary};
 use parking_lot::Mutex;
 use regex::Regex;
@@ -53,7 +52,7 @@ use std::{
     str,
     sync::{
         atomic::{AtomicU64, AtomicUsize, Ordering::SeqCst},
-        Arc,
+        Arc, LazyLock,
     },
 };
 use syntax_map::{QueryCursorHandle, SyntaxSnapshot};
@@ -111,23 +110,23 @@ where
     func(cursor.deref_mut())
 }
 
-lazy_static! {
-    static ref NEXT_LANGUAGE_ID: AtomicUsize = Default::default();
-    static ref NEXT_GRAMMAR_ID: AtomicUsize = Default::default();
-    static ref WASM_ENGINE: wasmtime::Engine = {
-        wasmtime::Engine::new(&wasmtime::Config::new()).unwrap()
-    };
+static NEXT_LANGUAGE_ID: LazyLock<AtomicUsize> = LazyLock::new(Default::default);
+static NEXT_GRAMMAR_ID: LazyLock<AtomicUsize> = LazyLock::new(Default::default);
+static WASM_ENGINE: LazyLock<wasmtime::Engine> = LazyLock::new(|| {
+    wasmtime::Engine::new(&wasmtime::Config::new()).expect("Failed to create Wasmtime engine")
+});
 
-    /// A shared grammar for plain text, exposed for reuse by downstream crates.
-    pub static ref PLAIN_TEXT: Arc<Language> = Arc::new(Language::new(
+/// A shared grammar for plain text, exposed for reuse by downstream crates.
+pub static PLAIN_TEXT: LazyLock<Arc<Language>> = LazyLock::new(|| {
+    Arc::new(Language::new(
         LanguageConfig {
             name: "Plain Text".into(),
             soft_wrap: Some(SoftWrap::EditorWidth),
             ..Default::default()
         },
         None,
-    ));
-}
+    ))
+});
 
 /// Types that represent a position in a buffer, and can be converted into
 /// an LSP position, to send to a language server.

crates/languages/Cargo.toml πŸ”—

@@ -22,7 +22,6 @@ futures.workspace = true
 gpui.workspace = true
 http_client.workspace = true
 language.workspace = true
-lazy_static.workspace = true
 log.workspace = true
 lsp.workspace = true
 node_runtime.workspace = true

crates/languages/src/go.rs πŸ”—

@@ -4,7 +4,6 @@ use futures::StreamExt;
 use gpui::{AppContext, AsyncAppContext, Task};
 use http_client::github::latest_github_release;
 pub use language::*;
-use lazy_static::lazy_static;
 use lsp::LanguageServerBinary;
 use project::project_settings::{BinarySettings, ProjectSettings};
 use regex::Regex;
@@ -20,7 +19,7 @@ use std::{
     str,
     sync::{
         atomic::{AtomicBool, Ordering::SeqCst},
-        Arc,
+        Arc, LazyLock,
     },
 };
 use task::{TaskTemplate, TaskTemplates, TaskVariables, VariableName};
@@ -37,12 +36,12 @@ impl GoLspAdapter {
     const SERVER_NAME: &'static str = "gopls";
 }
 
-lazy_static! {
-    static ref GOPLS_VERSION_REGEX: Regex = Regex::new(r"\d+\.\d+\.\d+").unwrap();
-    static ref GO_EXTRACT_SUBTEST_NAME_REGEX: Regex =
-        Regex::new(r#".*t\.Run\("([^"]*)".*"#).unwrap();
-    static ref GO_ESCAPE_SUBTEST_NAME_REGEX: Regex = Regex::new(r#"[.*+?^${}()|\[\]\\]"#).unwrap();
-}
+static GOPLS_VERSION_REGEX: LazyLock<Regex> =
+    LazyLock::new(|| Regex::new(r"\d+\.\d+\.\d+").expect("Failed to create GOPLS_VERSION_REGEX"));
+
+static GO_ESCAPE_SUBTEST_NAME_REGEX: LazyLock<Regex> = LazyLock::new(|| {
+    Regex::new(r#"[.*+?^${}()|\[\]\\]"#).expect("Failed to create GO_ESCAPE_SUBTEST_NAME_REGEX")
+});
 
 #[async_trait(?Send)]
 impl super::LspAdapter for GoLspAdapter {

crates/languages/src/rust.rs πŸ”—

@@ -6,7 +6,6 @@ use gpui::{AppContext, AsyncAppContext};
 use http_client::github::{latest_github_release, GitHubLspBinaryVersion};
 pub use language::*;
 use language_settings::all_language_settings;
-use lazy_static::lazy_static;
 use lsp::LanguageServerBinary;
 use project::project_settings::{BinarySettings, ProjectSettings};
 use regex::Regex;
@@ -18,6 +17,7 @@ use std::{
     env::consts,
     path::{Path, PathBuf},
     sync::Arc,
+    sync::LazyLock,
 };
 use task::{TaskTemplate, TaskTemplates, TaskVariables, VariableName};
 use util::{fs::remove_matching, maybe, ResultExt};
@@ -178,9 +178,8 @@ impl LspAdapter for RustLspAdapter {
     }
 
     fn process_diagnostics(&self, params: &mut lsp::PublishDiagnosticsParams) {
-        lazy_static! {
-            static ref REGEX: Regex = Regex::new("(?m)`([^`]+)\n`$").unwrap();
-        }
+        static REGEX: LazyLock<Regex> =
+            LazyLock::new(|| Regex::new(r"(?m)`([^`]+)\n`$").expect("Failed to create REGEX"));
 
         for diagnostic in &mut params.diagnostics {
             for message in diagnostic
@@ -243,9 +242,8 @@ impl LspAdapter for RustLspAdapter {
             Some(lsp::CompletionItemKind::FUNCTION | lsp::CompletionItemKind::METHOD)
                 if detail.is_some() =>
             {
-                lazy_static! {
-                    static ref REGEX: Regex = Regex::new("\\(…?\\)").unwrap();
-                }
+                static REGEX: LazyLock<Regex> = LazyLock::new(|| Regex::new("\\(…?\\)").unwrap());
+
                 let detail = detail.unwrap();
                 const FUNCTION_PREFIXES: [&'static str; 6] = [
                     "async fn",

crates/settings/Cargo.toml πŸ”—

@@ -21,7 +21,6 @@ collections.workspace = true
 fs.workspace = true
 futures.workspace = true
 gpui.workspace = true
-lazy_static.workspace = true
 log.workspace = true
 paths.workspace = true
 release_channel.workspace = true

crates/settings/src/settings_store.rs πŸ”—

@@ -3,7 +3,6 @@ use collections::{btree_map, hash_map, BTreeMap, HashMap};
 use fs::Fs;
 use futures::{channel::mpsc, future::LocalBoxFuture, FutureExt, StreamExt};
 use gpui::{AppContext, AsyncAppContext, BorrowAppContext, Global, Task, UpdateGlobal};
-use lazy_static::lazy_static;
 use schemars::{gen::SchemaGenerator, schema::RootSchema, JsonSchema};
 use serde::{de::DeserializeOwned, Deserialize as _, Serialize};
 use smallvec::SmallVec;
@@ -13,8 +12,10 @@ use std::{
     ops::Range,
     path::Path,
     str,
-    sync::Arc,
+    sync::{Arc, LazyLock},
 };
+use tree_sitter::Query;
+use tree_sitter_json::language;
 use util::{merge_non_null_json_value_into, RangeExt, ResultExt as _};
 
 use crate::SettingsJsonSchemaParams;
@@ -944,13 +945,10 @@ fn replace_value_in_json_text(
     tab_size: usize,
     new_value: &serde_json::Value,
 ) -> (Range<usize>, String) {
-    lazy_static! {
-        static ref PAIR_QUERY: tree_sitter::Query = tree_sitter::Query::new(
-            &tree_sitter_json::language(),
-            "(pair key: (string) @key value: (_) @value)",
-        )
-        .unwrap();
-    }
+    static PAIR_QUERY: LazyLock<Query> = LazyLock::new(|| {
+        Query::new(&language(), "(pair key: (string) @key value: (_) @value)")
+            .expect("Failed to create PAIR_QUERY")
+    });
 
     let mut parser = tree_sitter::Parser::new();
     parser.set_language(&tree_sitter_json::language()).unwrap();

crates/sqlez/Cargo.toml πŸ”—

@@ -13,7 +13,6 @@ anyhow.workspace = true
 collections.workspace = true
 futures.workspace = true
 indoc.workspace = true
-lazy_static.workspace = true
 libsqlite3-sys = { version = "0.26", features = ["bundled"] }
 parking_lot.workspace = true
 smol.workspace = true

crates/sqlez/src/thread_safe_connection.rs πŸ”—

@@ -1,9 +1,13 @@
 use anyhow::Context;
 use collections::HashMap;
 use futures::{channel::oneshot, Future, FutureExt};
-use lazy_static::lazy_static;
 use parking_lot::{Mutex, RwLock};
-use std::{marker::PhantomData, ops::Deref, sync::Arc, thread};
+use std::{
+    marker::PhantomData,
+    ops::Deref,
+    sync::{Arc, LazyLock},
+    thread,
+};
 use thread_local::ThreadLocal;
 
 use crate::{connection::Connection, domain::Migrator, util::UnboundedSyncSender};
@@ -13,14 +17,13 @@ const MIGRATION_RETRIES: usize = 10;
 type QueuedWrite = Box<dyn 'static + Send + FnOnce()>;
 type WriteQueue = Box<dyn 'static + Send + Sync + Fn(QueuedWrite)>;
 type WriteQueueConstructor = Box<dyn 'static + Send + FnMut() -> WriteQueue>;
-lazy_static! {
-    /// List of queues of tasks by database uri. This lets us serialize writes to the database
-    /// and have a single worker thread per db file. This means many thread safe connections
-    /// (possibly with different migrations) could all be communicating with the same background
-    /// thread.
-    static ref QUEUES: RwLock<HashMap<Arc<str>, WriteQueue>> =
-        Default::default();
-}
+
+/// List of queues of tasks by database uri. This lets us serialize writes to the database
+/// and have a single worker thread per db file. This means many thread safe connections
+/// (possibly with different migrations) could all be communicating with the same background
+/// thread.
+static QUEUES: LazyLock<RwLock<HashMap<Arc<str>, WriteQueue>>> =
+    LazyLock::new(|| Default::default());
 
 /// Thread safe connection to a given database file or in memory db. This can be cloned, shared, static,
 /// whatever. It derefs to a synchronous connection by thread that is read only. A write capable connection
@@ -276,7 +279,7 @@ pub fn locking_queue() -> WriteQueueConstructor {
 #[cfg(test)]
 mod test {
     use indoc::indoc;
-    use lazy_static::__Deref;
+    use std::ops::Deref;
 
     use std::thread;
 

crates/sqlez_macros/Cargo.toml πŸ”—

@@ -14,7 +14,6 @@ proc-macro = true
 doctest = false
 
 [dependencies]
-lazy_static.workspace = true
 sqlez.workspace = true
 sqlformat = "0.2"
 syn = "1.0"

crates/sqlez_macros/src/sqlez_macros.rs πŸ”—

@@ -1,12 +1,16 @@
 use proc_macro::{Delimiter, Span, TokenStream, TokenTree};
-use sqlez::thread_safe_connection::{locking_queue, ThreadSafeConnection};
 use syn::Error;
 
-lazy_static::lazy_static! {
-    static ref SQLITE: ThreadSafeConnection =  {
-        ThreadSafeConnection::new(":memory:", false, None, Some(locking_queue()))
-    };
-}
+#[cfg(not(target_os = "linux"))]
+static SQLITE: std::sync::LazyLock<sqlez::thread_safe_connection::ThreadSafeConnection> =
+    std::sync::LazyLock::new(|| {
+        sqlez::thread_safe_connection::ThreadSafeConnection::new(
+            ":memory:",
+            false,
+            None,
+            Some(sqlez::thread_safe_connection::locking_queue()),
+        )
+    });
 
 #[proc_macro]
 pub fn sql(tokens: TokenStream) -> TokenStream {

crates/text/Cargo.toml πŸ”—

@@ -19,7 +19,6 @@ test-support = ["rand"]
 anyhow.workspace = true
 clock.workspace = true
 collections.workspace = true
-lazy_static.workspace = true
 log.workspace = true
 parking_lot.workspace = true
 postage.workspace = true

crates/text/src/locator.rs πŸ”—

@@ -1,11 +1,9 @@
-use lazy_static::lazy_static;
 use smallvec::{smallvec, SmallVec};
 use std::iter;
+use std::sync::LazyLock;
 
-lazy_static! {
-    static ref MIN: Locator = Locator::min();
-    static ref MAX: Locator = Locator::max();
-}
+static MIN: LazyLock<Locator> = LazyLock::new(|| Locator::min());
+static MAX: LazyLock<Locator> = LazyLock::new(|| Locator::max());
 
 /// An identifier for a position in a ordered collection.
 ///

crates/text/src/text.rs πŸ”—

@@ -19,7 +19,6 @@ use operation_queue::OperationQueue;
 pub use patch::Patch;
 use postage::{oneshot, prelude::*};
 
-use lazy_static::lazy_static;
 use regex::Regex;
 pub use rope::*;
 pub use selection::*;
@@ -32,7 +31,7 @@ use std::{
     num::NonZeroU64,
     ops::{self, Deref, Range, Sub},
     str,
-    sync::Arc,
+    sync::{Arc, LazyLock},
     time::{Duration, Instant},
 };
 pub use subscription::*;
@@ -44,9 +43,9 @@ use util::ResultExt;
 #[cfg(any(test, feature = "test-support"))]
 use util::RandomCharIter;
 
-lazy_static! {
-    static ref LINE_SEPARATORS_REGEX: Regex = Regex::new("\r\n|\r|\u{2028}|\u{2029}").unwrap();
-}
+static LINE_SEPARATORS_REGEX: LazyLock<Regex> = LazyLock::new(|| {
+    Regex::new(r"\r\n|\r|\u{2028}|\u{2029}").expect("Failed to create LINE_SEPARATORS_REGEX")
+});
 
 pub type TransactionId = clock::Lamport;
 

crates/vim/Cargo.toml πŸ”—

@@ -26,7 +26,6 @@ editor.workspace = true
 gpui.workspace = true
 itertools.workspace = true
 language.workspace = true
-lazy_static.workspace = true
 log.workspace = true
 multi_buffer.workspace = true
 nvim-rs = { git = "https://github.com/KillTheMule/nvim-rs", branch = "master", features = [

crates/vim/src/digraph.rs πŸ”—

@@ -2,25 +2,23 @@ use std::sync::Arc;
 
 use collections::HashMap;
 use gpui::AppContext;
-use lazy_static::lazy_static;
 use settings::Settings;
+use std::sync::LazyLock;
 use ui::WindowContext;
 
 use crate::{Vim, VimSettings};
 
 mod default;
 
-lazy_static! {
-    static ref DEFAULT_DIGRAPHS_MAP: HashMap<String, Arc<str>> = {
-        let mut map = HashMap::default();
-        for &(a, b, c) in default::DEFAULT_DIGRAPHS {
-            let key = format!("{a}{b}");
-            let value = char::from_u32(c).unwrap().to_string().into();
-            map.insert(key, value);
-        }
-        map
-    };
-}
+static DEFAULT_DIGRAPHS_MAP: LazyLock<HashMap<String, Arc<str>>> = LazyLock::new(|| {
+    let mut map = HashMap::default();
+    for &(a, b, c) in default::DEFAULT_DIGRAPHS {
+        let key = format!("{a}{b}");
+        let value = char::from_u32(c).unwrap().to_string().into();
+        map.insert(key, value);
+    }
+    map
+});
 
 fn lookup_digraph(a: char, b: char, cx: &AppContext) -> Arc<str> {
     let custom_digraphs = &VimSettings::get_global(cx).custom_digraphs;

crates/workspace/Cargo.toml πŸ”—

@@ -43,7 +43,6 @@ gpui.workspace = true
 http_client.workspace = true
 itertools.workspace = true
 language.workspace = true
-lazy_static.workspace = true
 log.workspace = true
 node_runtime.workspace = true
 parking_lot.workspace = true

crates/workspace/src/workspace.rs πŸ”—

@@ -44,7 +44,6 @@ pub use item::{
 };
 use itertools::Itertools;
 use language::{LanguageRegistry, Rope};
-use lazy_static::lazy_static;
 pub use modal_layer::*;
 use node_runtime::NodeRuntime;
 use notifications::{simple_message_notification::MessageNotification, NotificationHandle};
@@ -77,7 +76,7 @@ use std::{
     hash::{Hash, Hasher},
     path::{Path, PathBuf},
     rc::Rc,
-    sync::{atomic::AtomicUsize, Arc, Weak},
+    sync::{atomic::AtomicUsize, Arc, LazyLock, Weak},
     time::Duration,
 };
 use task::SpawnInTerminal;
@@ -101,16 +100,19 @@ use crate::persistence::{
     SerializedAxis,
 };
 
-lazy_static! {
-    static ref ZED_WINDOW_SIZE: Option<Size<Pixels>> = env::var("ZED_WINDOW_SIZE")
+static ZED_WINDOW_SIZE: LazyLock<Option<Size<Pixels>>> = LazyLock::new(|| {
+    env::var("ZED_WINDOW_SIZE")
         .ok()
         .as_deref()
-        .and_then(parse_pixel_size_env_var);
-    static ref ZED_WINDOW_POSITION: Option<Point<Pixels>> = env::var("ZED_WINDOW_POSITION")
+        .and_then(parse_pixel_size_env_var)
+});
+
+static ZED_WINDOW_POSITION: LazyLock<Option<Point<Pixels>>> = LazyLock::new(|| {
+    env::var("ZED_WINDOW_POSITION")
         .ok()
         .as_deref()
-        .and_then(parse_pixel_position_env_var);
-}
+        .and_then(parse_pixel_position_env_var)
+});
 
 #[derive(Clone, PartialEq)]
 pub struct RemoveWorktreeFromProject(pub WorktreeId);