Detailed changes
@@ -49,6 +49,11 @@ pub trait UpdateGlobal {
where
C: BorrowAppContext,
F: FnOnce(&mut Self, &mut C) -> R;
+
+ /// Set the global instance of the implementing type.
+ fn set_global<C>(cx: &mut C, global: Self)
+ where
+ C: BorrowAppContext;
}
impl<T: Global> UpdateGlobal for T {
@@ -59,4 +64,11 @@ impl<T: Global> UpdateGlobal for T {
{
cx.update_global(update)
}
+
+ fn set_global<C>(cx: &mut C, global: Self)
+ where
+ C: BorrowAppContext,
+ {
+ cx.set_global(global)
+ }
}
@@ -34,6 +34,142 @@ macro_rules! debug_panic {
};
}
+#[macro_export]
+macro_rules! with_clone {
+ ($i:ident, move ||$l:expr) => {{
+ let $i = $i.clone();
+ move || {
+ $l
+ }
+ }};
+ ($i:ident, move |$($k:pat_param),*|$l:expr) => {{
+ let $i = $i.clone();
+ move |$( $k ),*| {
+ $l
+ }
+ }};
+
+ (($($i:ident),+), move ||$l:expr) => {{
+ let ($($i),+) = ($($i.clone()),+);
+ move || {
+ $l
+ }
+ }};
+ (($($i:ident),+), move |$($k:pat_param),*|$l:expr) => {{
+ let ($($i),+) = ($($i.clone()),+);
+ move |$( $k ),*| {
+ $l
+ }
+ }};
+}
+
+mod test_with_clone {
+
+ // If this test compiles, it works
+ #[test]
+ fn test() {
+ let x = "String".to_string();
+ let y = std::sync::Arc::new(5);
+
+ fn no_arg(f: impl FnOnce()) {
+ f()
+ }
+
+ no_arg(with_clone!(x, move || {
+ drop(x);
+ }));
+
+ no_arg(with_clone!((x, y), move || {
+ drop(x);
+ drop(y);
+ }));
+
+ fn one_arg(f: impl FnOnce(usize)) {
+ f(1)
+ }
+
+ one_arg(with_clone!(x, move |_| {
+ drop(x);
+ }));
+ one_arg(with_clone!((x, y), move |b| {
+ drop(x);
+ drop(y);
+ println!("{}", b);
+ }));
+
+ fn two_arg(f: impl FnOnce(usize, bool)) {
+ f(5, true)
+ }
+
+ two_arg(with_clone!((x, y), move |a, b| {
+ drop(x);
+ drop(y);
+ println!("{}{}", a, b)
+ }));
+ two_arg(with_clone!((x, y), move |a, _| {
+ drop(x);
+ drop(y);
+ println!("{}", a)
+ }));
+ two_arg(with_clone!((x, y), move |_, b| {
+ drop(x);
+ drop(y);
+ println!("{}", b)
+ }));
+
+ struct Example {
+ z: usize,
+ }
+
+ fn destructuring_example(f: impl FnOnce(Example)) {
+ f(Example { z: 10 })
+ }
+
+ destructuring_example(with_clone!(x, move |Example { z }| {
+ drop(x);
+ println!("{}", z);
+ }));
+
+ let a_long_variable_1 = "".to_string();
+ let a_long_variable_2 = "".to_string();
+ let a_long_variable_3 = "".to_string();
+ let a_long_variable_4 = "".to_string();
+ two_arg(with_clone!(
+ (
+ x,
+ y,
+ a_long_variable_1,
+ a_long_variable_2,
+ a_long_variable_3,
+ a_long_variable_4
+ ),
+ move |a, b| {
+ drop(x);
+ drop(y);
+ drop(a_long_variable_1);
+ drop(a_long_variable_2);
+ drop(a_long_variable_3);
+ drop(a_long_variable_4);
+ println!("{}{}", a, b)
+ }
+ ));
+
+ fn single_expression_body(f: impl FnOnce(usize) -> usize) -> usize {
+ f(20)
+ }
+
+ let _result = single_expression_body(with_clone!(y, move |z| *y + z));
+
+ // Explicitly move all variables
+ drop(x);
+ drop(y);
+ drop(a_long_variable_1);
+ drop(a_long_variable_2);
+ drop(a_long_variable_3);
+ drop(a_long_variable_4);
+ }
+}
+
pub fn truncate(s: &str, max_chars: usize) -> &str {
match s.char_indices().nth(max_chars) {
None => s,
@@ -17,7 +17,9 @@ use env_logger::Builder;
use fs::RealFs;
use futures::{future, StreamExt};
use git::GitHostingProviderRegistry;
-use gpui::{App, AppContext, AsyncAppContext, Context, Global, Task, VisualContext};
+use gpui::{
+ App, AppContext, AsyncAppContext, Context, Global, Task, UpdateGlobal as _, VisualContext,
+};
use image_viewer;
use language::LanguageRegistry;
use log::LevelFilter;
@@ -38,11 +40,7 @@ use std::{
sync::Arc,
};
use theme::{ActiveTheme, SystemAppearance, ThemeRegistry, ThemeSettings};
-use util::{
- maybe, parse_env_output,
- paths::{self},
- ResultExt, TryFutureExt,
-};
+use util::{maybe, parse_env_output, paths, with_clone, ResultExt, TryFutureExt};
use uuid::Uuid;
use welcome::{show_welcome_view, BaseKeymap, FIRST_OPEN};
use workspace::{AppState, WorkspaceSettings, WorkspaceStore};
@@ -260,13 +258,11 @@ fn main() {
let session_id = Uuid::new_v4().to_string();
reliability::init_panic_hook(&app, installation_id.clone(), session_id.clone());
- let (listener, mut open_rx) = OpenListener::new();
- let listener = Arc::new(listener);
- let open_listener = listener.clone();
+ let (open_listener, mut open_rx) = OpenListener::new();
#[cfg(target_os = "linux")]
{
- if crate::zed::listen_for_cli_connections(listener.clone()).is_err() {
+ if crate::zed::listen_for_cli_connections(open_listener.clone()).is_err() {
println!("zed is already running");
return;
}
@@ -317,7 +313,7 @@ fn main() {
})
};
- app.on_open_urls(move |urls| open_listener.open_urls(urls));
+ app.on_open_urls(with_clone!(open_listener, move |urls| open_listener.open_urls(urls)));
app.on_reopen(move |cx| {
if let Some(app_state) = AppState::try_global(cx).and_then(|app_state| app_state.upgrade())
{
@@ -338,7 +334,7 @@ fn main() {
GitHostingProviderRegistry::set_global(git_hosting_provider_registry, cx);
git_hosting_providers::init(cx);
- OpenListener::set_global(listener.clone(), cx);
+ OpenListener::set_global(cx, open_listener.clone());
settings::init(cx);
handle_settings_file_changes(user_settings_file_rx, cx);
@@ -396,7 +392,7 @@ fn main() {
.collect();
if !urls.is_empty() {
- listener.open_urls(urls)
+ open_listener.open_urls(urls)
}
match open_rx
@@ -11,7 +11,7 @@ use collections::VecDeque;
use editor::{scroll::Autoscroll, Editor, MultiBuffer};
use gpui::{
actions, point, px, AppContext, AsyncAppContext, Context, FocusableView, MenuItem, PromptLevel,
- TitlebarOptions, View, ViewContext, VisualContext, WindowKind, WindowOptions,
+ ReadGlobal, TitlebarOptions, View, ViewContext, VisualContext, WindowKind, WindowOptions,
};
pub use open_listener::*;
@@ -90,30 +90,19 @@ impl OpenRequest {
}
}
-pub struct OpenListener {
- tx: UnboundedSender<Vec<String>>,
-}
-
-struct GlobalOpenListener(Arc<OpenListener>);
+#[derive(Clone)]
+pub struct OpenListener(UnboundedSender<Vec<String>>);
-impl Global for GlobalOpenListener {}
+impl Global for OpenListener {}
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<Vec<String>>) {
let (tx, rx) = mpsc::unbounded();
- (OpenListener { tx }, rx)
+ (OpenListener(tx), rx)
}
pub fn open_urls(&self, urls: Vec<String>) {
- self.tx
+ self.0
.unbounded_send(urls)
.map_err(|_| anyhow!("no listener for open requests"))
.log_err();
@@ -121,7 +110,7 @@ impl OpenListener {
}
#[cfg(target_os = "linux")]
-pub fn listen_for_cli_connections(opener: Arc<OpenListener>) -> Result<()> {
+pub fn listen_for_cli_connections(opener: OpenListener) -> Result<()> {
use release_channel::RELEASE_CHANNEL_NAME;
use std::os::{linux::net::SocketAddrExt, unix::net::SocketAddr, unix::net::UnixDatagram};